/* Copyright 2014 SINTEF ICT, Applied Mathematics. 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_REGIONMAPPING_HEADER_INCLUDED #define OPM_REGIONMAPPING_HEADER_INCLUDED #include #include #include namespace Opm { /** * Forward and reverse mappings between cells and * regions/partitions (e.g., the ECLIPSE-style 'SATNUM', * 'PVTNUM', or 'EQUILNUM' arrays). * * \tparam Region Type of a forward region mapping. Expected * to provide indexed access through * operator[]() as well as inner types * 'value_type', 'size_type', and * 'const_iterator'. */ template < class Region = std::vector > class RegionMapping { public: /** * Constructor. * * \param[in] reg Forward region mapping, restricted to * active cells only. */ explicit RegionMapping(const Region& reg) : reg_(reg) { rev_.init(reg_); } /** * Type of forward (cell-to-region) mapping result. * Expected to be an integer. */ typedef typename Region::value_type RegionId; /** * Type of reverse (region-to-cell) mapping (element) * result. */ typedef typename Region::size_type CellId; /** * Type of reverse region-to-cell range bounds and * iterators. */ typedef typename std::vector::const_iterator CellIter; typedef boost::iterator_range Range; /** * Compute region number of given active cell. * * \param[in] c Active cell * \return Region to which @c c belongs. */ RegionId region(const CellId c) const { return reg_[c]; } const std::vector& activeRegions() const { return rev_.active; } /** * Extract active cells in particular region. * * \param[in] r Region number * * \return Range of active cells in region @c r. Empty if @c r is * not an active region. */ Range cells(const RegionId r) const { const auto id = rev_.binid.find(r); if (id == rev_.binid.end()) { // Region 'r' not an active region. Return empty. return Range(rev_.c.end(), rev_.c.end()); } const auto i = id->second; return Range(rev_.c.begin() + rev_.p[i + 0], rev_.c.begin() + rev_.p[i + 1]); } private: /** * Copy of forward region mapping (cell-to-region). */ Region reg_; /** * Reverse mapping (region-to-cell). */ struct { typedef typename std::vector::size_type Pos; std::unordered_map binid; std::vector active; std::vector p; /**< Region start pointers */ std::vector c; /**< Region cells */ /** * Compute reverse mapping. Standard linear insertion * sort algorithm. */ void init(const Region& reg) { binid.clear(); for (const auto& r : reg) { ++binid[r]; } p .clear(); p.emplace_back(0); active.clear(); { Pos n = 0; for (auto& id : binid) { active.push_back(id.first); p .push_back(id.second); id.second = n++; } } for (decltype(p.size()) i = 1, sz = p.size(); i < sz; ++i) { p[0] += p[i]; p[i] = p[0] - p[i]; } assert (p[0] == static_cast(reg.size())); c.resize(reg.size()); { CellId i = 0; for (const auto& r : reg) { auto& pos = p[ binid[r] + 1 ]; c[ pos++ ] = i++; } } p[0] = 0; } } rev_; /**< Reverse mapping instance */ }; } // namespace Opm #endif // OPM_REGIONMAPPING_HEADER_INCLUDED