pydae 0.53.5__py3-none-any.whl → 0.54.0__py3-none-any.whl

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (34) hide show
  1. pydae/__init__.py +1 -1
  2. pydae/optimization/__init__.py +1 -0
  3. pydae/optimization/ofo.py +127 -0
  4. pydae/svg_tools/__init__.py +8 -0
  5. pydae/svg_tools/set_tooltips_v2.py +369 -0
  6. pydae/{svg_tools.py → svg_tools/svg_tools.py} +26 -368
  7. pydae/urisi/sources/ac3ph4w_ideal.py +9 -9
  8. pydae/urisi/sources/sources.py +1 -0
  9. pydae/urisi/sources/vdc_src.py +5 -5
  10. pydae/urisi/transformers/Dyn11.json +36 -0
  11. pydae/urisi/transformers/Dyn11.py +203 -0
  12. pydae/urisi/transformers/Dyn11t.json +38 -0
  13. pydae/urisi/transformers/cigre_eu_lv_ind.py +1823 -0
  14. pydae/urisi/transformers/cigre_eu_lv_ind_ini_cffi.c +1672 -0
  15. pydae/urisi/transformers/cigre_eu_lv_ind_run_cffi.c +1672 -0
  16. pydae/urisi/transformers/cigre_eu_lv_ind_trap_cffi.c +1324 -0
  17. pydae/urisi/transformers/transformers.py +121 -7
  18. pydae/urisi/transformers/xy_0.json +28 -0
  19. pydae/urisi/urisi_builder.py +37 -19
  20. pydae/urisi/utils/model2svg.py +214 -0
  21. pydae/urisi/vscs/acdc_3ph_4w_pq.hjson +39 -0
  22. pydae/urisi/vscs/acdc_3ph_4w_pq.ipynb +333 -0
  23. pydae/urisi/vscs/acdc_3ph_4w_pq.py +50 -17
  24. pydae/urisi/vscs/temp.py +29 -28
  25. pydae/urisi/vscs/temp_ini_cffi.c +161 -453
  26. pydae/urisi/vscs/temp_run_cffi.c +161 -453
  27. pydae/urisi/vscs/temp_trap_cffi.c +110 -382
  28. pydae/urisi/vscs/xy_0.json +12 -16
  29. {pydae-0.53.5.dist-info → pydae-0.54.0.dist-info}/METADATA +1 -1
  30. {pydae-0.53.5.dist-info → pydae-0.54.0.dist-info}/RECORD +33 -19
  31. pydae/urisi/vscs/acdc_7bus.hjson +0 -53
  32. {pydae-0.53.5.dist-info → pydae-0.54.0.dist-info}/COPYING +0 -0
  33. {pydae-0.53.5.dist-info → pydae-0.54.0.dist-info}/LICENSE +0 -0
  34. {pydae-0.53.5.dist-info → pydae-0.54.0.dist-info}/WHEEL +0 -0
pydae/__init__.py CHANGED
@@ -7,5 +7,5 @@ Differential Algebraic Equations in Python
7
7
 
