25251 Commits
Author SHA1 Message Date
Bård Skaflestad 60a7dffffc Merge pull request #7333 from GitPaean/network-well-without-vfp
Network well without vfp
2026-09-04 16:11:42 +02:00
Bård Skaflestad 878dce8b7b Merge pull request #7327 from totto82/depth_from_eclgrid
Use depth from eclGrid instead of recomputing it.
2026-09-04 15:43:53 +02:00
Kai Bao 39b11c2c45 Merge pull request #7385 from GitPaean/fix-compositional-keyword-validation
Stop reporting compositional keywords as unsupported
2026-09-04 13:46:48 +02:00
Kai Bao 693cf232d5 Stop reporting compositional keywords as unsupported
COMPS, NCOMPS, WELLSTRE and WINJGAS are all consumed: COMPS and NCOMPS
set the component count, and WELLSTRE/WINJGAS supply the injection
stream composition used by the compositional well model. Listing them
as unsupported made every flow_comp run warn about its own input.

Record the WINJGAS items the handler really does ignore, MAKEUPGAS and
STAGE, as partially supported instead, so that signal is not lost.
2026-09-04 11:34:15 +02:00
Arne Morten Kvarving e4c00a14fd Merge pull request #7358 from svenn-t/tpsa_lin_system_restructure
TPSA restructure (2/3): New preconditioner structure
2026-09-04 10:50:02 +02:00
Tor Harald Sandve f23ab03bc5 Use edited DEPTH values consistently in Flow
DEPTH array is used directly if DEPTH is edited in the EDIT section.
Note EclGrid can not be used directly as it is only available on rank 0.
2026-09-04 10:41:50 +02:00
Tor Harald Sandve 0c0893ea99 Merge pull request #7379 from hakonhagland/rc_slave_ebm
Reservoir coupling: Continue the master run when a slave run ends before it
2026-09-04 09:50:04 +02:00
Svenn Tveit 7224831c9f Apply new matrix/vector structure on TPSA linear solver
- One preconditioner for whole TPSA system; three sub-block preconditioner can be set by user
- Allows for Hypre, which is default if linked; else ilu0
2026-09-04 09:47:46 +02:00
Kai Bao 70e996ce81 Drop stale network node pressures at report step start
Pressures left from an earlier network were imposed on the wells as if
they had just been balanced.
2026-09-04 09:33:17 +02:00
Kai Bao 0d7090351d Do not impose the auto-choke group THP on wells without VFP table
The auto-choke group pressure is imposed on its wells through a path of
its own. Apply the same eligibility rule as for the extended network:
a well without a VFP table cannot be put under THP control, so no THP
limit is imposed on it, while its rates still contribute to the group
flow.

No result changes: wellHasTHPConstraints() already neutralized the
imposed limit for such wells, so the guarded path was inert.
2026-09-04 09:33:17 +02:00
Kai Bao 5b44b426eb Do not impose or retain network THP limits for wells without VFP table
The network cannot put a well without a VFP table under THP control,
so it should neither impose a dynamic THP limit on such a well nor
record a retained network_thp_limit for it. Previously only
wellHasTHPConstraints() neutralized the imposed limit; guarding the
imposition sites as well keeps the retained state meaningful and
removes the reliance on every getTHPConstraint() caller checking
wellHasTHPConstraints() first. No result changes: the guarded paths
were inert for wells without a VFP table.
2026-09-04 09:33:17 +02:00
Kai Bao 38d8c1ad5c Reconstruct network-imposed well THP limits at restart
No restart array carries the retained limit yet, so it is reconstructed
for a detached THP-controlled producer whose restart THP differs from
the schedule THP limit (a well on its own, possibly UDA-driven, limit
is left untouched). A retained limit that is not active at the restart
time is lost; this limitation is documented in the code.
2026-09-04 09:33:17 +02:00
Kai Bao 97bf3394f6 Clear retained network THP limits for wells re-specified in ACTIONX
Report-step events do not reach the simulator for ACTIONX updates, so
the SimulatorUpdate::thp_respecified_wells set of the companion opm-common
branch is used instead.
2026-09-04 09:33:17 +02:00
Kai Bao 7c803f7d45 Keep network-imposed well THP limit when a well leaves the network
The limit is stored in SingleWellState and stays in force, also across
shut periods, until the deck re-specifies the well THP limit or VFP
table (the WELL_THP_UPDATE event of the companion opm-common branch).
Previously a detached well silently reverted to the static THP limit
from the deck.
2026-09-04 09:33:17 +02:00
Kai Bao 4c8bd3696a Remove the now unused trivial_group_target well state
The preceding commit removed the only reader of this flag, leaving
write-only state that was still computed, serialized and compared.
Wells with a trivial group rate target are recognised on demand by
stoppedOrZeroRateTarget() and wellUnderZeroRateTarget().

