Defining a grid from scratch

In this example we are going to create a grid just by using GrdiCal's comands and we will run a power flow study.


In [46]:
import pandas as pd
import numpy as np

from GridCal.Engine import *

%matplotlib inline

Let's create a new grid object:


In [47]:
grid = MultiCircuit(name='lynn 5 bus')

Define this first bus with all the parameters for demonstration purposes:


In [48]:
bus1 = Bus(name='Bus1',
           vnom=10,   # Nominal voltage in kV
           vmin=0.9,  # Bus minimum voltage in per unit
           vmax=1.1,  # Bus maximum voltage in per unit
           xpos=0,    # Bus x position in pixels
           ypos=0,    # Bus y position in pixels
           height=0,  # Bus height in pixels
           width=0,   # Bus width in pixels
           active=True,   # Is the bus active?
           is_slack=False,  # Is this bus a slack bus?
           area='Default',  # Area (for grouping purposes only)
           zone='Default',  # Zone (for grouping purposes only)
           substation='Default'  # Substation (for grouping purposes only)
          )

The rest of the buses are defined with the default parameters:


In [49]:
bus2 = Bus(name='Bus2')
bus3 = Bus(name='Bus3')
bus4 = Bus(name='Bus4')
bus5 = Bus(name='Bus5')

Add the bus objects to the circuit:


In [50]:
grid.add_bus(bus1)
grid.add_bus(bus2)
grid.add_bus(bus3)
grid.add_bus(bus4)
grid.add_bus(bus5)

In GridCal, the loads, generators etc. are stored within each bus object.

We'll define the first load completely:


In [51]:
l2 = Load(name='Load',
          G=0,  # Impedance of the ZIP model in MVA at the nominal voltage
          B=0,
          Ir=0,
          Ii=0,  # Current of the ZIP model in MVA at the nominal voltage
          P=40,
          Q=20,  # Power of the ZIP model in MVA
          P_prof=None,  # Impedance profile
          Q_prof=None,  # Current profile
          Ir_prof=None,  # Power profile
          Ii_prof=None,
          G_prof=None,
          B_prof=None,
          active=True,  # Is active?
          mttf=0.0,  # Mean time to failure
          mttr=0.0  # Mean time to recovery
        )
grid.add_load(bus2, l2)


Out[51]:
<GridCal.Engine.Devices.load.Load at 0x7f02890d8fd0>

Define the others with the default parameters:


In [52]:
grid.add_load(bus3, Load(P=25, Q=15))
grid.add_load(bus4, Load(P=40, Q=20))
grid.add_load(bus5, Load(P=50, Q=20))


Out[52]:
<GridCal.Engine.Devices.load.Load at 0x7f0288a88ac8>

In [53]:
g1 = Generator(
    name='gen',
    active_power=0.0,  # Active power in MW, since this generator is used to set the slack , is 0
    voltage_module=1.0,  # Voltage set point to control
    Qmin=-9999,  # minimum reactive power in MVAr
    Qmax=9999,  # Maximum reactive power in MVAr
    Snom=9999,  # Nominal power in MVA
    power_prof=None,  # power profile
    vset_prof=None,  # voltage set point profile
    active=True  # Is active?
)
grid.add_generator(bus1, g1)


Out[53]:
<GridCal.Engine.Devices.generator.Generator at 0x7f02881bfda0>

In [54]:
br1 = Line(bus_from=bus1,
           bus_to=bus2,
           name='Line 1-2',
           r=0.05,  # resistance of the pi model in per unit
           x=0.11,  # reactance of the pi model in per unit
           b=0.02,  # susceptance of the pi model in per unit
           rate=50,  # Rate in MVA
           active=True,  # is the branch active?
           mttf=0,  # Mean time to failure
           mttr=0,  # Mean time to recovery
           length=1,  # Length in km (to be used with templates)
           template=None  # Branch template (The default one is void)
          )
grid.add_branch(br1)

All other branches with necessary parameters only:


