FrontISTR  5.9.0
Large-scale structural analysis program with finit element method
fstr_CheckConvergence.f90
Go to the documentation of this file.
1 !-------------------------------------------------------------------------------
2 ! Copyright (c) 2019 FrontISTR Commons
3 ! This software is released under the MIT License, see LICENSE.txt
4 !-------------------------------------------------------------------------------
17 
19  use m_fstr
20  implicit none
21 
22  private
23  public :: fstr_convergence_measure
24  public :: fstr_convergence_state
25  public :: fstr_check_convergence
27  public :: fstr_check_linear_solver
28 
30  type fstr_convergence_measure
31  real(kind=kreal) :: value = 0.0d0
32  real(kind=kreal) :: tol = 0.0d0
33  logical :: check = .false.
34  logical :: ok = .false.
35  logical :: absolute = .false.
36  integer(kind=kint) :: node = 0
37  integer(kind=kint) :: dof = 0
38  end type fstr_convergence_measure
39 
45  type fstr_convergence_state
46  type(fstr_convergence_measure) :: m(2,3,2)
47  end type fstr_convergence_state
48 
50  real(kind=kreal), parameter :: fref_floor = 1.0d-8
51 
52 contains
53 
59  subroutine fstr_check_convergence( hecMESH, hecMAT, fstrSOLID, fstrPR, ndof, iter, sub_step, cstep, &
60  residual_vec, cnvstat, iterStatus, hecLagMAT )
61  implicit none
62 
63  type(hecmwst_local_mesh), intent(in) :: hecmesh
64  type(hecmwst_matrix), intent(in) :: hecmat
65  type(fstr_solid), intent(inout) :: fstrsolid
66  type(fstr_param), intent(in) :: fstrpr
67  integer(kind=kint), intent(in) :: ndof
68  integer(kind=kint), intent(in) :: iter
69  integer(kind=kint), intent(in) :: sub_step
70  integer(kind=kint), intent(in) :: cstep
71  real(kind=kreal), intent(in) :: residual_vec(:)
72  type(fstr_convergence_state), intent(out) :: cnvstat
73  integer(kind=kint), intent(out) :: iterstatus
74  type(hecmwst_matrix_lagrange), intent(in), optional :: heclagmat
75 
76  real(kind=kreal) :: res_for_check
77  logical :: do_failure_check
78 
79  ! --- core convergence check (customizable) ---
80  call fstr_check_convergence_main( hecmesh, hecmat, fstrsolid, fstrpr, ndof, iter, cstep, &
81  residual_vec, cnvstat, iterstatus, do_failure_check, res_for_check, heclagmat )
82 
83  if( iterstatus == kitrconverged ) return
84  if( .not. do_failure_check ) return
85 
86  ! --- common divergence / NaN classification ---
87  if( res_for_check /= res_for_check ) then
88  iterstatus = kitrfloatingerror
89  else if( iter == fstrsolid%step_ctrl(cstep)%max_iter .or. &
90  res_for_check > fstrsolid%step_ctrl(cstep)%maxres ) then
91  iterstatus = kitrdiverged
92  endif
93 
94  if( iterstatus == kitrcontinue ) return
95 
96  ! --- common failure handling: log + stats update ---
97  if( hecmesh%my_rank == 0 ) then
98  write(ilog,'(a,i5,a,i5)') '### Fail to Converge : at total_step=', cstep, ' sub_step=', sub_step
99  write( *,'(a,i5,a,i5)') ' ### Fail to Converge : at total_step=', cstep, ' sub_step=', sub_step
100  endif
101  fstrsolid%NRstat_i(knstmaxit) = max(fstrsolid%NRstat_i(knstmaxit), iter)
102  fstrsolid%NRstat_i(knstsumit) = fstrsolid%NRstat_i(knstsumit) + iter
103  fstrsolid%CutBack_stat = fstrsolid%CutBack_stat + 1
104  if( iterstatus == kitrdiverged .and. &
105  iter == fstrsolid%step_ctrl(cstep)%max_iter ) then
106  fstrsolid%NRstat_i(knstdresn) = 1
107  else
108  ! kitrDiverged due to maxres, or kitrFloatingError due to NaN
109  fstrsolid%NRstat_i(knstdresn) = 2
110  endif
111 
112  end subroutine fstr_check_convergence
113 
151  subroutine fstr_check_convergence_main( hecMESH, hecMAT, fstrSOLID, fstrPR, ndof, iter, cstep, &
152  residual_vec, cnvstat, iterStatus, do_failure_check, res_for_check, hecLagMAT )
153  implicit none
154 
155  type(hecmwst_local_mesh), intent(in) :: hecmesh
156  type(hecmwst_matrix), intent(in) :: hecmat
157  type(fstr_solid), intent(inout) :: fstrsolid
158  type(fstr_param), intent(in) :: fstrpr
159  integer(kind=kint), intent(in) :: ndof
160  integer(kind=kint), intent(in) :: iter
161  integer(kind=kint), intent(in) :: cstep
162  real(kind=kreal), intent(in) :: residual_vec(:)
163  type(fstr_convergence_state), intent(out) :: cnvstat
164  integer(kind=kint), intent(out) :: iterstatus
165  logical, intent(out) :: do_failure_check
166  real(kind=kreal), intent(out) :: res_for_check
167  type(hecmwst_matrix_lagrange), intent(in), optional :: heclagmat
168 
169  logical :: has_dx
170 
171  iterstatus = kitrcontinue
172  do_failure_check = .false.
173  res_for_check = 0.0d0
174 
175  has_dx = .not. ( fstrpr%solution_type == kstdynamic .and. iter == 1 )
176 
177  call fstr_evaluate_convergence( hecmesh, hecmat, fstrsolid, ndof, cstep, has_dx, residual_vec, cnvstat, heclagmat )
178 
179  if( hecmesh%my_rank == 0 ) call fstr_print_convergence_state( iter, cnvstat )
180 
181  if( .not. has_dx ) return
182 
183  if( fstr_decide_convergence( cnvstat ) ) then
184  iterstatus = kitrconverged
185  return
186  endif
187 
188  do_failure_check = .true.
189  res_for_check = max( cnvstat%m(kcnvresidual, kcnvtranslation, kcnvl2)%value, &
190  cnvstat%m(kcnvresidual, kcnvrotation, kcnvl2)%value )
191 
192  end subroutine fstr_check_convergence_main
193 
201  logical function fstr_decide_convergence( cnvstat )
202  implicit none
203  type(fstr_convergence_state), intent(in) :: cnvstat
204 
205  type(fstr_convergence_measure) :: lag(2), dx(4), res(4)
206 
207  lag = [ cnvstat%m(kcnvcorrection, kcnvlagrange, :) ]
208  dx = [ cnvstat%m(kcnvcorrection, kcnvtranslation:kcnvrotation, :) ]
209  res = [ cnvstat%m(kcnvresidual, kcnvtranslation:kcnvrotation, :) ]
210 
211  fstr_decide_convergence = cnv_all_ok(lag) .and. &
212  ( ( cnv_any_check(dx) .and. cnv_all_ok(dx) ) .or. &
213  ( cnv_any_check(res) .and. cnv_all_ok(res) ) )
214 
215  end function fstr_decide_convergence
216 
218  logical function cnv_all_ok( ms )
219  implicit none
220  type(fstr_convergence_measure), intent(in) :: ms(:)
221 
222  cnv_all_ok = all( ms%ok .or. .not. ms%check )
223 
224  end function cnv_all_ok
225 
227  logical function cnv_any_check( ms )
228  implicit none
229  type(fstr_convergence_measure), intent(in) :: ms(:)
230 
231  cnv_any_check = any( ms%check )
232 
233  end function cnv_any_check
234 
239  subroutine fstr_evaluate_convergence( hecMESH, hecMAT, fstrSOLID, ndof, cstep, has_dx, residual_vec, cnvstat, &
240  hecLagMAT )
241  implicit none
242 
243  type(hecmwst_local_mesh), intent(in) :: hecmesh
244  type(hecmwst_matrix), intent(in) :: hecmat
245  type(fstr_solid), intent(in) :: fstrsolid
246  integer(kind=kint), intent(in) :: ndof
247  integer(kind=kint), intent(in) :: cstep
248  logical, intent(in) :: has_dx
249  real(kind=kreal), intent(in) :: residual_vec(:)
250  type(fstr_convergence_state), intent(out) :: cnvstat
251  type(hecmwst_matrix_lagrange), intent(in), optional :: heclagmat
252 
253  integer(kind=kint), parameter :: nsum = 13
254  real(kind=kreal) :: sq(nsum)
255  integer(kind=kint) :: i, npndof, num_lagrange
256  real(kind=kreal) :: dx_t, dx_r, fref_t
257  logical :: has_rot, has_lag
258 
259  num_lagrange = 0
260  if( present(heclagmat) ) num_lagrange = heclagmat%num_lagrange
261  npndof = hecmat%NP*ndof
262 
263  has_rot = ( ndof == 6 )
264 
265  ! --- squares of the norms, reduced in a single collective ---
266  sq(:) = 0.0d0
267  call fstr_get_sqnorm_dofgroup( hecmesh, ndof, residual_vec, sq(1), sq(2) )
268  call fstr_get_sqnorm_dofgroup( hecmesh, ndof, fstrsolid%QFORCE, sq(3), sq(4) )
269  call fstr_get_sqnorm_dofgroup( hecmesh, ndof, fstrsolid%DFORCE, sq(5), sq(6) )
270  if( has_dx ) then
271  call fstr_get_sqnorm_dofgroup( hecmesh, ndof, hecmat%X, sq(7), sq(8) )
272  call fstr_get_sqnorm_dofgroup( hecmesh, ndof, fstrsolid%dunode, sq(9), sq(10) )
273  do i = 1, num_lagrange
274  sq(11) = sq(11) + hecmat%X(npndof+i)*hecmat%X(npndof+i)
275  sq(12) = sq(12) + heclagmat%Lagrange(i)*heclagmat%Lagrange(i)
276  enddo
277  endif
278  sq(13) = dble(num_lagrange)
279  call hecmw_allreduce_r( hecmesh, sq, nsum, hecmw_sum )
280 
281  ! Lagrange rows may be absent from a subdomain while present in the model, so the criteria must be selected from
282  ! the reduced count.
283  has_lag = ( sq(13) > 0.5d0 )
284 
285  cnvstat%m(:,:,:)%tol = fstrsolid%step_ctrl(cstep)%cnv_tol(:,:,:)
286  cnvstat%m(:,:,:)%check = fstrsolid%step_ctrl(cstep)%cnv_check(:,:,:)
287  if( .not. has_rot ) cnvstat%m(:,kcnvrotation,:)%check = .false.
288  if( .not. has_lag ) cnvstat%m(:,kcnvlagrange,:)%check = .false.
289  if( .not. has_dx ) cnvstat%m(kcnvcorrection,:,:)%check = .false.
290 
291  ! --- residual relative to the reference force ---
292  fref_t = max( sqrt(sq(3)), sqrt(sq(5)) )
293  call fstr_set_relative_measure( cnvstat%m(kcnvresidual,kcnvtranslation,kcnvl2), &
294  sqrt(sq(1)), fref_t )
295  if( has_rot ) then
296  call fstr_set_relative_measure( cnvstat%m(kcnvresidual,kcnvrotation,kcnvl2), &
297  sqrt(sq(2)), max( sqrt(sq(4)), sqrt(sq(6)) ) )
298  endif
299 
300  ! --- correction relative to the accumulated increment ---
301  ! A vanishing denominator leaves the ratio at 1, i.e. not converged.
302  if( has_dx ) then
303  dx_t = 1.0d0
304  if( sq(9) > 0.0d0 ) dx_t = sqrt( sq(7)/sq(9) )
305  dx_r = 1.0d0
306  if( sq(10) > 0.0d0 ) dx_r = sqrt( sq(8)/sq(10) )
307  cnvstat%m(kcnvcorrection,kcnvtranslation,kcnvl2)%value = dx_t
308  if( has_rot ) cnvstat%m(kcnvcorrection,kcnvrotation,kcnvl2)%value = dx_r
309  ! The multiplier is a contact force, so the reference force bounds its norm from below.
310  if( has_lag ) then
311  call fstr_set_relative_measure( cnvstat%m(kcnvcorrection,kcnvlagrange,kcnvl2), &
312  sqrt(sq(11)), max( sqrt(sq(12)), fref_t ) )
313  endif
314  endif
315 
316  ! The flags are the same on every subdomain, so the collectives of the max norms are skipped consistently.
317  if( any( cnvstat%m(:,:,kcnvmax)%check ) ) then
318  call fstr_evaluate_convergence_max( hecmesh, hecmat, fstrsolid, ndof, has_dx, residual_vec, cnvstat, &
319  heclagmat )
320  endif
321 
322  ! A NaN component fails every comparison above: it never wins a maximum and never passes the test on a denominator,
323  ! so a ratio would keep its default. The sums are the only place it survives, and every criterion takes it over.
324  do i = 1, nsum-1
325  if( sq(i) /= sq(i) ) cnvstat%m(:,:,:)%value = sq(i)
326  enddo
327 
328  cnvstat%m(:,:,:)%ok = cnvstat%m(:,:,:)%check .and. ( cnvstat%m(:,:,:)%value < cnvstat%m(:,:,:)%tol )
329 
330  end subroutine fstr_evaluate_convergence
331 
337  subroutine fstr_evaluate_convergence_max( hecMESH, hecMAT, fstrSOLID, ndof, has_dx, residual_vec, cnvstat, &
338  hecLagMAT )
339  implicit none
340 
341  type(hecmwst_local_mesh), intent(in) :: hecmesh
342  type(hecmwst_matrix), intent(in) :: hecmat
343  type(fstr_solid), intent(in) :: fstrsolid
344  integer(kind=kint), intent(in) :: ndof
345  logical, intent(in) :: has_dx
346  real(kind=kreal), intent(in) :: residual_vec(:)
347  type(fstr_convergence_state), intent(inout) :: cnvstat
348  type(hecmwst_matrix_lagrange), intent(in), optional :: heclagmat
349 
350  integer(kind=kint), parameter :: nmax = 12
351  ! entries of vmax located, and the criteria they belong to
352  integer(kind=kint), parameter :: nloc = 4
353  integer(kind=kint), parameter :: imax_loc(nloc) = [ 1, 2, 7, 8 ]
354  integer(kind=kint), parameter :: iq_loc(nloc) = [ kcnvresidual, kcnvresidual, kcnvcorrection, kcnvcorrection ]
355  integer(kind=kint), parameter :: ig_loc(nloc) = [ kcnvtranslation, kcnvrotation, kcnvtranslation, kcnvrotation ]
356  real(kind=kreal) :: vmax(nmax), gmax(nmax)
357  integer(kind=kint) :: loc(2,nloc), gnode(nloc), gdof(nloc)
358  integer(kind=kint) :: i, k, npndof, num_lagrange
359  real(kind=kreal) :: dx_t, dx_r, fref_t
360 
361  num_lagrange = 0
362  if( present(heclagmat) ) num_lagrange = heclagmat%num_lagrange
363  npndof = hecmat%NP*ndof
364 
365  vmax(:) = 0.0d0
366  loc(:,:) = 0
367  call fstr_get_maxabs_dofgroup( hecmesh, ndof, residual_vec, vmax(1), vmax(2), loc(:,1), loc(:,2) )
368  call fstr_get_maxabs_dofgroup( hecmesh, ndof, fstrsolid%QFORCE, vmax(3), vmax(4) )
369  call fstr_get_maxabs_dofgroup( hecmesh, ndof, fstrsolid%DFORCE, vmax(5), vmax(6) )
370  if( has_dx ) then
371  call fstr_get_maxabs_dofgroup( hecmesh, ndof, hecmat%X, vmax(7), vmax(8), loc(:,3), loc(:,4) )
372  call fstr_get_maxabs_dofgroup( hecmesh, ndof, fstrsolid%dunode, vmax(9), vmax(10) )
373  do i = 1, num_lagrange
374  vmax(11) = max( vmax(11), abs(hecmat%X(npndof+i)) )
375  vmax(12) = max( vmax(12), abs(heclagmat%Lagrange(i)) )
376  enddo
377  endif
378  gmax(:) = vmax(:)
379  call hecmw_allreduce_r( hecmesh, gmax, nmax, hecmw_max )
380 
381  do k = 1, nloc
382  if( gmax(imax_loc(k)) > vmax(imax_loc(k)) ) loc(1,k) = 0
383  enddo
384  gnode(:) = loc(1,:)
385  call hecmw_allreduce_i( hecmesh, gnode, nloc, hecmw_max )
386  do k = 1, nloc
387  gdof(k) = 0
388  if( loc(1,k) == gnode(k) ) gdof(k) = loc(2,k)
389  enddo
390  call hecmw_allreduce_i( hecmesh, gdof, nloc, hecmw_max )
391 
392  ! --- residual relative to the reference force ---
393  fref_t = max( gmax(3), gmax(5) )
394  call fstr_set_relative_measure( cnvstat%m(kcnvresidual,kcnvtranslation,kcnvmax), &
395  gmax(1), fref_t )
396  if( ndof == 6 ) then
397  call fstr_set_relative_measure( cnvstat%m(kcnvresidual,kcnvrotation,kcnvmax), &
398  gmax(2), max( gmax(4), gmax(6) ) )
399  endif
400 
401  ! --- correction relative to the accumulated increment, with the same rules as the L2 norms ---
402  if( has_dx ) then
403  dx_t = 1.0d0
404  if( gmax(9) > 0.0d0 ) dx_t = gmax(7) / gmax(9)
405  dx_r = 1.0d0
406  if( gmax(10) > 0.0d0 ) dx_r = gmax(8) / gmax(10)
407  cnvstat%m(kcnvcorrection,kcnvtranslation,kcnvmax)%value = dx_t
408  if( ndof == 6 ) cnvstat%m(kcnvcorrection,kcnvrotation,kcnvmax)%value = dx_r
409  call fstr_set_relative_measure( cnvstat%m(kcnvcorrection,kcnvlagrange,kcnvmax), &
410  gmax(11), max( gmax(12), fref_t ) )
411  endif
412 
413  do k = 1, nloc
414  cnvstat%m(iq_loc(k),ig_loc(k),kcnvmax)%node = gnode(k)
415  cnvstat%m(iq_loc(k),ig_loc(k),kcnvmax)%dof = gdof(k)
416  enddo
417 
418  end subroutine fstr_evaluate_convergence_max
419 
421  subroutine fstr_set_relative_measure( ms, val, fref )
422  implicit none
423  type(fstr_convergence_measure), intent(inout) :: ms
424  real(kind=kreal), intent(in) :: val
425  real(kind=kreal), intent(in) :: fref
426 
427  ms%absolute = ( fref < fref_floor )
428  if( ms%absolute ) then
429  ms%value = val
430  else
431  ms%value = val / fref
432  endif
433 
434  end subroutine fstr_set_relative_measure
435 
441  subroutine fstr_get_sqnorm_dofgroup( hecMESH, ndof, vec, sq_t, sq_r )
442  implicit none
443  type(hecmwst_local_mesh), intent(in) :: hecmesh
444  integer(kind=kint), intent(in) :: ndof
445  real(kind=kreal), intent(in) :: vec(:)
446  real(kind=kreal), intent(out) :: sq_t
447  real(kind=kreal), intent(out) :: sq_r
448 
449  integer(kind=kint) :: i, idof, idx
450 
451  sq_t = 0.0d0
452  sq_r = 0.0d0
453  do i = 1, hecmesh%nn_internal
454  idx = ndof*(i-1)
455  do idof = 1, min(ndof,3)
456  sq_t = sq_t + vec(idx+idof)*vec(idx+idof)
457  enddo
458  if( ndof /= 6 ) cycle
459  do idof = 4, 6
460  sq_r = sq_r + vec(idx+idof)*vec(idx+idof)
461  enddo
462  enddo
463 
464  end subroutine fstr_get_sqnorm_dofgroup
465 
470  subroutine fstr_get_maxabs_dofgroup( hecMESH, ndof, vec, vmax_t, vmax_r, loc_t, loc_r )
471  implicit none
472  type(hecmwst_local_mesh), intent(in) :: hecmesh
473  integer(kind=kint), intent(in) :: ndof
474  real(kind=kreal), intent(in) :: vec(:)
475  real(kind=kreal), intent(out) :: vmax_t
476  real(kind=kreal), intent(out) :: vmax_r
477  integer(kind=kint), intent(out), optional :: loc_t(2)
478  integer(kind=kint), intent(out), optional :: loc_r(2)
479 
480  integer(kind=kint) :: i, idof, idx, gid
481  integer(kind=kint) :: lt(2), lr(2)
482  real(kind=kreal) :: a
483 
484  vmax_t = 0.0d0
485  vmax_r = 0.0d0
486  lt(:) = 0
487  lr(:) = 0
488  ! Ties between nodes go to the largest node ID, as in the reduction across subdomains, so that the location does
489  ! not depend on the partitioning.
490  do i = 1, hecmesh%nn_internal
491  idx = ndof*(i-1)
492  gid = hecmesh%global_node_ID(i)
493  do idof = 1, min(ndof,3)
494  a = abs(vec(idx+idof))
495  if( a > vmax_t .or. ( a >= vmax_t .and. a > 0.0d0 .and. gid > lt(1) ) ) then
496  vmax_t = a
497  lt(1) = gid
498  lt(2) = idof
499  endif
500  enddo
501  if( ndof /= 6 ) cycle
502  do idof = 4, 6
503  a = abs(vec(idx+idof))
504  if( a > vmax_r .or. ( a >= vmax_r .and. a > 0.0d0 .and. gid > lr(1) ) ) then
505  vmax_r = a
506  lr(1) = gid
507  lr(2) = idof
508  endif
509  enddo
510  enddo
511  if( present(loc_t) ) loc_t(:) = lt(:)
512  if( present(loc_r) ) loc_r(:) = lr(:)
513 
514  end subroutine fstr_get_maxabs_dofgroup
515 
520  subroutine fstr_print_convergence_state( iter, cnvstat )
521  implicit none
522  integer(kind=kint), intent(in) :: iter
523  type(fstr_convergence_state), intent(in) :: cnvstat
524 
525  character(len=512) :: line
526  integer(kind=kint) :: iq, ig
527 
528  write(line,'(a,i8)') " iter:", iter
529  do iq = kcnvresidual, kcnvcorrection
530  do ig = kcnvtranslation, kcnvlagrange
531  if( .not. cnvstat%m(iq,ig,kcnvl2)%check ) cycle
532  write(line(len_trim(line)+1:),'(a,a,a,1pe11.4)') ", ", &
533  trim(fstr_convergence_label( iq, ig, kcnvl2, cnvstat%m(iq,ig,kcnvl2)%absolute )), ":", &
534  cnvstat%m(iq,ig,kcnvl2)%value
535  enddo
536  enddo
537  write(*,'(a)') trim(line)
538 
539  line = ""
540  do iq = kcnvresidual, kcnvcorrection
541  do ig = kcnvtranslation, kcnvlagrange
542  if( .not. cnvstat%m(iq,ig,kcnvmax)%check ) cycle
543  if( len_trim(line) > 0 ) line = trim(line) // ","
544  write(line(len_trim(line)+1:),'(a,a,a,1pe11.4)') " ", &
545  trim(fstr_convergence_label( iq, ig, kcnvmax, cnvstat%m(iq,ig,kcnvmax)%absolute )), ":", &
546  cnvstat%m(iq,ig,kcnvmax)%value
547  if( cnvstat%m(iq,ig,kcnvmax)%node > 0 ) then
548  write(line(len_trim(line)+1:),'(a,i0,a,i0,a)') " (node ", cnvstat%m(iq,ig,kcnvmax)%node, &
549  ", dof ", cnvstat%m(iq,ig,kcnvmax)%dof, ")"
550  endif
551  enddo
552  enddo
553  if( len_trim(line) > 0 ) write(*,'(a,a)') repeat(" ", 15), trim(line)
554 
555  end subroutine fstr_print_convergence_state
556 
558  function fstr_convergence_label( iq, ig, inorm, absolute ) result( label )
559  implicit none
560  integer(kind=kint), intent(in) :: iq
561  integer(kind=kint), intent(in) :: ig
562  integer(kind=kint), intent(in) :: inorm
563  logical, intent(in) :: absolute
564  character(len=32) :: label
565 
566  character(len=5), parameter :: res_name(3) = [ 'force', 'mom ', 'lag ' ]
567  character(len=10), parameter :: corr_name(3) = [ 'disp.corr.', 'rot.corr. ', 'lag.corr. ' ]
568 
569  if( iq == kcnvresidual ) then
570  label = 'res(' // trim(res_name(ig))
571  if( inorm == kcnvmax ) label = trim(label) // ',max'
572  if( absolute ) label = trim(label) // ',abs'
573  label = trim(label) // ')'
574  else
575  label = corr_name(ig)
576  if( inorm == kcnvmax ) label = trim(label) // '(max)'
577  endif
578 
579  end function fstr_convergence_label
580 
585  subroutine fstr_check_linear_solver( hecMESH, hecMAT, fstrSOLID, cstep, sub_step, iterStatus, istat )
586  implicit none
587 
588  type(hecmwst_local_mesh), intent(in) :: hecmesh
589  type(hecmwst_matrix), intent(in) :: hecmat
590  type(fstr_solid), intent(inout) :: fstrsolid
591  integer(kind=kint), intent(in) :: cstep
592  integer(kind=kint), intent(in) :: sub_step
593  integer(kind=kint), intent(out) :: iterstatus
594  integer(kind=kint), intent(in), optional :: istat
595 
596  iterstatus = kitrcontinue
597 
598  ! direct solvers report a genuine failure only through istat
599  if( present(istat) ) then
600  if( istat /= 0 ) then
601  iterstatus = kitrdiverged
602  fstrsolid%NRstat_i(knstdresn) = 4
603  endif
604  endif
605 
606  if( iterstatus == kitrcontinue ) then
607  if( hecmw_mat_get_flag_diverged(hecmat) /= kno ) then
608  ! broke down: indefinite preconditioner/matrix, or NaN
609  iterstatus = kitrdiverged
610  fstrsolid%NRstat_i(knstdresn) = 6
611  else if( hecmw_mat_get_solver_type(hecmat) == 1 .and. &
612  hecmw_mat_get_flag_converged(hecmat) == kno ) then
613  ! ran out of iterations. Restricted to iterative solvers because a direct solver leaves the same flag unset
614  ! whenever its residual exceeds the tolerance, and hecmw_solve only warns and keeps going in that case
615  iterstatus = kitrdiverged
616  fstrsolid%NRstat_i(knstdresn) = 5
617  endif
618  endif
619 
620  if( iterstatus == kitrcontinue ) return
621 
622  if( hecmesh%my_rank == 0 ) then
623  write(*,'(a,i5,a,i5)') ' ### Fail to Converge : at total_step=', cstep, ' sub_step=', sub_step
624  endif
625  fstrsolid%CutBack_stat = fstrsolid%CutBack_stat + 1
626 
627  end subroutine fstr_check_linear_solver
628 
629 end module m_fstr_iterationcontrol
This module provides a unified convergence check for Newton iteration.
subroutine, public fstr_check_convergence_main(hecMESH, hecMAT, fstrSOLID, fstrPR, ndof, iter, cstep, residual_vec, cnvstat, iterStatus, do_failure_check, res_for_check, hecLagMAT)
Core convergence check.
subroutine, public fstr_check_linear_solver(hecMESH, hecMAT, fstrSOLID, cstep, sub_step, iterStatus, istat)
Classify the linear solver result and record why the solve failed.
subroutine, public fstr_check_convergence(hecMESH, hecMAT, fstrSOLID, fstrPR, ndof, iter, sub_step, cstep, residual_vec, cnvstat, iterStatus, hecLagMAT)
Wrapper that calls fstr_check_convergence_main and applies the common divergence/NaN handling (status...
This module defines common data and basic structures for analysis.
Definition: m_fstr.F90:15
integer(kind=kint), parameter kitrfloatingerror
Definition: m_fstr.F90:99
integer(kind=kint), parameter kstdynamic
Definition: m_fstr.F90:41
integer(kind=kint), parameter kitrconverged
Definition: m_fstr.F90:97
integer(kind=kint), parameter ilog
FILE HANDLER.
Definition: m_fstr.F90:114
type(fstr_param), target fstrpr
GLOBAL VARIABLE INITIALIZED IN FSTR_SETUP.
Definition: m_fstr.F90:222
integer(kind=kint), parameter kitrcontinue
iteration control
Definition: m_fstr.F90:96
integer(kind=kint), parameter kno
Definition: m_fstr.F90:32
integer(kind=kint), parameter kitrdiverged
Definition: m_fstr.F90:98
FSTR INNER CONTROL PARAMETERS (fstrPARAM)
Definition: m_fstr.F90:161