Skip to content

Migrate to the PowerAnalytics 1.0 metrics API - #1

Open
PabloBotin wants to merge 9 commits into
mainfrom
feature/migrate-to-poweranalytics-new-api
Open

Migrate to the PowerAnalytics 1.0 metrics API#1
PabloBotin wants to merge 9 commits into
mainfrom
feature/migrate-to-poweranalytics-new-api

Conversation

@PabloBotin

@PabloBotin PabloBotin commented Jul 27, 2026

Copy link
Copy Markdown
Owner

Tackles the PowerAnalytics old-API deprecation: PowerAnalytics deprecated its pre-1.0
accessors (get_generation_data, get_load_data, get_service_data, categorize_data,
PowerData, ...) in favor of the 1.0 Metric/ComponentSelector API — see the
"Old PowerAnalytics" notice
in its reference docs ("This interface predates the 1.0 version and will eventually be
deprecated") and the tracking issue
Sienna-Platform/PowerAnalytics.jl#28.
This PR moves PowerGraphics' internals onto the new API without breaking any public
signature, so PowerGraphics is ready before the old interface is removed.

Commits

  1. test: pin fuel stack and demand plot behavior — behavior contract (column ordering,
    In/Out signs, curtailment/slack names, demand naming) pinned on the old implementation
    before touching anything.
  2. refactor: use PA.get_system instead of reaching through PA.PSI.
  3. refactor: migrate plot_demand to the PowerAnalytics metrics API — Results path on
    calc_load_forecast; column naming unchanged.
  4. refactor: migrate plot_fuel to the metrics/selectors API — per-component metric
    evaluation with a variable → parameter → aux-variable fallback chain, storage/source
    In/Out split, curtailment, and slacks reassembled on the new API.
  5. refactor: reimplement plot_results internally; deprecate plot_powerdata(::PowerData)
    plot_results no longer constructs PA.PowerData; the plot_powerdata methods live in
    src/deprecated.jl as forwarding shims that warn.
  6. docs: update report template and document the migration.

Bug fixes along the way

  • The plot_fuel net-load line now includes storage charging / source input, as its
    comment always claimed; previously the computed offset was dropped.
  • plot_results(...; combine_categories = false) used to crash; it now plots one trace
    per stored column, and the docstrings state the actual default (true).
  • Fixed two fuel-enum typos in the test mapping yaml (AG_BYPRODUCT, WOOD_WASTE_SOLIDS);
    the new parser validates enum names, the old one silently never matched them.
  • Time windowing (initial_time/horizon, start_time/len) is applied locally by row
    slicing because PowerAnalytics.compute currently mishandles window kwargs on
    simulation results (TODO comment filed in code).
  • Demand plots no longer show a separate Dispatchable_Load trace for
    dispatchable/interruptible load formulations (the old rename_load! split; no new-API
    metric exists) — that load folds into the single "Load" trace.
  • ext_category entries in custom generator mapping yamls are ignored by the new selector
    parser: those rules match without the ext discrimination, and a @warn is emitted.
  • The report template's Services table was removed (no new-API service metric; a comment
    in the template points to the DIY compute route).
  • Generation/curtailment membership is now availability-filtered via the Results path —
    practically benign, since unavailable components have no results.
  • Unmapped generators are reported in one aggregate @error instead of one per component.

Intentionally still on the old API

  • plot_demand(::PSY.System) (get_load_data(::System) has no new-API equivalent),
    no_datetime on user-supplied DataFrames (copy semantics), and the deprecated
    plot_powerdata(::PowerData) shims. PowerAnalytics still exports and maintains the old
    API, so these keep working unchanged until a future breaking release.
  • A few PowerAnalytics gaps surfaced during the migration and are worked around locally,
    each marked with a # TODO upstream comment: broken compute time-window kwargs, a stale
    get_subselectors export, inconsistent missing-result error types, missing
    calc_system_slack_down/forecast metrics, and parse_generator_categories returning
    nothing. Every workaround becomes an optional simplification once these are fixed upstream.

