diff --git a/src/libcadet/AdUtils.cpp b/src/libcadet/AdUtils.cpp index e05573e82..cd187f4e2 100644 --- a/src/libcadet/AdUtils.cpp +++ b/src/libcadet/AdUtils.cpp @@ -100,10 +100,10 @@ void extractBandedEigenJacobianFromAd(active const* const adVec, int adDirOffset } void extractBandedBlockEigenJacobianFromAd(active const* const adVec, int adDirOffset, int diagDir, const int lowerBandwidth, const int upperBandwidth, - const int blockOffset, const int nCols, Eigen::SparseMatrix& mat, const int matrixOffset) + const int blockOffset, const int nRows, Eigen::SparseMatrix& mat, const int matrixOffset) { const int stride = lowerBandwidth + 1 + upperBandwidth; - for (int eq = blockOffset; eq < blockOffset + nCols; ++eq) + for (int eq = blockOffset; eq < blockOffset + nRows; ++eq) { // Start with lowest subdiagonal and stay in the range of the columns: // diagDir might be too big for the matrix and, hence, dir ranges between @@ -114,7 +114,7 @@ void extractBandedBlockEigenJacobianFromAd(active const* const adVec, int adDirO for (int diag = 0; diag < stride; ++diag) { if (eq - lowerBandwidth + diag >= blockOffset && // left block boundary - eq - lowerBandwidth + diag < blockOffset + nCols && // right block boundary + eq - lowerBandwidth + diag < blockOffset + nRows && // right block boundary adVec[eq].getADValue(adDirOffset + dir) != 0.0 // keep pattern ) mat.coeffRef(matrixOffset + eq, matrixOffset + eq - lowerBandwidth + diag) = adVec[eq].getADValue(adDirOffset + dir); @@ -281,6 +281,51 @@ double compareDenseJacobianWithBandedAd(active const* const adVec, int row, int return maxDiff; } +double compareBandedEigenJacobianWithAd(active const* const adVec, const int adDirOffset, const int diagDir, const int lowerBandwidth, const int upperBandwidth, + const int blockOffset, const int nRows, const Eigen::SparseMatrix& mat, const int matrixOffset) +{ + double maxDiff = 0.0; + + const int stride = lowerBandwidth + 1 + upperBandwidth; + for (int eq = blockOffset; eq < blockOffset + nRows; ++eq) + { + // Start with lowest subdiagonal and stay in the range of the columns: + // diagDir might be too big for the matrix and, hence, dir ranges between + // diagDir - lowerBandwidth <= dir <= diagDir + upperBandwidth + int dir = diagDir - lowerBandwidth + eq % stride; + + // Loop over diagonals + for (int diag = 0; diag < stride; ++diag) + { + if (eq - lowerBandwidth + diag >= blockOffset && // left block boundary + eq - lowerBandwidth + diag < blockOffset + nRows && // right block boundary + adVec[eq].getADValue(adDirOffset + dir) != 0.0 // keep pattern + ) + { + double baseVal = adVec[eq].getADValue(adDirOffset + dir); + double matVal = mat.coeff(matrixOffset + eq, matrixOffset + eq - lowerBandwidth + diag); + + if (std::isnan(matVal) || std::isnan(baseVal)) + return std::numeric_limits::quiet_NaN(); + const double diff = std::abs(matVal - baseVal); + + baseVal = std::abs(baseVal); + if (baseVal > 0.0) + maxDiff = std::max(maxDiff, diff / baseVal); + else + maxDiff = std::max(maxDiff, diff); + } + + // Wrap around at end of row and jump to lowest subdiagonal + if (dir == diagDir + upperBandwidth) + dir = diagDir - lowerBandwidth; + else + ++dir; + } + } + return maxDiff; +} + void adMatrixVectorMultiply(const linalg::SparseMatrix& mat, double const* x, double* y, double alpha, double beta, int adDir) { const std::vector& rows = mat.rows(); diff --git a/src/libcadet/AdUtils.hpp b/src/libcadet/AdUtils.hpp index 6abedcfb0..d30b6e782 100644 --- a/src/libcadet/AdUtils.hpp +++ b/src/libcadet/AdUtils.hpp @@ -145,6 +145,26 @@ void extractDenseJacobianFromBandedAd(active const* const adVec, int row, int ad */ double compareBandedJacobianWithAd(active const* const adVec, int adDirOffset, int diagDir, const linalg::BandMatrix& mat); +/** + * @brief Compares a (block-) banded Jacobian in Eigen library row-major format with an AD version derived by band compressed AD seed vectors + * @details Uses the results of an AD computation with seed vectors set by prepareAdVectorSeedsForBandMatrix() to + compare the results with a given banded Jacobian. The AD Jacobian is treated as base and the analytic + Jacobian is compared against it. The relative difference + @f[ \Delta_{ij} = \begin{cases} \left\lvert \frac{ J_{\text{ana},ij} - J_{\text{ad},ij} }{ J_{\text{ad},ij} }\right\rvert, & J_{\text{ad},ij} \neq 0 \\ + \left\lvert J_{\text{ana},ij} - J_{\text{ad},ij} \right\rvert, & J_{\text{ad},ij} = 0 \end{cases} @f] + is computed for each matrix entry. The maximum of all @f$ \Delta_{ij} @f$ is returned. + * @param [in] adVec Vector of AD datatypes with band compressed seed vectors + * @param [in] adDirOffset Offset in the AD directions (can be used to move past parameter sensitivity directions) + * @param [in] diagDir Diagonal direction index + * @param [in] lowerBandwidth of the block + * @param [in] upperBandwidth of the block + * @param [in] blockOffset of the currently considered block + * @param [in] nRows of the matrix or number of equations to be compared + * @param [in] mat BandMatrix populated with the analytic Jacobian + * @return The maximum absolute relative difference between the matrix elements + */ +double compareBandedEigenJacobianWithAd(active const* const adVec, const int adDirOffset, const int diagDir, const int lowerBandwidth, const int upperBandwidth, const int blockOffset, const int nRows, const Eigen::SparseMatrix& mat, const int matrixOffset); + /** * @brief Compares a dense Jacobian with an AD version derived by AD seed vectors * @details Uses the results of an AD computation with seed vectors set by prepareAdVectorSeedsForDenseMatrix() to diff --git a/src/libcadet/model/LumpedRateModelWithPoresDG.cpp b/src/libcadet/model/LumpedRateModelWithPoresDG.cpp index 29176d3fe..d755749a8 100644 --- a/src/libcadet/model/LumpedRateModelWithPoresDG.cpp +++ b/src/libcadet/model/LumpedRateModelWithPoresDG.cpp @@ -805,23 +805,56 @@ void LumpedRateModelWithPoresDG::extractJacobianFromAD(active const* const adRes */ void LumpedRateModelWithPoresDG::checkAnalyticJacobianAgainstAd(active const* const adRes, unsigned int adDirOffset) const { - // todo write this function - //Indexer idxr(_disc); - - //LOG(Debug) << "AD dir offset: " << adDirOffset << " DiagDirCol: " << _convDispOp.jacobian().lowerBandwidth(); - - //// Column - //const double maxDiffCol = _convDispOp.checkAnalyticJacobianAgainstAd(adRes, adDirOffset); - - //// Particles - //double maxDiffPar = 0.0; - //for (unsigned int type = 0; type < _disc.nParType; ++type) - //{ - // const linalg::BandMatrix& jacMat = _jacP[type]; - // const double localDiff = ad::compareBandedJacobianWithAd(adRes + idxr.offsetCp(ParticleTypeIndex{ type }), adDirOffset, jacMat.lowerBandwidth(), jacMat); - // LOG(Debug) << "-> Par type " << type << " diff: " << localDiff; - // maxDiffPar = std::max(maxDiffPar, localDiff); - //} + Indexer idxr(_disc); + + const int lowerBandwidth = (_disc.exactInt) ? 2 * _disc.nNodes * idxr.strideColNode() : _disc.nNodes * idxr.strideColNode(); + const int upperBandwidth = lowerBandwidth; + const int stride = lowerBandwidth + 1 + upperBandwidth; + + const double maxDiff = ad::compareBandedEigenJacobianWithAd(adRes + idxr.offsetC(), adDirOffset, lowerBandwidth, lowerBandwidth, upperBandwidth, 0, numPureDofs(), _globalJac, 0); + + if (maxDiff > 1e-6) + int jojo = 0; + + double maxDiffPar = 0.0; + + for (unsigned int type = 0; type < _disc.nParType; type++) + { + int offsetParticleTypeDirs = adDirOffset + idxr.offsetCp(ParticleTypeIndex{ type }) - idxr.offsetC(); + + for (unsigned int par = 0; par < _disc.nPoints; par++) + { + const int eqOffset_res = idxr.offsetCp(ParticleTypeIndex{ type }, ParticleIndex{ par }); + const int eqOffset_mat = idxr.offsetCp(ParticleTypeIndex{ type }, ParticleIndex{ par }) - idxr.offsetC(); + for (unsigned int phase = 0; phase < idxr.strideParBlock(type); phase++) + { + for (unsigned int phaseTo = 0; phaseTo < idxr.strideParBlock(type); phaseTo++) + { + + double baseVal = adRes[eqOffset_res + phase].getADValue(offsetParticleTypeDirs + phaseTo); + double matVal = _globalJac.coeff(eqOffset_mat + phase, eqOffset_mat + phaseTo); + + if (std::isnan(matVal) || std::isnan(baseVal)) + continue; + + const double diff = std::abs(matVal - baseVal); + + baseVal = std::abs(baseVal); + if (baseVal > 0.0) + maxDiffPar = std::max(maxDiffPar, diff / baseVal); + else + maxDiffPar = std::max(maxDiffPar, diff); + + } + } + } + offsetParticleTypeDirs += idxr.strideParBlock(type); + } + + if (maxDiffPar > 1e-6) + int jojo2 = 0; + + LOG(Debug) << "AD dir offset: " << adDirOffset << " DiagBlockSize: " << stride << " MaxDiffBulk: " << maxDiff << " MaxDiffParticle: " << maxDiffPar; } #endif diff --git a/src/libcadet/model/LumpedRateModelWithoutPoresDG.cpp b/src/libcadet/model/LumpedRateModelWithoutPoresDG.cpp index e92a6b95b..6cc984841 100644 --- a/src/libcadet/model/LumpedRateModelWithoutPoresDG.cpp +++ b/src/libcadet/model/LumpedRateModelWithoutPoresDG.cpp @@ -387,8 +387,7 @@ namespace cadet #ifndef CADET_CHECK_ANALYTIC_JACOBIAN return _jacobianAdDirs; #else - // If CADET_CHECK_ANALYTIC_JACOBIAN is active, we always need the AD directions for the Jacobian - return _jac.cols();// _jac.stride();@SAM? + return _convDispOp.requiredADdirs(); #endif } @@ -427,10 +426,10 @@ namespace cadet const int stride = lowerBandwidth + 1 + upperBandwidth; int diagDir = lowerBandwidth; - const int nCols = _jac.cols(); + const int nRows = _jac.rows(); const int colOffset = 0; - ad::extractBandedBlockEigenJacobianFromAd(adVec, adDirOffset, diagDir, lowerBandwidth, upperBandwidth, colOffset, nCols, _jac); + ad::extractBandedBlockEigenJacobianFromAd(adVec, adDirOffset, diagDir, lowerBandwidth, upperBandwidth, colOffset, nRows, _jac); } @@ -446,9 +445,16 @@ namespace cadet { Indexer idxr(_disc); - // @TODO - //const double maxDiff = ad::compareBandedJacobianWithAd(adRes + idxr.offsetC(), adDirOffset, _jac.lowerBandwidth(), _jac); - //LOG(Debug) << "AD dir offset: " << adDirOffset << " DiagDirCol: " << _jac.lowerBandwidth() << " MaxDiff: " << maxDiff; + const int lowerBandwidth = (_disc.exactInt) ? 2 * _disc.nNodes * idxr.strideColNode() : _disc.nNodes * idxr.strideColNode(); + const int upperBandwidth = lowerBandwidth; + const int stride = lowerBandwidth + 1 + upperBandwidth; + + const double maxDiff = ad::compareBandedEigenJacobianWithAd(adRes + idxr.offsetC(), adDirOffset, lowerBandwidth, lowerBandwidth, upperBandwidth, 0, _jac.rows(), _jac, 0); + + if (maxDiff > 1e-6) + int jojo = 0; + + LOG(Debug) << "AD dir offset: " << adDirOffset << " DiagBlockSize: " << stride << " MaxDiff: " << maxDiff; } #endif diff --git a/test/CMakeLists.txt b/test/CMakeLists.txt index fa0d0dd9e..ea36c9819 100644 --- a/test/CMakeLists.txt +++ b/test/CMakeLists.txt @@ -62,7 +62,8 @@ if (ENABLE_GRM_2D) endif() add_executable(testRunner testRunner.cpp JsonTestModels.cpp ColumnTests.cpp UnitOperationTests.cpp SimHelper.cpp ParticleHelper.cpp - GeneralRateModel.cpp GeneralRateModel2D.cpp LumpedRateModelWithPores.cpp LumpedRateModelWithoutPores.cpp LumpedRateModelWithoutPoresDG.cpp + GeneralRateModel.cpp GeneralRateModel2D.cpp LumpedRateModelWithPores.cpp LumpedRateModelWithoutPores.cpp + GeneralRateModelDG.cpp LumpedRateModelWithPoresDG.cpp LumpedRateModelWithoutPoresDG.cpp RadialGeneralRateModel.cpp RadialLumpedRateModelWithPores.cpp RadialLumpedRateModelWithoutPores.cpp CSTR-Residual.cpp CSTR-Simulation.cpp ConvectionDispersionOperator.cpp diff --git a/test/ColumnTests.cpp b/test/ColumnTests.cpp index 74cabcdb3..11a5aa7b7 100644 --- a/test/ColumnTests.cpp +++ b/test/ColumnTests.cpp @@ -138,7 +138,7 @@ namespace test namespace column { - void FVparams::setDisc(JsonParameterProvider& jpp) const { + void FVparams::setDisc(JsonParameterProvider& jpp, const std::string unitID) const { int level = 0; @@ -147,33 +147,36 @@ namespace column jpp.pushScope("model"); ++level; } - if (jpp.exists("unit_000")) + if (jpp.exists("unit_" + unitID)) { - jpp.pushScope("unit_000"); + jpp.pushScope("unit_" + unitID); ++level; } jpp.pushScope("discretization"); + jpp.set("SPATIAL_METHOD", "FV"); - if (nCol) - jpp.set("NCOL", nCol); + if (nAxCells) + jpp.set("NCOL", nAxCells); - if (nPar) - jpp.set("NPAR", nPar); + if (nParCells) + jpp.set("NPAR", nParCells); - jpp.pushScope("weno"); - - if (wenoOrder) - jpp.set("WENO_ORDER", wenoOrder); + if (jpp.exists("weno")) + { + jpp.pushScope("weno"); + if (wenoOrder) + jpp.set("WENO_ORDER", wenoOrder); - jpp.popScope(); + jpp.popScope(); + } jpp.popScope(); for (int l = 0; l < level; ++l) jpp.popScope(); } - void DGparams::setDisc(JsonParameterProvider& jpp) const { + void DGparams::setDisc(JsonParameterProvider& jpp, const std::string unitID) const { int level = 0; @@ -182,24 +185,25 @@ namespace column jpp.pushScope("model"); ++level; } - if (jpp.exists("unit_000")) + if (jpp.exists("unit_" + unitID)) { - jpp.pushScope("unit_000"); + jpp.pushScope("unit_" + unitID); ++level; } jpp.pushScope("discretization"); + jpp.set("SPATIAL_METHOD", "DG"); if (exactIntegration > -1) jpp.set("EXACT_INTEGRATION", exactIntegration); if (polyDeg) jpp.set("POLYDEG", polyDeg); - if (nElem) - jpp.set("NELEM", nElem); - if (parNelem) - jpp.set("NELEM", parNelem); + if (nAxCells) + jpp.set("NELEM", nAxCells); + if (nParCells) + jpp.set("PAR_NELEM", nParCells); if (parPolyDeg) - jpp.set("POLYDEG", parPolyDeg); + jpp.set("PAR_POLYDEG", parPolyDeg); jpp.popScope(); @@ -833,7 +837,7 @@ namespace column destroyModelBuilder(mb); } - void testJacobianForwardBackward(cadet::JsonParameterProvider& jpp) + void testJacobianForwardBackward(cadet::JsonParameterProvider& jpp, const double absTolFDpattern) { cadet::IModelBuilder* const mb = cadet::createModelBuilder(); REQUIRE(nullptr != mb); @@ -882,8 +886,8 @@ namespace column std::fill(jacDir.begin(), jacDir.end(), 0.0); // Compare Jacobians - cadet::test::checkJacobianPatternFD(unitAna, unitAD, y.data(), nullptr, jacDir.data(), jacCol1.data(), jacCol2.data(), tls); - cadet::test::checkJacobianPatternFD(unitAna, unitAna, y.data(), nullptr, jacDir.data(), jacCol1.data(), jacCol2.data(), tls); + cadet::test::checkJacobianPatternFD(unitAna, unitAD, y.data(), nullptr, jacDir.data(), jacCol1.data(), jacCol2.data(), tls, absTolFDpattern); + cadet::test::checkJacobianPatternFD(unitAna, unitAna, y.data(), nullptr, jacDir.data(), jacCol1.data(), jacCol2.data(), tls, absTolFDpattern); cadet::test::compareJacobian(unitAna, unitAD, nullptr, nullptr, jacDir.data(), jacCol1.data(), jacCol2.data()); // cadet::test::compareJacobianFD(unitAna, unitAD, y.data(), nullptr, jacDir.data(), jacCol1.data(), jacCol2.data()); @@ -896,15 +900,15 @@ namespace column const bool paramSet2 = unitAD->setParameter(cadet::makeParamId(cadet::hashString("VELOCITY_COEFF"), 0, cadet::CompIndep, cadet::ParTypeIndep, cadet::BoundStateIndep, cadet::ReactionIndep, cadet::SectionIndep), -jpp.getDouble("VELOCITY_COEFF")); REQUIRE(paramSet2); } - else - { - // Reverse flow - const bool paramSet = unitAna->setParameter(cadet::makeParamId(cadet::hashString("VELOCITY"), 0, cadet::CompIndep, cadet::ParTypeIndep, cadet::BoundStateIndep, cadet::ReactionIndep, cadet::SectionIndep), -jpp.getDouble("VELOCITY")); - REQUIRE(paramSet); - // Reverse flow - const bool paramSet2 = unitAD->setParameter(cadet::makeParamId(cadet::hashString("VELOCITY"), 0, cadet::CompIndep, cadet::ParTypeIndep, cadet::BoundStateIndep, cadet::ReactionIndep, cadet::SectionIndep), -jpp.getDouble("VELOCITY")); - REQUIRE(paramSet2); - } + else + { + // Reverse flow + const bool paramSet = unitAna->setParameter(cadet::makeParamId(cadet::hashString("VELOCITY"), 0, cadet::CompIndep, cadet::ParTypeIndep, cadet::BoundStateIndep, cadet::ReactionIndep, cadet::SectionIndep), -jpp.getDouble("VELOCITY")); + REQUIRE(paramSet); + // Reverse flow + const bool paramSet2 = unitAD->setParameter(cadet::makeParamId(cadet::hashString("VELOCITY"), 0, cadet::CompIndep, cadet::ParTypeIndep, cadet::BoundStateIndep, cadet::ReactionIndep, cadet::SectionIndep), -jpp.getDouble("VELOCITY")); + REQUIRE(paramSet2); + } // Setup unitAna->notifyDiscontinuousSectionTransition(0.0, 0u, {y.data(), nullptr}, noAdParams); @@ -916,8 +920,8 @@ namespace column std::fill(jacDir.begin(), jacDir.end(), 0.0); // Compare Jacobians - cadet::test::checkJacobianPatternFD(unitAna, unitAD, y.data(), nullptr, jacDir.data(), jacCol1.data(), jacCol2.data(), tls); - cadet::test::checkJacobianPatternFD(unitAna, unitAna, y.data(), nullptr, jacDir.data(), jacCol1.data(), jacCol2.data(), tls); + cadet::test::checkJacobianPatternFD(unitAna, unitAD, y.data(), nullptr, jacDir.data(), jacCol1.data(), jacCol2.data(), tls, absTolFDpattern); + cadet::test::checkJacobianPatternFD(unitAna, unitAna, y.data(), nullptr, jacDir.data(), jacCol1.data(), jacCol2.data(), tls, absTolFDpattern); // cadet::test::compareJacobianFD(unitAD, unitAna, y.data(), jacDir.data(), nullptr, jacCol1.data(), jacCol2.data()); // cadet::test::compareJacobianFD(unitAna, unitAD, y.data(), jacDir.data(), nullptr, jacCol1.data(), jacCol2.data()); cadet::test::compareJacobian(unitAna, unitAD, nullptr, nullptr, jacDir.data(), jacCol1.data(), jacCol2.data()); @@ -931,7 +935,7 @@ namespace column destroyModelBuilder(mb); } - void testJacobianForwardBackward(const char* uoType, FVparams disc) + void testJacobianForwardBackward(const char* uoType, FVparams disc, const double absTolFDpattern) { SECTION("Forward vs backward flow Jacobian (WENO=" + std::to_string(disc.getWenoOrder()) + ")") { @@ -939,11 +943,11 @@ namespace column cadet::JsonParameterProvider jpp = createColumnWithTwoCompLinearBinding(uoType, "FV"); disc.setDisc(jpp); - testJacobianForwardBackward(jpp); + testJacobianForwardBackward(jpp, absTolFDpattern); } } - void testJacobianForwardBackward(const char* uoType, DGparams disc) + void testJacobianForwardBackward(const char* uoType, DGparams disc, const double absTolFDpattern) { SECTION("Forward vs backward flow Jacobian (DG integration mode " + std::to_string(disc.getIntegrationMode()) + ")") { @@ -951,7 +955,7 @@ namespace column cadet::JsonParameterProvider jpp = createColumnWithTwoCompLinearBinding(uoType, "DG"); disc.setDisc(jpp); - testJacobianForwardBackward(jpp); + testJacobianForwardBackward(jpp, absTolFDpattern); } } @@ -1423,16 +1427,20 @@ namespace column } } - void testConsistentInitializationLinearBinding(const std::string& uoType, const std::string& spatialMethod, double consTol, double absTol) + void testConsistentInitializationLinearBinding(const std::string& uoType, const std::string& spatialMethod, double consTol, double absTol, const int reqBnd, const int useAD) { cadet::IModelBuilder* const mb = cadet::createModelBuilder(); REQUIRE(nullptr != mb); for (int bindingMode = 0; bindingMode < 2; ++bindingMode) { + if ((bindingMode == 0 && reqBnd == 1) || (bindingMode == 1 && reqBnd == 0)) + continue; const bool isKinetic = (bindingMode == 0); for (int adMode = 0; adMode < 2; ++adMode) { + if ((adMode == 0 && useAD == 1) || (adMode == 1 && useAD == 0)) + continue; const bool adEnabled = (adMode > 0); SECTION(std::string(isKinetic ? " Kinetic binding" : " Quasi-stationary binding") + " with AD " + (adEnabled ? "enabled" : "disabled")) { @@ -1454,16 +1462,20 @@ namespace column destroyModelBuilder(mb); } - void testConsistentInitializationSMABinding(const std::string& uoType, const std::string& spatialMethod, double const* const initState, double consTol, double absTol) + void testConsistentInitializationSMABinding(const std::string& uoType, const std::string& spatialMethod, double const* const initState, double consTol, double absTol, const int reqBnd, const int useAD) { cadet::IModelBuilder* const mb = cadet::createModelBuilder(); REQUIRE(nullptr != mb); for (int bindingMode = 0; bindingMode < 2; ++bindingMode) { + if ((bindingMode == 0 && reqBnd == 1) || (bindingMode == 1 && reqBnd == 0)) + continue; const bool isKinetic = (bindingMode == 0); for (int adMode = 0; adMode < 2; ++adMode) { + if ((adMode == 0 && useAD == 1) || (adMode == 1 && useAD == 0)) + continue; const bool adEnabled = (adMode > 0); SECTION(std::string(isKinetic ? " Kinetic binding" : " Quasi-stationary binding") + " with AD " + (adEnabled ? "enabled" : "disabled")) { @@ -1484,16 +1496,20 @@ namespace column destroyModelBuilder(mb); } - void testConsistentInitializationSensitivity(const std::string& uoType, const std::string& spatialMethod, double const* const y, double const* const yDot, bool linearBinding, double absTol) + void testConsistentInitializationSensitivity(const std::string& uoType, const std::string& spatialMethod, double const* const y, double const* const yDot, bool linearBinding, double absTol, const int reqBnd, const int useAD) { cadet::IModelBuilder* const mb = cadet::createModelBuilder(); REQUIRE(nullptr != mb); - for (int bindingMode = 0; bindingMode < 2; ++bindingMode) + for (int bindingMode = 0; bindingMode < 1; ++bindingMode) { + if ((bindingMode == 0 && reqBnd == 1) || (bindingMode == 1 && reqBnd == 0)) + continue; const bool isKinetic = (bindingMode == 0); for (int adMode = 0; adMode < 2; ++adMode) { + if ((adMode == 0 && useAD == 1) || (adMode == 1 && useAD == 0)) + continue; const bool adEnabled = (adMode > 0); SECTION(std::string(isKinetic ? " Kinetic binding" : " Quasi-stationary binding") + " with AD " + (adEnabled ? "enabled" : "disabled")) { @@ -1542,7 +1558,7 @@ namespace column destroyModelBuilder(mb); } - void testReferenceBenchmark(const std::string& modelFileRelPath, const std::string& refFileRelPath, const std::string& unitID, const std::vector absTol, const std::vector relTol, const unsigned int nCol, const unsigned int nPar, const bool compare_sens) + void testReferenceBenchmark(const std::string& modelFileRelPath, const std::string& refFileRelPath, const std::string& unitID, const std::vector absTol, const std::vector relTol, const DiscParams& disc, const bool compare_sens) { const int unitOpID = std::stoi(unitID); @@ -1581,9 +1597,7 @@ namespace column rd.closeFile(); // set remaining spatial numerical parameters - setNumAxialCells(pp_setup, nCol, unitID); - if (nPar > 0) - setNumParCells(pp_setup, nPar, unitID); + disc.setDisc(pp_setup, unitID); // run simulation Driver drv; @@ -1640,7 +1654,7 @@ namespace column } // todo ? include L1 errors or parameterize error choice ? - void testEOCReferenceBenchmark(const std::string& modelFileRelPath, const std::string& refFileRelPath, const std::string& convFileRelPath, const std::string& unitID, const std::vector absTol, const std::vector relTol, const unsigned int nDisc, const unsigned int startNCol, const unsigned int startNPar, const bool compare_sens) + void testEOCReferenceBenchmark(const std::string& modelFileRelPath, const std::string& refFileRelPath, const std::string& convFileRelPath, const std::string& unitID, const std::vector absTol, const std::vector relTol, const unsigned int nDisc, const DiscParams& startDisc, const bool compare_sens) { const int unitOpID = std::stoi(unitID); @@ -1703,6 +1717,8 @@ namespace column pp_conv.pushScope("outlet"); std::vector discZ = pp_conv.getDoubleArray("$N_e^z$"); std::vector discP; + const int startNCol = startDisc.getNAxCells(); + const int startNPar = startDisc.getNParCells(); if (startNPar > 0) discP = pp_conv.getDoubleArray("$N_e^p$"); pp_conv.popScope(); diff --git a/test/ColumnTests.hpp b/test/ColumnTests.hpp index 48ff35007..2219e1197 100644 --- a/test/ColumnTests.hpp +++ b/test/ColumnTests.hpp @@ -33,44 +33,57 @@ namespace test namespace column { struct DiscParams { + int nAxCells; + int nParCells; + virtual ~DiscParams() = default; - virtual void setDisc(JsonParameterProvider& jpp) const = 0; + + virtual int getNAxCells() const = 0; + virtual int getNParCells() const = 0; + + virtual void setDisc(JsonParameterProvider& jpp, const std::string unitID = "000") const = 0; }; struct FVparams : public DiscParams { - int nCol; + int nAxCells; + int nParCells; int wenoOrder; - int nPar; - FVparams() : nCol(0), wenoOrder(0), nPar(0) {} + FVparams() : nAxCells(0), nParCells(0), wenoOrder(0) {} FVparams(int nCol) - : nCol(nCol), wenoOrder(0), nPar(0) {} - FVparams(int nCol, int wenoOrder) - : nCol(nCol), wenoOrder(wenoOrder), nPar(0) {} - FVparams(int nCol, int wenoOrder, int nPar) - : nCol(nCol), wenoOrder(wenoOrder), nPar(nPar) {} - + : nAxCells(nCol), nParCells(0), wenoOrder(0) {} + FVparams(int nCol, int nPar) + : nAxCells(nCol), nParCells(nPar), wenoOrder(0) {} + FVparams(int nCol, int nPar, int wenoOrder) + : nAxCells(nCol), nParCells(nPar), wenoOrder(wenoOrder) {} + + int getNAxCells() const override { return nAxCells; } + int getNParCells() const override { return nParCells; } void setWenoOrder(int order) { wenoOrder = order; } int getWenoOrder() { return wenoOrder; } - void setDisc(JsonParameterProvider& jpp) const override; + void setDisc(JsonParameterProvider& jpp, const std::string unitID = "000") const override; }; struct DGparams : public DiscParams { + int nAxCells; + int nParCells; int exactIntegration; int polyDeg; int nElem; int parPolyDeg; int parNelem; - DGparams() : exactIntegration(-1), polyDeg(0), nElem(0), parPolyDeg(0), parNelem(0) {} + DGparams() : exactIntegration(-1), polyDeg(0), nAxCells(0), parPolyDeg(0), nParCells(0) {} DGparams(int exact, int poly, int elem) - : exactIntegration(exact), polyDeg(poly), nElem(elem), parPolyDeg(0), parNelem(0) {} + : exactIntegration(exact), polyDeg(poly), nAxCells(elem), parPolyDeg(0), nParCells(0) {} DGparams(int exact, int poly, int elem, int parPolyDeg, int parNelem) - : exactIntegration(exact), polyDeg(poly), nElem(elem), parPolyDeg(parPolyDeg), parNelem(parNelem) {} + : exactIntegration(exact), polyDeg(poly), nAxCells(elem), parPolyDeg(parPolyDeg), nParCells(parNelem) {} + int getNAxCells() const override { return nAxCells; } + int getNParCells() const override { return nParCells; } void setIntegrationMode(int integrationMode) { exactIntegration = integrationMode; } int getIntegrationMode() { return exactIntegration; } - void setDisc(JsonParameterProvider& jpp) const override; + void setDisc(JsonParameterProvider& jpp, const std::string unitID = "000") const override; }; /** @@ -182,10 +195,11 @@ namespace column * * @param [in] uoType Unit operation type * @param [in] disc spatial discretization parameters + * @param [in] absTolFDpattern absolute tolerance when comparing the sign in the FD Jacobian pattern */ - void testJacobianForwardBackward(const char* uoType, FVparams disc); - void testJacobianForwardBackward(const char* uoType, DGparams disc); - void testJacobianForwardBackward(cadet::JsonParameterProvider& jpp); + void testJacobianForwardBackward(const char* uoType, FVparams disc, const double absTolFDpattern = 0.0); + void testJacobianForwardBackward(const char* uoType, DGparams disc, const double absTolFDpattern = 0.0); + void testJacobianForwardBackward(cadet::JsonParameterProvider& jpp, const double absTolFDpattern = 0.0); /** * @brief Checks the full Jacobian against FD switching from forward to backward flow and back @@ -299,8 +313,10 @@ namespace column * @param [in] uoType Unit operation type * @param [in] consTol Error tolerance for consistent initialization solver * @param [in] absTol Error tolerance for checking whether algebraic residual is 0 + * @param [in] reqBnd specifies binding mode, defaults to using both kinetic and equilibrium + * @param [in] useAD specifies Jacobian mode, defaults to using both analytical and AD */ - void testConsistentInitializationLinearBinding(const std::string& uoType, const std::string& spatialMethod, double consTol, double absTol); + void testConsistentInitializationLinearBinding(const std::string& uoType, const std::string& spatialMethod, double consTol, double absTol, const int reqBnd = -1, const int useAD = -1); /** * @brief Checks consistent initialization using a model with SMA binding @@ -310,8 +326,10 @@ namespace column * @param [in] initState Initial state vector to start process from * @param [in] consTol Error tolerance for consistent initialization solver * @param [in] absTol Error tolerance for checking whether algebraic residual is 0 + * @param [in] reqBnd specifies binding mode, defaults to using both kinetic and equilibrium + * @param [in] useAD specifies Jacobian mode, defaults to using both analytical and AD */ - void testConsistentInitializationSMABinding(const std::string& uoType, const std::string& spatialMethod, double const* const initState, double consTol, double absTol); + void testConsistentInitializationSMABinding(const std::string& uoType, const std::string& spatialMethod, double const* const initState, double consTol, double absTol, const int reqBnd = -1, const int useAD = -1); /** * @brief Checks consistent initialization of sensitivities in a column-like model @@ -322,8 +340,10 @@ namespace column * @param [in] yDot Time derivative of state vector of original system * @param [in] linearBinding Determines whether linear binding or SMA binding model is used * @param [in] absTol Error tolerance for checking whether sensitivity residual is 0 + * @param [in] reqBnd specifies binding mode, defaults to using both kinetic and equilibrium + * @param [in] useAD specifies Jacobian mode, defaults to using both analytical and AD */ - void testConsistentInitializationSensitivity(const std::string& uoType, const std::string& spatialMethod, double const* const y, double const* const yDot, bool linearBinding, double absTol); + void testConsistentInitializationSensitivity(const std::string& uoType, const std::string& spatialMethod, double const* const y, double const* const yDot, bool linearBinding, double absTol, const int reqBnd = -1, const int useAD = -1); /** * @brief Checks whether the inlet DOFs produce the identity matrix in the Jacobian of the unit operation @@ -339,11 +359,10 @@ namespace column * @param [in] unitID ID of the unit of interest * @param [in] absTol Absolute error tolerance * @param [in] relTol Relative error tolerance - * @param [in] nCol Number of axial cells - * @param [in] nPar Number of particle cells (if required) + * @param [in] disc Numerical discretization parameters * @param [in] compare_sens Specifies whether sensitivities are included */ - void testReferenceBenchmark(const std::string& modelFileRelPath, const std::string& refFileRelPath, const std::string& unitID, const std::vector absTol, const std::vector relTol, const unsigned int nCol, const unsigned int nPar = 0, const bool compare_sens = false); + void testReferenceBenchmark(const std::string& modelFileRelPath, const std::string& refFileRelPath, const std::string& unitID, const std::vector absTol, const std::vector relTol, const cadet::test::column::DiscParams& disc, const bool compare_sens = false); /** * @brief Runs an EOC test comparing against numerical reference data (outlet data) @@ -354,11 +373,10 @@ namespace column * @param [in] absTol Absolute error tolerance * @param [in] relTol Relative error tolerance * @param [in] nDisc number of discretizations to be computed for EOC - * @param [in] startNCol starting number of axial cells - * @param [in] startNPar starting number of particle cells (if required) + * @param [in] disc Numerical discretization parameters with starting resolution * @param [in] compare_sens Specifies whether sensitivities are included */ - void testEOCReferenceBenchmark(const std::string& modelFileRelPath, const std::string& refFileRelPath, const std::string& convFileRelPath, const std::string& unitID, const std::vector absTol, const std::vector relTol, const unsigned int nDisc, const unsigned int startNCol, const unsigned int startNPar = 0, const bool compare_sens = false); + void testEOCReferenceBenchmark(const std::string& modelFileRelPath, const std::string& refFileRelPath, const std::string& convFileRelPath, const std::string& unitID, const std::vector absTol, const std::vector relTol, const unsigned int nDisc, const cadet::test::column::DiscParams& disc, const bool compare_sens = false); } // namespace column } // namespace test diff --git a/test/GeneralRateModel.cpp b/test/GeneralRateModel.cpp index 5845045fa..6cef5db52 100644 --- a/test/GeneralRateModel.cpp +++ b/test/GeneralRateModel.cpp @@ -59,42 +59,50 @@ TEST_CASE("GRM Jacobian forward vs backward flow", "[GRM],[FV],[UnitOp],[Residua } } -TEST_CASE("GRM numerical Benchmark with parameter sensitivities for linear case", "[GRM],[FV],[Simulation],[Reference],[Sensitivity]") // todo CI flag: currently only runs locally but fails on server +TEST_CASE("GRM numerical Benchmark with parameter sensitivities for linear case", "[GRM],[FV],[Simulation],[Reference],[Sensitivity],[dddff]") // todo CI flag: currently only runs locally but fails on server { const std::string& modelFilePath = std::string("/data/model_GRM_dynLin_1comp_benchmark1.json"); const std::string& refFilePath = std::string("/data/ref_GRM_dynLin_1comp_sensbenchmark1_FV_Z32parZ4.h5"); const std::vector absTol = { 1e-12, 1e-12, 1e-12, 1e-12 }; - const std::vector relTol = { 1.0, 1.0, 1.0, 1.0 }; - cadet::test::column::testReferenceBenchmark(modelFilePath, refFilePath, "001", absTol, relTol, 32, 4, true); + const std::vector relTol = { 1e-4, 1e-4, 1e-4, 1e-4 }; + + cadet::test::column::FVparams disc(32, 4); + cadet::test::column::testReferenceBenchmark(modelFilePath, refFilePath, "001", absTol, relTol, disc, true); } -TEST_CASE("GRM numerical Benchmark with parameter sensitivities for SMA LWE case", "[GRM],[FV],[Simulation],[Reference],[Sensitivity]") // todo CI flag: currently only runs locally but fails on server +TEST_CASE("GRM numerical Benchmark with parameter sensitivities for SMA LWE case", "[GRM],[FV],[Simulation],[Reference],[Sensitivity],[dddff]") // todo CI flag: currently only runs locally but fails on server { const std::string& modelFilePath = std::string("/data/model_GRM_reqSMA_4comp_benchmark1.json"); const std::string& refFilePath = std::string("/data/ref_GRM_reqSMA_4comp_sensbenchmark1_FV_Z16parZ2.h5"); const std::vector absTol = { 1e-12, 1e-12, 1e-12, 1e-12 }; - const std::vector relTol = { 1.0, 1.0, 1.0, 1.0 }; - cadet::test::column::testReferenceBenchmark(modelFilePath, refFilePath, "000", absTol, relTol, 16, 2, true); + const std::vector relTol = { 1e-4, 1e-4, 1e-4, 1e-4 }; + + cadet::test::column::FVparams disc(16, 2); + cadet::test::column::testReferenceBenchmark(modelFilePath, refFilePath, "000", absTol, relTol, disc, true); } -TEST_CASE("GRM numerical EOC Benchmark with parameter sensitivities for linear case", "[GRM],[FV],[releaseCI],[EOC],[EOC_GRM_FV]") +TEST_CASE("GRM numerical EOC Benchmark with parameter sensitivities for linear case", "[GRM],[FV],[releaseCI],[EOC],[EOC_GRM_FV],[dddff]") { const std::string& modelFilePath = std::string("/data/model_GRM_dynLin_1comp_benchmark1.json"); const std::string& refFilePath = std::string("/data/ref_GRM_dynLin_1comp_sensbenchmark1_FV_Z1024parZ128.h5"); const std::string& convFilePath = std::string("/data/convergence_GRM_dynLin_1comp_sensbenchmark1.json"); const std::vector absTol = { 1e-12, 1e-12, 1e-12, 1e-12 }; - const std::vector relTol = { 1.0, 1.0, 1.0, 1.0 }; - cadet::test::column::testEOCReferenceBenchmark(modelFilePath, refFilePath, convFilePath, "001", absTol, relTol, 3, 8, 1, true); + const std::vector relTol = { 1e-4, 1e-4, 1e-4, 1e-4 }; + + cadet::test::column::FVparams disc(8, 1); + cadet::test::column::testEOCReferenceBenchmark(modelFilePath, refFilePath, convFilePath, "001", absTol, relTol, 3, disc, true); } -TEST_CASE("GRM numerical EOC Benchmark with parameter sensitivities for SMA LWE case", "[GRM],[FV],[releaseCI],[EOC],[EOC_GRM_FV]") +TEST_CASE("GRM numerical EOC Benchmark with parameter sensitivities for SMA LWE case", "[GRM],[FV],[releaseCI],[EOC],[EOC_GRM_FV],[dddff]") { const std::string& modelFilePath = std::string("/data/model_GRM_reqSMA_4comp_benchmark1.json"); const std::string& refFilePath = std::string("/data/ref_GRM_reqSMA_4comp_sensbenchmark1_FV_Z512parZ64.h5"); const std::string& convFilePath = std::string("/data/convergence_GRM_reqSMA_4comp_sensbenchmark1.json"); const std::vector absTol = { 1e-12, 1e-12, 1e-12, 1e-12 }; - const std::vector relTol = { 1.0, 1.0, 1.0, 1.0 }; - cadet::test::column::testEOCReferenceBenchmark(modelFilePath, refFilePath, convFilePath, "000", absTol, relTol, 2, 8, 1, true); + const std::vector relTol = { 1e-4, 1e-4, 1e-4, 1e-4 }; + + cadet::test::column::FVparams disc(8, 1); + cadet::test::column::testEOCReferenceBenchmark(modelFilePath, refFilePath, convFilePath, "000", absTol, relTol, 2, disc, true); } TEST_CASE("GRM time derivative Jacobian vs FD", "[GRM],[FV],[UnitOp],[Residual],[Jacobian],[CI],[FD]") diff --git a/test/GeneralRateModelDG.cpp b/test/GeneralRateModelDG.cpp new file mode 100644 index 000000000..77cf319c3 --- /dev/null +++ b/test/GeneralRateModelDG.cpp @@ -0,0 +1,405 @@ +// ============================================================================= +// CADET +// +// Copyright © 2008-2023: The CADET Authors +// Please see the AUTHORS and CONTRIBUTORS file. +// +// All rights reserved. This program and the accompanying materials +// are made available under the terms of the GNU Public License v3.0 (or, at +// your option, any later version) which accompanies this distribution, and +// is available at http://www.gnu.org/licenses/gpl.html +// ============================================================================= + +#include +#include "Approx.hpp" + +#define CADET_LOGGING_DISABLE +#include "Logging.hpp" + +#include "ColumnTests.hpp" +#include "ParticleHelper.hpp" +#include "ReactionModelTests.hpp" +#include "JsonTestModels.hpp" +#include "Utils.hpp" +#include "common/Driver.hpp" + +TEST_CASE("GRM_DG LWE forward vs backward flow", "[GRM],[DG],[Simulation],[CI]") +{ + cadet::test::column::DGparams disc; + + // Test all integration modes + for (int i = 0; i <= 1; i++) + { + disc.setIntegrationMode(i); + cadet::test::column::testForwardBackward("GENERAL_RATE_MODEL", disc, 1e-9, 2e-4); + } +} + +TEST_CASE("GRM_DG linear pulse vs analytic solution", "[GRM],[DG],[Simulation],[Analytic],[CI]") +{ + cadet::test::column::DGparams disc; + cadet::test::column::testAnalyticBenchmark("GENERAL_RATE_MODEL", "/data/grm-pulseBenchmark.data", true, true, disc, 6e-5, 1e-7); + cadet::test::column::testAnalyticBenchmark("GENERAL_RATE_MODEL", "/data/grm-pulseBenchmark.data", true, false, disc, 6e-5, 1e-7); + cadet::test::column::testAnalyticBenchmark("GENERAL_RATE_MODEL", "/data/grm-pulseBenchmark.data", false, true, disc, 6e-5, 1e-7); + cadet::test::column::testAnalyticBenchmark("GENERAL_RATE_MODEL", "/data/grm-pulseBenchmark.data", false, false, disc, 6e-5, 1e-7); +} + +TEST_CASE("GRM_DG non-binding linear pulse vs analytic solution", "[GRM],[DG],[Simulation],[Analytic],[NonBinding],[CI]") +{ + cadet::test::column::DGparams disc; + cadet::test::column::testAnalyticNonBindingBenchmark("GENERAL_RATE_MODEL", "/data/grm-nonBinding.data", true, disc, 6e-5, 1e-7); + cadet::test::column::testAnalyticNonBindingBenchmark("GENERAL_RATE_MODEL", "/data/grm-nonBinding.data", false, disc, 6e-5, 1e-7); +} + +// todo FIX (scheitert bei backward flow jacobian vs AD) +//TEST_CASE("GRM_DG Jacobian forward vs backward flow", "[GRM],[DG],[UnitOp],[Residual],[Jacobian],[AD],[todo]") +//{ +// cadet::test::column::DGparams disc; +// +// // Test all integration modes +// for (int i = 0; i <= 1; i++) +// { +// disc.setIntegrationMode(i); +// cadet::test::column::testJacobianForwardBackward("GENERAL_RATE_MODEL", disc, std::numeric_limits::epsilon() * 100.0); +// } +//} + +TEST_CASE("GRM_DG numerical Benchmark with parameter sensitivities for linear case", "[GRM],[DG],[Simulation],[Reference],[Sensitivity]") // todo CI flag: currently only runs locally but fails on server +{ + const std::string& modelFilePath = std::string("/data/model_GRM_dynLin_1comp_benchmark1.json"); + const std::string& refFilePath = std::string("/data/ref_GRM_dynLin_1comp_sensbenchmark1_cDG_P3Z8_GSM_parP3parZ1.h5"); + const std::vector absTol = { 1e-12, 1e-12, 1e-12, 1e-12 }; + const std::vector relTol = { 1.0, 1.0, 1.0, 1.0 }; + + cadet::test::column::DGparams disc(0, 3, 8, 3, 1); + cadet::test::column::testReferenceBenchmark(modelFilePath, refFilePath, "001", absTol, relTol, disc, true); +} + +TEST_CASE("GRM_DG numerical Benchmark with parameter sensitivities for SMA LWE case", "[GRM],[DG],[Simulation],[Reference],[Sensitivity]") // todo CI flag: currently only runs locally but fails on server +{ + const std::string& modelFilePath = std::string("/data/model_GRM_reqSMA_4comp_benchmark1.json"); + const std::string& refFilePath = std::string("/data/ref_GRM_reqSMA_4comp_sensbenchmark1_cDG_P3Z8_GSM_parP3parZ1.h5"); + const std::vector absTol = { 1e-12, 1e-12, 1e-12, 1e-12 }; + const std::vector relTol = { 1.0, 1.0, 1.0, 1.0 }; + + cadet::test::column::DGparams disc(0, 3, 8, 3, 1); + cadet::test::column::testReferenceBenchmark(modelFilePath, refFilePath, "000", absTol, relTol, disc, true); +} + +TEST_CASE("GRM_DG LWE DGSEM and GSM particle discretization yields similar accuracy", "[GRM],[DG],[Simulation],[CI]") +{ + cadet::JsonParameterProvider jpp = createLWE("GENERAL_RATE_MODEL", "DG"); + cadet::test::column::DGparams disc(0, 4, 2, 3, 1); // Note that we want to employ only a single particle element + disc.setDisc(jpp); + + const double absTol = 1e-9; + const double relTol = 2e-4; + + // GSM discretization + cadet::Driver drvGSM; + drvGSM.configure(jpp); + drvGSM.run(); + + // Force single element DGSEM discretization (GSM is default for single particle element discretization) + jpp.pushScope("model"); + jpp.pushScope("unit_000"); + jpp.pushScope("discretization"); + jpp.set("PAR_GSM", false); + jpp.popScope(); + jpp.popScope(); + jpp.popScope(); + + cadet::Driver drvDGSEM; + drvDGSEM.configure(jpp); + drvDGSEM.run(); + + cadet::InternalStorageUnitOpRecorder const* const GSMData = drvGSM.solution()->unitOperation(0); + cadet::InternalStorageUnitOpRecorder const* const DGSEMData = drvDGSEM.solution()->unitOperation(0); + + double const* GSMOutlet = GSMData->outlet(); + double const* DGSEMOutlet = DGSEMData->outlet(); + + const unsigned int nComp = GSMData->numComponents(); + for (unsigned int i = 0; i < GSMData->numDataPoints() * GSMData->numInletPorts() * nComp; ++i, ++GSMOutlet, ++DGSEMOutlet) + { + // Forward flow inlet = backward flow outlet + CAPTURE(i); + CHECK((*GSMOutlet) == cadet::test::makeApprox(*DGSEMOutlet, relTol, absTol)); + } +} + +TEST_CASE("GRM_DG time derivative Jacobian vs FD", "[GRM],[DG],[UnitOp],[Residual],[Jacobian],[CI],[FD]") +{ + cadet::test::column::testTimeDerivativeJacobianFD("GENERAL_RATE_MODEL", "DG", 1e-6, 0.0, 9e-4); +} + +//TEST_CASE("GRM_DG dynamic binding with surf diff par dep Jacobian vs AD", "[GRM],[DG],[UnitOp],[Residual],[Jacobian],[ParameterDependence],[fix]") +//{ +// cadet::test::column::testJacobianADVariableParSurfDiff("GENERAL_RATE_MODEL", "DG", true); +//} + +TEST_CASE("GRM_DG rapid-equilibrium binding with surf diff par dep Jacobian vs AD", "[GRM],[DG],[UnitOp],[Residual],[Jacobian],[ParameterDependence]") // todo include in CI (runs locally but fails on server with linux) +{ + cadet::test::column::testJacobianADVariableParSurfDiff("GENERAL_RATE_MODEL", "DG", false); +} + +TEST_CASE("GRM_DG sensitivity Jacobians", "[GRM],[DG],[UnitOp],[Sensitivity]") // todo does not run on CI but locally on windows +{ + cadet::test::column::testFwdSensJacobians("GENERAL_RATE_MODEL", "DG", 1e-4, 6e-7); +} + +//// todo fix: not just adjust tolerances as in FV but theres an actual error here: access violation in densematrix +//TEST_CASE("GRM_DG forward sensitivity vs FD", "[GRM],[DG],[Sensitivity],[Simulation],[todo]") +//{ +// // Relative error is checked first, we use high absolute error for letting +// // some points that are far off pass the error test, too. This is required +// // due to errors in finite differences. +// const double fdStepSize[] = { 5e-5, 1e-4, 1e-4, 1e-3 }; +// const double absTols[] = { 3e5, 2e-3, 2e-4, 5.0 }; +// const double relTols[] = { 5e-3, 7e-2, 8e-2, 1e-4 }; +// const double passRatio[] = { 0.95, 0.9, 0.91, 0.83 }; +// cadet::test::column::testFwdSensSolutionFD("GENERAL_RATE_MODEL", "DG", false, fdStepSize, absTols, relTols, passRatio); +//} + +//// todo fix: not just adjust tolerances as in FV but theres an actual error here: access violation in densematrix +//TEST_CASE("GRM_DG forward sensitivity forward vs backward flow", "[GRM],[DG],[Sensitivity],[Simulation],[todo]") +//{ +// const double absTols[] = { 4e-5, 1e-11, 1e-11, 8e-9 }; +// const double relTols[] = { 6e-9, 5e-8, 5e-6, 5e-10 }; +// const double passRatio[] = { 0.99, 0.95, 0.98, 0.98 }; +// cadet::test::column::testFwdSensSolutionForwardBackward("GENERAL_RATE_MODEL", "DG", absTols, relTols, passRatio); +//} + +// todo fix consistent initialization for AD with req binding +TEST_CASE("GRM_DG consistent initialization with linear binding", "[GRM],[DG],[ConsistentInit],[CI]") +{ + cadet::test::column::testConsistentInitializationLinearBinding("GENERAL_RATE_MODEL", "DG", 1e-12, 1e-14, 0, 0); + cadet::test::column::testConsistentInitializationLinearBinding("GENERAL_RATE_MODEL", "DG", 1e-12, 1e-12, 1, 0); + cadet::test::column::testConsistentInitializationLinearBinding("GENERAL_RATE_MODEL", "DG", 1e-12, 1e-14, 0, 1); + //cadet::test::column::testConsistentInitializationLinearBinding("GENERAL_RATE_MODEL", "DG", 1e-12, 1e-14, 1, 1); +} + +//// todo fix consistent initialization for SMA (initialization not completely correct; AD gives assertion error) +//TEST_CASE("GRM_DG consistent initialization with SMA binding", "[GRM],[DG],[ConsistentInit],[todo]") +//{ +// std::vector y(4 + 4 * 16 + 16 * 4 * (4 + 4) + 4 * 16, 0.0); +// // Optimal values: +// // const double bindingCell[] = {1.2, 2.0, 1.0, 1.5, 858.034, 66.7896, 3.53273, 2.53153, +// // 1.0, 1.8, 1.5, 1.6, 856.173, 64.457, 5.73227, 2.85286}; +// const double bindingCell[] = { 1.2, 2.0, 1.0, 1.5, 840.0, 63.0, 3.0, 3.0, +// 1.0, 1.8, 1.5, 1.6, 840.0, 63.0, 6.0, 3.0 }; +// cadet::test::util::populate(y.data(), [](unsigned int idx) { return std::abs(std::sin(idx * 0.13)) + 1e-4; }, 4 + 4 * 16); +// cadet::test::util::repeat(y.data() + 4 + 4 * 16, bindingCell, 16, 4 * 16 / 2); +// cadet::test::util::populate(y.data() + 4 + 4 * 16 + 16 * 4 * (4 + 4), [](unsigned int idx) { return std::abs(std::sin(idx * 0.13)) + 1e-4; }, 4 * 16); +// +// cadet::test::column::testConsistentInitializationSMABinding("GENERAL_RATE_MODEL", "DG", y.data(), 1e-14, 1e-5); +//} + +// todo fix kinetic binding sensitivity init +TEST_CASE("GRM_DG consistent sensitivity initialization with linear binding", "[GRM],[DG],[ConsistentInit],[Sensitivity],[CI]") +{ + // Fill state vector with given initial values + const unsigned int numDofs = 4 + 4 * 16 + 16 * 4 * (4 + 4) + 4 * 16; + std::vector y(numDofs, 0.0); + std::vector yDot(numDofs, 0.0); + cadet::test::util::populate(y.data(), [](unsigned int idx) { return std::abs(std::sin(idx * 0.13)) + 1e-4; }, numDofs); + cadet::test::util::populate(yDot.data(), [](unsigned int idx) { return std::abs(std::sin(idx * 0.9)) + 1e-4; }, numDofs); + + //cadet::test::column::testConsistentInitializationSensitivity("GENERAL_RATE_MODEL", "DG", y.data(), yDot.data(), true, 1e-14, 0, 0); + cadet::test::column::testConsistentInitializationSensitivity("GENERAL_RATE_MODEL", "DG", y.data(), yDot.data(), true, 1e-14, 1, 0); + //cadet::test::column::testConsistentInitializationSensitivity("GENERAL_RATE_MODEL", "DG", y.data(), yDot.data(), true, 1e-14, 0, 1); + cadet::test::column::testConsistentInitializationSensitivity("GENERAL_RATE_MODEL", "DG", y.data(), yDot.data(), true, 1e-14, 1, 1); +} + +//// todo fix memory stuff (works for FV) +//TEST_CASE("GRM_DG consistent sensitivity initialization with SMA binding", "[GRM],[DG],[ConsistentInit],[Sensitivity],[fffffffiujbnlk]") +//{ +// // Fill state vector with given initial values +// const unsigned int numDofs = 4 + 4 * 16 + 16 * 4 * (4 + 4) + 4 * 16; +// std::vector y(numDofs, 0.0); +// std::vector yDot(numDofs, 0.0); +// +// const double bindingCell[] = { 1.0, 1.8, 1.5, 1.6, 840.0, 63.0, 6.0, 3.0 }; +// cadet::test::util::populate(y.data(), [](unsigned int idx) { return std::abs(std::sin(idx * 0.13)) + 1e-4; }, 4 + 4 * 16); +// cadet::test::util::repeat(y.data() + 4 + 4 * 16, bindingCell, 8, 4 * 16); +// cadet::test::util::populate(y.data() + 4 + 4 * 16 + 16 * 4 * (4 + 4), [](unsigned int idx) { return std::abs(std::sin(idx * 0.13)) + 1e-4; }, 4 * 16); +// +// cadet::test::util::populate(yDot.data(), [](unsigned int idx) { return std::abs(std::sin(idx * 0.9)) + 1e-4; }, numDofs); +// +// cadet::test::column::testConsistentInitializationSensitivity("GENERAL_RATE_MODEL", "DG", y.data(), yDot.data(), false, 1e-9); +//} + +TEST_CASE("GRM_DG inlet DOF Jacobian", "[GRM],[DG],[UnitOp],[Jacobian],[Inlet],[CI]") +{ + cadet::test::column::testInletDofJacobian("GENERAL_RATE_MODEL", "DG"); +} + +TEST_CASE("GRM_DG transport Jacobian", "[GRM],[DG],[UnitOp],[Jacobian],[CI]") +{ + cadet::JsonParameterProvider jpp = createColumnLinearBenchmark(false, true, "GENERAL_RATE_MODEL", "DG"); + cadet::test::column::testJacobianAD(jpp, std::numeric_limits::epsilon() * 100.0); +} + +TEST_CASE("GRM_DG with two component linear binding Jacobian", "[GRM],[DG],[UnitOp],[Jacobian],[CI]") +{ + cadet::JsonParameterProvider jpp = createColumnWithTwoCompLinearBinding("GENERAL_RATE_MODEL", "DG"); + cadet::test::column::testJacobianAD(jpp, std::numeric_limits::epsilon() * 100.0); +} + +//// todo fix cant load library with debug info +//TEST_CASE("GRM_DG LWE one vs two identical particle types match", "[GRM],[DG],[Simulation],[ParticleType],[todo]") +//{ +// cadet::test::particle::testOneVsTwoIdenticalParticleTypes("GENERAL_RATE_MODEL", "DG", 2e-8, 5e-5); +//} + +//// todo fix cant load library with debug info in all of the following tests +//TEST_CASE("GRM_DG LWE separate identical particle types match", "[GRM],[DG],[Simulation],[ParticleType],[todo]") +//{ +// cadet::test::particle::testSeparateIdenticalParticleTypes("GENERAL_RATE_MODEL", "DG", 1e-15, 1e-15); +//} +// +//TEST_CASE("GRM_DG linear binding single particle matches particle distribution", "[GRM],[DG],[Simulation],[ParticleType],[todo]") +//{ +// cadet::test::particle::testLinearMixedParticleTypes("GENERAL_RATE_MODEL", "DG", 5e-8, 5e-5); +//} +// +//TEST_CASE("GRM_DG multiple particle types Jacobian analytic vs AD", "[GRM],[DG],[Jacobian],[AD],[ParticleType],[todo]") +//{ +// cadet::test::particle::testJacobianMixedParticleTypes("GENERAL_RATE_MODEL", "DG"); +//} +// +//TEST_CASE("GRM_DG multiple particle types time derivative Jacobian vs FD", "[GRM],[DG],[UnitOp],[Residual],[Jacobian],[ParticleType],[todo]") +//{ +// cadet::test::particle::testTimeDerivativeJacobianMixedParticleTypesFD("GENERAL_RATE_MODEL", "DG", 1e-6, 0.0, 9e-4); +//} +// +//TEST_CASE("GRM_DG multiple spatially dependent particle types Jacobian analytic vs AD", "[GRM],[DG],[Jacobian],[AD],[ParticleType],[todo]") +//{ +// cadet::test::particle::testJacobianSpatiallyMixedParticleTypes("GENERAL_RATE_MODEL", "DG"); +//} +// +//TEST_CASE("GRM_DG linear binding single particle matches spatially dependent particle distribution", "[GRM],[DG],[Simulation],[ParticleType],[todo]") +//{ +// cadet::test::particle::testLinearSpatiallyMixedParticleTypes("GENERAL_RATE_MODEL", "DG", 5e-8, 5e-5); +//} + +TEST_CASE("GRM_DG dynamic reactions Jacobian vs AD bulk", "[GRM],[DG],[Jacobian],[AD],[ReactionModel],[CI]") +{ + cadet::test::reaction::testUnitJacobianDynamicReactionsAD("GENERAL_RATE_MODEL", "DG", true, false, false); +} + +TEST_CASE("GRM_DG dynamic reactions Jacobian vs AD particle", "[GRM],[DG],[Jacobian],[AD],[ReactionModel],[CI]") +{ + cadet::test::reaction::testUnitJacobianDynamicReactionsAD("GENERAL_RATE_MODEL", "DG", false, true, false); +} + +TEST_CASE("GRM_DG dynamic reactions Jacobian vs AD modified particle", "[GRM],[DG],[Jacobian],[AD],[ReactionModel],[CI]") +{ + cadet::test::reaction::testUnitJacobianDynamicReactionsAD("GENERAL_RATE_MODEL", "DG", false, true, true); +} + +TEST_CASE("GRM_DG dynamic reactions Jacobian vs AD bulk and particle", "[GRM],[DG],[Jacobian],[AD],[ReactionModel],[CI]") +{ + cadet::test::reaction::testUnitJacobianDynamicReactionsAD("GENERAL_RATE_MODEL", "DG", true, true, false); +} + +TEST_CASE("GRM_DG dynamic reactions Jacobian vs AD bulk and modified particle", "[GRM],[DG],[Jacobian],[AD],[ReactionModel],[CI]") +{ + cadet::test::reaction::testUnitJacobianDynamicReactionsAD("GENERAL_RATE_MODEL", "DG", true, true, true); +} + +TEST_CASE("GRM_DG dynamic reactions time derivative Jacobian vs FD bulk", "[GRM],[DG],[Jacobian],[Residual],[ReactionModel],[CI],[FD]") +{ + cadet::test::reaction::testTimeDerivativeJacobianDynamicReactionsFD("GENERAL_RATE_MODEL", "DG", true, false, false, 1e-6, 1e-14, 9e-4); +} + +TEST_CASE("GRM_DG dynamic reactions time derivative Jacobian vs FD particle", "[GRM],[DG],[Jacobian],[Residual],[ReactionModel],[CI],[FD]") +{ + cadet::test::reaction::testTimeDerivativeJacobianDynamicReactionsFD("GENERAL_RATE_MODEL", "DG", false, true, false, 1e-6, 1e-14, 9e-4); +} + +TEST_CASE("GRM_DG dynamic reactions time derivative Jacobian vs FD modified particle", "[GRM],[DG],[Jacobian],[Residual],[ReactionModel],[CI],[FD]") +{ + cadet::test::reaction::testTimeDerivativeJacobianDynamicReactionsFD("GENERAL_RATE_MODEL", "DG", false, true, true, 1e-6, 1e-14, 9e-4); +} + +TEST_CASE("GRM_DG dynamic reactions time derivative Jacobian vs FD bulk and particle", "[GRM],[DG],[Jacobian],[Residual],[ReactionModel],[CI],[FD]") +{ + cadet::test::reaction::testTimeDerivativeJacobianDynamicReactionsFD("GENERAL_RATE_MODEL", "DG", true, true, false, 1e-6, 1e-14, 9e-4); +} + +TEST_CASE("GRM_DG dynamic reactions time derivative Jacobian vs FD bulk and modified particle", "[GRM],[DG],[Jacobian],[Residual],[ReactionModel],[CI],[FD]") +{ + cadet::test::reaction::testTimeDerivativeJacobianDynamicReactionsFD("GENERAL_RATE_MODEL", "DG", true, true, true, 1e-6, 1e-14, 9e-4); +} + +inline cadet::JsonParameterProvider createColumnWithTwoCompLinearBindingThreeParticleTypes() +{ + cadet::JsonParameterProvider jpp = createColumnWithTwoCompLinearBinding("GENERAL_RATE_MODEL", "DG"); + + const double parVolFrac[] = { 0.3, 0.6, 0.1 }; + const double parFactor[] = { 0.9, 0.8 }; + cadet::test::particle::extendModelToManyParticleTypes(jpp, 3, parFactor, parVolFrac); + + return jpp; +} + +TEST_CASE("GRM_DG multi particle types dynamic reactions Jacobian vs AD bulk", "[GRM],[DG],[Jacobian],[AD],[ReactionModel],[ParticleType],[CI]") +{ + cadet::JsonParameterProvider jpp = createColumnWithTwoCompLinearBindingThreeParticleTypes(); + cadet::test::reaction::testUnitJacobianDynamicReactionsAD(jpp, true, false, false); +} + +TEST_CASE("GRM_DG multi particle types dynamic reactions Jacobian vs AD particle", "[GRM],[DG],[Jacobian],[AD],[ReactionModel],[ParticleType],[CI]") +{ + cadet::JsonParameterProvider jpp = createColumnWithTwoCompLinearBindingThreeParticleTypes(); + cadet::test::reaction::testUnitJacobianDynamicReactionsAD(jpp, false, true, false); +} + +TEST_CASE("GRM_DG multi particle types dynamic reactions Jacobian vs AD modified particle", "[GRM],[DG],[Jacobian],[AD],[ReactionModel],[ParticleType],[CI]") +{ + cadet::JsonParameterProvider jpp = createColumnWithTwoCompLinearBindingThreeParticleTypes(); + cadet::test::reaction::testUnitJacobianDynamicReactionsAD(jpp, false, true, true); +} + +TEST_CASE("GRM_DG multi particle types dynamic reactions Jacobian vs AD bulk and particle", "[GRM],[DG],[Jacobian],[AD],[ReactionModel],[ParticleType],[CI]") +{ + cadet::JsonParameterProvider jpp = createColumnWithTwoCompLinearBindingThreeParticleTypes(); + cadet::test::reaction::testUnitJacobianDynamicReactionsAD(jpp, true, true, false); +} + +TEST_CASE("GRM_DG multi particle types dynamic reactions Jacobian vs AD bulk and modified particle", "[GRM],[DG],[Jacobian],[AD],[ReactionModel],[ParticleType],[CI]") +{ + cadet::JsonParameterProvider jpp = createColumnWithTwoCompLinearBindingThreeParticleTypes(); + cadet::test::reaction::testUnitJacobianDynamicReactionsAD(jpp, true, true, true); +} + +TEST_CASE("GRM_DG multi particle types dynamic reactions time derivative Jacobian vs FD bulk", "[GRM],[DG],[Jacobian],[Residual],[ReactionModel],[ParticleType],[CI]") +{ + cadet::JsonParameterProvider jpp = createColumnWithTwoCompLinearBindingThreeParticleTypes(); + cadet::test::reaction::testTimeDerivativeJacobianDynamicReactionsFD(jpp, true, false, false, 1e-6, 1e-14, 9e-4); +} + +TEST_CASE("GRM_DG multi particle types dynamic reactions time derivative Jacobian vs FD particle", "[GRM],[DG],[Jacobian],[Residual],[ReactionModel],[ParticleType],[CI]") +{ + cadet::JsonParameterProvider jpp = createColumnWithTwoCompLinearBindingThreeParticleTypes(); + cadet::test::reaction::testTimeDerivativeJacobianDynamicReactionsFD(jpp, false, true, false, 1e-6, 1e-14, 9e-4); +} + +TEST_CASE("GRM_DG multi particle types dynamic reactions time derivative Jacobian vs FD modified particle", "[GRM],[DG],[Jacobian],[Residual],[ReactionModel],[ParticleType],[CI]") +{ + cadet::JsonParameterProvider jpp = createColumnWithTwoCompLinearBindingThreeParticleTypes(); + cadet::test::reaction::testTimeDerivativeJacobianDynamicReactionsFD(jpp, false, true, true, 1e-6, 1e-14, 9e-4); +} + +TEST_CASE("GRM_DG multi particle types dynamic reactions time derivative Jacobian vs FD bulk and particle", "[GRM],[DG],[Jacobian],[Residual],[ReactionModel],[ParticleType],[CI]") +{ + cadet::JsonParameterProvider jpp = createColumnWithTwoCompLinearBindingThreeParticleTypes(); + cadet::test::reaction::testTimeDerivativeJacobianDynamicReactionsFD(jpp, true, true, false, 1e-6, 1e-14, 9e-4); +} + +TEST_CASE("GRM_DG multi particle types dynamic reactions time derivative Jacobian vs FD bulk and modified particle", "[GRM],[DG],[Jacobian],[Residual],[ReactionModel],[ParticleType],[CI]") +{ + cadet::JsonParameterProvider jpp = createColumnWithTwoCompLinearBindingThreeParticleTypes(); + cadet::test::reaction::testTimeDerivativeJacobianDynamicReactionsFD(jpp, true, true, true, 1e-6, 1e-14, 9e-4); +} diff --git a/test/JacobianHelper.hpp b/test/JacobianHelper.hpp index 763d31974..4906129aa 100644 --- a/test/JacobianHelper.hpp +++ b/test/JacobianHelper.hpp @@ -406,6 +406,8 @@ inline void checkJacobianPatternFD(const std::function& residual, const std::function& multiplyJacobian, double const* y, - double* dir, double* colA, double* colB, unsigned int n, const double absTol = 0.0) + double* dir, double* colA, double* colB, unsigned int n, const double absTol=0.0) { checkJacobianPatternFD(residual, multiplyJacobian, y, dir, colA, colB, n, n, absTol); } diff --git a/test/LumpedRateModelWithPores.cpp b/test/LumpedRateModelWithPores.cpp index 785a01fce..1d44c8845 100644 --- a/test/LumpedRateModelWithPores.cpp +++ b/test/LumpedRateModelWithPores.cpp @@ -64,8 +64,10 @@ TEST_CASE("LRMP numerical Benchmark with parameter sensitivities for linear case const std::string& modelFilePath = std::string("/data/model_LRMP_dynLin_1comp_benchmark1.json"); const std::string& refFilePath = std::string("/data/ref_LRMP_dynLin_1comp_sensbenchmark1_FV_Z32.h5"); const std::vector absTol = { 1e-12, 1e-12, 1e-12, 1e-12 }; - const std::vector relTol = { 1.0, 1.0, 1.0, 1.0 }; - cadet::test::column::testReferenceBenchmark(modelFilePath, refFilePath, "001", absTol, relTol, 32, 0, true); + const std::vector relTol = { 1e-4, 1e-4, 1e-4, 1e-4 }; + + cadet::test::column::FVparams disc(32); + cadet::test::column::testReferenceBenchmark(modelFilePath, refFilePath, "001", absTol, relTol, disc, true); } TEST_CASE("LRMP numerical Benchmark with parameter sensitivities for SMA LWE case", "[LRMP],[FV],[Simulation],[Reference],[Sensitivity]") // todo CI flag: currently only runs locally but fails on server @@ -73,8 +75,10 @@ TEST_CASE("LRMP numerical Benchmark with parameter sensitivities for SMA LWE cas const std::string& modelFilePath = std::string("/data/model_LRMP_reqSMA_4comp_benchmark1.json"); const std::string& refFilePath = std::string("/data/ref_LRMP_reqSMA_4comp_sensbenchmark1_FV_Z32.h5"); const std::vector absTol = { 1e-12, 1e-12, 1e-12, 1e-12 }; - const std::vector relTol = { 1.0, 1.0, 1.0, 1.0 }; - cadet::test::column::testReferenceBenchmark(modelFilePath, refFilePath, "000", absTol, relTol, 32, 0, true); + const std::vector relTol = { 1e-4, 1e-4, 1e-4, 1e-4 }; + + cadet::test::column::FVparams disc(32); + cadet::test::column::testReferenceBenchmark(modelFilePath, refFilePath, "000", absTol, relTol, disc, true); } TEST_CASE("LRMP numerical EOC Benchmark with parameter sensitivities for linear case", "[releaseCI],[EOC],[EOC_LRMP_FV]") @@ -83,8 +87,10 @@ TEST_CASE("LRMP numerical EOC Benchmark with parameter sensitivities for linear const std::string& refFilePath = std::string("/data/ref_LRMP_dynLin_1comp_sensbenchmark1_FV_Z32768.h5"); const std::string& convFilePath = std::string("/data/convergence_LRMP_dynLin_1comp_sensbenchmark1.json"); const std::vector absTol = { 1e-12, 1e-12, 1e-12, 1e-12 }; - const std::vector relTol = { 1.0, 1.0, 1.0, 1.0 }; - cadet::test::column::testEOCReferenceBenchmark(modelFilePath, refFilePath, convFilePath, "001", absTol, relTol, 4, 16, 0, true); + const std::vector relTol = { 1e-4, 1e-4, 1e-4, 1e-4 }; + + cadet::test::column::FVparams disc(16); + cadet::test::column::testEOCReferenceBenchmark(modelFilePath, refFilePath, convFilePath, "001", absTol, relTol, 4, disc, true); } TEST_CASE("LRMP numerical EOC Benchmark with parameter sensitivities for SMA LWE case", "[releaseCI],[EOC],[EOC_LRMP_FV]") @@ -93,8 +99,10 @@ TEST_CASE("LRMP numerical EOC Benchmark with parameter sensitivities for SMA LWE const std::string& refFilePath = std::string("/data/ref_LRMP_reqSMA_4comp_sensbenchmark1_FV_Z2048.h5"); const std::string& convFilePath = std::string("/data/convergence_LRMP_reqSMA_4comp_sensbenchmark1.json"); const std::vector absTol = { 1e-12, 1e-12, 1e-12, 1e-12 }; - const std::vector relTol = { 1.0, 1.0, 1.0, 1.0 }; - cadet::test::column::testEOCReferenceBenchmark(modelFilePath, refFilePath, convFilePath, "000", absTol, relTol, 2, 8, 0, true); + const std::vector relTol = { 1e-4, 1e-4, 1e-4, 1e-4 }; + + cadet::test::column::FVparams disc(8); + cadet::test::column::testEOCReferenceBenchmark(modelFilePath, refFilePath, convFilePath, "000", absTol, relTol, 2, disc, true); } TEST_CASE("LRMP time derivative Jacobian vs FD", "[LRMP],[UnitOp],[Residual],[Jacobian],[CI]") diff --git a/test/LumpedRateModelWithPoresDG.cpp b/test/LumpedRateModelWithPoresDG.cpp new file mode 100644 index 000000000..5ccdf03b6 --- /dev/null +++ b/test/LumpedRateModelWithPoresDG.cpp @@ -0,0 +1,347 @@ +// ============================================================================= +// CADET +// +// Copyright © 2008-2023: The CADET Authors +// Please see the AUTHORS and CONTRIBUTORS file. +// +// All rights reserved. This program and the accompanying materials +// are made available under the terms of the GNU Public License v3.0 (or, at +// your option, any later version) which accompanies this distribution, and +// is available at http://www.gnu.org/licenses/gpl.html +// ============================================================================= + +#include + +#include "ColumnTests.hpp" +#include "ParticleHelper.hpp" +#include "ReactionModelTests.hpp" +#include "JsonTestModels.hpp" +#include "Utils.hpp" + +TEST_CASE("LRMP_DG LWE forward vs backward flow", "[LRMP],[DG],[Simulation],[CI]") +{ + cadet::test::column::DGparams disc; + + // Test all integration modes + for (int i = 0; i <= 1; i++) + { + disc.setIntegrationMode(i); + cadet::test::column::testForwardBackward("LUMPED_RATE_MODEL_WITH_PORES", disc, 6e-8, 4e-6); + } +} + +TEST_CASE("LRMP_DG linear pulse vs analytic solution", "[LRMP],[DG],[Simulation],[Analytic],[CI]") +{ + cadet::test::column::DGparams disc; + cadet::test::column::testAnalyticBenchmark("LUMPED_RATE_MODEL_WITH_PORES", "/data/lrmp-pulseBenchmark.data", true, true, disc, 6e-5, 1e-7); + cadet::test::column::testAnalyticBenchmark("LUMPED_RATE_MODEL_WITH_PORES", "/data/lrmp-pulseBenchmark.data", true, false, disc, 6e-5, 1e-7); + cadet::test::column::testAnalyticBenchmark("LUMPED_RATE_MODEL_WITH_PORES", "/data/lrmp-pulseBenchmark.data", false, true, disc, 6e-5, 1e-7); + cadet::test::column::testAnalyticBenchmark("LUMPED_RATE_MODEL_WITH_PORES", "/data/lrmp-pulseBenchmark.data", false, false, disc, 6e-5, 1e-7); +} + +TEST_CASE("LRMP_DG non-binding linear pulse vs analytic solution", "[LRMP],[DG],[Simulation],[Analytic],[NonBinding],[CI]") +{ + cadet::test::column::DGparams disc; + cadet::test::column::testAnalyticNonBindingBenchmark("LUMPED_RATE_MODEL_WITH_PORES", "/data/lrmp-nonBinding.data", true, disc, 6e-5, 1e-7); + cadet::test::column::testAnalyticNonBindingBenchmark("LUMPED_RATE_MODEL_WITH_PORES", "/data/lrmp-nonBinding.data", false, disc, 6e-5, 1e-7); +} + +//TEST_CASE("LRMP_DG Jacobian forward vs backward flow", "[LRMP],[DG],[UnitOp],[Residual],[Jacobian],[AD],[fix]") +//{ +// cadet::test::column::DGparams disc; +// +// // Test all integration modes +// for (int i = 0; i <= 1; i++) +// { +// disc.setIntegrationMode(i); +// cadet::test::column::testJacobianForwardBackward("LUMPED_RATE_MODEL_WITH_PORES", disc, std::numeric_limits::epsilon() * 100.0); +// } +//} + +TEST_CASE("LRMP_DG numerical Benchmark with parameter sensitivities for linear case", "[LRMP],[DG],[Simulation],[Reference],[Sensitivity],[CI]") +{ + const std::string& modelFilePath = std::string("/data/model_LRMP_dynLin_1comp_benchmark1.json"); + const std::string& refFilePath = std::string("/data/ref_LRMP_dynLin_1comp_sensbenchmark1_DG_P3Z8.h5"); + const std::vector absTol = { 1e-12, 1e-12, 1e-12, 1e-12 }; + const std::vector relTol = { 1.0, 1.0, 1.0, 1.0 }; + + cadet::test::column::DGparams disc(0, 3, 8); + cadet::test::column::testReferenceBenchmark(modelFilePath, refFilePath, "001", absTol, relTol, disc, true); +} + +TEST_CASE("LRMP_DG numerical Benchmark with parameter sensitivities for SMA LWE case", "[LRMP],[DG],[Simulation],[Reference],[Sensitivity],[CI]") +{ + const std::string& modelFilePath = std::string("/data/model_LRMP_reqSMA_4comp_benchmark1.json"); + const std::string& refFilePath = std::string("/data/ref_LRMP_reqSMA_4comp_sensbenchmark1_DG_P3Z8.h5"); + const std::vector absTol = { 1e-12, 1e-12, 1e-12, 1e-12 }; + const std::vector relTol = { 1.0, 1.0, 1.0, 1.0 }; + + cadet::test::column::DGparams disc(0, 3, 8); + cadet::test::column::testReferenceBenchmark(modelFilePath, refFilePath, "000", absTol, relTol, disc, true); +} + +TEST_CASE("LRMP_DG time derivative Jacobian vs FD", "[LRMP],[DG],[UnitOp],[Residual],[Jacobian],[CI]") +{ + cadet::test::column::testTimeDerivativeJacobianFD("LUMPED_RATE_MODEL_WITH_PORES", "DG"); +} + +TEST_CASE("LRMP_DG sensitivity Jacobians", "[LRMP],[DG],[UnitOp],[Sensitivity],[CI]") +{ + cadet::test::column::testFwdSensJacobians("LUMPED_RATE_MODEL_WITH_PORES", "DG", 1e-4, 6e-7); +} + +//// todo fix: not just adjust tolerances as in FV but theres an actual error here: access violation in densematrix +//TEST_CASE("LRMP_DG forward sensitivity vs FD", "[LRMP],[DG],[Sensitivity],[Simulation],[todo]") +//{ +// // Relative error is checked first, we use high absolute error for letting +// // some points that are far off pass the error test, too. This is required +// // due to errors in finite differences. +// const double fdStepSize[] = { 1e-5, 1e-6, 1e-3, 1e-5 }; +// const double absTols[] = { 6e5, 2e-2, 2e-2, 1.0 }; +// const double relTols[] = { 5e-3, 1e-1, 5e-1, 6e-3 }; +// const double passRatio[] = { 0.87, 0.84, 0.88, 0.95 }; +// cadet::test::column::testFwdSensSolutionFD("LUMPED_RATE_MODEL_WITH_PORES", "DG", true, fdStepSize, absTols, relTols, passRatio); +//} + +// todo fix: not just adjust tolerances as in FV but theres an actual error here: access violation in densematrix +//TEST_CASE("LRMP_DG forward sensitivity forward vs backward flow", "[LRMP],[DG],[Sensitivity],[Simulation],[todo]") +//{ +// const double absTols[] = { 50.0, 2e-10, 1.0, 5e-7 }; +// const double relTols[] = { 2e-4, 9e-6, 5e-7, 1e-7 }; +// const double passRatio[] = { 1.0, 0.99, 0.98, 0.99 }; +// cadet::test::column::testFwdSensSolutionForwardBackward("LUMPED_RATE_MODEL_WITH_PORES", "DG", absTols, relTols, passRatio); +//} + +// todo fix consistent initialization for AD with req binding +TEST_CASE("LRMP_DG consistent initialization with linear binding", "[LRMP],[DG],[ConsistentInit],[CI]") +{ + cadet::test::column::testConsistentInitializationLinearBinding("LUMPED_RATE_MODEL_WITH_PORES", "DG", 1e-12, 1e-12, 0, 0); + cadet::test::column::testConsistentInitializationLinearBinding("LUMPED_RATE_MODEL_WITH_PORES", "DG", 1e-12, 1e-12, 1, 0); + cadet::test::column::testConsistentInitializationLinearBinding("LUMPED_RATE_MODEL_WITH_PORES", "DG", 1e-12, 1e-12, 0, 1); + //cadet::test::column::testConsistentInitializationLinearBinding("LUMPED_RATE_MODEL_WITH_PORES", "DG", 1e-12, 1e-12, 1, 1); +} + +////// todo fix consistent initialization for SMA (initialization not completely correct; AD gives assertion error) +//TEST_CASE("LRMP_DG consistent initialization with SMA binding", "[LRMP],[DG],[ConsistentInit],[todo]") +//{ +// std::vector y(4 + 4 * 16 + 16 * (4 + 4) + 4 * 16, 0.0); +// const double bindingCell[] = { 1.2, 2.0, 1.0, 1.5, 840.0, 63.0, 3.0, 3.0, +// 1.0, 1.8, 1.5, 1.6, 840.0, 63.0, 6.0, 3.0 }; +// cadet::test::util::populate(y.data(), [](unsigned int idx) { return std::abs(std::sin(idx * 0.13)) + 1e-4; }, 4 + 4 * 16); +// cadet::test::util::repeat(y.data() + 4 + 4 * 16, bindingCell, 16, 8); +// cadet::test::util::populate(y.data() + 4 + 4 * 16 + 16 * (4 + 4), [](unsigned int idx) { return std::abs(std::sin(idx * 0.13)) + 1e-4; }, 4 * 16); +// +// //cadet::test::column::testConsistentInitializationSMABinding("LUMPED_RATE_MODEL_WITH_PORES", "DG", y.data(), 1e-14, 1e-5, 0, 0); +// //cadet::test::column::testConsistentInitializationSMABinding("LUMPED_RATE_MODEL_WITH_PORES", "DG", y.data(), 1e-14, 1e-5, 1, 0); +// //cadet::test::column::testConsistentInitializationSMABinding("LUMPED_RATE_MODEL_WITH_PORES", "DG", y.data(), 1e-14, 1e-5, 0, 1); +// //cadet::test::column::testConsistentInitializationSMABinding("LUMPED_RATE_MODEL_WITH_PORES", "DG", y.data(), 1e-14, 1e-5, 1, 1); +//} + +// todo fix kinetic binding sensitivity init +TEST_CASE("LRMP_DG consistent sensitivity initialization with linear binding", "[LRMP],[DG],[ConsistentInit],[Sensitivity],[CI]") +{ + // Fill state vector with given initial values + const unsigned int numDofs = 2 + 2 * 10 + 10 * (2 + 2); + std::vector y(numDofs, 0.0); + std::vector yDot(numDofs, 0.0); + cadet::test::util::populate(y.data(), [](unsigned int idx) { return std::abs(std::sin(idx * 0.13)) + 1e-4; }, numDofs); + cadet::test::util::populate(yDot.data(), [](unsigned int idx) { return std::abs(std::sin(idx * 0.9)) + 1e-4; }, numDofs); + + //cadet::test::column::testConsistentInitializationSensitivity("LUMPED_RATE_MODEL_WITH_PORES", "DG", y.data(), yDot.data(), true, 1e-14, 0, 0); // doesnt work + cadet::test::column::testConsistentInitializationSensitivity("LUMPED_RATE_MODEL_WITH_PORES", "DG", y.data(), yDot.data(), true, 1e-14, 1, 0); // works + //cadet::test::column::testConsistentInitializationSensitivity("LUMPED_RATE_MODEL_WITH_PORES", "DG", y.data(), yDot.data(), true, 1e-14, 0, 1); // doesnt work + cadet::test::column::testConsistentInitializationSensitivity("LUMPED_RATE_MODEL_WITH_PORES", "DG", y.data(), yDot.data(), true, 1e-14, 1, 1); // works +} + +//// todo fix memory stuff (works for FV) +//TEST_CASE("LRMP_DG consistent sensitivity initialization with SMA binding", "[LRMP],[DG],[ConsistentInit],[Sensitivity],[todo]") +//{ +// // Fill state vector with given initial values +// const unsigned int numDofs = 4 + 4 * 10 + 10 * (4 + 4); +// std::vector y(numDofs, 0.0); +// std::vector yDot(numDofs, 0.0); +// +// const double bindingCell[] = { 1.0, 1.8, 1.5, 1.6, 840.0, 63.0, 6.0, 3.0 }; +// cadet::test::util::populate(y.data(), [](unsigned int idx) { return std::abs(std::sin(idx * 0.13)) + 1e-4; }, 4 + 4 * 10); +// cadet::test::util::repeat(y.data() + 4 + 4 * 10, bindingCell, 8, 10); +// cadet::test::util::populate(y.data() + 4 + 4 * 10 + 10 * (4 + 4), [](unsigned int idx) { return std::abs(std::sin(idx * 0.13)) + 1e-4; }, 4 * 10); +// +// cadet::test::util::populate(yDot.data(), [](unsigned int idx) { return std::abs(std::sin(idx * 0.9)) + 1e-4; }, numDofs); +// +// //cadet::test::column::testConsistentInitializationSensitivity("LUMPED_RATE_MODEL_WITH_PORES", "DG", y.data(), yDot.data(), false, 1e-10, 0, 0); +// //cadet::test::column::testConsistentInitializationSensitivity("LUMPED_RATE_MODEL_WITH_PORES", "DG", y.data(), yDot.data(), false, 1e-10, 1, 0); +// //cadet::test::column::testConsistentInitializationSensitivity("LUMPED_RATE_MODEL_WITH_PORES", "DG", y.data(), yDot.data(), false, 1e-10, 0, 1); +// //cadet::test::column::testConsistentInitializationSensitivity("LUMPED_RATE_MODEL_WITH_PORES", "DG", y.data(), yDot.data(), false, 1e-10, 1, 1); +//} + +TEST_CASE("LRMP_DG inlet DOF Jacobian", "[LRMP],[DG],[UnitOp],[Jacobian],[Inlet],[CI]") +{ + cadet::test::column::testInletDofJacobian("LUMPED_RATE_MODEL_WITH_PORES", "DG"); +} + +TEST_CASE("LRMP_DG transport Jacobian", "[LRMP],[DG],[UnitOp],[Jacobian],[CI]") +{ + cadet::JsonParameterProvider jpp = createColumnLinearBenchmark(false, true, "LUMPED_RATE_MODEL_WITH_PORES", "DG"); + cadet::test::column::testJacobianAD(jpp, std::numeric_limits::epsilon() * 100.0); +} + +TEST_CASE("LRMP_DG with two component linear binding Jacobian", "[LRMP],[DG],[UnitOp],[Jacobian],[CI]") +{ + cadet::JsonParameterProvider jpp = createColumnWithTwoCompLinearBinding("LUMPED_RATE_MODEL_WITH_PORES", "DG"); + cadet::test::column::testJacobianAD(jpp, std::numeric_limits::epsilon() * 100.0); +} + +TEST_CASE("LRMP_DG LWE one vs two identical particle types match", "[LRMP],[DG],[Simulation],[ParticleType],[CI]") +{ + cadet::test::particle::testOneVsTwoIdenticalParticleTypes("LUMPED_RATE_MODEL_WITH_PORES", "DG", 2.2e-8, 6e-5); +} + +TEST_CASE("LRMP_DG LWE separate identical particle types match", "[LRMP],[DG],[Simulation],[ParticleType],[CI]") +{ + cadet::test::particle::testSeparateIdenticalParticleTypes("LUMPED_RATE_MODEL_WITH_PORES", "DG", 1e-12, 1e-12); +} + +TEST_CASE("LRMP_DG linear binding single particle matches particle distribution", "[LRMP],[DG],[Simulation],[ParticleType],[CI]") +{ + cadet::test::particle::testLinearMixedParticleTypes("LUMPED_RATE_MODEL_WITH_PORES", "DG", 5e-8, 5e-5); +} + +TEST_CASE("LRMP_DG multiple particle types Jacobian analytic vs AD", "[LRMP],[DG],[Jacobian],[AD],[ParticleType],[CI]") +{ + cadet::test::particle::testJacobianMixedParticleTypes("LUMPED_RATE_MODEL_WITH_PORES", "DG", 1e-11); +} + +TEST_CASE("LRMP_DG multiple particle types time derivative Jacobian vs FD", "[LRMP],[DG],[UnitOp],[Residual],[Jacobian],[ParticleType],[CI]") +{ + cadet::test::particle::testTimeDerivativeJacobianMixedParticleTypesFD("LUMPED_RATE_MODEL_WITH_PORES", "DG", 1e-6, 0.0, 9e-4); +} + +TEST_CASE("LRMP_DG multiple spatially dependent particle types Jacobian analytic vs AD", "[LRMP],[DG],[Jacobian],[AD],[ParticleType],[CI]") +{ + cadet::test::particle::testJacobianSpatiallyMixedParticleTypes("LUMPED_RATE_MODEL_WITH_PORES", "DG", std::numeric_limits::epsilon() * 100.0); +} + +TEST_CASE("LRMP_DG linear binding single particle matches spatially dependent particle distribution", "[LRMP],[DG],[Simulation],[ParticleType],[CI]") +{ + cadet::test::particle::testLinearSpatiallyMixedParticleTypes("LUMPED_RATE_MODEL_WITH_PORES", "DG", 5e-8, 5e-5); +} + +TEST_CASE("LRMP_DG dynamic reactions Jacobian vs AD bulk", "[LRMP],[DG],[Jacobian],[AD],[ReactionModel],[CI]") +{ + cadet::test::reaction::testUnitJacobianDynamicReactionsAD("LUMPED_RATE_MODEL_WITH_PORES", "DG", true, false, false, std::numeric_limits::epsilon() * 100.0); +} +TEST_CASE("LRMP_DG dynamic reactions Jacobian vs AD particle", "[LRMP],[DG],[Jacobian],[AD],[ReactionModel],[CI]") +{ + cadet::test::reaction::testUnitJacobianDynamicReactionsAD("LUMPED_RATE_MODEL_WITH_PORES", "DG", false, true, false, std::numeric_limits::epsilon() * 100.0); +} + +TEST_CASE("LRMP_DG dynamic reactions Jacobian vs AD modified particle", "[LRMP],[DG],[Jacobian],[AD],[ReactionModel],[CI]") +{ + cadet::test::reaction::testUnitJacobianDynamicReactionsAD("LUMPED_RATE_MODEL_WITH_PORES", "DG", false, true, true, std::numeric_limits::epsilon() * 100.0); +} + +TEST_CASE("LRMP_DG dynamic reactions Jacobian vs AD bulk and particle", "[LRMP],[DG],[Jacobian],[AD],[ReactionModel],[CI]") +{ + cadet::test::reaction::testUnitJacobianDynamicReactionsAD("LUMPED_RATE_MODEL_WITH_PORES", "DG", true, true, false, std::numeric_limits::epsilon() * 100.0); +} + +TEST_CASE("LRMP_DG dynamic reactions Jacobian vs AD bulk and modified particle", "[LRMP],[DG],[Jacobian],[AD],[ReactionModel],[CI]") +{ + cadet::test::reaction::testUnitJacobianDynamicReactionsAD("LUMPED_RATE_MODEL_WITH_PORES", "DG", true, true, true, std::numeric_limits::epsilon() * 100.0); +} + +TEST_CASE("LRMP_DG dynamic reactions time derivative Jacobian vs FD bulk", "[LRMP],[DG],[Jacobian],[Residual],[ReactionModel],[CI]") +{ + cadet::test::reaction::testTimeDerivativeJacobianDynamicReactionsFD("LUMPED_RATE_MODEL_WITH_PORES", "DG", true, false, false, 1e-6, 1e-14, 8e-4); +} + +TEST_CASE("LRMP_DG dynamic reactions time derivative Jacobian vs FD particle", "[LRMP],[DG],[Jacobian],[Residual],[ReactionModel],[CI]") +{ + cadet::test::reaction::testTimeDerivativeJacobianDynamicReactionsFD("LUMPED_RATE_MODEL_WITH_PORES", "DG", false, true, false, 1e-6, 1e-14, 8e-4); +} + +TEST_CASE("LRMP_DG dynamic reactions time derivative Jacobian vs FD modified particle", "[LRMP],[DG],[Jacobian],[Residual],[ReactionModel],[CI]") +{ + cadet::test::reaction::testTimeDerivativeJacobianDynamicReactionsFD("LUMPED_RATE_MODEL_WITH_PORES", "DG", false, true, true, 1e-6, 1e-14, 8e-4); +} + +TEST_CASE("LRMP_DG dynamic reactions time derivative Jacobian vs FD bulk and particle", "[LRMP],[DG],[Jacobian],[Residual],[ReactionModel],[CI]") +{ + cadet::test::reaction::testTimeDerivativeJacobianDynamicReactionsFD("LUMPED_RATE_MODEL_WITH_PORES", "DG", true, true, false, 1e-6, 1e-14, 8e-4); +} + +TEST_CASE("LRMP_DG dynamic reactions time derivative Jacobian vs FD bulk and modified particle", "[LRMP],[DG],[Jacobian],[Residual],[ReactionModel],[CI]") +{ + cadet::test::reaction::testTimeDerivativeJacobianDynamicReactionsFD("LUMPED_RATE_MODEL_WITH_PORES", "DG", true, true, true, 1e-6, 1e-14, 8e-4); +} + +inline cadet::JsonParameterProvider createLRMPColumnWithTwoCompLinearBindingThreeParticleTypes() +{ + cadet::JsonParameterProvider jpp = createColumnWithTwoCompLinearBinding("LUMPED_RATE_MODEL_WITH_PORES", "DG"); + + const double parVolFrac[] = { 0.3, 0.6, 0.1 }; + const double parFactor[] = { 0.9, 0.8 }; + cadet::test::particle::extendModelToManyParticleTypes(jpp, 3, parFactor, parVolFrac); + + return jpp; +} + +TEST_CASE("LRMP_DG multi particle types dynamic reactions Jacobian vs AD bulk", "[LRMP],[DG],[Jacobian],[AD],[ReactionModel],[ParticleType],[CI]") +{ + cadet::JsonParameterProvider jpp = createLRMPColumnWithTwoCompLinearBindingThreeParticleTypes(); + cadet::test::reaction::testUnitJacobianDynamicReactionsAD(jpp, true, false, false, 1e-11); +} + +TEST_CASE("LRMP_DG multi particle types dynamic reactions Jacobian vs AD particle", "[LRMP],[DG],[Jacobian],[AD],[ReactionModel],[ParticleType],[CI]") +{ + cadet::JsonParameterProvider jpp = createLRMPColumnWithTwoCompLinearBindingThreeParticleTypes(); + cadet::test::reaction::testUnitJacobianDynamicReactionsAD(jpp, false, true, false, 1e-11); +} + +TEST_CASE("LRMP_DG multi particle types dynamic reactions Jacobian vs AD modified particle", "[LRMP],[DG],[Jacobian],[AD],[ReactionModel],[ParticleType],[CI]") +{ + cadet::JsonParameterProvider jpp = createLRMPColumnWithTwoCompLinearBindingThreeParticleTypes(); + cadet::test::reaction::testUnitJacobianDynamicReactionsAD(jpp, false, true, true, 1e-11); +} + +TEST_CASE("LRMP_DG multi particle types dynamic reactions Jacobian vs AD bulk and particle", "[LRMP],[DG],[Jacobian],[AD],[ReactionModel],[ParticleType],[CI]") +{ + cadet::JsonParameterProvider jpp = createLRMPColumnWithTwoCompLinearBindingThreeParticleTypes(); + cadet::test::reaction::testUnitJacobianDynamicReactionsAD(jpp, true, true, false, 1e-11); +} + +TEST_CASE("LRMP_DG multi particle types dynamic reactions Jacobian vs AD bulk and modified particle", "[LRMP],[DG],[Jacobian],[AD],[ReactionModel],[ParticleType],[CI]") +{ + cadet::JsonParameterProvider jpp = createLRMPColumnWithTwoCompLinearBindingThreeParticleTypes(); + cadet::test::reaction::testUnitJacobianDynamicReactionsAD(jpp, true, true, true, 1e-11); +} + +TEST_CASE("LRMP_DG multi particle types dynamic reactions time derivative Jacobian vs FD bulk", "[LRMP],[DG],[Jacobian],[Residual],[ReactionModel],[ParticleType],[CI]") +{ + cadet::JsonParameterProvider jpp = createLRMPColumnWithTwoCompLinearBindingThreeParticleTypes(); + cadet::test::reaction::testTimeDerivativeJacobianDynamicReactionsFD(jpp, true, false, false, 1e-6, 1e-14, 8e-4); +} + +TEST_CASE("LRMP_DG multi particle types dynamic reactions time derivative Jacobian vs FD particle", "[LRMP],[DG],[Jacobian],[Residual],[ReactionModel],[ParticleType],[CI]") +{ + cadet::JsonParameterProvider jpp = createLRMPColumnWithTwoCompLinearBindingThreeParticleTypes(); + cadet::test::reaction::testTimeDerivativeJacobianDynamicReactionsFD(jpp, false, true, false, 1e-6, 1e-14, 8e-4); +} + +TEST_CASE("LRMP_DG multi particle types dynamic reactions time derivative Jacobian vs FD modified particle", "[LRMP],[DG],[Jacobian],[Residual],[ReactionModel],[ParticleType],[CI]") +{ + cadet::JsonParameterProvider jpp = createLRMPColumnWithTwoCompLinearBindingThreeParticleTypes(); + cadet::test::reaction::testTimeDerivativeJacobianDynamicReactionsFD(jpp, false, true, true, 1e-6, 1e-14, 8e-4); +} + +TEST_CASE("LRMP_DG multi particle types dynamic reactions time derivative Jacobian vs FD bulk and particle", "[LRMP],[DG],[Jacobian],[Residual],[ReactionModel],[ParticleType],[CI]") +{ + cadet::JsonParameterProvider jpp = createLRMPColumnWithTwoCompLinearBindingThreeParticleTypes(); + cadet::test::reaction::testTimeDerivativeJacobianDynamicReactionsFD(jpp, true, true, false, 1e-6, 1e-14, 8e-4); +} + +TEST_CASE("LRMP_DG multi particle types dynamic reactions time derivative Jacobian vs FD bulk and modified particle", "[LRMP],[DG],[Jacobian],[Residual],[ReactionModel],[ParticleType],[CI]") +{ + cadet::JsonParameterProvider jpp = createLRMPColumnWithTwoCompLinearBindingThreeParticleTypes(); + cadet::test::reaction::testTimeDerivativeJacobianDynamicReactionsFD(jpp, true, true, true, 1e-6, 1e-14, 8e-4); +} diff --git a/test/LumpedRateModelWithoutPores.cpp b/test/LumpedRateModelWithoutPores.cpp index 8929e6cc1..22733a118 100644 --- a/test/LumpedRateModelWithoutPores.cpp +++ b/test/LumpedRateModelWithoutPores.cpp @@ -63,17 +63,21 @@ TEST_CASE("LRM numerical Benchmark with parameter sensitivities for linear case" const std::string& modelFilePath = std::string("/data/model_LRM_dynLin_1comp_benchmark1.json"); const std::string& refFilePath = std::string("/data/ref_LRM_dynLin_1comp_sensbenchmark1_FV_Z32.h5"); const std::vector absTol = { 1e-12, 1e-12, 1e-12, 1e-12 }; - const std::vector relTol = { 1.0, 1.0, 1.0, 1.0 }; - cadet::test::column::testReferenceBenchmark(modelFilePath, refFilePath, "001", absTol, relTol, 32, 0, false); + const std::vector relTol = { 1e-4, 1e-4, 1e-4, 1e-4 }; + + cadet::test::column::FVparams disc(32); + cadet::test::column::testReferenceBenchmark(modelFilePath, refFilePath, "001", absTol, relTol, disc, true); } TEST_CASE("LRM numerical Benchmark with parameter sensitivities for SMA LWE case", "[LRM],[FV],[Simulation],[Reference],[Sensitivity]") // todo CI flag: currently only runs locally but fails on server { const std::string& modelFilePath = std::string("/data/model_LRM_reqSMA_4comp_benchmark1.json"); const std::string& refFilePath = std::string("/data/ref_LRM_reqSMA_4comp_sensbenchmark1_FV_Z32.h5"); - const std::vector absTol = { 1e-12, 1e-0, 1e-12, 1e-12 }; // todo 1-4 tolerance required here, but not in LRMP and GRM - const std::vector relTol = { 1.0, 1.0, 1.0, 1.0 }; - cadet::test::column::testReferenceBenchmark(modelFilePath, refFilePath, "000", absTol, relTol, 32, 0, true); + const std::vector absTol = { 1e-12, 1e-0, 1e-12, 1e-12 }; // todo: why is such a high tolerance required for first sensitivity parameter + const std::vector relTol = { 1e-4, 1.0, 1e-4, 1e-4 }; + + cadet::test::column::FVparams disc(32); + cadet::test::column::testReferenceBenchmark(modelFilePath, refFilePath, "000", absTol, relTol, disc, true); } TEST_CASE("LRM numerical EOC Benchmark with parameter sensitivities for linear case", "[releaseCI],[EOC],[EOC_LRM_FV]") @@ -82,8 +86,10 @@ TEST_CASE("LRM numerical EOC Benchmark with parameter sensitivities for linear c const std::string& refFilePath = std::string("/data/ref_LRM_dynLin_1comp_sensbenchmark1_FV_Z131072.h5"); const std::string& convFilePath = std::string("/data/convergence_LRM_dynLin_1comp_sensbenchmark1.json"); const std::vector absTol = { 1e-12, 1e-12, 1e-12, 1e-12 }; - const std::vector relTol = { 1.0, 1.0, 1.0, 1.0 }; - cadet::test::column::testEOCReferenceBenchmark(modelFilePath, refFilePath, convFilePath, "001", absTol, relTol, 4, 16, 0, true); + const std::vector relTol = { 1e-2, 1e-3, 1e-1, 1e-2 }; + + cadet::test::column::FVparams disc(16); + cadet::test::column::testEOCReferenceBenchmark(modelFilePath, refFilePath, convFilePath, "001", absTol, relTol, 4, disc, true); } TEST_CASE("LRM numerical EOC Benchmark with parameter sensitivities for SMA LWE case", "[releaseCI],[EOC],[EOC_LRM_FV]") @@ -92,8 +98,10 @@ TEST_CASE("LRM numerical EOC Benchmark with parameter sensitivities for SMA LWE const std::string& refFilePath = std::string("/data/ref_LRM_reqSMA_4comp_sensbenchmark1_FV_Z4096.h5"); const std::string& convFilePath = std::string("/data/convergence_LRM_reqSMA_4comp_sensbenchmark1.json"); const std::vector absTol = { 1e-12, 1e-12, 1e-12, 1e-12 }; - const std::vector relTol = { 1.0, 1.0, 1.0, 1.0 }; - cadet::test::column::testEOCReferenceBenchmark(modelFilePath, refFilePath, convFilePath, "000", absTol, relTol, 2, 8, 0, true); + const std::vector relTol = { 1e-4, 1e-4, 1e-4, 1e-4 }; + + cadet::test::column::FVparams disc(8); + cadet::test::column::testEOCReferenceBenchmark(modelFilePath, refFilePath, convFilePath, "000", absTol, relTol, 2, disc, true); } TEST_CASE("LRM time derivative Jacobian vs FD", "[LRM],[FV],[UnitOp],[Residual],[Jacobian],[CI],[FD]") diff --git a/test/LumpedRateModelWithoutPoresDG.cpp b/test/LumpedRateModelWithoutPoresDG.cpp index 9dd0943f5..1c27d3bd4 100644 --- a/test/LumpedRateModelWithoutPoresDG.cpp +++ b/test/LumpedRateModelWithoutPoresDG.cpp @@ -1,7 +1,7 @@ // ============================================================================= // CADET // -// Copyright © 2008-2021: The CADET Authors +// Copyright © 2008-2023: The CADET Authors // Please see the AUTHORS and CONTRIBUTORS file. // // All rights reserved. This program and the accompanying materials @@ -11,95 +11,185 @@ // ============================================================================= #include -#include "Approx.hpp" -#include "cadet/cadet.hpp" -#include "Logging.hpp" + #include "ColumnTests.hpp" +#include "ReactionModelTests.hpp" #include "Utils.hpp" -#include "SimHelper.hpp" -#include "ModelBuilderImpl.hpp" -#include "common/Driver.hpp" -#include "Weno.hpp" -#include "linalg/Norms.hpp" -#include "SimulationTypes.hpp" -#include "ParallelSupport.hpp" - #include "JsonTestModels.hpp" -#include "JacobianHelper.hpp" -#include "UnitOperationTests.hpp" - -#include -#include -#include - -namespace +TEST_CASE("LRM_DG LWE forward vs backward flow", "[LRM],[DG],[Simulation],[CI]") { - void setParameters(cadet::JsonParameterProvider& jpp, unsigned int nCol, unsigned int nNodes, std::string basis) + cadet::test::column::DGparams disc; + + // Test all integration modes + for (int i = 0; i <= 1; i++) { - int level = 0; - - if (jpp.exists("model")) - { - jpp.pushScope("model"); - ++level; - } - if (jpp.exists("unit_000")) - { - jpp.pushScope("unit_000"); - ++level; - } - - jpp.pushScope("discretization"); - - // Set discretization parameters - jpp.set("NCOL", static_cast(nCol)); - jpp.set("NNODES", static_cast(nNodes)); - jpp.set("POLYNOMIAL_BASIS", basis); - - jpp.popScope(); - - for (int l = 0; l < level; ++l) - jpp.popScope(); + disc.setIntegrationMode(i); + cadet::test::column::testForwardBackward("LUMPED_RATE_MODEL_WITHOUT_PORES", disc, 6e-9, 6e-2); } +} +TEST_CASE("LRM_DG linear pulse vs analytic solution", "[LRM],[DG],[Simulation],[Analytic],[CI]") +{ + cadet::test::column::DGparams disc; + cadet::test::column::testAnalyticBenchmark("LUMPED_RATE_MODEL_WITHOUT_PORES", "/data/lrm-pulseBenchmark.data", true, true, disc, 2e-5, 1e-7); + cadet::test::column::testAnalyticBenchmark("LUMPED_RATE_MODEL_WITHOUT_PORES", "/data/lrm-pulseBenchmark.data", true, false, disc, 2e-5, 1e-7); + cadet::test::column::testAnalyticBenchmark("LUMPED_RATE_MODEL_WITHOUT_PORES", "/data/lrm-pulseBenchmark.data", false, true, disc, 2e-5, 1e-7); + cadet::test::column::testAnalyticBenchmark("LUMPED_RATE_MODEL_WITHOUT_PORES", "/data/lrm-pulseBenchmark.data", false, false, disc, 2e-5, 1e-7); +} + +TEST_CASE("LRM_DG non-binding linear pulse vs analytic solution", "[LRM],[DG],[Simulation],[Analytic],[NonBinding],[CI]") +{ + cadet::test::column::DGparams disc; + cadet::test::column::testAnalyticNonBindingBenchmark("LUMPED_RATE_MODEL_WITHOUT_PORES", "/data/lrm-nonBinding.data", true, disc, 2e-5, 1e-7); + cadet::test::column::testAnalyticNonBindingBenchmark("LUMPED_RATE_MODEL_WITHOUT_PORES", "/data/lrm-nonBinding.data", false, disc, 2e-5, 1e-7); +} +//TEST_CASE("LRM_DG Jacobian forward vs backward flow", "[LRM],[DG],[UnitOp],[Residual],[Jacobian],[AD],[fix]") +//{ +// cadet::test::column::DGparams disc; +// +// // Test all integration modes +// for (int i = 0; i < 2; i++) +// { +// disc.setIntegrationMode(i); +// cadet::test::column::testJacobianForwardBackward("LUMPED_RATE_MODEL_WITHOUT_PORES", disc, std::numeric_limits::epsilon() * 100.0); +// } +//} + +TEST_CASE("LRM_DG numerical Benchmark with parameter sensitivities for linear case", "[LRM],[DG],[Simulation],[Reference],[Sensitivity],[CI]") +{ + const std::string& modelFilePath = std::string("/data/model_LRM_dynLin_1comp_benchmark1.json"); + const std::string& refFilePath = std::string("/data/ref_LRM_dynLin_1comp_sensbenchmark1_DG_P3Z8.h5"); + const std::vector absTol = { 1e-12, 1e-12, 1e-12, 1e-12 }; + const std::vector relTol = { 1.0, 1.0, 1.0, 1.0 }; + cadet::test::column::DGparams disc(0, 3, 8); + cadet::test::column::testReferenceBenchmark(modelFilePath, refFilePath, "001", absTol, relTol, disc, true); } -TEST_CASE("LRM_DG linear pulse vs analytic solution", "[LRM],[Simulation],[Analytic]") +TEST_CASE("LRM_DG numerical Benchmark with parameter sensitivities for SMA LWE case", "[LRM],[DG],[Simulation],[Reference],[Sensitivity]") // todo CI flag: currently only runs locally but fails on server { - cadet::IModelBuilder* const mb = cadet::createModelBuilder(); - REQUIRE(nullptr != mb); + const std::string& modelFilePath = std::string("/data/model_LRM_reqSMA_4comp_benchmark1.json"); + const std::string& refFilePath = std::string("/data/ref_LRM_reqSMA_4comp_sensbenchmark1_DG_P3Z8.h5"); + const std::vector absTol = { 1e-12, 1e-12, 1e-12, 1e-12 }; + const std::vector relTol = { 1.0, 1.0, 1.0, 1.0 }; - // Setup simulation - bool dynamicBinding = true; - cadet::JsonParameterProvider jpp = createColumnWithTwoCompLinearBinding("LUMPED_RATE_MODEL_WITHOUT_PORES", "DG"); - setParameters(jpp, 10, 2, "LAGRANGE"); - cadet::IUnitOperation* const unit = cadet::test::unitoperation::createAndConfigureUnit(jpp, *mb); + cadet::test::column::DGparams disc(0, 3, 8); + cadet::test::column::testReferenceBenchmark(modelFilePath, refFilePath, "000", absTol, relTol, disc, true); +} - // Disable AD - unit->useAnalyticJacobian(true); +TEST_CASE("LRM_DG time derivative Jacobian vs FD", "[LRM],[DG],[UnitOp],[Residual],[Jacobian],[CI]") +{ + cadet::test::column::testTimeDerivativeJacobianFD("LUMPED_RATE_MODEL_WITHOUT_PORES", "DG"); +} - // Obtain memory for state, etc. - std::vector y(unit->numDofs(), 0.0); - std::vector yDot(unit->numDofs(), 0.0); - std::vector res(unit->numDofs(), 0.0); +TEST_CASE("LRM_DG sensitivity Jacobians", "[LRM],[DG],[UnitOp],[Sensitivity],[CI]") +{ + cadet::test::column::testFwdSensJacobians("LUMPED_RATE_MODEL_WITHOUT_PORES", "DG", 1e-4, 3e-7, 5e-4); +} - // Fill state vector with some values - cadet::test::util::populate(y.data(), [](unsigned int idx) { return std::abs(std::sin(idx * 0.13)) + 1e-4; }, unit->numDofs()); - cadet::test::util::populate(yDot.data(), [](unsigned int idx) { return std::abs(std::sin(idx * 0.11)) + 2e-4; }, unit->numDofs()); +//TEST_CASE("LRM_DG forward sensitivity vs FD", "[LRM],[DG],[Sensitivity],[Simulation]") // todo fix tolerances (also for FV) +//{ +// // Relative error is checked first, we use high absolute error for letting +// // some points that are far off pass the error test, too. This is required +// // due to errors in finite differences. +// const double fdStepSize[] = { 5e-3, 5e-3, 5e-3, 1e-3 }; +// const double absTols[] = { 2e8, 8e-3, 2e-2, 3e-1 }; +// const double relTols[] = { 1e-1, 5e-1, 5e-2, 1e-2 }; +// const double passRatio[] = { 0.88, 0.84, 0.73, 0.87 }; +// cadet::test::column::testFwdSensSolutionFD("LUMPED_RATE_MODEL_WITHOUT_PORES", "DG", false, fdStepSize, absTols, relTols, passRatio); +//} + +//TEST_CASE("LRM_DG forward sensitivity forward vs backward flow", "[LRM],[DG],[Sensitivity],[Simulation]") // todo fix (also for FV) tolerances? why is there a pass ratio here, shouldnt this be precise? +//{ +// const double absTols[] = { 500.0, 8e-7, 9e-7, 2e-3 }; +// const double relTols[] = { 7e-3, 5e-5, 5e-5, 9e-4 }; +// const double passRatio[] = { 0.99, 0.97, 0.97, 0.98 }; +// cadet::test::column::testFwdSensSolutionForwardBackward("LUMPED_RATE_MODEL_WITHOUT_PORES", "DG", absTols, relTols, passRatio); +//} + +TEST_CASE("LRM_DG consistent initialization with linear binding", "[LRM],[DG],[ConsistentInit],[CI]") +{ + cadet::test::column::testConsistentInitializationLinearBinding("LUMPED_RATE_MODEL_WITHOUT_PORES", "DG", 1e-12, 1e-12); +} - const cadet::AdJacobianParams noAdParams{nullptr, nullptr, 0u}; - const cadet::ConstSimulationState simState{y.data(), yDot.data()}; +//TEST_CASE("LRM_DG consistent initialization with SMA binding", "[LRM],[DG],[ConsistentInit]") // todo fix (also for FV) +//{ +// std::vector y(4 + 16 * (4 + 4), 0.0); +// // Optimal values: +// // const double bindingCell[] = {1.2, 2.0, 1.0, 1.5, 858.034, 66.7896, 3.53273, 2.53153, +// // 1.0, 1.8, 1.5, 1.6, 856.173, 64.457, 5.73227, 2.85286}; +// const double bindingCell[] = { 1.2, 2.0, 1.0, 1.5, 840.0, 63.0, 3.0, 3.0, +// 1.0, 1.8, 1.5, 1.6, 840.0, 63.0, 6.0, 3.0 }; +// cadet::test::util::populate(y.data(), [](unsigned int idx) { return std::abs(std::sin(idx * 0.13)) + 1e-4; }, 4); +// cadet::test::util::repeat(y.data() + 4, bindingCell, 16, 8); +// +// cadet::test::column::testConsistentInitializationSMABinding("LUMPED_RATE_MODEL_WITHOUT_PORES", "DG", y.data(), 1e-14, 1e-5); +//} + +TEST_CASE("LRM_DG consistent sensitivity initialization with linear binding", "[LRM],[DG],[ConsistentInit],[Sensitivity],[CI]") +{ + // Fill state vector with given initial values + const unsigned int numDofs = 4 + 10 * (4 + 4); + std::vector y(numDofs, 0.0); + std::vector yDot(numDofs, 0.0); + cadet::test::util::populate(y.data(), [](unsigned int idx) { return std::abs(std::sin(idx * 0.13)) + 1e-4; }, numDofs); + cadet::test::util::populate(yDot.data(), [](unsigned int idx) { return std::abs(std::sin(idx * 0.9)) + 1e-4; }, numDofs); + + cadet::test::column::testConsistentInitializationSensitivity("LUMPED_RATE_MODEL_WITHOUT_PORES", "DG", y.data(), yDot.data(), true, 1e-14); +} - // Evaluate residual - const cadet::SimulationTime simTime{0.0, 0u}; - cadet::util::ThreadLocalStorage tls; - tls.resize(unit->threadLocalMemorySize()); +//// todo fix: sigsev read access violation when allocating _tempState = new double[numDofs()] in configure model discretization +//TEST_CASE("LRM_DG consistent sensitivity initialization with SMA binding", "[LRM],[DG],[ConsistentInit],[Sensitivity],[todo]") +//{ +// // Fill state vector with given initial values +// const unsigned int numDofs = 4 + 10 * (4 + 4); +// std::vector y(numDofs, 0.0); +// std::vector yDot(numDofs, 0.0); +// +// const double bindingCell[] = { 1.0, 1.8, 1.5, 1.6, 840.0, 63.0, 6.0, 3.0 }; +// cadet::test::util::populate(y.data(), [](unsigned int idx) { return std::abs(std::sin(idx * 0.13)) + 1e-4; }, 4); +// cadet::test::util::repeat(y.data() + 4, bindingCell, 8, 16); +// +// cadet::test::util::populate(yDot.data(), [](unsigned int idx) { return std::abs(std::sin(idx * 0.9)) + 1e-4; }, numDofs); +// +// cadet::test::column::testConsistentInitializationSensitivity("LUMPED_RATE_MODEL_WITHOUT_PORES", "DG", y.data(), yDot.data(), false, 1e-10); +//} + +TEST_CASE("LRM_DG inlet DOF Jacobian", "[LRM],[DG],[UnitOp],[Jacobian],[Inlet],[CI]") +{ + cadet::test::column::testInletDofJacobian("LUMPED_RATE_MODEL_WITHOUT_PORES", "DG"); +} - unit->residualWithJacobian(simTime, simState, res.data(), noAdParams, tls); +TEST_CASE("LRM_DG transport Jacobian", "[LRM],[FV],[UnitOp],[Jacobian],[CI]") +{ + cadet::JsonParameterProvider jpp = createColumnLinearBenchmark(false, true, "LUMPED_RATE_MODEL_WITHOUT_PORES", "DG"); + cadet::test::column::testJacobianAD(jpp, std::numeric_limits::epsilon() * 100.0); +} - mb->destroyUnitOperation(unit); - destroyModelBuilder(mb); +TEST_CASE("LRM_DG with two component linear binding Jacobian", "[LRM],[FV],[UnitOp],[Jacobian],[CI]") +{ + cadet::JsonParameterProvider jpp = createColumnWithTwoCompLinearBinding("LUMPED_RATE_MODEL_WITHOUT_PORES", "DG"); + cadet::test::column::testJacobianAD(jpp, std::numeric_limits::epsilon() * 100.0); } + +TEST_CASE("LRM_DG dynamic reactions Jacobian vs AD bulk", "[LRM],[DG],[Jacobian],[AD],[ReactionModel],[CI]") +{ + cadet::test::reaction::testUnitJacobianDynamicReactionsAD("LUMPED_RATE_MODEL_WITHOUT_PORES", "DG", true, false, false, std::numeric_limits::epsilon() * 100.0); +} + +TEST_CASE("LRM_DG dynamic reactions Jacobian vs AD modified bulk", "[LRM],[DG],[Jacobian],[AD],[ReactionModel],[CI]") +{ + cadet::test::reaction::testUnitJacobianDynamicReactionsAD("LUMPED_RATE_MODEL_WITHOUT_PORES", "DG", true, false, true, std::numeric_limits::epsilon() * 100.0); +} + +TEST_CASE("LRM_DG dynamic reactions time derivative Jacobian vs FD bulk", "[LRM],[DG],[Jacobian],[Residual],[ReactionModel],[CI]") +{ + cadet::test::reaction::testTimeDerivativeJacobianDynamicReactionsFD("LUMPED_RATE_MODEL_WITHOUT_PORES", "DG", true, false, false, 1e-6, 1e-14, 8e-4); +} + +TEST_CASE("LRM_DG dynamic reactions time derivative Jacobian vs FD modified bulk", "[LRM],[DG],[Jacobian],[Residual],[ReactionModel],[CI]") +{ + cadet::test::reaction::testTimeDerivativeJacobianDynamicReactionsFD("LUMPED_RATE_MODEL_WITHOUT_PORES", "DG", true, false, true, 1e-6, 1e-14, 8e-4); +} \ No newline at end of file diff --git a/test/ParticleHelper.cpp b/test/ParticleHelper.cpp index 11ea80303..5f3742ac4 100644 --- a/test/ParticleHelper.cpp +++ b/test/ParticleHelper.cpp @@ -97,7 +97,17 @@ namespace { auto ds = cadet::test::util::makeOptionalGroupScope(jpp, "discretization"); - replicateFieldDataInt(jpp, "NPAR", nTypes); + if(jpp.exists("SPATIAL_METHOD")) + if (jpp.getString("SPATIAL_METHOD") == "DG") + { + replicateFieldDataInt(jpp, "PAR_POLYDEG", nTypes); + replicateFieldDataInt(jpp, "PAR_NELEM", nTypes); + } + else + replicateFieldDataInt(jpp, "NPAR", nTypes); + else + replicateFieldDataInt(jpp, "NPAR", nTypes); + replicateFieldDataString(jpp, "PAR_DISC_TYPE", nTypes); replicateFieldDataDouble(jpp, "PAR_DISC_VECTOR", nTypes); } @@ -105,6 +115,7 @@ namespace replicateFieldDataDouble(jpp, "FILM_DIFFUSION", factors); replicateFieldDataDouble(jpp, "PAR_DIFFUSION", factors); replicateFieldDataDouble(jpp, "PAR_SURFDIFFUSION", factors); + replicateFieldDataDouble(jpp, "PAR_GEOM", factors); replicateFieldDataDouble(jpp, "PAR_RADIUS", factors); replicateFieldDataDouble(jpp, "PAR_CORERADIUS", factors); replicateFieldDataDouble(jpp, "PAR_POROSITY", factors); @@ -191,7 +202,10 @@ namespace particle unsigned int nRad = 1; { auto ds = cadet::test::util::makeOptionalGroupScope(jpp, "discretization"); - nCol = jpp.getInt("NCOL"); + if (jpp.exists("SPATIAL_METHOD")) + nCol = jpp.getString("SPATIAL_METHOD") == "DG" ? (jpp.getInt("POLYDEG") + 1) * jpp.getInt("NELEM") : jpp.getInt("NCOL"); + else + nCol = jpp.getInt("NCOL"); if (jpp.exists("NRAD")) nRad = jpp.getInt("NRAD"); @@ -368,22 +382,22 @@ namespace particle testLinearMixedParticleTypesImpl(jpp, absTol, relTol, [](cadet::JsonParameterProvider& jpp) { scrambleParticleTypeFractionsSpatially(jpp, 3); }); } - void testJacobianMixedParticleTypes(const std::string& uoType, const std::string& spatialMethod) + void testJacobianMixedParticleTypes(const std::string& uoType, const std::string& spatialMethod, const double absTolFDpattern) { cadet::JsonParameterProvider jpp = createColumnWithTwoCompLinearBinding(uoType, spatialMethod); - testJacobianMixedParticleTypes(jpp); + testJacobianMixedParticleTypes(jpp, absTolFDpattern); } - void testJacobianMixedParticleTypes(cadet::JsonParameterProvider& jpp) + void testJacobianMixedParticleTypes(cadet::JsonParameterProvider& jpp, const double absTolFDpattern) { // Add more particle types (such that we have a total of 3 types) const double volFrac[] = {0.3, 0.6, 0.1}; extendModelToManyParticleTypes(jpp, {0.9, 0.8}, volFrac); - unitoperation::testJacobianAD(jpp); + unitoperation::testJacobianAD(jpp, absTolFDpattern); } - void testJacobianSpatiallyMixedParticleTypes(const std::string& uoType, const std::string& spatialMethod) + void testJacobianSpatiallyMixedParticleTypes(const std::string& uoType, const std::string& spatialMethod, const double absTolFDpattern) { cadet::JsonParameterProvider jpp = createColumnWithTwoCompLinearBinding(uoType, spatialMethod); @@ -393,7 +407,7 @@ namespace particle // Spatially inhomogeneous scrambleParticleTypeFractionsSpatially(jpp, 3); - unitoperation::testJacobianAD(jpp); + unitoperation::testJacobianAD(jpp, absTolFDpattern); } void testTimeDerivativeJacobianMixedParticleTypesFD(const std::string& uoType, const std::string& spatialMethod, double h, double absTol, double relTol) diff --git a/test/ParticleHelper.hpp b/test/ParticleHelper.hpp index 9b24f6922..666eceb37 100644 --- a/test/ParticleHelper.hpp +++ b/test/ParticleHelper.hpp @@ -170,8 +170,9 @@ namespace particle /** * @brief Checks the full analytic Jacobian against AD for a model with multiple particle types * @param [in] jpp Unit operation configuration + * @param [in] absTolFDpattern absolute tolerance when comparing the sign in the FD Jacobian pattern */ - void testJacobianMixedParticleTypes(cadet::JsonParameterProvider& jpp); + void testJacobianMixedParticleTypes(cadet::JsonParameterProvider& jpp, const double absTolFDpattern = 0.0); /** * @brief Checks whether a linear binding model with multiple identical particle types produces the same as result as a single type model @@ -190,14 +191,16 @@ namespace particle /** * @brief Checks the full analytic Jacobian against AD for a model with multiple particle types * @param [in] uoType Unit operation type + * @param [in] absTolFDpattern absolute tolerance when comparing the sign in the FD Jacobian pattern */ - void testJacobianMixedParticleTypes(const std::string& uoType, const std::string& spatialMethod); + void testJacobianMixedParticleTypes(const std::string& uoType, const std::string& spatialMethod, const double absTolFDpattern = 0.0); /** * @brief Checks the full analytic Jacobian against AD for a model with multiple particle types and spatial dependence of volume fractions * @param [in] uoType Unit operation type + * @param [in] absTolFDpattern absolute tolerance when comparing the sign in the FD Jacobian pattern */ - void testJacobianSpatiallyMixedParticleTypes(const std::string& uoType, const std::string& spatialMethod); + void testJacobianSpatiallyMixedParticleTypes(const std::string& uoType, const std::string& spatialMethod, const double absTolFDpattern = 0.0); /** * @brief Checks the (analytic) time derivative Jacobian against FD for a model with multiple particle types diff --git a/test/RadialGeneralRateModel.cpp b/test/RadialGeneralRateModel.cpp index 7d36538e4..9d6fef722 100644 --- a/test/RadialGeneralRateModel.cpp +++ b/test/RadialGeneralRateModel.cpp @@ -32,7 +32,8 @@ TEST_CASE("Radial GRM numerical Benchmark with parameter sensitivities for linea const std::string& refFilePath = std::string("/data/ref_radGRM_dynLin_1comp_sensbenchmark1_FV_Z32parZ4.h5"); const std::vector absTol = { 1e-12, 1e-12, 1e-12, 1e-12 }; const std::vector relTol = { 1e-6, 1e-6, 1e-6, 1e-6 }; - cadet::test::column::testReferenceBenchmark(modelFilePath, refFilePath, "001", absTol, relTol, 32, 4, true); + cadet::test::column::FVparams disc(32, 4); + cadet::test::column::testReferenceBenchmark(modelFilePath, refFilePath, "001", absTol, relTol, disc, true); } TEST_CASE("Radial GRM transport Jacobian", "[RadGRM],[UnitOp],[Jacobian],[CI]") diff --git a/test/RadialLumpedRateModelWithPores.cpp b/test/RadialLumpedRateModelWithPores.cpp index 1bbb91852..d5db18a4e 100644 --- a/test/RadialLumpedRateModelWithPores.cpp +++ b/test/RadialLumpedRateModelWithPores.cpp @@ -32,7 +32,8 @@ TEST_CASE("Radial LRMP numerical Benchmark with parameter sensitivities for line const std::string& refFilePath = std::string("/data/ref_radLRMP_dynLin_1comp_sensbenchmark1_FV_Z32.h5"); const std::vector absTol = { 1e-12, 1e-12, 1e-12, 1e-12 }; const std::vector relTol = { 1e-6, 1e-6, 1e-6, 1e-6 }; - cadet::test::column::testReferenceBenchmark(modelFilePath, refFilePath, "001", absTol, relTol, 32, 0, true); + cadet::test::column::FVparams disc(32); + cadet::test::column::testReferenceBenchmark(modelFilePath, refFilePath, "001", absTol, relTol, disc, true); } TEST_CASE("Radial LRMP transport Jacobian", "[RadLRMP],[UnitOp],[Jacobian],[CI]") diff --git a/test/RadialLumpedRateModelWithoutPores.cpp b/test/RadialLumpedRateModelWithoutPores.cpp index d7dab177d..2b983d095 100644 --- a/test/RadialLumpedRateModelWithoutPores.cpp +++ b/test/RadialLumpedRateModelWithoutPores.cpp @@ -31,7 +31,8 @@ TEST_CASE("Radial LRM numerical Benchmark with parameter sensitivities for linea const std::string& refFilePath = std::string("/data/ref_radLRM_dynLin_1comp_sensbenchmark1_FV_Z32.h5"); const std::vector absTol = { 1e-12, 1e-12, 1e-12, 1e-12 }; const std::vector relTol = { 1e-5, 1e-6, 1e-6, 1e-6 }; - cadet::test::column::testReferenceBenchmark(modelFilePath, refFilePath, "001", absTol, relTol, 32, 0, false); + cadet::test::column::FVparams disc(32); + cadet::test::column::testReferenceBenchmark(modelFilePath, refFilePath, "001", absTol, relTol, disc, false); } TEST_CASE("Radial LRM transport Jacobian", "[RadLRM],[UnitOp],[Jacobian],[CI]") diff --git a/test/ReactionModelTests.cpp b/test/ReactionModelTests.cpp index d77f52851..dbdc6be70 100644 --- a/test/ReactionModelTests.cpp +++ b/test/ReactionModelTests.cpp @@ -411,16 +411,16 @@ namespace reaction } } - void testUnitJacobianDynamicReactionsAD(cadet::JsonParameterProvider& jpp, bool bulk, bool particle, bool particleModifiers) + void testUnitJacobianDynamicReactionsAD(cadet::JsonParameterProvider& jpp, bool bulk, bool particle, bool particleModifiers, const double absTolFDpattern) { extendModelWithDynamicReactions(jpp, 0, bulk, particle, particleModifiers); - unitoperation::testJacobianAD(jpp); + unitoperation::testJacobianAD(jpp, absTolFDpattern); } - void testUnitJacobianDynamicReactionsAD(const std::string& uoType, const std::string& spatialMethod, bool bulk, bool particle, bool particleModifiers) + void testUnitJacobianDynamicReactionsAD(const std::string& uoType, const std::string& spatialMethod, bool bulk, bool particle, bool particleModifiers, const double absTolFDpattern) { cadet::JsonParameterProvider jpp = createColumnWithTwoCompLinearBinding(uoType, spatialMethod); - testUnitJacobianDynamicReactionsAD(jpp, bulk, particle, particleModifiers); + testUnitJacobianDynamicReactionsAD(jpp, bulk, particle, particleModifiers, absTolFDpattern); } void testTimeDerivativeJacobianDynamicReactionsFD(cadet::JsonParameterProvider& jpp, bool bulk, bool particle, bool particleModifiers, double h, double absTol, double relTol) diff --git a/test/ReactionModelTests.hpp b/test/ReactionModelTests.hpp index b4c28650d..8680b6430 100644 --- a/test/ReactionModelTests.hpp +++ b/test/ReactionModelTests.hpp @@ -133,8 +133,9 @@ namespace reaction * @param [in] bulk Determines whether reactions are added to bulk volume * @param [in] particle Determines whether reactions are added to each particle type * @param [in] particleModifiers Determines whether reaction rates in particles are modified by the respective other phase + * @param [in] absTolFDpattern absolute tolerance when comparing the sign in the FD Jacobian pattern */ - void testUnitJacobianDynamicReactionsAD(cadet::JsonParameterProvider& jpp, bool bulk, bool particle, bool particleModifiers); + void testUnitJacobianDynamicReactionsAD(cadet::JsonParameterProvider& jpp, bool bulk, bool particle, bool particleModifiers, const double absTolFDpattern=0.0); /** * @brief Checks the full analytic Jacobian of a unit operation model with dynamic reactions against AD @@ -143,8 +144,9 @@ namespace reaction * @param [in] bulk Determines whether reactions are added to bulk volume * @param [in] particle Determines whether reactions are added to each particle type * @param [in] particleModifiers Determines whether reaction rates in particles are modified by the respective other phase + * @param [in] absTolFDpattern absolute tolerance when comparing the sign in the FD Jacobian pattern */ - void testUnitJacobianDynamicReactionsAD(const std::string& uoType, const std::string& spatialMethod, bool bulk, bool particle, bool particleModifiers); + void testUnitJacobianDynamicReactionsAD(const std::string& uoType, const std::string& spatialMethod, bool bulk, bool particle, bool particleModifiers, const double absTolFDpattern = 0.0); /** * @brief Checks the (analytic) time derivative Jacobian against FD for a model with dynamic reactions diff --git a/test/UnitOperationTests.cpp b/test/UnitOperationTests.cpp index 8e3aac8ff..df1ef2e89 100644 --- a/test/UnitOperationTests.cpp +++ b/test/UnitOperationTests.cpp @@ -62,7 +62,7 @@ namespace unitoperation return unit; } - void testJacobianAD(cadet::JsonParameterProvider& jpp) + void testJacobianAD(cadet::JsonParameterProvider& jpp, const double absTolFDpattern) { cadet::IModelBuilder* const mb = cadet::createModelBuilder(); REQUIRE(nullptr != mb); @@ -104,8 +104,8 @@ namespace unitoperation std::fill(jacDir.begin(), jacDir.end(), 0.0); // Compare Jacobians - cadet::test::checkJacobianPatternFD(unitAna, unitAD, y.data(), nullptr, jacDir.data(), jacCol1.data(), jacCol2.data(), tls); - cadet::test::checkJacobianPatternFD(unitAna, unitAna, y.data(), nullptr, jacDir.data(), jacCol1.data(), jacCol2.data(), tls); + cadet::test::checkJacobianPatternFD(unitAna, unitAD, y.data(), nullptr, jacDir.data(), jacCol1.data(), jacCol2.data(), tls, absTolFDpattern); + cadet::test::checkJacobianPatternFD(unitAna, unitAna, y.data(), nullptr, jacDir.data(), jacCol1.data(), jacCol2.data(), tls, absTolFDpattern); cadet::test::compareJacobian(unitAna, unitAD, nullptr, nullptr, jacDir.data(), jacCol1.data(), jacCol2.data()); // cadet::test::compareJacobianFD(unitAna, unitAD, y.data(), nullptr, jacDir.data(), jacCol1.data(), jacCol2.data()); diff --git a/test/UnitOperationTests.hpp b/test/UnitOperationTests.hpp index 054dbde43..b3e4c76ca 100644 --- a/test/UnitOperationTests.hpp +++ b/test/UnitOperationTests.hpp @@ -52,8 +52,9 @@ namespace unitoperation /** * @brief Checks the full analytic Jacobian against AD for a given model * @param [in] jpp Unit operation configuration + * @param [in] absTolFDpattern absolute tolerance when comparing the sign in the FD Jacobian pattern */ - void testJacobianAD(cadet::JsonParameterProvider& jpp); + void testJacobianAD(cadet::JsonParameterProvider& jpp, const double absTolFDpattern=0.0); /** * @brief Checks the (analytic) time derivative Jacobian against FD for a given model diff --git a/test/data/ref_GRM_dynLin_1comp_sensbenchmark1_cDG_P3Z8_GSM_parP3parZ1.h5 b/test/data/ref_GRM_dynLin_1comp_sensbenchmark1_cDG_P3Z8_GSM_parP3parZ1.h5 new file mode 100644 index 000000000..3023fac7f Binary files /dev/null and b/test/data/ref_GRM_dynLin_1comp_sensbenchmark1_cDG_P3Z8_GSM_parP3parZ1.h5 differ diff --git a/test/data/ref_GRM_reqSMA_4comp_sensbenchmark1_cDG_P3Z8_GSM_parP3parZ1.h5 b/test/data/ref_GRM_reqSMA_4comp_sensbenchmark1_cDG_P3Z8_GSM_parP3parZ1.h5 new file mode 100644 index 000000000..2d432841f Binary files /dev/null and b/test/data/ref_GRM_reqSMA_4comp_sensbenchmark1_cDG_P3Z8_GSM_parP3parZ1.h5 differ diff --git a/test/data/ref_LRMP_dynLin_1comp_sensbenchmark1_DG_P3Z8.h5 b/test/data/ref_LRMP_dynLin_1comp_sensbenchmark1_DG_P3Z8.h5 new file mode 100644 index 000000000..44993a7e2 Binary files /dev/null and b/test/data/ref_LRMP_dynLin_1comp_sensbenchmark1_DG_P3Z8.h5 differ diff --git a/test/data/ref_LRMP_reqSMA_4comp_sensbenchmark1_DG_P3Z8.h5 b/test/data/ref_LRMP_reqSMA_4comp_sensbenchmark1_DG_P3Z8.h5 new file mode 100644 index 000000000..5f997c430 Binary files /dev/null and b/test/data/ref_LRMP_reqSMA_4comp_sensbenchmark1_DG_P3Z8.h5 differ diff --git a/test/data/ref_LRM_dynLin_1comp_sensbenchmark1_DG_P3Z8.h5 b/test/data/ref_LRM_dynLin_1comp_sensbenchmark1_DG_P3Z8.h5 new file mode 100644 index 000000000..6c78a6df7 Binary files /dev/null and b/test/data/ref_LRM_dynLin_1comp_sensbenchmark1_DG_P3Z8.h5 differ diff --git a/test/data/ref_LRM_reqSMA_4comp_sensbenchmark1_DG_P3Z8.h5 b/test/data/ref_LRM_reqSMA_4comp_sensbenchmark1_DG_P3Z8.h5 new file mode 100644 index 000000000..bbfcb7852 Binary files /dev/null and b/test/data/ref_LRM_reqSMA_4comp_sensbenchmark1_DG_P3Z8.h5 differ diff --git a/test/data/ref_LRM_reqSMA_4comp_sensbenchmark1_FV_Z32.h5 b/test/data/ref_LRM_reqSMA_4comp_sensbenchmark1_FV_Z32.h5 index b1a4b7f9b..339298f14 100644 Binary files a/test/data/ref_LRM_reqSMA_4comp_sensbenchmark1_FV_Z32.h5 and b/test/data/ref_LRM_reqSMA_4comp_sensbenchmark1_FV_Z32.h5 differ