API and Services Reference
Public API
SparlectraApp.SparlectraApiArtifact — Type
SparlectraApiArtifactMetadata for one file produced or discovered by run_sparlectra_api. Artifact paths are absolute so callers do not need to know Sparlectra's internal file naming or working-directory conventions.
SparlectraApp.SparlectraApiResult — Type
SparlectraApiResultStable, non-interactive result returned by run_sparlectra_api. Each result has a unique run_id and a schema_version for transport consumers. The raw_result field contains the underlying SparlectraRunResult for a completed solver invocation and is nothing for input or configuration errors. Use the serialization helpers for transport-safe representations that omit raw_result by default.
SparlectraApp.list_powerflow_artifacts — Method
list_powerflow_artifacts(run_id::AbstractString)Return transport-safe metadata for artifacts currently available for a registered local PowerFlow service run. Unknown run IDs are returned as a structured service failure dictionary.
SparlectraApp.resolve_powerflow_artifact — Method
resolve_powerflow_artifact(run_id::AbstractString, artifact_name::AbstractString)Resolve an artifact by its metadata name, never by an arbitrary filesystem path. Absolute paths, traversal components, Windows-style paths, missing files, and artifacts escaping the selected run directory are returned as structured failures.
SparlectraApp.collect_sparlectra_api_artifacts — Method
collect_sparlectra_api_artifacts(output_dir) -> Vector{SparlectraApiArtifact}Discover files beneath an API run directory and return deterministic artifact metadata. This is the only filename-discovery contract needed by GUI clients.
SparlectraApp.get_powerflow_result — Method
get_powerflow_result(run_id::AbstractString) -> Dict{String,Any}Return serialized metadata for a registered local PowerFlow service run.
If the run ID is unknown, return a structured service failure dictionary instead of throwing, so Web UI callers can render a stable error response.
SparlectraApp.start_powerflow_run — Method
start_powerflow_run(request::AbstractDict; case_directory=nothing) -> Dict{String,Any}Start one local PowerFlow service run above run_sparlectra_api. The request must provide casefile, config_file, and output_root; optional config_overrides are forwarded to the programmatic API. A unique run ID is chosen before execution, and all generated files are written beneath output_root/run_id. Completed API runs, including failed runs with a result.json, are registered in memory and in the persistent run index. Public service failures are returned as structured dictionaries.
When case_directory is provided by a trusted caller, bare .m case names are resolved there through ensure_casefile and remain the executed source. Generated Julia cache files in that directory are hidden from the Web UI service path: explicit .jl requests resolve to a matching .m source when present and are rejected otherwise.
SparlectraApp.run_sparlectra_api — Method
run_sparlectra_api(; casefile, config_file, output_dir, config_overrides=Dict(),
performance_timing=:off, run_diagnostics=false,
detailed_result_csv=false,
detailed_result_csv_format="technical",
detailed_result_csv_semicolon=false) -> SparlectraApiResultRun one MATPOWER power-flow case through a stable, non-interactive API contract. The function validates GUI overrides, writes effective_config.yaml, delegates the numerical work to run_sparlectra, captures textual output in run.log, writes result.json, discovers all generated files, and returns structured status and artifact metadata. The input configuration template is never modified. performance_timing may be :off, :compact, or :full and writes a single-run performance.log; run_diagnostics=true captures existing PowerFlow diagnostic printers in diagnose.log; and detailed_result_csv=true writes Excel-friendly bus-voltage and branch-flow CSV artifacts. Optional detailed_result_csv_format accepts auto, technical, excel_de, or excel_us. The legacy detailed_result_csv_semicolon=true maps to excel_de when the explicit format is omitted. Artifact generation does not change PowerFlow run success.
SparlectraApp.POWERFLOW_RUN_INDEX_FILENAME — Constant
File name of the persistent run index the service writes under its output root.
SparlectraApp.delete_all_powerflow_runs — Method
delete_all_powerflow_runs(; output_root::AbstractString) -> Dict{String,Any}Delete all safely registered PowerFlow run directories beneath output_root. Entries that cannot be validated or removed remain indexed and are reported in failed_runs; deletion never follows an indexed path outside the output root.
SparlectraApp.delete_powerflow_run — Method
delete_powerflow_run(run_id::AbstractString; output_root::AbstractString) -> Dict{String,Any}Delete one registered PowerFlow run beneath output_root. The run ID must be a safe index entry whose directory is exactly <output_root>/<run_id>; arbitrary paths and unregistered directories are never removed.
SparlectraApp.list_powerflow_runs — Method
list_powerflow_runs(output_root::AbstractString) -> Vector{Dict{String,Any}}List runs from the persistent index for a future run-history UI. Each entry has an available flag; missing directories, missing result.json files, and unsafe indexed paths are described by a structured reason instead of raising.
SparlectraApp.load_powerflow_run_index — Method
load_powerflow_run_index(output_root::AbstractString) -> Dict{String,Any}Load the persistent PowerFlow run index beneath output_root. A missing or unreadable index returns an empty transport-safe index. Invalid top-level content is reported through reason and message without throwing.
SparlectraApp.refresh_powerflow_run_registry! — Method
refresh_powerflow_run_registry!(output_root::AbstractString) -> Dict{String,Any}Reload valid PowerFlow service runs from the persistent index under output_root into the in-process registry. Runs that were active when the Web UI stopped are marked as stale aborted results before registration, while invalid or missing entries are reported in unavailable_runs.
SparlectraApp.run_fixed_reference_self_check — Method
run_fixed_reference_self_check(; casefile, config_file=DEFAULT_SPARLECTRA_CONFIG_PATH,
output_dir, config_overrides=Dict(), case_format=:auto) -> SparlectraApiResultEvaluate the Newton-Raphson mismatch at a case's own stored operating point, without letting any start-value machinery adjust it. Where a normal run answers "does this case converge with the configured start/step-control settings?", the self-check answers a narrower, model-focused question: is the case's own recorded operating point already close to power balance under Sparlectra's imported network model? A large residual here points at the imported network model (branch parameters, shifted angles, a wrong per-unit convention) rather than at the solver's start guess or step control.
Supported inputs:
- MATPOWER (
case_format = :matpower/:auto): evaluates at the case's storedVM/VAcolumns. - CGMES (
case_format = :cgmes): evaluates at the delivery'sSvVoltagestate, which the importer writes into the bus objects at creation time. Buses without a usableSvVoltagekeep the importer's1.0 pu / 0°fallback; their count is reported inself_check.logand per bus in thehas_svcolumn ofself_check_residuals.csv— a large no-SV share weakens the interpretation of the residual.self_check.logalso lists the tap changers whoseSvPowerFlowfits another step clearly better than theirSvTapStep, with both steps and mismatches.
Arguments
casefile: case path (MATPOWER file or CGMES delivery), forwarded torun_sparlectra_api.config_file: base configuration; the self-check settings are merged on top of it (see "How" below), so any other settings inconfig_file(e.g. import conventions) still apply.output_dir: forwarded torun_sparlectra_api; all normal run artifacts (includingdiagnose.log) are written here, plusself_check.logandself_check_residuals.csv.config_overrides: optional furtherGUI_EDITABLE_CONFIG_KEYSoverrides. They adjust everything the self-check does not force (power_flow.tolfor the reported mismatch classification, for instance); a forced key stays forced, because a fixed reference the caller can move is not a reference.
How
The forced settings ride the explicit override level, the only one above a case configuration file, plus a merged temporary configuration file for the two keys the override allowlist does not admit (see the comment at the top of src/api/run_self_check.jl). Forces power_flow.max_iter = 1, power_flow.qlimits.enabled = false, and every start-value machine off (start_mode.flatstart = false, start_mode.start_projection = false, start_mode.dc_seed_unconditional = false, start_current_iteration.enabled = false, apslf_start.enabled = false), then runs through run_sparlectra_api with diagnostics enabled. The imported bus voltages therefore reach the solver verbatim; the only remaining adjustment is the solver pinning the slack magnitude to its regulating setpoint (noted in self_check.log).
Returns
A SparlectraApiResult. success reflects whether the run completed, not whether the residual is small — read self_check.log's start_state_residual_inf (the max |P|/|Q| residual at the unmodified start state) or raw_result.final_mismatch (after the single corrective step) for that. self_check_residuals.csv holds the full per-bus residual export for attribution.
SparlectraApp.to_dict — Method
Convert artifact metadata to a transport-safe dictionary.
SparlectraApp.to_dict — Method
to_dict(result::SparlectraApiResult; include_raw_result=false) -> Dict{String,Any}Convert an API result to a transport-safe dictionary. raw_result is omitted by default because the solved network is not a stable JSON/YAML transport type.
SparlectraApp.to_json — Method
Serialize an API result as JSON without an additional JSON package.
SparlectraApp.to_namedtuple — Method
Convert an API result to a transport-safe NamedTuple.
SparlectraApp.to_yaml — Method
Serialize an API result as YAML without an additional YAML package.
Application entry points
The Web UI server and the build tools live outside the reference page set (app/src/webui/, app/src/sysimage_builder.jl); their exported entry points render here.
SparlectraApp.start_sparlectra_webui — Function
start_sparlectra_webui(; host="127.0.0.1", port=8080,
output_root=nothing,
config_file=DEFAULT_SPARLECTRA_CONFIG_PATH,
open_browser=false,
shutdown_on_browser_close=false) -> Union{Nothing,SparlectraWebUIServer}Start the loopback-only PowerFlow interface and load its persistent run registry before accepting requests. The returned handle can be stopped with close(server) or the browser's Stop Web UI button. When the requested port is already held by another Sparlectra Web UI (probed via its /powerflow page), no error is raised: the running instance is opened in the browser (with open_browser = true) and nothing is returned: stop that instance first to actually restart. A foreign process on the port still raises the explicit ArgumentError. Browser-process lifetime is not used for automatic shutdown by default because common browsers may return a short-lived launcher process instead of a reliably owned window.
SparlectraApp.default_webui_output_root — Function
default_webui_output_root() -> StringReturn the operating-system-specific, user-writable directory used for Web UI runs, downloaded MATPOWER cases, and the operation log.
SparlectraApp.default_webui_config_path — Function
Return the user-writable default Web UI configuration path.
SparlectraApp.default_webui_case_cache_dir — Function
Return the user-writable MATPOWER case cache used by the Web UI.
SparlectraApp.default_webui_operation_log_path — Function
Return the Web UI operation-log path beneath the user application root.
SparlectraApp.buildSysimage — Function
buildSysimage(; dry_run = false, quiet = false) -> NamedTupleBuild the Sparlectra sysimage with one call.
The build precompiles the interactive paths through a workload (power flow on the embedded cases small to large: case3, case14, case118; a state-estimation run with bad-data diagnostics; an N-1 contingency run; a CGMES import with short circuit; network losses and the result/diagnostics printers), so the Web UI afterwards starts in seconds instead of paying JIT compilation on every first click.
This takes a while: typically 10 to 20 minutes of CPU time, a few GB of RAM, and roughly half a GB of disk for the image. Run it once after installing or updating Sparlectra, not before every session. The launch scripts (start_webui.sh / start_webui.bat) pick the image up automatically on the next start; bypass it with SPARLECTRA_NO_SYSIMAGE=1.
PackageCompiler is installed into the shared @sparlectra-sysimage-build environment on first use (one-time network access); the package's own dependencies stay untouched. The build runs in a child Julia process, so the calling session keeps its active project.
Keyword arguments:
dry_run = trueonly reports the target paths without building.quiet = truesuppresses the build output.
Returns (sysimage_path, meta_path, built, size_mb).
Internals
SparlectraApp._service_fold_csv_format! — Method
_service_fold_csv_format!(config_overrides, request) -> Dict{String,Any}The request-level CSV keys of older callers (detailed_result_csv_format, detailed_result_csv_semicolon) folded into the one configuration key output.csv_format (issue #386): every service below reads the format from the run's configuration only, so a run type without the form field (state estimation) cannot fall back to a request default. An explicit config_overrides entry wins over the request keys. Throws ArgumentError on an unknown format name.
SparlectraApp._ApiRunOptions — Type
_ApiRunOptionsThe loosely typed run options of _run_sparlectra_api in one concrete carrier with Any fields. The 800-line body below is compiled once per distinct signature, and every call site used to bring its own combination of types (a String or a Symbol for the format, nothing or a path, a different closure type for each callback), so the body was inferred over and over: fourteen specializations of about three seconds each in one test group. Behind one struct the body has one specialization, and the values keep their meaning: the normalizers inside still see the raw value.
SparlectraApp._matpower_calc_export_name — Method
_matpower_calc_export_name(case_path) -> StringFile name of the MATPOWER export artifact of a run: <case stem>_calc_<YYYYMMDD>.m. A new file, never the input file; the date is compact because the stem is also the MATLAB function name of the case (function mpc = case118_calc_20260930) and a hyphen is not allowed there. Characters outside [A-Za-z0-9_] in the stem are replaced by _ for the same reason.
SparlectraApp._bus_powers_rows — Method
_bus_powers_rows(net::Net) -> Vector{NamedTuple}Build the per-bus rows for bus_powers.csv. Reuses the same data sources as the console result table and the Q-V characteristic check so the values agree on one run (issue #376):
- generation/load:
_bus_power_component_cache(same cache the detailed bus CSV and the console table read); - shunt: the node's own
_pShunt/_qShunt(not carried byBusPowerComponents, read directly as the console table does); bus_type_start/bus_type_end/q_limit_side: a bus can only ever move PV -> PQ under Q-limit enforcement (Slack and originally-PQ/Isolated buses never change type), sobus_type_startisPVexactly for the buses in the pre-solve snapshot (net.qLimitInitialPVRows, the same snapshotq_limit_initial_limits.csvuses) and the CURRENT type otherwise;bus_type_endis the current type with a*suffix while the bus sits innet.qLimitEvents, matching the star the console table prints;non_physical: a bus is flagged exactly whenqvCharacteristicViolationsreports it (clamped at a limit with the voltage on the wrong side of its setpoint) - the same rowsprintQVCharacteristicCheckprints;control/control_target_bus/control_status/vm_setpoint_pu: combines the Q(U)/P(U)/HVDC flags from_bus_control_flag_cachewith the RVC/STATCOM (machine) and SVC/MSC (shunt) outer controllers and the voltage-mode tap-changer target (_tap_voltage_target_by_bus), i.e. exactly the labels the console result table's Control column shows (results.jl, thefacts_bus_labels/_cached_control_labelblock) plusOLTC_targetfor a tap-controller's regulated bus, which the console table does not currently label at all.control_target_busis populated for the machine's own bus row of an RVC/STATCOM controller (the bus it regulates); for theOLTC_targetrow itself there is no further "other" bus to name, so it stays empty there - a deliberate asymmetry, not a gap.
SparlectraApp._write_bus_powers_artifact — Method
_write_bus_powers_artifact(output_dir, net; format = "technical") -> StringWrite bus_powers.csv next to bus_voltages_complex.csv (issue #376). See _bus_powers_rows for the per-bus values and how they are kept consistent with the console Q-V characteristic check and controller summary. format selects the delimiter/decimal separator like every other CSV artifact of the run (_resolve_detailed_csv_format).
SparlectraApp._run_contingency_service — Method
_run_contingency_service(case_path, config_file, output_dir, run_id, kind; weights_path = nothing) -> SparlectraApiResultService backend of the Web UI "Contingency (N-1)" button. Builds the net (MATPOWER through the shared config-driven import path, CGMES through importCGMES), enumerates single-element outages for kind ("branch" or "gen"), evaluates them with runContingencies! using config.contingency.rescue_ladder, writes contingency_n1.csv plus a run.log narrative built from buildContingencyReport, and returns a SparlectraApiResult through the normal result conventions.
When weights_path names an existing per-case weight file it is read with readContingencyWeightsCSV and applied with applyContingencyWeights after case generation; the presence of the file IS the switch (there is no request key). Weights only reorder the severity ranking, never skip a case. Names that match no case are warned about in the run.log (a weight list can outlive a case edit), never fatal; a file that cannot be read leaves the run unweighted rather than failing it. The metadata reports contingency_weights_applied and contingency_weighted_cases.
An outage that removes the reference (the slack unit itself, or the branch that ties it to an island) does not end the case: the run solves with auto_slack, the best remaining unit takes over (stated reference priority first, then the strongest unit; an island without a voltage-controlled unit takes its best generating unit), and the row names the bus ("reference taken over by bus ..."). Only an island without any generating unit stays without a reference and is reported as islanded with the load it loses.
Scenario task step 5: the request may carry scenario_source (file_block runs the case file's own scenarios block through the scenario model, external_file a scenario JSON named by scenario_file, n1_all/n1_branches/n1_generators the generated case lists) and screening_mode (off/flag/only; absent means the contingency.screening configuration, default off). With screening active the CSV gains the screened/screening_estimate columns and the metadata reports contingency_screening_mode and contingency_screened.
progress (default nothing) is handed to runContingencies! / runScenarios! unchanged: a thread-safe callable progress(done, total) called once per finished outage or scenario. The Web UI job passes one that stores the counter in the job snapshot (see webui_jobs.jl).
Failure behavior: contingency_unsupported_format (not MATPOWER, CGMES, PowSyBl or Sparlectra Case Format), contingency_no_cases (no in-service element of the requested kind), invalid_request (bad kind, unknown scenario_source or screening_mode, missing scenario_file), plus the shared import/config failures.
SparlectraApp._write_diagnosis_narrative — Method
_write_diagnosis_narrative(io, result)Write the "Diagnosis" and "Recommendations" sections of diagnose.log: a short prose summary of what the worst-mismatch bus, mismatch trend, and autodamp behavior indicate, followed by a "Worst-mismatch bus" data section (reusing the same top_mismatch_rows already computed once per solve by _rectangular_mismatch_diagnostics) and a "Branch anomalies" section from _branch_anomaly_diagnostics for the branches incident to that bus. This turns a flat key/value dump into a report that names a likely cause and a next step, instead of only reporting numbers.
SparlectraApp._write_execution_failure_diagnostics — Method
_write_execution_failure_diagnostics(path, reason, message)Write a best-effort diagnose.log when a run fails before a SparlectraRunResult is available — e.g. run_sparlectra throwing for an AC-island failure with a non-finite mismatch before the first Newton iteration (stage=before_nr), or an unsupported MATPOWER DC-line convention. Without this, run_diagnostics = true silently produced no diagnose.log at all for these early/exception failures, since the normal _write_powerflow_diagnostics call site is only reached after run_sparlectra returns successfully. Rich per-bus/branch diagnostics need a solved network, which this failure mode never reaches; per-island detail, when available, lives in ac_island_<id>_solver.log.
SparlectraApp._write_start_residuals_artifact — Method
_write_start_residuals_artifact(output_dir, profile) -> Union{Nothing,String}Write self_check_residuals.csv from the per-bus start-state mismatch rows the rectangular solver captured into profile[:initial_residual_rows] (see _capture_initial_residual_rows!; captured only on diagnostics/self-check runs). One row per bus with the start voltages, the P residual, the Q residual (PQ buses only — PV/slack second equations are voltage setpoints), the per-bus SV coverage on CGMES imports (has_sv, true for other formats), and transformer-terminal/shunt counts for attribution grouping. When the same bus was captured more than once (e.g. a rescue re-solve), the last capture wins. Returns the artifact path, or nothing when no rows were captured. format (technical/excel_de/excel_us, see _resolve_detailed_csv_format) sets the delimiter and number formatting for this artifact, matching every other CSV the run writes (issue #376).
SparlectraApp._capture_run_output — Method
_capture_run_output(f, io; live=false)Run f() with stdout/stderr/logging captured into io (the archived run.log stream). With live = true (config output.console_live) the same bytes are additionally mirrored to the process's real stdout while the run executes — console and archive become two views of one stream instead of the console being silenced. The archive content is identical in both modes.
Implementation note: redirect_stdout needs an OS-level stream, so the live mode tees through a Pipe pumped by an async task; the pump is drained before returning so io is complete when the caller closes the logfile.
SparlectraApp._write_service_performance_log! — Method
_write_service_performance_log!(output_dir, recorder, total_start_ns; headline, status, label)Write performance.log for a service run that has no SparlectraRunResult of its own: state estimation, contingency, short circuit, import analysis. The power-flow path writes the same file through _write_performance_log with its result object; these runs supply only their phase recorder.
headline maps the summary keys at the top of the file to phase names of this service, for example (:case_loading_network_solver => "importing_case", :solver => "state_estimation"). Phases that never ran are left out instead of printed as zero.
Called on the success path AND on early exits worth timing (a non-converged estimation is exactly the run whose timing someone wants to see). Never raises: a failed timing file must not turn a finished run into an error. Returns the recorder's timings so the caller can put them into result.json as service_phase_timings.
SparlectraApp._run_import_analysis_service — Method
_run_import_analysis_service(case_path, config_file, output_dir, run_id) -> SparlectraApiResultService backend of the Web UI "Analyze import" button: loads the CGMES delivery files (boundary resolution shared with the power-flow path — same _cgmes_delivery_paths), builds the importFailureAnalysis report, and writes it as import_analysis.txt next to run.log. No mapping and no power-flow solve is involved, so the check answers well before a full import would.
Failure reasons: import_analysis_requires_cgmes for non-CGMES cases, cgmes_read_error when the delivery files cannot even be parsed.
SparlectraApp._powerflow_run_index_solver — Method
Method name for the run history, taken from what ACTUALLY ran.
The history used a hard "rectangular" default whenever the run outcome carried no solver of its own. That claimed the rectangular Newton-Raphson power flow for every kind of run: a state estimation solves weighted least squares, a short circuit is a direct IEC 60909 solve, and an import analysis solves nothing at all. Seen on an SE run listed as rectangular.
The names match the configuration keys a user can set (power_flow.method, state_estimation.method), so the column and the configuration speak the same language. An import analysis reports an empty method rather than an invented one.
SparlectraApp._final_q_check_summary — Method
_final_q_check_summary(raw_result) -> NamedTupleThe final Q-limit check of a run as the service reports it: status, buses, max_dev_pu from the solver status and the one line (final_q_check_line) that goes into run.log, the metadata and the result page next to the Q-V verdict.
SparlectraApp._qv_characteristic_summary — Method
_qv_characteristic_summary(net, converged) -> NamedTupleThe Q-V characteristic verdict of a solved network in one line, the same finding the classic result print reports through printQVCharacteristicCheck: machines that ended at a reactive limit with the voltage on the wrong side of their setpoint (non-physical solution). Fields: states (rows), significant (rows beyond the band), buses (the significant ones, ;-joined) and line. Two switching strategies need not end on the same point; whether the point is physical is what a reader has to see, so this line goes into run.log, the result metadata (qv_characteristic_line, qv_non_physical_states, qv_non_physical_buses) and the Web UI result page.
SparlectraApp._self_check_effective_overrides — Function
_self_check_effective_overrides(config_overrides) -> Dict{String,Any}Caller overrides with the forced self-check settings ON TOP. A caller may adjust everything the self-check does not force (power_flow.tol, for instance); a forced key cannot be overridden, because a fixed reference that the caller can move is not a reference. The Web UI form is such a caller: it submits power_flow.max_iter and friends with every run.
SparlectraApp._self_check_forced_gui_overrides — Method
_self_check_forced_gui_overrides() -> Dict{String,Any}The forced self-check settings as flat override keys, i.e. the subset of _self_check_forced_overrides that GUI_EDITABLE_CONFIG_KEYS admits.
SparlectraApp._run_short_circuit_powsybl — Method
_run_short_circuit_powsybl(case_path, config, ...) -> SparlectraApiResultShort-circuit run on a PowSyBl case (an IIDM file or a table bundle). The sources are the connected generators of the file. A generator with the IIDM extension generatorShortCircuit contributes its subtransient reactance; one without it is evaluated with the engine's documented default and every row that depends on it is flagged, so the result of a file without any short-circuit data is complete but says on every row that it rests on defaults. Both cases are evaluated on all buses (short_circuit_max.csv, short_circuit_min.csv).
A run in which no generator carries short-circuit data ends with status warning (reason short_circuit_defaults_only), and the statement leads the message and run.log.
Failure behavior: import_error when the case does not import, short_circuit_data_missing when the file carries no connected generator or when no generator carries short-circuit data or a rated power, short_circuit_error when the evaluation fails.
SparlectraApp._run_short_circuit_scf — Method
_run_short_circuit_scf(case_path, config, ...) -> SparlectraApiResultShort-circuit run on a Sparlectra Case Format case (#342). The file carries its own IEC 60909 source data in sparlectra.components.sc_source and may define the study in sparlectra.short_circuit: which case is the headline (max/min), the c_factor, and whether the sweep covers all buses or a listed selection.
Both cases are always evaluated, so short_circuit_max.csv and short_circuit_min.csv exist for every format; the file's case decides which one the headline numbers come from. A c_factor in the file loses against an explicitly configured short_circuit.c_factor (a case file sits below API and CLI overrides), and applies when the configuration is at its default.
SparlectraApp._run_short_circuit_service — Method
_run_short_circuit_service(case_path, config_file, output_dir, run_id) -> SparlectraApiResultService backend of the Web UI "Short circuit" button: imports the CGMES delivery (boundary resolution shared with the power-flow path), evaluates runShortCircuit! for both cases, writes short_circuit_max.csv / short_circuit_min.csv plus a run.log narrative including the short-circuit coverage report, and returns a SparlectraApiResult through the normal result conventions (result.json, artifact scan, run registry).
Failure behavior — explicit reasons instead of empty tables:
short_circuit_requires_cgmes: the case is neither a CGMES delivery nor a Sparlectra Case Format case (MATPOWER/DTF carry no harvested short-circuit data yet, issue #277 follow-up).cgmes_import_error/cgmes_boundary_missing: import failed.short_circuit_data_missing: the delivery imported but carries no usable short-circuit source (every bus would report:no_source).
SparlectraApp._run_pf_from_se_service — Method
_run_pf_from_se_service(case_path, config_file, output_dir, run_id, se_state_file, se_run_id, se_mode) -> SparlectraApiResultSE-started power-flow chain run: builds the net, restores the estimated state from se_state_file (the se_state.csv of a preceding SE run), and runs runpf_from_se! with se_mode ("se_state" or "se_snapshot"). The persistent model is never mutated (the snapshot's balance takeover lives on the working import only). Metadata records the start mode, the referenced SE run id, and the slack pickup.
SparlectraApp._run_state_estimation_service — Method
_run_state_estimation_service(case_path, config_file, output_dir, run_id, measurement_file; kwargs...) -> SparlectraApiResultService backend of the Web UI "Run state estimation" action (SE phase 5). Builds the net through the shared import paths, reads measurement_file (a measurement table; without one, the set an SCF case carries), evaluates global observability (structural islands plus FD-aware rank, phase 4), runs the bad-data diagnostics (runse_diagnostics, sequential elimination on the configured budget) and the final runse!(updateNet = true), and writes the SE artifacts: measurements.csv (the estimated set as a measurement table, comments carried over; the run estimates the set this file reads back to), measurements_verdict.csv (the verdict per table row), se_diagnostics.md, se_view.md, shunt_estimates.csv (when shunts were released), and se_state.csv (the chain anchor a later SE-started power flow consumes via readSEStateCSV!).
Options: max_iter, tol, flatstart, robust, max_eliminations, update_shunts, report_correlation mirror the estimator keywords. tap_estimation = true releases the tap of every in-service transformer that carries a ratio tap changer (setTapEstimation! mode :ratio) before the solve; the estimator then fixes each tap to its nearest mechanical step and reports J before versus after the fixation (se_tap_estimates.csv). That release is staged: one solve with the taps frozen first, the estimate from that state, kept only if its fixed positions fit at least as well as the model positions (otherwise the frozen-tap fallback, reason worse_fit). The internal keyword tap_staged_start = false keeps the release cold (regression fixtures only).
Failure reasons: se_unsupported_format, import_error, invalid_measurements (missing/unreadable/rejected file), se_not_observable (observability quality :not_observable), se_not_converged, plus the shared config failure.
SparlectraApp._se_convert_measurements_v1 — Method
_se_convert_measurements_v1(case_path, v1_path, out; config_file = DEFAULT_SPARLECTRA_CONFIG_PATH, requested_format = :auto) -> NamedTupleconvertMeasurementsV1 for a case file: imports the case the way the SE service does (effective configuration of config_file and the case; requested_format as the service's case_format, needed for a bare DTF .DAT) and writes the table with the key index the service reads it with (mRIDs for a CGMES case, element names otherwise). Returns the result of convertMeasurementsV1. Throws ArgumentError when a CGMES import keeps no CGMES model, and the reader's error for a v1 file it refuses.
SparlectraApp._se_criticality_lines — Method
_se_criticality_lines(net, obs) -> Vector{String}The criticality report of a state-estimation run as plain lines: the count per method, the critical rows BY NAME (or "none", so a reader never has to infer criticality from a wii column), and the nearly critical rows with their wii. Written to the run log and to se_diagnostics.md.
SparlectraApp._se_import_case — Method
_se_import_case(case_path, config) -> ImportedCaseImport a case for the state-estimation workflow through the one import entry point. Throws on unsupported formats and on import errors. Shared by the SE service run and the Web UI measurement generator so both accept exactly the same cases, and both run with ImportedCase.config (the CGMES start-value decision and the auto-profile rewrites reach the SE solves exactly like the power-flow service).
SparlectraApp._se_truth_run_warning — Method
_se_truth_run_warning(metadata) -> StringThe warning a measurement set inherits from the run it takes its truth state from: empty for a clean run, otherwise one sentence naming why the state is no solution of the model (state estimation outside the band, taps frozen at model positions, a non-converged run). Flows derived from such a state violate the node balances, and the set then contradicts the model before any estimation (a set built from a fallback run far outside the band produced KCL findings at every passive bus).
SparlectraApp.MeasurementGeneratorOptions — Type
MeasurementGeneratorOptions(; kwargs...)Options of the measurement generator _se_generate_measurement_set. The fields carry the same names, defaults and meaning as the former keyword arguments of the generator; fields without a default are required keywords. Every combination is validated at construction, so an invalid request throws ArgumentError with a user-readable text BEFORE any case is imported (the Web UI handler shows the text as its redirect message).
Fields:
noise: seeded gaussian noise on the generated values (falsegives an ideal set whose J is 0 by construction).gross_k,gross_count: bad data ofgross_ksigma ongross_countseed-randomly drawn telemetry rows (gross_k = 0for none;gross_countmust be at least 1).tap_steps,tap_count: mechanical tap deviation oftap_stepssteps on up totap_countseed-randomly drawn in-service transformers (0.0for none; whole steps only, the Web UI enforces this;tap_countat least 1).include_i: current magnitude rows on top of the power rows.sigma_u_pct,sigma_i_pct,sigma_p_pct,sigma_q_pct: sigmas in percent of reading per quantity.sigma_ia_deg: PMU current-angle sigma in degrees;0.0means no angle rows.truth_source::fresh_solve(solve the configured power flow at reference tightness) or:from_run(adopt the solved voltages of runrun_idunderrun_rootwithout re-solving; needs both and is mutually exclusive with a tap deviation).flow_ends::bothkeeps both flow ends per branch,:one_balance_awarekeeps one, chosen by the injection telemetry at the terminal buses.passive_sigma,passive_as_zi: passive-node balances as protected zero-injection constraints (true) or as balance rows atpassive_sigma(MW; must be positive).nothing(the default) takes the case's effectivestate_estimation.zero_injection(onandconstraintaretrue), the switch every SE path of the case reads.seed: RNG seed; the same seed regenerates the identical set.critical_count: number of rows to make critical by targeted thinning (0= off; must be zero or positive).
SparlectraApp._se_generate_measurement_set — Method
_se_generate_measurement_set(case_path, out_path, opts::MeasurementGeneratorOptions; config_file) -> NamedTupleService backend of the Web UI measurement generator (the Web UI layer never calls a solver directly). With the settings in opts (see MeasurementGeneratorOptions for every field): import the case through the shared SE import paths, optionally shift up to tap_count seed-randomly selected in-service transformers by tap_steps MECHANICAL steps each on their own grids (the seed decides WHICH transformers, non-machine declared changers are drawn first), obtain the truth state (truth_source = :fresh_solve solves the configured power flow at reference tightness; :from_run adopts the solved voltages of run run_id under run_root without re-solving), optionally keep only one balance-aware flow end per branch (flow_ends), rewrite passive-node balances at passive_sigma or as protected zero-injection constraints (passive_as_zi), thin the set by targeted partner removal until critical_count rows are critical, generate a measurement table with percent-of-reading sigmas (a row at a level of state_estimation.sigma_by_voltage_level takes the level sigma, its noise drawn at that sigma), optional seeded noise, optional currents and current angles, optional gross errors (gross_k sigma on gross_count seed-randomly selected telemetry rows; protected zero-injection rows are never corrupted), readable name-based ids, the structured tap comment table, and the in-file case binding.
Returns (rows, noisy, tap_note, gross_note, island_note, truth_note, flow_note, passive_note, critical_note, sigma_level_rows, measurements, not_written) for the caller's confirmation message; rows counts the rows of the written measurement table, sigma_level_rows the rows with a level sigma, measurements is the generated set before it is written and not_written lists the rows the table cannot carry (a negative current magnitude drawn by the noise), also named in the file. Side effect: writes out_path. Throws ArgumentError with a user-readable text when the case has no in-service transformer for a requested deviation, the requested run state is missing or bound to another case, or the power flow does not converge; the option combination itself is already validated by the constructor of opts.
SparlectraApp._seeded_permutation — Method
_seeded_permutation(rng, v) -> VectorA random permutation of v that depends only on the RNG's Float64 stream. Random.shuffle changed its algorithm in Julia 1.13: the same MersenneTwister seed then drew other rows than on 1.12, so a generated set with "bad data on 1 row" hit a different measurement per Julia version (found when the extended profile went red on 1.13 only). The Float64 stream of the Mersenne Twister is the same on both, so ordering by one uniform draw per element keeps "the seed decides which rows" true across Julia versions.
SparlectraApp.start_webui_powerflow_run — Method
start_webui_powerflow_run(request; case_directory=nothing, runner=start_powerflow_run)Start one Web UI PowerFlow job in a background task. Only one active Web UI job is accepted at a time. Cancellation is cooperative: an abort request releases the UI immediately and the worker discards any later solver success.