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,550 @@
|
|
|
1
|
+
"""Leaf-level set projections.
|
|
2
|
+
|
|
3
|
+
Four families of trivial "setof" derivations. Each helper reads one
|
|
4
|
+
or two ``input/*.csv`` (or ``solve_data/*.csv``) files and emits a
|
|
5
|
+
small single- or multi-column set CSV under ``solve_data/``:
|
|
6
|
+
|
|
7
|
+
* ``period_param_sets`` — 4 period projections from pd_*.csv.
|
|
8
|
+
* ``invest_method_sets`` — 4 method-filter projections.
|
|
9
|
+
* ``co2_method_sets`` — 3 co2-method projections.
|
|
10
|
+
* ``simple_projections`` — 11 trivial setof projections.
|
|
11
|
+
|
|
12
|
+
Each public ``derive_*`` returns a fresh ``pl.DataFrame`` in-memory.
|
|
13
|
+
``write_*`` wrappers materialise that frame to the canonical CSV path
|
|
14
|
+
so downstream consumers see the same file layout.
|
|
15
|
+
|
|
16
|
+
Style: read tiny CSVs eagerly with polars, project with native polars
|
|
17
|
+
expressions, deduplicate via ``.unique(maintain_order=True)``. No
|
|
18
|
+
abstraction beyond a per-family ``write_all`` orchestrator. Match
|
|
19
|
+
:mod:`._derived_existing` / :mod:`._projection_params` style.
|
|
20
|
+
"""
|
|
21
|
+
from __future__ import annotations
|
|
22
|
+
|
|
23
|
+
from pathlib import Path
|
|
24
|
+
|
|
25
|
+
import polars as pl
|
|
26
|
+
|
|
27
|
+
from . import _provider_keys as K
|
|
28
|
+
from ._axis_enums import alias_to_axis
|
|
29
|
+
from ._emit_provider_io import _emit
|
|
30
|
+
|
|
31
|
+
|
|
32
|
+
# ---------------------------------------------------------------------------
|
|
33
|
+
# Method-enum constants — mirror flextool/flextool_base.dat and the legacy
|
|
34
|
+
# constants in preprocessing/{invest_method_sets,co2_method_sets}.py.
|
|
35
|
+
# ---------------------------------------------------------------------------
|
|
36
|
+
|
|
37
|
+
_INVEST_METHOD_NOT_ALLOWED: frozenset[str] = frozenset((
|
|
38
|
+
"not_allowed", "retire_period", "retire_total", "retire_no_limit",
|
|
39
|
+
))
|
|
40
|
+
_DIVEST_METHOD_NOT_ALLOWED: frozenset[str] = frozenset((
|
|
41
|
+
"not_allowed", "invest_period", "invest_total", "invest_no_limit",
|
|
42
|
+
))
|
|
43
|
+
|
|
44
|
+
_CO2_PRICE_METHOD: frozenset[str] = frozenset((
|
|
45
|
+
"price", "price_period", "price_total", "price_period_total",
|
|
46
|
+
))
|
|
47
|
+
_CO2_MAX_PERIOD_METHOD: frozenset[str] = frozenset((
|
|
48
|
+
"period", "price_period", "period_total", "price_period_total",
|
|
49
|
+
))
|
|
50
|
+
_CO2_MAX_TOTAL_METHOD: frozenset[str] = frozenset((
|
|
51
|
+
"total", "price_total", "period_total", "price_period_total",
|
|
52
|
+
))
|
|
53
|
+
|
|
54
|
+
|
|
55
|
+
# ---------------------------------------------------------------------------
|
|
56
|
+
# Internal CSV reader. All inputs are tiny set/parameter CSVs (≤ thousands
|
|
57
|
+
# of rows in any realistic fixture) so eager read is fine. Missing source
|
|
58
|
+
# means "empty set" — flextool's legacy code returns ``[]`` in that case.
|
|
59
|
+
# ---------------------------------------------------------------------------
|
|
60
|
+
|
|
61
|
+
def _read_csv(path: Path, columns: list[str],
|
|
62
|
+
*, provider: "object | None" = None) -> pl.DataFrame:
|
|
63
|
+
"""Provider-only — returns an empty all-Utf8 frame on Provider miss.
|
|
64
|
+
|
|
65
|
+
Step 2.5 Phase C dropped the disk-fallback arm. The
|
|
66
|
+
canonical-schema empty frame is the documented behaviour when an
|
|
67
|
+
upstream writer hasn't populated *path*'s key (legacy behaviour
|
|
68
|
+
for a missing on-disk CSV).
|
|
69
|
+
"""
|
|
70
|
+
from flextool.engine_polars._emit_provider_io import (
|
|
71
|
+
_provider_key,
|
|
72
|
+
_provider_lookup_positional,
|
|
73
|
+
)
|
|
74
|
+
seeded = _provider_lookup_positional(
|
|
75
|
+
provider, _provider_key(path), path, columns,
|
|
76
|
+
)
|
|
77
|
+
if seeded is not None:
|
|
78
|
+
return seeded
|
|
79
|
+
return pl.DataFrame(
|
|
80
|
+
{c: [] for c in columns}, schema={c: pl.Utf8 for c in columns},
|
|
81
|
+
)
|
|
82
|
+
|
|
83
|
+
|
|
84
|
+
# ---------------------------------------------------------------------------
|
|
85
|
+
# Family 1 — period_param_sets (legacy: preprocessing/period_param_sets.py)
|
|
86
|
+
# ---------------------------------------------------------------------------
|
|
87
|
+
|
|
88
|
+
# (source pd_*.csv, target solve_data csv)
|
|
89
|
+
_PERIOD_PARAM_SOURCES: list[tuple[str, str]] = [
|
|
90
|
+
("pd_group.csv", "period_group.csv"),
|
|
91
|
+
("pd_node.csv", "period_node.csv"),
|
|
92
|
+
("pd_commodity.csv", "period_commodity.csv"),
|
|
93
|
+
("pd_process.csv", "period_process.csv"),
|
|
94
|
+
]
|
|
95
|
+
|
|
96
|
+
|
|
97
|
+
def derive_period_param_set(input_dir: Path, source_csv: str,
|
|
98
|
+
*, provider: "object | None" = None,
|
|
99
|
+
) -> pl.DataFrame:
|
|
100
|
+
"""Project the ``period`` column out of a ``pd_*.csv`` file.
|
|
101
|
+
|
|
102
|
+
Legacy: setof {(e, param, d, value) in entity__param__period} (d).
|
|
103
|
+
Order = first occurrence in the source CSV.
|
|
104
|
+
"""
|
|
105
|
+
df = _read_csv(input_dir / source_csv,
|
|
106
|
+
["entity", "param", "period", "value"],
|
|
107
|
+
provider=provider)
|
|
108
|
+
return (
|
|
109
|
+
df.filter(pl.col("period") != "")
|
|
110
|
+
.select("period")
|
|
111
|
+
.unique(maintain_order=True)
|
|
112
|
+
)
|
|
113
|
+
|
|
114
|
+
|
|
115
|
+
def emit_period_param_sets(input_dir: Path, solve_data_dir: Path,
|
|
116
|
+
*, provider) -> None:
|
|
117
|
+
"""Emit ``period_param_sets`` to the Provider."""
|
|
118
|
+
del solve_data_dir # legacy signature parity; keys are static
|
|
119
|
+
for source_csv, target_name in _PERIOD_PARAM_SOURCES:
|
|
120
|
+
_emit(provider, f"solve_data/{target_name}",
|
|
121
|
+
derive_period_param_set(input_dir, source_csv, provider=provider))
|
|
122
|
+
|
|
123
|
+
|
|
124
|
+
# ---------------------------------------------------------------------------
|
|
125
|
+
# Family 2 — invest_method_sets (legacy: preprocessing/invest_method_sets.py)
|
|
126
|
+
# ---------------------------------------------------------------------------
|
|
127
|
+
|
|
128
|
+
def _project_entity_by_method(
|
|
129
|
+
df: pl.DataFrame,
|
|
130
|
+
disallowed_methods: frozenset[str],
|
|
131
|
+
out_column: str,
|
|
132
|
+
) -> pl.DataFrame:
|
|
133
|
+
"""``setof {(e, m) : m not in disallowed} (e)`` — order preserved."""
|
|
134
|
+
return (
|
|
135
|
+
df.filter(
|
|
136
|
+
(pl.col("entity") != "") & (~pl.col("method").is_in(list(disallowed_methods)))
|
|
137
|
+
)
|
|
138
|
+
.select(alias_to_axis("entity", out_column))
|
|
139
|
+
.unique(maintain_order=True)
|
|
140
|
+
)
|
|
141
|
+
|
|
142
|
+
|
|
143
|
+
def derive_entity_invest(input_dir: Path,
|
|
144
|
+
*, provider: "object | None" = None,
|
|
145
|
+
) -> pl.DataFrame:
|
|
146
|
+
df = _read_csv(input_dir / "entity__invest_method.csv",
|
|
147
|
+
["entity", "method"], provider=provider)
|
|
148
|
+
return _project_entity_by_method(df, _INVEST_METHOD_NOT_ALLOWED, "entity")
|
|
149
|
+
|
|
150
|
+
|
|
151
|
+
def derive_entity_divest(input_dir: Path,
|
|
152
|
+
*, provider: "object | None" = None,
|
|
153
|
+
) -> pl.DataFrame:
|
|
154
|
+
df = _read_csv(input_dir / "entity__invest_method.csv",
|
|
155
|
+
["entity", "method"], provider=provider)
|
|
156
|
+
return _project_entity_by_method(df, _DIVEST_METHOD_NOT_ALLOWED, "entity")
|
|
157
|
+
|
|
158
|
+
|
|
159
|
+
def derive_group_invest(input_dir: Path,
|
|
160
|
+
*, provider: "object | None" = None,
|
|
161
|
+
) -> pl.DataFrame:
|
|
162
|
+
df = _read_csv(input_dir / "group__invest_method.csv",
|
|
163
|
+
["entity", "method"], provider=provider)
|
|
164
|
+
return _project_entity_by_method(df, _INVEST_METHOD_NOT_ALLOWED, "group")
|
|
165
|
+
|
|
166
|
+
|
|
167
|
+
def derive_group_divest(input_dir: Path,
|
|
168
|
+
*, provider: "object | None" = None,
|
|
169
|
+
) -> pl.DataFrame:
|
|
170
|
+
df = _read_csv(input_dir / "group__invest_method.csv",
|
|
171
|
+
["entity", "method"], provider=provider)
|
|
172
|
+
return _project_entity_by_method(df, _DIVEST_METHOD_NOT_ALLOWED, "group")
|
|
173
|
+
|
|
174
|
+
|
|
175
|
+
def emit_invest_method_sets(input_dir: Path, solve_data_dir: Path,
|
|
176
|
+
*, provider) -> None:
|
|
177
|
+
"""Emit ``invest_method_sets`` to the Provider."""
|
|
178
|
+
del solve_data_dir
|
|
179
|
+
_emit(provider, "solve_data/entityInvest.csv",
|
|
180
|
+
derive_entity_invest(input_dir, provider=provider))
|
|
181
|
+
_emit(provider, "solve_data/entityDivest.csv",
|
|
182
|
+
derive_entity_divest(input_dir, provider=provider))
|
|
183
|
+
_emit(provider, "solve_data/group_invest.csv",
|
|
184
|
+
derive_group_invest(input_dir, provider=provider))
|
|
185
|
+
_emit(provider, "solve_data/group_divest.csv",
|
|
186
|
+
derive_group_divest(input_dir, provider=provider))
|
|
187
|
+
|
|
188
|
+
|
|
189
|
+
# ---------------------------------------------------------------------------
|
|
190
|
+
# Family 3 — co2_method_sets (legacy: preprocessing/co2_method_sets.py)
|
|
191
|
+
# ---------------------------------------------------------------------------
|
|
192
|
+
|
|
193
|
+
def _project_group_by_method_in(
|
|
194
|
+
df: pl.DataFrame, allowed_methods: frozenset[str],
|
|
195
|
+
) -> pl.DataFrame:
|
|
196
|
+
return (
|
|
197
|
+
df.filter(
|
|
198
|
+
(pl.col("group") != "") & pl.col("method").is_in(list(allowed_methods))
|
|
199
|
+
)
|
|
200
|
+
.select("group")
|
|
201
|
+
.unique(maintain_order=True)
|
|
202
|
+
)
|
|
203
|
+
|
|
204
|
+
|
|
205
|
+
def derive_group_co2(input_dir: Path, kind: str,
|
|
206
|
+
*, provider: "object | None" = None,
|
|
207
|
+
) -> pl.DataFrame:
|
|
208
|
+
"""Project groups whose co2_method ∈ allowed set.
|
|
209
|
+
|
|
210
|
+
``kind`` is one of ``"price"``, ``"max_period"``, ``"max_total"``.
|
|
211
|
+
"""
|
|
212
|
+
allowed = {
|
|
213
|
+
"price": _CO2_PRICE_METHOD,
|
|
214
|
+
"max_period": _CO2_MAX_PERIOD_METHOD,
|
|
215
|
+
"max_total": _CO2_MAX_TOTAL_METHOD,
|
|
216
|
+
}[kind]
|
|
217
|
+
df = _read_csv(input_dir / "group__co2_method.csv",
|
|
218
|
+
["group", "method"], provider=provider)
|
|
219
|
+
return _project_group_by_method_in(df, allowed)
|
|
220
|
+
|
|
221
|
+
|
|
222
|
+
def emit_co2_method_sets(input_dir: Path, solve_data_dir: Path,
|
|
223
|
+
*, provider) -> None:
|
|
224
|
+
"""Emit ``co2_method_sets`` to the Provider."""
|
|
225
|
+
del solve_data_dir
|
|
226
|
+
for kind, target in (
|
|
227
|
+
("price", "group_co2_price.csv"),
|
|
228
|
+
("max_period", "group_co2_max_period.csv"),
|
|
229
|
+
("max_total", "group_co2_max_total.csv"),
|
|
230
|
+
):
|
|
231
|
+
_emit(provider, f"solve_data/{target}",
|
|
232
|
+
derive_group_co2(input_dir, kind, provider=provider))
|
|
233
|
+
|
|
234
|
+
|
|
235
|
+
# ---------------------------------------------------------------------------
|
|
236
|
+
# Family 4 — simple_projections (legacy: preprocessing/simple_projections.py)
|
|
237
|
+
# ---------------------------------------------------------------------------
|
|
238
|
+
|
|
239
|
+
def derive_optional_yes(input_dir: Path,
|
|
240
|
+
*, provider: "object | None" = None,
|
|
241
|
+
) -> pl.DataFrame:
|
|
242
|
+
"""optional_outputs filtered to value == 'yes'."""
|
|
243
|
+
df = _read_csv(input_dir / "optional_outputs.csv",
|
|
244
|
+
["output", "value"], provider=provider)
|
|
245
|
+
return (
|
|
246
|
+
df.filter(pl.col("value") == "yes")
|
|
247
|
+
.select("output")
|
|
248
|
+
.unique(maintain_order=True)
|
|
249
|
+
)
|
|
250
|
+
|
|
251
|
+
|
|
252
|
+
def derive_reserve_upDown_group(input_dir: Path,
|
|
253
|
+
*, provider: "object | None" = None,
|
|
254
|
+
) -> pl.DataFrame:
|
|
255
|
+
"""3-tuple (reserve, upDown, group) for method != 'no_reserve'."""
|
|
256
|
+
df = _read_csv(
|
|
257
|
+
input_dir / "reserve__upDown__group__method.csv",
|
|
258
|
+
["reserve", "upDown", "group", "method"],
|
|
259
|
+
provider=provider,
|
|
260
|
+
)
|
|
261
|
+
return (
|
|
262
|
+
df.filter(pl.col("method") != "no_reserve")
|
|
263
|
+
.select("reserve", "upDown", "group")
|
|
264
|
+
.unique(maintain_order=True)
|
|
265
|
+
)
|
|
266
|
+
|
|
267
|
+
|
|
268
|
+
def derive_group_loss_share(input_dir: Path,
|
|
269
|
+
*, provider: "object | None" = None,
|
|
270
|
+
) -> pl.DataFrame:
|
|
271
|
+
df = _read_csv(input_dir / "group__loss_share_type.csv",
|
|
272
|
+
["group", "type"], provider=provider)
|
|
273
|
+
return (
|
|
274
|
+
df.filter(pl.col("group") != "")
|
|
275
|
+
.select("group")
|
|
276
|
+
.unique(maintain_order=True)
|
|
277
|
+
)
|
|
278
|
+
|
|
279
|
+
|
|
280
|
+
def derive_def_optional_yes(input_dir: Path,
|
|
281
|
+
*, provider: "object | None" = None,
|
|
282
|
+
) -> pl.DataFrame:
|
|
283
|
+
"""def_optional_outputs filtered to 'yes' and not overridden 'no'."""
|
|
284
|
+
explicit = _read_csv(input_dir / "optional_outputs.csv",
|
|
285
|
+
["output", "value"], provider=provider)
|
|
286
|
+
explicit_no = explicit.filter(pl.col("value") == "no").select("output")
|
|
287
|
+
defaults = _read_csv(input_dir / "def_optional_outputs.csv",
|
|
288
|
+
["output", "value"], provider=provider)
|
|
289
|
+
return (
|
|
290
|
+
defaults.filter(pl.col("value") == "yes")
|
|
291
|
+
.join(explicit_no, on="output", how="anti")
|
|
292
|
+
.select("output")
|
|
293
|
+
.unique(maintain_order=True)
|
|
294
|
+
)
|
|
295
|
+
|
|
296
|
+
|
|
297
|
+
def derive_process_delayed(solve_data_dir: Path,
|
|
298
|
+
*, provider: "object | None" = None,
|
|
299
|
+
) -> pl.DataFrame:
|
|
300
|
+
"""Project ``process`` out of solve_data/process_delayed__duration.csv."""
|
|
301
|
+
df = _read_csv(
|
|
302
|
+
solve_data_dir / "process_delayed__duration.csv",
|
|
303
|
+
["process", "duration"],
|
|
304
|
+
provider=provider,
|
|
305
|
+
)
|
|
306
|
+
return (
|
|
307
|
+
df.filter(pl.col("process") != "")
|
|
308
|
+
.select("process")
|
|
309
|
+
.unique(maintain_order=True)
|
|
310
|
+
)
|
|
311
|
+
|
|
312
|
+
|
|
313
|
+
def derive_period_solve(solve_data_dir: Path,
|
|
314
|
+
*, provider: "object | None" = None,
|
|
315
|
+
) -> pl.DataFrame:
|
|
316
|
+
"""Project ``period`` out of solve_data/solve_period.csv."""
|
|
317
|
+
df = _read_csv(solve_data_dir / "solve_period.csv",
|
|
318
|
+
["solve", "period"], provider=provider)
|
|
319
|
+
return (
|
|
320
|
+
df.filter(pl.col("period") != "")
|
|
321
|
+
.select("period")
|
|
322
|
+
.unique(maintain_order=True)
|
|
323
|
+
)
|
|
324
|
+
|
|
325
|
+
|
|
326
|
+
def derive_time_set(input_dir: Path,
|
|
327
|
+
*, provider: "object | None" = None,
|
|
328
|
+
) -> pl.DataFrame:
|
|
329
|
+
"""Project ``time`` out of input/timeline.csv (cols: timeline, step, ...)."""
|
|
330
|
+
df = _read_csv(input_dir / "timeline.csv",
|
|
331
|
+
["timeline", "step"], provider=provider)
|
|
332
|
+
return (
|
|
333
|
+
df.filter(pl.col("step") != "")
|
|
334
|
+
.select(pl.col("step").alias("time"))
|
|
335
|
+
.unique(maintain_order=True)
|
|
336
|
+
)
|
|
337
|
+
|
|
338
|
+
|
|
339
|
+
def derive_enable_optional_outputs(solve_data_dir: Path,
|
|
340
|
+
*, provider: "object | None" = None,
|
|
341
|
+
) -> pl.DataFrame:
|
|
342
|
+
"""Union of optional_yes and def_optional_yes (order: optional first)."""
|
|
343
|
+
a = _read_csv(solve_data_dir / "optional_yes.csv", ["output"],
|
|
344
|
+
provider=provider)
|
|
345
|
+
b = _read_csv(solve_data_dir / "def_optional_yes.csv", ["output"],
|
|
346
|
+
provider=provider)
|
|
347
|
+
return (
|
|
348
|
+
pl.concat([a, b], how="vertical")
|
|
349
|
+
.filter(pl.col("output") != "")
|
|
350
|
+
.select("output")
|
|
351
|
+
.unique(maintain_order=True)
|
|
352
|
+
)
|
|
353
|
+
|
|
354
|
+
|
|
355
|
+
def derive_node_state_subset(
|
|
356
|
+
solve_data_dir: Path, binding_method: "str | tuple[str, ...]",
|
|
357
|
+
*, provider: "object | None" = None,
|
|
358
|
+
) -> pl.DataFrame:
|
|
359
|
+
"""Filter nodeState by one or more storage_binding_method values.
|
|
360
|
+
|
|
361
|
+
``binding_method`` is either a single string or a tuple of strings.
|
|
362
|
+
For ``nodeState_rp`` (Phase D onwards) the caller passes the tuple
|
|
363
|
+
``("bind_within_solve_blended_weights",
|
|
364
|
+
"bind_forward_only_blended_weights")`` so the resulting set is
|
|
365
|
+
the UNION of every node carrying either RP-flavoured method — the
|
|
366
|
+
SHARED RP machinery in ``model.py`` (``rp_inter_period_balance``,
|
|
367
|
+
``rp_inter_period_max_state``, ``maxState_rp_start``, and the
|
|
368
|
+
intra-period state-change branches in ``nodeBalance_eq``) fires
|
|
369
|
+
over this union; only ``rp_inter_period_cyclic`` further filters
|
|
370
|
+
back to the within_solve subset. For ``nodeStateBlock`` the caller
|
|
371
|
+
still passes the single string ``"bind_intraperiod_blocks"``.
|
|
372
|
+
"""
|
|
373
|
+
state = _read_csv(solve_data_dir / "nodeState.csv", ["node"],
|
|
374
|
+
provider=provider)
|
|
375
|
+
binding = _read_csv(
|
|
376
|
+
solve_data_dir / "node__storage_binding_method.csv",
|
|
377
|
+
["node", "method"], provider=provider,
|
|
378
|
+
)
|
|
379
|
+
if isinstance(binding_method, str):
|
|
380
|
+
methods = (binding_method,)
|
|
381
|
+
else:
|
|
382
|
+
methods = tuple(binding_method)
|
|
383
|
+
matching = (binding
|
|
384
|
+
.filter(pl.col("method").is_in(list(methods)))
|
|
385
|
+
.select("node"))
|
|
386
|
+
return (
|
|
387
|
+
state.join(matching, on="node", how="inner")
|
|
388
|
+
.select("node")
|
|
389
|
+
.unique(maintain_order=True)
|
|
390
|
+
)
|
|
391
|
+
|
|
392
|
+
|
|
393
|
+
# --- simple_setof_projections: 4 trivial single-column projections ---------
|
|
394
|
+
|
|
395
|
+
def derive_solve_period(input_dir: Path,
|
|
396
|
+
*, provider: "object | None" = None,
|
|
397
|
+
) -> pl.DataFrame:
|
|
398
|
+
"""(solve, period) projected from input/timesets_in_use.csv."""
|
|
399
|
+
df = _read_csv(
|
|
400
|
+
input_dir / "timesets_in_use.csv",
|
|
401
|
+
["solve", "period", "tb"],
|
|
402
|
+
provider=provider,
|
|
403
|
+
)
|
|
404
|
+
return (
|
|
405
|
+
df.filter((pl.col("solve") != "") & (pl.col("period") != ""))
|
|
406
|
+
.select("solve", "period")
|
|
407
|
+
.unique(maintain_order=True)
|
|
408
|
+
)
|
|
409
|
+
|
|
410
|
+
|
|
411
|
+
def derive_timeline(input_dir: Path,
|
|
412
|
+
*, provider: "object | None" = None,
|
|
413
|
+
) -> pl.DataFrame:
|
|
414
|
+
"""``timeline`` projected from input/timesets__timeline.csv (col 1)."""
|
|
415
|
+
df = _read_csv(
|
|
416
|
+
input_dir / "timesets__timeline.csv", ["tb", "timeline"],
|
|
417
|
+
provider=provider,
|
|
418
|
+
)
|
|
419
|
+
return (
|
|
420
|
+
df.filter(pl.col("timeline") != "")
|
|
421
|
+
.select("timeline")
|
|
422
|
+
.unique(maintain_order=True)
|
|
423
|
+
)
|
|
424
|
+
|
|
425
|
+
|
|
426
|
+
def derive_commodity_tier_ann(input_dir: Path,
|
|
427
|
+
*, provider: "object | None" = None,
|
|
428
|
+
) -> pl.DataFrame:
|
|
429
|
+
"""(commodity, tier) projected from input/commodity_ladder_annual.csv.
|
|
430
|
+
|
|
431
|
+
Header order: commodity, period, tier, price, quantity — tier is col 2.
|
|
432
|
+
"""
|
|
433
|
+
df = _read_csv(
|
|
434
|
+
input_dir / "commodity_ladder_annual.csv",
|
|
435
|
+
["commodity", "period", "tier", "price", "quantity"],
|
|
436
|
+
provider=provider,
|
|
437
|
+
)
|
|
438
|
+
return (
|
|
439
|
+
df.filter((pl.col("commodity") != "") & (pl.col("tier") != ""))
|
|
440
|
+
.select("commodity", "tier")
|
|
441
|
+
.unique(maintain_order=True)
|
|
442
|
+
)
|
|
443
|
+
|
|
444
|
+
|
|
445
|
+
# --- orchestrators for simple_projections (preserves legacy call order) ----
|
|
446
|
+
|
|
447
|
+
# --- emit_* twins for the simple_projections orchestrators ---------------
|
|
448
|
+
|
|
449
|
+
def emit_optional_yes(input_dir: Path, solve_data_dir: Path,
|
|
450
|
+
*, provider) -> None:
|
|
451
|
+
"""Emit ``optional_yes`` to the Provider."""
|
|
452
|
+
del solve_data_dir
|
|
453
|
+
_emit(provider, "solve_data/optional_yes.csv",
|
|
454
|
+
derive_optional_yes(input_dir, provider=provider))
|
|
455
|
+
|
|
456
|
+
|
|
457
|
+
def emit_reserve_upDown_group(input_dir: Path, solve_data_dir: Path,
|
|
458
|
+
*, provider) -> None:
|
|
459
|
+
"""Emit ``reserve_upDown_group`` to the Provider."""
|
|
460
|
+
del solve_data_dir
|
|
461
|
+
_emit(provider, "solve_data/reserve__upDown__group.csv",
|
|
462
|
+
derive_reserve_upDown_group(input_dir, provider=provider))
|
|
463
|
+
|
|
464
|
+
|
|
465
|
+
def emit_group_loss_share(input_dir: Path, solve_data_dir: Path,
|
|
466
|
+
*, provider) -> None:
|
|
467
|
+
"""Emit ``group_loss_share`` to the Provider."""
|
|
468
|
+
del solve_data_dir
|
|
469
|
+
_emit(provider, "solve_data/group_loss_share.csv",
|
|
470
|
+
derive_group_loss_share(input_dir, provider=provider))
|
|
471
|
+
|
|
472
|
+
|
|
473
|
+
def emit_def_optional_yes(input_dir: Path, solve_data_dir: Path,
|
|
474
|
+
*, provider) -> None:
|
|
475
|
+
"""Emit ``def_optional_yes`` to the Provider."""
|
|
476
|
+
del solve_data_dir
|
|
477
|
+
_emit(provider, "solve_data/def_optional_yes.csv",
|
|
478
|
+
derive_def_optional_yes(input_dir, provider=provider))
|
|
479
|
+
|
|
480
|
+
|
|
481
|
+
def emit_process_delayed(input_dir: Path, solve_data_dir: Path,
|
|
482
|
+
*, provider) -> None:
|
|
483
|
+
"""Emit ``process_delayed`` to the Provider."""
|
|
484
|
+
del input_dir
|
|
485
|
+
_emit(provider, "solve_data/process_delayed.csv",
|
|
486
|
+
derive_process_delayed(solve_data_dir, provider=provider))
|
|
487
|
+
|
|
488
|
+
|
|
489
|
+
def emit_period_solve(solve_data_dir: Path, *, provider) -> None:
|
|
490
|
+
"""Emit ``period_solve`` to the Provider."""
|
|
491
|
+
_emit(provider, "solve_data/period_solve.csv",
|
|
492
|
+
derive_period_solve(solve_data_dir, provider=provider))
|
|
493
|
+
|
|
494
|
+
|
|
495
|
+
def emit_time_set(input_dir: Path, solve_data_dir: Path,
|
|
496
|
+
*, provider) -> None:
|
|
497
|
+
"""Emit ``time_set`` to the Provider."""
|
|
498
|
+
del solve_data_dir
|
|
499
|
+
_emit(provider, "solve_data/time.csv",
|
|
500
|
+
derive_time_set(input_dir, provider=provider))
|
|
501
|
+
|
|
502
|
+
|
|
503
|
+
def emit_enable_optional_outputs(solve_data_dir: Path,
|
|
504
|
+
*, provider) -> None:
|
|
505
|
+
"""Emit ``enable_optional_outputs`` to the Provider."""
|
|
506
|
+
_emit(provider, "solve_data/enable_optional_outputs.csv",
|
|
507
|
+
derive_enable_optional_outputs(solve_data_dir, provider=provider))
|
|
508
|
+
|
|
509
|
+
|
|
510
|
+
def emit_node_state_subsets(solve_data_dir: Path,
|
|
511
|
+
*, provider) -> None:
|
|
512
|
+
"""Emit ``node_state_subsets`` to the Provider.
|
|
513
|
+
|
|
514
|
+
Phase E: ``nodeState_rp`` is the UNION of every node carrying any
|
|
515
|
+
of the three blended-weights methods —
|
|
516
|
+
``bind_within_solve_blended_weights`` (across-solve cyclic
|
|
517
|
+
closure), ``bind_within_period_blended_weights`` (per-FlexTool-
|
|
518
|
+
period cyclic closure), and ``bind_forward_only_blended_weights``
|
|
519
|
+
(no closure). The shared RP machinery in ``model.py``
|
|
520
|
+
(intra-period state-change branches in ``nodeBalance_eq``,
|
|
521
|
+
``rp_inter_period_balance``, ``rp_inter_period_max_state``,
|
|
522
|
+
``maxState_rp_start``) fires over this union; only the
|
|
523
|
+
``rp_inter_period_cyclic`` constraint further filters to the
|
|
524
|
+
within_solve ∪ within_period subset, with per-period pairing on
|
|
525
|
+
the optional ``d`` column carried on ``rp_base_first`` /
|
|
526
|
+
``rp_base_last`` (see ``model.py``'s cyclic-emit block).
|
|
527
|
+
"""
|
|
528
|
+
rp = derive_node_state_subset(
|
|
529
|
+
solve_data_dir,
|
|
530
|
+
("bind_within_solve_blended_weights",
|
|
531
|
+
"bind_within_period_blended_weights",
|
|
532
|
+
"bind_forward_only_blended_weights"),
|
|
533
|
+
provider=provider,
|
|
534
|
+
)
|
|
535
|
+
block = derive_node_state_subset(solve_data_dir, "bind_intraperiod_blocks",
|
|
536
|
+
provider=provider)
|
|
537
|
+
_emit(provider, K.SOLVE_DATA_NODE_STATE_RP, rp)
|
|
538
|
+
_emit(provider, "solve_data/nodeStateBlock.csv", block)
|
|
539
|
+
|
|
540
|
+
|
|
541
|
+
def emit_simple_setof_projections(input_dir: Path, solve_data_dir: Path,
|
|
542
|
+
*, provider) -> None:
|
|
543
|
+
"""Emit ``simple_setof_projections`` to the Provider."""
|
|
544
|
+
del solve_data_dir
|
|
545
|
+
_emit(provider, "solve_data/solve_period.csv",
|
|
546
|
+
derive_solve_period(input_dir, provider=provider))
|
|
547
|
+
_emit(provider, "solve_data/timeline.csv",
|
|
548
|
+
derive_timeline(input_dir, provider=provider))
|
|
549
|
+
_emit(provider, "solve_data/commodity__tier_ann.csv",
|
|
550
|
+
derive_commodity_tier_ann(input_dir, provider=provider))
|