/* Copyright 2014 Statoil ASA. This file is part of the Open Porous Media project (OPM). OPM is free software: you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation, either version 3 of the License, or (at your option) any later version. OPM is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with OPM. If not, see . */ #ifndef OPM_PARSER_ECLIPSE_GRID_HPP #define OPM_PARSER_ECLIPSE_GRID_HPP #include #include #include #include #include #include #include #include #include namespace Opm { class Deck; class ZcornMapper; /** About cell information and dimension: The actual grid information is held in a pointer to an ERT ecl_grid_type instance. This pointer must be used for access to all cell related properties, including: - Size of cells - Real world position of cells - Active/inactive status of cells */ class EclipseGrid : public GridDims { public: explicit EclipseGrid(const std::string& filename); /* These constructors will make a copy of the src grid, with zcorn and or actnum have been adjustments. */ EclipseGrid(const EclipseGrid& src, const double* zcorn , const std::vector& actnum); EclipseGrid(const EclipseGrid& src, const std::vector& zcorn , const std::vector& actnum); EclipseGrid(const EclipseGrid& src, const std::vector& actnum); EclipseGrid(size_t nx, size_t ny, size_t nz, double dx = 1.0, double dy = 1.0, double dz = 1.0); EclipseGrid(std::array& dims , const std::vector& coord , const std::vector& zcorn , const int * actnum = nullptr, const double * mapaxes = nullptr); /// EclipseGrid ignores ACTNUM in Deck, and therefore needs ACTNUM /// explicitly. If a null pointer is passed, every cell is active. EclipseGrid(const Deck& deck, const int * actnum = nullptr); static bool hasCylindricalKeywords(const Deck& deck); static bool hasCornerPointKeywords(const Deck&); static bool hasCartesianKeywords(const Deck&); size_t getNumActive( ) const; bool allActive() const; size_t activeIndex(size_t i, size_t j, size_t k) const; size_t activeIndex(size_t globalIndex) const; /* Observe that the there is a getGlobalIndex(i,j,k) implementation in the base class. This method - translating from an active index to a global index must be implemented in the current class. */ size_t getGlobalIndex(size_t active_index) const; size_t getGlobalIndex(size_t i, size_t j, size_t k) const; /* For RADIAL grids you can *optionally* use the keyword 'CIRCLE' to denote that period boundary conditions should be applied in the 'THETA' direction; this will only apply if the theta keywords entered sum up to exactly 360 degrees! */ bool circle( ) const; bool isPinchActive( ) const; double getPinchThresholdThickness( ) const; PinchMode::ModeEnum getPinchOption( ) const; PinchMode::ModeEnum getMultzOption( ) const; MinpvMode::ModeEnum getMinpvMode() const; double getMinpvValue( ) const; /* Will return a vector of nactive elements. The method will behave differently depending on the lenght of the input_vector: nx*ny*nz: only the values corresponding to active cells are copied out. nactive: The input vector is copied straight out again. ??? : Exception. */ template std::vector compressedVector(const std::vector& input_vector) const { if( input_vector.size() == this->getNumActive() ) { return input_vector; } if (input_vector.size() != getCartesianSize()) throw std::invalid_argument("Input vector must have full size"); { std::vector compressed_vector( this->getNumActive() ); const auto& active_map = this->getActiveMap( ); for (size_t i = 0; i < this->getNumActive(); ++i) compressed_vector[i] = input_vector[ active_map[i] ]; return compressed_vector; } } /// Will return a vector a length num_active; where the value /// of each element is the corresponding global index. const std::vector& getActiveMap() const; std::array getCellCenter(size_t i,size_t j, size_t k) const; std::array getCellCenter(size_t globalIndex) const; std::array getCornerPos(size_t i,size_t j, size_t k, size_t corner_index) const; double getCellVolume(size_t globalIndex) const; double getCellVolume(size_t i , size_t j , size_t k) const; double getCellThicknes(size_t globalIndex) const; double getCellThicknes(size_t i , size_t j , size_t k) const; std::array getCellDims(size_t i,size_t j, size_t k) const; std::array getCellDims(size_t globalIndex) const; bool cellActive( size_t globalIndex ) const; bool cellActive( size_t i , size_t j, size_t k ) const; double getCellDepth(size_t i,size_t j, size_t k) const; double getCellDepth(size_t globalIndex) const; ZcornMapper zcornMapper() const; /* The exportZCORN method will adjust the z coordinates to ensure that cells do not overlap. The return value is the number of points which have been adjusted. */ size_t exportZCORN( std::vector& zcorn) const; void exportMAPAXES( std::vector& mapaxes) const; void exportCOORD( std::vector& coord) const; void exportACTNUM( std::vector& actnum) const; void resetACTNUM( const int * actnum); bool equal(const EclipseGrid& other) const; const ecl_grid_type * c_ptr() const; private: double m_minpvValue; MinpvMode::ModeEnum m_minpvMode; Value m_pinch; PinchMode::ModeEnum m_pinchoutMode; PinchMode::ModeEnum m_multzMode; mutable std::vector volume_cache; mutable std::vector< int > activeMap; bool m_circle = false; /* The internal class grid_ptr is a a std::unique_ptr with special copy semantics. The purpose of implementing this is that the EclipseGrid class can now use the default implementation for the copy and move constructors. */ using ert_ptr = ERT::ert_unique_ptr; class grid_ptr : public ert_ptr { public: using ert_ptr::unique_ptr; grid_ptr() = default; grid_ptr(grid_ptr&&) = default; grid_ptr(const grid_ptr& src) : ert_ptr( ecl_grid_alloc_copy( src.get() ) ) {} }; grid_ptr m_grid; void initCornerPointGrid(const std::array& dims , const std::vector& coord , const std::vector& zcorn , const int * actnum, const double * mapaxes); void initCylindricalGrid( const std::array&, const Deck&); void initCartesianGrid( const std::array&, const Deck&); void initCornerPointGrid( const std::array&, const Deck&); void initDTOPSGrid( const std::array&, const Deck&); void initDVDEPTHZGrid( const std::array&, const Deck&); void initGrid( const std::array&, const Deck&); void assertCornerPointKeywords( const std::array&, const Deck&); static bool hasDVDEPTHZKeywords(const Deck&); static bool hasDTOPSKeywords( const Deck&); static void assertVectorSize( const std::vector& vector, size_t expectedSize, const std::string& msg); static std::vector createTOPSVector(const std::array& dims, const std::vector& DZ, const Deck&); static std::vector createDVector(const std::array& dims, size_t dim, const std::string& DKey, const std::string& DVKey, const Deck&); static void scatterDim(const std::array& dims , size_t dim , const std::vector& DV , std::vector& D); }; class CoordMapper { public: CoordMapper(size_t nx, size_t ny); size_t size() const; /* dim = 0,1,2 for x, y and z coordinate respectively. layer = 0,1 for k=0 and k=nz layers respectively. */ size_t index(size_t i, size_t j, size_t dim, size_t layer) const; private: size_t nx; size_t ny; }; class ZcornMapper { public: ZcornMapper(size_t nx, size_t ny, size_t nz); size_t index(size_t i, size_t j, size_t k, int c) const; size_t index(size_t g, int c) const; size_t size() const; /* The fixupZCORN method will take a zcorn vector as input and run through it. If the following situation is detected: /| /| / | / | / | / | / | / | / | ==> / | / | / | ---/------x /---------x | / |/ */ size_t fixupZCORN( std::vector& zcorn); bool validZCORN( const std::vector& zcorn) const; private: std::array dims; std::array stride; std::array cell_shift; }; } #endif // OPM_PARSER_ECLIPSE_GRID_HPP