Merge pull request #1056 from joakim-hove/field-properties

Add FieldProps skeleton
This commit is contained in:
Joakim Hove 2019-10-31 11:36:29 +01:00 committed by GitHub
commit 0fb55b23c0
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
15 changed files with 1154 additions and 16 deletions

View File

@ -11,7 +11,11 @@ option(ENABLE_MOCKSIM "Build the mock simulator for io testing" ON)
option(OPM_ENABLE_PYTHON "Enable python bindings?" OFF)
option(OPM_INSTALL_PYTHON "Enable python bindings?" OFF)
option(OPM_ENABLE_EMBEDDED_PYTHON "Enable python bindings?" OFF)
option(ENABLE_3DPROPS_TESTING "Enable the in-constructor testing of 3D properties" OFF)
if (ENABLE_3DPROPS_TESTING)
add_definitions(-DENABLE_3DPROPS_TESTING)
endif()
# Output implies input
if(ENABLE_ECL_OUTPUT)

View File

@ -58,6 +58,8 @@ if(ENABLE_ECL_INPUT)
src/opm/parser/eclipse/EclipseState/EclipseState.cpp
src/opm/parser/eclipse/EclipseState/EndpointScaling.cpp
src/opm/parser/eclipse/EclipseState/Edit/EDITNNC.cpp
src/opm/parser/eclipse/EclipseState/Grid/FieldProps.cpp
src/opm/parser/eclipse/EclipseState/Grid/FieldPropsManager.cpp
src/opm/parser/eclipse/EclipseState/Grid/Box.cpp
src/opm/parser/eclipse/EclipseState/Grid/BoxManager.cpp
src/opm/parser/eclipse/EclipseState/Grid/EclipseGrid.cpp
@ -284,6 +286,7 @@ if(ENABLE_ECL_INPUT)
tests/parser/EventTests.cpp
tests/parser/FaceDirTests.cpp
tests/parser/FaultTests.cpp
tests/parser/FieldPropsTests.cpp
tests/parser/FoamTests.cpp
tests/parser/FunctionalTests.cpp
tests/parser/GeomodifierTests.cpp
@ -501,6 +504,7 @@ if(ENABLE_ECL_INPUT)
opm/parser/eclipse/EclipseState/Grid/SatfuncPropertyInitializers.hpp
opm/parser/eclipse/EclipseState/Grid/Fault.hpp
opm/parser/eclipse/EclipseState/Grid/Box.hpp
opm/parser/eclipse/EclipseState/Grid/FieldPropsManager.hpp
opm/parser/eclipse/EclipseState/Grid/GridProperty.hpp
opm/parser/eclipse/EclipseState/Grid/FaultFace.hpp
opm/parser/eclipse/EclipseState/Grid/NNC.hpp

View File

@ -4,7 +4,7 @@ declare -A configurations
declare -A EXTRA_MODULE_FLAGS
EXTRA_MODULE_FLAGS[opm-simulators]="-DBUILD_EBOS_EXTENSIONS=ON -DBUILD_EBOS_DEBUG_EXTENSIONS=ON -DBUILD_FLOW_VARIANTS=ON"
EXTRA_MODULE_FLAGS[opm-common]="-DOPM_ENABLE_PYTHON=ON -DOPM_ENABLE_EMBEDDED_PYTHON=ON -DOPM_INSTALL_PYTHON=ON"
EXTRA_MODULE_FLAGS[opm-common]="-DOPM_ENABLE_PYTHON=ON -DOPM_ENABLE_EMBEDDED_PYTHON=ON -DOPM_INSTALL_PYTHON=ON -DENABLE_3DPROPS_TESTING=ON"
# Parse revisions from trigger comment and setup arrays
# Depends on: 'upstreams', upstreamRev',

View File

