1+
2+ " Variables needed for modeling flow in CWP models"
3+ function variable_flow (gm:: AbstractCWPModel , nw:: Int = nw_id_default; bounded:: Bool = true , report:: Bool = true )
4+ variable_mass_flow (gm, nw; bounded = bounded, report = report)
5+ variable_pipe_mass_flow_slack (gm, nw; bounded, report)
6+ end
7+
8+
9+ " Variables needed for modeling flow in CWP models"
10+ function variable_flow_ne (gm:: AbstractCWPModel , nw:: Int = nw_id_default; bounded:: Bool = true , report:: Bool = true )
11+ variable_mass_flow_ne (gm, nw; bounded = bounded, report = report)
12+ variable_pipe_mass_flow_slack_ne (gm, nw; bounded, report)
13+ end
14+
15+
16+ """
17+ variable_pipe_mass_flow(gm::CWPGasModel, data, cdata)
18+
19+ Overrides the default pipe flow variable creation to define complementarity-based
20+ flow variables f⁺[p] and f⁻[p], along with a net flow variable f[p] = f⁺[p] - f⁻[p].
21+ """
22+ function variable_pipe_mass_flow_slack (gm:: AbstractCWPModel , nw:: Int = nw_id_default; bounded:: Bool = true , report:: Bool = true )
23+ # 1) Define f⁺ variables (nonnegative)
24+ f_plus_pipe = var (gm, nw)[:f_plus_pipe ] = JuMP. @variable (
25+ gm. model,
26+ [i in ids (gm, nw, :pipe )],
27+ lower_bound = 0 ,
28+ base_name = " $(nw) _f_plus" ,
29+ start = comp_start_value (ref (gm, nw, :pipe ), i, " f_plus_start" , 0 )
30+ )
31+
32+ # 2) Define f⁻ variables (nonnegative)
33+ f_minus_pipe = var (gm, nw)[:f_minus_pipe ] = JuMP. @variable (
34+ gm. model,
35+ [i in ids (gm, nw, :pipe )],
36+ lower_bound = 0 ,
37+ base_name = " $(nw) _f_minus" ,
38+ start = comp_start_value (ref (gm, nw, :pipe ), i, " f_minus_start" , 0 )
39+ )
40+
41+ # 2) Optionally set bounds from pipe data
42+ if bounded
43+ for (i, pipe_dict) in ref (gm, nw, :pipe )
44+ # handle flow_min
45+ if haskey (pipe_dict, " flow_min" )
46+ flow_min = pipe_dict[" flow_min" ]
47+ if flow_min > 0
48+ # pipe demands a strictly positive lower bound on "forward" flow
49+ JuMP. set_lower_bound (f_plus_pipe[i], flow_min)
50+ elseif flow_min <= 0
51+ # pipe demands a strictly negative flow_min => set a bound on "reverse" flow
52+ JuMP. set_upper_bound (f_minus_pipe[i], - flow_min)
53+ end
54+ end
55+
56+ # handle flow_max
57+ if haskey (pipe_dict, " flow_max" )
58+ flow_max = pipe_dict[" flow_max" ]
59+ if flow_max < 0
60+ # maximum is negative => limit the reverse flow variable
61+ JuMP. set_lower_bound (f_minus_pipe[i], - flow_max)
62+ elseif flow_max >= 0
63+ # standard positive flow bound
64+ JuMP. set_upper_bound (f_plus_pipe[i], flow_max)
65+ end
66+ end
67+ end
68+ end
69+
70+ # 4) Optionally register these variables for solution reporting
71+ if report
72+ sol_component_value (gm, nw, :pipe , :f_plus_pipe , ids (gm, nw, :pipe ), f_plus_pipe)
73+ sol_component_value (gm, nw, :pipe , :f_minus_pipe , ids (gm, nw, :pipe ), f_minus_pipe)
74+ end
75+ end
76+
77+
78+ """
79+ variable_pipe_mass_flow(gm::CWPGasModel, data, cdata)
80+
81+ Overrides the default pipe flow variable creation to define complementarity-based
82+ flow variables f⁺[p] and f⁻[p], along with a net flow variable f[p] = f⁺[p] - f⁻[p].
83+ """
84+ function variable_pipe_mass_flow_slack_ne (gm:: AbstractCWPModel , nw:: Int = nw_id_default; bounded:: Bool = true , report:: Bool = true )
85+ # 1) Define f⁺ variables (nonnegative)
86+ f_plus_pipe = var (gm, nw)[:f_plus_ne_pipe ] = JuMP. @variable (
87+ gm. model,
88+ [i in ids (gm, nw, :ne_pipe )],
89+ lower_bound = 0 ,
90+ base_name = " $(nw) _f_plus" ,
91+ start = comp_start_value (ref (gm, nw, :ne_pipe ), i, " f_plus_start" , 0 )
92+ )
93+
94+ # 2) Define f⁻ variables (nonnegative)
95+ f_minus_pipe = var (gm, nw)[:f_minus_ne_pipe ] = JuMP. @variable (
96+ gm. model,
97+ [i in ids (gm, nw, :ne_pipe )],
98+ lower_bound = 0 ,
99+ base_name = " $(nw) _f_minus" ,
100+ start = comp_start_value (ref (gm, nw, :ne_pipe ), i, " f_minus_start" , 0 )
101+ )
102+
103+ # 2) Optionally set bounds from pipe data
104+ if bounded
105+ for (i, pipe_dict) in ref (gm, nw, :ne_pipe )
106+ # handle flow_min
107+ if haskey (pipe_dict, " flow_min" )
108+ flow_min = pipe_dict[" flow_min" ]
109+ if flow_min <= 0
110+ # pipe demands a strictly negative flow_min => set a bound on "reverse" flow
111+ JuMP. set_upper_bound (f_minus_pipe[i], - flow_min)
112+ end
113+ end
114+
115+ # handle flow_max
116+ if haskey (pipe_dict, " flow_max" )
117+ flow_max = pipe_dict[" flow_max" ]
118+ if flow_max >= 0
119+ # standard positive flow bound
120+ JuMP. set_upper_bound (f_plus_pipe[i], flow_max)
121+ end
122+ end
123+ end
124+ end
125+
126+ # 4) Optionally register these variables for solution reporting
127+ if report
128+ sol_component_value (gm, nw, :ne_pipe , :f_plus_ne_pipe , ids (gm, nw, :ne_pipe ), f_plus_pipe)
129+ sol_component_value (gm, nw, :ne_pipe , :f_minus_ne_pipe , ids (gm, nw, :ne_pipe ), f_minus_pipe)
130+ end
131+ end
132+
133+ " Weymouth equation with absolute value"
134+ function constraint_pipe_weymouth (gm:: AbstractCWPModel , n:: Int , k, i, j, f_min, f_max, w, pd_min, pd_max)
135+ # Retrieve squared pressures at the 'from' and 'to' nodes
136+ pi = var (gm, n, :psqr , i)
137+ pj = var (gm, n, :psqr , j)
138+
139+ # Retrieve f for this pipe
140+ f_plus = var (gm, n, :f_plus_pipe , k)
141+ f_minus = var (gm, n, :f_minus_pipe , k)
142+ f = var (gm, n, :f_pipe , k)
143+
144+ if w == 0.0
145+ # Degenerate case
146+ _add_constraint! (gm, n, :weymouth1 , k, JuMP. @constraint (gm. model, pi - pj == 0.0 ))
147+ else
148+ _add_constraint! (gm, n, :weymouth1 , k, JuMP. @constraint (gm. model, pi - pj == (f_plus^ 2 - f_minus^ 2 ) / w))
149+ end
150+
151+ # Complementarity (no simultaneous forward and reverse flow):
152+ _add_constraint! (gm, n, :complementarity_weymouth , k, JuMP. @constraint (gm. model, f_plus * f_minus == 0 ))
153+
154+ # Relate the net flow variable f to f_plus and f_minus:
155+ _add_constraint! (gm, n, :weymouth_flow_relation , k, JuMP. @constraint (gm. model, f == f_plus - f_minus))
156+ end
157+
158+ " Weymouth equation for an expansion pipe"
159+ function constraint_pipe_weymouth_ne (gm:: AbstractCWPModel , n:: Int , k, i, j, w, f_min, f_max, pd_min, pd_max)
160+ # Retrieve squared pressures at the 'from' and 'to' nodes
161+ pi = var (gm, n, :psqr , i)
162+ pj = var (gm, n, :psqr , j)
163+
164+ # Retrieve f for this pipe
165+ f_plus = var (gm, n, :f_plus_ne_pipe , k)
166+ f_minus = var (gm, n, :f_minus_ne_pipe , k)
167+ f = var (gm, n, :f_ne_pipe , k)
168+ zp = var (gm, n, :zp , k)
169+
170+ # when z = 1, constraint is active
171+ # when z = 0 f is also 0. Therefore, the big M we need is just the smallest and largest pressure difference that is possible
172+ aux = JuMP. @variable (gm. model)
173+ JuMP. @constraint (gm. model, aux == f_plus^ 2 - f_minus^ 2 )
174+
175+ if w == 0.0
176+ # Degenerate case
177+ _add_constraint! (gm, n, :weymouth_ne1 , k, JuMP. @constraint (gm. model, pi - pj <= (1 - zp) * pd_max))
178+ _add_constraint! (gm, n, :weymouth_ne2 , k, JuMP. @constraint (gm. model, pi - pj >= (1 - zp) * pd_min))
179+ else
180+ _add_constraint! (gm, n, :weymouth_ne1 , k, JuMP. @constraint (gm. model, (pi - pj) <= aux / w + (1 - zp) * pd_max))
181+ _add_constraint! (gm, n, :weymouth_ne2 , k, JuMP. @constraint (gm. model, (pi - pj) >= aux / w + (1 - zp) * pd_min))
182+ end
183+
184+ # Complementarity (no simultaneous forward and reverse flow):
185+ _add_constraint! (gm, n, :complementarity_weymouth , k, JuMP. @constraint (gm. model, f_plus * f_minus == 0 ))
186+
187+ # Relate the net flow variable f to f_plus and f_minus:
188+ _add_constraint! (gm, n, :weymouth_flow_relation , k, JuMP. @constraint (gm. model, f == f_plus - f_minus))
189+ end
190+
0 commit comments