diff --git a/.patches/exercise-model/exercise-model.patch b/.patches/exercise-model/exercise-model.patch index ce11c12f724aa4b5534adeb65f059da6eddf4f12..fcbdb5d606a439db4f1334d7d2c7621a26acbcde 100644 --- a/.patches/exercise-model/exercise-model.patch +++ b/.patches/exercise-model/exercise-model.patch @@ -1,16 +1,15 @@ diff -ruN exercises/exercise-model/CMakeLists.txt exercises/solution/exercise-model/CMakeLists.txt ---- exercises/exercise-model/CMakeLists.txt 2024-05-21 14:15:07.153554813 +0200 -+++ exercises/solution/exercise-model/CMakeLists.txt 2024-05-21 14:15:07.213555107 +0200 +--- exercises/exercise-model/CMakeLists.txt 2024-07-12 09:11:32.256227192 +0200 ++++ exercises/solution/exercise-model/CMakeLists.txt 2024-07-12 09:11:32.264227248 +0200 @@ -1,4 +1,4 @@ --set(CMAKE_BUILD_TYPE Release) dune_symlink_to_source_files(FILES images params.input) + -dumux_add_test(NAME exercise_nonlineardiffusion -+ +dumux_add_test(NAME exercise_nonlineardiffusion_sol SOURCES main.cc) diff -ruN exercises/exercise-model/main.cc exercises/solution/exercise-model/main.cc ---- exercises/exercise-model/main.cc 2024-05-29 14:31:49.247625156 +0200 -+++ exercises/solution/exercise-model/main.cc 2024-05-21 14:15:07.213555107 +0200 +--- exercises/exercise-model/main.cc 2024-07-12 09:11:32.256227192 +0200 ++++ exercises/solution/exercise-model/main.cc 2024-07-12 09:11:32.264227248 +0200 @@ -41,6 +41,8 @@ #include <dumux/nonlinear/newtonsolver.hh> #include <dumux/assembly/fvassembler.hh> @@ -38,11 +37,51 @@ diff -ruN exercises/exercise-model/main.cc exercises/solution/exercise-model/mai - // using Problem = GetPropType<TypeTag, Properties::Problem>; - // using SolutionVector = GetPropType<TypeTag, Properties::SolutionVector>; - // using GridVariables = GetPropType<TypeTag, Properties::GridVariables>; -- // +- - // auto problem = std::make_shared<Problem>(gridGeometry); - // auto sol = createInitialSolution<SolutionVector>(*gridGeometry, imageData); - // auto gridVariables = std::make_shared<GridVariables>(problem, gridGeometry); - // gridVariables->init(sol); +- +- // // We initialize the VTK output module and write out the initial concentration field +- // VtkOutputModule<GridVariables, SolutionVector> vtkWriter(*gridVariables, sol, problem->name()); +- // vtkWriter.addVolumeVariable([](const auto& vv){ return vv.priVar(0); }, "imageIntensity"); +- // vtkWriter.write(0.0); +- +- // // We instantiate time loop using start and end time as well as +- // // the time step size from the parameter tree (`params.input`) +- // auto timeLoop = std::make_shared<CheckPointTimeLoop<Scalar>>( +- // getParam<Scalar>("TimeLoop.TStart", 0.0), +- // getParam<Scalar>("TimeLoop.Dt"), +- // getParam<Scalar>("TimeLoop.TEnd") +- // ); +- +- // // Next, we choose the type of assembler, linear solver and nonlinear solver +- // // and construct instances of these classes. +- // using Assembler = FVAssembler<TypeTag, DiffMethod::numeric>; +- // using LinearSolver = SSORCGIstlSolver<LinearSolverTraits<GridGeometry>, LinearAlgebraTraitsFromAssembler<Assembler>>; +- // using Solver = Dumux::NewtonSolver<Assembler, LinearSolver>; +- +- // auto oldSol = sol; // copy the vector to store state of previous time step +- // auto assembler = std::make_shared<Assembler>(problem, gridGeometry, gridVariables, timeLoop, oldSol); +- // auto linearSolver = std::make_shared<LinearSolver>(gridGeometry->gridView(), gridGeometry->dofMapper()); +- // Solver solver(assembler, linearSolver); +- +- // // time loop +- // timeLoop->start(); do +- // { +- // // assemble & solve +- // solver.solve(sol); +- +- // // make the new solution the old solution +- // oldSol = sol; +- // gridVariables->advanceTimeStep(); +- +- // // advance to the time loop to the next step +- // timeLoop->advanceTimeStep(); +- +- // // write VTK output (writes out the concentration field) +- // vtkWriter.write(timeLoop->time()); + using Scalar = GetPropType<TypeTag, Properties::Scalar>; + using Problem = GetPropType<TypeTag, Properties::Problem>; + using SolutionVector = GetPropType<TypeTag, Properties::SolutionVector>; @@ -52,33 +91,22 @@ diff -ruN exercises/exercise-model/main.cc exercises/solution/exercise-model/mai + auto sol = createInitialSolution<SolutionVector>(*gridGeometry, imageData); + auto gridVariables = std::make_shared<GridVariables>(problem, gridGeometry); + gridVariables->init(sol); - - // We initialize the VTK output module and write out the initial concentration field -- // VtkOutputModule<GridVariables, SolutionVector> vtkWriter(*gridVariables, sol, problem->name()); -- // vtkWriter.addVolumeVariable([](const auto& vv){ return vv.priVar(0); }, "imageIntensity"); -- // vtkWriter.write(0.0); ++ ++ // We initialize the VTK output module and write out the initial concentration field + VtkOutputModule<GridVariables, SolutionVector> vtkWriter(*gridVariables, sol, problem->name()); + vtkWriter.addVolumeVariable([](const auto& vv){ return vv.imageIntensity(); }, "imageIntensity"); + vtkWriter.write(0.0); - - // We instantiate time loop using start and end time as well as - // the time step size from the parameter tree (`params.input`) -- // auto timeLoop = std::make_shared<CheckPointTimeLoop<Scalar>>( -- // getParam<Scalar>("TimeLoop.TStart", 0.0), -- // getParam<Scalar>("TimeLoop.Dt"), -- // getParam<Scalar>("TimeLoop.TEnd") -- // ); ++ ++ // We instantiate time loop using start and end time as well as ++ // the time step size from the parameter tree (`params.input`) + auto timeLoop = std::make_shared<CheckPointTimeLoop<Scalar>>( + getParam<Scalar>("TimeLoop.TStart", 0.0), + getParam<Scalar>("TimeLoop.Dt"), + getParam<Scalar>("TimeLoop.TEnd") + ); - - // Next, we choose the type of assembler, linear solver and nonlinear solver - // and construct instances of these classes. -- // using Assembler = FVAssembler<TypeTag, DiffMethod::numeric>; -- // using LinearSolver = SSORCGIstlSolver<LinearSolverTraits<GridGeometry>, LinearAlgebraTraitsFromAssembler<Assembler>>; -- // using Solver = Dumux::NewtonSolver<Assembler, LinearSolver>; ++ ++ // Next, we choose the type of assembler, linear solver and nonlinear solver ++ // and construct instances of these classes. + using Assembler = FVAssembler<TypeTag, DiffMethod::numeric>; + using LinearSolver = SSORCGIstlSolver<LinearSolverTraits<GridGeometry>, LinearAlgebraTraitsFromAssembler<Assembler>>; + using Solver = Dumux::NewtonSolver<Assembler, LinearSolver>; @@ -87,37 +115,20 @@ diff -ruN exercises/exercise-model/main.cc exercises/solution/exercise-model/mai + auto assembler = std::make_shared<Assembler>(problem, gridGeometry, gridVariables, timeLoop, oldSol); + auto linearSolver = std::make_shared<LinearSolver>(gridGeometry->gridView(), gridGeometry->dofMapper()); + Solver solver(assembler, linearSolver); - -- // auto oldSol = sol; // copy the vector to store state of previous time step -- // auto assembler = std::make_shared<Assembler>(problem, gridGeometry, gridVariables, timeLoop, oldSol); -- // auto linearSolver = std::make_shared<LinearSolver>(gridGeometry->gridView(), gridGeometry->dofMapper()); -- // Solver solver(assembler, linearSolver); -- -- // // time loop -- // timeLoop->start(); do -- // { -- // // assemble & solve -- // solver.solve(sol); ++ + // time loop + timeLoop->start(); do + { + // assemble & solve + solver.solve(sol); - -- // // make the new solution the old solution -- // oldSol = sol; -- // gridVariables->advanceTimeStep(); ++ + // make the new solution the old solution + oldSol = sol; + gridVariables->advanceTimeStep(); - -- // // advance to the time loop to the next step -- // timeLoop->advanceTimeStep(); ++ + // advance to the time loop to the next step + timeLoop->advanceTimeStep(); - -- // // write VTK output (writes out the concentration field) -- // vtkWriter.write(timeLoop->time()); ++ + // write VTK output (writes out the concentration field) + vtkWriter.write(timeLoop->time()); @@ -136,7 +147,7 @@ diff -ruN exercises/exercise-model/main.cc exercises/solution/exercise-model/mai }// end main diff -ruN exercises/exercise-model/model.hh exercises/solution/exercise-model/model.hh --- exercises/exercise-model/model.hh 1970-01-01 01:00:00.000000000 +0100 -+++ exercises/solution/exercise-model/model.hh 2024-05-21 14:15:07.213555107 +0200 ++++ exercises/solution/exercise-model/model.hh 2024-07-12 09:11:32.264227248 +0200 @@ -0,0 +1,222 @@ +// -*- mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- +// vi: set et ts=4 sw=4 sts=4: @@ -361,9 +372,9 @@ diff -ruN exercises/exercise-model/model.hh exercises/solution/exercise-model/mo + +#endif diff -ruN exercises/exercise-model/README.md exercises/solution/exercise-model/README.md ---- exercises/exercise-model/README.md 2024-05-21 14:15:07.153554813 +0200 +--- exercises/exercise-model/README.md 2024-07-12 09:11:32.256227192 +0200 +++ exercises/solution/exercise-model/README.md 1970-01-01 01:00:00.000000000 +0100 -@@ -1,208 +0,0 @@ +@@ -1,195 +0,0 @@ -# Exercise Model (DuMuX course) -The aim of this exercise is it to learn how to set up a new model (new system of equations). -As an example, we implement a nonlinear diffusion equation model and apply it for image denoising. @@ -373,7 +384,7 @@ diff -ruN exercises/exercise-model/README.md exercises/solution/exercise-model/R - -## Equation and Problem set-up - --We consider a nonlinear diffusion equation on a domain $\Omega \subset \mathbb{R}^2$ and time interval $(0,T]$ with boundary $\partial\Omega$ given by +-We consider a nonlinear diffusion equation on a domain $\Omega \subset \mathbb{R}^2$, with boundary $\partial\Omega$, and time interval $(0,T]$ given by - -```math -\begin{aligned} @@ -382,25 +393,20 @@ diff -ruN exercises/exercise-model/README.md exercises/solution/exercise-model/R - c &= c^0 && \mathrm{for}\; t = 0, -\end{aligned} -``` --where for a position $\mathbf{x} \in \Omega$ and time $t$, $c(\mathbf{x},t)$ denotes the unknown evolving concentration field and $D(c)$ the solution-dependent diffusion coefficient. +-where for a position $\mathbf{x} \in \Omega$ and time $t$, $c(\mathbf{x},t)$ denotes the unknown evolving concentration field, $D(c)$ the solution-dependent diffusion coefficient, and $c^0$ the initial concentration field. - --In this exercise we want to model image denoising such that the primary variable $c$ corresponds to the **image intensity** and $D$ is given (due to Perona & Malik), as +-In this exercise we want to model image denoising such that the primary variable $c$ corresponds to the **image intensity**, $c^0$ to the noisy image data, and $D$ is given (due to Perona & Malik), as -```math -D(c) = \frac{1}{1 + \left(\frac{|| \nabla c ||}{K}\right)^2}, -``` -with conductance $K$. - --<br><br> -## Task 1: Getting familiar with the diffusion example --<hr> - -When implementing a new model it is advisable to built upon an already existing model that might be similar and only needs modifications. Since the above equation is a nonlinear diffusion equation, we can built upon the diffusion model implemented in the [diffusion example](https://git.iws.uni-stuttgart.de/dumux-repositories/dumux/-/tree/master/examples/diffusion). -The diffusion example also derives the discrete equations using the Box method as spatial discretization scheme. --<hr> - --<br><br> -## Task 2: Set up the model --<hr> - -:arrow_right: Copy the `model.hh` file from the diffusion example into `dumux-course/exercises/exercise-model` and choose appropriate class names. - @@ -428,9 +434,7 @@ diff -ruN exercises/exercise-model/README.md exercises/solution/exercise-model/R -} // end namespace Dumux::Properties -``` - --<br><br> -## Task 3: Set up the test case --<hr> - -:arrow_right: Open the file `main.cc`. - @@ -451,7 +455,7 @@ diff -ruN exercises/exercise-model/README.md exercises/solution/exercise-model/R - -:arrow_right: Include the header `model.hh` <br> -:arrow_right: To use the new model for this test case, make --the test type tag inherit properties from the model type tag +-the `NonlinearDiffusionTest` type tag inherit properties from the model type tag - -```c++ -namespace Dumux::Properties::TTag { @@ -487,11 +491,9 @@ diff -ruN exercises/exercise-model/README.md exercises/solution/exercise-model/R - -:arrow_right: Fix any compiler errors and warnings. - --<br><br> -## Task 4: Nonlinear diffusion --<hr> - --In the local residual class, instead of using a constant `1.0`, we now +-In the local residual class, instead of using a constant diffusion coefficient of `1.0`, we now -want to implement the nonlinear diffusion function specified above. With a `Dune::FieldVector` -you can get the 2-norm of the vector via `v.two_norm()` and its square with `v.two_norm2()`. (The reason -for having two different interfaces is that the second one is more efficient.) @@ -507,9 +509,7 @@ diff -ruN exercises/exercise-model/README.md exercises/solution/exercise-model/R -the derivatives of your residual by hand and implement them. This greatly simplifies implementing -nonlinear equations. - --<br><br> -## Task 5: Running the image denosing test case --<hr> - -:arrow_right: Compile and run like above. - @@ -525,11 +525,9 @@ diff -ruN exercises/exercise-model/README.md exercises/solution/exercise-model/R - </center> -</figure> - --<br><br> -## Task 6: Custom volume variables --<hr> - --The volume variables represent variables of the control volume. So far we have used +-The volume variables represent variables related to control volumes. So far we have used -the `BasicVolumeVariables` class that only stores the primary variables at control volumes. -We have used the interface `priVar` to access the primary variables. In more complex models, -we often want to @@ -541,7 +539,7 @@ diff -ruN exercises/exercise-model/README.md exercises/solution/exercise-model/R - -:arrow_right: Implement your own `ImageDenoisingVolumeVariables` class (either within a new header file or directly in `model.hh`). As basis you can use the `BasicVolumeVariables`, see `dumux/common/volumevariables.hh`. Copy the class into `model.hh` and rename it. - --<br> Add a function `imageIntensity()` that returns the first primary variable. <br> +-:arrow_right: Add a function `imageIntensity()` that returns the first primary variable. - -:arrow_right: In order to use the new `ImageDenoisingVolumeVariables` class in your model, set in your model-specific properties (see `dumux-course/exercises/exercise-properties`): -```c++ diff --git a/exercises/exercise-model/CMakeLists.txt b/exercises/exercise-model/CMakeLists.txt index 6dba1f0cda89446a4ed51963a86929f4a3cd0c94..0cade55c90e8e424516229c1e126bf149a4cc529 100644 --- a/exercises/exercise-model/CMakeLists.txt +++ b/exercises/exercise-model/CMakeLists.txt @@ -1,4 +1,4 @@ -set(CMAKE_BUILD_TYPE Release) dune_symlink_to_source_files(FILES images params.input) + dumux_add_test(NAME exercise_nonlineardiffusion SOURCES main.cc) diff --git a/exercises/exercise-model/README.md b/exercises/exercise-model/README.md index 265dfb4a6bd7d4536f2b853c188dbc005dd11f98..e9018ef5d7bbd9d0dcd33e50e680fefbb8dde5cd 100644 --- a/exercises/exercise-model/README.md +++ b/exercises/exercise-model/README.md @@ -7,7 +7,7 @@ and solve such a problem with DuMux. We also implement the model for a specific ## Equation and Problem set-up -We consider a nonlinear diffusion equation on a domain $\Omega \subset \mathbb{R}^2$ and time interval $(0,T]$ with boundary $\partial\Omega$ given by +We consider a nonlinear diffusion equation on a domain $\Omega \subset \mathbb{R}^2$, with boundary $\partial\Omega$, and time interval $(0,T]$ given by ```math \begin{aligned} @@ -16,25 +16,20 @@ We consider a nonlinear diffusion equation on a domain $\Omega \subset \mathbb{R c &= c^0 && \mathrm{for}\; t = 0, \end{aligned} ``` -where for a position $\mathbf{x} \in \Omega$ and time $t$, $c(\mathbf{x},t)$ denotes the unknown evolving concentration field and $D(c)$ the solution-dependent diffusion coefficient. +where for a position $\mathbf{x} \in \Omega$ and time $t$, $c(\mathbf{x},t)$ denotes the unknown evolving concentration field, $D(c)$ the solution-dependent diffusion coefficient, and $c^0$ the initial concentration field. -In this exercise we want to model image denoising such that the primary variable $c$ corresponds to the **image intensity** and $D$ is given (due to Perona & Malik), as +In this exercise we want to model image denoising such that the primary variable $c$ corresponds to the **image intensity**, $c^0$ to the noisy image data, and $D$ is given (due to Perona & Malik), as ```math D(c) = \frac{1}{1 + \left(\frac{|| \nabla c ||}{K}\right)^2}, ``` with conductance $K$. -<br><br> ## Task 1: Getting familiar with the diffusion example -<hr> When implementing a new model it is advisable to built upon an already existing model that might be similar and only needs modifications. Since the above equation is a nonlinear diffusion equation, we can built upon the diffusion model implemented in the [diffusion example](https://git.iws.uni-stuttgart.de/dumux-repositories/dumux/-/tree/master/examples/diffusion). The diffusion example also derives the discrete equations using the Box method as spatial discretization scheme. -<hr> -<br><br> ## Task 2: Set up the model -<hr> :arrow_right: Copy the `model.hh` file from the diffusion example into `dumux-course/exercises/exercise-model` and choose appropriate class names. @@ -62,9 +57,7 @@ namespace Dumux::Properties { } // end namespace Dumux::Properties ``` -<br><br> ## Task 3: Set up the test case -<hr> :arrow_right: Open the file `main.cc`. @@ -85,7 +78,7 @@ const auto imageData = NetPBMReader::readPGM(imageFileName); :arrow_right: Include the header `model.hh` <br> :arrow_right: To use the new model for this test case, make -the test type tag inherit properties from the model type tag +the `NonlinearDiffusionTest` type tag inherit properties from the model type tag ```c++ namespace Dumux::Properties::TTag { @@ -121,11 +114,9 @@ make exercise_nonlineardiffusion :arrow_right: Fix any compiler errors and warnings. -<br><br> ## Task 4: Nonlinear diffusion -<hr> -In the local residual class, instead of using a constant `1.0`, we now +In the local residual class, instead of using a constant diffusion coefficient of `1.0`, we now want to implement the nonlinear diffusion function specified above. With a `Dune::FieldVector` you can get the 2-norm of the vector via `v.two_norm()` and its square with `v.two_norm2()`. (The reason for having two different interfaces is that the second one is more efficient.) @@ -141,9 +132,7 @@ As the DuMux assembler uses numeric differentiation to approximate the Jacobian the derivatives of your residual by hand and implement them. This greatly simplifies implementing nonlinear equations. -<br><br> ## Task 5: Running the image denosing test case -<hr> :arrow_right: Compile and run like above. @@ -159,11 +148,9 @@ __The final result should look like this:__ </center> </figure> -<br><br> ## Task 6: Custom volume variables -<hr> -The volume variables represent variables of the control volume. So far we have used +The volume variables represent variables related to control volumes. So far we have used the `BasicVolumeVariables` class that only stores the primary variables at control volumes. We have used the interface `priVar` to access the primary variables. In more complex models, we often want to @@ -175,7 +162,7 @@ In this task we will implement a custom volume variable class, while in this sim :arrow_right: Implement your own `ImageDenoisingVolumeVariables` class (either within a new header file or directly in `model.hh`). As basis you can use the `BasicVolumeVariables`, see `dumux/common/volumevariables.hh`. Copy the class into `model.hh` and rename it. -<br> Add a function `imageIntensity()` that returns the first primary variable. <br> +:arrow_right: Add a function `imageIntensity()` that returns the first primary variable. :arrow_right: In order to use the new `ImageDenoisingVolumeVariables` class in your model, set in your model-specific properties (see `dumux-course/exercises/exercise-properties`): ```c++ diff --git a/exercises/exercise-model/main.cc b/exercises/exercise-model/main.cc index a036a6eb2e06a20534a69d371fc1ac61ca6bd325..8883fbb81b1bc680c1e99a8d000bc260d0c1b28c 100644 --- a/exercises/exercise-model/main.cc +++ b/exercises/exercise-model/main.cc @@ -153,27 +153,27 @@ int main(int argc, char** argv) // using Problem = GetPropType<TypeTag, Properties::Problem>; // using SolutionVector = GetPropType<TypeTag, Properties::SolutionVector>; // using GridVariables = GetPropType<TypeTag, Properties::GridVariables>; - // + // auto problem = std::make_shared<Problem>(gridGeometry); // auto sol = createInitialSolution<SolutionVector>(*gridGeometry, imageData); // auto gridVariables = std::make_shared<GridVariables>(problem, gridGeometry); // gridVariables->init(sol); - // We initialize the VTK output module and write out the initial concentration field + // // We initialize the VTK output module and write out the initial concentration field // VtkOutputModule<GridVariables, SolutionVector> vtkWriter(*gridVariables, sol, problem->name()); // vtkWriter.addVolumeVariable([](const auto& vv){ return vv.priVar(0); }, "imageIntensity"); // vtkWriter.write(0.0); - // We instantiate time loop using start and end time as well as - // the time step size from the parameter tree (`params.input`) + // // We instantiate time loop using start and end time as well as + // // the time step size from the parameter tree (`params.input`) // auto timeLoop = std::make_shared<CheckPointTimeLoop<Scalar>>( // getParam<Scalar>("TimeLoop.TStart", 0.0), // getParam<Scalar>("TimeLoop.Dt"), // getParam<Scalar>("TimeLoop.TEnd") // ); - // Next, we choose the type of assembler, linear solver and nonlinear solver - // and construct instances of these classes. + // // Next, we choose the type of assembler, linear solver and nonlinear solver + // // and construct instances of these classes. // using Assembler = FVAssembler<TypeTag, DiffMethod::numeric>; // using LinearSolver = SSORCGIstlSolver<LinearSolverTraits<GridGeometry>, LinearAlgebraTraitsFromAssembler<Assembler>>; // using Solver = Dumux::NewtonSolver<Assembler, LinearSolver>;