Note
You can download this example as a Jupyter notebook or start it in interactive mode.
Transformer with non-trivial phase shift and tap ratio
This example is a copy of pandapower’s minimal example.
[1]:
import pypsa
import numpy as np
import pandas as pd
[2]:
network = pypsa.Network()
network.add("Bus","MV bus",v_nom=20, v_mag_pu_set=1.02)
network.add("Bus","LV1 bus",v_nom=.4)
network.add("Bus","LV2 bus",v_nom=.4)
network.add("Transformer", "MV-LV trafo", type="0.4 MVA 20/0.4 kV", bus0="MV bus", bus1="LV1 bus")
network.add("Line", "LV cable", type="NAYY 4x50 SE",bus0="LV1 bus", bus1="LV2 bus", length=0.1)
network.add("Generator", "External Grid", bus="MV bus", control="Slack")
network.add("Load", "LV load", bus="LV2 bus", p_set=0.1, q_set=0.05)
[3]:
def run_pf():
network.lpf()
network.pf(use_seed=True)
return pd.DataFrame({'Voltage Angles': network.buses_t.v_ang.loc['now']*180./np.pi,
'Volate Magnitude': network.buses_t.v_mag_pu.loc['now']})
[4]:
run_pf()
INFO:pypsa.pf:Performing linear load-flow on AC sub-network SubNetwork 0 for snapshot(s) Index(['now'], dtype='object')
INFO:pypsa.pf:Performing non-linear load-flow on AC sub-network SubNetwork 0 for snapshots Index(['now'], dtype='object')
INFO:pypsa.pf:Newton-Raphson solved in 3 iterations with error of 0.000000 in 0.026950 seconds
[4]:
| Voltage Angles | Volate Magnitude | |
|---|---|---|
| MV bus | 0.000000 | 1.020000 |
| LV1 bus | -150.760126 | 1.008843 |
| LV2 bus | -149.884141 | 0.964431 |
[5]:
network.transformers.tap_position = 2
run_pf()
INFO:pypsa.pf:Performing linear load-flow on AC sub-network SubNetwork 0 for snapshot(s) Index(['now'], dtype='object')
INFO:pypsa.pf:Performing non-linear load-flow on AC sub-network SubNetwork 0 for snapshots Index(['now'], dtype='object')
INFO:pypsa.pf:Newton-Raphson solved in 3 iterations with error of 0.000000 in 0.026923 seconds
[5]:
| Voltage Angles | Volate Magnitude | |
|---|---|---|
| MV bus | 0.000000 | 1.020000 |
| LV1 bus | -150.843911 | 0.959655 |
| LV2 bus | -149.870837 | 0.912713 |
[6]:
network.transformers.tap_position = -2
run_pf()
INFO:pypsa.pf:Performing linear load-flow on AC sub-network SubNetwork 0 for snapshot(s) Index(['now'], dtype='object')
INFO:pypsa.pf:Performing non-linear load-flow on AC sub-network SubNetwork 0 for snapshots Index(['now'], dtype='object')
INFO:pypsa.pf:Newton-Raphson solved in 3 iterations with error of 0.000000 in 0.026316 seconds
[6]:
| Voltage Angles | Volate Magnitude | |
|---|---|---|
| MV bus | 0.000000 | 1.020000 |
| LV1 bus | -150.681666 | 1.063133 |
| LV2 bus | -149.896634 | 1.021202 |
Now play with tap changer on LV side
[7]:
new_trafo_lv_tap = network.transformer_types.loc[["0.4 MVA 20/0.4 kV"]]
new_trafo_lv_tap.index = ["New trafo"]
new_trafo_lv_tap.tap_side = 1
new_trafo_lv_tap.T
[7]:
| New trafo | |
|---|---|
| f_nom | 50.0 |
| s_nom | 0.4 |
| v_nom_0 | 20.0 |
| v_nom_1 | 0.4 |
| vsc | 6.0 |
| vscr | 1.425 |
| pfe | 1.35 |
| i0 | 0.3375 |
| phase_shift | 150.0 |
| tap_side | 1 |
| tap_neutral | 0 |
| tap_min | -2 |
| tap_max | 2 |
| tap_step | 2.5 |
| references | pandapower;Oswald - Transformatoren - Vorlesun... |
[8]:
network.transformer_types = network.transformer_types.append(new_trafo_lv_tap)
network.transformers.type = "New trafo"
network.transformers.tap_position = 2
run_pf()
INFO:pypsa.pf:Performing linear load-flow on AC sub-network SubNetwork 0 for snapshot(s) Index(['now'], dtype='object')
INFO:pypsa.pf:Performing non-linear load-flow on AC sub-network SubNetwork 0 for snapshots Index(['now'], dtype='object')
INFO:pypsa.pf:Newton-Raphson solved in 3 iterations with error of 0.000000 in 0.025110 seconds
[8]:
| Voltage Angles | Volate Magnitude | |
|---|---|---|
| MV bus | 0.000000 | 1.020000 |
| LV1 bus | -150.755820 | 1.059317 |
| LV2 bus | -149.964875 | 1.017221 |
[9]:
network.transformers.T
[9]:
| MV-LV trafo | |
|---|---|
| attribute | |
| bus0 | MV bus |
| bus1 | LV1 bus |
| type | New trafo |
| model | t |
| x | 0.058283 |
| r | 0.01425 |
| g | 0.003375 |
| b | -0.0 |
| s_nom | 0.4 |
| s_nom_extendable | False |
| s_nom_min | 0.0 |
| s_nom_max | inf |
| s_max_pu | 1.0 |
| capital_cost | 0.0 |
| num_parallel | 1.0 |
| tap_ratio | 1.05 |
| tap_side | 1 |
| tap_position | 2 |
| phase_shift | 150.0 |
| build_year | 0 |
| lifetime | inf |
| v_ang_min | -inf |
| v_ang_max | inf |
| sub_network | 0 |
| x_pu | 0.145712 |
| r_pu | 0.035618 |
| g_pu | 0.00135 |
| b_pu | -0.0 |
| x_pu_eff | 0.152994 |
| r_pu_eff | 0.037406 |
| s_nom_opt | 0.0 |
[10]:
network.transformers.tap_position = -2
run_pf()
INFO:pypsa.pf:Performing linear load-flow on AC sub-network SubNetwork 0 for snapshot(s) Index(['now'], dtype='object')
INFO:pypsa.pf:Performing non-linear load-flow on AC sub-network SubNetwork 0 for snapshots Index(['now'], dtype='object')
INFO:pypsa.pf:Newton-Raphson solved in 3 iterations with error of 0.000000 in 0.027012 seconds
[10]:
| Voltage Angles | Volate Magnitude | |
|---|---|---|
| MV bus | 0.000000 | 1.020000 |
| LV1 bus | -150.765232 | 0.958366 |
| LV2 bus | -149.789394 | 0.911353 |
Now make sure that the phase shift is also there in the LOPF
[11]:
network.generators.p_nom = 1.
network.lines.s_nom = 1.
network.lopf()
pd.DataFrame({'Voltage Angles': network.buses_t.v_ang.loc['now']*180./np.pi,
'Volate Magnitude': network.buses_t.v_mag_pu.loc['now']})
INFO:pypsa.opf:Performed preliminary steps
INFO:pypsa.opf:Building pyomo model using `kirchhoff` formulation
INFO:pypsa.opf:Solving model using glpk
WARNING:pyomo.solvers:Could not locate the 'glpsol' executable, which is required for solver 'glpk'
---------------------------------------------------------------------------
ApplicationError Traceback (most recent call last)
/tmp/ipykernel_870/2785965588.py in <module>
1 network.generators.p_nom = 1.
2 network.lines.s_nom = 1.
----> 3 network.lopf()
4 pd.DataFrame({'Voltage Angles': network.buses_t.v_ang.loc['now']*180./np.pi,
5 'Volate Magnitude': network.buses_t.v_mag_pu.loc['now']})
~/checkouts/readthedocs.org/user_builds/pypsa-docs-staging/envs/latest/lib/python3.7/site-packages/pypsa/components.py in lopf(self, snapshots, pyomo, solver_name, solver_options, solver_logfile, formulation, keep_files, extra_functionality, multi_investment_periods, **kwargs)
646
647 if pyomo:
--> 648 return network_lopf(self, **args)
649 else:
650 return network_lopf_lowmem(self, **args)
~/checkouts/readthedocs.org/user_builds/pypsa-docs-staging/envs/latest/lib/python3.7/site-packages/pypsa/opf.py in network_lopf(network, snapshots, solver_name, solver_io, skip_pre, extra_functionality, multi_investment_periods, solver_logfile, solver_options, keep_files, formulation, ptdf_tolerance, free_memory, extra_postprocessing)
1663 solver_logfile=solver_logfile, solver_options=solver_options,
1664 keep_files=keep_files, free_memory=free_memory,
-> 1665 extra_postprocessing=extra_postprocessing)
~/checkouts/readthedocs.org/user_builds/pypsa-docs-staging/envs/latest/lib/python3.7/site-packages/pypsa/opf.py in network_lopf_solve(network, snapshots, formulation, solver_options, solver_logfile, keep_files, free_memory, extra_postprocessing)
1563 network.results = network.opt.solve(*args, suffixes=["dual"], keepfiles=keep_files, logfile=solver_logfile, options=solver_options)
1564 else:
-> 1565 network.results = network.opt.solve(*args, suffixes=["dual"], keepfiles=keep_files, logfile=solver_logfile, options=solver_options)
1566
1567 if logger.isEnabledFor(logging.INFO):
~/checkouts/readthedocs.org/user_builds/pypsa-docs-staging/envs/latest/lib/python3.7/site-packages/pyomo/opt/base/solvers.py in solve(self, *args, **kwds)
510 """ Solve the problem """
511
--> 512 self.available(exception_flag=True)
513 #
514 # If the inputs are models, then validate that they have been
~/checkouts/readthedocs.org/user_builds/pypsa-docs-staging/envs/latest/lib/python3.7/site-packages/pyomo/opt/solver/shellcmd.py in available(self, exception_flag)
123 if exception_flag:
124 msg = "No executable found for solver '%s'"
--> 125 raise ApplicationError(msg % self.name)
126 return False
127 return True
ApplicationError: No executable found for solver 'glpk'