@ -28,6 +28,7 @@
#include <opm/parser/eclipse/EclipseState/Eclipse3DProperties.hpp>
#include <opm/parser/eclipse/EclipseState/EclipseConfig.hpp>
#include <opm/parser/eclipse/EclipseState/Edit/EDITNNC.hpp>
#include <opm/parser/eclipse/EclipseState/Grid/FieldPropsManager.hpp>
#include <opm/parser/eclipse/EclipseState/Grid/EclipseGrid.hpp>
#include <opm/parser/eclipse/EclipseState/Grid/FaultCollection.hpp>
#include <opm/parser/eclipse/EclipseState/Grid/NNC.hpp>
@ -129,6 +130,7 @@ namespace Opm {
EDITNNC m_inputEditNnc;
EclipseGrid m_inputGrid;
Eclipse3DProperties m_eclipseProperties;
FieldPropsManager field_props;
const SimulationConfig m_simulationConfig;
TransMult m_transMult;

View File

@ -64,6 +64,7 @@ namespace Opm {
void endKeyword();
const Box& getActiveBox() const;
const std::vector<Box::cell_index>& index_list() const;
private:
const EclipseGrid& grid;

View File

@ -0,0 +1,56 @@
/*
Copyright 2019 Equinor ASA.
This file is part of the Open Porous Media project (OPM).
OPM is free software: you can redistribute it and/or modify it under the terms
of the GNU General Public License as published by the Free Software
Foundation, either version 3 of the License, or (at your option) any later
version.
OPM is distributed in the hope that it will be useful, but WITHOUT ANY
WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR
A PARTICULAR PURPOSE. See the GNU General Public License for more details.
You should have received a copy of the GNU General Public License along with
OPM. If not, see <http://www.gnu.org/licenses/>.
*/
#ifndef FIELDPROPS_MANAGER_HPP
#define FIELDPROPS_MANAGER_HPP
#include <memory>
namespace Opm {
class EclipseGrid;
class Deck;
class FieldProps;
class FieldPropsManager {
public:
// The default constructor should be removed when the FieldPropsManager is mandatory
FieldPropsManager() = default;
FieldPropsManager(const Deck& deck, const EclipseGrid& grid);
void reset_grid(const EclipseGrid& grid);
template <typename T>
const std::vector<T>& get(const std::string& keyword) const;
template <typename T>
const std::vector<T>* try_get(const std::string& keyword) const;
template <typename T>
std::vector<T> get_global(const std::string& keyword) const;
template <typename T>
static bool supported(const std::string& keyword);
private:
std::shared_ptr<FieldProps> fp;
};
}
#endif

View File

@ -51,7 +51,7 @@ const std::vector< double >& DeckItem::value_ref< double >() const {
if (this->type == get_type<double>())
return this->dval;
throw std::invalid_argument( "DeckItem::value_ref<double> Item of wrong type." );
throw std::invalid_argument( "DeckItem::value_ref<double> Item of wrong type. this->type: " + tag_name(this->type) + " " + this->name());
}
template<>

View File

@ -49,6 +49,88 @@
namespace Opm {
namespace {
#ifdef ENABLE_3DPROPS_TESTING
void assert_field_properties(const EclipseGrid& grid, const FieldPropsManager& fp, const Eclipse3DProperties& ep) {
std::vector<std::string> int_keywords = {"FLUXNUM",
"MULTNUM",
"OPERNUM",
"ROCKNUM",
//"ENDNUM",
"EQLNUM",
"FIPNUM",
"IMBNUM",
"MISCNUM",
"OPERNUM",
"PVTNUM",
"SATNUM"};
std::vector<std::string> double_keywords = {"MULTPV",
//"NTG",
"PORO",
"PERMX",
"PERMY",
"PERMZ",
"SWATINIT",
"TEMPI",
"THCONR"};
for (const auto& kw : double_keywords) {
bool has = fp.try_get<double>(kw);
if (has != ep.hasDeckDoubleGridProperty(kw)) {
std::cerr << "FieldPropsManager: " << has << std::endl;
std::cerr << "Eclipse3dProperties: " << ep.hasDeckDoubleGridProperty(kw) << std::endl;
throw std::logic_error("Exist Error for: " + kw);
}
if (has) {
const auto& fp_data = fp.get<double>(kw);
const auto& ep_data = ep.getDoubleGridProperty(kw).compressedCopy(grid);
if (fp_data != ep_data) {
printf("size: %ld %ld \n", fp_data.size(), ep_data.size());
for (std::size_t i=0; i< fp_data.size(); i++) {
if (fp_data[i] == ep_data[i])
printf("fp[%ld]: %lg ep[%ld]: %lg \n", i, fp_data[i], i, ep_data[i]);
else
printf("fp[%ld]: %lg ep[%ld]: %lg ** \n", i, fp_data[i], i, ep_data[i]);
}
throw std::logic_error("Data error for: " + kw);
}
}
}
for (const auto& kw : int_keywords) {
bool has = fp.try_get<int>(kw);
if (has != ep.hasDeckIntGridProperty(kw)) {
std::cerr << "FieldPropsManager: " << has << std::endl;
std::cerr << "Eclipse3dProperties: " << ep.hasDeckIntGridProperty(kw) << std::endl;
throw std::logic_error("Exists error for: " + kw);
}
if (has) {
const auto& fp_data = fp.get<int>(kw);
const auto& ep_data = ep.getIntGridProperty(kw).compressedCopy(grid);
if (fp_data != ep_data) {
printf("size: %ld %ld \n", fp_data.size(), ep_data.size());
for (std::size_t i=0; i< fp_data.size(); i++)
printf("fp[%ld]: %d ep[%ld]: %d \n", i, fp_data[i], i, ep_data[i]);
throw std::logic_error("Data error for: " + kw);
}
}
}
}
#endif
}
EclipseState::EclipseState(const Deck& deck , const ParseContext& parseContext, ErrorGuard& errors) :
m_tables( deck ),
m_runspec( deck ),
@ -58,6 +140,9 @@ namespace Opm {
m_inputEditNnc( deck ),
m_inputGrid( deck, nullptr ),
m_eclipseProperties( deck, m_tables, m_inputGrid ),
#ifdef ENABLE_3DPROPS_TESTING
field_props( deck, m_inputGrid),
#endif
m_simulationConfig( m_eclipseConfig.getInitConfig().restartRequested(), deck, m_eclipseProperties ),
m_transMult( GridDims(deck), deck, m_eclipseProperties )
{
@ -76,6 +161,10 @@ namespace Opm {
initTransMult();
initFaults(deck);
#ifdef ENABLE_3DPROPS_TESTING
this->field_props.reset_grid( this->m_inputGrid );
assert_field_properties(this->m_inputGrid, this->field_props, this->m_eclipseProperties);
#endif
}
@ -199,6 +288,9 @@ namespace Opm {
}
void EclipseState::initFaults(const Deck& deck) {
if (!Section::hasGRID(deck))
return;
const GRIDSection gridSection ( deck );
m_faults = FaultCollection(gridSection, m_inputGrid);

View File

@ -64,4 +64,7 @@ namespace Opm {
this->m_keywordBox.reset( 0 );
}
const std::vector<Box::cell_index>& BoxManager::index_list() const {
return this->getActiveBox().index_list();
}
}

View File

@ -0,0 +1,569 @@
/*
Copyright 2019 Equinor ASA.
This file is part of the Open Porous Media project (OPM).
OPM is free software: you can redistribute it and/or modify it under the terms
of the GNU General Public License as published by the Free Software
Foundation, either version 3 of the License, or (at your option) any later
version.
OPM is distributed in the hope that it will be useful, but WITHOUT ANY
WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR
A PARTICULAR PURPOSE. See the GNU General Public License for more details.
You should have received a copy of the GNU General Public License along with
OPM. If not, see <http://www.gnu.org/licenses/>.
*/
#include <opm/parser/eclipse/Parser/ParserKeywords/A.hpp>
#include <opm/parser/eclipse/Parser/ParserKeywords/B.hpp>
#include <opm/parser/eclipse/Parser/ParserKeywords/C.hpp>
#include <opm/parser/eclipse/Parser/ParserKeywords/E.hpp>
#include <opm/parser/eclipse/Parser/ParserKeywords/M.hpp>
#include <opm/parser/eclipse/Parser/ParserKeywords/P.hpp>
#include <opm/parser/eclipse/Deck/Deck.hpp>
#include <opm/parser/eclipse/EclipseState/Grid/EclipseGrid.hpp>
#include <opm/parser/eclipse/EclipseState/Grid/BoxManager.hpp>
#include "FieldProps.hpp"
namespace Opm {
namespace {
namespace keywords {
static const std::map<std::string, std::string> unit_string = {{"PORO", "1"},
{"PERMX", "Permeability"},
{"PERMY", "Permeability"},
{"PERMZ", "Permeability"},
{"NTG", "1"},
{"SWATINIT", "1"}};
static const std::set<std::string> oper_keywords = {"ADD", "EQUALS", "MAXVALUE", "MINVALUE", "MULTIPLY"};
static const std::set<std::string> box_keywords = {"BOX", "ENDBOX"};
static const std::map<std::string, double> double_scalar_init = {{"NTG", 1}};
namespace GRID {
static const std::set<std::string> double_keywords = {"MULTPV", "NTG", "PORO", "PERMX", "PERMY", "PERMZ", "THCONR"};
static const std::set<std::string> int_keywords = {"FLUXNUM", "MULTNUM", "OPERNUM", "ROCKNUM"};
static const std::set<std::string> top_keywords = {"PORO", "PERMX", "PERMY", "PERMZ"};
}
namespace EDIT {
static const std::set<std::string> double_keywords = {"MULTPV"};
}
namespace PROPS {
static const std::set<std::string> double_keywords = {"SWATINIT"};
}
namespace REGIONS {
static const std::set<std::string> int_keywords = {"ENDNUM", "EQLNUM", "FIPNUM", "IMBNUM", "MISCNUM", "OPERNUM", "PVTNUM", "SATNUM"};
}
namespace SOLUTION {
static const std::set<std::string> double_keywords = {"TEMPI"};
}
namespace SCHEDULE {
static const std::set<std::string> int_keywords = {"ROCKNUM"};
}
}
/*
* The EQUALREG, MULTREG, COPYREG, ... keywords are used to manipulate
* vectors based on region values; for instance the statement
*
* EQUALREG
* PORO 0.25 3 / -- Region array not specified
* PERMX 100 3 F /
* /
*
* will set the PORO field to 0.25 for all cells in region 3 and the PERMX
* value to 100 mD for the same cells. The fourth optional argument to the
* EQUALREG keyword is used to indicate which REGION array should be used
* for the selection.
*
* If the REGION array is not indicated (as in the PORO case) above, the
* default region to use in the xxxREG keywords depends on the GRIDOPTS
* keyword:
*
* 1. If GRIDOPTS is present, and the NRMULT item is greater than zero,
* the xxxREG keywords will default to use the MULTNUM region.
*
* 2. If the GRIDOPTS keyword is not present - or the NRMULT item equals
* zero, the xxxREG keywords will default to use the FLUXNUM keyword.
*
* This quite weird behaviour comes from reading the GRIDOPTS and MULTNUM
* documentation, and practical experience with ECLIPSE
* simulations. Ufortunately the documentation of the xxxREG keywords does
* not confirm this.
*/
std::string default_region_keyword(const Deck& deck) {
if (deck.hasKeyword("GRIDOPTS")) {
const auto& gridOpts = deck.getKeyword("GRIDOPTS");
const auto& record = gridOpts.getRecord(0);
const auto& nrmult_item = record.getItem("NRMULT");
if (nrmult_item.get<int>(0) > 0)
return "MULTNUM"; // GRIDOPTS and positive NRMULT
}
return "FLUXNUM";
}
template <typename T>
void assign_deck(const DeckKeyword& keyword, FieldProps::FieldData<T>& field_data, const std::vector<T>& deck_data, const Box& box) {
if (box.size() != deck_data.size()) {
const auto& location = keyword.location();
std::string msg = "Fundamental error with keyword: " + keyword.name() +
" at: " + location.filename + ", line: " + std::to_string(location.lineno) +
" got " + std::to_string(deck_data.size()) + " elements - expected : " + std::to_string(box.size());
throw std::invalid_argument(msg);
}
for (const auto& cell_index : box.index_list()) {
field_data.data[cell_index.active_index] = deck_data[cell_index.data_index];
field_data.assigned[cell_index.active_index] = true;
}
}
template <typename T>
void distribute_toplayer(const EclipseGrid& grid, FieldProps::FieldData<T>& field_data, const std::vector<T>& deck_data, const Box& box) {
const std::size_t layer_size = grid.getNX() * grid.getNY();
FieldProps::FieldData<double> toplayer(grid.getNX() * grid.getNY());
for (const auto& cell_index : box.index_list()) {
if (cell_index.global_index < layer_size) {
toplayer.data[cell_index.global_index] = deck_data[cell_index.data_index];
toplayer.assigned[cell_index.global_index] = true;
}
}
for (std::size_t active_index = 0; active_index < field_data.size(); active_index++) {
if (!field_data.assigned[active_index]) {
std::size_t global_index = grid.getGlobalIndex(active_index);
const auto ijk = grid.getIJK(global_index);
std::size_t layer_index = ijk[0] + ijk[1] * grid.getNX();
if (toplayer.assigned[layer_index]) {
field_data.data[active_index] = toplayer.data[layer_index];
field_data.assigned[active_index] = true;
}
}
}
}
template <typename T>
void assign_scalar(FieldProps::FieldData<T>& field_data, T value, const std::vector<Box::cell_index>& index_list) {
for (const auto& cell_index : index_list) {
field_data.data[cell_index.active_index] = value;
field_data.assigned[cell_index.active_index] = true;
}
}
template <typename T>
void multiply_scalar(FieldProps::FieldData<T>& field_data, T value, const std::vector<Box::cell_index>& index_list) {
for (const auto& cell_index : index_list) {
if (field_data.assigned[cell_index.active_index])
field_data.data[cell_index.active_index] *= value;
}
}
template <typename T>
void add_scalar(FieldProps::FieldData<T>& field_data, T value, const std::vector<Box::cell_index>& index_list) {
for (const auto& cell_index : index_list) {
if (field_data.assigned[cell_index.active_index])
field_data.data[cell_index.active_index] += value;
}
}
template <typename T>
void min_value(FieldProps::FieldData<T>& field_data, T min_value, const std::vector<Box::cell_index>& index_list) {
for (const auto& cell_index : index_list) {
if (field_data.assigned[cell_index.active_index]) {
T value = field_data.data[cell_index.active_index];
field_data.data[cell_index.active_index] = std::max(value, min_value);
}
}
}
template <typename T>
void max_value(FieldProps::FieldData<T>& field_data, T max_value, const std::vector<Box::cell_index>& index_list) {
for (const auto& cell_index : index_list) {
if (field_data.assigned[cell_index.active_index]) {
T value = field_data.data[cell_index.active_index];
field_data.data[cell_index.active_index] = std::min(value, max_value);
}
}
}
void setKeywordBox( const DeckRecord& deckRecord, BoxManager& boxManager) {
const auto& I1Item = deckRecord.getItem("I1");
const auto& I2Item = deckRecord.getItem("I2");
const auto& J1Item = deckRecord.getItem("J1");
const auto& J2Item = deckRecord.getItem("J2");
const auto& K1Item = deckRecord.getItem("K1");
const auto& K2Item = deckRecord.getItem("K2");
const auto& active_box = boxManager.getActiveBox();
const int i1 = I1Item.defaultApplied(0) ? active_box.I1() : I1Item.get<int>(0) - 1;
const int i2 = I2Item.defaultApplied(0) ? active_box.I2() : I2Item.get<int>(0) - 1;
const int j1 = J1Item.defaultApplied(0) ? active_box.J1() : J1Item.get<int>(0) - 1;
const int j2 = J2Item.defaultApplied(0) ? active_box.J2() : J2Item.get<int>(0) - 1;
const int k1 = K1Item.defaultApplied(0) ? active_box.K1() : K1Item.get<int>(0) - 1;
const int k2 = K2Item.defaultApplied(0) ? active_box.K2() : K2Item.get<int>(0) - 1;
boxManager.setKeywordBox( i1,i2,j1,j2,k1,k2 );
}
void handle_box_keyword(const EclipseGrid& grid, const DeckKeyword& deckKeyword, BoxManager& boxManager) {
if (deckKeyword.name() == ParserKeywords::BOX::keywordName) {
const auto& record = deckKeyword.getRecord(0);
const auto& I1Item = record.getItem("I1");
const auto& I2Item = record.getItem("I2");
const auto& J1Item = record.getItem("J1");
const auto& J2Item = record.getItem("J2");
const auto& K1Item = record.getItem("K1");
const auto& K2Item = record.getItem("K2");
const int i1 = I1Item.defaultApplied(0) ? 0 : I1Item.get<int>(0) - 1;
const int i2 = I2Item.defaultApplied(0) ? grid.getNX() : I2Item.get<int>(0) - 1;
const int j1 = J1Item.defaultApplied(0) ? 0 : J1Item.get<int>(0) - 1;
const int j2 = J2Item.defaultApplied(0) ? grid.getNY() : J2Item.get<int>(0) - 1;
const int k1 = K1Item.defaultApplied(0) ? 0 : K1Item.get<int>(0) - 1;
const int k2 = K2Item.defaultApplied(0) ? grid.getNZ() : K2Item.get<int>(0) - 1;
boxManager.setInputBox( i1 , i2 , j1 , j2 , k1 , k2 );
} else if (deckKeyword.name() == ParserKeywords::ENDBOX::keywordName)
boxManager.endInputBox();
}
}
FieldProps::FieldProps(const Deck& deck, const EclipseGrid& grid_arg) :
unit_system(deck.getActiveUnitSystem()),
grid(std::addressof(grid_arg)),
active_size(grid_arg.getNumActive()),
actnum(grid_arg.getACTNUM()),
default_region(default_region_keyword(deck))
{
if (Section::hasGRID(deck))
this->scanGRIDSection(GRIDSection(deck));
if (Section::hasPROPS(deck))
this->scanPROPSSection(PROPSSection(deck));
if (Section::hasREGIONS(deck))
this->scanREGIONSSection(REGIONSSection(deck));
}
void FieldProps::reset_grid(const EclipseGrid& grid_arg) {
const auto& new_actnum = grid_arg.getACTNUM();
if (new_actnum == this->actnum)
return;
std::vector<bool> active_map(this->active_size, true);
std::size_t active_index = 0;
for (std::size_t g = 0; g < this->actnum.size(); g++) {
if (this->actnum[g] != 0) {
if (new_actnum[g] == 0)
active_map[active_index] = false;
active_index += 1;
} else {
if (new_actnum[g] != 0)
throw std::logic_error("It is not possible to activate cells");
}
}
for (auto& data : this->double_data)
data.second.compress(active_map);
for (auto& data : this->int_data)
data.second.compress(active_map);
this->grid = std::addressof(grid_arg);
this->actnum = new_actnum;
}
template <>
bool FieldProps::supported<double>(const std::string& keyword) {
if (keywords::GRID::double_keywords.count(keyword) != 0)
return true;
if (keywords::EDIT::double_keywords.count(keyword) != 0)
return true;
if (keywords::PROPS::double_keywords.count(keyword) != 0)
return true;
if (keywords::SOLUTION::double_keywords.count(keyword) != 0)
return true;
return false;
}
template <>
bool FieldProps::supported<int>(const std::string& keyword) {
if (keywords::REGIONS::int_keywords.count(keyword) != 0)
return true;
if (keywords::GRID::int_keywords.count(keyword) != 0)
return true;
if (keywords::SCHEDULE::int_keywords.count(keyword) != 0)
return true;
return false;
}
template <>
FieldProps::FieldData<double>& FieldProps::get(const std::string& keyword) {
auto iter = this->double_data.find(keyword);
if (iter != this->double_data.end())
return iter->second;
if (FieldProps::supported<double>(keyword)) {
this->double_data[keyword] = FieldData<double>(this->grid->getNumActive());
auto init_iter = keywords::double_scalar_init.find(keyword);
if (init_iter != keywords::double_scalar_init.end())
this->double_data[keyword].assign(init_iter->second);
return this->double_data[keyword];
} else
throw std::out_of_range("Double keyword: " + keyword + " is not supported");
}
template <>
FieldProps::FieldData<int>& FieldProps::get(const std::string& keyword) {
auto iter = this->int_data.find(keyword);
if (iter != this->int_data.end())
return iter->second;
if (FieldProps::supported<int>(keyword)) {
this->int_data[keyword] = FieldData<int>(this->grid->getNumActive());
return this->int_data[keyword];
} else
throw std::out_of_range("Integer keyword " + keyword + " is not supported");
}
template <>
bool FieldProps::has<double>(const std::string& keyword) const {
return (this->double_data.count(keyword) != 0);
}
template <>
bool FieldProps::has<int>(const std::string& keyword) const {
return (this->int_data.count(keyword) != 0);
}
template <>
void FieldProps::erase<int>(const std::string& keyword) {
this->int_data.erase(keyword);
}
template <>
void FieldProps::erase<double>(const std::string& keyword) {
this->double_data.erase(keyword);
}
double FieldProps::getSIValue(const std::string& keyword, double raw_value) const {
const auto& iter = keywords::unit_string.find(keyword);
if (iter == keywords::unit_string.end())
throw std::logic_error("Trying to look up dimension string for keyword: " + keyword);
const auto& dim_string = iter->second;
const auto& dim = this->unit_system.parse( dim_string );
return dim.convertRawToSi(raw_value);
}
void FieldProps::scanGRIDSection(const GRIDSection& grid_section) {
BoxManager box_manager(*this->grid);
for (const auto& keyword : grid_section) {
const std::string& name = keyword.name();
if (keywords::GRID::double_keywords.count(name) == 1)
this->handle_grid_section_double_keyword(keyword, box_manager);
if (keywords::GRID::int_keywords.count(name) == 1)
this->handle_int_keyword(keyword, box_manager);
else if (keywords::oper_keywords.count(name) == 1)
this->handle_scalar_operation(keyword, box_manager);
else if (keywords::box_keywords.count(name) == 1)
handle_box_keyword(*this->grid, keyword, box_manager);
else if (name == ParserKeywords::COPY::keywordName)
handle_COPY(keyword, box_manager);
box_manager.endKeyword();
}
}
void FieldProps::scanPROPSSection(const PROPSSection& props_section) {
BoxManager box_manager(*this->grid);
for (const auto& keyword : props_section) {
const std::string& name = keyword.name();
if (keywords::PROPS::double_keywords.count(name) == 1)
this->handle_props_section_double_keyword(keyword, box_manager);
else if (keywords::oper_keywords.count(name) == 1)
this->handle_scalar_operation(keyword, box_manager);
else if (keywords::box_keywords.count(name) == 1)
handle_box_keyword(*this->grid, keyword, box_manager);
else if (name == ParserKeywords::COPY::keywordName)
handle_COPY(keyword, box_manager);
box_manager.endKeyword();
}
}
void FieldProps::scanREGIONSSection(const REGIONSSection& regions_section) {
BoxManager box_manager(*this->grid);
for (const auto& keyword : regions_section) {
const std::string& name = keyword.name();
if (keywords::REGIONS::int_keywords.count(name) == 1)
this->handle_int_keyword(keyword, box_manager);
else if (keywords::oper_keywords.count(name) == 1)
this->handle_scalar_operation(keyword, box_manager);
else if (keywords::box_keywords.count(name) == 1)
handle_box_keyword(*this->grid, keyword, box_manager);
else if (name == ParserKeywords::COPY::keywordName)
handle_COPY(keyword, box_manager);
box_manager.endKeyword();
}
}
void FieldProps::handle_int_keyword(const DeckKeyword& keyword, const BoxManager& box_manager) {
auto& field_data = this->get<int>(keyword.name());
const auto& deck_data = keyword.getIntData();
assign_deck(keyword, field_data, deck_data, box_manager.getActiveBox());
}
void FieldProps::handle_props_section_double_keyword(const DeckKeyword& keyword, const BoxManager& box_manager) {
auto& field_data = this->get<double>(keyword.name());
const auto& deck_data = keyword.getSIDoubleData();
assign_deck(keyword, field_data, deck_data, box_manager.getActiveBox());
}
void FieldProps::handle_grid_section_double_keyword(const DeckKeyword& keyword, const BoxManager& box_manager) {
auto& field_data = this->get<double>(keyword.name());
const auto& deck_data = keyword.getSIDoubleData();
assign_deck(keyword, field_data, deck_data, box_manager.getActiveBox());
if (field_data.valid())
return;
if (keywords::GRID::top_keywords.count(keyword.name()) == 1)
distribute_toplayer(*this->grid, field_data, deck_data, box_manager.getActiveBox());
}
template <typename T>
void FieldProps::handle_scalar_operation(const std::string& keyword, FieldData<T>& data, T scalar_value, const Box& box) {
if (keyword == ParserKeywords::EQUALS::keywordName)
assign_scalar(data, scalar_value, box.index_list());
else if (keyword == ParserKeywords::MULTIPLY::keywordName)
multiply_scalar(data, scalar_value, box.index_list());
else if (keyword == ParserKeywords::ADD::keywordName)
add_scalar(data, scalar_value, box.index_list());
else if (keyword == ParserKeywords::MINVALUE::keywordName)
min_value(data, scalar_value, box.index_list());
else if (keyword == ParserKeywords::MAXVALUE::keywordName)
max_value(data, scalar_value, box.index_list());
}
void FieldProps::handle_scalar_operation(const DeckKeyword& keyword, BoxManager& box_manager) {
for (const auto& record : keyword) {
setKeywordBox(record, box_manager);
const std::string& target_kw = record.getItem(0).get<std::string>(0);
if (FieldProps::supported<double>(target_kw)) {
double scalar_value = record.getItem(1).get<double>(0);
if (keyword.name() != ParserKeywords::MULTIPLY::keywordName)
scalar_value = this->getSIValue(target_kw, scalar_value);
auto& field_data = this->get<double>(target_kw);
FieldProps::handle_scalar_operation(keyword.name(), field_data, scalar_value, box_manager.getActiveBox());
continue;
}
if (FieldProps::supported<int>(target_kw)) {
int scalar_value = static_cast<int>(record.getItem(1).get<double>(0));
auto& field_data = this->get<int>(target_kw);
FieldProps::handle_scalar_operation(keyword.name(), field_data, scalar_value, box_manager.getActiveBox());
continue;
}
//throw std::out_of_range("The keyword: " + target_kw + " is not supported");
}
}
void FieldProps::handle_COPY(const DeckKeyword& keyword, BoxManager& box_manager) {
for (const auto& record : keyword) {
setKeywordBox(record, box_manager);
const std::string& src_kw = record.getItem(0).get<std::string>(0);
const std::string& target_kw = record.getItem(1).get<std::string>(0);
if (FieldProps::supported<double>(src_kw)) {
const auto * src_data = this->try_get<double>(src_kw);
if (!src_data)
throw std::invalid_argument("Tried to copy from not fully initialized keword: " + src_kw);
auto& target_data = this->get<double>(target_kw);
target_data.assign(*src_data, box_manager.getActiveBox());
continue;
}
if (FieldProps::supported<int>(src_kw)) {
const auto * src_data = this->try_get<int>(src_kw);
if (!src_data)
throw std::invalid_argument("Tried to copy from not fully initialized keword: " + src_kw);
auto& target_data = this->get<int>(target_kw);
target_data.assign(*src_data, box_manager.getActiveBox());
continue;
}
}
}
}

View File

@ -0,0 +1,168 @@
/*
Copyright 2019 Equinor ASA.
This file is part of the Open Porous Media project (OPM).
OPM is free software: you can redistribute it and/or modify it under the terms
of the GNU General Public License as published by the Free Software
Foundation, either version 3 of the License, or (at your option) any later
version.
OPM is distributed in the hope that it will be useful, but WITHOUT ANY
WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR
A PARTICULAR PURPOSE. See the GNU General Public License for more details.
You should have received a copy of the GNU General Public License along with
OPM. If not, see <http://www.gnu.org/licenses/>.
*/
#ifndef FIELDPROPS_HPP
#define FIELDPROPS_HPP
#include <string>
#include <unordered_set>
#include <opm/parser/eclipse/Deck/Section.hpp>
#include <opm/parser/eclipse/Units/UnitSystem.hpp>
#include <opm/parser/eclipse/EclipseState/Grid/BoxManager.hpp>
namespace Opm {
class Deck;
class EclipseGrid;
class FieldProps {
public:
template<typename T>
struct FieldData {
std::vector<T> data;
std::vector<bool> assigned;
FieldData() = default;
FieldData(std::size_t active_size) :
data(std::vector<T>(active_size)),
assigned(std::vector<bool>(active_size, false))
{
}
std::size_t size() const {
return this->data.size();
}
bool valid() const {
const auto& it = std::find(this->assigned.begin(), this->assigned.end(), false);
if (it == this->assigned.end())
return true;
return false;
}
void compress(const std::vector<bool>& active_map) {
std::size_t shift = 0;
for (std::size_t g = 0; g < active_map.size(); g++) {
if (active_map[g] && shift > 0) {
this->data[g - shift] = this->data[g];
this->assigned[g - shift] = this->assigned[g];
continue;
}
if (!active_map[g])
shift += 1;
}
this->data.resize(this->data.size() - shift);
this->assigned.resize(this->assigned.size() - shift);
}
void assign(T value) {
std::fill(this->data.begin(), this->data.end(), value);
std::fill(this->assigned.begin(), this->assigned.end(), true);
}
void assign(const FieldData<T>& src, const Box& box) {
for (const auto& ci : box.index_list()) {
if (src.assigned[ci.active_index]) {
this->data[ci.active_index] = src.data[ci.active_index];
this->assigned[ci.active_index] = true;
}
}
}
};
FieldProps(const Deck& deck, const EclipseGrid& grid);
void reset_grid(const EclipseGrid& grid);
template <typename T>
FieldData<T>& get(const std::string& keyword);
template <typename T>
static bool supported(const std::string& keyword);
template <typename T>
bool has(const std::string& keyword) const;
template <typename T>
const FieldData<T>* try_get(const std::string& keyword) {
const FieldData<T> * field_data;
try {
field_data = std::addressof(this->get<T>(keyword));
} catch (const std::out_of_range&) {
return nullptr;
}
if (field_data->valid())
return field_data;
this->erase<T>(keyword);
return nullptr;
}
template <typename T>
std::vector<T> global_copy(const std::vector<T>& data) const {
std::vector<T> global_data(this->grid->getCartesianSize());
std::size_t i = 0;
for (std::size_t g = 0; g < this->grid->getCartesianSize(); g++) {
if (this->grid->cellActive(g)) {
global_data[g] = data[i];
i++;
}
}
return global_data;
}
private:
void scanGRIDSection(const GRIDSection& grid_section);
void scanPROPSSection(const PROPSSection& props_section);
void scanREGIONSSection(const REGIONSSection& regions_section);
double getSIValue(const std::string& keyword, double raw_value) const;
template <typename T>
void erase(const std::string& keyword);
template <typename T>
static void handle_scalar_operation(const std::string& keyword, FieldData<T>& data, T scalar_value, const Box& box);
void handle_scalar_operation(const DeckKeyword& keyword, BoxManager& box_manager);
void handle_props_section_double_keyword(const DeckKeyword& keyword, const BoxManager& box_manager);
void handle_grid_section_double_keyword(const DeckKeyword& keyword, const BoxManager& box_manager);
void handle_int_keyword(const DeckKeyword& keyword, const BoxManager& box_manager);
void handle_COPY(const DeckKeyword& keyword, BoxManager& box_manager);
const UnitSystem unit_system;
const EclipseGrid* grid; // A reseatable pointer to const.
std::size_t active_size;
std::vector<int> actnum;
const std::string default_region;
std::unordered_map<std::string, FieldData<int>> int_data;
std::unordered_map<std::string, FieldData<double>> double_data;
};
}
#endif

View File

@ -0,0 +1,85 @@
/*
Copyright 2019 Equinor ASA.
This file is part of the Open Porous Media project (OPM).
OPM is free software: you can redistribute it and/or modify it under the terms
of the GNU General Public License as published by the Free Software
Foundation, either version 3 of the License, or (at your option) any later
version.
OPM is distributed in the hope that it will be useful, but WITHOUT ANY
WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR
A PARTICULAR PURPOSE. See the GNU General Public License for more details.
You should have received a copy of the GNU General Public License along with
OPM. If not, see <http://www.gnu.org/licenses/>.
*/
#include <opm/parser/eclipse/Deck/Deck.hpp>
#include <opm/parser/eclipse/EclipseState/Grid/EclipseGrid.hpp>
#include <opm/parser/eclipse/EclipseState/Grid/FieldPropsManager.hpp>
#include "FieldProps.hpp"
namespace Opm {
FieldPropsManager::FieldPropsManager(const Deck& deck, const EclipseGrid& grid_arg) :
fp(std::make_shared<FieldProps>(deck, grid_arg))
{}
void FieldPropsManager::reset_grid(const EclipseGrid& grid) {
this->fp->reset_grid(grid);
}
template <typename T>
const std::vector<T>& FieldPropsManager::get(const std::string& keyword) const {
const auto& data_ptr = this->try_get<T>(keyword);
if (data_ptr)
return *data_ptr;
if (!this->fp->has<T>(keyword))
throw std::out_of_range("No such keyword in deck: " + keyword);
throw std::logic_error("Internal error - should not be here");
}
template <typename T>
const std::vector<T>* FieldPropsManager::try_get(const std::string& keyword) const {
const auto& data_ptr = this->fp->try_get<T>(keyword);
if (data_ptr)
return std::addressof(data_ptr->data);
if (!FieldProps::supported<T>(keyword))
throw std::invalid_argument("The keyword: " + keyword + " is not supported");
return nullptr;
}
template <typename T>
std::vector<T> FieldPropsManager::get_global(const std::string& keyword) const {
const auto& data = this->get<T>(keyword);
return this->fp->global_copy(data);
}
template <typename T>
bool FieldPropsManager::supported(const std::string& keyword) {
return FieldProps::supported<T>(keyword);
}
template bool FieldPropsManager::supported<int>(const std::string&);
template bool FieldPropsManager::supported<double>(const std::string&);
template std::vector<int> FieldPropsManager::get_global(const std::string& keyword) const;
template std::vector<double> FieldPropsManager::get_global(const std::string& keyword) const;
template const std::vector<int>& FieldPropsManager::get(const std::string& keyword) const;
template const std::vector<double>& FieldPropsManager::get(const std::string& keyword) const;
template const std::vector<int>* FieldPropsManager::try_get(const std::string& keyword) const;
template const std::vector<double>* FieldPropsManager::try_get(const std::string& keyword) const;
}

View File

@ -31,6 +31,7 @@
#include <opm/parser/eclipse/EclipseState/Eclipse3DProperties.hpp>
#include <opm/parser/eclipse/EclipseState/Grid/EclipseGrid.hpp>
#include <opm/parser/eclipse/EclipseState/Grid/FieldPropsManager.hpp>
#include <opm/parser/eclipse/EclipseState/Tables/TableManager.hpp>
#include <opm/parser/eclipse/Parser/Parser.hpp>
@ -263,12 +264,14 @@ struct Setup
Opm::TableManager tablemanager;
Opm::EclipseGrid grid;
Opm::Eclipse3DProperties props;
Opm::FieldPropsManager fp;
explicit Setup(Opm::Deck&& deckArg) :
deck(std::move( deckArg ) ),
tablemanager(deck),
grid(deck),
props(deck, tablemanager, grid)
props(deck, tablemanager, grid),
fp(deck, grid)
{
}
};
@ -277,22 +280,26 @@ struct Setup
BOOST_AUTO_TEST_CASE(HasDeckProperty) {
Setup s(createDeck());
BOOST_CHECK(s.props.hasDeckIntGridProperty("SATNUM"));
BOOST_CHECK(s.fp.try_get<int>("SATNUM") != nullptr);
}
BOOST_AUTO_TEST_CASE(SupportsProperty) {
Setup s(createDeck());
std::vector<std::string> keywordList = {
// int props
"ACTNUM", "SATNUM", "IMBNUM", "PVTNUM", "EQLNUM", "ENDNUM", "FLUXNUM", "MULTNUM", "FIPNUM", "MISCNUM", "OPERNUM", "ROCKNUM",
// double props
"TEMPI", "MULTPV", "PERMX", "permy", "PERMZ", "SWATINIT", "THCONR", "NTG"
};
std::vector<std::string> int_keywords = {"SATNUM", "IMBNUM", "PVTNUM", "EQLNUM", "ENDNUM", "FLUXNUM", "MULTNUM", "FIPNUM", "MISCNUM", "OPERNUM", "ROCKNUM"};
std::vector<std::string> double_keywords = {"TEMPI", "MULTPV", "PERMX", "PERMY", "PERMZ", "SWATINIT", "THCONR", "NTG"};
for (auto keyword : keywordList)
for (auto keyword : int_keywords) {
BOOST_CHECK(s.props.supportsGridProperty(keyword));
BOOST_CHECK(s.fp.supported<int>(keyword));
}
for (auto keyword : double_keywords) {
BOOST_CHECK(s.props.supportsGridProperty(keyword));
BOOST_CHECK(s.fp.supported<double>(keyword));
}
}
BOOST_AUTO_TEST_CASE(DefaultRegionFluxnum) {
Setup s(createDeck());
BOOST_CHECK_EQUAL(s.props.getDefaultRegionKeyword(), "FLUXNUM");
@ -305,6 +312,8 @@ BOOST_AUTO_TEST_CASE(UnsupportedKeywordsThrows) {
BOOST_CHECK_THROW(s.props.getIntGridProperty("NONO"), std::logic_error);
BOOST_CHECK_THROW(s.props.getDoubleGridProperty("NONO"), std::logic_error);
BOOST_CHECK_THROW(s.fp.get<double>("NONO"), std::invalid_argument);
BOOST_CHECK_THROW(s.fp.get<int>("NONO"), std::invalid_argument);
BOOST_CHECK_NO_THROW(s.props.hasDeckIntGridProperty("FluxNUM"));
BOOST_CHECK_NO_THROW(s.props.supportsGridProperty("NONO"));
@ -312,12 +321,22 @@ BOOST_AUTO_TEST_CASE(UnsupportedKeywordsThrows) {
BOOST_AUTO_TEST_CASE(IntGridProperty) {
Setup s(createDeck());
int cnt = 0;
for (auto x : s.props.getIntGridProperty("SaTNuM").getData()) {
BOOST_CHECK_EQUAL(x, 2);
cnt++;
{
int cnt = 0;
for (auto x : s.props.getIntGridProperty("SATNUM").getData()) {
BOOST_CHECK_EQUAL(x, 2);
cnt++;
}
BOOST_CHECK_EQUAL(cnt, 1000);
}
{
int cnt = 0;
for (auto x : s.fp.get_global<int>("SATNUM")) {
BOOST_CHECK_EQUAL(x, 2);
cnt++;
}
BOOST_CHECK_EQUAL(cnt, 1000);
}
BOOST_CHECK_EQUAL(cnt, 1000);
}
BOOST_AUTO_TEST_CASE(AddregIntSetCorrectly) {

View File

@ -675,7 +675,7 @@ BOOST_AUTO_TEST_CASE(TestBox) {
"1 1 2 3 /\n";
Parser parser;
auto deck = parser.parseString(regionData);
EclipseState state(deck);
EclipseState state(deck);
}

View File

@ -0,0 +1,135 @@
/*
Copyright 2019 Equinor ASA.
This file is part of the Open Porous Media project (OPM).
OPM is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation, either version 3 of the License, or
(at your option) any later version.
OPM is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with OPM. If not, see <http://www.gnu.org/licenses/>.
*/
#include <stdexcept>
#include <iostream>
#include <memory>
#define BOOST_TEST_MODULE FieldPropsTests
#include <boost/filesystem.hpp>
#include <boost/test/unit_test.hpp>
#include <boost/date_time/posix_time/posix_time.hpp>
#include <opm/parser/eclipse/Parser/Parser.hpp>
#include <opm/parser/eclipse/Units/UnitSystem.hpp>
#include <opm/parser/eclipse/Deck/Section.hpp>
#include <opm/parser/eclipse/Deck/Deck.hpp>
#include <opm/parser/eclipse/Deck/DeckKeyword.hpp>
#include <opm/parser/eclipse/EclipseState/Grid/FieldPropsManager.hpp>
#include <opm/parser/eclipse/EclipseState/Grid/EclipseGrid.hpp>
using namespace Opm;
BOOST_AUTO_TEST_CASE(CreateFieldProps) {
EclipseGrid grid(10,10,10);
Deck deck;
FieldPropsManager fpm(deck, grid);
BOOST_CHECK(!fpm.try_get<int>("SATNUM"));
BOOST_CHECK(!fpm.try_get<double>("PORO"));
BOOST_CHECK(!fpm.try_get<int>("SATNUM"));
BOOST_CHECK(!fpm.try_get<double>("PORO"));
BOOST_CHECK_THROW(fpm.get<double>("PORO"), std::out_of_range);
BOOST_CHECK_THROW(fpm.get<int>("SATNUM"), std::out_of_range);
BOOST_CHECK_THROW(fpm.get_global<double>("PORO"), std::out_of_range);
BOOST_CHECK_THROW(fpm.get_global<int>("SATNUM"), std::out_of_range);
BOOST_CHECK_THROW(fpm.try_get<int>("NOT_SUPPORTED"), std::invalid_argument);
BOOST_CHECK_THROW(fpm.try_get<double>("NOT_SUPPORTED"), std::invalid_argument);
BOOST_CHECK_THROW(fpm.get<int>("NOT_SUPPORTED"), std::invalid_argument);
BOOST_CHECK_THROW(fpm.get<double>("NOT_SUPPORTED"), std::invalid_argument);
BOOST_CHECK_THROW(fpm.get_global<double>("NO1"), std::invalid_argument);
BOOST_CHECK_THROW(fpm.get_global<int>("NO2"), std::invalid_argument);
}
BOOST_AUTO_TEST_CASE(CreateFieldProps2) {
std::string deck_string = R"(
GRID
PORO
1000*0.10 /
)";
std::vector<int> actnum(1000, 1);
for (std::size_t i=0; i< 1000; i += 2)
actnum[i] = 0;
EclipseGrid grid(EclipseGrid(10,10,10), actnum);
Deck deck = Parser{}.parseString(deck_string);
FieldPropsManager fpm(deck, grid);
const auto& poro1 = fpm.get<double>("PORO");
BOOST_CHECK_EQUAL(poro1.size(), grid.getNumActive());
const auto& poro2 = fpm.try_get<double>("PORO");
BOOST_CHECK(poro1 == *poro2);
}
BOOST_AUTO_TEST_CASE(INVALID_COPY) {
std::string deck_string = R"(
GRID
COPY
PERMX PERMY /
/
)";
EclipseGrid grid(EclipseGrid(10,10,10));
Deck deck = Parser{}.parseString(deck_string);
BOOST_CHECK_THROW( FieldPropsManager(deck, grid), std::invalid_argument);
}
BOOST_AUTO_TEST_CASE(GRID_RESET) {
std::string deck_string = R"(
REGIONS
SATNUM
0 1 2 3 4 5 6 7 8
/
)";
std::vector<int> actnum1 = {1,1,1,0,0,0,1,1,1};
EclipseGrid grid(3,1,3); grid.resetACTNUM(actnum1);
Deck deck = Parser{}.parseString(deck_string);
FieldPropsManager fpm(deck, grid);
const auto& s1 = fpm.get<int>("SATNUM");
BOOST_CHECK_EQUAL(s1.size(), 6);
BOOST_CHECK_EQUAL(s1[0], 0);
BOOST_CHECK_EQUAL(s1[1], 1);
BOOST_CHECK_EQUAL(s1[2], 2);
BOOST_CHECK_EQUAL(s1[3], 6);
BOOST_CHECK_EQUAL(s1[4], 7);
BOOST_CHECK_EQUAL(s1[5], 8);
std::vector<int> actnum2 = {1,0,1,0,0,0,1,0,1};
grid.resetACTNUM(actnum2);
fpm.reset_grid(grid);
BOOST_CHECK_EQUAL(s1.size(), 4);
BOOST_CHECK_EQUAL(s1[0], 0);
BOOST_CHECK_EQUAL(s1[1], 2);
BOOST_CHECK_EQUAL(s1[2], 6);
BOOST_CHECK_EQUAL(s1[3], 8);
grid.resetACTNUM(actnum1);
BOOST_CHECK_THROW(fpm.reset_grid(grid), std::logic_error);
}