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