Skip to content

Public API

The public API is for developers who want to build workflows, reports, dashboards, adapters, or automation on top of Gridalyn without depending on study-specific scripts.

New code should use the native seven-module structure:

Module Stable responsibility
gridalyn.foundation Workspaces, artifact policy, reports, manifests, validation, and governance.
gridalyn.twin Network repositories, the canonical NetworkModel and its ModelIdentity, declared operational state (OperationalState, resolved per loaded snapshot — reached through gridalyn.twin.network), observed state (NetworkObservation with a required provenance, observe_network, the measured-state ingest and the observation producer registry), model authority declarations (ModelAuthoritySet, ModelProfile), topology, source adapters, IO helpers, and semantic graph.
gridalyn.assets Building, EV, DER, thermal, load, and asset-model generation.
gridalyn.simulation Synthetic-network builders, power-flow builders, solver adapters, network impact, and validation analytics.
gridalyn.operations Providers, aggregators, offers, clearing, dispatch, settlement, constraints, and KPIs.
gridalyn.projects project.yaml, workflow.yaml, workflow execution, regression, and sense checks.
gridalyn.interfaces CLI, visualization, reporting entrypoints, and application-facing surfaces.

Project API

Use gridalyn.projects when building tooling around project.yaml and workflow.yaml.

from gridalyn import projects

created = projects.init_project("projects/my_case", name="my_case")
project = projects.load_project(created.root)
stages = projects.plan_project(project)
status = projects.project_status(project.root, check_artifacts=True)
verification = projects.project_verify(project.root)

Stable project imports:

Symbol Purpose
CreatedProject Result object returned by project initialization.
init_project Create a governed project workspace.
list_projects Discover project workspaces under projects/.
load_project Load a project from a workspace directory or project.yaml.
validate_project Validate the project contract.
plan_project Convert workflow metadata into executable stages.
prepare_project_workspace Create the standard outputs/ directory contract for a project run.
run_workflow Execute or dry-run project stages.
project_status Summarize contract, stages, manifests, and required reports.
project_sense_check Run declared and registered objective checks.
project_verify Run contract, artifact, report, and sense-check verification for one project.
project_verify_all Verify every governed project in the workspace.
project_regression Run a project-local numerical regression verifier when present.

Network And Adapter API

Use gridalyn.twin when applications need topology, source adapters, or semantic graph generation.

from gridalyn import twin

repo = twin.NetworkModelRepository.from_parquet("instances/default/digital_twin/base")
model = repo.load_model()
downstream = repo.get_downstream("transformer:25")
equipment = repo.get_connected_equipment("bus:17")
integrity = repo.validate_integrity()

Five things about that snippet have changed since 2026-08-12 and are worth knowing before you build on it:

  • load_model() now carries identity. The returned NetworkModel exposes .identity, a ModelIdentity with a content-addressed model:sha256:… id, read from the base metadata.json. It is None only when no manifest is present. Three of its six fields carry CGMES FullModel header semantics; artifact_paths and governance_schema_version deliberately carry none, because the values they hold do not honour one — see the ModelIdentity docstring for which is which and why.
  • validate_integrity() fails loudly on an absent artifact. It reports three states, not two: a required artifact that is missing is an error, an artifact that exists but is empty is a warning that still validates. An empty directory no longer reports valid=True.
  • from_parquet takes a provenance policy"require" | "warn" | "ignore". The default warns and records a degraded provenance_status; "require" raises FileNotFoundError naming the remedy, and is what an export uses to check its own post-condition. "ignore" additionally means the on-disk manifest is not consulted as authority, so its operational_state is neither read nor validated — which is what lets the manifest producer run against a snapshot whose current manifest is corrupt.
  • from_parquet also takes an operational_state"base" | "normal" | "current" | "planned" | "study_case", or None, which means undeclared rather than "base". load_model() resolves exactly one onto the returned NetworkModel: an explicit argument wins, else the operational_state recorded in the manifest, else "base". A manifest that records no state loads as "base" rather than failing; one recording anything outside the five is rejected, naming the path, the valid set and the remedy. A NetworkModel a source adapter builds in memory carries None, because nothing has declared which state it represents.
  • NetworkExportResult gained a required identity field — a breaking change for out-of-tree adapters. NetworkSourceAdapter is a Protocol whose export() must return one, and third-party adapters are an intended, registry-backed extension point, so an existing implementation now raises TypeError until it supplies the field. The one-line fix is identity=exported_model_identity(out_dir), which reads the manifest the export just wrote back through NetworkModelRepository — so the producer and the consumer are proven to agree rather than assumed to.

