FrontISTR  5.9.0
Large-scale structural analysis program with finit element method
fstr_contact_smoothing.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, only: kint, kreal
9  use elementinfo
10  use m_utilities, only: calinverse
11  use msurfelement, only: tsurfelement
12  implicit none
13 
14  ! Tikhonov regularization parameter
15  real(kind=kreal), parameter, private :: nagata_epsilon = 1.0d-4
16 
17  integer(kind=kint), parameter, private :: DEBUG = 0
18 
19  private
20  public :: compute_cab
22  public :: update_surface_normal
24  public :: reorder_tri3n_to_tri6n
25 
26 contains
27 
31  subroutine reorder_tri3n_to_tri6n(vertices_in, midpoints_in, nodes_out)
32  real(kind=kreal), intent(in) :: vertices_in(3,3) ! fe_tri3n vertices
33  real(kind=kreal), intent(in) :: midpoints_in(3,3) ! fe_tri3n midpoints
34  real(kind=kreal), intent(out) :: nodes_out(3,6) ! fe_tri6n nodes
35 
36  ! Reorder vertices: xi,et,st -> st,xi,et
37  nodes_out(1:3, 1) = vertices_in(1:3, 3) ! st
38  nodes_out(1:3, 2) = vertices_in(1:3, 1) ! xi
39  nodes_out(1:3, 3) = vertices_in(1:3, 2) ! et
40 
41  ! Reorder midpoints: xi-et,et-st,st-xi -> xi-st,xi-et,et-st
42  nodes_out(1:3, 4) = midpoints_in(1:3, 3) ! xi-st (was st-xi, same point)
43  nodes_out(1:3, 5) = midpoints_in(1:3, 1) ! xi-et
44  nodes_out(1:3, 6) = midpoints_in(1:3, 2) ! et-st
45  end subroutine reorder_tri3n_to_tri6n
46 
48  subroutine reorder_normals_tri3n_to_tri6n(normals_in, normals_out)
49  real(kind=kreal), intent(in) :: normals_in(3,3) ! fe_tri3n order
50  real(kind=kreal), intent(out) :: normals_out(3,3) ! fe_tri6n order
51 
52  ! xi,et,st -> st,xi,et
53  normals_out(1:3, 1) = normals_in(1:3, 3) ! st
54  normals_out(1:3, 2) = normals_in(1:3, 1) ! xi
55  normals_out(1:3, 3) = normals_in(1:3, 2) ! et
56  end subroutine reorder_normals_tri3n_to_tri6n
57 
58  subroutine update_surface_normal( surf, currpos, hecMESH )
61  type(tsurfelement), intent(inout) :: surf(:)
62  real(kind=kreal), intent(in) :: currpos(:)
63  type(hecmwst_local_mesh), intent(in), optional :: hecmesh
64 
65  integer(kind=kint) :: i, j, nn, gnode, n_node
66  real(kind=kreal) :: normal(3), norm_len
67  real(kind=kreal), allocatable :: vnormal(:)
68 
69  ! Calculate geometric normals at vertices (skip if no local surf elements)
70  if (size(surf) > 0) then
71  call calc_all_surf_vertex_normals(surf, currpos)
72  endif
73 
74  ! Determine array size
75  if (present(hecmesh)) then
76  n_node = hecmesh%n_node
77  else
78  if (size(surf) == 0) return
79  n_node = maxval([(maxval(surf(i)%nodes), i=1,size(surf))])
80  endif
81 
82  ! Allocate flat array for MPI communication: vnormal(3*n_node)
83  allocate(vnormal(3*n_node))
84  vnormal = 0.0d0
85 
86  ! Accumulate vertex normals from all local surface elements
87  do i = 1, size(surf)
88  nn = size(surf(i)%nodes)
89  do j = 1, nn
90  gnode = surf(i)%nodes(j)
91  vnormal(3*(gnode-1)+1:3*(gnode-1)+3) = &
92  vnormal(3*(gnode-1)+1:3*(gnode-1)+3) &
93  + surf(i)%vertex_normals(:, j)
94  enddo
95  enddo
96 
97  ! MPI communication: allreduce (sum) across processes
98  ! All processes must participate even if they have no local surf elements
99  if (present(hecmesh)) then
100  call hecmw_assemble_r(hecmesh, vnormal, n_node, 3)
101  call hecmw_update_r(hecmesh, vnormal, n_node, 3)
102  endif
103 
104  ! Normalize and write back to surf%vertex_normals
105  do i = 1, size(surf)
106  nn = size(surf(i)%nodes)
107  do j = 1, nn
108  gnode = surf(i)%nodes(j)
109  normal(:) = vnormal(3*(gnode-1)+1:3*(gnode-1)+3)
110  norm_len = dsqrt(dot_product(normal, normal))
111  if (norm_len > 1.0d-20) then
112  surf(i)%vertex_normals(:, j) = normal / norm_len
113  endif
114  enddo
115  enddo
116 
117  deallocate(vnormal)
118 
119  end subroutine update_surface_normal
120 
124  subroutine compute_cab_old(na_vec, nb_vec, Cab_a, Cab_b)
125  implicit none
126  real(kind=kreal), intent(in) :: na_vec(3) ! unit normal at vertex a
127  real(kind=kreal), intent(in) :: nb_vec(3) ! unit normal at vertex b
128  real(kind=kreal), intent(out) :: cab_a(3,3) ! correction matrix for vertex a
129  real(kind=kreal), intent(out) :: cab_b(3,3) ! correction matrix for vertex b
130 
131  real(kind=kreal) :: aab(2,3), ata(3,3), ata_orig(3,3), ata_inv(3,3)
132  real(kind=kreal) :: p(3,3)
133  real(kind=kreal) :: epsilon
134  integer(kind=kint) :: i
135 
136  ! Build Aab = [na^T; nb^T]
137  aab(1,:) = na_vec(:)
138  aab(2,:) = nb_vec(:)
139 
140  ! Compute AtA = Aab^T * Aab
141  ata = matmul(transpose(aab), aab)
142  ata_orig = ata
143 
144  ! Regularize: AtA_reg = AtA + eps*I
145  epsilon = (ata(1,1)+ata(2,2)+ata(3,3)) * nagata_epsilon
146  do i = 1, 3
147  ata(i,i) = ata(i,i) + epsilon
148  enddo
149 
150  ! Invert AtA_reg using calInverse
151  ata_inv = ata
152  call calinverse(3, ata_inv)
153 
154  ! Compute P = AtA_inv * AtA_orig
155  p = matmul(ata_inv, ata_orig)
156 
157  ! Cab_a = 0.5*I + 0.25*P
158  cab_a = 0.25d0 * p
159  do i = 1, 3
160  cab_a(i,i) = cab_a(i,i) + 0.5d0
161  enddo
162 
163  ! Cab_b = 0.5*I - 0.25*P
164  cab_b = -0.25d0 * p
165  do i = 1, 3
166  cab_b(i,i) = cab_b(i,i) + 0.5d0
167  enddo
168 
169  end subroutine compute_cab_old
170 
171  subroutine compute_cab(na_vec, nb_vec, Cab_a, Cab_b)
172  implicit none
173  real(kind=kreal), intent(in) :: na_vec(3) ! unit normal at vertex a (n1)
174  real(kind=kreal), intent(in) :: nb_vec(3) ! unit normal at vertex b (n2)
175  real(kind=kreal), intent(out) :: cab_a(3,3)
176  real(kind=kreal), intent(out) :: cab_b(3,3)
177 
178  real(kind=kreal) :: i3(3,3)
179  real(kind=kreal) :: m(3), mnorm
180  real(kind=kreal) :: a1, a2
181  real(kind=kreal) :: beta, den, k
182  real(kind=kreal) :: r(3) ! r = a2*nb - a1*na
183  real(kind=kreal) :: q(3,3) ! outer(m, r)
184  integer(kind=kint) :: i, j
185 
186  ! Identity
187  i3 = 0.0d0
188  do i=1,3
189  i3(i,i) = 1.0d0
190  enddo
191 
192  ! m = normalize(na + nb)
193  m(:) = na_vec(:) + nb_vec(:)
194  mnorm = sqrt( m(1)*m(1) + m(2)*m(2) + m(3)*m(3) )
195 
196  if (mnorm < 1.0d-12) then
197  m(:) = na_vec(:)
198  mnorm = 1.0d0
199  else
200  m(:) = m(:) / mnorm
201  endif
202 
203  a1 = m(1)*na_vec(1) + m(2)*na_vec(2) + m(3)*na_vec(3)
204  a2 = m(1)*nb_vec(1) + m(2)*nb_vec(2) + m(3)*nb_vec(3)
205 
206  ! Regularization for alpha (beta >= 0)
207  ! Option 1: fixed dimensionless parameter
208  beta = nagata_epsilon ! << define e.g. 1e-3 .. 1e-1 (see notes below)
209 
210  den = 16.0d0*(a1*a1 + a2*a2) + beta
211 
212  ! If den too small, do no curvature (midpoint)
213  if (den < 1.0d-20) then
214  cab_a = 0.5d0 * i3
215  cab_b = 0.5d0 * i3
216  return
217  endif
218 
219  k = 4.0d0 / den
220 
221  ! r = a2*nb - a1*na (3-vector)
222  r(:) = a2*nb_vec(:) - a1*na_vec(:)
223 
224  ! Q = outer(m, r) = m * r^T (3x3)
225  do i=1,3
226  do j=1,3
227  q(i,j) = m(i) * r(j)
228  enddo
229  enddo
230 
231  ! Cab_a = 0.5*I - K*Q
232  ! Cab_b = 0.5*I + K*Q
233  cab_a = 0.5d0*i3 - k*q
234  cab_b = 0.5d0*i3 + k*q
235 
236  end subroutine compute_cab
237 
240  subroutine compute_interpolation_matrix_p(etype, nnode, lpos, vertex_normals, P_matrix)
241  implicit none
242  integer(kind=kint), intent(in) :: etype ! element type
243  integer(kind=kint), intent(in) :: nnode ! number of nodes
244  real(kind=kreal), intent(in) :: lpos(2) ! local coordinates (xi, eta)
245  real(kind=kreal), intent(in) :: vertex_normals(3,nnode) ! unit normals at vertices
246  real(kind=kreal), intent(out) :: p_matrix(3,nnode*3) ! interpolation matrix
247 
248  real(kind=kreal) :: n(8)
249  real(kind=kreal) :: cab_12_1(3,3), cab_12_2(3,3)
250  real(kind=kreal) :: cab_23_2(3,3), cab_23_3(3,3)
251  real(kind=kreal) :: cab_31_3(3,3), cab_31_1(3,3)
252  real(kind=kreal) :: cab_34_3(3,3), cab_34_4(3,3)
253  real(kind=kreal) :: cab_41_4(3,3), cab_41_1(3,3)
254  real(kind=kreal) :: p1(3,3), p2(3,3), p3(3,3), p4(3,3)
255  real(kind=kreal) :: i3(3,3)
256  real(kind=kreal) :: normals_tri6n(3,3)
257  integer(kind=kint) :: i, j
258 
259  p_matrix = 0.0d0
260 
261  ! Identity matrix
262  i3 = 0.0d0
263  i3(1,1) = 1.0d0
264  i3(2,2) = 1.0d0
265  i3(3,3) = 1.0d0
266 
267  select case(etype)
268  case(fe_tri3n)
269  call getshapefunc(fe_tri6n, lpos, n)
270  call reorder_normals_tri3n_to_tri6n(vertex_normals, normals_tri6n)
271 
272  ! Compute Cab for fe_tri6n edges: (st-xi), (xi-et), (et-st)
273  call compute_cab(normals_tri6n(:,1), normals_tri6n(:,2), cab_31_3, cab_31_1)
274  call compute_cab(normals_tri6n(:,2), normals_tri6n(:,3), cab_12_1, cab_12_2)
275  call compute_cab(normals_tri6n(:,3), normals_tri6n(:,1), cab_23_2, cab_23_3)
276 
277  ! P matrices for fe_tri6n: st, xi, et
278  p1 = n(1) * i3 + n(4) * cab_31_3 + n(6) * cab_23_3
279  p2 = n(2) * i3 + n(4) * cab_31_1 + n(5) * cab_12_1
280  p3 = n(3) * i3 + n(5) * cab_12_2 + n(6) * cab_23_2
281 
282  ! Assemble P in fe_tri3n order: xi, et, st
283  p_matrix(1:3, 1:3) = p2
284  p_matrix(1:3, 4:6) = p3
285  p_matrix(1:3, 7:9) = p1
286 
287  case(fe_quad4n)
288  call getshapefunc(fe_quad8n, lpos, n)
289 
290  ! Compute Cab for 4 edges: (1,2), (2,3), (3,4), (4,1)
291  call compute_cab(vertex_normals(:,1), vertex_normals(:,2), cab_12_1, cab_12_2)
292  call compute_cab(vertex_normals(:,2), vertex_normals(:,3), cab_23_2, cab_23_3)
293  call compute_cab(vertex_normals(:,3), vertex_normals(:,4), cab_34_3, cab_34_4)
294  call compute_cab(vertex_normals(:,4), vertex_normals(:,1), cab_41_4, cab_41_1)
295 
296  ! P matrices for fe_quad8n: node 1, 2, 3, 4
297  p1 = n(1) * i3 + n(5) * cab_12_1 + n(8) * cab_41_1
298  p2 = n(2) * i3 + n(5) * cab_12_2 + n(6) * cab_23_2
299  p3 = n(3) * i3 + n(6) * cab_23_3 + n(7) * cab_34_3
300  p4 = n(4) * i3 + n(7) * cab_34_4 + n(8) * cab_41_4
301 
302  ! Assemble P in fe_quad4n order: 1, 2, 3, 4
303  p_matrix(1:3, 1:3) = p1
304  p_matrix(1:3, 4:6) = p2
305  p_matrix(1:3, 7:9) = p3
306  p_matrix(1:3, 10:12) = p4
307 
308  case default
309  write(*,*) "Error: compute_interpolation_matrix_P - Unsupported element type for Nagata patch.",etype
310  stop
311  end select
312 
313  end subroutine compute_interpolation_matrix_p
314 
315  subroutine create_intermediate_points( surf, currpos, contact_name )
316  type(tsurfelement), intent(inout) :: surf(:)
317  real(kind=kreal), intent(in) :: currpos(:)
318  character(len=HECMW_NAME_LEN), intent(in) :: contact_name
319 
320  integer(kind=kint) :: i
321 
322  if (size(surf) == 0) return
323 
324  !$omp parallel do private(i)
325  do i = 1, size(surf)
326  call create_intermediate_points_single(surf(i), currpos)
327  enddo
328  !$omp end parallel do
329 
330  if( debug > 0 ) then
331  call print_surface_elements_to_vtk(surf, currpos, contact_name)
332  end if
333 
334  end subroutine create_intermediate_points
335 
336  subroutine create_intermediate_points_single( surf, currpos )
337  type(tsurfelement), intent(inout) :: surf
338  real(kind=kreal), intent(in) :: currpos(:)
339 
340  integer(kind=kint) :: i, etype
341  real(kind=kreal) :: elem(3,4)
342  real(kind=kreal), pointer :: vertex_normals(:,:)
343  real(kind=kreal) :: cab_12_1(3,3), cab_12_2(3,3)
344  real(kind=kreal) :: cab_23_2(3,3), cab_23_3(3,3)
345  real(kind=kreal) :: cab_31_3(3,3), cab_31_1(3,3)
346  real(kind=kreal) :: cab_34_3(3,3), cab_34_4(3,3)
347  real(kind=kreal) :: cab_41_4(3,3), cab_41_1(3,3)
348 
349  etype = surf%etype
350  vertex_normals => surf%vertex_normals
351 
352  select case(etype)
353  case(fe_tri3n)
354 
355  if (.not. associated(surf%intermediate_points)) then
356  allocate(surf%intermediate_points(3,3))
357  end if
358 
359  do i=1,3
360  elem(1:3,i) = currpos(3*(surf%nodes(i)-1)+1 : 3*surf%nodes(i))
361  enddo
362 
363  ! Compute Cab for 3 edges: (1,2), (2,3), (3,1)
364  call compute_cab(vertex_normals(:,1), vertex_normals(:,2), cab_12_1, cab_12_2)
365  call compute_cab(vertex_normals(:,2), vertex_normals(:,3), cab_23_2, cab_23_3)
366  call compute_cab(vertex_normals(:,3), vertex_normals(:,1), cab_31_3, cab_31_1)
367 
368  ! intermediate point
369  surf%intermediate_points(:,1) = matmul(cab_12_1(1:3,1:3), elem(1:3,1)) + matmul(cab_12_2(1:3,1:3), elem(1:3,2))
370  surf%intermediate_points(:,2) = matmul(cab_23_2(1:3,1:3), elem(1:3,2)) + matmul(cab_23_3(1:3,1:3), elem(1:3,3))
371  surf%intermediate_points(:,3) = matmul(cab_31_3(1:3,1:3), elem(1:3,3)) + matmul(cab_31_1(1:3,1:3), elem(1:3,1))
372 
373  case(fe_quad4n)
374 
375  if (.not. associated(surf%intermediate_points)) then
376  allocate(surf%intermediate_points(3,4))
377  end if
378 
379  do i=1,4
380  elem(1:3,i) = currpos(3*(surf%nodes(i)-1)+1 : 3*surf%nodes(i))
381  enddo
382 
383  ! Compute Cab for 4 edges: (1,2), (2,3), (3,4), (4,1)
384  call compute_cab(vertex_normals(:,1), vertex_normals(:,2), cab_12_1, cab_12_2)
385  call compute_cab(vertex_normals(:,2), vertex_normals(:,3), cab_23_2, cab_23_3)
386  call compute_cab(vertex_normals(:,3), vertex_normals(:,4), cab_34_3, cab_34_4)
387  call compute_cab(vertex_normals(:,4), vertex_normals(:,1), cab_41_4, cab_41_1)
388 
389  ! intermediate points
390  surf%intermediate_points(:,1) = matmul(cab_12_1(1:3,1:3), elem(1:3,1)) + matmul(cab_12_2(1:3,1:3), elem(1:3,2))
391  surf%intermediate_points(:,2) = matmul(cab_23_2(1:3,1:3), elem(1:3,2)) + matmul(cab_23_3(1:3,1:3), elem(1:3,3))
392  surf%intermediate_points(:,3) = matmul(cab_34_3(1:3,1:3), elem(1:3,3)) + matmul(cab_34_4(1:3,1:3), elem(1:3,4))
393  surf%intermediate_points(:,4) = matmul(cab_41_4(1:3,1:3), elem(1:3,4)) + matmul(cab_41_1(1:3,1:3), elem(1:3,1))
394 
395  case default
396  write(*,*) "Error: create_intermediate_points - Unsupported element type for Nagata patch.",etype
397  stop
398  end select
399 
400  end subroutine create_intermediate_points_single
401 
402  subroutine print_surface_elements_to_vtk( surf, currpos, contact_name )
403  type(tsurfelement), intent(in) :: surf(:)
404  real(kind=kreal), intent(in) :: currpos(:)
405  character(len=HECMW_NAME_LEN), intent(in) :: contact_name
406 
407  integer(kind=kint), parameter :: vtk_unit = 99
408  integer(kind=kint) :: i, j, nn, n_tri, n_quad, n_elem, n_points, n_cells_size, node_id, inode
409  real(kind=kreal) :: coord(3), normal(3)
410  character(len=256) :: filename
411 
412  ! Count valid elements
413  n_tri = 0
414  n_quad = 0
415  do i = 1, size(surf)
416  if (surf(i)%etype == fe_tri3n) then
417  n_tri = n_tri + 1
418  else if (surf(i)%etype == fe_quad4n) then
419  n_quad = n_quad + 1
420  endif
421  enddo
422 
423  n_elem = n_tri + n_quad
424  if (n_elem == 0) return
425 
426  ! Calculate total points and cells size
427  n_points = n_tri * 6 + n_quad * 8
428  n_cells_size = n_tri * 7 + n_quad * 9 ! tri: 1+6, quad: 1+8
429 
430  ! Open VTK file
431  filename = trim(contact_name) // '_nagata_debug.vtk'
432  open(unit=vtk_unit, file=filename, status='replace', action='write', form='formatted')
433 
434  ! Write header
435  write(vtk_unit, '(A)') '# vtk DataFile Version 3.0'
436  write(vtk_unit, '(A,A)') 'Nagata patch debug: ', trim(contact_name)
437  write(vtk_unit, '(A)') 'ASCII'
438  write(vtk_unit, '(A)') 'DATASET UNSTRUCTURED_GRID'
439  write(vtk_unit, *)
440 
441  ! Write POINTS
442  write(vtk_unit, '(A,I0,A)') 'POINTS ', n_points, ' float'
443  do i = 1, size(surf)
444  if (surf(i)%etype == fe_tri3n .or. surf(i)%etype == fe_quad4n) then
445  nn = size(surf(i)%nodes)
446  ! Output vertex coordinates
447  do j = 1, nn
448  inode = surf(i)%nodes(j)
449  coord(1:3) = currpos(3*(inode-1)+1 : 3*inode)
450  write(vtk_unit, '(3(E15.7,1X))') coord(1), coord(2), coord(3)
451  enddo
452  ! Output intermediate point coordinates
453  do j = 1, nn
454  coord(1:3) = surf(i)%intermediate_points(1:3, j)
455  write(vtk_unit, '(3(E15.7,1X))') coord(1), coord(2), coord(3)
456  enddo
457  endif
458  enddo
459  write(vtk_unit, *)
460 
461  ! Write CELLS
462  write(vtk_unit, '(A,I0,1X,I0)') 'CELLS ', n_elem, n_cells_size
463  node_id = 0
464  do i = 1, size(surf)
465  if (surf(i)%etype == fe_tri3n) then
466  write(vtk_unit, '(I0,1X,I0,1X,I0,1X,I0,1X,I0,1X,I0,1X,I0)') &
467  6, node_id, node_id+1, node_id+2, node_id+3, node_id+4, node_id+5
468  node_id = node_id + 6
469  else if (surf(i)%etype == fe_quad4n) then
470  write(vtk_unit, '(I0,1X,I0,1X,I0,1X,I0,1X,I0,1X,I0,1X,I0,1X,I0,1X,I0)') &
471  8, node_id, node_id+1, node_id+2, node_id+3, node_id+4, node_id+5, node_id+6, node_id+7
472  node_id = node_id + 8
473  endif
474  enddo
475  write(vtk_unit, *)
476 
477  ! Write CELL_TYPES
478  write(vtk_unit, '(A,I0)') 'CELL_TYPES ', n_elem
479  do i = 1, size(surf)
480  if (surf(i)%etype == fe_tri3n) then
481  write(vtk_unit, '(I0)') 22 ! VTK_QUADRATIC_TRIANGLE
482  else if (surf(i)%etype == fe_quad4n) then
483  write(vtk_unit, '(I0)') 23 ! VTK_QUADRATIC_QUAD
484  endif
485  enddo
486  write(vtk_unit, *)
487 
488  ! Write POINT_DATA - VECTORS (vertex normals)
489  write(vtk_unit, '(A,I0)') 'POINT_DATA ', n_points
490  write(vtk_unit, '(A)') 'VECTORS vertex_normal float'
491  do i = 1, size(surf)
492  if (surf(i)%etype == fe_tri3n .or. surf(i)%etype == fe_quad4n) then
493  nn = size(surf(i)%nodes)
494  ! Output vertex normals
495  do j = 1, nn
496  normal(1:3) = surf(i)%vertex_normals(1:3, j)
497  write(vtk_unit, '(3(E15.7,1X))') normal(1), normal(2), normal(3)
498  enddo
499  ! Output zero normals for intermediate points
500  do j = 1, nn
501  write(vtk_unit, '(A)') '0.0 0.0 0.0'
502  enddo
503  endif
504  enddo
505 
506  close(vtk_unit)
507 
508  write(*,'(A,A)') 'VTK debug file written: ', trim(filename)
509 
510  end subroutine print_surface_elements_to_vtk
511 
512 
513 end module m_fstr_contact_smoothing
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, parameter fe_tri6n
Definition: element.f90:70
integer, parameter fe_tri3n
Definition: element.f90:69
integer, parameter fe_quad4n
Definition: element.f90:72
integer, parameter fe_quad8n
Definition: element.f90:73
I/O and Utility.
Definition: hecmw_util_f.F90:7
integer(kind=kint), parameter hecmw_name_len
Definition: hecmw.f90:6
Contact surface smoothing using Nagata patch interpolation.
subroutine compute_cab_old(na_vec, nb_vec, Cab_a, Cab_b)
Compute Cab correction matrices for edge (a,b) Kab = (Aab^T*Aab + eps*I)^-1 * Aab^T * D * Aab Cab_a =...
subroutine, public reorder_tri3n_to_tri6n(vertices_in, midpoints_in, nodes_out)
Reorder triangle vertices and midpoints from fe_tri3n to fe_tri6n order fe_tri3n: v1(xi),...
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; ...
subroutine, public compute_cab(na_vec, nb_vec, Cab_a, Cab_b)
subroutine, public update_surface_normal(surf, currpos, hecMESH)
subroutine, public create_intermediate_points(surf, currpos, contact_name)
subroutine hecmw_assemble_r(hecMESH, val, n, m)
subroutine hecmw_update_r(hecMESH, val, n, m)
This module provides aux functions.
Definition: utilities.f90:6
subroutine calinverse(NN, A)
calculate inverse of matrix a
Definition: utilities.f90:295
This module manages surface elements in 3D It provides basic definition of surface elements (triangla...
Definition: surf_ele.f90:8
subroutine calc_all_surf_vertex_normals(surf, currpos)
Calculate vertex normals for all surface elements (geometric calculation only)
Definition: surf_ele.f90:342
Structure to define surface group.
Definition: surf_ele.f90:23