# pnnl/ll-risk-assessment architecture

> Architecture diagram of the GitHub repository pnnl/ll-risk-assessment, generated by GitDiagram from its file tree, README and a sample of source files (last updated 2026-06-12). It is an AI-made overview: check details against the source.

- Interactive diagram: https://gitdiagram.com/pnnl/ll-risk-assessment
- Repository: https://github.com/pnnl/ll-risk-assessment

## Overview

1. **What this repository is**
   This is a **batch Python workflow around PSS/E** for assessing risk from large dynamic digital loads (LDDLs). It is not a web service or library package; the architecture is a **sequence of standalone scripts** that pass files between stages.

2. **Primary boundary: Python orchestration vs. PSS/E simulation engine**
   The Python scripts call into **PSS/E v35** to read power-flow and dynamic cases, modify models, run time-domain simulations, and extract channel outputs. The main external dependency is the local PSS/E installation configured in `psse_config.py`.

3. **Input case layer**
   Network models live in `PSSE_Cases/` as `.sav`, `.raw`, and `.dyr` files. These are the base system artifacts that every stage reads and/or clones. The repo includes a WECC 240-bus example plus legacy/demo cases in `RATLLE_v1.0/PSSE_Cases/`.

4. **Configuration-driven control plane**
   User choices are not hardcoded into the pipeline; they come from CSVs:
   - `Pre_Screening_config.csv` for screening and modal prep
   - `modal_analysis_config.csv` for impulse and mode estimation
   - `simulation_config.csv` for oscillation scenario definition  
   These configs determine case name, bus, load size, oscillation shape, frequency, and amplitude.

5. **Stage 1: case extraction and system summaries**
   `Step1_extract_case_info.py` reads the base PSS/E case and writes structured summaries into `Processing/`:
   buses, branches, generators, loads, and areas. These CSVs become the data foundation for later selection, monitoring, and reporting steps.

6. **Module 1: pre-screening for vulnerable locations**
   `Step2a_locational_sensitivity.py` computes local sensitivity metrics such as **dV/dP, dV/dQ, and dθ/dP** by applying small fictitious injections at candidate buses.  
   `Step2b_load_impulse.py` injects a load impulse at a selected bus and records the ringdown response.  
   `Step2c_mode_estimates.py` analyzes that response to identify excitable oscillatory modes.  
   Together, these scripts narrow the search space from “entire system” to “specific risky buses and frequencies.”

7. **Module 2: simulation model preparation**
   `Step3a_simsetup_loadadd.py` transforms a chosen load into an LDDL scenario by modifying the case, creating `LLmod.sav`, `LLmod.snp`, and a modified `.dyr`. It also adds the oscillation injection block.  
   `Step3b_simsetup_monitoredqty.py` generates the monitored bus/branch/load/generator lists used for channel logging during simulation.  
   This stage is the main **model-boundary transition** from screening artifacts to executable dynamic simulation setup.

8. **Stage 4: dynamic simulation execution**
   `Step4_runsim.py` runs the PSS/E time-domain simulation using the scenario parameters from `simulation_config.csv`.  
   The outputs are scenario-tagged and stored in `results/` as simulation traces, typically a `.out` file plus a CSV export. The naming convention keeps multiple runs side-by-side without overwriting.

9. **Module 3: post-simulation risk analysis**
   `Step5_analyze_sim.py` reads simulation time series and computes risk metrics for buses, generators, lines, loads, and LDDL-related quantities. It produces summary and detail CSVs for threshold violations, worst elements, and time-series metrics.  
   This is the main data-reduction boundary: dense simulation traces become decision-oriented risk reports.

10. **Visualization and engineering checks**
   `Step6_metrics_visualization.py` turns analysis outputs into a self-contained HTML dashboard in `results/`, making the risk output directly reviewable without rerunning PSS/E.  
   `Step7a_distance_z3_reach.py` adds a protection-oriented boundary check by comparing apparent impedance trajectories against a Zone 3 distance relay reach.  
   `Step7b_RAS_check.py` evaluates simple remedial action scheme trigger rules against the simulated time series.