In [55]:
grid.add_branch(Line(bus1, bus3, name='Line 1-3', r=0.05, x=0.11, b=0.02, rate=50))
grid.add_branch(Line(bus1, bus5, name='Line 1-5', r=0.03, x=0.08, b=0.02, rate=80))
grid.add_branch(Line(bus2, bus3, name='Line 2-3', r=0.04, x=0.09, b=0.02, rate=3))
grid.add_branch(Line(bus2, bus5, name='Line 2-5', r=0.04, x=0.09, b=0.02, rate=10))
grid.add_branch(Line(bus3, bus4, name='Line 3-4', r=0.06, x=0.13, b=0.03, rate=30))
grid.add_branch(Line(bus4, bus5, name='Line 4-5', r=0.04, x=0.09, b=0.02, rate=30))

Define power flow options:


In [56]:
power_flow_options = PowerFlowOptions(
    solver_type=SolverType.NR,  # Base method to use
    verbose=False,  # Verbose option where available
    tolerance=1e-6,  # power error in p.u.
    max_iter=25,  # maximum iteration number
    control_q=True  # if to control the reactive power
)

Declare and execute the power flow simulation


In [57]:
pf = PowerFlowDriver(grid, power_flow_options)
pf.run()

Now, let's compose a data frame with the voltage results:


In [58]:
headers = ['Vm (p.u.)', 'Va (Deg)', 'Vre', 'Vim']
Vm = np.abs(pf.results.voltage)
Va = np.angle(pf.results.voltage, deg=True)
Vre = pf.results.voltage.real
Vim = pf.results.voltage.imag
data = np.c_[Vm, Va, Vre, Vim]
v_df = pd.DataFrame(data=data, columns=headers, index=grid.bus_names)
print('\n', v_df)


    Vm (p.u.)  Va (Deg)       Vre       Vim
0   1.000000  0.000000  1.000000  0.000000
1   0.955324 -2.404434  0.954483 -0.040079
2   0.954838 -2.363420  0.954026 -0.039375
3   0.933366 -3.648173  0.931474 -0.059390
4   0.953415 -2.688384  0.952366 -0.044719

Let's do the same for the branch results:


In [59]:
headers = ['Loading (%)', 'Current(p.u.)', 'Power (MVA)']
loading = np.abs(pf.results.loading) * 100
current = np.abs(pf.results.Ibranch)
power = np.abs(pf.results.Sbranch)
data = np.c_[loading, current, power]
br_df = pd.DataFrame(data=data, columns=headers, index=grid.branch_names)
print('\n', br_df)


    Loading (%)  Current(p.u.)  Power (MVA)
0    99.581363       0.497907    49.790681
1    99.364567       0.496823    49.682284
2    95.041166       0.760329    76.032933
3    15.512118       0.004871     0.465364
4    50.595276       0.052961     5.059528
5    65.510510       0.205827    19.653153
6    82.016167       0.263614    24.604850

Finally, print the execution metrics:


In [60]:
print('\nError:', pf.results.error)
print('Elapsed time (s):', pf.results.get_report_dataframe(0), '\n')

print(v_df)
print()
print(br_df)


Error: <bound method PowerFlowResults.error of <GridCal.Engine.Simulations.PowerFlow.power_flow_results.PowerFlowResults object at 0x7f0288a7db00>>
Elapsed time (s):           Method  Converged?         Error  Elapsed (s)  Iterations
0  SolverType.NR           1  7.547707e-08     0.000531           2 

   Vm (p.u.)  Va (Deg)       Vre       Vim
0   1.000000  0.000000  1.000000  0.000000
1   0.955324 -2.404434  0.954483 -0.040079
2   0.954838 -2.363420  0.954026 -0.039375
3   0.933366 -3.648173  0.931474 -0.059390
4   0.953415 -2.688384  0.952366 -0.044719

   Loading (%)  Current(p.u.)  Power (MVA)
0    99.581363       0.497907    49.790681
1    99.364567       0.496823    49.682284
2    95.041166       0.760329    76.032933
3    15.512118       0.004871     0.465364
4    50.595276       0.052961     5.059528
5    65.510510       0.205827    19.653153
6    82.016167       0.263614    24.604850