Merge pull request #2246 from GitPaean/new_numerical_aquifer
numerical aquifers
This commit is contained in:
@@ -60,6 +60,10 @@ if(ENABLE_ECL_INPUT)
|
||||
src/opm/parser/eclipse/EclipseState/Aquifer/Aquifetp.cpp
|
||||
src/opm/parser/eclipse/EclipseState/Aquifer/Aquancon.cpp
|
||||
src/opm/parser/eclipse/EclipseState/Aquifer/AquiferHelpers.cpp
|
||||
src/opm/parser/eclipse/EclipseState/Aquifer/NumericalAquifer/NumericalAquiferCell.cpp
|
||||
src/opm/parser/eclipse/EclipseState/Aquifer/NumericalAquifer/NumericalAquiferConnection.cpp
|
||||
src/opm/parser/eclipse/EclipseState/Aquifer/NumericalAquifer/SingleNumericalAquifer.cpp
|
||||
src/opm/parser/eclipse/EclipseState/Aquifer/NumericalAquifer/NumericalAquifers.cpp
|
||||
src/opm/parser/eclipse/EclipseState/checkDeck.cpp
|
||||
src/opm/parser/eclipse/EclipseState/EclipseConfig.cpp
|
||||
src/opm/parser/eclipse/EclipseState/EclipseState.cpp
|
||||
@@ -702,6 +706,10 @@ if(ENABLE_ECL_INPUT)
|
||||
opm/parser/eclipse/EclipseState/Aquifer/AquiferConfig.hpp
|
||||
opm/parser/eclipse/EclipseState/Aquifer/AquiferCT.hpp
|
||||
opm/parser/eclipse/EclipseState/Aquifer/Aquifetp.hpp
|
||||
opm/parser/eclipse/EclipseState/Aquifer/NumericalAquifer/NumericalAquiferCell.hpp
|
||||
opm/parser/eclipse/EclipseState/Aquifer/NumericalAquifer/NumericalAquiferConnection.hpp
|
||||
opm/parser/eclipse/EclipseState/Aquifer/NumericalAquifer/SingleNumericalAquifer.hpp
|
||||
opm/parser/eclipse/EclipseState/Aquifer/NumericalAquifer/NumericalAquifers.hpp
|
||||
opm/parser/eclipse/EclipseState/Schedule/Action/ActionAST.hpp
|
||||
opm/parser/eclipse/EclipseState/Schedule/Action/ActionContext.hpp
|
||||
opm/parser/eclipse/EclipseState/Schedule/Action/ActionResult.hpp
|
||||
|
||||
@@ -23,17 +23,20 @@
|
||||
#include <opm/parser/eclipse/EclipseState/Aquifer/Aquancon.hpp>
|
||||
#include <opm/parser/eclipse/EclipseState/Aquifer/Aquifetp.hpp>
|
||||
#include <opm/parser/eclipse/EclipseState/Aquifer/AquiferCT.hpp>
|
||||
#include <opm/parser/eclipse/EclipseState/Aquifer/NumericalAquifer/NumericalAquifers.hpp>
|
||||
|
||||
namespace Opm {
|
||||
|
||||
class TableManager;
|
||||
class EclipseGrid;
|
||||
class Deck;
|
||||
class FieldPropsManager;
|
||||
|
||||
class AquiferConfig {
|
||||
public:
|
||||
AquiferConfig() = default;
|
||||
AquiferConfig(const TableManager& tables, const EclipseGrid& grid, const Deck& deck);
|
||||
AquiferConfig(const TableManager& tables, const EclipseGrid& grid,
|
||||
const Deck& deck, const FieldPropsManager& field_props);
|
||||
AquiferConfig(const Aquifetp& fetp, const AquiferCT& ct, const Aquancon& conn);
|
||||
|
||||
static AquiferConfig serializeObject();
|
||||
@@ -51,12 +54,14 @@ public:
|
||||
aquifetp.serializeOp(serializer);
|
||||
aquiferct.serializeOp(serializer);
|
||||
aqconn.serializeOp(serializer);
|
||||
numerical_aquifers.serializeOp(serializer);
|
||||
}
|
||||
|
||||
private:
|
||||
Aquifetp aquifetp;
|
||||
AquiferCT aquiferct;
|
||||
Aquancon aqconn;
|
||||
NumericalAquifers numerical_aquifers;
|
||||
};
|
||||
|
||||
}
|
||||
|
||||
@@ -0,0 +1,68 @@
|
||||
/*
|
||||
Copyright (C) 2020 SINTEF Digital
|
||||
|
||||
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 OPM_NUMERICALAQUIFERCELL_HPP
|
||||
#define OPM_NUMERICALAQUIFERCELL_HPP
|
||||
|
||||
#include <optional>
|
||||
|
||||
namespace Opm {
|
||||
class DeckRecord;
|
||||
class EclipseGrid;
|
||||
class FieldPropsManager;
|
||||
|
||||
struct NumericalAquiferCell {
|
||||
NumericalAquiferCell(const DeckRecord&, const EclipseGrid&, const FieldPropsManager&);
|
||||
NumericalAquiferCell() = default;
|
||||
size_t aquifer_id;
|
||||
size_t I, J, K;
|
||||
double area;
|
||||
double length;
|
||||
double porosity;
|
||||
double permeability;
|
||||
double depth;
|
||||
std::optional<double> init_pressure;
|
||||
int pvttable;
|
||||
int sattable;
|
||||
size_t global_index;
|
||||
|
||||
double cellVolume() const;
|
||||
double poreVolume() const;
|
||||
double transmissiblity() const;
|
||||
bool operator == (const NumericalAquiferCell& other) const;
|
||||
|
||||
template<class Serializer>
|
||||
void serializeOp(Serializer& serializer) {
|
||||
serializer(this->aquifer_id);
|
||||
serializer(this->I);
|
||||
serializer(this->J);
|
||||
serializer(this->K);
|
||||
serializer(this->area);
|
||||
serializer(this->length);
|
||||
serializer(this->porosity);
|
||||
serializer(this->permeability);
|
||||
serializer(this->depth);
|
||||
serializer(this->pvttable);
|
||||
serializer(this->sattable);
|
||||
serializer(this->global_index);
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
#endif //OPM_NUMERICALAQUIFERCELL_HPP
|
||||
+74
@@ -0,0 +1,74 @@
|
||||
/*
|
||||
Copyright (C) 2020 SINTEF Digital
|
||||
|
||||
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 OPM_NUMERICALAQUIFERCONNECTION_HPP
|
||||
#define OPM_NUMERICALAQUIFERCONNECTION_HPP
|
||||
|
||||
#include <opm/parser/eclipse/EclipseState/Grid/FaceDir.hpp>
|
||||
#include <map>
|
||||
#include <array>
|
||||
#include <vector>
|
||||
|
||||
namespace Opm {
|
||||
|
||||
class EclipseGrid;
|
||||
class Deck;
|
||||
class DeckRecord;
|
||||
|
||||
struct NumericalAquiferConnection {
|
||||
// TODO: I do not think we need all the values here
|
||||
size_t aquifer_id;
|
||||
size_t I, J, K;
|
||||
size_t global_index;
|
||||
FaceDir::DirEnum face_dir;
|
||||
double trans_multipler;
|
||||
int trans_option;
|
||||
bool connect_active_cell;
|
||||
|
||||
// The following are options related to VE simulation
|
||||
double ve_frac_relperm;
|
||||
double ve_frac_cappress;
|
||||
|
||||
NumericalAquiferConnection(size_t i, size_t j, size_t k, size_t global_index, bool allow_connect_active, const DeckRecord& record);
|
||||
NumericalAquiferConnection() = default;
|
||||
|
||||
bool operator==(const NumericalAquiferConnection& other) const;
|
||||
|
||||
template<class Serializer>
|
||||
void serializeOp(Serializer& serializer) {
|
||||
serializer(this->aquifer_id);
|
||||
serializer(this->I);
|
||||
serializer(this->J);
|
||||
serializer(this->K);
|
||||
serializer(this->global_index);
|
||||
serializer(this->face_dir);
|
||||
serializer(this->trans_multipler);
|
||||
serializer(this->trans_option);
|
||||
serializer(this->connect_active_cell);
|
||||
serializer(this->ve_frac_relperm);
|
||||
serializer(this->ve_frac_cappress);
|
||||
}
|
||||
|
||||
static std::map<size_t, std::map<size_t, NumericalAquiferConnection>> generateConnections(const Deck& deck, const EclipseGrid& grid);
|
||||
private:
|
||||
static std::vector<NumericalAquiferConnection> connectionsFromSingleRecord(const EclipseGrid& grid, const DeckRecord& record);
|
||||
};
|
||||
}
|
||||
|
||||
#endif //OPM_NUMERICALAQUIFERCONNECTION_HPP
|
||||
@@ -0,0 +1,61 @@
|
||||
/*
|
||||
Copyright (C) 2020 SINTEF Digital
|
||||
|
||||
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 OPM_NUMERICALAQUIFERS_HPP
|
||||
#define OPM_NUMERICALAQUIFERS_HPP
|
||||
|
||||
#include <unordered_map>
|
||||
|
||||
#include <opm/parser/eclipse/EclipseState/Aquifer/NumericalAquifer/SingleNumericalAquifer.hpp>
|
||||
|
||||
namespace Opm {
|
||||
class Deck;
|
||||
class EclipseGrid;
|
||||
class FieldPropsManager;
|
||||
struct NumericalAquiferCell;
|
||||
|
||||
class NumericalAquifers {
|
||||
public:
|
||||
NumericalAquifers() = default;
|
||||
NumericalAquifers(const Deck& deck, const EclipseGrid& grid, const FieldPropsManager& field_props);
|
||||
|
||||
size_t numAquifer() const;
|
||||
bool hasAquifer(size_t aquifer_id) const;
|
||||
const SingleNumericalAquifer& getAquifer(size_t aquifer_id) const;
|
||||
bool operator==(const NumericalAquifers& other) const;
|
||||
|
||||
std::unordered_map<size_t, const NumericalAquiferCell*> allAquiferCells() const;
|
||||
|
||||
static NumericalAquifers serializeObject();
|
||||
template <class Serializer>
|
||||
void serializeOp(Serializer& serializer)
|
||||
{
|
||||
serializer.map(this->m_aquifers);
|
||||
}
|
||||
|
||||
private:
|
||||
std::unordered_map <size_t, SingleNumericalAquifer> m_aquifers;
|
||||
|
||||
void addAquiferCell(const NumericalAquiferCell& aqu_cell);
|
||||
|
||||
void addAquiferConnections(const Deck &deck, const EclipseGrid &grid);
|
||||
};
|
||||
}
|
||||
|
||||
#endif //OPM_NUMERICALAQUIFERS_HPP
|
||||
@@ -0,0 +1,65 @@
|
||||
/*
|
||||
Copyright (C) 2020 SINTEF Digital
|
||||
|
||||
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 OPM_SINGLENUMERICALAQUIFER_HPP
|
||||
#define OPM_SINGLENUMERICALAQUIFER_HPP
|
||||
|
||||
#include <vector>
|
||||
|
||||
#include <opm/parser/eclipse/EclipseState/Aquifer/NumericalAquifer/NumericalAquiferConnection.hpp>
|
||||
#include <opm/parser/eclipse/EclipseState/Aquifer/NumericalAquifer/NumericalAquiferCell.hpp>
|
||||
|
||||
namespace Opm {
|
||||
|
||||
class SingleNumericalAquifer {
|
||||
public:
|
||||
explicit SingleNumericalAquifer(const size_t aqu_id);
|
||||
SingleNumericalAquifer() = default;
|
||||
|
||||
void addAquiferCell(const NumericalAquiferCell& aqu_cell);
|
||||
void addAquiferConnection(const NumericalAquiferConnection& aqu_con);
|
||||
|
||||
// TODO: the following two can be made one function. Let us see
|
||||
// how we use them at the end
|
||||
size_t numCells() const;
|
||||
size_t numConnections() const;
|
||||
const NumericalAquiferCell* getCellPrt(size_t index) const;
|
||||
|
||||
bool operator==(const SingleNumericalAquifer& other) const;
|
||||
|
||||
template<class Serializer>
|
||||
void serializeOp(Serializer& serializer) {
|
||||
serializer(this->id_);
|
||||
serializer.vector(this->cells_);
|
||||
serializer.vector(this->connections_);
|
||||
}
|
||||
|
||||
private:
|
||||
// Maybe this id_ is not necessary
|
||||
// Because if it is a map, the id will be there
|
||||
// Then adding aquifer cells will be much easier with the
|
||||
// default constructor
|
||||
size_t id_;
|
||||
std::vector<NumericalAquiferCell> cells_;
|
||||
std::vector<NumericalAquiferConnection> connections_;
|
||||
};
|
||||
}
|
||||
|
||||
|
||||
#endif //OPM_SINGLENUMERICALAQUIFER_HPP
|
||||
@@ -22,14 +22,14 @@
|
||||
#include <opm/parser/eclipse/EclipseState/Tables/TableManager.hpp>
|
||||
#include <opm/parser/eclipse/EclipseState/Grid/EclipseGrid.hpp>
|
||||
|
||||
#include <opm/parser/eclipse/EclipseState/Grid/EclipseGrid.hpp>
|
||||
|
||||
namespace Opm {
|
||||
|
||||
AquiferConfig::AquiferConfig(const TableManager& tables, const EclipseGrid& grid, const Deck& deck):
|
||||
AquiferConfig::AquiferConfig(const TableManager& tables, const EclipseGrid& grid,
|
||||
const Deck& deck, const FieldPropsManager& field_props):
|
||||
aquifetp(deck),
|
||||
aquiferct(tables, deck),
|
||||
aqconn(grid,deck)
|
||||
aqconn(grid,deck),
|
||||
numerical_aquifers(deck, grid, field_props)
|
||||
{}
|
||||
|
||||
AquiferConfig::AquiferConfig(const Aquifetp& fetp, const AquiferCT& ct, const Aquancon& conn) :
|
||||
@@ -44,18 +44,22 @@ AquiferConfig AquiferConfig::serializeObject()
|
||||
result.aquifetp = Aquifetp::serializeObject();
|
||||
result.aquiferct = AquiferCT::serializeObject();
|
||||
result.aqconn = Aquancon::serializeObject();
|
||||
result.numerical_aquifers = NumericalAquifers::serializeObject();
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
bool AquiferConfig::active() const {
|
||||
return this->aqconn.active();
|
||||
return this->aquiferct.size() > 0 ||
|
||||
this->aquifetp.size() > 0 ||
|
||||
this->numerical_aquifers.numAquifer() > 0;
|
||||
}
|
||||
|
||||
bool AquiferConfig::operator==(const AquiferConfig& other) {
|
||||
return this->aquifetp == other.aquifetp &&
|
||||
this->aquiferct == other.aquiferct &&
|
||||
this->aqconn == other.aqconn;
|
||||
this->aqconn == other.aqconn &&
|
||||
this->numerical_aquifers == other.numerical_aquifers;
|
||||
}
|
||||
|
||||
const AquiferCT& AquiferConfig::ct() const {
|
||||
@@ -71,7 +75,9 @@ const Aquancon& AquiferConfig::connections() const {
|
||||
}
|
||||
|
||||
bool AquiferConfig::hasAquifer(const int aquID) const {
|
||||
return aquifetp.hasAquifer(aquID) || aquiferct.hasAquifer(aquID);
|
||||
return aquifetp.hasAquifer(aquID) ||
|
||||
aquiferct.hasAquifer(aquID) ||
|
||||
numerical_aquifers.hasAquifer(aquID);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
+106
@@ -0,0 +1,106 @@
|
||||
/*
|
||||
Copyright (C) 2020 SINTEF Digital
|
||||
|
||||
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/EclipseState/Grid/FieldPropsManager.hpp>
|
||||
#include <opm/parser/eclipse/EclipseState/Grid/EclipseGrid.hpp>
|
||||
#include <opm/parser/eclipse/Deck/DeckRecord.hpp>
|
||||
|
||||
#include <opm/parser/eclipse/EclipseState/Aquifer/NumericalAquifer/NumericalAquiferCell.hpp>
|
||||
|
||||
namespace Opm {
|
||||
|
||||
using AQUNUM = ParserKeywords::AQUNUM;
|
||||
NumericalAquiferCell::NumericalAquiferCell(const DeckRecord& record, const EclipseGrid& grid, const FieldPropsManager& field_props)
|
||||
: aquifer_id( record.getItem<AQUNUM::AQUIFER_ID>().get<int>(0) )
|
||||
, I ( record.getItem<AQUNUM::I>().get<int>(0) - 1 )
|
||||
, J ( record.getItem<AQUNUM::J>().get<int>(0) - 1 )
|
||||
, K ( record.getItem<AQUNUM::K>().get<int>(0) - 1 )
|
||||
, area (record.getItem<AQUNUM::CROSS_SECTION>().getSIDouble(0) )
|
||||
, length ( record.getItem<AQUNUM::LENGTH>().getSIDouble(0) )
|
||||
, permeability( record.getItem<AQUNUM::PERM>().getSIDouble(0) )
|
||||
{
|
||||
const auto& poro = field_props.get_double("PORO");
|
||||
const auto& pvtnum = field_props.get_int("PVTNUM");
|
||||
const auto& satnum = field_props.get_int("SATNUM");
|
||||
|
||||
this->global_index = grid.getGlobalIndex(I, J, K);
|
||||
const size_t active_index = grid.activeIndex(this->global_index);
|
||||
|
||||
if ( !record.getItem<AQUNUM::PORO>().defaultApplied(0) ) {
|
||||
this->porosity = record.getItem<AQUNUM::PORO>().getSIDouble(0);
|
||||
} else {
|
||||
this->porosity = poro[active_index];
|
||||
}
|
||||
|
||||
if ( !record.getItem<AQUNUM::DEPTH>().defaultApplied(0) ) {
|
||||
this->depth = record.getItem<AQUNUM::DEPTH>().getSIDouble(0);
|
||||
} else {
|
||||
this->depth = grid.getCellDepth(this->global_index);
|
||||
}
|
||||
|
||||
if ( !record.getItem<AQUNUM::INITIAL_PRESSURE>().defaultApplied(0) ) {
|
||||
this->init_pressure = record.getItem<AQUNUM::INITIAL_PRESSURE>().getSIDouble(0);
|
||||
}
|
||||
|
||||
if ( !record.getItem<AQUNUM::PVT_TABLE_NUM>().defaultApplied(0) ) {
|
||||
this->pvttable = record.getItem<AQUNUM::PVT_TABLE_NUM>().get<int>(0);
|
||||
} else {
|
||||
this->pvttable = pvtnum[active_index];
|
||||
}
|
||||
|
||||
if ( !record.getItem<AQUNUM::SAT_TABLE_NUM>().defaultApplied(0) ) {
|
||||
this->sattable = record.getItem<AQUNUM::SAT_TABLE_NUM>().get<int>(0);
|
||||
} else {
|
||||
this->sattable = satnum[active_index];
|
||||
}
|
||||
}
|
||||
|
||||
double NumericalAquiferCell::cellVolume() const {
|
||||
return this->area * this->length;
|
||||
}
|
||||
|
||||
bool NumericalAquiferCell::operator==(const NumericalAquiferCell& other) const {
|
||||
return this->aquifer_id == other.aquifer_id &&
|
||||
this->I == other.I &&
|
||||
this->J == other.J &&
|
||||
this->K == other.K &&
|
||||
this->area == other.area &&
|
||||
this->length == other.length &&
|
||||
this->porosity == other.porosity &&
|
||||
this->permeability == other.permeability &&
|
||||
this->depth == other.depth &&
|
||||
this->init_pressure == other.init_pressure &&
|
||||
this->pvttable == other.pvttable &&
|
||||
this->sattable == other.sattable &&
|
||||
this->global_index == other.global_index;
|
||||
}
|
||||
|
||||
double NumericalAquiferCell::poreVolume() const {
|
||||
return this->porosity * this->cellVolume();
|
||||
}
|
||||
|
||||
double NumericalAquiferCell::transmissiblity() const {
|
||||
return 2. * this->permeability * this->area / this->length;;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
+130
@@ -0,0 +1,130 @@
|
||||
/*
|
||||
Copyright (C) 2020 SINTEF Digital
|
||||
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/EclipseState/Aquifer/NumericalAquifer/NumericalAquiferConnection.hpp>
|
||||
|
||||
#include <opm/parser/eclipse/Deck/Deck.hpp>
|
||||
#include <opm/parser/eclipse/Deck/DeckRecord.hpp>
|
||||
#include <opm/parser/eclipse/EclipseState/Grid/EclipseGrid.hpp>
|
||||
#include <opm/common/utility/OpmInputError.hpp>
|
||||
#include <opm/common/OpmLog/OpmLog.hpp>
|
||||
#include <fmt/format.h>
|
||||
|
||||
#include "../AquiferHelpers.hpp"
|
||||
|
||||
#include <string>
|
||||
|
||||
namespace Opm {
|
||||
|
||||
std::map<size_t, std::map<size_t, NumericalAquiferConnection>>
|
||||
NumericalAquiferConnection::generateConnections(const Deck &deck, const EclipseGrid &grid)
|
||||
{
|
||||
using AQUCON=ParserKeywords::AQUCON;
|
||||
if ( !deck.hasKeyword<AQUCON>() ) return {};
|
||||
|
||||
std::map<size_t, std::map<size_t, NumericalAquiferConnection>> connections;
|
||||
|
||||
const auto& aqucon_keywords = deck.getKeywordList<AQUCON>();
|
||||
for (const auto& keyword : aqucon_keywords) {
|
||||
OpmLog::info(OpmInputError::format("Initializing numerical aquifer connections from {keyword} in {file} line {line}", keyword->location()));
|
||||
for (const auto& record : *keyword) {
|
||||
const auto cons_from_record = NumericalAquiferConnection::connectionsFromSingleRecord(grid, record);
|
||||
for (auto con : cons_from_record) {
|
||||
const size_t aqu_id = con.aquifer_id;
|
||||
const size_t global_index = con.global_index;
|
||||
auto& aqu_cons = connections[aqu_id];
|
||||
if (aqu_cons.find(global_index) == aqu_cons.end()) {
|
||||
aqu_cons.insert({global_index, con});
|
||||
} else {
|
||||
auto error = fmt::format("Numerical aquifer cell at ({}, {}, {}) is declared more than once"
|
||||
" as a connection for numerical aquifer {}",
|
||||
con.I + 1, con.J + 1, con.K + 1, con.aquifer_id);
|
||||
throw OpmInputError(error, keyword->location());
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
return connections;
|
||||
}
|
||||
|
||||
// TODO: we should not need all following the information here
|
||||
using AQUCON = ParserKeywords::AQUCON;
|
||||
NumericalAquiferConnection::NumericalAquiferConnection(const size_t i, const size_t j, const size_t k,
|
||||
const size_t global_index_in, const bool allow_connection_active, const DeckRecord& record)
|
||||
: aquifer_id(record.getItem<AQUCON::ID>().get<int>(0))
|
||||
, I(i)
|
||||
, J(j)
|
||||
, K(k)
|
||||
, global_index(global_index_in)
|
||||
, face_dir(FaceDir::FromString(record.getItem<AQUCON::CONNECT_FACE>().getTrimmedString(0)))
|
||||
, trans_multipler(record.getItem<AQUCON::TRANS_MULT>().get<double>(0))
|
||||
, trans_option(record.getItem<AQUCON::TRANS_OPTION>().get<int>(0))
|
||||
, connect_active_cell(allow_connection_active)
|
||||
, ve_frac_relperm(record.getItem<AQUCON::VEFRAC>().get<double>(0))
|
||||
, ve_frac_cappress(record.getItem<AQUCON::VEFRACP>().get<double>(0))
|
||||
{
|
||||
}
|
||||
|
||||
std::vector<NumericalAquiferConnection> NumericalAquiferConnection::connectionsFromSingleRecord(const EclipseGrid& grid, const DeckRecord& record) {
|
||||
std::vector<NumericalAquiferConnection> cons;
|
||||
|
||||
const size_t i1 = record.getItem<AQUCON::I1>().get<int>(0) - 1;
|
||||
const size_t j1 = record.getItem<AQUCON::J1>().get<int>(0) - 1;
|
||||
const size_t k1 = record.getItem<AQUCON::K1>().get<int>(0) - 1;
|
||||
const size_t i2 = record.getItem<AQUCON::I2>().get<int>(0) - 1;
|
||||
const size_t j2 = record.getItem<AQUCON::J2>().get<int>(0) - 1;
|
||||
const size_t k2 = record.getItem<AQUCON::K2>().get<int>(0) - 1;
|
||||
|
||||
// whether the connection face can connect to active/internal cells
|
||||
// by default NO, which means basically the aquifer should be outside of the reservoir
|
||||
const bool allow_internal_cells = DeckItem::to_bool( record.getItem<AQUCON::ALLOW_INTERNAL_CELLS>().getTrimmedString(0) );
|
||||
const FaceDir::DirEnum face_dir
|
||||
= FaceDir::FromString(record.getItem<AQUCON::CONNECT_FACE>().getTrimmedString(0));
|
||||
|
||||
for (size_t k = k1; k <= k2; ++k) {
|
||||
for (size_t j = j1; j <=j2; ++j) {
|
||||
for (size_t i = i1; i <= i2; ++i) {
|
||||
// TODO: we probably should give a message here
|
||||
if (!grid.cellActive(i, j, k)) {
|
||||
continue;
|
||||
}
|
||||
if (allow_internal_cells ||
|
||||
!AquiferHelpers::neighborCellInsideReservoirAndActive(grid, i, j, k, face_dir)) {
|
||||
const size_t global_index = grid.getGlobalIndex(i, j, k);
|
||||
cons.emplace_back(i, j, k, global_index, allow_internal_cells, record);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
return cons;
|
||||
}
|
||||
|
||||
bool NumericalAquiferConnection::operator==(const NumericalAquiferConnection& other) const {
|
||||
return this->aquifer_id == other.aquifer_id &&
|
||||
this->I == other.I &&
|
||||
this->J == other.J &&
|
||||
this->K == other.K &&
|
||||
this->global_index == other.global_index &&
|
||||
this->face_dir == other.face_dir &&
|
||||
this->trans_multipler == other.trans_multipler &&
|
||||
this->trans_option == other.trans_option &&
|
||||
this->connect_active_cell == other.connect_active_cell &&
|
||||
this->ve_frac_relperm == other.ve_frac_relperm &&
|
||||
this->ve_frac_cappress == other.ve_frac_cappress;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,148 @@
|
||||
/*
|
||||
Copyright (C) 2020 SINTEF Digital
|
||||
|
||||
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 <fmt/format.h>
|
||||
#include <opm/common/utility/OpmInputError.hpp>
|
||||
#include <opm/common/OpmLog/OpmLog.hpp>
|
||||
#include <opm/common/OpmLog/KeywordLocation.hpp>
|
||||
|
||||
#include <opm/parser/eclipse/Deck/Deck.hpp>
|
||||
|
||||
#include <opm/parser/eclipse/EclipseState/Aquifer/NumericalAquifer/NumericalAquiferCell.hpp>
|
||||
#include <opm/parser/eclipse/EclipseState/Aquifer/NumericalAquifer/NumericalAquifers.hpp>
|
||||
#include <opm/parser/eclipse/EclipseState/Aquifer/NumericalAquifer/SingleNumericalAquifer.hpp>
|
||||
|
||||
#include <set>
|
||||
|
||||
|
||||
namespace Opm {
|
||||
|
||||
NumericalAquifers::NumericalAquifers(const Deck& deck, const EclipseGrid& grid,
|
||||
const FieldPropsManager& field_props) {
|
||||
using AQUNUM=ParserKeywords::AQUNUM;
|
||||
if ( !deck.hasKeyword<AQUNUM>() ) return;
|
||||
|
||||
std::set<size_t> cells;
|
||||
// there might be multiple keywords of keyword AQUNUM, it is not totally
|
||||
// clear about the rules here. For now, we take care of all the keywords
|
||||
const auto& aqunum_keywords = deck.getKeywordList<AQUNUM>();
|
||||
for (const auto& keyword : aqunum_keywords) {
|
||||
for (const auto& record : *keyword) {
|
||||
const NumericalAquiferCell aqu_cell(record, grid, field_props);
|
||||
if (cells.count(aqu_cell.global_index) > 0) {
|
||||
auto error = fmt::format("Numerical aquifer cell at ({}, {}, {}) is declared more than once",
|
||||
aqu_cell.I + 1, aqu_cell.J + 1, aqu_cell.K + 1);
|
||||
throw OpmInputError(error, keyword->location());
|
||||
} else {
|
||||
this->addAquiferCell(aqu_cell);
|
||||
cells.insert(aqu_cell.global_index);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
this->addAquiferConnections(deck, grid);
|
||||
}
|
||||
|
||||
|
||||
void NumericalAquifers::addAquiferCell(const NumericalAquiferCell& aqu_cell) {
|
||||
const size_t id = aqu_cell.aquifer_id;
|
||||
if (!this->hasAquifer(id)) {
|
||||
this->m_aquifers.insert(std::make_pair(id, SingleNumericalAquifer{id}));
|
||||
}
|
||||
|
||||
auto& aquifer = this->m_aquifers.at(id);
|
||||
aquifer.addAquiferCell(aqu_cell);
|
||||
}
|
||||
|
||||
bool NumericalAquifers::hasAquifer(const size_t aquifer_id) const {
|
||||
return (this->m_aquifers.find(aquifer_id) != this->m_aquifers.end());
|
||||
}
|
||||
|
||||
void NumericalAquifers::addAquiferConnections(const Deck& deck, const EclipseGrid& grid) {
|
||||
const auto aquifer_connections = NumericalAquiferConnection::generateConnections(deck, grid);
|
||||
|
||||
for (auto& pair : this->m_aquifers) {
|
||||
const size_t aqu_id = pair.first;
|
||||
const auto& aqu_cons = aquifer_connections.find(aqu_id);
|
||||
if (aqu_cons == aquifer_connections.end()) {
|
||||
const auto error = fmt::format("Numerical aquifer {} does not have any connections\n", aqu_id);
|
||||
throw std::runtime_error(error);
|
||||
}
|
||||
auto& aquifer = pair.second;
|
||||
const auto& cons = aqu_cons->second;
|
||||
|
||||
const auto all_aquifer_cells = this->allAquiferCells();
|
||||
// For now, there is no two aquifers can be connected to one cell
|
||||
// aquifer can not connect to aquifer cells
|
||||
for (const auto& con : cons) {
|
||||
const auto& aqu_con = con.second;
|
||||
const size_t con_global_index = aqu_con.global_index;
|
||||
const auto cell_iter = all_aquifer_cells.find(con_global_index);
|
||||
if (cell_iter != all_aquifer_cells.end()) {
|
||||
const size_t cell_aquifer_id = cell_iter->second->aquifer_id;
|
||||
auto msg = fmt::format("Problem with keyword AQUCON \n"
|
||||
"Aquifer connection declared at grid cell ({}, {}, {}), is a aquifer cell "
|
||||
"of Aquifer {}, and will be removed",
|
||||
aqu_con.I + 1, aqu_con.J + 1, aqu_con.K + 1, cell_aquifer_id);
|
||||
OpmLog::warning(msg);
|
||||
continue;
|
||||
}
|
||||
|
||||
aquifer.addAquiferConnection(con.second);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
bool NumericalAquifers::operator==(const NumericalAquifers& other) const {
|
||||
return this->m_aquifers == other.m_aquifers;
|
||||
}
|
||||
|
||||
size_t NumericalAquifers::numAquifer() const {
|
||||
return this->m_aquifers.size();
|
||||
}
|
||||
|
||||
NumericalAquifers NumericalAquifers::serializeObject() {
|
||||
NumericalAquifers result;
|
||||
result.m_aquifers = {{1, SingleNumericalAquifer{1}}};
|
||||
return result;
|
||||
}
|
||||
|
||||
const SingleNumericalAquifer& NumericalAquifers::getAquifer(const size_t aquifer_id) const {
|
||||
const auto iter = this->m_aquifers.find(aquifer_id);
|
||||
if ( iter != this->m_aquifers.end() ) {
|
||||
return iter->second;
|
||||
} else {
|
||||
const auto msg = fmt::format(" There is no numerical aquifer {}", aquifer_id);
|
||||
throw std::runtime_error(msg);
|
||||
}
|
||||
}
|
||||
|
||||
std::unordered_map<size_t, const NumericalAquiferCell*> NumericalAquifers::allAquiferCells() const {
|
||||
std::unordered_map<size_t, const NumericalAquiferCell*> cells;
|
||||
for (const auto& [id, aquifer] : this->m_aquifers) {
|
||||
for (size_t i = 0; i < aquifer.numCells(); ++i) {
|
||||
const NumericalAquiferCell* cell_ptr = aquifer.getCellPrt(i);
|
||||
cells.insert(std::make_pair(cell_ptr->global_index, cell_ptr));
|
||||
}
|
||||
}
|
||||
return cells;
|
||||
}
|
||||
}
|
||||
+55
@@ -0,0 +1,55 @@
|
||||
/*
|
||||
Copyright (C) 2020 SINTEF Digital
|
||||
|
||||
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/EclipseState/Aquifer/NumericalAquifer/NumericalAquiferConnection.hpp>
|
||||
#include <opm/parser/eclipse/EclipseState/Aquifer/NumericalAquifer/NumericalAquiferCell.hpp>
|
||||
#include <opm/parser/eclipse/EclipseState/Aquifer/NumericalAquifer/SingleNumericalAquifer.hpp>
|
||||
|
||||
namespace Opm {
|
||||
SingleNumericalAquifer::SingleNumericalAquifer(const size_t aqu_id)
|
||||
: id_(aqu_id)
|
||||
{
|
||||
}
|
||||
|
||||
void SingleNumericalAquifer::addAquiferCell(const NumericalAquiferCell& aqu_cell) {
|
||||
cells_.push_back(aqu_cell);
|
||||
}
|
||||
|
||||
size_t SingleNumericalAquifer::numCells() const {
|
||||
return this->cells_.size();
|
||||
}
|
||||
|
||||
const NumericalAquiferCell* SingleNumericalAquifer::getCellPrt(const size_t index) const {
|
||||
return &this->cells_[index];
|
||||
}
|
||||
|
||||
void SingleNumericalAquifer::addAquiferConnection(const NumericalAquiferConnection& aqu_con) {
|
||||
this->connections_.push_back(aqu_con);
|
||||
}
|
||||
|
||||
bool SingleNumericalAquifer::operator==(const SingleNumericalAquifer& other) const {
|
||||
return this->cells_ == other.cells_ &&
|
||||
this->connections_ == other.connections_ &&
|
||||
this->id_ == other.id_;
|
||||
}
|
||||
|
||||
size_t SingleNumericalAquifer::numConnections() const {
|
||||
return this->connections_.size();
|
||||
}
|
||||
}
|
||||
@@ -69,7 +69,7 @@ namespace Opm {
|
||||
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->aquifer_config = AquiferConfig(this->m_tables, this->m_inputGrid, deck, this->field_props);
|
||||
|
||||
if (deck.hasKeyword( "TITLE" )) {
|
||||
const auto& titleKeyword = deck.getKeyword( "TITLE" );
|
||||
|
||||
@@ -539,12 +539,23 @@ BOOST_AUTO_TEST_CASE(Test_Aquifer_Config) {
|
||||
const std::string deck_string = R"(
|
||||
DIMENS
|
||||
3 3 3 /
|
||||
GRID
|
||||
DX
|
||||
27*1 /
|
||||
DY
|
||||
27*1 /
|
||||
DZ
|
||||
27*1 /
|
||||
TOPS
|
||||
9*1 /
|
||||
PORO
|
||||
27*1 /
|
||||
)";
|
||||
Opm::Parser parser;
|
||||
Opm::Deck deck = parser.parseString(deck_string);
|
||||
Opm::EclipseState ecl_state(deck);
|
||||
Opm::TableManager tables;
|
||||
Opm::EclipseGrid grid(10,10,10);
|
||||
Opm::AquiferConfig conf(tables, grid, deck);
|
||||
Opm::AquiferConfig conf(tables, ecl_state.getInputGrid(), deck, ecl_state.fieldProps());
|
||||
BOOST_CHECK(!conf.active());
|
||||
|
||||
|
||||
@@ -554,3 +565,66 @@ DIMENS
|
||||
Opm::AquiferConfig conf2(fetp, ct, conn);
|
||||
BOOST_CHECK( conf == conf2 );
|
||||
}
|
||||
|
||||
|
||||
inline Deck createNumericalAquiferDeck() {
|
||||
const char *deckData = R"(
|
||||
DIMENS
|
||||
8 15 3 /
|
||||
AQUDIMS
|
||||
3 2 1* 1* 1* 50 1* 1* /
|
||||
GRID
|
||||
|
||||
DX
|
||||
360*10./
|
||||
DY
|
||||
360*10./
|
||||
DZ
|
||||
360*1./
|
||||
TOPS
|
||||
360*100./
|
||||
|
||||
PORO
|
||||
360*0.25/
|
||||
PERMX
|
||||
360*1000./
|
||||
PERMY
|
||||
360*1000./
|
||||
PERMZ
|
||||
360*10./
|
||||
|
||||
AQUNUM
|
||||
--AQnr. I J K Area Length PHI K Depth Initial.Pr PVTNUM SATNUM
|
||||
1 1 1 1 1000000.0 10000 0.25 400 2585.00 285.00 1 1 /
|
||||
1 3 1 1 1500000.0 20000 0.24 600 2585.00 285.00 1 1 /
|
||||
1 4 1 1 2000000.0 30000 0.23 700 2585.00 285.00 1 1 /
|
||||
/
|
||||
AQUCON
|
||||
-- Connect numerical aquifer to the reservoir
|
||||
-- Id.nr I1 I2 J1 J2 K1 K2 Face Trans.mult. Trans.opt.
|
||||
1 1 8 15 15 3 3 'J+' 1.00 1 /
|
||||
/
|
||||
)";
|
||||
|
||||
Parser parser;
|
||||
return parser.parseString(deckData);
|
||||
}
|
||||
|
||||
BOOST_AUTO_TEST_CASE(NumericalAquiferTest){
|
||||
const Opm::Deck numaquifer_deck = createNumericalAquiferDeck();
|
||||
const Opm::EclipseState ecl_state(numaquifer_deck);
|
||||
const Opm::EclipseGrid& grid = ecl_state.getInputGrid();
|
||||
|
||||
const Opm::NumericalAquifers num_aqu{numaquifer_deck, grid, ecl_state.fieldProps()};
|
||||
BOOST_CHECK(num_aqu.hasAquifer(1));
|
||||
BOOST_CHECK(num_aqu.numAquifer() == 1);
|
||||
const auto all_aquifer_cells = num_aqu.allAquiferCells();
|
||||
BOOST_CHECK(all_aquifer_cells.count(0) > 0);
|
||||
BOOST_CHECK(all_aquifer_cells.count(2) > 0);
|
||||
BOOST_CHECK(all_aquifer_cells.count(3) > 0);
|
||||
BOOST_CHECK(all_aquifer_cells.count(1) == 0);
|
||||
|
||||
const auto& aquifer = num_aqu.getAquifer(1);
|
||||
BOOST_CHECK(aquifer.numCells() == 3);
|
||||
BOOST_CHECK(aquifer.numConnections() == 8 );
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user