OpenPinch 0.7.1__tar.gz → 0.7.2__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.
- {openpinch-0.7.1 → openpinch-0.7.2}/OpenPinch/adapters/io/csv.py +13 -14
- {openpinch-0.7.1 → openpinch-0.7.2}/OpenPinch/adapters/io/records.py +41 -4
- {openpinch-0.7.1 → openpinch-0.7.2}/OpenPinch/adapters/io/tabular.py +127 -1
- {openpinch-0.7.1 → openpinch-0.7.2}/OpenPinch/adapters/io/workbook.py +14 -18
- {openpinch-0.7.1 → openpinch-0.7.2}/OpenPinch/analysis/energy_transfer/diagram.py +9 -0
- {openpinch-0.7.1 → openpinch-0.7.2}/OpenPinch/analysis/exergy/service.py +126 -5
- {openpinch-0.7.1 → openpinch-0.7.2}/OpenPinch/analysis/graphs/composite.py +15 -7
- {openpinch-0.7.1 → openpinch-0.7.2}/OpenPinch/analysis/heat_exchanger_networks/extraction/metadata.py +2 -2
- {openpinch-0.7.1 → openpinch-0.7.2}/OpenPinch/analysis/heat_exchanger_networks/extraction/period_state.py +87 -58
- {openpinch-0.7.1 → openpinch-0.7.2}/OpenPinch/analysis/heat_exchanger_networks/extraction/segment_area.py +2 -1
- {openpinch-0.7.1 → openpinch-0.7.2}/OpenPinch/analysis/heat_exchanger_networks/extraction/service.py +31 -19
- {openpinch-0.7.1 → openpinch-0.7.2}/OpenPinch/analysis/heat_exchanger_networks/extraction/utility.py +18 -4
- {openpinch-0.7.1 → openpinch-0.7.2}/OpenPinch/analysis/heat_exchanger_networks/models/_base/alpha.py +1 -1
- openpinch-0.7.2/OpenPinch/analysis/heat_exchanger_networks/models/_base/approach.py +499 -0
- openpinch-0.7.2/OpenPinch/analysis/heat_exchanger_networks/models/_base/area.py +469 -0
- {openpinch-0.7.1 → openpinch-0.7.2}/OpenPinch/analysis/heat_exchanger_networks/models/_base/costing.py +32 -16
- {openpinch-0.7.1 → openpinch-0.7.2}/OpenPinch/analysis/heat_exchanger_networks/models/_base/parameters.py +2 -0
- {openpinch-0.7.1 → openpinch-0.7.2}/OpenPinch/analysis/heat_exchanger_networks/models/_base/piecewise.py +146 -118
- {openpinch-0.7.1 → openpinch-0.7.2}/OpenPinch/analysis/heat_exchanger_networks/models/_base/superstructure.py +46 -43
- {openpinch-0.7.1 → openpinch-0.7.2}/OpenPinch/analysis/heat_exchanger_networks/models/_pinch_design/amalgamation.py +42 -22
- {openpinch-0.7.1 → openpinch-0.7.2}/OpenPinch/analysis/heat_exchanger_networks/models/_pinch_design/equations.py +64 -11
- openpinch-0.7.2/OpenPinch/analysis/heat_exchanger_networks/models/_pinch_design/postprocess.py +115 -0
- {openpinch-0.7.1 → openpinch-0.7.2}/OpenPinch/analysis/heat_exchanger_networks/models/_pinch_design/preprocessing.py +18 -8
- {openpinch-0.7.1 → openpinch-0.7.2}/OpenPinch/analysis/heat_exchanger_networks/models/_stagewise/equations.py +10 -8
- {openpinch-0.7.1 → openpinch-0.7.2}/OpenPinch/analysis/heat_exchanger_networks/models/_stagewise/evolution.py +7 -0
- {openpinch-0.7.1 → openpinch-0.7.2}/OpenPinch/analysis/heat_exchanger_networks/models/_stagewise/objectives.py +146 -132
- {openpinch-0.7.1 → openpinch-0.7.2}/OpenPinch/analysis/heat_exchanger_networks/models/_stagewise/postprocess.py +8 -130
- {openpinch-0.7.1 → openpinch-0.7.2}/OpenPinch/analysis/heat_exchanger_networks/models/_stagewise/setup.py +35 -22
- {openpinch-0.7.1 → openpinch-0.7.2}/OpenPinch/analysis/heat_exchanger_networks/models/_stagewise/verification.py +67 -84
- {openpinch-0.7.1 → openpinch-0.7.2}/OpenPinch/analysis/heat_exchanger_networks/models/_stagewise/warm_start.py +65 -87
- {openpinch-0.7.1 → openpinch-0.7.2}/OpenPinch/analysis/heat_exchanger_networks/models/base.py +20 -3
- {openpinch-0.7.1 → openpinch-0.7.2}/OpenPinch/analysis/heat_exchanger_networks/models/problem.py +58 -13
- {openpinch-0.7.1 → openpinch-0.7.2}/OpenPinch/analysis/heat_exchanger_networks/reporting/ranking.py +1 -9
- {openpinch-0.7.1 → openpinch-0.7.2}/OpenPinch/analysis/heat_exchanger_networks/reporting/verification.py +55 -34
- {openpinch-0.7.1 → openpinch-0.7.2}/OpenPinch/analysis/heat_exchanger_networks/results/assembly.py +17 -11
- {openpinch-0.7.1 → openpinch-0.7.2}/OpenPinch/analysis/heat_exchanger_networks/solver/arrays.py +4 -5
- {openpinch-0.7.1 → openpinch-0.7.2}/OpenPinch/analysis/heat_exchanger_networks/solver/backend.py +11 -8
- {openpinch-0.7.1 → openpinch-0.7.2}/OpenPinch/analysis/heat_exchanger_networks/solver/piecewise.py +13 -5
- {openpinch-0.7.1 → openpinch-0.7.2}/OpenPinch/analysis/heat_exchanger_networks/targeting/pinch_design_method.py +19 -7
- {openpinch-0.7.1 → openpinch-0.7.2}/OpenPinch/analysis/heat_pumps/common/shared.py +23 -1
- {openpinch-0.7.1 → openpinch-0.7.2}/OpenPinch/analysis/heat_pumps/cycles/carnot_cycles.py +53 -19
- {openpinch-0.7.1 → openpinch-0.7.2}/OpenPinch/analysis/heat_pumps/cycles/cascade_vapour_compression_cycle.py +2 -2
- {openpinch-0.7.1 → openpinch-0.7.2}/OpenPinch/analysis/heat_pumps/cycles/vapour_compression_cycle.py +15 -6
- {openpinch-0.7.1 → openpinch-0.7.2}/OpenPinch/analysis/heat_pumps/targeting/_carnot_common.py +10 -1
- {openpinch-0.7.1 → openpinch-0.7.2}/OpenPinch/analysis/targeting/area_cost.py +23 -9
- {openpinch-0.7.1 → openpinch-0.7.2}/OpenPinch/analysis/targeting/direct.py +30 -2
- {openpinch-0.7.1 → openpinch-0.7.2}/OpenPinch/analysis/targeting/grand_composite.py +22 -8
- {openpinch-0.7.1 → openpinch-0.7.2}/OpenPinch/analysis/targeting/indirect.py +112 -28
- {openpinch-0.7.1 → openpinch-0.7.2}/OpenPinch/analysis/targeting/temperature_driving_force.py +23 -81
- {openpinch-0.7.1 → openpinch-0.7.2}/OpenPinch/analysis/targeting/utilities.py +12 -0
- {openpinch-0.7.1 → openpinch-0.7.2}/OpenPinch/analysis/utility_placement/bounds.py +19 -0
- {openpinch-0.7.1 → openpinch-0.7.2}/OpenPinch/analysis/utility_placement/thermodynamics.py +15 -17
- {openpinch-0.7.1 → openpinch-0.7.2}/OpenPinch/application/_problem/accessors/design.py +0 -4
- {openpinch-0.7.1 → openpinch-0.7.2}/OpenPinch/application/_problem/input/construction.py +23 -7
- {openpinch-0.7.1 → openpinch-0.7.2}/OpenPinch/application/_problem/input/semantics.py +161 -21
- {openpinch-0.7.1 → openpinch-0.7.2}/OpenPinch/application/_problem/output/reporting.py +22 -3
- {openpinch-0.7.1 → openpinch-0.7.2}/OpenPinch/application/_problem/periods/aggregation.py +27 -7
- {openpinch-0.7.1 → openpinch-0.7.2}/OpenPinch/application/_problem/targeting/state.py +9 -3
- {openpinch-0.7.1 → openpinch-0.7.2}/OpenPinch/application/commands.py +100 -16
- {openpinch-0.7.1 → openpinch-0.7.2}/OpenPinch/application/problem.py +9 -0
- {openpinch-0.7.1 → openpinch-0.7.2}/OpenPinch/application/utility_placement.py +110 -21
- {openpinch-0.7.1 → openpinch-0.7.2}/OpenPinch/contracts/input.py +11 -4
- {openpinch-0.7.1 → openpinch-0.7.2}/OpenPinch/contracts/reporting.py +6 -1
- {openpinch-0.7.1 → openpinch-0.7.2}/OpenPinch/contracts/units.py +48 -1
- {openpinch-0.7.1 → openpinch-0.7.2}/OpenPinch/contracts/utility_placement.py +15 -3
- {openpinch-0.7.1 → openpinch-0.7.2}/OpenPinch/contracts/workspace.py +1 -0
- {openpinch-0.7.1 → openpinch-0.7.2}/OpenPinch/domain/_problem_table/intervals.py +1 -1
- {openpinch-0.7.1 → openpinch-0.7.2}/OpenPinch/domain/_stream/linearisation.py +10 -4
- {openpinch-0.7.1 → openpinch-0.7.2}/OpenPinch/domain/_stream/segment.py +1 -1
- {openpinch-0.7.1 → openpinch-0.7.2}/OpenPinch/domain/_stream/value_state.py +7 -0
- {openpinch-0.7.1 → openpinch-0.7.2}/OpenPinch/domain/_value/units.py +68 -0
- {openpinch-0.7.1 → openpinch-0.7.2}/OpenPinch/domain/configuration.py +33 -0
- {openpinch-0.7.1 → openpinch-0.7.2}/OpenPinch/domain/configuration_fields.py +5 -0
- openpinch-0.7.2/OpenPinch/domain/solver_options.py +134 -0
- {openpinch-0.7.1 → openpinch-0.7.2}/OpenPinch/domain/targets.py +1 -0
- {openpinch-0.7.1 → openpinch-0.7.2}/OpenPinch/domain/value.py +6 -0
- {openpinch-0.7.1 → openpinch-0.7.2}/OpenPinch/domain/zone.py +21 -25
- {openpinch-0.7.1 → openpinch-0.7.2}/OpenPinch/optimisation/backends/_multistart.py +3 -0
- {openpinch-0.7.1 → openpinch-0.7.2}/OpenPinch/optimisation/backends/bayesian.py +3 -0
- {openpinch-0.7.1 → openpinch-0.7.2}/OpenPinch/optimisation/backends/cma_es.py +3 -0
- {openpinch-0.7.1 → openpinch-0.7.2}/OpenPinch/optimisation/backends/dual_annealing.py +3 -0
- {openpinch-0.7.1 → openpinch-0.7.2}/OpenPinch/optimisation/backends/rbf.py +3 -0
- {openpinch-0.7.1 → openpinch-0.7.2}/OpenPinch/optimisation/candidates.py +29 -9
- {openpinch-0.7.1 → openpinch-0.7.2}/OpenPinch/optimisation/execution.py +61 -1
- openpinch-0.7.2/OpenPinch/optimisation/feasibility.py +106 -0
- {openpinch-0.7.1 → openpinch-0.7.2}/OpenPinch/optimisation/models.py +15 -0
- {openpinch-0.7.1 → openpinch-0.7.2}/OpenPinch/optimisation/service.py +41 -61
- {openpinch-0.7.1 → openpinch-0.7.2}/OpenPinch/presentation/configuration.py +16 -15
- {openpinch-0.7.1 → openpinch-0.7.2}/OpenPinch/presentation/configuration_text.py +21 -8
- {openpinch-0.7.1 → openpinch-0.7.2}/OpenPinch/presentation/dashboard/exports.py +2 -0
- openpinch-0.7.2/OpenPinch/presentation/reporting/excel_text.py +29 -0
- {openpinch-0.7.1 → openpinch-0.7.2}/OpenPinch/presentation/reporting/problem_table.py +2 -0
- {openpinch-0.7.1 → openpinch-0.7.2}/OpenPinch/presentation/reporting/thermal.py +1 -0
- {openpinch-0.7.1 → openpinch-0.7.2}/OpenPinch/presentation/reporting/workbook.py +3 -1
- {openpinch-0.7.1 → openpinch-0.7.2}/PKG-INFO +1 -1
- {openpinch-0.7.1 → openpinch-0.7.2}/pyproject.toml +1 -1
- openpinch-0.7.1/OpenPinch/analysis/heat_exchanger_networks/models/_base/approach.py +0 -382
- openpinch-0.7.1/OpenPinch/analysis/heat_exchanger_networks/models/_base/area.py +0 -316
- openpinch-0.7.1/OpenPinch/analysis/heat_exchanger_networks/models/_pinch_design/postprocess.py +0 -202
- {openpinch-0.7.1 → openpinch-0.7.2}/.gitignore +0 -0
- {openpinch-0.7.1 → openpinch-0.7.2}/LICENSE +0 -0
- {openpinch-0.7.1 → openpinch-0.7.2}/OpenPinch/__init__.py +0 -0
- {openpinch-0.7.1 → openpinch-0.7.2}/OpenPinch/__main__.py +0 -0
- {openpinch-0.7.1 → openpinch-0.7.2}/OpenPinch/adapters/__init__.py +0 -0
- {openpinch-0.7.1 → openpinch-0.7.2}/OpenPinch/adapters/io/__init__.py +0 -0
- {openpinch-0.7.1 → openpinch-0.7.2}/OpenPinch/adapters/io/file_exports.py +0 -0
- {openpinch-0.7.1 → openpinch-0.7.2}/OpenPinch/adapters/io/json.py +0 -0
- {openpinch-0.7.1 → openpinch-0.7.2}/OpenPinch/adapters/io/problem_sources.py +0 -0
- {openpinch-0.7.1 → openpinch-0.7.2}/OpenPinch/adapters/io/workspace_bundles.py +0 -0
- {openpinch-0.7.1 → openpinch-0.7.2}/OpenPinch/adapters/optional_dependencies.py +0 -0
- {openpinch-0.7.1 → openpinch-0.7.2}/OpenPinch/analysis/__init__.py +0 -0
- {openpinch-0.7.1 → openpinch-0.7.2}/OpenPinch/analysis/economics.py +0 -0
- {openpinch-0.7.1 → openpinch-0.7.2}/OpenPinch/analysis/energy_transfer/__init__.py +0 -0
- {openpinch-0.7.1 → openpinch-0.7.2}/OpenPinch/analysis/energy_transfer/cascade.py +0 -0
- {openpinch-0.7.1 → openpinch-0.7.2}/OpenPinch/analysis/energy_transfer/selection.py +0 -0
- {openpinch-0.7.1 → openpinch-0.7.2}/OpenPinch/analysis/energy_transfer/serialization.py +0 -0
- {openpinch-0.7.1 → openpinch-0.7.2}/OpenPinch/analysis/energy_transfer/service.py +0 -0
- {openpinch-0.7.1 → openpinch-0.7.2}/OpenPinch/analysis/exergy/__init__.py +0 -0
- {openpinch-0.7.1 → openpinch-0.7.2}/OpenPinch/analysis/graphs/__init__.py +0 -0
- {openpinch-0.7.1 → openpinch-0.7.2}/OpenPinch/analysis/graphs/grand_composite.py +0 -0
- {openpinch-0.7.1 → openpinch-0.7.2}/OpenPinch/analysis/graphs/metadata.py +0 -0
- {openpinch-0.7.1 → openpinch-0.7.2}/OpenPinch/analysis/graphs/primitives.py +0 -0
- {openpinch-0.7.1 → openpinch-0.7.2}/OpenPinch/analysis/graphs/service.py +0 -0
- {openpinch-0.7.1 → openpinch-0.7.2}/OpenPinch/analysis/graphs/specifications.py +0 -0
- {openpinch-0.7.1 → openpinch-0.7.2}/OpenPinch/analysis/heat_exchanger_networks/__init__.py +0 -0
- {openpinch-0.7.1 → openpinch-0.7.2}/OpenPinch/analysis/heat_exchanger_networks/context.py +0 -0
- {openpinch-0.7.1 → openpinch-0.7.2}/OpenPinch/analysis/heat_exchanger_networks/controllability.py +0 -0
- {openpinch-0.7.1 → openpinch-0.7.2}/OpenPinch/analysis/heat_exchanger_networks/duty_optimisation.py +0 -0
- {openpinch-0.7.1 → openpinch-0.7.2}/OpenPinch/analysis/heat_exchanger_networks/errors.py +0 -0
- {openpinch-0.7.1 → openpinch-0.7.2}/OpenPinch/analysis/heat_exchanger_networks/execution/__init__.py +0 -0
- {openpinch-0.7.1 → openpinch-0.7.2}/OpenPinch/analysis/heat_exchanger_networks/execution/executor.py +0 -0
- {openpinch-0.7.1 → openpinch-0.7.2}/OpenPinch/analysis/heat_exchanger_networks/execution/fake_executor.py +0 -0
- {openpinch-0.7.1 → openpinch-0.7.2}/OpenPinch/analysis/heat_exchanger_networks/execution/fallbacks.py +0 -0
- {openpinch-0.7.1 → openpinch-0.7.2}/OpenPinch/analysis/heat_exchanger_networks/execution/pathways.py +0 -0
- {openpinch-0.7.1 → openpinch-0.7.2}/OpenPinch/analysis/heat_exchanger_networks/execution/settings.py +0 -0
- {openpinch-0.7.1 → openpinch-0.7.2}/OpenPinch/analysis/heat_exchanger_networks/execution/task_builders.py +0 -0
- {openpinch-0.7.1 → openpinch-0.7.2}/OpenPinch/analysis/heat_exchanger_networks/extraction/__init__.py +0 -0
- {openpinch-0.7.1 → openpinch-0.7.2}/OpenPinch/analysis/heat_exchanger_networks/extraction/recovery.py +0 -0
- {openpinch-0.7.1 → openpinch-0.7.2}/OpenPinch/analysis/heat_exchanger_networks/indexing.py +0 -0
- {openpinch-0.7.1 → openpinch-0.7.2}/OpenPinch/analysis/heat_exchanger_networks/models/__init__.py +0 -0
- {openpinch-0.7.1 → openpinch-0.7.2}/OpenPinch/analysis/heat_exchanger_networks/models/_base/__init__.py +0 -0
- {openpinch-0.7.1 → openpinch-0.7.2}/OpenPinch/analysis/heat_exchanger_networks/models/_base/execution.py +0 -0
- {openpinch-0.7.1 → openpinch-0.7.2}/OpenPinch/analysis/heat_exchanger_networks/models/_pinch_design/__init__.py +0 -0
- {openpinch-0.7.1 → openpinch-0.7.2}/OpenPinch/analysis/heat_exchanger_networks/models/_stagewise/__init__.py +0 -0
- {openpinch-0.7.1 → openpinch-0.7.2}/OpenPinch/analysis/heat_exchanger_networks/models/fixed_structure.py +0 -0
- {openpinch-0.7.1 → openpinch-0.7.2}/OpenPinch/analysis/heat_exchanger_networks/models/packed_pinch_design.py +0 -0
- {openpinch-0.7.1 → openpinch-0.7.2}/OpenPinch/analysis/heat_exchanger_networks/models/packed_stagewise.py +0 -0
- {openpinch-0.7.1 → openpinch-0.7.2}/OpenPinch/analysis/heat_exchanger_networks/models/pinch_decomposition.py +0 -0
- {openpinch-0.7.1 → openpinch-0.7.2}/OpenPinch/analysis/heat_exchanger_networks/models/stage_packing.py +0 -0
- {openpinch-0.7.1 → openpinch-0.7.2}/OpenPinch/analysis/heat_exchanger_networks/models/stagewise.py +0 -0
- {openpinch-0.7.1 → openpinch-0.7.2}/OpenPinch/analysis/heat_exchanger_networks/models/thermal_profiles.py +0 -0
- {openpinch-0.7.1 → openpinch-0.7.2}/OpenPinch/analysis/heat_exchanger_networks/prepared_problem.py +0 -0
- {openpinch-0.7.1 → openpinch-0.7.2}/OpenPinch/analysis/heat_exchanger_networks/reporting/__init__.py +0 -0
- {openpinch-0.7.1 → openpinch-0.7.2}/OpenPinch/analysis/heat_exchanger_networks/reporting/exports.py +0 -0
- {openpinch-0.7.1 → openpinch-0.7.2}/OpenPinch/analysis/heat_exchanger_networks/results/__init__.py +0 -0
- {openpinch-0.7.1 → openpinch-0.7.2}/OpenPinch/analysis/heat_exchanger_networks/results/seeds.py +0 -0
- {openpinch-0.7.1 → openpinch-0.7.2}/OpenPinch/analysis/heat_exchanger_networks/results/selection.py +0 -0
- {openpinch-0.7.1 → openpinch-0.7.2}/OpenPinch/analysis/heat_exchanger_networks/service.py +0 -0
- {openpinch-0.7.1 → openpinch-0.7.2}/OpenPinch/analysis/heat_exchanger_networks/solver/__init__.py +0 -0
- {openpinch-0.7.1 → openpinch-0.7.2}/OpenPinch/analysis/heat_exchanger_networks/solver/dependencies.py +0 -0
- {openpinch-0.7.1 → openpinch-0.7.2}/OpenPinch/analysis/heat_exchanger_networks/solver/pinch_design_decomposition.py +0 -0
- {openpinch-0.7.1 → openpinch-0.7.2}/OpenPinch/analysis/heat_exchanger_networks/targeting/__init__.py +0 -0
- {openpinch-0.7.1 → openpinch-0.7.2}/OpenPinch/analysis/heat_exchanger_networks/targeting/_stage.py +0 -0
- {openpinch-0.7.1 → openpinch-0.7.2}/OpenPinch/analysis/heat_exchanger_networks/targeting/network_evolution_method.py +0 -0
- {openpinch-0.7.1 → openpinch-0.7.2}/OpenPinch/analysis/heat_exchanger_networks/targeting/open_hens_method.py +0 -0
- {openpinch-0.7.1 → openpinch-0.7.2}/OpenPinch/analysis/heat_exchanger_networks/targeting/thermal_derivative_method.py +0 -0
- {openpinch-0.7.1 → openpinch-0.7.2}/OpenPinch/analysis/heat_exchanger_networks/targeting/topology.py +0 -0
- {openpinch-0.7.1 → openpinch-0.7.2}/OpenPinch/analysis/heat_pumps/__init__.py +0 -0
- {openpinch-0.7.1 → openpinch-0.7.2}/OpenPinch/analysis/heat_pumps/_multiperiod/__init__.py +0 -0
- {openpinch-0.7.1 → openpinch-0.7.2}/OpenPinch/analysis/heat_pumps/_multiperiod/aggregation.py +0 -0
- {openpinch-0.7.1 → openpinch-0.7.2}/OpenPinch/analysis/heat_pumps/_multiperiod/execution.py +0 -0
- {openpinch-0.7.1 → openpinch-0.7.2}/OpenPinch/analysis/heat_pumps/_multiperiod/preparation.py +0 -0
- {openpinch-0.7.1 → openpinch-0.7.2}/OpenPinch/analysis/heat_pumps/_multiperiod/setup.py +0 -0
- {openpinch-0.7.1 → openpinch-0.7.2}/OpenPinch/analysis/heat_pumps/_multiperiod/state.py +0 -0
- {openpinch-0.7.1 → openpinch-0.7.2}/OpenPinch/analysis/heat_pumps/_process_mvr/__init__.py +0 -0
- {openpinch-0.7.1 → openpinch-0.7.2}/OpenPinch/analysis/heat_pumps/_process_mvr/membership.py +0 -0
- {openpinch-0.7.1 → openpinch-0.7.2}/OpenPinch/analysis/heat_pumps/_process_mvr/replacement_streams.py +0 -0
- {openpinch-0.7.1 → openpinch-0.7.2}/OpenPinch/analysis/heat_pumps/_process_mvr/selection.py +0 -0
- {openpinch-0.7.1 → openpinch-0.7.2}/OpenPinch/analysis/heat_pumps/_process_mvr/state.py +0 -0
- {openpinch-0.7.1 → openpinch-0.7.2}/OpenPinch/analysis/heat_pumps/_process_mvr/values.py +0 -0
- {openpinch-0.7.1 → openpinch-0.7.2}/OpenPinch/analysis/heat_pumps/_process_mvr/work.py +0 -0
- {openpinch-0.7.1 → openpinch-0.7.2}/OpenPinch/analysis/heat_pumps/common/__init__.py +0 -0
- {openpinch-0.7.1 → openpinch-0.7.2}/OpenPinch/analysis/heat_pumps/common/_shared/__init__.py +0 -0
- {openpinch-0.7.1 → openpinch-0.7.2}/OpenPinch/analysis/heat_pumps/common/_shared/air.py +0 -0
- {openpinch-0.7.1 → openpinch-0.7.2}/OpenPinch/analysis/heat_pumps/common/_shared/plotting.py +0 -0
- {openpinch-0.7.1 → openpinch-0.7.2}/OpenPinch/analysis/heat_pumps/common/_shared/streams.py +0 -0
- {openpinch-0.7.1 → openpinch-0.7.2}/OpenPinch/analysis/heat_pumps/common/encoding.py +0 -0
- {openpinch-0.7.1 → openpinch-0.7.2}/OpenPinch/analysis/heat_pumps/common/layout.py +0 -0
- {openpinch-0.7.1 → openpinch-0.7.2}/OpenPinch/analysis/heat_pumps/common/load_selection.py +0 -0
- {openpinch-0.7.1 → openpinch-0.7.2}/OpenPinch/analysis/heat_pumps/common/multi_vc_objective.py +0 -0
- {openpinch-0.7.1 → openpinch-0.7.2}/OpenPinch/analysis/heat_pumps/common/postprocessing.py +0 -0
- {openpinch-0.7.1 → openpinch-0.7.2}/OpenPinch/analysis/heat_pumps/common/preprocessing.py +0 -0
- {openpinch-0.7.1 → openpinch-0.7.2}/OpenPinch/analysis/heat_pumps/common/units.py +0 -0
- {openpinch-0.7.1 → openpinch-0.7.2}/OpenPinch/analysis/heat_pumps/components.py +0 -0
- {openpinch-0.7.1 → openpinch-0.7.2}/OpenPinch/analysis/heat_pumps/cycles/__init__.py +0 -0
- {openpinch-0.7.1 → openpinch-0.7.2}/OpenPinch/analysis/heat_pumps/cycles/_multi_cycle_base.py +0 -0
- {openpinch-0.7.1 → openpinch-0.7.2}/OpenPinch/analysis/heat_pumps/cycles/brayton_heat_pump.py +0 -0
- {openpinch-0.7.1 → openpinch-0.7.2}/OpenPinch/analysis/heat_pumps/cycles/mechanical_vapour_recompression_cycle.py +0 -0
- {openpinch-0.7.1 → openpinch-0.7.2}/OpenPinch/analysis/heat_pumps/cycles/parallel_vapour_compression_cycles.py +0 -0
- {openpinch-0.7.1 → openpinch-0.7.2}/OpenPinch/analysis/heat_pumps/cycles/vapour_compression_mvr_cascade.py +0 -0
- {openpinch-0.7.1 → openpinch-0.7.2}/OpenPinch/analysis/heat_pumps/direct_mvr/__init__.py +0 -0
- {openpinch-0.7.1 → openpinch-0.7.2}/OpenPinch/analysis/heat_pumps/direct_mvr/execution.py +0 -0
- {openpinch-0.7.1 → openpinch-0.7.2}/OpenPinch/analysis/heat_pumps/direct_mvr/models.py +0 -0
- {openpinch-0.7.1 → openpinch-0.7.2}/OpenPinch/analysis/heat_pumps/direct_mvr/thermodynamics.py +0 -0
- {openpinch-0.7.1 → openpinch-0.7.2}/OpenPinch/analysis/heat_pumps/direct_mvr/units.py +0 -0
- {openpinch-0.7.1 → openpinch-0.7.2}/OpenPinch/analysis/heat_pumps/optimisation_adapter.py +0 -0
- {openpinch-0.7.1 → openpinch-0.7.2}/OpenPinch/analysis/heat_pumps/performance_maps/__init__.py +0 -0
- {openpinch-0.7.1 → openpinch-0.7.2}/OpenPinch/analysis/heat_pumps/performance_maps/adapters/__init__.py +0 -0
- {openpinch-0.7.1 → openpinch-0.7.2}/OpenPinch/analysis/heat_pumps/performance_maps/adapters/coolprop.py +0 -0
- {openpinch-0.7.1 → openpinch-0.7.2}/OpenPinch/analysis/heat_pumps/performance_maps/adapters/tespy.py +0 -0
- {openpinch-0.7.1 → openpinch-0.7.2}/OpenPinch/analysis/heat_pumps/performance_maps/characteristics/__init__.py +0 -0
- {openpinch-0.7.1 → openpinch-0.7.2}/OpenPinch/analysis/heat_pumps/performance_maps/characteristics/openpinch-single-stage-compressor-v1.json +0 -0
- {openpinch-0.7.1 → openpinch-0.7.2}/OpenPinch/analysis/heat_pumps/performance_maps/context.py +0 -0
- {openpinch-0.7.1 → openpinch-0.7.2}/OpenPinch/analysis/heat_pumps/performance_maps/coolprop_preflight.py +0 -0
- {openpinch-0.7.1 → openpinch-0.7.2}/OpenPinch/analysis/heat_pumps/performance_maps/errors.py +0 -0
- {openpinch-0.7.1 → openpinch-0.7.2}/OpenPinch/analysis/heat_pumps/performance_maps/factory.py +0 -0
- {openpinch-0.7.1 → openpinch-0.7.2}/OpenPinch/analysis/heat_pumps/performance_maps/fluids.py +0 -0
- {openpinch-0.7.1 → openpinch-0.7.2}/OpenPinch/analysis/heat_pumps/performance_maps/generation.py +0 -0
- {openpinch-0.7.1 → openpinch-0.7.2}/OpenPinch/analysis/heat_pumps/performance_maps/models.py +0 -0
- {openpinch-0.7.1 → openpinch-0.7.2}/OpenPinch/analysis/heat_pumps/performance_maps/points.py +0 -0
- {openpinch-0.7.1 → openpinch-0.7.2}/OpenPinch/analysis/heat_pumps/performance_maps/protocols.py +0 -0
- {openpinch-0.7.1 → openpinch-0.7.2}/OpenPinch/analysis/heat_pumps/performance_maps/provenance.py +0 -0
- {openpinch-0.7.1 → openpinch-0.7.2}/OpenPinch/analysis/heat_pumps/performance_maps/resources.py +0 -0
- {openpinch-0.7.1 → openpinch-0.7.2}/OpenPinch/analysis/heat_pumps/performance_maps/settings.py +0 -0
- {openpinch-0.7.1 → openpinch-0.7.2}/OpenPinch/analysis/heat_pumps/performance_maps/target_basis.py +0 -0
- {openpinch-0.7.1 → openpinch-0.7.2}/OpenPinch/analysis/heat_pumps/performance_maps/target_records.py +0 -0
- {openpinch-0.7.1 → openpinch-0.7.2}/OpenPinch/analysis/heat_pumps/performance_maps/targeting.py +0 -0
- {openpinch-0.7.1 → openpinch-0.7.2}/OpenPinch/analysis/heat_pumps/performance_maps/targeting_models.py +0 -0
- {openpinch-0.7.1 → openpinch-0.7.2}/OpenPinch/analysis/heat_pumps/process_mvr.py +0 -0
- {openpinch-0.7.1 → openpinch-0.7.2}/OpenPinch/analysis/heat_pumps/service.py +0 -0
- {openpinch-0.7.1 → openpinch-0.7.2}/OpenPinch/analysis/heat_pumps/targeting/__init__.py +0 -0
- {openpinch-0.7.1 → openpinch-0.7.2}/OpenPinch/analysis/heat_pumps/targeting/brayton.py +0 -0
- {openpinch-0.7.1 → openpinch-0.7.2}/OpenPinch/analysis/heat_pumps/targeting/cascade_carnot.py +0 -0
- {openpinch-0.7.1 → openpinch-0.7.2}/OpenPinch/analysis/heat_pumps/targeting/cascade_vapour_compression.py +0 -0
- {openpinch-0.7.1 → openpinch-0.7.2}/OpenPinch/analysis/heat_pumps/targeting/parallel_carnot.py +0 -0
- {openpinch-0.7.1 → openpinch-0.7.2}/OpenPinch/analysis/heat_pumps/targeting/parallel_vapour_compression.py +0 -0
- {openpinch-0.7.1 → openpinch-0.7.2}/OpenPinch/analysis/heat_pumps/targeting/vapour_compression_mvr.py +0 -0
- {openpinch-0.7.1 → openpinch-0.7.2}/OpenPinch/analysis/heat_transfer.py +0 -0
- {openpinch-0.7.1 → openpinch-0.7.2}/OpenPinch/analysis/numerics.py +0 -0
- {openpinch-0.7.1 → openpinch-0.7.2}/OpenPinch/analysis/orc/__init__.py +0 -0
- {openpinch-0.7.1 → openpinch-0.7.2}/OpenPinch/analysis/orc/carnot.py +0 -0
- {openpinch-0.7.1 → openpinch-0.7.2}/OpenPinch/analysis/orc/costing.py +0 -0
- {openpinch-0.7.1 → openpinch-0.7.2}/OpenPinch/analysis/orc/cycle.py +0 -0
- {openpinch-0.7.1 → openpinch-0.7.2}/OpenPinch/analysis/orc/inputs.py +0 -0
- {openpinch-0.7.1 → openpinch-0.7.2}/OpenPinch/analysis/orc/profile.py +0 -0
- {openpinch-0.7.1 → openpinch-0.7.2}/OpenPinch/analysis/orc/search.py +0 -0
- {openpinch-0.7.1 → openpinch-0.7.2}/OpenPinch/analysis/orc/service.py +0 -0
- {openpinch-0.7.1 → openpinch-0.7.2}/OpenPinch/analysis/orc/simulated.py +0 -0
- {openpinch-0.7.1 → openpinch-0.7.2}/OpenPinch/analysis/parallelism.py +0 -0
- {openpinch-0.7.1 → openpinch-0.7.2}/OpenPinch/analysis/power/__init__.py +0 -0
- {openpinch-0.7.1 → openpinch-0.7.2}/OpenPinch/analysis/power/service.py +0 -0
- {openpinch-0.7.1 → openpinch-0.7.2}/OpenPinch/analysis/power/steam_turbine.py +0 -0
- {openpinch-0.7.1 → openpinch-0.7.2}/OpenPinch/analysis/targeting/__init__.py +0 -0
- {openpinch-0.7.1 → openpinch-0.7.2}/OpenPinch/analysis/targeting/cascade.py +0 -0
- {openpinch-0.7.1 → openpinch-0.7.2}/OpenPinch/analysis/targeting/context.py +0 -0
- {openpinch-0.7.1 → openpinch-0.7.2}/OpenPinch/analysis/targeting/heat_recovery_dt_min.py +0 -0
- {openpinch-0.7.1 → openpinch-0.7.2}/OpenPinch/analysis/targeting/residual.py +0 -0
- {openpinch-0.7.1 → openpinch-0.7.2}/OpenPinch/analysis/thermodynamics/__init__.py +0 -0
- {openpinch-0.7.1 → openpinch-0.7.2}/OpenPinch/analysis/thermodynamics/water.py +0 -0
- {openpinch-0.7.1 → openpinch-0.7.2}/OpenPinch/analysis/utility_placement/__init__.py +0 -0
- {openpinch-0.7.1 → openpinch-0.7.2}/OpenPinch/analysis/utility_placement/allocation.py +0 -0
- {openpinch-0.7.1 → openpinch-0.7.2}/OpenPinch/analysis/utility_placement/codec.py +0 -0
- {openpinch-0.7.1 → openpinch-0.7.2}/OpenPinch/analysis/utility_placement/context.py +0 -0
- {openpinch-0.7.1 → openpinch-0.7.2}/OpenPinch/analysis/utility_placement/errors.py +0 -0
- {openpinch-0.7.1 → openpinch-0.7.2}/OpenPinch/analysis/utility_placement/evaluation.py +0 -0
- {openpinch-0.7.1 → openpinch-0.7.2}/OpenPinch/analysis/utility_placement/normalization.py +0 -0
- {openpinch-0.7.1 → openpinch-0.7.2}/OpenPinch/analysis/utility_placement/optimisation.py +0 -0
- {openpinch-0.7.1 → openpinch-0.7.2}/OpenPinch/analysis/utility_placement/penalties.py +0 -0
- {openpinch-0.7.1 → openpinch-0.7.2}/OpenPinch/analysis/utility_placement/profiles.py +0 -0
- {openpinch-0.7.1 → openpinch-0.7.2}/OpenPinch/analysis/utility_placement/replay.py +0 -0
- {openpinch-0.7.1 → openpinch-0.7.2}/OpenPinch/analysis/utility_placement/service.py +0 -0
- {openpinch-0.7.1 → openpinch-0.7.2}/OpenPinch/analysis/utility_placement/start_points.py +0 -0
- {openpinch-0.7.1 → openpinch-0.7.2}/OpenPinch/analysis/utility_placement/units.py +0 -0
- {openpinch-0.7.1 → openpinch-0.7.2}/OpenPinch/application/__init__.py +0 -0
- {openpinch-0.7.1 → openpinch-0.7.2}/OpenPinch/application/_problem/__init__.py +0 -0
- {openpinch-0.7.1 → openpinch-0.7.2}/OpenPinch/application/_problem/accessors/__init__.py +0 -0
- {openpinch-0.7.1 → openpinch-0.7.2}/OpenPinch/application/_problem/accessors/component.py +0 -0
- {openpinch-0.7.1 → openpinch-0.7.2}/OpenPinch/application/_problem/accessors/plot.py +0 -0
- {openpinch-0.7.1 → openpinch-0.7.2}/OpenPinch/application/_problem/accessors/target.py +0 -0
- {openpinch-0.7.1 → openpinch-0.7.2}/OpenPinch/application/_problem/arguments.py +0 -0
- {openpinch-0.7.1 → openpinch-0.7.2}/OpenPinch/application/_problem/input/__init__.py +0 -0
- {openpinch-0.7.1 → openpinch-0.7.2}/OpenPinch/application/_problem/input/canonicalization.py +0 -0
- {openpinch-0.7.1 → openpinch-0.7.2}/OpenPinch/application/_problem/input/loading.py +0 -0
- {openpinch-0.7.1 → openpinch-0.7.2}/OpenPinch/application/_problem/input/segments.py +0 -0
- {openpinch-0.7.1 → openpinch-0.7.2}/OpenPinch/application/_problem/input/utilities.py +0 -0
- {openpinch-0.7.1 → openpinch-0.7.2}/OpenPinch/application/_problem/input/validation.py +0 -0
- {openpinch-0.7.1 → openpinch-0.7.2}/OpenPinch/application/_problem/output/__init__.py +0 -0
- {openpinch-0.7.1 → openpinch-0.7.2}/OpenPinch/application/_problem/output/result_extraction.py +0 -0
- {openpinch-0.7.1 → openpinch-0.7.2}/OpenPinch/application/_problem/periods/__init__.py +0 -0
- {openpinch-0.7.1 → openpinch-0.7.2}/OpenPinch/application/_problem/targeting/__init__.py +0 -0
- {openpinch-0.7.1 → openpinch-0.7.2}/OpenPinch/application/_problem/targeting/catalog.py +0 -0
- {openpinch-0.7.1 → openpinch-0.7.2}/OpenPinch/application/_problem/targeting/dispatch.py +0 -0
- {openpinch-0.7.1 → openpinch-0.7.2}/OpenPinch/application/_problem/targeting/execution.py +0 -0
- {openpinch-0.7.1 → openpinch-0.7.2}/OpenPinch/application/_problem/targeting/provenance.py +0 -0
- {openpinch-0.7.1 → openpinch-0.7.2}/OpenPinch/application/_workspace/__init__.py +0 -0
- {openpinch-0.7.1 → openpinch-0.7.2}/OpenPinch/application/_workspace/case_inputs.py +0 -0
- {openpinch-0.7.1 → openpinch-0.7.2}/OpenPinch/application/_workspace/state.py +0 -0
- {openpinch-0.7.1 → openpinch-0.7.2}/OpenPinch/application/case_derivation.py +0 -0
- {openpinch-0.7.1 → openpinch-0.7.2}/OpenPinch/application/heat_recovery_dt_min.py +0 -0
- {openpinch-0.7.1 → openpinch-0.7.2}/OpenPinch/application/hpr_selection.py +0 -0
- {openpinch-0.7.1 → openpinch-0.7.2}/OpenPinch/application/residual_utility.py +0 -0
- {openpinch-0.7.1 → openpinch-0.7.2}/OpenPinch/application/targeting.py +0 -0
- {openpinch-0.7.1 → openpinch-0.7.2}/OpenPinch/application/workspace.py +0 -0
- {openpinch-0.7.1 → openpinch-0.7.2}/OpenPinch/contracts/__init__.py +0 -0
- {openpinch-0.7.1 → openpinch-0.7.2}/OpenPinch/contracts/common.py +0 -0
- {openpinch-0.7.1 → openpinch-0.7.2}/OpenPinch/contracts/controllability.py +0 -0
- {openpinch-0.7.1 → openpinch-0.7.2}/OpenPinch/contracts/graphs.py +0 -0
- {openpinch-0.7.1 → openpinch-0.7.2}/OpenPinch/contracts/heat_recovery_dt_min.py +0 -0
- {openpinch-0.7.1 → openpinch-0.7.2}/OpenPinch/contracts/hpr.py +0 -0
- {openpinch-0.7.1 → openpinch-0.7.2}/OpenPinch/contracts/hpr_performance_map.py +0 -0
- {openpinch-0.7.1 → openpinch-0.7.2}/OpenPinch/contracts/output.py +0 -0
- {openpinch-0.7.1 → openpinch-0.7.2}/OpenPinch/contracts/report_metrics.py +0 -0
- {openpinch-0.7.1 → openpinch-0.7.2}/OpenPinch/contracts/report_units.py +0 -0
- {openpinch-0.7.1 → openpinch-0.7.2}/OpenPinch/contracts/resources/__init__.py +0 -0
- {openpinch-0.7.1 → openpinch-0.7.2}/OpenPinch/contracts/resources/hpr_performance_map/__init__.py +0 -0
- {openpinch-0.7.1 → openpinch-0.7.2}/OpenPinch/contracts/resources/hpr_performance_map/heat-pump-1.0.json +0 -0
- {openpinch-0.7.1 → openpinch-0.7.2}/OpenPinch/contracts/resources/hpr_performance_map/refrigeration-1.0.json +0 -0
- {openpinch-0.7.1 → openpinch-0.7.2}/OpenPinch/contracts/resources/hpr_performance_map/schema-1.0.json +0 -0
- {openpinch-0.7.1 → openpinch-0.7.2}/OpenPinch/contracts/schema.py +0 -0
- {openpinch-0.7.1 → openpinch-0.7.2}/OpenPinch/contracts/synthesis/__init__.py +0 -0
- {openpinch-0.7.1 → openpinch-0.7.2}/OpenPinch/contracts/synthesis/common.py +0 -0
- {openpinch-0.7.1 → openpinch-0.7.2}/OpenPinch/contracts/synthesis/method.py +0 -0
- {openpinch-0.7.1 → openpinch-0.7.2}/OpenPinch/contracts/synthesis/result.py +0 -0
- {openpinch-0.7.1 → openpinch-0.7.2}/OpenPinch/contracts/synthesis/task.py +0 -0
- {openpinch-0.7.1 → openpinch-0.7.2}/OpenPinch/contracts/synthesis/topology.py +0 -0
- {openpinch-0.7.1 → openpinch-0.7.2}/OpenPinch/contracts/synthesis/view.py +0 -0
- {openpinch-0.7.1 → openpinch-0.7.2}/OpenPinch/contracts/turbine.py +0 -0
- {openpinch-0.7.1 → openpinch-0.7.2}/OpenPinch/domain/__init__.py +0 -0
- {openpinch-0.7.1 → openpinch-0.7.2}/OpenPinch/domain/_heat_exchanger/__init__.py +0 -0
- {openpinch-0.7.1 → openpinch-0.7.2}/OpenPinch/domain/_heat_exchanger/area.py +0 -0
- {openpinch-0.7.1 → openpinch-0.7.2}/OpenPinch/domain/_heat_exchanger/period_state.py +0 -0
- {openpinch-0.7.1 → openpinch-0.7.2}/OpenPinch/domain/_heat_exchanger/rules.py +0 -0
- {openpinch-0.7.1 → openpinch-0.7.2}/OpenPinch/domain/_heat_exchanger_network/__init__.py +0 -0
- {openpinch-0.7.1 → openpinch-0.7.2}/OpenPinch/domain/_heat_exchanger_network/types.py +0 -0
- {openpinch-0.7.1 → openpinch-0.7.2}/OpenPinch/domain/_problem_table/__init__.py +0 -0
- {openpinch-0.7.1 → openpinch-0.7.2}/OpenPinch/domain/_problem_table/constants.py +0 -0
- {openpinch-0.7.1 → openpinch-0.7.2}/OpenPinch/domain/_problem_table/equality.py +0 -0
- {openpinch-0.7.1 → openpinch-0.7.2}/OpenPinch/domain/_problem_table/types.py +0 -0
- {openpinch-0.7.1 → openpinch-0.7.2}/OpenPinch/domain/_stream/__init__.py +0 -0
- {openpinch-0.7.1 → openpinch-0.7.2}/OpenPinch/domain/_stream/profile.py +0 -0
- {openpinch-0.7.1 → openpinch-0.7.2}/OpenPinch/domain/_stream/segments.py +0 -0
- {openpinch-0.7.1 → openpinch-0.7.2}/OpenPinch/domain/_stream/thermodynamics.py +0 -0
- {openpinch-0.7.1 → openpinch-0.7.2}/OpenPinch/domain/_stream_collection/__init__.py +0 -0
- {openpinch-0.7.1 → openpinch-0.7.2}/OpenPinch/domain/_stream_collection/filters.py +0 -0
- {openpinch-0.7.1 → openpinch-0.7.2}/OpenPinch/domain/_stream_collection/numeric_view.py +0 -0
- {openpinch-0.7.1 → openpinch-0.7.2}/OpenPinch/domain/_stream_collection/serialization.py +0 -0
- {openpinch-0.7.1 → openpinch-0.7.2}/OpenPinch/domain/_stream_collection/sorting.py +0 -0
- {openpinch-0.7.1 → openpinch-0.7.2}/OpenPinch/domain/_validation.py +0 -0
- {openpinch-0.7.1 → openpinch-0.7.2}/OpenPinch/domain/_value/__init__.py +0 -0
- {openpinch-0.7.1 → openpinch-0.7.2}/OpenPinch/domain/_value/coercion.py +0 -0
- {openpinch-0.7.1 → openpinch-0.7.2}/OpenPinch/domain/_value/resolution.py +0 -0
- {openpinch-0.7.1 → openpinch-0.7.2}/OpenPinch/domain/analysis.py +0 -0
- {openpinch-0.7.1 → openpinch-0.7.2}/OpenPinch/domain/enums.py +0 -0
- {openpinch-0.7.1 → openpinch-0.7.2}/OpenPinch/domain/fluids.py +0 -0
- {openpinch-0.7.1 → openpinch-0.7.2}/OpenPinch/domain/heat_exchanger.py +0 -0
- {openpinch-0.7.1 → openpinch-0.7.2}/OpenPinch/domain/heat_exchanger_network.py +0 -0
- {openpinch-0.7.1 → openpinch-0.7.2}/OpenPinch/domain/hpr.py +0 -0
- {openpinch-0.7.1 → openpinch-0.7.2}/OpenPinch/domain/problem_table.py +0 -0
- {openpinch-0.7.1 → openpinch-0.7.2}/OpenPinch/domain/progress.py +0 -0
- {openpinch-0.7.1 → openpinch-0.7.2}/OpenPinch/domain/stream.py +0 -0
- {openpinch-0.7.1 → openpinch-0.7.2}/OpenPinch/domain/stream_collection.py +0 -0
- {openpinch-0.7.1 → openpinch-0.7.2}/OpenPinch/optimisation/__init__.py +0 -0
- {openpinch-0.7.1 → openpinch-0.7.2}/OpenPinch/optimisation/backends/__init__.py +0 -0
- {openpinch-0.7.1 → openpinch-0.7.2}/OpenPinch/optimisation/backends/_surrogate.py +0 -0
- {openpinch-0.7.1 → openpinch-0.7.2}/OpenPinch/optimisation/backends/protocol.py +0 -0
- {openpinch-0.7.1 → openpinch-0.7.2}/OpenPinch/optimisation/errors.py +0 -0
- {openpinch-0.7.1 → openpinch-0.7.2}/OpenPinch/presentation/__init__.py +0 -0
- {openpinch-0.7.1 → openpinch-0.7.2}/OpenPinch/presentation/dashboard/__init__.py +0 -0
- {openpinch-0.7.1 → openpinch-0.7.2}/OpenPinch/presentation/dashboard/dashboard.css +0 -0
- {openpinch-0.7.1 → openpinch-0.7.2}/OpenPinch/presentation/dashboard/dependencies.py +0 -0
- {openpinch-0.7.1 → openpinch-0.7.2}/OpenPinch/presentation/dashboard/rendering.py +0 -0
- {openpinch-0.7.1 → openpinch-0.7.2}/OpenPinch/presentation/dashboard/state.py +0 -0
- {openpinch-0.7.1 → openpinch-0.7.2}/OpenPinch/presentation/graphs/__init__.py +0 -0
- {openpinch-0.7.1 → openpinch-0.7.2}/OpenPinch/presentation/graphs/plotly.py +0 -0
- {openpinch-0.7.1 → openpinch-0.7.2}/OpenPinch/presentation/graphs/problem.py +0 -0
- {openpinch-0.7.1 → openpinch-0.7.2}/OpenPinch/presentation/graphs/simple.py +0 -0
- {openpinch-0.7.1 → openpinch-0.7.2}/OpenPinch/presentation/network_grid/__init__.py +0 -0
- {openpinch-0.7.1 → openpinch-0.7.2}/OpenPinch/presentation/network_grid/_constants.py +0 -0
- {openpinch-0.7.1 → openpinch-0.7.2}/OpenPinch/presentation/network_grid/dependencies.py +0 -0
- {openpinch-0.7.1 → openpinch-0.7.2}/OpenPinch/presentation/network_grid/geometry.py +0 -0
- {openpinch-0.7.1 → openpinch-0.7.2}/OpenPinch/presentation/network_grid/labels.py +0 -0
- {openpinch-0.7.1 → openpinch-0.7.2}/OpenPinch/presentation/network_grid/layout.py +0 -0
- {openpinch-0.7.1 → openpinch-0.7.2}/OpenPinch/presentation/network_grid/plotly.py +0 -0
- {openpinch-0.7.1 → openpinch-0.7.2}/OpenPinch/presentation/network_grid/rendering.py +0 -0
- {openpinch-0.7.1 → openpinch-0.7.2}/OpenPinch/presentation/network_grid/results.py +0 -0
- {openpinch-0.7.1 → openpinch-0.7.2}/OpenPinch/presentation/network_grid/service.py +0 -0
- {openpinch-0.7.1 → openpinch-0.7.2}/OpenPinch/presentation/network_grid/state.py +0 -0
- {openpinch-0.7.1 → openpinch-0.7.2}/OpenPinch/presentation/network_grid/temperatures.py +0 -0
- {openpinch-0.7.1 → openpinch-0.7.2}/OpenPinch/presentation/network_grid/view.py +0 -0
- {openpinch-0.7.1 → openpinch-0.7.2}/OpenPinch/presentation/reporting/__init__.py +0 -0
- {openpinch-0.7.1 → openpinch-0.7.2}/OpenPinch/presentation/reporting/adapters.py +0 -0
- {openpinch-0.7.1 → openpinch-0.7.2}/OpenPinch/presentation/reporting/hpr.py +0 -0
- {openpinch-0.7.1 → openpinch-0.7.2}/OpenPinch/presentation/reporting/results.py +0 -0
- {openpinch-0.7.1 → openpinch-0.7.2}/OpenPinch/presentation/reporting/specialist.py +0 -0
- {openpinch-0.7.1 → openpinch-0.7.2}/OpenPinch/presentation/reporting/stream_collection.py +0 -0
- {openpinch-0.7.1 → openpinch-0.7.2}/OpenPinch/resources.py +0 -0
- {openpinch-0.7.1 → openpinch-0.7.2}/OpenPinch/tutorials/__init__.py +0 -0
- {openpinch-0.7.1 → openpinch-0.7.2}/OpenPinch/tutorials/notebooks/01_first_solve_and_core_curves.ipynb +0 -0
- {openpinch-0.7.1 → openpinch-0.7.2}/OpenPinch/tutorials/notebooks/02_focused_direct_and_total_site.ipynb +0 -0
- {openpinch-0.7.1 → openpinch-0.7.2}/OpenPinch/tutorials/notebooks/03_multisegment_streams.ipynb +0 -0
- {openpinch-0.7.1 → openpinch-0.7.2}/OpenPinch/tutorials/notebooks/04_workspace_cases_and_scenarios.ipynb +0 -0
- {openpinch-0.7.1 → openpinch-0.7.2}/OpenPinch/tutorials/notebooks/05_workspace_persistence.ipynb +0 -0
- {openpinch-0.7.1 → openpinch-0.7.2}/OpenPinch/tutorials/notebooks/06_multiperiod_heat_integration.ipynb +0 -0
- {openpinch-0.7.1 → openpinch-0.7.2}/OpenPinch/tutorials/notebooks/07_area_cost_and_exergy.ipynb +0 -0
- {openpinch-0.7.1 → openpinch-0.7.2}/OpenPinch/tutorials/notebooks/08_carnot_heat_pump_and_refrigeration.ipynb +0 -0
- {openpinch-0.7.1 → openpinch-0.7.2}/OpenPinch/tutorials/notebooks/09_vapour_compression.ipynb +0 -0
- {openpinch-0.7.1 → openpinch-0.7.2}/OpenPinch/tutorials/notebooks/10_multiperiod_heat_pumps.ipynb +0 -0
- {openpinch-0.7.1 → openpinch-0.7.2}/OpenPinch/tutorials/notebooks/11_process_mvr_and_cascade.ipynb +0 -0
- {openpinch-0.7.1 → openpinch-0.7.2}/OpenPinch/tutorials/notebooks/12_cogeneration.ipynb +0 -0
- {openpinch-0.7.1 → openpinch-0.7.2}/OpenPinch/tutorials/notebooks/13_multiperiod_cogeneration.ipynb +0 -0
- {openpinch-0.7.1 → openpinch-0.7.2}/OpenPinch/tutorials/notebooks/14_energy_transfer.ipynb +0 -0
- {openpinch-0.7.1 → openpinch-0.7.2}/OpenPinch/tutorials/notebooks/15_hen_synthesis_and_selection.ipynb +0 -0
- {openpinch-0.7.1 → openpinch-0.7.2}/OpenPinch/tutorials/notebooks/16_advanced_hen_methods.ipynb +0 -0
- {openpinch-0.7.1 → openpinch-0.7.2}/OpenPinch/tutorials/notebooks/17_multiperiod_hen_synthesis.ipynb +0 -0
- {openpinch-0.7.1 → openpinch-0.7.2}/OpenPinch/tutorials/notebooks/18_results_plots_reports_exports.ipynb +0 -0
- {openpinch-0.7.1 → openpinch-0.7.2}/OpenPinch/tutorials/notebooks/19_utility_placement_optimisation.ipynb +0 -0
- {openpinch-0.7.1 → openpinch-0.7.2}/OpenPinch/tutorials/notebooks/__init__.py +0 -0
- {openpinch-0.7.1 → openpinch-0.7.2}/OpenPinch/tutorials/sample_cases/Four-stream-Yee-and-Grossmann-1990-1.json +0 -0
- {openpinch-0.7.1 → openpinch-0.7.2}/OpenPinch/tutorials/sample_cases/__init__.py +0 -0
- {openpinch-0.7.1 → openpinch-0.7.2}/OpenPinch/tutorials/sample_cases/basic_pinch.json +0 -0
- {openpinch-0.7.1 → openpinch-0.7.2}/OpenPinch/tutorials/sample_cases/chocolate_factory.json +0 -0
- {openpinch-0.7.1 → openpinch-0.7.2}/OpenPinch/tutorials/sample_cases/crude_preheat_train.json +0 -0
- {openpinch-0.7.1 → openpinch-0.7.2}/OpenPinch/tutorials/sample_cases/crude_preheat_train_multiperiod.json +0 -0
- {openpinch-0.7.1 → openpinch-0.7.2}/OpenPinch/tutorials/sample_cases/dairy_chilling_multiperiod.json +0 -0
- {openpinch-0.7.1 → openpinch-0.7.2}/OpenPinch/tutorials/sample_cases/process_mvr.json +0 -0
- {openpinch-0.7.1 → openpinch-0.7.2}/OpenPinch/tutorials/sample_cases/pulp_mill.json +0 -0
- {openpinch-0.7.1 → openpinch-0.7.2}/OpenPinch/tutorials/sample_cases/zonal_site.json +0 -0
- {openpinch-0.7.1 → openpinch-0.7.2}/OpenPinch/tutorials/sample_cases/zonal_site_multiperiod.json +0 -0
- {openpinch-0.7.1 → openpinch-0.7.2}/README.md +0 -0
|
@@ -13,11 +13,14 @@ from .records import (
|
|
|
13
13
|
validate_utility_data,
|
|
14
14
|
)
|
|
15
15
|
from .tabular import (
|
|
16
|
-
|
|
16
|
+
problem_frame_from_sheet as _problem_frame_from_sheet,
|
|
17
17
|
)
|
|
18
18
|
from .tabular import (
|
|
19
19
|
problem_records_from_frame as _write_problem_to_dict_and_list,
|
|
20
20
|
)
|
|
21
|
+
from .tabular import (
|
|
22
|
+
summary_frame_from_sheet as _summary_frame_from_sheet,
|
|
23
|
+
)
|
|
21
24
|
from .tabular import (
|
|
22
25
|
target_records_from_frame as _write_targets_to_dict_and_list,
|
|
23
26
|
)
|
|
@@ -121,18 +124,15 @@ def _parse_csv_with_units(
|
|
|
121
124
|
"(names, units, and data rows)."
|
|
122
125
|
)
|
|
123
126
|
|
|
124
|
-
|
|
125
|
-
df_full,
|
|
126
|
-
|
|
127
|
-
|
|
128
|
-
|
|
129
|
-
|
|
130
|
-
|
|
131
|
-
|
|
132
|
-
|
|
133
|
-
# Columns the table leaves out stay absent so the input contract applies
|
|
134
|
-
# its defaults; padding them with 0 forced dt_cont and htc to zero.
|
|
135
|
-
df_data.columns = col_names[: len(df_data.columns)]
|
|
127
|
+
if kind == "Summary":
|
|
128
|
+
df_data, units_map = _summary_frame_from_sheet(df_full, row_units, row_data)
|
|
129
|
+
else:
|
|
130
|
+
# Columns the table leaves out stay absent so the input contract
|
|
131
|
+
# applies its defaults; padding them with 0 forced dt_cont and htc to
|
|
132
|
+
# zero.
|
|
133
|
+
df_data, units_map = _problem_frame_from_sheet(
|
|
134
|
+
df_full, kind, row_units, row_data
|
|
135
|
+
)
|
|
136
136
|
|
|
137
137
|
def to_number_maybe(value):
|
|
138
138
|
if isinstance(value, str):
|
|
@@ -151,7 +151,6 @@ def _parse_csv_with_units(
|
|
|
151
151
|
text_columns = [name for name in ("zone", "name", "type") if name in df_data]
|
|
152
152
|
numeric_columns = [name for name in df_data.columns if name not in text_columns]
|
|
153
153
|
df_data[numeric_columns] = df_data[numeric_columns].map(to_number_maybe)
|
|
154
|
-
units_map = dict(zip(col_names, col_units))
|
|
155
154
|
if kind == "Summary":
|
|
156
155
|
return _write_targets_to_dict_and_list(df_data, units_map, project_name)
|
|
157
156
|
return _write_problem_to_dict_and_list(df_data, units_map)
|
|
@@ -53,6 +53,7 @@ def validate_stream_data(sd: pd.DataFrame):
|
|
|
53
53
|
append = cleaned.append
|
|
54
54
|
previous_zone = None
|
|
55
55
|
used_names = set()
|
|
56
|
+
original_names: dict[tuple, str] = {}
|
|
56
57
|
next_default_name_idx = 1
|
|
57
58
|
|
|
58
59
|
for record in records:
|
|
@@ -84,6 +85,15 @@ def validate_stream_data(sd: pd.DataFrame):
|
|
|
84
85
|
)
|
|
85
86
|
else:
|
|
86
87
|
record["name"] = _normalize_label(name, default_stream_prefix)
|
|
88
|
+
key = (record["zone"], record["name"])
|
|
89
|
+
original = _label_text(name)
|
|
90
|
+
earlier = original_names.setdefault(key, original)
|
|
91
|
+
if earlier != original:
|
|
92
|
+
raise ValueError(
|
|
93
|
+
f"Stream names {earlier!r} and {original!r} in zone "
|
|
94
|
+
f"{record['zone']!r} both become {record['name']!r}; "
|
|
95
|
+
"rename one of them."
|
|
96
|
+
)
|
|
87
97
|
|
|
88
98
|
used_names.add(record["name"])
|
|
89
99
|
append(record)
|
|
@@ -121,24 +131,51 @@ def validate_utility_data(ud: pd.DataFrame):
|
|
|
121
131
|
valid = ~name_series.isna()
|
|
122
132
|
if valid.any():
|
|
123
133
|
valid &= name_series.astype(str).str.strip() != ""
|
|
134
|
+
records = ud.replace({pd.NA: None}).to_dict(orient="records")
|
|
135
|
+
for row, record in enumerate(records, start=1):
|
|
136
|
+
if not valid.iloc[row - 1]:
|
|
137
|
+
_warn_unnamed_utility(row, record)
|
|
124
138
|
ud = ud.loc[valid].reset_index(drop=True)
|
|
125
139
|
return ud
|
|
126
140
|
|
|
127
141
|
cleaned = []
|
|
128
142
|
append = cleaned.append
|
|
129
|
-
for record in ud:
|
|
143
|
+
for row, record in enumerate(ud, start=1):
|
|
130
144
|
if not isinstance(record, dict):
|
|
131
145
|
continue
|
|
132
146
|
name = record.get("name")
|
|
133
|
-
if
|
|
134
|
-
|
|
135
|
-
|
|
147
|
+
if (
|
|
148
|
+
name is None
|
|
149
|
+
or pd.isna(name)
|
|
150
|
+
or (isinstance(name, str) and not name.strip())
|
|
151
|
+
):
|
|
152
|
+
_warn_unnamed_utility(row, record)
|
|
136
153
|
continue
|
|
137
154
|
record = {**record, "name": _label_text(name)}
|
|
138
155
|
append(record)
|
|
139
156
|
return cleaned
|
|
140
157
|
|
|
141
158
|
|
|
159
|
+
def _warn_unnamed_utility(row: int, record: dict) -> None:
|
|
160
|
+
"""Warn when a utility row dropped for having no name carries data."""
|
|
161
|
+
if any(_cell_has_data(value) for key, value in record.items() if key != "name"):
|
|
162
|
+
warnings.warn(
|
|
163
|
+
f"Utility data: utility row {row} has no name and was ignored.",
|
|
164
|
+
UserWarning,
|
|
165
|
+
stacklevel=4,
|
|
166
|
+
)
|
|
167
|
+
|
|
168
|
+
|
|
169
|
+
def _cell_has_data(value) -> bool:
|
|
170
|
+
if isinstance(value, dict):
|
|
171
|
+
value = value.get("value", value.get("values"))
|
|
172
|
+
if isinstance(value, str):
|
|
173
|
+
return bool(value.strip())
|
|
174
|
+
if isinstance(value, (list, tuple)):
|
|
175
|
+
return any(_cell_has_data(item) for item in value)
|
|
176
|
+
return value is not None and not pd.isna(value)
|
|
177
|
+
|
|
178
|
+
|
|
142
179
|
def _label_text(value) -> str:
|
|
143
180
|
"""Return a name as text; spreadsheets give numeric names as numbers."""
|
|
144
181
|
if isinstance(value, float) and value.is_integer():
|
|
@@ -2,8 +2,11 @@
|
|
|
2
2
|
|
|
3
3
|
from __future__ import annotations
|
|
4
4
|
|
|
5
|
+
import re
|
|
6
|
+
import warnings
|
|
5
7
|
from typing import Any, Optional
|
|
6
8
|
|
|
9
|
+
import numpy as np
|
|
7
10
|
import pandas as pd
|
|
8
11
|
|
|
9
12
|
from ...domain.enums import IntegrationType, TargetMethod, ZoneType
|
|
@@ -59,12 +62,126 @@ def get_column_names_and_units(df_full, sheet_name, row_units=1):
|
|
|
59
62
|
return col_names, col_units
|
|
60
63
|
|
|
61
64
|
|
|
65
|
+
# Header spellings accepted for each column, compared after lower-casing,
|
|
66
|
+
# reading a Greek delta as "d", dropping any bracketed unit and removing
|
|
67
|
+
# everything but letters and digits.
|
|
68
|
+
_HEADER_ALIASES = {
|
|
69
|
+
"Stream Data": {
|
|
70
|
+
"zone": ("process zone", "zone name"),
|
|
71
|
+
"name": ("stream", "stream name"),
|
|
72
|
+
"t_supply": ("ts", "tsupply", "supply temperature", "tin"),
|
|
73
|
+
"t_target": ("tt", "ttarget", "target temperature", "tout"),
|
|
74
|
+
"heat_flow": ("dh", "heat load", "duty", "q"),
|
|
75
|
+
"heat_capacity_flowrate": ("cp", "mcp", "fcp", "heat capacity flowrate"),
|
|
76
|
+
"dt_cont": ("dtcont", "dt contribution"),
|
|
77
|
+
"htc": ("heat transfer coefficient",),
|
|
78
|
+
},
|
|
79
|
+
"Utility Data": {
|
|
80
|
+
"name": ("utility", "utility name"),
|
|
81
|
+
"type": ("utility type",),
|
|
82
|
+
"t_supply": ("ts", "tsupply", "supply temperature", "tin"),
|
|
83
|
+
"t_target": ("tt", "ttarget", "target temperature", "tout"),
|
|
84
|
+
"dt_cont": ("dtcont", "dt contribution"),
|
|
85
|
+
"price": ("cost", "unit price"),
|
|
86
|
+
"htc": ("heat transfer coefficient",),
|
|
87
|
+
"heat_flow": ("dh", "heat load", "duty", "q"),
|
|
88
|
+
},
|
|
89
|
+
}
|
|
90
|
+
|
|
91
|
+
|
|
92
|
+
def _header_key(text: str) -> str:
|
|
93
|
+
key = re.sub(r"\(.*?\)|\[.*?\]", "", text).lower().replace("δ", "d")
|
|
94
|
+
return re.sub(r"[^a-z0-9]", "", key)
|
|
95
|
+
|
|
96
|
+
|
|
97
|
+
def _map_header_row(header: list, sheet_name: str) -> Optional[list]:
|
|
98
|
+
"""Return the field name for each column, or None when no header is known."""
|
|
99
|
+
aliases = {
|
|
100
|
+
_header_key(alias): field
|
|
101
|
+
for field, names in _HEADER_ALIASES[sheet_name].items()
|
|
102
|
+
for alias in (field, *names)
|
|
103
|
+
}
|
|
104
|
+
labels = [
|
|
105
|
+
cell.strip() if isinstance(cell, str) and cell.strip() else None
|
|
106
|
+
for cell in header
|
|
107
|
+
]
|
|
108
|
+
fields = [aliases.get(_header_key(label)) if label else None for label in labels]
|
|
109
|
+
if not any(fields):
|
|
110
|
+
return None
|
|
111
|
+
for field in set(filter(None, fields)):
|
|
112
|
+
columns = [label for label, f in zip(labels, fields) if f == field]
|
|
113
|
+
if len(columns) > 1:
|
|
114
|
+
raise ValueError(
|
|
115
|
+
f"{sheet_name} has more than one column for {field!r}: "
|
|
116
|
+
f"{', '.join(repr(column) for column in columns)}."
|
|
117
|
+
)
|
|
118
|
+
unknown = [label for label, f in zip(labels, fields) if label and not f]
|
|
119
|
+
if unknown:
|
|
120
|
+
warnings.warn(
|
|
121
|
+
f"{sheet_name} column(s) {', '.join(repr(u) for u in unknown)} "
|
|
122
|
+
"are not recognised and were ignored.",
|
|
123
|
+
UserWarning,
|
|
124
|
+
stacklevel=4,
|
|
125
|
+
)
|
|
126
|
+
return fields
|
|
127
|
+
|
|
128
|
+
|
|
129
|
+
def problem_frame_from_sheet(
|
|
130
|
+
df_full: pd.DataFrame,
|
|
131
|
+
sheet_name: str,
|
|
132
|
+
row_units: int,
|
|
133
|
+
row_data: int,
|
|
134
|
+
) -> tuple[pd.DataFrame, dict]:
|
|
135
|
+
"""Select a stream or utility table's columns and their units.
|
|
136
|
+
|
|
137
|
+
Columns are matched by the header text in the first row. A header with no
|
|
138
|
+
recognised column name falls back to the fixed column order.
|
|
139
|
+
"""
|
|
140
|
+
col_names, _ = get_column_names_and_units(df_full, sheet_name, row_units)
|
|
141
|
+
raw_units = [
|
|
142
|
+
unit.replace("°", "deg") if isinstance(unit, str) else None
|
|
143
|
+
for unit in df_full.iloc[row_units].tolist()
|
|
144
|
+
]
|
|
145
|
+
fields = _map_header_row(df_full.iloc[0].tolist(), sheet_name)
|
|
146
|
+
if fields is None:
|
|
147
|
+
warnings.warn(
|
|
148
|
+
f"{sheet_name} header row has no recognised column names; columns "
|
|
149
|
+
f"are read in the order {', '.join(col_names)}.",
|
|
150
|
+
UserWarning,
|
|
151
|
+
stacklevel=3,
|
|
152
|
+
)
|
|
153
|
+
count = min(len(df_full.columns), len(col_names))
|
|
154
|
+
fields = col_names[:count] + [None] * (len(df_full.columns) - count)
|
|
155
|
+
positions = [index for index, field in enumerate(fields) if field]
|
|
156
|
+
df_data = df_full.iloc[row_data:, positions].copy()
|
|
157
|
+
df_data.columns = [fields[index] for index in positions]
|
|
158
|
+
units_map = {fields[index]: raw_units[index] for index in positions}
|
|
159
|
+
return df_data, units_map
|
|
160
|
+
|
|
161
|
+
|
|
162
|
+
def summary_frame_from_sheet(
|
|
163
|
+
df_full: pd.DataFrame,
|
|
164
|
+
row_units: int,
|
|
165
|
+
row_data: int,
|
|
166
|
+
) -> tuple[pd.DataFrame, dict]:
|
|
167
|
+
"""Name a summary table's columns by position and collect their units."""
|
|
168
|
+
col_names, col_units = get_column_names_and_units(df_full, "Summary", row_units)
|
|
169
|
+
df_data = df_full.iloc[row_data:, : len(col_names)].copy()
|
|
170
|
+
df_data.columns = col_names[: len(df_data.columns)]
|
|
171
|
+
return df_data, dict(zip(col_names, col_units))
|
|
172
|
+
|
|
173
|
+
|
|
62
174
|
def problem_records_from_frame(df_data: pd.DataFrame, units_map: dict) -> list:
|
|
63
175
|
"""Convert stream/utility tables into JSON-ready row dictionaries with units."""
|
|
64
176
|
if df_data.empty:
|
|
65
177
|
return []
|
|
66
178
|
|
|
67
179
|
clean_df = df_data.replace({pd.NA: None}).reset_index(drop=True)
|
|
180
|
+
# Blank separator rows (empty or whitespace-only cells) carry no data; drop
|
|
181
|
+
# them before numeric cells are wrapped as {"value": None, ...} records.
|
|
182
|
+
clean_df = clean_df.loc[~clean_df.map(_is_blank_cell).all(axis=1)]
|
|
183
|
+
if clean_df.empty:
|
|
184
|
+
return []
|
|
68
185
|
records = clean_df.to_dict(orient="records")
|
|
69
186
|
|
|
70
187
|
for column_name, unit in units_map.items():
|
|
@@ -78,11 +195,14 @@ def problem_records_from_frame(df_data: pd.DataFrame, units_map: dict) -> list:
|
|
|
78
195
|
lambda value: isinstance(value, str) and not value.strip()
|
|
79
196
|
)
|
|
80
197
|
invalid = numeric_values.isna() & ~missing
|
|
198
|
+
invalid |= column_values.map(
|
|
199
|
+
lambda value: isinstance(value, (bool, np.bool_))
|
|
200
|
+
)
|
|
81
201
|
if invalid.any():
|
|
82
202
|
row = invalid[invalid].index[0]
|
|
83
203
|
raise ValueError(
|
|
84
204
|
f"Column {column_name!r} has a non-numeric value at "
|
|
85
|
-
f"data row {row + 1}: {column_values.
|
|
205
|
+
f"data row {row + 1}: {column_values.loc[row]!r}."
|
|
86
206
|
)
|
|
87
207
|
value_entries = [
|
|
88
208
|
{"value": (None if pd.isna(val) else float(val)), "unit": unit}
|
|
@@ -97,6 +217,12 @@ def problem_records_from_frame(df_data: pd.DataFrame, units_map: dict) -> list:
|
|
|
97
217
|
return records
|
|
98
218
|
|
|
99
219
|
|
|
220
|
+
def _is_blank_cell(value: Any) -> bool:
|
|
221
|
+
if isinstance(value, str):
|
|
222
|
+
return not value.strip()
|
|
223
|
+
return value is None or bool(pd.isna(value))
|
|
224
|
+
|
|
225
|
+
|
|
100
226
|
def target_records_from_frame(
|
|
101
227
|
df_data: pd.DataFrame,
|
|
102
228
|
units_map: dict,
|
|
@@ -11,11 +11,14 @@ from .records import (
|
|
|
11
11
|
validate_utility_data,
|
|
12
12
|
)
|
|
13
13
|
from .tabular import (
|
|
14
|
-
|
|
14
|
+
problem_frame_from_sheet as _problem_frame_from_sheet,
|
|
15
15
|
)
|
|
16
16
|
from .tabular import (
|
|
17
17
|
problem_records_from_frame as _write_problem_to_dict_and_list,
|
|
18
18
|
)
|
|
19
|
+
from .tabular import (
|
|
20
|
+
summary_frame_from_sheet as _summary_frame_from_sheet,
|
|
21
|
+
)
|
|
19
22
|
from .tabular import (
|
|
20
23
|
target_records_from_frame as _write_targets_to_dict_and_list,
|
|
21
24
|
)
|
|
@@ -102,23 +105,16 @@ def _parse_sheet_with_units(
|
|
|
102
105
|
"(names, units, and data rows)."
|
|
103
106
|
)
|
|
104
107
|
|
|
105
|
-
|
|
106
|
-
df_full,
|
|
107
|
-
|
|
108
|
-
|
|
109
|
-
|
|
110
|
-
|
|
111
|
-
|
|
112
|
-
|
|
113
|
-
|
|
114
|
-
|
|
115
|
-
# its defaults; padding them with 0 forced dt_cont and htc to zero.
|
|
116
|
-
df_data.columns = col_names[: len(df_data.columns)]
|
|
117
|
-
|
|
118
|
-
units_map = dict(zip(col_names, col_units))
|
|
119
|
-
if sheet_name != "Summary":
|
|
120
|
-
# Keep every numeric column's unit (price included), as the CSV reader
|
|
121
|
-
# does; text columns carry no unit.
|
|
108
|
+
if sheet_name == "Summary":
|
|
109
|
+
df_data, units_map = _summary_frame_from_sheet(df_full, row_units, row_data)
|
|
110
|
+
else:
|
|
111
|
+
# Columns the table leaves out stay absent so the input contract
|
|
112
|
+
# applies its defaults; padding them with 0 forced dt_cont and htc to
|
|
113
|
+
# zero. Numeric columns keep their unit (price included), as the CSV
|
|
114
|
+
# reader does; text columns carry no unit.
|
|
115
|
+
df_data, units_map = _problem_frame_from_sheet(
|
|
116
|
+
df_full, sheet_name, row_units, row_data
|
|
117
|
+
)
|
|
122
118
|
units_map = {
|
|
123
119
|
key: unit
|
|
124
120
|
for key, unit in units_map.items()
|
|
@@ -259,6 +259,15 @@ def get_base_problem_table(
|
|
|
259
259
|
|
|
260
260
|
|
|
261
261
|
def get_source_problem_table(target: UtilitySummaryTarget) -> ProblemTable:
|
|
262
|
+
# The target's own table is unrounded; the saved GCC graph is rounded to
|
|
263
|
+
# 4 dp for plotting, so it is only a fallback.
|
|
264
|
+
table = getattr(target, "pt", None)
|
|
265
|
+
if (
|
|
266
|
+
isinstance(table, ProblemTable)
|
|
267
|
+
and has_problem_table_values(table, ProblemTableLabel.T)
|
|
268
|
+
and has_problem_table_values(table, ProblemTableLabel.H_NET)
|
|
269
|
+
):
|
|
270
|
+
return table
|
|
262
271
|
graphs = getattr(target, "graphs", None)
|
|
263
272
|
if isinstance(graphs, dict):
|
|
264
273
|
gcc = graphs.get(GraphType.GCC.value)
|
|
@@ -332,11 +332,9 @@ def apply_exergy_targeting(target: Any, *, dt_cont_multiplier: float = 1.0) -> A
|
|
|
332
332
|
}
|
|
333
333
|
target.exergy_sources = float(nlp_output["source_total"])
|
|
334
334
|
target.exergy_sinks = float(nlp_output["sink_total"])
|
|
335
|
-
|
|
336
|
-
|
|
337
|
-
|
|
338
|
-
else 0.0
|
|
339
|
-
)
|
|
335
|
+
gained, released = _balanced_curve_exergy_transfer(target, spec)
|
|
336
|
+
target.exergy_released = released
|
|
337
|
+
target.ETE = gained / released if released > tol else 0.0
|
|
340
338
|
target.exergy_req_min = float(gcc_output[ProblemTableLabel.X_GCC.value][0])
|
|
341
339
|
target.exergy_des_min = float(gcc_output[ProblemTableLabel.X_GCC.value][-1])
|
|
342
340
|
return target
|
|
@@ -515,6 +513,129 @@ def _resolve_target_exergy_spec(
|
|
|
515
513
|
return None
|
|
516
514
|
|
|
517
515
|
|
|
516
|
+
def _balanced_curve_exergy_transfer(
|
|
517
|
+
target: Any, spec: dict[str, Any]
|
|
518
|
+
) -> tuple[float, float]:
|
|
519
|
+
"""Return the exergy gained and released across the BCC heat transfer (kW).
|
|
520
|
+
|
|
521
|
+
The Balanced Composite Curves are the process composites plus the
|
|
522
|
+
utilities (and any heat-pump streams), relative to ``ENV_TEMPERATURE``.
|
|
523
|
+
Above ambient the hot curve releases exergy and the cold curve gains it;
|
|
524
|
+
below ambient the roles swap, since cooling a stream there raises its
|
|
525
|
+
exergy. The ratio of gained to released exergy is the exergy transfer
|
|
526
|
+
effectiveness: at most 1, and the shortfall is the exergy destroyed in
|
|
527
|
+
heat transfer. A Direct Integration target uses its real-temperature
|
|
528
|
+
table. Other targets use their own table, un-shifted interval by interval
|
|
529
|
+
as the exergy curves are.
|
|
530
|
+
"""
|
|
531
|
+
t_env = spec["t_env"]
|
|
532
|
+
pt_real = getattr(target, "pt_real", None)
|
|
533
|
+
real_columns = (
|
|
534
|
+
[
|
|
535
|
+
_optional_column(pt_real, label)
|
|
536
|
+
for label in (
|
|
537
|
+
ProblemTableLabel.H_HOT,
|
|
538
|
+
ProblemTableLabel.H_HOT_UT,
|
|
539
|
+
ProblemTableLabel.H_COLD,
|
|
540
|
+
ProblemTableLabel.H_COLD_UT,
|
|
541
|
+
)
|
|
542
|
+
]
|
|
543
|
+
if pt_real is not None
|
|
544
|
+
else [None]
|
|
545
|
+
)
|
|
546
|
+
if all(column is not None for column in real_columns):
|
|
547
|
+
t_vals = _to_float_array(pt_real[ProblemTableLabel.T])
|
|
548
|
+
hot_curves = [(real_columns[0], 0.0), (real_columns[1], 0.0)]
|
|
549
|
+
cold_curves = [(real_columns[2], 0.0), (real_columns[3], 0.0)]
|
|
550
|
+
else:
|
|
551
|
+
pt = target.pt
|
|
552
|
+
t_vals = spec["temperatures"]
|
|
553
|
+
n_intervals = max(len(t_vals) - 1, 0)
|
|
554
|
+
if spec["gcc_is_real"]:
|
|
555
|
+
hot_offset = cold_offset = np.zeros(n_intervals, dtype=float)
|
|
556
|
+
else:
|
|
557
|
+
hot_offset = _interval_shifts(
|
|
558
|
+
spec.get("hot_shifts"), n_intervals, spec["dt_cont_shift"]
|
|
559
|
+
)
|
|
560
|
+
cold_offset = -_interval_shifts(
|
|
561
|
+
spec.get("cold_shifts"), n_intervals, spec["dt_cont_shift"]
|
|
562
|
+
)
|
|
563
|
+
# Heat-pump streams carry no temperature contribution.
|
|
564
|
+
hot_curves = [
|
|
565
|
+
(_optional_column(pt, ProblemTableLabel.H_HOT), hot_offset),
|
|
566
|
+
(_optional_column(pt, ProblemTableLabel.H_HOT_UT), hot_offset),
|
|
567
|
+
(_optional_column(pt, ProblemTableLabel.H_HOT_HP), 0.0),
|
|
568
|
+
]
|
|
569
|
+
cold_curves = [
|
|
570
|
+
(_optional_column(pt, ProblemTableLabel.H_COLD), cold_offset),
|
|
571
|
+
(_optional_column(pt, ProblemTableLabel.H_COLD_UT), cold_offset),
|
|
572
|
+
(_optional_column(pt, ProblemTableLabel.H_COLD_HP), 0.0),
|
|
573
|
+
]
|
|
574
|
+
gained = released = 0.0
|
|
575
|
+
for curves, is_hot in ((hot_curves, True), (cold_curves, False)):
|
|
576
|
+
for h_vals, offset in curves:
|
|
577
|
+
if h_vals is None:
|
|
578
|
+
continue
|
|
579
|
+
# Above ambient the hot curve releases and the cold curve gains;
|
|
580
|
+
# below ambient it is the other way round.
|
|
581
|
+
above, below = _curve_exergy_changes(t_vals, h_vals, offset, t_env)
|
|
582
|
+
if is_hot:
|
|
583
|
+
released += above
|
|
584
|
+
gained += below
|
|
585
|
+
else:
|
|
586
|
+
released += below
|
|
587
|
+
gained += above
|
|
588
|
+
return float(gained), float(released)
|
|
589
|
+
|
|
590
|
+
|
|
591
|
+
def _curve_exergy_changes(
|
|
592
|
+
t_vals: np.ndarray,
|
|
593
|
+
h_vals: np.ndarray,
|
|
594
|
+
offset: np.ndarray | float,
|
|
595
|
+
t_env: float,
|
|
596
|
+
) -> tuple[float, float]:
|
|
597
|
+
"""Return the (above-ambient, below-ambient) exergy of a T-H curve, in kW.
|
|
598
|
+
|
|
599
|
+
Each interval contributes dH (1 - T0/T) integrated along it, which is
|
|
600
|
+
positive above ambient and negative below; intervals that cross ambient
|
|
601
|
+
are split there, and the below-ambient part is returned as a magnitude.
|
|
602
|
+
``t_vals`` are in degC, falling down the table, and ``offset`` moves each
|
|
603
|
+
interval onto real temperatures. A linear segment is integrated exactly.
|
|
604
|
+
"""
|
|
605
|
+
h_vals = np.nan_to_num(np.asarray(h_vals, dtype=float))
|
|
606
|
+
t_abs = np.asarray(t_vals, dtype=float) + C_to_K
|
|
607
|
+
t_upper = t_abs[:-1] + offset
|
|
608
|
+
t_lower = t_abs[1:] + offset
|
|
609
|
+
t_ref = t_env + C_to_K
|
|
610
|
+
delta_h = h_vals[:-1] - h_vals[1:]
|
|
611
|
+
above = below = 0.0
|
|
612
|
+
for t_u, t_l, d_h in zip(
|
|
613
|
+
np.broadcast_to(t_upper, delta_h.shape),
|
|
614
|
+
np.broadcast_to(t_lower, delta_h.shape),
|
|
615
|
+
delta_h,
|
|
616
|
+
):
|
|
617
|
+
if abs(d_h) <= tol:
|
|
618
|
+
continue
|
|
619
|
+
span = t_u - t_l
|
|
620
|
+
if abs(span) <= tol:
|
|
621
|
+
pieces = [d_h * (1.0 - t_ref / t_u)]
|
|
622
|
+
else:
|
|
623
|
+
cp = d_h / span
|
|
624
|
+
hi, lo = max(t_u, t_l), min(t_u, t_l)
|
|
625
|
+
bounds = [hi, t_ref, lo] if lo < t_ref < hi else [hi, lo]
|
|
626
|
+
sign = 1.0 if span > 0 else -1.0
|
|
627
|
+
pieces = [
|
|
628
|
+
sign * cp * ((a - b) - t_ref * np.log(a / b))
|
|
629
|
+
for a, b in zip(bounds[:-1], bounds[1:])
|
|
630
|
+
]
|
|
631
|
+
for piece in pieces:
|
|
632
|
+
if piece >= 0.0:
|
|
633
|
+
above += piece
|
|
634
|
+
else:
|
|
635
|
+
below -= piece
|
|
636
|
+
return float(above), float(below)
|
|
637
|
+
|
|
638
|
+
|
|
518
639
|
def _zone_stream_shift_sources(target: Any) -> tuple[list, list, int | None] | None:
|
|
519
640
|
"""Return the hot and cold streams (with utilities) behind ``target``."""
|
|
520
641
|
zone = getattr(target, "parent_zone", None)
|
|
@@ -6,7 +6,7 @@ from typing import Any
|
|
|
6
6
|
|
|
7
7
|
import numpy as np
|
|
8
8
|
|
|
9
|
-
from ...domain.configuration import tol
|
|
9
|
+
from ...domain.configuration import duty_tolerance, heat_resolution, tol
|
|
10
10
|
from ...domain.enums import (
|
|
11
11
|
ArrowHead,
|
|
12
12
|
GraphType,
|
|
@@ -34,12 +34,16 @@ def clean_composite_curve_ends(
|
|
|
34
34
|
"""Remove redundant constant-enthalpy points from curve ends."""
|
|
35
35
|
y_vals = np.asarray(y_vals)
|
|
36
36
|
x_vals = np.asarray(x_vals)
|
|
37
|
-
# Compare the duty range with
|
|
38
|
-
# with a real duty would vanish).
|
|
39
|
-
if x_vals.size == 0 or np.ptp(x_vals) <=
|
|
37
|
+
# Compare the duty range with the heat-flow resolution (variance is in
|
|
38
|
+
# kW^2, so a small curve with a real duty would vanish).
|
|
39
|
+
if x_vals.size == 0 or np.ptp(x_vals) <= heat_resolution(x_vals):
|
|
40
40
|
return np.array([]), np.array([])
|
|
41
|
-
|
|
42
|
-
|
|
41
|
+
# Only rounding residue counts as constant at the ends: an absolute
|
|
42
|
+
# tolerance relative to the duty, not np.isclose's default rtol=1e-5 of
|
|
43
|
+
# the end value, which trimmed real end segments on MW-scale curves.
|
|
44
|
+
atol = max(duty_tolerance(x_vals), np.finfo(float).eps)
|
|
45
|
+
start_mask = np.abs(x_vals - x_vals[0]) > atol
|
|
46
|
+
end_mask = np.abs(x_vals - x_vals[-1]) > atol
|
|
43
47
|
start = np.flatnonzero(start_mask)[0] - 1
|
|
44
48
|
end = np.flatnonzero(end_mask)[-1] + 1
|
|
45
49
|
return y_vals[start : end + 1], x_vals[start : end + 1]
|
|
@@ -114,7 +118,11 @@ def _make_composite_graph(
|
|
|
114
118
|
for field, stream_loc in zip(fields, stream_types):
|
|
115
119
|
column_key = _column_key(field)
|
|
116
120
|
x_vals = _column_to_list(data, column_key)
|
|
117
|
-
|
|
121
|
+
# A constant series (for example the cold composite of a problem with
|
|
122
|
+
# only hot streams) has no curve to draw.
|
|
123
|
+
if _should_plot_series(x_vals) and np.ptp(
|
|
124
|
+
np.asarray(x_vals, dtype=float)
|
|
125
|
+
) > heat_resolution(x_vals):
|
|
118
126
|
segments.extend(
|
|
119
127
|
_graph_cc(
|
|
120
128
|
key,
|
|
@@ -252,9 +252,9 @@ def _identities_by_axis(
|
|
|
252
252
|
)
|
|
253
253
|
|
|
254
254
|
|
|
255
|
-
def
|
|
255
|
+
def _utilities(identities: tuple[str, ...], label: str) -> tuple[str, ...]:
|
|
256
256
|
if not identities:
|
|
257
257
|
raise ValueError(
|
|
258
258
|
f"solved heat exchanger network extraction requires at least one {label}."
|
|
259
259
|
)
|
|
260
|
-
return identities
|
|
260
|
+
return identities
|