co2plumeshapeproblem.hh 13.9 KB
Newer Older
1
2
3
// -*- mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*-
// vi: set et ts=4 sw=4 sts=4:
/*****************************************************************************
4
 *   See the file COPYING for full copying permissions.                      *
5
6
7
8
9
10
11
12
 *                                                                           *
 *   This program is free software: you can redistribute it and/or modify    *
 *   it under the terms of the GNU General Public License as published by    *
 *   the Free Software Foundation, either version 2 of the License, or       *
 *   (at your option) any later version.                                     *
 *                                                                           *
 *   This program is distributed in the hope that it will be useful,         *
 *   but WITHOUT ANY WARRANTY; without even the implied warranty of          *
13
 *   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the            *
14
15
16
17
18
19
20
 *   GNU General Public License for more details.                            *
 *                                                                           *
 *   You should have received a copy of the GNU General Public License       *
 *   along with this program.  If not, see <http://www.gnu.org/licenses/>.   *
 *****************************************************************************/
/*!
 * \file
Kai Wendel's avatar
Kai Wendel committed
21
 * \brief Definition of a problem, where CO2 is injected in a reservoir.
22
 */
Kai Wendel's avatar
Kai Wendel committed
23
24
25
#ifndef DUMUX_PLUMESHAPE_PROBLEM_HH
#define DUMUX_PLUMESHAPE_PROBLEM_HH

26
27
#include <dumux/common/properties.hh>
#include <dumux/common/parameters.hh>
28
#include <dumux/common/boundarytypes.hh>
29
#include <dumux/common/numeqvector.hh>
Kai Wendel's avatar
Kai Wendel committed
30
31
#include <dumux/porousmediumflow/problem.hh>

32
#include <dumux/material/fluidsystems/brineco2.hh>
Kai Wendel's avatar
Kai Wendel committed
33
#include <dumux/discretization/box/scvftoscvboundarytypes.hh>
34

35
#include <lecture/common/co2tablesbenchmark3.hh>
36

Kai Wendel's avatar
Kai Wendel committed
37
38
// per default use isothermal model
#ifndef ISOTHERMAL
Katharina Heck's avatar
Katharina Heck committed
39
#define ISOTHERMAL 0
Kai Wendel's avatar
Kai Wendel committed
40
#endif
41

