/* Copyright 2016 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_OUTPUT_WELLS_HPP #define OPM_OUTPUT_WELLS_HPP #include #include #include #include #include #include #include #include #include namespace Opm { namespace data { class Rates { /* Methods are defined inline for performance, as the actual *work* done * is trivial, but somewhat frequent (typically once per time step per * completion per well). * * To add a new rate type, add an entry in the enum with the correct * shift, and if needed, increase the size type. Add a member variable * and a new case in get_ref. */ public: Rates() = default; enum class opt : uint32_t { wat = (1 << 0), oil = (1 << 1), gas = (1 << 2), polymer = (1 << 3), solvent = (1 << 4), energy = (1 << 5), dissolved_gas = (1 << 6), vaporized_oil = (1 << 7), reservoir_water = (1 << 8), reservoir_oil = (1 << 9), reservoir_gas = (1 << 10), productivity_index_water = (1 << 11), productivity_index_oil = (1 << 12), productivity_index_gas = (1 << 13), well_potential_water = (1 << 14), well_potential_oil = (1 << 15), well_potential_gas = (1 << 16), }; using enum_size = std::underlying_type< opt >::type; /// Query if a value is set. inline bool has( opt ) const; /// Read the value indicated by m. Throws an exception if /// if the requested value is unset. inline double get( opt m ) const; /// Read the value indicated by m. Returns a default value if /// the requested value is unset. inline double get( opt m, double default_value ) const; /// Set the value specified by m. Throws an exception if multiple /// values are requested. Returns a self-reference to support /// chaining. inline Rates& set( opt m, double value ); /// true if any option is set; false otherwise inline bool any() const noexcept; template void write(MessageBufferType& buffer) const; template void read(MessageBufferType& buffer); private: double& get_ref( opt ); const double& get_ref( opt ) const; opt mask = static_cast< opt >( 0 ); double wat = 0.0; double oil = 0.0; double gas = 0.0; double polymer = 0.0; double solvent = 0.0; double energy = 0.0; double dissolved_gas = 0.0; double vaporized_oil = 0.0; double reservoir_water = 0.0; double reservoir_oil = 0.0; double reservoir_gas = 0.0; double productivity_index_water = 0.0; double productivity_index_oil = 0.0; double productivity_index_gas = 0.0; double well_potential_water = 0.0; double well_potential_oil = 0.0; double well_potential_gas = 0.0; }; struct Connection { using global_index = size_t; static const constexpr int restart_size = 2; global_index index; Rates rates; double pressure; double reservoir_rate; double cell_pressure; double cell_saturation_water; double cell_saturation_gas; double effective_Kh; template void write(MessageBufferType& buffer) const; template void read(MessageBufferType& buffer); }; struct Segment { Rates rates; double pressure; std::size_t segNumber; template void write(MessageBufferType& buffer) const; template void read(MessageBufferType& buffer); }; struct Well { Rates rates; double bhp; double thp; double temperature; int control; std::vector< Connection > connections; std::unordered_map segments; inline bool flowing() const noexcept; template void write(MessageBufferType& buffer) const; template void read(MessageBufferType& buffer); }; class WellRates : public std::map { public: double get(const std::string& well_name , Rates::opt m) const { const auto& well = this->find( well_name ); if( well == this->end() ) return 0.0; return well->second.rates.get( m, 0.0 ); } double get(const std::string& well_name , Connection::global_index connection_grid_index, Rates::opt m) const { const auto& witr = this->find( well_name ); if( witr == this->end() ) return 0.0; const auto& well = witr->second; const auto& connection = std::find_if( well.connections.begin() , well.connections.end() , [=]( const Connection& c ) { return c.index == connection_grid_index; }); if( connection == well.connections.end() ) return 0.0; return connection->rates.get( m, 0.0 ); } template void write(MessageBufferType& buffer) const { unsigned int size = this->size(); buffer.write(size); for (const auto& witr : *this) { const std::string& name = witr.first; buffer.write(name); const Well& well = witr.second; well.write(buffer); } } template void read(MessageBufferType& buffer) { unsigned int size; buffer.read(size); for (size_t i = 0; i < size; ++i) { std::string name; buffer.read(name); Well well; well.read(buffer); this->emplace(name, well); } } }; using Wells = WellRates; /* IMPLEMENTATIONS */ inline bool Rates::has( opt m ) const { const auto mand = static_cast< enum_size >( this->mask ) & static_cast< enum_size >( m ); return static_cast< opt >( mand ) == m; } inline double Rates::get( opt m ) const { if( !this->has( m ) ) throw std::invalid_argument( "Uninitialized value." ); return this->get_ref( m ); } inline double Rates::get( opt m, double default_value ) const { if( !this->has( m ) ) return default_value; return this->get_ref( m ); } inline Rates& Rates::set( opt m, double value ) { this->get_ref( m ) = value; /* mask |= m */ this->mask = static_cast< opt >( static_cast< enum_size >( this->mask ) | static_cast< enum_size >( m ) ); return *this; } /* * To avoid error-prone and repetitve work when extending rates with new * values, the get+set methods use this helper get_ref to determine what * member to manipulate. To add a new option, just add another case * corresponding to the enum entry in Rates to this function. * * This is an implementation detail and understanding this has no * significant impact on correct use of the class. */ inline const double& Rates::get_ref( opt m ) const { switch( m ) { case opt::wat: return this->wat; case opt::oil: return this->oil; case opt::gas: return this->gas; case opt::polymer: return this->polymer; case opt::solvent: return this->solvent; case opt::energy: return this->energy; case opt::dissolved_gas: return this->dissolved_gas; case opt::vaporized_oil: return this->vaporized_oil; case opt::reservoir_water: return this->reservoir_water; case opt::reservoir_oil: return this->reservoir_oil; case opt::reservoir_gas: return this->reservoir_gas; case opt::productivity_index_water: return this->productivity_index_water; case opt::productivity_index_oil: return this->productivity_index_oil; case opt::productivity_index_gas: return this->productivity_index_gas; case opt::well_potential_water: return this->well_potential_water; case opt::well_potential_oil: return this->well_potential_oil; case opt::well_potential_gas: return this->well_potential_gas; } throw std::invalid_argument( "Unknown value type '" + std::to_string( static_cast< enum_size >( m ) ) + "'" ); } inline double& Rates::get_ref( opt m ) { return const_cast< double& >( static_cast< const Rates* >( this )->get_ref( m ) ); } inline bool Rates::any() const noexcept { return static_cast< enum_size >( this->mask ) != 0; } inline bool Well::flowing() const noexcept { return this->rates.any(); } template void Rates::write(MessageBufferType& buffer) const { buffer.write(this->mask); buffer.write(this->wat); buffer.write(this->oil); buffer.write(this->gas); buffer.write(this->polymer); buffer.write(this->solvent); buffer.write(this->energy); buffer.write(this->dissolved_gas); buffer.write(this->vaporized_oil); buffer.write(this->reservoir_water); buffer.write(this->reservoir_oil); buffer.write(this->reservoir_gas); buffer.write(this->productivity_index_water); buffer.write(this->productivity_index_oil); buffer.write(this->productivity_index_gas); buffer.write(this->well_potential_water); buffer.write(this->well_potential_oil); buffer.write(this->well_potential_gas); } template void Connection::write(MessageBufferType& buffer) const { buffer.write(this->index); this->rates.write(buffer); buffer.write(this->pressure); buffer.write(this->reservoir_rate); buffer.write(this->cell_pressure); buffer.write(this->cell_saturation_water); buffer.write(this->cell_saturation_gas); buffer.write(this->effective_Kh); } template void Segment::write(MessageBufferType& buffer) const { buffer.write(this->segNumber); this->rates.write(buffer); buffer.write(this->pressure); } template void Well::write(MessageBufferType& buffer) const { this->rates.write(buffer); buffer.write(this->bhp); buffer.write(this->thp); buffer.write(this->temperature); buffer.write(this->control); unsigned int size = this->connections.size(); buffer.write(size); for (const Connection& comp : this->connections) comp.write(buffer); { const auto nSeg = static_cast(this->segments.size()); buffer.write(nSeg); for (const auto& seg : this->segments) { seg.second.write(buffer); } } } template void Rates::read(MessageBufferType& buffer) { buffer.read(this->mask); buffer.read(this->wat); buffer.read(this->oil); buffer.read(this->gas); buffer.read(this->polymer); buffer.read(this->solvent); buffer.read(this->energy); buffer.read(this->dissolved_gas); buffer.read(this->vaporized_oil); buffer.read(this->reservoir_water); buffer.read(this->reservoir_oil); buffer.read(this->reservoir_gas); buffer.read(this->productivity_index_water); buffer.read(this->productivity_index_oil); buffer.read(this->productivity_index_gas); buffer.read(this->well_potential_water); buffer.read(this->well_potential_oil); buffer.read(this->well_potential_gas); } template void Connection::read(MessageBufferType& buffer) { buffer.read(this->index); this->rates.read(buffer); buffer.read(this->pressure); buffer.read(this->reservoir_rate); buffer.read(this->cell_pressure); buffer.read(this->cell_saturation_water); buffer.read(this->cell_saturation_gas); buffer.read(this->effective_Kh); } template void Segment::read(MessageBufferType& buffer) { buffer.read(this->segNumber); this->rates.read(buffer); buffer.read(this->pressure); } template void Well::read(MessageBufferType& buffer) { this->rates.read(buffer); buffer.read(this->bhp); buffer.read(this->thp); buffer.read(this->temperature); buffer.read(this->control); // Connection information unsigned int size = 0.0; //this->connections.size(); buffer.read(size); this->connections.resize(size); for (size_t i = 0; i < size; ++i) { auto& comp = this->connections[ i ]; comp.read(buffer); } // Segment information (if applicable) const auto nSeg = [&buffer]() -> unsigned int { auto n = 0u; buffer.read(n); return n; }(); for (auto segID = 0*nSeg; segID < nSeg; ++segID) { auto seg = Segment{}; seg.read(buffer); const auto segNumber = seg.segNumber; this->segments.emplace(segNumber, std::move(seg)); } } }} // Opm::data #endif //OPM_OUTPUT_WELLS_HPP