diff --git a/CMakeLists.txt b/CMakeLists.txt index aaf9a18af7..45272a2b19 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -186,7 +186,7 @@ adios_option(Sodium "Enable support for Sodium for encryption" AUTO) adios_option(Catalyst "Enable support for in situ visualization plugin using ParaView Catalyst" AUTO) adios_option(Campaign "Enable support for Campaigns (requires SQLite3 and ZLIB)" AUTO) adios_option(AWSSDK "Enable support for S3 compatible storage using AWS SDK's S3 module" OFF) -adios_option(Derived_Variable "Enable support for derived variables" OFF) +adios_option(Derived_Variable "Enable support for derived variables" ON) adios_option(PIP "Enable support for pip packaging" OFF) adios_option(XRootD "Enable support for XRootD" AUTO) adios_option(KVCACHE "Enable support for KVCache" AUTO) diff --git a/examples/CMakeLists.txt b/examples/CMakeLists.txt index ad7194aacf..93829159d6 100644 --- a/examples/CMakeLists.txt +++ b/examples/CMakeLists.txt @@ -11,3 +11,7 @@ add_subdirectory(useCases) if(ADIOS2_USE_Campaign) add_subdirectory(campaign) endif() +if(ADIOS2_USE_Derived_Variable) + add_subdirectory(derived) +endif() + diff --git a/examples/derived/CMakeLists.txt b/examples/derived/CMakeLists.txt new file mode 100644 index 0000000000..593d9f3476 --- /dev/null +++ b/examples/derived/CMakeLists.txt @@ -0,0 +1,9 @@ +#------------------------------------------------------------------------------# +# Distributed under the OSI-approved Apache License, Version 2.0. See +# accompanying file Copyright.txt for details. +#------------------------------------------------------------------------------# + +add_executable(adios2_read_write_derived_serial read_write_derived.cpp) +target_link_libraries(adios2_read_write_derived_serial adios2::cxx11 adios2_core) +add_executable(adios2_write_derived_serial write_derived.cpp) +target_link_libraries(adios2_write_derived_serial adios2::cxx11 adios2_core) diff --git a/examples/derived/read_write_derived.cpp b/examples/derived/read_write_derived.cpp new file mode 100644 index 0000000000..144781c7a3 --- /dev/null +++ b/examples/derived/read_write_derived.cpp @@ -0,0 +1,74 @@ +#include +#include + +#include +#include +#include +#include +#include +#include + +#include + +int main(int argc, char **argv) +{ + const size_t Nx = 25, Ny = 70, Nz = 13; + + // Application variables + std::vector simArray1(Nx * Ny * Nz); + std::vector simArray2(Nx * Ny * Nz); + std::vector simArray3(Nx * Ny * Nz); + + for (size_t i = 0; i < Nx; ++i) + { + for (size_t j = 0; j < Ny; ++j) + { + for (size_t k = 0; k < Nz; ++k) + { + size_t idx = (i * Ny * Nz) + (j * Nz) + k; + float x = static_cast(i); + float y = static_cast(j); + float z = static_cast(k); + // Linear curl example + simArray1[idx] = (6 * x * y) + (7 * z); + simArray2[idx] = (4 * x * z) + powf(y, 2); + simArray3[idx] = sqrtf(z) + (2 * x * y); + } + } + } + + adios2::ADIOS adios; + adios2::IO bpOut = adios.DeclareIO("BPWriteExpression"); + + adios2::IO bpIn = adios.DeclareIO("BPReadCurlExpression"); + std::string filename = "expCurl.bp"; + std::string derivedname = "derived/curlV"; + adios2::Engine bpFileReader = bpIn.Open(filename, adios2::Mode::Read); + + std::vector readCurl; + + bpFileReader.BeginStep(); + auto varCurl = bpIn.InquireVariable(derivedname); + bpFileReader.Get(varCurl, readCurl); + bpFileReader.EndStep(); + + auto curlV = + bpOut.DefineVariable("copied/curlV", {Nx, Ny, Nz, 3}, {0, 0, 0, 0}, {Nx, Ny, Nz, 3}); + // clang-format off + bpOut.DefineDerivedVariable("derived/magofcurl", + "curlV =copied/curlV \n" + "magnitude(curlV, 3)", + adios2::DerivedVarType::StoreData); + // clang-format on + + adios2::Engine bpFileWriter = bpOut.Open("expMagCopiedCurl.bp", adios2::Mode::Write); + + bpFileWriter.BeginStep(); + bpFileWriter.Put(curlV, readCurl.data()); + bpFileWriter.EndStep(); + bpFileWriter.Close(); + + bpFileReader.Close(); + + return 0; +} diff --git a/examples/derived/write_derived.cpp b/examples/derived/write_derived.cpp new file mode 100644 index 0000000000..f07e4362a2 --- /dev/null +++ b/examples/derived/write_derived.cpp @@ -0,0 +1,102 @@ +#include +#include + +#include +#include +#include +#include +#include +#include + +#include + +int main(int argc, char **argv) +{ + const size_t Nn = 320; + const size_t Nx = Nn, Ny = Nn, Nz = Nn; + + // Application variable + std::vector simArray1(Nx * Ny * Nz); + std::vector simArray2(Nx * Ny * Nz); + std::vector simArray3(Nx * Ny * Nz); + for (size_t i = 0; i < Nx; ++i) + { + for (size_t j = 0; j < Ny; ++j) + { + for (size_t k = 0; k < Nz; ++k) + { + size_t idx = (i * Ny * Nz) + (j * Nz) + k; + float x = static_cast(i); + float y = static_cast(j); + float z = static_cast(k); + // Linear curl example + simArray1[idx] = (6 * x * y) + (7 * z); + simArray2[idx] = (4 * x * z) + powf(y, 2); + simArray3[idx] = sqrtf(z) + (2 * x * y); + /* Less linear example + simArray1[idx] = sinf(z); + simArray2[idx] = 4 * x; + simArray3[idx] = powf(y, 2) * cosf(x); + */ + /* Nonlinear example + simArray1[idx] = expf(2 * y) * sinf(x); + simArray2[idx] = sqrtf(z + 1) * cosf(x); + simArray3[idx] = powf(x, 2) * sinf(y) + (6 * z); + */ + } + } + } + + adios2::ADIOS adios; + adios2::IO bpOut = adios.DeclareIO("BPWriteExpression"); + + auto VX = bpOut.DefineVariable("sim/VX", {Nx, Ny, Nz}, {0, 0, 0}, {Nx, Ny, Nz}); + auto VY = bpOut.DefineVariable("sim/VY", {Nx, Ny, Nz}, {0, 0, 0}, {Nx, Ny, Nz}); + auto VZ = bpOut.DefineVariable("sim/VZ", {Nx, Ny, Nz}, {0, 0, 0}, {Nx, Ny, Nz}); + // clang-format off + //* + bpOut.DefineDerivedVariable("derived/curlV", + "Vx =sim/VX \n" + "Vy =sim/VY \n" + "Vz =sim/VZ \n" + "curl(Vx,Vy,Vz)", + adios2::DerivedVarType::StoreData); + //*/ + /* + bpOut.DefineDerivedVariable("derived/magV", + "Vx =sim/VX \n" + "Vy =sim/VY \n" + "Vz =sim/VZ \n" + "magnitude(Vx,Vy,Vz)", + adios2::DerivedVarType::StoreData); + */ + /* + bpOut.DefineDerivedVariable("derived/addV", + "Vx =sim/VX \n" + "Vy =sim/VY \n" + "Vx + Vy", + adios2::DerivedVarType::StoreData); + */ + /* + bpOut.DefineDerivedVariable("derived/magofcurl", + "curlx =derived/curlV[::3] \n" + "curly =derived/curlV[1::3] \n" + "curlz =derived/curlV[2::3] \n" + "magnitude(curlx,curly,curlz)", + adios2::DerivedVarType::StoreData); + */ + // clang-format on + std::string filename = "expCurl.bp"; + adios2::Engine bpFileWriter = bpOut.Open(filename, adios2::Mode::Write); + + bpFileWriter.BeginStep(); + bpFileWriter.Put(VX, simArray1.data()); + bpFileWriter.Put(VY, simArray2.data()); + bpFileWriter.Put(VZ, simArray3.data()); + bpFileWriter.EndStep(); + bpFileWriter.Close(); + + std::cout << "Example complete, check " << filename << " for data" << std::endl; + + return 0; +} diff --git a/source/adios2/toolkit/derived/Expression.cpp b/source/adios2/toolkit/derived/Expression.cpp index c1be9922ce..dc4622d910 100644 --- a/source/adios2/toolkit/derived/Expression.cpp +++ b/source/adios2/toolkit/derived/Expression.cpp @@ -235,7 +235,7 @@ std::string ExpressionTree::toStringExpr() if (!detail.indices.empty()) { result += "[ "; - for (std::tuple idx : detail.indices) + for (std::tuple idx : detail.indices) { result += (std::get<0>(idx) < 0 ? "" : std::to_string(std::get<0>(idx))) + ":"; result += (std::get<1>(idx) < 0 ? "" : std::to_string(std::get<1>(idx))) + ":"; @@ -308,9 +308,23 @@ ExpressionTree::ApplyExpression(DataType type, size_t numBlocks, // apply the computation operator on all blocks std::vector outputData(numBlocks); auto op_fct = OpFunctions.at(detail.operation); - for (size_t blk = 0; blk < numBlocks; blk++) + // If function called over single expression with a constant, + // (ex: magnitude(curl(x,y,z), 3)) + // assume user wants to extract dimension + if (detail.constant > 0 && sub_exprs.size() == 1) { - outputData[blk] = op_fct.ComputeFct(exprData[blk], type); + for (size_t blk = 0; blk < numBlocks; blk++) + { + outputData[blk] = op_fct.ComputeFct( + ExtractDimensionN(exprData[blk][0], type, (size_t)detail.constant), type); + } + } + else + { + for (size_t blk = 0; blk < numBlocks; blk++) + { + outputData[blk] = op_fct.ComputeFct(exprData[blk], type); + } } // deallocate intermediate data after computing the operation for (size_t blk = 0; blk < numBlocks; blk++) diff --git a/source/adios2/toolkit/derived/Function.cpp b/source/adios2/toolkit/derived/Function.cpp index 9863a3012f..085742a0bd 100644 --- a/source/adios2/toolkit/derived/Function.cpp +++ b/source/adios2/toolkit/derived/Function.cpp @@ -44,13 +44,13 @@ T *ApplyCurl(const T *input1, const T *input2, const T *input3, const size_t dim size_t dataSize = dims[0] * dims[1] * dims[2]; T *data = (T *)malloc(dataSize * sizeof(float) * 3); size_t index = 0; - for (int i = 0; i < dims[0]; ++i) + for (int i = 0; i < (int)dims[0]; ++i) { size_t prev_i = std::max(0, i - 1), next_i = std::min((int)dims[0] - 1, i + 1); - for (int j = 0; j < dims[1]; ++j) + for (int j = 0; j < (int)dims[1]; ++j) { size_t prev_j = std::max(0, j - 1), next_j = std::min((int)dims[1] - 1, j + 1); - for (int k = 0; k < dims[2]; ++k) + for (int k = 0; k < (int)dims[2]; ++k) { size_t prev_k = std::max(0, k - 1), next_k = std::min((int)dims[2] - 1, k + 1); // curl[0] = dv3 / dy - dv2 / dz @@ -80,21 +80,6 @@ T *ApplyCurl(const T *input1, const T *input2, const T *input3, const size_t dim } return data; } - -// types not supported for curl -std::complex *ApplyCurl(const std::complex * /*input 1*/, - const std::complex * /*input 2*/, - const std::complex * /*input 3*/, const size_t[3] /*dims*/) -{ - return NULL; -} - -std::complex *ApplyCurl(const std::complex * /*input 1*/, - const std::complex * /*input 2*/, - const std::complex * /*input 3*/, const size_t[3] /*dims*/) -{ - return NULL; -} } namespace derived @@ -112,7 +97,7 @@ DerivedData AddFunc(std::vector inputData, DataType type) [](T a, T b) { return a + b; }); \ return DerivedData({(void *)addValues, inputData[0].Start, inputData[0].Count}); \ } - ADIOS2_FOREACH_PRIMITIVE_STDTYPE_1ARG(declare_type_add) + ADIOS2_FOREACH_ATTRIBUTE_PRIMITIVE_STDTYPE_1ARG(declare_type_add) helper::Throw("Derived", "Function", "AddFunc", "Invalid variable types"); return DerivedData(); @@ -134,7 +119,7 @@ DerivedData SubtractFunc(std::vector inputData, DataType type) *(reinterpret_cast(inputData[0].Data) + i) - subtractValues[i]; \ return DerivedData({(void *)subtractValues, inputData[0].Start, inputData[0].Count}); \ } - ADIOS2_FOREACH_PRIMITIVE_STDTYPE_1ARG(declare_type_subtract) + ADIOS2_FOREACH_ATTRIBUTE_PRIMITIVE_STDTYPE_1ARG(declare_type_subtract) helper::Throw("Derived", "Function", "SubtractFunc", "Invalid variable types"); return DerivedData(); @@ -156,7 +141,7 @@ DerivedData MagnitudeFunc(std::vector inputData, DataType type) } \ return DerivedData({(void *)magValues, inputData[0].Start, inputData[0].Count}); \ } - ADIOS2_FOREACH_PRIMITIVE_STDTYPE_1ARG(declare_type_mag) + ADIOS2_FOREACH_ATTRIBUTE_PRIMITIVE_STDTYPE_1ARG(declare_type_mag) helper::Throw("Derived", "Function", "MagnitudeFunc", "Invalid variable types"); return DerivedData(); @@ -196,12 +181,67 @@ DerivedData Curl3DFunc(const std::vector inputData, DataType type) curl.Data = detail::ApplyCurl(input1, input2, input3, dims); \ return curl; \ } - ADIOS2_FOREACH_PRIMITIVE_STDTYPE_1ARG(declare_type_curl) + ADIOS2_FOREACH_ATTRIBUTE_PRIMITIVE_STDTYPE_1ARG(declare_type_curl) helper::Throw("Derived", "Function", "Curl3DFunc", "Invalid variable types"); return DerivedData(); } +std::vector ExtractDimensionN(DerivedData inputData, DataType type, size_t dim) +{ + size_t num_data_sets = inputData.Count[dim]; + size_t num_chunks = 1; + size_t chunk_length = 1; + for (size_t i = 0; i < dim; ++i) + { + num_chunks *= inputData.Count[i]; + } + for (size_t i = dim + 1; i < inputData.Count.size(); ++i) + { + chunk_length *= inputData.Count[i]; + } + + Dims set_Start; + Dims set_Count; + for (size_t i = 0; i < inputData.Start.size(); ++i) + { + if (i != dim) + { + set_Start.push_back(inputData.Start[i]); + set_Count.push_back(inputData.Count[i]); + } + } + + std::vector result; + size_t chunk_size = chunk_length * helper::GetDataTypeSize(type); + // TO DO - FREE + for (size_t i = 0; i < num_data_sets; ++i) + result.push_back({malloc(num_chunks * chunk_size), set_Start, set_Count}); + + // How does Start factor in? + // size_t data_iter = 0; + char *input_ptr = (char *)inputData.Data; + for (size_t chunk = 0; chunk < num_chunks; ++chunk) + { + for (size_t data_set = 0; data_set < num_data_sets; ++data_set) + { + char *result_ptr = (char *)(result[data_set].Data); + memcpy(result_ptr + (chunk * chunk_size), + input_ptr + (((num_data_sets * chunk) + data_set) * chunk_size), chunk_size); + + // memcpy(&(result[data_set].Data[chunk * chunk_length]), &(inputData.Data[data_iter]), + /* + for (size_t chunk_iter = 0; chunk_iter < chunk_length; ++chunk_iter) + { + result[data_set].Data[(chunk * chunk_length) + chunk_iter] = + inputData.Data[data_iter++]; + }*/ + } + } + + return result; +} + Dims SameDimsFunc(std::vector input) { // check that all dimenstions are the same diff --git a/source/adios2/toolkit/derived/Function.h b/source/adios2/toolkit/derived/Function.h index 4ecb20b95e..99d1f60228 100644 --- a/source/adios2/toolkit/derived/Function.h +++ b/source/adios2/toolkit/derived/Function.h @@ -12,6 +12,8 @@ DerivedData SubtractFunc(std::vector input, DataType type); DerivedData MagnitudeFunc(std::vector input, DataType type); DerivedData Curl3DFunc(std::vector input, DataType type); +std::vector ExtractDimensionN(DerivedData inputData, DataType type, size_t dim); + Dims SameDimsFunc(std::vector input); Dims CurlDimsFunc(std::vector input); } diff --git a/source/adios2/toolkit/derived/parser/ASTDriver.cpp b/source/adios2/toolkit/derived/parser/ASTDriver.cpp index 53871e0db8..15ad4349b9 100644 --- a/source/adios2/toolkit/derived/parser/ASTDriver.cpp +++ b/source/adios2/toolkit/derived/parser/ASTDriver.cpp @@ -84,6 +84,12 @@ void ASTDriver::createNode(std::string op_name, size_t numsubexprs) holding.push(node); } +void ASTDriver::createNode(double num) +{ + ASTNode *node = new ASTNode("NUM", num); + holding.push(node); +} + void ASTDriver::createNode(std::string alias) { ASTNode *node = new ASTNode("ALIAS", alias); diff --git a/source/adios2/toolkit/derived/parser/ASTDriver.h b/source/adios2/toolkit/derived/parser/ASTDriver.h index c1f2855800..22ff6fb257 100644 --- a/source/adios2/toolkit/derived/parser/ASTDriver.h +++ b/source/adios2/toolkit/derived/parser/ASTDriver.h @@ -40,6 +40,7 @@ class ASTDriver void add_lookup_entry(std::string alias, std::string var_name); void createNode(std::string, size_t); + void createNode(double); void createNode(std::string); void createNode(std::string, indx_type); diff --git a/source/adios2/toolkit/derived/parser/ASTNode.cpp b/source/adios2/toolkit/derived/parser/ASTNode.cpp index 3563a4c78f..08f5ebc208 100644 --- a/source/adios2/toolkit/derived/parser/ASTNode.cpp +++ b/source/adios2/toolkit/derived/parser/ASTNode.cpp @@ -21,6 +21,12 @@ ASTNode::ASTNode(std::string op, std::string a) alias = a; } +ASTNode::ASTNode(std::string op, double v) +{ + opname = op; + value = v; +} + ASTNode::ASTNode(std::string op, std::vector> i) { opname = op; diff --git a/source/adios2/toolkit/derived/parser/ASTNode.h b/source/adios2/toolkit/derived/parser/ASTNode.h index 1d83ab5855..1b44d10ee2 100644 --- a/source/adios2/toolkit/derived/parser/ASTNode.h +++ b/source/adios2/toolkit/derived/parser/ASTNode.h @@ -16,6 +16,7 @@ class ASTNode ASTNode(std::string); ASTNode(std::string, size_t); ASTNode(std::string, std::string); + ASTNode(std::string, double); ASTNode(std::string, std::vector>); ~ASTNode(); diff --git a/source/adios2/toolkit/derived/parser/parser.y b/source/adios2/toolkit/derived/parser/parser.y index a258b34bc1..f65f2893c1 100644 --- a/source/adios2/toolkit/derived/parser/parser.y +++ b/source/adios2/toolkit/derived/parser/parser.y @@ -49,7 +49,8 @@ %token OPERATOR %token IDENTIFIER "identifier" %token VARNAME -%token INT "number" +%token DOUBLE "number" +%token INT %nterm list %nterm >> indices_list %nterm > index @@ -70,7 +71,8 @@ assignment: ; exp: - "number" { } + "number" { drv.createNode($1); } +| INT { drv.createNode($1); } | exp OPERATOR exp { drv.createNode($2, 2); } | "(" exp ")" { } | IDENTIFIER "(" list ")" { drv.createNode($1, $3); } diff --git a/source/adios2/toolkit/derived/parser/pregen-source/parser.cpp b/source/adios2/toolkit/derived/parser/pregen-source/parser.cpp index e11401c54d..c1dc11d3f2 100644 --- a/source/adios2/toolkit/derived/parser/pregen-source/parser.cpp +++ b/source/adios2/toolkit/derived/parser/pregen-source/parser.cpp @@ -209,7 +209,11 @@ namespace adios2 { namespace detail { { switch (that.kind ()) { - case symbol_kind::S_INT: // "number" + case symbol_kind::S_DOUBLE: // "number" + value.YY_MOVE_OR_COPY< double > (YY_MOVE (that.value)); + break; + + case symbol_kind::S_INT: // INT case symbol_kind::S_list: // list value.YY_MOVE_OR_COPY< int > (YY_MOVE (that.value)); break; @@ -243,7 +247,11 @@ namespace adios2 { namespace detail { { switch (that.kind ()) { - case symbol_kind::S_INT: // "number" + case symbol_kind::S_DOUBLE: // "number" + value.move< double > (YY_MOVE (that.value)); + break; + + case symbol_kind::S_INT: // INT case symbol_kind::S_list: // list value.move< int > (YY_MOVE (that.value)); break; @@ -277,7 +285,11 @@ namespace adios2 { namespace detail { state = that.state; switch (that.kind ()) { - case symbol_kind::S_INT: // "number" + case symbol_kind::S_DOUBLE: // "number" + value.copy< double > (that.value); + break; + + case symbol_kind::S_INT: // INT case symbol_kind::S_list: // list value.copy< int > (that.value); break; @@ -310,7 +322,11 @@ namespace adios2 { namespace detail { state = that.state; switch (that.kind ()) { - case symbol_kind::S_INT: // "number" + case symbol_kind::S_DOUBLE: // "number" + value.move< double > (that.value); + break; + + case symbol_kind::S_INT: // INT case symbol_kind::S_list: // list value.move< int > (that.value); break; @@ -598,7 +614,11 @@ namespace adios2 { namespace detail { when using variants. */ switch (yyr1_[yyn]) { - case symbol_kind::S_INT: // "number" + case symbol_kind::S_DOUBLE: // "number" + yylhs.value.emplace< double > (); + break; + + case symbol_kind::S_INT: // INT case symbol_kind::S_list: // list yylhs.value.emplace< int > (); break; @@ -638,187 +658,193 @@ namespace adios2 { namespace detail { switch (yyn) { case 2: // lines: assignment lines -#line 61 "../parser.y" +#line 62 "../parser.y" {} -#line 644 "parser.cpp" +#line 664 "parser.cpp" break; case 3: // lines: exp -#line 62 "../parser.y" +#line 63 "../parser.y" {} -#line 650 "parser.cpp" +#line 670 "parser.cpp" break; case 4: // assignment: "identifier" "=" VARNAME -#line 66 "../parser.y" +#line 67 "../parser.y" { drv.add_lookup_entry(yystack_[2].value.as < std::string > (), yystack_[0].value.as < std::string > ()); } -#line 656 "parser.cpp" +#line 676 "parser.cpp" break; case 5: // assignment: "identifier" "=" "identifier" -#line 67 "../parser.y" +#line 68 "../parser.y" { drv.add_lookup_entry(yystack_[2].value.as < std::string > (), yystack_[0].value.as < std::string > ()); } -#line 662 "parser.cpp" +#line 682 "parser.cpp" break; case 6: // assignment: "identifier" "=" VARNAME "[" indices_list "]" -#line 68 "../parser.y" +#line 69 "../parser.y" { drv.add_lookup_entry(yystack_[5].value.as < std::string > (), yystack_[3].value.as < std::string > (), yystack_[1].value.as < std::vector> > ()); } -#line 668 "parser.cpp" +#line 688 "parser.cpp" break; case 7: // assignment: "identifier" "=" "identifier" "[" indices_list "]" -#line 69 "../parser.y" +#line 70 "../parser.y" { drv.add_lookup_entry(yystack_[5].value.as < std::string > (), yystack_[3].value.as < std::string > (), yystack_[1].value.as < std::vector> > ()); } -#line 674 "parser.cpp" +#line 694 "parser.cpp" break; case 8: // exp: "number" -#line 73 "../parser.y" - { } -#line 680 "parser.cpp" +#line 74 "../parser.y" + { drv.createNode(yystack_[0].value.as < double > ()); } +#line 700 "parser.cpp" break; - case 9: // exp: exp OPERATOR exp -#line 74 "../parser.y" + case 9: // exp: INT +#line 75 "../parser.y" + { drv.createNode(yystack_[0].value.as < int > ()); } +#line 706 "parser.cpp" + break; + + case 10: // exp: exp OPERATOR exp +#line 76 "../parser.y" { drv.createNode(yystack_[1].value.as < std::string > (), 2); } -#line 686 "parser.cpp" +#line 712 "parser.cpp" break; - case 10: // exp: "(" exp ")" -#line 75 "../parser.y" + case 11: // exp: "(" exp ")" +#line 77 "../parser.y" { } -#line 692 "parser.cpp" +#line 718 "parser.cpp" break; - case 11: // exp: "identifier" "(" list ")" -#line 76 "../parser.y" + case 12: // exp: "identifier" "(" list ")" +#line 78 "../parser.y" { drv.createNode(yystack_[3].value.as < std::string > (), yystack_[1].value.as < int > ()); } -#line 698 "parser.cpp" +#line 724 "parser.cpp" break; - case 12: // exp: "identifier" "[" indices_list "]" -#line 77 "../parser.y" + case 13: // exp: "identifier" "[" indices_list "]" +#line 79 "../parser.y" { drv.createNode(yystack_[3].value.as < std::string > (), yystack_[1].value.as < std::vector> > ()); } -#line 704 "parser.cpp" +#line 730 "parser.cpp" break; - case 13: // exp: "identifier" -#line 78 "../parser.y" + case 14: // exp: "identifier" +#line 80 "../parser.y" { drv.createNode(yystack_[0].value.as < std::string > ()); } -#line 710 "parser.cpp" +#line 736 "parser.cpp" break; - case 14: // indices_list: %empty -#line 83 "../parser.y" + case 15: // indices_list: %empty +#line 85 "../parser.y" { yylhs.value.as < std::vector> > () = {}; } -#line 716 "parser.cpp" +#line 742 "parser.cpp" break; - case 15: // indices_list: indices_list "," index -#line 84 "../parser.y" + case 16: // indices_list: indices_list "," index +#line 86 "../parser.y" { yystack_[2].value.as < std::vector> > ().push_back(yystack_[0].value.as < std::tuple > ()); yylhs.value.as < std::vector> > () = yystack_[2].value.as < std::vector> > (); } -#line 722 "parser.cpp" +#line 748 "parser.cpp" break; - case 16: // indices_list: index -#line 85 "../parser.y" + case 17: // indices_list: index +#line 87 "../parser.y" { yylhs.value.as < std::vector> > () = {yystack_[0].value.as < std::tuple > ()}; } -#line 728 "parser.cpp" +#line 754 "parser.cpp" break; - case 17: // index: %empty -#line 89 "../parser.y" + case 18: // index: %empty +#line 91 "../parser.y" { yylhs.value.as < std::tuple > () = {-1, -1, 1}; } -#line 734 "parser.cpp" +#line 760 "parser.cpp" break; - case 18: // index: "number" ":" "number" ":" "number" -#line 90 "../parser.y" + case 19: // index: INT ":" INT ":" INT +#line 92 "../parser.y" { yylhs.value.as < std::tuple > () = {yystack_[4].value.as < int > (), yystack_[2].value.as < int > (), yystack_[0].value.as < int > ()}; } -#line 740 "parser.cpp" +#line 766 "parser.cpp" break; - case 19: // index: ":" "number" ":" "number" -#line 91 "../parser.y" + case 20: // index: ":" INT ":" INT +#line 93 "../parser.y" { yylhs.value.as < std::tuple > () = {-1, yystack_[2].value.as < int > (), yystack_[0].value.as < int > ()}; } -#line 746 "parser.cpp" +#line 772 "parser.cpp" break; - case 20: // index: "number" ":" ":" "number" -#line 92 "../parser.y" + case 21: // index: INT ":" ":" INT +#line 94 "../parser.y" { yylhs.value.as < std::tuple > () = {yystack_[3].value.as < int > (), -1, yystack_[0].value.as < int > ()}; } -#line 752 "parser.cpp" +#line 778 "parser.cpp" break; - case 21: // index: "number" ":" "number" ":" -#line 93 "../parser.y" + case 22: // index: INT ":" INT ":" +#line 95 "../parser.y" { yylhs.value.as < std::tuple > () = {yystack_[3].value.as < int > (), yystack_[1].value.as < int > (), 1}; } -#line 758 "parser.cpp" +#line 784 "parser.cpp" break; - case 22: // index: "number" ":" "number" -#line 94 "../parser.y" + case 23: // index: INT ":" INT +#line 96 "../parser.y" { yylhs.value.as < std::tuple > () = {yystack_[2].value.as < int > (), yystack_[0].value.as < int > (), 1}; } -#line 764 "parser.cpp" +#line 790 "parser.cpp" break; - case 23: // index: ":" ":" "number" -#line 95 "../parser.y" + case 24: // index: ":" ":" INT +#line 97 "../parser.y" { yylhs.value.as < std::tuple > () = {-1, -1, yystack_[0].value.as < int > ()}; } -#line 770 "parser.cpp" +#line 796 "parser.cpp" break; - case 24: // index: ":" "number" ":" -#line 96 "../parser.y" + case 25: // index: ":" INT ":" +#line 98 "../parser.y" { yylhs.value.as < std::tuple > () = {-1, yystack_[1].value.as < int > (), 1}; } -#line 776 "parser.cpp" +#line 802 "parser.cpp" break; - case 25: // index: ":" "number" -#line 97 "../parser.y" + case 26: // index: ":" INT +#line 99 "../parser.y" { yylhs.value.as < std::tuple > () = {-1, yystack_[0].value.as < int > (), 1}; } -#line 782 "parser.cpp" +#line 808 "parser.cpp" break; - case 26: // index: "number" ":" ":" -#line 98 "../parser.y" + case 27: // index: INT ":" ":" +#line 100 "../parser.y" { yylhs.value.as < std::tuple > () = {yystack_[2].value.as < int > (), -1, 1}; } -#line 788 "parser.cpp" +#line 814 "parser.cpp" break; - case 27: // index: "number" ":" -#line 99 "../parser.y" + case 28: // index: INT ":" +#line 101 "../parser.y" { yylhs.value.as < std::tuple > () = {yystack_[1].value.as < int > (), -1, 1}; } -#line 794 "parser.cpp" +#line 820 "parser.cpp" break; - case 28: // index: "number" -#line 100 "../parser.y" + case 29: // index: INT +#line 102 "../parser.y" { yylhs.value.as < std::tuple > () = {yystack_[0].value.as < int > (), yystack_[0].value.as < int > (), 1}; } -#line 800 "parser.cpp" +#line 826 "parser.cpp" break; - case 29: // list: %empty -#line 104 "../parser.y" + case 30: // list: %empty +#line 106 "../parser.y" { yylhs.value.as < int > () = 0; } -#line 806 "parser.cpp" +#line 832 "parser.cpp" break; - case 30: // list: exp "," list -#line 105 "../parser.y" + case 31: // list: exp "," list +#line 107 "../parser.y" { yylhs.value.as < int > () = yystack_[0].value.as < int > () + 1; } -#line 812 "parser.cpp" +#line 838 "parser.cpp" break; - case 31: // list: exp -#line 106 "../parser.y" + case 32: // list: exp +#line 108 "../parser.y" { yylhs.value.as < int > () = 1; } -#line 818 "parser.cpp" +#line 844 "parser.cpp" break; -#line 822 "parser.cpp" +#line 848 "parser.cpp" default: break; @@ -1003,8 +1029,8 @@ namespace adios2 { namespace detail { static const char *const yy_sname[] = { "end of file", "error", "invalid token", "=", ",", ":", "(", ")", "[", - "]", "OPERATOR", "identifier", "VARNAME", "number", "$accept", "lines", - "assignment", "exp", "indices_list", "index", "list", YY_NULLPTR + "]", "OPERATOR", "identifier", "VARNAME", "number", "INT", "$accept", + "lines", "assignment", "exp", "indices_list", "index", "list", YY_NULLPTR }; return yy_sname[yysymbol]; } @@ -1273,90 +1299,90 @@ namespace adios2 { namespace detail { } - const signed char parser::yypact_ninf_ = -7; + const signed char parser::yypact_ninf_ = -10; const signed char parser::yytable_ninf_ = -1; const signed char parser::yypact_[] = { - 6, 9, 22, -7, 5, 6, 13, 27, -6, -4, - 9, -3, -7, -7, 9, -7, 30, 31, 14, 24, - -2, 35, 12, -7, -7, -3, -3, 9, -7, 28, - 37, 1, -3, -7, 23, 25, -7, -7, 32, 33, - 38, -7, -7, -7, -7, -7, 34, -7 + 7, 11, 25, -10, -10, 5, 7, -9, 30, 9, + -4, 11, -3, -10, -10, 11, -10, 18, 33, 19, + 27, -2, 37, 0, -10, -10, -3, -3, 11, -10, + 29, 39, 1, -3, -10, 26, 28, -10, -10, 31, + 32, 42, -10, -10, -10, -10, -10, 34, -10 }; const signed char parser::yydefact_[] = { - 0, 0, 13, 8, 0, 0, 3, 13, 0, 0, - 29, 14, 1, 2, 0, 10, 5, 4, 31, 0, - 0, 28, 0, 16, 9, 14, 14, 29, 11, 0, - 25, 27, 17, 12, 0, 0, 30, 23, 24, 26, - 22, 15, 7, 6, 19, 20, 21, 18 + 0, 0, 14, 8, 9, 0, 0, 3, 14, 0, + 0, 30, 15, 1, 2, 0, 11, 5, 4, 32, + 0, 0, 29, 0, 17, 10, 15, 15, 30, 12, + 0, 26, 28, 18, 13, 0, 0, 31, 24, 25, + 27, 23, 16, 7, 6, 20, 21, 22, 19 }; const signed char parser::yypgoto_[] = { - -7, 39, -7, -1, 11, 16, 26 + -10, 43, -10, -1, 13, 17, 23 }; const signed char parser::yydefgoto_[] = { - 0, 4, 5, 6, 22, 23, 19 + 0, 5, 6, 7, 23, 24, 20 }; const signed char parser::yytable_[] = { - 8, 15, 20, 29, 14, 12, 39, 16, 17, 18, - 21, 30, 1, 24, 40, 1, 32, 2, 27, 3, - 7, 33, 3, 14, 14, 9, 18, 32, 10, 32, - 11, 28, 42, 10, 43, 11, 34, 35, 25, 26, - 31, 37, 38, 46, 13, 44, 45, 47, 41, 0, - 0, 0, 0, 36 + 9, 15, 21, 30, 33, 13, 40, 17, 18, 34, + 19, 22, 31, 1, 25, 41, 16, 1, 2, 15, + 3, 4, 8, 28, 3, 4, 26, 19, 10, 15, + 33, 11, 33, 12, 29, 43, 11, 44, 12, 35, + 36, 27, 32, 38, 39, 45, 46, 47, 48, 14, + 42, 37 }; const signed char parser::yycheck_[] = { - 1, 7, 5, 5, 10, 0, 5, 11, 12, 10, - 13, 13, 6, 14, 13, 6, 4, 11, 4, 13, - 11, 9, 13, 10, 10, 3, 27, 4, 6, 4, - 8, 7, 9, 6, 9, 8, 25, 26, 8, 8, - 5, 13, 5, 5, 5, 13, 13, 13, 32, -1, - -1, -1, -1, 27 + 1, 10, 5, 5, 4, 0, 5, 11, 12, 9, + 11, 14, 14, 6, 15, 14, 7, 6, 11, 10, + 13, 14, 11, 4, 13, 14, 8, 28, 3, 10, + 4, 6, 4, 8, 7, 9, 6, 9, 8, 26, + 27, 8, 5, 14, 5, 14, 14, 5, 14, 6, + 33, 28 }; const signed char parser::yystos_[] = { - 0, 6, 11, 13, 15, 16, 17, 11, 17, 3, - 6, 8, 0, 15, 10, 7, 11, 12, 17, 20, - 5, 13, 18, 19, 17, 8, 8, 4, 7, 5, - 13, 5, 4, 9, 18, 18, 20, 13, 5, 5, - 13, 19, 9, 9, 13, 13, 5, 13 + 0, 6, 11, 13, 14, 16, 17, 18, 11, 18, + 3, 6, 8, 0, 16, 10, 7, 11, 12, 18, + 21, 5, 14, 19, 20, 18, 8, 8, 4, 7, + 5, 14, 5, 4, 9, 19, 19, 21, 14, 5, + 5, 14, 20, 9, 9, 14, 14, 5, 14 }; const signed char parser::yyr1_[] = { - 0, 14, 15, 15, 16, 16, 16, 16, 17, 17, - 17, 17, 17, 17, 18, 18, 18, 19, 19, 19, - 19, 19, 19, 19, 19, 19, 19, 19, 19, 20, - 20, 20 + 0, 15, 16, 16, 17, 17, 17, 17, 18, 18, + 18, 18, 18, 18, 18, 19, 19, 19, 20, 20, + 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, + 21, 21, 21 }; const signed char parser::yyr2_[] = { - 0, 2, 2, 1, 3, 3, 6, 6, 1, 3, - 3, 4, 4, 1, 0, 3, 1, 0, 5, 4, - 4, 4, 3, 3, 3, 2, 3, 2, 1, 0, - 3, 1 + 0, 2, 2, 1, 3, 3, 6, 6, 1, 1, + 3, 3, 4, 4, 1, 0, 3, 1, 0, 5, + 4, 4, 4, 3, 3, 3, 2, 3, 2, 1, + 0, 3, 1 }; @@ -1366,10 +1392,10 @@ namespace adios2 { namespace detail { const signed char parser::yyrline_[] = { - 0, 61, 61, 62, 66, 67, 68, 69, 73, 74, - 75, 76, 77, 78, 83, 84, 85, 89, 90, 91, - 92, 93, 94, 95, 96, 97, 98, 99, 100, 104, - 105, 106 + 0, 62, 62, 63, 67, 68, 69, 70, 74, 75, + 76, 77, 78, 79, 80, 85, 86, 87, 91, 92, + 93, 94, 95, 96, 97, 98, 99, 100, 101, 102, + 106, 107, 108 }; void @@ -1402,9 +1428,9 @@ namespace adios2 { namespace detail { #line 6 "../parser.y" } } // adios2::detail -#line 1406 "parser.cpp" +#line 1432 "parser.cpp" -#line 107 "../parser.y" +#line 109 "../parser.y" void diff --git a/source/adios2/toolkit/derived/parser/pregen-source/parser.h b/source/adios2/toolkit/derived/parser/pregen-source/parser.h index 819381e379..0e330956c2 100644 --- a/source/adios2/toolkit/derived/parser/pregen-source/parser.h +++ b/source/adios2/toolkit/derived/parser/pregen-source/parser.h @@ -419,19 +419,22 @@ namespace adios2 { namespace detail { union union_type { // "number" + char dummy1[sizeof (double)]; + + // INT // list - char dummy1[sizeof (int)]; + char dummy2[sizeof (int)]; // OPERATOR // "identifier" // VARNAME - char dummy2[sizeof (std::string)]; + char dummy3[sizeof (std::string)]; // index - char dummy3[sizeof (std::tuple)]; + char dummy4[sizeof (std::tuple)]; // indices_list - char dummy4[sizeof (std::vector>)]; + char dummy5[sizeof (std::vector>)]; }; /// The size of the largest semantic type. @@ -494,7 +497,8 @@ namespace adios2 { namespace detail { TOK_OPERATOR = 10, // OPERATOR TOK_IDENTIFIER = 11, // "identifier" TOK_VARNAME = 12, // VARNAME - TOK_INT = 13 // "number" + TOK_DOUBLE = 13, // "number" + TOK_INT = 14 // INT }; /// Backward compatibility alias (Bison 3.6). typedef token_kind_type yytokentype; @@ -511,7 +515,7 @@ namespace adios2 { namespace detail { { enum symbol_kind_type { - YYNTOKENS = 14, ///< Number of tokens. + YYNTOKENS = 15, ///< Number of tokens. S_YYEMPTY = -2, S_YYEOF = 0, // "end of file" S_YYerror = 1, // error @@ -526,14 +530,15 @@ namespace adios2 { namespace detail { S_OPERATOR = 10, // OPERATOR S_IDENTIFIER = 11, // "identifier" S_VARNAME = 12, // VARNAME - S_INT = 13, // "number" - S_YYACCEPT = 14, // $accept - S_lines = 15, // lines - S_assignment = 16, // assignment - S_exp = 17, // exp - S_indices_list = 18, // indices_list - S_index = 19, // index - S_list = 20 // list + S_DOUBLE = 13, // "number" + S_INT = 14, // INT + S_YYACCEPT = 15, // $accept + S_lines = 16, // lines + S_assignment = 17, // assignment + S_exp = 18, // exp + S_indices_list = 19, // indices_list + S_index = 20, // index + S_list = 21 // list }; }; @@ -570,7 +575,11 @@ namespace adios2 { namespace detail { { switch (this->kind ()) { - case symbol_kind::S_INT: // "number" + case symbol_kind::S_DOUBLE: // "number" + value.move< double > (std::move (that.value)); + break; + + case symbol_kind::S_INT: // INT case symbol_kind::S_list: // list value.move< int > (std::move (that.value)); break; @@ -612,6 +621,20 @@ namespace adios2 { namespace detail { {} #endif +#if 201103L <= YY_CPLUSPLUS + basic_symbol (typename Base::kind_type t, double&& v, location_type&& l) + : Base (t) + , value (std::move (v)) + , location (std::move (l)) + {} +#else + basic_symbol (typename Base::kind_type t, const double& v, const location_type& l) + : Base (t) + , value (v) + , location (l) + {} +#endif + #if 201103L <= YY_CPLUSPLUS basic_symbol (typename Base::kind_type t, int&& v, location_type&& l) : Base (t) @@ -692,7 +715,11 @@ namespace adios2 { namespace detail { // Value type destructor. switch (yykind) { - case symbol_kind::S_INT: // "number" + case symbol_kind::S_DOUBLE: // "number" + value.template destroy< double > (); + break; + + case symbol_kind::S_INT: // INT case symbol_kind::S_list: // list value.template destroy< int > (); break; @@ -812,6 +839,18 @@ switch (yykind) || (token::TOK_YYerror <= tok && tok <= token::TOK_R_BRACE)); #endif } +#if 201103L <= YY_CPLUSPLUS + symbol_type (int tok, double v, location_type l) + : super_type (token_kind_type (tok), std::move (v), std::move (l)) +#else + symbol_type (int tok, const double& v, const location_type& l) + : super_type (token_kind_type (tok), v, l) +#endif + { +#if !defined _MSC_VER || defined __clang__ + YY_ASSERT (tok == token::TOK_DOUBLE); +#endif + } #if 201103L <= YY_CPLUSPLUS symbol_type (int tok, int v, location_type l) : super_type (token_kind_type (tok), std::move (v), std::move (l)) @@ -1079,6 +1118,21 @@ switch (yykind) return symbol_type (token::TOK_VARNAME, v, l); } #endif +#if 201103L <= YY_CPLUSPLUS + static + symbol_type + make_DOUBLE (double v, location_type l) + { + return symbol_type (token::TOK_DOUBLE, std::move (v), std::move (l)); + } +#else + static + symbol_type + make_DOUBLE (const double& v, const location_type& l) + { + return symbol_type (token::TOK_DOUBLE, v, l); + } +#endif #if 201103L <= YY_CPLUSPLUS static symbol_type @@ -1438,9 +1492,9 @@ switch (yykind) /// Constants. enum { - yylast_ = 53, ///< Last index in yytable_. + yylast_ = 51, ///< Last index in yytable_. yynnts_ = 7, ///< Number of nonterminal symbols. - yyfinal_ = 12 ///< Termination state number. + yyfinal_ = 13 ///< Termination state number. }; @@ -1465,7 +1519,11 @@ switch (yykind) { switch (this->kind ()) { - case symbol_kind::S_INT: // "number" + case symbol_kind::S_DOUBLE: // "number" + value.copy< double > (YY_MOVE (that.value)); + break; + + case symbol_kind::S_INT: // INT case symbol_kind::S_list: // list value.copy< int > (YY_MOVE (that.value)); break; @@ -1515,7 +1573,11 @@ switch (yykind) super_type::move (s); switch (this->kind ()) { - case symbol_kind::S_INT: // "number" + case symbol_kind::S_DOUBLE: // "number" + value.move< double > (YY_MOVE (s.value)); + break; + + case symbol_kind::S_INT: // INT case symbol_kind::S_list: // list value.move< int > (YY_MOVE (s.value)); break; @@ -1601,7 +1663,7 @@ switch (yykind) #line 6 "../parser.y" } } // adios2::detail -#line 1605 "parser.h" +#line 1667 "parser.h" diff --git a/testing/adios2/derived/TestBPDerivedCorrectness.cpp b/testing/adios2/derived/TestBPDerivedCorrectness.cpp index 10a51069f5..9c341ce34d 100644 --- a/testing/adios2/derived/TestBPDerivedCorrectness.cpp +++ b/testing/adios2/derived/TestBPDerivedCorrectness.cpp @@ -396,6 +396,135 @@ TEST(DerivedCorrectness, CurlCorrectnessTest) EXPECT_LT(sum_z / (Nx * Ny * Nz), error_limit); } +TEST(DerivedCorrectness, MagCurlCorrectnessTest) +{ + const size_t Nx = 25, Ny = 70, Nz = 13; + float error_limit = 0.0000001f; + + // Application variable + std::vector simArray1(Nx * Ny * Nz); + std::vector simArray2(Nx * Ny * Nz); + std::vector simArray3(Nx * Ny * Nz); + for (size_t i = 0; i < Nx; ++i) + { + for (size_t j = 0; j < Ny; ++j) + { + for (size_t k = 0; k < Nz; ++k) + { + size_t idx = (i * Ny * Nz) + (j * Nz) + k; + float x = static_cast(i); + float y = static_cast(j); + float z = static_cast(k); + // Linear curl example + simArray1[idx] = (6 * x * y) + (7 * z); + simArray2[idx] = (4 * x * z) + powf(y, 2); + simArray3[idx] = sqrtf(z) + (2 * x * y); + /* Less linear example + simArray1[idx] = sinf(z); + simArray2[idx] = 4 * x; + simArray3[idx] = powf(y, 2) * cosf(x); + */ + /* Nonlinear example + simArray1[idx] = expf(2 * y) * sinf(x); + simArray2[idx] = sqrtf(z + 1) * cosf(x); + simArray3[idx] = powf(x, 2) * sinf(y) + (6 * z); + */ + } + } + } + + adios2::ADIOS adios; + adios2::IO bpOut = adios.DeclareIO("BPWriteExpression"); + std::vector varname = {"sim4/VX", "sim4/VY", "sim4/VZ"}; + std::string derivedname = "derived/magcurlV"; + + auto VX = bpOut.DefineVariable(varname[0], {Nx, Ny, Nz}, {0, 0, 0}, {Nx, Ny, Nz}); + auto VY = bpOut.DefineVariable(varname[1], {Nx, Ny, Nz}, {0, 0, 0}, {Nx, Ny, Nz}); + auto VZ = bpOut.DefineVariable(varname[2], {Nx, Ny, Nz}, {0, 0, 0}, {Nx, Ny, Nz}); + // clang-format off + bpOut.DefineDerivedVariable(derivedname, + "Vx =" + varname[0] + " \n" + "Vy =" + varname[1] + " \n" + "Vz =" + varname[2] + " \n" + "magnitude(curl(Vx,Vy,Vz),3)", + adios2::DerivedVarType::StoreData); + // clang-format on + std::string filename = "expMagCurl.bp"; + adios2::Engine bpFileWriter = bpOut.Open(filename, adios2::Mode::Write); + + bpFileWriter.BeginStep(); + bpFileWriter.Put(VX, simArray1.data()); + bpFileWriter.Put(VY, simArray2.data()); + bpFileWriter.Put(VZ, simArray3.data()); + bpFileWriter.EndStep(); + bpFileWriter.Close(); + + adios2::IO bpIn = adios.DeclareIO("BPReadMagCurlExpression"); + adios2::Engine bpFileReader = bpIn.Open(filename, adios2::Mode::Read); + + std::vector readVX; + std::vector readVY; + std::vector readVZ; + // TODO/DEBUG - VERIFY DATATYPE + std::vector readMagCurl; + + std::vector> calcMagCurl; + double sum = 0; + bpFileReader.BeginStep(); + auto varVX = bpIn.InquireVariable(varname[0]); + auto varVY = bpIn.InquireVariable(varname[1]); + auto varVZ = bpIn.InquireVariable(varname[2]); + auto varMagCurl = bpIn.InquireVariable(derivedname); + + bpFileReader.Get(varVX, readVX); + bpFileReader.Get(varVY, readVY); + bpFileReader.Get(varVZ, readVZ); + bpFileReader.Get(varMagCurl, readMagCurl); + bpFileReader.EndStep(); + + float curl_x, curl_y, curl_z, mag; + float err; + for (size_t i = 0; i < Nx; ++i) + { + for (size_t j = 0; j < Ny; ++j) + { + for (size_t k = 0; k < Nz; ++k) + { + size_t idx = (i * Ny * Nz) + (j * Nz) + k; + float x = static_cast(i); + float y = static_cast(j); + float z = static_cast(k); + // Linear example + curl_x = -(2 * x); + curl_y = 7 - (2 * y); + curl_z = (4 * z) - (6 * x); + /* Less linear + curl_x = 2 * y * cosf(x); + curl_y = cosf(z) + (powf(y, 2) * sinf(x)); + curl_z = 4; + */ + /* Nonlinear example + curl_x = powf(x, 2) * cosf(y) - (cosf(x) / (2 * sqrtf(z + 1))); + curl_y = -2 * x * sinf(y); + curl_z = -sqrtf(z + 1) * sinf(x) - (2 * expf(2 * y) * sinf(x)); + */ + mag = sqrtf(powf(curl_x, 2) + powf(curl_y, 2) + powf(curl_z, 2)); + if (fabs(mag) < 1) + { + err = fabs(mag - readMagCurl[idx]) / (1 + fabs(mag)); + } + else + { + err = fabs(mag - readMagCurl[idx]) / fabs(mag); + } + sum += err; + } + } + } + bpFileReader.Close(); + EXPECT_LT(sum / (Nx * Ny * Nz), error_limit); +} + int main(int argc, char **argv) { int result;