From 7628d7e13b0365a9e5566de87f63f509507a69aa Mon Sep 17 00:00:00 2001 From: Kai Bao Date: Thu, 28 Jan 2021 21:13:49 +0100 Subject: [PATCH] isolating the aquifer cells from the rest of the reservoir by setting the transmissiblity associated with aquifer cells to be zero. --- .../EclipseState/Aquifer/AquiferConfig.hpp | 3 ++ .../NumericalAquifer/NumericalAquifers.hpp | 2 + .../SingleNumericalAquifer.hpp | 6 +++ .../eclipse/EclipseState/EclipseState.hpp | 4 +- .../EclipseState/Grid/FieldPropsManager.hpp | 4 ++ .../EclipseState/Aquifer/AquiferConfig.cpp | 8 ++++ .../NumericalAquifer/NumericalAquifers.cpp | 11 ++++++ .../SingleNumericalAquifer.cpp | 31 +++++++++++++++ .../eclipse/EclipseState/EclipseState.cpp | 8 +++- .../eclipse/EclipseState/Grid/FieldProps.cpp | 38 +++++++++++++++++++ .../eclipse/EclipseState/Grid/FieldProps.hpp | 6 +++ .../EclipseState/Grid/FieldPropsManager.cpp | 5 +++ 12 files changed, 122 insertions(+), 4 deletions(-) diff --git a/opm/parser/eclipse/EclipseState/Aquifer/AquiferConfig.hpp b/opm/parser/eclipse/EclipseState/Aquifer/AquiferConfig.hpp index ba1ead919..1ea0c8b0f 100644 --- a/opm/parser/eclipse/EclipseState/Aquifer/AquiferConfig.hpp +++ b/opm/parser/eclipse/EclipseState/Aquifer/AquiferConfig.hpp @@ -48,6 +48,9 @@ public: bool operator==(const AquiferConfig& other); bool hasAquifer(const int aquID) const; + bool hasNumericalAquifer() const; + const NumericalAquifers& numericalAquifers() const; + template void serializeOp(Serializer& serializer) { diff --git a/opm/parser/eclipse/EclipseState/Aquifer/NumericalAquifer/NumericalAquifers.hpp b/opm/parser/eclipse/EclipseState/Aquifer/NumericalAquifer/NumericalAquifers.hpp index 88fa3a018..6b778838d 100644 --- a/opm/parser/eclipse/EclipseState/Aquifer/NumericalAquifer/NumericalAquifers.hpp +++ b/opm/parser/eclipse/EclipseState/Aquifer/NumericalAquifer/NumericalAquifers.hpp @@ -40,6 +40,8 @@ namespace Opm { const SingleNumericalAquifer& getAquifer(size_t aquifer_id) const; bool operator==(const NumericalAquifers& other) const; + std::array, 3> transToRemove(const EclipseGrid& grid) const; + std::unordered_map allAquiferCells() const; static NumericalAquifers serializeObject(); diff --git a/opm/parser/eclipse/EclipseState/Aquifer/NumericalAquifer/SingleNumericalAquifer.hpp b/opm/parser/eclipse/EclipseState/Aquifer/NumericalAquifer/SingleNumericalAquifer.hpp index 95714fa01..bbe77a210 100644 --- a/opm/parser/eclipse/EclipseState/Aquifer/NumericalAquifer/SingleNumericalAquifer.hpp +++ b/opm/parser/eclipse/EclipseState/Aquifer/NumericalAquifer/SingleNumericalAquifer.hpp @@ -21,6 +21,7 @@ #define OPM_SINGLENUMERICALAQUIFER_HPP #include +#include #include #include @@ -41,6 +42,11 @@ namespace Opm { size_t numConnections() const; const NumericalAquiferCell* getCellPrt(size_t index) const; + // we remove the connection around the aquifer cells to isolate aquifer cells + // from the other part of the reservoir + // the removing of the connection is done by make transmissiblities to be zero + std::array, 3> transToRemove(const EclipseGrid& grid) const; + bool operator==(const SingleNumericalAquifer& other) const; template diff --git a/opm/parser/eclipse/EclipseState/EclipseState.hpp b/opm/parser/eclipse/EclipseState/EclipseState.hpp index 0779a958e..eae4b9c9b 100644 --- a/opm/parser/eclipse/EclipseState/EclipseState.hpp +++ b/opm/parser/eclipse/EclipseState/EclipseState.hpp @@ -122,11 +122,11 @@ namespace Opm { m_deckUnitSystem.serializeOp(serializer); m_inputNnc.serializeOp(serializer); m_gridDims.serializeOp(serializer); + aquifer_config.serializeOp(serializer); m_simulationConfig.serializeOp(serializer); m_transMult.serializeOp(serializer); m_faults.serializeOp(serializer); serializer(m_title); - aquifer_config.serializeOp(serializer); tracer_config.serializeOp(serializer); } @@ -149,12 +149,12 @@ namespace Opm { NNC m_inputNnc; GridDims m_gridDims; FieldPropsManager field_props; + AquiferConfig aquifer_config; SimulationConfig m_simulationConfig; TransMult m_transMult; FaultCollection m_faults; std::string m_title; - AquiferConfig aquifer_config; TracerConfig tracer_config; }; } diff --git a/opm/parser/eclipse/EclipseState/Grid/FieldPropsManager.hpp b/opm/parser/eclipse/EclipseState/Grid/FieldPropsManager.hpp index dc269319f..c53872074 100644 --- a/opm/parser/eclipse/EclipseState/Grid/FieldPropsManager.hpp +++ b/opm/parser/eclipse/EclipseState/Grid/FieldPropsManager.hpp @@ -32,6 +32,7 @@ class Deck; class FieldProps; class Phases; class TableManager; +class NumericalAquifers; class FieldPropsManager { @@ -217,6 +218,9 @@ public: */ virtual void apply_tran(const std::string& keyword, std::vector& tran_data) const; + void applyNumericalAquifer(const NumericalAquifers& aquifers); + + /* When using MPI the FieldPropsManager is typically only assembled on the root node and then distributed to the other nodes afterwards. These diff --git a/src/opm/parser/eclipse/EclipseState/Aquifer/AquiferConfig.cpp b/src/opm/parser/eclipse/EclipseState/Aquifer/AquiferConfig.cpp index 0769b77c6..f35d789ea 100644 --- a/src/opm/parser/eclipse/EclipseState/Aquifer/AquiferConfig.cpp +++ b/src/opm/parser/eclipse/EclipseState/Aquifer/AquiferConfig.cpp @@ -80,4 +80,12 @@ bool AquiferConfig::hasAquifer(const int aquID) const { numerical_aquifers.hasAquifer(aquID); } +bool AquiferConfig::hasNumericalAquifer() const { + return this->numerical_aquifers.numAquifer(); +} + +const NumericalAquifers& AquiferConfig::numericalAquifers() const { + return this->numerical_aquifers; +} + } diff --git a/src/opm/parser/eclipse/EclipseState/Aquifer/NumericalAquifer/NumericalAquifers.cpp b/src/opm/parser/eclipse/EclipseState/Aquifer/NumericalAquifer/NumericalAquifers.cpp index 4c76ed574..1d18e1495 100644 --- a/src/opm/parser/eclipse/EclipseState/Aquifer/NumericalAquifer/NumericalAquifers.cpp +++ b/src/opm/parser/eclipse/EclipseState/Aquifer/NumericalAquifer/NumericalAquifers.cpp @@ -145,4 +145,15 @@ namespace Opm { } return cells; } + + std::array, 3> NumericalAquifers::transToRemove(const EclipseGrid& grid) const { + std::array, 3> trans; + for (const auto& [id, aquifer] : this->m_aquifers) { + auto trans_aquifer = aquifer.transToRemove(grid); + for (size_t i = 0; i < 3; ++i) { + trans[i].merge(trans_aquifer[i]); + } + } + return trans; + } } \ No newline at end of file diff --git a/src/opm/parser/eclipse/EclipseState/Aquifer/NumericalAquifer/SingleNumericalAquifer.cpp b/src/opm/parser/eclipse/EclipseState/Aquifer/NumericalAquifer/SingleNumericalAquifer.cpp index 6f17e0aff..671389dc8 100644 --- a/src/opm/parser/eclipse/EclipseState/Aquifer/NumericalAquifer/SingleNumericalAquifer.cpp +++ b/src/opm/parser/eclipse/EclipseState/Aquifer/NumericalAquifer/SingleNumericalAquifer.cpp @@ -17,9 +17,12 @@ along with OPM. If not, see . */ +#include + #include #include #include +#include "../AquiferHelpers.hpp" namespace Opm { SingleNumericalAquifer::SingleNumericalAquifer(const size_t aqu_id) @@ -52,4 +55,32 @@ namespace Opm { size_t SingleNumericalAquifer::numConnections() const { return this->connections_.size(); } + + std::array, 3> SingleNumericalAquifer::transToRemove(const EclipseGrid& grid) const { + std::array, 3> trans; + for (const auto& cell : this->cells_) { + const size_t i = cell.I; + const size_t j = cell.J; + const size_t k = cell.K; + if (AquiferHelpers::neighborCellInsideReservoirAndActive(grid, i, j, k, FaceDir::XPlus)) { + trans[0].insert(cell.global_index); + } + if (AquiferHelpers::neighborCellInsideReservoirAndActive(grid, i, j, k, FaceDir::XMinus)) { + trans[0].insert(grid.getGlobalIndex(i-1, j, k)); + } + if (AquiferHelpers::neighborCellInsideReservoirAndActive(grid, i, j, k, FaceDir::YPlus)) { + trans[1].insert(cell.global_index); + } + if (AquiferHelpers::neighborCellInsideReservoirAndActive(grid, i, j, k, FaceDir::YMinus)) { + trans[1].insert(grid.getGlobalIndex(i, j-1, k)); + } + if (AquiferHelpers::neighborCellInsideReservoirAndActive(grid, i, j, k, FaceDir::ZPlus)) { + trans[2].insert(cell.global_index); + } + if (AquiferHelpers::neighborCellInsideReservoirAndActive(grid, i, j, k, FaceDir::ZMinus)) { + trans[2].insert(grid.getGlobalIndex(i, j, k-1)); + } + } + return trans; + } } diff --git a/src/opm/parser/eclipse/EclipseState/EclipseState.cpp b/src/opm/parser/eclipse/EclipseState/EclipseState.cpp index 1b9e48e89..8585466c4 100644 --- a/src/opm/parser/eclipse/EclipseState/EclipseState.cpp +++ b/src/opm/parser/eclipse/EclipseState/EclipseState.cpp @@ -61,16 +61,20 @@ namespace Opm { m_inputNnc( m_inputGrid, deck), m_gridDims( deck ), field_props( deck, m_runspec.phases(), m_inputGrid, m_tables), + aquifer_config(this->m_tables, this->m_inputGrid, deck, this->field_props), m_simulationConfig( m_eclipseConfig.getInitConfig().restartRequested(), deck, field_props), m_transMult( GridDims(deck), deck, field_props), tracer_config( m_deckUnitSystem, deck) { + if (this->aquifer().hasNumericalAquifer()) { + const auto& numerical_aquifer = this->aquifer().numericalAquifers(); + this->field_props.applyNumericalAquifer(numerical_aquifer); + } + m_inputGrid.resetACTNUM(this->field_props.actnum()); if( this->runspec().phases().size() < 3 ) OpmLog::info(fmt::format("Only {} fluid phases are enabled", this->runspec().phases().size() )); - this->aquifer_config = AquiferConfig(this->m_tables, this->m_inputGrid, deck, this->field_props); - if (deck.hasKeyword( "TITLE" )) { const auto& titleKeyword = deck.getKeyword( "TITLE" ); const auto& item = titleKeyword.getRecord( 0 ).getItem( 0 ); diff --git a/src/opm/parser/eclipse/EclipseState/Grid/FieldProps.cpp b/src/opm/parser/eclipse/EclipseState/Grid/FieldProps.cpp index 1da68a393..612f9c784 100644 --- a/src/opm/parser/eclipse/EclipseState/Grid/FieldProps.cpp +++ b/src/opm/parser/eclipse/EclipseState/Grid/FieldProps.cpp @@ -18,6 +18,9 @@ #include #include #include +#include +#include +#include #include @@ -39,6 +42,7 @@ #include #include #include +#include #include "FieldProps.hpp" #include "Operate.hpp" @@ -1211,6 +1215,40 @@ bool FieldProps::tran_active(const std::string& keyword) const { return calculator != this->tran.end() && calculator->second.size() > 0; } +void FieldProps::applyNumericalAquifers(const NumericalAquifers& numerical_aquifers) { + this->updateTransWithNumericalAquifer(numerical_aquifers); +} + +void FieldProps::updateTransWithNumericalAquifer(const NumericalAquifers& numerical_aquifers) { + const std::array, 3> trans_to_remove = numerical_aquifers.transToRemove(*(this->grid_ptr)); + std::array, 3> index_lists; + for (int i = 0; i < 3; ++i) { + size_t num = 0; + for (const auto& elem : trans_to_remove[i]) { + const size_t active_index = this->grid_ptr->activeIndex(elem); + index_lists[i].emplace_back(elem, active_index, num); + num++; + } + } + + const std::array trans_string {"TRANX", "TRANY", "TRANZ"}; + for (int i = 0; i < 3; ++i) { + const std::string& target_kw = trans_string[i]; + const std::vector& single_index_list = index_lists[i]; + auto tran_iter = this->tran.find(target_kw); + assert(tran_iter != this->tran.end()); + const std::string unique_name = tran_iter->second.next_name(); + const auto operation = Fieldprops::ScalarOperation::EQUAL; + tran_iter->second.add_action(operation, unique_name); + const auto kw_info = tran_iter->second.make_kw_info(operation); + auto& field_data = this->init_get(unique_name, kw_info); + // setting the transmissiblity to be zero to remove the connection between specific cells + FieldProps::apply(operation, field_data.data, field_data.value_status, 0.0, single_index_list); + // TODO: not sure when we need the following. If we need, we also need to make a global_index_list; + /* if (field_data.global_data) + FieldProps::apply(operation, *field_data.global_data, *field_data.global_value_status, scalar_value, box.global_index_list()); */ + } +} template std::vector FieldProps::defaulted(const std::string& keyword); diff --git a/src/opm/parser/eclipse/EclipseState/Grid/FieldProps.hpp b/src/opm/parser/eclipse/EclipseState/Grid/FieldProps.hpp index 84702f86d..b71887f04 100644 --- a/src/opm/parser/eclipse/EclipseState/Grid/FieldProps.hpp +++ b/src/opm/parser/eclipse/EclipseState/Grid/FieldProps.hpp @@ -41,6 +41,7 @@ namespace Opm { class Deck; class EclipseGrid; class TableManager; +class NumericalAquifers; namespace Fieldprops { @@ -360,6 +361,11 @@ public: FieldProps(const Deck& deck, const Phases& phases, const EclipseGrid& grid, const TableManager& table_arg); void reset_actnum(const std::vector& actnum); + void applyNumericalAquifers(const NumericalAquifers& numerical_aquifers); + // set the transmissiblities around the numerical aquifer cells to be zero, so we can isolate them + // from the other reservoir cells + void updateTransWithNumericalAquifer(const NumericalAquifers& numerical_aquifer); + const std::string& default_region() const; std::vector actnum(); diff --git a/src/opm/parser/eclipse/EclipseState/Grid/FieldPropsManager.cpp b/src/opm/parser/eclipse/EclipseState/Grid/FieldPropsManager.cpp index 132876878..226b54c4a 100644 --- a/src/opm/parser/eclipse/EclipseState/Grid/FieldPropsManager.cpp +++ b/src/opm/parser/eclipse/EclipseState/Grid/FieldPropsManager.cpp @@ -22,6 +22,7 @@ #include #include #include +#include #include "FieldProps.hpp" @@ -141,6 +142,10 @@ bool FieldPropsManager::tran_active(const std::string& keyword) const { return this->fp->tran_active(keyword); } +void FieldPropsManager::applyNumericalAquifer(const NumericalAquifers& aquifers) { + return this->fp->applyNumericalAquifers(aquifers); +} + template void apply_tran(const std::unordered_map& tran, const MapType& double_data,