From 4026559e0d9c09301d81b318b24d68522681fd4a Mon Sep 17 00:00:00 2001 From: Liz Dulac <47396187+lizdulac@users.noreply.github.com> Date: Tue, 20 Aug 2024 09:42:08 -0400 Subject: [PATCH] Extend Derived Variable Expressions: Trig functions (#4282) * Create sin, cos, tan functionality * Add trig functions to derived variable expressions * ApplyOneToOneOnce does not need memset * Add typeFunc * Change trig functions to transforms of float type func * Remove unused function --------- Co-authored-by: Ana Gainaru --- source/adios2/toolkit/derived/Expression.cpp | 15 ++ source/adios2/toolkit/derived/Expression.h | 6 + source/adios2/toolkit/derived/Function.cpp | 228 ++++++++++++++++++ source/adios2/toolkit/derived/Function.h | 6 + .../derived/parser/pregen-source/lexer.cpp | 1 + .../derived/TestBPDerivedCorrectness.cpp | 141 ++++++++++- 6 files changed, 396 insertions(+), 1 deletion(-) diff --git a/source/adios2/toolkit/derived/Expression.cpp b/source/adios2/toolkit/derived/Expression.cpp index a44e25f178..0878374805 100644 --- a/source/adios2/toolkit/derived/Expression.cpp +++ b/source/adios2/toolkit/derived/Expression.cpp @@ -30,6 +30,12 @@ const std::map op_property = { {ExpressionOperator::OP_DIV, {"DIV", false}}, {ExpressionOperator::OP_SQRT, {"SQRT", false}}, {ExpressionOperator::OP_POW, {"POW", false}}, + {ExpressionOperator::OP_SIN, {"SIN", false}}, + {ExpressionOperator::OP_COS, {"COS", false}}, + {ExpressionOperator::OP_TAN, {"TAN", false}}, + {ExpressionOperator::OP_ASIN, {"ASIN", false}}, + {ExpressionOperator::OP_ACOS, {"ACOS", false}}, + {ExpressionOperator::OP_ATAN, {"ATAN", false}}, {ExpressionOperator::OP_CURL, {"CURL", false}}, {ExpressionOperator::OP_MAGN, {"MAGNITUDE", false}}}; @@ -45,6 +51,9 @@ const std::map string_to_op = { {"multiply", ExpressionOperator::OP_MULT}, {"MULTIPLY", ExpressionOperator::OP_MULT}, {"SQRT", ExpressionOperator::OP_SQRT}, {"sqrt", ExpressionOperator::OP_SQRT}, {"pow", ExpressionOperator::OP_POW}, {"POW", ExpressionOperator::OP_POW}, + {"sin", ExpressionOperator::OP_SIN}, {"cos", ExpressionOperator::OP_COS}, + {"tan", ExpressionOperator::OP_TAN}, {"asin", ExpressionOperator::OP_ASIN}, + {"acos", ExpressionOperator::OP_ACOS}, {"atan", ExpressionOperator::OP_ATAN}, {"^", ExpressionOperator::OP_POW}, {"CURL", ExpressionOperator::OP_CURL}, {"curl", ExpressionOperator::OP_CURL}, {"MAGNITUDE", ExpressionOperator::OP_MAGN}, {"magnitude", ExpressionOperator::OP_MAGN}}; @@ -136,6 +145,12 @@ std::map OpFunctions = { {adios2::detail::ExpressionOperator::OP_DIV, {DivFunc, SameDimsFunc, SameTypeFunc}}, {adios2::detail::ExpressionOperator::OP_POW, {PowFunc, SameDimsFunc, FloatTypeFunc}}, {adios2::detail::ExpressionOperator::OP_SQRT, {SqrtFunc, SameDimsFunc, FloatTypeFunc}}, + {adios2::detail::ExpressionOperator::OP_SIN, {SinFunc, SameDimsFunc, FloatTypeFunc}}, + {adios2::detail::ExpressionOperator::OP_COS, {CosFunc, SameDimsFunc, FloatTypeFunc}}, + {adios2::detail::ExpressionOperator::OP_TAN, {TanFunc, SameDimsFunc, FloatTypeFunc}}, + {adios2::detail::ExpressionOperator::OP_ASIN, {AsinFunc, SameDimsFunc, FloatTypeFunc}}, + {adios2::detail::ExpressionOperator::OP_ACOS, {AcosFunc, SameDimsFunc, FloatTypeFunc}}, + {adios2::detail::ExpressionOperator::OP_ATAN, {AtanFunc, SameDimsFunc, FloatTypeFunc}}, {adios2::detail::ExpressionOperator::OP_CURL, {Curl3DFunc, CurlDimsFunc, SameTypeFunc}}, {adios2::detail::ExpressionOperator::OP_MAGN, {MagnitudeFunc, SameDimsFunc, SameTypeFunc}}}; diff --git a/source/adios2/toolkit/derived/Expression.h b/source/adios2/toolkit/derived/Expression.h index ff62939cd6..73222cbc66 100644 --- a/source/adios2/toolkit/derived/Expression.h +++ b/source/adios2/toolkit/derived/Expression.h @@ -22,6 +22,12 @@ enum ExpressionOperator OP_DIV, OP_SQRT, OP_POW, + OP_SIN, + OP_COS, + OP_TAN, + OP_ASIN, + OP_ACOS, + OP_ATAN, OP_MAGN, OP_CURL }; diff --git a/source/adios2/toolkit/derived/Function.cpp b/source/adios2/toolkit/derived/Function.cpp index 284dc2c4c5..e35e7f0346 100644 --- a/source/adios2/toolkit/derived/Function.cpp +++ b/source/adios2/toolkit/derived/Function.cpp @@ -258,6 +258,234 @@ DerivedData PowFunc(std::vector inputData, DataType type) return DerivedData(); } +DerivedData SinFunc(std::vector inputData, DataType type) +{ + PERFSTUBS_SCOPED_TIMER("derived::Function::SinFunc"); + if (inputData.size() != 1) + { + helper::Throw("Derived", "Function", "SinFunc", + "Invalid number of arguments passed to SinFunc"); + } + size_t dataSize = std::accumulate(std::begin(inputData[0].Count), std::end(inputData[0].Count), + 1, std::multiplies()); + DataType inputType = inputData[0].Type; + + if (inputType == DataType::LongDouble) + { + long double *sinValues = (long double *)malloc(dataSize * sizeof(long double)); + std::transform(reinterpret_cast(inputData[0].Data), + reinterpret_cast(inputData[0].Data) + dataSize, sinValues, + [](long double &a) { return std::sin(a); }); + return DerivedData({(void *)sinValues, inputData[0].Start, inputData[0].Count}); + } +#define declare_type_sin(T) \ + if (inputType == helper::GetDataType()) \ + { \ + if (inputType != DataType::LongDouble) \ + { \ + double *sinValues = (double *)malloc(dataSize * sizeof(double)); \ + std::transform(reinterpret_cast(inputData[0].Data), \ + reinterpret_cast(inputData[0].Data) + dataSize, sinValues, \ + [](T &a) { return std::sin(a); }); \ + return DerivedData({(void *)sinValues, inputData[0].Start, inputData[0].Count}); \ + } \ + } + ADIOS2_FOREACH_ATTRIBUTE_PRIMITIVE_STDTYPE_1ARG(declare_type_sin) + helper::Throw("Derived", "Function", "SinFunc", + "Invalid variable types"); + return DerivedData(); +} + +DerivedData CosFunc(std::vector inputData, DataType type) +{ + PERFSTUBS_SCOPED_TIMER("derived::Function::CosFunc"); + if (inputData.size() != 1) + { + helper::Throw("Derived", "Function", "CosFunc", + "Invalid number of arguments passed to CosFunc"); + } + size_t dataSize = std::accumulate(std::begin(inputData[0].Count), std::end(inputData[0].Count), + 1, std::multiplies()); + DataType inputType = inputData[0].Type; + + if (inputType == DataType::LongDouble) + { + long double *cosValues = (long double *)malloc(dataSize * sizeof(long double)); + std::transform(reinterpret_cast(inputData[0].Data), + reinterpret_cast(inputData[0].Data) + dataSize, cosValues, + [](long double &a) { return std::cos(a); }); + return DerivedData({(void *)cosValues, inputData[0].Start, inputData[0].Count}); + } +#define declare_type_cos(T) \ + if (inputType == helper::GetDataType()) \ + { \ + if (inputType != DataType::LongDouble) \ + { \ + double *cosValues = (double *)malloc(dataSize * sizeof(double)); \ + std::transform(reinterpret_cast(inputData[0].Data), \ + reinterpret_cast(inputData[0].Data) + dataSize, cosValues, \ + [](T &a) { return std::cos(a); }); \ + return DerivedData({(void *)cosValues, inputData[0].Start, inputData[0].Count}); \ + } \ + } + ADIOS2_FOREACH_ATTRIBUTE_PRIMITIVE_STDTYPE_1ARG(declare_type_cos) + helper::Throw("Derived", "Function", "CosFunc", + "Invalid variable types"); + return DerivedData(); +} + +DerivedData TanFunc(std::vector inputData, DataType type) +{ + PERFSTUBS_SCOPED_TIMER("derived::Function::TanFunc"); + if (inputData.size() != 1) + { + helper::Throw("Derived", "Function", "TanFunc", + "Invalid number of arguments passed to TanFunc"); + } + size_t dataSize = std::accumulate(std::begin(inputData[0].Count), std::end(inputData[0].Count), + 1, std::multiplies()); + DataType inputType = inputData[0].Type; + + if (inputType == DataType::LongDouble) + { + long double *tanValues = (long double *)malloc(dataSize * sizeof(long double)); + std::transform(reinterpret_cast(inputData[0].Data), + reinterpret_cast(inputData[0].Data) + dataSize, tanValues, + [](long double &a) { return std::tan(a); }); + return DerivedData({(void *)tanValues, inputData[0].Start, inputData[0].Count}); + } +#define declare_type_tan(T) \ + if (inputType == helper::GetDataType()) \ + { \ + if (inputType != DataType::LongDouble) \ + { \ + double *tanValues = (double *)malloc(dataSize * sizeof(double)); \ + std::transform(reinterpret_cast(inputData[0].Data), \ + reinterpret_cast(inputData[0].Data) + dataSize, tanValues, \ + [](T &a) { return std::tan(a); }); \ + return DerivedData({(void *)tanValues, inputData[0].Start, inputData[0].Count}); \ + } \ + } + ADIOS2_FOREACH_ATTRIBUTE_PRIMITIVE_STDTYPE_1ARG(declare_type_tan) + helper::Throw("Derived", "Function", "TanFunc", + "Invalid variable types"); + return DerivedData(); +} + +DerivedData AsinFunc(std::vector inputData, DataType type) +{ + PERFSTUBS_SCOPED_TIMER("derived::Function::AsinFunc"); + if (inputData.size() != 1) + { + helper::Throw("Derived", "Function", "AsinFunc", + "Invalid number of arguments passed to AsinFunc"); + } + size_t dataSize = std::accumulate(std::begin(inputData[0].Count), std::end(inputData[0].Count), + 1, std::multiplies()); + DataType inputType = inputData[0].Type; + + if (inputType == DataType::LongDouble) + { + long double *asinValues = (long double *)malloc(dataSize * sizeof(long double)); + std::transform(reinterpret_cast(inputData[0].Data), + reinterpret_cast(inputData[0].Data) + dataSize, asinValues, + [](long double &a) { return std::asin(a); }); + return DerivedData({(void *)asinValues, inputData[0].Start, inputData[0].Count}); + } +#define declare_type_asin(T) \ + if (inputType == helper::GetDataType()) \ + { \ + if (inputType != DataType::LongDouble) \ + { \ + double *asinValues = (double *)malloc(dataSize * sizeof(double)); \ + std::transform(reinterpret_cast(inputData[0].Data), \ + reinterpret_cast(inputData[0].Data) + dataSize, asinValues, \ + [](T &a) { return std::asin(a); }); \ + return DerivedData({(void *)asinValues, inputData[0].Start, inputData[0].Count}); \ + } \ + } + ADIOS2_FOREACH_ATTRIBUTE_PRIMITIVE_STDTYPE_1ARG(declare_type_asin) + helper::Throw("Derived", "Function", "AsinFunc", + "Invalid variable types"); + return DerivedData(); +} + +DerivedData AcosFunc(std::vector inputData, DataType type) +{ + PERFSTUBS_SCOPED_TIMER("derived::Function::AcosFunc"); + if (inputData.size() != 1) + { + helper::Throw("Derived", "Function", "AcosFunc", + "Invalid number of arguments passed to AcosFunc"); + } + size_t dataSize = std::accumulate(std::begin(inputData[0].Count), std::end(inputData[0].Count), + 1, std::multiplies()); + DataType inputType = inputData[0].Type; + + if (inputType == DataType::LongDouble) + { + long double *acosValues = (long double *)malloc(dataSize * sizeof(long double)); + std::transform(reinterpret_cast(inputData[0].Data), + reinterpret_cast(inputData[0].Data) + dataSize, acosValues, + [](long double &a) { return std::acos(a); }); + return DerivedData({(void *)acosValues, inputData[0].Start, inputData[0].Count}); + } +#define declare_type_acos(T) \ + if (inputType == helper::GetDataType()) \ + { \ + if (inputType != DataType::LongDouble) \ + { \ + double *acosValues = (double *)malloc(dataSize * sizeof(double)); \ + std::transform(reinterpret_cast(inputData[0].Data), \ + reinterpret_cast(inputData[0].Data) + dataSize, acosValues, \ + [](T &a) { return std::acos(a); }); \ + return DerivedData({(void *)acosValues, inputData[0].Start, inputData[0].Count}); \ + } \ + } + ADIOS2_FOREACH_ATTRIBUTE_PRIMITIVE_STDTYPE_1ARG(declare_type_acos) + helper::Throw("Derived", "Function", "AcosFunc", + "Invalid variable types"); + return DerivedData(); +} + +DerivedData AtanFunc(std::vector inputData, DataType type) +{ + PERFSTUBS_SCOPED_TIMER("derived::Function::AtanFunc"); + if (inputData.size() != 1) + { + helper::Throw("Derived", "Function", "AtanFunc", + "Invalid number of arguments passed to AtanFunc"); + } + size_t dataSize = std::accumulate(std::begin(inputData[0].Count), std::end(inputData[0].Count), + 1, std::multiplies()); + DataType inputType = inputData[0].Type; + + if (inputType == DataType::LongDouble) + { + long double *atanValues = (long double *)malloc(dataSize * sizeof(long double)); + std::transform(reinterpret_cast(inputData[0].Data), + reinterpret_cast(inputData[0].Data) + dataSize, atanValues, + [](long double &a) { return std::atan(a); }); + return DerivedData({(void *)atanValues, inputData[0].Start, inputData[0].Count}); + } +#define declare_type_atan(T) \ + if (inputType == helper::GetDataType()) \ + { \ + if (inputType != DataType::LongDouble) \ + { \ + double *atanValues = (double *)malloc(dataSize * sizeof(double)); \ + std::transform(reinterpret_cast(inputData[0].Data), \ + reinterpret_cast(inputData[0].Data) + dataSize, atanValues, \ + [](T &a) { return std::atan(a); }); \ + return DerivedData({(void *)atanValues, inputData[0].Start, inputData[0].Count}); \ + } \ + } + ADIOS2_FOREACH_ATTRIBUTE_PRIMITIVE_STDTYPE_1ARG(declare_type_atan) + helper::Throw("Derived", "Function", "AtanFunc", + "Invalid variable types"); + return DerivedData(); +} + DerivedData MagnitudeFunc(std::vector inputData, DataType type) { PERFSTUBS_SCOPED_TIMER("derived::Function::MagnitudeFunc"); diff --git a/source/adios2/toolkit/derived/Function.h b/source/adios2/toolkit/derived/Function.h index c5b2087aac..0cdc56244d 100644 --- a/source/adios2/toolkit/derived/Function.h +++ b/source/adios2/toolkit/derived/Function.h @@ -9,6 +9,12 @@ namespace derived { DerivedData AddFunc(std::vector input, DataType type); DerivedData SubtractFunc(std::vector input, DataType type); +DerivedData SinFunc(std::vector input, DataType type); +DerivedData CosFunc(std::vector input, DataType type); +DerivedData TanFunc(std::vector input, DataType type); +DerivedData AsinFunc(std::vector input, DataType type); +DerivedData AcosFunc(std::vector input, DataType type); +DerivedData AtanFunc(std::vector input, DataType type); DerivedData MultFunc(std::vector input, DataType type); DerivedData DivFunc(std::vector input, DataType type); DerivedData SqrtFunc(std::vector input, DataType type); diff --git a/source/adios2/toolkit/derived/parser/pregen-source/lexer.cpp b/source/adios2/toolkit/derived/parser/pregen-source/lexer.cpp index 4012823b7c..10d2362360 100644 --- a/source/adios2/toolkit/derived/parser/pregen-source/lexer.cpp +++ b/source/adios2/toolkit/derived/parser/pregen-source/lexer.cpp @@ -1910,3 +1910,4 @@ adios2::detail::ASTDriver::destroy_lex_structures () { yylex_destroy(); } + diff --git a/testing/adios2/derived/TestBPDerivedCorrectness.cpp b/testing/adios2/derived/TestBPDerivedCorrectness.cpp index ccc60ee53e..88832f756a 100644 --- a/testing/adios2/derived/TestBPDerivedCorrectness.cpp +++ b/testing/adios2/derived/TestBPDerivedCorrectness.cpp @@ -162,6 +162,146 @@ TEST_P(DerivedCorrectnessP, ScalarFunctionsCorrectnessTest) bpFileReader.Close(); } +TEST_P(DerivedCorrectnessP, TrigCorrectnessTest) +{ + const size_t Nx = 10, Ny = 3, Nz = 6; + const size_t steps = 2; + // Application variable + std::default_random_engine generator; + std::uniform_real_distribution randomDist(0.0, 100.0); + std::uniform_real_distribution sinDist(-1.0, 1.0); + + adios2::DerivedVarType mode = GetParam(); + std::cout << "Mode is " << mode << std::endl; + + std::vector simArray1(Nx * Ny * Nz); + std::vector simArray2(Nx * Ny * Nz); + for (size_t i = 0; i < Nx * Ny * Nz; ++i) + { + simArray1[i] = randomDist(generator); + simArray2[i] = sinDist(generator); + } + + adios2::ADIOS adios; + + adios2::IO bpOut = adios.DeclareIO("BPWriteSinExpression"); + + std::string randDistVar = "sim/randDist"; + std::string sinDistVar = "sim/sinDist"; + std::string derSinName = "derived/sin"; + std::string derCosName = "derived/cos"; + std::string derTanName = "derived/tan"; + std::string derAsinName = "derived/asin"; + std::string derAcosName = "derived/acos"; + std::string derAtanName = "derived/atan"; + + auto Ux = bpOut.DefineVariable(randDistVar, {Nx, Ny, Nz}, {0, 0, 0}, {Nx, Ny, Nz}); + auto Uy = bpOut.DefineVariable(sinDistVar, {Nx, Ny, Nz}, {0, 0, 0}, {Nx, Ny, Nz}); + // clang-format off + bpOut.DefineDerivedVariable(derSinName, + "x =" + randDistVar + " \n" + "sin(x)", + mode); + bpOut.DefineDerivedVariable(derCosName, + "x =" + randDistVar + " \n" + "cos(x)", + mode); + bpOut.DefineDerivedVariable(derTanName, + "x =" + randDistVar + " \n" + "tan(x)", + mode); + bpOut.DefineDerivedVariable(derAsinName, + "x =" + sinDistVar + " \n" + "asin(x)", + mode); + bpOut.DefineDerivedVariable(derAcosName, + "x =" + sinDistVar + " \n" + "acos(x)", + mode); + bpOut.DefineDerivedVariable(derAtanName, + "x =" + randDistVar + " \n" + "atan(x)", + mode); + // clang-format on + std::string filename = "expTrig.bp"; + adios2::Engine bpFileWriter = bpOut.Open(filename, adios2::Mode::Write); + + for (size_t i = 0; i < steps; i++) + { + bpFileWriter.BeginStep(); + bpFileWriter.Put(Ux, simArray1.data()); + bpFileWriter.Put(Uy, simArray2.data()); + bpFileWriter.EndStep(); + } + bpFileWriter.Close(); + + adios2::IO bpIn = adios.DeclareIO("BPReadExpression"); + adios2::Engine bpFileReader = bpIn.Open(filename, adios2::Mode::Read); + + std::vector readRandDist; + std::vector readSinDist; + std::vector readSin; + std::vector readCos; + std::vector readTan; + std::vector readAsin; + std::vector readAcos; + std::vector readAtan; + + double calcTrig; + double epsilon = (double)0.01; + for (size_t i = 0; i < steps; i++) + { + bpFileReader.BeginStep(); + bpFileReader.Get(randDistVar, readRandDist); + bpFileReader.Get(sinDistVar, readSinDist); + + bpFileReader.Get(derSinName, readSin); + bpFileReader.Get(derCosName, readCos); + bpFileReader.Get(derTanName, readTan); + bpFileReader.Get(derAsinName, readAsin); + bpFileReader.Get(derAcosName, readAcos); + bpFileReader.Get(derAtanName, readAtan); + bpFileReader.EndStep(); + + for (size_t ind = 0; ind < Nx * Ny * Nz; ++ind) + { + calcTrig = std::sin(readRandDist[ind]); + EXPECT_TRUE(fabs(calcTrig - readSin[ind]) < epsilon); + } + + for (size_t ind = 0; ind < Nx * Ny * Nz; ++ind) + { + calcTrig = std::cos(readRandDist[ind]); + EXPECT_TRUE(fabs(calcTrig - readCos[ind]) < epsilon); + } + + for (size_t ind = 0; ind < Nx * Ny * Nz; ++ind) + { + calcTrig = std::tan(readRandDist[ind]); + EXPECT_TRUE(fabs(calcTrig - readTan[ind]) < epsilon); + } + + for (size_t ind = 0; ind < Nx * Ny * Nz; ++ind) + { + calcTrig = std::asin(readSinDist[ind]); + EXPECT_TRUE(fabs(calcTrig - readAsin[ind]) < epsilon); + } + + for (size_t ind = 0; ind < Nx * Ny * Nz; ++ind) + { + calcTrig = std::acos(readSinDist[ind]); + EXPECT_TRUE(fabs(calcTrig - readAcos[ind]) < epsilon); + } + + for (size_t ind = 0; ind < Nx * Ny * Nz; ++ind) + { + calcTrig = std::atan(readRandDist[ind]); + EXPECT_TRUE(fabs(calcTrig - readAtan[ind]) < epsilon); + } + } + bpFileReader.Close(); +} + TEST_P(DerivedCorrectnessP, MagCorrectnessTest) { const size_t Nx = 2, Ny = 3, Nz = 10; @@ -317,7 +457,6 @@ TEST_P(DerivedCorrectnessP, CurlCorrectnessTest) std::vector readVX; std::vector readVY; std::vector readVZ; - // TODO/DEBUG - VERIFY DATATYPE std::vector readCurl; std::vector> calcCurl;