diff --git a/.patches/exercise-runtimeparams/exercise-runtimeparams.patch b/.patches/exercise-runtimeparams/exercise-runtimeparams.patch index fc625c9bb65b8f52fc5a5f9e33249d539e7f0880..ef881c7aef33c834ea1f62c67c6605acb9eda29b 100644 --- a/.patches/exercise-runtimeparams/exercise-runtimeparams.patch +++ b/.patches/exercise-runtimeparams/exercise-runtimeparams.patch @@ -98,19 +98,20 @@ diff -ruN exercises/exercise-runtimeparams/README.md exercises/solution/exercise +++ exercises/solution/exercise-runtimeparams/README.md 1970-01-01 01:00:00.000000000 +0100 @@ -1,171 +0,0 @@ -# Exercise Runtime Parameters (DuMuX course) --<br> +- - -## Problem set-up - -Here we will expand on what we've covered in the basics exercise (see `dumux-course/exercises/exercise-basic/README.md`), and the problem set up will remain the same. - +- -## Preparing the exercise - -Navigate to the directory `dumux-course/exercises/exercise-runtimeparams/` - --<br><br> --### Task 1: Understanding Input Parameters --<hr> +- +-## Task 1: Understanding Input Parameters +- -For this task we will edit the following files: - -* The shared __problem file__: `problem.hh` @@ -140,23 +141,23 @@ diff -ruN exercises/exercise-runtimeparams/README.md exercises/solution/exercise -[SpatialParams] -PermeabilityAquitard = 1e-15 # m^2 -Aquitard.BrooksCoreyPcEntry = 4.5e4 # Pa --PermeabilityAquifer = 1e-12 # m^2 --Aquifer.BrooksCoreyPcEntry = 1e4 # Pa +-Aquitard.BrooksCoreyLambda = 2.0 +-Aquitard.Swr = 0.2 +-Aquitard.Snr = 0.0 -``` -When a parameter is defined directly within your program, you'll need to recompile your program every time you change the value. When a parameter is passed via the input file, this is not the case. If we decided to vary the entry pressure in our geologic units a few times via the parameters listed above, there would be no need to recompile between simulation runs. - -* > __Task 1__: Change the aquitard's entry pressure in the input file to a lower value and compare the results with the previous solution. You do not need to recompile the executable. - --<br><br> --### Task 2: Setting a variable to collect a runtime parameter --<hr> +- +-## Task 2: Setting a variable to collect a runtime parameter - -Let's free one of the variables in this exercise. Within the class `problem.hh`, in the first line of the Neumann boundary condition definition function `neumannAtPos(...)`, the injection rate is defined as $`1.0 \cdot 10^{-4} kg s^{-1} m^{-2}`$. - -```c++ -// inject nitrogen. negative values mean injection -// units kg/(s*m^2) --values[Indices::conti0EqIdx + FluidSystem::N2Idx]= -1e-4/FluidSystem::molarMass(FluidSystem::N2Idx); +-values[Indices::conti0EqIdx + FluidSystem::N2Idx]= -1e-4; -values[Indices::conti0EqIdx + FluidSystem::H2OIdx] = 0.0; -``` - @@ -205,7 +206,7 @@ diff -ruN exercises/exercise-runtimeparams/README.md exercises/solution/exercise -* > __Task 2__: The goal is to replace the value `-1e-4` in - > - >```c++ -- >values[Indices::conti0EqIdx + FluidSystem::N2Idx]= -1e-4/FluidSystem::molarMass(FluidSystem::N2Idx); +- >values[Indices::conti0EqIdx + FluidSystem::N2Idx]= -1e-4; - >``` - >with a runtime variable. - > @@ -218,15 +219,15 @@ diff -ruN exercises/exercise-runtimeparams/README.md exercises/solution/exercise - >```bash - > make exercise_runtimeparams && ./exercise_runtimeparams params.input - >``` --<br><br> --### Task 3: Default Values for Runtime Parameters --<hr> +- +- +-## Task 3: Default Values for Runtime Parameters - -In the case that no path to a required runtime parameter is provided in the input file, the program will no longer run. You can try this if you like by removing the `TotalAreaSpecificInflow` from the input file. The resulting error message should look like this: - -```bash --loggingparametertree.hh:316: --Key Problem.TotalAreaSpecificInflow not found in the parameter tree ---> Abort! +-terminate called after throwing an instance of 'Dumux::ParameterException' +- what(): Dumux::ParameterException [get:/dumux/dumux/common/loggingparametertree.hh:411]: Key Problem.TotalAreaSpecificInflow not found in the parameter tree -``` - -To avoid this, we can place a default value in the variable definition. Whenever the parameter is specified in the input file, this default value in your class will be overwritten. In the case that no value is provided in the input file, this default value will be used. In order to do this, follow the following template. @@ -241,9 +242,8 @@ diff -ruN exercises/exercise-runtimeparams/README.md exercises/solution/exercise - -* > __Task 3__: Set up the `totalAreaSpecificInflow_` variable to record a default value of `-1e-4` and run this with and without a provided value of `-1e-3` in the input file. - --<br><br> --### Task 4: Other Runtime Parameter Functions --<hr> +- +-## Task 4: Other Runtime Parameter Functions - -Setting default values for variables defined with runtime parameters can also lead to problems. If one runtime parameter from the input file is set to multiple different variables, each with a different default value, changing the variable in one location can lead to unexpected changes elsewhere. On top of this, in DuMu<sup>x</sup>, there are a few base variables that are set with default values for all DuMu<sup>x</sup> simulations. These can be found in the header file `dumux/common/parameters.hh` in the function `globalDefaultParameters`. - @@ -268,6 +268,80 @@ diff -ruN exercises/exercise-runtimeparams/README.md exercises/solution/exercise -Using these functions we can better check which parameter values are being included in our program. - -* > __Task 4__: Using one of the bool `hasParam` functions, place an output in the problem file to alert the user where the parameter value comes from. +diff -ruN exercises/exercise-runtimeparams/params.input exercises/solution/exercise-runtimeparams/params.input +--- exercises/exercise-runtimeparams/params.input 2024-02-08 11:19:46.419932806 +0100 ++++ exercises/solution/exercise-runtimeparams/params.input 2024-02-08 11:19:46.449932806 +0100 +@@ -12,11 +12,12 @@ + AquiferDepth = 2700.0 # m + InjectionDuration = 2.628e6 # in seconds, i.e. one month + # TODO: Task 2: Create a parameter called "TotalAreaSpecificInflow" ++TotalAreaSpecificInflow = -1e-4 # kg/(s m^2) + + [SpatialParams] + PermeabilityAquitard = 1e-15 # m^2 + # TODO: Task 1: Change the Aquitard's Entry Pressure +-Aquitard.BrooksCoreyPcEntry = 4.5e4 # Pa ++Aquitard.BrooksCoreyPcEntry = 4.5e3 # Pa + Aquitard.BrooksCoreyLambda = 2.0 + Aquitard.Swr = 0.2 + Aquitard.Snr = 0.0 +@@ -24,4 +25,4 @@ + Aquifer.BrooksCoreyPcEntry = 1e4 # Pa + Aquifer.BrooksCoreyLambda = 2.0 + Aquifer.Swr = 0.2 +-Aquifer.Snr = 0.0 ++Aquifer.Snr = 0.0 +\ No newline at end of file +diff -ruN exercises/exercise-runtimeparams/problem.hh exercises/solution/exercise-runtimeparams/problem.hh +--- exercises/exercise-runtimeparams/problem.hh 2024-07-16 14:19:19.027763434 +0200 ++++ exercises/solution/exercise-runtimeparams/problem.hh 2024-07-16 14:19:19.027763434 +0200 +@@ -93,12 +93,16 @@ + injectionDuration_ = getParamFromGroup<Scalar>("Problem","InjectionDuration"); + // TODO: dumux-course-task 2 + // Set a variable "TotalAreaSpecificInflow" to read in a value from the parameter tree via the input file +- ++ totalAreaSpecificInflow_ = getParam<Scalar>("Problem.TotalAreaSpecificInflow"); + // TODO: dumux-course-task 3 + // Set a default value for the above parameter. +- ++ // totalAreaSpecificInflow_ = getParam<Scalar>("Problem.TotalAreaSpecificInflow", -1e-4); + // TODO: dumux-course-task 4 + // Provide output describing where the parameter value comes from using parameter bool functions. ++ // if (hasParamInGroup("Problem","TotalAreaSpecificInflow")) ++ // std::cout << "Parameter value is read from the input file." << std::endl; ++ // else ++ // std::cout << "Using the default parameter value." << std::endl; + } + + +@@ -161,7 +165,7 @@ + // units kg/(s*m^2) + // TODO: dumux-course-task 2 + // Incorporate "totalAreaSpecificInflow_" into the injection boundary condition +- values[Indices::conti0EqIdx + FluidSystem::N2Idx]= -1e-4; ++ values[Indices::conti0EqIdx + FluidSystem::N2Idx] = totalAreaSpecificInflow_; + values[Indices::conti0EqIdx + FluidSystem::H2OIdx] = 0.0; + } + +@@ -216,6 +220,7 @@ + Scalar injectionDuration_; //! Duration of the injection in seconds + // TODO: dumux-course-task 2 + // Set a variable "totalAreaSpecificInflow_" to read in a value from the parameter tree via the input file ++ Scalar totalAreaSpecificInflow_; //! Rate of the Injection in kg/(s m^2) + Scalar time_; + }; + +diff -ruN exercises/exercise-runtimeparams/properties.hh exercises/solution/exercise-runtimeparams/properties.hh +--- exercises/exercise-runtimeparams/properties.hh 2024-02-08 11:19:46.419932806 +0100 ++++ exercises/solution/exercise-runtimeparams/properties.hh 2024-02-08 11:19:46.449932806 +0100 +@@ -70,6 +70,6 @@ + FluidSystems::H2ON2DefaultPolicy</*fastButSimplifiedRelations=*/ true> >; + }; + +-} //end namespace Dumux::Properties ++} // end namespace Dumux::Properties + + #endif diff -ruN exercises/exercise-runtimeparams/spatialparams.hh exercises/solution/exercise-runtimeparams/spatialparams.hh --- exercises/exercise-runtimeparams/spatialparams.hh 2024-07-08 09:06:59.589159960 +0200 +++ exercises/solution/exercise-runtimeparams/spatialparams.hh 2024-07-08 09:06:59.617159848 +0200 diff --git a/exercises/exercise-runtimeparams/README.md b/exercises/exercise-runtimeparams/README.md index 57349c3629c757493893ccaa00b505bc1e918ed4..57bb20221825ada3ef8bc523b1c5f8a795037bff 100644 --- a/exercises/exercise-runtimeparams/README.md +++ b/exercises/exercise-runtimeparams/README.md @@ -1,17 +1,18 @@ # Exercise Runtime Parameters (DuMuX course) -<br> + ## Problem set-up Here we will expand on what we've covered in the basics exercise (see `dumux-course/exercises/exercise-basic/README.md`), and the problem set up will remain the same. + ## Preparing the exercise Navigate to the directory `dumux-course/exercises/exercise-runtimeparams/` -<br><br> -### Task 1: Understanding Input Parameters -<hr> + +## Task 1: Understanding Input Parameters + For this task we will edit the following files: * The shared __problem file__: `problem.hh` @@ -41,23 +42,23 @@ In the input file `params.input` you can find the following section [SpatialParams] PermeabilityAquitard = 1e-15 # m^2 Aquitard.BrooksCoreyPcEntry = 4.5e4 # Pa -PermeabilityAquifer = 1e-12 # m^2 -Aquifer.BrooksCoreyPcEntry = 1e4 # Pa +Aquitard.BrooksCoreyLambda = 2.0 +Aquitard.Swr = 0.2 +Aquitard.Snr = 0.0 ``` When a parameter is defined directly within your program, you'll need to recompile your program every time you change the value. When a parameter is passed via the input file, this is not the case. If we decided to vary the entry pressure in our geologic units a few times via the parameters listed above, there would be no need to recompile between simulation runs. * > __Task 1__: Change the aquitard's entry pressure in the input file to a lower value and compare the results with the previous solution. You do not need to recompile the executable. -<br><br> -### Task 2: Setting a variable to collect a runtime parameter -<hr> + +## Task 2: Setting a variable to collect a runtime parameter Let's free one of the variables in this exercise. Within the class `problem.hh`, in the first line of the Neumann boundary condition definition function `neumannAtPos(...)`, the injection rate is defined as $`1.0 \cdot 10^{-4} kg s^{-1} m^{-2}`$. ```c++ // inject nitrogen. negative values mean injection // units kg/(s*m^2) -values[Indices::conti0EqIdx + FluidSystem::N2Idx]= -1e-4/FluidSystem::molarMass(FluidSystem::N2Idx); +values[Indices::conti0EqIdx + FluidSystem::N2Idx]= -1e-4; values[Indices::conti0EqIdx + FluidSystem::H2OIdx] = 0.0; ``` @@ -106,7 +107,7 @@ InjectionDuration = 2.628e6 # in seconds, i.e. one month * > __Task 2__: The goal is to replace the value `-1e-4` in > >```c++ - >values[Indices::conti0EqIdx + FluidSystem::N2Idx]= -1e-4/FluidSystem::molarMass(FluidSystem::N2Idx); + >values[Indices::conti0EqIdx + FluidSystem::N2Idx]= -1e-4; >``` >with a runtime variable. > @@ -119,15 +120,15 @@ InjectionDuration = 2.628e6 # in seconds, i.e. one month >```bash > make exercise_runtimeparams && ./exercise_runtimeparams params.input >``` -<br><br> -### Task 3: Default Values for Runtime Parameters -<hr> + + +## Task 3: Default Values for Runtime Parameters In the case that no path to a required runtime parameter is provided in the input file, the program will no longer run. You can try this if you like by removing the `TotalAreaSpecificInflow` from the input file. The resulting error message should look like this: ```bash -loggingparametertree.hh:316: -Key Problem.TotalAreaSpecificInflow not found in the parameter tree ---> Abort! +terminate called after throwing an instance of 'Dumux::ParameterException' + what(): Dumux::ParameterException [get:/dumux/dumux/common/loggingparametertree.hh:411]: Key Problem.TotalAreaSpecificInflow not found in the parameter tree ``` To avoid this, we can place a default value in the variable definition. Whenever the parameter is specified in the input file, this default value in your class will be overwritten. In the case that no value is provided in the input file, this default value will be used. In order to do this, follow the following template. @@ -142,9 +143,8 @@ variable_ = getParamFromGroup<TYPE>("GROUPNAME","PARAMNAME", DEFAULTVALUE); * > __Task 3__: Set up the `totalAreaSpecificInflow_` variable to record a default value of `-1e-4` and run this with and without a provided value of `-1e-3` in the input file. -<br><br> -### Task 4: Other Runtime Parameter Functions -<hr> + +## Task 4: Other Runtime Parameter Functions Setting default values for variables defined with runtime parameters can also lead to problems. If one runtime parameter from the input file is set to multiple different variables, each with a different default value, changing the variable in one location can lead to unexpected changes elsewhere. On top of this, in DuMu<sup>x</sup>, there are a few base variables that are set with default values for all DuMu<sup>x</sup> simulations. These can be found in the header file `dumux/common/parameters.hh` in the function `globalDefaultParameters`. diff --git a/exercises/exercise-runtimeparams/problem.hh b/exercises/exercise-runtimeparams/problem.hh index 79e62ed62dfb509bb2cd5d2459eb4915e7e54da3..8345b0ba1466afab6515e3b6ca84fb864e54b5fb 100644 --- a/exercises/exercise-runtimeparams/problem.hh +++ b/exercises/exercise-runtimeparams/problem.hh @@ -155,14 +155,13 @@ public: // if we are inside the injection zone set inflow Neumann boundary conditions // using < boundary + eps_ or > boundary - eps_ is safer for floating point comparisons // than using <= or >= as it is robust with regard to imprecision introduced by rounding errors. - if (time_ < injectionDuration_ - && globalPos[1] < 15 + eps_ && globalPos[1] > 7 - eps_ && globalPos[0] > 0.9*this->gridGeometry().bBoxMax()[0]) + if (injectionActive() && onInjectionBoundary(globalPos)) { // inject nitrogen. negative values mean injection // units kg/(s*m^2) // TODO: dumux-course-task 2 // Incorporate "totalAreaSpecificInflow_" into the injection boundary condition - values[Indices::conti0EqIdx + FluidSystem::N2Idx]= -1e-4/FluidSystem::molarMass(FluidSystem::N2Idx); + values[Indices::conti0EqIdx + FluidSystem::N2Idx]= -1e-4; values[Indices::conti0EqIdx + FluidSystem::H2OIdx] = 0.0; } @@ -198,6 +197,18 @@ public: void setTime(Scalar time) { time_ = time; } + //! Return true if the injection is currently active + bool injectionActive() const + { return time_ < injectionDuration_; } + + //! Return true if the given position is in the injection boundary region + bool onInjectionBoundary(const GlobalPosition& globalPos) const + { + return globalPos[1] < 15. + eps_ + && globalPos[1] > 7. - eps_ + && globalPos[0] > this->gridGeometry().bBoxMax()[0] - eps_; + } + private: static constexpr Scalar eps_ = 1e-6; std::string name_; //! Problem name diff --git a/exercises/solution/exercise-runtimeparams/problem.hh b/exercises/solution/exercise-runtimeparams/problem.hh index 2e9b1ec57f601058d47560088005976f85c11a5a..8627910d064e618edf1be1222e752310ce88649d 100644 --- a/exercises/solution/exercise-runtimeparams/problem.hh +++ b/exercises/solution/exercise-runtimeparams/problem.hh @@ -91,11 +91,14 @@ public: aquiferDepth_ = getParam<Scalar>("Problem.AquiferDepth"); // the duration of the injection, units: second injectionDuration_ = getParamFromGroup<Scalar>("Problem","InjectionDuration"); - //TODO: Task 2: Set a variable "TotalAreaSpecificInflow" to read in a value from the parameter tree via the input file + // TODO: dumux-course-task 2 + // Set a variable "TotalAreaSpecificInflow" to read in a value from the parameter tree via the input file totalAreaSpecificInflow_ = getParam<Scalar>("Problem.TotalAreaSpecificInflow"); - //TODO: Task 3: Set a default value for the above parameter. + // TODO: dumux-course-task 3 + // Set a default value for the above parameter. // totalAreaSpecificInflow_ = getParam<Scalar>("Problem.TotalAreaSpecificInflow", -1e-4); - //TODO: Task 4: Provide output describing where the parameter value comes from using parameter bool functions. + // TODO: dumux-course-task 4 + // Provide output describing where the parameter value comes from using parameter bool functions. // if (hasParamInGroup("Problem","TotalAreaSpecificInflow")) // std::cout << "Parameter value is read from the input file." << std::endl; // else @@ -156,13 +159,13 @@ public: // if we are inside the injection zone set inflow Neumann boundary conditions // using < boundary + eps_ or > boundary - eps_ is safer for floating point comparisons // than using <= or >= as it is robust with regard to imprecision introduced by rounding errors. - if (time_ < injectionDuration_ - && globalPos[1] < 15 + eps_ && globalPos[1] > 7 - eps_ && globalPos[0] > 0.9*this->gridGeometry().bBoxMax()[0]) + if (injectionActive() && onInjectionBoundary(globalPos)) { // inject nitrogen. negative values mean injection // units kg/(s*m^2) - //TODO: Task 2: incorporate "totalAreaSpecificInflow_" into the injection boundary condition - values[Indices::conti0EqIdx + FluidSystem::N2Idx] = totalAreaSpecificInflow_/FluidSystem::molarMass(FluidSystem::N2Idx); + // TODO: dumux-course-task 2 + // Incorporate "totalAreaSpecificInflow_" into the injection boundary condition + values[Indices::conti0EqIdx + FluidSystem::N2Idx] = totalAreaSpecificInflow_; values[Indices::conti0EqIdx + FluidSystem::H2OIdx] = 0.0; } @@ -198,12 +201,25 @@ public: void setTime(Scalar time) { time_ = time; } + //! Return true if the injection is currently active + bool injectionActive() const + { return time_ < injectionDuration_; } + + //! Return true if the given position is in the injection boundary region + bool onInjectionBoundary(const GlobalPosition& globalPos) const + { + return globalPos[1] < 15. + eps_ + && globalPos[1] > 7. - eps_ + && globalPos[0] > this->gridGeometry().bBoxMax()[0] - eps_; + } + private: static constexpr Scalar eps_ = 1e-6; std::string name_; //! Problem name Scalar aquiferDepth_; //! Depth of the aquifer in m Scalar injectionDuration_; //! Duration of the injection in seconds - //TODO: Task 2: Set a variable "totalAreaSpecificInflow_" to read in a value from the parameter tree via the input file + // TODO: dumux-course-task 2 + // Set a variable "totalAreaSpecificInflow_" to read in a value from the parameter tree via the input file Scalar totalAreaSpecificInflow_; //! Rate of the Injection in kg/(s m^2) Scalar time_; }; diff --git a/slides/params.md b/slides/params.md index d8dd8a4cb3638bb905f3f555067721ece091790c..16462a6fd1e739a4059e0798605ef7db8cef0e64 100644 --- a/slides/params.md +++ b/slides/params.md @@ -31,7 +31,7 @@ int main(int argc, char** argv) ## Initialize Parameter Tree -Expliticly specify parameter file (default: `params.input`) +Explicitly specify parameter file (default: `params.input`) ```cpp #include <dumux/common/parameters.hh> int main(int argc, char** argv) @@ -43,7 +43,7 @@ int main(int argc, char** argv) ## Initialize Parameter Tree -Explciticly specify default parameters +Explicitly specify default parameters ```cpp #include <dune/common/parametertree.hh> #include <dumux/common/parameters.hh>