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  fstrsolid%finite_rotation_state_ready = .true.
130 
131  end subroutine fstr_ensure_finite_rotation_state
132 
135  subroutine fstr_begin_nodal_kinematics_step( hecMESH, fstrSOLID, ndof )
136  implicit none
137 
138  type (hecmwst_local_mesh), intent(in) :: hecmesh
139  type (fstr_solid), intent(inout) :: fstrsolid
140  integer(kind=kint), intent(in) :: ndof
141 
142  call fstr_ensure_finite_rotation_state( hecmesh, fstrsolid, ndof )
143  if( .not. associated(fstrsolid%shell_triad) ) return
144 
145  fstrsolid%shell_triad_bak(:) = fstrsolid%shell_triad(:)
146  fstrsolid%shell_drill_bak(:) = fstrsolid%shell_drill(:)
147  fstrsolid%shell_dtriad(:) = fstrsolid%shell_triad(:)
148  fstrsolid%shell_ddrill(:) = fstrsolid%shell_drill(:)
149 
150  end subroutine fstr_begin_nodal_kinematics_step
151 
157  subroutine fstr_apply_solution_increment( hecMESH, fstrSOLID, ndof, x )
158  implicit none
159 
160  type (hecmwst_local_mesh), intent(in) :: hecmesh
161  type (fstr_solid), intent(inout) :: fstrsolid
162  integer(kind=kint), intent(in) :: ndof
163  real(kind=kreal), intent(in) :: x(:)
164 
165  integer(kind=kint) :: node_id, idx, base
166  real(kind=kreal) :: theta_inc(3), theta_compat(3)
167  real(kind=kreal) :: triad_old(3, 3), triad_new(3, 3), drill_new
168 
169  if( .not. fstrsolid%has_finite_rotation_kinematics ) then
170  do node_id = 1, hecmesh%n_node
171  idx = ndof*(node_id-1)
172  fstrsolid%dunode(idx+1:idx+ndof) = fstrsolid%dunode(idx+1:idx+ndof) + x(idx+1:idx+ndof)
173  end do
174  return
175  endif
176  call fstr_ensure_finite_rotation_state( hecmesh, fstrsolid, ndof )
177  if( .not. associated(fstrsolid%shell_node_mode) ) then
178  do node_id = 1, hecmesh%n_node
179  idx = ndof*(node_id-1)
180  fstrsolid%dunode(idx+1:idx+ndof) = fstrsolid%dunode(idx+1:idx+ndof) + x(idx+1:idx+ndof)
181  end do
182  return
183  endif
184 
185  do node_id = 1, hecmesh%n_node
186  idx = ndof*(node_id-1)
187  if( fstrsolid%shell_node_mode(node_id) == 1 ) then
188  fstrsolid%dunode(idx+1:idx+3) = fstrsolid%dunode(idx+1:idx+3) + x(idx+1:idx+3)
189  theta_inc(1:3) = x(idx+4:idx+6)
190  base = 9*(node_id-1)
191  triad_old(1:3, 1) = fstrsolid%shell_dtriad(base+1:base+3)
192  triad_old(1:3, 2) = fstrsolid%shell_dtriad(base+4:base+6)
193  triad_old(1:3, 3) = fstrsolid%shell_dtriad(base+7:base+9)
194  call shellupdatetriadwithincrement( triad_old, fstrsolid%shell_ddrill(node_id), &
195  theta_inc, triad_new, drill_new )
196  fstrsolid%shell_dtriad(base+1:base+3) = triad_new(1:3, 1)
197  fstrsolid%shell_dtriad(base+4:base+6) = triad_new(1:3, 2)
198  fstrsolid%shell_dtriad(base+7:base+9) = triad_new(1:3, 3)
199  fstrsolid%shell_ddrill(node_id) = drill_new
200  ! update nodal rotation vector for output
201  call shellcomposerotationvector( fstrsolid%dunode(idx+4:idx+6), x(idx+4:idx+6), theta_compat )
202  fstrsolid%dunode(idx+4:idx+6) = theta_compat(1:3)
203  if( ndof > 6 ) then
204  fstrsolid%dunode(idx+7:idx+ndof) = fstrsolid%dunode(idx+7:idx+ndof) + x(idx+7:idx+ndof)
205  endif
206  else
207  fstrsolid%dunode(idx+1:idx+ndof) = fstrsolid%dunode(idx+1:idx+ndof) + x(idx+1:idx+ndof)
208  endif
209  end do
210 
211  end subroutine fstr_apply_solution_increment
212 
217  subroutine fstr_commit_solution_increment( hecMESH, fstrSOLID, ndof )
218  implicit none
219 
220  type (hecmwst_local_mesh), intent(in) :: hecmesh
221  type (fstr_solid), intent(inout) :: fstrsolid
222  integer(kind=kint), intent(in) :: ndof
223 
224  integer(kind=kint) :: node_id, idx, base
225  real(kind=kreal) :: theta_compat(3)
226 
227  if( .not. fstrsolid%has_finite_rotation_kinematics ) then
228  do node_id = 1, hecmesh%n_node
229  idx = ndof*(node_id-1)
230  fstrsolid%unode(idx+1:idx+ndof) = fstrsolid%unode(idx+1:idx+ndof) + fstrsolid%dunode(idx+1:idx+ndof)
231  end do
232  return
233  endif
234  call fstr_ensure_finite_rotation_state( hecmesh, fstrsolid, ndof )
235  if( .not. associated(fstrsolid%shell_node_mode) ) then
236  do node_id = 1, hecmesh%n_node
237  idx = ndof*(node_id-1)
238  fstrsolid%unode(idx+1:idx+ndof) = fstrsolid%unode(idx+1:idx+ndof) + fstrsolid%dunode(idx+1:idx+ndof)
239  end do
240  return
241  endif
242 
243  do node_id = 1, hecmesh%n_node
244  idx = ndof*(node_id-1)
245  if( fstrsolid%shell_node_mode(node_id) == 1 ) then
246  fstrsolid%unode(idx+1:idx+3) = fstrsolid%unode(idx+1:idx+3) + fstrsolid%dunode(idx+1:idx+3)
247  base = 9*(node_id-1)
248  fstrsolid%shell_triad(base+1:base+9) = fstrsolid%shell_dtriad(base+1:base+9)
249  fstrsolid%shell_drill(node_id) = fstrsolid%shell_ddrill(node_id)
250  ! update nodal rotation vector for output
251  call shellcomposerotationvector( fstrsolid%unode(idx+4:idx+6), fstrsolid%dunode(idx+4:idx+6), theta_compat )
252  fstrsolid%unode(idx+4:idx+6) = theta_compat(1:3)
253  if( ndof > 6 ) then
254  fstrsolid%unode(idx+7:idx+ndof) = fstrsolid%unode(idx+7:idx+ndof) + fstrsolid%dunode(idx+7:idx+ndof)
255  endif
256  else
257  fstrsolid%unode(idx+1:idx+ndof) = fstrsolid%unode(idx+1:idx+ndof) + fstrsolid%dunode(idx+1:idx+ndof)
258  endif
259  end do
260 
261  end subroutine fstr_commit_solution_increment
262 
263  ! ---------------------------------------------------------------------------
264  ! Private helpers: reference-frame construction at element nodes.
265  ! ---------------------------------------------------------------------------
266 
267  subroutine fstr_set_identity_triad( triad )
268  implicit none
269 
270  real(kind=kreal), intent(out) :: triad(3, 3)
271 
272  triad(:, :) = 0.0d0
273  triad(1, 1) = 1.0d0
274  triad(2, 2) = 1.0d0
275  triad(3, 3) = 1.0d0
276 
277  end subroutine fstr_set_identity_triad
278 
281  subroutine fstr_reference_shell_triad( nn, ecoord, inode, triad )
283  implicit none
284 
285  integer(kind=kint), intent(in) :: nn
286  integer(kind=kint), intent(in) :: inode
287  real(kind=kreal), intent(in) :: ecoord(3, nn)
288  real(kind=kreal), intent(out) :: triad(3, 3)
289 
290  real(kind=kreal) :: xi, eta
291  real(kind=kreal) :: shapederiv(4, 2)
292  real(kind=kreal) :: g1(3), g2(3), e0(3), trial(3, 3), normv
293  integer(kind=kint) :: i
294 
295  call fstr_set_identity_triad( trial )
296  if( nn /= 4 ) then
297  triad(1:3, 1:3) = trial(1:3, 1:3)
298  return
299  endif
300 
301  call getshapederiv( fe_mitc4_shell, (/ 0.0d0, 0.0d0 /), shapederiv )
302  e0(1:3) = 0.0d0
303  do i = 1, 4
304  e0(1:3) = e0(1:3) + shapederiv(i, 1)*ecoord(1:3, i)
305  end do
306 
307  select case( inode )
308  case( 1 )
309  xi = -1.0d0
310  eta = -1.0d0
311  case( 2 )
312  xi = 1.0d0
313  eta = -1.0d0
314  case( 3 )
315  xi = 1.0d0
316  eta = 1.0d0
317  case default
318  xi = -1.0d0
319  eta = 1.0d0
320  end select
321 
322  call getshapederiv( fe_mitc4_shell, (/ xi, eta /), shapederiv )
323  g1(1:3) = 0.0d0
324  g2(1:3) = 0.0d0
325  do i = 1, 4
326  g1(1:3) = g1(1:3) + shapederiv(i, 1)*ecoord(1:3, i)
327  g2(1:3) = g2(1:3) + shapederiv(i, 2)*ecoord(1:3, i)
328  end do
329 
330  trial(1, 3) = g1(2)*g2(3) - g1(3)*g2(2)
331  trial(2, 3) = g1(3)*g2(1) - g1(1)*g2(3)
332  trial(3, 3) = g1(1)*g2(2) - g1(2)*g2(1)
333 
334  trial(1, 2) = trial(2, 3)*e0(3) - trial(3, 3)*e0(2)
335  trial(2, 2) = trial(3, 3)*e0(1) - trial(1, 3)*e0(3)
336  trial(3, 2) = trial(1, 3)*e0(2) - trial(2, 3)*e0(1)
337  normv = dsqrt( dot_product( trial(1:3, 2), trial(1:3, 2) ) )
338  if( normv > 1.0d-14 ) trial(1:3, 2) = trial(1:3, 2)/normv
339 
340  trial(1, 1) = trial(2, 2)*trial(3, 3) - trial(3, 2)*trial(2, 3)
341  trial(2, 1) = trial(3, 2)*trial(1, 3) - trial(1, 2)*trial(3, 3)
342  trial(3, 1) = trial(1, 2)*trial(2, 3) - trial(2, 2)*trial(1, 3)
343 
344  call shellorthonormalizetriad( trial, triad )
345 
346  end subroutine fstr_reference_shell_triad
347 
349  subroutine fstr_store_shell_triad_node( fstrSOLID, node_id, triad, mode )
350  implicit none
351 
352  type (fstr_solid), intent(inout) :: fstrSOLID
353  integer(kind=kint), intent(in) :: node_id, mode
354  real(kind=kreal), intent(in) :: triad(3, 3)
355 
356  integer(kind=kint) :: base
357 
358  if( node_id <= 0 ) return
359  if( node_id > size(fstrsolid%shell_rot_state) ) return
360  if( fstrsolid%shell_rot_state(node_id) /= 0 ) return
361 
362  base = 9*(node_id-1)
363  fstrsolid%shell_rot_state(node_id) = mode
364  ! initialize reference and current shell triads
365  fstrsolid%shell_ref_triad(base+1:base+3) = triad(1:3, 1)
366  fstrsolid%shell_ref_triad(base+4:base+6) = triad(1:3, 2)
367  fstrsolid%shell_ref_triad(base+7:base+9) = triad(1:3, 3)
368  fstrsolid%shell_triad(base+1:base+3) = triad(1:3, 1)
369  fstrsolid%shell_triad(base+4:base+6) = triad(1:3, 2)
370  fstrsolid%shell_triad(base+7:base+9) = triad(1:3, 3)
371  fstrsolid%shell_triad_bak(base+1:base+9) = fstrsolid%shell_triad(base+1:base+9)
372  fstrsolid%shell_dtriad(base+1:base+9) = fstrsolid%shell_triad(base+1:base+9)
373  fstrsolid%shell_drill(node_id) = 0.0d0
374  fstrsolid%shell_drill_bak(node_id) = 0.0d0
375  fstrsolid%shell_ddrill(node_id) = 0.0d0
376 
377  end subroutine fstr_store_shell_triad_node
378 
379 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:627
integer, parameter fe_mitc4_shell
Definition: element.f90:94
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