Merge pull request #3793 from akva2/handlercontext_separate

HandlerContext: put in separate compilation unit
This commit is contained in:
Bård Skaflestad 2023-11-24 14:18:03 +01:00 committed by GitHub
commit f45eb1afbf
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
8 changed files with 356 additions and 141 deletions

View File

@ -177,6 +177,7 @@ if(ENABLE_ECL_INPUT)
src/opm/input/eclipse/Schedule/Group/GConSump.cpp
src/opm/input/eclipse/Schedule/Group/GroupEconProductionLimits.cpp
src/opm/input/eclipse/Schedule/Group/GTNode.cpp
src/opm/input/eclipse/Schedule/HandlerContext.cpp
src/opm/input/eclipse/Schedule/KeywordHandlers.cpp
src/opm/input/eclipse/Schedule/MessageLimits.cpp
src/opm/input/eclipse/Schedule/MSW/icd.cpp
@ -184,6 +185,7 @@ if(ENABLE_ECL_INPUT)
src/opm/input/eclipse/Schedule/MSW/Segment.cpp
src/opm/input/eclipse/Schedule/MSW/SegmentMatcher.cpp
src/opm/input/eclipse/Schedule/MSW/WellSegments.cpp
src/opm/input/eclipse/Schedule/MSW/WelSegsSet.cpp
src/opm/input/eclipse/Schedule/MSW/AICD.cpp
src/opm/input/eclipse/Schedule/MSW/SICD.cpp
src/opm/input/eclipse/Schedule/MSW/Valve.cpp

View File

