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 !-------------------------------------------------------------------------------
23  use m_fstr
25  implicit none
26 
27  private
28 
36 
37 contains
38 
42  subroutine fstr_ensure_finite_rotation_state( hecMESH, fstrSOLID, ndof )
43  use elementinfo, only: fe_mitc4_shell
45  implicit none
46 
47  type (hecmwst_local_mesh), intent(in) :: hecmesh
48  type (fstr_solid), intent(inout) :: fstrsolid
49  integer(kind=kint), intent(in) :: ndof
50 
51  integer(kind=kint) :: itype, is, ie, ic_type, icel, iis, nn, j, node_id
52  integer(kind=kint), allocatable :: node_mode(:), node_count(:)
53  real(kind=kreal), allocatable :: director_sum(:,:), tangent_sum(:,:)
54  real(kind=kreal) :: ecoord(3, 8), triad(3, 3), trial(3, 3)
55  real(kind=kreal) :: director(3), tangent(3), ref_axis(3), normv, proj
56 
57  if( .not. fstrsolid%has_finite_rotation_kinematics ) return
58  if( fstrsolid%finite_rotation_state_ready ) return
59  if( .not. associated(fstrsolid%shell_rot_state) ) return
60 
61  allocate( director_sum(3, hecmesh%n_node) )
62  allocate( tangent_sum(3, hecmesh%n_node) )
63  allocate( node_mode(hecmesh%n_node) )
64  allocate( node_count(hecmesh%n_node) )
65  director_sum(:, :) = 0.0d0
66  tangent_sum(:, :) = 0.0d0
67  node_mode(:) = 0
68  node_count(:) = 0
69 
70  do itype = 1, hecmesh%n_elem_type
71  is = hecmesh%elem_type_index(itype-1) + 1
72  ie = hecmesh%elem_type_index(itype)
73  ic_type = hecmesh%elem_type_item(itype)
74  if( ic_type /= fe_mitc4_shell ) cycle
75  do icel = is, ie
76  iis = hecmesh%elem_node_index(icel-1)
77  nn = hecmesh%elem_node_index(icel) - iis
78  if( .not. associated( fstrsolid%elements(icel)%gausses ) ) cycle
79  if( .not. fstr_uses_finite_rotation_kinematics( ic_type, nn, &
80  fstrsolid%elements(icel)%gausses(1)%pMaterial ) ) cycle
81 
82  do j = 1, min(nn, 8)
83  node_id = hecmesh%elem_node_item(iis+j)
84  ecoord(1:3, j) = hecmesh%node(3*node_id-2:3*node_id)
85  end do
86 
87  if( ndof >= 6 ) then
88  do j = 1, nn
89  call fstr_reference_shell_triad( nn, ecoord(1:3, 1:nn), j, triad )
90  node_id = hecmesh%elem_node_item(iis+j)
91  if( node_id <= 0 .or. node_id > hecmesh%n_node ) cycle
92  if( fstrsolid%shell_rot_state(node_id) /= 0 ) cycle
93  ! average shell triads at shared nodes
94  director_sum(1:3, node_id) = director_sum(1:3, node_id) + triad(1:3, 3)
95  tangent_sum(1:3, node_id) = tangent_sum(1:3, node_id) + triad(1:3, 1)
96  node_count(node_id) = node_count(node_id) + 1
97  node_mode(node_id) = 1
98  end do
99  endif
100  end do
101  end do
102 
103  do node_id = 1, hecmesh%n_node
104  if( node_count(node_id) <= 0 ) cycle
105  if( fstrsolid%shell_rot_state(node_id) /= 0 ) cycle
106 
107  director(1:3) = director_sum(1:3, node_id)
108  normv = dsqrt( dot_product( director(1:3), director(1:3) ) )
109  if( normv <= 1.0d-14 ) then
110  call fstr_set_identity_triad( triad )
111  call fstr_store_shell_triad_node( fstrsolid, node_id, triad, node_mode(node_id) )
112  cycle
113  endif
114  director(1:3) = director(1:3)/normv
115 
116  tangent(1:3) = tangent_sum(1:3, node_id)
117  proj = dot_product( tangent(1:3), director(1:3) )
118  tangent(1:3) = tangent(1:3) - proj*director(1:3)
119  normv = dsqrt( dot_product( tangent(1:3), tangent(1:3) ) )
120  if( normv <= 1.0d-14 ) then
121  ref_axis(1:3) = (/ 1.0d0, 0.0d0, 0.0d0 /)
122  if( dabs(director(1)) > 0.9d0 ) ref_axis(1:3) = (/ 0.0d0, 1.0d0, 0.0d0 /)
123  proj = dot_product( ref_axis(1:3), director(1:3) )
124  tangent(1:3) = ref_axis(1:3) - proj*director(1:3)
125  normv = dsqrt( dot_product( tangent(1:3), tangent(1:3) ) )
126  endif
127  tangent(1:3) = tangent(1:3)/normv
128 
129  call fstr_set_identity_triad( trial )
130  trial(1:3, 1) = tangent(1:3)
131  trial(1:3, 3) = director(1:3)
132  call shellorthonormalizetriad( trial, triad )
133  call fstr_store_shell_triad_node( fstrsolid, node_id, triad, node_mode(node_id) )
134  end do
135 
136  deallocate( director_sum )
137  deallocate( tangent_sum )
138  deallocate( node_mode )
139  deallocate( node_count )
140  fstrsolid%finite_rotation_state_ready = .true.
141 
142  end subroutine fstr_ensure_finite_rotation_state
143 
146  subroutine fstr_begin_nodal_kinematics_step( hecMESH, fstrSOLID, ndof )
147  implicit none
148 
149  type (hecmwst_local_mesh), intent(in) :: hecmesh
150  type (fstr_solid), intent(inout) :: fstrsolid
151  integer(kind=kint), intent(in) :: ndof
152 
153  call fstr_ensure_finite_rotation_state( hecmesh, fstrsolid, ndof )
154  if( .not. associated(fstrsolid%shell_triad) ) return
155 
156  fstrsolid%shell_triad_bak(:) = fstrsolid%shell_triad(:)
157  fstrsolid%shell_drill_bak(:) = fstrsolid%shell_drill(:)
158  fstrsolid%shell_dtriad(:) = fstrsolid%shell_triad(:)
159  fstrsolid%shell_ddrill(:) = fstrsolid%shell_drill(:)
160 
161  end subroutine fstr_begin_nodal_kinematics_step
162 
168  subroutine fstr_apply_solution_increment( hecMESH, fstrSOLID, ndof, x )
170  implicit none
171 
172  type (hecmwst_local_mesh), intent(in) :: hecmesh
173  type (fstr_solid), intent(inout) :: fstrsolid
174  integer(kind=kint), intent(in) :: ndof
175  real(kind=kreal), intent(in) :: x(:)
176 
177  integer(kind=kint) :: node_id, idx, base
178  real(kind=kreal) :: theta_inc(3), theta_compat(3)
179  real(kind=kreal) :: triad_old(3, 3), triad_new(3, 3), drill_new
180 
181  if( .not. fstrsolid%has_finite_rotation_kinematics ) then
182  do node_id = 1, hecmesh%n_node
183  idx = ndof*(node_id-1)
184  fstrsolid%dunode(idx+1:idx+ndof) = fstrsolid%dunode(idx+1:idx+ndof) + x(idx+1:idx+ndof)
185  end do
186  return
187  endif
188  call fstr_ensure_finite_rotation_state( hecmesh, fstrsolid, ndof )
189  if( .not. associated(fstrsolid%shell_node_mode) ) then
190  do node_id = 1, hecmesh%n_node
191  idx = ndof*(node_id-1)
192  fstrsolid%dunode(idx+1:idx+ndof) = fstrsolid%dunode(idx+1:idx+ndof) + x(idx+1:idx+ndof)
193  end do
194  return
195  endif
196 
197  do node_id = 1, hecmesh%n_node
198  idx = ndof*(node_id-1)
199  if( fstrsolid%shell_node_mode(node_id) == 1 ) then
200  fstrsolid%dunode(idx+1:idx+3) = fstrsolid%dunode(idx+1:idx+3) + x(idx+1:idx+3)
201  theta_inc(1:3) = x(idx+4:idx+6)
202  base = 9*(node_id-1)
203  triad_old(1:3, 1) = fstrsolid%shell_dtriad(base+1:base+3)
204  triad_old(1:3, 2) = fstrsolid%shell_dtriad(base+4:base+6)
205  triad_old(1:3, 3) = fstrsolid%shell_dtriad(base+7:base+9)
206  call shellupdatetriadwithincrement( triad_old, fstrsolid%shell_ddrill(node_id), &
207  theta_inc, triad_new, drill_new )
208  fstrsolid%shell_dtriad(base+1:base+3) = triad_new(1:3, 1)
209  fstrsolid%shell_dtriad(base+4:base+6) = triad_new(1:3, 2)
210  fstrsolid%shell_dtriad(base+7:base+9) = triad_new(1:3, 3)
211  fstrsolid%shell_ddrill(node_id) = drill_new
212  ! update nodal rotation vector for output
213  call shellcomposerotationvector( fstrsolid%dunode(idx+4:idx+6), x(idx+4:idx+6), theta_compat )
214  fstrsolid%dunode(idx+4:idx+6) = theta_compat(1:3)
215  if( ndof > 6 ) then
216  fstrsolid%dunode(idx+7:idx+ndof) = fstrsolid%dunode(idx+7:idx+ndof) + x(idx+7:idx+ndof)
217  endif
218  else
219  fstrsolid%dunode(idx+1:idx+ndof) = fstrsolid%dunode(idx+1:idx+ndof) + x(idx+1:idx+ndof)
220  endif
221  end do
222 
223  end subroutine fstr_apply_solution_increment
224 
229  subroutine fstr_commit_solution_increment( hecMESH, fstrSOLID, ndof )
231  implicit none
232 
233  type (hecmwst_local_mesh), intent(in) :: hecmesh
234  type (fstr_solid), intent(inout) :: fstrsolid
235  integer(kind=kint), intent(in) :: ndof
236 
237  integer(kind=kint) :: node_id, idx, base
238  real(kind=kreal) :: theta_compat(3)
239 
240  if( .not. fstrsolid%has_finite_rotation_kinematics ) then
241  do node_id = 1, hecmesh%n_node
242  idx = ndof*(node_id-1)
243  fstrsolid%unode(idx+1:idx+ndof) = fstrsolid%unode(idx+1:idx+ndof) + fstrsolid%dunode(idx+1:idx+ndof)
244  end do
245  return
246  endif
247  call fstr_ensure_finite_rotation_state( hecmesh, fstrsolid, ndof )
248  if( .not. associated(fstrsolid%shell_node_mode) ) then
249  do node_id = 1, hecmesh%n_node
250  idx = ndof*(node_id-1)
251  fstrsolid%unode(idx+1:idx+ndof) = fstrsolid%unode(idx+1:idx+ndof) + fstrsolid%dunode(idx+1:idx+ndof)
252  end do
253  return
254  endif
255 
256  do node_id = 1, hecmesh%n_node
257  idx = ndof*(node_id-1)
258  if( fstrsolid%shell_node_mode(node_id) == 1 ) then
259  fstrsolid%unode(idx+1:idx+3) = fstrsolid%unode(idx+1:idx+3) + fstrsolid%dunode(idx+1:idx+3)
260  base = 9*(node_id-1)
261  fstrsolid%shell_triad(base+1:base+9) = fstrsolid%shell_dtriad(base+1:base+9)
262  fstrsolid%shell_drill(node_id) = fstrsolid%shell_ddrill(node_id)
263  ! update nodal rotation vector for output
264  call shellcomposerotationvector( fstrsolid%unode(idx+4:idx+6), fstrsolid%dunode(idx+4:idx+6), theta_compat )
265  fstrsolid%unode(idx+4:idx+6) = theta_compat(1:3)
266  if( ndof > 6 ) then
267  fstrsolid%unode(idx+7:idx+ndof) = fstrsolid%unode(idx+7:idx+ndof) + fstrsolid%dunode(idx+7:idx+ndof)
268  endif
269  else
270  fstrsolid%unode(idx+1:idx+ndof) = fstrsolid%unode(idx+1:idx+ndof) + fstrsolid%dunode(idx+1:idx+ndof)
271  endif
272  end do
273 
274  end subroutine fstr_commit_solution_increment
275 
277  subroutine fstr_get_shell_trial_directors( fstrSOLID, thick, nn, nodLOCAL, directors )
278  implicit none
279 
280  type (fstr_solid), intent(in) :: fstrsolid
281  real(kind=kreal), intent(in) :: thick
282  integer(kind=kint), intent(in) :: nn
283  integer(kind=kint), intent(in) :: nodlocal(:)
284  real(kind=kreal), intent(out) :: directors(3, nn)
285 
286  integer(kind=kint) :: j, node_id, base
287 
288  directors(:, :) = 0.0d0
289  if( .not. associated(fstrsolid%shell_dtriad) ) return
290 
291  do j = 1, nn
292  node_id = nodlocal(j)
293  if( node_id <= 0 .or. node_id > size(fstrsolid%shell_rot_state) ) cycle
294  base = 9*(node_id-1)
295  directors(1:3, j) = 0.5d0*thick*fstrsolid%shell_dtriad(base+7:base+9)
296  end do
297 
298  end subroutine fstr_get_shell_trial_directors
299 
301  subroutine fstr_get_shell_current_directors( fstrSOLID, thick, nn, nodLOCAL, directors )
302  implicit none
303 
304  type (fstr_solid), intent(in) :: fstrsolid
305  real(kind=kreal), intent(in) :: thick
306  integer(kind=kint), intent(in) :: nn
307  integer(kind=kint), intent(in) :: nodlocal(:)
308  real(kind=kreal), intent(out) :: directors(3, nn)
309 
310  integer(kind=kint) :: j, node_id, base
311 
312  directors(:, :) = 0.0d0
313  if( .not. associated(fstrsolid%shell_triad) ) return
314 
315  do j = 1, nn
316  node_id = nodlocal(j)
317  if( node_id <= 0 .or. node_id > size(fstrsolid%shell_rot_state) ) cycle
318  base = 9*(node_id-1)
319  directors(1:3, j) = 0.5d0*thick*fstrsolid%shell_triad(base+7:base+9)
320  end do
321 
322  end subroutine fstr_get_shell_current_directors
323 
325  subroutine fstr_get_shell_reference_directors( fstrSOLID, thick, nn, nodLOCAL, directors )
326  implicit none
327 
328  type (fstr_solid), intent(in) :: fstrsolid
329  real(kind=kreal), intent(in) :: thick
330  integer(kind=kint), intent(in) :: nn
331  integer(kind=kint), intent(in) :: nodlocal(:)
332  real(kind=kreal), intent(out) :: directors(3, nn)
333 
334  integer(kind=kint) :: j, node_id, base
335 
336  directors(:, :) = 0.0d0
337  if( .not. associated(fstrsolid%shell_ref_triad) ) return
338 
339  do j = 1, nn
340  node_id = nodlocal(j)
341  if( node_id <= 0 .or. node_id > size(fstrsolid%shell_rot_state) ) cycle
342  base = 9*(node_id-1)
343  directors(1:3, j) = 0.5d0*thick*fstrsolid%shell_ref_triad(base+7:base+9)
344  end do
345 
347 
348  ! ---------------------------------------------------------------------------
349  ! Private helpers: reference-frame construction at element nodes.
350  ! ---------------------------------------------------------------------------
351 
352  subroutine fstr_set_identity_triad( triad )
353  implicit none
354 
355  real(kind=kreal), intent(out) :: triad(3, 3)
356 
357  triad(:, :) = 0.0d0
358  triad(1, 1) = 1.0d0
359  triad(2, 2) = 1.0d0
360  triad(3, 3) = 1.0d0
361 
362  end subroutine fstr_set_identity_triad
363 
366  subroutine fstr_reference_shell_triad( nn, ecoord, inode, triad )
369  implicit none
370 
371  integer(kind=kint), intent(in) :: nn
372  integer(kind=kint), intent(in) :: inode
373  real(kind=kreal), intent(in) :: ecoord(3, nn)
374  real(kind=kreal), intent(out) :: triad(3, 3)
375 
376  real(kind=kreal) :: xi, eta
377  real(kind=kreal) :: shapederiv(4, 2)
378  real(kind=kreal) :: g1(3), g2(3), e0(3), trial(3, 3), normv
379  integer(kind=kint) :: i
380 
381  call fstr_set_identity_triad( trial )
382  if( nn /= 4 ) then
383  triad(1:3, 1:3) = trial(1:3, 1:3)
384  return
385  endif
386 
387  call getshapederiv( fe_mitc4_shell, (/ 0.0d0, 0.0d0 /), shapederiv )
388  e0(1:3) = 0.0d0
389  do i = 1, 4
390  e0(1:3) = e0(1:3) + shapederiv(i, 1)*ecoord(1:3, i)
391  end do
392 
393  select case( inode )
394  case( 1 )
395  xi = -1.0d0
396  eta = -1.0d0
397  case( 2 )
398  xi = 1.0d0
399  eta = -1.0d0
400  case( 3 )
401  xi = 1.0d0
402  eta = 1.0d0
403  case default
404  xi = -1.0d0
405  eta = 1.0d0
406  end select
407 
408  call getshapederiv( fe_mitc4_shell, (/ xi, eta /), shapederiv )
409  g1(1:3) = 0.0d0
410  g2(1:3) = 0.0d0
411  do i = 1, 4
412  g1(1:3) = g1(1:3) + shapederiv(i, 1)*ecoord(1:3, i)
413  g2(1:3) = g2(1:3) + shapederiv(i, 2)*ecoord(1:3, i)
414  end do
415 
416  trial(1, 3) = g1(2)*g2(3) - g1(3)*g2(2)
417  trial(2, 3) = g1(3)*g2(1) - g1(1)*g2(3)
418  trial(3, 3) = g1(1)*g2(2) - g1(2)*g2(1)
419 
420  trial(1, 2) = trial(2, 3)*e0(3) - trial(3, 3)*e0(2)
421  trial(2, 2) = trial(3, 3)*e0(1) - trial(1, 3)*e0(3)
422  trial(3, 2) = trial(1, 3)*e0(2) - trial(2, 3)*e0(1)
423  normv = dsqrt( dot_product( trial(1:3, 2), trial(1:3, 2) ) )
424  if( normv > 1.0d-14 ) trial(1:3, 2) = trial(1:3, 2)/normv
425 
426  trial(1, 1) = trial(2, 2)*trial(3, 3) - trial(3, 2)*trial(2, 3)
427  trial(2, 1) = trial(3, 2)*trial(1, 3) - trial(1, 2)*trial(3, 3)
428  trial(3, 1) = trial(1, 2)*trial(2, 3) - trial(2, 2)*trial(1, 3)
429 
430  call shellorthonormalizetriad( trial, triad )
431 
432  end subroutine fstr_reference_shell_triad
433 
435  subroutine fstr_store_shell_triad_node( fstrSOLID, node_id, triad, mode )
436  implicit none
437 
438  type (fstr_solid), intent(inout) :: fstrSOLID
439  integer(kind=kint), intent(in) :: node_id, mode
440  real(kind=kreal), intent(in) :: triad(3, 3)
441 
442  integer(kind=kint) :: base
443 
444  if( node_id <= 0 ) return
445  if( node_id > size(fstrsolid%shell_rot_state) ) return
446  if( fstrsolid%shell_rot_state(node_id) /= 0 ) return
447 
448  base = 9*(node_id-1)
449  fstrsolid%shell_rot_state(node_id) = mode
450  ! initialize reference and current shell triads
451  fstrsolid%shell_ref_triad(base+1:base+3) = triad(1:3, 1)
452  fstrsolid%shell_ref_triad(base+4:base+6) = triad(1:3, 2)
453  fstrsolid%shell_ref_triad(base+7:base+9) = triad(1:3, 3)
454  fstrsolid%shell_triad(base+1:base+3) = triad(1:3, 1)
455  fstrsolid%shell_triad(base+4:base+6) = triad(1:3, 2)
456  fstrsolid%shell_triad(base+7:base+9) = triad(1:3, 3)
457  fstrsolid%shell_triad_bak(base+1:base+9) = fstrsolid%shell_triad(base+1:base+9)
458  fstrsolid%shell_dtriad(base+1:base+9) = fstrsolid%shell_triad(base+1:base+9)
459  fstrsolid%shell_drill(node_id) = 0.0d0
460  fstrsolid%shell_drill_bak(node_id) = 0.0d0
461  fstrsolid%shell_ddrill(node_id) = 0.0d0
462 
463  end subroutine fstr_store_shell_triad_node
464 
465 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:578
integer, parameter fe_mitc4_shell
Definition: element.f90:94
Shared predicates for finite-rotation nodal kinematics.
logical function, public fstr_uses_finite_rotation_kinematics(etype, nn, material)
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, public fstr_get_shell_trial_directors(fstrSOLID, thick, nn, nodLOCAL, directors)
Half-thickness director from the current Newton trial frame (dtriad).
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.
subroutine, public fstr_get_shell_current_directors(fstrSOLID, thick, nn, nodLOCAL, directors)
Half-thickness director from the converged frame (triad).
subroutine, public fstr_get_shell_reference_directors(fstrSOLID, thick, nn, nodLOCAL, directors)
Half-thickness director from the fixed reference frame (ref_triad).
This module defines common data and basic structures for analysis.
Definition: m_fstr.F90:15
This module ...
pure subroutine shellorthonormalizetriad(triad_in, triad_out)
pure subroutine shellcomposerotationvector(theta_old, theta_inc, theta_new)
pure subroutine shellupdatetriadwithincrement(triad_old, drill_old, theta_inc, triad_new, drill_new)