FrontISTR  5.9.0
Large-scale structural analysis program with finit element method
fstr_FiniteRotationKinematics.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 !-------------------------------------------------------------------------------
6 
8  use hecmw
9  use elementinfo, only: fe_mitc4_shell
10  use m_fstr, only: fstr_solid
12  implicit none
13 
14  private
15 
22  public :: shellskewmatrix
24  public :: shellorthonormalizetriad
27 
28 contains
29 
30  logical function fstr_is_finite_rotation_shell_element( etype, nn )
31  integer(kind=kint), intent(in) :: etype
32  integer(kind=kint), intent(in) :: nn
33 
36 
37  logical function fstr_uses_finite_rotation_kinematics( etype, nn, material )
38  integer(kind=kint), intent(in) :: etype
39  integer(kind=kint), intent(in) :: nn
40  type(tmaterial), intent(in) :: material
41 
43  .and. ( material%nlgeom_flag == totallag .or. material%nlgeom_flag == updatelag ) &
44  .and. iselastic( material%mtype ) )
46 
47  logical function fstr_has_finite_rotation_kinematics( hecMESH, fstrSOLID )
49  type (hecmwst_local_mesh), intent(in) :: hecmesh
50  type (fstr_solid), intent(in) :: fstrsolid
51 
52  integer(kind=kint) :: itype, is, ie, ic_type, icel, iis, nn
53  logical :: local_has_finite_rotation_kinematics
54 
55  local_has_finite_rotation_kinematics = .false.
56  if( hecmesh%n_dof >= 6 .and. associated( fstrsolid%elements ) ) then
57  element_type_loop: do itype = 1, hecmesh%n_elem_type
58  is = hecmesh%elem_type_index(itype-1) + 1
59  ie = hecmesh%elem_type_index(itype)
60  ic_type = hecmesh%elem_type_item(itype)
61  if( ic_type /= fe_mitc4_shell ) cycle
62 
63  do icel = is, ie
64  iis = hecmesh%elem_node_index(icel-1)
65  nn = hecmesh%elem_node_index(icel) - iis
66  if( .not. associated( fstrsolid%elements(icel)%gausses ) ) cycle
67  if( fstr_uses_finite_rotation_kinematics( ic_type, nn, &
68  fstrsolid%elements(icel)%gausses(1)%pMaterial ) ) then
69  local_has_finite_rotation_kinematics = .true.
70  exit element_type_loop
71  endif
72  end do
73  end do element_type_loop
74  endif
75 
76  ! Keep allocation and communication paths rank-uniform. Ranks without a
77  ! local finite-rotation shell element must still participate in shell state
78  ! communication when another rank contains one.
79  call hecmw_allreduce_l1( hecmesh, local_has_finite_rotation_kinematics, hecmw_lor )
80  fstr_has_finite_rotation_kinematics = local_has_finite_rotation_kinematics
82 
83  subroutine fstr_mark_finite_rotation_nodes( hecMESH, fstrSOLID, ndof, shell_node_mode )
84  type (hecmwst_local_mesh), intent(in) :: hecmesh
85  type (fstr_solid), intent(in) :: fstrsolid
86  integer(kind=kint), intent(in) :: ndof
87  integer(kind=kint), intent(out) :: shell_node_mode(:)
88 
89  integer(kind=kint) :: itype, is, ie, ic_type, icel, iis, nn, j, node_id
90 
91  shell_node_mode(:) = 0
92  if( ndof < 6 ) return
93  if( .not. associated( fstrsolid%elements ) ) return
94 
95  do itype = 1, hecmesh%n_elem_type
96  is = hecmesh%elem_type_index(itype-1) + 1
97  ie = hecmesh%elem_type_index(itype)
98  ic_type = hecmesh%elem_type_item(itype)
99  if( ic_type /= fe_mitc4_shell ) cycle
100 
101  do icel = is, ie
102  iis = hecmesh%elem_node_index(icel-1)
103  nn = hecmesh%elem_node_index(icel) - iis
104  if( .not. associated( fstrsolid%elements(icel)%gausses ) ) cycle
105  if( .not. fstr_uses_finite_rotation_kinematics( ic_type, nn, &
106  fstrsolid%elements(icel)%gausses(1)%pMaterial ) ) cycle
107 
108  do j = 1, nn
109  node_id = hecmesh%elem_node_item(iis+j)
110  if( node_id > 0 .and. node_id <= size(shell_node_mode) ) shell_node_mode(node_id) = 1
111  end do
112  end do
113  end do
114  end subroutine fstr_mark_finite_rotation_nodes
115 
116  pure subroutine shellrotationvectortomatrix(theta, rotmat)
117  real(kind=kreal), intent(in) :: theta(3)
118  real(kind=kreal), intent(out) :: rotmat(3, 3)
119 
120  integer :: i
121  real(kind=kreal) :: theta_norm, theta_norm2
122  real(kind=kreal) :: sin_over_theta, one_minus_cos_over_theta2
123  real(kind=kreal) :: skew(3, 3), skew2(3, 3)
124 
125  theta_norm2 = dot_product(theta, theta)
126  theta_norm = dsqrt(theta_norm2)
127  skew = shellskewmatrix(theta)
128  skew2 = matmul(skew, skew)
129 
130  if (theta_norm < 1.0d-12) then
131  sin_over_theta = 1.0d0-theta_norm2/6.0d0+theta_norm2*theta_norm2/120.0d0
132  one_minus_cos_over_theta2 = 0.5d0-theta_norm2/24.0d0+theta_norm2*theta_norm2/720.0d0
133  else
134  sin_over_theta = dsin(theta_norm)/theta_norm
135  one_minus_cos_over_theta2 = (1.0d0-dcos(theta_norm))/theta_norm2
136  endif
137 
138  rotmat = sin_over_theta*skew+one_minus_cos_over_theta2*skew2
139  do i = 1, 3
140  rotmat(i, i) = rotmat(i, i)+1.0d0
141  end do
142  end subroutine shellrotationvectortomatrix
143 
144  pure subroutine shellrotationmatrixtovector(rotmat, theta)
145  real(kind=kreal), intent(in) :: rotmat(3, 3)
146  real(kind=kreal), intent(out) :: theta(3)
147 
148  real(kind=kreal) :: pi, trace_r, cos_angle, angle, sin_angle
149  real(kind=kreal) :: axis(3), axis_abs
150 
151  pi = 4.0d0*datan(1.0d0)
152  trace_r = rotmat(1, 1)+rotmat(2, 2)+rotmat(3, 3)
153  cos_angle = max(-1.0d0, min(1.0d0, 0.5d0*(trace_r-1.0d0)))
154  angle = dacos(cos_angle)
155 
156  theta(1) = rotmat(3, 2)-rotmat(2, 3)
157  theta(2) = rotmat(1, 3)-rotmat(3, 1)
158  theta(3) = rotmat(2, 1)-rotmat(1, 2)
159 
160  if (angle < 1.0d-12) then
161  theta = 0.5d0*theta
162  else if (pi-angle < 1.0d-8) then
163  axis(1) = dsqrt(max(0.0d0, 0.5d0*(rotmat(1, 1)+1.0d0)))
164  axis(2) = dsqrt(max(0.0d0, 0.5d0*(rotmat(2, 2)+1.0d0)))
165  axis(3) = dsqrt(max(0.0d0, 0.5d0*(rotmat(3, 3)+1.0d0)))
166  if (rotmat(2, 1)+rotmat(1, 2) < 0.0d0) axis(2) = -axis(2)
167  if (rotmat(3, 1)+rotmat(1, 3) < 0.0d0) axis(3) = -axis(3)
168  axis_abs = dsqrt(dot_product(axis, axis))
169  if (axis_abs > 1.0d-12) then
170  theta = angle*axis/axis_abs
171  else
172  theta = 0.0d0
173  endif
174  else
175  sin_angle = dsin(angle)
176  theta = angle*theta/(2.0d0*sin_angle)
177  endif
178  end subroutine shellrotationmatrixtovector
179 
180  pure function shellskewmatrix(vector) result(matrix)
181  real(kind=kreal), intent(in) :: vector(3)
182  real(kind=kreal) :: matrix(3, 3)
183 
184  matrix = 0.0d0
185  matrix(1, 2) = -vector(3)
186  matrix(1, 3) = vector(2)
187  matrix(2, 1) = vector(3)
188  matrix(2, 3) = -vector(1)
189  matrix(3, 1) = -vector(2)
190  matrix(3, 2) = vector(1)
191  end function shellskewmatrix
192 
193  pure subroutine shellcomposerotationvector(theta_old, theta_inc, theta_new)
194  real(kind=kreal), intent(in) :: theta_old(3), theta_inc(3)
195  real(kind=kreal), intent(out) :: theta_new(3)
196 
197  real(kind=kreal) :: rot_old(3, 3), rot_inc(3, 3), rot_new(3, 3)
198 
199  call shellrotationvectortomatrix(theta_old, rot_old)
200  call shellrotationvectortomatrix(theta_inc, rot_inc)
201  rot_new = matmul(rot_inc, rot_old)
202  call shellrotationmatrixtovector(rot_new, theta_new)
203  end subroutine shellcomposerotationvector
204 
205 
206  pure subroutine shellorthonormalizetriad(triad_in, triad_out)
207  real(kind=kreal), intent(in) :: triad_in(3, 3)
208  real(kind=kreal), intent(out) :: triad_out(3, 3)
209 
210  real(kind=kreal) :: e1(3), e2(3), e3(3), normv
211 
212  e1 = triad_in(:, 1)
213  e3 = triad_in(:, 3)
214  normv = dsqrt(dot_product(e3, e3))
215  if (normv < 1.0d-14) then
216  e3 = (/ 0.0d0, 0.0d0, 1.0d0 /)
217  else
218  e3 = e3/normv
219  endif
220 
221  e1 = e1-dot_product(e1, e3)*e3
222  normv = dsqrt(dot_product(e1, e1))
223  if (normv < 1.0d-14) then
224  if (dabs(e3(1)) < 0.9d0) then
225  e1 = (/ 1.0d0, 0.0d0, 0.0d0 /)
226  else
227  e1 = (/ 0.0d0, 1.0d0, 0.0d0 /)
228  endif
229  e1 = e1-dot_product(e1, e3)*e3
230  normv = dsqrt(dot_product(e1, e1))
231  endif
232  e1 = e1/normv
233  e2(1) = e3(2)*e1(3)-e3(3)*e1(2)
234  e2(2) = e3(3)*e1(1)-e3(1)*e1(3)
235  e2(3) = e3(1)*e1(2)-e3(2)*e1(1)
236 
237  triad_out(:, 1) = e1
238  triad_out(:, 2) = e2
239  triad_out(:, 3) = e3
240  end subroutine shellorthonormalizetriad
241 
242  pure subroutine shellupdatetriadwithincrement(triad_old, drill_old, theta_inc, triad_new, drill_new)
243  real(kind=kreal), intent(in) :: triad_old(3, 3), drill_old, theta_inc(3)
244  real(kind=kreal), intent(out) :: triad_new(3, 3), drill_new
245 
246  integer :: isub, nsub
247  real(kind=kreal) :: triad_base(3, 3)
248  real(kind=kreal) :: director(3), theta_step(3), theta_phys(3)
249  real(kind=kreal) :: drill_acc, drill_inc, theta_norm
250  real(kind=kreal) :: rot_inc(3, 3), rot_full(3, 3), triad_trial(3, 3)
251 
252  call shellorthonormalizetriad(triad_old, triad_base)
253  theta_norm = dsqrt(dot_product(theta_inc, theta_inc))
254  nsub = max(1, ceiling(theta_norm/5.0d-2))
255  theta_step = theta_inc/dble(nsub)
256  drill_acc = drill_old
257 
258  do isub = 1, nsub
259  director = triad_base(:, 3)
260  drill_inc = dot_product(theta_step, director)
261  theta_phys = theta_step-drill_inc*director
262  call shellrotationvectortomatrix(theta_phys, rot_inc)
263  triad_trial = matmul(rot_inc, triad_base)
264  call shellorthonormalizetriad(triad_trial, triad_base)
265  drill_acc = drill_acc+drill_inc
266  end do
267 
268  call shellrotationvectortomatrix(theta_inc, rot_full)
269  triad_trial = triad_base
270  triad_trial(:, 3) = matmul(rot_full, triad_old(:, 3))
271  call shellorthonormalizetriad(triad_trial, triad_new)
272  drill_new = drill_acc
273  end subroutine shellupdatetriadwithincrement
274 
275  pure subroutine shellcomposenodaldisplacement(ndof, nn, disp_old, disp_inc, disp_new)
276  integer(kind=kint), intent(in) :: ndof, nn
277  real(kind=kreal), intent(in) :: disp_old(:, :), disp_inc(:, :)
278  real(kind=kreal), intent(out) :: disp_new(6, nn)
279 
280  integer :: i, ndof_copy
281 
282  disp_new = 0.0d0
283  ndof_copy = min(ndof, 6)
284  do i = 1, nn
285  disp_new(1:min(3, ndof_copy), i) = disp_old(1:min(3, ndof_copy), i)+disp_inc(1:min(3, ndof_copy), i)
286  if (ndof_copy >= 6) then
287  call shellcomposerotationvector(disp_old(4:6, i), disp_inc(4:6, i), disp_new(4:6, i))
288  else if (ndof_copy > 3) then
289  disp_new(4:ndof_copy, i) = disp_old(4:ndof_copy, i)+disp_inc(4:ndof_copy, i)
290  endif
291  end do
292  end subroutine shellcomposenodaldisplacement
293 
This module encapsulate the basic functions of all elements provide by this software.
Definition: element.f90:43
integer, parameter fe_mitc4_shell
Definition: element.f90:95
Definition: hecmw.f90:6
Shared finite-rotation nodal kinematics and rotation algebra.
logical function, public fstr_is_finite_rotation_shell_element(etype, nn)
pure subroutine, public shellrotationvectortomatrix(theta, rotmat)
pure subroutine, public shellorthonormalizetriad(triad_in, triad_out)
logical function, public fstr_has_finite_rotation_kinematics(hecMESH, fstrSOLID)
pure real(kind=kreal) function, dimension(3, 3), public shellskewmatrix(vector)
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 shellcomposenodaldisplacement(ndof, nn, disp_old, disp_inc, disp_new)
pure subroutine, public shellcomposerotationvector(theta_old, theta_inc, theta_new)
subroutine, public fstr_mark_finite_rotation_nodes(hecMESH, fstrSOLID, ndof, shell_node_mode)
pure subroutine, public shellrotationmatrixtovector(rotmat, theta)
This module defines common data and basic structures for analysis.
Definition: m_fstr.F90:15
subroutine hecmw_allreduce_l1(hecMESH, flag, ntag)
This module summarizes all information of material properties.
Definition: material.f90:6
integer(kind=kint), parameter totallag
Definition: material.f90:14
logical function iselastic(mtype)
If it is an elastic material?
Definition: material.f90:324
integer(kind=kint), parameter updatelag
Definition: material.f90:15
Structure to manage all material related data.
Definition: material.f90:166