Define Networks and Objects

This section describes how to create an electric network and its associated objects using pySAInt.

1. Create a New Electric Dataset

In pySAInt, all data is contained within a dataset object. When building a dataset from scratch, we begin by initializing an empty electric dataset. Throughout this documentation we will use a simple triangle dataset.

import pysaint as ps

# This creates an empty electric dataset called "triangle"
triangle = ps.create_electric_dataset()
python

This generates an empty pySAInt electric dataset, ready for the addition of objects, profiles, and events. We can add any number of additional objects, profiles, and events to our dataset.

2. Add Objects to a Dataset

With our dataset initialized we can populate it with objects using the add_object method. Users can add objects of different types into the dataset with their specified properties. Please refer to the SAInt documentation for any questions about the object types that exist in SAInt.

The add_object method accepts the following arguments:

Parameter Type Description

ObjType

str

SAInt object type (e.g., ENET for electric network).

Name

str

Object name.

kwargs

Additional properties of the object.

We can add an ENET object called triangle to our dataset with the following command.

# Add an ENET object to the dataset
triangle.add_object(ObjType="ENET", Name="triangle")
python

Objects can be added to a pySAInt dataset in any order. However, we recommend adding objects in the following order:

  • Network (ENET)

  • Nodes

  • Branches

  • Fuels, Ancillary Services, and Hydro Plants

  • Externals (generators, storages, and demands)

  • Ancillary Service Externals

  • Constraints and Variables

  • Groups and Group Memberships

2.1. Specify Properties and Values for Objects

When adding an object to a dataset, you can also specify the value for any property of that object using kwargs (key-word arguments). All the properties defined with kwargs should match exactly the property names in SAInt. For example, some of the properties for ENO and LI objects are included when these objects are added to the "triangle" dataset below.

2.1.1. Add Nodes and Branches

# Add ENO objects to the dataset
# dataset_name.add_object(ObjType, Name, Property1=value1, Property2=value2, ...)
triangle.add_object(ObjType="ENO", Name="NODE1", **{"X/Long": 0, "Y/Lat": 0})
triangle.add_object(ObjType="ENO", Name="NODE2", **{"X/Long": 1, "Y/Lat": 1})
triangle.add_object(ObjType="ENO", Name="NODE3", **{"X/Long": 0, "Y/Lat": 2})

# Add LI objects to the dataset
triangle.add_object(ObjType="LI",  Name="LINE1", FromName="NODE1", ToName="NODE2", PMAXDEF=400)
triangle.add_object(ObjType="LI",  Name="LINE2", FromName="NODE2", ToName="NODE3", PMAXDEF=400)
triangle.add_object(ObjType="LI",  Name="LINE3", FromName="NODE3", ToName="NODE1", PMAXDEF=400)
python

2.1.2. Add Fuels, Ancillary Services, and Hydro Plants (if they exist in your model)

  • When adding FUEL objects, always specify the FuelUnit property!

  • When adding ASVC objects, always specify the ASVCType property!

# Add FUEL objects to the dataset
triangle.add_object(ObjType="FUEL", Name="GAS", FuelUnit="MMBTU", FuelPriceDef=5, CO2=54000)

# Add ASVC objects to the dataset
triangle.add_object(
    ObjType="ASVC",
    Name="SPINNING_RESERVE",
    ASVCType="UpReserve",
    Unit="MW",
    MinValPriceDef=2000,
    Info="10-minute response time"
)
python

2.1.3. Add Externals

# Add demand objects
triangle.add_object(ObjType="EDEM", Name="DEMAND1", NodeName="NODE1", PSETPRCDEF=100000)
triangle.add_object(ObjType="EDEM", Name="DEMAND2", NodeName="NODE2", PSETPRCDEF=100000)

# Add generator objects
triangle.add_object(ObjType="XGEN", Name="GEOTHERMAL", NodeName="NODE1", PMAXDEF=10)
triangle.add_object(ObjType="PV", Name="SOLAR", NodeName="NODE1", PMAXDEF=50)
triangle.add_object(
    ObjType="FGEN",
    Name="GAS_CT",
    NodeName="NODE3",
    FuelName="GAS",
    PMAXDEF=100,
    PMINDEF=40,
    MaxUpRampDef=10,
    MaxDownRampDef=10,
    FC0=100,
    FC1=9
)
triangle.add_object(
    ObjType="FGEN",
    Name="GAS_CC",
    NodeName="NODE2",
    FuelName="GAS",
    PMAXDEF=400,
    PMINDEF=140,
    MaxUpRampDef=2,
    MaxDownRampDef=2,
    FC0=100,
    FC1=7
)