Pin the current fuel/demand data contract ahead of the PowerAnalytics
metrics-API migration: category naming (In/Out split, Curtailment, slack
display names), charging sign conventions, palette-first column ordering,
demand column naming, time-window and filter_func kwargs, and per-backend
series counts.
PowerAnalytics imports get_system from PowerSimulations, so the unexported
PA.PSI alias is unnecessary. Also extend the missing-system error to mention
loading results with populate_system = true.
The IS.Results path now computes Metrics.calc_load_forecast over the all_loads
selector (grouped into a single column renamed to "Load" so palette and label
behavior are unchanged); a user filter_func folds into the selector. Time
windows (initial_time/horizon, also spelled start_time/len) are applied by
local row slicing because compute rejects unknown kwargs and mishandles len on
simulation results in PA 1.4. The PSY.System path stays on the old
get_load_data API, which has no new-API equivalent. The dead isnothing guard
on the aggregated demand frame is replaced by an isempty check that can
actually fire.
Assemble the fuel stack from PowerAnalytics Metric/ComponentSelector
primitives instead of get_generation_data/make_fuel_dictionary/
categorize_data/combine_categories, preserving the exact column set, order,
names, and signs. Components are assigned to a single category by replaying
the old first-match-wins priority over the per-rule subselectors (the
independent new selectors would otherwise double-count, e.g. NG-CC vs
NG-Steam); generators fall back variable -> forecast parameter -> PowerOutput
aux; storage/sources split into '<category> In'/'<category> Out' with charging
flipped negative; slacks keep their BALANCE_SLACKVARS display names; unmatched
components go to 'Other' with an error log.

Also fix the net-load overlay to actually include storage charging by passing
the charging total as extra_load, update the test mapping yaml for the new
parser's strict fuel enums, and pin both behaviors with new tests.
…ta(::PowerData)

plot_results now owns its dict-of-DataFrames path (DateTime stripped per entry,
time axis from the first entry) instead of constructing PowerAnalytics.PowerData.
The plot_powerdata methods move to src/deprecated.jl as forwarding shims that
warn about removal in a future breaking release. combine_categories = false no
longer crashes: it plots one trace per stored column, and the docstrings now
state the actual default (true).
The Weave report template's tables now use the PowerAnalytics metrics API
(calc_active_power per fuel category, calc_system_load_forecast) instead of the
deprecated get_generation_data/get_load_data accessors; the Services table is
dropped since get_service_data has no metrics-API equivalent. Docstrings drop
the never-functional plot_fuel 'variables' kwarg, document the storage/sources
kwargs, and reference plot_results instead of the deprecated plot_powerdata.
The public API reference gains a hand-written Deprecated section.
@PabloBotin PabloBotin changed the title Migrate off deprecated PowerAnalytics pre-1.0 API (phase 1: pinning tests, get_system, plot_demand) Migrate to the PowerAnalytics 1.0 metrics API Jul 27, 2026
- plot_demand no longer crashes when a load type has no results; missing
  results skip to the "No load data found" path (now an ArgumentError)
- warn on the unsupported `variables` kwarg of plot_fuel instead of
  silently ignoring it
- warn when a custom generator mapping yaml contains ext_category keys,
  which the PowerAnalytics 1.0 selector parser cannot honor
- _combine_result_categories: unknown `names` entries raise an actionable
  ArgumentError; Vector{Symbol} accepted for the deprecated powerdata path
- docstrings: aggregate scope (System path only), time-window kwargs and
  aliases, aggregate-function return-shape contract
- _FuelRule stores type_name::Symbol to avoid per-supertype allocations
- test: old-vs-new numeric equivalence of fuel category traces
…names

Every plot function now takes `backend::PlottingBackend`, defaulting to
`CairoMakieBackend()`:

    plot_fuel(res)                                 # CairoMakie
    plot_fuel(res; backend = PlotlyLightBackend()) # PlotlyLight

