Extract CTF Input Data to Separate Structure

This commit creates a new helper structure,

    Opm::Connection::CTFProperties

that holds all of the individual items which go into calculating the
final connection transmissibility factor (CTF).  These include the
'Kh' product, the pressure equivalent radius ('r0'), the well-bore
radius ('rw'), and the skin factor.  We reimplement the Connection
constructor in terms of this new helper structure and this changes
the API of the constructor.  As an additional helper for the
implementation, and with a view towards simulation restart support,
we also store the value of the Peaceman formula denominator in
CTFProperties as

    double CTFProperties::peaceman_denom

This, in turn, simplifies the implementation of CSKIN.  It also
fixes a latent problem in the current CSKIN implementation which
would ignore any explicitly input CTF values in favour of the
pressure equivalent radius.  By updating the explicit denominator
with a new skin factor instead we do not need to recompute the
logarithmic term involving 'r0' as part of CSKIN handling.
This commit is contained in:
Bård Skaflestad 2023-11-10 12:05:46 +01:00
parent 9a0ccfd853
commit 73c58dba48
15 changed files with 2263 additions and 1763 deletions

View File

@ -17,91 +17,167 @@
along with OPM. If not, see <http://www.gnu.org/licenses/>.
*/
#ifndef COMPLETION_HPP_
#define COMPLETION_HPP_
#include <opm/input/eclipse/Schedule/Well/FilterCake.hpp>
#include <opm/input/eclipse/Schedule/Well/WINJMULT.hpp>
#include <array>
#include <cstddef>
#include <map>
#include <memory>
#include <string>
#include <string_view>
#include <vector>
#include <optional>
#include <limits>
#include <opm/input/eclipse/Schedule/Well/FilterCake.hpp>
#include <opm/input/eclipse/Schedule/Well/WINJMULT.hpp>
namespace Opm {
namespace RestartIO {
struct RstConnection;
}
class DeckKeyword;
class DeckRecord;
class ScheduleGrid;
class FieldPropsManager;
} // namespace Opm
class Connection {
namespace Opm { namespace RestartIO {
struct RstConnection;
}} // namespace Opm::RestartIO
namespace Opm {
class Connection
{
public:
enum class State {
OPEN = 1,
SHUT = 2,
AUTO = 3 // Seems like the AUTO state can not be serialized to restart files.
AUTO = 3, // Seems like the AUTO state can not be serialized to restart files.
};
static const std::string State2String( State enumValue );
static State StateFromString( const std::string& stringValue );
static std::string State2String(State enumValue);
static State StateFromString(std::string_view stringValue);
enum class Direction{
enum class Direction {
X = 1,
Y = 2,
Z = 3
Z = 3,
};
static std::string Direction2String(const Direction enumValue);
static Direction DirectionFromString(const std::string& stringValue);
static Direction DirectionFromString(std::string_view stringValue);
enum class Order {
DEPTH,
INPUT,
TRACK
TRACK,
};
static const std::string Order2String( Order enumValue );
static Order OrderFromString(const std::string& comporderStringValue);
static std::string Order2String(Order enumValue);
static Order OrderFromString(std::string_view comporderStringValue);
enum class CTFKind {
DeckValue,
Defaulted,
};
Connection();
Connection(int i, int j , int k ,
/// Quantities that go into calculating the connection
/// transmissibility factor.
struct CTFProperties
{
/// Static connection transmissibility factor calculated from
/// input quantities.
double CF{};
/// Static 'Kh' product
double Kh{};
/// Effective permeability.
double Ke{};
/// Connection's wellbore radius
double rw{};
/// Connection's pressure equivalent radius
double r0{};
/// Connection's area equivalent radius--mostly for use by the
/// polymer code.
double re{};
/// Length of connection's perfororation interval
double connection_length{};
/// Connection's skin factor.
double skin_factor{};
/// Connection's D factor-i.e., the flow-dependent skin factor
/// for gas.
double d_factor{};
/// Denominator in peaceman's formula-i.e., log(r0/rw) + skin.
double peaceman_denom{};
/// Serialisation test object.
static CTFProperties serializationTestObject();
/// Equality operator
///
/// \param[in] that Property object to which \c *this will be compared.
bool operator==(const CTFProperties& that) const;
/// Inequality operator
///
/// \param[in] that Property object to which \c *this will be compared.
bool operator!=(const CTFProperties& that) const
{
return ! (*this == that);
}
/// Serialisation operator
///
/// \tparam Serializer Protocol for serialising and
/// deserialising objects between memory and character
/// buffers.
///
/// \param[in,out] serializer Serialisation object.
template <class Serializer>
void serializeOp(Serializer& serializer)
{
serializer(this->CF);
serializer(this->Kh);
serializer(this->Ke);
serializer(this->rw);
serializer(this->r0);
serializer(this->re);
serializer(this->connection_length);
serializer(this->skin_factor);
serializer(this->d_factor);
serializer(this->peaceman_denom);
}
};
Connection() = default;
Connection(int i, int j, int k,
std::size_t global_index,
int complnum,
double depth,
State state,
double CF,
double Kh,
double rw,
double r0,
double re,
double connection_length,
double skin_factor,
double d_factor,
double Ke,
Direction direction,
CTFKind ctf_kind,
const int satTableId,
const Direction direction,
const CTFKind ctf_kind,
double depth,
const CTFProperties& ctf_properties,
const std::size_t sort_value,
const bool defaultSatTabId);
Connection(const RestartIO::RstConnection& rst_connection, const ScheduleGrid& grid, const FieldPropsManager& fp);
Connection(const RestartIO::RstConnection& rst_connection,
const ScheduleGrid& grid,
const FieldPropsManager& fp);
static Connection serializationTestObject();
@ -117,104 +193,104 @@ namespace RestartIO {
int satTableId() const;
int complnum() const;
int segment() const;
double CF() const;
double wpimult() const;
double CF() const;
double Kh() const;
double Ke() const;
double rw() const;
double r0() const;
double re() const;
double connectionLength() const;
double skinFactor() const;
double dFactor() const;
double Ke() const;
CTFKind kind() const;
const InjMult& injmult() const;
bool activeInjMult() const;
void setInjMult(const InjMult& inj_mult);
void setFilterCake(const FilterCake& filter_cake);
const FilterCake& getFilterCake() const;
bool filterCakeActive() const;
double getFilterCakeRadius() const;
double getFilterCakeArea() const;
const CTFProperties& ctfProperties() const
{
return this->ctf_properties_;
}
std::size_t sort_value() const;
bool getDefaultSatTabId() const;
const std::optional<std::pair<double, double>>& perf_range() const;
std::string str() const;
bool ctfAssignedFromInput() const
{
return this->m_ctfkind == CTFKind::DeckValue;
}
bool operator==(const Connection&) const;
bool operator!=(const Connection& that) const
{
return ! (*this == that);
}
void setInjMult(const InjMult& inj_mult);
void setFilterCake(const FilterCake& filter_cake);
void setState(State state);
void setComplnum(int compnum);
void setSkinFactor(double skin_factor);
void setDFactor(double d_factor);
void setKe(double Ke);
void setCF(double CF);
void setDefaultSatTabId(bool id);
void scaleWellPi(double wellPi);
bool prepareWellPIScaling();
bool applyWellPIScaling(const double scaleFactor);
void updateSegmentRST(int segment_number_arg,
double center_depth_arg);
void updateSegment(int segment_number_arg,
double center_depth_arg,
std::size_t compseg_insert_index,
const std::optional<std::pair<double,double>>& perf_range);
std::size_t sort_value() const;
const bool& getDefaultSatTabId() const;
void setDefaultSatTabId(bool id);
const std::optional<std::pair<double, double>>& perf_range() const;
std::string str() const;
bool ctfAssignedFromInput() const
{
return this->m_ctfkind == CTFKind::DeckValue;
}
bool operator==( const Connection& ) const;
bool operator!=( const Connection& ) const;
template<class Serializer>
void serializeOp(Serializer& serializer)
{
serializer(direction);
serializer(center_depth);
serializer(open_state);
serializer(sat_tableId);
serializer(m_complnum);
serializer(m_CF);
serializer(m_Kh);
serializer(m_rw);
serializer(m_r0);
serializer(m_re);
serializer(m_connection_length);
serializer(m_skin_factor);
serializer(m_d_factor);
serializer(m_Ke);
serializer(ijk);
serializer(m_global_index);
serializer(m_ctfkind);
serializer(m_injmult);
serializer(m_sort_value);
serializer(m_perf_range);
serializer(m_defaultSatTabId);
serializer(segment_number);
serializer(m_subject_to_welpi);
serializer(m_filter_cake);
serializer(m_wpimult);
serializer(this->direction);
serializer(this->center_depth);
serializer(this->open_state);
serializer(this->sat_tableId);
serializer(this->m_complnum);
serializer(this->ctf_properties_);
serializer(this->ijk);
serializer(this->m_ctfkind);
serializer(this->m_global_index);
serializer(this->m_injmult);
serializer(this->m_sort_value);
serializer(this->m_perf_range);
serializer(this->m_defaultSatTabId);
serializer(this->segment_number);
serializer(this->m_wpimult);
serializer(this->m_subject_to_welpi);
serializer(this->m_filter_cake);
}
private:
Direction direction;
double center_depth;
State open_state;
int sat_tableId;
int m_complnum;
double m_CF;
double m_Kh;
double m_rw;
double m_r0;
double m_re;
double m_connection_length;
double m_skin_factor;
double m_d_factor;
double m_Ke;
// Note to maintainer: If you add new members to this list, then
// please also update the operator==(), serializeOp(), and
// serializationTestObject() member functions.
Direction direction { Direction::Z };
double center_depth { 0.0 };
State open_state { State::SHUT };
int sat_tableId { -1 };
int m_complnum { -1 };
CTFProperties ctf_properties_{};
std::array<int,3> ijk{};
CTFKind m_ctfkind { CTFKind::DeckValue };
std::optional<InjMult> m_injmult{};
std::size_t m_global_index{};
std::array<int,3> ijk;
CTFKind m_ctfkind;
std::optional<InjMult> m_injmult;
std::size_t m_global_index;
/*
The sort_value member is a peculiar quantity. The connections are
assembled in the WellConnections class. During the lifetime of the
@ -266,26 +342,26 @@ namespace RestartIO {
explicitly, so the truth is probably that the storage order
during simulation makes no difference?
*/
std::size_t m_sort_value{};
std::size_t m_sort_value;
std::optional<std::pair<double,double>> m_perf_range;
bool m_defaultSatTabId;
std::optional<std::pair<double,double>> m_perf_range{};
bool m_defaultSatTabId{true};
// related segment number
// 0 means the completion is not related to segment
int segment_number = 0;
// Associate segment number
//
// 0 means the connection is not associated to a segment.
int segment_number { 0 };
double m_wpimult { 1.0 };
// Whether or not this Connection is subject to WELPI scaling.
bool m_subject_to_welpi = false;
bool m_subject_to_welpi { false };
// For applying last known WPIMULT to when calculating connection transmissibilty factor in CSKIN
double m_wpimult = 1.0;
std::optional<FilterCake> m_filter_cake;
std::optional<FilterCake> m_filter_cake{};
static std::string CTFKindToString(const CTFKind);
};
}
#endif /* COMPLETION_HPP_ */
} // namespace Opm
#endif // COMPLETION_HPP_

View File

@ -527,7 +527,7 @@ public:
bool handleWELSEGS(const DeckKeyword& keyword);
bool handleCOMPSEGS(const DeckKeyword& keyword, const ScheduleGrid& grid, const ParseContext& parseContext, ErrorGuard& errors);
bool handleWELOPENConnections(const DeckRecord& record, Connection::State status);
bool handleCSKINConnections(const DeckRecord& record);
bool handleCSKIN(const DeckRecord& record, const KeywordLocation& location);
bool handleCOMPLUMP(const DeckRecord& record);
bool handleWPIMULT(const DeckRecord& record);
bool handleWINJCLN(const DeckRecord& record, const KeywordLocation& location);

View File

@ -23,9 +23,11 @@
#include <opm/input/eclipse/Schedule/Well/Connection.hpp>
#include <external/resinsight/LibGeometry/cvfBoundingBoxTree.h>
#include <array>
#include <cstddef>
#include <optional>
#include <string>
#include <utility>
#include <vector>
#include <stddef.h>
@ -33,10 +35,10 @@
namespace Opm {
class ActiveGridCells;
class DeckRecord;
class EclipseGrid;
class FieldPropsManager;
class KeywordLocation;
class ScheduleGrid;
class EclipseGrid;
} // namespace Opm
namespace Opm {
@ -67,19 +69,16 @@ namespace Opm {
}
}
void add(const Connection& conn)
{
this->m_connections.push_back(conn);
}
void addConnection(const int i, const int j, const int k,
const std::size_t global_index,
const double depth,
const Connection::State state,
const double CF,
const double Kh,
const double rw,
const double r0,
const double re,
const double connection_length,
const double skin_factor,
const double d_factor,
const double Ke,
const double depth,
const Connection::CTFProperties& ctf_props,
const int satTableId,
const Connection::Direction direction = Connection::Direction::Z,
const Connection::CTFKind ctf_kind = Connection::CTFKind::DeckValue,
@ -91,14 +90,20 @@ namespace Opm {
const std::string& wname,
const KeywordLocation& location);
void loadCOMPTRAJ(const DeckRecord& record, const ScheduleGrid& grid, const std::string& wname, const KeywordLocation& location, external::cvf::ref<external::cvf::BoundingBoxTree>& cellSearchTree);
void loadCOMPTRAJ(const DeckRecord& record,
const ScheduleGrid& grid,
const std::string& wname,
const KeywordLocation& location,
external::cvf::ref<external::cvf::BoundingBoxTree>& cellSearchTree);
void loadWELTRAJ(const DeckRecord& record, const ScheduleGrid& grid, const std::string& wname, const KeywordLocation& location);
void loadWELTRAJ(const DeckRecord& record,
const ScheduleGrid& grid,
const std::string& wname,
const KeywordLocation& location);
int getHeadI() const;
int getHeadJ() const;
const std::vector<double>& getMD() const;
void add(Connection);
std::size_t size() const;
bool empty() const;
std::size_t num_open() const;
@ -165,39 +170,32 @@ namespace Opm {
serializer(this->coord);
serializer(this->md);
}
private:
Connection::Order m_ordering { Connection::Order::TRACK };
int headI{0};
int headJ{0};
std::vector<Connection> m_connections{};
std::vector<std::vector<double>> coord{3, std::vector<double>(0, 0.0) };
std::array<std::vector<double>, 3> coord{};
std::vector<double> md{};
void addConnection(const int i, const int j, const int k,
const std::size_t global_index,
const int complnum,
const double depth,
const Connection::State state,
const double CF,
const double Kh,
const double rw,
const double r0,
const double re,
const double connection_length,
const double skin_factor,
const double d_factor,
const double Ke,
const double depth,
const Connection::CTFProperties& ctf_props,
const int satTableId,
const Connection::Direction direction = Connection::Direction::Z,
const Connection::CTFKind ctf_kind = Connection::CTFKind::DeckValue,
const std::size_t seqIndex = 0,
const bool defaultSatTabId = true);
const Connection::Direction direction,
const Connection::CTFKind ctf_kind,
const std::size_t seqIndex,
const bool defaultSatTabId);
size_t findClosestConnection(int oi, int oj, double oz, size_t start_pos);
void orderTRACK();
void orderMSW();
void orderDEPTH();
};
std::optional<int>

View File

@ -377,23 +377,29 @@ File {} line {}.)", wname, location.keyword, location.filename, location.lineno)
handlerContext.compsegs_handled(wname);
}
void Schedule::handleCSKIN(HandlerContext& handlerContext) {
void Schedule::handleCSKIN(HandlerContext& handlerContext)
{
using Kw = ParserKeywords::CSKIN;
// Get CSKIN keyword info and current step
const auto& keyword = handlerContext.keyword;
const auto& currentStep = handlerContext.currentStep;
// Loop over records in CSKIN
for (const auto& record: keyword) {
for (const auto& record : keyword) {
// Get well names
const auto& wellNamePattern = record.getItem( "WELL" ).getTrimmedString(0);
const auto wellNamePattern = record.getItem<Kw::WELL>().getTrimmedString(0);
const auto well_names = this->wellNames(wellNamePattern, handlerContext);
// Loop over well(s) in record
for (const auto& wname : well_names) {
// Get well information, modify connection skin factor, and update well
// Get well information, modify connection skin factor, and
// update well.
auto well = this->snapshots[currentStep].wells.get(wname);
well.handleCSKINConnections(record);
this->snapshots[currentStep].wells.update( std::move(well) );
if (well.handleCSKIN(record, handlerContext.keyword.location())) {
this->snapshots[currentStep].wells.update(std::move(well));
}
}
}
}

View File

@ -17,125 +17,157 @@
along with OPM. If not, see <http://www.gnu.org/licenses/>.
*/
#include <opm/input/eclipse/Schedule/Well/Connection.hpp>
#include <opm/io/eclipse/rst/connection.hpp>
#include <opm/input/eclipse/EclipseState/Grid/FieldPropsManager.hpp>
#include <opm/input/eclipse/Schedule/ScheduleGrid.hpp>
#include <opm/input/eclipse/Schedule/Well/FilterCake.hpp>
#include <opm/input/eclipse/Deck/DeckItem.hpp>
#include <opm/input/eclipse/Deck/DeckKeyword.hpp>
#include <opm/input/eclipse/Deck/DeckRecord.hpp>
#include <algorithm>
#include <cassert>
#include <exception>
#include <sstream>
#include <stdexcept>
#include <string>
#include <string_view>
#include <vector>
#include <opm/io/eclipse/rst/connection.hpp>
#include <opm/input/eclipse/Deck/DeckItem.hpp>
#include <opm/input/eclipse/Deck/DeckKeyword.hpp>
#include <opm/input/eclipse/Deck/DeckRecord.hpp>
#include <opm/input/eclipse/EclipseState/Grid/FieldPropsManager.hpp>
#include <opm/input/eclipse/Schedule/Well/Connection.hpp>
#include <opm/input/eclipse/Schedule/Well/FilterCake.hpp>
#include <opm/input/eclipse/Schedule/ScheduleGrid.hpp>
namespace Opm {
Connection::Connection(int i, int j , int k ,
std::size_t global_index,
int compnum,
double depth,
State stateArg ,
double CF,
double Kh,
double rw,
double r0,
double re,
double connection_length,
double skin_factor,
double d_factor,
double Ke,
const int satTableId,
const Direction directionArg,
const CTFKind ctf_kind,
const std::size_t sort_value,
const bool defaultSatTabId)
: direction(directionArg),
center_depth(depth),
open_state(stateArg),
sat_tableId(satTableId),
m_complnum( compnum ),
m_CF(CF),
m_Kh(Kh),
m_rw(rw),
m_r0(r0),
m_re(re),
m_connection_length(connection_length),
m_skin_factor(skin_factor),
m_d_factor(d_factor),
m_Ke(Ke),
ijk({i,j,k}),
m_ctfkind(ctf_kind),
m_global_index(global_index),
m_sort_value(sort_value),
m_defaultSatTabId(defaultSatTabId)
{
}
namespace {
constexpr bool defaultSatTabId = true;
constexpr bool restartDefaultSatTabId = true;
Opm::Connection::CTFProperties
collectCTFProps(const Opm::RestartIO::RstConnection& rst_conn)
{
auto props = Opm::Connection::CTFProperties{};
props.CF = rst_conn.cf;
props.Kh = rst_conn.kh;
props.Ke = 0.0;
props.rw = rst_conn.diameter / 2;
props.r0 = rst_conn.r0;
props.re = 0.0;
props.connection_length = 0.0;
props.skin_factor = rst_conn.skin_factor;
props.d_factor = 0.0;
return props;
}
}
Connection::Connection(const RestartIO::RstConnection& rst_connection, const ScheduleGrid& grid, const FieldPropsManager& fp) :
direction(rst_connection.dir),
center_depth(rst_connection.depth),
open_state(rst_connection.state),
sat_tableId(rst_connection.drain_sat_table),
m_complnum(rst_connection.completion),
m_CF(rst_connection.cf),
m_Kh(rst_connection.kh),
m_rw(rst_connection.diameter / 2),
m_r0(rst_connection.r0),
m_re(0.0),
m_connection_length(0.0),
m_skin_factor(rst_connection.skin_factor),
m_d_factor(0.0),
m_Ke(0.0),
ijk(rst_connection.ijk),
m_ctfkind(rst_connection.cf_kind),
m_global_index(grid.get_cell(this->ijk[0], this->ijk[1], this->ijk[2]).global_index),
m_sort_value(rst_connection.rst_index),
m_defaultSatTabId(defaultSatTabId),
segment_number(rst_connection.segment)
namespace Opm
{
Connection::CTFProperties
Connection::CTFProperties::serializationTestObject()
{
auto props = Opm::Connection::CTFProperties{};
props.CF = 1.0;
props.Kh = 2.0;
props.Ke = 3.0;
props.rw = 4.0;
props.r0 = 5.0;
props.re = 6.0;
props.connection_length = 7.0;
props.skin_factor = 8.0;
props.d_factor = 9.0;
props.peaceman_denom = 10.0;
return props;
}
bool Connection::CTFProperties::operator==(const CTFProperties& that) const
{
return (this->CF == that.CF)
&& (this->Kh == that.Kh)
&& (this->Ke == that.Ke)
&& (this->rw == that.rw)
&& (this->r0 == that.r0)
&& (this->re == that.re)
&& (this->connection_length == that.connection_length)
&& (this->skin_factor == that.skin_factor)
&& (this->d_factor == that.d_factor)
&& (this->peaceman_denom == that.peaceman_denom)
;
}
// =========================================================================
Connection::Connection(const int i, const int j, const int k,
const std::size_t global_index,
const int complnum,
const State stateArg,
const Direction directionArg,
const CTFKind ctf_kind,
const int satTableId,
const double depth,
const CTFProperties& ctf_props,
const std::size_t sort_value,
const bool defaultSatTabId)
: direction (directionArg)
, center_depth (depth)
, open_state (stateArg)
, sat_tableId (satTableId)
, m_complnum (complnum)
, ctf_properties_ { ctf_props }
, ijk { i, j, k }
, m_ctfkind (ctf_kind)
, m_global_index (global_index)
, m_sort_value (sort_value)
, m_defaultSatTabId(defaultSatTabId)
{}
Connection::Connection(const RestartIO::RstConnection& rst_connection,
const ScheduleGrid& grid,
const FieldPropsManager& fp)
: direction (rst_connection.dir)
, center_depth (rst_connection.depth)
, open_state (rst_connection.state)
, sat_tableId (rst_connection.drain_sat_table)
, m_complnum (rst_connection.completion)
, ctf_properties_ (collectCTFProps(rst_connection))
, ijk (rst_connection.ijk)
, m_ctfkind (rst_connection.cf_kind)
, m_global_index (grid.get_cell(this->ijk[0], this->ijk[1], this->ijk[2]).global_index)
, m_sort_value (rst_connection.rst_index)
, m_defaultSatTabId(restartDefaultSatTabId)
, segment_number (rst_connection.segment)
{
if (this->m_defaultSatTabId) {
const auto& satnum = fp.get_int("SATNUM");
auto active_index = grid.get_cell(this->ijk[0], this->ijk[1], this->ijk[2]).active_index();
this->sat_tableId = satnum[active_index];
const auto active_index = grid
.get_cell(this->ijk[0], this->ijk[1], this->ijk[2])
.active_index();
this->sat_tableId = fp.get_int("SATNUM")[active_index];
}
if (this->segment_number > 0) {
this->m_perf_range = std::make_pair(rst_connection.segdist_start,
rst_connection.segdist_end);
}
if (this->segment_number > 0)
this->m_perf_range = std::make_pair(rst_connection.segdist_start, rst_connection.segdist_end);
//TODO recompute re and perf_length from the grid
}
Connection::Connection()
: Connection(0, 0, 0, 0, 0, 0.0, State::SHUT, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0,
0, Direction::X, CTFKind::DeckValue, 0, false)
{}
Connection Connection::serializationTestObject()
{
Connection result;
result.direction = Direction::Y;
result.center_depth = 1.0;
result.open_state = State::OPEN;
result.sat_tableId = 2;
result.m_complnum = 3;
result.m_CF = 4.0;
result.m_Kh = 5.0;
result.m_rw = 6.0;
result.m_r0 = 7.0;
result.m_re = 7.1;
result.m_connection_length = 7.2;
result.m_skin_factor = 8.0;
result.m_d_factor = 8.5;
result.m_Ke = 8.9;
result.ctf_properties_ = CTFProperties::serializationTestObject();
result.ijk = {9, 10, 11};
result.m_ctfkind = CTFKind::Defaulted;
result.m_global_index = 12;
@ -144,144 +176,181 @@ Connection::Connection(const RestartIO::RstConnection& rst_connection, const Sch
result.m_sort_value = 14;
result.m_defaultSatTabId = true;
result.segment_number = 16;
result.m_wpimult = 0.123;
result.m_subject_to_welpi = true;
result.m_filter_cake = FilterCake::serializationTestObject();
return result;
}
bool Connection::sameCoordinate(const int i, const int j, const int k) const {
if ((ijk[0] == i) && (ijk[1] == j) && (ijk[2] == k)) {
return true;
} else {
return false;
}
bool Connection::sameCoordinate(const int i, const int j, const int k) const
{
return this->ijk == std::array { i, j, k };
}
int Connection::getI() const {
int Connection::getI() const
{
return ijk[0];
}
int Connection::getJ() const {
int Connection::getJ() const
{
return ijk[1];
}
int Connection::getK() const {
int Connection::getK() const
{
return ijk[2];
}
std::size_t Connection::global_index() const {
std::size_t Connection::global_index() const
{
return this->m_global_index;
}
bool Connection::attachedToSegment() const {
return (segment_number > 0);
bool Connection::attachedToSegment() const
{
return this->segment_number > 0;
}
std::size_t Connection::sort_value() const {
std::size_t Connection::sort_value() const
{
return m_sort_value;
}
const bool& Connection::getDefaultSatTabId() const {
bool Connection::getDefaultSatTabId() const
{
return m_defaultSatTabId;
}
Connection::Direction Connection::dir() const {
Connection::Direction Connection::dir() const
{
return this->direction;
}
const std::optional<std::pair<double, double>>& Connection::perf_range() const {
const std::optional<std::pair<double, double>>&
Connection::perf_range() const
{
return this->m_perf_range;
}
void Connection::setDefaultSatTabId(bool id) {
void Connection::setDefaultSatTabId(bool id)
{
m_defaultSatTabId = id;
}
double Connection::depth() const {
double Connection::depth() const
{
return this->center_depth;
}
Connection::State Connection::state() const {
Connection::State Connection::state() const
{
return this->open_state;
}
int Connection::satTableId() const {
int Connection::satTableId() const
{
return this->sat_tableId;
}
int Connection::complnum() const {
int Connection::complnum() const
{
return this->m_complnum;
}
void Connection::setComplnum(int complnum) {
void Connection::setComplnum(int complnum)
{
this->m_complnum = complnum;
}
void Connection::setSkinFactor(double skin_factor) {
this->m_skin_factor = skin_factor;
void Connection::setSkinFactor(double skin_factor)
{
auto& ctf_p = this->ctf_properties_;
const auto peaceman_denom = ctf_p.peaceman_denom
- ctf_p.skin_factor + skin_factor;
ctf_p.skin_factor = skin_factor;
ctf_p.CF *= ctf_p.peaceman_denom / peaceman_denom;
ctf_p.peaceman_denom = peaceman_denom;
}
void Connection::setDFactor(double d_factor) {
this->m_d_factor = d_factor;
void Connection::setDFactor(double d_factor)
{
this->ctf_properties_.d_factor = d_factor;
}
void Connection::setKe(double Ke) {
this->m_Ke = Ke;
void Connection::setKe(double Ke)
{
this->ctf_properties_.Ke = Ke;
}
void Connection::setCF(double CF) {
this->m_CF = CF;
void Connection::setCF(double CF)
{
this->ctf_properties_.CF = CF;
}
double Connection::CF() const {
return this->m_CF;
}
double Connection::wpimult() const {
double Connection::wpimult() const
{
return this->m_wpimult;
}
double Connection::Kh() const {
return this->m_Kh;
double Connection::CF() const
{
return this->ctf_properties_.CF;
}
double Connection::rw() const {
return this->m_rw;
double Connection::Kh() const
{
return this->ctf_properties_.Kh;
}
double Connection::r0() const {
return this->m_r0;
double Connection::rw() const
{
return this->ctf_properties_.rw;
}
double Connection::re() const {
return this->m_re;
double Connection::r0() const
{
return this->ctf_properties_.r0;
}
double Connection::connectionLength() const {
return this->m_connection_length;
double Connection::re() const
{
return this->ctf_properties_.re;
}
double Connection::skinFactor() const {
return this->m_skin_factor;
double Connection::connectionLength() const
{
return this->ctf_properties_.connection_length;
}
double Connection::dFactor() const {
return this->m_d_factor;
double Connection::skinFactor() const
{
return this->ctf_properties_.skin_factor;
}
double Connection::Ke() const {
return this->m_Ke;
double Connection::dFactor() const
{
return this->ctf_properties_.d_factor;
}
void Connection::setState(State state) {
double Connection::Ke() const
{
return this->ctf_properties_.Ke;
}
void Connection::setState(State state)
{
this->open_state = state;
}
void Connection::updateSegment(int segment_number_arg,
double center_depth_arg,
std::size_t compseg_insert_index,
const std::optional<std::pair<double, double>>& perf_range) {
void Connection::updateSegment(const int segment_number_arg,
const double center_depth_arg,
const std::size_t compseg_insert_index,
const std::optional<std::pair<double, double>>& perf_range)
{
this->segment_number = segment_number_arg;
this->center_depth = center_depth_arg;
this->m_sort_value = compseg_insert_index;
@ -289,21 +358,25 @@ const std::optional<std::pair<double, double>>& Connection::perf_range() const {
}
void Connection::updateSegmentRST(int segment_number_arg,
double center_depth_arg) {
double center_depth_arg)
{
this->segment_number = segment_number_arg;
this->center_depth = center_depth_arg;
}
int Connection::segment() const {
int Connection::segment() const
{
return this->segment_number;
}
void Connection::scaleWellPi(double wellPi) {
void Connection::scaleWellPi(double wellPi)
{
this->m_wpimult *= wellPi;
this->m_CF *= wellPi;
this->ctf_properties_.CF *= wellPi;
}
bool Connection::prepareWellPIScaling() {
bool Connection::prepareWellPIScaling()
{
const auto update = !this->m_subject_to_welpi;
this->m_subject_to_welpi = true;
@ -311,102 +384,111 @@ const std::optional<std::pair<double, double>>& Connection::perf_range() const {
return update;
}
bool Connection::applyWellPIScaling(const double scaleFactor) {
if (! this->m_subject_to_welpi)
bool Connection::applyWellPIScaling(const double scaleFactor)
{
if (! this->m_subject_to_welpi) {
return false;
}
this->scaleWellPi(scaleFactor);
return true;
}
std::string Connection::str() const {
std::string Connection::str() const
{
std::stringstream ss;
ss << "ijk: " << this->ijk[0] << "," << this->ijk[1] << "," << this->ijk[2] << std::endl;
ss << "COMPLNUM " << this->m_complnum << std::endl;
ss << "CF " << this->m_CF << std::endl;
ss << "RW " << this->m_rw << std::endl;
ss << "R0 " << this->m_r0 << std::endl;
ss << "Re " << this->m_re << std::endl;
ss << "connection length " << this->m_connection_length << std::endl;
ss << "skinf " << this->m_skin_factor << std::endl;
ss << "dfactor " << this->m_d_factor << std::endl;
ss << "Ke " << this->m_Ke << std::endl;
ss << "kh " << this->m_Kh << std::endl;
ss << "sat_tableId " << this->sat_tableId << std::endl;
ss << "open_state " << Connection::State2String(this->open_state) << std::endl;
ss << "direction " << Connection::Direction2String(this->direction) << std::endl;
ss << "CTF Source " << Connection::CTFKindToString(this->m_ctfkind) << '\n';
ss << "segment_nr " << this->segment_number << std::endl;
ss << "center_depth " << this->center_depth << std::endl;
ss << "sort_value" << this->m_sort_value<< std::endl;
ss << "ijk: " << this->ijk[0] << ',' << this->ijk[1] << ',' << this->ijk[2] << '\n'
<< "COMPLNUM " << this->m_complnum << '\n'
<< "CF " << this->CF() << '\n'
<< "RW " << this->rw() << '\n'
<< "R0 " << this->r0() << '\n'
<< "Re " << this->re() << '\n'
<< "connection length " << this->connectionLength() << '\n'
<< "skinf " << this->skinFactor() << '\n'
<< "dfactor " << this->dFactor() << '\n'
<< "Ke " << this->Ke() << '\n'
<< "kh " << this->Kh() << '\n'
<< "sat_tableId " << this->sat_tableId << '\n'
<< "open_state " << Connection::State2String(this->open_state) << '\n'
<< "direction " << Connection::Direction2String(this->direction) << '\n'
<< "CTF Source " << Connection::CTFKindToString(this->m_ctfkind) << '\n'
<< "segment_nr " << this->segment_number << '\n'
<< "center_depth " << this->center_depth << '\n'
<< "sort_value" << this->m_sort_value<< '\n';
if (this->m_injmult.has_value()) {
ss << "INJMULT " << InjMult::InjMultToString(this->m_injmult.value()) << std::endl;
ss << "INJMULT " << InjMult::InjMultToString(this->m_injmult.value()) << '\n';
}
if (this->m_filter_cake.has_value()) {
ss << "FilterCake " << FilterCake::filterCakeToString(this->m_filter_cake.value()) << std::endl;
ss << "FilterCake " << FilterCake::filterCakeToString(this->m_filter_cake.value()) << '\n';
}
return ss.str();
}
bool Connection::operator==( const Connection& rhs ) const {
return this->ijk == rhs.ijk
&& this->m_global_index == rhs.m_global_index
&& this->m_complnum == rhs.m_complnum
&& this->m_CF == rhs.m_CF
&& this->m_rw == rhs.m_rw
&& this->m_r0 == rhs.m_r0
&& this->m_re == rhs.m_re
&& this->m_connection_length == rhs.m_connection_length
&& this->m_skin_factor == rhs.m_skin_factor
&& this->m_d_factor == rhs.m_d_factor
&& this->m_Ke == rhs.m_Ke
&& this->m_injmult == rhs.m_injmult
&& this->m_Kh == rhs.m_Kh
&& this->sat_tableId == rhs.sat_tableId
&& this->open_state == rhs.open_state
&& this->direction == rhs.direction
&& this->segment_number == rhs.segment_number
&& this->center_depth == rhs.center_depth
&& this->m_sort_value == rhs.m_sort_value
&& this->m_subject_to_welpi == rhs.m_subject_to_welpi
&& this->m_filter_cake == rhs.m_filter_cake;
}
bool Connection::operator!=( const Connection& rhs ) const {
return !( *this == rhs );
bool Connection::operator==(const Connection& that) const
{
return (this->direction == that.direction)
&& (this->open_state == that.open_state)
&& (this->sat_tableId == that.sat_tableId)
&& (this->m_complnum == that.m_complnum)
&& (this->m_ctfkind == that.m_ctfkind)
&& (this->m_global_index == that.m_global_index)
&& (this->m_sort_value == that.m_sort_value)
&& (this->m_defaultSatTabId == that.m_defaultSatTabId)
&& (this->segment_number == that.segment_number)
&& (this->m_subject_to_welpi == that.m_subject_to_welpi)
&& (this->ijk == that.ijk)
&& (this->m_injmult == that.m_injmult)
&& (this->center_depth == that.center_depth)
&& (this->m_perf_range == that.m_perf_range)
&& (this->ctf_properties_ == that.ctf_properties_)
&& (this->m_filter_cake == that.m_filter_cake)
;
}
const std::string Connection::State2String( State enumValue ) {
switch( enumValue ) {
std::string Connection::State2String(State enumValue)
{
switch (enumValue) {
case State::OPEN:
return "OPEN";
case State::AUTO:
return "AUTO";
case State::SHUT:
return "SHUT";
default:
throw std::invalid_argument("Unhandled enum value");
throw std::invalid_argument {
"Unhandled Connection::State value " +
std::to_string(static_cast<int>(enumValue))
};
}
}
Connection::State Connection::StateFromString( const std::string& stringValue ) {
Connection::State
Connection::StateFromString(std::string_view stringValue)
{
if (stringValue == "OPEN")
return State::OPEN;
else if (stringValue == "SHUT")
return State::SHUT;
else if (stringValue == "STOP")
return State::SHUT;
else if (stringValue == "AUTO")
return State::AUTO;
else
throw std::invalid_argument("Unknown enum state string: " + stringValue );
}
if (stringValue == "SHUT")
return State::SHUT;
if (stringValue == "STOP")
return State::SHUT;
if (stringValue == "AUTO")
return State::AUTO;
throw std::invalid_argument {
"Unknown Connection::State string: " + std::string { stringValue }
};
}
std::string Connection::Direction2String(const Direction enumValue)
@ -434,8 +516,7 @@ std::string Connection::Direction2String(const Direction enumValue)
return stringValue;
}
Connection::Direction Connection::DirectionFromString(const std::string& s )
Connection::Direction Connection::DirectionFromString(std::string_view s)
{
Direction direction;
@ -443,39 +524,53 @@ Connection::Direction Connection::DirectionFromString(const std::string& s )
else if ((s == "Y") || (s == "y")) { direction = Direction::Y; }
else if ((s == "Z") || (s == "z")) { direction = Direction::Z; }
else {
std::string msg = "Unsupported completion direction " + s;
throw std::invalid_argument(msg);
throw std::invalid_argument {
"Unsupported completion direction "
+ std::string { s }
};
}
return direction;
}
const std::string Connection::Order2String( Order enumValue ) {
switch( enumValue ) {
std::string Connection::Order2String(Order enumValue)
{
switch (enumValue) {
case Order::DEPTH:
return "DEPTH";
case Order::INPUT:
return "INPUT";
case Order::TRACK:
return "TRACK";
default:
throw std::invalid_argument("Unhandled enum value");
throw std::invalid_argument {
"Unhandled Connection::Order value " +
std::to_string(static_cast<int>(enumValue))
};
}
}
Connection::Order Connection::OrderFromString(const std::string& stringValue ) {
Connection::Order Connection::OrderFromString(std::string_view stringValue)
{
if (stringValue == "DEPTH")
return Order::DEPTH;
else if (stringValue == "INPUT")
if (stringValue == "INPUT")
return Order::INPUT;
else if (stringValue == "TRACK")
if (stringValue == "TRACK")
return Order::TRACK;
else
throw std::invalid_argument("Unknown enum state string: " + stringValue );
throw std::invalid_argument {
"Unknown Connection::Order string: " + std::string { stringValue }
};
}
std::string Connection::CTFKindToString(const CTFKind ctf_kind)
{
switch (ctf_kind) {
@ -492,58 +587,62 @@ std::string Connection::CTFKindToString(const CTFKind ctf_kind)
};
}
Connection::CTFKind Connection::kind() const {
Connection::CTFKind Connection::kind() const
{
return m_ctfkind;
}
const InjMult& Connection::injmult() const {
const InjMult& Connection::injmult() const
{
assert(this->activeInjMult());
return m_injmult.value();
}
bool Connection::activeInjMult() const {
bool Connection::activeInjMult() const
{
return this->m_injmult.has_value();
}
void Connection::setInjMult(const InjMult& inj_mult) {
void Connection::setInjMult(const InjMult& inj_mult)
{
m_injmult = inj_mult;
}
void Connection::setFilterCake(const FilterCake& filter_cake) {
void Connection::setFilterCake(const FilterCake& filter_cake)
{
this->m_filter_cake = filter_cake;
}
bool Connection::filterCakeActive() const {
bool Connection::filterCakeActive() const
{
return this->m_filter_cake.has_value();
}
const FilterCake& Connection::getFilterCake() const {
const FilterCake& Connection::getFilterCake() const
{
assert(this->filterCakeActive());
return this->m_filter_cake.value();
}
double Connection::getFilterCakeRadius() const {
if (this->getFilterCake().radius.has_value()) {
return this->getFilterCake().radius.value();
} else {
return this->m_rw;
double Connection::getFilterCakeRadius() const
{
if (const auto& radius = this->getFilterCake().radius; radius.has_value()) {
return *radius;
}
else {
return this->rw();
}
}
double Connection::getFilterCakeArea() const {
if (this->getFilterCake().flow_area.has_value()) {
return this->getFilterCake().flow_area.value();
} else {
const double radius = this->getFilterCakeRadius();
const double length = this->m_connection_length;
constexpr double pi = 3.14159265;
return 2. * pi * radius * length;
double Connection::getFilterCakeArea() const
{
if (const auto& flow_area = this->getFilterCake().flow_area; flow_area.has_value()) {
return *flow_area;
}
else {
constexpr double two_pi = 2 * 3.14159265358979323846264;
return two_pi * this->getFilterCakeRadius() * this->connectionLength();
}
}
} // end of namespace Opm

View File

@ -40,13 +40,12 @@
#include <opm/input/eclipse/Schedule/Well/WVFPDP.hpp>
#include <opm/input/eclipse/Schedule/Well/WVFPEXP.hpp>
#include <opm/input/eclipse/Units/Units.hpp>
#include <opm/common/utility/OpmInputError.hpp>
#include <opm/common/utility/shmatch.hpp>
#include <opm/input/eclipse/Parser/ParserKeywords/C.hpp>
#include <opm/input/eclipse/Parser/ParserKeywords/S.hpp>
#include <opm/input/eclipse/Parser/ParserKeywords/W.hpp>
@ -1300,42 +1299,60 @@ bool Well::handleWELOPENConnections(const DeckRecord& record, Connection::State
return this->updateConnections(std::move(new_connections), false);
}
bool Well::handleCSKINConnections(const DeckRecord& record) {
// Lambda expression to check if record coordinates match connection coordinates
auto match = [=]( const Connection &c) -> bool {
if (!match_eq(c.getI(), record, "I" , -1)) return false;
if (!match_eq(c.getJ(), record, "J" , -1)) return false;
if (!match_ge(c.getK(), record, "K_UPPER", -1)) return false;
if (!match_le(c.getK(), record, "K_LOWER", -1)) return false;
bool Well::handleCSKIN(const DeckRecord& record,
const KeywordLocation& location)
{
using Kw = ParserKeywords::CSKIN;
return true;
auto need_skin_adjustment = [&record](const Connection &c) {
const auto value_shift = -1;
return match_eq(c.getI(), record, Kw::I::itemName, value_shift)
&& match_eq(c.getJ(), record, Kw::J::itemName, value_shift)
&& match_ge(c.getK(), record, Kw::K_UPPER::itemName, value_shift)
&& match_le(c.getK(), record, Kw::K_LOWER::itemName, value_shift);
};
// Generate a new connection which will be updated with new connection skin factor
auto new_connections = std::make_shared<WellConnections>(this->connections->ordering(), this->headI, this->headJ);
// New connection set which will be updated with new connection level
// skin factors.
auto new_connections = std::make_shared<WellConnections>
(this->connections->ordering(), this->headI, this->headJ);
// Update skin factor
double skin_factor = record.getItem("CONNECTION_SKIN_FACTOR").get<double>(0);
const double angle = 6.2831853071795864769252867665590057683943387987502116419498;
for (auto c : *this->connections) {
if (match(c)) {
// Check for potential negative new CF
if ((std::log(c.r0() / std::min(c.rw(), c.r0())) + skin_factor) < 0.0) {
throw std::runtime_error("Negative connection transmissibility factor produced by CSKIN for well "
+ name());
const auto skin_factor = record.getItem<Kw::CONNECTION_SKIN_FACTOR>().getSIDouble(0);
for (const auto& connection : *this->connections) {
if (! need_skin_adjustment(connection)) {
// No CSKIN adjustment needed here. Include connection as-is
// into new connection set.
new_connections->add(connection);
continue;
}
// Calculate new connection transmissibility factor
double CF = angle * c.Kh() / (std::log(c.r0() / std::min(c.rw(), c.r0())) + skin_factor);
// Apply last known WPIMULT (defaulted to 1.0)
CF *= c.wpimult();
// Set skin factor and connection factor
c.setSkinFactor(skin_factor);
c.setCF(CF);
// If we get here, we must make the connection's skin factor be
// 'skin_factor'.
//
// First guard against this adjustment making the CTF go negative,
// typically because the 'skin_factor' value is large and negative
// itself.
if (const auto& ctf_props = connection.ctfProperties();
ctf_props.peaceman_denom + skin_factor - ctf_props.skin_factor < 0.0)
{
throw OpmInputError {
fmt::format("Negative connection transmissibility "
"factor generated by skin factor {} "
"in connection ({},{},{}) for well {}.",
skin_factor,
connection.getI() + 1,
connection.getJ() + 1,
connection.getK() + 1,
this->name()),
location
};
}
new_connections->add(c);
auto connection_copy = connection;
connection_copy.setSkinFactor(skin_factor);
new_connections->add(connection_copy);
}
return this->updateConnections(std::move(new_connections), false);
@ -1390,6 +1407,7 @@ bool Well::handleWPIMULT(const DeckRecord& record) {
new_connections->add(c);
}
return this->updateConnections(std::move(new_connections), false);
}

File diff suppressed because it is too large Load Diff

View File

@ -17,32 +17,38 @@
along with OPM. If not, see <http://www.gnu.org/licenses/>.
*/
#include <cstddef>
#include <stdexcept>
#include <ostream>
#define BOOST_TEST_MODULE CompletionTests
#include <boost/test/unit_test.hpp>
#include <opm/common/utility/ActiveGridCells.hpp>
#include <opm/input/eclipse/Python/Python.hpp>
#include <opm/input/eclipse/Parser/Parser.hpp>
#include <opm/input/eclipse/Deck/Deck.hpp>
#include <opm/input/eclipse/Schedule/Well/Connection.hpp>
#include <opm/input/eclipse/Schedule/Well/Well.hpp>
#include <opm/input/eclipse/Schedule/Well/WellConnections.hpp>
#include <opm/common/utility/ActiveGridCells.hpp>
#include <opm/input/eclipse/Python/Python.hpp>
#include <opm/input/eclipse/EclipseState/EclipseState.hpp>
#include <opm/input/eclipse/EclipseState/Grid/EclipseGrid.hpp>
#include <opm/input/eclipse/EclipseState/Tables/TableManager.hpp>
#include <opm/input/eclipse/EclipseState/Grid/FieldPropsManager.hpp>
#include <opm/input/eclipse/Schedule/CompletedCells.hpp>
#include <opm/input/eclipse/Schedule/ScheduleGrid.hpp>
#include <opm/input/eclipse/EclipseState/Tables/TableManager.hpp>
#include <opm/input/eclipse/Schedule/CompletedCells.hpp>
#include <opm/input/eclipse/Schedule/Schedule.hpp>
#include <opm/input/eclipse/Schedule/ScheduleGrid.hpp>
#include <opm/input/eclipse/Schedule/Well/Well.hpp>
#include <opm/input/eclipse/Schedule/Well/WellConnections.hpp>
#include <opm/common/OpmLog/KeywordLocation.hpp>
#include <opm/input/eclipse/Units/Units.hpp>
#include <opm/input/eclipse/Units/UnitSystem.hpp>
#include <opm/input/eclipse/Deck/Deck.hpp>
#include <opm/input/eclipse/Parser/Parser.hpp>
#include <cstddef>
#include <stdexcept>
#include <ostream>
namespace {
double cp_rm3_per_db()
@ -51,20 +57,31 @@ namespace {
/ (Opm::unit::day * Opm::unit::barsa);
}
Opm::WellConnections loadCOMPDAT(const std::string& compdat_keyword) {
Opm::EclipseGrid grid(10,10,10);
Opm::TableManager tables;
Opm::Parser parser;
const auto deck = parser.parseString(compdat_keyword);
Opm::FieldPropsManager field_props(deck, Opm::Phases{true, true, true}, grid, Opm::TableManager());
const auto& keyword = deck["COMPDAT"][0];
Opm::WellConnections connections(Opm::Connection::Order::TRACK, 10,10);
Opm::CompletedCells cells(grid);
for (const auto& rec : keyword)
connections.loadCOMPDAT(rec, Opm::ScheduleGrid(grid, field_props, cells), "WELL", {});
Opm::WellConnections
loadCOMPDAT(const std::string& compdat_keyword)
{
Opm::WellConnections connections {
Opm::Connection::Order::TRACK, 10, 10
};
const auto deck = Opm::Parser{}.parseString(compdat_keyword);
const auto loc = Opm::KeywordLocation{};
const Opm::EclipseGrid grid { 10, 10, 10 };
const Opm::FieldPropsManager field_props {
deck, Opm::Phases{true, true, true}, grid, Opm::TableManager{}
};
// Must be mutable.
Opm::CompletedCells completed_cells(grid);
const auto sg = Opm::ScheduleGrid { grid, field_props, completed_cells };
for (const auto& rec : deck["COMPDAT"][0]) {
connections.loadCOMPDAT(rec, sg, "WELL", loc);
}
return connections;
}
}
}
namespace Opm {
@ -94,12 +111,22 @@ BOOST_AUTO_TEST_CASE(CreateWellConnectionsOK) {
BOOST_AUTO_TEST_CASE(AddCompletionSizeCorrect) {
auto dir = Opm::Connection::Direction::Z;
BOOST_AUTO_TEST_CASE(AddCompletionSizeCorrect)
{
const auto dir = Opm::Connection::Direction::Z;
const auto kind = Opm::Connection::CTFKind::DeckValue;
const auto depth = 0.0;
auto ctf_props = Opm::Connection::CTFProperties{};
ctf_props.CF = 99.88;
ctf_props.Kh = 355.113;
ctf_props.rw = 0.25;
const auto completion1 = Opm::Connection { 10,10,10, 100, 1, Opm::Connection::State::OPEN, dir, kind, 0, depth, ctf_props, 0, true };
const auto completion2 = Opm::Connection { 10,10,11, 102, 1, Opm::Connection::State::SHUT, dir, kind, 0, depth, ctf_props, 0, true };
Opm::WellConnections completionSet(Opm::Connection::Order::TRACK, 1,1);
Opm::Connection completion1( 10,10,10, 100, 1, 0.0, Opm::Connection::State::OPEN , 99.88, 355.113, 0.25, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0, dir, kind, 0, true);
Opm::Connection completion2( 10,10,11, 102, 1, 0.0, Opm::Connection::State::SHUT , 99.88, 355.113, 0.25, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0, dir, kind, 0, true);
completionSet.add( completion1 );
BOOST_CHECK_EQUAL( 1U , completionSet.size() );
BOOST_CHECK_MESSAGE( !completionSet.empty(), "Non-empty completion set must not be empty" );
@ -111,11 +138,21 @@ BOOST_AUTO_TEST_CASE(AddCompletionSizeCorrect) {
}
BOOST_AUTO_TEST_CASE(WellConnectionsGetOutOfRangeThrows) {
auto dir = Opm::Connection::Direction::Z;
BOOST_AUTO_TEST_CASE(WellConnectionsGetOutOfRangeThrows)
{
const auto dir = Opm::Connection::Direction::Z;
const auto kind = Opm::Connection::CTFKind::DeckValue;
Opm::Connection completion1( 10,10,10, 100, 1, 0.0, Opm::Connection::State::OPEN , 99.88, 355.113, 0.25, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0, dir, kind, 0,true);
Opm::Connection completion2( 10,10,11, 102, 1, 0.0, Opm::Connection::State::SHUT , 99.88, 355.113, 0.25, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0, dir, kind, 0,true);
const auto depth = 0.0;
auto ctf_props = Opm::Connection::CTFProperties{};
ctf_props.CF = 99.88;
ctf_props.Kh = 355.113;
ctf_props.rw = 0.25;
const auto completion1 = Opm::Connection { 10,10,10, 100, 1, Opm::Connection::State::OPEN, dir, kind, 0, depth, ctf_props, 0, true };
const auto completion2 = Opm::Connection { 10,10,11, 102, 1, Opm::Connection::State::SHUT, dir, kind, 0, depth, ctf_props, 0, true };
Opm::WellConnections completionSet(Opm::Connection::Order::TRACK, 1,1);
completionSet.add( completion1 );
BOOST_CHECK_EQUAL( 1U , completionSet.size() );
@ -148,15 +185,23 @@ BOOST_AUTO_TEST_CASE(Compdat_Direction) {
}
BOOST_AUTO_TEST_CASE(AddCompletionCopy) {
Opm::WellConnections completionSet(Opm::Connection::Order::TRACK, 10,10);
auto dir = Opm::Connection::Direction::Z;
BOOST_AUTO_TEST_CASE(AddCompletionCopy)
{
const auto dir = Opm::Connection::Direction::Z;
const auto kind = Opm::Connection::CTFKind::DeckValue;
const auto depth = 0.0;
Opm::Connection completion1( 10,10,10, 100, 1, 0.0, Opm::Connection::State::OPEN , 99.88, 355.113, 0.25, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0, dir, kind, 0, true);
Opm::Connection completion2( 10,10,11, 101, 1, 0.0, Opm::Connection::State::SHUT , 99.88, 355.113, 0.25, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0, dir, kind, 0, true);
Opm::Connection completion3( 10,10,12, 102, 1, 0.0, Opm::Connection::State::SHUT , 99.88, 355.113, 0.25, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0, dir, kind, 0, true);
auto ctf_props = Opm::Connection::CTFProperties{};
ctf_props.CF = 99.88;
ctf_props.Kh = 355.113;
ctf_props.rw = 0.25;
const auto completion1 = Opm::Connection { 10,10,10, 100, 1, Opm::Connection::State::OPEN, dir, kind, 0, depth, ctf_props, 0, true };
const auto completion2 = Opm::Connection { 10,10,11, 101, 1, Opm::Connection::State::SHUT, dir, kind, 0, depth, ctf_props, 0, true };
const auto completion3 = Opm::Connection { 10,10,12, 102, 1, Opm::Connection::State::SHUT, dir, kind, 0, depth, ctf_props, 0, true };
Opm::WellConnections completionSet(Opm::Connection::Order::TRACK, 10,10);
completionSet.add( completion1 );
completionSet.add( completion2 );
completionSet.add( completion3 );
@ -171,31 +216,43 @@ BOOST_AUTO_TEST_CASE(AddCompletionCopy) {
}
BOOST_AUTO_TEST_CASE(ActiveCompletions) {
Opm::EclipseGrid grid(10,20,20);
auto dir = Opm::Connection::Direction::Z;
const auto kind = Opm::Connection::CTFKind::Defaulted;
Opm::WellConnections completions(Opm::Connection::Order::TRACK, 10,10);
Opm::Connection completion1( 0,0,0, grid.getGlobalIndex(0,0,0), 1, 0.0, Opm::Connection::State::OPEN , 99.88, 355.113, 0.25, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0, dir, kind, 0, true);
Opm::Connection completion2( 0,0,1, grid.getGlobalIndex(0,0,1), 1, 0.0, Opm::Connection::State::SHUT , 99.88, 355.113, 0.25, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0, dir, kind, 0, true);
Opm::Connection completion3( 0,0,2, grid.getGlobalIndex(0,0,2), 1, 0.0, Opm::Connection::State::SHUT , 99.88, 355.113, 0.25, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0, dir, kind, 0, true);
BOOST_AUTO_TEST_CASE(ActiveCompletions)
{
const auto dir = Opm::Connection::Direction::Z;
const auto kind = Opm::Connection::CTFKind::DeckValue;
const auto depth = 0.0;
auto ctf_props = Opm::Connection::CTFProperties{};
ctf_props.CF = 99.88;
ctf_props.Kh = 355.113;
ctf_props.rw = 0.25;
Opm::EclipseGrid grid { 10, 20, 20 };
const auto completion1 = Opm::Connection { 0,0,0, grid.getGlobalIndex(0,0,0), 1, Opm::Connection::State::OPEN, dir, kind, 0, depth, ctf_props, 0, true };
const auto completion2 = Opm::Connection { 0,0,1, grid.getGlobalIndex(0,0,1), 1, Opm::Connection::State::SHUT, dir, kind, 0, depth, ctf_props, 0, true };
const auto completion3 = Opm::Connection { 0,0,2, grid.getGlobalIndex(0,0,2), 1, Opm::Connection::State::SHUT, dir, kind, 0, depth, ctf_props, 0, true };
Opm::WellConnections completions(Opm::Connection::Order::TRACK, 10,10);
completions.add( completion1 );
completions.add( completion2 );
completions.add( completion3 );
std::vector<int> actnum(grid.getCartesianSize(), 1);
actnum[0] = 0;
grid.resetACTNUM( actnum);
grid.resetACTNUM(actnum);
Opm::WellConnections active_completions(completions, grid);
const Opm::WellConnections active_completions(completions, grid);
BOOST_CHECK_EQUAL( active_completions.size() , 2U);
BOOST_CHECK_EQUAL( completion2, active_completions.get(0));
BOOST_CHECK_EQUAL( completion3, active_completions.get(1));
}
BOOST_AUTO_TEST_CASE(loadCOMPDATTEST) {
Opm::UnitSystem units(Opm::UnitSystem::UnitType::UNIT_TYPE_METRIC); // Unit system used in deck FIRST_SIM.DATA.
BOOST_AUTO_TEST_CASE(loadCOMPDATTEST)
{
const Opm::UnitSystem units(Opm::UnitSystem::UnitType::UNIT_TYPE_METRIC); // Unit system used in deck FIRST_SIM.DATA.
{
const std::string deck = R"(GRID
@ -212,7 +269,8 @@ COMPDAT
-- CF Diam Kh Skin Df
'WELL' 1 1 1 1 'OPEN' 1* 1.168 0.311 107.872 1* 1* 'Z' 21.925 /
/)";
Opm::WellConnections connections = loadCOMPDAT(deck);
const Opm::WellConnections connections = loadCOMPDAT(deck);
const auto& conn0 = connections[0];
BOOST_CHECK_EQUAL(conn0.CF(), units.to_si(Opm::UnitSystem::measure::transmissibility, 1.168));
BOOST_CHECK_EQUAL(conn0.Kh(), units.to_si(Opm::UnitSystem::measure::effective_Kh, 107.872));
@ -236,7 +294,8 @@ COMPDAT
-- CF Diam Kh Skin Df
'WELL' 1 1 1 1 'OPEN' 1* 1.168 0.311 0 1* 1* 'Z' 21.925 /
/)";
Opm::WellConnections connections = loadCOMPDAT(deck);
const Opm::WellConnections connections = loadCOMPDAT(deck);
const auto& conn0 = connections[0];
BOOST_CHECK_EQUAL(conn0.CF(), units.to_si(Opm::UnitSystem::measure::transmissibility, 1.168));
BOOST_CHECK_EQUAL(conn0.Kh(), units.to_si(Opm::UnitSystem::measure::effective_Kh, 0.10 * 1.0));
@ -460,20 +519,16 @@ END
}
// Reset CF -- simulating COMPDAT record (inactive cell)
auto ctf_props = Opm::Connection::CTFProperties{};
ctf_props.CF = 50.0*cp_rm3_per_db();
ctf_props.Kh = 0.123;
ctf_props.rw = 0.234;
ctf_props.r0 = 0.157;
connP.addConnection(9, 9, 1, // 10, 10, 2
199,
2015.0,
Opm::Connection::State::OPEN,
50.0*cp_rm3_per_db(),
0.123,
0.234,
0.157,
0.0,
0.0,
0.0,
0.0,
0.0,
1);
2015.0, ctf_props, 1);
BOOST_REQUIRE_EQUAL(connP.size(), std::size_t{3});
@ -507,18 +562,8 @@ END
// Reset CF -- simulating COMPDAT record (active cell)
connP.addConnection(8, 9, 1, // 10, 10, 2
198,
2015.0,
Opm::Connection::State::OPEN,
50.0*cp_rm3_per_db(),
0.123,
0.234,
0.157,
0.0,
0.0,
0.0,
0.0,
0.0,
1);
2015.0, ctf_props, 1);
BOOST_REQUIRE_EQUAL(connP.size(), std::size_t{4});

View File

@ -55,20 +55,32 @@
#include <stdexcept>
#include <string>
BOOST_AUTO_TEST_CASE(AICDWellTest) {
auto dir = Opm::Connection::Direction::Z;
BOOST_AUTO_TEST_CASE(AICDWellTest)
{
const auto dir_z = Opm::Connection::Direction::Z;
const auto dir_x = Opm::Connection::Direction::X;
const auto kind = Opm::Connection::CTFKind::DeckValue;
Opm::WellConnections connection_set(Opm::Connection::Order::TRACK, 10,10);
Opm::EclipseGrid grid(20,20,20, 1., 1., 25.0, 2500.0);
connection_set.add(Opm::Connection( 19, 0, 0,grid.getGlobalIndex(19,0,0), 1, 0.0, Opm::Connection::State::OPEN , 200, 17.29, 0.25, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0, dir, kind, 0, true) );
connection_set.add(Opm::Connection( 19, 0, 1,grid.getGlobalIndex(19,0,1), 1, 0.0, Opm::Connection::State::OPEN , 200, 17.29, 0.25, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0, dir, kind, 0, true) );
connection_set.add(Opm::Connection( 19, 0, 2,grid.getGlobalIndex(19,0,2), 1, 0.0, Opm::Connection::State::OPEN , 200, 17.29, 0.25, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0, dir, kind, 0, true) );
connection_set.add(Opm::Connection( 18, 0, 1,grid.getGlobalIndex(18,0,1), 1, 0.0, Opm::Connection::State::OPEN , 200, 17.29, 0.25, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0, Opm::Connection::Direction::X, kind, 0, true) );
connection_set.add(Opm::Connection( 17, 0, 1,grid.getGlobalIndex(17,0,1), 1, 0.0, Opm::Connection::State::OPEN , 200, 17.29, 0.25, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0, Opm::Connection::Direction::X, kind, 0, true) );
connection_set.add(Opm::Connection( 16, 0, 1,grid.getGlobalIndex(16,0,1), 1, 0.0, Opm::Connection::State::OPEN , 200, 17.29, 0.25, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0, Opm::Connection::Direction::X, kind, 0, true) );
connection_set.add(Opm::Connection( 15, 0, 1,grid.getGlobalIndex(15,0,1), 1, 0.0, Opm::Connection::State::OPEN , 200, 17.29, 0.25, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0, Opm::Connection::Direction::X, kind, 0, true) );
const Opm::EclipseGrid grid { 20,20,20, 1.0, 1.0, 25.0, 2500.0 };
const auto depth = 0.0;
const auto state = Opm::Connection::State::OPEN;
auto ctf_props = Opm::Connection::CTFProperties{};
ctf_props.CF = 200.0;
ctf_props.Kh = 17.29;
ctf_props.rw = 0.25;
Opm::WellConnections connection_set(Opm::Connection::Order::TRACK, 10,10);
connection_set.add({ 19, 0, 0, grid.getGlobalIndex(19,0,0), 1, state, dir_z, kind, 0, depth, ctf_props, 0, true });
connection_set.add({ 19, 0, 1, grid.getGlobalIndex(19,0,1), 1, state, dir_z, kind, 0, depth, ctf_props, 0, true });
connection_set.add({ 19, 0, 2, grid.getGlobalIndex(19,0,2), 1, state, dir_z, kind, 0, depth, ctf_props, 0, true });
connection_set.add({ 18, 0, 1, grid.getGlobalIndex(18,0,1), 1, state, dir_x, kind, 0, depth, ctf_props, 0, true });
connection_set.add({ 17, 0, 1, grid.getGlobalIndex(17,0,1), 1, state, dir_x, kind, 0, depth, ctf_props, 0, true });
connection_set.add({ 16, 0, 1, grid.getGlobalIndex(16,0,1), 1, state, dir_x, kind, 0, depth, ctf_props, 0, true });
connection_set.add({ 15, 0, 1, grid.getGlobalIndex(15,0,1), 1, state, dir_x, kind, 0, depth, ctf_props, 0, true });
BOOST_CHECK_EQUAL( 7U , connection_set.size() );
@ -212,23 +224,33 @@ WSEGAICD
const double center_depth_connection7 = connection7.depth();
BOOST_CHECK_EQUAL(segment_number_connection7, 8);
BOOST_CHECK_EQUAL(center_depth_connection7, 2534.5);
}
BOOST_AUTO_TEST_CASE(MultisegmentWellTest) {
auto dir = Opm::Connection::Direction::Z;
BOOST_AUTO_TEST_CASE(MultisegmentWellTest)
{
const auto dir_z = Opm::Connection::Direction::Z;
const auto dir_x = Opm::Connection::Direction::X;
const auto kind = Opm::Connection::CTFKind::DeckValue;
Opm::WellConnections connection_set(Opm::Connection::Order::TRACK, 10,10);
Opm::EclipseGrid grid(20,20,20, 1., 1., 25.0, 2500.0);
connection_set.add(Opm::Connection( 19, 0, 0,grid.getGlobalIndex(19,0,0), 1, 0.0, Opm::Connection::State::OPEN , 200, 17.29, 0.25, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0, dir, kind, 0, true) );
connection_set.add(Opm::Connection( 19, 0, 1,grid.getGlobalIndex(19,0,1), 1, 0.0, Opm::Connection::State::OPEN , 200, 17.29, 0.25, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0, dir, kind, 0, true) );
connection_set.add(Opm::Connection( 19, 0, 2,grid.getGlobalIndex(19,0,2), 1, 0.0, Opm::Connection::State::OPEN , 200, 17.29, 0.25, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0, dir, kind, 0, true) );
const Opm::EclipseGrid grid { 20,20,20, 1.0, 1.0, 25.0, 2500.0 };
connection_set.add(Opm::Connection( 18, 0, 1,grid.getGlobalIndex(18,0,1), 1, 0.0, Opm::Connection::State::OPEN , 200, 17.29, 0.25, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0, Opm::Connection::Direction::X, kind, 0, true) );
connection_set.add(Opm::Connection( 17, 0, 1,grid.getGlobalIndex(17,0,1), 1, 0.0, Opm::Connection::State::OPEN , 200, 17.29, 0.25, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0, Opm::Connection::Direction::X, kind, 0, true) );
connection_set.add(Opm::Connection( 16, 0, 1,grid.getGlobalIndex(16,0,1), 1, 0.0, Opm::Connection::State::OPEN , 200, 17.29, 0.25, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0, Opm::Connection::Direction::X, kind, 0, true) );
connection_set.add(Opm::Connection( 15, 0, 1,grid.getGlobalIndex(15,0,1), 1, 0.0, Opm::Connection::State::OPEN , 200, 17.29, 0.25, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0, Opm::Connection::Direction::X, kind, 0, true) );
const auto depth = 0.0;
const auto state = Opm::Connection::State::OPEN;
auto ctf_props = Opm::Connection::CTFProperties{};
ctf_props.CF = 200.0;
ctf_props.Kh = 17.29;
ctf_props.rw = 0.25;
Opm::WellConnections connection_set(Opm::Connection::Order::TRACK, 10,10);
connection_set.add({ 19, 0, 0, grid.getGlobalIndex(19,0,0), 1, state, dir_z, kind, 0, depth, ctf_props, 0, true });
connection_set.add({ 19, 0, 1, grid.getGlobalIndex(19,0,1), 1, state, dir_z, kind, 0, depth, ctf_props, 0, true });
connection_set.add({ 19, 0, 2, grid.getGlobalIndex(19,0,2), 1, state, dir_z, kind, 0, depth, ctf_props, 0, true });
connection_set.add({ 18, 0, 1, grid.getGlobalIndex(18,0,1), 1, state, dir_x, kind, 0, depth, ctf_props, 0, true });
connection_set.add({ 17, 0, 1, grid.getGlobalIndex(17,0,1), 1, state, dir_x, kind, 0, depth, ctf_props, 0, true });
connection_set.add({ 16, 0, 1, grid.getGlobalIndex(16,0,1), 1, state, dir_x, kind, 0, depth, ctf_props, 0, true });
connection_set.add({ 15, 0, 1, grid.getGlobalIndex(15,0,1), 1, state, dir_x, kind, 0, depth, ctf_props, 0, true });
BOOST_CHECK_EQUAL( 7U , connection_set.size() );
@ -383,19 +405,32 @@ WSEGSICD
}
BOOST_AUTO_TEST_CASE(WrongDistanceCOMPSEGS) {
auto dir = Opm::Connection::Direction::Z;
BOOST_AUTO_TEST_CASE(WrongDistanceCOMPSEGS)
{
const auto dir_z = Opm::Connection::Direction::Z;
const auto dir_x = Opm::Connection::Direction::X;
const auto kind = Opm::Connection::CTFKind::DeckValue;
Opm::WellConnections connection_set(Opm::Connection::Order::TRACK, 10,10);
Opm::EclipseGrid grid(20,20,20, 1., 1., 25., 2500.);
connection_set.add(Opm::Connection( 19, 0, 0, grid.getGlobalIndex(19,0,0),1, 0.0, Opm::Connection::State::OPEN , 200, 17.29, 0.25, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0, dir, kind, 0, true) );
connection_set.add(Opm::Connection( 19, 0, 1, grid.getGlobalIndex(19,0,1),1, 0.0, Opm::Connection::State::OPEN , 200, 17.29, 0.25, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0, dir, kind, 0, true) );
connection_set.add(Opm::Connection( 19, 0, 2, grid.getGlobalIndex(19,0,2),1, 0.0, Opm::Connection::State::OPEN , 200, 17.29, 0.25, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0, dir, kind, 0, true) );
connection_set.add(Opm::Connection( 18, 0, 1, grid.getGlobalIndex(18,0,1),1, 0.0, Opm::Connection::State::OPEN , 200, 17.29, 0.25, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0, Opm::Connection::Direction::X, kind, 0, true) );
connection_set.add(Opm::Connection( 17, 0, 1, grid.getGlobalIndex(17,0,1),1, 0.0, Opm::Connection::State::OPEN , 200, 17.29, 0.25, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0, Opm::Connection::Direction::X, kind, 0, true) );
connection_set.add(Opm::Connection( 16, 0, 1, grid.getGlobalIndex(16,0,1),1, 0.0, Opm::Connection::State::OPEN , 200, 17.29, 0.25, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0, Opm::Connection::Direction::X, kind, 0, true) );
connection_set.add(Opm::Connection( 15, 0, 1, grid.getGlobalIndex(15,0,1),1, 0.0, Opm::Connection::State::OPEN , 200, 17.29, 0.25, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0, Opm::Connection::Direction::X, kind, 0, true) );
const Opm::EclipseGrid grid { 20,20,20, 1.0, 1.0, 25., 2500.0 };
const auto depth = 0.0;
const auto state = Opm::Connection::State::OPEN;
auto ctf_props = Opm::Connection::CTFProperties{};
ctf_props.CF = 200.0;
ctf_props.Kh = 17.29;
ctf_props.rw = 0.25;
Opm::WellConnections connection_set(Opm::Connection::Order::TRACK, 10,10);
connection_set.add({ 19, 0, 0, grid.getGlobalIndex(19,0,0), 1, state, dir_z, kind, 0, depth, ctf_props, 0, true });
connection_set.add({ 19, 0, 1, grid.getGlobalIndex(19,0,1), 1, state, dir_z, kind, 0, depth, ctf_props, 0, true });
connection_set.add({ 19, 0, 2, grid.getGlobalIndex(19,0,2), 1, state, dir_z, kind, 0, depth, ctf_props, 0, true });
connection_set.add({ 18, 0, 1, grid.getGlobalIndex(18,0,1), 1, state, dir_x, kind, 0, depth, ctf_props, 0, true });
connection_set.add({ 17, 0, 1, grid.getGlobalIndex(17,0,1), 1, state, dir_x, kind, 0, depth, ctf_props, 0, true });
connection_set.add({ 16, 0, 1, grid.getGlobalIndex(16,0,1), 1, state, dir_x, kind, 0, depth, ctf_props, 0, true });
connection_set.add({ 15, 0, 1, grid.getGlobalIndex(15,0,1), 1, state, dir_x, kind, 0, depth, ctf_props, 0, true });
BOOST_CHECK_EQUAL( 7U , connection_set.size() );
@ -452,19 +487,32 @@ BOOST_AUTO_TEST_CASE(WrongDistanceCOMPSEGS) {
BOOST_CHECK_NO_THROW(Opm::Compsegs::processCOMPSEGS(compsegs, connection_set, segment_set, Opm::ScheduleGrid(grid, fp, cells), parseContext, errorGuard));
}
BOOST_AUTO_TEST_CASE(NegativeDepthCOMPSEGS) {
auto dir = Opm::Connection::Direction::Z;
BOOST_AUTO_TEST_CASE(NegativeDepthCOMPSEGS)
{
const auto dir_z = Opm::Connection::Direction::Z;
const auto dir_x = Opm::Connection::Direction::X;
const auto kind = Opm::Connection::CTFKind::DeckValue;
Opm::WellConnections connection_set(Opm::Connection::Order::TRACK, 10,10);
Opm::EclipseGrid grid(20,20,20, 1., 1., 25., 2500.);
connection_set.add(Opm::Connection( 19, 0, 0, grid.getGlobalIndex(19,0,0),1, 0.0, Opm::Connection::State::OPEN , 200, 17.29, 0.25, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0, dir, kind, 0, true) );
connection_set.add(Opm::Connection( 19, 0, 1, grid.getGlobalIndex(19,0,1),1, 0.0, Opm::Connection::State::OPEN , 200, 17.29, 0.25, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0, dir, kind, 0, true) );
connection_set.add(Opm::Connection( 19, 0, 2, grid.getGlobalIndex(19,0,2),1, 0.0, Opm::Connection::State::OPEN , 200, 17.29, 0.25, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0, dir, kind, 0, true) );
connection_set.add(Opm::Connection( 18, 0, 1, grid.getGlobalIndex(18,0,1),1, 0.0, Opm::Connection::State::OPEN , 200, 17.29, 0.25, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0, Opm::Connection::Direction::X, kind, 0, true) );
connection_set.add(Opm::Connection( 17, 0, 1, grid.getGlobalIndex(17,0,1),1, 0.0, Opm::Connection::State::OPEN , 200, 17.29, 0.25, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0, Opm::Connection::Direction::X, kind, 0, true) );
connection_set.add(Opm::Connection( 16, 0, 1, grid.getGlobalIndex(16,0,1),1, 0.0, Opm::Connection::State::OPEN , 200, 17.29, 0.25, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0, Opm::Connection::Direction::X, kind, 0, true) );
connection_set.add(Opm::Connection( 15, 0, 1, grid.getGlobalIndex(15,0,1),1, 0.0, Opm::Connection::State::OPEN , 200, 17.29, 0.25, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0, Opm::Connection::Direction::X, kind, 0, true) );
const Opm::EclipseGrid grid { 20,20,20, 1.0, 1.0, 25.0, 2500.0 };
const auto depth = 0.0;
const auto state = Opm::Connection::State::OPEN;
auto ctf_props = Opm::Connection::CTFProperties{};
ctf_props.CF = 200.0;
ctf_props.Kh = 17.29;
ctf_props.rw = 0.25;
Opm::WellConnections connection_set(Opm::Connection::Order::TRACK, 10,10);
connection_set.add({ 19, 0, 0, grid.getGlobalIndex(19,0,0), 1, state, dir_z, kind, 0, depth, ctf_props, 0, true });
connection_set.add({ 19, 0, 1, grid.getGlobalIndex(19,0,1), 1, state, dir_z, kind, 0, depth, ctf_props, 0, true });
connection_set.add({ 19, 0, 2, grid.getGlobalIndex(19,0,2), 1, state, dir_z, kind, 0, depth, ctf_props, 0, true });
connection_set.add({ 18, 0, 1, grid.getGlobalIndex(18,0,1), 1, state, dir_x, kind, 0, depth, ctf_props, 0, true });
connection_set.add({ 17, 0, 1, grid.getGlobalIndex(17,0,1), 1, state, dir_x, kind, 0, depth, ctf_props, 0, true });
connection_set.add({ 16, 0, 1, grid.getGlobalIndex(16,0,1), 1, state, dir_x, kind, 0, depth, ctf_props, 0, true });
connection_set.add({ 15, 0, 1, grid.getGlobalIndex(15,0,1), 1, state, dir_x, kind, 0, depth, ctf_props, 0, true });
BOOST_CHECK_EQUAL( 7U , connection_set.size() );
@ -521,19 +569,31 @@ BOOST_AUTO_TEST_CASE(NegativeDepthCOMPSEGS) {
BOOST_CHECK_NO_THROW( Opm::Compsegs::processCOMPSEGS(compsegs, connection_set, segment_set, Opm::ScheduleGrid(grid, fp, cells), parseContext, errorGuard) );
}
BOOST_AUTO_TEST_CASE(testwsegvalv) {
auto dir = Opm::Connection::Direction::Z;
BOOST_AUTO_TEST_CASE(testwsegvalv)
{
const auto dir_z = Opm::Connection::Direction::Z;
const auto dir_x = Opm::Connection::Direction::X;
const auto kind = Opm::Connection::CTFKind::DeckValue;
Opm::WellConnections connection_set(Opm::Connection::Order::TRACK, 10,10);
Opm::EclipseGrid grid(20,20,20, 1., 1., 25., 2500.);
connection_set.add(Opm::Connection( 19, 0, 0, grid.getGlobalIndex(19,0,0), 1, 0.0, Opm::Connection::State::OPEN , 200, 17.29, 0.25, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0, dir, kind, 0, true) );
connection_set.add(Opm::Connection( 19, 0, 1, grid.getGlobalIndex(19,0,1), 1, 0.0, Opm::Connection::State::OPEN , 200, 17.29, 0.25, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0, dir, kind, 0, true) );
connection_set.add(Opm::Connection( 19, 0, 2, grid.getGlobalIndex(19,0,2), 1, 0.0, Opm::Connection::State::OPEN , 200, 17.29, 0.25, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0, dir, kind, 0, true) );
const Opm::EclipseGrid grid { 20,20,20, 1.0, 1.0, 25.0, 2500.0 };
connection_set.add(Opm::Connection( 18, 0, 1, grid.getGlobalIndex(18,0,1), 1, 0.0, Opm::Connection::State::OPEN , 200, 17.29, 0.25, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0, Opm::Connection::Direction::X, kind, 0, true) );
connection_set.add(Opm::Connection( 17, 0, 1, grid.getGlobalIndex(17,0,1), 1, 0.0, Opm::Connection::State::OPEN , 200, 17.29, 0.25, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0, Opm::Connection::Direction::X, kind, 0, true) );
connection_set.add(Opm::Connection( 16, 0, 1, grid.getGlobalIndex(16,0,1), 1, 0.0, Opm::Connection::State::OPEN , 200, 17.29, 0.25, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0, Opm::Connection::Direction::X, kind, 0, true) );
connection_set.add(Opm::Connection( 15, 0, 1, grid.getGlobalIndex(15,0,1), 1, 0.0, Opm::Connection::State::OPEN , 200, 17.29, 0.25, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0, Opm::Connection::Direction::X, kind, 0, true) );
const auto depth = 0.0;
const auto state = Opm::Connection::State::OPEN;
auto ctf_props = Opm::Connection::CTFProperties{};
ctf_props.CF = 200.0;
ctf_props.Kh = 17.29;
ctf_props.rw = 0.25;
Opm::WellConnections connection_set(Opm::Connection::Order::TRACK, 10,10);
connection_set.add({ 19, 0, 0, grid.getGlobalIndex(19,0,0), 1, state, dir_z, kind, 0, depth, ctf_props, 0, true });
connection_set.add({ 19, 0, 1, grid.getGlobalIndex(19,0,1), 1, state, dir_z, kind, 0, depth, ctf_props, 0, true });
connection_set.add({ 19, 0, 2, grid.getGlobalIndex(19,0,2), 1, state, dir_z, kind, 0, depth, ctf_props, 0, true });
connection_set.add({ 18, 0, 1, grid.getGlobalIndex(18,0,1), 1, state, dir_x, kind, 0, depth, ctf_props, 0, true });
connection_set.add({ 17, 0, 1, grid.getGlobalIndex(17,0,1), 1, state, dir_x, kind, 0, depth, ctf_props, 0, true });
connection_set.add({ 16, 0, 1, grid.getGlobalIndex(16,0,1), 1, state, dir_x, kind, 0, depth, ctf_props, 0, true });
connection_set.add({ 15, 0, 1, grid.getGlobalIndex(15,0,1), 1, state, dir_x, kind, 0, depth, ctf_props, 0, true });
BOOST_CHECK_EQUAL( 7U , connection_set.size() );

File diff suppressed because it is too large Load Diff

View File

@ -22,192 +22,219 @@
#include <boost/test/unit_test.hpp>
#include <opm/input/eclipse/Python/Python.hpp>
#include <opm/input/eclipse/EclipseState/Grid/FieldPropsManager.hpp>
#include <opm/input/eclipse/EclipseState/Grid/EclipseGrid.hpp>
#include <opm/input/eclipse/EclipseState/Runspec.hpp>
#include <opm/input/eclipse/EclipseState/Tables/TableManager.hpp>
#include <opm/input/eclipse/Schedule/Schedule.hpp>
#include <opm/input/eclipse/Schedule/Well/Well.hpp>
#include <opm/input/eclipse/Deck/Deck.hpp>
#include <opm/input/eclipse/Deck/DeckItem.hpp>
#include <opm/input/eclipse/Deck/DeckKeyword.hpp>
#include <opm/input/eclipse/Deck/DeckRecord.hpp>
#include <opm/input/eclipse/Parser/Parser.hpp>
#include <opm/input/eclipse/Parser/ParseContext.hpp>
using namespace Opm;
static Deck createDeckWithOutSolvent() {
Opm::Parser parser;
std::string input =
"GRID\n"
"PERMX\n"
" 1000*0.25/\n"
"COPY\n"
" PERMX PERMY /\n"
" PERMX PERMZ /\n"
"/\n"
"SCHEDULE\n"
"WELSPECS\n"
" 'W_1' 'OP' 2 2 1* \'OIL\' 7* / \n"
"/\n"
"COMPDAT\n"
" 'W_1' 2* 1 1 'OPEN' / \n"
"/\n"
"WCONINJE\n"
" 'W_1' 'WATER' 'OPEN' 'BHP' 1 2 3/\n/\n";
namespace {
return parser.parseString(input);
Deck createDeckWithOutSolvent()
{
return Parser{}.parseString(R"(
GRID
PERMX
1000*0.25/
COPY
PERMX PERMY /
PERMX PERMZ /
/
PORO
1000*0.3 /
SCHEDULE
WELSPECS
'W_1' 'OP' 2 2 1* 'OIL' 7* /
/
COMPDAT
'W_1' 2* 1 1 'OPEN' /
/
WCONINJE
'W_1' 'WATER' 'OPEN' 'BHP' 1 2 3/
/
END
)");
}
static Deck createDeckWithGasInjector() {
Opm::Parser parser;
std::string input =
"GRID\n"
"PERMX\n"
" 1000*0.25/\n"
"COPY\n"
" PERMX PERMY /\n"
" PERMX PERMZ /\n"
"/\n"
"SCHEDULE\n"
"WELSPECS\n"
" 'W_1' 'OP' 1 1 1* \'GAS\' 7* / \n"
"/\n"
"COMPDAT\n"
" 'W_1' 2* 1 1 'OPEN' / \n"
"/\n"
"WCONINJE\n"
" 'W_1' 'GAS' 'OPEN' 'BHP' 1 2 3/\n/\n"
"WSOLVENT\n"
" 'W_1' 1 / \n "
"/\n";
Deck createDeckWithGasInjector()
{
return Parser{}.parseString(R"(
GRID
PERMX
1000*0.25/
COPY
PERMX PERMY /
PERMX PERMZ /
/
PORO
1000*0.3 /
return parser.parseString(input);
SCHEDULE
WELSPECS
'W_1' 'OP' 1 1 1* 'GAS' 7* /
/
COMPDAT
'W_1' 2* 1 1 'OPEN' /
/
WCONINJE
'W_1' 'GAS' 'OPEN' 'BHP' 1 2 3/
/
WSOLVENT
'W_1' 1 /
/
END
)");
}
static Deck createDeckWithDynamicWSOLVENT() {
Opm::Parser parser;
std::string input =
"START -- 0 \n"
"1 JAN 2000 / \n"
"GRID\n"
"PERMX\n"
" 1000*0.25/\n"
"COPY\n"
" PERMX PERMY /\n"
" PERMX PERMZ /\n"
"/\n"
"SCHEDULE\n"
"WELSPECS\n"
" 'W_1' 'OP' 1 1 1* \'GAS\' 7* / \n"
"/\n"
"COMPDAT\n"
" 'W_1' 2* 1 1 'OPEN' / \n"
"/\n"
"WCONINJE\n"
" 'W_1' 'GAS' 'OPEN' 'BHP' 1 2 3/\n/\n"
"DATES -- 2\n"
" 1 MAY 2000 / \n"
"/\n"
"WSOLVENT\n"
" 'W_1' 1 / \n "
"/\n"
"DATES -- 3,4\n"
" 1 JUL 2000 / \n"
" 1 AUG 2000 / \n"
"/\n"
"WSOLVENT\n"
" 'W_1' 0 / \n "
"/\n";
Deck createDeckWithDynamicWSOLVENT()
{
return Parser{}.parseString(R"(
START -- 0
1 JAN 2000 /
GRID
PERMX
1000*0.25/
COPY
PERMX PERMY /
PERMX PERMZ /
/
PORO
1000*0.3 /
return parser.parseString(input);
SCHEDULE
WELSPECS
'W_1' 'OP' 1 1 1* 'GAS' 7* /
/
COMPDAT
'W_1' 2* 1 1 'OPEN' /
/
WCONINJE
'W_1' 'GAS' 'OPEN' 'BHP' 1 2 3/
/
DATES -- 2
1 MAY 2000 /
/
WSOLVENT
'W_1' 1 /
/
DATES -- 3,4
1 JUL 2000 /
1 AUG 2000 /
/
WSOLVENT
'W_1' 0 /
/
END
)");
}
static Deck createDeckWithOilInjector() {
Opm::Parser parser;
std::string input =
"GRID\n"
"PERMX\n"
" 1000*0.25/\n"
"COPY\n"
" PERMX PERMY /\n"
" PERMX PERMZ /\n"
"/\n"
"SCHEDULE\n"
"WELSPECS\n"
" 'W_1' 'OP' 2 2 1* \'OIL\' 7* / \n"
"/\n"
"COMPDAT\n"
" 'W_1' 2* 1 1 'OPEN' / \n"
"/\n"
"WCONINJE\n"
" 'W_1' 'OIL' 'OPEN' 'BHP' 1 2 3/\n/\n"
"WSOLVENT\n"
" 'W_1' 1 / \n "
"/\n";
return parser.parseString(input);
Deck createDeckWithOilInjector()
{
return Parser{}.parseString(R"(
GRID
PERMX
1000*0.25/
COPY
PERMX PERMY /
PERMX PERMZ /
/
SCHEDULE
WELSPECS
'W_1' 'OP' 2 2 1* 'OIL' 7* /
/
COMPDAT
'W_1' 2* 1 1 'OPEN' /
/
WCONINJE
'W_1' 'OIL' 'OPEN' 'BHP' 1 2 3/
/
WSOLVENT
'W_1' 1 /
/
END
)");
}
static Deck createDeckWithWaterInjector() {
Opm::Parser parser;
std::string input =
"GRID\n"
"PERMX\n"
" 1000*0.25/\n"
"COPY\n"
" PERMX PERMY /\n"
" PERMX PERMZ /\n"
"/\n"
"SCHEDULE\n"
"WELSPECS\n"
" 'W_1' 'OP' 2 2 1* \'OIL\' 7* / \n"
"/\n"
"COMPDAT\n"
" 'W_1' 2* 1 1 'OPEN' / \n"
"/\n"
"WCONINJE\n"
" 'W_1' 'WATER' 'OPEN' 'BHP' 1 2 3/\n/\n"
"WSOLVENT\n"
" 'W_1' 1 / \n "
"/\n";
return parser.parseString(input);
Deck createDeckWithWaterInjector()
{
return Parser{}.parseString(R"(
GRID
PERMX
1000*0.25/
COPY
PERMX PERMY /
PERMX PERMZ /
/
SCHEDULE
WELSPECS
'W_1' 'OP' 2 2 1* \'OIL\' 7* /
/
COMPDAT
'W_1' 2* 1 1 'OPEN' /
/
WCONINJE
'W_1' 'WATER' 'OPEN' 'BHP' 1 2 3/
/
WSOLVENT
'W_1' 1 /
/
END
)");
}
BOOST_AUTO_TEST_CASE(TestNoSolvent) {
auto deck = createDeckWithOutSolvent();
auto python = std::make_shared<Python>();
EclipseGrid grid(10,10,10);
TableManager table ( deck );
FieldPropsManager fp(deck, Phases{true, true, true}, grid, table);
Runspec runspec(deck);
Schedule schedule(deck, grid , fp, runspec, python);
} // Anonymous namespace
BOOST_AUTO_TEST_CASE(TestNoSolvent)
{
const auto deck = createDeckWithOutSolvent();
const EclipseGrid grid(10,10,10);
const TableManager table (deck);
const FieldPropsManager fp(deck, Phases{true, true, true}, grid, table);
const Runspec runspec(deck);
const Schedule schedule(deck, grid, fp, runspec, std::make_shared<Python>());
BOOST_CHECK(!deck.hasKeyword("WSOLVENT"));
}
BOOST_AUTO_TEST_CASE(TestGasInjector) {
auto deck = createDeckWithGasInjector();
auto python = std::make_shared<Python>();
EclipseGrid grid(10,10,10);
TableManager table ( deck );
FieldPropsManager fp(deck, Phases{true, true, true}, grid, table);
Runspec runspec(deck);
Schedule schedule(deck, grid , fp, runspec, python);
const auto deck = createDeckWithGasInjector();
const EclipseGrid grid(10,10,10);
const TableManager table (deck);
const FieldPropsManager fp(deck, Phases{true, true, true}, grid, table);
const Runspec runspec(deck);
const Schedule schedule(deck, grid, fp, runspec, std::make_shared<Python>());
BOOST_CHECK(deck.hasKeyword("WSOLVENT"));
}
BOOST_AUTO_TEST_CASE(TestDynamicWSOLVENT) {
auto deck = createDeckWithDynamicWSOLVENT();
auto python = std::make_shared<Python>();
EclipseGrid grid(10,10,10);
TableManager table ( deck );
FieldPropsManager fp(deck, Phases{true, true, true}, grid, table);
Runspec runspec(deck);
Schedule schedule(deck, grid , fp, runspec, python);
BOOST_AUTO_TEST_CASE(TestDynamicWSOLVENT)
{
const auto deck = createDeckWithDynamicWSOLVENT();
const EclipseGrid grid(10,10,10);
const TableManager table (deck);
const FieldPropsManager fp(deck, Phases{true, true, true}, grid, table);
const Runspec runspec(deck);
const Schedule schedule(deck, grid, fp, runspec, std::make_shared<Python>());
BOOST_CHECK(deck.hasKeyword("WSOLVENT"));
const auto& keyword = deck["WSOLVENT"].back();
BOOST_CHECK_EQUAL(keyword.size(),1U);
const auto& record = keyword.getRecord(0);
const std::string& well_name = record.getItem("WELL").getTrimmedString(0);
BOOST_CHECK_EQUAL(well_name, "W_1");
@ -217,22 +244,24 @@ BOOST_AUTO_TEST_CASE(TestDynamicWSOLVENT) {
BOOST_CHECK_EQUAL(schedule.getWell("W_1", 3).getSolventFraction(),0);
}
BOOST_AUTO_TEST_CASE(TestOilInjector) {
auto deck = createDeckWithOilInjector();
auto python = std::make_shared<Python>();
EclipseGrid grid(10,10,10);
TableManager table ( deck );
FieldPropsManager fp(deck, Phases{true, true, true}, grid, table);
Runspec runspec(deck);
BOOST_CHECK_THROW (Schedule(deck , grid , fp, runspec, python), std::exception);
BOOST_AUTO_TEST_CASE(TestOilInjector)
{
const auto deck = createDeckWithOilInjector();
const EclipseGrid grid(10,10,10);
const TableManager table (deck);
const FieldPropsManager fp(deck, Phases{true, true, true}, grid, table);
const Runspec runspec(deck);
BOOST_CHECK_THROW (Schedule(deck, grid, fp, runspec, std::make_shared<Python>()), std::exception);
}
BOOST_AUTO_TEST_CASE(TestWaterInjector) {
auto deck = createDeckWithWaterInjector();
auto python = std::make_shared<Python>();
EclipseGrid grid(10,10,10);
TableManager table ( deck );
FieldPropsManager fp(deck, Phases{true, true, true}, grid, table);
Runspec runspec(deck);
BOOST_CHECK_THROW (Schedule(deck, grid , fp, runspec, python), std::exception);
BOOST_AUTO_TEST_CASE(TestWaterInjector)
{
const auto deck = createDeckWithWaterInjector();
const EclipseGrid grid(10,10,10);
const TableManager table ( deck );
const FieldPropsManager fp(deck, Phases{true, true, true}, grid, table);
const Runspec runspec(deck);
BOOST_CHECK_THROW (Schedule(deck, grid , fp, runspec, std::make_shared<Python>()), std::exception);
}

View File

@ -22,141 +22,166 @@
#include <boost/test/unit_test.hpp>
#include <opm/common/utility/OpmInputError.hpp>
#include <opm/input/eclipse/Python/Python.hpp>
#include <opm/input/eclipse/EclipseState/Grid/FieldPropsManager.hpp>
#include <opm/input/eclipse/EclipseState/Grid/EclipseGrid.hpp>
#include <opm/input/eclipse/EclipseState/Runspec.hpp>
#include <opm/input/eclipse/EclipseState/Tables/TableManager.hpp>
#include <opm/input/eclipse/Schedule/Schedule.hpp>
#include <opm/input/eclipse/Schedule/Well/Well.hpp>
#include <opm/input/eclipse/Schedule/Well/WellTracerProperties.hpp>
#include <opm/input/eclipse/Deck/Deck.hpp>
#include <opm/input/eclipse/Deck/DeckItem.hpp>
#include <opm/input/eclipse/Deck/DeckKeyword.hpp>
#include <opm/input/eclipse/Deck/DeckRecord.hpp>
#include <opm/input/eclipse/Parser/Parser.hpp>
using namespace Opm;
static Deck createDeckWithOutTracer() {
Opm::Parser parser;
std::string input =
"GRID\n"
"PERMX\n"
" 1000*0.25/\n"
"COPY\n"
" PERMX PERMY /\n"
" PERMX PERMZ /\n"
"/\n"
"SCHEDULE\n"
"WELSPECS\n"
" 'W_1' 'OP' 2 2 1* \'OIL\' 7* / \n"
"/\n"
"COMPDAT\n"
" 'W_1' 2* 1 1 'OPEN' / \n"
"/\n"
"WCONINJE\n"
" 'W_1' 'WATER' 'OPEN' 'BHP' 1 2 3/\n/\n";
namespace {
return parser.parseString(input);
Deck createDeckWithOutTracer()
{
return Parser{}.parseString(R"(
GRID
PERMX
1000*0.25/
COPY
PERMX PERMY /
PERMX PERMZ /
/
PORO
1000*0.3 /
SCHEDULE
WELSPECS
'W_1' 'OP' 2 2 1* 'OIL' 7* /
/
COMPDAT
'W_1' 2* 1 1 'OPEN' /
/
WCONINJE
'W_1' 'WATER' 'OPEN' 'BHP' 1 2 3/
/
END
)");
}
Deck createDeckWithDynamicWTRACER()
{
return Parser{}.parseString(R"(
START -- 0
1 JAN 2000 /
GRID
PERMX
1000*0.25/
COPY
PERMX PERMY /
PERMX PERMZ /
/
PORO
1000*0.3 /
static Deck createDeckWithDynamicWTRACER() {
Opm::Parser parser;
std::string input =
"START -- 0 \n"
"1 JAN 2000 / \n"
"GRID\n"
"PERMX\n"
" 1000*0.25/\n"
"COPY\n"
" PERMX PERMY /\n"
" PERMX PERMZ /\n"
"/\n"
"SCHEDULE\n"
"WELSPECS\n"
" 'W_1' 'OP' 1 1 1* \'GAS\' 7* / \n"
"/\n"
"COMPDAT\n"
" 'W_1' 2* 1 1 'OPEN' / \n"
"/\n"
"WCONINJE\n"
" 'W_1' 'GAS' 'OPEN' 'BHP' 1 2 3/\n/\n"
"DATES -- 1\n"
" 1 MAY 2000 / \n"
"/\n"
"WTRACER\n"
" 'W_1' 'I1' 1 / \n "
" 'W_1' 'I2' 1 / \n "
"/\n"
"DATES -- 2, 3\n"
" 1 JUL 2000 / \n"
" 1 AUG 2000 / \n"
"/\n"
"WTRACER\n"
" 'W_1' 'I1' 0 / \n "
"/\n"
"DATES -- 4\n"
" 1 SEP 2000 / \n"
"/\n";
SCHEDULE
WELSPECS
'W_1' 'OP' 1 1 1* 'GAS' 7* /
/
COMPDAT
'W_1' 2* 1 1 'OPEN' /
/
WCONINJE
'W_1' 'GAS' 'OPEN' 'BHP' 1 2 3/
/
DATES -- 1
1 MAY 2000 /
/
WTRACER
'W_1' 'I1' 1 /
'W_1' 'I2' 1 /
/
DATES -- 2, 3
1 JUL 2000 /
1 AUG 2000 /
/
WTRACER
'W_1' 'I1' 0 /
/
DATES -- 4
1 SEP 2000 /
/
return parser.parseString(input);
END
)");
}
static Deck createDeckWithTracerInProducer() {
Opm::Parser parser;
std::string input =
"START -- 0 \n"
"1 JAN 2000 / \n"
"GRID\n"
"PERMX\n"
" 1000*0.25/\n"
"COPY\n"
" PERMX PERMY /\n"
" PERMX PERMZ /\n"
"/\n"
"SCHEDULE\n"
"WELSPECS\n"
" 'W_1' 'OP' 1 1 1* \'GAS\' 7* / \n"
"/\n"
"COMPDAT\n"
" 'W_1' 2* 1 1 'OPEN' / \n"
"/\n"
"WCONPROD\n"
"'W_1' 'OPEN' 'ORAT' 20000 4* 1000 /\n"
"WTRACER\n"
" 'W_1' 'I1' 1 / \n "
" 'W_1' 'I2' 1 / \n "
"/\n";
Deck createDeckWithTracerInProducer()
{
return Parser{}.parseString(R"(
START -- 0
1 JAN 2000 /
GRID
PERMX
1000*0.25/
COPY
PERMX PERMY /
PERMX PERMZ /
/
PORO
1000*0.3 /
return parser.parseString(input);
SCHEDULE
WELSPECS
'W_1' 'OP' 1 1 1* 'GAS' 7* /
/
COMPDAT
'W_1' 2* 1 1 'OPEN' /
/
WCONPROD
'W_1' 'OPEN' 'ORAT' 20000 4* 1000 /
WTRACER
'W_1' 'I1' 1 /
'W_1' 'I2' 1 /
/
END
)");
}
} // Anonymous namespace
BOOST_AUTO_TEST_CASE(TestNoTracer)
{
const auto deck = createDeckWithOutTracer();
const EclipseGrid grid(10,10,10);
const TableManager table (deck);
const FieldPropsManager fp(deck, Phases{true, true, true}, grid, table);
const Runspec runspec (deck);
const Schedule schedule(deck, grid, fp, runspec, std::make_shared<Python>());
BOOST_AUTO_TEST_CASE(TestNoTracer) {
auto deck = createDeckWithOutTracer();
EclipseGrid grid(10,10,10);
TableManager table ( deck );
FieldPropsManager fp(deck, Phases{true, true, true}, grid, table);
auto python = std::make_shared<Python>();
Runspec runspec ( deck );
Schedule schedule(deck, grid , fp, runspec, python);
BOOST_CHECK(!deck.hasKeyword("WTRACER"));
}
BOOST_AUTO_TEST_CASE(TestDynamicWTRACER) {
auto deck = createDeckWithDynamicWTRACER();
auto python = std::make_shared<Python>();
EclipseGrid grid(10,10,10);
TableManager table ( deck );
FieldPropsManager fp( deck, Phases{true, true, true}, grid, table);
Runspec runspec ( deck );
Schedule schedule(deck, grid , fp, runspec, python);
BOOST_AUTO_TEST_CASE(TestDynamicWTRACER)
{
const auto deck = createDeckWithDynamicWTRACER();
const EclipseGrid grid(10,10,10);
const TableManager table (deck);
const FieldPropsManager fp(deck, Phases{true, true, true}, grid, table);
const Runspec runspec (deck);
const Schedule schedule(deck, grid, fp, runspec, std::make_shared<Python>());
BOOST_CHECK(deck.hasKeyword("WTRACER"));
const auto& keyword = deck["WTRACER"].back();
BOOST_CHECK_EQUAL(keyword.size(),1U);
const auto& record = keyword.getRecord(0);
const std::string& well_name = record.getItem("WELL").getTrimmedString(0);
BOOST_CHECK_EQUAL(well_name, "W_1");
@ -169,13 +194,13 @@ BOOST_AUTO_TEST_CASE(TestDynamicWTRACER) {
}
BOOST_AUTO_TEST_CASE(TestTracerInProducerTHROW) {
auto deck = createDeckWithTracerInProducer();
auto python = std::make_shared<Python>();
EclipseGrid grid(10,10,10);
TableManager table ( deck );
FieldPropsManager fp( deck, Phases{true, true, true}, grid, table);
Runspec runspec ( deck );
BOOST_AUTO_TEST_CASE(TestTracerInProducerTHROW)
{
const auto deck = createDeckWithTracerInProducer();
const EclipseGrid grid(10,10,10);
const TableManager table (deck);
const FieldPropsManager fp(deck, Phases{true, true, true}, grid, table);
const Runspec runspec (deck);
BOOST_CHECK_THROW(Schedule(deck, grid, fp, runspec, python), OpmInputError);
BOOST_CHECK_THROW(Schedule(deck, grid, fp, runspec, std::make_shared<Python>()), OpmInputError);
}

View File

@ -518,34 +518,39 @@ BOOST_AUTO_TEST_CASE(WellTestWGRUPCONWellPropertiesSet) {
}
BOOST_AUTO_TEST_CASE(TestDefaultedCOMPDATIJ) {
Parser parser;
const char * deckString = "\n\
START\n\
\n\
10 MAI 2007 /\n\
\n\
GRID\n\
PERMX\n\
9000*0.25 /\n\
COPY \n\
PERMX PERMY /\n\
PERMX PERMZ /\n\
/\n\
SCHEDULE\n\
WELSPECS \n\
'W1' 'OP' 11 21 3.33 'OIL' 7* / \n\
/\n\
COMPDAT \n\
'W1' 2* 1 1 'OPEN' 1* 32.948 0.311 3047.839 2* 'X' 22.100 /\n\
/\n";
auto deck = parser.parseString(deckString);
auto python = std::make_shared<Python>();
EclipseGrid grid(30,30,10);
TableManager table ( deck );
FieldPropsManager fp(deck, Phases{true, true, true}, grid, table);
Runspec runspec (deck);
Schedule sched(deck, grid , fp, runspec, python);
BOOST_AUTO_TEST_CASE(TestDefaultedCOMPDATIJ)
{
const auto deck = Parser{}.parseString(R"(
START
10 MAI 2007 /
GRID
PERMX
9000*0.25 /
COPY
PERMX PERMY /
PERMX PERMZ /
/
PORO
9000*0.3 /
SCHEDULE
WELSPECS
'W1' 'OP' 11 21 3.33 'OIL' 7* /
/
COMPDAT
'W1' 2* 1 1 'OPEN' 1* 32.948 0.311 3047.839 2* 'X' 22.100 /
/
END
)");
const EclipseGrid grid(30,30,10);
const TableManager table (deck);
const FieldPropsManager fp(deck, Phases{true, true, true}, grid, table);
const Runspec runspec (deck);
const Schedule sched(deck, grid, fp, runspec, std::make_shared<Python>());
const auto& connections = sched.getWell("W1", 0).getConnections();
BOOST_CHECK_EQUAL( 10 , connections.get(0).getI() );
BOOST_CHECK_EQUAL( 20 , connections.get(0).getJ() );
@ -907,4 +912,3 @@ BOOST_AUTO_TEST_CASE(TestWellEvents) {
BOOST_CHECK( sched[0].wellgroup_events().hasEvent( "W_1", ScheduleEvents::COMPLETION_CHANGE));
BOOST_CHECK( sched[5].wellgroup_events().hasEvent( "W_1", ScheduleEvents::COMPLETION_CHANGE));
}

View File

@ -57,12 +57,22 @@ namespace {
const auto j = (dims[1] - 1) - 1;
for (auto k = top; k < static_cast<int>(dims.size()); ++k) {
const auto depth = 2000 + (2*k + 1) / static_cast<double>(2);
auto ctf_props = Opm::Connection::CTFProperties{};
ctf_props.CF = k / 100.0;
ctf_props.Kh = 1.0;
ctf_props.Ke = 1.0;
ctf_props.rw = 1.0;
ctf_props.r0 = 0.5;
ctf_props.re = 0.5;
ctf_props.connection_length = 1.0;
conns.emplace_back(i, j, k, globIndex({i, j, k}, dims), k,
2000 + (2*k + 1) / static_cast<double>(2),
Opm::Connection::State::OPEN,
k / 100.0, 1.0, 1.0, 0.5, 0.5, 1.0, 0.0, 0.0, 0.0, 0,
Opm::Connection::Direction::Z,
Opm::Connection::CTFKind::DeckValue, k, false);
Opm::Connection::CTFKind::DeckValue,
0, depth, ctf_props, k, false);
}
return { Opm::Connection::Order::INPUT, i, j, conns };
@ -87,18 +97,28 @@ namespace {
};
for (auto k = topConn; k < kMax; ++k) {
const auto depth = 2000 + (2*k + 1) / static_cast<double>(2);
auto ctf_props = Opm::Connection::CTFProperties{};
// 0.03, 0.0, 0.01, 0.02, 0.03, ...
ctf_props.CF = ((k + 3 - topConn) % 4) / 100.0;
ctf_props.Kh = 1.0;
ctf_props.Ke = 1.0;
ctf_props.rw = 1.0;
ctf_props.r0 = 0.5;
ctf_props.re = 0.5;
ctf_props.connection_length = 1.0;
conns.emplace_back(i, j, k, globIndex({i, j, k}, dims), k - topConn,
2000 + (2*k + 1) / static_cast<double>(2),
// Open, Shut, Open, Open, Shut, ...
state[(k - topConn) % state.size()],
// 0.03, 0.0, 0.01, 0.02, 0.03, ...
((k + 3 - topConn) % 4) / 100.0,
1.0, 1.0, 0.5, 0.5, 1.0, 0.0, 0.0, 0.0, 0,
Opm::Connection::Direction::Z,
Opm::Connection::CTFKind::DeckValue, k - topConn, false);
Opm::Connection::CTFKind::DeckValue,
0, depth, ctf_props, k - topConn, false);
}
return { Opm::Connection::Order::INPUT, i, j, conns };
@ -115,12 +135,22 @@ namespace {
const auto iMax = std::min(dims[0] - 1, left + numConns);
for (auto i = left; i < iMax; ++i) {
const auto depth = 2000 + (2*k + 1) / static_cast<double>(2);
auto ctf_props = Opm::Connection::CTFProperties{};
ctf_props.CF = i / 100.0;
ctf_props.Kh = 1.0;
ctf_props.Ke = 1.0;
ctf_props.rw = 1.0;
ctf_props.r0 = 0.5;
ctf_props.re = 0.5;
ctf_props.connection_length = 1.0;
conns.emplace_back(i, j, k, globIndex({i, j, k}, dims), i - left,
2000 + (2*k + 1) / static_cast<double>(2),
Opm::Connection::State::OPEN,
i / 100.0, 1.0, 1.0, 0.5, 0.5, 1.0, 0.0, 0.0, 0.0, 0,
Opm::Connection::Direction::X,
Opm::Connection::CTFKind::DeckValue, i - left, false);
Opm::Connection::CTFKind::DeckValue,
0, depth, ctf_props, i - left, false);
}
return { Opm::Connection::Order::INPUT, left, j, conns };

View File

@ -193,6 +193,7 @@ TEST_FOR_TYPE_NAMED(Action::State, ActionState)
TEST_FOR_TYPE(BCConfig)
TEST_FOR_TYPE(BrineDensityTable)
TEST_FOR_TYPE(ColumnSchema)
TEST_FOR_TYPE_NAMED(Connection::CTFProperties, CTFProperties)
TEST_FOR_TYPE(Connection)
TEST_FOR_TYPE_NAMED_OBJ(data::AquiferData, AquiferData_CarterTracy, serializationTestObjectC)
TEST_FOR_TYPE_NAMED_OBJ(data::AquiferData, AquiferData_Fetkovich, serializationTestObjectF)