processpi 0.2.0.4__tar.gz → 0.2.1__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.
- {processpi-0.2.0.4 → processpi-0.2.1}/PKG-INFO +1 -1
- processpi-0.2.1/processpi/calculations/heat_transfer/__init__.py +92 -0
- processpi-0.2.1/processpi/calculations/heat_transfer/heat_exchanger.py +103 -0
- {processpi-0.2.0.4 → processpi-0.2.1}/processpi/calculations/heat_transfer/heat_exchanger_area.py +3 -1
- processpi-0.2.1/processpi/calculations/heat_transfer/hx_kern.py +266 -0
- {processpi-0.2.0.4 → processpi-0.2.1}/processpi/calculations/heat_transfer/lmtd.py +15 -2
- {processpi-0.2.0.4 → processpi-0.2.1}/processpi/components/air.py +1 -0
- {processpi-0.2.0.4 → processpi-0.2.1}/processpi/components/base.py +58 -12
- {processpi-0.2.0.4 → processpi-0.2.1}/processpi/components/benzene.py +10 -3
- {processpi-0.2.0.4 → processpi-0.2.1}/processpi/components/carbonmonoxide.py +1 -1
- {processpi-0.2.0.4 → processpi-0.2.1}/processpi/components/gas.py +1 -0
- {processpi-0.2.0.4 → processpi-0.2.1}/processpi/components/inorganic_liquid.py +1 -0
- {processpi-0.2.0.4 → processpi-0.2.1}/processpi/components/oil.py +10 -3
- {processpi-0.2.0.4 → processpi-0.2.1}/processpi/components/organic_liquid.py +10 -3
- {processpi-0.2.0.4 → processpi-0.2.1}/processpi/components/steam.py +1 -0
- {processpi-0.2.0.4 → processpi-0.2.1}/processpi/components/toluene.py +9 -2
- {processpi-0.2.0.4 → processpi-0.2.1}/processpi/components/vapor.py +1 -0
- {processpi-0.2.0.4 → processpi-0.2.1}/processpi/components/water.py +23 -0
- processpi-0.2.1/processpi/equipment/__init__.py +15 -0
- processpi-0.2.1/processpi/equipment/base.py +120 -0
- processpi-0.2.1/processpi/equipment/heatexchangers/__init__.py +20 -0
- processpi-0.2.1/processpi/equipment/heatexchangers/base.py +214 -0
- processpi-0.2.1/processpi/equipment/heatexchangers/bell_delaware.py +10 -0
- processpi-0.2.1/processpi/equipment/heatexchangers/condenser.py +138 -0
- processpi-0.2.1/processpi/equipment/heatexchangers/double_pipe.py +504 -0
- processpi-0.2.1/processpi/equipment/heatexchangers/engine.py +376 -0
- processpi-0.2.1/processpi/equipment/heatexchangers/evaporator.py +149 -0
- processpi-0.2.1/processpi/equipment/heatexchangers/reboiler.py +94 -0
- processpi-0.2.1/processpi/equipment/heatexchangers/shell_and_tube.py +2633 -0
- processpi-0.2.1/processpi/equipment/heatexchangers/standards.py +552 -0
- processpi-0.2.1/processpi/integration/flowsheet.py +181 -0
- {processpi-0.2.0.4 → processpi-0.2.1}/processpi.egg-info/PKG-INFO +1 -1
- {processpi-0.2.0.4 → processpi-0.2.1}/processpi.egg-info/SOURCES.txt +12 -30
- {processpi-0.2.0.4 → processpi-0.2.1}/pyproject.toml +1 -1
- {processpi-0.2.0.4 → processpi-0.2.1}/setup.py +1 -1
- processpi-0.2.1/tests/test_heatexchanger_mechanical_dispatch.py +51 -0
- processpi-0.2.1/tests/test_integration_flowsheet_ports.py +70 -0
- processpi-0.2.1/tests/test_shell_tube_kern_bell_workflow.py +62 -0
- processpi-0.2.0.4/processpi/calculations/heat_transfer/__init__.py +0 -59
- processpi-0.2.0.4/processpi/equipment/__init__.py +0 -21
- processpi-0.2.0.4/processpi/equipment/absorber.py +0 -67
- processpi-0.2.0.4/processpi/equipment/base.py +0 -57
- processpi-0.2.0.4/processpi/equipment/batch.py +0 -39
- processpi-0.2.0.4/processpi/equipment/compressor.py +0 -80
- processpi-0.2.0.4/processpi/equipment/cstr.py +0 -41
- processpi-0.2.0.4/processpi/equipment/decanter.py +0 -61
- processpi-0.2.0.4/processpi/equipment/distillation.py +0 -82
- processpi-0.2.0.4/processpi/equipment/flash.py +0 -84
- processpi-0.2.0.4/processpi/equipment/heater_cooler.py +0 -103
- processpi-0.2.0.4/processpi/equipment/heatexchangers/__init__.py +0 -7
- processpi-0.2.0.4/processpi/equipment/heatexchangers/base.py +0 -129
- processpi-0.2.0.4/processpi/equipment/heatexchangers/examples.py +0 -116
- processpi-0.2.0.4/processpi/equipment/heatexchangers/mechanical/__init__.py +0 -53
- processpi-0.2.0.4/processpi/equipment/heatexchangers/mechanical/basic_params.py +0 -83
- processpi-0.2.0.4/processpi/equipment/heatexchangers/mechanical/bell_method.py +0 -101
- processpi-0.2.0.4/processpi/equipment/heatexchangers/mechanical/classification.py +0 -66
- processpi-0.2.0.4/processpi/equipment/heatexchangers/mechanical/condenser.py +0 -262
- processpi-0.2.0.4/processpi/equipment/heatexchangers/mechanical/double_pipe.py +0 -633
- processpi-0.2.0.4/processpi/equipment/heatexchangers/mechanical/evaporator.py +0 -263
- processpi-0.2.0.4/processpi/equipment/heatexchangers/mechanical/kern_method.py +0 -112
- processpi-0.2.0.4/processpi/equipment/heatexchangers/mechanical/reboiler.py +0 -288
- processpi-0.2.0.4/processpi/equipment/heatexchangers/mechanical/shell_tube.py +0 -686
- processpi-0.2.0.4/processpi/equipment/heatexchangers/mechanical.py +0 -20
- processpi-0.2.0.4/processpi/equipment/heatexchangers/simulation.py +0 -186
- processpi-0.2.0.4/processpi/equipment/heatexchangers/standards.py +0 -118
- processpi-0.2.0.4/processpi/equipment/heatexchangers/utils.py +0 -1
- processpi-0.2.0.4/processpi/equipment/heatexchangers_.py +0 -155
- processpi-0.2.0.4/processpi/equipment/mixer.py +0 -54
- processpi-0.2.0.4/processpi/equipment/pfr.py +0 -44
- processpi-0.2.0.4/processpi/equipment/pumps.py +0 -92
- processpi-0.2.0.4/processpi/equipment/splitter.py +0 -41
- processpi-0.2.0.4/processpi/equipment/stripper.py +0 -67
- processpi-0.2.0.4/processpi/equipment/turbine.py +0 -81
- processpi-0.2.0.4/processpi/equipment/valves.py +0 -112
- processpi-0.2.0.4/processpi/integration/flowsheet.py +0 -150
- {processpi-0.2.0.4 → processpi-0.2.1}/LICENSE +0 -0
- {processpi-0.2.0.4 → processpi-0.2.1}/README.md +0 -0
- {processpi-0.2.0.4 → processpi-0.2.1}/processpi/__init__.py +0 -0
- {processpi-0.2.0.4 → processpi-0.2.1}/processpi/calculations/__init__.py +0 -0
- {processpi-0.2.0.4 → processpi-0.2.1}/processpi/calculations/base.py +0 -0
- {processpi-0.2.0.4 → processpi-0.2.1}/processpi/calculations/engine.py +0 -0
- {processpi-0.2.0.4 → processpi-0.2.1}/processpi/calculations/fluids/__init__.py +0 -0
- {processpi-0.2.0.4 → processpi-0.2.1}/processpi/calculations/fluids/flow_type.py +0 -0
- {processpi-0.2.0.4 → processpi-0.2.1}/processpi/calculations/fluids/friction_factor_colebrookwhite.py +0 -0
- {processpi-0.2.0.4 → processpi-0.2.1}/processpi/calculations/fluids/optimium_pipe_dia.py +0 -0
- {processpi-0.2.0.4 → processpi-0.2.1}/processpi/calculations/fluids/pressure_drop_darcy.py +0 -0
- {processpi-0.2.0.4 → processpi-0.2.1}/processpi/calculations/fluids/pressure_drop_fanning.py +0 -0
- {processpi-0.2.0.4 → processpi-0.2.1}/processpi/calculations/fluids/pressure_drop_hazen_williams.py +0 -0
- {processpi-0.2.0.4 → processpi-0.2.1}/processpi/calculations/fluids/pump_power.py +0 -0
- {processpi-0.2.0.4 → processpi-0.2.1}/processpi/calculations/fluids/reynolds_number.py +0 -0
- {processpi-0.2.0.4 → processpi-0.2.1}/processpi/calculations/fluids/velocity.py +0 -0
- {processpi-0.2.0.4 → processpi-0.2.1}/processpi/calculations/heat_transfer/biot.py +0 -0
- {processpi-0.2.0.4 → processpi-0.2.1}/processpi/calculations/heat_transfer/boiling_chen.py +0 -0
- {processpi-0.2.0.4 → processpi-0.2.1}/processpi/calculations/heat_transfer/combined_modes.py +0 -0
- {processpi-0.2.0.4 → processpi-0.2.1}/processpi/calculations/heat_transfer/condensation.py +0 -0
- {processpi-0.2.0.4 → processpi-0.2.1}/processpi/calculations/heat_transfer/condensation_dropwise.py +0 -0
- {processpi-0.2.0.4 → processpi-0.2.1}/processpi/calculations/heat_transfer/condensation_nusselt.py +0 -0
- {processpi-0.2.0.4 → processpi-0.2.1}/processpi/calculations/heat_transfer/conduction_heat_loss.py +0 -0
- {processpi-0.2.0.4 → processpi-0.2.1}/processpi/calculations/heat_transfer/convection_heat_loss.py +0 -0
- {processpi-0.2.0.4 → processpi-0.2.1}/processpi/calculations/heat_transfer/crossflow_tube.py +0 -0
- {processpi-0.2.0.4 → processpi-0.2.1}/processpi/calculations/heat_transfer/fourier.py +0 -0
- {processpi-0.2.0.4 → processpi-0.2.1}/processpi/calculations/heat_transfer/fourierlaw.py +0 -0
- {processpi-0.2.0.4 → processpi-0.2.1}/processpi/calculations/heat_transfer/grashof.py +0 -0
- {processpi-0.2.0.4 → processpi-0.2.1}/processpi/calculations/heat_transfer/newton_cooling.py +0 -0
- {processpi-0.2.0.4 → processpi-0.2.1}/processpi/calculations/heat_transfer/ntu.py +0 -0
- {processpi-0.2.0.4 → processpi-0.2.1}/processpi/calculations/heat_transfer/nusselt.py +0 -0
- {processpi-0.2.0.4 → processpi-0.2.1}/processpi/calculations/heat_transfer/overall_u.py +0 -0
- {processpi-0.2.0.4 → processpi-0.2.1}/processpi/calculations/heat_transfer/peclet.py +0 -0
- {processpi-0.2.0.4 → processpi-0.2.1}/processpi/calculations/heat_transfer/prandtl.py +0 -0
- {processpi-0.2.0.4 → processpi-0.2.1}/processpi/calculations/heat_transfer/radial_cylinder.py +0 -0
- {processpi-0.2.0.4 → processpi-0.2.1}/processpi/calculations/heat_transfer/radiation_blackbody.py +0 -0
- {processpi-0.2.0.4 → processpi-0.2.1}/processpi/calculations/heat_transfer/radiation_exchange.py +0 -0
- {processpi-0.2.0.4 → processpi-0.2.1}/processpi/calculations/heat_transfer/radiation_greybody.py +0 -0
- {processpi-0.2.0.4 → processpi-0.2.1}/processpi/calculations/heat_transfer/radiation_viewfactor.py +0 -0
- {processpi-0.2.0.4 → processpi-0.2.1}/processpi/calculations/heat_transfer/resistance.py +0 -0
- {processpi-0.2.0.4 → processpi-0.2.1}/processpi/calculations/heat_transfer/reyleigh.py +0 -0
- {processpi-0.2.0.4 → processpi-0.2.1}/processpi/calculations/heat_transfer/rohsenow_boiling.py +0 -0
- {processpi-0.2.0.4 → processpi-0.2.1}/processpi/calculations/heat_transfer/stefan_boltzmann.py +0 -0
- {processpi-0.2.0.4 → processpi-0.2.1}/processpi/calculations/mass_transfer/__init__.py +0 -0
- {processpi-0.2.0.4 → processpi-0.2.1}/processpi/calculations/mass_transfer/distillation_stage_count.py +0 -0
- {processpi-0.2.0.4 → processpi-0.2.1}/processpi/calculations/mass_transfer/drying_rate.py +0 -0
- {processpi-0.2.0.4 → processpi-0.2.1}/processpi/calculations/reaction_engineering/__init__.py +0 -0
- {processpi-0.2.0.4 → processpi-0.2.1}/processpi/calculations/reaction_engineering/catalyst_activity.py +0 -0
- {processpi-0.2.0.4 → processpi-0.2.1}/processpi/calculations/reaction_engineering/reaction_rate.py +0 -0
- {processpi-0.2.0.4 → processpi-0.2.1}/processpi/calculations/reaction_engineering/residence_time.py +0 -0
- {processpi-0.2.0.4 → processpi-0.2.1}/processpi/calculations/thermodynamics/__init__.py +0 -0
- {processpi-0.2.0.4 → processpi-0.2.1}/processpi/calculations/thermodynamics/enthalpy_change.py +0 -0
- {processpi-0.2.0.4 → processpi-0.2.1}/processpi/calculations/thermodynamics/entropy_change.py +0 -0
- {processpi-0.2.0.4 → processpi-0.2.1}/processpi/calculations/thermodynamics/heat_of_vaporization.py +0 -0
- {processpi-0.2.0.4 → processpi-0.2.1}/processpi/components/__init__.py +0 -0
- {processpi-0.2.0.4 → processpi-0.2.1}/processpi/components/aceticacid.py +0 -0
- {processpi-0.2.0.4 → processpi-0.2.1}/processpi/components/acetone.py +0 -0
- {processpi-0.2.0.4 → processpi-0.2.1}/processpi/components/acrylicacid.py +0 -0
- {processpi-0.2.0.4 → processpi-0.2.1}/processpi/components/ammonia.py +0 -0
- {processpi-0.2.0.4 → processpi-0.2.1}/processpi/components/benzoicacid.py +0 -0
- {processpi-0.2.0.4 → processpi-0.2.1}/processpi/components/bromine.py +0 -0
- {processpi-0.2.0.4 → processpi-0.2.1}/processpi/components/butane.py +0 -0
- {processpi-0.2.0.4 → processpi-0.2.1}/processpi/components/carbondioxide.py +0 -0
- {processpi-0.2.0.4 → processpi-0.2.1}/processpi/components/carbontetrachloride.py +0 -0
- {processpi-0.2.0.4 → processpi-0.2.1}/processpi/components/chlorine.py +0 -0
- {processpi-0.2.0.4 → processpi-0.2.1}/processpi/components/chlorobenzene.py +0 -0
- {processpi-0.2.0.4 → processpi-0.2.1}/processpi/components/chloroform.py +0 -0
- {processpi-0.2.0.4 → processpi-0.2.1}/processpi/components/chloromethane.py +0 -0
- {processpi-0.2.0.4 → processpi-0.2.1}/processpi/components/constants.py +0 -0
- {processpi-0.2.0.4 → processpi-0.2.1}/processpi/components/cyanogen.py +0 -0
- {processpi-0.2.0.4 → processpi-0.2.1}/processpi/components/cyclohexene.py +0 -0
- {processpi-0.2.0.4 → processpi-0.2.1}/processpi/components/ethane.py +0 -0
- {processpi-0.2.0.4 → processpi-0.2.1}/processpi/components/ethanol.py +0 -0
- {processpi-0.2.0.4 → processpi-0.2.1}/processpi/components/ethylacetate.py +0 -0
- {processpi-0.2.0.4 → processpi-0.2.1}/processpi/components/ethylene.py +0 -0
- {processpi-0.2.0.4 → processpi-0.2.1}/processpi/components/fluorine.py +0 -0
- {processpi-0.2.0.4 → processpi-0.2.1}/processpi/components/fluorobenzene.py +0 -0
- {processpi-0.2.0.4 → processpi-0.2.1}/processpi/components/formicacid.py +0 -0
- {processpi-0.2.0.4 → processpi-0.2.1}/processpi/components/methanol.py +0 -0
- {processpi-0.2.0.4 → processpi-0.2.1}/processpi/constants.py +0 -0
- {processpi-0.2.0.4 → processpi-0.2.1}/processpi/integration/__init__.py +0 -0
- {processpi-0.2.0.4 → processpi-0.2.1}/processpi/pipelines/__init__.py +0 -0
- {processpi-0.2.0.4 → processpi-0.2.1}/processpi/pipelines/base.py +0 -0
- {processpi-0.2.0.4 → processpi-0.2.1}/processpi/pipelines/design_rules.py +0 -0
- {processpi-0.2.0.4 → processpi-0.2.1}/processpi/pipelines/engine.py +0 -0
- {processpi-0.2.0.4 → processpi-0.2.1}/processpi/pipelines/equipment.py +0 -0
- {processpi-0.2.0.4 → processpi-0.2.1}/processpi/pipelines/fittings.py +0 -0
- {processpi-0.2.0.4 → processpi-0.2.1}/processpi/pipelines/insulation.py +0 -0
- {processpi-0.2.0.4 → processpi-0.2.1}/processpi/pipelines/materials.py +0 -0
- {processpi-0.2.0.4 → processpi-0.2.1}/processpi/pipelines/network.py +0 -0
- {processpi-0.2.0.4 → processpi-0.2.1}/processpi/pipelines/nozzle.py +0 -0
- {processpi-0.2.0.4 → processpi-0.2.1}/processpi/pipelines/pipelineresults.py +0 -0
- {processpi-0.2.0.4 → processpi-0.2.1}/processpi/pipelines/pipes.py +0 -0
- {processpi-0.2.0.4 → processpi-0.2.1}/processpi/pipelines/piping_costs.py +0 -0
- {processpi-0.2.0.4 → processpi-0.2.1}/processpi/pipelines/pumps.py +0 -0
- {processpi-0.2.0.4 → processpi-0.2.1}/processpi/pipelines/selection.py +0 -0
- {processpi-0.2.0.4 → processpi-0.2.1}/processpi/pipelines/standards.py +0 -0
- {processpi-0.2.0.4 → processpi-0.2.1}/processpi/pipelines/vessel.py +0 -0
- {processpi-0.2.0.4 → processpi-0.2.1}/processpi/streams/__init__.py +0 -0
- {processpi-0.2.0.4 → processpi-0.2.1}/processpi/streams/energy.py +0 -0
- {processpi-0.2.0.4 → processpi-0.2.1}/processpi/streams/material.py +0 -0
- {processpi-0.2.0.4 → processpi-0.2.1}/processpi/units/__init__.py +0 -0
- {processpi-0.2.0.4 → processpi-0.2.1}/processpi/units/area.py +0 -0
- {processpi-0.2.0.4 → processpi-0.2.1}/processpi/units/base.py +0 -0
- {processpi-0.2.0.4 → processpi-0.2.1}/processpi/units/density.py +0 -0
- {processpi-0.2.0.4 → processpi-0.2.1}/processpi/units/diameter.py +0 -0
- {processpi-0.2.0.4 → processpi-0.2.1}/processpi/units/dimensionless.py +0 -0
- {processpi-0.2.0.4 → processpi-0.2.1}/processpi/units/heat_flow.py +0 -0
- {processpi-0.2.0.4 → processpi-0.2.1}/processpi/units/heat_flux.py +0 -0
- {processpi-0.2.0.4 → processpi-0.2.1}/processpi/units/heat_of_vaporization.py +0 -0
- {processpi-0.2.0.4 → processpi-0.2.1}/processpi/units/heat_transfer_coefficient.py +0 -0
- {processpi-0.2.0.4 → processpi-0.2.1}/processpi/units/length.py +0 -0
- {processpi-0.2.0.4 → processpi-0.2.1}/processpi/units/mass.py +0 -0
- {processpi-0.2.0.4 → processpi-0.2.1}/processpi/units/mass_flowrate.py +0 -0
- {processpi-0.2.0.4 → processpi-0.2.1}/processpi/units/molar_flowrate.py +0 -0
- {processpi-0.2.0.4 → processpi-0.2.1}/processpi/units/power.py +0 -0
- {processpi-0.2.0.4 → processpi-0.2.1}/processpi/units/pressure.py +0 -0
- {processpi-0.2.0.4 → processpi-0.2.1}/processpi/units/specific_heat.py +0 -0
- {processpi-0.2.0.4 → processpi-0.2.1}/processpi/units/strings.py +0 -0
- {processpi-0.2.0.4 → processpi-0.2.1}/processpi/units/temperature.py +0 -0
- {processpi-0.2.0.4 → processpi-0.2.1}/processpi/units/thermal_conductivity.py +0 -0
- {processpi-0.2.0.4 → processpi-0.2.1}/processpi/units/thermal_resistance.py +0 -0
- {processpi-0.2.0.4 → processpi-0.2.1}/processpi/units/velocity.py +0 -0
- {processpi-0.2.0.4 → processpi-0.2.1}/processpi/units/viscosity.py +0 -0
- {processpi-0.2.0.4 → processpi-0.2.1}/processpi/units/volume.py +0 -0
- {processpi-0.2.0.4 → processpi-0.2.1}/processpi/units/volumetric_flowrate.py +0 -0
- {processpi-0.2.0.4 → processpi-0.2.1}/processpi.egg-info/dependency_links.txt +0 -0
- {processpi-0.2.0.4 → processpi-0.2.1}/processpi.egg-info/requires.txt +0 -0
- {processpi-0.2.0.4 → processpi-0.2.1}/processpi.egg-info/top_level.txt +0 -0
- {processpi-0.2.0.4 → processpi-0.2.1}/setup.cfg +0 -0
- {processpi-0.2.0.4 → processpi-0.2.1}/tests/test_engine_network.py +0 -0
- {processpi-0.2.0.4 → processpi-0.2.1}/tests/test_network.py +0 -0
- {processpi-0.2.0.4 → processpi-0.2.1}/tests/test_pipeline_network.py +0 -0
- {processpi-0.2.0.4 → processpi-0.2.1}/tests/test_variables.py +0 -0
|
@@ -0,0 +1,92 @@
|
|
|
1
|
+
from .biot import BiotNumber
|
|
2
|
+
from .combined_modes import ConductionConvectionCombined
|
|
3
|
+
from .condensation import CondensingVapourFilm
|
|
4
|
+
from .condensation_dropwise import DropwiseCondensation
|
|
5
|
+
from .condensation_nusselt import NusseltCondensation
|
|
6
|
+
from .conduction_heat_loss import ConductionHeatLoss
|
|
7
|
+
from .convection_heat_loss import ConvectionHeatLoss
|
|
8
|
+
from .crossflow_tube import CrossFlowSingleTube
|
|
9
|
+
from .fourier import FourierNumber
|
|
10
|
+
from .fourierlaw import FourierLaw
|
|
11
|
+
from .heat_exchanger import (
|
|
12
|
+
ConvectiveCoefficient,
|
|
13
|
+
DarcyPressureDrop,
|
|
14
|
+
KernNusselt,
|
|
15
|
+
LatentHeatDuty,
|
|
16
|
+
ReynoldsFromProperties,
|
|
17
|
+
SensibleHeatDuty,
|
|
18
|
+
)
|
|
19
|
+
from .heat_exchanger_area import HeatExchangerArea
|
|
20
|
+
from .hx_kern import (
|
|
21
|
+
ConvectiveH,
|
|
22
|
+
DarcyDrop,
|
|
23
|
+
DittusBoelter,
|
|
24
|
+
KernShellNu,
|
|
25
|
+
LatentDuty,
|
|
26
|
+
Reynolds,
|
|
27
|
+
SensibleDuty,
|
|
28
|
+
ShellDiameterEstimate,
|
|
29
|
+
TubeCountFromArea,
|
|
30
|
+
)
|
|
31
|
+
from .lmtd import LMTD
|
|
32
|
+
from .newton_cooling import NewtonCooling
|
|
33
|
+
from .ntu import NTUHeatExchanger
|
|
34
|
+
from .nusselt import NusseltNumber
|
|
35
|
+
from .overall_u import OverallHeatTransferCoefficient
|
|
36
|
+
from .peclet import PecletNumber
|
|
37
|
+
from .prandtl import PrandtlNumber
|
|
38
|
+
from .radial_cylinder import RadialHeatFlowCylinder
|
|
39
|
+
from .radiation_blackbody import BlackbodyRadiation
|
|
40
|
+
from .radiation_exchange import RadiationExchange
|
|
41
|
+
from .radiation_greybody import GreybodyRadiation
|
|
42
|
+
from .radiation_viewfactor import RadiationWithViewFactor
|
|
43
|
+
from .resistance import ThermalResistanceParallel, ThermalResistanceSeries
|
|
44
|
+
from .reyleigh import RayleighNumber
|
|
45
|
+
from .rohsenow_boiling import RohsenowBoiling
|
|
46
|
+
from .stefan_boltzmann import StefanBoltzmann
|
|
47
|
+
|
|
48
|
+
__all__ = [
|
|
49
|
+
"BiotNumber",
|
|
50
|
+
"ConductionConvectionCombined",
|
|
51
|
+
"CondensingVapourFilm",
|
|
52
|
+
"DropwiseCondensation",
|
|
53
|
+
"NusseltCondensation",
|
|
54
|
+
"ConductionHeatLoss",
|
|
55
|
+
"ConvectionHeatLoss",
|
|
56
|
+
"CrossFlowSingleTube",
|
|
57
|
+
"FourierNumber",
|
|
58
|
+
"FourierLaw",
|
|
59
|
+
"HeatExchangerArea",
|
|
60
|
+
"LMTD",
|
|
61
|
+
"NewtonCooling",
|
|
62
|
+
"NTUHeatExchanger",
|
|
63
|
+
"NusseltNumber",
|
|
64
|
+
"OverallHeatTransferCoefficient",
|
|
65
|
+
"PecletNumber",
|
|
66
|
+
"PrandtlNumber",
|
|
67
|
+
"RadialHeatFlowCylinder",
|
|
68
|
+
"BlackbodyRadiation",
|
|
69
|
+
"RadiationExchange",
|
|
70
|
+
"GreybodyRadiation",
|
|
71
|
+
"RadiationWithViewFactor",
|
|
72
|
+
"ThermalResistanceSeries",
|
|
73
|
+
"ThermalResistanceParallel",
|
|
74
|
+
"RayleighNumber",
|
|
75
|
+
"RohsenowBoiling",
|
|
76
|
+
"StefanBoltzmann",
|
|
77
|
+
"SensibleHeatDuty",
|
|
78
|
+
"LatentHeatDuty",
|
|
79
|
+
"KernNusselt",
|
|
80
|
+
"ConvectiveCoefficient",
|
|
81
|
+
"DarcyPressureDrop",
|
|
82
|
+
"ReynoldsFromProperties",
|
|
83
|
+
"SensibleDuty",
|
|
84
|
+
"LatentDuty",
|
|
85
|
+
"Reynolds",
|
|
86
|
+
"DittusBoelter",
|
|
87
|
+
"KernShellNu",
|
|
88
|
+
"ConvectiveH",
|
|
89
|
+
"TubeCountFromArea",
|
|
90
|
+
"ShellDiameterEstimate",
|
|
91
|
+
"DarcyDrop",
|
|
92
|
+
]
|
|
@@ -0,0 +1,103 @@
|
|
|
1
|
+
from __future__ import annotations
|
|
2
|
+
|
|
3
|
+
from ..base import CalculationBase
|
|
4
|
+
from ...units import HeatFlow, HeatTransferCoefficient, Pressure
|
|
5
|
+
|
|
6
|
+
|
|
7
|
+
class SensibleHeatDuty(CalculationBase):
|
|
8
|
+
"""Q = m * Cp * (Tin - Tout)."""
|
|
9
|
+
|
|
10
|
+
def validate_inputs(self):
|
|
11
|
+
required = ["mass_flow_rate", "specific_heat", "t_in", "t_out"]
|
|
12
|
+
for key in required:
|
|
13
|
+
if key not in self.inputs:
|
|
14
|
+
raise ValueError(f"Missing required input: {key}")
|
|
15
|
+
|
|
16
|
+
def calculate(self):
|
|
17
|
+
m = self._get_value(self.inputs["mass_flow_rate"], "mass_flow_rate")
|
|
18
|
+
cp = self._get_value(self.inputs["specific_heat"], "specific_heat")
|
|
19
|
+
t_in = self._get_value(self.inputs["t_in"], "t_in")
|
|
20
|
+
t_out = self._get_value(self.inputs["t_out"], "t_out")
|
|
21
|
+
return HeatFlow(abs(m * cp * (t_in - t_out)), "W")
|
|
22
|
+
|
|
23
|
+
|
|
24
|
+
class LatentHeatDuty(CalculationBase):
|
|
25
|
+
"""Q = m * lambda."""
|
|
26
|
+
|
|
27
|
+
def validate_inputs(self):
|
|
28
|
+
required = ["mass_flow_rate", "latent_heat"]
|
|
29
|
+
for key in required:
|
|
30
|
+
if key not in self.inputs:
|
|
31
|
+
raise ValueError(f"Missing required input: {key}")
|
|
32
|
+
|
|
33
|
+
def calculate(self):
|
|
34
|
+
m = self._get_value(self.inputs["mass_flow_rate"], "mass_flow_rate")
|
|
35
|
+
latent = self._get_value(self.inputs["latent_heat"], "latent_heat")
|
|
36
|
+
return HeatFlow(abs(m * latent), "W")
|
|
37
|
+
|
|
38
|
+
|
|
39
|
+
class KernNusselt(CalculationBase):
|
|
40
|
+
"""Nu = 0.023 * Re^0.8 * Pr^n."""
|
|
41
|
+
|
|
42
|
+
def validate_inputs(self):
|
|
43
|
+
required = ["reynolds", "prandtl"]
|
|
44
|
+
for key in required:
|
|
45
|
+
if key not in self.inputs:
|
|
46
|
+
raise ValueError(f"Missing required input: {key}")
|
|
47
|
+
|
|
48
|
+
def calculate(self):
|
|
49
|
+
re = self._get_value(self.inputs["reynolds"], "reynolds")
|
|
50
|
+
pr = self._get_value(self.inputs["prandtl"], "prandtl")
|
|
51
|
+
n = self.inputs.get("n", 0.4)
|
|
52
|
+
return 0.023 * (re ** 0.8) * (pr ** n)
|
|
53
|
+
|
|
54
|
+
|
|
55
|
+
class ConvectiveCoefficient(CalculationBase):
|
|
56
|
+
"""h = Nu * k / D."""
|
|
57
|
+
|
|
58
|
+
def validate_inputs(self):
|
|
59
|
+
required = ["nusselt", "thermal_conductivity", "characteristic_diameter"]
|
|
60
|
+
for key in required:
|
|
61
|
+
if key not in self.inputs:
|
|
62
|
+
raise ValueError(f"Missing required input: {key}")
|
|
63
|
+
|
|
64
|
+
def calculate(self):
|
|
65
|
+
nu = self._get_value(self.inputs["nusselt"], "nusselt")
|
|
66
|
+
k = self._get_value(self.inputs["thermal_conductivity"], "thermal_conductivity")
|
|
67
|
+
d = self._get_value(self.inputs["characteristic_diameter"], "characteristic_diameter")
|
|
68
|
+
return HeatTransferCoefficient((nu * k) / d, "W/m2K")
|
|
69
|
+
|
|
70
|
+
|
|
71
|
+
class DarcyPressureDrop(CalculationBase):
|
|
72
|
+
"""dP = f * (L / D) * (rho * v^2 / 2)."""
|
|
73
|
+
|
|
74
|
+
def validate_inputs(self):
|
|
75
|
+
required = ["friction_factor", "length", "diameter", "density", "velocity"]
|
|
76
|
+
for key in required:
|
|
77
|
+
if key not in self.inputs:
|
|
78
|
+
raise ValueError(f"Missing required input: {key}")
|
|
79
|
+
|
|
80
|
+
def calculate(self):
|
|
81
|
+
f = self._get_value(self.inputs["friction_factor"], "friction_factor")
|
|
82
|
+
length = self._get_value(self.inputs["length"], "length")
|
|
83
|
+
diameter = self._get_value(self.inputs["diameter"], "diameter")
|
|
84
|
+
rho = self._get_value(self.inputs["density"], "density")
|
|
85
|
+
vel = self._get_value(self.inputs["velocity"], "velocity")
|
|
86
|
+
return Pressure(f * (length / diameter) * (rho * vel * vel / 2.0), "Pa")
|
|
87
|
+
|
|
88
|
+
|
|
89
|
+
class ReynoldsFromProperties(CalculationBase):
|
|
90
|
+
"""Re = rho * v * D / mu."""
|
|
91
|
+
|
|
92
|
+
def validate_inputs(self):
|
|
93
|
+
required = ["density", "velocity", "diameter", "viscosity"]
|
|
94
|
+
for key in required:
|
|
95
|
+
if key not in self.inputs:
|
|
96
|
+
raise ValueError(f"Missing required input: {key}")
|
|
97
|
+
|
|
98
|
+
def calculate(self):
|
|
99
|
+
rho = self._get_value(self.inputs["density"], "density")
|
|
100
|
+
vel = self._get_value(self.inputs["velocity"], "velocity")
|
|
101
|
+
dia = self._get_value(self.inputs["diameter"], "diameter")
|
|
102
|
+
mu = self._get_value(self.inputs["viscosity"], "viscosity")
|
|
103
|
+
return (rho * vel * dia) / mu
|
{processpi-0.2.0.4 → processpi-0.2.1}/processpi/calculations/heat_transfer/heat_exchanger_area.py
RENAMED
|
@@ -14,7 +14,9 @@ class HeatExchangerArea(CalculationBase):
|
|
|
14
14
|
for key in required:
|
|
15
15
|
if key not in self.inputs:
|
|
16
16
|
raise ValueError(f"Missing required input: {key}")
|
|
17
|
-
|
|
17
|
+
dtlm = self.inputs["log_mean_temp_diff"]
|
|
18
|
+
dtlm_val = dtlm.value if hasattr(dtlm, "value") else float(dtlm)
|
|
19
|
+
if dtlm_val <= 0:
|
|
18
20
|
raise ValueError("Log mean temperature difference must be positive")
|
|
19
21
|
|
|
20
22
|
def calculate(self):
|
|
@@ -0,0 +1,266 @@
|
|
|
1
|
+
from __future__ import annotations
|
|
2
|
+
|
|
3
|
+
import math
|
|
4
|
+
|
|
5
|
+
from ..base import CalculationBase
|
|
6
|
+
from ...units import HeatFlow, HeatTransferCoefficient, Pressure
|
|
7
|
+
|
|
8
|
+
|
|
9
|
+
class SensibleDuty(CalculationBase):
|
|
10
|
+
def validate_inputs(self):
|
|
11
|
+
for key in ("m_dot", "cp", "t_in", "t_out"):
|
|
12
|
+
if key not in self.inputs:
|
|
13
|
+
raise ValueError(f"Missing required input: {key}")
|
|
14
|
+
|
|
15
|
+
def calculate(self):
|
|
16
|
+
m = self._get_value(self.inputs["m_dot"], "m_dot")
|
|
17
|
+
cp = self._get_value(self.inputs["cp"], "cp")
|
|
18
|
+
t_in = self._get_value(self.inputs["t_in"], "t_in")
|
|
19
|
+
t_out = self._get_value(self.inputs["t_out"], "t_out")
|
|
20
|
+
return HeatFlow(abs(m * cp * (t_in - t_out)), "W")
|
|
21
|
+
|
|
22
|
+
|
|
23
|
+
class LatentDuty(CalculationBase):
|
|
24
|
+
def validate_inputs(self):
|
|
25
|
+
for key in ("m_dot", "latent_heat"):
|
|
26
|
+
if key not in self.inputs:
|
|
27
|
+
raise ValueError(f"Missing required input: {key}")
|
|
28
|
+
|
|
29
|
+
def calculate(self):
|
|
30
|
+
m = self._get_value(self.inputs["m_dot"], "m_dot")
|
|
31
|
+
latent = self._get_value(self.inputs["latent_heat"], "latent_heat")
|
|
32
|
+
return HeatFlow(abs(m * latent), "W")
|
|
33
|
+
|
|
34
|
+
|
|
35
|
+
class Reynolds(CalculationBase):
|
|
36
|
+
def validate_inputs(self):
|
|
37
|
+
for key in ("density", "velocity", "diameter", "viscosity"):
|
|
38
|
+
if key not in self.inputs:
|
|
39
|
+
raise ValueError(f"Missing required input: {key}")
|
|
40
|
+
|
|
41
|
+
def calculate(self):
|
|
42
|
+
rho = self._get_value(self.inputs["density"], "density")
|
|
43
|
+
v = self._get_value(self.inputs["velocity"], "velocity")
|
|
44
|
+
d = self._get_value(self.inputs["diameter"], "diameter")
|
|
45
|
+
mu = self._get_value(self.inputs["viscosity"], "viscosity")
|
|
46
|
+
return (rho * v * d) / mu
|
|
47
|
+
|
|
48
|
+
|
|
49
|
+
class DittusBoelter(CalculationBase):
|
|
50
|
+
def validate_inputs(self):
|
|
51
|
+
for key in ("reynolds", "prandtl"):
|
|
52
|
+
if key not in self.inputs:
|
|
53
|
+
raise ValueError(f"Missing required input: {key}")
|
|
54
|
+
|
|
55
|
+
def calculate(self):
|
|
56
|
+
re = self._get_value(self.inputs["reynolds"], "reynolds")
|
|
57
|
+
pr = self._get_value(self.inputs["prandtl"], "prandtl")
|
|
58
|
+
n = self.inputs.get("n", 0.4)
|
|
59
|
+
return 0.023 * re**0.8 * pr**n
|
|
60
|
+
|
|
61
|
+
class KernShellNu(CalculationBase):
|
|
62
|
+
def validate_inputs(self):
|
|
63
|
+
for key in ("reynolds", "prandtl"):
|
|
64
|
+
if key not in self.inputs:
|
|
65
|
+
raise ValueError(f"Missing required input: {key}")
|
|
66
|
+
|
|
67
|
+
def calculate(self):
|
|
68
|
+
re = self._get_value(self.inputs["reynolds"], "reynolds")
|
|
69
|
+
pr = self._get_value(self.inputs["prandtl"], "prandtl")
|
|
70
|
+
return 0.36 * re**0.55 * pr**(1 / 3)
|
|
71
|
+
|
|
72
|
+
|
|
73
|
+
class ConvectiveH(CalculationBase):
|
|
74
|
+
def validate_inputs(self):
|
|
75
|
+
for key in ("nusselt", "k", "diameter"):
|
|
76
|
+
if key not in self.inputs:
|
|
77
|
+
raise ValueError(f"Missing required input: {key}")
|
|
78
|
+
|
|
79
|
+
def calculate(self):
|
|
80
|
+
nu = self._get_value(self.inputs["nusselt"], "nusselt")
|
|
81
|
+
k = self._get_value(self.inputs["k"], "k")
|
|
82
|
+
d = self._get_value(self.inputs["diameter"], "diameter")
|
|
83
|
+
return HeatTransferCoefficient((nu * k) / d, "W/m2K")
|
|
84
|
+
|
|
85
|
+
|
|
86
|
+
class TubeCountFromArea(CalculationBase):
|
|
87
|
+
def validate_inputs(self):
|
|
88
|
+
for key in ("area", "tube_od", "tube_length"):
|
|
89
|
+
if key not in self.inputs:
|
|
90
|
+
raise ValueError(f"Missing required input: {key}")
|
|
91
|
+
|
|
92
|
+
def calculate(self):
|
|
93
|
+
area = self._get_value(self.inputs["area"], "area")
|
|
94
|
+
d_o = self._get_value(self.inputs["tube_od"], "tube_od")
|
|
95
|
+
l_t = self._get_value(self.inputs["tube_length"], "tube_length")
|
|
96
|
+
return max(1, math.ceil(area / (math.pi * d_o * l_t)))
|
|
97
|
+
|
|
98
|
+
|
|
99
|
+
class ShellDiameterEstimate(CalculationBase):
|
|
100
|
+
def validate_inputs(self):
|
|
101
|
+
for key in ("tube_count", "tube_pitch"):
|
|
102
|
+
if key not in self.inputs:
|
|
103
|
+
raise ValueError(f"Missing required input: {key}")
|
|
104
|
+
|
|
105
|
+
def calculate(self):
|
|
106
|
+
n_t = self._get_value(self.inputs["tube_count"], "tube_count")
|
|
107
|
+
p_t = self._get_value(self.inputs["tube_pitch"], "tube_pitch")
|
|
108
|
+
return 0.637 * p_t * (n_t ** 0.5)
|
|
109
|
+
|
|
110
|
+
|
|
111
|
+
class DarcyDrop(CalculationBase):
|
|
112
|
+
def validate_inputs(self):
|
|
113
|
+
for key in ("f", "length", "diameter", "density", "velocity"):
|
|
114
|
+
if key not in self.inputs:
|
|
115
|
+
raise ValueError(f"Missing required input: {key}")
|
|
116
|
+
|
|
117
|
+
def calculate(self):
|
|
118
|
+
f = self._get_value(self.inputs["f"], "f")
|
|
119
|
+
l = self._get_value(self.inputs["length"], "length")
|
|
120
|
+
d = self._get_value(self.inputs["diameter"], "diameter")
|
|
121
|
+
rho = self._get_value(self.inputs["density"], "density")
|
|
122
|
+
v = self._get_value(self.inputs["velocity"], "velocity")
|
|
123
|
+
return Pressure(f * (l / d) * rho * v * v / 2.0, "Pa")
|
|
124
|
+
|
|
125
|
+
|
|
126
|
+
class CondensationHTC(CalculationBase):
|
|
127
|
+
"""
|
|
128
|
+
Nusselt film condensation correlation
|
|
129
|
+
for vertical tube condensation.
|
|
130
|
+
|
|
131
|
+
Preliminary engineering approximation.
|
|
132
|
+
"""
|
|
133
|
+
|
|
134
|
+
def validate_inputs(self):
|
|
135
|
+
|
|
136
|
+
required = (
|
|
137
|
+
"rho_l",
|
|
138
|
+
"rho_v",
|
|
139
|
+
"mu_l",
|
|
140
|
+
"k_l",
|
|
141
|
+
"h_fg",
|
|
142
|
+
"delta_t",
|
|
143
|
+
"length",
|
|
144
|
+
)
|
|
145
|
+
|
|
146
|
+
for key in required:
|
|
147
|
+
|
|
148
|
+
if key not in self.inputs:
|
|
149
|
+
|
|
150
|
+
raise ValueError(
|
|
151
|
+
f"Missing required input: {key}"
|
|
152
|
+
)
|
|
153
|
+
|
|
154
|
+
def calculate(self):
|
|
155
|
+
|
|
156
|
+
rho_l = self._get_value(
|
|
157
|
+
self.inputs["rho_l"],
|
|
158
|
+
"rho_l",
|
|
159
|
+
)
|
|
160
|
+
|
|
161
|
+
rho_v = self._get_value(
|
|
162
|
+
self.inputs["rho_v"],
|
|
163
|
+
"rho_v",
|
|
164
|
+
)
|
|
165
|
+
|
|
166
|
+
mu_l = self._get_value(
|
|
167
|
+
self.inputs["mu_l"],
|
|
168
|
+
"mu_l",
|
|
169
|
+
)
|
|
170
|
+
|
|
171
|
+
k_l = self._get_value(
|
|
172
|
+
self.inputs["k_l"],
|
|
173
|
+
"k_l",
|
|
174
|
+
)
|
|
175
|
+
|
|
176
|
+
h_fg = self._get_value(
|
|
177
|
+
self.inputs["h_fg"],
|
|
178
|
+
"h_fg",
|
|
179
|
+
)
|
|
180
|
+
|
|
181
|
+
delta_t = self._get_value(
|
|
182
|
+
self.inputs["delta_t"],
|
|
183
|
+
"delta_t",
|
|
184
|
+
)
|
|
185
|
+
|
|
186
|
+
length = self._get_value(
|
|
187
|
+
self.inputs["length"],
|
|
188
|
+
"length",
|
|
189
|
+
)
|
|
190
|
+
|
|
191
|
+
g = 9.81
|
|
192
|
+
|
|
193
|
+
h = 0.943 * (
|
|
194
|
+
(
|
|
195
|
+
rho_l
|
|
196
|
+
* (rho_l - rho_v)
|
|
197
|
+
* g
|
|
198
|
+
* h_fg
|
|
199
|
+
* (k_l ** 3)
|
|
200
|
+
)
|
|
201
|
+
/ (
|
|
202
|
+
mu_l
|
|
203
|
+
* length
|
|
204
|
+
* delta_t
|
|
205
|
+
)
|
|
206
|
+
) ** 0.25
|
|
207
|
+
|
|
208
|
+
return HeatTransferCoefficient(
|
|
209
|
+
h,
|
|
210
|
+
"W/m2K",
|
|
211
|
+
)
|
|
212
|
+
|
|
213
|
+
class BoilingHTC(CalculationBase):
|
|
214
|
+
"""
|
|
215
|
+
Simplified boiling heat-transfer coefficient.
|
|
216
|
+
|
|
217
|
+
Preliminary engineering approximation.
|
|
218
|
+
"""
|
|
219
|
+
|
|
220
|
+
def validate_inputs(self):
|
|
221
|
+
|
|
222
|
+
required = (
|
|
223
|
+
"heat_flux",
|
|
224
|
+
"pressure",
|
|
225
|
+
)
|
|
226
|
+
|
|
227
|
+
for key in required:
|
|
228
|
+
|
|
229
|
+
if key not in self.inputs:
|
|
230
|
+
|
|
231
|
+
raise ValueError(
|
|
232
|
+
f"Missing required input: {key}"
|
|
233
|
+
)
|
|
234
|
+
|
|
235
|
+
def calculate(self):
|
|
236
|
+
|
|
237
|
+
q_flux = self._get_value(
|
|
238
|
+
self.inputs["heat_flux"],
|
|
239
|
+
"heat_flux",
|
|
240
|
+
)
|
|
241
|
+
|
|
242
|
+
pressure = self._get_value(
|
|
243
|
+
self.inputs["pressure"],
|
|
244
|
+
"pressure",
|
|
245
|
+
)
|
|
246
|
+
|
|
247
|
+
# ======================================================
|
|
248
|
+
# SIMPLE ENGINEERING APPROXIMATION
|
|
249
|
+
# ======================================================
|
|
250
|
+
|
|
251
|
+
h = (
|
|
252
|
+
55.0
|
|
253
|
+
* (q_flux ** 0.67)
|
|
254
|
+
* (pressure ** 0.12)
|
|
255
|
+
)
|
|
256
|
+
|
|
257
|
+
# prevent unrealistic values
|
|
258
|
+
h = max(
|
|
259
|
+
1500.0,
|
|
260
|
+
min(h, 15000.0),
|
|
261
|
+
)
|
|
262
|
+
|
|
263
|
+
return HeatTransferCoefficient(
|
|
264
|
+
h,
|
|
265
|
+
"W/m2K",
|
|
266
|
+
)
|
|
@@ -14,9 +14,22 @@ class LMTD(CalculationBase):
|
|
|
14
14
|
raise ValueError(f"Missing required input: {key}")
|
|
15
15
|
|
|
16
16
|
def calculate(self):
|
|
17
|
+
eps = 1e-6
|
|
17
18
|
|
|
18
19
|
dT1 = self._get_value(self.inputs["dT1"], "temperature")
|
|
19
20
|
dT2 = self._get_value(self.inputs["dT2"], "temperature")
|
|
20
21
|
|
|
21
|
-
|
|
22
|
-
|
|
22
|
+
if dT1 <= 0 or dT2 <= 0:
|
|
23
|
+
raise ValueError("Invalid temperature approach in LMTD calculation.")
|
|
24
|
+
|
|
25
|
+
dT1 = max(dT1, eps)
|
|
26
|
+
dT2 = max(dT2, eps)
|
|
27
|
+
|
|
28
|
+
if abs(dT1 - dT2) < eps:
|
|
29
|
+
return dT1
|
|
30
|
+
|
|
31
|
+
ratio = dT1 / dT2
|
|
32
|
+
if ratio <= 0:
|
|
33
|
+
raise ValueError("Invalid temperature approach in LMTD calculation.")
|
|
34
|
+
|
|
35
|
+
return (dT1 - dT2) / math.log(ratio)
|
|
@@ -44,8 +44,9 @@ class Component(ABC):
|
|
|
44
44
|
vapor_pressure: Pressure = None,
|
|
45
45
|
enthalpy: HeatOfVaporization = None,
|
|
46
46
|
):
|
|
47
|
-
self.temperature = temperature or Temperature(
|
|
47
|
+
self.temperature = temperature or Temperature(25, "C")
|
|
48
48
|
self.pressure = pressure or Pressure(101325, "Pa")
|
|
49
|
+
self.hx_type = getattr(self, "hx_type", self._infer_hx_type())
|
|
49
50
|
|
|
50
51
|
self._density = density
|
|
51
52
|
self._specific_heat = specific_heat
|
|
@@ -54,6 +55,18 @@ class Component(ABC):
|
|
|
54
55
|
self._vapor_pressure = vapor_pressure
|
|
55
56
|
self._enthalpy = enthalpy
|
|
56
57
|
|
|
58
|
+
def _infer_hx_type(self) -> str:
|
|
59
|
+
"""Infer a default heat-exchanger fluid category for U standards lookup."""
|
|
60
|
+
name = getattr(self, "name", "").lower()
|
|
61
|
+
class_name = self.__class__.__name__.lower()
|
|
62
|
+
if "water" in name or "water" in class_name:
|
|
63
|
+
return "water"
|
|
64
|
+
if "air" in name or "steam" in name or "vapor" in class_name or "gas" in class_name:
|
|
65
|
+
return "gas_low_pressure"
|
|
66
|
+
if "oil" in name or "oil" in class_name:
|
|
67
|
+
return "heavy_oil"
|
|
68
|
+
return "organic"
|
|
69
|
+
|
|
57
70
|
# ----------------------------------------------------------------------
|
|
58
71
|
# Abstract Properties
|
|
59
72
|
# ----------------------------------------------------------------------
|
|
@@ -120,10 +133,22 @@ class Component(ABC):
|
|
|
120
133
|
def specific_heat(self) -> SpecificHeat:
|
|
121
134
|
if self._specific_heat is not None:
|
|
122
135
|
return self._specific_heat
|
|
123
|
-
|
|
124
|
-
|
|
136
|
+
|
|
137
|
+
# ✅ Always use Kelvin
|
|
138
|
+
T = self.temperature.to("K").value
|
|
139
|
+
|
|
140
|
+
a, b, c, d, e = self._specific_heat_constants
|
|
141
|
+
|
|
142
|
+
# Cp in J/kmol·K
|
|
143
|
+
cp_kmol = a + b*T + c*(T**2) + d*(T**3) + e*(T**4)
|
|
144
|
+
|
|
145
|
+
# ✅ Convert to J/kg·K
|
|
125
146
|
cp_kg = cp_kmol / self.molecular_weight
|
|
126
|
-
|
|
147
|
+
|
|
148
|
+
# ✅ Safety check
|
|
149
|
+
if cp_kg < 0 or cp_kg > 10000:
|
|
150
|
+
raise ValueError(f"Unphysical Cp detected: {cp_kg} J/kgK")
|
|
151
|
+
|
|
127
152
|
return SpecificHeat(cp_kg, "J/kgK")
|
|
128
153
|
|
|
129
154
|
|
|
@@ -192,13 +217,34 @@ class Component(ABC):
|
|
|
192
217
|
def enthalpy(self) -> HeatOfVaporization:
|
|
193
218
|
if self._enthalpy is not None:
|
|
194
219
|
return self._enthalpy
|
|
195
|
-
|
|
196
|
-
|
|
220
|
+
|
|
221
|
+
T = self.temperature.to("K").value
|
|
222
|
+
Tc = self._critical_temperature.to("K").value
|
|
223
|
+
|
|
224
|
+
# Guard: above critical → no vaporization
|
|
225
|
+
if T >= Tc:
|
|
226
|
+
return HeatOfVaporization(0.0, "J/kg")
|
|
227
|
+
|
|
228
|
+
Tr = T / Tc
|
|
197
229
|
tau = 1 - Tr
|
|
198
|
-
|
|
199
|
-
|
|
200
|
-
|
|
201
|
-
|
|
202
|
-
|
|
203
|
-
#
|
|
230
|
+
|
|
231
|
+
C1, C2, C3, C4, C5 = self._enthalpy_constants
|
|
232
|
+
|
|
233
|
+
exponent = C2 + C3*Tr + C4*(Tr**2) + C5*(Tr**3)
|
|
234
|
+
|
|
235
|
+
# Base calculation
|
|
236
|
+
dH = C1 * (tau ** exponent)
|
|
237
|
+
|
|
238
|
+
# 🔥 AUTO FIX: detect wrong C1 scale
|
|
239
|
+
# If value is too small → scale up
|
|
240
|
+
if dH < 1: # clearly wrong (should be ~1e5–1e6)
|
|
241
|
+
dH *= 1e14
|
|
242
|
+
|
|
243
|
+
# Convert kmol → kg
|
|
244
|
+
dH = dH / self.molecular_weight
|
|
245
|
+
|
|
246
|
+
# Safety
|
|
247
|
+
if dH < 0 or isinstance(dH, complex):
|
|
248
|
+
dH = 0.0
|
|
249
|
+
|
|
204
250
|
return HeatOfVaporization(dH, "J/kg")
|
|
@@ -11,6 +11,7 @@ class Benzene(Component):
|
|
|
11
11
|
and constants for various property calculations.
|
|
12
12
|
"""
|
|
13
13
|
name = "Benzene"
|
|
14
|
+
hx_type = "organic"
|
|
14
15
|
formula = "C6H6"
|
|
15
16
|
molecular_weight = 78.114
|
|
16
17
|
# Critical properties of Benzene. These are essential reference points for
|
|
@@ -67,11 +68,17 @@ class Benzene(Component):
|
|
|
67
68
|
|
|
68
69
|
return SpecificHeat(cp_kg, "J/kgK")
|
|
69
70
|
|
|
71
|
+
def hx_data(self):
|
|
72
|
+
p = self.pressure.to("Pa").value
|
|
73
|
+
pvap = self.vapor_pressure().to("Pa").value
|
|
74
|
+
phase = "vapor" if p < pvap else "liquid"
|
|
75
|
+
return {"family": "organic", "phase": phase, "velocity_key": "benzene", "u_key": "organic", "fouling_key": "hydrocarbons", "corrosion_key": "hydrocarbon"}
|
|
76
|
+
|
|
70
77
|
def httype(self):
|
|
71
78
|
P = self.pressure.to("Pa").value
|
|
72
79
|
Pvap = self.vapor_pressure().to("Pa").value
|
|
73
80
|
if P < Pvap:
|
|
74
|
-
httype = "
|
|
81
|
+
httype = "vapor"
|
|
75
82
|
else:
|
|
76
|
-
httype = "
|
|
77
|
-
return httype
|
|
83
|
+
httype = "organic"
|
|
84
|
+
return httype
|
|
@@ -24,5 +24,5 @@ class CarbonMonoxide(Component):
|
|
|
24
24
|
T = self.temperature.value
|
|
25
25
|
Tr = T / self._critical_temperature.value
|
|
26
26
|
t = 1 - Tr
|
|
27
|
-
cp = (self.
|
|
27
|
+
cp = (self._specific_heat_constants[0] / t ) + (self._specific_heat_constants[1]) - ( 2 * self._specific_heat_constants[0] * self._specific_heat_constants[2] * t) - (self._specific_heat_constants[0] * self._specific_heat_constants[3] * (t**2)) - ((self._specific_heat_constants[2]**2)*(t**3)/3) - ((self._specific_heat_constants[2] * self._specific_heat_constants[3] * (t**4))/2) - ((self._specific_heat_constants[0]**2) * (t**5)/5)
|
|
28
28
|
return SpecificHeat(cp, "J/kgK")
|