veragrid

VeraGrid, a cross-platform power systems software written in Python with user interface, used in academia and industry.

https://github.com/sanpen/veragrid

Science Score: 36.0%

This score indicates how likely this project is to be science-related based on various indicators:

  • CITATION.cff file
  • codemeta.json file
    Found codemeta.json file
  • .zenodo.json file
    Found .zenodo.json file
  • DOI references
  • Academic publication links
    Links to: zenodo.org
  • Academic email domains
  • Institutional organization owner
  • JOSS paper metadata
  • Scientific vocabulary similarity
    Low similarity (16.4%) to scientific vocabulary

Keywords

acdc cim comon-information-model electrical electrical-engineering helm latin-hypercube monte-carlo-simulation multi-terminal newton-raphson optimization power-systems powerflow python stochastic-power-flow
Last synced: 6 months ago · JSON representation

Repository

VeraGrid, a cross-platform power systems software written in Python with user interface, used in academia and industry.

Basic Info
Statistics
  • Stars: 468
  • Watchers: 34
  • Forks: 113
  • Open Issues: 28
  • Releases: 28
Topics
acdc cim comon-information-model electrical electrical-engineering helm latin-hypercube monte-carlo-simulation multi-terminal newton-raphson optimization power-systems powerflow python stochastic-power-flow
Created about 10 years ago · Last pushed 6 months ago
Metadata Files
Readme Contributing License Security

README.md

VeraGrid

VeraGrid is a top tier power systems planning and simulation software. As such it has all the static analysis studies that you can think of, plus linear and non-linear optimization functions. Some of these functions are well known, while others you may have never heard of as they are a product of cutting-edge research.

VeraGrid

Codacy Badge Documentation Status Build Status DOI Downloads Discord

VeraGrid started in 2015 with a clear objective: create a solid programming library and a user-friendly interface. This straightforward approach sparked many innovations some driven by the necessity for commercial use, and others fueled by curiosity and research.

Whether you're a pro needing free tools, a researcher wanting a real-world tested platform, a teacher sharing commercial-grade software insights, or a student diving into practical algorithms, VeraGrid's got your back. It's a high quality product made for all of us now and for the future generations.

Installation

VeraGrid is a software made in the Python programming language. Therefore, it needs a Python interpreter installed in your operative system.

The VeraGrid project is divided in three packages:

  • VeraGridEngine: A package with the database and calculations logic.
  • VeraGridServer: A package that serves an API-rest to use VeraGridEngine remotely.
  • VeraGrid: A package that contains the Graphical User Interface (GUI) and operates with VeraGridEngine and VeraGridServer seamlessly.

To install everything, you only need to install the VeraGrid package and the others will be installed as dependencies.

Standalone setup

If you don't know what is this Python thing, we offer a windows installation:

Windows setup

This will install VeraGrid as a normal windows program, and you don't need to worry about any of the previous instructions. Still, if you need some guidance, the following video might be of assistance: Setup tutorial (video).

Package installation

We recommend to install the latest version of Python and then, install VeraGrid with the following terminal command:

pip install VeraGrid

You may need to use pip3 if you are under Linux or MacOS, both of which come with Python pre-installed already.

Install into an environment

bash python3 -m venv gc5venv source gc5venv/bin/activate pip install VeraGrid veragrid

Run the graphical user interface

Once you install VeraGrid in your local Python distribution, you can run the graphical user interface with the following terminal command:

veragrid

If this doesn't work, try:

python -c "from VeraGrid.ExecuteVeraGrid import runVeraGrid; runVeraGrid()"

You may save this command in a shortcut for easy future access.

Install only the engine

Some of you may only need VeraGrid as a library for some other purpose like batch calculations, AI training or simple scripting. Whatever it may be, you can get the VeraGrid engine with the following terminal command:

pip install VeraGridEngine

This will install the VeraGridEngine package that is a dependency of VeraGrid.

Again, you may need to use pip3 if you are under Linux or MacOS.

Features

VeraGrid is packed with features:

  • Large collection of devices to model electricity grids
  • AC/DC multi-grid power flow
  • 3-phase unbalanced power flow and short circuit
  • AC/DC multi-grid linear optimal power flow
  • AC linear analysis (PTDF & LODF)
  • AC linear net transfer capacity calculation
  • AC+HVDC optimal net transfer capacity calculation
  • AC/DC Stochastic power flow
  • AC Short circuit
  • AC Continuation power flow
  • Contingency analysis (Power flow and LODF variants)
  • Sigma analysis (one-shot stability analysis)
  • Investments analysis
  • Bus-branch schematic
  • Substation-line map diagram
  • Time series and snapshot for most simulations
  • Overhead tower designer
  • Inputs analysis
  • Model bug report and repair
  • Import many formats (PSSe .raw/rawx, epc, dgs, matpower, pypsa, json, cim, cgmes)
  • Export in many formats (veragrid .xlsx/.veragrid/.json, cgmes, psse .raw/.rawx)

All of these are industry tested algorithms, some of which surpass most commercially available software. The aim is to be a drop-in replacement for the expensive and less usable commercial software, so that you can work, research and learn with it.

Resources

In an effort to ease the simulation and construction of grids, We have included extra materials to work with. These are included in the standalone setups.

Tutorials and examples

Matpower grids

Matpower's excellent formulations and consistency has allowed this and other projects to develop, relying on its sound math. That is why VeraGrid reads Matpower cases out of the box, without you having to do anything special. And of course, VeraGrid solves all Matpower 8 provided grids, solving the continental USA case in about 1 second:

VeraGrid

Find the results at the benchmarks page for more details.

Results simulated with AMD 9750x and 64 GB of RAM under Ubuntu 24.04. All solved using Newton-Raphson, and only using the provided solution that comes with the files when the flat start fails.

Cool right?

API

Since day one, VeraGrid was meant to be used as a library as much as it was meant to be used from the user interface. Following, we include some usage examples, but feel free to check the documentation out where you will find a complete description of the theory, the models and the objects.

Understanding the program structure

VeraGrid structure is composed by objects arranged in a "database" and by "structs" at a deeper level. Learn here why.

All simulations in VeraGrid are handled by the simulation drivers. The structure is as follows:

Any driver is fed with the data model (MultiCircuit object), the respective driver options, and often another object relative to specific inputs for that driver. The driver is run, storing the driver results object. Although this may seem overly complicated, it has proven to be maintainable and very convenient.

Snapshot vs. time series

VeraGrid has dual structure to handle legacy cases (snapshot), as well as cases with many variations (time series)

  • A snapshot is the grid for a particular moment in time. This includes the infrastructure plus the variable values of that infrastructure such as the load, the generation, the rating, etc.

  • The time series record the variations of the magnitudes that can vary. These are applied along with the infrastructure definition.

In VeraGrid, the inputs do not get modified by the simulation results. This very important concept, helps to maintain the independence of the inputs and outputs, allowing the replicability of the results. This key feature is not true for other open-source of commercial programs.

A snapshot or any point of the time series, may be compiled to a NumericalCircuit. This object holds the numerical arrays and matrices of a time step, ready for the numerical methods. For those simulations that require many time steps, a collection of NumericalCircuit is compiled and used.

It may seem that this extra step is redundant. However, the compilation step is composed by mere copy operations, which are fast. This steps benefits greatly the efficiency of the numerical calculations since the arrays are aligned in memory. The VeraGrid data model is object-oriented, while the numerical circuit is array-oriented (despite beign packed into objects)

Loading a grid

```python import VeraGridEngine as gce

load a grid (.veragrid, .m (Matpower), .raw (PSS/e) .rawx (PSS/e), .epc (PSLF), .dgs (PowerFactory)

mygrid = gce.openfile("my_file.veragrid") ```

In the case of CIM/CGMES, you may need to pass a list of files or a single zip file:

```python import VeraGridEngine as gce

load a grid from many xml files

mygrid = gce.openfile(["gridEQ.xml", "gridTP.xml", "grid_SV.xml", ])

or from a single zip assumed to contain CGMES files

mygrid = gce.openfile("mycgmessetoffiles.zip")

or load a grid from a combination of xml and zip files assumed to be CGMES

mygrid = gce.openfile(["gridEQ.xml", "gridTP.xml", "grid_SV.xml", "boundary.zip"]) ```

If you need to explore the CGMEs assets before conversion, you'll need to dive deeper in the API:

```python import VeraGridEngine as gce

fname = "tests/data/grids/CGMES24_15/IEEE 118 Bus v2.zip"

logger = gce.Logger() dataparser = gce.CgmesDataParser() dataparser.loadfiles(files=[fname]) cgmescircuit = gce.CgmesCircuit(cgmesversion=dataparser.cgmesversion, cgmesmapareaslikeraw=False, logger=logger) cgmescircuit.parsefiles(dataparser=data_parser)

print all the ac line segment names

for aclinesegment in cgmescircuit.cgmesassets.ACLineSegmentlist: print(acline_segment.name)

print the logs

logger.print() ```

VeraGrid supports many file formats:

  • CIM 16 (.zip and .xml)
  • UCTE.
  • CGMES 2.4.15 and 3.0 (.zip and .xml)
  • PSS/e raw and rawx versions 29 to 35, including USA market exchange RAW-30 specifics.
  • Matpower .m files directly.
  • DigSilent .DGS (not fully compatible)
  • PSLF .EPC (not fully compatible, supports substation coordinates)

Similarly to CGMES you may be able to use the conversion objects to explore the original formats.

Save a grid

```python import VeraGridEngine as gce

load a grid

mygrid = gce.openfile("my_file.veragrid")

save

gce.savefile(mygrid, "myfile2.veragrid") ```

In the case of saving a model in CGMES mode, we need to specify some extra parameters. To simplify we can use the API function save_cgmes_file:

```python import VeraGridEngine as gce

load a grid

mygrid = gce.openfile("my_file.veragrid")

run power flow (this is optional and it is used to generate the SV profile)

pfresults = gce.powerflow(my_grid)

save the grid in CGMES mode

gce.savecgmesfile(grid=mygrid, filename="Mycgmesmodel.zip", cgmesboundarysetpath="pathtotheboundaryset.zip", cgmesversion=gce.CGMESVersions.v2415, pfresults=pf_results)

```

Creating a Grid using the API objects

We are going to create a very simple 5-node grid from the excellent book Power System Load Flow Analysis by Lynn Powell.

Lynn 5 buses

```python import VeraGridEngine as gce

declare a circuit object

grid = gce.MultiCircuit()

Add the buses and the generators and loads attached

bus1 = gce.Bus('Bus 1', Vnom=20)

bus1.is_slack = True # we may mark the bus a slack

grid.add_bus(bus1)

add a generator to the bus 1

gen1 = gce.Generator('Slack Generator', vset=1.0) grid.add_generator(bus1, gen1)

add bus 2 with a load attached

bus2 = gce.Bus('Bus 2', Vnom=20) grid.addbus(bus2) grid.addload(bus2, gce.Load('load 2', P=40, Q=20))

add bus 3 with a load attached

bus3 = gce.Bus('Bus 3', Vnom=20) grid.addbus(bus3) grid.addload(bus3, gce.Load('load 3', P=25, Q=15))

add bus 4 with a load attached

bus4 = gce.Bus('Bus 4', Vnom=20) grid.addbus(bus4) grid.addload(bus4, gce.Load('load 4', P=40, Q=20))

add bus 5 with a load attached

bus5 = gce.Bus('Bus 5', Vnom=20) grid.addbus(bus5) grid.addload(bus5, gce.Load('load 5', P=50, Q=20))

add Lines connecting the buses

grid.addline(gce.Line(bus1, bus2, name='line 1-2', r=0.05, x=0.11, b=0.02)) grid.addline(gce.Line(bus1, bus3, name='line 1-3', r=0.05, x=0.11, b=0.02)) grid.addline(gce.Line(bus1, bus5, name='line 1-5', r=0.03, x=0.08, b=0.02)) grid.addline(gce.Line(bus2, bus3, name='line 2-3', r=0.04, x=0.09, b=0.02)) grid.addline(gce.Line(bus2, bus5, name='line 2-5', r=0.04, x=0.09, b=0.02)) grid.addline(gce.Line(bus3, bus4, name='line 3-4', r=0.06, x=0.13, b=0.03)) grid.add_line(gce.Line(bus4, bus5, name='line 4-5', r=0.04, x=0.09, b=0.02)) ```

IEEE9

A more complex example comes from the issue 354. In this example we create the IEEE9 bus grid from line and transformer definition information instead of per-unit values:

```python import numpy as np import VeraGridEngine.api as gce

ieee9 grid

grid9 = gce.MultiCircuit('IEEE-9', Sbase=100, fbase=50)

Add the buses

bus1 = gce.Bus(name='Bus 1', Vnom=17.16, is_slack=True) bus2 = gce.Bus(name='Bus 2', Vnom=18.45) bus3 = gce.Bus(name='Bus 3', Vnom=14.145) bus4 = gce.Bus(name='Bus 4', Vnom=230) bus5 = gce.Bus(name='Bus 5', Vnom=230) bus6 = gce.Bus(name='Bus 6', Vnom=230) bus7 = gce.Bus(name='Bus 7', Vnom=230) bus8 = gce.Bus(name='Bus 8', Vnom=230) bus9 = gce.Bus(name='Bus 9', Vnom=230)

grid9.addbus(bus1) grid9.addbus(bus2) grid9.addbus(bus3) grid9.addbus(bus4) grid9.addbus(bus5) grid9.addbus(bus6) grid9.addbus(bus7) grid9.addbus(bus8) grid9.add_bus(bus9)

add generators

grid9.addgenerator(bus1, gce.Generator(name='Slack Generator', P=0.0, vset=1.0)) grid9.addgenerator(bus2, gce.Generator(name='Gen2', P=163, Sbase=100, vset=1.0)) grid9.add_generator(bus3, gce.Generator(name='Gen3', P=85, vset=1.0))

add loads

grid9.addload(bus5, gce.Load(name='Load 1', P=125, Q=50)) grid9.addload(bus6, gce.Load(name='Load 2', P=90, Q=30)) grid9.add_load(bus8, gce.Load(name='Load 3', P=100, Q=35))

add transformers

tr1 = gce.Transformer2W(busfrom=bus4, busto=bus1, name='T1', HV=230, LV=16.5, nominalpower=247.5, rate=247.5, tapphase=150 * np.pi / 180) tr1.filldesignproperties(Pcu=0.0, Pfe=0.0, I0=0.0, Vsc=14.3, Sbase=grid9.Sbase)

tr2 = gce.Transformer2W(busfrom=bus7, busto=bus2, name='T2', HV=230, LV=18, nominalpower=192, rate=192, tapphase=150 * np.pi / 180) tr2.filldesignproperties(Pcu=0.0, Pfe=0.0, I0=0.0, Vsc=12.0, Sbase=grid9.Sbase)

tr3 = gce.Transformer2W(busfrom=bus9, busto=bus3, name='T3', HV=230, LV=13.8, nominalpower=128, rate=128, tapphase=150 * np.pi / 180) tr3.filldesignproperties(Pcu=0.0, Pfe=0.0, I0=0.0, Vsc=7.5, Sbase=grid9.Sbase)

grid9.addtransformer2w(tr1) # 0.5236 => 30#2.618 grid9.addtransformer2w(tr2) # 2.618#2.618#0.5236 grid9.add_transformer2w(tr3) # 0.5236

add lines

l1 = gce.Line(busfrom=bus4, busto=bus5, name='line 4-5') l1.filldesignproperties(rohm=5.3, xohm=45.0, c_nf=1060, length=1.0, Imax=1.0, freq=grid9.fBase, Sbase=grid9.Sbase)

l2 = gce.Line(busfrom=bus4, busto=bus6, name='line 4-6') l2.filldesignproperties(rohm=9.0, xohm=48.7, c_nf=950, length=1.0, Imax=1.0, freq=grid9.fBase, Sbase=grid9.Sbase)

l3 = gce.Line(busfrom=bus5, busto=bus7, name='line 5-7') l3.filldesignproperties(rohm=16.9, xohm=85.2, c_nf=1840, length=1.0, Imax=1.0, freq=grid9.fBase, Sbase=grid9.Sbase)

l4 = gce.Line(busfrom=bus6, busto=bus9, name='line 6-9') l4.filldesignproperties(rohm=20.6, xohm=89.9, c_nf=2150, length=1.0, Imax=1.0, freq=grid9.fBase, Sbase=grid9.Sbase)

l5 = gce.Line(busfrom=bus7, busto=bus8, name='line 7-8') l5.filldesignproperties(rohm=4.5, xohm=38.1, c_nf=870, length=1.0, Imax=1.0, freq=grid9.fBase, Sbase=grid9.Sbase)

l6 = gce.Line(busfrom=bus8, busto=bus9, name='line 8-9') l6.filldesignproperties(rohm=6.3, xohm=53.3, c_nf=1260, length=1.0, Imax=1.0, freq=grid9.fBase, Sbase=grid9.Sbase)

grid9.addline(l1) grid9.addline(l2) grid9.addline(l3) grid9.addline(l4) grid9.addline(l5) grid9.addline(l6)

save (optional)

gce.save_file(grid9, "IEEE9.veragrid")

Power flow

options = gce.PowerFlowOptions(gce.SolverType.NR, retrywithothermethods=False, tolerance=1e-6, controlq=False, controltapsphase=False, controltapsmodules=False, applytemperaturecorrection=False, usestoredguess=False, initialize_angles=True, verbose=False)

powerflow = gce.PowerFlowDriver(grid9, options) powerflow.run()

print the results

resultsDF = powerflow.results.getbus_df() resultsDF['V (kV)'] = resultsDF['Vm'] * np.array([bus.Vnom for bus in grid9.buses]) print(resultsDF) ```

