GridForge Configuration Definition¶
This document defines the GridForge YAML format and the execution logic used by
construct_grid_config(...).
GridForge configurations are intentionally sheet-oriented. A configuration starts from a PYPOWER/MATPOWER-style network, edits the core sheets, adds custom asset sheets attached to buses, then optionally rebalances aggregate quantities.
This document covers static grid construction only. Time-series CSV assignment
is a separate workflow handled by gridforge.data and described in
bus-data-assignment.md.
Table of Contents¶
- 1) Top-Level Shape
- 2) Construction Pipeline
- 3) Core Sheets
- 4) Custom Sheets
- 5) Column Rules
- 6) Relative Mapping
- 7) BUS_IDX Placement
- 8) Rescale Rules
- 9) Common Patterns
- 10) Common Validation Failures
- 11) Minimal Example
1) Top-Level Shape¶
The idea of the configuration is to define several useful rules to efficiently modify basic grid settings defined by MATPOWER/PYPOWER.
In short: manual setting means editing many rows in Excel by hand. GridForge config construction lets the user describe patterns, placement logic, relative values, and system-level scaling, then generates the consistent grid workbook automatically.
The top-level shape of the configuration is as follows:
super_config:
pypower_case_name: case14
baseMVA: 100
grid_config:
bus: {}
gen: {}
branch: {}
solar: {}
load: {}
rescale: []
super_config: base-case settings.grid_config: rules for core sheets and custom asset sheets attached to buses.rescale: optional post-build aggregate balancing rules.
pypower_case_name identifies the base case to load. It can be:
- a built-in PYPOWER case name, such as
case14, see all the built-in cases here. - a path to a local PYPOWER-style
.pycase file - a path to a local MATPOWER
.mcase file, see here
Relative file paths are resolved relative to the YAML file location.
grid_config keys are interpreted by sheet name:
- core sheets:
bus,gen,branch - custom sheets: every other key, such as
load,solar,wind,storage
The best way to understand the configuration is to look at the 14-bus configuration example.
2) Construction Pipeline¶
Construction runs in this order:
- Load the base case named by
super_config.pypower_case_name. - Convert base arrays to DataFrames with GridForge column names.
- Merge PYPOWER/MATPOWER
gencostrows intogenasCOST_*columns. - Renumber buses to dense 1-based
BUS_IDXvalues and rewrite generator and branch bus references accordingly. - Apply
grid_configrules to existing core sheets. - Build custom sheets in YAML order.
- Apply
rescalerules. See Rescale Rules for more details. - Write the resulting Excel workbook.
3) Core Sheets¶
GridForge core sheets are:
busgenbranch
Base PYPOWER columns are renamed as follows:
- bus index:
BUS_IDX - generator bus index:
BUS_IDX - branch endpoints:
F_BUS_IDX,T_BUS_IDX - status fields:
STATUS
Generator cost data is not kept as a separate gencost sheet in GridForge. It
is merged into gen during loading:
Source gencost column |
GridForge gen column |
|---|---|
MODEL |
COST_MODEL |
STARTUP |
COST_STARTUP |
SHUTDOWN |
COST_SHUTDOWN |
ORDER |
COST_ORDER |
SECOND |
COST_SECOND |
FIRST |
COST_FIRST |
ZERO |
COST_ZERO |
Rules under a core sheet can overwrite existing columns or add extra columns.
Example:
grid_config:
gen:
PMIN:
format: relative
value: [0.1]
relative_to:
sheet: gen
column: PMAX
map_by: row
COST_FIRST:
format: absolute
value: [3, 1, 6, 4, 5]
The detailed rules for each column are described in Column Rules.
4) Custom Sheets¶
Every custom sheet must define BUS_IDX.
Custom sheets are asset tables attached to buses. BUS_IDX determines:
- how many rows the sheet has,
- which bus each asset row is attached to,
- the incidence matrix exposed later as
grid.custom["name"].Cbus.
For custom sheets, STATUS is automatically added as 1 unless you define it
explicitly.
Example:
grid_config:
load:
BUS_IDX:
format: relative
value: [1]
relative_to:
bus_type: [4]
PMAX:
format: relative
value: [1.0]
relative_to:
sheet: bus
column: PD
map_by: bus_idx
If a custom sheet omits BUS_IDX, construction raises an error.
5) Column Rules¶
Every non-BUS_IDX column rule has this shape:
<COLUMN_NAME>:
format: absolute | relative
value: [ ... ]
random_ratio: 0.0 # optional
relative_to: ... # required when format: relative
5.1 Absolute Rules¶
An absolute rule writes values directly:
PMAX:
format: absolute
value: [160, 140, 100]
value can be:
- one item, which is broadcast to every target row
- one item per target row
If random_ratio: r is provided, values are multiplied by:
1 + U[-r, r]
Use random_ratio in the range [0, 1]; the constructor rejects values
outside that range.
5.2 Relative Rules¶
A relative rule multiplies value by a referenced base quantity:
PMIN:
format: relative
value: [0.1]
relative_to:
sheet: gen
column: PMAX
map_by: row
relative_to must include:
sheet: the sheet name to reference such asgen,bus,branch, etc.column: the column name to reference such asPMAX,PD,QMAX, etc.- exactly one of:
map_by: row | bus_idxaggregate: sum | mean | min | max
Relative references read from the current in-memory sheet state. That means
core-sheet edits are visible to custom sheets, and earlier custom sheets can
affect later custom sheets if they use options such as remove_gen.
6) Relative Mapping¶
map_by: row¶
Use row mapping when source and target rows are aligned by position.
Rules:
- source and target row counts must match exactly
- source row
imaps to target rowi
Example: The minimum generation capacity is set to 10% of the maximum generation capacity for each generator.
PMIN:
format: relative
value: [0.1]
relative_to:
sheet: gen
column: PMAX
map_by: row
map_by: bus_idx¶
Use bus-index mapping when values should follow BUS_IDX.
Rules:
- source and target sheets must both contain
BUS_IDX - duplicate source rows on the same bus are summed
- duplicate target rows on the same bus split the source value evenly
- missing source buses raise an error
Example: The base active demand is set to the active demand of the same bus.
PD_BASE:
format: relative
value: [1.0]
relative_to:
sheet: bus
column: PD
map_by: bus_idx
aggregate¶
Use aggregation when the source column should become one scalar:
CURTAIL_COST:
format: relative
value: [10]
relative_to:
sheet: gen
column: COST_FIRST
aggregate: max
This means that the curtailment cost is set to the 10 times the maximum first cost of the generators.
CURTAIL_COST = 10 * max(gen.COST_FIRST)
7) BUS_IDX Placement¶
BUS_IDX is a special required rule for every custom sheet.
7.1 Absolute Placement¶
BUS_IDX:
format: absolute
value: [2, 8, 10]
Rules:
- every value must exist in
bus.BUS_IDX - row count equals the number of listed bus IDs
7.2 Relative Placement By Bus Pool¶
BUS_IDX:
format: relative
value: [0.5]
relative_to:
bus_type: [2]
Rules:
valuemust contain exactly one ratio- the ratio must be
<= 1 - candidate buses are selected from
relative_to.bus_type - selected count is
max(1, int(ratio * pool_size)); e.g., at least 1 bus is selected - sampling is without replacement
Allowed bus_type tokens:
1: PQ buses2: PV buses3: slack buses4: buses with positivePDpositive_pdandpd_positive: aliases for4
bus_type can be a scalar, a list, or a comma-/pipe-separated string. Multiple tokens are interpreted as a union; e.g., [1, 2, 3] means all PQ, PV, and slack buses.
7.3 Placement Groups¶
group prevents sheets in the same group from selecting the same bus.
solar:
BUS_IDX:
format: relative
value: [0.3]
relative_to:
bus_type: [2]
group: renewable
wind:
BUS_IDX:
format: relative
value: [0.3]
relative_to:
bus_type: [2]
group: renewable
Here solar and wind cannot use the same selected bus.
7.4 Generator Replacement¶
remove_gen: true removes generator rows on selected buses after the custom
sheet is built.
solar:
BUS_IDX:
format: absolute
value: [2, 8]
remove_gen: true
This will remove the generators on buses 2 and 8 from the grid configuration (if they exist).
8) Rescale Rules¶
rescale runs after all core and custom sheets are built. It multiplies
selected target rows by one scale factor so a target aggregate matches a ratio of source aggregates.
For example, if you want the total load capacity to be scaled to 90% of the total generation capacity (generators + solar), you can use the following rescale rule:
rescale:
- name: load_to_active_supply_ratio # optional
target: # the sheet and column to be scaled
sheet: load
column: PMAX
aggregate: sum # the sum of the selected target over all rows should be rescaled t0 ...
filter:
STATUS: 1 # only pick up the rows with status = 1
ratio: 0.9
sources: # the sheets and columns to be used as the source/reference of the scaling
- sheet: gen
column: PMAX
aggregate: sum # the sum of the selected source over all rows should be used as the reference of the scaling
filter:
STATUS: 1
- sheet: solar
column: PMAX
aggregate: sum
filter:
STATUS: 1
The target after scaling is:
aggregate(target selected rows)
= ratio * sum(aggregate(each source's selected rows))
nameis optional.
8.1 Target And Source Terms¶
Each target/source term supports:
sheet: sheet namecolumn: numeric column to aggregateaggregate:sum,mean,min, ormax; default issumfilter: optional current-sheet filter
The rule itself must include:
ratio- non-empty
sources target
8.2 Filter Semantics¶
Filters are current-sheet scoped only.
filter:
STATUS: 1
ZONE: [1, 2]
9) Common Patterns¶
Use A Local Base Case¶
super_config:
pypower_case_name: cases/my_case.py
baseMVA: 100
or:
super_config:
pypower_case_name: cases/my_case.m
baseMVA: 100
Local .py files should define a PYPOWER-style function with the same name as
the file stem. For example, cases/my_case.py should define my_case() and
return a PYPOWER case dictionary. See a case14.py example.
MATPOWER .m files are converted through GridForge's built-in converter (see matpower_io.py). The
converter supports common literal MATPOWER case files, but it does not execute
arbitrary MATLAB code. If a .m file builds arrays programmatically, load it in
MATLAB/Octave first and export a literal case file before using it in GridForge. See a case14.m example.
Add Load At Positive-Demand Buses¶
load:
BUS_IDX:
format: relative
value: [1]
relative_to:
bus_type: [4] # 4 means buses with positive PD in original case file
Add Renewable Assets And Replace Generators¶
solar:
BUS_IDX:
format: absolute
value: [2, 8]
group: renewable
remove_gen: true
PMAX:
format: relative
value: [1.0]
relative_to:
sheet: gen
column: PMAX
map_by: bus_idx # map the PMAX of the generators to the PMAX of the solar assets on the same buses
CURTAIL_COST:
format: relative
value: [10]
relative_to:
sheet: gen
column: COST_FIRST
aggregate: max
Rescale Load To Active Supply¶
rescale:
- name: load_to_active_supply_ratio
target:
sheet: load
column: PMAX
aggregate: sum
filter: { STATUS: 1 }
ratio: 0.9
sources:
- { sheet: gen, column: PMAX, aggregate: sum, filter: { STATUS: 1 } }
- { sheet: solar, column: PMAX, aggregate: sum, filter: { STATUS: 1 } }
- { sheet: wind, column: PMAX, aggregate: sum, filter: { STATUS: 1 } }
10) Common Validation Failures¶
The following are common validation failures that the constructor raises:
- missing top-level
super_configorgrid_config - unsupported
format format: relativewithoutrelative_torelative_tomissingsheetorcolumnrelative_tousing bothmap_byandaggregate- custom sheet without
BUS_IDX - relative
BUS_IDXwithoutrelative_to.bus_type - absolute
BUS_IDXcontaining IDs outsidebus.BUS_IDX - value list length is neither
1nor the target row count map_by: rowsource and target row counts differmap_by: bus_idxsource or target lacksBUS_IDXmap_by: bus_idxcannot find a source value for a target busgroupplacement has too few available busesremove_genis not boolean- rescale source/target filters select zero rows
- rescale target aggregate is zero but requested target is nonzero
11) Minimal Example¶
super_config:
pypower_case_name: case14
baseMVA: 100
grid_config:
gen:
PMIN:
# The minimum generation capacity is set to 20% of the maximum generation capacity for each generator.
format: relative
value: [0.2]
relative_to:
sheet: gen
column: PMAX
map_by: row
solar:
BUS_IDX:
# The solar assets are randomly placed on 30% of the PV buses.
format: relative
value: [0.3]
relative_to:
bus_type: [2]
group: renewable
remove_gen: true
PMAX:
# The PMAX of the solar assets is set to 1.0 times the PMAX of the generators on the same buses. This is correct because the solar assets are placed on the same buses as the generators (type 2 bus)
format: relative
value: [1.0]
relative_to:
sheet: gen
column: PMAX
map_by: bus_idx
CURTAIL_COST:
# The curtailment cost is set to 10 times the maximum first cost of the generators.
format: relative
value: [10]
relative_to:
sheet: gen
column: COST_FIRST
aggregate: max
rescale: [] # no rescale rules are applied in this example