Nektar++
 All Classes Namespaces Files Functions Variables Typedefs Enumerations Enumerator Friends Macros Pages
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 #ifdef NEKTAR_USE_MPI
53 #endif
54 
55 #ifdef NEKTAR_USE_PETSC
57 #endif
58 
59 namespace Nektar
60 {
61 
63  RegisterCreatorFunction("LinearElasticSystem",
65 
66 /*
67  * @brief Generate mapping between a simplex and the reference element.
68  *
69  * Mapping that requires the coordinates of the three vertices (x,y) of the
70  * triangular element and outputs the function coefficients that defines the
71  * mapping to the reference element for each coordinate (xfunc and yfunc)
72  *
73  * @param x co-ordinates of triangle/tetrahedron
74  * @param xf components of mapping
75  */
77 {
78  int n = geom->GetNumVerts(), i, j;
79 
80  DNekMat map (n, n, 1.0, eFULL);
81  DNekMat mapref(n, n, 1.0, eFULL);
82 
83  // Extract coordinate information.
84  for (i = 0; i < n; ++i)
85  {
86  for (j = 0; j < n-1; ++j)
87  {
88  map(j,i) = (*geom->GetVertex(i))[j];
89  }
90  }
91 
92  // Set up reference triangle or tetrahedron mapping.
93  if (n == 3)
94  {
95  mapref(0,0) = -1.0; mapref(1,0) = -1.0;
96  mapref(0,1) = 1.0; mapref(1,1) = -1.0;
97  mapref(0,2) = -1.0; mapref(1,2) = 1.0;
98  }
99  else if (n == 4)
100  {
101  mapref(0,0) = -1.0; mapref(1,0) = -1.0; mapref(2,0) = -1.0;
102  mapref(0,1) = 1.0; mapref(1,1) = -1.0; mapref(2,1) = -1.0;
103  mapref(0,2) = -1.0; mapref(1,2) = 1.0; mapref(2,2) = -1.0;
104  mapref(0,3) = -1.0; mapref(1,3) = -1.0; mapref(2,3) = 1.0;
105  }
106 
107  map.Invert();
108 
109  DNekMat newmap = mapref * map;
110  DNekMat mapred(n-1, n-1, 1.0, eFULL);
111 
112  for (i = 0; i < n-1; ++i)
113  {
114  for (j = 0; j < n-1; ++j)
115  {
116  mapred(i,j) = newmap(i,j);
117  }
118  }
119 
120  return mapred;
121 }
122 
123 
124 /**
125  * @brief Default constructor.
126  */
128  const LibUtilities::SessionReaderSharedPtr& pSession)
129  : EquationSystem(pSession)
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 {
142  EquationSystem::v_InitObject();
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  if (nVel == 2)
158  {
159  MultiRegions::ContField2DSharedPtr u = boost::dynamic_pointer_cast<
163  m_graph,
164  u->GetLocalToGlobalMap(),
165  m_fields[0]->GetBndConditions(),
166  m_fields);
167  }
168 
169  if (nVel == 3)
170  {
171  MultiRegions::ContField3DSharedPtr u = boost::dynamic_pointer_cast<
175  m_graph,
176  u->GetLocalToGlobalMap(),
177  m_fields[0]->GetBndConditions(),
178  m_fields);
179  }
180 
181  // Figure out size of our new matrix systems by looping over all expansions
182  // and multiply number of coefficients by velocity components.
183  const int nEl = m_fields[0]->GetExpSize();
185 
186  Array<OneD, unsigned int> sizeBnd(nEl);
187  Array<OneD, unsigned int> sizeInt(nEl);
188 
189  // Allocate storage for boundary and interior map caches.
192 
193  // Cache interior and boundary maps to avoid recalculating
194  // constantly. Should really be handled by manager in StdRegions but not
195  // really working yet.
196  for (n = 0; n < nEl; ++n)
197  {
198  exp = m_fields[0]->GetExp(m_fields[0]->GetOffset_Elmt_Id(n));
199  sizeBnd[n] = nVel * exp->NumBndryCoeffs();
200  sizeInt[n] = nVel * exp->GetNcoeffs() - sizeBnd[n];
201  exp->GetBoundaryMap(m_bmap[n]);
202  exp->GetInteriorMap(m_imap[n]);
203  }
204 
205  // Create block matrix storage for the statically condensed system.
206  MatrixStorage blkmatStorage = eDIAGONAL;
208  sizeBnd, sizeBnd, blkmatStorage);
210  sizeBnd, sizeInt, blkmatStorage);
212  sizeInt, sizeBnd, blkmatStorage);
214  sizeInt, sizeInt, blkmatStorage);
215 }
216 
217 /**
218  * @brief Build matrix system for linear elasticity equations.
219  *
220  * This routine constructs the matrix discretisation arising from the weak
221  * formulation of the linear elasticity equations. The resulting matrix system
222  * is then passed to LinearElasticSystem::SetStaticCondBlock in order to
223  * construct the statically condensed system.
224  *
225  * All of the matrices involved in the construction of the divergence of the
226  * stress tensor are Laplacian-like. We use the variable coefficient
227  * functionality within the library to multiply the Laplacian by the appropriate
228  * constants for all diagonal terms, and off-diagonal terms use
229  * LinearElasticSystem::BuildLaplacianIJMatrix to construct matrices containing
230  *
231  * \f[ \int \partial_{x_i} \phi_k \partial_{x_j} \phi_l \f]
232  *
233  * where mixed derivative terms are present. Symmetry (in terms of k,l) is
234  * exploited to avoid constructing this matrix repeatedly.
235  *
236  * @todo Make static condensation optional and construct full system instead.
237  */
239 {
240  const int nEl = m_fields[0]->GetExpSize();
241  const int nVel = m_fields[0]->GetCoordim(0);
242 
244  int n;
245 
246  // Factors map for matrix keys.
248 
249  // Calculate various constants
250  NekDouble mu = m_E * 0.5 / (1.0 + m_nu);
251  NekDouble lambda = m_E * m_nu / (1.0 + m_nu) / (1.0 - 2.0*m_nu);
252 
253  bool verbose = m_session->DefinesCmdLineArgument("verbose");
254  bool root = m_session->GetComm()->GetRank() == 0;
255 
256  // Loop over each element and construct matrices.
257  if (nVel == 2)
258  {
259  for (n = 0; n < nEl; ++n)
260  {
261  exp = m_fields[0]->GetExp(m_fields[0]->GetOffset_Elmt_Id(n));
262  const int nPhys = exp->GetTotPoints();
263  Array<OneD, NekDouble> aArr(nPhys, lambda + 2*mu);
264  Array<OneD, NekDouble> bArr(nPhys, mu);
265 
266  StdRegions::VarCoeffMap varcoeffA, varcoeffD;
267  varcoeffA[StdRegions::eVarCoeffD00] = aArr;
268  varcoeffA[StdRegions::eVarCoeffD11] = bArr;
269  varcoeffD[StdRegions::eVarCoeffD00] = bArr;
270  varcoeffD[StdRegions::eVarCoeffD11] = aArr;
271 
273  exp->DetShapeType(),
274  *exp, factors, varcoeffA);
276  exp->DetShapeType(),
277  *exp, factors, varcoeffD);
278 
279  /*
280  * mat holds the linear operator [ A B ] acting on [ u ].
281  * [ C D ] [ v ]
282  */
284  mat[0][0] = exp->GenMatrix(matkeyA);
285  mat[0][1] = BuildLaplacianIJMatrix(1, 0, mu+lambda, exp);
286  mat[1][0] = mat[0][1];
287  mat[1][1] = exp->GenMatrix(matkeyD);
288 
289  // Set up the statically condensed block for this element.
290  SetStaticCondBlock(n, exp, mat);
291 
292  if (verbose && root)
293  {
294  cout << "\rBuilding matrix system: "
295  << (int)(100.0 * n / nEl) << "%" << flush;
296  }
297  }
298  }
299  else if (nVel == 3)
300  {
301  for (n = 0; n < nEl; ++n)
302  {
303  exp = m_fields[0]->GetExp(m_fields[0]->GetOffset_Elmt_Id(n));
304  const int nPhys = exp->GetTotPoints();
305  Array<OneD, NekDouble> aArr(nPhys, lambda + 2*mu);
306  Array<OneD, NekDouble> bArr(nPhys, mu);
307 
308  StdRegions::VarCoeffMap varcoeffA, varcoeffE, varcoeffI;
309  varcoeffA[StdRegions::eVarCoeffD00] = aArr;
310  varcoeffA[StdRegions::eVarCoeffD11] = bArr;
311  varcoeffA[StdRegions::eVarCoeffD22] = bArr;
312  varcoeffE[StdRegions::eVarCoeffD00] = bArr;
313  varcoeffE[StdRegions::eVarCoeffD11] = aArr;
314  varcoeffE[StdRegions::eVarCoeffD22] = bArr;
315  varcoeffI[StdRegions::eVarCoeffD00] = bArr;
316  varcoeffI[StdRegions::eVarCoeffD11] = bArr;
317  varcoeffI[StdRegions::eVarCoeffD22] = aArr;
318 
320  exp->DetShapeType(),
321  *exp, factors, varcoeffA);
323  exp->DetShapeType(),
324  *exp, factors, varcoeffE);
326  exp->DetShapeType(),
327  *exp, factors, varcoeffI);
328 
329  /*
330  * mat holds the linear operator [ A B C ] acting on [ u ].
331  * [ D E F ] [ v ]
332  * [ G H I ] [ w ]
333  */
335  mat[0][0] = exp->GenMatrix(matkeyA);
336  mat[0][1] = BuildLaplacianIJMatrix(1, 0, mu + lambda, exp);
337  mat[0][2] = BuildLaplacianIJMatrix(2, 0, mu + lambda, exp);
338 
339  mat[1][0] = mat[0][1];
340  mat[1][1] = exp->GenMatrix(matkeyE);
341  mat[1][2] = BuildLaplacianIJMatrix(2, 1, mu + lambda, exp);
342 
343  mat[2][0] = mat[0][2];
344  mat[2][1] = mat[1][2];
345  mat[2][2] = exp->GenMatrix(matkeyI);
346 
347  // Set up the statically condensed block for this element.
348  SetStaticCondBlock(n, exp, mat);
349 
350  if (verbose && root)
351  {
352  cout << "\rBuilding matrix system: "
353  << (int)(100.0 * n / nEl) << "%" << flush;
354  }
355  }
356  }
357 
358  if (verbose && root)
359  {
360  cout << "\rBuilding matrix system: done." << endl;
361  }
362 }
363 
364 /**
365  * @brief Generate summary at runtime.
366  */
368 {
369  EquationSystem::SessionSummary(s);
370 
371  AddSummaryItem(s, "Young's modulus", m_E);
372  AddSummaryItem(s, "Poisson ratio", m_nu);
373 }
374 
375 /**
376  * @brief Solve elliptic linear elastic system.
377  *
378  * The solve proceeds as follows:
379  *
380  * - Create a MultiRegions::GlobalLinSys object.
381  * - Evaluate a forcing function from the session file.
382  * - If the temperature term is enabled, evaluate this and add to forcing.
383  * - Apply Dirichlet boundary conditions.
384  * - Scatter forcing into the correct ordering according to the coupled
385  * assembly map.
386  * - Do the solve.
387  * - Scatter solution back to fields and backwards transform to physical space.
388  */
390 {
391 
392  int i, j, k, l, nv;
393  const int nVel = m_fields[0]->GetCoordim(0);
394 
395  // Build initial matrix system.
397 
398  // Now we've got the matrix system set up, create a GlobalLinSys
399  // object. We mask ourselves as LinearAdvectionReaction to create a full
400  // matrix instead of symmetric storage.
404 
405  // Currently either direct or iterative static condensation is
406  // supported.
407  if (m_assemblyMap->GetGlobalSysSolnType() == MultiRegions::eDirectStaticCond)
408  {
409  linSys = MemoryManager<
410  MultiRegions::GlobalLinSysDirectStaticCond>::AllocateSharedPtr(
411  key, m_fields[0], m_schurCompl, m_BinvD, m_C, m_Dinv,
412  m_assemblyMap);
413  }
414  else if (m_assemblyMap->GetGlobalSysSolnType() ==
416  {
417  linSys = MemoryManager<
419  key, m_fields[0], m_schurCompl, m_BinvD, m_C, m_Dinv,
421  }
422 #ifdef NEKTAR_USE_PETSC
423  else if (m_assemblyMap->GetGlobalSysSolnType() ==
425  {
426  linSys = MemoryManager<
427  MultiRegions::GlobalLinSysPETScStaticCond>::AllocateSharedPtr(
428  key, m_fields[0], m_schurCompl, m_BinvD, m_C, m_Dinv,
429  m_assemblyMap);
430  }
431 #endif
432 #ifdef NEKTAR_USE_MPI
433  else if (m_assemblyMap->GetGlobalSysSolnType() ==
435  {
436  linSys = MemoryManager<
437  MultiRegions::GlobalLinSysXxtStaticCond>::AllocateSharedPtr(
438  key, m_fields[0], m_schurCompl, m_BinvD, m_C, m_Dinv,
439  m_assemblyMap);
440  }
441 #endif
442 
443  linSys->Initialise(m_assemblyMap);
444 
445  const int nCoeffs = m_fields[0]->GetNcoeffs();
446  const int nGlobDofs = m_assemblyMap->GetNumGlobalCoeffs();
447 
448  //
449  // -- Evaluate forcing functions
450  //
451 
452  // Evaluate the forcing function from the XML file.
453  Array<OneD, Array<OneD, NekDouble> > forcing(nVel);
454  EvaluateFunction(forcing, "Forcing");
455 
456  // Add temperature term
457  string tempEval;
458  m_session->LoadSolverInfo("Temperature", tempEval, "None");
459 
460  if (tempEval == "Jacobian")
461  {
462  // Allocate storage
464 
465  for (nv = 0; nv < nVel; ++nv)
466  {
469  m_fields[nv]->GetNpoints());
470 
471  for (i = 0; i < m_fields[0]->GetExpSize(); ++i)
472  {
473  // Calculate element area
475  m_fields[0]->GetExp(i);
477  exp->GetPointsKeys();
479  exp->GetMetricInfo()->GetJac(pkey);
480 
481  int offset = m_fields[0]->GetPhys_Offset(i);
482 
483  if (exp->GetMetricInfo()->GetGtype() ==
485  {
486  Vmath::Smul(exp->GetTotPoints(), m_beta, jac, 1,
487  tmp = m_temperature[nv] + offset, 1);
488  }
489  else
490  {
491  Vmath::Fill(exp->GetTotPoints(), m_beta*jac[0],
492  tmp = m_temperature[nv] + offset, 1);
493  }
494  }
495  m_fields[nv]->PhysDeriv(nv, m_temperature[nv], forcing[nv]);
496  }
497  }
498  else if (tempEval == "Metric")
499  {
500  ASSERTL0((m_fields[0]->GetCoordim(0) == 2 &&
501  m_graph->GetAllQuadGeoms().size() == 0) ||
502  (m_fields[0]->GetCoordim(0) == 3 &&
503  m_graph->GetAllPrismGeoms().size() == 0 &&
504  m_graph->GetAllPyrGeoms ().size() == 0 &&
505  m_graph->GetAllHexGeoms ().size() == 0),
506  "LinearIdealMetric temperature only implemented for "
507  "two-dimensional triangular meshes or three-dimensional "
508  "tetrahedral meshes.");
509 
512 
513  for (nv = 0; nv < nVel; ++nv)
514  {
516  m_fields[nv]->GetNpoints(), 0.0);
517  m_stress[nv] = Array<OneD, Array<OneD, NekDouble> >(nVel);
518 
519  for (i = 0; i < nVel; ++i)
520  {
521  m_stress[nv][i] = Array<OneD, NekDouble>(
522  m_fields[nv]->GetNpoints(), 0.0);
523  }
524  }
525 
526  for (i = 0; i < m_fields[0]->GetExpSize(); ++i)
527  {
528  // Calculate element area
530  m_fields[0]->GetExp(i);
531  LibUtilities::PointsKeyVector pkey = exp->GetPointsKeys();
533  exp->GetMetricInfo()->GetDeriv(pkey);
534  int offset = m_fields[0]->GetPhys_Offset(i);
535 
536  DNekMat i2rm = MappingIdealToRef(exp->GetGeom());
537 
538  // Compute metric tensor
539  DNekMat jac (nVel, nVel, 0.0, eFULL);
540  DNekMat jacIdeal(nVel, nVel, 0.0, eFULL);
541  DNekMat metric (nVel, nVel, 0.0, eFULL);
542 
543  for (j = 0; j < deriv[0][0].num_elements(); ++j)
544  {
545  for (k = 0; k < nVel; ++k)
546  {
547  for (l = 0; l < nVel; ++l)
548  {
549  jac(l,k) = deriv[k][l][j];
550  }
551  }
552 
553  jacIdeal = jac * i2rm;
554  metric = Transpose(jacIdeal) * jacIdeal;
555 
556  // Compute eigenvalues/eigenvectors of metric tensor using
557  // ideal mapping.
558  char jobvl = 'N', jobvr = 'V';
559  int worklen = 8*nVel, info;
560 
561  DNekMat eval (nVel, nVel, 0.0, eDIAGONAL);
562  DNekMat evec (nVel, nVel, 0.0, eFULL);
563  DNekMat evecinv(nVel, nVel, 0.0, eFULL);
564  Array<OneD, NekDouble> vl (nVel*nVel);
565  Array<OneD, NekDouble> work(worklen);
566  Array<OneD, NekDouble> wi (nVel);
567 
568  Lapack::Dgeev(jobvl, jobvr, nVel, metric.GetRawPtr(), nVel,
569  &(eval.GetPtr())[0], &wi[0], &vl[0], nVel,
570  &(evec.GetPtr())[0], nVel,
571  &work[0], worklen, info);
572 
573  evecinv = evec;
574  evecinv.Invert();
575 
576  // rescaling of the eigenvalues
577  for (nv = 0; nv < nVel; ++nv)
578  {
579  eval(nv,nv) = m_beta * (sqrt(eval(nv,nv)) - 1.0);
580  }
581 
582  DNekMat beta = evec * eval * evecinv;
583 
584  for (k = 0; k < nVel; ++k)
585  {
586  for (l = 0; l < nVel; ++l)
587  {
588  m_stress[k][l][offset+j] = beta(k,l);
589  }
590  }
591  }
592 
593  if (deriv[0][0].num_elements() != exp->GetTotPoints())
594  {
596  for (k = 0; k < nVel; ++k)
597  {
598  for (l = 0; l < nVel; ++l)
599  {
600  Vmath::Fill(
601  exp->GetTotPoints(), m_stress[k][l][offset],
602  tmp = m_stress[k][l] + offset, 1);
603  }
604  }
605  }
606  }
607 
608  // Calculate divergence of stress tensor.
610  for (i = 0; i < nVel; ++i)
611  {
612  for (j = 0; j < nVel; ++j)
613  {
614  m_fields[i]->PhysDeriv(j, m_stress[i][j], tmpderiv);
615  Vmath::Vadd (m_fields[i]->GetNpoints(), tmpderiv, 1,
616  m_temperature[i], 1, m_temperature[i], 1);
617  }
618 
620  m_temperature[i], 1, forcing[i], 1);
621  }
622  }
623  else if (tempEval != "None")
624  {
625  ASSERTL0(false, "Unknown temperature form: " + tempEval);
626  }
627 
628  // Set up some temporary storage.
629  //
630  // - forCoeffs holds the forcing coefficients in a local ordering;
631  // however note that the ordering is different and dictated by the
632  // assembly map. We loop over each element, then the boundary degrees of
633  // freedom for u, boundary for v, followed by the interior for u and then
634  // interior for v.
635  // - rhs is the global assembly of forCoeffs.
636  // - inout holds the Dirichlet degrees of freedom in the global ordering,
637  // which have been assembled from the boundary expansion.
638  Array<OneD, NekDouble> forCoeffs(nVel * nCoeffs, 0.0);
639  Array<OneD, NekDouble> inout (nGlobDofs, 0.0);
640  Array<OneD, NekDouble> rhs (nGlobDofs, 0.0);
641 
642  for (nv = 0; nv < nVel; ++nv)
643  {
644  // Take the inner product of the forcing function.
645  Array<OneD, NekDouble> tmp(nCoeffs);
646  m_fields[nv]->IProductWRTBase_IterPerExp(forcing[nv], tmp);
647 
648  // Scatter forcing into RHS vector according to the ordering dictated in
649  // the comment above.
650  for (i = 0; i < m_fields[nv]->GetExpSize(); ++i)
651  {
652  int nBnd = m_bmap[i].num_elements();
653  int nInt = m_imap[i].num_elements();
654  int offset = m_fields[nv]->GetCoeff_Offset(i);
655 
656  for (j = 0; j < nBnd; ++j)
657  {
658  forCoeffs[nVel*offset + nv*nBnd + j] =
659  tmp[offset+m_bmap[i][j]];
660  }
661  for (j = 0; j < nInt; ++j)
662  {
663  forCoeffs[nVel*(offset + nBnd) + nv*nInt + j] =
664  tmp[offset+m_imap[i][j]];
665  }
666  }
667  }
668 
669  // -- Impose Dirichlet boundary conditions.
670 
671  // First try to do parallel assembly: the intention here is that Dirichlet
672  // values at some edges/vertices need to be communicated to processes which
673  // don't contain the entire boundary region. See
674  // ContField2D::v_ImposeDirichletConditions for more detail.
675  map<int, vector<MultiRegions::ExtraDirDof> > &extraDirDofs =
676  m_assemblyMap->GetExtraDirDofs();
677  map<int, vector<MultiRegions::ExtraDirDof> >::iterator it;
678 
679  for (nv = 0; nv < nVel; ++nv)
680  {
682  = m_fields[nv]->GetBndCondExpansions();
683 
684  // First try to do parallel stuff
685  for (it = extraDirDofs.begin(); it != extraDirDofs.end(); ++it)
686  {
687  for (i = 0; i < it->second.size(); ++i)
688  {
689  inout[it->second.at(i).get<1>()*nVel + nv] =
690  bndCondExp[it->first]->GetCoeffs()[
691  it->second.at(i).get<0>()]*it->second.at(i).get<2>();
692  }
693  }
694  }
695 
696  m_assemblyMap->UniversalAssemble(inout);
697 
698  // Counter for the local Dirichlet boundary to global ordering.
699  int bndcnt = 0;
700 
701  // Now assemble local boundary contributions.
702  for (nv = 0; nv < nVel; ++nv)
703  {
705  = m_fields[nv]->GetBndCondExpansions();
706  const Array<OneD, const int> &bndMap
707  = m_assemblyMap->GetBndCondCoeffsToGlobalCoeffsMap();
708 
709  for (i = 0; i < bndCondExp.num_elements(); ++i)
710  {
711  if (m_fields[nv]->GetBndConditions()[i]->GetBoundaryConditionType()
713  {
714  const Array<OneD,const NekDouble> &bndCoeffs =
715  bndCondExp[i]->GetCoeffs();
716 
717  for (j = 0; j < bndCondExp[i]->GetNcoeffs(); ++j)
718  {
719  NekDouble sign =
720  m_assemblyMap->GetBndCondCoeffsToGlobalCoeffsSign(
721  bndcnt);
722  inout[bndMap[bndcnt++]] = sign * bndCoeffs[j];
723  }
724  }
725  else
726  {
727  bndcnt += bndCondExp[i]->GetNcoeffs();
728  }
729  }
730  }
731 
732  //
733  // -- Perform solve
734  //
735 
736  // Assemble forcing into the RHS.
737  m_assemblyMap->Assemble(forCoeffs, rhs);
738 
739  // Negate RHS to be consistent with matrix definition.
740  Vmath::Neg(rhs.num_elements(), rhs, 1);
741 
742  // Solve.
743  linSys->Solve(rhs, inout, m_assemblyMap);
744 
745  // Scatter the global ordering back to the alternate local ordering.
746  Array<OneD, NekDouble> tmp(nVel * nCoeffs);
747  m_assemblyMap->GlobalToLocal(inout, tmp);
748 
749  //
750  // -- Postprocess
751  //
752 
753  // Scatter back to field degrees of freedom
754  for (nv = 0; nv < nVel; ++nv)
755  {
756  for (i = 0; i < m_fields[nv]->GetExpSize(); ++i)
757  {
758  int nBnd = m_bmap[i].num_elements();
759  int nInt = m_imap[i].num_elements();
760  int offset = m_fields[nv]->GetCoeff_Offset(i);
761 
762  for (j = 0; j < nBnd; ++j)
763  {
764  m_fields[nv]->UpdateCoeffs()[offset+m_bmap[i][j]] =
765  tmp[nVel*offset + nv*nBnd + j];
766  }
767  for (j = 0; j < nInt; ++j)
768  {
769  m_fields[nv]->UpdateCoeffs()[offset+m_imap[i][j]] =
770  tmp[nVel*(offset + nBnd) + nv*nInt + j];
771  }
772  }
773  m_fields[nv]->BwdTrans(m_fields[nv]->GetCoeffs(),
774  m_fields[nv]->UpdatePhys());
775  }
776 }
777 
778 /**
779  * @brief Given a block matrix for an element, construct its static condensation
780  * matrices.
781  *
782  * This routine essentially duplicates the logic present in many of the
783  * LocalRegions matrix generation routines to construct the statically condensed
784  * equivalent of mat to pass to the GlobalLinSys solver.
785  *
786  * @param n Element/block number.
787  * @param exp Pointer to expansion.
788  * @param mat Block matrix containing matrix operator.
789  */
791  const int n,
794 {
795  int i, j, k, l;
796  const int nVel = mat.GetRows();
797  const int nB = exp->NumBndryCoeffs();
798  const int nI = exp->GetNcoeffs() - nB;
799  const int nBnd = exp->NumBndryCoeffs() * nVel;
800  const int nInt = exp->GetNcoeffs() * nVel - nBnd;
801  const MatrixStorage s = eFULL; // Maybe look into doing symmetric
802  // version of this?
803 
804  DNekMatSharedPtr A =
805  MemoryManager<DNekMat>::AllocateSharedPtr(nBnd, nBnd, 0.0, s);
806  DNekMatSharedPtr B =
807  MemoryManager<DNekMat>::AllocateSharedPtr(nBnd, nInt, 0.0, s);
808  DNekMatSharedPtr C =
809  MemoryManager<DNekMat>::AllocateSharedPtr(nInt, nBnd, 0.0, s);
810  DNekMatSharedPtr D =
811  MemoryManager<DNekMat>::AllocateSharedPtr(nInt, nInt, 0.0, s);
812 
813  for (i = 0; i < nVel; ++i)
814  {
815  for (j = 0; j < nVel; ++j)
816  {
817  // Boundary-boundary and boundary-interior
818  for (k = 0; k < nB; ++k)
819  {
820  for (l = 0; l < nB; ++l)
821  {
822  (*A)(k + i*nB, l + j*nB) =
823  (*mat[i][j])(m_bmap[n][k], m_bmap[n][l]);
824  }
825 
826  for (l = 0; l < nI; ++l)
827  {
828  (*B)(k + i*nB, l + j*nI) =
829  (*mat[i][j])(m_bmap[n][k], m_imap[n][l]);
830  }
831  }
832 
833  // Interior-boundary / interior-interior
834  for (k = 0; k < nI; ++k)
835  {
836  for (l = 0; l < nB; ++l)
837  {
838  (*C)(k + i*nI, l + j*nB) =
839  (*mat[i][j])(m_imap[n][k], m_bmap[n][l]);
840  }
841 
842  for (l = 0; l < nI; ++l)
843  {
844  (*D)(k + i*nI, l + j*nI) =
845  (*mat[i][j])(m_imap[n][k], m_imap[n][l]);
846  }
847  }
848  }
849  }
850 
851  // Construct static condensation matrices.
852  D->Invert();
853  (*B) = (*B)*(*D);
854  (*A) = (*A) - (*B)*(*C);
855 
856  DNekScalMatSharedPtr tmp_mat;
857  m_schurCompl->SetBlock(
859  1.0, A));
860  m_BinvD ->SetBlock(
862  1.0, B));
863  m_C ->SetBlock(
865  1.0, C));
866  m_Dinv ->SetBlock(
868  1.0, D));
869 }
870 
871 /**
872  * @brief Construct a LaplacianIJ matrix for a given expansion.
873  *
874  * This routine constructs matrices whose entries contain the evaluation of
875  *
876  * \f[ \partial_{\tt k1} \phi_i \partial_{\tt k2} \phi_j \,dx \f]
877  */
879  const int k1,
880  const int k2,
881  const NekDouble scale,
883 {
884  const int nCoeffs = exp->GetNcoeffs();
885  const int nPhys = exp->GetTotPoints();
886  int i;
887 
889  nCoeffs, nCoeffs, 0.0, eFULL);
890 
891  Array<OneD, NekDouble> tmp2(nPhys);
892  Array<OneD, NekDouble> tmp3(nPhys);
893 
894  for (i = 0; i < nCoeffs; ++i)
895  {
896  Array<OneD, NekDouble> tmp1(nCoeffs, 0.0);
897  tmp1[i] = 1.0;
898 
899  exp->BwdTrans ( tmp1, tmp2);
900  exp->PhysDeriv (k1, tmp2, tmp3);
901  exp->IProductWRTDerivBase(k2, tmp3, tmp1);
902 
903  Vmath::Smul(
904  nCoeffs, scale, &tmp1[0], 1, &(ret->GetPtr())[0]+i*nCoeffs, 1);
905  }
906 
907  return ret;
908 }
909 
911  std::vector<Array<OneD, NekDouble> > &fieldcoeffs,
912  std::vector<std::string> &variables)
913 {
914  const int nVel = m_fields[0]->GetCoordim(0);
915  const int nCoeffs = m_fields[0]->GetNcoeffs();
916 
917  if (m_temperature.num_elements() == 0)
918  {
919  return;
920  }
921 
922  for (int i = 0; i < nVel; ++i)
923  {
924  Array<OneD, NekDouble> tFwd(nCoeffs);
925  m_fields[i]->FwdTrans(m_temperature[i], tFwd);
926  fieldcoeffs.push_back(tFwd);
927  variables.push_back(
928  "ThermStressDiv" + boost::lexical_cast<std::string>(i));
929  }
930 
931  if (m_stress.num_elements() == 0)
932  {
933  return;
934  }
935 
936  for (int i = 0; i < nVel; ++i)
937  {
938  for (int j = 0; j < nVel; ++j)
939  {
940  Array<OneD, NekDouble> tFwd(nCoeffs);
941  m_fields[i]->FwdTrans(m_stress[i][j], tFwd);
942  fieldcoeffs.push_back(tFwd);
943  variables.push_back(
944  "ThermStress"
945  + boost::lexical_cast<std::string>(i)
946  + boost::lexical_cast<std::string>(j));
947  }
948  }
949 }
950 
951 }
static EquationSystemSharedPtr create(const LibUtilities::SessionReaderSharedPtr &pSession)
Creates an instance of this class.
#define ASSERTL0(condition, msg)
Definition: ErrorUtil.hpp:161
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:293
std::map< ConstFactorType, NekDouble > ConstFactorMap
Definition: StdRegions.hpp:251
DNekScalBlkMatSharedPtr m_BinvD
Matrix of elemental components.
boost::shared_ptr< DNekMat > DNekMatSharedPtr
Definition: NekTypeDefs.hpp:70
boost::shared_ptr< SessionReader > SessionReaderSharedPtr
Definition: MeshPartition.h:51
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:226
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.
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
boost::shared_ptr< Expansion > ExpansionSharedPtr
Definition: Expansion.h:68
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.
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:52
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:191
DNekMat MappingIdealToRef(SpatialDomains::GeometrySharedPtr geom)
void Vcopy(int n, const T *x, const int incx, T *y, const int incy)
Definition: Vmath.cpp:1047
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