mirror of
https://github.com/OPM/opm-simulators.git
synced 2025-02-25 18:55:30 -06:00
changed: ewoms/disc -> opm/models/discretization
This commit is contained in:
parent
f48ae0f7f1
commit
474ae4ded8
@ -34,7 +34,7 @@
|
||||
|
||||
#include <opm/models/utils/start.hh>
|
||||
#include <ewoms/models/flash/flashmodel.hh>
|
||||
#include <ewoms/disc/ecfv/ecfvdiscretization.hh>
|
||||
#include <opm/models/discretization/ecfv/ecfvdiscretization.hh>
|
||||
#include "problems/co2injectionflash.hh"
|
||||
#include "problems/co2injectionproblem.hh"
|
||||
|
||||
|
@ -31,7 +31,7 @@
|
||||
#include <opm/material/common/quad.hpp>
|
||||
#include <opm/models/utils/start.hh>
|
||||
#include <ewoms/models/flash/flashmodel.hh>
|
||||
#include <ewoms/disc/ecfv/ecfvdiscretization.hh>
|
||||
#include <opm/models/discretization/ecfv/ecfvdiscretization.hh>
|
||||
#include "problems/co2injectionflash.hh"
|
||||
#include "problems/co2injectionproblem.hh"
|
||||
|
||||
|
@ -31,7 +31,7 @@
|
||||
#include <opm/material/common/quad.hpp>
|
||||
#include <opm/models/utils/start.hh>
|
||||
#include <ewoms/models/flash/flashmodel.hh>
|
||||
#include <ewoms/disc/vcfv/vcfvdiscretization.hh>
|
||||
#include <opm/models/discretization/vcfv/vcfvdiscretization.hh>
|
||||
#include "problems/co2injectionflash.hh"
|
||||
#include "problems/co2injectionproblem.hh"
|
||||
|
||||
|
@ -34,7 +34,7 @@
|
||||
|
||||
#include <opm/models/utils/start.hh>
|
||||
#include <ewoms/models/flash/flashmodel.hh>
|
||||
#include <ewoms/disc/vcfv/vcfvdiscretization.hh>
|
||||
#include <opm/models/discretization/vcfv/vcfvdiscretization.hh>
|
||||
#include "problems/co2injectionflash.hh"
|
||||
#include "problems/co2injectionproblem.hh"
|
||||
|
||||
|
@ -30,7 +30,7 @@
|
||||
|
||||
#include <opm/models/utils/start.hh>
|
||||
#include <ewoms/models/immiscible/immisciblemodel.hh>
|
||||
#include <ewoms/disc/ecfv/ecfvdiscretization.hh>
|
||||
#include <opm/models/discretization/ecfv/ecfvdiscretization.hh>
|
||||
|
||||
#include "problems/co2injectionproblem.hh"
|
||||
|
||||
|
@ -30,7 +30,7 @@
|
||||
|
||||
#include <opm/models/utils/start.hh>
|
||||
#include <ewoms/models/immiscible/immisciblemodel.hh>
|
||||
#include <ewoms/disc/ecfv/ecfvdiscretization.hh>
|
||||
#include <opm/models/discretization/ecfv/ecfvdiscretization.hh>
|
||||
#include "problems/co2injectionproblem.hh"
|
||||
|
||||
BEGIN_PROPERTIES
|
||||
|
@ -30,7 +30,7 @@
|
||||
|
||||
#include <opm/models/utils/start.hh>
|
||||
#include <ewoms/models/immiscible/immisciblemodel.hh>
|
||||
#include <ewoms/disc/vcfv/vcfvdiscretization.hh>
|
||||
#include <opm/models/discretization/vcfv/vcfvdiscretization.hh>
|
||||
#include "problems/co2injectionproblem.hh"
|
||||
|
||||
BEGIN_PROPERTIES
|
||||
|
@ -30,7 +30,7 @@
|
||||
|
||||
#include <opm/models/utils/start.hh>
|
||||
#include <ewoms/models/immiscible/immisciblemodel.hh>
|
||||
#include <ewoms/disc/vcfv/vcfvdiscretization.hh>
|
||||
#include <opm/models/discretization/vcfv/vcfvdiscretization.hh>
|
||||
|
||||
#include "problems/co2injectionproblem.hh"
|
||||
|
||||
|
@ -30,7 +30,7 @@
|
||||
|
||||
#include <opm/models/utils/start.hh>
|
||||
#include <ewoms/models/ncp/ncpmodel.hh>
|
||||
#include <ewoms/disc/ecfv/ecfvdiscretization.hh>
|
||||
#include <opm/models/discretization/ecfv/ecfvdiscretization.hh>
|
||||
#include "problems/co2injectionproblem.hh"
|
||||
|
||||
BEGIN_PROPERTIES
|
||||
|
@ -30,7 +30,7 @@
|
||||
|
||||
#include <opm/models/utils/start.hh>
|
||||
#include <ewoms/models/ncp/ncpmodel.hh>
|
||||
#include <ewoms/disc/ecfv/ecfvdiscretization.hh>
|
||||
#include <opm/models/discretization/ecfv/ecfvdiscretization.hh>
|
||||
#include "problems/co2injectionproblem.hh"
|
||||
|
||||
BEGIN_PROPERTIES
|
||||
|
@ -30,7 +30,7 @@
|
||||
|
||||
#include <opm/models/utils/start.hh>
|
||||
#include <ewoms/models/ncp/ncpmodel.hh>
|
||||
#include <ewoms/disc/vcfv/vcfvdiscretization.hh>
|
||||
#include <opm/models/discretization/vcfv/vcfvdiscretization.hh>
|
||||
#include "problems/co2injectionproblem.hh"
|
||||
|
||||
BEGIN_PROPERTIES
|
||||
|
@ -30,7 +30,7 @@
|
||||
|
||||
#include <opm/models/utils/start.hh>
|
||||
#include <ewoms/models/ncp/ncpmodel.hh>
|
||||
#include <ewoms/disc/vcfv/vcfvdiscretization.hh>
|
||||
#include <opm/models/discretization/vcfv/vcfvdiscretization.hh>
|
||||
|
||||
#include "problems/co2injectionproblem.hh"
|
||||
|
||||
|
@ -30,7 +30,7 @@
|
||||
|
||||
#include <opm/models/utils/start.hh>
|
||||
#include <ewoms/models/pvs/pvsmodel.hh>
|
||||
#include <ewoms/disc/ecfv/ecfvdiscretization.hh>
|
||||
#include <opm/models/discretization/ecfv/ecfvdiscretization.hh>
|
||||
#include "problems/co2injectionproblem.hh"
|
||||
|
||||
BEGIN_PROPERTIES
|
||||
|
@ -30,7 +30,7 @@
|
||||
|
||||
#include <opm/models/utils/start.hh>
|
||||
#include <ewoms/models/pvs/pvsmodel.hh>
|
||||
#include <ewoms/disc/ecfv/ecfvdiscretization.hh>
|
||||
#include <opm/models/discretization/ecfv/ecfvdiscretization.hh>
|
||||
#include "problems/co2injectionproblem.hh"
|
||||
|
||||
BEGIN_PROPERTIES
|
||||
|
@ -30,7 +30,7 @@
|
||||
|
||||
#include <opm/models/utils/start.hh>
|
||||
#include <ewoms/models/pvs/pvsmodel.hh>
|
||||
#include <ewoms/disc/vcfv/vcfvdiscretization.hh>
|
||||
#include <opm/models/discretization/vcfv/vcfvdiscretization.hh>
|
||||
#include "problems/co2injectionproblem.hh"
|
||||
|
||||
BEGIN_PROPERTIES
|
||||
|
@ -30,7 +30,7 @@
|
||||
|
||||
#include <opm/models/utils/start.hh>
|
||||
#include <ewoms/models/pvs/pvsmodel.hh>
|
||||
#include <ewoms/disc/vcfv/vcfvdiscretization.hh>
|
||||
#include <opm/models/discretization/vcfv/vcfvdiscretization.hh>
|
||||
|
||||
#include "problems/co2injectionproblem.hh"
|
||||
|
||||
|
@ -29,7 +29,7 @@
|
||||
|
||||
#include <opm/models/utils/start.hh>
|
||||
#include <ewoms/models/immiscible/immisciblemodel.hh>
|
||||
#include <ewoms/disc/ecfv/ecfvdiscretization.hh>
|
||||
#include <opm/models/discretization/ecfv/ecfvdiscretization.hh>
|
||||
#include "problems/fingerproblem.hh"
|
||||
|
||||
BEGIN_PROPERTIES
|
||||
|
@ -29,7 +29,7 @@
|
||||
|
||||
#include <ewoms/common/start.hh>
|
||||
#include <ewoms/models/immiscible/immisciblemodel.hh>
|
||||
#include <ewoms/disc/vcfv/vcfvdiscretization.hh>
|
||||
#include <opm/models/discretization/vcfv/vcfvdiscretization.hh>
|
||||
#include "problems/fingerproblem.hh"
|
||||
|
||||
BEGIN_PROPERTIES
|
||||
|
@ -30,7 +30,7 @@
|
||||
#define EWOMS_LENS_IMMISCIBLE_ECFV_AD_HH
|
||||
|
||||
#include <ewoms/models/immiscible/immisciblemodel.hh>
|
||||
#include <ewoms/disc/ecfv/ecfvdiscretization.hh>
|
||||
#include <opm/models/discretization/ecfv/ecfvdiscretization.hh>
|
||||
#include "problems/lensproblem.hh"
|
||||
|
||||
BEGIN_PROPERTIES
|
||||
|
@ -28,7 +28,7 @@
|
||||
#include "config.h"
|
||||
|
||||
#include <opm/models/utils/start.hh>
|
||||
#include <ewoms/disc/ecfv/ecfvdiscretization.hh>
|
||||
#include <opm/models/discretization/ecfv/ecfvdiscretization.hh>
|
||||
|
||||
#include "problems/richardslensproblem.hh"
|
||||
|
||||
|
@ -28,7 +28,7 @@
|
||||
#include "config.h"
|
||||
|
||||
#include <opm/models/utils/start.hh>
|
||||
#include <ewoms/disc/vcfv/vcfvdiscretization.hh>
|
||||
#include <opm/models/discretization/vcfv/vcfvdiscretization.hh>
|
||||
|
||||
#include "problems/richardslensproblem.hh"
|
||||
|
||||
|
@ -42,7 +42,7 @@
|
||||
#include <opm/material/components/Air.hpp>
|
||||
|
||||
#include <ewoms/models/immiscible/immiscibleproperties.hh>
|
||||
#include <ewoms/disc/common/restrictprolong.hh>
|
||||
#include <opm/models/discretization/common/restrictprolong.hh>
|
||||
|
||||
#if HAVE_DUNE_ALUGRID
|
||||
#include <dune/alugrid/grid.hh>
|
||||
|
@ -30,8 +30,8 @@
|
||||
|
||||
#include <ewoms/io/structuredgridvanguard.hh>
|
||||
#include <ewoms/models/immiscible/immiscibleproperties.hh>
|
||||
#include <ewoms/disc/common/fvbaseadlocallinearizer.hh>
|
||||
#include <ewoms/disc/ecfv/ecfvdiscretization.hh>
|
||||
#include <opm/models/discretization/common/fvbaseadlocallinearizer.hh>
|
||||
#include <opm/models/discretization/ecfv/ecfvdiscretization.hh>
|
||||
|
||||
#include <opm/material/fluidmatrixinteractions/RegularizedVanGenuchten.hpp>
|
||||
#include <opm/material/fluidmatrixinteractions/LinearMaterial.hpp>
|
||||
|
@ -30,7 +30,7 @@
|
||||
|
||||
#include <opm/models/utils/start.hh>
|
||||
#include <opm/models/blackoil/blackoilmodel.hh>
|
||||
#include <ewoms/disc/ecfv/ecfvdiscretization.hh>
|
||||
#include <opm/models/discretization/ecfv/ecfvdiscretization.hh>
|
||||
#include "problems/reservoirproblem.hh"
|
||||
|
||||
BEGIN_PROPERTIES
|
||||
|
@ -29,7 +29,7 @@
|
||||
|
||||
#include <opm/models/utils/start.hh>
|
||||
#include <opm/models/blackoil/blackoilmodel.hh>
|
||||
#include <ewoms/disc/vcfv/vcfvdiscretization.hh>
|
||||
#include <opm/models/discretization/vcfv/vcfvdiscretization.hh>
|
||||
#include "problems/reservoirproblem.hh"
|
||||
|
||||
BEGIN_PROPERTIES
|
||||
|
@ -29,7 +29,7 @@
|
||||
|
||||
#include <opm/models/utils/start.hh>
|
||||
#include <ewoms/models/ncp/ncpmodel.hh>
|
||||
#include <ewoms/disc/ecfv/ecfvdiscretization.hh>
|
||||
#include <opm/models/discretization/ecfv/ecfvdiscretization.hh>
|
||||
#include "problems/reservoirproblem.hh"
|
||||
|
||||
BEGIN_PROPERTIES
|
||||
|
@ -30,7 +30,7 @@
|
||||
|
||||
#include <opm/models/utils/start.hh>
|
||||
#include <ewoms/models/ncp/ncpmodel.hh>
|
||||
#include <ewoms/disc/vcfv/vcfvdiscretization.hh>
|
||||
#include <opm/models/discretization/vcfv/vcfvdiscretization.hh>
|
||||
#include "problems/reservoirproblem.hh"
|
||||
|
||||
BEGIN_PROPERTIES
|
||||
|
@ -32,7 +32,7 @@
|
||||
#include <ewoms/models/immiscible/immisciblemodel.hh>
|
||||
|
||||
// The spatial discretization (VCFV == Vertex-Centered Finite Volumes)
|
||||
#include <ewoms/disc/vcfv/vcfvdiscretization.hh> /*@\label{tutorial1:include-discretization}@*/
|
||||
#include <opm/models/discretization/vcfv/vcfvdiscretization.hh> /*@\label{tutorial1:include-discretization}@*/
|
||||
|
||||
// The chemical species that are used
|
||||
#include <opm/material/components/SimpleH2O.hpp>
|
||||
|
@ -34,7 +34,7 @@
|
||||
#include "blackoilenergymodules.hh"
|
||||
#include "blackoilfoammodules.hh"
|
||||
|
||||
#include <ewoms/disc/common/fvbaseprimaryvariables.hh>
|
||||
#include <opm/models/discretization/common/fvbaseprimaryvariables.hh>
|
||||
|
||||
#include <dune/common/fvector.hh>
|
||||
|
||||
|
@ -28,7 +28,7 @@
|
||||
#ifndef EWOMS_DIFFUSION_MODULE_HH
|
||||
#define EWOMS_DIFFUSION_MODULE_HH
|
||||
|
||||
#include <ewoms/disc/common/fvbaseproperties.hh>
|
||||
#include <opm/models/discretization/common/fvbaseproperties.hh>
|
||||
#include <opm/models/common/quantitycallbacks.hh>
|
||||
|
||||
#include <opm/material/common/Valgrind.hpp>
|
||||
|
@ -29,7 +29,7 @@
|
||||
#ifndef EWOMS_ENERGY_MODULE_HH
|
||||
#define EWOMS_ENERGY_MODULE_HH
|
||||
|
||||
#include <ewoms/disc/common/fvbaseproperties.hh>
|
||||
#include <opm/models/discretization/common/fvbaseproperties.hh>
|
||||
#include <opm/models/common/quantitycallbacks.hh>
|
||||
|
||||
#include <opm/material/common/Valgrind.hpp>
|
||||
|
@ -32,7 +32,7 @@
|
||||
|
||||
#include "darcyfluxmodule.hh"
|
||||
|
||||
#include <ewoms/disc/common/fvbaseproperties.hh>
|
||||
#include <opm/models/discretization/common/fvbaseproperties.hh>
|
||||
|
||||
#include <opm/material/common/Valgrind.hpp>
|
||||
#include <opm/material/common/Unused.hpp>
|
||||
|
@ -31,7 +31,7 @@
|
||||
#include "multiphasebaseproperties.hh"
|
||||
|
||||
#include <opm/models/common/quantitycallbacks.hh>
|
||||
#include <ewoms/disc/common/fvbaseextensivequantities.hh>
|
||||
#include <opm/models/discretization/common/fvbaseextensivequantities.hh>
|
||||
#include <opm/models/utils/parametersystem.hh>
|
||||
|
||||
#include <opm/material/common/Valgrind.hpp>
|
||||
|
@ -35,7 +35,7 @@
|
||||
#include "multiphasebaseextensivequantities.hh"
|
||||
|
||||
#include <opm/models/common/flux.hh>
|
||||
#include <ewoms/disc/vcfv/vcfvdiscretization.hh>
|
||||
#include <opm/models/discretization/vcfv/vcfvdiscretization.hh>
|
||||
|
||||
#include <opm/material/fluidmatrixinteractions/NullMaterial.hpp>
|
||||
#include <opm/material/fluidmatrixinteractions/MaterialTraits.hpp>
|
||||
|
@ -30,8 +30,8 @@
|
||||
|
||||
#include "multiphasebaseproperties.hh"
|
||||
|
||||
#include <ewoms/disc/common/fvbaseproblem.hh>
|
||||
#include <ewoms/disc/common/fvbaseproperties.hh>
|
||||
#include <opm/models/discretization/common/fvbaseproblem.hh>
|
||||
#include <opm/models/discretization/common/fvbaseproperties.hh>
|
||||
|
||||
#include <opm/material/fluidmatrixinteractions/NullMaterial.hpp>
|
||||
#include <opm/material/common/Means.hpp>
|
||||
|
@ -30,7 +30,7 @@
|
||||
#ifndef EWOMS_MULTI_PHASE_BASE_PROPERTIES_HH
|
||||
#define EWOMS_MULTI_PHASE_BASE_PROPERTIES_HH
|
||||
|
||||
#include <ewoms/disc/common/fvbaseproperties.hh>
|
||||
#include <opm/models/discretization/common/fvbaseproperties.hh>
|
||||
#include <ewoms/io/vtkmultiphasemodule.hh>
|
||||
#include <ewoms/io/vtktemperaturemodule.hh>
|
||||
|
||||
|
@ -29,7 +29,7 @@
|
||||
#ifndef EWOMS_QUANTITY_CALLBACKS_HH
|
||||
#define EWOMS_QUANTITY_CALLBACKS_HH
|
||||
|
||||
#include <ewoms/disc/common/fvbaseproperties.hh>
|
||||
#include <opm/models/discretization/common/fvbaseproperties.hh>
|
||||
|
||||
#include <opm/material/common/MathToolbox.hpp>
|
||||
#include <opm/material/common/Valgrind.hpp>
|
||||
|
138
opm/models/discretization/common/baseauxiliarymodule.hh
Normal file
138
opm/models/discretization/common/baseauxiliarymodule.hh
Normal file
@ -0,0 +1,138 @@
|
||||
// -*- mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*-
|
||||
// vi: set et ts=4 sw=4 sts=4:
|
||||
/*
|
||||
This file is part of the Open Porous Media project (OPM).
|
||||
|
||||
OPM 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.
|
||||
|
||||
OPM is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
GNU General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU General Public License
|
||||
along with OPM. If not, see <http://www.gnu.org/licenses/>.
|
||||
|
||||
Consult the COPYING file in the top-level source directory of this
|
||||
module for the precise wording of the license and the list of
|
||||
copyright holders.
|
||||
*/
|
||||
/*!
|
||||
* \file
|
||||
* \copydoc Opm::BaseAuxiliaryModule
|
||||
*/
|
||||
#ifndef EWOMS_BASE_AUXILIARY_MODULE_HH
|
||||
#define EWOMS_BASE_AUXILIARY_MODULE_HH
|
||||
|
||||
#include <opm/models/utils/propertysystem.hh>
|
||||
|
||||
#include <opm/models/discretization/common/fvbaseproperties.hh>
|
||||
|
||||
#include <set>
|
||||
#include <vector>
|
||||
|
||||
BEGIN_PROPERTIES
|
||||
|
||||
NEW_TYPE_TAG(AuxModule);
|
||||
|
||||
// declare the properties required by the for the ecl grid manager
|
||||
NEW_PROP_TAG(Grid);
|
||||
NEW_PROP_TAG(GridView);
|
||||
NEW_PROP_TAG(Scalar);
|
||||
NEW_PROP_TAG(DofMapper);
|
||||
NEW_PROP_TAG(GlobalEqVector);
|
||||
NEW_PROP_TAG(SparseMatrixAdapter);
|
||||
|
||||
END_PROPERTIES
|
||||
|
||||
namespace Opm {
|
||||
|
||||
/*!
|
||||
* \ingroup ModelModules
|
||||
*
|
||||
* \brief Base class for specifying auxiliary equations.
|
||||
*
|
||||
* For example, these equations can be wells, non-neighboring connections, interfaces
|
||||
* between model domains, etc.
|
||||
*/
|
||||
template <class TypeTag>
|
||||
class BaseAuxiliaryModule
|
||||
{
|
||||
typedef typename GET_PROP_TYPE(TypeTag, Scalar) Scalar;
|
||||
typedef typename GET_PROP_TYPE(TypeTag, GridView) GridView;
|
||||
typedef typename GET_PROP_TYPE(TypeTag, GlobalEqVector) GlobalEqVector;
|
||||
typedef typename GET_PROP_TYPE(TypeTag, SparseMatrixAdapter) SparseMatrixAdapter;
|
||||
|
||||
protected:
|
||||
typedef std::set<unsigned> NeighborSet;
|
||||
|
||||
public:
|
||||
virtual ~BaseAuxiliaryModule()
|
||||
{}
|
||||
|
||||
/*!
|
||||
* \brief Returns the number of additional degrees of freedom required for the
|
||||
* auxiliary module.
|
||||
*/
|
||||
virtual unsigned numDofs() const = 0;
|
||||
|
||||
/*!
|
||||
* \brief Set the offset in the global system of equations for the first degree of
|
||||
* freedom of this auxiliary module.
|
||||
*/
|
||||
void setDofOffset(int value)
|
||||
{ dofOffset_ = value; }
|
||||
|
||||
/*!
|
||||
* \brief Return the offset in the global system of equations for the first degree of
|
||||
* freedom of this auxiliary module.
|
||||
*/
|
||||
int dofOffset()
|
||||
{ return dofOffset_; }
|
||||
|
||||
/*!
|
||||
* \brief Given a degree of freedom relative to the current auxiliary equation,
|
||||
* return the corresponding index in the global system of equations.
|
||||
*/
|
||||
int localToGlobalDof(unsigned localDofIdx) const
|
||||
{
|
||||
assert(0 <= localDofIdx);
|
||||
assert(localDofIdx < numDofs());
|
||||
return dofOffset_ + localDofIdx;
|
||||
}
|
||||
|
||||
/*!
|
||||
* \brief Specify the additional neighboring correlations caused by the auxiliary
|
||||
* module.
|
||||
*/
|
||||
virtual void addNeighbors(std::vector<NeighborSet>& neighbors) const = 0;
|
||||
|
||||
/*!
|
||||
* \brief Set the initial condition of the auxiliary module in the solution vector.
|
||||
*/
|
||||
virtual void applyInitial() = 0;
|
||||
|
||||
/*!
|
||||
* \brief Linearize the auxiliary equation.
|
||||
*/
|
||||
virtual void linearize(SparseMatrixAdapter& matrix, GlobalEqVector& residual) = 0;
|
||||
|
||||
/*!
|
||||
* \brief This method is called after the linear solver has been called but before
|
||||
* the solution is updated for the next iteration.
|
||||
*
|
||||
* It is intended to implement stuff like Schur complements.
|
||||
*/
|
||||
virtual void postSolve(GlobalEqVector& residual OPM_UNUSED)
|
||||
{};
|
||||
|
||||
private:
|
||||
int dofOffset_;
|
||||
};
|
||||
|
||||
} // namespace Opm
|
||||
|
||||
#endif
|
316
opm/models/discretization/common/fvbaseadlocallinearizer.hh
Normal file
316
opm/models/discretization/common/fvbaseadlocallinearizer.hh
Normal file
@ -0,0 +1,316 @@
|
||||
// -*- mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*-
|
||||
// vi: set et ts=4 sw=4 sts=4:
|
||||
/*
|
||||
This file is part of the Open Porous Media project (OPM).
|
||||
|
||||
OPM 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.
|
||||
|
||||
OPM is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
GNU General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU General Public License
|
||||
along with OPM. If not, see <http://www.gnu.org/licenses/>.
|
||||
|
||||
Consult the COPYING file in the top-level source directory of this
|
||||
module for the precise wording of the license and the list of
|
||||
copyright holders.
|
||||
*/
|
||||
/*!
|
||||
* \file
|
||||
*
|
||||
* \copydoc Opm::FvBaseAdLocalLinearizer
|
||||
*/
|
||||
#ifndef EWOMS_FV_BASE_AD_LOCAL_LINEARIZER_HH
|
||||
#define EWOMS_FV_BASE_AD_LOCAL_LINEARIZER_HH
|
||||
|
||||
#include "fvbaseproperties.hh"
|
||||
|
||||
#include <opm/material/densead/Math.hpp>
|
||||
#include <opm/material/common/Valgrind.hpp>
|
||||
#include <opm/material/common/Unused.hpp>
|
||||
|
||||
#include <dune/istl/bvector.hh>
|
||||
#include <dune/istl/matrix.hh>
|
||||
|
||||
#include <dune/common/fvector.hh>
|
||||
#include <dune/common/fmatrix.hh>
|
||||
|
||||
namespace Opm {
|
||||
// forward declaration
|
||||
template<class TypeTag>
|
||||
class FvBaseAdLocalLinearizer;
|
||||
}
|
||||
|
||||
BEGIN_PROPERTIES
|
||||
|
||||
// declare the property tags required for the finite differences local linearizer
|
||||
NEW_TYPE_TAG(AutoDiffLocalLinearizer);
|
||||
|
||||
NEW_PROP_TAG(LocalLinearizer);
|
||||
NEW_PROP_TAG(Evaluation);
|
||||
|
||||
NEW_PROP_TAG(LocalResidual);
|
||||
NEW_PROP_TAG(Simulator);
|
||||
NEW_PROP_TAG(Problem);
|
||||
NEW_PROP_TAG(Model);
|
||||
NEW_PROP_TAG(PrimaryVariables);
|
||||
NEW_PROP_TAG(ElementContext);
|
||||
NEW_PROP_TAG(Scalar);
|
||||
NEW_PROP_TAG(Evaluation);
|
||||
NEW_PROP_TAG(GridView);
|
||||
|
||||
// set the properties to be spliced in
|
||||
SET_TYPE_PROP(AutoDiffLocalLinearizer, LocalLinearizer,
|
||||
Opm::FvBaseAdLocalLinearizer<TypeTag>);
|
||||
|
||||
//! Set the function evaluation w.r.t. the primary variables
|
||||
SET_PROP(AutoDiffLocalLinearizer, Evaluation)
|
||||
{
|
||||
private:
|
||||
static const unsigned numEq = GET_PROP_VALUE(TypeTag, NumEq);
|
||||
|
||||
typedef typename GET_PROP_TYPE(TypeTag, Scalar) Scalar;
|
||||
|
||||
public:
|
||||
typedef Opm::DenseAd::Evaluation<Scalar, numEq> type;
|
||||
};
|
||||
|
||||
END_PROPERTIES
|
||||
|
||||
namespace Opm {
|
||||
|
||||
/*!
|
||||
* \ingroup FiniteVolumeDiscretizations
|
||||
*
|
||||
* \brief Calculates the local residual and its Jacobian for a single element of the grid.
|
||||
*
|
||||
* This class uses automatic differentiation to calculate the partial derivatives (the
|
||||
* alternative is finite differences).
|
||||
*/
|
||||
template<class TypeTag>
|
||||
class FvBaseAdLocalLinearizer
|
||||
{
|
||||
private:
|
||||
typedef typename GET_PROP_TYPE(TypeTag, LocalLinearizer) Implementation;
|
||||
typedef typename GET_PROP_TYPE(TypeTag, LocalResidual) LocalResidual;
|
||||
typedef typename GET_PROP_TYPE(TypeTag, Simulator) Simulator;
|
||||
typedef typename GET_PROP_TYPE(TypeTag, Problem) Problem;
|
||||
typedef typename GET_PROP_TYPE(TypeTag, Model) Model;
|
||||
typedef typename GET_PROP_TYPE(TypeTag, PrimaryVariables) PrimaryVariables;
|
||||
typedef typename GET_PROP_TYPE(TypeTag, ElementContext) ElementContext;
|
||||
typedef typename GET_PROP_TYPE(TypeTag, Scalar) Scalar;
|
||||
typedef typename GET_PROP_TYPE(TypeTag, GridView) GridView;
|
||||
typedef typename GridView::template Codim<0>::Entity Element;
|
||||
|
||||
enum { numEq = GET_PROP_VALUE(TypeTag, NumEq) };
|
||||
|
||||
typedef Dune::FieldVector<Scalar, numEq> ScalarVectorBlock;
|
||||
// extract local matrices from jacobian matrix for consistency
|
||||
typedef typename GET_PROP_TYPE(TypeTag, SparseMatrixAdapter)::MatrixBlock ScalarMatrixBlock;
|
||||
|
||||
typedef Dune::BlockVector<ScalarVectorBlock> ScalarLocalBlockVector;
|
||||
typedef Dune::Matrix<ScalarMatrixBlock> ScalarLocalBlockMatrix;
|
||||
|
||||
public:
|
||||
FvBaseAdLocalLinearizer()
|
||||
: internalElemContext_(0)
|
||||
{ }
|
||||
|
||||
// copying local linearizer objects around is a very bad idea, so we explicitly
|
||||
// prevent it...
|
||||
FvBaseAdLocalLinearizer(const FvBaseAdLocalLinearizer&) = delete;
|
||||
|
||||
~FvBaseAdLocalLinearizer()
|
||||
{ delete internalElemContext_; }
|
||||
|
||||
/*!
|
||||
* \brief Register all run-time parameters for the local jacobian.
|
||||
*/
|
||||
static void registerParameters()
|
||||
{ }
|
||||
|
||||
/*!
|
||||
* \brief Initialize the local Jacobian object.
|
||||
*
|
||||
* At this point we can assume that everything has been allocated,
|
||||
* although some objects may not yet be completely initialized.
|
||||
*
|
||||
* \param simulator The simulator object of the simulation.
|
||||
*/
|
||||
void init(Simulator& simulator)
|
||||
{
|
||||
simulatorPtr_ = &simulator;
|
||||
delete internalElemContext_;
|
||||
internalElemContext_ = new ElementContext(simulator);
|
||||
}
|
||||
|
||||
/*!
|
||||
* \brief Compute an element's local Jacobian matrix and evaluate its residual.
|
||||
*
|
||||
* The local Jacobian for a given context is defined as the derivatives of the
|
||||
* residuals of all degrees of freedom featured by the stencil with regard to the
|
||||
* primary variables of the stencil's "primary" degrees of freedom. Adding the local
|
||||
* Jacobians for all elements in the grid will give the global Jacobian 'grad f(x)'.
|
||||
*
|
||||
* \param element The grid element for which the local residual and its local
|
||||
* Jacobian should be calculated.
|
||||
*/
|
||||
void linearize(const Element& element)
|
||||
{
|
||||
linearize(*internalElemContext_, element);
|
||||
}
|
||||
|
||||
/*!
|
||||
* \brief Compute an element's local Jacobian matrix and evaluate its residual.
|
||||
*
|
||||
* The local Jacobian for a given context is defined as the derivatives of the
|
||||
* residuals of all degrees of freedom featured by the stencil with regard to the
|
||||
* primary variables of the stencil's "primary" degrees of freedom. Adding the local
|
||||
* Jacobians for all elements in the grid will give the global Jacobian 'grad f(x)'.
|
||||
*
|
||||
* After calling this method the ElementContext is in an undefined state, so do not
|
||||
* use it anymore!
|
||||
*
|
||||
* \param elemCtx The element execution context for which the local residual and its
|
||||
* local Jacobian should be calculated.
|
||||
*/
|
||||
void linearize(ElementContext& elemCtx, const Element& elem)
|
||||
{
|
||||
elemCtx.updateStencil(elem);
|
||||
elemCtx.updateAllIntensiveQuantities();
|
||||
|
||||
// update the weights of the primary variables for the context
|
||||
model_().updatePVWeights(elemCtx);
|
||||
|
||||
// resize the internal arrays of the linearizer
|
||||
resize_(elemCtx);
|
||||
reset_(elemCtx);
|
||||
|
||||
// compute the local residual and its Jacobian
|
||||
unsigned numPrimaryDof = elemCtx.numPrimaryDof(/*timeIdx=*/0);
|
||||
for (unsigned focusDofIdx = 0; focusDofIdx < numPrimaryDof; focusDofIdx++) {
|
||||
elemCtx.setFocusDofIndex(focusDofIdx);
|
||||
elemCtx.updateAllExtensiveQuantities();
|
||||
|
||||
// calculate the local residual
|
||||
localResidual_.eval(elemCtx);
|
||||
|
||||
// convert the local Jacobian matrix and the right hand side from the data
|
||||
// structures used by the automatic differentiation code to the conventional
|
||||
// ones used by the linear solver.
|
||||
updateLocalLinearization_(elemCtx, focusDofIdx);
|
||||
}
|
||||
}
|
||||
|
||||
/*!
|
||||
* \brief Return reference to the local residual.
|
||||
*/
|
||||
LocalResidual& localResidual()
|
||||
{ return localResidual_; }
|
||||
|
||||
/*!
|
||||
* \brief Return reference to the local residual.
|
||||
*/
|
||||
const LocalResidual& localResidual() const
|
||||
{ return localResidual_; }
|
||||
|
||||
/*!
|
||||
* \brief Returns the local Jacobian matrix of the residual of a sub-control volume.
|
||||
*
|
||||
* \param domainScvIdx The local index of the sub control volume to which the primary
|
||||
* variables are associated with
|
||||
* \param rangeScvIdx The local index of the sub control volume which contains the
|
||||
* local residual
|
||||
*/
|
||||
const ScalarMatrixBlock& jacobian(unsigned domainScvIdx, unsigned rangeScvIdx) const
|
||||
{ return jacobian_[domainScvIdx][rangeScvIdx]; }
|
||||
|
||||
/*!
|
||||
* \brief Returns the local residual of a sub-control volume.
|
||||
*
|
||||
* \param dofIdx The local index of the sub control volume
|
||||
*/
|
||||
const ScalarVectorBlock& residual(unsigned dofIdx) const
|
||||
{ return residual_[dofIdx]; }
|
||||
|
||||
protected:
|
||||
Implementation& asImp_()
|
||||
{ return *static_cast<Implementation*>(this); }
|
||||
const Implementation& asImp_() const
|
||||
{ return *static_cast<const Implementation*>(this); }
|
||||
|
||||
const Simulator& simulator_() const
|
||||
{ return *simulatorPtr_; }
|
||||
const Problem& problem_() const
|
||||
{ return simulatorPtr_->problem(); }
|
||||
const Model& model_() const
|
||||
{ return simulatorPtr_->model(); }
|
||||
|
||||
/*!
|
||||
* \brief Resize all internal attributes to the size of the
|
||||
* element.
|
||||
*/
|
||||
void resize_(const ElementContext& elemCtx)
|
||||
{
|
||||
size_t numDof = elemCtx.numDof(/*timeIdx=*/0);
|
||||
size_t numPrimaryDof = elemCtx.numPrimaryDof(/*timeIdx=*/0);
|
||||
|
||||
residual_.resize(numDof);
|
||||
jacobian_.setSize(numDof, numPrimaryDof);
|
||||
}
|
||||
|
||||
/*!
|
||||
* \brief Reset the all relevant internal attributes to 0
|
||||
*/
|
||||
void reset_(const ElementContext& elemCtx OPM_UNUSED)
|
||||
{
|
||||
residual_ = 0.0;
|
||||
jacobian_ = 0.0;
|
||||
}
|
||||
|
||||
/*!
|
||||
* \brief Updates the current local Jacobian matrix with the partial derivatives of
|
||||
* all equations for the degree of freedom associated with 'focusDofIdx'.
|
||||
*/
|
||||
void updateLocalLinearization_(const ElementContext& elemCtx,
|
||||
unsigned focusDofIdx)
|
||||
{
|
||||
const auto& resid = localResidual_.residual();
|
||||
|
||||
for (unsigned eqIdx = 0; eqIdx < numEq; eqIdx++)
|
||||
residual_[focusDofIdx][eqIdx] = resid[focusDofIdx][eqIdx].value();
|
||||
|
||||
size_t numDof = elemCtx.numDof(/*timeIdx=*/0);
|
||||
for (unsigned dofIdx = 0; dofIdx < numDof; dofIdx++) {
|
||||
for (unsigned eqIdx = 0; eqIdx < numEq; eqIdx++) {
|
||||
for (unsigned pvIdx = 0; pvIdx < numEq; pvIdx++) {
|
||||
// A[dofIdx][focusDofIdx][eqIdx][pvIdx] is the partial derivative of
|
||||
// the residual function 'eqIdx' for the degree of freedom 'dofIdx'
|
||||
// with regard to the focus variable 'pvIdx' of the degree of freedom
|
||||
// 'focusDofIdx'
|
||||
jacobian_[dofIdx][focusDofIdx][eqIdx][pvIdx] = resid[dofIdx][eqIdx].derivative(pvIdx);
|
||||
Opm::Valgrind::CheckDefined(jacobian_[dofIdx][focusDofIdx][eqIdx][pvIdx]);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
Simulator *simulatorPtr_;
|
||||
Model *modelPtr_;
|
||||
|
||||
ElementContext *internalElemContext_;
|
||||
|
||||
LocalResidual localResidual_;
|
||||
|
||||
ScalarLocalBlockVector residual_;
|
||||
ScalarLocalBlockMatrix jacobian_;
|
||||
};
|
||||
|
||||
} // namespace Opm
|
||||
|
||||
#endif
|
269
opm/models/discretization/common/fvbaseboundarycontext.hh
Normal file
269
opm/models/discretization/common/fvbaseboundarycontext.hh
Normal file
@ -0,0 +1,269 @@
|
||||
// -*- mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*-
|
||||
// vi: set et ts=4 sw=4 sts=4:
|
||||
/*
|
||||
This file is part of the Open Porous Media project (OPM).
|
||||
|
||||
OPM 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.
|
||||
|
||||
OPM is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
GNU General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU General Public License
|
||||
along with OPM. If not, see <http://www.gnu.org/licenses/>.
|
||||
|
||||
Consult the COPYING file in the top-level source directory of this
|
||||
module for the precise wording of the license and the list of
|
||||
copyright holders.
|
||||
*/
|
||||
/*!
|
||||
* \file
|
||||
*
|
||||
* \copydoc Opm::FvBaseBoundaryContext
|
||||
*/
|
||||
#ifndef EWOMS_FV_BASE_BOUNDARY_CONTEXT_HH
|
||||
#define EWOMS_FV_BASE_BOUNDARY_CONTEXT_HH
|
||||
|
||||
#include "fvbaseproperties.hh"
|
||||
|
||||
#include <opm/material/common/Unused.hpp>
|
||||
|
||||
#include <dune/common/fvector.hh>
|
||||
|
||||
namespace Opm {
|
||||
|
||||
/*!
|
||||
* \ingroup FiniteVolumeDiscretizations
|
||||
*
|
||||
* \brief Represents all quantities which available on boundary segments
|
||||
*/
|
||||
template<class TypeTag>
|
||||
class FvBaseBoundaryContext
|
||||
{
|
||||
typedef typename GET_PROP_TYPE(TypeTag, Scalar) Scalar;
|
||||
typedef typename GET_PROP_TYPE(TypeTag, Problem) Problem;
|
||||
typedef typename GET_PROP_TYPE(TypeTag, Model) Model;
|
||||
typedef typename GET_PROP_TYPE(TypeTag, Stencil) Stencil;
|
||||
typedef typename GET_PROP_TYPE(TypeTag, ElementContext) ElementContext;
|
||||
typedef typename GET_PROP_TYPE(TypeTag, IntensiveQuantities) IntensiveQuantities;
|
||||
typedef typename GET_PROP_TYPE(TypeTag, ExtensiveQuantities) ExtensiveQuantities;
|
||||
typedef typename GET_PROP_TYPE(TypeTag, GradientCalculator) GradientCalculator;
|
||||
|
||||
typedef typename GET_PROP_TYPE(TypeTag, GridView) GridView;
|
||||
typedef typename GridView::template Codim<0>::Entity Element;
|
||||
typedef typename GridView::IntersectionIterator IntersectionIterator;
|
||||
typedef typename GridView::Intersection Intersection;
|
||||
|
||||
enum { dim = GridView::dimension };
|
||||
enum { dimWorld = GridView::dimensionworld };
|
||||
|
||||
typedef typename GridView::ctype CoordScalar;
|
||||
typedef Dune::FieldVector<CoordScalar, dimWorld> GlobalPosition;
|
||||
typedef Dune::FieldVector<Scalar, dimWorld> Vector;
|
||||
|
||||
public:
|
||||
/*!
|
||||
* \brief The constructor.
|
||||
*/
|
||||
explicit FvBaseBoundaryContext(const ElementContext& elemCtx)
|
||||
: elemCtx_(elemCtx)
|
||||
, intersectionIt_(gridView().ibegin(element()))
|
||||
{ }
|
||||
|
||||
void increment()
|
||||
{
|
||||
const auto& iend = gridView().iend(element());
|
||||
while (intersectionIt_ != iend && !intersectionIt_->boundary())
|
||||
++ intersectionIt_;
|
||||
}
|
||||
|
||||
/*!
|
||||
* \copydoc Opm::ElementContext::problem()
|
||||
*/
|
||||
const Problem& problem() const
|
||||
{ return elemCtx_.problem(); }
|
||||
|
||||
/*!
|
||||
* \copydoc Opm::ElementContext::model()
|
||||
*/
|
||||
const Model& model() const
|
||||
{ return elemCtx_.model(); }
|
||||
|
||||
/*!
|
||||
* \copydoc Opm::ElementContext::gridView()
|
||||
*/
|
||||
const GridView& gridView() const
|
||||
{ return elemCtx_.gridView(); }
|
||||
|
||||
/*!
|
||||
* \copydoc Opm::ElementContext::element()
|
||||
*/
|
||||
const Element& element() const
|
||||
{ return elemCtx_.element(); }
|
||||
|
||||
/*!
|
||||
* \brief Returns a reference to the element context object.
|
||||
*/
|
||||
const ElementContext& elementContext() const
|
||||
{ return elemCtx_; }
|
||||
|
||||
/*!
|
||||
* \brief Returns a reference to the current gradient calculator.
|
||||
*/
|
||||
const GradientCalculator& gradientCalculator() const
|
||||
{ return elemCtx_.gradientCalculator(); }
|
||||
|
||||
/*!
|
||||
* \copydoc Opm::ElementContext::numDof()
|
||||
*/
|
||||
size_t numDof(unsigned timeIdx) const
|
||||
{ return elemCtx_.numDof(timeIdx); }
|
||||
|
||||
/*!
|
||||
* \copydoc Opm::ElementContext::numPrimaryDof()
|
||||
*/
|
||||
size_t numPrimaryDof(unsigned timeIdx) const
|
||||
{ return elemCtx_.numPrimaryDof(timeIdx); }
|
||||
|
||||
/*!
|
||||
* \copydoc Opm::ElementContext::numInteriorFaces()
|
||||
*/
|
||||
size_t numInteriorFaces(unsigned timeIdx) const
|
||||
{ return elemCtx_.numInteriorFaces(timeIdx); }
|
||||
|
||||
/*!
|
||||
* \brief Return the number of boundary segments of the current element
|
||||
*/
|
||||
size_t numBoundaryFaces(unsigned timeIdx) const
|
||||
{ return elemCtx_.stencil(timeIdx).numBoundaryFaces(); }
|
||||
|
||||
/*!
|
||||
* \copydoc Opm::ElementContext::stencil()
|
||||
*/
|
||||
const Stencil& stencil(unsigned timeIdx) const
|
||||
{ return elemCtx_.stencil(timeIdx); }
|
||||
|
||||
/*!
|
||||
* \brief Returns the outer unit normal of the boundary segment
|
||||
*
|
||||
* \param boundaryFaceIdx The local index of the boundary segment
|
||||
* \param timeIdx The index of the solution used by the time discretization
|
||||
*/
|
||||
Vector normal(unsigned boundaryFaceIdx, unsigned timeIdx) const
|
||||
{
|
||||
auto tmp = stencil(timeIdx).boundaryFace[boundaryFaceIdx].normal;
|
||||
tmp /= tmp.two_norm();
|
||||
return tmp;
|
||||
}
|
||||
|
||||
/*!
|
||||
* \brief Returns the area [m^2] of a given boudary segment.
|
||||
*/
|
||||
Scalar boundarySegmentArea(unsigned boundaryFaceIdx, unsigned timeIdx) const
|
||||
{ return elemCtx_.stencil(timeIdx).boundaryFace(boundaryFaceIdx).area(); }
|
||||
|
||||
/*!
|
||||
* \brief Return the position of a local entity in global coordinates.
|
||||
*
|
||||
* \param boundaryFaceIdx The local index of the boundary segment
|
||||
* \param timeIdx The index of the solution used by the time discretization
|
||||
*/
|
||||
const GlobalPosition& pos(unsigned boundaryFaceIdx, unsigned timeIdx) const
|
||||
{ return stencil(timeIdx).boundaryFace(boundaryFaceIdx).integrationPos(); }
|
||||
|
||||
/*!
|
||||
* \brief Return the position of a control volume's center in global coordinates.
|
||||
*
|
||||
* \param boundaryFaceIdx The local index of the boundary segment
|
||||
* \param timeIdx The index of the solution used by the time discretization
|
||||
*/
|
||||
const GlobalPosition& cvCenter(unsigned boundaryFaceIdx, unsigned timeIdx) const
|
||||
{
|
||||
unsigned scvIdx = stencil(timeIdx).boundaryFace(boundaryFaceIdx).interiorIndex();
|
||||
return stencil(timeIdx).subControlVolume(scvIdx).globalPos();
|
||||
}
|
||||
|
||||
/*!
|
||||
* \brief Return the local sub-control volume index upon which the linearization is
|
||||
* currently focused.
|
||||
*/
|
||||
unsigned focusDofIndex() const
|
||||
{ return elemCtx_.focusDofIndex(); }
|
||||
|
||||
/*!
|
||||
* \brief Return the local sub-control volume index of the
|
||||
* interior of a boundary segment
|
||||
*
|
||||
* \param boundaryFaceIdx The local index of the boundary segment
|
||||
* \param timeIdx The index of the solution used by the time discretization
|
||||
*/
|
||||
unsigned interiorScvIndex(unsigned boundaryFaceIdx, unsigned timeIdx) const
|
||||
{ return stencil(timeIdx).boundaryFace(boundaryFaceIdx).interiorIndex(); }
|
||||
|
||||
/*!
|
||||
* \brief Return the global space index of the sub-control volume
|
||||
* at the interior of a boundary segment
|
||||
*
|
||||
* \param boundaryFaceIdx The local index of the boundary segment
|
||||
* \param timeIdx The index of the solution used by the time discretization
|
||||
*/
|
||||
unsigned globalSpaceIndex(unsigned boundaryFaceIdx, unsigned timeIdx) const
|
||||
{ return elemCtx_.globalSpaceIndex(interiorScvIndex(boundaryFaceIdx, timeIdx), timeIdx); }
|
||||
|
||||
/*!
|
||||
* \brief Return the intensive quantities for the finite volume in the
|
||||
* interiour of a boundary segment
|
||||
*
|
||||
* \param boundaryFaceIdx The local index of the boundary segment
|
||||
* \param timeIdx The index of the solution used by the time discretization
|
||||
*/
|
||||
const IntensiveQuantities& intensiveQuantities(unsigned boundaryFaceIdx, unsigned timeIdx) const
|
||||
{
|
||||
unsigned interiorScvIdx = this->interiorScvIndex(boundaryFaceIdx, timeIdx);
|
||||
return elemCtx_.intensiveQuantities(interiorScvIdx, timeIdx);
|
||||
}
|
||||
|
||||
/*!
|
||||
* \brief Return the extensive quantities for a given boundary face.
|
||||
*
|
||||
* \param boundaryFaceIdx The local index of the boundary segment
|
||||
* \param timeIdx The index of the solution used by the time discretization
|
||||
*/
|
||||
const ExtensiveQuantities& extensiveQuantities(unsigned boundaryFaceIdx, unsigned timeIdx) const
|
||||
{ return elemCtx_.boundaryExtensiveQuantities(boundaryFaceIdx, timeIdx); }
|
||||
|
||||
/*!
|
||||
* \brief Return the intersection for the neumann segment
|
||||
*
|
||||
* TODO/HACK: The intersection should take a local index as an
|
||||
* argument. since that's not supported efficiently by the DUNE
|
||||
* grid interface, we just ignore the index argument here!
|
||||
*
|
||||
* \param boundaryFaceIdx The local index of the boundary segment
|
||||
*/
|
||||
const Intersection& intersection(unsigned boundaryFaceIdx OPM_UNUSED) const
|
||||
{ return *intersectionIt_; }
|
||||
|
||||
/*!
|
||||
* \brief Return the intersection for the neumann segment
|
||||
*
|
||||
* TODO/HACK: the intersection iterator can basically be
|
||||
* considered as an index which is manipulated externally, but
|
||||
* context classes should not store any indices. it is done this
|
||||
* way for performance reasons
|
||||
*/
|
||||
IntersectionIterator& intersectionIt()
|
||||
{ return intersectionIt_; }
|
||||
|
||||
protected:
|
||||
const ElementContext& elemCtx_;
|
||||
IntersectionIterator intersectionIt_;
|
||||
};
|
||||
|
||||
} // namespace Opm
|
||||
|
||||
#endif
|
86
opm/models/discretization/common/fvbaseconstraints.hh
Normal file
86
opm/models/discretization/common/fvbaseconstraints.hh
Normal file
@ -0,0 +1,86 @@
|
||||
// -*- mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*-
|
||||
// vi: set et ts=4 sw=4 sts=4:
|
||||
/*
|
||||
This file is part of the Open Porous Media project (OPM).
|
||||
|
||||
OPM 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.
|
||||
|
||||
OPM is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
GNU General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU General Public License
|
||||
along with OPM. If not, see <http://www.gnu.org/licenses/>.
|
||||
|
||||
Consult the COPYING file in the top-level source directory of this
|
||||
module for the precise wording of the license and the list of
|
||||
copyright holders.
|
||||
*/
|
||||
/*!
|
||||
* \file
|
||||
*
|
||||
* \copydoc Opm::FvBaseConstraints
|
||||
*/
|
||||
#ifndef EWOMS_FV_BASE_CONSTRAINTS_HH
|
||||
#define EWOMS_FV_BASE_CONSTRAINTS_HH
|
||||
|
||||
#include <opm/models/utils/propertysystem.hh>
|
||||
#include <opm/material/common/Valgrind.hpp>
|
||||
|
||||
BEGIN_PROPERTIES
|
||||
|
||||
NEW_PROP_TAG(PrimaryVariables);
|
||||
|
||||
END_PROPERTIES
|
||||
|
||||
namespace Opm {
|
||||
|
||||
/*!
|
||||
* \ingroup FiniteVolumeDiscretizations
|
||||
*
|
||||
* \brief Class to specify constraints for a finite volume spatial discretization.
|
||||
*
|
||||
* Note that eWoms does not support "partial" constraints. (I.e., either all equations
|
||||
* must be constraint or none.)
|
||||
*/
|
||||
template <class TypeTag>
|
||||
class FvBaseConstraints : public GET_PROP_TYPE(TypeTag, PrimaryVariables)
|
||||
{
|
||||
typedef typename GET_PROP_TYPE(TypeTag, PrimaryVariables) ParentType;
|
||||
|
||||
public:
|
||||
FvBaseConstraints()
|
||||
{ setActive(false); }
|
||||
|
||||
FvBaseConstraints(const FvBaseConstraints&) = default;
|
||||
|
||||
//! \cond SKIP
|
||||
/*!
|
||||
* \brief Use the default assignment operator
|
||||
*/
|
||||
FvBaseConstraints &operator=(const FvBaseConstraints&) = default;
|
||||
//! \endcond
|
||||
|
||||
/*!
|
||||
* \brief Returns true if the constraints are enforced.
|
||||
*/
|
||||
bool isActive() const
|
||||
{ return isActive_; }
|
||||
|
||||
/*!
|
||||
* \brief Specify whether the constraints should be enforced or not
|
||||
*/
|
||||
void setActive(bool yesno)
|
||||
{ isActive_ = yesno; }
|
||||
|
||||
private:
|
||||
bool isActive_;
|
||||
};
|
||||
|
||||
} // namespace Opm
|
||||
|
||||
#endif
|
118
opm/models/discretization/common/fvbaseconstraintscontext.hh
Normal file
118
opm/models/discretization/common/fvbaseconstraintscontext.hh
Normal file
@ -0,0 +1,118 @@
|
||||
// -*- mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*-
|
||||
// vi: set et ts=4 sw=4 sts=4:
|
||||
/*
|
||||
This file is part of the Open Porous Media project (OPM).
|
||||
|
||||
OPM 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.
|
||||
|
||||
OPM is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
GNU General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU General Public License
|
||||
along with OPM. If not, see <http://www.gnu.org/licenses/>.
|
||||
|
||||
Consult the COPYING file in the top-level source directory of this
|
||||
module for the precise wording of the license and the list of
|
||||
copyright holders.
|
||||
*/
|
||||
/*!
|
||||
* \file
|
||||
*
|
||||
* \copydoc Opm::FvBaseConstraintsContext
|
||||
*/
|
||||
#ifndef EWOMS_FV_BASE_CONSTRAINTS_CONTEXT_HH
|
||||
#define EWOMS_FV_BASE_CONSTRAINTS_CONTEXT_HH
|
||||
|
||||
#include "fvbaseproperties.hh"
|
||||
|
||||
#include <dune/common/fvector.hh>
|
||||
|
||||
namespace Opm {
|
||||
|
||||
/*!
|
||||
* \ingroup FiniteVolumeDiscretizations
|
||||
*
|
||||
* \brief Represents all quantities which available for calculating constraints
|
||||
*/
|
||||
template<class TypeTag>
|
||||
class FvBaseConstraintsContext
|
||||
{
|
||||
typedef typename GET_PROP_TYPE(TypeTag, Problem) Problem;
|
||||
typedef typename GET_PROP_TYPE(TypeTag, Model) Model;
|
||||
typedef typename GET_PROP_TYPE(TypeTag, ElementContext) ElementContext;
|
||||
typedef typename GET_PROP_TYPE(TypeTag, GridView) GridView;
|
||||
typedef typename GridView::template Codim<0>::Entity Element;
|
||||
|
||||
enum { dimWorld = GridView::dimensionworld };
|
||||
|
||||
typedef typename GridView::ctype CoordScalar;
|
||||
typedef Dune::FieldVector<CoordScalar, dimWorld> GlobalPosition;
|
||||
|
||||
public:
|
||||
/*!
|
||||
* \brief The constructor.
|
||||
*/
|
||||
explicit FvBaseConstraintsContext(const ElementContext& elemCtx)
|
||||
: elemCtx_(elemCtx)
|
||||
{ }
|
||||
|
||||
/*!
|
||||
* \copydoc Opm::ElementContext::problem()
|
||||
*/
|
||||
const Problem& problem() const
|
||||
{ return elemCtx_.problem(); }
|
||||
|
||||
/*!
|
||||
* \copydoc Opm::ElementContext::model()
|
||||
*/
|
||||
const Model& model() const
|
||||
{ return elemCtx_.model(); }
|
||||
|
||||
/*!
|
||||
* \copydoc Opm::ElementContext::gridView()
|
||||
*/
|
||||
const GridView& gridView() const
|
||||
{ return elemCtx_.gridView(); }
|
||||
|
||||
/*!
|
||||
* \copydoc Opm::ElementContext::element()
|
||||
*/
|
||||
const Element& element() const
|
||||
{ return elemCtx_.element(); }
|
||||
|
||||
/*!
|
||||
* \copydoc Opm::ElementContext::numDof()
|
||||
*/
|
||||
int numDof(int timeIdx) const
|
||||
{ return elemCtx_.numDof(timeIdx); }
|
||||
|
||||
/*!
|
||||
* \copydoc Opm::ElementContext::numInteriorFaces()
|
||||
*/
|
||||
int numInteriorFaces(int timeIdx) const
|
||||
{ return elemCtx_.numInteriorFaces(timeIdx); }
|
||||
|
||||
/*!
|
||||
* \copydoc Opm::ElementContext::globalSpaceIndex
|
||||
*/
|
||||
int globalSpaceIndex(int dofIdx, int timeIdx) const
|
||||
{ return elemCtx_.globalSpaceIndex(dofIdx, timeIdx); }
|
||||
|
||||
/*!
|
||||
* \copydoc Opm::ElementContext::pos
|
||||
*/
|
||||
GlobalPosition pos(int dofIdx, int timeIdx) const
|
||||
{ return elemCtx_.pos(dofIdx, timeIdx); }
|
||||
|
||||
protected:
|
||||
const ElementContext& elemCtx_;
|
||||
};
|
||||
|
||||
} // namespace Opm
|
||||
|
||||
#endif
|
1919
opm/models/discretization/common/fvbasediscretization.hh
Normal file
1919
opm/models/discretization/common/fvbasediscretization.hh
Normal file
File diff suppressed because it is too large
Load Diff
607
opm/models/discretization/common/fvbaseelementcontext.hh
Normal file
607
opm/models/discretization/common/fvbaseelementcontext.hh
Normal file
@ -0,0 +1,607 @@
|
||||
// -*- mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*-
|
||||
// vi: set et ts=4 sw=4 sts=4:
|
||||
/*
|
||||
This file is part of the Open Porous Media project (OPM).
|
||||
|
||||
OPM 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.
|
||||
|
||||
OPM is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
GNU General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU General Public License
|
||||
along with OPM. If not, see <http://www.gnu.org/licenses/>.
|
||||
|
||||
Consult the COPYING file in the top-level source directory of this
|
||||
module for the precise wording of the license and the list of
|
||||
copyright holders.
|
||||
*/
|
||||
/*!
|
||||
* \file
|
||||
*
|
||||
* \copydoc Opm::FvBaseElementContext
|
||||
*/
|
||||
#ifndef EWOMS_FV_BASE_ELEMENT_CONTEXT_HH
|
||||
#define EWOMS_FV_BASE_ELEMENT_CONTEXT_HH
|
||||
|
||||
#include "fvbaseproperties.hh"
|
||||
|
||||
#include <opm/models/utils/alignedallocator.hh>
|
||||
|
||||
#include <opm/material/common/Unused.hpp>
|
||||
#include <opm/material/common/Exceptions.hpp>
|
||||
|
||||
#include <dune/common/fvector.hh>
|
||||
|
||||
#include <vector>
|
||||
|
||||
namespace Opm {
|
||||
|
||||
/*!
|
||||
* \ingroup FiniteVolumeDiscretizations
|
||||
*
|
||||
* \brief This class stores an array of IntensiveQuantities objects, one
|
||||
* intensive quantities object for each of the element's vertices
|
||||
*/
|
||||
template<class TypeTag>
|
||||
class FvBaseElementContext
|
||||
{
|
||||
typedef typename GET_PROP_TYPE(TypeTag, ElementContext) Implementation;
|
||||
|
||||
typedef typename GET_PROP_TYPE(TypeTag, Scalar) Scalar;
|
||||
typedef typename GET_PROP_TYPE(TypeTag, PrimaryVariables) PrimaryVariables;
|
||||
typedef typename GET_PROP_TYPE(TypeTag, IntensiveQuantities) IntensiveQuantities;
|
||||
typedef typename GET_PROP_TYPE(TypeTag, ExtensiveQuantities) ExtensiveQuantities;
|
||||
|
||||
// the history size of the time discretization in number of steps
|
||||
enum { timeDiscHistorySize = GET_PROP_VALUE(TypeTag, TimeDiscHistorySize) };
|
||||
|
||||
struct DofStore_ {
|
||||
IntensiveQuantities intensiveQuantities[timeDiscHistorySize];
|
||||
PrimaryVariables priVars[timeDiscHistorySize];
|
||||
const IntensiveQuantities *thermodynamicHint[timeDiscHistorySize];
|
||||
};
|
||||
typedef std::vector<DofStore_> DofVarsVector;
|
||||
typedef std::vector<ExtensiveQuantities> ExtensiveQuantitiesVector;
|
||||
|
||||
typedef typename GET_PROP_TYPE(TypeTag, Simulator) Simulator;
|
||||
typedef typename GET_PROP_TYPE(TypeTag, Problem) Problem;
|
||||
typedef typename GET_PROP_TYPE(TypeTag, Model) Model;
|
||||
typedef typename GET_PROP_TYPE(TypeTag, Stencil) Stencil;
|
||||
typedef typename GET_PROP_TYPE(TypeTag, GradientCalculator) GradientCalculator;
|
||||
typedef typename GET_PROP_TYPE(TypeTag, SolutionVector) SolutionVector;
|
||||
|
||||
typedef typename GET_PROP_TYPE(TypeTag, GridView) GridView;
|
||||
typedef typename GridView::template Codim<0>::Entity Element;
|
||||
|
||||
static const unsigned dimWorld = GridView::dimensionworld;
|
||||
static const unsigned numEq = GET_PROP_VALUE(TypeTag, NumEq);
|
||||
|
||||
typedef typename GridView::ctype CoordScalar;
|
||||
typedef Dune::FieldVector<CoordScalar, dimWorld> GlobalPosition;
|
||||
|
||||
// we don't allow copies of element contexts!
|
||||
FvBaseElementContext(const FvBaseElementContext& ) = delete;
|
||||
|
||||
public:
|
||||
/*!
|
||||
* \brief The constructor.
|
||||
*/
|
||||
explicit FvBaseElementContext(const Simulator& simulator)
|
||||
: gridView_(simulator.gridView())
|
||||
, stencil_(gridView_, simulator.model().dofMapper() )
|
||||
{
|
||||
// remember the simulator object
|
||||
simulatorPtr_ = &simulator;
|
||||
enableStorageCache_ = EWOMS_GET_PARAM(TypeTag, bool, EnableStorageCache);
|
||||
stashedDofIdx_ = -1;
|
||||
focusDofIdx_ = -1;
|
||||
}
|
||||
|
||||
static void *operator new(size_t size)
|
||||
{ return Opm::aligned_alloc(alignof(FvBaseElementContext), size); }
|
||||
|
||||
static void operator delete(void *ptr)
|
||||
{ Opm::aligned_free(ptr); }
|
||||
|
||||
/*!
|
||||
* \brief Construct all volume and extensive quantities of an element
|
||||
* from scratch.
|
||||
*
|
||||
* \param elem The DUNE Codim<0> entity for which the volume
|
||||
* variables ought to be calculated
|
||||
*/
|
||||
void updateAll(const Element& elem)
|
||||
{
|
||||
asImp_().updateStencil(elem);
|
||||
asImp_().updateAllIntensiveQuantities();
|
||||
asImp_().updateAllExtensiveQuantities();
|
||||
}
|
||||
|
||||
/*!
|
||||
* \brief Compute the finite volume geometry for an element.
|
||||
*
|
||||
* \param elem The grid element for which the finite volume geometry ought to be
|
||||
* computed.
|
||||
*/
|
||||
void updateStencil(const Element& elem)
|
||||
{
|
||||
// remember the current element
|
||||
elemPtr_ = &elem;
|
||||
|
||||
// update the stencil. the center gradients are quite expensive to calculate and
|
||||
// most models don't need them, so that we only do this if the model explicitly
|
||||
// enables them
|
||||
stencil_.update(elem);
|
||||
|
||||
// resize the arrays containing the flux and the volume variables
|
||||
dofVars_.resize(stencil_.numDof());
|
||||
extensiveQuantities_.resize(stencil_.numInteriorFaces());
|
||||
}
|
||||
|
||||
/*!
|
||||
* \brief Update the primary topological part of the stencil, but nothing else.
|
||||
*
|
||||
* \param elem The grid element for which the finite volume geometry ought to be
|
||||
* computed.
|
||||
*/
|
||||
void updatePrimaryStencil(const Element& elem)
|
||||
{
|
||||
// remember the current element
|
||||
elemPtr_ = &elem;
|
||||
|
||||
// update the finite element geometry
|
||||
stencil_.updatePrimaryTopology(elem);
|
||||
|
||||
dofVars_.resize(stencil_.numPrimaryDof());
|
||||
}
|
||||
|
||||
/*!
|
||||
* \brief Update the topological part of the stencil, but nothing else.
|
||||
*
|
||||
* \param elem The grid element for which the finite volume geometry ought to be
|
||||
* computed.
|
||||
*/
|
||||
void updateStencilTopology(const Element& elem)
|
||||
{
|
||||
// remember the current element
|
||||
elemPtr_ = &elem;
|
||||
|
||||
// update the finite element geometry
|
||||
stencil_.updateTopology(elem);
|
||||
}
|
||||
|
||||
/*!
|
||||
* \brief Compute the intensive quantities of all sub-control volumes of the current
|
||||
* element for all time indices.
|
||||
*/
|
||||
void updateAllIntensiveQuantities()
|
||||
{
|
||||
if (!enableStorageCache_) {
|
||||
// if the storage cache is disabled, we need to calculate the storage term
|
||||
// from scratch, i.e. we need the intensive quantities of all of the history.
|
||||
for (unsigned timeIdx = 0; timeIdx < timeDiscHistorySize; ++ timeIdx)
|
||||
asImp_().updateIntensiveQuantities(timeIdx);
|
||||
}
|
||||
else
|
||||
// if the storage cache is enabled, we only need to recalculate the storage
|
||||
// term for the most recent point of history (i.e., for the current iterative
|
||||
// solution)
|
||||
asImp_().updateIntensiveQuantities(/*timeIdx=*/0);
|
||||
}
|
||||
|
||||
/*!
|
||||
* \brief Compute the intensive quantities of all sub-control volumes of the current
|
||||
* element for a single time index.
|
||||
*
|
||||
* \param timeIdx The index of the solution vector used by the time discretization.
|
||||
*/
|
||||
void updateIntensiveQuantities(unsigned timeIdx)
|
||||
{ updateIntensiveQuantities_(timeIdx, numDof(timeIdx)); }
|
||||
|
||||
/*!
|
||||
* \brief Compute the intensive quantities of all sub-control volumes of the current
|
||||
* element for a single time index.
|
||||
*
|
||||
* \param timeIdx The index of the solution vector used by the time discretization.
|
||||
*/
|
||||
void updatePrimaryIntensiveQuantities(unsigned timeIdx)
|
||||
{ updateIntensiveQuantities_(timeIdx, numPrimaryDof(timeIdx)); }
|
||||
|
||||
/*!
|
||||
* \brief Compute the intensive quantities of a single sub-control volume of the
|
||||
* current element for a single time index.
|
||||
*
|
||||
* \param priVars The PrimaryVariables which should be used to calculate the
|
||||
* intensive quantities.
|
||||
* \param dofIdx The local index in the current element of the sub-control volume
|
||||
* which should be updated.
|
||||
* \param timeIdx The index of the solution vector used by the time discretization.
|
||||
*/
|
||||
void updateIntensiveQuantities(const PrimaryVariables& priVars, unsigned dofIdx, unsigned timeIdx)
|
||||
{ asImp_().updateSingleIntQuants_(priVars, dofIdx, timeIdx); }
|
||||
|
||||
/*!
|
||||
* \brief Compute the extensive quantities of all sub-control volume
|
||||
* faces of the current element for all time indices.
|
||||
*/
|
||||
void updateAllExtensiveQuantities()
|
||||
{ asImp_().updateExtensiveQuantities(/*timeIdx=*/0); }
|
||||
|
||||
/*!
|
||||
* \brief Compute the extensive quantities of all sub-control volume
|
||||
* faces of the current element for a single time index.
|
||||
*
|
||||
* \param timeIdx The index of the solution vector used by the
|
||||
* time discretization.
|
||||
*/
|
||||
void updateExtensiveQuantities(unsigned timeIdx)
|
||||
{
|
||||
gradientCalculator_.prepare(/*context=*/asImp_(), timeIdx);
|
||||
|
||||
for (unsigned fluxIdx = 0; fluxIdx < numInteriorFaces(timeIdx); fluxIdx++) {
|
||||
extensiveQuantities_[fluxIdx].update(/*context=*/asImp_(),
|
||||
/*localIndex=*/fluxIdx,
|
||||
timeIdx);
|
||||
}
|
||||
}
|
||||
|
||||
/*!
|
||||
* \brief Sets the degree of freedom on which the simulator is currently "focused" on
|
||||
*
|
||||
* I.e., in the case of automatic differentiation, all derivatives are with regard to
|
||||
* the primary variables of that degree of freedom. Only "primary" DOFs can be
|
||||
* focused on.
|
||||
*/
|
||||
void setFocusDofIndex(unsigned dofIdx)
|
||||
{ focusDofIdx_ = dofIdx; }
|
||||
|
||||
/*!
|
||||
* \brief Returns the degree of freedom on which the simulator is currently "focused" on
|
||||
*
|
||||
* \copydetails setFocusDof()
|
||||
*/
|
||||
unsigned focusDofIndex() const
|
||||
{ return focusDofIdx_; }
|
||||
|
||||
/*!
|
||||
* \brief Return a reference to the simulator.
|
||||
*/
|
||||
const Simulator& simulator() const
|
||||
{ return *simulatorPtr_; }
|
||||
|
||||
/*!
|
||||
* \brief Return a reference to the problem.
|
||||
*/
|
||||
const Problem& problem() const
|
||||
{ return simulatorPtr_->problem(); }
|
||||
|
||||
/*!
|
||||
* \brief Return a reference to the model.
|
||||
*/
|
||||
const Model& model() const
|
||||
{ return simulatorPtr_->model(); }
|
||||
|
||||
/*!
|
||||
* \brief Return a reference to the grid view.
|
||||
*/
|
||||
const GridView& gridView() const
|
||||
{ return gridView_; }
|
||||
|
||||
/*!
|
||||
* \brief Return the current element.
|
||||
*/
|
||||
const Element& element() const
|
||||
{ return *elemPtr_; }
|
||||
|
||||
/*!
|
||||
* \brief Return the number of sub-control volumes of the current element.
|
||||
*/
|
||||
size_t numDof(unsigned timeIdx) const
|
||||
{ return stencil(timeIdx).numDof(); }
|
||||
|
||||
/*!
|
||||
* \brief Return the number of primary degrees of freedom of the current element.
|
||||
*/
|
||||
size_t numPrimaryDof(unsigned timeIdx) const
|
||||
{ return stencil(timeIdx).numPrimaryDof(); }
|
||||
|
||||
/*!
|
||||
* \brief Return the number of non-boundary faces which need to be
|
||||
* considered for the flux apporixmation.
|
||||
*/
|
||||
size_t numInteriorFaces(unsigned timeIdx) const
|
||||
{ return stencil(timeIdx).numInteriorFaces(); }
|
||||
|
||||
/*!
|
||||
* \brief Return the number of boundary faces which need to be
|
||||
* considered for the flux apporixmation.
|
||||
*/
|
||||
size_t numBoundaryFaces(unsigned timeIdx) const
|
||||
{ return stencil(timeIdx).numBoundaryFaces(); }
|
||||
|
||||
/*!
|
||||
* \brief Return the current finite element geometry.
|
||||
*
|
||||
* \param timeIdx The index of the solution vector used by the
|
||||
* time discretization.
|
||||
*/
|
||||
const Stencil& stencil(unsigned timeIdx OPM_UNUSED) const
|
||||
{ return stencil_; }
|
||||
|
||||
/*!
|
||||
* \brief Return the position of a local entities in global coordinates
|
||||
*
|
||||
* \param dofIdx The local index of the degree of freedom
|
||||
* in the current element.
|
||||
* \param timeIdx The index of the solution vector used by the
|
||||
* time discretization.
|
||||
*/
|
||||
const GlobalPosition& pos(unsigned dofIdx, unsigned timeIdx OPM_UNUSED) const
|
||||
{ return stencil_.subControlVolume(dofIdx).globalPos(); }
|
||||
|
||||
/*!
|
||||
* \brief Return the global spatial index for a sub-control volume
|
||||
*
|
||||
* \param dofIdx The local index of the degree of freedom
|
||||
* in the current element.
|
||||
* \param timeIdx The index of the solution vector used by the
|
||||
* time discretization.
|
||||
*/
|
||||
unsigned globalSpaceIndex(unsigned dofIdx, unsigned timeIdx) const
|
||||
{ return stencil(timeIdx).globalSpaceIndex(dofIdx); }
|
||||
|
||||
|
||||
/*!
|
||||
* \brief Return the element-local volume associated with a degree of freedom
|
||||
*
|
||||
* In the case of the vertex-centered finite volume method, this is different from
|
||||
* the total volume because a finite volume usually spans multiple elements...
|
||||
*
|
||||
* \param dofIdx The local index of the degree of freedom in the current element.
|
||||
* \param timeIdx The index of the solution vector used by the time discretization.
|
||||
*/
|
||||
Scalar dofVolume(unsigned dofIdx, unsigned timeIdx) const
|
||||
{ return stencil(timeIdx).subControlVolume(dofIdx).volume(); }
|
||||
|
||||
/*!
|
||||
* \brief Return the total volume associated with a degree of freedom
|
||||
*
|
||||
* "Total" means the volume controlled by a degree of freedom disregarding the
|
||||
* element. (For example in the vertex-centered finite volume method, a control
|
||||
* volume typically encompasses parts of multiple elements.)
|
||||
*
|
||||
* \param dofIdx The local index of the degree of freedom in the current element.
|
||||
* \param timeIdx The index of the solution vector used by the time discretization.
|
||||
*/
|
||||
Scalar dofTotalVolume(unsigned dofIdx, unsigned timeIdx) const
|
||||
{ return model().dofTotalVolume(globalSpaceIndex(dofIdx, timeIdx)); }
|
||||
|
||||
/*!
|
||||
* \brief Returns whether the current element is on the domain's
|
||||
* boundary.
|
||||
*/
|
||||
bool onBoundary() const
|
||||
{ return element().hasBoundaryIntersections(); }
|
||||
|
||||
/*!
|
||||
* \brief Return a reference to the intensive quantities of a
|
||||
* sub-control volume at a given time.
|
||||
*
|
||||
* If the time step index is not given, return the volume
|
||||
* variables for the current time.
|
||||
*
|
||||
* \param dofIdx The local index of the degree of freedom in the current element.
|
||||
* \param timeIdx The index of the solution vector used by the time discretization.
|
||||
*/
|
||||
const IntensiveQuantities& intensiveQuantities(unsigned dofIdx, unsigned timeIdx) const
|
||||
{
|
||||
#ifndef NDEBUG
|
||||
assert(0 <= dofIdx && dofIdx < numDof(timeIdx));
|
||||
|
||||
if (enableStorageCache_ && timeIdx != 0 && problem().recycleFirstIterationStorage())
|
||||
throw std::logic_error("If caching of the storage term is enabled, only the intensive quantities "
|
||||
"for the most-recent substep (i.e. time index 0) are available!");
|
||||
#endif
|
||||
|
||||
return dofVars_[dofIdx].intensiveQuantities[timeIdx];
|
||||
}
|
||||
|
||||
/*!
|
||||
* \brief Return the thermodynamic hint for a given local index.
|
||||
*
|
||||
* \sa Discretization::thermodynamicHint(int, int)
|
||||
*
|
||||
* \param dofIdx The local index of the degree of freedom in the current element.
|
||||
* \param timeIdx The index of the solution vector used by the time discretization.
|
||||
*/
|
||||
const IntensiveQuantities *thermodynamicHint(unsigned dofIdx, unsigned timeIdx) const
|
||||
{
|
||||
assert(0 <= dofIdx && dofIdx < numDof(timeIdx));
|
||||
return dofVars_[dofIdx].thermodynamicHint[timeIdx];
|
||||
}
|
||||
/*!
|
||||
* \copydoc intensiveQuantities()
|
||||
*/
|
||||
IntensiveQuantities& intensiveQuantities(unsigned dofIdx, unsigned timeIdx)
|
||||
{
|
||||
assert(0 <= dofIdx && dofIdx < numDof(timeIdx));
|
||||
return dofVars_[dofIdx].intensiveQuantities[timeIdx];
|
||||
}
|
||||
|
||||
/*!
|
||||
* \brief Return the primary variables for a given local index.
|
||||
*
|
||||
* \param dofIdx The local index of the degree of freedom
|
||||
* in the current element.
|
||||
* \param timeIdx The index of the solution vector used by the
|
||||
* time discretization.
|
||||
*/
|
||||
PrimaryVariables& primaryVars(unsigned dofIdx, unsigned timeIdx)
|
||||
{
|
||||
assert(0 <= dofIdx && dofIdx < numDof(timeIdx));
|
||||
return dofVars_[dofIdx].priVars[timeIdx];
|
||||
}
|
||||
/*!
|
||||
* \copydoc primaryVars()
|
||||
*/
|
||||
const PrimaryVariables& primaryVars(unsigned dofIdx, unsigned timeIdx) const
|
||||
{
|
||||
assert(0 <= dofIdx && dofIdx < numDof(timeIdx));
|
||||
return dofVars_[dofIdx].priVars[timeIdx];
|
||||
}
|
||||
|
||||
/*!
|
||||
* \brief Returns true if no intensive quanties are stashed
|
||||
*
|
||||
* In most cases quantities are stashed only if a partial derivative is to be
|
||||
* calculated via finite difference methods.
|
||||
*/
|
||||
bool haveStashedIntensiveQuantities() const
|
||||
{ return stashedDofIdx_ != -1; }
|
||||
|
||||
/*!
|
||||
* \brief Return the (local) index of the DOF for which the primary variables were
|
||||
* stashed
|
||||
*
|
||||
* If none, then this returns -1.
|
||||
*/
|
||||
int stashedDofIdx() const
|
||||
{ return stashedDofIdx_; }
|
||||
|
||||
/*!
|
||||
* \brief Stash the intensive quantities for a degree of freedom on internal memory.
|
||||
*
|
||||
* \param dofIdx The local index of the degree of freedom in the current element.
|
||||
*/
|
||||
void stashIntensiveQuantities(unsigned dofIdx)
|
||||
{
|
||||
assert(0 <= dofIdx && dofIdx < numDof(/*timeIdx=*/0));
|
||||
|
||||
intensiveQuantitiesStashed_ = dofVars_[dofIdx].intensiveQuantities[/*timeIdx=*/0];
|
||||
priVarsStashed_ = dofVars_[dofIdx].priVars[/*timeIdx=*/0];
|
||||
stashedDofIdx_ = static_cast<int>(dofIdx);
|
||||
}
|
||||
|
||||
/*!
|
||||
* \brief Restores the intensive quantities for a degree of freedom from internal memory.
|
||||
*
|
||||
* \param dofIdx The local index of the degree of freedom in the current element.
|
||||
*/
|
||||
void restoreIntensiveQuantities(unsigned dofIdx)
|
||||
{
|
||||
dofVars_[dofIdx].priVars[/*timeIdx=*/0] = priVarsStashed_;
|
||||
dofVars_[dofIdx].intensiveQuantities[/*timeIdx=*/0] = intensiveQuantitiesStashed_;
|
||||
stashedDofIdx_ = -1;
|
||||
}
|
||||
|
||||
/*!
|
||||
* \brief Return a reference to the gradient calculation class of
|
||||
* the chosen spatial discretization.
|
||||
*/
|
||||
const GradientCalculator& gradientCalculator() const
|
||||
{ return gradientCalculator_; }
|
||||
|
||||
/*!
|
||||
* \brief Return a reference to the extensive quantities of a
|
||||
* sub-control volume face.
|
||||
*
|
||||
* \param fluxIdx The local index of the sub-control volume face for which the
|
||||
* extensive quantities are requested
|
||||
* \param timeIdx The index of the solution vector used by the time discretization.
|
||||
*/
|
||||
const ExtensiveQuantities& extensiveQuantities(unsigned fluxIdx, unsigned timeIdx OPM_UNUSED) const
|
||||
{ return extensiveQuantities_[fluxIdx]; }
|
||||
|
||||
/*!
|
||||
* \brief Returns true iff the cache for the storage term ought to be used for this context.
|
||||
*
|
||||
* If it is used, intensive quantities can only be accessed for the most recent time
|
||||
* index. (time index 0.)
|
||||
*/
|
||||
bool enableStorageCache() const
|
||||
{ return enableStorageCache_; }
|
||||
|
||||
/*!
|
||||
* \brief Specifies if the cache for the storage term ought to be used for this context.
|
||||
*/
|
||||
void setEnableStorageCache(bool yesno)
|
||||
{ enableStorageCache_ = yesno; }
|
||||
|
||||
private:
|
||||
Implementation& asImp_()
|
||||
{ return *static_cast<Implementation*>(this); }
|
||||
|
||||
const Implementation& asImp_() const
|
||||
{ return *static_cast<const Implementation*>(this); }
|
||||
|
||||
protected:
|
||||
/*!
|
||||
* \brief Update the first 'n' intensive quantities objects from the primary variables.
|
||||
*
|
||||
* This method considers the intensive quantities cache.
|
||||
*/
|
||||
void updateIntensiveQuantities_(unsigned timeIdx, size_t numDof)
|
||||
{
|
||||
// update the intensive quantities for the whole history
|
||||
const SolutionVector& globalSol = model().solution(timeIdx);
|
||||
|
||||
// update the non-gradient quantities
|
||||
for (unsigned dofIdx = 0; dofIdx < numDof; dofIdx++) {
|
||||
unsigned globalIdx = globalSpaceIndex(dofIdx, timeIdx);
|
||||
const PrimaryVariables& dofSol = globalSol[globalIdx];
|
||||
dofVars_[dofIdx].priVars[timeIdx] = dofSol;
|
||||
|
||||
dofVars_[dofIdx].thermodynamicHint[timeIdx] =
|
||||
model().thermodynamicHint(globalIdx, timeIdx);
|
||||
|
||||
const auto *cachedIntQuants = model().cachedIntensiveQuantities(globalIdx, timeIdx);
|
||||
if (cachedIntQuants) {
|
||||
dofVars_[dofIdx].intensiveQuantities[timeIdx] = *cachedIntQuants;
|
||||
}
|
||||
else {
|
||||
updateSingleIntQuants_(dofSol, dofIdx, timeIdx);
|
||||
model().updateCachedIntensiveQuantities(dofVars_[dofIdx].intensiveQuantities[timeIdx],
|
||||
globalIdx,
|
||||
timeIdx);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void updateSingleIntQuants_(const PrimaryVariables& priVars, unsigned dofIdx, unsigned timeIdx)
|
||||
{
|
||||
#ifndef NDEBUG
|
||||
if (enableStorageCache_ && timeIdx != 0 && problem().recycleFirstIterationStorage())
|
||||
throw std::logic_error("If caching of the storage term is enabled, only the intensive quantities "
|
||||
"for the most-recent substep (i.e. time index 0) are available!");
|
||||
#endif
|
||||
|
||||
dofVars_[dofIdx].priVars[timeIdx] = priVars;
|
||||
dofVars_[dofIdx].intensiveQuantities[timeIdx].update(/*context=*/asImp_(), dofIdx, timeIdx);
|
||||
}
|
||||
|
||||
IntensiveQuantities intensiveQuantitiesStashed_;
|
||||
PrimaryVariables priVarsStashed_;
|
||||
|
||||
GradientCalculator gradientCalculator_;
|
||||
|
||||
std::vector<DofStore_, Opm::aligned_allocator<DofStore_, alignof(DofStore_)> > dofVars_;
|
||||
std::vector<ExtensiveQuantities, Opm::aligned_allocator<ExtensiveQuantities, alignof(ExtensiveQuantities)> > extensiveQuantities_;
|
||||
|
||||
const Simulator *simulatorPtr_;
|
||||
const Element *elemPtr_;
|
||||
const GridView gridView_;
|
||||
Stencil stencil_;
|
||||
|
||||
int stashedDofIdx_;
|
||||
int focusDofIdx_;
|
||||
bool enableStorageCache_;
|
||||
};
|
||||
|
||||
} // namespace Opm
|
||||
|
||||
#endif
|
134
opm/models/discretization/common/fvbaseextensivequantities.hh
Normal file
134
opm/models/discretization/common/fvbaseextensivequantities.hh
Normal file
@ -0,0 +1,134 @@
|
||||
// -*- mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*-
|
||||
// vi: set et ts=4 sw=4 sts=4:
|
||||
/*
|
||||
This file is part of the Open Porous Media project (OPM).
|
||||
|
||||
OPM 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.
|
||||
|
||||
OPM is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
GNU General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU General Public License
|
||||
along with OPM. If not, see <http://www.gnu.org/licenses/>.
|
||||
|
||||
Consult the COPYING file in the top-level source directory of this
|
||||
module for the precise wording of the license and the list of
|
||||
copyright holders.
|
||||
*/
|
||||
/*!
|
||||
* \file
|
||||
*
|
||||
* \copydoc Opm::FvBaseExtensiveQuantities
|
||||
*/
|
||||
#ifndef EWOMS_FV_BASE_EXTENSIVE_QUANTITIES_HH
|
||||
#define EWOMS_FV_BASE_EXTENSIVE_QUANTITIES_HH
|
||||
|
||||
#include "fvbaseproperties.hh"
|
||||
|
||||
#include <opm/material/common/Valgrind.hpp>
|
||||
#include <opm/material/common/Unused.hpp>
|
||||
|
||||
namespace Opm {
|
||||
/*!
|
||||
* \ingroup FiniteVolumeDiscretizations
|
||||
*
|
||||
* \brief Provide the properties at a face which make sense indepentently
|
||||
* of the conserved quantities.
|
||||
*/
|
||||
template <class TypeTag>
|
||||
class FvBaseExtensiveQuantities
|
||||
{
|
||||
typedef typename GET_PROP_TYPE(TypeTag, Scalar) Scalar;
|
||||
typedef typename GET_PROP_TYPE(TypeTag, ElementContext) ElementContext;
|
||||
typedef typename GET_PROP_TYPE(TypeTag, FluidSystem) FluidSystem;
|
||||
|
||||
public:
|
||||
/*!
|
||||
* \brief Register all run-time parameters for the extensive quantities.
|
||||
*/
|
||||
static void registerParameters()
|
||||
{ }
|
||||
|
||||
/*!
|
||||
* \brief Update the extensive quantities for a given sub-control-volume face.
|
||||
*
|
||||
* \param elemCtx Reference to the current element context.
|
||||
* \param scvfIdx The local index of the sub-control-volume face for which the
|
||||
* extensive quantities should be calculated.
|
||||
* \param timeIdx The index used by the time discretization.
|
||||
*/
|
||||
void update(const ElementContext& elemCtx, unsigned scvfIdx, unsigned timeIdx)
|
||||
{
|
||||
const auto& scvf = elemCtx.stencil(timeIdx).interiorFace(scvfIdx);
|
||||
interiorScvIdx_ = scvf.interiorIndex();
|
||||
exteriorScvIdx_ = scvf.exteriorIndex();
|
||||
|
||||
extrusionFactor_ =
|
||||
(elemCtx.intensiveQuantities(interiorScvIdx_, timeIdx).extrusionFactor()
|
||||
+ elemCtx.intensiveQuantities(exteriorScvIdx_, timeIdx).extrusionFactor()) / 2;
|
||||
Opm::Valgrind::CheckDefined(extrusionFactor_);
|
||||
assert(extrusionFactor_ > 0);
|
||||
}
|
||||
|
||||
|
||||
/*!
|
||||
* \brief Update the extensive quantities for a given boundary face.
|
||||
*
|
||||
* \param context Reference to the current execution context.
|
||||
* \param bfIdx The local index of the boundary face for which
|
||||
* the extensive quantities should be calculated.
|
||||
* \param timeIdx The index used by the time discretization.
|
||||
* \param fluidState The FluidState on the domain boundary.
|
||||
* \param paramCache The FluidSystem's parameter cache.
|
||||
*/
|
||||
template <class Context, class FluidState>
|
||||
void updateBoundary(const Context& context,
|
||||
unsigned bfIdx,
|
||||
unsigned timeIdx,
|
||||
const FluidState& fluidState OPM_UNUSED)
|
||||
{
|
||||
unsigned dofIdx = context.interiorScvIndex(bfIdx, timeIdx);
|
||||
interiorScvIdx_ = static_cast<unsigned short>(dofIdx);
|
||||
exteriorScvIdx_ = static_cast<unsigned short>(dofIdx);
|
||||
|
||||
extrusionFactor_ = context.intensiveQuantities(bfIdx, timeIdx).extrusionFactor();
|
||||
Opm::Valgrind::CheckDefined(extrusionFactor_);
|
||||
assert(extrusionFactor_ > 0);
|
||||
}
|
||||
|
||||
/*!
|
||||
* \brief Returns th extrusion factor for the sub-control-volume face
|
||||
*/
|
||||
Scalar extrusionFactor() const
|
||||
{ return extrusionFactor_; }
|
||||
|
||||
/*!
|
||||
* \brief Return the local index of the control volume which is on the "interior" of
|
||||
* the sub-control volume face.
|
||||
*/
|
||||
unsigned short interiorIndex() const
|
||||
{ return interiorScvIdx_; }
|
||||
|
||||
/*!
|
||||
* \brief Return the local index of the control volume which is on the "exterior" of
|
||||
* the sub-control volume face.
|
||||
*/
|
||||
unsigned short exteriorIndex() const
|
||||
{ return exteriorScvIdx_; }
|
||||
|
||||
private:
|
||||
// local indices of the interior and the exterior sub-control-volumes
|
||||
unsigned short interiorScvIdx_;
|
||||
unsigned short exteriorScvIdx_;
|
||||
|
||||
Scalar extrusionFactor_;
|
||||
};
|
||||
|
||||
} // namespace Opm
|
||||
|
||||
#endif
|
520
opm/models/discretization/common/fvbasefdlocallinearizer.hh
Normal file
520
opm/models/discretization/common/fvbasefdlocallinearizer.hh
Normal file
@ -0,0 +1,520 @@
|
||||
// -*- mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*-
|
||||
// vi: set et ts=4 sw=4 sts=4:
|
||||
/*
|
||||
This file is part of the Open Porous Media project (OPM).
|
||||
|
||||
OPM 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.
|
||||
|
||||
OPM is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
GNU General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU General Public License
|
||||
along with OPM. If not, see <http://www.gnu.org/licenses/>.
|
||||
|
||||
Consult the COPYING file in the top-level source directory of this
|
||||
module for the precise wording of the license and the list of
|
||||
copyright holders.
|
||||
*/
|
||||
/*!
|
||||
* \file
|
||||
*
|
||||
* \copydoc Opm::FvBaseFdLocalLinearizer
|
||||
*/
|
||||
#ifndef EWOMS_FV_BASE_FD_LOCAL_LINEARIZER_HH
|
||||
#define EWOMS_FV_BASE_FD_LOCAL_LINEARIZER_HH
|
||||
|
||||
#include <opm/models/utils/propertysystem.hh>
|
||||
#include <opm/models/utils/parametersystem.hh>
|
||||
|
||||
#include <opm/material/common/MathToolbox.hpp>
|
||||
#include <opm/material/common/Valgrind.hpp>
|
||||
|
||||
#include <dune/istl/bvector.hh>
|
||||
#include <dune/istl/matrix.hh>
|
||||
|
||||
#include <dune/common/fvector.hh>
|
||||
#include <dune/common/fmatrix.hh>
|
||||
|
||||
#include <limits>
|
||||
|
||||
namespace Opm {
|
||||
// forward declaration
|
||||
template<class TypeTag>
|
||||
class FvBaseFdLocalLinearizer;
|
||||
|
||||
} // namespace Opm
|
||||
|
||||
BEGIN_PROPERTIES
|
||||
|
||||
// declare the property tags required for the finite differences local linearizer
|
||||
NEW_TYPE_TAG(FiniteDifferenceLocalLinearizer);
|
||||
|
||||
NEW_PROP_TAG(LocalLinearizer);
|
||||
NEW_PROP_TAG(Evaluation);
|
||||
NEW_PROP_TAG(NumericDifferenceMethod);
|
||||
NEW_PROP_TAG(BaseEpsilon);
|
||||
NEW_PROP_TAG(SparseMatrixAdapter);
|
||||
NEW_PROP_TAG(LocalResidual);
|
||||
NEW_PROP_TAG(Simulator);
|
||||
NEW_PROP_TAG(Problem);
|
||||
NEW_PROP_TAG(Model);
|
||||
NEW_PROP_TAG(PrimaryVariables);
|
||||
NEW_PROP_TAG(ElementContext);
|
||||
NEW_PROP_TAG(Scalar);
|
||||
NEW_PROP_TAG(Evaluation);
|
||||
NEW_PROP_TAG(GridView);
|
||||
NEW_PROP_TAG(NumEq);
|
||||
|
||||
// set the properties to be spliced in
|
||||
SET_TYPE_PROP(FiniteDifferenceLocalLinearizer, LocalLinearizer,
|
||||
Opm::FvBaseFdLocalLinearizer<TypeTag>);
|
||||
|
||||
SET_TYPE_PROP(FiniteDifferenceLocalLinearizer, Evaluation,
|
||||
typename GET_PROP_TYPE(TypeTag, Scalar));
|
||||
|
||||
/*!
|
||||
* \brief Specify which kind of method should be used to numerically
|
||||
* calculate the partial derivatives of the residual.
|
||||
*
|
||||
* -1 means backward differences, 0 means central differences, 1 means
|
||||
* forward differences. By default we use central differences.
|
||||
*/
|
||||
SET_INT_PROP(FiniteDifferenceLocalLinearizer, NumericDifferenceMethod, +1);
|
||||
|
||||
//! The base epsilon value for finite difference calculations
|
||||
SET_SCALAR_PROP(FiniteDifferenceLocalLinearizer,
|
||||
BaseEpsilon,
|
||||
std::max<Scalar>(0.9123e-10, std::numeric_limits<Scalar>::epsilon()*1.23e3));
|
||||
|
||||
END_PROPERTIES
|
||||
|
||||
namespace Opm {
|
||||
|
||||
/*!
|
||||
* \ingroup FiniteVolumeDiscretizations
|
||||
*
|
||||
* \brief Calculates the Jacobian of the local residual for finite volume spatial
|
||||
* discretizations using a finite difference method
|
||||
*
|
||||
* The local Jacobian for a given context is defined as the derivatives of the residuals
|
||||
* of all degrees of freedom featured by the stencil with regard to the primary variables
|
||||
* of the stencil's "primary" degrees of freedom.
|
||||
*
|
||||
* This class implements numeric differentiation using finite difference methods, i.e.
|
||||
* forward or backward differences (2nd order), or central differences (3rd order). The
|
||||
* method used is determined by the "NumericDifferenceMethod" property:
|
||||
*
|
||||
* - If the value of this property is smaller than 0, backward differences are used,
|
||||
* i.e.:
|
||||
* \f[
|
||||
* \frac{\partial f(x)}{\partial x} \approx \frac{f(x) - f(x - \epsilon)}{\epsilon}
|
||||
* \f]
|
||||
*
|
||||
* - If the value of this property is 0, central differences are used, i.e.:
|
||||
* \f[
|
||||
* \frac{\partial f(x)}{\partial x} \approx
|
||||
* \frac{f(x + \epsilon) - f(x - \epsilon)}{2 \epsilon}
|
||||
* \f]
|
||||
*
|
||||
* - if the value of this property is larger than 0, forward differences are used, i.e.:
|
||||
* \f[
|
||||
* \frac{\partial f(x)}{\partial x} \approx
|
||||
* \frac{f(x + \epsilon) - f(x)}{\epsilon}
|
||||
* \f]
|
||||
*
|
||||
* Here, \f$ f \f$ is the residual function for all equations, \f$x\f$ is the value of a
|
||||
* sub-control volume's primary variable at the evaluation point and \f$\epsilon\f$ is a
|
||||
* small scalar value larger than 0.
|
||||
*/
|
||||
template<class TypeTag>
|
||||
class FvBaseFdLocalLinearizer
|
||||
{
|
||||
private:
|
||||
typedef typename GET_PROP_TYPE(TypeTag, LocalLinearizer) Implementation;
|
||||
typedef typename GET_PROP_TYPE(TypeTag, LocalResidual) LocalResidual;
|
||||
typedef typename GET_PROP_TYPE(TypeTag, Simulator) Simulator;
|
||||
typedef typename GET_PROP_TYPE(TypeTag, Problem) Problem;
|
||||
typedef typename GET_PROP_TYPE(TypeTag, Model) Model;
|
||||
typedef typename GET_PROP_TYPE(TypeTag, PrimaryVariables) PrimaryVariables;
|
||||
typedef typename GET_PROP_TYPE(TypeTag, ElementContext) ElementContext;
|
||||
typedef typename GET_PROP_TYPE(TypeTag, Scalar) Scalar;
|
||||
typedef typename GET_PROP_TYPE(TypeTag, GridView) GridView;
|
||||
typedef typename GridView::template Codim<0>::Entity Element;
|
||||
|
||||
enum { numEq = GET_PROP_VALUE(TypeTag, NumEq) };
|
||||
|
||||
// extract local matrices from jacobian matrix for consistency
|
||||
typedef typename GET_PROP_TYPE(TypeTag, SparseMatrixAdapter)::MatrixBlock ScalarMatrixBlock;
|
||||
typedef Dune::FieldVector<Scalar, numEq> ScalarVectorBlock;
|
||||
|
||||
typedef Dune::BlockVector<ScalarVectorBlock> ScalarLocalBlockVector;
|
||||
typedef Dune::Matrix<ScalarMatrixBlock> ScalarLocalBlockMatrix;
|
||||
|
||||
typedef typename LocalResidual::LocalEvalBlockVector LocalEvalBlockVector;
|
||||
|
||||
#if __GNUC__ == 4 && __GNUC_MINOR__ <= 6
|
||||
public:
|
||||
// make older GCCs happy by providing a public copy constructor (this is necessary
|
||||
// for their implementation of std::vector, although the method is never called...)
|
||||
FvBaseFdLocalLinearizer(const FvBaseFdLocalLinearizer&)
|
||||
: internalElemContext_(0)
|
||||
{}
|
||||
|
||||
#else
|
||||
// copying local residual objects around is a very bad idea, so we explicitly prevent
|
||||
// it...
|
||||
FvBaseFdLocalLinearizer(const FvBaseFdLocalLinearizer&) = delete;
|
||||
#endif
|
||||
public:
|
||||
FvBaseFdLocalLinearizer()
|
||||
: internalElemContext_(0)
|
||||
{ }
|
||||
|
||||
~FvBaseFdLocalLinearizer()
|
||||
{ delete internalElemContext_; }
|
||||
|
||||
/*!
|
||||
* \brief Register all run-time parameters for the local jacobian.
|
||||
*/
|
||||
static void registerParameters()
|
||||
{
|
||||
EWOMS_REGISTER_PARAM(TypeTag, int, NumericDifferenceMethod,
|
||||
"The method used for numeric differentiation (-1: backward "
|
||||
"differences, 0: central differences, 1: forward differences)");
|
||||
}
|
||||
|
||||
/*!
|
||||
* \brief Initialize the local Jacobian object.
|
||||
*
|
||||
* At this point we can assume that everything has been allocated,
|
||||
* although some objects may not yet be completely initialized.
|
||||
*
|
||||
* \param simulator The simulator object of the simulation.
|
||||
*/
|
||||
void init(Simulator& simulator)
|
||||
{
|
||||
simulatorPtr_ = &simulator;
|
||||
delete internalElemContext_;
|
||||
internalElemContext_ = new ElementContext(simulator);
|
||||
}
|
||||
|
||||
/*!
|
||||
* \brief Compute an element's local Jacobian matrix and evaluate its residual.
|
||||
*
|
||||
* The local Jacobian for a given context is defined as the derivatives of the
|
||||
* residuals of all degrees of freedom featured by the stencil with regard to the
|
||||
* primary variables of the stencil's "primary" degrees of freedom. Adding the local
|
||||
* Jacobians for all elements in the grid will give the global Jacobian 'grad f(x)'.
|
||||
*
|
||||
* \param element The grid element for which the local residual and its local
|
||||
* Jacobian should be calculated.
|
||||
*/
|
||||
void linearize(const Element& element)
|
||||
{
|
||||
linearize(*internalElemContext_, element);
|
||||
}
|
||||
|
||||
/*!
|
||||
* \brief Compute an element's local Jacobian matrix and evaluate its residual.
|
||||
*
|
||||
* The local Jacobian for a given context is defined as the derivatives of the
|
||||
* residuals of all degrees of freedom featured by the stencil with regard to the
|
||||
* primary variables of the stencil's "primary" degrees of freedom. Adding the local
|
||||
* Jacobians for all elements in the grid will give the global Jacobian 'grad f(x)'.
|
||||
*
|
||||
* After calling this method the ElementContext is in an undefined state, so do not
|
||||
* use it anymore!
|
||||
*
|
||||
* \param elemCtx The element execution context for which the local residual and its
|
||||
* local Jacobian should be calculated.
|
||||
*/
|
||||
void linearize(ElementContext& elemCtx, const Element& elem)
|
||||
{
|
||||
elemCtx.updateAll(elem);
|
||||
|
||||
// update the weights of the primary variables for the context
|
||||
model_().updatePVWeights(elemCtx);
|
||||
|
||||
resize_(elemCtx);
|
||||
reset_(elemCtx);
|
||||
|
||||
// calculate the local residual
|
||||
localResidual_.eval(residual_, elemCtx);
|
||||
|
||||
// calculate the local jacobian matrix
|
||||
size_t numPrimaryDof = elemCtx.numPrimaryDof(/*timeIdx=*/0);
|
||||
for (unsigned dofIdx = 0; dofIdx < numPrimaryDof; dofIdx++) {
|
||||
for (unsigned pvIdx = 0; pvIdx < numEq; pvIdx++) {
|
||||
asImp_().evalPartialDerivative_(elemCtx, dofIdx, pvIdx);
|
||||
|
||||
// incorporate the partial derivatives into the local Jacobian matrix
|
||||
updateLocalJacobian_(elemCtx, dofIdx, pvIdx);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/*!
|
||||
* \brief Returns the unweighted epsilon value used to calculate
|
||||
* the local derivatives
|
||||
*/
|
||||
static Scalar baseEpsilon()
|
||||
{ return GET_PROP_VALUE(TypeTag, BaseEpsilon); }
|
||||
|
||||
/*!
|
||||
* \brief Returns the epsilon value which is added and removed
|
||||
* from the current solution.
|
||||
*
|
||||
* \param elemCtx The element execution context for which the
|
||||
* local residual and its gradient should be
|
||||
* calculated.
|
||||
* \param dofIdx The local index of the element's vertex for
|
||||
* which the local derivative ought to be calculated.
|
||||
* \param pvIdx The index of the primary variable which gets varied
|
||||
*/
|
||||
Scalar numericEpsilon(const ElementContext& elemCtx,
|
||||
unsigned dofIdx,
|
||||
unsigned pvIdx) const
|
||||
{
|
||||
unsigned globalIdx = elemCtx.globalSpaceIndex(dofIdx, /*timeIdx=*/0);
|
||||
Scalar pvWeight = elemCtx.model().primaryVarWeight(globalIdx, pvIdx);
|
||||
assert(pvWeight > 0 && std::isfinite(pvWeight));
|
||||
Opm::Valgrind::CheckDefined(pvWeight);
|
||||
|
||||
return baseEpsilon()/pvWeight;
|
||||
}
|
||||
|
||||
/*!
|
||||
* \brief Return reference to the local residual.
|
||||
*/
|
||||
LocalResidual& localResidual()
|
||||
{ return localResidual_; }
|
||||
|
||||
/*!
|
||||
* \brief Return reference to the local residual.
|
||||
*/
|
||||
const LocalResidual& localResidual() const
|
||||
{ return localResidual_; }
|
||||
|
||||
/*!
|
||||
* \brief Returns the local Jacobian matrix of the residual of a sub-control volume.
|
||||
*
|
||||
* \param domainScvIdx The local index of the sub control volume
|
||||
* which contains the independents
|
||||
* \param rangeScvIdx The local index of the sub control volume
|
||||
* which contains the local residual
|
||||
*/
|
||||
const ScalarMatrixBlock& jacobian(unsigned domainScvIdx, unsigned rangeScvIdx) const
|
||||
{ return jacobian_[domainScvIdx][rangeScvIdx]; }
|
||||
|
||||
/*!
|
||||
* \brief Returns the local residual of a sub-control volume.
|
||||
*
|
||||
* \param dofIdx The local index of the sub control volume
|
||||
*/
|
||||
const ScalarVectorBlock& residual(unsigned dofIdx) const
|
||||
{ return residual_[dofIdx]; }
|
||||
|
||||
protected:
|
||||
Implementation& asImp_()
|
||||
{ return *static_cast<Implementation*>(this); }
|
||||
const Implementation& asImp_() const
|
||||
{ return *static_cast<const Implementation*>(this); }
|
||||
|
||||
const Simulator& simulator_() const
|
||||
{ return *simulatorPtr_; }
|
||||
const Problem& problem_() const
|
||||
{ return simulatorPtr_->problem(); }
|
||||
const Model& model_() const
|
||||
{ return simulatorPtr_->model(); }
|
||||
|
||||
/*!
|
||||
* \brief Returns the numeric difference method which is applied.
|
||||
*/
|
||||
static int numericDifferenceMethod_()
|
||||
{ return EWOMS_GET_PARAM(TypeTag, int, NumericDifferenceMethod); }
|
||||
|
||||
/*!
|
||||
* \brief Resize all internal attributes to the size of the
|
||||
* element.
|
||||
*/
|
||||
void resize_(const ElementContext& elemCtx)
|
||||
{
|
||||
size_t numDof = elemCtx.numDof(/*timeIdx=*/0);
|
||||
size_t numPrimaryDof = elemCtx.numPrimaryDof(/*timeIdx=*/0);
|
||||
|
||||
residual_.resize(numDof);
|
||||
jacobian_.setSize(numDof, numPrimaryDof);
|
||||
|
||||
derivResidual_.resize(numDof);
|
||||
}
|
||||
|
||||
/*!
|
||||
* \brief Reset the all relevant internal attributes to 0
|
||||
*/
|
||||
void reset_(const ElementContext& elemCtx)
|
||||
{
|
||||
size_t numDof = elemCtx.numDof(/*timeIdx=*/0);
|
||||
size_t numPrimaryDof = elemCtx.numPrimaryDof(/*timeIdx=*/0);
|
||||
for (unsigned primaryDofIdx = 0; primaryDofIdx < numPrimaryDof; ++ primaryDofIdx)
|
||||
for (unsigned dof2Idx = 0; dof2Idx < numDof; ++ dof2Idx)
|
||||
jacobian_[dof2Idx][primaryDofIdx] = 0.0;
|
||||
|
||||
for (unsigned primaryDofIdx = 0; primaryDofIdx < numDof; ++ primaryDofIdx)
|
||||
residual_[primaryDofIdx] = 0.0;
|
||||
}
|
||||
|
||||
/*!
|
||||
* \brief Compute the partial derivatives of a context's residual functions
|
||||
*
|
||||
* This method can be overwritten by the implementation if a better scheme than
|
||||
* numerical differentiation is available.
|
||||
*
|
||||
* The default implementation of this method uses numeric differentiation,
|
||||
* i.e. forward or backward differences (2nd order), or central differences (3rd
|
||||
* order). The method used is determined by the "NumericDifferenceMethod" property:
|
||||
*
|
||||
* - If the value of this property is smaller than 0, backward differences are used,
|
||||
* i.e.:
|
||||
* \f[
|
||||
* \frac{\partial f(x)}{\partial x} \approx \frac{f(x) - f(x - \epsilon)}{\epsilon}
|
||||
* \f]
|
||||
*
|
||||
* - If the value of this property is 0, central differences are used, i.e.:
|
||||
* \f[
|
||||
* \frac{\partial f(x)}{\partial x} \approx
|
||||
* \frac{f(x + \epsilon) - f(x - \epsilon)}{2 \epsilon}
|
||||
* \f]
|
||||
*
|
||||
* - if the value of this property is larger than 0, forward
|
||||
* differences are used, i.e.:
|
||||
* \f[
|
||||
\frac{\partial f(x)}{\partial x} \approx \frac{f(x + \epsilon) - f(x)}{\epsilon}
|
||||
* \f]
|
||||
*
|
||||
* Here, \f$ f \f$ is the residual function for all equations, \f$x\f$ is the value
|
||||
* of a sub-control volume's primary variable at the evaluation point and
|
||||
* \f$\epsilon\f$ is a small value larger than 0.
|
||||
*
|
||||
* \param elemCtx The element context for which the local partial
|
||||
* derivative ought to be calculated
|
||||
* \param dofIdx The sub-control volume index of the current
|
||||
* finite element for which the partial derivative
|
||||
* ought to be calculated
|
||||
* \param pvIdx The index of the primary variable at the dofIdx'
|
||||
* sub-control volume of the current finite element
|
||||
* for which the partial derivative ought to be
|
||||
* calculated
|
||||
*/
|
||||
void evalPartialDerivative_(ElementContext& elemCtx,
|
||||
unsigned dofIdx,
|
||||
unsigned pvIdx)
|
||||
{
|
||||
// save all quantities which depend on the specified primary
|
||||
// variable at the given sub control volume
|
||||
elemCtx.stashIntensiveQuantities(dofIdx);
|
||||
|
||||
PrimaryVariables priVars(elemCtx.primaryVars(dofIdx, /*timeIdx=*/0));
|
||||
Scalar eps = asImp_().numericEpsilon(elemCtx, dofIdx, pvIdx);
|
||||
Scalar delta = 0.0;
|
||||
|
||||
if (numericDifferenceMethod_() >= 0) {
|
||||
// we are not using backward differences, i.e. we need to
|
||||
// calculate f(x + \epsilon)
|
||||
|
||||
// deflect primary variables
|
||||
priVars[pvIdx] += eps;
|
||||
delta += eps;
|
||||
|
||||
// calculate the deflected residual
|
||||
elemCtx.updateIntensiveQuantities(priVars, dofIdx, /*timeIdx=*/0);
|
||||
elemCtx.updateAllExtensiveQuantities();
|
||||
localResidual_.eval(derivResidual_, elemCtx);
|
||||
}
|
||||
else {
|
||||
// we are using backward differences, i.e. we don't need
|
||||
// to calculate f(x + \epsilon) and we can recycle the
|
||||
// (already calculated) residual f(x)
|
||||
derivResidual_ = residual_;
|
||||
}
|
||||
|
||||
if (numericDifferenceMethod_() <= 0) {
|
||||
// we are not using forward differences, i.e. we don't
|
||||
// need to calculate f(x - \epsilon)
|
||||
|
||||
// deflect the primary variables
|
||||
priVars[pvIdx] -= delta + eps;
|
||||
delta += eps;
|
||||
|
||||
// calculate the deflected residual again, this time we use the local
|
||||
// residual's internal storage.
|
||||
elemCtx.updateIntensiveQuantities(priVars, dofIdx, /*timeIdx=*/0);
|
||||
elemCtx.updateAllExtensiveQuantities();
|
||||
localResidual_.eval(elemCtx);
|
||||
|
||||
derivResidual_ -= localResidual_.residual();
|
||||
}
|
||||
else {
|
||||
// we are using forward differences, i.e. we don't need to
|
||||
// calculate f(x - \epsilon) and we can recycle the
|
||||
// (already calculated) residual f(x)
|
||||
derivResidual_ -= residual_;
|
||||
}
|
||||
|
||||
assert(delta > 0);
|
||||
|
||||
// divide difference in residuals by the magnitude of the
|
||||
// deflections between the two function evaluation
|
||||
derivResidual_ /= delta;
|
||||
|
||||
// restore the original state of the element's volume
|
||||
// variables
|
||||
elemCtx.restoreIntensiveQuantities(dofIdx);
|
||||
|
||||
#ifndef NDEBUG
|
||||
for (unsigned i = 0; i < derivResidual_.size(); ++i)
|
||||
Opm::Valgrind::CheckDefined(derivResidual_[i]);
|
||||
#endif
|
||||
}
|
||||
|
||||
/*!
|
||||
* \brief Updates the current local Jacobian matrix with the partial derivatives of
|
||||
* all equations for primary variable 'pvIdx' at the degree of freedom
|
||||
* associated with 'focusDofIdx'.
|
||||
*/
|
||||
void updateLocalJacobian_(const ElementContext& elemCtx,
|
||||
unsigned focusDofIdx,
|
||||
unsigned pvIdx)
|
||||
{
|
||||
size_t numDof = elemCtx.numDof(/*timeIdx=*/0);
|
||||
for (unsigned dofIdx = 0; dofIdx < numDof; dofIdx++) {
|
||||
for (unsigned eqIdx = 0; eqIdx < numEq; eqIdx++) {
|
||||
// A[dofIdx][focusDofIdx][eqIdx][pvIdx] is the partial derivative of the
|
||||
// residual function 'eqIdx' for the degree of freedom 'dofIdx' with
|
||||
// regard to the primary variable 'pvIdx' of the degree of freedom
|
||||
// 'focusDofIdx'
|
||||
jacobian_[dofIdx][focusDofIdx][eqIdx][pvIdx] = derivResidual_[dofIdx][eqIdx];
|
||||
Opm::Valgrind::CheckDefined(jacobian_[dofIdx][focusDofIdx][eqIdx][pvIdx]);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
Simulator *simulatorPtr_;
|
||||
Model *modelPtr_;
|
||||
|
||||
ElementContext *internalElemContext_;
|
||||
|
||||
LocalEvalBlockVector residual_;
|
||||
LocalEvalBlockVector derivResidual_;
|
||||
ScalarLocalBlockMatrix jacobian_;
|
||||
|
||||
LocalResidual localResidual_;
|
||||
};
|
||||
|
||||
} // namespace Opm
|
||||
|
||||
#endif
|
358
opm/models/discretization/common/fvbasegradientcalculator.hh
Normal file
358
opm/models/discretization/common/fvbasegradientcalculator.hh
Normal file
@ -0,0 +1,358 @@
|
||||
// -*- mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*-
|
||||
// vi: set et ts=4 sw=4 sts=4:
|
||||
/*
|
||||
This file is part of the Open Porous Media project (OPM).
|
||||
|
||||
OPM 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.
|
||||
|
||||
OPM is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
GNU General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU General Public License
|
||||
along with OPM. If not, see <http://www.gnu.org/licenses/>.
|
||||
|
||||
Consult the COPYING file in the top-level source directory of this
|
||||
module for the precise wording of the license and the list of
|
||||
copyright holders.
|
||||
*/
|
||||
/*!
|
||||
* \file
|
||||
*
|
||||
* \copydoc Opm::FvBaseGradientCalculator
|
||||
*/
|
||||
#ifndef EWOMS_FV_BASE_GRADIENT_CALCULATOR_HH
|
||||
#define EWOMS_FV_BASE_GRADIENT_CALCULATOR_HH
|
||||
|
||||
#include "fvbaseproperties.hh"
|
||||
|
||||
#include <opm/material/common/Unused.hpp>
|
||||
|
||||
#include <dune/common/fvector.hh>
|
||||
|
||||
namespace Opm {
|
||||
template<class TypeTag>
|
||||
class EcfvDiscretization;
|
||||
|
||||
/*!
|
||||
* \ingroup FiniteVolumeDiscretizations
|
||||
*
|
||||
* \brief This class calculates gradients of arbitrary quantities at
|
||||
* flux integration points using the two-point approximation scheme
|
||||
*/
|
||||
template<class TypeTag>
|
||||
class FvBaseGradientCalculator
|
||||
{
|
||||
typedef typename GET_PROP_TYPE(TypeTag, GridView) GridView;
|
||||
typedef typename GET_PROP_TYPE(TypeTag, Scalar) Scalar;
|
||||
typedef typename GET_PROP_TYPE(TypeTag, Evaluation) Evaluation;
|
||||
typedef typename GET_PROP_TYPE(TypeTag, Discretization) Discretization;
|
||||
typedef typename GET_PROP_TYPE(TypeTag, ElementContext) ElementContext;
|
||||
|
||||
enum { dim = GridView::dimension };
|
||||
enum { dimWorld = GridView::dimensionworld };
|
||||
|
||||
// maximum number of flux approximation points. to calculate this,
|
||||
// we assume that the geometry with the most pointsq is a cube.
|
||||
enum { maxFap = 2 << dim };
|
||||
|
||||
typedef Dune::FieldVector<Scalar, dimWorld> DimVector;
|
||||
typedef Dune::FieldVector<Evaluation, dimWorld> EvalDimVector;
|
||||
|
||||
public:
|
||||
/*!
|
||||
* \brief Register all run-time parameters for the gradient calculator
|
||||
* of the base class of the discretization.
|
||||
*/
|
||||
static void registerParameters()
|
||||
{ }
|
||||
|
||||
/*!
|
||||
* \brief Precomputes the common values to calculate gradients and values of
|
||||
* quantities at every interior flux approximation point.
|
||||
*
|
||||
* \param elemCtx The current execution context
|
||||
* \param timeIdx The index used by the time discretization.
|
||||
*/
|
||||
template <bool prepareValues = true, bool prepareGradients = true>
|
||||
void prepare(const ElementContext& elemCtx OPM_UNUSED, unsigned timeIdx OPM_UNUSED)
|
||||
{ /* noting to do */ }
|
||||
|
||||
/*!
|
||||
* \brief Calculates the value of an arbitrary scalar quantity at any interior flux
|
||||
* approximation point.
|
||||
*
|
||||
* \param elemCtx The current execution context
|
||||
* \param fapIdx The local index of the flux approximation point in the current
|
||||
* element's stencil.
|
||||
* \param quantityCallback A callable object returning the value
|
||||
* of the quantity at an index of a degree of
|
||||
* freedom
|
||||
*/
|
||||
template <class QuantityCallback>
|
||||
auto calculateScalarValue(const ElementContext& elemCtx,
|
||||
unsigned fapIdx,
|
||||
const QuantityCallback& quantityCallback) const
|
||||
-> typename std::remove_reference<decltype(quantityCallback.operator()(0))>::type
|
||||
{
|
||||
typedef decltype(quantityCallback.operator()(0)) RawReturnType;
|
||||
typedef typename std::remove_const<typename std::remove_reference<RawReturnType>::type>::type ReturnType;
|
||||
|
||||
Scalar interiorDistance;
|
||||
Scalar exteriorDistance;
|
||||
computeDistances_(interiorDistance, exteriorDistance, elemCtx, fapIdx);
|
||||
|
||||
const auto& face = elemCtx.stencil(/*timeIdx=*/0).interiorFace(fapIdx);
|
||||
auto i = face.interiorIndex();
|
||||
auto j = face.exteriorIndex();
|
||||
auto focusDofIdx = elemCtx.focusDofIndex();
|
||||
|
||||
// use the average weighted by distance...
|
||||
ReturnType value;
|
||||
if (i == focusDofIdx)
|
||||
value = quantityCallback(i)*interiorDistance;
|
||||
else
|
||||
value = Opm::getValue(quantityCallback(i))*interiorDistance;
|
||||
|
||||
if (j == focusDofIdx)
|
||||
value += quantityCallback(j)*exteriorDistance;
|
||||
else
|
||||
value += Opm::getValue(quantityCallback(j))*exteriorDistance;
|
||||
|
||||
value /= interiorDistance + exteriorDistance;
|
||||
|
||||
return value;
|
||||
}
|
||||
|
||||
/*!
|
||||
* \brief Calculates the value of an arbitrary vectorial quantity at any interior flux
|
||||
* approximation point.
|
||||
*
|
||||
* \param elemCtx The current execution context
|
||||
* \param fapIdx The local index of the flux approximation point in the current
|
||||
* element's stencil.
|
||||
* \param quantityCallback A callable object returning the value
|
||||
* of the quantity at an index of a degree of
|
||||
* freedom
|
||||
*/
|
||||
template <class QuantityCallback>
|
||||
auto calculateVectorValue(const ElementContext& elemCtx,
|
||||
unsigned fapIdx,
|
||||
const QuantityCallback& quantityCallback) const
|
||||
-> typename std::remove_reference<decltype(quantityCallback.operator()(0))>::type
|
||||
{
|
||||
typedef decltype(quantityCallback.operator()(0)) RawReturnType;
|
||||
typedef typename std::remove_const<typename std::remove_reference<RawReturnType>::type>::type ReturnType;
|
||||
|
||||
Scalar interiorDistance;
|
||||
Scalar exteriorDistance;
|
||||
computeDistances_(interiorDistance, exteriorDistance, elemCtx, fapIdx);
|
||||
|
||||
const auto& face = elemCtx.stencil(/*timeIdx=*/0).interiorFace(fapIdx);
|
||||
auto i = face.interiorIndex();
|
||||
auto j = face.exteriorIndex();
|
||||
auto focusDofIdx = elemCtx.focusDofIndex();
|
||||
|
||||
// use the average weighted by distance...
|
||||
ReturnType value;
|
||||
if (i == focusDofIdx) {
|
||||
value = quantityCallback(i);
|
||||
for (int k = 0; k < value.size(); ++k)
|
||||
value[k] *= interiorDistance;
|
||||
}
|
||||
else {
|
||||
const auto& dofVal = Opm::getValue(quantityCallback(i));
|
||||
for (int k = 0; k < dofVal.size(); ++k)
|
||||
value[k] = Opm::getValue(dofVal[k])*interiorDistance;
|
||||
}
|
||||
|
||||
if (j == focusDofIdx) {
|
||||
const auto& dofVal = quantityCallback(j);
|
||||
for (int k = 0; k < dofVal.size(); ++k)
|
||||
value[k] += dofVal[k]*exteriorDistance;
|
||||
}
|
||||
else {
|
||||
const auto& dofVal = quantityCallback(j);
|
||||
for (int k = 0; k < dofVal.size(); ++k)
|
||||
value[k] += Opm::getValue(dofVal[k])*exteriorDistance;
|
||||
}
|
||||
|
||||
Scalar totDistance = interiorDistance + exteriorDistance;
|
||||
for (int k = 0; k < value.size(); ++k)
|
||||
value[k] /= totDistance;
|
||||
|
||||
return value;
|
||||
}
|
||||
|
||||
/*!
|
||||
* \brief Calculates the gradient of an arbitrary quantity at any
|
||||
* flux approximation point.
|
||||
*
|
||||
* \param elemCtx The current execution context
|
||||
* \param fapIdx The local index of the flux approximation point
|
||||
* in the current element's stencil.
|
||||
* \param quantityCallback A callable object returning the value
|
||||
* of the quantity given the index of a degree of
|
||||
* freedom
|
||||
*/
|
||||
template <class QuantityCallback>
|
||||
void calculateGradient(EvalDimVector& quantityGrad,
|
||||
const ElementContext& elemCtx,
|
||||
unsigned fapIdx,
|
||||
const QuantityCallback& quantityCallback) const
|
||||
{
|
||||
const auto& stencil = elemCtx.stencil(/*timeIdx=*/0);
|
||||
const auto& face = stencil.interiorFace(fapIdx);
|
||||
|
||||
auto i = face.interiorIndex();
|
||||
auto j = face.exteriorIndex();
|
||||
auto focusIdx = elemCtx.focusDofIndex();
|
||||
|
||||
const auto& interiorPos = stencil.subControlVolume(i).globalPos();
|
||||
const auto& exteriorPos = stencil.subControlVolume(j).globalPos();
|
||||
|
||||
Evaluation deltay;
|
||||
if (i == focusIdx) {
|
||||
deltay =
|
||||
Opm::getValue(quantityCallback(j))
|
||||
- quantityCallback(i);
|
||||
}
|
||||
else if (j == focusIdx) {
|
||||
deltay =
|
||||
quantityCallback(j)
|
||||
- Opm::getValue(quantityCallback(i));
|
||||
}
|
||||
else
|
||||
deltay =
|
||||
Opm::getValue(quantityCallback(j))
|
||||
- Opm::getValue(quantityCallback(i));
|
||||
|
||||
Scalar distSquared = 0.0;
|
||||
for (unsigned dimIdx = 0; dimIdx < dimWorld; ++dimIdx) {
|
||||
Scalar tmp = exteriorPos[dimIdx] - interiorPos[dimIdx];
|
||||
distSquared += tmp*tmp;
|
||||
}
|
||||
|
||||
// divide the gradient by the squared distance between the centers of the
|
||||
// sub-control volumes: the gradient is the normalized directional vector between
|
||||
// the two centers times the ratio of the difference of the values and their
|
||||
// distance, i.e., d/abs(d) * delta y / abs(d) = d*delta y / abs(d)^2.
|
||||
for (unsigned dimIdx = 0; dimIdx < dimWorld; ++dimIdx) {
|
||||
Scalar tmp = exteriorPos[dimIdx] - interiorPos[dimIdx];
|
||||
quantityGrad[dimIdx] = deltay*(tmp/distSquared);
|
||||
}
|
||||
}
|
||||
|
||||
/*!
|
||||
* \brief Calculates the value of an arbitrary quantity at any
|
||||
* flux approximation point on the grid boundary.
|
||||
*
|
||||
* Boundary values are always calculated using the two-point
|
||||
* approximation.
|
||||
*
|
||||
* \param elemCtx The current execution context
|
||||
* \param fapIdx The local index of the flux approximation point
|
||||
* in the current element's stencil.
|
||||
* \param quantityCallback A callable object returning the value
|
||||
* of the quantity given the index of a degree of
|
||||
* freedom
|
||||
*/
|
||||
template <class QuantityCallback>
|
||||
auto calculateBoundaryValue(const ElementContext& elemCtx OPM_UNUSED,
|
||||
unsigned fapIdx OPM_UNUSED,
|
||||
const QuantityCallback& quantityCallback)
|
||||
-> decltype(quantityCallback.boundaryValue())
|
||||
{ return quantityCallback.boundaryValue(); }
|
||||
|
||||
/*!
|
||||
* \brief Calculates the gradient of an arbitrary quantity at any
|
||||
* flux approximation point on the boundary.
|
||||
*
|
||||
* Boundary gradients are always calculated using the two-point
|
||||
* approximation.
|
||||
*
|
||||
* \param elemCtx The current execution context
|
||||
* \param faceIdx The local index of the flux approximation point
|
||||
* in the current element's stencil.
|
||||
* \param quantityCallback A callable object returning the value
|
||||
* of the quantity at an index of a degree of
|
||||
* freedom
|
||||
*/
|
||||
template <class QuantityCallback>
|
||||
void calculateBoundaryGradient(EvalDimVector& quantityGrad,
|
||||
const ElementContext& elemCtx,
|
||||
unsigned faceIdx,
|
||||
const QuantityCallback& quantityCallback) const
|
||||
{
|
||||
const auto& stencil = elemCtx.stencil(/*timeIdx=*/0);
|
||||
const auto& face = stencil.boundaryFace(faceIdx);
|
||||
|
||||
Evaluation deltay;
|
||||
if (face.interiorIndex() == elemCtx.focusDofIndex())
|
||||
deltay = quantityCallback.boundaryValue() - quantityCallback(face.interiorIndex());
|
||||
else
|
||||
deltay =
|
||||
Opm::getValue(quantityCallback.boundaryValue())
|
||||
- Opm::getValue(quantityCallback(face.interiorIndex()));
|
||||
|
||||
const auto& boundaryFacePos = face.integrationPos();
|
||||
const auto& interiorPos = stencil.subControlVolume(face.interiorIndex()).center();
|
||||
|
||||
Scalar distSquared = 0;
|
||||
for (unsigned dimIdx = 0; dimIdx < dimWorld; ++dimIdx) {
|
||||
Scalar tmp = boundaryFacePos[dimIdx] - interiorPos[dimIdx];
|
||||
distSquared += tmp*tmp;
|
||||
}
|
||||
|
||||
// divide the gradient by the squared distance between the center of the
|
||||
// sub-control and the center of the boundary face: the gradient is the
|
||||
// normalized directional vector between the two centers times the ratio of the
|
||||
// difference of the values and their distance, i.e., d/abs(d) * deltay / abs(d)
|
||||
// = d*deltay / abs(d)^2.
|
||||
for (unsigned dimIdx = 0; dimIdx < dimWorld; ++dimIdx) {
|
||||
Scalar tmp = boundaryFacePos[dimIdx] - interiorPos[dimIdx];
|
||||
quantityGrad[dimIdx] = deltay*(tmp/distSquared);
|
||||
}
|
||||
}
|
||||
|
||||
private:
|
||||
void computeDistances_(Scalar& interiorDistance,
|
||||
Scalar& exteriorDistance,
|
||||
const ElementContext& elemCtx,
|
||||
unsigned fapIdx) const
|
||||
{
|
||||
const auto& stencil = elemCtx.stencil(/*timeIdx=*/0);
|
||||
const auto& face = stencil.interiorFace(fapIdx);
|
||||
|
||||
// calculate the distances of the position of the interior and of the exterior
|
||||
// finite volume to the position of the integration point.
|
||||
const auto& normal = face.normal();
|
||||
auto i = face.interiorIndex();
|
||||
auto j = face.exteriorIndex();
|
||||
const auto& interiorPos = stencil.subControlVolume(i).globalPos();
|
||||
const auto& exteriorPos = stencil.subControlVolume(j).globalPos();
|
||||
const auto& integrationPos = face.integrationPos();
|
||||
|
||||
interiorDistance = 0.0;
|
||||
exteriorDistance = 0.0;
|
||||
for (unsigned dimIdx = 0; dimIdx < dimWorld; ++dimIdx) {
|
||||
interiorDistance +=
|
||||
(interiorPos[dimIdx] - integrationPos[dimIdx])
|
||||
* normal[dimIdx];
|
||||
|
||||
exteriorDistance +=
|
||||
(exteriorPos[dimIdx] - integrationPos[dimIdx])
|
||||
* normal[dimIdx];
|
||||
}
|
||||
|
||||
interiorDistance = std::sqrt(std::abs(interiorDistance));
|
||||
exteriorDistance = std::sqrt(std::abs(exteriorDistance));
|
||||
}
|
||||
};
|
||||
} // namespace Opm
|
||||
|
||||
#endif
|
103
opm/models/discretization/common/fvbaseintensivequantities.hh
Normal file
103
opm/models/discretization/common/fvbaseintensivequantities.hh
Normal file
@ -0,0 +1,103 @@
|
||||
// -*- mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*-
|
||||
// vi: set et ts=4 sw=4 sts=4:
|
||||
/*
|
||||
This file is part of the Open Porous Media project (OPM).
|
||||
|
||||
OPM 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.
|
||||
|
||||
OPM is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
GNU General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU General Public License
|
||||
along with OPM. If not, see <http://www.gnu.org/licenses/>.
|
||||
|
||||
Consult the COPYING file in the top-level source directory of this
|
||||
module for the precise wording of the license and the list of
|
||||
copyright holders.
|
||||
*/
|
||||
/*!
|
||||
* \file
|
||||
*
|
||||
* \copydoc Opm::FvBaseIntensiveQuantities
|
||||
*/
|
||||
#ifndef EWOMS_FV_BASE_INTENSIVE_QUANTITIES_HH
|
||||
#define EWOMS_FV_BASE_INTENSIVE_QUANTITIES_HH
|
||||
|
||||
#include "fvbaseproperties.hh"
|
||||
|
||||
#include <opm/material/common/Valgrind.hpp>
|
||||
#include <opm/material/common/Unused.hpp>
|
||||
|
||||
namespace Opm {
|
||||
|
||||
/*!
|
||||
* \ingroup FiniteVolumeDiscretizations
|
||||
*
|
||||
* \brief Base class for the model specific class which provides access to all intensive
|
||||
* (i.e., volume averaged) quantities.
|
||||
*/
|
||||
template <class TypeTag>
|
||||
class FvBaseIntensiveQuantities
|
||||
{
|
||||
typedef typename GET_PROP_TYPE(TypeTag, IntensiveQuantities) Implementation;
|
||||
typedef typename GET_PROP_TYPE(TypeTag, Scalar) Scalar;
|
||||
typedef typename GET_PROP_TYPE(TypeTag, ElementContext) ElementContext;
|
||||
|
||||
public:
|
||||
// default constructor
|
||||
FvBaseIntensiveQuantities()
|
||||
{ }
|
||||
|
||||
// copy constructor
|
||||
FvBaseIntensiveQuantities(const FvBaseIntensiveQuantities& v) = default;
|
||||
|
||||
/*!
|
||||
* \brief Register all run-time parameters for the intensive quantities.
|
||||
*/
|
||||
static void registerParameters()
|
||||
{ }
|
||||
|
||||
/*!
|
||||
* \brief Update all quantities for a given control volume.
|
||||
*/
|
||||
void update(const ElementContext& elemCtx,
|
||||
unsigned dofIdx,
|
||||
unsigned timeIdx)
|
||||
{ extrusionFactor_ = elemCtx.problem().extrusionFactor(elemCtx, dofIdx, timeIdx); }
|
||||
|
||||
/*!
|
||||
* \brief Return how much a given sub-control volume is extruded.
|
||||
*
|
||||
* This means the factor by which a lower-dimensional (1D or 2D)
|
||||
* entity needs to be expanded to get a full dimensional cell. The
|
||||
* default is 1.0 which means that 1D problems are actually
|
||||
* thought as pipes with a cross section of 1 m^2 and 2D problems
|
||||
* are assumed to extend 1 m to the back.
|
||||
*/
|
||||
Scalar extrusionFactor() const
|
||||
{ return extrusionFactor_; }
|
||||
|
||||
/*!
|
||||
* \brief If running in valgrind this makes sure that all
|
||||
* quantities in the intensive quantities are defined.
|
||||
*/
|
||||
void checkDefined() const
|
||||
{ }
|
||||
|
||||
private:
|
||||
const Implementation& asImp_() const
|
||||
{ return *static_cast<const Implementation*>(this); }
|
||||
Implementation& asImp_()
|
||||
{ return *static_cast<Implementation*>(this); }
|
||||
|
||||
Scalar extrusionFactor_;
|
||||
};
|
||||
|
||||
} // namespace Opm
|
||||
|
||||
#endif
|
601
opm/models/discretization/common/fvbaselinearizer.hh
Normal file
601
opm/models/discretization/common/fvbaselinearizer.hh
Normal file
@ -0,0 +1,601 @@
|
||||
// -*- mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*-
|
||||
// vi: set et ts=4 sw=4 sts=4:
|
||||
/*
|
||||
This file is part of the Open Porous Media project (OPM).
|
||||
|
||||
OPM 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.
|
||||
|
||||
OPM is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
GNU General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU General Public License
|
||||
along with OPM. If not, see <http://www.gnu.org/licenses/>.
|
||||
|
||||
Consult the COPYING file in the top-level source directory of this
|
||||
module for the precise wording of the license and the list of
|
||||
copyright holders.
|
||||
*/
|
||||
/*!
|
||||
* \file
|
||||
*
|
||||
* \copydoc Opm::FvBaseLinearizer
|
||||
*/
|
||||
#ifndef EWOMS_FV_BASE_LINEARIZER_HH
|
||||
#define EWOMS_FV_BASE_LINEARIZER_HH
|
||||
|
||||
#include "fvbaseproperties.hh"
|
||||
|
||||
#include <opm/models/parallel/gridcommhandles.hh>
|
||||
#include <opm/models/parallel/threadmanager.hh>
|
||||
#include <opm/models/parallel/threadedentityiterator.hh>
|
||||
#include <opm/models/discretization/common/baseauxiliarymodule.hh>
|
||||
|
||||
#include <opm/material/common/Exceptions.hpp>
|
||||
|
||||
#include <dune/common/version.hh>
|
||||
#include <dune/common/fvector.hh>
|
||||
#include <dune/common/fmatrix.hh>
|
||||
|
||||
#include <type_traits>
|
||||
#include <iostream>
|
||||
#include <vector>
|
||||
#include <thread>
|
||||
#include <set>
|
||||
#include <exception> // current_exception, rethrow_exception
|
||||
#include <mutex>
|
||||
|
||||
namespace Opm {
|
||||
// forward declarations
|
||||
template<class TypeTag>
|
||||
class EcfvDiscretization;
|
||||
|
||||
/*!
|
||||
* \ingroup FiniteVolumeDiscretizations
|
||||
*
|
||||
* \brief The common code for the linearizers of non-linear systems of equations
|
||||
*
|
||||
* This class assumes that these system of equations to be linearized are stemming from
|
||||
* models that use an finite volume scheme for spatial discretization and an Euler
|
||||
* scheme for time discretization.
|
||||
*/
|
||||
template<class TypeTag>
|
||||
class FvBaseLinearizer
|
||||
{
|
||||
//! \cond SKIP_THIS
|
||||
typedef typename GET_PROP_TYPE(TypeTag, Model) Model;
|
||||
typedef typename GET_PROP_TYPE(TypeTag, Discretization) Discretization;
|
||||
typedef typename GET_PROP_TYPE(TypeTag, Problem) Problem;
|
||||
typedef typename GET_PROP_TYPE(TypeTag, Simulator) Simulator;
|
||||
typedef typename GET_PROP_TYPE(TypeTag, GridView) GridView;
|
||||
typedef typename GET_PROP_TYPE(TypeTag, Scalar) Scalar;
|
||||
typedef typename GET_PROP_TYPE(TypeTag, Evaluation) Evaluation;
|
||||
typedef typename GET_PROP_TYPE(TypeTag, DofMapper) DofMapper;
|
||||
typedef typename GET_PROP_TYPE(TypeTag, ElementMapper) ElementMapper;
|
||||
typedef typename GET_PROP_TYPE(TypeTag, ElementContext) ElementContext;
|
||||
|
||||
typedef typename GET_PROP_TYPE(TypeTag, SolutionVector) SolutionVector;
|
||||
typedef typename GET_PROP_TYPE(TypeTag, GlobalEqVector) GlobalEqVector;
|
||||
typedef typename GET_PROP_TYPE(TypeTag, SparseMatrixAdapter) SparseMatrixAdapter;
|
||||
typedef typename GET_PROP_TYPE(TypeTag, EqVector) EqVector;
|
||||
typedef typename GET_PROP_TYPE(TypeTag, Constraints) Constraints;
|
||||
typedef typename GET_PROP_TYPE(TypeTag, Stencil) Stencil;
|
||||
typedef typename GET_PROP_TYPE(TypeTag, ThreadManager) ThreadManager;
|
||||
|
||||
typedef typename GET_PROP_TYPE(TypeTag, GridCommHandleFactory) GridCommHandleFactory;
|
||||
|
||||
typedef Opm::MathToolbox<Evaluation> Toolbox;
|
||||
|
||||
typedef typename GridView::template Codim<0>::Entity Element;
|
||||
typedef typename GridView::template Codim<0>::Iterator ElementIterator;
|
||||
|
||||
typedef GlobalEqVector Vector;
|
||||
|
||||
typedef typename SparseMatrixAdapter::IstlMatrix IstlMatrix;
|
||||
|
||||
enum { numEq = GET_PROP_VALUE(TypeTag, NumEq) };
|
||||
enum { historySize = GET_PROP_VALUE(TypeTag, TimeDiscHistorySize) };
|
||||
|
||||
typedef typename SparseMatrixAdapter::MatrixBlock MatrixBlock;
|
||||
typedef Dune::FieldVector<Scalar, numEq> VectorBlock;
|
||||
|
||||
static const bool linearizeNonLocalElements = GET_PROP_VALUE(TypeTag, LinearizeNonLocalElements);
|
||||
|
||||
// copying the linearizer is not a good idea
|
||||
FvBaseLinearizer(const FvBaseLinearizer&);
|
||||
//! \endcond
|
||||
|
||||
public:
|
||||
FvBaseLinearizer()
|
||||
: jacobian_()
|
||||
{
|
||||
simulatorPtr_ = 0;
|
||||
}
|
||||
|
||||
~FvBaseLinearizer()
|
||||
{
|
||||
auto it = elementCtx_.begin();
|
||||
const auto& endIt = elementCtx_.end();
|
||||
for (; it != endIt; ++it)
|
||||
delete *it;
|
||||
}
|
||||
|
||||
/*!
|
||||
* \brief Register all run-time parameters for the Jacobian linearizer.
|
||||
*/
|
||||
static void registerParameters()
|
||||
{ }
|
||||
|
||||
/*!
|
||||
* \brief Initialize the linearizer.
|
||||
*
|
||||
* At this point we can assume that all objects in the simulator
|
||||
* have been allocated. We cannot assume that they are fully
|
||||
* initialized, though.
|
||||
*
|
||||
* \copydetails Doxygen::simulatorParam
|
||||
*/
|
||||
void init(Simulator& simulator)
|
||||
{
|
||||
simulatorPtr_ = &simulator;
|
||||
eraseMatrix();
|
||||
}
|
||||
|
||||
/*!
|
||||
* \brief Causes the Jacobian matrix to be recreated from scratch before the next
|
||||
* iteration.
|
||||
*
|
||||
* This method is usally called if the sparsity pattern has changed for some
|
||||
* reason. (e.g. by modifications of the grid or changes of the auxiliary equations.)
|
||||
*/
|
||||
void eraseMatrix()
|
||||
{
|
||||
jacobian_.reset();
|
||||
}
|
||||
|
||||
/*!
|
||||
* \brief Linearize the full system of non-linear equations.
|
||||
*
|
||||
* This means the spatial domain plus all auxiliary equations.
|
||||
*/
|
||||
void linearize()
|
||||
{
|
||||
linearizeDomain();
|
||||
linearizeAuxiliaryEquations();
|
||||
}
|
||||
|
||||
/*!
|
||||
* \brief Linearize the part of the non-linear system of equations that is associated
|
||||
* with the spatial domain.
|
||||
*
|
||||
* That means that the global Jacobian of the residual is assembled and the residual
|
||||
* is evaluated for the current solution.
|
||||
*
|
||||
* The current state of affairs (esp. the previous and the current solutions) is
|
||||
* represented by the model object.
|
||||
*/
|
||||
void linearizeDomain()
|
||||
{
|
||||
// we defer the initialization of the Jacobian matrix until here because the
|
||||
// auxiliary modules usually assume the problem, model and grid to be fully
|
||||
// initialized...
|
||||
if (!jacobian_)
|
||||
initFirstIteration_();
|
||||
|
||||
int succeeded;
|
||||
try {
|
||||
linearize_();
|
||||
succeeded = 1;
|
||||
}
|
||||
#if ! DUNE_VERSION_NEWER(DUNE_COMMON, 2,5)
|
||||
catch (const Dune::Exception& e)
|
||||
{
|
||||
std::cout << "rank " << simulator_().gridView().comm().rank()
|
||||
<< " caught an exception while linearizing:" << e.what()
|
||||
<< "\n" << std::flush;
|
||||
succeeded = 0;
|
||||
}
|
||||
#endif
|
||||
catch (const std::exception& e)
|
||||
{
|
||||
std::cout << "rank " << simulator_().gridView().comm().rank()
|
||||
<< " caught an exception while linearizing:" << e.what()
|
||||
<< "\n" << std::flush;
|
||||
succeeded = 0;
|
||||
}
|
||||
catch (...)
|
||||
{
|
||||
std::cout << "rank " << simulator_().gridView().comm().rank()
|
||||
<< " caught an exception while linearizing"
|
||||
<< "\n" << std::flush;
|
||||
succeeded = 0;
|
||||
}
|
||||
succeeded = gridView_().comm().min(succeeded);
|
||||
|
||||
if (!succeeded)
|
||||
throw Opm::NumericalIssue("A process did not succeed in linearizing the system");
|
||||
}
|
||||
|
||||
void finalize()
|
||||
{ jacobian_->finalize(); }
|
||||
|
||||
/*!
|
||||
* \brief Linearize the part of the non-linear system of equations that is associated
|
||||
* with the spatial domain.
|
||||
*/
|
||||
void linearizeAuxiliaryEquations()
|
||||
{
|
||||
// flush possible local caches into matrix structure
|
||||
jacobian_->commit();
|
||||
|
||||
auto& model = model_();
|
||||
const auto& comm = simulator_().gridView().comm();
|
||||
for (unsigned auxModIdx = 0; auxModIdx < model.numAuxiliaryModules(); ++auxModIdx) {
|
||||
bool succeeded = true;
|
||||
try {
|
||||
model.auxiliaryModule(auxModIdx)->linearize(*jacobian_, residual_);
|
||||
}
|
||||
catch (const std::exception& e) {
|
||||
succeeded = false;
|
||||
|
||||
std::cout << "rank " << simulator_().gridView().comm().rank()
|
||||
<< " caught an exception while linearizing:" << e.what()
|
||||
<< "\n" << std::flush;
|
||||
}
|
||||
#if ! DUNE_VERSION_NEWER(DUNE_COMMON, 2,5)
|
||||
catch (const Dune::Exception& e)
|
||||
{
|
||||
succeeded = false;
|
||||
|
||||
std::cout << "rank " << simulator_().gridView().comm().rank()
|
||||
<< " caught an exception while linearizing:" << e.what()
|
||||
<< "\n" << std::flush;
|
||||
}
|
||||
#endif
|
||||
|
||||
succeeded = comm.min(succeeded);
|
||||
|
||||
if (!succeeded)
|
||||
throw Opm::NumericalIssue("linearization of an auxilary equation failed");
|
||||
}
|
||||
}
|
||||
|
||||
/*!
|
||||
* \brief Return constant reference to global Jacobian matrix backend.
|
||||
*/
|
||||
const SparseMatrixAdapter& jacobian() const
|
||||
{ return *jacobian_; }
|
||||
|
||||
SparseMatrixAdapter& jacobian()
|
||||
{ return *jacobian_; }
|
||||
|
||||
/*!
|
||||
* \brief Return constant reference to global residual vector.
|
||||
*/
|
||||
const GlobalEqVector& residual() const
|
||||
{ return residual_; }
|
||||
|
||||
GlobalEqVector& residual()
|
||||
{ return residual_; }
|
||||
|
||||
/*!
|
||||
* \brief Returns the map of constraint degrees of freedom.
|
||||
*
|
||||
* (This object is only non-empty if the EnableConstraints property is true.)
|
||||
*/
|
||||
const std::map<unsigned, Constraints>& constraintsMap() const
|
||||
{ return constraintsMap_; }
|
||||
|
||||
private:
|
||||
Simulator& simulator_()
|
||||
{ return *simulatorPtr_; }
|
||||
const Simulator& simulator_() const
|
||||
{ return *simulatorPtr_; }
|
||||
|
||||
Problem& problem_()
|
||||
{ return simulator_().problem(); }
|
||||
const Problem& problem_() const
|
||||
{ return simulator_().problem(); }
|
||||
|
||||
Model& model_()
|
||||
{ return simulator_().model(); }
|
||||
const Model& model_() const
|
||||
{ return simulator_().model(); }
|
||||
|
||||
const GridView& gridView_() const
|
||||
{ return problem_().gridView(); }
|
||||
|
||||
const ElementMapper& elementMapper_() const
|
||||
{ return model_().elementMapper(); }
|
||||
|
||||
const DofMapper& dofMapper_() const
|
||||
{ return model_().dofMapper(); }
|
||||
|
||||
void initFirstIteration_()
|
||||
{
|
||||
// initialize the BCRS matrix for the Jacobian of the residual function
|
||||
createMatrix_();
|
||||
|
||||
// initialize the Jacobian matrix and the vector for the residual function
|
||||
residual_.resize(model_().numTotalDof());
|
||||
resetSystem_();
|
||||
|
||||
// create the per-thread context objects
|
||||
elementCtx_.resize(ThreadManager::maxThreads());
|
||||
for (unsigned threadId = 0; threadId != ThreadManager::maxThreads(); ++ threadId)
|
||||
elementCtx_[threadId] = new ElementContext(simulator_());
|
||||
}
|
||||
|
||||
// Construct the BCRS matrix for the Jacobian of the residual function
|
||||
void createMatrix_()
|
||||
{
|
||||
const auto& model = model_();
|
||||
Stencil stencil(gridView_(), model_().dofMapper());
|
||||
|
||||
// for the main model, find out the global indices of the neighboring degrees of
|
||||
// freedom of each primary degree of freedom
|
||||
typedef std::set< unsigned > NeighborSet;
|
||||
std::vector<NeighborSet> sparsityPattern(model.numTotalDof());
|
||||
|
||||
ElementIterator elemIt = gridView_().template begin<0>();
|
||||
const ElementIterator elemEndIt = gridView_().template end<0>();
|
||||
for (; elemIt != elemEndIt; ++elemIt) {
|
||||
const Element& elem = *elemIt;
|
||||
stencil.update(elem);
|
||||
|
||||
for (unsigned primaryDofIdx = 0; primaryDofIdx < stencil.numPrimaryDof(); ++primaryDofIdx) {
|
||||
unsigned myIdx = stencil.globalSpaceIndex(primaryDofIdx);
|
||||
|
||||
for (unsigned dofIdx = 0; dofIdx < stencil.numDof(); ++dofIdx) {
|
||||
unsigned neighborIdx = stencil.globalSpaceIndex(dofIdx);
|
||||
sparsityPattern[myIdx].insert(neighborIdx);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// add the additional neighbors and degrees of freedom caused by the auxiliary
|
||||
// equations
|
||||
size_t numAuxMod = model.numAuxiliaryModules();
|
||||
for (unsigned auxModIdx = 0; auxModIdx < numAuxMod; ++auxModIdx)
|
||||
model.auxiliaryModule(auxModIdx)->addNeighbors(sparsityPattern);
|
||||
|
||||
// allocate raw matrix
|
||||
jacobian_.reset(new SparseMatrixAdapter(simulator_()));
|
||||
|
||||
// create matrix structure based on sparsity pattern
|
||||
jacobian_->reserve(sparsityPattern);
|
||||
}
|
||||
|
||||
// reset the global linear system of equations.
|
||||
void resetSystem_()
|
||||
{
|
||||
residual_ = 0.0;
|
||||
// zero all matrix entries
|
||||
jacobian_->clear();
|
||||
}
|
||||
|
||||
// query the problem for all constraint degrees of freedom. note that this method is
|
||||
// quite involved and is thus relatively slow.
|
||||
void updateConstraintsMap_()
|
||||
{
|
||||
if (!enableConstraints_())
|
||||
// constraints are not explictly enabled, so we don't need to consider them!
|
||||
return;
|
||||
|
||||
constraintsMap_.clear();
|
||||
|
||||
// loop over all elements...
|
||||
ThreadedEntityIterator<GridView, /*codim=*/0> threadedElemIt(gridView_());
|
||||
#ifdef _OPENMP
|
||||
#pragma omp parallel
|
||||
#endif
|
||||
{
|
||||
unsigned threadId = ThreadManager::threadId();
|
||||
ElementIterator elemIt = threadedElemIt.beginParallel();
|
||||
for (; !threadedElemIt.isFinished(elemIt); elemIt = threadedElemIt.increment()) {
|
||||
// create an element context (the solution-based quantities are not
|
||||
// available here!)
|
||||
const Element& elem = *elemIt;
|
||||
ElementContext& elemCtx = *elementCtx_[threadId];
|
||||
elemCtx.updateStencil(elem);
|
||||
|
||||
// check if the problem wants to constrain any degree of the current
|
||||
// element's freedom. if yes, add the constraint to the map.
|
||||
for (unsigned primaryDofIdx = 0;
|
||||
primaryDofIdx < elemCtx.numPrimaryDof(/*timeIdx=*/0);
|
||||
++ primaryDofIdx)
|
||||
{
|
||||
Constraints constraints;
|
||||
elemCtx.problem().constraints(constraints,
|
||||
elemCtx,
|
||||
primaryDofIdx,
|
||||
/*timeIdx=*/0);
|
||||
if (constraints.isActive()) {
|
||||
unsigned globI = elemCtx.globalSpaceIndex(primaryDofIdx, /*timeIdx=*/0);
|
||||
constraintsMap_[globI] = constraints;
|
||||
continue;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// linearize the whole system
|
||||
void linearize_()
|
||||
{
|
||||
resetSystem_();
|
||||
|
||||
// before the first iteration of each time step, we need to update the
|
||||
// constraints. (i.e., we assume that constraints can be time dependent, but they
|
||||
// can't depend on the solution.)
|
||||
if (model_().newtonMethod().numIterations() == 0)
|
||||
updateConstraintsMap_();
|
||||
|
||||
applyConstraintsToSolution_();
|
||||
|
||||
// to avoid a race condition if two threads handle an exception at the same time,
|
||||
// we use an explicit lock to control access to the exception storage object
|
||||
// amongst thread-local handlers
|
||||
std::mutex exceptionLock;
|
||||
|
||||
// storage to any exception that needs to be bridged out of the
|
||||
// parallel block below. initialized to null to indicate no exception
|
||||
std::exception_ptr exceptionPtr = nullptr;
|
||||
|
||||
// relinearize the elements...
|
||||
ThreadedEntityIterator<GridView, /*codim=*/0> threadedElemIt(gridView_());
|
||||
#ifdef _OPENMP
|
||||
#pragma omp parallel
|
||||
#endif
|
||||
{
|
||||
ElementIterator elemIt = threadedElemIt.beginParallel();
|
||||
ElementIterator nextElemIt = elemIt;
|
||||
try {
|
||||
for (; !threadedElemIt.isFinished(elemIt); elemIt = nextElemIt) {
|
||||
// give the model and the problem a chance to prefetch the data required
|
||||
// to linearize the next element, but only if we need to consider it
|
||||
nextElemIt = threadedElemIt.increment();
|
||||
if (!threadedElemIt.isFinished(nextElemIt)) {
|
||||
const auto& nextElem = *nextElemIt;
|
||||
if (linearizeNonLocalElements
|
||||
|| nextElem.partitionType() == Dune::InteriorEntity)
|
||||
{
|
||||
model_().prefetch(nextElem);
|
||||
problem_().prefetch(nextElem);
|
||||
}
|
||||
}
|
||||
|
||||
const Element& elem = *elemIt;
|
||||
if (!linearizeNonLocalElements && elem.partitionType() != Dune::InteriorEntity)
|
||||
continue;
|
||||
|
||||
linearizeElement_(elem);
|
||||
}
|
||||
}
|
||||
// If an exception occurs in the parallel block, it won't escape the
|
||||
// block; terminate() is called instead of a handler outside! hence, we
|
||||
// tuck any exceptions that occur away in the pointer. If an exception
|
||||
// occurs in more than one thread at the same time, we must pick one of
|
||||
// them to be rethrown as we cannot have two active exceptions at the
|
||||
// same time. This solution essentially picks one at random. This will
|
||||
// only be a problem if two different kinds of exceptions are thrown, for
|
||||
// instance if one thread experiences a (recoverable) numerical issue
|
||||
// while another is out of memory.
|
||||
catch(...) {
|
||||
std::lock_guard<std::mutex> take(exceptionLock);
|
||||
exceptionPtr = std::current_exception();
|
||||
threadedElemIt.setFinished();
|
||||
}
|
||||
} // parallel block
|
||||
|
||||
// after reduction from the parallel block, exceptionPtr will point to
|
||||
// a valid exception if one occurred in one of the threads; rethrow
|
||||
// it here to let the outer handler take care of it properly
|
||||
if(exceptionPtr) {
|
||||
std::rethrow_exception(exceptionPtr);
|
||||
}
|
||||
|
||||
applyConstraintsToLinearization_();
|
||||
}
|
||||
|
||||
// linearize an element in the interior of the process' grid partition
|
||||
void linearizeElement_(const Element& elem)
|
||||
{
|
||||
unsigned threadId = ThreadManager::threadId();
|
||||
|
||||
ElementContext *elementCtx = elementCtx_[threadId];
|
||||
auto& localLinearizer = model_().localLinearizer(threadId);
|
||||
|
||||
// the actual work of linearization is done by the local linearizer class
|
||||
localLinearizer.linearize(*elementCtx, elem);
|
||||
|
||||
// update the right hand side and the Jacobian matrix
|
||||
if (GET_PROP_VALUE(TypeTag, UseLinearizationLock))
|
||||
globalMatrixMutex_.lock();
|
||||
|
||||
size_t numPrimaryDof = elementCtx->numPrimaryDof(/*timeIdx=*/0);
|
||||
for (unsigned primaryDofIdx = 0; primaryDofIdx < numPrimaryDof; ++ primaryDofIdx) {
|
||||
unsigned globI = elementCtx->globalSpaceIndex(/*spaceIdx=*/primaryDofIdx, /*timeIdx=*/0);
|
||||
|
||||
// update the right hand side
|
||||
residual_[globI] += localLinearizer.residual(primaryDofIdx);
|
||||
|
||||
// update the global Jacobian matrix
|
||||
for (unsigned dofIdx = 0; dofIdx < elementCtx->numDof(/*timeIdx=*/0); ++ dofIdx) {
|
||||
unsigned globJ = elementCtx->globalSpaceIndex(/*spaceIdx=*/dofIdx, /*timeIdx=*/0);
|
||||
|
||||
jacobian_->addToBlock(globJ, globI, localLinearizer.jacobian(dofIdx, primaryDofIdx));
|
||||
}
|
||||
}
|
||||
|
||||
if (GET_PROP_VALUE(TypeTag, UseLinearizationLock))
|
||||
globalMatrixMutex_.unlock();
|
||||
}
|
||||
|
||||
// apply the constraints to the solution. (i.e., the solution of constraint degrees
|
||||
// of freedom is set to the value of the constraint.)
|
||||
void applyConstraintsToSolution_()
|
||||
{
|
||||
if (!enableConstraints_())
|
||||
return;
|
||||
|
||||
// TODO: assuming a history size of 2 only works for Euler time discretizations!
|
||||
auto& sol = model_().solution(/*timeIdx=*/0);
|
||||
auto& oldSol = model_().solution(/*timeIdx=*/1);
|
||||
|
||||
auto it = constraintsMap_.begin();
|
||||
const auto& endIt = constraintsMap_.end();
|
||||
for (; it != endIt; ++it) {
|
||||
sol[it->first] = it->second;
|
||||
oldSol[it->first] = it->second;
|
||||
}
|
||||
}
|
||||
|
||||
// apply the constraints to the linearization. (i.e., for constrain degrees of
|
||||
// freedom the Jacobian matrix maps to identity and the residual is zero)
|
||||
void applyConstraintsToLinearization_()
|
||||
{
|
||||
if (!enableConstraints_())
|
||||
return;
|
||||
|
||||
auto it = constraintsMap_.begin();
|
||||
const auto& endIt = constraintsMap_.end();
|
||||
for (; it != endIt; ++it) {
|
||||
unsigned constraintDofIdx = it->first;
|
||||
|
||||
// reset the column of the Jacobian matrix
|
||||
// put an identity matrix on the main diagonal of the Jacobian
|
||||
jacobian_->clearRow(constraintDofIdx, Scalar(1.0));
|
||||
|
||||
// make the right-hand side of constraint DOFs zero
|
||||
residual_[constraintDofIdx] = 0.0;
|
||||
}
|
||||
}
|
||||
|
||||
static bool enableConstraints_()
|
||||
{ return GET_PROP_VALUE(TypeTag, EnableConstraints); }
|
||||
|
||||
Simulator *simulatorPtr_;
|
||||
std::vector<ElementContext*> elementCtx_;
|
||||
|
||||
// The constraint equations (only non-empty if the
|
||||
// EnableConstraints property is true)
|
||||
std::map<unsigned, Constraints> constraintsMap_;
|
||||
|
||||
// the jacobian matrix
|
||||
std::unique_ptr<SparseMatrixAdapter> jacobian_;
|
||||
|
||||
// the right-hand side
|
||||
GlobalEqVector residual_;
|
||||
|
||||
|
||||
std::mutex globalMatrixMutex_;
|
||||
};
|
||||
|
||||
} // namespace Opm
|
||||
|
||||
#endif
|
638
opm/models/discretization/common/fvbaselocalresidual.hh
Normal file
638
opm/models/discretization/common/fvbaselocalresidual.hh
Normal file
@ -0,0 +1,638 @@
|
||||
// -*- mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*-
|
||||
// vi: set et ts=4 sw=4 sts=4:
|
||||
/*
|
||||
This file is part of the Open Porous Media project (OPM).
|
||||
|
||||
OPM 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.
|
||||
|
||||
OPM is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
GNU General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU General Public License
|
||||
along with OPM. If not, see <http://www.gnu.org/licenses/>.
|
||||
|
||||
Consult the COPYING file in the top-level source directory of this
|
||||
module for the precise wording of the license and the list of
|
||||
copyright holders.
|
||||
*/
|
||||
/*!
|
||||
* \file
|
||||
*
|
||||
* \copydoc Opm::FvBaseLocalResidual
|
||||
*/
|
||||
#ifndef EWOMS_FV_BASE_LOCAL_RESIDUAL_HH
|
||||
#define EWOMS_FV_BASE_LOCAL_RESIDUAL_HH
|
||||
|
||||
#include "fvbaseproperties.hh"
|
||||
|
||||
#include <opm/models/utils/parametersystem.hh>
|
||||
#include <opm/models/utils/alignedallocator.hh>
|
||||
|
||||
#include <opm/material/common/Valgrind.hpp>
|
||||
#include <opm/material/common/Unused.hpp>
|
||||
#include <opm/material/common/Exceptions.hpp>
|
||||
|
||||
#include <dune/istl/bvector.hh>
|
||||
#include <dune/grid/common/geometry.hh>
|
||||
|
||||
#include <dune/common/fvector.hh>
|
||||
|
||||
#include <dune/common/classname.hh>
|
||||
|
||||
#include <cmath>
|
||||
|
||||
namespace Opm {
|
||||
/*!
|
||||
* \ingroup FiniteVolumeDiscretizations
|
||||
*
|
||||
* \brief Element-wise caculation of the residual matrix for models based on a finite
|
||||
* volume spatial discretization.
|
||||
*
|
||||
* \copydetails Doxygen::typeTagTParam
|
||||
*/
|
||||
template<class TypeTag>
|
||||
class FvBaseLocalResidual
|
||||
{
|
||||
private:
|
||||
typedef typename GET_PROP_TYPE(TypeTag, LocalResidual) Implementation;
|
||||
|
||||
typedef typename GET_PROP_TYPE(TypeTag, GridView) GridView;
|
||||
typedef typename GridView::template Codim<0>::Entity Element;
|
||||
|
||||
typedef typename GET_PROP_TYPE(TypeTag, Problem) Problem;
|
||||
typedef typename GET_PROP_TYPE(TypeTag, Scalar) Scalar;
|
||||
typedef typename GET_PROP_TYPE(TypeTag, Evaluation) Evaluation;
|
||||
typedef typename GET_PROP_TYPE(TypeTag, BoundaryRateVector) BoundaryRateVector;
|
||||
typedef typename GET_PROP_TYPE(TypeTag, RateVector) RateVector;
|
||||
typedef typename GET_PROP_TYPE(TypeTag, EqVector) EqVector;
|
||||
typedef typename GET_PROP_TYPE(TypeTag, PrimaryVariables) PrimaryVariables;
|
||||
typedef typename GET_PROP_TYPE(TypeTag, ElementContext) ElementContext;
|
||||
typedef typename GET_PROP_TYPE(TypeTag, BoundaryContext) BoundaryContext;
|
||||
|
||||
static constexpr bool useVolumetricResidual = GET_PROP_VALUE(TypeTag, UseVolumetricResidual);
|
||||
|
||||
enum { numEq = GET_PROP_VALUE(TypeTag, NumEq) };
|
||||
enum { extensiveStorageTerm = GET_PROP_VALUE(TypeTag, ExtensiveStorageTerm) };
|
||||
|
||||
typedef Opm::MathToolbox<Evaluation> Toolbox;
|
||||
typedef Dune::FieldVector<Evaluation, numEq> EvalVector;
|
||||
|
||||
// copying the local residual class is not a good idea
|
||||
FvBaseLocalResidual(const FvBaseLocalResidual& )
|
||||
{}
|
||||
|
||||
public:
|
||||
typedef Dune::BlockVector<EvalVector, Opm::aligned_allocator<EvalVector, alignof(EvalVector)> > LocalEvalBlockVector;
|
||||
|
||||
FvBaseLocalResidual()
|
||||
{ }
|
||||
|
||||
~FvBaseLocalResidual()
|
||||
{ }
|
||||
|
||||
/*!
|
||||
* \brief Register all run-time parameters for the local residual.
|
||||
*/
|
||||
static void registerParameters()
|
||||
{ }
|
||||
|
||||
/*!
|
||||
* \brief Return the result of the eval() call using internal
|
||||
* storage.
|
||||
*/
|
||||
const LocalEvalBlockVector& residual() const
|
||||
{ return internalResidual_; }
|
||||
|
||||
/*!
|
||||
* \brief Return the result of the eval() call using internal
|
||||
* storage.
|
||||
*
|
||||
* \copydetails Doxygen::ecfvScvIdxParam
|
||||
*/
|
||||
const EvalVector& residual(unsigned dofIdx) const
|
||||
{ return internalResidual_[dofIdx]; }
|
||||
|
||||
/*!
|
||||
* \brief Compute the local residual, i.e. the deviation of the
|
||||
* conservation equations from zero and store the results
|
||||
* internally.
|
||||
*
|
||||
* The results can be requested afterwards using the residual() method.
|
||||
*
|
||||
* \copydetails Doxygen::problemParam
|
||||
* \copydetails Doxygen::elementParam
|
||||
*/
|
||||
void eval(const Problem& problem, const Element& element)
|
||||
{
|
||||
ElementContext elemCtx(problem);
|
||||
elemCtx.updateAll(element);
|
||||
eval(elemCtx);
|
||||
}
|
||||
|
||||
/*!
|
||||
* \brief Compute the local residual, i.e. the deviation of the
|
||||
* conservation equations from zero and store the results
|
||||
* internally.
|
||||
*
|
||||
* The results can be requested afterwards using the residual() method.
|
||||
*
|
||||
* \copydetails Doxygen::ecfvElemCtxParam
|
||||
*/
|
||||
void eval(ElementContext& elemCtx)
|
||||
{
|
||||
size_t numDof = elemCtx.numDof(/*timeIdx=*/0);
|
||||
internalResidual_.resize(numDof);
|
||||
asImp_().eval(internalResidual_, elemCtx);
|
||||
}
|
||||
|
||||
/*!
|
||||
* \brief Compute the local residual, i.e. the deviation of the
|
||||
* conservation equations from zero.
|
||||
*
|
||||
* \copydetails Doxygen::residualParam
|
||||
* \copydetails Doxygen::ecfvElemCtxParam
|
||||
*/
|
||||
void eval(LocalEvalBlockVector& residual,
|
||||
ElementContext& elemCtx) const
|
||||
{
|
||||
assert(residual.size() == elemCtx.numDof(/*timeIdx=*/0));
|
||||
|
||||
residual = 0.0;
|
||||
|
||||
// evaluate the flux terms
|
||||
asImp_().evalFluxes(residual, elemCtx, /*timeIdx=*/0);
|
||||
|
||||
// evaluate the storage and the source terms
|
||||
asImp_().evalVolumeTerms_(residual, elemCtx);
|
||||
|
||||
// evaluate the boundary conditions
|
||||
asImp_().evalBoundary_(residual, elemCtx, /*timeIdx=*/0);
|
||||
|
||||
if (useVolumetricResidual) {
|
||||
// make the residual volume specific (i.e., make it incorrect mass per cubic
|
||||
// meter instead of total mass)
|
||||
size_t numDof = elemCtx.numDof(/*timeIdx=*/0);
|
||||
for (unsigned dofIdx=0; dofIdx < numDof; ++dofIdx) {
|
||||
if (elemCtx.dofTotalVolume(dofIdx, /*timeIdx=*/0) > 0.0) {
|
||||
// interior DOF
|
||||
Scalar dofVolume = elemCtx.dofTotalVolume(dofIdx, /*timeIdx=*/0);
|
||||
|
||||
assert(std::isfinite(dofVolume));
|
||||
Opm::Valgrind::CheckDefined(dofVolume);
|
||||
|
||||
for (unsigned eqIdx = 0; eqIdx < numEq; ++ eqIdx)
|
||||
residual[dofIdx][eqIdx] /= dofVolume;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/*!
|
||||
* \brief Calculate the amount of all conservation quantities stored in all element's
|
||||
* sub-control volumes for a given history index.
|
||||
*
|
||||
* This is used to figure out how much of each conservation quantity is inside the
|
||||
* element.
|
||||
*
|
||||
* \copydetails Doxygen::storageParam
|
||||
* \copydetails Doxygen::ecfvElemCtxParam
|
||||
* \copydetails Doxygen::timeIdxParam
|
||||
*/
|
||||
void evalStorage(LocalEvalBlockVector& storage,
|
||||
const ElementContext& elemCtx,
|
||||
unsigned timeIdx) const
|
||||
{
|
||||
// the derivative of the storage term depends on the current primary variables;
|
||||
// for time indices != 0, the storage term is constant (because these solutions
|
||||
// are not changed by the Newton method!)
|
||||
if (timeIdx == 0) {
|
||||
// calculate the amount of conservation each quantity inside
|
||||
// all primary sub control volumes
|
||||
size_t numPrimaryDof = elemCtx.numPrimaryDof(/*timeIdx=*/0);
|
||||
for (unsigned dofIdx=0; dofIdx < numPrimaryDof; dofIdx++) {
|
||||
storage[dofIdx] = 0.0;
|
||||
|
||||
// the volume of the associated DOF
|
||||
Scalar alpha =
|
||||
elemCtx.stencil(timeIdx).subControlVolume(dofIdx).volume()
|
||||
* elemCtx.intensiveQuantities(dofIdx, timeIdx).extrusionFactor();
|
||||
|
||||
// If the degree of freedom which we currently look at is the one at the
|
||||
// center of attention, we need to consider the derivatives for the
|
||||
// storage term, else the storage term is constant w.r.t. the primary
|
||||
// variables of the focused DOF.
|
||||
if (dofIdx == elemCtx.focusDofIndex()) {
|
||||
asImp_().computeStorage(storage[dofIdx],
|
||||
elemCtx,
|
||||
dofIdx,
|
||||
timeIdx);
|
||||
|
||||
for (unsigned eqIdx = 0; eqIdx < numEq; ++ eqIdx)
|
||||
storage[dofIdx][eqIdx] *= alpha;
|
||||
}
|
||||
else {
|
||||
Dune::FieldVector<Scalar, numEq> tmp;
|
||||
asImp_().computeStorage(tmp,
|
||||
elemCtx,
|
||||
dofIdx,
|
||||
timeIdx);
|
||||
|
||||
for (unsigned eqIdx = 0; eqIdx < numEq; ++ eqIdx)
|
||||
storage[dofIdx][eqIdx] = tmp[eqIdx]*alpha;
|
||||
}
|
||||
}
|
||||
}
|
||||
else {
|
||||
// for all previous solutions, the storage term does _not_ depend on the
|
||||
// current primary variables, so we use scalars to store it.
|
||||
if (elemCtx.enableStorageCache()) {
|
||||
size_t numPrimaryDof = elemCtx.numPrimaryDof(timeIdx);
|
||||
for (unsigned dofIdx=0; dofIdx < numPrimaryDof; dofIdx++) {
|
||||
unsigned globalDofIdx = elemCtx.globalSpaceIndex(dofIdx, timeIdx);
|
||||
const auto& cachedStorage = elemCtx.model().cachedStorage(globalDofIdx, timeIdx);
|
||||
for (unsigned eqIdx=0; eqIdx < numEq; eqIdx++)
|
||||
storage[dofIdx][eqIdx] = cachedStorage[eqIdx];
|
||||
}
|
||||
}
|
||||
else {
|
||||
// calculate the amount of conservation each quantity inside
|
||||
// all primary sub control volumes
|
||||
Dune::FieldVector<Scalar, numEq> tmp;
|
||||
size_t numPrimaryDof = elemCtx.numPrimaryDof(/*timeIdx=*/0);
|
||||
for (unsigned dofIdx=0; dofIdx < numPrimaryDof; dofIdx++) {
|
||||
tmp = 0.0;
|
||||
asImp_().computeStorage(tmp,
|
||||
elemCtx,
|
||||
dofIdx,
|
||||
timeIdx);
|
||||
tmp *=
|
||||
elemCtx.stencil(timeIdx).subControlVolume(dofIdx).volume()
|
||||
* elemCtx.intensiveQuantities(dofIdx, timeIdx).extrusionFactor();
|
||||
|
||||
for (unsigned eqIdx = 0; eqIdx < numEq; ++eqIdx)
|
||||
storage[dofIdx][eqIdx] = tmp[eqIdx];
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#ifndef NDEBUG
|
||||
size_t numPrimaryDof = elemCtx.numPrimaryDof(/*timeIdx=*/0);
|
||||
for (unsigned dofIdx=0; dofIdx < numPrimaryDof; dofIdx++) {
|
||||
for (unsigned eqIdx = 0; eqIdx < numEq; ++eqIdx) {
|
||||
Opm::Valgrind::CheckDefined(storage[dofIdx][eqIdx]);
|
||||
assert(Opm::isfinite(storage[dofIdx][eqIdx]));
|
||||
}
|
||||
}
|
||||
#endif
|
||||
}
|
||||
|
||||
/*!
|
||||
* \brief Add the flux term to a local residual.
|
||||
*
|
||||
* \copydetails Doxygen::residualParam
|
||||
* \copydetails Doxygen::ecfvElemCtxParam
|
||||
* \copydetails Doxygen::timeIdxParam
|
||||
*/
|
||||
void evalFluxes(LocalEvalBlockVector& residual,
|
||||
const ElementContext& elemCtx,
|
||||
unsigned timeIdx) const
|
||||
{
|
||||
RateVector flux;
|
||||
|
||||
const auto& stencil = elemCtx.stencil(timeIdx);
|
||||
// calculate the mass flux over the sub-control volume faces
|
||||
size_t numInteriorFaces = elemCtx.numInteriorFaces(timeIdx);
|
||||
for (unsigned scvfIdx = 0; scvfIdx < numInteriorFaces; scvfIdx++) {
|
||||
const auto& face = stencil.interiorFace(scvfIdx);
|
||||
unsigned i = face.interiorIndex();
|
||||
unsigned j = face.exteriorIndex();
|
||||
|
||||
Opm::Valgrind::SetUndefined(flux);
|
||||
asImp_().computeFlux(flux, /*context=*/elemCtx, scvfIdx, timeIdx);
|
||||
Opm::Valgrind::CheckDefined(flux);
|
||||
#ifndef NDEBUG
|
||||
for (unsigned eqIdx = 0; eqIdx < numEq; ++eqIdx)
|
||||
assert(Opm::isfinite(flux[eqIdx]));
|
||||
#endif
|
||||
|
||||
Scalar alpha = elemCtx.extensiveQuantities(scvfIdx, timeIdx).extrusionFactor();
|
||||
alpha *= face.area();
|
||||
Opm::Valgrind::CheckDefined(alpha);
|
||||
assert(alpha > 0.0);
|
||||
assert(Opm::isfinite(alpha));
|
||||
|
||||
for (unsigned eqIdx = 0; eqIdx < numEq; ++ eqIdx)
|
||||
flux[eqIdx] *= alpha;
|
||||
|
||||
// The balance equation for a finite volume is given by
|
||||
//
|
||||
// dStorage/dt + Flux = Source
|
||||
//
|
||||
// where the 'Flux' and the 'Source' terms represent the
|
||||
// mass per second which leaves the finite
|
||||
// volume. Re-arranging this, we get
|
||||
//
|
||||
// dStorage/dt + Flux - Source = 0
|
||||
//
|
||||
// Since the mass flux as calculated by computeFlux() goes out of sub-control
|
||||
// volume i and into sub-control volume j, we need to add the flux to finite
|
||||
// volume i and subtract it from finite volume j
|
||||
for (unsigned eqIdx = 0; eqIdx < numEq; ++eqIdx) {
|
||||
assert(Opm::isfinite(flux[eqIdx]));
|
||||
residual[i][eqIdx] += flux[eqIdx];
|
||||
residual[j][eqIdx] -= flux[eqIdx];
|
||||
}
|
||||
}
|
||||
|
||||
#if !defined NDEBUG
|
||||
// in debug mode, ensure that the residual is well-defined
|
||||
size_t numDof = elemCtx.numDof(timeIdx);
|
||||
for (unsigned i=0; i < numDof; i++) {
|
||||
for (unsigned j = 0; j < numEq; ++ j) {
|
||||
assert(Opm::isfinite(residual[i][j]));
|
||||
Opm::Valgrind::CheckDefined(residual[i][j]);
|
||||
}
|
||||
}
|
||||
#endif
|
||||
|
||||
}
|
||||
|
||||
/////////////////////////////
|
||||
// The following methods _must_ be overloaded by the actual flow
|
||||
// models!
|
||||
/////////////////////////////
|
||||
|
||||
/*!
|
||||
* \brief Evaluate the amount all conservation quantities
|
||||
* (e.g. phase mass) within a finite sub-control volume.
|
||||
*
|
||||
* \copydetails Doxygen::storageParam
|
||||
* \copydetails Doxygen::ecfvScvCtxParams
|
||||
*/
|
||||
void computeStorage(EqVector& storage OPM_UNUSED,
|
||||
const ElementContext& elemCtx OPM_UNUSED,
|
||||
unsigned dofIdx OPM_UNUSED,
|
||||
unsigned timeIdx OPM_UNUSED) const
|
||||
{
|
||||
throw std::logic_error("Not implemented: The local residual "+Dune::className<Implementation>()
|
||||
+" does not implement the required method 'computeStorage()'");
|
||||
}
|
||||
|
||||
/*!
|
||||
* \brief Evaluates the total mass flux of all conservation
|
||||
* quantities over a face of a sub-control volume.
|
||||
*
|
||||
* \copydetails Doxygen::areaFluxParam
|
||||
* \copydetails Doxygen::ecfvScvfCtxParams
|
||||
*/
|
||||
void computeFlux(RateVector& flux OPM_UNUSED,
|
||||
const ElementContext& elemCtx OPM_UNUSED,
|
||||
unsigned scvfIdx OPM_UNUSED,
|
||||
unsigned timeIdx OPM_UNUSED) const
|
||||
{
|
||||
throw std::logic_error("Not implemented: The local residual "+Dune::className<Implementation>()
|
||||
+" does not implement the required method 'computeFlux()'");
|
||||
}
|
||||
|
||||
/*!
|
||||
* \brief Calculate the source term of the equation
|
||||
*
|
||||
* \copydoc Doxygen::sourceParam
|
||||
* \copydoc Doxygen::ecfvScvCtxParams
|
||||
*/
|
||||
void computeSource(RateVector& source OPM_UNUSED,
|
||||
const ElementContext& elemCtx OPM_UNUSED,
|
||||
unsigned dofIdx OPM_UNUSED,
|
||||
unsigned timeIdx OPM_UNUSED) const
|
||||
{
|
||||
throw std::logic_error("Not implemented: The local residual "+Dune::className<Implementation>()
|
||||
+" does not implement the required method 'computeSource()'");
|
||||
}
|
||||
|
||||
protected:
|
||||
/*!
|
||||
* \brief Evaluate the boundary conditions of an element.
|
||||
*/
|
||||
void evalBoundary_(LocalEvalBlockVector& residual,
|
||||
const ElementContext& elemCtx,
|
||||
unsigned timeIdx) const
|
||||
{
|
||||
if (!elemCtx.onBoundary())
|
||||
return;
|
||||
|
||||
BoundaryContext boundaryCtx(elemCtx);
|
||||
|
||||
// evaluate the boundary for all boundary faces of the current context
|
||||
size_t numBoundaryFaces = boundaryCtx.numBoundaryFaces(/*timeIdx=*/0);
|
||||
for (unsigned faceIdx = 0; faceIdx < numBoundaryFaces; ++faceIdx, boundaryCtx.increment()) {
|
||||
// add the residual of all vertices of the boundary
|
||||
// segment
|
||||
evalBoundarySegment_(residual,
|
||||
boundaryCtx,
|
||||
faceIdx,
|
||||
timeIdx);
|
||||
}
|
||||
|
||||
#if !defined NDEBUG
|
||||
// in debug mode, ensure that the residual and the storage terms are well-defined
|
||||
size_t numDof = elemCtx.numDof(/*timeIdx=*/0);
|
||||
for (unsigned i=0; i < numDof; i++) {
|
||||
for (unsigned j = 0; j < numEq; ++ j) {
|
||||
assert(Opm::isfinite(residual[i][j]));
|
||||
Opm::Valgrind::CheckDefined(residual[i][j]);
|
||||
}
|
||||
}
|
||||
#endif
|
||||
|
||||
}
|
||||
|
||||
/*!
|
||||
* \brief Evaluate all boundary conditions for a single
|
||||
* sub-control volume face to the local residual.
|
||||
*/
|
||||
void evalBoundarySegment_(LocalEvalBlockVector& residual,
|
||||
const BoundaryContext& boundaryCtx,
|
||||
unsigned boundaryFaceIdx,
|
||||
unsigned timeIdx) const
|
||||
{
|
||||
BoundaryRateVector values;
|
||||
|
||||
Opm::Valgrind::SetUndefined(values);
|
||||
boundaryCtx.problem().boundary(values, boundaryCtx, boundaryFaceIdx, timeIdx);
|
||||
Opm::Valgrind::CheckDefined(values);
|
||||
|
||||
const auto& stencil = boundaryCtx.stencil(timeIdx);
|
||||
unsigned dofIdx = stencil.boundaryFace(boundaryFaceIdx).interiorIndex();
|
||||
const auto& insideIntQuants = boundaryCtx.elementContext().intensiveQuantities(dofIdx, timeIdx);
|
||||
for (unsigned eqIdx = 0; eqIdx < values.size(); ++eqIdx) {
|
||||
values[eqIdx] *=
|
||||
stencil.boundaryFace(boundaryFaceIdx).area()
|
||||
* insideIntQuants.extrusionFactor();
|
||||
|
||||
Opm::Valgrind::CheckDefined(values[eqIdx]);
|
||||
assert(Opm::isfinite(values[eqIdx]));
|
||||
}
|
||||
|
||||
for (unsigned eqIdx = 0; eqIdx < numEq; ++eqIdx)
|
||||
residual[dofIdx][eqIdx] += values[eqIdx];
|
||||
}
|
||||
|
||||
/*!
|
||||
* \brief Add the change in the storage terms and the source term
|
||||
* to the local residual of all sub-control volumes of the
|
||||
* current element.
|
||||
*/
|
||||
void evalVolumeTerms_(LocalEvalBlockVector& residual,
|
||||
ElementContext& elemCtx) const
|
||||
{
|
||||
EvalVector tmp;
|
||||
EqVector tmp2;
|
||||
RateVector sourceRate;
|
||||
|
||||
tmp = 0.0;
|
||||
tmp2 = 0.0;
|
||||
|
||||
// evaluate the volumetric terms (storage + source terms)
|
||||
size_t numPrimaryDof = elemCtx.numPrimaryDof(/*timeIdx=*/0);
|
||||
for (unsigned dofIdx=0; dofIdx < numPrimaryDof; dofIdx++) {
|
||||
Scalar extrusionFactor =
|
||||
elemCtx.intensiveQuantities(dofIdx, /*timeIdx=*/0).extrusionFactor();
|
||||
Opm::Valgrind::CheckDefined(extrusionFactor);
|
||||
assert(Opm::isfinite(extrusionFactor));
|
||||
assert(extrusionFactor > 0.0);
|
||||
Scalar scvVolume =
|
||||
elemCtx.stencil(/*timeIdx=*/0).subControlVolume(dofIdx).volume() * extrusionFactor;
|
||||
Opm::Valgrind::CheckDefined(scvVolume);
|
||||
assert(Opm::isfinite(scvVolume));
|
||||
assert(scvVolume > 0.0);
|
||||
|
||||
// if the model uses extensive quantities in its storage term, and we use
|
||||
// automatic differention and current DOF is also not the one we currently
|
||||
// focus on, the storage term does not need any derivatives!
|
||||
if (!extensiveStorageTerm &&
|
||||
!std::is_same<Scalar, Evaluation>::value &&
|
||||
dofIdx != elemCtx.focusDofIndex())
|
||||
{
|
||||
asImp_().computeStorage(tmp2, elemCtx, dofIdx, /*timeIdx=*/0);
|
||||
for (unsigned eqIdx = 0; eqIdx < numEq; ++eqIdx)
|
||||
tmp[eqIdx] = tmp2[eqIdx];
|
||||
}
|
||||
else
|
||||
asImp_().computeStorage(tmp, elemCtx, dofIdx, /*timeIdx=*/0);
|
||||
|
||||
#ifndef NDEBUG
|
||||
Opm::Valgrind::CheckDefined(tmp);
|
||||
for (unsigned eqIdx = 0; eqIdx < numEq; ++eqIdx)
|
||||
assert(Opm::isfinite(tmp[eqIdx]));
|
||||
#endif
|
||||
|
||||
if (elemCtx.enableStorageCache()) {
|
||||
const auto& model = elemCtx.model();
|
||||
unsigned globalDofIdx = elemCtx.globalSpaceIndex(dofIdx, /*timeIdx=*/0);
|
||||
if (model.newtonMethod().numIterations() == 0 &&
|
||||
!elemCtx.haveStashedIntensiveQuantities())
|
||||
{
|
||||
if (!elemCtx.problem().recycleFirstIterationStorage()) {
|
||||
// we re-calculate the storage term for the solution of the
|
||||
// previous time step from scratch instead of using the one of
|
||||
// the first iteration of the current time step.
|
||||
tmp2 = 0.0;
|
||||
elemCtx.updatePrimaryIntensiveQuantities(/*timeIdx=*/1);
|
||||
asImp_().computeStorage(tmp2, elemCtx, dofIdx, /*timeIdx=*/1);
|
||||
}
|
||||
else {
|
||||
// if the storage term is cached and we're in the first iteration
|
||||
// of the time step, use the storage term of the first iteration
|
||||
// as the one as the solution of the last time step (this assumes
|
||||
// that the initial guess for the solution at the end of the time
|
||||
// step is the same as the solution at the beginning of the time
|
||||
// step. This is usually true, but some fancy preprocessing
|
||||
// scheme might invalidate that assumption.)
|
||||
for (unsigned eqIdx = 0; eqIdx < numEq; ++ eqIdx)
|
||||
tmp2[eqIdx] = Toolbox::value(tmp[eqIdx]);
|
||||
}
|
||||
|
||||
Opm::Valgrind::CheckDefined(tmp2);
|
||||
|
||||
model.updateCachedStorage(globalDofIdx, /*timeIdx=*/1, tmp2);
|
||||
}
|
||||
else {
|
||||
// if the mass storage at the beginning of the time step is not cached,
|
||||
// if the storage term is cached and we're not looking at the first
|
||||
// iteration of the time step, we take the cached data.
|
||||
tmp2 = model.cachedStorage(globalDofIdx, /*timeIdx=*/1);
|
||||
Opm::Valgrind::CheckDefined(tmp2);
|
||||
}
|
||||
}
|
||||
else {
|
||||
// if the mass storage at the beginning of the time step is not cached,
|
||||
// we re-calculate it from scratch.
|
||||
tmp2 = 0.0;
|
||||
asImp_().computeStorage(tmp2, elemCtx, dofIdx, /*timeIdx=*/1);
|
||||
Opm::Valgrind::CheckDefined(tmp2);
|
||||
}
|
||||
|
||||
// Use the implicit Euler time discretization
|
||||
for (unsigned eqIdx = 0; eqIdx < numEq; ++eqIdx) {
|
||||
tmp[eqIdx] -= tmp2[eqIdx];
|
||||
tmp[eqIdx] *= scvVolume / elemCtx.simulator().timeStepSize();
|
||||
|
||||
residual[dofIdx][eqIdx] += tmp[eqIdx];
|
||||
}
|
||||
|
||||
Opm::Valgrind::CheckDefined(residual[dofIdx]);
|
||||
|
||||
// deal with the source term
|
||||
asImp_().computeSource(sourceRate, elemCtx, dofIdx, /*timeIdx=*/0);
|
||||
|
||||
// if the model uses extensive quantities in its storage term, and we use
|
||||
// automatic differention and current DOF is also not the one we currently
|
||||
// focus on, the storage term does not need any derivatives!
|
||||
if (!extensiveStorageTerm &&
|
||||
!std::is_same<Scalar, Evaluation>::value &&
|
||||
dofIdx != elemCtx.focusDofIndex())
|
||||
{
|
||||
for (unsigned eqIdx = 0; eqIdx < numEq; ++eqIdx)
|
||||
residual[dofIdx][eqIdx] -= Opm::scalarValue(sourceRate[eqIdx])*scvVolume;
|
||||
}
|
||||
else {
|
||||
for (unsigned eqIdx = 0; eqIdx < numEq; ++eqIdx) {
|
||||
sourceRate[eqIdx] *= scvVolume;
|
||||
residual[dofIdx][eqIdx] -= sourceRate[eqIdx];
|
||||
}
|
||||
}
|
||||
|
||||
Opm::Valgrind::CheckDefined(residual[dofIdx]);
|
||||
}
|
||||
|
||||
#if !defined NDEBUG
|
||||
// in debug mode, ensure that the residual is well-defined
|
||||
size_t numDof = elemCtx.numDof(/*timeIdx=*/0);
|
||||
for (unsigned i=0; i < numDof; i++) {
|
||||
for (unsigned j = 0; j < numEq; ++ j) {
|
||||
assert(Opm::isfinite(residual[i][j]));
|
||||
Opm::Valgrind::CheckDefined(residual[i][j]);
|
||||
}
|
||||
}
|
||||
#endif
|
||||
}
|
||||
|
||||
|
||||
private:
|
||||
Implementation& asImp_()
|
||||
{ return *static_cast<Implementation*>(this); }
|
||||
|
||||
const Implementation& asImp_() const
|
||||
{ return *static_cast<const Implementation*>(this); }
|
||||
|
||||
LocalEvalBlockVector internalResidual_;
|
||||
};
|
||||
|
||||
} // namespace Opm
|
||||
|
||||
#endif
|
@ -0,0 +1,156 @@
|
||||
// -*- mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*-
|
||||
// vi: set et ts=4 sw=4 sts=4:
|
||||
/*
|
||||
This file is part of the Open Porous Media project (OPM).
|
||||
|
||||
OPM 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.
|
||||
|
||||
OPM is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
GNU General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU General Public License
|
||||
along with OPM. If not, see <http://www.gnu.org/licenses/>.
|
||||
|
||||
Consult the COPYING file in the top-level source directory of this
|
||||
module for the precise wording of the license and the list of
|
||||
copyright holders.
|
||||
*/
|
||||
/*!
|
||||
* \file
|
||||
*
|
||||
* \copydoc Opm::FvBaseNewtonConvergenceWriter
|
||||
*/
|
||||
#ifndef EWOMS_FV_BASE_NEWTON_CONVERGENCE_WRITER_HH
|
||||
#define EWOMS_FV_BASE_NEWTON_CONVERGENCE_WRITER_HH
|
||||
|
||||
#include <ewoms/io/vtkmultiwriter.hh>
|
||||
#include <opm/models/utils/propertysystem.hh>
|
||||
|
||||
#include <iostream>
|
||||
|
||||
//! \cond SKIP_THIS
|
||||
BEGIN_PROPERTIES
|
||||
|
||||
// forward declaration of the required property tags
|
||||
NEW_PROP_TAG(GridView);
|
||||
NEW_PROP_TAG(NewtonMethod);
|
||||
NEW_PROP_TAG(SolutionVector);
|
||||
NEW_PROP_TAG(GlobalEqVector);
|
||||
NEW_PROP_TAG(VtkOutputFormat);
|
||||
|
||||
END_PROPERTIES
|
||||
//! \endcond
|
||||
|
||||
namespace Opm {
|
||||
/*!
|
||||
* \ingroup FiniteVolumeDiscretizations
|
||||
*
|
||||
* \brief Writes the intermediate solutions during the Newton scheme
|
||||
* for models using a finite volume discretization
|
||||
*/
|
||||
template <class TypeTag>
|
||||
class FvBaseNewtonConvergenceWriter
|
||||
{
|
||||
typedef typename GET_PROP_TYPE(TypeTag, GridView) GridView;
|
||||
|
||||
typedef typename GET_PROP_TYPE(TypeTag, SolutionVector) SolutionVector;
|
||||
typedef typename GET_PROP_TYPE(TypeTag, GlobalEqVector) GlobalEqVector;
|
||||
typedef typename GET_PROP_TYPE(TypeTag, NewtonMethod) NewtonMethod;
|
||||
|
||||
static const int vtkFormat = GET_PROP_VALUE(TypeTag, VtkOutputFormat);
|
||||
typedef Opm::VtkMultiWriter<GridView, vtkFormat> VtkMultiWriter;
|
||||
|
||||
public:
|
||||
FvBaseNewtonConvergenceWriter(NewtonMethod& nm)
|
||||
: newtonMethod_(nm)
|
||||
{
|
||||
timeStepIdx_ = 0;
|
||||
iteration_ = 0;
|
||||
vtkMultiWriter_ = 0;
|
||||
}
|
||||
|
||||
~FvBaseNewtonConvergenceWriter()
|
||||
{ delete vtkMultiWriter_; }
|
||||
|
||||
/*!
|
||||
* \brief Called by the Newton method before the actual algorithm
|
||||
* is started for any given timestep.
|
||||
*/
|
||||
void beginTimeStep()
|
||||
{
|
||||
++timeStepIdx_;
|
||||
iteration_ = 0;
|
||||
}
|
||||
|
||||
/*!
|
||||
* \brief Called by the Newton method before an iteration of the
|
||||
* Newton algorithm is started.
|
||||
*/
|
||||
void beginIteration()
|
||||
{
|
||||
++ iteration_;
|
||||
if (!vtkMultiWriter_)
|
||||
vtkMultiWriter_ =
|
||||
new VtkMultiWriter(/*async=*/false,
|
||||
newtonMethod_.problem().gridView(),
|
||||
newtonMethod_.problem().outputDir(),
|
||||
"convergence");
|
||||
vtkMultiWriter_->beginWrite(timeStepIdx_ + iteration_ / 100.0);
|
||||
}
|
||||
|
||||
/*!
|
||||
* \brief Write the Newton update to disk.
|
||||
*
|
||||
* Called after the linear solution is found for an iteration.
|
||||
*
|
||||
* \param uLastIter The solution vector of the previous iteration.
|
||||
* \param deltaU The negative difference between the solution
|
||||
* vectors of the previous and the current iteration.
|
||||
*/
|
||||
void writeFields(const SolutionVector& uLastIter,
|
||||
const GlobalEqVector& deltaU)
|
||||
{
|
||||
try {
|
||||
newtonMethod_.problem().model().addConvergenceVtkFields(*vtkMultiWriter_,
|
||||
uLastIter,
|
||||
deltaU);
|
||||
}
|
||||
catch (...) {
|
||||
std::cout << "Oops: exception thrown on rank "
|
||||
<< newtonMethod_.problem().gridView().comm().rank()
|
||||
<< " while writing the convergence\n" << std::flush;
|
||||
}
|
||||
}
|
||||
|
||||
/*!
|
||||
* \brief Called by the Newton method after an iteration of the
|
||||
* Newton algorithm has been completed.
|
||||
*/
|
||||
void endIteration()
|
||||
{ vtkMultiWriter_->endWrite(); }
|
||||
|
||||
/*!
|
||||
* \brief Called by the Newton method after Newton algorithm
|
||||
* has been completed for any given timestep.
|
||||
*
|
||||
* This method is called regardless of whether the Newton method
|
||||
* converged or not.
|
||||
*/
|
||||
void endTimeStep()
|
||||
{ iteration_ = 0; }
|
||||
|
||||
private:
|
||||
int timeStepIdx_;
|
||||
int iteration_;
|
||||
VtkMultiWriter *vtkMultiWriter_;
|
||||
NewtonMethod& newtonMethod_;
|
||||
};
|
||||
|
||||
} // namespace Opm
|
||||
|
||||
#endif
|
179
opm/models/discretization/common/fvbasenewtonmethod.hh
Normal file
179
opm/models/discretization/common/fvbasenewtonmethod.hh
Normal file
@ -0,0 +1,179 @@
|
||||
// -*- mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*-
|
||||
// vi: set et ts=4 sw=4 sts=4:
|
||||
/*
|
||||
This file is part of the Open Porous Media project (OPM).
|
||||
|
||||
OPM 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.
|
||||
|
||||
OPM is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
GNU General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU General Public License
|
||||
along with OPM. If not, see <http://www.gnu.org/licenses/>.
|
||||
|
||||
Consult the COPYING file in the top-level source directory of this
|
||||
module for the precise wording of the license and the list of
|
||||
copyright holders.
|
||||
*/
|
||||
/*!
|
||||
* \file
|
||||
*
|
||||
* \copydoc Opm::FvBaseNewtonMethod
|
||||
*/
|
||||
#ifndef EWOMS_FV_BASE_NEWTON_METHOD_HH
|
||||
#define EWOMS_FV_BASE_NEWTON_METHOD_HH
|
||||
|
||||
#include "fvbasenewtonconvergencewriter.hh"
|
||||
|
||||
#include <ewoms/nonlinear/newtonmethod.hh>
|
||||
#include <opm/models/utils/propertysystem.hh>
|
||||
|
||||
namespace Opm {
|
||||
|
||||
template <class TypeTag>
|
||||
class FvBaseNewtonMethod;
|
||||
|
||||
template <class TypeTag>
|
||||
class FvBaseNewtonConvergenceWriter;
|
||||
} // namespace Opm
|
||||
|
||||
BEGIN_PROPERTIES
|
||||
|
||||
//! create a type tag for the Newton method of the finite-volume discretization
|
||||
NEW_TYPE_TAG(FvBaseNewtonMethod, INHERITS_FROM(NewtonMethod));
|
||||
|
||||
//! The class dealing with the balance equations
|
||||
NEW_PROP_TAG(Model);
|
||||
|
||||
//! The class storing primary variables plus pseudo primary variables
|
||||
NEW_PROP_TAG(PrimaryVariables);
|
||||
|
||||
//! The class storing values of conservation equations (e.g., a "naked" primary varible
|
||||
//! vector)
|
||||
NEW_PROP_TAG(EqVector);
|
||||
|
||||
//! The number of balance equations.
|
||||
NEW_PROP_TAG(NumEq);
|
||||
|
||||
//! The discretization specific part of he implementing the Newton algorithm
|
||||
NEW_PROP_TAG(DiscNewtonMethod);
|
||||
|
||||
//! The class implementing the Newton algorithm
|
||||
NEW_PROP_TAG(NewtonMethod);
|
||||
|
||||
// set default values
|
||||
SET_TYPE_PROP(FvBaseNewtonMethod, DiscNewtonMethod,
|
||||
Opm::FvBaseNewtonMethod<TypeTag>);
|
||||
SET_TYPE_PROP(FvBaseNewtonMethod, NewtonMethod,
|
||||
typename GET_PROP_TYPE(TypeTag, DiscNewtonMethod));
|
||||
SET_TYPE_PROP(FvBaseNewtonMethod, NewtonConvergenceWriter,
|
||||
Opm::FvBaseNewtonConvergenceWriter<TypeTag>);
|
||||
|
||||
END_PROPERTIES
|
||||
|
||||
namespace Opm {
|
||||
|
||||
/*!
|
||||
* \ingroup FiniteVolumeDiscretizations
|
||||
*
|
||||
* \brief A Newton method for models using a finite volume discretization.
|
||||
*
|
||||
* This class is sufficient for most models which use an Element or a
|
||||
* Vertex Centered Finite Volume discretization.
|
||||
*/
|
||||
template <class TypeTag>
|
||||
class FvBaseNewtonMethod : public NewtonMethod<TypeTag>
|
||||
{
|
||||
typedef Opm::NewtonMethod<TypeTag> ParentType;
|
||||
typedef typename GET_PROP_TYPE(TypeTag, NewtonMethod) Implementation;
|
||||
|
||||
typedef typename GET_PROP_TYPE(TypeTag, Scalar) Scalar;
|
||||
typedef typename GET_PROP_TYPE(TypeTag, Simulator) Simulator;
|
||||
typedef typename GET_PROP_TYPE(TypeTag, Model) Model;
|
||||
typedef typename GET_PROP_TYPE(TypeTag, Linearizer) Linearizer;
|
||||
typedef typename GET_PROP_TYPE(TypeTag, NewtonMethod) NewtonMethod;
|
||||
typedef typename GET_PROP_TYPE(TypeTag, GlobalEqVector) GlobalEqVector;
|
||||
typedef typename GET_PROP_TYPE(TypeTag, SolutionVector) SolutionVector;
|
||||
typedef typename GET_PROP_TYPE(TypeTag, PrimaryVariables) PrimaryVariables;
|
||||
typedef typename GET_PROP_TYPE(TypeTag, EqVector) EqVector;
|
||||
|
||||
|
||||
public:
|
||||
FvBaseNewtonMethod(Simulator& simulator)
|
||||
: ParentType(simulator)
|
||||
{ }
|
||||
|
||||
protected:
|
||||
friend class Opm::NewtonMethod<TypeTag>;
|
||||
|
||||
/*!
|
||||
* \brief Update the current solution with a delta vector.
|
||||
*
|
||||
* The error estimates required for the converged() and
|
||||
* proceed() methods should be updated inside this method.
|
||||
*
|
||||
* Different update strategies, such as line search and chopped
|
||||
* updates can be implemented. The default behavior is just to
|
||||
* subtract deltaU from uLastIter, i.e.
|
||||
* \f[ u^{k+1} = u^k - \Delta u^k \f]
|
||||
*
|
||||
* \param nextSolution The solution vector at the end of the current iteration
|
||||
* \param currentSolution The solution vector at the beginning of the current iteration
|
||||
* \param solutionUpdate The delta as calculated by solving the linear system of
|
||||
* equations. This parameter also stores the updated solution.
|
||||
* \param currentResidual The residual (i.e., right-hand-side) of the current solution.
|
||||
*/
|
||||
void update_(SolutionVector& nextSolution,
|
||||
const SolutionVector& currentSolution,
|
||||
const GlobalEqVector& solutionUpdate,
|
||||
const GlobalEqVector& currentResidual)
|
||||
{
|
||||
ParentType::update_(nextSolution, currentSolution, solutionUpdate, currentResidual);
|
||||
|
||||
// make sure that the intensive quantities get recalculated at the next
|
||||
// linearization
|
||||
if (model_().storeIntensiveQuantities()) {
|
||||
for (unsigned dofIdx = 0; dofIdx < model_().numGridDof(); ++dofIdx)
|
||||
model_().setIntensiveQuantitiesCacheEntryValidity(dofIdx,
|
||||
/*timeIdx=*/0,
|
||||
/*valid=*/false);
|
||||
}
|
||||
}
|
||||
|
||||
/*!
|
||||
* \brief Indicates the beginning of a Newton iteration.
|
||||
*/
|
||||
void beginIteration_()
|
||||
{
|
||||
model_().syncOverlap();
|
||||
|
||||
ParentType::beginIteration_();
|
||||
}
|
||||
|
||||
/*!
|
||||
* \brief Returns a reference to the model.
|
||||
*/
|
||||
Model& model_()
|
||||
{ return ParentType::model(); }
|
||||
|
||||
/*!
|
||||
* \brief Returns a reference to the model.
|
||||
*/
|
||||
const Model& model_() const
|
||||
{ return ParentType::model(); }
|
||||
|
||||
private:
|
||||
Implementation& asImp_()
|
||||
{ return *static_cast<Implementation*>(this); }
|
||||
|
||||
const Implementation& asImp_() const
|
||||
{ return *static_cast<const Implementation*>(this); }
|
||||
};
|
||||
} // namespace Opm
|
||||
|
||||
#endif
|
166
opm/models/discretization/common/fvbaseprimaryvariables.hh
Normal file
166
opm/models/discretization/common/fvbaseprimaryvariables.hh
Normal file
@ -0,0 +1,166 @@
|
||||
// -*- mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*-
|
||||
// vi: set et ts=4 sw=4 sts=4:
|
||||
/*
|
||||
This file is part of the Open Porous Media project (OPM).
|
||||
|
||||
OPM 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.
|
||||
|
||||
OPM is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
GNU General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU General Public License
|
||||
along with OPM. If not, see <http://www.gnu.org/licenses/>.
|
||||
|
||||
Consult the COPYING file in the top-level source directory of this
|
||||
module for the precise wording of the license and the list of
|
||||
copyright holders.
|
||||
*/
|
||||
/*!
|
||||
* \file
|
||||
*
|
||||
* \copydoc Opm::FvBasePrimaryVariables
|
||||
*/
|
||||
#ifndef EWOMS_FV_BASE_PRIMARY_VARIABLES_HH
|
||||
#define EWOMS_FV_BASE_PRIMARY_VARIABLES_HH
|
||||
|
||||
#include <type_traits>
|
||||
|
||||
#include "fvbaseproperties.hh"
|
||||
|
||||
#include <opm/material/common/Valgrind.hpp>
|
||||
#include <opm/material/common/Unused.hpp>
|
||||
#include <opm/material/common/Exceptions.hpp>
|
||||
|
||||
#include <dune/common/fvector.hh>
|
||||
|
||||
namespace Opm {
|
||||
|
||||
/*!
|
||||
* \ingroup FiniteVolumeDiscretizations
|
||||
*
|
||||
* \brief Represents the primary variables used by the a model.
|
||||
*/
|
||||
template <class TypeTag>
|
||||
class FvBasePrimaryVariables
|
||||
: public Dune::FieldVector<typename GET_PROP_TYPE(TypeTag, Scalar),
|
||||
GET_PROP_VALUE(TypeTag, NumEq)>
|
||||
{
|
||||
typedef typename GET_PROP_TYPE(TypeTag, Scalar) Scalar;
|
||||
typedef typename GET_PROP_TYPE(TypeTag, Evaluation) Evaluation;
|
||||
|
||||
enum { numEq = GET_PROP_VALUE(TypeTag, NumEq) };
|
||||
|
||||
typedef Opm::MathToolbox<Evaluation> Toolbox;
|
||||
typedef Dune::FieldVector<Scalar, numEq> ParentType;
|
||||
|
||||
public:
|
||||
FvBasePrimaryVariables()
|
||||
: ParentType()
|
||||
{ Opm::Valgrind::SetUndefined(*this); }
|
||||
|
||||
/*!
|
||||
* \brief Construction from a scalar value
|
||||
*/
|
||||
FvBasePrimaryVariables(Scalar value)
|
||||
: ParentType(value)
|
||||
{ }
|
||||
|
||||
/*!
|
||||
* \brief Assignment from another primary variables object
|
||||
*/
|
||||
FvBasePrimaryVariables(const FvBasePrimaryVariables& value) = default;
|
||||
|
||||
/*!
|
||||
* \brief Assignment from another primary variables object
|
||||
*/
|
||||
FvBasePrimaryVariables& operator=(const FvBasePrimaryVariables& value) = default;
|
||||
|
||||
/*!
|
||||
* \brief Return a primary variable intensive evaluation.
|
||||
*
|
||||
* i.e., the result represents the function f = x_i if the time index is zero, else
|
||||
* it represents the a constant f = x_i. (the difference is that in the first case,
|
||||
* the derivative w.r.t. x_i is 1, while it is 0 in the second case.
|
||||
*/
|
||||
Evaluation makeEvaluation(unsigned varIdx, unsigned timeIdx) const
|
||||
{
|
||||
if (std::is_same<Evaluation, Scalar>::value)
|
||||
return (*this)[varIdx]; // finite differences
|
||||
else {
|
||||
// automatic differentiation
|
||||
if (timeIdx == 0)
|
||||
return Toolbox::createVariable((*this)[varIdx], varIdx);
|
||||
else
|
||||
return Toolbox::createConstant((*this)[varIdx]);
|
||||
}
|
||||
}
|
||||
|
||||
/*!
|
||||
* \brief Assign the primary variables "somehow" from a fluid state
|
||||
*
|
||||
* That is without considering any consistency issues which the
|
||||
* fluid state might have. This method is guaranteed to produce
|
||||
* consistent results if the fluid state is consistent to the
|
||||
* properties at a given spatial location. (Where "consistent
|
||||
* results" means that the same fluid state can be reconstructed
|
||||
* from the primary variables.)
|
||||
*/
|
||||
template <class FluidState>
|
||||
void assignNaive(const FluidState& fluidState OPM_UNUSED)
|
||||
{
|
||||
throw std::runtime_error("The PrimaryVariables class does not define "
|
||||
"an assignNaive() method");
|
||||
}
|
||||
|
||||
/*!
|
||||
* \brief Instruct valgrind to check the definedness of all attributes of this class.
|
||||
*/
|
||||
void checkDefined() const
|
||||
{
|
||||
Opm::Valgrind::CheckDefined(*static_cast<const ParentType*>(this));
|
||||
}
|
||||
};
|
||||
|
||||
} // namespace Opm
|
||||
|
||||
namespace Dune {
|
||||
|
||||
/** Compatibility traits class for DenseVector and DenseMatrix.
|
||||
*/
|
||||
template<class TypeTag, bool>
|
||||
struct FieldTraitsImpl;
|
||||
|
||||
/** FieldTraitsImpl for classes derived from
|
||||
* Opm::FvBasePrimaryVariables: use FieldVector's FieldTraits implementation) */
|
||||
template<class TypeTag>
|
||||
struct FieldTraitsImpl< TypeTag, true >
|
||||
: public FieldTraits<FieldVector<typename GET_PROP_TYPE(TypeTag, Scalar),
|
||||
GET_PROP_VALUE(TypeTag, NumEq)> >
|
||||
{
|
||||
};
|
||||
|
||||
/** FieldTraitsImpl for classes not derived from
|
||||
* Opm::FvBasePrimaryVariables, fall bakc to existing implementation */
|
||||
template<class T>
|
||||
struct FieldTraitsImpl< T, false >
|
||||
: public FieldTraits< T >
|
||||
{
|
||||
};
|
||||
|
||||
|
||||
/** Specialization of FieldTraits for all PrimaryVariables derived from Opm::FvBasePrimaryVariables */
|
||||
template<class TypeTag, template <class> class EwomsPrimaryVariable>
|
||||
struct FieldTraits< EwomsPrimaryVariable< TypeTag > >
|
||||
: public FieldTraitsImpl< TypeTag,
|
||||
std::is_base_of< Opm::FvBasePrimaryVariables< TypeTag >,
|
||||
EwomsPrimaryVariable< TypeTag > > :: value >
|
||||
{
|
||||
};
|
||||
}
|
||||
|
||||
#endif
|
841
opm/models/discretization/common/fvbaseproblem.hh
Normal file
841
opm/models/discretization/common/fvbaseproblem.hh
Normal file
@ -0,0 +1,841 @@
|
||||
// -*- mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*-
|
||||
// vi: set et ts=4 sw=4 sts=4:
|
||||
/*
|
||||
This file is part of the Open Porous Media project (OPM).
|
||||
|
||||
OPM 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.
|
||||
|
||||
OPM is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
GNU General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU General Public License
|
||||
along with OPM. If not, see <http://www.gnu.org/licenses/>.
|
||||
|
||||
Consult the COPYING file in the top-level source directory of this
|
||||
module for the precise wording of the license and the list of
|
||||
copyright holders.
|
||||
*/
|
||||
/*!
|
||||
* \file
|
||||
*
|
||||
* \copydoc Opm::FvBaseProblem
|
||||
*/
|
||||
#ifndef EWOMS_FV_BASE_PROBLEM_HH
|
||||
#define EWOMS_FV_BASE_PROBLEM_HH
|
||||
|
||||
#include "fvbaseproperties.hh"
|
||||
|
||||
#include <ewoms/io/vtkmultiwriter.hh>
|
||||
#include <ewoms/io/restart.hh>
|
||||
#include <opm/models/discretization/common/restrictprolong.hh>
|
||||
|
||||
#include <opm/material/common/Unused.hpp>
|
||||
#include <opm/material/common/Exceptions.hpp>
|
||||
|
||||
#include <dune/common/fvector.hh>
|
||||
|
||||
#include <iostream>
|
||||
#include <limits>
|
||||
#include <string>
|
||||
|
||||
#include <sys/stat.h>
|
||||
|
||||
namespace Opm {
|
||||
|
||||
/*!
|
||||
* \ingroup FiniteVolumeDiscretizations
|
||||
*
|
||||
* \brief Base class for all problems which use a finite volume spatial discretization.
|
||||
*
|
||||
* \note All quantities are specified assuming a threedimensional world. Problems
|
||||
* discretized using 2D grids are assumed to be extruded by \f$1 m\f$ and 1D grids
|
||||
* are assumed to have a cross section of \f$1m \times 1m\f$.
|
||||
*/
|
||||
template<class TypeTag>
|
||||
class FvBaseProblem
|
||||
{
|
||||
private:
|
||||
typedef typename GET_PROP_TYPE(TypeTag, Problem) Implementation;
|
||||
typedef typename GET_PROP_TYPE(TypeTag, GridView) GridView;
|
||||
|
||||
static const int vtkOutputFormat = GET_PROP_VALUE(TypeTag, VtkOutputFormat);
|
||||
typedef Opm::VtkMultiWriter<GridView, vtkOutputFormat> VtkMultiWriter;
|
||||
|
||||
typedef typename GET_PROP_TYPE(TypeTag, Model) Model;
|
||||
typedef typename GET_PROP_TYPE(TypeTag, Scalar) Scalar;
|
||||
typedef typename GET_PROP_TYPE(TypeTag, Simulator) Simulator;
|
||||
typedef typename GET_PROP_TYPE(TypeTag, ThreadManager) ThreadManager;
|
||||
typedef typename GET_PROP_TYPE(TypeTag, NewtonMethod) NewtonMethod;
|
||||
|
||||
typedef typename GET_PROP_TYPE(TypeTag, VertexMapper) VertexMapper;
|
||||
typedef typename GET_PROP_TYPE(TypeTag, ElementMapper) ElementMapper;
|
||||
|
||||
typedef typename GET_PROP_TYPE(TypeTag, RateVector) RateVector;
|
||||
typedef typename GET_PROP_TYPE(TypeTag, BoundaryRateVector) BoundaryRateVector;
|
||||
typedef typename GET_PROP_TYPE(TypeTag, PrimaryVariables) PrimaryVariables;
|
||||
typedef typename GET_PROP_TYPE(TypeTag, Constraints) Constraints;
|
||||
|
||||
enum {
|
||||
dim = GridView::dimension,
|
||||
dimWorld = GridView::dimensionworld
|
||||
};
|
||||
|
||||
typedef typename GridView::template Codim<0>::Entity Element;
|
||||
typedef typename GridView::template Codim<dim>::Entity Vertex;
|
||||
typedef typename GridView::template Codim<dim>::Iterator VertexIterator;
|
||||
|
||||
typedef typename GridView::Grid::ctype CoordScalar;
|
||||
typedef Dune::FieldVector<CoordScalar, dimWorld> GlobalPosition;
|
||||
|
||||
public:
|
||||
// the default restriction and prolongation for adaptation is simply an empty one
|
||||
typedef EmptyRestrictProlong RestrictProlongOperator;
|
||||
|
||||
private:
|
||||
// copying a problem is not a good idea
|
||||
FvBaseProblem(const FvBaseProblem& ) = delete;
|
||||
|
||||
public:
|
||||
/*!
|
||||
* \copydoc Doxygen::defaultProblemConstructor
|
||||
*
|
||||
* \param simulator The time manager of the simulation
|
||||
* \param gridView The view on the DUNE grid which ought to be
|
||||
* used (normally the leaf grid view)
|
||||
*/
|
||||
FvBaseProblem(Simulator& simulator)
|
||||
: nextTimeStepSize_(0.0)
|
||||
, gridView_(simulator.gridView())
|
||||
#if DUNE_VERSION_NEWER(DUNE_GRID, 2,6)
|
||||
, elementMapper_(gridView_, Dune::mcmgElementLayout())
|
||||
, vertexMapper_(gridView_, Dune::mcmgVertexLayout())
|
||||
#else
|
||||
, elementMapper_(gridView_)
|
||||
, vertexMapper_(gridView_)
|
||||
#endif
|
||||
, boundingBoxMin_(std::numeric_limits<double>::max())
|
||||
, boundingBoxMax_(-std::numeric_limits<double>::max())
|
||||
, simulator_(simulator)
|
||||
, defaultVtkWriter_(0)
|
||||
{
|
||||
// calculate the bounding box of the local partition of the grid view
|
||||
VertexIterator vIt = gridView_.template begin<dim>();
|
||||
const VertexIterator vEndIt = gridView_.template end<dim>();
|
||||
for (; vIt!=vEndIt; ++vIt) {
|
||||
for (unsigned i=0; i<dim; i++) {
|
||||
boundingBoxMin_[i] = std::min(boundingBoxMin_[i], vIt->geometry().corner(0)[i]);
|
||||
boundingBoxMax_[i] = std::max(boundingBoxMax_[i], vIt->geometry().corner(0)[i]);
|
||||
}
|
||||
}
|
||||
|
||||
// communicate to get the bounding box of the whole domain
|
||||
for (unsigned i = 0; i < dim; ++i) {
|
||||
boundingBoxMin_[i] = gridView_.comm().min(boundingBoxMin_[i]);
|
||||
boundingBoxMax_[i] = gridView_.comm().max(boundingBoxMax_[i]);
|
||||
}
|
||||
|
||||
if (enableVtkOutput_()) {
|
||||
bool asyncVtkOutput =
|
||||
simulator_.gridView().comm().size() == 1 &&
|
||||
EWOMS_GET_PARAM(TypeTag, bool, EnableAsyncVtkOutput);
|
||||
|
||||
// asynchonous VTK output currently does not work in conjunction with grid
|
||||
// adaptivity because the async-IO code assumes that the grid stays
|
||||
// constant. complain about that case.
|
||||
bool enableGridAdaptation = EWOMS_GET_PARAM(TypeTag, bool, EnableGridAdaptation);
|
||||
if (asyncVtkOutput && enableGridAdaptation)
|
||||
throw std::runtime_error("Asynchronous VTK output currently cannot be used "
|
||||
"at the same time as grid adaptivity");
|
||||
|
||||
std::string outputDir = asImp_().outputDir();
|
||||
|
||||
defaultVtkWriter_ =
|
||||
new VtkMultiWriter(asyncVtkOutput, gridView_, outputDir, asImp_().name());
|
||||
}
|
||||
}
|
||||
|
||||
~FvBaseProblem()
|
||||
{ delete defaultVtkWriter_; }
|
||||
|
||||
/*!
|
||||
* \brief Registers all available parameters for the problem and
|
||||
* the model.
|
||||
*/
|
||||
static void registerParameters()
|
||||
{
|
||||
Model::registerParameters();
|
||||
EWOMS_REGISTER_PARAM(TypeTag, Scalar, MaxTimeStepSize,
|
||||
"The maximum size to which all time steps are limited to [s]");
|
||||
EWOMS_REGISTER_PARAM(TypeTag, Scalar, MinTimeStepSize,
|
||||
"The minimum size to which all time steps are limited to [s]");
|
||||
EWOMS_REGISTER_PARAM(TypeTag, unsigned, MaxTimeStepDivisions,
|
||||
"The maximum number of divisions by two of the timestep size "
|
||||
"before the simulation bails out");
|
||||
EWOMS_REGISTER_PARAM(TypeTag, bool, EnableAsyncVtkOutput,
|
||||
"Dispatch a separate thread to write the VTK output");
|
||||
EWOMS_REGISTER_PARAM(TypeTag, bool, ContinueOnConvergenceError,
|
||||
"Continue with a non-converged solution instead of giving up "
|
||||
"if we encounter a time step size smaller than the minimum time "
|
||||
"step size.");
|
||||
}
|
||||
|
||||
/*!
|
||||
* \brief Return if the storage term of the first iteration is identical to the storage
|
||||
* term for the solution of the previous time step.
|
||||
*
|
||||
* This is only relevant if the storage cache is enabled and is usually the case,
|
||||
* i.e., this method only needs to be overwritten in rare corner cases.
|
||||
*/
|
||||
bool recycleFirstIterationStorage() const
|
||||
{ return true; }
|
||||
|
||||
/*!
|
||||
* \brief Determine the directory for simulation output.
|
||||
*
|
||||
* The actual problem may chose to transform the value of the OutputDir parameter and
|
||||
* it can e.g. choose to create the directory on demand if it does not exist. The
|
||||
* default behaviour is to just return the OutputDir parameter and to throw an
|
||||
* exception if no directory with this name exists.
|
||||
*/
|
||||
std::string outputDir() const
|
||||
{
|
||||
std::string outputDir = EWOMS_GET_PARAM(TypeTag, std::string, OutputDir);
|
||||
|
||||
if (outputDir == "")
|
||||
throw std::runtime_error("No directory for output specified");
|
||||
|
||||
// TODO: replace this by std::filesystem once we require c++-2017
|
||||
struct stat st;
|
||||
if (::stat(outputDir.c_str(), &st) != 0)
|
||||
throw std::runtime_error("Could not access output directory '"+outputDir+"':"
|
||||
+strerror(errno));
|
||||
if (!S_ISDIR(st.st_mode))
|
||||
throw std::runtime_error("Path to output directory '"+outputDir+"' exists but is not a directory");
|
||||
|
||||
if (access(outputDir.c_str(), W_OK) != 0)
|
||||
throw std::runtime_error("Output directory '"+outputDir+"' exists but is not writeable");
|
||||
|
||||
return outputDir;
|
||||
}
|
||||
|
||||
/*!
|
||||
* \brief Returns the string that is printed before the list of command line
|
||||
* parameters in the help message.
|
||||
*
|
||||
* If the returned string is empty, no help message will be generated.
|
||||
*/
|
||||
static std::string helpPreamble(int argc OPM_UNUSED,
|
||||
const char **argv)
|
||||
{
|
||||
std::string desc = Implementation::briefDescription();
|
||||
if (!desc.empty())
|
||||
desc = desc + "\n";
|
||||
|
||||
return
|
||||
"Usage: "+std::string(argv[0]) + " [OPTIONS]\n"
|
||||
+ desc;
|
||||
}
|
||||
|
||||
/*!
|
||||
* \brief Returns a human readable description of the problem for the help message
|
||||
*
|
||||
* The problem description is printed as part of the --help message. It is optional
|
||||
* and should not exceed one or two lines of text.
|
||||
*/
|
||||
static std::string briefDescription()
|
||||
{ return ""; }
|
||||
|
||||
// TODO (?): detailedDescription()
|
||||
|
||||
/*!
|
||||
* \brief Handles positional command line parameters.
|
||||
*
|
||||
* Positional parameters are parameters that are not prefixed by any parameter name.
|
||||
*
|
||||
* \param seenParams The parameters which have already been seen in the current context
|
||||
* \param errorMsg If the positional argument cannot be handled, this is the reason why
|
||||
* \param argc The total number of command line parameters
|
||||
* \param argv The string value of the command line parameters
|
||||
* \param paramIdx The index of the positional parameter in the array of all parameters
|
||||
* \param posParamIdx The number of the positional parameter encountered so far
|
||||
*
|
||||
* \return The number of array entries which ought to be skipped before processing
|
||||
* the next regular parameter. If this is less than 1, it indicated that the
|
||||
* positional parameter was invalid.
|
||||
*/
|
||||
static int handlePositionalParameter(std::set<std::string>& seenParams OPM_UNUSED,
|
||||
std::string& errorMsg,
|
||||
int argc OPM_UNUSED,
|
||||
const char** argv,
|
||||
int paramIdx,
|
||||
int posParamIdx OPM_UNUSED)
|
||||
{
|
||||
errorMsg = std::string("Illegal parameter \"")+argv[paramIdx]+"\".";
|
||||
return 0;
|
||||
}
|
||||
|
||||
/*!
|
||||
* \brief Called by the Opm::Simulator in order to initialize the problem.
|
||||
*
|
||||
* If you overload this method don't forget to call ParentType::finishInit()
|
||||
*/
|
||||
void finishInit()
|
||||
{ }
|
||||
|
||||
/*!
|
||||
* \brief Allows to improve the performance by prefetching all data which is
|
||||
* associated with a given element.
|
||||
*/
|
||||
void prefetch(const Element& elem OPM_UNUSED) const
|
||||
{
|
||||
// do nothing by default
|
||||
}
|
||||
|
||||
/*!
|
||||
* \brief Handle changes of the grid
|
||||
*/
|
||||
void gridChanged()
|
||||
{
|
||||
elementMapper_.update();
|
||||
vertexMapper_.update();
|
||||
|
||||
if (enableVtkOutput_())
|
||||
defaultVtkWriter_->gridChanged();
|
||||
}
|
||||
|
||||
/*!
|
||||
* \brief Evaluate the boundary conditions for a boundary segment.
|
||||
*
|
||||
* \param values Stores the fluxes over the boundary segment.
|
||||
* \param context The object representing the execution context from
|
||||
* which this method is called.
|
||||
* \param spaceIdx The local index of the spatial entity which represents the boundary segment.
|
||||
* \param timeIdx The index used for the time discretization
|
||||
*/
|
||||
template <class Context>
|
||||
void boundary(BoundaryRateVector& values OPM_UNUSED,
|
||||
const Context& context OPM_UNUSED,
|
||||
unsigned spaceIdx OPM_UNUSED,
|
||||
unsigned timeIdx OPM_UNUSED) const
|
||||
{ throw std::logic_error("Problem does not provide a boundary() method"); }
|
||||
|
||||
/*!
|
||||
* \brief Evaluate the constraints for a control volume.
|
||||
*
|
||||
* \param constraints Stores the values of the primary variables at a
|
||||
* given spatial and temporal location.
|
||||
* \param context The object representing the execution context from
|
||||
* which this method is called.
|
||||
* \param spaceIdx The local index of the spatial entity which represents the boundary segment.
|
||||
* \param timeIdx The index used for the time discretization
|
||||
*/
|
||||
template <class Context>
|
||||
void constraints(Constraints& constrs OPM_UNUSED,
|
||||
const Context& context OPM_UNUSED,
|
||||
unsigned spaceIdx OPM_UNUSED,
|
||||
unsigned timeIdx OPM_UNUSED) const
|
||||
{ throw std::logic_error("Problem does not provide a constraints() method"); }
|
||||
|
||||
/*!
|
||||
* \brief Evaluate the source term for all phases within a given
|
||||
* sub-control-volume.
|
||||
*
|
||||
* \param rate Stores the values of the volumetric creation/anihilition
|
||||
* rates of the conserved quantities.
|
||||
* \param context The object representing the execution context from which
|
||||
* this method is called.
|
||||
* \param spaceIdx The local index of the spatial entity which represents
|
||||
* the boundary segment.
|
||||
* \param timeIdx The index used for the time discretization
|
||||
*/
|
||||
template <class Context>
|
||||
void source(RateVector& rate OPM_UNUSED,
|
||||
const Context& context OPM_UNUSED,
|
||||
unsigned spaceIdx OPM_UNUSED,
|
||||
unsigned timeIdx OPM_UNUSED) const
|
||||
{ throw std::logic_error("Problem does not provide a source() method"); }
|
||||
|
||||
/*!
|
||||
* \brief Evaluate the initial value for a control volume.
|
||||
*
|
||||
* \param values Stores the primary variables.
|
||||
* \param context The object representing the execution context from which
|
||||
* this method is called.
|
||||
* \param spaceIdx The local index of the spatial entity which represents
|
||||
* the boundary segment.
|
||||
* \param timeIdx The index used for the time discretization
|
||||
*/
|
||||
template <class Context>
|
||||
void initial(PrimaryVariables& values OPM_UNUSED,
|
||||
const Context& context OPM_UNUSED,
|
||||
unsigned spaceIdx OPM_UNUSED,
|
||||
unsigned timeIdx OPM_UNUSED) const
|
||||
{ throw std::logic_error("Problem does not provide a initial() method"); }
|
||||
|
||||
/*!
|
||||
* \brief Return how much the domain is extruded at a given sub-control volume.
|
||||
*
|
||||
* This means the factor by which a lower-dimensional (1D or 2D)
|
||||
* entity needs to be expanded to get a full dimensional cell. The
|
||||
* default is 1.0 which means that 1D problems are actually
|
||||
* thought as pipes with a cross section of 1 m^2 and 2D problems
|
||||
* are assumed to extend 1 m to the back.
|
||||
*
|
||||
* \param context The object representing the execution context from which
|
||||
* this method is called.
|
||||
* \param spaceIdx The local index of the spatial entity which represents
|
||||
* the boundary segment.
|
||||
* \param timeIdx The index used for the time discretization
|
||||
*/
|
||||
template <class Context>
|
||||
Scalar extrusionFactor(const Context& context OPM_UNUSED,
|
||||
unsigned spaceIdx OPM_UNUSED,
|
||||
unsigned timeIdx OPM_UNUSED) const
|
||||
{ return asImp_().extrusionFactor(); }
|
||||
|
||||
Scalar extrusionFactor() const
|
||||
{ return 1.0; }
|
||||
|
||||
/*!
|
||||
* \brief Callback used by the model to indicate that the initial solution has been
|
||||
* determined for all degrees of freedom.
|
||||
*/
|
||||
void initialSolutionApplied()
|
||||
{}
|
||||
|
||||
/*!
|
||||
* \brief Called at the beginning of an simulation episode.
|
||||
*/
|
||||
void beginEpisode()
|
||||
{ }
|
||||
|
||||
/*!
|
||||
* \brief Called by the simulator before each time integration.
|
||||
*/
|
||||
void beginTimeStep()
|
||||
{ }
|
||||
|
||||
/*!
|
||||
* \brief Called by the simulator before each Newton-Raphson iteration.
|
||||
*/
|
||||
void beginIteration()
|
||||
{ }
|
||||
|
||||
/*!
|
||||
* \brief Called by the simulator after each Newton-Raphson update.
|
||||
*/
|
||||
void endIteration()
|
||||
{ }
|
||||
|
||||
/*!
|
||||
* \brief Called by the simulator after each time integration.
|
||||
*
|
||||
* This method is intended to do some post processing of the
|
||||
* solution. (e.g., some additional output)
|
||||
*/
|
||||
void endTimeStep()
|
||||
{ }
|
||||
|
||||
/*!
|
||||
* \brief Called when the end of an simulation episode is reached.
|
||||
*
|
||||
* Typically, a new episode is started in this method.
|
||||
*/
|
||||
void endEpisode()
|
||||
{
|
||||
std::cerr << "The end of episode " << simulator().episodeIndex() + 1 << " has been "
|
||||
<< "reached, but the problem does not override the endEpisode() method. "
|
||||
<< "Doing nothing!\n";
|
||||
}
|
||||
|
||||
/*!
|
||||
* \brief Called after the simulation has been run sucessfully.
|
||||
*/
|
||||
void finalize()
|
||||
{
|
||||
const auto& executionTimer = simulator().executionTimer();
|
||||
|
||||
Scalar executionTime = executionTimer.realTimeElapsed();
|
||||
Scalar setupTime = simulator().setupTimer().realTimeElapsed();
|
||||
Scalar prePostProcessTime = simulator().prePostProcessTimer().realTimeElapsed();
|
||||
Scalar localCpuTime = executionTimer.cpuTimeElapsed();
|
||||
Scalar globalCpuTime = executionTimer.globalCpuTimeElapsed();
|
||||
Scalar writeTime = simulator().writeTimer().realTimeElapsed();
|
||||
Scalar linearizeTime = simulator().linearizeTimer().realTimeElapsed();
|
||||
Scalar solveTime = simulator().solveTimer().realTimeElapsed();
|
||||
Scalar updateTime = simulator().updateTimer().realTimeElapsed();
|
||||
unsigned numProcesses = static_cast<unsigned>(this->gridView().comm().size());
|
||||
unsigned threadsPerProcess = ThreadManager::maxThreads();
|
||||
if (gridView().comm().rank() == 0) {
|
||||
std::cout << std::setprecision(3)
|
||||
<< "Simulation of problem '" << asImp_().name() << "' finished.\n"
|
||||
<< "\n"
|
||||
<< "------------------------ Timing receipt ------------------------\n"
|
||||
<< "Setup time: " << setupTime << " seconds" << Simulator::humanReadableTime(setupTime)
|
||||
<< ", " << setupTime/(executionTime + setupTime)*100 << "%\n"
|
||||
<< "Simulation time: " << executionTime << " seconds" << Simulator::humanReadableTime(executionTime)
|
||||
<< ", " << executionTime/(executionTime + setupTime)*100 << "%\n"
|
||||
<< " Linearization time: " << linearizeTime << " seconds" << Simulator::humanReadableTime(linearizeTime)
|
||||
<< ", " << linearizeTime/executionTime*100 << "%\n"
|
||||
<< " Linear solve time: " << solveTime << " seconds" << Simulator::humanReadableTime(solveTime)
|
||||
<< ", " << solveTime/executionTime*100 << "%\n"
|
||||
<< " Newton update time: " << updateTime << " seconds" << Simulator::humanReadableTime(updateTime)
|
||||
<< ", " << updateTime/executionTime*100 << "%\n"
|
||||
<< " Pre/postprocess time: " << prePostProcessTime << " seconds" << Simulator::humanReadableTime(prePostProcessTime)
|
||||
<< ", " << prePostProcessTime/executionTime*100 << "%\n"
|
||||
<< " Output write time: " << writeTime << " seconds" << Simulator::humanReadableTime(writeTime)
|
||||
<< ", " << writeTime/executionTime*100 << "%\n"
|
||||
<< "First process' simulation CPU time: " << localCpuTime << " seconds" << Simulator::humanReadableTime(localCpuTime) << "\n"
|
||||
<< "Number of processes: " << numProcesses << "\n"
|
||||
<< "Threads per processes: " << threadsPerProcess << "\n"
|
||||
<< "Total CPU time: " << globalCpuTime << " seconds" << Simulator::humanReadableTime(globalCpuTime) << "\n"
|
||||
<< "\n"
|
||||
<< "Note 1: If not stated otherwise, all times are wall clock times\n"
|
||||
<< "Note 2: Taxes and administrative overhead are "
|
||||
<< (executionTime - (linearizeTime+solveTime+updateTime+prePostProcessTime+writeTime))/executionTime*100
|
||||
<< "%\n"
|
||||
<< "\n"
|
||||
<< "Our simulation hours are 24/7. Thank you for choosing us.\n"
|
||||
<< "----------------------------------------------------------------\n"
|
||||
<< "\n"
|
||||
<< std::flush;
|
||||
}
|
||||
}
|
||||
|
||||
/*!
|
||||
* \brief Called by Opm::Simulator in order to do a time
|
||||
* integration on the model.
|
||||
*/
|
||||
void timeIntegration()
|
||||
{
|
||||
unsigned maxFails = asImp_().maxTimeIntegrationFailures();
|
||||
Scalar minTimeStepSize = asImp_().minTimeStepSize();
|
||||
|
||||
std::string errorMessage;
|
||||
for (unsigned i = 0; i < maxFails; ++i) {
|
||||
bool converged = model().update();
|
||||
if (converged)
|
||||
return;
|
||||
|
||||
Scalar dt = simulator().timeStepSize();
|
||||
Scalar nextDt = dt / 2.0;
|
||||
if (dt < minTimeStepSize*(1 + 1e-9)) {
|
||||
if (asImp_().continueOnConvergenceError()) {
|
||||
if (gridView().comm().rank() == 0)
|
||||
std::cout << "Newton solver did not converge with minimum time step of "
|
||||
<< dt << " seconds. Continuing with unconverged solution!\n"
|
||||
<< std::flush;
|
||||
return;
|
||||
}
|
||||
else {
|
||||
errorMessage =
|
||||
"Time integration did not succeed with the minumum time step size of "
|
||||
+ std::to_string(double(minTimeStepSize)) + " seconds. Giving up!";
|
||||
break; // give up: we can't make the time step smaller anymore!
|
||||
}
|
||||
}
|
||||
else if (nextDt < minTimeStepSize)
|
||||
nextDt = minTimeStepSize;
|
||||
simulator().setTimeStepSize(nextDt);
|
||||
|
||||
// update failed
|
||||
if (gridView().comm().rank() == 0)
|
||||
std::cout << "Newton solver did not converge with "
|
||||
<< "dt=" << dt << " seconds. Retrying with time step of "
|
||||
<< nextDt << " seconds\n" << std::flush;
|
||||
}
|
||||
|
||||
if (errorMessage.empty())
|
||||
errorMessage =
|
||||
"Newton solver didn't converge after "
|
||||
+std::to_string(maxFails)+" time-step divisions. dt="
|
||||
+std::to_string(double(simulator().timeStepSize()));
|
||||
throw std::runtime_error(errorMessage);
|
||||
}
|
||||
|
||||
/*!
|
||||
* \brief Returns the minimum allowable size of a time step.
|
||||
*/
|
||||
Scalar minTimeStepSize() const
|
||||
{ return EWOMS_GET_PARAM(TypeTag, Scalar, MinTimeStepSize); }
|
||||
|
||||
/*!
|
||||
* \brief Returns the maximum number of subsequent failures for the time integration
|
||||
* before giving up.
|
||||
*/
|
||||
unsigned maxTimeIntegrationFailures() const
|
||||
{ return EWOMS_GET_PARAM(TypeTag, unsigned, MaxTimeStepDivisions); }
|
||||
|
||||
/*!
|
||||
* \brief Returns if we should continue with a non-converged solution instead of
|
||||
* giving up if we encounter a time step size smaller than the minimum time
|
||||
* step size.
|
||||
*/
|
||||
bool continueOnConvergenceError() const
|
||||
{ return EWOMS_GET_PARAM(TypeTag, unsigned, ContinueOnConvergenceError); }
|
||||
|
||||
/*!
|
||||
* \brief Impose the next time step size to be used externally.
|
||||
*/
|
||||
void setNextTimeStepSize(Scalar dt)
|
||||
{ nextTimeStepSize_ = dt; }
|
||||
|
||||
/*!
|
||||
* \brief Called by Opm::Simulator whenever a solution for a
|
||||
* time step has been computed and the simulation time has
|
||||
* been updated.
|
||||
*/
|
||||
Scalar nextTimeStepSize() const
|
||||
{
|
||||
if (nextTimeStepSize_ > 0.0)
|
||||
return nextTimeStepSize_;
|
||||
|
||||
Scalar dtNext = std::min(EWOMS_GET_PARAM(TypeTag, Scalar, MaxTimeStepSize),
|
||||
newtonMethod().suggestTimeStepSize(simulator().timeStepSize()));
|
||||
|
||||
if (dtNext < simulator().maxTimeStepSize()
|
||||
&& simulator().maxTimeStepSize() < dtNext*2)
|
||||
{
|
||||
dtNext = simulator().maxTimeStepSize()/2 * 1.01;
|
||||
}
|
||||
|
||||
return dtNext;
|
||||
}
|
||||
|
||||
/*!
|
||||
* \brief Returns true if a restart file should be written to
|
||||
* disk.
|
||||
*
|
||||
* The default behavior is to write one restart file every 10 time
|
||||
* steps. This method should be overwritten by the
|
||||
* implementation if the default behavior is deemed insufficient.
|
||||
*/
|
||||
bool shouldWriteRestartFile() const
|
||||
{
|
||||
return simulator().timeStepIndex() > 0 &&
|
||||
(simulator().timeStepIndex() % 10 == 0);
|
||||
}
|
||||
|
||||
/*!
|
||||
* \brief Returns true if the current solution should be written to
|
||||
* disk (i.e. as a VTK file)
|
||||
*
|
||||
* The default behavior is to write out the solution for every
|
||||
* time step. This method is should be overwritten by the
|
||||
* implementation if the default behavior is deemed insufficient.
|
||||
*/
|
||||
bool shouldWriteOutput() const
|
||||
{ return true; }
|
||||
|
||||
/*!
|
||||
* \brief Called by the simulator after everything which can be
|
||||
* done about the current time step is finished and the
|
||||
* model should be prepared to do the next time integration.
|
||||
*/
|
||||
void advanceTimeLevel()
|
||||
{ model().advanceTimeLevel(); }
|
||||
|
||||
/*!
|
||||
* \brief The problem name.
|
||||
*
|
||||
* This is used as a prefix for files generated by the simulation.
|
||||
* It is highly recommend to overwrite this method in the concrete
|
||||
* problem which is simulated.
|
||||
*/
|
||||
std::string name() const
|
||||
{ return "sim"; }
|
||||
|
||||
/*!
|
||||
* \brief The GridView which used by the problem.
|
||||
*/
|
||||
const GridView& gridView() const
|
||||
{ return gridView_; }
|
||||
|
||||
/*!
|
||||
* \brief The coordinate of the corner of the GridView's bounding
|
||||
* box with the smallest values.
|
||||
*/
|
||||
const GlobalPosition& boundingBoxMin() const
|
||||
{ return boundingBoxMin_; }
|
||||
|
||||
/*!
|
||||
* \brief The coordinate of the corner of the GridView's bounding
|
||||
* box with the largest values.
|
||||
*/
|
||||
const GlobalPosition& boundingBoxMax() const
|
||||
{ return boundingBoxMax_; }
|
||||
|
||||
/*!
|
||||
* \brief Returns the mapper for vertices to indices.
|
||||
*/
|
||||
const VertexMapper& vertexMapper() const
|
||||
{ return vertexMapper_; }
|
||||
|
||||
/*!
|
||||
* \brief Returns the mapper for elements to indices.
|
||||
*/
|
||||
const ElementMapper& elementMapper() const
|
||||
{ return elementMapper_; }
|
||||
|
||||
/*!
|
||||
* \brief Returns Simulator object used by the simulation
|
||||
*/
|
||||
Simulator& simulator()
|
||||
{ return simulator_; }
|
||||
|
||||
/*!
|
||||
* \copydoc simulator()
|
||||
*/
|
||||
const Simulator& simulator() const
|
||||
{ return simulator_; }
|
||||
|
||||
/*!
|
||||
* \brief Returns numerical model used for the problem.
|
||||
*/
|
||||
Model& model()
|
||||
{ return simulator_.model(); }
|
||||
|
||||
/*!
|
||||
* \copydoc model()
|
||||
*/
|
||||
const Model& model() const
|
||||
{ return simulator_.model(); }
|
||||
|
||||
/*!
|
||||
* \brief Returns object which implements the Newton method.
|
||||
*/
|
||||
NewtonMethod& newtonMethod()
|
||||
{ return model().newtonMethod(); }
|
||||
|
||||
/*!
|
||||
* \brief Returns object which implements the Newton method.
|
||||
*/
|
||||
const NewtonMethod& newtonMethod() const
|
||||
{ return model().newtonMethod(); }
|
||||
// \}
|
||||
|
||||
/*!
|
||||
* \brief return restriction and prolongation operator
|
||||
* \note This method has to be overloaded by the implementation.
|
||||
*/
|
||||
RestrictProlongOperator restrictProlongOperator()
|
||||
{
|
||||
return RestrictProlongOperator();
|
||||
}
|
||||
|
||||
/*!
|
||||
* \brief Mark grid cells for refinement or coarsening
|
||||
* \note This method has to be overloaded in derived classes to proper implement
|
||||
* marking of grid entities.
|
||||
*
|
||||
* \return number of marked cells (default is 0)
|
||||
*/
|
||||
unsigned markForGridAdaptation()
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
|
||||
/*!
|
||||
* \brief This method writes the complete state of the problem
|
||||
* to the harddisk.
|
||||
*
|
||||
* The file will start with the prefix returned by the name()
|
||||
* method, has the current time of the simulation clock in it's
|
||||
* name and uses the extension <tt>.ers</tt>. (Ewoms ReStart
|
||||
* file.) See Opm::Restart for details.
|
||||
*
|
||||
* \tparam Restarter The serializer type
|
||||
*
|
||||
* \param res The serializer object
|
||||
*/
|
||||
template <class Restarter>
|
||||
void serialize(Restarter& res)
|
||||
{
|
||||
if (enableVtkOutput_())
|
||||
defaultVtkWriter_->serialize(res);
|
||||
}
|
||||
|
||||
/*!
|
||||
* \brief This method restores the complete state of the problem
|
||||
* from disk.
|
||||
*
|
||||
* It is the inverse of the serialize() method.
|
||||
*
|
||||
* \tparam Restarter The deserializer type
|
||||
*
|
||||
* \param res The deserializer object
|
||||
*/
|
||||
template <class Restarter>
|
||||
void deserialize(Restarter& res)
|
||||
{
|
||||
if (enableVtkOutput_())
|
||||
defaultVtkWriter_->deserialize(res);
|
||||
}
|
||||
|
||||
/*!
|
||||
* \brief Write the relevant secondary variables of the current
|
||||
* solution into an VTK output file.
|
||||
*
|
||||
* \param verbose Specify if a message should be printed whenever a file is written
|
||||
*/
|
||||
void writeOutput(bool verbose = true)
|
||||
{
|
||||
if (!enableVtkOutput_())
|
||||
return;
|
||||
|
||||
if (verbose && gridView().comm().rank() == 0)
|
||||
std::cout << "Writing visualization results for the current time step.\n"
|
||||
<< std::flush;
|
||||
|
||||
// calculate the time _after_ the time was updated
|
||||
Scalar t = simulator().time() + simulator().timeStepSize();
|
||||
|
||||
defaultVtkWriter_->beginWrite(t);
|
||||
model().prepareOutputFields();
|
||||
model().appendOutputFields(*defaultVtkWriter_);
|
||||
defaultVtkWriter_->endWrite();
|
||||
|
||||
}
|
||||
|
||||
/*!
|
||||
* \brief Method to retrieve the VTK writer which should be used
|
||||
* to write the default ouput after each time step to disk.
|
||||
*/
|
||||
VtkMultiWriter& defaultVtkWriter() const
|
||||
{ return defaultVtkWriter_; }
|
||||
|
||||
protected:
|
||||
Scalar nextTimeStepSize_;
|
||||
|
||||
private:
|
||||
bool enableVtkOutput_() const
|
||||
{ return EWOMS_GET_PARAM(TypeTag, bool, EnableVtkOutput); }
|
||||
|
||||
//! Returns the implementation of the problem (i.e. static polymorphism)
|
||||
Implementation& asImp_()
|
||||
{ return *static_cast<Implementation *>(this); }
|
||||
|
||||
//! \copydoc asImp_()
|
||||
const Implementation& asImp_() const
|
||||
{ return *static_cast<const Implementation *>(this); }
|
||||
|
||||
// Grid management stuff
|
||||
const GridView gridView_;
|
||||
ElementMapper elementMapper_;
|
||||
VertexMapper vertexMapper_;
|
||||
GlobalPosition boundingBoxMin_;
|
||||
GlobalPosition boundingBoxMax_;
|
||||
|
||||
// Attributes required for the actual simulation
|
||||
Simulator& simulator_;
|
||||
mutable VtkMultiWriter *defaultVtkWriter_;
|
||||
};
|
||||
|
||||
} // namespace Opm
|
||||
|
||||
#endif
|
324
opm/models/discretization/common/fvbaseproperties.hh
Normal file
324
opm/models/discretization/common/fvbaseproperties.hh
Normal file
@ -0,0 +1,324 @@
|
||||
// -*- mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*-
|
||||
// vi: set et ts=4 sw=4 sts=4:
|
||||
/*
|
||||
This file is part of the Open Porous Media project (OPM).
|
||||
|
||||
OPM 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.
|
||||
|
||||
OPM is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
GNU General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU General Public License
|
||||
along with OPM. If not, see <http://www.gnu.org/licenses/>.
|
||||
|
||||
Consult the COPYING file in the top-level source directory of this
|
||||
module for the precise wording of the license and the list of
|
||||
copyright holders.
|
||||
*/
|
||||
/*!
|
||||
* \file
|
||||
* \ingroup FiniteVolumeDiscretizations
|
||||
*
|
||||
* \brief Declare the properties used by the infrastructure code of
|
||||
* the finite volume discretizations.
|
||||
*/
|
||||
#ifndef EWOMS_FV_BASE_PROPERTIES_HH
|
||||
#define EWOMS_FV_BASE_PROPERTIES_HH
|
||||
|
||||
#include "fvbasenewtonmethod.hh"
|
||||
#include "fvbaseproperties.hh"
|
||||
#include "fvbasefdlocallinearizer.hh"
|
||||
|
||||
#include <opm/models/utils/basicproperties.hh>
|
||||
#include <ewoms/io/vtkprimaryvarsmodule.hh>
|
||||
#include <opm/simulators/linalg/parallelbicgstabbackend.hh>
|
||||
|
||||
BEGIN_PROPERTIES
|
||||
|
||||
//! The type tag for models based on the finite volume schemes
|
||||
NEW_TYPE_TAG(FvBaseDiscretization,
|
||||
INHERITS_FROM(ImplicitModel,
|
||||
FvBaseNewtonMethod,
|
||||
VtkPrimaryVars));
|
||||
|
||||
|
||||
//! set the splices for the finite volume discretizations
|
||||
NEW_PROP_TAG(LinearSolverSplice);
|
||||
NEW_PROP_TAG(ParallelBiCGStabLinearSolver);
|
||||
|
||||
NEW_PROP_TAG(LocalLinearizerSplice);
|
||||
NEW_PROP_TAG(FiniteDifferenceLocalLinearizer);
|
||||
|
||||
SET_SPLICES(FvBaseDiscretization, LinearSolverSplice, LocalLinearizerSplice);
|
||||
|
||||
//! use a parallel BiCGStab linear solver by default
|
||||
SET_TAG_PROP(FvBaseDiscretization, LinearSolverSplice, ParallelBiCGStabLinearSolver);
|
||||
|
||||
//! by default, use finite differences to linearize the system of PDEs
|
||||
SET_TAG_PROP(FvBaseDiscretization, LocalLinearizerSplice, FiniteDifferenceLocalLinearizer);
|
||||
|
||||
/*!
|
||||
* \brief Representation of a function evaluation and all necessary derivatives with
|
||||
* regard to the intensive quantities of the primary variables.
|
||||
*
|
||||
* Depending on the chosen linearization method, this property may be the same as the
|
||||
* "Scalar" property (if the finite difference linearizer is used), or it may be more
|
||||
* complex (for the linearizer which uses automatic differentiation).
|
||||
*/
|
||||
NEW_PROP_TAG(Evaluation);
|
||||
|
||||
//! The type of the DUNE grid
|
||||
NEW_PROP_TAG(Grid);
|
||||
//! The type of the grid view
|
||||
NEW_PROP_TAG(GridView);
|
||||
|
||||
//! The class describing the stencil of the spatial discretization
|
||||
NEW_PROP_TAG(Stencil);
|
||||
|
||||
//! The class describing the discrete function space when dune-fem is used, otherwise it points to the stencil class
|
||||
NEW_PROP_TAG(DiscreteFunctionSpace);
|
||||
|
||||
//! The type of the problem
|
||||
NEW_PROP_TAG(Problem);
|
||||
//! The type of the base class for all problems which use this model
|
||||
NEW_PROP_TAG(BaseProblem);
|
||||
//! The type of the model
|
||||
NEW_PROP_TAG(Model);
|
||||
//! Number of equations in the system of PDEs
|
||||
NEW_PROP_TAG(NumEq);
|
||||
|
||||
//! The type of the spatial discretization used by the model
|
||||
NEW_PROP_TAG(Discretization);
|
||||
//! The discretization specific part of the local residual
|
||||
NEW_PROP_TAG(DiscLocalResidual);
|
||||
//! The type of the local residual function
|
||||
NEW_PROP_TAG(LocalResidual);
|
||||
//! The type of the local linearizer
|
||||
NEW_PROP_TAG(LocalLinearizer);
|
||||
//! Specify if elements that do not belong to the local process' grid partition should be
|
||||
//! skipped
|
||||
NEW_PROP_TAG(LinearizeNonLocalElements);
|
||||
|
||||
//! Linearizes the global non-linear system of equations
|
||||
NEW_PROP_TAG(BaseLinearizer);
|
||||
//! The class that allows to manipulate sparse matrices
|
||||
NEW_PROP_TAG(SparseMatrixAdapter);
|
||||
|
||||
//! A vector of holding a quantity for each equation (usually at a given spatial location)
|
||||
NEW_PROP_TAG(EqVector);
|
||||
//! A vector of holding a quantity for each equation for each DOF of an element
|
||||
NEW_PROP_TAG(ElementEqVector);
|
||||
//! Vector containing a quantity of for equation for each DOF of the whole grid
|
||||
NEW_PROP_TAG(GlobalEqVector);
|
||||
|
||||
//! Vector containing volumetric or areal rates of quantities
|
||||
NEW_PROP_TAG(RateVector);
|
||||
//! Type of object for specifying boundary conditions
|
||||
NEW_PROP_TAG(BoundaryRateVector);
|
||||
//! The class which represents a constraint degree of freedom
|
||||
NEW_PROP_TAG(Constraints);
|
||||
|
||||
//! Vector containing all primary variables of the grid
|
||||
NEW_PROP_TAG(SolutionVector);
|
||||
|
||||
//! A vector of primary variables within a sub-control volume
|
||||
NEW_PROP_TAG(PrimaryVariables);
|
||||
//! The secondary variables within a sub-control volume
|
||||
NEW_PROP_TAG(IntensiveQuantities);
|
||||
//! The discretization specific part of the intensive quantities
|
||||
NEW_PROP_TAG(DiscIntensiveQuantities);
|
||||
|
||||
//! The secondary variables of all degrees of freedom in an element's stencil
|
||||
NEW_PROP_TAG(ElementContext);
|
||||
//! The secondary variables of a boundary segment
|
||||
NEW_PROP_TAG(BoundaryContext);
|
||||
//! The secondary variables of a constraint degree of freedom
|
||||
NEW_PROP_TAG(ConstraintsContext);
|
||||
//! Data required to calculate a flux over a face
|
||||
NEW_PROP_TAG(ExtensiveQuantities);
|
||||
//! Calculates gradients of arbitrary quantities at flux integration points
|
||||
NEW_PROP_TAG(GradientCalculator);
|
||||
|
||||
//! The part of the intensive quantities which is specific to the spatial discretization
|
||||
NEW_PROP_TAG(DiscBaseIntensiveQuantities);
|
||||
|
||||
//! The part of the extensive quantities which is specific to the spatial discretization
|
||||
NEW_PROP_TAG(DiscExtensiveQuantities);
|
||||
|
||||
//! The part of the VTK ouput modules which is specific to the spatial discretization
|
||||
NEW_PROP_TAG(DiscBaseOutputModule);
|
||||
|
||||
//! The class to create grid communication handles
|
||||
NEW_PROP_TAG(GridCommHandleFactory);
|
||||
|
||||
/*!
|
||||
* \brief The OpenMP threads manager
|
||||
*/
|
||||
NEW_PROP_TAG(ThreadManager);
|
||||
NEW_PROP_TAG(ThreadsPerProcess);
|
||||
|
||||
//! use locking to prevent race conditions when linearizing the global system of
|
||||
//! equations in multi-threaded mode. (setting this property to true is always save, but
|
||||
//! it may slightly deter performance in multi-threaded simlations and some
|
||||
//! discretizations do not need this.)
|
||||
NEW_PROP_TAG(UseLinearizationLock);
|
||||
|
||||
// high-level simulation control
|
||||
|
||||
//! Manages the simulation time
|
||||
NEW_PROP_TAG(Simulator);
|
||||
|
||||
/*!
|
||||
* \brief Switch to enable or disable grid adaptation
|
||||
*
|
||||
* Currently grid adaptation requires the presence of the dune-FEM module. If it is not
|
||||
* available and grid adaptation is enabled, an exception is thrown.
|
||||
*/
|
||||
NEW_PROP_TAG(EnableGridAdaptation);
|
||||
|
||||
/*!
|
||||
* \brief The directory to which simulation output ought to be written to.
|
||||
*/
|
||||
NEW_PROP_TAG(OutputDir);
|
||||
|
||||
/*!
|
||||
* \brief Global switch to enable or disable the writing of VTK output files
|
||||
*
|
||||
* If writing VTK files is disabled, then the WriteVtk$FOO options do
|
||||
* not have any effect...
|
||||
*/
|
||||
NEW_PROP_TAG(EnableVtkOutput);
|
||||
|
||||
/*!
|
||||
* \brief Determines if the VTK output is written to disk asynchronously
|
||||
*
|
||||
* I.e. written to disk using a separate thread. This has only an effect if
|
||||
* EnableVtkOutput is true and if the simulation is run sequentially. The reasons for
|
||||
* this not being used for MPI-parallel simulations are that Dune's VTK output code does
|
||||
* not support multi-threaded multi-process VTK output and even if it would, the result
|
||||
* would be slower than when using synchronous output.
|
||||
*/
|
||||
NEW_PROP_TAG(EnableAsyncVtkOutput);
|
||||
|
||||
/*!
|
||||
* \brief Specify the format the VTK output is written to disk
|
||||
*
|
||||
* Possible values are:
|
||||
* - Dune::VTK::ascii (default)
|
||||
* - Dune::VTK::base64
|
||||
* - Dune::VTK::appendedraw
|
||||
* - Dune::VTK::appendedbase64
|
||||
*/
|
||||
NEW_PROP_TAG(VtkOutputFormat);
|
||||
|
||||
//! Specify whether the some degrees of fredom can be constraint
|
||||
NEW_PROP_TAG(EnableConstraints);
|
||||
|
||||
/*!
|
||||
* \brief Specify the maximum size of a time integration [s].
|
||||
*
|
||||
* The default is to not limit the step size.
|
||||
*/
|
||||
NEW_PROP_TAG(MaxTimeStepSize);
|
||||
|
||||
/*!
|
||||
* \brief Specify the minimal size of a time integration [s].
|
||||
*
|
||||
* The default is to not limit the step size.
|
||||
*/
|
||||
NEW_PROP_TAG(MinTimeStepSize);
|
||||
|
||||
/*!
|
||||
* \brief The maximum allowed number of timestep divisions for the
|
||||
* Newton solver.
|
||||
*/
|
||||
NEW_PROP_TAG(MaxTimeStepDivisions);
|
||||
|
||||
/*!
|
||||
* \brief Continue with a non-converged solution instead of giving up
|
||||
* if we encounter a time step size smaller than the minimum time
|
||||
* step size.
|
||||
*/
|
||||
NEW_PROP_TAG(ContinueOnConvergenceError);
|
||||
|
||||
/*!
|
||||
* \brief Specify whether all intensive quantities for the grid should be
|
||||
* cached in the discretization.
|
||||
*
|
||||
* This potentially reduces the CPU time, but comes at the cost of
|
||||
* higher memory consumption. In turn, the higher memory requirements
|
||||
* may cause the simulation to exhibit worse cache coherence behavior
|
||||
* which eats some of the computational benefits again.
|
||||
*/
|
||||
NEW_PROP_TAG(EnableIntensiveQuantityCache);
|
||||
|
||||
/*!
|
||||
* \brief Specify whether the storage terms for previous solutions should be cached.
|
||||
*
|
||||
* This potentially reduces the CPU time, but comes at the cost of higher memory
|
||||
* consumption.
|
||||
*/
|
||||
NEW_PROP_TAG(EnableStorageCache);
|
||||
|
||||
/*!
|
||||
* \brief Specify whether to use the already calculated solutions as
|
||||
* starting values of the intensive quantities.
|
||||
*
|
||||
* This only makes sense if the calculation of the intensive quantities is
|
||||
* very expensive (e.g. for non-linear fugacity functions where the
|
||||
* solver converges faster).
|
||||
*/
|
||||
NEW_PROP_TAG(EnableThermodynamicHints);
|
||||
|
||||
// mappers from local to global DOF indices
|
||||
|
||||
/*!
|
||||
* \brief The mapper to find the global index of a vertex.
|
||||
*/
|
||||
NEW_PROP_TAG(VertexMapper);
|
||||
|
||||
/*!
|
||||
* \brief The mapper to find the global index of an element.
|
||||
*/
|
||||
NEW_PROP_TAG(ElementMapper);
|
||||
|
||||
/*!
|
||||
* \brief The mapper to find the global index of a degree of freedom.
|
||||
*/
|
||||
NEW_PROP_TAG(DofMapper);
|
||||
|
||||
/*!
|
||||
* \brief The class which marks the border indices associated with the
|
||||
* degrees of freedom on a process boundary.
|
||||
*
|
||||
* This is required for the algebraic overlap stuff.
|
||||
*/
|
||||
NEW_PROP_TAG(BorderListCreator);
|
||||
|
||||
/*!
|
||||
* \brief The history size required by the time discretization
|
||||
*/
|
||||
NEW_PROP_TAG(TimeDiscHistorySize);
|
||||
|
||||
/*!
|
||||
* \brief Specify whether the storage terms use extensive quantities or not.
|
||||
*
|
||||
* Most models don't need this, but the (Navier-)Stokes ones do...
|
||||
*/
|
||||
NEW_PROP_TAG(ExtensiveStorageTerm);
|
||||
|
||||
//! \brief Specify whether to use volumetric residuals or not
|
||||
NEW_PROP_TAG(UseVolumetricResidual);
|
||||
|
||||
|
||||
//! Specify if experimental features should be enabled or not.
|
||||
NEW_PROP_TAG(EnableExperiments);
|
||||
|
||||
END_PROPERTIES
|
||||
|
||||
#endif
|
205
opm/models/discretization/common/restrictprolong.hh
Normal file
205
opm/models/discretization/common/restrictprolong.hh
Normal file
@ -0,0 +1,205 @@
|
||||
// -*- mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*-
|
||||
// vi: set et ts=4 sw=4 sts=4:
|
||||
/*
|
||||
This file is part of the Open Porous Media project (OPM).
|
||||
|
||||
OPM 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.
|
||||
|
||||
OPM is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
GNU General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU General Public License
|
||||
along with OPM. If not, see <http://www.gnu.org/licenses/>.
|
||||
|
||||
Consult the COPYING file in the top-level source directory of this
|
||||
module for the precise wording of the license and the list of
|
||||
copyright holders.
|
||||
*/
|
||||
#ifndef EWOMS_COPYRESTRICTPROLONG_HH
|
||||
#define EWOMS_COPYRESTRICTPROLONG_HH
|
||||
|
||||
#include <opm/material/common/Unused.hpp>
|
||||
|
||||
#if HAVE_DUNE_FEM
|
||||
#include <dune/fem/space/common/restrictprolonginterface.hh>
|
||||
#endif
|
||||
|
||||
namespace Opm
|
||||
{
|
||||
template < class Grid, class Container >
|
||||
class CopyRestrictProlong;
|
||||
|
||||
template < class Grid, class Container >
|
||||
struct CopyRestrictProlongTraits
|
||||
{
|
||||
typedef typename Grid::ctype DomainFieldType;
|
||||
typedef CopyRestrictProlong< Grid, Container > RestProlImp;
|
||||
};
|
||||
|
||||
template< class Grid, class Container >
|
||||
class CopyRestrictProlong
|
||||
#if HAVE_DUNE_FEM
|
||||
: public Dune::Fem::RestrictProlongInterfaceDefault< CopyRestrictProlongTraits< Grid, Container > >
|
||||
#endif
|
||||
{
|
||||
typedef CopyRestrictProlong< Grid, Container > ThisType;
|
||||
|
||||
Container& container_;
|
||||
public:
|
||||
typedef typename Grid::ctype DomainFieldType;
|
||||
|
||||
explicit CopyRestrictProlong( Container& container )
|
||||
: container_( container )
|
||||
{}
|
||||
|
||||
/** \brief explicit set volume ratio of son and father
|
||||
*
|
||||
* \param[in] weight volume of son / volume of father
|
||||
*
|
||||
* \note If this ratio is set, it is assume to be constant.
|
||||
*/
|
||||
template <class Field>
|
||||
void setFatherChildWeight(const Field& weight OPM_UNUSED) const
|
||||
{}
|
||||
|
||||
//! restrict data to father
|
||||
template< class Entity >
|
||||
void restrictLocal ( const Entity& father, const Entity& son, bool initialize ) const
|
||||
{
|
||||
container_.resize();
|
||||
assert( container_.codimension() == 0 );
|
||||
if( initialize )
|
||||
{
|
||||
// copy values from son to father (only once)
|
||||
container_[ father ] = container_[ son ];
|
||||
}
|
||||
}
|
||||
|
||||
//! restrict data to father
|
||||
template< class Entity, class LocalGeometry >
|
||||
void restrictLocal(const Entity& father,
|
||||
const Entity& son,
|
||||
const LocalGeometry& geometryInFather OPM_UNUSED,
|
||||
bool initialize) const
|
||||
{ restrictLocal(father, son, initialize); }
|
||||
|
||||
//! prolong data to children
|
||||
template< class Entity >
|
||||
void prolongLocal(const Entity& father,
|
||||
const Entity& son,
|
||||
bool initialize OPM_UNUSED) const
|
||||
{
|
||||
container_.resize();
|
||||
assert( container_.codimension() == 0 );
|
||||
// copy values from father to son all sons
|
||||
container_[ son ] = container_[ father ];
|
||||
}
|
||||
|
||||
//! prolong data to children
|
||||
template< class Entity, class LocalGeometry >
|
||||
void prolongLocal(const Entity& father,
|
||||
const Entity& son,
|
||||
const LocalGeometry& geometryInFather OPM_UNUSED,
|
||||
bool initialize) const
|
||||
{ prolongLocal(father, son, initialize); }
|
||||
|
||||
/** \brief add discrete function to communicator
|
||||
* \param[in] comm Communicator to add the discrete functions to
|
||||
*/
|
||||
template< class Communicator >
|
||||
void addToList(Communicator& comm OPM_UNUSED)
|
||||
{
|
||||
// TODO
|
||||
}
|
||||
|
||||
/** \brief add discrete function to load balancer
|
||||
* \param[in] lb LoadBalancer to add the discrete functions to
|
||||
*/
|
||||
template< class LoadBalancer >
|
||||
void addToLoadBalancer(LoadBalancer& lb OPM_UNUSED)
|
||||
{
|
||||
// TODO
|
||||
}
|
||||
|
||||
};
|
||||
|
||||
|
||||
class EmptyRestrictProlong;
|
||||
|
||||
struct EmptyRestrictProlongTraits
|
||||
{
|
||||
typedef double DomainFieldType;
|
||||
typedef EmptyRestrictProlong RestProlImp;
|
||||
};
|
||||
|
||||
class EmptyRestrictProlong
|
||||
#if HAVE_DUNE_FEM
|
||||
: public Dune::Fem::RestrictProlongInterfaceDefault< EmptyRestrictProlongTraits >
|
||||
#endif
|
||||
{
|
||||
typedef EmptyRestrictProlong ThisType;
|
||||
|
||||
public:
|
||||
/** \brief explicit set volume ratio of son and father
|
||||
*
|
||||
* \param[in] weight volume of son / volume of father
|
||||
*
|
||||
* \note If this ratio is set, it is assume to be constant.
|
||||
*/
|
||||
template <class Field>
|
||||
void setFatherChildWeight(const Field& weight OPM_UNUSED) const
|
||||
{ }
|
||||
|
||||
//! restrict data to father
|
||||
template< class Entity >
|
||||
void restrictLocal(const Entity& father OPM_UNUSED,
|
||||
const Entity& son OPM_UNUSED,
|
||||
bool initialize OPM_UNUSED) const
|
||||
{ }
|
||||
|
||||
//! restrict data to father
|
||||
template< class Entity, class LocalGeometry >
|
||||
void restrictLocal(const Entity& father OPM_UNUSED,
|
||||
const Entity& son OPM_UNUSED,
|
||||
const LocalGeometry& geometryInFather OPM_UNUSED,
|
||||
bool initialize OPM_UNUSED) const
|
||||
{ }
|
||||
|
||||
//! prolong data to children
|
||||
template< class Entity >
|
||||
void prolongLocal(const Entity& father OPM_UNUSED,
|
||||
const Entity& son OPM_UNUSED,
|
||||
bool initialize OPM_UNUSED) const
|
||||
{ }
|
||||
|
||||
//! prolong data to children
|
||||
template< class Entity, class LocalGeometry >
|
||||
void prolongLocal(const Entity& father OPM_UNUSED,
|
||||
const Entity& son OPM_UNUSED,
|
||||
const LocalGeometry& geometryInFather OPM_UNUSED,
|
||||
bool initialize OPM_UNUSED) const
|
||||
{ }
|
||||
|
||||
/** \brief add discrete function to communicator
|
||||
* \param[in] comm Communicator to add the discrete functions to
|
||||
*/
|
||||
template< class Communicator >
|
||||
void addToList(Communicator& comm OPM_UNUSED)
|
||||
{ }
|
||||
|
||||
/** \brief add discrete function to load balancer
|
||||
* \param[in] lb LoadBalancer to add the discrete functions to
|
||||
*/
|
||||
template< class LoadBalancer >
|
||||
void addToLoadBalancer(LoadBalancer& lb OPM_UNUSED)
|
||||
{ }
|
||||
};
|
||||
|
||||
} // namespace Opm
|
||||
|
||||
#endif
|
81
opm/models/discretization/ecfv/ecfvbaseoutputmodule.hh
Normal file
81
opm/models/discretization/ecfv/ecfvbaseoutputmodule.hh
Normal file
@ -0,0 +1,81 @@
|
||||
// -*- mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*-
|
||||
// vi: set et ts=4 sw=4 sts=4:
|
||||
/*
|
||||
This file is part of the Open Porous Media project (OPM).
|
||||
|
||||
OPM 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.
|
||||
|
||||
OPM is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
GNU General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU General Public License
|
||||
along with OPM. If not, see <http://www.gnu.org/licenses/>.
|
||||
|
||||
Consult the COPYING file in the top-level source directory of this
|
||||
module for the precise wording of the license and the list of
|
||||
copyright holders.
|
||||
*/
|
||||
/*!
|
||||
* \file
|
||||
*
|
||||
* \copydoc Opm::EcfvBaseOutputModule
|
||||
*/
|
||||
#ifndef EWOMS_ECFV_VTK_BASE_OUTPUT_MODULE_HH
|
||||
#define EWOMS_ECFV_VTK_BASE_OUTPUT_MODULE_HH
|
||||
|
||||
#include "ecfvproperties.hh"
|
||||
|
||||
#include <ewoms/io/vtkmultiwriter.hh>
|
||||
|
||||
namespace Opm {
|
||||
/*!
|
||||
* \ingroup EcfvDiscretization
|
||||
*
|
||||
* \brief Implements the discretization specific parts of writing files.
|
||||
*/
|
||||
template<class TypeTag>
|
||||
class EcfvBaseOutputModule
|
||||
{
|
||||
public:
|
||||
typedef BaseOutputWriter::Scalar Scalar;
|
||||
typedef BaseOutputWriter::Vector Vector;
|
||||
typedef BaseOutputWriter::ScalarBuffer ScalarBuffer;
|
||||
typedef BaseOutputWriter::VectorBuffer VectorBuffer;
|
||||
typedef BaseOutputWriter::TensorBuffer TensorBuffer;
|
||||
|
||||
/*!
|
||||
* \brief Add a buffer where the data is associated with the
|
||||
* degrees of freedom to the current VTK output file.
|
||||
*/
|
||||
static void attachScalarDofData_(BaseOutputWriter& baseWriter,
|
||||
ScalarBuffer& buffer,
|
||||
const std::string& name)
|
||||
{ baseWriter.attachScalarElementData(buffer, name.c_str()); }
|
||||
|
||||
/*!
|
||||
* \brief Add a buffer where the data is associated with the
|
||||
* degrees of freedom to the current VTK output file.
|
||||
*/
|
||||
static void attachVectorDofData_(BaseOutputWriter& baseWriter,
|
||||
VectorBuffer& buffer,
|
||||
const std::string& name)
|
||||
{ baseWriter.attachVectorElementData(buffer, name.c_str()); }
|
||||
|
||||
/*!
|
||||
* \brief Add a buffer where the data is associated with the
|
||||
* degrees of freedom to the current VTK output file.
|
||||
*/
|
||||
static void attachTensorDofData_(BaseOutputWriter& baseWriter,
|
||||
TensorBuffer& buffer,
|
||||
const std::string& name)
|
||||
{ baseWriter.attachTensorElementData(buffer, name.c_str()); }
|
||||
};
|
||||
|
||||
} // namespace Opm
|
||||
|
||||
#endif
|
216
opm/models/discretization/ecfv/ecfvdiscretization.hh
Normal file
216
opm/models/discretization/ecfv/ecfvdiscretization.hh
Normal file
@ -0,0 +1,216 @@
|
||||
// -*- mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*-
|
||||
// vi: set et ts=4 sw=4 sts=4:
|
||||
/*
|
||||
This file is part of the Open Porous Media project (OPM).
|
||||
|
||||
OPM 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.
|
||||
|
||||
OPM is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
GNU General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU General Public License
|
||||
along with OPM. If not, see <http://www.gnu.org/licenses/>.
|
||||
|
||||
Consult the COPYING file in the top-level source directory of this
|
||||
module for the precise wording of the license and the list of
|
||||
copyright holders.
|
||||
*/
|
||||
/*!
|
||||
* \file
|
||||
*
|
||||
* \copydoc Opm::EcfvDiscretization
|
||||
*/
|
||||
#ifndef EWOMS_ECFV_DISCRETIZATION_HH
|
||||
#define EWOMS_ECFV_DISCRETIZATION_HH
|
||||
|
||||
#include <opm/material/densead/Math.hpp>
|
||||
|
||||
#include "ecfvproperties.hh"
|
||||
#include "ecfvstencil.hh"
|
||||
#include "ecfvgridcommhandlefactory.hh"
|
||||
#include "ecfvbaseoutputmodule.hh"
|
||||
|
||||
#include <opm/simulators/linalg/elementborderlistfromgrid.hh>
|
||||
#include <opm/models/discretization/common/fvbasediscretization.hh>
|
||||
|
||||
#if HAVE_DUNE_FEM
|
||||
#include <dune/fem/space/common/functionspace.hh>
|
||||
#include <dune/fem/space/finitevolume.hh>
|
||||
#endif
|
||||
|
||||
namespace Opm {
|
||||
template <class TypeTag>
|
||||
class EcfvDiscretization;
|
||||
}
|
||||
|
||||
BEGIN_PROPERTIES
|
||||
|
||||
//! Set the stencil
|
||||
SET_PROP(EcfvDiscretization, Stencil)
|
||||
{
|
||||
private:
|
||||
typedef typename GET_PROP_TYPE(TypeTag, Scalar) Scalar;
|
||||
typedef typename GET_PROP_TYPE(TypeTag, GridView) GridView;
|
||||
|
||||
public:
|
||||
typedef Opm::EcfvStencil<Scalar, GridView> type;
|
||||
};
|
||||
|
||||
//! Mapper for the degrees of freedoms.
|
||||
SET_TYPE_PROP(EcfvDiscretization, DofMapper, typename GET_PROP_TYPE(TypeTag, ElementMapper));
|
||||
|
||||
//! The concrete class which manages the spatial discretization
|
||||
SET_TYPE_PROP(EcfvDiscretization, Discretization, Opm::EcfvDiscretization<TypeTag>);
|
||||
|
||||
//! The base class for the output modules (decides whether to write
|
||||
//! element or vertex based fields)
|
||||
SET_TYPE_PROP(EcfvDiscretization, DiscBaseOutputModule,
|
||||
Opm::EcfvBaseOutputModule<TypeTag>);
|
||||
|
||||
//! The class to create grid communication handles
|
||||
SET_TYPE_PROP(EcfvDiscretization, GridCommHandleFactory,
|
||||
Opm::EcfvGridCommHandleFactory<TypeTag>);
|
||||
|
||||
#if HAVE_DUNE_FEM
|
||||
//! Set the DiscreteFunctionSpace
|
||||
SET_PROP(EcfvDiscretization, DiscreteFunctionSpace)
|
||||
{
|
||||
private:
|
||||
typedef typename GET_PROP_TYPE(TypeTag, Scalar) Scalar;
|
||||
typedef typename GET_PROP_TYPE(TypeTag, GridPart) GridPart;
|
||||
enum { numEq = GET_PROP_VALUE(TypeTag, NumEq) };
|
||||
typedef Dune::Fem::FunctionSpace<typename GridPart::GridType::ctype,
|
||||
Scalar,
|
||||
GridPart::GridType::dimensionworld,
|
||||
numEq> FunctionSpace;
|
||||
public:
|
||||
typedef Dune::Fem::FiniteVolumeSpace< FunctionSpace, GridPart, 0 > type;
|
||||
};
|
||||
#endif
|
||||
|
||||
//! Set the border list creator for to the one of an element based
|
||||
//! method
|
||||
SET_PROP(EcfvDiscretization, BorderListCreator)
|
||||
{ private:
|
||||
typedef typename GET_PROP_TYPE(TypeTag, ElementMapper) ElementMapper;
|
||||
typedef typename GET_PROP_TYPE(TypeTag, GridView) GridView;
|
||||
public:
|
||||
typedef Opm::Linear::ElementBorderListFromGrid<GridView, ElementMapper> type;
|
||||
};
|
||||
|
||||
//! For the element centered finite volume method, ghost and overlap elements must be
|
||||
//! assembled to calculate the fluxes over the process boundary faces of the local
|
||||
//! process' grid partition
|
||||
SET_BOOL_PROP(EcfvDiscretization, LinearizeNonLocalElements, true);
|
||||
|
||||
//! locking is not required for the element centered finite volume method because race
|
||||
//! conditions cannot occur since each matrix/vector entry is written exactly once
|
||||
SET_BOOL_PROP(EcfvDiscretization, UseLinearizationLock, false);
|
||||
|
||||
END_PROPERTIES
|
||||
|
||||
namespace Opm {
|
||||
/*!
|
||||
* \ingroup EcfvDiscretization
|
||||
*
|
||||
* \brief The base class for the element-centered finite-volume discretization scheme.
|
||||
*/
|
||||
template<class TypeTag>
|
||||
class EcfvDiscretization : public FvBaseDiscretization<TypeTag>
|
||||
{
|
||||
typedef FvBaseDiscretization<TypeTag> ParentType;
|
||||
|
||||
typedef typename GET_PROP_TYPE(TypeTag, Model) Implementation;
|
||||
typedef typename GET_PROP_TYPE(TypeTag, DofMapper) DofMapper;
|
||||
typedef typename GET_PROP_TYPE(TypeTag, PrimaryVariables) PrimaryVariables;
|
||||
typedef typename GET_PROP_TYPE(TypeTag, SolutionVector) SolutionVector;
|
||||
typedef typename GET_PROP_TYPE(TypeTag, GridView) GridView;
|
||||
typedef typename GET_PROP_TYPE(TypeTag, Simulator) Simulator;
|
||||
|
||||
public:
|
||||
EcfvDiscretization(Simulator& simulator)
|
||||
: ParentType(simulator)
|
||||
{ }
|
||||
|
||||
/*!
|
||||
* \brief Returns a string of discretization's human-readable name
|
||||
*/
|
||||
static std::string discretizationName()
|
||||
{ return "ecfv"; }
|
||||
|
||||
/*!
|
||||
* \brief Returns the number of global degrees of freedom (DOFs) due to the grid
|
||||
*/
|
||||
size_t numGridDof() const
|
||||
{ return static_cast<size_t>(this->gridView_.size(/*codim=*/0)); }
|
||||
|
||||
/*!
|
||||
* \brief Mapper to convert the Dune entities of the
|
||||
* discretization's degrees of freedoms are to indices.
|
||||
*/
|
||||
const DofMapper& dofMapper() const
|
||||
{ return this->elementMapper(); }
|
||||
|
||||
/*!
|
||||
* \brief Syncronize the values of the primary variables on the
|
||||
* degrees of freedom that overlap with the neighboring
|
||||
* processes.
|
||||
*
|
||||
* For the Element Centered Finite Volume discretization, this
|
||||
* method retrieves the primary variables corresponding to
|
||||
* overlap/ghost elements from their respective master process.
|
||||
*/
|
||||
void syncOverlap()
|
||||
{
|
||||
// syncronize the solution on the ghost and overlap elements
|
||||
typedef GridCommHandleGhostSync<PrimaryVariables,
|
||||
SolutionVector,
|
||||
DofMapper,
|
||||
/*commCodim=*/0> GhostSyncHandle;
|
||||
|
||||
auto ghostSync = GhostSyncHandle(this->solution(/*timeIdx=*/0),
|
||||
asImp_().dofMapper());
|
||||
this->gridView().communicate(ghostSync,
|
||||
Dune::InteriorBorder_All_Interface,
|
||||
Dune::ForwardCommunication);
|
||||
}
|
||||
|
||||
/*!
|
||||
* \brief Serializes the current state of the model.
|
||||
*
|
||||
* \tparam Restarter The type of the serializer class
|
||||
*
|
||||
* \param res The serializer object
|
||||
*/
|
||||
template <class Restarter>
|
||||
void serialize(Restarter& res)
|
||||
{ res.template serializeEntities</*codim=*/0>(asImp_(), this->gridView_); }
|
||||
|
||||
/*!
|
||||
* \brief Deserializes the state of the model.
|
||||
*
|
||||
* \tparam Restarter The type of the serializer class
|
||||
*
|
||||
* \param res The serializer object
|
||||
*/
|
||||
template <class Restarter>
|
||||
void deserialize(Restarter& res)
|
||||
{
|
||||
res.template deserializeEntities</*codim=*/0>(asImp_(), this->gridView_);
|
||||
this->solution(/*timeIdx=*/1) = this->solution(/*timeIdx=*/0);
|
||||
}
|
||||
|
||||
private:
|
||||
Implementation& asImp_()
|
||||
{ return *static_cast<Implementation*>(this); }
|
||||
const Implementation& asImp_() const
|
||||
{ return *static_cast<const Implementation*>(this); }
|
||||
};
|
||||
} // namespace Opm
|
||||
|
||||
#endif
|
88
opm/models/discretization/ecfv/ecfvgridcommhandlefactory.hh
Normal file
88
opm/models/discretization/ecfv/ecfvgridcommhandlefactory.hh
Normal file
@ -0,0 +1,88 @@
|
||||
// -*- mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*-
|
||||
// vi: set et ts=4 sw=4 sts=4:
|
||||
/*
|
||||
This file is part of the Open Porous Media project (OPM).
|
||||
|
||||
OPM 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.
|
||||
|
||||
OPM is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
GNU General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU General Public License
|
||||
along with OPM. If not, see <http://www.gnu.org/licenses/>.
|
||||
|
||||
Consult the COPYING file in the top-level source directory of this
|
||||
module for the precise wording of the license and the list of
|
||||
copyright holders.
|
||||
*/
|
||||
/*!
|
||||
* \file
|
||||
*
|
||||
* \copydoc Opm::EcfvGridCommHandleFactory
|
||||
*/
|
||||
#ifndef EWOMS_ECFV_GRID_COMM_HANDLE_FACTORY_HH
|
||||
#define EWOMS_ECFV_GRID_COMM_HANDLE_FACTORY_HH
|
||||
|
||||
#include "ecfvproperties.hh"
|
||||
|
||||
#include <opm/models/parallel/gridcommhandles.hh>
|
||||
|
||||
namespace Opm {
|
||||
/*!
|
||||
* \ingroup EcfvDiscretization
|
||||
*
|
||||
* \brief A class which provides types for DUNE grid handles for
|
||||
* communication.
|
||||
*
|
||||
* This is required for parallel computations
|
||||
*/
|
||||
template<class TypeTag>
|
||||
class EcfvGridCommHandleFactory
|
||||
{
|
||||
typedef typename GET_PROP_TYPE(TypeTag, DofMapper) DofMapper;
|
||||
|
||||
public:
|
||||
/*!
|
||||
* \brief Return a handle which computes the minimum of a value
|
||||
* for each overlapping degree of freedom across all processes.
|
||||
*/
|
||||
template <class ValueType, class ArrayType>
|
||||
static std::shared_ptr<GridCommHandleMin<ValueType, ArrayType, DofMapper, /*commCodim=*/0> >
|
||||
minHandle(ArrayType& array, const DofMapper& dofMapper)
|
||||
{
|
||||
typedef GridCommHandleMin<ValueType, ArrayType, DofMapper, /*commCodim=*/0> Handle;
|
||||
return std::shared_ptr<Handle>(new Handle(array, dofMapper));
|
||||
}
|
||||
|
||||
/*!
|
||||
* \brief Return a handle which computes the maximum of a value
|
||||
* for each overlapping degree of freedom across all processes.
|
||||
*/
|
||||
template <class ValueType, class ArrayType>
|
||||
static std::shared_ptr<GridCommHandleMax<ValueType, ArrayType, DofMapper, /*commCodim=*/0> >
|
||||
maxHandle(ArrayType& array, const DofMapper& dofMapper)
|
||||
{
|
||||
typedef GridCommHandleMax<ValueType, ArrayType, DofMapper, /*commCodim=*/0> Handle;
|
||||
return std::shared_ptr<Handle>(new Handle(array, dofMapper));
|
||||
}
|
||||
|
||||
/*!
|
||||
* \brief Return a handle which computes the sum of all values
|
||||
* all overlapping degrees of freedom across all processes.
|
||||
*/
|
||||
template <class ValueType, class ArrayType>
|
||||
static std::shared_ptr<GridCommHandleSum<ValueType, ArrayType, DofMapper, /*commCodim=*/0> >
|
||||
sumHandle(ArrayType& array, const DofMapper& dofMapper)
|
||||
{
|
||||
typedef GridCommHandleSum<ValueType, ArrayType, DofMapper, /*commCodim=*/0> Handle;
|
||||
return std::shared_ptr<Handle>(new Handle(array, dofMapper));
|
||||
}
|
||||
};
|
||||
} // namespace Opm
|
||||
|
||||
#endif
|
43
opm/models/discretization/ecfv/ecfvproperties.hh
Normal file
43
opm/models/discretization/ecfv/ecfvproperties.hh
Normal file
@ -0,0 +1,43 @@
|
||||
// -*- mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*-
|
||||
// vi: set et ts=4 sw=4 sts=4:
|
||||
/*
|
||||
This file is part of the Open Porous Media project (OPM).
|
||||
|
||||
OPM 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.
|
||||
|
||||
OPM is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
GNU General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU General Public License
|
||||
along with OPM. If not, see <http://www.gnu.org/licenses/>.
|
||||
|
||||
Consult the COPYING file in the top-level source directory of this
|
||||
module for the precise wording of the license and the list of
|
||||
copyright holders.
|
||||
*/
|
||||
/*!
|
||||
* \file
|
||||
*
|
||||
* \brief Declare the basic properties used by the common infrastructure of
|
||||
* the element-centered finite volume discretization.
|
||||
*/
|
||||
#ifndef EWOMS_ECFV_PROPERTIES_HH
|
||||
#define EWOMS_ECFV_PROPERTIES_HH
|
||||
|
||||
#include <opm/models/discretization/common/fvbaseproperties.hh>
|
||||
|
||||
#include <opm/models/utils/propertysystem.hh>
|
||||
|
||||
BEGIN_PROPERTIES
|
||||
|
||||
//! The type tag for models based on the ECFV-scheme
|
||||
NEW_TYPE_TAG(EcfvDiscretization, INHERITS_FROM(FvBaseDiscretization));
|
||||
|
||||
END_PROPERTIES
|
||||
|
||||
#endif
|
399
opm/models/discretization/ecfv/ecfvstencil.hh
Normal file
399
opm/models/discretization/ecfv/ecfvstencil.hh
Normal file
@ -0,0 +1,399 @@
|
||||
// -*- mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*-
|
||||
// vi: set et ts=4 sw=4 sts=4:
|
||||
/*
|
||||
This file is part of the Open Porous Media project (OPM).
|
||||
|
||||
OPM 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.
|
||||
|
||||
OPM is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
GNU General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU General Public License
|
||||
along with OPM. If not, see <http://www.gnu.org/licenses/>.
|
||||
|
||||
Consult the COPYING file in the top-level source directory of this
|
||||
module for the precise wording of the license and the list of
|
||||
copyright holders.
|
||||
*/
|
||||
/*!
|
||||
* \file
|
||||
*
|
||||
* \copydoc Opm::EcfvStencil
|
||||
*/
|
||||
#ifndef EWOMS_ECFV_STENCIL_HH
|
||||
#define EWOMS_ECFV_STENCIL_HH
|
||||
|
||||
#include <opm/models/utils/quadraturegeometries.hh>
|
||||
|
||||
#include <opm/material/common/ConditionalStorage.hpp>
|
||||
|
||||
#include <dune/grid/common/mcmgmapper.hh>
|
||||
#include <dune/grid/common/intersectioniterator.hh>
|
||||
#include <dune/geometry/type.hh>
|
||||
#include <dune/common/fvector.hh>
|
||||
#include <dune/common/version.hh>
|
||||
|
||||
#include <vector>
|
||||
|
||||
namespace Opm {
|
||||
/*!
|
||||
* \ingroup EcfvDiscretization
|
||||
*
|
||||
* \brief Represents the stencil (finite volume geometry) of a single
|
||||
* element in the ECFV discretization.
|
||||
*
|
||||
* The ECFV discretization is a element centered finite volume
|
||||
* approach. This means that each element corresponds to a control
|
||||
* volume.
|
||||
*/
|
||||
template <class Scalar,
|
||||
class GridView,
|
||||
bool needFaceIntegrationPos = true,
|
||||
bool needFaceNormal = true>
|
||||
class EcfvStencil
|
||||
{
|
||||
enum { dimWorld = GridView::dimensionworld };
|
||||
|
||||
typedef typename GridView::ctype CoordScalar;
|
||||
typedef typename GridView::Intersection Intersection;
|
||||
typedef typename GridView::template Codim<0>::Entity Element;
|
||||
|
||||
#if DUNE_VERSION_NEWER(DUNE_GRID, 2,6)
|
||||
typedef Dune::MultipleCodimMultipleGeomTypeMapper<GridView> ElementMapper;
|
||||
#else
|
||||
typedef Dune::MultipleCodimMultipleGeomTypeMapper<GridView, Dune::MCMGElementLayout> ElementMapper;
|
||||
#endif
|
||||
|
||||
typedef Dune::FieldVector<CoordScalar, dimWorld> GlobalPosition;
|
||||
|
||||
typedef Dune::FieldVector<Scalar, dimWorld> WorldVector;
|
||||
|
||||
public:
|
||||
typedef Element Entity;
|
||||
typedef ElementMapper Mapper;
|
||||
|
||||
typedef typename Element::Geometry LocalGeometry;
|
||||
|
||||
/*!
|
||||
* \brief Represents a sub-control volume.
|
||||
*
|
||||
* For element centered finite volumes, this is equivalent to the
|
||||
* element, in the vertex centered finite volume approach, this
|
||||
* corresponds to the intersection of a finite volume and the
|
||||
* grid element.
|
||||
*/
|
||||
class SubControlVolume
|
||||
{
|
||||
public:
|
||||
// default construct an uninitialized object.
|
||||
// this is only here because std::vector needs it...
|
||||
SubControlVolume()
|
||||
{}
|
||||
|
||||
SubControlVolume(const Element& element)
|
||||
: element_(element)
|
||||
{ update(); }
|
||||
|
||||
void update(const Element& element)
|
||||
{ element_ = element; }
|
||||
|
||||
void update()
|
||||
{
|
||||
const auto& geometry = element_.geometry();
|
||||
centerPos_ = geometry.center();
|
||||
volume_ = geometry.volume();
|
||||
}
|
||||
|
||||
/*!
|
||||
* \brief The global position associated with the sub-control volume
|
||||
*/
|
||||
const GlobalPosition& globalPos() const
|
||||
{ return centerPos_; }
|
||||
|
||||
/*!
|
||||
* \brief The center of the sub-control volume
|
||||
*/
|
||||
const GlobalPosition& center() const
|
||||
{ return centerPos_; }
|
||||
|
||||
/*!
|
||||
* \brief The volume [m^3] occupied by the sub-control volume
|
||||
*/
|
||||
Scalar volume() const
|
||||
{ return volume_; }
|
||||
|
||||
/*!
|
||||
* \brief The geometry of the sub-control volume.
|
||||
*/
|
||||
const LocalGeometry geometry() const
|
||||
{ return element_.geometry(); }
|
||||
|
||||
/*!
|
||||
* \brief Geometry of the sub-control volume relative to parent.
|
||||
*/
|
||||
const LocalGeometry localGeometry() const
|
||||
{ return element_.geometryInFather(); }
|
||||
|
||||
private:
|
||||
GlobalPosition centerPos_;
|
||||
Scalar volume_;
|
||||
Element element_;
|
||||
};
|
||||
|
||||
/*!
|
||||
* \brief Represents a face of a sub-control volume.
|
||||
*/
|
||||
template <bool needIntegrationPos, bool needNormal>
|
||||
class EcfvSubControlVolumeFace
|
||||
{
|
||||
public:
|
||||
EcfvSubControlVolumeFace()
|
||||
{}
|
||||
|
||||
EcfvSubControlVolumeFace(const Intersection& intersection, unsigned localNeighborIdx)
|
||||
{
|
||||
exteriorIdx_ = static_cast<unsigned short>(localNeighborIdx);
|
||||
|
||||
if (needNormal)
|
||||
(*normal_) = intersection.centerUnitOuterNormal();
|
||||
|
||||
const auto& geometry = intersection.geometry();
|
||||
if (needIntegrationPos)
|
||||
(*integrationPos_) = geometry.center();
|
||||
area_ = geometry.volume();
|
||||
}
|
||||
|
||||
/*!
|
||||
* \brief Returns the local index of the degree of freedom to
|
||||
* the face's interior.
|
||||
*/
|
||||
unsigned short interiorIndex() const
|
||||
{
|
||||
// The local index of the control volume in the interior
|
||||
// of a face of the stencil in the element centered finite
|
||||
// volume discretization is always the "central"
|
||||
// element. In this implementation this element always has
|
||||
// index 0....
|
||||
return 0;
|
||||
}
|
||||
|
||||
/*!
|
||||
* \brief Returns the local index of the degree of freedom to
|
||||
* the face's outside.
|
||||
*/
|
||||
unsigned short exteriorIndex() const
|
||||
{ return exteriorIdx_; }
|
||||
|
||||
/*!
|
||||
* \brief Returns the global position of the face's
|
||||
* integration point.
|
||||
*/
|
||||
const GlobalPosition& integrationPos() const
|
||||
{ return *integrationPos_; }
|
||||
|
||||
/*!
|
||||
* \brief Returns the outer unit normal at the face's
|
||||
* integration point.
|
||||
*/
|
||||
const WorldVector& normal() const
|
||||
{ return *normal_; }
|
||||
|
||||
/*!
|
||||
* \brief Returns the area [m^2] of the face
|
||||
*/
|
||||
Scalar area() const
|
||||
{ return area_; }
|
||||
|
||||
private:
|
||||
Opm::ConditionalStorage<needIntegrationPos, GlobalPosition> integrationPos_;
|
||||
Opm::ConditionalStorage<needNormal, WorldVector> normal_;
|
||||
Scalar area_;
|
||||
|
||||
unsigned short exteriorIdx_;
|
||||
};
|
||||
|
||||
typedef EcfvSubControlVolumeFace<needFaceIntegrationPos, needFaceNormal> SubControlVolumeFace;
|
||||
typedef EcfvSubControlVolumeFace</*needFaceIntegrationPos=*/true, needFaceNormal> BoundaryFace;
|
||||
|
||||
EcfvStencil(const GridView& gridView, const Mapper& mapper)
|
||||
: gridView_(gridView)
|
||||
, elementMapper_(mapper)
|
||||
{
|
||||
// try to ensure that the mapper passed indeed maps elements
|
||||
assert(int(gridView.size(/*codim=*/0)) == int(elementMapper_.size()));
|
||||
}
|
||||
|
||||
void updateTopology(const Element& element)
|
||||
{
|
||||
auto isIt = gridView_.ibegin(element);
|
||||
const auto& endIsIt = gridView_.iend(element);
|
||||
|
||||
// add the "center" element of the stencil
|
||||
subControlVolumes_.clear();
|
||||
subControlVolumes_.emplace_back(/*SubControlVolume(*/element/*)*/);
|
||||
elements_.clear();
|
||||
elements_.emplace_back(element);
|
||||
|
||||
interiorFaces_.clear();
|
||||
boundaryFaces_.clear();
|
||||
|
||||
for (; isIt != endIsIt; ++isIt) {
|
||||
const auto& intersection = *isIt;
|
||||
// if the current intersection has a neighbor, add a
|
||||
// degree of freedom and an internal face, else add a
|
||||
// boundary face
|
||||
if (intersection.neighbor()) {
|
||||
elements_.emplace_back( intersection.outside() );
|
||||
subControlVolumes_.emplace_back(/*SubControlVolume(*/elements_.back()/*)*/);
|
||||
interiorFaces_.emplace_back(/*SubControlVolumeFace(*/intersection, subControlVolumes_.size() - 1/*)*/);
|
||||
}
|
||||
else {
|
||||
boundaryFaces_.emplace_back(/*SubControlVolumeFace(*/intersection, - 10000/*)*/);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void updatePrimaryTopology(const Element& element)
|
||||
{
|
||||
// add the "center" element of the stencil
|
||||
subControlVolumes_.clear();
|
||||
subControlVolumes_.emplace_back(/*SubControlVolume(*/element/*)*/);
|
||||
elements_.clear();
|
||||
elements_.emplace_back(element);
|
||||
}
|
||||
|
||||
void update(const Element& element)
|
||||
{
|
||||
updateTopology(element);
|
||||
}
|
||||
|
||||
void updateCenterGradients()
|
||||
{
|
||||
assert(false); // not yet implemented
|
||||
}
|
||||
|
||||
/*!
|
||||
* \brief Return the element to which the stencil refers.
|
||||
*/
|
||||
const Element& element() const
|
||||
{ return element( 0 ); }
|
||||
|
||||
/*!
|
||||
* \brief Return the grid view of the element to which the stencil
|
||||
* refers.
|
||||
*/
|
||||
const GridView& gridView() const
|
||||
{ return *gridView_; }
|
||||
|
||||
/*!
|
||||
* \brief Returns the number of degrees of freedom which the
|
||||
* current element interacts with.
|
||||
*/
|
||||
size_t numDof() const
|
||||
{ return subControlVolumes_.size(); }
|
||||
|
||||
/*!
|
||||
* \brief Returns the number of degrees of freedom which are contained
|
||||
* by within the current element.
|
||||
*
|
||||
* Primary DOFs are always expected to have a lower index than
|
||||
* "secondary" DOFs.
|
||||
*
|
||||
* For element centered finite elements, this is only the central DOF.
|
||||
*/
|
||||
size_t numPrimaryDof() const
|
||||
{ return 1; }
|
||||
|
||||
/*!
|
||||
* \brief Return the global space index given the index of a degree of
|
||||
* freedom.
|
||||
*/
|
||||
unsigned globalSpaceIndex(unsigned dofIdx) const
|
||||
{
|
||||
assert(0 <= dofIdx && dofIdx < numDof());
|
||||
|
||||
return static_cast<unsigned>(elementMapper_.index(element(dofIdx)));
|
||||
}
|
||||
|
||||
/*!
|
||||
* \brief Return partition type of a given degree of freedom
|
||||
*/
|
||||
Dune::PartitionType partitionType(unsigned dofIdx) const
|
||||
{ return elements_[dofIdx]->partitionType(); }
|
||||
|
||||
/*!
|
||||
* \brief Return the element given the index of a degree of
|
||||
* freedom.
|
||||
*
|
||||
* If no degree of freedom index is passed, the element which was
|
||||
* passed to the update() method is returned...
|
||||
*/
|
||||
const Element& element(unsigned dofIdx) const
|
||||
{
|
||||
assert(0 <= dofIdx && dofIdx < numDof());
|
||||
|
||||
return elements_[dofIdx];
|
||||
}
|
||||
|
||||
/*!
|
||||
* \brief Return the entity given the index of a degree of
|
||||
* freedom.
|
||||
*/
|
||||
const Entity& entity(unsigned dofIdx) const
|
||||
{
|
||||
return element( dofIdx );
|
||||
}
|
||||
|
||||
/*!
|
||||
* \brief Returns the sub-control volume object belonging to a
|
||||
* given degree of freedom.
|
||||
*/
|
||||
const SubControlVolume& subControlVolume(unsigned dofIdx) const
|
||||
{ return subControlVolumes_[dofIdx]; }
|
||||
|
||||
/*!
|
||||
* \brief Returns the number of interior faces of the stencil.
|
||||
*/
|
||||
size_t numInteriorFaces() const
|
||||
{ return interiorFaces_.size(); }
|
||||
|
||||
/*!
|
||||
* \brief Returns the face object belonging to a given face index
|
||||
* in the interior of the domain.
|
||||
*/
|
||||
const SubControlVolumeFace& interiorFace(unsigned faceIdx) const
|
||||
{ return interiorFaces_[faceIdx]; }
|
||||
|
||||
/*!
|
||||
* \brief Returns the number of boundary faces of the stencil.
|
||||
*/
|
||||
size_t numBoundaryFaces() const
|
||||
{ return boundaryFaces_.size(); }
|
||||
|
||||
/*!
|
||||
* \brief Returns the boundary face object belonging to a given
|
||||
* boundary face index.
|
||||
*/
|
||||
const BoundaryFace& boundaryFace(unsigned bfIdx) const
|
||||
{ return boundaryFaces_[bfIdx]; }
|
||||
|
||||
protected:
|
||||
const GridView& gridView_;
|
||||
const ElementMapper& elementMapper_;
|
||||
|
||||
std::vector<Element> elements_;
|
||||
std::vector<SubControlVolume> subControlVolumes_;
|
||||
std::vector<SubControlVolumeFace> interiorFaces_;
|
||||
std::vector<BoundaryFace> boundaryFaces_;
|
||||
};
|
||||
|
||||
} // namespace Opm
|
||||
|
||||
|
||||
#endif
|
||||
|
365
opm/models/discretization/vcfv/p1fegradientcalculator.hh
Normal file
365
opm/models/discretization/vcfv/p1fegradientcalculator.hh
Normal file
@ -0,0 +1,365 @@
|
||||
// -*- mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*-
|
||||
// vi: set et ts=4 sw=4 sts=4:
|
||||
/*
|
||||
This file is part of the Open Porous Media project (OPM).
|
||||
|
||||
OPM 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.
|
||||
|
||||
OPM is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
GNU General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU General Public License
|
||||
along with OPM. If not, see <http://www.gnu.org/licenses/>.
|
||||
|
||||
Consult the COPYING file in the top-level source directory of this
|
||||
module for the precise wording of the license and the list of
|
||||
copyright holders.
|
||||
*/
|
||||
/*!
|
||||
* \file
|
||||
*
|
||||
* \copydoc Opm::P1FeGradientCalculator
|
||||
*/
|
||||
#ifndef EWOMS_P1FE_GRADIENT_CALCULATOR_HH
|
||||
#define EWOMS_P1FE_GRADIENT_CALCULATOR_HH
|
||||
|
||||
#include "vcfvproperties.hh"
|
||||
|
||||
#include <opm/models/discretization/common/fvbasegradientcalculator.hh>
|
||||
|
||||
#include <dune/common/fvector.hh>
|
||||
#include <dune/common/version.hh>
|
||||
|
||||
#include <dune/geometry/type.hh>
|
||||
|
||||
#if HAVE_DUNE_LOCALFUNCTIONS
|
||||
#include <dune/localfunctions/lagrange/pqkfactory.hh>
|
||||
#endif // HAVE_DUNE_LOCALFUNCTIONS
|
||||
|
||||
#include <dune/common/fvector.hh>
|
||||
|
||||
#include <vector>
|
||||
|
||||
#ifdef HAVE_DUNE_LOCALFUNCTIONS
|
||||
#define EWOMS_NO_LOCALFUNCTIONS_UNUSED
|
||||
#else
|
||||
#define EWOMS_NO_LOCALFUNCTIONS_UNUSED OPM_UNUSED
|
||||
#endif
|
||||
|
||||
namespace Opm {
|
||||
/*!
|
||||
* \ingroup FiniteElementDiscretizations
|
||||
*
|
||||
* \brief This class calculates gradients of arbitrary quantities at flux integration
|
||||
* points using first order finite elemens ansatz functions.
|
||||
*
|
||||
* This approach can also be used for the vertex-centered finite volume (VCFV)
|
||||
* discretization.
|
||||
*/
|
||||
template<class TypeTag>
|
||||
class P1FeGradientCalculator : public FvBaseGradientCalculator<TypeTag>
|
||||
{
|
||||
typedef FvBaseGradientCalculator<TypeTag> ParentType;
|
||||
typedef typename GET_PROP_TYPE(TypeTag, Scalar) Scalar;
|
||||
typedef typename GET_PROP_TYPE(TypeTag, Evaluation) Evaluation;
|
||||
typedef typename GET_PROP_TYPE(TypeTag, GridView) GridView;
|
||||
typedef typename GET_PROP_TYPE(TypeTag, ElementContext) ElementContext;
|
||||
|
||||
enum { dim = GridView::dimension };
|
||||
|
||||
// set the maximum number of degrees of freedom and the maximum
|
||||
// number of flux approximation points per elements. For this, we
|
||||
// assume cubes as the type of element with the most vertices...
|
||||
enum { maxDof = (2 << dim) };
|
||||
enum { maxFap = maxDof };
|
||||
|
||||
typedef typename GridView::ctype CoordScalar;
|
||||
typedef Dune::FieldVector<Scalar, dim> DimVector;
|
||||
|
||||
#if HAVE_DUNE_LOCALFUNCTIONS
|
||||
typedef Dune::PQkLocalFiniteElementCache<CoordScalar, Scalar, dim, 1> LocalFiniteElementCache;
|
||||
typedef typename LocalFiniteElementCache::FiniteElementType LocalFiniteElement;
|
||||
typedef typename LocalFiniteElement::Traits::LocalBasisType::Traits LocalBasisTraits;
|
||||
typedef typename LocalBasisTraits::JacobianType ShapeJacobian;
|
||||
#endif // HAVE_DUNE_LOCALFUNCTIONS
|
||||
|
||||
public:
|
||||
/*!
|
||||
* \brief Precomputes the common values to calculate gradients and
|
||||
* values of quantities at any flux approximation point.
|
||||
*
|
||||
* \param elemCtx The current execution context
|
||||
*/
|
||||
template <bool prepareValues = true, bool prepareGradients = true>
|
||||
void prepare(const ElementContext& elemCtx EWOMS_NO_LOCALFUNCTIONS_UNUSED,
|
||||
unsigned timeIdx EWOMS_NO_LOCALFUNCTIONS_UNUSED)
|
||||
{
|
||||
if (GET_PROP_VALUE(TypeTag, UseP1FiniteElementGradients)) {
|
||||
#if !HAVE_DUNE_LOCALFUNCTIONS
|
||||
// The dune-localfunctions module is required for P1 finite element gradients
|
||||
throw std::logic_error("The dune-localfunctions module is required in oder to use"
|
||||
" finite element gradients");
|
||||
#else
|
||||
const auto& stencil = elemCtx.stencil(timeIdx);
|
||||
|
||||
const LocalFiniteElement& localFE = feCache_.get(elemCtx.element().type());
|
||||
localFiniteElement_ = &localFE;
|
||||
|
||||
// loop over all face centeres
|
||||
for (unsigned faceIdx = 0; faceIdx < stencil.numInteriorFaces(); ++faceIdx) {
|
||||
const auto& localFacePos = stencil.interiorFace(faceIdx).localPos();
|
||||
|
||||
// Evaluate the P1 shape functions and their gradients at all
|
||||
// flux approximation points.
|
||||
if (prepareValues)
|
||||
localFE.localBasis().evaluateFunction(localFacePos, p1Value_[faceIdx]);
|
||||
|
||||
if (prepareGradients) {
|
||||
// first, get the shape function's gradient in local coordinates
|
||||
std::vector<ShapeJacobian> localGradient;
|
||||
localFE.localBasis().evaluateJacobian(localFacePos, localGradient);
|
||||
|
||||
// convert to a gradient in global space by
|
||||
// multiplying with the inverse transposed jacobian of
|
||||
// the position
|
||||
const auto& geom = elemCtx.element().geometry();
|
||||
const auto& jacInvT =
|
||||
geom.jacobianInverseTransposed(localFacePos);
|
||||
|
||||
size_t numVertices = elemCtx.numDof(timeIdx);
|
||||
for (unsigned vertIdx = 0; vertIdx < numVertices; vertIdx++) {
|
||||
jacInvT.mv(/*xVector=*/localGradient[vertIdx][0],
|
||||
/*destVector=*/p1Gradient_[faceIdx][vertIdx]);
|
||||
}
|
||||
}
|
||||
}
|
||||
#endif
|
||||
}
|
||||
else
|
||||
ParentType::template prepare<prepareValues, prepareGradients>(elemCtx, timeIdx);
|
||||
}
|
||||
|
||||
/*!
|
||||
* \brief Calculates the value of an arbitrary quantity at any
|
||||
* interior flux approximation point.
|
||||
*
|
||||
* \param elemCtx The current execution context
|
||||
* \param fapIdx The local index of the flux approximation point
|
||||
* in the current element's stencil.
|
||||
* \param quantityCallback A callable object returning the value
|
||||
* of the quantity at an index of a degree of
|
||||
* freedom
|
||||
*/
|
||||
template <class QuantityCallback>
|
||||
auto calculateScalarValue(const ElementContext& elemCtx EWOMS_NO_LOCALFUNCTIONS_UNUSED,
|
||||
unsigned fapIdx EWOMS_NO_LOCALFUNCTIONS_UNUSED,
|
||||
const QuantityCallback& quantityCallback EWOMS_NO_LOCALFUNCTIONS_UNUSED) const
|
||||
-> typename std::remove_reference<typename QuantityCallback::ResultType>::type
|
||||
{
|
||||
if (GET_PROP_VALUE(TypeTag, UseP1FiniteElementGradients)) {
|
||||
#if !HAVE_DUNE_LOCALFUNCTIONS
|
||||
// The dune-localfunctions module is required for P1 finite element gradients
|
||||
throw std::logic_error("The dune-localfunctions module is required in oder to use"
|
||||
" finite element gradients");
|
||||
#else
|
||||
typedef typename std::remove_reference<typename QuantityCallback::ResultType>::type QuantityConstType;
|
||||
typedef typename std::remove_const<QuantityConstType>::type QuantityType;
|
||||
typedef Opm::MathToolbox<QuantityType> Toolbox;
|
||||
|
||||
// If the user does not want to use two-point gradients, we
|
||||
// use P1 finite element gradients..
|
||||
QuantityType value(0.0);
|
||||
for (unsigned vertIdx = 0; vertIdx < elemCtx.numDof(/*timeIdx=*/0); ++vertIdx) {
|
||||
if (std::is_same<QuantityType, Scalar>::value ||
|
||||
elemCtx.focusDofIndex() == vertIdx)
|
||||
value += quantityCallback(vertIdx)*p1Value_[fapIdx][vertIdx];
|
||||
else
|
||||
value += Toolbox::value(quantityCallback(vertIdx))*p1Value_[fapIdx][vertIdx];
|
||||
}
|
||||
|
||||
return value;
|
||||
#endif
|
||||
}
|
||||
else
|
||||
return ParentType::calculateScalarValue(elemCtx, fapIdx, quantityCallback);
|
||||
}
|
||||
|
||||
/*!
|
||||
* \brief Calculates the value of an arbitrary quantity at any
|
||||
* interior flux approximation point.
|
||||
*
|
||||
* \param elemCtx The current execution context
|
||||
* \param fapIdx The local index of the flux approximation point
|
||||
* in the current element's stencil.
|
||||
* \param quantityCallback A callable object returning the value
|
||||
* of the quantity at an index of a degree of
|
||||
* freedom
|
||||
*/
|
||||
template <class QuantityCallback>
|
||||
auto calculateVectorValue(const ElementContext& elemCtx EWOMS_NO_LOCALFUNCTIONS_UNUSED,
|
||||
unsigned fapIdx EWOMS_NO_LOCALFUNCTIONS_UNUSED,
|
||||
const QuantityCallback& quantityCallback EWOMS_NO_LOCALFUNCTIONS_UNUSED) const
|
||||
-> typename std::remove_reference<typename QuantityCallback::ResultType>::type
|
||||
{
|
||||
if (GET_PROP_VALUE(TypeTag, UseP1FiniteElementGradients)) {
|
||||
#if !HAVE_DUNE_LOCALFUNCTIONS
|
||||
// The dune-localfunctions module is required for P1 finite element gradients
|
||||
throw std::logic_error("The dune-localfunctions module is required in oder to use"
|
||||
" finite element gradients");
|
||||
#else
|
||||
typedef typename std::remove_reference<typename QuantityCallback::ResultType>::type QuantityConstType;
|
||||
typedef typename std::remove_const<QuantityConstType>::type QuantityType;
|
||||
|
||||
typedef decltype(std::declval<QuantityType>()[0]) RawFieldType;
|
||||
typedef typename std::remove_const<typename std::remove_reference<RawFieldType>::type>::type FieldType;
|
||||
|
||||
typedef Opm::MathToolbox<FieldType> Toolbox;
|
||||
|
||||
// If the user does not want to use two-point gradients, we
|
||||
// use P1 finite element gradients..
|
||||
QuantityType value(0.0);
|
||||
for (unsigned vertIdx = 0; vertIdx < elemCtx.numDof(/*timeIdx=*/0); ++vertIdx) {
|
||||
if (std::is_same<QuantityType, Scalar>::value ||
|
||||
elemCtx.focusDofIndex() == vertIdx)
|
||||
{
|
||||
const auto& tmp = quantityCallback(vertIdx);
|
||||
for (unsigned k = 0; k < tmp.size(); ++k)
|
||||
value[k] += tmp[k]*p1Value_[fapIdx][vertIdx];
|
||||
}
|
||||
else {
|
||||
const auto& tmp = quantityCallback(vertIdx);
|
||||
for (unsigned k = 0; k < tmp.size(); ++k)
|
||||
value[k] += Toolbox::value(tmp[k])*p1Value_[fapIdx][vertIdx];
|
||||
}
|
||||
}
|
||||
|
||||
return value;
|
||||
#endif
|
||||
}
|
||||
else
|
||||
return ParentType::calculateVectorValue(elemCtx, fapIdx, quantityCallback);
|
||||
}
|
||||
|
||||
/*!
|
||||
* \brief Calculates the gradient of an arbitrary quantity at any
|
||||
* flux approximation point.
|
||||
*
|
||||
* \param elemCtx The current execution context
|
||||
* \param fapIdx The local index of the flux approximation point
|
||||
* in the current element's stencil.
|
||||
* \param quantityCallback A callable object returning the value
|
||||
* of the quantity at an index of a degree of
|
||||
* freedom
|
||||
*/
|
||||
template <class QuantityCallback, class EvalDimVector>
|
||||
void calculateGradient(EvalDimVector& quantityGrad EWOMS_NO_LOCALFUNCTIONS_UNUSED,
|
||||
const ElementContext& elemCtx EWOMS_NO_LOCALFUNCTIONS_UNUSED,
|
||||
unsigned fapIdx EWOMS_NO_LOCALFUNCTIONS_UNUSED,
|
||||
const QuantityCallback& quantityCallback EWOMS_NO_LOCALFUNCTIONS_UNUSED) const
|
||||
{
|
||||
if (GET_PROP_VALUE(TypeTag, UseP1FiniteElementGradients)) {
|
||||
#if !HAVE_DUNE_LOCALFUNCTIONS
|
||||
// The dune-localfunctions module is required for P1 finite element gradients
|
||||
throw std::logic_error("The dune-localfunctions module is required in oder to use"
|
||||
" finite element gradients");
|
||||
#else
|
||||
typedef typename std::remove_reference<typename QuantityCallback::ResultType>::type QuantityConstType;
|
||||
typedef typename std::remove_const<QuantityConstType>::type QuantityType;
|
||||
|
||||
// If the user does not want two-point gradients, we use P1 finite element
|
||||
// gradients...
|
||||
quantityGrad = 0.0;
|
||||
for (unsigned vertIdx = 0; vertIdx < elemCtx.numDof(/*timeIdx=*/0); ++vertIdx) {
|
||||
if (std::is_same<QuantityType, Scalar>::value ||
|
||||
elemCtx.focusDofIndex() == vertIdx)
|
||||
{
|
||||
const auto& dofVal = quantityCallback(vertIdx);
|
||||
const auto& tmp = p1Gradient_[fapIdx][vertIdx];
|
||||
for (int dimIdx = 0; dimIdx < dim; ++ dimIdx)
|
||||
quantityGrad[dimIdx] += dofVal*tmp[dimIdx];
|
||||
}
|
||||
else {
|
||||
const auto& dofVal = quantityCallback(vertIdx);
|
||||
const auto& tmp = p1Gradient_[fapIdx][vertIdx];
|
||||
for (int dimIdx = 0; dimIdx < dim; ++ dimIdx)
|
||||
quantityGrad[dimIdx] += Opm::scalarValue(dofVal)*tmp[dimIdx];
|
||||
}
|
||||
}
|
||||
#endif
|
||||
}
|
||||
else
|
||||
ParentType::calculateGradient(quantityGrad, elemCtx, fapIdx, quantityCallback);
|
||||
}
|
||||
|
||||
/*!
|
||||
* \brief Calculates the value of an arbitrary quantity at any
|
||||
* flux approximation point on the grid boundary.
|
||||
*
|
||||
* Boundary values are always calculated using the two-point
|
||||
* approximation.
|
||||
*
|
||||
* \param elemCtx The current execution context
|
||||
* \param fapIdx The local index of the flux approximation point
|
||||
* in the current element's stencil.
|
||||
* \param quantityCallback A callable object returning the value
|
||||
* of the quantity at an index of a degree of
|
||||
* freedom
|
||||
*/
|
||||
template <class QuantityCallback>
|
||||
auto calculateBoundaryValue(const ElementContext& elemCtx,
|
||||
unsigned fapIdx,
|
||||
const QuantityCallback& quantityCallback)
|
||||
-> decltype(ParentType::calculateBoundaryValue(elemCtx, fapIdx, quantityCallback))
|
||||
{ return ParentType::calculateBoundaryValue(elemCtx, fapIdx, quantityCallback); }
|
||||
|
||||
/*!
|
||||
* \brief Calculates the gradient of an arbitrary quantity at any
|
||||
* flux approximation point on the boundary.
|
||||
*
|
||||
* Boundary gradients are always calculated using the two-point
|
||||
* approximation.
|
||||
*
|
||||
* \param elemCtx The current execution context
|
||||
* \param fapIdx The local index of the flux approximation point
|
||||
* in the current element's stencil.
|
||||
* \param quantityCallback A callable object returning the value
|
||||
* of the quantity at an index of a degree of
|
||||
* freedom
|
||||
*/
|
||||
template <class QuantityCallback, class EvalDimVector>
|
||||
void calculateBoundaryGradient(EvalDimVector& quantityGrad,
|
||||
const ElementContext& elemCtx,
|
||||
unsigned fapIdx,
|
||||
const QuantityCallback& quantityCallback) const
|
||||
{ ParentType::calculateBoundaryGradient(quantityGrad, elemCtx, fapIdx, quantityCallback); }
|
||||
|
||||
#if HAVE_DUNE_LOCALFUNCTIONS
|
||||
static LocalFiniteElementCache& localFiniteElementCache()
|
||||
{ return feCache_; }
|
||||
#endif
|
||||
|
||||
private:
|
||||
#if HAVE_DUNE_LOCALFUNCTIONS
|
||||
static LocalFiniteElementCache feCache_;
|
||||
|
||||
const LocalFiniteElement* localFiniteElement_;
|
||||
std::vector<Dune::FieldVector<Scalar, 1>> p1Value_[maxFap];
|
||||
DimVector p1Gradient_[maxFap][maxDof];
|
||||
#endif // HAVE_DUNE_LOCALFUNCTIONS
|
||||
};
|
||||
|
||||
#if HAVE_DUNE_LOCALFUNCTIONS
|
||||
template<class TypeTag>
|
||||
typename P1FeGradientCalculator<TypeTag>::LocalFiniteElementCache
|
||||
P1FeGradientCalculator<TypeTag>::feCache_;
|
||||
#endif
|
||||
} // namespace Opm
|
||||
|
||||
#undef EWOMS_NO_LOCALFUNCTIONS_UNUSED
|
||||
|
||||
#endif
|
85
opm/models/discretization/vcfv/vcfvbaseoutputmodule.hh
Normal file
85
opm/models/discretization/vcfv/vcfvbaseoutputmodule.hh
Normal file
@ -0,0 +1,85 @@
|
||||
// -*- mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*-
|
||||
// vi: set et ts=4 sw=4 sts=4:
|
||||
/*
|
||||
This file is part of the Open Porous Media project (OPM).
|
||||
|
||||
OPM 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.
|
||||
|
||||
OPM is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
GNU General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU General Public License
|
||||
along with OPM. If not, see <http://www.gnu.org/licenses/>.
|
||||
|
||||
Consult the COPYING file in the top-level source directory of this
|
||||
module for the precise wording of the license and the list of
|
||||
copyright holders.
|
||||
*/
|
||||
/*!
|
||||
* \file
|
||||
*
|
||||
* \copydoc Opm::VcfvBaseOutputModule
|
||||
*/
|
||||
#ifndef EWOMS_VCFV_VTK_BASE_OUTPUT_MODULE_HH
|
||||
#define EWOMS_VCFV_VTK_BASE_OUTPUT_MODULE_HH
|
||||
|
||||
#include "vcfvproperties.hh"
|
||||
|
||||
#include <ewoms/io/baseoutputwriter.hh>
|
||||
|
||||
#include <string>
|
||||
#include <vector>
|
||||
|
||||
namespace Opm {
|
||||
/*!
|
||||
* \ingroup VcfvDiscretization
|
||||
*
|
||||
* \brief Implements the discretization specific parts of writing files.
|
||||
*/
|
||||
template<class TypeTag>
|
||||
class VcfvBaseOutputModule
|
||||
{
|
||||
public:
|
||||
typedef BaseOutputWriter::Scalar Scalar;
|
||||
typedef BaseOutputWriter::Vector Vector;
|
||||
typedef BaseOutputWriter::ScalarBuffer ScalarBuffer;
|
||||
typedef BaseOutputWriter::VectorBuffer VectorBuffer;
|
||||
typedef BaseOutputWriter::TensorBuffer TensorBuffer;
|
||||
|
||||
/*!
|
||||
* \brief Add a buffer where the data is associated with the
|
||||
* degrees of freedom to the current VTK output file.
|
||||
*/
|
||||
static void attachScalarDofData_(BaseOutputWriter& baseWriter,
|
||||
ScalarBuffer& buffer,
|
||||
const std::string& name)
|
||||
{ baseWriter.attachScalarVertexData(buffer, name.c_str()); }
|
||||
|
||||
/*!
|
||||
* \brief Add a buffer where the data is associated with the
|
||||
* degrees of freedom to the current VTK output file.
|
||||
*/
|
||||
static void attachVectorDofData_(BaseOutputWriter& baseWriter,
|
||||
VectorBuffer& buffer,
|
||||
const std::string& name)
|
||||
{ baseWriter.attachVectorVertexData(buffer, name.c_str()); }
|
||||
|
||||
|
||||
/*!
|
||||
* \brief Add a buffer where the data is associated with the
|
||||
* degrees of freedom to the current VTK output file.
|
||||
*/
|
||||
static void attachTensorDofData_(BaseOutputWriter& baseWriter,
|
||||
TensorBuffer& buffer,
|
||||
const std::string& name)
|
||||
{ baseWriter.attachTensorVertexData(buffer, name.c_str()); }
|
||||
};
|
||||
|
||||
} // namespace Opm
|
||||
|
||||
#endif
|
198
opm/models/discretization/vcfv/vcfvdiscretization.hh
Normal file
198
opm/models/discretization/vcfv/vcfvdiscretization.hh
Normal file
@ -0,0 +1,198 @@
|
||||
// -*- mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*-
|
||||
// vi: set et ts=4 sw=4 sts=4:
|
||||
/*
|
||||
This file is part of the Open Porous Media project (OPM).
|
||||
|
||||
OPM 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.
|
||||
|
||||
OPM is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
GNU General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU General Public License
|
||||
along with OPM. If not, see <http://www.gnu.org/licenses/>.
|
||||
|
||||
Consult the COPYING file in the top-level source directory of this
|
||||
module for the precise wording of the license and the list of
|
||||
copyright holders.
|
||||
*/
|
||||
/*!
|
||||
* \file
|
||||
*
|
||||
* \copydoc Opm::VcfvDiscretization
|
||||
*/
|
||||
#ifndef EWOMS_VCFV_DISCRETIZATION_HH
|
||||
#define EWOMS_VCFV_DISCRETIZATION_HH
|
||||
|
||||
#include <opm/material/densead/Math.hpp>
|
||||
|
||||
#include "vcfvproperties.hh"
|
||||
#include "vcfvstencil.hh"
|
||||
#include "p1fegradientcalculator.hh"
|
||||
#include "vcfvgridcommhandlefactory.hh"
|
||||
#include "vcfvbaseoutputmodule.hh"
|
||||
|
||||
#include <opm/simulators/linalg/vertexborderlistfromgrid.hh>
|
||||
#include <opm/models/discretization/common/fvbasediscretization.hh>
|
||||
|
||||
#if HAVE_DUNE_FEM
|
||||
#include <dune/fem/space/common/functionspace.hh>
|
||||
#include <dune/fem/space/lagrange.hh>
|
||||
#endif
|
||||
|
||||
namespace Opm {
|
||||
template <class TypeTag>
|
||||
class VcfvDiscretization;
|
||||
|
||||
} // namespace Opm
|
||||
|
||||
BEGIN_PROPERTIES
|
||||
|
||||
//! Set the stencil
|
||||
SET_PROP(VcfvDiscretization, Stencil)
|
||||
{
|
||||
private:
|
||||
typedef typename GET_PROP_TYPE(TypeTag, GridView) GridView;
|
||||
typedef typename GridView::ctype CoordScalar;
|
||||
|
||||
public:
|
||||
typedef Opm::VcfvStencil<CoordScalar, GridView> type;
|
||||
};
|
||||
|
||||
//! Mapper for the degrees of freedoms.
|
||||
SET_TYPE_PROP(VcfvDiscretization, DofMapper, typename GET_PROP_TYPE(TypeTag, VertexMapper));
|
||||
|
||||
//! The concrete class which manages the spatial discretization
|
||||
SET_TYPE_PROP(VcfvDiscretization, Discretization, Opm::VcfvDiscretization<TypeTag>);
|
||||
|
||||
//! The base class for the output modules (decides whether to write
|
||||
//! element or vertex based fields)
|
||||
SET_TYPE_PROP(VcfvDiscretization, DiscBaseOutputModule,
|
||||
Opm::VcfvBaseOutputModule<TypeTag>);
|
||||
|
||||
//! Calculates the gradient of any quantity given the index of a flux approximation point
|
||||
SET_TYPE_PROP(VcfvDiscretization, GradientCalculator,
|
||||
Opm::P1FeGradientCalculator<TypeTag>);
|
||||
|
||||
//! The class to create grid communication handles
|
||||
SET_TYPE_PROP(VcfvDiscretization, GridCommHandleFactory,
|
||||
Opm::VcfvGridCommHandleFactory<TypeTag>);
|
||||
|
||||
//! Use two-point gradients by default for the vertex centered finite volume scheme.
|
||||
SET_BOOL_PROP(VcfvDiscretization, UseP1FiniteElementGradients, false);
|
||||
|
||||
#if HAVE_DUNE_FEM
|
||||
//! Set the DiscreteFunctionSpace
|
||||
SET_PROP(VcfvDiscretization, DiscreteFunctionSpace)
|
||||
{
|
||||
private:
|
||||
typedef typename GET_PROP_TYPE(TypeTag, Scalar) Scalar;
|
||||
typedef typename GET_PROP_TYPE(TypeTag, GridPart) GridPart;
|
||||
enum { numEq = GET_PROP_VALUE(TypeTag, NumEq) };
|
||||
typedef Dune::Fem::FunctionSpace<typename GridPart::GridType::ctype,
|
||||
Scalar,
|
||||
GridPart::GridType::dimensionworld,
|
||||
numEq> FunctionSpace;
|
||||
public:
|
||||
// Lagrange discrete function space with unknowns at the cell vertices
|
||||
typedef Dune::Fem::LagrangeDiscreteFunctionSpace< FunctionSpace, GridPart, 1 > type;
|
||||
};
|
||||
#endif
|
||||
|
||||
//! Set the border list creator for vertices
|
||||
SET_PROP(VcfvDiscretization, BorderListCreator)
|
||||
{ private:
|
||||
typedef typename GET_PROP_TYPE(TypeTag, VertexMapper) VertexMapper;
|
||||
typedef typename GET_PROP_TYPE(TypeTag, GridView) GridView;
|
||||
public:
|
||||
typedef Opm::Linear::VertexBorderListFromGrid<GridView, VertexMapper> type;
|
||||
};
|
||||
|
||||
//! For the vertex centered finite volume method, ghost and overlap elements must _not_
|
||||
//! be assembled to avoid accounting twice for the fluxes over the process boundary faces
|
||||
//! of the local process' grid partition
|
||||
SET_BOOL_PROP(VcfvDiscretization, LinearizeNonLocalElements, false);
|
||||
|
||||
|
||||
END_PROPERTIES
|
||||
|
||||
namespace Opm {
|
||||
|
||||
/*!
|
||||
* \ingroup VcfvDiscretization
|
||||
*
|
||||
* \brief The base class for the vertex centered finite volume discretization scheme.
|
||||
*/
|
||||
template<class TypeTag>
|
||||
class VcfvDiscretization : public FvBaseDiscretization<TypeTag>
|
||||
{
|
||||
typedef FvBaseDiscretization<TypeTag> ParentType;
|
||||
typedef typename GET_PROP_TYPE(TypeTag, Model) Implementation;
|
||||
typedef typename GET_PROP_TYPE(TypeTag, DofMapper) DofMapper;
|
||||
typedef typename GET_PROP_TYPE(TypeTag, GridView) GridView;
|
||||
typedef typename GET_PROP_TYPE(TypeTag, Simulator) Simulator;
|
||||
|
||||
enum { dim = GridView::dimension };
|
||||
|
||||
public:
|
||||
VcfvDiscretization(Simulator& simulator)
|
||||
: ParentType(simulator)
|
||||
{ }
|
||||
|
||||
/*!
|
||||
* \brief Returns a string of discretization's human-readable name
|
||||
*/
|
||||
static std::string discretizationName()
|
||||
{ return "vcfv"; }
|
||||
|
||||
/*!
|
||||
* \brief Returns the number of global degrees of freedom (DOFs) due to the grid
|
||||
*/
|
||||
size_t numGridDof() const
|
||||
{ return static_cast<size_t>(this->gridView_.size(/*codim=*/dim)); }
|
||||
|
||||
/*!
|
||||
* \brief Mapper to convert the Dune entities of the
|
||||
* discretization's degrees of freedoms are to indices.
|
||||
*/
|
||||
const DofMapper& dofMapper() const
|
||||
{ return this->vertexMapper(); }
|
||||
|
||||
/*!
|
||||
* \brief Serializes the current state of the model.
|
||||
*
|
||||
* \tparam Restarter The type of the serializer class
|
||||
*
|
||||
* \param res The serializer object
|
||||
*/
|
||||
template <class Restarter>
|
||||
void serialize(Restarter& res)
|
||||
{ res.template serializeEntities</*codim=*/dim>(asImp_(), this->gridView_); }
|
||||
|
||||
/*!
|
||||
* \brief Deserializes the state of the model.
|
||||
*
|
||||
* \tparam Restarter The type of the serializer class
|
||||
*
|
||||
* \param res The serializer object
|
||||
*/
|
||||
template <class Restarter>
|
||||
void deserialize(Restarter& res)
|
||||
{
|
||||
res.template deserializeEntities</*codim=*/dim>(asImp_(), this->gridView_);
|
||||
this->solution(/*timeIdx=*/1) = this->solution(/*timeIdx=*/0);
|
||||
}
|
||||
|
||||
private:
|
||||
Implementation& asImp_()
|
||||
{ return *static_cast<Implementation*>(this); }
|
||||
const Implementation& asImp_() const
|
||||
{ return *static_cast<const Implementation*>(this); }
|
||||
};
|
||||
} // namespace Opm
|
||||
|
||||
#endif
|
91
opm/models/discretization/vcfv/vcfvgridcommhandlefactory.hh
Normal file
91
opm/models/discretization/vcfv/vcfvgridcommhandlefactory.hh
Normal file
@ -0,0 +1,91 @@
|
||||
// -*- mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*-
|
||||
// vi: set et ts=4 sw=4 sts=4:
|
||||
/*
|
||||
This file is part of the Open Porous Media project (OPM).
|
||||
|
||||
OPM 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.
|
||||
|
||||
OPM is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
GNU General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU General Public License
|
||||
along with OPM. If not, see <http://www.gnu.org/licenses/>.
|
||||
|
||||
Consult the COPYING file in the top-level source directory of this
|
||||
module for the precise wording of the license and the list of
|
||||
copyright holders.
|
||||
*/
|
||||
/*!
|
||||
* \file
|
||||
*
|
||||
* \copydoc Opm::VcfvGridCommHandleFactory
|
||||
*/
|
||||
#ifndef EWOMS_VCFV_GRID_COMM_HANDLE_FACTORY_HH
|
||||
#define EWOMS_VCFV_GRID_COMM_HANDLE_FACTORY_HH
|
||||
|
||||
#include "vcfvproperties.hh"
|
||||
|
||||
#include <opm/models/parallel/gridcommhandles.hh>
|
||||
|
||||
namespace Opm {
|
||||
/*!
|
||||
* \ingroup VcfvDiscretization
|
||||
*
|
||||
* \brief A class which provides types for DUNE grid handles for
|
||||
* communication.
|
||||
*
|
||||
* This is required for parallel computations
|
||||
*/
|
||||
template<class TypeTag>
|
||||
class VcfvGridCommHandleFactory
|
||||
{
|
||||
typedef typename GET_PROP_TYPE(TypeTag, DofMapper) DofMapper;
|
||||
typedef typename GET_PROP_TYPE(TypeTag, GridView) GridView;
|
||||
|
||||
static const int dim = GridView::dimension;
|
||||
|
||||
public:
|
||||
/*!
|
||||
* \brief Return a handle which computes the minimum of a value
|
||||
* for each overlapping degree of freedom across all processes.
|
||||
*/
|
||||
template <class ValueType, class ArrayType>
|
||||
static std::shared_ptr<GridCommHandleMin<ValueType, ArrayType, DofMapper, /*commCodim=*/dim> >
|
||||
minHandle(ArrayType& array, const DofMapper& dofMapper)
|
||||
{
|
||||
typedef GridCommHandleMin<ValueType, ArrayType, DofMapper, /*commCodim=*/dim> Handle;
|
||||
return std::shared_ptr<Handle>(new Handle(array, dofMapper));
|
||||
}
|
||||
|
||||
/*!
|
||||
* \brief Return a handle which computes the maximum of a value
|
||||
* for each overlapping degree of freedom across all processes.
|
||||
*/
|
||||
template <class ValueType, class ArrayType>
|
||||
static std::shared_ptr<GridCommHandleMax<ValueType, ArrayType, DofMapper, /*commCodim=*/dim> >
|
||||
maxHandle(ArrayType& array, const DofMapper& dofMapper)
|
||||
{
|
||||
typedef GridCommHandleMax<ValueType, ArrayType, DofMapper, /*commCodim=*/dim> Handle;
|
||||
return std::shared_ptr<Handle>(new Handle(array, dofMapper));
|
||||
}
|
||||
|
||||
/*!
|
||||
* \brief Return a handle which computes the sum of all values
|
||||
* all overlapping degrees of freedom across all processes.
|
||||
*/
|
||||
template <class ValueType, class ArrayType>
|
||||
static std::shared_ptr<GridCommHandleSum<ValueType, ArrayType, DofMapper, /*commCodim=*/dim> >
|
||||
sumHandle(ArrayType& array, const DofMapper& dofMapper)
|
||||
{
|
||||
typedef GridCommHandleSum<ValueType, ArrayType, DofMapper, /*commCodim=*/dim> Handle;
|
||||
return std::shared_ptr<Handle>(new Handle(array, dofMapper));
|
||||
}
|
||||
};
|
||||
} // namespace Opm
|
||||
|
||||
#endif
|
47
opm/models/discretization/vcfv/vcfvproperties.hh
Normal file
47
opm/models/discretization/vcfv/vcfvproperties.hh
Normal file
@ -0,0 +1,47 @@
|
||||
// -*- mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*-
|
||||
// vi: set et ts=4 sw=4 sts=4:
|
||||
/*
|
||||
This file is part of the Open Porous Media project (OPM).
|
||||
|
||||
OPM 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.
|
||||
|
||||
OPM is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
GNU General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU General Public License
|
||||
along with OPM. If not, see <http://www.gnu.org/licenses/>.
|
||||
|
||||
Consult the COPYING file in the top-level source directory of this
|
||||
module for the precise wording of the license and the list of
|
||||
copyright holders.
|
||||
*/
|
||||
/*!
|
||||
* \file
|
||||
*
|
||||
* \brief Declares the basic properties used by the common infrastructure of
|
||||
* the vertex-centered finite volume discretization.
|
||||
*/
|
||||
#ifndef EWOMS_VCFV_PROPERTIES_HH
|
||||
#define EWOMS_VCFV_PROPERTIES_HH
|
||||
|
||||
#include <opm/models/discretization/common/fvbaseproperties.hh>
|
||||
|
||||
#include <opm/models/utils/propertysystem.hh>
|
||||
|
||||
BEGIN_PROPERTIES
|
||||
|
||||
//! The type tag for models based on the VCFV-scheme
|
||||
NEW_TYPE_TAG(VcfvDiscretization, INHERITS_FROM(FvBaseDiscretization));
|
||||
|
||||
//! Use P1 finite-elements gradients instead of two-point gradients. Note that setting
|
||||
//! this property to true requires the dune-localfunctions module to be available.
|
||||
NEW_PROP_TAG(UseP1FiniteElementGradients);
|
||||
|
||||
END_PROPERTIES
|
||||
|
||||
#endif
|
1396
opm/models/discretization/vcfv/vcfvstencil.hh
Normal file
1396
opm/models/discretization/vcfv/vcfvstencil.hh
Normal file
File diff suppressed because it is too large
Load Diff
@ -39,7 +39,7 @@
|
||||
#include <dune/common/version.hh>
|
||||
#include <dune/geometry/quadraturerules.hh>
|
||||
|
||||
#include <ewoms/disc/vcfv/vcfvstencil.hh>
|
||||
#include <opm/models/discretization/vcfv/vcfvstencil.hh>
|
||||
|
||||
#include <opm/material/common/Unused.hpp>
|
||||
|
||||
|
Loading…
Reference in New Issue
Block a user