Merge 9b034978bd
into 9a0ccfd853
This commit is contained in:
commit
22a6bc3e16
@ -16,40 +16,42 @@
|
||||
You should have received a copy of the GNU General Public License
|
||||
along with OPM. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
#ifndef COMPLETED_CELLS
|
||||
#define COMPLETED_CELLS
|
||||
#include <optional>
|
||||
#include <unordered_map>
|
||||
|
||||
#include <opm/input/eclipse/EclipseState/Grid/GridDims.hpp>
|
||||
|
||||
#include <array>
|
||||
#include <cstddef>
|
||||
#include <optional>
|
||||
#include <unordered_map>
|
||||
#include <utility>
|
||||
|
||||
namespace Opm {
|
||||
|
||||
class CompletedCells {
|
||||
class CompletedCells
|
||||
{
|
||||
public:
|
||||
|
||||
struct Cell {
|
||||
struct Cell
|
||||
{
|
||||
std::size_t global_index;
|
||||
std::size_t i, j, k;
|
||||
|
||||
struct Props{
|
||||
std::size_t active_index;
|
||||
double permx;
|
||||
double permy;
|
||||
double permz;
|
||||
int satnum;
|
||||
int pvtnum;
|
||||
double ntg;
|
||||
struct Props
|
||||
{
|
||||
std::size_t active_index{};
|
||||
double permx{};
|
||||
double permy{};
|
||||
double permz{};
|
||||
double poro{};
|
||||
int satnum{};
|
||||
int pvtnum{};
|
||||
double ntg{};
|
||||
|
||||
bool operator==(const Props& other) const{
|
||||
return this->active_index == other.active_index &&
|
||||
this->permx == other.permx &&
|
||||
this->permy == other.permy &&
|
||||
this->permz == other.permz &&
|
||||
this->satnum == other.satnum &&
|
||||
this->pvtnum == other.pvtnum &&
|
||||
this->ntg == other.ntg;
|
||||
}
|
||||
bool operator==(const Props& other) const;
|
||||
|
||||
static Props serializationTestObject();
|
||||
|
||||
template<class Serializer>
|
||||
void serializeOp(Serializer& serializer)
|
||||
@ -57,46 +59,23 @@ public:
|
||||
serializer(this->permx);
|
||||
serializer(this->permy);
|
||||
serializer(this->permz);
|
||||
serializer(this->poro);
|
||||
serializer(this->satnum);
|
||||
serializer(this->pvtnum);
|
||||
serializer(this->ntg);
|
||||
}
|
||||
|
||||
static Props serializationTestObject(){
|
||||
Props props;
|
||||
props.permx = 10.0;
|
||||
props.permy = 78.0;
|
||||
props.permz = 45.4;
|
||||
props.satnum = 3;
|
||||
props.pvtnum = 5;
|
||||
props.ntg = 45.1;
|
||||
return props;
|
||||
}
|
||||
};
|
||||
|
||||
std::optional<Props> props;
|
||||
std::size_t active_index() const;
|
||||
bool is_active() const;
|
||||
|
||||
double depth;
|
||||
std::array<double, 3> dimensions;
|
||||
double depth{};
|
||||
std::array<double, 3> dimensions{};
|
||||
|
||||
bool operator==(const Cell& other) const {
|
||||
return this->global_index == other.global_index &&
|
||||
this->i == other.i &&
|
||||
this->j == other.j &&
|
||||
this->k == other.k &&
|
||||
this->depth == other.depth &&
|
||||
this->dimensions == other.dimensions &&
|
||||
this->props == other.props;
|
||||
}
|
||||
bool operator==(const Cell& other) const;
|
||||
|
||||
static Cell serializationTestObject() {
|
||||
Cell cell(0,1,1,1);
|
||||
cell.depth = 12345;
|
||||
cell.dimensions = {1.0,2.0,3.0};
|
||||
return cell;
|
||||
}
|
||||
static Cell serializationTestObject();
|
||||
|
||||
template<class Serializer>
|
||||
void serializeOp(Serializer& serializer)
|
||||
@ -123,6 +102,7 @@ public:
|
||||
CompletedCells() = default;
|
||||
explicit CompletedCells(const GridDims& dims);
|
||||
CompletedCells(std::size_t nx, std::size_t ny, std::size_t nz);
|
||||
|
||||
const Cell& get(std::size_t i, std::size_t j, std::size_t k) const;
|
||||
std::pair<bool, Cell&> try_get(std::size_t i, std::size_t j, std::size_t k);
|
||||
|
||||
@ -141,5 +121,5 @@ private:
|
||||
std::unordered_map<std::size_t, Cell> cells;
|
||||
};
|
||||
}
|
||||
#endif
|
||||
|
||||
#endif // COMPLETED_CELLS
|
||||
|
@ -21,17 +21,30 @@
|
||||
|
||||
#include <opm/input/eclipse/Schedule/CompletedCells.hpp>
|
||||
|
||||
#include <cstddef>
|
||||
#include <string>
|
||||
|
||||
namespace Opm {
|
||||
|
||||
class EclipseGrid;
|
||||
class FieldPropsManager;
|
||||
|
||||
class ScheduleGrid {
|
||||
} // namespace Opm
|
||||
|
||||
namespace Opm {
|
||||
|
||||
class ScheduleGrid
|
||||
{
|
||||
public:
|
||||
ScheduleGrid(const EclipseGrid& ecl_grid, const FieldPropsManager& fpm, CompletedCells& completed_cells);
|
||||
ScheduleGrid(const EclipseGrid& ecl_grid,
|
||||
const FieldPropsManager& fpm,
|
||||
CompletedCells& completed_cells);
|
||||
|
||||
explicit ScheduleGrid(CompletedCells& completed_cells);
|
||||
|
||||
const CompletedCells::Cell& get_cell(std::size_t i, std::size_t j, std::size_t k) const;
|
||||
const CompletedCells::Cell&
|
||||
get_cell(std::size_t i, std::size_t j, std::size_t k) const;
|
||||
|
||||
const Opm::EclipseGrid* get_grid() const;
|
||||
|
||||
private:
|
||||
@ -40,8 +53,6 @@ private:
|
||||
CompletedCells& cells;
|
||||
};
|
||||
|
||||
} // namespace Opm
|
||||
|
||||
|
||||
}
|
||||
#endif
|
||||
|
||||
#endif // SCHEDULE_GRID
|
||||
|
@ -17,91 +17,172 @@
|
||||
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
|
||||
DEPTH,
|
||||
INPUT,
|
||||
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 ,
|
||||
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,
|
||||
const int satTableId,
|
||||
const Direction direction,
|
||||
const CTFKind ctf_kind,
|
||||
const std::size_t sort_value,
|
||||
const bool defaultSatTabId);
|
||||
|
||||
Connection(const RestartIO::RstConnection& rst_connection, const ScheduleGrid& grid, const FieldPropsManager& fp);
|
||||
/// 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{};
|
||||
|
||||
/// Product of certain static elements of D-factor correlation
|
||||
/// law (WDFACCOR keyword).
|
||||
double static_dfac_corr_coeff{};
|
||||
|
||||
/// 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->static_dfac_corr_coeff);
|
||||
serializer(this->peaceman_denom);
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
Connection() = default;
|
||||
Connection(int i, int j, int k,
|
||||
std::size_t global_index,
|
||||
int complnum,
|
||||
State state,
|
||||
Direction direction,
|
||||
CTFKind ctf_kind,
|
||||
const int satTableId,
|
||||
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);
|
||||
|
||||
static Connection serializationTestObject();
|
||||
|
||||
@ -117,104 +198,105 @@ 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 setStaticDFacCorrCoeff(const double c);
|
||||
|
||||
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 +348,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_
|
||||
|
@ -21,6 +21,7 @@
|
||||
#define WDFAC_HPP_HEADER_INCLUDED
|
||||
|
||||
namespace Opm {
|
||||
class Connection;
|
||||
class DeckRecord;
|
||||
class WellConnections;
|
||||
} // namespace Opm
|
||||
@ -31,49 +32,221 @@ namespace Opm { namespace RestartIO {
|
||||
|
||||
namespace Opm {
|
||||
|
||||
enum class WDFACTYPE {
|
||||
NONE = 1,
|
||||
DFACTOR = 2,
|
||||
DAKEMODEL = 3,
|
||||
CON_DFACTOR = 4
|
||||
};
|
||||
|
||||
class WDFAC
|
||||
{
|
||||
public:
|
||||
/// Parameters for Dake's D-factor correlation model.
|
||||
///
|
||||
/// In particular, holds the coefficient 'A' and the exponents 'B'
|
||||
/// and 'C' of the correlation relation
|
||||
///
|
||||
/// D = A * (Ke/K0)**B * porosity**C * Ke / (h * rw) * (sg_g/mu_g)
|
||||
///
|
||||
/// in which
|
||||
///
|
||||
/// * Ke is the connection's effective permeability (sqrt(Kx*Ky)
|
||||
/// in the case of a vertical connection)
|
||||
///
|
||||
/// * K0 is a reference/background permeability scale (1mD)
|
||||
///
|
||||
/// * h is the effective length of the connection's perforation
|
||||
/// interval (dz*ntg in the case of a vertical connection)
|
||||
///
|
||||
/// * rw is the connection's wellbore radius
|
||||
///
|
||||
/// * sg_g is the specific gravity of surface condition gas
|
||||
/// relative to surface condition air
|
||||
///
|
||||
/// * mu_g is the reservoir condition viscosity of the free gas phase.
|
||||
struct Correlation
|
||||
{
|
||||
/// Multiplicative coefficient 'A'.
|
||||
double coeff_a{0.0};
|
||||
|
||||
/// Power coefficient 'B' for the effective permeability.
|
||||
double exponent_b{0.0};
|
||||
|
||||
/// Power coefficient 'C' for the porosity term.
|
||||
double exponent_c{0.0};
|
||||
|
||||
/// Serialisation test object.
|
||||
static Correlation serializationTestObject();
|
||||
|
||||
/// Equality operator
|
||||
///
|
||||
/// \param[in] other Object to which \c *this will be compared.
|
||||
bool operator==(const Correlation& other) const;
|
||||
|
||||
/// Inequality operator
|
||||
///
|
||||
/// \param[in] other Object to which \c *this will be compared.
|
||||
bool operator!=(const Correlation& other) const
|
||||
{
|
||||
return ! (*this == other);
|
||||
}
|
||||
|
||||
/// 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->coeff_a);
|
||||
serializer(this->exponent_b);
|
||||
serializer(this->exponent_c);
|
||||
}
|
||||
};
|
||||
|
||||
/// Default constructor
|
||||
WDFAC() = default;
|
||||
|
||||
/// Constructor
|
||||
///
|
||||
/// Creates an object from restart information
|
||||
///
|
||||
/// \param[in] rst_well Linearised well-level restart information,
|
||||
/// including D-factor parameters.
|
||||
explicit WDFAC(const RestartIO::RstWell& rst_well);
|
||||
|
||||
/// Serialisation test object
|
||||
static WDFAC serializationTestObject();
|
||||
|
||||
double getDFactor(const Connection& connection, double mu, double rho, double phi) const;
|
||||
/// Configure D-factor calculation from well-level D-factor
|
||||
/// description (keyword 'WDFAC')
|
||||
///
|
||||
/// \param[in] record Well-level D-factor description. Single
|
||||
/// record from WDFAC keyword.
|
||||
void updateWDFAC(const DeckRecord& record);
|
||||
//void updateWDFAC(const RestartIO::RstWell& rst_well);
|
||||
void updateWDFACCOR(const DeckRecord& record);
|
||||
//void updateWDFACOR(const RestartIO::RstWell& rst_well);
|
||||
|
||||
/// Configure D-factor calculation from Dake correlation model
|
||||
/// (keyword WDFACCOR).
|
||||
///
|
||||
/// \param[in] record Dake correlation model description. Single
|
||||
/// record from WDFACCOR keyword.
|
||||
void updateWDFACCOR(const DeckRecord& record);
|
||||
|
||||
/// Check if any input-level connctions have a non-trivial D-factor
|
||||
/// and update this well's D-factor category accordingly.
|
||||
///
|
||||
/// \param[in] connections Connection set as defined by keyword
|
||||
/// COMPDAT. This function will detect if any of the connections
|
||||
/// created from COMPDAT define a non-trivial D-factor at the
|
||||
/// connection level (item 12 of COMPDAT) and update the D-factor
|
||||
/// category if so.
|
||||
void updateWDFACType(const WellConnections& connections);
|
||||
|
||||
/// Capture sum of all CTFs for the purpose of translating
|
||||
/// well-level D-factors to connection-level D-factors.
|
||||
///
|
||||
/// \param[in] connections Connection set as defined by keyword
|
||||
/// COMPDAT.
|
||||
void updateTotalCF(const WellConnections& connections);
|
||||
|
||||
/// Retrieve currently configured D-factor for single connection
|
||||
///
|
||||
/// \param[in] rhoGS Surface condition mass density of gas
|
||||
///
|
||||
/// \param[in] gas_visc Reservoir condition gas viscosity
|
||||
///
|
||||
/// \param[in] conn Reservoir connection for which to retrieve the
|
||||
/// D-factor.
|
||||
///
|
||||
/// \return D-factor for connection \p conn.
|
||||
double getDFactor(const double rhoGS,
|
||||
const double gas_visc,
|
||||
const Connection& conn) const;
|
||||
|
||||
/// Retrieve current D-factor correlation model coefficients.
|
||||
const Correlation& getDFactorCorrelationCoefficients() const
|
||||
{
|
||||
return this->m_corr;
|
||||
}
|
||||
|
||||
/// Whether or not a flow-dependent skin factor ('D') has been
|
||||
/// configured for the current well.
|
||||
bool useDFactor() const;
|
||||
|
||||
/// Equality operator
|
||||
///
|
||||
/// \param[in] other Object to which \c *this will be compared.
|
||||
bool operator==(const WDFAC& other) const;
|
||||
bool operator!=(const WDFAC& other) const;
|
||||
|
||||
template<class Serializer>
|
||||
/// Inequality operator
|
||||
///
|
||||
/// \param[in] other Object to which \c *this will be compared.
|
||||
bool operator!=(const WDFAC& other) const
|
||||
{
|
||||
return ! (*this == other);
|
||||
}
|
||||
|
||||
/// 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(m_a);
|
||||
serializer(m_b);
|
||||
serializer(m_c);
|
||||
serializer(m_d);
|
||||
serializer(m_total_cf);
|
||||
serializer(m_type);
|
||||
serializer(this->m_type);
|
||||
serializer(this->m_d);
|
||||
serializer(this->m_total_cf);
|
||||
serializer(this->m_corr);
|
||||
}
|
||||
|
||||
private:
|
||||
double m_a{0.0};
|
||||
double m_b{0.0};
|
||||
double m_c{0.0};
|
||||
/// D-factor categories.
|
||||
enum class WDFacType
|
||||
{
|
||||
/// No flow-dependent skin factor is configured for this well.
|
||||
NONE = 1,
|
||||
|
||||
/// Well-level D-factor.
|
||||
DFACTOR = 2,
|
||||
|
||||
/// Use Dake's D-factor correlation model.
|
||||
DAKEMODEL = 3,
|
||||
|
||||
/// Connection-level D-factor.
|
||||
CON_DFACTOR = 4,
|
||||
};
|
||||
|
||||
/// D-factor category for this well.
|
||||
WDFacType m_type { WDFacType::NONE };
|
||||
|
||||
/// Well-level D-factor for this well.
|
||||
double m_d{0.0};
|
||||
|
||||
/// Total CTF sum for this well.
|
||||
double m_total_cf{-1.0};
|
||||
WDFACTYPE m_type = WDFACTYPE::NONE;
|
||||
|
||||
/// Coefficients for Dake's correlation model.
|
||||
Correlation m_corr{};
|
||||
|
||||
/// Retrieve connection-level D-Factor from COMPDAT entries
|
||||
///
|
||||
/// Possibly translated from well-level values.
|
||||
///
|
||||
/// \param[in] conn Reservoir connection for which to retrieve the
|
||||
/// D-factor.
|
||||
///
|
||||
/// \return Connection-level D-factor.
|
||||
double connectionLevelDFactor(const Connection& conn) const;
|
||||
|
||||
/// Translate well-level D-factor to connection level D-factor
|
||||
///
|
||||
/// \param[in] dfac Well-level D-factor.
|
||||
///
|
||||
/// \param[in] conn Reservoir connection for which to retrieve the
|
||||
/// D-factor.
|
||||
///
|
||||
/// \return Connection-level D-factor, translated from well level.
|
||||
double scaledWellLevelDFactor(const double dfac,
|
||||
const Connection& conn) const;
|
||||
};
|
||||
|
||||
} // namespace Opm
|
||||
|
@ -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);
|
||||
|
@ -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,11 @@
|
||||
namespace Opm {
|
||||
class ActiveGridCells;
|
||||
class DeckRecord;
|
||||
class EclipseGrid;
|
||||
class FieldPropsManager;
|
||||
class KeywordLocation;
|
||||
class ScheduleGrid;
|
||||
class EclipseGrid;
|
||||
class WDFAC;
|
||||
} // namespace Opm
|
||||
|
||||
namespace Opm {
|
||||
@ -67,19 +70,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,
|
||||
@ -89,16 +89,26 @@ namespace Opm {
|
||||
void loadCOMPDAT(const DeckRecord& record,
|
||||
const ScheduleGrid& grid,
|
||||
const std::string& wname,
|
||||
const WDFAC& wdfac,
|
||||
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);
|
||||
|
||||
void applyDFactorCorrelation(const ScheduleGrid& grid,
|
||||
const WDFAC& wdfac);
|
||||
|
||||
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 +175,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>
|
||||
|
@ -3,7 +3,8 @@
|
||||
|
||||
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
|
||||
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.
|
||||
|
||||
@ -19,19 +20,27 @@
|
||||
#ifndef RST_CONNECTION
|
||||
#define RST_CONNECTION
|
||||
|
||||
#include <array>
|
||||
|
||||
#include <opm/input/eclipse/Schedule/Well/Connection.hpp>
|
||||
|
||||
#include <array>
|
||||
|
||||
namespace Opm {
|
||||
|
||||
class UnitSystem;
|
||||
|
||||
namespace RestartIO {
|
||||
} // namespace Opm
|
||||
|
||||
class Header;
|
||||
namespace Opm { namespace RestartIO {
|
||||
|
||||
struct RstConnection
|
||||
{
|
||||
RstConnection(const UnitSystem& unit_system,
|
||||
std::size_t rst_index,
|
||||
int nsconz,
|
||||
const int* icon,
|
||||
const float* scon,
|
||||
const double *xcon);
|
||||
|
||||
struct RstConnection {
|
||||
RstConnection(const ::Opm::UnitSystem& unit_system, std::size_t rst_index, int nsconz, const int* icon, const float* scon, const double *xcon);
|
||||
static double inverse_peaceman(double cf, double kh, double rw, double skin);
|
||||
|
||||
std::size_t rst_index;
|
||||
@ -49,6 +58,9 @@ struct RstConnection {
|
||||
float depth;
|
||||
float diameter;
|
||||
float kh;
|
||||
float denom;
|
||||
float length;
|
||||
float static_dfac_corr_coeff;
|
||||
float segdist_end;
|
||||
float segdist_start;
|
||||
|
||||
@ -60,11 +72,6 @@ struct RstConnection {
|
||||
double r0;
|
||||
};
|
||||
|
||||
}} // namespace Opm::RestartIO
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
#endif
|
||||
#endif // RST_CONNECTION
|
||||
|
@ -126,6 +126,9 @@ struct RstWell
|
||||
float glift_min_rate;
|
||||
float glift_weight_factor;
|
||||
float glift_inc_weight_factor;
|
||||
float dfac_corr_coeff_a{};
|
||||
float dfac_corr_exponent_b{};
|
||||
float dfac_corr_exponent_c{};
|
||||
std::vector<float> tracer_concentration_injection;
|
||||
|
||||
double oil_rate;
|
||||
|
@ -36,9 +36,7 @@
|
||||
#include <unordered_map>
|
||||
#include <vector>
|
||||
|
||||
namespace Opm {
|
||||
|
||||
namespace data {
|
||||
namespace Opm { namespace data {
|
||||
|
||||
class Rates {
|
||||
/* Methods are defined inline for performance, as the actual *work* done
|
||||
@ -257,22 +255,25 @@ namespace Opm {
|
||||
double effective_Kh;
|
||||
double trans_factor;
|
||||
double d_factor;
|
||||
double compact_mult{1.0}; // Rock compaction transmissibility multiplier (ROCKTAB)
|
||||
|
||||
ConnectionFiltrate filtrate;
|
||||
|
||||
bool operator==(const Connection& conn2) const
|
||||
{
|
||||
return index == conn2.index &&
|
||||
rates == conn2.rates &&
|
||||
pressure == conn2.pressure &&
|
||||
reservoir_rate == conn2.reservoir_rate &&
|
||||
cell_pressure == conn2.cell_pressure &&
|
||||
cell_saturation_water == conn2.cell_saturation_water &&
|
||||
cell_saturation_gas == conn2.cell_saturation_gas &&
|
||||
effective_Kh == conn2.effective_Kh &&
|
||||
trans_factor == conn2.trans_factor &&
|
||||
d_factor == conn2.d_factor &&
|
||||
filtrate == conn2.filtrate;
|
||||
return (index == conn2.index)
|
||||
&& (rates == conn2.rates)
|
||||
&& (pressure == conn2.pressure)
|
||||
&& (reservoir_rate == conn2.reservoir_rate)
|
||||
&& (cell_pressure == conn2.cell_pressure)
|
||||
&& (cell_saturation_water == conn2.cell_saturation_water)
|
||||
&& (cell_saturation_gas == conn2.cell_saturation_gas)
|
||||
&& (effective_Kh == conn2.effective_Kh)
|
||||
&& (trans_factor == conn2.trans_factor)
|
||||
&& (d_factor == conn2.d_factor)
|
||||
&& (compact_mult == conn2.compact_mult)
|
||||
&& (filtrate == conn2.filtrate)
|
||||
;
|
||||
}
|
||||
|
||||
template <class MessageBufferType>
|
||||
@ -295,15 +296,18 @@ namespace Opm {
|
||||
serializer(effective_Kh);
|
||||
serializer(trans_factor);
|
||||
serializer(d_factor);
|
||||
serializer(compact_mult);
|
||||
serializer(filtrate);
|
||||
}
|
||||
|
||||
static Connection serializationTestObject()
|
||||
{
|
||||
return Connection{1, Rates::serializationTestObject(),
|
||||
2.0, 3.0, 4.0, 5.0,
|
||||
6.0, 7.0, 8.0, 9.0,
|
||||
ConnectionFiltrate::serializationTestObject() };
|
||||
return Connection {
|
||||
1, Rates::serializationTestObject(),
|
||||
2.0, 3.0, 4.0, 5.0,
|
||||
6.0, 7.0, 8.0, 9.0, 0.987,
|
||||
ConnectionFiltrate::serializationTestObject()
|
||||
};
|
||||
}
|
||||
};
|
||||
|
||||
@ -1187,6 +1191,7 @@ namespace Opm {
|
||||
buffer.write(this->effective_Kh);
|
||||
buffer.write(this->trans_factor);
|
||||
buffer.write(this->d_factor);
|
||||
buffer.write(this->compact_mult);
|
||||
this->filtrate.write(buffer);
|
||||
}
|
||||
|
||||
@ -1203,6 +1208,7 @@ namespace Opm {
|
||||
json_data.add_item("Kh", this->effective_Kh);
|
||||
json_data.add_item("trans_factor", this->trans_factor);
|
||||
json_data.add_item("d_factor", this->d_factor);
|
||||
json_data.add_item("compact_mult", this->compact_mult);
|
||||
}
|
||||
|
||||
template <class MessageBufferType>
|
||||
@ -1349,6 +1355,7 @@ namespace Opm {
|
||||
buffer.read(this->effective_Kh);
|
||||
buffer.read(this->trans_factor);
|
||||
buffer.read(this->d_factor);
|
||||
buffer.read(this->compact_mult);
|
||||
this->filtrate.read(buffer);
|
||||
}
|
||||
|
||||
|
@ -44,19 +44,29 @@ namespace Opm { namespace RestartIO { namespace Helpers { namespace VectorItems
|
||||
|
||||
namespace SConn {
|
||||
enum index : std::vector<float>::size_type {
|
||||
ConnTrans = 0, // Connection transmissibility factor
|
||||
EffConnTrans = 0, // Effective connection transmissibility factor (incl. ROCKTAB &c)
|
||||
Depth = 1, // Connection centre depth
|
||||
Diameter = 2, // Connection diameter
|
||||
|
||||
EffectiveKH = 3, // Effective Kh product of connection
|
||||
SkinFactor = 4, // Skinfactor - item 'SKIN' from COMPDAT
|
||||
item12 = 11, // Connection transmissibility factor
|
||||
|
||||
CFDenom = 6, // Denominator in connection transmissibility
|
||||
// factor expression
|
||||
|
||||
ConnTrans = 11, // Connection transmissibility factor
|
||||
|
||||
SegDistEnd = 20, // Distance to end of connection in segment
|
||||
SegDistStart = 21, // Distance to start of connection in segment
|
||||
|
||||
item30 = 29, // Unknown
|
||||
item31 = 30, // Unknown
|
||||
|
||||
EffectiveLength = 31, // Effective length of connection's perforation interval.
|
||||
|
||||
StaticDFacCorrCoeff = 37, // Static component of Forchheimer
|
||||
// D-factor correlation.
|
||||
|
||||
CFInDeck = 40, // = 0 for connection factor not defined, = 1 for connection factor defined
|
||||
};
|
||||
} // SConn
|
||||
|
@ -331,6 +331,9 @@ namespace Opm { namespace RestartIO { namespace Helpers { namespace VectorItems
|
||||
VfpBhpScalingFact = 83, // Tubing pressure loss scaling factor (WVFPDP(3))
|
||||
WGrupConGRScaling = 84, // Guide rate scaling factor (WGRUPCON(5))
|
||||
|
||||
DFacCorrCoeffA = 104, // Coefficient 'A' of D-factor correlation (WDFACCOR(2))
|
||||
DFacCorrExpB = 105, // Exponent 'B' of D-factor correlation (WDFACCOR(3))
|
||||
DFacCorrExpC = 106, // Exponent 'C' of D-factor correlation (WDFACCOR(4))
|
||||
|
||||
LOincFac = 115,
|
||||
|
||||
|
@ -19,50 +19,105 @@
|
||||
|
||||
#include <opm/input/eclipse/Schedule/CompletedCells.hpp>
|
||||
|
||||
bool Opm::CompletedCells::Cell::Props::operator==(const Props& other) const
|
||||
{
|
||||
return (this->active_index == other.active_index)
|
||||
&& (this->permx == other.permx)
|
||||
&& (this->permy == other.permy)
|
||||
&& (this->permz == other.permz)
|
||||
&& (this->poro == other.poro)
|
||||
&& (this->satnum == other.satnum)
|
||||
&& (this->pvtnum == other.pvtnum)
|
||||
&& (this->ntg == other.ntg)
|
||||
;
|
||||
}
|
||||
|
||||
Opm::CompletedCells::Cell::Props
|
||||
Opm::CompletedCells::Cell::Props::serializationTestObject()
|
||||
{
|
||||
Props props;
|
||||
|
||||
props.permx = 10.0;
|
||||
props.permy = 78.0;
|
||||
props.permz = 45.4;
|
||||
props.poro = 0.321;
|
||||
props.satnum = 3;
|
||||
props.pvtnum = 5;
|
||||
props.ntg = 45.1;
|
||||
|
||||
return props;
|
||||
}
|
||||
|
||||
bool Opm::CompletedCells::Cell::operator==(const Cell& other) const
|
||||
{
|
||||
return (this->global_index == other.global_index)
|
||||
&& (this->i == other.i)
|
||||
&& (this->j == other.j)
|
||||
&& (this->k == other.k)
|
||||
&& (this->depth == other.depth)
|
||||
&& (this->dimensions == other.dimensions)
|
||||
&& (this->props == other.props)
|
||||
;
|
||||
}
|
||||
|
||||
Opm::CompletedCells::Cell
|
||||
Opm::CompletedCells::Cell::serializationTestObject()
|
||||
{
|
||||
Cell cell { 0, 1, 1, 1 };
|
||||
|
||||
cell.props = Props::serializationTestObject();
|
||||
cell.depth = 12345;
|
||||
cell.dimensions = {1.0,2.0,3.0};
|
||||
|
||||
return cell;
|
||||
}
|
||||
|
||||
Opm::CompletedCells::CompletedCells(std::size_t nx, std::size_t ny, std::size_t nz)
|
||||
: dims(nx,ny,nz)
|
||||
: dims(nx, ny, nz)
|
||||
{}
|
||||
|
||||
|
||||
Opm::CompletedCells::CompletedCells(const Opm::GridDims& dims_)
|
||||
:dims(dims_)
|
||||
: dims(dims_)
|
||||
{}
|
||||
|
||||
|
||||
const Opm::CompletedCells::Cell& Opm::CompletedCells::get(std::size_t i, std::size_t j, std::size_t k) const {
|
||||
auto g = this->dims.getGlobalIndex(i,j,k);
|
||||
return this->cells.at(g);
|
||||
const Opm::CompletedCells::Cell&
|
||||
Opm::CompletedCells::get(std::size_t i, std::size_t j, std::size_t k) const
|
||||
{
|
||||
return this->cells.at(this->dims.getGlobalIndex(i, j, k));
|
||||
}
|
||||
|
||||
std::pair<bool, Opm::CompletedCells::Cell&>
|
||||
Opm::CompletedCells::try_get(std::size_t i, std::size_t j, std::size_t k)
|
||||
{
|
||||
const auto g = this->dims.getGlobalIndex(i, j, k);
|
||||
|
||||
std::pair<bool, Opm::CompletedCells::Cell&> Opm::CompletedCells::try_get(std::size_t i, std::size_t j, std::size_t k) {
|
||||
auto g = this->dims.getGlobalIndex(i,j,k);
|
||||
auto iter = this->cells.find(g);
|
||||
if (iter != this->cells.end())
|
||||
return {true, iter->second};
|
||||
const auto& [pos, inserted] = this->cells.try_emplace(g, g, i, j, k);
|
||||
|
||||
this->cells.emplace(g, Cell{g,i,j,k});
|
||||
return {false, this->cells.at(g)};
|
||||
return { !inserted, pos->second };
|
||||
}
|
||||
|
||||
|
||||
bool Opm::CompletedCells::operator==(const Opm::CompletedCells& other) const {
|
||||
return this->dims == other.dims &&
|
||||
this->cells == other.cells;
|
||||
bool Opm::CompletedCells::operator==(const Opm::CompletedCells& other) const
|
||||
{
|
||||
return (this->dims == other.dims)
|
||||
&& (this->cells == other.cells)
|
||||
;
|
||||
}
|
||||
|
||||
|
||||
Opm::CompletedCells Opm::CompletedCells::serializationTestObject() {
|
||||
Opm::CompletedCells
|
||||
Opm::CompletedCells::serializationTestObject()
|
||||
{
|
||||
Opm::CompletedCells cells(2,3,4);
|
||||
cells.cells.emplace(7, Opm::CompletedCells::Cell::serializationTestObject());
|
||||
|
||||
return cells;
|
||||
}
|
||||
|
||||
std::size_t Opm::CompletedCells::Cell::active_index() const{
|
||||
std::size_t Opm::CompletedCells::Cell::active_index() const
|
||||
{
|
||||
return this->props.value().active_index;
|
||||
}
|
||||
|
||||
bool Opm::CompletedCells::Cell::is_active() const{
|
||||
bool Opm::CompletedCells::Cell::is_active() const
|
||||
{
|
||||
return this->props.has_value();
|
||||
}
|
||||
|
@ -196,37 +196,51 @@ namespace {
|
||||
this->snapshots.back().network.update( std::move( ext_network ));
|
||||
}
|
||||
|
||||
void Schedule::handleCOMPDAT(HandlerContext& handlerContext) {
|
||||
void Schedule::handleCOMPDAT(HandlerContext& handlerContext) {
|
||||
std::unordered_set<std::string> wells;
|
||||
for (const auto& record : handlerContext.keyword) {
|
||||
const std::string& wellNamePattern = record.getItem("WELL").getTrimmedString(0);
|
||||
auto wellnames = this->wellNames(wellNamePattern, handlerContext,
|
||||
isWList(handlerContext.currentStep,
|
||||
wellNamePattern));
|
||||
const auto wellNamePattern = record.getItem("WELL").getTrimmedString(0);
|
||||
const auto wellnames =
|
||||
this->wellNames(wellNamePattern, handlerContext,
|
||||
isWList(handlerContext.currentStep, wellNamePattern));
|
||||
|
||||
for (const auto& name : wellnames) {
|
||||
auto well2 = this->snapshots.back().wells.get(name);
|
||||
auto connections = std::shared_ptr<WellConnections>( new WellConnections( well2.getConnections()));
|
||||
connections->loadCOMPDAT(record, handlerContext.grid, name, handlerContext.keyword.location());
|
||||
|
||||
if (well2.updateConnections(connections, handlerContext.grid)) {
|
||||
auto connections = std::make_shared<WellConnections>(well2.getConnections());
|
||||
const auto origWellConnSetIsEmpty = connections->empty();
|
||||
|
||||
connections->loadCOMPDAT(record, handlerContext.grid, name,
|
||||
well2.getWDFAC(), handlerContext.keyword.location());
|
||||
const auto newWellConnSetIsEmpty = connections->empty();
|
||||
|
||||
if (well2.updateConnections(std::move(connections), handlerContext.grid)) {
|
||||
auto wdfac = std::make_shared<WDFAC>(well2.getWDFAC());
|
||||
wdfac->updateWDFACType(*connections);
|
||||
wdfac->updateWDFACType(well2.getConnections());
|
||||
|
||||
well2.updateWDFAC(std::move(wdfac));
|
||||
this->snapshots.back().wells.update( well2 );
|
||||
wells.insert( name );
|
||||
this->snapshots.back().wells.update(well2);
|
||||
|
||||
wells.insert(name);
|
||||
}
|
||||
|
||||
if (connections->empty() && well2.getConnections().empty()) {
|
||||
if (origWellConnSetIsEmpty && newWellConnSetIsEmpty) {
|
||||
const auto& location = handlerContext.keyword.location();
|
||||
auto msg = fmt::format("Problem with COMPDAT/{}\n"
|
||||
"In {} line {}\n"
|
||||
"Well {} is not connected to grid - will remain SHUT", name, location.filename, location.lineno, name);
|
||||
|
||||
const auto msg = fmt::format(R"(Problem with COMPDAT/{}
|
||||
In {} line {}
|
||||
Well {} is not connected to grid - will remain SHUT)",
|
||||
name, location.filename,
|
||||
location.lineno, name);
|
||||
|
||||
OpmLog::warning(msg);
|
||||
}
|
||||
this->snapshots.back().wellgroup_events().addEvent( name, ScheduleEvents::COMPLETION_CHANGE);
|
||||
|
||||
this->snapshots.back().wellgroup_events()
|
||||
.addEvent(name, ScheduleEvents::COMPLETION_CHANGE);
|
||||
}
|
||||
}
|
||||
|
||||
this->snapshots.back().events().addEvent(ScheduleEvents::COMPLETION_CHANGE);
|
||||
|
||||
// In the case the wells reference depth has been defaulted in the
|
||||
@ -234,9 +248,10 @@ namespace {
|
||||
// reference depth exactly when the COMPDAT keyword has been completely
|
||||
// processed.
|
||||
for (const auto& wname : wells) {
|
||||
auto& well = this->snapshots.back().wells.get( wname );
|
||||
auto well = this->snapshots.back().wells.get(wname);
|
||||
well.updateRefDepth();
|
||||
this->snapshots.back().wells.update( std::move(well));
|
||||
|
||||
this->snapshots.back().wells.update(std::move(well));
|
||||
}
|
||||
|
||||
if (! wells.empty()) {
|
||||
@ -268,20 +283,30 @@ namespace {
|
||||
this->snapshots.back().events().addEvent(ScheduleEvents::COMPLETION_CHANGE);
|
||||
}
|
||||
|
||||
void Schedule::handleCOMPTRAJ(HandlerContext& handlerContext) {
|
||||
void Schedule::handleCOMPTRAJ(HandlerContext& handlerContext)
|
||||
{
|
||||
// Keyword WELTRAJ must be read first
|
||||
std::unordered_set<std::string> wells;
|
||||
external::cvf::ref<external::cvf::BoundingBoxTree> cellSearchTree = nullptr;
|
||||
|
||||
for (const auto& record : handlerContext.keyword) {
|
||||
const std::string& wellNamePattern = record.getItem("WELL").getTrimmedString(0);
|
||||
auto wellnames = this->wellNames(wellNamePattern, handlerContext );
|
||||
const auto wellNamePattern = record.getItem("WELL").getTrimmedString(0);
|
||||
const auto wellnames = this->wellNames(wellNamePattern, handlerContext);
|
||||
|
||||
for (const auto& name : wellnames) {
|
||||
auto well2 = this->snapshots.back().wells.get(name);
|
||||
auto connections = std::make_shared<WellConnections>(WellConnections(well2.getConnections()));
|
||||
// cellsearchTree is calculated only once and is used to calculated cell intersections of the perforations specified in COMPTRAJ
|
||||
connections->loadCOMPTRAJ(record, handlerContext.grid, name, handlerContext.keyword.location(), cellSearchTree);
|
||||
// In the case that defaults are used in WELSPECS for headI/J the headI/J are calculated based on the well trajectory data
|
||||
auto connections = std::make_shared<WellConnections>(well2.getConnections());
|
||||
|
||||
// cellsearchTree is calculated only once and is used to
|
||||
// calculated cell intersections of the perforations
|
||||
// specified in COMPTRAJ
|
||||
connections->loadCOMPTRAJ(record, handlerContext.grid, name,
|
||||
handlerContext.keyword.location(),
|
||||
cellSearchTree);
|
||||
|
||||
// In the case that defaults are used in WELSPECS for
|
||||
// headI/J the headI/J are calculated based on the well
|
||||
// trajectory data
|
||||
well2.updateHead(connections->getHeadI(), connections->getHeadJ());
|
||||
if (well2.updateConnections(connections, handlerContext.grid)) {
|
||||
this->snapshots.back().wells.update( well2 );
|
||||
@ -295,19 +320,23 @@ namespace {
|
||||
"Well {} is not connected to grid - will remain SHUT", name, location.filename, location.lineno, name);
|
||||
OpmLog::warning(msg);
|
||||
}
|
||||
this->snapshots.back().wellgroup_events().addEvent( name, ScheduleEvents::COMPLETION_CHANGE);
|
||||
|
||||
this->snapshots.back().wellgroup_events()
|
||||
.addEvent(name, ScheduleEvents::COMPLETION_CHANGE);
|
||||
}
|
||||
}
|
||||
|
||||
this->snapshots.back().events().addEvent(ScheduleEvents::COMPLETION_CHANGE);
|
||||
|
||||
// In the case the wells reference depth has been defaulted in the
|
||||
// WELSPECS keyword we need to force a calculation of the wells
|
||||
// reference depth exactly when the WELCOML keyword has been completely
|
||||
// processed.
|
||||
// reference depth exactly when the WELCOML keyword has been
|
||||
// completely processed.
|
||||
for (const auto& wname : wells) {
|
||||
auto& well = this->snapshots.back().wells.get( wname );
|
||||
auto& well = this->snapshots.back().wells.get(wname);
|
||||
well.updateRefDepth();
|
||||
this->snapshots.back().wells.update( std::move(well));
|
||||
|
||||
this->snapshots.back().wells.update(std::move(well));
|
||||
}
|
||||
|
||||
if (! wells.empty()) {
|
||||
@ -377,23 +406,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));
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -1635,25 +1670,55 @@ File {} line {}.)", wname, location.keyword, location.filename, location.lineno)
|
||||
auto wdfac = std::make_shared<WDFAC>(well.getWDFAC());
|
||||
wdfac->updateWDFAC( record );
|
||||
wdfac->updateTotalCF(well.getConnections());
|
||||
if (well.updateWDFAC(std::move(wdfac)))
|
||||
this->snapshots.back().wells.update( std::move(well) );
|
||||
|
||||
if (well.updateWDFAC(std::move(wdfac))) {
|
||||
this->snapshots.back().wells.update(std::move(well));
|
||||
|
||||
handlerContext.affected_well(well_name);
|
||||
handlerContext.record_well_structure_change();
|
||||
|
||||
this->snapshots.back().events()
|
||||
.addEvent(ScheduleEvents::COMPLETION_CHANGE);
|
||||
|
||||
this->snapshots.back().wellgroup_events()
|
||||
.addEvent(well_name, ScheduleEvents::COMPLETION_CHANGE);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void Schedule::handleWDFACCOR(HandlerContext& handlerContext) {
|
||||
for (const auto& record : handlerContext.keyword) {
|
||||
const std::string& wellNamePattern = record.getItem("WELLNAME").getTrimmedString(0);
|
||||
const std::string wellNamePattern = record.getItem("WELLNAME").getTrimmedString(0);
|
||||
const auto well_names = wellNames(wellNamePattern, handlerContext.currentStep);
|
||||
if (well_names.empty())
|
||||
this->invalidNamePattern(wellNamePattern, handlerContext);
|
||||
|
||||
for (const auto& well_name : well_names) {
|
||||
auto well = this->snapshots.back().wells.get(well_name);
|
||||
auto conns = std::make_shared<WellConnections>(well.getConnections());
|
||||
|
||||
auto wdfac = std::make_shared<WDFAC>(well.getWDFAC());
|
||||
wdfac->updateWDFACCOR( record );
|
||||
if (well.updateWDFAC(std::move(wdfac)))
|
||||
this->snapshots.back().wells.update( std::move(well) );
|
||||
wdfac->updateWDFACCOR(record);
|
||||
|
||||
conns->applyDFactorCorrelation(handlerContext.grid, *wdfac);
|
||||
const auto updateConns =
|
||||
well.updateConnections(std::move(conns), handlerContext.grid);
|
||||
|
||||
if (well.updateWDFAC(std::move(wdfac)) || updateConns) {
|
||||
this->snapshots.back().wells.update(std::move(well));
|
||||
|
||||
handlerContext.affected_well(well_name);
|
||||
handlerContext.record_well_structure_change();
|
||||
|
||||
if (updateConns) {
|
||||
this->snapshots.back().events()
|
||||
.addEvent(ScheduleEvents::COMPLETION_CHANGE);
|
||||
|
||||
this->snapshots.back().wellgroup_events()
|
||||
.addEvent(well_name, ScheduleEvents::COMPLETION_CHANGE);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -17,16 +17,24 @@
|
||||
along with OPM. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
#include <fmt/format.h>
|
||||
#include <opm/input/eclipse/Schedule/CompletedCells.hpp>
|
||||
#include <opm/input/eclipse/Schedule/ScheduleGrid.hpp>
|
||||
|
||||
#include <opm/input/eclipse/Schedule/CompletedCells.hpp>
|
||||
|
||||
#include <opm/input/eclipse/EclipseState/Grid/EclipseGrid.hpp>
|
||||
#include <opm/input/eclipse/EclipseState/Grid/FieldPropsManager.hpp>
|
||||
|
||||
Opm::ScheduleGrid::ScheduleGrid(const Opm::EclipseGrid& ecl_grid, const Opm::FieldPropsManager& fpm, Opm::CompletedCells& completed_cells)
|
||||
: grid(&ecl_grid)
|
||||
, fp(&fpm)
|
||||
, cells(completed_cells)
|
||||
#include <cstddef>
|
||||
#include <string>
|
||||
|
||||
#include <fmt/format.h>
|
||||
|
||||
Opm::ScheduleGrid::ScheduleGrid(const Opm::EclipseGrid& ecl_grid,
|
||||
const Opm::FieldPropsManager& fpm,
|
||||
Opm::CompletedCells& completed_cells)
|
||||
: grid { &ecl_grid }
|
||||
, fp { &fpm }
|
||||
, cells { completed_cells }
|
||||
{}
|
||||
|
||||
Opm::ScheduleGrid::ScheduleGrid(Opm::CompletedCells& completed_cells)
|
||||
@ -34,45 +42,58 @@ Opm::ScheduleGrid::ScheduleGrid(Opm::CompletedCells& completed_cells)
|
||||
{}
|
||||
|
||||
namespace {
|
||||
double try_get_value(const Opm::FieldPropsManager& fp, const std::string& kw, std::size_t active_index) {
|
||||
if (fp.has_double(kw))
|
||||
return fp.try_get<double>(kw)->at(active_index);
|
||||
else
|
||||
double try_get_value(const Opm::FieldPropsManager& fp,
|
||||
const std::string& kw,
|
||||
const std::size_t active_index)
|
||||
{
|
||||
if (! fp.has_double(kw)) {
|
||||
throw std::logic_error(fmt::format("FieldPropsManager is missing keyword '{}'", kw));
|
||||
}
|
||||
|
||||
double try_get_ntg_value(const Opm::FieldPropsManager& fp, const std::string& kw, std::size_t active_index){
|
||||
if (fp.has_double(kw))
|
||||
return fp.try_get<double>(kw)->at(active_index);
|
||||
else
|
||||
return 1.0;
|
||||
}
|
||||
}
|
||||
|
||||
const Opm::CompletedCells::Cell& Opm::ScheduleGrid::get_cell(std::size_t i, std::size_t j, std::size_t k) const {
|
||||
if (this->grid) {
|
||||
auto [valid, cell] = this->cells.try_get(i,j,k);
|
||||
if (!valid) {
|
||||
cell.depth = this->grid->getCellDepth(i,j,k);
|
||||
cell.dimensions = this->grid->getCellDimensions(i,j,k);
|
||||
if (this->grid->cellActive(i,j,k)){
|
||||
CompletedCells::Cell::Props props;
|
||||
|
||||
props.active_index = this->grid->getActiveIndex(i,j,k);
|
||||
props.permx = try_get_value(*this->fp, "PERMX", props.active_index);
|
||||
props.permy = try_get_value(*this->fp, "PERMY", props.active_index);
|
||||
props.permz = try_get_value(*this->fp, "PERMZ", props.active_index);
|
||||
props.satnum = this->fp->get_int("SATNUM").at(props.active_index);
|
||||
props.pvtnum = this->fp->get_int("PVTNUM").at(props.active_index);
|
||||
props.ntg = try_get_ntg_value(*this->fp, "NTG", props.active_index);
|
||||
cell.props = props;
|
||||
}
|
||||
}
|
||||
return cell;
|
||||
} else
|
||||
return this->cells.get(i,j,k);
|
||||
|
||||
return fp.try_get<double>(kw)->at(active_index);
|
||||
}
|
||||
|
||||
double try_get_ntg_value(const Opm::FieldPropsManager& fp,
|
||||
const std::string& kw,
|
||||
const std::size_t active_index)
|
||||
{
|
||||
return fp.has_double(kw)
|
||||
? fp.try_get<double>(kw)->at(active_index)
|
||||
: 1.0;
|
||||
}
|
||||
}
|
||||
|
||||
const Opm::EclipseGrid* Opm::ScheduleGrid::get_grid() const {
|
||||
return this->grid;
|
||||
const Opm::CompletedCells::Cell&
|
||||
Opm::ScheduleGrid::get_cell(std::size_t i, std::size_t j, std::size_t k) const
|
||||
{
|
||||
if (this->grid == nullptr) {
|
||||
return this->cells.get(i, j, k);
|
||||
}
|
||||
|
||||
auto [valid, cellRef] = this->cells.try_get(i, j, k);
|
||||
|
||||
if (!valid) {
|
||||
cellRef.depth = this->grid->getCellDepth(i, j, k);
|
||||
cellRef.dimensions = this->grid->getCellDimensions(i, j, k);
|
||||
|
||||
if (this->grid->cellActive(i, j, k)) {
|
||||
auto& props = cellRef.props.emplace(CompletedCells::Cell::Props{});
|
||||
|
||||
props.active_index = this->grid->getActiveIndex(i, j, k);
|
||||
props.permx = try_get_value(*this->fp, "PERMX", props.active_index);
|
||||
props.permy = try_get_value(*this->fp, "PERMY", props.active_index);
|
||||
props.permz = try_get_value(*this->fp, "PERMZ", props.active_index);
|
||||
props.poro = try_get_value(*this->fp, "PORO", props.active_index);
|
||||
props.satnum = this->fp->get_int("SATNUM").at(props.active_index);
|
||||
props.pvtnum = this->fp->get_int("PVTNUM").at(props.active_index);
|
||||
props.ntg = try_get_ntg_value(*this->fp, "NTG", props.active_index);
|
||||
}
|
||||
}
|
||||
|
||||
return cellRef;
|
||||
}
|
||||
|
||||
const Opm::EclipseGrid* Opm::ScheduleGrid::get_grid() const
|
||||
{
|
||||
return this->grid;
|
||||
}
|
||||
|
@ -17,125 +17,164 @@
|
||||
along with OPM. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
#include <algorithm>
|
||||
#include <cassert>
|
||||
#include <exception>
|
||||
#include <sstream>
|
||||
#include <stdexcept>
|
||||
#include <vector>
|
||||
#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 <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)
|
||||
{
|
||||
}
|
||||
#include <algorithm>
|
||||
#include <array>
|
||||
#include <cassert>
|
||||
#include <cstddef>
|
||||
#include <exception>
|
||||
#include <sstream>
|
||||
#include <stdexcept>
|
||||
#include <string>
|
||||
#include <string_view>
|
||||
#include <utility>
|
||||
#include <vector>
|
||||
|
||||
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 = rst_conn.length;
|
||||
props.skin_factor = rst_conn.skin_factor;
|
||||
props.d_factor = 0.0;
|
||||
props.static_dfac_corr_coeff = rst_conn.static_dfac_corr_coeff;
|
||||
props.peaceman_denom = rst_conn.denom;
|
||||
|
||||
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)
|
||||
{
|
||||
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];
|
||||
}
|
||||
if (this->segment_number > 0)
|
||||
this->m_perf_range = std::make_pair(rst_connection.segdist_start, rst_connection.segdist_end);
|
||||
namespace Opm
|
||||
{
|
||||
|
||||
//TODO recompute re and perf_length from the grid
|
||||
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.static_dfac_corr_coeff = 10.0;
|
||||
props.peaceman_denom = 11.0;
|
||||
|
||||
return props;
|
||||
}
|
||||
|
||||
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)
|
||||
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->static_dfac_corr_coeff == that.static_dfac_corr_coeff)
|
||||
&& (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 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);
|
||||
}
|
||||
|
||||
// TODO: recompute re from the grid
|
||||
}
|
||||
|
||||
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 +183,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,124 +365,142 @@ 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;
|
||||
|
||||
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 {
|
||||
void Connection::setStaticDFacCorrCoeff(const double c)
|
||||
{
|
||||
this->ctf_properties_.static_dfac_corr_coeff = c;
|
||||
}
|
||||
|
||||
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 +528,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,47 +536,61 @@ 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) {
|
||||
case CTFKind::DeckValue:
|
||||
return "DeckValue";
|
||||
case CTFKind::DeckValue:
|
||||
return "DeckValue";
|
||||
|
||||
case CTFKind::Defaulted:
|
||||
return "Defaulted";
|
||||
case CTFKind::Defaulted:
|
||||
return "Defaulted";
|
||||
}
|
||||
|
||||
throw std::invalid_argument {
|
||||
@ -492,58 +599,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) {
|
||||
this->m_filter_cake = 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 {
|
||||
assert(this->filterCakeActive());
|
||||
return this->m_filter_cake.value();
|
||||
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
|
||||
|
@ -17,126 +17,180 @@
|
||||
along with OPM. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
#include <opm/input/eclipse/Schedule/Well/WDFAC.hpp>
|
||||
|
||||
#include <opm/io/eclipse/rst/well.hpp>
|
||||
#include <opm/output/eclipse/VectorItems/well.hpp>
|
||||
#include <opm/input/eclipse/Parser/ParserKeywords/W.hpp>
|
||||
#include <opm/input/eclipse/Deck/DeckRecord.hpp>
|
||||
|
||||
#include <opm/input/eclipse/Schedule/Well/Connection.hpp>
|
||||
#include <opm/input/eclipse/Schedule/Well/WellConnections.hpp>
|
||||
|
||||
#include <opm/input/eclipse/Units/Dimension.hpp>
|
||||
#include <opm/input/eclipse/Units/UnitSystem.hpp>
|
||||
#include <opm/input/eclipse/Units/Units.hpp>
|
||||
#include <opm/input/eclipse/Schedule/Well/WDFAC.hpp>
|
||||
#include <opm/input/eclipse/Schedule/Well/WellConnections.hpp>
|
||||
|
||||
#include <opm/input/eclipse/Deck/DeckRecord.hpp>
|
||||
|
||||
#include <string>
|
||||
#include <vector>
|
||||
#include <cmath>
|
||||
#include <iostream>
|
||||
#include <opm/input/eclipse/Parser/ParserKeywords/W.hpp>
|
||||
|
||||
#include <algorithm>
|
||||
#include <cassert>
|
||||
#include <cmath>
|
||||
#include <numeric>
|
||||
#include <string>
|
||||
|
||||
namespace {
|
||||
|
||||
double dakeModelDFactor(const double rhoGS,
|
||||
const double gas_visc,
|
||||
const Opm::Connection::CTFProperties& ctf_props)
|
||||
{
|
||||
using namespace Opm::unit;
|
||||
|
||||
// Specific gravity of gas relative to air at standard conditions.
|
||||
constexpr auto rho_air = 1.22*kilogram / cubic(meter);
|
||||
const auto specific_gravity = rhoGS / rho_air;
|
||||
|
||||
return ctf_props.static_dfac_corr_coeff * specific_gravity / gas_visc;
|
||||
}
|
||||
}
|
||||
|
||||
namespace Opm {
|
||||
|
||||
WDFAC::Correlation WDFAC::Correlation::serializationTestObject()
|
||||
{
|
||||
return { 1.23, 0.456, 0.457 };
|
||||
}
|
||||
|
||||
bool WDFAC::Correlation::operator==(const Correlation& other) const
|
||||
{
|
||||
return (this->coeff_a == other.coeff_a)
|
||||
&& (this->exponent_b == other.exponent_b)
|
||||
&& (this->exponent_c == other.exponent_c)
|
||||
;
|
||||
}
|
||||
|
||||
// -------------------------------------------------------------------------
|
||||
|
||||
WDFAC::WDFAC(const RestartIO::RstWell& rst_well)
|
||||
: m_type { WDFacType::NONE }
|
||||
, m_d { 0.0 }
|
||||
, m_corr { rst_well.dfac_corr_coeff_a ,
|
||||
rst_well.dfac_corr_exponent_b ,
|
||||
rst_well.dfac_corr_exponent_c }
|
||||
{
|
||||
if (m_corr.coeff_a > 0.0) {
|
||||
this->m_type = WDFacType::DAKEMODEL;
|
||||
}
|
||||
}
|
||||
|
||||
WDFAC WDFAC::serializationTestObject()
|
||||
{
|
||||
WDFAC result;
|
||||
result.m_a = 1.23;
|
||||
result.m_b = 0.456;
|
||||
result.m_c = 0.457;
|
||||
|
||||
result.m_type = WDFacType::DAKEMODEL;
|
||||
result.m_d = 0.458;
|
||||
result.m_total_cf = 1.0;
|
||||
result.m_type = WDFACTYPE::NONE;
|
||||
result.m_corr = Correlation::serializationTestObject();
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
bool WDFAC::operator==(const WDFAC& other) const {
|
||||
return (m_a == other.m_a)
|
||||
&& (m_b == other.m_b)
|
||||
&& (m_c == other.m_c)
|
||||
&& (m_d == other.m_d)
|
||||
&& (m_total_cf == other.m_total_cf)
|
||||
&& (m_type == other.m_type);
|
||||
}
|
||||
|
||||
void WDFAC::updateWDFAC(const DeckRecord& record) {
|
||||
void WDFAC::updateWDFAC(const DeckRecord& record)
|
||||
{
|
||||
m_d = record.getItem<ParserKeywords::WDFAC::DFACTOR>().getSIDouble(0);
|
||||
m_type = WDFACTYPE::DFACTOR;
|
||||
|
||||
m_type = WDFacType::DFACTOR;
|
||||
}
|
||||
|
||||
void WDFAC::updateWDFACCOR(const DeckRecord& record) {
|
||||
m_a = record.getItem<ParserKeywords::WDFACCOR::A>().getSIDouble(0);
|
||||
m_b = record.getItem<ParserKeywords::WDFACCOR::B>().getSIDouble(0);
|
||||
m_c = record.getItem<ParserKeywords::WDFACCOR::C>().getSIDouble(0);
|
||||
m_type = WDFACTYPE::DAKEMODEL;
|
||||
void WDFAC::updateWDFACCOR(const DeckRecord& record)
|
||||
{
|
||||
this->m_corr.coeff_a = record.getItem<ParserKeywords::WDFACCOR::A>().getSIDouble(0);
|
||||
this->m_corr.exponent_b = record.getItem<ParserKeywords::WDFACCOR::B>().getSIDouble(0);
|
||||
this->m_corr.exponent_c = record.getItem<ParserKeywords::WDFACCOR::C>().getSIDouble(0);
|
||||
|
||||
m_type = WDFacType::DAKEMODEL;
|
||||
}
|
||||
|
||||
void WDFAC::updateWDFACType(const WellConnections& connections) {
|
||||
|
||||
void WDFAC::updateWDFACType(const WellConnections& connections)
|
||||
{
|
||||
const auto non_trivial_dfactor =
|
||||
std::any_of(connections.begin(), connections.end(),
|
||||
[](const auto& conn) { return conn.dFactor() != 0.0; });
|
||||
|
||||
// non-trivial dfactors detected use connection D factors
|
||||
if (non_trivial_dfactor) {
|
||||
m_type = WDFACTYPE::CON_DFACTOR;
|
||||
updateTotalCF(connections);
|
||||
// Non-trivial D-factors detected. Use connection D-factors.
|
||||
m_type = WDFacType::CON_DFACTOR;
|
||||
this->updateTotalCF(connections);
|
||||
}
|
||||
}
|
||||
|
||||
void WDFAC::updateTotalCF(const WellConnections& connections) {
|
||||
m_total_cf = std::accumulate(connections.begin(), connections.end(), 0.0,
|
||||
[](const double tot_cf, const auto& conn) { return tot_cf + conn.CF(); });
|
||||
void WDFAC::updateTotalCF(const WellConnections& connections)
|
||||
{
|
||||
this->m_total_cf = std::accumulate(connections.begin(), connections.end(), 0.0,
|
||||
[](const double tot_cf, const auto& conn) { return tot_cf + conn.CF(); });
|
||||
}
|
||||
|
||||
double WDFAC::getDFactor(const Connection& connection, double mu, double rho, double phi) const {
|
||||
|
||||
switch (m_type)
|
||||
{
|
||||
case WDFACTYPE::NONE:
|
||||
double WDFAC::getDFactor(const double rhoGS,
|
||||
const double gas_visc,
|
||||
const Connection& conn) const
|
||||
{
|
||||
switch (this->m_type) {
|
||||
case WDFacType::NONE:
|
||||
return 0.0;
|
||||
case WDFACTYPE::DFACTOR: {
|
||||
if (m_total_cf < 0.0) {
|
||||
throw std::invalid_argument { "Total connection factor is not set" };
|
||||
}
|
||||
return m_d * m_total_cf / connection.CF();
|
||||
}
|
||||
case WDFACTYPE::CON_DFACTOR: {
|
||||
double d = connection.dFactor();
|
||||
// If a negative d factor is set in COMPDAT individual connection d factors should be used directly.
|
||||
if (d < 0)
|
||||
return -d;
|
||||
// If a positive d factor is set in COMPDAT the connection d factors is treated like a well d factor.
|
||||
// and thus scaled with the connection index
|
||||
if (m_total_cf < 0.0) {
|
||||
throw std::invalid_argument { "Total connection factor is not set" };
|
||||
}
|
||||
|
||||
return d * m_total_cf / connection.CF();
|
||||
}
|
||||
case WDFACTYPE::DAKEMODEL:
|
||||
{
|
||||
double Kh = connection.Kh();
|
||||
double Ke = connection.Ke();
|
||||
double h = Kh / Ke;
|
||||
double rw = connection.rw();
|
||||
const auto k_md = unit::convert::to(Ke, prefix::milli*unit::darcy);
|
||||
double beta = m_a * (std::pow(k_md, m_b) * std::pow(phi, m_c));
|
||||
double specific_gravity = rho / 1.225; // divide by density of air at standard conditions.
|
||||
return beta * specific_gravity * Ke / (h * mu * rw );
|
||||
}
|
||||
default:
|
||||
break;
|
||||
case WDFacType::DFACTOR:
|
||||
return this->scaledWellLevelDFactor(this->m_d, conn);
|
||||
|
||||
case WDFacType::DAKEMODEL:
|
||||
return dakeModelDFactor(rhoGS, gas_visc, conn.ctfProperties());
|
||||
|
||||
case WDFacType::CON_DFACTOR:
|
||||
return this->connectionLevelDFactor(conn);
|
||||
}
|
||||
|
||||
return 0.0;
|
||||
}
|
||||
|
||||
bool WDFAC::useDFactor() const {
|
||||
return m_type != WDFACTYPE::NONE;
|
||||
bool WDFAC::useDFactor() const
|
||||
{
|
||||
return m_type != WDFacType::NONE;
|
||||
}
|
||||
|
||||
bool WDFAC::operator!=(const WDFAC& other) const {
|
||||
return !(*this == other);
|
||||
bool WDFAC::operator==(const WDFAC& other) const
|
||||
{
|
||||
return (this->m_type == other.m_type)
|
||||
&& (this->m_d == other.m_d)
|
||||
&& (this->m_total_cf == other.m_total_cf)
|
||||
&& (this->m_corr == other.m_corr)
|
||||
;
|
||||
}
|
||||
|
||||
double WDFAC::connectionLevelDFactor(const Connection& conn) const
|
||||
{
|
||||
const double d = conn.dFactor();
|
||||
|
||||
// Negative D-factor values in COMPDAT should be used directly as
|
||||
// connection-level D-factors.
|
||||
if (d < 0.0) {
|
||||
return -d;
|
||||
}
|
||||
|
||||
// Positive D-factor values in COMPDAT are treated as well-level
|
||||
// values and scaled with the CTF for translation to connection
|
||||
// level.
|
||||
return this->scaledWellLevelDFactor(d, conn);
|
||||
}
|
||||
|
||||
double WDFAC::scaledWellLevelDFactor(const double dfac,
|
||||
const Connection& conn) const
|
||||
{
|
||||
if (this->m_total_cf < 0.0) {
|
||||
throw std::invalid_argument {
|
||||
"Total well-level connection factor is not set"
|
||||
};
|
||||
}
|
||||
|
||||
return dfac * this->m_total_cf / conn.CF();
|
||||
}
|
||||
}
|
||||
|
@ -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>
|
||||
|
||||
@ -314,7 +313,7 @@ Well::Well(const RestartIO::RstWell& rst_well,
|
||||
injection(std::make_shared<WellInjectionProperties>(unit_system_arg, wname)),
|
||||
wvfpdp(std::make_shared<WVFPDP>()),
|
||||
wvfpexp(explicitTHPOptions(rst_well)),
|
||||
wdfac(std::make_shared<WDFAC>()),
|
||||
wdfac(std::make_shared<WDFAC>(rst_well)),
|
||||
status(status_from_int(rst_well.well_status)),
|
||||
well_temperature(Metric::TemperatureOffset + ParserKeywords::STCOND::TEMPERATURE::defaultValue),
|
||||
well_inj_mult(std::nullopt)
|
||||
@ -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());
|
||||
}
|
||||
|
||||
// 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);
|
||||
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;
|
||||
}
|
||||
new_connections->add(c);
|
||||
|
||||
// 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
|
||||
};
|
||||
}
|
||||
|
||||
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
@ -3,7 +3,8 @@
|
||||
|
||||
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
|
||||
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.
|
||||
|
||||
@ -16,99 +17,129 @@
|
||||
along with OPM. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
#include <cmath>
|
||||
#include <stdexcept>
|
||||
|
||||
#include <opm/io/eclipse/rst/header.hpp>
|
||||
#include <opm/io/eclipse/rst/connection.hpp>
|
||||
|
||||
#include <opm/output/eclipse/VectorItems/connection.hpp>
|
||||
|
||||
#include <opm/input/eclipse/Units/UnitSystem.hpp>
|
||||
|
||||
#include <array>
|
||||
#include <cmath>
|
||||
#include <cstddef>
|
||||
#include <stdexcept>
|
||||
#include <string>
|
||||
|
||||
namespace VI = ::Opm::RestartIO::Helpers::VectorItems;
|
||||
|
||||
namespace Opm {
|
||||
namespace RestartIO {
|
||||
|
||||
namespace {
|
||||
|
||||
template <typename T>
|
||||
T from_int(int);
|
||||
|
||||
template <>
|
||||
Connection::State from_int(int int_state) {
|
||||
if (int_state == 1)
|
||||
return Connection::State::OPEN;
|
||||
|
||||
return Connection::State::SHUT;
|
||||
template<> Opm::Connection::State from_int(int int_state)
|
||||
{
|
||||
return (int_state == 1)
|
||||
? Opm::Connection::State::OPEN
|
||||
: Opm::Connection::State::SHUT;
|
||||
}
|
||||
|
||||
template <>
|
||||
Connection::Direction from_int(int int_dir) {
|
||||
template<> Opm::Connection::Direction from_int(int int_dir)
|
||||
{
|
||||
switch (int_dir) {
|
||||
case 1:
|
||||
return Connection::Direction::X;
|
||||
case 2:
|
||||
return Connection::Direction::Y;
|
||||
case 3:
|
||||
return Connection::Direction::Z;
|
||||
default:
|
||||
throw std::invalid_argument("Can not convert: " + std::to_string(int_dir) + " to string");
|
||||
case 1: return Opm::Connection::Direction::X;
|
||||
case 2: return Opm::Connection::Direction::Y;
|
||||
case 3: return Opm::Connection::Direction::Z;
|
||||
}
|
||||
|
||||
throw std::invalid_argument {
|
||||
"Unable to convert direction value: " +
|
||||
std::to_string(int_dir) + " to Direction category"
|
||||
};
|
||||
}
|
||||
|
||||
/*
|
||||
That the CTFKind variable comes from a float looks extremely suspicious; but
|
||||
it has been double checked ...
|
||||
*/
|
||||
Connection::CTFKind from_float(float float_kind) {
|
||||
if (float_kind == 0)
|
||||
return Connection::CTFKind::Defaulted;
|
||||
|
||||
return Connection::CTFKind::DeckValue;
|
||||
}
|
||||
// Note: CTFKind originates in SCON and is indeed a float.
|
||||
Opm::Connection::CTFKind from_float(float float_kind)
|
||||
{
|
||||
return (float_kind == 0.0f)
|
||||
? Opm::Connection::CTFKind::Defaulted
|
||||
: Opm::Connection::CTFKind::DeckValue;
|
||||
}
|
||||
|
||||
double RstConnection::inverse_peaceman(double cf, double kh, double rw, double skin) {
|
||||
float as_float(const double x)
|
||||
{
|
||||
return static_cast<float>(x);
|
||||
}
|
||||
|
||||
float staticDFactorCorrCoeff(const Opm::UnitSystem& usys,
|
||||
const float coeff)
|
||||
{
|
||||
using M = ::Opm::UnitSystem::measure;
|
||||
|
||||
// Coefficient's units are [D] * [viscosity]
|
||||
return as_float(usys.to_si(M::viscosity, usys.to_si(M::dfactor, coeff)));
|
||||
}
|
||||
|
||||
double pressEquivRadius(const float denom,
|
||||
const float skin,
|
||||
const float rw)
|
||||
{
|
||||
// Recall: denom = log(r0 / rw) + skin
|
||||
return rw * std::exp(denom - skin);
|
||||
}
|
||||
|
||||
} // Anonymous namespace
|
||||
|
||||
double Opm::RestartIO::RstConnection::inverse_peaceman(double cf, double kh, double rw, double skin)
|
||||
{
|
||||
auto alpha = 3.14159265 * 2 * kh / cf - skin;
|
||||
return rw * std::exp(alpha);
|
||||
}
|
||||
|
||||
using M = ::Opm::UnitSystem::measure;
|
||||
using M = ::Opm::UnitSystem::measure;
|
||||
|
||||
RstConnection::RstConnection(const ::Opm::UnitSystem& unit_system, std::size_t rst_index_, int nsconz, const int* icon, const float* scon, const double* xcon) :
|
||||
rst_index( rst_index_),
|
||||
ijk( {icon[VI::IConn::CellI] - 1, icon[VI::IConn::CellJ] - 1, icon[VI::IConn::CellK] - 1}),
|
||||
state( from_int<Connection::State>(icon[VI::IConn::ConnStat])),
|
||||
drain_sat_table( icon[VI::IConn::Drainage]),
|
||||
imb_sat_table( icon[VI::IConn::Imbibition]),
|
||||
completion( icon[VI::IConn::ComplNum]),
|
||||
dir( from_int<Connection::Direction>(icon[VI::IConn::ConnDir])),
|
||||
segment( icon[VI::IConn::Segment]),
|
||||
cf_kind( from_float(1.0)),
|
||||
skin_factor( scon[VI::SConn::SkinFactor]),
|
||||
cf( unit_system.to_si(M::transmissibility, scon[VI::SConn::ConnTrans])),
|
||||
depth( unit_system.to_si(M::length, scon[VI::SConn::Depth])),
|
||||
diameter( unit_system.to_si(M::length, scon[VI::SConn::Diameter])),
|
||||
kh( unit_system.to_si(M::effective_Kh, scon[VI::SConn::EffectiveKH])),
|
||||
segdist_end( unit_system.to_si(M::length, scon[VI::SConn::SegDistEnd])),
|
||||
segdist_start( unit_system.to_si(M::length, scon[VI::SConn::SegDistStart])),
|
||||
oil_rate( unit_system.to_si(M::liquid_surface_rate, xcon[VI::XConn::OilRate])),
|
||||
water_rate( unit_system.to_si(M::liquid_surface_rate, xcon[VI::XConn::WaterRate])),
|
||||
gas_rate( unit_system.to_si(M::gas_surface_rate, xcon[VI::XConn::GasRate])),
|
||||
pressure( unit_system.to_si(M::pressure, xcon[VI::XConn::Pressure])),
|
||||
resv_rate( unit_system.to_si(M::rate, xcon[VI::XConn::ResVRate])),
|
||||
r0( RstConnection::inverse_peaceman(this->cf, this->kh, this->diameter/2, this->skin_factor) )
|
||||
/*
|
||||
r0: The r0 quantity is currently not written or read from the restart
|
||||
file. If the r0 value is given explicitly in the deck it is possible
|
||||
to give a value which is not consistent with the Peaceman formula -
|
||||
that value will be lost when loading back from a restart file.
|
||||
*/
|
||||
Opm::RestartIO::RstConnection::RstConnection(const UnitSystem& unit_system,
|
||||
const std::size_t rst_index_,
|
||||
const int nsconz,
|
||||
const int* icon,
|
||||
const float* scon,
|
||||
const double* xcon)
|
||||
: rst_index { rst_index_ }
|
||||
// -----------------------------------------------------------------
|
||||
// Integer values (ICON)
|
||||
, ijk { icon[VI::IConn::CellI] - 1 ,
|
||||
icon[VI::IConn::CellJ] - 1 ,
|
||||
icon[VI::IConn::CellK] - 1 }
|
||||
, state { from_int<Connection::State>(icon[VI::IConn::ConnStat]) }
|
||||
, drain_sat_table { icon[VI::IConn::Drainage] }
|
||||
, imb_sat_table { icon[VI::IConn::Imbibition] }
|
||||
, completion { icon[VI::IConn::ComplNum] }
|
||||
, dir { from_int<Connection::Direction>(icon[VI::IConn::ConnDir]) }
|
||||
, segment { icon[VI::IConn::Segment] }
|
||||
// -----------------------------------------------------------------
|
||||
// Float values (SCON)
|
||||
, cf_kind { from_float(1.0f) }
|
||||
, skin_factor { scon[VI::SConn::SkinFactor] }
|
||||
, cf { as_float(unit_system.to_si(M::transmissibility, scon[VI::SConn::ConnTrans])) }
|
||||
, depth { as_float(unit_system.to_si(M::length, scon[VI::SConn::Depth])) }
|
||||
, diameter { as_float(unit_system.to_si(M::length, scon[VI::SConn::Diameter])) }
|
||||
, kh { as_float(unit_system.to_si(M::effective_Kh, scon[VI::SConn::EffectiveKH])) }
|
||||
, denom { scon[VI::SConn::CFDenom] }
|
||||
, length { as_float(unit_system.to_si(M::length, scon[VI::SConn::EffectiveLength])) }
|
||||
, static_dfac_corr_coeff { staticDFactorCorrCoeff(unit_system, scon[VI::SConn::StaticDFacCorrCoeff]) }
|
||||
, segdist_end { as_float(unit_system.to_si(M::length, scon[VI::SConn::SegDistEnd])) }
|
||||
, segdist_start { as_float(unit_system.to_si(M::length, scon[VI::SConn::SegDistStart])) }
|
||||
// -----------------------------------------------------------------
|
||||
// Double values (XCON)
|
||||
, oil_rate { unit_system.to_si(M::liquid_surface_rate, xcon[VI::XConn::OilRate]) }
|
||||
, water_rate { unit_system.to_si(M::liquid_surface_rate, xcon[VI::XConn::WaterRate]) }
|
||||
, gas_rate { unit_system.to_si(M::gas_surface_rate, xcon[VI::XConn::GasRate]) }
|
||||
, pressure { unit_system.to_si(M::pressure, xcon[VI::XConn::Pressure]) }
|
||||
, resv_rate { unit_system.to_si(M::rate, xcon[VI::XConn::ResVRate]) }
|
||||
// -----------------------------------------------------------------
|
||||
// Derived quantities
|
||||
, r0 { pressEquivRadius(this->denom, this->skin_factor, this->diameter / 2) }
|
||||
{
|
||||
if (static_cast<std::size_t>(nsconz) > VI::SConn::CFInDeck)
|
||||
if (static_cast<std::size_t>(nsconz) > VI::SConn::CFInDeck) {
|
||||
this->cf_kind = from_float(scon[VI::SConn::CFInDeck]);
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -3,7 +3,8 @@
|
||||
|
||||
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
|
||||
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.
|
||||
|
||||
|
@ -17,17 +17,24 @@
|
||||
along with OPM. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
#include <opm/common/utility/String.hpp>
|
||||
#include <opm/io/eclipse/rst/well.hpp>
|
||||
|
||||
#include <opm/io/eclipse/rst/header.hpp>
|
||||
#include <opm/io/eclipse/rst/connection.hpp>
|
||||
#include <opm/io/eclipse/rst/well.hpp>
|
||||
|
||||
#include <opm/output/eclipse/VectorItems/connection.hpp>
|
||||
#include <opm/output/eclipse/VectorItems/msw.hpp>
|
||||
#include <opm/output/eclipse/VectorItems/well.hpp>
|
||||
|
||||
#include <opm/input/eclipse/Units/UnitSystem.hpp>
|
||||
|
||||
#include <opm/common/utility/String.hpp>
|
||||
|
||||
#include <opm/input/eclipse/Parser/ParserItem.hpp>
|
||||
#include <opm/input/eclipse/Parser/ParserKeyword.hpp>
|
||||
#include <opm/input/eclipse/Parser/ParserRecord.hpp>
|
||||
#include <opm/input/eclipse/Parser/ParserKeywords/W.hpp>
|
||||
|
||||
#include <algorithm>
|
||||
#include <cmath>
|
||||
#include <cstddef>
|
||||
@ -54,28 +61,34 @@ namespace {
|
||||
{
|
||||
return is_sentinel(raw_value) ? raw_value : convert(raw_value);
|
||||
}
|
||||
}
|
||||
|
||||
float dfactor_correlation_coefficient_a(const Opm::UnitSystem& unit_system,
|
||||
const float coeff_a)
|
||||
{
|
||||
const auto dimension = Opm::ParserKeywords::WDFACCOR{}
|
||||
.getRecord(0).get(Opm::ParserKeywords::WDFACCOR::A::itemName)
|
||||
.dimensions().front();
|
||||
|
||||
return static_cast<float>(unit_system.to_si(dimension, coeff_a));
|
||||
}
|
||||
|
||||
constexpr int def_ecl_phase = 1;
|
||||
constexpr int def_pvt_table = 0;
|
||||
} // Anonymous namespace
|
||||
|
||||
namespace VI = ::Opm::RestartIO::Helpers::VectorItems;
|
||||
using M = ::Opm::UnitSystem::measure;
|
||||
|
||||
namespace Opm {
|
||||
namespace RestartIO {
|
||||
|
||||
constexpr int def_ecl_phase = 1;
|
||||
constexpr int def_pvt_table = 0;
|
||||
|
||||
using M = ::Opm::UnitSystem::measure;
|
||||
|
||||
RstWell::RstWell(const ::Opm::UnitSystem& unit_system,
|
||||
const RstHeader& header,
|
||||
const std::string& group_arg,
|
||||
const std::string* zwel,
|
||||
const int * iwel,
|
||||
const float * swel,
|
||||
const double * xwel,
|
||||
const int * icon,
|
||||
const float * scon,
|
||||
const double * xcon) :
|
||||
Opm::RestartIO::RstWell::RstWell(const UnitSystem& unit_system,
|
||||
const RstHeader& header,
|
||||
const std::string& group_arg,
|
||||
const std::string* zwel,
|
||||
const int* iwel,
|
||||
const float* swel,
|
||||
const double* xwel,
|
||||
const int* icon,
|
||||
const float* scon,
|
||||
const double* xcon) :
|
||||
name(rtrim_copy(zwel[0])),
|
||||
group(group_arg),
|
||||
ij( {iwel[VI::IWell::IHead] - 1, iwel[VI::IWell::JHead] - 1}),
|
||||
@ -139,6 +152,9 @@ RstWell::RstWell(const ::Opm::UnitSystem& unit_system,
|
||||
glift_min_rate( unit_system.to_si(M::gas_surface_rate, swel[VI::SWell::LOminRate])),
|
||||
glift_weight_factor( swel[VI::SWell::LOweightFac]),
|
||||
glift_inc_weight_factor( swel[VI::SWell::LOincFac]),
|
||||
dfac_corr_coeff_a(dfactor_correlation_coefficient_a(unit_system, swel[VI::SWell::DFacCorrCoeffA])),
|
||||
dfac_corr_exponent_b( swel[VI::SWell::DFacCorrExpB]),
|
||||
dfac_corr_exponent_c( swel[VI::SWell::DFacCorrExpC]),
|
||||
//
|
||||
oil_rate( unit_system.to_si(M::liquid_surface_rate, xwel[VI::XWell::OilPrRate])),
|
||||
water_rate( unit_system.to_si(M::liquid_surface_rate, xwel[VI::XWell::WatPrRate])),
|
||||
@ -167,66 +183,81 @@ RstWell::RstWell(const ::Opm::UnitSystem& unit_system,
|
||||
gas_void_rate( unit_system.to_si(M::gas_surface_volume, xwel[VI::XWell::GasVoidPrRate]))
|
||||
{
|
||||
|
||||
for (std::size_t tracer_index = 0; tracer_index < static_cast<std::size_t>(header.runspec.tracers().water_tracers()); tracer_index++)
|
||||
this->tracer_concentration_injection.push_back( swel[VI::SWell::TracerOffset + tracer_index] );
|
||||
for (std::size_t tracer_index = 0;
|
||||
tracer_index < static_cast<std::size_t>(header.runspec.tracers().water_tracers());
|
||||
++tracer_index)
|
||||
{
|
||||
this->tracer_concentration_injection.push_back(swel[VI::SWell::TracerOffset + tracer_index]);
|
||||
}
|
||||
|
||||
for (int ic = 0; ic < iwel[VI::IWell::NConn]; ++ic) {
|
||||
const std::size_t icon_offset = ic * header.niconz;
|
||||
const std::size_t scon_offset = ic * header.nsconz;
|
||||
const std::size_t xcon_offset = ic * header.nxconz;
|
||||
|
||||
for (int ic = 0; ic < iwel[VI::IWell::NConn]; ic++) {
|
||||
std::size_t icon_offset = ic * header.niconz;
|
||||
std::size_t scon_offset = ic * header.nsconz;
|
||||
std::size_t xcon_offset = ic * header.nxconz;
|
||||
this->connections.emplace_back( unit_system, ic, header.nsconz, icon + icon_offset, scon + scon_offset, xcon + xcon_offset);
|
||||
this->connections.emplace_back(unit_system, ic, header.nsconz,
|
||||
icon + icon_offset,
|
||||
scon + scon_offset,
|
||||
xcon + xcon_offset);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
RstWell::RstWell(const ::Opm::UnitSystem& unit_system,
|
||||
const RstHeader& header,
|
||||
const std::string& group_arg,
|
||||
const std::string* zwel,
|
||||
const int * iwel,
|
||||
const float * swel,
|
||||
const double * xwel,
|
||||
const int * icon,
|
||||
const float * scon,
|
||||
const double * xcon,
|
||||
const std::vector<int>& iseg,
|
||||
const std::vector<double>& rseg) :
|
||||
RstWell(unit_system, header, group_arg, zwel, iwel, swel, xwel, icon, scon, xcon)
|
||||
Opm::RestartIO::RstWell::RstWell(const UnitSystem& unit_system,
|
||||
const RstHeader& header,
|
||||
const std::string& group_arg,
|
||||
const std::string* zwel,
|
||||
const int* iwel,
|
||||
const float* swel,
|
||||
const double* xwel,
|
||||
const int* icon,
|
||||
const float* scon,
|
||||
const double* xcon,
|
||||
const std::vector<int>& iseg,
|
||||
const std::vector<double>& rseg)
|
||||
: RstWell { unit_system, header, group_arg,
|
||||
zwel, iwel, swel, xwel,
|
||||
icon, scon, xcon }
|
||||
{
|
||||
if (this->msw_index == 0) {
|
||||
return;
|
||||
}
|
||||
|
||||
if (this->msw_index) {
|
||||
std::unordered_map<int, std::size_t> segment_map;
|
||||
for (int is=0; is < header.nsegmx; is++) {
|
||||
std::size_t iseg_offset = header.nisegz * (is + (this->msw_index - 1) * header.nsegmx);
|
||||
std::size_t rseg_offset = header.nrsegz * (is + (this->msw_index - 1) * header.nsegmx);
|
||||
auto other_segment_number = iseg[iseg_offset + VI::ISeg::SegNo];
|
||||
if (other_segment_number != 0) {
|
||||
auto segment_number = is + 1;
|
||||
segment_map.insert({segment_number, this->segments.size()});
|
||||
this->segments.emplace_back( unit_system, segment_number, iseg.data() + iseg_offset, rseg.data() + rseg_offset);
|
||||
}
|
||||
std::unordered_map<int, std::size_t> segment_map;
|
||||
for (int is = 0; is < header.nsegmx; ++is) {
|
||||
const std::size_t iseg_offset = header.nisegz * (is + (this->msw_index - 1)*header.nsegmx);
|
||||
const std::size_t rseg_offset = header.nrsegz * (is + (this->msw_index - 1)*header.nsegmx);
|
||||
const auto other_segment_number = iseg[iseg_offset + VI::ISeg::SegNo];
|
||||
|
||||
if (other_segment_number != 0) {
|
||||
auto segment_number = is + 1;
|
||||
segment_map.insert({segment_number, this->segments.size()});
|
||||
this->segments.emplace_back(unit_system, segment_number,
|
||||
iseg.data() + iseg_offset,
|
||||
rseg.data() + rseg_offset);
|
||||
}
|
||||
}
|
||||
|
||||
for (auto& segment : this->segments) {
|
||||
if (segment.outlet_segment != 0) {
|
||||
auto& outlet_segment = this->segments[ segment_map[segment.outlet_segment] ];
|
||||
outlet_segment.inflow_segments.push_back(segment.segment);
|
||||
}
|
||||
for (auto& segment : this->segments) {
|
||||
if (segment.outlet_segment != 0) {
|
||||
auto& outlet_segment = this->segments[ segment_map[segment.outlet_segment] ];
|
||||
outlet_segment.inflow_segments.push_back(segment.segment);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
const RstSegment&
|
||||
RstWell::segment(int segment_number) const
|
||||
{
|
||||
const auto& iter = std::find_if(this->segments.begin(), this->segments.end(), [segment_number](const RstSegment& segment) { return segment.segment == segment_number; });
|
||||
|
||||
if (iter == this->segments.end())
|
||||
const Opm::RestartIO::RstSegment&
|
||||
Opm::RestartIO::RstWell::segment(int segment_number) const
|
||||
{
|
||||
auto iter = std::find_if(this->segments.begin(), this->segments.end(),
|
||||
[segment_number](const RstSegment& segment)
|
||||
{ return segment.segment == segment_number; });
|
||||
|
||||
if (iter == this->segments.end()) {
|
||||
throw std::invalid_argument("No such segment");
|
||||
}
|
||||
|
||||
return *iter;
|
||||
}
|
||||
|
||||
}} // namepace Opm::RestartIO
|
||||
|
@ -167,6 +167,16 @@ namespace {
|
||||
};
|
||||
}
|
||||
|
||||
double staticDFacCorrCoeff(const Opm::Connection::CTFProperties& ctf_props,
|
||||
const Opm::UnitSystem& units)
|
||||
{
|
||||
using M = Opm::UnitSystem::measure;
|
||||
|
||||
// Coefficient's units are [D] * [viscosity]
|
||||
|
||||
return units.from_si(M::viscosity, units.from_si(M::dfactor, ctf_props.static_dfac_corr_coeff));
|
||||
}
|
||||
|
||||
template <class SConnArray>
|
||||
void staticContrib(const Opm::Connection& conn,
|
||||
const Opm::UnitSystem& units,
|
||||
@ -180,7 +190,7 @@ namespace {
|
||||
return static_cast<float>(units.from_si(u, x));
|
||||
};
|
||||
|
||||
sConn[Ix::ConnTrans] =
|
||||
sConn[Ix::EffConnTrans] = sConn[Ix::ConnTrans] =
|
||||
scprop(M::transmissibility, conn.CF());
|
||||
|
||||
sConn[Ix::Depth] = scprop(M::length, conn.depth());
|
||||
@ -191,8 +201,7 @@ namespace {
|
||||
|
||||
sConn[Ix::SkinFactor] = conn.skinFactor();
|
||||
|
||||
sConn[Ix::item12] = sConn[Ix::ConnTrans];
|
||||
|
||||
sConn[Ix::CFDenom] = conn.ctfProperties().peaceman_denom;
|
||||
|
||||
if (conn.attachedToSegment()) {
|
||||
const auto& [start, end] = *conn.perf_range();
|
||||
@ -202,7 +211,14 @@ namespace {
|
||||
|
||||
sConn[Ix::item30] = -1.0e+20f;
|
||||
sConn[Ix::item31] = -1.0e+20f;
|
||||
sConn[Ix::CFInDeck] = (conn.ctfAssignedFromInput()) ? 1 : 0;
|
||||
|
||||
sConn[Ix::EffectiveLength] =
|
||||
scprop(M::length, conn.connectionLength());
|
||||
|
||||
sConn[Ix::StaticDFacCorrCoeff] =
|
||||
staticDFacCorrCoeff(conn.ctfProperties(), units);
|
||||
|
||||
sConn[Ix::CFInDeck] = conn.ctfAssignedFromInput() ? 1.0f : 0.0f;
|
||||
}
|
||||
|
||||
template <class SConnArray>
|
||||
@ -218,8 +234,15 @@ namespace {
|
||||
return static_cast<float>(units.from_si(u, x));
|
||||
};
|
||||
|
||||
sConn[Ix::item12] = sConn[Ix::ConnTrans] =
|
||||
sConn[Ix::EffConnTrans] = sConn[Ix::ConnTrans] =
|
||||
scprop(M::transmissibility, xconn.trans_factor);
|
||||
|
||||
// xconn.trans_factor == CTFAC == CF * rock compaction. Divide
|
||||
// out the rock compaction contribution to infer the "real"
|
||||
// connection transmissibility factor. No additional unit
|
||||
// conversion needed since the rock compaction effect (keyword
|
||||
// ROCKTAB) is imparted through a dimensionless multiplier.
|
||||
sConn[Ix::ConnTrans] /= xconn.compact_mult;
|
||||
}
|
||||
} // SConn
|
||||
|
||||
@ -314,12 +337,12 @@ AggregateConnectionData(const std::vector<int>& inteHead)
|
||||
|
||||
void
|
||||
Opm::RestartIO::Helpers::AggregateConnectionData::
|
||||
captureDeclaredConnData(const Schedule& sched,
|
||||
const EclipseGrid& grid,
|
||||
const UnitSystem& units,
|
||||
const data::Wells& xw,
|
||||
const SummaryState& summary_state,
|
||||
const std::size_t sim_step)
|
||||
captureDeclaredConnData(const Schedule& sched,
|
||||
const EclipseGrid& grid,
|
||||
const UnitSystem& units,
|
||||
const data::Wells& xw,
|
||||
const SummaryState& summary_state,
|
||||
const std::size_t sim_step)
|
||||
{
|
||||
wellConnectionLoop(sched, sim_step, grid, xw, [&units, &summary_state, this]
|
||||
(const std::string& wellName,
|
||||
|
@ -37,6 +37,7 @@
|
||||
#include <opm/input/eclipse/Schedule/Schedule.hpp>
|
||||
#include <opm/input/eclipse/Schedule/SummaryState.hpp>
|
||||
#include <opm/input/eclipse/Schedule/VFPProdTable.hpp>
|
||||
#include <opm/input/eclipse/Schedule/Well/WDFAC.hpp>
|
||||
#include <opm/input/eclipse/Schedule/Well/Well.hpp>
|
||||
#include <opm/input/eclipse/Schedule/Well/WellConnections.hpp>
|
||||
#include <opm/input/eclipse/Schedule/Well/WellEconProductionLimits.hpp>
|
||||
@ -49,6 +50,11 @@
|
||||
#include <opm/input/eclipse/Units/UnitSystem.hpp>
|
||||
#include <opm/input/eclipse/Units/Units.hpp>
|
||||
|
||||
#include <opm/input/eclipse/Parser/ParserItem.hpp>
|
||||
#include <opm/input/eclipse/Parser/ParserKeyword.hpp>
|
||||
#include <opm/input/eclipse/Parser/ParserRecord.hpp>
|
||||
#include <opm/input/eclipse/Parser/ParserKeywords/W.hpp>
|
||||
|
||||
#include <algorithm>
|
||||
#include <cassert>
|
||||
#include <cmath>
|
||||
@ -1028,6 +1034,26 @@ namespace {
|
||||
sWell[Ix::EfficiencyFactor2] = sWell[Ix::EfficiencyFactor1];
|
||||
}
|
||||
|
||||
template <class SWellArray>
|
||||
void assignDFactorCorrelation(const Opm::Well& well,
|
||||
const Opm::UnitSystem& units,
|
||||
SWellArray& sWell)
|
||||
{
|
||||
using Ix = VI::SWell::index;
|
||||
|
||||
const auto& corr = well.getWDFAC().getDFactorCorrelationCoefficients();
|
||||
|
||||
// D-Factor correlation exponents don't need unit conversion.
|
||||
sWell[Ix::DFacCorrExpB] = corr.exponent_b;
|
||||
sWell[Ix::DFacCorrExpC] = corr.exponent_c;
|
||||
|
||||
const auto dimension = Opm::ParserKeywords::WDFACCOR{}
|
||||
.getRecord(0).get(Opm::ParserKeywords::WDFACCOR::A::itemName)
|
||||
.dimensions().front();
|
||||
|
||||
sWell[Ix::DFacCorrCoeffA] = units.from_si(dimension, corr.coeff_a);
|
||||
}
|
||||
|
||||
template <class SWProp, class SWellArray>
|
||||
void assignBhpVfpAdjustment(const Opm::Well& well,
|
||||
SWProp&& swprop,
|
||||
@ -1094,6 +1120,7 @@ namespace {
|
||||
|
||||
assignWGrupCon(well, sWell);
|
||||
assignEfficiencyFactors(well, sWell);
|
||||
assignDFactorCorrelation(well, units, sWell);
|
||||
assignEconomicLimits(well, swprop, sWell);
|
||||
assignWellTest(well.name(), sched, wtest_state, sim_step, swprop, sWell);
|
||||
assignTracerData(tracers, smry, well.name(), sWell);
|
||||
|
@ -17,32 +17,39 @@
|
||||
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/WDFAC.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 +58,32 @@ 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
|
||||
};
|
||||
|
||||
return connections;
|
||||
}
|
||||
const auto deck = Opm::Parser{}.parseString(compdat_keyword);
|
||||
const auto wdfac = Opm::WDFAC{};
|
||||
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", wdfac, loc);
|
||||
}
|
||||
|
||||
return connections;
|
||||
}
|
||||
}
|
||||
|
||||
namespace Opm {
|
||||
@ -94,12 +113,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 +140,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 +187,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 +218,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
|
||||
|
||||
@ -206,13 +265,18 @@ COPY
|
||||
'PERMX' 'PERMZ' /
|
||||
'PERMX' 'PERMY' /
|
||||
/
|
||||
|
||||
PORO
|
||||
1000*0.3 /
|
||||
|
||||
SCHEDULE
|
||||
|
||||
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));
|
||||
@ -230,13 +294,17 @@ COPY
|
||||
'PERMX' 'PERMY' /
|
||||
/
|
||||
|
||||
PORO
|
||||
1000*0.3 /
|
||||
|
||||
SCHEDULE
|
||||
|
||||
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 +528,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);
|
||||
199,
|
||||
Opm::Connection::State::OPEN,
|
||||
2015.0, ctf_props, 1);
|
||||
|
||||
BOOST_REQUIRE_EQUAL(connP.size(), std::size_t{3});
|
||||
|
||||
@ -506,19 +570,9 @@ 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);
|
||||
198,
|
||||
Opm::Connection::State::OPEN,
|
||||
2015.0, ctf_props, 1);
|
||||
|
||||
BOOST_REQUIRE_EQUAL(connP.size(), std::size_t{4});
|
||||
|
||||
|
@ -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
@ -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);
|
||||
}
|
||||
|
@ -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);
|
||||
}
|
||||
|
@ -14,6 +14,8 @@ COPY
|
||||
PERMX PERMZ /
|
||||
/
|
||||
|
||||
PORO
|
||||
1000*0.3 /
|
||||
|
||||
DX
|
||||
1000*1 /
|
||||
|
@ -16,6 +16,9 @@ COPY
|
||||
PERMX PERMZ /
|
||||
/
|
||||
|
||||
PORO
|
||||
48000*0.3 /
|
||||
|
||||
SCHEDULE
|
||||
|
||||
WELSPECS
|
||||
|
@ -17,6 +17,9 @@ COPY
|
||||
PERMX PERMZ /
|
||||
/
|
||||
|
||||
PORO
|
||||
27000*0.3 /
|
||||
|
||||
SCHEDULE
|
||||
|
||||
|
||||
|
@ -15,6 +15,9 @@ COPY
|
||||
PERMX PERMZ /
|
||||
/
|
||||
|
||||
PORO
|
||||
27000*0.3 /
|
||||
|
||||
SCHEDULE
|
||||
|
||||
|
||||
|
@ -17,6 +17,8 @@ COPY
|
||||
PERMX PERMZ /
|
||||
/
|
||||
|
||||
PORO
|
||||
800*0.3 /
|
||||
|
||||
SCHEDULE
|
||||
|
||||
|
@ -16,6 +16,8 @@ COPY
|
||||
PERMX PERMZ /
|
||||
/
|
||||
|
||||
PORO
|
||||
27000*0.3 /
|
||||
|
||||
SCHEDULE
|
||||
|
||||
|
@ -13,6 +13,9 @@ COPY
|
||||
PERMX PERMZ /
|
||||
/
|
||||
|
||||
PORO
|
||||
72000*0.3 /
|
||||
|
||||
SCHEDULE
|
||||
|
||||
-- 0
|
||||
|
@ -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));
|
||||
}
|
||||
|
||||
|
@ -25,6 +25,7 @@
|
||||
|
||||
#include <opm/output/eclipse/AggregateMSWData.hpp>
|
||||
#include <opm/output/eclipse/AggregateWellData.hpp>
|
||||
|
||||
#include <opm/output/eclipse/VectorItems/connection.hpp>
|
||||
#include <opm/output/eclipse/VectorItems/intehead.hpp>
|
||||
#include <opm/output/eclipse/VectorItems/well.hpp>
|
||||
@ -34,70 +35,100 @@
|
||||
|
||||
#include <opm/output/data/Wells.hpp>
|
||||
|
||||
#include <opm/input/eclipse/Deck/Deck.hpp>
|
||||
#include <opm/input/eclipse/Parser/Parser.hpp>
|
||||
#include <opm/input/eclipse/EclipseState/EclipseState.hpp>
|
||||
|
||||
#include <opm/input/eclipse/Python/Python.hpp>
|
||||
|
||||
#include <opm/input/eclipse/Schedule/Schedule.hpp>
|
||||
#include <opm/input/eclipse/Schedule/SummaryState.hpp>
|
||||
#include <opm/input/eclipse/Schedule/Well/Well.hpp>
|
||||
#include <opm/input/eclipse/Schedule/Well/WellConnections.hpp>
|
||||
#include <opm/input/eclipse/Python/Python.hpp>
|
||||
|
||||
#include <opm/input/eclipse/Units/Units.hpp>
|
||||
|
||||
#include <opm/common/utility/TimeService.hpp>
|
||||
|
||||
#include <opm/input/eclipse/Deck/Deck.hpp>
|
||||
|
||||
#include <opm/input/eclipse/Parser/Parser.hpp>
|
||||
|
||||
#include <cmath>
|
||||
#include <cstddef>
|
||||
#include <exception>
|
||||
#include <memory>
|
||||
#include <stdexcept>
|
||||
#include <string>
|
||||
#include <tuple>
|
||||
#include <utility>
|
||||
#include <vector>
|
||||
|
||||
struct MockIH
|
||||
{
|
||||
MockIH(const int numWells,
|
||||
namespace {
|
||||
struct MockIH
|
||||
{
|
||||
MockIH(const int numWells,
|
||||
const int nsegWell = 1, // E100
|
||||
const int ncwMax = 20,
|
||||
const int iConnPerConn = 25, // NICONZ
|
||||
const int sConnPerConn = 41, // NSCONZ
|
||||
const int xConnPerConn = 58); // NXCONZ
|
||||
|
||||
const int nsegWell = 1, // E100
|
||||
const int ncwMax = 20,
|
||||
const int iConnPerConn = 25, // NICONZ
|
||||
const int sConnPerConn = 41, // NSCONZ
|
||||
const int xConnPerConn = 58); // NXCONZ
|
||||
std::vector<int> value;
|
||||
|
||||
using Sz = std::vector<int>::size_type;
|
||||
|
||||
std::vector<int> value;
|
||||
Sz nwells;
|
||||
Sz nsegwl;
|
||||
Sz nsegmx;
|
||||
Sz nswlmx;
|
||||
Sz ncwmax;
|
||||
Sz niconz;
|
||||
Sz nsconz;
|
||||
Sz nxconz;
|
||||
};
|
||||
|
||||
using Sz = std::vector<int>::size_type;
|
||||
MockIH::MockIH(const int numWells,
|
||||
const int nsegWell,
|
||||
const int ncwMax,
|
||||
const int iConnPerConn,
|
||||
const int sConnPerConn,
|
||||
const int xConnPerConn)
|
||||
: value(411, 0)
|
||||
{
|
||||
using Ix = ::Opm::RestartIO::Helpers::VectorItems::intehead;
|
||||
|
||||
Sz nwells;
|
||||
Sz nsegwl;
|
||||
Sz nsegmx;
|
||||
Sz nswlmx;
|
||||
Sz ncwmax;
|
||||
Sz niconz;
|
||||
Sz nsconz;
|
||||
Sz nxconz;
|
||||
};
|
||||
this->nwells = this->value[Ix::NWELLS] = numWells;
|
||||
|
||||
MockIH::MockIH(const int numWells,
|
||||
const int nsegWell,
|
||||
const int /* ncwMax */,
|
||||
const int iConnPerConn,
|
||||
const int sConnPerConn,
|
||||
const int xConnPerConn)
|
||||
: value(411, 0)
|
||||
{
|
||||
using Ix = ::Opm::RestartIO::Helpers::VectorItems::intehead;
|
||||
this->nsegwl = this->value[Ix::NSEGWL] = nsegWell;
|
||||
this->ncwmax = this->value[Ix::NCWMAX] = ncwMax;
|
||||
this->nswlmx = this->value[Ix::NSWLMX] = nsegWell;
|
||||
this->nsegmx = this->value[Ix::NSEGMX] = 32;
|
||||
this->niconz = this->value[Ix::NICONZ] = iConnPerConn;
|
||||
this->nsconz = this->value[Ix::NSCONZ] = sConnPerConn;
|
||||
this->nxconz = this->value[Ix::NXCONZ] = xConnPerConn;
|
||||
}
|
||||
|
||||
this->nwells = this->value[Ix::NWELLS] = numWells;
|
||||
struct SimulationCase
|
||||
{
|
||||
explicit SimulationCase(const Opm::Deck& deck)
|
||||
: es (deck)
|
||||
, grid (deck)
|
||||
, sched(deck, es, std::make_shared<Opm::Python>())
|
||||
{}
|
||||
|
||||
this->nsegwl = this->value[Ix::NSEGWL] = nsegWell;
|
||||
this->ncwmax = this->value[Ix::NCWMAX] = 20;
|
||||
this->nswlmx = this->value[Ix::NSWLMX] = 1;
|
||||
this->nsegmx = this->value[Ix::NSEGMX] = 32;
|
||||
this->niconz = this->value[Ix::NICONZ] = iConnPerConn;
|
||||
this->nsconz = this->value[Ix::NSCONZ] = sConnPerConn;
|
||||
this->nxconz = this->value[Ix::NXCONZ] = xConnPerConn;
|
||||
}
|
||||
// Order requirement: 'es' must be declared/initialised before 'sched'.
|
||||
Opm::EclipseState es;
|
||||
Opm::EclipseGrid grid;
|
||||
Opm::Schedule sched;
|
||||
};
|
||||
|
||||
} // Anonymous namespace
|
||||
|
||||
// =====================================================================
|
||||
|
||||
BOOST_AUTO_TEST_SUITE(Aggregate_ConnData)
|
||||
|
||||
namespace {
|
||||
|
||||
Opm::Deck first_sim()
|
||||
{
|
||||
// Mostly copy of tests/FIRST_SIM.DATA
|
||||
@ -474,7 +505,8 @@ END
|
||||
return Opm::Parser{}.parseString(input);
|
||||
}
|
||||
|
||||
std::pair<Opm::data::Wells, Opm::SummaryState> wr(const Opm::Schedule& sched)
|
||||
std::pair<Opm::data::Wells, Opm::SummaryState>
|
||||
wr(const Opm::Schedule& sched)
|
||||
{
|
||||
using o = ::Opm::data::Rates::opt;
|
||||
|
||||
@ -502,6 +534,7 @@ END
|
||||
c.pressure = 215.0;
|
||||
c.index = connections[i].global_index();
|
||||
c.trans_factor = connections[i].CF();
|
||||
c.compact_mult = 0.875;
|
||||
|
||||
const auto& global_index = connections[i].global_index();
|
||||
sum_state.update_conn_var("PROD", "CWPR", global_index + 1, qw * (i + 1));
|
||||
@ -543,6 +576,7 @@ END
|
||||
c.pressure = 218.0;
|
||||
c.index = connections[i].global_index();
|
||||
c.trans_factor = connections[i].CF();
|
||||
c.compact_mult = 0.987;
|
||||
|
||||
const auto& global_index = connections[i].global_index();
|
||||
sum_state.update_conn_var("WINJ", "CWIR", global_index+ 1, qw*(i + 1));
|
||||
@ -562,24 +596,8 @@ END
|
||||
|
||||
return { std::move(xw), std::move(sum_state) };
|
||||
}
|
||||
} // namespace
|
||||
|
||||
struct SimulationCase {
|
||||
explicit SimulationCase(const Opm::Deck& deck)
|
||||
: es (deck)
|
||||
, grid (deck)
|
||||
, sched(deck, es, std::make_shared<Opm::Python>())
|
||||
{}
|
||||
|
||||
// Order requirement: 'es' must be declared/initialised before 'sched'.
|
||||
Opm::EclipseState es;
|
||||
Opm::EclipseGrid grid;
|
||||
Opm::Schedule sched;
|
||||
};
|
||||
|
||||
// =====================================================================
|
||||
|
||||
BOOST_AUTO_TEST_SUITE(Aggregate_ConnData)
|
||||
} // Anonymous namespace
|
||||
|
||||
// test dimensions of Connection data
|
||||
BOOST_AUTO_TEST_CASE (Constructor)
|
||||
@ -683,40 +701,46 @@ BOOST_AUTO_TEST_CASE(Declared_Connection_Data)
|
||||
const auto& sconn = amconn.getSConn();
|
||||
int connNo = 1;
|
||||
auto i0 = (connNo - 1) * ih.nsconz;
|
||||
BOOST_CHECK_CLOSE(sconn[i0 + Ix::ConnTrans], 2.55826545, 1.0e-5); // PROD - conn 1 : Transmissibility factor
|
||||
BOOST_CHECK_CLOSE(sconn[i0 + Ix::EffConnTrans], 2.55826545, 1.0e-5); // PROD - conn 1 : Effective transmissibility factor
|
||||
BOOST_CHECK_CLOSE(sconn[i0 + Ix::Depth], 7050., 1.0e-5); // PROD - conn 1 : Centre depth
|
||||
BOOST_CHECK_CLOSE(sconn[i0 + Ix::Diameter], 0.20, 1.0e-5); // PROD - conn 1 : diameter
|
||||
BOOST_CHECK_CLOSE(sconn[i0 + Ix::EffectiveKH], 1581.13879, 1.0e-5); // PROD - conn 1 : effective kh-product
|
||||
BOOST_CHECK_CLOSE(sconn[i0 + Ix::item12], 2.55826545, 1.0e-5); // PROD - conn 1 : Transmissibility factor
|
||||
BOOST_CHECK_CLOSE(sconn[i0 + Ix::CFDenom], 4.37696314, 1.0e-5);
|
||||
BOOST_CHECK_CLOSE(sconn[i0 + Ix::ConnTrans], 2.55826545 / 0.875, 1.0e-5); // PROD - conn 1 : Transmissibility factor
|
||||
BOOST_CHECK_CLOSE(
|
||||
sconn[i0 + Ix::SegDistEnd], 130., 1.0e-5); // PROD - conn 1 : Distance to end of connection in segment
|
||||
BOOST_CHECK_CLOSE(
|
||||
sconn[i0 + Ix::SegDistStart], 30., 1.0e-5); // PROD - conn 1 : Distance to start of connection in segment
|
||||
BOOST_CHECK_CLOSE(sconn[i0 + Ix::EffectiveLength], 100.0, 1.0e-5);
|
||||
|
||||
// Well no 2 - WINJ well
|
||||
connNo = 3;
|
||||
i0 = ih.ncwmax * ih.nsconz + (connNo - 1) * ih.nsconz;
|
||||
BOOST_CHECK_CLOSE(sconn[i0 + Ix::ConnTrans], 2.55826545, 1.0e-5); // WINJ - conn 3 : Transmissibility factor
|
||||
BOOST_CHECK_CLOSE(sconn[i0 + Ix::EffConnTrans], 2.55826545, 1.0e-5); // WINJ - conn 3 : Effective transmissibility factor
|
||||
BOOST_CHECK_CLOSE(sconn[i0 + Ix::Depth], 7250., 1.0e-5); // WINJ - conn 3 : Centre depth
|
||||
BOOST_CHECK_CLOSE(sconn[i0 + Ix::Diameter], 0.20, 1.0e-5); // WINJ - conn 3 : diameter
|
||||
BOOST_CHECK_CLOSE(sconn[i0 + Ix::EffectiveKH], 1581.13879, 1.0e-5); // WINJ - conn 3 : effective kh-product
|
||||
BOOST_CHECK_CLOSE(sconn[i0 + Ix::item12], 2.55826545, 1.0e-5); // WINJ - conn 3 : Transmissibility factor
|
||||
BOOST_CHECK_CLOSE(sconn[i0 + Ix::CFDenom], 4.37696314, 1.0e-5);
|
||||
BOOST_CHECK_CLOSE(sconn[i0 + Ix::ConnTrans], 2.55826545 / 0.987, 1.0e-5); // WINJ - conn 3 : Transmissibility factor
|
||||
BOOST_CHECK_CLOSE(
|
||||
sconn[i0 + Ix::SegDistEnd], 0., 1.0e-5); // WINJ - conn 3 : Distance to end of connection in segment
|
||||
BOOST_CHECK_CLOSE(
|
||||
sconn[i0 + Ix::SegDistStart], 0., 1.0e-5); // WINJ - conn 3 : Distance to start of connection in segment
|
||||
BOOST_CHECK_CLOSE(sconn[i0 + Ix::EffectiveLength], 100.0, 1.0e-5);
|
||||
|
||||
connNo = 4;
|
||||
i0 = ih.ncwmax * ih.nsconz + (connNo - 1) * ih.nsconz;
|
||||
BOOST_CHECK_CLOSE(sconn[i0 + Ix::ConnTrans], 2.55826545, 1.0e-5); // WINJ - conn 4 : Transmissibility factor
|
||||
BOOST_CHECK_CLOSE(sconn[i0 + Ix::EffConnTrans], 2.55826545, 1.0e-5); // WINJ - conn 4 : Effective transmissibility factor
|
||||
BOOST_CHECK_CLOSE(sconn[i0 + Ix::Depth], 7250., 1.0e-5); // WINJ - conn 4 : Centre depth
|
||||
BOOST_CHECK_CLOSE(sconn[i0 + Ix::Diameter], 0.20, 1.0e-5); // WINJ - conn 4 : diameter
|
||||
BOOST_CHECK_CLOSE(sconn[i0 + Ix::EffectiveKH], 1581.13879, 1.0e-5); // WINJ - conn 4 : effective kh-product
|
||||
BOOST_CHECK_CLOSE(sconn[i0 + Ix::item12], 2.55826545, 1.0e-5); // WINJ - conn 4 : Transmissibility factor
|
||||
BOOST_CHECK_CLOSE(sconn[i0 + Ix::CFDenom], 4.37696314, 1.0e-5);
|
||||
BOOST_CHECK_CLOSE(sconn[i0 + Ix::ConnTrans], 2.55826545 / 0.987, 1.0e-5); // WINJ - conn 4 : Transmissibility factor
|
||||
BOOST_CHECK_CLOSE(
|
||||
sconn[i0 + Ix::SegDistEnd], 0., 1.0e-5); // WINJ - conn 4 : Distance to end of connection in segment
|
||||
BOOST_CHECK_CLOSE(
|
||||
sconn[i0 + Ix::SegDistStart], 0., 1.0e-5); // WINJ - conn 4 : Distance to start of connection in segment
|
||||
BOOST_CHECK_CLOSE(sconn[i0 + Ix::EffectiveLength], 100.0, 1.0e-5);
|
||||
}
|
||||
|
||||
// XCONN (PROD) + (WINJ)
|
||||
@ -808,10 +832,12 @@ BOOST_AUTO_TEST_CASE(Declared_Connection_Data)
|
||||
}
|
||||
}
|
||||
|
||||
BOOST_AUTO_TEST_CASE(InactiveCell) {
|
||||
BOOST_AUTO_TEST_CASE(InactiveCell)
|
||||
{
|
||||
auto simCase = SimulationCase{first_sim()};
|
||||
const auto rptStep = std::size_t{1};
|
||||
const auto ih = MockIH {static_cast<int>(simCase.sched.getWells(rptStep).size())};
|
||||
|
||||
const auto& [wrc, sum_state] = wr(simCase.sched);
|
||||
auto conn0 = Opm::RestartIO::Helpers::AggregateConnectionData{ih.value};
|
||||
conn0.captureDeclaredConnData(simCase.sched,
|
||||
@ -819,11 +845,10 @@ BOOST_AUTO_TEST_CASE(InactiveCell) {
|
||||
simCase.es.getUnits(),
|
||||
wrc,
|
||||
sum_state,
|
||||
rptStep
|
||||
);
|
||||
rptStep);
|
||||
|
||||
std::vector<int> actnum(500, 1);
|
||||
// Here we deactive the cell holding connection number 2.
|
||||
std::vector<int> actnum(500, 1);
|
||||
actnum[simCase.grid.getGlobalIndex(2,4,1)] = 0;
|
||||
simCase.grid.resetACTNUM(actnum);
|
||||
|
||||
@ -833,62 +858,330 @@ BOOST_AUTO_TEST_CASE(InactiveCell) {
|
||||
simCase.es.getUnits(),
|
||||
wrc,
|
||||
sum_state,
|
||||
rptStep
|
||||
);
|
||||
rptStep);
|
||||
|
||||
const std::size_t num_test_connections = 4;
|
||||
|
||||
{
|
||||
using IC = ::Opm::RestartIO::Helpers::VectorItems::IConn::index;
|
||||
const auto iconn0 = conn0.getIConn();
|
||||
const auto iconn1 = conn1.getIConn();
|
||||
for (std::size_t conn_index = 0; conn_index < num_test_connections; conn_index++) {
|
||||
std::size_t offset1 = conn_index * ih.niconz;
|
||||
std::size_t offset0 = offset1;
|
||||
using IC = ::Opm::RestartIO::Helpers::VectorItems::IConn::index;
|
||||
|
||||
if (conn_index >= 2)
|
||||
offset0 += ih.niconz;
|
||||
const auto iconn0 = conn0.getIConn();
|
||||
const auto iconn1 = conn1.getIConn();
|
||||
|
||||
for (std::size_t elm_index = 0; elm_index < ih.niconz; elm_index++) {
|
||||
if (elm_index == IC::SeqIndex && conn_index >= 2) {
|
||||
// Comparing the connection ID - which should be different;
|
||||
BOOST_CHECK_EQUAL(iconn1[offset1 + elm_index] + 1 , iconn0[offset0 + elm_index]);
|
||||
} else
|
||||
BOOST_CHECK_EQUAL(iconn1[offset1 + elm_index], iconn0[offset0 + elm_index]);
|
||||
for (std::size_t conn_index = 0; conn_index < num_test_connections; ++conn_index) {
|
||||
const std::size_t offset1 = conn_index * ih.niconz;
|
||||
const std::size_t offset0 = offset1 + (conn_index >= 2)*ih.niconz;
|
||||
|
||||
for (std::size_t elm_index = 0; elm_index < ih.niconz; ++elm_index) {
|
||||
if (elm_index == IC::SeqIndex && conn_index >= 2) {
|
||||
// Comparing the connection ID - which should be different;
|
||||
BOOST_CHECK_EQUAL(iconn1[offset1 + elm_index] + 1,
|
||||
iconn0[offset0 + elm_index]);
|
||||
}
|
||||
else {
|
||||
BOOST_CHECK_EQUAL(iconn1[offset1 + elm_index],
|
||||
iconn0[offset0 + elm_index]);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
{
|
||||
const auto sconn0 = conn0.getSConn();
|
||||
const auto sconn1 = conn1.getSConn();
|
||||
for (std::size_t conn_index = 0; conn_index < num_test_connections; conn_index++) {
|
||||
std::size_t offset1 = conn_index * ih.nsconz;
|
||||
std::size_t offset0 = offset1;
|
||||
|
||||
if (conn_index >= 2)
|
||||
offset0 += ih.nsconz;
|
||||
for (std::size_t conn_index = 0; conn_index < num_test_connections; ++conn_index) {
|
||||
const std::size_t offset1 = conn_index * ih.nsconz;
|
||||
const std::size_t offset0 = offset1 + (conn_index >= 2)*ih.nsconz;
|
||||
|
||||
for (std::size_t elm_index = 0; elm_index < ih.nsconz; elm_index++)
|
||||
BOOST_CHECK_EQUAL(sconn1[offset1 + elm_index], sconn0[offset0 + elm_index]);
|
||||
for (std::size_t elm_index = 0; elm_index < ih.nsconz; ++elm_index) {
|
||||
BOOST_CHECK_EQUAL(sconn1[offset1 + elm_index],
|
||||
sconn0[offset0 + elm_index]);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
{
|
||||
const auto xconn0 = conn0.getXConn();
|
||||
const auto xconn1 = conn1.getXConn();
|
||||
for (std::size_t conn_index = 0; conn_index < num_test_connections; conn_index++) {
|
||||
|
||||
for (std::size_t conn_index = 0; conn_index < num_test_connections; ++conn_index) {
|
||||
std::size_t offset1 = conn_index * ih.nxconz;
|
||||
std::size_t offset0 = offset1;
|
||||
|
||||
if (conn_index >= 2)
|
||||
if (conn_index >= 2) {
|
||||
offset0 += ih.nxconz;
|
||||
}
|
||||
|
||||
for (std::size_t elm_index = 0; elm_index < ih.nxconz; elm_index++)
|
||||
BOOST_CHECK_EQUAL(xconn1[offset1 + elm_index], xconn0[offset0 + elm_index]);
|
||||
for (std::size_t elm_index = 0; elm_index < ih.nxconz; ++elm_index) {
|
||||
BOOST_CHECK_EQUAL(xconn1[offset1 + elm_index],
|
||||
xconn0[offset0 + elm_index]);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
BOOST_AUTO_TEST_SUITE_END()
|
||||
BOOST_AUTO_TEST_SUITE_END() // Aggregate_ConnData
|
||||
|
||||
// ---------------------------------------------------------------------------
|
||||
|
||||
BOOST_AUTO_TEST_SUITE(DFactor_Correlation)
|
||||
|
||||
namespace {
|
||||
|
||||
SimulationCase wdfaccorCase()
|
||||
{
|
||||
return SimulationCase { Opm::Parser{}.parseString(R"(
|
||||
DIMENS
|
||||
10 10 10 /
|
||||
|
||||
START -- 0
|
||||
19 JUN 2007 /
|
||||
|
||||
GRID
|
||||
|
||||
DXV
|
||||
10*100.0 /
|
||||
DYV
|
||||
10*100.0 /
|
||||
DZV
|
||||
10*10.0 /
|
||||
DEPTHZ
|
||||
121*2000.0 /
|
||||
|
||||
PORO
|
||||
1000*0.1 /
|
||||
PERMX
|
||||
1000*1 /
|
||||
PERMY
|
||||
1000*0.1 /
|
||||
PERMZ
|
||||
1000*0.01 /
|
||||
|
||||
SCHEDULE
|
||||
|
||||
DATES -- 1
|
||||
10 OKT 2008 /
|
||||
/
|
||||
|
||||
WELSPECS
|
||||
'W1' 'G1' 3 3 2873.94 'WATER' 0.00 'STD' 'SHUT' 'NO' 0 'SEG' /
|
||||
'W2' 'G2' 5 5 1 'OIL' 0.00 'STD' 'SHUT' 'NO' 0 'SEG' /
|
||||
/
|
||||
|
||||
COMPDAT
|
||||
'W1' 3 3 1 1 'OPEN' 1* 32.948 0.311 3047.839 1* 1* 'X' 22.100 /
|
||||
'W2' 3 3 2 2 'OPEN' 1* 32.948 0.311 3047.839 1* 1* 'X' 22.100 /
|
||||
/
|
||||
|
||||
WDFACCOR
|
||||
'W2' 1.984e-7 -1.1045 0.0 /
|
||||
/
|
||||
|
||||
WCONINJE
|
||||
'W1' 'WATER' 'OPEN' 'RATE' 4000.0 1* 850.0 /
|
||||
/
|
||||
|
||||
WCONPROD
|
||||
'W2' 'OPEN' 'ORAT' 5000.0 4* 20.0 /
|
||||
/
|
||||
|
||||
DATES -- 2
|
||||
12 NOV 2008 /
|
||||
/
|
||||
|
||||
END
|
||||
)") };
|
||||
}
|
||||
|
||||
std::pair<Opm::data::Wells, Opm::SummaryState>
|
||||
dynamicState(const Opm::Schedule& sched)
|
||||
{
|
||||
auto dyn_state = std::pair<Opm::data::Wells, Opm::SummaryState> {
|
||||
std::piecewise_construct,
|
||||
std::forward_as_tuple(),
|
||||
std::forward_as_tuple(Opm::TimeService::now())
|
||||
};
|
||||
|
||||
using o = ::Opm::data::Rates::opt;
|
||||
|
||||
auto& [xw, sum_state] = dyn_state;
|
||||
|
||||
const double qv = 12.34*Opm::unit::cubic(Opm::unit::meter)/Opm::unit::day;
|
||||
|
||||
{
|
||||
const auto wname = std::string { "W2" };
|
||||
|
||||
xw[wname].rates.set(o::wat, 1.0).set(o::oil, 2.0).set(o::gas, 3.0);
|
||||
xw[wname].bhp = 213.0*Opm::unit::barsa;
|
||||
|
||||
{
|
||||
const double qw = 4.0*Opm::unit::cubic(Opm::unit::meter)/Opm::unit::day;
|
||||
const double qo = 5.0*Opm::unit::cubic(Opm::unit::meter)/Opm::unit::day;
|
||||
const double qg = 50.0*Opm::unit::cubic(Opm::unit::meter)/Opm::unit::day;
|
||||
|
||||
const auto& well = sched.getWell(wname, 1);
|
||||
const auto& connections = well.getConnections();
|
||||
for (auto i = 0*connections.size(); i < connections.size(); ++i) {
|
||||
auto& c = xw[wname].connections.emplace_back();
|
||||
|
||||
c.rates
|
||||
.set(o::wat, qw * (float(i) + 1.0)*Opm::unit::cubic(Opm::unit::meter)/Opm::unit::day)
|
||||
.set(o::oil, qo * (float(i) + 1.0)*Opm::unit::cubic(Opm::unit::meter)/Opm::unit::day)
|
||||
.set(o::gas, qg * (float(i) + 1.0)*Opm::unit::cubic(Opm::unit::meter)/Opm::unit::day);
|
||||
c.pressure = 215.0*Opm::unit::barsa;
|
||||
c.index = connections[i].global_index();
|
||||
c.trans_factor = connections[i].CF();
|
||||
c.cell_pressure = 200.0*Opm::unit::barsa;
|
||||
c.cell_saturation_water = 0.55;
|
||||
c.cell_saturation_gas =.038;
|
||||
c.effective_Kh = 100*Opm::prefix::milli*Opm::unit::darcy*Opm::unit::meter;
|
||||
c.d_factor = 3.0e-6*Opm::unit::day/Opm::unit::cubic(Opm::unit::meter);
|
||||
c.compact_mult = 0.875;
|
||||
|
||||
const auto& global_index = connections[i].global_index();
|
||||
sum_state.update_conn_var(wname, "CWPR", global_index + 1, qw * (i + 1));
|
||||
sum_state.update_conn_var(wname, "COPR", global_index + 1, qo * (i + 1));
|
||||
sum_state.update_conn_var(wname, "CGPR", global_index + 1, qg * (i + 1));
|
||||
sum_state.update_conn_var(wname, "CVPR", global_index + 1, qv * (i + 1));
|
||||
|
||||
sum_state.update_conn_var(wname, "COPT", global_index + 1, qo * (i + 1) * 2.0);
|
||||
sum_state.update_conn_var(wname, "CWPT", global_index + 1, qw * (i + 1) * 2.0);
|
||||
sum_state.update_conn_var(wname, "CGPT", global_index + 1, qg * (i + 1) * 2.0);
|
||||
sum_state.update_conn_var(wname, "CVPT", global_index + 1, qv * (i + 1) * 2.0);
|
||||
|
||||
sum_state.update_conn_var(wname, "CGOR", global_index + 1, qg / qo);
|
||||
|
||||
sum_state.update_conn_var(wname, "CPR", global_index + 1, 215.0);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
{
|
||||
const auto wname = std::string { "W1" };
|
||||
|
||||
const auto& well = sched.getWell(wname, 1);
|
||||
const auto& connections = well.getConnections();
|
||||
|
||||
xw[wname].bhp = 234.0*Opm::unit::barsa;
|
||||
xw[wname].rates
|
||||
.set(o::wat, 5.0*Opm::unit::cubic(Opm::unit::meter)/Opm::unit::day)
|
||||
.set(o::oil, 0.0*Opm::unit::cubic(Opm::unit::meter)/Opm::unit::day)
|
||||
.set(o::gas, 0.0*Opm::unit::cubic(Opm::unit::meter)/Opm::unit::day);
|
||||
|
||||
const double qw = 7.0;
|
||||
for (auto i = 0*connections.size(); i < connections.size(); ++i) {
|
||||
xw[wname].connections.emplace_back();
|
||||
auto& c = xw[wname].connections.back();
|
||||
|
||||
c.rates.set(o::wat, qw * (float(i) + 1.0)).set(o::oil, 0.0).set(o::gas, 0.0);
|
||||
c.pressure = 218.0*Opm::unit::barsa;
|
||||
c.index = connections[i].global_index();
|
||||
c.trans_factor = connections[i].CF();
|
||||
c.cell_pressure = 230.0*Opm::unit::barsa;
|
||||
c.cell_saturation_water = 0.15;
|
||||
c.cell_saturation_gas = 0.50;
|
||||
c.effective_Kh = 100*Opm::prefix::milli*Opm::unit::darcy*Opm::unit::meter;
|
||||
c.d_factor = 3.0e-6*Opm::unit::day/Opm::unit::cubic(Opm::unit::meter);
|
||||
c.compact_mult = 0.987;
|
||||
|
||||
const auto& global_index = connections[i].global_index();
|
||||
sum_state.update_conn_var(wname, "CWIR", global_index+ 1, qw*(i + 1));
|
||||
sum_state.update_conn_var(wname, "COIR", global_index+ 1, 0.0);
|
||||
sum_state.update_conn_var(wname, "CGIR", global_index+ 1, 0.0);
|
||||
sum_state.update_conn_var(wname, "CVIR", global_index+ 1, qv*(i + 1));
|
||||
|
||||
sum_state.update_conn_var(wname, "COIT", global_index + 1, 543.21 * (i + 1));
|
||||
sum_state.update_conn_var(wname, "CWIT", global_index + 1, qw * (i + 1) * 2.0);
|
||||
sum_state.update_conn_var(wname, "CGIT", global_index + 1, 9876.54 * (i + 1));
|
||||
sum_state.update_conn_var(wname, "CVIT", global_index + 1, qv * (i + 1) * 2.0);
|
||||
|
||||
sum_state.update_conn_var(wname, "CPR", global_index + 1, 218.0);
|
||||
}
|
||||
}
|
||||
|
||||
return dyn_state;
|
||||
}
|
||||
|
||||
} // Anonymous namespace
|
||||
|
||||
BOOST_AUTO_TEST_CASE(Basic)
|
||||
{
|
||||
const auto cse = wdfaccorCase();
|
||||
|
||||
const auto ih = MockIH { 2, 0, 1 };
|
||||
|
||||
const auto& [wrc, sum_state] = dynamicState(cse.sched);
|
||||
|
||||
auto amconn = Opm::RestartIO::Helpers::AggregateConnectionData {ih.value};
|
||||
|
||||
{
|
||||
const auto rptStep = std::size_t {0};
|
||||
|
||||
amconn.captureDeclaredConnData(cse.sched,
|
||||
cse.grid,
|
||||
cse.es.getUnits(),
|
||||
wrc, sum_state, rptStep);
|
||||
|
||||
// W1 (injector)
|
||||
{
|
||||
using Ix = ::Opm::RestartIO::Helpers::VectorItems::SConn::index;
|
||||
const auto& sconn = amconn.getSConn();
|
||||
|
||||
const auto wellNo = 1;
|
||||
const auto connNo = 1;
|
||||
const auto wellStart = (wellNo - 1) * ih.ncwmax * ih.nsconz;
|
||||
const auto start = wellStart + (connNo - 1) * ih.nsconz;
|
||||
|
||||
BOOST_CHECK_CLOSE(sconn[start + Ix::StaticDFacCorrCoeff], 0.0, 1.0e-7);
|
||||
}
|
||||
|
||||
// W2 (producer)
|
||||
{
|
||||
using Ix = ::Opm::RestartIO::Helpers::VectorItems::SConn::index;
|
||||
const auto& sconn = amconn.getSConn();
|
||||
|
||||
const auto wellNo = 2;
|
||||
const auto connNo = 1;
|
||||
const auto wellStart = (wellNo - 1) * ih.ncwmax * ih.nsconz;
|
||||
const auto start = wellStart + (connNo - 1)*ih.nsconz;
|
||||
|
||||
BOOST_CHECK_CLOSE(sconn[start + Ix::StaticDFacCorrCoeff], 0.0, 1.0e-7);
|
||||
}
|
||||
}
|
||||
|
||||
{
|
||||
const auto rptStep = std::size_t {1};
|
||||
|
||||
amconn.captureDeclaredConnData(cse.sched,
|
||||
cse.grid,
|
||||
cse.es.getUnits(),
|
||||
wrc, sum_state, rptStep);
|
||||
|
||||
// W1 (injector)
|
||||
{
|
||||
using Ix = ::Opm::RestartIO::Helpers::VectorItems::SConn::index;
|
||||
const auto& sconn = amconn.getSConn();
|
||||
|
||||
const auto wellNo = 1;
|
||||
const auto connNo = 1;
|
||||
const auto wellStart = (wellNo - 1) * ih.ncwmax * ih.nsconz;
|
||||
const auto start = wellStart + (connNo - 1) * ih.nsconz;
|
||||
|
||||
BOOST_CHECK_CLOSE(sconn[start + Ix::StaticDFacCorrCoeff], 0.0, 1.0e-7);
|
||||
}
|
||||
|
||||
// W2 (producer)
|
||||
{
|
||||
using Ix = ::Opm::RestartIO::Helpers::VectorItems::SConn::index;
|
||||
const auto& sconn = amconn.getSConn();
|
||||
|
||||
const auto wellNo = 2;
|
||||
const auto connNo = 1;
|
||||
const auto wellStart = (wellNo - 1) * ih.ncwmax * ih.nsconz;
|
||||
const auto start = wellStart + (connNo - 1)*ih.nsconz;
|
||||
|
||||
BOOST_CHECK_CLOSE(sconn[start + Ix::StaticDFacCorrCoeff], 1.89919365e-11, 1.0e-7);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
BOOST_AUTO_TEST_SUITE_END() // DFactor_Correlation
|
||||
|
@ -51,6 +51,8 @@
|
||||
#include <opm/input/eclipse/Schedule/Well/WellTestConfig.hpp>
|
||||
#include <opm/input/eclipse/Schedule/Well/WellTestState.hpp>
|
||||
|
||||
#include <opm/input/eclipse/Units/Units.hpp>
|
||||
|
||||
#include <opm/input/eclipse/Parser/Parser.hpp>
|
||||
#include <opm/input/eclipse/Deck/Deck.hpp>
|
||||
|
||||
@ -64,42 +66,65 @@
|
||||
|
||||
#include "tests/WorkArea.hpp"
|
||||
|
||||
struct MockIH
|
||||
{
|
||||
MockIH(const int numWells,
|
||||
const int iwelPerWell = 155, // E100
|
||||
const int swelPerWell = 122, // E100
|
||||
const int xwelPerWell = 130, // E100
|
||||
const int zwelPerWell = 3); // E100
|
||||
namespace {
|
||||
|
||||
std::vector<int> value;
|
||||
struct MockIH
|
||||
{
|
||||
MockIH(const int numWells,
|
||||
const int iwelPerWell = 155, // E100
|
||||
const int swelPerWell = 122, // E100
|
||||
const int xwelPerWell = 130, // E100
|
||||
const int zwelPerWell = 3); // E100
|
||||
|
||||
using Sz = std::vector<int>::size_type;
|
||||
std::vector<int> value;
|
||||
|
||||
Sz nwells;
|
||||
Sz niwelz;
|
||||
Sz nswelz;
|
||||
Sz nxwelz;
|
||||
Sz nzwelz;
|
||||
};
|
||||
using Sz = std::vector<int>::size_type;
|
||||
|
||||
MockIH::MockIH(const int numWells,
|
||||
const int iwelPerWell,
|
||||
const int swelPerWell,
|
||||
const int xwelPerWell,
|
||||
const int zwelPerWell)
|
||||
: value(411, 0)
|
||||
{
|
||||
using Ix = ::Opm::RestartIO::Helpers::VectorItems::intehead;
|
||||
Sz nwells;
|
||||
Sz niwelz;
|
||||
Sz nswelz;
|
||||
Sz nxwelz;
|
||||
Sz nzwelz;
|
||||
};
|
||||
|
||||
this->nwells = this->value[Ix::NWELLS] = numWells;
|
||||
this->niwelz = this->value[Ix::NIWELZ] = iwelPerWell;
|
||||
this->nswelz = this->value[Ix::NSWELZ] = swelPerWell;
|
||||
this->nxwelz = this->value[Ix::NXWELZ] = xwelPerWell;
|
||||
this->nzwelz = this->value[Ix::NZWELZ] = zwelPerWell;
|
||||
}
|
||||
MockIH::MockIH(const int numWells,
|
||||
const int iwelPerWell,
|
||||
const int swelPerWell,
|
||||
const int xwelPerWell,
|
||||
const int zwelPerWell)
|
||||
: value(411, 0)
|
||||
{
|
||||
using Ix = ::Opm::RestartIO::Helpers::VectorItems::intehead;
|
||||
|
||||
this->nwells = this->value[Ix::NWELLS] = numWells;
|
||||
this->niwelz = this->value[Ix::NIWELZ] = iwelPerWell;
|
||||
this->nswelz = this->value[Ix::NSWELZ] = swelPerWell;
|
||||
this->nxwelz = this->value[Ix::NXWELZ] = xwelPerWell;
|
||||
this->nzwelz = this->value[Ix::NZWELZ] = zwelPerWell;
|
||||
}
|
||||
|
||||
struct SimulationCase
|
||||
{
|
||||
explicit SimulationCase(const Opm::Deck& deck)
|
||||
: es { deck }
|
||||
, grid { deck }
|
||||
, sched{ deck, es, std::make_shared<Opm::Python>() }
|
||||
{}
|
||||
|
||||
// Order requirement: 'es' must be declared/initialised before 'sched'.
|
||||
Opm::EclipseState es;
|
||||
Opm::EclipseGrid grid;
|
||||
Opm::Schedule sched;
|
||||
};
|
||||
|
||||
} // Anonymous namespace
|
||||
|
||||
// =====================================================================
|
||||
|
||||
BOOST_AUTO_TEST_SUITE(Aggregate_WD)
|
||||
|
||||
namespace {
|
||||
|
||||
Opm::Deck first_sim()
|
||||
{
|
||||
// Mostly copy of tests/FIRST_SIM.DATA
|
||||
@ -817,25 +842,8 @@ TSTEP -- 3
|
||||
|
||||
return xw;
|
||||
}
|
||||
} // namespace
|
||||
|
||||
struct SimulationCase
|
||||
{
|
||||
explicit SimulationCase(const Opm::Deck& deck)
|
||||
: es { deck }
|
||||
, grid { deck }
|
||||
, sched{ deck, es, std::make_shared<Opm::Python>() }
|
||||
{}
|
||||
|
||||
// Order requirement: 'es' must be declared/initialised before 'sched'.
|
||||
Opm::EclipseState es;
|
||||
Opm::EclipseGrid grid;
|
||||
Opm::Schedule sched;
|
||||
};
|
||||
|
||||
// =====================================================================
|
||||
|
||||
BOOST_AUTO_TEST_SUITE(Aggregate_WD)
|
||||
} // Anonymous namespace
|
||||
|
||||
BOOST_AUTO_TEST_CASE (Constructor)
|
||||
{
|
||||
@ -1822,3 +1830,157 @@ BOOST_AUTO_TEST_CASE(WELL_POD)
|
||||
}
|
||||
|
||||
BOOST_AUTO_TEST_SUITE_END()
|
||||
|
||||
// ===========================================================================
|
||||
|
||||
BOOST_AUTO_TEST_SUITE(Extra_Effects)
|
||||
|
||||
namespace {
|
||||
|
||||
SimulationCase wdfaccorCase()
|
||||
{
|
||||
return SimulationCase { Opm::Parser{}.parseString(R"~(
|
||||
DIMENS
|
||||
10 10 10 /
|
||||
|
||||
START -- 0
|
||||
19 JUN 2007 /
|
||||
|
||||
GRID
|
||||
|
||||
DXV
|
||||
10*100.0 /
|
||||
DYV
|
||||
10*100.0 /
|
||||
DZV
|
||||
10*10.0 /
|
||||
DEPTHZ
|
||||
121*2000.0 /
|
||||
|
||||
PORO
|
||||
1000*0.1 /
|
||||
PERMX
|
||||
1000*1 /
|
||||
PERMY
|
||||
1000*0.1 /
|
||||
PERMZ
|
||||
1000*0.01 /
|
||||
|
||||
SCHEDULE
|
||||
|
||||
DATES -- 1
|
||||
10 OKT 2008 /
|
||||
/
|
||||
|
||||
WELSPECS
|
||||
'W1' 'G1' 3 3 2873.94 'WATER' 0.00 'STD' 'SHUT' 'NO' 0 'SEG' /
|
||||
'W2' 'G2' 5 5 1 'OIL' 0.00 'STD' 'SHUT' 'NO' 0 'SEG' /
|
||||
/
|
||||
|
||||
COMPDAT
|
||||
'W1' 3 3 1 1 'OPEN' 1* 32.948 0.311 3047.839 1* 1* 'X' 22.100 /
|
||||
'W2' 3 3 2 2 'OPEN' 1* 32.948 0.311 3047.839 1* 1* 'X' 22.100 /
|
||||
/
|
||||
|
||||
WDFACCOR
|
||||
'W2' 1.984e-7 -1.1045 0.0 /
|
||||
/
|
||||
|
||||
WCONINJE
|
||||
'W1' 'WATER' 'OPEN' 'RATE' 4000.0 1* 850.0 /
|
||||
/
|
||||
|
||||
WCONPROD
|
||||
'W2' 'OPEN' 'ORAT' 5000.0 4* 20.0 /
|
||||
/
|
||||
|
||||
DATES -- 2
|
||||
12 NOV 2008 /
|
||||
/
|
||||
|
||||
END
|
||||
)~") };
|
||||
}
|
||||
|
||||
std::pair<Opm::data::Wells, Opm::SummaryState>
|
||||
dynamicStateWDFacCorr(const Opm::Schedule& sched)
|
||||
{
|
||||
auto dyn_state = std::pair<Opm::data::Wells, Opm::SummaryState> {
|
||||
std::piecewise_construct,
|
||||
std::forward_as_tuple(),
|
||||
std::forward_as_tuple(Opm::TimeService::now())
|
||||
};
|
||||
|
||||
using o = ::Opm::data::Rates::opt;
|
||||
|
||||
auto& [xw, sum_state] = dyn_state;
|
||||
|
||||
{
|
||||
const auto wname = std::string { "W2" };
|
||||
|
||||
xw[wname].rates.set(o::wat, 1.0).set(o::oil, 2.0).set(o::gas, 3.0);
|
||||
xw[wname].bhp = 213.0*Opm::unit::barsa;
|
||||
}
|
||||
|
||||
{
|
||||
const auto wname = std::string { "W1" };
|
||||
|
||||
xw[wname].bhp = 234.0*Opm::unit::barsa;
|
||||
xw[wname].rates
|
||||
.set(o::wat, 5.0*Opm::unit::cubic(Opm::unit::meter)/Opm::unit::day)
|
||||
.set(o::oil, 0.0*Opm::unit::cubic(Opm::unit::meter)/Opm::unit::day)
|
||||
.set(o::gas, 0.0*Opm::unit::cubic(Opm::unit::meter)/Opm::unit::day);
|
||||
}
|
||||
|
||||
return dyn_state;
|
||||
}
|
||||
|
||||
} // Anonymous namespace
|
||||
|
||||
BOOST_AUTO_TEST_CASE(WdFac_Correlation)
|
||||
{
|
||||
const auto cse = wdfaccorCase();
|
||||
const auto& [xw, smry] = dynamicStateWDFacCorr(cse.sched);
|
||||
|
||||
const auto ih = MockIH{ 2 };
|
||||
|
||||
const auto action_state = Opm::Action::State{};
|
||||
const auto wtest_state = Opm::WellTestState{};
|
||||
|
||||
const auto rptStep = std::size_t{1};
|
||||
|
||||
auto awd = Opm::RestartIO::Helpers::AggregateWellData{ ih.value };
|
||||
awd.captureDeclaredWellData(cse.sched,
|
||||
cse.es.tracer(),
|
||||
rptStep,
|
||||
action_state,
|
||||
wtest_state,
|
||||
smry,
|
||||
ih.value);
|
||||
|
||||
// W1 (injector)
|
||||
{
|
||||
using Ix = ::Opm::RestartIO::Helpers::VectorItems::SWell::index;
|
||||
|
||||
const auto i1 = 0*ih.nswelz;
|
||||
|
||||
const auto& swell = awd.getSWell();
|
||||
BOOST_CHECK_CLOSE(swell[i1 + Ix::DFacCorrCoeffA], 0.0f, 1.0e-7f);
|
||||
BOOST_CHECK_CLOSE(swell[i1 + Ix::DFacCorrExpB] , 0.0f, 1.0e-7f);
|
||||
BOOST_CHECK_CLOSE(swell[i1 + Ix::DFacCorrExpC] , 0.0f, 1.0e-7f);
|
||||
}
|
||||
|
||||
// W2 (producer)
|
||||
{
|
||||
using Ix = ::Opm::RestartIO::Helpers::VectorItems::SWell::index;
|
||||
|
||||
const auto i1 = 1*ih.nswelz;
|
||||
|
||||
const auto& swell = awd.getSWell();
|
||||
BOOST_CHECK_CLOSE(swell[i1 + Ix::DFacCorrCoeffA], 1.984e-7f, 1.0e-7f);
|
||||
BOOST_CHECK_CLOSE(swell[i1 + Ix::DFacCorrExpB] , -1.1045f , 1.0e-7f);
|
||||
BOOST_CHECK_CLOSE(swell[i1 + Ix::DFacCorrExpC] , 0.0f , 1.0e-7f);
|
||||
}
|
||||
}
|
||||
|
||||
BOOST_AUTO_TEST_SUITE_END() // Extra_Effects
|
||||
|
@ -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 };
|
||||
|
@ -732,12 +732,12 @@ BOOST_AUTO_TEST_CASE(test_RFT)
|
||||
std::vector<Opm::data::Connection> well1_comps(9);
|
||||
Opm::data::ConnectionFiltrate con_filtrate {0.1, 1, 3, 0.4, 1.e-9, 0.2, 0.05, 10.}; // values are not used in this test
|
||||
for (size_t i = 0; i < 9; ++i) {
|
||||
Opm::data::Connection well_comp { grid.getGlobalIndex(8,8,i) ,r1, 0.0 , 0.0, (double)i, 0.1*i,0.2*i, 1.2e3, 4.321, 0.0, con_filtrate};
|
||||
Opm::data::Connection well_comp { grid.getGlobalIndex(8,8,i), r1, 0.0 , 0.0, (double)i, 0.1*i,0.2*i, 1.2e3, 4.321, 0.0, 1.23, con_filtrate};
|
||||
well1_comps[i] = std::move(well_comp);
|
||||
}
|
||||
std::vector<Opm::data::Connection> well2_comps(6);
|
||||
for (size_t i = 0; i < 6; ++i) {
|
||||
Opm::data::Connection well_comp { grid.getGlobalIndex(3,3,i+3) ,r2, 0.0 , 0.0, (double)i, i*0.1,i*0.2, 0.15, 0.54321, 0.0, con_filtrate};
|
||||
Opm::data::Connection well_comp { grid.getGlobalIndex(3,3,i+3), r2, 0.0 , 0.0, (double)i, i*0.1,i*0.2, 0.15, 0.54321, 0.0, 0.98, con_filtrate};
|
||||
well2_comps[i] = std::move(well_comp);
|
||||
}
|
||||
|
||||
@ -871,12 +871,12 @@ BOOST_AUTO_TEST_CASE(test_RFT2)
|
||||
std::vector<Opm::data::Connection> well1_comps(9);
|
||||
Opm::data::ConnectionFiltrate con_filtrate {0.1, 1, 3, 0.4, 1.e-9, 0.2, 0.05, 10.}; // values are not used in this test
|
||||
for (size_t i = 0; i < 9; ++i) {
|
||||
Opm::data::Connection well_comp { grid.getGlobalIndex(8,8,i) ,r1, 0.0 , 0.0, (double)i, 0.1*i,0.2*i, 3.14e5, 0.1234, 0.0, con_filtrate};
|
||||
Opm::data::Connection well_comp { grid.getGlobalIndex(8,8,i), r1, 0.0 , 0.0, (double)i, 0.1*i,0.2*i, 3.14e5, 0.1234, 0.0, 1.23, con_filtrate};
|
||||
well1_comps[i] = std::move(well_comp);
|
||||
}
|
||||
std::vector<Opm::data::Connection> well2_comps(6);
|
||||
for (size_t i = 0; i < 6; ++i) {
|
||||
Opm::data::Connection well_comp { grid.getGlobalIndex(3,3,i+3) ,r2, 0.0 , 0.0, (double)i, i*0.1,i*0.2, 355.113, 0.9876, 0.0, con_filtrate};
|
||||
Opm::data::Connection well_comp { grid.getGlobalIndex(3,3,i+3), r2, 0.0 , 0.0, (double)i, i*0.1,i*0.2, 355.113, 0.9876, 0.0, 0.98, con_filtrate};
|
||||
well2_comps[i] = std::move(well_comp);
|
||||
}
|
||||
|
||||
|
@ -187,15 +187,15 @@ data::Wells mkWells() {
|
||||
* input deck. All other entries in the well structures are arbitrary.
|
||||
*/
|
||||
Opm::data::ConnectionFiltrate con_filtrate {0.1, 1, 3, 0.4, 1.e-9, 0.2, 0.05, 10.}; // values are not used in this test
|
||||
w1.connections.push_back( { 88, rc1, 30.45, 123.4, 543.21, 0.62, 0.15, 1.0e3, 1.234, 0.0, con_filtrate } );
|
||||
w1.connections.push_back( { 288, rc2, 33.19, 123.4, 432.1, 0.26, 0.45, 2.56, 2.345, 0.0, con_filtrate } );
|
||||
w1.connections.push_back( { 88, rc1, 30.45, 123.4, 543.21, 0.62, 0.15, 1.0e3, 1.234, 0.0, 1.23, con_filtrate } );
|
||||
w1.connections.push_back( { 288, rc2, 33.19, 123.4, 432.1, 0.26, 0.45, 2.56, 2.345, 0.0, 0.98, con_filtrate } );
|
||||
|
||||
w2.rates = r2;
|
||||
w2.thp = 2.0;
|
||||
w2.bhp = 2.34;
|
||||
w2.temperature = 4.56;
|
||||
w2.control = 2;
|
||||
w2.connections.push_back( { 188, rc3, 36.22, 123.4, 256.1, 0.55, 0.0125, 314.15, 3.456, 0.0, con_filtrate } );
|
||||
w2.connections.push_back( { 188, rc3, 36.22, 123.4, 256.1, 0.55, 0.0125, 314.15, 3.456, 0.0, 2.46, con_filtrate } );
|
||||
|
||||
{
|
||||
data::Wells wellRates;
|
||||
|
@ -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)
|
||||
@ -315,6 +316,8 @@ TEST_FOR_TYPE(VFPInjTable)
|
||||
TEST_FOR_TYPE(VFPProdTable)
|
||||
TEST_FOR_TYPE(ViscrefTable)
|
||||
TEST_FOR_TYPE(WatdentTable)
|
||||
TEST_FOR_TYPE_NAMED(WDFAC::Correlation, Correlation)
|
||||
TEST_FOR_TYPE(WDFAC)
|
||||
TEST_FOR_TYPE(Well)
|
||||
TEST_FOR_TYPE(Welldims)
|
||||
TEST_FOR_TYPE(WellBrineProperties)
|
||||
@ -335,11 +338,14 @@ TEST_FOR_TYPE(WListManager)
|
||||
TEST_FOR_TYPE(WriteRestartFileEvents)
|
||||
|
||||
|
||||
namespace {
|
||||
|
||||
bool init_unit_test_func()
|
||||
{
|
||||
return true;
|
||||
}
|
||||
|
||||
} // Anonymous namespace
|
||||
|
||||
int main(int argc, char** argv)
|
||||
{
|
||||
|
@ -319,11 +319,11 @@ data::Wells result_wells(const bool w3_injector = true)
|
||||
data::ConnectionFiltrate zero_filtrate {}; // only injecting connections are counted for filtration related
|
||||
data::ConnectionFiltrate con_filtrate = {0.1*sm3_pr_day(), 1*sm3(), 3, 0.01*unit::meter, 1.e-3*unit::darcy, 0.2, 0.05*unit::meter, 10.*unit::square(unit::meter)};
|
||||
data::ConnectionFiltrate w3_con_filtrate = w3_injector ? con_filtrate : zero_filtrate;
|
||||
data::Connection well1_comp1 { 0 , crates1, 1.9 *unit::barsa, -123.4 *rm3_pr_day(), 314.15, 0.35 , 0.25, 2.718e2, 111.222*cp_rm3_per_db(), 0.0, zero_filtrate};
|
||||
data::Connection well2_comp1 { 1 , crates2, 1.10*unit::barsa, - 23.4 *rm3_pr_day(), 212.1 , 0.78 , 0.0 , 12.34 , 222.333*cp_rm3_per_db(), 0.0, zero_filtrate};
|
||||
data::Connection well2_comp2 { 101, crates3, 1.11*unit::barsa, -234.5 *rm3_pr_day(), 150.6 , 0.001, 0.89, 100.0 , 333.444*cp_rm3_per_db(), 0.0, con_filtrate /* output should be zero since it is a producer */};
|
||||
data::Connection well3_comp1 { 2 , crates3, 1.11*unit::barsa, 432.1 *rm3_pr_day(), 456.78, 0.0 , 0.15, 432.1 , 444.555*cp_rm3_per_db(), 0.0, w3_con_filtrate};
|
||||
data::Connection well6_comp1 { 77 , crates6, 6.11*unit::barsa, 321.09*rm3_pr_day(), 656.78, 0.0 , 0.65, 632.1 , 555.666*cp_rm3_per_db(), 0.0, zero_filtrate};
|
||||
data::Connection well1_comp1 { 0 , crates1, 1.9 *unit::barsa, -123.4 *rm3_pr_day(), 314.15, 0.35 , 0.25, 2.718e2, 111.222*cp_rm3_per_db(), 0.0, 1.0, zero_filtrate};
|
||||
data::Connection well2_comp1 { 1 , crates2, 1.10*unit::barsa, - 23.4 *rm3_pr_day(), 212.1 , 0.78 , 0.0 , 12.34 , 222.333*cp_rm3_per_db(), 0.0, 1.0, zero_filtrate};
|
||||
data::Connection well2_comp2 { 101, crates3, 1.11*unit::barsa, -234.5 *rm3_pr_day(), 150.6 , 0.001, 0.89, 100.0 , 333.444*cp_rm3_per_db(), 0.0, 1.0, con_filtrate /* output should be zero since it is a producer */};
|
||||
data::Connection well3_comp1 { 2 , crates3, 1.11*unit::barsa, 432.1 *rm3_pr_day(), 456.78, 0.0 , 0.15, 432.1 , 444.555*cp_rm3_per_db(), 0.0, 1.0, w3_con_filtrate};
|
||||
data::Connection well6_comp1 { 77 , crates6, 6.11*unit::barsa, 321.09*rm3_pr_day(), 656.78, 0.0 , 0.65, 632.1 , 555.666*cp_rm3_per_db(), 0.0, 1.0, zero_filtrate};
|
||||
|
||||
/*
|
||||
The completions
|
||||
|
@ -172,7 +172,7 @@ static data::Wells result_wells() {
|
||||
input deck.
|
||||
*/
|
||||
data::ConnectionFiltrate con_filtrate {0.1, 1, 3, 0.4, 1.e-9, 0.2, 0.05, 10.}; // values are not tested in this test
|
||||
data::Connection well1_comp1 { 0 , crates1, 1.9 , 123.4, 314.15, 0.35, 0.25, 2.718e2, 0.12345, 0.0, con_filtrate };
|
||||
data::Connection well1_comp1 { 0, crates1, 1.9, 123.4, 314.15, 0.35, 0.25, 2.718e2, 0.12345, 0.0, 1.23, con_filtrate };
|
||||
|
||||
/*
|
||||
The completions
|
||||
|
@ -116,8 +116,8 @@ BOOST_AUTO_TEST_CASE(get_connections) {
|
||||
* the completion keys (active indices) and well names correspond to the
|
||||
* input deck. All other entries in the well structures are arbitrary.
|
||||
*/
|
||||
w1.connections.push_back( { 88, rc1, 30.45, 123.45, 543.21, 0.123, 0.5, 17.29, 0.1729,0.0,{}} );
|
||||
w1.connections.push_back( { 288, rc2, 33.19, 67.89, 98.76, 0.5, 0.125, 355.113, 0.355113,0.0, {}} );
|
||||
w1.connections.push_back( { 88, rc1, 30.45, 123.45, 543.21, 0.123, 0.5, 17.29, 0.1729, 0.0, 1.23, {}} );
|
||||
w1.connections.push_back( { 288, rc2, 33.19, 67.89, 98.76, 0.5, 0.125, 355.113, 0.355113, 0.0, 0.98, {}} );
|
||||
|
||||
{
|
||||
Json::JsonObject json_data;
|
||||
@ -134,7 +134,7 @@ BOOST_AUTO_TEST_CASE(get_connections) {
|
||||
w2.temperature = 4.56;
|
||||
w2.control = 2;
|
||||
w2.filtrate = {0.3, 3, 0.4}; // values are not tested in this test
|
||||
w2.connections.push_back( { 188, rc3, 36.22, 19.28, 28.91, 0.125, 0.125, 3.141, 0.31415, 0.0, {}} );
|
||||
w2.connections.push_back( { 188, rc3, 36.22, 19.28, 28.91, 0.125, 0.125, 3.141, 0.31415, 0.0, 1.21, {}} );
|
||||
data::Wells wellRates;
|
||||
|
||||
wellRates["OP_1"] = w1;
|
||||
|
Loading…
Reference in New Issue
Block a user