# Problem Specifications

## Water Flow (WF)

### Functions

```
# Create head loss functions, if necessary.
_function_head_loss(wm)
```

### Objective

`objective_wf(wm)`

### Variables

```
# Create head loss functions, if necessary.
variable_head(wm)
variable_flow(wm)
variable_pump_head_gain(wm)
variable_pump_power(wm)
# Indicator (status) variables.
variable_des_pipe_indicator(wm)
variable_pump_indicator(wm)
variable_regulator_indicator(wm)
variable_valve_indicator(wm)
# Create flow-related variables for node attachments.
variable_demand_flow(wm)
variable_reservoir_flow(wm)
variable_tank_flow(wm)
```

### Constraints

```
# Flow conservation at all nodes.
for (i, node) in ref(wm, :node)
constraint_flow_conservation(wm, i)
constraint_node_directionality(wm, i)
end
# Constraints on pipe flows, heads, and physics.
for (a, pipe) in ref(wm, :pipe)
constraint_pipe_head(wm, a)
constraint_pipe_head_loss(wm, a)
constraint_pipe_flow(wm, a)
end
# Selection of design pipes along unique arcs.
for (k, arc) in ref(wm, :des_pipe_arc)
constraint_des_pipe_flow(wm, k, arc[1], arc[2])
constraint_des_pipe_head(wm, k, arc[1], arc[2])
constraint_des_pipe_selection(wm, k, arc[1], arc[2])
end
# Constraints on design pipe flows, heads, and physics.
for (a, des_pipe) in ref(wm, :des_pipe)
constraint_on_off_des_pipe_head(wm, a)
constraint_on_off_des_pipe_head_loss(wm, a)
constraint_on_off_des_pipe_flow(wm, a)
end
# Constraints on pump flows, heads, and physics.
for (a, pump) in ref(wm, :pump)
constraint_on_off_pump_head(wm, a)
constraint_on_off_pump_head_gain(wm, a)
constraint_on_off_pump_flow(wm, a)
constraint_on_off_pump_power(wm, a)
end
for (k, pump_group) in ref(wm, :pump_group)
constraint_on_off_pump_group(wm, k)
end
# Constraints on short pipe flows and heads.
for (a, regulator) in ref(wm, :regulator)
constraint_on_off_regulator_head(wm, a)
constraint_on_off_regulator_flow(wm, a)
end
# Constraints on short pipe flows and heads.
for (a, short_pipe) in ref(wm, :short_pipe)
constraint_short_pipe_head(wm, a)
constraint_short_pipe_flow(wm, a)
end
# Constraints on tank volumes.
for (i, tank) in ref(wm, :tank)
# Set the initial tank volume.
constraint_tank_volume(wm, i)
end
# Constraints on valve flows and heads.
for (a, valve) in ref(wm, :valve)
constraint_on_off_valve_head(wm, a)
constraint_on_off_valve_flow(wm, a)
end
```

## Multinetwork Water Flow (MN WF)

### Functions

```
# Create head loss functions, if necessary.
_function_head_loss(wm)
```

### Objective

`objective_wf(wm)`

### Variables

```
# Get all network IDs in the multinetwork.
network_ids = sort(collect(nw_ids(wm)))
network_ids_inner = length(network_ids) > 1 ? network_ids[1:end-1] : network_ids
for n in network_ids_inner
# Physical variables.
variable_head(wm; nw=n)
variable_flow(wm; nw=n)
variable_pump_head_gain(wm; nw=n)
variable_pump_power(wm; nw=n)
# Indicator (status) variables.
variable_des_pipe_indicator(wm; nw=n)
variable_pump_indicator(wm; nw=n)
variable_regulator_indicator(wm; nw=n)
variable_valve_indicator(wm; nw=n)
# Create flow-related variables for node attachments.
variable_demand_flow(wm; nw=n)
variable_reservoir_flow(wm; nw=n)
variable_tank_flow(wm; nw=n)
end
if length(network_ids) > 1
variable_head(wm; nw = network_ids[end])
end
```

### Constraints

