mirror of
https://github.com/OPM/opm-simulators.git
synced 2025-02-25 18:55:30 -06:00
remove 'flow_multisegment' and associated files
use 'flow' with use_multisegment_well=true
This commit is contained in:
parent
5c048782ee
commit
ad23d98726
@ -121,7 +121,6 @@ list (APPEND EXAMPLE_SOURCE_FILES
|
||||
examples/flow_reorder.cpp
|
||||
examples/flow_sequential.cpp
|
||||
examples/flow.cpp
|
||||
examples/flow_multisegment.cpp
|
||||
examples/flow_solvent.cpp
|
||||
examples/sim_2p_incomp.cpp
|
||||
examples/sim_2p_incomp_ad.cpp
|
||||
@ -176,8 +175,6 @@ list (APPEND PUBLIC_HEADER_FILES
|
||||
opm/autodiff/BlackoilSequentialModel.hpp
|
||||
opm/autodiff/BlackoilSolventModel.hpp
|
||||
opm/autodiff/BlackoilSolventModel_impl.hpp
|
||||
opm/autodiff/BlackoilMultiSegmentModel.hpp
|
||||
opm/autodiff/BlackoilMultiSegmentModel_impl.hpp
|
||||
opm/autodiff/BlackoilReorderingTransportModel.hpp
|
||||
opm/autodiff/BlackoilTransportModel.hpp
|
||||
opm/autodiff/fastSparseOperations.hpp
|
||||
@ -217,8 +214,6 @@ list (APPEND PUBLIC_HEADER_FILES
|
||||
opm/autodiff/SimulatorFullyImplicitBlackoil.hpp
|
||||
opm/autodiff/SimulatorFullyImplicitBlackoilSolvent.hpp
|
||||
opm/autodiff/SimulatorFullyImplicitBlackoilSolvent_impl.hpp
|
||||
opm/autodiff/SimulatorFullyImplicitBlackoilMultiSegment.hpp
|
||||
opm/autodiff/SimulatorFullyImplicitBlackoilMultiSegment_impl.hpp
|
||||
opm/autodiff/SimulatorIncompTwophaseAd.hpp
|
||||
opm/autodiff/SimulatorSequentialBlackoil.hpp
|
||||
opm/autodiff/TransportSolverTwophaseAd.hpp
|
||||
|
@ -1,41 +0,0 @@
|
||||
/*
|
||||
Copyright 2013, 2014, 2015 SINTEF ICT, Applied Mathematics.
|
||||
Copyright 2014 Dr. Blatt - HPC-Simulation-Software & Services
|
||||
Copyright 2015 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 <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
|
||||
#ifdef HAVE_CONFIG_H
|
||||
#include "config.h"
|
||||
#endif // HAVE_CONFIG_H
|
||||
|
||||
|
||||
#include <opm/core/grid.h>
|
||||
#include <opm/autodiff/SimulatorFullyImplicitBlackoilMultiSegment.hpp>
|
||||
#include <opm/autodiff/FlowMain.hpp>
|
||||
|
||||
|
||||
// ----------------- Main program -----------------
|
||||
int
|
||||
main(int argc, char** argv)
|
||||
{
|
||||
typedef UnstructuredGrid Grid;
|
||||
typedef Opm::SimulatorFullyImplicitBlackoilMultiSegment<Grid> Simulator;
|
||||
Opm::FlowMain<Grid, Simulator> mainfunc;
|
||||
return mainfunc.execute(argc, argv);
|
||||
}
|
@ -1,207 +0,0 @@
|
||||
/*
|
||||
Copyright 2013, 2015 SINTEF ICT, Applied Mathematics.
|
||||
|
||||
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 <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
#ifndef OPM_BLACKOILMULTISEGMENTMODEL_HEADER_INCLUDED
|
||||
#define OPM_BLACKOILMULTISEGMENTMODEL_HEADER_INCLUDED
|
||||
|
||||
#include <opm/core/simulator/BlackoilState.hpp>
|
||||
#include <opm/autodiff/BlackoilModelBase.hpp>
|
||||
#include <opm/autodiff/BlackoilModelParameters.hpp>
|
||||
#include <opm/autodiff/WellStateMultiSegment.hpp>
|
||||
#include <opm/autodiff/WellMultiSegment.hpp>
|
||||
#include <opm/autodiff/StandardWells.hpp>
|
||||
#include <opm/simulators/timestepping/SimulatorTimerInterface.hpp>
|
||||
|
||||
#include <opm/autodiff/MultisegmentWells.hpp>
|
||||
|
||||
namespace Opm {
|
||||
|
||||
struct BlackoilMultiSegmentSolutionState : public DefaultBlackoilSolutionState
|
||||
{
|
||||
explicit BlackoilMultiSegmentSolutionState(const int np)
|
||||
: DefaultBlackoilSolutionState(np)
|
||||
, segp ( ADB::null())
|
||||
, segqs ( ADB::null())
|
||||
{
|
||||
}
|
||||
ADB segp; // the segment pressures
|
||||
ADB segqs; // the segment phase rate in surface volume
|
||||
};
|
||||
|
||||
/// A model implementation for three-phase black oil with support
|
||||
/// for multi-segment wells.
|
||||
///
|
||||
/// It uses automatic differentiation via the class AutoDiffBlock
|
||||
/// to simplify assembly of the jacobian matrix.
|
||||
/// \tparam Grid UnstructuredGrid or CpGrid.
|
||||
/// \tparam Implementation Provides concrete state types.
|
||||
template<class Grid>
|
||||
class BlackoilMultiSegmentModel : public BlackoilModelBase<Grid, MultisegmentWells, BlackoilMultiSegmentModel<Grid> >
|
||||
{
|
||||
public:
|
||||
|
||||
typedef BlackoilModelBase<Grid, MultisegmentWells, BlackoilMultiSegmentModel<Grid> > Base; // base class
|
||||
typedef typename Base::ReservoirState ReservoirState;
|
||||
typedef typename Base::WellState WellState;
|
||||
typedef BlackoilMultiSegmentSolutionState SolutionState;
|
||||
|
||||
friend Base;
|
||||
|
||||
// --------- 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] fluid fluid properties
|
||||
/// \param[in] geo rock properties
|
||||
/// \param[in] rock_comp_props if non-null, rock compressibility properties
|
||||
/// \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] has_disgas turn on dissolved gas
|
||||
/// \param[in] has_vapoil turn on vaporized oil feature
|
||||
/// \param[in] terminal_output request output to cout/cerr
|
||||
/// \param[in] wells_multisegment a vector of multisegment wells
|
||||
BlackoilMultiSegmentModel(const typename Base::ModelParameters& param,
|
||||
const Grid& grid ,
|
||||
const BlackoilPropsAdFromDeck& fluid,
|
||||
const DerivedGeology& geo ,
|
||||
const RockCompressibility* rock_comp_props,
|
||||
const MultisegmentWells& well_model,
|
||||
const NewtonIterationBlackoilInterface& linsolver,
|
||||
std::shared_ptr< const EclipseState > eclState,
|
||||
std::shared_ptr<const Schedule> schedule,
|
||||
std::shared_ptr<const SummaryConfig> summaryConfig,
|
||||
const bool has_disgas,
|
||||
const bool has_vapoil,
|
||||
const bool terminal_output);
|
||||
|
||||
/// Called once before each time step.
|
||||
/// \param[in] timer simulation timer
|
||||
/// \param[in, out] reservoir_state reservoir state variables
|
||||
/// \param[in, out] well_state well state variables
|
||||
void prepareStep(const SimulatorTimerInterface& timer,
|
||||
const ReservoirState& reservoir_state,
|
||||
const WellState& well_state);
|
||||
|
||||
|
||||
/// Assemble the residual and Jacobian of the nonlinear system.
|
||||
/// \param[in] reservoir_state reservoir state variables
|
||||
/// \param[in, out] well_state well state variables
|
||||
/// \param[in] initial_assembly pass true if this is the first call to assemble() in this timestep
|
||||
SimulatorReport
|
||||
assemble(const ReservoirState& reservoir_state,
|
||||
WellState& well_state,
|
||||
const bool initial_assembly);
|
||||
|
||||
using Base::numPhases;
|
||||
using Base::numMaterials;
|
||||
using Base::materialName;
|
||||
using Base::wellModel;
|
||||
|
||||
|
||||
protected:
|
||||
// --------- Data members ---------
|
||||
|
||||
// For non-segmented wells, it should be the density calculated with AVG or SEG way.
|
||||
// while usually SEG way by default.
|
||||
using Base::pvdt_;
|
||||
using Base::geo_;
|
||||
using Base::active_;
|
||||
using Base::sd_;
|
||||
using Base::fluid_;
|
||||
using Base::terminal_output_;
|
||||
using Base::grid_;
|
||||
using Base::canph_;
|
||||
using Base::residual_;
|
||||
using Base::isSg_;
|
||||
using Base::isRs_;
|
||||
using Base::isRv_;
|
||||
using Base::has_disgas_;
|
||||
using Base::has_vapoil_;
|
||||
using Base::cells_;
|
||||
using Base::param_;
|
||||
using Base::linsolver_;
|
||||
using Base::phaseCondition_;
|
||||
using Base::vfp_properties_;
|
||||
using Base::well_model_;
|
||||
|
||||
// using Base::wells;
|
||||
using Base::wellsActive;
|
||||
using Base::updatePrimalVariableFromState;
|
||||
using Base::phaseCondition;
|
||||
using Base::fluidRvSat;
|
||||
using Base::fluidRsSat;
|
||||
using Base::fluidDensity;
|
||||
using Base::updatePhaseCondFromPrimalVariable;
|
||||
using Base::computeGasPressure;
|
||||
using Base::dpMaxRel;
|
||||
using Base::dsMax;
|
||||
using Base::drMaxRel;
|
||||
using Base::convergenceReduction;
|
||||
using Base::maxResidualAllowed;
|
||||
using Base::variableState;
|
||||
// using Base::variableWellStateIndices;
|
||||
using Base::asImpl;
|
||||
using Base::variableReservoirStateInitials;
|
||||
|
||||
|
||||
const std::vector<WellMultiSegmentConstPtr>& wellsMultiSegment() const { return well_model_.msWells(); }
|
||||
|
||||
const MultisegmentWells::MultisegmentWellOps& msWellOps() const { return well_model_.wellOps(); }
|
||||
|
||||
SimulatorReport
|
||||
solveWellEq(const std::vector<ADB>& mob_perfcells,
|
||||
const std::vector<ADB>& b_perfcells,
|
||||
const ReservoirState& reservoir_state,
|
||||
SolutionState& state,
|
||||
WellState& well_state);
|
||||
|
||||
void
|
||||
makeConstantState(SolutionState& state) const;
|
||||
|
||||
// TODO: added since the interfaces of the function are different
|
||||
// TODO: for StandardWells and MultisegmentWells
|
||||
void
|
||||
computeWellConnectionPressures(const SolutionState& state,
|
||||
const WellState& well_state);
|
||||
|
||||
};
|
||||
|
||||
/// Providing types by template specialisation of ModelTraits for BlackoilMultiSegmentModel.
|
||||
template <class GridT>
|
||||
struct ModelTraits< BlackoilMultiSegmentModel<GridT> >
|
||||
{
|
||||
typedef BlackoilState ReservoirState;
|
||||
typedef WellStateMultiSegment WellState;
|
||||
typedef BlackoilModelParameters ModelParameters;
|
||||
typedef BlackoilMultiSegmentSolutionState SolutionState;
|
||||
};
|
||||
|
||||
|
||||
|
||||
|
||||
} // namespace Opm
|
||||
|
||||
#include "BlackoilMultiSegmentModel_impl.hpp"
|
||||
|
||||
#endif // OPM_BLACKOILMULTISEGMENTMODEL_HEADER_INCLUDED
|
@ -1,295 +0,0 @@
|
||||
/*
|
||||
Copyright 2013, 2015 SINTEF ICT, Applied Mathematics.
|
||||
|
||||
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 <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
#ifndef OPM_BLACKOIMULTISEGMENTLMODEL_IMPL_HEADER_INCLUDED
|
||||
#define OPM_BLACKOIMULTISEGMENTLMODEL_IMPL_HEADER_INCLUDED
|
||||
|
||||
#include <opm/autodiff/BlackoilMultiSegmentModel.hpp>
|
||||
|
||||
#include <opm/autodiff/AutoDiffBlock.hpp>
|
||||
#include <opm/autodiff/AutoDiffHelpers.hpp>
|
||||
#include <opm/autodiff/GridHelpers.hpp>
|
||||
#include <opm/autodiff/BlackoilPropsAdFromDeck.hpp>
|
||||
#include <opm/autodiff/GeoProps.hpp>
|
||||
#include <opm/autodiff/WellDensitySegmented.hpp>
|
||||
#include <opm/autodiff/VFPProperties.hpp>
|
||||
#include <opm/autodiff/VFPProdProperties.hpp>
|
||||
#include <opm/autodiff/VFPInjProperties.hpp>
|
||||
|
||||
#include <opm/core/grid.h>
|
||||
#include <opm/core/linalg/LinearSolverInterface.hpp>
|
||||
#include <opm/core/linalg/ParallelIstlInformation.hpp>
|
||||
#include <opm/core/props/rock/RockCompressibility.hpp>
|
||||
#include <opm/common/ErrorMacros.hpp>
|
||||
#include <opm/common/Exceptions.hpp>
|
||||
#include <opm/parser/eclipse/Units/Units.hpp>
|
||||
#include <opm/core/well_controls.h>
|
||||
#include <opm/core/utility/parameters/ParameterGroup.hpp>
|
||||
#include <opm/parser/eclipse/EclipseState/EclipseState.hpp>
|
||||
|
||||
#include <cassert>
|
||||
#include <cmath>
|
||||
#include <iostream>
|
||||
#include <iomanip>
|
||||
#include <limits>
|
||||
#include <vector>
|
||||
//#include <fstream>
|
||||
|
||||
|
||||
namespace Opm {
|
||||
|
||||
|
||||
template <class Grid>
|
||||
BlackoilMultiSegmentModel<Grid>::
|
||||
BlackoilMultiSegmentModel(const typename Base::ModelParameters& param,
|
||||
const Grid& grid ,
|
||||
const BlackoilPropsAdFromDeck& fluid,
|
||||
const DerivedGeology& geo ,
|
||||
const RockCompressibility* rock_comp_props,
|
||||
const MultisegmentWells& well_model,
|
||||
const NewtonIterationBlackoilInterface& linsolver,
|
||||
std::shared_ptr< const EclipseState > eclState,
|
||||
std::shared_ptr<const Schedule> schedule,
|
||||
std::shared_ptr<const SummaryConfig> summary_config,
|
||||
const bool has_disgas,
|
||||
const bool has_vapoil,
|
||||
const bool terminal_output)
|
||||
: Base(param, grid, fluid, geo, rock_comp_props, well_model, linsolver,
|
||||
eclState, schedule, summary_config, has_disgas, has_vapoil, terminal_output)
|
||||
{
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
template <class Grid>
|
||||
void
|
||||
BlackoilMultiSegmentModel<Grid>::
|
||||
prepareStep(const SimulatorTimerInterface& timer,
|
||||
const ReservoirState& reservoir_state,
|
||||
const WellState& well_state)
|
||||
{
|
||||
const double dt = timer.currentStepLength();
|
||||
pvdt_ = geo_.poreVolume() / dt;
|
||||
if (active_[Gas]) {
|
||||
updatePrimalVariableFromState(reservoir_state);
|
||||
}
|
||||
|
||||
const int nw = wellsMultiSegment().size();
|
||||
|
||||
if ( !msWellOps().has_multisegment_wells ) {
|
||||
wellModel().segVDt() = V::Zero(nw);
|
||||
return;
|
||||
}
|
||||
|
||||
const int nseg_total = well_state.numSegments();
|
||||
std::vector<double> segment_volume;
|
||||
segment_volume.reserve(nseg_total);
|
||||
for (int w = 0; w < nw; ++w) {
|
||||
WellMultiSegmentConstPtr well = wellsMultiSegment()[w];
|
||||
const std::vector<double>& segment_volume_well = well->segmentVolume();
|
||||
segment_volume.insert(segment_volume.end(), segment_volume_well.begin(), segment_volume_well.end());
|
||||
}
|
||||
assert(int(segment_volume.size()) == nseg_total);
|
||||
wellModel().segVDt() = Eigen::Map<V>(segment_volume.data(), nseg_total) / dt;
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
template <class Grid>
|
||||
void
|
||||
BlackoilMultiSegmentModel<Grid>::makeConstantState(SolutionState& state) const
|
||||
{
|
||||
Base::makeConstantState(state);
|
||||
state.segp = ADB::constant(state.segp.value());
|
||||
state.segqs = ADB::constant(state.segqs.value());
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
template <class Grid>
|
||||
SimulatorReport
|
||||
BlackoilMultiSegmentModel<Grid>::
|
||||
assemble(const ReservoirState& reservoir_state,
|
||||
WellState& well_state,
|
||||
const bool initial_assembly)
|
||||
{
|
||||
using namespace Opm::AutoDiffGrid;
|
||||
|
||||
// TODO: include VFP effect.
|
||||
// If we have VFP tables, we need the well connection
|
||||
// pressures for the "simple" hydrostatic correction
|
||||
// between well depth and vfp table depth.
|
||||
// if (isVFPActive()) {
|
||||
// SolutionState state = asImpl().variableState(reservoir_state, well_state);
|
||||
// SolutionState state0 = state;
|
||||
// asImpl().makeConstantState(state0);
|
||||
// asImpl().computeWellConnectionPressures(state0, well_state);
|
||||
// }
|
||||
|
||||
// Possibly switch well controls and updating well state to
|
||||
// get reasonable initial conditions for the wells
|
||||
wellModel().updateWellControls(well_state);
|
||||
|
||||
// TODO: I do not think the multi_segment well can handle group control yet
|
||||
if (asImpl().wellModel().wellCollection()->groupControlActive()) {
|
||||
// enforce VREP control when necessary.
|
||||
Base::applyVREPGroupControl(reservoir_state, well_state);
|
||||
|
||||
asImpl().wellModel().wellCollection()->updateWellTargets(well_state.wellRates());
|
||||
}
|
||||
|
||||
// Create the primary variables.
|
||||
SolutionState state = asImpl().variableState(reservoir_state, well_state);
|
||||
|
||||
if (initial_assembly) {
|
||||
// Create the (constant, derivativeless) initial state.
|
||||
SolutionState state0 = state;
|
||||
asImpl().makeConstantState(state0);
|
||||
// Compute initial accumulation contributions
|
||||
// and well connection pressures.
|
||||
asImpl().computeAccum(state0, 0);
|
||||
wellModel().computeSegmentFluidProperties(state0);
|
||||
const int np = numPhases();
|
||||
assert(np == int(wellModel().segmentCompSurfVolumeInitial().size()));
|
||||
for (int phase = 0; phase < np; ++phase) {
|
||||
wellModel().segmentCompSurfVolumeInitial()[phase] = wellModel().segmentCompSurfVolumeCurrent()[phase].value();
|
||||
}
|
||||
|
||||
asImpl().computeWellConnectionPressures(state0, well_state);
|
||||
}
|
||||
|
||||
// OPM_AD_DISKVAL(state.pressure);
|
||||
// OPM_AD_DISKVAL(state.saturation[0]);
|
||||
// OPM_AD_DISKVAL(state.saturation[1]);
|
||||
// OPM_AD_DISKVAL(state.saturation[2]);
|
||||
// OPM_AD_DISKVAL(state.rs);
|
||||
// OPM_AD_DISKVAL(state.rv);
|
||||
// OPM_AD_DISKVAL(state.qs);
|
||||
// OPM_AD_DISKVAL(state.bhp);
|
||||
|
||||
// -------- Mass balance equations --------
|
||||
asImpl().assembleMassBalanceEq(state);
|
||||
|
||||
// -------- Well equations ----------
|
||||
if ( ! wellsActive() ) {
|
||||
SimulatorReport report;
|
||||
return report;
|
||||
}
|
||||
|
||||
wellModel().computeSegmentFluidProperties(state);
|
||||
|
||||
const double gravity = detail::getGravity(geo_.gravity(), UgGridHelpers::dimensions(grid_));
|
||||
wellModel().computeSegmentPressuresDelta(gravity);
|
||||
|
||||
std::vector<ADB> mob_perfcells;
|
||||
std::vector<ADB> b_perfcells;
|
||||
SimulatorReport report;
|
||||
wellModel().extractWellPerfProperties(state, sd_.rq, mob_perfcells, b_perfcells);
|
||||
if (param_.solve_welleq_initially_ && initial_assembly) {
|
||||
// solve the well equations as a pre-processing step
|
||||
report = asImpl().solveWellEq(mob_perfcells, b_perfcells, reservoir_state, state, well_state);
|
||||
}
|
||||
|
||||
// the perforation flux here are different
|
||||
// it is related to the segment location
|
||||
V aliveWells;
|
||||
std::vector<ADB> cq_s;
|
||||
wellModel().computeWellFlux(state, mob_perfcells, b_perfcells, aliveWells, cq_s);
|
||||
wellModel().updatePerfPhaseRatesAndPressures(cq_s, state, well_state);
|
||||
wellModel().addWellFluxEq(cq_s, state, residual_);
|
||||
asImpl().addWellContributionToMassBalanceEq(cq_s, state, well_state);
|
||||
wellModel().addWellControlEq(state, well_state, aliveWells, residual_);
|
||||
return report;
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
template <class Grid>
|
||||
SimulatorReport
|
||||
BlackoilMultiSegmentModel<Grid>::solveWellEq(const std::vector<ADB>& mob_perfcells,
|
||||
const std::vector<ADB>& b_perfcells,
|
||||
const ReservoirState& reservoir_state,
|
||||
SolutionState& state,
|
||||
WellState& well_state)
|
||||
{
|
||||
SimulatorReport report = Base::solveWellEq(mob_perfcells, b_perfcells, reservoir_state, state, well_state);
|
||||
|
||||
if (report.converged) {
|
||||
// We must now update the state.segp and state.segqs members,
|
||||
// that the base version does not know about.
|
||||
const int np = numPhases();
|
||||
const int nseg_total =well_state.numSegments();
|
||||
{
|
||||
// We will set the segp primary variable to the new ones,
|
||||
// but we do not change the derivatives here.
|
||||
ADB::V new_segp = Eigen::Map<ADB::V>(well_state.segPress().data(), nseg_total);
|
||||
// Avoiding the copy below would require a value setter method
|
||||
// in AutoDiffBlock.
|
||||
std::vector<ADB::M> old_segp_derivs = state.segp.derivative();
|
||||
state.segp = ADB::function(std::move(new_segp), std::move(old_segp_derivs));
|
||||
}
|
||||
{
|
||||
// Need to reshuffle well rates, from phase running fastest
|
||||
// to wells running fastest.
|
||||
// The transpose() below switches the ordering.
|
||||
const DataBlock segrates = Eigen::Map<const DataBlock>(well_state.segPhaseRates().data(), nseg_total, np).transpose();
|
||||
ADB::V new_segqs = Eigen::Map<const V>(segrates.data(), nseg_total * np);
|
||||
std::vector<ADB::M> old_segqs_derivs = state.segqs.derivative();
|
||||
state.segqs = ADB::function(std::move(new_segqs), std::move(old_segqs_derivs));
|
||||
}
|
||||
|
||||
// This is also called by the base version, but since we have updated
|
||||
// state.segp we must call it again.
|
||||
asImpl().computeWellConnectionPressures(state, well_state);
|
||||
}
|
||||
|
||||
return report;
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
template <class Grid>
|
||||
void
|
||||
BlackoilMultiSegmentModel<Grid>::
|
||||
computeWellConnectionPressures(const SolutionState& state,
|
||||
const WellState& well_state)
|
||||
{
|
||||
const int np = numPhases();
|
||||
const std::vector<ADB> kr_adb = Base::computeRelPerm(state);
|
||||
std::vector<ADB> fluid_density(np, ADB::null());
|
||||
// TODO: make sure the order of the density and the order of the kr are the same.
|
||||
for (int phaseIdx = 0; phaseIdx < np; ++phaseIdx) {
|
||||
const int canonicalPhaseIdx = canph_[phaseIdx];
|
||||
fluid_density[phaseIdx] = fluidDensity(canonicalPhaseIdx, sd_.rq[phaseIdx].b, state.rs, state.rv);
|
||||
}
|
||||
wellModel().computeWellConnectionPressures(state, well_state, kr_adb, fluid_density);
|
||||
}
|
||||
|
||||
} // namespace Opm
|
||||
|
||||
#endif // OPM_BLACKOILMODELBASE_IMPL_HEADER_INCLUDED
|
@ -1,114 +0,0 @@
|
||||
/*
|
||||
Copyright 2013 SINTEF ICT, Applied Mathematics.
|
||||
Copyright 2015 Andreas Lauser
|
||||
|
||||
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 <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
#ifndef OPM_SIMULATORFULLYIMPLICITBLACKOILMULTISEGMENT_HEADER_INCLUDED
|
||||
#define OPM_SIMULATORFULLYIMPLICITBLACKOILMULTISEGMENT_HEADER_INCLUDED
|
||||
|
||||
#include <opm/autodiff/SimulatorBase.hpp>
|
||||
|
||||
|
||||
#include <opm/autodiff/NonlinearSolver.hpp>
|
||||
#include <opm/autodiff/BlackoilMultiSegmentModel.hpp>
|
||||
#include <opm/autodiff/WellStateMultiSegment.hpp>
|
||||
|
||||
namespace Opm {
|
||||
|
||||
template <class GridT>
|
||||
class SimulatorFullyImplicitBlackoilMultiSegment;
|
||||
|
||||
class MultisegmentWells;
|
||||
|
||||
template <class GridT>
|
||||
struct SimulatorTraits<SimulatorFullyImplicitBlackoilMultiSegment<GridT> >
|
||||
{
|
||||
typedef WellStateMultiSegment WellState;
|
||||
typedef BlackoilState ReservoirState;
|
||||
typedef BlackoilOutputWriter OutputWriter;
|
||||
typedef GridT Grid;
|
||||
typedef BlackoilMultiSegmentModel<Grid> Model;
|
||||
typedef NonlinearSolver<Model> Solver;
|
||||
typedef MultisegmentWells WellModel;
|
||||
};
|
||||
|
||||
/// a simulator for the blackoil model
|
||||
template <class GridT>
|
||||
class SimulatorFullyImplicitBlackoilMultiSegment
|
||||
: public SimulatorBase<SimulatorFullyImplicitBlackoilMultiSegment<GridT> >
|
||||
{
|
||||
public:
|
||||
typedef SimulatorBase<SimulatorFullyImplicitBlackoilMultiSegment<GridT> > Base;
|
||||
typedef SimulatorFullyImplicitBlackoilMultiSegment<GridT> ThisType;
|
||||
typedef SimulatorTraits<ThisType> Traits;
|
||||
typedef typename Traits::ReservoirState ReservoirState;
|
||||
typedef typename Traits::WellState WellState;
|
||||
typedef typename Traits::Solver Solver;
|
||||
typedef typename Traits::WellModel WellModel;
|
||||
|
||||
// forward the constructor to the base class
|
||||
SimulatorFullyImplicitBlackoilMultiSegment(const ParameterGroup& param,
|
||||
const GridT& grid,
|
||||
DerivedGeology& geo,
|
||||
BlackoilPropsAdFromDeck& props,
|
||||
const RockCompressibility* rock_comp_props,
|
||||
NewtonIterationBlackoilInterface& linsolver,
|
||||
const double* gravity,
|
||||
const bool disgas,
|
||||
const bool vapoil,
|
||||
std::shared_ptr<EclipseState> eclipse_state,
|
||||
std::shared_ptr<Schedule> schedule,
|
||||
std::shared_ptr<SummaryConfig> summary_config,
|
||||
BlackoilOutputWriter& output_writer,
|
||||
const std::vector<double>& threshold_pressures_by_face,
|
||||
const std::unordered_set<std::string>& defunct_well_names)
|
||||
: Base(param, grid, geo, props, rock_comp_props, linsolver, gravity, disgas, vapoil,
|
||||
eclipse_state, schedule, summary_config, output_writer, threshold_pressures_by_face, defunct_well_names)
|
||||
{}
|
||||
|
||||
|
||||
SimulatorReport run(SimulatorTimer& timer,
|
||||
ReservoirState& state);
|
||||
|
||||
protected:
|
||||
|
||||
std::unique_ptr<Solver> createSolver(const WellModel& well_model);
|
||||
|
||||
using Base::output_writer_;
|
||||
using Base::param_;
|
||||
using Base::solver_;
|
||||
using Base::terminal_output_;
|
||||
using Base::eclipse_state_;
|
||||
using Base::schedule_;
|
||||
using Base::summary_config_;
|
||||
using Base::grid_;
|
||||
using Base::props_;
|
||||
using Base::is_parallel_run_;
|
||||
using Base::allcells_;
|
||||
using Base::model_param_;
|
||||
using Base::geo_;
|
||||
using Base::rock_comp_props_;
|
||||
using Base::has_disgas_;
|
||||
using Base::has_vapoil_;
|
||||
};
|
||||
|
||||
} // namespace Opm
|
||||
|
||||
#include "SimulatorFullyImplicitBlackoilMultiSegment_impl.hpp"
|
||||
|
||||
#endif // OPM_SIMULATORFULLYIMPLICITBLACKOILMULTISEGMENT_HEADER_INCLUDED
|
@ -1,253 +0,0 @@
|
||||
/*
|
||||
Copyright 2013 SINTEF ICT, Applied Mathematics.
|
||||
Copyright 2014 IRIS AS
|
||||
Copyright 2015 Andreas Lauser
|
||||
|
||||
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 <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
|
||||
namespace Opm
|
||||
{
|
||||
|
||||
template <class GridT>
|
||||
auto SimulatorFullyImplicitBlackoilMultiSegment<GridT>::
|
||||
createSolver(const WellModel& well_model)
|
||||
-> std::unique_ptr<Solver>
|
||||
{
|
||||
typedef typename Traits::Model Model;
|
||||
|
||||
auto model = std::unique_ptr<Model>(new Model(model_param_,
|
||||
grid_,
|
||||
props_,
|
||||
geo_,
|
||||
rock_comp_props_,
|
||||
well_model,
|
||||
solver_,
|
||||
eclipse_state_,
|
||||
schedule_,
|
||||
summary_config_,
|
||||
has_disgas_,
|
||||
has_vapoil_,
|
||||
terminal_output_));
|
||||
|
||||
if (!Base::threshold_pressures_by_face_.empty()) {
|
||||
model->setThresholdPressures(Base::threshold_pressures_by_face_);
|
||||
}
|
||||
|
||||
return std::unique_ptr<ThisType::Solver>(new Solver(Base::solver_param_, std::move(model)));
|
||||
|
||||
}
|
||||
|
||||
template <class GridT>
|
||||
SimulatorReport SimulatorFullyImplicitBlackoilMultiSegment<GridT>::run(SimulatorTimer& timer,
|
||||
ReservoirState& state)
|
||||
{
|
||||
WellState prev_well_state;
|
||||
|
||||
// Create timers and file for writing timing info.
|
||||
Opm::time::StopWatch solver_timer;
|
||||
double stime = 0.0;
|
||||
Opm::time::StopWatch step_timer;
|
||||
Opm::time::StopWatch total_timer;
|
||||
total_timer.start();
|
||||
std::string tstep_filename = output_writer_.outputDirectory() + "/step_timing.txt";
|
||||
std::ofstream tstep_os(tstep_filename.c_str());
|
||||
|
||||
// adaptive time stepping
|
||||
const auto& events = schedule_->getEvents();
|
||||
std::unique_ptr< AdaptiveTimeStepping > adaptiveTimeStepping;
|
||||
if( param_.getDefault("timestep.adaptive", true ) )
|
||||
{
|
||||
adaptiveTimeStepping.reset( new AdaptiveTimeStepping( param_, terminal_output_ ) );
|
||||
}
|
||||
|
||||
std::string restorefilename = param_.getDefault("restorefile", std::string("") );
|
||||
if( ! restorefilename.empty() )
|
||||
{
|
||||
// -1 means that we'll take the last report step that was written
|
||||
const int desiredRestoreStep = param_.getDefault("restorestep", int(-1) );
|
||||
output_writer_.restore( timer,
|
||||
state,
|
||||
prev_well_state,
|
||||
restorefilename,
|
||||
desiredRestoreStep );
|
||||
}
|
||||
|
||||
unsigned int totalNonlinearIterations = 0;
|
||||
unsigned int totalLinearIterations = 0;
|
||||
DynamicListEconLimited dynamic_list_econ_limited;
|
||||
|
||||
bool ooip_computed = false;
|
||||
std::vector<int> fipnum_global = eclipse_state_->get3DProperties().getIntGridProperty("FIPNUM").getData();
|
||||
//Get compressed cell fipnum.
|
||||
std::vector<int> fipnum(AutoDiffGrid::numCells(grid_));
|
||||
if (fipnum_global.empty()) {
|
||||
std::fill(fipnum.begin(), fipnum.end(), 0);
|
||||
} else {
|
||||
for (size_t c = 0; c < fipnum.size(); ++c) {
|
||||
fipnum[c] = fipnum_global[AutoDiffGrid::globalCell(grid_)[c]];
|
||||
}
|
||||
}
|
||||
std::vector<std::vector<double> > OOIP;
|
||||
|
||||
// Main simulation loop.
|
||||
while (!timer.done()) {
|
||||
// Report timestep.
|
||||
step_timer.start();
|
||||
if ( terminal_output_ )
|
||||
{
|
||||
timer.report(std::cout);
|
||||
}
|
||||
|
||||
// Create wells and well state.
|
||||
WellsManager wells_manager(*eclipse_state_,
|
||||
*schedule_,
|
||||
timer.currentStepNum(),
|
||||
Opm::UgGridHelpers::numCells(grid_),
|
||||
Opm::UgGridHelpers::globalCell(grid_),
|
||||
Opm::UgGridHelpers::cartDims(grid_),
|
||||
Opm::UgGridHelpers::dimensions(grid_),
|
||||
Opm::UgGridHelpers::cell2Faces(grid_),
|
||||
Opm::UgGridHelpers::beginFaceCentroids(grid_),
|
||||
dynamic_list_econ_limited,
|
||||
is_parallel_run_,
|
||||
// We need to pass the optionaly arguments
|
||||
// as we get the following error otherwise
|
||||
// with c++ (Debian 4.9.2-10) 4.9.2 and -std=c++11
|
||||
// converting to ‘const std::unordered_set<std::basic_string<char> >’ from initializer list would use explicit constructor
|
||||
Base::defunct_well_names_);
|
||||
const Wells* wells = wells_manager.c_wells();
|
||||
WellState well_state;
|
||||
// well_state.init(wells, state, prev_well_state);
|
||||
|
||||
const auto wells_ecl = schedule_->getWells(timer.currentStepNum());
|
||||
const int current_time_step = timer.currentStepNum();
|
||||
|
||||
const WellModel well_model(wells, &(wells_manager.wellCollection()), wells_ecl, current_time_step);
|
||||
|
||||
well_state.init(well_model, state, prev_well_state, wells);
|
||||
|
||||
// give the polymer and surfactant simulators the chance to do their stuff
|
||||
Base::asImpl().handleAdditionalWellInflow(timer, wells_manager, well_state, wells);
|
||||
|
||||
// write the inital state at the report stage
|
||||
if (timer.initialStep()) {
|
||||
// No per cell data is written for initial step, but will be
|
||||
// for subsequent steps, when we have started simulating
|
||||
output_writer_.writeTimeStepWithoutCellProperties( timer, state, well_state, {}, {} );
|
||||
}
|
||||
|
||||
// Max oil saturation (for VPPARS), hysteresis update.
|
||||
props_.updateSatOilMax(state.saturation());
|
||||
props_.updateSatHyst(state.saturation(), allcells_);
|
||||
|
||||
// Compute reservoir volumes for RESV controls.
|
||||
Base::asImpl().computeRESV(timer.currentStepNum(), wells, state, well_state);
|
||||
|
||||
// Run a multiple steps of the solver depending on the time step control.
|
||||
solver_timer.start();
|
||||
|
||||
auto solver = createSolver(well_model);
|
||||
|
||||
// Compute orignal FIP;
|
||||
if (!ooip_computed) {
|
||||
OOIP = solver->computeFluidInPlace(state, fipnum);
|
||||
Base::FIPUnitConvert(eclipse_state_->getUnits(), OOIP);
|
||||
ooip_computed = true;
|
||||
}
|
||||
|
||||
// If sub stepping is enabled allow the solver to sub cycle
|
||||
// in case the report steps are too large for the solver to converge
|
||||
//
|
||||
// \Note: The report steps are met in any case
|
||||
// \Note: The sub stepping will require a copy of the state variables
|
||||
if( adaptiveTimeStepping ) {
|
||||
bool event = events.hasEvent(ScheduleEvents::NEW_WELL, timer.currentStepNum()) ||
|
||||
events.hasEvent(ScheduleEvents::PRODUCTION_UPDATE, timer.currentStepNum()) ||
|
||||
events.hasEvent(ScheduleEvents::INJECTION_UPDATE, timer.currentStepNum()) ||
|
||||
events.hasEvent(ScheduleEvents::WELL_STATUS_CHANGE, timer.currentStepNum());
|
||||
adaptiveTimeStepping->step( timer, *solver, state, well_state, event, output_writer_);
|
||||
}
|
||||
else {
|
||||
// solve for complete report step
|
||||
solver->step(timer, state, well_state);
|
||||
}
|
||||
|
||||
// take time that was used to solve system for this reportStep
|
||||
solver_timer.stop();
|
||||
|
||||
// accumulate the number of nonlinear and linear Iterations
|
||||
totalNonlinearIterations += solver->nonlinearIterations();
|
||||
totalLinearIterations += solver->linearIterations();
|
||||
|
||||
// Report timing.
|
||||
const double st = solver_timer.secsSinceStart();
|
||||
|
||||
// Compute current FIP.
|
||||
std::vector<std::vector<double> > COIP;
|
||||
COIP = solver->computeFluidInPlace(state, fipnum);
|
||||
std::vector<double> OOIP_totals = Base::FIPTotals(OOIP, state);
|
||||
std::vector<double> COIP_totals = Base::FIPTotals(COIP, state);
|
||||
|
||||
//Convert to correct units
|
||||
Base::FIPUnitConvert(eclipse_state_->getUnits(), COIP);
|
||||
Base::FIPUnitConvert(eclipse_state_->getUnits(), OOIP_totals);
|
||||
Base::FIPUnitConvert(eclipse_state_->getUnits(), COIP_totals);
|
||||
|
||||
if ( terminal_output_ )
|
||||
{
|
||||
Base::outputFluidInPlace(OOIP_totals, COIP_totals,eclipse_state_->getUnits(), 0);
|
||||
for (size_t reg = 0; reg < OOIP.size(); ++reg) {
|
||||
Base::outputFluidInPlace(OOIP[reg], COIP[reg], eclipse_state_->getUnits(), reg+1);
|
||||
}
|
||||
}
|
||||
|
||||
if ( terminal_output_ )
|
||||
{
|
||||
std::cout << "Fully implicit solver took: " << st << " seconds." << std::endl;
|
||||
}
|
||||
|
||||
stime += st;
|
||||
if ( output_writer_.output() ) {
|
||||
SimulatorReport step_report;
|
||||
step_report.solver_time = st;
|
||||
step_report.total_time = step_timer.secsSinceStart();
|
||||
step_report.reportParam(tstep_os);
|
||||
}
|
||||
|
||||
// Increment timer, remember well state.
|
||||
++timer;
|
||||
|
||||
|
||||
// write simulation state at the report stage
|
||||
const auto& physicalModel = solver->model();
|
||||
output_writer_.writeTimeStep( timer, state, well_state, physicalModel );
|
||||
|
||||
prev_well_state = well_state;
|
||||
}
|
||||
|
||||
// Stop timer and create timing report
|
||||
total_timer.stop();
|
||||
SimulatorReport report;
|
||||
report.total_time = total_timer.secsSinceStart();
|
||||
report.solver_time = stime;
|
||||
report.total_newton_iterations = totalNonlinearIterations;
|
||||
report.total_linear_iterations = totalLinearIterations;
|
||||
return report;
|
||||
}
|
||||
|
||||
} // namespace Opm
|
Loading…
Reference in New Issue
Block a user