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