Which yields:

aiignore | | Vm (p.u.) | V(kV) | Va (deg) | P (MW) | Q (MVAr) | |-------|-----------|------------|------------|-------------|------------| | Bus 1 | 1 | 17.16 | 0 | 71.63834 | 27.114476 | | Bus 2 | 1 | 18.45 | 9.277313 | 163.000003 | 6.973044 | | Bus 3 | 1 | 14.145 | 4.657059 | 85.000001 | -10.669872 | | Bus 4 | 1.025709 | 235.91303 | 147.776277 | -0.000009 | 0.000006 | | Bus 5 | 0.995498 | 228.96449 | 146.002536 | -125.000009 | -49.999972 | | Bus 6 | 1.01254 | 232.884245 | 146.305199 | -90.000008 | -29.999988 | | Bus 7 | 1.025576 | 235.882375 | 153.715955 | 0.000034 | 0.000033 | | Bus 8 | 1.015629 | 233.594652 | 150.721498 | -100.000018 | -34.999992 | | Bus 9 | 1.032244 | 237.416038 | 151.959026 | 0.000016 | 0.000008 |

Exactly the same results as the example from the book of the issue.

Power Flow

VeraGrid has the most power flow features in any open-source software. The following table shows the features present in each solver:

| | Newton Raphson |Powell Dog-leg|Levenberg-Marquardt|Iwamoto|Fast-decoupled|Gauss-seidel|Holomorphic embedding|Linear without voltage modules|Linear with voltage modules| |---------------------------------------------------------------------|---|---|---|---|---|---|---|---|---| | Local voltage control using a Generator. | | | | | | | | | | | Remote voltage control using a Generator. | | | | | | | | | | | Generator reactive power limits. | | | | | | | | | | | Local and remote voltage control using a transformer's tap changer. | | | | | | | | | | | Local active power control using a transformer's tap changer. | | | | | | | | | | | Local reactive power control using a transformer's tap changer. | | | | | | | | | | | Local and remote AC and DC voltage control using a converter. | | | | | | | | | | | Local AC and DC active power control using converter. | | | | | | | | | | | Local AC reactive power control using a converter. | | | | | | | | | | | 3-phase unbalanced. | | | | | | | | | |

Using the simplified API:

```python import os import VeraGridEngine as gce

folder = os.path.join('..', 'Gridsandprofiles', 'grids') fname = os.path.join(folder, 'IEEE391W.veragrid') maincircuit = gce.open_file(fname)

results = gce.powerflow(maincircuit)

print(maincircuit.name) print('Converged:', results.converged, 'error:', results.error) print(results.getbusdf()) print(results.getbranch_df()) ```

Using the more complex library objects:

```python import os import VeraGridEngine as gce

folder = os.path.join('..', 'Gridsandprofiles', 'grids') fname = os.path.join(folder, 'IEEE14fromraw.veragrid') maincircuit = gce.openfile(fname)

options = gce.PowerFlowOptions(gce.SolverType.NR, verbose=False) powerflow = gce.PowerFlowDriver(maincircuit, options) power_flow.run()

print(maincircuit.name) print('Converged:', powerflow.results.converged, 'error:', powerflow.results.error) print(powerflow.results.getbusdf()) print(powerflow.results.getbranch_df()) ```

Output:

```text IEEE14fromraw

Converged: True error: 5.98e-08

Bus resuts: Vm Va P Q BUS 1 1.06 0.00 232.39 -16.55 BUS 2 1.04 -4.98 18.30 30.86 BUS 3 1.01 -12.73 -94.20 6.08 BUS 4 1.02 -10.31 -47.80 3.90 BUS 5 1.02 -8.77 -7.60 -1.60 BUS 6 1.07 -14.22 -11.20 5.23 BUS 7 1.06 -13.36 0.00 0.00 BUS 8 1.09 -13.36 0.00 17.62 BUS 9 1.06 -14.94 -29.50 -16.60 BUS 10 1.05 -15.10 -9.00 -5.80 BUS 11 1.06 -14.79 -3.50 -1.80 BUS 12 1.06 -15.08 -6.10 -1.60 BUS 13 1.05 -15.16 -13.50 -5.80 BUS 14 1.04 -16.03 -14.90 -5.00

Branch results: Pf Qf Pt Qt loading Ploss Qloss 121 156.882887 -20.404291 -152.585286 27.676248 15688288652036.908203 4.297600 7.271957 151 75.510380 3.854989 -72.747507 2.229360 7551037982438.064453 2.762872 6.084349 231 73.237578 3.560203 -70.914309 1.602232 7323757808601.912109 2.323269 5.162436 241 56.131495 -1.550352 -54.454837 3.020689 5613149456668.273438 1.676658 1.470337 251 41.516214 1.170996 -40.612460 -2.099032 4151621353697.657715 0.903753 -0.928036 341 -23.285691 4.473114 23.659136 -4.835650 -2328569062725.765625 0.373445 -0.362537 451 -61.158231 15.823642 61.672651 -14.201004 -6115823108351.800781 0.514420 1.622637 6111 7.353277 3.560471 -7.297904 -3.444512 735327693069.753418 0.055373 0.115959 6121 7.786067 2.503414 -7.714258 -2.353959 778606687855.751465 0.071809 0.149455 6131 17.747977 7.216574 -17.535891 -6.798912 1774797671583.112793 0.212085 0.417662 781 -0.000000 -17.162967 0.000000 17.623448 -0.001718 0.000000 0.460481 791 28.074179 5.778690 -28.074179 -4.976621 2807417855964.891602 0.000000 0.802069 9101 5.227551 4.219139 -5.214676 -4.184938 522755058212.680359 0.012875 0.034201 9141 9.426380 3.610007 -9.310226 -3.362932 942638030136.208130 0.116154 0.247075 10111 -3.785324 -1.615061 3.797906 1.644513 -378532426869.186707 0.012581 0.029451 12131 1.614258 0.753959 -1.607959 -0.748260 161425771970.211853 0.006298 0.005698 13141 5.643852 1.747172 -5.589774 -1.637068 564385175482.526855 0.054078 0.110105 471 28.074176 -9.681066 -28.074176 11.384281 2807417645485.176270 0.000000 1.703214 491 16.079758 -0.427611 -16.079758 1.732322 1607975830176.256104 0.000000 1.304711 561 44.087319 12.470682 -44.087319 -8.049520 4408731875605.579102 0.000000 4.421161 ```

Inputs analysis

VeraGrid can perform a summary of the inputs with the InputsAnalysisDriver:

```python import os import VeraGridEngine as gce

folder = os.path.join('..', 'Gridsandprofiles', 'grids') fname = os.path.join(folder, 'IEEE 118 Bus - ntc_areas.veragrid')

maincircuit = gce.openfile(fname)

drv = gce.InputsAnalysisDriver(grid=maincircuit) mdl = drv.results.mdl(gce.ResultTypes.AreaAnalysis) df = mdl.todf()

print(df) ```

The results per area:

text P Pgen Pload Pbatt Pstagen Pmin Pmax Q Qmin Qmax IEEE118-3 -57.0 906.0 963.0 0.0 0.0 -150000.0 150000.0 -345.0 -2595.0 3071.0 IEEE118-2 -117.0 1369.0 1486.0 0.0 0.0 -140000.0 140000.0 -477.0 -1431.0 2196.0 IEEE118-1 174.0 1967.0 1793.0 0.0 0.0 -250000.0 250000.0 -616.0 -3319.0 6510.0

