flextool 4.0.0__tar.gz
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-4.0.0/LICENSE.txt +19 -0
- flextool-4.0.0/PKG-INFO +217 -0
- flextool-4.0.0/README.md +149 -0
- flextool-4.0.0/flextool/__init__.py +41 -0
- flextool-4.0.0/flextool/_mem_sampler.py +193 -0
- flextool-4.0.0/flextool/_resources.py +43 -0
- flextool-4.0.0/flextool/calibrate/__init__.py +51 -0
- flextool-4.0.0/flextool/calibrate/__main__.py +11 -0
- flextool-4.0.0/flextool/calibrate/_cli.py +316 -0
- flextool-4.0.0/flextool/calibrate/_db_alt.py +166 -0
- flextool-4.0.0/flextool/calibrate/_final_outputs.py +110 -0
- flextool-4.0.0/flextool/calibrate/_guard.py +151 -0
- flextool-4.0.0/flextool/calibrate/_loop.py +558 -0
- flextool-4.0.0/flextool/calibrate/_readers.py +223 -0
- flextool-4.0.0/flextool/calibrate/_report.py +263 -0
- flextool-4.0.0/flextool/calibrate/_sizing.py +699 -0
- flextool-4.0.0/flextool/calibrate/_solve.py +134 -0
- flextool-4.0.0/flextool/calibrate/_solve_status.py +495 -0
- flextool-4.0.0/flextool/cli/__init__.py +9 -0
- flextool-4.0.0/flextool/cli/_console.py +51 -0
- flextool-4.0.0/flextool/cli/_timing.py +147 -0
- flextool-4.0.0/flextool/cli/cmd_execute_flextool_workflow.py +187 -0
- flextool-4.0.0/flextool/cli/cmd_export_to_tabular.py +56 -0
- flextool-4.0.0/flextool/cli/cmd_import_sensitivities.py +75 -0
- flextool-4.0.0/flextool/cli/cmd_migrate_database.py +13 -0
- flextool-4.0.0/flextool/cli/cmd_open_results_db.py +269 -0
- flextool-4.0.0/flextool/cli/cmd_read_matpower.py +66 -0
- flextool-4.0.0/flextool/cli/cmd_read_old_flextool.py +63 -0
- flextool-4.0.0/flextool/cli/cmd_read_self_describing_tabular_input.py +50 -0
- flextool-4.0.0/flextool/cli/cmd_read_tabular_input.py +81 -0
- flextool-4.0.0/flextool/cli/cmd_run_flextool.py +1095 -0
- flextool-4.0.0/flextool/cli/cmd_scenario_results.py +284 -0
- flextool-4.0.0/flextool/cli/cmd_solve_mps.py +169 -0
- flextool-4.0.0/flextool/cli/cmd_update_flextool.py +17 -0
- flextool-4.0.0/flextool/cli/cmd_write_outputs.py +125 -0
- flextool-4.0.0/flextool/common_utils/__init__.py +1 -0
- flextool-4.0.0/flextool/common_utils/plot_mem_shape.py +77 -0
- flextool-4.0.0/flextool/common_utils/precision.py +451 -0
- flextool-4.0.0/flextool/decomposition/__init__.py +0 -0
- flextool-4.0.0/flextool/decomposition/region_decomposition.py +128 -0
- flextool-4.0.0/flextool/decomposition/region_filter.py +1261 -0
- flextool-4.0.0/flextool/engine_polars/__init__.py +110 -0
- flextool-4.0.0/flextool/engine_polars/_axis_enums.py +742 -0
- flextool-4.0.0/flextool/engine_polars/_benders.py +3462 -0
- flextool-4.0.0/flextool/engine_polars/_block_layout.py +1479 -0
- flextool-4.0.0/flextool/engine_polars/_blocks.py +1515 -0
- flextool-4.0.0/flextool/engine_polars/_commodity_ladder.py +660 -0
- flextool-4.0.0/flextool/engine_polars/_cumulative_invest.py +1165 -0
- flextool-4.0.0/flextool/engine_polars/_db_loader.py +153 -0
- flextool-4.0.0/flextool/engine_polars/_db_reader.py +127 -0
- flextool-4.0.0/flextool/engine_polars/_dc_power_flow.py +445 -0
- flextool-4.0.0/flextool/engine_polars/_delay.py +442 -0
- flextool-4.0.0/flextool/engine_polars/_derived_arithmetic.py +432 -0
- flextool-4.0.0/flextool/engine_polars/_derived_block.py +990 -0
- flextool-4.0.0/flextool/engine_polars/_derived_branch.py +769 -0
- flextool-4.0.0/flextool/engine_polars/_derived_existing.py +1353 -0
- flextool-4.0.0/flextool/engine_polars/_derived_npv.py +1297 -0
- flextool-4.0.0/flextool/engine_polars/_derived_params.py +9850 -0
- flextool-4.0.0/flextool/engine_polars/_derived_profile.py +881 -0
- flextool-4.0.0/flextool/engine_polars/_derived_walks.py +276 -0
- flextool-4.0.0/flextool/engine_polars/_determinism.py +70 -0
- flextool-4.0.0/flextool/engine_polars/_direct_params.py +2186 -0
- flextool-4.0.0/flextool/engine_polars/_dump_csvs.py +1009 -0
- flextool-4.0.0/flextool/engine_polars/_emit_arc_unions.py +1631 -0
- flextool-4.0.0/flextool/engine_polars/_emit_calc_params.py +729 -0
- flextool-4.0.0/flextool/engine_polars/_emit_chain_params.py +709 -0
- flextool-4.0.0/flextool/engine_polars/_emit_co2_accumulators.py +400 -0
- flextool-4.0.0/flextool/engine_polars/_emit_dispatchers.py +690 -0
- flextool-4.0.0/flextool/engine_polars/_emit_energy_margin.py +125 -0
- flextool-4.0.0/flextool/engine_polars/_emit_energy_margin_adder.py +290 -0
- flextool-4.0.0/flextool/engine_polars/_emit_entity_annual.py +428 -0
- flextool-4.0.0/flextool/engine_polars/_emit_inflow_scaling.py +1420 -0
- flextool-4.0.0/flextool/engine_polars/_emit_leaf_sets.py +550 -0
- flextool-4.0.0/flextool/engine_polars/_emit_lp_scaling.py +665 -0
- flextool-4.0.0/flextool/engine_polars/_emit_mid_sets.py +859 -0
- flextool-4.0.0/flextool/engine_polars/_emit_pdt_params.py +759 -0
- flextool-4.0.0/flextool/engine_polars/_emit_per_solve.py +774 -0
- flextool-4.0.0/flextool/engine_polars/_emit_period_calc.py +504 -0
- flextool-4.0.0/flextool/engine_polars/_emit_period_params.py +2398 -0
- flextool-4.0.0/flextool/engine_polars/_emit_provider_io.py +141 -0
- flextool-4.0.0/flextool/engine_polars/_emit_reserve.py +574 -0
- flextool-4.0.0/flextool/engine_polars/_emit_solve_time.py +311 -0
- flextool-4.0.0/flextool/engine_polars/_emit_solve_writers.py +1249 -0
- flextool-4.0.0/flextool/engine_polars/_flex_data_accumulator.py +388 -0
- flextool-4.0.0/flextool/engine_polars/_flex_data_provider.py +478 -0
- flextool-4.0.0/flextool/engine_polars/_group_slack.py +1253 -0
- flextool-4.0.0/flextool/engine_polars/_inmemory_reader.py +140 -0
- flextool-4.0.0/flextool/engine_polars/_input_source.py +336 -0
- flextool-4.0.0/flextool/engine_polars/_invest_seeds.py +191 -0
- flextool-4.0.0/flextool/engine_polars/_native_input_writer.py +100 -0
- flextool-4.0.0/flextool/engine_polars/_native_run_model.py +1348 -0
- flextool-4.0.0/flextool/engine_polars/_orchestration.py +4314 -0
- flextool-4.0.0/flextool/engine_polars/_output_writer.py +439 -0
- flextool-4.0.0/flextool/engine_polars/_param_shapes.py +1595 -0
- flextool-4.0.0/flextool/engine_polars/_parquet_bundle.py +723 -0
- flextool-4.0.0/flextool/engine_polars/_pdt_join.py +167 -0
- flextool-4.0.0/flextool/engine_polars/_pdt_lookup.py +547 -0
- flextool-4.0.0/flextool/engine_polars/_per_solve_sets.py +335 -0
- flextool-4.0.0/flextool/engine_polars/_projection_params.py +2056 -0
- flextool-4.0.0/flextool/engine_polars/_provider_keys.py +173 -0
- flextool-4.0.0/flextool/engine_polars/_provider_translators.py +225 -0
- flextool-4.0.0/flextool/engine_polars/_recursive_solve.py +703 -0
- flextool-4.0.0/flextool/engine_polars/_region_filter.py +2508 -0
- flextool-4.0.0/flextool/engine_polars/_reserve.py +649 -0
- flextool-4.0.0/flextool/engine_polars/_solve_acceptance.py +331 -0
- flextool-4.0.0/flextool/engine_polars/_solve_config.py +1001 -0
- flextool-4.0.0/flextool/engine_polars/_solve_context.py +885 -0
- flextool-4.0.0/flextool/engine_polars/_solve_handoff.py +164 -0
- flextool-4.0.0/flextool/engine_polars/_solve_state.py +232 -0
- flextool-4.0.0/flextool/engine_polars/_solver_base.py +36 -0
- flextool-4.0.0/flextool/engine_polars/_solver_dispatch.py +511 -0
- flextool-4.0.0/flextool/engine_polars/_spinedb_reader.py +1165 -0
- flextool-4.0.0/flextool/engine_polars/_stochastic.py +593 -0
- flextool-4.0.0/flextool/engine_polars/_subprocess_solve.py +1838 -0
- flextool-4.0.0/flextool/engine_polars/_timeline.py +1416 -0
- flextool-4.0.0/flextool/engine_polars/_vectorize.py +438 -0
- flextool-4.0.0/flextool/engine_polars/_warm.py +858 -0
- flextool-4.0.0/flextool/engine_polars/autoscale/__init__.py +107 -0
- flextool-4.0.0/flextool/engine_polars/autoscale/_config.py +218 -0
- flextool-4.0.0/flextool/engine_polars/autoscale/_layer2.py +1253 -0
- flextool-4.0.0/flextool/engine_polars/autoscale/_layer2_types.py +584 -0
- flextool-4.0.0/flextool/engine_polars/autoscale/_quantity_types.py +621 -0
- flextool-4.0.0/flextool/engine_polars/autoscale/_report.py +336 -0
- flextool-4.0.0/flextool/engine_polars/chain.py +259 -0
- flextool-4.0.0/flextool/engine_polars/input.py +6638 -0
- flextool-4.0.0/flextool/engine_polars/model.py +4754 -0
- flextool-4.0.0/flextool/env_check.py +388 -0
- flextool-4.0.0/flextool/export_to_tabular/__init__.py +5 -0
- flextool-4.0.0/flextool/export_to_tabular/db_reader.py +224 -0
- flextool-4.0.0/flextool/export_to_tabular/excel_writer.py +3559 -0
- flextool-4.0.0/flextool/export_to_tabular/export_settings.yaml +377 -0
- flextool-4.0.0/flextool/export_to_tabular/export_to_excel.py +227 -0
- flextool-4.0.0/flextool/export_to_tabular/formatting.py +543 -0
- flextool-4.0.0/flextool/export_to_tabular/sheet_config.py +876 -0
- flextool-4.0.0/flextool/gui/__init__.py +0 -0
- flextool-4.0.0/flextool/gui/__main__.py +118 -0
- flextool-4.0.0/flextool/gui/calibrate_commands.py +184 -0
- flextool-4.0.0/flextool/gui/calibrate_jobs.py +424 -0
- flextool-4.0.0/flextool/gui/check_tree.py +142 -0
- flextool-4.0.0/flextool/gui/cli_format.py +83 -0
- flextool-4.0.0/flextool/gui/config_parser.py +68 -0
- flextool-4.0.0/flextool/gui/data_models.py +362 -0
- flextool-4.0.0/flextool/gui/db_editor_integration.py +202 -0
- flextool-4.0.0/flextool/gui/db_version_check.py +269 -0
- flextool-4.0.0/flextool/gui/dialogs/__init__.py +0 -0
- flextool-4.0.0/flextool/gui/dialogs/add_dialog.py +1098 -0
- flextool-4.0.0/flextool/gui/dialogs/calibrate_dialog.py +1259 -0
- flextool-4.0.0/flextool/gui/dialogs/file_picker.py +473 -0
- flextool-4.0.0/flextool/gui/dialogs/group_picker.py +299 -0
- flextool-4.0.0/flextool/gui/dialogs/migration_consent_dialog.py +106 -0
- flextool-4.0.0/flextool/gui/dialogs/migration_progress_dialog.py +237 -0
- flextool-4.0.0/flextool/gui/dialogs/plot_dialog.py +459 -0
- flextool-4.0.0/flextool/gui/dialogs/plot_settings_picker.py +2184 -0
- flextool-4.0.0/flextool/gui/dialogs/project_dialog.py +426 -0
- flextool-4.0.0/flextool/gui/dialogs/update_dialog.py +212 -0
- flextool-4.0.0/flextool/gui/downsampling.py +88 -0
- flextool-4.0.0/flextool/gui/error_handling.py +50 -0
- flextool-4.0.0/flextool/gui/execution_manager.py +1715 -0
- flextool-4.0.0/flextool/gui/execution_window.py +1377 -0
- flextool-4.0.0/flextool/gui/hover_tooltip.py +111 -0
- flextool-4.0.0/flextool/gui/input_sources.py +730 -0
- flextool-4.0.0/flextool/gui/main_window.py +6181 -0
- flextool-4.0.0/flextool/gui/network_graph.py +215 -0
- flextool-4.0.0/flextool/gui/output_actions.py +393 -0
- flextool-4.0.0/flextool/gui/output_log_window.py +159 -0
- flextool-4.0.0/flextool/gui/platform_utils.py +421 -0
- flextool-4.0.0/flextool/gui/plot_cache.py +88 -0
- flextool-4.0.0/flextool/gui/plot_canvas.py +543 -0
- flextool-4.0.0/flextool/gui/plot_config_reader.py +272 -0
- flextool-4.0.0/flextool/gui/project_utils.py +100 -0
- flextool-4.0.0/flextool/gui/result_viewer.py +4394 -0
- flextool-4.0.0/flextool/gui/scenario_key.py +162 -0
- flextool-4.0.0/flextool/gui/scenario_lists.py +516 -0
- flextool-4.0.0/flextool/gui/settings_io.py +360 -0
- flextool-4.0.0/flextool/gui/solve_reader.py +103 -0
- flextool-4.0.0/flextool/gui/tree_reorder.py +88 -0
- flextool-4.0.0/flextool/gui/ui_metrics.py +420 -0
- flextool-4.0.0/flextool/input_derivation/__init__.py +281 -0
- flextool-4.0.0/flextool/input_derivation/_commodity_ladder.py +375 -0
- flextool-4.0.0/flextool/input_derivation/_commodity_ladder_sets.py +70 -0
- flextool-4.0.0/flextool/input_derivation/_dc_power_flow.py +377 -0
- flextool-4.0.0/flextool/input_derivation/_method_constants.py +77 -0
- flextool-4.0.0/flextool/input_derivation/_process_method.py +258 -0
- flextool-4.0.0/flextool/input_derivation/_specs.py +1026 -0
- flextool-4.0.0/flextool/input_derivation/_validators.py +321 -0
- flextool-4.0.0/flextool/lean_parquet.py +159 -0
- flextool-4.0.0/flextool/model_builder/__init__.py +5 -0
- flextool-4.0.0/flextool/model_builder/build_model.py +589 -0
- flextool-4.0.0/flextool/model_builder/encoding.py +67 -0
- flextool-4.0.0/flextool/model_builder/names.py +34 -0
- flextool-4.0.0/flextool/model_builder/profiles.py +129 -0
- flextool-4.0.0/flextool/plot_outputs/__init__.py +14 -0
- flextool-4.0.0/flextool/plot_outputs/axis_helpers.py +355 -0
- flextool-4.0.0/flextool/plot_outputs/color_template.py +888 -0
- flextool-4.0.0/flextool/plot_outputs/config.py +171 -0
- flextool-4.0.0/flextool/plot_outputs/format_helpers.py +345 -0
- flextool-4.0.0/flextool/plot_outputs/legend_helpers.py +143 -0
- flextool-4.0.0/flextool/plot_outputs/orchestrator.py +1141 -0
- flextool-4.0.0/flextool/plot_outputs/perf.py +37 -0
- flextool-4.0.0/flextool/plot_outputs/plan.py +1787 -0
- flextool-4.0.0/flextool/plot_outputs/plot_bars.py +1510 -0
- flextool-4.0.0/flextool/plot_outputs/plot_bars_detail.py +753 -0
- flextool-4.0.0/flextool/plot_outputs/plot_lines.py +951 -0
- flextool-4.0.0/flextool/plot_outputs/shared_manifest.py +564 -0
- flextool-4.0.0/flextool/plot_outputs/subplot_helpers.py +137 -0
- flextool-4.0.0/flextool/process_inputs/__init__.py +188 -0
- flextool-4.0.0/flextool/process_inputs/import_old_excel_input.json +4159 -0
- flextool-4.0.0/flextool/process_inputs/read_matpower.py +451 -0
- flextool-4.0.0/flextool/process_inputs/read_old_flextool.py +1288 -0
- flextool-4.0.0/flextool/process_inputs/read_self_describing_excel.py +1423 -0
- flextool-4.0.0/flextool/process_inputs/read_tabular_with_specification.py +1114 -0
- flextool-4.0.0/flextool/process_inputs/write_old_flextool_to_db.py +3077 -0
- flextool-4.0.0/flextool/process_inputs/write_self_describing_to_db.py +977 -0
- flextool-4.0.0/flextool/process_inputs/write_to_input_db.py +269 -0
- flextool-4.0.0/flextool/process_outputs/__init__.py +7 -0
- flextool-4.0.0/flextool/process_outputs/_annualize.py +55 -0
- flextool-4.0.0/flextool/process_outputs/_inmemory_helpers.py +292 -0
- flextool-4.0.0/flextool/process_outputs/_output_meta.py +672 -0
- flextool-4.0.0/flextool/process_outputs/calc_capacity_flows.py +107 -0
- flextool-4.0.0/flextool/process_outputs/calc_connections.py +136 -0
- flextool-4.0.0/flextool/process_outputs/calc_costs.py +260 -0
- flextool-4.0.0/flextool/process_outputs/calc_group_flows.py +192 -0
- flextool-4.0.0/flextool/process_outputs/calc_slacks.py +103 -0
- flextool-4.0.0/flextool/process_outputs/calc_storage_vre.py +160 -0
- flextool-4.0.0/flextool/process_outputs/drop_levels.py +208 -0
- flextool-4.0.0/flextool/process_outputs/handoff_writers.py +1315 -0
- flextool-4.0.0/flextool/process_outputs/out_ancillary.py +544 -0
- flextool-4.0.0/flextool/process_outputs/out_capacity.py +179 -0
- flextool-4.0.0/flextool/process_outputs/out_costs.py +334 -0
- flextool-4.0.0/flextool/process_outputs/out_flowgroup.py +189 -0
- flextool-4.0.0/flextool/process_outputs/out_flows.py +301 -0
- flextool-4.0.0/flextool/process_outputs/out_group.py +475 -0
- flextool-4.0.0/flextool/process_outputs/out_node.py +190 -0
- flextool-4.0.0/flextool/process_outputs/persist_realized_slice.py +601 -0
- flextool-4.0.0/flextool/process_outputs/process_results.py +24 -0
- flextool-4.0.0/flextool/process_outputs/read_highs_solution.py +2256 -0
- flextool-4.0.0/flextool/process_outputs/read_parameters.py +1799 -0
- flextool-4.0.0/flextool/process_outputs/read_sets.py +1095 -0
- flextool-4.0.0/flextool/process_outputs/read_variables.py +553 -0
- flextool-4.0.0/flextool/process_outputs/solve_order.py +81 -0
- flextool-4.0.0/flextool/process_outputs/spinedb_replay.py +412 -0
- flextool-4.0.0/flextool/process_outputs/union_realized_slice.py +224 -0
- flextool-4.0.0/flextool/process_outputs/write_outputs.py +1286 -0
- flextool-4.0.0/flextool/process_outputs/write_spinedb.py +1267 -0
- flextool-4.0.0/flextool/representative_periods/__init__.py +5 -0
- flextool-4.0.0/flextool/representative_periods/clustering.py +165 -0
- flextool-4.0.0/flextool/representative_periods/force_include.py +563 -0
- flextool-4.0.0/flextool/representative_periods/netload.py +365 -0
- flextool-4.0.0/flextool/representative_periods/netload_inputs.py +345 -0
- flextool-4.0.0/flextool/representative_periods/netload_iterate.py +722 -0
- flextool-4.0.0/flextool/representative_periods/preprocess.py +948 -0
- flextool-4.0.0/flextool/representative_periods/scenario_stack.py +195 -0
- flextool-4.0.0/flextool/representative_periods/weights.py +124 -0
- flextool-4.0.0/flextool/scenario_comparison/__init__.py +13 -0
- flextool-4.0.0/flextool/scenario_comparison/config_builder.py +158 -0
- flextool-4.0.0/flextool/scenario_comparison/constants.py +20 -0
- flextool-4.0.0/flextool/scenario_comparison/data_models.py +222 -0
- flextool-4.0.0/flextool/scenario_comparison/db_reader.py +399 -0
- flextool-4.0.0/flextool/scenario_comparison/dispatch_data.py +1002 -0
- flextool-4.0.0/flextool/scenario_comparison/dispatch_mappings.py +205 -0
- flextool-4.0.0/flextool/scenario_comparison/dispatch_plots.py +691 -0
- flextool-4.0.0/flextool/scenario_comparison/input_entity_colors.py +319 -0
- flextool-4.0.0/flextool/scenario_comparison/orchestrator.py +453 -0
- flextool-4.0.0/flextool/scenario_comparison/plan_union.py +244 -0
- flextool-4.0.0/flextool/scenario_comparison/plot_settings_seed.py +205 -0
- flextool-4.0.0/flextool/schemas/AXIS_CONTRACT.md +71 -0
- flextool-4.0.0/flextool/schemas/canonical_databases/howto_aggregate_output.json +6225 -0
- flextool-4.0.0/flextool/schemas/canonical_databases/howto_connections.json +5606 -0
- flextool-4.0.0/flextool/schemas/canonical_databases/howto_demand.json +5518 -0
- flextool-4.0.0/flextool/schemas/canonical_databases/howto_hydro_reservoir.json +6239 -0
- flextool-4.0.0/flextool/schemas/canonical_databases/howto_hydro_reservoir_with_pump.json +5933 -0
- flextool-4.0.0/flextool/schemas/canonical_databases/howto_non_sync_and_curtailment.json +5794 -0
- flextool-4.0.0/flextool/schemas/canonical_databases/howto_ramp_and_start_up.json +5707 -0
- flextool-4.0.0/flextool/schemas/canonical_databases/howto_stochastics.json +6032 -0
- flextool-4.0.0/flextool/schemas/canonical_databases/templates_examples.json +13532 -0
- flextool-4.0.0/flextool/schemas/canonical_databases/templates_time_settings_only.json +5340 -0
- flextool-4.0.0/flextool/schemas/comparison_settings_template.json +197 -0
- flextool-4.0.0/flextool/schemas/default_plot_settings.yaml +260 -0
- flextool-4.0.0/flextool/schemas/default_plots.yaml +2293 -0
- flextool-4.0.0/flextool/schemas/flextool_axis_contract.json +303 -0
- flextool-4.0.0/flextool/schemas/flextool_axis_contract.schema.json +247 -0
- flextool-4.0.0/flextool/schemas/old_flextool_import_template.json +4443 -0
- flextool-4.0.0/flextool/schemas/output_info_template.json +48 -0
- flextool-4.0.0/flextool/schemas/output_settings_template.json +256 -0
- flextool-4.0.0/flextool/schemas/pre_v26/flextool_template_constant_default.json +2105 -0
- flextool-4.0.0/flextool/schemas/pre_v26/flextool_template_default_optional_output.json +2152 -0
- flextool-4.0.0/flextool/schemas/pre_v26/flextool_template_default_value.json +2094 -0
- flextool-4.0.0/flextool/schemas/pre_v26/flextool_template_drop_down.json +2080 -0
- flextool-4.0.0/flextool/schemas/pre_v26/flextool_template_lifetime_method.json +1990 -0
- flextool-4.0.0/flextool/schemas/pre_v26/flextool_template_optional_outputs.json +2094 -0
- flextool-4.0.0/flextool/schemas/pre_v26/flextool_template_output_node_flows.json +2105 -0
- flextool-4.0.0/flextool/schemas/pre_v26/flextool_template_results_master.json +493 -0
- flextool-4.0.0/flextool/schemas/pre_v26/flextool_template_rolling_start_remove.json +2087 -0
- flextool-4.0.0/flextool/schemas/pre_v26/flextool_template_rolling_window.json +2059 -0
- flextool-4.0.0/flextool/schemas/pre_v26/flextool_template_storage_binding_defaults.json +46 -0
- flextool-4.0.0/flextool/schemas/pre_v26/flextool_template_v2.json +1990 -0
- flextool-4.0.0/flextool/schemas/pre_v26/flextool_template_v25.json +3864 -0
- flextool-4.0.0/flextool/schemas/spinedb_results_schema.json +581 -0
- flextool-4.0.0/flextool/schemas/spinedb_schema.json +4636 -0
- flextool-4.0.0/flextool/solver_config/copt.opt.template +18 -0
- flextool-4.0.0/flextool/solver_config/cplex.opt.template +25 -0
- flextool-4.0.0/flextool/solver_config/gurobi.opt.template +18 -0
- flextool-4.0.0/flextool/solver_config/highs.opt.template +18 -0
- flextool-4.0.0/flextool/solver_config/xpress.opt.template +26 -0
- flextool-4.0.0/flextool/spinedb_backend/__init__.py +26 -0
- flextool-4.0.0/flextool/spinedb_backend/_axis_enums.py +1119 -0
- flextool-4.0.0/flextool/spinedb_backend/_backend.py +1139 -0
- flextool-4.0.0/flextool/update_flextool/__init__.py +12 -0
- flextool-4.0.0/flextool/update_flextool/canonical_databases.py +251 -0
- flextool-4.0.0/flextool/update_flextool/db_migration.py +7108 -0
- flextool-4.0.0/flextool/update_flextool/ensure_settings_db.py +138 -0
- flextool-4.0.0/flextool/update_flextool/export_database.py +103 -0
- flextool-4.0.0/flextool/update_flextool/extend_tests_fixture.py +772 -0
- flextool-4.0.0/flextool/update_flextool/generate_canonical.py +274 -0
- flextool-4.0.0/flextool/update_flextool/initialize_database.py +42 -0
- flextool-4.0.0/flextool/update_flextool/install_info.py +225 -0
- flextool-4.0.0/flextool/update_flextool/self_update.py +464 -0
- flextool-4.0.0/flextool/update_flextool/sync_master_json_template.py +125 -0
- flextool-4.0.0/flextool/update_flextool/test_fixtures.py +187 -0
- flextool-4.0.0/flextool.egg-info/PKG-INFO +217 -0
- flextool-4.0.0/flextool.egg-info/SOURCES.txt +399 -0
- flextool-4.0.0/flextool.egg-info/dependency_links.txt +1 -0
- flextool-4.0.0/flextool.egg-info/entry_points.txt +17 -0
- flextool-4.0.0/flextool.egg-info/requires.txt +32 -0
- flextool-4.0.0/flextool.egg-info/top_level.txt +1 -0
- flextool-4.0.0/pyproject.toml +225 -0
- flextool-4.0.0/setup.cfg +4 -0
- flextool-4.0.0/tests/test_bar_layout.py +367 -0
- flextool-4.0.0/tests/test_bar_sub_pixel_labels.py +128 -0
- flextool-4.0.0/tests/test_blocks.py +619 -0
- flextool-4.0.0/tests/test_branch_weights.py +260 -0
- flextool-4.0.0/tests/test_color_template.py +1458 -0
- flextool-4.0.0/tests/test_commodity_ladder_rolling.py +814 -0
- flextool-4.0.0/tests/test_comparison_excel.py +139 -0
- flextool-4.0.0/tests/test_comparison_project_root.py +195 -0
- flextool-4.0.0/tests/test_complete_period_share_reduction.py +90 -0
- flextool-4.0.0/tests/test_connection_node_warnings.py +97 -0
- flextool-4.0.0/tests/test_console_run_tool.py +107 -0
- flextool-4.0.0/tests/test_cost_aggregation_semantics.py +1037 -0
- flextool-4.0.0/tests/test_cost_breakdown_by_entity.py +524 -0
- flextool-4.0.0/tests/test_csv_dump_roundtrip.py +131 -0
- flextool-4.0.0/tests/test_dc_power_flow.py +1145 -0
- flextool-4.0.0/tests/test_dispatch_consumer_and_connection_signs.py +290 -0
- flextool-4.0.0/tests/test_dispatch_node_debug_and_tree.py +184 -0
- flextool-4.0.0/tests/test_dispatch_order_specials.py +455 -0
- flextool-4.0.0/tests/test_dispatch_scenario_tag.py +154 -0
- flextool-4.0.0/tests/test_ensure_settings_db.py +118 -0
- flextool-4.0.0/tests/test_entity_unitsize_invariant.py +97 -0
- flextool-4.0.0/tests/test_entity_universe_carrier.py +75 -0
- flextool-4.0.0/tests/test_env_check.py +156 -0
- flextool-4.0.0/tests/test_export_to_tabular.py +1492 -0
- flextool-4.0.0/tests/test_extend_tests_fixture.py +232 -0
- flextool-4.0.0/tests/test_flowgroup_indicators.py +325 -0
- flextool-4.0.0/tests/test_force_include.py +583 -0
- flextool-4.0.0/tests/test_group_output_warnings.py +272 -0
- flextool-4.0.0/tests/test_handoff_writers.py +490 -0
- flextool-4.0.0/tests/test_input_entity_colors.py +389 -0
- flextool-4.0.0/tests/test_lh2_three_region.py +379 -0
- flextool-4.0.0/tests/test_min_load_rolling.py +131 -0
- flextool-4.0.0/tests/test_non_anticipativity.py +282 -0
- flextool-4.0.0/tests/test_old_flextool_importer_schema_drift.py +92 -0
- flextool-4.0.0/tests/test_open_results_db.py +278 -0
- flextool-4.0.0/tests/test_output_column_metadata.py +93 -0
- flextool-4.0.0/tests/test_output_metadata_renderers.py +252 -0
- flextool-4.0.0/tests/test_parameter_group_coverage.py +41 -0
- flextool-4.0.0/tests/test_plan_union.py +254 -0
- flextool-4.0.0/tests/test_plot_draw_order.py +154 -0
- flextool-4.0.0/tests/test_plot_pipeline.py +1326 -0
- flextool-4.0.0/tests/test_plot_plan_chunk_reconstruction.py +263 -0
- flextool-4.0.0/tests/test_plot_plan_time_labels_roundtrip.py +197 -0
- flextool-4.0.0/tests/test_plot_settings_seed.py +552 -0
- flextool-4.0.0/tests/test_precision.py +226 -0
- flextool-4.0.0/tests/test_read_highs_solution.py +485 -0
- flextool-4.0.0/tests/test_regional_filter.py +443 -0
- flextool-4.0.0/tests/test_representative_periods.py +435 -0
- flextool-4.0.0/tests/test_rp_alternative_name.py +211 -0
- flextool-4.0.0/tests/test_rp_force_include_wiring.py +296 -0
- flextool-4.0.0/tests/test_rp_solves_filter.py +164 -0
- flextool-4.0.0/tests/test_scenario_colors.py +126 -0
- flextool-4.0.0/tests/test_scenario_stack.py +172 -0
- flextool-4.0.0/tests/test_scenarios.py +371 -0
- flextool-4.0.0/tests/test_self_describing_reader.py +478 -0
- flextool-4.0.0/tests/test_shared_axis_manifest.py +1171 -0
- flextool-4.0.0/tests/test_simple_bar_entity_color.py +357 -0
- flextool-4.0.0/tests/test_solve_config.py +141 -0
- flextool-4.0.0/tests/test_solve_reader.py +79 -0
- flextool-4.0.0/tests/test_synthesize_invest_dual.py +333 -0
- flextool-4.0.0/tests/test_timings_csv.py +145 -0
- flextool-4.0.0/tests/test_unidirectional_connection.py +106 -0
- flextool-4.0.0/tests/test_unit_online_dt_columns.py +170 -0
- flextool-4.0.0/tests/test_v52_migration.py +40 -0
- flextool-4.0.0/tests/test_v63_migration.py +84 -0
- flextool-4.0.0/tests/test_v64_migration.py +102 -0
- flextool-4.0.0/tests/test_v65_migration.py +266 -0
- flextool-4.0.0/tests/test_v66_migration.py +204 -0
- flextool-4.0.0/tests/test_v67_migration.py +76 -0
- flextool-4.0.0/tests/test_v68_migration.py +91 -0
- flextool-4.0.0/tests/test_v69_migration.py +88 -0
- flextool-4.0.0/tests/test_workdir_empty_default.py +202 -0
- flextool-4.0.0/tests/test_xlsx_workflow.py +241 -0
- flextool-4.0.0/tests/test_years_represented.py +543 -0
|
@@ -0,0 +1,19 @@
|
|
|
1
|
+
© International Renewable Energy Agency 2018-2022
|
|
2
|
+
|
|
3
|
+
The FlexTool is free software: you can redistribute it and/or modify it under the terms of the GNU Lesser General Public License
|
|
4
|
+
as published by the Free Software Foundation, either version 3 of the License, or (at your option) any later version.
|
|
5
|
+
|
|
6
|
+
The FlexTool is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY;
|
|
7
|
+
without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more details.
|
|
8
|
+
|
|
9
|
+
You should have received a copy of the GNU Lesser General Public License along with the FlexTool.
|
|
10
|
+
If not, see <https://www.gnu.org/licenses/>.
|
|
11
|
+
|
|
12
|
+
Author: Juha Kiviluoma (2017-2022), VTT Technical Research Centre of Finland
|
|
13
|
+
|
|
14
|
+
|
|
15
|
+
|
|
16
|
+
|
|
17
|
+
-----------------------------------------------
|
|
18
|
+
IRENA FlexTool uses the HiGHS solver, which has its own license.
|
|
19
|
+
HiGHS is licensed with MIT license. Please see https://github.com/ERGO-Code/HiGHS for more information.
|
flextool-4.0.0/PKG-INFO
ADDED
|
@@ -0,0 +1,217 @@
|
|
|
1
|
+
Metadata-Version: 2.4
|
|
2
|
+
Name: flextool
|
|
3
|
+
Version: 4.0.0
|
|
4
|
+
Summary: IRENA FlexTool is an energy and power systems model for understanding the role of variable power generation in future energy systems.
|
|
5
|
+
Author: IRENA FlexTool contributors
|
|
6
|
+
License: © International Renewable Energy Agency 2018-2022
|
|
7
|
+
|
|
8
|
+
The FlexTool is free software: you can redistribute it and/or modify it under the terms of the GNU Lesser General Public License
|
|
9
|
+
as published by the Free Software Foundation, either version 3 of the License, or (at your option) any later version.
|
|
10
|
+
|
|
11
|
+
The FlexTool is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY;
|
|
12
|
+
without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more details.
|
|
13
|
+
|
|
14
|
+
You should have received a copy of the GNU Lesser General Public License along with the FlexTool.
|
|
15
|
+
If not, see <https://www.gnu.org/licenses/>.
|
|
16
|
+
|
|
17
|
+
Author: Juha Kiviluoma (2017-2022), VTT Technical Research Centre of Finland
|
|
18
|
+
|
|
19
|
+
|
|
20
|
+
|
|
21
|
+
|
|
22
|
+
-----------------------------------------------
|
|
23
|
+
IRENA FlexTool uses the HiGHS solver, which has its own license.
|
|
24
|
+
HiGHS is licensed with MIT license. Please see https://github.com/ERGO-Code/HiGHS for more information.
|
|
25
|
+
Project-URL: Documentation, https://irena-flextool.github.io/flextool/
|
|
26
|
+
Project-URL: Repository, https://github.com/irena-flextool/flextool
|
|
27
|
+
Project-URL: Issues, https://github.com/irena-flextool/flextool/issues
|
|
28
|
+
Keywords: energy-systems,optimization,linear-programming,mixed-integer-programming,power-systems,investment-planning,highs,spine
|
|
29
|
+
Classifier: Development Status :: 5 - Production/Stable
|
|
30
|
+
Classifier: Intended Audience :: Science/Research
|
|
31
|
+
Classifier: License :: OSI Approved :: GNU Lesser General Public License v3 (LGPLv3)
|
|
32
|
+
Classifier: Operating System :: OS Independent
|
|
33
|
+
Classifier: Programming Language :: Python :: 3
|
|
34
|
+
Classifier: Programming Language :: Python :: 3.11
|
|
35
|
+
Classifier: Programming Language :: Python :: 3.12
|
|
36
|
+
Classifier: Programming Language :: Python :: 3.13
|
|
37
|
+
Classifier: Topic :: Scientific/Engineering
|
|
38
|
+
Requires-Python: >=3.11
|
|
39
|
+
Description-Content-Type: text/markdown
|
|
40
|
+
License-File: LICENSE.txt
|
|
41
|
+
Requires-Dist: polar-high>=3.7.0
|
|
42
|
+
Requires-Dist: highspy<=1.14.0
|
|
43
|
+
Requires-Dist: polars>=1.40
|
|
44
|
+
Requires-Dist: pandas
|
|
45
|
+
Requires-Dist: spinedb-api
|
|
46
|
+
Requires-Dist: openpyxl
|
|
47
|
+
Requires-Dist: odfpy
|
|
48
|
+
Requires-Dist: python-calamine
|
|
49
|
+
Requires-Dist: xlsxwriter
|
|
50
|
+
Requires-Dist: pyyaml
|
|
51
|
+
Requires-Dist: matplotlib
|
|
52
|
+
Requires-Dist: psutil
|
|
53
|
+
Requires-Dist: sv-ttk
|
|
54
|
+
Requires-Dist: screeninfo
|
|
55
|
+
Requires-Dist: pywin32; sys_platform == "win32"
|
|
56
|
+
Provides-Extra: toolbox
|
|
57
|
+
Requires-Dist: spinetoolbox; extra == "toolbox"
|
|
58
|
+
Provides-Extra: viewer
|
|
59
|
+
Requires-Dist: tsdownsample>=0.1.3; extra == "viewer"
|
|
60
|
+
Requires-Dist: networkx>=3.0; extra == "viewer"
|
|
61
|
+
Provides-Extra: engine-polars
|
|
62
|
+
Provides-Extra: dev
|
|
63
|
+
Requires-Dist: pytest>=8.0; extra == "dev"
|
|
64
|
+
Requires-Dist: pytest-timeout>=2.3; extra == "dev"
|
|
65
|
+
Requires-Dist: pytest-xdist>=3.0; extra == "dev"
|
|
66
|
+
Requires-Dist: ruff>=0.5; extra == "dev"
|
|
67
|
+
Dynamic: license-file
|
|
68
|
+
|
|
69
|
+
[](https://pypi.org/project/flextool/)
|
|
70
|
+
[](https://irena-flextool.github.io/flextool/)
|
|
71
|
+
[](https://www.python.org/downloads/release/python-3120/)
|
|
72
|
+
|
|
73
|
+

|
|
74
|
+
|
|
75
|
+
IRENA FlexTool is an energy and power systems model for understanding the role of variable power generation in future energy systems. It performs capacity expansion planning as well as operational planning.
|
|
76
|
+
|
|
77
|
+
> [!NOTE]
|
|
78
|
+
> The previous `master` branch is deprecated and no longer updated — `main` is
|
|
79
|
+
> now FlexTool. If you still run FlexTool from `master`, migrate with a fresh
|
|
80
|
+
> parallel install (separate directory and venv); see
|
|
81
|
+
> [Installation](#installation) so your existing setup is left untouched.
|
|
82
|
+
|
|
83
|
+
## What's new
|
|
84
|
+
|
|
85
|
+
- **A lot faster.** The model build and pre-processing now run as pure Python
|
|
86
|
+
instead of the previous GLPSOL-based text pre-processing and AMPL-style model
|
|
87
|
+
translation. There is no LP file written to disk and re-read between build and
|
|
88
|
+
solve.
|
|
89
|
+
- **Automatic problem scaling.** The `polar-high` matrix layer automatically
|
|
90
|
+
scales the optimisation problem before it reaches the solver. Better numerical
|
|
91
|
+
conditioning often speeds up the HiGHS solve considerably — sometimes
|
|
92
|
+
dramatically — so total run time usually improves well beyond the faster build
|
|
93
|
+
alone. The solver is still HiGHS; the gain comes from handing it a
|
|
94
|
+
better-conditioned problem.
|
|
95
|
+
- **A new, easy-to-use interface.** The **FlexTool GUI** is a standalone
|
|
96
|
+
application (`python -m flextool.gui`) that manages projects and input
|
|
97
|
+
sources, runs scenarios, and lets you **browse the results** — a result viewer
|
|
98
|
+
reads outputs directly and supports single-scenario, scenario-comparison, and
|
|
99
|
+
network-graph views with keyboard navigation. See the
|
|
100
|
+
[FlexTool GUI guide](https://irena-flextool.github.io/flextool/flextool_gui_interface/).
|
|
101
|
+
- **Spine Toolbox is still a parallel interface.** Advanced users who build
|
|
102
|
+
multi-tool workflows or integrate FlexTool with other models can keep using
|
|
103
|
+
the [Spine Toolbox workflow](https://irena-flextool.github.io/flextool/spine_toolbox/).
|
|
104
|
+
- **The same model and data.** Existing input databases continue to work; the
|
|
105
|
+
change is in how the matrix is generated and solved, not in the model
|
|
106
|
+
formulation.
|
|
107
|
+
|
|
108
|
+
This is IRENA FlexTool v4 (see the current version in CHANGELOG.md). Report any bugs or difficulties in the [issue tracker](https://github.com/irena-flextool/flextool/issues).
|
|
109
|
+
The previous version of IRENA FlexTool can be found in https://www.irena.org/energytransition/Energy-System-Models-and-Data/IRENA-FlexTool.
|
|
110
|
+
|
|
111
|
+
## Under the hood: Rust-based matrix generation
|
|
112
|
+
|
|
113
|
+
FlexTool is a thin Python layer over a Rust engine. It reads its input data and
|
|
114
|
+
builds the optimisation matrix as [polars](https://pola.rs/) DataFrames via
|
|
115
|
+
[`polar-high`](https://github.com/nodal-tools/polar-high), then solves with
|
|
116
|
+
[HiGHS](https://highs.dev/). Variables and parameters are polars frames, so
|
|
117
|
+
multiplications become joins and aggregations become group-bys — the heavy
|
|
118
|
+
coefficient work runs inside polars' Rust core rather than as per-coefficient
|
|
119
|
+
Python objects, and the matrix goes straight to HiGHS through `highspy` with no
|
|
120
|
+
intermediate LP/MPS file. `polar-high` is a general-purpose, domain-free
|
|
121
|
+
modelling layer published separately (Apache-2.0, `pip install polar-high`); it
|
|
122
|
+
also applies the automatic problem scaling noted above, and its
|
|
123
|
+
[benchmark](https://nodal-tools.fi/polar-high/compare/benchmark/) compares it
|
|
124
|
+
against linopy and Pyomo on the same HiGHS solver.
|
|
125
|
+
|
|
126
|
+
## Installation
|
|
127
|
+
|
|
128
|
+
### Check your Python (and possibly install it)
|
|
129
|
+
|
|
130
|
+
FlexTool requires **Python 3.11+**.
|
|
131
|
+
|
|
132
|
+
Open a terminal (Windows: Command Prompt or PowerShell; macOS: Terminal; Linux: your shell)
|
|
133
|
+
and check which Python you have:
|
|
134
|
+
|
|
135
|
+
| Platform | Command |
|
|
136
|
+
|---|---|
|
|
137
|
+
| Windows | `py --version` (falls back to `python --version`) |
|
|
138
|
+
| macOS / Linux | `python3 --version` |
|
|
139
|
+
|
|
140
|
+
The output looks like `Python 3.12.4`. If the command is not found, prints
|
|
141
|
+
something below 3.11, or (on Windows) opens the Microsoft Store, install Python
|
|
142
|
+
from https://www.python.org/downloads/ — on Windows tick
|
|
143
|
+
**"Add python.exe to PATH"** in the installer. Then close and reopen the
|
|
144
|
+
terminal so the new PATH takes effect.
|
|
145
|
+
|
|
146
|
+
> On Windows, use `py` in place of `python` in the commands below if `python`
|
|
147
|
+
> is not recognised. If several versions are installed, `py -3.11 --version`
|
|
148
|
+
> (or `-3.12`, …) picks a specific one, and `py -0` lists them all.
|
|
149
|
+
> On macOS/Linux, `python` often means Python 2 or does not exist at all, so
|
|
150
|
+
> use `python3`. Inside an activated virtual environment, plain `python` always
|
|
151
|
+
> means that environment's Python on every platform.
|
|
152
|
+
|
|
153
|
+
|
|
154
|
+
### Install from PyPI (recommended)
|
|
155
|
+
|
|
156
|
+
Install FlexTool into a virtual environment to keep its packages separate from
|
|
157
|
+
other Python applications. If you want to install into the base Python (perhaps
|
|
158
|
+
because you do not otherwise use Python), just run the last command from below,
|
|
159
|
+
`pip install flextool`.
|
|
160
|
+
|
|
161
|
+
```
|
|
162
|
+
python -m venv .venv # Windows: py -m venv .venv
|
|
163
|
+
# macOS/Linux: python3 -m venv .venv
|
|
164
|
+
# activate — Windows PowerShell: .\.venv\Scripts\Activate.ps1
|
|
165
|
+
# Windows CMD: .\.venv\Scripts\activate.bat
|
|
166
|
+
# Linux / macOS: . .venv/bin/activate
|
|
167
|
+
python -m pip install --upgrade pip
|
|
168
|
+
pip install flextool
|
|
169
|
+
```
|
|
170
|
+
|
|
171
|
+
Your prompt should now show `(.venv)`. Verify with `python --version` — it
|
|
172
|
+
should report 3.11 or newer.
|
|
173
|
+
|
|
174
|
+
(If PowerShell blocks the activate script, run once per user:
|
|
175
|
+
`Set-ExecutionPolicy -Scope CurrentUser RemoteSigned`.)
|
|
176
|
+
|
|
177
|
+
Launch the FlexTool GUI:
|
|
178
|
+
|
|
179
|
+
```
|
|
180
|
+
flextool
|
|
181
|
+
```
|
|
182
|
+
|
|
183
|
+
— equivalently `python -m flextool.gui`. The GUI creates and manages your
|
|
184
|
+
projects and input databases; to seed the bundled template and example
|
|
185
|
+
databases (handy for the CLI or Spine Toolbox workflows) run `flextool-update`.
|
|
186
|
+
|
|
187
|
+
### Install from source (developers / latest `main`)
|
|
188
|
+
|
|
189
|
+
To participate in FlexTool development — or to run the not-yet-released `main`
|
|
190
|
+
— clone the repo and install it editable:
|
|
191
|
+
|
|
192
|
+
```powershell
|
|
193
|
+
git clone https://github.com/irena-flextool/flextool.git
|
|
194
|
+
cd flextool
|
|
195
|
+
python -m venv .venv
|
|
196
|
+
.\.venv\Scripts\Activate.ps1 # Linux / macOS: . .venv/bin/activate
|
|
197
|
+
python -m pip install --upgrade pip
|
|
198
|
+
pip install -e .
|
|
199
|
+
```
|
|
200
|
+
|
|
201
|
+
The editable install picks up source changes on `git pull`; re-run
|
|
202
|
+
`pip install -e .` only when a dependency pin in `pyproject.toml` changes.
|
|
203
|
+
|
|
204
|
+
### Update FlexTool:
|
|
205
|
+
|
|
206
|
+
```
|
|
207
|
+
# If using virtual environment (venv), then activate venv first:
|
|
208
|
+
# Windows PowerShell: .\.venv\Scripts\Activate.ps1
|
|
209
|
+
# Windows CMD: .\.venv\Scripts\activate.bat
|
|
210
|
+
# Linux / macOS: . .venv/bin/activate
|
|
211
|
+
pip install --upgrade flextool
|
|
212
|
+
```
|
|
213
|
+
|
|
214
|
+
## [Documentation](https://irena-flextool.github.io/flextool/) and [installation](https://irena-flextool.github.io/flextool/install_toolbox/)
|
|
215
|
+
|
|
216
|
+
> [!IMPORTANT]
|
|
217
|
+
> Installation, user guide and ***documentation*** can be found at: https://irena-flextool.github.io/flextool/.
|
flextool-4.0.0/README.md
ADDED
|
@@ -0,0 +1,149 @@
|
|
|
1
|
+
[](https://pypi.org/project/flextool/)
|
|
2
|
+
[](https://irena-flextool.github.io/flextool/)
|
|
3
|
+
[](https://www.python.org/downloads/release/python-3120/)
|
|
4
|
+
|
|
5
|
+

|
|
6
|
+
|
|
7
|
+
IRENA FlexTool is an energy and power systems model for understanding the role of variable power generation in future energy systems. It performs capacity expansion planning as well as operational planning.
|
|
8
|
+
|
|
9
|
+
> [!NOTE]
|
|
10
|
+
> The previous `master` branch is deprecated and no longer updated — `main` is
|
|
11
|
+
> now FlexTool. If you still run FlexTool from `master`, migrate with a fresh
|
|
12
|
+
> parallel install (separate directory and venv); see
|
|
13
|
+
> [Installation](#installation) so your existing setup is left untouched.
|
|
14
|
+
|
|
15
|
+
## What's new
|
|
16
|
+
|
|
17
|
+
- **A lot faster.** The model build and pre-processing now run as pure Python
|
|
18
|
+
instead of the previous GLPSOL-based text pre-processing and AMPL-style model
|
|
19
|
+
translation. There is no LP file written to disk and re-read between build and
|
|
20
|
+
solve.
|
|
21
|
+
- **Automatic problem scaling.** The `polar-high` matrix layer automatically
|
|
22
|
+
scales the optimisation problem before it reaches the solver. Better numerical
|
|
23
|
+
conditioning often speeds up the HiGHS solve considerably — sometimes
|
|
24
|
+
dramatically — so total run time usually improves well beyond the faster build
|
|
25
|
+
alone. The solver is still HiGHS; the gain comes from handing it a
|
|
26
|
+
better-conditioned problem.
|
|
27
|
+
- **A new, easy-to-use interface.** The **FlexTool GUI** is a standalone
|
|
28
|
+
application (`python -m flextool.gui`) that manages projects and input
|
|
29
|
+
sources, runs scenarios, and lets you **browse the results** — a result viewer
|
|
30
|
+
reads outputs directly and supports single-scenario, scenario-comparison, and
|
|
31
|
+
network-graph views with keyboard navigation. See the
|
|
32
|
+
[FlexTool GUI guide](https://irena-flextool.github.io/flextool/flextool_gui_interface/).
|
|
33
|
+
- **Spine Toolbox is still a parallel interface.** Advanced users who build
|
|
34
|
+
multi-tool workflows or integrate FlexTool with other models can keep using
|
|
35
|
+
the [Spine Toolbox workflow](https://irena-flextool.github.io/flextool/spine_toolbox/).
|
|
36
|
+
- **The same model and data.** Existing input databases continue to work; the
|
|
37
|
+
change is in how the matrix is generated and solved, not in the model
|
|
38
|
+
formulation.
|
|
39
|
+
|
|
40
|
+
This is IRENA FlexTool v4 (see the current version in CHANGELOG.md). Report any bugs or difficulties in the [issue tracker](https://github.com/irena-flextool/flextool/issues).
|
|
41
|
+
The previous version of IRENA FlexTool can be found in https://www.irena.org/energytransition/Energy-System-Models-and-Data/IRENA-FlexTool.
|
|
42
|
+
|
|
43
|
+
## Under the hood: Rust-based matrix generation
|
|
44
|
+
|
|
45
|
+
FlexTool is a thin Python layer over a Rust engine. It reads its input data and
|
|
46
|
+
builds the optimisation matrix as [polars](https://pola.rs/) DataFrames via
|
|
47
|
+
[`polar-high`](https://github.com/nodal-tools/polar-high), then solves with
|
|
48
|
+
[HiGHS](https://highs.dev/). Variables and parameters are polars frames, so
|
|
49
|
+
multiplications become joins and aggregations become group-bys — the heavy
|
|
50
|
+
coefficient work runs inside polars' Rust core rather than as per-coefficient
|
|
51
|
+
Python objects, and the matrix goes straight to HiGHS through `highspy` with no
|
|
52
|
+
intermediate LP/MPS file. `polar-high` is a general-purpose, domain-free
|
|
53
|
+
modelling layer published separately (Apache-2.0, `pip install polar-high`); it
|
|
54
|
+
also applies the automatic problem scaling noted above, and its
|
|
55
|
+
[benchmark](https://nodal-tools.fi/polar-high/compare/benchmark/) compares it
|
|
56
|
+
against linopy and Pyomo on the same HiGHS solver.
|
|
57
|
+
|
|
58
|
+
## Installation
|
|
59
|
+
|
|
60
|
+
### Check your Python (and possibly install it)
|
|
61
|
+
|
|
62
|
+
FlexTool requires **Python 3.11+**.
|
|
63
|
+
|
|
64
|
+
Open a terminal (Windows: Command Prompt or PowerShell; macOS: Terminal; Linux: your shell)
|
|
65
|
+
and check which Python you have:
|
|
66
|
+
|
|
67
|
+
| Platform | Command |
|
|
68
|
+
|---|---|
|
|
69
|
+
| Windows | `py --version` (falls back to `python --version`) |
|
|
70
|
+
| macOS / Linux | `python3 --version` |
|
|
71
|
+
|
|
72
|
+
The output looks like `Python 3.12.4`. If the command is not found, prints
|
|
73
|
+
something below 3.11, or (on Windows) opens the Microsoft Store, install Python
|
|
74
|
+
from https://www.python.org/downloads/ — on Windows tick
|
|
75
|
+
**"Add python.exe to PATH"** in the installer. Then close and reopen the
|
|
76
|
+
terminal so the new PATH takes effect.
|
|
77
|
+
|
|
78
|
+
> On Windows, use `py` in place of `python` in the commands below if `python`
|
|
79
|
+
> is not recognised. If several versions are installed, `py -3.11 --version`
|
|
80
|
+
> (or `-3.12`, …) picks a specific one, and `py -0` lists them all.
|
|
81
|
+
> On macOS/Linux, `python` often means Python 2 or does not exist at all, so
|
|
82
|
+
> use `python3`. Inside an activated virtual environment, plain `python` always
|
|
83
|
+
> means that environment's Python on every platform.
|
|
84
|
+
|
|
85
|
+
|
|
86
|
+
### Install from PyPI (recommended)
|
|
87
|
+
|
|
88
|
+
Install FlexTool into a virtual environment to keep its packages separate from
|
|
89
|
+
other Python applications. If you want to install into the base Python (perhaps
|
|
90
|
+
because you do not otherwise use Python), just run the last command from below,
|
|
91
|
+
`pip install flextool`.
|
|
92
|
+
|
|
93
|
+
```
|
|
94
|
+
python -m venv .venv # Windows: py -m venv .venv
|
|
95
|
+
# macOS/Linux: python3 -m venv .venv
|
|
96
|
+
# activate — Windows PowerShell: .\.venv\Scripts\Activate.ps1
|
|
97
|
+
# Windows CMD: .\.venv\Scripts\activate.bat
|
|
98
|
+
# Linux / macOS: . .venv/bin/activate
|
|
99
|
+
python -m pip install --upgrade pip
|
|
100
|
+
pip install flextool
|
|
101
|
+
```
|
|
102
|
+
|
|
103
|
+
Your prompt should now show `(.venv)`. Verify with `python --version` — it
|
|
104
|
+
should report 3.11 or newer.
|
|
105
|
+
|
|
106
|
+
(If PowerShell blocks the activate script, run once per user:
|
|
107
|
+
`Set-ExecutionPolicy -Scope CurrentUser RemoteSigned`.)
|
|
108
|
+
|
|
109
|
+
Launch the FlexTool GUI:
|
|
110
|
+
|
|
111
|
+
```
|
|
112
|
+
flextool
|
|
113
|
+
```
|
|
114
|
+
|
|
115
|
+
— equivalently `python -m flextool.gui`. The GUI creates and manages your
|
|
116
|
+
projects and input databases; to seed the bundled template and example
|
|
117
|
+
databases (handy for the CLI or Spine Toolbox workflows) run `flextool-update`.
|
|
118
|
+
|
|
119
|
+
### Install from source (developers / latest `main`)
|
|
120
|
+
|
|
121
|
+
To participate in FlexTool development — or to run the not-yet-released `main`
|
|
122
|
+
— clone the repo and install it editable:
|
|
123
|
+
|
|
124
|
+
```powershell
|
|
125
|
+
git clone https://github.com/irena-flextool/flextool.git
|
|
126
|
+
cd flextool
|
|
127
|
+
python -m venv .venv
|
|
128
|
+
.\.venv\Scripts\Activate.ps1 # Linux / macOS: . .venv/bin/activate
|
|
129
|
+
python -m pip install --upgrade pip
|
|
130
|
+
pip install -e .
|
|
131
|
+
```
|
|
132
|
+
|
|
133
|
+
The editable install picks up source changes on `git pull`; re-run
|
|
134
|
+
`pip install -e .` only when a dependency pin in `pyproject.toml` changes.
|
|
135
|
+
|
|
136
|
+
### Update FlexTool:
|
|
137
|
+
|
|
138
|
+
```
|
|
139
|
+
# If using virtual environment (venv), then activate venv first:
|
|
140
|
+
# Windows PowerShell: .\.venv\Scripts\Activate.ps1
|
|
141
|
+
# Windows CMD: .\.venv\Scripts\activate.bat
|
|
142
|
+
# Linux / macOS: . .venv/bin/activate
|
|
143
|
+
pip install --upgrade flextool
|
|
144
|
+
```
|
|
145
|
+
|
|
146
|
+
## [Documentation](https://irena-flextool.github.io/flextool/) and [installation](https://irena-flextool.github.io/flextool/install_toolbox/)
|
|
147
|
+
|
|
148
|
+
> [!IMPORTANT]
|
|
149
|
+
> Installation, user guide and ***documentation*** can be found at: https://irena-flextool.github.io/flextool/.
|
|
@@ -0,0 +1,41 @@
|
|
|
1
|
+
"""FlexTool energy system optimization model package."""
|
|
2
|
+
import os as _os
|
|
3
|
+
# jemalloc decay config — set BEFORE the first ``import polars`` (which
|
|
4
|
+
# happens transitively in the imports just below). polars statically
|
|
5
|
+
# links jemalloc; jemalloc reads ``_RJEM_MALLOC_CONF`` exactly once at
|
|
6
|
+
# .so load. Its default ``dirty_decay_ms`` (~10 s) is longer than the
|
|
7
|
+
# gap between rolling-solve rolls, so each roll's freed GB-scale
|
|
8
|
+
# coefficient frames stay resident as dirty pages when the next roll
|
|
9
|
+
# starts allocating — the per-roll ``priv_dirty`` floor ratchets up
|
|
10
|
+
# (~+2 GB/roll on the 9-roll DES run). ``dirty_decay_ms:1000`` purges a
|
|
11
|
+
# roll's freed pages ~1 s after they go idle (well before the next roll,
|
|
12
|
+
# which takes minutes) without eagerly madvise-ing on every transient
|
|
13
|
+
# free inside a hot operation. ``muzzy_decay_ms:0`` forces MADV_DONTNEED
|
|
14
|
+
# (so Private_Dirty actually drops) rather than leaving pages as
|
|
15
|
+
# reclaimable-but-resident MADV_FREE. glibc knobs (MALLOC_ARENA_MAX,
|
|
16
|
+
# malloc_trim) do NOT touch polars memory — this is the lever that does.
|
|
17
|
+
# ``setdefault`` so a shell-provided value still wins (A/B profiling).
|
|
18
|
+
_os.environ.setdefault("_RJEM_MALLOC_CONF", "dirty_decay_ms:1000,muzzy_decay_ms:0")
|
|
19
|
+
import warnings as _warnings
|
|
20
|
+
# Silence requests' RequestsDependencyWarning. The FlexTool venv ships a
|
|
21
|
+
# ``requests`` whose pinned urllib3/charset_normalizer version ranges lag the
|
|
22
|
+
# (working) installed versions, so ``import requests`` warns once at import
|
|
23
|
+
# time. It is harmless but leaks into Spine Toolbox's Tool console for any
|
|
24
|
+
# path that pulls in requests (e.g. an ``http://`` Spine DB-server URL).
|
|
25
|
+
# Match by message — set BEFORE requests is imported transitively below — so
|
|
26
|
+
# we needn't import requests here just to reference its warning class, and the
|
|
27
|
+
# filter stays robust across the venv's exact version numbers.
|
|
28
|
+
_warnings.filterwarnings(
|
|
29
|
+
"ignore",
|
|
30
|
+
message=r"urllib3 .*doesn't match a supported version",
|
|
31
|
+
)
|
|
32
|
+
__all__ = [
|
|
33
|
+
'write_outputs',
|
|
34
|
+
'migrate_database',
|
|
35
|
+
'initialize_database',
|
|
36
|
+
'update_flextool',
|
|
37
|
+
]
|
|
38
|
+
from flextool.process_outputs import write_outputs # noqa: E402 (after env/warning config above)
|
|
39
|
+
from flextool.update_flextool import migrate_database, initialize_database, update_flextool # noqa: E402
|
|
40
|
+
|
|
41
|
+
name = "flextool"
|
|
@@ -0,0 +1,193 @@
|
|
|
1
|
+
"""In-process memory sampler — timestamped, allocator-aware memory trace.
|
|
2
|
+
|
|
3
|
+
RSS is a poor signal for this workload: it conflates shared, clean, and
|
|
4
|
+
allocator-reserved-but-free pages with genuinely-live private data. This
|
|
5
|
+
sampler additionally records, per sample:
|
|
6
|
+
|
|
7
|
+
* ``pss_gb`` / ``priv_dirty_gb`` / ``proc_swap_gb`` — from
|
|
8
|
+
``/proc/self/smaps_rollup``. ``Private_Dirty + Swap`` is the
|
|
9
|
+
allocator-agnostic "what this process truly owns" number (counts dirty
|
|
10
|
+
anon pages whether they live in glibc, mimalloc, or the C++ heap, and
|
|
11
|
+
whether resident or swapped).
|
|
12
|
+
* ``glibc_inuse_gb`` / ``glibc_free_gb`` / ``glibc_mmap_gb`` — from
|
|
13
|
+
glibc ``mallinfo2()`` (``uordblks`` / ``fordblks`` / ``hblkhd``). The
|
|
14
|
+
*live-vs-reserved* discriminator: ``fordblks`` is memory glibc has
|
|
15
|
+
freed but is holding on its arena free-list rather than returning to
|
|
16
|
+
the OS (what ``malloc_trim`` would release). NOTE: only sees the glibc
|
|
17
|
+
allocator — HiGHS/C++ go through glibc, but polars (Rust) may use its
|
|
18
|
+
own allocator, so a large ``priv_dirty`` with small ``glibc_inuse``
|
|
19
|
+
points at the non-glibc (polars) side.
|
|
20
|
+
* ``mem_used_gb`` — system used (``MemTotal - MemAvailable``), the number
|
|
21
|
+
most desktop system monitors plot. ``available_gb`` / ``swap_used_gb``
|
|
22
|
+
kept for back-compat.
|
|
23
|
+
|
|
24
|
+
Gated by ``FLEXTOOL_MEM_SAMPLER``; interval via
|
|
25
|
+
``FLEXTOOL_MEM_SAMPLER_INTERVAL_MS`` (default 100 ms).
|
|
26
|
+
"""
|
|
27
|
+
from __future__ import annotations
|
|
28
|
+
|
|
29
|
+
import ctypes
|
|
30
|
+
import datetime
|
|
31
|
+
import os
|
|
32
|
+
import sys
|
|
33
|
+
import threading
|
|
34
|
+
import time
|
|
35
|
+
|
|
36
|
+
|
|
37
|
+
class _Mallinfo2(ctypes.Structure):
|
|
38
|
+
# glibc >= 2.33. All fields size_t (the legacy ``mallinfo`` used int
|
|
39
|
+
# and overflows past 2 GB — useless here).
|
|
40
|
+
_fields_ = [
|
|
41
|
+
(n, ctypes.c_size_t)
|
|
42
|
+
for n in (
|
|
43
|
+
"arena", "ordblks", "smblks", "hblks", "hblkhd", "usmblks",
|
|
44
|
+
"fsmblks", "uordblks", "fordblks", "keepcost",
|
|
45
|
+
)
|
|
46
|
+
]
|
|
47
|
+
|
|
48
|
+
|
|
49
|
+
def _make_mallinfo2():
|
|
50
|
+
"""Return a callable giving (inuse, free, mmap) bytes, or None."""
|
|
51
|
+
try:
|
|
52
|
+
libc = ctypes.CDLL("libc.so.6")
|
|
53
|
+
fn = libc.mallinfo2 # AttributeError on glibc < 2.33
|
|
54
|
+
fn.restype = _Mallinfo2
|
|
55
|
+
fn.argtypes = []
|
|
56
|
+
except (OSError, AttributeError):
|
|
57
|
+
return None
|
|
58
|
+
|
|
59
|
+
def _read():
|
|
60
|
+
mi = fn()
|
|
61
|
+
return mi.uordblks, mi.fordblks, mi.hblkhd
|
|
62
|
+
|
|
63
|
+
return _read
|
|
64
|
+
|
|
65
|
+
|
|
66
|
+
def start_mem_sampler() -> None:
|
|
67
|
+
"""Start a daemon thread that samples memory at a fixed interval if FLEXTOOL_MEM_SAMPLER is set."""
|
|
68
|
+
if os.environ.get("FLEXTOOL_MEM_SAMPLER", "").strip().lower() in ("", "0", "false"):
|
|
69
|
+
return
|
|
70
|
+
|
|
71
|
+
pid = os.getpid()
|
|
72
|
+
log_path = os.environ.get("FLEXTOOL_MEM_SAMPLER_LOG", f"/tmp/flextool_mem_sampler_{pid}.log")
|
|
73
|
+
try:
|
|
74
|
+
interval_ms = max(20, min(10000, int(os.environ.get("FLEXTOOL_MEM_SAMPLER_INTERVAL_MS", "100"))))
|
|
75
|
+
except ValueError:
|
|
76
|
+
interval_ms = 100
|
|
77
|
+
interval_s = interval_ms / 1000.0
|
|
78
|
+
|
|
79
|
+
if not sys.platform.startswith("linux"):
|
|
80
|
+
with open(log_path, "a", buffering=1) as _f:
|
|
81
|
+
_f.write(
|
|
82
|
+
f"# flextool memory sampler pid={pid} WARNING: platform is not "
|
|
83
|
+
f"linux — sampler disabled\n"
|
|
84
|
+
)
|
|
85
|
+
return
|
|
86
|
+
|
|
87
|
+
_GB = float(2 ** 30)
|
|
88
|
+
_mallinfo2 = _make_mallinfo2()
|
|
89
|
+
|
|
90
|
+
def _read_kv_bytes(path: str, keys: tuple[str, ...]) -> dict[str, int]:
|
|
91
|
+
"""Parse ``Key: N kB`` lines from a /proc file → bytes."""
|
|
92
|
+
out: dict[str, int] = {}
|
|
93
|
+
want = set(keys)
|
|
94
|
+
with open(path) as fh:
|
|
95
|
+
for line in fh:
|
|
96
|
+
k = line.split(":", 1)[0]
|
|
97
|
+
if k in want:
|
|
98
|
+
out[k] = int(line.split()[1]) * 1024
|
|
99
|
+
if len(out) == len(want):
|
|
100
|
+
break
|
|
101
|
+
return out
|
|
102
|
+
|
|
103
|
+
def _sample() -> dict[str, float]:
|
|
104
|
+
# Per-process private cost — allocator-agnostic.
|
|
105
|
+
rss = pss = priv_dirty = proc_swap = 0
|
|
106
|
+
try:
|
|
107
|
+
r = _read_kv_bytes(
|
|
108
|
+
"/proc/self/smaps_rollup",
|
|
109
|
+
("Rss", "Pss", "Private_Dirty", "Swap"),
|
|
110
|
+
)
|
|
111
|
+
rss = r.get("Rss", 0)
|
|
112
|
+
pss = r.get("Pss", 0)
|
|
113
|
+
priv_dirty = r.get("Private_Dirty", 0)
|
|
114
|
+
proc_swap = r.get("Swap", 0)
|
|
115
|
+
except Exception:
|
|
116
|
+
pass
|
|
117
|
+
if rss == 0:
|
|
118
|
+
# smaps_rollup unavailable — fall back to VmRSS.
|
|
119
|
+
try:
|
|
120
|
+
rss = _read_kv_bytes("/proc/self/status", ("VmRSS",)).get("VmRSS", 0)
|
|
121
|
+
except Exception:
|
|
122
|
+
pass
|
|
123
|
+
|
|
124
|
+
# System-wide.
|
|
125
|
+
mem_total = mem_avail = swap_total = swap_free = 0
|
|
126
|
+
try:
|
|
127
|
+
m = _read_kv_bytes(
|
|
128
|
+
"/proc/meminfo",
|
|
129
|
+
("MemTotal", "MemAvailable", "SwapTotal", "SwapFree"),
|
|
130
|
+
)
|
|
131
|
+
mem_total = m.get("MemTotal", 0)
|
|
132
|
+
mem_avail = m.get("MemAvailable", 0)
|
|
133
|
+
swap_total = m.get("SwapTotal", 0)
|
|
134
|
+
swap_free = m.get("SwapFree", 0)
|
|
135
|
+
except Exception:
|
|
136
|
+
pass
|
|
137
|
+
|
|
138
|
+
# glibc allocator breakdown — live vs reserved-free.
|
|
139
|
+
g_inuse = g_free = g_mmap = -1
|
|
140
|
+
if _mallinfo2 is not None:
|
|
141
|
+
try:
|
|
142
|
+
g_inuse, g_free, g_mmap = _mallinfo2()
|
|
143
|
+
except Exception:
|
|
144
|
+
pass
|
|
145
|
+
|
|
146
|
+
return {
|
|
147
|
+
"rss_gb": rss / _GB,
|
|
148
|
+
"pss_gb": pss / _GB,
|
|
149
|
+
"priv_dirty_gb": priv_dirty / _GB,
|
|
150
|
+
"proc_swap_gb": proc_swap / _GB,
|
|
151
|
+
"available_gb": mem_avail / _GB,
|
|
152
|
+
"mem_used_gb": (mem_total - mem_avail) / _GB,
|
|
153
|
+
"swap_used_gb": (swap_total - swap_free) / _GB,
|
|
154
|
+
"glibc_inuse_gb": g_inuse / _GB if g_inuse >= 0 else -1.0,
|
|
155
|
+
"glibc_free_gb": g_free / _GB if g_free >= 0 else -1.0,
|
|
156
|
+
"glibc_mmap_gb": g_mmap / _GB if g_mmap >= 0 else -1.0,
|
|
157
|
+
}
|
|
158
|
+
|
|
159
|
+
started_at = datetime.datetime.now(datetime.UTC).isoformat()
|
|
160
|
+
# Stable column order so post-hoc parsing is trivial.
|
|
161
|
+
_cols = (
|
|
162
|
+
"rss_gb", "pss_gb", "priv_dirty_gb", "proc_swap_gb",
|
|
163
|
+
"available_gb", "mem_used_gb", "swap_used_gb",
|
|
164
|
+
"glibc_inuse_gb", "glibc_free_gb", "glibc_mmap_gb",
|
|
165
|
+
)
|
|
166
|
+
|
|
167
|
+
def _loop(log_path: str, interval_s: float) -> None:
|
|
168
|
+
mono_start = time.monotonic()
|
|
169
|
+
with open(log_path, "a", buffering=1) as f:
|
|
170
|
+
f.write(
|
|
171
|
+
f"# flextool memory sampler pid={pid} started_at={started_at} "
|
|
172
|
+
f"interval_ms={interval_ms} mallinfo2={'yes' if _mallinfo2 else 'no'}\n"
|
|
173
|
+
)
|
|
174
|
+
f.write("# priv_dirty_gb+proc_swap_gb = true private cost; "
|
|
175
|
+
"glibc_free_gb = held-free (malloc_trim-able); "
|
|
176
|
+
"mem_used_gb = system used (monitor metric)\n")
|
|
177
|
+
while True:
|
|
178
|
+
ts = datetime.datetime.now(datetime.UTC).isoformat()
|
|
179
|
+
mono_s = time.monotonic() - mono_start
|
|
180
|
+
try:
|
|
181
|
+
s = _sample()
|
|
182
|
+
parts = "\t".join(f"{c}={s[c]:.4f}" for c in _cols)
|
|
183
|
+
line = f"ts={ts}\tmono_s={mono_s:.3f}\tepoch={time.time():.3f}\t{parts}\n"
|
|
184
|
+
except Exception as exc:
|
|
185
|
+
line = f"ts={ts}\tmono_s={mono_s:.3f}\tepoch={time.time():.3f}\terror={repr(exc)}\n"
|
|
186
|
+
f.write(line)
|
|
187
|
+
# Explicit flush so the last samples before SIGKILL reach disk;
|
|
188
|
+
# line-buffered mode alone won't flush until the process exits cleanly.
|
|
189
|
+
f.flush()
|
|
190
|
+
time.sleep(interval_s)
|
|
191
|
+
|
|
192
|
+
t = threading.Thread(target=_loop, args=(log_path, interval_s), name="flextool-mem-sampler", daemon=True)
|
|
193
|
+
t.start()
|
|
@@ -0,0 +1,43 @@
|
|
|
1
|
+
"""Locate bundled FlexTool package data files.
|
|
2
|
+
|
|
3
|
+
Static FlexTool resources — schema JSONs, YAML/text templates, and
|
|
4
|
+
canonical-database sources (all under ``flextool/schemas/``), plus the HiGHS
|
|
5
|
+
options template (``flextool/bin/``) — must be reached through
|
|
6
|
+
:mod:`importlib.resources` rather than ``Path(__file__).resolve()``
|
|
7
|
+
walks. After ``pip install flextool`` the package is the only thing
|
|
8
|
+
on ``sys.path``; the historical layout where these dirs sat at the
|
|
9
|
+
*repo root* alongside the package no longer exists.
|
|
10
|
+
|
|
11
|
+
Two helpers are exposed:
|
|
12
|
+
|
|
13
|
+
``package_data_path(relative)``
|
|
14
|
+
Returns a :class:`pathlib.Path` to a resource inside the
|
|
15
|
+
``flextool`` package, e.g.
|
|
16
|
+
``package_data_path("schemas/default_plots.yaml")``.
|
|
17
|
+
Editable installs return the real on-disk path; wheel installs
|
|
18
|
+
return the unpacked site-packages path (importlib.resources
|
|
19
|
+
materialises zipped data on demand, but we never ship zipped so
|
|
20
|
+
in practice this is always a stable filesystem path).
|
|
21
|
+
|
|
22
|
+
``package_data_text(relative)``
|
|
23
|
+
Convenience wrapper that returns the file contents as a string —
|
|
24
|
+
handy when the caller doesn't actually need a path (YAML/JSON
|
|
25
|
+
parsing).
|
|
26
|
+
"""
|
|
27
|
+
|
|
28
|
+
from __future__ import annotations
|
|
29
|
+
|
|
30
|
+
from importlib import resources
|
|
31
|
+
from pathlib import Path
|
|
32
|
+
|
|
33
|
+
import flextool
|
|
34
|
+
|
|
35
|
+
|
|
36
|
+
def package_data_path(relative: str) -> Path:
|
|
37
|
+
"""Path to ``flextool/<relative>`` inside the installed package."""
|
|
38
|
+
return Path(resources.files(flextool).joinpath(relative))
|
|
39
|
+
|
|
40
|
+
|
|
41
|
+
def package_data_text(relative: str) -> str:
|
|
42
|
+
"""Text contents of ``flextool/<relative>``."""
|
|
43
|
+
return resources.files(flextool).joinpath(relative).read_text(encoding="utf-8")
|