skip to main content
Accounting : Water Rights Allocation : Solution Algorithm for SolveWaterRights
Solution Algorithm for SolveWaterRights
This section provides a detailed description of the solution algorithm for the function SolveWaterRights and SolveWaterRightsWithLags. SolveWaterRights can only be called on a subbasin with no lags on the passthrough accounts in the subbasin, and so when it is used, all Local Timestep Offsets are zero, and the solution involves data at the current rules-controller timestep only. When SolveWaterRightsWithLags is called, Local Timestep Offsets may be greater than zero, and the solution involves data at timesteps which may differ from the current rules-controller timestep.
The rule function’s subbasin argument identifies a computational subbasin with a method selected in the Water Rights Allocation category. The Prior Appropriation method is described here. The method does the following:
1. Determine local timestep of the accounts representing the rights. See Determine the Local Timesteps of the Rights) for details.
2. Clone the accounting network. The solver works on this cloned system to solve the problem. See Cloning for details.
3. Clear values on supplies that represent allocations from the allocatable flow supply chain. See Clear Values for details.
For each water right in priority order:
4. Compute the appropriation request See Computing Appropriation Requests for details.
5. Compute allocation that meets the request, constrained by not violating senior rights. See Computing Appropriation for details.
6. Create a list of {slot name, value} pairs or a list of {slot name, date-time, value} triplets of allocations that are returned by rule function. See Return {Slot Name,Value} or {Slot Name, DateTime, Value} List to Rule for details.
The following sections describe these steps in detail.
Determine the Local Timesteps of the Rights
The local timestep of an account representing a right is defined to be the timestep of the passthrough account representing the appropriation point of the right. For this purpose, the appropriation point of an instream flow right is the sibling passthrough account on the supply chain for which the solver is called. Because the supply chain of interest is not known until run-time (when the predefined rules function SolveWaterRightsWithLags() is called), the local timesteps of the accounts representing the rights must be computed by the solver.
When SolveWaterRights() or SolveWaterRightsWithLags() is called on a subbasin that contains no lags, all the Local Timestep Offsets are zero, and the local timesteps of the rights are the current rules control timestep.
Note:  The entire subbasin must contain no lagged passthrough accounts for this to be true.
The local timestep of the appropriation point is a timestep in the future, defined as current rules-controller timestep + Local Timestep Offset timesteps. All solver operations on the account, its sibling accounts, its appropriation point account and the appropriation point’s siblings, and the underlying simulation object will take place at this local timestep. The Local Timestep Offset slot values of the passthrough accounts have been computed at the beginning of the run. The process of determining these offsets is described below.
At the Beginning of a Run
At the beginning of a run, before the first timestep, an enabled computational subbasin with the Prior Appropriation method selected will compute the Local Timestep Offset slot values for necessary passthrough accounts on objects in the subbasin.
The computation is not system-wide; it's a computation done on the water-rights subbasin, and it's restricted to the part of the subbasin containing rights that appropriate within the subbasin. Thus, only the accounts that figure in the solution for the subbasin are given the offsets. If there's no appropriation at or upstream of a passthrough account on its chain, then the passthrough doesn't need a local timestep and is not reset. If you desire to use the Local Timestep Offset in rules or OLAMs and it is not set by the solver, you should set it yourself.
The computation of the Local Timestep Offset takes place in steps:
1. Compute maximum lag to each passthrough account. This is the largest cumulative lag time (in number-of-timesteps) from any headwater account to the passthrough account, considering only passthrough account lag times (not return flow lags).
2. Compute Lag Distance of the subbasin. The lag distance of the subbasin is the largest maximum lag of all the passthrough accounts in the subbasin; it represents the longest travel time through any supply chain in the subbasin.
3. Compute Local Timestep Offset of the passthrough accounts. The local timestep of an account is the lag distance of the subbasin minus the lag, in timesteps, from the account’s inflow to the end of the subbasin. If lags on supply chains do not match, this can give counter-intuitive Local Timestep Offsets, which can be corrected by adding dummy lagged passthrough accounts at the ends of the supply chains with lower net-lags.
To the right is an example subbasin that shows the Local Timestep Offset computation. In this example, there is a 1 timestep lag at the two yellow reaches (Lag 1TS). Thus, the subbasin’s Lag Distance is 2. The resulting Local Timestep Offset (LTO) are shown.
Note:  LTO at Reach1 and ControlPoint are NaN as they are not needed by the solver.
Figure 6.7   
In the Solver Rule Function
During a call to the solver, the water rights use a local timestep that is determined as follows:
• A Diversion Account uses the local timestep of the passthrough account that represents the (single) appropriation point from the supply chain for which the solver is called. This is an account from which a diversion is made into the diversion account, and has the water type given as an argument to the solver.
• A Storage Account uses the local timestep of the passthrough account representing the (single) appropriation point from the supply chain for which the solver is called. For an in-stream storage right, this is an account from which transfers are made into the storage account, and it has the water type given as an argument to the solver. For an off-stream storage right, this is a passthrough account from which diversions are made into a passthrough account on a Diversion Object, and through which the paper water flows into the off-stream storage account’s Inflow slot.
• An Instream Flow Account uses the local timestep of the sibling passthrough account that has the water type indicating the supply chain for which the solver is called.
Note:  Some Solutions Involve Other Timesteps
A Passthrough Account may have data requirements for timesteps other than its local timestep. Two examples of such cases are when objects have more than one supply chain and the lags on the supply chains differ. In such a model, solving for the Flow slot on an Instream Flow Account requires summation of the inflows across all sibling accounts at the local timestep of the Instream Flow Account for a given Water Type, which may differ from the local timestep of one or more of its sibling accounts. Similarly, solving for the Appropriation Request on a storage account requires summation of the inflows (including transfers in) into all the sibling storage accounts at the local timestep of the storage account whose Appropriation Request is being solved.
Note:  Inasmuch as account methods use data from the underlying simulation object at local (future) timesteps for the accounts, the simulation objects must have dispatched at these future timesteps before the solver is called. An example is the storage account’s Fill Conservation Pool method for computing the Appropriation Request. This method uses the underlying reservoir’s Conservation Pool Initial Empty Space slot value at the storage account’s local timestep. If the local timestep offset of a storage account’s appropriation point is non-zero, the value of the Conservation Pool Initial Empty Space will be needed before it is computed by the beginning-of-timestep phase of the run controller, so the solver will force the computation of the value if needed. The beginning-of-timestep method for the reservoir will not recompute the value once it is defined. The reservoir must have dispatched at the prior timestep to provide a value for Storage, which is needed to compute the Conservation Pool Initial Empty Space.
Cloning
When the rule function is called the first time in a run, it clones all the accounts in the subbasin and their supplies (links). Using the cloned network, the solver can utilize the standard account solution methods without the risk of having side effects on the real accounts, and it can store intermediate results. Each time the solver is invoked by the rule function, current values from the real account slots are copied to the slots on the clones for the set of timesteps necessary to compute the solution. Thus, the rule function abides by the dictate that rules have an all-or-nothing effect and rule functions do not change the state of objects.
As the clones are constructed, tables are created to map donor accounts to their clones. The computational subbasin maintains this table. The cloned accounts reside on the computational subbasin because their underlying objects are not cloned, in the interest of performance. When the solver has to determine which cloned accounts are siblings (their donors reside on the same simulation object), it refers to the mapping.
Clear Values
Each time the rule function is called, in the cloned network it clears all supplies that represent allocations to water rights accounts. Only these supplies are cleared, and not other supplies. As illustrated in Figure 6.7, a call to the solver using the water type “Allocatable Flow” will clear (in the corresponding cloned accounting network) the following supplies:
• Bartlett Reservoir ^ Allocatable Flow to Bartlett Reservoir ^ 1922 Storage
• Bartlett Reservoir ^ Allocatable Flow to Bartlett Reservoir ^ Farmers Project
• Bartlett to Border ^ Allocatable Flow to Green Valley Diversions ^ 1902 Diverters.
• Muddy Reservoir^ Allocatable Flow to Muddy Reservoir ^ Project.
Computing Appropriation Requests
The solver visits each account in priority order: most senior first, and computes appropriation request, then the appropriation. This section describes the computation of the Appropriation Request.
The appropriation request is the amount that the account is legally entitled to ask for. It is the amount that the solver tries to allocate, subject to availability of water not already taken by senior rights. The appropriation request is derived from an initial request, which might be known a priori and taken from the Initial Request slot, or which might have to be computed, based on the state of the network. The account’s method selection in the Initial Request category determines how the initial request is obtained. If the Initial Request slot becomes visible as a result of the method selection and the initial request is computed, its value is stored in the slot. (Whenever the Initial Request slot is visible, so is the Shortage slot.)
Legal and physical constraints may apply to the initial request value, producing a reduced value for the appropriation request, which is stored in the Appropriation Request slot. The legal and physical constraints must reflect the state of the network at in-priority time, namely, after all seniors have received their appropriations.
Computing Appropriation Request from Initial Request
The solver does this in steps:
1. Compute physical constraints applicable to the allocation, based on the state of the cloned network at this time. The solver does this before having the account do anything, because the solver knows about the physical network, which the account does not. The solver determines an upper bound on the allocation due to the physical constraints. Specifically, the means the following:
– Reach Diversion Capacity. If the water right account is a diverter from a reach, the capacity of the diversion structure on the reach limits the diversion. All other diverters from the same reach share this structure, so the upper bound on the Appropriation Request is the Reach object’s Diversion Capacity minus the sum of all existing diversions from the reach passthrough accounts. (Remember that before we got here in the solver, this appropriation was cleared, so its diversion is zero.). The reach Diversion Capacity slot is used to determine the diversion capacity, and if its value is not defined, no diversion capacity limit is applied.
– Reservoir Conservation Pool. If the account is a storage right, the remaining space in the reservoir’s conservation pool limits the Appropriation Request. The inflow required to fill the conservation pool is taken from the underlying simulation object. The reservoir’s slot Conservation Pool Initial Empty Space is computed at the beginning of each timestep as the Inflow volume that would be required to bring the reservoir to the top of conservation pool. It is computed by executing a method on the reservoir “solve inflow given storage and outflow.” The method assumes that outflow is zero and includes evaporation in the mass balance. This flow is used by the solver to determine how much flow it can add, through appropriation, to the total flows into Storage Accounts on the reservoir. All of the reservoirs’ Storage Accounts’ Inflow, Slot Inflow and Transfers In slots are summed; all Transfers Out are subtracted, and the resulting flow is the amount of flow already going into the Storage Accounts. This value is subtracted from the conservation pool initial empty space, to determine an upper bound on the appropriation.
Both of these physical constraints might apply, so the lower of the two upper bounds is chosen.
2. Execute Appropriation Request Methods on Water Right Account. The solver asks the account to compute its appropriation request, applying the upper bounds on the request due to physical constraints: Call the C++ utility method computeDemandForWRA on the account. This method has three steps:
a. First invoke the account’s user-selectable method for determining its initial request as described above, and store this value in a temporary place, Then the upper bound is applied, possibly reducing the request, and the result is again stored in a temporary place.
b. Second, invoke the account’s user-selectable method for Appropriation Request Adjustment, if any (available method is the Return Flow Credit method on Storage Accounts). Pass in the temporary result from above, and store the reduced request again in a temporary place.
c. Invoke the account’s user-selectable methods for legal constraints, including Max Legal Request and Min Bypass.
• Max Legal Request allows the user to enter a value for the Initial Request (on Diversion Accounts only) that is larger than the legal right. This is useful if you are computing the Initial Request from aggregated or historical data. If there is a valid Maximum Request (not NaN), then:
Note:  The reduced request is constrained to be non-negative. See Max Legal Request. for details.
• Min Bypass constraints require storage and diversion rights to leave a prescribed flow in the stream at one and only one reference (measurement point), or a percentage of the flow at that reference point, or a combination of absolute flow + percentage. The default reference location is the point of appropriation for the right (a passthrough account on a Reach or Reservoir). An alternate location can be specified, but it must be a Control Point. It can be given in the Bypass Reference Location, which is a list slot that can refer to an object.
The input data needed to compute the MinBypass are:
AbsMinBypass = Absolute minimum required (or zero) to be left in the river at the ref point
FractionAboveMin = Fraction of flow required to be river (or zero), or fraction above the AbsMinBypass if that value is greater than zero.
The Minimum ByPass, the amount required to be left in the stream at the ref point is calculated as:
MinBypass = Min((AbsMinBypass+(TotalFlow-AbsMinBypass)*FractionAboveMin),
TotalFlow)
Where the total flow is the flow at the reference point before the allocation is made.
At the default reference location (Reach or Reservoir), the Total flow is
Total Flow = sum of Available for Appropriation on all passthrough accounts
If the reference point is an alternate location; that is,, a Control Point, the Total Flow is
Total Flow = sum of Outflow of all accounts
The Upper Bound on the Appropriation Request due to Minimum ByPass is
UpperBound(at point of reference) = Total Flow - Minimum Bypass
This is the Upper Bound that the solver applies if the reference location is the default; that is,, the point of appropriation. However, if the reference point is a downstream Control Point, the effects of gain/loss and lag between the reference location and the appropriation point must be taken into account when determining the resulting upper bound on the appropriator’s appropriation request. To do this, the account method makes a callback to the solver, which then pushes onto a stack all the passthrough accounts on the allocatable flow supply chain from the appropriation point to the measurement location. Then it solves upstream by popping accounts from the stack and for each, it routes the upper bound through the account as follows:
UpperBound = UpperBound(from d.s.Account) / (1-GainLossCoeff)
The new upper bound is passed in as input to the solution for the next account popped from the stack. When the stack is empty, the resulting upper bound is returned to the selected method on the appropriating account, which then stores the upper bound in the Temp Min Bypass Constraint (temporary1) slot. Hence, another upper bound has been computed by computeDemandForWRA.
Note:  The minimum bypass constraint applies only to the account with the method selected; it does not in any way affect rights that are junior to this appropriator. If the minimum flow is required to be left in the stream by juniors, all juniors must also have the same method selection and slot values to model the constraint.
3. After these 3 possible constraints on the Appropriation Request have been computed, the solver computes the final Appropriation Request by applying the constraints to the Initial Request and writing the resulting request value to the Appropriation Request slot.
4. If the water right account is an Instream Flow Account on a Control Point object, and it is junior to the controlling date on the solver call, then computeDemandForWRA copies the current Outflow slot value on the allocatable flow supply chain passthrough account on this Control Point into the Available Allocatable Flow slot on the Instream Flow Account.

1 This temporary slot is not stored in the model file, and is present for debugging purposes only, and may be removed from RiverWare at any time; do not write rules that use it.

Revised: 01/05/2024