FrontISTR  5.9.0
Large-scale structural analysis program with finit element method
fstr_contact_elem_common.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 !-------------------------------------------------------------------------------
7  use hecmw
8  use elementinfo
9  use mcontactdef
12  implicit none
13 
14  public :: computetm_tt
15  public :: computecontactmaps_alag
18  public :: update_tangentforce
19 
20 contains
21 
26  subroutine computetm_tt(ctState, tSurf, fcoeff, Tm, Tt, smoothing_type, Bn)
27  implicit none
28 
29  ! Input arguments
30  type(tcontactstate), intent(in) :: ctstate
31  type(tsurfelement), intent(in) :: tsurf
32  real(kind=kreal), intent(in) :: fcoeff
33  integer(kind=kint), optional, intent(in) :: smoothing_type
34 
35  ! Output arguments
36  real(kind=kreal), intent(out) :: tm(3, 3*(l_max_surface_node+1))
37  real(kind=kreal), intent(out) :: tt(3, 3*(l_max_surface_node+1))
38  real(kind=kreal), optional, intent(out) :: bn(:)
39 
40  ! Local variables
41  integer(kind=kint) :: i, j
42  integer(kind=kint) :: nnode
43  integer(kind=kint) :: smoothing
44  real(kind=kreal) :: shapefunc(l_max_surface_node)
45  real(kind=kreal) :: p_matrix(3, 3*l_max_surface_node)
46  real(kind=kreal) :: normal(3)
47  real(kind=kreal) :: pt(3,3)
48 
49  tm = 0.0d0
50  tt = 0.0d0
51 
52  nnode = size(tsurf%nodes)
53  normal(1:3) = ctstate%direction(1:3)
54 
55  ! Determine smoothing type
56  smoothing = kcsnone
57  if (present(smoothing_type)) smoothing = smoothing_type
58 
59  ! Construct Tm
60  if ( smoothing == kcsnone ) then
61  ! Standard linear shape functions
62  call getshapefunc(tsurf%etype, ctstate%lpos, shapefunc)
63 
64  ! First block (slave node): Identity matrix I_3
65  tm(1,1) = 1.0d0
66  tm(2,2) = 1.0d0
67  tm(3,3) = 1.0d0
68 
69  ! Remaining blocks (master nodes): -N_i * I_3
70  do i = 1, nnode
71  tm(1, i*3+1) = -shapefunc(i)
72  tm(2, i*3+2) = -shapefunc(i)
73  tm(3, i*3+3) = -shapefunc(i)
74  enddo
75 
76  else if ( smoothing == kcsnagata ) then
77  ! Use Nagata patch interpolation
78  call compute_interpolation_matrix_p(tsurf%etype, nnode, ctstate%lpos, &
79  tsurf%vertex_normals, p_matrix)
80 
81  ! Tm = [I_3; -P_matrix]
82  tm(1,1) = 1.0d0
83  tm(2,2) = 1.0d0
84  tm(3,3) = 1.0d0
85  tm(1:3, 4:3*(nnode+1)) = -p_matrix(1:3, 1:3*nnode)
86 
87  endif
88 
89  ! Optionally compute normal distribution vector: Bn = Tm^T * n
90  if (present(bn)) then
91  bn(:) = 0.0d0
92  bn(1:3*(nnode+1)) = matmul(transpose(tm(1:3, 1:3*(nnode+1))), normal(1:3))
93  endif
94 
95  ! Compute Tt only if friction coefficient is non-zero
96  if (fcoeff /= 0.0d0) then
97  ! Construct tangential projection operator Pt = I_3 - n x n
98  do i = 1, 3
99  do j = 1, 3
100  if (i == j) then
101  pt(i,j) = 1.0d0 - normal(i)*normal(j)
102  else
103  pt(i,j) = -normal(i)*normal(j)
104  endif
105  enddo
106  enddo
107 
108  ! Compute Tt = Pt * Tm using matrix multiplication
109  tt(1:3, 1:3*(l_max_surface_node+1)) = matmul(pt(1:3,1:3), tm(1:3, 1:3*(l_max_surface_node+1)))
110  endif
111 
112  end subroutine computetm_tt
113 
123  subroutine computecontactmaps_alag(ctState, tSurf, ele, &
124  Bn, metric, Ht, Gt, smoothing_type)
125  implicit none
126 
127  ! Input arguments
128  type(tcontactstate), intent(in) :: ctstate
129  type(tsurfelement), intent(in) :: tsurf
130  real(kind=kreal), intent(in) :: ele(:,:)
131  integer(kind=kint), optional, intent(in) :: smoothing_type
132 
133  ! Output arguments
134  real(kind=kreal), intent(out) :: bn(:)
135  real(kind=kreal), intent(out) :: metric(2,2)
136  real(kind=kreal), intent(out) :: ht(:,:)
137  real(kind=kreal), intent(out) :: gt(:,:)
138 
139  ! Local variables
140  integer(kind=kint) :: nnode, ndof
141  real(kind=kreal) :: tangent(3,2)
142  real(kind=kreal) :: tm(3, 3*(l_max_surface_node+1))
143  real(kind=kreal) :: tt(3, 3*(l_max_surface_node+1))
144 
145  ! Initialize arrays to zero for safety
146  bn(:) = 0.0d0
147  metric(:,:) = 0.0d0
148  ht(:,:) = 0.0d0
149  gt(:,:) = 0.0d0
150 
151  nnode = size(tsurf%nodes)
152  ndof = nnode*3 + 3
153 
154  ! Call computeTm_Tt as the core routine (fcoeff=0 since we don't need Tt for ALag)
155  ! Bn is computed inside computeTm_Tt as Tm^T * normal
156  call computetm_tt(ctstate, tsurf, 0.0d0, tm, tt, smoothing_type, bn=bn)
157 
158  ! Call DispIncreMatrix to get tangent displacement map and metric
159  ! DispIncreMatrix returns: tangent basis, metric tensor, and displacement increment matrix
160  call dispincrematrix(ctstate%lpos(1:2), tsurf%etype, nnode, ele(1:3,1:nnode), &
161  tangent, metric, ht(1:2,1:ndof))
162 
163  ! Compute covariant displacement map: Gt = metric * Ht
164  ! This gives: dxy = Gt * edisp = metric * (Ht * edisp)
165  gt(1:2,1:ndof) = matmul(metric(1:2,1:2), ht(1:2,1:ndof))
166 
167  end subroutine computecontactmaps_alag
168 
195  subroutine computefrictionforce_alag(ctState, fcoeff, lambda_n, metric, Ht, Gt, edisp, edof, ctTForce, &
196  mut, update_multiplier, slave_id, ctchanged, &
197  norm_trial, alpha, that, jump_ratio)
198  implicit none
199 
200  type(tcontactstate), intent(inout) :: ctstate
201  real(kind=kreal), intent(in) :: fcoeff
202  real(kind=kreal), intent(in) :: lambda_n
203  real(kind=kreal), intent(in) :: metric(2,2)
204  real(kind=kreal), intent(in) :: ht(:,:)
205  real(kind=kreal), intent(in) :: gt(:,:)
206  real(kind=kreal), intent(in) :: edisp(:)
207  integer(kind=kint), intent(in) :: edof
208  real(kind=kreal), intent(out) :: cttforce(:)
209  real(kind=kreal), intent(in) :: mut
210  logical, optional, intent(in) :: update_multiplier
211  integer(kind=kint), optional, intent(in) :: slave_id
212  logical, optional, intent(inout) :: ctchanged
213  real(kind=kreal), optional, intent(out) :: norm_trial
214  real(kind=kreal), optional, intent(out) :: alpha
215  real(kind=kreal), optional, intent(out) :: that(2)
216  real(kind=kreal), optional, intent(out) :: jump_ratio
217 
218  real(kind=kreal) :: dxy(2)
219  real(kind=kreal) :: fric(2)
220  real(kind=kreal) :: f3(edof)
221  real(kind=kreal) :: invmetric(2,2)
222  real(kind=kreal) :: det
223  real(kind=kreal) :: norm_fric
224  real(kind=kreal) :: tmp(2)
225  real(kind=kreal) :: alpha_local
226  logical :: do_update
227 
228  cttforce = 0.0d0
229  do_update = .false.
230  if(present(jump_ratio)) jump_ratio = 0.0d0
231  if(present(update_multiplier)) do_update = update_multiplier
232 
233  ! Compute inverse of metric tensor (2x2)
234  det = metric(1,1)*metric(2,2) - metric(1,2)*metric(2,1)
235  if( abs(det) < 1.0d-20 ) then
236  ! Degenerate metric: set friction to zero
237  cttforce = 0.0d0
238  return
239  endif
240  invmetric(1,1) = metric(2,2) / det
241  invmetric(2,2) = metric(1,1) / det
242  invmetric(1,2) = -metric(1,2) / det
243  invmetric(2,1) = -metric(2,1) / det
244 
245  ! Compute tangent displacement using Gt map: dxy = Gt * edisp
246  dxy(1:2) = matmul( gt(1:2,1:edof), edisp(1:edof) )
247 
248  ! Trial friction force: fric = λ_t + ρ_t * dxy
249  fric(1:2) = ctstate%multiplier(2:3) + mut*dxy(1:2)
250 
251  ! Compute 2D local norm: ||fric||_g = sqrt(fric^T * inv(metric) * fric)
252  tmp(1:2) = matmul(invmetric(1:2,1:2), fric(1:2))
253  norm_fric = dsqrt( dot_product(fric(1:2), tmp(1:2)) )
254 
255  ! Return projection information for stiffness (optional outputs)
256  if(present(norm_trial)) norm_trial = norm_fric
257  if(present(that) .and. norm_fric > 1.0d-20) then
258  that(1:2) = fric(1:2) / norm_fric
259  else if(present(that)) then
260  that(1:2) = 0.0d0
261  endif
262 
263  ! Compute projection ratio: alpha = min(1, r/norm_trial)
264  if( lambda_n > 0.0d0 .and. norm_fric > 1.0d-20 ) then
265  alpha_local = min(1.0d0, fcoeff*lambda_n / norm_fric)
266  else
267  alpha_local = 0.0d0
268  endif
269  if(present(alpha)) alpha = alpha_local
270 
271  ! Check stick/slip state using projection ratio
272  if( do_update .and. lambda_n > 0.0d0 ) then
273  ! Update mode: check state and update multiplier
274  if( alpha_local < 1.0d0 ) then
275  ! Slip state: projected to friction cone
276  if( ctstate%state == contactstick ) then
277  if(present(ctchanged)) ctchanged = .true.
278  if(present(slave_id)) print *, "Node", slave_id, "to slip state", norm_fric, fcoeff*lambda_n
279  if(present(jump_ratio) .and. lambda_n > 1.0e-20 .and. norm_fric > 1.0e-20) &
280  & jump_ratio = norm_fric / (fcoeff*lambda_n)
281  endif
282  ctstate%state = contactslip
283  fric(1:2) = fric(1:2) * alpha_local
284  else
285  ! Stick state
286  if( ctstate%state == contactslip ) then
287  if(present(ctchanged)) ctchanged = .true.
288  if(present(slave_id)) print *, "Node", slave_id, "to stick state", norm_fric, fcoeff*lambda_n
289  endif
290  ctstate%state = contactstick
291  endif
292  ! Update multiplier
293  ctstate%multiplier(2:3) = fric(1:2)
294  else if( lambda_n <= 0.0d0 ) then
295  ! No normal force: no friction
296  fric(1:2) = 0.0d0
297  else
298  ! Read-only mode: just scale if alpha < 1
299  if( alpha_local < 1.0d0 ) then
300  fric(1:2) = fric(1:2) * alpha_local
301  endif
302  endif
303 
304  ! Compute friction force vector using Ht map: f3 = Ht^T * fric
305  f3(1:edof) = matmul( transpose(ht(1:2,1:edof)), fric(1:2) )
306 
307  ! Distribute friction force (negative for equilibrium)
308  cttforce(1:edof) = -f3(1:edof)
309 
310  end subroutine computefrictionforce_alag
311 
313  subroutine gettrialfricforceandcheckfricstate(ctstate,fcoeff,tPenalty,lagrange)
314 
315  type(tcontactstate) :: ctstate
316  real(kind=kreal) :: fcoeff, tpenalty
317  real(kind=kreal) :: lagrange
318 
319  integer(kind=kint) :: i
320  real(kind=kreal) :: tf_yield
321 
322  do i = 1, 3
323  ctstate%tangentForce_trial(i) = ctstate%tangentForce1(i) + tpenalty*ctstate%reldisp(i)
324  enddo
325 
326  tf_yield = fcoeff*dabs(lagrange)
327  if(ctstate%state == contactslip) tf_yield =0.99d0*tf_yield
328  if( dsqrt(dot_product(ctstate%tangentForce_trial,ctstate%tangentForce_trial)) <= tf_yield ) then
329  ctstate%state = contactstick
330  else
331  ctstate%state = contactslip
332  endif
333 
335 
337  subroutine update_tangentforce(etype,nn,elemt0,elemt,cstate)
338  integer, intent(in) :: etype
339  integer, intent(in) :: nn
340  real(kind=kreal),intent(in) :: elemt0(3,nn)
341  real(kind=kreal),intent(in) :: elemt(3,nn)
342  type(tcontactstate), intent(inout) :: cstate
343 
344  integer :: i
345  real(kind=kreal) :: tangent0(3,2), tangent(3,2) ! base vectors in tangent space
346  real(kind=kreal) :: coeff(2), norm, norm_tmp
347  real(kind=kreal) :: tangentforce_tmp(3)
348 
349  call tangentbase( etype, nn, cstate%lpos(1:2), elemt0, tangent0 )
350  call tangentbase( etype, nn, cstate%lpos(1:2), elemt, tangent )
351 
352  !project tangentforce to base vector tangent0
353  do i=1,2
354  coeff(i) = dot_product(cstate%tangentForce(1:3),tangent0(1:3,i))
355  coeff(i) = coeff(i)/dot_product(tangent0(1:3,i),tangent0(1:3,i))
356  enddo
357  tangentforce_tmp(1:3) = coeff(1)*tangent0(1:3,1) + coeff(2)*tangent0(1:3,2)
358  norm_tmp = dsqrt(dot_product(tangentforce_tmp,tangentforce_tmp))
359  !adjust tangent force of slave point which moved over element boundary
360  if( norm_tmp > 1.d-6 ) then
361  norm = dsqrt(dot_product(cstate%tangentForce,cstate%tangentForce))
362  coeff(1:2) = (norm/norm_tmp)*coeff(1:2)
363  end if
364 
365  !set rotated tangentforce to tangentforce1
366  cstate%tangentForce1(1:3) = coeff(1)*tangent(1:3,1) + coeff(2)*tangent(1:3,2)
367 
368  end subroutine update_tangentforce
369 
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
subroutine tangentbase(fetype, nn, localcoord, elecoord, tangent)
Calculate base vector of tangent space of 3d surface.
Definition: element.f90:933
Definition: hecmw.f90:6
Common utilities for contact element calculations.
subroutine, public gettrialfricforceandcheckfricstate(ctstate, fcoeff, tPenalty, lagrange)
This subroutine calculates trial friction force and checks friction state.
subroutine, public computefrictionforce_alag(ctState, fcoeff, lambda_n, metric, Ht, Gt, edisp, edof, ctTForce, mut, update_multiplier, slave_id, ctchanged, norm_trial, alpha, that, jump_ratio)
Compute friction force for ALag method Given tangent maps Ht, Gt and displacement increment,...
subroutine, public update_tangentforce(etype, nn, elemt0, elemt, cstate)
This subroutine find the projection of a slave point onto master surface.
subroutine, public computecontactmaps_alag(ctState, tSurf, ele, Bn, metric, Ht, Gt, smoothing_type)
Compute contact maps for ALag method (normal distribution and tangential displacement maps) This subr...
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...
This module provides geometric calculations for contact.
subroutine dispincrematrix(pos, etype, nnode, ele, tangent, tensor, matrix)
This subroutine calculate the relation between global disp and displacement along natural coordinate ...
Contact surface smoothing using Nagata patch interpolation.
subroutine, public compute_interpolation_matrix_p(etype, nnode, lpos, vertex_normals, P_matrix)
Compute interpolation matrix P for Nagata patch P_matrix(3, nnode*3) represents x = P * [X1; X2; X3; ...
This module manages the data structure for contact calculation.
integer, parameter contactslip
integer, parameter kcsnone
contact smoothing type
integer, parameter contactstick
integer, parameter kcsnagata
This structure records contact status.