Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Compositional well #4334

Draft
wants to merge 3 commits into
base: master
Choose a base branch
from
Draft
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -394,7 +394,7 @@ struct SummaryConfigContext {
bool is_well_comp(const std::string& keyword)
{
static const auto well_comp_kw = keyword_set {
"WXMF", "WYMF", "WZMF", "WCGMR", "WCOMR"
"WAMF", "WXMF", "WYMF", "WZMF", "WCGMR", "WCOMR"
};

return is_in_set(well_comp_kw, keyword);
Expand Down
1 change: 1 addition & 0 deletions opm/input/eclipse/Schedule/ScheduleState.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -311,6 +311,7 @@ bool ScheduleState::operator==(const ScheduleState& other) const {
&& this->bhp_defaults.get() == other.bhp_defaults.get()
&& this->source.get() == other.source.get()
&& this->wells == other.wells
&& this->inj_streams == other.inj_streams
&& this->groups == other.groups
&& this->vfpprod == other.vfpprod
&& this->vfpinj == other.vfpinj
Expand Down
8 changes: 8 additions & 0 deletions opm/input/eclipse/Schedule/ScheduleState.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -201,6 +201,10 @@ namespace Opm {
return (ptr != nullptr);
}

void update(const K& key, std::shared_ptr<T> value) {
this->m_data[key] = value;
}


void update(T object) {
auto key = object.name();
Expand Down Expand Up @@ -509,6 +513,9 @@ namespace Opm {
// constant flux aquifers
std::unordered_map<int, SingleAquiferFlux> aqufluxs;
BCProp bcprop;
// injection streams for compostional STREAM injection using WINJGAS
map_member<std::string, std::vector<double>> inj_streams;

std::unordered_map<std::string, double> target_wellpi;
std::optional<NextStep> next_tstep;

Expand Down Expand Up @@ -546,6 +553,7 @@ namespace Opm {
serializer(wells);
serializer(aqufluxs);
serializer(bcprop);
serializer(inj_streams);
serializer(target_wellpi);
serializer(this->next_tstep);
serializer(m_start_time);
Expand Down
7 changes: 7 additions & 0 deletions opm/input/eclipse/Schedule/Well/Well.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -160,6 +160,9 @@ class Well {

double rsRvInj;

// injection stream compostion for compositional simulation
std::optional<std::vector<double>> gas_inj_composition{};

bool operator==(const WellInjectionProperties& other) const;
bool operator!=(const WellInjectionProperties& other) const;

Expand Down Expand Up @@ -226,6 +229,9 @@ class Well {
void update_uda(const UDQConfig& udq_config, UDQActive& udq_active, UDAControl control, const UDAValue& value);
void handleWTMULT(Well::WELTARGCMode cmode, double factor);

void setGasInjComposition(const std::vector<double>& composition);
const std::vector<double>& gasInjComposition() const;

template<class Serializer>
void serializeOp(Serializer& serializer)
{
Expand All @@ -244,6 +250,7 @@ class Well {
serializer(injectorType);
serializer(controlMode);
serializer(rsRvInj);
serializer(gas_inj_composition);
}
};

Expand Down
19 changes: 17 additions & 2 deletions opm/input/eclipse/Schedule/Well/WellInjectionProperties.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -60,7 +60,8 @@ namespace Opm {
injectionControls(0),
injectorType(InjectorType::WATER),
controlMode(InjectorCMode::CMODE_UNDEFINED),
rsRvInj(0.0)
rsRvInj(0.0),
gas_inj_composition(std::nullopt)
{
}

Expand All @@ -82,6 +83,7 @@ namespace Opm {
result.injectorType = InjectorType::OIL;
result.controlMode = InjectorCMode::BHP;
result.rsRvInj = 11;
result.gas_inj_composition = std::vector<double>{1.0, 2.0, 3.0};

return result;
}
Expand Down Expand Up @@ -284,7 +286,8 @@ namespace Opm {
(injectionControls == other.injectionControls) &&
(injectorType == other.injectorType) &&
(controlMode == other.controlMode) &&
(rsRvInj == other.rsRvInj))
(rsRvInj == other.rsRvInj) &&
(gas_inj_composition == other.gas_inj_composition))
return true;
else
return false;
Expand Down Expand Up @@ -324,6 +327,7 @@ namespace Opm {
<< "injector type: " << InjectorType2String(wp.injectorType) << ", "
<< "control mode: " << WellInjectorCMode2String(wp.controlMode) << " , "
<< "rs/rv concentration: " << wp.rsRvInj << " }";
// TODO: add gas_inj_composition
}


Expand All @@ -344,6 +348,7 @@ namespace Opm {
controls.vfp_table_number = this->VFPTableNumber;
controls.prediction_mode = this->predictionMode;
controls.rs_rv_inj = this->rsRvInj;
// TODO: should we add gas_inj_composition here?

return controls;
}
Expand Down Expand Up @@ -500,5 +505,15 @@ namespace Opm {
}
}

void Well::WellInjectionProperties::setGasInjComposition(const std::vector<double>& composition) {
gas_inj_composition = composition;
}

const std::vector<double>& Well::WellInjectionProperties::gasInjComposition() const {
if (!gas_inj_composition.has_value()) {
throw std::invalid_argument("Gas injection composition not set");
}
return gas_inj_composition.value();
}

}
62 changes: 62 additions & 0 deletions opm/input/eclipse/Schedule/Well/WellKeywordHandlers.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -446,6 +446,25 @@ void handleWCYCLE(HandlerContext& handlerContext)
handlerContext.state().wcycle.update(std::move(new_config));
}

void handleWELLSTRE(HandlerContext& handlerContext)
{
auto& inj_streams = handlerContext.state().inj_streams;
for (const auto& record : handlerContext.keyword) {
const std::string& stream_name = record.getItem("STREAM").getTrimmedString(0);
const auto& compostion = record.getItem("COMPOSITIONS").getData<double>();
// TODO: we need to check the number of the values in the composition is the same as the number of components

const double sum = std::accumulate(compostion.begin(), compostion.end(), 0.0);
if (std::abs(sum - 1.0) > std::numeric_limits<double>::epsilon()) {
std::string msg = fmt::format("The sum of the composition values for stream '{}' is not 1.0, but {}.", stream_name, sum);
throw OpmInputError(msg, handlerContext.keyword.location());
}
auto composition_ptr = std::make_shared<std::vector<double>>(std::move(compostion));
inj_streams.update(stream_name, composition_ptr);
}

}

void handleWELOPEN(HandlerContext& handlerContext)
{
const auto& keyword = handlerContext.keyword;
Expand Down Expand Up @@ -528,6 +547,45 @@ void handleWELOPEN(HandlerContext& handlerContext)
}
}

void handleWINJGAS(HandlerContext& handlerContext)
{
for (const auto& record : handlerContext.keyword) {
const std::string& wellNamePattern = record.getItem("WELL").getTrimmedString(0);
const auto well_names = handlerContext.wellNames(wellNamePattern, false);
const std::string& fluid_nature = record.getItem("FLUID").getTrimmedString(0);
// TODO: technically, only the firt two characters are significant
// TODO: we need to test it out whether only the first two characters matter
if (fluid_nature != "STREAM") {
std::string msg = fmt::format("The fluid nature '{}' is not supported in WINJGAS keyword.", fluid_nature);
throw OpmInputError(msg, handlerContext.keyword.location());
}
const std::string& stream_name = record.getItem("STREAM").getTrimmedString(0);
// TODO: we do not handle other records for now

// we make sure the stream is defined in WELLSTRE keyword
const auto& inj_streams = handlerContext.state().inj_streams;
if (!inj_streams.has(stream_name)) {
std::string msg = fmt::format("The stream '{}' is not defined in WELLSTRE keyword.", stream_name);
throw OpmInputError(msg, handlerContext.keyword.location());
}

auto well2 = handlerContext.state().wells.get(well_names[0]);
// if (well2.isProducer()) {
// std::string msg = fmt::format("The well '{}' is a producer, not an injector.", well_names[0]);
// throw OpmInputError(msg, HandlerContext.keyword.location());
// }
auto injection = std::make_shared<Well::WellInjectionProperties>(well2.getInjectionProperties());

// TODO: should we make it a injection event?
const auto& inj_stream = inj_streams.get(stream_name);
injection->setGasInjComposition(inj_stream);

if (well2.updateInjection(injection)) {
handlerContext.state().wells.update( std::move(well2) );
}
}
}

void handleWELSPECS(HandlerContext& handlerContext)
{
using Kw = ParserKeywords::WELSPECS;
Expand Down Expand Up @@ -923,12 +981,16 @@ getWellHandlers()
{ "WCONINJE", &handleWCONINJE },
{ "WCONINJH", &handleWCONINJH },
{ "WCONPROD", &handleWCONPROD },

{ "WCYCLE", &handleWCYCLE },

{ "WELOPEN" , &handleWELOPEN },
{ "WELLSTRE", &handleWELLSTRE },
{ "WELSPECS", &handleWELSPECS },
{ "WELTARG" , &handleWELTARG },
{ "WELTRAJ" , &handleWELTRAJ },
{ "WHISTCTL", &handleWHISTCTL },
{ "WINJGAS", &handleWINJGAS },
{ "WLIST" , &handleWLIST },
{ "WPAVE" , &handleWPAVE },
{ "WPAVEDEP", &handleWPAVEDEP },
Expand Down
17 changes: 6 additions & 11 deletions opm/input/eclipse/share/keywords/001_Eclipse300/W/WELLSTRE
Original file line number Diff line number Diff line change
Expand Up @@ -10,16 +10,11 @@
"value_type": "STRING"
},
{
"item": 2,
"name": "XMOLE1",
"value_type": "DOUBLE",
"dimension": "1"
},
{
"item": 3,
"name": "XMOLE2",
"value_type": "DOUBLE",
"dimension": "1"
}
"item": 2,
"name": "COMPOSITIONS",
"value_type": "DOUBLE",
"dimension": "1",
"size_type": "ALL"
}
]
}
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@
"SUMMARY"
],
"deck_names": [
"WAMF",
"WXMF",
"WYMF",
"WZMF",
Expand Down