commit
54cae0f07e
@ -63,7 +63,6 @@ if(ENABLE_ECL_INPUT)
|
||||
src/opm/parser/eclipse/EclipseState/EclipseConfig.cpp
|
||||
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
|
||||
@ -382,6 +381,7 @@ if(ENABLE_ECL_INPUT)
|
||||
tests/parser/TuningTests.cpp
|
||||
tests/parser/UDQTests.cpp
|
||||
tests/parser/UnitTests.cpp
|
||||
tests/parser/integration/NNCTests.cpp
|
||||
tests/parser/WellSolventTests.cpp
|
||||
tests/parser/WellTracerTests.cpp
|
||||
tests/parser/WellTests.cpp
|
||||
@ -580,7 +580,6 @@ if(ENABLE_ECL_INPUT)
|
||||
opm/parser/eclipse/EclipseState/Util/IOrderSet.hpp
|
||||
opm/parser/eclipse/EclipseState/Util/OrderedMap.hpp
|
||||
opm/parser/eclipse/EclipseState/SummaryConfig/SummaryConfig.hpp
|
||||
opm/parser/eclipse/EclipseState/Edit/EDITNNC.hpp
|
||||
opm/parser/eclipse/EclipseState/Grid/FieldData.hpp
|
||||
opm/parser/eclipse/EclipseState/Grid/Keywords.hpp
|
||||
opm/parser/eclipse/EclipseState/Grid/GridDims.hpp
|
||||
|
@ -44,11 +44,9 @@ list(APPEND EXTRA_TESTS EclipseStateTests)
|
||||
foreach (test BoxTest
|
||||
CheckDeckValidity
|
||||
EclipseGridCreateFromDeck
|
||||
EDITNNCTests
|
||||
IncludeTest
|
||||
IntegrationTests
|
||||
IOConfigIntegrationTest
|
||||
NNCTests
|
||||
ParseKEYWORD
|
||||
Polymer
|
||||
ScheduleCreateFromDeck
|
||||
|
@ -112,7 +112,7 @@ public:
|
||||
* are not yet written to disk.
|
||||
*/
|
||||
|
||||
void writeInitial( data::Solution simProps = data::Solution(), std::map<std::string, std::vector<int> > int_data = {}, const NNC& nnc = NNC());
|
||||
void writeInitial( data::Solution simProps = data::Solution(), std::map<std::string, std::vector<int> > int_data = {}, const std::vector<NNCdata>& nnc = {});
|
||||
|
||||
/**
|
||||
* \brief Overwrite the initial OIP values.
|
||||
|
@ -24,6 +24,8 @@
|
||||
#include <string>
|
||||
#include <vector>
|
||||
|
||||
#include <opm/parser/eclipse/EclipseState/Grid/NNC.hpp>
|
||||
|
||||
namespace Opm {
|
||||
|
||||
class EclipseGrid;
|
||||
@ -52,7 +54,7 @@ namespace Opm { namespace InitIO {
|
||||
const ::Opm::Schedule& schedule,
|
||||
const ::Opm::data::Solution& simProps,
|
||||
std::map<std::string, std::vector<int>> int_data,
|
||||
const ::Opm::NNC& nnc,
|
||||
const std::vector<::Opm::NNCdata>& nnc,
|
||||
::Opm::EclIO::OutputStream::Init& initFile);
|
||||
|
||||
}} // namespace Opm::InitIO
|
||||
|
@ -27,7 +27,6 @@
|
||||
#include <opm/parser/eclipse/EclipseState/AquiferConfig.hpp>
|
||||
#include <opm/parser/eclipse/EclipseState/EclipseConfig.hpp>
|
||||
#include <opm/parser/eclipse/EclipseState/TracerConfig.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>
|
||||
@ -78,7 +77,7 @@ namespace Opm {
|
||||
|
||||
const InitConfig& getInitConfig() const;
|
||||
InitConfig& getInitConfig();
|
||||
|
||||
|
||||
const SimulationConfig& getSimulationConfig() const;
|
||||
virtual const EclipseGrid& getInputGrid() const;
|
||||
|
||||
@ -90,11 +89,6 @@ namespace Opm {
|
||||
const NNC& getInputNNC() const;
|
||||
bool hasInputNNC() const;
|
||||
|
||||
/// editing non-neighboring connections
|
||||
/// the non-standard adjacencies as specified in input deck
|
||||
const EDITNNC& getInputEDITNNC() const;
|
||||
bool hasInputEDITNNC() const;
|
||||
|
||||
// The potentially parallelized field properties
|
||||
virtual const FieldPropsManager& fieldProps() const;
|
||||
// Always the non-parallel field properties
|
||||
@ -127,7 +121,6 @@ namespace Opm {
|
||||
m_eclipseConfig.serializeOp(serializer);
|
||||
m_deckUnitSystem.serializeOp(serializer);
|
||||
m_inputNnc.serializeOp(serializer);
|
||||
m_inputEditNnc.serializeOp(serializer);
|
||||
m_gridDims.serializeOp(serializer);
|
||||
m_simulationConfig.serializeOp(serializer);
|
||||
m_transMult.serializeOp(serializer);
|
||||
@ -152,9 +145,8 @@ namespace Opm {
|
||||
Runspec m_runspec;
|
||||
EclipseConfig m_eclipseConfig;
|
||||
UnitSystem m_deckUnitSystem;
|
||||
NNC m_inputNnc;
|
||||
EDITNNC m_inputEditNnc;
|
||||
EclipseGrid m_inputGrid;
|
||||
NNC m_inputNnc;
|
||||
GridDims m_gridDims;
|
||||
FieldPropsManager field_props;
|
||||
SimulationConfig m_simulationConfig;
|
||||
|
@ -1,60 +0,0 @@
|
||||
/*
|
||||
Copyright 2018 Equinor AS
|
||||
|
||||
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_COMMON_EDITNNC_HPP
|
||||
#define OPM_COMMON_EDITNNC_HPP
|
||||
|
||||
#include <opm/parser/eclipse/EclipseState/Grid/NNC.hpp>
|
||||
namespace Opm
|
||||
{
|
||||
|
||||
/// Represents edit information for non-neighboring connections (NNCs, faults, etc.)
|
||||
class EDITNNC
|
||||
{
|
||||
public:
|
||||
EDITNNC() = default;
|
||||
|
||||
/// Construct from input deck
|
||||
explicit EDITNNC(const Deck& deck);
|
||||
|
||||
/// Returns an instance used for serialization test
|
||||
static EDITNNC serializeObject();
|
||||
|
||||
/// \brief Get an ordered set of EDITNNC
|
||||
const std::vector<NNCdata>& data() const
|
||||
{
|
||||
return m_editnnc;
|
||||
}
|
||||
/// \brief Get the number of entries
|
||||
size_t size() const;
|
||||
/// \brief Whether EDITNNC was empty.
|
||||
bool empty() const;
|
||||
|
||||
bool operator==(const EDITNNC& data) const;
|
||||
|
||||
template<class Serializer>
|
||||
void serializeOp(Serializer& serializer)
|
||||
{
|
||||
serializer.vector(m_editnnc);
|
||||
}
|
||||
|
||||
private:
|
||||
std::vector<NNCdata> m_editnnc;
|
||||
};
|
||||
}
|
||||
#endif // OPM_COMMON_EDITNNC_HPP
|
@ -89,7 +89,7 @@ namespace Opm {
|
||||
size_t activeIndex(size_t i, size_t j, size_t k) const;
|
||||
size_t activeIndex(size_t globalIndex) const;
|
||||
|
||||
void save(const std::string& filename, bool formatted, const Opm::NNC& nnc, const Opm::UnitSystem& units) const;
|
||||
void save(const std::string& filename, bool formatted, const std::vector<Opm::NNCdata>& nnc, const Opm::UnitSystem& units) const;
|
||||
/*
|
||||
Observe that the there is a getGlobalIndex(i,j,k)
|
||||
implementation in the base class. This method - translating
|
||||
|
@ -1,18 +1,18 @@
|
||||
/*
|
||||
Copyright 2015 IRIS
|
||||
|
||||
|
||||
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/>.
|
||||
*/
|
||||
@ -22,11 +22,17 @@
|
||||
|
||||
#include <cstddef>
|
||||
#include <memory>
|
||||
#include <optional>
|
||||
#include <tuple>
|
||||
#include <vector>
|
||||
|
||||
#include <opm/common/OpmLog/KeywordLocation.hpp>
|
||||
|
||||
namespace Opm
|
||||
{
|
||||
|
||||
class GridDims;
|
||||
|
||||
struct NNCdata {
|
||||
NNCdata(size_t c1, size_t c2, double t)
|
||||
: cell1(c1), cell2(c2), trans(t)
|
||||
@ -48,41 +54,89 @@ struct NNCdata {
|
||||
serializer(trans);
|
||||
}
|
||||
|
||||
// Observe that the operator< is only for cell ordering and does not consider the
|
||||
// trans member
|
||||
bool operator<(const NNCdata& other) const
|
||||
{
|
||||
return std::tie(this->cell1, this->cell2) < std::tie(other.cell1, other.cell2);
|
||||
}
|
||||
|
||||
size_t cell1;
|
||||
size_t cell2;
|
||||
double trans;
|
||||
};
|
||||
|
||||
class Deck;
|
||||
|
||||
/// Represents non-neighboring connections (non-standard adjacencies).
|
||||
/// This class is essentially a directed weighted graph.
|
||||
|
||||
class Deck;
|
||||
class EclipseGrid;
|
||||
|
||||
/*
|
||||
This class is an internalization of the NNC and EDITNNC keywords. Because the
|
||||
opm-common codebase does not itself manage the simulation grid the purpose of
|
||||
the NNC class is mainly to hold on to the NNC/EDITNNC input and pass it on to
|
||||
the grid construction proper.
|
||||
|
||||
The EDITNNC keywords can operate on two different types of NNCs.
|
||||
|
||||
1. NNCs which have been explicitly entered using the NNC keyword.
|
||||
2. NNCs which are inderectly inferred from the grid - e.g. due to faults.
|
||||
|
||||
When processing the EDITNNC keyword the class will search through the NNCs
|
||||
configured explicitly with the NNC keyword and apply the edit transformation
|
||||
on those NNCs, EDITNNCs which affect NNCs which are not configured explicitly
|
||||
are stored for later use by the simulator.
|
||||
|
||||
The class guarantees the following ordering:
|
||||
|
||||
1. For all NNC / EDITNNC records we will have cell1 <= cell2
|
||||
2. The vectors NNC::input() and NNC::edit() will be ordered in ascending
|
||||
order.
|
||||
|
||||
While constructing from a deck NNCs connected to inactive cells will be
|
||||
silently ignored. Do observe though that the addNNC() function does not check
|
||||
the arguments and alas there is no guarantee that only active cells are
|
||||
involved.
|
||||
*/
|
||||
|
||||
class NNC
|
||||
{
|
||||
public:
|
||||
NNC() = default;
|
||||
|
||||
/// Construct from input deck.
|
||||
explicit NNC(const Deck& deck);
|
||||
NNC(const EclipseGrid& grid, const Deck& deck);
|
||||
|
||||
static NNC serializeObject();
|
||||
|
||||
void addNNC(const size_t cell1, const size_t cell2, const double trans);
|
||||
const std::vector<NNCdata>& data() const { return m_nnc; }
|
||||
size_t numNNC() const;
|
||||
bool hasNNC() const;
|
||||
bool addNNC(const size_t cell1, const size_t cell2, const double trans);
|
||||
const std::vector<NNCdata>& input() const { return m_input; }
|
||||
const std::vector<NNCdata>& edit() const { return m_edit; }
|
||||
KeywordLocation input_location(const NNCdata& nnc) const;
|
||||
KeywordLocation edit_location(const NNCdata& nnc) const;
|
||||
|
||||
|
||||
bool operator==(const NNC& data) const;
|
||||
|
||||
template<class Serializer>
|
||||
void serializeOp(Serializer& serializer)
|
||||
{
|
||||
serializer.vector(m_nnc);
|
||||
serializer.vector(m_input);
|
||||
serializer.vector(m_edit);
|
||||
serializer(m_nnc_location);
|
||||
serializer(m_edit_location);
|
||||
}
|
||||
|
||||
private:
|
||||
|
||||
std::vector<NNCdata> m_nnc;
|
||||
void load_input(const EclipseGrid& grid, const Deck& deck);
|
||||
void load_edit(const EclipseGrid& grid, const Deck& deck);
|
||||
void add_edit(const NNCdata& edit_node);
|
||||
bool update_nnc(std::size_t global_index1, std::size_t global_index2, double tran_mult);
|
||||
|
||||
std::vector<NNCdata> m_input;
|
||||
std::vector<NNCdata> m_edit;
|
||||
std::optional<KeywordLocation> m_nnc_location;
|
||||
std::optional<KeywordLocation> m_edit_location;
|
||||
};
|
||||
|
||||
|
||||
|
@ -10,7 +10,7 @@ namespace {
|
||||
|
||||
py::list getNNC( const EclipseState& state ) {
|
||||
py::list l;
|
||||
for( const auto& x : state.getInputNNC().data() )
|
||||
for( const auto& x : state.getInputNNC().input() )
|
||||
l.append( py::make_tuple( x.cell1, x.cell2, x.trans ) );
|
||||
return l;
|
||||
}
|
||||
|
@ -99,8 +99,8 @@ namespace Opm {
|
||||
class EclipseIO::Impl {
|
||||
public:
|
||||
Impl( const EclipseState&, EclipseGrid, const Schedule&, const SummaryConfig& );
|
||||
void writeINITFile( const data::Solution& simProps, std::map<std::string, std::vector<int> > int_data, const NNC& nnc) const;
|
||||
void writeEGRIDFile( const NNC& nnc );
|
||||
void writeINITFile( const data::Solution& simProps, std::map<std::string, std::vector<int> > int_data, const std::vector<NNCdata>& nnc) const;
|
||||
void writeEGRIDFile( const std::vector<NNCdata>& nnc );
|
||||
bool wantRFTOutput( const int report_step, const bool isSubstep ) const;
|
||||
|
||||
const EclipseState& es;
|
||||
@ -130,7 +130,7 @@ EclipseIO::Impl::Impl( const EclipseState& eclipseState,
|
||||
|
||||
void EclipseIO::Impl::writeINITFile(const data::Solution& simProps,
|
||||
std::map<std::string, std::vector<int>> int_data,
|
||||
const NNC& nnc) const
|
||||
const std::vector<NNCdata>& nnc) const
|
||||
{
|
||||
EclIO::OutputStream::Init initFile {
|
||||
EclIO::OutputStream::ResultSet { this->outputDir, this->baseName },
|
||||
@ -142,7 +142,7 @@ void EclipseIO::Impl::writeINITFile(const data::Solution& simP
|
||||
}
|
||||
|
||||
|
||||
void EclipseIO::Impl::writeEGRIDFile( const NNC& nnc ) {
|
||||
void EclipseIO::Impl::writeEGRIDFile( const std::vector<NNCdata>& nnc ) {
|
||||
const auto formatted = this->es.cfg().io().getFMTOUT();
|
||||
|
||||
const auto ext = '.'
|
||||
@ -168,7 +168,7 @@ int_data: Writes key(string) and integers vector to INIT file as eclipse keyword
|
||||
- Key: Max 8 chars.
|
||||
- Wrong input: invalid_argument exception.
|
||||
*/
|
||||
void EclipseIO::writeInitial( data::Solution simProps, std::map<std::string, std::vector<int> > int_data, const NNC& nnc) {
|
||||
void EclipseIO::writeInitial( data::Solution simProps, std::map<std::string, std::vector<int> > int_data, const std::vector<NNCdata>& nnc) {
|
||||
if( !this->impl->output_enabled )
|
||||
return;
|
||||
|
||||
|
@ -544,14 +544,14 @@ namespace {
|
||||
}
|
||||
}
|
||||
|
||||
void writeNonNeighbourConnections(const ::Opm::NNC& nnc,
|
||||
const ::Opm::UnitSystem& units,
|
||||
::Opm::EclIO::OutputStream::Init& initFile)
|
||||
void writeNonNeighbourConnections(const std::vector<::Opm::NNCdata>& nnc,
|
||||
const ::Opm::UnitSystem& units,
|
||||
::Opm::EclIO::OutputStream::Init& initFile)
|
||||
{
|
||||
auto tran = std::vector<double>{};
|
||||
tran.reserve(nnc.numNNC());
|
||||
tran.reserve(nnc.size());
|
||||
|
||||
for (const auto& nd : nnc.data()) {
|
||||
for (const auto& nd : nnc) {
|
||||
tran.push_back(nd.trans);
|
||||
}
|
||||
|
||||
@ -566,7 +566,7 @@ void Opm::InitIO::write(const ::Opm::EclipseState& es,
|
||||
const ::Opm::Schedule& schedule,
|
||||
const ::Opm::data::Solution& simProps,
|
||||
std::map<std::string, std::vector<int>> int_data,
|
||||
const ::Opm::NNC& nnc,
|
||||
const std::vector<::Opm::NNCdata>& nnc,
|
||||
::Opm::EclIO::OutputStream::Init& initFile)
|
||||
{
|
||||
const auto& units = es.getUnits();
|
||||
@ -587,7 +587,7 @@ void Opm::InitIO::write(const ::Opm::EclipseState& es,
|
||||
writeIntegerMaps(std::move(int_data), initFile);
|
||||
writeSatFuncScaling(es, units, initFile);
|
||||
|
||||
if (nnc.numNNC() > std::size_t{0}) {
|
||||
if (!nnc.empty()) {
|
||||
writeNonNeighbourConnections(nnc, units, initFile);
|
||||
}
|
||||
}
|
||||
|
@ -57,9 +57,8 @@ namespace Opm {
|
||||
m_runspec( deck ),
|
||||
m_eclipseConfig( deck ),
|
||||
m_deckUnitSystem( deck.getActiveUnitSystem() ),
|
||||
m_inputNnc( deck ),
|
||||
m_inputEditNnc( deck ),
|
||||
m_inputGrid( deck, nullptr ),
|
||||
m_inputNnc( m_inputGrid, deck),
|
||||
m_gridDims( deck ),
|
||||
field_props( deck, m_runspec.phases(), m_inputGrid, m_tables),
|
||||
m_simulationConfig( m_eclipseConfig.getInitConfig().restartRequested(), deck, field_props),
|
||||
@ -177,16 +176,9 @@ namespace Opm {
|
||||
}
|
||||
|
||||
bool EclipseState::hasInputNNC() const {
|
||||
return m_inputNnc.hasNNC();
|
||||
return !m_inputNnc.input().empty();
|
||||
}
|
||||
|
||||
const EDITNNC& EclipseState::getInputEDITNNC() const {
|
||||
return m_inputEditNnc;
|
||||
}
|
||||
|
||||
bool EclipseState::hasInputEDITNNC() const {
|
||||
return !m_inputEditNnc.empty();
|
||||
}
|
||||
std::string EclipseState::getTitle() const {
|
||||
return m_title;
|
||||
}
|
||||
|
@ -1,101 +0,0 @@
|
||||
|
||||
#include <array>
|
||||
#include <sstream>
|
||||
#include <opm/parser/eclipse/Deck/Deck.hpp>
|
||||
#include <opm/parser/eclipse/Deck/DeckItem.hpp>
|
||||
#include <opm/parser/eclipse/Deck/DeckKeyword.hpp>
|
||||
#include <opm/parser/eclipse/Deck/DeckRecord.hpp>
|
||||
#include <opm/parser/eclipse/EclipseState/Grid/EclipseGrid.hpp>
|
||||
#include <opm/parser/eclipse/EclipseState/Grid/GridDims.hpp>
|
||||
#include <opm/parser/eclipse/EclipseState/Edit/EDITNNC.hpp>
|
||||
#include <opm/parser/eclipse/Parser/ParserKeywords/E.hpp>
|
||||
#include <opm/common/OpmLog/OpmLog.hpp>
|
||||
|
||||
|
||||
namespace Opm
|
||||
{
|
||||
|
||||
bool isNeighbor(const std::array<size_t, 3>& ijk1, const std::array<size_t, 3>& ijk2)
|
||||
{
|
||||
if ( (ijk1[0] + 1) == ijk2[0] || (ijk1[0] - 1) == ijk2[0] )
|
||||
{
|
||||
return ijk1[1] == ijk2[1] && ijk1[2] == ijk2[2];
|
||||
}
|
||||
if ( (ijk1[1] + 1) == ijk2[1] || (ijk1[1] - 1) == ijk2[1] )
|
||||
{
|
||||
return ijk1[0] == ijk2[0] && ijk1[2] == ijk2[2];
|
||||
}
|
||||
if( (ijk1[2] + 1) == ijk2[2] || (ijk1[2] - 1) == ijk2[2] )
|
||||
{
|
||||
return ijk1[1] == ijk2[1] && ijk1[1] == ijk2[1];
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
void readEditNncs(const std::vector< const DeckKeyword* >& editNncsKw, std::vector<NNCdata>& editNncs, const GridDims& gridDims)
|
||||
{
|
||||
for (size_t idx_nnc = 0; idx_nnc<editNncsKw.size(); ++idx_nnc) {
|
||||
const auto& nnc = *editNncsKw[idx_nnc];
|
||||
editNncs.reserve(editNncs.size()+nnc.size());
|
||||
for (size_t i = 0; i < nnc.size(); ++i) {
|
||||
std::array<size_t, 3> ijk1;
|
||||
ijk1[0] = static_cast<size_t>(nnc.getRecord(i).getItem(0).get< int >(0)-1);
|
||||
ijk1[1] = static_cast<size_t>(nnc.getRecord(i).getItem(1).get< int >(0)-1);
|
||||
ijk1[2] = static_cast<size_t>(nnc.getRecord(i).getItem(2).get< int >(0)-1);
|
||||
size_t global_index1 = gridDims.getGlobalIndex(ijk1[0],ijk1[1],ijk1[2]);
|
||||
|
||||
std::array<size_t, 3> ijk2;
|
||||
ijk2[0] = static_cast<size_t>(nnc.getRecord(i).getItem(3).get< int >(0)-1);
|
||||
ijk2[1] = static_cast<size_t>(nnc.getRecord(i).getItem(4).get< int >(0)-1);
|
||||
ijk2[2] = static_cast<size_t>(nnc.getRecord(i).getItem(5).get< int >(0)-1);
|
||||
size_t global_index2 = gridDims.getGlobalIndex(ijk2[0],ijk2[1],ijk2[2]);
|
||||
|
||||
const double trans = nnc.getRecord(i).getItem(6).get<double>(0);
|
||||
using std::abs;
|
||||
if ( !isNeighbor(ijk1, ijk2) )
|
||||
{
|
||||
editNncs.emplace_back(global_index1, global_index2, trans);
|
||||
}
|
||||
else
|
||||
{
|
||||
std::ostringstream sstr;
|
||||
sstr << "Cannot edit neighboring connection from " << global_index1 <<" to "<<
|
||||
global_index2<< " with EDITNNC";
|
||||
Opm::OpmLog::warning(sstr.str());
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
EDITNNC::EDITNNC(const Deck& deck)
|
||||
{
|
||||
GridDims gridDims(deck);
|
||||
const auto& tmpEditNncs = deck.getKeywordList<ParserKeywords::EDITNNC>();
|
||||
readEditNncs(tmpEditNncs, m_editnnc, gridDims);
|
||||
auto compare = [](const NNCdata& d1, const NNCdata& d2)
|
||||
{ return d1.cell1 < d2.cell1 ||
|
||||
( d1.cell1 == d2.cell1 && d1.cell2 < d2.cell2 );};
|
||||
std::sort(m_editnnc.begin(), m_editnnc.end(), compare);
|
||||
}
|
||||
|
||||
EDITNNC EDITNNC::serializeObject()
|
||||
{
|
||||
EDITNNC result;
|
||||
result.m_editnnc = {{1,2,1.0},{2,3,2.0}};
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
size_t EDITNNC::size() const {
|
||||
return(m_editnnc.size());
|
||||
}
|
||||
|
||||
bool EDITNNC::empty() const {
|
||||
return m_editnnc.empty();
|
||||
}
|
||||
|
||||
bool EDITNNC::operator==(const EDITNNC& data) const {
|
||||
return m_editnnc == data.m_editnnc;
|
||||
}
|
||||
|
||||
} // namespace Opm
|
@ -1558,7 +1558,7 @@ std::vector<double> EclipseGrid::createDVector(const std::array<int,3>& dims, st
|
||||
return m_zcorn;
|
||||
}
|
||||
|
||||
void EclipseGrid::save(const std::string& filename, bool formatted, const Opm::NNC& nnc, const Opm::UnitSystem& units) const {
|
||||
void EclipseGrid::save(const std::string& filename, bool formatted, const std::vector<Opm::NNCdata>& nnc, const Opm::UnitSystem& units) const {
|
||||
|
||||
Opm::UnitSystem::UnitType unitSystemType = units.getType();
|
||||
const auto length = ::Opm::UnitSystem::measure::length;
|
||||
@ -1601,7 +1601,7 @@ std::vector<double> EclipseGrid::createDVector(const std::array<int,3>& dims, st
|
||||
std::vector<int> nnc1;
|
||||
std::vector<int> nnc2;
|
||||
|
||||
for (const NNCdata& n : nnc.data() ) {
|
||||
for (const NNCdata& n : nnc ) {
|
||||
nnc1.push_back(n.cell1 + 1);
|
||||
nnc2.push_back(n.cell2 + 1);
|
||||
}
|
||||
|
@ -1,18 +1,18 @@
|
||||
/*
|
||||
Copyright 2015 IRIS
|
||||
|
||||
|
||||
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/>.
|
||||
*/
|
||||
@ -23,64 +23,218 @@
|
||||
#include <opm/parser/eclipse/Deck/DeckKeyword.hpp>
|
||||
#include <opm/parser/eclipse/Deck/DeckRecord.hpp>
|
||||
#include <opm/parser/eclipse/EclipseState/Grid/EclipseGrid.hpp>
|
||||
#include <opm/parser/eclipse/EclipseState/Grid/GridDims.hpp>
|
||||
#include <opm/parser/eclipse/EclipseState/Grid/NNC.hpp>
|
||||
#include <opm/parser/eclipse/Parser/ParserKeywords/E.hpp>
|
||||
#include <opm/parser/eclipse/Parser/ParserKeywords/N.hpp>
|
||||
|
||||
|
||||
namespace Opm
|
||||
{
|
||||
NNC::NNC(const Deck& deck) {
|
||||
GridDims gridDims(deck);
|
||||
const auto& nncs = deck.getKeywordList<ParserKeywords::NNC>();
|
||||
for (size_t idx_nnc = 0; idx_nnc<nncs.size(); ++idx_nnc) {
|
||||
const auto& nnc = *nncs[idx_nnc];
|
||||
for (size_t i = 0; i < nnc.size(); ++i) {
|
||||
std::array<size_t, 3> ijk1;
|
||||
ijk1[0] = static_cast<size_t>(nnc.getRecord(i).getItem(0).get< int >(0)-1);
|
||||
ijk1[1] = static_cast<size_t>(nnc.getRecord(i).getItem(1).get< int >(0)-1);
|
||||
ijk1[2] = static_cast<size_t>(nnc.getRecord(i).getItem(2).get< int >(0)-1);
|
||||
size_t global_index1 = gridDims.getGlobalIndex(ijk1[0],ijk1[1],ijk1[2]);
|
||||
|
||||
std::array<size_t, 3> ijk2;
|
||||
ijk2[0] = static_cast<size_t>(nnc.getRecord(i).getItem(3).get< int >(0)-1);
|
||||
ijk2[1] = static_cast<size_t>(nnc.getRecord(i).getItem(4).get< int >(0)-1);
|
||||
ijk2[2] = static_cast<size_t>(nnc.getRecord(i).getItem(5).get< int >(0)-1);
|
||||
size_t global_index2 = gridDims.getGlobalIndex(ijk2[0],ijk2[1],ijk2[2]);
|
||||
|
||||
const double trans = nnc.getRecord(i).getItem(6).getSIDouble(0);
|
||||
|
||||
addNNC(global_index1,global_index2,trans);
|
||||
|
||||
namespace {
|
||||
|
||||
std::optional<std::size_t> global_index(const EclipseGrid& grid, const DeckRecord& record, std::size_t item_offset) {
|
||||
std::size_t i = static_cast<size_t>(record.getItem(0 + item_offset).get< int >(0)-1);
|
||||
std::size_t j = static_cast<size_t>(record.getItem(1 + item_offset).get< int >(0)-1);
|
||||
std::size_t k = static_cast<size_t>(record.getItem(2 + item_offset).get< int >(0)-1);
|
||||
|
||||
if (i >= grid.getNX())
|
||||
return {};
|
||||
|
||||
if (j >= grid.getNY())
|
||||
return {};
|
||||
|
||||
if (k >= grid.getNZ())
|
||||
return {};
|
||||
|
||||
if (!grid.cellActive(i,j,k))
|
||||
return {};
|
||||
|
||||
return grid.getGlobalIndex(i,j,k);
|
||||
}
|
||||
|
||||
|
||||
std::optional<std::pair<std::size_t, std::size_t>> make_index_pair(const EclipseGrid& grid, const DeckRecord& record) {
|
||||
auto g1 = global_index(grid, record, 0);
|
||||
auto g2 = global_index(grid, record, 3);
|
||||
if (!g1)
|
||||
return {};
|
||||
|
||||
if (!g2)
|
||||
return {};
|
||||
|
||||
if (*g1 < *g2)
|
||||
return std::make_pair(*g1, *g2);
|
||||
else
|
||||
return std::make_pair(*g2, *g1);
|
||||
}
|
||||
|
||||
bool is_neighbor(const EclipseGrid& grid, std::size_t g1, std::size_t g2) {
|
||||
auto diff = g2 - g1;
|
||||
if (diff == 0)
|
||||
return true;
|
||||
|
||||
if (diff == 1)
|
||||
return true;
|
||||
|
||||
if (diff == grid.getNX())
|
||||
return true;
|
||||
|
||||
if (diff == grid.getNY())
|
||||
return true;
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
NNC::NNC(const EclipseGrid& grid, const Deck& deck) {
|
||||
this->load_input(grid, deck);
|
||||
this->load_edit(grid, deck);
|
||||
}
|
||||
|
||||
|
||||
void NNC::load_input(const EclipseGrid& grid, const Deck& deck) {
|
||||
for (const auto& keyword_ptr : deck.getKeywordList<ParserKeywords::NNC>()) {
|
||||
for (const auto& record : *keyword_ptr) {
|
||||
auto index_pair = make_index_pair(grid, record);
|
||||
if (!index_pair)
|
||||
continue;
|
||||
|
||||
auto [g1, g2] = index_pair.value();
|
||||
double trans = record.getItem(6).getSIDouble(0);
|
||||
this->m_input.emplace_back(g1, g2, trans);
|
||||
}
|
||||
|
||||
if (!this->m_nnc_location)
|
||||
this->m_nnc_location = keyword_ptr->location();
|
||||
}
|
||||
|
||||
std::sort(this->m_input.begin(), this->m_input.end());
|
||||
}
|
||||
|
||||
|
||||
void NNC::load_edit(const EclipseGrid& grid, const Deck& deck) {
|
||||
std::vector<NNCdata> nnc_edit;
|
||||
for (const auto& keyword_ptr : deck.getKeywordList<ParserKeywords::EDITNNC>()) {
|
||||
for (const auto& record : *keyword_ptr) {
|
||||
double tran_mult = record.getItem(6).get<double>(0);
|
||||
if (tran_mult == 1.0)
|
||||
continue;
|
||||
|
||||
auto index_pair = make_index_pair(grid, record);
|
||||
if (!index_pair)
|
||||
continue;
|
||||
|
||||
auto [g1, g2] = index_pair.value();
|
||||
if (is_neighbor(grid, g1, g2))
|
||||
continue;
|
||||
|
||||
nnc_edit.emplace_back( g1, g2, tran_mult);
|
||||
}
|
||||
|
||||
if (!this->m_edit_location)
|
||||
this->m_edit_location = keyword_ptr->location();
|
||||
}
|
||||
|
||||
std::sort(nnc_edit.begin(), nnc_edit.end());
|
||||
|
||||
auto current_input = this->m_input.begin();
|
||||
for (const auto& current_edit : nnc_edit) {
|
||||
if (current_input == this->m_input.end()) {
|
||||
this->add_edit(current_edit);
|
||||
continue;
|
||||
}
|
||||
|
||||
if (current_input->cell1 != current_edit.cell1 || current_input->cell2 != current_edit.cell2) {
|
||||
current_input = std::lower_bound(this->m_input.begin(),
|
||||
this->m_input.end(),
|
||||
NNCdata(current_edit.cell1, current_edit.cell2, 0));
|
||||
if (current_input == this->m_input.end()) {
|
||||
this->add_edit(current_edit);
|
||||
continue;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
bool edit_processed = false;
|
||||
while (current_input != this->m_input.end()
|
||||
&& current_input->cell1 == current_edit.cell1
|
||||
&& current_input->cell2 == current_edit.cell2)
|
||||
{
|
||||
current_input->trans *= current_edit.trans;
|
||||
++current_input;
|
||||
edit_processed = true;
|
||||
}
|
||||
|
||||
if (!edit_processed)
|
||||
this->add_edit(current_edit);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
NNC NNC::serializeObject()
|
||||
{
|
||||
NNC result;
|
||||
result.m_nnc = {{1,2,1.0},{2,3,2.0}};
|
||||
|
||||
result.m_input= {{1,2,1.0},{2,3,2.0}};
|
||||
result.m_edit= {{1,2,1.0},{2,3,2.0}};
|
||||
result.m_nnc_location = {"NNC?", "File", 123};
|
||||
result.m_edit_location = {"EDITNNC?", "File", 123};
|
||||
return result;
|
||||
}
|
||||
|
||||
void NNC::addNNC(const size_t cell1, const size_t cell2, const double trans) {
|
||||
NNCdata tmp;
|
||||
tmp.cell1 = cell1;
|
||||
tmp.cell2 = cell2;
|
||||
tmp.trans = trans;
|
||||
m_nnc.push_back(tmp);
|
||||
}
|
||||
bool NNC::addNNC(const size_t cell1, const size_t cell2, const double trans) {
|
||||
if (cell1 > cell2)
|
||||
return this->addNNC(cell2, cell1, trans);
|
||||
|
||||
size_t NNC::numNNC() const {
|
||||
return(m_nnc.size());
|
||||
}
|
||||
|
||||
bool NNC::hasNNC() const {
|
||||
return m_nnc.size()>0;
|
||||
auto nnc = NNCdata(cell1, cell2, trans);
|
||||
auto insert_iter = std::lower_bound(this->m_input.begin(), this->m_input.end(), nnc);
|
||||
this->m_input.insert( insert_iter, nnc);
|
||||
return true;
|
||||
}
|
||||
|
||||
bool NNC::operator==(const NNC& data) const {
|
||||
return m_nnc == data.m_nnc;
|
||||
return m_input == data.m_input &&
|
||||
m_edit == data.m_edit &&
|
||||
m_edit_location == data.m_edit_location &&
|
||||
m_nnc_location == data.m_nnc_location;
|
||||
|
||||
}
|
||||
|
||||
void NNC::add_edit(const NNCdata& edit_node) {
|
||||
if (!this->m_edit.empty()) {
|
||||
auto& back = this->m_edit.back();
|
||||
if (back.cell1 == edit_node.cell1 && back.cell2 == edit_node.cell2) {
|
||||
back.trans *= edit_node.trans;
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
this->m_edit.push_back(edit_node);
|
||||
}
|
||||
|
||||
|
||||
|
||||
/*
|
||||
In principle we can have multiple NNC keywords, and to provide a good error
|
||||
message we should be able to return the location of the offending NNC. That
|
||||
will require some bookkeeping of which NNC originated in which NNC
|
||||
keyword/location. For now we just return the location of the first NNC
|
||||
keyword, but we should be ready for a more elaborate implementation without
|
||||
any API change.
|
||||
*/
|
||||
KeywordLocation NNC::input_location([[maybe_unused]] const NNCdata& nnc) const {
|
||||
if (this->m_nnc_location)
|
||||
return *this->m_nnc_location;
|
||||
else
|
||||
return {};
|
||||
}
|
||||
|
||||
|
||||
KeywordLocation NNC::edit_location([[maybe_unused]] const NNCdata& nnc) const {
|
||||
if (this->m_edit_location)
|
||||
return *this->m_edit_location;
|
||||
else
|
||||
return {};
|
||||
}
|
||||
|
||||
} // namespace Opm
|
||||
|
@ -1686,7 +1686,7 @@ BOOST_AUTO_TEST_CASE(SAVE_FIELD_UNITS) {
|
||||
|
||||
const auto& grid1 = es.getInputGrid();
|
||||
|
||||
Opm::NNC nnc( deck );
|
||||
Opm::NNC nnc(grid1, deck);
|
||||
bool formatted = false;
|
||||
|
||||
time_t timer;
|
||||
@ -1702,7 +1702,7 @@ BOOST_AUTO_TEST_CASE(SAVE_FIELD_UNITS) {
|
||||
Opm::filesystem::create_directory(testDir);
|
||||
|
||||
std::string fileName = testDir + "/" + "TMP.EGRID";
|
||||
grid1.save(fileName, formatted, nnc, units);
|
||||
grid1.save(fileName, formatted, nnc.input(), units);
|
||||
|
||||
Opm::EclIO::EclFile file1(fileName);
|
||||
|
||||
@ -1757,13 +1757,13 @@ BOOST_AUTO_TEST_CASE(SAVE_FIELD_UNITS) {
|
||||
|
||||
Opm::EclipseState es2(deck2);
|
||||
Opm::UnitSystem units2 = es.getDeckUnitSystem();
|
||||
Opm::NNC nnc2( deck2 );
|
||||
|
||||
const auto& grid2 = es2.getInputGrid();
|
||||
Opm::NNC nnc2(grid2, deck2 );
|
||||
|
||||
|
||||
std::string fileName2 = testDir + "/" + "TMP2.FEGRID";
|
||||
|
||||
grid2.save(fileName2, true, nnc2, units);
|
||||
grid2.save(fileName2, true, nnc2.input(), units);
|
||||
|
||||
Opm::EclIO::EclFile file2(fileName2);
|
||||
|
||||
@ -1783,13 +1783,13 @@ BOOST_AUTO_TEST_CASE(SAVE_FIELD_UNITS) {
|
||||
|
||||
Opm::EclipseState es3(deck3);
|
||||
Opm::UnitSystem units3 = es.getDeckUnitSystem();
|
||||
Opm::NNC nnc3( deck3 );
|
||||
|
||||
const auto& grid3 = es3.getInputGrid();
|
||||
Opm::NNC nnc3(grid3, deck3);
|
||||
|
||||
|
||||
std::string fileName3 = testDir + "/" + "TMP3.FEGRID";
|
||||
|
||||
grid3.save(fileName3, true, nnc3, units3);
|
||||
grid3.save(fileName3, true, nnc3.input(), units3);
|
||||
|
||||
Opm::EclIO::EclFile file3(fileName3);
|
||||
|
||||
@ -1878,7 +1878,7 @@ BOOST_AUTO_TEST_CASE(SAVE_METRIC_UNITS) {
|
||||
const auto length = ::Opm::UnitSystem::measure::length;
|
||||
|
||||
const auto& grid1 = es1.getInputGrid();
|
||||
Opm::NNC nnc( deck1 );
|
||||
Opm::NNC nnc(grid1, deck1);
|
||||
|
||||
bool formatted = true;
|
||||
|
||||
@ -1895,7 +1895,7 @@ BOOST_AUTO_TEST_CASE(SAVE_METRIC_UNITS) {
|
||||
Opm::filesystem::create_directory(testDir);
|
||||
|
||||
std::string fileName = testDir + "/" + "TMP.FEGRID";
|
||||
grid1.save(fileName, formatted, nnc, units1);
|
||||
grid1.save(fileName, formatted, nnc.input(), units1);
|
||||
|
||||
Opm::EclIO::EclFile file1(fileName);
|
||||
|
||||
@ -1949,7 +1949,7 @@ BOOST_AUTO_TEST_CASE(SAVE_METRIC_UNITS) {
|
||||
BOOST_CHECK( file1.hasKey("NNCHEAD"));
|
||||
const std::vector<int> nnchead = file1.get<int>("NNCHEAD");
|
||||
|
||||
BOOST_CHECK( nnchead[0] == static_cast<int>(nnc.numNNC()) );
|
||||
BOOST_CHECK( nnchead[0] == static_cast<int>(nnc.input().size()) );
|
||||
|
||||
std::vector<int> ref_nnc1 = { 6, 7, 8 };
|
||||
std::vector<int> ref_nnc2 = { 26, 27, 28 };
|
||||
@ -1981,7 +1981,7 @@ BOOST_AUTO_TEST_CASE(SAVE_METRIC_UNITS) {
|
||||
|
||||
std::string fileName2 = testDir + "/" + "TMP2.FEGRID";
|
||||
|
||||
grid2.save(fileName2, true, nnc, units2);
|
||||
grid2.save(fileName2, true, nnc.input(), units2);
|
||||
|
||||
Opm::EclIO::EclFile file2(fileName2);
|
||||
|
||||
@ -2588,16 +2588,16 @@ BOOST_AUTO_TEST_CASE(TEST_GDFILE_2) {
|
||||
Opm::UnitSystem units1a = es1a.getDeckUnitSystem();
|
||||
|
||||
const auto& grid1a = es1a.getInputGrid();
|
||||
Opm::NNC nnc( deck1a );
|
||||
Opm::NNC nnc(grid1a, deck1a);
|
||||
|
||||
grid1a.save("BAD_CP_M.EGRID", false, nnc, units1a);
|
||||
grid1a.save("BAD_CP_M.EGRID", false, nnc.input(), units1a);
|
||||
|
||||
auto deck1b = parser.parseString( deckData1b) ;
|
||||
Opm::EclipseState es1b( deck1b );
|
||||
Opm::UnitSystem units1b = es1b.getDeckUnitSystem();
|
||||
const auto& grid1b = es1b.getInputGrid();
|
||||
|
||||
grid1b.save("BAD_CP_F.EGRID", false, nnc, units1b);
|
||||
grid1b.save("BAD_CP_F.EGRID", false, nnc.input(), units1b);
|
||||
|
||||
auto deck1 = parser.parseString( deckData1) ;
|
||||
Opm::EclipseGrid grid1( deck1);
|
||||
|
@ -1,43 +0,0 @@
|
||||
RUNSPEC
|
||||
|
||||
OIL
|
||||
GAS
|
||||
WATER
|
||||
|
||||
|
||||
DIMENS
|
||||
10 10 1 /
|
||||
|
||||
GRID
|
||||
|
||||
DXV
|
||||
10*1000.0
|
||||
/
|
||||
|
||||
DYV
|
||||
10*1000.0
|
||||
/
|
||||
|
||||
DZ
|
||||
100*20.0
|
||||
/
|
||||
|
||||
TOPS
|
||||
100*10
|
||||
/
|
||||
|
||||
PORO
|
||||
100*0.15 /
|
||||
|
||||
EDIT
|
||||
|
||||
EDITNNC
|
||||
3 1 1 1 1 1 0.1 /
|
||||
1 1 1 1 2 1 0.01 /
|
||||
2 1 1 2 3 1 0.1 /
|
||||
/
|
||||
|
||||
EDITNNC
|
||||
1 1 1 2 1 1 0.1 /
|
||||
2 1 1 2 3 1 0.1 /
|
||||
/
|
@ -1,40 +0,0 @@
|
||||
RUNSPEC
|
||||
|
||||
OIL
|
||||
GAS
|
||||
WATER
|
||||
|
||||
|
||||
DIMENS
|
||||
10 10 1 /
|
||||
|
||||
GRID
|
||||
|
||||
DXV
|
||||
10*1000.0
|
||||
/
|
||||
|
||||
DYV
|
||||
10*1000.0
|
||||
/
|
||||
|
||||
DZ
|
||||
100*20.0
|
||||
/
|
||||
|
||||
TOPS
|
||||
100*10
|
||||
/
|
||||
|
||||
PORO
|
||||
100*0.15 /
|
||||
|
||||
NNC
|
||||
1 1 1 2 1 1 0.5 /
|
||||
1 1 1 1 2 1 1.0 /
|
||||
/
|
||||
|
||||
NNC
|
||||
1 1 1 2 1 1 0.5 /
|
||||
1 2 1 1 2 1 1.0 /
|
||||
/
|
@ -1,30 +0,0 @@
|
||||
RUNSPEC
|
||||
|
||||
OIL
|
||||
GAS
|
||||
WATER
|
||||
|
||||
|
||||
DIMENS
|
||||
10 10 1 /
|
||||
|
||||
GRID
|
||||
|
||||
DXV
|
||||
10*1000.0
|
||||
/
|
||||
|
||||
DYV
|
||||
10*1000.0
|
||||
/
|
||||
|
||||
DZ
|
||||
100*20.0
|
||||
/
|
||||
|
||||
TOPS
|
||||
100*10
|
||||
/
|
||||
|
||||
PORO
|
||||
100*0.15 /
|
@ -1,69 +0,0 @@
|
||||
/*
|
||||
Copyright 2015 IRIS
|
||||
Copyright 2018 Equinor AS
|
||||
|
||||
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/Edit/EDITNNC.hpp>
|
||||
#include <opm/parser/eclipse/Parser/Parser.hpp>
|
||||
#include <opm/parser/eclipse/Deck/Deck.hpp>
|
||||
#include <opm/parser/eclipse/EclipseState/Grid/EclipseGrid.hpp>
|
||||
#include <opm/parser/eclipse/EclipseState/EclipseState.hpp>
|
||||
#include <opm/parser/eclipse/Units/Units.hpp>
|
||||
|
||||
#define BOOST_TEST_MODULE NNCTests
|
||||
|
||||
#include <boost/test/unit_test.hpp>
|
||||
|
||||
using namespace Opm;
|
||||
|
||||
inline std::string pathprefix() {
|
||||
return boost::unit_test::framework::master_test_suite().argv[1];
|
||||
}
|
||||
|
||||
BOOST_AUTO_TEST_CASE(noNNC)
|
||||
{
|
||||
Parser parser;
|
||||
auto deck = parser.parseFile(pathprefix() + "NNC/noNNC.DATA");
|
||||
EclipseState eclipseState(deck);
|
||||
const auto& editnnc = eclipseState.getInputEDITNNC();
|
||||
BOOST_CHECK(!eclipseState.hasInputEDITNNC());
|
||||
BOOST_CHECK(editnnc.empty());
|
||||
}
|
||||
|
||||
BOOST_AUTO_TEST_CASE(readDeck)
|
||||
{
|
||||
Parser parser;
|
||||
auto deck = parser.parseFile(pathprefix() + "EDITNNC/EDITNNC.DATA");
|
||||
EclipseState eclipseState(deck);
|
||||
const auto& editnnc = eclipseState.getInputEDITNNC();
|
||||
BOOST_CHECK(!editnnc.empty());
|
||||
const std::vector<NNCdata>& data = editnnc.data();
|
||||
|
||||
// test the NNCs in nnc.DATA
|
||||
BOOST_CHECK_EQUAL(editnnc.size(), 3); //neighbouring connections in EDITNNC are ignored
|
||||
BOOST_CHECK_EQUAL(data[0].cell1, 1);
|
||||
BOOST_CHECK_EQUAL(data[0].cell2, 21);
|
||||
BOOST_CHECK_EQUAL(data[0].trans, 0.1);
|
||||
BOOST_CHECK_EQUAL(data[1].cell1, 1);
|
||||
BOOST_CHECK_EQUAL(data[1].cell2, 21);
|
||||
BOOST_CHECK_EQUAL(data[1].trans, 0.1);
|
||||
BOOST_CHECK_EQUAL(data[2].cell1, 2);
|
||||
BOOST_CHECK_EQUAL(data[2].cell2, 0);
|
||||
BOOST_CHECK_EQUAL(data[2].trans, 0.1);
|
||||
|
||||
}
|
@ -20,7 +20,7 @@
|
||||
#include <opm/parser/eclipse/EclipseState/Grid/NNC.hpp>
|
||||
#include <opm/parser/eclipse/Parser/Parser.hpp>
|
||||
#include <opm/parser/eclipse/Deck/Deck.hpp>
|
||||
#include <opm/parser/eclipse/EclipseState/Grid/EclipseGrid.hpp>
|
||||
#include <opm/parser/eclipse/EclipseState/Grid/GridDims.hpp>
|
||||
#include <opm/parser/eclipse/EclipseState/EclipseState.hpp>
|
||||
#include <opm/parser/eclipse/Units/Units.hpp>
|
||||
|
||||
@ -30,67 +30,330 @@
|
||||
|
||||
using namespace Opm;
|
||||
|
||||
inline std::string pathprefix() {
|
||||
return boost::unit_test::framework::master_test_suite().argv[1];
|
||||
|
||||
const std::string no_nnc_input = R"(
|
||||
RUNSPEC
|
||||
|
||||
OIL
|
||||
GAS
|
||||
WATER
|
||||
|
||||
|
||||
DIMENS
|
||||
10 10 1 /
|
||||
|
||||
GRID
|
||||
|
||||
DXV
|
||||
10*1000.0
|
||||
/
|
||||
|
||||
DYV
|
||||
10*1000.0
|
||||
/
|
||||
|
||||
DZ
|
||||
100*20.0
|
||||
/
|
||||
|
||||
TOPS
|
||||
100*10
|
||||
/
|
||||
|
||||
PORO
|
||||
100*0.15 /
|
||||
)";
|
||||
|
||||
const std::string actnum = R"(
|
||||
RUNSPEC
|
||||
|
||||
OIL
|
||||
GAS
|
||||
WATER
|
||||
|
||||
|
||||
DIMENS
|
||||
10 10 1 /
|
||||
|
||||
GRID
|
||||
|
||||
DXV
|
||||
10*1000.0
|
||||
/
|
||||
|
||||
DYV
|
||||
10*1000.0
|
||||
/
|
||||
|
||||
DZ
|
||||
100*20.0
|
||||
/
|
||||
|
||||
TOPS
|
||||
100*10
|
||||
/
|
||||
|
||||
ACTNUM
|
||||
10*0 90*1
|
||||
/
|
||||
|
||||
NNC
|
||||
1 1 1 1 3 1 0.5 / -- Inactive cell
|
||||
3 1 1 3 3 1 0.5 / -- Inactive cell
|
||||
2 2 1 3 3 1 1.0 / -- Valid
|
||||
100 100 100 200 200 200 1.0 / -- Very invalid
|
||||
/
|
||||
|
||||
PORO
|
||||
100*0.15 /
|
||||
|
||||
EDIT
|
||||
|
||||
EDITNNC
|
||||
5 1 1 1 5 3 0.5 / -- Inactive cell
|
||||
2 2 1 3 3 1 0.5 / -- Valid - coupled to NNC
|
||||
4 4 1 5 5 1 2.0 / -- Valid
|
||||
-1 4 4 -1 7 7 1.0 / -- Very invalid
|
||||
/
|
||||
|
||||
)";
|
||||
|
||||
|
||||
|
||||
|
||||
const std::string nnc_input = R"(
|
||||
RUNSPEC
|
||||
|
||||
OIL
|
||||
GAS
|
||||
WATER
|
||||
|
||||
|
||||
DIMENS
|
||||
10 10 1 /
|
||||
|
||||
GRID
|
||||
|
||||
DXV
|
||||
10*1000.0
|
||||
/
|
||||
|
||||
DYV
|
||||
10*1000.0
|
||||
/
|
||||
|
||||
DZ
|
||||
100*20.0
|
||||
/
|
||||
|
||||
TOPS
|
||||
100*10
|
||||
/
|
||||
|
||||
PORO
|
||||
100*0.15 /
|
||||
|
||||
NNC
|
||||
1 1 1 2 1 1 0.5 /
|
||||
1 1 1 1 2 1 1.0 /
|
||||
/
|
||||
|
||||
NNC
|
||||
1 1 1 2 1 1 0.5 /
|
||||
1 2 1 1 2 1 1.0 /
|
||||
/
|
||||
)";
|
||||
|
||||
|
||||
|
||||
const std::string editnnc_input = R"(
|
||||
RUNSPEC
|
||||
|
||||
OIL
|
||||
GAS
|
||||
WATER
|
||||
|
||||
|
||||
DIMENS
|
||||
10 10 1 /
|
||||
|
||||
GRID
|
||||
|
||||
NNC
|
||||
7 1 1 3 1 1 0.1 /
|
||||
3 1 1 5 1 1 0.1 /
|
||||
/
|
||||
|
||||
|
||||
DXV
|
||||
10*1000.0
|
||||
/
|
||||
|
||||
DYV
|
||||
10*1000.0
|
||||
/
|
||||
|
||||
DZ
|
||||
100*20.0
|
||||
/
|
||||
|
||||
TOPS
|
||||
100*10
|
||||
/
|
||||
|
||||
PORO
|
||||
100*0.15 /
|
||||
|
||||
EDIT
|
||||
|
||||
|
||||
EDITNNC
|
||||
5 1 1 3 1 1 2.0 /
|
||||
3 1 1 1 1 1 0.1 /
|
||||
1 1 1 1 2 1 0.01 / -- This is ignored because the two cells are ijk neighbours
|
||||
2 1 1 2 3 1 0.2 /
|
||||
/
|
||||
|
||||
EDITNNC
|
||||
1 1 1 2 1 1 0.1 / -- Ignored
|
||||
2 1 1 2 3 1 0.3 /
|
||||
/
|
||||
)";
|
||||
|
||||
|
||||
std::optional<NNCdata> find_nnc(const std::vector<NNCdata>& v, std::size_t c1, std::size_t c2) {
|
||||
if (c1 > c2)
|
||||
return find_nnc(v, c2, c1);
|
||||
|
||||
auto iter = std::find_if(v.begin(), v.end(), [c1,c2](const NNCdata& nnc) { return nnc.cell1 == c1 && nnc.cell2 == c2; });
|
||||
if (iter != v.end())
|
||||
return *iter;
|
||||
|
||||
return {};
|
||||
}
|
||||
|
||||
void check_edit_nnc(const std::vector<NNCdata>& v, std::size_t c1, std::size_t c2, double t) {
|
||||
const auto& nnc = find_nnc(v, c1, c2);
|
||||
BOOST_REQUIRE(nnc.has_value());
|
||||
BOOST_CHECK_CLOSE(nnc->trans, t , 1e-6);
|
||||
}
|
||||
|
||||
void check_nnc(const std::vector<NNCdata>& v, std::size_t c1, std::size_t c2, double t) {
|
||||
check_edit_nnc(v, c1, c2, t*Opm::Metric::Transmissibility);
|
||||
}
|
||||
|
||||
bool has_nnc(const std::vector<NNCdata>& v, std::size_t c1, std::size_t c2) {
|
||||
const auto& nnc = find_nnc(v, c1, c2);
|
||||
return nnc.has_value();
|
||||
}
|
||||
|
||||
void check_order(const std::vector<NNCdata>& d) {
|
||||
for (const auto& nnc : d)
|
||||
BOOST_CHECK(nnc.cell1 <= nnc.cell2);
|
||||
|
||||
if (d.size() <= 1)
|
||||
return;
|
||||
|
||||
for (std::size_t index=1; index < d.size(); index++) {
|
||||
const auto& nnc1 = d[index - 1];
|
||||
const auto& nnc2 = d[index];
|
||||
|
||||
if (nnc1 < nnc2)
|
||||
continue;
|
||||
|
||||
BOOST_CHECK_EQUAL(nnc1.cell1, nnc2.cell1);
|
||||
BOOST_CHECK_EQUAL(nnc1.cell2, nnc2.cell2);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
void check_order(const NNC& nnc) {
|
||||
check_order(nnc.input());
|
||||
check_order(nnc.edit());
|
||||
}
|
||||
|
||||
|
||||
|
||||
BOOST_AUTO_TEST_CASE(noNNC)
|
||||
{
|
||||
Parser parser;
|
||||
auto deck = parser.parseFile(pathprefix() + "NNC/noNNC.DATA");
|
||||
auto deck = parser.parseString(no_nnc_input);
|
||||
EclipseState eclipseState(deck);
|
||||
const auto& nnc = eclipseState.getInputNNC();
|
||||
check_order(nnc);
|
||||
BOOST_CHECK(!eclipseState.hasInputNNC());
|
||||
BOOST_CHECK(!nnc.hasNNC());
|
||||
BOOST_CHECK(nnc.input().empty());
|
||||
}
|
||||
|
||||
BOOST_AUTO_TEST_CASE(readDeck)
|
||||
{
|
||||
Parser parser;
|
||||
auto deck = parser.parseFile(pathprefix() + "NNC/NNC.DATA");
|
||||
auto deck = parser.parseString(nnc_input);
|
||||
EclipseState eclipseState(deck);
|
||||
const auto& grid = eclipseState.getInputGrid();
|
||||
const auto& nnc = eclipseState.getInputNNC();
|
||||
BOOST_CHECK(nnc.hasNNC());
|
||||
const std::vector<NNCdata>& nncdata = nnc.data();
|
||||
check_order(nnc);
|
||||
BOOST_CHECK(!nnc.input().empty());
|
||||
const std::vector<NNCdata>& nncdata = nnc.input();
|
||||
|
||||
// test the NNCs in nnc.DATA
|
||||
BOOST_CHECK_EQUAL(nnc.numNNC(), 4);
|
||||
BOOST_CHECK_EQUAL(nncdata[0].cell1, 0);
|
||||
BOOST_CHECK_EQUAL(nncdata[0].cell2, 1);
|
||||
BOOST_CHECK_EQUAL(nncdata[0].trans, 0.5 * Opm::Metric::Transmissibility);
|
||||
BOOST_CHECK_EQUAL(nncdata[1].cell1, 0);
|
||||
BOOST_CHECK_EQUAL(nncdata[1].cell2, 10);
|
||||
BOOST_CHECK_EQUAL(nncdata[1].trans, 1.0 * Opm::Metric::Transmissibility);
|
||||
BOOST_CHECK_EQUAL(nncdata.size(), 4);
|
||||
check_nnc(nncdata, grid.getGlobalIndex(0,0,0), grid.getGlobalIndex(1,0,0), 0.50);
|
||||
check_nnc(nncdata, grid.getGlobalIndex(0,0,0), grid.getGlobalIndex(0,1,0), 1.00);
|
||||
|
||||
const auto& loc = nnc.input_location( nncdata[0] );
|
||||
BOOST_CHECK_EQUAL(loc.keyword, "NNC");
|
||||
}
|
||||
|
||||
BOOST_AUTO_TEST_CASE(addNNCfromDeck)
|
||||
|
||||
|
||||
BOOST_AUTO_TEST_CASE(noNNC_EDIT)
|
||||
{
|
||||
Parser parser;
|
||||
auto deck = parser.parseFile(pathprefix() + "NNC/NNC.DATA");
|
||||
auto deck = parser.parseString(no_nnc_input);
|
||||
EclipseState eclipseState(deck);
|
||||
auto nnc = eclipseState.getInputNNC();
|
||||
BOOST_CHECK(nnc.hasNNC());
|
||||
const std::vector<NNCdata>& nncdata = nnc.data();
|
||||
|
||||
BOOST_CHECK_EQUAL(nnc.numNNC(), 4);
|
||||
// test add NNC
|
||||
nnc.addNNC(2, 2, 2.0);
|
||||
BOOST_CHECK_EQUAL(nnc.numNNC(), 5);
|
||||
BOOST_CHECK_EQUAL(nncdata[4].cell1, 2);
|
||||
BOOST_CHECK_EQUAL(nncdata[4].cell2, 2);
|
||||
BOOST_CHECK_EQUAL(nncdata[4].trans, 2.0);
|
||||
const auto& editnnc = eclipseState.getInputNNC();
|
||||
BOOST_CHECK(editnnc.edit().empty());
|
||||
}
|
||||
|
||||
BOOST_AUTO_TEST_CASE(addNNC)
|
||||
|
||||
BOOST_AUTO_TEST_CASE(readDeck_EDIT)
|
||||
{
|
||||
Opm::NNC nnc;
|
||||
// add NNC
|
||||
nnc.addNNC(2,2,2.0);
|
||||
const std::vector<NNCdata>& nncdata = nnc.data();
|
||||
BOOST_CHECK_EQUAL(nnc.numNNC(), 1);
|
||||
BOOST_CHECK_EQUAL(nncdata[0].cell1, 2);
|
||||
BOOST_CHECK_EQUAL(nncdata[0].cell1, 2);
|
||||
BOOST_CHECK_EQUAL(nncdata[0].trans, 2.0);
|
||||
Parser parser;
|
||||
auto deck = parser.parseString(editnnc_input);
|
||||
EclipseGrid grid(10,10,10);
|
||||
|
||||
NNC nnc(grid, deck);
|
||||
const std::vector<NNCdata>& data = nnc.edit();
|
||||
|
||||
BOOST_CHECK_EQUAL(data.size(), 2); //neighbouring connections in EDITNNC are ignored
|
||||
BOOST_CHECK(!has_nnc(data, grid.getGlobalIndex(0,0,0), grid.getGlobalIndex(0,1,0)));
|
||||
BOOST_CHECK(!has_nnc(data, grid.getGlobalIndex(0,0,0), grid.getGlobalIndex(1,0,0)));
|
||||
|
||||
check_order(nnc);
|
||||
check_edit_nnc(data, grid.getGlobalIndex(2,0,0), grid.getGlobalIndex(0,0,0), 0.1);
|
||||
check_edit_nnc(data, grid.getGlobalIndex(1,0,0), grid.getGlobalIndex(1,2,0), 0.06);
|
||||
|
||||
const std::vector<NNCdata>& input = nnc.input();
|
||||
check_nnc(input, grid.getGlobalIndex(2,0,0), grid.getGlobalIndex(4,0,0), 0.20);
|
||||
check_nnc(input, grid.getGlobalIndex(2,0,0), grid.getGlobalIndex(6,0,0), 0.10);
|
||||
}
|
||||
|
||||
|
||||
BOOST_AUTO_TEST_CASE(ACTNUM)
|
||||
{
|
||||
Parser parser;
|
||||
auto deck = parser.parseString(actnum);
|
||||
EclipseState eclipseState(deck);
|
||||
const auto& grid = eclipseState.getInputGrid();
|
||||
const auto& editnnc = eclipseState.getInputNNC();
|
||||
const auto& edit = editnnc.edit();
|
||||
const auto& input = editnnc.input();
|
||||
BOOST_CHECK_EQUAL(edit.size(), 1);
|
||||
BOOST_CHECK_EQUAL(input.size(), 1);
|
||||
check_nnc(input, grid.getGlobalIndex(1,1,0), grid.getGlobalIndex(2,2,0), 0.5);
|
||||
check_edit_nnc(edit, grid.getGlobalIndex(3,3,0), grid.getGlobalIndex(4,4,0), 2.0);
|
||||
check_order(editnnc);
|
||||
}
|
||||
|
||||
|
||||
|
Loading…
Reference in New Issue
Block a user