Intrepid2
Intrepid2_TestUtils.hpp
Go to the documentation of this file.
1// @HEADER
2// ************************************************************************
3//
4// Intrepid2 Package
5// Copyright (2007) Sandia Corporation
6//
7// Under terms of Contract DE-AC04-94AL85000, there is a non-exclusive
8// license for use of this work by or on behalf of the U.S. Government.
9//
10// Redistribution and use in source and binary forms, with or without
11// modification, are permitted provided that the following conditions are
12// met:
13//
14// 1. Redistributions of source code must retain the above copyright
15// notice, this list of conditions and the following disclaimer.
16//
17// 2. Redistributions in binary form must reproduce the above copyright
18// notice, this list of conditions and the following disclaimer in the
19// documentation and/or other materials provided with the distribution.
20//
21// 3. Neither the name of the Corporation nor the names of the
22// contributors may be used to endorse or promote products derived from
23// this software without specific prior written permission.
24//
25// THIS SOFTWARE IS PROVIDED BY SANDIA CORPORATION "AS IS" AND ANY
26// EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
27// IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
28// PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL SANDIA CORPORATION OR THE
29// CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
30// EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
31// PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
32// PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
33// LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
34// NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
35// SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
36//
37// Questions? Contact Kyungjoo Kim (kyukim@sandia.gov),
38// Mauro Perego (mperego@sandia.gov), or
39// Nate Roberts (nvrober@sandia.gov)
40//
41// ************************************************************************
42// @HEADER
43
49#ifndef Intrepid2_TestUtils_h
50#define Intrepid2_TestUtils_h
51
52#include "Kokkos_Core.hpp"
53#include "Kokkos_DynRankView.hpp"
54
55#include "Intrepid2_Basis.hpp"
60#include "Intrepid2_Sacado.hpp" // Sacado includes, guarded by the appropriate preprocessor variable
61#include "Intrepid2_Utils.hpp"
62
63#include "Teuchos_UnitTestHarness.hpp"
64
65namespace Intrepid2
66{
69
71#ifdef KOKKOS_ENABLE_CUDA
72 using DefaultTestDeviceType = Kokkos::Device<Kokkos::Cuda,Kokkos::CudaSpace>;
73#else
74 using DefaultTestDeviceType = typename Kokkos::DefaultExecutionSpace::device_type;
75#endif
76
78 template <class Scalar>
79 const typename Teuchos::ScalarTraits<Scalar>::magnitudeType
81 {
82 using ST = Teuchos::ScalarTraits<Scalar>;
83 return ST::magnitude(Teuchos::RelErrSmallNumber<ST::hasMachineParameters,Scalar>::smallNumber());
84 }
85
87 template <class Scalar1, class Scalar2>
88 KOKKOS_INLINE_FUNCTION
89 bool
90 relErrMeetsTol( const Scalar1 &s1, const Scalar2 &s2, const typename Teuchos::ScalarTraits< typename std::common_type<Scalar1,Scalar2>::type >::magnitudeType &smallNumber, const double &tol )
91 {
92 using Scalar = typename std::common_type<Scalar1,Scalar2>::type;
93 const Scalar s1Abs = fabs(s1);
94 const Scalar s2Abs = fabs(s2);
95 const Scalar maxAbs = (s1Abs > s2Abs) ? s1Abs : s2Abs;
96 const Scalar relErr = fabs( s1 - s2 ) / ( smallNumber + maxAbs );
97 return relErr < tol;
98 }
99
100 template <class Scalar1, class Scalar2>
101 KOKKOS_INLINE_FUNCTION
102 bool
103 errMeetsAbsAndRelTol( const Scalar1 &s1, const Scalar2 &s2, const double &relTol, const double &absTol )
104 {
105 return fabs( s1 - s2 ) <= absTol + fabs(s1) * relTol;
106 }
107
108 static const double TEST_TOLERANCE_TIGHT = 1.e2 * std::numeric_limits<double>::epsilon();
109
110 // we use DynRankView for both input points and values
111 template<typename ScalarType, typename DeviceType>
112 using ViewType = Kokkos::DynRankView<ScalarType,DeviceType>;
113
114 template<typename ScalarType, typename DeviceType>
115 using FixedRankViewType = Kokkos::View<ScalarType,DeviceType>;
116
117 template<typename ScalarType>
118 KOKKOS_INLINE_FUNCTION bool valuesAreSmall(const ScalarType &a, const ScalarType &b, const double &epsilon)
119 {
120 using std::abs;
121 return (abs(a) < epsilon) && (abs(b) < epsilon);
122 }
123
124 inline bool approximatelyEqual(double a, double b, double epsilon)
125 {
126 const double larger_magnitude = (std::abs(a) < std::abs(b) ? std::abs(b) : std::abs(a));
127 return std::abs(a - b) <= larger_magnitude * epsilon;
128 }
129
130 inline bool essentiallyEqual(double a, double b, double epsilon)
131 {
132 const double smaller_magnitude = (std::abs(a) > std::abs(b) ? std::abs(b) : std::abs(a));
133 return std::abs(a - b) <= smaller_magnitude * epsilon;
134 }
135
136 // conversion from the ref element [0,1] (used by ESEAS) to the ref element [-1,1] (used by Intrepid2)
137 KOKKOS_INLINE_FUNCTION double fromZeroOne(double x_zero_one)
138 {
139 return x_zero_one * 2.0 - 1.0;
140 }
141
142 // conversion from the ref element [-1,1] (used by Intrepid2) to the ref element [0,1] (used by ESEAS)
143 KOKKOS_INLINE_FUNCTION double toZeroOne(double x_minus_one_one)
144 {
145 return (x_minus_one_one + 1.0) / 2.0;
146 }
147
148 // conversion from the ref element [0,1] (used by ESEAS) to the ref element [-1,1] (used by Intrepid2)
149 KOKKOS_INLINE_FUNCTION double fromZeroOne_dx(double dx_zero_one)
150 {
151 return dx_zero_one / 2.0;
152 }
153
154 // conversion from the ref element [-1,1] (used by Intrepid2) to the ref element [0,1] (used by ESEAS)
155 KOKKOS_INLINE_FUNCTION double toZeroOne_dx(double dx_minus_one_one)
156 {
157 return dx_minus_one_one * 2.0;
158 }
159
160 template<class DeviceViewType>
161 typename DeviceViewType::HostMirror getHostCopy(const DeviceViewType &deviceView)
162 {
163 typename DeviceViewType::HostMirror hostView = Kokkos::create_mirror(deviceView);
164 Kokkos::deep_copy(hostView, deviceView);
165 return hostView;
166 }
167
168 template<class BasisFamily>
169 inline Teuchos::RCP< Intrepid2::Basis<DefaultTestDeviceType,double,double> > getBasisUsingFamily(shards::CellTopology cellTopo, Intrepid2::EFunctionSpace fs,
170 int polyOrder_x, int polyOrder_y=-1, int polyOrder_z = -1)
171 {
172 using BasisPtr = typename BasisFamily::BasisPtr;
173
174 BasisPtr basis;
175 using namespace Intrepid2;
176
177 if (cellTopo.getBaseKey() == shards::Line<>::key)
178 {
179 basis = getLineBasis<BasisFamily>(fs,polyOrder_x);
180 }
181 else if (cellTopo.getBaseKey() == shards::Quadrilateral<>::key)
182 {
183 INTREPID2_TEST_FOR_EXCEPTION(polyOrder_y < 0, std::invalid_argument, "polyOrder_y must be specified");
184 basis = getQuadrilateralBasis<BasisFamily>(fs,polyOrder_x,polyOrder_y);
185 }
186 else if (cellTopo.getBaseKey() == shards::Triangle<>::key)
187 {
188 basis = getTriangleBasis<BasisFamily>(fs,polyOrder_x);
189 }
190 else if (cellTopo.getBaseKey() == shards::Hexahedron<>::key)
191 {
192 INTREPID2_TEST_FOR_EXCEPTION(polyOrder_y < 0, std::invalid_argument, "polyOrder_y must be specified");
193 INTREPID2_TEST_FOR_EXCEPTION(polyOrder_z < 0, std::invalid_argument, "polyOrder_z must be specified");
194 basis = getHexahedronBasis<BasisFamily>(fs,polyOrder_x,polyOrder_y,polyOrder_z);
195 }
196 else if (cellTopo.getBaseKey() == shards::Tetrahedron<>::key)
197 {
198 basis = getTetrahedronBasis<BasisFamily>(fs, polyOrder_x);
199 }
200 else
201 {
202 INTREPID2_TEST_FOR_EXCEPTION(true, std::invalid_argument, "Unsupported cell topology");
203 }
204 return basis;
205 }
206
207 template<bool defineVertexFunctions>
208 inline Teuchos::RCP< Intrepid2::Basis<DefaultTestDeviceType,double,double> > getHierarchicalBasis(shards::CellTopology cellTopo, Intrepid2::EFunctionSpace fs,
209 int polyOrder_x, int polyOrder_y=-1, int polyOrder_z = -1)
210 {
211 using DeviceType = DefaultTestDeviceType;
212 using Scalar = double;
213 using namespace Intrepid2;
214
219
221
222 return getBasisUsingFamily<BasisFamily>(cellTopo, fs, polyOrder_x, polyOrder_y, polyOrder_z);
223 }
224
225 template<typename ValueType, typename DeviceType, class ... DimArgs>
226 inline ViewType<ValueType,DeviceType> getView(const std::string &label, DimArgs... dims)
227 {
228 const bool allocateFadStorage = !std::is_pod<ValueType>::value;
229 if (!allocateFadStorage)
230 {
231 return ViewType<ValueType,DeviceType>(label,dims...);
232 }
233 else
234 {
235 return ViewType<ValueType,DeviceType>(label,dims...,MAX_FAD_DERIVATIVES_FOR_TESTS+1);
236 }
237 }
238
239 // this method is to allow us to switch tests over incrementally; should collapse with ViewType once everything has been switched
240 template<typename ValueType, class ... DimArgs>
241 inline FixedRankViewType< typename RankExpander<ValueType, sizeof...(DimArgs) >::value_type, DefaultTestDeviceType > getFixedRankView(const std::string &label, DimArgs... dims)
242 {
243 const bool allocateFadStorage = !std::is_pod<ValueType>::value;
244 using value_type = typename RankExpander<ValueType, sizeof...(dims) >::value_type;
245 if (!allocateFadStorage)
246 {
247 return FixedRankViewType<value_type,DefaultTestDeviceType>(label,dims...);
248 }
249 else
250 {
251 return FixedRankViewType<value_type,DefaultTestDeviceType>(label,dims...,MAX_FAD_DERIVATIVES_FOR_TESTS+1);
252 }
253 }
254
261 template <typename PointValueType, typename DeviceType>
262 inline ViewType<PointValueType,DeviceType> getInputPointsView(shards::CellTopology &cellTopo, int numPoints_1D)
263 {
264 const ordinal_type order = numPoints_1D - 1;
265 ordinal_type numPoints = PointTools::getLatticeSize(cellTopo, order);
266 ordinal_type spaceDim = cellTopo.getDimension();
267
268 ViewType<PointValueType,DeviceType> inputPoints = getView<PointValueType,DeviceType>("input points",numPoints,spaceDim);
269 PointTools::getLattice(inputPoints, cellTopo, order, 0, POINTTYPE_EQUISPACED );
270
271 return inputPoints;
272 }
273
274 template<typename OutputValueType, typename DeviceType>
275 inline ViewType<OutputValueType,DeviceType> getOutputView(Intrepid2::EFunctionSpace fs, Intrepid2::EOperator op, int basisCardinality, int numPoints, int spaceDim)
276 {
277 switch (fs) {
278 case Intrepid2::FUNCTION_SPACE_HGRAD:
279 switch (op) {
280 case Intrepid2::OPERATOR_VALUE:
281 return getView<OutputValueType,DeviceType>("H^1 value output",basisCardinality,numPoints);
282 case Intrepid2::OPERATOR_GRAD:
283 return getView<OutputValueType,DeviceType>("H^1 derivative output",basisCardinality,numPoints,spaceDim);
284 case Intrepid2::OPERATOR_D1:
285 case Intrepid2::OPERATOR_D2:
286 case Intrepid2::OPERATOR_D3:
287 case Intrepid2::OPERATOR_D4:
288 case Intrepid2::OPERATOR_D5:
289 case Intrepid2::OPERATOR_D6:
290 case Intrepid2::OPERATOR_D7:
291 case Intrepid2::OPERATOR_D8:
292 case Intrepid2::OPERATOR_D9:
293 case Intrepid2::OPERATOR_D10:
294 {
295 const auto dkcard = getDkCardinality(op, spaceDim);
296 return getView<OutputValueType,DeviceType>("H^1 derivative output",basisCardinality,numPoints,dkcard);
297 }
298 default:
299 INTREPID2_TEST_FOR_EXCEPTION(true, std::invalid_argument, "Unsupported op/fs combination");
300 }
301 case Intrepid2::FUNCTION_SPACE_HCURL:
302 switch (op) {
303 case Intrepid2::OPERATOR_VALUE:
304 return getView<OutputValueType,DeviceType>("H(curl) value output",basisCardinality,numPoints,spaceDim);
305 case Intrepid2::OPERATOR_CURL:
306 if (spaceDim == 2)
307 return getView<OutputValueType,DeviceType>("H(curl) derivative output",basisCardinality,numPoints);
308 else if (spaceDim == 3)
309 return getView<OutputValueType,DeviceType>("H(curl) derivative output",basisCardinality,numPoints,spaceDim);
310 default:
311 INTREPID2_TEST_FOR_EXCEPTION(true, std::invalid_argument, "Unsupported op/fs combination");
312 }
313 case Intrepid2::FUNCTION_SPACE_HDIV:
314 switch (op) {
315 case Intrepid2::OPERATOR_VALUE:
316 return getView<OutputValueType,DeviceType>("H(div) value output",basisCardinality,numPoints,spaceDim);
317 case Intrepid2::OPERATOR_DIV:
318 return getView<OutputValueType,DeviceType>("H(div) derivative output",basisCardinality,numPoints);
319 default:
320 INTREPID2_TEST_FOR_EXCEPTION(true, std::invalid_argument, "Unsupported op/fs combination");
321 }
322
323 case Intrepid2::FUNCTION_SPACE_HVOL:
324 switch (op) {
325 case Intrepid2::OPERATOR_VALUE:
326 return getView<OutputValueType,DeviceType>("H(vol) value output",basisCardinality,numPoints);
327 case Intrepid2::OPERATOR_D1:
328 case Intrepid2::OPERATOR_D2:
329 case Intrepid2::OPERATOR_D3:
330 case Intrepid2::OPERATOR_D4:
331 case Intrepid2::OPERATOR_D5:
332 case Intrepid2::OPERATOR_D6:
333 case Intrepid2::OPERATOR_D7:
334 case Intrepid2::OPERATOR_D8:
335 case Intrepid2::OPERATOR_D9:
336 case Intrepid2::OPERATOR_D10:
337 {
338 const auto dkcard = getDkCardinality(op, spaceDim);
339 return getView<OutputValueType,DeviceType>("H(vol) derivative output",basisCardinality,numPoints,dkcard);
340 }
341 default:
342 INTREPID2_TEST_FOR_EXCEPTION(true, std::invalid_argument, "Unsupported op/fs combination");
343 }
344 default:
345 INTREPID2_TEST_FOR_EXCEPTION(true, std::invalid_argument, "Unsupported op/fs combination");
346 }
347 }
348
349 // ! This returns a vector whose entries are vector<int>s containing 1-3 polynomial orders from 1 up to and including those specified
350 // ! Intended for testing bases that support anisotropic polynomial degree, such as the hierarchical bases
351 inline std::vector< std::vector<int> > getBasisTestCasesUpToDegree(int spaceDim, int minDegree, int polyOrder_x, int polyOrder_y=-1, int polyOrder_z = -1)
352 {
353 std::vector<int> degrees(spaceDim);
354 degrees[0] = polyOrder_x;
355 if (spaceDim > 1) degrees[1] = polyOrder_y;
356 if (spaceDim > 2) degrees[2] = polyOrder_z;
357
358 int numCases = degrees[0];
359 for (unsigned d=1; d<degrees.size(); d++)
360 {
361 numCases = numCases * (degrees[d] + 1 - minDegree);
362 }
363 std::vector< std::vector<int> > subBasisDegreeTestCases(numCases);
364 for (int caseOrdinal=0; caseOrdinal<numCases; caseOrdinal++)
365 {
366 std::vector<int> subBasisDegrees(degrees.size());
367 int caseRemainder = caseOrdinal;
368 for (int d=degrees.size()-1; d>=0; d--)
369 {
370 int subBasisDegree = caseRemainder % (degrees[d] + 1 - minDegree);
371 caseRemainder = caseRemainder / (degrees[d] + 1 - minDegree);
372 subBasisDegrees[d] = subBasisDegree + minDegree;
373 }
374 subBasisDegreeTestCases[caseOrdinal] = subBasisDegrees;
375 }
376 return subBasisDegreeTestCases;
377 }
378
380 template<class Functor, class Scalar, int rank>
381 typename ViewType<Scalar,DefaultTestDeviceType>::HostMirror copyFunctorToHostView(const Functor &deviceFunctor)
382 {
383 INTREPID2_TEST_FOR_EXCEPTION(rank != getFunctorRank(deviceFunctor), std::invalid_argument, "functor rank must match the template argument");
384
385 using DeviceType = DefaultTestDeviceType;
386 ViewType<Scalar,DeviceType> view;
387 const std::string label = "functor copy";
388 const auto &f = deviceFunctor;
389 switch (rank)
390 {
391 case 0:
392 view = getView<Scalar,DeviceType>(label);
393 break;
394 case 1:
395 view = getView<Scalar,DeviceType>(label, f.extent_int(0));
396 break;
397 case 2:
398 view = getView<Scalar,DeviceType>(label, f.extent_int(0), f.extent_int(1));
399 break;
400 case 3:
401 view = getView<Scalar,DeviceType>(label, f.extent_int(0), f.extent_int(1), f.extent_int(2));
402 break;
403 case 4:
404 view = getView<Scalar,DeviceType>(label, f.extent_int(0), f.extent_int(1), f.extent_int(2), f.extent_int(3));
405 break;
406 case 5:
407 view = getView<Scalar,DeviceType>(label, f.extent_int(0), f.extent_int(1), f.extent_int(2), f.extent_int(3), f.extent_int(4));
408 break;
409 case 6:
410 view = getView<Scalar,DeviceType>(label, f.extent_int(0), f.extent_int(1), f.extent_int(2), f.extent_int(3), f.extent_int(4), f.extent_int(5));
411 break;
412 case 7:
413 view = getView<Scalar,DeviceType>(label, f.extent_int(0), f.extent_int(1), f.extent_int(2), f.extent_int(3), f.extent_int(4), f.extent_int(5), f.extent_int(6));
414 break;
415 default:
416 INTREPID2_TEST_FOR_EXCEPTION(true, std::invalid_argument, "Unsupported functor rank");
417 }
418
419 int entryCount = view.size();
420
421 using ExecutionSpace = typename ViewType<Scalar,DeviceType>::execution_space;
422
423 using ViewIteratorScalar = Intrepid2::ViewIterator<ViewType<Scalar,DeviceType>, Scalar>;
424 using FunctorIteratorScalar = FunctorIterator<Functor, Scalar, rank>;
425
426 Kokkos::RangePolicy < ExecutionSpace > policy(0,entryCount);
427 Kokkos::parallel_for( policy,
428 KOKKOS_LAMBDA (const int &enumerationIndex )
429 {
430 ViewIteratorScalar vi(view);
431 FunctorIteratorScalar fi(f);
432
433 vi.setEnumerationIndex(enumerationIndex);
434 fi.setEnumerationIndex(enumerationIndex);
435
436 vi.set(fi.get());
437 }
438 );
439
440 auto hostView = Kokkos::create_mirror_view(view);
441 Kokkos::deep_copy(hostView, view);
442 return hostView;
443 }
444
445 template<class FunctorType, typename Scalar, int rank>
446 void printFunctor(const FunctorType &functor, std::ostream &out, const std::string &functorName = "")
447 {
448 auto functorHostCopy = copyFunctorToHostView<FunctorType, Scalar, rank>(functor);
449
450 std::string name = (functorName == "") ? "Functor" : functorName;
451
452 out << "\n******** " << name << " (rank " << rank << ") ********\n";
453 out << "dimensions: (";
454 for (int r=0; r<rank; r++)
455 {
456 out << functor.extent_int(r);
457 if (r<rank-1) out << ",";
458 }
459 out << ")\n";
460
461 ViewIterator<decltype(functorHostCopy),Scalar> vi(functorHostCopy);
462
463 bool moreEntries = true;
464 while (moreEntries)
465 {
466 Scalar value = vi.get();
467
468 auto location = vi.getLocation();
469 out << functorName << "(";
470 for (ordinal_type i=0; i<rank; i++)
471 {
472 out << location[i];
473 if (i<rank-1)
474 {
475 out << ",";
476 }
477 }
478 out << ") " << value << std::endl;
479
480 moreEntries = (vi.increment() != -1);
481 }
482 out << "\n";
483 }
484
485 template<class FunctorType>
486 void printFunctor1(const FunctorType &functor, std::ostream &out, const std::string &functorName = "")
487 {
488 using Scalar = typename std::remove_reference<decltype(functor(0))>::type;
489 printFunctor<FunctorType, Scalar, 1>(functor, out, functorName);
490 }
491
492 template<class FunctorType>
493 void printFunctor2(const FunctorType &functor, std::ostream &out, const std::string &functorName = "")
494 {
495 using Scalar = typename std::remove_const<typename std::remove_reference<decltype(functor(0,0))>::type>::type;
496 printFunctor<FunctorType, Scalar, 2>(functor, out, functorName);
497 }
498
499 template<class FunctorType>
500 void printFunctor3(const FunctorType &functor, std::ostream &out, const std::string &functorName = "")
501 {
502 using Scalar = typename std::remove_const<typename std::remove_reference<decltype(functor(0,0,0))>::type>::type;
503 printFunctor<FunctorType, Scalar, 3>(functor, out, functorName);
504 }
505
506 template<class FunctorType>
507 void printFunctor4(const FunctorType &functor, std::ostream &out, const std::string &functorName = "")
508 {
509 using Scalar = typename std::remove_const<typename std::remove_reference<decltype(functor(0,0,0,0))>::type>::type;
510 printFunctor<FunctorType, Scalar, 4>(functor, out, functorName);
511 }
512
513 template<class FunctorType>
514 void printFunctor5(const FunctorType &functor, std::ostream &out, const std::string &functorName = "")
515 {
516 using Scalar = typename std::remove_const<typename std::remove_reference<decltype(functor(0,0,0,0,0))>::type>::type;
517 printFunctor<FunctorType, Scalar, 5>(functor, out, functorName);
518 }
519
520 template<class FunctorType>
521 void printFunctor6(const FunctorType &functor, std::ostream &out, const std::string &functorName = "")
522 {
523 using Scalar = typename std::remove_const<typename std::remove_reference<decltype(functor(0,0,0,0,0,0))>::type>::type;
524 printFunctor<FunctorType, Scalar, 6>(functor, out, functorName);
525 }
526
527 template<class FunctorType>
528 void printFunctor7(const FunctorType &functor, std::ostream &out, const std::string &functorName = "")
529 {
530 using Scalar = typename std::remove_const<typename std::remove_reference<decltype(functor(0,0,0,0,0,0,0))>::type>::type;
531 printFunctor<FunctorType, Scalar, 7>(functor, out, functorName);
532 }
533
534 template<class View>
535 void printView(const View &view, std::ostream &out, const std::string &viewName = "")
536 {
537 using Scalar = typename View::value_type;
538 using HostView = typename View::HostMirror;
539 using HostViewIteratorScalar = Intrepid2::ViewIterator<HostView, Scalar>;
540
541 auto hostView = getHostCopy(view);
542
543 HostViewIteratorScalar vi(hostView);
544
545 bool moreEntries = (vi.nextIncrementRank() != -1);
546 while (moreEntries)
547 {
548 Scalar value = vi.get();
549
550 auto location = vi.getLocation();
551 out << viewName << "(";
552 for (unsigned i=0; i<getFunctorRank(view); i++)
553 {
554 out << location[i];
555 if (i<getFunctorRank(view)-1)
556 {
557 out << ",";
558 }
559 }
560 out << ") " << value << std::endl;
561
562 moreEntries = (vi.increment() != -1);
563 }
564 }
565
566 template <class FunctorType1, class FunctorType2, int rank, typename Scalar=typename FunctorType1::value_type, class ExecutionSpace = typename FunctorType1::execution_space>
567 typename std::enable_if< !supports_rank<FunctorType1,rank>::value, void >::type
568 testFloatingEquality(const FunctorType1 &functor1, const FunctorType2 &functor2, double relTol, double absTol, Teuchos::FancyOStream &out, bool &success,
569 std::string functor1Name = "Functor 1", std::string functor2Name = "Functor 2")
570 {
571 INTREPID2_TEST_FOR_EXCEPTION(true, std::invalid_argument, "testFloatingEquality() called on FunctorType1 that does not support the specified rank.\n");
572 }
573
575 template <class FunctorType1, class FunctorType2, int rank, typename Scalar=typename FunctorType1::value_type, class ExecutionSpace = typename FunctorType1::execution_space>
576 typename std::enable_if< supports_rank<FunctorType1,rank>::value, void >::type
577 testFloatingEquality(const FunctorType1 &functor1, const FunctorType2 &functor2, double relTol, double absTol, Teuchos::FancyOStream &out, bool &success,
578 std::string functor1Name = "Functor 1", std::string functor2Name = "Functor 2")
579 {
580 static_assert( supports_rank<FunctorType2,rank>::value, "Both Functor1 and Functor2 must support the specified rank through operator().");
581 using Functor1IteratorScalar = FunctorIterator<FunctorType1, Scalar, rank>;
582 using Functor2IteratorScalar = FunctorIterator<FunctorType2, Scalar, rank>;
583
584 // check that rank/size match
585 TEUCHOS_TEST_FOR_EXCEPTION(getFunctorRank(functor1) != rank, std::invalid_argument, "functor1 and functor2 must agree in rank"); // Kokkos::View does not provide rank() method; getFunctorRank() provides common interface
586 TEUCHOS_TEST_FOR_EXCEPTION(getFunctorRank(functor2) != rank, std::invalid_argument, "functor1 and functor2 must agree in rank"); // Kokkos::View does not provide rank() method; getFunctorRank() provides common interface
587
588 int entryCount = 1;
589 for (unsigned i=0; i<getFunctorRank(functor1); i++)
590 {
591 TEUCHOS_TEST_FOR_EXCEPTION(functor1.extent_int(i) != functor2.extent_int(i), std::invalid_argument,
592 "functor1 and functor2 must agree in size in each dimension; functor1 has extent "
593 + std::to_string(functor1.extent_int(i)) + " in dimension " + std::to_string(i)
594 + "; functor2 has extent " + std::to_string(functor2.extent_int(i)) );
595 entryCount *= functor1.extent_int(i);
596 }
597 if (entryCount == 0) return; // nothing to test
598
599 ViewType<bool,ExecutionSpace> valuesMatch = getView<bool,ExecutionSpace>("valuesMatch", entryCount);
600
601 Kokkos::RangePolicy < ExecutionSpace > policy(0,entryCount);
602 Kokkos::parallel_for( policy,
603 KOKKOS_LAMBDA (const int &enumerationIndex )
604 {
605 Functor1IteratorScalar vi1(functor1);
606 Functor2IteratorScalar vi2(functor2);
607
608 vi1.setEnumerationIndex(enumerationIndex);
609 vi2.setEnumerationIndex(enumerationIndex);
610
611 const Scalar & value1 = vi1.get();
612 const Scalar & value2 = vi2.get();
613
614 bool errMeetsTol = errMeetsAbsAndRelTol(value1, value2, relTol, absTol);
615 valuesMatch(enumerationIndex) = errMeetsTol;
616 }
617 );
618
619 int failureCount = 0;
620 Kokkos::RangePolicy<ExecutionSpace > reducePolicy(0, entryCount);
621 Kokkos::parallel_reduce( reducePolicy,
622 KOKKOS_LAMBDA( const int &enumerationIndex, int &reducedValue )
623 {
624 reducedValue += valuesMatch(enumerationIndex) ? 0 : 1;
625 }, failureCount);
626
627 const bool allValuesMatch = (failureCount == 0);
628 success = success && allValuesMatch;
629
630 if (!allValuesMatch)
631 {
632 // copy functors to host views
633 auto functor1CopyHost = copyFunctorToHostView<FunctorType1,Scalar,rank>(functor1);
634 auto functor2CopyHost = copyFunctorToHostView<FunctorType2,Scalar,rank>(functor2);
635
636 auto valuesMatchHost = getHostCopy(valuesMatch);
637
638 FunctorIterator<decltype(functor1CopyHost),Scalar,rank> vi1(functor1CopyHost);
639 FunctorIterator<decltype(functor2CopyHost),Scalar,rank> vi2(functor2CopyHost);
640 Intrepid2::ViewIterator<decltype(valuesMatchHost), bool> viMatch(valuesMatchHost);
641
642 bool moreEntries = true;
643 while (moreEntries)
644 {
645 bool errMeetsTol = viMatch.get();
646
647 if (!errMeetsTol)
648 {
649 const Scalar value1 = vi1.get();
650 const Scalar value2 = vi2.get();
651
652 success = false;
653 auto location = vi1.getLocation();
654 out << "At location (";
655 for (unsigned i=0; i<getFunctorRank(functor1); i++)
656 {
657 out << location[i];
658 if (i<getFunctorRank(functor1)-1)
659 {
660 out << ",";
661 }
662 }
663 out << ") " << functor1Name << " value != " << functor2Name << " value (";
664 out << value1 << " != " << value2 << "); diff is " << std::abs(value1-value2) << std::endl;
665 }
666
667 moreEntries = (vi1.increment() != -1);
668 moreEntries = moreEntries && (vi2.increment() != -1);
669 moreEntries = moreEntries && (viMatch.increment() != -1);
670 }
671 }
672 }
673
674 template <class ViewType, class FunctorType>
675 void testFloatingEquality1(const ViewType &view, const FunctorType &functor, double relTol, double absTol, Teuchos::FancyOStream &out, bool &success,
676 std::string view1Name = "View", std::string view2Name = "Functor")
677 {
678 testFloatingEquality<ViewType, FunctorType, 1>(view, functor, relTol, absTol, out, success, view1Name, view2Name);
679 }
680
681 template <class ViewType, class FunctorType>
682 void testFloatingEquality2(const ViewType &view, const FunctorType &functor, double relTol, double absTol, Teuchos::FancyOStream &out, bool &success,
683 std::string view1Name = "View", std::string view2Name = "Functor")
684 {
685 testFloatingEquality<ViewType, FunctorType, 2>(view, functor, relTol, absTol, out, success, view1Name, view2Name);
686 }
687
688 template <class ViewType, class FunctorType>
689 void testFloatingEquality3(const ViewType &view, const FunctorType &functor, double relTol, double absTol, Teuchos::FancyOStream &out, bool &success,
690 std::string view1Name = "View", std::string view2Name = "Functor")
691 {
692 testFloatingEquality<ViewType, FunctorType, 3>(view, functor, relTol, absTol, out, success, view1Name, view2Name);
693 }
694
695 template <class ViewType, class FunctorType>
696 void testFloatingEquality4(const ViewType &view, const FunctorType &functor, double relTol, double absTol, Teuchos::FancyOStream &out, bool &success,
697 std::string view1Name = "View", std::string view2Name = "Functor")
698 {
699 testFloatingEquality<ViewType, FunctorType, 4>(view, functor, relTol, absTol, out, success, view1Name, view2Name);
700 }
701
702 template <class ViewType, class FunctorType>
703 void testFloatingEquality5(const ViewType &view, const FunctorType &functor, double relTol, double absTol, Teuchos::FancyOStream &out, bool &success,
704 std::string view1Name = "View", std::string view2Name = "Functor")
705 {
706 testFloatingEquality<ViewType, FunctorType, 5>(view, functor, relTol, absTol, out, success, view1Name, view2Name);
707 }
708
709 template <class ViewType, class FunctorType>
710 void testFloatingEquality6(const ViewType &view, const FunctorType &functor, double relTol, double absTol, Teuchos::FancyOStream &out, bool &success,
711 std::string view1Name = "View", std::string view2Name = "Functor")
712 {
713 testFloatingEquality<ViewType, FunctorType, 6>(view, functor, relTol, absTol, out, success, view1Name, view2Name);
714 }
715
716 template <class ViewType, class FunctorType>
717 void testFloatingEquality7(const ViewType &view, const FunctorType &functor, double relTol, double absTol, Teuchos::FancyOStream &out, bool &success,
718 std::string view1Name = "View", std::string view2Name = "Functor")
719 {
720 testFloatingEquality<ViewType, FunctorType, 7>(view, functor, relTol, absTol, out, success, view1Name, view2Name);
721 }
722
723 template <class ViewType1, class ViewType2>
724 void testViewFloatingEquality(const ViewType1 &view1, const ViewType2 &view2, double relTol, double absTol, Teuchos::FancyOStream &out, bool &success,
725 std::string view1Name = "View 1", std::string view2Name = "View 2")
726 {
727 // check that rank/size match
728 TEUCHOS_TEST_FOR_EXCEPTION(view1.rank() != view2.rank(), std::invalid_argument, "views must agree in rank");
729 for (unsigned i=0; i<view1.rank(); i++)
730 {
731 TEUCHOS_TEST_FOR_EXCEPTION(view1.extent_int(i) != view2.extent_int(i), std::invalid_argument, "views must agree in size in each dimension");
732 }
733
734 if (view1.size() == 0) return; // nothing to test
735
736 const int rank = view1.rank();
737 switch (rank)
738 {
739 case 0: testFloatingEquality<ViewType1, ViewType2, 0>(view1, view2, relTol, absTol, out, success, view1Name, view2Name); break;
740 case 1: testFloatingEquality<ViewType1, ViewType2, 1>(view1, view2, relTol, absTol, out, success, view1Name, view2Name); break;
741 case 2: testFloatingEquality<ViewType1, ViewType2, 2>(view1, view2, relTol, absTol, out, success, view1Name, view2Name); break;
742 case 3: testFloatingEquality<ViewType1, ViewType2, 3>(view1, view2, relTol, absTol, out, success, view1Name, view2Name); break;
743 case 4: testFloatingEquality<ViewType1, ViewType2, 4>(view1, view2, relTol, absTol, out, success, view1Name, view2Name); break;
744 case 5: testFloatingEquality<ViewType1, ViewType2, 5>(view1, view2, relTol, absTol, out, success, view1Name, view2Name); break;
745 case 6: testFloatingEquality<ViewType1, ViewType2, 6>(view1, view2, relTol, absTol, out, success, view1Name, view2Name); break;
746 case 7: testFloatingEquality<ViewType1, ViewType2, 7>(view1, view2, relTol, absTol, out, success, view1Name, view2Name); break;
747 default: INTREPID2_TEST_FOR_EXCEPTION(true, std::invalid_argument, "Unsupported rank");
748 }
749 }
750
751} // namespace Intrepid2
752
753#ifdef HAVE_INTREPID2_SACADO
754using Sacado_Fad_DFadType = Sacado::Fad::DFad<double>;
755#define INTREPID2_POINTSCALAR_TEST_INSTANT(GROUP_NAME, TEST_NAME) \
756\
757TEUCHOS_UNIT_TEST_TEMPLATE_1_INSTANT( GROUP_NAME, TEST_NAME, double ) \
758\
759TEUCHOS_UNIT_TEST_TEMPLATE_1_INSTANT( GROUP_NAME, TEST_NAME, Sacado_Fad_DFadType ) \
760
761#define INTREPID2_OUTPUTSCALAR_POINTSCALAR_TEST_INSTANT(GROUP_NAME, TEST_NAME) \
762\
763TEUCHOS_UNIT_TEST_TEMPLATE_2_INSTANT( GROUP_NAME, TEST_NAME, double, double ) \
764\
765TEUCHOS_UNIT_TEST_TEMPLATE_2_INSTANT( GROUP_NAME, TEST_NAME, Sacado_Fad_DFadType, Sacado_Fad_DFadType ) \
766
767#else
768#define INTREPID2_POINTSCALAR_TEST_INSTANT(GROUP_NAME, TEST_NAME) \
769\
770TEUCHOS_UNIT_TEST_TEMPLATE_1_INSTANT( GROUP_NAME, TEST_NAME, double ) \
771
772#define INTREPID2_OUTPUTSCALAR_POINTSCALAR_TEST_INSTANT(GROUP_NAME, TEST_NAME) \
773\
774TEUCHOS_UNIT_TEST_TEMPLATE_2_INSTANT( GROUP_NAME, TEST_NAME, double, double ) \
775
776#endif
777
778#endif /* Intrepid2_TestUtils_h */
Header file for the abstract base class Intrepid2::Basis.
Teuchos::RCP< Basis< DeviceType, OutputType, PointType > > BasisPtr
Basis Pointer.
KOKKOS_INLINE_FUNCTION ordinal_type getDkCardinality(const EOperator operatorType, const ordinal_type spaceDim)
Returns cardinality of Dk, i.e., the number of all derivatives of order k.
Stateless class representing a family of basis functions, templated on H(vol) and H(grad) on the line...
Defines the Intrepid2::FunctorIterator class, as well as the Intrepid2::functor_returns_ref SFINAE he...
Stateless classes that act as factories for two families of hierarchical bases. HierarchicalBasisFami...
Header file for Intrepid2::PointTools class to provide utilities for barycentric coordinates,...
Header file to include all Sacado headers that are required if using Intrepid2 with Sacado types.
ViewType< Scalar, DefaultTestDeviceType >::HostMirror copyFunctorToHostView(const Functor &deviceFunctor)
Copy the values for the specified functor.
ViewType< PointValueType, DeviceType > getInputPointsView(shards::CellTopology &cellTopo, int numPoints_1D)
Returns a DynRankView containing regularly-spaced points on the specified cell topology.
typename Kokkos::DefaultExecutionSpace::device_type DefaultTestDeviceType
Default Kokkos::Device to use for tests; depends on platform.
constexpr int MAX_FAD_DERIVATIVES_FOR_TESTS
Maximum number of derivatives to track for Fad types in tests.
const Teuchos::ScalarTraits< Scalar >::magnitudeType smallNumber()
Use Teuchos small number determination on host; pass this to Intrepid2::relErr() on device.
KOKKOS_INLINE_FUNCTION bool relErrMeetsTol(const Scalar1 &s1, const Scalar2 &s2, const typename Teuchos::ScalarTraits< typename std::common_type< Scalar1, Scalar2 >::type >::magnitudeType &smallNumber, const double &tol)
Adapted from Teuchos::relErr(); for use in code that may be executed on device.
Header function for Intrepid2::Util class and other utility functions.
enable_if_t< has_rank_method< Functor >::value, unsigned > KOKKOS_INLINE_FUNCTION getFunctorRank(const Functor &functor)
A family of basis functions, constructed from H(vol) and H(grad) bases on the line.
essentially, a read-only variant of ViewIterator, for a general functor (extent_int() and rank() supp...
Basis defining integrated Legendre basis on the line, a polynomial subspace of H(grad) on the line.
Basis defining Legendre basis on the line, a polynomial subspace of L^2 (a.k.a. H(vol)) on the line.
static ordinal_type getLatticeSize(const shards::CellTopology cellType, const ordinal_type order, const ordinal_type offset=0)
Computes the number of points in a lattice of a given order on a simplex (currently disabled for othe...
static void getLattice(Kokkos::DynRankView< pointValueType, pointProperties... > points, const shards::CellTopology cellType, const ordinal_type order, const ordinal_type offset=0, const EPointType pointType=POINTTYPE_EQUISPACED)
Computes a lattice of points of a given order on a reference simplex, quadrilateral or hexahedron (cu...
A helper class that allows iteration over some part of a Kokkos View, while allowing the calling code...
SFINAE helper to detect whether a type supports a rank-integral-argument operator().
Helper to get Scalar[*+] where the number of *'s matches the given rank.