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,574 @@
|
|
|
1
|
+
"""Reserve calculated params — per-solve emitters.
|
|
2
|
+
|
|
3
|
+
Fired per-solve from ``_emit_solve_time.run`` at batches 43, 44 and 49.
|
|
4
|
+
|
|
5
|
+
Three public entry points:
|
|
6
|
+
|
|
7
|
+
* :func:`emit_pdtReserve_upDown_group` — mod L1319. 4-branch hourly
|
|
8
|
+
resolution for reserve groups, emitting ``pdtReserve_upDown_group.csv``
|
|
9
|
+
``(reserve, upDown, group, param, period, time, value)``.
|
|
10
|
+
* :func:`emit_process_reserve_upDown_node_active_and_prundt` — mod
|
|
11
|
+
L1321-1322. Filters ``process_reserve_upDown_node`` by nonzero summed
|
|
12
|
+
reservation across the matching ``reserve__upDown__group`` × ``dt``
|
|
13
|
+
cross product, then emits ``prundt = process_reserve_upDown_node_active
|
|
14
|
+
× dt``.
|
|
15
|
+
* :func:`emit_process_reserve_filters_and_reliability` — mod L1655 /
|
|
16
|
+
L1660-1668. Emits the reliability fallback (default 1) and two
|
|
17
|
+
``> 0`` filter sets (``increase_reserve_ratio`` /
|
|
18
|
+
``large_failure_ratio``) plus the ``process_large_failure`` projection.
|
|
19
|
+
|
|
20
|
+
Output CSVs (7 total):
|
|
21
|
+
|
|
22
|
+
* ``pdtReserve_upDown_group.csv``
|
|
23
|
+
* ``process_reserve_upDown_node_active.csv``
|
|
24
|
+
* ``prundt.csv``
|
|
25
|
+
* ``p_process_reserve_upDown_node_reliability.csv``
|
|
26
|
+
* ``process_reserve_upDown_node_increase_reserve_ratio.csv``
|
|
27
|
+
* ``process_reserve_upDown_node_large_failure_ratio.csv``
|
|
28
|
+
* ``process_large_failure.csv``
|
|
29
|
+
|
|
30
|
+
Reuse note
|
|
31
|
+
----------
|
|
32
|
+
|
|
33
|
+
``flextool.engine_polars._reserve`` consumes these CSVs as RHS / domain
|
|
34
|
+
inputs (``prundt`` for v_reserve, ``pdtReserve_upDown_group_reservation``
|
|
35
|
+
for the balance constraint, etc.) but does not derive them — it is a
|
|
36
|
+
constraint-builder that runs *after* preprocessing. No code is shared
|
|
37
|
+
across the port boundary; this module mirrors the legacy emitter's
|
|
38
|
+
shape verbatim for byte-identical parity.
|
|
39
|
+
|
|
40
|
+
Float values formatted with ``repr(float(v))`` for byte-identical
|
|
41
|
+
parity with the legacy emitter.
|
|
42
|
+
"""
|
|
43
|
+
from __future__ import annotations
|
|
44
|
+
|
|
45
|
+
from pathlib import Path
|
|
46
|
+
|
|
47
|
+
import polars as pl
|
|
48
|
+
|
|
49
|
+
from flextool.engine_polars._emit_provider_io import (
|
|
50
|
+
_emit,
|
|
51
|
+
_provider_key,
|
|
52
|
+
)
|
|
53
|
+
|
|
54
|
+
|
|
55
|
+
# ---------------------------------------------------------------------------
|
|
56
|
+
# I/O contract: legacy emitters in this family used
|
|
57
|
+
# ``path.open("w") + fh.write(...)`` with plain ``\n`` line terminators
|
|
58
|
+
# (no CRLF), so the default polars ``write_csv`` line ending matches
|
|
59
|
+
# byte-for-byte. Float cells are pre-rendered with ``repr(float(v))``
|
|
60
|
+
# by the ``derive_*`` builders, so the underlying frame is all-``Utf8``
|
|
61
|
+
# and polars does no extra numeric formatting at emission time.
|
|
62
|
+
# ---------------------------------------------------------------------------
|
|
63
|
+
|
|
64
|
+
|
|
65
|
+
def _to_utf8_frame(
|
|
66
|
+
headers: tuple[str, ...],
|
|
67
|
+
rows: list[tuple],
|
|
68
|
+
) -> pl.DataFrame:
|
|
69
|
+
"""Build an all-``Utf8`` polars frame from a header tuple + row list.
|
|
70
|
+
|
|
71
|
+
Each cell is taken verbatim when already a string, otherwise via
|
|
72
|
+
``str(v)``. All ``derive_*`` builders in this module pre-render
|
|
73
|
+
float cells through ``repr(float(v))`` so byte parity with the
|
|
74
|
+
legacy emit holds.
|
|
75
|
+
"""
|
|
76
|
+
cols: dict[str, list[str]] = {h: [] for h in headers}
|
|
77
|
+
for row in rows:
|
|
78
|
+
for h, v in zip(headers, row):
|
|
79
|
+
cols[h].append(v if isinstance(v, str) else str(v))
|
|
80
|
+
return pl.DataFrame(cols, schema={h: pl.Utf8 for h in headers})
|
|
81
|
+
|
|
82
|
+
|
|
83
|
+
# ---------------------------------------------------------------------------
|
|
84
|
+
# Native-frame readers — same shape as _emit_inflow_scaling / _pdt_lookup
|
|
85
|
+
# helpers. The legacy emitter wrote plain text with ``repr(v)``; these
|
|
86
|
+
# read the in-memory polars frame directly via
|
|
87
|
+
# ``provider.get(_provider_key(path))`` instead of round-tripping through
|
|
88
|
+
# CSV text.
|
|
89
|
+
#
|
|
90
|
+
# Type-fidelity contract — reproduce *exactly* what ``line.split(",")``
|
|
91
|
+
# over a ``DataFrame.write_csv`` serialisation would have yielded:
|
|
92
|
+
#
|
|
93
|
+
# * Key columns (dict-key / structural string positions) were string
|
|
94
|
+
# cells. ``write_csv`` serialises ``null`` → ``""`` and any scalar
|
|
95
|
+
# to its textual form; we coerce each key cell with :func:`_cell_str`
|
|
96
|
+
# and apply the original truthiness guard to the *string* form so a
|
|
97
|
+
# null cell is skipped while a literal ``"0"`` is kept.
|
|
98
|
+
# * Value columns were re-coerced with ``float(...)``. We apply the same
|
|
99
|
+
# coercion to the native cell and widen the legacy ``except
|
|
100
|
+
# ValueError`` to ``except (ValueError, TypeError)`` so a null value
|
|
101
|
+
# cell is skipped (matching the legacy empty-string ``ValueError``).
|
|
102
|
+
#
|
|
103
|
+
# ``provider.get`` returns data rows only (no header), so there is no
|
|
104
|
+
# header row to skip; an empty / missing frame yields the same empty
|
|
105
|
+
# output the legacy loop produced.
|
|
106
|
+
# ---------------------------------------------------------------------------
|
|
107
|
+
|
|
108
|
+
|
|
109
|
+
def _cell_str(value: "object | None") -> str:
|
|
110
|
+
"""Reproduce a CSV cell string for a native frame value.
|
|
111
|
+
|
|
112
|
+
``DataFrame.write_csv`` renders ``null`` as the empty string and every
|
|
113
|
+
other scalar as its textual form; the legacy ``line.split(",")`` then
|
|
114
|
+
read those strings back. Mirror that here so dict keys / structural
|
|
115
|
+
strings stay byte-identical to the legacy CSV round-trip.
|
|
116
|
+
"""
|
|
117
|
+
return "" if value is None else str(value)
|
|
118
|
+
|
|
119
|
+
|
|
120
|
+
def _read_singles(path: Path,
|
|
121
|
+
*, provider: "object | None" = None) -> list[str]:
|
|
122
|
+
"""First-column reader (data rows only)."""
|
|
123
|
+
df = provider.get(_provider_key(path))
|
|
124
|
+
if df is None:
|
|
125
|
+
return []
|
|
126
|
+
out: list[str] = []
|
|
127
|
+
for row in df.iter_rows():
|
|
128
|
+
if not row:
|
|
129
|
+
continue
|
|
130
|
+
c0 = _cell_str(row[0])
|
|
131
|
+
if c0:
|
|
132
|
+
out.append(c0)
|
|
133
|
+
return out
|
|
134
|
+
|
|
135
|
+
|
|
136
|
+
def _read_pairs(path: Path,
|
|
137
|
+
*, provider: "object | None" = None) -> list[tuple[str, str]]:
|
|
138
|
+
"""First-two-column reader (data rows only)."""
|
|
139
|
+
df = provider.get(_provider_key(path))
|
|
140
|
+
if df is None:
|
|
141
|
+
return []
|
|
142
|
+
out: list[tuple[str, str]] = []
|
|
143
|
+
for row in df.iter_rows():
|
|
144
|
+
if len(row) < 2:
|
|
145
|
+
continue
|
|
146
|
+
c0, c1 = _cell_str(row[0]), _cell_str(row[1])
|
|
147
|
+
if c0 and c1:
|
|
148
|
+
out.append((c0, c1))
|
|
149
|
+
return out
|
|
150
|
+
|
|
151
|
+
|
|
152
|
+
def _read_n_col(path: Path, n: int,
|
|
153
|
+
*, provider: "object | None" = None) -> list[tuple[str, ...]]:
|
|
154
|
+
"""First-n-column reader; rows with any empty key skipped."""
|
|
155
|
+
df = provider.get(_provider_key(path))
|
|
156
|
+
if df is None:
|
|
157
|
+
return []
|
|
158
|
+
out: list[tuple[str, ...]] = []
|
|
159
|
+
for row in df.iter_rows():
|
|
160
|
+
if len(row) < n:
|
|
161
|
+
continue
|
|
162
|
+
cells = tuple(_cell_str(row[i]) for i in range(n))
|
|
163
|
+
if all(cells):
|
|
164
|
+
out.append(cells)
|
|
165
|
+
return out
|
|
166
|
+
|
|
167
|
+
|
|
168
|
+
def _read_pairs_to_dict(path: Path, key_col: int,
|
|
169
|
+
*, provider: "object | None" = None,
|
|
170
|
+
) -> dict[str, list[str]]:
|
|
171
|
+
"""Two-col frame → {row[key_col]: [row[other_col], ...]} preserving order."""
|
|
172
|
+
out: dict[str, list[str]] = {}
|
|
173
|
+
df = provider.get(_provider_key(path))
|
|
174
|
+
if df is None:
|
|
175
|
+
return out
|
|
176
|
+
other_col = 1 - key_col
|
|
177
|
+
for row in df.iter_rows():
|
|
178
|
+
if len(row) < 2:
|
|
179
|
+
continue
|
|
180
|
+
c0, c1 = _cell_str(row[0]), _cell_str(row[1])
|
|
181
|
+
if c0 and c1:
|
|
182
|
+
cells = (c0, c1)
|
|
183
|
+
out.setdefault(cells[key_col], []).append(cells[other_col])
|
|
184
|
+
return out
|
|
185
|
+
|
|
186
|
+
|
|
187
|
+
def _read_pbt_reserve(
|
|
188
|
+
path: Path,
|
|
189
|
+
*, provider: "object | None" = None,
|
|
190
|
+
) -> dict[tuple[str, str, str, str, str, str, str], float]:
|
|
191
|
+
"""``pbt_reserve__upDown__group.csv`` →
|
|
192
|
+
{(r, ud, g, param, branch, ts, t): float}. Malformed / non-numeric
|
|
193
|
+
rows silently skipped (matches legacy)."""
|
|
194
|
+
out: dict[tuple[str, str, str, str, str, str, str], float] = {}
|
|
195
|
+
df = provider.get(_provider_key(path))
|
|
196
|
+
if df is None:
|
|
197
|
+
return out
|
|
198
|
+
for row in df.iter_rows():
|
|
199
|
+
if len(row) < 8:
|
|
200
|
+
continue
|
|
201
|
+
c = [_cell_str(row[i]) for i in range(7)]
|
|
202
|
+
if all(c):
|
|
203
|
+
try:
|
|
204
|
+
out[(c[0], c[1], c[2], c[3], c[4], c[5], c[6])] = float(row[7])
|
|
205
|
+
except (ValueError, TypeError):
|
|
206
|
+
continue
|
|
207
|
+
return out
|
|
208
|
+
|
|
209
|
+
|
|
210
|
+
def _read_pt_reserve(
|
|
211
|
+
path: Path,
|
|
212
|
+
*, provider: "object | None" = None,
|
|
213
|
+
) -> dict[tuple[str, str, str, str, str], float]:
|
|
214
|
+
"""``pt_reserve__upDown__group.csv`` →
|
|
215
|
+
{(r, ud, g, param, t): float}."""
|
|
216
|
+
out: dict[tuple[str, str, str, str, str], float] = {}
|
|
217
|
+
df = provider.get(_provider_key(path))
|
|
218
|
+
if df is None:
|
|
219
|
+
return out
|
|
220
|
+
for row in df.iter_rows():
|
|
221
|
+
if len(row) < 6:
|
|
222
|
+
continue
|
|
223
|
+
c = [_cell_str(row[i]) for i in range(5)]
|
|
224
|
+
if all(c):
|
|
225
|
+
try:
|
|
226
|
+
out[(c[0], c[1], c[2], c[3], c[4])] = float(row[5])
|
|
227
|
+
except (ValueError, TypeError):
|
|
228
|
+
continue
|
|
229
|
+
return out
|
|
230
|
+
|
|
231
|
+
|
|
232
|
+
def _read_p_reserve(
|
|
233
|
+
path: Path,
|
|
234
|
+
*, provider: "object | None" = None,
|
|
235
|
+
) -> dict[tuple[str, str, str, str], float]:
|
|
236
|
+
"""``p_reserve__upDown__group.csv`` → {(r, ud, g, param): float}."""
|
|
237
|
+
out: dict[tuple[str, str, str, str], float] = {}
|
|
238
|
+
df = provider.get(_provider_key(path))
|
|
239
|
+
if df is None:
|
|
240
|
+
return out
|
|
241
|
+
for row in df.iter_rows():
|
|
242
|
+
if len(row) < 5:
|
|
243
|
+
continue
|
|
244
|
+
c = [_cell_str(row[i]) for i in range(4)]
|
|
245
|
+
if all(c):
|
|
246
|
+
try:
|
|
247
|
+
out[(c[0], c[1], c[2], c[3])] = float(row[4])
|
|
248
|
+
except (ValueError, TypeError):
|
|
249
|
+
continue
|
|
250
|
+
return out
|
|
251
|
+
|
|
252
|
+
|
|
253
|
+
# Reserve param table fixed across the writers — flextool_base.dat L183
|
|
254
|
+
# defines only the ``reservation`` reserveTimeParam. Default per
|
|
255
|
+
# reserveParam_defaults (mod L493) is 0 for reservation.
|
|
256
|
+
_RESERVE_TIME_PARAMS: tuple[str, ...] = ("reservation",)
|
|
257
|
+
_RESERVATION_DEFAULT: float = 0.0
|
|
258
|
+
|
|
259
|
+
|
|
260
|
+
# ---------------------------------------------------------------------------
|
|
261
|
+
# write_pdtReserve_upDown_group (mod L1319)
|
|
262
|
+
# ---------------------------------------------------------------------------
|
|
263
|
+
|
|
264
|
+
|
|
265
|
+
def _resolve_pdtReserve(
|
|
266
|
+
r: str, ud: str, g: str, param: str, d: str, t: str,
|
|
267
|
+
*,
|
|
268
|
+
pbt: dict[tuple[str, str, str, str, str, str, str], float],
|
|
269
|
+
pt: dict[tuple[str, str, str, str, str], float],
|
|
270
|
+
p: dict[tuple[str, str, str, str], float],
|
|
271
|
+
ts_for_d: dict[str, list[str]],
|
|
272
|
+
tb_for_d: dict[str, list[str]],
|
|
273
|
+
pe_for_d: dict[str, list[str]],
|
|
274
|
+
g_stoch: bool,
|
|
275
|
+
) -> float:
|
|
276
|
+
"""4-branch fallback mirroring ``pdtReserve_upDown_group``'s mod body.
|
|
277
|
+
|
|
278
|
+
Branches mirror ``pdtProcess``'s branches 1, 2, 4, 5 (no period axis,
|
|
279
|
+
no def1 — and the scalar branch returns the table's default of 0
|
|
280
|
+
for ``reservation`` when the (r, ud, g) row is missing).
|
|
281
|
+
"""
|
|
282
|
+
# Branch 1: stochastic + outer-d's ts/tb.
|
|
283
|
+
if g_stoch:
|
|
284
|
+
ts_list = ts_for_d.get(d, ())
|
|
285
|
+
tb_list = tb_for_d.get(d, ())
|
|
286
|
+
total = 0.0
|
|
287
|
+
hit = False
|
|
288
|
+
for tb in tb_list:
|
|
289
|
+
for ts in ts_list:
|
|
290
|
+
v = pbt.get((r, ud, g, param, tb, ts, t))
|
|
291
|
+
if v is not None:
|
|
292
|
+
total += v
|
|
293
|
+
hit = True
|
|
294
|
+
if hit:
|
|
295
|
+
return total
|
|
296
|
+
# Branch 2: parent period pe of d, tb from solve_branch[pe], ts from
|
|
297
|
+
# period__time_first[d].
|
|
298
|
+
ts_list = ts_for_d.get(d, ())
|
|
299
|
+
pe_list = pe_for_d.get(d, ())
|
|
300
|
+
if pe_list and ts_list:
|
|
301
|
+
total = 0.0
|
|
302
|
+
hit = False
|
|
303
|
+
for pe in pe_list:
|
|
304
|
+
for tb in tb_for_d.get(pe, ()):
|
|
305
|
+
for ts in ts_list:
|
|
306
|
+
v = pbt.get((r, ud, g, param, tb, ts, t))
|
|
307
|
+
if v is not None:
|
|
308
|
+
total += v
|
|
309
|
+
hit = True
|
|
310
|
+
if hit:
|
|
311
|
+
return total
|
|
312
|
+
# Branch 3: time axis.
|
|
313
|
+
v = pt.get((r, ud, g, param, t))
|
|
314
|
+
if v is not None:
|
|
315
|
+
return v
|
|
316
|
+
# Branch 4: scalar (with table default 0 for ``reservation``).
|
|
317
|
+
v = p.get((r, ud, g, param))
|
|
318
|
+
if v is not None:
|
|
319
|
+
return v
|
|
320
|
+
return _RESERVATION_DEFAULT
|
|
321
|
+
|
|
322
|
+
|
|
323
|
+
def derive_pdtReserve_upDown_group(
|
|
324
|
+
input_dir: Path, solve_data_dir: Path,
|
|
325
|
+
*, provider: "object | None" = None,
|
|
326
|
+
) -> pl.DataFrame:
|
|
327
|
+
"""Build the canonical ``pdtReserve_upDown_group`` frame
|
|
328
|
+
``(reserve, upDown, group, param, period, time, value)``.
|
|
329
|
+
|
|
330
|
+
Value column is pre-rendered with ``repr(float(v))`` for byte
|
|
331
|
+
parity with the legacy emitter.
|
|
332
|
+
"""
|
|
333
|
+
pbt = _read_pbt_reserve(
|
|
334
|
+
input_dir / "pbt_reserve__upDown__group.csv", provider=provider,
|
|
335
|
+
)
|
|
336
|
+
pt = _read_pt_reserve(
|
|
337
|
+
input_dir / "pt_reserve__upDown__group.csv", provider=provider,
|
|
338
|
+
)
|
|
339
|
+
p = _read_p_reserve(
|
|
340
|
+
input_dir / "p_reserve__upDown__group.csv", provider=provider,
|
|
341
|
+
)
|
|
342
|
+
|
|
343
|
+
ts_for_d = _read_pairs_to_dict(
|
|
344
|
+
solve_data_dir / "first_timesteps.csv", 0, provider=provider,
|
|
345
|
+
)
|
|
346
|
+
tb_for_d = _read_pairs_to_dict(
|
|
347
|
+
solve_data_dir / "solve_branch__time_branch.csv", 0, provider=provider,
|
|
348
|
+
)
|
|
349
|
+
pe_for_d = _read_pairs_to_dict(
|
|
350
|
+
solve_data_dir / "period__branch.csv", 1, provider=provider,
|
|
351
|
+
)
|
|
352
|
+
groups_stoch = frozenset(
|
|
353
|
+
_read_singles(
|
|
354
|
+
input_dir / "groupIncludeStochastics.csv", provider=provider,
|
|
355
|
+
)
|
|
356
|
+
)
|
|
357
|
+
|
|
358
|
+
rug = _read_n_col(
|
|
359
|
+
solve_data_dir / "reserve__upDown__group.csv", 3, provider=provider,
|
|
360
|
+
)
|
|
361
|
+
dt = _read_pairs(solve_data_dir / "steps_in_use.csv", provider=provider)
|
|
362
|
+
|
|
363
|
+
rows: list[tuple] = []
|
|
364
|
+
for (r, ud, g) in rug:
|
|
365
|
+
g_stoch = g in groups_stoch
|
|
366
|
+
for param in _RESERVE_TIME_PARAMS:
|
|
367
|
+
for (d, t) in dt:
|
|
368
|
+
val = _resolve_pdtReserve(
|
|
369
|
+
r, ud, g, param, d, t,
|
|
370
|
+
pbt=pbt, pt=pt, p=p,
|
|
371
|
+
ts_for_d=ts_for_d,
|
|
372
|
+
tb_for_d=tb_for_d,
|
|
373
|
+
pe_for_d=pe_for_d,
|
|
374
|
+
g_stoch=g_stoch,
|
|
375
|
+
)
|
|
376
|
+
rows.append((r, ud, g, param, d, t, repr(float(val))))
|
|
377
|
+
return _to_utf8_frame(
|
|
378
|
+
("reserve", "upDown", "group", "param", "period", "time", "value"),
|
|
379
|
+
rows,
|
|
380
|
+
)
|
|
381
|
+
|
|
382
|
+
|
|
383
|
+
def emit_pdtReserve_upDown_group(
|
|
384
|
+
input_dir: Path, solve_data_dir: Path,
|
|
385
|
+
*, provider,
|
|
386
|
+
) -> None:
|
|
387
|
+
"""Emit ``pdtReserve_upDown_group`` to the Provider."""
|
|
388
|
+
_emit(
|
|
389
|
+
provider, "solve_data/pdtReserve_upDown_group.csv",
|
|
390
|
+
derive_pdtReserve_upDown_group(
|
|
391
|
+
input_dir, solve_data_dir, provider=provider,
|
|
392
|
+
),
|
|
393
|
+
)
|
|
394
|
+
|
|
395
|
+
|
|
396
|
+
# ---------------------------------------------------------------------------
|
|
397
|
+
# write_process_reserve_upDown_node_active_and_prundt (mod L1321-1322)
|
|
398
|
+
# ---------------------------------------------------------------------------
|
|
399
|
+
|
|
400
|
+
|
|
401
|
+
def _compute_process_reserve_active(
|
|
402
|
+
input_dir: Path, solve_data_dir: Path,
|
|
403
|
+
*, provider: "object | None" = None,
|
|
404
|
+
) -> tuple[list[tuple[str, str, str, str]], list[tuple[str, str]]]:
|
|
405
|
+
"""Shared computation for the active/prundt pair — returns the
|
|
406
|
+
active ``(p, r, ud, n)`` list and the ``dt`` pair list."""
|
|
407
|
+
pdt_reserve: dict[tuple[str, str, str, str, str, str], float] = {}
|
|
408
|
+
pdt_path = solve_data_dir / "pdtReserve_upDown_group.csv"
|
|
409
|
+
pdt_df = provider.get(_provider_key(pdt_path))
|
|
410
|
+
if pdt_df is not None:
|
|
411
|
+
for row in pdt_df.iter_rows():
|
|
412
|
+
if len(row) < 7:
|
|
413
|
+
continue
|
|
414
|
+
c = [_cell_str(row[i]) for i in range(6)]
|
|
415
|
+
if all(c):
|
|
416
|
+
try:
|
|
417
|
+
pdt_reserve[(c[0], c[1], c[2], c[3], c[4], c[5])] = float(row[6])
|
|
418
|
+
except (ValueError, TypeError):
|
|
419
|
+
continue
|
|
420
|
+
|
|
421
|
+
rug_by_ru: dict[tuple[str, str], list[str]] = {}
|
|
422
|
+
for r, ud, g in _read_n_col(
|
|
423
|
+
solve_data_dir / "reserve__upDown__group.csv", 3, provider=provider,
|
|
424
|
+
):
|
|
425
|
+
rug_by_ru.setdefault((r, ud), []).append(g)
|
|
426
|
+
|
|
427
|
+
dt = _read_pairs(solve_data_dir / "steps_in_use.csv", provider=provider)
|
|
428
|
+
prun = _read_n_col(
|
|
429
|
+
input_dir / "process__reserve__upDown__node.csv", 4, provider=provider,
|
|
430
|
+
)
|
|
431
|
+
|
|
432
|
+
active_rows: list[tuple[str, str, str, str]] = []
|
|
433
|
+
for (p, r, ud, n) in prun:
|
|
434
|
+
groups = rug_by_ru.get((r, ud), ())
|
|
435
|
+
total = 0.0
|
|
436
|
+
for g in groups:
|
|
437
|
+
for (d, t) in dt:
|
|
438
|
+
total += pdt_reserve.get(
|
|
439
|
+
(r, ud, g, "reservation", d, t), 0.0,
|
|
440
|
+
)
|
|
441
|
+
if total != 0.0:
|
|
442
|
+
active_rows.append((p, r, ud, n))
|
|
443
|
+
return active_rows, dt
|
|
444
|
+
|
|
445
|
+
|
|
446
|
+
def emit_process_reserve_upDown_node_active_and_prundt(
|
|
447
|
+
input_dir: Path, solve_data_dir: Path,
|
|
448
|
+
*, provider,
|
|
449
|
+
) -> None:
|
|
450
|
+
"""Emit ``process_reserve_upDown_node_active_and_prundt`` to the Provider."""
|
|
451
|
+
active_rows, dt = _compute_process_reserve_active(
|
|
452
|
+
input_dir, solve_data_dir, provider=provider,
|
|
453
|
+
)
|
|
454
|
+
_emit(
|
|
455
|
+
provider,
|
|
456
|
+
"solve_data/process_reserve_upDown_node_active.csv",
|
|
457
|
+
_to_utf8_frame(
|
|
458
|
+
("process", "reserve", "upDown", "node"), active_rows,
|
|
459
|
+
),
|
|
460
|
+
)
|
|
461
|
+
prundt_rows: list[tuple[str, str, str, str, str, str]] = []
|
|
462
|
+
for (p, r, ud, n) in active_rows:
|
|
463
|
+
for (d, t) in dt:
|
|
464
|
+
prundt_rows.append((p, r, ud, n, d, t))
|
|
465
|
+
_emit(
|
|
466
|
+
provider,
|
|
467
|
+
"solve_data/prundt.csv",
|
|
468
|
+
_to_utf8_frame(
|
|
469
|
+
("process", "reserve", "upDown", "node", "period", "time"),
|
|
470
|
+
prundt_rows,
|
|
471
|
+
),
|
|
472
|
+
)
|
|
473
|
+
|
|
474
|
+
|
|
475
|
+
# ---------------------------------------------------------------------------
|
|
476
|
+
# write_process_reserve_filters_and_reliability (mod L1655, L1660-1668)
|
|
477
|
+
# ---------------------------------------------------------------------------
|
|
478
|
+
|
|
479
|
+
|
|
480
|
+
def _read_p_process_reserve(
|
|
481
|
+
path: Path,
|
|
482
|
+
*, provider: "object | None" = None,
|
|
483
|
+
) -> dict[tuple[str, str, str, str, str], float]:
|
|
484
|
+
"""``p_process__reserve__upDown__node.csv`` →
|
|
485
|
+
{(process, reserve, upDown, node, param): float}."""
|
|
486
|
+
out: dict[tuple[str, str, str, str, str], float] = {}
|
|
487
|
+
df = provider.get(_provider_key(path))
|
|
488
|
+
if df is None:
|
|
489
|
+
return out
|
|
490
|
+
for row in df.iter_rows():
|
|
491
|
+
if len(row) < 6:
|
|
492
|
+
continue
|
|
493
|
+
c = [_cell_str(row[i]) for i in range(5)]
|
|
494
|
+
if all(c):
|
|
495
|
+
try:
|
|
496
|
+
out[(c[0], c[1], c[2], c[3], c[4])] = float(row[5])
|
|
497
|
+
except (ValueError, TypeError):
|
|
498
|
+
continue
|
|
499
|
+
return out
|
|
500
|
+
|
|
501
|
+
|
|
502
|
+
def _compute_reserve_filters(
|
|
503
|
+
input_dir: Path, solve_data_dir: Path,
|
|
504
|
+
*, provider: "object | None" = None,
|
|
505
|
+
) -> tuple[
|
|
506
|
+
list[tuple[str, str, str, str, str]], # reliability rows (with value)
|
|
507
|
+
list[tuple[str, str, str, str]], # increase_reserve_ratio rows
|
|
508
|
+
list[tuple[str, str, str, str]], # large_failure_ratio rows
|
|
509
|
+
list[tuple[str]], # process_large_failure rows
|
|
510
|
+
]:
|
|
511
|
+
"""Shared scan of the four reserve-filter frames. All value cells
|
|
512
|
+
pre-stringified via ``repr(float(v))``.
|
|
513
|
+
"""
|
|
514
|
+
p_prn = _read_p_process_reserve(
|
|
515
|
+
input_dir / "p_process__reserve__upDown__node.csv", provider=provider,
|
|
516
|
+
)
|
|
517
|
+
active = _read_n_col(
|
|
518
|
+
solve_data_dir / "process_reserve_upDown_node_active.csv", 4,
|
|
519
|
+
provider=provider,
|
|
520
|
+
)
|
|
521
|
+
|
|
522
|
+
rel_rows: list[tuple[str, str, str, str, str]] = []
|
|
523
|
+
incr_rows: list[tuple[str, str, str, str]] = []
|
|
524
|
+
lf_rows: list[tuple[str, str, str, str]] = []
|
|
525
|
+
for (p, r, ud, n) in active:
|
|
526
|
+
v = p_prn.get((p, r, ud, n, "reliability"), 1.0)
|
|
527
|
+
if v == 0.0:
|
|
528
|
+
v = 1.0
|
|
529
|
+
rel_rows.append((p, r, ud, n, repr(float(v))))
|
|
530
|
+
if p_prn.get((p, r, ud, n, "increase_reserve_ratio"), 0.0) > 0:
|
|
531
|
+
incr_rows.append((p, r, ud, n))
|
|
532
|
+
if p_prn.get((p, r, ud, n, "large_failure_ratio"), 0.0) > 0:
|
|
533
|
+
lf_rows.append((p, r, ud, n))
|
|
534
|
+
|
|
535
|
+
process_lf = [
|
|
536
|
+
(p,) for p in dict.fromkeys(p for (p, _, _, _) in lf_rows)
|
|
537
|
+
]
|
|
538
|
+
return rel_rows, incr_rows, lf_rows, process_lf
|
|
539
|
+
|
|
540
|
+
|
|
541
|
+
def emit_process_reserve_filters_and_reliability(
|
|
542
|
+
input_dir: Path, solve_data_dir: Path,
|
|
543
|
+
*, provider,
|
|
544
|
+
) -> None:
|
|
545
|
+
"""Emit ``process_reserve_filters_and_reliability`` to the Provider."""
|
|
546
|
+
rel_rows, incr_rows, lf_rows, process_lf = _compute_reserve_filters(
|
|
547
|
+
input_dir, solve_data_dir, provider=provider,
|
|
548
|
+
)
|
|
549
|
+
_emit(
|
|
550
|
+
provider,
|
|
551
|
+
"solve_data/p_process_reserve_upDown_node_reliability.csv",
|
|
552
|
+
_to_utf8_frame(
|
|
553
|
+
("process", "reserve", "upDown", "node", "value"), rel_rows,
|
|
554
|
+
),
|
|
555
|
+
)
|
|
556
|
+
_emit(
|
|
557
|
+
provider,
|
|
558
|
+
"solve_data/process_reserve_upDown_node_increase_reserve_ratio.csv",
|
|
559
|
+
_to_utf8_frame(
|
|
560
|
+
("process", "reserve", "upDown", "node"), incr_rows,
|
|
561
|
+
),
|
|
562
|
+
)
|
|
563
|
+
_emit(
|
|
564
|
+
provider,
|
|
565
|
+
"solve_data/process_reserve_upDown_node_large_failure_ratio.csv",
|
|
566
|
+
_to_utf8_frame(
|
|
567
|
+
("process", "reserve", "upDown", "node"), lf_rows,
|
|
568
|
+
),
|
|
569
|
+
)
|
|
570
|
+
_emit(
|
|
571
|
+
provider,
|
|
572
|
+
"solve_data/process_large_failure.csv",
|
|
573
|
+
_to_utf8_frame(("process",), process_lf),
|
|
574
|
+
)
|