Linear analysis

We can run an PTDF equivalent of the power flow with the linear analysis drivers:

```python import os import VeraGridEngine as gce

folder = os.path.join('..', 'Gridsandprofiles', 'grids') fname = os.path.join(folder, 'IEEE 5 Bus.xlsx')

maincircuit = gce.openfile(fname)

snapshot

results = gce.linearpowerflow(grid=main_circuit)

print("Bus results:\n", results.getbusdf()) print("Branch results:\n", results.getbranchdf()) print("PTDF:\n", results.mdl(gce.ResultTypes.PTDF).todf()) print("LODF:\n", results.mdl(gce.ResultTypes.LODF).todf()) ```

Simulating with a more detailed control of the objects:

```python import os import VeraGridEngine as gce

folder = os.path.join('..', 'Gridsandprofiles', 'grids') fname = os.path.join(folder, 'IEEE 5 Bus.xlsx')

maincircuit = gce.openfile(fname)

options_ = gce.LinearAnalysisOptions(distributeslack=False, correctvalues=True)

snapshot

sndriver = gce.LinearAnalysisDriver(grid=maincircuit, options=options) sndriver.run()

print("Bus results:\n", sndriver.results.getbusdf()) print("Branch results:\n", sndriver.results.getbranchdf()) print("PTDF:\n", sndriver.results.mdl(gce.ResultTypes.PTDF).todf()) print("LODF:\n", sndriver.results.mdl(gce.ResultTypes.LODF).todf()) ```

Output:

```text Bus results: Vm Va P Q Bus 0 1.0 0.0 2.1000 0.0 Bus 1 1.0 0.0 -3.0000 0.0 Bus 2 1.0 0.0 0.2349 0.0 Bus 3 1.0 0.0 -0.9999 0.0 Bus 4 1.0 0.0 4.6651 0.0

Branch results: Pf loading Branch 0-1 2.497192 0.624298 Branch 0-3 1.867892 0.832394 Branch 0-4 -2.265084 -0.828791 Branch 1-2 -0.502808 -0.391900 Branch 2-3 -0.267908 -0.774300 Branch 3-4 -2.400016 -1.000006

PTDF: Bus 0 Bus 1 Bus 2 Bus 3 Bus 4 Branch 0-1 0.193917 -0.475895 -0.348989 0.0 0.159538 Branch 0-3 0.437588 0.258343 0.189451 0.0 0.360010 Branch 0-4 0.368495 0.217552 0.159538 0.0 -0.519548 Branch 1-2 0.193917 0.524105 -0.348989 0.0 0.159538 Branch 2-3 0.193917 0.524105 0.651011 0.0 0.159538 Branch 3-4 -0.368495 -0.217552 -0.159538 0.0 -0.480452

LODF: Branch 0-1 Branch 0-3 Branch 0-4 Branch 1-2 Branch 2-3 Branch 3-4 Branch 0-1 -1.000000 0.344795 0.307071 -1.000000 -1.000000 -0.307071 Branch 0-3 0.542857 -1.000000 0.692929 0.542857 0.542857 -0.692929 Branch 0-4 0.457143 0.655205 -1.000000 0.457143 0.457143 1.000000 Branch 1-2 -1.000000 0.344795 0.307071 -1.000000 -1.000000 -0.307071 Branch 2-3 -1.000000 0.344795 0.307071 -1.000000 -1.000000 -0.307071 Branch 3-4 -0.457143 -0.655205 1.000000 -0.457143 -0.457143 -1.000000 ```

Linear vs non-linear analysis comparison

Now let's make a comparison between the linear flows and the non-linear flows from Newton-Raphson:

```python import os from matplotlib import pyplot as plt import VeraGridEngine as gce

plt.style.use('fivethirtyeight')

folder = os.path.join('..', 'Gridsandprofiles', 'grids') fname = os.path.join(folder, 'IEEE391W.veragrid') maincircuit = gce.open_file(fname)

ptdfdriver = gce.LinearAnalysisTimeSeriesDriver(grid=maincircuit) ptdf_driver.run()

pfoptions = gce.PowerFlowOptions(solvertype=gce.SolverType.NR) tsdriver = gce.PowerFlowTimeSeriesDriver(grid=maincircuit, options=pfoptions) tsdriver.run()

fig = plt.figure(figsize=(30, 6)) ax1 = fig.addsubplot(131) ax1.settitle('Newton-Raphson based flow') ax1.plot(tsdriver.results.Sf.real) ax1.setylabel('MW') ax1.set_xlabel('Time')

ax2 = fig.addsubplot(132) ax2.settitle('PTDF based flow') ax2.plot(ptdfdriver.results.Sf.real) ax2.setylabel('MW') ax2.set_xlabel('Time')

ax3 = fig.addsubplot(133) ax3.settitle('Difference') diff = tsdriver.results.Sf.real - ptdfdriver.results.Sf.real ax3.plot(diff) ax3.setylabel('MW') ax3.setxlabel('Time')

fig.settightlayout(tight=True)

plt.show() ```

PTDF flows comparison.png

Linear optimization

```python import os import numpy as np import VeraGridEngine as gce

folder = os.path.join('..', 'Gridsandprofiles', 'grids') fname = os.path.join(folder, 'IEEE39_1W.veragrid')

maincircuit = gce.openfile(fname)

declare the snapshot opf

opfoptions = gce.OptimalPowerFlowOptions(mipsolver=gce.MIPSolvers.HIGHS) opfdriver = gce.OptimalPowerFlowDriver(grid=maincircuit, options=opf_options)

print('Solving...') opf_driver.run()

print("Status:", opfdriver.results.converged) print('Angles\n', np.angle(opfdriver.results.voltage)) print('Branch loading\n', opfdriver.results.loading) print('Gen power\n', opfdriver.results.generatorpower) print('Nodal prices \n', opfdriver.results.busshadowprices)

declare the time series opf

opftsdriver = gce.OptimalPowerFlowTimeSeriesDriver(grid=main_circuit)

print('Solving...') opftsdriver.run()

print("Status:", opftsdriver.results.converged) print('Angles\n', np.angle(opftsdriver.results.voltage)) print('Branch loading\n', opftsdriver.results.loading) print('Gen power\n', opftsdriver.results.generatorpower) print('Nodal prices \n', opftsdriver.results.busshadow_prices) ```

Run a linear optimization and verify with power flow

Often ties, you want to dispatch the generation using a linear optimization, to then verify the results using the power exact power flow. With VeraGrid, to do so is as easy as passing the results of the OPF into the PowerFlowDriver:

```python import os import VeraGridEngine as gce

folder = os.path.join('..', 'Gridsandprofiles', 'grids') fname = os.path.join(folder, 'IEEE39_1W.veragrid')

maincircuit = gce.openfile(fname)

declare the snapshot opf

opfdriver = gce.OptimalPowerFlowDriver(grid=maincircuit) opf_driver.run()

create the power flow driver, with the OPF results

pfoptions = gce.PowerFlowOptions(solvertype=gce.SolverType.NR) pfdriver = gce.PowerFlowDriver(grid=maincircuit, options=pfoptions, opfresults=opfdriver.results) pfdriver.run()

Print results

print('Converged:', pfdriver.results.converged, '\nError:', pfdriver.results.error) print(pfdriver.results.getbusdf()) print(pfdriver.results.getbranchdf()) ```

Output:

text Converged: True Error: 5.553046023010211e-09 Vm Va P Q bus 0 1.027155 -21.975050 -97.600000 -44.200000 bus 1 1.018508 -17.390151 -0.000000 0.000000 bus 2 0.979093 -21.508225 -322.000000 -2.400000 bus 3 0.934378 -19.864840 -500.000000 -184.000000 bus 4 0.931325 -16.488297 -0.000000 0.000000 bus 5 0.932254 -15.184820 -0.000000 0.000000 bus 6 0.925633 -18.287327 -233.800000 -84.000000 bus 7 0.927339 -19.147130 -522.000000 -176.600000 bus 8 1.008660 -21.901696 -6.500000 66.600000 bus 9 0.933232 -12.563826 0.000000 0.000000 bus 10 0.931530 -13.489535 0.000000 -0.000000 bus 11 0.911143 -13.919901 -8.530000 -88.000000 bus 12 0.932956 -14.194410 -0.000000 0.000000 bus 13 0.939456 -18.071831 95.000000 80.000000 bus 14 0.947946 -24.501201 -320.000000 -153.000000 bus 15 0.969547 -25.398839 -329.000000 -32.300000 bus 16 0.975073 -24.329289 -0.000000 0.000000 bus 17 0.974923 -23.729596 -158.000000 -30.000000 bus 18 0.978267 -32.658992 0.000000 -0.000000 bus 19 0.976962 -38.320718 -680.000000 -103.000000 bus 20 0.975875 -21.466364 -274.000000 -115.000000 bus 21 1.005675 -15.328363 0.000000 0.000000 bus 22 1.005660 -16.083736 -247.500000 -84.600000 bus 23 0.977732 -24.971264 -308.600000 92.200000 bus 24 1.008485 -18.545657 -224.000000 -47.200000 bus 25 1.000534 -20.462156 -139.000000 -17.000000 bus 26 0.981806 -23.507873 -281.000000 -75.500000 bus 27 1.008509 -15.740313 -206.000000 -27.600000 bus 28 1.012968 -12.490634 -283.500000 -26.900000 bus 29 1.049900 -8.627698 900.000000 251.046579 bus 30 0.982000 0.000000 959.172868 323.252930 bus 31 0.945335 -0.791018 900.000000 150.000000 bus 32 0.997200 -32.044975 80.000000 129.407620 bus 33 1.006817 -38.408267 0.000000 167.000000 bus 34 1.039299 -8.255317 900.000000 300.000000 bus 35 1.060037 -8.077926 550.259634 240.000000 bus 36 1.027500 -16.918435 128.970365 82.680976 bus 37 1.026500 -4.776516 900.000000 103.207961 bus 38 1.030000 -23.362551 -204.000000 6.956520 Pf Qf Pt Qt loading Ploss Qloss branch 0 -199.490166 9.886924 200.882852 -66.631030 -33.248361 1.392685 -56.744105 branch 1 101.890166 -54.086924 -101.789768 -22.751166 10.189017 0.100398 -76.838090 branch 2 494.939507 226.957177 -491.146020 -208.562681 98.987901 3.793487 18.394496 branch 3 204.177641 -52.633324 -201.227524 41.260633 40.835528 2.950117 -11.372692 branch 4 -900.000000 -107.692823 900.000000 251.046579 -100.000000 0.000000 143.353757 branch 5 -110.112636 203.416014 110.898270 -210.820460 -22.022527 0.785633 -7.404446 branch 6 279.258656 2.746666 -278.361852 -12.311738 55.851731 0.896804 -9.565072 branch 7 -396.736291 53.024640 398.210339 -41.118140 -66.122715 1.474048 11.906501 branch 8 -214.161979 -26.204180 214.585979 20.909705 -42.832396 0.424000 -5.294474 branch 9 -757.052621 31.704768 758.376760 -18.259085 -63.087718 1.324139 13.445683 branch 10 358.842282 9.413372 -357.652308 -5.501385 39.871365 1.189974 3.911986 branch 11 510.748653 42.617618 -508.932128 -24.515536 56.749850 1.816525 18.102081 branch 12 -309.952545 33.292523 310.738787 -36.144659 -64.573447 0.786242 -2.852137 branch 13 -959.172868 -57.651055 959.172868 323.252930 -53.287382 -0.000000 265.601874 branch 14 275.132128 -59.484464 -274.764014 57.022428 30.570236 0.368114 -2.462036 branch 15 110.416322 -228.121043 -108.890865 216.489512 12.268480 1.525457 -11.631531 branch 16 102.390865 -149.889512 -102.210232 29.707685 11.376763 0.180633 -120.181827 branch 17 327.473237 5.932303 -326.980326 -6.970962 54.578873 0.492911 -1.038659 branch 18 572.526763 -42.245014 -571.014280 52.157064 95.421127 1.512483 9.912050 branch 19 -900.000000 36.312711 900.000000 150.000000 -100.000000 0.000000 186.312711 branch 20 -16.202399 -42.051495 16.241539 43.115621 -3.240480 0.039140 1.064126 branch 21 7.672399 -45.948505 -7.630574 47.085615 1.534480 0.041825 1.137109 branch 22 578.644854 -99.242678 -575.095683 123.970310 96.440809 3.549172 24.727632 branch 23 455.509704 -64.880015 -451.229578 83.883725 75.918284 4.280126 19.003709 branch 24 131.229578 -236.883725 -130.530951 228.460261 21.871596 0.698627 -8.423463 branch 25 -201.616968 -48.791645 201.933110 40.123973 -33.602828 0.316142 -8.667672 branch 26 610.218277 -68.716891 -603.829849 117.741029 101.703046 6.388428 49.024138 branch 27 -480.680339 -12.436131 482.646709 21.510035 -80.113390 1.966370 9.073904 branch 28 -126.390019 -130.815594 126.492978 126.394116 -21.065003 0.102959 -4.421477 branch 29 -120.254199 6.410659 120.361852 -17.688262 -20.042367 0.107653 -11.277602 branch 30 -81.678911 -46.534633 81.783480 17.137675 -13.613152 0.104569 -29.396957 branch 31 683.666914 8.361328 -680.247614 59.047728 75.962990 3.419300 67.409057 branch 32 -79.837065 -126.102358 80.000000 129.407620 -8.870785 0.162935 3.305263 branch 33 0.247614 -162.047728 0.000000 167.000000 0.027513 0.247614 4.952272 branch 34 -756.646709 -136.510035 761.585858 197.760507 -84.071857 4.939149 61.250472 branch 35 138.414142 -16.911352 -138.300144 0.065486 23.069024 0.113998 -16.845866 branch 36 -900.000000 -180.849155 900.000000 300.000000 -100.000000 0.000000 119.150845 branch 37 439.456180 68.098749 -435.092978 -34.194116 73.242697 4.363202 33.904632 branch 38 -548.656035 -152.764235 550.259634 240.000000 -60.961782 1.603599 87.235765 branch 39 106.064510 -10.937025 -105.702431 -38.989055 17.677418 0.362078 -49.926080 branch 40 -128.836985 -77.523608 128.970365 82.680976 -14.315221 0.133380 5.157368 branch 41 364.790468 90.170222 -362.783480 -92.637675 60.798411 2.006988 -2.467453 branch 42 -174.673027 -32.815129 175.985257 -31.448155 -29.112171 1.312230 -64.263284 branch 43 -223.415010 -35.366038 226.271920 -37.606217 -37.235835 2.856910 -72.972254 branch 44 -381.985257 3.848155 383.997464 -7.582852 -63.664210 2.012206 -3.734697 branch 45 -893.769383 18.289069 900.000000 103.207961 -74.480782 6.230617 121.497030

Hydro linear OPF

The following example loads and runs the linear optimization for a system that integrates fluid elements into a regular electrical grid.

```python import os import VeraGridEngine as gce

folder = os.path.join('..', 'Gridsandprofiles', 'grids') fname = os.path.join(folder, 'hydrosimple.veragrid') grid = gce.openfile(fname)

Run the simulation

opf_driver = gce.OptimalPowerFlowTimeSeriesDriver(grid=grid)

print('Solving...') opf_driver.run()

print('Gen power\n', opfdriver.results.generatorpower) print('Branch loading\n', opfdriver.results.loading) print('Reservoir level\n', opfdriver.results.fluidnodecurrent_level) ```

Output:

