Newer
Older
diff -ruN exercises/exercise-basic/2pmain.cc exercises/solution/exercise-basic/2pmain.cc
--- exercises/exercise-basic/2pmain.cc 2025-03-03 15:56:59.902625104 +0100
+++ exercises/solution/exercise-basic/2pmain.cc 1970-01-01 01:00:00.000000000 +0100
-// -*- mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*-
-// vi: set et ts=4 sw=4 sts=4:
-//
-// SPDX-FileCopyrightInfo: Copyright © DuMux-Course contributors, see AUTHORS.md in root folder
-// SPDX-License-Identifier: GPL-3.0-or-later
-//
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
-/*!
- * \file
- * \brief The main file for the two-phase porousmediumflow problem of exercise-basic
- */
-#include <config.h>
-
-#include <iostream>
-
-#include <dumux/common/initialize.hh>
-#include <dumux/common/properties.hh>
-#include <dumux/common/parameters.hh>
-
-#include <dumux/linear/istlsolvers.hh>
-#include <dumux/linear/linearsolvertraits.hh>
-#include <dumux/linear/linearalgebratraits.hh>
-#include <dumux/nonlinear/newtonsolver.hh>
-
-#include <dumux/assembly/fvassembler.hh>
-#include <dumux/assembly/diffmethod.hh>
-
-#include <dumux/io/vtkoutputmodule.hh>
-#include <dumux/io/grid/gridmanager_yasp.hh>
-
-// The properties file, where the compile time options are defined
-#include "properties2p.hh"
-
-////////////////////////
-// the main function
-////////////////////////
-int main(int argc, char** argv)
-{
- using namespace Dumux;
-
- // define the type tag for this problem
- using TypeTag = Properties::TTag::Injection2pCC;
-
- /// initialize MPI+X, finalize is done automatically on exit
- Dumux::initialize(argc, argv);
-
- // parse command line arguments and input file
- Parameters::init(argc, argv);
-
- // try to create a grid (from the given grid file or the input file)
- GridManager<GetPropType<TypeTag, Properties::Grid>> gridManager;
- gridManager.init();
-
- ////////////////////////////////////////////////////////////
- // run instationary non-linear problem on this grid
- ////////////////////////////////////////////////////////////
-
- // we compute on the leaf grid view
- const auto& leafGridView = gridManager.grid().leafGridView();
-
- // create the finite volume grid geometry
- using GridGeometry = GetPropType<TypeTag, Properties::GridGeometry>;
- auto gridGeometry = std::make_shared<GridGeometry>(leafGridView);
-
- // the problem (initial and boundary conditions)
- using Problem = GetPropType<TypeTag, Properties::Problem>;
- auto problem = std::make_shared<Problem>(gridGeometry);
-
- // the solution vector
- using SolutionVector = GetPropType<TypeTag, Properties::SolutionVector>;
- SolutionVector x;
- problem->applyInitialSolution(x);
- auto xOld = x;
-
- // the grid variables
- using GridVariables = GetPropType<TypeTag, Properties::GridVariables>;
- auto gridVariables = std::make_shared<GridVariables>(problem, gridGeometry);
- gridVariables->init(x);
-
- // initialize the vtk output module
- using IOFields = GetPropType<TypeTag, Properties::IOFields>;
-
- // use non-conforming output for the test with interface solver
- const auto ncOutput = getParam<bool>("Problem.UseNonConformingOutput", false);
- VtkOutputModule<GridVariables, SolutionVector> vtkWriter(*gridVariables, x, problem->name(), "",
- ncOutput ? Dune::VTK::nonconforming : Dune::VTK::conforming);
- using VelocityOutput = GetPropType<TypeTag, Properties::VelocityOutput>;
- vtkWriter.addVelocityOutput(std::make_shared<VelocityOutput>(*gridVariables));
- IOFields::initOutputModule(vtkWriter); //!< Add model specific output fields
- vtkWriter.write(0.0);
-
- // instantiate time loop
- using Scalar = GetPropType<TypeTag, Properties::Scalar>;
- const auto tEnd = getParam<Scalar>("TimeLoop.TEnd");
- const auto maxDt = getParam<Scalar>("TimeLoop.MaxTimeStepSize");
- const auto dt = getParam<Scalar>("TimeLoop.DtInitial");
- auto timeLoop = std::make_shared<TimeLoop<Scalar>>(0.0, dt, tEnd);
- timeLoop->setMaxTimeStepSize(maxDt);
-
- // the assembler with time loop for instationary problem
- using Assembler = FVAssembler<TypeTag, DiffMethod::numeric>;
- auto assembler = std::make_shared<Assembler>(problem, gridGeometry, gridVariables, timeLoop, xOld);
-
- // the linear solver
- using LinearSolver = AMGBiCGSTABIstlSolver<LinearSolverTraits<GridGeometry>, LinearAlgebraTraitsFromAssembler<Assembler>>;
- auto linearSolver = std::make_shared<LinearSolver>(gridGeometry->gridView(), gridGeometry->dofMapper());
-
- // the non-linear solver
- using NewtonSolver = Dumux::NewtonSolver<Assembler, LinearSolver>;
- NewtonSolver nonLinearSolver(assembler, linearSolver);
-
- // time loop
- timeLoop->start();
- while (!timeLoop->finished())
- {
- //set time in problem (is used in time-dependent Neumann boundary condition)
- problem->setTime(timeLoop->time()+timeLoop->timeStepSize());
-
- // solve the non-linear system with time step control
- nonLinearSolver.solve(x, *timeLoop);
-
- // make the new solution the old solution
- xOld = x;
- gridVariables->advanceTimeStep();
-
- // advance to the time loop to the next step
- timeLoop->advanceTimeStep();
-
- // report statistics of this time step
- timeLoop->reportTimeStep();
-
- // set new dt as suggested by the newton solver
- timeLoop->setTimeStepSize(nonLinearSolver.suggestTimeStepSize(timeLoop->timeStepSize()));
-
- // output to vtk
- vtkWriter.write(timeLoop->time());
- }
-
- timeLoop->finalize(leafGridView.comm());
-
- // print parameter report
- if (leafGridView.comm().rank() == 0)
- Parameters::print();
-
- return 0;
-} // end main
diff -ruN exercises/exercise-basic/2pnimain.cc exercises/solution/exercise-basic/2pnimain.cc
--- exercises/exercise-basic/2pnimain.cc 1970-01-01 01:00:00.000000000 +0100
+++ exercises/solution/exercise-basic/2pnimain.cc 2025-03-03 15:56:59.909624983 +0100
+// -*- mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*-
+// vi: set et ts=4 sw=4 sts=4:
+//
+// SPDX-FileCopyrightInfo: Copyright © DuMux-Course contributors, see AUTHORS.md in root folder
+// SPDX-License-Identifier: GPL-3.0-or-later
+//
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
+/*!
+ * \file
+ * \brief The solution main file for the two-phase porousmediumflow problem of exercise-basic
+ */
+#include <config.h>
+
+#include <iostream>
+
+#include <dumux/common/initialize.hh>
+#include <dumux/common/properties.hh>
+#include <dumux/common/parameters.hh>
+
+#include <dumux/linear/istlsolvers.hh>
+#include <dumux/linear/linearsolvertraits.hh>
+#include <dumux/linear/linearalgebratraits.hh>
+#include <dumux/nonlinear/newtonsolver.hh>
+
+#include <dumux/assembly/fvassembler.hh>
+#include <dumux/assembly/diffmethod.hh>
+
+#include <dumux/io/vtkoutputmodule.hh>
+#include <dumux/io/grid/gridmanager_yasp.hh>
+
+// The properties file, where the compile time options are defined
+#include "properties2pni.hh"
+
+int main(int argc, char** argv)
+{
+ using namespace Dumux;
+
+ // define the type tag for this problem
+ using TypeTag = Properties::TTag::Injection2pNICC;
+
+ // initialize MPI+X, finalize is done automatically on exit
+ Dumux::initialize(argc, argv);
+
+ // parse command line arguments and input file
+ Parameters::init(argc, argv);
+
+ // try to create a grid (from the given grid file or the input file)
+ GridManager<GetPropType<TypeTag, Properties::Grid>> gridManager;
+ gridManager.init();
+
+ ////////////////////////////////////////////////////////////
+ // run instationary non-linear problem on this grid
+ ////////////////////////////////////////////////////////////
+
+ // we compute on the leaf grid view
+ const auto& leafGridView = gridManager.grid().leafGridView();
+
+ // create the finite volume grid geometry
+ using GridGeometry = GetPropType<TypeTag, Properties::GridGeometry>;
+ auto gridGeometry = std::make_shared<GridGeometry>(leafGridView);
+
+ // the problem (initial and boundary conditions)
+ using Problem = GetPropType<TypeTag, Properties::Problem>;
+ auto problem = std::make_shared<Problem>(gridGeometry);
+
+ // the solution vector
+ using SolutionVector = GetPropType<TypeTag, Properties::SolutionVector>;
+ SolutionVector x;
+ problem->applyInitialSolution(x);
+ auto xOld = x;
+
+ // the grid variables
+ using GridVariables = GetPropType<TypeTag, Properties::GridVariables>;
+ auto gridVariables = std::make_shared<GridVariables>(problem, gridGeometry);
+ gridVariables->init(x);
+
+ // initialize the vtk output module
+ using IOFields = GetPropType<TypeTag, Properties::IOFields>;
+ VtkOutputModule<GridVariables, SolutionVector> vtkWriter(*gridVariables, x, problem->name());
+ using VelocityOutput = GetPropType<TypeTag, Properties::VelocityOutput>;
+ vtkWriter.addVelocityOutput(std::make_shared<VelocityOutput>(*gridVariables));
+ IOFields::initOutputModule(vtkWriter); //!< Add model specific output fields
+ vtkWriter.write(0.0);
+
+ // instantiate time loop
+ using Scalar = GetPropType<TypeTag, Properties::Scalar>;
+ const auto tEnd = getParam<Scalar>("TimeLoop.TEnd");
+ const auto maxDt = getParam<Scalar>("TimeLoop.MaxTimeStepSize");
+ const auto dt = getParam<Scalar>("TimeLoop.DtInitial");
+ auto timeLoop = std::make_shared<TimeLoop<Scalar>>(0.0, dt, tEnd);
+ timeLoop->setMaxTimeStepSize(maxDt);
+
+ // the assembler with time loop for instationary problem
+ using Assembler = FVAssembler<TypeTag, DiffMethod::numeric>;
+ auto assembler = std::make_shared<Assembler>(problem, gridGeometry, gridVariables, timeLoop, xOld);
+
+ // the linear solver
+ using LinearSolver = AMGBiCGSTABIstlSolver<LinearSolverTraits<GridGeometry>, LinearAlgebraTraitsFromAssembler<Assembler>>;
+ auto linearSolver = std::make_shared<LinearSolver>(gridGeometry->gridView(), gridGeometry->dofMapper());
+
+ // the non-linear solver
+ using NewtonSolver = Dumux::NewtonSolver<Assembler, LinearSolver>;
+ NewtonSolver nonLinearSolver(assembler, linearSolver);
+
+ // time loop
+ timeLoop->start();
+ while (!timeLoop->finished())
+ {
+ //set time in problem (is used in time-dependent Neumann boundary condition)
+ problem->setTime(timeLoop->time()+timeLoop->timeStepSize());
+
+ // solve the non-linear system with time step control
+ nonLinearSolver.solve(x, *timeLoop);
+
+ // make the new solution the old solution
+ xOld = x;
+ gridVariables->advanceTimeStep();
+
+ // advance to the time loop to the next step
+ timeLoop->advanceTimeStep();
+
+ // report statistics of this time step
+ timeLoop->reportTimeStep();
+
+ // set new dt as suggested by the newton solver
+ timeLoop->setTimeStepSize(nonLinearSolver.suggestTimeStepSize(timeLoop->timeStepSize()));
+
+ // output to vtk
+ vtkWriter.write(timeLoop->time());
+ }
+
+ timeLoop->finalize(leafGridView.comm());
+
+ // print parameter report
+ if (leafGridView.comm().rank() == 0)
+ Parameters::print();
+
+ return 0;
+} // end main
diff -ruN exercises/exercise-basic/CMakeLists.txt exercises/solution/exercise-basic/CMakeLists.txt
--- exercises/exercise-basic/CMakeLists.txt 2025-03-03 15:56:59.902625104 +0100
+++ exercises/solution/exercise-basic/CMakeLists.txt 2025-03-03 15:56:59.909624983 +0100
@@ -1,12 +1,9 @@
# SPDX-FileCopyrightInfo: Copyright © DuMux-Course contributors, see AUTHORS.md in root folder
# SPDX-License-Identifier: GPL-3.0-or-later
-# the immiscible two-phase simulation program
-dumux_add_test(NAME exercise_basic_2p
- SOURCES 2pmain.cc)
-
-# here, add the two-phase non-isothermal simulation program
-
+# the two-phase non-isothermal simulation program
+dumux_add_test(NAME exercise_basic_2pni_solution
+ SOURCES 2pnimain.cc)
# add a symlink for each input file

