Scenario builder
The scenario builder lets you control which data-series column is used for each
Monte-Carlo (MC) scenario, independently per component group. Without it,
scenario index i always maps to column i of every timeseries file.
Motivation
A study that simulates 100 MC scenarios may have some components (e.g. wind farms) whose data only has 10 distinct columns, while others (e.g. demand) have 100. The scenario builder lets you express this mapping explicitly, so GemsPy reads the right column for each component and scenario.
The modeler-scenariobuilder.dat file
Place the file at:
Each non-empty, non-comment line has the form:
<scenario_group>— a group name you assign to one or more components<mc_scenario>— the MC scenario index (0-based in the file)<time_serie_number>— the column of the timeseries file to use (1-based)
Example
Suppose you have 4 MC scenarios, 2 wind-power columns, and 4 load columns:
# Wind turbines: map 4 MC scenarios onto 2 data columns (round-robin)
wind, 0 = 1
wind, 1 = 2
wind, 2 = 1
wind, 3 = 2
# Demand: one distinct column per scenario
demand, 0 = 1
demand, 1 = 2
demand, 2 = 3
demand, 3 = 4
Note
Every MC scenario index that appears in the simulation playlist must be
listed for every group in the file. Missing entries raise a ValueError
at load time. validate_optim_config() cross-checks the
scenario-scope playlist against the
scenario builder and reports any out-of-bounds indices.
Linking components to a scenario group
In the system YAML, set scenario-group on any component whose parameters
should use this mapping:
system:
model-libraries: my_library
components:
- id: wind_north
model: my_library.wind
scenario-group: wind # ← links this component to the "wind" group
parameters:
- id: p_max
time-dependent: true
scenario-dependent: true
value: wind_north_data
- id: load_city
model: my_library.load
scenario-group: demand
parameters:
- id: load
time-dependent: true
scenario-dependent: true
value: city_load_data
Components without a scenario-group use the identity mapping (MC scenario i
→ column i).
How load_study() handles the file
load_study() automatically reads input/data-series/modeler-scenariobuilder.dat if present and
attaches the resulting ScenarioBuilder to the returned Study object:
from pathlib import Path
from gems.study import load_study
study = load_study(Path("my_study"))
# study.scenario_builder is populated from modeler-scenariobuilder.dat
When the file is absent, study.scenario_builder is an empty ScenarioBuilder
that passes MC scenario indices through unchanged.
Python API
import numpy as np
from pathlib import Path
from gems.study.scenario_builder import ScenarioBuilder
# Load from file
sb = ScenarioBuilder.load(Path("my_study/input/data-series/modeler-scenariobuilder.dat"))
# Resolve a batch of MC scenarios for the "wind" group
mc_scenarios = np.array([0, 1, 2, 3]) # 0-based internally
col_indices = sb.resolve_vectorized("wind", mc_scenarios)
# → array([0, 1, 0, 1]) (0-based column indices)
# Components without a group use None → identity mapping
col_indices = sb.resolve_vectorized(None, mc_scenarios)
# → array([0, 1, 2, 3])
Note
resolve_vectorized works with 0-based indices internally, even though
the .dat file uses 1-based numbering. The conversion is handled
automatically by ScenarioBuilder.load().