FrontISTR  5.9.0
Large-scale structural analysis program with finit element method
fstr_NodalKinematics.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 !-------------------------------------------------------------------------------
15  use m_fstr
18  implicit none
19 
20  private
21 
26 
27 contains
28 
32  subroutine fstr_ensure_finite_rotation_state( hecMESH, fstrSOLID, ndof )
33  use elementinfo, only: fe_mitc4_shell
34  implicit none
35 
36  type (hecmwst_local_mesh), intent(in) :: hecmesh
37  type (fstr_solid), intent(inout) :: fstrsolid
38  integer(kind=kint), intent(in) :: ndof
39 
40  integer(kind=kint) :: itype, is, ie, ic_type, icel, iis, nn, j, node_id
41  integer(kind=kint), allocatable :: node_mode(:), node_count(:)
42  real(kind=kreal), allocatable :: director_sum(:,:), tangent_sum(:,:)
43  real(kind=kreal) :: ecoord(3, 8), triad(3, 3), trial(3, 3)
44  real(kind=kreal) :: director(3), tangent(3), ref_axis(3), normv, proj
45 
46  if( .not. fstrsolid%has_finite_rotation_kinematics ) return
47  if( fstrsolid%finite_rotation_state_ready ) return
48  if( .not. associated(fstrsolid%shell_rot_state) ) return
49 
50  allocate( director_sum(3, hecmesh%n_node) )
51  allocate( tangent_sum(3, hecmesh%n_node) )
52  allocate( node_mode(hecmesh%n_node) )
53  allocate( node_count(hecmesh%n_node) )
54  director_sum(:, :) = 0.0d0
55  tangent_sum(:, :) = 0.0d0
56  node_mode(:) = 0
57  node_count(:) = 0
58 
59  do itype = 1, hecmesh%n_elem_type
60  is = hecmesh%elem_type_index(itype-1) + 1
61  ie = hecmesh%elem_type_index(itype)
62  ic_type = hecmesh%elem_type_item(itype)
63  if( ic_type /= fe_mitc4_shell ) cycle
64  do icel = is, ie
65  iis = hecmesh%elem_node_index(icel-1)
66  nn = hecmesh%elem_node_index(icel) - iis
67  if( .not. associated( fstrsolid%elements(icel)%gausses ) ) cycle
68  if( .not. fstr_uses_finite_rotation_kinematics( ic_type, nn, &
69  fstrsolid%elements(icel)%gausses(1)%pMaterial ) ) cycle
70 
71  do j = 1, min(nn, 8)
72  node_id = hecmesh%elem_node_item(iis+j)
73  ecoord(1:3, j) = hecmesh%node(3*node_id-2:3*node_id)
74  end do
75 
76  if( ndof >= 6 ) then
77  do j = 1, nn
78  call fstr_reference_shell_triad( nn, ecoord(1:3, 1:nn), j, triad )
79  node_id = hecmesh%elem_node_item(iis+j)
80  if( node_id <= 0 .or. node_id > hecmesh%n_node ) cycle
81  if( fstrsolid%shell_rot_state(node_id) /= 0 ) cycle
82  ! average shell triads at shared nodes
83  director_sum(1:3, node_id) = director_sum(1:3, node_id) + triad(1:3, 3)
84  tangent_sum(1:3, node_id) = tangent_sum(1:3, node_id) + triad(1:3, 1)
85  node_count(node_id) = node_count(node_id) + 1
86  node_mode(node_id) = 1
87  end do
88  endif
89  end do
90  end do
91 
92  do node_id = 1, hecmesh%n_node
93  if( node_count(node_id) <= 0 ) cycle
94  if( fstrsolid%shell_rot_state(node_id) /= 0 ) cycle
95 
96  director(1:3) = director_sum(1:3, node_id)
97  normv = dsqrt( dot_product( director(1:3), director(1:3) ) )
98  if( normv <= 1.0d-14 ) then
99  call fstr_set_identity_triad( triad )
100  call fstr_store_shell_triad_node( fstrsolid, node_id, triad, node_mode(node_id) )
101  cycle
102  endif
103  director(1:3) = director(1:3)/normv
104 
105  tangent(1:3) = tangent_sum(1:3, node_id)
106  proj = dot_product( tangent(1:3), director(1:3) )
107  tangent(1:3) = tangent(1:3) - proj*director(1:3)
108  normv = dsqrt( dot_product( tangent(1:3), tangent(1:3) ) )
109  if( normv <= 1.0d-14 ) then
110  ref_axis(1:3) = (/ 1.0d0, 0.0d0, 0.0d0 /)
111  if( dabs(director(1)) > 0.9d0 ) ref_axis(1:3) = (/ 0.0d0, 1.0d0, 0.0d0 /)
112  proj = dot_product( ref_axis(1:3), director(1:3) )
113  tangent(1:3) = ref_axis(1:3) - proj*director(1:3)
114  normv = dsqrt( dot_product( tangent(1:3), tangent(1:3) ) )
115  endif
116  tangent(1:3) = tangent(1:3)/normv
117 
118  call fstr_set_identity_triad( trial )
119  trial(1:3, 1) = tangent(1:3)
120  trial(1:3, 3) = director(1:3)
121  call shellorthonormalizetriad( trial, triad )
122  call fstr_store_shell_triad_node( fstrsolid, node_id, triad, node_mode(node_id) )
123  end do
124 
125  deallocate( director_sum )
126  deallocate( tangent_sum )
127  deallocate( node_mode )
128  deallocate( node_count )
129 
130  call fstr_update_initialized_finite_rotation_state( hecmesh, fstrsolid )
131  fstrsolid%finite_rotation_state_ready = .true.
132 
133  end subroutine fstr_ensure_finite_rotation_state
134 
137  subroutine fstr_begin_nodal_kinematics_step( hecMESH, fstrSOLID, ndof )
138  implicit none
139 
140  type (hecmwst_local_mesh), intent(in) :: hecmesh
141  type (fstr_solid), intent(inout) :: fstrsolid
142  integer(kind=kint), intent(in) :: ndof
143 
144  call fstr_ensure_finite_rotation_state( hecmesh, fstrsolid, ndof )
145  if( .not. associated(fstrsolid%shell_triad) ) return
146 
147  fstrsolid%shell_triad_bak(:) = fstrsolid%shell_triad(:)
148  fstrsolid%shell_drill_bak(:) = fstrsolid%shell_drill(:)
149  fstrsolid%shell_dtriad(:) = fstrsolid%shell_triad(:)
150  fstrsolid%shell_ddrill(:) = fstrsolid%shell_drill(:)
151 
152  end subroutine fstr_begin_nodal_kinematics_step
153 
159  subroutine fstr_apply_solution_increment( hecMESH, fstrSOLID, ndof, x )
160  implicit none
161 
162  type (hecmwst_local_mesh), intent(in) :: hecmesh
163  type (fstr_solid), intent(inout) :: fstrsolid
164  integer(kind=kint), intent(in) :: ndof
165  real(kind=kreal), intent(in) :: x(:)
166 
167  integer(kind=kint) :: node_id, idx, base
168  real(kind=kreal) :: theta_inc(3), theta_compat(3)
169  real(kind=kreal) :: triad_old(3, 3), triad_new(3, 3), drill_new
170 
171  if( .not. fstrsolid%has_finite_rotation_kinematics ) then
172  do node_id = 1, hecmesh%n_node
173  idx = ndof*(node_id-1)
174  fstrsolid%dunode(idx+1:idx+ndof) = fstrsolid%dunode(idx+1:idx+ndof) + x(idx+1:idx+ndof)
175  end do
176  return
177  endif
178  call fstr_ensure_finite_rotation_state( hecmesh, fstrsolid, ndof )
179  if( .not. associated(fstrsolid%shell_node_mode) ) then
180  do node_id = 1, hecmesh%n_node
181  idx = ndof*(node_id-1)
182  fstrsolid%dunode(idx+1:idx+ndof) = fstrsolid%dunode(idx+1:idx+ndof) + x(idx+1:idx+ndof)
183  end do
184  return
185  endif
186 
187  do node_id = 1, hecmesh%n_node
188  idx = ndof*(node_id-1)
189  if( fstrsolid%shell_node_mode(node_id) == 1 ) then
190  fstrsolid%dunode(idx+1:idx+3) = fstrsolid%dunode(idx+1:idx+3) + x(idx+1:idx+3)
191  theta_inc(1:3) = x(idx+4:idx+6)
192  base = 9*(node_id-1)
193  triad_old(1:3, 1) = fstrsolid%shell_dtriad(base+1:base+3)
194  triad_old(1:3, 2) = fstrsolid%shell_dtriad(base+4:base+6)
195  triad_old(1:3, 3) = fstrsolid%shell_dtriad(base+7:base+9)
196  call shellupdatetriadwithincrement( triad_old, fstrsolid%shell_ddrill(node_id), &
197  theta_inc, triad_new, drill_new )
198  fstrsolid%shell_dtriad(base+1:base+3) = triad_new(1:3, 1)
199  fstrsolid%shell_dtriad(base+4:base+6) = triad_new(1:3, 2)
200  fstrsolid%shell_dtriad(base+7:base+9) = triad_new(1:3, 3)
201  fstrsolid%shell_ddrill(node_id) = drill_new
202  ! update nodal rotation vector for output
203  call shellcomposerotationvector( fstrsolid%dunode(idx+4:idx+6), x(idx+4:idx+6), theta_compat )
204  fstrsolid%dunode(idx+4:idx+6) = theta_compat(1:3)
205  if( ndof > 6 ) then
206  fstrsolid%dunode(idx+7:idx+ndof) = fstrsolid%dunode(idx+7:idx+ndof) + x(idx+7:idx+ndof)
207  endif
208  else
209  fstrsolid%dunode(idx+1:idx+ndof) = fstrsolid%dunode(idx+1:idx+ndof) + x(idx+1:idx+ndof)
210  endif
211  end do
212 
213  end subroutine fstr_apply_solution_increment
214 
219  subroutine fstr_commit_solution_increment( hecMESH, fstrSOLID, ndof )
220  implicit none
221 
222  type (hecmwst_local_mesh), intent(in) :: hecmesh
223  type (fstr_solid), intent(inout) :: fstrsolid
224  integer(kind=kint), intent(in) :: ndof
225 
226  integer(kind=kint) :: node_id, idx, base
227  real(kind=kreal) :: theta_compat(3)
228 
229  if( .not. fstrsolid%has_finite_rotation_kinematics ) then
230  do node_id = 1, hecmesh%n_node
231  idx = ndof*(node_id-1)
232  fstrsolid%unode(idx+1:idx+ndof) = fstrsolid%unode(idx+1:idx+ndof) + fstrsolid%dunode(idx+1:idx+ndof)
233  end do
234  return
235  endif
236  call fstr_ensure_finite_rotation_state( hecmesh, fstrsolid, ndof )
237  if( .not. associated(fstrsolid%shell_node_mode) ) then
238  do node_id = 1, hecmesh%n_node
239  idx = ndof*(node_id-1)
240  fstrsolid%unode(idx+1:idx+ndof) = fstrsolid%unode(idx+1:idx+ndof) + fstrsolid%dunode(idx+1:idx+ndof)
241  end do
242  return
243  endif
244 
245  do node_id = 1, hecmesh%n_node
246  idx = ndof*(node_id-1)
247  if( fstrsolid%shell_node_mode(node_id) == 1 ) then
248  fstrsolid%unode(idx+1:idx+3) = fstrsolid%unode(idx+1:idx+3) + fstrsolid%dunode(idx+1:idx+3)
249  base = 9*(node_id-1)
250  fstrsolid%shell_triad(base+1:base+9) = fstrsolid%shell_dtriad(base+1:base+9)
251  fstrsolid%shell_drill(node_id) = fstrsolid%shell_ddrill(node_id)
252  ! update nodal rotation vector for output
253  call shellcomposerotationvector( fstrsolid%unode(idx+4:idx+6), fstrsolid%dunode(idx+4:idx+6), theta_compat )
254  fstrsolid%unode(idx+4:idx+6) = theta_compat(1:3)
255  if( ndof > 6 ) then
256  fstrsolid%unode(idx+7:idx+ndof) = fstrsolid%unode(idx+7:idx+ndof) + fstrsolid%dunode(idx+7:idx+ndof)
257  endif
258  else
259  fstrsolid%unode(idx+1:idx+ndof) = fstrsolid%unode(idx+1:idx+ndof) + fstrsolid%dunode(idx+1:idx+ndof)
260  endif
261  end do
262 
263  end subroutine fstr_commit_solution_increment
264 
265  ! ---------------------------------------------------------------------------
266  ! Private helpers: reference-frame construction at element nodes.
267  ! ---------------------------------------------------------------------------
268 
269  subroutine fstr_set_identity_triad( triad )
270  implicit none
271 
272  real(kind=kreal), intent(out) :: triad(3, 3)
273 
274  triad(:, :) = 0.0d0
275  triad(1, 1) = 1.0d0
276  triad(2, 2) = 1.0d0
277  triad(3, 3) = 1.0d0
278 
279  end subroutine fstr_set_identity_triad
280 
283  subroutine fstr_reference_shell_triad( nn, ecoord, inode, triad )
285  implicit none
286 
287  integer(kind=kint), intent(in) :: nn
288  integer(kind=kint), intent(in) :: inode
289  real(kind=kreal), intent(in) :: ecoord(3, nn)
290  real(kind=kreal), intent(out) :: triad(3, 3)
291 
292  real(kind=kreal) :: xi, eta
293  real(kind=kreal) :: shapederiv(4, 2)
294  real(kind=kreal) :: g1(3), g2(3), e0(3), trial(3, 3), normv
295  integer(kind=kint) :: i
296 
297  call fstr_set_identity_triad( trial )
298  if( nn /= 4 ) then
299  triad(1:3, 1:3) = trial(1:3, 1:3)
300  return
301  endif
302 
303  call getshapederiv( fe_mitc4_shell, (/ 0.0d0, 0.0d0 /), shapederiv )
304  e0(1:3) = 0.0d0
305  do i = 1, 4
306  e0(1:3) = e0(1:3) + shapederiv(i, 1)*ecoord(1:3, i)
307  end do
308 
309  select case( inode )
310  case( 1 )
311  xi = -1.0d0
312  eta = -1.0d0
313  case( 2 )
314  xi = 1.0d0
315  eta = -1.0d0
316  case( 3 )
317  xi = 1.0d0
318  eta = 1.0d0
319  case default
320  xi = -1.0d0
321  eta = 1.0d0
322  end select
323 
324  call getshapederiv( fe_mitc4_shell, (/ xi, eta /), shapederiv )
325  g1(1:3) = 0.0d0
326  g2(1:3) = 0.0d0
327  do i = 1, 4
328  g1(1:3) = g1(1:3) + shapederiv(i, 1)*ecoord(1:3, i)
329  g2(1:3) = g2(1:3) + shapederiv(i, 2)*ecoord(1:3, i)
330  end do
331 
332  trial(1, 3) = g1(2)*g2(3) - g1(3)*g2(2)
333  trial(2, 3) = g1(3)*g2(1) - g1(1)*g2(3)
334  trial(3, 3) = g1(1)*g2(2) - g1(2)*g2(1)
335 
336  trial(1, 2) = trial(2, 3)*e0(3) - trial(3, 3)*e0(2)
337  trial(2, 2) = trial(3, 3)*e0(1) - trial(1, 3)*e0(3)
338  trial(3, 2) = trial(1, 3)*e0(2) - trial(2, 3)*e0(1)
339  normv = dsqrt( dot_product( trial(1:3, 2), trial(1:3, 2) ) )
340  if( normv > 1.0d-14 ) trial(1:3, 2) = trial(1:3, 2)/normv
341 
342  trial(1, 1) = trial(2, 2)*trial(3, 3) - trial(3, 2)*trial(2, 3)
343  trial(2, 1) = trial(3, 2)*trial(1, 3) - trial(1, 2)*trial(3, 3)
344  trial(3, 1) = trial(1, 2)*trial(2, 3) - trial(2, 2)*trial(1, 3)
345 
346  call shellorthonormalizetriad( trial, triad )
347 
348  end subroutine fstr_reference_shell_triad
349 
351  subroutine fstr_store_shell_triad_node( fstrSOLID, node_id, triad, mode )
352  implicit none
353 
354  type (fstr_solid), intent(inout) :: fstrSOLID
355  integer(kind=kint), intent(in) :: node_id, mode
356  real(kind=kreal), intent(in) :: triad(3, 3)
357 
358  integer(kind=kint) :: base
359 
360  if( node_id <= 0 ) return
361  if( node_id > size(fstrsolid%shell_rot_state) ) return
362  if( fstrsolid%shell_rot_state(node_id) /= 0 ) return
363 
364  base = 9*(node_id-1)
365  fstrsolid%shell_rot_state(node_id) = mode
366  ! initialize reference and current shell triads
367  fstrsolid%shell_ref_triad(base+1:base+3) = triad(1:3, 1)
368  fstrsolid%shell_ref_triad(base+4:base+6) = triad(1:3, 2)
369  fstrsolid%shell_ref_triad(base+7:base+9) = triad(1:3, 3)
370  fstrsolid%shell_triad(base+1:base+3) = triad(1:3, 1)
371  fstrsolid%shell_triad(base+4:base+6) = triad(1:3, 2)
372  fstrsolid%shell_triad(base+7:base+9) = triad(1:3, 3)
373  fstrsolid%shell_triad_bak(base+1:base+9) = fstrsolid%shell_triad(base+1:base+9)
374  fstrsolid%shell_dtriad(base+1:base+9) = fstrsolid%shell_triad(base+1:base+9)
375  fstrsolid%shell_drill(node_id) = 0.0d0
376  fstrsolid%shell_drill_bak(node_id) = 0.0d0
377  fstrsolid%shell_ddrill(node_id) = 0.0d0
378 
379  end subroutine fstr_store_shell_triad_node
380 
382  subroutine fstr_reset_shell_state_from_reference( fstrSOLID )
383  implicit none
384 
385  type (fstr_solid), intent(inout) :: fstrSOLID
386 
387  integer(kind=kint) :: node_id, base
388 
389  if( .not. fstrsolid%has_finite_rotation_kinematics ) return
390  if( .not. associated(fstrsolid%shell_rot_state) ) return
391  if( .not. associated(fstrsolid%shell_ref_triad) ) return
392 
393  do node_id = 1, size(fstrsolid%shell_rot_state)
394  if( fstrsolid%shell_rot_state(node_id) == 0 ) cycle
395  base = 9*(node_id-1)
396  if( associated(fstrsolid%shell_triad) ) &
397  fstrsolid%shell_triad(base+1:base+9) = fstrsolid%shell_ref_triad(base+1:base+9)
398  if( associated(fstrsolid%shell_triad_bak) ) &
399  fstrsolid%shell_triad_bak(base+1:base+9) = fstrsolid%shell_ref_triad(base+1:base+9)
400  if( associated(fstrsolid%shell_dtriad) ) &
401  fstrsolid%shell_dtriad(base+1:base+9) = fstrsolid%shell_ref_triad(base+1:base+9)
402  if( associated(fstrsolid%shell_drill) ) fstrsolid%shell_drill(node_id) = 0.0d0
403  if( associated(fstrsolid%shell_drill_bak) ) fstrsolid%shell_drill_bak(node_id) = 0.0d0
404  if( associated(fstrsolid%shell_ddrill) ) fstrsolid%shell_ddrill(node_id) = 0.0d0
405  end do
406 
407  end subroutine fstr_reset_shell_state_from_reference
408 
416  subroutine fstr_update_initialized_finite_rotation_state( hecMESH, fstrSOLID )
417  use m_hecmw_comm_f, only: hecmw_update_r
418  implicit none
419 
420  type (hecmwST_local_mesh), intent(in) :: hecMESH
421  type (fstr_solid), intent(inout) :: fstrSOLID
422 
423  if( .not. fstrsolid%has_finite_rotation_kinematics ) return
424 
425  if( associated(fstrsolid%shell_ref_triad) ) &
426  call hecmw_update_r( hecmesh, fstrsolid%shell_ref_triad, hecmesh%n_node, 9 )
427 
428  call fstr_reset_shell_state_from_reference( fstrsolid )
429 
430  end subroutine fstr_update_initialized_finite_rotation_state
431 
432 end module m_fstr_nodalkinematics
This module encapsulate the basic functions of all elements provide by this software.
Definition: element.f90:43
subroutine getshapederiv(fetype, localcoord, shapederiv)
Calculate derivatives of shape function in natural coordinate system.
Definition: element.f90:685
integer, parameter fe_mitc4_shell
Definition: element.f90:95
Shared finite-rotation nodal kinematics and rotation algebra.
pure subroutine, public shellorthonormalizetriad(triad_in, triad_out)
pure subroutine, public shellupdatetriadwithincrement(triad_old, drill_old, theta_inc, triad_new, drill_new)
logical function, public fstr_uses_finite_rotation_kinematics(etype, nn, material)
pure subroutine, public shellcomposerotationvector(theta_old, theta_inc, theta_new)
Finite-rotation nodal kinematics for NLGEOM.
subroutine, public fstr_begin_nodal_kinematics_step(hecMESH, fstrSOLID, ndof)
Snapshot the converged rotation state at the start of a load step and reset the Newton trial state to...
subroutine fstr_store_shell_triad_node(fstrSOLID, node_id, triad, mode)
Store the reference frame into all rotation-state arrays for a fresh node.
subroutine, public fstr_ensure_finite_rotation_state(hecMESH, fstrSOLID, ndof)
Build the per-node reference frames once, by averaging element shell triads at shared nodes....
subroutine, public fstr_apply_solution_increment(hecMESH, fstrSOLID, ndof, x)
Apply the linear-solver solution increment x to the step displacement dunode.
subroutine, public fstr_commit_solution_increment(hecMESH, fstrSOLID, ndof)
Commit the converged step increment dunode into the total displacement unode.
This module defines common data and basic structures for analysis.
Definition: m_fstr.F90:15
subroutine hecmw_update_r(hecMESH, val, n, m)