11. **Working directories and artifact flow**
   `Processing/` is the intermediate workspace for extracted case data, sensitivities, impulse responses, and monitored-element lists.  
   `results/` is the final output workspace for simulation traces, metrics, violation tables, and dashboards.  
   The overall flow is: **base case → extracted summaries → pre-screening/modal analysis → modified LDDL case + monitored channels → dynamic run → metrics/visualization/protection checks**.

12. **Legacy/packaged subproject**
   `RATLLE_v1.0/` is a self-contained version of the same workflow with its own case examples, input configs, scripts, and documentation. Architecturally it mirrors the root-level pipeline, so you can treat it as an older packaged distribution rather than a separate subsystem.

Main entry points: [`Processing`](https://github.com/pnnl/ll-risk-assessment/tree/main/Processing) (Processing), [`results`](https://github.com/pnnl/ll-risk-assessment/tree/main/results) (Results), [`Step2a_locational_sensitivity.py`](https://github.com/pnnl/ll-risk-assessment/blob/main/Step2a_locational_sensitivity.py) (Sensitivity), [`Step2b_load_impulse.py`](https://github.com/pnnl/ll-risk-assessment/blob/main/Step2b_load_impulse.py) (Impulse test)

## Diagram (Mermaid)

```mermaid
flowchart TD

subgraph group_root["Root workflow"]
  node_psse_config["PSS/E config<br/>[psse_config.py]"]
  node_cfg_screen["Screen config<br/>config csv"]
  node_cfg_modal["Modal config<br/>config csv"]
  node_cfg_sim["Sim config<br/>config csv"]
  node_case_base[("Base cases<br/>psse cases")]
  node_step1["Extract case<br/>case summary"]
  node_processing[("Processing<br/>workspace")]
  node_step2a["Sensitivity<br/>screening"]
  node_step2b["Impulse test<br/>response test"]
  node_step2c["Mode estimates<br/>modal analysis"]
  node_step3a["Build LDDL<br/>model setup"]
  node_step3b["Monitor setup<br/>channel setup"]
  node_step4["Run sim<br/>dynamic simulation<br/>[Step4_runsim.py]"]
  node_results[("Results<br/>output workspace")]
  node_step5["Analyze risk<br/>postprocess"]
  node_step6["Visualize metrics<br/>dashboard"]
  node_step7a["Zone 3 check<br/>protection check"]
  node_step7b["RAS check<br/>protection check"]
end

subgraph group_legacy["Legacy package"]
  node_legacy_pkg[("RATLLE v1.0<br/>legacy workflow<br/>[RATLLE_v1.0]")]
  node_legacy_main["Legacy main<br/>orchestrator"]
  node_legacy_summary["Legacy summary<br/>system summary<br/>[system_summary.py]"]
  node_legacy_viz["Legacy viz<br/>visualization"]
end

subgraph group_external["External engine"]
  node_psse_engine{{"PSS/E v35<br/>simulation engine"}}
end

node_psse_config -->|"configures"| node_psse_engine
node_case_base -->|"input"| node_step1
node_psse_engine -->|"reads"| node_step1
node_step1 -->|"writes"| node_processing
node_cfg_screen -->|"drives"| node_step2a
node_processing -->|"reads"| node_step2a
node_psse_engine -->|"simulates"| node_step2a
node_step2a -->|"writes"| node_processing
node_cfg_modal -->|"drives"| node_step2b
node_step2a -->|"selects"| node_step2b
node_psse_engine -->|"simulates"| node_step2b
node_step2b -->|"writes"| node_processing
node_step2b -->|"feeds"| node_step2c
node_cfg_modal -->|"drives"| node_step2c
node_step2c -->|"writes"| node_processing
node_cfg_sim -->|"drives"| node_step3a
node_processing -->|"reads"| node_step3a
node_case_base -->|"clones"| node_step3a
node_step3a -->|"writes"| node_processing
node_step3b -->|"writes"| node_processing
node_cfg_sim -->|"drives"| node_step4
node_step3a -->|"inputs"| node_step4
node_step3b -->|"inputs"| node_step4
node_psse_engine -->|"runs"| node_step4
node_step4 -->|"writes"| node_results
node_results -->|"reads"| node_step5
node_step5 -->|"writes"| node_results
node_step5 -->|"feeds"| node_step6
node_results -->|"reads"| node_step6
node_results -->|"reads"| node_step7a
node_results -->|"reads"| node_step7b
node_legacy_pkg -->|"contains"| node_legacy_main
node_legacy_main -->|"uses"| node_legacy_summary
node_legacy_main -->|"uses"| node_legacy_viz
node_legacy_pkg -->|"ships cases"| node_case_base

click node_psse_config "https://github.com/pnnl/ll-risk-assessment/blob/main/psse_config.py"
click node_cfg_screen "https://github.com/pnnl/ll-risk-assessment/blob/main/Pre_Screening_config.csv"
click node_cfg_modal "https://github.com/pnnl/ll-risk-assessment/blob/main/modal_analysis_config.csv"
click node_cfg_sim "https://github.com/pnnl/ll-risk-assessment/blob/main/simulation_config.csv"
click node_case_base "https://github.com/pnnl/ll-risk-assessment/tree/main/PSSE_Cases"
click node_step1 "https://github.com/pnnl/ll-risk-assessment/blob/main/Step1_extract_case_info.py"
click node_processing "https://github.com/pnnl/ll-risk-assessment/tree/main/Processing"
click node_step2a "https://github.com/pnnl/ll-risk-assessment/blob/main/Step2a_locational_sensitivity.py"
click node_step2b "https://github.com/pnnl/ll-risk-assessment/blob/main/Step2b_load_impulse.py"
click node_step2c "https://github.com/pnnl/ll-risk-assessment/blob/main/Step2c_mode_estimates.py"
click node_step3a "https://github.com/pnnl/ll-risk-assessment/blob/main/Step3a_simsetup_loadadd.py"
click node_step3b "https://github.com/pnnl/ll-risk-assessment/blob/main/Step3b_simsetup_monitoredqty.py"
click node_step4 "https://github.com/pnnl/ll-risk-assessment/blob/main/Step4_runsim.py"
click node_results "https://github.com/pnnl/ll-risk-assessment/tree/main/results"
click node_step5 "https://github.com/pnnl/ll-risk-assessment/blob/main/Step5_analyze_sim.py"
click node_step6 "https://github.com/pnnl/ll-risk-assessment/blob/main/Step6_metrics_visualization.py"
click node_step7a "https://github.com/pnnl/ll-risk-assessment/blob/main/Step7a_distance_z3_reach.py"
click node_step7b "https://github.com/pnnl/ll-risk-assessment/blob/main/Step7b_RAS_check.py"
click node_legacy_pkg "https://github.com/pnnl/ll-risk-assessment/blob/main/RATLLE_v1.0"
click node_legacy_main "https://github.com/pnnl/ll-risk-assessment/blob/main/RATLLE_v1.0/main_LL_risk_assessment.py"
click node_legacy_summary "https://github.com/pnnl/ll-risk-assessment/blob/main/RATLLE_v1.0/system_summary.py"
click node_legacy_viz "https://github.com/pnnl/ll-risk-assessment/blob/main/RATLLE_v1.0/LDDL_Viz_Functions.py"

classDef toneNeutral fill:#f8fafc,stroke:#334155,stroke-width:1.5px,color:#0f172a
classDef toneBlue fill:#dbeafe,stroke:#2563eb,stroke-width:1.5px,color:#172554
classDef toneAmber fill:#fef3c7,stroke:#d97706,stroke-width:1.5px,color:#78350f
classDef toneMint fill:#dcfce7,stroke:#16a34a,stroke-width:1.5px,color:#14532d
classDef toneRose fill:#ffe4e6,stroke:#e11d48,stroke-width:1.5px,color:#881337
classDef toneIndigo fill:#e0e7ff,stroke:#4f46e5,stroke-width:1.5px,color:#312e81
classDef toneTeal fill:#ccfbf1,stroke:#0f766e,stroke-width:1.5px,color:#134e4a
class node_psse_config,node_cfg_screen,node_cfg_modal,node_cfg_sim,node_case_base,node_step1,node_processing,node_step2a,node_step2b,node_step2c,node_step3a,node_step3b,node_step4,node_results,node_step5,node_step6,node_step7a,node_step7b toneBlue
class node_legacy_pkg,node_legacy_main,node_legacy_summary,node_legacy_viz toneAmber
class node_psse_engine toneMint
```

## Components

### Root workflow

Current batch pipeline for PSS/E-based LDDL risk assessment

- [PSS/E config](https://github.com/pnnl/ll-risk-assessment/blob/main/psse_config.py): config · Local engine configuration and import setup · `psse_config.py`
- [Screen config](https://github.com/pnnl/ll-risk-assessment/blob/main/Pre_Screening_config.csv): config csv · Pre-screening and modal-analysis parameters · `Pre_Screening_config.csv`
- [Modal config](https://github.com/pnnl/ll-risk-assessment/blob/main/modal_analysis_config.csv): config csv · Impulse and mode-estimation parameters · `modal_analysis_config.csv`
- [Sim config](https://github.com/pnnl/ll-risk-assessment/blob/main/simulation_config.csv): config csv · Dynamic scenario definition for simulation runs · `simulation_config.csv`
- [Base cases](https://github.com/pnnl/ll-risk-assessment/tree/main/PSSE_Cases): psse cases · Source power-flow and dynamic cases · `PSSE_Cases`
- [Extract case](https://github.com/pnnl/ll-risk-assessment/blob/main/Step1_extract_case_info.py): case summary · Reads the base case and writes buses, branches, generators, loads, and areas · `Step1_extract_case_info.py`
- [Processing](https://github.com/pnnl/ll-risk-assessment/tree/main/Processing): workspace · Intermediate artifacts for summaries, sensitivities, impulse responses, and monitored lists · `Processing`
- [Sensitivity](https://github.com/pnnl/ll-risk-assessment/blob/main/Step2a_locational_sensitivity.py): screening · Computes local voltage and angle sensitivities around candidate buses · `Step2a_locational_sensitivity.py`
- [Impulse test](https://github.com/pnnl/ll-risk-assessment/blob/main/Step2b_load_impulse.py): response test · Injects a load impulse and records ringdown response · `Step2b_load_impulse.py`
- [Mode estimates](https://github.com/pnnl/ll-risk-assessment/blob/main/Step2c_mode_estimates.py): modal analysis · Extracts excitable oscillatory modes from impulse response · `Step2c_mode_estimates.py`
- [Build LDDL](https://github.com/pnnl/ll-risk-assessment/blob/main/Step3a_simsetup_loadadd.py): model setup · Modifies the case into an LDDL scenario and writes modified case artifacts · `Step3a_simsetup_loadadd.py`
- [Monitor setup](https://github.com/pnnl/ll-risk-assessment/blob/main/Step3b_simsetup_monitoredqty.py): channel setup · Generates monitored buses, branches, loads, and generators for simulation logging · `Step3b_simsetup_monitoredqty.py`
- [Run sim](https://github.com/pnnl/ll-risk-assessment/blob/main/Step4_runsim.py): dynamic simulation · Executes the PSS/E time-domain run and exports scenario-tagged traces · `Step4_runsim.py`
- [Results](https://github.com/pnnl/ll-risk-assessment/tree/main/results): output workspace · Final simulation traces, metrics, violation tables, and dashboards · `results`
- [Analyze risk](https://github.com/pnnl/ll-risk-assessment/blob/main/Step5_analyze_sim.py): postprocess · Computes risk metrics and violation summaries from simulation time series · `Step5_analyze_sim.py`
- [Visualize metrics](https://github.com/pnnl/ll-risk-assessment/blob/main/Step6_metrics_visualization.py): dashboard · Builds a self-contained HTML risk dashboard · `Step6_metrics_visualization.py`
- [Zone 3 check](https://github.com/pnnl/ll-risk-assessment/blob/main/Step7a_distance_z3_reach.py): protection check · Tests apparent-impedance trajectories against distance relay reach · `Step7a_distance_z3_reach.py`
- [RAS check](https://github.com/pnnl/ll-risk-assessment/blob/main/Step7b_RAS_check.py): protection check · Evaluates remedial action scheme trigger rules against simulation output · `Step7b_RAS_check.py`

### Legacy package

Older packaged distribution that mirrors the root workflow

- [RATLLE v1.0](https://github.com/pnnl/ll-risk-assessment/blob/main/RATLLE_v1.0): legacy workflow · Older self-contained distribution of the same workflow · `RATLLE_v1.0`
- [Legacy main](https://github.com/pnnl/ll-risk-assessment/blob/main/RATLLE_v1.0/main_LL_risk_assessment.py): orchestrator · Legacy end-to-end risk assessment driver · `RATLLE_v1.0/main_LL_risk_assessment.py`
- [Legacy summary](https://github.com/pnnl/ll-risk-assessment/blob/main/RATLLE_v1.0/system_summary.py): system summary · Legacy case summary generator · `RATLLE_v1.0/system_summary.py`
- [Legacy viz](https://github.com/pnnl/ll-risk-assessment/blob/main/RATLLE_v1.0/LDDL_Viz_Functions.py): visualization · Legacy plotting and visualization helpers · `RATLLE_v1.0/LDDL_Viz_Functions.py`

### External engine

Local PSS/E installation used to read cases, run dynamics, and export channels

- **PSS/E v35**: simulation engine · External dynamic simulation and case-processing engine

## Connections

- PSS/E config → PSS/E v35: configures · Sets up access to the local PSS/E installation
- Base cases → Extract case: input · Base cases are summarized into structured system data
- PSS/E v35 → Extract case: reads · PSS/E reads the case model during extraction
- Extract case → Processing: writes · Exports bus, branch, generator, load, and area summaries
- Screen config → Sensitivity: drives · Provides pre-screening choices and candidate-bus parameters
- Processing → Sensitivity: reads · Uses extracted system summaries for sensitivity calculations
- PSS/E v35 → Sensitivity: simulates · Applies fictitious injections through PSS/E
- Sensitivity → Processing: writes · Stores sensitivity metrics for later selection
- Modal config → Impulse test: drives · Provides impulse and modal-analysis settings
- Sensitivity → Impulse test: selects · Narrows the candidate bus for impulse testing
- PSS/E v35 → Impulse test: simulates · Runs the impulse perturbation and ringdown capture
- Impulse test → Processing: writes · Stores impulse traces and response data
- Impulse test → Mode estimates: feeds · Impulse response is analyzed for oscillatory modes
- Modal config → Mode estimates: drives · Provides frequency and analysis settings
- Mode estimates → Processing: writes · Stores modal estimates and dominant frequencies
- Sim config → Build LDDL: drives · Selects scenario bus, load size, oscillation shape, frequency, and amplitude
- Processing → Build LDDL: reads · Uses selected bus and monitored context for case modification
- Base cases → Build LDDL: clones · Creates modified LDDL case artifacts from the base model
- Build LDDL → Processing: writes · Creates modified case files such as LLmod.sav and LLmod.snp
- Monitor setup → Processing: writes · Exports monitored buses, lines, loads, and generators
- Sim config → Run sim: drives · Provides the scenario parameters for the run
- Build LDDL → Run sim: inputs · Supplies the modified dynamic case for execution
- Monitor setup → Run sim: inputs · Supplies channel lists for logging
- PSS/E v35 → Run sim: runs · Executes the time-domain simulation in PSS/E
- Run sim → Results: writes · Stores run traces and scenario-tagged outputs
- Results → Analyze risk: reads · Consumes simulation traces for risk scoring
- Analyze risk → Results: writes · Produces metrics, violations, and worst-element summaries
- Analyze risk → Visualize metrics: feeds · Analysis outputs are turned into a dashboard
- Results → Visualize metrics: reads · Uses metrics and time-series outputs for visualization
- Results → Zone 3 check: reads · Uses simulation trajectories for relay reach evaluation
- Results → RAS check: reads · Uses simulation trajectories for RAS rule evaluation
- RATLLE v1.0 → Legacy main: contains · Packaged legacy end-to-end workflow
- Legacy main → Legacy summary: uses · Legacy driver relies on system summaries
- Legacy main → Legacy viz: uses · Legacy driver relies on visualization helpers
- RATLLE v1.0 → Base cases: ships cases · Legacy package includes example PSS/E cases