@ -61,6 +61,7 @@ namespace Opm
class GTNode;
class GuideRateConfig;
class GuideRateModel;
class HandlerContext;
enum class InputErrorAction;
class ParseContext;
class Python;
@ -76,6 +77,7 @@ namespace Opm
class WellMatcher;
enum class WellProducerCMode;
enum class WellStatus;
class WelSegsSet;
class WellTestConfig;
namespace RestartIO { struct RstState; }
@ -132,28 +134,6 @@ namespace Opm
class Schedule {
public:
struct PairComp
{
bool operator()(const std::pair<std::string,KeywordLocation>& pair,
const std::string& str) const
{
return std::get<0>(pair) < str;
}
bool operator()(const std::pair<std::string,KeywordLocation>& pair1,
const std::pair<std::string,KeywordLocation>& pair2) const
{
return std::get<0>(pair1) < std::get<0>(pair2);
}
bool operator()(const std::string& str,
const std::pair<std::string,KeywordLocation>& pair) const
{
return str < std::get<0>(pair);
}
};
using WelSegsSet = std::set<std::pair<std::string,KeywordLocation>,PairComp>;
Schedule() = default;
explicit Schedule(std::shared_ptr<const Python> python_handle);
Schedule(const Deck& deck,
@ -510,71 +490,6 @@ namespace Opm
void dump_deck(std::ostream& os) const;
private:
struct HandlerContext {
const ScheduleBlock& block;
const DeckKeyword& keyword;
const std::size_t currentStep;
const std::vector<std::string>& matching_wells;
const bool actionx_mode;
const ParseContext& parseContext;
ErrorGuard& errors;
SimulatorUpdate* sim_update{nullptr};
const std::unordered_map<std::string, double>* target_wellpi{nullptr};
std::unordered_map<std::string, double>* wpimult_global_factor{nullptr};
WelSegsSet* welsegs_wells{nullptr};
std::set<std::string>* compsegs_wells{nullptr};
const ScheduleGrid& grid;
/// \param welsegs_wells All wells with a WELSEGS entry for checks.
/// \param compegs_wells All wells with a COMPSEGS entry for checks.
HandlerContext(const ScheduleBlock& block_,
const DeckKeyword& keyword_,
const ScheduleGrid& grid_,
const std::size_t currentStep_,
const std::vector<std::string>& matching_wells_,
bool actionx_mode_,
const ParseContext& parseContext_,
ErrorGuard& errors_,
SimulatorUpdate* sim_update_,
const std::unordered_map<std::string, double>* target_wellpi_,
std::unordered_map<std::string, double>* wpimult_global_factor_,
WelSegsSet* welsegs_wells_,
std::set<std::string>* compsegs_wells_)
: block(block_)
, keyword(keyword_)
, currentStep(currentStep_)
, matching_wells(matching_wells_)
, actionx_mode(actionx_mode_)
, parseContext(parseContext_)
, errors(errors_)
, sim_update(sim_update_)
, target_wellpi(target_wellpi_)
, wpimult_global_factor(wpimult_global_factor_)
, welsegs_wells(welsegs_wells_)
, compsegs_wells(compsegs_wells_)
, grid(grid_)
{}
void affected_well(const std::string& well_name);
void record_well_structure_change();
/// \brief Mark that the well occured in a WELSEGS keyword
void welsegs_handled(const std::string& well_name)
{
if (welsegs_wells)
welsegs_wells->insert({well_name, keyword.location()});
}
/// \brief Mark that the well occured in a COMPSEGS keyword
void compsegs_handled(const std::string& well_name)
{
if (compsegs_wells)
compsegs_wells->insert(well_name);
}
};
// Please update the member functions
// - operator==(const Schedule&) const
// - serializationTestObject()
@ -641,7 +556,7 @@ namespace Opm
bool actionx_mode,
SimulatorUpdate* sim_update,
const std::unordered_map<std::string, double>* target_wellpi,
std::unordered_map<std::string, double>* wpimult_global_factor = nullptr,
std::unordered_map<std::string, double>& wpimult_global_factor,
WelSegsSet* welsegs_wells = nullptr,
std::set<std::string>* compsegs_wells = nullptr);

View File

@ -0,0 +1,81 @@
/*
Copyright 2013 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 <http://www.gnu.org/licenses/>.
*/
#include "HandlerContext.hpp"
#include <opm/input/eclipse/Deck/DeckKeyword.hpp>
#include <opm/input/eclipse/Schedule/Action/SimulatorUpdate.hpp>
#include "MSW/WelSegsSet.hpp"
#include <stdexcept>
namespace Opm {
void HandlerContext::affected_well(const std::string& well_name)
{
if (sim_update) {
sim_update->affected_wells.insert(well_name);
}
}
void HandlerContext::record_tran_change()
{
if (sim_update) {
sim_update->tran_update = true;
}
}
void HandlerContext::record_well_structure_change()
{
if (sim_update) {
sim_update->well_structure_changed = true;
}
}
void HandlerContext::welsegs_handled(const std::string& well_name)
{
if (welsegs_wells) {
welsegs_wells->insert(well_name, keyword.location());
}
}
void HandlerContext::compsegs_handled(const std::string& well_name)
{
if (compsegs_wells) {
compsegs_wells->insert(well_name);
}
}
double HandlerContext::getWellPI(const std::string& well_name) const
{
if (!target_wellpi) {
throw std::logic_error("Lookup of well PI with no map available");
}
auto wellpi_iter = target_wellpi->find(well_name);
if (wellpi_iter == target_wellpi->end()) {
throw std::logic_error("Missing current PI for well " + well_name);
}
return wellpi_iter->second;
}
}

View File

@ -0,0 +1,111 @@
/*
Copyright 2013 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 <http://www.gnu.org/licenses/>.
*/
#ifndef HANDLER_CONTEXT_HPP
#define HANDLER_CONTEXT_HPP
#include <opm/common/OpmLog/KeywordLocation.hpp>
#include <cstddef>
#include <set>
#include <string>
#include <unordered_map>
#include <vector>
namespace Opm {
class DeckKeyword;
class ErrorGuard;
class ParseContext;
class ScheduleBlock;
class ScheduleGrid;
class ScheduleState;
struct SimulatorUpdate;
class WelSegsSet;
class HandlerContext
{
public:
/// \param welsegs_wells All wells with a WELSEGS entry for checks.
/// \param compegs_wells All wells with a COMPSEGS entry for checks.
HandlerContext(const ScheduleBlock& block_,
const DeckKeyword& keyword_,
const ScheduleGrid& grid_,
const std::size_t currentStep_,
const std::vector<std::string>& matching_wells_,
bool actionx_mode_,
const ParseContext& parseContext_,
ErrorGuard& errors_,
SimulatorUpdate* sim_update_,
const std::unordered_map<std::string, double>* target_wellpi_,
std::unordered_map<std::string, double>& wpimult_global_factor_,
WelSegsSet* welsegs_wells_,
std::set<std::string>* compsegs_wells_)
: block(block_)
, keyword(keyword_)
, currentStep(currentStep_)
, matching_wells(matching_wells_)
, actionx_mode(actionx_mode_)
, parseContext(parseContext_)
, errors(errors_)
, wpimult_global_factor(wpimult_global_factor_)
, grid(grid_)
, target_wellpi(target_wellpi_)
, welsegs_wells(welsegs_wells_)
, compsegs_wells(compsegs_wells_)
, sim_update(sim_update_)
{}
//! \brief Mark that a well has changed.
void affected_well(const std::string& well_name);
//! \brief Mark that transmissibilities must be recalculated.
void record_tran_change();
//! \brief Mark that well structure has changed.
void record_well_structure_change();
/// \brief Mark that the well occured in a WELSEGS keyword.
void welsegs_handled(const std::string& well_name);
/// \brief Mark that the well occured in a COMPSEGS keyword.
void compsegs_handled(const std::string& well_name);
//! \brief Obtain PI for a well.
double getWellPI(const std::string& well_name) const;
const ScheduleBlock& block;
const DeckKeyword& keyword;
const std::size_t currentStep;
const std::vector<std::string>& matching_wells;
const bool actionx_mode;
const ParseContext& parseContext;
ErrorGuard& errors;
std::unordered_map<std::string, double>& wpimult_global_factor;
const ScheduleGrid& grid;
private:
const std::unordered_map<std::string, double>* target_wellpi{nullptr};
WelSegsSet* welsegs_wells{nullptr};
std::set<std::string>* compsegs_wells{nullptr};
SimulatorUpdate* sim_update{nullptr};
};
} // end namespace Opm
#endif // HANDLER_CONTEXT_HPP

View File

@ -96,6 +96,7 @@
#include <opm/input/eclipse/Parser/ParserKeywords/V.hpp>
#include <opm/input/eclipse/Parser/ParserKeywords/W.hpp>
#include "HandlerContext.hpp"
#include "Well/injection.hpp"
#include <algorithm>
@ -150,7 +151,7 @@ namespace {
throw OpmInputError("AQUFETP is not supported as SCHEDULE keyword", handlerContext.keyword.location());
}
void Schedule::handleAQUFLUX(Schedule::HandlerContext& handlerContext) {
void Schedule::handleAQUFLUX(HandlerContext& handlerContext) {
// auto& aqufluxs = this->snapshots.back().aqufluxs;
auto& aqufluxs = this->snapshots.back().aqufluxs;
for (const auto& record : handlerContext.keyword) {
@ -159,7 +160,7 @@ namespace {
}
}
void Schedule::handleBCProp(Schedule::HandlerContext& handlerContext) {
void Schedule::handleBCProp(HandlerContext& handlerContext) {
auto& bcprop = this->snapshots.back().bcprop;
for (const auto& record : handlerContext.keyword) {
bcprop.updateBCProp(record);
@ -989,8 +990,7 @@ File {} line {}.)", wname, location.keyword, location.filename, location.lineno)
void Schedule::handleGEOKeyword(HandlerContext& handlerContext) {
this->snapshots.back().geo_keywords().push_back(handlerContext.keyword);
this->snapshots.back().events().addEvent( ScheduleEvents::GEO_MODIFIER );
if (handlerContext.sim_update)
handlerContext.sim_update->tran_update = true;
handlerContext.record_tran_change();
}
void Schedule::handleMXUNSUPP(HandlerContext& handlerContext) {
@ -1773,14 +1773,10 @@ File {} line {}.)", wname, location.keyword, location.filename, location.lineno)
const auto targetPI = record.getItem<PI>().get<double>(0);
std::vector<bool> scalingApplicable;
const auto& current_wellpi = *handlerContext.target_wellpi;
for (const auto& well_name : well_names) {
auto wellpi_iter = current_wellpi.find(well_name);
if (wellpi_iter == current_wellpi.end())
throw std::logic_error(fmt::format("Missing current PI for well {}", well_name));
auto new_well = this->getWell(well_name, report_step);
auto scalingFactor = new_well.convertDeckPI(targetPI) / wellpi_iter->second;
auto scalingFactor = new_well.convertDeckPI(targetPI) /
handlerContext.getWellPI(well_name);
new_well.updateWellProductivityIndex();
new_well.applyWellProdIndexScaling(scalingFactor, scalingApplicable);
this->snapshots.back().wells.update( std::move(new_well) );
@ -2122,7 +2118,7 @@ Well{0} entered with 'FIELD' parent group:
}
}
void Schedule::handleWINJMULT(Opm::Schedule::HandlerContext& handlerContext) {
void Schedule::handleWINJMULT(HandlerContext& handlerContext) {
for (const auto& record : handlerContext.keyword) {
const std::string& wellNamePattern = record.getItem("WELL_NAME").getTrimmedString(0);
const auto well_names = wellNames(wellNamePattern);
@ -2295,13 +2291,10 @@ Well{0} entered with 'FIELD' parent group:
// whether it is the last one.
const bool default_con_comp = defaultConCompRec(record);
if (default_con_comp) {
auto wpimult_global_factor = handlerContext.wpimult_global_factor;
if (!wpimult_global_factor) {
throw std::runtime_error(" wpimult_global_factor is nullptr in function handleWPIMULT ");
}
auto& wpimult_global_factor = handlerContext.wpimult_global_factor;
const auto scaling_factor = record.getItem("WELLPI").get<double>(0);
for (const auto& wname : well_names) {
(*wpimult_global_factor)[wname] = scaling_factor;
wpimult_global_factor.insert_or_assign(wname, scaling_factor);
}
continue;
}

View File

@ -0,0 +1,79 @@
/*
Copyright 2013 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 <http://www.gnu.org/licenses/>.
*/
#include "WelSegsSet.hpp"
#include <opm/input/eclipse/Schedule/Well/Well.hpp>
#include <opm/input/eclipse/Schedule/Well/WellConnections.hpp>
#include <algorithm>
namespace Opm {
void WelSegsSet::insert(const std::string& well_name,
const KeywordLocation& location)
{
entries_.emplace(well_name, location);
}
std::vector<WelSegsSet::Entry>
WelSegsSet::difference(const std::set<std::string>& compsegs,
const std::vector<Well>& wells) const
{
std::vector<Entry> difference;
difference.reserve(entries_.size());
std::set_difference(entries_.begin(), entries_.end(),
compsegs.begin(), compsegs.end(),
std::back_inserter(difference),
PairComp());
// Ignore wells without connections
const auto empty_conn = [&wells](const Entry &x) {
return std::any_of(wells.begin(), wells.end(),
[wname = x.first](const Well& well)
{ return (well.name() == wname) && well.getConnections().empty(); });
};
difference.erase(std::remove_if(difference.begin(),
difference.end(), empty_conn),
difference.end());
return difference;
}
bool WelSegsSet::PairComp::
operator()(const Entry& pair, const std::string& str) const
{
return std::get<0>(pair) < str;
}
bool WelSegsSet::PairComp::
operator()(const Entry& pair1, const Entry& pair2) const
{
return std::get<0>(pair1) < std::get<0>(pair2);
}
bool WelSegsSet::PairComp::
operator()(const std::string& str, const Entry& pair) const
{
return str < std::get<0>(pair);
}
} // end namespace Opm

View File

@ -0,0 +1,57 @@
/*
Copyright 2013 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 <http://www.gnu.org/licenses/>.
*/
#ifndef WEL_SEGS_SET_HPP
#define WEL_SEGS_SET_HPP
#include <opm/common/OpmLog/KeywordLocation.hpp>
#include <set>
#include <string>
#include <utility>
#include <vector>
namespace Opm {
class Well;
class WelSegsSet
{
public:
using Entry = std::pair<std::string,KeywordLocation>;
void insert(const std::string& well_name,
const KeywordLocation& location);
std::vector<Entry> difference(const std::set<std::string>& compsegs,
const std::vector<Well>& wells) const;
private:
struct PairComp
{
bool operator()(const Entry& pair, const std::string& str) const;
bool operator()(const Entry& pair1, const Entry& pair2) const;
bool operator()(const std::string& str, const Entry& pair) const;
};
std::set<Entry,PairComp> entries_;
};
} // end namespace Opm
#endif // WEL_SEGS_SET_HPP

View File

@ -91,8 +91,10 @@
#include <opm/input/eclipse/Deck/DeckRecord.hpp>
#include <opm/input/eclipse/Deck/DeckSection.hpp>
#include "Well/injection.hpp"
#include "HandlerContext.hpp"
#include "MSW/Compsegs.hpp"
#include "MSW/WelSegsSet.hpp"
#include "Well/injection.hpp"
#include <algorithm>
#include <ctime>
@ -370,7 +372,7 @@ Schedule::Schedule(const Deck& deck, const EclipseState& es, const std::optional
bool actionx_mode,
SimulatorUpdate* sim_update,
const std::unordered_map<std::string, double>* target_wellpi,
std::unordered_map<std::string, double>* wpimult_global_factor,
std::unordered_map<std::string, double>& wpimult_global_factor,
WelSegsSet* welsegs_wells,
std::set<std::string>* compsegs_wells)
{
@ -521,34 +523,22 @@ namespace
/// \brief Check whether each MS well has COMPSEGS entry andissue error if not.
/// \param welsegs All wells with a WELSEGS entry together with the location.
/// \param compegs All wells with a COMPSEGS entry
void check_compsegs_consistency(::Opm::Schedule::WelSegsSet& welsegs,
std::set<std::string>& compsegs,
void check_compsegs_consistency(Opm::WelSegsSet& welsegs,
const std::set<std::string>& compsegs,
const std::vector<::Opm::Well>& wells)
{
std::vector<std::pair<std::string,::Opm::KeywordLocation>> difference;
difference.reserve(welsegs.size());
std::set_difference(welsegs.begin(), welsegs.end(),
compsegs.begin(), compsegs.end(),
std::back_inserter(difference),
::Opm::Schedule::PairComp());
// Ignore wells without connections
const auto empty_conn = [&wells](const std::pair<std::string,::Opm::KeywordLocation> &x) -> bool {
return std::any_of(wells.begin(), wells.end(),
[wname = x.first](const ::Opm::Well& well) {
return (well.name() == wname) && well.getConnections().empty(); }
);
};
difference.erase(std::remove_if(difference.begin(), difference.end(), empty_conn), difference.end());
const auto difference = welsegs.difference(compsegs, wells);
if (difference.size()) {
if (!difference.empty()) {
std::string well_str = "well";
if (difference.size()>1) {
if (difference.size() > 1) {
well_str.append("s");
}
well_str.append(":");
for(const auto& [name, location] : difference) {
well_str.append(fmt::format("\n {} in {} at line {}", name, location.filename, location.lineno));
well_str.append(fmt::format("\n {} in {} at line {}",
name, location.filename, location.lineno));
}
auto msg = fmt::format("Missing COMPSEGS keyword for the following multisegment {}.", well_str);
throw Opm::OpmInputError(msg, std::get<1>(difference[0]));
@ -700,7 +690,7 @@ void Schedule::iterateScheduleSection(std::size_t load_start, std::size_t load_e
false,
nullptr,
target_wellpi,
&wpimult_global_factor,
wpimult_global_factor,
&welsegs_wells,
&compsegs_wells);
keyword_index++;
@ -1532,7 +1522,7 @@ File {} line {}.)", pattern, location.keyword, location.filename, location.linen
/*actionx_mode=*/false,
&sim_update,
&target_wellpi,
&wpimult_global_factor);
wpimult_global_factor);
}
this->applyGlobalWPIMULT(wpimult_global_factor);
this->end_report(reportStep);
@ -1587,7 +1577,7 @@ File {} line {}.)", pattern, location.keyword, location.filename, location.linen
true,
&sim_update,
&target_wellpi,
&wpimult_global_factor);
wpimult_global_factor);
}
this->applyGlobalWPIMULT(wpimult_global_factor);
@ -2469,17 +2459,4 @@ std::ostream& operator<<(std::ostream& os, const Schedule& sched)
return os;
}
void Schedule::HandlerContext::affected_well(const std::string& well_name)
{
if (this->sim_update)
this->sim_update->affected_wells.insert(well_name);
}
void Schedule::HandlerContext::record_well_structure_change()
{
if (this->sim_update != nullptr) {
this->sim_update->well_structure_changed = true;
}
}
}