FrontISTR  6.0.0
Large-scale structural analysis program with finit element method
fstr_contact_assembly.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 hecmw
9  use m_fstr
10  use mcontactdef
16  implicit none
17 
19 
20 contains
21 
23  subroutine calc_contact_pair_refstiff(contact, diag, ndof, hecMESH)
24  type(tcontact), intent(inout) :: contact
25  real(kind=kreal), intent(in) :: diag(:)
26  integer(kind=kint), intent(in) :: ndof
27  type(hecmwst_local_mesh), intent(in) :: hecmesh
28 
29  integer(kind=kint) :: i, j, k, slave_node, master_node, nnode, ctsurf
30  integer(kind=kint) :: idx_start, idx_end, n_slave
31  integer(kind=kint) :: cgrp, ic, iss, outtype, fnodes(100)
32  real(kind=kreal) :: maxv
33  real(kind=kreal) :: a_rep, slave_reflen_sum
34  real(kind=kreal) :: elem(3, l_max_surface_node), r0(2)
35 
36  maxv = 0.0d0
37 
38  ! Loop over slave nodes
39  do j = 1, size(contact%slave)
40  slave_node = contact%slave(j)
41  ! The mortar refStiff must be partition-invariant: skip GHOST(external) rows, whose
42  ! diagonal is not fully assembled here. Every slave node is internal on exactly one
43  ! rank, so the allreduce-MAX below still sees every fully-assembled diagonal.
44  if( contact%method == contacts2s .and. slave_node > hecmesh%nn_internal ) cycle
45  idx_start = ndof * (slave_node - 1) + 1
46  idx_end = ndof * slave_node
47  maxv = max(maxv, maxval(diag(idx_start:idx_end)))
48  enddo
49 
50  ! Loop over master surfaces and nodes
51  if( contact%method == contacts2s ) then
52  ! Enumerate the master faces from the surface group instead of contact%master: with
53  ! !PARTITION, CONTACT_OWNER=SLAVE a rank that owns no slave node takes no master surface
54  ! at all (fstr_contact_init), so the diagonals of the master nodes it owns would never
55  ! enter the max and refStiff would depend on the partition. The surface group items are
56  ! present wherever the element is, so taking internal rows only on every rank lets the
57  ! allreduce-MAX reproduce the serial value.
58  cgrp = contact%surf_id2
59  if( cgrp > 0 ) then
60  do i = hecmesh%surf_group%grp_index(cgrp-1)+1, hecmesh%surf_group%grp_index(cgrp)
61  ic = hecmesh%surf_group%grp_item(2*i-1)
62  call getsubface( hecmesh%elem_type(ic), hecmesh%surf_group%grp_item(2*i), outtype, fnodes )
63  nnode = getnumberofnodes( outtype )
64  iss = hecmesh%elem_node_index(ic-1)
65  do j = 1, nnode
66  master_node = hecmesh%elem_node_item( iss + fnodes(j) )
67  if( master_node > hecmesh%nn_internal ) cycle
68  idx_start = ndof * (master_node - 1) + 1
69  idx_end = ndof * master_node
70  maxv = max(maxv, maxval(diag(idx_start:idx_end)))
71  enddo
72  enddo
73  endif
74  else
75  do ctsurf = 1, size(contact%master)
76  nnode = size(contact%master(ctsurf)%nodes)
77  do j = 1, nnode
78  master_node = contact%master(ctsurf)%nodes(j)
79  idx_start = ndof * (master_node - 1) + 1
80  idx_end = ndof * master_node
81  maxv = max(maxv, maxval(diag(idx_start:idx_end)))
82  enddo
83  enddo
84  endif
85 
86  ! Parallel reduction
87  call hecmw_allreduce_r1(hecmesh, maxv, hecmw_max)
88 
89  ! Set reference stiffness for this contact pair
90  contact%refStiff = maxv
91 
92  ! Mortar dimensional correction: the mortar penalty multiplies refStiff by the contact
93  ! area, so refStiff is divided by a representative tributary area A_rep = (slave reflen)^2
94  ! to make mu = nPenalty*refStiff a pressure density. The same nPenalty then gives the same
95  ! effective stiffness as the NODE-SURF per-node form. reflen is taken from the slave element
96  ! (the constraint is integrated on the slave surface). NODE-SURF pairs are left untouched.
97  if( contact%method == contacts2s ) then
98  ! Local slave reference-length sum and slave-face count (0 if this rank owns none).
99  slave_reflen_sum = 0.0d0
100  n_slave = 0
101  if( associated(contact%slave_surf) ) n_slave = size(contact%slave_surf)
102  do j = 1, n_slave
103  nnode = size(contact%slave_surf(j)%nodes)
104  do k = 1, nnode
105  ctsurf = contact%slave_surf(j)%nodes(k)
106  elem(1:3,k) = hecmesh%node(3*ctsurf-2:3*ctsurf)
107  enddo
108  call getelementcenter( contact%slave_surf(j)%etype, r0 )
109  slave_reflen_sum = slave_reflen_sum + &
110  getreferencelength( contact%slave_surf(j)%etype, nnode, r0, elem )
111  enddo
112  ! Reduced outside the slave_surf>0 gate (ranks owning no slave face must still join the
113  ! collective) but inside the method gate. Slave faces are owned by exactly one rank, so the
114  ! SUM reproduces the serial value on every rank.
115  call hecmw_allreduce_r1(hecmesh, slave_reflen_sum, hecmw_sum)
116  call hecmw_allreduce_i1(hecmesh, n_slave, hecmw_sum)
117  a_rep = 0.0d0
118  if( n_slave > 0 ) then
119  a_rep = ( slave_reflen_sum / dble(n_slave) ) ** 2
120  if( a_rep > 0.0d0 ) contact%refStiff = contact%refStiff / a_rep
121  endif
122  endif
123 
124  ! Report penalty settings
125  if (hecmw_comm_get_rank() == 0) then
126  write(*,'(A,A,A,1pE12.3,A,1pE12.3,A,1pE12.3)') " Contact [", &
127  trim(contact%pair_name), "] set penalty: normal & tied ", &
128  contact%nPenalty * contact%refStiff, ", tangential ", &
129  contact%tPenalty * contact%refStiff, ", refStiff ", contact%refStiff
130  endif
131 
132  end subroutine calc_contact_pair_refstiff
133 
135  subroutine assemble_contact_force_residual(nnode,ndLocal,id_lagrange,ctNForce,ctTForce,conMAT)
136  integer(kind=kint), intent(in) :: nnode
137  integer(kind=kint), intent(in) :: ndLocal(nnode + 1)
138  integer(kind=kint), intent(in) :: id_lagrange
139  real(kind=kreal), intent(in) :: ctnforce((nnode+1)*3+1)
140  real(kind=kreal), intent(in) :: cttforce((nnode+1)*3+1)
141  type(hecmwst_matrix), intent(inout) :: conmat
142 
143  integer(kind=kint) :: i, inod, idx
144 
145  do i = 1, nnode + 1
146  inod = ndlocal(i)
147  idx = (inod-1)*3+1
148  conmat%B(idx:idx+2) = conmat%B(idx:idx+2) + ctnforce((i-1)*3+1:(i-1)*3+3) + cttforce((i-1)*3+1:(i-1)*3+3)
149  enddo
150 
151  ! Accumulate: several contributions can target the same Lagrange row (the caller
152  ! zero-clears conMAT%B before the contact assembly).
153  if( id_lagrange > 0 ) then
154  conmat%B(conmat%NP*conmat%NDOF+id_lagrange) = &
155  conmat%B(conmat%NP*conmat%NDOF+id_lagrange) + ctnforce((nnode+1)*3+1) + cttforce((nnode+1)*3+1)
156  endif
157 
158  end subroutine assemble_contact_force_residual
159 
161  subroutine assemble_contact_force_output(nnode,ndLocal,ctNForce,ctTForce,cont_nforce,cont_fric)
162  integer(kind=kint), intent(in) :: nnode
163  integer(kind=kint), intent(in) :: ndlocal(nnode + 1)
164  real(kind=kreal), intent(in) :: ctnforce((nnode+1)*3+1)
165  real(kind=kreal), intent(in) :: cttforce((nnode+1)*3+1)
166  real(kind=kreal), pointer, intent(inout) :: cont_nforce(:)
167  real(kind=kreal), pointer, optional, intent(inout) :: cont_fric(:)
168 
169  integer(kind=kint) :: i, inod, idx
170 
171  do i = 1, nnode + 1
172  inod = ndlocal(i)
173  idx = (inod-1)*3+1
174  cont_nforce(idx:idx+2) = cont_nforce(idx:idx+2) + ctnforce((i-1)*3+1:(i-1)*3+3)
175  if( present(cont_fric) ) cont_fric(idx:idx+2) = cont_fric(idx:idx+2) + cttforce((i-1)*3+1:(i-1)*3+3)
176  enddo
177 
178  end subroutine assemble_contact_force_output
179 
182  subroutine update_contact_multiplier( contact, coord, disp, ddisp, fcoeff, &
183  hecMESH, hecLagMAT, gnt, ctchanged )
184  type( tcontact ), intent(inout) :: contact
185  real(kind=kreal), intent(in) :: coord(:)
186  real(kind=kreal), intent(in) :: disp(:)
187  real(kind=kreal), intent(in) :: ddisp(:)
188  real(kind=kreal), intent(in) :: fcoeff
189  type(hecmwst_local_mesh), intent(in) :: hecmesh
190  type(hecmwst_matrix_lagrange), intent(in) :: hecLagMAT
191  real(kind=kreal), intent(inout) :: gnt(2)
192  logical, intent(inout) :: ctchanged
193 
194  integer(kind=kint) :: slave, etype, master
195  integer(kind=kint) :: nn, i, cnt
196  real(kind=kreal) :: lgnt(2)
197  integer(kind=kint) :: ndLocal(l_max_elem_node+1)
198  real(kind=kreal) :: ctnforce(l_max_elem_node*3+3)
199  real(kind=kreal) :: cttforce(l_max_elem_node*3+3)
200  real(kind=kreal) :: max_jump_ratio, jump_ratio_local
201  real(kind=kreal) :: mut_old, mut_new, threthold
202 
203  cnt = 0
204  lgnt(:) = 0.d0
205  max_jump_ratio = 0.0d0
206  ! ===== NODE-SURF multiplier update (per slave node) =====
207  do i = 1, size(contact%slave)
208  if(.not. is_contact_active(contact%states(i)%state)) cycle ! only STICK/SLIP
209 
210  slave = contact%slave(i)
211  master = contact%states(i)%surface
212  nn = size(contact%master(master)%nodes)
213  etype = contact%master(master)%etype
214 
215  ndlocal(1) = slave
216  ndlocal(2:nn+1) = contact%master(master)%nodes(1:nn)
217 
218  ! Update multiplier and calculate forces
219  call updatecontactmultiplier_alag(contact%states(i), ndlocal(1:nn+1), coord, disp, ddisp, &
220  contact%nPenalty * contact%refStiff, contact%tPenalty * contact%refStiff, &
221  fcoeff, contact%master(master), lgnt, ctchanged, ctnforce, cttforce, jump_ratio_local, contact%smoothing)
222 
223  ! Track maximum jump ratio
224  max_jump_ratio = max(max_jump_ratio, jump_ratio_local)
225 
226  cnt = cnt + 1
227  enddo
228 
229  if(cnt > 0) lgnt(:) = lgnt(:) / cnt
230  gnt = gnt + lgnt
231 
232  call hecmw_allreduce_r1(hecmesh, max_jump_ratio, hecmw_max)
233 
234  ! Adjust tPenalty
235  threthold = 100.d0
236  if (max_jump_ratio > threthold) then
237  mut_old = contact%tPenalty * contact%refStiff
238  contact%tPenalty = contact%tPenalty * max(1.d0/dsqrt(threthold), 1.0d0/dsqrt(max_jump_ratio))
239  mut_new = contact%tPenalty * contact%refStiff
240  if (hecmw_comm_get_rank() == 0) then
241  write(*,'(A,A,A,1pE12.3,A,1pE12.3,A)') " Contact [", trim(contact%pair_name), &
242  "] tangential penalty adjusted: ", mut_old, " -> ", mut_new, " (friction jump)"
243  endif
244  endif
245 
246  end subroutine update_contact_multiplier
247 
254  subroutine update_contact_multiplier_surfsurf( contact, coord, disp, ddisp, fcoeff )
255  type( tcontact ), intent(inout) :: contact
256  real(kind=kreal), intent(in) :: coord(:)
257  real(kind=kreal), intent(in) :: disp(:)
258  real(kind=kreal), intent(in) :: ddisp(:)
259  real(kind=kreal), intent(in) :: fcoeff
260 
261  integer(kind=kint) :: i, g, r, a, nnode_s, unique_count
262  integer(kind=kint) :: maplist(max_n_intp), master_idxs(MAX_N_INTP)
263  integer(kind=kint), allocatable :: sorted_idx(:)
264  ! per-node-within-group quantities; the per-node lambda_n drives the normal path
265  real(kind=kreal), allocatable :: snode(:,:), nsnode(:,:,:), gapwnode(:,:), lambda_node(:,:)
266  real(kind=kreal) :: mu, lambda_new
267  ! --- friction: per-node slip/normal, per-node basis, return mapping ---
268  real(kind=kreal), allocatable :: sigma_node(:,:,:), nacc_node(:,:,:)
269  real(kind=kreal), allocatable :: lam_t_cur(:,:,:)
270  integer(kind=kint), allocatable :: fric_state_cur(:,:)
271  real(kind=kreal) :: nhat(3), t1(3), t2(3), nrm, dxi(2)
272  real(kind=kreal) :: rho_t, alpha, that(2), lam_t_new(2)
273  integer(kind=kint) :: fstate
274 
275  ! ===== mortar multiplier update (per slave segment) =====
276  mu = contact%nPenalty * contact%refStiff
277  rho_t = contact%tPenalty * contact%refStiff ! tangential penalty, used only if fcoeff/=0
278  do i = 1, size(contact%slave_surf)
279  if( contact%slave_surf(i)%state == contactfree ) cycle
280 
281  call get_unique_map(contact%slave_surf(i), maplist, master_idxs, unique_count)
282  nnode_s = size(contact%slave_surf(i)%nodes)
283  allocate(snode(unique_count,nnode_s), nsnode(unique_count,nnode_s,24), gapwnode(unique_count,nnode_s))
284  call getintgap(contact%slave_surf(i), contact%master, coord, disp, ddisp, &
285  unique_count, maplist, master_idxs, &
286  snode, nsnode, gapwnode)
287 
288  allocate(sorted_idx(unique_count), lambda_node(nnode_s,unique_count))
289  if( fcoeff /= 0.d0 ) then
290  ! Resolve the tangent warm-start (working -> begin -> 0/STICK) before the working
291  ! buffer is rebuilt below. lambda_n resolution is identical to the fcoeff=0 path.
292  allocate(lam_t_cur(2,nnode_s,unique_count), fric_state_cur(nnode_s,unique_count))
293  call resolve_lambda_cur(contact%slave_surf(i), master_idxs, unique_count, nnode_s, sorted_idx, &
294  lambda_node, lam_t_cur, fric_state_cur)
295  else
296  call resolve_lambda_cur(contact%slave_surf(i), master_idxs, unique_count, nnode_s, sorted_idx, &
297  lambda_node)
298  endif
299 
300  ! Per-node augmented update: lambda_node(a,g) += mu*gapwnode(g,a), clamped at 0.
301  do g = 1, unique_count
302  do a = 1, nnode_s
303  lambda_new = lambda_node(a,g) + (mu * gapwnode(g,a))
304  if( lambda_new < 0.d0 ) lambda_new = 0.d0
305  lambda_node(a,g) = lambda_new
306  enddo
307  enddo
308 
309  ! Rebuild the working buffer from the active master set (ascending); BEGIN left it empty.
310  contact%slave_surf(i)%lam_work_n = unique_count
311  do r = 1, unique_count
312  contact%slave_surf(i)%lam_work_id(r) = master_idxs(sorted_idx(r))
313  contact%slave_surf(i)%lam_work_val(1:nnode_s,r) = lambda_node(1:nnode_s,sorted_idx(r))
314  enddo
315 
316  ! --- friction tangent update: per slave node, project the mortar slip onto the
317  ! per-node tangent frame, return-map with cone radius fcoeff*lambda_node(a,g),
318  ! and write lambda_t / fric_state into the working buffer. ---
319  if( fcoeff /= 0.d0 ) then
320  allocate(sigma_node(unique_count,nnode_s,3), nacc_node(unique_count,nnode_s,3))
321  call gettangentslip(contact%slave_surf(i), contact%master, coord, disp, ddisp, &
322  maplist, sigma_node, nacc_node)
323  do g = 1, unique_count
324  do a = 1, nnode_s
325  nrm = sqrt( nacc_node(g,a,1)**2 + nacc_node(g,a,2)**2 + nacc_node(g,a,3)**2 )
326  ! Project the per-node slip onto the per-node orthonormal frame, then Coulomb
327  ! return-map. rho_t*Dxi matches the per-node mu*gapwnode area weighting (both
328  ! node-tributary integrated), so the averaged back-distribution cancels the area.
329  if( nrm < 1.d-30 ) then
330  dxi(1:2) = 0.d0
331  nhat(1:3) = 0.d0
332  else
333  nhat(1:3) = nacc_node(g,a,1:3) / nrm
334  call build_group_tangent_basis(nhat, t1, t2)
335  dxi(1) = dot_product(t1(1:3), sigma_node(g,a,1:3))
336  dxi(2) = dot_product(t2(1:3), sigma_node(g,a,1:3))
337  endif
338  fstate = fric_state_cur(a,g)
339  call group_return_mapping(lam_t_cur(1:2,a,g), rho_t, dxi, fcoeff, lambda_node(a,g), &
340  contact%eps_fric_band, lam_t_new, fstate, alpha, that, &
341  update_state=.true.)
342  lam_t_cur(1:2,a,g) = lam_t_new(1:2)
343  fric_state_cur(a,g) = fstate
344  enddo
345  enddo
346  ! Write the tangent working buffer parallel to the rebuilt lambda_n (ascending master order).
347  do r = 1, unique_count
348  contact%slave_surf(i)%lam_work_t(1:2,1:nnode_s,r) = lam_t_cur(1:2,1:nnode_s,sorted_idx(r))
349  contact%slave_surf(i)%lam_work_fstate(1:nnode_s,r) = fric_state_cur(1:nnode_s,sorted_idx(r))
350  enddo
351  deallocate(sigma_node, nacc_node, lam_t_cur, fric_state_cur)
352  endif
353 
354  deallocate(sorted_idx)
355  deallocate(snode, nsnode, gapwnode, lambda_node)
356  enddo
357 
359 
362  subroutine update_tied_multiplier( contact, disp, ddisp, ctchanged )
363  type( tcontact ), intent(inout) :: contact
364  real(kind=kreal), intent(in) :: disp(:)
365  real(kind=kreal), intent(in) :: ddisp(:)
366  logical, intent(inout) :: ctchanged
367 
368  integer(kind=kint) :: slave, etype, master
369  integer(kind=kint) :: nn, i, j, iSS
370  real(kind=kreal) :: dg(3), dgmax
371  real(kind=kreal) :: shapefunc(l_max_surface_node)
372  real(kind=kreal) :: edisp(3*l_max_elem_node+3)
373  real(kind=kreal) :: mu
374 
375  ! Calculate penalty from contact structure
376  mu = contact%nPenalty * contact%refStiff
377 
378  do i= 1, size(contact%slave)
379  if( .not. is_contact_active(contact%states(i)%state) ) cycle ! only STICK/SLIP
380  slave = contact%slave(i)
381  edisp(1:3) = disp(3*slave-2:3*slave)+ddisp(3*slave-2:3*slave)
382  master = contact%states(i)%surface
383 
384  nn = size( contact%master(master)%nodes )
385  etype = contact%master(master)%etype
386  do j=1,nn
387  iss = contact%master(master)%nodes(j)
388  edisp(3*j+1:3*j+3) = disp(3*iss-2:3*iss)+ddisp(3*iss-2:3*iss)
389  enddo
390  call getshapefunc( etype, contact%states(i)%lpos(1:2), shapefunc )
391 
392  ! normal component
393  dg(1:3) = edisp(1:3)
394  do j=1,nn
395  dg(1:3) = dg(1:3)-shapefunc(j)*edisp(3*j+1:3*j+3)
396  enddo
397 
398  contact%states(i)%multiplier(1:3) = contact%states(i)%multiplier(1:3) + mu*dg(1:3)
399 
400  ! check if tied constraint converged
401  dgmax = 0.d0
402  do j=1,(nn+1)*3
403  dgmax = dgmax + dabs(edisp(j))
404  enddo
405  dgmax = dgmax/dble((nn+1)*3)
406  do j=1,3
407  if( dabs(dg(j))/dmax1(1.d0,dgmax) > 1.d-3 ) ctchanged = .true.
408  enddo
409 
410  enddo
411  end subroutine
412 
413  subroutine update_contact_tangentforce( contact )
414  type( tcontact ), intent(inout) :: contact
415 
416  integer(kind=kint) :: i
417 
418  do i= 1, size(contact%slave)
419  if( .not. is_contact_active(contact%states(i)%state) ) then
420  contact%states(i)%tangentForce(1:3) = 0.d0
421  contact%states(i)%tangentForce_trial(1:3) = 0.d0
422  contact%states(i)%tangentForce_final(1:3) = 0.d0
423  else
424  contact%states(i)%tangentForce(1:3) = contact%states(i)%tangentForce_final(1:3)
425  end if
426  contact%states(i)%tangentForce1(1:3) = contact%states(i)%tangentForce(1:3)
427  enddo
428  end subroutine update_contact_tangentforce
429 
432  subroutine calcu_contact_stiffness_nodesurf( ctAlgo, contact, coord, disp, ddisp, iter, lagrange_array, &
433  conMAT, hecLagMAT)
434  integer(kind=kint), intent(in) :: ctalgo
435  type(tcontact), intent(inout) :: contact
436  real(kind=kreal), intent(in) :: coord(:)
437  real(kind=kreal), intent(in) :: disp(:)
438  real(kind=kreal), intent(in) :: ddisp(:)
439  integer(kind=kint), intent(in) :: iter
440  real(kind=kreal), intent(in) :: lagrange_array(:)
441  type(hecmwst_matrix), intent(inout) :: conmat
442  type(hecmwst_matrix_lagrange), intent(inout) :: hecLagMAT
443 
444  integer(kind=kint) :: ctsurf, nnode, ndLocal(21), etype
445  integer(kind=kint) :: j, k, algtype, id_lagrange
446  real(kind=kreal) :: lagrange
447  real(kind=kreal) :: stiffness((l_max_surface_node+1)*3+1, (l_max_surface_node+1)*3+1)
448  real(kind=kreal) :: elecoord(3, l_max_surface_node)
449  real(kind=kreal) :: eledisp(l_max_surface_node*3+3)
450  real(kind=kreal) :: force(l_max_surface_node*3+3)
451  logical :: is_contact_active_flag, is_damping_active_flag
452 
453  algtype = contact%algtype
454 
455  do j = 1, size(contact%slave)
456 
457  ! stick or sliding contact is active
458  is_contact_active_flag = is_contact_active(contact%states(j)%state)
459  ! damping is active
460  is_damping_active_flag = contact%states(j)%state == contactnear .and. &
461  & is_damping_enabled(contact)
462 
463  if( .not. is_contact_active_flag .and. .not. is_damping_active_flag ) cycle
464 
465  ctsurf = contact%states(j)%surface
466  etype = contact%master(ctsurf)%etype
467  nnode = size(contact%master(ctsurf)%nodes)
468  ndlocal(1) = contact%slave(j)
469  ndlocal(2:nnode+1) = contact%master(ctsurf)%nodes(1:nnode)
470 
471  ! Prepare master node coordinates for ALagrange (deformed configuration)
472  do k = 1, nnode
473  elecoord(1:3, k) = coord(3*ndlocal(k+1)-2:3*ndlocal(k+1)) + disp(3*ndlocal(k+1)-2:3*ndlocal(k+1))
474  enddo
475 
476  if( is_contact_active_flag ) then
477 
478  if( algtype == contactsslid .or. algtype == contactfslid ) then
479 
480  if( ctalgo == kcaslagrange ) then
481  id_lagrange = contact%states(j)%id_lagrange
482  lagrange = lagrange_array(id_lagrange)
483  call getcontactstiffness_slag(contact%states(j), contact%master(ctsurf), iter, &
484  contact%tPenalty, contact%fcoeff, lagrange, stiffness, smoothing_type=contact%smoothing)
485 
486  ! Assemble contact stiffness matrix of contact pair into global stiffness matrix
487  call hecmw_mat_ass_contactlag(nnode, ndlocal, id_lagrange, contact%fcoeff, stiffness, conmat, heclagmat)
488 
489  else if( ctalgo == kcaalagrange ) then
490  ! Build element displacement increment for consistent tangent evaluation
491  eledisp(1:3) = ddisp(3*ndlocal(1)-2:3*ndlocal(1))
492  do k = 1, nnode
493  eledisp(k*3+1:k*3+3) = ddisp(3*ndlocal(k+1)-2:3*ndlocal(k+1))
494  enddo
495  call getcontactstiffness_alag(contact%states(j), contact%master(ctsurf), elecoord(:,1:nnode), &
496  contact%nPenalty * contact%refStiff, contact%tPenalty * contact%refStiff, &
497  contact%fcoeff, contact%symmetric, stiffness, force, &
498  smoothing_type=contact%smoothing, edisp=eledisp(1:nnode*3+3), iter=iter, &
499  slvpos=coord(3*ndlocal(1)-2:3*ndlocal(1)) + disp(3*ndlocal(1)-2:3*ndlocal(1)))
500 
501  ! Assemble contact stiffness matrix into global stiffness matrix
502  call hecmw_mat_ass_elem(conmat, nnode+1, ndlocal, stiffness)
503 
504  end if
505 
506  else if( algtype == contacttied ) then
507 
508  if( ctalgo == kcaslagrange ) then
509  do k = 1, 3
510  id_lagrange = contact%states(j)%id_lagrange + k - 1
511  lagrange = lagrange_array(id_lagrange)
512 
513  call gettiedstiffness_slag(contact%states(j), contact%master(ctsurf), k, stiffness, &
514  contact%smoothing)
515  ! Assemble contact stiffness matrix of contact pair into global stiffness matrix
516  call hecmw_mat_ass_contactlag(nnode, ndlocal, id_lagrange, 0.d0, stiffness, conmat, heclagmat)
517  enddo
518 
519  else if( ctalgo == kcaalagrange ) then
520  call gettiedstiffness_alag(contact%states(j), contact%master(ctsurf), &
521  contact%nPenalty * contact%refStiff, stiffness, force)
522 
523  ! Assemble contact stiffness matrix into global stiffness matrix
524  call hecmw_mat_ass_elem(conmat, nnode+1, ndlocal, stiffness)
525 
526  end if
527 
528  endif
529 
530  else if( is_damping_active_flag ) then
531  call getdampingstiffness(contact%states(j), contact%master(ctsurf), &
532  contact%damp_alpha * contact%refStiff, contact%damp_gact, &
533  stiffness, smoothing_type=contact%smoothing)
534 
535  ! Assemble full damping stiffness for slave+master contact element
536  call hecmw_mat_ass_elem(conmat, nnode+1, ndlocal, stiffness)
537 
538  endif
539 
540  enddo
541 
542  end subroutine calcu_contact_stiffness_nodesurf
543 
544  subroutine calcu_contact_stiffness_surfsurf( ctAlgo, contact, coord, disp, ddisp, hecMAT )
545  integer(kind=kint), intent(in) :: ctAlgo
546  type(tcontact), intent(inout) :: contact
547  real(kind=kreal), intent(in) :: coord(:)
548  real(kind=kreal), intent(in) :: disp(:)
549  real(kind=kreal), intent(in) :: ddisp(:)
550  type(hecmwst_matrix), intent(inout) :: hecmat
551 
552  integer(kind=kint) :: i, g, a, nnode_m, nnode_s, unique_count, ctsurf
553  integer(kind=kint) :: ndlocal(l_max_surface_node+1)
554  integer(kind=kint) :: maplist(MAX_N_INTP), master_idxs(MAX_N_INTP)
555  real(kind=kreal), allocatable :: stiff_n(:,:,:,:), stiff_t(:,:,:,:)
556  logical, allocatable :: active_n(:,:), active_t(:,:)
557 
558  do i = 1, size(contact%slave_surf)
559  if( contact%slave_surf(i)%state == contactfree ) cycle
560  if( ctalgo /= kcaalagrange ) cycle
561 
562  call get_unique_map( contact%slave_surf(i), maplist, master_idxs, unique_count )
563  nnode_s = size(contact%slave_surf(i)%nodes)
564  allocate(stiff_n(24,24,nnode_s,unique_count), active_n(nnode_s,unique_count))
565 
566  ! Element level: one stiffness block per (slave-surf node a, master group g) constraint.
567  if( contact%fcoeff /= 0.d0 ) then
568  allocate(stiff_t(24,24,nnode_s,unique_count), active_t(nnode_s,unique_count))
569  call getcontactstiffness_alag_surfsurf( contact%slave_surf(i), contact%master, coord, disp, ddisp, &
570  contact%nPenalty * contact%refStiff, contact%tPenalty * contact%refStiff, contact%fcoeff, &
571  contact%symmetric, contact%eps_fric_band, unique_count, maplist, master_idxs, &
572  stiff_n, active_n, stiff_t, active_t )
573  else
574  call getcontactstiffness_alag_surfsurf( contact%slave_surf(i), contact%master, coord, disp, ddisp, &
575  contact%nPenalty * contact%refStiff, contact%tPenalty * contact%refStiff, contact%fcoeff, &
576  contact%symmetric, contact%eps_fric_band, unique_count, maplist, master_idxs, &
577  stiff_n, active_n )
578  endif
579 
580  ! ===== Normal stiffness =====
581  do g = 1, unique_count
582  ctsurf = master_idxs(g)
583  nnode_m = size(contact%master(ctsurf)%nodes)
584  ndlocal(1:nnode_s) = contact%slave_surf(i)%nodes(1:nnode_s)
585  ndlocal(nnode_s+1:nnode_s+nnode_m) = contact%master(ctsurf)%nodes(1:nnode_m)
586  do a = 1, nnode_s
587  if( .not. active_n(a,g) ) cycle
588  call hecmw_mat_ass_elem(hecmat, nnode_s+nnode_m, ndlocal, stiff_n(:,:,a,g))
589  enddo
590  enddo
591 
592  ! ===== Friction consistent tangent, assembled in a second pass =====
593  if( contact%fcoeff /= 0.d0 ) then
594  do g = 1, unique_count
595  ctsurf = master_idxs(g)
596  nnode_m = size(contact%master(ctsurf)%nodes)
597  ndlocal(1:nnode_s) = contact%slave_surf(i)%nodes(1:nnode_s)
598  ndlocal(nnode_s+1:nnode_s+nnode_m) = contact%master(ctsurf)%nodes(1:nnode_m)
599  do a = 1, nnode_s
600  if( .not. active_t(a,g) ) cycle
601  call hecmw_mat_ass_elem(hecmat, nnode_s+nnode_m, ndlocal, stiff_t(:,:,a,g))
602  enddo
603  enddo
604  deallocate(stiff_t, active_t)
605  endif
606 
607  deallocate(stiff_n, active_n)
608  enddo
609 
610  end subroutine calcu_contact_stiffness_surfsurf
611 
616  subroutine calcu_contact_ndforce_nodesurf( purpose, ctAlgo, contact, coord, disp, ddisp, lagrange_array, &
617  conMAT, CONT_NFORCE, CONT_FRIC )
618  integer(kind=kint), intent(in) :: purpose
619  integer(kind=kint), intent(in) :: ctAlgo
620  type( tcontact ), intent(inout) :: contact
621  real(kind=kreal), intent(in) :: coord(:)
622  real(kind=kreal), intent(in) :: disp(:)
623  real(kind=kreal), intent(in) :: ddisp(:)
624  real(kind=kreal), intent(in) :: lagrange_array(:)
625  type(hecmwst_matrix), intent(inout) :: conmat
626  real(kind=kreal), pointer :: cont_nforce(:)
627  real(kind=kreal), pointer :: cont_fric(:)
628 
629  integer(kind=kint) :: ctsurf, nnode, ndlocal(21)
630  integer(kind=kint) :: j, k, algtype, id_lagrange
631  real(kind=kreal) :: ndcoord(21*3)
632  real(kind=kreal) :: ndu(21*3), nddu(21*3)
633  real(kind=kreal) :: lagrange
634  real(kind=kreal) :: ctnforce(21*3+1)
635  real(kind=kreal) :: cttforce(21*3+1)
636  real(kind=kreal) :: mu_n, mu_t
637  logical :: if_flag
638  logical :: is_contact_active_flag, is_damping_active_flag
639  real(kind=kreal) :: ctime, etime
640  integer(kind=kint) :: if_type
641 
642  algtype = contact%algtype
643  if_flag = (contact%if_type /= 0)
644  if(if_flag)then
645  ctime = contact%ctime
646  etime = contact%if_etime
647  if_type = contact%if_type
648  end if
649 
650  do j = 1, size(contact%slave)
651 
652  ! stick or sliding contact is active
653  is_contact_active_flag = is_contact_active(contact%states(j)%state)
654  ! damping is active (residual only)
655  is_damping_active_flag = (purpose == kctforresidual) .and. &
656  contact%states(j)%state == contactnear .and. is_damping_enabled(contact)
657 
658  if( .not. is_contact_active_flag .and. .not. is_damping_active_flag ) cycle
659 
660  ctsurf = contact%states(j)%surface
661  nnode = size(contact%master(ctsurf)%nodes)
662  ndlocal(1) = contact%slave(j)
663  ndlocal(2:nnode+1) = contact%master(ctsurf)%nodes(1:nnode)
664  do k = 1, nnode+1
665  nddu((k-1)*3+1:(k-1)*3+3) = ddisp((ndlocal(k)-1)*3+1:(ndlocal(k)-1)*3+3)
666  ndu((k-1)*3+1:(k-1)*3+3) = disp((ndlocal(k)-1)*3+1:(ndlocal(k)-1)*3+3) + nddu((k-1)*3+1:(k-1)*3+3)
667  ndcoord((k-1)*3+1:(k-1)*3+3) = coord((ndlocal(k)-1)*3+1:(ndlocal(k)-1)*3+3) + ndu((k-1)*3+1:(k-1)*3+3)
668  enddo
669 
670  if( is_contact_active_flag ) then
671 
672  if(if_flag) call set_shrink_factor(ctime, contact%states(j), etime, if_type)
673 
674  ! --- Determine penalty parameters: zero for output (multiplier-only)
675  if( ctalgo == kcaalagrange .and. purpose == kctforoutput ) then
676  mu_n = 0.0d0
677  mu_t = 0.0d0
678  else
679  mu_n = contact%nPenalty * contact%refStiff
680  mu_t = contact%tPenalty * contact%refStiff
681  endif
682 
683  if( algtype == contactsslid .or. algtype == contactfslid ) then
684  ! Obtain contact nodal force vector of contact pair
685  if(if_flag) call get_shrink_elemact_surf(contact%states(j),ndcoord, nnode)
686 
687  if( ctalgo == kcaslagrange ) then
688  id_lagrange = contact%states(j)%id_lagrange
689  lagrange = lagrange_array(id_lagrange)
690  call getcontactnodalforce_slag(contact%states(j),contact%master(ctsurf),ndcoord,nddu, &
691  contact%tPenalty,contact%fcoeff,lagrange,ctnforce,cttforce,.true.,contact%smoothing)
692 
693  else if( ctalgo == kcaalagrange ) then
694  id_lagrange = 0
695  call getcontactnodalforce_alag(contact%states(j),contact%master(ctsurf),ndcoord,nddu, &
696  mu_n, mu_t, contact%fcoeff,contact%symmetric,ctnforce,cttforce,contact%smoothing)
697 
698  end if
699 
700  ! Assemble contact force
701  if( purpose == kctforresidual ) then
702  call assemble_contact_force_residual(nnode,ndlocal,id_lagrange,ctnforce,cttforce,conmat)
703  else
704  call assemble_contact_force_output(nnode,ndlocal,ctnforce,cttforce,cont_nforce,cont_fric)
705  endif
706 
707  else if( algtype == contacttied ) then
708 
709  if( ctalgo == kcaslagrange ) then
710  do k=1,3
711  id_lagrange = contact%states(j)%id_lagrange + k - 1
712  lagrange = lagrange_array(id_lagrange)
713  contact%states(j)%multiplier(k) = lagrange
714 
715  call gettiednodalforce_slag(contact%states(j),contact%master(ctsurf),k,ndu, &
716  & lagrange,ctnforce,cttforce,contact%smoothing)
717  if( purpose == kctforresidual ) then
718  call assemble_contact_force_residual(nnode,ndlocal,id_lagrange,ctnforce,cttforce,conmat)
719  else
720  call assemble_contact_force_output(nnode,ndlocal,ctnforce,cttforce,cont_nforce)
721  endif
722  end do
723 
724  else if( ctalgo == kcaalagrange ) then
725  id_lagrange = 0
726  call gettiednodalforce_alag(contact%states(j),contact%master(ctsurf),ndu, &
727  mu_n, ctnforce,cttforce)
728  if( purpose == kctforresidual ) then
729  call assemble_contact_force_residual(nnode,ndlocal,id_lagrange,ctnforce,cttforce,conmat)
730  else
731  call assemble_contact_force_output(nnode,ndlocal,ctnforce,cttforce,cont_nforce)
732  endif
733 
734  end if
735 
736  endif
737 
738  else if( is_damping_active_flag ) then
739 
740  call getdampingnodalforce(contact%states(j), contact%master(ctsurf), nddu, &
741  contact%damp_alpha * contact%refStiff, contact%damp_gact, &
742  ctnforce, cttforce, smoothing_type=contact%smoothing)
743 
744  ! Assemble damping force for slave+master contact element
745  call assemble_contact_force_residual(nnode,ndlocal,0,ctnforce,cttforce,conmat)
746 
747  endif
748 
749  enddo
750 
751  end subroutine calcu_contact_ndforce_nodesurf
752 
765  subroutine calcu_contact_ndforce_exp( contact, coord, disp, ddisp, CONT_NFORCE, CONT_FRIC )
766  type( tcontact ), intent(inout) :: contact
767  real(kind=kreal), intent(in) :: coord(:)
768  real(kind=kreal), intent(in) :: disp(:)
769  real(kind=kreal), intent(in) :: ddisp(:)
770  real(kind=kreal), pointer :: cont_nforce(:)
771  real(kind=kreal), pointer :: cont_fric(:)
772 
773  integer(kind=kint) :: ctsurf, nnode, ndLocal(21), j, k
774  real(kind=kreal) :: ndcoord(21*3), ndu(21*3), nddu(21*3)
775  real(kind=kreal) :: ctnforce(21*3+1), cttforce(21*3+1)
776  real(kind=kreal) :: tm(3,3*(l_max_surface_node+1)), tt(3,3*(l_max_surface_node+1))
777 
778  do j = 1, size(contact%slave)
779  if( .not. is_contact_active(contact%states(j)%state) ) cycle
780 
781  ctsurf = contact%states(j)%surface
782  nnode = size(contact%master(ctsurf)%nodes)
783  ndlocal(1) = contact%slave(j)
784  ndlocal(2:nnode+1) = contact%master(ctsurf)%nodes(1:nnode)
785  do k = 1, nnode+1
786  nddu((k-1)*3+1:(k-1)*3+3) = ddisp((ndlocal(k)-1)*3+1:(ndlocal(k)-1)*3+3)
787  ndu((k-1)*3+1:(k-1)*3+3) = disp((ndlocal(k)-1)*3+1:(ndlocal(k)-1)*3+3) + nddu((k-1)*3+1:(k-1)*3+3)
788  ndcoord((k-1)*3+1:(k-1)*3+3) = coord((ndlocal(k)-1)*3+1:(ndlocal(k)-1)*3+3) + ndu((k-1)*3+1:(k-1)*3+3)
789  enddo
790 
791  call getcontactnodalforce_slag( contact%states(j), contact%master(ctsurf), ndcoord, nddu, &
792  0.d0, 0.d0, contact%states(j)%multiplier(1), ctnforce, cttforce, .false., contact%smoothing )
793 
794  call computetm_tt( contact%states(j), contact%master(ctsurf), contact%fcoeff, &
795  tm, tt, contact%smoothing )
796  cttforce(:) = 0.d0
797  cttforce(1:3*(nnode+1)) = -matmul(transpose(tm(1:3,1:3*(nnode+1))), &
798  contact%states(j)%tangentForce_final)
799 
800  call assemble_contact_force_output( nnode, ndlocal, ctnforce, cttforce, cont_nforce, cont_fric )
801  enddo
802 
803  end subroutine calcu_contact_ndforce_exp
804 
805  subroutine calcu_contact_ndforce_surfsurf( purpose, ctAlgo, contact, coord, disp, ddisp, &
806  conMAT, CONT_NFORCE, CONT_FRIC )
807  integer(kind=kint), intent(in) :: purpose
808  integer(kind=kint), intent(in) :: ctAlgo
809  type( tcontact ), intent(inout) :: contact
810  real(kind=kreal), intent(in) :: coord(:)
811  real(kind=kreal), intent(in) :: disp(:)
812  real(kind=kreal), intent(in) :: ddisp(:)
813  type(hecmwst_matrix), intent(inout) :: conmat
814  real(kind=kreal), pointer :: cont_nforce(:)
815  real(kind=kreal), pointer :: cont_fric(:)
816 
817  integer(kind=kint) :: i, g, a, j, nd, nnode_m, nnode_s, unique_count, ctsurf
818  integer(kind=kint) :: ndlocal(l_max_surface_node+1)
819  integer(kind=kint) :: maplist(MAX_N_INTP), master_idxs(MAX_N_INTP)
820  real(kind=kreal), allocatable :: ctnforce(:,:,:), cttforce(:,:,:)
821  logical, allocatable :: active_n(:,:), active_t(:,:)
822 
823  do i = 1, size(contact%slave_surf)
824  if( contact%slave_surf(i)%state == contactfree ) cycle
825  if( ctalgo /= kcaalagrange ) cycle
826 
827  call get_unique_map( contact%slave_surf(i), maplist, master_idxs, unique_count )
828  nnode_s = size(contact%slave_surf(i)%nodes)
829  allocate(ctnforce(24,nnode_s,unique_count), active_n(nnode_s,unique_count))
830 
831  ! Element level: one force vector per (slave-surf node a, master group g) constraint,
832  ! already signed as the residual contribution.
833  if( contact%fcoeff /= 0.d0 ) then
834  allocate(cttforce(24,nnode_s,unique_count), active_t(nnode_s,unique_count))
835  call getcontactnodalforce_alag_surfsurf( purpose, contact%slave_surf(i), contact%master, coord, disp, ddisp, &
836  contact%nPenalty * contact%refStiff, contact%tPenalty * contact%refStiff, contact%fcoeff, &
837  contact%symmetric, contact%eps_fric_band, unique_count, maplist, master_idxs, &
838  ctnforce, active_n, cttforce, active_t )
839  else
840  call getcontactnodalforce_alag_surfsurf( purpose, contact%slave_surf(i), contact%master, coord, disp, ddisp, &
841  contact%nPenalty * contact%refStiff, contact%tPenalty * contact%refStiff, contact%fcoeff, &
842  contact%symmetric, contact%eps_fric_band, unique_count, maplist, master_idxs, &
843  ctnforce, active_n )
844  endif
845 
846  ! ===== Normal force =====
847  do g = 1, unique_count
848  ctsurf = master_idxs(g)
849  nnode_m = size(contact%master(ctsurf)%nodes)
850  ndlocal(1:nnode_s) = contact%slave_surf(i)%nodes(1:nnode_s)
851  ndlocal(nnode_s+1:nnode_s+nnode_m) = contact%master(ctsurf)%nodes(1:nnode_m)
852  do a = 1, nnode_s
853  if( .not. active_n(a,g) ) cycle
854  do j = 1, nnode_s + nnode_m
855  nd = ndlocal(j)
856  if( purpose == kctforresidual ) then
857  conmat%B(3*nd-2:3*nd) = conmat%B(3*nd-2:3*nd) + ctnforce(3*j-2:3*j,a,g)
858  else if ( purpose == kctforoutput ) then
859  cont_nforce(3*nd-2:3*nd) = cont_nforce(3*nd-2:3*nd) + ctnforce(3*j-2:3*j,a,g)
860  end if
861  enddo
862  enddo
863  enddo
864 
865  ! ===== Friction force, assembled in a second pass =====
866  if( contact%fcoeff /= 0.d0 ) then
867  do g = 1, unique_count
868  ctsurf = master_idxs(g)
869  nnode_m = size(contact%master(ctsurf)%nodes)
870  ndlocal(1:nnode_s) = contact%slave_surf(i)%nodes(1:nnode_s)
871  ndlocal(nnode_s+1:nnode_s+nnode_m) = contact%master(ctsurf)%nodes(1:nnode_m)
872  do a = 1, nnode_s
873  if( .not. active_t(a,g) ) cycle
874  do j = 1, nnode_s + nnode_m
875  nd = ndlocal(j)
876  if( purpose == kctforresidual ) then
877  conmat%B(3*nd-2:3*nd) = conmat%B(3*nd-2:3*nd) + cttforce(3*j-2:3*j,a,g)
878  else if( purpose == kctforoutput ) then
879  cont_fric(3*nd-2:3*nd) = cont_fric(3*nd-2:3*nd) + cttforce(3*j-2:3*j,a,g)
880  end if
881  enddo
882  enddo
883  enddo
884  deallocate(cttforce, active_t)
885  endif
886 
887  deallocate(ctnforce, active_n)
888  enddo
889 
890  end subroutine calcu_contact_ndforce_surfsurf
891 
892 end module m_fstr_contact_assembly
Definition: hecmw.f90:6
Contact processing at assembly level (all pairs in one tContact object)
subroutine calcu_contact_stiffness_surfsurf(ctAlgo, contact, coord, disp, ddisp, hecMAT)
subroutine, public calc_contact_pair_refstiff(contact, diag, ndof, hecMESH)
Calculate reference stiffness for one contact pair.
subroutine assemble_contact_force_residual(nnode, ndLocal, id_lagrange, ctNForce, ctTForce, conMAT)
Assemble contact nodal force into residual vector (conMATB).
subroutine calcu_contact_ndforce_surfsurf(purpose, ctAlgo, contact, coord, disp, ddisp, conMAT, CONT_NFORCE, CONT_FRIC)
subroutine calcu_contact_ndforce_exp(contact, coord, disp, ddisp, CONT_NFORCE, CONT_FRIC)
Compute contact nodal normal force for output from the stored contact multiplier, for the explicit dy...
subroutine update_contact_multiplier(contact, coord, disp, ddisp, fcoeff, hecMESH, hecLagMAT, gnt, ctchanged)
This subroutine update lagrangian multiplier and the distance between contacting nodes.
subroutine calcu_contact_ndforce_nodesurf(purpose, ctAlgo, contact, coord, disp, ddisp, lagrange_array, conMAT, CONT_NFORCE, CONT_FRIC)
This subroutine calculates contact nodal force for each contact pair and assembles it into contact ma...
subroutine calcu_contact_stiffness_nodesurf(ctAlgo, contact, coord, disp, ddisp, iter, lagrange_array, conMAT, hecLagMAT)
This subroutine calculates contact stiffness for each contact pair and assembles it into global stiff...
subroutine assemble_contact_force_output(nnode, ndLocal, ctNForce, ctTForce, cont_nforce, cont_fric)
Accumulate contact nodal force into output arrays (CONT_NFORCE/CONT_FRIC).
subroutine update_contact_tangentforce(contact)
subroutine update_tied_multiplier(contact, disp, ddisp, ctchanged)
This subroutine update lagrangian multiplier and the distance between contacting nodes.
subroutine update_contact_multiplier_surfsurf(contact, coord, disp, ddisp, fcoeff)
This subroutine updates the lagrangian multiplier of a mortar (MORTAR=YES) contact pair....
Contact damping module for CONTACTNEAR state.
subroutine, public getdampingstiffness(cstate, surf, alpha, gact, stiff, smoothing_type)
Compute damping stiffness matrix K_damp = alpha * w(g) * Bn (x) Bn.
subroutine, public getdampingnodalforce(cstate, surf, ndDu, alpha, gact, ctNForce, ctTForce, smoothing_type)
Compute damping nodal force vector f_damp = alpha * w(g) * (Bn^T * ddu) * Bn.
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 updatecontactmultiplier_alag(ctState, ndLocal, coord, disp, ddisp, mu, mut, fcoeff, tSurf, lgnt, ctchanged, ctNForce, ctTForce, jump_ratio, smoothing_type)
subroutine, public getcontactstiffness_alag_surfsurf(slave_surf, master, coord, disp, ddisp, mu, mut, fcoeff, symm, eps_fric_band, unique_count, maplist, master_idxs, stiff_n, active_n, stiff_t, active_t)
Mortar (SURF-SURF) ALag: contact stiffness of one slave segment.
subroutine, public getcontactstiffness_alag(cstate, tSurf, ele, mu, mut, fcoeff, symm, stiff, force, smoothing_type, edisp, iter, slvpos)
subroutine, public gettiedstiffness_alag(cstate, tSurf, mu, stiff, force)
subroutine, public gettangentslip(slave_surf, master, coord, disp, ddisp, maplist, Sigma_node, nacc_node)
Aggregate, per master group g and slave-surf node a of one mortar slave segment, the mortar-weighted ...
subroutine, public gettiednodalforce_alag(ctState, tSurf, ndu, mu, ctNForce, ctTForce)
subroutine, public group_return_mapping(lam_t_in, rho_t, Dxi, fcoeff, lam_n, eps_fric_band, lam_t_out, fric_state, alpha, that, update_state)
Group-level Coulomb return mapping for the tangent multiplier (metric = I).
subroutine, public get_unique_map(sSurf, maplist, master_idxs, unique_count)
subroutine, public build_group_tangent_basis(n_hat, t1, t2)
Build an orthonormal tangent basis (t1,t2) as the orthogonal complement of a group-representative sla...
subroutine, public getintgap(slave_surf, master, coord, disp, ddisp, unique_count, maplist, master_idxs, Snode, Nsnode, gapwnode)
Compute the per-node mortar constraint quantities of one slave segment.
subroutine, public getcontactnodalforce_alag(ctState, tSurf, ndCoord, ndDu, mu, mut, fcoeff, symm, ctNForce, ctTForce, smoothing_type)
subroutine, public getcontactnodalforce_alag_surfsurf(purpose, slave_surf, master, coord, disp, ddisp, mu, mut, fcoeff, symm, eps_fric_band, unique_count, maplist, master_idxs, ctNForce, active_n, ctTForce, active_t)
Mortar (SURF-SURF) ALag: contact nodal force of one slave segment.
subroutine, public resolve_lambda_cur(surf, master_idxs, unique_count, nnode_s, sorted_idx, lambda_node, lam_t_cur, fric_state_cur)
Mortar: resolve the current per-node lambda of each active group of one slave surf....
Common utilities for contact element calculations.
subroutine, public computetm_tt(ctState, tSurf, fcoeff, Tm, Tt, smoothing_type, Bn)
Compute Tm (relative displacement mapping) and optionally Tt (tangential mapping) This subroutine con...
Contact mechanics calculations at element level (single contact pair)
This module provides interference fit (shrink) functions for contact.
subroutine get_shrink_elemact_surf(cstate, coords, nnode)
subroutine, public set_shrink_factor(ctime, cstate, etime, if_type)
This module defines common data and basic structures for analysis.
Definition: m_fstr.F90:15
integer(kind=kint), parameter kcaslagrange
contact analysis algorithm
Definition: m_fstr.F90:62
integer(kind=kint), parameter kcaalagrange
Definition: m_fstr.F90:63
This module manages the data structure for contact calculation.
integer, parameter contactsslid
integer, parameter kctforresidual
purpose flag for contact force calculation
integer, parameter contacts2s
integer, parameter contactnear
near contact: projection info available, no LM constraint
real(kind=kreal), dimension(2), save gnt
1:current average penetration; 2:current relative tangent displacement
integer, parameter max_n_intp
upper bound of integration points per SURF-SURF slave segment
integer, parameter contacttied
contact type or algorithm definition
integer, parameter kctforoutput
compute contact force for output (CONT_NFORCE/CONT_FRIC)
pure logical function is_contact_active(state)
Whether the contact state has active LM constraint (STICK or SLIP)
integer, parameter contactfree
contact state definition
integer, parameter contactfslid
Structure to includes all info needed by contact calculation.