```text OPF results:

time | p2x1gen | pump1gen | turbine1gen | slack_gen ------------------- | --------- | ---------- | ------------- | --------- 2023-01-01 00:00:00 | 0.0 | -6.8237821 | 6.0 | 11.823782 2023-01-01 01:00:00 | 0.0 | -6.8237821 | 6.0 | 11.823782 2023-01-01 02:00:00 | 0.0 | -6.8237821 | 6.0 | 11.823782 2023-01-01 03:00:00 | 0.0 | -6.8237821 | 6.0 | 11.823782 2023-01-01 04:00:00 | 0.0 | -6.8237821 | 6.0 | 11.823782 2023-01-01 05:00:00 | 0.0 | -6.8237821 | 6.0 | 11.823782 2023-01-01 06:00:00 | 0.0 | -6.8237821 | 6.0 | 11.823782 2023-01-01 07:00:00 | 0.0 | -6.8237821 | 6.0 | 11.823782 2023-01-01 08:00:00 | 0.0 | -6.8237821 | 6.0 | 11.823782 2023-01-01 09:00:00 | 0.0 | -6.8237821 | 6.0 | 11.823782

time | line1 | line2 | line3 | line4 ------------------- | ------ | ----- | --------- | ----- 2023-01-01 00:00:00 | 100.0 | 0.0 | 68.237821 | 40.0 2023-01-01 01:00:00 | 100.0 | 0.0 | 68.237821 | 40.0 2023-01-01 02:00:00 | 100.0 | 0.0 | 68.237821 | 40.0 2023-01-01 03:00:00 | 100.0 | 0.0 | 68.237821 | 40.0 2023-01-01 04:00:00 | 100.0 | 0.0 | 68.237821 | 40.0 2023-01-01 05:00:00 | 100.0 | 0.0 | 68.237821 | 40.0 2023-01-01 06:00:00 | 100.0 | 0.0 | 68.237821 | 40.0 2023-01-01 07:00:00 | 100.0 | 0.0 | 68.237821 | 40.0 2023-01-01 08:00:00 | 100.0 | 0.0 | 68.237821 | 40.0 2023-01-01 09:00:00 | 100.0 | 0.0 | 68.237821 | 40.0

time | f1 | f2 | f3 | f4
------------------- | ---------- | --- | --- | ---------- 2023-01-01 00:00:00 | 49.998977 | 0.0 | 0.0 | 50.001022 2023-01-01 01:00:00 | 49.997954 | 0.0 | 0.0 | 50.002046 2023-01-01 02:00:00 | 49.996931 | 0.0 | 0.0 | 50.003068 2023-01-01 03:00:00 | 49.995906 | 0.0 | 0.0 | 50.004093 2023-01-01 04:00:00 | 49.994884 | 0.0 | 0.0 | 50.005116 2023-01-01 05:00:00 | 49.993860 | 0.0 | 0.0 | 50.006139 2023-01-01 06:00:00 | 49.992838 | 0.0 | 0.0 | 50.007162 2023-01-01 07:00:00 | 49.991814 | 0.0 | 0.0 | 50.008185 2023-01-01 08:00:00 | 49.990792 | 0.0 | 0.0 | 50.009208 2023-01-01 09:00:00 | 49.989768 | 0.0 | 0.0 | 50.010231 ```

Short circuit

VeraGrid has unbalanced short circuit calculations. Now let's run a line-ground short circuit in the third bus of the South island of New Zealand grid example from reference book Computer Analysis of Power Systems by J. Arrillaga and C.P. Arnold

```python import os import VeraGridEngine as gce

folder = os.path.join('..', 'Gridsandprofiles', 'grids') fname = os.path.join(folder, 'South Island of New Zealand.veragrid')

grid = gce.open_file(filename=fname)

Define fault index explicitly

fault_index = 2

Run a Line-Ground short circuit on the bus at index 2

Since we do not provide any power flow results, it will run one for us

results = gce.shortcircuit(grid, faultindex, fault_type=gce.FaultType.LG)

print("Short circuit power: ", results.SCpower[fault_index]) ```

A more elaborated way to run the simulation, controlling all the steps:

```python import os import VeraGridEngine as gce

folder = os.path.join('..', 'Gridsandprofiles', 'grids') fname = os.path.join(folder, 'South Island of New Zealand.veragrid')

grid = gce.open_file(filename=fname)

pfoptions = gce.PowerFlowOptions() pf = gce.PowerFlowDriver(grid, pfoptions) pf.run()

faultindex = 2 scoptions = gce.ShortCircuitOptions(busindex=faultindex, fault_type=gce.FaultType.LG)

sc = gce.ShortCircuitDriver(grid, options=scoptions, pfoptions=pfoptions, pfresults=pf.results) sc.run()

print("Short circuit power: ", sc.results.SCpower[fault_index]) ```

Output:

text Short circuit power: -217.00 MW - 680.35j MVAr

Sequence voltage, currents and powers are also available.

Continuation power flow

VeraGrid can run continuation power flows (voltage collapse studies)

```python import os from matplotlib import pyplot as plt import VeraGridEngine as gce

plt.style.use('fivethirtyeight')

folder = os.path.join('..', 'Gridsandprofiles', 'grids') fname = os.path.join(folder, 'South Island of New Zealand.veragrid')

open the grid file

maincircuit = gce.openfile(fname)

Run the continuation power flow with the default options

Since we do not provide any power flow results, it will run one for us

results = gce.continuationpowerflow(grid=maincircuit, factor=2.0, stopat=gce.CpfStopAt.Full)

plot the results

fig = plt.figure(figsize=(18, 6))

ax1 = fig.add_subplot(121) res = results.mdl(gce.ResultTypes.BusActivePower) res.plot(ax=ax1)

ax2 = fig.add_subplot(122) res = results.mdl(gce.ResultTypes.BusVoltageModule) res.plot(ax=ax2)

plt.tight_layout()

plt.show() ```

A more elaborated way to run the simulation, controlling all the steps:

```python import os from matplotlib import pyplot as plt import VeraGridEngine as gce

plt.style.use('fivethirtyeight')

folder = os.path.join('..', 'Gridsandprofiles', 'grids') fname = os.path.join(folder, 'South Island of New Zealand.veragrid')

open the grid file

main_circuit = gce.FileOpen(fname).open()

we need to initialize with a power flow solution

pfoptions = gce.PowerFlowOptions() powerflow = gce.PowerFlowDriver(grid=maincircuit, options=pfoptions) power_flow.run()

declare the CPF options

vcoptions = gce.ContinuationPowerFlowOptions(step=0.001, approximationorder=gce.CpfParametrization.ArcLength, adaptstep=True, stepmin=0.00001, stepmax=0.2, errortol=1e-3, tol=1e-6, maxit=20, stopat=gce.CpfStopAt.Full, verbose=False)

We compose the target direction

factor = 2.0 basepower = powerflow.results.Sbus / maincircuit.Sbase vcinputs = gce.ContinuationPowerFlowInput(Sbase=basepower, Vbase=powerflow.results.voltage, Starget=base_power * factor)

declare the CPF driver and run

vc = gce.ContinuationPowerFlowDriver(grid=maincircuit, options=vcoptions, inputs=vcinputs, pfoptions=pf_options) vc.run()

plot the results

fig = plt.figure(figsize=(18, 6))

ax1 = fig.add_subplot(121) res = vc.results.mdl(gce.ResultTypes.BusActivePower) res.plot(ax=ax1)

ax2 = fig.add_subplot(122) res = vc.results.mdl(gce.ResultTypes.BusVoltageModule) res.plot(ax=ax2)

plt.tight_layout()

plt.show() ```

cpf_south_island_new_zealand.png

Contingency analysis

GriCal has contingency simulations, and it features a quite flexible way of defining contingencies. Firs you define a contingency group, and then define individual events that are assigned to that contingency group. The simulation then tries all the contingency groups and apply the events registered in each group:

```python import os import VeraGridEngine as gce

folder = os.path.join('Gridsandprofiles', 'grids') fname = os.path.join(folder, 'IEEE 5 Bus.xlsx')

maincircuit = gce.openfile(fname)

branches = maincircuit.getbranches()

manually generate the contingencies

for i, br in enumerate(branches): # add a contingency group group = gce.ContingencyGroup(name="contingency {}".format(i + 1)) maincircuit.addcontingency_group(group)

# add the branch contingency to the groups, only groups are failed at once
con = gce.Contingency(device=br, name=br.name, group=group)
main_circuit.add_contingency(con)

add a special contingency

group = gce.ContingencyGroup(name="Special contingency") maincircuit.addcontingencygroup(group) maincircuit.addcontingency(gce.Contingency(device=branches[3], name=branches[3].name, group=group)) maincircuit.add_contingency(gce.Contingency(device=branches[5], name=branches[5].name, group=group))

pfoptions = gce.PowerFlowOptions(solvertype=gce.SolverType.NR)

declare the contingency options

options_ = gce.ContingencyAnalysisOptions(useprovidedflows=False, Pf=None, contingencymethod=gce.ContingencyMethod.PowerFlow, # if no power flow options are provided # a linear power flow is used pfoptions=pf_options)

Get all the defined contingency groups from the circuit

contingencygroups = maincircuit.getcontingencygroups()

Pass the list of contingency groups as required

linearmultiplecontingencies = gce.LinearMultiContingencies(grid=maincircuit, contingencygroupsused=contingencygroups)

simulation = gce.ContingencyAnalysisDriver(grid=maincircuit, options=options, linearmultiplecontingencies=linearmultiplecontingencies)

simulation.run()

print results

df = simulation.results.mdl(gce.ResultTypes.BranchActivePowerFrom).to_df() print("Contingency flows:\n", df)

```

