Remove unused code.

This commit is contained in:
Atgeirr Flø Rasmussen 2019-11-25 10:41:56 +01:00
parent bddeaba880
commit e718bf3ccf
21 changed files with 0 additions and 7041 deletions

View File

@ -26,13 +26,6 @@ list (APPEND MAIN_SOURCE_FILES
ebos/nncsorter.cpp
opm/core/props/satfunc/RelpermDiagnostics.cpp
opm/simulators/timestepping/SimulatorReport.cpp
opm/core/wells/InjectionSpecification.cpp
opm/core/wells/ProductionSpecification.cpp
opm/core/wells/WellCollection.cpp
opm/core/wells/WellsGroup.cpp
opm/core/wells/WellsManager.cpp
opm/core/wells/well_controls.cpp
opm/core/wells/wells.c
opm/simulators/flow/MissingFeatures.cpp
opm/simulators/linalg/ExtractParallelGridInformationToISTL.cpp
opm/simulators/linalg/setupPropertyTree.cpp
@ -66,11 +59,6 @@ list (APPEND TEST_SOURCE_FILES
tests/test_deferredlogger.cpp
tests/test_timer.cpp
tests/test_invert.cpp
tests/test_wells.cpp
tests/test_wellsmanager.cpp
tests/test_wellcontrols.cpp
tests/test_wellsgroup.cpp
tests/test_wellcollection.cpp
tests/test_stoppedwells.cpp
tests/test_relpermdiagnostics.cpp
tests/test_norne_pvt.cpp
@ -135,14 +123,6 @@ list (APPEND PUBLIC_HEADER_FILES
opm/core/props/satfunc/RelpermDiagnostics_impl.hpp
opm/simulators/timestepping/SimulatorReport.hpp
opm/simulators/wells/WellState.hpp
opm/core/well_controls.h
opm/core/wells.h
opm/core/wells/InjectionSpecification.hpp
opm/core/wells/ProductionSpecification.hpp
opm/core/wells/WellCollection.hpp
opm/core/wells/WellsGroup.hpp
opm/core/wells/WellsManager.hpp
opm/core/wells/WellsManager_impl.hpp
opm/simulators/aquifers/AquiferInterface.hpp
opm/simulators/aquifers/AquiferCarterTracy.hpp
opm/simulators/aquifers/AquiferFetkovich.hpp

View File

@ -1,138 +0,0 @@
/*
Copyright 2012 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_WELL_CONTROLS_H_INCLUDED
#define OPM_WELL_CONTROLS_H_INCLUDED
#include <stdbool.h>
/**
* @file
* API for managing sets of well controls.
*/
#ifdef __cplusplus
extern "C" {
#endif
enum WellControlType {
BHP, /**< Well constrained by BHP target */
THP, /**< Well constrained by THP target */
RESERVOIR_RATE, /**< Well constrained by reservoir volume flow rate */
SURFACE_RATE /**< Well constrained by surface volume flow rate */
};
struct WellControls;
bool
well_controls_equal(const struct WellControls *ctrls1, const struct WellControls *ctrls2 , bool verbose);
struct WellControls *
well_controls_create(void);
/**
* Create deep copy (clone) of an existing set of well controls.
*
* @param[in] ctrl Existing set of well controls.
*
* @return Deep copy of @c ctrl.
*/
struct WellControls *
well_controls_clone(const struct WellControls *ctrl);
void
well_controls_destroy(struct WellControls *ctrl);
int
well_controls_get_num(const struct WellControls *ctrl);
int
well_controls_get_current( const struct WellControls * ctrl);
void
well_controls_set_current( struct WellControls * ctrl, int current);
bool
well_controls_well_is_stopped(const struct WellControls * ctrl);
bool
well_controls_well_is_open(const struct WellControls * ctrl);
void
well_controls_open_well( struct WellControls * ctrl);
void
well_controls_stop_well( struct WellControls * ctrl);
int
well_controls_add_new(enum WellControlType type , double target , double alq , int vfp , const double * distr , struct WellControls * ctrl);
enum WellControlType
well_controls_iget_type(const struct WellControls * ctrl, int control_index);
enum WellControlType
well_controls_get_current_type(const struct WellControls * ctrl);
void
well_controls_iset_type( struct WellControls * ctrls , int control_index , enum WellControlType type);
void
well_controls_iset_target(struct WellControls * ctrl, int control_index , double target);
double
well_controls_iget_target(const struct WellControls * ctrl, int control_index);
void
well_controls_iset_alq(struct WellControls * ctrl, int control_index , double alq);
double
well_controls_iget_alq(const struct WellControls * ctrl, int control_index );
void
well_controls_iset_vfp(struct WellControls * ctrl, int control_index , int vfp);
int
well_controls_iget_vfp(const struct WellControls * ctrl, int control_index );
double
well_controls_get_current_target(const struct WellControls * ctrl);
const double *
well_controls_iget_distr(const struct WellControls * ctrl, int control_index);
void
well_controls_iset_distr(const struct WellControls * ctrl, int control_index, const double * distr);
const double *
well_controls_get_current_distr(const struct WellControls * ctrl);
void
well_controls_assert_number_of_phases(struct WellControls * ctrl , int number_of_phases);
void
well_controls_clear(struct WellControls * ctrl);
#ifdef __cplusplus
}
#endif
#endif /* OPM_WELL_CONTROLS_H_INCLUDED */

View File

@ -1,352 +0,0 @@
/*
Copyright 2012 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_WELLS_H_INCLUDED
#define OPM_WELLS_H_INCLUDED
#include <stdbool.h>
#include <opm/core/well_controls.h>
/**
* \file
*
* Main OPM-Core well data structure along with functions
* to create, populate and destroy it.
*/
#ifdef __cplusplus
extern "C" {
#endif
/**
* Well type indicates desired/expected well behaviour.
*/
enum WellType {
INJECTOR, /**< Well is an injector */
PRODUCER /**< Well is a producer */
};
/**
* Data structure aggregating static information about all wells in a scenario.
*/
struct Wells
{
int number_of_wells; /**< Number of wells. */
int number_of_phases; /**< Number of phases. */
/**
* Array of well types.
*/
enum WellType *type;
/**
* Array of well reference depths.
*/
double *depth_ref;
/**
* Component fractions for each well. Array of size
* <CODE>number_of_wells * number_of_phases</CODE>.
* For injection wells, this gives the injected component mix.
* For production wells the component fractions of the wellbore
* will vary and cannot be specified a priori, the component mix
* given here should be considered a default or preferred mix.
*/
double *comp_frac;
/**
* Array of indices into well_cells (and WI). For a well @c w,
* <CODE>well_connpos[w]</CODE> and <CODE>well_connpos[w+1]</CODE> are start
* and one-beyond-end indices into the @c well_cells array for accessing
* @c w's perforation cell indices.
*/
int *well_connpos;
/**
* Array of perforation cell indices.
* Size is number of perforations (== well_connpos[number_of_wells]).
*/
int *well_cells;
/**
* Well productivity index, same size and structure as well_cells.
*/
double *WI;
/**
* Saturation table number , same size and structure as well_cells.
*/
int *sat_table_id;
/**
* Well controls, one set of controls for each well.
*/
struct WellControls **ctrls;
/**
* Well names. One string for each well.
*/
char **name;
/**
* Array of flags indicating whether crossflow is allowed or not
* if allow_cf[w] == 0 (false) then crossflow is not allowed in well w.
*/
int *allow_cf;
/**
* Internal management structure.
*/
void *data;
};
/**
* Data structure aggregating dynamic information about all wells in a scenario.
* All arrays in this structure contain data for each perforation, ordered the
* same as Wells::well_cells and Wells:WI. The array sizes are, respectively,
*
* wdp NP
* A n²*NP (matrix in column-major (i.e., Fortran) order).
* phasemob n*NP
*
* in which "n" denotes the number of active fluid phases (and constituent
* components) and "NP" is the total number of perforations,
* <CODE>well_connpos[ number_of_wells ]</CODE>.
*/
struct CompletionData
{
/**
* Gravity potentials.
*/
double *wdp;
/**
* Volumes to surface-components matrix, A = RB^{-1}.
*/
double *A;
/**
* Phase mobilities for all perforations, stored consecutively with the
* phase index cycling the most rapidly.
*/
double *phasemob;
};
/**
* Construct a Wells object initially capable of managing a given
* number of wells and total number of well connections
* (perforations).
*
* Function add_well() is used to populate the Wells object. No
* reallocation occurs in function add_well() as long as the
* initially indicated capacities are sufficient. Call function
* destroy_wells() to dispose of the Wells object and its allocated
* memory resources.
*
* \param[in] nphases Number of active phases in simulation scenario.
*
* \param[in] nwells Expected number of wells in simulation scenario.
* Pass zero if the total number of wells is unknown.
*
* \param[in] nperf Expected total number of well connections
* (perforations) for all wells in simulation
* scenario. Pass zero if the total number of well
* connections is unknown.
*
* \return A valid Wells object with no wells if successful, and NULL
* otherwise.
*/
struct Wells *
create_wells(int nphases, int nwells, int nperf);
/**
* Append a new well to an existing Wells object.
*
* Increments W->number_of_wells by one if successful. The new well
* does not include operational constraints. Such information is
* specified using function append_well_controls(). The current
* control index is set to -1 (invalid).
*
* \param[in] type Type of well.
* \param[in] depth_ref Reference depth for well's BHP.
* \param[in] nperf Number of perforations.
* \param[in] comp_frac Injection fraction array (size equal to W->number_of_phases) or NULL.
* \param[in] cells Grid cells in which well is perforated. Should
* ideally be track ordered.
* \param[in] WI Well production index per perforation, or NULL.
* \param[in] name Name of new well. NULL if no name.
* \param[in] allow_cf Flag to determine whether crossflow is allowed or not.
* \param[in,out] W Existing set of wells to which new well will
* be added.
*
* \return Non-zero (true) if successful and zero otherwise.
*/
int
add_well(enum WellType type ,
double depth_ref,
int nperf ,
const double *comp_frac,
const int *cells ,
const double *WI ,
const int *sat_table_id,
const char *name ,
int allow_cf ,
struct Wells *W );
/**
* Append operational constraint to an existing well.
*
* Increments ctrl->num by one if successful. Introducing a new
* operational constraint does not affect the well's notion of the
* currently active constraint represented by ctrl->current.
* Note that *_RATE controls now require a phase distribution array
* to be associated with the control, see WellControls.
*
* \param[in] type Control type.
* \param[in] target Target value for the control.
* \param[in] alq Artificial lift quantity for control (for THP type only)
* \param[in] vfp VFP table number for control (for THP type only)
* \param[in] distr Array of size W->number_of_phases or NULL.
* \param[in] well_index Index of well to receive additional control.
* \param[in,out] W Existing set of well controls.
* \return Non-zero (true) if successful and zero (false) otherwise.
*/
int
append_well_controls(enum WellControlType type ,
double target,
double alq,
int vfp,
const double *distr,
int well_index,
struct Wells *W);
/**
* Set the current/active control for a single well.
*
* The new control ID must refer to a previously defined control mode.
* Total number of defined control modes available through function
* well_controls_get_num().
*
* \param[in] well_index
* Identity of particular well. Must be in
* \code [0 .. number_of_wells - 1] \endcode.
*
* \param[in] current_control
* Index of new control mode.
*
* \param[in,out] W Existing set of wells.
*/
void
set_current_control(int well_index, int current_control, struct Wells *W);
/**
* Clear all controls from a single well.
*
* Does not affect the control set capacity.
*
* \param[in] well_index
* Identity of particular well. Must be in
* \code [0 .. number_of_wells - 1] \endcode.
*
* \param[in,out] W Existing set of wells.
*/
void
clear_well_controls(int well_index, struct Wells *W);
/**
* Wells object destructor.
*
* Disposes of all resources managed by the Wells object.
*
* The Wells object must be built using function create_wells() and
* subsequently populated using function add_well().
*/
void
destroy_wells(struct Wells *W);
/**
* Create a deep-copy (i.e., clone) of an existing Wells object, including its
* controls.
*
* @param[in] W Existing Wells object.
* @return Complete clone of the input object. Dispose of resources using
* function destroy_wells() when no longer needed. Returns @c NULL in case of
* allocation failure.
*/
struct Wells *
clone_wells(const struct Wells *W);
/**
* Compare well structures for equality.
*
* Two sets of wells are equal if all of the following conditions hold
* - They have the same number of wells
*
* - They have the same number of completions/connections
*
* - They specify the same number of phases
*
* - Individual wells with corresponding well IDs have the same names
* (including both being \c NULL).
*
* - Individual wells with corresponding well IDs have the same
* completions
*
* - Individual wells with corresponding well IDs have the same well
* types
*
* - Individual wells with corresponding well IDs specify the same
* reference depths
*
* - Individual wells with corresponding well IDs have the same set
* of defined and active operational constraints as determined by
* function well_controls_equal()
*
* \param[in] W1 Existing set of wells.
* \param[in] W2 Existing set of wells.
*
* \param[in] verbose Flag for whether or not to report which
* conditions do not hold. Use \code verbose =
* true \endcode to print transcript to \c stdout.
*
* \return Whether or not well structures \c W1 and \c W2 represent
* the same set of wells.
*/
bool
wells_equal(const struct Wells *W1, const struct Wells *W2 , bool verbose);
#ifdef __cplusplus
}
#endif
#endif /* OPM_WELLS_H_INCLUDED */

View File

@ -1,82 +0,0 @@
/*
Copyright 2012 Sintef.
Copyright 2016 Statoil.
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/>.
*/
#include <stdexcept>
#include "config.h"
#include <opm/common/ErrorMacros.hpp>
#include <opm/core/wells/InjectionSpecification.hpp>
namespace Opm
{
InjectionSpecification::InjectionSpecification()
: injector_type_(WATER),
control_mode_(NONE),
surface_flow_max_rate_(-1e100),
reservoir_flow_max_rate_(-1e100),
BHP_limit_(-1e100),
reinjection_fraction_target_(1),
voidage_replacment_fraction_(1),
guide_rate_(-1.0),
guide_rate_type_(NONE_GRT)
{
}
std::string
InjectionSpecification::toString(const ControlMode& mode)
{
switch(mode) {
case ControlMode::NONE: return "NONE";
case ControlMode::RATE: return "RATE";
case ControlMode::RESV: return "RESV";
case ControlMode::BHP : return "BHP" ;
case ControlMode::THP : return "THP" ;
case ControlMode::REIN: return "REIN";
case ControlMode::VREP: return "VREP";
case ControlMode::GRUP: return "GRUP";
case ControlMode::FLD : return "FLD" ;
}
OPM_THROW(std::domain_error, "Unknown control mode " << mode << " encountered in injection specification");
}
std::string
InjectionSpecification::toString(const InjectorType& type)
{
switch(type) {
case InjectorType::WATER: return "WATER";
case InjectorType::OIL : return "OIL" ;
case InjectorType::GAS : return "GAS" ;
}
OPM_THROW(std::domain_error, "Unknown injector type " << type << " encountered in injection specification");
}
std::string
InjectionSpecification::toString(const GuideRateType& type)
{
switch(type) {
case GuideRateType::RAT : return "RAT" ;
case GuideRateType::NONE_GRT: return "NONE_GRT";
}
OPM_THROW(std::domain_error, "Unknown guide rate type " << type << " encountered in injection specification");
}
} // namespace Opm

View File

@ -1,46 +0,0 @@
#ifndef OPM_INJECTORSPECIFICATION_HPP
#define OPM_INJECTORSPECIFICATION_HPP
#include <opm/core/wells.h>
#include <string>
namespace Opm
{
struct InjectionSpecification
{
enum ControlMode
{
NONE, RATE, RESV, BHP, THP, REIN, VREP, GRUP, FLD
};
enum InjectorType
{
WATER, OIL, GAS
};
enum GuideRateType
{
RAT, NONE_GRT
};
InjectionSpecification();
static std::string toString(const ControlMode& mode);
static std::string toString(const InjectorType& type);
static std::string toString(const GuideRateType& type);
InjectorType injector_type_;
ControlMode control_mode_;
double surface_flow_max_rate_;
double reservoir_flow_max_rate_;
double BHP_limit_;
double reinjection_fraction_target_;
double voidage_replacment_fraction_;
double guide_rate_;
GuideRateType guide_rate_type_;
};
}
#endif /* OPM_INJECTORSPECIFICATION_HPP */

View File

@ -1,92 +0,0 @@
/*
Copyright 2012 Sintef.
Copyright 2016 Statoil.
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/>.
*/
#include <stdexcept>
#include "config.h"
#include <opm/common/ErrorMacros.hpp>
#include <opm/core/wells/ProductionSpecification.hpp>
namespace Opm
{
ProductionSpecification::ProductionSpecification()
:
control_mode_(NONE),
procedure_(NONE_P),
oil_max_rate_(-1e100),
water_max_rate_(-1e100),
gas_max_rate_(-1e100),
liquid_max_rate_(-1e100),
reservoir_flow_max_rate_(-1e100),
BHP_limit_(-1e100),
guide_rate_(-1.0),
guide_rate_type_(NONE_GRT)
{
}
std::string
ProductionSpecification::toString(const ControlMode& mode)
{
switch(mode) {
case ControlMode::NONE: return "NONE";
case ControlMode::ORAT: return "ORAT";
case ControlMode::WRAT: return "WRAT";
case ControlMode::GRAT: return "GRAT";
case ControlMode::LRAT: return "LRAT";
case ControlMode::CRAT: return "CRAT";
case ControlMode::RESV: return "RESV";
case ControlMode::PRBL: return "RPBL";
case ControlMode::BHP : return "BHP" ;
case ControlMode::THP : return "THP" ;
case ControlMode::GRUP: return "GRUP";
case ControlMode::FLD : return "FLD" ;
}
OPM_THROW(std::domain_error, "Unknown control mode " << mode << " encountered in production specification");
}
std::string
ProductionSpecification::toString(const Procedure& type)
{
switch(type) {
case Procedure::NONE_P: return "NONE_P";
case Procedure::RATE : return "RATE" ;
case Procedure::WELL : return "WELL" ;
}
OPM_THROW(std::domain_error, "Unknown procedure " << type << " encountered in production specification");
}
std::string
ProductionSpecification::toString(const GuideRateType& type)
{
switch(type) {
case GuideRateType::OIL : return "OIL" ;
case GuideRateType::GAS : return "GAS" ;
case GuideRateType::WATER : return "WATER" ;
case GuideRateType::LIQ : return "LIQ" ;
case GuideRateType::NONE_GRT: return "NONE_GRT";
}
OPM_THROW(std::domain_error, "Unknown guide rate type " << type << " encountered in production specification");
}
}

View File

@ -1,48 +0,0 @@
#ifndef OPM_PRODUCTIONSPECIFICATION_HPP
#define OPM_PRODUCTIONSPECIFICATION_HPP
#include <opm/core/wells.h>
#include <string>
namespace Opm
{
struct ProductionSpecification
{
enum ControlMode
{
NONE = 0, ORAT = 1, WRAT=2, GRAT=3, LRAT=4, CRAT=5, RESV=6, PRBL=7, BHP=8, THP=9, GRUP=10, FLD=11
};
enum Procedure
{
NONE_P, RATE, WELL
};
enum GuideRateType
{
OIL, GAS, WATER, LIQ, NONE_GRT
};
ProductionSpecification();
static std::string toString(const ControlMode& mode);
static std::string toString(const Procedure& type);
static std::string toString(const GuideRateType& type);
ControlMode control_mode_;
Procedure procedure_;
double oil_max_rate_;
double water_max_rate_;
double gas_max_rate_;
double liquid_max_rate_;
double reservoir_flow_max_rate_;
double BHP_limit_;
double guide_rate_;
GuideRateType guide_rate_type_;
};
}
#endif /* OPM_PRODUCTIONSPECIFICATION_HPP */

View File

@ -1,502 +0,0 @@
/*
Copyright 2011 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/>.
*/
#include "config.h"
#include <opm/core/wells/WellCollection.hpp>
#include <opm/parser/eclipse/EclipseState/Schedule/Well/Well.hpp>
#include <opm/parser/eclipse/EclipseState/Schedule/Group/Group.hpp>
#include <opm/parser/eclipse/EclipseState/Schedule/SummaryState.hpp>
#include <boost/lexical_cast.hpp>
#include <memory>
namespace Opm
{
void WellCollection::addField(const Group& fieldGroup, const SummaryState& summaryState, const PhaseUsage& phaseUsage) {
WellsGroupInterface* fieldNode = findNode(fieldGroup.name());
if (fieldNode) {
OPM_THROW(std::runtime_error, "Trying to add FIELD node, but this already exists. Can only have one FIELD node.");
}
roots_.push_back(createGroupWellsGroup(fieldGroup, summaryState, phaseUsage));
}
void WellCollection::addGroup(const Group& groupChild, std::string parent_name,
const SummaryState& summaryState, const PhaseUsage& phaseUsage) {
WellsGroupInterface* parent = findNode(parent_name);
if (!parent) {
OPM_THROW(std::runtime_error, "Trying to add child group to group named " << parent_name << ", but this does not exist in the WellCollection.");
}
if (findNode(groupChild.name())) {
OPM_THROW(std::runtime_error, "Trying to add child group named " << groupChild.name() << ", but this group is already in the WellCollection.");
}
if (groupChild.isProductionGroup() || groupChild.isInjectionGroup()) {
group_control_active_ = true;
}
std::shared_ptr<WellsGroupInterface> child = createGroupWellsGroup(groupChild, summaryState, phaseUsage);
if (child->injSpec().control_mode_ == InjectionSpecification::VREP) {
having_vrep_groups_ = true;
}
WellsGroup* parent_as_group = static_cast<WellsGroup*> (parent);
if (!parent_as_group) {
OPM_THROW(std::runtime_error, "Trying to add child group to group named " << parent->name() << ", but it's not a group.");
}
parent_as_group->addChild(child);
child->setParent(parent);
}
void WellCollection::addWell(const Well& wellChild, const SummaryState& summaryState, const PhaseUsage& phaseUsage) {
if (wellChild.getStatus() == Well::Status::SHUT) {
//SHUT wells are not added to the well collection
return;
}
WellsGroupInterface* parent = findNode(wellChild.groupName());
if (!parent) {
OPM_THROW(std::runtime_error, "Trying to add well " << wellChild.name() << " to group named " << wellChild.groupName() << ", but this group does not exist in the WellCollection.");
}
std::shared_ptr<WellsGroupInterface> child = createWellWellsGroup(wellChild, summaryState, phaseUsage);
WellsGroup* parent_as_group = static_cast<WellsGroup*> (parent);
if (!parent_as_group) {
OPM_THROW(std::runtime_error, "Trying to add well to group named " << wellChild.groupName() << ", but it's not a group.");
}
parent_as_group->addChild(child);
leaf_nodes_.push_back(static_cast<WellNode*>(child.get()));
child->setParent(parent);
}
const std::vector<WellNode*>& WellCollection::getLeafNodes() const {
return leaf_nodes_;
}
WellsGroupInterface* WellCollection::findNode(const std::string& name)
{
for (size_t i = 0; i < roots_.size(); i++) {
WellsGroupInterface* result = roots_[i]->findGroup(name);
if (result) {
return result;
}
}
return NULL;
}
const WellsGroupInterface* WellCollection::findNode(const std::string& name) const
{
for (size_t i = 0; i < roots_.size(); i++) {
WellsGroupInterface* result = roots_[i]->findGroup(name);
if (result) {
return result;
}
}
return NULL;
}
WellNode& WellCollection::findWellNode(const std::string& name) const
{
auto well_node = std::find_if(leaf_nodes_.begin(), leaf_nodes_.end(),
[&] ( WellNode* w) {
return w->name() == name;
});
// Does not find the well
if (well_node == leaf_nodes_.end()) {
OPM_THROW(std::runtime_error, "Could not find well " << name << " in the well collection!\n");
}
return *(*well_node);
}
/// Adds the child to the collection
/// and appends it to parent's children.
/// \param[in] child the child node
/// \param[in] parent name of parent node
void WellCollection::addChild(std::shared_ptr<WellsGroupInterface>& child_node,
const std::string& parent_name)
{
WellsGroupInterface* parent = findNode(parent_name);
if (parent == NULL) {
OPM_THROW(std::runtime_error, "Parent with name = " << parent_name << " not found.");
}
assert(!parent->isLeafNode());
static_cast<WellsGroup*>(parent)->addChild(child_node);
if (child_node->isLeafNode()) {
leaf_nodes_.push_back(static_cast<WellNode*>(child_node.get()));
}
}
/// Adds the node to the collection (as a root node)
void WellCollection::addChild(std::shared_ptr<WellsGroupInterface>& child_node)
{
roots_.push_back(child_node);
if (child_node->isLeafNode()) {
leaf_nodes_.push_back(static_cast<WellNode*> (child_node.get()));
}
}
bool WellCollection::conditionsMet(const std::vector<double>& well_bhp,
const std::vector<double>& well_reservoirrates_phase,
const std::vector<double>& well_surfacerates_phase)
{
for (size_t i = 0; i < roots_.size(); i++) {
WellPhasesSummed phases;
if (!roots_[i]->conditionsMet(well_bhp,
well_reservoirrates_phase,
well_surfacerates_phase,
phases)) {
return false;
}
}
return true;
}
void WellCollection::setWellsPointer(Wells* wells) {
for(size_t i = 0; i < leaf_nodes_.size(); i++) {
leaf_nodes_[i]->setWellsPointer(wells, i);
}
}
void WellCollection::applyGroupControls()
{
for (size_t i = 0; i < roots_.size(); ++i) {
roots_[i]->applyProdGroupControls();
roots_[i]->applyInjGroupControls();
}
group_control_applied_ = true;
}
/// Applies explicit reinjection controls. This must be called at each timestep to be correct.
/// \param[in] well_reservoirrates_phase
/// A vector containing reservoir rates by phase for each well.
/// Is assumed to be ordered the same way as the related Wells-struct,
/// with all phase rates of a single well adjacent in the array.
/// \param[in] well_surfacerates_phase
/// A vector containing surface rates by phase for each well.
/// Is assumed to be ordered the same way as the related Wells-struct,
/// with all phase rates of a single well adjacent in the array.
void WellCollection::applyExplicitReinjectionControls(const std::vector<double>& well_reservoirrates_phase,
const std::vector<double>& well_surfacerates_phase)
{
for (size_t i = 0; i < roots_.size(); ++i) {
roots_[i]->applyExplicitReinjectionControls(well_reservoirrates_phase, well_surfacerates_phase);
}
}
void WellCollection::applyVREPGroupControls(const std::vector<double>& well_voidage_rates,
const std::vector<double>& conversion_coeffs)
{
for (size_t i = 0; i < roots_.size(); ++i) {
roots_[i]->applyVREPGroupControls(well_voidage_rates, conversion_coeffs);
}
}
// TODO: later, it should be extended to update group targets
bool WellCollection::needUpdateWellTargets() const
{
return needUpdateInjectionTargets() || needUpdateProductionTargets();
}
bool WellCollection::needUpdateInjectionTargets() const
{
// TODO: it should based on individual group
// With current approach, it will potentially result in more update,
// thus more iterations, while it will not cause result wrong.
// If the group control and individual control is mixed, then it need to
// update the well targets
bool any_group_control_node = false;
bool any_individual_control_node = false;
for (size_t i = 0; i < leaf_nodes_.size(); ++i) {
if (leaf_nodes_[i]->isInjector()) {
if (leaf_nodes_[i]->individualControl()) {
any_individual_control_node = true;
} else {
any_group_control_node = true;
}
}
}
return (any_group_control_node && any_individual_control_node);
}
// These two functions should be made one
bool WellCollection::needUpdateProductionTargets() const
{
// TODO: it should based on individual group
// With current approach, it will potentially result in more update,
// thus more iterations, while it will not cause result wrong.
// If the group control and individual control is mixed, then it need to
// update the well targets
bool any_group_control_node = false;
bool any_individual_control_node = false;
for (size_t i = 0; i < leaf_nodes_.size(); ++i) {
if (leaf_nodes_[i]->isProducer()) {
if (leaf_nodes_[i]->individualControl()) {
any_individual_control_node = true;
} else {
any_group_control_node = true;
}
}
}
return (any_group_control_node && any_individual_control_node);
}
void WellCollection::updateWellTargets(const std::vector<double>& well_rates)
{
// TODO: if it gets converged, should we still update targets?
// set the target_updated to be false
for (WellNode* well_node : leaf_nodes_) {
well_node->setTargetUpdated(false);
}
// TODO: currently, we only handle the level of the well groups for the moment, i.e. the level just above wells
// We believe the relations between groups are similar to the relations between different wells inside the same group.
// While there will be somre more complication invloved for sure.
for (size_t i = 0; i < leaf_nodes_.size(); ++i) {
// find a node needs to update targets, then update targets for all the wellls inside the group.
if (!leaf_nodes_[i]->targetUpdated()) {
WellsGroupInterface* parent_node = leaf_nodes_[i]->getParent();
// update the target within this group.
if (leaf_nodes_[i]->isProducer()) {
if (parent_node->prodSpec().control_mode_ == ProductionSpecification::NONE) {
continue;
}
parent_node->updateWellProductionTargets(well_rates);
}
if (leaf_nodes_[i]->isInjector()) {
if (parent_node->injSpec().control_mode_ == InjectionSpecification::NONE) {
continue;
}
parent_node->updateWellInjectionTargets(well_rates);
}
}
}
}
bool WellCollection::havingVREPGroups() const
{
return having_vrep_groups_;
}
bool WellCollection::groupControlActive() const
{
return group_control_active_;
}
bool WellCollection::groupControlApplied() const
{
return group_control_applied_;
}
bool WellCollection::groupTargetConverged(const std::vector<double>& well_rates) const
{
// TODO: eventually, there should be only one root node
// TODO: we also need to check the injection target, while we have not done that.
for (const std::shared_ptr<WellsGroupInterface>& root_node : roots_) {
if ( !root_node->groupProdTargetConverged(well_rates) ) {
return false;
}
}
return true;
}
void WellCollection::
setGuideRatesWithPotentials(const Wells* wells,
const PhaseUsage& phase_usage,
const std::vector<double>& well_potentials) const
{
// TODO: assuming the order of well_potentials is the same with the order in wells struct
// TODO: it will overwrite the well potentials from other means. It should be changed after
// fixing the other part of the code. It makes the current flow only support guide rates based on
// well potentials.
const int np = wells->number_of_phases;
const int nw = wells->number_of_wells;
for (int w = 0; w < nw; ++w) {
const std::string well_name = wells->name[w];
WellNode& well_node = findWellNode(well_name);
const WellType well_type = wells->type[w];
// TODO: eventually the following standard will be wrong, it will belong to FIELD group
if (well_node.getParent() != nullptr) { // If it does not belong a group, will it belong to FIELD?
const WellsGroupInterface* group = well_node.getParent();
if (well_type == PRODUCER) {
// The guide rates is calculated based on the group control
// Currently only supporting WRAT, ORAT and GRAT.
ProductionSpecification::ControlMode control_mode = group->prodSpec().control_mode_;
if (control_mode == ProductionSpecification::FLD) {
if (group->getParent() != nullptr) {
// TODO: only handle one level FLD control
const WellsGroupInterface* higher_group = group->getParent();
control_mode = higher_group->prodSpec().control_mode_;
} else {
OPM_THROW(std::runtime_error, "Group " << group->name() << " is under FLD control while no higher level of group is specified.");
}
}
switch (control_mode) {
case ProductionSpecification::WRAT: {
if (!phase_usage.phase_used[BlackoilPhases::Aqua]) {
OPM_THROW(std::runtime_error, "Water phase not used, yet found water rate controlled well.");
}
const int water_index = phase_usage.phase_pos[BlackoilPhases::Aqua];
well_node.prodSpec().guide_rate_ = well_potentials[np * w + water_index];
well_node.prodSpec().guide_rate_type_ = ProductionSpecification::WATER;
break;
}
case ProductionSpecification::ORAT: {
if (!phase_usage.phase_used[BlackoilPhases::Liquid]) {
OPM_THROW(std::runtime_error, "Oil phase not used, yet found oil rate controlled well.");
}
const int oil_index = phase_usage.phase_pos[BlackoilPhases::Liquid];
well_node.prodSpec().guide_rate_ = well_potentials[np * w + oil_index];
well_node.prodSpec().guide_rate_type_ = ProductionSpecification::OIL;
break;
}
case ProductionSpecification::GRAT: {
if (!phase_usage.phase_used[BlackoilPhases::Vapour]) {
OPM_THROW(std::runtime_error, "Gas phase not used, yet found gas rate controlled well.");
}
const int gas_index = phase_usage.phase_pos[BlackoilPhases::Vapour];
well_node.prodSpec().guide_rate_ = well_potentials[np * w + gas_index];
well_node.prodSpec().guide_rate_type_ = ProductionSpecification::GAS;
break;
}
case ProductionSpecification::FLD: {
OPM_THROW(std::logic_error, "Not support more than one continous level of FLD control");
}
case ProductionSpecification::LRAT: {
double guide_rate = 0;
if (phase_usage.phase_used[BlackoilPhases::Liquid]) {
const int oil_index = phase_usage.phase_pos[BlackoilPhases::Liquid];
const double potential_oil = well_potentials[np * w + oil_index];
guide_rate += potential_oil;
}
if (phase_usage.phase_used[BlackoilPhases::Aqua]) {
const int water_index = phase_usage.phase_pos[BlackoilPhases::Aqua];
const double potential_water = well_potentials[np * w + water_index];
guide_rate += potential_water;
}
// not sure if no water and no oil, what will happen here, zero guide_rate?
well_node.prodSpec().guide_rate_ = guide_rate;
well_node.prodSpec().guide_rate_type_ = ProductionSpecification::LIQ;
break;
}
case ProductionSpecification::NONE: {
// Group control is not in use for this group.
break;
}
default:
OPM_THROW(std::logic_error, "Not supported control_mode for guide rate computed" <<
" from well potentials: " << ProductionSpecification::toString(group->prodSpec().control_mode_) );
}
} else if (well_type == INJECTOR) {
// The guide rates is calculated based on the group injector type
switch (group->injSpec().injector_type_) {
case InjectionSpecification::WATER: {
if (!phase_usage.phase_used[BlackoilPhases::Aqua]) {
OPM_THROW(std::runtime_error, "Water phase not used, yet found water injecting well.");
}
const int water_index = phase_usage.phase_pos[BlackoilPhases::Aqua];
well_node.injSpec().guide_rate_ = well_potentials[np * w + water_index];
// Guide rates applies to the phase that the well is injecting i.e water
well_node.injSpec().guide_rate_type_ = InjectionSpecification::RAT;
break;
}
case InjectionSpecification::OIL: {
if (!phase_usage.phase_used[BlackoilPhases::Liquid]) {
OPM_THROW(std::runtime_error, "Oil phase not used, yet found oil injecting well.");
}
const int oil_index = phase_usage.phase_pos[BlackoilPhases::Liquid];
well_node.injSpec().guide_rate_ = well_potentials[np * w + oil_index];
// Guide rates applies to the phase that the well is injecting i.e. oil
well_node.injSpec().guide_rate_type_ = InjectionSpecification::RAT;
break;
}
case InjectionSpecification::GAS: {
if (!phase_usage.phase_used[BlackoilPhases::Vapour]) {
OPM_THROW(std::runtime_error, "Gas phase not used, yet found gas injecting well.");
}
const int gas_index = phase_usage.phase_pos[BlackoilPhases::Vapour];
well_node.injSpec().guide_rate_ = well_potentials[np * w + gas_index];
// Guide rates applies to the phase that the well is injecting i.e gas
well_node.injSpec().guide_rate_type_ = InjectionSpecification::RAT;
break;
}
default:
OPM_THROW(std::logic_error, "Not supported injector type for guide rate computed" <<
" from well potentials: " << InjectionSpecification::toString(group->injSpec().injector_type_) );
}
} else { // neither injector nor producer
OPM_THROW(std::logic_error, "Expected well type to be either INJECTOR or PRODUCER for well " << well_node.name() );
}
} // end of if (well_node.getParent() != nullptr)
} // end of for (int w = 0; w < nw; ++w)
}
bool WellCollection::requireWellPotentials() const
{
for (const auto& well_node : leaf_nodes_) {
if (well_node->isGuideRateWellPotential()) {
return true;
}
}
return false;
}
}

View File

@ -1,179 +0,0 @@
/*
Copyright 2011 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_WELLCOLLECTION_HPP
#define OPM_WELLCOLLECTION_HPP
#include <vector>
#include <memory>
#include <opm/core/wells/WellsGroup.hpp>
#include <opm/grid/UnstructuredGrid.h>
#include <opm/core/props/phaseUsageFromDeck.hpp>
#include <opm/parser/eclipse/EclipseState/Schedule/Well/Well.hpp>
#include <opm/parser/eclipse/EclipseState/Schedule/Group/Group.hpp>
namespace Opm
{
class SummaryState;
class WellCollection
{
public:
void addField(const Group& fieldGroup, const SummaryState& summaryState, const PhaseUsage& phaseUsage);
void addWell(const Well& wellChild, const SummaryState& summaryState, const PhaseUsage& phaseUsage);
void addGroup(const Group& groupChild, std::string parent_name,
const SummaryState& summaryState, const PhaseUsage& phaseUsage);
/// Adds the child to the collection
/// and appends it to parent's children.
/// \param[in] child the child node
/// \param[in] parent name of parent node
void addChild(std::shared_ptr<WellsGroupInterface>& child_node,
const std::string& parent);
/// Adds the node to the collection (as a root node)
void addChild(std::shared_ptr<WellsGroupInterface>& child_node);
/// Checks if each condition is met, applies well controls where needed
/// (that is, it either changes the active control of violating wells, or shuts
/// down wells). Only one change is applied per invocation. Typical use will be
/// \code
/// solve_pressure();
/// while(!collection.conditionsMet(well_bhp, well_rate, summed_phases)) {
/// solve_pressure();
/// }
/// \endcode
///
/// \note It's highly recommended to use the conditionsMet found in WellsManager.
/// \param[in] well_bhp A vector containing the bhp for each well. Is assumed
/// to be ordered the same way as the related Wells-struct.
/// \param[in] well_reservoirrates_phase
/// A vector containing reservoir rates by phase for each well.
/// Is assumed to be ordered the same way as the related Wells-struct,
/// with all phase rates of a single well adjacent in the array.
/// \param[in] well_surfacerates_phase
/// A vector containing surface rates by phase for each well.
/// Is assumed to be ordered the same way as the related Wells-struct,
/// with all phase rates of a single well adjacent in the array.
/// \return true if no violations were found, false otherwise (false also implies a change).
bool conditionsMet(const std::vector<double>& well_bhp,
const std::vector<double>& well_reservoirrates_phase,
const std::vector<double>& well_surfacerates_phase);
/// Adds the well pointer to each leaf node (does not take ownership).
void setWellsPointer(Wells* wells);
/// \return A set of pointers to every well in the collection
const std::vector<WellNode*>& getLeafNodes() const;
/// Finds the group with the given name.
/// \param[in] the name of the group
/// \return the pointer to the group if found, NULL otherwise
WellsGroupInterface* findNode(const std::string& name);
/// Finds the group with the given name.
/// \param[in] the name of the group
/// \return the pointer to the group if found, NULL otherwise
const WellsGroupInterface* findNode(const std::string& name) const;
WellNode& findWellNode(const std::string& name) const;
/// Applies all group controls (injection and production)
void applyGroupControls();
/// Applies explicit reinjection controls. This must be called at each timestep to be correct.
/// \param[in] well_reservoirrates_phase
/// A vector containing reservoir rates by phase for each well.
/// Is assumed to be ordered the same way as the related Wells-struct,
/// with all phase rates of a single well adjacent in the array.
/// \param[in] well_surfacerates_phase
/// A vector containing surface rates by phase for each well.
/// Is assumed to be ordered the same way as the related Wells-struct,
/// with all phase rates of a single well adjacent in the array.
void applyExplicitReinjectionControls(const std::vector<double>& well_reservoirrates_phase,
const std::vector<double>& well_surfacerates_phase);
/// applying VREP group control based on calculated voidage rates
void applyVREPGroupControls(const std::vector<double>& well_voidage_rates,
const std::vector<double>& conversion_coeffs);
/// Checking whether need to update the targets of the wells / or the groups later
/// True need to update well targets within this iteration, no switching control within this iteration.
/// False no need to update well targets within this iteration, continuing as usual.
bool needUpdateWellTargets() const;
/// Checking whether need to update the targets for the injection wells.
bool needUpdateInjectionTargets() const;
/// Checking whehter need to update the targets for the production wells.
bool needUpdateProductionTargets() const;
/// Updating the well targets based on the well rates.
void updateWellTargets(const std::vector<double>& well_rates);
/// When we have VREP group, we need to update the targets based on the updated production voidage rates for each iteration.
bool havingVREPGroups() const;
/// Whether we have active group control
bool groupControlActive() const;
/// Whether we have applied the group control
bool groupControlApplied() const;
/// Whether the group target is converged
// It is considered converged if eitehr the group targets are matched or the group targets are not matched while the wells are
// running under their own limits so that they can not produce more
// It is considered not converged if the group targets are not matched while some of the wells are still running under group control
// The strategy may need to be adjusted when more complicated multi-layered group control situation applied, not sure about thatyet.
bool groupTargetConverged(const std::vector<double>& well_rates) const;
/// Setting the guide rates with well potentials
void setGuideRatesWithPotentials(const Wells* wells,
const PhaseUsage& phase_usage,
const std::vector<double>& well_potentials) const;
bool requireWellPotentials() const;
private:
// To account for the possibility of a forest
std::vector<std::shared_ptr<WellsGroupInterface> > roots_;
// This will be used to traverse the bottom nodes.
std::vector<WellNode*> leaf_nodes_;
bool having_vrep_groups_ = false;
bool group_control_active_ = false;
// This is used to mark whether apply or update the group control
bool group_control_applied_ = false;
};
} // namespace Opm
#endif /* OPM_WELLCOLLECTION_HPP */

File diff suppressed because it is too large Load Diff

View File

@ -1,558 +0,0 @@
/*
Copyright 2012 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_WELLSGROUP_HPP
#define OPM_WELLSGROUP_HPP
#include <opm/core/wells/InjectionSpecification.hpp>
#include <opm/core/wells/ProductionSpecification.hpp>
#include <opm/grid/UnstructuredGrid.h>
#include <opm/core/props/BlackoilPhases.hpp>
#include <opm/parser/eclipse/EclipseState/Schedule/Well/Well.hpp>
#include <opm/parser/eclipse/EclipseState/Schedule/Group/Group.hpp>
#include <string>
#include <memory>
namespace Opm
{
// Need to forward declare this one, some of the methods in the base
// class returns pointers to it.
class WellNode;
/// Basic information needed for group control (each group should typically
/// not exceed the sum of its leaf nodes)
struct WellPhasesSummed
{
WellPhasesSummed();
double res_inj_rates[3];
double res_prod_rates[3];
double surf_inj_rates[3];
double surf_prod_rates[3];
/// Sums each component
void operator+=(const WellPhasesSummed& other);
};
class WellsGroupInterface
{
public:
WellsGroupInterface(const std::string& name,
const double efficiency_factor,
const ProductionSpecification& prod_spec,
const InjectionSpecification& inj_spec,
const PhaseUsage& phase_usage);
virtual ~WellsGroupInterface();
/// The unique identifier for the well or well group.
const std::string& name() const;
/// Production specifications for the well or well group.
const ProductionSpecification& prodSpec() const;
/// Injection specifications for the well or well group.
const InjectionSpecification& injSpec() const;
/// Production specifications for the well or well group.
ProductionSpecification& prodSpec();
/// Injection specifications for the well or well group.
InjectionSpecification& injSpec();
/// Phase usage information.
const PhaseUsage& phaseUsage() const;
/// \returns true if the object is a leaf node (WellNode), false otherwise.
virtual bool isLeafNode() const;
/// \returns the pointer to the WellsGroupInterface with the given name. NULL if
/// the name is not found.a
virtual WellsGroupInterface* findGroup(const std::string& name_of_node) = 0;
/// Sets the parent
/// \param[in] parent the pointer to the parent
void setParent(WellsGroupInterface* parent);
/// Gets the parent of the group, NULL if no parent.
const WellsGroupInterface* getParent() const;
WellsGroupInterface* getParent();
/// Calculates the number of leaf nodes in the given group.
/// A leaf node is defined to have one leaf node in its group.
virtual int numberOfLeafNodes() = 0;
/// Checks if each condition is met, applies well controls where needed
/// (that is, it either changes the active control of violating wells, or shuts
/// down wells). Only one change is applied per invocation. Typical use will be
/// \code
/// solve_pressure();
/// while(!group.conditionsMet(...)) {
/// solve_pressure();
/// }
/// \endcode
///
/// \note It's highly recommended to use the conditionsMet found in WellsManager.
/// \param[in] well_bhp A vector containing the bhp for each well. Is assumed
/// to be ordered the same way as the related Wells-struct.
/// \param[in] well_reservoirrates_phase
/// A vector containing reservoir rates by phase for each well.
/// Is assumed to be ordered the same way as the related Wells-struct,
/// with all phase rates of a single well adjacent in the array.
/// \param[in] well_surfacerates_phase
/// A vector containing surface rates by phase for each well.
/// Is assumed to be ordered the same way as the related Wells-struct,
/// with all phase rates of a single well adjacent in the array.
/// \param[out] summed_phases Will at end of invocation contain the summed phase rates
/// (rate ,etc.) for the group.
/// \return true if no violations were found, false otherwise (false also implies a change).
virtual bool conditionsMet(const std::vector<double>& well_bhp,
const std::vector<double>& well_reservoirrates_phase,
const std::vector<double>& well_surfacerates_phase,
WellPhasesSummed& summed_phases) = 0;
/// Sets the current active control to the provided one for all injectors within the group.
/// After this call, the combined rate (which rate depending on control_mode) of the group
/// shall be equal to target.
/// \param[in] only_group if true, only children that are under group control will be changed.
// otherwise, all children will be set under group control
virtual void applyInjGroupControl(const InjectionSpecification::ControlMode control_mode,
const InjectionSpecification::InjectorType injector_type,
const double target,
const bool only_group) = 0;
/// Sets the current active control to the provided one for all producers within the group.
/// After this call, the combined rate (which rate depending on control_mode) of the group
/// shall be equal to target.
/// \param[in] only_group if true, only children that are under group control will be changed.
// otherwise, all children will be set under group control
virtual void applyProdGroupControl(const ProductionSpecification::ControlMode control_mode,
const double target,
const bool only_group) = 0;
/// Gets the worst offending well based on the input
/// \param[in] well_reservoirrates_phase
/// A vector containing reservoir rates by phase for each well.
/// Is assumed to be ordered the same way as the related Wells-struct,
/// with all phase rates of a single well adjacent in the array.
/// \param[in] well_surfacerates_phase
/// A vector containing surface rates by phase for each well.
/// Is assumed to be ordered the same way as the related Wells-struct,
/// with all phase rates of a single well adjacent in the array.
/// \param[in] mode
/// The relevant control mode to find the maximum over.
/// \return first will be a pointer to the worst offending well, second will be the obtained value at that well.
virtual std::pair<WellNode*, double> getWorstOffending(const std::vector<double>& well_reservoirrates_phase,
const std::vector<double>& well_surfacerates_phase,
ProductionSpecification::ControlMode mode) = 0;
/// Gets the target rate for the given mode.
double getTarget(ProductionSpecification::ControlMode mode) const;
/// Gets the target rate for the given mode.
double getTarget(InjectionSpecification::ControlMode mode) const;
/// Applies any production group control relevant to all children nodes.
/// If no group control is set, this is called recursively to the children.
virtual void applyProdGroupControls() = 0;
/// Applies any injection group control relevant to all children nodes.
/// If no group control is set, this is called recursively to the children.
virtual void applyInjGroupControls() = 0;
/// Calculates the production guide rate for the group.
/// \param[in] only_group If true, will only accumelate guide rates for
/// wells under group control
virtual double productionGuideRate(bool only_group) = 0;
/// Calculates the injection guide rate for the group.
/// \param[in] only_group If true, will only accumelate guide rates for
/// wells under group control
virtual double injectionGuideRate(bool only_group) = 0;
/// Gets the total production flow of the given phase.
/// \param[in] phase_flows A vector containing rates by phase for each well.
/// Is assumed to be ordered the same way as the related Wells-struct,
/// with all phase rates of a single well adjacent in the array.
/// \param[in] phase The phase for which to sum up.
virtual double getTotalProductionFlow(const std::vector<double>& phase_flows,
const BlackoilPhases::PhaseIndex phase) const = 0;
/// Applies explicit reinjection controls. This must be called at each timestep to be correct.
/// \param[in] well_reservoirrates_phase
/// A vector containing reservoir rates by phase for each well.
/// Is assumed to be ordered the same way as the related Wells-struct,
/// with all phase rates of a single well adjacent in the array.
/// \param[in] well_surfacerates_phase
/// A vector containing surface rates by phase for each well.
/// Is assumed to be ordered the same way as the related Wells-struct,
/// with all phase rates of a single well adjacent in the array.
virtual void applyExplicitReinjectionControls(const std::vector<double>& well_reservoirrates_phase,
const std::vector<double>& well_surfacerates_phase) = 0;
/// TODO: prototyping a VREP enforcement function.
virtual void applyVREPGroupControls(const std::vector<double>& well_voidage_rates,
const std::vector<double>& conversion_coeffs) = 0;
virtual void applyVREPGroupControl(const double target,
const InjectionSpecification::InjectorType injector_type,
const std::vector<double>& well_voidage_rates,
const std::vector<double>& conversion_coeffs,
const bool only_group) = 0;
virtual double getTotalVoidageRate(const std::vector<double>& well_voidage_rates) = 0;
/// Return whether the well is running under group control target
/// or under their own limit.
/// True under their own limit.
/// False running under group control target
bool individualControl() const;
/// Update the status for individual contrl
void setIndividualControl(const bool);
virtual double getProductionRate(const std::vector<double>& well_rates,
const ProductionSpecification::ControlMode prod_mode) const = 0;
virtual void updateWellProductionTargets(const std::vector<double>& well_rates) = 0;
virtual void updateWellInjectionTargets(const std::vector<double>& well_rates) = 0;
virtual void setTargetUpdated(const bool flag) = 0;
// bascially, for the group or wells under group control
// they have the potential to adjust their targets to produce more to match the higher level target
virtual bool canProduceMore() const = 0;
// checking wether group production target converged
// if the group is producing following the target, then it should be considered okay
// if the group is not producing following the target, then we should check wether the group
// should be able to produce more to match the target.
// if the group can not produce more, we also consider the effort to match the group target is
// also done and the group target converged while we should give a message
virtual bool groupProdTargetConverged(const std::vector<double>& well_rates) const = 0;
double efficiencyFactor() const;
void setEfficiencyFactor(const double efficiency_factor);
protected:
/// Calculates the correct rate for the given ProductionSpecification::ControlMode
double rateByMode(const double* res_rates,
const double* surf_rates,
const ProductionSpecification::ControlMode mode);
/// Calculates the correct rate for the given InjectionSpecification::ControlMode
double rateByMode(const double* res_rates,
const double* surf_rates,
const InjectionSpecification::ControlMode mode);
WellsGroupInterface* parent_;
// Whether well is running under the group control target.
// Current only consider one level of control.
// So not putting it in the WellsGroupInterface yet.
bool individual_control_;
// Efficiency factor
double efficiency_factor_;
private:
std::string name_;
ProductionSpecification production_specification_;
InjectionSpecification injection_specification_;
PhaseUsage phase_usage_;
};
class WellsGroup : public WellsGroupInterface
{
public:
WellsGroup(const std::string& name,
const double efficiency_factor,
const ProductionSpecification& prod_spec,
const InjectionSpecification& inj_spec,
const PhaseUsage& phase_usage);
virtual WellsGroupInterface* findGroup(const std::string& name_of_node);
void addChild(std::shared_ptr<WellsGroupInterface> child);
virtual bool conditionsMet(const std::vector<double>& well_bhp,
const std::vector<double>& well_reservoirrates_phase,
const std::vector<double>& well_surfacerates_phase,
WellPhasesSummed& summed_phases);
virtual int numberOfLeafNodes();
virtual std::pair<WellNode*, double> getWorstOffending(const std::vector<double>& well_reservoirrates_phase,
const std::vector<double>& well_surfacerates_phase,
ProductionSpecification::ControlMode mode);
/// Sets the current active control to the provided one for all injectors within the group.
/// After this call, the combined rate (which rate depending on control_mode) of the group
/// shall be equal to target.
/// \param[in] only_group if true, only children that are under group control will be changed.
// otherwise, all children will be set under group control
virtual void applyInjGroupControl(const InjectionSpecification::ControlMode control_mode,
const InjectionSpecification::InjectorType injector_type,
const double target,
bool only_group);
/// Sets the current active control to the provided one for all producers within the group.
/// After this call, the combined rate (which rate depending on control_mode) of the group
/// shall be equal to target.
/// \param[in] only_group if true, only children that are under group control will be changed.
// otherwise, all children will be set under group control
virtual void applyProdGroupControl(const ProductionSpecification::ControlMode control_mode,
const double target,
bool only_group);
/// Applies any production group control relevant to all children nodes.
/// If no group control is set, this is called recursively to the children.
virtual void applyProdGroupControls();
/// Applies any injection group control relevant to all children nodes.
/// If no group control is set, this is called recursively to the children.
virtual void applyInjGroupControls();
/// Calculates the production guide rate for the group.
/// \param[in] only_group If true, will only accumelate guide rates for
/// wells under group control
virtual double productionGuideRate(bool only_group);
/// Calculates the injection guide rate for the group.
/// \param[in] only_group If true, will only accumelate guide rates for
/// wells under group control
virtual double injectionGuideRate(bool only_group);
/// Gets the total production flow of the given phase.
/// \param[in] phase_flows A vector containing rates by phase for each well.
/// Is assumed to be ordered the same way as the related Wells-struct,
/// with all phase rates of a single well adjacent in the array.
/// \param[in] phase The phase for which to sum up.
virtual double getTotalProductionFlow(const std::vector<double>& phase_flows,
const BlackoilPhases::PhaseIndex phase) const;
/// Applies explicit reinjection controls. This must be called at each timestep to be correct.
/// \param[in] well_reservoirrates_phase
/// A vector containing reservoir rates by phase for each well.
/// Is assumed to be ordered the same way as the related Wells-struct,
/// with all phase rates of a single well adjacent in the array.
/// \param[in] well_surfacerates_phase
/// A vector containing surface rates by phase for each well.
/// Is assumed to be ordered the same way as the related Wells-struct,
/// with all phase rates of a single well adjacent in the array.
virtual void applyExplicitReinjectionControls(const std::vector<double>& well_reservoirrates_phase,
const std::vector<double>& well_surfacerates_phase);
/// TODO: prototyping a VREP enforcement function.
virtual void applyVREPGroupControls(const std::vector<double>& well_voidage_rates,
const std::vector<double>& conversion_coeffs);
virtual void applyVREPGroupControl(const double target,
const InjectionSpecification::InjectorType injector_type,
const std::vector<double>& well_voidage_rates,
const std::vector<double>& conversion_coeffs,
const bool only_group);
virtual double getTotalVoidageRate(const std::vector<double>& well_voidage_rates);
virtual void updateWellProductionTargets(const std::vector<double>& well_rates);
virtual void updateWellInjectionTargets(const std::vector<double>& well_rates);
virtual void setTargetUpdated(const bool flag);
virtual double getProductionRate(const std::vector<double>& well_rates,
const ProductionSpecification::ControlMode prod_mode) const;
virtual bool canProduceMore() const;
virtual bool groupProdTargetConverged(const std::vector<double>& well_rates) const;
private:
std::vector<std::shared_ptr<WellsGroupInterface> > children_;
};
class WellNode : public WellsGroupInterface
{
public:
WellNode(const std::string& name,
const double efficiency_factor,
const ProductionSpecification& prod_spec,
const InjectionSpecification& inj_spec,
const PhaseUsage& phase_usage);
virtual WellsGroupInterface* findGroup(const std::string& name_of_node);
virtual bool conditionsMet(const std::vector<double>& well_bhp,
const std::vector<double>& well_reservoirrates_phase,
const std::vector<double>& well_surfacerates_phase,
WellPhasesSummed& summed_phases);
virtual bool isLeafNode() const;
void setWellsPointer(Wells* wells, int self_index);
virtual int numberOfLeafNodes();
// Shuts the well (in the well struct)
void shutWell();
virtual std::pair<WellNode*, double> getWorstOffending(const std::vector<double>& well_reservoirrates_phase,
const std::vector<double>& well_surfacerates_phase,
ProductionSpecification::ControlMode mode);
/// Sets the current active control to the provided one for all injectors within the group.
/// After this call, the combined rate (which rate depending on control_mode) of the group
/// shall be equal to target.
/// \param[in] only_group if true, only children that are under group control will be changed.
/// otherwise, all children will be set under group control
virtual void applyInjGroupControl(const InjectionSpecification::ControlMode control_mode,
const InjectionSpecification::InjectorType injector_type,
const double target,
bool only_group);
/// Sets the current active control to the provided one for all producers within the group.
/// After this call, the combined rate (which rate depending on control_mode) of the group
/// shall be equal to target.
/// \param[in] only_group if true, only children that are under group control will be changed.
/// otherwise, all children will be set under group control
virtual void applyProdGroupControl(const ProductionSpecification::ControlMode control_mode,
const double target,
bool only_group);
/// Applies any production group control relevant to all children nodes.
/// If no group control is set, this is called recursively to the children.
virtual void applyProdGroupControls();
/// Applies any injection group control relevant to all children nodes.
/// If no group control is set, this is called recursively to the children.
virtual void applyInjGroupControls();
/// Calculates the production guide rate for the group.
/// \param[in] only_group If true, will only accumelate guide rates for
/// wells under group control
virtual double productionGuideRate(bool only_group);
/// Calculates the injection guide rate for the group.
/// \param[in] only_group If true, will only accumelate guide rates for
/// wells under group control
virtual double injectionGuideRate(bool only_group);
/// Gets the total production flow of the given phase.
/// \param[in] phase_flows A vector containing rates by phase for each well.
/// Is assumed to be ordered the same way as the related Wells-struct,
/// with all phase rates of a single well adjacent in the array.
/// \param[in] phase The phase for which to sum up.
virtual double getTotalProductionFlow(const std::vector<double>& phase_flows,
const BlackoilPhases::PhaseIndex phase) const;
/// Returns the type of the well.
WellType type() const;
/// Applies explicit reinjection controls. This must be called at each timestep to be correct.
/// \param[in] well_reservoirrates_phase
/// A vector containing reservoir rates by phase for each well.
/// Is assumed to be ordered the same way as the related Wells-struct,
/// with all phase rates of a single well adjacent in the array.
/// \param[in] well_surfacerates_phase
/// A vector containing surface rates by phase for each well.
/// Is assumed to be ordered the same way as the related Wells-struct,
/// with all phase rates of a single well adjacent in the array.
virtual void applyExplicitReinjectionControls(const std::vector<double>& well_reservoirrates_phase,
const std::vector<double>& well_surfacerates_phase);
/// TODO: prototyping a VREP enforcement function.
virtual void applyVREPGroupControls(const std::vector<double>& well_voidage_rates,
const std::vector<double>& conversion_coeffs);
virtual void applyVREPGroupControl(const double target,
const InjectionSpecification::InjectorType injector_type,
const std::vector<double>& well_voidage_rates,
const std::vector<double>& conversion_coeffs,
const bool only_group);
virtual double getTotalVoidageRate(const std::vector<double>& well_voidage_rates);
int groupControlIndex() const;
virtual double getProductionRate(const std::vector<double>& well_rates,
const ProductionSpecification::ControlMode prod_mode) const;
virtual void updateWellProductionTargets(const std::vector<double>& well_rates);
virtual void updateWellInjectionTargets(const std::vector<double>& well_rates);
/// the efficiency factor for groups are muliplitive, this function return the resulted final efficiency factor
/// to the well in a multi-layer group structure.
double getAccumulativeEfficiencyFactor() const;
bool isProducer() const;
bool isInjector() const;
int selfIndex() const;
bool targetUpdated() const;
bool isGuideRateWellPotential() const;
void setIsGuideRateWellPotential(const bool flag);
virtual void setTargetUpdated(const bool flag);
virtual bool canProduceMore() const;
virtual bool groupProdTargetConverged(const std::vector<double>& well_rates) const;
private:
Wells* wells_;
int self_index_;
int group_control_index_;
bool shut_well_;
// TODO: used when updating well targets
bool target_updated_;
// whether the guide rate is specified with well potential
// TODO: we have never handle the guide rates for groups, maybe this
// is something will go to WellsGroupInterface later
bool is_guiderate_wellpotential_;
};
/// Creates the WellsGroupInterface for the given well
/// \param[in] well the Well to construct object for
/// \param[in] timeStep the time step in question
/// \param[in] the phase usage
std::shared_ptr<WellsGroupInterface> createWellWellsGroup(const Well& well,
const SummaryState& summaryState,
const PhaseUsage& phase_usage );
/// Creates the WellsGroupInterface for the given Group
/// \param[in] group the Group to construct object for
/// \param[in] timeStep the time step in question
/// \param[in] the phase usage
std::shared_ptr<WellsGroupInterface> createGroupWellsGroup(const Group& group,
const SummaryState& summaryState,
const PhaseUsage& phase_usage );
}
#endif /* OPM_WELLSGROUP_HPP */

View File

@ -1,639 +0,0 @@
/*
Copyright 2012 SINTEF ICT, Applied Mathematics.
Copyright 2016 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/>.
*/
#include "config.h"
#include <opm/core/wells/WellsManager.hpp>
#include <opm/grid/UnstructuredGrid.h>
#include <opm/core/wells.h>
#include <opm/core/well_controls.h>
#include <opm/common/ErrorMacros.hpp>
#include <opm/core/wells/WellCollection.hpp>
#include <opm/core/wells/WellsGroup.hpp>
#include <opm/core/props/phaseUsageFromDeck.hpp>
#include <algorithm>
#include <cassert>
#include <cmath>
#include <cstddef>
#include <map>
#include <string>
#include <utility>
#include <iostream>
namespace
{
static double invalid_alq = -1e100;
static double invalid_vfp = -2147483647;
} //Namespace
// Helper structs and functions for the implementation.
namespace WellsManagerDetail
{
namespace ProductionControl
{
namespace Details {
std::map<std::string, Mode>
init_mode_map() {
std::map<std::string, Mode> m;
m.insert(std::make_pair("ORAT", ORAT));
m.insert(std::make_pair("WRAT", WRAT));
m.insert(std::make_pair("GRAT", GRAT));
m.insert(std::make_pair("LRAT", LRAT));
m.insert(std::make_pair("CRAT", CRAT));
m.insert(std::make_pair("RESV", RESV));
m.insert(std::make_pair("BHP" , BHP ));
m.insert(std::make_pair("THP" , THP ));
m.insert(std::make_pair("GRUP", GRUP));
return m;
}
} // namespace Details
Mode mode(const std::string& control)
{
static std::map<std::string, Mode>
mode_map = Details::init_mode_map();
std::map<std::string, Mode>::iterator
p = mode_map.find(control);
if (p != mode_map.end()) {
return p->second;
}
else {
OPM_THROW(std::runtime_error, "Unknown well control mode = "
<< control << " in input file");
}
}
Mode mode(Opm::Well::ProducerCMode controlMode)
{
switch( controlMode ) {
case Opm::Well::ProducerCMode::ORAT:
return ORAT;
case Opm::Well::ProducerCMode::WRAT:
return WRAT;
case Opm::Well::ProducerCMode::GRAT:
return GRAT;
case Opm::Well::ProducerCMode::LRAT:
return LRAT;
case Opm::Well::ProducerCMode::CRAT:
return CRAT;
case Opm::Well::ProducerCMode::RESV:
return RESV;
case Opm::Well::ProducerCMode::BHP:
return BHP;
case Opm::Well::ProducerCMode::THP:
return THP;
case Opm::Well::ProducerCMode::GRUP:
return GRUP;
default:
throw std::invalid_argument("unhandled enum value");
}
}
} // namespace ProductionControl
namespace InjectionControl
{
namespace Details {
std::map<std::string, Mode>
init_mode_map() {
std::map<std::string, Mode> m;
m.insert(std::make_pair("RATE", RATE));
m.insert(std::make_pair("RESV", RESV));
m.insert(std::make_pair("BHP" , BHP ));
m.insert(std::make_pair("THP" , THP ));
m.insert(std::make_pair("GRUP", GRUP));
return m;
}
} // namespace Details
Mode mode(const std::string& control)
{
static std::map<std::string, Mode>
mode_map = Details::init_mode_map();
std::map<std::string, Mode>::iterator
p = mode_map.find(control);
if (p != mode_map.end()) {
return p->second;
}
else {
OPM_THROW(std::runtime_error, "Unknown well control mode = "
<< control << " in input file");
}
}
Mode mode(Opm::Well::InjectorCMode controlMode)
{
switch ( controlMode ) {
case Opm::Well::InjectorCMode::GRUP:
return GRUP;
case Opm::Well::InjectorCMode::RESV:
return RESV;
case Opm::Well::InjectorCMode::RATE:
return RATE;
case Opm::Well::InjectorCMode::THP:
return THP;
case Opm::Well::InjectorCMode::BHP:
return BHP;
default:
throw std::invalid_argument("unhandled enum value");
}
}
} // namespace InjectionControl
} // anonymous namespace
namespace Opm
{
/// Default constructor.
WellsManager::WellsManager()
: w_(create_wells(0,0,0)), is_parallel_run_(false)
{
}
/// Construct from existing wells object.
WellsManager::WellsManager(struct Wells* W)
: w_(clone_wells(W)), is_parallel_run_(false)
{
}
/// Construct wells from deck.
WellsManager::WellsManager(const Opm::EclipseState& eclipseState,
const Opm::Schedule& schedule,
const SummaryState& summaryState,
const size_t timeStep,
const UnstructuredGrid& grid)
: w_(create_wells(0,0,0)), is_parallel_run_(false)
{
init(eclipseState, schedule, summaryState, timeStep, UgGridHelpers::numCells(grid),
UgGridHelpers::globalCell(grid), UgGridHelpers::cartDims(grid),
UgGridHelpers::dimensions(grid),
UgGridHelpers::cell2Faces(grid), UgGridHelpers::beginFaceCentroids(grid),
std::unordered_set<std::string>());
}
/// Destructor.
WellsManager::~WellsManager()
{
destroy_wells(w_);
}
/// Does the "deck" define any wells?
bool WellsManager::empty() const
{
return (w_ == 0) || (w_->number_of_wells == 0);
}
/// Access the managed Wells.
/// The method is named similarly to c_str() in std::string,
/// to make it clear that we are returning a C-compatible struct.
const Wells* WellsManager::c_wells() const
{
return w_;
}
const WellCollection& WellsManager::wellCollection() const
{
return well_collection_;
}
WellCollection& WellsManager::wellCollection() {
return well_collection_;
}
bool WellsManager::conditionsMet(const std::vector<double>& well_bhp,
const std::vector<double>& well_reservoirrates_phase,
const std::vector<double>& well_surfacerates_phase)
{
return well_collection_.conditionsMet(well_bhp,
well_reservoirrates_phase,
well_surfacerates_phase);
}
/// Applies explicit reinjection controls. This must be called at each timestep to be correct.
/// \param[in] well_reservoirrates_phase
/// A vector containing reservoir rates by phase for each well.
/// Is assumed to be ordered the same way as the related Wells-struct,
/// with all phase rates of a single well adjacent in the array.
/// \param[in] well_surfacerates_phase
/// A vector containing surface rates by phase for each well.
/// Is assumed to be ordered the same way as the related Wells-struct,
/// with all phase rates of a single well adjacent in the array.
void WellsManager::applyExplicitReinjectionControls(const std::vector<double>& well_reservoirrates_phase,
const std::vector<double>& well_surfacerates_phase)
{
well_collection_.applyExplicitReinjectionControls(well_reservoirrates_phase, well_surfacerates_phase);
}
void WellsManager::setupCompressedToCartesian(const int* global_cell, int number_of_cells,
std::map<int,int>& cartesian_to_compressed ) {
// global_cell is a map from compressed cells to Cartesian grid cells.
// We must make the inverse lookup.
if (global_cell) {
for (int i = 0; i < number_of_cells; ++i) {
cartesian_to_compressed.insert(std::make_pair(global_cell[i], i));
}
}
else {
for (int i = 0; i < number_of_cells; ++i) {
cartesian_to_compressed.insert(std::make_pair(i, i));
}
}
}
void WellsManager::setupWellControls(const std::vector<Well>& wells,
const SummaryState& summaryState,
std::vector<std::string>& well_names,
const PhaseUsage& phaseUsage,
const std::vector<int>& wells_on_proc) {
int well_index = 0;
auto well_on_proc = wells_on_proc.begin();
for (auto wellIter = wells.begin(); wellIter != wells.end(); ++wellIter, ++well_on_proc) {
if( ! *well_on_proc )
{
// Wells not stored on the process are not in the list
continue;
}
const auto& well = (*wellIter);
if (well.getStatus() == Well::Status::SHUT) {
//SHUT wells are not added to the well list
continue;
}
if (well.getStatus() == Well::Status::STOP) {
// Stopped wells are kept in the well list but marked as stopped.
well_controls_stop_well(w_->ctrls[well_index]);
}
if (well.isInjector()) {
const auto controls = well.injectionControls(summaryState);
int ok = 1;
int control_pos[5] = { -1, -1, -1, -1, -1 };
clear_well_controls(well_index, w_);
if (controls.hasControl(Well::InjectorCMode::RATE)) {
control_pos[WellsManagerDetail::InjectionControl::RATE] = well_controls_get_num(w_->ctrls[well_index]);
double distr[3] = { 0.0, 0.0, 0.0 };
auto injectorType = controls.injector_type;
if (injectorType == Well::InjectorType::WATER) {
distr[phaseUsage.phase_pos[BlackoilPhases::Aqua]] = 1.0;
} else if (injectorType == Well::InjectorType::OIL) {
distr[phaseUsage.phase_pos[BlackoilPhases::Liquid]] = 1.0;
} else if (injectorType == Well::InjectorType::GAS) {
distr[phaseUsage.phase_pos[BlackoilPhases::Vapour]] = 1.0;
}
ok = append_well_controls(SURFACE_RATE,
controls.surface_rate,
invalid_alq,
invalid_vfp,
distr,
well_index,
w_);
}
if (ok && controls.hasControl(Well::InjectorCMode::RESV)) {
control_pos[WellsManagerDetail::InjectionControl::RESV] = well_controls_get_num(w_->ctrls[well_index]);
double distr[3] = { 0.0, 0.0, 0.0 };
auto injectorType = controls.injector_type;
if (injectorType == Well::InjectorType::WATER) {
distr[phaseUsage.phase_pos[BlackoilPhases::Aqua]] = 1.0;
} else if (injectorType == Well::InjectorType::OIL) {
distr[phaseUsage.phase_pos[BlackoilPhases::Liquid]] = 1.0;
} else if (injectorType == Well::InjectorType::GAS) {
distr[phaseUsage.phase_pos[BlackoilPhases::Vapour]] = 1.0;
}
ok = append_well_controls(RESERVOIR_RATE,
controls.reservoir_rate,
invalid_alq,
invalid_vfp,
distr,
well_index,
w_);
}
if (ok && controls.hasControl(Well::InjectorCMode::BHP)) {
control_pos[WellsManagerDetail::InjectionControl::BHP] = well_controls_get_num(w_->ctrls[well_index]);
ok = append_well_controls(BHP,
controls.bhp_limit,
invalid_alq,
invalid_vfp,
NULL,
well_index,
w_);
}
if (ok && controls.hasControl(Well::InjectorCMode::THP)) {
control_pos[WellsManagerDetail::InjectionControl::THP] = well_controls_get_num(w_->ctrls[well_index]);
const double thp_limit = controls.thp_limit;
const int vfp_number = controls.vfp_table_number;
ok = append_well_controls(THP,
thp_limit,
invalid_alq,
vfp_number,
NULL,
well_index,
w_);
}
if (!ok) {
OPM_THROW(std::runtime_error, "Failure occured appending controls for well " << well_names[well_index]);
}
if (controls.cmode != Well::InjectorCMode::CMODE_UNDEFINED) {
WellsManagerDetail::InjectionControl::Mode mode = WellsManagerDetail::InjectionControl::mode(controls.cmode);
int cpos = control_pos[mode];
if (cpos == -1 && mode != WellsManagerDetail::InjectionControl::GRUP) {
OPM_THROW(std::runtime_error, "Control not specified in well " << well_names[well_index]);
}
set_current_control(well_index, cpos, w_);
}
// Set well component fraction.
double cf[3] = { 0.0, 0.0, 0.0 };
{
auto injectorType = controls.injector_type;
if (injectorType == Well::InjectorType::WATER) {
if (!phaseUsage.phase_used[BlackoilPhases::Aqua]) {
OPM_THROW(std::runtime_error, "Water phase not used, yet found water-injecting well.");
}
cf[phaseUsage.phase_pos[BlackoilPhases::Aqua]] = 1.0;
} else if (injectorType == Well::InjectorType::OIL) {
if (!phaseUsage.phase_used[BlackoilPhases::Liquid]) {
OPM_THROW(std::runtime_error, "Oil phase not used, yet found oil-injecting well.");
}
cf[phaseUsage.phase_pos[BlackoilPhases::Liquid]] = 1.0;
} else if (injectorType == Well::InjectorType::GAS) {
if (!phaseUsage.phase_used[BlackoilPhases::Vapour]) {
OPM_THROW(std::runtime_error, "Gas phase not used, yet found gas-injecting well.");
}
cf[phaseUsage.phase_pos[BlackoilPhases::Vapour]] = 1.0;
}
std::copy(cf, cf + phaseUsage.num_phases, w_->comp_frac + well_index*phaseUsage.num_phases);
}
}
if (well.isProducer( )) {
// Add all controls that are present in well.
// First we must clear existing controls, in case the
// current WCONPROD line is modifying earlier controls.
const auto controls = well.productionControls(summaryState);
int control_pos[9] = { -1, -1, -1, -1, -1, -1, -1, -1, -1 };
int ok = 1;
clear_well_controls(well_index, w_);
if (ok && controls.hasControl(Well::ProducerCMode::ORAT)) {
if (!phaseUsage.phase_used[BlackoilPhases::Liquid]) {
OPM_THROW(std::runtime_error, "Oil phase not active and ORAT control specified.");
}
control_pos[WellsManagerDetail::ProductionControl::ORAT] = well_controls_get_num(w_->ctrls[well_index]);
double distr[3] = { 0.0, 0.0, 0.0 };
distr[phaseUsage.phase_pos[BlackoilPhases::Liquid]] = 1.0;
ok = append_well_controls(SURFACE_RATE,
-controls.oil_rate,
invalid_alq,
invalid_vfp,
distr,
well_index,
w_);
}
if (ok && controls.hasControl(Well::ProducerCMode::WRAT)) {
if (!phaseUsage.phase_used[BlackoilPhases::Aqua]) {
OPM_THROW(std::runtime_error, "Water phase not active and WRAT control specified.");
}
control_pos[WellsManagerDetail::ProductionControl::WRAT] = well_controls_get_num(w_->ctrls[well_index]);
double distr[3] = { 0.0, 0.0, 0.0 };
distr[phaseUsage.phase_pos[BlackoilPhases::Aqua]] = 1.0;
ok = append_well_controls(SURFACE_RATE,
-controls.water_rate,
invalid_alq,
invalid_vfp,
distr,
well_index,
w_);
}
if (ok && controls.hasControl(Well::ProducerCMode::GRAT)) {
if (!phaseUsage.phase_used[BlackoilPhases::Vapour]) {
OPM_THROW(std::runtime_error, "Gas phase not active and GRAT control specified.");
}
control_pos[WellsManagerDetail::ProductionControl::GRAT] = well_controls_get_num(w_->ctrls[well_index]);
double distr[3] = { 0.0, 0.0, 0.0 };
distr[phaseUsage.phase_pos[BlackoilPhases::Vapour]] = 1.0;
ok = append_well_controls(SURFACE_RATE,
-controls.gas_rate,
invalid_alq,
invalid_vfp,
distr,
well_index,
w_);
}
if (ok && controls.hasControl(Well::ProducerCMode::LRAT)) {
if (!phaseUsage.phase_used[BlackoilPhases::Aqua]) {
OPM_THROW(std::runtime_error, "Water phase not active and LRAT control specified.");
}
if (!phaseUsage.phase_used[BlackoilPhases::Liquid]) {
OPM_THROW(std::runtime_error, "Oil phase not active and LRAT control specified.");
}
control_pos[WellsManagerDetail::ProductionControl::LRAT] = well_controls_get_num(w_->ctrls[well_index]);
double distr[3] = { 0.0, 0.0, 0.0 };
distr[phaseUsage.phase_pos[BlackoilPhases::Aqua]] = 1.0;
distr[phaseUsage.phase_pos[BlackoilPhases::Liquid]] = 1.0;
ok = append_well_controls(SURFACE_RATE,
-controls.liquid_rate,
invalid_alq,
invalid_vfp,
distr,
well_index,
w_);
}
if (ok && controls.hasControl(Well::ProducerCMode::RESV)) {
control_pos[WellsManagerDetail::ProductionControl::RESV] = well_controls_get_num(w_->ctrls[well_index]);
double distr[3] = { 1.0, 1.0, 1.0 };
ok = append_well_controls(RESERVOIR_RATE,
-controls.resv_rate,
invalid_alq,
invalid_vfp,
distr,
well_index,
w_);
}
if (ok && controls.hasControl(Well::ProducerCMode::THP)) {
const double thp_limit = controls.thp_limit;
const double alq_value = controls.alq_value;
const int vfp_number = controls.vfp_table_number;
control_pos[WellsManagerDetail::ProductionControl::THP] = well_controls_get_num(w_->ctrls[well_index]);
ok = append_well_controls(THP,
thp_limit,
alq_value,
vfp_number,
NULL,
well_index,
w_);
}
if (ok) {
const double bhp_limit = controls.bhp_limit;
control_pos[WellsManagerDetail::ProductionControl::BHP] = well_controls_get_num(w_->ctrls[well_index]);
ok = append_well_controls(BHP,
bhp_limit,
invalid_alq,
invalid_vfp,
NULL,
well_index,
w_);
}
if (!ok) {
OPM_THROW(std::runtime_error, "Failure occured appending controls for well " << well_names[well_index]);
}
if (controls.cmode != Well::ProducerCMode::CMODE_UNDEFINED) {
WellsManagerDetail::ProductionControl::Mode mode = WellsManagerDetail::ProductionControl::mode(controls.cmode);
int cpos = control_pos[mode];
if (cpos == -1 && mode != WellsManagerDetail::ProductionControl::GRUP) {
OPM_THROW(std::runtime_error, "Control mode type " << mode << " not present in well " << well_names[well_index]);
}
else {
set_current_control(well_index, cpos, w_);
}
}
// Set well component fraction to match preferred phase for the well.
double cf[3] = { 0.0, 0.0, 0.0 };
{
switch (well.getPreferredPhase()) {
case Phase::WATER:
if (!phaseUsage.phase_used[BlackoilPhases::Aqua]) {
OPM_THROW(std::runtime_error, "Water phase not used, yet found water-preferring well.");
}
cf[phaseUsage.phase_pos[BlackoilPhases::Aqua]] = 1.0;
break;
case Phase::OIL:
if (!phaseUsage.phase_used[BlackoilPhases::Liquid]) {
OPM_THROW(std::runtime_error, "Oil phase not used, yet found oil-preferring well.");
}
cf[phaseUsage.phase_pos[BlackoilPhases::Liquid]] = 1.0;
break;
case Phase::GAS:
if (!phaseUsage.phase_used[BlackoilPhases::Vapour]) {
OPM_THROW(std::runtime_error, "Gas phase not used, yet found gas-preferring well.");
}
cf[phaseUsage.phase_pos[BlackoilPhases::Vapour]] = 1.0;
break;
default:
OPM_THROW(std::logic_error, "Unknown preferred phase: " << well.getPreferredPhase());
}
std::copy(cf, cf + phaseUsage.num_phases, w_->comp_frac + well_index*phaseUsage.num_phases);
}
}
well_index++;
}
}
// only handle the guide rates from the keyword WGRUPCON
void WellsManager::setupGuideRates(const std::vector<Well>& wells, std::vector<WellData>& well_data, std::map<std::string, int>& well_names_to_index)
{
for (auto wellIter = wells.begin(); wellIter != wells.end(); ++wellIter ) {
const auto& well = *wellIter;
if (well.getStatus() == Well::Status::SHUT) {
//SHUT wells does not need guide rates
continue;
}
const int wix = well_names_to_index[well.name()];
WellNode& wellnode = *well_collection_.getLeafNodes()[wix];
// TODO: looks like only handling OIL phase guide rate for producers
if (well.getGuideRatePhase() != Well::GuideRateTarget::UNDEFINED && well.getGuideRate() >= 0.) {
if (well_data[wix].type == PRODUCER) {
wellnode.prodSpec().guide_rate_ = well.getGuideRate();
if (well.getGuideRatePhase() == Well::GuideRateTarget::OIL) {
wellnode.prodSpec().guide_rate_type_ = ProductionSpecification::OIL;
} else {
OPM_THROW(std::runtime_error, "Guide rate type " << Well::GuideRateTarget2String(well.getGuideRatePhase()) << " specified for producer "
<< well.name() << " in WGRUPCON, cannot handle.");
}
} else if (well_data[wix].type == INJECTOR) {
wellnode.injSpec().guide_rate_ = well.getGuideRate();
if (well.getGuideRatePhase() == Well::GuideRateTarget::RAT) {
wellnode.injSpec().guide_rate_type_ = InjectionSpecification::RAT;
} else {
OPM_THROW(std::runtime_error, "Guide rate type " << Well::GuideRateTarget2String(well.getGuideRatePhase()) << " specified for injector "
<< well.name() << " in WGRUPCON, cannot handle.");
}
} else {
OPM_THROW(std::runtime_error, "Unknown well type " << well_data[wix].type << " for well " << well.name());
}
} else {
wellnode.setIsGuideRateWellPotential(true);
}
}
}
} // namespace Opm

View File

@ -1,201 +0,0 @@
/*
Copyright 2012 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_WELLSMANAGER_HEADER_INCLUDED
#define OPM_WELLSMANAGER_HEADER_INCLUDED
#include <unordered_set>
#include <opm/parser/eclipse/EclipseState/EclipseState.hpp>
#include <opm/core/wells/WellCollection.hpp>
#include <opm/core/wells/WellsGroup.hpp>
struct Wells;
struct UnstructuredGrid;
namespace Opm
{
class Schedule;
struct WellData
{
WellType type;
bool allowCrossFlow;
// WellControlType control;
// double target;
double reference_bhp_depth;
// Opm::InjectionSpecification::InjectorType injected_phase;
int welspecsline;
};
struct PerfData
{
int cell;
double well_index;
int satnumid;
};
/// This class manages a Wells struct in the sense that it
/// encapsulates creation and destruction of the wells
/// data structure.
/// The resulting Wells is available through the c_wells() method.
class WellsManager
{
public:
/// Default constructor -- no wells.
WellsManager();
/// Construct from existing wells object.
/// WellsManager is not properly initialised in the sense that the logic to
/// manage control switching does not exist.
///
/// @param[in] W Existing wells object.
explicit WellsManager(struct Wells* W);
/// Construct from input deck and grid.
/// The permeability argument may be zero if the input contain
/// well productivity indices, otherwise it must be given in
/// order to approximate these by the Peaceman formula.
///
/// \param deactivated_wells A set of wells that should be treated
/// like shut wells. E.g. in a a parallel run these would be
/// the wells handeled by another process. Defaults to empty set.
template<class F2C, class FC>
WellsManager(const Opm::EclipseState& eclipseState,
const Opm::Schedule& schedule,
const SummaryState& summaryState,
const size_t timeStep,
int num_cells,
const int* global_cell,
const int* cart_dims,
int dimensions,
const F2C& f2c,
FC begin_face_centroids,
bool is_parallel_run=false,
const std::unordered_set<std::string>& deactivated_wells = std::unordered_set<std::string> ());
WellsManager(const Opm::EclipseState& eclipseState,
const Opm::Schedule& schedule,
const Opm::SummaryState& summaryState,
const size_t timeStep,
const UnstructuredGrid& grid);
/// Destructor.
~WellsManager();
/// Does the "deck" define any wells?
bool empty() const;
/// Access the managed Wells.
/// The method is named similarly to c_str() in std::string,
/// to make it clear that we are returning a C-compatible struct.
const Wells* c_wells() const;
/// Access the well group hierarchy.
const WellCollection& wellCollection() const;
WellCollection& wellCollection();
/// Checks if each condition is met, applies well controls where needed
/// (that is, it either changes the active control of violating wells, or shuts
/// down wells). Only one change is applied per invocation. Typical use will be
/// \code
/// solve_pressure();
/// while(!wells.conditionsMet(...)) {
/// solve_pressure();
/// }
/// \endcode
/// \param[in] well_bhp A vector containing the bhp for each well. Is assumed
/// to be ordered the same way as the related Wells-struct.
/// \param[in] well_reservoirrates_phase
/// A vector containing reservoir rates by phase for each well.
/// Is assumed to be ordered the same way as the related Wells-struct,
/// with all phase rates of a single well adjacent in the array.
/// \param[in] well_surfacerates_phase
/// A vector containing surface rates by phase for each well.
/// Is assumed to be ordered the same way as the related Wells-struct,
/// with all phase rates of a single well adjacent in the array.
/// \return true if no violations were found, false otherwise (false also implies a change).
bool conditionsMet(const std::vector<double>& well_bhp,
const std::vector<double>& well_reservoirrates_phase,
const std::vector<double>& well_surfacerates_phase);
/// Applies explicit reinjection controls. This must be called at each timestep to be correct.
/// \param[in] well_reservoirrates_phase
/// A vector containing reservoir rates by phase for each well.
/// Is assumed to be ordered the same way as the related Wells-struct,
/// with all phase rates of a single well adjacent in the array.
/// \param[in] well_surfacerates_phase
/// A vector containing surface rates by phase for each well.
/// Is assumed to be ordered the same way as the related Wells-struct,
/// with all phase rates of a single well adjacent in the array.
void applyExplicitReinjectionControls(const std::vector<double>& well_reservoirrates_phase,
const std::vector<double>& well_surfacerates_phase);
private:
template<class C2F, class FC>
void init(const Opm::EclipseState& eclipseState,
const Opm::Schedule& schedule,
const Opm::SummaryState& summaryState,
const size_t timeStep,
int num_cells,
const int* global_cell,
const int* cart_dims,
int dimensions,
const C2F& cell_to_faces,
FC begin_face_centroids,
const std::unordered_set<std::string>& deactivated_wells);
// Disable copying and assignment.
WellsManager(const WellsManager& other);
WellsManager& operator=(const WellsManager& other);
static void setupCompressedToCartesian(const int* global_cell, int number_of_cells, std::map<int,int>& cartesian_to_compressed );
void setupWellControls(const std::vector<Well>& wells, const SummaryState& summaryState,
std::vector<std::string>& well_names, const PhaseUsage& phaseUsage,
const std::vector<int>& wells_on_proc);
template<class C2F, class FC>
void createWellsFromSpecs( const std::vector<Well>& wells, size_t timeStep,
const C2F& cell_to_faces,
const int* cart_dims,
FC begin_face_centroids,
int dimensions,
std::vector<double>& dz,
std::vector<std::string>& well_names,
std::vector<WellData>& well_data,
std::map<std::string, int> & well_names_to_index,
const PhaseUsage& phaseUsage,
const std::map<int,int>& cartesian_to_compressed,
std::vector<int>& wells_on_proc,
const std::unordered_set<std::string>& deactivated_wells);
void setupGuideRates(const std::vector<Well>& wells, std::vector<WellData>& well_data, std::map<std::string, int>& well_names_to_index);
// Data
Wells* w_;
WellCollection well_collection_;
// Whether this is a parallel simulation
bool is_parallel_run_;
};
} // namespace Opm
#include "WellsManager_impl.hpp"
#endif // OPM_WELLSMANAGER_HEADER_INCLUDED

View File

@ -1,408 +0,0 @@
#include <opm/parser/eclipse/Units/Units.hpp>
#include <opm/grid/GridHelpers.hpp>
#include <opm/common/ErrorMacros.hpp>
#include <opm/common/OpmLog/OpmLog.hpp>
#include <opm/grid/utility/compressedToCartesian.hpp>
#include <opm/parser/eclipse/EclipseState/Grid/EclipseGrid.hpp>
#include <opm/parser/eclipse/EclipseState/Schedule/Well/WellConnections.hpp>
#include <opm/parser/eclipse/EclipseState/Schedule/Schedule.hpp>
#include <algorithm>
#include <array>
#include <cstddef>
#include <exception>
#include <iterator>
#include <numeric>
namespace WellsManagerDetail
{
namespace ProductionControl
{
enum Mode { ORAT, WRAT, GRAT,
LRAT, CRAT, RESV,
BHP , THP , GRUP };
/*
namespace Details {
std::map<std::string, Mode>
init_mode_map();
} // namespace Details
*/
Mode mode(const std::string& control);
Mode mode(Opm::Well::ProducerCMode controlMode);
} // namespace ProductionControl
namespace InjectionControl
{
enum Mode { RATE, RESV, BHP,
THP, GRUP };
/*
namespace Details {
std::map<std::string, Mode>
init_mode_map();
} // namespace Details
*/
Mode mode(const std::string& control);
Mode mode(Opm::Well::InjectorCMode controlMode);
} // namespace InjectionControl
template <int dim, class C2F, class FC>
std::array<double, dim>
getCubeDim(const C2F& c2f,
FC begin_face_centroids,
int cell)
{
std::array< std::vector<double>, dim > X;
{
const std::vector<double>::size_type
nf = std::distance(c2f[cell].begin(),
c2f[cell].end ());
for (int d = 0; d < dim; ++d) {
X[d].reserve(nf);
}
}
typedef typename C2F::row_type::const_iterator FI;
for (FI f = c2f[cell].begin(), e = c2f[cell].end(); f != e; ++f) {
using Opm::UgGridHelpers::increment;
using Opm::UgGridHelpers::getCoordinate;
const FC& fc = increment(begin_face_centroids, *f, dim);
for (int d = 0; d < dim; ++d) {
X[d].push_back(getCoordinate(fc, d));
}
}
std::array<double, dim> cube;
for (int d = 0; d < dim; ++d) {
typedef std::vector<double>::iterator VI;
typedef std::pair<VI,VI> PVI;
const PVI m = std::minmax_element(X[d].begin(), X[d].end());
cube[d] = *m.second - *m.first;
}
return cube;
}
} // end namespace WellsManagerDetail
namespace Opm
{
template<class C2F, class FC>
void WellsManager::createWellsFromSpecs(const std::vector<Well>& wells, size_t timeStep,
const C2F& /* c2f */,
const int* cart_dims,
FC /* begin_face_centroids */,
int dimensions,
std::vector<double>& /* dz */,
std::vector<std::string>& well_names,
std::vector<WellData>& well_data,
std::map<std::string, int>& well_names_to_index,
const PhaseUsage& phaseUsage,
const std::map<int,int>& cartesian_to_compressed,
std::vector<int>& wells_on_proc,
const std::unordered_set<std::string>& ignored_wells)
{
if (dimensions != 3) {
OPM_THROW(std::domain_error,
"WellsManager::createWellsFromSpecs() only "
"supported in three space dimensions");
}
std::vector<std::vector<PerfData> > wellperf_data;
wellperf_data.resize(wells.size());
wells_on_proc.resize(wells.size(), 1);
// The well index on the current process.
// Note that some wells are deactivated as they live on the interior
// domain of another proccess. Therefore this might different from
// the index of the well according to the eclipse state
int active_well_index = 0;
for (auto wellIter= wells.begin(); wellIter != wells.end(); ++wellIter) {
const auto& well = (*wellIter);
if (well.getStatus() == Well::Status::SHUT) {
continue;
}
if ( ignored_wells.find(well.name()) != ignored_wells.end() ) {
wells_on_proc[ wellIter - wells.begin() ] = 0;
continue;
}
{ // COMPDAT handling
// shut completions and open ones stored in this process will have 1 others 0.
for(const auto& completion : well.getConnections()) {
if (completion.state() == Connection::State::OPEN) {
const int i = completion.getI();
const int j = completion.getJ();
const int k = completion.getK();
const int* cpgdim = cart_dims;
const int cart_grid_indx = i + cpgdim[0]*(j + cpgdim[1]*k);
const std::map<int, int>::const_iterator cgit = cartesian_to_compressed.find(cart_grid_indx);
if (cgit == cartesian_to_compressed.end()) {
const std::string msg = ("Cell with i,j,k indices " + std::to_string(i) + " " + std::to_string(j)
+ " " + std::to_string(k) + " not found in grid (well = " + well.name() + ").");
OPM_THROW(std::runtime_error, msg);
}
else
{
PerfData pd;
pd.cell = cgit->second;
pd.well_index = completion.CF() * completion.wellPi();
pd.satnumid = completion.satTableId();
wellperf_data[active_well_index].push_back(pd);
}
} else {
if (completion.state() != Connection::State::SHUT) {
OPM_THROW(std::runtime_error, "Completion state: " << Connection::State2String( completion.state() ) << " not handled");
}
}
}
}
if (wellperf_data[active_well_index].empty()) {
const std::string msg = " there is no perforations associated with the well "
+ well.name() + ", the well is ignored for the report step "
+ std::to_string(timeStep);
OpmLog::warning(msg);
wells_on_proc[wellIter - wells.begin()] = 0;
continue;
}
{ // WELSPECS handling
well_names_to_index[well.name()] = active_well_index;
well_names.push_back(well.name());
{
WellData wd;
wd.reference_bhp_depth = well.getRefDepth( );
wd.welspecsline = -1;
if (well.isInjector( ))
wd.type = INJECTOR;
else
wd.type = PRODUCER;
wd.allowCrossFlow = well.getAllowCrossFlow();
well_data.push_back(wd);
}
}
active_well_index++;
}
// Set up reference depths that were defaulted. Count perfs.
const int num_wells = well_data.size();
int num_perfs = 0;
assert (dimensions == 3);
for (int w = 0; w < num_wells; ++w) {
num_perfs += wellperf_data[w].size();
}
// Create the well data structures.
struct Wells* w = create_wells(phaseUsage.num_phases, num_wells, num_perfs);
if (!w) {
OPM_THROW(std::runtime_error, "Failed creating Wells struct.");
}
std::swap( w, w_ );
destroy_wells( w );
// Add wells.
for (int iw = 0; iw < num_wells; ++iw) {
const int w_num_perf = wellperf_data[iw].size();
std::vector<int> perf_cells (w_num_perf);
std::vector<double> perf_prodind(w_num_perf);
std::vector<int> perf_satnumid(w_num_perf);
for (int perf = 0; perf < w_num_perf; ++perf) {
perf_cells [perf] = wellperf_data[iw][perf].cell;
perf_prodind[perf] = wellperf_data[iw][perf].well_index;
perf_satnumid[perf] = wellperf_data[iw][perf].satnumid;
}
const double* comp_frac = NULL;
// We initialize all wells with a null component fraction,
// and must (for injection wells) overwrite it later.
const int ok =
add_well(well_data[iw].type,
well_data[iw].reference_bhp_depth,
w_num_perf,
comp_frac,
perf_cells.data(),
perf_prodind.data(),
perf_satnumid.data(),
well_names[iw].c_str(),
well_data[iw].allowCrossFlow,
w_);
if (!ok) {
OPM_THROW(std::runtime_error,
"Failed adding well "
<< well_names[iw]
<< " to Wells data structure.");
}
}
}
template <class C2F, class FC>
WellsManager::
WellsManager(const Opm::EclipseState& eclipseState,
const Opm::Schedule& schedule,
const Opm::SummaryState& summaryState,
const size_t timeStep,
int number_of_cells,
const int* global_cell,
const int* cart_dims,
int dimensions,
const C2F& cell_to_faces,
FC begin_face_centroids,
bool is_parallel_run,
const std::unordered_set<std::string>& deactivated_wells)
: w_(create_wells(0,0,0)), is_parallel_run_(is_parallel_run)
{
init(eclipseState, schedule, summaryState, timeStep, number_of_cells, global_cell,
cart_dims, dimensions,
cell_to_faces, begin_face_centroids, deactivated_wells);
}
/// Construct wells from deck.
template <class C2F, class FC>
void
WellsManager::init(const Opm::EclipseState& eclipseState,
const Opm::Schedule& schedule,
const Opm::SummaryState& summaryState,
const size_t timeStep,
int number_of_cells,
const int* global_cell,
const int* cart_dims,
int dimensions,
const C2F& cell_to_faces,
FC begin_face_centroids,
const std::unordered_set<std::string>& deactivated_wells)
{
if (dimensions != 3) {
OPM_THROW(std::runtime_error,
"We cannot initialize wells from a deck unless "
"the corresponding grid is 3-dimensional.");
}
if (schedule.numWells() == 0) {
OPM_MESSAGE("No wells specified in Schedule section, "
"initializing no wells");
return;
}
std::map<int,int> cartesian_to_compressed;
setupCompressedToCartesian(global_cell, number_of_cells,
cartesian_to_compressed);
// Obtain phase usage data.
PhaseUsage pu = phaseUsageFromDeck(eclipseState);
// These data structures will be filled in this constructor,
// then used to initialize the Wells struct.
std::vector<std::string> well_names;
std::vector<WellData> well_data;
// For easy lookup:
std::map<std::string, int> well_names_to_index;
const auto wells = schedule.getWells(timeStep);
std::vector<int> wells_on_proc;
well_names.reserve(wells.size());
well_data.reserve(wells.size());
const auto& eclGrid = eclipseState.getInputGrid();
// use cell thickness (dz) from eclGrid
// dz overwrites values calculated by WellDetails::getCubeDim
std::vector<double> dz(number_of_cells);
{
std::vector<int> gc = compressedToCartesian(number_of_cells, global_cell);
for (int cell = 0; cell < number_of_cells; ++cell) {
dz[cell] = eclGrid.getCellThickness(gc[cell]);
}
}
createWellsFromSpecs(wells, timeStep, cell_to_faces,
cart_dims,
begin_face_centroids,
dimensions,
dz,
well_names, well_data, well_names_to_index,
pu, cartesian_to_compressed,
wells_on_proc, deactivated_wells);
setupWellControls(wells, summaryState, well_names, pu, wells_on_proc);
{
const auto& fieldGroup = schedule.getGroup( "FIELD", timeStep);
well_collection_.addField(fieldGroup, summaryState, pu);
std::vector< std::string > group_stack = { "FIELD" };
do {
const auto& parent = schedule.getGroup(group_stack.back(), timeStep);
group_stack.pop_back();
for (const auto& child: parent.groups()) {
group_stack.push_back(child);
well_collection_.addGroup( schedule.getGroup( child, timeStep ), parent.name(), summaryState, pu );
}
} while( !group_stack.empty() );
}
for (size_t i = 0; i < wells_on_proc.size(); ++i) {
// wells_on_proc is a vector of flag to indicate whether a well is on the process
if (wells_on_proc[i]) {
well_collection_.addWell(wells[i], summaryState, pu);
}
}
well_collection_.setWellsPointer(w_);
if (well_collection_.groupControlActive()) {
// here does not consider the well potentials related guide rate setting
setupGuideRates(wells, well_data, well_names_to_index);
}
// Debug output.
#define EXTRA_OUTPUT
#ifdef EXTRA_OUTPUT
/*
std::cout << "\t WELL DATA" << std::endl;
for(int i = 0; i< num_wells; ++i) {
std::cout << i << ": " << well_data[i].type << " "
<< well_data[i].control << " " << well_data[i].target
<< std::endl;
}
std::cout << "\n\t PERF DATA" << std::endl;
for(int i=0; i< int(wellperf_data.size()); ++i) {
for(int j=0; j< int(wellperf_data[i].size()); ++j) {
std::cout << i << ": " << wellperf_data[i][j].cell << " "
<< wellperf_data[i][j].well_index << std::endl;
}
}
*/
#endif
}
} // end namespace Opm

View File

@ -1,459 +0,0 @@
/*===========================================================================
//
// File: newwells.c
//
// Created: 2012-02-03 11:28:40+0100
//
// Authors: Knut-Andreas Lie <Knut-Andreas.Lie@sintef.no>
// Jostein R. Natvig <Jostein.R.Natvig@sintef.no>
// Halvor M. Nilsen <HalvorMoll.Nilsen@sintef.no>
// Atgeirr F. Rasmussen <atgeirr@sintef.no>
// Xavier Raynaud <Xavier.Raynaud@sintef.no>
// Bård Skaflestad <Bard.Skaflestad@sintef.no>
//
//==========================================================================*/
/*
Copyright 2012 SINTEF ICT, Applied Mathematics.
Copyright 2012 Statoil ASA.
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/>.
*/
#include "config.h"
#include <opm/core/well_controls.h>
#include <assert.h>
#include <string.h>
#include <stdlib.h>
#include <stdio.h>
#include <stdexcept>
/**
* Controls for a single well.
* Each control specifies a well rate or bottom-hole pressure. Only
* one control can be active at a time, indicated by current. The
* meaning of each control's target value depends on the control type:
*
* - BHP -> target bottom hole pressure in Pascal.
* - THP -> target tubing head pressure in Pascal.
* - RESERVOIR_RATE -> target reservoir volume rate in cubic(meter)/second
* - SURFACE_RATE -> target surface volume rate in cubic(meter)/second
*
* The sign convention for RATE targets is as follows:
*
* - (+) Fluid flowing into reservoir, i.e. injecting.
* - (-) Fluid flowing out of reservoir, i.e. producing.
*
* For *_RATE controls, the distribution of phases used for the control
* is also needed. For example, a total rate control should have 1.0
* for each phase, whereas a control on oil rate should have 1.0 for
* the oil phase and 0.0 for the rest. For BHP controls, this is unused.
* The active control acts as an equality constraint, whereas the
* non-active controls should be interpreted as inequality
* constraints (upper or lower bounds). For instance, a PRODUCER's
* BHP constraint defines a minimum acceptable bottom-hole pressure
* value for the well.
*/
struct WellControls
{
/**
* Number of controls.
*/
int num;
int number_of_phases;
/**
* Array of control types.
*/
enum WellControlType *type;
/**
* Array of control targets.
*/
double *target;
/**
* Array of artificial lift quantities.
*/
double *alq;
/**
* Array of VFP table numbers
*/
int *vfp;
/**
* Array of rate control distributions,
* <CODE>number_of_phases</CODE> numbers for each control
*/
double *distr;
/**
* Index of current active control.
*/
int current;
bool well_is_open;
/*
The capacity allocated.
*/
int cpty;
};
/* ---------------------------------------------------------------------- */
void
well_controls_destroy(struct WellControls *ctrl)
/* ---------------------------------------------------------------------- */
{
if (ctrl != NULL) {
free (ctrl->distr);
free (ctrl->target);
free (ctrl->type);
free (ctrl->alq);
free (ctrl->vfp);
}
free(ctrl);
}
/* ---------------------------------------------------------------------- */
struct WellControls *
well_controls_create(void)
/* ---------------------------------------------------------------------- */
{
struct WellControls *ctrl;
ctrl = static_cast<WellControls*>(malloc(1 * sizeof *ctrl));
if (ctrl != NULL) {
/* Initialise empty control set; the well is created open. */
ctrl->num = 0;
ctrl->number_of_phases = 0;
ctrl->type = NULL;
ctrl->target = NULL;
ctrl->alq = NULL;
ctrl->vfp = NULL;
ctrl->distr = NULL;
ctrl->current = -1;
ctrl->cpty = 0;
ctrl->well_is_open = true;
}
return ctrl;
}
/* ---------------------------------------------------------------------- */
static int
well_controls_reserve(int nctrl, struct WellControls *ctrl)
/* ---------------------------------------------------------------------- */
{
void *type, *target, *alq, *vfp, *distr;
type = realloc(ctrl->type , nctrl * 1 * sizeof *ctrl->type );
target = realloc(ctrl->target, nctrl * 1 * sizeof *ctrl->target);
alq = realloc(ctrl->alq , nctrl * 1 * sizeof *ctrl->alq );
vfp = realloc(ctrl->vfp , nctrl * 1 * sizeof *ctrl->vfp );
distr = realloc(ctrl->distr , nctrl * ctrl->number_of_phases * sizeof *ctrl->distr );
int ok = 0;
if (type != NULL) { ctrl->type = static_cast<WellControlType*>(type) ; ok++; }
if (target != NULL) { ctrl->target = static_cast<double*>(target); ok++; }
if (alq != NULL) { ctrl->alq = static_cast<double*>(alq ); ok++; }
if (vfp != NULL) { ctrl->vfp = static_cast<int*>(vfp); ok++; }
if (distr != NULL) { ctrl->distr = static_cast<double*>(distr) ; ok++; }
if (ok == 5) {
for (int c = ctrl->cpty; c < nctrl; c++) {
ctrl->type [c] = BHP;
ctrl->target[c] = -1.0;
}
for (int p = ctrl->cpty * ctrl->number_of_phases; p < nctrl * ctrl->number_of_phases; ++p) {
ctrl->distr[ p ] = 0.0;
}
ctrl->cpty = nctrl;
}
return ok == 5;
}
/* ---------------------------------------------------------------------- */
struct WellControls *
well_controls_clone(const struct WellControls *ctrl)
/* ---------------------------------------------------------------------- */
{
struct WellControls* new_ctrls = well_controls_create();
if (new_ctrls != NULL) {
/* Assign appropriate number of phases */
well_controls_assert_number_of_phases(new_ctrls, ctrl->number_of_phases);
int n = well_controls_get_num(ctrl);
int ok = well_controls_reserve(n, new_ctrls);
if (! ok) {
well_controls_destroy(new_ctrls);
new_ctrls= NULL;
}
else {
int i;
for (i = 0; ok && (i < n); i++) {
enum WellControlType type = well_controls_iget_type (ctrl, i);
const double* distr = well_controls_iget_distr (ctrl, i);
double target = well_controls_iget_target(ctrl, i);
double alq = well_controls_iget_alq (ctrl, i);
int vfp = well_controls_iget_vfp (ctrl, i);
ok = well_controls_add_new(type, target, alq, vfp, distr, new_ctrls);
}
if (i < n) {
assert (!ok);
well_controls_destroy(new_ctrls);
new_ctrls = NULL;
}
else {
i = well_controls_get_current(ctrl);
well_controls_set_current(new_ctrls, i);
if (well_controls_well_is_open(ctrl)) {
well_controls_open_well(new_ctrls);
}
else {
well_controls_stop_well(new_ctrls);
}
}
}
}
assert (well_controls_equal(ctrl, new_ctrls, true));
return new_ctrls;
}
int well_controls_get_num(const struct WellControls *ctrl) {
return ctrl->num;
}
int well_controls_get_current( const struct WellControls * ctrl) {
return ctrl->current;
}
void
well_controls_set_current( struct WellControls * ctrl, int current) {
ctrl->current = current;
}
bool well_controls_well_is_stopped(const struct WellControls * ctrl) {
return !ctrl->well_is_open;
}
bool well_controls_well_is_open(const struct WellControls * ctrl) {
return ctrl->well_is_open;
}
void well_controls_open_well( struct WellControls * ctrl) {
ctrl->well_is_open = true;
}
void well_controls_stop_well( struct WellControls * ctrl) {
ctrl->well_is_open = false;
}
enum WellControlType
well_controls_iget_type(const struct WellControls * ctrl, int control_index) {
return ctrl->type[control_index];
}
enum WellControlType
well_controls_get_current_type(const struct WellControls * ctrl) {
if (ctrl->current < 0)
throw std::logic_error("Tried to use invalid current control < 0");
return well_controls_iget_type( ctrl , ctrl->current);
}
void
well_controls_iset_type( struct WellControls * ctrls , int control_index , enum WellControlType type) {
ctrls->type[control_index] = type;
}
double
well_controls_iget_target(const struct WellControls * ctrl, int control_index) {
return ctrl->target[control_index];
}
double
well_controls_get_current_target(const struct WellControls * ctrl) {
if (ctrl->current < 0)
throw std::logic_error("Tried to use invalid current control < 0");
return ctrl->target[ctrl->current];
}
void
well_controls_iset_target(struct WellControls * ctrl, int control_index , double target) {
ctrl->target[control_index] = target;
}
double
well_controls_iget_alq(const struct WellControls * ctrl, int control_index) {
return ctrl->alq[control_index];
}
void
well_controls_iset_alq(struct WellControls * ctrl, int control_index , double alq) {
ctrl->alq[control_index] = alq;
}
int
well_controls_iget_vfp(const struct WellControls * ctrl, int control_index) {
return ctrl->vfp[control_index];
}
void
well_controls_iset_vfp(struct WellControls * ctrl, int control_index , int vfp) {
ctrl->vfp[control_index] = vfp;
}
const double *
well_controls_iget_distr(const struct WellControls * ctrl, int control_index) {
int offset = control_index * ctrl->number_of_phases;
return &ctrl->distr[offset];
}
const double *
well_controls_get_current_distr(const struct WellControls * ctrl) {
if (ctrl->current < 0)
throw std::logic_error("Tried to use invalid current control < 0");
return well_controls_iget_distr( ctrl , ctrl->current );
}
void
well_controls_iset_distr(const struct WellControls * ctrl, int control_index, const double * distr) {
int offset = control_index * ctrl->number_of_phases;
int p;
for (p=0; p < ctrl->number_of_phases; p++)
ctrl->distr[offset + p] = distr[p];
}
void
well_controls_assert_number_of_phases(struct WellControls * ctrl , int number_of_phases) {
if (ctrl->num == 0)
ctrl->number_of_phases = number_of_phases;
assert( ctrl->number_of_phases == number_of_phases );
}
void
well_controls_clear(struct WellControls * ctrl) {
ctrl->num = 0;
ctrl->number_of_phases = 0;
}
int
well_controls_add_new(enum WellControlType type , double target , double alq , int vfp , const double * distr , struct WellControls * ctrl) {
if (ctrl->num == ctrl->cpty) {
int new_cpty = 2*ctrl->cpty;
if (new_cpty == ctrl->num)
new_cpty += 1;
if (!well_controls_reserve( new_cpty , ctrl))
return 0;
}
well_controls_iset_type( ctrl , ctrl->num , type);
well_controls_iset_target( ctrl , ctrl->num , target);
well_controls_iset_alq(ctrl , ctrl->num , alq);
well_controls_iset_vfp(ctrl , ctrl->num , vfp);
if (distr != NULL)
well_controls_iset_distr( ctrl , ctrl->num , distr);
ctrl->num += 1;
return 1;
}
bool
well_controls_equal(const struct WellControls *ctrls1, const struct WellControls *ctrls2 , bool verbose)
/* ---------------------------------------------------------------------- */
{
bool are_equal = true;
if (!ctrls1 || !ctrls2) {
if (verbose)
printf("ctrls1 %p or cntrls2 %p is NULL\n",
(void*) ctrls1, (void*) ctrls2);
return false;
}
if (ctrls1->num != ctrls2->num) {
are_equal = false;
if (verbose)
printf("ctrls1->num:%d ctrls2->num:%d \n",ctrls1->num , ctrls2->num);
}
if (ctrls1->number_of_phases != ctrls2->number_of_phases) {
are_equal = false;
if (verbose)
printf("ctrls1->number_of_phases:%d ctrls2->number_of_phases:%d \n",ctrls1->number_of_phases , ctrls2->number_of_phases);
}
if (!are_equal) {
return are_equal;
}
if (memcmp(ctrls1->type, ctrls2->type, ctrls1->num * sizeof *ctrls1->type ) != 0) {
are_equal = false;
if (verbose)
printf("The ->type vectors are different \n");
}
if (memcmp(ctrls1->target, ctrls2->target, ctrls1->num * sizeof *ctrls1->target ) != 0) {
are_equal = false;
if (verbose)
printf("The ->target vectors are different \n");
}
return are_equal;
}

View File

@ -1,632 +0,0 @@
/*===========================================================================
//
// File: newwells.c
//
// Created: 2012-02-03 11:28:40+0100
//
// Authors: Knut-Andreas Lie <Knut-Andreas.Lie@sintef.no>
// Jostein R. Natvig <Jostein.R.Natvig@sintef.no>
// Halvor M. Nilsen <HalvorMoll.Nilsen@sintef.no>
// Atgeirr F. Rasmussen <atgeirr@sintef.no>
// Xavier Raynaud <Xavier.Raynaud@sintef.no>
// Bård Skaflestad <Bard.Skaflestad@sintef.no>
//
//==========================================================================*/
/*
Copyright 2012 SINTEF ICT, Applied Mathematics.
Copyright 2012 Statoil ASA.
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/>.
*/
#include "config.h"
#include <opm/core/wells.h>
#include <opm/core/well_controls.h>
#include <assert.h>
#include <stddef.h>
#include <stdlib.h>
#include <string.h>
#include <stdio.h>
struct WellMgmt {
int well_cpty;
int perf_cpty;
};
static void
destroy_well_mgmt(struct WellMgmt *m)
{
free(m);
}
static struct WellMgmt *
create_well_mgmt(void)
{
struct WellMgmt *m;
m = malloc(1 * sizeof *m);
if (m != NULL) {
m->well_cpty = 0;
m->perf_cpty = 0;
}
return m;
}
/* ---------------------------------------------------------------------- */
static int
wells_allocate(int nwells, struct Wells *W)
/* ---------------------------------------------------------------------- */
{
int ok, np;
void *type, *depth_ref, *comp_frac;
void *well_connpos;
void *ctrls, *name;
void *allow_cf;
np = W->number_of_phases;
type = realloc(W->type , 1 * nwells * sizeof *W->type);
depth_ref = realloc(W->depth_ref, 1 * nwells * sizeof *W->depth_ref);
comp_frac = realloc(W->comp_frac, np * nwells * sizeof *W->comp_frac);
ctrls = realloc(W->ctrls , 1 * nwells * sizeof *W->ctrls);
name = realloc(W->name , 1 * nwells * sizeof *W->name);
allow_cf = realloc(W->allow_cf , 1 * nwells * sizeof *W->allow_cf);
well_connpos = realloc(W->well_connpos,
(nwells + 1) * sizeof *W->well_connpos);
ok = 0;
if (type != NULL) { W->type = type ; ok++; }
if (depth_ref != NULL) { W->depth_ref = depth_ref ; ok++; }
if (comp_frac != NULL) { W->comp_frac = comp_frac ; ok++; }
if (well_connpos != NULL) { W->well_connpos = well_connpos; ok++; }
if (ctrls != NULL) { W->ctrls = ctrls ; ok++; }
if (name != NULL) { W->name = name ; ok++; }
if (allow_cf != NULL) { W->allow_cf = allow_cf ; ok++; }
return ok == 7;
}
/* ---------------------------------------------------------------------- */
static int
perfs_allocate(int nperf, struct Wells *W)
/* ---------------------------------------------------------------------- */
{
int ok;
void *well_cells, *WI, *sat_table_id;
well_cells = realloc(W->well_cells, nperf * sizeof *W->well_cells);
WI = realloc(W->WI , nperf * sizeof *W->WI );
sat_table_id = realloc(W->sat_table_id , nperf * sizeof *W->sat_table_id );
ok = 0;
if (well_cells != NULL) { W->well_cells = well_cells; ok++; }
if (WI != NULL) { W->WI = WI ; ok++; }
if (sat_table_id != NULL) { W->sat_table_id = sat_table_id ; ok++; }
return ok == 3;
}
/* ---------------------------------------------------------------------- */
static int
initialise_new_wells(int nwells, struct Wells *W)
/* ---------------------------------------------------------------------- */
{
int ok, w, p;
struct WellMgmt *m;
m = W->data;
for (w = m->well_cpty; w < nwells; w++) {
W->type [w] = PRODUCER;
W->depth_ref[w] = -1.0;
W->name [w] = NULL;
W->allow_cf [w] = 1;
for (p = 0; p < W->number_of_phases; ++p) {
W->comp_frac[W->number_of_phases*w + p] = 0.0;
}
W->well_connpos[w + 1] = W->well_connpos[w];
}
for (w = m->well_cpty, ok = 1; ok && (w < nwells); w++) {
W->ctrls[w] = well_controls_create( );
ok = W->ctrls[w] != NULL;
}
if (! ok) {
for (; w < nwells; w++) {
W->ctrls[w] = NULL;
}
}
return ok;
}
/* ---------------------------------------------------------------------- */
static void
initialise_new_perfs(int nperf, struct Wells *W)
/* ---------------------------------------------------------------------- */
{
int k;
struct WellMgmt *m;
m = W->data;
for (k = m->perf_cpty; k < nperf; k++) {
W->well_cells[k] = -1 ;
W->WI [k] = 0.0;
W->sat_table_id[k] = -1;
}
}
/* ---------------------------------------------------------------------- */
static int
wells_reserve(int nwells, int nperf, struct Wells *W)
/* ---------------------------------------------------------------------- */
{
int ok;
struct WellMgmt *m;
m = W->data;
assert (nwells >= m->well_cpty);
assert (nperf >= m->perf_cpty);
ok = 1;
if (nwells > m->well_cpty) {
ok = wells_allocate(nwells, W);
if (ok) {
ok = initialise_new_wells(nwells, W);
}
if (ok) {
m->well_cpty = nwells;
}
}
if (ok && (nperf > m->perf_cpty)) {
ok = perfs_allocate(nperf, W);
if (ok) {
initialise_new_perfs(nperf, W);
m->perf_cpty = nperf;
}
}
return ok;
}
/* ---------------------------------------------------------------------- */
static char *
dup_string(const char *s)
/* ---------------------------------------------------------------------- */
{
char *t;
assert (s != NULL);
t = malloc((strlen(s) + 1) * sizeof *t);
if (t != NULL) {
strcpy(t, s);
}
return t;
}
/* ======================================================================
* Public entry points below separator.
* ====================================================================== */
/* ---------------------------------------------------------------------- */
struct Wells *
create_wells(int nphases, int nwells, int nperf)
/* ---------------------------------------------------------------------- */
{
struct Wells* W = malloc(1 * sizeof *W);
if (W != NULL) {
W->number_of_wells = 0;
W->number_of_phases = nphases;
W->type = NULL;
W->depth_ref = NULL;
W->comp_frac = NULL;
W->well_connpos = malloc(1 * sizeof *W->well_connpos);
W->well_cells = NULL;
W->WI = NULL;
W->sat_table_id = NULL;
W->ctrls = NULL;
W->name = NULL;
W->allow_cf = NULL;
W->data = create_well_mgmt();
int ok = (W->well_connpos != NULL) && (W->data != NULL);
if (ok) {
W->well_connpos[0] = 0;
if ((nwells > 0) || (nperf > 0)) {
ok = wells_reserve(nwells, nperf, W);
}
}
if (! ok) {
destroy_wells(W);
W = NULL;
}
}
return W;
}
/* ---------------------------------------------------------------------- */
void
destroy_wells(struct Wells *W)
/* ---------------------------------------------------------------------- */
{
if (W != NULL) {
struct WellMgmt* m = W->data;
for (int w = 0; w < m->well_cpty; w++) {
well_controls_destroy(W->ctrls[w]);
}
for (int w = 0; w < m->well_cpty; w++) {
free(W->name[w]);
}
destroy_well_mgmt(m);
free(W->name);
free(W->ctrls);
free(W->WI);
free(W->sat_table_id);
free(W->well_cells);
free(W->well_connpos);
free(W->comp_frac);
free(W->depth_ref);
free(W->type);
free(W->allow_cf);
}
free(W);
}
/* ---------------------------------------------------------------------- */
static int
alloc_size(int n, int a, int cpty)
/* ---------------------------------------------------------------------- */
{
if (cpty < n + a) {
cpty *= 2; /* log_2(n) allocations */
if (cpty < n + a) { /* Typically for the first few allocs */
cpty = n + a;
}
}
return cpty;
}
/* ---------------------------------------------------------------------- */
int
add_well(enum WellType type ,
double depth_ref,
int nperf ,
const double *comp_frac, /* Injection fraction or NULL */
const int *cells ,
const double *WI , /* Well index per perf (or NULL) */
const int *sat_table_id, /*Saturation table id per perf (or NULL) */
const char *name , /* Well name (or NULL) */
int allow_cf ,
struct Wells *W )
/* ---------------------------------------------------------------------- */
{
assert (W != NULL);
int nw = W->number_of_wells;
int nperf_tot = W->well_connpos[nw];
struct WellMgmt* m = W->data;
int ok = (nw < m->well_cpty) && (nperf_tot + nperf <= m->perf_cpty);
if (! ok) {
int nwalloc = alloc_size(nw , 1 , m->well_cpty);
int nperfalloc = alloc_size(nperf_tot, nperf, m->perf_cpty);
ok = wells_reserve(nwalloc, nperfalloc, W);
}
int off = W->well_connpos[nw];
if (ok && (nperf > 0)) {
assert (cells != NULL);
if (cells != NULL && W->well_cells != NULL)
memcpy(W->well_cells + off,
cells, nperf * sizeof *W->well_cells);
if (W->WI != NULL && WI != NULL) {
memcpy(W->WI + off, WI, nperf * sizeof *W->WI);
}
if (W->sat_table_id != NULL && sat_table_id != NULL) {
memcpy(W->sat_table_id + off, sat_table_id, nperf * sizeof *W->sat_table_id);
}
}
if (ok) {
W->type [nw] = type ;
W->depth_ref[nw] = depth_ref;
W->allow_cf [nw] = allow_cf;
if (name != NULL) {
/* May return NULL, but that's fine for the current
* purpose. */
W->name [nw] = dup_string(name);
}
int np = W->number_of_phases;
if (comp_frac != NULL) {
memcpy(W->comp_frac + np*nw, comp_frac, np * sizeof *W->comp_frac);
}
W->well_connpos[nw + 1] = off + nperf;
W->number_of_wells += 1;
}
return ok;
}
/* ---------------------------------------------------------------------- */
int
append_well_controls(enum WellControlType type,
double target,
double alq,
int vfp,
const double *distr,
int well_index,
struct Wells *W)
/* ---------------------------------------------------------------------- */
{
struct WellControls *ctrl;
assert (W != NULL);
assert ((0 <= well_index) && (well_index < W->number_of_wells));
ctrl = W->ctrls[well_index];
assert (ctrl != NULL);
well_controls_assert_number_of_phases( ctrl , W->number_of_phases);
return well_controls_add_new(type , target , alq , vfp , distr , ctrl);
}
/* ---------------------------------------------------------------------- */
void
set_current_control(int well_index, int current_control, struct Wells *W)
/* ---------------------------------------------------------------------- */
{
assert (W != NULL);
assert ((0 <= well_index) && (well_index < W->number_of_wells));
assert (W->ctrls[well_index] != NULL);
assert (current_control < well_controls_get_num(W->ctrls[well_index]));
well_controls_set_current(W->ctrls[well_index] , current_control);
}
/* ---------------------------------------------------------------------- */
void
clear_well_controls(int well_index, struct Wells *W)
/* ---------------------------------------------------------------------- */
{
assert (W != NULL);
assert ((0 <= well_index) && (well_index < W->number_of_wells));
if (W->ctrls[well_index] != NULL)
well_controls_clear( W->ctrls[well_index] );
}
/* ---------------------------------------------------------------------- */
struct Wells *
clone_wells(const struct Wells *W)
/* ---------------------------------------------------------------------- */
{
struct WellControls *ctrl;
struct Wells *newWells;
if (W == NULL) {
newWells = NULL;
}
else {
int np = W->number_of_phases;
newWells = create_wells(W->number_of_phases, W->number_of_wells,
W->well_connpos[ W->number_of_wells ]);
if (newWells != NULL) {
int pos = W->well_connpos[ 0 ];
int ok = 1;
for (int w = 0; ok && (w < W->number_of_wells); w++) {
int nperf = W->well_connpos[w + 1] - pos;
const int* cells = W->well_cells + pos;
const double* WI = W->WI != NULL ? W->WI + pos : NULL;
const int* sat_table_id = W->sat_table_id != NULL ? W->sat_table_id + pos : NULL;
const double* comp_frac = W->comp_frac != NULL ? W->comp_frac + w*np : NULL;
ok = add_well(W->type[ w ], W->depth_ref[ w ], nperf,
comp_frac, cells, WI, sat_table_id, W->name[ w ], W->allow_cf[ w ], newWells);
if (ok) {
ok = (ctrl = well_controls_clone(W->ctrls[w])) != NULL;
}
if (ok) {
/* Destroy control set implied by add_well() */
well_controls_destroy(newWells->ctrls[w]);
/* Assign complete clone of w's control set */
newWells->ctrls[w] = ctrl;
}
pos = W->well_connpos[w + 1];
}
if (! ok) {
destroy_wells(newWells);
newWells = NULL;
}
}
}
assert (wells_equal(newWells, W, false));
return newWells;
}
/* ---------------------------------------------------------------------- */
bool
wells_equal(const struct Wells *W1, const struct Wells *W2 , bool verbose)
/* ---------------------------------------------------------------------- */
{
// Cater the case where W1 and W2 are the same (null) pointers.
if( W1 == W2 )
{
return true;
}
if( W1 == NULL || W2 == NULL)
{
return false;
}
bool are_equal = (W1->number_of_wells == W2->number_of_wells) &&
(W1->number_of_phases == W2->number_of_phases);
if (!are_equal) {
return are_equal;
}
int i;
for (i=0; i<W1->number_of_wells; i++) {
if (are_equal) {
/*
The name attribute can be NULL. The comparison is as
follows:
1. If both names are different from NULL a normal
strcmp() is performed.
2. If both names are NULL they compare as equal.
3. If one name is NULL and the other is not NULL
they are regarded as different.
*/
if (W1->name[i] && W2->name[i])
are_equal = are_equal && (strcmp(W1->name[i], W2->name[i]) == 0);
else
are_equal = are_equal && (W1->name[i] == W2->name[i]);
if (verbose && !are_equal)
printf("Well name[%d] %s and %s are different \n", i , W1->name[i] , W2->name[i]);
}
if (W1->type[i] != W2->type[i]) {
are_equal = false;
if (verbose)
printf("Well->type[%d] different %d %d \n",i , W1->type[i] , W2->type[i] );
}
if (W1->depth_ref[i] != W2->depth_ref[i]) {
are_equal = false;
if (verbose)
printf("Well->depth_ref[%d] different %g %g \n",i , W1->depth_ref[i] , W2->depth_ref[i] );
}
if (!well_controls_equal(W1->ctrls[i], W2->ctrls[i],verbose)) {
are_equal = false;
if (verbose)
printf("Well controls are different for well[%d]:%s \n",i,W1->name[i]);
}
if (W1->allow_cf[i] != W2->allow_cf[i]) {
are_equal = false;
if (verbose)
printf("Well->allow_cf[%d] different %d %d \n",i , W1->type[i] , W2->type[i] );
}
}
{
struct WellMgmt* mgmt1 = W1->data;
struct WellMgmt* mgmt2 = W2->data;
are_equal = are_equal && (mgmt1->perf_cpty == mgmt2->perf_cpty);
are_equal = are_equal && (mgmt1->well_cpty == mgmt2->well_cpty);
}
if (memcmp(W1->comp_frac, W2->comp_frac, W1->number_of_wells * W1->number_of_phases * sizeof *W1->comp_frac ) != 0) {
are_equal = false;
if (verbose)
printf("Component fractions different \n");
}
if (memcmp(W1->well_connpos, W2->well_connpos, (1 + W1->number_of_wells) * sizeof *W1->well_connpos ) != 0) {
are_equal = false;
if (verbose)
printf("perforation position map difference \n");
}
{
int number_of_perforations = W1->well_connpos[W1->number_of_wells];
are_equal = are_equal && (memcmp(W1->well_cells, W2->well_cells, number_of_perforations * sizeof *W1->well_cells ) == 0);
are_equal = are_equal && (memcmp(W1->WI, W2->WI, number_of_perforations * sizeof *W1->WI ) == 0);
are_equal = are_equal && (memcmp(W1->sat_table_id, W2->sat_table_id, number_of_perforations * sizeof *W1->sat_table_id ) == 0);
}
return are_equal;
}
/* ---------------------------------------------------------------------- */

View File

@ -1,115 +0,0 @@
/*
Copyright 2012 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/>.
*/
#include <chrono>
#include <config.h>
#define NVERBOSE // Suppress own messages when throw()ing
#define BOOST_TEST_MODULE WellCollectionTest
#include <boost/test/unit_test.hpp>
#include <opm/core/wells/WellCollection.hpp>
#include <opm/parser/eclipse/Parser/Parser.hpp>
#include <opm/parser/eclipse/Deck/Deck.hpp>
#include <opm/parser/eclipse/EclipseState/EclipseState.hpp>
#include <opm/parser/eclipse/EclipseState/Schedule/Well/Well.hpp>
#include <opm/parser/eclipse/EclipseState/Schedule/Schedule.hpp>
#include <opm/parser/eclipse/EclipseState/Schedule/Group/Group.hpp>
using namespace Opm;
BOOST_AUTO_TEST_CASE(AddWellsAndGroupToCollection) {
Parser parser;
std::string scheduleFile("wells_group.data");
Deck deck = parser.parseFile(scheduleFile);
EclipseState eclipseState(deck);
PhaseUsage pu = phaseUsageFromDeck(eclipseState);
const auto& grid = eclipseState.getInputGrid();
const TableManager table ( deck );
const Eclipse3DProperties eclipseProperties ( deck , table, grid);
const Runspec runspec(deck);
const Schedule sched(deck, grid, eclipseProperties, runspec);
SummaryState summaryState(std::chrono::system_clock::from_time_t(sched.getStartTime()));
WellCollection collection;
// Add groups to WellCollection
const auto& fieldGroup = sched.getGroup("FIELD", 2);
collection.addField(fieldGroup, summaryState, pu);
collection.addGroup( sched.getGroup( "G1", 2 ), fieldGroup.name(), summaryState, pu);
collection.addGroup( sched.getGroup( "G2", 2 ), fieldGroup.name(), summaryState, pu);
BOOST_CHECK_EQUAL("FIELD", collection.findNode("FIELD")->name());
BOOST_CHECK_EQUAL("FIELD", collection.findNode("G1")->getParent()->name());
BOOST_CHECK_EQUAL("FIELD", collection.findNode("G2")->getParent()->name());
// Add wells to WellCollection
WellCollection wellCollection;
const auto wells = sched.getWellsatEnd();
for (size_t i=0; i<wells.size(); i++) {
collection.addWell(wells[i], summaryState, pu);
}
BOOST_CHECK_EQUAL("G1", collection.findNode("INJ1")->getParent()->name());
BOOST_CHECK_EQUAL("G1", collection.findNode("INJ2")->getParent()->name());
BOOST_CHECK_EQUAL("G2", collection.findNode("PROD1")->getParent()->name());
BOOST_CHECK_EQUAL("G2", collection.findNode("PROD2")->getParent()->name());
}
BOOST_AUTO_TEST_CASE(EfficiencyFactor) {
Parser parser;
std::string scheduleFile("wells_group.data");
Deck deck = parser.parseFile(scheduleFile);
EclipseState eclipseState(deck);
PhaseUsage pu = phaseUsageFromDeck(eclipseState);
const auto& grid = eclipseState.getInputGrid();
const TableManager table ( deck );
const Eclipse3DProperties eclipseProperties ( deck , table, grid);
const Runspec runspec(deck);
const Schedule sched(deck, grid, eclipseProperties, runspec);
Opm::SummaryState summaryState(std::chrono::system_clock::from_time_t(sched.getStartTime()));
size_t timestep = 2;
WellCollection collection;
// Add groups to WellCollection
const auto& fieldGroup = sched.getGroup("FIELD", timestep);
collection.addField( fieldGroup, summaryState, pu);
collection.addGroup( sched.getGroup( "G1", timestep ), fieldGroup.name(), summaryState, pu);
collection.addGroup( sched.getGroup( "G2", timestep ), fieldGroup.name(), summaryState, pu);
BOOST_CHECK_EQUAL(1.0, collection.findNode("FIELD")->efficiencyFactor());
BOOST_CHECK_EQUAL(1.0, collection.findNode("G1")->getParent()->efficiencyFactor());
BOOST_CHECK_EQUAL(1.0, collection.findNode("G2")->getParent()->efficiencyFactor());
// Add wells to WellCollection
const auto wells1 = sched.getWells(timestep);
for (size_t i=0; i<wells1.size(); i++) {
collection.addWell(wells1[i], summaryState, pu);
}
// 0.5(inj1) * 0.8(G1)
BOOST_CHECK_CLOSE(0.4, collection.findWellNode("INJ1").getAccumulativeEfficiencyFactor(), 1e-10);
// 0.8(inj2) * 0.8(G1)
BOOST_CHECK_CLOSE(0.64, collection.findWellNode("INJ2").getAccumulativeEfficiencyFactor(), 1e-10);
// 0.5 (prod1) * 1.0 (G2)
BOOST_CHECK_CLOSE(0.5, collection.findWellNode("PROD1").getAccumulativeEfficiencyFactor(), 1e-10);
// 1.0 (prod2) * 1.0 (G2)
BOOST_CHECK_CLOSE(1.0, collection.findWellNode("PROD2").getAccumulativeEfficiencyFactor(), 1e-10);
}

View File

@ -1,157 +0,0 @@
/*
Copyright 2014 Statoil.
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/>.
*/
#include <config.h>
#define NVERBOSE // Suppress own messages when throw()ing
#define BOOST_TEST_MODULE WellsModuleTest
#include <boost/test/unit_test.hpp>
#include <opm/core/wells.h>
#include <opm/core/well_controls.h>
#include <iostream>
#include <vector>
#include <memory>
BOOST_AUTO_TEST_CASE(Construction)
{
struct WellControls * ctrls = well_controls_create();
well_controls_set_current( ctrls , 1 );
BOOST_CHECK_EQUAL( 1 , well_controls_get_current( ctrls ));
well_controls_set_current( ctrls , 2 );
BOOST_CHECK_EQUAL( 2 , well_controls_get_current( ctrls ));
{
enum WellControlType type1 = BHP;
enum WellControlType type2 = SURFACE_RATE;
int num_phases = 3;
double dist1[3] = {0 , 1 , 2};
double dist2[3] = {10, 11 , 12};
double target = 77;
double alq = 88;
int vfp = 42;
well_controls_assert_number_of_phases( ctrls , num_phases );
well_controls_add_new( type1 , target , alq , vfp , dist1 , ctrls );
well_controls_add_new( type2 , 2*target , 2*alq , 2*vfp , dist2 , ctrls );
BOOST_CHECK_EQUAL( target , well_controls_iget_target(ctrls , 0 ));
BOOST_CHECK_EQUAL( alq , well_controls_iget_alq(ctrls , 0 ));
BOOST_CHECK_EQUAL( vfp , well_controls_iget_vfp(ctrls , 0 ));
BOOST_CHECK_EQUAL( type1 , well_controls_iget_type(ctrls , 0 ));
BOOST_CHECK_EQUAL( 2*target , well_controls_iget_target(ctrls , 1 ));
BOOST_CHECK_EQUAL( 2*alq , well_controls_iget_alq(ctrls , 1 ));
BOOST_CHECK_EQUAL( 2*vfp , well_controls_iget_vfp(ctrls , 1 ));
BOOST_CHECK_EQUAL( type2 , well_controls_iget_type(ctrls , 1 ));
well_controls_set_current( ctrls , 1 );
BOOST_CHECK_EQUAL( type2 , well_controls_get_current_type( ctrls ));
BOOST_CHECK_EQUAL( well_controls_iget_target( ctrls , 1 ) , well_controls_get_current_target( ctrls ));
{
const double * d1 = well_controls_iget_distr( ctrls , 0 );
const double * d2 = well_controls_iget_distr( ctrls , 1 );
BOOST_CHECK( memcmp(d1 , dist1 , num_phases * sizeof * d1 ) == 0);
BOOST_CHECK( memcmp(d2 , dist2 , num_phases * sizeof * d2 ) == 0);
}
}
well_controls_iset_target( ctrls , 0 , 123);
BOOST_CHECK_EQUAL( 123 , well_controls_iget_target( ctrls , 0 ));
well_controls_iset_target( ctrls , 1 , 456);
BOOST_CHECK_EQUAL( 456 , well_controls_iget_target( ctrls , 1 ));
well_controls_iset_alq( ctrls , 0 , 789);
BOOST_CHECK_EQUAL( 789 , well_controls_iget_alq( ctrls , 0 ));
well_controls_iset_alq( ctrls , 1 , 234);
BOOST_CHECK_EQUAL( 234 , well_controls_iget_alq( ctrls , 1 ));
well_controls_iset_vfp( ctrls , 0 , 567);
BOOST_CHECK_EQUAL( 567 , well_controls_iget_vfp( ctrls , 0 ));
well_controls_iset_vfp( ctrls , 1 , 890);
BOOST_CHECK_EQUAL( 890 , well_controls_iget_vfp( ctrls , 1 ));
well_controls_iset_type( ctrls , 0 , SURFACE_RATE);
BOOST_CHECK_EQUAL( SURFACE_RATE , well_controls_iget_type( ctrls , 0 ));
well_controls_iset_type( ctrls , 1 , BHP);
BOOST_CHECK_EQUAL( BHP, well_controls_iget_type( ctrls , 1 ));
{
double newDist[3] = {77,78,79};
const double * tmp;
well_controls_iset_distr( ctrls , 0 , newDist );
tmp = well_controls_iget_distr( ctrls , 0);
BOOST_CHECK( memcmp(tmp , newDist , 3 * sizeof * tmp ) == 0);
}
well_controls_destroy( ctrls );
}
BOOST_AUTO_TEST_CASE(OpenClose)
{
struct WellControls * ctrls = well_controls_create();
BOOST_CHECK_EQUAL( true , well_controls_well_is_open(ctrls) );
BOOST_CHECK_EQUAL( false , well_controls_well_is_stopped(ctrls) );
well_controls_open_well( ctrls );
BOOST_CHECK_EQUAL( true , well_controls_well_is_open(ctrls) );
BOOST_CHECK_EQUAL( false , well_controls_well_is_stopped(ctrls) );
well_controls_stop_well( ctrls );
BOOST_CHECK_EQUAL( false , well_controls_well_is_open(ctrls) );
BOOST_CHECK_EQUAL( true , well_controls_well_is_stopped(ctrls) );
well_controls_destroy( ctrls );
}
BOOST_AUTO_TEST_CASE(Clone)
{
std::shared_ptr<WellControls>
ctrls(well_controls_create(),
& well_controls_destroy);
const WellControlType type1 = BHP;
const WellControlType type2 = SURFACE_RATE;
const int num_phases = 3;
const double dist1[] = { 0, 1, 2};
const double dist2[] = {10, 11, 12};
const double target = 77;
const double alq = 88;
const int vfp = 42;
well_controls_assert_number_of_phases(ctrls.get(), num_phases);
well_controls_add_new(type1, target, alq, vfp, dist1, ctrls.get());
well_controls_add_new(type2, 2*target, 2*alq, 2*vfp, dist2, ctrls.get());
std::shared_ptr<WellControls>
c(well_controls_clone(ctrls.get()),
& well_controls_destroy);
BOOST_CHECK(well_controls_equal(ctrls.get(), c.get(), false));
}

View File

@ -1,249 +0,0 @@
/*
Copyright 2012 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/>.
*/
#include <config.h>
#define NVERBOSE // Suppress own messages when throw()ing
#define BOOST_TEST_MODULE WellsModuleTest
#include <boost/test/unit_test.hpp>
#include <opm/core/wells.h>
#include <opm/core/well_controls.h>
#include <iostream>
#include <vector>
#include <memory>
namespace
{
static double invalid_alq = -1e100;
static double invalid_vfp = -2147483647;
} //Namespace
BOOST_AUTO_TEST_CASE(Construction)
{
const int nphases = 2;
const int nwells = 2;
const int nperfs = 2;
std::shared_ptr<Wells> W(create_wells(nphases, nwells, nperfs),
destroy_wells);
if (W) {
int cells[] = { 0, 9 };
double WI = 1.0;
int sat_table_id = -1;
const double ifrac[] = { 1.0, 0.0 };
const bool ok0 = add_well(INJECTOR, 0.0, 1, &ifrac[0], &cells[0],
&WI, &sat_table_id,"INJECTOR", true, W.get());
const double pfrac[] = { 0.0, 0.0 };
const bool ok1 = add_well(PRODUCER, 0.0, 1, &pfrac[0], &cells[1],
&WI, &sat_table_id,"PRODUCER", true, W.get());
if (ok0 && ok1) {
BOOST_CHECK_EQUAL(W->number_of_phases, nphases);
BOOST_CHECK_EQUAL(W->number_of_wells , nwells );
BOOST_CHECK_EQUAL(W->well_connpos[0], 0);
BOOST_CHECK_EQUAL(W->well_connpos[1], 1);
BOOST_CHECK_EQUAL(W->well_connpos[W->number_of_wells], nperfs);
BOOST_CHECK_EQUAL(W->well_cells[W->well_connpos[0]], cells[0]);
BOOST_CHECK_EQUAL(W->well_cells[W->well_connpos[1]], cells[1]);
BOOST_CHECK_EQUAL(W->WI[W->well_connpos[0]], WI);
BOOST_CHECK_EQUAL(W->WI[W->well_connpos[1]], WI);
using std::string;
BOOST_CHECK_EQUAL(string(W->name[0]), string("INJECTOR"));
BOOST_CHECK_EQUAL(string(W->name[1]), string("PRODUCER"));
}
}
}
BOOST_AUTO_TEST_CASE(Controls)
{
const int nphases = 2;
const int nwells = 1;
const int nperfs = 2;
std::shared_ptr<Wells> W(create_wells(nphases, nwells, nperfs),
destroy_wells);
if (W) {
int cells[] = { 0 , 9 };
double WI [] = { 1.0, 1.0 };
const double ifrac[] = { 1.0, 0.0 };
int sat_table_id = -1;
const bool ok = add_well(INJECTOR, 0.0, nperfs, &ifrac[0], &cells[0],
&WI[0], &sat_table_id, "INJECTOR", true, W.get());
if (ok) {
const double distr[] = { 1.0, 0.0 };
const bool ok1 = append_well_controls(BHP, 1,
invalid_alq, invalid_vfp,
&distr[0],
0, W.get());
const bool ok2 = append_well_controls(SURFACE_RATE, 1,
invalid_alq, invalid_vfp,
&distr[0],
0, W.get());
if (ok1 && ok2) {
WellControls* ctrls = W->ctrls[0];
BOOST_CHECK_EQUAL(well_controls_get_num(ctrls) , 2);
BOOST_CHECK_EQUAL(well_controls_get_current(ctrls), -1);
set_current_control(0, 0, W.get());
BOOST_CHECK_EQUAL(well_controls_get_current(ctrls), 0);
set_current_control(0, 1, W.get());
BOOST_CHECK_EQUAL(well_controls_get_current(ctrls), 1);
BOOST_CHECK_EQUAL(well_controls_iget_type(ctrls , 0) , BHP);
BOOST_CHECK_EQUAL(well_controls_iget_type(ctrls , 1) , SURFACE_RATE);
BOOST_CHECK_EQUAL(well_controls_iget_target(ctrls , 0), 1.0);
BOOST_CHECK_EQUAL(well_controls_iget_target(ctrls , 1), 1.0);
}
}
}
}
BOOST_AUTO_TEST_CASE(Copy)
{
const int nphases = 2;
const int nwells = 2;
const int nperfs = 2;
std::shared_ptr<Wells> W1(create_wells(nphases, nwells, nperfs),
destroy_wells);
std::shared_ptr<Wells> W2;
if (W1) {
int cells[] = { 0, 9 };
const double WI = 1.0;
const double ifrac[] = { 1.0, 0.0 };
int sat_table_id = -1;
const bool ok0 = add_well(INJECTOR, 0.0, 1, &ifrac[0], &cells[0],
&WI, &sat_table_id, "INJECTOR", true, W1.get());
const double pfrac[] = { 0.0, 0.0 };
const bool ok1 = add_well(PRODUCER, 0.0, 1, &pfrac[0], &cells[1],
&WI, &sat_table_id, "PRODUCER", true, W1.get());
bool ok = ok0 && ok1;
for (int w = 0; ok && (w < W1->number_of_wells); ++w) {
const double distr[] = { 1.0, 0.0 };
const bool okc1 = append_well_controls(BHP, 1,
invalid_alq, invalid_vfp,
&distr[0], w,
W1.get());
const bool okc2 = append_well_controls(SURFACE_RATE, 1,
invalid_alq, invalid_vfp,
&distr[0], w,
W1.get());
ok = okc1 && okc2;
}
if (ok) {
W2.reset(clone_wells(W1.get()), destroy_wells);
}
}
if (W2) {
BOOST_CHECK_EQUAL(W2->number_of_phases, W1->number_of_phases);
BOOST_CHECK_EQUAL(W2->number_of_wells , W1->number_of_wells );
BOOST_CHECK_EQUAL(W2->well_connpos[0] , W1->well_connpos[0] );
for (int w = 0; w < W1->number_of_wells; ++w) {
using std::string;
BOOST_CHECK_EQUAL(string(W2->name[w]), string(W1->name[w]));
BOOST_CHECK_EQUAL( W2->type[w] , W1->type[w] );
BOOST_CHECK_EQUAL(W2->well_connpos[w + 1],
W1->well_connpos[w + 1]);
for (int j = W1->well_connpos[w];
j < W1->well_connpos[w + 1]; ++j) {
BOOST_CHECK_EQUAL(W2->well_cells[j], W1->well_cells[j]);
BOOST_CHECK_EQUAL(W2->WI [j], W1->WI [j]);
}
BOOST_CHECK(W1->ctrls[w] != 0);
BOOST_CHECK(W2->ctrls[w] != 0);
WellControls* c1 = W1->ctrls[w];
WellControls* c2 = W2->ctrls[w];
BOOST_CHECK_EQUAL(well_controls_get_num(c2) , well_controls_get_num(c1));
BOOST_CHECK_EQUAL(well_controls_get_current(c2) , well_controls_get_current(c1));
for (int c = 0; c < well_controls_get_num(c1); ++c) {
BOOST_CHECK_EQUAL(well_controls_iget_type(c2, c) , well_controls_iget_type(c1 , c));
BOOST_CHECK_EQUAL(well_controls_iget_target(c2, c) , well_controls_iget_target(c1 , c));
{
const double * dist1 = well_controls_iget_distr(c1 , c );
const double * dist2 = well_controls_iget_distr(c2 , c );
for (int p = 0; p < W1->number_of_phases; ++p)
BOOST_CHECK_EQUAL( dist1[p] , dist2[p]);
}
}
BOOST_CHECK( well_controls_equal( c1 , c2 , false) );
}
}
}
BOOST_AUTO_TEST_CASE(Equals_WellsEqual_ReturnsTrue) {
const int nphases = 2;
const int nwells = 2;
const int nperfs = 2;
std::shared_ptr<Wells> W1(create_wells(nphases, nwells, nperfs),
destroy_wells);
std::shared_ptr<Wells> W2(create_wells(nphases, nwells, nperfs),
destroy_wells);
BOOST_CHECK(wells_equal(W1.get(), W2.get() , false));
}
BOOST_AUTO_TEST_CASE(Equals_WellsDiffer_ReturnsFalse) {
const int nphases = 2;
const int nperfs = 2;
std::shared_ptr<Wells> W1(create_wells(nphases, 2, nperfs),
destroy_wells);
std::shared_ptr<Wells> W2(create_wells(nphases, 3, nperfs),
destroy_wells);
BOOST_CHECK(!wells_equal(W1.get(), W2.get() , false ));
}

View File

@ -1,143 +0,0 @@
/*
Copyright 2014 Statoil.
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/>.
*/
#include <config.h>
#define NVERBOSE // Suppress own messages when throw()ing
#define BOOST_TEST_MODULE WellsGroupTest
#include <chrono>
#include <memory>
#include <vector>
#include <boost/test/unit_test.hpp>
#include <boost/date_time/posix_time/posix_time.hpp>
#include <opm/core/props/phaseUsageFromDeck.hpp>
#include <opm/core/wells/WellsGroup.hpp>
#include <opm/parser/eclipse/Parser/Parser.hpp>
#include <opm/parser/eclipse/EclipseState/Schedule/Group/Group.hpp>
#include <opm/parser/eclipse/EclipseState/Schedule/Schedule.hpp>
#include <opm/parser/eclipse/EclipseState/Schedule/Well/Well.hpp>
#include <opm/parser/eclipse/EclipseState/EclipseState.hpp>
using namespace Opm;
BOOST_AUTO_TEST_CASE(ConstructGroupFromWell) {
std::string scheduleFile("wells_group.data");
Parser parser;
Deck deck = parser.parseFile(scheduleFile);
EclipseState eclipseState(deck);
const auto& grid = eclipseState.getInputGrid();
const TableManager table ( deck );
const Eclipse3DProperties eclipseProperties ( deck , table, grid);
const Opm::Runspec runspec (deck);
const Schedule sched(deck, grid, eclipseProperties, runspec);
SummaryState summaryState(std::chrono::system_clock::from_time_t(sched.getStartTime()));
PhaseUsage pu = phaseUsageFromDeck(eclipseState);
auto wells = sched.getWellsatEnd();
for (size_t i=0; i<wells.size(); i++) {
const auto& well = wells[i];
std::shared_ptr<WellsGroupInterface> wellsGroup = createWellWellsGroup(well, summaryState, pu);
BOOST_CHECK_EQUAL(well.name(), wellsGroup->name());
if (well.isInjector()) {
const auto controls = well.injectionControls(summaryState);
BOOST_CHECK_EQUAL(controls.surface_rate, wellsGroup->injSpec().surface_flow_max_rate_);
BOOST_CHECK_EQUAL(controls.bhp_limit, wellsGroup->injSpec().BHP_limit_);
BOOST_CHECK_EQUAL(controls.reservoir_rate, wellsGroup->injSpec().reservoir_flow_max_rate_);
BOOST_CHECK_EQUAL(0.0, wellsGroup->prodSpec().guide_rate_);
}
if (well.isProducer()) {
const auto controls = well.productionControls(summaryState);
BOOST_CHECK_EQUAL(controls.resv_rate, wellsGroup->prodSpec().reservoir_flow_max_rate_);
BOOST_CHECK_EQUAL(controls.bhp_limit, wellsGroup->prodSpec().BHP_limit_);
BOOST_CHECK_EQUAL(controls.oil_rate, wellsGroup->prodSpec().oil_max_rate_);
BOOST_CHECK_EQUAL(controls.water_rate, wellsGroup->prodSpec().water_max_rate_);
BOOST_CHECK_EQUAL(0.0, wellsGroup->injSpec().guide_rate_);
}
}
}
BOOST_AUTO_TEST_CASE(ConstructGroupFromGroup) {
Parser parser;
std::string scheduleFile("wells_group.data");
Deck deck = parser.parseFile(scheduleFile);
EclipseState eclipseState(deck);
PhaseUsage pu = phaseUsageFromDeck(eclipseState);
const auto& grid = eclipseState.getInputGrid();
const TableManager table ( deck );
const Eclipse3DProperties eclipseProperties ( deck , table, grid);
const Opm::Runspec runspec (deck);
const Schedule sched(deck, grid, eclipseProperties, runspec);
Opm::SummaryState summaryState(std::chrono::system_clock::from_time_t(sched.getStartTime()));
for( const auto& grp_name : sched.groupNames() ) {
const auto& group = sched.getGroup(grp_name, 2);
std::shared_ptr<WellsGroupInterface> wellsGroup = createGroupWellsGroup(group, summaryState, pu);
BOOST_CHECK_EQUAL(group.name(), wellsGroup->name());
if (group.isInjectionGroup()) {
const auto& injection = group.injectionControls(summaryState);
BOOST_CHECK_EQUAL(injection.surface_max_rate, wellsGroup->injSpec().surface_flow_max_rate_);
BOOST_CHECK_EQUAL(injection.resv_max_rate, wellsGroup->injSpec().reservoir_flow_max_rate_);
BOOST_CHECK_EQUAL(injection.target_reinj_fraction, wellsGroup->injSpec().reinjection_fraction_target_);
BOOST_CHECK_EQUAL(injection.target_void_fraction, wellsGroup->injSpec().voidage_replacment_fraction_);
}
if (group.isProductionGroup()) {
const auto& production = group.productionControls(summaryState);
BOOST_CHECK_EQUAL(production.resv_target, wellsGroup->prodSpec().reservoir_flow_max_rate_);
BOOST_CHECK_EQUAL(production.gas_target, wellsGroup->prodSpec().gas_max_rate_);
BOOST_CHECK_EQUAL(production.oil_target, wellsGroup->prodSpec().oil_max_rate_);
BOOST_CHECK_EQUAL(production.water_target, wellsGroup->prodSpec().water_max_rate_);
BOOST_CHECK_EQUAL(production.liquid_target, wellsGroup->prodSpec().liquid_max_rate_);
}
}
}
BOOST_AUTO_TEST_CASE(EfficiencyFactor) {
Parser parser;
std::string scheduleFile("wells_group.data");
Deck deck = parser.parseFile(scheduleFile);
EclipseState eclipseState(deck);
PhaseUsage pu = phaseUsageFromDeck(eclipseState);
const auto& grid = eclipseState.getInputGrid();
const TableManager table ( deck );
const Eclipse3DProperties eclipseProperties ( deck , table, grid);
const Opm::Runspec runspec (deck);
const Schedule sched(deck, grid, eclipseProperties, runspec);
Opm::SummaryState summaryState(std::chrono::system_clock::from_time_t(sched.getStartTime()));
for( const auto& grp_name : sched.groupNames() ) {
const auto& group = sched.getGroup(grp_name, 2);
std::shared_ptr<WellsGroupInterface> wellsGroup = createGroupWellsGroup(group, summaryState, pu);
BOOST_CHECK_EQUAL(group.name(), wellsGroup->name());
BOOST_CHECK_EQUAL(group.getGroupEfficiencyFactor(), wellsGroup->efficiencyFactor());
BOOST_CHECK_EQUAL(group.getGroupEfficiencyFactor(), wellsGroup->efficiencyFactor());
}
}

View File

@ -1,331 +0,0 @@
/*
Copyright 2013 Statoil ASA.
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/>.
*/
#include <config.h>
#define NVERBOSE // Suppress own messages when throw()ing
#define BOOST_TEST_MODULE WellsManagerTests
#include <boost/test/unit_test.hpp>
#include <opm/parser/eclipse/Parser/Parser.hpp>
#include <opm/parser/eclipse/EclipseState/Schedule/Schedule.hpp>
#include <opm/parser/eclipse/EclipseState/Tables/TableManager.hpp>
#include <opm/core/wells/WellsManager.hpp>
#include <opm/core/wells.h>
#include <opm/core/well_controls.h>
#include <opm/grid/GridManager.hpp>
void wells_static_check(const Wells* wells) {
BOOST_CHECK_EQUAL(2, wells->number_of_wells);
BOOST_CHECK_EQUAL(3, wells->number_of_phases);
BOOST_CHECK_EQUAL("INJ1", wells->name[0]);
BOOST_CHECK_EQUAL("PROD1", wells->name[1]);
/* The mapping from well number into the wells->WI and wells->well_cells arrays. */
BOOST_CHECK_EQUAL(0, wells->well_connpos[0]);
BOOST_CHECK_EQUAL(1, wells->well_connpos[1]);
BOOST_CHECK_EQUAL(2, wells->well_connpos[2]);
/* Connection factor */
BOOST_CHECK_CLOSE(1.2279166666666664e-12, wells->WI[0], 0.001);
BOOST_CHECK_CLOSE(1.2279166666666664e-12, wells->WI[1], 0.001);
/* Completed cells */
BOOST_CHECK_EQUAL(0, wells->well_cells[0]);
BOOST_CHECK_EQUAL(9 + 2 * 10 + 2 * 10 * 10, wells->well_cells[1]);
}
/*
The number of controls is determined by looking at which elements
have been given explicit - non-default - values in the WCONxxxx
keyword. Is that at all interesting?
*/
void check_controls_epoch0(struct WellControls ** ctrls) {
// The injector
{
const struct WellControls * ctrls0 = ctrls[0];
BOOST_CHECK_EQUAL(3, well_controls_get_num(ctrls0)); // The number of controls for the injector == 3??
BOOST_CHECK_EQUAL(SURFACE_RATE, well_controls_iget_type(ctrls0, 0));
BOOST_CHECK_EQUAL(RESERVOIR_RATE, well_controls_iget_type(ctrls0, 1));
BOOST_CHECK_EQUAL(BHP, well_controls_iget_type(ctrls0, 2));
// The different targets
BOOST_CHECK_EQUAL(100.0 / 86400, well_controls_iget_target(ctrls0, 0));
BOOST_CHECK_EQUAL(200.0 / 86400, well_controls_iget_target(ctrls0, 1));
BOOST_CHECK_EQUAL(400 * 100000, well_controls_iget_target(ctrls0, 2));
// Which control is active
BOOST_CHECK_EQUAL(0, well_controls_get_current(ctrls0));
// The phase distribution in the active target
{
const double * distr = well_controls_iget_distr(ctrls0, 0);
BOOST_CHECK_EQUAL(0, distr[0]); // Water
BOOST_CHECK_EQUAL(0, distr[1]); // Oil
BOOST_CHECK_EQUAL(1, distr[2]); // Gas
}
}
// The producer
{
const struct WellControls * ctrls1 = ctrls[1];
BOOST_CHECK_EQUAL(2, well_controls_get_num(ctrls1)); // The number of controls for the producer == 2??
BOOST_CHECK_EQUAL(SURFACE_RATE, well_controls_iget_type(ctrls1, 0));
BOOST_CHECK_EQUAL(BHP, well_controls_iget_type(ctrls1, 1));
// The different targets
BOOST_CHECK_EQUAL(-20000.0 / 86400, well_controls_iget_target(ctrls1, 0));
BOOST_CHECK_EQUAL(1000 * 100000, well_controls_iget_target(ctrls1, 1));
// Which control is active
BOOST_CHECK_EQUAL(0, well_controls_get_current(ctrls1));
// The phase distribution in the active target
{
const double * distr = well_controls_iget_distr(ctrls1, 0);
BOOST_CHECK_EQUAL(0, distr[0]); // Water
BOOST_CHECK_EQUAL(1, distr[1]); // Oil
BOOST_CHECK_EQUAL(0, distr[2]); // Gas
}
}
}
void check_controls_epoch1(struct WellControls ** ctrls) {
// The injector
{
const struct WellControls * ctrls0 = ctrls[0];
BOOST_CHECK_EQUAL(3, well_controls_get_num(ctrls0)); // The number of controls for the injector == 3??
BOOST_CHECK_EQUAL(SURFACE_RATE, well_controls_iget_type(ctrls0, 0));
BOOST_CHECK_EQUAL(RESERVOIR_RATE, well_controls_iget_type(ctrls0, 1));
BOOST_CHECK_EQUAL(BHP, well_controls_iget_type(ctrls0, 2));
// The different targets
BOOST_CHECK_CLOSE(10.0 / 86400, well_controls_iget_target(ctrls0, 0), 0.001);
BOOST_CHECK_CLOSE(20.0 / 86400, well_controls_iget_target(ctrls0, 1), 0.001);
BOOST_CHECK_CLOSE(40 * 100000, well_controls_iget_target(ctrls0, 2), 0.001);
// Which control is active
BOOST_CHECK_EQUAL(1, well_controls_get_current(ctrls0));
{
const double * distr = well_controls_iget_distr(ctrls0, 1);
BOOST_CHECK_EQUAL(1, distr[0]); // Water
BOOST_CHECK_EQUAL(0, distr[1]); // Oil
BOOST_CHECK_EQUAL(0, distr[2]); // Gas
}
}
// The producer
{
const struct WellControls * ctrls1 = ctrls[1];
BOOST_CHECK_EQUAL(3, well_controls_get_num(ctrls1)); // The number of controls for the producer - now 3.
BOOST_CHECK_EQUAL(SURFACE_RATE, well_controls_iget_type(ctrls1, 0));
BOOST_CHECK_EQUAL(RESERVOIR_RATE, well_controls_iget_type(ctrls1, 1));
BOOST_CHECK_EQUAL(BHP, well_controls_iget_type(ctrls1, 2));
// The different targets
BOOST_CHECK_CLOSE(-999.0 / 86400, well_controls_iget_target(ctrls1, 0), 0.001);
BOOST_CHECK_CLOSE(-123.0 / 86400, well_controls_iget_target(ctrls1, 1), 0.001);
BOOST_CHECK_CLOSE(100 * 100000, well_controls_iget_target(ctrls1, 2), 0.001);
// Which control is active
BOOST_CHECK_EQUAL(1, well_controls_get_current(ctrls1));
{
const double * distr = well_controls_iget_distr(ctrls1, 1);
BOOST_CHECK_EQUAL(1, distr[0]); // Water
BOOST_CHECK_EQUAL(1, distr[1]); // Oil
BOOST_CHECK_EQUAL(1, distr[2]); // Gas
}
}
}
void check_controls_epoch3(struct WellControls ** ctrls) {
// The new producer
const struct WellControls * ctrls1 = ctrls[1];
// Note: controls include default (1 atm) BHP control.
// and also an ORAT control
BOOST_CHECK_EQUAL(2, well_controls_get_num(ctrls1));
}
BOOST_AUTO_TEST_CASE(New_Constructor_Works) {
const std::string filename = "wells_manager_data.data";
Opm::Parser parser;
Opm::Deck deck = parser.parseFile(filename);
Opm::EclipseState eclipseState(deck);
Opm::GridManager vanguard(eclipseState.getInputGrid());
const auto& grid = eclipseState.getInputGrid();
const Opm::TableManager table ( deck );
const Opm::Eclipse3DProperties eclipseProperties ( deck , table, grid);
const Opm::Runspec runspec (deck);
const Opm::Schedule sched(deck, grid, eclipseProperties, runspec);
Opm::SummaryState summaryState(std::chrono::system_clock::from_time_t(sched.getStartTime()));
{
Opm::WellsManager wellsManager(eclipseState, sched, summaryState, 0, *vanguard.c_grid());
wells_static_check(wellsManager.c_wells());
check_controls_epoch0(wellsManager.c_wells()->ctrls);
}
{
Opm::WellsManager wellsManager(eclipseState, sched, summaryState, 1, *vanguard.c_grid());
wells_static_check(wellsManager.c_wells());
check_controls_epoch1(wellsManager.c_wells()->ctrls);
}
{
Opm::WellsManager wellsManager(eclipseState, sched, summaryState, 3, *vanguard.c_grid());
const Wells* wells = wellsManager.c_wells();
// There is 3 wells in total in the deck at the 3rd schedule step.
// PROD1 is shut and should therefore not be counted.
// The new well is therefore the secound well.
BOOST_CHECK_EQUAL(2, wells->number_of_wells);
BOOST_CHECK_EQUAL(wells->name[0], "INJ1");
BOOST_CHECK_EQUAL(wells->name[1], "NEW");
check_controls_epoch3(wellsManager.c_wells()->ctrls);
}
}
BOOST_AUTO_TEST_CASE(WellsEqual) {
const std::string filename = "wells_manager_data.data";
Opm::Parser parser;
Opm::Deck deck(parser.parseFile(filename));
Opm::EclipseState eclipseState(deck);
Opm::GridManager vanguard(eclipseState.getInputGrid());
const auto& grid = eclipseState.getInputGrid();
const Opm::TableManager table ( deck );
const Opm::Eclipse3DProperties eclipseProperties ( deck , table, grid);
const Opm::Runspec runspec (deck);
const Opm::Schedule sched(deck, grid, eclipseProperties, runspec);
Opm::SummaryState summaryState(std::chrono::system_clock::from_time_t(sched.getStartTime()));
Opm::WellsManager wellsManager0(eclipseState, sched, summaryState, 0, *vanguard.c_grid());
Opm::WellsManager wellsManager1(eclipseState, sched, summaryState, 1, *vanguard.c_grid());
BOOST_CHECK(wells_equal( wellsManager0.c_wells() , wellsManager0.c_wells(),false));
BOOST_CHECK(!wells_equal( wellsManager0.c_wells() , wellsManager1.c_wells(),false));
}
BOOST_AUTO_TEST_CASE(ControlsEqual) {
const std::string filename = "wells_manager_data.data";
Opm::Parser parser;
Opm::Deck deck(parser.parseFile(filename));
Opm::EclipseState eclipseState(deck);
Opm::GridManager vanguard(eclipseState.getInputGrid());
const auto& grid = eclipseState.getInputGrid();
const Opm::TableManager table ( deck );
const Opm::Eclipse3DProperties eclipseProperties ( deck , table, grid);
const Opm::Runspec runspec (deck);
const Opm::Schedule sched(deck, grid, eclipseProperties, runspec);
Opm::SummaryState summaryState(std::chrono::system_clock::from_time_t(sched.getStartTime()));
Opm::WellsManager wellsManager0(eclipseState, sched, summaryState, 0, *vanguard.c_grid());
Opm::WellsManager wellsManager1(eclipseState, sched, summaryState, 1, *vanguard.c_grid());
BOOST_CHECK(well_controls_equal( wellsManager0.c_wells()->ctrls[0] , wellsManager0.c_wells()->ctrls[0] , false));
BOOST_CHECK(well_controls_equal( wellsManager0.c_wells()->ctrls[1] , wellsManager0.c_wells()->ctrls[1] , false));
BOOST_CHECK(well_controls_equal( wellsManager1.c_wells()->ctrls[0] , wellsManager1.c_wells()->ctrls[0] , false));
BOOST_CHECK(well_controls_equal( wellsManager1.c_wells()->ctrls[1] , wellsManager1.c_wells()->ctrls[1] , false));
BOOST_CHECK(!well_controls_equal( wellsManager0.c_wells()->ctrls[0] , wellsManager0.c_wells()->ctrls[1] , false));
BOOST_CHECK(!well_controls_equal( wellsManager0.c_wells()->ctrls[1] , wellsManager0.c_wells()->ctrls[0] , false));
BOOST_CHECK(!well_controls_equal( wellsManager1.c_wells()->ctrls[0] , wellsManager0.c_wells()->ctrls[0] , false));
BOOST_CHECK(!well_controls_equal( wellsManager1.c_wells()->ctrls[1] , wellsManager0.c_wells()->ctrls[1] , false));
}
BOOST_AUTO_TEST_CASE(WellShutOK) {
const std::string filename = "wells_manager_data.data";
Opm::Parser parser;
Opm::Deck deck(parser.parseFile(filename));
Opm::EclipseState eclipseState(deck);
Opm::GridManager vanguard(eclipseState.getInputGrid());
const auto& grid = eclipseState.getInputGrid();
const Opm::TableManager table ( deck );
const Opm::Eclipse3DProperties eclipseProperties ( deck , table, grid);
const Opm::Runspec runspec (deck);
const Opm::Schedule sched(deck, grid, eclipseProperties, runspec);
Opm::SummaryState summaryState(std::chrono::system_clock::from_time_t(sched.getStartTime()));
Opm::WellsManager wellsManager2(eclipseState, sched, summaryState, 2, *vanguard.c_grid());
// Shut wells are not added to the deck. i.e number of wells should be 2-1
BOOST_CHECK(wellsManager2.c_wells()->number_of_wells == 1);
//BOOST_CHECK_NO_THROW( Opm::WellsManager wellsManager2(eclipseState , 2 , *vanguard.c_grid(), NULL));
}
BOOST_AUTO_TEST_CASE(WellSTOPOK) {
const std::string filename = "wells_manager_data_wellSTOP.data";
Opm::Parser parser;
Opm::Deck deck(parser.parseFile(filename));
Opm::EclipseState eclipseState(deck);
Opm::GridManager vanguard(eclipseState.getInputGrid());
const auto& grid = eclipseState.getInputGrid();
const Opm::TableManager table ( deck );
const Opm::Eclipse3DProperties eclipseProperties ( deck , table, grid);
const Opm::Runspec runspec (deck);
const Opm::Schedule sched(deck, grid, eclipseProperties, runspec);
Opm::SummaryState summaryState(std::chrono::system_clock::from_time_t(sched.getStartTime()));
Opm::WellsManager wellsManager(eclipseState, sched, summaryState, 0, *vanguard.c_grid());
const Wells* wells = wellsManager.c_wells();
const struct WellControls* ctrls0 = wells->ctrls[0];
const struct WellControls* ctrls1 = wells->ctrls[1];
BOOST_CHECK(well_controls_well_is_stopped(ctrls0)); // The first well is closed
BOOST_CHECK(well_controls_well_is_open(ctrls1)); // The second well is open
}
BOOST_AUTO_TEST_CASE(removeWellWithNoPerforation) {
const std::string filename = "wells_no_perforation.data";
Opm::Parser parser;
Opm::Deck deck(parser.parseFile(filename));
Opm::EclipseState eclipseState(deck);
Opm::GridManager gridManager(eclipseState.getInputGrid());
const auto& inputGrid = eclipseState.getInputGrid();
const Opm::TableManager table ( deck );
const Opm::Eclipse3DProperties eclipseProperties ( deck , table, inputGrid);
const Opm::Runspec runspec (deck);
Opm::Schedule sched(deck, inputGrid, eclipseProperties, runspec);
Opm::SummaryState summaryState(std::chrono::system_clock::from_time_t(sched.getStartTime()));
const auto eclipseGrid = Opm::UgGridHelpers::createEclipseGrid(*gridManager.c_grid(), inputGrid);
sched.filterConnections(eclipseGrid);
Opm::WellsManager wellsManager0(eclipseState, sched, summaryState, 0, *gridManager.c_grid());
BOOST_CHECK_EQUAL( wellsManager0.c_wells()->number_of_wells, 1);
Opm::WellsManager wellsManager5(eclipseState, sched, summaryState, 5, *gridManager.c_grid());
BOOST_CHECK_EQUAL( wellsManager5.c_wells()->number_of_wells, 1);
}