The else branch of the rate scaling only existed to set the flag and
goes with it; the scaling itself is unchanged.
2026-09-04 09:33:17 +02:00
Kai Bao 6d274ac1da Remove stale trivial_group_target veto from THP switch check
activeProductionConstraint() skipped the switch to THP control for
GRUP-controlled wells when ws.trivial_group_target was set. That flag
is only rewritten in updateWellStateWithTarget() when a well switches
control, so it can go stale - it is set at the initial ORAT->GRUP
switch while a sibling well still covers the whole group target - and
the veto then blocks the very switch that would refresh it. Network
wells could therefore keep flowing with a THP below the nodal pressure
of the node they feed, which Eclipse never does.

Both call paths into checkIndividualConstraints() already return early
for wells whose freshly evaluated group target is zero
(stoppedOrZeroRateTarget() and wellUnderZeroRateTarget()), so the veto
could only ever act on stale information and is removed.
2026-09-04 09:33:17 +02:00
Kai Bao dc099a8462 Do not treat wells without VFP table as THP-constrained
Without a VFP table a THP limit cannot be converted to a BHP, so the
well cannot operate under a THP constraint. Previously, a network well
with WCONPROD items 10 and 11 defaulted aborted the simulation with
"Nonexistent VFP table 0 referenced". The well now stays on its
remaining controls while its rates still enter the network pressure
calculation.
2026-09-04 09:33:17 +02:00
Bård Skaflestad 88567212df Merge pull request #7244 from hnil/pr/lgr-region-arrays-on-leaf
Map region arrays onto the leaf grid for LGR (EQLNUM, PVTNUM, SWATINIT, FIP)
2026-09-03 14:19:53 +02:00
Arne Morten Kvarving 0dab45a1a6 Merge pull request #7383 from akva2/jenkins_use_ssh
use ssh for git clones
2026-09-03 12:43:30 +02:00
Arne Morten Kvarving 0ec8197007 use ssh for git clones 2026-09-03 12:28:59 +02:00
Arne Morten Kvarving 8235b4575d Merge pull request #7332 from akva2/janitoring_use_forwarding
simulator.hh: use forwarding
2026-09-03 09:38:30 +02:00
Håkon Hægland 5fa821e242 Continue the master run when a slave run ends before it
A slave whose schedule ran out before the master's deadlocked the whole
coupled run.  The slave called MPI_Comm_disconnect(), which blocks until
the master joins the collective close, while the master blocked in
MPI_Recv() waiting for a next report date that the slave would never
send.  Neither side could proceed, and the remaining slaves were starved
behind the stuck master.

Two things were wrong.  The message protocol had no way for a slave to
say that its run had ended.  And receiveTerminateAndDisconnect()
disconnected without checking the signal value it had just received, so
it mistook the master's routine "keep going" for a shutdown order and
also logged a misleading "Received terminate signal from master
process".

A slave that runs out of report steps now answers on the
next-report-date channel with a negative sentinel value.  A genuine
offset is measured from the slave's own start and is therefore never
negative, so no new message tag is needed, and the master learns about
the ended slave at exactly the point where it used to block.  The master
acknowledges, disconnects that one intercommunicator, reports

    Slave run RES-1 has ended.
    Master run will continue with no flow from this slave.

and carries on without that slave.

Add slaveHasEnded() and slaveIsCoupled() alongside the existing
slaveIsActivated().  slaveIsActivated() keeps its literal meaning and
stays monotonic, while slaveIsCoupled() means "activated and not ended"
- the question every gate actually wants to ask before exchanging
messages with a slave, or before letting its master groups contribute
rates and guide rates.  Switching those gates is most of the diff.

