FrontISTR  6.0.0
Large-scale structural analysis program with finit element method
fstr_contact_search.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 !-------------------------------------------------------------------------------
8  use m_fstr
9  use hecmw
10  use elementinfo
11  use mcontactdef
18  implicit none
19 
20  integer(kind=kint), parameter :: contact_log_level = 0
21 
22 contains
23 
29  subroutine is_known_master_in_segment(contact, known_masters, n_known, id, is_known)
30  type(tcontact), intent(in) :: contact
31  integer(kind=kint), intent(inout) :: known_masters(:)
32  integer(kind=kint), intent(inout) :: n_known
33  integer(kind=kint), intent(in) :: id
34  logical, intent(out) :: is_known
35 
36  integer(kind=kint) :: k
37 
38  is_known = any(known_masters(1:n_known) == id)
39  if( .not. is_known .and. contact%sparsity_expansion == sparsity_neighbor ) then
40  ! neighbors of known masters are pre-registered in sparsity
41  do k = 1, n_known
42  if( associated(contact%master(known_masters(k))%neighbor) ) then
43  if( any(contact%master(known_masters(k))%neighbor(1:contact%master(known_masters(k))%n_neighbor) == id) ) then
44  is_known = .true.; exit
45  endif
46  endif
47  enddo
48  endif
49  if( .not. is_known ) then
50  n_known = n_known + 1
51  known_masters(n_known) = id
52  endif
53  end subroutine is_known_master_in_segment
54 
58  subroutine track_contact_position( nslave, contact, currpos, currdisp, infoCTChange, nodeID, elemID, flag_ctAlgo )
59  integer, intent(in) :: nslave
60  type( tcontact ), intent(inout) :: contact
61  type( fstr_info_contactchange ), intent(inout) :: infoCTChange
62  real(kind=kreal), intent(in) :: currpos(:)
63  real(kind=kreal), intent(in) :: currdisp(:)
64  integer(kind=kint), intent(in) :: nodeID(:)
65  integer(kind=kint), intent(in) :: elemID(:)
66  character(len=9), intent(in), optional :: flag_ctAlgo
67 
68  integer(kind=kint) :: slave, sid0, sid, etype
69  integer(kind=kint) :: nn, i, j, iSS
70  real(kind=kreal) :: coord(3), elem(3, l_max_elem_node), elem0(3, l_max_elem_node)
71  logical :: isin
72  real(kind=kreal) :: opos(2)
73  integer(kind=kint) :: bktID, nCand, idm, id_best
74  integer(kind=kint), allocatable :: indexCand(:)
75  logical :: is_implicit, update_tangent
76  type(tcontactstate) :: cstate_free, cstate_try, cstate_best
77 
78  is_implicit = present(flag_ctalgo)
79  if( is_implicit ) then
80  update_tangent = (flag_ctalgo == 'SLagrange')
81  else
82  update_tangent = .true.
83  endif
84 
85  sid = 0
86 
87  slave = contact%slave(nslave)
88  coord(:) = currpos(3*slave-2:3*slave)
90  sid0 = contact%states(nslave)%surface
91  opos = contact%states(nslave)%lpos(1:2)
92  etype = contact%master(sid0)%etype
93  nn = getnumberofnodes( etype )
94  do j=1,nn
95  iss = contact%master(sid0)%nodes(j)
96  elem0(1:3,j)=currpos(3*iss-2:3*iss)-currdisp(3*iss-2:3*iss)
97  enddo
98  call project_point2surfelement( coord, contact%master(sid0), currpos, &
99  contact%states(nslave), isin, contact%cparam%DISTCLR_NOCHECK, contact%cparam%PENCLR_NOCHECK, &
100  contact%states(nslave)%lpos(1:2), contact%cparam%CLR_SAME_ELEM, smoothing=contact%smoothing )
101  if( .not. isin ) then
102  ! The neighbors include the faces across a convex edge, which the loose checks of
103  ! DISTCLR_NOCHECK and PENCLR_NOCHECK accept at a large depth, so the nearest surface
104  ! is taken here as well as in the search of free nodes.
105  cstate_free = contact%states(nslave)
106  id_best = 0
107  do i=1, contact%master(sid0)%n_neighbor
108  sid = contact%master(sid0)%neighbor(i)
109  cstate_try = cstate_free
110  call project_point2surfelement( coord, contact%master(sid), currpos, &
111  cstate_try, isin, contact%cparam%DISTCLR_NOCHECK, contact%cparam%PENCLR_NOCHECK, &
112  localclr=contact%cparam%CLEARANCE, smoothing=contact%smoothing )
113  if( .not. isin ) cycle
114  if( id_best /= 0 ) then
115  if( dabs(cstate_try%distance) > dabs(cstate_best%distance) ) cycle
116  if( dabs(cstate_try%distance) == dabs(cstate_best%distance) .and. sid > id_best ) cycle
117  endif
118  id_best = sid
119  cstate_best = cstate_try
120  enddo
121  isin = ( id_best /= 0 )
122  if( isin ) then
123  sid = id_best
124  contact%states(nslave) = cstate_best
125  contact%states(nslave)%surface = sid
126  endif
127  endif
128 
129  if( .not. isin ) then ! such case is considered to rarely or never occur
130  !$omp critical
131  write(*,*) 'Warning: contact moved beyond neighbor elements'
132  !$omp end critical
133  cstate_free = contact%states(nslave)
134  ! get master candidates from bucketDB
135  bktid = bucketdb_getbucketid(contact%master_bktDB, coord)
136  ncand = bucketdb_getnumcand(contact%master_bktDB, bktid)
137  if (ncand > 0) then
138  allocate(indexcand(ncand))
139  call bucketdb_getcand(contact%master_bktDB, bktid, ncand, indexcand)
140  id_best = 0
141  do idm= 1, ncand
142  sid = indexcand(idm)
143  if( sid==sid0 ) cycle
144  if( associated(contact%master(sid0)%neighbor) ) then
145  if( any(sid==contact%master(sid0)%neighbor(1:contact%master(sid0)%n_neighbor)) ) cycle
146  endif
147  cstate_try = cstate_free
148  call project_point2surfelement( coord, contact%master(sid), currpos, &
149  cstate_try, isin, contact%cparam%DISTCLR_NOCHECK, contact%cparam%PENCLR_FREE, &
150  localclr=contact%cparam%CLEARANCE, smoothing=contact%smoothing )
151  if( .not. isin ) cycle
152  if( id_best /= 0 ) then
153  if( dabs(cstate_try%distance) > dabs(cstate_best%distance) ) cycle
154  if( dabs(cstate_try%distance) == dabs(cstate_best%distance) .and. sid > id_best ) cycle
155  endif
156  id_best = sid
157  cstate_best = cstate_try
158  enddo
159  deallocate(indexcand)
160  isin = ( id_best /= 0 )
161  if( isin ) then
162  sid = id_best
163  contact%states(nslave) = cstate_best
164  contact%states(nslave)%surface = sid
165  endif
166  endif
167  endif
168 
169  if( isin ) then
170  if( contact%states(nslave)%surface==sid0 ) then
171  if(any(dabs(contact%states(nslave)%lpos(1:2)-opos(:)) >= contact%cparam%CLR_DIFFLPOS)) then
172  !$omp atomic
173  infoctchange%contact2difflpos = infoctchange%contact2difflpos + 1
174  endif
175  else
176  if (contact_log_level >= 1) then
177  !$omp critical
178  write(*,'(A,i10,A,i10,A,f7.3,A,2f7.3)') "Node",nodeid(slave)," move to contact with", &
179  elemid(contact%master(sid)%eid), " with distance ", &
180  contact%states(nslave)%distance," at ",contact%states(nslave)%lpos(1:2)
181  !$omp end critical
182  endif
183  !$omp atomic
184  infoctchange%contact2neighbor = infoctchange%contact2neighbor + 1
185  endif
186  if( update_tangent .and. contact%fcoeff /= 0.d0 ) then
187  ! Setup elem array for update_TangentForce
188  etype = contact%master(contact%states(nslave)%surface)%etype
189  nn = size(contact%master(contact%states(nslave)%surface)%nodes)
190  do j=1,nn
191  iss = contact%master(contact%states(nslave)%surface)%nodes(j)
192  elem(1:3,j)=currpos(3*iss-2:3*iss)
193  enddo
194  call update_tangentforce(etype,nn,elem0,elem,contact%states(nslave))
195  endif
196  iss = isinsideelement( etype, contact%states(nslave)%lpos(1:2), contact%cparam%CLR_CAL_NORM )
197  if( iss>0 .and. contact%smoothing /= kcsnagata ) &
198  call cal_node_normal( contact%states(nslave)%surface, iss, contact%master, currpos, &
199  contact%states(nslave)%lpos(1:2), contact%states(nslave)%direction(:) )
200  else if( .not. isin ) then
201  if (contact_log_level >= 1) then
202  !$omp critical
203  write(*,'(A,i10,A)') "Node",nodeid(slave)," move out of contact"
204  !$omp end critical
205  endif
206  contact%states(nslave)%state = contactfree
207  contact%states(nslave)%multiplier(:) = 0.d0
208  endif
209 
210  end subroutine track_contact_position
211 
219  subroutine scan_contact_state( contact, currpos, currdisp, infoCTChange, &
220  nodeID, elemID, is_init, active, hecMESH, flag_ctAlgo, ndforce )
221  type( tcontact ), intent(inout) :: contact
222  type( fstr_info_contactchange ), intent(inout) :: infoCTChange
223  real(kind=kreal), intent(in) :: currpos(:)
224  real(kind=kreal), intent(in) :: currdisp(:)
225  integer(kind=kint), intent(in) :: nodeID(:)
226  integer(kind=kint), intent(in) :: elemID(:)
227  logical, intent(in) :: is_init
228  logical, intent(out) :: active
229  type( hecmwst_local_mesh ), intent(in), optional :: hecMESH
230  character(len=9), intent(in), optional :: flag_ctAlgo
231  real(kind=kreal), intent(in), optional :: ndforce(:)
232 
233  real(kind=kreal) :: distclr
234  integer(kind=kint) :: slave, id, etype
235  integer(kind=kint) :: i, iSS, nactive, icat_prev, icat_curr, surf_key
236  real(kind=kreal) :: coord(3)
237  real(kind=kreal) :: nlforce
238  logical :: isin
239  integer(kind=kint), allocatable :: contact_surf(:), states_prev(:)
240  integer(kind=kint), allocatable :: contact_prio(:), contact_prio_min(:)
241  real(kind=kreal) :: effective_near_dist, distclr_use
242  !
243  integer, pointer :: indexCand(:)
244  integer :: idm,bktID,nCand,id_best
245  type(tcontactstate) :: cstate_free, cstate_try, cstate_best
246  logical :: is_implicit
247 
248  is_implicit = present(flag_ctalgo)
249 
250  if( is_init ) then
251  distclr = contact%cparam%DISTCLR_INIT
252  else
253  distclr = contact%cparam%DISTCLR_FREE
254  if( contact%algtype == contacttied ) then
255  active = .false.
256  do i= 1, size(contact%slave)
257  if( contact%states(i)%state==contactstick ) then
258  active = .true.
259  exit
260  endif
261  enddo
262  endif
263  endif
264 
265  allocate(contact_surf(size(nodeid)))
266  allocate(contact_prio(size(nodeid)))
267  allocate(states_prev(size(contact%slave)))
268  contact_surf(:) = huge(0)
269  contact_prio(:) = huge(0)
270  do i = 1, size(contact%slave)
271  states_prev(i) = contact%states(i)%state
272  enddo
273 
274  if( contact%smoothing == kcsnagata ) then
275  call update_surface_normal( contact%master, currpos, hecmesh )
276  call create_intermediate_points( contact%master, currpos, contact%pair_name )
277  endif
278 
279  call update_surface_box_info( contact%master, currpos )
280  call update_surface_bucket_info( contact%master, contact%master_bktDB )
281 
282  ! Compute effective near distance for CONTACTNEAR detection
283  ! If damping is configured (damp_gact > 0), use it as the near distance
284  effective_near_dist = contact%cparam%NEAR_DIST
285  if (contact%damp_gact > 0.0d0) then
286  effective_near_dist = max(effective_near_dist, contact%damp_gact)
287  endif
288 
289  !$omp parallel do &
290  !$omp& default(none) &
291  !$omp& private(i,slave,id,nlforce,coord,iSS,idm,etype,isin, &
292  !$omp& bktID,nCand,indexCand,distclr_use,id_best,cstate_free,cstate_try,cstate_best) &
293  !$omp& firstprivate(is_implicit,effective_near_dist) &
294  !$omp& shared(contact,ndforce,flag_ctAlgo,infoCTChange,currpos,currdisp,nodeID,elemID,distclr,contact_surf,contact_prio, &
295  !$omp& is_init) &
296  !$omp& reduction(.or.:active) &
297  !$omp& schedule(dynamic,1)
298  do i= 1, size(contact%slave)
299  if(contact%if_type /= 0) call set_shrink_factor(contact%ctime, contact%states(i), contact%if_etime, contact%if_type)
300  slave = contact%slave(i)
301  if( contact%states(i)%state==contactstick .or. contact%states(i)%state==contactslip ) then
302  id = contact%states(i)%surface
303  nlforce = contact%states(i)%multiplier(1)
304 
305  ! update direction of TIED contact
306  if( contact%algtype == contacttied ) then
307  call update_direction( i, contact, currpos )
308  if (.not.is_init) cycle
309  endif
310 
311  if( nlforce < contact%cparam%TENSILE_FORCE ) then
312  contact%states(i)%multiplier(:) = 0.d0
313  if( effective_near_dist > 0.0d0 ) then
314  ! keep the projection so that the NEAR branch re-projects on the next scan and
315  ! decides between NEAR and FREE with an up-to-date distance
316  contact%states(i)%state = contactnear
317  contact_surf(contact%slave(i)) = elemid(contact%master(id)%eid)
318  contact_prio(contact%slave(i)) = 1
319  if (contact_log_level >= 1) then
320  !$omp critical
321  write(*,'(A,i10,A,i10,A,e12.3)') "Node",nodeid(slave), &
322  " released to near contact with element", &
323  elemid(contact%master(id)%eid), " with tensile force ", nlforce
324  !$omp end critical
325  endif
326  else
327  contact%states(i)%state = contactfree
328  if (contact_log_level >= 1) then
329  !$omp critical
330  write(*,'(A,i10,A,i10,A,e12.3)') "Node",nodeid(slave)," free from contact with element", &
331  elemid(contact%master(id)%eid), " with tensile force ", nlforce
332  !$omp end critical
333  endif
334  endif
335  cycle
336  endif
337  if( contact%algtype /= contactfslid ) then ! small slide problem
338  contact_surf(contact%slave(i)) = -elemid(contact%master(id)%eid)
339  contact_prio(contact%slave(i)) = 0
340  else
341  if( is_implicit ) then
342  call track_contact_position( i, contact, currpos, currdisp, infoctchange, nodeid, elemid, &
343  flag_ctalgo=flag_ctalgo )
344  else
345  call track_contact_position( i, contact, currpos, currdisp, infoctchange, nodeid, elemid )
346  endif
347  if( contact%states(i)%state /= contactfree ) then
348  id = contact%states(i)%surface
349  contact_surf(contact%slave(i)) = -elemid(contact%master(id)%eid)
350  contact_prio(contact%slave(i)) = 0
351  endif
352  endif
353 
354  else if( contact%states(i)%state==contactnear ) then
355  ! NEAR tracking: re-project on current master surface
356  coord(:) = currpos(3*slave-2:3*slave)
357  id = contact%states(i)%surface
358  if (effective_near_dist > 0.0d0) then
359  distclr_use = max(distclr, effective_near_dist / contact%master(id)%reflen)
360  else
361  distclr_use = distclr
362  end if
363  call project_point2surfelement( coord, contact%master(id), currpos, &
364  contact%states(i), isin, distclr_use, contact%cparam%PENCLR_FREE, &
365  contact%states(i)%lpos(1:2), contact%cparam%CLR_SAME_ELEM, smoothing=contact%smoothing )
366  if (isin) then
367  if (contact%states(i)%distance <= distclr * contact%master(id)%reflen) then
368  ! Within contact threshold -> upgrade to STICK
369  contact%states(i)%state = contactstick
370  contact%states(i)%multiplier(:) = 0.d0
371  if (contact_log_level >= 1) then
372  !$omp critical
373  write(*,'(A,i10,A,i10,A,i6)') "Node",nodeid(slave)," upgraded NEAR->STICK on element", &
374  elemid(contact%master(id)%eid)," rank=",hecmw_comm_get_rank()
375  !$omp end critical
376  endif
377  else if (contact%states(i)%distance > effective_near_dist) then
378  ! Beyond NEAR range -> free
379  contact%states(i)%state = contactfree
380  contact%states(i)%multiplier(:) = 0.d0
381  end if
382  ! else: stay NEAR
383  if (.not. is_contact_free(contact%states(i)%state)) then
384  etype = contact%master(id)%etype
385  iss = isinsideelement( etype, contact%states(i)%lpos(1:2), contact%cparam%CLR_CAL_NORM )
386  if( iss>0 .and. contact%smoothing /= kcsnagata ) &
387  call cal_node_normal( id, iss, contact%master, currpos, &
388  contact%states(i)%lpos(1:2), contact%states(i)%direction(:) )
389  contact_surf(contact%slave(i)) = elemid(contact%master(id)%eid)
390  contact_prio(contact%slave(i)) = 1
391  end if
392  else
393  ! Lost projection -> free
394  contact%states(i)%state = contactfree
395  contact%states(i)%multiplier(:) = 0.d0
396  end if
397 
398  else if( contact%states(i)%state==contactfree ) then
399  if( contact%algtype == contacttied .and. .not. is_init ) cycle
400  coord(:) = currpos(3*slave-2:3*slave)
401 
402  ! get master candidates from bucketDB
403  bktid = bucketdb_getbucketid(contact%master_bktDB, coord)
404  ncand = bucketdb_getnumcand(contact%master_bktDB, bktid)
405  if (ncand == 0) cycle
406  allocate(indexcand(ncand))
407  call bucketdb_getcand(contact%master_bktDB, bktid, ncand, indexcand)
408 
409  ! The bucket collects candidates in scan order, not in distance order, so every
410  ! candidate is projected on a trial state and the closest one is adopted. Equal
411  ! distances are settled by the master index so that the choice never depends on
412  ! the order the bucket happened to return.
413  id_best = 0
414  cstate_free = contact%states(i)
415  do idm = 1,ncand
416  id = indexcand(idm)
417  ! Expand distclr for NEAR detection
418  if (effective_near_dist > 0.0d0) then
419  distclr_use = max(distclr, effective_near_dist / contact%master(id)%reflen)
420  else
421  distclr_use = distclr
422  end if
423  cstate_try = cstate_free
424  call project_point2surfelement( coord, contact%master(id), currpos, &
425  cstate_try, isin, distclr_use, contact%cparam%PENCLR_FREE, &
426  localclr=contact%cparam%CLEARANCE, smoothing=contact%smoothing )
427  if( .not. isin ) cycle
428  if( id_best /= 0 ) then
429  if( dabs(cstate_try%distance) > dabs(cstate_best%distance) ) cycle
430  if( dabs(cstate_try%distance) == dabs(cstate_best%distance) .and. id > id_best ) cycle
431  endif
432  id_best = id
433  cstate_best = cstate_try
434  enddo
435  deallocate(indexcand)
436  if( id_best == 0 ) cycle
437 
438  id = id_best
439  contact%states(i) = cstate_best
440  ! Classify: STICK or NEAR
441  if (effective_near_dist > 0.0d0 .and. &
442  contact%states(i)%distance > distclr * contact%master(id)%reflen) then
443  contact%states(i)%state = contactnear
444  end if
445  contact%states(i)%surface = id
446  contact%states(i)%multiplier(:) = 0.d0
447  etype = contact%master(id)%etype
448  iss = isinsideelement( etype, contact%states(i)%lpos(1:2), contact%cparam%CLR_CAL_NORM )
449  if( iss>0 .and. contact%smoothing /= kcsnagata ) &
450  call cal_node_normal( id, iss, contact%master, currpos, contact%states(i)%lpos(1:2), &
451  contact%states(i)%direction(:) )
452  contact_surf(contact%slave(i)) = elemid(contact%master(id)%eid)
453  contact_prio(contact%slave(i)) = 1
454  if (contact_log_level >= 1) then
455  !$omp critical
456  if (contact%states(i)%state == contactnear) then
457  write(*,'(A,i10,A,i10,A,f7.3,A,i6)') "Node",nodeid(slave)," near element", &
458  elemid(contact%master(id)%eid), &
459  " with distance ", contact%states(i)%distance," rank=",hecmw_comm_get_rank()
460  else
461  write(*,'(A,i10,A,i10,A,f7.3,A,2f7.3,A,3f7.3,A,i6)') "Node",nodeid(slave)," contact with element", &
462  elemid(contact%master(id)%eid), &
463  " with distance ", contact%states(i)%distance," at ",contact%states(i)%lpos(1:2), &
464  " along direction ", contact%states(i)%direction," rank=",hecmw_comm_get_rank()
465  end if
466  !$omp end critical
467  end if
468  endif
469  enddo
470  !$omp end parallel do
471 
472  if( contact%algtype == contacttied .and. .not. is_init ) then
473  deallocate(contact_surf)
474  deallocate(contact_prio)
475  deallocate(states_prev)
476  return
477  endif
478 
479  ! continued contacts take precedence; the sign of contact_surf cannot tell them apart
480  ! because a refined mesh has negative element IDs
481  allocate(contact_prio_min(size(nodeid)))
482  contact_prio_min(:) = contact_prio(:)
483  call hecmw_contact_comm_allreduce_i(contact%comm, contact_prio_min, hecmw_min)
484  where( contact_prio(:) > contact_prio_min(:) ) contact_surf(:) = huge(0)
485  call hecmw_contact_comm_allreduce_i(contact%comm, contact_surf, hecmw_min)
486  nactive = 0
487  do i = 1, size(contact%slave)
488  if (.not. is_contact_free(contact%states(i)%state)) then ! any slave in contact or near
489  id = contact%states(i)%surface
490  surf_key = elemid(contact%master(id)%eid)
491  if (contact_prio(contact%slave(i)) == 0) surf_key = -surf_key
492  if (contact_prio(contact%slave(i)) /= contact_prio_min(contact%slave(i)) .or. &
493  & contact_surf(contact%slave(i)) /= surf_key) then ! that is in contact with other surface
494  contact%states(i)%state = contactfree ! should be freed
495  if (contact_log_level >= 1) &
496  & write(*,'(A,i10,A,i10,A,i6,A,i6,A)') "Node",nodeid(contact%slave(i)), &
497  & " contact with element",elemid(contact%master(id)%eid), &
498  & " in rank",hecmw_comm_get_rank()," freed due to duplication"
499  else if (is_contact_active(contact%states(i)%state) .or. is_damping_enabled(contact)) then
500  nactive = nactive + 1 ! a NEAR node with damping also contributes stiffness and residual
501  endif
502  endif
503  icat_prev = contact_state_category(states_prev(i))
504  icat_curr = contact_state_category(contact%states(i)%state)
505  if (icat_prev /= icat_curr) infoctchange%n_statechange(icat_prev,icat_curr) = &
506  infoctchange%n_statechange(icat_prev,icat_curr) + 1
507  enddo
508  active = (nactive > 0)
509  deallocate(contact_surf)
510  deallocate(contact_prio, contact_prio_min)
511  deallocate(states_prev)
512  end subroutine scan_contact_state
513 
517  subroutine scan_embed_state( embed, currpos, infoCTChange, &
518  nodeID, elemID, is_init, active, B )
519  type( tcontact ), intent(inout) :: embed
520  type( fstr_info_contactchange ), intent(inout) :: infoCTChange
521  real(kind=kreal), intent(in) :: currpos(:)
522  integer(kind=kint), intent(in) :: nodeID(:)
523  integer(kind=kint), intent(in) :: elemID(:)
524  logical, intent(in) :: is_init
525  logical, intent(out) :: active
526  real(kind=kreal), optional, target :: b(:)
527 
528  real(kind=kreal) :: distclr
529  integer(kind=kint) :: slave, id, etype
530  integer(kind=kint) :: nn, i, j, iSS, nactive, icat_prev, icat_curr
531  real(kind=kreal) :: coord(3), elem(3, l_max_elem_node )
532  logical :: isin
533  integer(kind=kint), allocatable :: contact_surf(:), states_prev(:)
534  !
535  integer, pointer :: indexCand(:)
536  integer :: idm,bktID,nCand,id_best
537  type(tcontactstate) :: cstate_free, cstate_try, cstate_best
538  logical :: is_present_B
539  real(kind=kreal), pointer :: bp(:)
540 
541  if( is_init ) then
542  distclr = embed%cparam%DISTCLR_INIT
543  else
544  distclr = embed%cparam%DISTCLR_FREE
545  active = .false.
546  do i= 1, size(embed%slave)
547  if( embed%states(i)%state==contactstick ) then
548  active = .true.
549  exit
550  endif
551  enddo
552  return
553  endif
554 
555  allocate(contact_surf(size(nodeid)))
556  allocate(states_prev(size(embed%slave)))
557  contact_surf(:) = huge(0)
558  do i = 1, size(embed%slave)
559  states_prev(i) = embed%states(i)%state
560  enddo
561 
562  call update_surface_box_info( embed%master, currpos )
563  call update_surface_bucket_info( embed%master, embed%master_bktDB )
564 
565  ! for gfortran-10: optional parameter seems not allowed within omp parallel
566  is_present_b = present(b)
567  if( is_present_b ) bp => b
568 
569  !$omp parallel do &
570  !$omp& default(none) &
571  !$omp& private(i,slave,id,coord,nn,j,iSS,elem,idm,etype,isin, &
572  !$omp& bktID,nCand,indexCand,id_best,cstate_free,cstate_try,cstate_best) &
573  !$omp& firstprivate(is_present_B) &
574  !$omp& shared(embed,infoCTChange,currpos,nodeID,elemID,Bp,distclr,contact_surf) &
575  !$omp& reduction(.or.:active) &
576  !$omp& schedule(dynamic,1)
577  do i= 1, size(embed%slave)
578  slave = embed%slave(i)
579  if( embed%states(i)%state==contactfree ) then
580  coord(:) = currpos(3*slave-2:3*slave)
581 
582  ! get master candidates from bucketDB
583  bktid = bucketdb_getbucketid(embed%master_bktDB, coord)
584  ncand = bucketdb_getnumcand(embed%master_bktDB, bktid)
585  if (ncand == 0) cycle
586  allocate(indexcand(ncand))
587  call bucketdb_getcand(embed%master_bktDB, bktid, ncand, indexcand)
588 
589  ! As in scan_contact_state, the bucket order is not a distance order, so every
590  ! candidate is evaluated on a trial state and the closest element is adopted.
591  id_best = 0
592  cstate_free = embed%states(i)
593  do idm = 1,ncand
594  id = indexcand(idm)
595  etype = embed%master(id)%etype
596  if( mod(etype,10) == 2 ) etype = etype - 1 !search by 1st-order shape function
597  nn = getnumberofnodes(etype)
598  do j=1,nn
599  iss = embed%master(id)%nodes(j)
600  elem(1:3,j)=currpos(3*iss-2:3*iss)
601  enddo
602  cstate_try = cstate_free
603  call project_point2solidelement( coord,etype,nn,elem,cstate_try, &
604  isin,distclr,localclr=embed%cparam%CLEARANCE )
605  if( .not. isin ) cycle
606  if( id_best /= 0 ) then
607  if( cstate_try%distance > cstate_best%distance ) cycle
608  if( cstate_try%distance == cstate_best%distance .and. id > id_best ) cycle
609  endif
610  id_best = id
611  cstate_best = cstate_try
612  enddo
613  deallocate(indexcand)
614  if( id_best == 0 ) cycle
615 
616  id = id_best
617  embed%states(i) = cstate_best
618  embed%states(i)%surface = id
619  embed%states(i)%multiplier(:) = 0.d0
620  contact_surf(embed%slave(i)) = elemid(embed%master(id)%eid)
621  if (contact_log_level >= 1) then
622  !$omp critical
623  write(*,'(A,i10,A,i10,A,3f7.3,A,i6)') "Node",nodeid(slave)," embeded to element", &
624  elemid(embed%master(id)%eid), " at ",embed%states(i)%lpos(:)," rank=",hecmw_comm_get_rank()
625  !$omp end critical
626  endif
627  endif
628  enddo
629  !$omp end parallel do
630 
631  call hecmw_contact_comm_allreduce_i(embed%comm, contact_surf, hecmw_min)
632  nactive = 0
633  do i = 1, size(embed%slave)
634  if (embed%states(i)%state /= contactfree) then ! any slave in contact
635  id = embed%states(i)%surface
636  if (contact_surf(embed%slave(i)) /= elemid(embed%master(id)%eid)) then ! that is in contact with other surface
637  embed%states(i)%state = contactfree ! should be freed
638  if (contact_log_level >= 1) write(*,'(A,i10,A,i10,A,i6,A,i6,A)') "Node",nodeid(embed%slave(i))," contact with element", &
639  & elemid(embed%master(id)%eid), " in rank",hecmw_comm_get_rank()," freed due to duplication"
640  else
641  nactive = nactive + 1
642  endif
643  endif
644  icat_prev = contact_state_category(states_prev(i))
645  icat_curr = contact_state_category(embed%states(i)%state)
646  if (icat_prev /= icat_curr) infoctchange%n_statechange(icat_prev,icat_curr) = &
647  infoctchange%n_statechange(icat_prev,icat_curr) + 1
648  enddo
649  active = (nactive > 0)
650  deallocate(contact_surf)
651  deallocate(states_prev)
652  end subroutine scan_embed_state
653 
655  subroutine remove_duplication_tiedcontact( cstep, hecMESH, fstrSOLID, infoCTChange )
656  integer(kind=kint), intent(in) :: cstep
657  type( hecmwst_local_mesh ), intent(in) :: hecMESH
658  type(fstr_solid), intent(inout) :: fstrSOLID
659  type(fstr_info_contactchange), intent(inout):: infoCTChange
660 
661  integer(kind=kint) :: i, j, grpid, slave
662  integer(kind=kint) :: k, id, iSS, icat
663  integer(kind=kint) :: ig0, ig, iS0, iE0
664  integer(kind=kint), allocatable :: states(:)
665 
666  allocate(states(hecmesh%n_node))
667  states(:) = contactfree
668 
669  ! if a boundary condition is given, the slave
670  do ig0= 1, fstrsolid%BOUNDARY_ngrp_tot
671  grpid = fstrsolid%BOUNDARY_ngrp_GRPID(ig0)
672  if( .not. fstr_isboundaryactive( fstrsolid, grpid, cstep ) ) cycle
673  ig= fstrsolid%BOUNDARY_ngrp_ID(ig0)
674  is0= hecmesh%node_group%grp_index(ig-1) + 1
675  ie0= hecmesh%node_group%grp_index(ig )
676  do k= is0, ie0
677  iss = hecmesh%node_group%grp_item(k)
678  !states(iSS) = CONTACTSTICK
679  enddo
680  enddo
681 
682  do i=1,fstrsolid%n_contacts
683  if( fstrsolid%contacts(i)%algtype /= contacttied ) cycle
684  grpid = fstrsolid%contacts(i)%group
685  if( .not. fstr_iscontactactive( fstrsolid, grpid, cstep ) ) cycle
686 
687  do j=1, size(fstrsolid%contacts(i)%slave)
688  if( is_contact_free(fstrsolid%contacts(i)%states(j)%state) ) cycle ! free
689  slave = fstrsolid%contacts(i)%slave(j)
690  if( is_contact_free(states(slave)) ) then
691  states(slave) = fstrsolid%contacts(i)%states(j)%state
692  id = fstrsolid%contacts(i)%states(j)%surface
693  do k=1,size( fstrsolid%contacts(i)%master(id)%nodes )
694  iss = fstrsolid%contacts(i)%master(id)%nodes(k)
695  states(iss) = fstrsolid%contacts(i)%states(j)%state
696  enddo
697  else !found duplicate tied contact slave node
698  icat = contact_state_category(fstrsolid%contacts(i)%states(j)%state)
699  fstrsolid%contacts(i)%states(j)%state = contactfree
700  infoctchange%n_statechange(kcatfree,icat) = infoctchange%n_statechange(kcatfree,icat) - 1
701  if (contact_log_level >= 1) write(*,'(A,i10,A,i6,A,i6,A)') "Node",hecmesh%global_node_ID(slave), &
702  " in rank",hecmw_comm_get_rank()," freed due to duplication"
703  endif
704  enddo
705  enddo
706 
707  end subroutine
708 
713  subroutine scan_contact_state_ss( contact, currpos, infoCTChange, is_init, active )
714  type( tcontact ), intent(inout) :: contact
715  type( fstr_info_contactchange ), intent(inout) :: infoCTChange
716  real(kind=kreal), intent(in) :: currpos(:)
717  logical, intent(in) :: is_init
718  logical, intent(out) :: active
719 
720  real(kind=kreal) :: distclr
721  integer(kind=kint) :: slave, id
722  integer(kind=kint) :: nnode_s, i, j
723  real(kind=kreal) :: coord(3), ncoord(2)
724  real(kind=kreal) :: surf_node_pos(3,4), sfunc(4)
725  logical :: isin
726  !
727  integer, pointer :: indexCand(:)
728  integer :: idm,bktID,nCand,id_best
729  type(tcontactstate) :: state_free, state_try, state_best
730  ! per-segment known-master tracking for free2contact_new
731  integer(kind=kint) :: maplist(MAX_N_INTP), master_idxs(MAX_N_INTP)
732  integer(kind=kint) :: unique_count
733  integer(kind=kint) :: known_masters(MAX_N_INTP), n_known
734  logical :: is_known
735  ! each kind of change is counted once per slave segment; the convergence and rebuild checks only test for zero
736  logical :: counted_f2c, counted_nbr, counted_byd
737  if( is_init ) then
738  distclr = contact%cparam%DISTCLR_INIT
739  else
740  distclr = contact%cparam%DISTCLR_FREE
741  endif
742  call update_surface_box_info( contact%master, currpos )
743  call update_surface_bucket_info( contact%master, contact%master_bktDB )
744  ! the reduction below starts from the value active has on entry, so it must be defined
745  active = .false.
746  !$omp parallel do &
747  !$omp& default(none) &
748  !$omp& private(i,slave,id,coord,ncoord,surf_node_pos,sfunc,nnode_s, &
749  !$omp& j,idm,isin,bktID,nCand,indexCand,id_best,state_free,state_try,state_best, &
750  !$omp& maplist,master_idxs,unique_count,known_masters,n_known,is_known, &
751  !$omp& counted_f2c,counted_nbr,counted_byd) &
752  !$omp& shared(contact,infoCTChange,currpos,distclr,is_init) &
753  !$omp& reduction(.or.:active) &
754  !$omp& schedule(dynamic,1)
755 
756  ! loop element; if any node(nslave_index) in contact, call intp point projection
757  do i = 1, size(contact%slave_surf)
758  surf_node_pos(:,:) = 0.d0
759  nnode_s = size(contact%slave_surf(i)%nodes)
760  ! Snapshot the previous-step active master set for this slave segment.
761  ! Used by is_known_master_in_segment to detect genuinely new masters
762  ! (= those that change matrix sparsity).
763  call get_unique_map(contact%slave_surf(i), maplist, master_idxs, unique_count)
764  n_known = unique_count
765  if( n_known > 0 ) known_masters(1:n_known) = master_idxs(1:n_known)
766  counted_f2c = .false.
767  counted_nbr = .false.
768  counted_byd = .false.
769 
770  ! ALagrange SS only (SLAG+MORTAR rejected at fstr_setup): set all IPs as
771  ! candidates unconditionally (do not depend on NTS node-level contact state)
772  do j = 1, contact%slave_surf(i)%n_intp
773  if (contact%slave_surf(i)%states(j)%state == contactfree) then
774  contact%slave_surf(i)%states(j)%state = candidate_intp
775  endif
776  enddo
777 
778  do j = 1, nnode_s
779  slave = contact%slave_surf(i)%nodes(j)
780  surf_node_pos(:,j) = currpos(3*slave-2:3*slave)
781  enddo
782 
783  ! Snapshot this segment's previous state before reset (for seg on/off detection)
784  contact%slave_surf(i)%state_prev = contact%slave_surf(i)%state
785  contact%slave_surf(i)%state = contactfree
786  do j = 1, contact%slave_surf(i)%n_intp
787  ! All FREE IPs were promoted to CANDIDATE_INTP above; no IP can be CONTACTFREE here.
788  ! CONTACT_INTERFERENCE (if_type) not supported with MORTAR=YES (rejected at check_apply_Contact_IF)
789 
790  ! IP natural coord (ncoord) and physical position (coord): used by both the
791  ! already-active (track) and candidate (bucket search + projection) paths.
792  call getintpoint4ss( contact%slave_surf(i)%etype, j, ncoord, contact%slave_surf(i)%n_intp, sfunc )
793  coord(:) = matmul( surf_node_pos(:,1:nnode_s), sfunc(1:nnode_s) )
794 
795  !! already active contact
796  if( contact%slave_surf(i)%states(j)%state==contactstick .or. contact%slave_surf(i)%states(j)%state==contactslip ) then
797  active = .true.
798  id = contact%slave_surf(i)%states(j)%surface
799 
800  ! INTERACTION=TIED not supported with MORTAR=YES (rejected at fstr_setup)
801  if( contact%algtype /= contactfslid ) cycle ! small slide problem
802 
803  call track_contact_position_ss( coord, contact%slave_surf(i)%states(j),&
804  contact%slave_surf(i), ncoord, contact, currpos, infoctchange, counted_nbr, counted_byd )
805 
806  if( contact%slave_surf(i)%states(j)%state /= contactfree ) contact%slave_surf(i)%state = contactstick
807 
808  !! contact candidate integration point
809  else if( contact%slave_surf(i)%states(j)%state==candidate_intp ) then
810  contact%slave_surf(i)%states(j)%state=contactfree
811 
812  ! get master candidates from bucketDB
813  bktid = bucketdb_getbucketid(contact%master_bktDB, coord)
814  ncand = bucketdb_getnumcand(contact%master_bktDB, bktid)
815  if (ncand == 0) cycle
816  allocate(indexcand(ncand))
817  call bucketdb_getcand(contact%master_bktDB, bktid, ncand, indexcand)
818 
819  ! The bucket returns the candidates in scan order, so every candidate is
820  ! projected on a trial state and the nearest one is adopted, as in the
821  ! NODE-SURF scan. A surface across a convex edge is accepted as well and
822  ! would otherwise bind the integration point at a large depth.
823  state_free = contact%slave_surf(i)%states(j)
824  id_best = 0
825  do idm = 1,ncand
826  id = indexcand(idm)
827  ! OFF->ON uses is_init-dependent distclr (DISTCLR_INIT on initial scan,
828  ! DISTCLR_FREE on re-scan) to form a hysteresis band with DISTCLR_C2F.
829  ! The _ss wrapper sets direction to the slave inward normal (mortar normal).
830  state_try = state_free
831  call project_point2surfelement_ss( coord, contact%master(id), contact%slave_surf(i), &
832  ncoord, currpos, state_try, isin, distclr=distclr, &
833  penclr=contact%cparam%PENCLR_FREE, localclr=contact%cparam%CLEARANCE )
834  if( .not. isin ) cycle
835  if( id_best /= 0 ) then
836  if( dabs(state_try%distance) > dabs(state_best%distance) ) cycle
837  if( dabs(state_try%distance) == dabs(state_best%distance) .and. id > id_best ) cycle
838  endif
839  id_best = id
840  state_best = state_try
841  enddo
842  if( id_best /= 0 ) then
843  id = id_best
844  contact%slave_surf(i)%states(j) = state_best
845  contact%slave_surf(i)%states(j)%surface = id
846  contact%slave_surf(i)%states(j)%multiplier(:) = 0.d0
847 
848  contact%slave_surf(i)%states(j)%state = contactstick
849  active = .true.
850  contact%slave_surf(i)%state = contactstick
851  ! Always maintain the known-master set. SPARSITY_NEIGHBOR pre-registers the neighbors, so only a
852  ! genuinely-new master rebuilds / breaks convergence; current-master-only: every new contact rebuilds.
853  call is_known_master_in_segment(contact, known_masters, n_known, id, is_known)
854  if( (contact%sparsity_expansion == sparsity_none .or. .not. is_known) .and. .not. counted_f2c ) then
855  !$omp atomic
856  infoctchange%free2contact_new = infoctchange%free2contact_new + 1
857  counted_f2c = .true.
858  endif
859  endif
860  deallocate(indexcand)
861  endif
862  enddo
863 
864  enddo
865 
866  end subroutine scan_contact_state_ss
867 
868  subroutine track_contact_position_ss( coord, state, sSurf, ncoord, contact, currpos, infoCTChange, counted_nbr, counted_byd )
869  type( tcontact ), intent(inout) :: contact
870  type( tcontactstate ), intent(inout) :: state
871  type( tcontactsurf ), intent(in) :: sSurf
872  real(kind=kreal), intent(in) :: ncoord(2)
873  type( fstr_info_contactchange ), intent(inout) :: infoctchange
874  logical, intent(inout) :: counted_nbr
875  logical, intent(inout) :: counted_byd
876  real(kind=kreal), intent(in) :: currpos(:)
877  real(kind=kreal), intent(inout) :: coord(:)
878 
879  integer(kind=kint) :: sid0, sid
880  integer(kind=kint) :: i
881  logical :: isin, found_in_neighbor
882  real(kind=kreal) :: opos(2)
883  integer(kind=kint) :: bktid, ncand, idm, id_best
884  integer(kind=kint), allocatable :: indexcand(:)
885  type(tcontactstate) :: state_free, state_try, state_best
886 
887  sid = 0
888  found_in_neighbor = .false.
889 
891  sid0 = state%surface
892  opos = state%lpos(1:2)
893 
894  call project_point2surfelement_ss( coord, contact%master(sid0), ssurf, ncoord, currpos, &
895  state, isin, contact%cparam%DISTCLR_NOCHECK, contact%cparam%PENCLR_NOCHECK, &
896  state%lpos(1:2), contact%cparam%CLR_SAME_ELEM )
897  if( .not. isin ) then ! not contact previous master, search neighbor master surf
898  ! A neighbor across a convex edge is accepted at a large depth, so the nearest
899  ! surface is taken instead of the first accepted one.
900  state_free = state
901  id_best = 0
902  do i=1, contact%master(sid0)%n_neighbor
903  sid = contact%master(sid0)%neighbor(i)
904  state_try = state_free
905  call project_point2surfelement_ss( coord, contact%master(sid), ssurf, ncoord, currpos, &
906  state_try, isin, contact%cparam%DISTCLR_NOCHECK, contact%cparam%PENCLR_NOCHECK, &
907  localclr=contact%cparam%CLEARANCE )
908  if( .not. isin ) cycle
909  if( id_best /= 0 ) then
910  if( dabs(state_try%distance) > dabs(state_best%distance) ) cycle
911  if( dabs(state_try%distance) == dabs(state_best%distance) .and. sid > id_best ) cycle
912  endif
913  id_best = sid
914  state_best = state_try
915  enddo
916  isin = ( id_best /= 0 )
917  if( isin ) then
918  sid = id_best
919  state = state_best
920  state%surface = sid
921  found_in_neighbor = .true.
922  endif
923  endif
924 
925  if( .not. isin ) then ! such case is considered to rarely or never occur
926  state_free = state
927  ! get master candidates from bucketDB
928  bktid = bucketdb_getbucketid(contact%master_bktDB, coord)
929  ncand = bucketdb_getnumcand(contact%master_bktDB, bktid)
930  if (ncand > 0) then
931  allocate(indexcand(ncand))
932  call bucketdb_getcand(contact%master_bktDB, bktid, ncand, indexcand)
933  id_best = 0
934  do idm= 1, ncand
935  sid = indexcand(idm)
936  if( sid==sid0 ) cycle
937  if( associated(contact%master(sid0)%neighbor) ) then
938  if( any(sid==contact%master(sid0)%neighbor(1:contact%master(sid0)%n_neighbor)) ) cycle
939  endif
940  state_try = state_free
941  call project_point2surfelement_ss( coord, contact%master(sid), ssurf, ncoord, currpos, &
942  state_try, isin, contact%cparam%DISTCLR_NOCHECK, contact%cparam%PENCLR_FREE, &
943  localclr=contact%cparam%CLEARANCE )
944  if( .not. isin ) cycle
945  if( id_best /= 0 ) then
946  if( dabs(state_try%distance) > dabs(state_best%distance) ) cycle
947  if( dabs(state_try%distance) == dabs(state_best%distance) .and. sid > id_best ) cycle
948  endif
949  id_best = sid
950  state_best = state_try
951  enddo
952  deallocate(indexcand)
953  isin = ( id_best /= 0 )
954  if( isin ) then
955  sid = id_best
956  state = state_best
957  state%surface = sid
958  endif
959  endif
960  endif
961 
962  if( isin ) then
963  if( state%distance > contact%cparam%DISTCLR_C2F * contact%master(state%surface)%reflen ) then
964  state%state = contactfree
965  state%multiplier(:) = 0.d0
966  return
967  endif
968  ! An IP that stays on the same master is not counted: unlike NODE-SURF, its local position
969  ! never settles under sliding, so the jitter is not a state change.
970  if( state%surface /= sid0 ) then
971  if( found_in_neighbor ) then
972  ! SPARSITY_NEIGHBOR: neighbor is pre-registered, tolerated (no rebuild / no relance)
973  if( contact%sparsity_expansion == sparsity_none .and. .not. counted_nbr ) then
974  !$omp atomic
975  infoctchange%contact2neighbor = infoctchange%contact2neighbor + 1
976  counted_nbr = .true.
977  endif
978  else if( .not. counted_byd ) then
979  !$omp atomic
980  infoctchange%contact2beyond = infoctchange%contact2beyond + 1
981  counted_byd = .true.
982  endif
983  endif
984  ! direction already set to the slave inward normal by project_Point2SurfElement_ss
985  else if( .not. isin ) then
986  state%state = contactfree
987  state%multiplier(:) = 0.d0
988  endif
989 
990  end subroutine track_contact_position_ss
991 
992 end module m_fstr_contact_search
993 
This module encapsulate the basic functions of all elements provide by this software.
Definition: element.f90:43
integer(kind=kind(2)) function getnumberofnodes(etype)
Obtain number of nodes of the element.
Definition: element.f90:132
integer function isinsideelement(fetype, localcoord, clearance)
if a point is inside a surface element -1: No; 0: Yes; >0: Node's (vertex) number
Definition: element.f90:1182
subroutine getintpoint4ss(fetype, np, pos, n_intp, shapefunc)
Definition: element.f90:624
Definition: hecmw.f90:6
Contact damping module for CONTACTNEAR state.
pure logical function, public is_damping_enabled(contact)
Check if damping is enabled for a contact pair.
Alag method implementations for contact element calculations.
subroutine, public get_unique_map(sSurf, maplist, master_idxs, unique_count)
Contact mechanics calculations at element level (single contact pair)
This module provides geometric calculations for contact.
subroutine project_point2solidelement(xyz, etype, nn, elemt, cstate, isin, distclr, ctpos, localclr)
This subroutine find the projection of a slave point onto master surface.
subroutine update_direction(nslave, contact, currpos)
This subroutine tracks down next contact position after a finite slide.
subroutine, public cal_node_normal(csurf, isin, surf, currpos, lpos, normal)
Calculate averaged nodal normal.
subroutine project_point2surfelement(xyz, surf, currpos, cstate, isin, distclr, penclr, ctpos, localclr, smoothing)
Wrapper for project_Point2Element that takes tSurfElement structure This subroutine handles element c...
subroutine project_point2surfelement_ss(coord, master_surf, sSurf, ncoord, currpos, cstate, isin, distclr, penclr, ctpos, localclr)
Mortar projection wrapper. Projects a slave integration point onto a master surface (project_Point2Su...
This module provides interference fit (shrink) functions for contact.
subroutine, public set_shrink_factor(ctime, cstate, etime, if_type)
Contact search and state scanning at search level (all pairs in one tContact)
subroutine track_contact_position_ss(coord, state, sSurf, ncoord, contact, currpos, infoCTChange, counted_nbr, counted_byd)
subroutine is_known_master_in_segment(contact, known_masters, n_known, id, is_known)
Update the known-master set for one slave segment and report whether id is new. When the pair uses SP...
subroutine track_contact_position(nslave, contact, currpos, currdisp, infoCTChange, nodeID, elemID, flag_ctAlgo)
This subroutine tracks down next contact position after a finite slide When flag_ctAlgo is present,...
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.
integer(kind=kint), parameter contact_log_level
Set >= 1 to enable per-node contact log output (for debugging)
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...
Contact surface smoothing using Nagata patch interpolation.
subroutine, public update_surface_normal(surf, currpos, hecMESH)
subroutine, public create_intermediate_points(surf, currpos, contact_name)
This module defines common data and basic structures for analysis.
Definition: m_fstr.F90:15
logical function fstr_iscontactactive(fstrSOLID, nbc, cstep)
Definition: m_fstr.F90:1276
logical function fstr_isboundaryactive(fstrSOLID, nbc, cstep)
Definition: m_fstr.F90:1252
This module manages the data structure for contact calculation.
integer, parameter contactslip
integer, parameter sparsity_none
sparsity expansion mode (per contact pair, set by !CONTACT EXPANSION=)
integer, parameter contactnear
near contact: projection info available, no LM constraint
pure logical function is_contact_free(state)
Whether the contact state is completely free (no projection info)
integer, parameter contacttied
contact type or algorithm definition
pure integer function contact_state_category(state)
Which of the three categories the contact state belongs to.
pure logical function is_contact_active(state)
Whether the contact state has active LM constraint (STICK or SLIP)
integer, parameter kcatfree
contact state category: states sharing a category contribute to the matrix in the same way
integer, parameter candidate_intp
SURF-SURF: integration point to be re-projected in this scan.
integer, parameter contactfree
contact state definition
integer, parameter sparsity_neighbor
register current master + neighbors (fewer matrix rebuilds)
integer, parameter contactfslid
integer, parameter contactstick
integer, parameter kcsnagata
Structure to includes all info needed by contact calculation.
This structure records contact status.
Structure to define a slave surface segment of a SURF-SURF (mortar) contact pair.