Anna Mareike Kostelecky
committed
add_input_file_links()
diff -ruN exercises/exercise-basic/injection2pniproblem.hh exercises/solution/exercise-basic/injection2pniproblem.hh
--- exercises/exercise-basic/injection2pniproblem.hh 2025-03-03 15:56:59.902625104 +0100
+++ exercises/solution/exercise-basic/injection2pniproblem.hh 2025-03-03 15:56:59.909624983 +0100
/*!
* \file
*
- * \brief The two-phase nonisothermal porousmediumflow problem for exercise-basic
+ * \brief The solution of the two-phase nonisothermal porousmediumflow problem for exercise-basic
*/
#ifndef DUMUX_EX_BASIC_PROBLEM_2PNI_HH
using FluidSystem = GetPropType<TypeTag, Properties::FluidSystem>;
using NumEqVector = Dumux::NumEqVector<PrimaryVariables>;
+ using N2 = typename FluidSystem::N2;
+
static constexpr int dimWorld = GridView::dimensionworld;
using Element = typename GridView::template Codim<0>::Entity;
using GlobalPosition = typename Element::Geometry::GlobalCoordinate;
else
bcTypes.setAllNeumann();
- /*!
- * TODO:dumux-course-task 4:
- * Set Dirichlet conditions for the energy equation on the left boundary
- * and Neumann everywhere else.
- * Think about: is there anything necessary to do here?
- */
-
return bcTypes;
}
PrimaryVariables dirichletAtPos(const GlobalPosition &globalPos) const
{
return initialAtPos(globalPos);
-
- /*!
- * TODO:dumux-course-task 4:
- * Set Dirichlet conditions for the energy equation on the left boundary.
- * Think about: is there anything necessary to do here?
- */
}
/*!
@@ -144,17 +133,18 @@
// if we are inside the injection zone set inflow Neumann boundary conditions
if (injectionActive() && onInjectionBoundary(globalPos))
{
// inject nitrogen. Negative values mean injection
// unit: kg/(s*m^2)
- values[Indices::conti0EqIdx + FluidSystem::N2Idx] = -1e-4;
+ values[Indices::conti0EqIdx + FluidSystem::N2Idx] = injectionRate;
values[Indices::conti0EqIdx + FluidSystem::H2OIdx] = 0.0;
- /*!
- * Set Neumann noflow conditions for the energy equation everywhere else except the left boundary.
- * Additionally, consider the energy flux at the injection point which is equal to the product of the respective mass flux and the matching enthalpy. Use the function `gasEnthalpy(temperature,pressure)` from the N2 component to access the necessary enthalpy.
- * hint: use `Indices::energyEqIdx` to access the entry belonging to the energy flux.
- */
+ // energy fluxes are always mass specific
+ // unit: W/(m^2)
+ const Scalar temperatureAtInjection = initialAtPos(globalPos)[Indices::temperatureIdx];/*K*/
+ const Scalar pressureAtInjection = initialAtPos(globalPos)[Indices::pressureIdx];/*Pa*/
+ values[Indices::energyEqIdx] = injectionRate /*kg/(m^2 s)*/ *N2::gasEnthalpy(temperatureAtInjection, pressureAtInjection)/*J/kg*/;
}
return values;
values[Indices::pressureIdx] = pw;
values[Indices::saturationIdx] = 0.0;
- /*!
- * TODO:dumux-course-task 4:
- * Set a temperature gradient of 0.03 K per m beginning at 283 K here.
- * Hint: you can use aquiferDepth_ and the globalPos similar to the pressure gradient.
- * Use globalPos[0] and globalPos[1] to implement the high temperature lens with 380 K
- * Hint : use Indices::temperatureIdx to address the initial values for temperature
- */
+ values[Indices::temperatureIdx] = 283.0 + (aquiferDepth_ - globalPos[1])*0.03;
+ if (globalPos[0] > 20 - eps_ && globalPos[0] < 30 + eps_ && globalPos[1] > 5 - eps_ && globalPos[1] < 35 + eps_)
+
return values;
}
diff -ruN exercises/exercise-basic/injection2pproblem.hh exercises/solution/exercise-basic/injection2pproblem.hh
--- exercises/exercise-basic/injection2pproblem.hh 2025-03-03 15:56:59.902625104 +0100
+++ exercises/solution/exercise-basic/injection2pproblem.hh 1970-01-01 01:00:00.000000000 +0100
-// -*- mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*-
-// vi: set et ts=4 sw=4 sts=4:
-//
-// SPDX-FileCopyrightInfo: Copyright © DuMux-Course contributors, see AUTHORS.md in root folder
-// SPDX-License-Identifier: GPL-3.0-or-later
-//
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
440
441
442
443
444
445
446
447
448
449
450
451
452
453
454
455
456
457
458
459
460
461
462
463
464
465
466
467
468
469
470
471
-/*!
- * \file
- *
- * \brief The two-phase porousmediumflow problem for exercise-basic
- */
-
-#ifndef DUMUX_EX_BASIC_PROBLEM_2P_HH
-#define DUMUX_EX_BASIC_PROBLEM_2P_HH
-
-#include <dumux/common/properties.hh>
-#include <dumux/common/boundarytypes.hh>
-#include <dumux/common/numeqvector.hh>
-#include <dumux/porousmediumflow/problem.hh>
-
-namespace Dumux {
-
-/*!
- * \ingroup TwoPModel
- * \ingroup ImplicitTestProblems
- * \brief Gas injection problem where a gas (here nitrogen) is injected into a fully
- * water saturated medium. During buoyancy driven upward migration the gas
- * passes a high temperature area.
- *
- * The domain is sized 60 m times 40 m.
- *
- * For the mass conservation equation neumann boundary conditions are used on
- * the top, on the bottom and on the right of the domain, while dirichlet conditions
- * apply on the left boundary.
- *
- * Gas is injected at the right boundary from 7 m to 15 m at a rate of
- * 0.001 kg/(s m), the remaining neumann boundaries are no-flow
- * boundaries.
- *
- * At the dirichlet boundaries a hydrostatic pressure and a gas saturation of zero a
- *
- * This problem uses the \ref TwoPModel model.
- */
-template<class TypeTag>
-class Injection2PProblem : public PorousMediumFlowProblem<TypeTag>
-{
- using ParentType = PorousMediumFlowProblem<TypeTag>;
- using GridView = typename GetPropType<TypeTag, Properties::GridGeometry>::GridView;
- using Scalar = GetPropType<TypeTag, Properties::Scalar>;
- using Indices = typename GetPropType<TypeTag, Properties::ModelTraits>::Indices;
- using PrimaryVariables = GetPropType<TypeTag, Properties::PrimaryVariables>;
- using BoundaryTypes = Dumux::BoundaryTypes<GetPropType<TypeTag, Properties::ModelTraits>::numEq()>;
- using GridGeometry = GetPropType<TypeTag, Properties::GridGeometry>;
- using FVElementGeometry = typename GetPropType<TypeTag, Properties::GridGeometry>::LocalView;
- using FluidSystem = GetPropType<TypeTag, Properties::FluidSystem>;
- using NumEqVector = Dumux::NumEqVector<PrimaryVariables>;
-
- static constexpr int dimWorld = GridView::dimensionworld;
- using Element = typename GridView::template Codim<0>::Entity;
- using GlobalPosition = typename Element::Geometry::GlobalCoordinate;
-
-public:
- Injection2PProblem(std::shared_ptr<const GridGeometry> gridGeometry)
- : ParentType(gridGeometry)
- {
- FluidSystem::init(/*tempMin=*/273.15,
- /*tempMax=*/423.15,
- /*numTemp=*/50,
- /*pMin=*/0.0,
- /*pMax=*/30e6,
- /*numP=*/300);
-
- // getParam<TYPE>("GROUPNAME.PARAMNAME") reads and sets parameter PARAMNAME
- // of type TYPE given in the group GROUPNAME from the input file
- name_ = getParam<std::string>("Problem.Name");
- aquiferDepth_ = getParam<Scalar>("Problem.AquiferDepth");
- injectionDuration_ = getParam<Scalar>("Problem.InjectionDuration");
- }
-
-
- /*!
- * \brief Returns the problem name
- *
- * This is used as a prefix for files generated by the simulation.
- */
- std::string name() const
- { return name_+"-2p"; }
-
-
- /*!
- * \brief Specifies which kind of boundary condition should be
- * used for which equation on a given boundary segment.
- *
- * \param globalPos The position for which the bc type should be evaluated
- */
- BoundaryTypes boundaryTypesAtPos(const GlobalPosition &globalPos) const
- {
- BoundaryTypes bcTypes;
- // set the left of the domain (with the global position in "0 = x" direction as a Dirichlet boundary
- if (globalPos[0] < eps_)
- bcTypes.setAllDirichlet();
- // set all other as Neumann boundaries
- else
- bcTypes.setAllNeumann();
-
- return bcTypes;
- }
-
- /*!
- * \brief Evaluates the boundary conditions for a Dirichlet
- * boundary segment
- *
- * \param globalPos The global position
- */
- PrimaryVariables dirichletAtPos(const GlobalPosition &globalPos) const
- {
- return initialAtPos(globalPos);
- }
-
- /*!
- * \brief Evaluate the boundary conditions for a neumann
- * boundary segment.
- *
- * \param globalPos The position of the integration point of the boundary segment.
- */
- NumEqVector neumannAtPos(const GlobalPosition &globalPos) const
- {
- // initialize values to zero, i.e. no-flow Neumann boundary conditions
- NumEqVector values(0.0);
-
- // 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 (injectionActive() && onInjectionBoundary(globalPos))
- {
- // Inject nitrogen. Negative values mean injection
- // unit: kg/(s*m^2)
548
549
550
551
552
553
554
555
556
557
558
559
560
561
562
563
564
565
566
567
568
569
570
571
572
573
574
575
- values[Indices::conti0EqIdx + FluidSystem::N2Idx] = -1e-4;
- values[Indices::conti0EqIdx + FluidSystem::H2OIdx] = 0.0;
- }
-
- return values;
- }
-
-
- /*!
- * \brief Evaluate the source term for all phases within a given
- * sub-control-volume.
- *
- * \param globalPos The position for which the source term should be evaluated
- */
- NumEqVector sourceAtPos(const GlobalPosition &globalPos) const
- {
- return NumEqVector(0.0);
- }
-
- /*!
- * \brief Evaluate the initial value for a control volume.
- *
- * \param globalPos The position for which the initial condition should be evaluated
- */
- PrimaryVariables initialAtPos(const GlobalPosition &globalPos) const
- {
- PrimaryVariables values(0.0);
-
- // get the water density at atmospheric conditions
- const Scalar densityW = FluidSystem::H2O::liquidDensity(this->spatialParams().temperatureAtPos(globalPos), 1.0e5);
-
- // assume an initially hydrostatic liquid pressure profile
- // note: we subtract rho_w*g*h because g is defined negative
- const Scalar pw = 1.0e5 - densityW*this->spatialParams().gravity(globalPos)[dimWorld-1]*(aquiferDepth_ - globalPos[dimWorld-1]);
-
- values[Indices::pressureIdx] = pw;
- values[Indices::saturationIdx] = 0.0;
-
- return values;
- }
-
- // \}
-
- //! Set the time for the time dependent boundary conditions (called from main)
592
593
594
595
596
597
598
599
600
601
602
603
604
605
606
607
608
609
610
611
612
613
614
615
616
617
618
- 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
- Scalar time_;
-};
-
-} //end namespace Dumux
-
-#endif
diff -ruN exercises/exercise-basic/params.input exercises/solution/exercise-basic/params.input
--- exercises/exercise-basic/params.input 2024-07-11 13:35:11.644137283 +0200
+++ exercises/solution/exercise-basic/params.input 2025-03-03 15:23:33.246567644 +0100
@@ -24,7 +24,7 @@
Aquifer.Snr = 0.0
# these parameters are only used in the nonisothermal model. Uncomment them for that
-#[Component]
-#SolidDensity = 2700 # solid density of granite
-#SolidThermalConductivity = 2.8 # solid thermal conducitivity of granite
-#SolidHeatCapacity = 790 # solid heat capacity of granite
+[Component]
+SolidDensity = 2700 # solid density of granite
+SolidThermalConductivity = 2.8 # solid thermal conducitivity of granite
+SolidHeatCapacity = 790 # solid heat capacity of granite
diff -ruN exercises/exercise-basic/properties2p.hh exercises/solution/exercise-basic/properties2p.hh
--- exercises/exercise-basic/properties2p.hh 2025-03-03 15:56:59.902625104 +0100
+++ exercises/solution/exercise-basic/properties2p.hh 1970-01-01 01:00:00.000000000 +0100
-// -*- mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*-
-// vi: set et ts=4 sw=4 sts=4:
-//
-// SPDX-FileCopyrightInfo: Copyright © DuMux-Course contributors, see AUTHORS.md in root folder
-// SPDX-License-Identifier: GPL-3.0-or-later
-//
643
644
645
646
647
648
649
650
651
652
653
654
655
656
657
658
659
660
661
662
663
664
665
666
667
668
669
670
671
672
673
674
675
676
677
678
679
680
681
682
683
684
685
686
687
688
689
690
691
692
693
694
695
696
697
698
699
700
-/*!
- * \file
- *
- * \brief The two-phase porousmediumflow properties file for exercise-basic
- */
-
-#ifndef DUMUX_EX_BASIC_PROPERTIES_2P_HH
-#define DUMUX_EX_BASIC_PROPERTIES_2P_HH
-
-#include <dune/grid/yaspgrid.hh>
-
-#include <dumux/discretization/cctpfa.hh>
-#include <dumux/porousmediumflow/2p/model.hh>
-#include <dumux/material/fluidsystems/h2on2.hh>
-
-#include "injection2pproblem.hh"
-#include "injection2pspatialparams.hh"
-
-namespace Dumux::Properties {
-
-// define the TypeTag for this problem with a cell-centered two-point flux approximation spatial discretization.
-// Create new type tags
-namespace TTag {
-struct Injection2p { using InheritsFrom = std::tuple<TwoP>; };
-struct Injection2pCC { using InheritsFrom = std::tuple<Injection2p, CCTpfaModel>; };
-} // end namespace TTag
-
-// Set the grid type
-template<class TypeTag>
-struct Grid<TypeTag, TTag::Injection2p> { using type = Dune::YaspGrid<2>; };
-
-// Set the problem property
-template<class TypeTag>
-struct Problem<TypeTag, TTag::Injection2p> { using type = Injection2PProblem<TypeTag>; };
-
-// Set the spatial parameters
-template<class TypeTag>
-struct SpatialParams<TypeTag, TTag::Injection2p>
-{
-private:
- using GridGeometry = GetPropType<TypeTag, Properties::GridGeometry>;
- using Scalar = GetPropType<TypeTag, Properties::Scalar>;
-public:
- using type = InjectionSpatialParams<GridGeometry, Scalar>;
-};
-
-// Set fluid configuration
-template<class TypeTag>
-struct FluidSystem<TypeTag, TTag::Injection2p>
-{
- using type = FluidSystems::H2ON2< GetPropType<TypeTag, Properties::Scalar>,
- FluidSystems::H2ON2DefaultPolicy</*fastButSimplifiedRelations=*/ true> >;
-};
-
-} // end namespace Dumux::Properties
-
-#endif
diff -ruN exercises/exercise-basic/properties2pni.hh exercises/solution/exercise-basic/properties2pni.hh
--- exercises/exercise-basic/properties2pni.hh 2025-03-03 15:56:59.902625104 +0100
+++ exercises/solution/exercise-basic/properties2pni.hh 2025-03-03 15:56:59.909624983 +0100
namespace Dumux::Properties {
- /*!
-* TODO:dumux-course-task 4
-* Inherit from the TwoPNI model instead of TwoP here
-*/
// Create new type tags
namespace TTag {
-struct Injection2pNITypeTag { using InheritsFrom = std::tuple<TwoP>; };
+struct Injection2pNITypeTag { using InheritsFrom = std::tuple<TwoPNI>; };
struct Injection2pNICC { using InheritsFrom = std::tuple<Injection2pNITypeTag, CCTpfaModel>; };
} // end namespace TTag
diff -ruN exercises/exercise-basic/README.md exercises/solution/exercise-basic/README.md
--- exercises/exercise-basic/README.md 2025-03-03 15:23:33.239567801 +0100
+++ exercises/solution/exercise-basic/README.md 1970-01-01 01:00:00.000000000 +0100
-# Exercise Basics (DuMuX course)
-
-## Problem set-up
-
-N$_2$ is injected in an aquifer previously saturated with water with an injection rate of 0.0001 kg/(s*m$^2$).
-The aquifer is situated 2700 m below sea level and the domain size is 60 m x 40 m. It consists of two layers, a moderately permeable one ($\Omega_1$) and a lower permeable one ($\Omega_2$).
-
-<img src="https://git.iws.uni-stuttgart.de/dumux-repositories/dumux-course/raw/master/slides/img/exercise_basic_setup.png" width="1000">
-
-## Preparing the exercise
-
-* Navigate to the directory `dumux-course/exercises/exercise-basic`
-
-This exercise deals with two problems: a two-phase immiscible problem (__2p__) and a two-phase non-isothermal problem (__2pni__). They both set up the same scenario with the difference that the 2pni model introduces an extra energy equation.
-
-
-Locate all the files you will need for this exercise
-* The __main file__ for the __2p__ problem : `2pmain.cc`
-* The __problem file__ for the __2p__ problem: `injection2pproblem.hh`
-* The __problem file__ for the __2pni__ problem: `injection2pniproblem.hh`
-* The __properties file__ for the __2p__ problem: `properties2p.hh`
-* The __properties file__ for the __2pni__ problem: `properties2pni.hh`
-* The shared __spatial parameters file__: `injection2pspatialparams.hh`
-* The shared __input file__: `params.input`
-
-## Task 2: Compiling and running an executable
-
-* Change to the build-directory
-
-```bash
-cd ../../build-cmake/exercises/exercise-basic
-```
-
-
-```bash
-```
-
-
-```bash
-./exercise_basic_2p params.input
-```
-
-* you can look at the results with paraview
-
-```bash
-```
-
-## Task 3: Setting up a new executable (for a non-isothermal simulation)
-
-* Copy the main file `2pmain.cc` and rename it to `2pnimain.cc`
-* In `2pnimain.cc`, include the header `properties2pni.hh` instead of `properties2p.hh`.
-* In `2pnimain.cc`, change `Injection2pCC` to `Injection2pNICC` in the line `using TypeTag = Properties::TTag::Injection2pNICC;`
-* Add a new executable in `CMakeLists.txt` by adding the lines
-
-```cmake
-# the two-phase non-isothermal simulation program
-dumux_add_test(NAME exercise_basic_2pni
-```
-
-* In the respective build-cmake folder, test that everything compiles without error
-
-```bash
-make # should rerun cmake
-make exercise_basic_2pni # builds new executable
-```
-
-## Task 4: Setting up a non-isothermal __2pni__ test problem
-
-* Open the files `injection2pniproblem.hh` and `properties2pni.hh`.
-These are copies of the `injection2pproblem.hh` and `properties2p.hh` files, with some useful comments on how to implement a non-isothermal model.
-Look for comments containing
-
-```c++
-// TODO: dumux-course-task 4
-```
-
-* The following set-up should be realized:
-
- __Initial conditions:__ For the primary variable __temperature__ use a varying temperature of <br/>
-$`\displaystyle T(y) = 283~\text{K} + 0.03~\frac{\text{K}}{\text{m}} \cdot \left( d_\text{aquifer} - y \right)`$, <br/>
-with the aquifer depth
-$\displaystyle d_\text{aquifer}=2700~\text{m}$. Additionally, add a subdomain (20 < x < 30, 5 < y < 35), where you assign a constant initial temperature of 380 K.
-
- __Boundary conditions:__ Dirichlet boundary conditions at the left boundary with the same temperature gradient as in the initial conditions. For the Neumann conditions, assign an energy flux at the injection point of N$_2$ and no-flow conditions for the energy balance to the rest of the boundaries.
-
-<img src="https://git.iws.uni-stuttgart.de/dumux-repositories/dumux-course/raw/master/slides/img/exercise_basic_nonisothermal.png" width="800">
-
-The non-isothermal model requires additional parameters like the thermal conductivity of the solid component. They are already implemented and set in `params.input`, you just need to _uncomment_ them.