From e61e7afcc87cbd9c3fc28710ec1807406b6b2144 Mon Sep 17 00:00:00 2001 From: Joakim Hove Date: Sat, 7 Nov 2020 08:11:30 +0100 Subject: [PATCH 1/2] Refactor the NNC input class - The NNC and EDITNNC keywords are internalized in the same class. - The EDITNNC keyword operations are applied directly to the NNC keywords. - The nnc vectors are ordered with cell1 < cell2 and ascending order. - An api has been added to get the KeywordLocation from an NCC - NNC/EDITNNC which is connected to inactive cell is ignored --- CMakeLists_files.cmake | 3 +- ExtraTests.cmake | 2 - opm/output/eclipse/EclipseIO.hpp | 2 +- opm/output/eclipse/WriteInit.hpp | 4 +- .../eclipse/EclipseState/EclipseState.hpp | 12 +- .../eclipse/EclipseState/Edit/EDITNNC.hpp | 60 ---- .../eclipse/EclipseState/Grid/EclipseGrid.hpp | 2 +- opm/parser/eclipse/EclipseState/Grid/NNC.hpp | 84 ++++- python/cxx/eclipse_state.cpp | 2 +- src/opm/output/eclipse/EclipseIO.cpp | 10 +- src/opm/output/eclipse/WriteInit.cpp | 14 +- .../eclipse/EclipseState/EclipseState.cpp | 12 +- .../eclipse/EclipseState/Edit/EDITNNC.cpp | 101 ------ .../eclipse/EclipseState/Grid/EclipseGrid.cpp | 4 +- .../parser/eclipse/EclipseState/Grid/NNC.cpp | 237 +++++++++--- tests/parser/EclipseGridTests.cpp | 30 +- .../integration_tests/EDITNNC/EDITNNC.DATA | 43 --- .../data/integration_tests/NNC/NNC.DATA | 40 --- .../data/integration_tests/NNC/noNNC.DATA | 30 -- tests/parser/integration/EDITNNCTests.cpp | 69 ---- tests/parser/integration/NNCTests.cpp | 337 ++++++++++++++++-- 21 files changed, 603 insertions(+), 495 deletions(-) delete mode 100644 opm/parser/eclipse/EclipseState/Edit/EDITNNC.hpp delete mode 100644 src/opm/parser/eclipse/EclipseState/Edit/EDITNNC.cpp delete mode 100644 tests/parser/data/integration_tests/EDITNNC/EDITNNC.DATA delete mode 100644 tests/parser/data/integration_tests/NNC/NNC.DATA delete mode 100644 tests/parser/data/integration_tests/NNC/noNNC.DATA delete mode 100644 tests/parser/integration/EDITNNCTests.cpp diff --git a/CMakeLists_files.cmake b/CMakeLists_files.cmake index d8a3b08b9..0816979c9 100644 --- a/CMakeLists_files.cmake +++ b/CMakeLists_files.cmake @@ -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 @@ -380,6 +379,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 @@ -578,7 +578,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 diff --git a/ExtraTests.cmake b/ExtraTests.cmake index 524e54ed6..476a15c9c 100644 --- a/ExtraTests.cmake +++ b/ExtraTests.cmake @@ -44,11 +44,9 @@ list(APPEND EXTRA_TESTS EclipseStateTests) foreach (test BoxTest CheckDeckValidity EclipseGridCreateFromDeck - EDITNNCTests IncludeTest IntegrationTests IOConfigIntegrationTest - NNCTests ParseKEYWORD Polymer ScheduleCreateFromDeck diff --git a/opm/output/eclipse/EclipseIO.hpp b/opm/output/eclipse/EclipseIO.hpp index 43c616fb1..d38d5e8bd 100644 --- a/opm/output/eclipse/EclipseIO.hpp +++ b/opm/output/eclipse/EclipseIO.hpp @@ -112,7 +112,7 @@ public: * are not yet written to disk. */ - void writeInitial( data::Solution simProps = data::Solution(), std::map > int_data = {}, const NNC& nnc = NNC()); + void writeInitial( data::Solution simProps = data::Solution(), std::map > int_data = {}, const std::vector& nnc = {}); /** * \brief Overwrite the initial OIP values. diff --git a/opm/output/eclipse/WriteInit.hpp b/opm/output/eclipse/WriteInit.hpp index b2c7b99c7..6f6c5f0b8 100644 --- a/opm/output/eclipse/WriteInit.hpp +++ b/opm/output/eclipse/WriteInit.hpp @@ -24,6 +24,8 @@ #include #include +#include + namespace Opm { class EclipseGrid; @@ -52,7 +54,7 @@ namespace Opm { namespace InitIO { const ::Opm::Schedule& schedule, const ::Opm::data::Solution& simProps, std::map> int_data, - const ::Opm::NNC& nnc, + const std::vector<::Opm::NNCdata>& nnc, ::Opm::EclIO::OutputStream::Init& initFile); }} // namespace Opm::InitIO diff --git a/opm/parser/eclipse/EclipseState/EclipseState.hpp b/opm/parser/eclipse/EclipseState/EclipseState.hpp index 0b120100c..95c04b36f 100644 --- a/opm/parser/eclipse/EclipseState/EclipseState.hpp +++ b/opm/parser/eclipse/EclipseState/EclipseState.hpp @@ -27,7 +27,6 @@ #include #include #include -#include #include #include #include @@ -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; diff --git a/opm/parser/eclipse/EclipseState/Edit/EDITNNC.hpp b/opm/parser/eclipse/EclipseState/Edit/EDITNNC.hpp deleted file mode 100644 index 6bc1a378b..000000000 --- a/opm/parser/eclipse/EclipseState/Edit/EDITNNC.hpp +++ /dev/null @@ -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 . -*/ -#ifndef OPM_COMMON_EDITNNC_HPP -#define OPM_COMMON_EDITNNC_HPP - -#include -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& 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 - void serializeOp(Serializer& serializer) - { - serializer.vector(m_editnnc); - } - -private: - std::vector m_editnnc; -}; -} -#endif // OPM_COMMON_EDITNNC_HPP diff --git a/opm/parser/eclipse/EclipseState/Grid/EclipseGrid.hpp b/opm/parser/eclipse/EclipseState/Grid/EclipseGrid.hpp index a48e74a60..a7a0266ab 100644 --- a/opm/parser/eclipse/EclipseState/Grid/EclipseGrid.hpp +++ b/opm/parser/eclipse/EclipseState/Grid/EclipseGrid.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& nnc, const Opm::UnitSystem& units) const; /* Observe that the there is a getGlobalIndex(i,j,k) implementation in the base class. This method - translating diff --git a/opm/parser/eclipse/EclipseState/Grid/NNC.hpp b/opm/parser/eclipse/EclipseState/Grid/NNC.hpp index 8ba4633da..21df1a1e4 100644 --- a/opm/parser/eclipse/EclipseState/Grid/NNC.hpp +++ b/opm/parser/eclipse/EclipseState/Grid/NNC.hpp @@ -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 . */ @@ -22,11 +22,17 @@ #include #include +#include +#include #include +#include + 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& 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& input() const { return m_input; } + const std::vector& 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 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 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 m_input; + std::vector m_edit; + std::optional m_nnc_location; + std::optional m_edit_location; }; diff --git a/python/cxx/eclipse_state.cpp b/python/cxx/eclipse_state.cpp index 5758de6cf..60cdd07b4 100644 --- a/python/cxx/eclipse_state.cpp +++ b/python/cxx/eclipse_state.cpp @@ -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; } diff --git a/src/opm/output/eclipse/EclipseIO.cpp b/src/opm/output/eclipse/EclipseIO.cpp index ddff18012..bb78f16d6 100644 --- a/src/opm/output/eclipse/EclipseIO.cpp +++ b/src/opm/output/eclipse/EclipseIO.cpp @@ -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 > int_data, const NNC& nnc) const; - void writeEGRIDFile( const NNC& nnc ); + void writeINITFile( const data::Solution& simProps, std::map > int_data, const std::vector& nnc) const; + void writeEGRIDFile( const std::vector& 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> int_data, - const NNC& nnc) const + const std::vector& 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& 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 > int_data, const NNC& nnc) { +void EclipseIO::writeInitial( data::Solution simProps, std::map > int_data, const std::vector& nnc) { if( !this->impl->output_enabled ) return; diff --git a/src/opm/output/eclipse/WriteInit.cpp b/src/opm/output/eclipse/WriteInit.cpp index 30371219d..3dda5a84b 100644 --- a/src/opm/output/eclipse/WriteInit.cpp +++ b/src/opm/output/eclipse/WriteInit.cpp @@ -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{}; - 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> 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); } } diff --git a/src/opm/parser/eclipse/EclipseState/EclipseState.cpp b/src/opm/parser/eclipse/EclipseState/EclipseState.cpp index 052fc123c..5514075ae 100644 --- a/src/opm/parser/eclipse/EclipseState/EclipseState.cpp +++ b/src/opm/parser/eclipse/EclipseState/EclipseState.cpp @@ -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; } diff --git a/src/opm/parser/eclipse/EclipseState/Edit/EDITNNC.cpp b/src/opm/parser/eclipse/EclipseState/Edit/EDITNNC.cpp deleted file mode 100644 index e0fa56280..000000000 --- a/src/opm/parser/eclipse/EclipseState/Edit/EDITNNC.cpp +++ /dev/null @@ -1,101 +0,0 @@ - -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include - - -namespace Opm -{ - -bool isNeighbor(const std::array& ijk1, const std::array& 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& editNncs, const GridDims& gridDims) -{ - for (size_t idx_nnc = 0; idx_nnc ijk1; - ijk1[0] = static_cast(nnc.getRecord(i).getItem(0).get< int >(0)-1); - ijk1[1] = static_cast(nnc.getRecord(i).getItem(1).get< int >(0)-1); - ijk1[2] = static_cast(nnc.getRecord(i).getItem(2).get< int >(0)-1); - size_t global_index1 = gridDims.getGlobalIndex(ijk1[0],ijk1[1],ijk1[2]); - - std::array ijk2; - ijk2[0] = static_cast(nnc.getRecord(i).getItem(3).get< int >(0)-1); - ijk2[1] = static_cast(nnc.getRecord(i).getItem(4).get< int >(0)-1); - ijk2[2] = static_cast(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(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(); - 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 diff --git a/src/opm/parser/eclipse/EclipseState/Grid/EclipseGrid.cpp b/src/opm/parser/eclipse/EclipseState/Grid/EclipseGrid.cpp index 5b7e6f973..ce1c8ae54 100644 --- a/src/opm/parser/eclipse/EclipseState/Grid/EclipseGrid.cpp +++ b/src/opm/parser/eclipse/EclipseState/Grid/EclipseGrid.cpp @@ -1558,7 +1558,7 @@ std::vector EclipseGrid::createDVector(const std::array& 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& 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 EclipseGrid::createDVector(const std::array& dims, st std::vector nnc1; std::vector nnc2; - for (const NNCdata& n : nnc.data() ) { + for (const NNCdata& n : nnc ) { nnc1.push_back(n.cell1 + 1); nnc2.push_back(n.cell2 + 1); } diff --git a/src/opm/parser/eclipse/EclipseState/Grid/NNC.cpp b/src/opm/parser/eclipse/EclipseState/Grid/NNC.cpp index 4c33f0dc9..f92ede12e 100644 --- a/src/opm/parser/eclipse/EclipseState/Grid/NNC.cpp +++ b/src/opm/parser/eclipse/EclipseState/Grid/NNC.cpp @@ -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 . */ @@ -23,64 +23,215 @@ #include #include #include -#include #include +#include #include - namespace Opm { - NNC::NNC(const Deck& deck) { - GridDims gridDims(deck); - const auto& nncs = deck.getKeywordList(); - for (size_t idx_nnc = 0; idx_nnc ijk1; - ijk1[0] = static_cast(nnc.getRecord(i).getItem(0).get< int >(0)-1); - ijk1[1] = static_cast(nnc.getRecord(i).getItem(1).get< int >(0)-1); - ijk1[2] = static_cast(nnc.getRecord(i).getItem(2).get< int >(0)-1); - size_t global_index1 = gridDims.getGlobalIndex(ijk1[0],ijk1[1],ijk1[2]); - - std::array ijk2; - ijk2[0] = static_cast(nnc.getRecord(i).getItem(3).get< int >(0)-1); - ijk2[1] = static_cast(nnc.getRecord(i).getItem(4).get< int >(0)-1); - ijk2[2] = static_cast(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 global_index(const EclipseGrid& grid, const DeckRecord& record, std::size_t item_offset) { + std::size_t i = static_cast(record.getItem(0 + item_offset).get< int >(0)-1); + std::size_t j = static_cast(record.getItem(1 + item_offset).get< int >(0)-1); + std::size_t k = static_cast(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> 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()) { + 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 nnc_edit; + for (const auto& keyword_ptr : deck.getKeywordList()) { + for (const auto& record : *keyword_ptr) { + 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; + + double tran_mult = record.getItem(6).get(0); + 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 diff --git a/tests/parser/EclipseGridTests.cpp b/tests/parser/EclipseGridTests.cpp index cbce770cf..070b93702 100644 --- a/tests/parser/EclipseGridTests.cpp +++ b/tests/parser/EclipseGridTests.cpp @@ -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 nnchead = file1.get("NNCHEAD"); - BOOST_CHECK( nnchead[0] == static_cast(nnc.numNNC()) ); + BOOST_CHECK( nnchead[0] == static_cast(nnc.input().size()) ); std::vector ref_nnc1 = { 6, 7, 8 }; std::vector 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); diff --git a/tests/parser/data/integration_tests/EDITNNC/EDITNNC.DATA b/tests/parser/data/integration_tests/EDITNNC/EDITNNC.DATA deleted file mode 100644 index 7eb7a744a..000000000 --- a/tests/parser/data/integration_tests/EDITNNC/EDITNNC.DATA +++ /dev/null @@ -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 / -/ diff --git a/tests/parser/data/integration_tests/NNC/NNC.DATA b/tests/parser/data/integration_tests/NNC/NNC.DATA deleted file mode 100644 index 4cb2c8d1f..000000000 --- a/tests/parser/data/integration_tests/NNC/NNC.DATA +++ /dev/null @@ -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 / -/ diff --git a/tests/parser/data/integration_tests/NNC/noNNC.DATA b/tests/parser/data/integration_tests/NNC/noNNC.DATA deleted file mode 100644 index 0f4f422be..000000000 --- a/tests/parser/data/integration_tests/NNC/noNNC.DATA +++ /dev/null @@ -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 / \ No newline at end of file diff --git a/tests/parser/integration/EDITNNCTests.cpp b/tests/parser/integration/EDITNNCTests.cpp deleted file mode 100644 index 4dec620ad..000000000 --- a/tests/parser/integration/EDITNNCTests.cpp +++ /dev/null @@ -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 . -*/ - -#include -#include -#include -#include -#include -#include - -#define BOOST_TEST_MODULE NNCTests - -#include - -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& 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); - -} diff --git a/tests/parser/integration/NNCTests.cpp b/tests/parser/integration/NNCTests.cpp index a627b7f5b..a93c76729 100644 --- a/tests/parser/integration/NNCTests.cpp +++ b/tests/parser/integration/NNCTests.cpp @@ -20,7 +20,7 @@ #include #include #include -#include +#include #include #include @@ -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 1.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 find_nnc(const std::vector& 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& 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& 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& 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& 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 = nnc.data(); + check_order(nnc); + BOOST_CHECK(!nnc.input().empty()); + const std::vector& 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 = 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 = 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& 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& 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), 1.0); + check_order(editnnc); +} + + From 37b71e8be5badb98290a40a60722938e4eccc26f Mon Sep 17 00:00:00 2001 From: Joakim Hove Date: Wed, 11 Nov 2020 07:02:10 +0100 Subject: [PATCH 2/2] Skip NNCEDIT with multiplier = 1 --- src/opm/parser/eclipse/EclipseState/Grid/NNC.cpp | 5 ++++- tests/parser/integration/NNCTests.cpp | 4 ++-- 2 files changed, 6 insertions(+), 3 deletions(-) diff --git a/src/opm/parser/eclipse/EclipseState/Grid/NNC.cpp b/src/opm/parser/eclipse/EclipseState/Grid/NNC.cpp index f92ede12e..3cffd54be 100644 --- a/src/opm/parser/eclipse/EclipseState/Grid/NNC.cpp +++ b/src/opm/parser/eclipse/EclipseState/Grid/NNC.cpp @@ -117,6 +117,10 @@ bool is_neighbor(const EclipseGrid& grid, std::size_t g1, std::size_t g2) { std::vector nnc_edit; for (const auto& keyword_ptr : deck.getKeywordList()) { for (const auto& record : *keyword_ptr) { + double tran_mult = record.getItem(6).get(0); + if (tran_mult == 1.0) + continue; + auto index_pair = make_index_pair(grid, record); if (!index_pair) continue; @@ -125,7 +129,6 @@ bool is_neighbor(const EclipseGrid& grid, std::size_t g1, std::size_t g2) { if (is_neighbor(grid, g1, g2)) continue; - double tran_mult = record.getItem(6).get(0); nnc_edit.emplace_back( g1, g2, tran_mult); } diff --git a/tests/parser/integration/NNCTests.cpp b/tests/parser/integration/NNCTests.cpp index a93c76729..81c5ee7dd 100644 --- a/tests/parser/integration/NNCTests.cpp +++ b/tests/parser/integration/NNCTests.cpp @@ -112,7 +112,7 @@ 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 1.0 / -- Valid +4 4 1 5 5 1 2.0 / -- Valid -1 4 4 -1 7 7 1.0 / -- Very invalid / @@ -352,7 +352,7 @@ BOOST_AUTO_TEST_CASE(ACTNUM) 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), 1.0); + check_edit_nnc(edit, grid.getGlobalIndex(3,3,0), grid.getGlobalIndex(4,4,0), 2.0); check_order(editnnc); }