Little more was needed, because the master already had a complete
zero-flow path for a slave that has not activated yet:
receiveProductionDataFromSlaves() and receiveInjectionDataFromSlaves()
already substituted zeros, and
excludeInactiveSlaveMasterGroupsFromDistribution_() already forced the
effective group-controlled-wells count to zero so those master groups
drop out of guide-rate distribution.  An ended slave reuses all of it.

Verified on a two-slave case with the first slave's last report step
removed: the run now completes, and from the moment that slave ends the
field oil production rate equals the remaining slave's group rate
exactly.  With the unmodified deck, results are bit-identical to a run
without this change at every shared report point.

Making the master stop instead of continuing, via item 8 of GECON, is a
separate option that remains unimplemented.
2026-09-02 17:00:16 +02:00
Tor Harald Sandve cc86c4f5a2 Merge pull request #7366 from hakonhagland/fix_new_well_presolve_rates
Reservoir coupling: make a master group's injection target reflect what the slaves are actually producing
2026-09-02 16:56:01 +02:00
Markus Blatt 309d052375 Merge pull request #7375 from daavid00/unused
Fixing warning: unused variable
2026-09-02 13:25:17 +02:00
Bård Skaflestad 75620ac338 Merge pull request #7329 from hnil/pr/mech-keep-grid-and-deck
Keep the zero-trans overlap and the deck in mechanical runs
2026-08-31 10:45:27 +02:00
David Landa Marban 4165c1572a Fixing warning: unused variable 2026-08-31 09:04:18 +02:00
Bård Skaflestad 5e1a1325d2 Merge pull request #7328 from hnil/pr/eclwriter-dynamic-conns
EclWriter: forward dynamically created well connections to EclipseIO
2026-08-28 17:43:19 +02:00
hnilandClaude Opus 5 b727430847 Retain the Schedule keywords for FRAC runs, decided from the parsed RUNSPEC
A fracture model reads its seeds out of the deck during the run rather than
only at setup, so those keywords must survive.  Gated on runspec().frac()
rather than on mechanics as a whole: a TPSA run has no such need, and
svenn-t asked not to enable it for every geomechanics simulator.

Decided inside readDeck because keepKeywords is an input to deck reading
while frac() is an output of it - the caller cannot know yet.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
2026-08-28 15:57:20 +02:00
hnilandClaude Opus 5 db33610c05 Use isIORank() rather than comparing the rank directly
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
2026-08-28 13:58:38 +02:00
hnilandClaude Fable 5 3612d06a6c EclWriter: forward dynamically created well connections to EclipseIO
recordNewDynamicWellConns() passes fracture-created connections (well name
+ zero-based Cartesian cell ids) to the output layer on the I/O rank, so
the summary engine can instantiate connection-level vectors for them
(opm-common already provides the receiving API).

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
2026-08-28 13:57:36 +02:00
Håkon Hægland ae617f53b5 Say why the new-well correction reads the live schedule events
The correction applies only while the wells of this sync step have not
been solved, and only to wells the schedule flags as NEW_WELL.  That it
fires exactly once per newly opened well depends on the NEW_WELL flag
being cleared after the first time step of the report step, which is a
property of the live event object and not of the report-step snapshot
BlackoilWellModel keeps beside it.

Nothing in the code said so, and the snapshot is the more obvious source
to reach for.  Switching to it would reintroduce the very problem the
correction exists to avoid, on every sync step after the first.  Write
that down.

Prompted by a review comment on #7366.
2026-08-28 12:57:54 +02:00
Håkon Hægland 36d5269d56 Remove exactly what the group rate sum added for an unsolved new well
The correction for a newly opened, not yet solved well reproduced only
part of what sumWellPhaseRates() does per well: it applied the network
efficiency factor but not the well's efficiency_scaling_factor, and it
filtered on nothing but the NEW_WELL event.  Two consequences.  A newly
opened injector would have had its rate subtracted from the group's
*production*, because getWellRateVector() reports positive magnitudes
for producers and injectors alike; the model this was developed on only
escapes that because its new injectors are GRUP-controlled and start
from zero rather than from a target.  And a producer whose rates are
dynamically scaled was only partially removed.  Two further mismatches:
shut wells are skipped by the sum but were not skipped here, and
getWellRateVector() reads the nupcol well state where the sum reads the
live one.

