sdom.parametric — Parametric Analysis#
API reference for the sdom.parametric sub-package.
See the user guide for a full usage walkthrough and worked examples.
ParametricStudy#
- class sdom.parametric.ParametricStudy(base_data: dict, solver_config: dict, n_hours: int = 8760, output_dir: str | None = None, n_cores: int | None = None)[source]#
Run a multi-dimensional parametric sensitivity study in parallel.
Accepts scalar, storage-factor, and time-series sweep definitions, constructs the full Cartesian product of all sweep dimensions, and dispatches each combination to a separate worker process via
concurrent.futures.ProcessPoolExecutor.- Parameters:
base_data (dict) – SDOM data dictionary returned by
sdom.load_data(). This object is never modified; each worker process receives its own deep copy before applying mutations.solver_config (dict) – Solver configuration dict from
sdom.get_default_solver_config_dict().n_hours (int, optional) – Number of simulation hours. Defaults to
8760.output_dir (str or None, optional) – Directory where per-case sub-directories and the summary CSV will be written. Pass
Noneto skip all disk output.n_cores (int or None, optional) – Number of worker processes. Capped internally at
max(1, os.cpu_count() - 1). PassNoneto use the maximum safe count.
Examples
>>> study = ParametricStudy(base_data=data, solver_config=solver_cfg) >>> study.add_scalar_sweep("scalars", "GenMix_Target", [0.8, 0.9, 1.0]) >>> study.add_ts_sweep("load_data", [0.95, 1.05]) >>> results = study.run() # 3 × 2 = 6 cases
- __init__(base_data: dict, solver_config: dict, n_hours: int = 8760, output_dir: str | None = None, n_cores: int | None = None) None[source]#
- property case_metadata: List[dict]#
Per-case metadata populated after
run()is called.Returns a list of dicts, one per case in Cartesian-product order (matching the order of the list returned by
run()). Each dict contains:"case_name"— filesystem-safe case identifier"case_index"— zero-based position in the Cartesian productOne additional key per registered sweep dimension, using the param_name (scalar / storage-factor sweeps) or ts_key (time-series sweeps) as the key, and the swept value as the value.
Returns an empty list before
run()is called.
- add_scalar_sweep(data_key: str, param_name: str, values: list) None[source]#
Register a scalar parameter sweep.
Each value in values replaces
data[data_key].loc[param_name, "Value"]for one case dimension.
- add_storage_factor_sweep(param_name: str, factors: list) None[source]#
Register a multiplicative storage-parameter sweep.
Each factor scales the entire
data["storage_data"].loc[param_name]row (all storage technologies) uniformly.
- add_ts_sweep(ts_key: str, factors: list) None[source]#
Register a time-series multiplicative sweep.
Each factor scales the numeric column of
data[ts_key]. The column name is resolved automatically fromsdom.parametric.mutations.TS_KEY_TO_COLUMN.
- run() List[OptimizationResults][source]#
Execute all parametric combinations in parallel.
Constructs the Cartesian product of all registered sweeps, submits every case to a
ProcessPoolExecutor, reports progress as jobs complete, exports per-case CSVs (if output_dir was specified), and writes a summary CSV.- Returns:
One entry per combination, in Cartesian-product order (matching the order cases were submitted). Cases that failed have
is_optimal == Falseand a descriptivetermination_condition.- Return type:
Sweep descriptors#
- class sdom.parametric.ScalarSweep(data_key: str, param_name: str, values: ~typing.List[int | float] = <factory>)[source]#
Descriptor for a scalar parameter sweep.
Defines a sweep over discrete absolute values for a scalar parameter stored in the SDOM data dict. The sweep replaces
data[data_key].loc[param_name, "Value"]with each value in turn.- Parameters:
Examples
>>> ScalarSweep("scalars", "GenMix_Target", [0.7, 0.8, 0.9, 1.0])
- class sdom.parametric.StorageFactorSweep(param_name: str, factors: ~typing.List[float] = <factory>)[source]#
Descriptor for a multiplicative storage-parameter sweep.
Multiplies the entire row
data["storage_data"].loc[param_name](i.e. all storage technologies) by each factor. This is the primary use-case when scaling a cost parameter uniformly across all techs.- Parameters:
Examples
>>> StorageFactorSweep("P_Capex", [0.7, 0.8, 1.0])
- class sdom.parametric.TsSweep(ts_key: str, factors: ~typing.List[float] = <factory>)[source]#
Descriptor for a time-series parameter sweep.
Multiplies the numeric column of
data[ts_key]by each factor. The column name is resolved automatically via theTS_KEY_TO_COLUMNmapping insdom.parametric.mutations.- Parameters:
Examples
>>> TsSweep("load_data", [0.9, 1.0, 1.1])
Internal helpers (advanced)#
These are not part of the public API but are documented for contributors and advanced users who need to add custom mutation logic.
- sdom.parametric.mutations.TS_KEY_TO_COLUMN: dict[str, str] = {'cap_exports': 'Exports', 'cap_imports': 'Imports', 'large_hydro_data': 'LargeHydro', 'large_hydro_max': 'LargeHydro_max', 'large_hydro_min': 'LargeHydro_min', 'load_data': 'Load', 'nuclear_data': 'Nuclear', 'other_renewables_data': 'OtherRenewables', 'price_exports': 'Exports_price', 'price_imports': 'Imports_price'}#
Maps every supported
ts_keyto the column that holds numeric values in the corresponding DataFrame. Used by_apply_ts_mutation().
- sdom.parametric.mutations._apply_scalar_mutation(data: dict, data_key: str, param_name: str, value: Any) None[source]#
Replace a scalar value in a DataFrame row-indexed by parameter name.
Sets
data[data_key].loc[param_name, "Value"] = value.- Parameters:
- Raises:
ValueError – If data_key is not in data, or param_name is not a valid row label in
data[data_key].
- sdom.parametric.mutations._apply_storage_factor_mutation(data: dict, param_name: str, factor: float) None[source]#
Scale an entire row of
data["storage_data"]by a multiplicative factor.Multiplies
data["storage_data"].loc[param_name](all technology columns) by factor. This uniformly scales the parameter across all storage technologies.- Parameters:
- Raises:
ValueError – If
"storage_data"is absent from data or param_name is not a valid row label.
- sdom.parametric.mutations._apply_ts_mutation(data: dict, ts_key: str, factor: float) None[source]#
Scale the numeric column of a time-series DataFrame by a multiplicative factor.
Looks up the target column name in
TS_KEY_TO_COLUMNand multipliesdata[ts_key][column] *= factor.- Parameters:
data (dict) – SDOM data dictionary (already deep-copied; will be mutated in-place).
ts_key (str) – Key identifying the time-series DataFrame in data (e.g.
"load_data"). Must be present inTS_KEY_TO_COLUMN.factor (float) – Multiplicative scaling factor.
1.0leaves the series unchanged.
- Raises:
ValueError – If ts_key is not in
TS_KEY_TO_COLUMN, if ts_key is not present in data, or if the resolved column is absent from the DataFrame.
- sdom.parametric.worker._run_single_case(case_dict: dict)[source]#
Evaluate one parameter combination by building and solving a fresh model.
This is the worker function submitted to
ProcessPoolExecutor. Each invocation receives a fully self-contained description of the case; no shared state is required between processes.- Parameters:
case_dict (dict) –
Serialisable description of the case with the following keys:
"data"The shared SDOM base data dict. A deep copy is made inside the worker so that mutations are isolated to this case and the original is not modified. This avoids creating all copies up-front in the parent process.
"solver_config"Solver configuration dict from
sdom.optimization_main.get_default_solver_config_dict()."n_hours"Number of simulation hours.
"case_name"Human-readable identifier for this combination, used as the
case_nameargument tosdom.optimization_main.run_solver()."scalar_mutations"List of
(data_key, param_name, value)triples to apply."storage_factor_mutations"List of
(param_name, factor)pairs to apply."ts_mutations"List of
(ts_key, factor)pairs to apply.
- Returns:
Results dataclass.
is_optimalisFalsewhen the solver did not find a feasible solution or an exception was raised.- Return type: