vtk-m2/vtkm/testing/TestingMath.h
Sujin Philip e28309f09b Remove VTKM_EXEC_CONSTANT
If a global static array is declared with VTKM_EXEC_CONSTANT and the code
is compiled by nvcc (for multibackend code) then the array is only accesible
on the GPU. If for some reason a worklet fails on the cuda backend and it is
re-executed on any of the CPU backends, it will continue to fail.

We couldn't find a simple way to declare the array once and have it available
on both CPU and GPU. The approach we are using here is to declare the arrays
as static inside some "Get" function which is marked as VTKM_EXEC_CONT.
2017-12-05 13:49:55 -05:00

774 lines
25 KiB
C++

//=============================================================================
//
// Copyright (c) Kitware, Inc.
// All rights reserved.
// See LICENSE.txt for details.
//
// This software is distributed WITHOUT ANY WARRANTY; without even
// the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR
// PURPOSE. See the above copyright notice for more information.
//
// Copyright 2015 National Technology & Engineering Solutions of Sandia, LLC (NTESS).
// Copyright 2015 UT-Battelle, LLC.
// Copyright 2015 Los Alamos National Security.
//
// Under the terms of Contract DE-NA0003525 with NTESS,
// the U.S. Government retains certain rights in this software.
// Under the terms of Contract DE-AC52-06NA25396 with Los Alamos National
// Laboratory (LANL), the U.S. Government retains certain rights in
// this software.
//
//=============================================================================
#ifndef vtk_m_testing_TestingMath_h
#define vtk_m_testing_TestingMath_h
#include <vtkm/Math.h>
#include <vtkm/TypeListTag.h>
#include <vtkm/VecTraits.h>
#include <vtkm/exec/FunctorBase.h>
#include <vtkm/cont/DeviceAdapterAlgorithm.h>
#include <vtkm/cont/testing/Testing.h>
#define VTKM_MATH_ASSERT(condition, message) \
if (!(condition)) \
{ \
this->RaiseError(message); \
}
//-----------------------------------------------------------------------------
namespace UnitTestMathNamespace
{
class Lists
{
public:
static const vtkm::IdComponent NUM_NUMBERS = 5;
private:
struct Data
{
vtkm::Float64 NumberList[NUM_NUMBERS];
vtkm::Float64 AngleList[NUM_NUMBERS];
vtkm::Float64 OppositeList[NUM_NUMBERS];
vtkm::Float64 AdjacentList[NUM_NUMBERS];
vtkm::Float64 HypotenuseList[NUM_NUMBERS];
vtkm::Float64 NumeratorList[NUM_NUMBERS];
vtkm::Float64 DenominatorList[NUM_NUMBERS];
vtkm::Float64 FModRemainderList[NUM_NUMBERS];
vtkm::Float64 RemainderList[NUM_NUMBERS];
vtkm::Int64 QuotientList[NUM_NUMBERS];
vtkm::Float64 XList[NUM_NUMBERS];
vtkm::Float64 FractionalList[NUM_NUMBERS];
vtkm::Float64 FloorList[NUM_NUMBERS];
vtkm::Float64 CeilList[NUM_NUMBERS];
vtkm::Float64 RoundList[NUM_NUMBERS];
};
public:
VTKM_EXEC_CONT static const Data& Get()
{
static const Data data = {
// NumberList
{ 0.25, 0.5, 1.0, 2.0, 3.75 },
// AngleList
{ 0.643501108793284, // angle for 3, 4, 5 triangle.
0.78539816339745, // pi/4
0.5235987755983, // pi/6
1.0471975511966, // pi/3
0.0 },
// OppositeList
{ 3.0, 1.0, 1.0, 1.732050807568877 /*sqrt(3)*/, 0.0 },
// AdjacentList
{ 4.0, 1.0, 1.732050807568877 /*sqrt(3)*/, 1.0, 1.0 },
// HypotenuseList
{ 5.0, 1.414213562373095 /*sqrt(2)*/, 2.0, 2.0, 1.0 },
// NumeratorList
{ 6.5, 5.8, 9.3, 77.0, 0.1 },
// DenominatorList
{ 2.3, 1.6, 3.1, 19.0, 0.4 },
// FModRemainderList
{ 1.9, 1.0, 0.0, 1.0, 0.1 },
// RemainderList
{ -0.4, -0.6, 0.0, 1.0, 0.1 },
// QuotientList
{ 3, 4, 3, 4, 0 },
// XList
{ 4.6, 0.1, 73.4, 55.0, 3.75 },
// FractionalList
{ 0.6, 0.1, 0.4, 0.0, 0.75 },
// FloorList
{ 4.0, 0.0, 73.0, 55.0, 3.0 },
// CeilList
{ 5.0, 1.0, 74.0, 55.0, 4.0 },
// RoundList
{ 5.0, 0.0, 73.0, 55.0, 4.0 },
};
return data;
}
};
//-----------------------------------------------------------------------------
template <typename T>
struct ScalarFieldTests : public vtkm::exec::FunctorBase
{
VTKM_EXEC
void TestPi() const
{
// std::cout << "Testing Pi" << std::endl;
VTKM_MATH_ASSERT(test_equal(vtkm::Pi(), 3.14159265), "Pi not correct.");
}
VTKM_EXEC
void TestArcTan2() const
{
// std::cout << "Testing arc tan 2" << std::endl;
VTKM_MATH_ASSERT(test_equal(vtkm::ATan2(T(0.0), T(1.0)), T(0.0)), "ATan2 x+ axis.");
VTKM_MATH_ASSERT(test_equal(vtkm::ATan2(T(1.0), T(0.0)), T(0.5 * vtkm::Pi())),
"ATan2 y+ axis.");
VTKM_MATH_ASSERT(test_equal(vtkm::ATan2(T(-1.0), T(0.0)), T(-0.5 * vtkm::Pi())),
"ATan2 y- axis.");
VTKM_MATH_ASSERT(test_equal(vtkm::ATan2(T(1.0), T(1.0)), T(0.25 * vtkm::Pi())),
"ATan2 Quadrant 1");
VTKM_MATH_ASSERT(test_equal(vtkm::ATan2(T(1.0), T(-1.0)), T(0.75 * vtkm::Pi())),
"ATan2 Quadrant 2");
VTKM_MATH_ASSERT(test_equal(vtkm::ATan2(T(-1.0), T(-1.0)), T(-0.75 * vtkm::Pi())),
"ATan2 Quadrant 3");
VTKM_MATH_ASSERT(test_equal(vtkm::ATan2(T(-1.0), T(1.0)), T(-0.25 * vtkm::Pi())),
"ATan2 Quadrant 4");
}
VTKM_EXEC
void TestPow() const
{
// std::cout << "Running power tests." << std::endl;
for (vtkm::IdComponent index = 0; index < Lists::NUM_NUMBERS; index++)
{
T x = static_cast<T>(Lists::Get().NumberList[index]);
T powx = vtkm::Pow(x, static_cast<T>(2.0));
T sqrx = x * x;
VTKM_MATH_ASSERT(test_equal(powx, sqrx), "Power gave wrong result.");
}
}
VTKM_EXEC
void TestLog2() const
{
// std::cout << "Testing Log2" << std::endl;
VTKM_MATH_ASSERT(test_equal(vtkm::Log2(T(0.25)), T(-2.0)), "Bad value from Log2");
VTKM_MATH_ASSERT(test_equal(vtkm::Log2(vtkm::Vec<T, 4>(0.5, 1.0, 2.0, 4.0)),
vtkm::Vec<T, 4>(-1.0, 0.0, 1.0, 2.0)),
"Bad value from Log2");
}
VTKM_EXEC
void TestNonFinites() const
{
// std::cout << "Testing non-finites." << std::endl;
T zero = 0.0;
T finite = 1.0;
T nan = vtkm::Nan<T>();
T inf = vtkm::Infinity<T>();
T neginf = vtkm::NegativeInfinity<T>();
T epsilon = vtkm::Epsilon<T>();
// General behavior.
VTKM_MATH_ASSERT(nan != vtkm::Nan<T>(), "Nan not equal itself.");
VTKM_MATH_ASSERT(!(nan >= zero), "Nan not greater or less.");
VTKM_MATH_ASSERT(!(nan <= zero), "Nan not greater or less.");
VTKM_MATH_ASSERT(!(nan >= finite), "Nan not greater or less.");
VTKM_MATH_ASSERT(!(nan <= finite), "Nan not greater or less.");
VTKM_MATH_ASSERT(neginf < inf, "Infinity big");
VTKM_MATH_ASSERT(zero < inf, "Infinity big");
VTKM_MATH_ASSERT(finite < inf, "Infinity big");
VTKM_MATH_ASSERT(zero > -inf, "-Infinity small");
VTKM_MATH_ASSERT(finite > -inf, "-Infinity small");
VTKM_MATH_ASSERT(zero > neginf, "-Infinity small");
VTKM_MATH_ASSERT(finite > neginf, "-Infinity small");
VTKM_MATH_ASSERT(zero < epsilon, "Negative epsilon");
VTKM_MATH_ASSERT(finite > epsilon, "Large epsilon");
// Math check functions.
VTKM_MATH_ASSERT(!vtkm::IsNan(zero), "Bad IsNan check.");
VTKM_MATH_ASSERT(!vtkm::IsNan(finite), "Bad IsNan check.");
VTKM_MATH_ASSERT(vtkm::IsNan(nan), "Bad IsNan check.");
VTKM_MATH_ASSERT(!vtkm::IsNan(inf), "Bad IsNan check.");
VTKM_MATH_ASSERT(!vtkm::IsNan(neginf), "Bad IsNan check.");
VTKM_MATH_ASSERT(!vtkm::IsNan(epsilon), "Bad IsNan check.");
VTKM_MATH_ASSERT(!vtkm::IsInf(zero), "Bad infinity check.");
VTKM_MATH_ASSERT(!vtkm::IsInf(finite), "Bad infinity check.");
VTKM_MATH_ASSERT(!vtkm::IsInf(nan), "Bad infinity check.");
VTKM_MATH_ASSERT(vtkm::IsInf(inf), "Bad infinity check.");
VTKM_MATH_ASSERT(vtkm::IsInf(neginf), "Bad infinity check.");
VTKM_MATH_ASSERT(!vtkm::IsInf(epsilon), "Bad infinity check.");
VTKM_MATH_ASSERT(vtkm::IsFinite(zero), "Bad finite check.");
VTKM_MATH_ASSERT(vtkm::IsFinite(finite), "Bad finite check.");
VTKM_MATH_ASSERT(!vtkm::IsFinite(nan), "Bad finite check.");
VTKM_MATH_ASSERT(!vtkm::IsFinite(inf), "Bad finite check.");
VTKM_MATH_ASSERT(!vtkm::IsFinite(neginf), "Bad finite check.");
VTKM_MATH_ASSERT(vtkm::IsFinite(epsilon), "Bad finite check.");
}
VTKM_EXEC
void TestRemainders() const
{
// std::cout << "Testing remainders." << std::endl;
for (vtkm::IdComponent index = 0; index < Lists::NUM_NUMBERS; index++)
{
T numerator = static_cast<T>(Lists::Get().NumeratorList[index]);
T denominator = static_cast<T>(Lists::Get().DenominatorList[index]);
T fmodremainder = static_cast<T>(Lists::Get().FModRemainderList[index]);
T remainder = static_cast<T>(Lists::Get().RemainderList[index]);
vtkm::Int64 quotient = Lists::Get().QuotientList[index];
VTKM_MATH_ASSERT(test_equal(vtkm::FMod(numerator, denominator), fmodremainder),
"Bad FMod remainder.");
VTKM_MATH_ASSERT(test_equal(vtkm::Remainder(numerator, denominator), remainder),
"Bad remainder.");
vtkm::Int64 q;
VTKM_MATH_ASSERT(test_equal(vtkm::RemainderQuotient(numerator, denominator, q), remainder),
"Bad remainder-quotient remainder.");
VTKM_MATH_ASSERT(test_equal(q, quotient), "Bad reminder-quotient quotient.");
}
}
VTKM_EXEC
void TestRound() const
{
// std::cout << "Testing round." << std::endl;
for (vtkm::IdComponent index = 0; index < Lists::NUM_NUMBERS; index++)
{
T x = static_cast<T>(Lists::Get().XList[index]);
T fractional = static_cast<T>(Lists::Get().FractionalList[index]);
T floor = static_cast<T>(Lists::Get().FloorList[index]);
T ceil = static_cast<T>(Lists::Get().CeilList[index]);
T round = static_cast<T>(Lists::Get().RoundList[index]);
T intPart;
VTKM_MATH_ASSERT(test_equal(vtkm::ModF(x, intPart), fractional),
"ModF returned wrong fractional part.");
VTKM_MATH_ASSERT(test_equal(intPart, floor), "ModF returned wrong integral part.");
VTKM_MATH_ASSERT(test_equal(vtkm::Floor(x), floor), "Bad floor.");
VTKM_MATH_ASSERT(test_equal(vtkm::Ceil(x), ceil), "Bad ceil.");
VTKM_MATH_ASSERT(test_equal(vtkm::Round(x), round), "Bad round.");
}
}
VTKM_EXEC
void TestIsNegative() const
{
// std::cout << "Testing SignBit and IsNegative." << std::endl;
T x = 0;
VTKM_MATH_ASSERT(vtkm::SignBit(x) == 0, "SignBit wrong for 0.");
VTKM_MATH_ASSERT(!vtkm::IsNegative(x), "IsNegative wrong for 0.");
x = 20;
VTKM_MATH_ASSERT(vtkm::SignBit(x) == 0, "SignBit wrong for 20.");
VTKM_MATH_ASSERT(!vtkm::IsNegative(x), "IsNegative wrong for 20.");
x = -20;
VTKM_MATH_ASSERT(vtkm::SignBit(x) != 0, "SignBit wrong for -20.");
VTKM_MATH_ASSERT(vtkm::IsNegative(x), "IsNegative wrong for -20.");
x = 0.02f;
VTKM_MATH_ASSERT(vtkm::SignBit(x) == 0, "SignBit wrong for 0.02.");
VTKM_MATH_ASSERT(!vtkm::IsNegative(x), "IsNegative wrong for 0.02.");
x = -0.02f;
VTKM_MATH_ASSERT(vtkm::SignBit(x) != 0, "SignBit wrong for -0.02.");
VTKM_MATH_ASSERT(vtkm::IsNegative(x), "IsNegative wrong for -0.02.");
}
VTKM_EXEC
void operator()(vtkm::Id) const
{
this->TestPi();
this->TestArcTan2();
this->TestPow();
this->TestLog2();
this->TestNonFinites();
this->TestRemainders();
this->TestRound();
this->TestIsNegative();
}
};
template <typename Device>
struct TryScalarFieldTests
{
template <typename T>
void operator()(const T&) const
{
vtkm::cont::DeviceAdapterAlgorithm<Device>::Schedule(ScalarFieldTests<T>(), 1);
}
};
//-----------------------------------------------------------------------------
template <typename VectorType>
struct ScalarVectorFieldTests : public vtkm::exec::FunctorBase
{
typedef vtkm::VecTraits<VectorType> Traits;
typedef typename Traits::ComponentType ComponentType;
enum
{
NUM_COMPONENTS = Traits::NUM_COMPONENTS
};
VTKM_EXEC
void TestTriangleTrig() const
{
// std::cout << "Testing normal trig functions." << std::endl;
for (vtkm::IdComponent index = 0; index < Lists::NUM_NUMBERS - NUM_COMPONENTS + 1; index++)
{
VectorType angle;
VectorType opposite;
VectorType adjacent;
VectorType hypotenuse;
for (vtkm::IdComponent componentIndex = 0; componentIndex < NUM_COMPONENTS; componentIndex++)
{
Traits::SetComponent(
angle,
componentIndex,
static_cast<ComponentType>(Lists::Get().AngleList[componentIndex + index]));
Traits::SetComponent(
opposite,
componentIndex,
static_cast<ComponentType>(Lists::Get().OppositeList[componentIndex + index]));
Traits::SetComponent(
adjacent,
componentIndex,
static_cast<ComponentType>(Lists::Get().AdjacentList[componentIndex + index]));
Traits::SetComponent(
hypotenuse,
componentIndex,
static_cast<ComponentType>(Lists::Get().HypotenuseList[componentIndex + index]));
}
VTKM_MATH_ASSERT(test_equal(vtkm::Sin(angle), opposite / hypotenuse), "Sin failed test.");
VTKM_MATH_ASSERT(test_equal(vtkm::Cos(angle), adjacent / hypotenuse), "Cos failed test.");
VTKM_MATH_ASSERT(test_equal(vtkm::Tan(angle), opposite / adjacent), "Tan failed test.");
VTKM_MATH_ASSERT(test_equal(vtkm::ASin(opposite / hypotenuse), angle),
"Arc Sin failed test.");
#if defined(VTKM_ICC)
// When the intel compiler has vectorization enabled ( -O2/-O3 ) it converts the
// `adjacent/hypotenuse` divide operation into reciprocal (rcpps) and
// multiply (mulps) operations. This causes a change in the expected result that
// is larger than the default tolerance of test_equal.
//
VTKM_MATH_ASSERT(test_equal(vtkm::ACos(adjacent / hypotenuse), angle, 0.0004),
"Arc Cos failed test.");
#else
VTKM_MATH_ASSERT(test_equal(vtkm::ACos(adjacent / hypotenuse), angle),
"Arc Cos failed test.");
#endif
VTKM_MATH_ASSERT(test_equal(vtkm::ATan(opposite / adjacent), angle), "Arc Tan failed test.");
}
}
VTKM_EXEC
void TestHyperbolicTrig() const
{
// std::cout << "Testing hyperbolic trig functions." << std::endl;
const VectorType zero(0);
const VectorType half(0.5);
for (vtkm::IdComponent index = 0; index < Lists::NUM_NUMBERS - NUM_COMPONENTS + 1; index++)
{
VectorType x;
for (vtkm::IdComponent componentIndex = 0; componentIndex < NUM_COMPONENTS; componentIndex++)
{
Traits::SetComponent(
x,
componentIndex,
static_cast<ComponentType>(Lists::Get().AngleList[componentIndex + index]));
}
const VectorType minusX = zero - x;
VTKM_MATH_ASSERT(test_equal(vtkm::SinH(x), half * (vtkm::Exp(x) - vtkm::Exp(minusX))),
"SinH does not match definition.");
VTKM_MATH_ASSERT(test_equal(vtkm::CosH(x), half * (vtkm::Exp(x) + vtkm::Exp(minusX))),
"SinH does not match definition.");
VTKM_MATH_ASSERT(test_equal(vtkm::TanH(x), vtkm::SinH(x) / vtkm::CosH(x)),
"TanH does not match definition");
VTKM_MATH_ASSERT(test_equal(vtkm::ASinH(vtkm::SinH(x)), x), "SinH not inverting.");
VTKM_MATH_ASSERT(test_equal(vtkm::ACosH(vtkm::CosH(x)), x), "CosH not inverting.");
VTKM_MATH_ASSERT(test_equal(vtkm::ATanH(vtkm::TanH(x)), x), "TanH not inverting.");
}
}
template <typename FunctionType>
VTKM_EXEC void RaiseToTest(FunctionType function, ComponentType exponent) const
{
for (vtkm::IdComponent index = 0; index < Lists::NUM_NUMBERS - NUM_COMPONENTS + 1; index++)
{
VectorType original;
VectorType raiseresult;
for (vtkm::IdComponent componentIndex = 0; componentIndex < NUM_COMPONENTS; componentIndex++)
{
ComponentType x =
static_cast<ComponentType>(Lists::Get().NumberList[componentIndex + index]);
Traits::SetComponent(original, componentIndex, x);
Traits::SetComponent(raiseresult, componentIndex, vtkm::Pow(x, exponent));
}
VectorType mathresult = function(original);
VTKM_MATH_ASSERT(test_equal(mathresult, raiseresult), "Exponent functions do not agree.");
}
}
struct SqrtFunctor
{
VTKM_EXEC
VectorType operator()(VectorType x) const { return vtkm::Sqrt(x); }
};
VTKM_EXEC
void TestSqrt() const
{
// std::cout << " Testing Sqrt" << std::endl;
RaiseToTest(SqrtFunctor(), 0.5);
}
struct RSqrtFunctor
{
VTKM_EXEC
VectorType operator()(VectorType x) const { return vtkm::RSqrt(x); }
};
VTKM_EXEC
void TestRSqrt() const
{
// std::cout << " Testing RSqrt"<< std::endl;
RaiseToTest(RSqrtFunctor(), -0.5);
}
struct CbrtFunctor
{
VTKM_EXEC
VectorType operator()(VectorType x) const { return vtkm::Cbrt(x); }
};
VTKM_EXEC
void TestCbrt() const
{
// std::cout << " Testing Cbrt" << std::endl;
RaiseToTest(CbrtFunctor(), vtkm::Float32(1.0 / 3.0));
}
struct RCbrtFunctor
{
VTKM_EXEC
VectorType operator()(VectorType x) const { return vtkm::RCbrt(x); }
};
VTKM_EXEC
void TestRCbrt() const
{
// std::cout << " Testing RCbrt" << std::endl;
RaiseToTest(RCbrtFunctor(), vtkm::Float32(-1.0 / 3.0));
}
template <typename FunctionType>
VTKM_EXEC void RaiseByTest(FunctionType function,
ComponentType base,
ComponentType exponentbias = 0.0,
ComponentType resultbias = 0.0) const
{
for (vtkm::IdComponent index = 0; index < Lists::NUM_NUMBERS - NUM_COMPONENTS + 1; index++)
{
VectorType original;
VectorType raiseresult;
for (vtkm::IdComponent componentIndex = 0; componentIndex < NUM_COMPONENTS; componentIndex++)
{
ComponentType x =
static_cast<ComponentType>(Lists::Get().NumberList[componentIndex + index]);
Traits::SetComponent(original, componentIndex, x);
Traits::SetComponent(
raiseresult, componentIndex, vtkm::Pow(base, x + exponentbias) + resultbias);
}
VectorType mathresult = function(original);
VTKM_MATH_ASSERT(test_equal(mathresult, raiseresult), "Exponent functions do not agree.");
}
}
struct ExpFunctor
{
VTKM_EXEC
VectorType operator()(VectorType x) const { return vtkm::Exp(x); }
};
VTKM_EXEC
void TestExp() const
{
// std::cout << " Testing Exp" << std::endl;
RaiseByTest(ExpFunctor(), vtkm::Float32(2.71828183));
}
struct Exp2Functor
{
VTKM_EXEC
VectorType operator()(VectorType x) const { return vtkm::Exp2(x); }
};
VTKM_EXEC
void TestExp2() const
{
// std::cout << " Testing Exp2" << std::endl;
RaiseByTest(Exp2Functor(), 2.0);
}
struct ExpM1Functor
{
VTKM_EXEC
VectorType operator()(VectorType x) const { return vtkm::ExpM1(x); }
};
VTKM_EXEC
void TestExpM1() const
{
// std::cout << " Testing ExpM1" << std::endl;
RaiseByTest(ExpM1Functor(), ComponentType(2.71828183), 0.0, -1.0);
}
struct Exp10Functor
{
VTKM_EXEC
VectorType operator()(VectorType x) const { return vtkm::Exp10(x); }
};
VTKM_EXEC
void TestExp10() const
{
// std::cout << " Testing Exp10" << std::endl;
RaiseByTest(Exp10Functor(), 10.0);
}
template <typename FunctionType>
VTKM_EXEC void LogBaseTest(FunctionType function,
ComponentType base,
ComponentType bias = 0.0) const
{
for (vtkm::IdComponent index = 0; index < Lists::NUM_NUMBERS - NUM_COMPONENTS + 1; index++)
{
VectorType basevector(base);
VectorType original;
VectorType biased;
for (vtkm::IdComponent componentIndex = 0; componentIndex < NUM_COMPONENTS; componentIndex++)
{
ComponentType x =
static_cast<ComponentType>(Lists::Get().NumberList[componentIndex + index]);
Traits::SetComponent(original, componentIndex, x);
Traits::SetComponent(biased, componentIndex, x + bias);
}
VectorType logresult = vtkm::Log2(biased) / vtkm::Log2(basevector);
VectorType mathresult = function(original);
VTKM_MATH_ASSERT(test_equal(mathresult, logresult), "Exponent functions do not agree.");
}
}
struct LogFunctor
{
VTKM_EXEC
VectorType operator()(VectorType x) const { return vtkm::Log(x); }
};
VTKM_EXEC
void TestLog() const
{
// std::cout << " Testing Log" << std::endl;
LogBaseTest(LogFunctor(), vtkm::Float32(2.71828183));
}
struct Log10Functor
{
VTKM_EXEC
VectorType operator()(VectorType x) const { return vtkm::Log10(x); }
};
VTKM_EXEC
void TestLog10() const
{
// std::cout << " Testing Log10" << std::endl;
LogBaseTest(Log10Functor(), 10.0);
}
struct Log1PFunctor
{
VTKM_EXEC
VectorType operator()(VectorType x) const { return vtkm::Log1P(x); }
};
VTKM_EXEC
void TestLog1P() const
{
// std::cout << " Testing Log1P" << std::endl;
LogBaseTest(Log1PFunctor(), ComponentType(2.71828183), 1.0);
}
VTKM_EXEC
void TestCopySign() const
{
// std::cout << "Testing CopySign." << std::endl;
// Assuming all TestValues positive.
VectorType positive1 = TestValue(1, VectorType());
VectorType positive2 = TestValue(2, VectorType());
VectorType negative1 = -positive1;
VectorType negative2 = -positive2;
VTKM_MATH_ASSERT(test_equal(vtkm::CopySign(positive1, positive2), positive1),
"CopySign failed.");
VTKM_MATH_ASSERT(test_equal(vtkm::CopySign(negative1, positive2), positive1),
"CopySign failed.");
VTKM_MATH_ASSERT(test_equal(vtkm::CopySign(positive1, negative2), negative1),
"CopySign failed.");
VTKM_MATH_ASSERT(test_equal(vtkm::CopySign(negative1, negative2), negative1),
"CopySign failed.");
}
VTKM_EXEC
void operator()(vtkm::Id) const
{
this->TestTriangleTrig();
this->TestHyperbolicTrig();
this->TestSqrt();
this->TestRSqrt();
this->TestCbrt();
this->TestRCbrt();
this->TestExp();
this->TestExp2();
this->TestExpM1();
this->TestExp10();
this->TestLog();
this->TestLog10();
this->TestLog1P();
this->TestCopySign();
}
};
template <typename Device>
struct TryScalarVectorFieldTests
{
template <typename VectorType>
void operator()(const VectorType&) const
{
vtkm::cont::DeviceAdapterAlgorithm<Device>::Schedule(ScalarVectorFieldTests<VectorType>(), 1);
}
};
//-----------------------------------------------------------------------------
template <typename T>
struct AllTypesTests : public vtkm::exec::FunctorBase
{
VTKM_EXEC
void TestMinMax() const
{
T low = TestValue(2, T());
T high = TestValue(10, T());
// std::cout << "Testing min/max " << low << " " << high << std::endl;
VTKM_MATH_ASSERT(test_equal(vtkm::Min(low, high), low), "Wrong min.");
VTKM_MATH_ASSERT(test_equal(vtkm::Min(high, low), low), "Wrong min.");
VTKM_MATH_ASSERT(test_equal(vtkm::Max(low, high), high), "Wrong max.");
VTKM_MATH_ASSERT(test_equal(vtkm::Max(high, low), high), "Wrong max.");
typedef vtkm::VecTraits<T> Traits;
T mixed1 = low;
T mixed2 = high;
Traits::SetComponent(mixed1, 0, Traits::GetComponent(high, 0));
Traits::SetComponent(mixed2, 0, Traits::GetComponent(low, 0));
VTKM_MATH_ASSERT(test_equal(vtkm::Min(mixed1, mixed2), low), "Wrong min.");
VTKM_MATH_ASSERT(test_equal(vtkm::Min(mixed2, mixed1), low), "Wrong min.");
VTKM_MATH_ASSERT(test_equal(vtkm::Max(mixed1, mixed2), high), "Wrong max.");
VTKM_MATH_ASSERT(test_equal(vtkm::Max(mixed2, mixed1), high), "Wrong max.");
}
VTKM_EXEC
void operator()(vtkm::Id) const { this->TestMinMax(); }
};
template <typename Device>
struct TryAllTypesTests
{
template <typename T>
void operator()(const T&) const
{
vtkm::cont::DeviceAdapterAlgorithm<Device>::Schedule(AllTypesTests<T>(), 1);
}
};
//-----------------------------------------------------------------------------
template <typename T>
struct AbsTests : public vtkm::exec::FunctorBase
{
VTKM_EXEC
void operator()(vtkm::Id index) const
{
// std::cout << "Testing Abs." << std::endl;
T positive = TestValue(index, T()); // Assuming all TestValues positive.
T negative = -positive;
VTKM_MATH_ASSERT(test_equal(vtkm::Abs(positive), positive), "Abs returned wrong value.");
VTKM_MATH_ASSERT(test_equal(vtkm::Abs(negative), positive), "Abs returned wrong value.");
}
};
template <typename Device>
struct TryAbsTests
{
template <typename T>
void operator()(const T&) const
{
vtkm::cont::DeviceAdapterAlgorithm<Device>::Schedule(AbsTests<T>(), 10);
}
};
struct TypeListTagAbs
: vtkm::ListTagJoin<
vtkm::ListTagJoin<vtkm::ListTagBase<vtkm::Int32, vtkm::Int64>, vtkm::TypeListTagIndex>,
vtkm::TypeListTagField>
{
};
//-----------------------------------------------------------------------------
template <typename Device>
void RunMathTests()
{
std::cout << "Tests for scalar types." << std::endl;
vtkm::testing::Testing::TryTypes(TryScalarFieldTests<Device>(), vtkm::TypeListTagFieldScalar());
std::cout << "Test for scalar and vector types." << std::endl;
vtkm::testing::Testing::TryTypes(TryScalarVectorFieldTests<Device>(), vtkm::TypeListTagField());
std::cout << "Test for exemplar types." << std::endl;
vtkm::testing::Testing::TryTypes(TryAllTypesTests<Device>());
std::cout << "Test all Abs types" << std::endl;
vtkm::testing::Testing::TryTypes(TryAbsTests<Device>(), TypeListTagAbs());
}
} // namespace UnitTestMathNamespace
#endif //vtk_m_testing_TestingMath_h