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 None to skip all disk output.

  • n_cores (int or None, optional) – Number of worker processes. Capped internally at max(1, os.cpu_count() - 1). Pass None to 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 output_dir: str | None#

The root output directory passed to the constructor (may be None).

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 product

  • One 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.

Parameters:
  • data_key (str) – Key in the SDOM data dict (e.g. "scalars").

  • param_name (str) – Row label of the parameter (e.g. "GenMix_Target").

  • values (list of float) – Discrete values to sweep over.

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.

Parameters:
  • param_name (str) – Row label in data["storage_data"] (e.g. "P_Capex").

  • factors (list of float) – Multiplicative factors to apply.

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 from sdom.parametric.mutations.TS_KEY_TO_COLUMN.

Parameters:
  • ts_key (str) – Key in the SDOM data dict (e.g. "load_data").

  • factors (list of float) – Multiplicative scaling factors.

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 == False and a descriptive termination_condition.

Return type:

list of OptimizationResults


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:
  • data_key (str) – Key in the SDOM data dict whose DataFrame contains the parameter (e.g. "scalars").

  • param_name (str) – Row label in data[data_key] (e.g. "GenMix_Target").

  • values (list of float) – Discrete values to evaluate. Each entry produces one case dimension in the Cartesian product.

Examples

>>> ScalarSweep("scalars", "GenMix_Target", [0.7, 0.8, 0.9, 1.0])
data_key: str#
param_name: str#
values: List[int | float]#
__init__(data_key: str, param_name: str, values: ~typing.List[int | float] = <factory>) None#
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:
  • param_name (str) – Row label in data["storage_data"] (e.g. "P_Capex").

  • factors (list of float) – Multiplicative factors to apply. 1.0 keeps the base value.

Examples

>>> StorageFactorSweep("P_Capex", [0.7, 0.8, 1.0])
param_name: str#
factors: List[float]#
__init__(param_name: str, factors: ~typing.List[float] = <factory>) None#
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 the TS_KEY_TO_COLUMN mapping in sdom.parametric.mutations.

Parameters:
  • ts_key (str) – Key in the SDOM data dict (e.g. "load_data", "large_hydro_max").

  • factors (list of float) – Multiplicative scaling factors. 1.0 keeps the base series.

Examples

>>> TsSweep("load_data", [0.9, 1.0, 1.1])
ts_key: str#
factors: List[float]#
__init__(ts_key: str, factors: ~typing.List[float] = <factory>) None#

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_key to 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:
  • data (dict) – SDOM data dictionary (already deep-copied; will be mutated in-place).

  • data_key (str) – Key identifying the DataFrame in data (e.g. "scalars").

  • param_name (str) – Row label of the parameter to modify (e.g. "GenMix_Target").

  • value (float or int) – New value to assign.

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:
  • data (dict) – SDOM data dictionary (already deep-copied; will be mutated in-place).

  • param_name (str) – Row label in data["storage_data"] (e.g. "P_Capex").

  • factor (float) – Multiplicative factor. 1.0 leaves the row unchanged.

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_COLUMN and multiplies data[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 in TS_KEY_TO_COLUMN.

  • factor (float) – Multiplicative scaling factor. 1.0 leaves 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_name argument to sdom.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_optimal is False when the solver did not find a feasible solution or an exception was raised.

Return type:

sdom.results.OptimizationResults