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

Use cell temperature in perforated cell to compute reservoir rates #5490

Merged
merged 2 commits into from
Aug 2, 2024
Merged
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
4 changes: 3 additions & 1 deletion opm/simulators/wells/BlackoilWellModel_impl.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -812,6 +812,7 @@ namespace Opm {
initializeWellState(const int timeStepIdx)
{
std::vector<Scalar> cellPressures(this->local_num_cells_, 0.0);
std::vector<Scalar> cellTemperatures(this->local_num_cells_, 0.0);
ElementContext elemCtx(simulator_);

const auto& gridView = simulator_.vanguard().gridView();
Expand All @@ -831,10 +832,11 @@ namespace Opm {
} else {
perf_pressure = fs.pressure(FluidSystem::gasPhaseIdx).value();
}
cellTemperatures[elemCtx.globalSpaceIndex(/*spaceIdx=*/0, /*timeIdx=*/0)] = fs.temperature(0).value();
}
OPM_END_PARALLEL_TRY_CATCH("BlackoilWellModel::initializeWellState() failed: ", simulator_.vanguard().grid().comm());

this->wellState().init(cellPressures, this->schedule(), this->wells_ecl_,
this->wellState().init(cellPressures, cellTemperatures, this->schedule(), this->wells_ecl_,
this->local_parallel_well_info_, timeStepIdx,
&this->prevWellState(), this->well_perf_data_,
this->summaryState());
Expand Down
2 changes: 1 addition & 1 deletion opm/simulators/wells/MultisegmentWell_impl.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -711,7 +711,7 @@ namespace Opm
this->segments_.copyPhaseDensities(ws.pu, ws.segments);
}

Base::calculateReservoirRates(well_state.well(this->index_of_well_));
Base::calculateReservoirRates(simulator.vanguard().eclState().runspec().co2Storage(), well_state.well(this->index_of_well_));
}


Expand Down
4 changes: 2 additions & 2 deletions opm/simulators/wells/StandardWell_impl.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -706,7 +706,7 @@ namespace Opm

const auto& summary_state = simulator.vanguard().summaryState();
updateWellStateFromPrimaryVariables(stop_or_zero_rate_target, well_state, summary_state, deferred_logger);
Base::calculateReservoirRates(well_state.well(this->index_of_well_));
Base::calculateReservoirRates(simulator.vanguard().eclState().runspec().co2Storage(), well_state.well(this->index_of_well_));
}


