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
15  implicit none
16 
17 contains
18 
21  subroutine reset_contact_force( contact, currpos, lslave, omaster, opos, odirec, B )
22  type( tcontact ), intent(inout) :: contact
23  real(kind=kreal), intent(in) :: currpos(:)
24  integer, intent(in) :: lslave
25  integer, intent(in) :: omaster
26  real(kind=kreal), intent(in) :: opos(2)
27  real(kind=kreal), intent(in) :: odirec(3)
28  real(kind=kreal), intent(inout) :: b(:)
29 
30  integer(kind=kint) :: slave, etype, master
31  integer(kind=kint) :: nn, j, iSS
32  real(kind=kreal) :: nrlforce, fcoeff, tangent(3,2)
33  real(kind=kreal) :: elemcrd(3, l_max_elem_node )
34  real(kind=kreal) :: shapefunc(l_max_surface_node)
35  real(kind=kreal) :: metric(2,2), dispmat(2,l_max_elem_node*3+3)
36  real(kind=kreal) :: fric(2), f3(l_max_elem_node*3+3)
37  integer(kind=kint) :: i, idx0
38 
39  slave = contact%slave(lslave)
40  fcoeff = contact%fcoeff
41  ! clear contact force in former contacted element
42  nrlforce = contact%states(lslave)%multiplier(1)
43  b(3*slave-2:3*slave) = b(3*slave-2:3*slave)+nrlforce*odirec
44  nn = size( contact%master(omaster)%nodes )
45  etype = contact%master(omaster)%etype
46  call getshapefunc( etype, opos(:), shapefunc )
47  do j=1,nn
48  iss = contact%master(omaster)%nodes(j)
49  ! B(3*iSS-2:3*iSS) = B(3*iSS-2:3*iSS)-nrlforce*shapefunc(j)*odirec
50  idx0 = 3*(iss-1)
51  do i=1,3
52  !$omp atomic
53  b(idx0+i) = b(idx0+i)-nrlforce*shapefunc(j)*odirec(i)
54  enddo
55  enddo
56  if( fcoeff/=0.d0 ) then
57  do j=1,nn
58  iss = contact%master(omaster)%nodes(j)
59  elemcrd(:,j) = currpos(3*iss-2:3*iss)
60  enddo
61  call dispincrematrix( opos(:), etype, nn, elemcrd, tangent, &
62  metric, dispmat )
63  fric(1:2) = contact%states(lslave)%multiplier(2:3)
64  f3(:) = fric(1)*dispmat(1,:)+fric(2)*dispmat(2,:)
65  b(3*slave-2:3*slave) = b(3*slave-2:3*slave)+f3(1:3)
66  do j=1,nn
67  iss = contact%master(omaster)%nodes(j)
68  ! B(3*iSS-2:3*iSS) = B(3*iSS-2:3*iSS)+f3(3*j+1:3*j+3)
69  idx0 = 3*(iss-1)
70  do i=1,3
71  !$omp atomic
72  b(idx0+i) = b(idx0+i)+f3(3*j+i)
73  enddo
74  enddo
75  endif
76 
77  ! reset contact force in new contacting element
78  master = contact%states(lslave)%surface
79  nn = size( contact%master(master)%nodes )
80  etype = contact%master(master)%etype
81  call getshapefunc( etype, contact%states(lslave)%lpos(1:2), shapefunc )
82  b(3*slave-2:3*slave) = b(3*slave-2:3*slave)-nrlforce*contact%states(lslave)%direction
83  do j=1,nn
84  iss = contact%master(master)%nodes(j)
85  ! B(3*iSS-2:3*iSS) = B(3*iSS-2:3*iSS)+nrlforce* &
86  ! shapefunc(j)*contact%states(lslave)%direction
87  idx0 = 3*(iss-1)
88  do i=1,3
89  !$omp atomic
90  b(idx0+i) = b(idx0+i)+nrlforce* &
91  shapefunc(j)*contact%states(lslave)%direction(i)
92  enddo
93  enddo
94  if( fcoeff/=0.d0 ) then
95  do j=1,nn
96  iss = contact%master(master)%nodes(j)
97  elemcrd(:,j) = currpos(3*iss-2:3*iss)
98  enddo
99  call dispincrematrix( contact%states(lslave)%lpos(1:2), etype, nn, elemcrd, tangent, &
100  metric, dispmat )
101  fric(1:2) = contact%states(lslave)%multiplier(2:3)
102  f3(:) = fric(1)*dispmat(1,:)+fric(2)*dispmat(2,:)
103  b(3*slave-2:3*slave) = b(3*slave-2:3*slave)-f3(1:3)
104  do j=1,nn
105  iss = contact%master(master)%nodes(j)
106  ! B(3*iSS-2:3*iSS) = B(3*iSS-2:3*iSS)-f3(3*j+1:3*j+3)
107  idx0 = 3*(iss-1)
108  do i=1,3
109  !$omp atomic
110  b(idx0+i) = b(idx0+i)-f3(3*j+i)
111  enddo
112  enddo
113  endif
114 
115  end subroutine reset_contact_force
116 
118  subroutine track_contact_position( flag_ctAlgo, nslave, contact, currpos, currdisp, infoCTChange, nodeID, elemID, B )
119  character(len=9), intent(in) :: flag_ctAlgo
120  integer, intent(in) :: nslave
121  type( tcontact ), intent(inout) :: contact
122  type( fstr_info_contactchange ), intent(inout) :: infoCTChange
123  real(kind=kreal), intent(in) :: currpos(:)
124  real(kind=kreal), intent(in) :: currdisp(:)
125  integer(kind=kint), intent(in) :: nodeID(:)
126  integer(kind=kint), intent(in) :: elemID(:)
127  real(kind=kreal), intent(inout) :: b(:)
128 
129  integer(kind=kint) :: slave, sid0, sid, etype
130  integer(kind=kint) :: nn, i, j, iSS
131  real(kind=kreal) :: coord(3), elem(3, l_max_elem_node), elem0(3, l_max_elem_node)
132  logical :: isin
133  real(kind=kreal) :: opos(2), odirec(3)
134  integer(kind=kint) :: bktID, nCand, idm
135  integer(kind=kint), allocatable :: indexCand(:)
136 
137  sid = 0
138 
139  slave = contact%slave(nslave)
140  coord(:) = currpos(3*slave-2:3*slave)
142  sid0 = contact%states(nslave)%surface
143  opos = contact%states(nslave)%lpos(1:2)
144  odirec = contact%states(nslave)%direction
145  etype = contact%master(sid0)%etype
146  nn = getnumberofnodes( etype )
147  do j=1,nn
148  iss = contact%master(sid0)%nodes(j)
149  elem0(1:3,j)=currpos(3*iss-2:3*iss)-currdisp(3*iss-2:3*iss)
150  enddo
151  call project_point2surfelement( coord, contact%master(sid0), currpos, &
152  contact%states(nslave), isin, contact%cparam%DISTCLR_NOCHECK, &
153  contact%states(nslave)%lpos(1:2), contact%cparam%CLR_SAME_ELEM )
154  if( .not. isin ) then
155  do i=1, contact%master(sid0)%n_neighbor
156  sid = contact%master(sid0)%neighbor(i)
157  call project_point2surfelement( coord, contact%master(sid), currpos, &
158  contact%states(nslave), isin, contact%cparam%DISTCLR_NOCHECK, &
159  localclr=contact%cparam%CLEARANCE )
160  if( isin ) then
161  contact%states(nslave)%surface = sid
162  exit
163  endif
164  enddo
165  endif
166 
167  if( .not. isin ) then ! such case is considered to rarely or never occur
168  write(*,*) 'Warning: contact moved beyond neighbor elements'
169  ! get master candidates from bucketDB
170  bktid = bucketdb_getbucketid(contact%master_bktDB, coord)
171  ncand = bucketdb_getnumcand(contact%master_bktDB, bktid)
172  if (ncand > 0) then
173  allocate(indexcand(ncand))
174  call bucketdb_getcand(contact%master_bktDB, bktid, ncand, indexcand)
175  do idm= 1, ncand
176  sid = indexcand(idm)
177  if( sid==sid0 ) cycle
178  if( associated(contact%master(sid0)%neighbor) ) then
179  if( any(sid==contact%master(sid0)%neighbor(:)) ) cycle
180  endif
181  if (.not. is_in_surface_box( contact%master(sid), coord(1:3), contact%cparam%BOX_EXP_RATE )) cycle
182  call project_point2surfelement( coord, contact%master(sid), currpos, &
183  contact%states(nslave), isin, contact%cparam%DISTCLR_NOCHECK, &
184  localclr=contact%cparam%CLEARANCE )
185  if( isin ) then
186  contact%states(nslave)%surface = sid
187  exit
188  endif
189  enddo
190  deallocate(indexcand)
191  endif
192  endif
193 
194  if( isin ) then
195  if( contact%states(nslave)%surface==sid0 ) then
196  if(any(dabs(contact%states(nslave)%lpos(1:2)-opos(:)) >= contact%cparam%CLR_DIFFLPOS)) then
197  !$omp atomic
198  infoctchange%contact2difflpos = infoctchange%contact2difflpos + 1
199  endif
200  else
201  write(*,'(A,i10,A,i10,A,f7.3,A,2f7.3)') "Node",nodeid(slave)," move to contact with", &
202  elemid(contact%master(sid)%eid), " with distance ", &
203  contact%states(nslave)%distance," at ",contact%states(nslave)%lpos(1:2)
204  !$omp atomic
205  infoctchange%contact2neighbor = infoctchange%contact2neighbor + 1
206  if( flag_ctalgo=='ALagrange' ) &
207  call reset_contact_force( contact, currpos, nslave, sid0, opos, odirec, b )
208  endif
209  if( flag_ctalgo=='SLagrange' ) then
210  ! Setup elem array for update_TangentForce
211  etype = contact%master(contact%states(nslave)%surface)%etype
212  nn = size(contact%master(contact%states(nslave)%surface)%nodes)
213  do j=1,nn
214  iss = contact%master(contact%states(nslave)%surface)%nodes(j)
215  elem(1:3,j)=currpos(3*iss-2:3*iss)
216  enddo
217  call update_tangentforce(etype,nn,elem0,elem,contact%states(nslave))
218  endif
219  iss = isinsideelement( etype, contact%states(nslave)%lpos(1:2), contact%cparam%CLR_CAL_NORM )
220  if( iss>0 ) &
221  call cal_node_normal( contact%states(nslave)%surface, iss, contact%master, currpos, &
222  contact%states(nslave)%lpos(1:2), contact%states(nslave)%direction(:) )
223  else if( .not. isin ) then
224  write(*,'(A,i10,A)') "Node",nodeid(slave)," move out of contact"
225  contact%states(nslave)%state = contactfree
226  contact%states(nslave)%multiplier(:) = 0.d0
227  endif
228 
229  end subroutine track_contact_position
230 
232  subroutine track_contact_position_exp( nslave, contact, currpos, currdisp, infoCTChange, nodeID, elemID )
233  integer, intent(in) :: nslave
234  type( tcontact ), intent(inout) :: contact
235  type( fstr_info_contactchange ), intent(inout) :: infoCTChange
236  real(kind=kreal), intent(in) :: currpos(:)
237  real(kind=kreal), intent(in) :: currdisp(:)
238  integer(kind=kint), intent(in) :: nodeID(:)
239  integer(kind=kint), intent(in) :: elemID(:)
240 
241  integer(kind=kint) :: slave, sid0, sid, etype
242  integer(kind=kint) :: nn, i, j, iSS
243  real(kind=kreal) :: coord(3), elem0(3, l_max_elem_node )
244  logical :: isin
245  real(kind=kreal) :: opos(2), odirec(3)
246  integer(kind=kint) :: bktID, nCand, idm
247  integer(kind=kint), allocatable :: indexCand(:)
248 
249  sid = 0
250 
251  slave = contact%slave(nslave)
252  coord(:) = currpos(3*slave-2:3*slave)
254  sid0 = contact%states(nslave)%surface
255  opos = contact%states(nslave)%lpos(1:2)
256  odirec = contact%states(nslave)%direction
257  etype = contact%master(sid0)%etype
258  nn = getnumberofnodes( etype )
259  do j=1,nn
260  iss = contact%master(sid0)%nodes(j)
261  elem0(1:3,j)=currpos(3*iss-2:3*iss)-currdisp(3*iss-2:3*iss)
262  enddo
263  call project_point2surfelement( coord, contact%master(sid0), currpos, &
264  contact%states(nslave), isin, contact%cparam%DISTCLR_NOCHECK, &
265  contact%states(nslave)%lpos(1:2), contact%cparam%CLR_SAME_ELEM )
266  if( .not. isin ) then
267  do i=1, contact%master(sid0)%n_neighbor
268  sid = contact%master(sid0)%neighbor(i)
269  call project_point2surfelement( coord, contact%master(sid), currpos, &
270  contact%states(nslave), isin, contact%cparam%DISTCLR_NOCHECK, &
271  localclr=contact%cparam%CLEARANCE )
272  if( isin ) then
273  contact%states(nslave)%surface = sid
274  exit
275  endif
276  enddo
277  endif
278 
279  if( .not. isin ) then ! such case is considered to rarely or never occur
280  write(*,*) 'Warning: contact moved beyond neighbor elements'
281  ! get master candidates from bucketDB
282  bktid = bucketdb_getbucketid(contact%master_bktDB, coord)
283  ncand = bucketdb_getnumcand(contact%master_bktDB, bktid)
284  if (ncand > 0) then
285  allocate(indexcand(ncand))
286  call bucketdb_getcand(contact%master_bktDB, bktid, ncand, indexcand)
287  do idm= 1, ncand
288  sid = indexcand(idm)
289  if( sid==sid0 ) cycle
290  if( any(sid==contact%master(sid0)%neighbor(:)) ) cycle
291  if (.not. is_in_surface_box( contact%master(sid), coord(1:3), contact%cparam%BOX_EXP_RATE )) cycle
292  call project_point2surfelement( coord, contact%master(sid), currpos, &
293  contact%states(nslave), isin, contact%cparam%DISTCLR_NOCHECK, &
294  localclr=contact%cparam%CLEARANCE )
295  if( isin ) then
296  contact%states(nslave)%surface = sid
297  exit
298  endif
299  enddo
300  deallocate(indexcand)
301  endif
302  endif
303 
304  if( isin ) then
305  if( contact%states(nslave)%surface==sid0 ) then
306  if(any(dabs(contact%states(nslave)%lpos(1:2)-opos(:)) >= contact%cparam%CLR_DIFFLPOS)) then
307  !$omp atomic
308  infoctchange%contact2difflpos = infoctchange%contact2difflpos + 1
309  endif
310  else
311  write(*,'(A,i10,A,i10,A,f7.3,A,2f7.3)') "Node",nodeid(slave)," move to contact with", &
312  elemid(contact%master(sid)%eid), " with distance ", &
313  contact%states(nslave)%distance," at ",contact%states(nslave)%lpos(1:2)
314  !$omp atomic
315  infoctchange%contact2neighbor = infoctchange%contact2neighbor + 1
316  endif
317  iss = isinsideelement( etype, contact%states(nslave)%lpos(1:2), contact%cparam%CLR_CAL_NORM )
318  if( iss>0 ) then
319  call cal_node_normal( contact%states(nslave)%surface, iss, contact%master, currpos, &
320  contact%states(nslave)%lpos(1:2), contact%states(nslave)%direction(:) )
321  endif
322  else if( .not. isin ) then
323  write(*,'(A,i10,A)') "Node",nodeid(slave)," move out of contact"
324  contact%states(nslave)%state = contactfree
325  contact%states(nslave)%multiplier(:) = 0.d0
326  endif
327 
328  end subroutine track_contact_position_exp
329 
333  subroutine scan_contact_state( flag_ctAlgo, contact, currpos, currdisp, ndforce, infoCTChange, &
334  nodeID, elemID, is_init, active, B )
335  character(len=9), intent(in) :: flag_ctAlgo
336  type( tcontact ), intent(inout) :: contact
337  type( fstr_info_contactchange ), intent(inout) :: infoCTChange
338  real(kind=kreal), intent(in) :: currpos(:)
339  real(kind=kreal), intent(in) :: currdisp(:)
340  real(kind=kreal), intent(in) :: ndforce(:)
341  integer(kind=kint), intent(in) :: nodeID(:)
342  integer(kind=kint), intent(in) :: elemID(:)
343  logical, intent(in) :: is_init
344  logical, intent(out) :: active
345  real(kind=kreal), optional, target :: b(:)
346 
347  real(kind=kreal) :: distclr
348  integer(kind=kint) :: slave, id, etype
349  integer(kind=kint) :: i, iSS, nactive
350  real(kind=kreal) :: coord(3)
351  real(kind=kreal) :: nlforce, slforce(3)
352  logical :: isin
353  integer(kind=kint), allocatable :: contact_surf(:), states_prev(:)
354  !
355  integer, pointer :: indexMaster(:),indexCand(:)
356  integer :: nMaster,idm,nMasterMax,bktID,nCand
357  logical :: is_present_B
358  real(kind=kreal), pointer :: bp(:)
359 
360  if( is_init ) then
361  distclr = contact%cparam%DISTCLR_INIT
362  else
363  distclr = contact%cparam%DISTCLR_FREE
364  if( contact%algtype == contacttied ) then
365  active = .false.
366  do i= 1, size(contact%slave)
367  if( contact%states(i)%state==contactstick ) then
368  active = .true.
369  exit
370  endif
371  enddo
372  endif
373  endif
374 
375  allocate(contact_surf(size(nodeid)))
376  allocate(states_prev(size(contact%slave)))
377  contact_surf(:) = huge(0)
378  do i = 1, size(contact%slave)
379  states_prev(i) = contact%states(i)%state
380  enddo
381 
382  call update_surface_box_info( contact%master, currpos )
383  call update_surface_bucket_info( contact%master, contact%master_bktDB )
384 
385  ! for gfortran-10: optional parameter seems not allowed within omp parallel
386  is_present_b = present(b)
387  if( is_present_b ) bp => b
388 
389  !$omp parallel do &
390  !$omp& default(none) &
391  !$omp& private(i,slave,slforce,id,nlforce,coord,indexMaster,nMaster,iSS,idm,etype,isin, &
392  !$omp& bktID,nCand,indexCand) &
393  !$omp& firstprivate(nMasterMax,is_present_B) &
394  !$omp& shared(contact,ndforce,flag_ctAlgo,infoCTChange,currpos,currdisp,nodeID,elemID,Bp,distclr,contact_surf,is_init) &
395  !$omp& reduction(.or.:active) &
396  !$omp& schedule(dynamic,1)
397  do i= 1, size(contact%slave)
398  if(contact%if_type /= 0) call set_shrink_factor(contact%ctime, contact%states(i), contact%if_etime, contact%if_type)
399  slave = contact%slave(i)
400  if( contact%states(i)%state==contactstick .or. contact%states(i)%state==contactslip ) then
401  slforce(1:3)=ndforce(3*slave-2:3*slave)
402  id = contact%states(i)%surface
403  nlforce = contact%states(i)%multiplier(1)
404 
405  ! update direction of TIED contact
406  if( contact%algtype == contacttied ) then
407  call update_direction( i, contact, currpos )
408  if (.not.is_init) cycle
409  endif
410 
411  if( nlforce < contact%cparam%TENSILE_FORCE ) then
412  contact%states(i)%state = contactfree
413  contact%states(i)%multiplier(:) = 0.d0
414  write(*,'(A,i10,A,i10,A,e12.3)') "Node",nodeid(slave)," free from contact with element", &
415  elemid(contact%master(id)%eid), " with tensile force ", nlforce
416  cycle
417  endif
418  if( contact%algtype /= contactfslid .or. (.not. is_present_b) ) then ! small slide problem
419  contact_surf(contact%slave(i)) = -elemid(contact%master(id)%eid)
420  else
421  call track_contact_position( flag_ctalgo, i, contact, currpos, currdisp, infoctchange, nodeid, elemid, bp )
422  if( contact%states(i)%state /= contactfree ) then
423  id = contact%states(i)%surface
424  contact_surf(contact%slave(i)) = -elemid(contact%master(id)%eid)
425  endif
426  endif
427 
428  else if( contact%states(i)%state==contactfree ) then
429  if( contact%algtype == contacttied .and. .not. is_init ) cycle
430  coord(:) = currpos(3*slave-2:3*slave)
431 
432  ! get master candidates from bucketDB
433  bktid = bucketdb_getbucketid(contact%master_bktDB, coord)
434  ncand = bucketdb_getnumcand(contact%master_bktDB, bktid)
435  if (ncand == 0) cycle
436  allocate(indexcand(ncand))
437  call bucketdb_getcand(contact%master_bktDB, bktid, ncand, indexcand)
438 
439  nmastermax = ncand
440  allocate(indexmaster(nmastermax))
441  nmaster = 0
442 
443  ! narrow down candidates
444  do idm= 1, ncand
445  id = indexcand(idm)
446  if (.not. is_in_surface_box( contact%master(id), coord(1:3), contact%cparam%BOX_EXP_RATE )) cycle
447  nmaster = nmaster + 1
448  indexmaster(nmaster) = id
449  enddo
450  deallocate(indexcand)
451 
452  if(nmaster == 0) then
453  deallocate(indexmaster)
454  cycle
455  endif
456 
457  do idm = 1,nmaster
458  id = indexmaster(idm)
459  call project_point2surfelement( coord, contact%master(id), currpos, &
460  contact%states(i), isin, distclr, localclr=contact%cparam%CLEARANCE )
461  if( .not. isin ) cycle
462  contact%states(i)%surface = id
463  contact%states(i)%multiplier(:) = 0.d0
464  etype = contact%master(id)%etype
465  iss = isinsideelement( etype, contact%states(i)%lpos(1:2), contact%cparam%CLR_CAL_NORM )
466  if( iss>0 ) &
467  call cal_node_normal( id, iss, contact%master, currpos, contact%states(i)%lpos(1:2), &
468  contact%states(i)%direction(:) )
469  contact_surf(contact%slave(i)) = elemid(contact%master(id)%eid)
470  write(*,'(A,i10,A,i10,A,f7.3,A,2f7.3,A,3f7.3,A,i6)') "Node",nodeid(slave)," contact with element", &
471  elemid(contact%master(id)%eid), &
472  " with distance ", contact%states(i)%distance," at ",contact%states(i)%lpos(1:2), &
473  " along direction ", contact%states(i)%direction," rank=",hecmw_comm_get_rank()
474  exit
475  enddo
476  deallocate(indexmaster)
477  endif
478  enddo
479  !$omp end parallel do
480 
481  if( contact%algtype == contacttied .and. .not. is_init ) then
482  deallocate(contact_surf)
483  deallocate(states_prev)
484  return
485  endif
486 
487  call hecmw_contact_comm_allreduce_i(contact%comm, contact_surf, hecmw_min)
488  nactive = 0
489  do i = 1, size(contact%slave)
490  if (contact%states(i)%state /= contactfree) then ! any slave in contact
491  id = contact%states(i)%surface
492  if (abs(contact_surf(contact%slave(i))) /= elemid(contact%master(id)%eid)) then ! that is in contact with other surface
493  contact%states(i)%state = contactfree ! should be freed
494  write(*,'(A,i10,A,i10,A,i6,A,i6,A)') "Node",nodeid(contact%slave(i))," contact with element", &
495  & elemid(contact%master(id)%eid), " in rank",hecmw_comm_get_rank()," freed due to duplication"
496  else
497  nactive = nactive + 1
498  endif
499  endif
500  if (states_prev(i) == contactfree .and. contact%states(i)%state /= contactfree) then
501  infoctchange%free2contact = infoctchange%free2contact + 1
502  elseif (states_prev(i) /= contactfree .and. contact%states(i)%state == contactfree) then
503  infoctchange%contact2free = infoctchange%contact2free + 1
504  endif
505  enddo
506  active = (nactive > 0)
507  deallocate(contact_surf)
508  deallocate(states_prev)
509  end subroutine scan_contact_state
510 
514  subroutine scan_contact_state_exp( contact, currpos, currdisp, infoCTChange, &
515  nodeID, elemID, is_init, active )
516  type( tcontact ), intent(inout) :: contact
517  type( fstr_info_contactchange ), intent(inout) :: infoCTChange
518  real(kind=kreal), intent(in) :: currpos(:)
519  real(kind=kreal), intent(in) :: currdisp(:)
520  integer(kind=kint), intent(in) :: nodeID(:)
521  integer(kind=kint), intent(in) :: elemID(:)
522  logical, intent(in) :: is_init
523  logical, intent(out) :: active
524 
525  real(kind=kreal) :: distclr
526  integer(kind=kint) :: slave, id, etype
527  integer(kind=kint) :: i, iSS, nactive
528  real(kind=kreal) :: coord(3)
529  logical :: isin
530  integer(kind=kint), allocatable :: contact_surf(:), states_prev(:)
531  !
532  integer, pointer :: indexMaster(:),indexCand(:)
533  integer :: nMaster,idm,nMasterMax,bktID,nCand
534 
535  if( is_init ) then
536  distclr = contact%cparam%DISTCLR_INIT
537  else
538  distclr = contact%cparam%DISTCLR_FREE
539  if( contact%algtype == contacttied ) then
540  active = .false.
541  do i= 1, size(contact%slave)
542  if( contact%states(i)%state==contactstick ) then
543  active = .true.
544  exit
545  endif
546  enddo
547  return
548  endif
549  endif
550 
551  allocate(contact_surf(size(nodeid)))
552  allocate(states_prev(size(contact%slave)))
553  contact_surf(:) = size(elemid)+1
554  do i = 1, size(contact%slave)
555  states_prev(i) = contact%states(i)%state
556  enddo
557 
558  call update_surface_box_info( contact%master, currpos )
559  call update_surface_bucket_info( contact%master, contact%master_bktDB )
560 
561  !$omp parallel do &
562  !$omp& default(none) &
563  !$omp& private(i,slave,id,coord,indexMaster,nMaster,iSS,idm,etype,isin, &
564  !$omp& bktID,nCand,indexCand) &
565  !$omp& firstprivate(nMasterMax) &
566  !$omp& shared(contact,infoCTChange,currpos,currdisp,nodeID,elemID,distclr,contact_surf) &
567  !$omp& reduction(.or.:active) &
568  !$omp& schedule(dynamic,1)
569  do i= 1, size(contact%slave)
570  slave = contact%slave(i)
571  if( contact%states(i)%state==contactstick .or. contact%states(i)%state==contactslip ) then
572  call track_contact_position_exp( i, contact, currpos, currdisp, infoctchange, nodeid, elemid )
573  if( contact%states(i)%state /= contactfree ) then
574  contact_surf(contact%slave(i)) = -contact%states(i)%surface
575  endif
576  else if( contact%states(i)%state==contactfree ) then
577  coord(:) = currpos(3*slave-2:3*slave)
578 
579  ! get master candidates from bucketDB
580  bktid = bucketdb_getbucketid(contact%master_bktDB, coord)
581  ncand = bucketdb_getnumcand(contact%master_bktDB, bktid)
582  if (ncand == 0) cycle
583  allocate(indexcand(ncand))
584  call bucketdb_getcand(contact%master_bktDB, bktid, ncand, indexcand)
585 
586  nmastermax = ncand
587  allocate(indexmaster(nmastermax))
588  nmaster = 0
589 
590  ! narrow down candidates
591  do idm= 1, ncand
592  id = indexcand(idm)
593  if (.not. is_in_surface_box( contact%master(id), coord(1:3), contact%cparam%BOX_EXP_RATE )) cycle
594  nmaster = nmaster + 1
595  indexmaster(nmaster) = id
596  enddo
597  deallocate(indexcand)
598 
599  if(nmaster == 0) then
600  deallocate(indexmaster)
601  cycle
602  endif
603 
604  do idm = 1,nmaster
605  id = indexmaster(idm)
606  call project_point2surfelement( coord, contact%master(id), currpos, &
607  contact%states(i), isin, distclr, localclr=contact%cparam%CLEARANCE )
608  if( .not. isin ) cycle
609  contact%states(i)%surface = id
610  contact%states(i)%multiplier(:) = 0.d0
611  etype = contact%master(id)%etype
612  iss = isinsideelement( etype, contact%states(i)%lpos(1:2), contact%cparam%CLR_CAL_NORM )
613  if( iss>0 ) &
614  call cal_node_normal( id, iss, contact%master, currpos, contact%states(i)%lpos(1:2), &
615  contact%states(i)%direction(:) )
616  contact_surf(contact%slave(i)) = id
617  write(*,'(A,i10,A,i10,A,f7.3,A,2f7.3,A,3f7.3)') "Node",nodeid(slave)," contact with element", &
618  elemid(contact%master(id)%eid), &
619  " with distance ", contact%states(i)%distance," at ",contact%states(i)%lpos(1:2), &
620  " along direction ", contact%states(i)%direction
621  exit
622  enddo
623  deallocate(indexmaster)
624  endif
625  enddo
626  !$omp end parallel do
627 
628  call hecmw_contact_comm_allreduce_i(contact%comm, contact_surf, hecmw_min)
629  nactive = 0
630  do i = 1, size(contact%slave)
631  if (contact%states(i)%state /= contactfree) then ! any slave in contact
632  if (abs(contact_surf(contact%slave(i))) /= contact%states(i)%surface) then ! that is in contact with other surface
633  contact%states(i)%state = contactfree ! should be freed
634  write(*,'(A,i10,A,i6,A,i6,A)') "Node",nodeid(contact%slave(i)), &
635  " in rank",hecmw_comm_get_rank()," freed due to duplication"
636  else
637  nactive = nactive + 1
638  endif
639  endif
640  if (states_prev(i) == contactfree .and. contact%states(i)%state /= contactfree) then
641  infoctchange%free2contact = infoctchange%free2contact + 1
642  elseif (states_prev(i) /= contactfree .and. contact%states(i)%state == contactfree) then
643  infoctchange%contact2free = infoctchange%contact2free + 1
644  endif
645  enddo
646  active = (nactive > 0)
647  deallocate(contact_surf)
648  deallocate(states_prev)
649  end subroutine scan_contact_state_exp
650 
654  subroutine scan_embed_state( flag_ctAlgo, embed, currpos, currdisp, ndforce, infoCTChange, &
655  nodeID, elemID, is_init, active, B )
656  character(len=9), intent(in) :: flag_ctAlgo
657  type( tcontact ), intent(inout) :: embed
658  type( fstr_info_contactchange ), intent(inout) :: infoCTChange
659  real(kind=kreal), intent(in) :: currpos(:)
660  real(kind=kreal), intent(in) :: currdisp(:)
661  real(kind=kreal), intent(in) :: ndforce(:)
662  integer(kind=kint), intent(in) :: nodeID(:)
663  integer(kind=kint), intent(in) :: elemID(:)
664  logical, intent(in) :: is_init
665  logical, intent(out) :: active
666  real(kind=kreal), optional, target :: b(:)
667 
668  real(kind=kreal) :: distclr
669  integer(kind=kint) :: slave, id, etype
670  integer(kind=kint) :: nn, i, j, iSS, nactive
671  real(kind=kreal) :: coord(3), elem(3, l_max_elem_node )
672  logical :: isin
673  integer(kind=kint), allocatable :: contact_surf(:), states_prev(:)
674  !
675  integer, pointer :: indexMaster(:),indexCand(:)
676  integer :: nMaster,idm,nMasterMax,bktID,nCand
677  logical :: is_present_B
678  real(kind=kreal), pointer :: bp(:)
679 
680  if( is_init ) then
681  distclr = embed%cparam%DISTCLR_INIT
682  else
683  distclr = embed%cparam%DISTCLR_FREE
684  active = .false.
685  do i= 1, size(embed%slave)
686  if( embed%states(i)%state==contactstick ) then
687  active = .true.
688  exit
689  endif
690  enddo
691  return
692  endif
693 
694  allocate(contact_surf(size(nodeid)))
695  allocate(states_prev(size(embed%slave)))
696  contact_surf(:) = huge(0)
697  do i = 1, size(embed%slave)
698  states_prev(i) = embed%states(i)%state
699  enddo
700 
701  call update_surface_box_info( embed%master, currpos )
702  call update_surface_bucket_info( embed%master, embed%master_bktDB )
703 
704  ! for gfortran-10: optional parameter seems not allowed within omp parallel
705  is_present_b = present(b)
706  if( is_present_b ) bp => b
707 
708  !$omp parallel do &
709  !$omp& default(none) &
710  !$omp& private(i,slave,id,coord,indexMaster,nMaster,nn,j,iSS,elem,idm,etype,isin, &
711  !$omp& bktID,nCand,indexCand) &
712  !$omp& firstprivate(nMasterMax,is_present_B) &
713  !$omp& shared(embed,ndforce,flag_ctAlgo,infoCTChange,currpos,currdisp,nodeID,elemID,Bp,distclr,contact_surf) &
714  !$omp& reduction(.or.:active) &
715  !$omp& schedule(dynamic,1)
716  do i= 1, size(embed%slave)
717  slave = embed%slave(i)
718  if( embed%states(i)%state==contactfree ) then
719  coord(:) = currpos(3*slave-2:3*slave)
720 
721  ! get master candidates from bucketDB
722  bktid = bucketdb_getbucketid(embed%master_bktDB, coord)
723  ncand = bucketdb_getnumcand(embed%master_bktDB, bktid)
724  if (ncand == 0) cycle
725  allocate(indexcand(ncand))
726  call bucketdb_getcand(embed%master_bktDB, bktid, ncand, indexcand)
727 
728  nmastermax = ncand
729  allocate(indexmaster(nmastermax))
730  nmaster = 0
731 
732  ! narrow down candidates
733  do idm= 1, ncand
734  id = indexcand(idm)
735  if (.not. is_in_surface_box( embed%master(id), coord(1:3), embed%cparam%BOX_EXP_RATE )) cycle
736  nmaster = nmaster + 1
737  indexmaster(nmaster) = id
738  enddo
739  deallocate(indexcand)
740 
741  if(nmaster == 0) then
742  deallocate(indexmaster)
743  cycle
744  endif
745 
746  do idm = 1,nmaster
747  id = indexmaster(idm)
748  etype = embed%master(id)%etype
749  if( mod(etype,10) == 2 ) etype = etype - 1 !search by 1st-order shape function
750  nn = getnumberofnodes(etype)
751  do j=1,nn
752  iss = embed%master(id)%nodes(j)
753  elem(1:3,j)=currpos(3*iss-2:3*iss)
754  enddo
755  call project_point2solidelement( coord,etype,nn,elem,embed%master(id)%reflen,embed%states(i), &
756  isin,distclr,localclr=embed%cparam%CLEARANCE )
757  if( .not. isin ) cycle
758  embed%states(i)%surface = id
759  embed%states(i)%multiplier(:) = 0.d0
760  contact_surf(embed%slave(i)) = elemid(embed%master(id)%eid)
761  write(*,'(A,i10,A,i10,A,3f7.3,A,i6)') "Node",nodeid(slave)," embeded to element", &
762  elemid(embed%master(id)%eid), " at ",embed%states(i)%lpos(:)," rank=",hecmw_comm_get_rank()
763  exit
764  enddo
765  deallocate(indexmaster)
766  endif
767  enddo
768  !$omp end parallel do
769 
770  call hecmw_contact_comm_allreduce_i(embed%comm, contact_surf, hecmw_min)
771  nactive = 0
772  do i = 1, size(embed%slave)
773  if (embed%states(i)%state /= contactfree) then ! any slave in contact
774  id = embed%states(i)%surface
775  if (abs(contact_surf(embed%slave(i))) /= elemid(embed%master(id)%eid)) then ! that is in contact with other surface
776  embed%states(i)%state = contactfree ! should be freed
777  write(*,'(A,i10,A,i10,A,i6,A,i6,A)') "Node",nodeid(embed%slave(i))," contact with element", &
778  & elemid(embed%master(id)%eid), " in rank",hecmw_comm_get_rank()," freed due to duplication"
779  else
780  nactive = nactive + 1
781  endif
782  endif
783  if (states_prev(i) == contactfree .and. embed%states(i)%state /= contactfree) then
784  infoctchange%free2contact = infoctchange%free2contact + 1
785  elseif (states_prev(i) /= contactfree .and. embed%states(i)%state == contactfree) then
786  infoctchange%contact2free = infoctchange%contact2free + 1
787  endif
788  enddo
789  active = (nactive > 0)
790  deallocate(contact_surf)
791  deallocate(states_prev)
792  end subroutine scan_embed_state
793 
795  subroutine remove_duplication_tiedcontact( cstep, hecMESH, fstrSOLID, infoCTChange )
796  integer(kind=kint), intent(in) :: cstep
797  type( hecmwst_local_mesh ), intent(in) :: hecMESH
798  type(fstr_solid), intent(inout) :: fstrSOLID
799  type(fstr_info_contactchange), intent(inout):: infoCTChange
800 
801  integer(kind=kint) :: i, j, grpid, slave
802  integer(kind=kint) :: k, id, iSS
803  integer(kind=kint) :: ig0, ig, iS0, iE0
804  integer(kind=kint), allocatable :: states(:)
805 
806  allocate(states(hecmesh%n_node))
807  states(:) = contactfree
808 
809  ! if a boundary condition is given, the slave
810  do ig0= 1, fstrsolid%BOUNDARY_ngrp_tot
811  grpid = fstrsolid%BOUNDARY_ngrp_GRPID(ig0)
812  if( .not. fstr_isboundaryactive( fstrsolid, grpid, cstep ) ) cycle
813  ig= fstrsolid%BOUNDARY_ngrp_ID(ig0)
814  is0= hecmesh%node_group%grp_index(ig-1) + 1
815  ie0= hecmesh%node_group%grp_index(ig )
816  do k= is0, ie0
817  iss = hecmesh%node_group%grp_item(k)
818  !states(iSS) = CONTACTSTICK
819  enddo
820  enddo
821 
822  do i=1,fstrsolid%n_contacts
823  if( fstrsolid%contacts(i)%algtype /= contacttied ) cycle
824  grpid = fstrsolid%contacts(i)%group
825  if( .not. fstr_iscontactactive( fstrsolid, grpid, cstep ) ) cycle
826 
827  do j=1, size(fstrsolid%contacts(i)%slave)
828  if( fstrsolid%contacts(i)%states(j)%state==contactfree ) cycle ! free
829  slave = fstrsolid%contacts(i)%slave(j)
830  if( states(slave) == contactfree ) then
831  states(slave) = fstrsolid%contacts(i)%states(j)%state
832  id = fstrsolid%contacts(i)%states(j)%surface
833  do k=1,size( fstrsolid%contacts(i)%master(id)%nodes )
834  iss = fstrsolid%contacts(i)%master(id)%nodes(k)
835  states(iss) = fstrsolid%contacts(i)%states(j)%state
836  enddo
837  else !found duplicate tied contact slave node
838  fstrsolid%contacts(i)%states(j)%state = contactfree
839  infoctchange%free2contact = infoctchange%free2contact - 1
840  write(*,'(A,i10,A,i6,A,i6,A)') "Node",hecmesh%global_node_ID(slave), &
841  " in rank",hecmw_comm_get_rank()," freed due to duplication"
842  endif
843  enddo
844  enddo
845 
846  end subroutine
847 
848 end module m_fstr_contact_search
This module encapsulate the basic functions of all elements provide by this software.
Definition: element.f90:43
subroutine getshapefunc(fetype, localcoord, func)
Calculate the shape function in natural coordinate system.
Definition: element.f90:647
integer(kind=kind(2)) function getnumberofnodes(etype)
Obtain number of nodes of the element.
Definition: element.f90:131
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:1036
Definition: hecmw.f90:6
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 dispincrematrix(pos, etype, nnode, ele, tangent, tensor, matrix)
This subroutine calculate the relation between global disp and displacement along natural coordinate ...
subroutine project_point2surfelement(xyz, surf, currpos, cstate, isin, distclr, ctpos, localclr)
Wrapper for project_Point2Element that takes tSurfElement structure This subroutine handles element c...
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_exp(nslave, contact, currpos, currdisp, infoCTChange, nodeID, elemID)
This subroutine tracks down next contact position after a finite slide.
subroutine remove_duplication_tiedcontact(cstep, hecMESH, fstrSOLID, infoCTChange)
Scanning contact state.
subroutine scan_contact_state_exp(contact, currpos, currdisp, infoCTChange, nodeID, elemID, is_init, active)
This subroutine update contact states, which include.
subroutine scan_contact_state(flag_ctAlgo, contact, currpos, currdisp, ndforce, infoCTChange, nodeID, elemID, is_init, active, B)
This subroutine update contact states, which include.
subroutine reset_contact_force(contact, currpos, lslave, omaster, opos, odirec, B)
This subroutine update contact force in case that contacting element is changed.
subroutine scan_embed_state(flag_ctAlgo, embed, currpos, currdisp, ndforce, infoCTChange, nodeID, elemID, is_init, active, B)
This subroutine update contact states, which include.
subroutine track_contact_position(flag_ctAlgo, nslave, contact, currpos, currdisp, infoCTChange, nodeID, elemID, B)
This subroutine tracks down next contact position after a finite slide.
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:1067
logical function fstr_isboundaryactive(fstrSOLID, nbc, cstep)
Definition: m_fstr.f90:1043
This module manages the data structure for contact calculation.
integer, parameter contactslip
integer, parameter contacttied
contact type or algorithm definition
integer, parameter contactfree
contact state definition
integer, parameter contactfslid
integer, parameter contactstick
Structure to includes all info needed by contact calculation.