Merge pull request #797 from bska/load-using-ERst
Reimplement RestartIO::load() in Terms of Class ERst
This commit is contained in:
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
Copyright (c) 2018 Equinor ASA
|
||||
Copyright (c) 2018-2019 Equinor ASA
|
||||
Copyright (c) 2016 Statoil ASA
|
||||
Copyright (c) 2013-2015 Andreas Lauser
|
||||
Copyright (c) 2013 SINTEF ICT, Applied Mathematics.
|
||||
@@ -24,6 +24,9 @@
|
||||
|
||||
#include <opm/output/eclipse/RestartIO.hpp>
|
||||
|
||||
#include <opm/io/eclipse/ERst.hpp>
|
||||
#include <opm/io/eclipse/EclIOdata.hpp>
|
||||
|
||||
#include <opm/output/eclipse/RestartValue.hpp>
|
||||
|
||||
#include <opm/output/eclipse/VectorItems/connection.hpp>
|
||||
@@ -33,29 +36,59 @@
|
||||
#include <opm/output/eclipse/VectorItems/msw.hpp>
|
||||
#include <opm/output/eclipse/VectorItems/well.hpp>
|
||||
|
||||
#include <opm/output/eclipse/libECLRestart.hpp>
|
||||
|
||||
#include <opm/parser/eclipse/EclipseState/EclipseState.hpp>
|
||||
#include <opm/parser/eclipse/EclipseState/Grid/EclipseGrid.hpp>
|
||||
#include <opm/parser/eclipse/EclipseState/Schedule/MSW/WellSegments.hpp>
|
||||
#include <opm/parser/eclipse/EclipseState/Runspec.hpp>
|
||||
#include <opm/parser/eclipse/EclipseState/Schedule/Schedule.hpp>
|
||||
#include <opm/parser/eclipse/EclipseState/Schedule/SummaryState.hpp>
|
||||
#include <opm/parser/eclipse/EclipseState/Schedule/Well/Well2.hpp>
|
||||
|
||||
#include <algorithm>
|
||||
#include <cmath>
|
||||
#include <cstddef>
|
||||
#include <exception>
|
||||
#include <functional>
|
||||
#include <initializer_list>
|
||||
#include <map>
|
||||
#include <stdexcept>
|
||||
#include <string>
|
||||
#include <tuple>
|
||||
#include <type_traits>
|
||||
#include <unordered_map>
|
||||
#include <unordered_set>
|
||||
#include <utility>
|
||||
#include <vector>
|
||||
|
||||
namespace VI = ::Opm::RestartIO::Helpers::VectorItems;
|
||||
|
||||
namespace {
|
||||
template <typename T>
|
||||
struct ArrayType;
|
||||
|
||||
template<>
|
||||
struct ArrayType<int>
|
||||
{
|
||||
static Opm::EclIO::eclArrType T;
|
||||
};
|
||||
|
||||
template<>
|
||||
struct ArrayType<float>
|
||||
{
|
||||
static Opm::EclIO::eclArrType T;
|
||||
};
|
||||
|
||||
template<>
|
||||
struct ArrayType<double>
|
||||
{
|
||||
static Opm::EclIO::eclArrType T;
|
||||
};
|
||||
|
||||
Opm::EclIO::eclArrType ArrayType<int>::T = ::Opm::EclIO::eclArrType::INTE;
|
||||
Opm::EclIO::eclArrType ArrayType<float>::T = ::Opm::EclIO::eclArrType::REAL;
|
||||
Opm::EclIO::eclArrType ArrayType<double>::T = ::Opm::EclIO::eclArrType::DOUB;
|
||||
}
|
||||
|
||||
class RestartFileView
|
||||
{
|
||||
public:
|
||||
@@ -75,85 +108,97 @@ public:
|
||||
return this->sim_step_;
|
||||
}
|
||||
|
||||
int reportStep() const {
|
||||
return this->report_step;
|
||||
int reportStep() const
|
||||
{
|
||||
return this->report_step_;
|
||||
}
|
||||
|
||||
operator const Opm::RestartIO::ecl_file_view_type*() const
|
||||
template <typename ElmType>
|
||||
bool hasKeyword(const std::string& vector) const
|
||||
{
|
||||
return this->step_view_;
|
||||
if (this->rst_file_ == nullptr) { return false; }
|
||||
|
||||
return this->vectors_
|
||||
.at(ArrayType<ElmType>::T).count(vector) > 0;
|
||||
}
|
||||
|
||||
const Opm::RestartIO::ecl_kw_type* getKeyword(const char* kw) const
|
||||
template <typename ElmType>
|
||||
const std::vector<ElmType>&
|
||||
getKeyword(const std::string& vector)
|
||||
{
|
||||
namespace Load = Opm::RestartIO;
|
||||
return this->rst_file_->getRst<ElmType>(vector, this->report_step_);
|
||||
}
|
||||
|
||||
// Main grid only. Does not handle/support LGR.
|
||||
return Load::ecl_file_view_has_kw (*this, kw)
|
||||
? Load::ecl_file_view_iget_named_kw(*this, kw, 0)
|
||||
: nullptr;
|
||||
const std::vector<int>& intehead()
|
||||
{
|
||||
const auto& ihkw = std::string { "INTEHEAD" };
|
||||
|
||||
if (! this->hasKeyword<int>(ihkw)) {
|
||||
throw std::domain_error {
|
||||
"Purported Restart File Does not Have Integer Header"
|
||||
};
|
||||
}
|
||||
|
||||
return this->getKeyword<int>(ihkw);
|
||||
}
|
||||
|
||||
private:
|
||||
using RstFile = Opm::RestartIO::ert_unique_ptr<
|
||||
Opm::RestartIO::ecl_file_type,
|
||||
Opm::RestartIO::ecl_file_close>;
|
||||
using RstFile = std::unique_ptr<Opm::EclIO::ERst>;
|
||||
|
||||
std::size_t sim_step_;
|
||||
int report_step;
|
||||
RstFile rst_file_;
|
||||
Opm::RestartIO::ecl_file_view_type* step_view_ = nullptr;
|
||||
using VectorColl = std::unordered_set<std::string>;
|
||||
using TypedColl = std::unordered_map<
|
||||
Opm::EclIO::eclArrType, VectorColl, std::hash<int>
|
||||
>;
|
||||
|
||||
operator Opm::RestartIO::ecl_file_type*()
|
||||
{
|
||||
return this->rst_file_.get();
|
||||
}
|
||||
|
||||
operator const Opm::RestartIO::ecl_file_type*() const
|
||||
{
|
||||
return this->rst_file_.get();
|
||||
}
|
||||
RstFile rst_file_;
|
||||
int report_step_;
|
||||
std::size_t sim_step_;
|
||||
TypedColl vectors_;
|
||||
};
|
||||
|
||||
RestartFileView::RestartFileView(const std::string& filename,
|
||||
const int report_step)
|
||||
: sim_step_(std::max(report_step - 1, 0))
|
||||
, report_step(report_step)
|
||||
, rst_file_(Opm::RestartIO::ecl_file_open(filename.c_str(), 0))
|
||||
: rst_file_ { new Opm::EclIO::ERst{filename} }
|
||||
, report_step_(report_step)
|
||||
, sim_step_ (std::max(report_step - 1, 0))
|
||||
{
|
||||
namespace Load = Opm::RestartIO;
|
||||
|
||||
if (this->rst_file_ == nullptr) {
|
||||
throw std::invalid_argument {
|
||||
"Unable to open Restart File '" + filename
|
||||
+ "' at Report Step " + std::to_string(report_step)
|
||||
};
|
||||
if (! rst_file_->hasReportStepNumber(this->report_step_)) {
|
||||
rst_file_.reset();
|
||||
return;
|
||||
}
|
||||
|
||||
this->step_view_ =
|
||||
(Load::EclFiletype(filename) == Load::ECL_UNIFIED_RESTART_FILE)
|
||||
? Load::ecl_file_get_restart_view(*this, -1, report_step, -1, -1)
|
||||
: Load::ecl_file_get_global_view (*this); // Separate
|
||||
this->rst_file_->loadReportStepNumber(this->report_step_);
|
||||
|
||||
if (this->step_view_ == nullptr) {
|
||||
throw std::runtime_error {
|
||||
"Unable to acquire restart information for report step "
|
||||
+ std::to_string(report_step)
|
||||
};
|
||||
for (const auto& vector : this->rst_file_->listOfRstArrays(this->report_step_)) {
|
||||
const auto& type = std::get<1>(vector);
|
||||
|
||||
switch (type) {
|
||||
case ::Opm::EclIO::eclArrType::CHAR:
|
||||
case ::Opm::EclIO::eclArrType::LOGI:
|
||||
case ::Opm::EclIO::eclArrType::MESS:
|
||||
// Currently ignored
|
||||
continue;
|
||||
|
||||
default:
|
||||
this->vectors_[type].emplace(std::get<0>(vector));
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
RestartFileView::RestartFileView(RestartFileView&& rhs)
|
||||
: sim_step_ (rhs.sim_step_) // Scalar (size_t)
|
||||
, rst_file_ (std::move(rhs.rst_file_))
|
||||
, step_view_(rhs.step_view_) // Pointer
|
||||
: rst_file_ (std::move(rhs.rst_file_))
|
||||
, report_step_(rhs.report_step_)
|
||||
, sim_step_ (rhs.sim_step_) // Scalar (size_t)
|
||||
, vectors_ (std::move(rhs.vectors_))
|
||||
{}
|
||||
|
||||
RestartFileView& RestartFileView::operator=(RestartFileView&& rhs)
|
||||
{
|
||||
this->sim_step_ = rhs.sim_step_; // Scalar (size_t)
|
||||
this->rst_file_ = std::move(rhs.rst_file_);
|
||||
this->step_view_ = rhs.step_view_; // Pointer copy
|
||||
this->rst_file_ = std::move(rhs.rst_file_);
|
||||
this->report_step_ = rhs.report_step_; // Scalar (int)
|
||||
this->sim_step_ = rhs.sim_step_; // Scalar (size_t)
|
||||
this->vectors_ = std::move(rhs.vectors_);
|
||||
|
||||
return *this;
|
||||
}
|
||||
@@ -162,34 +207,21 @@ RestartFileView& RestartFileView::operator=(RestartFileView&& rhs)
|
||||
|
||||
namespace {
|
||||
template <typename T>
|
||||
const T* getPtr(const ::Opm::RestartIO::ecl_kw_type* kw)
|
||||
{
|
||||
return (kw == nullptr) ? nullptr
|
||||
: static_cast<const T*>(ecl_kw_iget_ptr(kw /* <- ADL */, 0));
|
||||
}
|
||||
|
||||
template <typename T>
|
||||
boost::iterator_range<const T*>
|
||||
getDataWindow(const T* arr,
|
||||
const std::size_t windowSize,
|
||||
const std::size_t entity,
|
||||
const std::size_t subEntity = 0,
|
||||
const std::size_t maxSubEntitiesPerEntity = 1)
|
||||
boost::iterator_range<typename std::vector<T>::const_iterator>
|
||||
getDataWindow(const std::vector<T>& arr,
|
||||
const std::size_t windowSize,
|
||||
const std::size_t entity,
|
||||
const std::size_t subEntity = 0,
|
||||
const std::size_t maxSubEntitiesPerEntity = 1)
|
||||
{
|
||||
const auto off =
|
||||
windowSize * (subEntity + maxSubEntitiesPerEntity*entity);
|
||||
|
||||
const auto* begin = arr + off;
|
||||
const auto* end = begin + windowSize;
|
||||
auto begin = arr.begin() + off;
|
||||
auto end = begin + windowSize;
|
||||
|
||||
return { begin, end };
|
||||
}
|
||||
|
||||
int getInteHeadElem(const ::Opm::RestartIO::ecl_kw_type* intehead,
|
||||
const std::vector<int>::size_type i)
|
||||
{
|
||||
return getPtr<int>(intehead)[i];
|
||||
}
|
||||
}
|
||||
|
||||
// ---------------------------------------------------------------------
|
||||
@@ -198,10 +230,12 @@ class WellVectors
|
||||
{
|
||||
public:
|
||||
template <typename T>
|
||||
using Window = boost::iterator_range<const T*>;
|
||||
using Window = boost::iterator_range<
|
||||
typename std::vector<T>::const_iterator
|
||||
>;
|
||||
|
||||
explicit WellVectors(const RestartFileView& rst_view,
|
||||
const ::Opm::RestartIO::ecl_kw_type* intehead);
|
||||
explicit WellVectors(const std::vector<int>& intehead,
|
||||
std::shared_ptr<RestartFileView> rst_view);
|
||||
|
||||
bool hasDefinedWellValues() const;
|
||||
bool hasDefinedConnectionValues() const;
|
||||
@@ -222,36 +256,29 @@ private:
|
||||
std::size_t numIConElem_;
|
||||
std::size_t numXConElem_;
|
||||
|
||||
const ::Opm::RestartIO::ecl_kw_type* iwel_;
|
||||
const ::Opm::RestartIO::ecl_kw_type* xwel_;
|
||||
|
||||
const ::Opm::RestartIO::ecl_kw_type* icon_;
|
||||
const ::Opm::RestartIO::ecl_kw_type* xcon_;
|
||||
std::shared_ptr<RestartFileView> rstView_;
|
||||
};
|
||||
|
||||
WellVectors::WellVectors(const RestartFileView& rst_view,
|
||||
const ::Opm::RestartIO::ecl_kw_type* intehead)
|
||||
: maxConnPerWell_(getInteHeadElem(intehead, VI::intehead::NCWMAX))
|
||||
, numIWelElem_ (getInteHeadElem(intehead, VI::intehead::NIWELZ))
|
||||
, numXWelElem_ (getInteHeadElem(intehead, VI::intehead::NXWELZ))
|
||||
, numIConElem_ (getInteHeadElem(intehead, VI::intehead::NICONZ))
|
||||
, numXConElem_ (getInteHeadElem(intehead, VI::intehead::NXCONZ))
|
||||
, iwel_ (rst_view.getKeyword("IWEL"))
|
||||
, xwel_ (rst_view.getKeyword("XWEL"))
|
||||
, icon_ (rst_view.getKeyword("ICON"))
|
||||
, xcon_ (rst_view.getKeyword("XCON"))
|
||||
WellVectors::WellVectors(const std::vector<int>& intehead,
|
||||
std::shared_ptr<RestartFileView> rst_view)
|
||||
: maxConnPerWell_(intehead[VI::intehead::NCWMAX])
|
||||
, numIWelElem_ (intehead[VI::intehead::NIWELZ])
|
||||
, numXWelElem_ (intehead[VI::intehead::NXWELZ])
|
||||
, numIConElem_ (intehead[VI::intehead::NICONZ])
|
||||
, numXConElem_ (intehead[VI::intehead::NXCONZ])
|
||||
, rstView_ (std::move(rst_view))
|
||||
{}
|
||||
|
||||
bool WellVectors::hasDefinedWellValues() const
|
||||
{
|
||||
return ! ((this->iwel_ == nullptr) ||
|
||||
(this->xwel_ == nullptr));
|
||||
return this->rstView_->hasKeyword<int> ("IWEL")
|
||||
&& this->rstView_->hasKeyword<double>("XWEL");
|
||||
}
|
||||
|
||||
bool WellVectors::hasDefinedConnectionValues() const
|
||||
{
|
||||
return ! ((this->icon_ == nullptr) ||
|
||||
(this->xcon_ == nullptr));
|
||||
return this->rstView_->hasKeyword<int> ("ICON")
|
||||
&& this->rstView_->hasKeyword<double>("XCON");
|
||||
}
|
||||
|
||||
WellVectors::Window<int>
|
||||
@@ -263,7 +290,7 @@ WellVectors::iwel(const std::size_t wellID) const
|
||||
};
|
||||
}
|
||||
|
||||
return getDataWindow(getPtr<int>(this->iwel_),
|
||||
return getDataWindow(this->rstView_->getKeyword<int>("IWEL"),
|
||||
this->numIWelElem_, wellID);
|
||||
}
|
||||
|
||||
@@ -276,7 +303,7 @@ WellVectors::xwel(const std::size_t wellID) const
|
||||
};
|
||||
}
|
||||
|
||||
return getDataWindow(getPtr<double>(this->xwel_),
|
||||
return getDataWindow(this->rstView_->getKeyword<double>("XWEL"),
|
||||
this->numXWelElem_, wellID);
|
||||
}
|
||||
|
||||
@@ -289,8 +316,9 @@ WellVectors::icon(const std::size_t wellID, const std::size_t connID) const
|
||||
};
|
||||
}
|
||||
|
||||
return getDataWindow(getPtr<int>(this->icon_), this->numIConElem_,
|
||||
wellID, connID, this->maxConnPerWell_);
|
||||
return getDataWindow(this->rstView_->getKeyword<int>("ICON"),
|
||||
this->numIConElem_, wellID, connID,
|
||||
this->maxConnPerWell_);
|
||||
}
|
||||
|
||||
WellVectors::Window<double>
|
||||
@@ -302,8 +330,9 @@ WellVectors::xcon(const std::size_t wellID, const std::size_t connID) const
|
||||
};
|
||||
}
|
||||
|
||||
return getDataWindow(getPtr<double>(this->xcon_), this->numXConElem_,
|
||||
wellID, connID, this->maxConnPerWell_);
|
||||
return getDataWindow(this->rstView_->getKeyword<double>("XCON"),
|
||||
this->numXConElem_, wellID, connID,
|
||||
this->maxConnPerWell_);
|
||||
}
|
||||
|
||||
// ---------------------------------------------------------------------
|
||||
@@ -312,10 +341,12 @@ class GroupVectors
|
||||
{
|
||||
public:
|
||||
template <typename T>
|
||||
using Window = boost::iterator_range<const T*>;
|
||||
using Window = boost::iterator_range<
|
||||
typename std::vector<T>::const_iterator
|
||||
>;
|
||||
|
||||
explicit GroupVectors(const RestartFileView& rst_view,
|
||||
const ::Opm::RestartIO::ecl_kw_type* intehead);
|
||||
explicit GroupVectors(const std::vector<int>& intehead,
|
||||
std::shared_ptr<RestartFileView> rst_view);
|
||||
|
||||
bool hasDefinedValues() const;
|
||||
|
||||
@@ -329,23 +360,21 @@ private:
|
||||
std::size_t numIGrpElem_;
|
||||
std::size_t numXGrpElem_;
|
||||
|
||||
const ::Opm::RestartIO::ecl_kw_type* igrp_;
|
||||
const ::Opm::RestartIO::ecl_kw_type* xgrp_;
|
||||
std::shared_ptr<RestartFileView> rstView_;
|
||||
};
|
||||
|
||||
GroupVectors::GroupVectors(const RestartFileView& rst_view,
|
||||
const ::Opm::RestartIO::ecl_kw_type* intehead)
|
||||
: maxNumGroups_(getInteHeadElem(intehead, VI::intehead::NGMAXZ) - 1) // -FIELD
|
||||
, numIGrpElem_ (getInteHeadElem(intehead, VI::intehead::NIGRPZ))
|
||||
, numXGrpElem_ (getInteHeadElem(intehead, VI::intehead::NXGRPZ))
|
||||
, igrp_ (rst_view.getKeyword("IGRP"))
|
||||
, xgrp_ (rst_view.getKeyword("XGRP"))
|
||||
GroupVectors::GroupVectors(const std::vector<int>& intehead,
|
||||
std::shared_ptr<RestartFileView> rst_view)
|
||||
: maxNumGroups_(intehead[VI::intehead::NGMAXZ] - 1) // -FIELD
|
||||
, numIGrpElem_ (intehead[VI::intehead::NIGRPZ])
|
||||
, numXGrpElem_ (intehead[VI::intehead::NXGRPZ])
|
||||
, rstView_ (std::move(rst_view))
|
||||
{}
|
||||
|
||||
bool GroupVectors::hasDefinedValues() const
|
||||
{
|
||||
return ! ((this->igrp_ == nullptr) ||
|
||||
(this->xgrp_ == nullptr));
|
||||
return this->rstView_->hasKeyword<int> ("IGRP")
|
||||
&& this->rstView_->hasKeyword<double>("XGRP");
|
||||
}
|
||||
|
||||
std::size_t GroupVectors::maxGroups() const
|
||||
@@ -358,11 +387,11 @@ GroupVectors::igrp(const std::size_t groupID) const
|
||||
{
|
||||
if (! this->hasDefinedValues()) {
|
||||
throw std::logic_error {
|
||||
"Cannot Request IWEL Values Unless Defined"
|
||||
"Cannot Request IGRP Values Unless Defined"
|
||||
};
|
||||
}
|
||||
|
||||
return getDataWindow(getPtr<int>(this->igrp_),
|
||||
return getDataWindow(this->rstView_->getKeyword<int>("IGRP"),
|
||||
this->numIGrpElem_, groupID);
|
||||
}
|
||||
|
||||
@@ -375,7 +404,7 @@ GroupVectors::xgrp(const std::size_t groupID) const
|
||||
};
|
||||
}
|
||||
|
||||
return getDataWindow(getPtr<double>(this->xgrp_),
|
||||
return getDataWindow(this->rstView_->getKeyword<double>("XGRP"),
|
||||
this->numXGrpElem_, groupID);
|
||||
}
|
||||
|
||||
@@ -385,10 +414,12 @@ class SegmentVectors
|
||||
{
|
||||
public:
|
||||
template <typename T>
|
||||
using Window = boost::iterator_range<const T*>;
|
||||
using Window = boost::iterator_range<
|
||||
typename std::vector<T>::const_iterator
|
||||
>;
|
||||
|
||||
explicit SegmentVectors(const RestartFileView& rst_view,
|
||||
const ::Opm::RestartIO::ecl_kw_type* intehead);
|
||||
explicit SegmentVectors(const std::vector<int>& intehead,
|
||||
std::shared_ptr<RestartFileView> rst_view);
|
||||
|
||||
bool hasDefinedValues() const;
|
||||
|
||||
@@ -403,23 +434,21 @@ private:
|
||||
std::size_t numISegElm_;
|
||||
std::size_t numRSegElm_;
|
||||
|
||||
const ::Opm::RestartIO::ecl_kw_type* iseg_;
|
||||
const ::Opm::RestartIO::ecl_kw_type* rseg_;
|
||||
std::shared_ptr<RestartFileView> rstView_;
|
||||
};
|
||||
|
||||
SegmentVectors::SegmentVectors(const RestartFileView& rst_view,
|
||||
const ::Opm::RestartIO::ecl_kw_type* intehead)
|
||||
: maxSegPerWell_(getInteHeadElem(intehead, VI::intehead::NSEGMX))
|
||||
, numISegElm_ (getInteHeadElem(intehead, VI::intehead::NISEGZ))
|
||||
, numRSegElm_ (getInteHeadElem(intehead, VI::intehead::NRSEGZ))
|
||||
, iseg_ (rst_view.getKeyword("ISEG"))
|
||||
, rseg_ (rst_view.getKeyword("RSEG"))
|
||||
SegmentVectors::SegmentVectors(const std::vector<int>& intehead,
|
||||
std::shared_ptr<RestartFileView> rst_view)
|
||||
: maxSegPerWell_(intehead[VI::intehead::NSEGMX])
|
||||
, numISegElm_ (intehead[VI::intehead::NISEGZ])
|
||||
, numRSegElm_ (intehead[VI::intehead::NRSEGZ])
|
||||
, rstView_ (std::move(rst_view))
|
||||
{}
|
||||
|
||||
bool SegmentVectors::hasDefinedValues() const
|
||||
{
|
||||
return ! ((this->iseg_ == nullptr) ||
|
||||
(this->rseg_ == nullptr));
|
||||
return this->rstView_->hasKeyword<int> ("ISEG")
|
||||
&& this->rstView_->hasKeyword<double>("RSEG");
|
||||
}
|
||||
|
||||
SegmentVectors::Window<int>
|
||||
@@ -431,8 +460,9 @@ SegmentVectors::iseg(const std::size_t mswID, const std::size_t segID) const
|
||||
};
|
||||
}
|
||||
|
||||
return getDataWindow(getPtr<int>(this->iseg_), this->numISegElm_,
|
||||
mswID, segID, this->maxSegPerWell_);
|
||||
return getDataWindow(this->rstView_->getKeyword<int>("ISEG"),
|
||||
this->numISegElm_, mswID, segID,
|
||||
this->maxSegPerWell_);
|
||||
}
|
||||
|
||||
SegmentVectors::Window<double>
|
||||
@@ -444,8 +474,9 @@ SegmentVectors::rseg(const std::size_t mswID, const std::size_t segID) const
|
||||
};
|
||||
}
|
||||
|
||||
return getDataWindow(getPtr<double>(this->rseg_), this->numRSegElm_,
|
||||
mswID, segID, this->maxSegPerWell_);
|
||||
return getDataWindow(this->rstView_->getKeyword<double>("RSEG"),
|
||||
this->numRSegElm_, mswID, segID,
|
||||
this->maxSegPerWell_);
|
||||
}
|
||||
|
||||
// ---------------------------------------------------------------------
|
||||
@@ -463,23 +494,21 @@ namespace {
|
||||
}
|
||||
|
||||
std::vector<double>
|
||||
double_vector(const ::Opm::RestartIO::ecl_kw_type* ecl_kw)
|
||||
double_vector(const std::string& key, RestartFileView& rst_view)
|
||||
{
|
||||
namespace Load = ::Opm::RestartIO;
|
||||
|
||||
const auto size = static_cast<std::size_t>(
|
||||
Load::ecl_kw_get_size(ecl_kw));
|
||||
|
||||
if (Load::ecl_type_get_type(Load::ecl_kw_get_data_type(ecl_kw)) == Load::ECL_DOUBLE_TYPE) {
|
||||
const double* ecl_data = Load::ecl_kw_get_type_ptr<double>(ecl_kw, Load::ECL_DOUBLE_TYPE);
|
||||
|
||||
return { ecl_data , ecl_data + size };
|
||||
if (rst_view.hasKeyword<double>(key)) {
|
||||
// Data exists as type DOUB. Return unchanged.
|
||||
return rst_view.getKeyword<double>(key);
|
||||
}
|
||||
else {
|
||||
const float* ecl_data = Load::ecl_kw_get_type_ptr<float>(ecl_kw, Load::ECL_FLOAT_TYPE);
|
||||
else if (rst_view.hasKeyword<float>(key)) {
|
||||
// Data exists as type REAL. Convert to double.
|
||||
const auto& data = rst_view.getKeyword<float>(key);
|
||||
|
||||
return { ecl_data , ecl_data + size };
|
||||
return { data.begin(), data.end() };
|
||||
}
|
||||
|
||||
// Data unavailable. Return empty.
|
||||
return {};
|
||||
}
|
||||
|
||||
void insertSolutionVector(const std::vector<double>& vector,
|
||||
@@ -499,14 +528,14 @@ namespace {
|
||||
Opm::data::TargetType::RESTART_SOLUTION);
|
||||
}
|
||||
|
||||
void loadIfAvailable(const RestartFileView& rst_view,
|
||||
const Opm::RestartKey& value,
|
||||
void loadIfAvailable(const Opm::RestartKey& value,
|
||||
const std::vector<double>::size_type numcells,
|
||||
RestartFileView& rst_view,
|
||||
Opm::data::Solution& sol)
|
||||
{
|
||||
const auto* kw = rst_view.getKeyword(value.key.c_str());
|
||||
const auto& kwdata = double_vector(value.key, rst_view);
|
||||
|
||||
if (kw == nullptr) {
|
||||
if (kwdata.empty()) {
|
||||
throwIfMissingRequired(value);
|
||||
|
||||
// If we get here, the requested value was not available in the
|
||||
@@ -515,27 +544,27 @@ namespace {
|
||||
return;
|
||||
}
|
||||
|
||||
insertSolutionVector(double_vector(kw), value, numcells, sol);
|
||||
insertSolutionVector(kwdata, value, numcells, sol);
|
||||
}
|
||||
|
||||
void loadHysteresisIfAvailable(const RestartFileView& rst_view,
|
||||
const std::string& primary,
|
||||
void loadHysteresisIfAvailable(const std::string& primary,
|
||||
const Opm::RestartKey& fallback_key,
|
||||
const std::vector<double>::size_type numcells,
|
||||
RestartFileView& rst_view,
|
||||
Opm::data::Solution& sol)
|
||||
{
|
||||
const auto* kw = rst_view.getKeyword(primary.c_str());
|
||||
auto kwdata = double_vector(primary, rst_view);
|
||||
|
||||
if (kw == nullptr) {
|
||||
if (kwdata.empty()) {
|
||||
// Primary key does not exist in rst_view. Attempt to load
|
||||
// fallback keys directly.
|
||||
|
||||
loadIfAvailable(rst_view, fallback_key, numcells, sol);
|
||||
loadIfAvailable(fallback_key, numcells, rst_view, sol);
|
||||
}
|
||||
else {
|
||||
// Primary exists in rst_view. Translate to Flow's hysteresis
|
||||
// parameter.
|
||||
auto smax = double_vector(kw);
|
||||
auto smax = std::move(kwdata);
|
||||
|
||||
std::transform(std::begin(smax), std::end(smax), std::begin(smax),
|
||||
[](const double s) { return 1.0 - s; });
|
||||
@@ -556,8 +585,8 @@ namespace {
|
||||
}
|
||||
|
||||
void restoreHysteresisVector(const Opm::RestartKey& value,
|
||||
const RestartFileView& rst_view,
|
||||
const int numcells,
|
||||
RestartFileView& rst_view,
|
||||
Opm::data::Solution& sol)
|
||||
{
|
||||
const auto& key = value.key;
|
||||
@@ -566,27 +595,26 @@ namespace {
|
||||
{
|
||||
// Attempt to load from SOMAX, fall back to value.key if
|
||||
// unavailable--typically in OPM Extended restart file.
|
||||
loadHysteresisIfAvailable(rst_view, "SOMAX",
|
||||
value, numcells, sol);
|
||||
loadHysteresisIfAvailable("SOMAX", value, numcells,
|
||||
rst_view, sol);
|
||||
}
|
||||
else if ((key == "KRNSW_GO") || (key == "PCSWM_GO"))
|
||||
{
|
||||
// Attempt to load from SGMAX, fall back to value.key if
|
||||
// unavailable--typically in OPM Extended restart file.
|
||||
loadHysteresisIfAvailable(rst_view, "SGMAX",
|
||||
value, numcells, sol);
|
||||
loadHysteresisIfAvailable("SGMAX", value, numcells,
|
||||
rst_view, sol);
|
||||
}
|
||||
}
|
||||
|
||||
std::vector<double>
|
||||
getOpmExtraFromDoubHEAD(const RestartFileView& rst_view,
|
||||
const bool required,
|
||||
const Opm::UnitSystem& usys)
|
||||
getOpmExtraFromDoubHEAD(const bool required,
|
||||
const Opm::UnitSystem& usys,
|
||||
RestartFileView& rst_view)
|
||||
{
|
||||
using M = Opm::UnitSystem::measure;
|
||||
|
||||
const auto* doubhead =
|
||||
getPtr<double>(rst_view.getKeyword("DOUBHEAD"));
|
||||
const auto& doubhead = rst_view.getKeyword<double>("DOUBHEAD");
|
||||
|
||||
const auto TsInit = doubhead[VI::doubhead::TsInit];
|
||||
|
||||
@@ -598,9 +626,9 @@ namespace {
|
||||
}
|
||||
|
||||
Opm::data::Solution
|
||||
restoreSOLUTION(const RestartFileView& rst_view,
|
||||
const std::vector<Opm::RestartKey>& solution_keys,
|
||||
const int numcells)
|
||||
restoreSOLUTION(const std::vector<Opm::RestartKey>& solution_keys,
|
||||
const int numcells,
|
||||
RestartFileView& rst_view)
|
||||
{
|
||||
Opm::data::Solution sol(/* init_si = */ false);
|
||||
|
||||
@@ -609,29 +637,27 @@ namespace {
|
||||
// Special case handling of hysteresis data. Possibly needs
|
||||
// translation from ECLIPSE-compatible set to Flow's known
|
||||
// set of hysteresis vectors.
|
||||
restoreHysteresisVector(value, rst_view, numcells, sol);
|
||||
restoreHysteresisVector(value, numcells, rst_view, sol);
|
||||
continue;
|
||||
}
|
||||
|
||||
// Load regular (non-hysteresis) vector if available.
|
||||
loadIfAvailable(rst_view, value, numcells, sol);
|
||||
loadIfAvailable(value, numcells, rst_view, sol);
|
||||
}
|
||||
|
||||
return sol;
|
||||
}
|
||||
|
||||
void restoreExtra(const RestartFileView& rst_view,
|
||||
const std::vector<Opm::RestartKey>& extra_keys,
|
||||
void restoreExtra(const std::vector<Opm::RestartKey>& extra_keys,
|
||||
const Opm::UnitSystem& usys,
|
||||
RestartFileView& rst_view,
|
||||
Opm::RestartValue& rst_value)
|
||||
{
|
||||
for (const auto& extra : extra_keys) {
|
||||
const auto& vector = extra.key;
|
||||
const auto* kw = rst_view.getKeyword(vector.c_str());
|
||||
auto kwdata = double_vector(vector, rst_view);
|
||||
|
||||
auto kwdata = std::vector<double>{};
|
||||
|
||||
if (kw == nullptr) {
|
||||
if (kwdata.empty()) {
|
||||
// Requested vector not available in result set. Take
|
||||
// appropriate action depending on specific vector and
|
||||
// 'extra.required'.
|
||||
@@ -651,15 +677,10 @@ namespace {
|
||||
// and caller requires that item be present through the
|
||||
// 'extra.required' mechanism.
|
||||
|
||||
kwdata = getOpmExtraFromDoubHEAD(rst_view,
|
||||
extra.required,
|
||||
usys);
|
||||
kwdata = getOpmExtraFromDoubHEAD(extra.required,
|
||||
usys, rst_view);
|
||||
}
|
||||
}
|
||||
else {
|
||||
// Requisite vector available in result set. Recover data.
|
||||
kwdata = double_vector(kw);
|
||||
}
|
||||
|
||||
rst_value.addExtra(vector, extra.dim, std::move(kwdata));
|
||||
}
|
||||
@@ -672,16 +693,15 @@ namespace {
|
||||
}
|
||||
}
|
||||
|
||||
void checkWellVectorSizes(const ::Opm::RestartIO::ecl_kw_type* opm_xwel,
|
||||
const ::Opm::RestartIO::ecl_kw_type* opm_iwel,
|
||||
const int sim_step,
|
||||
void checkWellVectorSizes(const std::vector<int>& opm_iwel,
|
||||
const std::vector<double>& opm_xwel,
|
||||
const std::vector<Opm::data::Rates::opt>& phases,
|
||||
const std::vector<Opm::Well2>& sched_wells)
|
||||
{
|
||||
const auto expected_xwel_size =
|
||||
std::accumulate(sched_wells.begin(), sched_wells.end(),
|
||||
std::size_t(0),
|
||||
[&phases, sim_step](const std::size_t acc, const Opm::Well2& w)
|
||||
[&phases](const std::size_t acc, const Opm::Well2& w)
|
||||
-> std::size_t
|
||||
{
|
||||
return acc
|
||||
@@ -690,39 +710,38 @@ namespace {
|
||||
* (phases.size() + Opm::data::Connection::restart_size));
|
||||
});
|
||||
|
||||
if (static_cast<std::size_t>(::Opm::RestartIO::ecl_kw_get_size(opm_xwel)) != expected_xwel_size)
|
||||
{
|
||||
if (opm_xwel.size() != expected_xwel_size) {
|
||||
throw std::runtime_error {
|
||||
"Mismatch between OPM_XWEL and deck; "
|
||||
"OPM_XWEL size was " + std::to_string(::Opm::RestartIO::ecl_kw_get_size(opm_xwel)) +
|
||||
"OPM_XWEL size was " + std::to_string(opm_xwel.size()) +
|
||||
", expected " + std::to_string(expected_xwel_size)
|
||||
};
|
||||
}
|
||||
|
||||
if (::Opm::RestartIO::ecl_kw_get_size(opm_iwel) != int(sched_wells.size())) {
|
||||
if (opm_iwel.size() != sched_wells.size()) {
|
||||
throw std::runtime_error {
|
||||
"Mismatch between OPM_IWEL and deck; "
|
||||
"OPM_IWEL size was " + std::to_string(::Opm::RestartIO::ecl_kw_get_size(opm_iwel)) +
|
||||
"OPM_IWEL size was " + std::to_string(opm_iwel.size()) +
|
||||
", expected " + std::to_string(sched_wells.size())
|
||||
};
|
||||
}
|
||||
}
|
||||
|
||||
Opm::data::Wells
|
||||
restore_wells_opm(const RestartFileView& rst_view,
|
||||
const ::Opm::EclipseState& es,
|
||||
restore_wells_opm(const ::Opm::EclipseState& es,
|
||||
const ::Opm::EclipseGrid& grid,
|
||||
const ::Opm::Schedule& schedule)
|
||||
const ::Opm::Schedule& schedule,
|
||||
RestartFileView& rst_view)
|
||||
{
|
||||
namespace Load = ::Opm::RestartIO;
|
||||
|
||||
const auto* opm_iwel = rst_view.getKeyword("OPM_IWEL");
|
||||
const auto* opm_xwel = rst_view.getKeyword("OPM_XWEL");
|
||||
|
||||
if ((opm_xwel == nullptr) || (opm_iwel == nullptr)) {
|
||||
if (! (rst_view.hasKeyword<int> ("OPM_IWEL") &&
|
||||
rst_view.hasKeyword<double>("OPM_XWEL")))
|
||||
{
|
||||
return {};
|
||||
}
|
||||
|
||||
const auto& opm_iwel = rst_view.getKeyword<int> ("OPM_IWEL");
|
||||
const auto& opm_xwel = rst_view.getKeyword<double>("OPM_XWEL");
|
||||
|
||||
using rt = Opm::data::Rates::opt;
|
||||
|
||||
const auto& sched_wells = schedule.getWells2(rst_view.simStep());
|
||||
@@ -735,23 +754,22 @@ namespace {
|
||||
if (phase.active(Opm::Phase::GAS)) { phases.push_back(rt::gas); }
|
||||
}
|
||||
|
||||
checkWellVectorSizes(opm_xwel, opm_iwel,
|
||||
rst_view.simStep(),
|
||||
phases, sched_wells);
|
||||
checkWellVectorSizes(opm_iwel, opm_xwel, phases, sched_wells);
|
||||
|
||||
Opm::data::Wells wells;
|
||||
const auto* opm_xwel_data = Load::ecl_kw_get_type_ptr<double>(opm_xwel, Load::ECL_DOUBLE_TYPE);
|
||||
const auto* opm_iwel_data = Load::ecl_kw_get_type_ptr<int>(opm_iwel, Load::ECL_INT_TYPE);
|
||||
auto opm_xwel_data = opm_xwel.begin();
|
||||
auto opm_iwel_data = opm_iwel.begin();
|
||||
|
||||
for (const auto& sched_well : sched_wells) {
|
||||
auto& well = wells[ sched_well.name() ];
|
||||
|
||||
well.bhp = *opm_xwel_data++;
|
||||
well.temperature = *opm_xwel_data++;
|
||||
well.control = *opm_iwel_data++;
|
||||
well.bhp = *opm_xwel_data; ++opm_xwel_data;
|
||||
well.temperature = *opm_xwel_data; ++opm_xwel_data;
|
||||
well.control = *opm_iwel_data; ++opm_iwel_data;
|
||||
|
||||
for (const auto& phase : phases) {
|
||||
well.rates.set(phase, *opm_xwel_data++);
|
||||
well.rates.set(phase, *opm_xwel_data);
|
||||
++opm_xwel_data;
|
||||
}
|
||||
|
||||
for (const auto& sc : sched_well.getConnections()) {
|
||||
@@ -766,11 +784,12 @@ namespace {
|
||||
auto& connection = well.connections.back();
|
||||
|
||||
connection.index = grid.getGlobalIndex(i, j, k);
|
||||
connection.pressure = *opm_xwel_data++;
|
||||
connection.reservoir_rate = *opm_xwel_data++;
|
||||
connection.pressure = *opm_xwel_data; ++opm_xwel_data;
|
||||
connection.reservoir_rate = *opm_xwel_data; ++opm_xwel_data;
|
||||
|
||||
for (const auto& phase : phases) {
|
||||
connection.rates.set(phase, *opm_xwel_data++);
|
||||
connection.rates.set(phase, *opm_xwel_data);
|
||||
++opm_xwel_data;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -840,9 +859,8 @@ namespace {
|
||||
if (gas) { xc.rates.set(Opm::data::Rates::opt::gas, 0.0); }
|
||||
}
|
||||
|
||||
void restoreConnResults(const Opm::Well2& well,
|
||||
void restoreConnResults(const Opm::Well2& well,
|
||||
const std::size_t wellID,
|
||||
const std::size_t sim_step,
|
||||
const Opm::EclipseGrid& grid,
|
||||
const Opm::UnitSystem& usys,
|
||||
const Opm::Phases& phases,
|
||||
@@ -964,7 +982,6 @@ namespace {
|
||||
Opm::data::Well
|
||||
restore_well(const Opm::Well2& well,
|
||||
const std::size_t wellID,
|
||||
const std::size_t sim_step,
|
||||
const Opm::EclipseGrid& grid,
|
||||
const Opm::UnitSystem& usys,
|
||||
const Opm::Phases& phases,
|
||||
@@ -1012,8 +1029,7 @@ namespace {
|
||||
|
||||
// 3) Restore connection flow rates (xw.connections[i].rates)
|
||||
// and pressure values (xw.connections[i].pressure).
|
||||
restoreConnResults(well, wellID, sim_step,
|
||||
grid, usys, phases, wellData, xw);
|
||||
restoreConnResults(well, wellID, grid, usys, phases, wellData, xw);
|
||||
|
||||
// 4) Restore segment quantities if applicable.
|
||||
if (well.isMultiSegment() &&
|
||||
@@ -1037,36 +1053,30 @@ namespace {
|
||||
}
|
||||
|
||||
Opm::data::Wells
|
||||
restore_wells_ecl(const RestartFileView& rst_view,
|
||||
const ::Opm::EclipseState& es,
|
||||
const ::Opm::EclipseGrid& grid,
|
||||
const ::Opm::Schedule& schedule)
|
||||
restore_wells_ecl(const ::Opm::EclipseState& es,
|
||||
const ::Opm::EclipseGrid& grid,
|
||||
const ::Opm::Schedule& schedule,
|
||||
std::shared_ptr<RestartFileView> rst_view)
|
||||
{
|
||||
auto soln = ::Opm::data::Wells{};
|
||||
|
||||
const auto* intehead = rst_view.getKeyword("INTEHEAD");
|
||||
const auto& intehead = rst_view->intehead();;
|
||||
|
||||
if (intehead == nullptr) {
|
||||
// Result set does not provide indexing information.
|
||||
// Can't do anything here.
|
||||
return soln;
|
||||
}
|
||||
|
||||
const auto wellData = WellVectors { rst_view, intehead };
|
||||
const auto segData = SegmentVectors{ rst_view, intehead };
|
||||
const auto wellData = WellVectors { intehead, rst_view };
|
||||
const auto segData = SegmentVectors{ intehead, rst_view };
|
||||
|
||||
const auto& units = es.getUnits();
|
||||
const auto& phases = es.runspec().phases();
|
||||
|
||||
const auto sim_step = rst_view.simStep();
|
||||
const auto& wells = schedule.getWells2(sim_step);
|
||||
for (auto nWells = wells.size(), wellID = 0*nWells; wellID < nWells; ++wellID)
|
||||
const auto& wells = schedule.getWells2(rst_view->simStep());
|
||||
for (auto nWells = wells.size(), wellID = 0*nWells;
|
||||
wellID < nWells; ++wellID)
|
||||
{
|
||||
const auto& well = wells[wellID];
|
||||
|
||||
soln[well.name()] =
|
||||
restore_well(well, wellID, sim_step, grid,
|
||||
units, phases, wellData, segData);
|
||||
restore_well(well, wellID, grid, units,
|
||||
phases, wellData, segData);
|
||||
}
|
||||
|
||||
return soln;
|
||||
@@ -1143,20 +1153,18 @@ namespace {
|
||||
smry.update(key("GITH"), xgrp[VI::XGroup::index::HistGasInjTotal]);
|
||||
}
|
||||
|
||||
void restore_cumulative(Opm::SummaryState& smry,
|
||||
const RestartFileView& rst_view,
|
||||
const ::Opm::Schedule& schedule)
|
||||
void restore_cumulative(::Opm::SummaryState& smry,
|
||||
const ::Opm::Schedule& schedule,
|
||||
std::shared_ptr<RestartFileView> rst_view)
|
||||
{
|
||||
const auto sim_step = rst_view.simStep();
|
||||
const auto* intehead = rst_view.getKeyword("INTEHEAD");
|
||||
smry.update_elapsed(schedule.seconds( rst_view.reportStep() ));
|
||||
const auto sim_step = rst_view->simStep();
|
||||
const auto& intehead = rst_view->intehead();
|
||||
|
||||
if (intehead == nullptr)
|
||||
return;
|
||||
smry.update_elapsed(schedule.seconds(rst_view->reportStep()));
|
||||
|
||||
// Well cumulatives
|
||||
{
|
||||
const auto wellData = WellVectors { rst_view, intehead };
|
||||
const auto wellData = WellVectors { intehead, rst_view };
|
||||
const auto& wells = schedule.getWells2(sim_step);
|
||||
|
||||
for (auto nWells = wells.size(), wellID = 0*nWells;
|
||||
@@ -1169,7 +1177,9 @@ namespace {
|
||||
|
||||
// Group cumulatives, including FIELD.
|
||||
{
|
||||
const auto groupData = GroupVectors { rst_view, intehead };
|
||||
const auto groupData = GroupVectors {
|
||||
intehead, std::move(rst_view)
|
||||
};
|
||||
|
||||
for (const auto* group : schedule.getGroups(sim_step)) {
|
||||
const auto& gname = group->name();
|
||||
@@ -1206,24 +1216,26 @@ namespace Opm { namespace RestartIO {
|
||||
const Schedule& schedule,
|
||||
const std::vector<RestartKey>& extra_keys)
|
||||
{
|
||||
const auto rst_view = RestartFileView{ filename, report_step };
|
||||
auto rst_view =
|
||||
std::make_shared<RestartFileView>(filename, report_step);
|
||||
|
||||
auto xr = restoreSOLUTION(rst_view, solution_keys,
|
||||
grid.getNumActive());
|
||||
auto xr = restoreSOLUTION(solution_keys,
|
||||
grid.getNumActive(), *rst_view);
|
||||
|
||||
xr.convertToSI(es.getUnits());
|
||||
|
||||
auto xw = Opm::RestartIO::ecl_file_view_has_kw(rst_view, "OPM_XWEL")
|
||||
? restore_wells_opm(rst_view, es, grid, schedule)
|
||||
: restore_wells_ecl(rst_view, es, grid, schedule);
|
||||
auto xw = rst_view->hasKeyword<double>("OPM_XWEL")
|
||||
? restore_wells_opm(es, grid, schedule, *rst_view)
|
||||
: restore_wells_ecl(es, grid, schedule, rst_view);
|
||||
|
||||
auto rst_value = RestartValue{ std::move(xr), std::move(xw) };
|
||||
|
||||
if (! extra_keys.empty()) {
|
||||
restoreExtra(rst_view, extra_keys, es.getUnits(), rst_value);
|
||||
restoreExtra(extra_keys, es.getUnits(), *rst_view, rst_value);
|
||||
}
|
||||
|
||||
restore_cumulative(summary_state, rst_view, schedule);
|
||||
restore_cumulative(summary_state, schedule, std::move(rst_view));
|
||||
|
||||
return rst_value;
|
||||
}
|
||||
|
||||
|
||||
Reference in New Issue
Block a user