Expand Down Expand Up @@ -2587,7 +2587,7 @@ namespace Opm
if (this->isInjector() && cq_s[activeCompIdx] > 0.0){
// only handles single phase injection now
assert(this->well_ecl_.injectorType() != InjectorType::MULTI);
fs.setTemperature(this->well_ecl_.temperature());
fs.setTemperature(this->well_ecl_.inj_temperature());
typedef typename std::decay<decltype(fs)>::type::Scalar FsScalar;
typename FluidSystem::template ParameterCache<FsScalar> paramCache;
const unsigned pvtRegionIdx = intQuants.pvtRegionIndex();
Expand Down
7 changes: 4 additions & 3 deletions opm/simulators/wells/WellInterfaceFluidSystem.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -64,12 +64,12 @@ WellInterfaceFluidSystem(const Well& well,
template <typename FluidSystem>
void
WellInterfaceFluidSystem<FluidSystem>::
calculateReservoirRates(SingleWellState<Scalar>& ws) const
calculateReservoirRates(const bool co2store, SingleWellState<Scalar>& ws) const
{
const int np = this->number_of_phases_;
const auto& pu = this->phaseUsage();
// Calculate reservoir rates from average pressure and temperature
if ( !pu.has_energy || this->wellEcl().isProducer()) {
if ( !(co2store || pu.has_energy) || this->wellEcl().isProducer()) {
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

It is a question here, the code change here mostly alters the situation that CO2STORE is active, while the pu.has_enery=false.

With the change in the PR, when CO2STORE is active, we always use the well bhp and temperature in the function below.

The question is, do we always have an meaningful temperature calculated/set with CO2STORE option ON and has_enery==false?

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

If well temperature is not set, we use the temperature in the top cell as default.

const int fipreg = 0; // not considering the region for now
this->rateConverter_
.calcReservoirVoidageRates(fipreg,
Expand Down Expand Up @@ -99,7 +99,8 @@ calculateReservoirRates(SingleWellState<Scalar>& ws) const
}
return;
}
// For injectors in a thermal case we convert using the well bhp and temperature
// For injectors in a co2 storage case or a thermal case
// we convert using the well bhp and temperature
// Assume pure phases in the injector
const Scalar saltConc = 0.0;
Scalar rsMax = 0.0;
Expand Down
2 changes: 1 addition & 1 deletion opm/simulators/wells/WellInterfaceFluidSystem.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -81,7 +81,7 @@ class WellInterfaceFluidSystem : public WellInterfaceGeneric<typename FluidSyste
const std::vector<PerforationData<Scalar>>& perf_data);

// updating the voidage rates in well_state when requested
void calculateReservoirRates(SingleWellState<Scalar>& ws) const;
void calculateReservoirRates(const bool co2store, SingleWellState<Scalar>& ws) const;

bool checkIndividualConstraints(SingleWellState<Scalar>& ws,
const SummaryState& summaryState,
Expand Down
23 changes: 16 additions & 7 deletions opm/simulators/wells/WellState.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -149,6 +149,7 @@ serializationTestObject(const ParallelWellInfo<Scalar>& pinfo)

template<class Scalar>
void WellState<Scalar>::base_init(const std::vector<Scalar>& cellPressures,
const std::vector<Scalar>& cellTemperatures,
const std::vector<Well>& wells_ecl,
const std::vector<std::reference_wrapper<ParallelWellInfo<Scalar>>>& parallel_well_info,
const std::vector<std::vector<PerforationData<Scalar>>>& well_perf_data,
Expand All @@ -164,7 +165,7 @@ void WellState<Scalar>::base_init(const std::vector<Scalar>& cellPressures,
const Well& well = wells_ecl[w];

// Initialize bhp(), thp(), wellRates(), temperature().
initSingleWell(cellPressures, well, well_perf_data[w], parallel_well_info[w], summary_state);
initSingleWell(cellPressures, cellTemperatures, well, well_perf_data[w], parallel_well_info[w], summary_state);
}
}
}
Expand Down Expand Up @@ -202,12 +203,12 @@ template<class Scalar>
void WellState<Scalar>::initSingleInjector(const Well& well,
const ParallelWellInfo<Scalar>& well_info,
Scalar pressure_first_connection,
Scalar temperature_first_connection,
const std::vector<PerforationData<Scalar>>& well_perf_data,
const SummaryState& summary_state)
{
const auto& pu = this->phase_usage_;
const Scalar temp = well.temperature();

const Scalar temp = well.hasInjTemperature() ? well.inj_temperature() : temperature_first_connection;
auto& ws = this->wells_.add(well.name(), SingleWellState<Scalar>{well.name(),
well_info,
false,
Expand All @@ -228,18 +229,25 @@ void WellState<Scalar>::initSingleInjector(const Well& well,

template<class Scalar>
void WellState<Scalar>::initSingleWell(const std::vector<Scalar>& cellPressures,
const std::vector<Scalar>& cellTemperatures,
const Well& well,
const std::vector<PerforationData<Scalar>>& well_perf_data,
const ParallelWellInfo<Scalar>& well_info,
const SummaryState& summary_state)
{
Scalar pressure_first_connection = -1;
if (!well_perf_data.empty())
if (!well_perf_data.empty()) {
pressure_first_connection = cellPressures[well_perf_data[0].cell_index];
}
pressure_first_connection = well_info.broadcastFirstPerforationValue(pressure_first_connection);

if (well.isInjector()) {
this->initSingleInjector(well, well_info, pressure_first_connection,
Scalar temperature_first_connection = -1;
if (!well_perf_data.empty()) {
temperature_first_connection = cellTemperatures[well_perf_data[0].cell_index];
}
temperature_first_connection = well_info.broadcastFirstPerforationValue(temperature_first_connection);
this->initSingleInjector(well, well_info, pressure_first_connection, temperature_first_connection,
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

temperature related should go to the bracket within if condition if (well.isInjector())? mostly to avoid the extra broadcast.

well_perf_data, summary_state);
} else {
this->initSingleProducer(well, well_info, pressure_first_connection,
Expand All @@ -249,6 +257,7 @@ void WellState<Scalar>::initSingleWell(const std::vector<Scalar>& cellPressures,

template<class Scalar>
void WellState<Scalar>::init(const std::vector<Scalar>& cellPressures,
const std::vector<Scalar>& cellTemperatures,
const Schedule& schedule,
const std::vector<Well>& wells_ecl,
const std::vector<std::reference_wrapper<ParallelWellInfo<Scalar>>>& parallel_well_info,
Expand All @@ -258,7 +267,7 @@ void WellState<Scalar>::init(const std::vector<Scalar>& cellPressures,
const SummaryState& summary_state)
{
// call init on base class
this->base_init(cellPressures, wells_ecl, parallel_well_info,
this->base_init(cellPressures, cellTemperatures, wells_ecl, parallel_well_info,
well_perf_data, summary_state);
this->global_well_info = std::make_optional<GlobalWellInfo>(schedule,
report_step,
Expand Down Expand Up @@ -428,7 +437,7 @@ void WellState<Scalar>::resize(const std::vector<Well>& wells_ecl,
const SummaryState& summary_state)
{
const std::vector<Scalar> tmp(numCells, 0.0); // <- UGLY HACK to pass the size
init(tmp, schedule, wells_ecl, parallel_well_info, 0, nullptr, well_perf_data, summary_state);
init(tmp, tmp, schedule, wells_ecl, parallel_well_info, 0, nullptr, well_perf_data, summary_state);

if (handle_ms_well) {
initWellStateMSWell(wells_ecl, nullptr);
Expand Down
4 changes: 4 additions & 0 deletions opm/simulators/wells/WellState.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -97,6 +97,7 @@ class WellState
/// to give useful initial values to the bhp(), wellRates()
/// and perfPhaseRatesORG() fields, depending on controls
void init(const std::vector<Scalar>& cellPressures,
const std::vector<Scalar>& cellTemperatures,
const Schedule& schedule,
const std::vector<Well>& wells_ecl,
const std::vector<std::reference_wrapper<ParallelWellInfo<Scalar>>>& parallel_well_info,
Expand Down Expand Up @@ -377,12 +378,14 @@ class WellState
/// perfRates() field is filled with zero, and perfPress()
/// with -1e100.
void base_init(const std::vector<Scalar>& cellPressures,
const std::vector<Scalar>& cellTemperatures,
const std::vector<Well>& wells_ecl,
const std::vector<std::reference_wrapper<ParallelWellInfo<Scalar>>>& parallel_well_info,
const std::vector<std::vector<PerforationData<Scalar>>>& well_perf_data,
const SummaryState& summary_state);

void initSingleWell(const std::vector<Scalar>& cellPressures,
const std::vector<Scalar>& cellTemperatures,
const Well& well,
const std::vector<PerforationData<Scalar>>& well_perf_data,
const ParallelWellInfo<Scalar>& well_info,
Expand All @@ -397,6 +400,7 @@ class WellState
void initSingleInjector(const Well& well,
const ParallelWellInfo<Scalar>& well_info,
Scalar pressure_first_connection,
Scalar temperature_first_connection,
const std::vector<PerforationData<Scalar>>& well_perf_data,
const SummaryState& summary_state);
};
Expand Down
8 changes: 7 additions & 1 deletion tests/test_wellstate.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -158,6 +158,12 @@ namespace {
std::vector<double>(setup.grid.c_grid()->number_of_cells,
100.0*Opm::unit::barsa);

const auto& unit_sytem = setup.es.getDeckUnitSystem();
const double temp = unit_sytem.to_si(Opm::UnitSystem::measure::temperature, 25);
const auto ctemp =
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

although the code above uses Opm::unit::barsa, while for new code, I suggest something as follows,

        const auto& unit_sytem = setup.es.getDeckUnitSystem();
        const double temp = unit_sytem.to_si(Opm::UnitSystem::measure::temperature, 25);   // 25C

std::vector<double>(setup.grid.c_grid()->number_of_cells,
temp);

auto wells = setup.sched.getWells(timeStep);
pinfos.resize(wells.size());
std::vector<std::reference_wrapper<Opm::ParallelWellInfo<double>>> ppinfos;
Expand All @@ -171,7 +177,7 @@ namespace {
++pw;
}

state.init(cpress, setup.sched,
state.init(cpress, ctemp, setup.sched,
wells, ppinfos,
timeStep, nullptr, setup.well_perf_data, setup.st);

Expand Down