### Merge branch 'water-content-as-initial-condition' into...

Merge branch 'water-content-as-initial-condition' into 127-add-data-assimilation-interface-to-richardssimulation
parents a81e1c9c 4cccaabc
 ... ... @@ -31,16 +31,16 @@ They are controlled by the initial.type key and available for every model. * type = analytic An analytic function :math:f(\vec{p}) which depends on the physical position :math:\vec{p}. The function must be defined via the key An analytic function :math:f(\mathbf{p}) which depends on the physical position :math:\mathbf{p}. The function must be defined via the key initial.equation. For parsing the input expression, we use muparser_ which supports a set of common mathematical functions. Additionally, the following variables can be used: Available variables: * x: X-coordinate :math:p_1 \, [\mathrm{m}]. * y: Y-coordinate :math:p_2 \, [\mathrm{m}]. * z: Z-coordinate :math:p_3 \, [\mathrm{m}] (only in 3D). * x: X-coordinate :math:p_1 \, [\text{m}]. * y: Y-coordinate :math:p_2 \, [\text{m}]. * z: Z-coordinate :math:p_3 \, [\text{m}] (only in 3D). * h: Height above origin. Synonymous to y in 2D and z in 3D. * pi: Mathematical constant :math:\pi. * dim: Number of physical dimensions. ... ... @@ -50,8 +50,9 @@ They are controlled by the initial.type key and available for every model. :ref:initial-transformation), typical initial conditions for a Richards simulation are * Hydrostatic equilibrium: A vertical gradient of :math:-1 and a fixed value  at height :math:h = 0 \, \mathrm{m}:: * Hydrostatic equilibrium: A vertical gradient of :math:\partial_h h_m = -1 and a fixed value  at height :math:h = 0 \, \text{m}: initial.equation = -h + ... ... @@ -59,7 +60,7 @@ They are controlled by the initial.type key and available for every model. .. tip:: The expression for a gaussian pulse of solute concentration centered at :math:\vec{p} = [0.5, 0.5]^T \, \mathrm{m} is:: :math:\mathbf{p} = [0.5, 0.5]^T \, \text{m} is:: initial.equation = exp(-sqrt((x-0.5)^2+(y-0.5)^2)/(4.*0.002))/(4*pi*0.002)^(2/dim). ... ... @@ -97,7 +98,22 @@ Initial condition tranformations for the Richards solver. * quantity = matricHead The input data is directly interpreted as matric head :math:f = h_m [\mathrm{m}]. :math:f = h_m \, [\text{m}]. .. object:: Water Content to Matric Head * quantity = waterContent The input data is interpreted as water content, :math:f = \theta_w \, [\text{-}], and transformed into matric head via the :doc:parameterization  of the medium. Values greater than the porosity :math:\phi and less than the residual water content :math:\theta_r are automatically clamped to fit the allowed range. Additionally, any input value :math:f(x_0) at some position :math:x_0 on the grid will result in a saturation greater zero, :math:\Theta (x_0) > 0, to avoid divergence of the matric head towards negative infinity. Transport ^^^^^^^^^ ... ... @@ -108,7 +124,7 @@ Initial condition tranformations for the Transport solver. * quantity = soluteConcentration The input data is directly interpreted as solute concentration, :math:f = c_w [\mathrm{kg}/\mathrm{m}^3]. :math:f = c_w [\text{kg}/\text{m}^3]. .. _H5: https://www.h5py.org/ .. _muparser: http://beltoforion.de/article.php?a=muparser&p=features
 ... ... @@ -34,7 +34,7 @@ protected: std::shared_ptr log=get_logger(log_base) ) { std::unique_ptr> ic; std::shared_ptr> ic; auto ic_type = ini_file.get("initial.type"); log->debug("Creating initial condition of type: {}", ic_type); ... ... @@ -56,7 +56,7 @@ protected: const auto file_type = ic_datafile.substr(ext_start + 1); if (file_type == "h5") { using ICH5 = InitialConditionH5; ic = std::make_unique(grid_view, ini_file, log); ic = std::make_shared(grid_view, ini_file, log); } else if (file_type == "vtu") { DUNE_THROW(NotImplemented, ... ... @@ -73,7 +73,7 @@ protected: auto equation_str = ini_file.get("initial.equation"); using ICAnalytic = InitialConditionAnalytic; ic = std::make_unique(log,grid_view,equation_str); ic = std::make_shared(log,grid_view,equation_str); } else { log->error("Unsupported initial condition type: {}", ic_type); ... ...
 ... ... @@ -7,28 +7,70 @@ #include #include #include namespace Dune { namespace Dorie { /// Transforms water content into matric head, serving as initial condition template class WaterContentInitialCondition : public InitialConditionTransformation { public: using ICTransf = InitialConditionTransformation; using GFTraits = typename ICTransf::Traits; using Base = InitialCondition; protected: using GV = typename ICTransf::GV; using MHA = MatricHeadAdapter; public: /// Construct the transformation from a grid view and an initial condition WaterContentInitialCondition (const Dune::ParameterTree& config, const GV& grid_view, std::shared_ptr ic, const std::shared_ptr param ): ICTransf(grid_view, ic), _adapter(std::make_shared(config, grid_view, ic, param)) { } void evaluate ( const typename GFTraits::ElementType& e, const typename GFTraits::DomainType& x, typename GFTraits::RangeType& y) const override { _adapter->evaluate(e, x, y); }; private: std::shared_ptr _adapter; }; /// An initial condition factory for the Richards solver /** * \tparam T Traits * \tparam Traits * \tparam Param * * \ingroup InitialConditions * \author Lukas Riedel * \date 2019 */ template class RichardsInitialConditionFactory : public InitialConditionFactory template class RichardsInitialConditionFactory : public InitialConditionFactory { private: using Base = InitialConditionFactory; using Base = InitialConditionFactory; public: /// Create an initial condition for the Richards solver static std::unique_ptr> create ( static std::shared_ptr> create ( const Dune::ParameterTree& config, const typename T::GridView& grid_view, const typename Traits::GridView& grid_view, const std::shared_ptr param, const std::shared_ptr log=get_logger(log_richards) ) { ... ... @@ -37,6 +79,14 @@ public: if (quantity == "matricHead") { return Base::create(config, grid_view, log); } else if (quantity == "waterContent") { // create initial condition grid function from input data auto ic_gf = Base::create(config, grid_view, log); // plug into adapter using WCIC = WaterContentInitialCondition; return std::make_shared(config, grid_view, ic_gf, param); } else { log->error("Unsupported quantity for initial condition: {}", quantity); ... ...
 ... ... @@ -53,7 +53,7 @@ RichardsSimulation::RichardsSimulation ( // --- Operator Helper Classes --- fboundary = std::make_shared(inifile); fsource = std::make_shared(inifile); finitial = FlowInitialFactory::create(inifile, gv, this->_log); finitial = FlowInitialFactory::create(inifile, gv, fparam, this->_log); // --- Local Operators --- #ifdef EXPERIMENTAL_DG_FEATURES ... ...
 ... ... @@ -86,7 +86,9 @@ struct RichardsSimulationTraits : public BaseTraits /// Class defining the initial condition using FlowInitial = Dune::Dorie::InitialCondition; /// Class defining the initial condition factory using FlowInitialFactory = Dune::Dorie::RichardsInitialConditionFactory; using FlowInitialFactory = Dune::Dorie::RichardsInitialConditionFactory< BaseTraits, FlowParameters>; /// Local spatial operator using SLOP = Dune::Dorie::Operator::RichardsDGSpatialOperator; /// Local temporal operator ... ... @@ -296,7 +298,7 @@ protected: std::shared_ptr fparam; std::shared_ptr fboundary; std::shared_ptr fsource; std::unique_ptr finitial; std::shared_ptr finitial; std::unique_ptr controller; std::unique_ptr slop; ... ...
 ... ... @@ -26,7 +26,7 @@ private: public: /// Create an initial condition for the Richards solver static std::unique_ptr> create ( static std::shared_ptr> create ( const Dune::ParameterTree& config, const typename T::GridView& grid_view, const std::shared_ptr log=get_logger(log_transport) ... ...
 ... ... @@ -290,7 +290,7 @@ protected: std::shared_ptr sparam; std::shared_ptr sboundary; std::unique_ptr sinitial; std::shared_ptr sinitial; std::unique_ptr controller; std::unique_ptr slop; ... ...
 ... ... @@ -45,12 +45,19 @@ add_custom_target(test_grid_creator ) add_dependencies(test_grid_creator prepare_testing) # initial condition test # initial condition tests dorie_add_metaini_test( UNIT_TEST SOURCE test-initial-condition.cc BASENAME test-initial-condition METAINI test-initial-condition.mini.in SOURCE test-initial-condition-richards.cc BASENAME test-initial-condition-richards METAINI test-initial-condition-richards.mini.in CREATED_TARGETS ic_target ) dorie_add_metaini_test( UNIT_TEST SOURCE test-initial-condition-transport.cc BASENAME test-initial-condition-transport METAINI test-initial-condition-transport.mini.in CREATED_TARGETS ic_target ) ... ...
 #ifdef HAVE_CONFIG_H #include "config.h" #endif #include #include #include #include #include "test-initial-condition.hh" /// Test the basic initial conditions (without transformation) /** \tparam T Traits * \tparam IFC InitialConditionFactory */ template void test_ic_base (const std::shared_ptr grid, const Dune::ParameterTree config, const std::shared_ptr param) { // create the initial condition const auto ic = ICF::create(config, grid->leafGridView(), param); const auto type = config.get("initial.type"); if (type == "analytic") { // define testing function const auto equation = config.get("initial.equation"); assert(equation == "-1+2*y"); auto test_f = [](const auto e, const auto x){ using Range = typename T::Scalar; constexpr int dim = T::Grid::dimension; const auto x_global = e.geometry().global(x); Range y = -1.0 + x_global[dim-1] * 2.0; return y; }; test_ic_against_function(grid, ic, test_f); } else if (type == "file") { const auto dataset = config.get("initial.dataset"); // define testing function auto test_f = [&dataset](const auto e, const auto x){ typename T::Scalar y; if (dataset == "twos") // case: matric head input y = 2.0; else if (dataset == "ones") // case: water content input y = 0.0; return y; }; test_ic_against_function(grid, ic, test_f); } } int main (int argc, char** argv) { try{ // Initialize ALL the things! auto [inifile, log, helper] = Dune::Dorie::Setup::init(argc, argv); // create the grid Dune::Dorie::GridCreator::Grid> gc(inifile, helper); auto grid = gc.grid(); const auto index_map = gc.element_index_map(); // fetch config for Richards auto config = Dune::Dorie::Setup::prep_ini_for_richards(inifile); // create the Richards logger const auto log_level = config.get("output.logLevel"); auto _log = Dune::Dorie::create_logger( Dune::Dorie::log_richards, helper, spdlog::level::from_str(log_level)); // create Richards parameterization using Param = Dune::Dorie::FlowParameters>; auto param = std::make_shared(config, grid, index_map); // initial condition factory using T = Traits<2>; using ICF = Dune::Dorie::RichardsInitialConditionFactory; const auto quantity = config.get("initial.quantity"); if (quantity == "matricHead" || quantity == "waterContent") { test_ic_base(grid, config, param); } else { log->error("Unsupported quantity for initial condition test: {}", quantity); DUNE_THROW(Dune::NotImplemented, "Unsupported initial condition " "quantity"); } return 0; } catch (Dune::Exception &e) { std::cerr << "Dune reported error: " << e << std::endl; return 1; } catch (std::exception &e) { std::cerr << "Exception thrown: " << e.what() << std::endl; return 1; } catch (...) { std::cerr << "Unknown exception!" << std::endl; return 1; } }
 include ${CMAKE_BINARY_DIR}/doc/default_files/config.ini _initial_type = analytic, data | expand _quantity = matricHead, waterContent | expand quantity_type {_quantity} == waterContent and {_initial_type} == analytic | exclude __name = ic-richards-{_initial_type}-{_quantity} _asset_path = "${PROJECT_SOURCE_DIR}/test" [grid] dimensions = 2 initialLevel = 1 gridType = rectangular cells = 50 50 extensions = 1 1 [grid.mapping] file = none [richards.initial] type = {_initial_type} quantity = {_quantity} file = ${CMAKE_CURRENT_LIST_DIR}/scaling.h5 dataset = twos interpolation = nearest equation = -1+2*y [richards.parameters] file = test-parameterization-unscaled.yml  ... ... @@ -2,53 +2,12 @@ #include "config.h" #endif #include #include #include #include #include #include #include #include /// Traits stub used for this test template struct Traits { static constexpr int dim = d; using Grid = Dune::YaspGrid; using GridView = typename Grid::LeafGridView; using GV = GridView; using DF = typename Grid::ctype; using Domain = Dune::FieldVector; using RF = double; using Scalar = Dune::FieldVector; }; /// Test an initial condition against a lambda function on the grid template void test_ic_against_function ( const std::shared_ptr grid, const std::unique_ptr& ic, const Function func ) { using Range = typename IC::Traits::RangeType; using namespace Dune::FloatCmp; // iterate over the grid vertices for (auto&& e : Dune::elements(grid->leafGridView())) { Range y; const auto x = e.geometry().local(e.geometry().center()); ic->evaluate(e, x, y); assert(eq(func(e, x), y)); } } #include "test-initial-condition.hh" /// Test the basic initial conditions (without transformation) /** \tparam T Traits ... ... @@ -97,53 +56,26 @@ int main (int argc, char** argv) auto grid = gc.grid(); const auto index_map = gc.element_index_map(); { auto config = Dune::Dorie::Setup::prep_ini_for_richards(inifile); auto config = Dune::Dorie::Setup::prep_ini_for_transport(inifile); // initial condition factory using T = Traits<2>; using ICF = Dune::Dorie::RichardsInitialConditionFactory; // initial condition factory using T = Traits<2>; using ICF = Dune::Dorie::TransportInitialConditionFactory; // create the Richards logger const auto log_level = config.get("output.logLevel"); auto _log = Dune::Dorie::create_logger(Dune::Dorie::log_richards, helper,spdlog::level::from_str(log_level)); // create the transport logger const auto log_level = config.get("output.logLevel"); // FIXME auto _log = Dune::Dorie::create_logger(Dune::Dorie::log_transport, helper/*,spdlog::level::from_str(log_level)*/); const auto quantity = config.get("initial.quantity"); if (quantity == "matricHead") { test_ic_base(grid, config); } else { log->error("Unsupported quantity for initial condition test: {}", quantity); DUNE_THROW(Dune::NotImplemented, "Unsupported initial condition " "quantity"); } const auto quantity = config.get("initial.quantity"); if (quantity == "soluteConcentration") { test_ic_base(grid, config); } { // auto config = Dune::Dorie::Setup::prep_ini_for_transport(inifile); // FIXME auto config = inifile.sub("transport"); // initial condition factory using T = Traits<2>; using ICF = Dune::Dorie::TransportInitialConditionFactory; // create the transport logger // const auto log_level = config.get("output.logLevel"); // FIXME auto _log = Dune::Dorie::create_logger(Dune::Dorie::log_transport, helper/*,spdlog::level::from_str(log_level)*/); const auto quantity = config.get("initial.quantity"); if (quantity == "soluteConcentration") { test_ic_base(grid, config); } else { log->error("Unsupported quantity for initial condition test: {}", quantity); DUNE_THROW(Dune::NotImplemented, "Unsupported initial condition " "quantity"); } else { log->error("Unsupported quantity for initial condition test: {}", quantity); DUNE_THROW(Dune::NotImplemented, "Unsupported initial condition " "quantity"); } return 0; ... ...  include${CMAKE_BINARY_DIR}/doc/default_files/config.ini _initial_type = analytic, data | expand __name = {_initial_type} __name = ic-transport-{_initial_type} _asset_path = "${PROJECT_SOURCE_DIR}/test" [grid] ... ... @@ -14,16 +14,6 @@ extensions = 1 1 [grid.mapping] file = none [richards.initial] type = {_initial_type} quantity = matricHead file =${CMAKE_CURRENT_LIST_DIR}/scaling.h5 dataset = twos interpolation = nearest equation = -1+2*y [transport.initial] type = {_initial_type} quantity = soluteConcentration ... ...
 #include #include #include #include #include #include /// Traits stub used for this test template struct Traits { static constexpr int dim = d; using Grid = Dune::YaspGrid; using GridView = typename Grid::LeafGridView; using GV = GridView; using DF = typename Grid::ctype; using Domain = Dune::FieldVector; using RF = double; using Scalar = Dune::FieldVector; using Vector = Domain; }; /// Test an initial condition against a lambda function on the grid template void test_ic_against_function ( const std::shared_ptr grid, const std::shared_ptr& ic, const Function func ) { using Range = typename IC::Traits::RangeType; using namespace Dune::FloatCmp; // iterate over the grid vertices for (auto&& e : elements(grid->leafGridView())) { Range y; const auto x = e.geometry().local(e.geometry().center()); ic->evaluate(e, x, y); assert(eq(func(e, x), y)); } }
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!