Output:

```text Contingency flows: Branch 0-1 Branch 0-3 Branch 0-4 Branch 1-2 Branch 2-3 Branch 3-4

contingency 1 0.000000 322.256814 -112.256814 -300.000000 -277.616985 -350.438026

contingency 2 314.174885 0.000000 -104.174887 11.387545 34.758624 -358.359122

contingency 3 180.382705 29.617295 0.000000 -120.547317 -97.293581 -460.040537

contingency 4 303.046401 157.540574 -250.586975 0.000000 23.490000 -214.130663

contingency 5 278.818887 170.710914 -239.529801 -23.378976 0.000000 -225.076976

contingency 6 323.104522 352.002620 -465.107139 20.157096 43.521763 0.000000

Special contingency 303.046401 372.060738 -465.107139 0.000000 23.490000 0.000000

```

This simulation can also be done for time series.

Contingency analysis time series

To perform the contingency analysis of a time series, it's easier to directly usi the API:

```python import os import VeraGridEngine as gce

folder = os.path.join('Gridsandprofiles', 'grids') fname = os.path.join(folder, 'IEEE391W.veragrid') maincircuit = gce.open_file(fname)

results = gce.contingenciests(circuit=maincircuit, detailedmassivereport=False, contingencydeadband=0.0, contingencymethod=gce.ContingencyMethod.PowerFlow) ```

Note that the grid must have the declared contingencies saved already. Also note that the results are statistics, and you will not get a cube because for large grids that demands terabytes of RAM memory.

State estimation

Now lets program the example from the state estimation reference book State Estimation in Electric Power Systems by A. Monticelli.

```python import VeraGridEngine as gce

m_circuit = gce.MultiCircuit()

b1 = gce.Bus('B1', is_slack=True) b2 = gce.Bus('B2') b3 = gce.Bus('B3')

br1 = gce.Line(b1, b2, name='Br1', r=0.01, x=0.03, rate=100.0) br2 = gce.Line(b1, b3, name='Br2', r=0.02, x=0.05, rate=100.0) br3 = gce.Line(b2, b3, name='Br3', r=0.03, x=0.08, rate=100.0)

add measurements

mcircuit.addpfmeasurement(gce.PfMeasurement(0.888, 0.008, br1)) mcircuit.addpfmeasurement(gce.PfMeasurement(1.173, 0.008, br2))

mcircuit.addqfmeasurement(gce.QfMeasurement(0.568, 0.008, br1)) mcircuit.addqfmeasurement(gce.QfMeasurement(0.663, 0.008, br2))

mcircuit.addpimeasurement(gce.PiMeasurement(-0.501, 0.01, b2)) mcircuit.addqimeasurement(gce.QiMeasurement(-0.286, 0.01, b2))

mcircuit.addvmmeasurement(gce.VmMeasurement(1.006, 0.004, b1)) mcircuit.addvmmeasurement(gce.VmMeasurement(0.968, 0.004, b2))

mcircuit.addbus(b1) mcircuit.addbus(b2) mcircuit.addbus(b3)

mcircuit.addline(br1) mcircuit.addline(br2) mcircuit.addline(br3)

Declare the simulation driver and run

se = gce.StateEstimation(circuit=m_circuit) se.run()

print(se.results.getbusdf()) print(se.results.getbranchdf()) ```

Output:

```text Vm Va P Q B1 0.999629 0.000000 2.064016 1.22644 B2 0.974156 -1.247547 0.000000 0.00000 B3 0.943890 -2.745717 0.000000 0.00000

        Pf        Qf          Pt         Qt    loading    Ploss    Qloss

Br1 89.299199 55.882169 -88.188659 -52.550550 89.299199 1.110540 3.331619 Br2 117.102446 66.761871 -113.465724 -57.670065 117.102446 3.636722 9.091805 Br3 38.591163 22.775597 -37.956374 -21.082828 38.591163 0.634789 1.692770 ```

Export the results

A simple function is available to export the results of a driver.

```python import os import VeraGridEngine as gce

fname = os.path.join("data", "grids", "IEEE391W.veragrid") grid = gce.openfile(fname)

create the driver

pfdriver = gce.PowerFlowTimeSeriesDriver(grid=grid, options=gce.PowerFlowOptions(), timeindices=grid.getalltime_indices())

run

pf_driver.run()

Save the driver results in a zip file with CSV files inside

gce.exportdrivers(driverslist=[pfdriver], filename="IEEE391Wresults.zip") ```

You could save many drivers in the same zip file passing then into the list drivers_list.

Also there is a function to save from the results objects themselves:

```python import os import VeraGridEngine as gce

fname = os.path.join("data", "grids", "IEEE391W.veragrid") grid = gce.openfile(fname)

run with the API shortcut functions

pfresults = gce.powerflow(grid) pftsresults = gce.powerflowts(grid)

Save the driver results in a zip file with CSV files inside

gce.exportresults(resultslist=[pfresults, pftsresults], filename="IEEE391Wresults.zip") ```

Client - Server operation

To use the veragrid server, you need to install the VeraGridServer python package. Once this is done, the veragridservercommand will be available on the system. To launch the server, simply type veragridserver. This will launch a VeraGrid server on the machine, on port 8000. This is https://localhost:8000

An example on how to send a grid from a script to the server:

```python import os import asyncio import VeraGridEngine as gce

path to your file

fname = os.path.join('..', '..', '..', 'Gridsandprofiles', 'grids', "IEEE57.veragrid")

read veragrid file

grid_ = gce.open_file(fname)

define instruction for the server

instruction = gce.RemoteInstruction(operation=gce.SimulationTypes.NoSim)

generate json to send

modeldata = gce.gathermodelasjsonsforcommunication(circuit=grid_, instruction=instruction)

get the sever certificate

gce.getcertificate(baseurl="https://localhost:8000", certificatepath=gce.getcertificate_path(), pwd="")

send json

replyfromserver = asyncio.geteventloop().rununtilcomplete( gce.sendjsondata(jsondata=modeldata, endpointurl="https://localhost:8000/upload", certificate=gce.getcertificate_path()) )

print(replyfromserver) ```

Tests

VeraGrid uses pytest for automatic software testing.

If you make changes to VeraGrid that you plan to submit, first make sure that all tests are still passing. You can do this locally with pytest.

If you have added new functionality, you should also add a new function that tests this functionality. pytest automatically detects all functions in the src/tests folder that start with test_ and are located in a file that also starts with test_ as relevant test cases. Unit test (for pytest) are included in src/tests. As defined in pytest.ini, all files matching test_*.py are executed by running pytest.

Files matching *_test.py are not executed; they were not formatted specifically for pytest but were mostly done for manual testing and documentation purposes.

Additional tests should be developed for each new and existing feature. pytest should be run before each commit to prevent easily detectable bugs.

Bug reporting

You have found a bug in VeraGrid or have a suggestion for a new functionality? Then get in touch with us by opening up an issue on the issue board to discuss possible new developments with the community and the maintainers.

Contributing

All contributions to the VeraGrid repository are made through pull requests to the devel branch. You can either submit a pull request from the develop branch of your fork or create a special feature branch that you keep the changes on. A feature branch is the way to go if you have multiple issues that you are working on in parallel and want to submit with separate pull requests. If you only have small, one-time changes to submit, you can also use the devel branch to submit your pull request.

However, it is best to discuss your contribution before the pull request is ready to be officially submitted. We only accept high quality contributions that align with the project design. Those are heavily reviewed, and you may expect joint work with us if your proposal is deemed good enough.

An easier alternative to contribute is to use the VeraGrid objects and functions to produce your contribution in a script-like fashion. Again, if that meets the functional and quality standards that we impose, we'll take care of the integration.

Contributions like a typo fixes must be addressed via issues since we don't allow those as pull requests.

All contributions must come with testing.

Contact

License

VeraGrid is licensed under the Mozilla Public License 2.0 (MPLv2)

