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 !-------------------------------------------------------------------------------
11 
13  use m_fstr
14  implicit none
15 
16  private
17  public :: fstr_check_convergence
19 
20 contains
21 
29  subroutine fstr_check_convergence( &
30  hecMESH, hecMAT, fstrSOLID, fstrPR, &
31  ndof, iter, sub_step, cstep, &
32  residual_vec, nresid, &
33  resb, res_prev, &
34  n_node_global, &
35  iterStatus, &
36  maxDLag, converg_dlag )
37  implicit none
38 
39  type(hecmwst_local_mesh), intent(in) :: hecmesh
40  type(hecmwst_matrix), intent(in) :: hecmat
41  type(fstr_solid), intent(inout) :: fstrsolid
42  type(fstr_param), intent(in) :: fstrpr
43  integer(kind=kint), intent(in) :: ndof
44  integer(kind=kint), intent(in) :: iter
45  integer(kind=kint), intent(in) :: sub_step
46  integer(kind=kint), intent(in) :: cstep
47  real(kind=kreal), intent(in) :: residual_vec(:)
48  integer(kind=kint), intent(in) :: nresid
49  real(kind=kreal), intent(inout) :: resb
50  real(kind=kreal), intent(inout) :: res_prev
51  integer(kind=kint), intent(in) :: n_node_global
52  integer(kind=kint), intent(out) :: iterstatus
53  real(kind=kreal), intent(in), optional :: maxdlag
54  real(kind=kreal), intent(in), optional :: converg_dlag
55 
56  real(kind=kreal) :: res_for_check
57  logical :: do_failure_check, is_dynamic, is_contact
58 
59  is_dynamic = (fstrpr%solution_type == kstdynamic)
60  is_contact = (n_node_global > 0)
61 
62  ! --- core convergence check (customizable) ---
64  hecmesh, hecmat, fstrsolid, fstrpr, &
65  ndof, iter, cstep, &
66  residual_vec, nresid, &
67  resb, res_prev, &
68  n_node_global, &
69  iterstatus, &
70  do_failure_check, res_for_check, &
71  maxdlag, converg_dlag )
72 
73  if( iterstatus == kitrconverged ) return
74  if( .not. do_failure_check ) return
75 
76  ! --- common divergence / NaN classification ---
77  if( res_for_check /= res_for_check ) then
78  iterstatus = kitrfloatingerror
79  else if( iter == fstrsolid%step_ctrl(cstep)%max_iter .or. &
80  res_for_check > fstrsolid%step_ctrl(cstep)%maxres ) then
81  iterstatus = kitrdiverged
82  endif
83 
84  if( iterstatus == kitrcontinue ) return
85 
86  ! --- common failure handling: log + stats update ---
87  if( hecmesh%my_rank == 0 ) then
88  ! Static non-contact path (legacy fstr_check_iteration_converged) also
89  ! wrote to ILOG; preserve that behaviour for backward compatibility.
90  if( .not. is_dynamic .and. .not. is_contact ) then
91  write(ilog,'(a,i5,a,i5)') '### Fail to Converge : at total_step=', cstep, ' sub_step=', sub_step
92  endif
93  write( *,'(a,i5,a,i5)') ' ### Fail to Converge : at total_step=', cstep, ' sub_step=', sub_step
94  endif
95  fstrsolid%NRstat_i(knstmaxit) = max(fstrsolid%NRstat_i(knstmaxit), iter)
96  fstrsolid%NRstat_i(knstsumit) = fstrsolid%NRstat_i(knstsumit) + iter
97  fstrsolid%CutBack_stat = fstrsolid%CutBack_stat + 1
98  if( iterstatus == kitrdiverged .and. &
99  iter == fstrsolid%step_ctrl(cstep)%max_iter ) then
100  fstrsolid%NRstat_i(knstdresn) = 1
101  else
102  ! kitrDiverged due to maxres, or kitrFloatingError due to NaN
103  fstrsolid%NRstat_i(knstdresn) = 2
104  endif
105 
106  end subroutine fstr_check_convergence
107 
138  hecMESH, hecMAT, fstrSOLID, fstrPR, &
139  ndof, iter, cstep, &
140  residual_vec, nresid, &
141  resb, res_prev, &
142  n_node_global, &
143  iterStatus, &
144  do_failure_check, res_for_check, &
145  maxDLag, converg_dlag )
146  implicit none
147 
148  type(hecmwst_local_mesh), intent(in) :: hecmesh
149  type(hecmwst_matrix), intent(in) :: hecmat
150  type(fstr_solid), intent(inout) :: fstrsolid
151  type(fstr_param), intent(in) :: fstrpr
152  integer(kind=kint), intent(in) :: ndof
153  integer(kind=kint), intent(in) :: iter
154  integer(kind=kint), intent(in) :: cstep
155  real(kind=kreal), intent(in) :: residual_vec(:)
156  integer(kind=kint), intent(in) :: nresid
157  real(kind=kreal), intent(inout) :: resb
158  real(kind=kreal), intent(inout) :: res_prev
159  integer(kind=kint), intent(in) :: n_node_global
160  integer(kind=kint), intent(out) :: iterstatus
161  logical, intent(out) :: do_failure_check
162  real(kind=kreal), intent(out) :: res_for_check
163  real(kind=kreal), intent(in), optional :: maxdlag
164  real(kind=kreal), intent(in), optional :: converg_dlag
165 
166  real(kind=kreal) :: res_sq, res_nrm, qnrm, rres, xnrm, dunrm, rxnrm
167  real(kind=kreal) :: relres, res_normalized
168  logical :: is_dynamic, is_contact
169 
170  iterstatus = kitrcontinue
171  do_failure_check = .false.
172  res_for_check = 0.0d0
173 
174  is_dynamic = (fstrpr%solution_type == kstdynamic)
175  is_contact = (n_node_global > 0)
176 
177  ! =========================================================================
178  ! PATH 1: Static, non-contact (QFORCE normalization + disp correction)
179  ! =========================================================================
180  if( .not. is_dynamic .and. .not. is_contact ) then
181  call hecmw_innerproduct_r(hecmesh, ndof, hecmat%B, hecmat%B, res_sq)
182  res_nrm = sqrt(res_sq)
183 
184  call hecmw_innerproduct_r(hecmesh, ndof, hecmat%X, hecmat%X, xnrm)
185  xnrm = sqrt(xnrm)
186 
187  call hecmw_innerproduct_r(hecmesh, ndof, fstrsolid%QFORCE, fstrsolid%QFORCE, qnrm)
188  qnrm = sqrt(qnrm)
189  if( qnrm < 1.0d-8 ) qnrm = 1.0d0
190 
191  if( iter == 1 ) then
192  dunrm = xnrm
193  else
194  call hecmw_innerproduct_r(hecmesh, ndof, fstrsolid%dunode, fstrsolid%dunode, dunrm)
195  dunrm = sqrt(dunrm)
196  endif
197 
198  rres = res_nrm / qnrm
199  rxnrm = xnrm / dunrm
200 
201  if( hecmesh%my_rank == 0 ) then
202  if( qnrm == 1.0d0 ) then
203  write(*,"(a,i8,a,1pe11.4,a,1pe11.4)") " iter:", iter, ", residual(abs):", rres, ", disp.corr.:", rxnrm
204  else
205  write(*,"(a,i8,a,1pe11.4,a,1pe11.4)") " iter:", iter, ", residual:", rres, ", disp.corr.:", rxnrm
206  endif
207  endif
208 
209  ! Convergence (skip if linear solver flagged divergence)
210  if( hecmw_mat_get_flag_diverged(hecmat) == kno ) then
211  if( rres < fstrsolid%step_ctrl(cstep)%converg .or. &
212  rxnrm < fstrsolid%step_ctrl(cstep)%converg_ddisp ) then
213  iterstatus = kitrconverged
214  return
215  endif
216  endif
217 
218  do_failure_check = .true.
219  res_for_check = rres
220 
221  ! =========================================================================
222  ! PATH 2: Static, contact (self-normalization by n_node_global)
223  ! =========================================================================
224  else if( .not. is_dynamic .and. is_contact ) then
225  res_sq = dot_product(residual_vec(1:nresid), residual_vec(1:nresid))
226  call hecmw_allreduce_r1(hecmesh, res_sq, hecmw_sum)
227  res_normalized = sqrt(res_sq) / dble(n_node_global)
228 
229  if( iter == 1 ) resb = res_normalized
230  if( resb == 0.0d0 ) then
231  resb = 1.0d0
232  else
233  relres = dabs(res_prev - res_normalized) / resb
234  endif
235 
236  if( hecmesh%my_rank == 0 ) then
237  if( iter == 1 ) then
238  write(*, '(a,i3,a,2e15.7)') ' - Residual(', iter, ') =', res_normalized, 0.0d0
239  else
240  write(*, '(a,i3,a,2e15.7)') ' - Residual(', iter, ') =', res_normalized, relres
241  endif
242  endif
243 
244  ! Convergence (iter==1: absolute only; iter>1: also relative)
245  if( iter > 1 ) then
246  if( res_normalized < fstrsolid%step_ctrl(cstep)%converg .or. &
247  relres < fstrsolid%step_ctrl(cstep)%converg_ddisp ) then
248  iterstatus = kitrconverged
249  res_prev = res_normalized
250  return
251  endif
252  else
253  if( res_normalized < fstrsolid%step_ctrl(cstep)%converg ) then
254  iterstatus = kitrconverged
255  res_prev = res_normalized
256  return
257  endif
258  endif
259 
260  res_prev = res_normalized
261 
262  do_failure_check = .true.
263  res_for_check = res_normalized
264 
265  ! =========================================================================
266  ! PATH 3: Dynamic, contact (self-normalization + maxDLag condition)
267  ! =========================================================================
268  else if( is_dynamic .and. is_contact ) then
269  res_sq = dot_product(residual_vec(1:nresid), residual_vec(1:nresid))
270  call hecmw_allreduce_r1(hecmesh, res_sq, hecmw_sum)
271 
272  if( iter == 1 ) resb = res_sq
273  res_normalized = dsqrt(res_sq / resb)
274 
275  ! Only check when nlgeom and ndof /= 4
276  if( fstrpr%nlgeom .and. ndof /= 4 ) then
277  if( hecmesh%my_rank == 0 ) then
278  write(*,'(a,i5,a,1pe12.4)') "iter: ", iter, ", res: ", res_normalized
279  write(ista,'(''iter='',I5,''- Residual'',E15.7)') iter, res_normalized
280  if( present(maxdlag) ) then
281  write(*,'(a,1e15.7)') ' - MaxDLag =', maxdlag
282  write(ista,'(a,1e15.7)') ' - MaxDLag =', maxdlag
283  endif
284  endif
285  if( present(maxdlag) .and. present(converg_dlag) ) then
286  if( res_normalized < fstrsolid%step_ctrl(cstep)%converg .and. &
287  maxdlag < converg_dlag ) then
288  iterstatus = kitrconverged
289  return
290  endif
291  else
292  if( res_normalized < fstrsolid%step_ctrl(cstep)%converg ) then
293  iterstatus = kitrconverged
294  return
295  endif
296  endif
297 
298  do_failure_check = .true.
299  res_for_check = res_normalized
300  endif
301 
302  endif
303 
304  end subroutine fstr_check_convergence_main
305 
306 end module m_fstr_iterationcontrol
This module provides a unified convergence check for Newton iteration.
subroutine, public fstr_check_convergence(hecMESH, hecMAT, fstrSOLID, fstrPR, ndof, iter, sub_step, cstep, residual_vec, nresid, resb, res_prev, n_node_global, iterStatus, maxDLag, converg_dlag)
Wrapper that calls fstr_check_convergence_main and applies the common divergence/NaN handling (status...
subroutine, public fstr_check_convergence_main(hecMESH, hecMAT, fstrSOLID, fstrPR, ndof, iter, cstep, residual_vec, nresid, resb, res_prev, n_node_global, iterStatus, do_failure_check, res_for_check, maxDLag, converg_dlag)
Core convergence check: computes residual norm, applies the per-path convergence criterion,...
This module defines common data and basic structures for analysis.
Definition: m_fstr.F90:15
integer(kind=kint), parameter kitrfloatingerror
Definition: m_fstr.F90:94
integer(kind=kint), parameter kstdynamic
Definition: m_fstr.F90:42
integer(kind=kint), parameter kitrconverged
Definition: m_fstr.F90:92
integer(kind=kint), parameter ilog
FILE HANDLER.
Definition: m_fstr.F90:109
integer(kind=kint), parameter ista
Definition: m_fstr.F90:110
type(fstr_param), target fstrpr
GLOBAL VARIABLE INITIALIZED IN FSTR_SETUP.
Definition: m_fstr.F90:212
integer(kind=kint), parameter kitrcontinue
iteration control
Definition: m_fstr.F90:91
integer(kind=kint), parameter kno
Definition: m_fstr.F90:33
integer(kind=kint), parameter kitrdiverged
Definition: m_fstr.F90:93
FSTR INNER CONTROL PARAMETERS (fstrPARAM)
Definition: m_fstr.F90:156