Build the correction from wellRateContributionToGroup() instead, the
same per-well step the sums use, so it removes precisely what they
added.  That makes it rank-local, like the sums: the network rates now
apply it before their reduction, and the surface rates reduce it before
subtracting it from the already-reduced group state value.

Spotted by Copilot in review of #7366.
2026-08-28 12:57:43 +02:00
Håkon Hægland 8f64eadb31 Extract the per-well contribution to a group rate sum
sumWellPhaseRates() decides per well whether it belongs in the sum at
all -- present in this rank's well state, owned by this rank, of the
right type, not shut -- and with what efficiency factor and sign it
enters.  Callers that need to add or remove a single well's share of
such a sum have to reproduce all of that, and get it wrong when they
reproduce only part.

Move the body of the well loop into wellRateContributionToGroup() and
call it from the loop.  No functional change.
2026-08-28 12:57:43 +02:00
Kai Bao f2a6ad1596 Merge pull request #7367 from GitPaean/stdwell_fsinfo_plumbing
moving getFirstPerforationFluidStateInfo to the WellInterface
2026-08-28 12:44:11 +02:00
Kai Bao 1bdff1bddc moving the first-perforation cell conditions to the WellInterface
so both StandardWell and MultisegmentWell can use them. The temperature and
salt concentration of the first perforated cell are kept in a small struct
with named members instead of a std::tuple.
2026-08-28 11:44:48 +02:00
Kai Bao b31a1ac19f Merge pull request #7365 from GitPaean/msw_segments_detemplate_fluidstate
MSW: move segment property calculations back to the .cpp file
2026-08-28 09:13:34 +02:00
Håkon Hægland f78037f0c8 RESCOUP: remove a declaration left without a definition
restoreMasterGroupControlsFromSchedule_() lost both its only caller and
its definition in #7203; the declaration in RescoupConstraintsCalculator
was left behind.
2026-08-27 20:36:03 +02:00
Håkon Hægland d0f4b6e947 Keep a master group's injection target in step with slave production
A master group under a GCONINJE mode that turns production into an
injection target -- REIN, SALE or VREP -- gets that target from the
production the master has been told about.  The target is computed once
per sync step, in beginTimeStep(), from the group rates the slaves report
before they solve their wells for that step, so it is a target for the
*previous* step's production.  The targets are never revised, even though
the master keeps receiving fresh slave rates all through the step.

A step in which slave production changes therefore injects the wrong
amount for its whole length.  With a field under GCONINJE ... REIN, the
gas not injected leaves the balance as sales gas, so the sales rate
jumps for one step and then returns.

Recompute the injection targets after each non-final slave-rate receive
inside the master's network iteration and send them to the slaves, which
now expect that message where they previously only sent.  Production
constraints are not resent: the slaves have already solved their wells
against them, and they are what produced the rates the recomputation is
based on.

The recomputation is unconditional, so it also re-sends targets that
cannot have changed -- a RATE target is a deck constant, and a RESV
target moves only with the other phases' reservoir injection.  A TODO on
the new entry point records what a filter would have to check: not the
group's own GCONINJE record, since the target comes from the controlling
ancestor and that ancestor's mode changes during a run.

The injection half of calculateSlaveGroupConstraints_() is split out as
calculateSlaveGroupInjectionTargets_() so both entry points share it.
2026-08-27 20:35:56 +02:00
Håkon Hægland 7e9be57452 RESCOUP: do not report an unsolved new well's target as achieved production
A reservoir-coupling slave ships its group rates to the master twice per
sync step: once in beginTimeStep() before it solves its wells for the
step, and once after.  A well that opens in the report step is put on its
WCONPROD target by SingleWellState::update_producer_targets() before that
solve runs, as an initial guess, so on the first send the slave reports a
target as achieved production.

The master folds those rates into the field's reinjection base.  With the
field under GCONINJE ... REIN, a multi-million sm3/day gas target arriving
that way pushes the reinjection target past the GCONINJE maximum, which
switches the field's gas injection control to RATE.  In RATE mode the
target is the maximum itself, independent of production, so the correct
values that arrive later in the same sync step cannot bring it back down:
the injectors sit on their cap for the whole step.

Track in ReservoirCouplingSlaveReportStep whether the wells have been
solved this sync step -- alongside the other per-sync-step flags kept
there -- and while they have not, leave a well that opens in this report
step out of the group rates the slave sends.  The event alone cannot be
used as the condition: it stays set for the whole report step and so
cannot tell the two sends apart.

