Nektar++
ProcessPhiFromFile.cpp
Go to the documentation of this file.
1 ///////////////////////////////////////////////////////////////////////////////
2 //
3 // File: ProcessPhiFromFile.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: Reads an STL file.
32 //
33 ///////////////////////////////////////////////////////////////////////////////
34 
35 #include "ProcessPhiFromFile.h"
38 #include <boost/core/ignore_unused.hpp>
39 
40 using namespace Nektar;
41 using namespace std;
42 
43 namespace Nektar
44 {
45 namespace FieldUtils
46 {
47 
48 ModuleKey ProcessPhiFromFile::m_className = {
50  ModuleKey(eProcessModule, "phifile"), ProcessPhiFromFile::create,
51  "Computes the Phi function from a file, used in IB methods.")};
52 
53 /**
54  * @brief Set up ProcessPhiFromFile object.
55  *
56  */
57 ProcessPhiFromFile::ProcessPhiFromFile(FieldSharedPtr f) : ProcessModule(f)
58 {
59  m_config["scale"] =
60  ConfigOption(false, "NotSet", "Scale coefficient for Phi.");
61  m_config["file"] =
62  ConfigOption(false, "NotSet", "File with the IB definition.");
63 }
64 
65 /**
66  *
67  */
69 {
70 }
71 
72 /**
73  *
74  */
75 void ProcessPhiFromFile::v_Process(po::variables_map &vm)
76 {
77  // Ignore warnings due to 'vm'
78  boost::ignore_unused(vm);
79 
80  // Do not run in parallel
81  ASSERTL0(m_f->m_session->GetComm()->GetSpaceComm()->IsSerial(),
82  "Parallel execution is "
83  "not supported yet in "
84  "this module.")
85 
86  // Check if required params are defined
87  ASSERTL0(m_f->m_graph, "A session file file must be provided before the "
88  "STL file.")
89 
90  // Skip in case of empty partition
91  if (m_f->m_exp[0]->GetNumElmts() == 0)
92  {
93  return;
94  }
95 
96  // Read Phi function from the session file...
97  if (m_config["file"].as<string>().compare("NotSet") == 0)
98  {
99  WARNINGL0(m_config["scale"].as<string>().compare("NotSet") == 0,
100  "Reading Phi function from session file, the provided scale "
101  "value will not be used");
103  }
104  // ...or Read STL file and append Phi values to the existing expansions
105  else
106  {
107  ASSERTL0(m_config["scale"].as<string>().compare("NotSet") != 0,
108  "Need to specify a scale coefficient, scale=value");
109 
110  STLobject phiFile = ReadSTL(m_config["file"].as<string>());
111  GetPhifromSTL(phiFile);
112  }
113 }
114 
115 /**
116  * @brief Read one 3D vector from a STL file, starting from the next line
117  * of the input 'ifstream'. Numbers in ifstream are defined as 'float'
118  *
119  * @param in
120  * @return Array<OneD, NekDouble>
121  */
123 {
124  Array<OneD, NekDouble> out(3, 0.0);
125  float tmp;
126  char buf[4];
127 
128  in.read(buf, sizeof(buf));
129  memcpy(&tmp, buf, sizeof(buf));
130  out[0] = tmp;
131  in.read(buf, sizeof(buf));
132  memcpy(&tmp, buf, sizeof(buf));
133  out[1] = tmp;
134  in.read(buf, sizeof(buf));
135  memcpy(&tmp, buf, sizeof(buf));
136  out[2] = tmp;
137 
138  return out;
139 }
140 
141 /**
142  * @brief Read an STL binary file and returns a struct of type 'STLobject'
143  * containing the parsed data
144  *
145  * @param filename
146  * @return ProcessPhiFromFile::STLobject
147  */
149 {
150  STLobject out;
151 
152  // Open file
153  ifstream fileStl(filename.c_str(), ios::binary);
154  ASSERTL0(fileStl, "An error occurred while trying to open the STL file.")
155 
156  // Buffers
157  char headerBuf[80];
158  char numTriBuf[4];
159  char dumpBuf[2];
160 
161  // Read header and num of triangles
162  fileStl.read(headerBuf, sizeof(headerBuf));
163  fileStl.read(numTriBuf, sizeof(numTriBuf));
164  memcpy(&out.numTri, numTriBuf, sizeof(numTriBuf));
165 
166  // Read triangle data
168  for (NekUInt32 i = 0; i < out.numTri; ++i)
169  {
170  // Read normal vector
171  triangle tmpTri;
172  tmpTri.normal = ReadVector(fileStl);
173 
174  // Read three vertices
175  tmpTri.v0 = ReadVector(fileStl);
176  tmpTri.v1 = ReadVector(fileStl);
177  tmpTri.v2 = ReadVector(fileStl);
178 
179  // Add centroid to the triangle object
180  Array<OneD, NekDouble> centre(3);
181  centre[0] = (tmpTri.v0[0] + tmpTri.v1[0] + tmpTri.v2[0]) / 3.0;
182  centre[1] = (tmpTri.v0[1] + tmpTri.v1[1] + tmpTri.v2[1]) / 3.0;
183  centre[2] = (tmpTri.v0[2] + tmpTri.v1[2] + tmpTri.v2[2]) / 3.0;
184  tmpTri.centroid = centre;
185 
186  out.triangles[i] = tmpTri;
187 
188  // Dump triangle type
189  fileStl.read(dumpBuf, sizeof(dumpBuf));
190  }
191 
192  // Close the file
193  fileStl.close();
194 
195  return out;
196 }
197 
198 /**
199  * @brief Smoothing function for the SPM method given a distance value
200  * and a scaling coefficient
201  *
202  * @param dist
203  * @param coeff
204  * @return NekDouble
205  */
206 NekDouble ProcessPhiFromFile::PhiFunction(double dist, double coeff)
207 {
208  return -0.5 * (std::tanh(dist / coeff) - 1.0);
209 }
210 
211 /**
212  * @brief Assigns to 'phi' the values indicated by 'ShapeFunction'
213  *
214  */
216 {
217  // Check that 'ShapeFunction' appears in the session file
218  ASSERTL0(m_f->m_session->DefinesFunction("ShapeFunction"),
219  "If file=file.stl is not supplied as an argument, a "
220  "'ShapeFunction' block must be provided in the session "
221  "file.")
222 
223  // Phi function in session file
224  LibUtilities::EquationSharedPtr phiFunction =
225  m_f->m_session->GetFunction("ShapeFunction", "Phi");
226 
227  // Get info about the domain
228  int nPts = m_f->m_exp[0]->GetNpoints();
229  int nVars = m_f->m_variables.size();
230  int nStrips;
231  m_f->m_session->LoadParameter("Strip_Z", nStrips, 1);
232 
233  // Add new variable
234  m_f->m_variables.push_back("phi");
235 
236  for (int s = 0; s < nStrips; ++s) // homogeneous strip varient
237  {
239  m_f->AppendExpList(m_f->m_numHomogeneousDir);
240  auto it = m_f->m_exp.begin() + s * (nVars + 1) + nVars;
241  m_f->m_exp.insert(it, Exp);
242  }
243 
244  for (int s = 0; s < nStrips; ++s)
245  {
246  // Get current coords of the point
248  for (int i = 0; i < 3; ++i)
249  {
250  coords[i] = Array<OneD, NekDouble>(nPts, 0.0);
251  }
252  m_f->m_exp[s * nVars]->GetCoords(coords[0], coords[1], coords[2]);
253 
254  // Append Phi expansion to 'm_f'
255  int fid = s * (nVars + 1) + nVars;
256 
257  phiFunction->Evaluate(coords[0], coords[1], coords[2],
258  m_f->m_exp[fid]->UpdatePhys());
259  m_f->m_exp[fid]->FwdTrans(m_f->m_exp[fid]->GetPhys(),
260  m_f->m_exp[fid]->UpdateCoeffs());
261  }
262 }
263 
264 /**
265  * @brief Assigns to 'phi' the corresponding values of Phi
266  *
267  * @param file
268  */
270  const ProcessPhiFromFile::STLobject &file)
271 {
272  // Get info about the domain
273  int nPts = m_f->m_exp[0]->GetNpoints();
274  int nVars = m_f->m_variables.size();
275 
276  // Get coordinates
278  for (int i = 0; i < 3; ++i)
279  {
280  coords[i] = Array<OneD, NekDouble>(nPts, 0.0);
281  }
282  m_f->m_exp[0]->GetCoords(coords[0], coords[1], coords[2]);
283 
284  // Add new variable
285  m_f->m_variables.push_back("phi");
286 
287  // Number of homogeneous strips
288  int nStrips;
289  m_f->m_session->LoadParameter("Strip_Z", nStrips, 1);
290 
291  // Find bounds of the mesh
292  Array<OneD, NekDouble> bounds(6);
293  bounds[0] = coords[0][0];
294  bounds[1] = coords[0][0];
295  bounds[2] = coords[1][0];
296  bounds[3] = coords[1][0];
297  bounds[4] = coords[2][0];
298  bounds[5] = coords[2][0];
299  for (int i = 1; i < nPts; ++i)
300  {
301  bounds[0] = (bounds[0] < coords[0][i]) ? bounds[0] : coords[0][i];
302  bounds[1] = (bounds[1] > coords[0][i]) ? bounds[1] : coords[0][i];
303  bounds[2] = (bounds[2] < coords[1][i]) ? bounds[2] : coords[1][i];
304  bounds[3] = (bounds[3] > coords[1][i]) ? bounds[3] : coords[1][i];
305  bounds[4] = (bounds[4] < coords[2][i]) ? bounds[4] : coords[2][i];
306  bounds[5] = (bounds[5] > coords[2][i]) ? bounds[5] : coords[2][i];
307  }
308  // and add a margin to avoid rounding errors
309  for (int i = 0; i < 6; ++i)
310  {
311  bounds[i] -= pow(-1, i) * 1e-10;
312  }
313 
314  // Array of centroids of triangles in the STL object
316  for (int i = 0; i < file.numTri; ++i)
317  {
318  centroids[i] = file.triangles[i].centroid;
319  }
320 
321  // Initialise octree
322  m_tree = Octree(centroids, 10, bounds);
323 
324  for (int s = 0; s < nStrips; ++s) // homogeneous strip varient
325  {
327  m_f->AppendExpList(m_f->m_numHomogeneousDir);
328  auto it = m_f->m_exp.begin() + s * (nVars + 1) + nVars;
329  m_f->m_exp.insert(it, Exp);
330  }
331 
332  // For each strip...
333  for (int s = 0; s < nStrips; ++s)
334  {
335  int fid = s * (nVars + 1) + nVars;
336 
337  Array<OneD, NekDouble> phys = m_f->m_exp[fid]->UpdatePhys();
338 
339  // Parallelisation is highly recommended here
340  for (int i = 0; i < nPts; ++i)
341  {
342  // Get coordinates of each point
343  Array<OneD, NekDouble> tmpCoords(3);
344  tmpCoords[2] = coords[2][i];
345  tmpCoords[1] = coords[1][i];
346  tmpCoords[0] = coords[0][i];
347 
348  // Find the shortest distance to the body(ies)
349  double dist;
350  FindShortestDist(file, tmpCoords, dist);
351 
352  // Get corresponding value of Phi
353  phys[i] = PhiFunction(dist, m_config["scale"].as<double>());
354  }
355 
356  // Update vector of expansions
357  m_f->m_exp[fid]->FwdTrans(phys, m_f->m_exp[fid]->UpdateCoeffs());
358  }
359 }
360 
361 /**
362  * @brief Checks if a ray traced from 'Origin' with direction 'Dvec' hits
363  * the triangle defined by 'tri'. Returns the distance to the plane
364  * defined by 'tri' in any case. A negative distance means that the hit
365  * happened in the direction oposite that of the ray. Approach to calculate
366  * the intersection point found in:
367  *
368  * Fast, minimum storage ray/triangle intersection,
369  * Tomas Moeller, Ben Trumbore
370  *
371  * @param tri
372  * @param Origin
373  * @param Dvec
374  * @param distance
375  * @param u
376  * @param v
377  * @return true
378  * @return false
379  */
381  const Array<OneD, NekDouble> &Origin,
382  const Array<OneD, NekDouble> &Dvec,
383  double &distance, double &u, double &v)
384 {
385  // Edge vectors
388  Vmath::Vsub(3, tri.v1, 1, tri.v0, 1, E1, 1);
389  Vmath::Vsub(3, tri.v2, 1, tri.v0, 1, E2, 1);
390 
391  // If det == 0, ray parallel to triangle
392  Array<OneD, NekDouble> Pvec = Cross(Dvec, E2);
393  double det = Vmath::Dot(3, Pvec, E1);
394  double inv_det = 1.0 / det;
395  if (IsEqual(0.0, det, 1e-10))
396  {
397  distance = numeric_limits<double>::max();
398  u = numeric_limits<double>::max();
399  v = numeric_limits<double>::max();
400  return false;
401  }
402 
403  // Vector T and parameter u = (0.0, 1.0)
404  Array<OneD, NekDouble> Tvec(3);
405  Vmath::Vsub(3, Origin, 1, tri.v0, 1, Tvec, 1);
406  u = Vmath::Dot(3, Pvec, Tvec) * inv_det;
407 
408  // Vector Q and parameter v = (0.0, 1.0)
409  Array<OneD, NekDouble> Qvec = Cross(Tvec, E1);
410  v = Vmath::Dot(3, Qvec, Dvec) * inv_det;
411 
412  // There is a hit if (u,v) coordinates are bounded
413  distance = Vmath::Dot(3, Qvec, E2) * inv_det;
414  if ((u < 0.0 || u > 1.0) || (v < 0.0 || u + v > 1.0))
415  {
416  return false;
417  }
418  else
419  {
420  return true;
421  }
422 }
423 
424 /**
425  * @brief Calculates the shortest distance from a point \f$x\f$ to the closed
426  * body contained in the STL file
427  *
428  * @param file
429  * @param x
430  * @param dist
431  */
434  double &dist)
435 {
436  // Find closest triangles
437  // First, use the ones in the node of 'x'
438  int node = m_tree.QueryNode(x);
439 
440  // Set 'dist' to an unreal value
441  dist = numeric_limits<double>::max();
442 
443  // If the node's depth is less than 3 the point is far from the object
444  int depth = m_tree.QueryDepth(node);
445 
446  if (depth > 2)
447  {
448  vector<int> treeTriangles;
449  vector<int> tmpTriangles = m_tree.QueryPoints(node);
450  for (int point : tmpTriangles)
451  {
452  treeTriangles.push_back(point);
453  }
454 
455  // Then, save the ones in the neighbouring nodes
456  vector<int> neighbours = m_tree.QueryNeighbours(node);
457  for (int neighNode : neighbours)
458  {
459  tmpTriangles = m_tree.QueryPoints(neighNode);
460  for (int point : tmpTriangles)
461  {
462  treeTriangles.push_back(point);
463  }
464  }
465 
466  // Keep the sign (interior or exterior),
467  int distSign = 1;
468  // the normal vector of closest triangle so far,
469  Array<OneD, NekDouble> triNormal =
470  file.triangles[treeTriangles[0]].normal;
471  // and the distance to the triangle PLANE
472  double tParam = dist;
473 
474  for (int i = 0; i < treeTriangles.size(); ++i)
475  {
476  // Find distance to triangle
477  triangle tri = file.triangles[treeTriangles[i]];
478  double currentTparam;
479  double u, v;
480  bool hit = CheckHit(tri, x, tri.normal, currentTparam, u, v);
481 
482  // Save "sign" of 'currentTparam'
483  int currentDistSign = (currentTparam >= 0) - (currentTparam < 0);
484  // and distance to the triangle
485  double currentDist;
486 
487  // Vector linking the hit point with the node
488  Array<OneD, NekDouble> distVector(3);
489 
490  if (hit)
491  {
492  Vmath::Smul(3, -currentTparam, tri.normal, 1, distVector, 1);
493  currentDist = fabs(currentTparam);
494  }
495  else
496  {
497  // The minimum has to be in one of the edges
498  if (v < 0) // Edge V0-V1
499  {
500  distVector = Vector2edge(x, tri.v0, tri.v1);
501  }
502  else if (u < 0) // Edge V0-V2
503  {
504  distVector = Vector2edge(x, tri.v0, tri.v2);
505  }
506  else // Edge V1-V2
507  {
508  distVector = Vector2edge(x, tri.v1, tri.v2);
509  }
510  currentDist = sqrt(Vmath::Dot(3, distVector, distVector));
511  }
512 
513  // Update 'dist', MAGIC CONSTANT AHEAD!
514  // In the case of corners, check that the new triangle is not
515  // giving contradictory information and, if so, use the one
516  // closer to 'x'. Otherwise, some exterior points will be treated
517  // as interior and viceversa
518  if (dist - currentDist > 1e-5 * currentDist ||
519  (IsEqual(dist, currentDist, 1e-5) &&
520  IsNegative(Vmath::Dot(3, triNormal, tri.normal), 1e-5) &&
521  fabs(currentTparam) > fabs(tParam)))
522  {
523  dist = currentDist;
524  tParam = currentTparam;
525  distSign = currentDistSign;
526  triNormal = tri.normal;
527  }
528  }
529 
530  // Update distance sign
531  dist *= -distSign;
532  }
533 }
534 
535 /**
536  * @brief Returns true if \f$x=y\f$ within the relative tolerance 'relTol'
537  * (relative to 'y')
538  *
539  * @param x
540  * @return true
541  * @return false
542  */
543 bool ProcessPhiFromFile::IsEqual(double x, double y, double relTol)
544 {
545  return (fabs(x - y) <= relTol * y);
546 }
547 
548 /**
549  * @brief Returns true if \f$x<tol\f$
550  *
551  * @param x
552  * @param relTol
553  * @return true
554  * @return false
555  */
556 bool ProcessPhiFromFile::IsNegative(double x, double tol)
557 {
558  return (x < tol);
559 }
560 
561 /**
562  * @brief Returns the cross product of vectors 'v0' y 'v1'
563  *
564  * @param v0
565  * @param v1
566  * @return Array<OneD, NekDouble>
567  */
569  const Array<OneD, NekDouble> &v0, const Array<OneD, NekDouble> &v1)
570 {
571  Array<OneD, NekDouble> out(3);
572 
573  out[0] = v0[1] * v1[2] - v0[2] * v1[1];
574  out[1] = v0[2] * v1[0] - v0[0] * v1[2];
575  out[2] = v0[0] * v1[1] - v0[1] * v1[0];
576 
577  return out;
578 }
579 
580 /**
581  * @brief Determines the shortest distance from a point 'x' to the segment
582  * defined by the points 'e1' and 'e2'. Note that this distance may be
583  * equal to that to one of the end points. The vector returned points towards
584  * the point 'x'
585  *
586  * @param x
587  * @param e1
588  * @param e2
589  * @return Array<OneD, NekDouble>
590  */
593  const Array<OneD, NekDouble> &e2)
594 {
595  size_t n = x.size();
596  Array<OneD, NekDouble> e1x(n);
597  Array<OneD, NekDouble> e1e2(n);
598  Vmath::Vsub(n, x, 1, e1, 1, e1x, 1);
599  Vmath::Vsub(n, e2, 1, e1, 1, e1e2, 1);
600  double norm = sqrt(Vmath::Dot(n, e1e2, e1e2));
601  for (size_t i = 0; i < n; ++i)
602  {
603  e1e2[i] /= norm;
604  }
605 
606  Array<OneD, NekDouble> out(n);
607  double proj = Vmath::Dot(n, e1x, e1e2);
608  if (proj < 0.0)
609  {
610  Vmath::Vsub(n, x, 1, e1, 1, out, 1);
611  }
612  else if (proj > norm)
613  {
614  Vmath::Vsub(n, x, 1, e2, 1, out, 1);
615  }
616  else
617  {
618  Vmath::Svtsvtp(n, 1.0, e1x, 1, -proj, e1e2, 1, out, 1);
619  }
620 
621  return out;
622 }
623 } // namespace FieldUtils
624 } // namespace Nektar
#define ASSERTL0(condition, msg)
Definition: ErrorUtil.hpp:215
#define WARNINGL0(condition, msg)
Definition: ErrorUtil.hpp:222
FieldSharedPtr m_f
Field object.
Definition: Module.h:234
std::map< std::string, ConfigOption > m_config
List of configuration values.
Definition: Module.h:263
int QueryDepth(int nodeID)
Definition: Octree.h:81
std::vector< int > QueryNeighbours(int nodeID)
Returns the IDs of the octants that surround the queried node. First, it finds the neighbouring nodes...
Definition: Octree.cpp:252
std::vector< int > QueryPoints(int nodeID)
Returns the indices of the points of the mesh contained in the tree.
Definition: Octree.cpp:237
int QueryNode(const Array< OneD, NekDouble > &coords, int depth=std::numeric_limits< int >::max())
Given the coordinates 'coords' of a point, returns the leaf octant that contains it....
Definition: Octree.cpp:139
Abstract base class for processing modules.
Definition: Module.h:292
bool CheckHit(const triangle &tri, const Array< OneD, NekDouble > &Origin, const Array< OneD, NekDouble > &Dvec, double &distance, double &u, double &v)
Checks if a ray traced from 'Origin' with direction 'Dvec' hits the triangle defined by 'tri'....
void GetPhifromSession()
Assigns to 'phi' the values indicated by 'ShapeFunction'.
Array< OneD, NekDouble > Vector2edge(const Array< OneD, NekDouble > &x, const Array< OneD, NekDouble > &e1, const Array< OneD, NekDouble > &e2)
Determines the shortest distance from a point 'x' to the segment defined by the points 'e1' and 'e2'....
Array< OneD, NekDouble > Cross(const Array< OneD, NekDouble > &v0, const Array< OneD, NekDouble > &v1)
Returns the cross product of vectors 'v0' y 'v1'.
STLobject ReadSTL(std::string filename)
Read an STL binary file and returns a struct of type 'STLobject' containing the parsed data.
void GetPhifromSTL(const STLobject &file)
Assigns to 'phi' the corresponding values of Phi.
void FindShortestDist(const STLobject &file, const Array< OneD, NekDouble > &x, double &dist)
Calculates the shortest distance from a point to the closed body contained in the STL file.
NekDouble PhiFunction(double dist, double coeff)
Smoothing function for the SPM method given a distance value and a scaling coefficient.
bool IsNegative(double x, double tol)
Returns true if .
virtual void v_Process(po::variables_map &vm) override
bool IsEqual(double x, double y, double relTol)
Returns true if within the relative tolerance 'relTol' (relative to 'y')
Array< OneD, NekDouble > ReadVector(std::ifstream &in)
Read one 3D vector from a STL file, starting from the next line of the input 'ifstream'....
tKey RegisterCreatorFunction(tKey idKey, CreatorFunction classCreator, std::string pDesc="")
Register a class with the factory.
Definition: NekFactory.hpp:198
std::shared_ptr< Field > FieldSharedPtr
Definition: Field.hpp:991
std::pair< ModuleType, std::string > ModuleKey
Definition: Module.h:317
ModuleFactory & GetModuleFactory()
Definition: Module.cpp:49
std::shared_ptr< Equation > EquationSharedPtr
Definition: Equation.h:129
std::shared_ptr< ExpList > ExpListSharedPtr
Shared pointer to an ExpList object.
The above copyright notice and this permission notice shall be included.
Definition: CoupledSolver.h:2
std::uint32_t NekUInt32
double NekDouble
void Svtsvtp(int n, const T alpha, const T *x, int incx, const T beta, const T *y, int incy, T *z, int incz)
svtvvtp (scalar times vector plus scalar times vector):
Definition: Vmath.cpp:751
T Dot(int n, const T *w, const T *x)
dot (vector times vector): z = w*x
Definition: Vmath.cpp:1100
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:248
void Vsub(int n, const T *x, const int incx, const T *y, const int incy, T *z, const int incz)
Subtract vector z = x-y.
Definition: Vmath.cpp:419
scalarT< T > sqrt(scalarT< T > in)
Definition: scalar.hpp:294
Represents a command-line configuration option.
Definition: Module.h:131