Nektar++
StdExpansion2D.cpp
Go to the documentation of this file.
1 ///////////////////////////////////////////////////////////////////////////////
2 //
3 // File StdExpansion2D.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: Daughter of StdExpansion. This class contains routine
32 // which are common to 2D expansion. Typically this inolves physiocal
33 // space operations.
34 //
35 ///////////////////////////////////////////////////////////////////////////////
36 
38 
39 #ifdef max
40 #undef max
41 #endif
42 
43 namespace Nektar
44 {
45 namespace StdRegions
46 {
47 
49 {
50 }
51 
53  const LibUtilities::BasisKey &Bb)
54  : StdExpansion(numcoeffs, 2, Ba, Bb)
55 {
56 }
57 
59 {
60 }
61 
63 {
64 }
65 
66 //----------------------------
67 // Differentiation Methods
68 //----------------------------
70  const Array<OneD, const NekDouble> &inarray,
71  Array<OneD, NekDouble> &outarray_d0, Array<OneD, NekDouble> &outarray_d1)
72 {
73  int nquad0 = m_base[0]->GetNumPoints();
74  int nquad1 = m_base[1]->GetNumPoints();
75 
76  if (outarray_d0.size() > 0) // calculate du/dx_0
77  {
78  DNekMatSharedPtr D0 = m_base[0]->GetD();
79  if (inarray.data() == outarray_d0.data())
80  {
81  Array<OneD, NekDouble> wsp(nquad0 * nquad1);
82  Vmath::Vcopy(nquad0 * nquad1, inarray.get(), 1, wsp.get(), 1);
83  Blas::Dgemm('N', 'N', nquad0, nquad1, nquad0, 1.0,
84  &(D0->GetPtr())[0], nquad0, &wsp[0], nquad0, 0.0,
85  &outarray_d0[0], nquad0);
86  }
87  else
88  {
89  Blas::Dgemm('N', 'N', nquad0, nquad1, nquad0, 1.0,
90  &(D0->GetPtr())[0], nquad0, &inarray[0], nquad0, 0.0,
91  &outarray_d0[0], nquad0);
92  }
93  }
94 
95  if (outarray_d1.size() > 0) // calculate du/dx_1
96  {
97  DNekMatSharedPtr D1 = m_base[1]->GetD();
98  if (inarray.data() == outarray_d1.data())
99  {
100  Array<OneD, NekDouble> wsp(nquad0 * nquad1);
101  Vmath::Vcopy(nquad0 * nquad1, inarray.get(), 1, wsp.get(), 1);
102  Blas::Dgemm('N', 'T', nquad0, nquad1, nquad1, 1.0, &wsp[0], nquad0,
103  &(D1->GetPtr())[0], nquad1, 0.0, &outarray_d1[0],
104  nquad0);
105  }
106  else
107  {
108  Blas::Dgemm('N', 'T', nquad0, nquad1, nquad1, 1.0, &inarray[0],
109  nquad0, &(D1->GetPtr())[0], nquad1, 0.0,
110  &outarray_d1[0], nquad0);
111  }
112  }
113 }
114 
116  const Array<OneD, const NekDouble> &coords,
117  const Array<OneD, const NekDouble> &physvals)
118 {
119  ASSERTL2(coords[0] > -1 - NekConstants::kNekZeroTol, "coord[0] < -1");
120  ASSERTL2(coords[0] < 1 + NekConstants::kNekZeroTol, "coord[0] > 1");
121  ASSERTL2(coords[1] > -1 - NekConstants::kNekZeroTol, "coord[1] < -1");
122  ASSERTL2(coords[1] < 1 + NekConstants::kNekZeroTol, "coord[1] > 1");
123 
124  Array<OneD, NekDouble> coll(2);
125  LocCoordToLocCollapsed(coords, coll);
126 
127  const int nq0 = m_base[0]->GetNumPoints();
128  const int nq1 = m_base[1]->GetNumPoints();
129 
130  Array<OneD, NekDouble> wsp(nq1);
131  for (int i = 0; i < nq1; ++i)
132  {
133  wsp[i] = StdExpansion::BaryEvaluate<0>(coll[0], &physvals[0] + i * nq0);
134  }
135 
136  return StdExpansion::BaryEvaluate<1>(coll[1], &wsp[0]);
137 }
138 
141  const Array<OneD, const NekDouble> &physvals)
142 {
143  NekDouble val;
144  int i;
145  int nq0 = m_base[0]->GetNumPoints();
146  int nq1 = m_base[1]->GetNumPoints();
147  Array<OneD, NekDouble> wsp1(nq1);
148 
149  // interpolate first coordinate direction
150  for (i = 0; i < nq1; ++i)
151  {
152  wsp1[i] =
153  Blas::Ddot(nq0, &(I[0]->GetPtr())[0], 1, &physvals[i * nq0], 1);
154  }
155 
156  // interpolate in second coordinate direction
157  val = Blas::Ddot(nq1, I[1]->GetPtr(), 1, wsp1, 1);
158 
159  return val;
160 }
161 
162 //////////////////////////////
163 // Integration Methods
164 //////////////////////////////
165 
169 {
170  int i;
171  NekDouble Int = 0.0;
172  int nquad0 = m_base[0]->GetNumPoints();
173  int nquad1 = m_base[1]->GetNumPoints();
174  Array<OneD, NekDouble> tmp(nquad0 * nquad1);
175 
176  // multiply by integration constants
177  for (i = 0; i < nquad1; ++i)
178  {
179  Vmath::Vmul(nquad0, &inarray[0] + i * nquad0, 1, w0.get(), 1,
180  &tmp[0] + i * nquad0, 1);
181  }
182 
183  for (i = 0; i < nquad0; ++i)
184  {
185  Vmath::Vmul(nquad1, &tmp[0] + i, nquad0, w1.get(), 1, &tmp[0] + i,
186  nquad0);
187  }
188  Int = Vmath::Vsum(nquad0 * nquad1, tmp, 1);
189 
190  return Int;
191 }
192 
194  const Array<OneD, const NekDouble> &base0,
195  const Array<OneD, const NekDouble> &base1,
196  const Array<OneD, const NekDouble> &inarray,
198  bool doCheckCollDir0, bool doCheckCollDir1)
199 {
200  v_BwdTrans_SumFacKernel(base0, base1, inarray, outarray, wsp,
201  doCheckCollDir0, doCheckCollDir1);
202 }
203 
205  const Array<OneD, const NekDouble> &base0,
206  const Array<OneD, const NekDouble> &base1,
207  const Array<OneD, const NekDouble> &inarray,
209  bool doCheckCollDir0, bool doCheckCollDir1)
210 {
211  v_IProductWRTBase_SumFacKernel(base0, base1, inarray, outarray, wsp,
212  doCheckCollDir0, doCheckCollDir1);
213 }
214 
216 {
217  ASSERTL1((dir == 0) || (dir == 1), "Invalid direction.");
218 
219  int nquad0 = m_base[0]->GetNumPoints();
220  int nquad1 = m_base[1]->GetNumPoints();
221  int nqtot = nquad0 * nquad1;
222  int nmodes0 = m_base[0]->GetNumModes();
223 
224  Array<OneD, NekDouble> tmp1(2 * nqtot + m_ncoeffs + nmodes0 * nquad1, 0.0);
225  Array<OneD, NekDouble> tmp3(tmp1 + 2 * nqtot);
226  Array<OneD, NekDouble> tmp4(tmp1 + 2 * nqtot + m_ncoeffs);
227 
228  switch (dir)
229  {
230  case 0:
231  for (int i = 0; i < nqtot; i++)
232  {
233  tmp1[i] = 1.0;
234  IProductWRTBase_SumFacKernel(m_base[0]->GetDbdata(),
235  m_base[1]->GetBdata(), tmp1, tmp3,
236  tmp4, false, true);
237  tmp1[i] = 0.0;
238 
239  for (int j = 0; j < m_ncoeffs; j++)
240  {
241  (*mat)(j, i) = tmp3[j];
242  }
243  }
244  break;
245  case 1:
246  for (int i = 0; i < nqtot; i++)
247  {
248  tmp1[i] = 1.0;
249  IProductWRTBase_SumFacKernel(m_base[0]->GetBdata(),
250  m_base[1]->GetDbdata(), tmp1, tmp3,
251  tmp4, true, false);
252  tmp1[i] = 0.0;
253 
254  for (int j = 0; j < m_ncoeffs; j++)
255  {
256  (*mat)(j, i) = tmp3[j];
257  }
258  }
259  break;
260  default:
261  NEKERROR(ErrorUtil::efatal, "Not a 2D expansion.");
262  break;
263  }
264 }
265 
267  const Array<OneD, const NekDouble> &inarray,
268  Array<OneD, NekDouble> &outarray, const StdRegions::StdMatrixKey &mkey)
269 {
270  if (mkey.GetNVarCoeff() == 0 &&
273  {
274  using std::max;
275 
276  // This implementation is only valid when there are no
277  // coefficients associated to the Laplacian operator
278  int nquad0 = m_base[0]->GetNumPoints();
279  int nquad1 = m_base[1]->GetNumPoints();
280  int nqtot = nquad0 * nquad1;
281  int nmodes0 = m_base[0]->GetNumModes();
282  int nmodes1 = m_base[1]->GetNumModes();
283  int wspsize =
284  max(max(max(nqtot, m_ncoeffs), nquad1 * nmodes0), nquad0 * nmodes1);
285 
286  const Array<OneD, const NekDouble> &base0 = m_base[0]->GetBdata();
287  const Array<OneD, const NekDouble> &base1 = m_base[1]->GetBdata();
288 
289  // Allocate temporary storage
290  Array<OneD, NekDouble> wsp0(4 * wspsize); // size wspsize
291  Array<OneD, NekDouble> wsp1(wsp0 + wspsize); // size 3*wspsize
292 
293  if (!(m_base[0]->Collocation() && m_base[1]->Collocation()))
294  {
295  // LAPLACIAN MATRIX OPERATION
296  // wsp0 = u = B * u_hat
297  // wsp1 = du_dxi1 = D_xi1 * wsp0 = D_xi1 * u
298  // wsp2 = du_dxi2 = D_xi2 * wsp0 = D_xi2 * u
299  BwdTrans_SumFacKernel(base0, base1, inarray, wsp0, wsp1, true,
300  true);
301  LaplacianMatrixOp_MatFree_Kernel(wsp0, outarray, wsp1);
302  }
303  else
304  {
305  LaplacianMatrixOp_MatFree_Kernel(inarray, outarray, wsp1);
306  }
307  }
308  else
309  {
311  mkey);
312  }
313 }
314 
316  const Array<OneD, const NekDouble> &inarray,
317  Array<OneD, NekDouble> &outarray, const StdRegions::StdMatrixKey &mkey)
318 {
319  if (mkey.GetNVarCoeff() == 0 &&
322  {
323  using std::max;
324 
325  int nquad0 = m_base[0]->GetNumPoints();
326  int nquad1 = m_base[1]->GetNumPoints();
327  int nqtot = nquad0 * nquad1;
328  int nmodes0 = m_base[0]->GetNumModes();
329  int nmodes1 = m_base[1]->GetNumModes();
330  int wspsize =
331  max(max(max(nqtot, m_ncoeffs), nquad1 * nmodes0), nquad0 * nmodes1);
333 
334  const Array<OneD, const NekDouble> &base0 = m_base[0]->GetBdata();
335  const Array<OneD, const NekDouble> &base1 = m_base[1]->GetBdata();
336 
337  // Allocate temporary storage
338  Array<OneD, NekDouble> wsp0(5 * wspsize); // size wspsize
339  Array<OneD, NekDouble> wsp1(wsp0 + wspsize); // size wspsize
340  Array<OneD, NekDouble> wsp2(wsp0 + 2 * wspsize); // size 3*wspsize
341 
342  if (!(m_base[0]->Collocation() && m_base[1]->Collocation()))
343  {
344  // MASS MATRIX OPERATION
345  // The following is being calculated:
346  // wsp0 = B * u_hat = u
347  // wsp1 = W * wsp0
348  // outarray = B^T * wsp1 = B^T * W * B * u_hat = M * u_hat
349  BwdTrans_SumFacKernel(base0, base1, inarray, wsp0, wsp2, true,
350  true);
351  MultiplyByQuadratureMetric(wsp0, wsp1);
352  IProductWRTBase_SumFacKernel(base0, base1, wsp1, outarray, wsp2,
353  true, true);
354 
355  LaplacianMatrixOp_MatFree_Kernel(wsp0, wsp1, wsp2);
356  }
357  else
358  {
359  MultiplyByQuadratureMetric(inarray, outarray);
360  LaplacianMatrixOp_MatFree_Kernel(inarray, wsp1, wsp2);
361  }
362 
363  // outarray = lambda * outarray + wsp1
364  // = (lambda * M + L ) * u_hat
365  Vmath::Svtvp(m_ncoeffs, lambda, &outarray[0], 1, &wsp1[0], 1,
366  &outarray[0], 1);
367  }
368  else
369  {
371  mkey);
372  }
373 }
374 
375 void StdExpansion2D::v_GetTraceCoeffMap(const unsigned int traceid,
376  Array<OneD, unsigned int> &maparray)
377 {
378  boost::ignore_unused(traceid, maparray);
379 
380  ASSERTL0(false,
381  "This method must be defined at the individual shape level");
382 }
383 
384 /** \brief Determine the mapping to re-orientate the
385  coefficients along the element trace (assumed to align
386  with the standard element) into the orientation of the
387  local trace given by edgeOrient.
388  */
390  const unsigned int eid, Array<OneD, unsigned int> &maparray,
391  Array<OneD, int> &signarray, Orientation edgeOrient, int P, int Q)
392 {
393  // Q is only used in 2D traces.
394  boost::ignore_unused(Q);
395 
396  unsigned int i;
397 
398  int dir;
399  // determine basis direction for edge.
401  {
402  dir = (eid == 0) ? 0 : 1;
403  }
404  else
405  {
406  dir = eid % 2;
407  }
408 
409  int numModes = m_base[dir]->GetNumModes();
410 
411  // P is the desired length of the map
412  P = (P == -1) ? numModes : P;
413 
414  // decalare maparray
415  if (maparray.size() != P)
416  {
417  maparray = Array<OneD, unsigned int>(P);
418  }
419 
420  // fill default mapping as increasing index
421  for (i = 0; i < P; ++i)
422  {
423  maparray[i] = i;
424  }
425 
426  if (signarray.size() != P)
427  {
428  signarray = Array<OneD, int>(P, 1);
429  }
430  else
431  {
432  std::fill(signarray.get(), signarray.get() + P, 1);
433  }
434 
435  // Zero signmap and set maparray to zero if
436  // elemental modes are not as large as trace modes
437  for (i = numModes; i < P; ++i)
438  {
439  signarray[i] = 0.0;
440  maparray[i] = maparray[0];
441  }
442 
443  if (edgeOrient == eBackwards)
444  {
445  const LibUtilities::BasisType bType = GetBasisType(dir);
446 
447  if ((bType == LibUtilities::eModified_A) ||
448  (bType == LibUtilities::eModified_B))
449  {
450  std::swap(maparray[0], maparray[1]);
451 
452  for (i = 3; i < std::min(P, numModes); i += 2)
453  {
454  signarray[i] *= -1;
455  }
456  }
457  else if (bType == LibUtilities::eGLL_Lagrange ||
459  {
460  ASSERTL1(P == numModes, "Different trace space edge dimension "
461  "and element edge dimension not currently "
462  "possible for GLL-Lagrange bases");
463 
464  std::reverse(maparray.get(), maparray.get() + P);
465  }
466  else
467  {
468  ASSERTL0(false, "Mapping not defined for this type of basis");
469  }
470  }
471 }
472 
474  Array<OneD, unsigned int> &maparray,
475  Array<OneD, int> &signarray,
476  Orientation edgeOrient, int P,
477  int Q)
478 {
479  Array<OneD, unsigned int> map1, map2;
480  v_GetTraceCoeffMap(eid, map1);
481  v_GetElmtTraceToTraceMap(eid, map2, signarray, edgeOrient, P, Q);
482 
483  if (maparray.size() != map2.size())
484  {
485  maparray = Array<OneD, unsigned int>(map2.size());
486  }
487 
488  for (int i = 0; i < map2.size(); ++i)
489  {
490  maparray[i] = map1[map2[i]];
491  }
492 }
493 
494 } // namespace StdRegions
495 } // namespace Nektar
#define ASSERTL0(condition, msg)
Definition: ErrorUtil.hpp:215
#define NEKERROR(type, msg)
Assert Level 0 – Fundamental assert which is used whether in FULLDEBUG, DEBUG or OPT compilation mode...
Definition: ErrorUtil.hpp:209
#define ASSERTL1(condition, msg)
Assert Level 1 – Debugging which is used whether in FULLDEBUG or DEBUG compilation mode....
Definition: ErrorUtil.hpp:249
#define ASSERTL2(condition, msg)
Assert Level 2 – Debugging which is used FULLDEBUG compilation mode. This level assert is designed to...
Definition: ErrorUtil.hpp:272
Describes the specification for a Basis.
Definition: Basis.h:50
virtual void v_IProductWRTBase_SumFacKernel(const Array< OneD, const NekDouble > &base0, const Array< OneD, const NekDouble > &base1, const Array< OneD, const NekDouble > &inarray, Array< OneD, NekDouble > &outarray, Array< OneD, NekDouble > &wsp, bool doCheckCollDir0, bool doCheckCollDir1)=0
virtual void v_GetElmtTraceToTraceMap(const unsigned int eid, Array< OneD, unsigned int > &maparray, Array< OneD, int > &signarray, Orientation edgeOrient, int P, int Q)
Determine the mapping to re-orientate the coefficients along the element trace (assumed to align with...
void PhysTensorDeriv(const Array< OneD, const NekDouble > &inarray, Array< OneD, NekDouble > &outarray_d0, Array< OneD, NekDouble > &outarray_d1)
Calculate the 2D derivative in the local tensor/collapsed coordinate at the physical points.
virtual void v_BwdTrans_SumFacKernel(const Array< OneD, const NekDouble > &base0, const Array< OneD, const NekDouble > &base1, const Array< OneD, const NekDouble > &inarray, Array< OneD, NekDouble > &outarray, Array< OneD, NekDouble > &wsp, bool doCheckCollDir0, bool doCheckCollDir1)=0
virtual NekDouble v_PhysEvaluate(const Array< OneD, const NekDouble > &coords, const Array< OneD, const NekDouble > &physvals)
This function evaluates the expansion at a single (arbitrary) point of the domain.
virtual void v_GetTraceToElementMap(const int eid, Array< OneD, unsigned int > &maparray, Array< OneD, int > &signarray, Orientation edgeOrient=eForwards, int P=-1, int Q=-1)
NekDouble Integral(const Array< OneD, const NekDouble > &inarray, const Array< OneD, const NekDouble > &w0, const Array< OneD, const NekDouble > &w1)
virtual void v_GetTraceCoeffMap(const unsigned int traceid, Array< OneD, unsigned int > &maparray)
void BwdTrans_SumFacKernel(const Array< OneD, const NekDouble > &base0, const Array< OneD, const NekDouble > &base1, const Array< OneD, const NekDouble > &inarray, Array< OneD, NekDouble > &outarray, Array< OneD, NekDouble > &wsp, bool doCheckCollDir0=true, bool doCheckCollDir1=true)
virtual void v_HelmholtzMatrixOp_MatFree(const Array< OneD, const NekDouble > &inarray, Array< OneD, NekDouble > &outarray, const StdRegions::StdMatrixKey &mkey)
virtual void v_LaplacianMatrixOp_MatFree(const Array< OneD, const NekDouble > &inarray, Array< OneD, NekDouble > &outarray, const StdRegions::StdMatrixKey &mkey)
void IProductWRTBase_SumFacKernel(const Array< OneD, const NekDouble > &base0, const Array< OneD, const NekDouble > &base1, const Array< OneD, const NekDouble > &inarray, Array< OneD, NekDouble > &outarray, Array< OneD, NekDouble > &wsp, bool doCheckCollDir0=true, bool doCheckCollDir1=true)
virtual void v_GenStdMatBwdDeriv(const int dir, DNekMatSharedPtr &mat)
The base class for all shapes.
Definition: StdExpansion.h:71
void LaplacianMatrixOp_MatFree_GenericImpl(const Array< OneD, const NekDouble > &inarray, Array< OneD, NekDouble > &outarray, const StdMatrixKey &mkey)
LibUtilities::BasisType GetBasisType(const int dir) const
This function returns the type of basis used in the dir direction.
Definition: StdExpansion.h:163
void LocCoordToLocCollapsed(const Array< OneD, const NekDouble > &xi, Array< OneD, NekDouble > &eta)
Convert local cartesian coordinate xi into local collapsed coordinates eta.
Definition: StdExpansion.h:974
LibUtilities::ShapeType DetShapeType() const
This function returns the shape of the expansion domain.
Definition: StdExpansion.h:375
void MultiplyByQuadratureMetric(const Array< OneD, const NekDouble > &inarray, Array< OneD, NekDouble > &outarray)
Definition: StdExpansion.h:731
void HelmholtzMatrixOp_MatFree_GenericImpl(const Array< OneD, const NekDouble > &inarray, Array< OneD, NekDouble > &outarray, const StdMatrixKey &mkey)
Array< OneD, LibUtilities::BasisSharedPtr > m_base
void LaplacianMatrixOp_MatFree_Kernel(const Array< OneD, const NekDouble > &inarray, Array< OneD, NekDouble > &outarray, Array< OneD, NekDouble > &wsp)
NekDouble GetConstFactor(const ConstFactorType &factor) const
Definition: StdMatrixKey.h:126
bool ConstFactorExists(const ConstFactorType &factor) const
Definition: StdMatrixKey.h:135
static double Ddot(const int &n, const double *x, const int &incx, const double *y, const int &incy)
BLAS level 1: output = .
Definition: Blas.hpp:182
static void Dgemm(const char &transa, const char &transb, const int &m, const int &n, const int &k, const double &alpha, const double *a, const int &lda, const double *b, const int &ldb, const double &beta, double *c, const int &ldc)
BLAS level 3: Matrix-matrix multiply C = A x B where op(A)[m x k], op(B)[k x n], C[m x n] DGEMM perfo...
Definition: Blas.hpp:368
@ eModified_B
Principle Modified Functions .
Definition: BasisType.h:51
@ eGauss_Lagrange
Lagrange Polynomials using the Gauss points.
Definition: BasisType.h:59
@ eGLL_Lagrange
Lagrange for SEM basis .
Definition: BasisType.h:58
@ eModified_A
Principle Modified Functions .
Definition: BasisType.h:50
static const NekDouble kNekZeroTol
The above copyright notice and this permission notice shall be included.
Definition: CoupledSolver.h:1
std::shared_ptr< DNekMat > DNekMatSharedPtr
Definition: NekTypeDefs.hpp:75
double NekDouble
void Vmul(int n, const T *x, const int incx, const T *y, const int incy, T *z, const int incz)
Multiply vector z = x*y.
Definition: Vmath.cpp:209
void Svtvp(int n, const T alpha, const T *x, const int incx, const T *y, const int incy, T *z, const int incz)
svtvp (scalar times vector plus vector): z = alpha*x + y
Definition: Vmath.cpp:622
T Vsum(int n, const T *x, const int incx)
Subtract return sum(x)
Definition: Vmath.cpp:895
void Vcopy(int n, const T *x, const int incx, T *y, const int incy)
Definition: Vmath.cpp:1255