Observed state is published from the same module: twin.NetworkObservation and twin.observe_network describe what a solved network shows, with a keyword-only, caller-supplied as_of. Every NetworkObservation now carries a required provenance field (ObservationProvenance = Literal["simulated", "measured"]) — observe_network stamps "simulated" unconditionally, and construction without a provenance is a TypeError (a documented breaking change). gridalyn.simulation.observation, the deprecation shim that used to re-export these from the old pre-Phase-11 location, was deleted 2026-08-19 — import from gridalyn.twin.observation (or the gridalyn.twin/gridalyn.simulation facades above).

In 2026-08-13 the same facade was extended with the measured-state ingest path and the observation producer registry. New stable gridalyn.twin imports:

Symbol Purpose
ObservationProvenance Literal["simulated", "measured"] — the required discriminator every NetworkObservation carries, so a consumer holding only the object can tell a simulation result from a measurement.
EntityJoin User-supplied, declared entity_id → bus_id mapping for the measured ingest; the join is configuration, never inference, and an entity absent from it fails loudly.
read_measured_observations The measured producer: reads (timestamp, entity_id, quantity, value) rows against the declared measurement schema and emits one observation per instant with provenance="measured" and as_of stamped from the datum (naive timestamps are rejected, never localized).
load_measurements CSV/parquet loader for measurement frames handed to read_measured_observations; validation lives once, in the reader.
ObservationProducerRegistry Explicit-ID registry over observation producers; no entry_points discovery.
ObservationProducerDescriptor Frozen descriptor (producer_id, provenance, summary) carried by each registered producer.
default_observation_producer_registry Registry pre-loaded with the two shipped producers: powerflow (simulated, wraps observe_network) and measured-ingest (measured, wraps read_measured_observations).
UnknownObservationProducerError Raised on an unknown producer ID, listing the available IDs.
ModelAuthoritySet CGMES Model Authority Set declaration — which producer owns which canonical artifacts (parquet fields and rules; no RDF).
ModelProfile CGMES profile declaration over the parquet artifacts.

Adapter discovery uses the same module:

from pathlib import Path
from gridalyn import twin

registry = twin.default_network_adapter_registry()
available = registry.list_descriptors()
adapter = registry.create(
    "synthetic_pandapower",
    cache_dir=Path("projects/ev_hosting_flex/outputs/cache"),
    config_path=Path("configs/grid/config.json"),
)
result = adapter.export(out_dir=Path("instances/default/digital_twin/base"), root=Path("."))

Current network adapter IDs include:

Adapter ID Source ecosystem Source format
synthetic_pandapower pandapower Synthetic pandapower cache.
cim_parquet cim Lightweight CIM-like Parquet interchange.

The adapter contract is intentionally source-neutral: every adapter should produce canonical base network artifacts plus validation metadata.

Report And Governance API

Use gridalyn.foundation for report contracts, manifests, workspace paths, and artifact policy checks.

from gridalyn import foundation

foundation.write_report(
    "projects/my_case/outputs/reports/sample_report.json",
    metadata=foundation.ReportMetadata(report_id="sample_report", source_domain="my_case"),
    inputs=[foundation.file_reference("projects/my_case/outputs/data/results.parquet")],
    artifacts=[],
    summary={"ready": True},
    validation={"valid": True, "errors": [], "warnings": []},
)

Stable foundation imports include:

Symbol Purpose
GridalynWorkspace Resolved workspace layout.
workspace_from_path Resolve canonical instance, project, cache, and output paths.
check_artifact_policy Detect generated, untracked, or misplaced artifacts.
ReportMetadata Common report metadata contract.
file_reference Build a report input/artifact file reference.
build_report Build a canonical report object.
read_json_report Load a JSON report from disk.
validate_report Validate report structure and required fields.
write_manifest Write a report manifest.
write_report Write a report JSON file.
build_model_version Create a governed model-version record.
build_study_run Create a governed study-run record.

Operations API

Use gridalyn.operations when an application or workflow needs utility-facing services instead of low-level market functions.

from gridalyn import operations

events, selections, report = operations.run_flexibility_clearing_operation(
    requirements=requirements,
    providers=provider_registry,
    impact=network_impact_predictions,
    scenario_id="S4",
    dt_h=0.25,
    clearing_method="surrogate",
    model_version_id="model:sha256:...",
    study_run_id="run:...",
)

Wrap completed operation artifacts in an OperationRun for APIs, dashboards, and audit trails:

operation_run = operations.build_operation_run(
    operation_id=report["operation_context"]["operation_id"],
    operation_type="flexibility_clearing",
    scenario_id="S4",
    network_model_version_id="model:sha256:...",
    study_run_id="run:...",
    input_artifacts={"provider_registry": "instances/default/digital_twin/flexibility/provider_registry.parquet"},
    output_artifacts={"dispatch_instructions": "projects/my_case/outputs/operations/dispatch_instructions.parquet"},
    kpi_report="projects/my_case/outputs/reports/operational_kpi_report.json",
)
operations.write_operation_run("projects/my_case/outputs/operations/operation_run.json", operation_run)

