FrontISTR  6.0.0
Large-scale structural analysis program with finit element method
fstr_contact.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 !-------------------------------------------------------------------------------
33 module mcontact
34 
35  use mcontactdef
36  use hecmw
37  use m_fstr
45  implicit none
46 
47  logical, private :: active
48 
49  ! Re-export functions from sub-modules
51  public :: initialize_embed_vectors
53  public :: calc_contact_area
58 
59 contains
60 
61  subroutine fstr_addcontactstiffness(cstep,ctAlgo, iter,hecMESH,conMAT,hecLagMAT,fstrSOLID)
62 
63  integer(kind=kint) :: cstep
64  integer(kind=kint) :: ctAlgo
65  integer(kind=kint) :: iter
66  type(hecmwst_local_mesh) :: hecMESH
67  type(hecmwst_matrix) :: conMAT
68  type(fstr_solid) :: fstrSOLID
69  type(hecmwst_matrix_lagrange) :: hecLagMAT
70  integer(kind=kint) :: i, grpid
71 
72  if( associated(heclagmat%AL_lagrange) ) heclagmat%AL_lagrange = 0.0d0
73  if( associated(heclagmat%AU_lagrange) ) heclagmat%AU_lagrange = 0.0d0
74 
75  do i = 1, fstrsolid%n_contacts
76 
77  grpid = fstrsolid%contacts(i)%group
78  if( .not. fstr_iscontactactive( fstrsolid, grpid, cstep ) ) cycle
79 
80  if( fstrsolid%contacts(i)%method == contacts2s ) then
81  call calcu_contact_stiffness_surfsurf( ctalgo, fstrsolid%contacts(i), hecmesh%node(:), fstrsolid%unode(:), &
82  fstrsolid%dunode(:), conmat )
83  else
84  call calcu_contact_stiffness_nodesurf( ctalgo, fstrsolid%contacts(i), hecmesh%node(:), fstrsolid%unode(:), &
85  fstrsolid%dunode(:), iter, heclagmat%Lagrange(:), conmat, heclagmat)
86  endif
87  enddo
88 
89  do i = 1, fstrsolid%n_embeds
90 
91  grpid = fstrsolid%embeds(i)%group
92  if( .not. fstr_isembedactive( fstrsolid, grpid, cstep ) ) cycle
93 
94  call calcu_contact_stiffness_nodesurf( ctalgo, fstrsolid%embeds(i), hecmesh%node(:), fstrsolid%unode(:), &
95  fstrsolid%dunode(:), iter, heclagmat%Lagrange(:), conmat, heclagmat)
96 
97  enddo
98 
99  end subroutine fstr_addcontactstiffness
100 
102  subroutine fstr_update_ndforce_contact(cstep,ctAlgo,hecMESH,hecLagMAT,fstrSOLID,conMAT)
103  integer(kind=kint), intent(in) :: cstep
104  integer(kind=kint), intent(in) :: ctAlgo
105  type(hecmwst_local_mesh) :: hecMESH
106  type(fstr_solid) :: fstrSOLID
107  type(hecmwst_matrix_lagrange) :: hecLagMAT
108  type(hecmwst_matrix) :: conMAT
109 
110  call fstr_contact_ndforce_core(kctforresidual,cstep,ctalgo,hecmesh,heclagmat,fstrsolid,conmat)
111 
112  end subroutine fstr_update_ndforce_contact
113 
115  subroutine fstr_calc_contact_output_force(cstep,ctAlgo,hecMESH,hecLagMAT,fstrSOLID,conMAT)
116  integer(kind=kint), intent(in) :: cstep
117  integer(kind=kint), intent(in) :: ctAlgo
118  type(hecmwst_local_mesh) :: hecMESH
119  type(fstr_solid) :: fstrSOLID
120  type(hecmwst_matrix_lagrange) :: hecLagMAT
121  type(hecmwst_matrix) :: conMAT
122 
123  call fstr_contact_ndforce_core(kctforoutput,cstep,ctalgo,hecmesh,heclagmat,fstrsolid,conmat)
124 
125  end subroutine fstr_calc_contact_output_force
126 
136  subroutine fstr_calc_contact_output_force_exp( hecMESH, fstrSOLID )
137  type(hecmwst_local_mesh), intent(in) :: hecmesh
138  type(fstr_solid), intent(inout) :: fstrsolid
139 
140  integer(kind=kint) :: i
141 
142  if( .not. associated(fstrsolid%CONT_NFORCE) ) return
143  fstrsolid%CONT_NFORCE(:) = 0.d0
144  if( associated(fstrsolid%CONT_FRIC) ) fstrsolid%CONT_FRIC(:) = 0.d0
145 
146  do i = 1, fstrsolid%n_contacts
147  call calcu_contact_ndforce_exp( fstrsolid%contacts(i), hecmesh%node(:), &
148  fstrsolid%unode(:), fstrsolid%dunode(:), fstrsolid%CONT_NFORCE, fstrsolid%CONT_FRIC )
149  enddo
150 
152 
156  subroutine fstr_contact_ndforce_core(purpose,cstep,ctAlgo,hecMESH,hecLagMAT,fstrSOLID,conMAT)
157  integer(kind=kint), intent(in) :: purpose
158  integer(kind=kint), intent(in) :: cstep
159  integer(kind=kint), intent(in) :: ctAlgo
160  type(hecmwst_local_mesh) :: hecMESH
161  type(fstr_solid) :: fstrSOLID
162  type(hecmwst_matrix_lagrange) :: hecLagMAT
163  type(hecmwst_matrix) :: conMAT
164  integer(kind=kint) :: i, grpid
165 
166  ! Zero-clear output arrays only when computing for output
167  if( purpose == kctforoutput ) then
168  if( associated(fstrsolid%CONT_NFORCE) ) fstrsolid%CONT_NFORCE(:) = 0.d0
169  if( associated(fstrsolid%CONT_FRIC) ) fstrsolid%CONT_FRIC(:) = 0.d0
170  if( associated(fstrsolid%EMBED_NFORCE) ) fstrsolid%EMBED_NFORCE(:) = 0.d0
171  endif
172 
173  do i = 1, fstrsolid%n_contacts
174  grpid = fstrsolid%contacts(i)%group
175  if( .not. fstr_iscontactactive( fstrsolid, grpid, cstep ) ) cycle
176  if( fstrsolid%contacts(i)%method == contacts2s ) then
177  call calcu_contact_ndforce_surfsurf( purpose, ctalgo, fstrsolid%contacts(i), hecmesh%node(:), fstrsolid%unode(:), &
178  fstrsolid%dunode(:), conmat, fstrsolid%CONT_NFORCE, fstrsolid%CONT_FRIC )
179  else
180  call calcu_contact_ndforce_nodesurf( purpose, ctalgo, fstrsolid%contacts(i), hecmesh%node(:), fstrsolid%unode(:), &
181  fstrsolid%dunode(:), heclagmat%Lagrange(:), conmat, &
182  fstrsolid%CONT_NFORCE, fstrsolid%CONT_FRIC )
183  endif
184  enddo
185 
186  do i = 1, fstrsolid%n_embeds
187  grpid = fstrsolid%embeds(i)%group
188  if( .not. fstr_isembedactive( fstrsolid, grpid, cstep ) ) cycle
189  call calcu_contact_ndforce_nodesurf( purpose, ctalgo, fstrsolid%embeds(i), hecmesh%node(:), fstrsolid%unode(:), &
190  fstrsolid%dunode(:), heclagmat%Lagrange(:), conmat, &
191  fstrsolid%EMBED_NFORCE, fstrsolid%EMBED_NFORCE )
192  enddo
193 
194  end subroutine fstr_contact_ndforce_core
195 
197  subroutine fstr_calc_contact_refstiff(cstep, hecMESH, hecMAT, fstrSOLID)
199  integer(kind=kint), intent(in) :: cstep
200  type(hecmwst_local_mesh) :: hecMESH
201  type(hecmwst_matrix) :: hecMAT
202  type(fstr_solid) :: fstrSOLID
203 
204  integer(kind=kint) :: i, grpid, ndof
205  real(kind=kreal), pointer :: diag(:)
206 
207  ndof = hecmat%NDOF
208 
209  ! Extract diagonal components once (efficient, called only once)
210  diag => hecmw_mat_diag(hecmat)
211 
212  ! Loop over contact pairs
213  do i = 1, fstrsolid%n_contacts
214  grpid = fstrsolid%contacts(i)%group
215  if(.not. fstr_iscontactactive(fstrsolid, grpid, cstep)) cycle
216 
217  call calc_contact_pair_refstiff(fstrsolid%contacts(i), diag, ndof, hecmesh)
218  enddo
219 
220  ! Same for embeds
221  do i = 1, fstrsolid%n_embeds
222  grpid = fstrsolid%embeds(i)%group
223  if(.not. fstr_isembedactive(fstrsolid, grpid, cstep)) cycle
224 
225  call calc_contact_pair_refstiff(fstrsolid%embeds(i), diag, ndof, hecmesh)
226  enddo
227 
228  deallocate(diag)
229  end subroutine fstr_calc_contact_refstiff
230 
232  subroutine fstr_scan_contact_state( cstep, sub_step, cont_step, ctAlgo, hecMESH, fstrSOLID, infoCTChange )
233  integer(kind=kint), intent(in) :: cstep
234  integer(kind=kint), intent(in) :: sub_step
235  integer(kind=kint), intent(in) :: cont_step
236  integer(kind=kint), intent(in) :: ctAlgo
237  type( hecmwst_local_mesh ), intent(in) :: hecMESH
238  type(fstr_solid), intent(inout) :: fstrSOLID
239  type(fstr_info_contactchange), intent(inout):: infoCTChange
240  character(len=9) :: flag_ctAlgo
241  integer(kind=kint) :: i, j, k, grpid
242  integer(kind=kint) :: s_chg(3,3), s_emov, s_ebey, s_islid, s_act
243  integer(kind=kint), allocatable :: in_contact(:)
244  logical :: iactive, is_init
245 
246  if( associated( fstrsolid%CONT_RELVEL ) ) fstrsolid%CONT_RELVEL(:) = 0.d0
247  if( associated( fstrsolid%CONT_STATE ) ) fstrsolid%CONT_STATE(:) = 0.d0
248 
249  if( ctalgo == kcaslagrange ) then
250  flag_ctalgo = 'SLagrange'
251  elseif( ctalgo == kcaalagrange ) then
252  flag_ctalgo = 'ALagrange'
253  endif
254 
255  ! P.A. We redefine fstrSOLID%ddunode as current coordinate of every nodes
256  ! fstrSOLID%ddunode(:) = fstrSOLID%unode(:) + fstrSOLID%dunode(:)
257  do i = 1, size(fstrsolid%unode)
258  fstrsolid%ddunode(i) = hecmesh%node(i) + fstrsolid%unode(i) + fstrsolid%dunode(i)
259  enddo
260  active = .false.
261 
262  infoctchange%n_statechange = 0
263  infoctchange%contact2neighbor = 0
264  infoctchange%contact2beyond = 0
265  infoctchange%contact2diffLpos = 0
266  infoctchange%free2contact_new = 0
267  infoctchange%contactNode_current = 0
268 
269  is_init = ( cstep == 1 .and. sub_step == 1 .and. cont_step == 0 )
270 
271  do i=1,fstrsolid%n_contacts
272  grpid = fstrsolid%contacts(i)%group
273  if( .not. fstr_iscontactactive( fstrsolid, grpid, cstep ) ) then
274  call clear_contact_state(fstrsolid%contacts(i)); cycle
275  endif
276  if( fstrsolid%contacts(i)%method == contacts2s ) then
277  call scan_contact_state_ss( fstrsolid%contacts(i), fstrsolid%ddunode(:), infoctchange, is_init, iactive )
278  else
279  call scan_contact_state( fstrsolid%contacts(i), &
280  & fstrsolid%ddunode(:), fstrsolid%dunode(:), infoctchange, &
281  & hecmesh%global_node_ID(:), hecmesh%global_elem_ID(:), &
282  & is_init, iactive, hecmesh=hecmesh, &
283  & flag_ctalgo=flag_ctalgo, ndforce=fstrsolid%QFORCE(:) )
284  endif
285  if( .not. active ) active = iactive
286  enddo
287 
288  do i=1,fstrsolid%n_embeds
289  grpid = fstrsolid%embeds(i)%group
290  if( .not. fstr_isembedactive( fstrsolid, grpid, cstep ) ) then
291  call clear_contact_state(fstrsolid%embeds(i)); cycle
292  endif
293  call scan_embed_state( fstrsolid%embeds(i), fstrsolid%ddunode(:), &
294  & infoctchange, hecmesh%global_node_ID(:), hecmesh%global_elem_ID(:), is_init, iactive )
295  if( .not. active ) active = iactive
296  enddo
297  ! kept in infoCTChange as well, so that a cutback restores it together with the contact state
298  infoctchange%active = active
299 
300  if( is_init .and. ctalgo == kcaslagrange .and. fstrsolid%n_contacts > 0 ) &
301  & call remove_duplication_tiedcontact( cstep, hecmesh, fstrsolid, infoctchange )
302 
303  infoctchange%contactNode_current = infoctchange%contactNode_previous &
304  + sum(infoctchange%n_statechange(:,kcatcont)) - sum(infoctchange%n_statechange(kcatcont,:))
305  infoctchange%contactNode_previous = infoctchange%contactNode_current
306 
307  ! Output summary of contact state changes (always on; per-node detail requires CONTACT_LOG_LEVEL>=1)
308  ! allreduce must be called by all ranks regardless of local counts
309  s_chg = infoctchange%n_statechange
310  s_chg(kcatfree,kcatcont) = s_chg(kcatfree,kcatcont) + infoctchange%free2contact_new
311  s_emov = infoctchange%contact2neighbor
312  s_ebey = infoctchange%contact2beyond
313  s_islid = infoctchange%contact2diffLpos
314  s_act = infoctchange%contactNode_current
315  ! SURF-SURF pairs add the slave nodes of their segments in contact, as update_contact_state_vectors marks them.
316  ! A slave segment is kept by one rank only, so the marks are summed onto the owner of each node and counted there.
317  allocate( in_contact(hecmesh%n_node) )
318  in_contact(:) = 0
319  do i = 1, fstrsolid%n_contacts
320  if( fstrsolid%contacts(i)%method /= contacts2s ) cycle
321  do j = 1, size(fstrsolid%contacts(i)%slave_surf)
322  if( fstrsolid%contacts(i)%slave_surf(j)%state <= 0 ) cycle
323  do k = 1, size(fstrsolid%contacts(i)%slave_surf(j)%nodes)
324  in_contact(fstrsolid%contacts(i)%slave_surf(j)%nodes(k)) = 1
325  enddo
326  enddo
327  enddo
328  call hecmw_assemble_i(hecmesh, in_contact, hecmesh%n_node, 1)
329  do i = 1, hecmesh%nn_internal
330  if( in_contact(i) /= 0 ) s_act = s_act + 1
331  enddo
332  deallocate( in_contact )
333  call hecmw_allreduce_i(hecmesh, s_chg, 9, hecmw_sum)
334  call hecmw_allreduce_i1(hecmesh, s_emov, hecmw_sum)
335  call hecmw_allreduce_i1(hecmesh, s_ebey, hecmw_sum)
336  call hecmw_allreduce_i1(hecmesh, s_islid, hecmw_sum)
337  call hecmw_allreduce_i1(hecmesh, s_act, hecmw_sum)
338  if (hecmw_comm_get_rank() == 0) then
339  write(*,'(A,i7,A,i7,A,i7,A,i7,A,i7,A,i7)') ' Contact change: Free2Cont=', s_chg(kcatfree,kcatcont), &
340  ' Cont2Free=', s_chg(kcatcont,kcatfree), &
341  ' InnerSlid=', s_islid, ' MoveNeibr=', s_emov, ' MoveBynd=', s_ebey, ' ActiveNodes=', s_act
342  if( sum(s_chg(kcatnear,:)) + sum(s_chg(:,kcatnear)) > 0 ) &
343  write(*,'(A,i7,A,i7,A,i7,A,i7)') ' near state change: Free2Near=', s_chg(kcatfree,kcatnear), &
344  ' Near2Free=', s_chg(kcatnear,kcatfree), &
345  ' Near2Cont=', s_chg(kcatnear,kcatcont), ' Cont2Near=', s_chg(kcatcont,kcatnear)
346  end if
347 
348  if( .not. active ) then
349  if( associated( fstrsolid%CONT_NFORCE ) ) fstrsolid%CONT_NFORCE(:) = 0.d0
350  if( associated( fstrsolid%CONT_FRIC ) ) fstrsolid%CONT_FRIC(:) = 0.d0
351  end if
352 
353  end subroutine
354 
356  subroutine fstr_scan_contact_state_exp( cstep, is_init, hecMESH, fstrSOLID, infoCTChange )
357  integer(kind=kint), intent(in) :: cstep
358  logical, intent(in) :: is_init
359  type( hecmwst_local_mesh ), intent(in) :: hecMESH
360  type(fstr_solid), intent(inout) :: fstrSOLID
361  type(fstr_info_contactchange), intent(inout) :: infoCTChange
362 
363  integer(kind=kint) :: i, grpid
364  integer(kind=kint) :: s_chg(3,3), s_emov, s_ebey, s_islid, s_act
365  logical :: iactive
366 
367 
368  ! P.A. We redefine fstrSOLID%ddunode as current coordinate of every nodes
369  ! fstrSOLID%ddunode(:) = fstrSOLID%unode(:) + fstrSOLID%dunode(:)
370  do i = 1, size(fstrsolid%unode)
371  fstrsolid%ddunode(i) = hecmesh%node(i) + fstrsolid%unode(i) + fstrsolid%dunode(i)
372  enddo
373  infoctchange%active = .false.
374 
375  infoctchange%n_statechange = 0
376  infoctchange%contact2neighbor = 0
377  infoctchange%contact2beyond = 0
378  infoctchange%contact2diffLpos = 0
379  infoctchange%free2contact_new = 0
380  infoctchange%contactNode_current = 0
381 
382  do i=1,fstrsolid%n_contacts
383  grpid = fstrsolid%contacts(i)%group
384  if( .not. fstr_iscontactactive( fstrsolid, grpid, cstep ) ) then
385  call clear_contact_state(fstrsolid%contacts(i)); cycle
386  endif
387 
388  call scan_contact_state( fstrsolid%contacts(i), fstrsolid%ddunode(:), fstrsolid%dunode(:), &
389  & infoctchange, hecmesh%global_node_ID(:), hecmesh%global_elem_ID(:), is_init, iactive, hecmesh )
390 
391  infoctchange%active = infoctchange%active .or. iactive
392  enddo
393  call hecmw_allreduce_l1(hecmesh, infoctchange%active, hecmw_lor)
394 
395  infoctchange%contactNode_current = infoctchange%contactNode_previous &
396  + sum(infoctchange%n_statechange(:,kcatcont)) - sum(infoctchange%n_statechange(kcatcont,:))
397  infoctchange%contactNode_previous = infoctchange%contactNode_current
398 
399  ! Output summary of contact state changes (always on; per-node detail requires CONTACT_LOG_LEVEL>=1)
400  ! allreduce must be called by all ranks regardless of local counts
401  s_chg = infoctchange%n_statechange
402  s_chg(kcatfree,kcatcont) = s_chg(kcatfree,kcatcont) + infoctchange%free2contact_new
403  s_emov = infoctchange%contact2neighbor
404  s_ebey = infoctchange%contact2beyond
405  s_islid = infoctchange%contact2diffLpos
406  s_act = infoctchange%contactNode_current
407  call hecmw_allreduce_i(hecmesh, s_chg, 9, hecmw_sum)
408  call hecmw_allreduce_i1(hecmesh, s_emov, hecmw_sum)
409  call hecmw_allreduce_i1(hecmesh, s_ebey, hecmw_sum)
410  call hecmw_allreduce_i1(hecmesh, s_islid, hecmw_sum)
411  call hecmw_allreduce_i1(hecmesh, s_act, hecmw_sum)
412  if (hecmw_comm_get_rank() == 0) then
413  write(*,'(A,i7,A,i7,A,i7,A,i7,A,i7,A,i7)') ' Contact change: Free2Cont=', s_chg(kcatfree,kcatcont), &
414  ' Cont2Free=', s_chg(kcatcont,kcatfree), &
415  ' InnerSlid=', s_islid, ' MoveNeibr=', s_emov, ' MoveBynd=', s_ebey, ' ActiveNodes=', s_act
416  if( sum(s_chg(kcatnear,:)) + sum(s_chg(:,kcatnear)) > 0 ) &
417  write(*,'(A,i7,A,i7,A,i7,A,i7)') ' near state change: Free2Near=', s_chg(kcatfree,kcatnear), &
418  ' Near2Free=', s_chg(kcatnear,kcatfree), &
419  ' Near2Cont=', s_chg(kcatnear,kcatcont), ' Cont2Near=', s_chg(kcatcont,kcatnear)
420  end if
421 
422  fstrsolid%ddunode = 0.d0
423  end subroutine
424 
427  logical function fstr_is_contact_active()
428  fstr_is_contact_active = active
429  end function
430 
431  subroutine fstr_set_contact_active( a )
432  logical, intent(in) :: a
433  active = a
434  end subroutine
435 
438  subroutine fstr_set_contact_active_restart( cstep, fstrSOLID, infoCTChange )
439  integer(kind=kint), intent(in) :: cstep
440  type(fstr_solid), intent(in) :: fstrSOLID
441  type(fstr_info_contactchange), intent(inout) :: infoCTChange
442  integer(kind=kint) :: i, grpid
443 
444  active = infoctchange%contactNode_previous > 0
445  do i = 1, fstrsolid%n_contacts
446  if( active ) exit
447  if( fstrsolid%contacts(i)%method /= contactn2s ) cycle
448  if( .not. is_damping_enabled(fstrsolid%contacts(i)) ) cycle
449  grpid = fstrsolid%contacts(i)%group
450  if( .not. fstr_iscontactactive( fstrsolid, grpid, cstep ) ) cycle
451  active = any( fstrsolid%contacts(i)%states(:)%state == contactnear )
452  enddo
453  infoctchange%active = active
454  end subroutine
455 
456  logical function fstr_is_contact_conv(infoCTChange,hecMESH)
457  type (fstr_info_contactchange), intent(in) :: infoctchange
458  type (hecmwst_local_mesh), intent(in) :: hecmesh
459 
460  fstr_is_contact_conv = .false.
461  ! The two SURF-SURF counters are incremented on the mortar path only, so the sum is
462  ! unchanged for a NODE-SURF analysis.
463  if( sum(infoctchange%n_statechange) + infoctchange%contact2neighbor + infoctchange%contact2beyond + &
464  infoctchange%free2contact_new + infoctchange%contact2diffLpos == 0 ) &
465  fstr_is_contact_conv = .true.
466 
467  call hecmw_allreduce_l1(hecmesh, fstr_is_contact_conv, hecmw_land)
468  end function
469 
471  logical function fstr_is_matrixstructure_changed(infoCTChange)
472  type (fstr_info_contactchange) :: infoctchange
473  ! Matrix sparsity changes when a node connection appears or disappears. Each pair reports
474  ! through the counters of its sparsity_expansion mode, so a plain sum covers any mix.
475  ! contact2difflpos is excluded (no structural change).
477  if( sum(infoctchange%n_statechange) + infoctchange%contact2neighbor + infoctchange%contact2beyond + &
478  infoctchange%free2contact_new > 0 ) &
480  end function
481 
482  subroutine fstr_update_contact_multiplier( cstep, hecMESH, hecLagMAT, fstrSOLID, ctchanged )
483  integer(kind=kint), intent(in) :: cstep
484  type( hecmwst_local_mesh ), intent(in) :: hecMESH
485  type(hecmwst_matrix_lagrange), intent(in) :: hecLagMAT
486  type(fstr_solid), intent(inout) :: fstrSOLID
487  logical, intent(out) :: ctchanged
488 
489  integer(kind=kint) :: i, nc, algtype, grpid
490 
491  gnt = 0.d0; ctchanged = .false.
492  nc = fstrsolid%n_contacts+fstrsolid%n_embeds
493  do i=1, fstrsolid%n_contacts
494  grpid = fstrsolid%contacts(i)%group
495  if( .not. fstr_iscontactactive( fstrsolid, grpid, cstep ) ) cycle
496 
497  if( fstrsolid%contacts(i)%method == contacts2s ) then
498  call update_contact_multiplier_surfsurf( fstrsolid%contacts(i), hecmesh%node(:), fstrsolid%unode(:), &
499  fstrsolid%dunode(:), fstrsolid%contacts(i)%fcoeff )
500  else
501  algtype = fstrsolid%contacts(i)%algtype
502  if( algtype == contactsslid .or. algtype == contactfslid ) then
503  call update_contact_multiplier( fstrsolid%contacts(i), hecmesh%node(:), fstrsolid%unode(:), &
504  fstrsolid%dunode(:), fstrsolid%contacts(i)%fcoeff, &
505  hecmesh, heclagmat, gnt, ctchanged )
506  else if( algtype == contacttied ) then
507  call update_tied_multiplier( fstrsolid%contacts(i), fstrsolid%unode(:), fstrsolid%dunode(:), &
508  & ctchanged )
509  endif
510  endif
511  enddo
512 
513  do i=1, fstrsolid%n_embeds
514  call update_tied_multiplier( fstrsolid%embeds(i), fstrsolid%unode(:), fstrsolid%dunode(:), &
515  & ctchanged )
516  enddo
517 
518  call hecmw_allreduce_l1(hecmesh, ctchanged, hecmw_lor)
519 
520  if( nc>0 ) gnt = gnt/nc
521  end subroutine
522 
525  subroutine fstr_begin_lambda_txn( fstrSOLID, cstep )
526  type(fstr_solid), intent(inout) :: fstrSOLID
527  integer(kind=kint), intent(in) :: cstep
528  integer(kind=kint) :: i, s, grpid
529 
530  do i = 1, fstrsolid%n_contacts
531  if( fstrsolid%contacts(i)%method /= contacts2s ) cycle
532  grpid = fstrsolid%contacts(i)%group
533  if( .not. fstr_iscontactactive( fstrsolid, grpid, cstep ) ) cycle
534  if( .not. associated(fstrsolid%contacts(i)%slave_surf) ) cycle
535  do s = 1, size(fstrsolid%contacts(i)%slave_surf)
536  fstrsolid%contacts(i)%slave_surf(s)%lam_work_n = 0
537  fstrsolid%contacts(i)%slave_surf(s)%lam_work_id(:) = 0
538  fstrsolid%contacts(i)%slave_surf(s)%lam_work_val(:,:) = 0.d0
539  ! the tangential working accumulator is cleared alongside lam_work_val; the
540  ! stick/slip warm-start is read from begin at resolve time, not restored here
541  fstrsolid%contacts(i)%slave_surf(s)%lam_work_t(:,:,:) = 0.d0
542  fstrsolid%contacts(i)%slave_surf(s)%lam_work_fstate(:,:) = contactstick
543  enddo
544  enddo
545  end subroutine
546 
551  subroutine fstr_commit_lambda_txn( fstrSOLID, cstep )
552  type(fstr_solid), intent(inout) :: fstrSOLID
553  integer(kind=kint), intent(in) :: cstep
554  integer(kind=kint) :: i, s, grpid, r, m
555  type(tcontactsurf), pointer :: surf
556 
557  do i = 1, fstrsolid%n_contacts
558  if( fstrsolid%contacts(i)%method /= contacts2s ) cycle
559  grpid = fstrsolid%contacts(i)%group
560  if( .not. fstr_iscontactactive( fstrsolid, grpid, cstep ) ) cycle
561  if( .not. associated(fstrsolid%contacts(i)%slave_surf) ) cycle
562  do s = 1, size(fstrsolid%contacts(i)%slave_surf)
563  surf => fstrsolid%contacts(i)%slave_surf(s)
564  m = 0
565  ! The master is kept if at least one slave node is active against it.
566  do r = 1, surf%lam_work_n
567  if( maxval(surf%lam_work_val(1:size(surf%nodes),r)) > 0.d0 ) then
568  m = m + 1
569  surf%lam_begin_id(m) = surf%lam_work_id(r)
570  surf%lam_begin_val(1:size(surf%nodes),m) = surf%lam_work_val(1:size(surf%nodes),r)
571  ! the tangential multiplier rides along the master that passed the lambda_n filter
572  surf%lam_begin_t(:,1:size(surf%nodes),m) = surf%lam_work_t(:,1:size(surf%nodes),r)
573  surf%lam_begin_fstate(1:size(surf%nodes),m) = surf%lam_work_fstate(1:size(surf%nodes),r)
574  endif
575  enddo
576  surf%lam_begin_n = m
577  enddo
578  enddo
579  end subroutine
580 
582  subroutine fstr_update_contact_tangentforce( cstep, fstrSOLID )
583  integer(kind=kint), intent(in) :: cstep
584  type(fstr_solid), intent(inout) :: fstrSOLID
585 
586  integer(kind=kint) :: i, grpid
587 
588  do i=1, fstrsolid%n_contacts
589 
590  grpid = fstrsolid%contacts(i)%group
591  if( .not. fstr_iscontactactive( fstrsolid, grpid, cstep ) ) cycle
592 
593  call update_contact_tangentforce( fstrsolid%contacts(i) )
594  enddo
595  end subroutine
596 
598  subroutine fstr_update_contact_state_vectors( fstrSOLID, dt )
599  type(fstr_solid), intent(inout) :: fstrsolid
600  real(kind=kreal), intent(in) :: dt
601 
602  integer(kind=kint) :: i
603 
604  if( associated( fstrsolid%CONT_RELVEL ) ) fstrsolid%CONT_RELVEL(:) = 0.d0
605  if( associated( fstrsolid%CONT_STATE ) ) fstrsolid%CONT_STATE(:) = 0.d0
606 
607  do i=1, fstrsolid%n_contacts
608  call update_contact_state_vectors( fstrsolid%contacts(i), dt, fstrsolid%CONT_RELVEL, fstrsolid%CONT_STATE )
609  enddo
610  end subroutine
611 
612 end module mcontact
real(kind=kreal) function, dimension(:), pointer, public hecmw_mat_diag(hecMAT)
Extract diagonal components from matrix D into a 1D vector Returns: diag(i) = D(ndof*ndof*(node-1) + ...
Definition: hecmw.f90:6
Contact processing at assembly level (all pairs in one tContact object)
subroutine calcu_contact_stiffness_surfsurf(ctAlgo, contact, coord, disp, ddisp, hecMAT)
subroutine, public calc_contact_pair_refstiff(contact, diag, ndof, hecMESH)
Calculate reference stiffness for one contact pair.
subroutine calcu_contact_ndforce_surfsurf(purpose, ctAlgo, contact, coord, disp, ddisp, conMAT, CONT_NFORCE, CONT_FRIC)
subroutine calcu_contact_ndforce_exp(contact, coord, disp, ddisp, CONT_NFORCE, CONT_FRIC)
Compute contact nodal normal force for output from the stored contact multiplier, for the explicit dy...
subroutine update_contact_multiplier(contact, coord, disp, ddisp, fcoeff, hecMESH, hecLagMAT, gnt, ctchanged)
This subroutine update lagrangian multiplier and the distance between contacting nodes.
subroutine calcu_contact_ndforce_nodesurf(purpose, ctAlgo, contact, coord, disp, ddisp, lagrange_array, conMAT, CONT_NFORCE, CONT_FRIC)
This subroutine calculates contact nodal force for each contact pair and assembles it into contact ma...
subroutine calcu_contact_stiffness_nodesurf(ctAlgo, contact, coord, disp, ddisp, iter, lagrange_array, conMAT, hecLagMAT)
This subroutine calculates contact stiffness for each contact pair and assembles it into global stiff...
subroutine update_contact_tangentforce(contact)
subroutine update_tied_multiplier(contact, disp, ddisp, ctchanged)
This subroutine update lagrangian multiplier and the distance between contacting nodes.
subroutine update_contact_multiplier_surfsurf(contact, coord, disp, ddisp, fcoeff)
This subroutine updates the lagrangian multiplier of a mortar (MORTAR=YES) contact pair....
Contact damping module for CONTACTNEAR state.
pure logical function, public is_damping_enabled(contact)
Check if damping is enabled for a contact pair.
Contact mechanics calculations at element level (single contact pair)
This module provides geometric calculations for contact.
MPC (Multi-Point Constraint) processing for contact analysis.
Contact output vector processing (initialization, area calculation, parallel)
subroutine, public fstr_setup_parancon_contactvalue(hecMESH, ndof, vec, vtype)
subroutine, public setup_contact_elesurf_for_area(hecMESH, fstrSOLID)
subroutine, public calc_contact_area(hecMESH, fstrSOLID, flag)
subroutine, public initialize_contact_output_vectors(fstrSOLID, hecMAT)
subroutine, public initialize_embed_vectors(fstrSOLID, hecMAT)
subroutine, public update_contact_state_vectors(contact, dt, relvel_vec, state_vec)
Update contact state output vectors (CONT_RELVEL, CONT_STATE)
Contact search and state scanning at search level (all pairs in one tContact)
subroutine scan_embed_state(embed, currpos, infoCTChange, nodeID, elemID, is_init, active, B)
This subroutine update contact states, which include.
subroutine scan_contact_state(contact, currpos, currdisp, infoCTChange, nodeID, elemID, is_init, active, hecMESH, flag_ctAlgo, ndforce)
This subroutine update contact states, which include.
subroutine remove_duplication_tiedcontact(cstep, hecMESH, fstrSOLID, infoCTChange)
Scanning contact state.
subroutine scan_contact_state_ss(contact, currpos, infoCTChange, is_init, active)
Scan the contact state of every integration point of every slave segment of one SURF-SURF (mortar) co...
This module defines common data and basic structures for analysis.
Definition: m_fstr.F90:15
logical function fstr_isembedactive(fstrSOLID, nbc, cstep)
Definition: m_fstr.F90:1286
logical function fstr_iscontactactive(fstrSOLID, nbc, cstep)
Definition: m_fstr.F90:1276
integer(kind=kint), parameter kcaslagrange
contact analysis algorithm
Definition: m_fstr.F90:62
integer(kind=kint), parameter kcaalagrange
Definition: m_fstr.F90:63
Top-level contact analysis module (System level)
subroutine fstr_set_contact_active(a)
subroutine fstr_update_ndforce_contact(cstep, ctAlgo, hecMESH, hecLagMAT, fstrSOLID, conMAT)
Compute contact forces for residual vector (conMATB).
subroutine fstr_scan_contact_state(cstep, sub_step, cont_step, ctAlgo, hecMESH, fstrSOLID, infoCTChange)
Scanning contact state.
logical function fstr_is_matrixstructure_changed(infoCTChange)
Any state category change moves a Lagrange multiplier row or a slave-master coupling.
subroutine fstr_scan_contact_state_exp(cstep, is_init, hecMESH, fstrSOLID, infoCTChange)
Scanning contact state.
subroutine fstr_update_contact_multiplier(cstep, hecMESH, hecLagMAT, fstrSOLID, ctchanged)
subroutine fstr_set_contact_active_restart(cstep, fstrSOLID, infoCTChange)
Assembly flag on restart. The restart file holds the number of nodes in contact and the slave states ...
subroutine fstr_contact_ndforce_core(purpose, cstep, ctAlgo, hecMESH, hecLagMAT, fstrSOLID, conMAT)
Core routine: compute contact nodal forces for all contact/embed pairs. purpose == kctForResidual: as...
subroutine fstr_addcontactstiffness(cstep, ctAlgo, iter, hecMESH, conMAT, hecLagMAT, fstrSOLID)
subroutine fstr_calc_contact_output_force(cstep, ctAlgo, hecMESH, hecLagMAT, fstrSOLID, conMAT)
Compute contact forces for output (CONT_NFORCE/CONT_FRIC).
logical function fstr_is_contact_conv(infoCTChange, hecMESH)
subroutine, public fstr_update_contact_state_vectors(fstrSOLID, dt)
Update contact state output vectors for all contacts.
subroutine, public fstr_calc_contact_output_force_exp(hecMESH, fstrSOLID)
Explicit-dynamic counterpart of fstr_calc_contact_output_force.
subroutine fstr_calc_contact_refstiff(cstep, hecMESH, hecMAT, fstrSOLID)
Calculate reference stiffness for all contact pairs (System Level)
subroutine fstr_commit_lambda_txn(fstrSOLID, cstep)
COMMIT lambda transaction (MORTAR=YES only): keep the masters with a positive per-node lambda and swa...
subroutine fstr_begin_lambda_txn(fstrSOLID, cstep)
BEGIN lambda transaction (MORTAR=YES only): clear the working buffer. Called at the start of every su...
logical function fstr_is_contact_active()
Whether contact stiffness and residual have to be assembled. Broader than is_contact_active(state): a...
subroutine fstr_update_contact_tangentforce(cstep, fstrSOLID)
Update tangent force.
This module manages the data structure for contact calculation.
integer, parameter contactsslid
integer, parameter kcatcont
Lagrange multiplier held (STICK or SLIP)
integer, parameter kcatnear
projection only, no Lagrange multiplier
integer, parameter kctforresidual
purpose flag for contact force calculation
integer, parameter contacts2s
integer, parameter contactnear
near contact: projection info available, no LM constraint
real(kind=kreal), dimension(2), save gnt
1:current average penetration; 2:current relative tangent displacement
subroutine clear_contact_state(contact)
Reset contact state all to free.
integer, parameter contactn2s
contact method
integer, parameter contacttied
contact type or algorithm definition
integer, parameter kctforoutput
compute contact force for output (CONT_NFORCE/CONT_FRIC)
integer, parameter kcatfree
contact state category: states sharing a category contribute to the matrix in the same way
integer, parameter contactfslid
integer, parameter contactstick
Structure to define a slave surface segment of a SURF-SURF (mortar) contact pair.