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);
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  Vector3Type(m_nodes[0]->getCrds()),
141  Vector3Type(m_nodes[1]->getCrds()),
142  Vector3Type(m_nodes[2]->getCrds()),
143  Vector3Type(m_nodes[3]->getCrds())
144  };
145  for (int i = 0; i < 4; i++) {
146  int index = i * 6;
147  Vector3Type& iP = def[i];
148  iP(0) += globalDisplacements(index) - m_U0(index);
149  iP(1) += globalDisplacements(index + 1) - m_U0(index + 1);
150  iP(2) += globalDisplacements(index + 2) - m_U0(index + 2);
151  }
152 
153  // current coordinate system
154  ASDShellQ4LocalCoordinateSystem b(def[0], def[1], def[2], def[3]);
155 
156 #ifndef USE_POLAR_DECOMP_ALLIGN
157  return b;
158 #endif // !USE_POLAR_DECOMP_ALLIGN
159 
160  double aX1 = a.X1(); double aY1 = a.Y1();
161  double bX1 = b.X1(); double bY1 = b.Y1();
162  double aX2 = a.X2(); double aY2 = a.Y2();
163  double bX2 = b.X2(); double bY2 = b.Y2();
164  double aX3 = a.X3(); double aY3 = a.Y3();
165  double bX3 = b.X3(); double bY3 = b.Y3();
166  double aX4 = a.X4(); double aY4 = a.Y4();
167  double bX4 = b.X4(); double bY4 = b.Y4();
168 
169  // now we are in the local coordinate systems (reference and current), i.e. we are looking in the local Z direction
170  // which is the same for both coordinate systems.
171  // now we can compute the 2D deformation gradient between the 2 configurations, at the element center.
172 
173  double C1 = 1.0 / (aX1 * aY2 - aX2 * aY1 - aX1 * aY4 + aX2 * aY3 - aX3 * aY2 + aX4 * aY1 + aX3 * aY4 - aX4 * aY3);
174  double C2 = bY1 / 4.0 + bY2 / 4.0 - bY3 / 4.0 - bY4 / 4.0;
175  double C3 = bY1 / 4.0 - bY2 / 4.0 - bY3 / 4.0 + bY4 / 4.0;
176  double C4 = bX1 / 4.0 + bX2 / 4.0 - bX3 / 4.0 - bX4 / 4.0;
177  double C5 = bX1 / 4.0 - bX2 / 4.0 - bX3 / 4.0 + bX4 / 4.0;
178  double C6 = aX1 + aX2 - aX3 - aX4;
179  double C7 = aX1 - aX2 - aX3 + aX4;
180  double C8 = aY1 + aY2 - aY3 - aY4;
181  double C9 = aY1 - aY2 - aY3 + aY4;
182  double f11 = 2.0 * C1 * C5 * C8 - 2.0 * C1 * C4 * C9;
183  double f12 = 2.0 * C1 * C4 * C7 - 2.0 * C1 * C5 * C6;
184  double f21 = 2.0 * C1 * C3 * C8 - 2.0 * C1 * C2 * C9;
185  double f22 = 2.0 * C1 * C2 * C7 - 2.0 * C1 * C3 * C6;
186 
187  // now we can extrapolate the rotation angle that makes this deformation gradient symmetric.
188  // F = R*U -> find R such that R'*F = U
189  double alpha = std::atan2(f21 - f12, f11 + f22);
190 
191  // this final coordinate system is the one in which
192  // the deformation gradient is equal to the stretch tensor
193  return ASDShellQ4LocalCoordinateSystem(def[0], def[1], def[2], def[3], alpha);
194  }
195 
196  virtual void calculateLocalDisplacements(
198  const VectorType& globalDisplacements,
199  VectorType& localDisplacements)
200  {
201  // orientation and center of current local coordinate system
202  QuaternionType Q = QuaternionType::FromRotationMatrix(LCS.Orientation());
203  const Vector3Type& C = LCS.Center();
204 
205  for (int i = 0; i < 4; i++)
206  {
207  int index = i * 6;
208 
209  // centered undeformed position
210  Vector3Type X0 = Vector3Type(m_nodes[i]->getCrds());
211  X0 -= m_C0;
212 
213  // centered deformed position
214  Vector3Type X = X0 + Vector3Type(globalDisplacements, index);
215  X -= C;
216 
217  // get deformational displacements
218  Q.rotateVector(X);
219  m_Q0.rotateVector(X0);
220  Vector3Type deformationalDisplacements = X - X0;
221 
222  localDisplacements[index] = deformationalDisplacements[0];
223  localDisplacements[index + 1] = deformationalDisplacements[1];
224  localDisplacements[index + 2] = deformationalDisplacements[2];
225 
226  // get deformational rotations
227  QuaternionType Qd = Q * m_QN[i] * m_Q0.conjugate();
228  Qd.toRotationVector(
229  localDisplacements[index + 3],
230  localDisplacements[index + 4],
231  localDisplacements[index + 5]);
232  }
233  }
234 
235  virtual void transformToGlobal(
237  const VectorType& globalDisplacements,
238  const VectorType& localDisplacements,
239  MatrixType& LHS,
240  VectorType& RHS,
241  bool LHSrequired)
242  {
243  // Get the total rotation matrix (local - to - global)
244  // Note: do NOT include the warpage correction matrix!
245  // Explanation:
246  // The Warpage correction matrix computed by the LocalCoordinateSystem is a Linear Projector.
247  // It should be used in a LinearCoordinateTransformation.
248  // Here instead we already calculate a nonlinear Projector (P = Pu - S * G)!
249 
250  static MatrixType T(24, 24);
251  LCS.ComputeTotalRotationMatrix(T);
252 
253  // Form all matrices:
254  // S: Spin-Fitter matrix
255  // G: Spin-Lever matrix
256  // P: Projector (Translational & Rotational)
257  static MatrixType P(24, 24);
258  static MatrixType S(24, 3);
259  static MatrixType G(3, 24);
260  EICR::Compute_Pt(4, P);
261  EICR::Compute_S(LCS.Nodes(), S);
262  RotationGradient(LCS, globalDisplacements, G);
263  P.addMatrixProduct(1.0, S, G, -1.0); // P -= S*G
264 
265  // Compute the projected local forces ( pe = P' * RHS ).
266  // Note: here the RHS is already given as a residual vector -> - internalForces -> (pe = - Ke * U)
267  // so projectedLocalForces = - P' * Ke * U
268 
269  static VectorType projectedLocalForces(24);
270  projectedLocalForces.addMatrixTransposeVector(0.0, P, RHS, 1.0);
271 
272  // Compute the Right-Hand-Side vector in global coordinate system (- T' * P' * Km * U).
273  // At this point the computation of the Right-Hand-Side is complete.
274 
275  RHS.addMatrixTransposeVector(0.0, T, projectedLocalForces, 1.0);
276 
277  // Begin the computation of the Left-Hand-Side Matrix :
278 
279  if (!LHSrequired)
280  return; // avoid useless calculations!
281 
282  // H: Axial Vector Jacobian
283  static MatrixType H(24, 24);
284  EICR::Compute_H(localDisplacements, H);
285 
286  // Step 1: ( K.M : Material Stiffness Matrix )
287  // Apply the projector to the Material Stiffness Matrix (Ke = P' * Km * H * P)
288  // At this point 'LHS' contains the 'projected' Material Stiffness matrix
289  // in local corotational coordinate system
290 
291  static MatrixType temp(24, 24);
292  temp.addMatrixProduct(0.0, LHS, H, 1.0);
293  LHS.addMatrixProduct(0.0, temp, P, 1.0);
294  temp.addMatrixTransposeProduct(0.0, P, LHS, 1.0);
295  LHS = temp;
296 
297  // Step 2: ( K.GP: Equilibrium Projection Geometric Stiffness Matrix )
298  // First assemble the 'Fnm' matrix with the Spins of the nodal forces.
299  // Actually at this point the 'Fnm' Matrix is the 'Fn' Matrix,
300  // because it only contains the spins of the 'translational' forces.
301  // At this point 'LHS' contains also this term of the Geometric stiffness
302  // (Ke = (P' * Km * H * P) - (G' * Fn' * P))
303 
304  static MatrixType Fnm(24, 3);
305  Fnm.Zero();
306  EICR::Spin_AtRow(projectedLocalForces, Fnm, 0);
307  EICR::Spin_AtRow(projectedLocalForces, Fnm, 6);
308  EICR::Spin_AtRow(projectedLocalForces, Fnm, 12);
309  EICR::Spin_AtRow(projectedLocalForces, Fnm, 18);
310 
311  static MatrixType FnmT(3, 24);
312  FnmT.addMatrixTranspose(0.0, Fnm, 1.0);
313 
314  temp.addMatrixTransposeProduct(0.0, G, FnmT, 1.0);
315  LHS.addMatrixProduct(1.0, temp, P, 1.0); // note: '+' not '-' because the RHS already has the negative sign
316 
317  // Step 3: ( K.GR: Rotational Geometric Stiffness Matrix )
318  // Add the Spins of the nodal moments to 'Fnm'.
319  // At this point 'LHS' contains also this term of the Geometric stiffness
320  // (Ke = (P' * Km * H * P) - (G' * Fn' * P) - (Fnm * G))
321 
322  EICR::Spin_AtRow(projectedLocalForces, Fnm, 3);
323  EICR::Spin_AtRow(projectedLocalForces, Fnm, 9);
324  EICR::Spin_AtRow(projectedLocalForces, Fnm, 15);
325  EICR::Spin_AtRow(projectedLocalForces, Fnm, 21);
326 
327  LHS.addMatrixProduct(1.0, Fnm, G, 1.0); // note: '+' not '-' because the RHS already has the negative sign
328 
329  // Step 4: (Global Stiffness Matrix)
330  // Transform the LHS to the Global coordinate system.
331  // T' * [(P' * Km * H * P) - (G' * Fn' * P) - (Fnm * G)] * T
332  temp.addMatrixProduct(0.0, LHS, T, 1.0);
333  LHS.addMatrixTransposeProduct(0.0, T, temp, 1.0);
334  }
335 
336  virtual void transformToGlobal(
338  MatrixType& LHS,
339  VectorType& RHS,
340  bool LHSrequired)
341  {
342  static VectorType globalDisplacements(24);
343  static VectorType localDisplacements(24);
344  computeGlobalDisplacements(globalDisplacements);
345  calculateLocalDisplacements(LCS, globalDisplacements, localDisplacements);
346  transformToGlobal(LCS, globalDisplacements, localDisplacements, LHS, RHS, LHSrequired);
347  }
348 
349  virtual int internalDataSize() const
350  {
351  // 24 -> initial displacement +
352  // 9*4 -> 9 quaternions +
353  // 9*3 -> 9 3d vectors
354  return 87;
355  }
356 
357  virtual Vector getInternalData(void) const
358  {
359  Vector retval(internalDataSize());
360  int pos= 0;
361 
362  // 24 -> initial displacement +
363  for (int i = 0; i < 24; i++)
364  retval(pos++) = m_U0(i);
365 
366  // 9*4 -> 9 quaternions +
367  auto lamq = [&retval, &pos](const QuaternionType& x)
368  {
369  retval(pos++) = x.w();
370  retval(pos++) = x.x();
371  retval(pos++) = x.y();
372  retval(pos++) = x.z();
373  };
374  lamq(m_Q0);
375  for (int i = 0; i < 4; i++)
376  lamq(m_QN[i]);
377  for (int i = 0; i < 4; i++)
378  lamq(m_QN_converged[i]);
379 
380  // 9*3 -> 9 3d vectors +
381  auto lamv = [&retval, &pos](const Vector3Type& x)
382  {
383  retval(pos++) = x.x();
384  retval(pos++) = x.y();
385  retval(pos++) = x.z();
386  };
387  lamv(m_C0);
388  for (int i = 0; i < 4; i++)
389  lamv(m_RV[i]);
390  for (int i = 0; i < 4; i++)
391  lamv(m_RV_converged[i]);
392  return retval;
393  }
394 
395  virtual void setInternalData(const VectorType &v)
396  {
397  int pos= 0;
398 
399  // 24 -> initial displacement +
400  for (int i = 0; i < 24; i++)
401  m_U0(i) = v(pos++);
402 
403  // 9*4 -> 9 quaternions +
404  auto lamq = [&v, &pos](QuaternionType& x)
405  {
406  const double ww= v(pos++);
407  const double xx= v(pos++);
408  const double yy= v(pos++);
409  const double zz= v(pos++);
410  x = QuaternionType(ww, xx, yy, zz);
411  };
412  lamq(m_Q0);
413  for(int i = 0; i < 4; i++)
414  lamq(m_QN[i]);
415  for(int i = 0; i < 4; i++)
416  lamq(m_QN_converged[i]);
417 
418  // 9*3 -> 9 3d vectors +
419  auto lamv = [&v, &pos](Vector3Type& x)
420  {
421  const double xx= v(pos++);
422  const double yy= v(pos++);
423  const double zz= v(pos++);
424  x = Vector3Type(xx, yy, zz);
425  };
426  lamv(m_C0);
427  for (int i = 0; i < 4; i++)
428  lamv(m_RV[i]);
429  for (int i = 0; i < 4; i++)
430  lamv(m_RV_converged[i]);
431  }
432 
433  private:
434 
444  inline void RotationGradient(
446  const VectorType& globalDisplacements,
447  MatrixType& G)
448  {
449  G.Zero();
450 
451 #ifdef USE_POLAR_DECOMP_ALLIGN
452 
458  //double pert = std::sqrt(createReferenceCoordinateSystem().Area()) * 1.0e-8;
460 
462  //auto CS0 = createLocalCoordinateSystem(globalDisplacements);
463  //Vector3Type e30 = CS0.Vz();
464  //Vector3Type e10 = CS0.Vx();
465  //QuaternionType Q0 = QuaternionType::FromRotationMatrix(CS0.Orientation());
466 
468  //static Vector UGP(24);
469  //UGP = globalDisplacements;
470 
472  //for (int i = 0; i < 4; i++)
473  //{
474  // int index = i * 6;
475 
476  // // for each component in [x, y, z] ...
477  // for (int j = 0; j < 3; j++)
478  // {
479  // // apply perturbation
480  // UGP(index + j) += pert;
481 
482  // // current coordinate system (perturbed at node i component j)
483  // auto CSi = createLocalCoordinateSystem(UGP);
484 
485  // // save the (numerical) rotation gradient
486 
487  // Vector3Type e3 = CSi.Vz();// - e30;
488  // Vector3Type e1 = CSi.Vx();// - e10;
489  // Q0.rotateVector(e3);
490  // Q0.rotateVector(e1);
491 
492  // G(0, index + j) = e3(1) / pert; // - d(e3.y)/dxj , where xj is x,y,z for j=0,1,2
493  // G(1, index + j) = -e3(0) / pert; // + d(e3.x)/dxj , where xj is x,y,z for j=0,1,2
494  // G(2, index + j) = -e1(1) / pert; // + d(e1.y)/dxj , where xj is x,y,z for j=0,1,2
495 
496  // UGP(index + j) = globalDisplacements(index + j); // restore the current coordinate
497  // }
498  //}
499 
500 #else // !USE_POLAR_DECOMP_ALLIGN
501 
502  const auto& P1 = LCS.P1();
503  const auto& P2 = LCS.P2();
504  const auto& P3 = LCS.P3();
505  const auto& P4 = LCS.P4();
506 
507  double Ap = 2.0 * LCS.Area();
508  double m = 1.0 / Ap;
509 
510  Vector3Type D12(P2 - P1);
511  Vector3Type D24(P4 - P2);
512  Vector3Type D13(P3 - P1);
513 
514  double x42 = D24(0);
515  double x24 = -x42;
516  double y42 = D24(1);
517  double y24 = -y42;
518  double x31 = D13(0);
519  double x13 = -x31;
520  double y31 = D13(1);
521  double y13 = -y31;
522 
523  // Note, assuming the input vectors are in local CR,
524  // l12 is the length of the side 1-2 projected onto the xy plane.
525  double l12 = std::sqrt(D12(0) * D12(0) + D12(1) * D12(1));
526 
527  // G1
528 
529  G(0, 2) = x42 * m;
530  G(1, 2) = y42 * m;
531  G(2, 1) = -1.0 / l12;
532 
533  // G2
534 
535  G(0, 8) = x13 * m;
536  G(1, 8) = y13 * m;
537  G(2, 7) = 1.0 / l12;
538 
539  // G3
540 
541  G(0, 14) = x24 * m;
542  G(1, 14) = y24 * m;
543 
544  // G4
545 
546  G(0, 20) = x31 * m;
547  G(1, 20) = y31 * m;
548 
549 #endif // USE_POLAR_DECOMP_ALLIGN
550 
551  }
552 
553  };
554 } // end of XC namespace
555 #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:395
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:357
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