In practical terms this means that:

  • You can use VeraGrid for commercial work.
  • You can sell commercial services based on VeraGrid.
  • If you distribute VeraGrid, you don't need to distribute VeraGrid's source code. However, with python in practice you do.
  • VeraGrid license does not propagate, even if you use VeraGrid or pieces of it in your code. However, you must retain the individual files licensing.

Nonetheless, read the license carefully.

Disclaimer

All trademarks mentioned in the documentation or the source code belong to their respective owners.

Owner

  • Name: Santiago Peñate Vera
  • Login: SanPen
  • Kind: user
  • Location: Madrid / Las Palmas
  • Company: Red Eléctrica de España (Spanish TSO)

Power systems researcher

GitHub Events

Total
  • Create event: 3
  • Issues event: 3
  • Release event: 1
  • Watch event: 2
  • Delete event: 18
  • Issue comment event: 3
  • Push event: 43
  • Fork event: 2
Last Year
  • Create event: 4
  • Issues event: 3
  • Release event: 1
  • Watch event: 2
  • Delete event: 18
  • Issue comment event: 6
  • Push event: 46
  • Fork event: 2

Issues and Pull Requests

Last synced: 6 months ago

All Time
  • Total issues: 6
  • Total pull requests: 0
  • Average time to close issues: 1 day
  • Average time to close pull requests: N/A
  • Total issue authors: 4
  • Total pull request authors: 0
  • Average comments per issue: 1.83
  • Average comments per pull request: 0
  • Merged pull requests: 0
  • Bot issues: 0
  • Bot pull requests: 0
Past Year
  • Issues: 6
  • Pull requests: 0
  • Average time to close issues: 1 day
  • Average time to close pull requests: N/A
  • Issue authors: 4
  • Pull request authors: 0
  • Average comments per issue: 1.83
  • Average comments per pull request: 0
  • Merged pull requests: 0
  • Bot issues: 0
  • Bot pull requests: 0
Top Authors
Issue Authors
  • SanPen (2)
  • Carlos-Alegre (2)
  • alexblancoeroots (1)
  • AnkurArohi (1)
Pull Request Authors
Top Labels
Issue Labels
Pull Request Labels

Packages

  • Total packages: 3
  • Total downloads:
    • pypi 1,886 last-month
  • Total dependent packages: 0
    (may contain duplicates)
  • Total dependent repositories: 0
    (may contain duplicates)
  • Total versions: 24
  • Total maintainers: 2
pypi.org: veragrid

VeraGrid is a Power Systems simulation program intended for professional use and research

  • Versions: 8
  • Dependent Packages: 0
  • Dependent Repositories: 0
  • Downloads: 630 Last month
Rankings
Dependent packages count: 8.6%
Average: 28.6%
Dependent repos count: 48.7%
Maintainers (2)
Last synced: 6 months ago
pypi.org: veragridengine

VeraGrid is a Power Systems simulation program intended for professional use and research

  • Versions: 8
  • Dependent Packages: 0
  • Dependent Repositories: 0
  • Downloads: 709 Last month
Rankings
Dependent packages count: 8.6%
Average: 28.6%
Dependent repos count: 48.7%
Maintainers (2)
Last synced: 6 months ago
pypi.org: veragridserver

VeraGrid is a Power Systems simulation program intended for professional use and research

  • Versions: 8
  • Dependent Packages: 0
  • Dependent Repositories: 0
  • Downloads: 547 Last month
Rankings
Dependent packages count: 8.6%
Average: 28.6%
Dependent repos count: 48.7%
Maintainers (2)
Last synced: 6 months ago

Dependencies

.github/workflows/pylint.yml actions
  • actions/checkout v3 composite
  • actions/setup-python v3 composite
doc/requirements.txt pypi
  • GridCalEngine >=5.3.41
  • linkify-it-py *
  • myst-parser *
  • pandas *
  • pytablewriter *
  • sphinx *
  • sphinx-rtd-theme *
requirements-dev.txt pypi
  • Cython * development
  • mpi4py >=3.0.1 development
  • nptyping * development
  • sphinx >=2.0.1 development
  • sphinx-rtd-theme >=0.4.3 development
requirements.txt pypi
  • PySide6 <=6.7.2
  • autograd >=1.7.0
  • chardet >=3.0.4
  • cryptography *
  • fastapi *
  • fastparquet >=2024
  • geopy >=1.16
  • h5py >=3.12
  • highspy >=1.8.0
  • matplotlib >=2.1.1
  • networkx >=2.1
  • nose >=1.3
  • numba >=0.61
  • numpy >=2.2.0
  • opencv-python >=4.10.0.84
  • openpyxl >=2.4.9
  • packaging *
  • pandas >=2.2.3
  • pvlib >=0.11
  • pyarrow >=18.0
  • pymoo *
  • pyproj *
  • pytest >=7.2.0
  • rdflib *
  • requests *
  • scikit-learn >=1.5.0
  • scipy >=1.0.0
  • setuptools *
  • starlette >=0.46.2
  • urllib3 *
  • uvicorn *
  • websockets *
  • windpowerlib >=0.2.2
  • xlrd >=1.1.0
  • xlwt >=1.3.0
requirements_nose.txt pypi
  • Jinja2 ==3.1.6
  • MarkupSafe ==1.1.1
  • POAP ==0.1.26
  • Pillow >=8.1.2
  • PySide2 ==5.15.2
  • Pygments ==2.15.0
  • QtPy ==1.9.0
  • attrs ==20.3.0
  • backcall ==0.2.0
  • branca ==0.4.2
  • certifi ==2024.7.4
  • chardet ==4.0.0
  • cycler ==0.10.0
  • decorator ==4.4.2
  • dill ==0.3.3
  • et-xmlfile ==1.0.1
  • folium ==0.12.1
  • geographiclib ==1.50
  • geopy ==2.1.0
  • h5py ==3.1.0
  • idna ==3.7
  • iniconfig ==1.1.1
  • ipykernel ==5.4.3
  • ipython >=7.16
  • ipython-genutils ==0.2.0
  • jdcal ==1.4.1
  • jedi ==0.18.0
  • joblib ==1.2.0
  • jupyter-client ==6.1.11
  • jupyter-core ==4.11.2
  • kiwisolver ==1.3.1
  • llvmlite ==0.35.0
  • matplotlib ==3.3.4
  • networkx ==2.5
  • nose ==1.3.7
  • nptyping ==2.5.0
  • numba ==0.52.0
  • numpy >=1.19
  • openpyxl ==3.0.6
  • ortools >=9.0.0
  • packaging ==20.9
  • pandas >=1.1
  • parso ==0.8.1
  • pexpect ==4.8.0
  • pickleshare ==0.7.5
  • pluggy ==0.13.1
  • prompt-toolkit ==3.0.16
  • ptyprocess ==0.7.0
  • pvlib *
  • py ==1.10.0
  • pySOT ==0.3.3
  • pyparsing ==2.4.7
  • pyproj ==3.0.0.post1
  • pytest ==6.2.2
  • pytestqt *
  • python-dateutil ==2.8.1
  • pytz ==2021.1
  • pyzmq ==22.0.3
  • qtconsole ==5.0.2
  • requests ==2.32.4
  • scikit-learn ==1.5.0
  • scipy >=1.5
  • shiboken2 ==5.15.2
  • six ==1.15.0
  • smopy ==0.0.7
  • threadpoolctl ==2.1.0
  • toml ==0.10.2
  • tornado ==6.5.1
  • traitlets >=4.3
  • urllib3 >=1.26.4
  • wcwidth ==0.2.5
  • windpowerlib *
  • xlrd ==2.0.1
  • xlwt ==1.3.0
requirements_venv.txt pypi
  • Cython *
  • atomicwrites ==1.3.0
  • attrs ==19.1.0
  • filelock ==3.0.12
  • importlib-metadata ==0.18
  • more-itertools ==7.2.0
  • nptyping *
  • numba >=0.46
  • ortools >=9.0.0
  • packaging ==19.0
  • pip ==23.3
  • pluggy ==0.12.0
  • pvlib *
  • py ==1.10.0
  • pyparsing ==2.4.1.1
  • pytest ==5.0.1
  • setuptools ==78.1.1
  • six ==1.12.0
  • toml ==0.10.0
  • tox ==3.13.2
  • virtualenv ==20.26.6
  • wcwidth ==0.1.7
  • windpowerlib *
  • zipp ==3.19.1
setup.py pypi
src/VeraGrid/setup.py pypi
src/VeraGridEngine/setup.py pypi
src/VeraGridServer/setup.py pypi