The exclusion covers both the surface production rates and the network
surface rates -- the master uses the latter as the flow of its network's
leaf nodes -- and descends into child groups applying their efficiency
factors, since a group named in GRUPSLAV need not hold wells directly.

The gas reinjection rate the slave reports is derived the same way and has
the same defect, but the master stores that field without ever reading it,
so it is left alone.
2026-08-27 18:50:33 +02:00
Kai Bao 1841d02546 MSW: reuse the segment PVT buffer
computeSegmentFluidProperties() allocated and value-initialized a vector of
segment PVT values on every call. Keep it as a member alongside the segment
fluid states it is filled from, so the assembly path only refills it.
2026-08-27 15:11:08 +02:00
Kai Bao 7fbfc2728a MSW: move segment property calculations back to the .cpp file
The segment property calculations were templated on the fluid state type, which
depends on the TypeTag that MultisegmentWellSegments does not have, so they had
to live in the header.

They only read pressure, temperature, salt concentration, the inverse formation
volume factors and Rs/Rv from the fluid state, and those are all EvalWell, which
is concrete for <FluidSystem, Indices>. Pass them in a small struct instead, so
computeFluidProperties(), computeVolumeRatio() and calculatePhaseState() are no
longer templates and are instantiated with the class in the .cpp file.
2026-08-27 14:34:21 +02:00
Kai Bao 1ece122daf Merge pull request #7363 from GitPaean/msw_segment_fs_cleanups
Msw segment fs cleanups
2026-08-27 13:48:29 +02:00
Kai Bao e051a005b4 MSW: compute the segment volume ratio where it is used
Before: updateSegmentFluidState() cached the volume ratio of every segment and
getSegmentSurfaceVolume() read that cache; on the assembly path
computeFluidProperties() overwrote it immediately, so the work was discarded.

Now: updateSegmentFluidState() only builds the fluid states, the ratio is
computed where it is consumed and passed to getSegmentSurfaceVolume(), and
volume_ratios_ has a single writer.
2026-08-27 13:15:44 +02:00
Kai Bao 61373ab5d8 Consolidated initialization into computeInitialSegmentInventory().
It initializes mass inventory and, when enabled, energy inventory in the
same per-segment loop; the separate computeInitialSegmentEnergy() helper was removed.
2026-08-27 13:15:44 +02:00
Kai Bao 15e9aa1b98 Merge pull request #7362 from GitPaean/msw_segment_fs_derive_properties
Msw segment fs derive properties
2026-08-27 13:08:32 +02:00
Arne Morten Kvarving 790ba86104 Merge pull request #7357 from svenn-t/tpsa_matrix_vector
TPSA restructure (1/3): New matrix/vector framework
2026-08-27 12:20:24 +02:00
Tobias Meyer Andersen 95ff1d3fd3 Merge pull request #7342 from havahol/test_preconditioner_factory_gpu-bugfix
bugfix when creating GpuSeqILU0 from GPU matrix
2026-08-27 11:43:07 +02:00
Kai Bao 1e192a10cc MSW: derive segment fluid properties from the segment fluid states
The per-segment fluid state becomes the single source of truth for the
segment fluid properties and surface volume, for thermal and non-thermal
runs alike. It is rebuilt from the current primary variables at the point
of consumption (computeSegmentFluidProperties), and its stored inverse
formation volume factors and Rs/Rv are reused whenever they coincide with
the values the property calculation needs (both oil and gas present, the
common case). This removes the duplicated from-scratch PVT calculations
in computeFluidProperties()/getSurfaceVolume() and the scattered fluid
state refresh calls, while reproducing the previous results exactly.
2026-08-27 11:12:50 +02:00
Bård Skaflestad 8a60739018 Merge pull request #7346 from GitPaean/add-weldraw
supporting the WELDRAW keyword from the simulator side.
2026-08-27 11:00:21 +02:00
Svenn Tveit 2f227eb6c2 New matrix and vector classes for TPSA.
- Old 7x7 block structure is broken up to several sub-matrices, purpose-made for preconditioners like Hypre.
- New structure made to interface 7x7 structure in linearizer without changes.
2026-08-27 11:00:05 +02:00