void ParserKeyword::applyUnitsToDeck( Deck& deck, DeckKeyword& deckKeyword) const { for (size_t index = 0; index < deckKeyword.size(); index++) { const auto& parserRecord = this->getRecord( index ); auto& deckRecord = deckKeyword.getRecord( index ); parserRecord.applyUnitsToDeck( deck, deckRecord ); } }
void TimeMap::addFromDATESKeyword( const DeckKeyword& DATESKeyword ) { if (DATESKeyword.name() != "DATES") throw std::invalid_argument("Method requires DATES keyword input."); for (size_t recordIndex = 0; recordIndex < DATESKeyword.size(); recordIndex++) { const auto& record = DATESKeyword.getRecord( recordIndex ); boost::posix_time::ptime nextTime = TimeMap::timeFromEclipse( record ); addTime( nextTime ); } }
bool DeckKeyword::equal_data(const DeckKeyword& other, bool cmp_default, bool cmp_numeric) const { if (this->size() != other.size()) return false; for (size_t index = 0; index < this->size(); index++) { const auto& this_record = this->getRecord( index ); const auto& other_record = other.getRecord( index ); if (!this_record.equal( other_record , cmp_default, cmp_numeric)) return false; } return true; }
std::vector<std::pair<size_t , size_t> > PvtxTable::recordRanges( const DeckKeyword& keyword ) { std::vector<std::pair<size_t,size_t> > ranges; size_t startRecord = 0; size_t recordIndex = 0; while (recordIndex < keyword.size()) { const auto& item = keyword.getRecord(recordIndex).getItem(0); if (item.size( ) == 0) { ranges.push_back( std::make_pair( startRecord , recordIndex ) ); startRecord = recordIndex + 1; } recordIndex++; } ranges.push_back( std::make_pair( startRecord , recordIndex ) ); return ranges; }
std::map<std::string , std::vector< CompletionPtr> > Completion::completionsFromCOMPDATKeyword( const DeckKeyword& compdatKeyword ) { std::map<std::string , std::vector< CompletionPtr> > completionMapList; for (size_t recordIndex = 0; recordIndex < compdatKeyword.size(); recordIndex++) { std::pair<std::string , std::vector< CompletionPtr> > wellCompletionsPair = completionsFromCOMPDATRecord( compdatKeyword.getRecord( recordIndex )); std::string well = wellCompletionsPair.first; std::vector<CompletionPtr>& newCompletions = wellCompletionsPair.second; if (completionMapList.find(well) == completionMapList.end()) completionMapList[well] = std::vector<CompletionPtr>(); { std::vector<CompletionPtr>& currentCompletions = completionMapList.find(well)->second; for (size_t ic = 0; ic < newCompletions.size(); ic++) currentCompletions.push_back( newCompletions[ic] ); } } return completionMapList; }
std::vector< Compsegs > Compsegs::compsegsFromCOMPSEGSKeyword( const DeckKeyword& compsegsKeyword ) { // only handle the second record here // The first record here only contains the well name std::vector< Compsegs > compsegs; for (size_t recordIndex = 1; recordIndex < compsegsKeyword.size(); ++recordIndex) { const auto& record = compsegsKeyword.getRecord(recordIndex); // following the coordinate rule for completions const int I = record.getItem<ParserKeywords::COMPSEGS::I>().get< int >(0) - 1; const int J = record.getItem<ParserKeywords::COMPSEGS::J>().get< int >(0) - 1; const int K = record.getItem<ParserKeywords::COMPSEGS::K>().get< int >(0) - 1; const int branch = record.getItem<ParserKeywords::COMPSEGS::BRANCH>().get< int >(0); double distance_start; double distance_end; if (record.getItem<ParserKeywords::COMPSEGS::DISTANCE_START>().hasValue(0)) { distance_start = record.getItem<ParserKeywords::COMPSEGS::DISTANCE_START>().getSIDouble(0); } else if (recordIndex == 1) { distance_start = 0.; } else { // TODO: the end of the previous connection or range // 'previous' should be in term of the input order // since basically no specific order for the completions throw std::runtime_error("this way to obtain DISTANCE_START not implemented yet!"); } if (record.getItem<ParserKeywords::COMPSEGS::DISTANCE_END>().hasValue(0)) { distance_end = record.getItem<ParserKeywords::COMPSEGS::DISTANCE_END>().getSIDouble(0); } else { // TODO: the distance_start plus the thickness of the grid block throw std::runtime_error("this way to obtain DISTANCE_END not implemented yet!"); } if( !record.getItem< ParserKeywords::COMPSEGS::DIRECTION >().hasValue( 0 ) && !record.getItem< ParserKeywords::COMPSEGS::DISTANCE_END >().hasValue( 0 ) ) { throw std::runtime_error("the direction has to be specified when DISTANCE_END in the record is not specified"); } if( record.getItem< ParserKeywords::COMPSEGS::END_IJK >().hasValue( 0 ) && !record.getItem< ParserKeywords::COMPSEGS::DIRECTION >().hasValue( 0 ) ) { throw std::runtime_error("the direction has to be specified when END_IJK in the record is specified"); } /* * Defaulted well completion. Must be non-defaulted if DISTANCE_END * is set or a range is specified. If not this is effectively ignored. */ WellCompletion::DirectionEnum direction = WellCompletion::X; if( record.getItem< ParserKeywords::COMPSEGS::DIRECTION >().hasValue( 0 ) ) { direction = WellCompletion::DirectionEnumFromString(record.getItem<ParserKeywords::COMPSEGS::DIRECTION>().get< std::string >(0)); } double center_depth; if (!record.getItem<ParserKeywords::COMPSEGS::CENTER_DEPTH>().defaultApplied(0)) { center_depth = record.getItem<ParserKeywords::COMPSEGS::CENTER_DEPTH>().getSIDouble(0); } else { // 0.0 is also the defaulted value // which is used to indicate to obtain the final value through related segment center_depth = 0.; } if (center_depth < 0.) { //TODO: get the depth from COMPDAT data. throw std::runtime_error("this way to obtain CENTER_DISTANCE not implemented yet either!"); } int segment_number; if (record.getItem<ParserKeywords::COMPSEGS::SEGMENT_NUMBER>().hasValue(0)) { segment_number = record.getItem<ParserKeywords::COMPSEGS::SEGMENT_NUMBER>().get< int >(0); } else { segment_number = 0; // will decide the segment number based on the distance in a process later. } if (!record.getItem<ParserKeywords::COMPSEGS::END_IJK>().hasValue(0)) { // only one compsegs compsegs.emplace_back( I, J, K, branch, distance_start, distance_end, direction, center_depth, segment_number ); } else { // a range is defined. genrate a range of Compsegs throw std::runtime_error("entering COMPSEGS entries with a range is not supported yet!"); } } return compsegs; }
VFPProdTable::VFPProdTable( const DeckKeyword& table, const UnitSystem& deck_unit_system) { using ParserKeywords::VFPPROD; //Check that the table has enough records if (table.size() < 7) { throw std::invalid_argument("VFPPROD table does not appear to have enough records to be valid"); } //Get record 1, the metadata for the table const auto& header = table.getRecord(0); //Get the different header items m_table_num = header.getItem<VFPPROD::TABLE>().get< int >(0); m_datum_depth = header.getItem<VFPPROD::DATUM_DEPTH>().getSIDouble(0); m_flo_type = Opm::getFloType(header.getItem<VFPPROD::RATE_TYPE>()); m_wfr_type = Opm::getWFRType(header.getItem<VFPPROD::WFR>()); m_gfr_type = Opm::getGFRType(header.getItem<VFPPROD::GFR>()); //Not used, but check that PRESSURE_DEF is indeed THP std::string quantity_string = header.getItem<VFPPROD::PRESSURE_DEF>().get< std::string >(0); if (quantity_string != "THP") { throw std::invalid_argument("PRESSURE_DEF is required to be THP"); } m_alq_type = Opm::getALQType(header.getItem<VFPPROD::ALQ_DEF>()); //Check units used for this table std::string units_string = ""; if (header.getItem<VFPPROD::UNITS>().hasValue(0)) { units_string = header.getItem<VFPPROD::UNITS>().get< std::string >(0); } else { //If units does not exist in record, the default value is the //unit system of the deck itself: do nothing... } if (units_string != "") { UnitSystem::UnitType table_unit_type; //FIXME: Only metric and field supported at the moment. //Need to change all of the convertToSI functions to support LAB/PVT-M if (units_string == "METRIC") { table_unit_type = UnitSystem::UnitType::UNIT_TYPE_METRIC; } else if (units_string == "FIELD") { table_unit_type = UnitSystem::UnitType::UNIT_TYPE_FIELD; } else if (units_string == "LAB") { table_unit_type = UnitSystem::UnitType::UNIT_TYPE_LAB; } else if (units_string == "PVT-M") { throw std::invalid_argument("Unsupported UNITS string: 'PVT-M'"); } else { throw std::invalid_argument("Invalid UNITS string"); } //Sanity check if(table_unit_type != deck_unit_system.getType()) { throw std::invalid_argument("Deck units are not equal VFPPROD table units."); } } //Quantity in the body of the table std::string body_string = header.getItem<VFPPROD::BODY_DEF>().get< std::string >(0); if (body_string == "TEMP") { throw std::invalid_argument("Invalid BODY_DEF string: TEMP not supported"); } else if (body_string == "BHP") { } else { throw std::invalid_argument("Invalid BODY_DEF string"); } //Get actual rate / flow values m_flo_data = table.getRecord(1).getItem<VFPPROD::FLOW_VALUES>().getData< double >(); convertFloToSI(m_flo_type, m_flo_data, deck_unit_system); //Get actual tubing head pressure values m_thp_data = table.getRecord(2).getItem<VFPPROD::THP_VALUES>().getData< double >(); convertTHPToSI(m_thp_data, deck_unit_system); //Get actual water fraction values m_wfr_data = table.getRecord(3).getItem<VFPPROD::WFR_VALUES>().getData< double >(); convertWFRToSI(m_wfr_type, m_wfr_data, deck_unit_system); //Get actual gas fraction values m_gfr_data = table.getRecord(4).getItem<VFPPROD::GFR_VALUES>().getData< double >(); convertGFRToSI(m_gfr_type, m_gfr_data, deck_unit_system); //Get actual gas fraction values m_alq_data = table.getRecord(5).getItem<VFPPROD::ALQ_VALUES>().getData< double >(); //Finally, read the actual table itself. size_t nt = m_thp_data.size(); size_t nw = m_wfr_data.size(); size_t ng = m_gfr_data.size(); size_t na = m_alq_data.size(); size_t nf = m_flo_data.size(); extents shape; shape[0] = nt; shape[1] = nw; shape[2] = ng; shape[3] = na; shape[4] = nf; m_data.resize(shape); std::fill_n(m_data.data(), m_data.num_elements(), std::nan("0")); //Check that size of table matches size of axis: if (table.size() != nt*nw*ng*na + 6) { throw std::invalid_argument("VFPPROD table does not contain enough records."); } //FIXME: Unit for TEMP=Tubing head temperature is not Pressure, see BODY_DEF const double table_scaling_factor = deck_unit_system.parse("Pressure").getSIScaling(); for (size_t i=6; i<table.size(); ++i) { const auto& record = table.getRecord(i); //Get indices (subtract 1 to get 0-based index) int t = record.getItem<VFPPROD::THP_INDEX>().get< int >(0) - 1; int w = record.getItem<VFPPROD::WFR_INDEX>().get< int >(0) - 1; int g = record.getItem<VFPPROD::GFR_INDEX>().get< int >(0) - 1; int a = record.getItem<VFPPROD::ALQ_INDEX>().get< int >(0) - 1; //Rest of values (bottom hole pressure or tubing head temperature) have index of flo value const std::vector<double>& bhp_tht = record.getItem<VFPPROD::VALUES>().getData< double >(); if (bhp_tht.size() != nf) { throw std::invalid_argument("VFPPROD table does not contain enough FLO values."); } for (size_t f=0; f<bhp_tht.size(); ++f) { //Check that all data is within reasonable ranges, defined to be up-to 1.0e10... if (bhp_tht[f] > 1.0e10) { //TODO: Replace with proper log message std::cerr << "VFPPROD element [" << t << "," << w << "," << g << "," << a << "," << f << "]=" << bhp_tht[f] << " too large" << std::endl; } m_data[t][w][g][a][f] = table_scaling_factor*bhp_tht[f]; } } check(table, table_scaling_factor); }