FrontISTR  5.9.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(:) == 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  write(*,*) 'Warning: contact moved beyond neighbor elements'
131  cstate_free = contact%states(nslave)
132  ! get master candidates from bucketDB
133  bktid = bucketdb_getbucketid(contact%master_bktDB, coord)
134  ncand = bucketdb_getnumcand(contact%master_bktDB, bktid)
135  if (ncand > 0) then
136  allocate(indexcand(ncand))
137  call bucketdb_getcand(contact%master_bktDB, bktid, ncand, indexcand)
138  id_best = 0
139  do idm= 1, ncand
140  sid = indexcand(idm)
141  if( sid==sid0 ) cycle
142  if( associated(contact%master(sid0)%neighbor) ) then
143  if( any(sid==contact%master(sid0)%neighbor(:)) ) cycle
144  endif
145  cstate_try = cstate_free
146  call project_point2surfelement( coord, contact%master(sid), currpos, &
147  cstate_try, isin, contact%cparam%DISTCLR_NOCHECK, contact%cparam%PENCLR_FREE, &
148  localclr=contact%cparam%CLEARANCE, smoothing=contact%smoothing )
149  if( .not. isin ) cycle
150  if( id_best /= 0 ) then
151  if( dabs(cstate_try%distance) > dabs(cstate_best%distance) ) cycle
152  if( dabs(cstate_try%distance) == dabs(cstate_best%distance) .and. sid > id_best ) cycle
153  endif
154  id_best = sid
155  cstate_best = cstate_try
156  enddo
157  deallocate(indexcand)
158  isin = ( id_best /= 0 )
159  if( isin ) then
160  sid = id_best
161  contact%states(nslave) = cstate_best
162  contact%states(nslave)%surface = sid
163  endif
164  endif
165  endif
166 
167  if( isin ) then
168  if( contact%states(nslave)%surface==sid0 ) then
169  if(any(dabs(contact%states(nslave)%lpos(1:2)-opos(:)) >= contact%cparam%CLR_DIFFLPOS)) then
170  !$omp atomic
171  infoctchange%contact2difflpos = infoctchange%contact2difflpos + 1
172  endif
173  else
174  if (contact_log_level >= 1) write(*,'(A,i10,A,i10,A,f7.3,A,2f7.3)') "Node",nodeid(slave)," move to contact with", &
175  elemid(contact%master(sid)%eid), " with distance ", &
176  contact%states(nslave)%distance," at ",contact%states(nslave)%lpos(1:2)
177  !$omp atomic
178  infoctchange%contact2neighbor = infoctchange%contact2neighbor + 1
179  endif
180  if( update_tangent .and. contact%fcoeff /= 0.d0 ) then
181  ! Setup elem array for update_TangentForce
182  etype = contact%master(contact%states(nslave)%surface)%etype
183  nn = size(contact%master(contact%states(nslave)%surface)%nodes)
184  do j=1,nn
185  iss = contact%master(contact%states(nslave)%surface)%nodes(j)
186  elem(1:3,j)=currpos(3*iss-2:3*iss)
187  enddo
188  call update_tangentforce(etype,nn,elem0,elem,contact%states(nslave))
189  endif
190  iss = isinsideelement( etype, contact%states(nslave)%lpos(1:2), contact%cparam%CLR_CAL_NORM )
191  if( iss>0 .and. contact%smoothing /= kcsnagata ) &
192  call cal_node_normal( contact%states(nslave)%surface, iss, contact%master, currpos, &
193  contact%states(nslave)%lpos(1:2), contact%states(nslave)%direction(:) )
194  else if( .not. isin ) then
195  if (contact_log_level >= 1) write(*,'(A,i10,A)') "Node",nodeid(slave)," move out of contact"
196  contact%states(nslave)%state = contactfree
197  contact%states(nslave)%multiplier(:) = 0.d0
198  endif
199 
200  end subroutine track_contact_position
201 
209  subroutine scan_contact_state( contact, currpos, currdisp, infoCTChange, &
210  nodeID, elemID, is_init, active, hecMESH, flag_ctAlgo, ndforce )
211  type( tcontact ), intent(inout) :: contact
212  type( fstr_info_contactchange ), intent(inout) :: infoCTChange
213  real(kind=kreal), intent(in) :: currpos(:)
214  real(kind=kreal), intent(in) :: currdisp(:)
215  integer(kind=kint), intent(in) :: nodeID(:)
216  integer(kind=kint), intent(in) :: elemID(:)
217  logical, intent(in) :: is_init
218  logical, intent(out) :: active
219  type( hecmwst_local_mesh ), intent(in), optional :: hecMESH
220  character(len=9), intent(in), optional :: flag_ctAlgo
221  real(kind=kreal), intent(in), optional :: ndforce(:)
222 
223  real(kind=kreal) :: distclr
224  integer(kind=kint) :: slave, id, etype
225  integer(kind=kint) :: i, iSS, nactive, icat_prev, icat_curr
226  real(kind=kreal) :: coord(3)
227  real(kind=kreal) :: nlforce
228  logical :: isin
229  integer(kind=kint), allocatable :: contact_surf(:), states_prev(:)
230  real(kind=kreal) :: effective_near_dist, distclr_use
231  !
232  integer, pointer :: indexCand(:)
233  integer :: idm,bktID,nCand,id_best
234  type(tcontactstate) :: cstate_free, cstate_try, cstate_best
235  logical :: is_implicit
236 
237  is_implicit = present(flag_ctalgo)
238 
239  if( is_init ) then
240  distclr = contact%cparam%DISTCLR_INIT
241  else
242  distclr = contact%cparam%DISTCLR_FREE
243  if( contact%algtype == contacttied ) then
244  active = .false.
245  do i= 1, size(contact%slave)
246  if( contact%states(i)%state==contactstick ) then
247  active = .true.
248  exit
249  endif
250  enddo
251  endif
252  endif
253 
254  allocate(contact_surf(size(nodeid)))
255  allocate(states_prev(size(contact%slave)))
256  contact_surf(:) = huge(0)
257  do i = 1, size(contact%slave)
258  states_prev(i) = contact%states(i)%state
259  enddo
260 
261  if( contact%smoothing == kcsnagata ) then
262  call update_surface_normal( contact%master, currpos, hecmesh )
263  call create_intermediate_points( contact%master, currpos, contact%pair_name )
264  endif
265 
266  call update_surface_box_info( contact%master, currpos )
267  call update_surface_bucket_info( contact%master, contact%master_bktDB )
268 
269  ! Compute effective near distance for CONTACTNEAR detection
270  ! If damping is configured (damp_gact > 0), use it as the near distance
271  effective_near_dist = contact%cparam%NEAR_DIST
272  if (contact%damp_gact > 0.0d0) then
273  effective_near_dist = max(effective_near_dist, contact%damp_gact)
274  endif
275 
276  !$omp parallel do &
277  !$omp& default(none) &
278  !$omp& private(i,slave,id,nlforce,coord,iSS,idm,etype,isin, &
279  !$omp& bktID,nCand,indexCand,distclr_use,id_best,cstate_free,cstate_try,cstate_best) &
280  !$omp& firstprivate(is_implicit,effective_near_dist) &
281  !$omp& shared(contact,ndforce,flag_ctAlgo,infoCTChange,currpos,currdisp,nodeID,elemID,distclr,contact_surf,is_init) &
282  !$omp& reduction(.or.:active) &
283  !$omp& schedule(dynamic,1)
284  do i= 1, size(contact%slave)
285  if(contact%if_type /= 0) call set_shrink_factor(contact%ctime, contact%states(i), contact%if_etime, contact%if_type)
286  slave = contact%slave(i)
287  if( contact%states(i)%state==contactstick .or. contact%states(i)%state==contactslip ) then
288  id = contact%states(i)%surface
289  nlforce = contact%states(i)%multiplier(1)
290 
291  ! update direction of TIED contact
292  if( contact%algtype == contacttied ) then
293  call update_direction( i, contact, currpos )
294  if (.not.is_init) cycle
295  endif
296 
297  if( nlforce < contact%cparam%TENSILE_FORCE ) then
298  contact%states(i)%multiplier(:) = 0.d0
299  if( effective_near_dist > 0.0d0 ) then
300  ! keep the projection so that the NEAR branch re-projects on the next scan and
301  ! decides between NEAR and FREE with an up-to-date distance
302  contact%states(i)%state = contactnear
303  contact_surf(contact%slave(i)) = elemid(contact%master(id)%eid)
304  if (contact_log_level >= 1) write(*,'(A,i10,A,i10,A,e12.3)') "Node",nodeid(slave), &
305  " released to near contact with element", &
306  elemid(contact%master(id)%eid), " with tensile force ", nlforce
307  else
308  contact%states(i)%state = contactfree
309  if (contact_log_level >= 1) write(*,'(A,i10,A,i10,A,e12.3)') "Node",nodeid(slave)," free from contact with element", &
310  elemid(contact%master(id)%eid), " with tensile force ", nlforce
311  endif
312  cycle
313  endif
314  if( contact%algtype /= contactfslid ) then ! small slide problem
315  contact_surf(contact%slave(i)) = -elemid(contact%master(id)%eid)
316  else
317  if( is_implicit ) then
318  call track_contact_position( i, contact, currpos, currdisp, infoctchange, nodeid, elemid, &
319  flag_ctalgo=flag_ctalgo )
320  else
321  call track_contact_position( i, contact, currpos, currdisp, infoctchange, nodeid, elemid )
322  endif
323  if( contact%states(i)%state /= contactfree ) then
324  id = contact%states(i)%surface
325  contact_surf(contact%slave(i)) = -elemid(contact%master(id)%eid)
326  endif
327  endif
328 
329  else if( contact%states(i)%state==contactnear ) then
330  ! NEAR tracking: re-project on current master surface
331  coord(:) = currpos(3*slave-2:3*slave)
332  id = contact%states(i)%surface
333  if (effective_near_dist > 0.0d0) then
334  distclr_use = max(distclr, effective_near_dist / contact%master(id)%reflen)
335  else
336  distclr_use = distclr
337  end if
338  call project_point2surfelement( coord, contact%master(id), currpos, &
339  contact%states(i), isin, distclr_use, contact%cparam%PENCLR_FREE, &
340  contact%states(i)%lpos(1:2), contact%cparam%CLR_SAME_ELEM, smoothing=contact%smoothing )
341  if (isin) then
342  if (contact%states(i)%distance <= distclr * contact%master(id)%reflen) then
343  ! Within contact threshold -> upgrade to STICK
344  contact%states(i)%state = contactstick
345  contact%states(i)%multiplier(:) = 0.d0
346  if (contact_log_level >= 1) write(*,'(A,i10,A,i10,A,i6)') "Node",nodeid(slave)," upgraded NEAR->STICK on element", &
347  elemid(contact%master(id)%eid)," rank=",hecmw_comm_get_rank()
348  else if (contact%states(i)%distance > effective_near_dist) then
349  ! Beyond NEAR range -> free
350  contact%states(i)%state = contactfree
351  contact%states(i)%multiplier(:) = 0.d0
352  end if
353  ! else: stay NEAR
354  if (.not. is_contact_free(contact%states(i)%state)) then
355  etype = contact%master(id)%etype
356  iss = isinsideelement( etype, contact%states(i)%lpos(1:2), contact%cparam%CLR_CAL_NORM )
357  if( iss>0 .and. contact%smoothing /= kcsnagata ) &
358  call cal_node_normal( id, iss, contact%master, currpos, &
359  contact%states(i)%lpos(1:2), contact%states(i)%direction(:) )
360  contact_surf(contact%slave(i)) = elemid(contact%master(id)%eid)
361  end if
362  else
363  ! Lost projection -> free
364  contact%states(i)%state = contactfree
365  contact%states(i)%multiplier(:) = 0.d0
366  end if
367 
368  else if( contact%states(i)%state==contactfree ) then
369  if( contact%algtype == contacttied .and. .not. is_init ) cycle
370  coord(:) = currpos(3*slave-2:3*slave)
371 
372  ! get master candidates from bucketDB
373  bktid = bucketdb_getbucketid(contact%master_bktDB, coord)
374  ncand = bucketdb_getnumcand(contact%master_bktDB, bktid)
375  if (ncand == 0) cycle
376  allocate(indexcand(ncand))
377  call bucketdb_getcand(contact%master_bktDB, bktid, ncand, indexcand)
378 
379  ! The bucket collects candidates in scan order, not in distance order, so every
380  ! candidate is projected on a trial state and the closest one is adopted. Equal
381  ! distances are settled by the master index so that the choice never depends on
382  ! the order the bucket happened to return.
383  id_best = 0
384  cstate_free = contact%states(i)
385  do idm = 1,ncand
386  id = indexcand(idm)
387  ! Expand distclr for NEAR detection
388  if (effective_near_dist > 0.0d0) then
389  distclr_use = max(distclr, effective_near_dist / contact%master(id)%reflen)
390  else
391  distclr_use = distclr
392  end if
393  cstate_try = cstate_free
394  call project_point2surfelement( coord, contact%master(id), currpos, &
395  cstate_try, isin, distclr_use, contact%cparam%PENCLR_FREE, &
396  localclr=contact%cparam%CLEARANCE, smoothing=contact%smoothing )
397  if( .not. isin ) cycle
398  if( id_best /= 0 ) then
399  if( dabs(cstate_try%distance) > dabs(cstate_best%distance) ) cycle
400  if( dabs(cstate_try%distance) == dabs(cstate_best%distance) .and. id > id_best ) cycle
401  endif
402  id_best = id
403  cstate_best = cstate_try
404  enddo
405  deallocate(indexcand)
406  if( id_best == 0 ) cycle
407 
408  id = id_best
409  contact%states(i) = cstate_best
410  ! Classify: STICK or NEAR
411  if (effective_near_dist > 0.0d0 .and. &
412  contact%states(i)%distance > distclr * contact%master(id)%reflen) then
413  contact%states(i)%state = contactnear
414  end if
415  contact%states(i)%surface = id
416  contact%states(i)%multiplier(:) = 0.d0
417  etype = contact%master(id)%etype
418  iss = isinsideelement( etype, contact%states(i)%lpos(1:2), contact%cparam%CLR_CAL_NORM )
419  if( iss>0 .and. contact%smoothing /= kcsnagata ) &
420  call cal_node_normal( id, iss, contact%master, currpos, contact%states(i)%lpos(1:2), &
421  contact%states(i)%direction(:) )
422  contact_surf(contact%slave(i)) = elemid(contact%master(id)%eid)
423  if (contact_log_level >= 1) then
424  if (contact%states(i)%state == contactnear) then
425  write(*,'(A,i10,A,i10,A,f7.3,A,i6)') "Node",nodeid(slave)," near element", &
426  elemid(contact%master(id)%eid), &
427  " with distance ", contact%states(i)%distance," rank=",hecmw_comm_get_rank()
428  else
429  write(*,'(A,i10,A,i10,A,f7.3,A,2f7.3,A,3f7.3,A,i6)') "Node",nodeid(slave)," contact with element", &
430  elemid(contact%master(id)%eid), &
431  " with distance ", contact%states(i)%distance," at ",contact%states(i)%lpos(1:2), &
432  " along direction ", contact%states(i)%direction," rank=",hecmw_comm_get_rank()
433  end if
434  end if
435  endif
436  enddo
437  !$omp end parallel do
438 
439  if( contact%algtype == contacttied .and. .not. is_init ) then
440  deallocate(contact_surf)
441  deallocate(states_prev)
442  return
443  endif
444 
445  call hecmw_contact_comm_allreduce_i(contact%comm, contact_surf, hecmw_min)
446  nactive = 0
447  do i = 1, size(contact%slave)
448  if (.not. is_contact_free(contact%states(i)%state)) then ! any slave in contact or near
449  id = contact%states(i)%surface
450  if (abs(contact_surf(contact%slave(i))) /= elemid(contact%master(id)%eid)) then ! that is in contact with other surface
451  contact%states(i)%state = contactfree ! should be freed
452  if (contact_log_level >= 1) &
453  & write(*,'(A,i10,A,i10,A,i6,A,i6,A)') "Node",nodeid(contact%slave(i)), &
454  & " contact with element",elemid(contact%master(id)%eid), &
455  & " in rank",hecmw_comm_get_rank()," freed due to duplication"
456  else if (is_contact_active(contact%states(i)%state) .or. is_damping_enabled(contact)) then
457  nactive = nactive + 1 ! a NEAR node with damping also contributes stiffness and residual
458  endif
459  endif
460  icat_prev = contact_state_category(states_prev(i))
461  icat_curr = contact_state_category(contact%states(i)%state)
462  if (icat_prev /= icat_curr) infoctchange%n_statechange(icat_prev,icat_curr) = &
463  infoctchange%n_statechange(icat_prev,icat_curr) + 1
464  enddo
465  active = (nactive > 0)
466  deallocate(contact_surf)
467  deallocate(states_prev)
468  end subroutine scan_contact_state
469 
473  subroutine scan_embed_state( flag_ctAlgo, embed, currpos, currdisp, ndforce, infoCTChange, &
474  nodeID, elemID, is_init, active, B )
475  character(len=9), intent(in) :: flag_ctAlgo
476  type( tcontact ), intent(inout) :: embed
477  type( fstr_info_contactchange ), intent(inout) :: infoCTChange
478  real(kind=kreal), intent(in) :: currpos(:)
479  real(kind=kreal), intent(in) :: currdisp(:)
480  real(kind=kreal), intent(in) :: ndforce(:)
481  integer(kind=kint), intent(in) :: nodeID(:)
482  integer(kind=kint), intent(in) :: elemID(:)
483  logical, intent(in) :: is_init
484  logical, intent(out) :: active
485  real(kind=kreal), optional, target :: b(:)
486 
487  real(kind=kreal) :: distclr
488  integer(kind=kint) :: slave, id, etype
489  integer(kind=kint) :: nn, i, j, iSS, nactive, icat_prev, icat_curr
490  real(kind=kreal) :: coord(3), elem(3, l_max_elem_node )
491  logical :: isin
492  integer(kind=kint), allocatable :: contact_surf(:), states_prev(:)
493  !
494  integer, pointer :: indexCand(:)
495  integer :: idm,bktID,nCand,id_best
496  type(tcontactstate) :: cstate_free, cstate_try, cstate_best
497  logical :: is_present_B
498  real(kind=kreal), pointer :: bp(:)
499 
500  if( is_init ) then
501  distclr = embed%cparam%DISTCLR_INIT
502  else
503  distclr = embed%cparam%DISTCLR_FREE
504  active = .false.
505  do i= 1, size(embed%slave)
506  if( embed%states(i)%state==contactstick ) then
507  active = .true.
508  exit
509  endif
510  enddo
511  return
512  endif
513 
514  allocate(contact_surf(size(nodeid)))
515  allocate(states_prev(size(embed%slave)))
516  contact_surf(:) = huge(0)
517  do i = 1, size(embed%slave)
518  states_prev(i) = embed%states(i)%state
519  enddo
520 
521  call update_surface_box_info( embed%master, currpos )
522  call update_surface_bucket_info( embed%master, embed%master_bktDB )
523 
524  ! for gfortran-10: optional parameter seems not allowed within omp parallel
525  is_present_b = present(b)
526  if( is_present_b ) bp => b
527 
528  !$omp parallel do &
529  !$omp& default(none) &
530  !$omp& private(i,slave,id,coord,nn,j,iSS,elem,idm,etype,isin, &
531  !$omp& bktID,nCand,indexCand,id_best,cstate_free,cstate_try,cstate_best) &
532  !$omp& firstprivate(is_present_B) &
533  !$omp& shared(embed,ndforce,flag_ctAlgo,infoCTChange,currpos,currdisp,nodeID,elemID,Bp,distclr,contact_surf) &
534  !$omp& reduction(.or.:active) &
535  !$omp& schedule(dynamic,1)
536  do i= 1, size(embed%slave)
537  slave = embed%slave(i)
538  if( embed%states(i)%state==contactfree ) then
539  coord(:) = currpos(3*slave-2:3*slave)
540 
541  ! get master candidates from bucketDB
542  bktid = bucketdb_getbucketid(embed%master_bktDB, coord)
543  ncand = bucketdb_getnumcand(embed%master_bktDB, bktid)
544  if (ncand == 0) cycle
545  allocate(indexcand(ncand))
546  call bucketdb_getcand(embed%master_bktDB, bktid, ncand, indexcand)
547 
548  ! As in scan_contact_state, the bucket order is not a distance order, so every
549  ! candidate is evaluated on a trial state and the closest element is adopted.
550  id_best = 0
551  cstate_free = embed%states(i)
552  do idm = 1,ncand
553  id = indexcand(idm)
554  etype = embed%master(id)%etype
555  if( mod(etype,10) == 2 ) etype = etype - 1 !search by 1st-order shape function
556  nn = getnumberofnodes(etype)
557  do j=1,nn
558  iss = embed%master(id)%nodes(j)
559  elem(1:3,j)=currpos(3*iss-2:3*iss)
560  enddo
561  cstate_try = cstate_free
562  call project_point2solidelement( coord,etype,nn,elem,embed%master(id)%reflen,cstate_try, &
563  isin,distclr,localclr=embed%cparam%CLEARANCE )
564  if( .not. isin ) cycle
565  if( id_best /= 0 ) then
566  if( cstate_try%distance > cstate_best%distance ) cycle
567  if( cstate_try%distance == cstate_best%distance .and. id > id_best ) cycle
568  endif
569  id_best = id
570  cstate_best = cstate_try
571  enddo
572  deallocate(indexcand)
573  if( id_best == 0 ) cycle
574 
575  id = id_best
576  embed%states(i) = cstate_best
577  embed%states(i)%surface = id
578  embed%states(i)%multiplier(:) = 0.d0
579  contact_surf(embed%slave(i)) = elemid(embed%master(id)%eid)
580  if (contact_log_level >= 1) write(*,'(A,i10,A,i10,A,3f7.3,A,i6)') "Node",nodeid(slave)," embeded to element", &
581  elemid(embed%master(id)%eid), " at ",embed%states(i)%lpos(:)," rank=",hecmw_comm_get_rank()
582  endif
583  enddo
584  !$omp end parallel do
585 
586  call hecmw_contact_comm_allreduce_i(embed%comm, contact_surf, hecmw_min)
587  nactive = 0
588  do i = 1, size(embed%slave)
589  if (embed%states(i)%state /= contactfree) then ! any slave in contact
590  id = embed%states(i)%surface
591  if (abs(contact_surf(embed%slave(i))) /= elemid(embed%master(id)%eid)) then ! that is in contact with other surface
592  embed%states(i)%state = contactfree ! should be freed
593  if (contact_log_level >= 1) write(*,'(A,i10,A,i10,A,i6,A,i6,A)') "Node",nodeid(embed%slave(i))," contact with element", &
594  & elemid(embed%master(id)%eid), " in rank",hecmw_comm_get_rank()," freed due to duplication"
595  else
596  nactive = nactive + 1
597  endif
598  endif
599  icat_prev = contact_state_category(states_prev(i))
600  icat_curr = contact_state_category(embed%states(i)%state)
601  if (icat_prev /= icat_curr) infoctchange%n_statechange(icat_prev,icat_curr) = &
602  infoctchange%n_statechange(icat_prev,icat_curr) + 1
603  enddo
604  active = (nactive > 0)
605  deallocate(contact_surf)
606  deallocate(states_prev)
607  end subroutine scan_embed_state
608 
610  subroutine remove_duplication_tiedcontact( cstep, hecMESH, fstrSOLID, infoCTChange )
611  integer(kind=kint), intent(in) :: cstep
612  type( hecmwst_local_mesh ), intent(in) :: hecMESH
613  type(fstr_solid), intent(inout) :: fstrSOLID
614  type(fstr_info_contactchange), intent(inout):: infoCTChange
615 
616  integer(kind=kint) :: i, j, grpid, slave
617  integer(kind=kint) :: k, id, iSS, icat
618  integer(kind=kint) :: ig0, ig, iS0, iE0
619  integer(kind=kint), allocatable :: states(:)
620 
621  allocate(states(hecmesh%n_node))
622  states(:) = contactfree
623 
624  ! if a boundary condition is given, the slave
625  do ig0= 1, fstrsolid%BOUNDARY_ngrp_tot
626  grpid = fstrsolid%BOUNDARY_ngrp_GRPID(ig0)
627  if( .not. fstr_isboundaryactive( fstrsolid, grpid, cstep ) ) cycle
628  ig= fstrsolid%BOUNDARY_ngrp_ID(ig0)
629  is0= hecmesh%node_group%grp_index(ig-1) + 1
630  ie0= hecmesh%node_group%grp_index(ig )
631  do k= is0, ie0
632  iss = hecmesh%node_group%grp_item(k)
633  !states(iSS) = CONTACTSTICK
634  enddo
635  enddo
636 
637  do i=1,fstrsolid%n_contacts
638  if( fstrsolid%contacts(i)%algtype /= contacttied ) cycle
639  grpid = fstrsolid%contacts(i)%group
640  if( .not. fstr_iscontactactive( fstrsolid, grpid, cstep ) ) cycle
641 
642  do j=1, size(fstrsolid%contacts(i)%slave)
643  if( is_contact_free(fstrsolid%contacts(i)%states(j)%state) ) cycle ! free
644  slave = fstrsolid%contacts(i)%slave(j)
645  if( is_contact_free(states(slave)) ) then
646  states(slave) = fstrsolid%contacts(i)%states(j)%state
647  id = fstrsolid%contacts(i)%states(j)%surface
648  do k=1,size( fstrsolid%contacts(i)%master(id)%nodes )
649  iss = fstrsolid%contacts(i)%master(id)%nodes(k)
650  states(iss) = fstrsolid%contacts(i)%states(j)%state
651  enddo
652  else !found duplicate tied contact slave node
653  icat = contact_state_category(fstrsolid%contacts(i)%states(j)%state)
654  fstrsolid%contacts(i)%states(j)%state = contactfree
655  infoctchange%n_statechange(kcatfree,icat) = infoctchange%n_statechange(kcatfree,icat) - 1
656  if (contact_log_level >= 1) write(*,'(A,i10,A,i6,A,i6,A)') "Node",hecmesh%global_node_ID(slave), &
657  " in rank",hecmw_comm_get_rank()," freed due to duplication"
658  endif
659  enddo
660  enddo
661 
662  end subroutine
663 
668  subroutine scan_contact_state_ss( contact, currpos, infoCTChange, is_init, active )
669  type( tcontact ), intent(inout) :: contact
670  type( fstr_info_contactchange ), intent(inout) :: infoCTChange
671  real(kind=kreal), intent(in) :: currpos(:)
672  logical, intent(in) :: is_init
673  logical, intent(out) :: active
674 
675  real(kind=kreal) :: distclr
676  integer(kind=kint) :: slave, id
677  integer(kind=kint) :: nnode_s, i, j
678  real(kind=kreal) :: coord(3), ncoord(2)
679  real(kind=kreal) :: surf_node_pos(3,4), sfunc(4)
680  logical :: isin
681  !
682  integer, pointer :: indexCand(:)
683  integer :: idm,bktID,nCand,id_best
684  type(tcontactstate) :: state_free, state_try, state_best
685  ! per-segment known-master tracking for free2contact_new
686  integer(kind=kint) :: maplist(MAX_N_INTP), master_idxs(MAX_N_INTP)
687  integer(kind=kint) :: unique_count
688  integer(kind=kint) :: known_masters(MAX_N_INTP), n_known
689  logical :: is_known
690  ! each kind of change is counted once per slave segment; the convergence and rebuild checks only test for zero
691  logical :: counted_f2c, counted_nbr, counted_byd
692  if( is_init ) then
693  distclr = contact%cparam%DISTCLR_INIT
694  else
695  distclr = contact%cparam%DISTCLR_FREE
696  endif
697  call update_surface_box_info( contact%master, currpos )
698  call update_surface_bucket_info( contact%master, contact%master_bktDB )
699  ! the reduction below starts from the value active has on entry, so it must be defined
700  active = .false.
701  !$omp parallel do &
702  !$omp& default(none) &
703  !$omp& private(i,slave,id,coord,ncoord,surf_node_pos,sfunc,nnode_s, &
704  !$omp& j,idm,isin,bktID,nCand,indexCand,id_best,state_free,state_try,state_best, &
705  !$omp& maplist,master_idxs,unique_count,known_masters,n_known,is_known, &
706  !$omp& counted_f2c,counted_nbr,counted_byd) &
707  !$omp& shared(contact,infoCTChange,currpos,distclr,is_init) &
708  !$omp& reduction(.or.:active) &
709  !$omp& schedule(dynamic,1)
710 
711  ! loop element; if any node(nslave_index) in contact, call intp point projection
712  do i = 1, size(contact%slave_surf)
713  surf_node_pos(:,:) = 0.d0
714  nnode_s = size(contact%slave_surf(i)%nodes)
715  ! Snapshot the previous-step active master set for this slave segment.
716  ! Used by is_known_master_in_segment to detect genuinely new masters
717  ! (= those that change matrix sparsity).
718  call get_unique_map(contact%slave_surf(i), maplist, master_idxs, unique_count)
719  n_known = unique_count
720  if( n_known > 0 ) known_masters(1:n_known) = master_idxs(1:n_known)
721  counted_f2c = .false.
722  counted_nbr = .false.
723  counted_byd = .false.
724 
725  ! ALagrange SS only (SLAG+MORTAR rejected at fstr_setup): set all IPs as
726  ! candidates unconditionally (do not depend on NTS node-level contact state)
727  do j = 1, contact%slave_surf(i)%n_intp
728  if (contact%slave_surf(i)%states(j)%state == contactfree) then
729  contact%slave_surf(i)%states(j)%state = candidate_intp
730  endif
731  enddo
732 
733  do j = 1, nnode_s
734  slave = contact%slave_surf(i)%nodes(j)
735  surf_node_pos(:,j) = currpos(3*slave-2:3*slave)
736  enddo
737 
738  ! Snapshot this segment's previous state before reset (for seg on/off detection)
739  contact%slave_surf(i)%state_prev = contact%slave_surf(i)%state
740  contact%slave_surf(i)%state = contactfree
741  do j = 1, contact%slave_surf(i)%n_intp
742  ! All FREE IPs were promoted to CANDIDATE_INTP above; no IP can be CONTACTFREE here.
743  ! CONTACT_INTERFERENCE (if_type) not supported with MORTAR=YES (rejected at check_apply_Contact_IF)
744 
745  ! IP natural coord (ncoord) and physical position (coord): used by both the
746  ! already-active (track) and candidate (bucket search + projection) paths.
747  call getintpoint4ss( contact%slave_surf(i)%etype, j, ncoord, contact%slave_surf(i)%n_intp, sfunc )
748  coord(:) = matmul( surf_node_pos(:,1:nnode_s), sfunc(1:nnode_s) )
749 
750  !! already active contact
751  if( contact%slave_surf(i)%states(j)%state==contactstick .or. contact%slave_surf(i)%states(j)%state==contactslip ) then
752  active = .true.
753  id = contact%slave_surf(i)%states(j)%surface
754 
755  ! INTERACTION=TIED not supported with MORTAR=YES (rejected at fstr_setup)
756  if( contact%algtype /= contactfslid ) cycle ! small slide problem
757 
758  call track_contact_position_ss( coord, contact%slave_surf(i)%states(j),&
759  contact%slave_surf(i), ncoord, contact, currpos, infoctchange, counted_nbr, counted_byd )
760 
761  if( contact%slave_surf(i)%states(j)%state /= contactfree ) contact%slave_surf(i)%state = contactstick
762 
763  !! contact candidate integration point
764  else if( contact%slave_surf(i)%states(j)%state==candidate_intp ) then
765  contact%slave_surf(i)%states(j)%state=contactfree
766 
767  ! get master candidates from bucketDB
768  bktid = bucketdb_getbucketid(contact%master_bktDB, coord)
769  ncand = bucketdb_getnumcand(contact%master_bktDB, bktid)
770  if (ncand == 0) cycle
771  allocate(indexcand(ncand))
772  call bucketdb_getcand(contact%master_bktDB, bktid, ncand, indexcand)
773 
774  ! The bucket returns the candidates in scan order, so every candidate is
775  ! projected on a trial state and the nearest one is adopted, as in the
776  ! NODE-SURF scan. A surface across a convex edge is accepted as well and
777  ! would otherwise bind the integration point at a large depth.
778  state_free = contact%slave_surf(i)%states(j)
779  id_best = 0
780  do idm = 1,ncand
781  id = indexcand(idm)
782  ! OFF->ON uses is_init-dependent distclr (DISTCLR_INIT on initial scan,
783  ! DISTCLR_FREE on re-scan) to form a hysteresis band with DISTCLR_C2F.
784  ! The _ss wrapper sets direction to the slave inward normal (mortar normal).
785  state_try = state_free
786  call project_point2surfelement_ss( coord, contact%master(id), contact%slave_surf(i), &
787  ncoord, currpos, state_try, isin, distclr=distclr, &
788  penclr=contact%cparam%PENCLR_FREE, localclr=contact%cparam%CLEARANCE )
789  if( .not. isin ) cycle
790  if( id_best /= 0 ) then
791  if( dabs(state_try%distance) > dabs(state_best%distance) ) cycle
792  if( dabs(state_try%distance) == dabs(state_best%distance) .and. id > id_best ) cycle
793  endif
794  id_best = id
795  state_best = state_try
796  enddo
797  if( id_best /= 0 ) then
798  id = id_best
799  contact%slave_surf(i)%states(j) = state_best
800  contact%slave_surf(i)%states(j)%surface = id
801  contact%slave_surf(i)%states(j)%multiplier(:) = 0.d0
802 
803  contact%slave_surf(i)%states(j)%state = contactstick
804  active = .true.
805  contact%slave_surf(i)%state = contactstick
806  ! Always maintain the known-master set. SPARSITY_NEIGHBOR pre-registers the neighbors, so only a
807  ! genuinely-new master rebuilds / breaks convergence; current-master-only: every new contact rebuilds.
808  call is_known_master_in_segment(contact, known_masters, n_known, id, is_known)
809  if( (contact%sparsity_expansion == sparsity_none .or. .not. is_known) .and. .not. counted_f2c ) then
810  !$omp atomic
811  infoctchange%free2contact_new = infoctchange%free2contact_new + 1
812  counted_f2c = .true.
813  endif
814  endif
815  deallocate(indexcand)
816  endif
817  enddo
818 
819  enddo
820 
821  end subroutine scan_contact_state_ss
822 
823  subroutine track_contact_position_ss( coord, state, sSurf, ncoord, contact, currpos, infoCTChange, counted_nbr, counted_byd )
824  type( tcontact ), intent(inout) :: contact
825  type( tcontactstate ), intent(inout) :: state
826  type( tcontactsurf ), intent(in) :: sSurf
827  real(kind=kreal), intent(in) :: ncoord(2)
828  type( fstr_info_contactchange ), intent(inout) :: infoctchange
829  logical, intent(inout) :: counted_nbr
830  logical, intent(inout) :: counted_byd
831  real(kind=kreal), intent(in) :: currpos(:)
832  real(kind=kreal), intent(inout) :: coord(:)
833 
834  integer(kind=kint) :: sid0, sid
835  integer(kind=kint) :: i, j
836  logical :: isin, found_in_neighbor
837  real(kind=kreal) :: opos(2)
838  integer(kind=kint) :: bktid, ncand, idm, id_best
839  integer(kind=kint), allocatable :: indexcand(:)
840  type(tcontactstate) :: state_free, state_try, state_best
841 
842  sid = 0
843  found_in_neighbor = .false.
844 
846  sid0 = state%surface
847  opos = state%lpos(1:2)
848 
849  call project_point2surfelement_ss( coord, contact%master(sid0), ssurf, ncoord, currpos, &
850  state, isin, contact%cparam%DISTCLR_NOCHECK, contact%cparam%PENCLR_NOCHECK, &
851  state%lpos(1:2), contact%cparam%CLR_SAME_ELEM )
852  if( .not. isin ) then ! not contact previous master, search neighbor master surf
853  ! A neighbor across a convex edge is accepted at a large depth, so the nearest
854  ! surface is taken instead of the first accepted one.
855  state_free = state
856  id_best = 0
857  do i=1, contact%master(sid0)%n_neighbor
858  sid = contact%master(sid0)%neighbor(i)
859  state_try = state_free
860  call project_point2surfelement_ss( coord, contact%master(sid), ssurf, ncoord, currpos, &
861  state_try, isin, contact%cparam%DISTCLR_NOCHECK, contact%cparam%PENCLR_NOCHECK, &
862  localclr=contact%cparam%CLEARANCE )
863  if( .not. isin ) cycle
864  if( id_best /= 0 ) then
865  if( dabs(state_try%distance) > dabs(state_best%distance) ) cycle
866  if( dabs(state_try%distance) == dabs(state_best%distance) .and. sid > id_best ) cycle
867  endif
868  id_best = sid
869  state_best = state_try
870  enddo
871  isin = ( id_best /= 0 )
872  if( isin ) then
873  sid = id_best
874  state = state_best
875  state%surface = sid
876  found_in_neighbor = .true.
877  endif
878  endif
879 
880  if( .not. isin ) then ! such case is considered to rarely or never occur
881  state_free = state
882  ! get master candidates from bucketDB
883  bktid = bucketdb_getbucketid(contact%master_bktDB, coord)
884  ncand = bucketdb_getnumcand(contact%master_bktDB, bktid)
885  if (ncand > 0) then
886  allocate(indexcand(ncand))
887  call bucketdb_getcand(contact%master_bktDB, bktid, ncand, indexcand)
888  id_best = 0
889  do idm= 1, ncand
890  sid = indexcand(idm)
891  if( sid==sid0 ) cycle
892  if( associated(contact%master(sid0)%neighbor) ) then
893  if( any(sid==contact%master(sid0)%neighbor(:)) ) cycle
894  endif
895  state_try = state_free
896  call project_point2surfelement_ss( coord, contact%master(sid), ssurf, ncoord, currpos, &
897  state_try, isin, contact%cparam%DISTCLR_NOCHECK, contact%cparam%PENCLR_FREE, &
898  localclr=contact%cparam%CLEARANCE )
899  if( .not. isin ) cycle
900  if( id_best /= 0 ) then
901  if( dabs(state_try%distance) > dabs(state_best%distance) ) cycle
902  if( dabs(state_try%distance) == dabs(state_best%distance) .and. sid > id_best ) cycle
903  endif
904  id_best = sid
905  state_best = state_try
906  enddo
907  deallocate(indexcand)
908  isin = ( id_best /= 0 )
909  if( isin ) then
910  sid = id_best
911  state = state_best
912  state%surface = sid
913  endif
914  endif
915  endif
916 
917  if( isin ) then
918  if( state%distance > contact%cparam%DISTCLR_C2F * contact%master(state%surface)%reflen ) then
919  state%state = contactfree
920  state%multiplier(:) = 0.d0
921  return
922  endif
923  ! An IP that stays on the same master is not counted: unlike NODE-SURF, its local position
924  ! never settles under sliding, so the jitter is not a state change.
925  if( state%surface /= sid0 ) then
926  if( found_in_neighbor ) then
927  ! SPARSITY_NEIGHBOR: neighbor is pre-registered, tolerated (no rebuild / no relance)
928  if( contact%sparsity_expansion == sparsity_none .and. .not. counted_nbr ) then
929  !$omp atomic
930  infoctchange%contact2neighbor = infoctchange%contact2neighbor + 1
931  counted_nbr = .true.
932  endif
933  else if( .not. counted_byd ) then
934  !$omp atomic
935  infoctchange%contact2beyond = infoctchange%contact2beyond + 1
936  counted_byd = .true.
937  endif
938  endif
939  ! direction already set to the slave inward normal by project_Point2SurfElement_ss
940  else if( .not. isin ) then
941  state%state = contactfree
942  state%multiplier(:) = 0.d0
943  endif
944 
945  end subroutine track_contact_position_ss
946 
947 end module m_fstr_contact_search
948 
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, reflen, 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_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...
subroutine scan_embed_state(flag_ctAlgo, embed, currpos, currdisp, ndforce, infoCTChange, nodeID, elemID, is_init, active, B)
This subroutine update contact states, which include.
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:1116
logical function fstr_isboundaryactive(fstrSOLID, nbc, cstep)
Definition: m_fstr.F90:1092
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.