flextool 4.0.0__py3-none-any.whl
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- flextool/__init__.py +41 -0
- flextool/_mem_sampler.py +193 -0
- flextool/_resources.py +43 -0
- flextool/calibrate/__init__.py +51 -0
- flextool/calibrate/__main__.py +11 -0
- flextool/calibrate/_cli.py +316 -0
- flextool/calibrate/_db_alt.py +166 -0
- flextool/calibrate/_final_outputs.py +110 -0
- flextool/calibrate/_guard.py +151 -0
- flextool/calibrate/_loop.py +558 -0
- flextool/calibrate/_readers.py +223 -0
- flextool/calibrate/_report.py +263 -0
- flextool/calibrate/_sizing.py +699 -0
- flextool/calibrate/_solve.py +134 -0
- flextool/calibrate/_solve_status.py +495 -0
- flextool/cli/__init__.py +9 -0
- flextool/cli/_console.py +51 -0
- flextool/cli/_timing.py +147 -0
- flextool/cli/cmd_execute_flextool_workflow.py +187 -0
- flextool/cli/cmd_export_to_tabular.py +56 -0
- flextool/cli/cmd_import_sensitivities.py +75 -0
- flextool/cli/cmd_migrate_database.py +13 -0
- flextool/cli/cmd_open_results_db.py +269 -0
- flextool/cli/cmd_read_matpower.py +66 -0
- flextool/cli/cmd_read_old_flextool.py +63 -0
- flextool/cli/cmd_read_self_describing_tabular_input.py +50 -0
- flextool/cli/cmd_read_tabular_input.py +81 -0
- flextool/cli/cmd_run_flextool.py +1095 -0
- flextool/cli/cmd_scenario_results.py +284 -0
- flextool/cli/cmd_solve_mps.py +169 -0
- flextool/cli/cmd_update_flextool.py +17 -0
- flextool/cli/cmd_write_outputs.py +125 -0
- flextool/common_utils/__init__.py +1 -0
- flextool/common_utils/plot_mem_shape.py +77 -0
- flextool/common_utils/precision.py +451 -0
- flextool/decomposition/__init__.py +0 -0
- flextool/decomposition/region_decomposition.py +128 -0
- flextool/decomposition/region_filter.py +1261 -0
- flextool/engine_polars/__init__.py +110 -0
- flextool/engine_polars/_axis_enums.py +742 -0
- flextool/engine_polars/_benders.py +3462 -0
- flextool/engine_polars/_block_layout.py +1479 -0
- flextool/engine_polars/_blocks.py +1515 -0
- flextool/engine_polars/_commodity_ladder.py +660 -0
- flextool/engine_polars/_cumulative_invest.py +1165 -0
- flextool/engine_polars/_db_loader.py +153 -0
- flextool/engine_polars/_db_reader.py +127 -0
- flextool/engine_polars/_dc_power_flow.py +445 -0
- flextool/engine_polars/_delay.py +442 -0
- flextool/engine_polars/_derived_arithmetic.py +432 -0
- flextool/engine_polars/_derived_block.py +990 -0
- flextool/engine_polars/_derived_branch.py +769 -0
- flextool/engine_polars/_derived_existing.py +1353 -0
- flextool/engine_polars/_derived_npv.py +1297 -0
- flextool/engine_polars/_derived_params.py +9850 -0
- flextool/engine_polars/_derived_profile.py +881 -0
- flextool/engine_polars/_derived_walks.py +276 -0
- flextool/engine_polars/_determinism.py +70 -0
- flextool/engine_polars/_direct_params.py +2186 -0
- flextool/engine_polars/_dump_csvs.py +1009 -0
- flextool/engine_polars/_emit_arc_unions.py +1631 -0
- flextool/engine_polars/_emit_calc_params.py +729 -0
- flextool/engine_polars/_emit_chain_params.py +709 -0
- flextool/engine_polars/_emit_co2_accumulators.py +400 -0
- flextool/engine_polars/_emit_dispatchers.py +690 -0
- flextool/engine_polars/_emit_energy_margin.py +125 -0
- flextool/engine_polars/_emit_energy_margin_adder.py +290 -0
- flextool/engine_polars/_emit_entity_annual.py +428 -0
- flextool/engine_polars/_emit_inflow_scaling.py +1420 -0
- flextool/engine_polars/_emit_leaf_sets.py +550 -0
- flextool/engine_polars/_emit_lp_scaling.py +665 -0
- flextool/engine_polars/_emit_mid_sets.py +859 -0
- flextool/engine_polars/_emit_pdt_params.py +759 -0
- flextool/engine_polars/_emit_per_solve.py +774 -0
- flextool/engine_polars/_emit_period_calc.py +504 -0
- flextool/engine_polars/_emit_period_params.py +2398 -0
- flextool/engine_polars/_emit_provider_io.py +141 -0
- flextool/engine_polars/_emit_reserve.py +574 -0
- flextool/engine_polars/_emit_solve_time.py +311 -0
- flextool/engine_polars/_emit_solve_writers.py +1249 -0
- flextool/engine_polars/_flex_data_accumulator.py +388 -0
- flextool/engine_polars/_flex_data_provider.py +478 -0
- flextool/engine_polars/_group_slack.py +1253 -0
- flextool/engine_polars/_inmemory_reader.py +140 -0
- flextool/engine_polars/_input_source.py +336 -0
- flextool/engine_polars/_invest_seeds.py +191 -0
- flextool/engine_polars/_native_input_writer.py +100 -0
- flextool/engine_polars/_native_run_model.py +1348 -0
- flextool/engine_polars/_orchestration.py +4314 -0
- flextool/engine_polars/_output_writer.py +439 -0
- flextool/engine_polars/_param_shapes.py +1595 -0
- flextool/engine_polars/_parquet_bundle.py +723 -0
- flextool/engine_polars/_pdt_join.py +167 -0
- flextool/engine_polars/_pdt_lookup.py +547 -0
- flextool/engine_polars/_per_solve_sets.py +335 -0
- flextool/engine_polars/_projection_params.py +2056 -0
- flextool/engine_polars/_provider_keys.py +173 -0
- flextool/engine_polars/_provider_translators.py +225 -0
- flextool/engine_polars/_recursive_solve.py +703 -0
- flextool/engine_polars/_region_filter.py +2508 -0
- flextool/engine_polars/_reserve.py +649 -0
- flextool/engine_polars/_solve_acceptance.py +331 -0
- flextool/engine_polars/_solve_config.py +1001 -0
- flextool/engine_polars/_solve_context.py +885 -0
- flextool/engine_polars/_solve_handoff.py +164 -0
- flextool/engine_polars/_solve_state.py +232 -0
- flextool/engine_polars/_solver_base.py +36 -0
- flextool/engine_polars/_solver_dispatch.py +511 -0
- flextool/engine_polars/_spinedb_reader.py +1165 -0
- flextool/engine_polars/_stochastic.py +593 -0
- flextool/engine_polars/_subprocess_solve.py +1838 -0
- flextool/engine_polars/_timeline.py +1416 -0
- flextool/engine_polars/_vectorize.py +438 -0
- flextool/engine_polars/_warm.py +858 -0
- flextool/engine_polars/autoscale/__init__.py +107 -0
- flextool/engine_polars/autoscale/_config.py +218 -0
- flextool/engine_polars/autoscale/_layer2.py +1253 -0
- flextool/engine_polars/autoscale/_layer2_types.py +584 -0
- flextool/engine_polars/autoscale/_quantity_types.py +621 -0
- flextool/engine_polars/autoscale/_report.py +336 -0
- flextool/engine_polars/chain.py +259 -0
- flextool/engine_polars/input.py +6638 -0
- flextool/engine_polars/model.py +4754 -0
- flextool/env_check.py +388 -0
- flextool/export_to_tabular/__init__.py +5 -0
- flextool/export_to_tabular/db_reader.py +224 -0
- flextool/export_to_tabular/excel_writer.py +3559 -0
- flextool/export_to_tabular/export_settings.yaml +377 -0
- flextool/export_to_tabular/export_to_excel.py +227 -0
- flextool/export_to_tabular/formatting.py +543 -0
- flextool/export_to_tabular/sheet_config.py +876 -0
- flextool/gui/__init__.py +0 -0
- flextool/gui/__main__.py +118 -0
- flextool/gui/calibrate_commands.py +184 -0
- flextool/gui/calibrate_jobs.py +424 -0
- flextool/gui/check_tree.py +142 -0
- flextool/gui/cli_format.py +83 -0
- flextool/gui/config_parser.py +68 -0
- flextool/gui/data_models.py +362 -0
- flextool/gui/db_editor_integration.py +202 -0
- flextool/gui/db_version_check.py +269 -0
- flextool/gui/dialogs/__init__.py +0 -0
- flextool/gui/dialogs/add_dialog.py +1098 -0
- flextool/gui/dialogs/calibrate_dialog.py +1259 -0
- flextool/gui/dialogs/file_picker.py +473 -0
- flextool/gui/dialogs/group_picker.py +299 -0
- flextool/gui/dialogs/migration_consent_dialog.py +106 -0
- flextool/gui/dialogs/migration_progress_dialog.py +237 -0
- flextool/gui/dialogs/plot_dialog.py +459 -0
- flextool/gui/dialogs/plot_settings_picker.py +2184 -0
- flextool/gui/dialogs/project_dialog.py +426 -0
- flextool/gui/dialogs/update_dialog.py +212 -0
- flextool/gui/downsampling.py +88 -0
- flextool/gui/error_handling.py +50 -0
- flextool/gui/execution_manager.py +1715 -0
- flextool/gui/execution_window.py +1377 -0
- flextool/gui/hover_tooltip.py +111 -0
- flextool/gui/input_sources.py +730 -0
- flextool/gui/main_window.py +6181 -0
- flextool/gui/network_graph.py +215 -0
- flextool/gui/output_actions.py +393 -0
- flextool/gui/output_log_window.py +159 -0
- flextool/gui/platform_utils.py +421 -0
- flextool/gui/plot_cache.py +88 -0
- flextool/gui/plot_canvas.py +543 -0
- flextool/gui/plot_config_reader.py +272 -0
- flextool/gui/project_utils.py +100 -0
- flextool/gui/result_viewer.py +4394 -0
- flextool/gui/scenario_key.py +162 -0
- flextool/gui/scenario_lists.py +516 -0
- flextool/gui/settings_io.py +360 -0
- flextool/gui/solve_reader.py +103 -0
- flextool/gui/tree_reorder.py +88 -0
- flextool/gui/ui_metrics.py +420 -0
- flextool/input_derivation/__init__.py +281 -0
- flextool/input_derivation/_commodity_ladder.py +375 -0
- flextool/input_derivation/_commodity_ladder_sets.py +70 -0
- flextool/input_derivation/_dc_power_flow.py +377 -0
- flextool/input_derivation/_method_constants.py +77 -0
- flextool/input_derivation/_process_method.py +258 -0
- flextool/input_derivation/_specs.py +1026 -0
- flextool/input_derivation/_validators.py +321 -0
- flextool/lean_parquet.py +159 -0
- flextool/model_builder/__init__.py +5 -0
- flextool/model_builder/build_model.py +589 -0
- flextool/model_builder/encoding.py +67 -0
- flextool/model_builder/names.py +34 -0
- flextool/model_builder/profiles.py +129 -0
- flextool/plot_outputs/__init__.py +14 -0
- flextool/plot_outputs/axis_helpers.py +355 -0
- flextool/plot_outputs/color_template.py +888 -0
- flextool/plot_outputs/config.py +171 -0
- flextool/plot_outputs/format_helpers.py +345 -0
- flextool/plot_outputs/legend_helpers.py +143 -0
- flextool/plot_outputs/orchestrator.py +1141 -0
- flextool/plot_outputs/perf.py +37 -0
- flextool/plot_outputs/plan.py +1787 -0
- flextool/plot_outputs/plot_bars.py +1510 -0
- flextool/plot_outputs/plot_bars_detail.py +753 -0
- flextool/plot_outputs/plot_lines.py +951 -0
- flextool/plot_outputs/shared_manifest.py +564 -0
- flextool/plot_outputs/subplot_helpers.py +137 -0
- flextool/process_inputs/__init__.py +188 -0
- flextool/process_inputs/import_old_excel_input.json +4159 -0
- flextool/process_inputs/read_matpower.py +451 -0
- flextool/process_inputs/read_old_flextool.py +1288 -0
- flextool/process_inputs/read_self_describing_excel.py +1423 -0
- flextool/process_inputs/read_tabular_with_specification.py +1114 -0
- flextool/process_inputs/write_old_flextool_to_db.py +3077 -0
- flextool/process_inputs/write_self_describing_to_db.py +977 -0
- flextool/process_inputs/write_to_input_db.py +269 -0
- flextool/process_outputs/__init__.py +7 -0
- flextool/process_outputs/_annualize.py +55 -0
- flextool/process_outputs/_inmemory_helpers.py +292 -0
- flextool/process_outputs/_output_meta.py +672 -0
- flextool/process_outputs/calc_capacity_flows.py +107 -0
- flextool/process_outputs/calc_connections.py +136 -0
- flextool/process_outputs/calc_costs.py +260 -0
- flextool/process_outputs/calc_group_flows.py +192 -0
- flextool/process_outputs/calc_slacks.py +103 -0
- flextool/process_outputs/calc_storage_vre.py +160 -0
- flextool/process_outputs/drop_levels.py +208 -0
- flextool/process_outputs/handoff_writers.py +1315 -0
- flextool/process_outputs/out_ancillary.py +544 -0
- flextool/process_outputs/out_capacity.py +179 -0
- flextool/process_outputs/out_costs.py +334 -0
- flextool/process_outputs/out_flowgroup.py +189 -0
- flextool/process_outputs/out_flows.py +301 -0
- flextool/process_outputs/out_group.py +475 -0
- flextool/process_outputs/out_node.py +190 -0
- flextool/process_outputs/persist_realized_slice.py +601 -0
- flextool/process_outputs/process_results.py +24 -0
- flextool/process_outputs/read_highs_solution.py +2256 -0
- flextool/process_outputs/read_parameters.py +1799 -0
- flextool/process_outputs/read_sets.py +1095 -0
- flextool/process_outputs/read_variables.py +553 -0
- flextool/process_outputs/solve_order.py +81 -0
- flextool/process_outputs/spinedb_replay.py +412 -0
- flextool/process_outputs/union_realized_slice.py +224 -0
- flextool/process_outputs/write_outputs.py +1286 -0
- flextool/process_outputs/write_spinedb.py +1267 -0
- flextool/representative_periods/__init__.py +5 -0
- flextool/representative_periods/clustering.py +165 -0
- flextool/representative_periods/force_include.py +563 -0
- flextool/representative_periods/netload.py +365 -0
- flextool/representative_periods/netload_inputs.py +345 -0
- flextool/representative_periods/netload_iterate.py +722 -0
- flextool/representative_periods/preprocess.py +948 -0
- flextool/representative_periods/scenario_stack.py +195 -0
- flextool/representative_periods/weights.py +124 -0
- flextool/scenario_comparison/__init__.py +13 -0
- flextool/scenario_comparison/config_builder.py +158 -0
- flextool/scenario_comparison/constants.py +20 -0
- flextool/scenario_comparison/data_models.py +222 -0
- flextool/scenario_comparison/db_reader.py +399 -0
- flextool/scenario_comparison/dispatch_data.py +1002 -0
- flextool/scenario_comparison/dispatch_mappings.py +205 -0
- flextool/scenario_comparison/dispatch_plots.py +691 -0
- flextool/scenario_comparison/input_entity_colors.py +319 -0
- flextool/scenario_comparison/orchestrator.py +453 -0
- flextool/scenario_comparison/plan_union.py +244 -0
- flextool/scenario_comparison/plot_settings_seed.py +205 -0
- flextool/schemas/AXIS_CONTRACT.md +71 -0
- flextool/schemas/canonical_databases/howto_aggregate_output.json +6225 -0
- flextool/schemas/canonical_databases/howto_connections.json +5606 -0
- flextool/schemas/canonical_databases/howto_demand.json +5518 -0
- flextool/schemas/canonical_databases/howto_hydro_reservoir.json +6239 -0
- flextool/schemas/canonical_databases/howto_hydro_reservoir_with_pump.json +5933 -0
- flextool/schemas/canonical_databases/howto_non_sync_and_curtailment.json +5794 -0
- flextool/schemas/canonical_databases/howto_ramp_and_start_up.json +5707 -0
- flextool/schemas/canonical_databases/howto_stochastics.json +6032 -0
- flextool/schemas/canonical_databases/templates_examples.json +13532 -0
- flextool/schemas/canonical_databases/templates_time_settings_only.json +5340 -0
- flextool/schemas/comparison_settings_template.json +197 -0
- flextool/schemas/default_plot_settings.yaml +260 -0
- flextool/schemas/default_plots.yaml +2293 -0
- flextool/schemas/flextool_axis_contract.json +303 -0
- flextool/schemas/flextool_axis_contract.schema.json +247 -0
- flextool/schemas/old_flextool_import_template.json +4443 -0
- flextool/schemas/output_info_template.json +48 -0
- flextool/schemas/output_settings_template.json +256 -0
- flextool/schemas/pre_v26/flextool_template_constant_default.json +2105 -0
- flextool/schemas/pre_v26/flextool_template_default_optional_output.json +2152 -0
- flextool/schemas/pre_v26/flextool_template_default_value.json +2094 -0
- flextool/schemas/pre_v26/flextool_template_drop_down.json +2080 -0
- flextool/schemas/pre_v26/flextool_template_lifetime_method.json +1990 -0
- flextool/schemas/pre_v26/flextool_template_optional_outputs.json +2094 -0
- flextool/schemas/pre_v26/flextool_template_output_node_flows.json +2105 -0
- flextool/schemas/pre_v26/flextool_template_results_master.json +493 -0
- flextool/schemas/pre_v26/flextool_template_rolling_start_remove.json +2087 -0
- flextool/schemas/pre_v26/flextool_template_rolling_window.json +2059 -0
- flextool/schemas/pre_v26/flextool_template_storage_binding_defaults.json +46 -0
- flextool/schemas/pre_v26/flextool_template_v2.json +1990 -0
- flextool/schemas/pre_v26/flextool_template_v25.json +3864 -0
- flextool/schemas/spinedb_results_schema.json +581 -0
- flextool/schemas/spinedb_schema.json +4636 -0
- flextool/solver_config/copt.opt.template +18 -0
- flextool/solver_config/cplex.opt.template +25 -0
- flextool/solver_config/gurobi.opt.template +18 -0
- flextool/solver_config/highs.opt.template +18 -0
- flextool/solver_config/xpress.opt.template +26 -0
- flextool/spinedb_backend/__init__.py +26 -0
- flextool/spinedb_backend/_axis_enums.py +1119 -0
- flextool/spinedb_backend/_backend.py +1139 -0
- flextool/update_flextool/__init__.py +12 -0
- flextool/update_flextool/canonical_databases.py +251 -0
- flextool/update_flextool/db_migration.py +7108 -0
- flextool/update_flextool/ensure_settings_db.py +138 -0
- flextool/update_flextool/export_database.py +103 -0
- flextool/update_flextool/extend_tests_fixture.py +772 -0
- flextool/update_flextool/generate_canonical.py +274 -0
- flextool/update_flextool/initialize_database.py +42 -0
- flextool/update_flextool/install_info.py +225 -0
- flextool/update_flextool/self_update.py +464 -0
- flextool/update_flextool/sync_master_json_template.py +125 -0
- flextool/update_flextool/test_fixtures.py +187 -0
- flextool-4.0.0.dist-info/METADATA +217 -0
- flextool-4.0.0.dist-info/RECORD +322 -0
- flextool-4.0.0.dist-info/WHEEL +5 -0
- flextool-4.0.0.dist-info/entry_points.txt +17 -0
- flextool-4.0.0.dist-info/licenses/LICENSE.txt +19 -0
- flextool-4.0.0.dist-info/top_level.txt +1 -0
|
@@ -0,0 +1,173 @@
|
|
|
1
|
+
"""Canonical Provider key constants.
|
|
2
|
+
|
|
3
|
+
Centralises the parent-qualified Provider keys
|
|
4
|
+
(``"solve_data/<basename>"``, ``"input/<basename>"``, etc.) used by
|
|
5
|
+
emit_* writers, cascade readers, and orchestration code.
|
|
6
|
+
|
|
7
|
+
Why this module exists
|
|
8
|
+
----------------------
|
|
9
|
+
|
|
10
|
+
Phase 0a of ``specs/provider_consolidation.md`` retired the dual-key
|
|
11
|
+
registration in :func:`_emit_provider_io._emit`. Every frame lives
|
|
12
|
+
under exactly one Provider key — the parent-qualified form. Stringly-
|
|
13
|
+
typed lookups (``provider.get("solve_data/active_timelines")``) are
|
|
14
|
+
typo-prone: a rename in one site without the other becomes a silent
|
|
15
|
+
``None`` return that the cascade tolerates by emitting an empty frame,
|
|
16
|
+
which then surfaces as wrong numbers downstream.
|
|
17
|
+
|
|
18
|
+
This module defines named Python constants for every key the cascade
|
|
19
|
+
emits or consumes. Producers do ``provider.put(K.SOLVE_DATA_ACTIVE_TIMELINES, df)``;
|
|
20
|
+
consumers do ``provider.get(K.SOLVE_DATA_ACTIVE_TIMELINES)``. IDE
|
|
21
|
+
rename / Find-Usages stays sound; a typo is a ``NameError`` at import
|
|
22
|
+
time, not a silent runtime miss.
|
|
23
|
+
|
|
24
|
+
Naming convention
|
|
25
|
+
-----------------
|
|
26
|
+
|
|
27
|
+
* The canonical form is **``"<parent>/<basename>"``** — no ``.csv``
|
|
28
|
+
suffix. Phase 3b retired the ``.csv`` suffix from key names: it
|
|
29
|
+
reinforced a misleading "this is a file" mental model, even though
|
|
30
|
+
the Provider stores frames in memory and strips ``.csv`` at lookup
|
|
31
|
+
time anyway. ``snapshot_processed_inputs`` adds the ``.csv``
|
|
32
|
+
suffix on disk dump.
|
|
33
|
+
* Constant names are uppercased, underscore-separated, prefixed with
|
|
34
|
+
the parent: ``SOLVE_DATA_ACTIVE_TIMELINES``, ``INPUT_TIMELINE``,
|
|
35
|
+
``DERIVED_CT_METHOD_OVERRIDES``, ``HANDOFF_REALIZED_INVEST``.
|
|
36
|
+
* Group constants by parent dir, then alphabetically within the group.
|
|
37
|
+
* New keys: add the constant here first, then use it from the call sites.
|
|
38
|
+
|
|
39
|
+
Coverage scope
|
|
40
|
+
--------------
|
|
41
|
+
|
|
42
|
+
This module currently covers the **cross-solve carrier set**, the
|
|
43
|
+
**handoff carriers** (Phase 2 translator), and other high-traffic keys
|
|
44
|
+
touched by orchestration and the ``_solve_context`` loaders. The
|
|
45
|
+
single-use ``solve_data/*`` emit-and-forget keys (most of
|
|
46
|
+
:func:`_flex_data_accumulator.expected_basenames`) still appear as
|
|
47
|
+
inline string literals at their producer call sites — migrating them
|
|
48
|
+
to constants is a mechanical follow-up that can land in batches
|
|
49
|
+
without changing semantics.
|
|
50
|
+
"""
|
|
51
|
+
from __future__ import annotations
|
|
52
|
+
|
|
53
|
+
|
|
54
|
+
SOLVE_DATA_FIX_STORAGE_QUANTITY = "solve_data/fix_storage_quantity"
|
|
55
|
+
SOLVE_DATA_FIX_STORAGE_PRICE = "solve_data/fix_storage_price"
|
|
56
|
+
SOLVE_DATA_FIX_STORAGE_USAGE = "solve_data/fix_storage_usage"
|
|
57
|
+
SOLVE_DATA_P_ENTITY_PRE_EXISTING = "solve_data/p_entity_pre_existing"
|
|
58
|
+
SOLVE_DATA_P_ENTITY_INVESTED = "solve_data/p_entity_invested"
|
|
59
|
+
SOLVE_DATA_P_ENTITY_DIVESTED = "solve_data/p_entity_divested"
|
|
60
|
+
SOLVE_DATA_P_ENTITY_PERIOD_EXISTING_CAPACITY = (
|
|
61
|
+
"solve_data/p_entity_period_existing_capacity"
|
|
62
|
+
)
|
|
63
|
+
SOLVE_DATA_P_ROLL_CONTINUE_STATE = "solve_data/p_roll_continue_state"
|
|
64
|
+
SOLVE_DATA_CO2_CUM_REALIZED_TONNES = "solve_data/co2_cum_realized_tonnes"
|
|
65
|
+
SOLVE_DATA_LADDER_CUM_SIM_HOURS = "solve_data/ladder_cum_sim_hours"
|
|
66
|
+
SOLVE_DATA_LADDER_CUM_REALIZED_MWH = "solve_data/ladder_cum_realized_mwh"
|
|
67
|
+
SOLVE_DATA_ED_HISTORY_REALIZED = "solve_data/ed_history_realized"
|
|
68
|
+
SOLVE_DATA_ED_HISTORY_REALIZED_FIRST = "solve_data/ed_history_realized_first"
|
|
69
|
+
SOLVE_DATA_EDD_HISTORY = "solve_data/edd_history"
|
|
70
|
+
|
|
71
|
+
|
|
72
|
+
# ---------------------------------------------------------------------------
|
|
73
|
+
# Frequently-referenced solve_data/ keys — touched by multiple cascade
|
|
74
|
+
# modules. Add to this section as call sites accumulate.
|
|
75
|
+
# ---------------------------------------------------------------------------
|
|
76
|
+
|
|
77
|
+
SOLVE_DATA_ACTIVE_TIMELINES = "solve_data/active_timelines"
|
|
78
|
+
SOLVE_DATA_INVEST_PERIODS_OF_CURRENT_SOLVE = (
|
|
79
|
+
"solve_data/invest_periods_of_current_solve"
|
|
80
|
+
)
|
|
81
|
+
SOLVE_DATA_PROCESS_SOURCE_TOSINK = "solve_data/process_source_toSink"
|
|
82
|
+
SOLVE_DATA_REGION_COUPLING = "solve_data/region_coupling"
|
|
83
|
+
|
|
84
|
+
|
|
85
|
+
# ---------------------------------------------------------------------------
|
|
86
|
+
# RP-blended-weights keys — populated by ``_emit_solve_writers._compute_rp_frames``
|
|
87
|
+
# (the six derived sets/params) plus the node-state RP subset (``_emit_leaf_sets``)
|
|
88
|
+
# and the per-solve base-period set (``_emit_per_solve``). Consumed by the
|
|
89
|
+
# storage-binding-method machinery once the model-side wiring lands.
|
|
90
|
+
# ---------------------------------------------------------------------------
|
|
91
|
+
|
|
92
|
+
SOLVE_DATA_NODE_STATE_RP = "solve_data/nodeState_rp"
|
|
93
|
+
SOLVE_DATA_RP_BASE_CHAIN = "solve_data/rp_base_chain"
|
|
94
|
+
SOLVE_DATA_RP_BASE_FIRST = "solve_data/rp_base_first"
|
|
95
|
+
SOLVE_DATA_RP_BASE_LAST = "solve_data/rp_base_last"
|
|
96
|
+
SOLVE_DATA_RP_BASE_PERIOD_SET = "solve_data/rp_base_period_set"
|
|
97
|
+
SOLVE_DATA_RP_BLOCK_FIRST = "solve_data/rp_block_first"
|
|
98
|
+
SOLVE_DATA_RP_BLOCK_LAST = "solve_data/rp_block_last"
|
|
99
|
+
SOLVE_DATA_RP_BLOCK_START_LAST = "solve_data/rp_block_start_last"
|
|
100
|
+
SOLVE_DATA_RP_REP_PERIOD_SET = "solve_data/rp_rep_period_set"
|
|
101
|
+
SOLVE_DATA_RP_WEIGHTS = "solve_data/rp_weights"
|
|
102
|
+
|
|
103
|
+
|
|
104
|
+
# ---------------------------------------------------------------------------
|
|
105
|
+
# input/ keys — populated by ``seed_provider_from_dir(kind="input")`` and
|
|
106
|
+
# the input_derivation modules. Subset listed; expand as call sites grow.
|
|
107
|
+
# ---------------------------------------------------------------------------
|
|
108
|
+
|
|
109
|
+
INPUT_COMMODITY_LADDER_ANNUAL = "input/commodity_ladder_annual"
|
|
110
|
+
INPUT_COMMODITY_LADDER_CUMULATIVE = "input/commodity_ladder_cumulative"
|
|
111
|
+
INPUT_CONNECTION_DC_POWER_FLOW = "input/connection_dc_power_flow"
|
|
112
|
+
INPUT_GROUP__CO2_METHOD = "input/group__co2_method"
|
|
113
|
+
INPUT_NODE_DC_POWER_FLOW = "input/node_dc_power_flow"
|
|
114
|
+
INPUT_NODE_REFERENCE_ANGLE = "input/node_reference_angle"
|
|
115
|
+
INPUT_P_CONNECTION_SUSCEPTANCE = "input/p_connection_susceptance"
|
|
116
|
+
INPUT_PERIODS_AVAILABLE = "input/periods_available"
|
|
117
|
+
INPUT_PROCESS_METHOD = "input/process_method"
|
|
118
|
+
|
|
119
|
+
|
|
120
|
+
# ---------------------------------------------------------------------------
|
|
121
|
+
# derived/ keys — populated by input_derivation between Spine read and
|
|
122
|
+
# cascade build. Distinct from input/ so derivation intermediates don't
|
|
123
|
+
# collide with raw user input.
|
|
124
|
+
# ---------------------------------------------------------------------------
|
|
125
|
+
|
|
126
|
+
DERIVED_CT_METHOD_OVERRIDES = "derived/ct_method_overrides"
|
|
127
|
+
|
|
128
|
+
|
|
129
|
+
# ---------------------------------------------------------------------------
|
|
130
|
+
# handoff/ keys — populated by ``_provider_translators.translate_handoff_to_provider``
|
|
131
|
+
# at iteration start, from the previous sub-solve's ``SolveHandoff``.
|
|
132
|
+
# One key per consumed handoff field; empty header-only frame written
|
|
133
|
+
# when the corresponding handoff field is ``None`` (first sub-solve, or
|
|
134
|
+
# carrier not active for the previous solve). Consumers should treat
|
|
135
|
+
# ``provider.get(K.HANDOFF_X).height == 0`` as the "no prior carrier"
|
|
136
|
+
# signal instead of checking the SolveHandoff object directly.
|
|
137
|
+
# ---------------------------------------------------------------------------
|
|
138
|
+
|
|
139
|
+
HANDOFF_REALIZED_INVEST = "handoff/realized_invest"
|
|
140
|
+
HANDOFF_REALIZED_EXISTING = "handoff/realized_existing"
|
|
141
|
+
HANDOFF_DIVEST_CUMULATIVE = "handoff/divest_cumulative"
|
|
142
|
+
HANDOFF_ROLL_END_STATE = "handoff/roll_end_state"
|
|
143
|
+
HANDOFF_UPWARD_ROLL_END_STATE = "handoff/upward_roll_end_state"
|
|
144
|
+
HANDOFF_CUMULATIVE_CO2 = "handoff/cumulative_co2"
|
|
145
|
+
HANDOFF_CUMULATIVE_COMMODITY = "handoff/cumulative_commodity"
|
|
146
|
+
HANDOFF_CUM_SIM_HOURS = "handoff/cum_sim_hours"
|
|
147
|
+
HANDOFF_FIX_STORAGE_QUANTITY = "handoff/fix_storage_quantity"
|
|
148
|
+
HANDOFF_FIX_STORAGE_PRICE = "handoff/fix_storage_price"
|
|
149
|
+
HANDOFF_FIX_STORAGE_USAGE = "handoff/fix_storage_usage"
|
|
150
|
+
|
|
151
|
+
|
|
152
|
+
# ---------------------------------------------------------------------------
|
|
153
|
+
# override/ keys — parallel to handoff/* and populated by
|
|
154
|
+
# ``_provider_translators.translate_overrides_to_provider`` from an
|
|
155
|
+
# external overrides dict (Phase 5 of specs/provider_consolidation.md).
|
|
156
|
+
# When present, ``read_handoff_frame`` returns the override frame in
|
|
157
|
+
# preference to the natural handoff carrier, so existing consumers pick
|
|
158
|
+
# up overrides without code changes. Each override key shadows the
|
|
159
|
+
# correspondingly-named ``HANDOFF_*`` key; only the existing handoff
|
|
160
|
+
# carriers are overridable.
|
|
161
|
+
# ---------------------------------------------------------------------------
|
|
162
|
+
|
|
163
|
+
OVERRIDE_REALIZED_INVEST = "override/realized_invest"
|
|
164
|
+
OVERRIDE_REALIZED_EXISTING = "override/realized_existing"
|
|
165
|
+
OVERRIDE_DIVEST_CUMULATIVE = "override/divest_cumulative"
|
|
166
|
+
OVERRIDE_ROLL_END_STATE = "override/roll_end_state"
|
|
167
|
+
OVERRIDE_UPWARD_ROLL_END_STATE = "override/upward_roll_end_state"
|
|
168
|
+
OVERRIDE_CUMULATIVE_CO2 = "override/cumulative_co2"
|
|
169
|
+
OVERRIDE_CUMULATIVE_COMMODITY = "override/cumulative_commodity"
|
|
170
|
+
OVERRIDE_CUM_SIM_HOURS = "override/cum_sim_hours"
|
|
171
|
+
OVERRIDE_FIX_STORAGE_QUANTITY = "override/fix_storage_quantity"
|
|
172
|
+
OVERRIDE_FIX_STORAGE_PRICE = "override/fix_storage_price"
|
|
173
|
+
OVERRIDE_FIX_STORAGE_USAGE = "override/fix_storage_usage"
|
|
@@ -0,0 +1,225 @@
|
|
|
1
|
+
"""Translators that fan typed orchestrator carriers into Provider entries.
|
|
2
|
+
|
|
3
|
+
Phase 2 of ``specs/provider_consolidation.md`` retires the
|
|
4
|
+
``prior_handoff`` parameter threading through preprocessing. Instead of
|
|
5
|
+
passing the typed :class:`SolveHandoff` dataclass alongside the Provider
|
|
6
|
+
into every preprocessing call site, the orchestrator translates each
|
|
7
|
+
consumed handoff field into a dedicated Provider key
|
|
8
|
+
(``handoff/<field>.csv``) at iteration start. Preprocessing consumers
|
|
9
|
+
then read via ``provider.get(K.HANDOFF_X)`` — one read interface, no
|
|
10
|
+
parameter threading.
|
|
11
|
+
|
|
12
|
+
The translator writes an **empty header-only frame** when a handoff
|
|
13
|
+
field is ``None`` so consumers can use a single check
|
|
14
|
+
(``provider.get(K.X).height > 0``) to distinguish "prior carrier
|
|
15
|
+
populated" from "no prior carrier". This matches the
|
|
16
|
+
``_read_csv``-style empty-frame contract used elsewhere in the cascade.
|
|
17
|
+
"""
|
|
18
|
+
from __future__ import annotations
|
|
19
|
+
|
|
20
|
+
from pathlib import Path
|
|
21
|
+
from typing import TYPE_CHECKING
|
|
22
|
+
|
|
23
|
+
import polars as pl
|
|
24
|
+
|
|
25
|
+
from flextool.engine_polars import _provider_keys as K
|
|
26
|
+
|
|
27
|
+
if TYPE_CHECKING:
|
|
28
|
+
from flextool.engine_polars._flex_data_provider import FlexDataProvider
|
|
29
|
+
from flextool.engine_polars._solve_handoff import SolveHandoff
|
|
30
|
+
|
|
31
|
+
|
|
32
|
+
# Schemas for each handoff carrier's empty-frame fallback. Column names
|
|
33
|
+
# match what consumers iter_rows(named=True) keys; Utf8 dtype matches
|
|
34
|
+
# the canonical CSV-roundtrip shape (consumers cast to float on read).
|
|
35
|
+
_HANDOFF_EMPTY_SCHEMAS: dict[str, tuple[str, ...]] = {
|
|
36
|
+
K.HANDOFF_REALIZED_INVEST: ("entity", "period", "value"),
|
|
37
|
+
K.HANDOFF_REALIZED_EXISTING: ("entity", "period", "value"),
|
|
38
|
+
K.HANDOFF_DIVEST_CUMULATIVE: ("entity", "value"),
|
|
39
|
+
K.HANDOFF_ROLL_END_STATE: ("node", "value"),
|
|
40
|
+
K.HANDOFF_UPWARD_ROLL_END_STATE: ("node", "value"),
|
|
41
|
+
K.HANDOFF_CUMULATIVE_CO2: ("group", "period", "value"),
|
|
42
|
+
K.HANDOFF_CUMULATIVE_COMMODITY: ("commodity", "tier", "period",
|
|
43
|
+
"p_ladder_cum_realized_mwh"),
|
|
44
|
+
K.HANDOFF_CUM_SIM_HOURS: ("period", "p_ladder_cum_sim_hours"),
|
|
45
|
+
K.HANDOFF_FIX_STORAGE_QUANTITY: ("node", "period", "step", "p_fix_storage_quantity"),
|
|
46
|
+
K.HANDOFF_FIX_STORAGE_PRICE: ("node", "period", "step", "p_fix_storage_price"),
|
|
47
|
+
K.HANDOFF_FIX_STORAGE_USAGE: ("node", "period", "step", "p_fix_storage_usage"),
|
|
48
|
+
}
|
|
49
|
+
|
|
50
|
+
|
|
51
|
+
def _empty_handoff_frame(key: str) -> pl.DataFrame:
|
|
52
|
+
cols = _HANDOFF_EMPTY_SCHEMAS[key]
|
|
53
|
+
return pl.DataFrame(
|
|
54
|
+
{c: [] for c in cols},
|
|
55
|
+
schema={c: pl.Utf8 for c in cols},
|
|
56
|
+
)
|
|
57
|
+
|
|
58
|
+
|
|
59
|
+
def translate_handoff_to_provider(
|
|
60
|
+
handoff: "SolveHandoff | None", provider,
|
|
61
|
+
) -> None:
|
|
62
|
+
"""Write each consumed ``SolveHandoff`` field as a Provider entry.
|
|
63
|
+
|
|
64
|
+
Called at iteration start *before* preprocessing runs. When
|
|
65
|
+
*handoff* is ``None`` (first sub-solve, or no prior carrier
|
|
66
|
+
available) every key receives an empty header-only frame so
|
|
67
|
+
consumers can read unconditionally and check ``height > 0`` to
|
|
68
|
+
decide whether prior-carrier data is available.
|
|
69
|
+
|
|
70
|
+
The translated keys are listed in
|
|
71
|
+
``flextool.engine_polars._provider_keys`` under the ``HANDOFF_*``
|
|
72
|
+
constants. See :data:`_HANDOFF_EMPTY_SCHEMAS` for column shapes.
|
|
73
|
+
"""
|
|
74
|
+
field_to_key = (
|
|
75
|
+
("realized_invest", K.HANDOFF_REALIZED_INVEST),
|
|
76
|
+
("realized_existing", K.HANDOFF_REALIZED_EXISTING),
|
|
77
|
+
("divest_cumulative", K.HANDOFF_DIVEST_CUMULATIVE),
|
|
78
|
+
("roll_end_state", K.HANDOFF_ROLL_END_STATE),
|
|
79
|
+
("upward_roll_end_state", K.HANDOFF_UPWARD_ROLL_END_STATE),
|
|
80
|
+
("cumulative_co2", K.HANDOFF_CUMULATIVE_CO2),
|
|
81
|
+
("cumulative_commodity", K.HANDOFF_CUMULATIVE_COMMODITY),
|
|
82
|
+
("cum_sim_hours", K.HANDOFF_CUM_SIM_HOURS),
|
|
83
|
+
("fix_storage_quantity", K.HANDOFF_FIX_STORAGE_QUANTITY),
|
|
84
|
+
("fix_storage_price", K.HANDOFF_FIX_STORAGE_PRICE),
|
|
85
|
+
("fix_storage_usage", K.HANDOFF_FIX_STORAGE_USAGE),
|
|
86
|
+
)
|
|
87
|
+
for field_name, key in field_to_key:
|
|
88
|
+
frame = getattr(handoff, field_name, None) if handoff is not None else None
|
|
89
|
+
if frame is None:
|
|
90
|
+
frame = _empty_handoff_frame(key)
|
|
91
|
+
provider.put(key, frame)
|
|
92
|
+
|
|
93
|
+
|
|
94
|
+
# Mapping from user-facing handoff Provider keys to their override
|
|
95
|
+
# siblings. Phase 5 of specs/provider_consolidation.md: external code
|
|
96
|
+
# supplies overrides keyed by ``K.HANDOFF_X`` (the user-facing identity);
|
|
97
|
+
# ``translate_overrides_to_provider`` writes each frame under the
|
|
98
|
+
# corresponding ``K.OVERRIDE_X`` key, and ``read_handoff_frame`` checks
|
|
99
|
+
# the override slot before falling back to the natural handoff carrier.
|
|
100
|
+
# Only the existing handoff carriers are overridable.
|
|
101
|
+
_HANDOFF_TO_OVERRIDE: dict[str, str] = {
|
|
102
|
+
K.HANDOFF_REALIZED_INVEST: K.OVERRIDE_REALIZED_INVEST,
|
|
103
|
+
K.HANDOFF_REALIZED_EXISTING: K.OVERRIDE_REALIZED_EXISTING,
|
|
104
|
+
K.HANDOFF_DIVEST_CUMULATIVE: K.OVERRIDE_DIVEST_CUMULATIVE,
|
|
105
|
+
K.HANDOFF_ROLL_END_STATE: K.OVERRIDE_ROLL_END_STATE,
|
|
106
|
+
K.HANDOFF_UPWARD_ROLL_END_STATE: K.OVERRIDE_UPWARD_ROLL_END_STATE,
|
|
107
|
+
K.HANDOFF_CUMULATIVE_CO2: K.OVERRIDE_CUMULATIVE_CO2,
|
|
108
|
+
K.HANDOFF_CUMULATIVE_COMMODITY: K.OVERRIDE_CUMULATIVE_COMMODITY,
|
|
109
|
+
K.HANDOFF_CUM_SIM_HOURS: K.OVERRIDE_CUM_SIM_HOURS,
|
|
110
|
+
K.HANDOFF_FIX_STORAGE_QUANTITY: K.OVERRIDE_FIX_STORAGE_QUANTITY,
|
|
111
|
+
K.HANDOFF_FIX_STORAGE_PRICE: K.OVERRIDE_FIX_STORAGE_PRICE,
|
|
112
|
+
K.HANDOFF_FIX_STORAGE_USAGE: K.OVERRIDE_FIX_STORAGE_USAGE,
|
|
113
|
+
}
|
|
114
|
+
|
|
115
|
+
|
|
116
|
+
def translate_overrides_to_provider(
|
|
117
|
+
overrides: "dict[str, pl.DataFrame] | None", provider,
|
|
118
|
+
) -> None:
|
|
119
|
+
"""Write external overrides under ``override/<field>`` Provider keys.
|
|
120
|
+
|
|
121
|
+
Phase 5 of ``specs/provider_consolidation.md``. External code provides
|
|
122
|
+
overrides keyed by ``K.HANDOFF_X`` constants (the user-facing identity);
|
|
123
|
+
this translator writes each frame under the corresponding ``K.OVERRIDE_X``
|
|
124
|
+
Provider key. Existing :func:`read_handoff_frame` consumers automatically
|
|
125
|
+
pick up overrides because the helper checks ``override/<field>`` before
|
|
126
|
+
falling back to ``handoff/<field>``.
|
|
127
|
+
|
|
128
|
+
When *overrides* is ``None`` or empty, no writes are made — the override
|
|
129
|
+
layer simply isn't present.
|
|
130
|
+
|
|
131
|
+
Raises
|
|
132
|
+
------
|
|
133
|
+
ValueError
|
|
134
|
+
If *overrides* contains a key that is not one of the whitelisted
|
|
135
|
+
``K.HANDOFF_*`` constants. Arbitrary Provider-key writes through
|
|
136
|
+
this translator are rejected so the override surface stays
|
|
137
|
+
explicit.
|
|
138
|
+
"""
|
|
139
|
+
if not overrides:
|
|
140
|
+
return
|
|
141
|
+
for handoff_key, frame in overrides.items():
|
|
142
|
+
override_key = _HANDOFF_TO_OVERRIDE.get(handoff_key)
|
|
143
|
+
if override_key is None:
|
|
144
|
+
raise ValueError(
|
|
145
|
+
f"translate_overrides_to_provider: key {handoff_key!r} is not "
|
|
146
|
+
f"a whitelisted handoff carrier; only K.HANDOFF_* keys are "
|
|
147
|
+
f"overridable. Allowed keys: "
|
|
148
|
+
f"{sorted(_HANDOFF_TO_OVERRIDE.keys())!r}"
|
|
149
|
+
)
|
|
150
|
+
# Phase 6a — tag every override write so the audit dump can
|
|
151
|
+
# distinguish externally-supplied keys from natural-cascade
|
|
152
|
+
# writes. The override key itself is the discriminator at the
|
|
153
|
+
# dump site, so a single stable tag is sufficient.
|
|
154
|
+
provider.put(override_key, frame, source="external_override")
|
|
155
|
+
|
|
156
|
+
|
|
157
|
+
def read_handoff_frame(provider, key: str) -> "pl.DataFrame | None":
|
|
158
|
+
"""Return a populated handoff frame from the Provider, or ``None``.
|
|
159
|
+
|
|
160
|
+
Phase 5: checks ``override/<field>`` first, falls back to
|
|
161
|
+
``handoff/<field>``. External overrides written via
|
|
162
|
+
:func:`translate_overrides_to_provider` shadow the natural handoff
|
|
163
|
+
carrier; consumers stay key-stable.
|
|
164
|
+
|
|
165
|
+
The translator writes an empty header-only frame when the
|
|
166
|
+
corresponding handoff field is ``None``; this helper collapses the
|
|
167
|
+
``height == 0`` empty back to ``None`` so consumers can preserve
|
|
168
|
+
their existing ``if frame is not None`` guard pattern. The same
|
|
169
|
+
``height == 0 → None`` semantics apply to the override slot: an
|
|
170
|
+
empty override frame is treated as "no override present" and we
|
|
171
|
+
fall through to the handoff carrier.
|
|
172
|
+
"""
|
|
173
|
+
if provider is None:
|
|
174
|
+
return None
|
|
175
|
+
override_key = _HANDOFF_TO_OVERRIDE.get(key)
|
|
176
|
+
if override_key is not None:
|
|
177
|
+
frame = provider.get(override_key)
|
|
178
|
+
if frame is not None and frame.height > 0:
|
|
179
|
+
return frame
|
|
180
|
+
frame = provider.get(key)
|
|
181
|
+
if frame is None or frame.height == 0:
|
|
182
|
+
return None
|
|
183
|
+
return frame
|
|
184
|
+
|
|
185
|
+
|
|
186
|
+
def dump_provider_sources(
|
|
187
|
+
provider: "FlexDataProvider",
|
|
188
|
+
dump_path: "str | Path",
|
|
189
|
+
solve_name: str,
|
|
190
|
+
) -> None:
|
|
191
|
+
"""Append every source-tagged Provider key to *dump_path*.
|
|
192
|
+
|
|
193
|
+
Phase 6b of ``specs/provider_consolidation.md``. Iterates the
|
|
194
|
+
Provider's keys; for each key whose :meth:`get_source` returns a
|
|
195
|
+
non-``None`` tag, appends one tab-separated line in the format::
|
|
196
|
+
|
|
197
|
+
<solve_name>\\t<key>\\t<source>\\n
|
|
198
|
+
|
|
199
|
+
The file is opened in append mode so multiple sub-solves
|
|
200
|
+
accumulate in a single log. The parent directory is created if
|
|
201
|
+
missing.
|
|
202
|
+
|
|
203
|
+
Untagged (natural-cascade) keys are skipped — the dump is a
|
|
204
|
+
minimal audit trail of writes whose origin differs from the
|
|
205
|
+
default preprocessing chain, not a snapshot of the full Provider.
|
|
206
|
+
"""
|
|
207
|
+
path = Path(dump_path)
|
|
208
|
+
path.parent.mkdir(parents=True, exist_ok=True)
|
|
209
|
+
# Sorted iteration keeps the log deterministic across runs so the
|
|
210
|
+
# audit trail diffs cleanly between cascades that differ only in
|
|
211
|
+
# dict-iteration order.
|
|
212
|
+
with path.open("a", encoding="utf-8") as fh:
|
|
213
|
+
for key in sorted(provider.keys()):
|
|
214
|
+
source = provider.get_source(key)
|
|
215
|
+
if source is None:
|
|
216
|
+
continue
|
|
217
|
+
fh.write(f"{solve_name}\t{key}\t{source}\n")
|
|
218
|
+
|
|
219
|
+
|
|
220
|
+
__all__ = [
|
|
221
|
+
"translate_handoff_to_provider",
|
|
222
|
+
"translate_overrides_to_provider",
|
|
223
|
+
"read_handoff_frame",
|
|
224
|
+
"dump_provider_sources",
|
|
225
|
+
]
|