Skip to content

Commit 6a15e85

Browse files
committed
latest changes from eroots repo
1 parent 34885ce commit 6a15e85

109 files changed

Lines changed: 7418 additions & 1355 deletions

File tree

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

README.md

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -14,7 +14,7 @@ product of cutting-edge research.
1414
[![Documentation Status](https://readthedocs.org/projects/veragrid/badge/?version=latest)](https://veragrid.readthedocs.io/en/latest/?badge=latest) [![Build Status](https://travis-ci.org/SanPen/VeraGrid.svg?branch=master)](https://travis-ci.org/SanPen/VeraGrid)
1515
[![DOI](https://www.zenodo.org/badge/49583206.svg)](https://www.zenodo.org/badge/latestdoi/49583206)
1616
[![Downloads](https://static.pepy.tech/personalized-badge/veragrid?period=total&units=abbreviation&left_color=grey&right_color=green&left_text=Downloads)](https://pepy.tech/project/veragrid)
17-
[![Discord](https://img.shields.io/badge/Discord-%235865F2.svg)](https://discord.gg/sVnwkaxN)
17+
[![Discord](https://img.shields.io/badge/Discord-%235865F2.svg)](https://discord.gg/ypgmWvT5)
1818

1919
VeraGrid started in 2015 with a clear objective: create a solid programming library and a user-friendly interface.
2020
This straightforward approach sparked many innovations — some driven by the necessity
@@ -1467,7 +1467,7 @@ All contributions must come with testing.
14671467

14681468
## Contact
14691469

1470-
- Join the [Discord VeraGrid channel](https://discord.com/invite/dzxctaNbvu) for a friendly chat, or quick question.
1470+
- Join the [Discord VeraGrid channel](https://discord.gg/ypgmWvT5) for a friendly chat, or quick question.
14711471
- Submit questions or comments to our [form](https://forms.gle/MpjJAntAwZiLwE6B6).
14721472
- Submit bugs or requests in the [Issues](https://github.com/SanPen/VeraGrid/issues) section.
14731473

src/VeraGridEngine/Compilers/circuit_to_gslv.py

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -2321,6 +2321,7 @@ def gslv_pf(circuit: MultiCircuit,
23212321
logger: Logger = Logger()) -> "pg.PowerFlowResults":
23222322
"""
23232323
GSLV power flow
2324+
:param logger:
23242325
:param circuit: MultiCircuit instance
23252326
:param pf_opt: Power Flow Options
23262327
:param time_series: Compile with VeraGrid time series?
@@ -2407,7 +2408,7 @@ def translate_gslv_pf_results(grid: MultiCircuit, res: "pg.PowerFlowResults", lo
24072408
results.loading_hvdc = res.loading_hvdc[0, :]
24082409
results.losses_hvdc = res.losses_hvdc[0, :]
24092410

2410-
results.Pf_vsc = res.Pf_vsc[0, :]
2411+
results.Pfp_vsc = res.Pf_vsc[0, :]
24112412
results.St_vsc = res.St_vsc[0, :]
24122413
results.loading_vsc = res.loading_vsc[0, :]
24132414
results.losses_vsc = res.losses_vsc[0, :]

src/VeraGridEngine/Devices/Branches/line.py

Lines changed: 35 additions & 19 deletions
Original file line numberDiff line numberDiff line change
@@ -662,8 +662,16 @@ def get_equivalent_transformer(self, index: pd.DatetimeIndex | None = None) -> T
662662

663663
return elm
664664

665-
def fill_design_properties(self, r_ohm: float, x_ohm: float, c_nf: float, length: float,
666-
Imax: float, freq: float, Sbase: float, apply_to_profile: bool = True, ) -> "Line":
665+
def fill_design_properties(self,
666+
r_ohm: float,
667+
x_ohm: float,
668+
c_nf: float,
669+
length: float,
670+
Imax: float,
671+
freq: float,
672+
Sbase: float,
673+
apply_to_profile: bool = True,
674+
logger: Logger = Logger()) -> "Line":
667675
"""
668676
Fill R, X, B from not-in-per-unit parameters
669677
:param r_ohm: Resistance per km in OHM/km
@@ -674,28 +682,36 @@ def fill_design_properties(self, r_ohm: float, x_ohm: float, c_nf: float, length
674682
:param freq: System frequency in Hz
675683
:param Sbase: Base power in MVA (take always 100 MVA)
676684
:param apply_to_profile: modify the ratings profile if checked
685+
:param logger: Logger
677686
:return self pointer
678687
"""
679-
self.R, self.X, self.B, new_rate = get_line_impedances_with_c(r_ohm=r_ohm,
680-
x_ohm=x_ohm,
681-
c_nf=c_nf,
682-
length=length,
683-
Imax=Imax,
684-
freq=freq,
685-
Sbase=Sbase,
686-
Vnom=self.get_max_bus_nominal_voltage())
688+
Vnom = self.get_max_bus_nominal_voltage()
687689

688-
old_rate = float(self.rate)
690+
if Vnom > 0:
689691

690-
self.rate = new_rate
691-
self._length = length
692+
self.R, self.X, self.B, new_rate = get_line_impedances_with_c(r_ohm=r_ohm,
693+
x_ohm=x_ohm,
694+
c_nf=c_nf,
695+
length=length,
696+
Imax=Imax,
697+
freq=freq,
698+
Sbase=Sbase,
699+
Vnom=Vnom,
700+
logger=logger)
692701

693-
if apply_to_profile:
694-
if old_rate != 0.0:
695-
prof_old = self.rate_prof.toarray()
696-
self.rate_prof.set(prof_old * new_rate / old_rate)
697-
else:
698-
self.rate_prof.fill(new_rate)
702+
old_rate = float(self.rate)
703+
704+
self.rate = new_rate
705+
self._length = length
706+
707+
if apply_to_profile:
708+
if old_rate != 0.0:
709+
prof_old = self.rate_prof.toarray()
710+
self.rate_prof.set(prof_old * new_rate / old_rate)
711+
else:
712+
self.rate_prof.fill(new_rate)
713+
else:
714+
logger.add_error("Nominal voltage is zero", device_class="Line", device=self.name)
699715

700716
return self
701717

src/VeraGridEngine/Devices/Branches/sequence_line_type.py

Lines changed: 62 additions & 31 deletions
Original file line numberDiff line numberDiff line change
@@ -6,11 +6,18 @@
66
import numpy as np
77
from VeraGridEngine.Devices.admittance_matrix import AdmittanceMatrix
88
from VeraGridEngine.Devices.Parents.editable_device import EditableDevice, DeviceType
9-
10-
11-
def get_line_impedances_with_c(r_ohm: float, x_ohm: float, c_nf: float,
12-
length: float, Imax: float,
13-
freq: float, Sbase: float, Vnom: float) -> Tuple[float, float, float, float]:
9+
from VeraGridEngine.basic_structures import Logger
10+
11+
12+
def get_line_impedances_with_c(r_ohm: float,
13+
x_ohm: float,
14+
c_nf: float,
15+
length: float,
16+
Imax: float,
17+
freq: float,
18+
Sbase: float,
19+
Vnom: float,
20+
logger: Logger = Logger()) -> Tuple[float, float, float, float]:
1421
"""
1522
Fill R, X, B from not-in-per-unit parameters
1623
:param r_ohm: Resistance per km in OHM/km
@@ -21,26 +28,31 @@ def get_line_impedances_with_c(r_ohm: float, x_ohm: float, c_nf: float,
2128
:param freq: System frequency in Hz
2229
:param Sbase: Base power in MVA (take always 100 MVA)
2330
:param Vnom: nominal voltage (kV)
31+
:param logger: logger
2432
:return R, X, B, rate
2533
"""
2634
r_ohm_total = r_ohm * length
2735
x_ohm_total = x_ohm * length
2836
b_siemens_total = (2 * np.pi * freq * c_nf * 1e-9) * length
2937

30-
Zbase = (Vnom * Vnom) / Sbase
31-
Ybase = 1.0 / Zbase
32-
33-
R = np.round(r_ohm_total / Zbase, 6)
34-
X = np.round(x_ohm_total / Zbase, 6)
35-
B = np.round(b_siemens_total / Ybase, 6)
38+
if Vnom > 0.0:
39+
Zbase = (Vnom * Vnom) / Sbase
40+
Ybase = 1.0 / Zbase
3641

37-
rate = np.round(Imax * Vnom * 1.73205080757, 6) # nominal power in MVA = kA * kV * sqrt(3)
42+
R: float = np.round(r_ohm_total / Zbase, 6)
43+
X: float = np.round(x_ohm_total / Zbase, 6)
44+
B: float = np.round(b_siemens_total / Ybase, 6)
45+
rate: float = np.round(Imax * Vnom * 1.73205080757, 6) # nominal power in MVA = kA * kV * sqrt(3)
3846

39-
return R, X, B, rate
47+
return R, X, B, rate
48+
else:
49+
logger.add_error("Nominal voltage is zero", device_class="SequenceLineType")
50+
return 1e-20, 1e-20, 0, 1e-20
4051

4152

4253
def get_line_impedances_with_b(r_ohm: float, x_ohm: float, b_us: float, length: float,
43-
Imax: float, Sbase: float, Vnom: float) -> Tuple[float, float, float, float]:
54+
Imax: float, Sbase: float, Vnom: float,
55+
logger: Logger = Logger()) -> Tuple[float, float, float, float]:
4456
"""
4557
Fill R, X, B from not-in-per-unit parameters
4658
:param r_ohm: Resistance per km in OHM/km
@@ -56,16 +68,20 @@ def get_line_impedances_with_b(r_ohm: float, x_ohm: float, b_us: float, length:
5668
x_ohm_total = x_ohm * length
5769
b_siemens_total = (b_us * 1e-6) * length
5870

59-
Zbase = (Vnom * Vnom) / Sbase
60-
Ybase = 1.0 / Zbase
71+
if Vnom > 0:
72+
Zbase = (Vnom * Vnom) / Sbase
73+
Ybase = 1.0 / Zbase
6174

62-
R = np.round(r_ohm_total / Zbase, 6)
63-
X = np.round(x_ohm_total / Zbase, 6)
64-
B = np.round(b_siemens_total / Ybase, 6)
75+
R: float = np.round(r_ohm_total / Zbase, 6)
76+
X: float = np.round(x_ohm_total / Zbase, 6)
77+
B: float = np.round(b_siemens_total / Ybase, 6)
78+
rate: float = np.round(Imax * Vnom * 1.73205080757, 6) # nominal power in MVA = kA * kV * sqrt(3)
6579

66-
rate = np.round(Imax * Vnom * 1.73205080757, 6) # nominal power in MVA = kA * kV * sqrt(3)
80+
return R, X, B, rate
81+
else:
82+
logger.add_error("Nominal voltage is zero", device_class="SequenceLineType")
6783

68-
return R, X, B, rate
84+
return 1e-20, 1e-20, 0, 1e-20
6985

7086

7187
class SequenceLineType(EditableDevice):
@@ -139,7 +155,8 @@ def __init__(self, name='SequenceLine', idtag=None, Imax=1, Vnom=1,
139155
definition='Use conductance? else the susceptance is used')
140156
self.register(key='n_circuits', units='', tpe=int, definition='number of circuits')
141157

142-
def get_values(self, Sbase: float, freq: float, length: float, line_Vnom: float, ):
158+
def get_values(self, Sbase: float, freq: float, length: float, line_Vnom: float,
159+
logger: Logger = Logger()):
143160
"""
144161
Get the per-unit values
145162
:param Sbase: Base power (MVA, always use 100MVA)
@@ -153,24 +170,38 @@ def get_values(self, Sbase: float, freq: float, length: float, line_Vnom: float,
153170
R, X, B, rate = get_line_impedances_with_c(r_ohm=self.R,
154171
x_ohm=self.X,
155172
c_nf=self.Cnf,
156-
length=length, Imax=self.Imax,
157-
freq=freq, Sbase=Sbase, Vnom=line_Vnom)
173+
length=length,
174+
Imax=self.Imax,
175+
freq=freq,
176+
Sbase=Sbase,
177+
Vnom=line_Vnom,
178+
logger=logger)
179+
158180
R0, X0, B0, _ = get_line_impedances_with_c(r_ohm=self.R0,
159181
x_ohm=self.X0,
160182
c_nf=self.Cnf0,
161-
length=length, Imax=self.Imax,
162-
freq=freq, Sbase=Sbase, Vnom=line_Vnom)
183+
length=length,
184+
Imax=self.Imax,
185+
freq=freq,
186+
Sbase=Sbase,
187+
Vnom=line_Vnom,
188+
logger=logger)
163189
else:
164190
R, X, B, rate = get_line_impedances_with_b(r_ohm=self.R,
165191
x_ohm=self.X,
166192
b_us=self.B,
167-
length=length, Imax=self.Imax,
168-
Sbase=Sbase, Vnom=line_Vnom)
193+
length=length,
194+
Imax=self.Imax,
195+
Sbase=Sbase,
196+
Vnom=line_Vnom)
197+
169198
R0, X0, B0, _ = get_line_impedances_with_b(r_ohm=self.R0,
170199
x_ohm=self.X0,
171200
b_us=self.B0,
172-
length=length, Imax=self.Imax,
173-
Sbase=Sbase, Vnom=line_Vnom)
201+
length=length,
202+
Imax=self.Imax,
203+
Sbase=Sbase,
204+
Vnom=line_Vnom)
174205

175206
return R, X, B, R0, X0, B0, rate
176207

@@ -227,4 +258,4 @@ def get_ysh_nabc(self) -> AdmittanceMatrix:
227258
adm.phB = 1
228259
adm.phC = 1
229260

230-
return adm
261+
return adm

src/VeraGridEngine/Devices/Branches/tap_changer.py

Lines changed: 2 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -56,7 +56,7 @@ def __init__(self,
5656
self._asymmetry_angle = float(asymmetry_angle)
5757

5858
# total number of positions
59-
self._total_positions = int(total_positions)
59+
self._total_positions = int(total_positions) if total_positions > 0 else 1
6060

6161
# voltage increment in p.u.
6262
self._dV = float(dV)
@@ -102,15 +102,6 @@ def dV(self, dV: float) -> None:
102102
self._dV = float(dV)
103103
self.recalc()
104104

105-
@property
106-
def neutral_position(self) -> int:
107-
return self._neutral_position
108-
109-
@neutral_position.setter
110-
def neutral_position(self, neutral_position: int) -> None:
111-
self._neutral_position = int(neutral_position)
112-
self.recalc()
113-
114105
@property
115106
def normal_position(self) -> int:
116107
return self._normal_position
@@ -249,7 +240,7 @@ def parse(self, data: Dict[str, Union[str, float]], logger: Logger = Logger()) -
249240
self.tc_type = TapChangerTypes(data.get("type", TapChangerTypes.NoRegulation.value))
250241
self._negative_low = data.get("negative_low", False)
251242

252-
# parse the impedance corerction factors
243+
# parse the impedance correction factors
253244

254245
_k_re_array = data.get("impedance_correction_real", None)
255246
if _k_re_array is not None:

src/VeraGridEngine/Devices/Injections/generator.py

Lines changed: 11 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -2,7 +2,7 @@
22
# License, v. 2.0. If a copy of the MPL was not distributed with this
33
# file, You can obtain one at https://mozilla.org/MPL/2.0/.
44
# SPDX-License-Identifier: MPL-2.0
5-
5+
from __future__ import annotations
66

77
import numpy as np
88
import pandas as pd
@@ -343,6 +343,16 @@ def get_Pf_at(self, t: int | None) -> float:
343343
"""
344344
return get_at(self.Pf, self.Pf_prof, t)
345345

346+
def get_Q_at(self, t: int | None) -> float:
347+
"""
348+
:param t:
349+
:return:
350+
"""
351+
p = self.get_P_at(t)
352+
pf = get_at(self.Pf, self.Pf_prof, t)
353+
354+
return p * np.sqrt(1.0 / (pf * pf) - 1.0)
355+
346356
@property
347357
def Vset_prof(self) -> Profile:
348358
"""

src/VeraGridEngine/Devices/Injections/static_generator.py

Lines changed: 24 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -9,11 +9,11 @@
99

1010

1111
class StaticGenerator(LoadParent):
12-
__slots__ = ()
12+
__slots__ = ("_Snom")
1313

1414
def __init__(self, name='StaticGen', idtag=None, code='', P=0.0, Q=0.0, active=True,
1515
P1=0.0, P2=0.0, P3=0.0, Q1=0.0, Q2=0.0, Q3=0.0,
16-
mttf=0.0, mttr=0.0, Cost=1200.0,
16+
mttf=0.0, mttr=0.0, Cost=1200.0, Snom=0,
1717
capex=0, opex=0, build_status: BuildStatus = BuildStatus.Commissioned):
1818
"""
1919
@@ -58,3 +58,25 @@ def __init__(self, name='StaticGen', idtag=None, code='', P=0.0, Q=0.0, active=T
5858
opex=opex,
5959
build_status=build_status,
6060
device_type=DeviceType.StaticGeneratorDevice)
61+
62+
# Nominal power in MVA (also the machine base)
63+
self._Snom = float(Snom)
64+
65+
self.register(key='Snom', units='MVA', tpe=float, definition='Nominal power.')
66+
67+
@property
68+
def Snom(self):
69+
"""
70+
Return the reactive power lower limit
71+
:return: value
72+
"""
73+
return self._Snom
74+
75+
@Snom.setter
76+
def Snom(self, val):
77+
"""
78+
Set the generator nominal power
79+
if the reactive power curve was generated automatically, then it is refreshed
80+
:param val: float value
81+
"""
82+
self._Snom = val

src/VeraGridEngine/Devices/Parents/branch_parent.py

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -497,6 +497,18 @@ def get_sorted_buses_voltages(self):
497497
else:
498498
return bus_t_v, bus_f_v
499499

500+
def get_buses_sorted_by_voltage(self):
501+
"""
502+
Get the sorted buses
503+
:return: HV bus, LV bus
504+
"""
505+
bus_f_v = self.bus_from.Vnom
506+
bus_t_v = self.bus_to.Vnom
507+
if bus_f_v > bus_t_v:
508+
return self.bus_from, self.bus_to
509+
else:
510+
return self.bus_to, self.bus_from
511+
500512
def get_virtual_taps(self) -> Tuple[float, float]:
501513
"""
502514
Get the branch virtual taps

0 commit comments

Comments
 (0)