```
# Get all network IDs in the multinetwork.
network_ids = sort(collect(nw_ids(wm)))
network_ids_inner = length(network_ids) > 1 ? network_ids[1:end-1] : network_ids
for n in network_ids_inner
# Flow conservation at all nodes.
for i in ids(wm, :node; nw=n)
constraint_flow_conservation(wm, i; nw=n)
constraint_node_directionality(wm, i; nw=n)
end
# Constraints on pipe flows, heads, and physics.
for a in ids(wm, :pipe; nw=n)
constraint_pipe_flow(wm, a; nw=n)
constraint_pipe_head(wm, a; nw=n)
constraint_pipe_head_loss(wm, a; nw=n)
end
# Constraints on pump flows, heads, and physics.
for a in ids(wm, :pump; nw=n)
constraint_on_off_pump_head(wm, a; nw=n)
constraint_on_off_pump_head_gain(wm, a; nw=n)
constraint_on_off_pump_flow(wm, a; nw=n)
constraint_on_off_pump_power(wm, a; nw=n)
end
# Constraints on groups of parallel pumps.
for k in ids(wm, :pump_group; nw=n)
constraint_on_off_pump_group(wm, k; nw=n)
end
# Constraints on short pipe flows and heads.
for a in ids(wm, :regulator; nw=n)
constraint_on_off_regulator_head(wm, a; nw=n)
constraint_on_off_regulator_flow(wm, a; nw=n)
end
# Constraints on short pipe flows and heads.
for a in ids(wm, :short_pipe; nw=n)
constraint_short_pipe_head(wm, a; nw=n)
constraint_short_pipe_flow(wm, a; nw=n)
end
# Constraints on valve flows and heads.
for a in ids(wm, :valve; nw=n)
constraint_on_off_valve_head(wm, a; nw=n)
constraint_on_off_valve_flow(wm, a; nw=n)
end
end
# Start with the first network, representing the initial time step.
n_1 = network_ids[1]
# Constraints on tank volumes.
for i in ids(wm, :tank; nw = n_1)
# Set initial conditions of tanks.
constraint_tank_volume(wm, i; nw = n_1)
end
if length(network_ids) > 1
# Constraints on tank volumes.
for n_2 in network_ids[2:end]
# Constrain tank volumes after the initial time index.
for i in ids(wm, :tank; nw = n_2)
constraint_tank_volume(wm, i, n_1, n_2)
end
# Update the first network used for integration.
n_1 = n_2
end
end
```

## Multinetwork Water Flow with Switching Constraints (MN WF SWITCHING)

### Inherited Functions, Variables, Constraints, and Objective

```
# Build the base multinetwork problem.
build_mn_wf(wm)
```

### Variables

```
# Get all network IDs in the multinetwork.
network_ids = sort(collect(nw_ids(wm)))
# Get the first network ID in the multinetwork.
n_1 = network_ids[1]
for n_2 in network_ids[2:end-1]
# Add pump switching variables.
variable_pump_switch_on(wm; nw = n_2)
variable_pump_switch_off(wm; nw = n_2)
n_1 = n_2
end
```

### Constraints

```
# Get all network IDs in the multinetwork.
network_ids = sort(collect(nw_ids(wm)))
# Get the first network ID in the multinetwork.
n_1 = network_ids[1]
for n_2 in network_ids[2:end-1]
for a in ids(wm, :pump, nw = n_2)
# Add constraints that define switching variables.
constraint_pump_switch_on(wm, a, n_1, n_2)
constraint_pump_switch_off(wm, a, n_1, n_2)
end
n_1 = n_2
end
for a in ids(wm, :pump; nw = network_ids[1])
# Add constraints on the total number of pump switches.
constraint_on_off_pump_switch(wm, a, network_ids[2:end-1])
end
```

## Optimal Water Flow (OWF)

### Inherited Functions, Variables, Constraints, and Objective

```
# Build the water flow problem.
build_wf(wm)
```

### Objective

```
# Add the optimal water flow objective.
objective_owf(wm)
```

## Multinetwork Optimal Water Flow (MN OWF)

### Inherited Functions, Variables, Constraints, and Objective

```
# Build the water flow problem.
build_mn_wf(wm)
```

### Objective

```
# Add the optimal water flow objective.
objective_owf(wm)
```

### Constraints

```
# Get all network IDs in the multinetwork.
network_ids = sort(collect(nw_ids(wm)))
# Ensure tanks recover their initial volume.
n_1, n_f = network_ids[1], network_ids[end]
for i in ids(wm, n_f, :tank)
constraint_tank_volume_recovery(wm, i, n_1, n_f)
end
```

## Optimal Design (DES)

### Inherited Functions, Variables, Constraints, and Objective

```
# Build the water flow problem.
build_wf(wm)
```

### Objective

```
# Add the network design objective.
objective_des(wm)
```