The backend was already modeled as a value in src/backends.jl, so encoding it in
the function name doubled the public API without buying any dispatch. The ten
`_plotly`-suffixed functions keep working but warn and forward. Passing both a
`_plotly` name and a `backend` key word raises an ArgumentError rather than
letting one silently win, since the two would disagree about the renderer.

Eight per-plot behaviors that were resolved twice, once in each recipe, are now
resolved once in call_plots.jl and handed to the recipes through _PlotOptions:
fill default, line width, line style, draw order, title sentinel, empty input,
save path, and palette selection.

User-visible changes:

- Both backends select from the whole palette returned by `load_palette`, so
  more series get a distinct color before the cycle repeats. PlotlyLight
  previously drew from a narrower set, so its default colors change.
- `_default_save_format` dispatches on the backend, making the PlotlyLight
  default `html`. A shared hardcoded "png" tripped the extension-rewrite warning
  on every default-path PlotlyLight save. An explicit `format` still wins.
- CairoMakie non-stacked draw order now matches PlotlyLight.
- WeaveExt = ["PlotlyLight", "Weave"] -> "Weave". Neither the extension nor
  generic_report_template.jmd touches PlotlyLight, so the old trigger withheld
  `report` from a CairoMakie-only user.

The backend stubs dispatch per concrete backend. With `backend` defaulting to
CairoMakie, a PlotlyLight-only user reached a stub telling them to run `using
PlotlyLight` when they already had; each stub now names its own package, and the
CairoMakie one names the key word that selects the other backend.

Two save-path defects go with it. `_resolve_save_file` is now the single place a
save path is decided, and it replaces spaces in the title with underscores as
every entry point on main already did; centralizing the path had dropped that
for `plot_dataframe` alone. `_plot_demand!` read `:save` without removing it
from the key words it forwarded, so one call saved the figure twice under two
different names; it now strips `:save`, `:title`, and `:set_display` like the
other wrappers.

Tests: plot_introspection.jl reads rendered marks back out of both libraries so
value assertions run against either backend; test_backend_parity.jl enforces the
parity contract; test_demand_semantics.jl and test_fuel_categories.jl pin the
demand sign and the fuel-rule specificity. Suite is at 368 pass / 0 fail.

Docs gain explanation/backend_parity.md and a Change Backends how-to; the
orphaned explanation/stub.md is removed. Personal notes are ignored through the
user-level git ignore rather than this repository's shared .gitignore.
@PabloBotin
PabloBotin force-pushed the feature/migrate-to-poweranalytics-new-api branch from d9d0097 to b89dc10 Compare July 29, 2026 22:32
Route the report template's Load table through the new public
`get_demand_data` rather than `calc_system_load_forecast`, which reported the
requested instead of the served demand and disagreed with `plot_demand` under
controllable load formulations.

Delegate `_combine_result_categories` to `PowerAnalytics.combine_categories`
instead of reimplementing it, keeping only the actionable error on an unknown
`names` entry.

Move `seriescolor`, `column_labels`, `interval`, the scaled data matrix and the
net-sign classification into `_PlotOptions`, so neither recipe derives them
independently and the third spelling of the sign test disappears.

Lowercase the extension in the PlotlyLight writer so `.HTML` is recognized
rather than silently rewritten to a different path, and pin it with a test.

Hoist the shared "Accepted Key Words" documentation into
`_COMMON_PLOT_KWARGS` and interpolate it, replacing eight verbatim copies.

Keep `_report_plot_fuel` as a forwarding shim: report templates copied from an
earlier release call it positionally, so removing it would throw
`UndefVarError` on their next `report`.
@PabloBotin
PabloBotin force-pushed the feature/migrate-to-poweranalytics-new-api branch from b89dc10 to 39be6fe Compare July 29, 2026 22:34
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant