Closed Huite closed 6 months ago
Another note: the current implementation only takes values from the demand
array in case of static forcing. This means the test model should set a UserDemand / static table, not a UserDemand / time table.
I think exposing the priorities
array via BMI is the easiest and most generic solution.
But a single user demand node might have multiple priorities, right? Do we also return a n_user * n_priority sized array for priorities, with fill values for the non-used priorities. And then assert that only a single priority is set for MetaSWAP users in the coupler pre-processing?
But a single user demand node might have multiple priorities, right? Do we also return a n_user * n_priority sized array for priorities, with fill values for the non-used priorities. And then assert that only a single priority is set for MetaSWAP users in the coupler pre-processing?
I don't understand what you mean, so let me just explain some things. The priorities
vector is global, i.e. it gives all priorities that appear somewhere in the model input. So if MetaSWAP knows at which priority it wants to set a demand, it just has to do a searchsorted
in the priorities
vector to know the index in the demand
and allocated
matrices in the priority dimension. For the other dimension it also has to know all UserDemand
IDs.
Coming from the talk we just had.
The current setup only works with a static user demand for the coupled nodes. Proposal is to let Ribasim determine the priority. So a single demand with a single priority is defined per coupled user demand node. Then the coupler infers the priority to set from this initial value.
Something along these lines:
self.user_demand = self.ribasim.get_value_ptr("user.demand").reshape((n_user, n_priority))
self.user_demand_flag = self.user_demand > 0
not_coupled = ~np.isin(np.arange(n_user), coupled_user_demand_indices)
self.user_demand_flag[not_coupled, :] = False
multiple_priorities = np.flatnonzero(self.user_demand_flag.sum(axis=1) > 1)
if multiple_priorities:
raise ValueError(f"Multiple priorities detected for coupled UserDemand nodes at indices: {multiple_priorities}")
...
# when setting demand
self.user_demand[self.user_demand_flag] = svat_demand
In the pre-processing, we should also check for multiple priorities. In fact, only a single row should be given in general:
df = ribasim_model.user_demand.static.df
coupled_df = df.loc[df["node_id"].isin(coupled_user_demand_node_ids)]
duplicated_ids = coupled_df["node_id"].loc[coupled_df["node_id"].duplicated()]
if duplicated_ids:
raise ValueError(
f"Found UserDemand to couple with multiple demands defined: {duplicated_ids}\n"
"Coupled UserDemand nodes may only have a single demand and priority value."
)
The BMI will offer a
demand
array which is sized n_priority * n_user, with multiple demands for a single water user.For a coupled model, we would like MetaSWAP to set the irrigation demand. However, the coupler has no way of setting this in the right column (Python) / row (Julia) of the
demand
array, since it does not know which priority the irrigation has.For now, I suggest the coupler just sets the irrigation demand with first priority. But we should think about whether either the priority should also be communicated via BMI, or whether a single external demand is offered instead, which is then distributed along the priorities in Ribasim internally.