This commit places more conditions on the branch discovery order
than the previous work in commit 6d3ee57dd. In particular, we now
ensure that branches are discovered ("created") in the order of
increasing segment number of the branch outlet segment.
Furthermore, if multiple branches have the same outlet segment, then
we sort those branches on their increasing branch IDs.
To this end, switch from using a std::queue<int> to using a
std::priority_queue<KickOffPoint>, with the KickOffPoint being a
custom structure holding the kick-off segment, the branch outlet
segment, and the branch ID and a custom operator<() to plug into the
priority_queue<> heap mechanism.
This new sort order changes the result of certain unit tests, but
those changes are expected and desired.
This commit adds a new class template argument,
bool PermitSelfConnections
with a default value of 'false', that enables client code to
configure whether or not function
addConnection(v1, v2)
creates a connection from v1 to v2 if v1 == v2. The default state
preserves the current behaviour which ignores such connections.
Permitting self connections makes the class slightly more general to
uses cases outside inter-region flow accumulation.
This way there is no constructor with an output parameter and we
prevent introducing an additional member in ActionX that is only used
in one constructor.
When encountering these (e.g. a number instead of an expression on
the left hand side) the simulator would immediately abort with an
error message like:
```
Error: An error occurred while creating the reservoir schedule
Internal error: Extra unhandled data starting with token[0] = 135
Error: Unrecoverable errors while loading input: Extra unhandled data starting with token[0] = 135
```
(The message above is for the number 135 on the left hand side)
With this change we now use the usual way of handling errors and
warnings in the parser and continue parsing.
The error message for the problem above is now
```
Error: condition of action EX1 has the following error: Left side of comparsion (135) has to be an expression!
Error: Problem with keyword ACTIONX
In model.schedule line 562
condition of action EX1 has the following error: Left side of comparsion (135) has to be an expression!
Error: Unrecoverable errors while loading input: Problem with keyword ACTIONX
In model.schedule line 562
condition of action EX1 has the following error: Left side of comparsion (135) has to be an expression!
This commit enables updating individual well properties for one or
more wells using the WELSPECS keyword. In particular, this revised
logic enables changing the controlling group without affecting any
other well property such as the location of the well head or the
well reference depth.
Defaulted properties do not affect change in Well::update*(). This,
in turn, begets a change to the logic of how we update the reference
depths. Previously, we always interpreted a defaulted reference
depth item as
Compute the reference depth from the location of the well's
reservoir connections
We now alter this interpretation slightly to mean
Don't recompute the reference depth if the input has already
assigned a numerical value for this property
If the input has never assigned an explicit numerical value for the
reference depth, then we continue using the original interpretation
of a defaulted reference depth item--e.g., to update the reference
depth as a result of new reservoir connections.
The simulation can request the original interpretation even after
having assigned a numeric reference depth, by entering a new
WELSPECS keyword specifying a negative value for the the reference
depth item.
To this end, introduce a new data member in the Well class,
bool Well::derive_refdepth_from_conns_
which tracks whether or not the reference depth has been assigned an
explicit numeric value.
As an example, this new WELSPECS behaviour enables using something
like
ACTIONX
A 1 /
WOPR 'P*' < 123.4 /
/
WELSPECS
'?' 'LOWPRESS' /
/
ENDACTIO
as a way to move all wells matching the pattern 'P*', and with a low
oil production rate, to the group 'LOWPRESS'. This could, in turn,
apply a different set of group-level production controls to those
wells.
This commit extracts the internal helpers of class
InterRegFlowMap
out to a new public helper class template, CSRGraphFromCoordinates.
Client code can, at the expense of one additional data member and
some dynamic memory, elect to track the index pairs. This enables
O(1) assembly per element when used as part of a CSR matrix with a
value array, SA.
Class CSRGraphFromCoordinates does not track values. It is purely
for the sake of forming the IA and JA structure arrays. Upon
calling 'compress()', column indices are sorted per row and
duplicate column indices condensed to a single, unique,
representative.
Member function SummaryState::update_udq() did not take into account
the possibility that wells or groups might not yet have come online.
In particular, UDQSet::operator[](const string&) will throw an
exception if the argument string does not name an existing member of
the UDQ set.
This commit makes the call to operator[]() conditional on the named
entity existing and thereby enables updating well and group level
UDQs before these names have been entered in, e.g., WELSPECS or
GRUPTREE. Missing entities get the 'undefined_value'.
The existing implementation used the UDQ State object to track
pending ASSIGN operations, mainly in terms of the report step index,
but this implies that the logic implicitly assumes an ASSIGN
operation can run at most once per report step. That assumption
usually holds, but fails if the ASSIGN operation is triggered from
an ACTIONX block that happens to run multiple times within a report
step.
This commit instead introduces a new data member,
UDQConfig::pending_assignments_
that keeps track of all ASSIGN operations that have been added for
the current report step. We clear those pending assignments when
forming a new Schedule block (ScheduleState object), under the
assumption that all pending ASSIGN operations have been affected at
the previous time level (report step).
In effect, this new data member assumes the role of
UDQState::assignments
and we therefore remove that data member and update the signature of
UDQState::add_assign()
to account for the fact that the 'report_step' parameter is no
longer needed.
This commit adds parser and evaluation logic necessary to handle
ASSIGN statements for segment level UDQs. This requires a segment
matching facility in UDQConfig::add_assign() which, in turn, must be
passed from the calling context in Schedule::handleUDQ(). Update
APIs accordingly.
We also split handling segment level UDQ assignments to a new helper
function, UDQConfig::add_enumerated_assign(), which might be
generalised to handle block level UDQs in the future.
This commit adds support for calculating UDQs at the segment level,
i.e., UDQs named 'SU*'. This necessitates an API change for the UDQ
context constructor and, transitively, every function that forms UDQ
context objects. We pass a factory function that will create
segment matcher objects on demand, and provide a default
implementation of this factory function in the Schedule class.
The existing algorithm was a little too fragile and dependent on
branch numbers. This new version starts at segment 1/branch 1 and
follows Segment::inletSegments() in depth-first order, taking care
to enqueue new branches as they're encountered instead of in
numerical order. We search to the end of each branch before
switching to the next branch. This ensures determinism regardless
of branch numbering and input ordering.
While here, switch iLBR_ to a WindowedMatrix<int> to simplify branch
references in the output table.
The value in ISEG[0] does not necessarily correspond to the search
order of that segment. Rather, ISEG[0] is the depth-first ordering
of the segment search tree when traversing kick-off branches before
the main stem from which those branches kick off.