Kai Wendel's avatar
Kai Wendel committed
42
namespace Dumux {
43
44

/*!
Kai Wendel's avatar
Kai Wendel committed
45
 * \brief Definition of a problem, where CO2 is injected in a reservoir.
46
 *
Kai Wendel's avatar
Kai Wendel committed
47
48
49
 * The domain is sized 200m times 100m and consists of four layers, a
 * permeable reservoir layer at the bottom, a barrier rock layer with reduced permeability, another reservoir layer
 * and at the top a barrier rock layer with a very low permeablility.
50
 *
Kai Wendel's avatar
Kai Wendel committed
51
52
 * CO2 is injected at the permeable bottom layer
 * from the left side. The domain is initially filled with brine.
53
 *
Kai Wendel's avatar
Kai Wendel committed
54
55
56
57
 * The grid is unstructered and permeability and porosity for the elements are read in from the grid file. The grid file
 * also contains so-called boundary ids which can be used assigned during the grid creation in order to differentiate
 * between different parts of the boundary.
 * These boundary ids can be imported into the problem where the boundary conditions can then be assigned accordingly.
58
 *
Kai Wendel's avatar
Kai Wendel committed
59
60
 * The model is able to use either mole or mass fractions. The property useMoles can be set to either true or false in the
 * problem file. Make sure that the according units are used in the problem setup. The default setting for useMoles is false.
61
 *
Kai Wendel's avatar
Kai Wendel committed
62
63
64
 * To run the simulation execute the following line in shell (works with the box and cell centered spatial discretization method):
 * <tt>./test_ccco2 </tt> or <tt>./test_boxco2 </tt>
 */
65
template <class TypeTag >
Kai Wendel's avatar
Kai Wendel committed
66
class PlumeShapeProblem : public PorousMediumFlowProblem<TypeTag>
67
{
Kai Wendel's avatar
Kai Wendel committed
68
    using ParentType = PorousMediumFlowProblem<TypeTag>;
69

70
    using GridView = typename GetPropType<TypeTag, Properties::GridGeometry>::GridView;
71
72
73
    using Scalar = GetPropType<TypeTag, Properties::Scalar>;
    using FluidSystem = GetPropType<TypeTag, Properties::FluidSystem>;
    using VolumeVariables = GetPropType<TypeTag, Properties::VolumeVariables>;
74
75
76
    using GridVariables = GetPropType<TypeTag, Properties::GridVariables>;
    using ElementFluxVariablesCache = typename GridVariables::GridFluxVariablesCache::LocalView;
    using ElementVolumeVariables = typename GridVariables::GridVolumeVariables::LocalView;
77

78
    using ModelTraits = GetPropType<TypeTag, Properties::ModelTraits>;
Kai Wendel's avatar
Kai Wendel committed
79
    using Indices = typename ModelTraits::Indices;
80

81
    // copy some indices for convenience
Kai Wendel's avatar
Kai Wendel committed
82
83
84
85
86
87
88
89
    enum
    {
        // primary variable indices
        pressureIdx = Indices::pressureIdx,
        switchIdx = Indices::switchIdx,

        // phase presence index
        firstPhaseOnly = Indices::firstPhaseOnly,
90

Kai Wendel's avatar
Kai Wendel committed
91
        // component indices
92
93
        BrineIdx = FluidSystem::BrineIdx,
        CO2Idx = FluidSystem::CO2Idx,
94

Kai Wendel's avatar
Kai Wendel committed
95
        // equation indices
96
        conti0EqIdx = Indices::conti0EqIdx,
Kai Wendel's avatar
Kai Wendel committed
97
98
        contiCO2EqIdx = conti0EqIdx + CO2Idx
    };
99

Kai Wendel's avatar
Kai Wendel committed
100
101
#if !ISOTHERMAL
    enum {
102
103
        temperatureIdx = Indices::temperatureIdx,
        energyEqIdx = Indices::energyEqIdx,
104
    };
Kai Wendel's avatar
Kai Wendel committed
105
#endif
106

107
    using PrimaryVariables = GetPropType<TypeTag, Properties::PrimaryVariables>;
108
    using NumEqVector = Dumux::NumEqVector<PrimaryVariables>;
109
    using BoundaryTypes = Dumux::BoundaryTypes<GetPropType<TypeTag, Properties::ModelTraits>::numEq()>;
Kai Wendel's avatar
Kai Wendel committed
110
111
    using Element = typename GridView::template Codim<0>::Entity;
    using GlobalPosition = typename Element::Geometry::GlobalCoordinate;
112
113
    using FVGridGeometry = GetPropType<TypeTag, Properties::GridGeometry>;
    using FVElementGeometry = typename GetPropType<TypeTag, Properties::GridGeometry>::LocalView;
Kai Wendel's avatar
Kai Wendel committed
114
115
    using SubControlVolumeFace = typename FVElementGeometry::SubControlVolumeFace;
    using SubControlVolume = typename FVElementGeometry::SubControlVolume;
116

Yue Wang's avatar
Yue Wang committed
117
    using CO2 = Components::CO2<Scalar, GeneratedCO2Tables::CO2Tables>;
118

Kai Wendel's avatar
Kai Wendel committed
119
120
    //! property that defines whether mole or mass fractions are used
    static constexpr bool useMoles = ModelTraits::useMoles();
121

Kai Wendel's avatar
Kai Wendel committed
122
    // the discretization method we are using
123
    static constexpr auto discMethod = GetPropType<TypeTag, Properties::GridGeometry>::discMethod;
Kai Wendel's avatar
Kai Wendel committed
124
125
126

    // world dimension to access gravity vector
    static constexpr int dimWorld = GridView::dimensionworld;
127
128
129
130
131
132
133
134

public:
    /*!
     * \brief The constructor
     *
     * \param timeManager The time manager
     * \param gridView The grid view
     */
Kai Wendel's avatar
Kai Wendel committed
135
136
    PlumeShapeProblem(std::shared_ptr<const FVGridGeometry> fvGridGeometry)
    : ParentType(fvGridGeometry)
137
    {
138
139
140
141
142
143
144
        nTemperature_         = getParam<int>("FluidSystem.NTemperature");
        nPressure_            = getParam<int>("FluidSystem.NPressure");
        pressureLow_          = getParam<Scalar>("FluidSystem.PressureLow");
        pressureHigh_         = getParam<Scalar>("FluidSystem.PressureHigh");
        temperatureLow_       = getParam<Scalar>("FluidSystem.TemperatureLow");
        temperatureHigh_      = getParam<Scalar>("FluidSystem.TemperatureHigh");
        name_                 = getParam<std::string>("Problem.Name");
Kai Wendel's avatar
Kai Wendel committed
145
146
        pressure_             = getParam<Scalar>("InitialConditions.Pressure"); // hydrodynamic pressure at top layer
        temperature_          = getParam<Scalar>("InitialConditions.Temperature");
147
        injectionRate_        = getParam<Scalar>("BoundaryConditions.InjectionRate");
Kai Wendel's avatar
Kai Wendel committed
148
149
        injectionTemperature_ = getParam<Scalar>("BoundaryConditions.InjectionTemperature");
        dipAngle_             = getParam<Scalar>("SpatialParams.DipAngle"); // [deg]
150
151
152
153
154
155

        dipAngleRadians_ = (dipAngle_ * M_PI)/180.0; // [rad]
        // rotate the coordinate system / gravity:
        gravity_[1] = -9.81 * cos(dipAngleRadians_);
        gravity_[0] = -9.81 * sin(dipAngleRadians_);

156

Kai Wendel's avatar
Kai Wendel committed
157
158
159
160
161
162
163
164
165
166
167
168
169
        // initialize the tables of the fluid system
        FluidSystem::init(/*Tmin=*/temperatureLow_,
                          /*Tmax=*/temperatureHigh_,
                          /*nT=*/nTemperature_,
                          /*pmin=*/pressureLow_,
                          /*pmax=*/pressureHigh_,
                          /*np=*/nPressure_);

        //stating in the console whether mole or mass fractions are used
        if(useMoles)
            std::cout<<"problem uses mole fractions"<<std::endl;
        else
            std::cout<<"problem uses mass fractions"<<std::endl;
170
171
172
173
174
175
176
177
178
179
180
181
    }

    /*!
     * \name Problem parameters
     */
    // \{

    /*!
     * \brief The problem name.
     *
     * This is used as a prefix for files generated by the simulation.
     */
Kai Wendel's avatar
Kai Wendel committed
182
    const std::string& name() const
183
    { return name_; }
184

185
186
187
    /*!
     * \brief Returns the temperature within the domain.
     *
Kai Wendel's avatar
Kai Wendel committed
188
189
190
191
     * \param globalPos The position
     *
     * This problem assumes a geothermal gradient with
     * a surface temperature of 10 degrees Celsius.
192
193
     */
    Scalar temperature() const
Kai Wendel's avatar
Kai Wendel committed
194
    { return temperature_; }
195

Kai Wendel's avatar
Kai Wendel committed
196
    // \}
197
198
199
200
201

    /*!
     * \name Boundary conditions
     */
    // \{
202

203
204
205
206
207
    /*!
     * \brief Specifies which kind of boundary condition should be
     *        used for which equation on a given boundary segment.
     *
     */
Kai Wendel's avatar
Kai Wendel committed
208
209

    BoundaryTypes boundaryTypesAtPos(const GlobalPosition &globalPos) const
210
    {
Kai Wendel's avatar
Kai Wendel committed
211
        BoundaryTypes values;
212

213
        values.setAllNeumann();
214

215
        // set East boundaries to Dirichlet values
216
        if ( globalPos[0] > this->gridGeometry().bBoxMax()[0] - eps_  )
217
218
219
        {
            values.setAllDirichlet();
        }
Kai Wendel's avatar
Kai Wendel committed
220
221

        return values;
222
    }
223

224
    /*!
Kai Wendel's avatar
Kai Wendel committed
225
226
     * \brief Evaluates the boundary conditions for a Dirichlet
     *        boundary segment
227
     *
Kai Wendel's avatar
Kai Wendel committed
228
229
230
     * \param returns the Dirichlet values for the conservation equations in
     *               \f$ [ \textnormal{unit of primary variable} ] \f$
     * \param globalPos The global position
231
     */
Kai Wendel's avatar
Kai Wendel committed
232
233
    PrimaryVariables dirichletAtPos(const GlobalPosition &globalPos) const
    { return initial_(globalPos); }
234

235
236
237
238
    /*!
     * \brief Evaluate the boundary conditions for a neumann
     *        boundary segment.
     *
Kai Wendel's avatar
Kai Wendel committed
239
240
241
242
243
244
     * This is the method for the case where the Neumann condition is
     * potentially solution dependent and requires some quantities that
     * are specific to the fully-implicit method.
     *
     * \param values The neumann values for the conservation equations in units of
     *                 \f$ [ \textnormal{unit of conserved quantity} / (m^2 \cdot s )] \f$
245
     * \param element The finite element
Kai Wendel's avatar
Kai Wendel committed
246
247
     * \param fvGeometry The finite-volume geometry
     * \param elemVolVars All volume variables for the element
248
     * \param elemFluxVarsCache Flux variables caches for all faces in stencil
Kai Wendel's avatar
Kai Wendel committed
249
     * \param scvf The sub control volume face
250
     *
Kai Wendel's avatar
Kai Wendel committed
251
     * For this method, the \a values parameter stores the flux
252
     * in normal direction of each phase. Negative values mean influx.
Kai Wendel's avatar
Kai Wendel committed
253
     * E.g. for the mass balance that would the mass flux in \f$ [ kg / (m^2 \cdot s)] \f$.
254
     */
Kai Wendel's avatar
Kai Wendel committed
255
    NumEqVector neumann(const Element& element,
Katharina Heck's avatar
Katharina Heck committed
256
                        const FVElementGeometry& fvGeometry,
257
258
                        const ElementVolumeVariables& elemVolVars,
                        const ElementFluxVariablesCache& elemFluxVarsCache,
Katharina Heck's avatar
Katharina Heck committed
259
                        const SubControlVolumeFace& scvf) const
260
    {
Kai Wendel's avatar
Kai Wendel committed
261
        NumEqVector fluxes(0.0);
262
        // kg/(m^2*s) or mole/(m^2*s) depending on useMoles
Katharina Heck's avatar
Katharina Heck committed
263
        const auto globalPos = scvf.ipGlobal();
264
265
266
        if ( globalPos[1] < 30.0 + eps_ && globalPos[0] < eps_ )
        {
            Scalar massFlux = injectionRate_ /30.0; // [kg/(s*m^2)]
Kai Wendel's avatar
Kai Wendel committed
267
            fluxes[contiCO2EqIdx] = -massFlux; // kg/(s*m^2)
268
#if !ISOTHERMAL
269
            const Scalar pressure = elemVolVars[scvf.insideScvIdx()].pressure(FluidSystem::phase1Idx);
Kai Wendel's avatar
Kai Wendel committed
270
            fluxes[energyEqIdx] = -massFlux*CO2::gasEnthalpy(injectionTemperature_, pressure);
271
272
#endif
        }
Kai Wendel's avatar
Kai Wendel committed
273
274

        return fluxes;
275
    }
276

Kai Wendel's avatar
Kai Wendel committed
277
    // \}
278

279
    /*!
Kai Wendel's avatar
Kai Wendel committed
280
     * \name Volume terms
281
     */
Kai Wendel's avatar
Kai Wendel committed
282
    // \{
283

284
    /*!
Kai Wendel's avatar
Kai Wendel committed
285
     * \brief Evaluates the initial values at a position
286
     *
Kai Wendel's avatar
Kai Wendel committed
287
288
     * \returns the initial values for the conservation equations in
     *           \f$ [ \textnormal{unit of primary variables} ] \f$
289
290
     * \param globalPos The global position
     */
Kai Wendel's avatar
Kai Wendel committed
291
    PrimaryVariables initialAtPos(const GlobalPosition &globalPos) const
292
    {
Kai Wendel's avatar
Kai Wendel committed
293
        return initial_(globalPos);
294
    }
295

Kai Wendel's avatar
Kai Wendel committed
296
297
    // \}

298
private:
Kai Wendel's avatar
Kai Wendel committed
299
300
301
302
303
304
305
306
307
308
    /*!
     * \brief Evaluates the initial values for a control volume
     *
     * The internal method for the initial condition
     *
     * \param values Stores the initial values for the conservation equations in
     *               \f$ [ \textnormal{unit of primary variables} ] \f$
     * \param globalPos The global position
     */
    PrimaryVariables initial_(const GlobalPosition &globalPos) const
309
    {
Kai Wendel's avatar
Kai Wendel committed
310
311
312
        PrimaryVariables values(0.0);
        values.setState(firstPhaseOnly);

313
        const Scalar densityW = FluidSystem::Brine::liquidDensity(temperature_, 1e5);
314

315
316
        const Scalar moleFracLiquidCO2 = 0.00;
        const Scalar moleFracLiquidBrine = 1.0 - moleFracLiquidCO2;
317

318
319
        const Scalar meanM = FluidSystem::molarMass(BrineIdx)*moleFracLiquidBrine +
                             FluidSystem::molarMass(CO2Idx)*moleFracLiquidCO2;
320

321
        const Scalar massFracLiquidCO2 = moleFracLiquidCO2*FluidSystem::molarMass(CO2Idx)/meanM;
322

323
        // set initial pressure and pressure Dirichlet conditions:
324
        const Scalar distanceToTopBoundary_ = ( this->gridGeometry().bBoxMax()[1] - this->gridGeometry().bBoxMin()[1] ) - globalPos[1]; // distance without rotation
325
        const Scalar distanceToTopBoundaryRotated_ = distanceToTopBoundary_ / std::cos(dipAngleRadians_);
326

327
        const Scalar distanceTopBoundaryToSurface_ = std::sin(dipAngleRadians_) * (this->gridGeometry().bBoxMax()[0] - globalPos[0]);
328
329
        values[Indices::pressureIdx] = pressure_ + densityW * 9.81 * distanceToTopBoundaryRotated_ +
                                       densityW * 9.81 * distanceTopBoundaryToSurface_;
330

331
        values[Indices::switchIdx] = massFracLiquidCO2;
332

Katharina Heck's avatar
Katharina Heck committed
333
334
335
336
337
#if !ISOTHERMAL
        values[temperatureIdx] = temperature_;//290.0 + (depthBOR_ - globalPos[1])*0.03;
#endif


Kai Wendel's avatar
Kai Wendel committed
338
        return values;
339
    }
340

341
    Scalar injectionRate_;
342

Kai Wendel's avatar
Kai Wendel committed
343
#if !ISOTHERMAL
Katharina Heck's avatar
Katharina Heck committed
344
    Scalar injectionTemperature_;
Kai Wendel's avatar
Kai Wendel committed
345
#endif
346

347
348
    int nTemperature_;
    int nPressure_;
349

Kai Wendel's avatar
Kai Wendel committed
350
351
352
353
354
355
356
    Scalar temperature_;
    Scalar pressure_;

    Scalar dipAngleRadians_, dipAngle_;

    GlobalPosition gravity_;

357
    Scalar eps_ = 1.e-6;
Kai Wendel's avatar
Kai Wendel committed
358

359
    std::string name_ ;
360

Kai Wendel's avatar
Kai Wendel committed
361
    Scalar pressureLow_, pressureHigh_;
362
363
    Scalar temperatureLow_, temperatureHigh_;
};
364

Kai Wendel's avatar
Kai Wendel committed
365
} //end namespace Dumux
366
367

#endif