FrontISTR  5.9.0
Large-scale structural analysis program with finit element method
fstr_solve_QuasiNewton.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 !-------------------------------------------------------------------------------
6 
8 
12 
13  implicit none
14  ! parameters for line search
15  real(kind=kreal), parameter :: c_line_search=2.0, psi0_line_search=1.0d-2
16  real(kind=kreal), parameter :: delta_wolfe=0.2, sigma_wolfe=0.9, eps_wolfe=1.0d-3
17  real(kind=kreal), parameter :: omega_wolfe=0.001, delta_approx_wolfe=0.7
18  real(kind=kreal) :: c_wolfe, q_wolfe
19  integer, parameter :: n_mem_max=10
20  integer(kind=kint), parameter :: maxiter_ls = 10
21  integer(kind=kint), parameter :: pot_type=1
22 
23 contains
24 
27  subroutine fstr_quasi_newton( cstep, hecMESH, hecMAT, fstrSOLID, fstrPARAM, &
28  restrt_step_num, sub_step, ctime, dtime )
29  implicit none
30 
31  integer, intent(in) :: cstep
32  type (hecmwST_local_mesh) :: hecMESH
33  type (hecmwST_matrix) :: hecMAT
34  type (fstr_solid) :: fstrSOLID
35  integer, intent(in) :: sub_step
36  real(kind=kreal), intent(in) :: ctime
37  real(kind=kreal), intent(in) :: dtime
38  type (fstr_param) :: fstrPARAM
39  type (hecmwST_matrix_lagrange) :: hecLagMAT
40 
41  type (hecmwST_local_mesh), pointer :: hecMESHmpc
42  type (hecmwST_matrix), pointer :: hecMATmpc
43  integer(kind=kint) :: ndof
44  integer(kind=kint) :: i, iter
45  integer(kind=kint) :: stepcnt
46  integer(kind=kint) :: restrt_step_num
47  real(kind=kreal) :: tt0, tt, res, qnrm, rres, tincr, xnrm, dunrm, rxnrm
48  logical :: isLinear = .false.
49  integer(kind=kint) :: iterStatus
50 
51  real(kind=kreal), allocatable :: z_k(:), s_k(:,:), y_k(:,:), g_prev(:), rho_k(:)
52  real(kind=kreal) :: sdoty
53  integer :: n_mem
54  integer :: len_vector
55  integer(kind=kint) :: k
56 
57  integer :: u_debug
58  integer :: max_iter_bak
59  logical :: flag_approx_Wolfe
60 
61  max_iter_bak = fstrsolid%step_ctrl(cstep)%max_iter
62  fstrsolid%step_ctrl(cstep)%max_iter = 100*fstrsolid%step_ctrl(cstep)%max_iter
63 
64  call hecmw_mpc_mat_init(hecmesh, hecmat, hecmeshmpc, hecmatmpc)
65 
66  if(.not. fstrpr%nlgeom)then
67  islinear = .true.
68  endif
69 
70  hecmat%NDOF = hecmesh%n_dof
71  ndof = hecmat%NDOF
72 
73  stepcnt = 0
74 
75  tincr = dtime
76  if( fstrsolid%step_ctrl(cstep)%solution == stepstatic ) tincr = 0.d0
77  call fstr_init_newton(hecmesh, hecmat, fstrsolid, ctime, tincr, iter, cstep, dtime, fstrparam, heclagmat, ndof, 0, hecmat)
78  fstrsolid%GL0(:) = fstrsolid%GL(:) !store external load at du=0
79 
80  !! initialize du for non-zero Dirichlet condition
81  call fstr_addbc(cstep, hecmesh, hecmat, fstrsolid, fstrparam, heclagmat, 1, rhsvector=fstrsolid%dunode)
82  !! update residual vector
83  call fstr_calc_residual_vector(hecmesh, hecmat, fstrsolid, ctime, tincr, iter, cstep, dtime, fstrparam)
84 
85  len_vector = hecmesh%n_node*ndof
86  allocate(z_k(len_vector))
87  allocate(s_k(len_vector, n_mem_max))
88  allocate(y_k(len_vector, n_mem_max))
89  allocate(g_prev(len_vector))
90  allocate(rho_k(n_mem_max))
91  z_k(:) = 0.0d0
92  s_k(:,:) = 0.0d0
93  y_k(:,:) = 0.0d0
94  g_prev(:) = 0.0d0
95  rho_k(:) = 0.0d0
96  do i=1,len_vector
97  y_k(i,1) = -hecmat%B(i)
98  enddo
99 
100  ! parameter to judge Wolfe/approx Wolfe selection
101  c_wolfe = 0.0d0
102  q_wolfe = 0.0d0
103  flag_approx_wolfe = .false.
104  n_mem = 1
105  ! ----- Inner Iteration, lagrange multiplier constant
106  do iter=1,fstrsolid%step_ctrl(cstep)%max_iter
107  stepcnt = stepcnt+1
108 
109  ! ----- calculate search direction by limited BFGS method
110  do i=1,hecmesh%n_node*ndof
111  g_prev(i) = -hecmat%B(i)
112  enddo
113  call fstr_calc_direction_lbfgs(hecmesh, g_prev, s_k, y_k, rho_k, z_k, n_mem)
114 
115  ! ! ----- Set Boundary condition
116  call fstr_addbc_to_direction_vector(z_k, hecmesh,fstrsolid, cstep)
117 
118  !----- line search of step length
119  call fstr_line_search_along_direction(hecmesh, hecmat, fstrsolid, ctime, tincr, iter, cstep, dtime, fstrparam, z_k)
120 
121  ! ----- update the small displacement and the displacement for 1step
122  ! \delta u^k => solver's solution
123  ! \Delta u_{n+1}^{k} = \Delta u_{n+1}^{k-1} + \delta u^k
124  call fstr_apply_solution_increment( hecmesh, fstrsolid, ndof, hecmat%X )
125 
126  !! set du for non-zero Dirichlet condition
127  ! call fstr_AddBC(cstep, hecMESH, hecMAT, fstrSOLID, fstrPARAM, hecLagMAT, 1, RHSvector=fstrSOLID%dunode)
128  call fstr_calc_residual_vector(hecmesh, hecmat, fstrsolid, ctime, tincr, iter, cstep, dtime, fstrparam)
129 
130  ! ----- check convergence
131  call fstr_check_convergence(hecmesh, hecmat, fstrsolid, fstrpr, &
132  ndof, iter, sub_step, cstep, &
133  hecmat%B, 0, &
134  res, res, &
135  0, &
136  iterstatus)
137  if (iterstatus == kitrconverged) exit
138  if (iterstatus == kitrdiverged .or. iterstatus==kitrfloatingerror) return
139  ! if (iterStatus == kitrDiverged) exit
140  ! if (iterStatus==kitrFloatingError) return
141 
142  n_mem = min(n_mem+1, n_mem_max)
143  do k=n_mem, 2, -1
144  s_k(:,k) = s_k(:,k-1)
145  y_k(:,k) = y_k(:,k-1)
146  rho_k(k) = rho_k(k-1)
147  enddo
148 
149  do i = 1, hecmesh%n_node*ndof
150  s_k(i,1) = hecmat%X(i)
151  y_k(i,1) = -hecmat%B(i) - g_prev(i)
152  enddo
153  call hecmw_innerproduct_r(hecmesh,ndof,s_k(:,1), y_k(:,1), sdoty)
154  if (abs(sdoty) < 1.0d-10) then
155  rho_k(1) = 0.0d0
156  else
157  rho_k(1) = 1.0d0/sdoty
158  endif
159  enddo
160  ! ----- end of inner loop
161 
162  fstrsolid%NRstat_i(knstmaxit) = max(fstrsolid%NRstat_i(knstmaxit),iter) ! logging newton iteration(maxtier)
163  fstrsolid%NRstat_i(knstsumit) = fstrsolid%NRstat_i(knstsumit) + iter ! logging newton iteration(sum of iter)
164 
165  ! ----- update the total displacement
166  ! u_{n+1} = u_{n} + \Delta u_{n+1}
167  call fstr_commit_solution_increment( hecmesh, fstrsolid, ndof )
168 
169  call fstr_updatestate( hecmesh, fstrsolid, tincr )
170 
171  fstrsolid%CutBack_stat = 0
172  call hecmw_mpc_mat_finalize(hecmesh, hecmat, hecmeshmpc, hecmatmpc)
173 
174  fstrsolid%step_ctrl(cstep)%max_iter = max_iter_bak
175  end subroutine fstr_quasi_newton
176 
177  subroutine fstr_calc_direction_lbfgs(hecMESH, g_prev, s_k, y_k, rho_k, z_k, n_mem)
178  implicit none
179 
180  type (hecmwST_local_mesh) :: hecMESH
181  real(kind=kreal) :: z_k(:), s_k(:,:), y_k(:,:), g_prev(:), rho_k(:)
182  integer :: n_mem
183 
184  real(kind=kreal), allocatable :: q(:)
185  real(kind=kreal) :: alpha(n_mem), beta
186  real(kind=kreal) :: sdotq, ysq, gamma, ydotz, g_max
187 
188  integer :: len_vector, ndof
189  integer(kind=kint) :: k,i
190 
191  ndof = hecmesh%n_dof
192  len_vector = hecmesh%n_node*hecmesh%n_dof
193  allocate(q(len_vector))
194 
195  q(1:len_vector) = g_prev(1:len_vector)
196 
197  do k=1, n_mem
198  call hecmw_innerproduct_r(hecmesh,ndof,s_k(:,k), q, sdotq)
199  alpha(k) = rho_k(k) * sdotq
200  do i=1, len_vector
201  q(i) = q(i) - alpha(k)*y_k(i,k)
202  enddo
203  enddo
204  call hecmw_innerproduct_r(hecmesh,ndof,y_k(:,1), y_k(:,1), ysq)
205  if (n_mem==1) then
206  call hecmw_absmax_r(hecmesh, ndof, g_prev, g_max)
207  ! if (g_max==0.0d0) then
208  ! write(6,*) 'gradient of potential is zero-vector'
209  ! stop
210  ! endif
211  ! gamma = 1.0d0/g_max
212  gamma = 1.0d0
213  else if (abs(rho_k(1)) < 1.0d-10) then
214  gamma = 1.0d0
215  else
216  gamma = 1.0d0/(rho_k(1)*ysq)
217  endif
218 
219  do i=1, len_vector
220  z_k(i) = gamma*q(i)
221  enddo
222 
223  do k=n_mem, 1, -1
224  call hecmw_innerproduct_r(hecmesh,ndof,y_k(:,k), z_k, ydotz)
225  beta = rho_k(k)*ydotz
226  do i=1, len_vector
227  z_k(i)=z_k(i) + s_k(i,k)*(alpha(k)-beta)
228  enddo
229  enddo
230  deallocate(q)
231  end subroutine fstr_calc_direction_lbfgs
232 
233  subroutine fstr_addbc_to_direction_vector(z_k, hecMESH,fstrSOLID, cstep)
234  implicit none
235  type (hecmwST_local_mesh) :: hecMESH
236  type (fstr_solid) :: fstrSOLID
237  integer(kind=kint) :: cstep
238  real(kind=kreal) :: z_k(:)
239 
240  integer(kind=kint) :: ig0, grpid, ig, ityp, idofS, idofE, iS0, iE0, ik, in, idof, ndof
241 
242  ndof = hecmesh%n_dof
243  ! ----- Prescibed displacement Boundary Conditions
244  do ig0 = 1, fstrsolid%BOUNDARY_ngrp_tot
245  grpid = fstrsolid%BOUNDARY_ngrp_GRPID(ig0)
246  if( .not. fstr_isboundaryactive( fstrsolid, grpid, cstep ) ) cycle
247  ig = fstrsolid%BOUNDARY_ngrp_ID(ig0)
248  ityp = fstrsolid%BOUNDARY_ngrp_type(ig0)
249  idofs = ityp/10
250  idofe = ityp - idofs*10
251  !
252  is0 = hecmesh%node_group%grp_index(ig-1) + 1
253  ie0 = hecmesh%node_group%grp_index(ig )
254  !
255  do ik = is0, ie0
256  in = hecmesh%node_group%grp_item(ik)
257  !
258  do idof = idofs, idofe
259  z_k(ndof*(in-1)+idof) = 0.0d0
260  enddo
261  enddo
262  enddo
263  end subroutine fstr_addbc_to_direction_vector
264 
265  subroutine fstr_apply_alpha0(hecMESH, hecMAT, fstrSOLID, ctime, tincr, iter, cstep, dtime, fstrPARAM, z_k, h_prime, pot)
266  implicit none
267  type (hecmwST_local_mesh) :: hecMESH
268  type (hecmwST_matrix) :: hecMAT
269  type (fstr_solid) :: fstrSOLID
270  real(kind=kreal), intent(in) :: ctime
271  real(kind=kreal), intent(in) :: tincr
272  integer(kind=kint) :: iter
273  integer, intent(in) :: cstep
274  real(kind=kreal), intent(in) :: dtime
275  type (fstr_param) :: fstrPARAM
276  real(kind=kreal), intent(in) :: z_k(:)
277  real(kind=kreal) :: h_prime, pot
278 
279  hecmat%X(:) = 0.0d0
280  call hecmw_innerproduct_r(hecmesh, hecmat%NDOF, hecmat%B, z_k, h_prime)
281  pot = fstr_get_potential(cstep,hecmesh,hecmat,fstrsolid,pot_type)
282  end subroutine fstr_apply_alpha0
283 
284  subroutine fstr_apply_alpha(hecMESH, hecMAT, fstrSOLID, ctime, tincr, iter, cstep, dtime, fstrPARAM, z_k, alpha, h_prime, pot)
285  implicit none
286  type (hecmwST_local_mesh) :: hecMESH
287  type (hecmwST_matrix) :: hecMAT
288  type (fstr_solid) :: fstrSOLID
289  real(kind=kreal), intent(in) :: ctime
290  real(kind=kreal), intent(in) :: tincr
291  integer(kind=kint) :: iter
292  integer, intent(in) :: cstep
293  real(kind=kreal), intent(in) :: dtime
294  type (fstr_param) :: fstrPARAM
295  real(kind=kreal), intent(in) :: z_k(:)
296  real(kind=kreal), intent(in) :: alpha
297  real(kind=kreal) :: h_prime, pot
298 
299  hecmat%X(:) = -alpha*z_k(:)
300  call fstr_calc_residual_vector_with_x(hecmesh, hecmat, fstrsolid, ctime, tincr, iter, cstep, dtime, fstrparam)
301  call hecmw_innerproduct_r(hecmesh, hecmat%NDOF, hecmat%B, z_k, h_prime)
302  pot = fstr_get_potential_with_x(cstep,hecmesh,hecmat,fstrsolid,pot_type)
303  end subroutine fstr_apply_alpha
304 
305  subroutine fstr_init_line_search_range(hecMESH, hecMAT, fstrSOLID, ctime, tincr, iter, cstep, dtime, fstrPARAM, z_k, &
306  h_prime_0, pot_0, alpha_S, h_prime_S, pot_S, alpha_E, h_prime_E, pot_E)
307  implicit none
308  type (hecmwST_local_mesh) :: hecMESH
309  type (hecmwST_matrix) :: hecMAT
310  type (fstr_solid) :: fstrSOLID
311  real(kind=kreal), intent(in) :: ctime
312  real(kind=kreal), intent(in) :: tincr
313  integer(kind=kint) :: iter
314  integer, intent(in) :: cstep
315  real(kind=kreal), intent(in) :: dtime
316  type (fstr_param) :: fstrPARAM
317  real(kind=kreal), intent(in) :: z_k(:)
318  real(kind=kreal), intent(in) :: h_prime_0, pot_0
319  real(kind=kreal) :: alpha_s, h_prime_s, pot_s
320  real(kind=kreal) :: alpha_e, h_prime_e, pot_e
321 
322  real(kind=kreal) :: alpha_s_new, h_prime_s_new, pot_s_new
323  real(kind=kreal) :: alpha_e_new, h_prime_e_new, pot_e_new
324  real(kind=kreal) :: alpha_tmp, h_prime_tmp, pot_tmp
325  real(kind=kreal) :: z_max
326  real(kind=kreal) :: pot_eps
327  pot_eps = eps_wolfe*c_wolfe
328 
329  alpha_s = 0.0d0
330  h_prime_s = h_prime_0
331  pot_s = pot_0
332 
333  if (iter==1) then
334  call hecmw_absmax_r(hecmesh, hecmat%NDOF, z_k, z_max)
335  alpha_e = psi0_line_search/z_max
336  else
337  alpha_e = 1.0d0
338  end if
339  call fstr_apply_alpha(hecmesh, hecmat, fstrsolid, ctime, tincr, iter, cstep, dtime, fstrparam, z_k, alpha_e, h_prime_e, pot_e)
340 
341  do while (h_prime_e < 0.0d0)
342  ! if (pot_E <= pot_0 + pot_eps) then
343  ! alpha_S = alpha_E
344  ! h_prime_S = h_prime_E ! so h_prime_S < 0
345  ! pot_S = h_prime_S
346 
347  alpha_e = alpha_e * c_line_search
348  call fstr_apply_alpha(hecmesh, hecmat, fstrsolid, ctime, tincr, iter, cstep, dtime, &
349  & fstrparam, z_k, alpha_e, h_prime_e, pot_e)
350  ! else
351  ! alpha_tmp = 2.0d0*alpha_E
352  ! h_prime_tmp = 0.0d0 ! elemact value
353  ! pot_tmp = 0.0d0 ! elemact value
354  ! call fstr_get_new_range_with_potential(hecMESH, hecMAT, fstrSOLID, ctime, tincr, iter, cstep, dtime, fstrPARAM, z_k, pot_0, &
355  ! alpha_S, h_prime_S, pot_S, alpha_tmp, h_prime_tmp, pot_tmp, alpha_E, h_prime_E, pot_E, &
356  ! alpha_S_new, h_prime_S_new, pot_S_new, alpha_E_new, h_prime_E_new, pot_E_new)
357 
358  ! alpha_S = alpha_S_new
359  ! h_prime_S = h_prime_S_new
360  ! pot_S = pot_S_new
361 
362  ! alpha_E = alpha_E_new
363  ! h_prime_E = h_prime_E_new
364  ! pot_E = pot_E_new
365  ! return
366  ! end if
367  enddo
368  end subroutine fstr_init_line_search_range
369 
370  subroutine fstr_update_range(hecMESH, hecMAT, fstrSOLID, ctime, tincr, iter, cstep, dtime, fstrPARAM, z_k, &
371  alpha_S, h_prime_S, pot_S, alpha_E, h_prime_E, pot_E, alpha_c, h_prime_c, pot_c, h_prime_0, pot_0)
372  implicit none
373  type (hecmwST_local_mesh) :: hecMESH
374  type (hecmwST_matrix) :: hecMAT
375  type (fstr_solid) :: fstrSOLID
376  real(kind=kreal), intent(in) :: ctime
377  real(kind=kreal), intent(in) :: tincr
378  integer(kind=kint) :: iter
379  integer, intent(in) :: cstep
380  real(kind=kreal), intent(in) :: dtime
381  type (fstr_param) :: fstrPARAM
382  real(kind=kreal) :: z_k(:)
383  real(kind=kreal) :: alpha_s, h_prime_s, pot_s
384  real(kind=kreal) :: alpha_e, h_prime_e, pot_e
385  real(kind=kreal) :: alpha_c, h_prime_c, pot_c
386  real(kind=kreal) :: h_prime_0, pot_0
387 
388  real(kind=kreal) :: alpha_a, h_prime_a, pot_a
389  real(kind=kreal) :: alpha_b, h_prime_b, pot_b
390  real(kind=kreal) :: alpha_a_bar, h_prime_a_bar, pot_a_bar
391  real(kind=kreal) :: alpha_b_bar, h_prime_b_bar, pot_b_bar
392  real(kind=kreal) :: alpha_c_bar, h_prime_c_bar, pot_c_bar
393 
394  call fstr_get_new_range_with_potential(hecmesh, hecmat, fstrsolid, ctime, tincr, iter, cstep, dtime, fstrparam, z_k, pot_0, &
395  alpha_s, h_prime_s, pot_s, alpha_e, h_prime_e, pot_e, alpha_c, h_prime_c, pot_c, &
396  alpha_a, h_prime_a, pot_a, alpha_b, h_prime_b, pot_b)
397 
398  if (alpha_c == alpha_a) then
399  call fstr_get_secant(alpha_s, h_prime_s, alpha_a, h_prime_a, alpha_c_bar)
400  call fstr_apply_alpha(hecmesh, hecmat, fstrsolid, ctime, tincr, iter, cstep, dtime, fstrparam, z_k, &
401  alpha_c_bar, h_prime_c_bar, pot_c_bar)
402  end if
403  if (alpha_c == alpha_b) then
404  call fstr_get_secant(alpha_b, h_prime_b, alpha_e, h_prime_e, alpha_c_bar)
405  call fstr_apply_alpha(hecmesh, hecmat, fstrsolid, ctime, tincr, iter, cstep, dtime, fstrparam, z_k, &
406  alpha_c_bar, h_prime_c_bar, pot_c_bar)
407  end if
408 
409  if ((alpha_c == alpha_a) .or. (alpha_c == alpha_b)) then
410  call fstr_get_new_range_with_potential(hecmesh, hecmat, fstrsolid, ctime, tincr, iter, cstep, dtime, fstrparam, z_k, pot_0, &
411  alpha_a, h_prime_a, pot_a, alpha_b, h_prime_b, pot_b, alpha_c_bar, h_prime_c_bar, pot_c_bar, &
412  alpha_a_bar, h_prime_a_bar, pot_a_bar, alpha_b_bar, h_prime_b_bar, pot_b_bar)
413  else
414  alpha_a_bar = alpha_a
415  h_prime_a_bar = h_prime_a
416  pot_a_bar = pot_a
417 
418  alpha_b_bar = alpha_b
419  h_prime_b_bar = h_prime_b
420  pot_b_bar = pot_b
421  end if
422 
423 
424  if ((alpha_b_bar - alpha_a_bar) > 0.66*(alpha_e - alpha_s)) then
425  alpha_c_bar = 0.5*(alpha_a_bar+alpha_b_bar)
426  call fstr_apply_alpha(hecmesh, hecmat, fstrsolid, ctime, tincr, iter, cstep, dtime, fstrparam, z_k, &
427  alpha_c_bar, h_prime_c_bar, pot_c_bar)
428  call fstr_get_new_range_with_potential(hecmesh, hecmat, fstrsolid, ctime, tincr, iter, cstep, dtime, fstrparam, z_k, pot_0, &
429  alpha_a, h_prime_a, pot_a, alpha_b, h_prime_b, pot_b, alpha_c_bar, h_prime_c_bar, pot_c_bar, &
430  alpha_s, h_prime_s, pot_s, alpha_e, h_prime_e, pot_e)
431  else
432  alpha_s = alpha_a_bar
433  h_prime_s = h_prime_a_bar
434  pot_s = pot_a_bar
435 
436  alpha_e = alpha_b_bar
437  h_prime_e = h_prime_b_bar
438  pot_e = pot_b_bar
439  end if
440  end subroutine fstr_update_range
441 
442  subroutine fstr_get_new_range_with_potential(hecMESH, hecMAT, fstrSOLID, ctime, tincr, iter, cstep, dtime, &
443  fstrPARAM, z_k, pot_0, alpha_a, h_prime_a, pot_a, alpha_b, h_prime_b, pot_b, alpha_c, h_prime_c, pot_c, &
444  alpha_a_bar, h_prime_a_bar, pot_a_bar, alpha_b_bar, h_prime_b_bar, pot_b_bar)
445  implicit none
446  type (hecmwST_local_mesh) :: hecMESH
447  type (hecmwST_matrix) :: hecMAT
448  type (fstr_solid) :: fstrSOLID
449  real(kind=kreal), intent(in) :: ctime
450  real(kind=kreal), intent(in) :: tincr
451  integer(kind=kint) :: iter
452  integer, intent(in) :: cstep
453  real(kind=kreal), intent(in) :: dtime
454  type (fstr_param) :: fstrPARAM
455  real(kind=kreal), intent(in) :: z_k(:)
456  real(kind=kreal), intent(in) :: pot_0
457  real(kind=kreal), intent(in) :: alpha_a, h_prime_a, pot_a
458  real(kind=kreal), intent(in) :: alpha_b, h_prime_b, pot_b
459  real(kind=kreal), intent(in) :: alpha_c, h_prime_c, pot_c
460  real(kind=kreal) :: alpha_a_bar, h_prime_a_bar, pot_a_bar
461  real(kind=kreal) :: alpha_b_bar, h_prime_b_bar, pot_b_bar
462 
463  integer, parameter :: count_max=100
464  integer :: count_while
465  real(kind=kreal) :: alpha_d, h_prime_d, pot_d
466  real(kind=kreal) :: theta_ls = 0.5d0
467  real(kind=kreal) :: pot_eps
468  pot_eps = eps_wolfe*c_wolfe
469 
470  ! case of NOT (a < c < b)
471  if (alpha_c <= alpha_a .or. alpha_b <= alpha_c) then
472  alpha_a_bar = alpha_a
473  h_prime_a_bar = h_prime_a
474  pot_a_bar = pot_a
475 
476  alpha_b_bar = alpha_b
477  h_prime_b_bar = h_prime_b
478  pot_b_bar = pot_b
479  return
480  end if
481 
482  if (h_prime_c >= 0.0d0) then
483  alpha_a_bar = alpha_a
484  h_prime_a_bar = h_prime_a
485  pot_a_bar = pot_a
486 
487  alpha_b_bar = alpha_c
488  h_prime_b_bar = h_prime_c
489  pot_b_bar = pot_c
490  return
491  end if
492  ! below here, it can be assumed that h_prime_c<0
493 
494  if(pot_c <= pot_0 + pot_eps) then
495  alpha_a_bar = alpha_c
496  h_prime_a_bar = h_prime_c
497  pot_a_bar = pot_c
498 
499  alpha_b_bar = alpha_b
500  h_prime_b_bar = h_prime_b
501  pot_b_bar = pot_b
502  return
503  end if
504 
505  alpha_a_bar = alpha_a
506  h_prime_a_bar = h_prime_a
507  pot_a_bar = pot_a
508 
509  alpha_b_bar = alpha_b
510  h_prime_b_bar = h_prime_b
511  pot_b_bar = pot_b
512 
513  count_while = 0
514  do while(count_while < count_max)
515  count_while = count_while + 1
516 
517  alpha_d = (1.0d0-theta_ls)*alpha_a_bar + theta_ls*alpha_b_bar
518  call fstr_apply_alpha(hecmesh, hecmat, fstrsolid, ctime, tincr, iter, cstep, dtime, fstrparam, z_k, alpha_d, h_prime_d, pot_d)
519 
520  if (h_prime_d >= 0.0d0) then
521  alpha_b_bar = alpha_d
522  h_prime_b_bar = h_prime_d
523  pot_b_bar = pot_d
524  return
525  end if
526 
527  if(pot_d <= pot_0 + pot_eps) then
528  alpha_a_bar = alpha_d
529  h_prime_a_bar = h_prime_d
530  pot_a_bar = pot_d
531  else
532  alpha_b_bar = alpha_d
533  h_prime_b_bar = h_prime_d
534  pot_b_bar = pot_d
535  end if
536  end do
537  write(6,*) 'fstr_get_new_range_with_potential reached loop count max.', hecmesh%my_rank, alpha_a_bar, alpha_b_bar
538  end subroutine fstr_get_new_range_with_potential
539 
540 
541  subroutine fstr_line_search_along_direction(hecMESH, hecMAT, fstrSOLID, ctime, tincr, iter, cstep, dtime, fstrPARAM, z_k)
542  implicit none
543  type (hecmwST_local_mesh) :: hecMESH
544  type (hecmwST_matrix) :: hecMAT
545  type (fstr_solid) :: fstrSOLID
546  real(kind=kreal), intent(in) :: ctime
547  real(kind=kreal), intent(in) :: tincr
548  integer(kind=kint) :: iter
549  integer, intent(in) :: cstep
550  real(kind=kreal), intent(in) :: dtime
551  type (fstr_param) :: fstrPARAM
552  real(kind=kreal) :: z_k(:)
553 
554  real(kind=kreal) :: alpha_s, h_prime_s, pot_s
555  real(kind=kreal) :: alpha_e, h_prime_e, pot_e
556  real(kind=kreal) :: alpha_c, h_prime_c, pot_c
557  real(kind=kreal) :: h_prime_0, pot_0
558  logical :: flag_converged
559  integer :: ndof, len_vector
560  real(kind=kreal) :: res
561 
562  integer(kind=kint) :: i, ierr, iter_ls
563  real(kind=kreal) :: z_max
564  integer :: elemact
565 
566  ndof = hecmat%NDOF
567  len_vector = hecmesh%n_node*hecmesh%n_dof
568 
569  call fstr_apply_alpha0(hecmesh, hecmat, fstrsolid, ctime, tincr, iter, cstep, dtime, fstrparam, z_k, h_prime_0, pot_0)
570  if (h_prime_0 > 0.0d0) then
571  write(6,*) 'residual vector is not directed to potential decretion.', h_prime_0
572  stop
573  endif
574 
575  call fstr_init_line_search_range(hecmesh, hecmat, fstrsolid, ctime, tincr, iter, cstep, dtime, &
576  fstrparam, z_k, h_prime_0, pot_0, alpha_s, h_prime_s, pot_s, alpha_e, h_prime_e, pot_e)
577  if( hecmesh%my_rank == 0 ) then
578  write(6,'(a, 6es27.16e3)') 'range initialized: alpha_S, alpha_E, h_prime_S, h_prime_E, pot_S, pot_E', &
579  & alpha_s, alpha_e, h_prime_s, h_prime_e, pot_s, pot_e
580  endif
581 
583  c_wolfe = c_wolfe + (abs(pot_0)-c_wolfe) / q_wolfe
584 
585  flag_converged = .false.
586  iter_ls=0
587  do while (iter_ls<maxiter_ls)
588  call fstr_get_secant(alpha_s, h_prime_s, alpha_e, h_prime_e, alpha_c)
589  call fstr_apply_alpha(hecmesh, hecmat, fstrsolid, ctime, tincr, iter, cstep, dtime, fstrparam, z_k, alpha_c, h_prime_c, pot_c)
590 
591  if (abs( pot_c - pot_0) <= (omega_wolfe * c_wolfe) ) then
592  flag_converged = fstr_approx_wolfe_condition(alpha_c, h_prime_c, pot_c, h_prime_0, pot_0)
593  else
594  flag_converged = fstr_wolfe_condition(alpha_c, h_prime_c, pot_c, h_prime_0, pot_0)
595  endif
596  if (flag_converged) exit
597 
598  call fstr_update_range(hecmesh, hecmat, fstrsolid, ctime, tincr, iter, cstep, dtime, fstrparam, z_k, &
599  alpha_s, h_prime_s, pot_s, alpha_e, h_prime_e, pot_e, alpha_c, h_prime_c, pot_c, h_prime_0, pot_0)
600  iter_ls = iter_ls +1
601  enddo
602  if( hecmesh%my_rank == 0 ) then
603  write(6,'(a, 1i8, 5es27.16e3)') 'converged: alpha_S, alpha_E, alpha_c, h_prime_c, pot_c', &
604  & iter_ls, &
605  & alpha_s, alpha_e, alpha_c, h_prime_c, pot_c
606  endif
607  end subroutine fstr_line_search_along_direction
608 
609  subroutine fstr_get_secant(a, Fa, b, Fb, c)
610  implicit none
611  real(kind=kreal), intent(in) :: a,b, fa,fb
612  real(kind=kreal), intent(out) :: c
613  if(fb /= fa) then
614  c = (a*fb - b*fa) / ( fb - fa )
615  else
616  c = 0.5*a + 0.5*b
617  endif
618  end subroutine fstr_get_secant
619 
620  function fstr_wolfe_condition(alpha_c, h_prime_c, pot_c, h_prime_0, pot_0) result(flag_converged)
621  implicit none
622  logical :: flag_converged
623 
624  real(kind=kreal), intent(in) :: alpha_c, h_prime_0, h_prime_c, pot_0, pot_c
625  real(kind=kreal) :: wolfe1_left, wolfe1_right, wolfe2_left, wolfe2_right
626 
627  wolfe1_left = pot_c - pot_0
628  wolfe1_right = delta_wolfe*h_prime_0*alpha_c
629 
630  wolfe2_left = h_prime_c
631  wolfe2_right = sigma_wolfe*h_prime_0
632 
633  flag_converged = (wolfe1_left<=wolfe1_right) .and. (wolfe2_left >= wolfe2_right)
634  if (flag_converged) write(6,'(a, 4es27.16e3)') 'oWolfe: ', wolfe1_left, wolfe1_right, wolfe2_left, wolfe2_right
635  end function fstr_wolfe_condition
636 
637  function fstr_approx_wolfe_condition(alpha_c, h_prime_c, pot_c, h_prime_0, pot_0) result(flag_converged)
638  implicit none
639  logical :: flag_converged
640 
641  real(kind=kreal), intent(in) :: alpha_c, h_prime_0, h_prime_c, pot_0, pot_c
642  real(kind=kreal) :: wolfe1_left, wolfe1_right, wolfe2_left, wolfe2_right
643 
644  real(kind=kreal) :: pot_eps
645  pot_eps = eps_wolfe*c_wolfe
646 
647  wolfe1_left = ( 2.0 * delta_wolfe - 1.0d0 ) * h_prime_0
648  wolfe1_right = h_prime_c
649 
650  wolfe2_left = h_prime_c
651  wolfe2_right = sigma_wolfe*h_prime_0
652 
653  flag_converged = &
654  (wolfe1_left>=wolfe1_right) &
655  .and. (wolfe2_left >= wolfe2_right) &
656  .and. (pot_c <= pot_0 + pot_eps)
657  if (flag_converged) write(6,'(a, 6es27.16e3)') 'aWolfe: ', wolfe1_left, wolfe1_right, &
658  & wolfe2_left, wolfe2_right, pot_c, pot_0 + (eps_wolfe*c_wolfe)
659  end function fstr_approx_wolfe_condition
660 end module m_fstr_quasinewton
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...
Finite-rotation nodal kinematics for NLGEOM.
subroutine, public fstr_apply_solution_increment(hecMESH, fstrSOLID, ndof, x)
Apply the linear-solver solution increment x to the step displacement dunode.
subroutine, public fstr_commit_solution_increment(hecMESH, fstrSOLID, ndof)
Commit the converged step increment dunode into the total displacement unode.
This module provides functions on nonlinear analysis.
subroutine fstr_init_newton(hecMESH, hecMAT, fstrSOLID, ctime, tincr, iter, cstep, dtime, fstrPARAM, hecLagMAT, ndof, ctAlgo, conMAT)
This module provides functions on nonlinear analysis.
real(kind=kreal), parameter delta_approx_wolfe
real(kind=kreal), parameter psi0_line_search
real(kind=kreal), parameter eps_wolfe
subroutine fstr_get_new_range_with_potential(hecMESH, hecMAT, fstrSOLID, ctime, tincr, iter, cstep, dtime, fstrPARAM, z_k, pot_0, alpha_a, h_prime_a, pot_a, alpha_b, h_prime_b, pot_b, alpha_c, h_prime_c, pot_c, alpha_a_bar, h_prime_a_bar, pot_a_bar, alpha_b_bar, h_prime_b_bar, pot_b_bar)
subroutine fstr_apply_alpha0(hecMESH, hecMAT, fstrSOLID, ctime, tincr, iter, cstep, dtime, fstrPARAM, z_k, h_prime, pot)
real(kind=kreal), parameter c_line_search
subroutine fstr_update_range(hecMESH, hecMAT, fstrSOLID, ctime, tincr, iter, cstep, dtime, fstrPARAM, z_k, alpha_S, h_prime_S, pot_S, alpha_E, h_prime_E, pot_E, alpha_c, h_prime_c, pot_c, h_prime_0, pot_0)
subroutine fstr_calc_direction_lbfgs(hecMESH, g_prev, s_k, y_k, rho_k, z_k, n_mem)
real(kind=kreal), parameter delta_wolfe
subroutine fstr_apply_alpha(hecMESH, hecMAT, fstrSOLID, ctime, tincr, iter, cstep, dtime, fstrPARAM, z_k, alpha, h_prime, pot)
integer, parameter n_mem_max
logical function fstr_wolfe_condition(alpha_c, h_prime_c, pot_c, h_prime_0, pot_0)
integer(kind=kint), parameter maxiter_ls
subroutine fstr_addbc_to_direction_vector(z_k, hecMESH, fstrSOLID, cstep)
subroutine fstr_line_search_along_direction(hecMESH, hecMAT, fstrSOLID, ctime, tincr, iter, cstep, dtime, fstrPARAM, z_k)
subroutine fstr_get_secant(a, Fa, b, Fb, c)
integer(kind=kint), parameter pot_type
subroutine fstr_init_line_search_range(hecMESH, hecMAT, fstrSOLID, ctime, tincr, iter, cstep, dtime, fstrPARAM, z_k, h_prime_0, pot_0, alpha_S, h_prime_S, pot_S, alpha_E, h_prime_E, pot_E)
real(kind=kreal), parameter omega_wolfe
logical function fstr_approx_wolfe_condition(alpha_c, h_prime_c, pot_c, h_prime_0, pot_0)
subroutine fstr_quasi_newton(cstep, hecMESH, hecMAT, fstrSOLID, fstrPARAM, restrt_step_num, sub_step, ctime, dtime)
This subroutine solve nonlinear solid mechanics problems by Newton-Raphson method.
real(kind=kreal), parameter sigma_wolfe