/*
Copyright 2013, 2015 SINTEF ICT, Applied Mathematics.
Copyright 2014, 2015 Dr. Blatt - HPC-Simulation-Software & Services
Copyright 2014, 2015 Statoil ASA.
Copyright 2015 NTNU
Copyright 2015, 2016, 2017 IRIS AS
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 3 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 .
*/
#ifndef OPM_BLACKOILMODEL_HEADER_INCLUDED
#define OPM_BLACKOILMODEL_HEADER_INCLUDED
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
namespace Opm {
/// A model implementation for three-phase black oil.
///
/// The simulator is capable of handling three-phase problems
/// where gas can be dissolved in oil and vice versa. It
/// uses an industry-standard TPFA discretization with per-phase
/// upwind weighting of mobilities.
template
class BlackoilModel
{
public:
// --------- Types and enums ---------
using Simulator = GetPropType;
using Grid = GetPropType;
using ElementContext = GetPropType;
using IntensiveQuantities = GetPropType;
using SparseMatrixAdapter = GetPropType;
using SolutionVector = GetPropType;
using PrimaryVariables = GetPropType;
using FluidSystem = GetPropType;
using Indices = GetPropType;
using MaterialLaw = GetPropType;
using MaterialLawParams = GetPropType;
using Scalar = GetPropType;
using ModelParameters = BlackoilModelParameters;
static constexpr int numEq = Indices::numEq;
static constexpr int contiSolventEqIdx = Indices::contiSolventEqIdx;
static constexpr int contiZfracEqIdx = Indices::contiZfracEqIdx;
static constexpr int contiPolymerEqIdx = Indices::contiPolymerEqIdx;
static constexpr int contiEnergyEqIdx = Indices::contiEnergyEqIdx;
static constexpr int contiPolymerMWEqIdx = Indices::contiPolymerMWEqIdx;
static constexpr int contiFoamEqIdx = Indices::contiFoamEqIdx;
static constexpr int contiBrineEqIdx = Indices::contiBrineEqIdx;
static constexpr int contiMicrobialEqIdx = Indices::contiMicrobialEqIdx;
static constexpr int contiOxygenEqIdx = Indices::contiOxygenEqIdx;
static constexpr int contiUreaEqIdx = Indices::contiUreaEqIdx;
static constexpr int contiBiofilmEqIdx = Indices::contiBiofilmEqIdx;
static constexpr int contiCalciteEqIdx = Indices::contiCalciteEqIdx;
static constexpr int solventSaturationIdx = Indices::solventSaturationIdx;
static constexpr int zFractionIdx = Indices::zFractionIdx;
static constexpr int polymerConcentrationIdx = Indices::polymerConcentrationIdx;
static constexpr int polymerMoleWeightIdx = Indices::polymerMoleWeightIdx;
static constexpr int temperatureIdx = Indices::temperatureIdx;
static constexpr int foamConcentrationIdx = Indices::foamConcentrationIdx;
static constexpr int saltConcentrationIdx = Indices::saltConcentrationIdx;
static constexpr int microbialConcentrationIdx = Indices::microbialConcentrationIdx;
static constexpr int oxygenConcentrationIdx = Indices::oxygenConcentrationIdx;
static constexpr int ureaConcentrationIdx = Indices::ureaConcentrationIdx;
static constexpr int biofilmConcentrationIdx = Indices::biofilmConcentrationIdx;
static constexpr int calciteConcentrationIdx = Indices::calciteConcentrationIdx;
using VectorBlockType = Dune::FieldVector;
using MatrixBlockType = typename SparseMatrixAdapter::MatrixBlock;
using Mat = typename SparseMatrixAdapter::IstlMatrix;
using BVector = Dune::BlockVector;
using ComponentName = ::Opm::ComponentName;
// --------- Public methods ---------
/// Construct the model. It will retain references to the
/// arguments of this functions, and they are expected to
/// remain in scope for the lifetime of the solver.
/// \param[in] param parameters
/// \param[in] grid grid data structure
/// \param[in] wells well structure
/// \param[in] vfp_properties Vertical flow performance tables
/// \param[in] linsolver linear solver
/// \param[in] eclState eclipse state
/// \param[in] terminal_output request output to cout/cerr
BlackoilModel(Simulator& simulator,
const ModelParameters& param,
BlackoilWellModel& well_model,
const bool terminal_output);
bool isParallel() const
{ return grid_.comm().size() > 1; }
const EclipseState& eclState() const
{ return simulator_.vanguard().eclState(); }
/// Called once before each time step.
/// \param[in] timer simulation timer
SimulatorReportSingle prepareStep(const SimulatorTimerInterface& timer);
void initialLinearization(SimulatorReportSingle& report,
const int iteration,
const int minIter,
const int maxIter,
const SimulatorTimerInterface& timer);
/// Called once per nonlinear iteration.
/// This model will perform a Newton-Raphson update, changing reservoir_state
/// and well_state. It will also use the nonlinear_solver to do relaxation of
/// updates if necessary.
/// \param[in] iteration should be 0 for the first call of a new timestep
/// \param[in] timer simulation timer
/// \param[in] nonlinear_solver nonlinear solver used (for oscillation/relaxation control)
template
SimulatorReportSingle nonlinearIteration(const int iteration,
const SimulatorTimerInterface& timer,
NonlinearSolverType& nonlinear_solver);
template
SimulatorReportSingle nonlinearIterationNewton(const int iteration,
const SimulatorTimerInterface& timer,
NonlinearSolverType& nonlinear_solver);
/// Called once after each time step.
/// In this class, this function does nothing.
/// \param[in] timer simulation timer
SimulatorReportSingle afterStep(const SimulatorTimerInterface&);
/// Assemble the residual and Jacobian of the nonlinear system.
SimulatorReportSingle assembleReservoir(const SimulatorTimerInterface& /* timer */,
const int iterationIdx);
// compute the "relative" change of the solution between time steps
Scalar relativeChange() const;
/// Number of linear iterations used in last call to solveJacobianSystem().
int linearIterationsLastSolve() const
{ return simulator_.model().newtonMethod().linearSolver().iterations (); }
// Obtain reference to linear solver setup time
double& linearSolveSetupTime()
{ return linear_solve_setup_time_; }
/// Solve the Jacobian system Jx = r where J is the Jacobian and
/// r is the residual.
void solveJacobianSystem(BVector& x);
/// Apply an update to the primary variables.
void updateSolution(const BVector& dx);
/// Return true if output to cout is wanted.
bool terminalOutputEnabled() const
{ return terminal_output_; }
std::tuple
convergenceReduction(Parallel::Communication comm,
const Scalar pvSumLocal,
const Scalar numAquiferPvSumLocal,
std::vector& R_sum,
std::vector& maxCoeff,
std::vector& B_avg);
/// \brief Get reservoir quantities on this process needed for convergence calculations.
/// \return A pair of the local pore volume of interior cells and the pore volumes
/// of the cells associated with a numerical aquifer.
std::pair
localConvergenceData(std::vector& R_sum,
std::vector& maxCoeff,
std::vector& B_avg,
std::vector& maxCoeffCell);
/// \brief Compute pore-volume/cell count split among "converged",
/// "relaxed converged", "unconverged" cells based on CNV point
/// measures.
std::pair, std::vector>
characteriseCnvPvSplit(const std::vector& B_avg, const double dt);
void updateTUNING(const Tuning& tuning);
ConvergenceReport
getReservoirConvergence(const double reportTime,
const double dt,
const int iteration,
const int maxIter,
std::vector& B_avg,
std::vector& residual_norms);
/// Compute convergence based on total mass balance (tol_mb) and maximum
/// residual mass balance (tol_cnv).
/// \param[in] timer simulation timer
/// \param[in] iteration current iteration number
/// \param[in] maxIter maximum number of iterations
/// \param[out] residual_norms CNV residuals by phase
ConvergenceReport
getConvergence(const SimulatorTimerInterface& timer,
const int iteration,
const int maxIter,
std::vector& residual_norms);
/// The number of active fluid phases in the model.
int numPhases() const
{ return phaseUsage_.num_phases; }
/// Wrapper required due to not following generic API
template
std::vector >
computeFluidInPlace(const T&, const std::vector& fipnum) const
{ return this->computeFluidInPlace(fipnum); }
/// Should not be called
std::vector >
computeFluidInPlace(const std::vector& /*fipnum*/) const;
const Simulator& simulator() const
{ return simulator_; }
Simulator& simulator()
{ return simulator_; }
/// return the statistics if the nonlinearIteration() method failed
const SimulatorReportSingle& failureReport() const
{ return failureReport_; }
/// return the statistics if the nonlinearIteration() method failed
SimulatorReportSingle localAccumulatedReports() const;
const std::vector& stepReports() const
{ return convergence_reports_; }
void writePartitions(const std::filesystem::path& odir) const;
const std::vector>& getConvCells() const
{ return rst_conv_.getData(); }
/// return the StandardWells object
BlackoilWellModel&
wellModel()
{ return well_model_; }
const BlackoilWellModel&
wellModel() const
{ return well_model_; }
void beginReportStep()
{ simulator_.problem().beginEpisode(); }
void endReportStep()
{ simulator_.problem().endEpisode(); }
template
void getMaxCoeff(const unsigned cell_idx,
const IntensiveQuantities& intQuants,
const FluidState& fs,
const Residual& modelResid,
const Scalar pvValue,
std::vector& B_avg,
std::vector& R_sum,
std::vector& maxCoeff,
std::vector& maxCoeffCell);
//! \brief Returns const reference to model parameters.
const ModelParameters& param() const
{ return param_; }
//! \brief Returns const reference to component names.
const ComponentName& compNames() const
{ return compNames_; }
protected:
// --------- Data members ---------
Simulator& simulator_;
const Grid& grid_;
const PhaseUsage phaseUsage_;
static constexpr bool has_solvent_ = getPropValue();
static constexpr bool has_extbo_ = getPropValue();
static constexpr bool has_polymer_ = getPropValue();
static constexpr bool has_polymermw_ = getPropValue();
static constexpr bool has_energy_ = getPropValue();
static constexpr bool has_foam_ = getPropValue();
static constexpr bool has_brine_ = getPropValue();
static constexpr bool has_micp_ = getPropValue();
ModelParameters param_;
SimulatorReportSingle failureReport_;
// Well Model
BlackoilWellModel& well_model_;
RSTConv rst_conv_; //!< Helper class for RPTRST CONV
/// \brief Whether we print something to std::cout
bool terminal_output_;
/// \brief The number of cells of the global grid.
long int global_nc_;
std::vector> residual_norms_history_;
Scalar current_relaxation_;
BVector dx_old_;
std::vector convergence_reports_;
ComponentName compNames_{};
std::unique_ptr> nlddSolver_; //!< Non-linear DD solver
BlackoilModelConvergenceMonitor conv_monitor_;
private:
Scalar dpMaxRel() const { return param_.dp_max_rel_; }
Scalar dsMax() const { return param_.ds_max_; }
Scalar drMaxRel() const { return param_.dr_max_rel_; }
Scalar maxResidualAllowed() const { return param_.max_residual_allowed_; }
double linear_solve_setup_time_;
std::vector wasSwitched_;
};
} // namespace Opm
#include
#endif // OPM_BLACKOILMODEL_HEADER_INCLUDED