# Add storage objects
triangle.add_object(
    ObjType="ESTR",
    Name="BATTERY",
    NodeName="NODE1",
    PGMAXDEF=20,
    PDMAXDEF=20,
    MaxCapDef=40,
    PGeff=0.9,
    PDeff=0.9
)
python

2.1.4. Add Ancillary Service Externals (if you are modeling ancillary services)

# Add ASVCX objects
triangle.add_object(
    ObjType="ASVCX",
    Name="GAS_CT_SPINNING_RESERVE",
    ASVCName="SPINNING_RESERVE",
    External="FGEN.GAS_CT"
)
triangle.add_object(
    ObjType="ASVCX",
    Name="GAS_CC_SPINNING_RESERVE",
    ASVCName="SPINNING_RESERVE",
    External="FGEN.GAS_CC"
)
python

We recommend using relational events to set the MaxVal property of ASVCX objects rather than just using MaxValDef. This will make your dataset easier to maintain if there are changes.

2.1.5. Add Constraints and Variables (if they are needed in your model)

In this example, we will add a constraint that says the ESTR object must be charged from the PV object. For questions about user-defined constraints, please consult the SAInt documentation.

# Add ECNSTR objects
triangle.add_object("ECNSTR", "HYBRID_PV_STORAGE", LowBoundDef=0)

# Add EVAR objects
triangle.add_object(
    ObjType="EVAR",
    Name="PV_GEN",
    CNSTRName="HYBRID_PV_STORAGE",
    NetObjID="PV.SOLAR",
    ObjVarName="P",
    Unit="MW",
    CoeffDef=1
)
triangle.add_object(
    ObjType="EVAR",
    Name="ESTR_CHARGE",
    CNSTRName="HYBRID_PV_STORAGE",
    NetObjID="ESTR.BATTERY",
    ObjVarName="PD",
    Unit="MW",
    CoeffDef=-1
)
python

This equation is read by SAInt as "PV.SOLAR.P - ESTR.BATTERY.PD >= 0".

2.1.6. Add Groups and Group Memberships

In this example, we use two groups - RENEWABLE_GEN and NONRENEWABLE_GEN - to categorize the generators in our model. This will help us easily get aggregated results for these categories.

Group memberships are handled slightly differently than all other object types. Group memberships should be defined with the same name as the corresponding group object, and the object IDs for all the members should be added as a list to the property Members.

# Add EGRP objects
triangle.add_object("EGRP", "RENEWABLE_GEN")
triangle.add_object("EGRP", "NONRENEWABLE_GEN")

# Add EGRPM objects
triangle.add_object(
    ObjType="EGRPM",
    Name="RENEWABLE_GEN",
    Members=[
        "PV.SOLAR",
        "XGEN.GEOTHERMAL"
    ]
)
triangle.add_object(
    ObjType="EGRPM",
    Name="NONRENEWABLE_GEN",
    Members=[
        "FGEN.GAS_CT",
        "FGEN.GAS_CC"
    ]
)
python

3. Defining the Units for Object Properties

Each dataset in pySAInt has an attribute called default_units. This defines the units for each property and object type. The attribute default_units for a pySAInt dataset is a nested dictionary with the first key corresponding to object type and the second corresponding to property.

# Display what is the default unit for the "PMAXDEF" property for "FGEN" objects.
print("FGEN PMAXDEF Units: ", triangle.default_units["FGEN"]["PMAXDEF"])
python

From the output of the print statement above, you should be able to see that PMAXDEF property for FGEN objects has units of MW.

This means that all FGEN objects must have PMAXDEF defined in terms of MW!

This applies for all object types and their properties.

The default units are taken from the SAInt lexicon available wherever SAInt is installed on your machine:

encoord/SAInt-v3/Documents/FilterableLexicon.xlsx

3.1. Changing the Default Units for a Property

The default units for battery are shown below.

# Disply the default units for power and energy capacity for ESTR objects.
print("ESTR PGMAXDEF Units: " + triangle.default_units["ESTR"]["PGMAXDEF"])
print("ESTR PDMAXDEF Units: " + triangle.default_units["ESTR"]["PDMAXDEF"])
print("ESTR MaxCapDef Units: " + triangle.default_units["ESTR"]["MaxCapDef"])
python

As we can see above, we need to change the units for MaxCapDef from MJ to MWh.

# Change the default units of "MaxCapDef" for "ESTR" objects to "MWh"
triangle.default_units["ESTR"]["MaxCapDef"] = "MWh"
python

Note that unlike in the SAInt GUI, unit conversions are not automatically applied in pySAInt. (i.e., changing the default units from MJ to MWh will not adjust the ESTR MaxCapDef values by a factor of 0.0002778)