8
8
  """
9
9
 
10
- __version__ = "0.53.5"
10
+ __version__ = "0.54.0"
11
11
 
@@ -0,0 +1 @@
1
+ from pydae.optimization.ofo import ofo
@@ -0,0 +1,127 @@
1
+ '''
2
+ File name: ofo.py
3
+ Author: Álvaro Rodriguez del Nozal
4
+ Date created: 05/07/2024
5
+
6
+ '''
7
+
8
+ import numpy as np
9
+
10
+ class ofo:
11
+ '''
12
+ Online Feedback Optmization
13
+
14
+ minimize q'.u + u'.Q.u + r'.z + z'.R.z
15
+
16
+ subject to:
17
+ -u < -u_min
18
+ u < u_max
19
+ C.z < bounds
20
+
21
+ Dimesions:
22
+
23
+ - q = [Nu,1]
24
+ - Q = [Nu,Nu]
25
+ - r = [Nz,1]
26
+ - R = [Nz,Nz]
27
+
28
+ '''
29
+
30
+ def __init__(self, in_bnds, C, d, alpha, rho, q, Q, r, R, model):
31
+ self.in_bnds = in_bnds # list of tuples (min, max) with the bounds of the "u" elements
32
+ self.C = C # Output "z" constraints: Cz \leq d
33
+ self.d = d
34
+ self.lmb = np.zeros((self.C.shape[0],1)) # Lagrangian dual variables
35
+ self.s = np.zeros((self.C.shape[0],1)) # Slack variables: Cz \leq d -> Cz - d + s = 0 with s \geq 0
36
+ self.nin = len(in_bnds) # Array "u" dimension
37
+ self.nout = C.shape[1] # Array "z" dimension
38
+ self.alpha = alpha # Step size
39
+ self.rho = rho # Augmented Lagrangian penalty term
40
+
41
+ # The cost function has the shape: q'*u + u'*Q*u + r'*z + z'*R*z
42
+ # Introduce a vector/matrix of zeros to the non used terms
43
+ self.q = q
44
+ self.Q = Q
45
+ self.r = r
46
+ self.R = R
47
+ self.model = model
48
+ self.u = np.zeros((q.shape[0],1))
49
+ self.delta_u = 0.05
50
+
51
+ def h(self, u):
52
+ y = self.model.h_eval(u)
53
+ return y
54
+
55
+ # def h(self, u):
56
+ # u_bounds = self.model.u_bounds(u)
57
+ # y = self.model.h_eval(u_bounds)
58
+ # return y
59
+
60
+
61
+ def compute_sens(self, delta_u):
62
+ '''
63
+ Method to compute the sensitivty matrix.
64
+ From a perturbation vector "delta_u", the inputs to the system are
65
+ perturbed one by one and the influence on the output vector is cuantified
66
+
67
+ '''
68
+
69
+ u = self.u
70
+ self.H = np.array([-np.array(self.h(u)) for _ in u])
71
+ for index_in in range(self.nin):
72
+ u[index_in] += delta_u
73
+ self.H[index_in, :] = (self.H[index_in, :] + self.model.h_eval(u))/delta_u # If the values in H are tiny, forget about divide by "delta_u"
74
+ u[index_in] -= delta_u
75
+ self.H = self.H.T[0]
76
+ return self.H
77
+
78
+ def run(self, niter, pr = False):
79
+ # Define at the beginning self.u and self.z
80
+ update_H = 1 # Every "update_H" time steps the sensitivity matrix is updated
81
+ self.compute_sens(self.delta_u)
82
+ self.z = self.h(self.u)
83
+
84
+ self.Z = np.zeros((niter,self.nout))
85
+ self.U = np.zeros((niter,self.nin))
86
+
87
+
88
+ for it in range(niter):
89
+ if pr:
90
+ print(f'Iteration {it+1}...')
91
+ if it == update_H:
92
+ self.compute_sens(self.delta_u) # Sensitivity matrix update
93
+ update_H += 10
94
+
95
+ ########################################### Step 1: Update slack variables
96
+ self.s = -(1/self.rho)*self.lmb - self.C.dot(self.z) + self.d
97
+ for index, item in enumerate(self.s):
98
+ self.s[index] = np.clip(item, 0, np.inf)
99
+
100
+ ########################################### Step 2: Update primal variables
101
+ dL = self.q + 2*self.Q.T.dot(self.u) + self.H.T.dot(self.r) + 2*self.H.T.dot(self.R).dot(self.z) # dJ/du
102
+ dL = dL + self.H.T.dot(self.C.T).dot(self.lmb + self.rho*(self.C.dot(self.z) - self.d + self.s)) # dL/du
103
+ u_unconstrained = self.u - self.alpha*(dL)
104
+ for index, item in enumerate(self.u):
105
+ self.u[index] = np.clip(u_unconstrained[index], self.in_bnds[index][0], self.in_bnds[index][1])
106
+ # self.u = u_unconstrained.clip([item[0] for item in self.in_bnds], [item[1] for item in self.in_bnds])
107
+
108
+ ########################################### Step 3: Dispacth new inputs "u" and gather outputs "z"
109
+ self.z = self.h(self.u)
110
+
111
+ ########################################### Step 4: Update dual variables
112
+ self.lmb = self.lmb + self.rho*(self.C.dot(self.z) - self.d + self.s)
113
+
114
+ self.U[it,:] = self.u[:,0]
115
+ self.Z[it,:] = self.z[:,0]
116
+
117
+ return niter
118
+
119
+ # def opf(self):
120
+ # opf_const = lambda u : - self.C.dot(self.h(u)) + self.d
121
+ # of = lambda u : self.qin.dot(u)
122
+ # cons = NonlinearConstraint(opf_const, 0, np.inf)
123
+ # sol = minimize(of,
124
+ # self.u[-1],
125
+ # bounds = self.in_bnds,
126
+ # constraints = (cons,))
127
+ # return sol
@@ -0,0 +1,8 @@
1
+ """
2
+ ===========================
3
+ SVG Tools
4
+ ===========================
5
+
6
+ """
7
+
8
+ from pydae.svg_tools.svg_tools import svg
@@ -0,0 +1,369 @@
1
+
2
+ from xml.etree.ElementTree import Element
3
+ import numpy as np
4
+
5
+
6
+
7
+ def set_tooltips_v2(self, output_file):
8
+
9
+ s = self
10
+ grid = self.grid
11
+
12
+ for bus in s.grid_data['buses']:
13
+ bus_id = bus['name']
14
+ bus_elm_list = s.root.findall(f".//*[@id='{bus_id}']")
15
+ if len(bus_elm_list) > 0:
16
+ bus_elm = bus_elm_list[0]
17
+ else:
18
+ print(f'SVG element {bus_id} not found')
19
+ continue
20
+
21
+ if f"V_{bus['name']}_3_r" in grid.y_ini_list:
22
+ v_n_r,v_n_i = grid.get_mvalue([f"V_{bus['name']}_3_r",f"V_{bus['name']}_3_i"])
23
+ v_n = v_n_r + 1j*v_n_i
24
+ else:
25
+ v_n = 0.0
26
+ for ph,da in zip(['0','1','2'],['data1','data2','data3']):
27
+ V_r_id,V_i_id = f"V_{bus['name']}_{ph}_r",f"V_{bus['name']}_{ph}_i"
28
+ if V_r_id in grid.y_ini_list:
29
+ v_r,v_i = grid.get_mvalue([V_r_id,V_i_id])
30
+ v = v_r + 1j*v_i
31
+ v_m = np.abs(v-v_n)
32
+ if 'acdc' in bus:
33
+ v_base = bus['U_kV']*1000/2
34
+ else:
35
+ v_base = bus['U_kV']*1000/np.sqrt(3)
36
+ bus_elm.attrib[da] =f"{v_m:20.1f} V / {v_m/v_base:9.2f} pu "
37
+ bus_elm.attrib['data4'] =f"{np.abs(v_n):20.1f} V"
38
+ bus_elm.attrib['data0'] = 'bus'
39
+
40
+ p_load_a,q_load_a = -0.001,-0.001
41
+ p_load_b,q_load_b = -0.001,-0.001
42
+ p_load_c,q_load_c = -0.001,-0.001
43
+ p_load = 0.0
44
+ q_load = 0.0
45
+ if f"p_load_{bus_id}_a" in grid.u_ini_list: # ac load
46
+ p_load_a = grid.get_value(f"p_load_{bus_id}_a")
47
+ q_load_a = grid.get_value(f"q_load_{bus_id}_a")
48
+ p_load_b = grid.get_value(f"p_load_{bus_id}_b")
49
+ q_load_b = grid.get_value(f"q_load_{bus_id}_b")
50
+ p_load_c = grid.get_value(f"p_load_{bus_id}_c")
51
+ q_load_c = grid.get_value(f"q_load_{bus_id}_c")
52
+ p_load = p_load_a + p_load_b + p_load_c
53
+ q_load = q_load_a + q_load_b + q_load_c
54
+ if f"p_load_{bus_id}" in grid.u_ini_list: # dc load
55
+ p_load = grid.get_value(f"p_load_{bus_id}")
56
+ q_load = 0.0
57
+
58
+ bus_elm.attrib['data5'] =f"{p_load/1e3:20.1f} kW"
59
+ bus_elm.attrib['data6'] =f"{q_load/1e3:20.1f} kvar"
60
+ bus_elm.attrib['data7'] ="xx"
61
+
62
+ bus_elm.attrib['class'] = 'tooltip-trigger'
63
+
64
+ for line in s.grid_data['lines']:
65
+
66
+ bus_j = line['bus_j']
67
+ bus_k = line['bus_k']
68
+
69
+ for ph in ['0','1','2','3']:
70
+
71
+ line_id = f'l_{bus_j}_{ph}_{bus_k}_{ph}'
72
+ line_svg = s.root.findall(f".//*[@id='{line_id}']")
73
+ if len(line_svg)>0:
74
+ line_elm = line_svg[0]
75
+ else:
76
+ continue
77
+ line_elm.attrib['data0'] = 'line'
78
+
79
+ for phi,da in zip(['0','1','2','3'],['data1','data2','data3','data4']):
80
+ meas_line_id = f'l_{bus_j}_{phi}_{bus_k}_{phi}'
81
+
82
+ i_m = 0.0
83
+
84
+ if f'i_{meas_line_id}_r' in grid.outputs_list:
85
+ i_r,i_i = grid.get_mvalue([f"i_{meas_line_id}_r",f"i_{meas_line_id}_i"])
86
+ i = i_r + 1j*i_i
87
+ i_m = np.abs(i)
88
+ v_base = 1.0
89
+ line_elm.attrib[da] =f"{i_m:20.1f} A / {i_m/v_base:9.2f} pu "
90
+
91
+ line_elm.attrib['class'] = 'tooltip-trigger'
92
+
93
+ if 'transformers' in s.grid_data:
94
+ for trafo in s.grid_data['transformers']:
95
+
96
+ bus_j = trafo['bus_j']
97
+ bus_k = trafo['bus_k']
98
+
99
+ for wind in [1,2]:
100
+ trafo_id = f'trafo_{bus_j}_{bus_k}_{wind}'
101
+
102
+ trafo_svg = s.root.findall(f".//*[@id='{trafo_id}']")
103
+ if len(trafo_svg)>0:
104
+ trafo_elm = trafo_svg[0]
105
+ else:
106
+ print(f'No trafo {trafo_id} found')
107
+ continue
108
+
109
+ trafo_elm.attrib['data0'] = 'trafo'
110
+
111
+
112
+ z2a = {'0':'a','1':'b','2':'c','3':'n'}
113
+ string_1 = ''
114
+ for ph in ['0','1','2']:
115
+ i_r_id = f'i_t_{bus_j}_{bus_k}_1_{ph}_r'
116
+ i_i_id = f'i_t_{bus_j}_{bus_k}_1_{ph}_i'
117
+ if i_r_id in grid.outputs_list:
118
+ i_r,i_i = grid.get_mvalue([i_r_id,i_i_id])
119
+ i = i_r + 1j*i_i
120
+ i_m = np.abs(i)
121
+ string_1 += f'{z2a[ph]}: {i_m:0.2f}\t '
122
+
123
+ string_2 = ''
124
+ for ph in ['0','1','2','3']:
125
+ i_r_id = f'i_t_{bus_j}_{bus_k}_2_{ph}_r'
126
+ i_i_id = f'i_t_{bus_j}_{bus_k}_2_{ph}_i'
127
+ if i_r_id in grid.outputs_list:
128
+ i_r,i_i = grid.get_mvalue([i_r_id,i_i_id])
129
+ i = i_r + 1j*i_i
130
+ i_m = np.abs(i)
131
+ string_2 += f'{z2a[ph]}: {i_m:0.2f} '
132
+
133
+ trafo_elm.attrib['data1'] = string_1 + ' A'
134
+ trafo_elm.attrib['data2'] = string_2 + ' A'
135
+ trafo_elm.attrib['data3'] = ''
136
+ trafo_elm.attrib['data4'] = ''
137
+ trafo_elm.attrib['class'] = 'tooltip-trigger'
138
+
139
+ if 'vscs' in self.grid_data:
140
+ vscs_list = self.grid_data['vscs']
141
+ else:
142
+ vscs_list = []
143
+
144
+ for vsc in vscs_list:
145
+
146
+ if not 'bus_ac' in vsc: continue
147
+
148
+ bus_ac = vsc['bus_ac']
149
+ bus_dc = vsc['bus_dc']
150
+ vsc_id = f'vsc_{bus_ac}_{bus_dc}'
151
+
152
+ vsc_svg = s.root.findall(f".//*[@id='{vsc_id}']")
153
+ if len(vsc_svg)>0:
154
+ vsc_elm = vsc_svg[0]
155
+ else:
156
+ print(f'No VSC {vsc_id} found')
157
+ continue
158
+ vsc_elm.attrib['data0'] = 'vsc'
159
+ p_dc = grid.get_value(f'p_vsc_{bus_dc}')
160
+ vsc_elm.attrib['data1'] = 'VSC'
161
+
162
+ p_ac = grid.get_value(f'p_vsc_{bus_ac}')
163
+ p_dc = grid.get_value(f'p_vsc_{bus_dc}')
164
+ vsc_elm.attrib['data2'] = f' Pac = {p_ac/1e3:0.1f} kW, Pdc = {p_dc/1e3:0.1f} kW'
165
+
166
+ p_loss = grid.get_value(f'p_vsc_loss_{bus_ac}')
167
+ vsc_elm.attrib['data3'] = f' Losses = {p_loss/1e3:0.1f} kW'
168
+
169
+ vsc_elm.attrib['class'] = 'tooltip-trigger'
170
+
171
+ script = '''
172
+ <![CDATA[
173
+ (function() {
174
+ var svg = document.getElementById('document_id');
175
+ var tooltip_1 = svg.getElementById('tooltip1');
176
+ var tooltipText_1_1 = tooltip_1.getElementsByTagName('text')[0];
177
+ var tooltipText_1_2 = tooltip_1.getElementsByTagName('text')[1];
178
+ var tooltipText_1_3 = tooltip_1.getElementsByTagName('text')[2];
179
+ var tooltipText_1_4 = tooltip_1.getElementsByTagName('text')[3];
180
+ var tooltipText_1_5 = tooltip_1.getElementsByTagName('text')[4];
181
+ var tooltipText_1_6 = tooltip_1.getElementsByTagName('text')[5];
182
+ var tooltip_2 = svg.getElementById('tooltip2');
183
+ var tooltipText_2_1 = tooltip_2.getElementsByTagName('text')[0];
184
+ var tooltipText_2_2 = tooltip_2.getElementsByTagName('text')[1];
185
+ var tooltipText_2_3 = tooltip_2.getElementsByTagName('text')[2];
186
+ var tooltipText_2_4 = tooltip_2.getElementsByTagName('text')[3];
187
+ var tooltipText_2_5 = tooltip_2.getElementsByTagName('text')[4];
188
+ var tooltipText_2_6 = tooltip_2.getElementsByTagName('text')[5];
189
+ var tooltip_3 = svg.getElementById('tooltip3');
190
+ var tooltipText_3_1 = tooltip_3.getElementsByTagName('text')[0];
191
+ var tooltipText_3_2 = tooltip_3.getElementsByTagName('text')[1];
192
+ var tooltipText_3_3 = tooltip_3.getElementsByTagName('text')[2];
193
+ var tooltipText_3_4 = tooltip_3.getElementsByTagName('text')[3];
194
+
195
+ var tooltipRects = tooltip_1.getElementsByTagName('rect');
196
+ var triggers = svg.getElementsByClassName('tooltip-trigger');
197
+ for (var i = 0; i < triggers.length; i++) {
198
+ triggers[i].addEventListener('mousemove', showTooltip);
199
+ triggers[i].addEventListener('mouseout', hideTooltip);
200
+ }
201
+ function showTooltip(evt) {
202
+ var CTM = svg.getScreenCTM();
203
+ var x_unsat = (evt.clientX - CTM.e) / CTM.a
204
+ var x = x_unsat;
205
+ if (x_unsat>x_max) {var x = x_max}
206
+ if (x_unsat<x_min) {var x = x_min}
207
+
208
+
209
+ var y_unsat = (evt.clientY - CTM.f) / CTM.d + 30;
210
+ var y = y_unsat;
211
+ if (y_unsat>y_max) {var y = y_max - y_height}
212
+
213
+
214
+ if (evt.target.getAttributeNS(null, "data0") == "bus") {
215
+ tooltip_1.setAttributeNS(null, "transform", "translate(" + x + " " + y + ")");
216
+ tooltip_1.setAttributeNS(null, "visibility", "visible")}
217
+
218
+ if (evt.target.getAttributeNS(null, "data0") == "line") {
219
+ tooltip_2.setAttributeNS(null, "transform", "translate(" + x + " " + y + ")");
220
+ tooltip_2.setAttributeNS(null, "visibility", "visible")}
221
+
222
+ if (evt.target.getAttributeNS(null, "data0") == "vsc") {
223
+ tooltip_3.setAttributeNS(null, "transform", "translate(" + x + " " + y + ")");
224
+ tooltip_3.setAttributeNS(null, "visibility", "visible")}
225
+
226
+ if (evt.target.getAttributeNS(null, "data0") == "trafo") {
227
+ tooltip_3.setAttributeNS(null, "transform", "translate(" + x + " " + y + ")");
228
+ tooltip_3.setAttributeNS(null, "visibility", "visible")}
229
+
230
+ tooltipText_1_1.firstChild.data = evt.target.getAttributeNS(null, "data1");
231
+ tooltipText_1_2.firstChild.data = evt.target.getAttributeNS(null, "data2");
232
+ tooltipText_1_3.firstChild.data = evt.target.getAttributeNS(null, "data3");
233
+ tooltipText_1_4.firstChild.data = evt.target.getAttributeNS(null, "data4");
234
+ tooltipText_1_5.firstChild.data = evt.target.getAttributeNS(null, "data5");
235
+ tooltipText_1_6.firstChild.data = evt.target.getAttributeNS(null, "data6");
236
+
237
+ tooltipText_2_1.firstChild.data = evt.target.getAttributeNS(null, "data1");
238
+ tooltipText_2_2.firstChild.data = evt.target.getAttributeNS(null, "data2");
239
+ tooltipText_2_3.firstChild.data = evt.target.getAttributeNS(null, "data3");
240
+ tooltipText_2_4.firstChild.data = evt.target.getAttributeNS(null, "data4");
241
+ tooltipText_2_5.firstChild.data = evt.target.getAttributeNS(null, "data5");
242
+ tooltipText_2_6.firstChild.data = evt.target.getAttributeNS(null, "data6");
243
+
244
+ tooltipText_3_1.firstChild.data = evt.target.getAttributeNS(null, "data1");
245
+ tooltipText_3_2.firstChild.data = evt.target.getAttributeNS(null, "data2");
246
+ tooltipText_3_3.firstChild.data = evt.target.getAttributeNS(null, "data3");
247
+ tooltipText_3_4.firstChild.data = evt.target.getAttributeNS(null, "data4");
248
+
249
+ var length = tooltipText_1_1.getComputedTextLength()+200;
250
+ for (var i = 0; i < tooltipRects.length; i++) {
251
+ tooltipRects[i].setAttributeNS(null, "width", length + 8);
252
+ }
253
+ }
254
+ function hideTooltip(evt) {
255
+ tooltip_1.setAttributeNS(null, "visibility", "hidden");
256
+ tooltip_2.setAttributeNS(null, "visibility", "hidden");
257
+ tooltip_3.setAttributeNS(null, "visibility", "hidden");
258
+ }
259
+ })()
260
+ ]]>'''
261
+
262
+
263
+
264
+ element = Element('script')
265
+ element.attrib['type'] ="text/ecmascript"
266
+ element.attrib['id'] = "script15"
267
+ element.text = 'scriptplace'
268
+ self.root.append(element)
269
+
270
+ set_lines_currents_v2(self)
271
+ set_buses_voltages_v2(self)
272
+
273
+ out = self.tostring().replace('scriptplace',script)
274
+ width = float(self.root.attrib['width'])
275
+ height = float(self.root.attrib['height'])
276
+ document_id = self.root.attrib['id']
277
+
278
+ tooltip_width = 320
279
+ tooltip_height = 100
280
+
281
+ out=out.replace('x_max',f'{width-tooltip_width/2}' )
282
+ out=out.replace('x_min',f'{tooltip_width/2}' )
283
+ out=out.replace('y_max',f'{height-tooltip_height}' )
284
+ out=out.replace('y_height',f'{tooltip_height}' )
285
+ out=out.replace('document_id', document_id)
286
+
287
+ with open(output_file,'w') as fobj:
288
+ fobj.write(out)
289
+
290
+ def set_lines_currents_v2(self):
291
+
292
+ for line in self.grid_data['lines']:
293
+ #if not 'monitor'in line or not 'vsc_line' in line: continue
294
+ if 'monitor' in line:
295
+ if not line['monitor']: continue
296
+ if 'vsc_line' in line:
297
+ if not line['vsc_line']: continue
298
+
299
+ bus_j = line['bus_j']
300
+ bus_k = line['bus_k']
301
+
302
+ z2a = {'0':'a','1':'b','2':'c','3':'n'}
303
+ for ph in ['0','1','2','3']:
304
+ line_id = f'l_{bus_j}_{ph}_{bus_k}_{ph}'
305
+ if f'i_{line_id}_r' in self.grid.outputs_list:
306
+ if 'code' in line:
307
+ I_max = self.grid_data["line_codes"][line['code']]['I_max']
308
+ else:
309
+ I_max = line['I_max']
310
+
311
+
312
+ i_r = self.grid.get_value(f'i_{line_id}_r')
313
+ i_i = self.grid.get_value(f'i_{line_id}_i')
314
+ i = i_r + 1j*i_i
315
+ i_abs = np.abs(i)
316
+ #print(f'l_{bus_j}_{bus_k}_{ph} = {i_abs:8.1f} A')
317
+ if i_abs < 1e-3: continue
318
+ i_sat = np.clip((i_abs/I_max)**2*255,0,255)
319
+ self.set_color('line',line_id,(int(i_sat),0,0))
320
+
321
+ def set_buses_voltages_v2(self):
322
+
323
+ v_ac_min = 20e6
324
+ min_dc_voltage = 20e6
325
+ min_n_ac_voltage = 20e6
326
+ min_n_dc_voltage = 20e6
327
+
328
+ v_ac_max = 0
329
+ max_dc_voltage = 0
330
+ max_n_ac_voltage = 0
331
+ max_n_dc_voltage = 0
332
+
333
+
334
+ for bus in self.grid_data['buses']:
335
+ v_r = self.grid.get_value(f'V_{bus["name"]}_0_r')
336
+ v_i = self.grid.get_value(f'V_{bus["name"]}_0_i')
337
+ v = v_r + 1j*v_i
338
+ v_abs = np.abs(v)
339
+ V_med_pu= 0.5*(self.V_max_pu + self.V_min_pu)
340
+ acdc = 'ac'
341
+ if 'acdc' in bus:
342
+ if bus['acdc'] == 'DC':
343
+ V_nom = bus['U_kV']*1000/2
344
+ acdc = 'dc'
345
+ if bus['acdc'] == 'AC':
346
+ V_nom = bus['U_kV']/np.sqrt(3)*1000
347
+ acdc = 'ac'
348
+ else:
349
+ V_nom = bus['U_kV']/np.sqrt(3)*1000
350
+ acdc = 'ac'
351
+
352
+ V_pu = v_abs/V_nom
353
+
354
+ # when V_pu = V_med_pu color = 0, when V_pu = V_max_pu color = 255 (red)
355
+ # when V_pu = V_med_pu color = 0, when V_pu = V_min_pu color = 255 (blue)
356
+ if V_pu < V_med_pu:
357
+ blue = np.clip(255*((V_pu - V_med_pu)/(self.V_min_pu - V_med_pu))**2,0,255)
358
+ self.set_color('rect',f'{bus["name"]}',(0,0,int(blue)))
359
+ if V_pu > V_med_pu:
360
+ red = np.clip(255*((V_pu - V_med_pu)/(self.V_max_pu - V_med_pu))**2,0,255)
361
+ self.set_color('rect',f'{bus["name"]}',(int(red),0,0))
362
+
363
+ if acdc == 'ac':
364
+ if V_pu < v_ac_min:
365
+ self.post_data.update({'v_ac_min':{'bus':bus['name'],'value':V_pu}})
366
+ v_ac_min = V_pu
367
+ if V_pu > v_ac_max:
368
+ self.post_data.update({'v_ac_max':{'bus':bus['name'],'value':V_pu}})
369
+ v_ac_max = V_pu