Skip to content

Store primary variables in well state, and improve well initialization#6114

Merged
GitPaean merged 7 commits intoOPM:masterfrom
atgeirr:safer_well_state
May 8, 2025
Merged

Store primary variables in well state, and improve well initialization#6114
GitPaean merged 7 commits intoOPM:masterfrom
atgeirr:safer_well_state

Conversation

@atgeirr
Copy link
Member

@atgeirr atgeirr commented Mar 27, 2025

Revised and rebased, based on #5990 originally. Removed some changes to simplify investigation.

For now, just for testing.

Description of the change for the manual: (new edit)
This changes well behaviour in two ways:

  • Improve initialization procedure for production wells to be more robust, in particular ensure we get good gas and water fractions for VFP table lookup.
  • Storing the gas and water fractions of a well across iterations to better deal with situations such as stopped wells, where it is not possible to reconstruct gas and water fractions from the rates.

@atgeirr
Copy link
Member Author

atgeirr commented Mar 27, 2025

jenkins build this failure_report please

if (well->isProducer() && !zero_target) {
well->updateWellStateRates(simulator_, this->wellState(), local_deferredLogger);
//const bool zero_target = well->stoppedOrZeroRateTarget(simulator_, this->wellState(), local_deferredLogger);
if (well->isProducer()){// && !zero_target) {
Copy link
Member

Choose a reason for hiding this comment

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

Here, I think this is the main change of this PR from #5990 . Just putting note for own reference.

if (stop_or_zero_rate_target && seg == 0) {
value_[seg][WQTotal] = 0;
}
assert(ws.initializedFromReservoir());
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 because of the if (well->isProducer()){// && !zero_target) { above, it caused many assertion failures, I believe. Because injectors also go here.

@atgeirr atgeirr force-pushed the safer_well_state branch 3 times, most recently from 60d47cd to d0f70c6 Compare April 2, 2025 11:25
@atgeirr atgeirr marked this pull request as ready for review April 2, 2025 13:00
@atgeirr
Copy link
Member Author

atgeirr commented Apr 2, 2025

I think this should be ready now. I have addressed the assert() issue pointed out by @GitPaean above. The major changes are:

  • Ensure that WellInterface::initializeProducerWellState() [new name for updateWellStateRates()] is called when initializing a well from scratch, also rewrite that function to evaluate at bhp limit or 1 bar instead of 0 bar (from default-initialized primary variables).
  • Store well primary variables in SingleWellState, and restore from that class if they are set (and have the right size), when in the update() methods of the (Standard and Multisegment)PrimaryVariable classes.

@atgeirr
Copy link
Member Author

atgeirr commented Apr 2, 2025

jenkins build this failure_report please

WellState<Scalar>& well_state,
DeferredLogger& deferred_logger) const
{
assert(isProducer());
Copy link
Contributor

Choose a reason for hiding this comment

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

assert(this->isProducer());

Copy link
Member Author

Choose a reason for hiding this comment

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

Oops, fixed.

@atgeirr atgeirr force-pushed the safer_well_state branch 2 times, most recently from 8a8f761 to d791cdc Compare April 2, 2025 13:40
@atgeirr
Copy link
Member Author

atgeirr commented Apr 2, 2025

jenkins build this failure_report please

@atgeirr atgeirr force-pushed the safer_well_state branch from d791cdc to 13461a4 Compare April 3, 2025 15:00
@atgeirr
Copy link
Member Author

atgeirr commented Apr 3, 2025

jenkins build this failure_report please

@atgeirr atgeirr force-pushed the safer_well_state branch 2 times, most recently from d0ad9b6 to 52f07a7 Compare April 4, 2025 13:12
@GitPaean
Copy link
Member

GitPaean commented Apr 7, 2025

jenkins build this failure_report please

const int gas_pos = pu.phase_pos[Gas];
value_[seg][GFrac] = well_.scalingFactor(gas_pos) * segment_rates[well_.numPhases() * seg + gas_pos] / total_seg_rate;
}
// what about water and gas injection?
Copy link
Member

Choose a reason for hiding this comment

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

Just explaining the question in the comments, for other segments, they can use the same formula, for top segments, segment rates are the well rates, for water and gas injection, they will have a non-zero rates for either water or gas, while it does not break the formula either.

Copy link
Member

Choose a reason for hiding this comment

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

If you agree with the response, you can remove the comment.

// This also applies to the ORAT/WRAT/GRAT above, but then only the
// rate not set in the above will be modified in
// WellInterface::initializeProducerWellState().
if (this->pu.phase_used[BlackoilPhases::Liquid]) {
Copy link
Member

Choose a reason for hiding this comment

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

I might miss something here, and not talking about the approach either, but from the code level, will we miss something by std::fill(this->surface_rates.begin(), this->surface_rates.end(), 0.); here?

const double factor = rates_evaluated_at_1bar ? 0.5 : 1.0;
for (int p = 0; p < this->number_of_phases_; ++p) {
ws.surface_rates[p] = well_q_s[this->flowPhaseToModelCompIdx(p)];
ws.surface_rates[p] = factor * well_q_s[this->flowPhaseToModelCompIdx(p)];
Copy link
Member

Choose a reason for hiding this comment

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

Do you see any situation that the factor matters? The efforts is about to improve the fractions.

@GitPaean
Copy link
Member

GitPaean commented Apr 7, 2025

I checked the regression failures a little bit, not exhaustive. Most of the cases look fine. while the mpi.compareECLFiles_flow+WVFPEXP-02 , mpi.compareECLFiles_flow+MOD4_UDQ_ACTIONX,

maybe also
mpi.compareECLFiles_flow+MSW-2D-VERT-02

can get some checking.

@atgeirr
Copy link
Member Author

atgeirr commented Apr 9, 2025

Thanks to @GitPaean for testing, and pointing out some errors that are now hopefully fixed.

@atgeirr
Copy link
Member Author

atgeirr commented Apr 9, 2025

jenkins build this failure_report please

@GitPaean
Copy link
Member

most of the regression failures look fine, the following ones have something to look at,

09_multiply_tranxyz_model2.pdf
image

14_udt_udt-1d-03.pdf
image

15_wvfpexp_02.pdf
image

36_network_balance_01.pdf (same with other few network models.)
image

@GitPaean
Copy link
Member

jenkins build this failure_report please

@GitPaean
Copy link
Member

The regression failure looks similar while there are more regressions. I will pick a couple to investigate some to see what is the problem.

The one I will look at 02_editnnc, 09_multiply, 15_wvfpexp_02, maybe also the network one.

@GitPaean
Copy link
Member

jenkins build this failure_report please

@atgeirr atgeirr changed the title Modified version of safer well state Store primary variables in well state, and improve well initialization May 5, 2025
@GitPaean
Copy link
Member

GitPaean commented May 5, 2025

The number of the regression failures, 191, stays unchanged and let me check the detailed comparisons.

https://ci.opm-project.org/job/opm-simulators-PR-builder/8015/#showFailuresLink

@GitPaean
Copy link
Member

GitPaean commented May 5, 2025

11_udt-1d-03
some bumps at the end
image

multiple cases in this series the guide rates are different,
e.g. 15_0a4_grctrl_lrat_lrat_ggr_base_model2_stw
image

multiple wells in this case 16_model4_udq_group

image

some chopping in this case, 17_6_endscale_model2
image

some chopping in this case also, 26_1_multregt_model2
image

the network cases have different guide rates, 34_network-01_standard
image

not saying there are problematic, while worth looking into a little bit.

const int comp_idx_nz = this->flowPhaseToModelCompIdx(nonzero_rate_index);
if (std::abs(well_q_s[comp_idx_nz]) > floating_point_error_epsilon) {
const Scalar computed_rate = well_q_s[nonzero_rate_index];
if (std::abs(initial_nonzero_rate) < std::abs(computed_rate)) {
Copy link
Member

@GitPaean GitPaean May 6, 2025

Choose a reason for hiding this comment

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

Why do we need to check std::abs(initial_nonzero_rate) < std::abs(computed_rate)? It might save some small computation potentially, while it adds more complication to the code. The results should be the same?

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 initial_nonzero_rate is greater than computed_rate we should not scale everything to match that rate, because the computed_rate comes from a bhp limit and we should not go above that rate (i.e. factor would be > 1).

An example: we have a GRAT control set to a high number as an important constraint for the later parts of the simulation, but at the start of simulation the gas rate is low. Then we might scale the rate up to be much higher than the BHP-limit rate.

@GitPaean
Copy link
Member

GitPaean commented May 6, 2025

11_udt-1d-03
some bumps at the end
image

This one is using UDT and UDQ to control the opening of the well, while somehow not sure why the wells is re-opened after 24 Jan 2023. There is not useful information in the DBG and PRT files.

The schedule looks like the following,

DATES
 2 JAN 2023 /
/
 
-- Reduce BHP limit as pressure drops

UDT
 'TU_FBHP' 1 /
 'LL'  100.0  500.0 / -- FOPR values
       100.0  180.0 / -- WBHP values
/
/

UDQ
ASSIGN WU_WBHP 0 /
DEFINE WU_WBHP0 WU_WBHP /
DEFINE WU_WBHP ((TU_FBHP[WOPR] UMIN WBHP) UMIN WU_WBHP0) UMAX 10.0 /  -- MIN BHP = 10
/

WCONPROD
  'PROD1'  'OPEN'  ORAT   500.0   4*   WU_WBHP /
  'PROD2'  'OPEN'  ORAT   500.0   4*   WU_WBHP /
/
 
DATES
 15 FEB 2023 /
/

@GitPaean
Copy link
Member

GitPaean commented May 6, 2025

11_udt-1d-03 some bumps at the end image

This one is using UDT and UDQ to control the opening of the well, while somehow not sure why the wells is re-opened after 24 Jan 2023. There is not useful information in the DBG and PRT files.

Basically, it shows that the local solve can open a well being STOPPed, which should be a fallout in the logic. The logic related to wellIsStopped and others are rather complicated.

@atgeirr
Copy link
Member Author

atgeirr commented May 6, 2025

Basically, it shows that the local solve can open a well being STOPPed, which should be a fallout in the logic. The logic related to wellIsStopped and others are rather complicated.

This would be an issue unrelated to this PR then, but something we should figure out and fix.

if (well->isProducer() && !zero_target) {
well->updateWellStateRates(simulator_, this->wellState(), local_deferredLogger);
if (well->isProducer()) {
well->initializeProducerWellState(simulator_, this->wellState(), local_deferredLogger);
Copy link
Member

Choose a reason for hiding this comment

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

removing && !zero_target caused the regression for the case, it is part of the difficulties that difficult to describe the flow fractions for zero rate situation when we use only surface rates to initialize the primary variables. We should have fraction information, basically zero total rate and proper fraction for the phases.

11_udt-1d-03
some bumps at the end
image

Copy link
Member

Choose a reason for hiding this comment

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

not saying the master branch is well designed, I believe the initialized rates play difference in the following logic with nonzero_rate_original.

            if (converged) {
                const bool zero_target = this->wellUnderZeroRateTarget(simulator, well_state, deferred_logger);
                if (this->wellIsStopped() && !zero_target && nonzero_rate_original) {
                    // Well had non-zero rate, but was stopped during local well-solve. We re-open the well 
                    // for the next global iteration, but if the zero rate persists, it will be stopped.
                    // This logic is introduced to prevent/ameliorate stopped/revived oscillations  
                    this->operability_status_.resetOperability();
                    this->openWell();
                    deferred_logger.debug("    " + this->name() + " is re-opened after being stopped during local solve");
                }
            }

It will open a well previously stopped due to not solvable or operable.

@GitPaean
Copy link
Member

GitPaean commented May 7, 2025

For the following case,
e.g. 15_0a4_grctrl_lrat_lrat_ggr_base_model2_stw=
image

It looks like that at the start of the simulation, the simulator mistakenly thinks some wells are under zero rate target due to the uninitialized well state, it is also the change that removing !zero_target makes the major difference, while it might be a good thing because the master branch mistakenly think the wells under zero rate target (from the mistaken calculation of the group target based on the uninitialized well rate and potentials (did not go through all the logics))

Likely the other guide rate related regression are also due to this.

@GitPaean
Copy link
Member

GitPaean commented May 7, 2025

some chopping in this case also, 26_1_multregt_model2
image

This one is due to different time stepping and no other abnormality is observed.

@GitPaean
Copy link
Member

GitPaean commented May 7, 2025

multiple wells in this case 16_model4_udq_group

image

This looks like due to different time stepping at the end the wells are under different controls. I will not investigate more in details due to capacity.

@atgeirr atgeirr force-pushed the safer_well_state branch from a99446e to 272fb20 Compare May 7, 2025 13:56
@GitPaean
Copy link
Member

GitPaean commented May 7, 2025

jenkins build this failure_report please

@steink
Copy link
Contributor

steink commented May 7, 2025

  • Tested suggestion to set ws.primaryvar.resize(0); at the top of 'updateWellStateWithTarget' in order to force updating of primary variables together with doing updatePrimaryVariables(simulator, well_state, deferred_logger); at beginning of iterateWellEqWithControl/ iterateWellEqWithSwitching (both std/ms versions) to ensure consistency. This removed all singularities for the case I'm looking at.

 - Discard stored primary variables in updateWellStateWithTarget().
 - Ensure primary variables are updated to match WellState before solving wells.
@atgeirr
Copy link
Member Author

atgeirr commented May 7, 2025

jenkins build this failure_report please


// Discard old primary variables, the new well state
// may not be anywhere near the old one.
ws.primaryvar.resize(0);
Copy link
Member

Choose a reason for hiding this comment

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

should we just call updatePrimaryVariable at the end of the this function instead so make sure the updated well state will be reflected in the primary variables?

Copy link
Member Author

Choose a reason for hiding this comment

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

The problem is that if we do that, the primary variables will read the values stored in ws.primaryvar (which are not modified in this function) instead of setting the primary variables based on surface_rates etc. An alternative would be a boolean flag similar to what was in earlier versions of this, but the current version requires no extra data member so I prefer it.

@GitPaean
Copy link
Member

GitPaean commented May 8, 2025

the regressions look good. I think we can update_data now from my side.

@steink
Copy link
Contributor

steink commented May 8, 2025

the regressions look good. I think we can update_data now from my side.

Good. Confirmed that I now get identical results with my previous testing

@atgeirr
Copy link
Member Author

atgeirr commented May 8, 2025

jenkins build this update_data please

jenkins4opm pushed a commit to jenkins4opm/opm-tests that referenced this pull request May 8, 2025
Reason: PR OPM/opm-simulators#6114

opm-common     = dd017b2947babb2f021044d3b04221d744de946a
opm-grid       = d908ec89a9f83d17a419cb0abfde8e0481f6cb28
opm-simulators = 595b2348dd5c71fc83f2c35d1de9c53418609118

### Changed Tests ###

  * spe1flowexp
  * spe1case1
  * spe1case1_import
  * spe1case2_krnum
  * spe1case2_thermal
  * spe1case2_thermal_watvisc
  * spe1case1_brine
  * spe1case1_precsalt
  * gasoil_precsalt
  * network-01
  * network-01_standard
  * network-01-reroute
  * network-01-reroute_std
  * network_01_wtest
  * spe1_metric_vfp1
  * jfunc_01
  * ctaquifer_2d_oilwater
  * numerical_aquifer_3d_2aqu
  * numerical_aquifer_3d_1aqu
  * aquflux_01
  * spe9
  * spe9(restart)
  * spe9group
  * spe9group_resv
  * msw_2d_h
  * msw_3d_hfa
  * polymer_injectivity
  * spe5
  * msw_model_1
  * base_model_1
  * faults_model_1
  * base_model2_welpi
  * 0a1_grpctl_msw_model2
  * 0a2_grpctl_msw_model2
  * 0a3_grpctl_msw_model2
  * 0a4_grpctl_msw_model2
  * udq_actionx
  * udq_wconprod
  * actionx_m1
  * waghyst2
  * gpmaint11
  * gconprod_t1l
  * gconprod_t1w
  * gconprod_t2o
  * pinch_pinch_multz_all
  * pinch_pinch_multz-_all
  * pinch_pinch_multz_all_barrier
  * pinch_pinch_multz-_all_barrier
  * pinch_pinch10_nopinch
  * pinch_t1a_gap
  * pinch_t1a_nogap
  * pinch_t1a_nopinch
  * pinch_t1a1_nogap
  * pinch_t2a1_gap
  * pinch_t2a_nopinch
  * pinch_t2a_gap
  * pinch_t1b_nopinch
  * pinch_t1b1_gap
  * pinch_t1b2_gap
  * pinch_t1b3_gap
  * pinch_t1b4_gap
  * pinch_t1b5_gap
  * pinch_t1b6_gap
  * pinch_t1c_nopinch
  * pinch_t1c1_nogap
  * pinch_t1c1_gap
  * pinch_t1c2_gap
  * pinch_t1c2_nogap
  * pinch_t1c3_gap
  * pinch_t1c3_nogap
  * pinch_t1d_nopinch
  * pinch_t1d1_gap
  * pinch_t1d1_nogap
  * udt-1d-03
  * equalreg_multy_1
  * equalreg_multy_2
  * equalreg_multy_3
  * equalreg_multy_4
  * equalreg_multy_6
  * WCYCLE_0
  * WCYCLE_1
  * WCYCLE_2
  * WCYCLE_3
  * WCYCLE_4
  * WCYCLE_5
  * WCYCLE_6
  * WCYCLE_7
  * WCYCLE_8
  * udq_undefined
  * udq_in_actionx
  * reg_smry_in_fld_udq
  * actionx_gconinje
  * actionx_gconprod
  * actionx_udq
  * actionx_wconhist
  * actionx_wconinjh
  * actionx_wefac
  * udq-01
  * cskin_1
  * cskin_2
  * cskin_3
  * cskin_4
  * co2store_gaswat
  * h2store_gaswat
  * udq_pyaction
  * 0_base_model2
  * 0_base_model2_let
  * 0a1_grctrl_lrat_orat_base_model2_stw
  * 0a2_grctrl_lrat_orat_ggr_base_model2_stw
  * 0a3_grctrl_lrat_lrat_base_model2_stw
  * 0a4_grctrl_lrat_lrat_ggr_base_model2_stw
  * 0c_base_fbhpdef
  * 1_multregt_model2
  * 2_multxyz_model2
  * 3_a_mpi_multflt_sched_model2
  * 5_swatinit_model2
  * 6_endscale_model2
  * 7_hysteresis_model2
  * 8_multiply_tranxyz_model2
  * 9_editnnc_model2
  * 9_1a_depl_max_rate_min_bhp_stw
  * 9_1a_depl_max_rate_min_bhp_msw
  * 9_1b_depl_max_rate_min_thp_stw
  * 9_1b_depl_max_rate_min_thp_msw
  * 9_2a_depl_gconprod_1l_stw
  * 9_2a_depl_gconprod_1l_msw
  * 9_2b_depl_gconprod_2l_stw
  * 9_2b_depl_gconprod_2l_msw
  * 9_3a_ginj_rein-g_stw
  * 9_3a_ginj_rein-g_msw
  * 9_3b_ginj_gas_export_stw
  * 9_3b_ginj_gas_export_msw
  * 9_3c_ginj_gas_gconsump_stw
  * 9_3c_ginj_gas_gconsump_msw
  * 9_3d_ginj_gas_max_export_msw
  * 9_3e_gas_min_export_stw
  * 9_3e_gas_min_export_msw
  * 9_4a_winj_maxwrates_maxbhp_gconprod_1l_stw
  * 9_4a_winj_maxwrates_maxbhp_gconprod_1l_msw
  * 9_4b_winj_vrep-w_stw
  * 9_4b_winj_vrep-w_msw
  * 9_4c_winj_ginj_vrep-w_rein-g_stw
  * 9_4c_winj_ginj_vrep-w_rein-g_msw
  * 9_4d_winj_ginj_gas_export_stw
  * 9_4d_winj_ginj_gas_export_msw
  * multflt_model2
  * multpvv_model2
  * 9_3d_grpctl_stw_model2
  * model4_udq_group
  * model4_gefac
  * model6_msw
  * wsegsicd
  * wsegaicd
  * wsegvalv
  * wsegvalv_2d_vert
  * spe1_foam
  * spe1_solvent_foam
  * spe1_gaswater_solvent
  * norne_reperf
  * compl_smry
  * 3d_tran_operator
  * 0_base_model6
  * 0a_aquct_model6
  * 0b_rocktab_model6
  * base_wt_tracer
  * base_wt_tracer(restart)
  * min_bhp_1
  * min_bhp_2
  * min_bhp_3
  * min_thp_1
  * max_gor_1
  * min_gasrate_1
  * min_qoil_1
  * max_watercut_1
  * max_watercut_2
  * max_watercut_3
  * max_watercut_4
  * rxft_smry
  * actionx_wpimult
  * wvfpexp_02
  * krnum-03y
  * krnum-03z
  * 01_wgrupcon
  * 02_wgrupcon
  * winjmult_stdw
  * winjmult_msw
  * winjdam_stdw
  * winjdam_msw
  * multflt-03
  * gsatprod
  * spe1_float
@GitPaean
Copy link
Member

GitPaean commented May 8, 2025

jenkins build this opm-tests=1338 please

GitPaean added a commit to OPM/opm-tests that referenced this pull request May 8, 2025
@GitPaean
Copy link
Member

GitPaean commented May 8, 2025

The downstream reference has been installed, I am merging this PR in now.

@GitPaean GitPaean merged commit 26c20d6 into OPM:master May 8, 2025
1 check passed
@atgeirr atgeirr added the manual:enhancement This is an enhancement/improvent that needs to be documented in the manual label May 9, 2025
@atgeirr atgeirr deleted the safer_well_state branch May 12, 2025 11:52
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

manual:enhancement This is an enhancement/improvent that needs to be documented in the manual

Projects

None yet

Development

Successfully merging this pull request may close these issues.

4 participants

Comments