Merge 3dc49856ee
into 9a0ccfd853
This commit is contained in:
commit
57fda2469f
@ -16,40 +16,42 @@
|
|||||||
You should have received a copy of the GNU General Public License
|
You should have received a copy of the GNU General Public License
|
||||||
along with OPM. If not, see <http://www.gnu.org/licenses/>.
|
along with OPM. If not, see <http://www.gnu.org/licenses/>.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
#ifndef COMPLETED_CELLS
|
#ifndef COMPLETED_CELLS
|
||||||
#define COMPLETED_CELLS
|
#define COMPLETED_CELLS
|
||||||
#include <optional>
|
|
||||||
#include <unordered_map>
|
|
||||||
|
|
||||||
#include <opm/input/eclipse/EclipseState/Grid/GridDims.hpp>
|
#include <opm/input/eclipse/EclipseState/Grid/GridDims.hpp>
|
||||||
|
|
||||||
|
#include <array>
|
||||||
|
#include <cstddef>
|
||||||
|
#include <optional>
|
||||||
|
#include <unordered_map>
|
||||||
|
#include <utility>
|
||||||
|
|
||||||
namespace Opm {
|
namespace Opm {
|
||||||
|
|
||||||
class CompletedCells {
|
class CompletedCells
|
||||||
|
{
|
||||||
public:
|
public:
|
||||||
|
struct Cell
|
||||||
struct Cell {
|
{
|
||||||
std::size_t global_index;
|
std::size_t global_index;
|
||||||
std::size_t i, j, k;
|
std::size_t i, j, k;
|
||||||
|
|
||||||
struct Props{
|
struct Props
|
||||||
std::size_t active_index;
|
{
|
||||||
double permx;
|
std::size_t active_index{};
|
||||||
double permy;
|
double permx{};
|
||||||
double permz;
|
double permy{};
|
||||||
int satnum;
|
double permz{};
|
||||||
int pvtnum;
|
double poro{};
|
||||||
double ntg;
|
int satnum{};
|
||||||
|
int pvtnum{};
|
||||||
|
double ntg{};
|
||||||
|
|
||||||
bool operator==(const Props& other) const{
|
bool operator==(const Props& other) const;
|
||||||
return this->active_index == other.active_index &&
|
|
||||||
this->permx == other.permx &&
|
static Props serializationTestObject();
|
||||||
this->permy == other.permy &&
|
|
||||||
this->permz == other.permz &&
|
|
||||||
this->satnum == other.satnum &&
|
|
||||||
this->pvtnum == other.pvtnum &&
|
|
||||||
this->ntg == other.ntg;
|
|
||||||
}
|
|
||||||
|
|
||||||
template<class Serializer>
|
template<class Serializer>
|
||||||
void serializeOp(Serializer& serializer)
|
void serializeOp(Serializer& serializer)
|
||||||
@ -57,46 +59,23 @@ public:
|
|||||||
serializer(this->permx);
|
serializer(this->permx);
|
||||||
serializer(this->permy);
|
serializer(this->permy);
|
||||||
serializer(this->permz);
|
serializer(this->permz);
|
||||||
|
serializer(this->poro);
|
||||||
serializer(this->satnum);
|
serializer(this->satnum);
|
||||||
serializer(this->pvtnum);
|
serializer(this->pvtnum);
|
||||||
serializer(this->ntg);
|
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::optional<Props> props;
|
||||||
std::size_t active_index() const;
|
std::size_t active_index() const;
|
||||||
bool is_active() const;
|
bool is_active() const;
|
||||||
|
|
||||||
double depth;
|
double depth{};
|
||||||
std::array<double, 3> dimensions;
|
std::array<double, 3> dimensions{};
|
||||||
|
|
||||||
bool operator==(const Cell& other) const {
|
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;
|
|
||||||
}
|
|
||||||
|
|
||||||
static Cell serializationTestObject() {
|
static Cell serializationTestObject();
|
||||||
Cell cell(0,1,1,1);
|
|
||||||
cell.depth = 12345;
|
|
||||||
cell.dimensions = {1.0,2.0,3.0};
|
|
||||||
return cell;
|
|
||||||
}
|
|
||||||
|
|
||||||
template<class Serializer>
|
template<class Serializer>
|
||||||
void serializeOp(Serializer& serializer)
|
void serializeOp(Serializer& serializer)
|
||||||
@ -123,6 +102,7 @@ public:
|
|||||||
CompletedCells() = default;
|
CompletedCells() = default;
|
||||||
explicit CompletedCells(const GridDims& dims);
|
explicit CompletedCells(const GridDims& dims);
|
||||||
CompletedCells(std::size_t nx, std::size_t ny, std::size_t nz);
|
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;
|
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);
|
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;
|
std::unordered_map<std::size_t, Cell> cells;
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
#endif
|
|
||||||
|
|
||||||
|
#endif // COMPLETED_CELLS
|
||||||
|
@ -21,17 +21,30 @@
|
|||||||
|
|
||||||
#include <opm/input/eclipse/Schedule/CompletedCells.hpp>
|
#include <opm/input/eclipse/Schedule/CompletedCells.hpp>
|
||||||
|
|
||||||
|
#include <cstddef>
|
||||||
|
#include <string>
|
||||||
|
|
||||||
namespace Opm {
|
namespace Opm {
|
||||||
|
|
||||||
class EclipseGrid;
|
class EclipseGrid;
|
||||||
class FieldPropsManager;
|
class FieldPropsManager;
|
||||||
|
|
||||||
class ScheduleGrid {
|
} // namespace Opm
|
||||||
|
|
||||||
|
namespace Opm {
|
||||||
|
|
||||||
|
class ScheduleGrid
|
||||||
|
{
|
||||||
public:
|
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);
|
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;
|
const Opm::EclipseGrid* get_grid() const;
|
||||||
|
|
||||||
private:
|
private:
|
||||||
@ -40,8 +53,6 @@ private:
|
|||||||
CompletedCells& cells;
|
CompletedCells& cells;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
} // namespace Opm
|
||||||
|
|
||||||
|
#endif // SCHEDULE_GRID
|
||||||
}
|
|
||||||
#endif
|
|
||||||
|
|
||||||
|
@ -17,91 +17,172 @@
|
|||||||
along with OPM. If not, see <http://www.gnu.org/licenses/>.
|
along with OPM. If not, see <http://www.gnu.org/licenses/>.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
|
|
||||||
#ifndef COMPLETION_HPP_
|
#ifndef COMPLETION_HPP_
|
||||||
#define COMPLETION_HPP_
|
#define COMPLETION_HPP_
|
||||||
|
|
||||||
|
#include <opm/input/eclipse/Schedule/Well/FilterCake.hpp>
|
||||||
|
#include <opm/input/eclipse/Schedule/Well/WINJMULT.hpp>
|
||||||
|
|
||||||
#include <array>
|
#include <array>
|
||||||
#include <cstddef>
|
#include <cstddef>
|
||||||
#include <map>
|
#include <map>
|
||||||
#include <memory>
|
#include <memory>
|
||||||
#include <string>
|
#include <string>
|
||||||
|
#include <string_view>
|
||||||
#include <vector>
|
#include <vector>
|
||||||
#include <optional>
|
#include <optional>
|
||||||
#include <limits>
|
#include <limits>
|
||||||
|
|
||||||
#include <opm/input/eclipse/Schedule/Well/FilterCake.hpp>
|
|
||||||
#include <opm/input/eclipse/Schedule/Well/WINJMULT.hpp>
|
|
||||||
|
|
||||||
namespace Opm {
|
namespace Opm {
|
||||||
|
|
||||||
namespace RestartIO {
|
|
||||||
struct RstConnection;
|
|
||||||
}
|
|
||||||
|
|
||||||
class DeckKeyword;
|
class DeckKeyword;
|
||||||
class DeckRecord;
|
class DeckRecord;
|
||||||
class ScheduleGrid;
|
class ScheduleGrid;
|
||||||
class FieldPropsManager;
|
class FieldPropsManager;
|
||||||
|
} // namespace Opm
|
||||||
|
|
||||||
class Connection {
|
namespace Opm { namespace RestartIO {
|
||||||
|
struct RstConnection;
|
||||||
|
}} // namespace Opm::RestartIO
|
||||||
|
|
||||||
|
namespace Opm {
|
||||||
|
|
||||||
|
class Connection
|
||||||
|
{
|
||||||
public:
|
public:
|
||||||
enum class State {
|
enum class State {
|
||||||
OPEN = 1,
|
OPEN = 1,
|
||||||
SHUT = 2,
|
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 std::string State2String(State enumValue);
|
||||||
static State StateFromString( const std::string& stringValue );
|
static State StateFromString(std::string_view stringValue);
|
||||||
|
|
||||||
|
|
||||||
enum class Direction{
|
enum class Direction {
|
||||||
X = 1,
|
X = 1,
|
||||||
Y = 2,
|
Y = 2,
|
||||||
Z = 3
|
Z = 3,
|
||||||
};
|
};
|
||||||
|
|
||||||
static std::string Direction2String(const Direction enumValue);
|
static std::string Direction2String(const Direction enumValue);
|
||||||
static Direction DirectionFromString(const std::string& stringValue);
|
static Direction DirectionFromString(std::string_view stringValue);
|
||||||
|
|
||||||
|
|
||||||
enum class Order {
|
enum class Order {
|
||||||
DEPTH,
|
DEPTH,
|
||||||
INPUT,
|
INPUT,
|
||||||
TRACK
|
TRACK,
|
||||||
};
|
};
|
||||||
|
|
||||||
static const std::string Order2String( Order enumValue );
|
static std::string Order2String(Order enumValue);
|
||||||
static Order OrderFromString(const std::string& comporderStringValue);
|
static Order OrderFromString(std::string_view comporderStringValue);
|
||||||
|
|
||||||
|
|
||||||
enum class CTFKind {
|
enum class CTFKind {
|
||||||
DeckValue,
|
DeckValue,
|
||||||
Defaulted,
|
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();
|
static Connection serializationTestObject();
|
||||||
|
|
||||||
@ -117,104 +198,105 @@ namespace RestartIO {
|
|||||||
int satTableId() const;
|
int satTableId() const;
|
||||||
int complnum() const;
|
int complnum() const;
|
||||||
int segment() const;
|
int segment() const;
|
||||||
double CF() const;
|
|
||||||
double wpimult() const;
|
double wpimult() const;
|
||||||
|
double CF() const;
|
||||||
double Kh() const;
|
double Kh() const;
|
||||||
|
double Ke() const;
|
||||||
double rw() const;
|
double rw() const;
|
||||||
double r0() const;
|
double r0() const;
|
||||||
double re() const;
|
double re() const;
|
||||||
double connectionLength() const;
|
double connectionLength() const;
|
||||||
double skinFactor() const;
|
double skinFactor() const;
|
||||||
double dFactor() const;
|
double dFactor() const;
|
||||||
double Ke() const;
|
|
||||||
CTFKind kind() const;
|
CTFKind kind() const;
|
||||||
const InjMult& injmult() const;
|
const InjMult& injmult() const;
|
||||||
bool activeInjMult() const;
|
bool activeInjMult() const;
|
||||||
void setInjMult(const InjMult& inj_mult);
|
|
||||||
void setFilterCake(const FilterCake& filter_cake);
|
|
||||||
const FilterCake& getFilterCake() const;
|
const FilterCake& getFilterCake() const;
|
||||||
bool filterCakeActive() const;
|
bool filterCakeActive() const;
|
||||||
double getFilterCakeRadius() const;
|
double getFilterCakeRadius() const;
|
||||||
double getFilterCakeArea() 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 setState(State state);
|
||||||
void setComplnum(int compnum);
|
void setComplnum(int compnum);
|
||||||
void setSkinFactor(double skin_factor);
|
void setSkinFactor(double skin_factor);
|
||||||
void setDFactor(double d_factor);
|
void setDFactor(double d_factor);
|
||||||
void setKe(double Ke);
|
void setKe(double Ke);
|
||||||
void setCF(double CF);
|
void setCF(double CF);
|
||||||
|
void setDefaultSatTabId(bool id);
|
||||||
|
void setStaticDFacCorrCoeff(const double c);
|
||||||
|
|
||||||
void scaleWellPi(double wellPi);
|
void scaleWellPi(double wellPi);
|
||||||
bool prepareWellPIScaling();
|
bool prepareWellPIScaling();
|
||||||
bool applyWellPIScaling(const double scaleFactor);
|
bool applyWellPIScaling(const double scaleFactor);
|
||||||
|
|
||||||
void updateSegmentRST(int segment_number_arg,
|
void updateSegmentRST(int segment_number_arg,
|
||||||
double center_depth_arg);
|
double center_depth_arg);
|
||||||
void updateSegment(int segment_number_arg,
|
void updateSegment(int segment_number_arg,
|
||||||
double center_depth_arg,
|
double center_depth_arg,
|
||||||
std::size_t compseg_insert_index,
|
std::size_t compseg_insert_index,
|
||||||
const std::optional<std::pair<double,double>>& perf_range);
|
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>
|
template<class Serializer>
|
||||||
void serializeOp(Serializer& serializer)
|
void serializeOp(Serializer& serializer)
|
||||||
{
|
{
|
||||||
serializer(direction);
|
serializer(this->direction);
|
||||||
serializer(center_depth);
|
serializer(this->center_depth);
|
||||||
serializer(open_state);
|
serializer(this->open_state);
|
||||||
serializer(sat_tableId);
|
serializer(this->sat_tableId);
|
||||||
serializer(m_complnum);
|
serializer(this->m_complnum);
|
||||||
serializer(m_CF);
|
serializer(this->ctf_properties_);
|
||||||
serializer(m_Kh);
|
serializer(this->ijk);
|
||||||
serializer(m_rw);
|
serializer(this->m_ctfkind);
|
||||||
serializer(m_r0);
|
serializer(this->m_global_index);
|
||||||
serializer(m_re);
|
serializer(this->m_injmult);
|
||||||
serializer(m_connection_length);
|
serializer(this->m_sort_value);
|
||||||
serializer(m_skin_factor);
|
serializer(this->m_perf_range);
|
||||||
serializer(m_d_factor);
|
serializer(this->m_defaultSatTabId);
|
||||||
serializer(m_Ke);
|
serializer(this->segment_number);
|
||||||
serializer(ijk);
|
serializer(this->m_wpimult);
|
||||||
serializer(m_global_index);
|
serializer(this->m_subject_to_welpi);
|
||||||
serializer(m_ctfkind);
|
serializer(this->m_filter_cake);
|
||||||
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);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
private:
|
private:
|
||||||
Direction direction;
|
// Note to maintainer: If you add new members to this list, then
|
||||||
double center_depth;
|
// please also update the operator==(), serializeOp(), and
|
||||||
State open_state;
|
// serializationTestObject() member functions.
|
||||||
int sat_tableId;
|
Direction direction { Direction::Z };
|
||||||
int m_complnum;
|
double center_depth { 0.0 };
|
||||||
double m_CF;
|
State open_state { State::SHUT };
|
||||||
double m_Kh;
|
int sat_tableId { -1 };
|
||||||
double m_rw;
|
int m_complnum { -1 };
|
||||||
double m_r0;
|
CTFProperties ctf_properties_{};
|
||||||
double m_re;
|
|
||||||
double m_connection_length;
|
std::array<int,3> ijk{};
|
||||||
double m_skin_factor;
|
CTFKind m_ctfkind { CTFKind::DeckValue };
|
||||||
double m_d_factor;
|
std::optional<InjMult> m_injmult{};
|
||||||
double m_Ke;
|
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
|
The sort_value member is a peculiar quantity. The connections are
|
||||||
assembled in the WellConnections class. During the lifetime of the
|
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
|
explicitly, so the truth is probably that the storage order
|
||||||
during simulation makes no difference?
|
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{};
|
||||||
std::optional<std::pair<double,double>> m_perf_range;
|
bool m_defaultSatTabId{true};
|
||||||
bool m_defaultSatTabId;
|
|
||||||
|
|
||||||
// related segment number
|
// Associate segment number
|
||||||
// 0 means the completion is not related to segment
|
//
|
||||||
int segment_number = 0;
|
// 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.
|
// 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
|
std::optional<FilterCake> m_filter_cake{};
|
||||||
double m_wpimult = 1.0;
|
|
||||||
|
|
||||||
std::optional<FilterCake> m_filter_cake;
|
|
||||||
|
|
||||||
static std::string CTFKindToString(const CTFKind);
|
static std::string CTFKindToString(const CTFKind);
|
||||||
};
|
};
|
||||||
}
|
|
||||||
|
|
||||||
#endif /* COMPLETION_HPP_ */
|
} // namespace Opm
|
||||||
|
|
||||||
|
#endif // COMPLETION_HPP_
|
||||||
|
@ -21,6 +21,7 @@
|
|||||||
#define WDFAC_HPP_HEADER_INCLUDED
|
#define WDFAC_HPP_HEADER_INCLUDED
|
||||||
|
|
||||||
namespace Opm {
|
namespace Opm {
|
||||||
|
class Connection;
|
||||||
class DeckRecord;
|
class DeckRecord;
|
||||||
class WellConnections;
|
class WellConnections;
|
||||||
} // namespace Opm
|
} // namespace Opm
|
||||||
@ -31,49 +32,210 @@ namespace Opm { namespace RestartIO {
|
|||||||
|
|
||||||
namespace Opm {
|
namespace Opm {
|
||||||
|
|
||||||
enum class WDFACTYPE {
|
|
||||||
NONE = 1,
|
|
||||||
DFACTOR = 2,
|
|
||||||
DAKEMODEL = 3,
|
|
||||||
CON_DFACTOR = 4
|
|
||||||
};
|
|
||||||
|
|
||||||
class WDFAC
|
class WDFAC
|
||||||
{
|
{
|
||||||
public:
|
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);
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
/// Serialisation test object
|
||||||
static WDFAC serializationTestObject();
|
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 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);
|
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);
|
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;
|
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;
|
||||||
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)
|
void serializeOp(Serializer& serializer)
|
||||||
{
|
{
|
||||||
serializer(m_a);
|
serializer(this->m_type);
|
||||||
serializer(m_b);
|
serializer(this->m_d);
|
||||||
serializer(m_c);
|
serializer(this->m_total_cf);
|
||||||
serializer(m_d);
|
serializer(this->m_corr);
|
||||||
serializer(m_total_cf);
|
|
||||||
serializer(m_type);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
private:
|
private:
|
||||||
double m_a{0.0};
|
/// D-factor categories.
|
||||||
double m_b{0.0};
|
enum class WDFacType
|
||||||
double m_c{0.0};
|
{
|
||||||
|
/// 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};
|
double m_d{0.0};
|
||||||
|
|
||||||
|
/// Total CTF sum for this well.
|
||||||
double m_total_cf{-1.0};
|
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
|
} // namespace Opm
|
||||||
|
@ -527,7 +527,7 @@ public:
|
|||||||
bool handleWELSEGS(const DeckKeyword& keyword);
|
bool handleWELSEGS(const DeckKeyword& keyword);
|
||||||
bool handleCOMPSEGS(const DeckKeyword& keyword, const ScheduleGrid& grid, const ParseContext& parseContext, ErrorGuard& errors);
|
bool handleCOMPSEGS(const DeckKeyword& keyword, const ScheduleGrid& grid, const ParseContext& parseContext, ErrorGuard& errors);
|
||||||
bool handleWELOPENConnections(const DeckRecord& record, Connection::State status);
|
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 handleCOMPLUMP(const DeckRecord& record);
|
||||||
bool handleWPIMULT(const DeckRecord& record);
|
bool handleWPIMULT(const DeckRecord& record);
|
||||||
bool handleWINJCLN(const DeckRecord& record, const KeywordLocation& location);
|
bool handleWINJCLN(const DeckRecord& record, const KeywordLocation& location);
|
||||||
|
@ -23,9 +23,11 @@
|
|||||||
#include <opm/input/eclipse/Schedule/Well/Connection.hpp>
|
#include <opm/input/eclipse/Schedule/Well/Connection.hpp>
|
||||||
#include <external/resinsight/LibGeometry/cvfBoundingBoxTree.h>
|
#include <external/resinsight/LibGeometry/cvfBoundingBoxTree.h>
|
||||||
|
|
||||||
|
#include <array>
|
||||||
#include <cstddef>
|
#include <cstddef>
|
||||||
#include <optional>
|
#include <optional>
|
||||||
#include <string>
|
#include <string>
|
||||||
|
#include <utility>
|
||||||
#include <vector>
|
#include <vector>
|
||||||
|
|
||||||
#include <stddef.h>
|
#include <stddef.h>
|
||||||
@ -33,10 +35,11 @@
|
|||||||
namespace Opm {
|
namespace Opm {
|
||||||
class ActiveGridCells;
|
class ActiveGridCells;
|
||||||
class DeckRecord;
|
class DeckRecord;
|
||||||
|
class EclipseGrid;
|
||||||
class FieldPropsManager;
|
class FieldPropsManager;
|
||||||
class KeywordLocation;
|
class KeywordLocation;
|
||||||
class ScheduleGrid;
|
class ScheduleGrid;
|
||||||
class EclipseGrid;
|
class WDFAC;
|
||||||
} // namespace Opm
|
} // namespace Opm
|
||||||
|
|
||||||
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,
|
void addConnection(const int i, const int j, const int k,
|
||||||
const std::size_t global_index,
|
const std::size_t global_index,
|
||||||
const double depth,
|
|
||||||
const Connection::State state,
|
const Connection::State state,
|
||||||
const double CF,
|
const double depth,
|
||||||
const double Kh,
|
const Connection::CTFProperties& ctf_props,
|
||||||
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 int satTableId,
|
const int satTableId,
|
||||||
const Connection::Direction direction = Connection::Direction::Z,
|
const Connection::Direction direction = Connection::Direction::Z,
|
||||||
const Connection::CTFKind ctf_kind = Connection::CTFKind::DeckValue,
|
const Connection::CTFKind ctf_kind = Connection::CTFKind::DeckValue,
|
||||||
@ -89,16 +89,26 @@ namespace Opm {
|
|||||||
void loadCOMPDAT(const DeckRecord& record,
|
void loadCOMPDAT(const DeckRecord& record,
|
||||||
const ScheduleGrid& grid,
|
const ScheduleGrid& grid,
|
||||||
const std::string& wname,
|
const std::string& wname,
|
||||||
|
const WDFAC& wdfac,
|
||||||
const KeywordLocation& location);
|
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 getHeadI() const;
|
||||||
int getHeadJ() const;
|
int getHeadJ() const;
|
||||||
const std::vector<double>& getMD() const;
|
const std::vector<double>& getMD() const;
|
||||||
void add(Connection);
|
|
||||||
std::size_t size() const;
|
std::size_t size() const;
|
||||||
bool empty() const;
|
bool empty() const;
|
||||||
std::size_t num_open() const;
|
std::size_t num_open() const;
|
||||||
@ -165,39 +175,32 @@ namespace Opm {
|
|||||||
serializer(this->coord);
|
serializer(this->coord);
|
||||||
serializer(this->md);
|
serializer(this->md);
|
||||||
}
|
}
|
||||||
|
|
||||||
private:
|
private:
|
||||||
Connection::Order m_ordering { Connection::Order::TRACK };
|
Connection::Order m_ordering { Connection::Order::TRACK };
|
||||||
int headI{0};
|
int headI{0};
|
||||||
int headJ{0};
|
int headJ{0};
|
||||||
std::vector<Connection> m_connections{};
|
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{};
|
std::vector<double> md{};
|
||||||
|
|
||||||
void addConnection(const int i, const int j, const int k,
|
void addConnection(const int i, const int j, const int k,
|
||||||
const std::size_t global_index,
|
const std::size_t global_index,
|
||||||
const int complnum,
|
const int complnum,
|
||||||
const double depth,
|
|
||||||
const Connection::State state,
|
const Connection::State state,
|
||||||
const double CF,
|
const double depth,
|
||||||
const double Kh,
|
const Connection::CTFProperties& ctf_props,
|
||||||
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 int satTableId,
|
const int satTableId,
|
||||||
const Connection::Direction direction = Connection::Direction::Z,
|
const Connection::Direction direction,
|
||||||
const Connection::CTFKind ctf_kind = Connection::CTFKind::DeckValue,
|
const Connection::CTFKind ctf_kind,
|
||||||
const std::size_t seqIndex = 0,
|
const std::size_t seqIndex,
|
||||||
const bool defaultSatTabId = true);
|
const bool defaultSatTabId);
|
||||||
|
|
||||||
size_t findClosestConnection(int oi, int oj, double oz, size_t start_pos);
|
size_t findClosestConnection(int oi, int oj, double oz, size_t start_pos);
|
||||||
void orderTRACK();
|
void orderTRACK();
|
||||||
void orderMSW();
|
void orderMSW();
|
||||||
void orderDEPTH();
|
void orderDEPTH();
|
||||||
|
|
||||||
};
|
};
|
||||||
|
|
||||||
std::optional<int>
|
std::optional<int>
|
||||||
|
@ -19,50 +19,105 @@
|
|||||||
|
|
||||||
#include <opm/input/eclipse/Schedule/CompletedCells.hpp>
|
#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)
|
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_)
|
Opm::CompletedCells::CompletedCells(const Opm::GridDims& dims_)
|
||||||
:dims(dims_)
|
: dims(dims_)
|
||||||
{}
|
{}
|
||||||
|
|
||||||
|
const Opm::CompletedCells::Cell&
|
||||||
const Opm::CompletedCells::Cell& Opm::CompletedCells::get(std::size_t i, std::size_t j, std::size_t k) const {
|
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);
|
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) {
|
const auto& [pos, inserted] = this->cells.try_emplace(g, g, i, j, k);
|
||||||
auto g = this->dims.getGlobalIndex(i,j,k);
|
|
||||||
auto iter = this->cells.find(g);
|
|
||||||
if (iter != this->cells.end())
|
|
||||||
return {true, iter->second};
|
|
||||||
|
|
||||||
this->cells.emplace(g, Cell{g,i,j,k});
|
return { !inserted, pos->second };
|
||||||
return {false, this->cells.at(g)};
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
bool Opm::CompletedCells::operator==(const Opm::CompletedCells& other) const
|
||||||
bool Opm::CompletedCells::operator==(const Opm::CompletedCells& other) const {
|
{
|
||||||
return this->dims == other.dims &&
|
return (this->dims == other.dims)
|
||||||
this->cells == other.cells;
|
&& (this->cells == other.cells)
|
||||||
|
;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
Opm::CompletedCells
|
||||||
Opm::CompletedCells Opm::CompletedCells::serializationTestObject() {
|
Opm::CompletedCells::serializationTestObject()
|
||||||
|
{
|
||||||
Opm::CompletedCells cells(2,3,4);
|
Opm::CompletedCells cells(2,3,4);
|
||||||
cells.cells.emplace(7, Opm::CompletedCells::Cell::serializationTestObject());
|
cells.cells.emplace(7, Opm::CompletedCells::Cell::serializationTestObject());
|
||||||
|
|
||||||
return cells;
|
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;
|
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();
|
return this->props.has_value();
|
||||||
}
|
}
|
||||||
|
@ -196,37 +196,51 @@ namespace {
|
|||||||
this->snapshots.back().network.update( std::move( ext_network ));
|
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;
|
std::unordered_set<std::string> wells;
|
||||||
for (const auto& record : handlerContext.keyword) {
|
for (const auto& record : handlerContext.keyword) {
|
||||||
const std::string& wellNamePattern = record.getItem("WELL").getTrimmedString(0);
|
const auto wellNamePattern = record.getItem("WELL").getTrimmedString(0);
|
||||||
auto wellnames = this->wellNames(wellNamePattern, handlerContext,
|
const auto wellnames =
|
||||||
isWList(handlerContext.currentStep,
|
this->wellNames(wellNamePattern, handlerContext,
|
||||||
wellNamePattern));
|
isWList(handlerContext.currentStep, wellNamePattern));
|
||||||
|
|
||||||
for (const auto& name : wellnames) {
|
for (const auto& name : wellnames) {
|
||||||
auto well2 = this->snapshots.back().wells.get(name);
|
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());
|
auto wdfac = std::make_shared<WDFAC>(well2.getWDFAC());
|
||||||
wdfac->updateWDFACType(*connections);
|
wdfac->updateWDFACType(well2.getConnections());
|
||||||
|
|
||||||
well2.updateWDFAC(std::move(wdfac));
|
well2.updateWDFAC(std::move(wdfac));
|
||||||
this->snapshots.back().wells.update( well2 );
|
this->snapshots.back().wells.update(well2);
|
||||||
wells.insert( name );
|
|
||||||
|
wells.insert(name);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (connections->empty() && well2.getConnections().empty()) {
|
if (origWellConnSetIsEmpty && newWellConnSetIsEmpty) {
|
||||||
const auto& location = handlerContext.keyword.location();
|
const auto& location = handlerContext.keyword.location();
|
||||||
auto msg = fmt::format("Problem with COMPDAT/{}\n"
|
|
||||||
"In {} line {}\n"
|
const auto msg = fmt::format(R"(Problem with COMPDAT/{}
|
||||||
"Well {} is not connected to grid - will remain SHUT", name, location.filename, location.lineno, name);
|
In {} line {}
|
||||||
|
Well {} is not connected to grid - will remain SHUT)",
|
||||||
|
name, location.filename,
|
||||||
|
location.lineno, name);
|
||||||
|
|
||||||
OpmLog::warning(msg);
|
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);
|
this->snapshots.back().events().addEvent(ScheduleEvents::COMPLETION_CHANGE);
|
||||||
|
|
||||||
// In the case the wells reference depth has been defaulted in the
|
// 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
|
// reference depth exactly when the COMPDAT keyword has been completely
|
||||||
// processed.
|
// processed.
|
||||||
for (const auto& wname : wells) {
|
for (const auto& wname : wells) {
|
||||||
auto& well = this->snapshots.back().wells.get( wname );
|
auto well = this->snapshots.back().wells.get(wname);
|
||||||
well.updateRefDepth();
|
well.updateRefDepth();
|
||||||
this->snapshots.back().wells.update( std::move(well));
|
|
||||||
|
this->snapshots.back().wells.update(std::move(well));
|
||||||
}
|
}
|
||||||
|
|
||||||
if (! wells.empty()) {
|
if (! wells.empty()) {
|
||||||
@ -268,20 +283,30 @@ namespace {
|
|||||||
this->snapshots.back().events().addEvent(ScheduleEvents::COMPLETION_CHANGE);
|
this->snapshots.back().events().addEvent(ScheduleEvents::COMPLETION_CHANGE);
|
||||||
}
|
}
|
||||||
|
|
||||||
void Schedule::handleCOMPTRAJ(HandlerContext& handlerContext) {
|
void Schedule::handleCOMPTRAJ(HandlerContext& handlerContext)
|
||||||
|
{
|
||||||
// Keyword WELTRAJ must be read first
|
// Keyword WELTRAJ must be read first
|
||||||
std::unordered_set<std::string> wells;
|
std::unordered_set<std::string> wells;
|
||||||
external::cvf::ref<external::cvf::BoundingBoxTree> cellSearchTree = nullptr;
|
external::cvf::ref<external::cvf::BoundingBoxTree> cellSearchTree = nullptr;
|
||||||
|
|
||||||
for (const auto& record : handlerContext.keyword) {
|
for (const auto& record : handlerContext.keyword) {
|
||||||
const std::string& wellNamePattern = record.getItem("WELL").getTrimmedString(0);
|
const auto wellNamePattern = record.getItem("WELL").getTrimmedString(0);
|
||||||
auto wellnames = this->wellNames(wellNamePattern, handlerContext );
|
const auto wellnames = this->wellNames(wellNamePattern, handlerContext);
|
||||||
|
|
||||||
for (const auto& name : wellnames) {
|
for (const auto& name : wellnames) {
|
||||||
auto well2 = this->snapshots.back().wells.get(name);
|
auto well2 = this->snapshots.back().wells.get(name);
|
||||||
auto connections = std::make_shared<WellConnections>(WellConnections(well2.getConnections()));
|
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);
|
// cellsearchTree is calculated only once and is used to
|
||||||
// In the case that defaults are used in WELSPECS for headI/J the headI/J are calculated based on the well trajectory data
|
// 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());
|
well2.updateHead(connections->getHeadI(), connections->getHeadJ());
|
||||||
if (well2.updateConnections(connections, handlerContext.grid)) {
|
if (well2.updateConnections(connections, handlerContext.grid)) {
|
||||||
this->snapshots.back().wells.update( well2 );
|
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);
|
"Well {} is not connected to grid - will remain SHUT", name, location.filename, location.lineno, name);
|
||||||
OpmLog::warning(msg);
|
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);
|
this->snapshots.back().events().addEvent(ScheduleEvents::COMPLETION_CHANGE);
|
||||||
|
|
||||||
// In the case the wells reference depth has been defaulted in the
|
// In the case the wells reference depth has been defaulted in the
|
||||||
// WELSPECS keyword we need to force a calculation of the wells
|
// WELSPECS keyword we need to force a calculation of the wells
|
||||||
// reference depth exactly when the WELCOML keyword has been completely
|
// reference depth exactly when the WELCOML keyword has been
|
||||||
// processed.
|
// completely processed.
|
||||||
for (const auto& wname : wells) {
|
for (const auto& wname : wells) {
|
||||||
auto& well = this->snapshots.back().wells.get( wname );
|
auto& well = this->snapshots.back().wells.get(wname);
|
||||||
well.updateRefDepth();
|
well.updateRefDepth();
|
||||||
this->snapshots.back().wells.update( std::move(well));
|
|
||||||
|
this->snapshots.back().wells.update(std::move(well));
|
||||||
}
|
}
|
||||||
|
|
||||||
if (! wells.empty()) {
|
if (! wells.empty()) {
|
||||||
@ -377,23 +406,29 @@ File {} line {}.)", wname, location.keyword, location.filename, location.lineno)
|
|||||||
handlerContext.compsegs_handled(wname);
|
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
|
// Get CSKIN keyword info and current step
|
||||||
const auto& keyword = handlerContext.keyword;
|
const auto& keyword = handlerContext.keyword;
|
||||||
const auto& currentStep = handlerContext.currentStep;
|
const auto& currentStep = handlerContext.currentStep;
|
||||||
|
|
||||||
// Loop over records in CSKIN
|
// Loop over records in CSKIN
|
||||||
for (const auto& record: keyword) {
|
for (const auto& record : keyword) {
|
||||||
// Get well names
|
// 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);
|
const auto well_names = this->wellNames(wellNamePattern, handlerContext);
|
||||||
|
|
||||||
// Loop over well(s) in record
|
// Loop over well(s) in record
|
||||||
for (const auto& wname : well_names) {
|
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);
|
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());
|
auto wdfac = std::make_shared<WDFAC>(well.getWDFAC());
|
||||||
wdfac->updateWDFAC( record );
|
wdfac->updateWDFAC( record );
|
||||||
wdfac->updateTotalCF(well.getConnections());
|
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) {
|
void Schedule::handleWDFACCOR(HandlerContext& handlerContext) {
|
||||||
for (const auto& record : handlerContext.keyword) {
|
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);
|
const auto well_names = wellNames(wellNamePattern, handlerContext.currentStep);
|
||||||
if (well_names.empty())
|
if (well_names.empty())
|
||||||
this->invalidNamePattern(wellNamePattern, handlerContext);
|
this->invalidNamePattern(wellNamePattern, handlerContext);
|
||||||
|
|
||||||
for (const auto& well_name : well_names) {
|
for (const auto& well_name : well_names) {
|
||||||
auto well = this->snapshots.back().wells.get(well_name);
|
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());
|
auto wdfac = std::make_shared<WDFAC>(well.getWDFAC());
|
||||||
wdfac->updateWDFACCOR( record );
|
wdfac->updateWDFACCOR(record);
|
||||||
if (well.updateWDFAC(std::move(wdfac)))
|
|
||||||
this->snapshots.back().wells.update( std::move(well) );
|
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/>.
|
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/ScheduleGrid.hpp>
|
||||||
|
|
||||||
|
#include <opm/input/eclipse/Schedule/CompletedCells.hpp>
|
||||||
|
|
||||||
#include <opm/input/eclipse/EclipseState/Grid/EclipseGrid.hpp>
|
#include <opm/input/eclipse/EclipseState/Grid/EclipseGrid.hpp>
|
||||||
#include <opm/input/eclipse/EclipseState/Grid/FieldPropsManager.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)
|
#include <cstddef>
|
||||||
: grid(&ecl_grid)
|
#include <string>
|
||||||
, fp(&fpm)
|
|
||||||
, cells(completed_cells)
|
#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)
|
Opm::ScheduleGrid::ScheduleGrid(Opm::CompletedCells& completed_cells)
|
||||||
@ -34,45 +42,58 @@ Opm::ScheduleGrid::ScheduleGrid(Opm::CompletedCells& completed_cells)
|
|||||||
{}
|
{}
|
||||||
|
|
||||||
namespace {
|
namespace {
|
||||||
double try_get_value(const Opm::FieldPropsManager& fp, const std::string& kw, std::size_t active_index) {
|
double try_get_value(const Opm::FieldPropsManager& fp,
|
||||||
if (fp.has_double(kw))
|
const std::string& kw,
|
||||||
return fp.try_get<double>(kw)->at(active_index);
|
const std::size_t active_index)
|
||||||
else
|
{
|
||||||
|
if (! fp.has_double(kw)) {
|
||||||
throw std::logic_error(fmt::format("FieldPropsManager is missing keyword '{}'", 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 fp.try_get<double>(kw)->at(active_index);
|
||||||
return this->cells.get(i,j,k);
|
}
|
||||||
|
|
||||||
|
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 {
|
const Opm::CompletedCells::Cell&
|
||||||
return this->grid;
|
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,159 @@
|
|||||||
along with OPM. If not, see <http://www.gnu.org/licenses/>.
|
along with OPM. If not, see <http://www.gnu.org/licenses/>.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
|
#include <opm/input/eclipse/Schedule/Well/Connection.hpp>
|
||||||
|
|
||||||
|
#include <opm/io/eclipse/rst/connection.hpp>
|
||||||
|
|
||||||
|
#include <opm/input/eclipse/EclipseState/Grid/FieldPropsManager.hpp>
|
||||||
|
|
||||||
|
#include <opm/input/eclipse/Schedule/ScheduleGrid.hpp>
|
||||||
|
#include <opm/input/eclipse/Schedule/Well/FilterCake.hpp>
|
||||||
|
|
||||||
|
#include <opm/input/eclipse/Deck/DeckItem.hpp>
|
||||||
|
#include <opm/input/eclipse/Deck/DeckKeyword.hpp>
|
||||||
|
#include <opm/input/eclipse/Deck/DeckRecord.hpp>
|
||||||
|
|
||||||
#include <algorithm>
|
#include <algorithm>
|
||||||
#include <cassert>
|
#include <cassert>
|
||||||
#include <exception>
|
#include <exception>
|
||||||
#include <sstream>
|
#include <sstream>
|
||||||
#include <stdexcept>
|
#include <stdexcept>
|
||||||
|
#include <string>
|
||||||
|
#include <string_view>
|
||||||
#include <vector>
|
#include <vector>
|
||||||
|
|
||||||
#include <opm/io/eclipse/rst/connection.hpp>
|
|
||||||
#include <opm/input/eclipse/Deck/DeckItem.hpp>
|
|
||||||
#include <opm/input/eclipse/Deck/DeckKeyword.hpp>
|
|
||||||
#include <opm/input/eclipse/Deck/DeckRecord.hpp>
|
|
||||||
#include <opm/input/eclipse/EclipseState/Grid/FieldPropsManager.hpp>
|
|
||||||
#include <opm/input/eclipse/Schedule/Well/Connection.hpp>
|
|
||||||
#include <opm/input/eclipse/Schedule/Well/FilterCake.hpp>
|
|
||||||
#include <opm/input/eclipse/Schedule/ScheduleGrid.hpp>
|
|
||||||
|
|
||||||
namespace Opm {
|
|
||||||
|
|
||||||
|
|
||||||
Connection::Connection(int i, int j , int k ,
|
|
||||||
std::size_t global_index,
|
|
||||||
int compnum,
|
|
||||||
double depth,
|
|
||||||
State stateArg ,
|
|
||||||
double CF,
|
|
||||||
double Kh,
|
|
||||||
double rw,
|
|
||||||
double r0,
|
|
||||||
double re,
|
|
||||||
double connection_length,
|
|
||||||
double skin_factor,
|
|
||||||
double d_factor,
|
|
||||||
double Ke,
|
|
||||||
const int satTableId,
|
|
||||||
const Direction directionArg,
|
|
||||||
const CTFKind ctf_kind,
|
|
||||||
const std::size_t sort_value,
|
|
||||||
const bool defaultSatTabId)
|
|
||||||
: direction(directionArg),
|
|
||||||
center_depth(depth),
|
|
||||||
open_state(stateArg),
|
|
||||||
sat_tableId(satTableId),
|
|
||||||
m_complnum( compnum ),
|
|
||||||
m_CF(CF),
|
|
||||||
m_Kh(Kh),
|
|
||||||
m_rw(rw),
|
|
||||||
m_r0(r0),
|
|
||||||
m_re(re),
|
|
||||||
m_connection_length(connection_length),
|
|
||||||
m_skin_factor(skin_factor),
|
|
||||||
m_d_factor(d_factor),
|
|
||||||
m_Ke(Ke),
|
|
||||||
ijk({i,j,k}),
|
|
||||||
m_ctfkind(ctf_kind),
|
|
||||||
m_global_index(global_index),
|
|
||||||
m_sort_value(sort_value),
|
|
||||||
m_defaultSatTabId(defaultSatTabId)
|
|
||||||
{
|
|
||||||
}
|
|
||||||
|
|
||||||
namespace {
|
namespace {
|
||||||
constexpr bool defaultSatTabId = true;
|
constexpr bool restartDefaultSatTabId = true;
|
||||||
|
|
||||||
|
Opm::Connection::CTFProperties
|
||||||
|
collectCTFProps(const Opm::RestartIO::RstConnection& rst_conn)
|
||||||
|
{
|
||||||
|
auto props = Opm::Connection::CTFProperties{};
|
||||||
|
|
||||||
|
props.CF = rst_conn.cf;
|
||||||
|
props.Kh = rst_conn.kh;
|
||||||
|
props.Ke = 0.0;
|
||||||
|
props.rw = rst_conn.diameter / 2;
|
||||||
|
props.r0 = rst_conn.r0;
|
||||||
|
props.re = 0.0;
|
||||||
|
props.connection_length = 0.0;
|
||||||
|
props.skin_factor = rst_conn.skin_factor;
|
||||||
|
props.d_factor = 0.0;
|
||||||
|
|
||||||
|
return props;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
Connection::Connection(const RestartIO::RstConnection& rst_connection, const ScheduleGrid& grid, const FieldPropsManager& fp) :
|
namespace Opm
|
||||||
direction(rst_connection.dir),
|
{
|
||||||
center_depth(rst_connection.depth),
|
|
||||||
open_state(rst_connection.state),
|
Connection::CTFProperties
|
||||||
sat_tableId(rst_connection.drain_sat_table),
|
Connection::CTFProperties::serializationTestObject()
|
||||||
m_complnum(rst_connection.completion),
|
{
|
||||||
m_CF(rst_connection.cf),
|
auto props = Opm::Connection::CTFProperties{};
|
||||||
m_Kh(rst_connection.kh),
|
|
||||||
m_rw(rst_connection.diameter / 2),
|
props.CF = 1.0;
|
||||||
m_r0(rst_connection.r0),
|
props.Kh = 2.0;
|
||||||
m_re(0.0),
|
props.Ke = 3.0;
|
||||||
m_connection_length(0.0),
|
props.rw = 4.0;
|
||||||
m_skin_factor(rst_connection.skin_factor),
|
props.r0 = 5.0;
|
||||||
m_d_factor(0.0),
|
props.re = 6.0;
|
||||||
m_Ke(0.0),
|
props.connection_length = 7.0;
|
||||||
ijk(rst_connection.ijk),
|
props.skin_factor = 8.0;
|
||||||
m_ctfkind(rst_connection.cf_kind),
|
props.d_factor = 9.0;
|
||||||
m_global_index(grid.get_cell(this->ijk[0], this->ijk[1], this->ijk[2]).global_index),
|
props.static_dfac_corr_coeff = 10.0;
|
||||||
m_sort_value(rst_connection.rst_index),
|
props.peaceman_denom = 11.0;
|
||||||
m_defaultSatTabId(defaultSatTabId),
|
|
||||||
segment_number(rst_connection.segment)
|
return props;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool Connection::CTFProperties::operator==(const CTFProperties& that) const
|
||||||
|
{
|
||||||
|
return (this->CF == that.CF)
|
||||||
|
&& (this->Kh == that.Kh)
|
||||||
|
&& (this->Ke == that.Ke)
|
||||||
|
&& (this->rw == that.rw)
|
||||||
|
&& (this->r0 == that.r0)
|
||||||
|
&& (this->re == that.re)
|
||||||
|
&& (this->connection_length == that.connection_length)
|
||||||
|
&& (this->skin_factor == that.skin_factor)
|
||||||
|
&& (this->d_factor == that.d_factor)
|
||||||
|
&& (this->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) {
|
if (this->m_defaultSatTabId) {
|
||||||
const auto& satnum = fp.get_int("SATNUM");
|
const auto active_index = grid
|
||||||
auto active_index = grid.get_cell(this->ijk[0], this->ijk[1], this->ijk[2]).active_index();
|
.get_cell(this->ijk[0], this->ijk[1], this->ijk[2])
|
||||||
this->sat_tableId = satnum[active_index];
|
.active_index();
|
||||||
|
|
||||||
|
this->sat_tableId = fp.get_int("SATNUM")[active_index];
|
||||||
|
}
|
||||||
|
|
||||||
|
if (this->segment_number > 0) {
|
||||||
|
this->m_perf_range = std::make_pair(rst_connection.segdist_start,
|
||||||
|
rst_connection.segdist_end);
|
||||||
}
|
}
|
||||||
if (this->segment_number > 0)
|
|
||||||
this->m_perf_range = std::make_pair(rst_connection.segdist_start, rst_connection.segdist_end);
|
|
||||||
|
|
||||||
//TODO recompute re and perf_length from the grid
|
//TODO recompute re and perf_length from the grid
|
||||||
}
|
}
|
||||||
|
|
||||||
Connection::Connection()
|
|
||||||
: Connection(0, 0, 0, 0, 0, 0.0, State::SHUT, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0,
|
|
||||||
0, Direction::X, CTFKind::DeckValue, 0, false)
|
|
||||||
{}
|
|
||||||
|
|
||||||
Connection Connection::serializationTestObject()
|
Connection Connection::serializationTestObject()
|
||||||
{
|
{
|
||||||
Connection result;
|
Connection result;
|
||||||
|
|
||||||
result.direction = Direction::Y;
|
result.direction = Direction::Y;
|
||||||
result.center_depth = 1.0;
|
result.center_depth = 1.0;
|
||||||
result.open_state = State::OPEN;
|
result.open_state = State::OPEN;
|
||||||
result.sat_tableId = 2;
|
result.sat_tableId = 2;
|
||||||
result.m_complnum = 3;
|
result.m_complnum = 3;
|
||||||
result.m_CF = 4.0;
|
|
||||||
result.m_Kh = 5.0;
|
result.ctf_properties_ = CTFProperties::serializationTestObject();
|
||||||
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.ijk = {9, 10, 11};
|
result.ijk = {9, 10, 11};
|
||||||
result.m_ctfkind = CTFKind::Defaulted;
|
result.m_ctfkind = CTFKind::Defaulted;
|
||||||
result.m_global_index = 12;
|
result.m_global_index = 12;
|
||||||
@ -144,144 +178,181 @@ Connection::Connection(const RestartIO::RstConnection& rst_connection, const Sch
|
|||||||
result.m_sort_value = 14;
|
result.m_sort_value = 14;
|
||||||
result.m_defaultSatTabId = true;
|
result.m_defaultSatTabId = true;
|
||||||
result.segment_number = 16;
|
result.segment_number = 16;
|
||||||
|
result.m_wpimult = 0.123;
|
||||||
result.m_subject_to_welpi = true;
|
result.m_subject_to_welpi = true;
|
||||||
result.m_filter_cake = FilterCake::serializationTestObject();
|
result.m_filter_cake = FilterCake::serializationTestObject();
|
||||||
|
|
||||||
return result;
|
return result;
|
||||||
}
|
}
|
||||||
|
|
||||||
bool Connection::sameCoordinate(const int i, const int j, const int k) const {
|
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;
|
return this->ijk == std::array { i, j, k };
|
||||||
} else {
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
int Connection::getI() const {
|
int Connection::getI() const
|
||||||
|
{
|
||||||
return ijk[0];
|
return ijk[0];
|
||||||
}
|
}
|
||||||
|
|
||||||
int Connection::getJ() const {
|
int Connection::getJ() const
|
||||||
|
{
|
||||||
return ijk[1];
|
return ijk[1];
|
||||||
}
|
}
|
||||||
|
|
||||||
int Connection::getK() const {
|
int Connection::getK() const
|
||||||
|
{
|
||||||
return ijk[2];
|
return ijk[2];
|
||||||
}
|
}
|
||||||
|
|
||||||
std::size_t Connection::global_index() const {
|
std::size_t Connection::global_index() const
|
||||||
|
{
|
||||||
return this->m_global_index;
|
return this->m_global_index;
|
||||||
}
|
}
|
||||||
|
|
||||||
bool Connection::attachedToSegment() const {
|
bool Connection::attachedToSegment() const
|
||||||
return (segment_number > 0);
|
{
|
||||||
|
return this->segment_number > 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
std::size_t Connection::sort_value() const {
|
std::size_t Connection::sort_value() const
|
||||||
|
{
|
||||||
return m_sort_value;
|
return m_sort_value;
|
||||||
}
|
}
|
||||||
|
|
||||||
const bool& Connection::getDefaultSatTabId() const {
|
bool Connection::getDefaultSatTabId() const
|
||||||
|
{
|
||||||
return m_defaultSatTabId;
|
return m_defaultSatTabId;
|
||||||
}
|
}
|
||||||
|
|
||||||
Connection::Direction Connection::dir() const {
|
Connection::Direction Connection::dir() const
|
||||||
|
{
|
||||||
return this->direction;
|
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;
|
return this->m_perf_range;
|
||||||
}
|
}
|
||||||
|
|
||||||
void Connection::setDefaultSatTabId(bool id) {
|
void Connection::setDefaultSatTabId(bool id)
|
||||||
|
{
|
||||||
m_defaultSatTabId = id;
|
m_defaultSatTabId = id;
|
||||||
}
|
}
|
||||||
|
|
||||||
double Connection::depth() const {
|
double Connection::depth() const
|
||||||
|
{
|
||||||
return this->center_depth;
|
return this->center_depth;
|
||||||
}
|
}
|
||||||
|
|
||||||
Connection::State Connection::state() const {
|
Connection::State Connection::state() const
|
||||||
|
{
|
||||||
return this->open_state;
|
return this->open_state;
|
||||||
}
|
}
|
||||||
|
|
||||||
int Connection::satTableId() const {
|
int Connection::satTableId() const
|
||||||
|
{
|
||||||
return this->sat_tableId;
|
return this->sat_tableId;
|
||||||
}
|
}
|
||||||
|
|
||||||
int Connection::complnum() const {
|
int Connection::complnum() const
|
||||||
|
{
|
||||||
return this->m_complnum;
|
return this->m_complnum;
|
||||||
}
|
}
|
||||||
|
|
||||||
void Connection::setComplnum(int complnum) {
|
void Connection::setComplnum(int complnum)
|
||||||
|
{
|
||||||
this->m_complnum = complnum;
|
this->m_complnum = complnum;
|
||||||
}
|
}
|
||||||
|
|
||||||
void Connection::setSkinFactor(double skin_factor) {
|
void Connection::setSkinFactor(double skin_factor)
|
||||||
this->m_skin_factor = 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) {
|
void Connection::setDFactor(double d_factor)
|
||||||
this->m_d_factor = d_factor;
|
{
|
||||||
|
this->ctf_properties_.d_factor = d_factor;
|
||||||
}
|
}
|
||||||
|
|
||||||
void Connection::setKe(double Ke) {
|
void Connection::setKe(double Ke)
|
||||||
this->m_Ke = Ke;
|
{
|
||||||
|
this->ctf_properties_.Ke = Ke;
|
||||||
}
|
}
|
||||||
|
|
||||||
void Connection::setCF(double CF) {
|
void Connection::setCF(double CF)
|
||||||
this->m_CF = CF;
|
{
|
||||||
|
this->ctf_properties_.CF = CF;
|
||||||
}
|
}
|
||||||
|
|
||||||
double Connection::CF() const {
|
double Connection::wpimult() const
|
||||||
return this->m_CF;
|
{
|
||||||
}
|
|
||||||
|
|
||||||
double Connection::wpimult() const {
|
|
||||||
return this->m_wpimult;
|
return this->m_wpimult;
|
||||||
}
|
}
|
||||||
|
|
||||||
double Connection::Kh() const {
|
double Connection::CF() const
|
||||||
return this->m_Kh;
|
{
|
||||||
|
return this->ctf_properties_.CF;
|
||||||
}
|
}
|
||||||
|
|
||||||
double Connection::rw() const {
|
double Connection::Kh() const
|
||||||
return this->m_rw;
|
{
|
||||||
|
return this->ctf_properties_.Kh;
|
||||||
}
|
}
|
||||||
|
|
||||||
double Connection::r0() const {
|
double Connection::rw() const
|
||||||
return this->m_r0;
|
{
|
||||||
|
return this->ctf_properties_.rw;
|
||||||
}
|
}
|
||||||
|
|
||||||
double Connection::re() const {
|
double Connection::r0() const
|
||||||
return this->m_re;
|
{
|
||||||
|
return this->ctf_properties_.r0;
|
||||||
}
|
}
|
||||||
|
|
||||||
double Connection::connectionLength() const {
|
double Connection::re() const
|
||||||
return this->m_connection_length;
|
{
|
||||||
|
return this->ctf_properties_.re;
|
||||||
}
|
}
|
||||||
|
|
||||||
double Connection::skinFactor() const {
|
double Connection::connectionLength() const
|
||||||
return this->m_skin_factor;
|
{
|
||||||
|
return this->ctf_properties_.connection_length;
|
||||||
}
|
}
|
||||||
|
|
||||||
double Connection::dFactor() const {
|
double Connection::skinFactor() const
|
||||||
return this->m_d_factor;
|
{
|
||||||
|
return this->ctf_properties_.skin_factor;
|
||||||
}
|
}
|
||||||
|
|
||||||
double Connection::Ke() const {
|
double Connection::dFactor() const
|
||||||
return this->m_Ke;
|
{
|
||||||
|
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;
|
this->open_state = state;
|
||||||
}
|
}
|
||||||
|
|
||||||
void Connection::updateSegment(int segment_number_arg,
|
void Connection::updateSegment(const int segment_number_arg,
|
||||||
double center_depth_arg,
|
const double center_depth_arg,
|
||||||
std::size_t compseg_insert_index,
|
const std::size_t compseg_insert_index,
|
||||||
const std::optional<std::pair<double, double>>& perf_range) {
|
const std::optional<std::pair<double, double>>& perf_range)
|
||||||
|
{
|
||||||
this->segment_number = segment_number_arg;
|
this->segment_number = segment_number_arg;
|
||||||
this->center_depth = center_depth_arg;
|
this->center_depth = center_depth_arg;
|
||||||
this->m_sort_value = compseg_insert_index;
|
this->m_sort_value = compseg_insert_index;
|
||||||
@ -289,124 +360,142 @@ const std::optional<std::pair<double, double>>& Connection::perf_range() const {
|
|||||||
}
|
}
|
||||||
|
|
||||||
void Connection::updateSegmentRST(int segment_number_arg,
|
void Connection::updateSegmentRST(int segment_number_arg,
|
||||||
double center_depth_arg) {
|
double center_depth_arg)
|
||||||
|
{
|
||||||
this->segment_number = segment_number_arg;
|
this->segment_number = segment_number_arg;
|
||||||
this->center_depth = center_depth_arg;
|
this->center_depth = center_depth_arg;
|
||||||
}
|
}
|
||||||
|
|
||||||
int Connection::segment() const {
|
int Connection::segment() const
|
||||||
|
{
|
||||||
return this->segment_number;
|
return this->segment_number;
|
||||||
}
|
}
|
||||||
|
|
||||||
void Connection::scaleWellPi(double wellPi) {
|
void Connection::scaleWellPi(double wellPi)
|
||||||
|
{
|
||||||
this->m_wpimult *= 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;
|
const auto update = !this->m_subject_to_welpi;
|
||||||
|
|
||||||
this->m_subject_to_welpi = true;
|
this->m_subject_to_welpi = true;
|
||||||
|
|
||||||
return update;
|
return update;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
bool Connection::applyWellPIScaling(const double scaleFactor) {
|
bool Connection::applyWellPIScaling(const double scaleFactor)
|
||||||
if (! this->m_subject_to_welpi)
|
{
|
||||||
|
if (! this->m_subject_to_welpi) {
|
||||||
return false;
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
this->scaleWellPi(scaleFactor);
|
this->scaleWellPi(scaleFactor);
|
||||||
return true;
|
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;
|
std::stringstream ss;
|
||||||
ss << "ijk: " << this->ijk[0] << "," << this->ijk[1] << "," << this->ijk[2] << std::endl;
|
|
||||||
ss << "COMPLNUM " << this->m_complnum << std::endl;
|
ss << "ijk: " << this->ijk[0] << ',' << this->ijk[1] << ',' << this->ijk[2] << '\n'
|
||||||
ss << "CF " << this->m_CF << std::endl;
|
<< "COMPLNUM " << this->m_complnum << '\n'
|
||||||
ss << "RW " << this->m_rw << std::endl;
|
<< "CF " << this->CF() << '\n'
|
||||||
ss << "R0 " << this->m_r0 << std::endl;
|
<< "RW " << this->rw() << '\n'
|
||||||
ss << "Re " << this->m_re << std::endl;
|
<< "R0 " << this->r0() << '\n'
|
||||||
ss << "connection length " << this->m_connection_length << std::endl;
|
<< "Re " << this->re() << '\n'
|
||||||
ss << "skinf " << this->m_skin_factor << std::endl;
|
<< "connection length " << this->connectionLength() << '\n'
|
||||||
ss << "dfactor " << this->m_d_factor << std::endl;
|
<< "skinf " << this->skinFactor() << '\n'
|
||||||
ss << "Ke " << this->m_Ke << std::endl;
|
<< "dfactor " << this->dFactor() << '\n'
|
||||||
ss << "kh " << this->m_Kh << std::endl;
|
<< "Ke " << this->Ke() << '\n'
|
||||||
ss << "sat_tableId " << this->sat_tableId << std::endl;
|
<< "kh " << this->Kh() << '\n'
|
||||||
ss << "open_state " << Connection::State2String(this->open_state) << std::endl;
|
<< "sat_tableId " << this->sat_tableId << '\n'
|
||||||
ss << "direction " << Connection::Direction2String(this->direction) << std::endl;
|
<< "open_state " << Connection::State2String(this->open_state) << '\n'
|
||||||
ss << "CTF Source " << Connection::CTFKindToString(this->m_ctfkind) << '\n';
|
<< "direction " << Connection::Direction2String(this->direction) << '\n'
|
||||||
ss << "segment_nr " << this->segment_number << std::endl;
|
<< "CTF Source " << Connection::CTFKindToString(this->m_ctfkind) << '\n'
|
||||||
ss << "center_depth " << this->center_depth << std::endl;
|
<< "segment_nr " << this->segment_number << '\n'
|
||||||
ss << "sort_value" << this->m_sort_value<< std::endl;
|
<< "center_depth " << this->center_depth << '\n'
|
||||||
|
<< "sort_value" << this->m_sort_value<< '\n';
|
||||||
|
|
||||||
if (this->m_injmult.has_value()) {
|
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()) {
|
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();
|
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 {
|
bool Connection::operator==(const Connection& that) const
|
||||||
return !( *this == rhs );
|
{
|
||||||
|
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)
|
||||||
|
;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
std::string Connection::State2String(State enumValue)
|
||||||
const std::string Connection::State2String( State enumValue ) {
|
{
|
||||||
switch( enumValue ) {
|
switch (enumValue) {
|
||||||
case State::OPEN:
|
case State::OPEN:
|
||||||
return "OPEN";
|
return "OPEN";
|
||||||
|
|
||||||
case State::AUTO:
|
case State::AUTO:
|
||||||
return "AUTO";
|
return "AUTO";
|
||||||
|
|
||||||
case State::SHUT:
|
case State::SHUT:
|
||||||
return "SHUT";
|
return "SHUT";
|
||||||
|
|
||||||
default:
|
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::State Connection::StateFromString( const std::string& stringValue ) {
|
Connection::StateFromString(std::string_view stringValue)
|
||||||
|
{
|
||||||
if (stringValue == "OPEN")
|
if (stringValue == "OPEN")
|
||||||
return State::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)
|
std::string Connection::Direction2String(const Direction enumValue)
|
||||||
@ -434,8 +523,7 @@ std::string Connection::Direction2String(const Direction enumValue)
|
|||||||
return stringValue;
|
return stringValue;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
Connection::Direction Connection::DirectionFromString(std::string_view s)
|
||||||
Connection::Direction Connection::DirectionFromString(const std::string& s )
|
|
||||||
{
|
{
|
||||||
Direction direction;
|
Direction direction;
|
||||||
|
|
||||||
@ -443,47 +531,61 @@ Connection::Direction Connection::DirectionFromString(const std::string& s )
|
|||||||
else if ((s == "Y") || (s == "y")) { direction = Direction::Y; }
|
else if ((s == "Y") || (s == "y")) { direction = Direction::Y; }
|
||||||
else if ((s == "Z") || (s == "z")) { direction = Direction::Z; }
|
else if ((s == "Z") || (s == "z")) { direction = Direction::Z; }
|
||||||
else {
|
else {
|
||||||
std::string msg = "Unsupported completion direction " + s;
|
throw std::invalid_argument {
|
||||||
throw std::invalid_argument(msg);
|
"Unsupported completion direction "
|
||||||
|
+ std::string { s }
|
||||||
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
return direction;
|
return direction;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
const std::string Connection::Order2String( Order enumValue ) {
|
std::string Connection::Order2String(Order enumValue)
|
||||||
switch( enumValue ) {
|
{
|
||||||
|
switch (enumValue) {
|
||||||
case Order::DEPTH:
|
case Order::DEPTH:
|
||||||
return "DEPTH";
|
return "DEPTH";
|
||||||
|
|
||||||
case Order::INPUT:
|
case Order::INPUT:
|
||||||
return "INPUT";
|
return "INPUT";
|
||||||
|
|
||||||
case Order::TRACK:
|
case Order::TRACK:
|
||||||
return "TRACK";
|
return "TRACK";
|
||||||
|
|
||||||
default:
|
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(std::string_view stringValue)
|
||||||
Connection::Order Connection::OrderFromString(const std::string& stringValue ) {
|
{
|
||||||
if (stringValue == "DEPTH")
|
if (stringValue == "DEPTH")
|
||||||
return Order::DEPTH;
|
return Order::DEPTH;
|
||||||
else if (stringValue == "INPUT")
|
|
||||||
|
if (stringValue == "INPUT")
|
||||||
return Order::INPUT;
|
return Order::INPUT;
|
||||||
else if (stringValue == "TRACK")
|
|
||||||
|
if (stringValue == "TRACK")
|
||||||
return Order::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)
|
std::string Connection::CTFKindToString(const CTFKind ctf_kind)
|
||||||
{
|
{
|
||||||
switch (ctf_kind) {
|
switch (ctf_kind) {
|
||||||
case CTFKind::DeckValue:
|
case CTFKind::DeckValue:
|
||||||
return "DeckValue";
|
return "DeckValue";
|
||||||
|
|
||||||
case CTFKind::Defaulted:
|
case CTFKind::Defaulted:
|
||||||
return "Defaulted";
|
return "Defaulted";
|
||||||
}
|
}
|
||||||
|
|
||||||
throw std::invalid_argument {
|
throw std::invalid_argument {
|
||||||
@ -492,58 +594,62 @@ std::string Connection::CTFKindToString(const CTFKind ctf_kind)
|
|||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
Connection::CTFKind Connection::kind() const {
|
Connection::CTFKind Connection::kind() const
|
||||||
|
{
|
||||||
return m_ctfkind;
|
return m_ctfkind;
|
||||||
}
|
}
|
||||||
|
|
||||||
const InjMult& Connection::injmult() const {
|
const InjMult& Connection::injmult() const
|
||||||
|
{
|
||||||
assert(this->activeInjMult());
|
assert(this->activeInjMult());
|
||||||
return m_injmult.value();
|
return m_injmult.value();
|
||||||
}
|
}
|
||||||
|
|
||||||
bool Connection::activeInjMult() const {
|
bool Connection::activeInjMult() const
|
||||||
|
{
|
||||||
return this->m_injmult.has_value();
|
return this->m_injmult.has_value();
|
||||||
}
|
}
|
||||||
|
|
||||||
void Connection::setInjMult(const InjMult& inj_mult) {
|
void Connection::setInjMult(const InjMult& inj_mult)
|
||||||
|
{
|
||||||
m_injmult = inj_mult;
|
m_injmult = inj_mult;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void Connection::setFilterCake(const FilterCake& filter_cake)
|
||||||
void Connection::setFilterCake(const FilterCake& filter_cake) {
|
{
|
||||||
this->m_filter_cake = filter_cake;
|
this->m_filter_cake = filter_cake;
|
||||||
}
|
}
|
||||||
|
|
||||||
bool Connection::filterCakeActive() const {
|
bool Connection::filterCakeActive() const
|
||||||
|
{
|
||||||
return this->m_filter_cake.has_value();
|
return this->m_filter_cake.has_value();
|
||||||
}
|
}
|
||||||
|
|
||||||
const FilterCake& Connection::getFilterCake() const {
|
const FilterCake& Connection::getFilterCake() const
|
||||||
assert(this->filterCakeActive());
|
{
|
||||||
return this->m_filter_cake.value();
|
assert(this->filterCakeActive());
|
||||||
|
return this->m_filter_cake.value();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
double Connection::getFilterCakeRadius() const
|
||||||
double Connection::getFilterCakeRadius() const {
|
{
|
||||||
if (this->getFilterCake().radius.has_value()) {
|
if (const auto& radius = this->getFilterCake().radius; radius.has_value()) {
|
||||||
return this->getFilterCake().radius.value();
|
return *radius;
|
||||||
} else {
|
}
|
||||||
return this->m_rw;
|
else {
|
||||||
|
return this->rw();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
double Connection::getFilterCakeArea() const
|
||||||
double Connection::getFilterCakeArea() const {
|
{
|
||||||
if (this->getFilterCake().flow_area.has_value()) {
|
if (const auto& flow_area = this->getFilterCake().flow_area; flow_area.has_value()) {
|
||||||
return this->getFilterCake().flow_area.value();
|
return *flow_area;
|
||||||
} else {
|
}
|
||||||
const double radius = this->getFilterCakeRadius();
|
else {
|
||||||
const double length = this->m_connection_length;
|
constexpr double two_pi = 2 * 3.14159265358979323846264;
|
||||||
constexpr double pi = 3.14159265;
|
return two_pi * this->getFilterCakeRadius() * this->connectionLength();
|
||||||
return 2. * pi * radius * length;
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
} // end of namespace Opm
|
} // end of namespace Opm
|
||||||
|
@ -17,126 +17,168 @@
|
|||||||
along with OPM. If not, see <http://www.gnu.org/licenses/>.
|
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/io/eclipse/rst/well.hpp>
|
||||||
#include <opm/output/eclipse/VectorItems/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/Dimension.hpp>
|
||||||
#include <opm/input/eclipse/Units/UnitSystem.hpp>
|
#include <opm/input/eclipse/Units/UnitSystem.hpp>
|
||||||
#include <opm/input/eclipse/Units/Units.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 <opm/input/eclipse/Parser/ParserKeywords/W.hpp>
|
||||||
#include <vector>
|
|
||||||
#include <cmath>
|
#include <algorithm>
|
||||||
#include <iostream>
|
|
||||||
#include <cassert>
|
#include <cassert>
|
||||||
|
#include <cmath>
|
||||||
#include <numeric>
|
#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 {
|
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::serializationTestObject()
|
WDFAC WDFAC::serializationTestObject()
|
||||||
{
|
{
|
||||||
WDFAC result;
|
WDFAC result;
|
||||||
result.m_a = 1.23;
|
|
||||||
result.m_b = 0.456;
|
result.m_type = WDFacType::DAKEMODEL;
|
||||||
result.m_c = 0.457;
|
|
||||||
result.m_d = 0.458;
|
result.m_d = 0.458;
|
||||||
result.m_total_cf = 1.0;
|
result.m_total_cf = 1.0;
|
||||||
result.m_type = WDFACTYPE::NONE;
|
result.m_corr = Correlation::serializationTestObject();
|
||||||
|
|
||||||
return result;
|
return result;
|
||||||
}
|
}
|
||||||
|
|
||||||
bool WDFAC::operator==(const WDFAC& other) const {
|
void WDFAC::updateWDFAC(const DeckRecord& record)
|
||||||
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) {
|
|
||||||
m_d = record.getItem<ParserKeywords::WDFAC::DFACTOR>().getSIDouble(0);
|
m_d = record.getItem<ParserKeywords::WDFAC::DFACTOR>().getSIDouble(0);
|
||||||
m_type = WDFACTYPE::DFACTOR;
|
|
||||||
|
m_type = WDFacType::DFACTOR;
|
||||||
}
|
}
|
||||||
|
|
||||||
void WDFAC::updateWDFACCOR(const DeckRecord& record) {
|
void WDFAC::updateWDFACCOR(const DeckRecord& record)
|
||||||
m_a = record.getItem<ParserKeywords::WDFACCOR::A>().getSIDouble(0);
|
{
|
||||||
m_b = record.getItem<ParserKeywords::WDFACCOR::B>().getSIDouble(0);
|
this->m_corr.coeff_a = record.getItem<ParserKeywords::WDFACCOR::A>().getSIDouble(0);
|
||||||
m_c = record.getItem<ParserKeywords::WDFACCOR::C>().getSIDouble(0);
|
this->m_corr.exponent_b = record.getItem<ParserKeywords::WDFACCOR::B>().getSIDouble(0);
|
||||||
m_type = WDFACTYPE::DAKEMODEL;
|
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 =
|
const auto non_trivial_dfactor =
|
||||||
std::any_of(connections.begin(), connections.end(),
|
std::any_of(connections.begin(), connections.end(),
|
||||||
[](const auto& conn) { return conn.dFactor() != 0.0; });
|
[](const auto& conn) { return conn.dFactor() != 0.0; });
|
||||||
|
|
||||||
// non-trivial dfactors detected use connection D factors
|
|
||||||
if (non_trivial_dfactor) {
|
if (non_trivial_dfactor) {
|
||||||
m_type = WDFACTYPE::CON_DFACTOR;
|
// Non-trivial D-factors detected. Use connection D-factors.
|
||||||
updateTotalCF(connections);
|
m_type = WDFacType::CON_DFACTOR;
|
||||||
|
this->updateTotalCF(connections);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void WDFAC::updateTotalCF(const WellConnections& 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(); });
|
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 {
|
double WDFAC::getDFactor(const double rhoGS,
|
||||||
|
const double gas_visc,
|
||||||
switch (m_type)
|
const Connection& conn) const
|
||||||
{
|
{
|
||||||
case WDFACTYPE::NONE:
|
switch (this->m_type) {
|
||||||
|
case WDFacType::NONE:
|
||||||
return 0.0;
|
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::DFACTOR:
|
||||||
}
|
return this->scaledWellLevelDFactor(this->m_d, conn);
|
||||||
case WDFACTYPE::DAKEMODEL:
|
|
||||||
{
|
case WDFacType::DAKEMODEL:
|
||||||
double Kh = connection.Kh();
|
return dakeModelDFactor(rhoGS, gas_visc, conn.ctfProperties());
|
||||||
double Ke = connection.Ke();
|
|
||||||
double h = Kh / Ke;
|
case WDFacType::CON_DFACTOR:
|
||||||
double rw = connection.rw();
|
return this->connectionLevelDFactor(conn);
|
||||||
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;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
return 0.0;
|
return 0.0;
|
||||||
}
|
}
|
||||||
|
|
||||||
bool WDFAC::useDFactor() const {
|
bool WDFAC::useDFactor() const
|
||||||
return m_type != WDFACTYPE::NONE;
|
{
|
||||||
|
return m_type != WDFacType::NONE;
|
||||||
}
|
}
|
||||||
|
|
||||||
bool WDFAC::operator!=(const WDFAC& other) const {
|
bool WDFAC::operator==(const WDFAC& other) const
|
||||||
return !(*this == other);
|
{
|
||||||
|
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/WVFPDP.hpp>
|
||||||
#include <opm/input/eclipse/Schedule/Well/WVFPEXP.hpp>
|
#include <opm/input/eclipse/Schedule/Well/WVFPEXP.hpp>
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
#include <opm/input/eclipse/Units/Units.hpp>
|
#include <opm/input/eclipse/Units/Units.hpp>
|
||||||
|
|
||||||
#include <opm/common/utility/OpmInputError.hpp>
|
#include <opm/common/utility/OpmInputError.hpp>
|
||||||
#include <opm/common/utility/shmatch.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/S.hpp>
|
||||||
#include <opm/input/eclipse/Parser/ParserKeywords/W.hpp>
|
#include <opm/input/eclipse/Parser/ParserKeywords/W.hpp>
|
||||||
|
|
||||||
@ -1300,42 +1299,60 @@ bool Well::handleWELOPENConnections(const DeckRecord& record, Connection::State
|
|||||||
return this->updateConnections(std::move(new_connections), false);
|
return this->updateConnections(std::move(new_connections), false);
|
||||||
}
|
}
|
||||||
|
|
||||||
bool Well::handleCSKINConnections(const DeckRecord& record) {
|
bool Well::handleCSKIN(const DeckRecord& record,
|
||||||
// Lambda expression to check if record coordinates match connection coordinates
|
const KeywordLocation& location)
|
||||||
auto match = [=]( const Connection &c) -> bool {
|
{
|
||||||
if (!match_eq(c.getI(), record, "I" , -1)) return false;
|
using Kw = ParserKeywords::CSKIN;
|
||||||
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;
|
|
||||||
|
|
||||||
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
|
// New connection set which will be updated with new connection level
|
||||||
auto new_connections = std::make_shared<WellConnections>(this->connections->ordering(), this->headI, this->headJ);
|
// skin factors.
|
||||||
|
auto new_connections = std::make_shared<WellConnections>
|
||||||
|
(this->connections->ordering(), this->headI, this->headJ);
|
||||||
|
|
||||||
// Update skin factor
|
const auto skin_factor = record.getItem<Kw::CONNECTION_SKIN_FACTOR>().getSIDouble(0);
|
||||||
double skin_factor = record.getItem("CONNECTION_SKIN_FACTOR").get<double>(0);
|
for (const auto& connection : *this->connections) {
|
||||||
const double angle = 6.2831853071795864769252867665590057683943387987502116419498;
|
if (! need_skin_adjustment(connection)) {
|
||||||
for (auto c : *this->connections) {
|
// No CSKIN adjustment needed here. Include connection as-is
|
||||||
if (match(c)) {
|
// into new connection set.
|
||||||
// Check for potential negative new CF
|
new_connections->add(connection);
|
||||||
if ((std::log(c.r0() / std::min(c.rw(), c.r0())) + skin_factor) < 0.0) {
|
continue;
|
||||||
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);
|
|
||||||
}
|
}
|
||||||
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);
|
return this->updateConnections(std::move(new_connections), false);
|
||||||
@ -1390,6 +1407,7 @@ bool Well::handleWPIMULT(const DeckRecord& record) {
|
|||||||
|
|
||||||
new_connections->add(c);
|
new_connections->add(c);
|
||||||
}
|
}
|
||||||
|
|
||||||
return this->updateConnections(std::move(new_connections), false);
|
return this->updateConnections(std::move(new_connections), false);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
File diff suppressed because it is too large
Load Diff
@ -17,32 +17,39 @@
|
|||||||
along with OPM. If not, see <http://www.gnu.org/licenses/>.
|
along with OPM. If not, see <http://www.gnu.org/licenses/>.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
#include <cstddef>
|
|
||||||
#include <stdexcept>
|
|
||||||
#include <ostream>
|
|
||||||
|
|
||||||
#define BOOST_TEST_MODULE CompletionTests
|
#define BOOST_TEST_MODULE CompletionTests
|
||||||
#include <boost/test/unit_test.hpp>
|
#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/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/EclipseState.hpp>
|
||||||
#include <opm/input/eclipse/EclipseState/Grid/EclipseGrid.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/EclipseState/Grid/FieldPropsManager.hpp>
|
||||||
#include <opm/input/eclipse/Schedule/CompletedCells.hpp>
|
#include <opm/input/eclipse/EclipseState/Tables/TableManager.hpp>
|
||||||
#include <opm/input/eclipse/Schedule/ScheduleGrid.hpp>
|
|
||||||
|
|
||||||
|
#include <opm/input/eclipse/Schedule/CompletedCells.hpp>
|
||||||
#include <opm/input/eclipse/Schedule/Schedule.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/common/OpmLog/KeywordLocation.hpp>
|
||||||
|
|
||||||
#include <opm/input/eclipse/Units/Units.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 {
|
namespace {
|
||||||
double cp_rm3_per_db()
|
double cp_rm3_per_db()
|
||||||
@ -51,20 +58,32 @@ namespace {
|
|||||||
/ (Opm::unit::day * Opm::unit::barsa);
|
/ (Opm::unit::day * Opm::unit::barsa);
|
||||||
}
|
}
|
||||||
|
|
||||||
Opm::WellConnections loadCOMPDAT(const std::string& compdat_keyword) {
|
Opm::WellConnections
|
||||||
Opm::EclipseGrid grid(10,10,10);
|
loadCOMPDAT(const std::string& compdat_keyword)
|
||||||
Opm::TableManager tables;
|
{
|
||||||
Opm::Parser parser;
|
Opm::WellConnections connections {
|
||||||
const auto deck = parser.parseString(compdat_keyword);
|
Opm::Connection::Order::TRACK, 10, 10
|
||||||
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", {});
|
|
||||||
|
|
||||||
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 {
|
namespace Opm {
|
||||||
@ -94,12 +113,22 @@ BOOST_AUTO_TEST_CASE(CreateWellConnectionsOK) {
|
|||||||
|
|
||||||
|
|
||||||
|
|
||||||
BOOST_AUTO_TEST_CASE(AddCompletionSizeCorrect) {
|
BOOST_AUTO_TEST_CASE(AddCompletionSizeCorrect)
|
||||||
auto dir = Opm::Connection::Direction::Z;
|
{
|
||||||
|
const auto dir = Opm::Connection::Direction::Z;
|
||||||
const auto kind = Opm::Connection::CTFKind::DeckValue;
|
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::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 );
|
completionSet.add( completion1 );
|
||||||
BOOST_CHECK_EQUAL( 1U , completionSet.size() );
|
BOOST_CHECK_EQUAL( 1U , completionSet.size() );
|
||||||
BOOST_CHECK_MESSAGE( !completionSet.empty(), "Non-empty completion set must not be empty" );
|
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) {
|
BOOST_AUTO_TEST_CASE(WellConnectionsGetOutOfRangeThrows)
|
||||||
auto dir = Opm::Connection::Direction::Z;
|
{
|
||||||
|
const auto dir = Opm::Connection::Direction::Z;
|
||||||
const auto kind = Opm::Connection::CTFKind::DeckValue;
|
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);
|
const auto depth = 0.0;
|
||||||
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);
|
|
||||||
|
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::WellConnections completionSet(Opm::Connection::Order::TRACK, 1,1);
|
||||||
completionSet.add( completion1 );
|
completionSet.add( completion1 );
|
||||||
BOOST_CHECK_EQUAL( 1U , completionSet.size() );
|
BOOST_CHECK_EQUAL( 1U , completionSet.size() );
|
||||||
@ -148,15 +187,23 @@ BOOST_AUTO_TEST_CASE(Compdat_Direction) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
BOOST_AUTO_TEST_CASE(AddCompletionCopy) {
|
BOOST_AUTO_TEST_CASE(AddCompletionCopy)
|
||||||
Opm::WellConnections completionSet(Opm::Connection::Order::TRACK, 10,10);
|
{
|
||||||
auto dir = Opm::Connection::Direction::Z;
|
const auto dir = Opm::Connection::Direction::Z;
|
||||||
const auto kind = Opm::Connection::CTFKind::DeckValue;
|
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);
|
auto ctf_props = Opm::Connection::CTFProperties{};
|
||||||
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);
|
|
||||||
|
|
||||||
|
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( completion1 );
|
||||||
completionSet.add( completion2 );
|
completionSet.add( completion2 );
|
||||||
completionSet.add( completion3 );
|
completionSet.add( completion3 );
|
||||||
@ -171,31 +218,43 @@ BOOST_AUTO_TEST_CASE(AddCompletionCopy) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
BOOST_AUTO_TEST_CASE(ActiveCompletions) {
|
BOOST_AUTO_TEST_CASE(ActiveCompletions)
|
||||||
Opm::EclipseGrid grid(10,20,20);
|
{
|
||||||
auto dir = Opm::Connection::Direction::Z;
|
const auto dir = Opm::Connection::Direction::Z;
|
||||||
const auto kind = Opm::Connection::CTFKind::Defaulted;
|
const auto kind = Opm::Connection::CTFKind::DeckValue;
|
||||||
Opm::WellConnections completions(Opm::Connection::Order::TRACK, 10,10);
|
const auto depth = 0.0;
|
||||||
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);
|
|
||||||
|
|
||||||
|
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( completion1 );
|
||||||
completions.add( completion2 );
|
completions.add( completion2 );
|
||||||
completions.add( completion3 );
|
completions.add( completion3 );
|
||||||
|
|
||||||
std::vector<int> actnum(grid.getCartesianSize(), 1);
|
std::vector<int> actnum(grid.getCartesianSize(), 1);
|
||||||
actnum[0] = 0;
|
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( active_completions.size() , 2U);
|
||||||
BOOST_CHECK_EQUAL( completion2, active_completions.get(0));
|
BOOST_CHECK_EQUAL( completion2, active_completions.get(0));
|
||||||
BOOST_CHECK_EQUAL( completion3, active_completions.get(1));
|
BOOST_CHECK_EQUAL( completion3, active_completions.get(1));
|
||||||
}
|
}
|
||||||
|
|
||||||
BOOST_AUTO_TEST_CASE(loadCOMPDATTEST) {
|
BOOST_AUTO_TEST_CASE(loadCOMPDATTEST)
|
||||||
Opm::UnitSystem units(Opm::UnitSystem::UnitType::UNIT_TYPE_METRIC); // Unit system used in deck FIRST_SIM.DATA.
|
{
|
||||||
|
const Opm::UnitSystem units(Opm::UnitSystem::UnitType::UNIT_TYPE_METRIC); // Unit system used in deck FIRST_SIM.DATA.
|
||||||
|
|
||||||
{
|
{
|
||||||
const std::string deck = R"(GRID
|
const std::string deck = R"(GRID
|
||||||
|
|
||||||
@ -206,13 +265,18 @@ COPY
|
|||||||
'PERMX' 'PERMZ' /
|
'PERMX' 'PERMZ' /
|
||||||
'PERMX' 'PERMY' /
|
'PERMX' 'PERMY' /
|
||||||
/
|
/
|
||||||
|
|
||||||
|
PORO
|
||||||
|
1000*0.3 /
|
||||||
|
|
||||||
SCHEDULE
|
SCHEDULE
|
||||||
|
|
||||||
COMPDAT
|
COMPDAT
|
||||||
-- CF Diam Kh Skin Df
|
-- CF Diam Kh Skin Df
|
||||||
'WELL' 1 1 1 1 'OPEN' 1* 1.168 0.311 107.872 1* 1* 'Z' 21.925 /
|
'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];
|
const auto& conn0 = connections[0];
|
||||||
BOOST_CHECK_EQUAL(conn0.CF(), units.to_si(Opm::UnitSystem::measure::transmissibility, 1.168));
|
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));
|
BOOST_CHECK_EQUAL(conn0.Kh(), units.to_si(Opm::UnitSystem::measure::effective_Kh, 107.872));
|
||||||
@ -230,13 +294,17 @@ COPY
|
|||||||
'PERMX' 'PERMY' /
|
'PERMX' 'PERMY' /
|
||||||
/
|
/
|
||||||
|
|
||||||
|
PORO
|
||||||
|
1000*0.3 /
|
||||||
|
|
||||||
SCHEDULE
|
SCHEDULE
|
||||||
|
|
||||||
COMPDAT
|
COMPDAT
|
||||||
-- CF Diam Kh Skin Df
|
-- CF Diam Kh Skin Df
|
||||||
'WELL' 1 1 1 1 'OPEN' 1* 1.168 0.311 0 1* 1* 'Z' 21.925 /
|
'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];
|
const auto& conn0 = connections[0];
|
||||||
BOOST_CHECK_EQUAL(conn0.CF(), units.to_si(Opm::UnitSystem::measure::transmissibility, 1.168));
|
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));
|
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)
|
// 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
|
connP.addConnection(9, 9, 1, // 10, 10, 2
|
||||||
199,
|
199,
|
||||||
2015.0,
|
Opm::Connection::State::OPEN,
|
||||||
Opm::Connection::State::OPEN,
|
2015.0, ctf_props, 1);
|
||||||
50.0*cp_rm3_per_db(),
|
|
||||||
0.123,
|
|
||||||
0.234,
|
|
||||||
0.157,
|
|
||||||
0.0,
|
|
||||||
0.0,
|
|
||||||
0.0,
|
|
||||||
0.0,
|
|
||||||
0.0,
|
|
||||||
1);
|
|
||||||
|
|
||||||
BOOST_REQUIRE_EQUAL(connP.size(), std::size_t{3});
|
BOOST_REQUIRE_EQUAL(connP.size(), std::size_t{3});
|
||||||
|
|
||||||
@ -506,19 +570,9 @@ END
|
|||||||
|
|
||||||
// Reset CF -- simulating COMPDAT record (active cell)
|
// Reset CF -- simulating COMPDAT record (active cell)
|
||||||
connP.addConnection(8, 9, 1, // 10, 10, 2
|
connP.addConnection(8, 9, 1, // 10, 10, 2
|
||||||
198,
|
198,
|
||||||
2015.0,
|
Opm::Connection::State::OPEN,
|
||||||
Opm::Connection::State::OPEN,
|
2015.0, ctf_props, 1);
|
||||||
50.0*cp_rm3_per_db(),
|
|
||||||
0.123,
|
|
||||||
0.234,
|
|
||||||
0.157,
|
|
||||||
0.0,
|
|
||||||
0.0,
|
|
||||||
0.0,
|
|
||||||
0.0,
|
|
||||||
0.0,
|
|
||||||
1);
|
|
||||||
|
|
||||||
BOOST_REQUIRE_EQUAL(connP.size(), std::size_t{4});
|
BOOST_REQUIRE_EQUAL(connP.size(), std::size_t{4});
|
||||||
|
|
||||||
|
@ -55,20 +55,32 @@
|
|||||||
#include <stdexcept>
|
#include <stdexcept>
|
||||||
#include <string>
|
#include <string>
|
||||||
|
|
||||||
BOOST_AUTO_TEST_CASE(AICDWellTest) {
|
BOOST_AUTO_TEST_CASE(AICDWellTest)
|
||||||
|
{
|
||||||
auto dir = Opm::Connection::Direction::Z;
|
const auto dir_z = Opm::Connection::Direction::Z;
|
||||||
|
const auto dir_x = Opm::Connection::Direction::X;
|
||||||
const auto kind = Opm::Connection::CTFKind::DeckValue;
|
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) );
|
const Opm::EclipseGrid grid { 20,20,20, 1.0, 1.0, 25.0, 2500.0 };
|
||||||
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) );
|
const auto depth = 0.0;
|
||||||
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 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() );
|
BOOST_CHECK_EQUAL( 7U , connection_set.size() );
|
||||||
|
|
||||||
@ -212,23 +224,33 @@ WSEGAICD
|
|||||||
const double center_depth_connection7 = connection7.depth();
|
const double center_depth_connection7 = connection7.depth();
|
||||||
BOOST_CHECK_EQUAL(segment_number_connection7, 8);
|
BOOST_CHECK_EQUAL(segment_number_connection7, 8);
|
||||||
BOOST_CHECK_EQUAL(center_depth_connection7, 2534.5);
|
BOOST_CHECK_EQUAL(center_depth_connection7, 2534.5);
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
BOOST_AUTO_TEST_CASE(MultisegmentWellTest) {
|
BOOST_AUTO_TEST_CASE(MultisegmentWellTest)
|
||||||
|
{
|
||||||
auto dir = Opm::Connection::Direction::Z;
|
const auto dir_z = Opm::Connection::Direction::Z;
|
||||||
|
const auto dir_x = Opm::Connection::Direction::X;
|
||||||
const auto kind = Opm::Connection::CTFKind::DeckValue;
|
const auto kind = Opm::Connection::CTFKind::DeckValue;
|
||||||
Opm::WellConnections connection_set(Opm::Connection::Order::TRACK, 10,10);
|
const Opm::EclipseGrid grid { 20,20,20, 1.0, 1.0, 25.0, 2500.0 };
|
||||||
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) );
|
const auto depth = 0.0;
|
||||||
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) );
|
const auto state = Opm::Connection::State::OPEN;
|
||||||
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) );
|
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() );
|
BOOST_CHECK_EQUAL( 7U , connection_set.size() );
|
||||||
|
|
||||||
@ -383,19 +405,32 @@ WSEGSICD
|
|||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
BOOST_AUTO_TEST_CASE(WrongDistanceCOMPSEGS) {
|
BOOST_AUTO_TEST_CASE(WrongDistanceCOMPSEGS)
|
||||||
auto dir = Opm::Connection::Direction::Z;
|
{
|
||||||
|
const auto dir_z = Opm::Connection::Direction::Z;
|
||||||
|
const auto dir_x = Opm::Connection::Direction::X;
|
||||||
const auto kind = Opm::Connection::CTFKind::DeckValue;
|
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) );
|
const Opm::EclipseGrid grid { 20,20,20, 1.0, 1.0, 25., 2500.0 };
|
||||||
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) );
|
const auto depth = 0.0;
|
||||||
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 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() );
|
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_CHECK_NO_THROW(Opm::Compsegs::processCOMPSEGS(compsegs, connection_set, segment_set, Opm::ScheduleGrid(grid, fp, cells), parseContext, errorGuard));
|
||||||
}
|
}
|
||||||
|
|
||||||
BOOST_AUTO_TEST_CASE(NegativeDepthCOMPSEGS) {
|
BOOST_AUTO_TEST_CASE(NegativeDepthCOMPSEGS)
|
||||||
auto dir = Opm::Connection::Direction::Z;
|
{
|
||||||
|
const auto dir_z = Opm::Connection::Direction::Z;
|
||||||
|
const auto dir_x = Opm::Connection::Direction::X;
|
||||||
const auto kind = Opm::Connection::CTFKind::DeckValue;
|
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) );
|
const Opm::EclipseGrid grid { 20,20,20, 1.0, 1.0, 25.0, 2500.0 };
|
||||||
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) );
|
const auto depth = 0.0;
|
||||||
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 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() );
|
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_CHECK_NO_THROW( Opm::Compsegs::processCOMPSEGS(compsegs, connection_set, segment_set, Opm::ScheduleGrid(grid, fp, cells), parseContext, errorGuard) );
|
||||||
}
|
}
|
||||||
|
|
||||||
BOOST_AUTO_TEST_CASE(testwsegvalv) {
|
BOOST_AUTO_TEST_CASE(testwsegvalv)
|
||||||
auto dir = Opm::Connection::Direction::Z;
|
{
|
||||||
|
const auto dir_z = Opm::Connection::Direction::Z;
|
||||||
|
const auto dir_x = Opm::Connection::Direction::X;
|
||||||
const auto kind = Opm::Connection::CTFKind::DeckValue;
|
const auto kind = Opm::Connection::CTFKind::DeckValue;
|
||||||
Opm::WellConnections connection_set(Opm::Connection::Order::TRACK, 10,10);
|
const Opm::EclipseGrid grid { 20,20,20, 1.0, 1.0, 25.0, 2500.0 };
|
||||||
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) );
|
const auto depth = 0.0;
|
||||||
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) );
|
const auto state = Opm::Connection::State::OPEN;
|
||||||
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) );
|
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() );
|
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 <boost/test/unit_test.hpp>
|
||||||
|
|
||||||
#include <opm/input/eclipse/Python/Python.hpp>
|
#include <opm/input/eclipse/Python/Python.hpp>
|
||||||
|
|
||||||
#include <opm/input/eclipse/EclipseState/Grid/FieldPropsManager.hpp>
|
#include <opm/input/eclipse/EclipseState/Grid/FieldPropsManager.hpp>
|
||||||
#include <opm/input/eclipse/EclipseState/Grid/EclipseGrid.hpp>
|
#include <opm/input/eclipse/EclipseState/Grid/EclipseGrid.hpp>
|
||||||
#include <opm/input/eclipse/EclipseState/Runspec.hpp>
|
#include <opm/input/eclipse/EclipseState/Runspec.hpp>
|
||||||
#include <opm/input/eclipse/EclipseState/Tables/TableManager.hpp>
|
#include <opm/input/eclipse/EclipseState/Tables/TableManager.hpp>
|
||||||
|
|
||||||
#include <opm/input/eclipse/Schedule/Schedule.hpp>
|
#include <opm/input/eclipse/Schedule/Schedule.hpp>
|
||||||
#include <opm/input/eclipse/Schedule/Well/Well.hpp>
|
#include <opm/input/eclipse/Schedule/Well/Well.hpp>
|
||||||
|
|
||||||
#include <opm/input/eclipse/Deck/Deck.hpp>
|
#include <opm/input/eclipse/Deck/Deck.hpp>
|
||||||
#include <opm/input/eclipse/Deck/DeckItem.hpp>
|
#include <opm/input/eclipse/Deck/DeckItem.hpp>
|
||||||
#include <opm/input/eclipse/Deck/DeckKeyword.hpp>
|
#include <opm/input/eclipse/Deck/DeckKeyword.hpp>
|
||||||
#include <opm/input/eclipse/Deck/DeckRecord.hpp>
|
#include <opm/input/eclipse/Deck/DeckRecord.hpp>
|
||||||
|
|
||||||
#include <opm/input/eclipse/Parser/Parser.hpp>
|
#include <opm/input/eclipse/Parser/Parser.hpp>
|
||||||
#include <opm/input/eclipse/Parser/ParseContext.hpp>
|
#include <opm/input/eclipse/Parser/ParseContext.hpp>
|
||||||
|
|
||||||
using namespace Opm;
|
using namespace Opm;
|
||||||
|
|
||||||
static Deck createDeckWithOutSolvent() {
|
namespace {
|
||||||
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";
|
|
||||||
|
|
||||||
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() {
|
Deck createDeckWithGasInjector()
|
||||||
Opm::Parser parser;
|
{
|
||||||
std::string input =
|
return Parser{}.parseString(R"(
|
||||||
"GRID\n"
|
GRID
|
||||||
"PERMX\n"
|
PERMX
|
||||||
" 1000*0.25/\n"
|
1000*0.25/
|
||||||
"COPY\n"
|
COPY
|
||||||
" PERMX PERMY /\n"
|
PERMX PERMY /
|
||||||
" PERMX PERMZ /\n"
|
PERMX PERMZ /
|
||||||
"/\n"
|
/
|
||||||
"SCHEDULE\n"
|
PORO
|
||||||
"WELSPECS\n"
|
1000*0.3 /
|
||||||
" '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";
|
|
||||||
|
|
||||||
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() {
|
Deck createDeckWithDynamicWSOLVENT()
|
||||||
Opm::Parser parser;
|
{
|
||||||
std::string input =
|
return Parser{}.parseString(R"(
|
||||||
"START -- 0 \n"
|
START -- 0
|
||||||
"1 JAN 2000 / \n"
|
1 JAN 2000 /
|
||||||
"GRID\n"
|
GRID
|
||||||
"PERMX\n"
|
PERMX
|
||||||
" 1000*0.25/\n"
|
1000*0.25/
|
||||||
"COPY\n"
|
COPY
|
||||||
" PERMX PERMY /\n"
|
PERMX PERMY /
|
||||||
" PERMX PERMZ /\n"
|
PERMX PERMZ /
|
||||||
"/\n"
|
/
|
||||||
"SCHEDULE\n"
|
PORO
|
||||||
"WELSPECS\n"
|
1000*0.3 /
|
||||||
" '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";
|
|
||||||
|
|
||||||
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() {
|
Deck createDeckWithOilInjector()
|
||||||
Opm::Parser parser;
|
{
|
||||||
std::string input =
|
return Parser{}.parseString(R"(
|
||||||
"GRID\n"
|
GRID
|
||||||
"PERMX\n"
|
PERMX
|
||||||
" 1000*0.25/\n"
|
1000*0.25/
|
||||||
"COPY\n"
|
COPY
|
||||||
" PERMX PERMY /\n"
|
PERMX PERMY /
|
||||||
" PERMX PERMZ /\n"
|
PERMX PERMZ /
|
||||||
"/\n"
|
/
|
||||||
"SCHEDULE\n"
|
SCHEDULE
|
||||||
"WELSPECS\n"
|
WELSPECS
|
||||||
" 'W_1' 'OP' 2 2 1* \'OIL\' 7* / \n"
|
'W_1' 'OP' 2 2 1* 'OIL' 7* /
|
||||||
"/\n"
|
/
|
||||||
"COMPDAT\n"
|
COMPDAT
|
||||||
" 'W_1' 2* 1 1 'OPEN' / \n"
|
'W_1' 2* 1 1 'OPEN' /
|
||||||
"/\n"
|
/
|
||||||
"WCONINJE\n"
|
WCONINJE
|
||||||
" 'W_1' 'OIL' 'OPEN' 'BHP' 1 2 3/\n/\n"
|
'W_1' 'OIL' 'OPEN' 'BHP' 1 2 3/
|
||||||
"WSOLVENT\n"
|
/
|
||||||
" 'W_1' 1 / \n "
|
WSOLVENT
|
||||||
"/\n";
|
'W_1' 1 /
|
||||||
|
/
|
||||||
return parser.parseString(input);
|
END
|
||||||
|
)");
|
||||||
}
|
}
|
||||||
|
|
||||||
static Deck createDeckWithWaterInjector() {
|
Deck createDeckWithWaterInjector()
|
||||||
Opm::Parser parser;
|
{
|
||||||
std::string input =
|
return Parser{}.parseString(R"(
|
||||||
"GRID\n"
|
GRID
|
||||||
"PERMX\n"
|
PERMX
|
||||||
" 1000*0.25/\n"
|
1000*0.25/
|
||||||
"COPY\n"
|
COPY
|
||||||
" PERMX PERMY /\n"
|
PERMX PERMY /
|
||||||
" PERMX PERMZ /\n"
|
PERMX PERMZ /
|
||||||
"/\n"
|
/
|
||||||
"SCHEDULE\n"
|
SCHEDULE
|
||||||
"WELSPECS\n"
|
WELSPECS
|
||||||
" 'W_1' 'OP' 2 2 1* \'OIL\' 7* / \n"
|
'W_1' 'OP' 2 2 1* \'OIL\' 7* /
|
||||||
"/\n"
|
/
|
||||||
"COMPDAT\n"
|
COMPDAT
|
||||||
" 'W_1' 2* 1 1 'OPEN' / \n"
|
'W_1' 2* 1 1 'OPEN' /
|
||||||
"/\n"
|
/
|
||||||
"WCONINJE\n"
|
WCONINJE
|
||||||
" 'W_1' 'WATER' 'OPEN' 'BHP' 1 2 3/\n/\n"
|
'W_1' 'WATER' 'OPEN' 'BHP' 1 2 3/
|
||||||
"WSOLVENT\n"
|
/
|
||||||
" 'W_1' 1 / \n "
|
WSOLVENT
|
||||||
"/\n";
|
'W_1' 1 /
|
||||||
|
/
|
||||||
return parser.parseString(input);
|
END
|
||||||
|
)");
|
||||||
}
|
}
|
||||||
BOOST_AUTO_TEST_CASE(TestNoSolvent) {
|
|
||||||
auto deck = createDeckWithOutSolvent();
|
} // Anonymous namespace
|
||||||
auto python = std::make_shared<Python>();
|
|
||||||
EclipseGrid grid(10,10,10);
|
BOOST_AUTO_TEST_CASE(TestNoSolvent)
|
||||||
TableManager table ( deck );
|
{
|
||||||
FieldPropsManager fp(deck, Phases{true, true, true}, grid, table);
|
const auto deck = createDeckWithOutSolvent();
|
||||||
Runspec runspec(deck);
|
const EclipseGrid grid(10,10,10);
|
||||||
Schedule schedule(deck, grid , fp, runspec, python);
|
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_CHECK(!deck.hasKeyword("WSOLVENT"));
|
||||||
}
|
}
|
||||||
|
|
||||||
BOOST_AUTO_TEST_CASE(TestGasInjector) {
|
BOOST_AUTO_TEST_CASE(TestGasInjector) {
|
||||||
auto deck = createDeckWithGasInjector();
|
const auto deck = createDeckWithGasInjector();
|
||||||
auto python = std::make_shared<Python>();
|
const EclipseGrid grid(10,10,10);
|
||||||
EclipseGrid grid(10,10,10);
|
const TableManager table (deck);
|
||||||
TableManager table ( deck );
|
const FieldPropsManager fp(deck, Phases{true, true, true}, grid, table);
|
||||||
FieldPropsManager fp(deck, Phases{true, true, true}, grid, table);
|
const Runspec runspec(deck);
|
||||||
Runspec runspec(deck);
|
const Schedule schedule(deck, grid, fp, runspec, std::make_shared<Python>());
|
||||||
Schedule schedule(deck, grid , fp, runspec, python);
|
|
||||||
BOOST_CHECK(deck.hasKeyword("WSOLVENT"));
|
BOOST_CHECK(deck.hasKeyword("WSOLVENT"));
|
||||||
}
|
}
|
||||||
|
|
||||||
BOOST_AUTO_TEST_CASE(TestDynamicWSOLVENT) {
|
BOOST_AUTO_TEST_CASE(TestDynamicWSOLVENT)
|
||||||
auto deck = createDeckWithDynamicWSOLVENT();
|
{
|
||||||
auto python = std::make_shared<Python>();
|
const auto deck = createDeckWithDynamicWSOLVENT();
|
||||||
EclipseGrid grid(10,10,10);
|
const EclipseGrid grid(10,10,10);
|
||||||
TableManager table ( deck );
|
const TableManager table (deck);
|
||||||
FieldPropsManager fp(deck, Phases{true, true, true}, grid, table);
|
const FieldPropsManager fp(deck, Phases{true, true, true}, grid, table);
|
||||||
Runspec runspec(deck);
|
const Runspec runspec(deck);
|
||||||
Schedule schedule(deck, grid , fp, runspec, python);
|
const Schedule schedule(deck, grid, fp, runspec, std::make_shared<Python>());
|
||||||
|
|
||||||
BOOST_CHECK(deck.hasKeyword("WSOLVENT"));
|
BOOST_CHECK(deck.hasKeyword("WSOLVENT"));
|
||||||
|
|
||||||
const auto& keyword = deck["WSOLVENT"].back();
|
const auto& keyword = deck["WSOLVENT"].back();
|
||||||
BOOST_CHECK_EQUAL(keyword.size(),1U);
|
BOOST_CHECK_EQUAL(keyword.size(),1U);
|
||||||
|
|
||||||
const auto& record = keyword.getRecord(0);
|
const auto& record = keyword.getRecord(0);
|
||||||
const std::string& well_name = record.getItem("WELL").getTrimmedString(0);
|
const std::string& well_name = record.getItem("WELL").getTrimmedString(0);
|
||||||
BOOST_CHECK_EQUAL(well_name, "W_1");
|
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_CHECK_EQUAL(schedule.getWell("W_1", 3).getSolventFraction(),0);
|
||||||
}
|
}
|
||||||
|
|
||||||
BOOST_AUTO_TEST_CASE(TestOilInjector) {
|
BOOST_AUTO_TEST_CASE(TestOilInjector)
|
||||||
auto deck = createDeckWithOilInjector();
|
{
|
||||||
auto python = std::make_shared<Python>();
|
const auto deck = createDeckWithOilInjector();
|
||||||
EclipseGrid grid(10,10,10);
|
const EclipseGrid grid(10,10,10);
|
||||||
TableManager table ( deck );
|
const TableManager table (deck);
|
||||||
FieldPropsManager fp(deck, Phases{true, true, true}, grid, table);
|
const FieldPropsManager fp(deck, Phases{true, true, true}, grid, table);
|
||||||
Runspec runspec(deck);
|
const Runspec runspec(deck);
|
||||||
BOOST_CHECK_THROW (Schedule(deck , grid , fp, runspec, python), std::exception);
|
|
||||||
|
BOOST_CHECK_THROW (Schedule(deck, grid, fp, runspec, std::make_shared<Python>()), std::exception);
|
||||||
}
|
}
|
||||||
|
|
||||||
BOOST_AUTO_TEST_CASE(TestWaterInjector) {
|
BOOST_AUTO_TEST_CASE(TestWaterInjector)
|
||||||
auto deck = createDeckWithWaterInjector();
|
{
|
||||||
auto python = std::make_shared<Python>();
|
const auto deck = createDeckWithWaterInjector();
|
||||||
EclipseGrid grid(10,10,10);
|
const EclipseGrid grid(10,10,10);
|
||||||
TableManager table ( deck );
|
const TableManager table ( deck );
|
||||||
FieldPropsManager fp(deck, Phases{true, true, true}, grid, table);
|
const FieldPropsManager fp(deck, Phases{true, true, true}, grid, table);
|
||||||
Runspec runspec(deck);
|
const Runspec runspec(deck);
|
||||||
BOOST_CHECK_THROW (Schedule(deck, grid , fp, runspec, python), std::exception);
|
|
||||||
|
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 <boost/test/unit_test.hpp>
|
||||||
|
|
||||||
#include <opm/common/utility/OpmInputError.hpp>
|
#include <opm/common/utility/OpmInputError.hpp>
|
||||||
|
|
||||||
#include <opm/input/eclipse/Python/Python.hpp>
|
#include <opm/input/eclipse/Python/Python.hpp>
|
||||||
|
|
||||||
#include <opm/input/eclipse/EclipseState/Grid/FieldPropsManager.hpp>
|
#include <opm/input/eclipse/EclipseState/Grid/FieldPropsManager.hpp>
|
||||||
#include <opm/input/eclipse/EclipseState/Grid/EclipseGrid.hpp>
|
#include <opm/input/eclipse/EclipseState/Grid/EclipseGrid.hpp>
|
||||||
#include <opm/input/eclipse/EclipseState/Runspec.hpp>
|
#include <opm/input/eclipse/EclipseState/Runspec.hpp>
|
||||||
#include <opm/input/eclipse/EclipseState/Tables/TableManager.hpp>
|
#include <opm/input/eclipse/EclipseState/Tables/TableManager.hpp>
|
||||||
|
|
||||||
#include <opm/input/eclipse/Schedule/Schedule.hpp>
|
#include <opm/input/eclipse/Schedule/Schedule.hpp>
|
||||||
#include <opm/input/eclipse/Schedule/Well/Well.hpp>
|
#include <opm/input/eclipse/Schedule/Well/Well.hpp>
|
||||||
#include <opm/input/eclipse/Schedule/Well/WellTracerProperties.hpp>
|
#include <opm/input/eclipse/Schedule/Well/WellTracerProperties.hpp>
|
||||||
|
|
||||||
#include <opm/input/eclipse/Deck/Deck.hpp>
|
#include <opm/input/eclipse/Deck/Deck.hpp>
|
||||||
#include <opm/input/eclipse/Deck/DeckItem.hpp>
|
#include <opm/input/eclipse/Deck/DeckItem.hpp>
|
||||||
#include <opm/input/eclipse/Deck/DeckKeyword.hpp>
|
#include <opm/input/eclipse/Deck/DeckKeyword.hpp>
|
||||||
#include <opm/input/eclipse/Deck/DeckRecord.hpp>
|
#include <opm/input/eclipse/Deck/DeckRecord.hpp>
|
||||||
|
|
||||||
#include <opm/input/eclipse/Parser/Parser.hpp>
|
#include <opm/input/eclipse/Parser/Parser.hpp>
|
||||||
|
|
||||||
using namespace Opm;
|
using namespace Opm;
|
||||||
|
|
||||||
static Deck createDeckWithOutTracer() {
|
namespace {
|
||||||
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";
|
|
||||||
|
|
||||||
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() {
|
SCHEDULE
|
||||||
Opm::Parser parser;
|
WELSPECS
|
||||||
std::string input =
|
'W_1' 'OP' 1 1 1* 'GAS' 7* /
|
||||||
"START -- 0 \n"
|
/
|
||||||
"1 JAN 2000 / \n"
|
COMPDAT
|
||||||
"GRID\n"
|
'W_1' 2* 1 1 'OPEN' /
|
||||||
"PERMX\n"
|
/
|
||||||
" 1000*0.25/\n"
|
WCONINJE
|
||||||
"COPY\n"
|
'W_1' 'GAS' 'OPEN' 'BHP' 1 2 3/
|
||||||
" PERMX PERMY /\n"
|
/
|
||||||
" PERMX PERMZ /\n"
|
DATES -- 1
|
||||||
"/\n"
|
1 MAY 2000 /
|
||||||
"SCHEDULE\n"
|
/
|
||||||
"WELSPECS\n"
|
WTRACER
|
||||||
" 'W_1' 'OP' 1 1 1* \'GAS\' 7* / \n"
|
'W_1' 'I1' 1 /
|
||||||
"/\n"
|
'W_1' 'I2' 1 /
|
||||||
"COMPDAT\n"
|
/
|
||||||
" 'W_1' 2* 1 1 'OPEN' / \n"
|
DATES -- 2, 3
|
||||||
"/\n"
|
1 JUL 2000 /
|
||||||
"WCONINJE\n"
|
1 AUG 2000 /
|
||||||
" 'W_1' 'GAS' 'OPEN' 'BHP' 1 2 3/\n/\n"
|
/
|
||||||
"DATES -- 1\n"
|
WTRACER
|
||||||
" 1 MAY 2000 / \n"
|
'W_1' 'I1' 0 /
|
||||||
"/\n"
|
/
|
||||||
"WTRACER\n"
|
DATES -- 4
|
||||||
" 'W_1' 'I1' 1 / \n "
|
1 SEP 2000 /
|
||||||
" '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";
|
|
||||||
|
|
||||||
return parser.parseString(input);
|
END
|
||||||
|
)");
|
||||||
}
|
}
|
||||||
|
|
||||||
static Deck createDeckWithTracerInProducer() {
|
Deck createDeckWithTracerInProducer()
|
||||||
Opm::Parser parser;
|
{
|
||||||
std::string input =
|
return Parser{}.parseString(R"(
|
||||||
"START -- 0 \n"
|
START -- 0
|
||||||
"1 JAN 2000 / \n"
|
1 JAN 2000 /
|
||||||
"GRID\n"
|
GRID
|
||||||
"PERMX\n"
|
PERMX
|
||||||
" 1000*0.25/\n"
|
1000*0.25/
|
||||||
"COPY\n"
|
COPY
|
||||||
" PERMX PERMY /\n"
|
PERMX PERMY /
|
||||||
" PERMX PERMZ /\n"
|
PERMX PERMZ /
|
||||||
"/\n"
|
/
|
||||||
"SCHEDULE\n"
|
PORO
|
||||||
"WELSPECS\n"
|
1000*0.3 /
|
||||||
" '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";
|
|
||||||
|
|
||||||
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_CHECK(!deck.hasKeyword("WTRACER"));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
BOOST_AUTO_TEST_CASE(TestDynamicWTRACER) {
|
BOOST_AUTO_TEST_CASE(TestDynamicWTRACER)
|
||||||
auto deck = createDeckWithDynamicWTRACER();
|
{
|
||||||
auto python = std::make_shared<Python>();
|
const auto deck = createDeckWithDynamicWTRACER();
|
||||||
EclipseGrid grid(10,10,10);
|
|
||||||
TableManager table ( deck );
|
const EclipseGrid grid(10,10,10);
|
||||||
FieldPropsManager fp( deck, Phases{true, true, true}, grid, table);
|
const TableManager table (deck);
|
||||||
Runspec runspec ( deck );
|
const FieldPropsManager fp(deck, Phases{true, true, true}, grid, table);
|
||||||
Schedule schedule(deck, grid , fp, runspec, python);
|
const Runspec runspec (deck);
|
||||||
|
const Schedule schedule(deck, grid, fp, runspec, std::make_shared<Python>());
|
||||||
|
|
||||||
BOOST_CHECK(deck.hasKeyword("WTRACER"));
|
BOOST_CHECK(deck.hasKeyword("WTRACER"));
|
||||||
|
|
||||||
const auto& keyword = deck["WTRACER"].back();
|
const auto& keyword = deck["WTRACER"].back();
|
||||||
BOOST_CHECK_EQUAL(keyword.size(),1U);
|
BOOST_CHECK_EQUAL(keyword.size(),1U);
|
||||||
|
|
||||||
const auto& record = keyword.getRecord(0);
|
const auto& record = keyword.getRecord(0);
|
||||||
const std::string& well_name = record.getItem("WELL").getTrimmedString(0);
|
const std::string& well_name = record.getItem("WELL").getTrimmedString(0);
|
||||||
BOOST_CHECK_EQUAL(well_name, "W_1");
|
BOOST_CHECK_EQUAL(well_name, "W_1");
|
||||||
@ -169,13 +194,13 @@ BOOST_AUTO_TEST_CASE(TestDynamicWTRACER) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
BOOST_AUTO_TEST_CASE(TestTracerInProducerTHROW) {
|
BOOST_AUTO_TEST_CASE(TestTracerInProducerTHROW)
|
||||||
auto deck = createDeckWithTracerInProducer();
|
{
|
||||||
auto python = std::make_shared<Python>();
|
const auto deck = createDeckWithTracerInProducer();
|
||||||
EclipseGrid grid(10,10,10);
|
const EclipseGrid grid(10,10,10);
|
||||||
TableManager table ( deck );
|
const TableManager table (deck);
|
||||||
FieldPropsManager fp( deck, Phases{true, true, true}, grid, table);
|
const FieldPropsManager fp(deck, Phases{true, true, true}, grid, table);
|
||||||
Runspec runspec ( deck );
|
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 /
|
PERMX PERMZ /
|
||||||
/
|
/
|
||||||
|
|
||||||
|
PORO
|
||||||
|
1000*0.3 /
|
||||||
|
|
||||||
DX
|
DX
|
||||||
1000*1 /
|
1000*1 /
|
||||||
|
@ -16,6 +16,9 @@ COPY
|
|||||||
PERMX PERMZ /
|
PERMX PERMZ /
|
||||||
/
|
/
|
||||||
|
|
||||||
|
PORO
|
||||||
|
48000*0.3 /
|
||||||
|
|
||||||
SCHEDULE
|
SCHEDULE
|
||||||
|
|
||||||
WELSPECS
|
WELSPECS
|
||||||
|
@ -17,6 +17,9 @@ COPY
|
|||||||
PERMX PERMZ /
|
PERMX PERMZ /
|
||||||
/
|
/
|
||||||
|
|
||||||
|
PORO
|
||||||
|
27000*0.3 /
|
||||||
|
|
||||||
SCHEDULE
|
SCHEDULE
|
||||||
|
|
||||||
|
|
||||||
|
@ -15,6 +15,9 @@ COPY
|
|||||||
PERMX PERMZ /
|
PERMX PERMZ /
|
||||||
/
|
/
|
||||||
|
|
||||||
|
PORO
|
||||||
|
27000*0.3 /
|
||||||
|
|
||||||
SCHEDULE
|
SCHEDULE
|
||||||
|
|
||||||
|
|
||||||
|
@ -17,6 +17,8 @@ COPY
|
|||||||
PERMX PERMZ /
|
PERMX PERMZ /
|
||||||
/
|
/
|
||||||
|
|
||||||
|
PORO
|
||||||
|
800*0.3 /
|
||||||
|
|
||||||
SCHEDULE
|
SCHEDULE
|
||||||
|
|
||||||
|
@ -16,6 +16,8 @@ COPY
|
|||||||
PERMX PERMZ /
|
PERMX PERMZ /
|
||||||
/
|
/
|
||||||
|
|
||||||
|
PORO
|
||||||
|
27000*0.3 /
|
||||||
|
|
||||||
SCHEDULE
|
SCHEDULE
|
||||||
|
|
||||||
|
@ -13,6 +13,9 @@ COPY
|
|||||||
PERMX PERMZ /
|
PERMX PERMZ /
|
||||||
/
|
/
|
||||||
|
|
||||||
|
PORO
|
||||||
|
72000*0.3 /
|
||||||
|
|
||||||
SCHEDULE
|
SCHEDULE
|
||||||
|
|
||||||
-- 0
|
-- 0
|
||||||
|
@ -518,34 +518,39 @@ BOOST_AUTO_TEST_CASE(WellTestWGRUPCONWellPropertiesSet) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
BOOST_AUTO_TEST_CASE(TestDefaultedCOMPDATIJ) {
|
BOOST_AUTO_TEST_CASE(TestDefaultedCOMPDATIJ)
|
||||||
Parser parser;
|
{
|
||||||
const char * deckString = "\n\
|
const auto deck = Parser{}.parseString(R"(
|
||||||
START\n\
|
START
|
||||||
\n\
|
|
||||||
10 MAI 2007 /\n\
|
10 MAI 2007 /
|
||||||
\n\
|
|
||||||
GRID\n\
|
GRID
|
||||||
PERMX\n\
|
PERMX
|
||||||
9000*0.25 /\n\
|
9000*0.25 /
|
||||||
COPY \n\
|
COPY
|
||||||
PERMX PERMY /\n\
|
PERMX PERMY /
|
||||||
PERMX PERMZ /\n\
|
PERMX PERMZ /
|
||||||
/\n\
|
/
|
||||||
SCHEDULE\n\
|
PORO
|
||||||
WELSPECS \n\
|
9000*0.3 /
|
||||||
'W1' 'OP' 11 21 3.33 'OIL' 7* / \n\
|
|
||||||
/\n\
|
SCHEDULE
|
||||||
COMPDAT \n\
|
WELSPECS
|
||||||
'W1' 2* 1 1 'OPEN' 1* 32.948 0.311 3047.839 2* 'X' 22.100 /\n\
|
'W1' 'OP' 11 21 3.33 'OIL' 7* /
|
||||||
/\n";
|
/
|
||||||
auto deck = parser.parseString(deckString);
|
COMPDAT
|
||||||
auto python = std::make_shared<Python>();
|
'W1' 2* 1 1 'OPEN' 1* 32.948 0.311 3047.839 2* 'X' 22.100 /
|
||||||
EclipseGrid grid(30,30,10);
|
/
|
||||||
TableManager table ( deck );
|
END
|
||||||
FieldPropsManager fp(deck, Phases{true, true, true}, grid, table);
|
)");
|
||||||
Runspec runspec (deck);
|
|
||||||
Schedule sched(deck, grid , fp, runspec, python);
|
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();
|
const auto& connections = sched.getWell("W1", 0).getConnections();
|
||||||
BOOST_CHECK_EQUAL( 10 , connections.get(0).getI() );
|
BOOST_CHECK_EQUAL( 10 , connections.get(0).getI() );
|
||||||
BOOST_CHECK_EQUAL( 20 , connections.get(0).getJ() );
|
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[0].wellgroup_events().hasEvent( "W_1", ScheduleEvents::COMPLETION_CHANGE));
|
||||||
BOOST_CHECK( sched[5].wellgroup_events().hasEvent( "W_1", ScheduleEvents::COMPLETION_CHANGE));
|
BOOST_CHECK( sched[5].wellgroup_events().hasEvent( "W_1", ScheduleEvents::COMPLETION_CHANGE));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -57,12 +57,22 @@ namespace {
|
|||||||
const auto j = (dims[1] - 1) - 1;
|
const auto j = (dims[1] - 1) - 1;
|
||||||
|
|
||||||
for (auto k = top; k < static_cast<int>(dims.size()); ++k) {
|
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,
|
conns.emplace_back(i, j, k, globIndex({i, j, k}, dims), k,
|
||||||
2000 + (2*k + 1) / static_cast<double>(2),
|
|
||||||
Opm::Connection::State::OPEN,
|
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::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 };
|
return { Opm::Connection::Order::INPUT, i, j, conns };
|
||||||
@ -87,18 +97,28 @@ namespace {
|
|||||||
};
|
};
|
||||||
|
|
||||||
for (auto k = topConn; k < kMax; ++k) {
|
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,
|
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, ...
|
// Open, Shut, Open, Open, Shut, ...
|
||||||
state[(k - topConn) % state.size()],
|
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::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 };
|
return { Opm::Connection::Order::INPUT, i, j, conns };
|
||||||
@ -115,12 +135,22 @@ namespace {
|
|||||||
const auto iMax = std::min(dims[0] - 1, left + numConns);
|
const auto iMax = std::min(dims[0] - 1, left + numConns);
|
||||||
|
|
||||||
for (auto i = left; i < iMax; ++i) {
|
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,
|
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,
|
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::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 };
|
return { Opm::Connection::Order::INPUT, left, j, conns };
|
||||||
|
@ -193,6 +193,7 @@ TEST_FOR_TYPE_NAMED(Action::State, ActionState)
|
|||||||
TEST_FOR_TYPE(BCConfig)
|
TEST_FOR_TYPE(BCConfig)
|
||||||
TEST_FOR_TYPE(BrineDensityTable)
|
TEST_FOR_TYPE(BrineDensityTable)
|
||||||
TEST_FOR_TYPE(ColumnSchema)
|
TEST_FOR_TYPE(ColumnSchema)
|
||||||
|
TEST_FOR_TYPE_NAMED(Connection::CTFProperties, CTFProperties)
|
||||||
TEST_FOR_TYPE(Connection)
|
TEST_FOR_TYPE(Connection)
|
||||||
TEST_FOR_TYPE_NAMED_OBJ(data::AquiferData, AquiferData_CarterTracy, serializationTestObjectC)
|
TEST_FOR_TYPE_NAMED_OBJ(data::AquiferData, AquiferData_CarterTracy, serializationTestObjectC)
|
||||||
TEST_FOR_TYPE_NAMED_OBJ(data::AquiferData, AquiferData_Fetkovich, serializationTestObjectF)
|
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(VFPProdTable)
|
||||||
TEST_FOR_TYPE(ViscrefTable)
|
TEST_FOR_TYPE(ViscrefTable)
|
||||||
TEST_FOR_TYPE(WatdentTable)
|
TEST_FOR_TYPE(WatdentTable)
|
||||||
|
TEST_FOR_TYPE_NAMED(WDFAC::Correlation, Correlation)
|
||||||
|
TEST_FOR_TYPE(WDFAC)
|
||||||
TEST_FOR_TYPE(Well)
|
TEST_FOR_TYPE(Well)
|
||||||
TEST_FOR_TYPE(Welldims)
|
TEST_FOR_TYPE(Welldims)
|
||||||
TEST_FOR_TYPE(WellBrineProperties)
|
TEST_FOR_TYPE(WellBrineProperties)
|
||||||
@ -335,11 +338,14 @@ TEST_FOR_TYPE(WListManager)
|
|||||||
TEST_FOR_TYPE(WriteRestartFileEvents)
|
TEST_FOR_TYPE(WriteRestartFileEvents)
|
||||||
|
|
||||||
|
|
||||||
|
namespace {
|
||||||
|
|
||||||
bool init_unit_test_func()
|
bool init_unit_test_func()
|
||||||
{
|
{
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
} // Anonymous namespace
|
||||||
|
|
||||||
int main(int argc, char** argv)
|
int main(int argc, char** argv)
|
||||||
{
|
{
|
||||||
|
Loading…
Reference in New Issue
Block a user