Nektar++
LinearElasticSystem.cpp
Go to the documentation of this file.
1 ///////////////////////////////////////////////////////////////////////////////
2 //
3 // File LinearElasticSystem.cpp
4 //
5 // For more information, please see: http://www.nektar.info
6 //
7 // The MIT License
8 //
9 // Copyright (c) 2006 Division of Applied Mathematics, Brown University (USA),
10 // Department of Aeronautics, Imperial College London (UK), and Scientific
11 // Computing and Imaging Institute, University of Utah (USA).
12 //
13 // Permission is hereby granted, free of charge, to any person obtaining a
14 // copy of this software and associated documentation files (the "Software"),
15 // to deal in the Software without restriction, including without limitation
16 // the rights to use, copy, modify, merge, publish, distribute, sublicense,
17 // and/or sell copies of the Software, and to permit persons to whom the
18 // Software is furnished to do so, subject to the following conditions:
19 //
20 // The above copyright notice and this permission notice shall be included
21 // in all copies or substantial portions of the Software.
22 //
23 // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
24 // OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
25 // FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
26 // THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
27 // LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
28 // FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
29 // DEALINGS IN THE SOFTWARE.
30 //
31 // Description: LinearElasticSystem solve routines
32 //
33 ///////////////////////////////////////////////////////////////////////////////
34 
35 #include <algorithm>
36 #include <iomanip>
37 
38 #include <LocalRegions/MatrixKey.h>
39 #include <LocalRegions/SegExp.h>
41 #include <MultiRegions/ContField.h>
47 
48 #ifdef NEKTAR_USE_MPI
50 #endif
51 
52 #ifdef NEKTAR_USE_PETSC
54 #endif
55 
56 using namespace std;
57 
58 namespace Nektar
59 {
60 
61 string LinearElasticSystem::className = GetEquationSystemFactory().
62  RegisterCreatorFunction("LinearElasticSystem",
63  LinearElasticSystem::create);
64 
65 /*
66  * @brief Generate mapping between a simplex and the reference element.
67  *
68  * Mapping that requires the coordinates of the three vertices (x,y) of the
69  * triangular element and outputs the function coefficients that defines the
70  * mapping to the reference element for each coordinate (xfunc and yfunc)
71  *
72  * @param x co-ordinates of triangle/tetrahedron
73  * @param xf components of mapping
74  */
76 {
77  int n = geom->GetNumVerts(), i, j;
78 
79  DNekMat map (n, n, 1.0, eFULL);
80  DNekMat mapref(n, n, 1.0, eFULL);
81 
82  // Extract coordinate information.
83  for (i = 0; i < n; ++i)
84  {
85  for (j = 0; j < n-1; ++j)
86  {
87  map(j,i) = (*geom->GetVertex(i))[j];
88  }
89  }
90 
91  // Set up reference triangle or tetrahedron mapping.
92  if (n == 3)
93  {
94  mapref(0,0) = -1.0; mapref(1,0) = -1.0;
95  mapref(0,1) = 1.0; mapref(1,1) = -1.0;
96  mapref(0,2) = -1.0; mapref(1,2) = 1.0;
97  }
98  else if (n == 4)
99  {
100  mapref(0,0) = -1.0; mapref(1,0) = -1.0; mapref(2,0) = -1.0;
101  mapref(0,1) = 1.0; mapref(1,1) = -1.0; mapref(2,1) = -1.0;
102  mapref(0,2) = -1.0; mapref(1,2) = 1.0; mapref(2,2) = -1.0;
103  mapref(0,3) = -1.0; mapref(1,3) = -1.0; mapref(2,3) = 1.0;
104  }
105 
106  map.Invert();
107 
108  DNekMat newmap = mapref * map;
109  DNekMat mapred(n-1, n-1, 1.0, eFULL);
110 
111  for (i = 0; i < n-1; ++i)
112  {
113  for (j = 0; j < n-1; ++j)
114  {
115  mapred(i,j) = newmap(i,j);
116  }
117  }
118 
119  return mapred;
120 }
121 
122 
123 /**
124  * @brief Default constructor.
125  */
126 LinearElasticSystem::LinearElasticSystem(
127  const LibUtilities::SessionReaderSharedPtr& pSession,
129  : EquationSystem(pSession, pGraph)
130 {
131 }
132 
133 /**
134  * @brief Set up the linear elasticity system.
135  *
136  * This routine loads the E and nu variables from the session file, creates a
137  * coupled assembly map and creates containers for the statically condensed
138  * block matrix system.
139  */
141 {
143 
144  const int nVel = m_fields[0]->GetCoordim(0);
145  int n;
146 
147  ASSERTL0(nVel > 1, "Linear elastic solver not set up for"
148  " this dimension (only 2D/3D supported).");
149 
150  // Make sure that we have Young's modulus and Poisson ratio set.
151  m_session->LoadParameter("E", m_E, 1.00);
152  m_session->LoadParameter("nu", m_nu, 0.25);
153  m_session->LoadParameter("Beta", m_beta, 1.00);
154 
155  // Create a coupled assembly map which allows us to tie u, v and w
156  // fields together.
157  MultiRegions::ContFieldSharedPtr u = std::dynamic_pointer_cast<
161  m_graph,
162  u->GetLocalToGlobalMap(),
163  m_fields[0]->GetBndConditions(),
164  m_fields);
165 
166  // Figure out size of our new matrix systems by looping over all expansions
167  // and multiply number of coefficients by velocity components.
168  const int nEl = m_fields[0]->GetExpSize();
170 
171  Array<OneD, unsigned int> sizeBnd(nEl);
172  Array<OneD, unsigned int> sizeInt(nEl);
173 
174  // Allocate storage for boundary and interior map caches.
177 
178  // Cache interior and boundary maps to avoid recalculating
179  // constantly. Should really be handled by manager in StdRegions but not
180  // really working yet.
181  for (n = 0; n < nEl; ++n)
182  {
183  exp = m_fields[0]->GetExp(n);
184  sizeBnd[n] = nVel * exp->NumBndryCoeffs();
185  sizeInt[n] = nVel * exp->GetNcoeffs() - sizeBnd[n];
186  exp->GetBoundaryMap(m_bmap[n]);
187  exp->GetInteriorMap(m_imap[n]);
188  }
189 
190  // Create block matrix storage for the statically condensed system.
191  MatrixStorage blkmatStorage = eDIAGONAL;
193  sizeBnd, sizeBnd, blkmatStorage);
195  sizeBnd, sizeInt, blkmatStorage);
197  sizeInt, sizeBnd, blkmatStorage);
199  sizeInt, sizeInt, blkmatStorage);
200 }
201 
202 /**
203  * @brief Build matrix system for linear elasticity equations.
204  *
205  * This routine constructs the matrix discretisation arising from the weak
206  * formulation of the linear elasticity equations. The resulting matrix system
207  * is then passed to LinearElasticSystem::SetStaticCondBlock in order to
208  * construct the statically condensed system.
209  *
210  * All of the matrices involved in the construction of the divergence of the
211  * stress tensor are Laplacian-like. We use the variable coefficient
212  * functionality within the library to multiply the Laplacian by the appropriate
213  * constants for all diagonal terms, and off-diagonal terms use
214  * LinearElasticSystem::BuildLaplacianIJMatrix to construct matrices containing
215  *
216  * \f[ \int \partial_{x_i} \phi_k \partial_{x_j} \phi_l \f]
217  *
218  * where mixed derivative terms are present. Symmetry (in terms of k,l) is
219  * exploited to avoid constructing this matrix repeatedly.
220  *
221  * @todo Make static condensation optional and construct full system instead.
222  */
224 {
225  const int nEl = m_fields[0]->GetExpSize();
226  const int nVel = m_fields[0]->GetCoordim(0);
227 
229  int n;
230 
231  // Factors map for matrix keys.
233 
234  // Calculate various constants
235  NekDouble mu = m_E * 0.5 / (1.0 + m_nu);
236  NekDouble lambda = m_E * m_nu / (1.0 + m_nu) / (1.0 - 2.0*m_nu);
237 
238  bool verbose = m_session->DefinesCmdLineArgument("verbose");
239  bool root = m_session->GetComm()->GetRank() == 0;
240 
241  // Loop over each element and construct matrices.
242  if (nVel == 2)
243  {
244  for (n = 0; n < nEl; ++n)
245  {
246  exp = m_fields[0]->GetExp(n);
247  const int nPhys = exp->GetTotPoints();
248  Array<OneD, NekDouble> aArr(nPhys, lambda + 2*mu);
249  Array<OneD, NekDouble> bArr(nPhys, mu);
250 
251  StdRegions::VarCoeffMap varcoeffA, varcoeffD;
252  varcoeffA[StdRegions::eVarCoeffD00] = aArr;
253  varcoeffA[StdRegions::eVarCoeffD11] = bArr;
254  varcoeffD[StdRegions::eVarCoeffD00] = bArr;
255  varcoeffD[StdRegions::eVarCoeffD11] = aArr;
256 
258  exp->DetShapeType(),
259  *exp, factors, varcoeffA);
261  exp->DetShapeType(),
262  *exp, factors, varcoeffD);
263 
264  /*
265  * mat holds the linear operator [ A B ] acting on [ u ].
266  * [ C D ] [ v ]
267  */
269  mat[0][0] = exp->GenMatrix(matkeyA);
270  mat[0][1] = BuildLaplacianIJMatrix(1, 0, mu+lambda, exp);
271  mat[1][0] = mat[0][1];
272  mat[1][1] = exp->GenMatrix(matkeyD);
273 
274  // Set up the statically condensed block for this element.
275  SetStaticCondBlock(n, exp, mat);
276 
277  if (verbose && root)
278  {
279  cout << "\rBuilding matrix system: "
280  << (int)(100.0 * n / nEl) << "%" << flush;
281  }
282  }
283  }
284  else if (nVel == 3)
285  {
286  for (n = 0; n < nEl; ++n)
287  {
288  exp = m_fields[0]->GetExp(n);
289  const int nPhys = exp->GetTotPoints();
290  Array<OneD, NekDouble> aArr(nPhys, lambda + 2*mu);
291  Array<OneD, NekDouble> bArr(nPhys, mu);
292 
293  StdRegions::VarCoeffMap varcoeffA, varcoeffE, varcoeffI;
294  varcoeffA[StdRegions::eVarCoeffD00] = aArr;
295  varcoeffA[StdRegions::eVarCoeffD11] = bArr;
296  varcoeffA[StdRegions::eVarCoeffD22] = bArr;
297  varcoeffE[StdRegions::eVarCoeffD00] = bArr;
298  varcoeffE[StdRegions::eVarCoeffD11] = aArr;
299  varcoeffE[StdRegions::eVarCoeffD22] = bArr;
300  varcoeffI[StdRegions::eVarCoeffD00] = bArr;
301  varcoeffI[StdRegions::eVarCoeffD11] = bArr;
302  varcoeffI[StdRegions::eVarCoeffD22] = aArr;
303 
305  exp->DetShapeType(),
306  *exp, factors, varcoeffA);
308  exp->DetShapeType(),
309  *exp, factors, varcoeffE);
311  exp->DetShapeType(),
312  *exp, factors, varcoeffI);
313 
314  /*
315  * mat holds the linear operator [ A B C ] acting on [ u ].
316  * [ D E F ] [ v ]
317  * [ G H I ] [ w ]
318  */
320  mat[0][0] = exp->GenMatrix(matkeyA);
321  mat[0][1] = BuildLaplacianIJMatrix(1, 0, mu + lambda, exp);
322  mat[0][2] = BuildLaplacianIJMatrix(2, 0, mu + lambda, exp);
323 
324  mat[1][0] = mat[0][1];
325  mat[1][1] = exp->GenMatrix(matkeyE);
326  mat[1][2] = BuildLaplacianIJMatrix(2, 1, mu + lambda, exp);
327 
328  mat[2][0] = mat[0][2];
329  mat[2][1] = mat[1][2];
330  mat[2][2] = exp->GenMatrix(matkeyI);
331 
332  // Set up the statically condensed block for this element.
333  SetStaticCondBlock(n, exp, mat);
334 
335  if (verbose && root)
336  {
337  cout << "\rBuilding matrix system: "
338  << (int)(100.0 * n / nEl) << "%" << flush;
339  }
340  }
341  }
342 
343  if (verbose && root)
344  {
345  cout << "\rBuilding matrix system: done." << endl;
346  }
347 }
348 
349 /**
350  * @brief Generate summary at runtime.
351  */
353 {
355 
356  AddSummaryItem(s, "Young's modulus", m_E);
357  AddSummaryItem(s, "Poisson ratio", m_nu);
358 }
359 
360 /**
361  * @brief Solve elliptic linear elastic system.
362  *
363  * The solve proceeds as follows:
364  *
365  * - Create a MultiRegions::GlobalLinSys object.
366  * - Evaluate a forcing function from the session file.
367  * - If the temperature term is enabled, evaluate this and add to forcing.
368  * - Apply Dirichlet boundary conditions.
369  * - Scatter forcing into the correct ordering according to the coupled
370  * assembly map.
371  * - Do the solve.
372  * - Scatter solution back to fields and backwards transform to physical space.
373  */
375 {
376  int i, j, k, l, nv;
377  const int nVel = m_fields[0]->GetCoordim(0);
378 
379  // Build initial matrix system.
381 
382  // Now we've got the matrix system set up, create a GlobalLinSys
383  // object. We mask ourselves as LinearAdvectionReaction to create a full
384  // matrix instead of symmetric storage.
388 
389  // Currently either direct or iterative static condensation is
390  // supported.
391  if (m_assemblyMap->GetGlobalSysSolnType() == MultiRegions::eDirectStaticCond)
392  {
393  linSys = MemoryManager<
394  MultiRegions::GlobalLinSysDirectStaticCond>::AllocateSharedPtr(
395  key, m_fields[0], m_schurCompl, m_BinvD, m_C, m_Dinv,
396  m_assemblyMap);
397  }
398  else if (m_assemblyMap->GetGlobalSysSolnType() ==
400  {
401  linSys = MemoryManager<
403  key, m_fields[0], m_schurCompl, m_BinvD, m_C, m_Dinv,
405  }
406 #ifdef NEKTAR_USE_PETSC
407  else if (m_assemblyMap->GetGlobalSysSolnType() ==
409  {
410  linSys = MemoryManager<
411  MultiRegions::GlobalLinSysPETScStaticCond>::AllocateSharedPtr(
412  key, m_fields[0], m_schurCompl, m_BinvD, m_C, m_Dinv,
413  m_assemblyMap);
414  }
415 #endif
416 #ifdef NEKTAR_USE_MPI
417  else if (m_assemblyMap->GetGlobalSysSolnType() ==
419  {
420  linSys = MemoryManager<
421  MultiRegions::GlobalLinSysXxtStaticCond>::AllocateSharedPtr(
422  key, m_fields[0], m_schurCompl, m_BinvD, m_C, m_Dinv,
423  m_assemblyMap);
424  }
425 #endif
426 
427  linSys->Initialise(m_assemblyMap);
428 
429  const int nCoeffs = m_fields[0]->GetNcoeffs();
430 
431  //
432  // -- Evaluate forcing functions
433  //
434 
435  // Evaluate the forcing function from the XML file.
436  Array<OneD, Array<OneD, NekDouble> > forcing(nVel);
437  GetFunction("Forcing")->Evaluate(forcing);
438 
439  // Add temperature term
440  string tempEval;
441  m_session->LoadSolverInfo("Temperature", tempEval, "None");
442 
443  if (tempEval == "Jacobian")
444  {
445  // Allocate storage
447 
448  for (nv = 0; nv < nVel; ++nv)
449  {
452  m_fields[nv]->GetNpoints());
453 
454  for (i = 0; i < m_fields[0]->GetExpSize(); ++i)
455  {
456  // Calculate element area
458  m_fields[0]->GetExp(i);
460  exp->GetPointsKeys();
462  exp->GetMetricInfo()->GetJac(pkey);
463 
464  int offset = m_fields[0]->GetPhys_Offset(i);
465 
466  if (exp->GetMetricInfo()->GetGtype() ==
468  {
469  Vmath::Smul(exp->GetTotPoints(), m_beta, jac, 1,
470  tmp = m_temperature[nv] + offset, 1);
471  }
472  else
473  {
474  Vmath::Fill(exp->GetTotPoints(), m_beta*jac[0],
475  tmp = m_temperature[nv] + offset, 1);
476  }
477  }
478  m_fields[nv]->PhysDeriv(nv, m_temperature[nv], forcing[nv]);
479  }
480  }
481  else if (tempEval == "Metric")
482  {
483  ASSERTL0((m_fields[0]->GetCoordim(0) == 2 &&
484  m_graph->GetAllQuadGeoms().size() == 0) ||
485  (m_fields[0]->GetCoordim(0) == 3 &&
486  m_graph->GetAllPrismGeoms().size() == 0 &&
487  m_graph->GetAllPyrGeoms ().size() == 0 &&
488  m_graph->GetAllHexGeoms ().size() == 0),
489  "LinearIdealMetric temperature only implemented for "
490  "two-dimensional triangular meshes or three-dimensional "
491  "tetrahedral meshes.");
492 
495 
496  for (nv = 0; nv < nVel; ++nv)
497  {
499  m_fields[nv]->GetNpoints(), 0.0);
501 
502  for (i = 0; i < nVel; ++i)
503  {
505  m_fields[nv]->GetNpoints(), 0.0);
506  }
507  }
508 
509  for (i = 0; i < m_fields[0]->GetExpSize(); ++i)
510  {
511  // Calculate element area
513  m_fields[0]->GetExp(i);
514  LibUtilities::PointsKeyVector pkey = exp->GetPointsKeys();
516  exp->GetMetricInfo()->GetDeriv(pkey);
517  int offset = m_fields[0]->GetPhys_Offset(i);
518 
519  DNekMat i2rm = MappingIdealToRef(exp->GetGeom());
520 
521  // Compute metric tensor
522  DNekMat jac (nVel, nVel, 0.0, eFULL);
523  DNekMat jacIdeal(nVel, nVel, 0.0, eFULL);
524  DNekMat metric (nVel, nVel, 0.0, eFULL);
525 
526  for (j = 0; j < deriv[0][0].size(); ++j)
527  {
528  for (k = 0; k < nVel; ++k)
529  {
530  for (l = 0; l < nVel; ++l)
531  {
532  jac(l,k) = deriv[k][l][j];
533  }
534  }
535 
536  jacIdeal = jac * i2rm;
537  metric = Transpose(jacIdeal) * jacIdeal;
538 
539  // Compute eigenvalues/eigenvectors of metric tensor using
540  // ideal mapping.
541  char jobvl = 'N', jobvr = 'V';
542  int worklen = 8*nVel, info;
543 
544  DNekMat eval (nVel, nVel, 0.0, eDIAGONAL);
545  DNekMat evec (nVel, nVel, 0.0, eFULL);
546  DNekMat evecinv(nVel, nVel, 0.0, eFULL);
547  Array<OneD, NekDouble> vl (nVel*nVel);
548  Array<OneD, NekDouble> work(worklen);
549  Array<OneD, NekDouble> wi (nVel);
550 
551  Lapack::Dgeev(jobvl, jobvr, nVel, metric.GetRawPtr(), nVel,
552  &(eval.GetPtr())[0], &wi[0], &vl[0], nVel,
553  &(evec.GetPtr())[0], nVel,
554  &work[0], worklen, info);
555 
556  evecinv = evec;
557  evecinv.Invert();
558 
559  // rescaling of the eigenvalues
560  for (nv = 0; nv < nVel; ++nv)
561  {
562  eval(nv,nv) = m_beta * (sqrt(eval(nv,nv)) - 1.0);
563  }
564 
565  DNekMat beta = evec * eval * evecinv;
566 
567  for (k = 0; k < nVel; ++k)
568  {
569  for (l = 0; l < nVel; ++l)
570  {
571  m_stress[k][l][offset+j] = beta(k,l);
572  }
573  }
574  }
575 
576  if (deriv[0][0].size() != exp->GetTotPoints())
577  {
579  for (k = 0; k < nVel; ++k)
580  {
581  for (l = 0; l < nVel; ++l)
582  {
583  Vmath::Fill(
584  exp->GetTotPoints(), m_stress[k][l][offset],
585  tmp = m_stress[k][l] + offset, 1);
586  }
587  }
588  }
589  }
590 
591  // Calculate divergence of stress tensor.
593  for (i = 0; i < nVel; ++i)
594  {
595  for (j = 0; j < nVel; ++j)
596  {
597  m_fields[i]->PhysDeriv(j, m_stress[i][j], tmpderiv);
598  Vmath::Vadd (m_fields[i]->GetNpoints(), tmpderiv, 1,
599  m_temperature[i], 1, m_temperature[i], 1);
600  }
601 
603  m_temperature[i], 1, forcing[i], 1);
604  }
605  }
606  else if (tempEval != "None")
607  {
608  ASSERTL0(false, "Unknown temperature form: " + tempEval);
609  }
610 
611  // Set up some temporary storage.
612  //
613  // - forCoeffs holds the forcing coefficients in a local ordering;
614  // however note that the ordering is different and dictated by the
615  // assembly map. We loop over each element, then the boundary degrees of
616  // freedom for u, boundary for v, followed by the interior for u and then
617  // interior for v.
618  // - inout holds the Dirichlet degrees of freedom in the local ordering,
619  // which have the boundary conditions imposed
620  Array<OneD, NekDouble> forCoeffs(nVel * nCoeffs, 0.0);
621  Array<OneD, NekDouble> inout (nVel * nCoeffs, 0.0);
622  Array<OneD, NekDouble> tmp (nCoeffs);
623 
624  for (nv = 0; nv < nVel; ++nv)
625  {
626  // Take the inner product of the forcing function.
627  m_fields[nv]->IProductWRTBase_IterPerExp(forcing[nv], tmp);
628 
629  // Impose Dirichlet condition on field which should be initialised
630  Array<OneD, NekDouble> loc_inout = m_fields[nv]->UpdateCoeffs();
631  m_fields[nv]->ImposeDirichletConditions(loc_inout);
632 
633  // Scatter forcing into RHS vector according to the ordering dictated in
634  // the comment above.
635  for (i = 0; i < m_fields[nv]->GetExpSize(); ++i)
636  {
637  int nBnd = m_bmap[i].size();
638  int nInt = m_imap[i].size();
639  int offset = m_fields[nv]->GetCoeff_Offset(i);
640 
641  for (j = 0; j < nBnd; ++j)
642  {
643  forCoeffs[nVel*offset + nv*nBnd + j] =
644  -1.0*tmp[offset+m_bmap[i][j]];
645  inout[nVel*offset + nv*nBnd + j] =
646  loc_inout[offset+m_bmap[i][j]];
647  }
648  for (j = 0; j < nInt; ++j)
649  {
650  forCoeffs[nVel*(offset + nBnd) + nv*nInt + j] =
651  -1.0*tmp[offset+m_imap[i][j]];
652  }
653  }
654  }
655 
656  //
657  // -- Perform solve
658  //
659  // Solve.
660  linSys->Solve(forCoeffs, inout, m_assemblyMap);
661 
662  //
663  // -- Postprocess
664  //
665 
666  // Scatter back to field degrees of freedom
667  for (nv = 0; nv < nVel; ++nv)
668  {
669  for (i = 0; i < m_fields[nv]->GetExpSize(); ++i)
670  {
671  int nBnd = m_bmap[i].size();
672  int nInt = m_imap[i].size();
673  int offset = m_fields[nv]->GetCoeff_Offset(i);
674 
675  for (j = 0; j < nBnd; ++j)
676  {
677  m_fields[nv]->UpdateCoeffs()[offset+m_bmap[i][j]] =
678  inout[nVel*offset + nv*nBnd + j];
679  }
680  for (j = 0; j < nInt; ++j)
681  {
682  m_fields[nv]->UpdateCoeffs()[offset+m_imap[i][j]] =
683  inout[nVel*(offset + nBnd) + nv*nInt + j];
684  }
685  }
686  m_fields[nv]->BwdTrans(m_fields[nv]->GetCoeffs(),
687  m_fields[nv]->UpdatePhys());
688  }
689 }
690 
691 /**
692  * @brief Given a block matrix for an element, construct its static condensation
693  * matrices.
694  *
695  * This routine essentially duplicates the logic present in many of the
696  * LocalRegions matrix generation routines to construct the statically condensed
697  * equivalent of mat to pass to the GlobalLinSys solver.
698  *
699  * @param n Element/block number.
700  * @param exp Pointer to expansion.
701  * @param mat Block matrix containing matrix operator.
702  */
704  const int n,
707 {
708  int i, j, k, l;
709  const int nVel = mat.GetRows();
710  const int nB = exp->NumBndryCoeffs();
711  const int nI = exp->GetNcoeffs() - nB;
712  const int nBnd = exp->NumBndryCoeffs() * nVel;
713  const int nInt = exp->GetNcoeffs() * nVel - nBnd;
714  const MatrixStorage s = eFULL; // Maybe look into doing symmetric
715  // version of this?
716 
718  MemoryManager<DNekMat>::AllocateSharedPtr(nBnd, nBnd, 0.0, s);
719  DNekMatSharedPtr B =
720  MemoryManager<DNekMat>::AllocateSharedPtr(nBnd, nInt, 0.0, s);
721  DNekMatSharedPtr C =
722  MemoryManager<DNekMat>::AllocateSharedPtr(nInt, nBnd, 0.0, s);
723  DNekMatSharedPtr D =
724  MemoryManager<DNekMat>::AllocateSharedPtr(nInt, nInt, 0.0, s);
725 
726  for (i = 0; i < nVel; ++i)
727  {
728  for (j = 0; j < nVel; ++j)
729  {
730  // Boundary-boundary and boundary-interior
731  for (k = 0; k < nB; ++k)
732  {
733  for (l = 0; l < nB; ++l)
734  {
735  (*A)(k + i*nB, l + j*nB) =
736  (*mat[i][j])(m_bmap[n][k], m_bmap[n][l]);
737  }
738 
739  for (l = 0; l < nI; ++l)
740  {
741  (*B)(k + i*nB, l + j*nI) =
742  (*mat[i][j])(m_bmap[n][k], m_imap[n][l]);
743  }
744  }
745 
746  // Interior-boundary / interior-interior
747  for (k = 0; k < nI; ++k)
748  {
749  for (l = 0; l < nB; ++l)
750  {
751  (*C)(k + i*nI, l + j*nB) =
752  (*mat[i][j])(m_imap[n][k], m_bmap[n][l]);
753  }
754 
755  for (l = 0; l < nI; ++l)
756  {
757  (*D)(k + i*nI, l + j*nI) =
758  (*mat[i][j])(m_imap[n][k], m_imap[n][l]);
759  }
760  }
761  }
762  }
763 
764  // Construct static condensation matrices.
765  D->Invert();
766  (*B) = (*B)*(*D);
767  (*A) = (*A) - (*B)*(*C);
768 
769  DNekScalMatSharedPtr tmp_mat;
770  m_schurCompl->SetBlock(
772  1.0, A));
773  m_BinvD ->SetBlock(
775  1.0, B));
776  m_C ->SetBlock(
778  1.0, C));
779  m_Dinv ->SetBlock(
781  1.0, D));
782 }
783 
784 /**
785  * @brief Construct a LaplacianIJ matrix for a given expansion.
786  *
787  * This routine constructs matrices whose entries contain the evaluation of
788  *
789  * \f[ \partial_{\tt k1} \phi_i \partial_{\tt k2} \phi_j \,dx \f]
790  */
792  const int k1,
793  const int k2,
794  const NekDouble scale,
796 {
797  const int nCoeffs = exp->GetNcoeffs();
798  const int nPhys = exp->GetTotPoints();
799  int i;
800 
802  nCoeffs, nCoeffs, 0.0, eFULL);
803 
804  Array<OneD, NekDouble> tmp2(nPhys);
805  Array<OneD, NekDouble> tmp3(nPhys);
806 
807  for (i = 0; i < nCoeffs; ++i)
808  {
809  Array<OneD, NekDouble> tmp1(nCoeffs, 0.0);
810  tmp1[i] = 1.0;
811 
812  exp->BwdTrans ( tmp1, tmp2);
813  exp->PhysDeriv (k1, tmp2, tmp3);
814  exp->IProductWRTDerivBase(k2, tmp3, tmp1);
815 
816  Vmath::Smul(
817  nCoeffs, scale, &tmp1[0], 1, &(ret->GetPtr())[0]+i*nCoeffs, 1);
818  }
819 
820  return ret;
821 }
822 
824  std::vector<Array<OneD, NekDouble> > &fieldcoeffs,
825  std::vector<std::string> &variables)
826 {
827  const int nVel = m_fields[0]->GetCoordim(0);
828  const int nCoeffs = m_fields[0]->GetNcoeffs();
829 
830  if (m_temperature.size() == 0)
831  {
832  return;
833  }
834 
835  for (int i = 0; i < nVel; ++i)
836  {
837  Array<OneD, NekDouble> tFwd(nCoeffs);
838  m_fields[i]->FwdTrans(m_temperature[i], tFwd);
839  fieldcoeffs.push_back(tFwd);
840  variables.push_back(
841  "ThermStressDiv" + boost::lexical_cast<std::string>(i));
842  }
843 
844  if (m_stress.size() == 0)
845  {
846  return;
847  }
848 
849  for (int i = 0; i < nVel; ++i)
850  {
851  for (int j = 0; j < nVel; ++j)
852  {
853  Array<OneD, NekDouble> tFwd(nCoeffs);
854  m_fields[i]->FwdTrans(m_stress[i][j], tFwd);
855  fieldcoeffs.push_back(tFwd);
856  variables.push_back(
857  "ThermStress"
858  + boost::lexical_cast<std::string>(i)
859  + boost::lexical_cast<std::string>(j));
860  }
861  }
862 }
863 
864 }
#define ASSERTL0(condition, msg)
Definition: ErrorUtil.hpp:216
Array< OneD, Array< OneD, unsigned int > > m_imap
Interior maps for each of the fields.
DNekScalBlkMatSharedPtr m_Dinv
Matrix of elemental components.
NekDouble m_nu
Poisson ratio.
void BuildMatrixSystem()
Build matrix system for linear elasticity equations.
void SetStaticCondBlock(const int n, const LocalRegions::ExpansionSharedPtr exp, Array< TwoD, DNekMatSharedPtr > &mat)
Given a block matrix for an element, construct its static condensation matrices.
Array< OneD, Array< OneD, NekDouble > > m_temperature
Storage for the temperature terms.
CoupledAssemblyMapSharedPtr m_assemblyMap
Assembly map for the coupled (u,v,w) system.
virtual void v_InitObject()
Set up the linear elasticity system.
DNekScalBlkMatSharedPtr m_BinvD
Matrix of elemental components.
virtual void v_GenerateSummary(SolverUtils::SummaryList &s)
Generate summary at runtime.
NekDouble m_beta
Parameter dictating amount of thermal stress to add.
DNekScalBlkMatSharedPtr m_schurCompl
Schur complement boundary-boundary matrix.
virtual void v_ExtraFldOutput(std::vector< Array< OneD, NekDouble > > &fieldcoeffs, std::vector< std::string > &variables)
NekDouble m_E
Young's modulus.
Array< OneD, Array< OneD, Array< OneD, NekDouble > > > m_stress
Storage for the thermal stress terms.
virtual void v_DoSolve()
Solve elliptic linear elastic system.
Array< OneD, Array< OneD, unsigned int > > m_bmap
Boundary maps for each of the fields.
DNekMatSharedPtr BuildLaplacianIJMatrix(const int k1, const int k2, const NekDouble scale, LocalRegions::ExpansionSharedPtr exp)
Construct a LaplacianIJ matrix for a given expansion.
DNekScalBlkMatSharedPtr m_C
Matrix of elemental components.
General purpose memory allocation routines with the ability to allocate from thread specific memory p...
static std::shared_ptr< DataType > AllocateSharedPtr(const Args &...args)
Allocate a shared pointer from the memory pool.
This class is the abstraction of a global continuous two- dimensional spectral/hp element expansion w...
Definition: ContField.h:56
A base class for describing how to solve specific equations.
SOLVER_UTILS_EXPORT void SessionSummary(SummaryList &vSummary)
Write out a session summary.
SpatialDomains::MeshGraphSharedPtr m_graph
Pointer to graph defining mesh.
Array< OneD, MultiRegions::ExpListSharedPtr > m_fields
Array holding all dependent variables.
LibUtilities::SessionReaderSharedPtr m_session
The session reader.
SOLVER_UTILS_EXPORT int GetNpoints()
virtual SOLVER_UTILS_EXPORT void v_InitObject()
Initialisation object for EquationSystem.
SOLVER_UTILS_EXPORT SessionFunctionSharedPtr GetFunction(std::string name, const MultiRegions::ExpListSharedPtr &field=MultiRegions::NullExpListSharedPtr, bool cache=false)
Get a SessionFunction by name.
static void Dgeev(const char &uplo, const char &lrev, const int &n, const double *a, const int &lda, double *wr, double *wi, double *rev, const int &ldr, double *lev, const int &ldv, double *work, const int &lwork, int &info)
Solve general real matrix eigenproblem.
Definition: Lapack.hpp:370
std::shared_ptr< SessionReader > SessionReaderSharedPtr
std::vector< PointsKey > PointsKeyVector
Definition: Points.h:246
std::shared_ptr< Expansion > ExpansionSharedPtr
Definition: Expansion.h:68
static PreconditionerSharedPtr NullPreconditionerSharedPtr
std::shared_ptr< GlobalLinSys > GlobalLinSysSharedPtr
Pointer to a GlobalLinSys object.
Definition: GlobalLinSys.h:50
std::shared_ptr< ContField > ContFieldSharedPtr
Definition: ContField.h:292
std::vector< std::pair< std::string, std::string > > SummaryList
Definition: Misc.h:46
EquationSystemFactory & GetEquationSystemFactory()
void AddSummaryItem(SummaryList &l, const std::string &name, const std::string &value)
Adds a summary item to the summary info list.
Definition: Misc.cpp:47
@ eDeformed
Geometry is curved or has non-constant factors.
std::shared_ptr< MeshGraph > MeshGraphSharedPtr
Definition: MeshGraph.h:174
std::shared_ptr< Geometry > GeometrySharedPtr
Definition: Geometry.h:53
std::map< StdRegions::VarCoeffType, Array< OneD, NekDouble > > VarCoeffMap
Definition: StdRegions.hpp:272
std::map< ConstFactorType, NekDouble > ConstFactorMap
Definition: StdRegions.hpp:314
The above copyright notice and this permission notice shall be included.
Definition: CoupledSolver.h:1
std::shared_ptr< DNekScalMat > DNekScalMatSharedPtr
NekMatrix< InnerMatrixType, BlockMatrixTag > Transpose(NekMatrix< InnerMatrixType, BlockMatrixTag > &rhs)
std::shared_ptr< DNekMat > DNekMatSharedPtr
Definition: NekTypeDefs.hpp:69
double NekDouble
DNekMat MappingIdealToRef(SpatialDomains::GeometrySharedPtr geom)
void Vadd(int n, const T *x, const int incx, const T *y, const int incy, T *z, const int incz)
Add vector z = x+y.
Definition: Vmath.cpp:322
void Smul(int n, const T alpha, const T *x, const int incx, T *y, const int incy)
Scalar multiply y = alpha*x.
Definition: Vmath.cpp:225
void Fill(int n, const T alpha, T *x, const int incx)
Fill a vector with a constant value.
Definition: Vmath.cpp:45
void Vcopy(int n, const T *x, const int incx, T *y, const int incy)
Definition: Vmath.cpp:1199
scalarT< T > sqrt(scalarT< T > in)
Definition: scalar.hpp:267