Stable operations imports include provider registries, locational clearing, dispatch instructions, settlement records, operation-run contracts, operational KPI reports, network-constraint summaries, and the prosumer real-time market runner:

from gridalyn.operations import (
    ProsumerRealtimeMarketConfig,
    run_prosumer_realtime_market,
)

Asset Modeling API

Use gridalyn.assets for reusable asset, building, scenario-device, thermal-limit, and synthetic input models. Project scripts may wrap these functions to pin local configuration, but implementation should stay in the SDK.

from gridalyn import assets

thermal_model = assets.TransformerThermalModel(
    s_rated_kva=15_000.0,
    theta_max=110.0,
)
forecast = assets.build_thermal_forecast(
    336,
    resolution_minutes=5,
    s_rated_kva=15_000.0,
    theta_max=110.0,
)
metadata = assets.thermal_forecast_metadata(forecast)

assets.build_thermal_forecast is a convenience facade over the synthetic datagen forecast builder. Pure thermal-limit conversion from an explicit ambient trace lives in gridalyn.assets.modeling.thermal.

Synthetic network generation from building footprints is owned by simulation, because it creates solver-ready network objects:

from gridalyn import simulation

result = simulation.build_synthetic_network_from_geojson(
    footprints_path="projects/my_project/inputs/buildings.geojson",
    config_path="projects/my_project/inputs/synthetic_network_config.json",
    out_dir="projects/my_project/outputs/cache",
)

Lower-level synthetic trajectory generation is available through gridalyn.assets.datagen:

from gridalyn.assets.datagen import GridLoadFacade, download_tmy, select_cold_day

tmy = download_tmy()
weather = select_cold_day(tmy)["temp_air"]
heat_kw, background_kw = GridLoadFacade.generate_loads(
    "parametric",
    weather,
    n_houses=100,
    resolution_minutes=15,
    seed=42,
)

Treat this surface as a reproducible synthetic baseline. Project reports should record generator type, seed, weather window, and any calibration assumptions.

Time-Series IO API

Use gridalyn.twin.io when workflow code needs to read time-series artifacts without binding itself to a specific project directory.

from pathlib import Path
from gridalyn.twin.io import get_baseline_building_load_all

baseline_kw = get_baseline_building_load_all(
    data_dir=Path("projects/ev_hosting_flex/outputs/data"),
)

Simulation API

Use gridalyn.simulation for solver engines and validation analytics. The SDK keeps solver-specific dependencies behind optional extras when possible, while the public objects remain stable.

from gridalyn import assets, simulation

feeder = simulation.build_voltage_control_feeder(...)
env = simulation.VoltageControlEnvironment(...)

Stable simulation helpers also include build_radial_pandapower_feeder, write_pandapower_element_tables, write_voltage_profile_figure, write_powerflow_report, StandardPowerflowScenario, and run_standard_powerflow_scenario. Project scripts should use these helpers instead of duplicating pandapower table/report/scenario code.

gridalyn.simulation.surrogates exposes the accuracy contract: a surrogate that stands in for a physical model states a measured ErrorBound or is refused. measure_error_bound(predicted, observed, *, metric, units, reference, method) measures any surrogate against any physical reference in that domain's own units; measure_relief_error_bound is the network-impact specialisation of it, and unmeasured_error_bound is how a surrogate declares a located reason for having no number rather than quietly reporting zero.

See Solver And Model Adapters for the adapter contract and optional solver capability groups.

Semantic Graph API

Use gridalyn.twin or the semantic CLI to convert digital-twin artifacts into node and edge tables.

uv run gridalyn semantic build --profile north_america
uv run gridalyn semantic validate --semantic-dir instances/default/digital_twin/semantic

Use SemanticGraphRepository for relationship queries over the materialized graph:

from gridalyn import twin

semantic = twin.SemanticGraphRepository.from_parquet("instances/default/digital_twin/semantic")
providers = semantic.providers_for_constraint("transformer:64", scenario_id="S4")
trace = semantic.trace_building_to_constraint("building:123", scenario_id="S4")

Boundary Rule

Reusable code belongs in the Gridalyn SDK. Project scripts may orchestrate a study, but they should not become hidden platform APIs. When another workflow needs the same behavior, move the behavior into gridalyn and keep the project script as a thin wrapper.

Preferred Entry Point

Prefer importing the module that owns the responsibility:

from gridalyn import assets, foundation, operations, projects, simulation, twin

project = projects.load_project("projects/ev_hosting_flex")
workspace = foundation.workspace_from_path(".")
repository = twin.NetworkModelRepository.from_parquet("instances/default/digital_twin/base")
registry = operations.build_provider_registry(...)