xc
ASDShellQ4CorotationalTransformation.h
1 /* ****************************************************************** **
2 ** OpenSees - Open System for Earthquake Engineering Simulation **
3 ** Pacific Earthquake Engineering Research Center **
4 ** **
5 ** **
6 ** (C) Copyright 1999, The Regents of the University of California **
7 ** All Rights Reserved. **
8 ** **
9 ** Commercial use of this program without express permission of the **
10 ** University of California, Berkeley, is strictly prohibited. See **
11 ** file 'COPYRIGHT' in main directory for information on usage and **
12 ** redistribution, and for a DISCLAIMER OF ALL WARRANTIES. **
13 ** **
14 ** Developed by: **
15 ** Frank McKenna (fmckenna@ce.berkeley.edu) **
16 ** Gregory L. Fenves (fenves@ce.berkeley.edu) **
17 ** Filip C. Filippou (filippou@ce.berkeley.edu) **
18 ** **
19 ** ****************************************************************** */
20 
21 // $Revision: 1.10 $
22 // $Date: 2020/05/18 22:51:21 $
23 
24 // Original implementation: Massimo Petracca (ASDEA)
25 //
26 // Implementation of a corotational coordinate transformation 4-node shells
27 //
28 
29 #ifndef ASDShellQ4CorotationalTransformation_h
30 #define ASDShellQ4CorotationalTransformation_h
31 
32 #include "ASDEICR.h"
33 #include "ASDShellQ4Transformation.h"
34 
35 namespace XC {
36 
37 // this is experimental: it fits the corotational frame following the polar
38 // decomposition rather than the 1-2 side allignement as per Felippa's work
39 #define USE_POLAR_DECOMP_ALLIGN
40 
67  {
68  private:
69  QuaternionType m_Q0;
70  Vector3Type m_C0;
71  std::array<QuaternionType, 4> m_QN;
72  std::array<Vector3Type, 4> m_RV;
73  std::array<QuaternionType, 4> m_QN_converged;
74  std::array<Vector3Type, 4> m_RV_converged;
75  public:
76 
79 
80  virtual ~ASDShellQ4CorotationalTransformation(void) {}
81 
82  virtual ASDShellQ4Transformation *getCopy(void) const;
83 
84  virtual bool isLinear() const
85  { return false; }
86 
87  virtual void revertToStart(void);
88  virtual void setDomain(Domain* domain, const ID& node_ids, bool initialized);
89 
90  virtual void revertToLastCommit()
91  {
92  for (int i = 0; i < 4; i++)
93  {
94  m_RV[i] = m_RV_converged[i];
95  m_QN[i] = m_QN_converged[i];
96  }
97  }
98 
99  virtual void commit()
100  {
101  for (int i = 0; i < 4; i++)
102  {
103  m_RV_converged[i] = m_RV[i];
104  m_QN_converged[i] = m_QN[i];
105  }
106  }
107 
108  virtual void update(const VectorType& globalDisplacements)
109  {
110  for (int i = 0; i < 4; i++)
111  {
112  // compute current rotation vector removing initial rotations if any
113  Vector3Type currentRotVec;
114  int index = i * 6;
115  currentRotVec(0) = globalDisplacements(index + 3) - m_U0(index + 3);
116  currentRotVec(1) = globalDisplacements(index + 4) - m_U0(index + 4);
117  currentRotVec(2) = globalDisplacements(index + 5) - m_U0(index + 5);
118 
119  // compute incremental rotation vector
120  Vector3Type incrementalRotation = currentRotVec - m_RV[i];
121 
122  // save current rotation vector
123  m_RV[i] = currentRotVec;
124 
125  // compute incremental quaternion from incremental rotation vector
126  QuaternionType incrementalQuaternion = QuaternionType::FromRotationVector(incrementalRotation);
127 
128  // update nodal quaternion
129  m_QN[i] = incrementalQuaternion * m_QN[i];
130  }
131  }
132 
133  virtual ASDShellQ4LocalCoordinateSystem createLocalCoordinateSystem(const VectorType& globalDisplacements)const
134  {
135  // reference coordinate system
136  ASDShellQ4LocalCoordinateSystem a = createReferenceCoordinateSystem();
137 
138  // compute nodal positions at current configuration removing intial displacements if any
139  std::array<Vector3Type, 4> def =
140  {
141  Vector3Type(m_nodes[0]->getCrds()),
142  Vector3Type(m_nodes[1]->getCrds()),
143  Vector3Type(m_nodes[2]->getCrds()),
144  Vector3Type(m_nodes[3]->getCrds())
145  };
146  for (int i = 0; i < 4; i++)
147  {
148  int index = i * 6;
149  Vector3Type& iP = def[i];
150  iP(0) += globalDisplacements(index) - m_U0(index);
151  iP(1) += globalDisplacements(index + 1) - m_U0(index + 1);
152  iP(2) += globalDisplacements(index + 2) - m_U0(index + 2);
153  }
154 
155  // current coordinate system
156  ASDShellQ4LocalCoordinateSystem b(def[0], def[1], def[2], def[3]);
157 
158 #ifndef USE_POLAR_DECOMP_ALLIGN
159  return b;
160 #endif // !USE_POLAR_DECOMP_ALLIGN
161 
162  double aX1 = a.X1(); double aY1 = a.Y1();
163  double bX1 = b.X1(); double bY1 = b.Y1();
164  double aX2 = a.X2(); double aY2 = a.Y2();
165  double bX2 = b.X2(); double bY2 = b.Y2();
166  double aX3 = a.X3(); double aY3 = a.Y3();
167  double bX3 = b.X3(); double bY3 = b.Y3();
168  double aX4 = a.X4(); double aY4 = a.Y4();
169  double bX4 = b.X4(); double bY4 = b.Y4();
170 
171  // now we are in the local coordinate systems (reference and current), i.e. we are looking in the local Z direction
172  // which is the same for both coordinate systems.
173  // now we can compute the 2D deformation gradient between the 2 configurations, at the element center.
174 
175  double C1 = 1.0 / (aX1 * aY2 - aX2 * aY1 - aX1 * aY4 + aX2 * aY3 - aX3 * aY2 + aX4 * aY1 + aX3 * aY4 - aX4 * aY3);
176  double C2 = bY1 / 4.0 + bY2 / 4.0 - bY3 / 4.0 - bY4 / 4.0;
177  double C3 = bY1 / 4.0 - bY2 / 4.0 - bY3 / 4.0 + bY4 / 4.0;
178  double C4 = bX1 / 4.0 + bX2 / 4.0 - bX3 / 4.0 - bX4 / 4.0;
179  double C5 = bX1 / 4.0 - bX2 / 4.0 - bX3 / 4.0 + bX4 / 4.0;
180  double C6 = aX1 + aX2 - aX3 - aX4;
181  double C7 = aX1 - aX2 - aX3 + aX4;
182  double C8 = aY1 + aY2 - aY3 - aY4;
183  double C9 = aY1 - aY2 - aY3 + aY4;
184  double f11 = 2.0 * C1 * C5 * C8 - 2.0 * C1 * C4 * C9;
185  double f12 = 2.0 * C1 * C4 * C7 - 2.0 * C1 * C5 * C6;
186  double f21 = 2.0 * C1 * C3 * C8 - 2.0 * C1 * C2 * C9;
187  double f22 = 2.0 * C1 * C2 * C7 - 2.0 * C1 * C3 * C6;
188 
189  // now we can extrapolate the rotation angle that makes this deformation gradient symmetric.
190  // F = R*U -> find R such that R'*F = U
191  double alpha = std::atan2(f21 - f12, f11 + f22);
192 
193  // this final coordinate system is the one in which
194  // the deformation gradient is equal to the stretch tensor
195  return ASDShellQ4LocalCoordinateSystem(def[0], def[1], def[2], def[3], alpha);
196  }
197 
198  virtual void calculateLocalDisplacements(
200  const VectorType& globalDisplacements,
201  VectorType& localDisplacements)
202  {
203  // orientation and center of current local coordinate system
204  QuaternionType Q = QuaternionType::FromRotationMatrix(LCS.Orientation());
205  const Vector3Type& C = LCS.Center();
206 
207  for (int i = 0; i < 4; i++)
208  {
209  int index = i * 6;
210 
211  // centered undeformed position
212  Vector3Type X0 = Vector3Type(m_nodes[i]->getCrds());
213  X0 -= m_C0;
214 
215  // centered deformed position
216  Vector3Type X = X0 + Vector3Type(globalDisplacements, index);
217  X -= C;
218 
219  // get deformational displacements
220  Q.rotateVector(X);
221  m_Q0.rotateVector(X0);
222  Vector3Type deformationalDisplacements = X - X0;
223 
224  localDisplacements[index] = deformationalDisplacements[0];
225  localDisplacements[index + 1] = deformationalDisplacements[1];
226  localDisplacements[index + 2] = deformationalDisplacements[2];
227 
228  // get deformational rotations
229  QuaternionType Qd = Q * m_QN[i] * m_Q0.conjugate();
230  Qd.toRotationVector(
231  localDisplacements[index + 3],
232  localDisplacements[index + 4],
233  localDisplacements[index + 5]);
234  }
235  }
236 
237  virtual void transformToGlobal(
239  const VectorType& globalDisplacements,
240  const VectorType& localDisplacements,
241  MatrixType& LHS,
242  VectorType& RHS,
243  bool LHSrequired)
244  {
245  // Get the total rotation matrix (local - to - global)
246  // Note: do NOT include the warpage correction matrix!
247  // Explanation:
248  // The Warpage correction matrix computed by the LocalCoordinateSystem is a Linear Projector.
249  // It should be used in a LinearCoordinateTransformation.
250  // Here instead we already calculate a nonlinear Projector (P = Pu - S * G)!
251 
252  static MatrixType T(24, 24);
253  LCS.ComputeTotalRotationMatrix(T);
254 
255  // Form all matrices:
256  // S: Spin-Fitter matrix
257  // G: Spin-Lever matrix
258  // P: Projector (Translational & Rotational)
259  static MatrixType P(24, 24);
260  static MatrixType S(24, 3);
261  static MatrixType G(3, 24);
262  EICR::Compute_Pt(4, P);
263  EICR::Compute_S(LCS.Nodes(), S);
264  RotationGradient(LCS, globalDisplacements, G);
265  P.addMatrixProduct(1.0, S, G, -1.0); // P -= S*G
266 
267  // Compute the projected local forces ( pe = P' * RHS ).
268  // Note: here the RHS is already given as a residual vector -> - internalForces -> (pe = - Ke * U)
269  // so projectedLocalForces = - P' * Ke * U
270 
271  static VectorType projectedLocalForces(24);
272  projectedLocalForces.addMatrixTransposeVector(0.0, P, RHS, 1.0);
273 
274  // Compute the Right-Hand-Side vector in global coordinate system (- T' * P' * Km * U).
275  // At this point the computation of the Right-Hand-Side is complete.
276 
277  RHS.addMatrixTransposeVector(0.0, T, projectedLocalForces, 1.0);
278 
279  // Begin the computation of the Left-Hand-Side Matrix :
280 
281  if (!LHSrequired)
282  return; // avoid useless calculations!
283 
284  // H: Axial Vector Jacobian
285  static MatrixType H(24, 24);
286  EICR::Compute_H(localDisplacements, H);
287 
288  // Step 1: ( K.M : Material Stiffness Matrix )
289  // Apply the projector to the Material Stiffness Matrix (Ke = P' * Km * H * P)
290  // At this point 'LHS' contains the 'projected' Material Stiffness matrix
291  // in local corotational coordinate system
292 
293  static MatrixType temp(24, 24);
294  temp.addMatrixProduct(0.0, LHS, H, 1.0);
295  LHS.addMatrixProduct(0.0, temp, P, 1.0);
296  temp.addMatrixTransposeProduct(0.0, P, LHS, 1.0);
297  LHS = temp;
298 
299  // Step 2: ( K.GP: Equilibrium Projection Geometric Stiffness Matrix )
300  // First assemble the 'Fnm' matrix with the Spins of the nodal forces.
301  // Actually at this point the 'Fnm' Matrix is the 'Fn' Matrix,
302  // because it only contains the spins of the 'translational' forces.
303  // At this point 'LHS' contains also this term of the Geometric stiffness
304  // (Ke = (P' * Km * H * P) - (G' * Fn' * P))
305 
306  static MatrixType Fnm(24, 3);
307  Fnm.Zero();
308  EICR::Spin_AtRow(projectedLocalForces, Fnm, 0);
309  EICR::Spin_AtRow(projectedLocalForces, Fnm, 6);
310  EICR::Spin_AtRow(projectedLocalForces, Fnm, 12);
311  EICR::Spin_AtRow(projectedLocalForces, Fnm, 18);
312 
313  static MatrixType FnmT(3, 24);
314  FnmT.addMatrixTranspose(0.0, Fnm, 1.0);
315 
316  temp.addMatrixTransposeProduct(0.0, G, FnmT, 1.0);
317  LHS.addMatrixProduct(1.0, temp, P, 1.0); // note: '+' not '-' because the RHS already has the negative sign
318 
319  // Step 3: ( K.GR: Rotational Geometric Stiffness Matrix )
320  // Add the Spins of the nodal moments to 'Fnm'.
321  // At this point 'LHS' contains also this term of the Geometric stiffness
322  // (Ke = (P' * Km * H * P) - (G' * Fn' * P) - (Fnm * G))
323 
324  EICR::Spin_AtRow(projectedLocalForces, Fnm, 3);
325  EICR::Spin_AtRow(projectedLocalForces, Fnm, 9);
326  EICR::Spin_AtRow(projectedLocalForces, Fnm, 15);
327  EICR::Spin_AtRow(projectedLocalForces, Fnm, 21);
328 
329  LHS.addMatrixProduct(1.0, Fnm, G, 1.0); // note: '+' not '-' because the RHS already has the negative sign
330 
331  // Step 4: (Global Stiffness Matrix)
332  // Transform the LHS to the Global coordinate system.
333  // T' * [(P' * Km * H * P) - (G' * Fn' * P) - (Fnm * G)] * T
334  temp.addMatrixProduct(0.0, LHS, T, 1.0);
335  LHS.addMatrixTransposeProduct(0.0, T, temp, 1.0);
336  }
337 
338  virtual void transformToGlobal(
340  MatrixType& LHS,
341  VectorType& RHS,
342  bool LHSrequired)
343  {
344  static VectorType globalDisplacements(24);
345  static VectorType localDisplacements(24);
346  computeGlobalDisplacements(globalDisplacements);
347  calculateLocalDisplacements(LCS, globalDisplacements, localDisplacements);
348  transformToGlobal(LCS, globalDisplacements, localDisplacements, LHS, RHS, LHSrequired);
349  }
350 
351  virtual int internalDataSize() const
352  {
353  // 24 -> initial displacement +
354  // 9*4 -> 9 quaternions +
355  // 9*3 -> 9 3d vectors
356  return 87;
357  }
358 
359  virtual Vector getInternalData(void) const
360  {
361  Vector retval(internalDataSize());
362  int pos= 0;
363 
364  // 24 -> initial displacement +
365  for (int i = 0; i < 24; i++)
366  retval(pos++) = m_U0(i);
367 
368  // 9*4 -> 9 quaternions +
369  auto lamq = [&retval, &pos](const QuaternionType& x)
370  {
371  retval(pos++) = x.w();
372  retval(pos++) = x.x();
373  retval(pos++) = x.y();
374  retval(pos++) = x.z();
375  };
376  lamq(m_Q0);
377  for (int i = 0; i < 4; i++)
378  lamq(m_QN[i]);
379  for (int i = 0; i < 4; i++)
380  lamq(m_QN_converged[i]);
381 
382  // 9*3 -> 9 3d vectors +
383  auto lamv = [&retval, &pos](const Vector3Type& x)
384  {
385  retval(pos++) = x.x();
386  retval(pos++) = x.y();
387  retval(pos++) = x.z();
388  };
389  lamv(m_C0);
390  for (int i = 0; i < 4; i++)
391  lamv(m_RV[i]);
392  for (int i = 0; i < 4; i++)
393  lamv(m_RV_converged[i]);
394  return retval;
395  }
396 
397  virtual void setInternalData(const VectorType &v)
398  {
399  int pos= 0;
400 
401  // 24 -> initial displacement +
402  for (int i = 0; i < 24; i++)
403  m_U0(i) = v(pos++);
404 
405  // 9*4 -> 9 quaternions +
406  auto lamq = [&v, &pos](QuaternionType& x)
407  {
408  const double ww= v(pos++);
409  const double xx= v(pos++);
410  const double yy= v(pos++);
411  const double zz= v(pos++);
412  x = QuaternionType(ww, xx, yy, zz);
413  };
414  lamq(m_Q0);
415  for(int i = 0; i < 4; i++)
416  lamq(m_QN[i]);
417  for(int i = 0; i < 4; i++)
418  lamq(m_QN_converged[i]);
419 
420  // 9*3 -> 9 3d vectors +
421  auto lamv = [&v, &pos](Vector3Type& x)
422  {
423  const double xx= v(pos++);
424  const double yy= v(pos++);
425  const double zz= v(pos++);
426  x = Vector3Type(xx, yy, zz);
427  };
428  lamv(m_C0);
429  for (int i = 0; i < 4; i++)
430  lamv(m_RV[i]);
431  for (int i = 0; i < 4; i++)
432  lamv(m_RV_converged[i]);
433  }
434 
435  private:
436 
446  inline void RotationGradient(
448  const VectorType& globalDisplacements,
449  MatrixType& G)
450  {
451  G.Zero();
452 
453 #ifdef USE_POLAR_DECOMP_ALLIGN
454 
460  //double pert = std::sqrt(createReferenceCoordinateSystem().Area()) * 1.0e-8;
462 
464  //auto CS0 = createLocalCoordinateSystem(globalDisplacements);
465  //Vector3Type e30 = CS0.Vz();
466  //Vector3Type e10 = CS0.Vx();
467  //QuaternionType Q0 = QuaternionType::FromRotationMatrix(CS0.Orientation());
468 
470  //static Vector UGP(24);
471  //UGP = globalDisplacements;
472 
474  //for (int i = 0; i < 4; i++)
475  //{
476  // int index = i * 6;
477 
478  // // for each component in [x, y, z] ...
479  // for (int j = 0; j < 3; j++)
480  // {
481  // // apply perturbation
482  // UGP(index + j) += pert;
483 
484  // // current coordinate system (perturbed at node i component j)
485  // auto CSi = createLocalCoordinateSystem(UGP);
486 
487  // // save the (numerical) rotation gradient
488 
489  // Vector3Type e3 = CSi.Vz();// - e30;
490  // Vector3Type e1 = CSi.Vx();// - e10;
491  // Q0.rotateVector(e3);
492  // Q0.rotateVector(e1);
493 
494  // G(0, index + j) = e3(1) / pert; // - d(e3.y)/dxj , where xj is x,y,z for j=0,1,2
495  // G(1, index + j) = -e3(0) / pert; // + d(e3.x)/dxj , where xj is x,y,z for j=0,1,2
496  // G(2, index + j) = -e1(1) / pert; // + d(e1.y)/dxj , where xj is x,y,z for j=0,1,2
497 
498  // UGP(index + j) = globalDisplacements(index + j); // restore the current coordinate
499  // }
500  //}
501 
502 #else // !USE_POLAR_DECOMP_ALLIGN
503 
504  const auto& P1 = LCS.P1();
505  const auto& P2 = LCS.P2();
506  const auto& P3 = LCS.P3();
507  const auto& P4 = LCS.P4();
508 
509  double Ap = 2.0 * LCS.Area();
510  double m = 1.0 / Ap;
511 
512  Vector3Type D12(P2 - P1);
513  Vector3Type D24(P4 - P2);
514  Vector3Type D13(P3 - P1);
515 
516  double x42 = D24(0);
517  double x24 = -x42;
518  double y42 = D24(1);
519  double y24 = -y42;
520  double x31 = D13(0);
521  double x13 = -x31;
522  double y31 = D13(1);
523  double y13 = -y31;
524 
525  // Note, assuming the input vectors are in local CR,
526  // l12 is the length of the side 1-2 projected onto the xy plane.
527  double l12 = std::sqrt(D12(0) * D12(0) + D12(1) * D12(1));
528 
529  // G1
530 
531  G(0, 2) = x42 * m;
532  G(1, 2) = y42 * m;
533  G(2, 1) = -1.0 / l12;
534 
535  // G2
536 
537  G(0, 8) = x13 * m;
538  G(1, 8) = y13 * m;
539  G(2, 7) = 1.0 / l12;
540 
541  // G3
542 
543  G(0, 14) = x24 * m;
544  G(1, 14) = y24 * m;
545 
546  // G4
547 
548  G(0, 20) = x31 * m;
549  G(1, 20) = y31 * m;
550 
551 #endif // USE_POLAR_DECOMP_ALLIGN
552 
553  }
554 
555  };
556 } // end of XC namespace
557 #endif // !ASDShellQ4CorotationalTransformation_h
Float vector abstraction.
Definition: Vector.h:94
virtual void setInternalData(const VectorType &v)
Restore the object from its internal data.
Definition: ASDShellQ4CorotationalTransformation.h:397
void Zero(void)
Zero&#39;s out the Matrix.
Definition: Matrix.cpp:226
static void Compute_Pt(size_t num_nodes, MatrixType &P)
Computes the Translational Projector Matrix.
Definition: ASDEICR.h:273
Vector of integers.
Definition: ID.h:95
static void Compute_H(const VectorType &displacements, MatrixType &H)
Computes the Axial Vector Jacobian.
Definition: ASDEICR.h:340
This class represent the local coordinate system of any element whose geometry is a 4-node Quadrilate...
Definition: ASDShellQ4LocalCoordinateSystem.h:41
void toRotationVector(T &rx, T &ry, T &rz) const
Extracts the Rotation Vector from this ASDQuaternion.
Definition: ASDMath.h:495
ASDQuaternion conjugate() const
Returns the Conjugate of this ASDQuaternion, which represents the opposite rotation.
Definition: ASDMath.h:456
static void Spin_AtRow(const TVec &V, TMat &S, size_t row_index)
Computes the Spin of the input vector V, and saves the result into the output matrix S...
Definition: ASDEICR.h:98
void rotateVector(const TVector3_A &a, TVector3_B &b) const
Rotates a vector using this quaternion.
Definition: ASDMath.h:556
static ASDQuaternion FromRotationVector(T rx, T ry, T rz)
Returns a ASDQuaternion from a rotation vector.
Definition: ASDMath.h:653
static void Compute_S(const NodeContainerType &nodes, MatrixType &S)
Computes the Spin Lever Matrix.
Definition: ASDEICR.h:314
ASDShellQ4CorotationalTransformation.
Definition: ASDShellQ4CorotationalTransformation.h:66
virtual Vector getInternalData(void) const
Return the data needed to recreate the object.
Definition: ASDShellQ4CorotationalTransformation.h:359
Open source finite element program for structural analysis.
Definition: ContinuaReprComponent.h:35
Matrix of floats.
Definition: Matrix.h:111
static ASDQuaternion FromRotationMatrix(const TMatrix3x3 &m)
Returns a ASDQuaternion from a Rotation Matrix.
Definition: ASDMath.h:704
This class represents a basic (linear) coordinate transformation that can be used by any element whos...
Definition: ASDShellQ4Transformation.h:74
Domain (mesh and boundary conditions) of the finite element model.
Definition: Domain.h:117
ASDQuaternion A simple class that implements the main features of quaternion algebra.
Definition: ASDMath.h:328