processpi 0.1.2.11__tar.gz → 0.2.0__tar.gz
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- {processpi-0.1.2.11 → processpi-0.2.0}/PKG-INFO +16 -2
- {processpi-0.1.2.11 → processpi-0.2.0}/README.md +15 -1
- {processpi-0.1.2.11 → processpi-0.2.0}/processpi/calculations/fluids/friction_factor_colebrookwhite.py +18 -26
- {processpi-0.1.2.11 → processpi-0.2.0}/processpi/calculations/fluids/pressure_drop_darcy.py +1 -1
- {processpi-0.1.2.11 → processpi-0.2.0}/processpi/calculations/fluids/reynolds_number.py +1 -1
- processpi-0.2.0/processpi/calculations/heat_transfer/biot.py +21 -0
- processpi-0.2.0/processpi/calculations/heat_transfer/boiling_chen.py +41 -0
- processpi-0.2.0/processpi/calculations/heat_transfer/combined_modes.py +45 -0
- processpi-0.2.0/processpi/calculations/heat_transfer/condensation.py +46 -0
- processpi-0.2.0/processpi/calculations/heat_transfer/condensation_dropwise.py +35 -0
- processpi-0.2.0/processpi/calculations/heat_transfer/condensation_nusselt.py +52 -0
- processpi-0.2.0/processpi/calculations/heat_transfer/crossflow_tube.py +34 -0
- processpi-0.2.0/processpi/calculations/heat_transfer/fourier.py +22 -0
- processpi-0.2.0/processpi/calculations/heat_transfer/fourierlaw.py +40 -0
- processpi-0.2.0/processpi/calculations/heat_transfer/grashof.py +24 -0
- processpi-0.2.0/processpi/calculations/heat_transfer/lmtd.py +23 -0
- processpi-0.2.0/processpi/calculations/heat_transfer/newton_cooling.py +40 -0
- processpi-0.2.0/processpi/calculations/heat_transfer/ntu.py +21 -0
- processpi-0.2.0/processpi/calculations/heat_transfer/nusselt.py +21 -0
- processpi-0.2.0/processpi/calculations/heat_transfer/overall_u.py +16 -0
- processpi-0.2.0/processpi/calculations/heat_transfer/peclet.py +26 -0
- processpi-0.2.0/processpi/calculations/heat_transfer/prandtl.py +21 -0
- processpi-0.2.0/processpi/calculations/heat_transfer/radial_cylinder.py +39 -0
- processpi-0.2.0/processpi/calculations/heat_transfer/radiation_blackbody.py +31 -0
- processpi-0.2.0/processpi/calculations/heat_transfer/radiation_exchange.py +41 -0
- processpi-0.2.0/processpi/calculations/heat_transfer/radiation_greybody.py +35 -0
- processpi-0.2.0/processpi/calculations/heat_transfer/radiation_viewfactor.py +41 -0
- processpi-0.2.0/processpi/calculations/heat_transfer/resistance.py +29 -0
- processpi-0.2.0/processpi/calculations/heat_transfer/reyleigh.py +21 -0
- processpi-0.2.0/processpi/calculations/heat_transfer/rohsenow_boiling.py +62 -0
- processpi-0.2.0/processpi/calculations/heat_transfer/stefan_boltzmann.py +44 -0
- {processpi-0.1.2.11 → processpi-0.2.0}/processpi/pipelines/__init__.py +1 -1
- {processpi-0.1.2.11 → processpi-0.2.0}/processpi/pipelines/engine.py +218 -232
- {processpi-0.1.2.11 → processpi-0.2.0}/processpi/pipelines/pipelineresults.py +86 -22
- {processpi-0.1.2.11 → processpi-0.2.0}/processpi/pipelines/pipes.py +1 -0
- {processpi-0.1.2.11 → processpi-0.2.0}/processpi/pipelines/standards.py +73 -3
- processpi-0.2.0/processpi/units/__init__.py +67 -0
- processpi-0.2.0/processpi/units/heat_flow.py +53 -0
- {processpi-0.1.2.11 → processpi-0.2.0}/processpi.egg-info/PKG-INFO +16 -2
- {processpi-0.1.2.11 → processpi-0.2.0}/processpi.egg-info/SOURCES.txt +27 -0
- {processpi-0.1.2.11 → processpi-0.2.0}/pyproject.toml +3 -1
- {processpi-0.1.2.11 → processpi-0.2.0}/setup.py +1 -1
- {processpi-0.1.2.11 → processpi-0.2.0}/tests/test_engine_network.py +1 -78
- processpi-0.2.0/tests/test_pipeline_network.py +739 -0
- processpi-0.1.2.11/processpi/units/__init__.py +0 -40
- processpi-0.1.2.11/tests/test_pipeline_network.py +0 -416
- {processpi-0.1.2.11 → processpi-0.2.0}/LICENSE +0 -0
- {processpi-0.1.2.11 → processpi-0.2.0}/processpi/__init__.py +0 -0
- {processpi-0.1.2.11 → processpi-0.2.0}/processpi/calculations/__init__.py +0 -0
- {processpi-0.1.2.11 → processpi-0.2.0}/processpi/calculations/base.py +0 -0
- {processpi-0.1.2.11 → processpi-0.2.0}/processpi/calculations/engine.py +0 -0
- {processpi-0.1.2.11 → processpi-0.2.0}/processpi/calculations/fluids/__init__.py +0 -0
- {processpi-0.1.2.11 → processpi-0.2.0}/processpi/calculations/fluids/flow_type.py +0 -0
- {processpi-0.1.2.11 → processpi-0.2.0}/processpi/calculations/fluids/optimium_pipe_dia.py +0 -0
- {processpi-0.1.2.11 → processpi-0.2.0}/processpi/calculations/fluids/pressure_drop_fanning.py +0 -0
- {processpi-0.1.2.11 → processpi-0.2.0}/processpi/calculations/fluids/pressure_drop_hazen_williams.py +0 -0
- {processpi-0.1.2.11 → processpi-0.2.0}/processpi/calculations/fluids/pump_power.py +0 -0
- {processpi-0.1.2.11 → processpi-0.2.0}/processpi/calculations/fluids/velocity.py +0 -0
- {processpi-0.1.2.11 → processpi-0.2.0}/processpi/calculations/heat_transfer/__init__.py +0 -0
- {processpi-0.1.2.11 → processpi-0.2.0}/processpi/calculations/heat_transfer/conduction_heat_loss.py +0 -0
- {processpi-0.1.2.11 → processpi-0.2.0}/processpi/calculations/heat_transfer/convection_heat_loss.py +0 -0
- {processpi-0.1.2.11 → processpi-0.2.0}/processpi/calculations/heat_transfer/heat_exchanger_area.py +0 -0
- {processpi-0.1.2.11 → processpi-0.2.0}/processpi/calculations/mass_transfer/__init__.py +0 -0
- {processpi-0.1.2.11 → processpi-0.2.0}/processpi/calculations/mass_transfer/distillation_stage_count.py +0 -0
- {processpi-0.1.2.11 → processpi-0.2.0}/processpi/calculations/mass_transfer/drying_rate.py +0 -0
- {processpi-0.1.2.11 → processpi-0.2.0}/processpi/calculations/reaction_engineering/__init__.py +0 -0
- {processpi-0.1.2.11 → processpi-0.2.0}/processpi/calculations/reaction_engineering/catalyst_activity.py +0 -0
- {processpi-0.1.2.11 → processpi-0.2.0}/processpi/calculations/reaction_engineering/reaction_rate.py +0 -0
- {processpi-0.1.2.11 → processpi-0.2.0}/processpi/calculations/reaction_engineering/residence_time.py +0 -0
- {processpi-0.1.2.11 → processpi-0.2.0}/processpi/calculations/thermodynamics/__init__.py +0 -0
- {processpi-0.1.2.11 → processpi-0.2.0}/processpi/calculations/thermodynamics/enthalpy_change.py +0 -0
- {processpi-0.1.2.11 → processpi-0.2.0}/processpi/calculations/thermodynamics/entropy_change.py +0 -0
- {processpi-0.1.2.11 → processpi-0.2.0}/processpi/calculations/thermodynamics/heat_of_vaporization.py +0 -0
- {processpi-0.1.2.11 → processpi-0.2.0}/processpi/components/__init__.py +0 -0
- {processpi-0.1.2.11 → processpi-0.2.0}/processpi/components/aceticacid.py +0 -0
- {processpi-0.1.2.11 → processpi-0.2.0}/processpi/components/acetone.py +0 -0
- {processpi-0.1.2.11 → processpi-0.2.0}/processpi/components/acrylicacid.py +0 -0
- {processpi-0.1.2.11 → processpi-0.2.0}/processpi/components/air.py +0 -0
- {processpi-0.1.2.11 → processpi-0.2.0}/processpi/components/ammonia.py +0 -0
- {processpi-0.1.2.11 → processpi-0.2.0}/processpi/components/base.py +0 -0
- {processpi-0.1.2.11 → processpi-0.2.0}/processpi/components/benzene.py +0 -0
- {processpi-0.1.2.11 → processpi-0.2.0}/processpi/components/benzoicacid.py +0 -0
- {processpi-0.1.2.11 → processpi-0.2.0}/processpi/components/bromine.py +0 -0
- {processpi-0.1.2.11 → processpi-0.2.0}/processpi/components/butane.py +0 -0
- {processpi-0.1.2.11 → processpi-0.2.0}/processpi/components/carbondioxide.py +0 -0
- {processpi-0.1.2.11 → processpi-0.2.0}/processpi/components/carbonmonoxide.py +0 -0
- {processpi-0.1.2.11 → processpi-0.2.0}/processpi/components/carbontetrachloride.py +0 -0
- {processpi-0.1.2.11 → processpi-0.2.0}/processpi/components/chlorine.py +0 -0
- {processpi-0.1.2.11 → processpi-0.2.0}/processpi/components/chlorobenzene.py +0 -0
- {processpi-0.1.2.11 → processpi-0.2.0}/processpi/components/chloroform.py +0 -0
- {processpi-0.1.2.11 → processpi-0.2.0}/processpi/components/chloromethane.py +0 -0
- {processpi-0.1.2.11 → processpi-0.2.0}/processpi/components/constants.py +0 -0
- {processpi-0.1.2.11 → processpi-0.2.0}/processpi/components/cyanogen.py +0 -0
- {processpi-0.1.2.11 → processpi-0.2.0}/processpi/components/cyclohexene.py +0 -0
- {processpi-0.1.2.11 → processpi-0.2.0}/processpi/components/ethane.py +0 -0
- {processpi-0.1.2.11 → processpi-0.2.0}/processpi/components/ethanol.py +0 -0
- {processpi-0.1.2.11 → processpi-0.2.0}/processpi/components/ethylacetate.py +0 -0
- {processpi-0.1.2.11 → processpi-0.2.0}/processpi/components/gas.py +0 -0
- {processpi-0.1.2.11 → processpi-0.2.0}/processpi/components/inorganic_liquid.py +0 -0
- {processpi-0.1.2.11 → processpi-0.2.0}/processpi/components/methanol.py +0 -0
- {processpi-0.1.2.11 → processpi-0.2.0}/processpi/components/oil.py +0 -0
- {processpi-0.1.2.11 → processpi-0.2.0}/processpi/components/organic_liquid.py +0 -0
- {processpi-0.1.2.11 → processpi-0.2.0}/processpi/components/steam.py +0 -0
- {processpi-0.1.2.11 → processpi-0.2.0}/processpi/components/toluene.py +0 -0
- {processpi-0.1.2.11 → processpi-0.2.0}/processpi/components/vapor.py +0 -0
- {processpi-0.1.2.11 → processpi-0.2.0}/processpi/components/water.py +0 -0
- {processpi-0.1.2.11 → processpi-0.2.0}/processpi/constants.py +0 -0
- {processpi-0.1.2.11 → processpi-0.2.0}/processpi/pipelines/base.py +0 -0
- {processpi-0.1.2.11 → processpi-0.2.0}/processpi/pipelines/design_rules.py +0 -0
- {processpi-0.1.2.11 → processpi-0.2.0}/processpi/pipelines/equipment.py +0 -0
- {processpi-0.1.2.11 → processpi-0.2.0}/processpi/pipelines/fittings.py +0 -0
- {processpi-0.1.2.11 → processpi-0.2.0}/processpi/pipelines/insulation.py +0 -0
- {processpi-0.1.2.11 → processpi-0.2.0}/processpi/pipelines/materials.py +0 -0
- {processpi-0.1.2.11 → processpi-0.2.0}/processpi/pipelines/network.py +0 -0
- {processpi-0.1.2.11 → processpi-0.2.0}/processpi/pipelines/nozzle.py +0 -0
- {processpi-0.1.2.11 → processpi-0.2.0}/processpi/pipelines/piping_costs.py +0 -0
- {processpi-0.1.2.11 → processpi-0.2.0}/processpi/pipelines/pumps.py +0 -0
- {processpi-0.1.2.11 → processpi-0.2.0}/processpi/pipelines/selection.py +0 -0
- {processpi-0.1.2.11 → processpi-0.2.0}/processpi/pipelines/vessel.py +0 -0
- {processpi-0.1.2.11 → processpi-0.2.0}/processpi/units/area.py +0 -0
- {processpi-0.1.2.11 → processpi-0.2.0}/processpi/units/base.py +0 -0
- {processpi-0.1.2.11 → processpi-0.2.0}/processpi/units/density.py +0 -0
- {processpi-0.1.2.11 → processpi-0.2.0}/processpi/units/diameter.py +0 -0
- {processpi-0.1.2.11 → processpi-0.2.0}/processpi/units/dimensionless.py +0 -0
- {processpi-0.1.2.11 → processpi-0.2.0}/processpi/units/heat_flux.py +0 -0
- {processpi-0.1.2.11 → processpi-0.2.0}/processpi/units/heat_of_vaporization.py +0 -0
- {processpi-0.1.2.11 → processpi-0.2.0}/processpi/units/heat_transfer_coefficient.py +0 -0
- {processpi-0.1.2.11 → processpi-0.2.0}/processpi/units/length.py +0 -0
- {processpi-0.1.2.11 → processpi-0.2.0}/processpi/units/mass.py +0 -0
- {processpi-0.1.2.11 → processpi-0.2.0}/processpi/units/mass_flowrate.py +0 -0
- {processpi-0.1.2.11 → processpi-0.2.0}/processpi/units/power.py +0 -0
- {processpi-0.1.2.11 → processpi-0.2.0}/processpi/units/pressure.py +0 -0
- {processpi-0.1.2.11 → processpi-0.2.0}/processpi/units/specific_heat.py +0 -0
- {processpi-0.1.2.11 → processpi-0.2.0}/processpi/units/strings.py +0 -0
- {processpi-0.1.2.11 → processpi-0.2.0}/processpi/units/temperature.py +0 -0
- {processpi-0.1.2.11 → processpi-0.2.0}/processpi/units/thermal_conductivity.py +0 -0
- {processpi-0.1.2.11 → processpi-0.2.0}/processpi/units/thermal_resistance.py +0 -0
- {processpi-0.1.2.11 → processpi-0.2.0}/processpi/units/velocity.py +0 -0
- {processpi-0.1.2.11 → processpi-0.2.0}/processpi/units/viscosity.py +0 -0
- {processpi-0.1.2.11 → processpi-0.2.0}/processpi/units/volume.py +0 -0
- {processpi-0.1.2.11 → processpi-0.2.0}/processpi/units/volumetric_flowrate.py +0 -0
- {processpi-0.1.2.11 → processpi-0.2.0}/processpi.egg-info/dependency_links.txt +0 -0
- {processpi-0.1.2.11 → processpi-0.2.0}/processpi.egg-info/requires.txt +0 -0
- {processpi-0.1.2.11 → processpi-0.2.0}/processpi.egg-info/top_level.txt +0 -0
- {processpi-0.1.2.11 → processpi-0.2.0}/setup.cfg +0 -0
- {processpi-0.1.2.11 → processpi-0.2.0}/tests/test_network.py +0 -0
- {processpi-0.1.2.11 → processpi-0.2.0}/tests/test_variables.py +0 -0
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.4
|
|
2
2
|
Name: processpi
|
|
3
|
-
Version: 0.
|
|
3
|
+
Version: 0.2.0
|
|
4
4
|
Summary: Python toolkit for chemical engineering simulations, equipment design, and unit conversions
|
|
5
5
|
Home-page: https://github.com/varma666/ProcessPi
|
|
6
6
|
Author: Raviteja Varma Nadimpalli
|
|
@@ -49,7 +49,11 @@ Dynamic: requires-python
|
|
|
49
49
|
</p>
|
|
50
50
|
|
|
51
51
|
<h1 align="center">Process PI</h1>
|
|
52
|
-
|
|
52
|
+
<p align="center">
|
|
53
|
+
<a href="https://pepy.tech/projects/processpi">
|
|
54
|
+
<img src="https://static.pepy.tech/personalized-badge/processpi?period=total&units=INTERNATIONAL_SYSTEM&left_color=BLACK&right_color=GREEN&left_text=downloads"/>
|
|
55
|
+
</a>
|
|
56
|
+
</p>
|
|
53
57
|
<p align="center">
|
|
54
58
|
<strong>Python toolkit for chemical engineering simulations, equipment design, and unit conversions</strong>
|
|
55
59
|
</p>
|
|
@@ -77,6 +81,16 @@ Dynamic: requires-python
|
|
|
77
81
|
</a>
|
|
78
82
|
</p>
|
|
79
83
|
|
|
84
|
+
<p align="center">
|
|
85
|
+
<a href="https://colab.research.google.com/github/varma666/ProcessPi/blob/main/notebooks/getting_started.ipynb">
|
|
86
|
+
<img src="https://colab.research.google.com/assets/colab-badge.svg" alt="Open in Colab"/>
|
|
87
|
+
</a>
|
|
88
|
+
<a href="https://mybinder.org/v2/gh/varma666/ProcessPi/HEAD?filepath=notebooks/getting_started.ipynb">
|
|
89
|
+
<img src="https://mybinder.org/badge_logo.svg" alt="Launch Binder"/>
|
|
90
|
+
</a>
|
|
91
|
+
</p>
|
|
92
|
+
|
|
93
|
+
|
|
80
94
|
<p align="center">
|
|
81
95
|
<em>Built with ❤️ for chemical engineers.</em>
|
|
82
96
|
</p>
|
|
@@ -3,7 +3,11 @@
|
|
|
3
3
|
</p>
|
|
4
4
|
|
|
5
5
|
<h1 align="center">Process PI</h1>
|
|
6
|
-
|
|
6
|
+
<p align="center">
|
|
7
|
+
<a href="https://pepy.tech/projects/processpi">
|
|
8
|
+
<img src="https://static.pepy.tech/personalized-badge/processpi?period=total&units=INTERNATIONAL_SYSTEM&left_color=BLACK&right_color=GREEN&left_text=downloads"/>
|
|
9
|
+
</a>
|
|
10
|
+
</p>
|
|
7
11
|
<p align="center">
|
|
8
12
|
<strong>Python toolkit for chemical engineering simulations, equipment design, and unit conversions</strong>
|
|
9
13
|
</p>
|
|
@@ -31,6 +35,16 @@
|
|
|
31
35
|
</a>
|
|
32
36
|
</p>
|
|
33
37
|
|
|
38
|
+
<p align="center">
|
|
39
|
+
<a href="https://colab.research.google.com/github/varma666/ProcessPi/blob/main/notebooks/getting_started.ipynb">
|
|
40
|
+
<img src="https://colab.research.google.com/assets/colab-badge.svg" alt="Open in Colab"/>
|
|
41
|
+
</a>
|
|
42
|
+
<a href="https://mybinder.org/v2/gh/varma666/ProcessPi/HEAD?filepath=notebooks/getting_started.ipynb">
|
|
43
|
+
<img src="https://mybinder.org/badge_logo.svg" alt="Launch Binder"/>
|
|
44
|
+
</a>
|
|
45
|
+
</p>
|
|
46
|
+
|
|
47
|
+
|
|
34
48
|
<p align="center">
|
|
35
49
|
<em>Built with ❤️ for chemical engineers.</em>
|
|
36
50
|
</p>
|
|
@@ -36,49 +36,41 @@ class ColebrookWhite(CalculationBase):
|
|
|
36
36
|
if key not in self.inputs:
|
|
37
37
|
raise ValueError(f"Missing required input: {key}")
|
|
38
38
|
|
|
39
|
+
# In your `friction_factor_colebrookwhite.py` file
|
|
40
|
+
|
|
41
|
+
# In your `friction_factor_colebrookwhite.py` file
|
|
42
|
+
|
|
39
43
|
def calculate(self):
|
|
40
44
|
"""
|
|
41
45
|
Calculates the Darcy friction factor.
|
|
42
|
-
|
|
43
|
-
The method first checks if the flow is laminar (Re < 2000). If so, it
|
|
44
|
-
uses the simple and direct formula f = 64/Re. For turbulent flow (Re >= 2000),
|
|
45
|
-
it solves the implicit Colebrook-White equation iteratively.
|
|
46
|
-
|
|
47
|
-
Returns:
|
|
48
|
-
Dimensionless: The calculated Darcy friction factor.
|
|
49
46
|
"""
|
|
50
|
-
# Retrieve and
|
|
47
|
+
# Retrieve Reynolds number and diameter using _get_value
|
|
51
48
|
Re = self._get_value(self.inputs["reynolds_number"], "reynolds_number")
|
|
52
|
-
D = self._get_value(self.inputs["diameter"], "diameter")
|
|
53
|
-
|
|
49
|
+
D = self._get_value(self.inputs["diameter"], "diameter")
|
|
50
|
+
#print(D)
|
|
51
|
+
eps_mm = self._get_value(self.inputs["roughness"], "roughness")
|
|
52
|
+
#print(eps_mm)
|
|
53
|
+
eps_m = eps_mm / 1000 # Convert to mm
|
|
54
|
+
#print(eps_m)
|
|
54
55
|
|
|
55
|
-
|
|
56
|
-
#
|
|
56
|
+
|
|
57
|
+
# Handle the special case of laminar flow.
|
|
57
58
|
if Re < 2000:
|
|
58
59
|
f = 64.0 / Re
|
|
59
60
|
return Dimensionless(f)
|
|
60
61
|
|
|
61
62
|
# For turbulent flow, solve the Colebrook-White equation iteratively.
|
|
62
|
-
# We start with a common initial guess for the friction factor.
|
|
63
63
|
f = 0.02
|
|
64
|
-
tol = 1e-6
|
|
65
|
-
max_iter = 100
|
|
64
|
+
tol = 1e-6
|
|
65
|
+
max_iter = 100
|
|
66
66
|
|
|
67
67
|
for _ in range(max_iter):
|
|
68
|
-
|
|
69
|
-
lhs = 1.0 / math.sqrt(f)
|
|
70
|
-
rhs = -2.0 * math.log10((eps / (3.7 * D)) + (2.51 / (Re * math.sqrt(f))))
|
|
71
|
-
|
|
72
|
-
# Calculate the new value of f based on the rhs.
|
|
68
|
+
rhs = -2.0 * math.log10((eps_m / (3.7 * D)) + (2.51 / (Re * math.sqrt(f))))
|
|
73
69
|
new_f = 1.0 / (rhs**2)
|
|
74
70
|
|
|
75
|
-
# Check for convergence. If the change in f is less than the tolerance,
|
|
76
|
-
# we have a stable solution and can return the result.
|
|
77
71
|
if abs(new_f - f) < tol:
|
|
78
72
|
return Dimensionless(new_f)
|
|
79
|
-
|
|
80
|
-
# Update f for the next iteration.
|
|
73
|
+
|
|
81
74
|
f = new_f
|
|
82
75
|
|
|
83
|
-
|
|
84
|
-
return Dimensionless(f)
|
|
76
|
+
return Dimensionless(f)
|
|
@@ -59,7 +59,7 @@ class PressureDropDarcy(CalculationBase):
|
|
|
59
59
|
D = self._get_value(self.inputs["diameter"], "diameter") # m
|
|
60
60
|
rho = self._get_value(self.inputs["density"], "density") # kg/m³
|
|
61
61
|
v = self._get_value(self.inputs["velocity"], "velocity") # m/s
|
|
62
|
-
|
|
62
|
+
#print(D)
|
|
63
63
|
# Apply the Darcy-Weisbach formula to calculate the pressure drop.
|
|
64
64
|
delta_P = f * (L / D) * (rho * v**2 / 2)
|
|
65
65
|
|
|
@@ -59,7 +59,7 @@ class ReynoldsNumber(CalculationBase):
|
|
|
59
59
|
v = self._get_value(self.inputs["velocity"], "velocity") # m/s
|
|
60
60
|
D = self._get_value(self.inputs["diameter"], "diameter") # m
|
|
61
61
|
viscosity = self.inputs["viscosity"]
|
|
62
|
-
|
|
62
|
+
#print(D,v,rho,viscosity)
|
|
63
63
|
# Check the type of viscosity provided (dynamic or kinematic) and apply
|
|
64
64
|
# the corresponding formula to calculate the Reynolds number.
|
|
65
65
|
if viscosity.viscosity_type == "dynamic":
|
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
from ..base import CalculationBase
|
|
2
|
+
from ...units import *
|
|
3
|
+
|
|
4
|
+
class BiotNumber(CalculationBase):
|
|
5
|
+
"""
|
|
6
|
+
Biot number.
|
|
7
|
+
|
|
8
|
+
**Formula:**
|
|
9
|
+
Bi = h * Lc / k
|
|
10
|
+
"""
|
|
11
|
+
def validate_inputs(self):
|
|
12
|
+
required = ["h", "Lc", "k"]
|
|
13
|
+
for key in required:
|
|
14
|
+
if key not in self.inputs:
|
|
15
|
+
raise ValueError(f"Missing required input: {key}")
|
|
16
|
+
|
|
17
|
+
def calculate(self):
|
|
18
|
+
h = self._get_value(self.inputs["h"], "heat_transfer_coefficient")
|
|
19
|
+
Lc = self._get_value(self.inputs["Lc"], "length")
|
|
20
|
+
k = self._get_value(self.inputs["k"], "thermal_conductivity")
|
|
21
|
+
return Dimensionless(h * Lc / k)
|
|
@@ -0,0 +1,41 @@
|
|
|
1
|
+
from ..base import CalculationBase
|
|
2
|
+
from ...units import *
|
|
3
|
+
|
|
4
|
+
class ChenBoiling(CalculationBase):
|
|
5
|
+
"""
|
|
6
|
+
Chen correlation for **flow boiling heat transfer**.
|
|
7
|
+
|
|
8
|
+
**Formula (simplified):**
|
|
9
|
+
h_total = S * h_pool + F * h_conv
|
|
10
|
+
|
|
11
|
+
**Where:**
|
|
12
|
+
* h_total = overall heat transfer coefficient [W/m²·K]
|
|
13
|
+
* h_pool = pool boiling coefficient (from Rohsenow or others)
|
|
14
|
+
* h_conv = forced convection coefficient (from Dittus-Boelter or similar)
|
|
15
|
+
* S = suppression factor (empirical, function of Re, Boiling number, etc.)
|
|
16
|
+
* F = enhancement factor (empirical, function of flow parameters)
|
|
17
|
+
|
|
18
|
+
**Inputs:**
|
|
19
|
+
* h_pool
|
|
20
|
+
* h_conv
|
|
21
|
+
* S
|
|
22
|
+
* F
|
|
23
|
+
|
|
24
|
+
**Output:**
|
|
25
|
+
* HeatTransferCoefficient [W/m²·K]
|
|
26
|
+
"""
|
|
27
|
+
|
|
28
|
+
def validate_inputs(self):
|
|
29
|
+
required = ["h_pool", "h_conv", "S", "F"]
|
|
30
|
+
for key in required:
|
|
31
|
+
if key not in self.inputs:
|
|
32
|
+
raise ValueError(f"Missing required input: {key}")
|
|
33
|
+
|
|
34
|
+
def calculate(self):
|
|
35
|
+
h_pool = self._get_value(self.inputs["h_pool"], "heat_transfer_coefficient")
|
|
36
|
+
h_conv = self._get_value(self.inputs["h_conv"], "heat_transfer_coefficient")
|
|
37
|
+
S = self._get_value(self.inputs["S"], "dimensionless")
|
|
38
|
+
F = self._get_value(self.inputs["F"], "dimensionless")
|
|
39
|
+
|
|
40
|
+
h_total = S * h_pool + F * h_conv
|
|
41
|
+
return HeatTransferCoefficient(h_total)
|
|
@@ -0,0 +1,45 @@
|
|
|
1
|
+
from ..base import CalculationBase
|
|
2
|
+
from ...units import *
|
|
3
|
+
|
|
4
|
+
class ConductionConvectionCombined(CalculationBase):
|
|
5
|
+
"""
|
|
6
|
+
Heat transfer with conduction resistance + convection resistance.
|
|
7
|
+
|
|
8
|
+
**Formula:**
|
|
9
|
+
Q = (Ts - T∞) / (R_cond + R_conv)
|
|
10
|
+
|
|
11
|
+
Where:
|
|
12
|
+
R_cond = dx / (k * A)
|
|
13
|
+
R_conv = 1 / (h * A)
|
|
14
|
+
|
|
15
|
+
**Inputs:**
|
|
16
|
+
* `thickness`: Conduction thickness [m]
|
|
17
|
+
* `k`: Thermal conductivity [W/m·K]
|
|
18
|
+
* `h`: Convective coefficient [W/m²·K]
|
|
19
|
+
* `area`: Heat transfer area [m²]
|
|
20
|
+
* `T_surface`: Surface temperature [K]
|
|
21
|
+
* `T_fluid`: Bulk fluid temperature [K]
|
|
22
|
+
|
|
23
|
+
**Output:**
|
|
24
|
+
* HeatFlow [W]
|
|
25
|
+
"""
|
|
26
|
+
|
|
27
|
+
def validate_inputs(self):
|
|
28
|
+
required = ["thickness", "k", "h", "area", "T_surface", "T_fluid"]
|
|
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
|
+
dx = self._get_value(self.inputs["thickness"], "length")
|
|
35
|
+
k = self._get_value(self.inputs["k"], "thermal_conductivity")
|
|
36
|
+
h = self._get_value(self.inputs["h"], "heat_transfer_coefficient")
|
|
37
|
+
A = self._get_value(self.inputs["area"], "area")
|
|
38
|
+
Ts = self._get_value(self.inputs["T_surface"], "temperature")
|
|
39
|
+
Tinf = self._get_value(self.inputs["T_fluid"], "temperature")
|
|
40
|
+
|
|
41
|
+
R_cond = dx / (k * A)
|
|
42
|
+
R_conv = 1 / (h * A)
|
|
43
|
+
|
|
44
|
+
Q = (Ts - Tinf) / (R_cond + R_conv)
|
|
45
|
+
return HeatFlow(Q)
|
|
@@ -0,0 +1,46 @@
|
|
|
1
|
+
import math
|
|
2
|
+
from ..base import CalculationBase
|
|
3
|
+
from ...units import *
|
|
4
|
+
|
|
5
|
+
class CondensingVapourFilm(CalculationBase):
|
|
6
|
+
"""
|
|
7
|
+
Heat transfer from condensing vapours on a vertical plate (Nusselt’s theory).
|
|
8
|
+
|
|
9
|
+
**Formula:**
|
|
10
|
+
h = 0.943 * [ (ρ_l * (ρ_l - ρ_v) * g * h_fg * k_l^3) / (μ_l * L * ΔT) ]^(1/4)
|
|
11
|
+
|
|
12
|
+
Then:
|
|
13
|
+
Q = h * A * ΔT
|
|
14
|
+
|
|
15
|
+
**Inputs:**
|
|
16
|
+
* `rho_l`: Liquid density [kg/m³]
|
|
17
|
+
* `rho_v`: Vapour density [kg/m³]
|
|
18
|
+
* `g`: Gravity [m/s²]
|
|
19
|
+
* `h_fg`: Latent heat [J/kg]
|
|
20
|
+
* `k_l`: Liquid thermal conductivity [W/m·K]
|
|
21
|
+
* `mu_l`: Liquid viscosity [Pa·s]
|
|
22
|
+
* `L`: Plate length [m]
|
|
23
|
+
* `A`: Area [m²]
|
|
24
|
+
* `deltaT`: Temperature difference [K]
|
|
25
|
+
"""
|
|
26
|
+
|
|
27
|
+
def validate_inputs(self):
|
|
28
|
+
required = ["rho_l", "rho_v", "g", "h_fg", "k_l", "mu_l", "L", "A", "deltaT"]
|
|
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
|
+
rho_l = self._get_value(self.inputs["rho_l"], "density")
|
|
35
|
+
rho_v = self._get_value(self.inputs["rho_v"], "density")
|
|
36
|
+
g = self._get_value(self.inputs["g"], "acceleration")
|
|
37
|
+
h_fg = self._get_value(self.inputs["h_fg"], "specific_energy")
|
|
38
|
+
k_l = self._get_value(self.inputs["k_l"], "thermal_conductivity")
|
|
39
|
+
mu_l = self._get_value(self.inputs["mu_l"], "dynamic_viscosity")
|
|
40
|
+
L = self._get_value(self.inputs["L"], "length")
|
|
41
|
+
A = self._get_value(self.inputs["A"], "area")
|
|
42
|
+
dT = self._get_value(self.inputs["deltaT"], "temperature")
|
|
43
|
+
|
|
44
|
+
h = 0.943 * ((rho_l * (rho_l - rho_v) * g * h_fg * k_l**3) / (mu_l * L * dT))**0.25
|
|
45
|
+
Q = h * A * dT
|
|
46
|
+
return HeatFlow(Q)
|
|
@@ -0,0 +1,35 @@
|
|
|
1
|
+
from ..base import CalculationBase
|
|
2
|
+
from ...units import *
|
|
3
|
+
|
|
4
|
+
class DropwiseCondensation(CalculationBase):
|
|
5
|
+
"""
|
|
6
|
+
Empirical correlations for **dropwise condensation**.
|
|
7
|
+
|
|
8
|
+
Dropwise condensation has much higher heat transfer coefficients
|
|
9
|
+
than filmwise (often 5–10× larger).
|
|
10
|
+
|
|
11
|
+
**Simple empirical model:**
|
|
12
|
+
h_dw = C * h_fw
|
|
13
|
+
|
|
14
|
+
**Where:**
|
|
15
|
+
* h_dw = dropwise condensation heat transfer coefficient [W/m²·K]
|
|
16
|
+
* h_fw = filmwise condensation coefficient [W/m²·K] (from Nusselt theory)
|
|
17
|
+
* C = enhancement factor (typically 5–10, depending on surface treatment)
|
|
18
|
+
|
|
19
|
+
**Inputs:**
|
|
20
|
+
* h_fw – filmwise coefficient [W/m²·K]
|
|
21
|
+
* C – enhancement factor (default: 7)
|
|
22
|
+
|
|
23
|
+
**Output:**
|
|
24
|
+
* HeatTransferCoefficient [W/m²·K]
|
|
25
|
+
"""
|
|
26
|
+
|
|
27
|
+
def validate_inputs(self):
|
|
28
|
+
if "h_fw" not in self.inputs:
|
|
29
|
+
raise ValueError("Missing required input: h_fw")
|
|
30
|
+
|
|
31
|
+
def calculate(self):
|
|
32
|
+
h_fw = self._get_value(self.inputs["h_fw"], "heat_transfer_coefficient")
|
|
33
|
+
C = self.inputs.get("C", 7.0)
|
|
34
|
+
h_dw = C * h_fw
|
|
35
|
+
return HeatTransferCoefficient(h_dw)
|
|
@@ -0,0 +1,52 @@
|
|
|
1
|
+
import math
|
|
2
|
+
from ..base import CalculationBase
|
|
3
|
+
from ...units import *
|
|
4
|
+
|
|
5
|
+
class NusseltCondensation(CalculationBase):
|
|
6
|
+
"""
|
|
7
|
+
Filmwise condensation heat transfer coefficient
|
|
8
|
+
based on **Nusselt’s theory** (laminar film condensation on vertical surface).
|
|
9
|
+
|
|
10
|
+
**Formula (vertical plate/tube):**
|
|
11
|
+
h = 0.943 * [ (k_l^3 * rho_l^2 * g * h_fg) / (mu_l * L * ΔT) ]^(1/4)
|
|
12
|
+
|
|
13
|
+
**Where:**
|
|
14
|
+
* h = average heat transfer coefficient [W/m²·K]
|
|
15
|
+
* k_l = liquid thermal conductivity [W/m·K]
|
|
16
|
+
* rho_l = liquid density [kg/m³]
|
|
17
|
+
* g = gravity [m/s²]
|
|
18
|
+
* h_fg = latent heat of vaporization [J/kg]
|
|
19
|
+
* mu_l = liquid viscosity [Pa·s]
|
|
20
|
+
* L = characteristic length (plate height or tube length) [m]
|
|
21
|
+
* ΔT = (T_wall – T_sat) [K]
|
|
22
|
+
|
|
23
|
+
**Inputs:**
|
|
24
|
+
* k_l
|
|
25
|
+
* rho_l
|
|
26
|
+
* g
|
|
27
|
+
* h_fg
|
|
28
|
+
* mu_l
|
|
29
|
+
* L
|
|
30
|
+
* dT
|
|
31
|
+
|
|
32
|
+
**Output:**
|
|
33
|
+
* HeatTransferCoefficient [W/m²·K]
|
|
34
|
+
"""
|
|
35
|
+
|
|
36
|
+
def validate_inputs(self):
|
|
37
|
+
required = ["k_l", "rho_l", "g", "h_fg", "mu_l", "L", "dT"]
|
|
38
|
+
for key in required:
|
|
39
|
+
if key not in self.inputs:
|
|
40
|
+
raise ValueError(f"Missing required input: {key}")
|
|
41
|
+
|
|
42
|
+
def calculate(self):
|
|
43
|
+
k_l = self._get_value(self.inputs["k_l"], "thermal_conductivity")
|
|
44
|
+
rho_l = self._get_value(self.inputs["rho_l"], "density")
|
|
45
|
+
g = self._get_value(self.inputs["g"], "acceleration")
|
|
46
|
+
h_fg = self._get_value(self.inputs["h_fg"], "specific_energy")
|
|
47
|
+
mu_l = self._get_value(self.inputs["mu_l"], "dynamic_viscosity")
|
|
48
|
+
L = self._get_value(self.inputs["L"], "length")
|
|
49
|
+
dT = self._get_value(self.inputs["dT"], "temperature")
|
|
50
|
+
|
|
51
|
+
h = 0.943 * ((k_l**3 * rho_l**2 * g * h_fg) / (mu_l * L * dT)) ** 0.25
|
|
52
|
+
return HeatTransferCoefficient(h)
|
|
@@ -0,0 +1,34 @@
|
|
|
1
|
+
from ..base import CalculationBase
|
|
2
|
+
from ...units import *
|
|
3
|
+
|
|
4
|
+
class CrossFlowSingleTube(CalculationBase):
|
|
5
|
+
"""
|
|
6
|
+
Heat transfer to/from fluid flowing normal to a single tube.
|
|
7
|
+
|
|
8
|
+
**Formula:**
|
|
9
|
+
Q = h * A * (T_surface - T_fluid)
|
|
10
|
+
|
|
11
|
+
**Inputs:**
|
|
12
|
+
* `h`: Convective heat transfer coefficient [W/m²·K]
|
|
13
|
+
* `diameter`: Tube outer diameter [m]
|
|
14
|
+
* `length`: Tube length [m]
|
|
15
|
+
* `T_surface`: Tube surface temperature [K]
|
|
16
|
+
* `T_fluid`: Bulk fluid temperature [K]
|
|
17
|
+
"""
|
|
18
|
+
|
|
19
|
+
def validate_inputs(self):
|
|
20
|
+
required = ["h", "diameter", "length", "T_surface", "T_fluid"]
|
|
21
|
+
for key in required:
|
|
22
|
+
if key not in self.inputs:
|
|
23
|
+
raise ValueError(f"Missing required input: {key}")
|
|
24
|
+
|
|
25
|
+
def calculate(self):
|
|
26
|
+
h = self._get_value(self.inputs["h"], "heat_transfer_coefficient")
|
|
27
|
+
D = self._get_value(self.inputs["diameter"], "length")
|
|
28
|
+
L = self._get_value(self.inputs["length"], "length")
|
|
29
|
+
Ts = self._get_value(self.inputs["T_surface"], "temperature")
|
|
30
|
+
Tinf = self._get_value(self.inputs["T_fluid"], "temperature")
|
|
31
|
+
|
|
32
|
+
A = math.pi * D * L
|
|
33
|
+
Q = h * A * (Ts - Tinf)
|
|
34
|
+
return HeatFlow(Q)
|
|
@@ -0,0 +1,22 @@
|
|
|
1
|
+
from ..base import CalculationBase
|
|
2
|
+
from ...units import *
|
|
3
|
+
|
|
4
|
+
class FourierNumber(CalculationBase):
|
|
5
|
+
"""
|
|
6
|
+
Fourier number (transient conduction).
|
|
7
|
+
|
|
8
|
+
**Formula:**
|
|
9
|
+
Fo = α * t / L²
|
|
10
|
+
"""
|
|
11
|
+
def validate_inputs(self):
|
|
12
|
+
required = ["alpha", "time", "L"]
|
|
13
|
+
for key in required:
|
|
14
|
+
if key not in self.inputs:
|
|
15
|
+
raise ValueError(f"Missing required input: {key}")
|
|
16
|
+
|
|
17
|
+
def calculate(self):
|
|
18
|
+
alpha = self._get_value(self.inputs["alpha"], "thermal_diffusivity")
|
|
19
|
+
t = self._get_value(self.inputs["time"], "time")
|
|
20
|
+
L = self._get_value(self.inputs["L"], "length")
|
|
21
|
+
|
|
22
|
+
return Dimensionless(alpha * t / (L**2))
|
|
@@ -0,0 +1,40 @@
|
|
|
1
|
+
from ..base import CalculationBase
|
|
2
|
+
from ...units import *
|
|
3
|
+
|
|
4
|
+
class FourierLaw(CalculationBase):
|
|
5
|
+
"""
|
|
6
|
+
Heat transfer rate by conduction (Fourier's Law).
|
|
7
|
+
|
|
8
|
+
**Formula:**
|
|
9
|
+
q = k * A * (ΔT / dx)
|
|
10
|
+
|
|
11
|
+
**Where:**
|
|
12
|
+
* k = Thermal conductivity [W/m·K]
|
|
13
|
+
* A = Cross-sectional area [m²]
|
|
14
|
+
* ΔT = Temperature difference [K]
|
|
15
|
+
* dx = Thickness of material [m]
|
|
16
|
+
|
|
17
|
+
**Inputs:**
|
|
18
|
+
* `conductivity`: Thermal conductivity (k).
|
|
19
|
+
* `area`: Heat transfer area (A).
|
|
20
|
+
* `deltaT`: Temperature difference (ΔT).
|
|
21
|
+
* `thickness`: Material thickness (dx).
|
|
22
|
+
|
|
23
|
+
**Output:**
|
|
24
|
+
* HeatFlow [W]
|
|
25
|
+
"""
|
|
26
|
+
|
|
27
|
+
def validate_inputs(self):
|
|
28
|
+
required = ["conductivity", "area", "deltaT", "thickness"]
|
|
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
|
+
k = self._get_value(self.inputs["conductivity"], "conductivity") # W/m·K
|
|
35
|
+
A = self._get_value(self.inputs["area"], "area") # m²
|
|
36
|
+
dT = self._get_value(self.inputs["deltaT"], "temperature") # K
|
|
37
|
+
dx = self._get_value(self.inputs["thickness"], "length") # m
|
|
38
|
+
|
|
39
|
+
q = k * A * (dT / dx) # W
|
|
40
|
+
return HeatFlow(q) # return in Watts
|
|
@@ -0,0 +1,24 @@
|
|
|
1
|
+
from ..base import CalculationBase
|
|
2
|
+
from ...units import *
|
|
3
|
+
|
|
4
|
+
class GrashofNumber(CalculationBase):
|
|
5
|
+
"""
|
|
6
|
+
Grashof number (buoyancy vs. viscous forces in natural convection).
|
|
7
|
+
|
|
8
|
+
**Formula:**
|
|
9
|
+
Gr = g * β * ΔT * L³ / ν²
|
|
10
|
+
"""
|
|
11
|
+
def validate_inputs(self):
|
|
12
|
+
required = ["g", "beta", "dT", "L", "nu"]
|
|
13
|
+
for key in required:
|
|
14
|
+
if key not in self.inputs:
|
|
15
|
+
raise ValueError(f"Missing required input: {key}")
|
|
16
|
+
|
|
17
|
+
def calculate(self):
|
|
18
|
+
g = self._get_value(self.inputs["g"], "acceleration")
|
|
19
|
+
beta = self._get_value(self.inputs["beta"], "thermal_expansion_coefficient")
|
|
20
|
+
dT = self._get_value(self.inputs["dT"], "temperature")
|
|
21
|
+
L = self._get_value(self.inputs["L"], "length")
|
|
22
|
+
nu = self._get_value(self.inputs["nu"], "kinematic_viscosity")
|
|
23
|
+
|
|
24
|
+
return Dimensionless((g * beta * dT * (L**3)) / (nu**2))
|
|
@@ -0,0 +1,23 @@
|
|
|
1
|
+
import math
|
|
2
|
+
from ..base import CalculationBase
|
|
3
|
+
from ...units import *
|
|
4
|
+
|
|
5
|
+
class LMTDHeatExchanger(CalculationBase):
|
|
6
|
+
"""
|
|
7
|
+
Heat Exchanger using LMTD method.
|
|
8
|
+
Q = U * A * ΔTlm
|
|
9
|
+
"""
|
|
10
|
+
def validate_inputs(self):
|
|
11
|
+
required = ["U", "area", "dT1", "dT2"]
|
|
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
|
+
U = self._get_value(self.inputs["U"], "heat_transfer_coefficient")
|
|
18
|
+
A = self._get_value(self.inputs["area"], "area")
|
|
19
|
+
dT1 = self._get_value(self.inputs["dT1"], "temperature")
|
|
20
|
+
dT2 = self._get_value(self.inputs["dT2"], "temperature")
|
|
21
|
+
|
|
22
|
+
dTlm = dT1 if dT1 == dT2 else (dT1 - dT2) / math.log(dT1 / dT2)
|
|
23
|
+
return HeatFlow(U * A * dTlm)
|
|
@@ -0,0 +1,40 @@
|
|
|
1
|
+
from ..base import CalculationBase
|
|
2
|
+
from ...units import *
|
|
3
|
+
|
|
4
|
+
class NewtonCooling(CalculationBase):
|
|
5
|
+
"""
|
|
6
|
+
Convective heat transfer (Newton’s Law of Cooling).
|
|
7
|
+
|
|
8
|
+
**Formula:**
|
|
9
|
+
q = h * A * (Ts - T∞)
|
|
10
|
+
|
|
11
|
+
**Where:**
|
|
12
|
+
* h = Heat transfer coefficient [W/m²·K]
|
|
13
|
+
* A = Surface area [m²]
|
|
14
|
+
* Ts = Surface temperature [K]
|
|
15
|
+
* T∞ = Bulk fluid temperature [K]
|
|
16
|
+
|
|
17
|
+
**Inputs:**
|
|
18
|
+
* `h`: Heat transfer coefficient.
|
|
19
|
+
* `area`: Surface area.
|
|
20
|
+
* `T_surface`: Surface temperature.
|
|
21
|
+
* `T_fluid`: Bulk fluid temperature.
|
|
22
|
+
|
|
23
|
+
**Output:**
|
|
24
|
+
* HeatFlow [W]
|
|
25
|
+
"""
|
|
26
|
+
|
|
27
|
+
def validate_inputs(self):
|
|
28
|
+
required = ["h", "area", "T_surface", "T_fluid"]
|
|
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
|
+
h = self._get_value(self.inputs["h"], "heat_transfer_coefficient") # W/m²·K
|
|
35
|
+
A = self._get_value(self.inputs["area"], "area") # m²
|
|
36
|
+
Ts = self._get_value(self.inputs["T_surface"], "temperature") # K
|
|
37
|
+
Tinf = self._get_value(self.inputs["T_fluid"], "temperature") # K
|
|
38
|
+
|
|
39
|
+
q = h * A * (Ts - Tinf) # W
|
|
40
|
+
return HeatFlow(q)
|
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
from ..base import CalculationBase
|
|
2
|
+
from ...units import *
|
|
3
|
+
|
|
4
|
+
class NTUHeatExchanger(CalculationBase):
|
|
5
|
+
"""
|
|
6
|
+
Heat Exchanger using Effectiveness-NTU method.
|
|
7
|
+
Q = ε * C_min * (T_hot,in - T_cold,in)
|
|
8
|
+
"""
|
|
9
|
+
def validate_inputs(self):
|
|
10
|
+
required = ["effectiveness", "C_min", "T_hot_in", "T_cold_in"]
|
|
11
|
+
for key in required:
|
|
12
|
+
if key not in self.inputs:
|
|
13
|
+
raise ValueError(f"Missing required input: {key}")
|
|
14
|
+
|
|
15
|
+
def calculate(self):
|
|
16
|
+
eps = self._get_value(self.inputs["effectiveness"], "dimensionless")
|
|
17
|
+
C_min = self._get_value(self.inputs["C_min"], "heat_capacity_rate") # W/K
|
|
18
|
+
Th_in = self._get_value(self.inputs["T_hot_in"], "temperature")
|
|
19
|
+
Tc_in = self._get_value(self.inputs["T_cold_in"], "temperature")
|
|
20
|
+
|
|
21
|
+
return HeatFlow(eps * C_min * (Th_in - Tc_in))
|
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
from ..base import CalculationBase
|
|
2
|
+
from ...units import *
|
|
3
|
+
|
|
4
|
+
class NusseltNumber(CalculationBase):
|
|
5
|
+
"""
|
|
6
|
+
Nusselt number (dimensionless heat transfer coefficient).
|
|
7
|
+
|
|
8
|
+
**Formula:**
|
|
9
|
+
Nu = h * L / k
|
|
10
|
+
"""
|
|
11
|
+
def validate_inputs(self):
|
|
12
|
+
required = ["h", "L", "k"]
|
|
13
|
+
for key in required:
|
|
14
|
+
if key not in self.inputs:
|
|
15
|
+
raise ValueError(f"Missing required input: {key}")
|
|
16
|
+
|
|
17
|
+
def calculate(self):
|
|
18
|
+
h = self._get_value(self.inputs["h"], "heat_transfer_coefficient")
|
|
19
|
+
L = self._get_value(self.inputs["L"], "length")
|
|
20
|
+
k = self._get_value(self.inputs["k"], "thermal_conductivity")
|
|
21
|
+
return Dimensionless(h * L / k)
|
|
@@ -0,0 +1,16 @@
|
|
|
1
|
+
from ..base import CalculationBase
|
|
2
|
+
from ...units import *
|
|
3
|
+
|
|
4
|
+
class OverallHeatTransferCoefficient(CalculationBase):
|
|
5
|
+
"""
|
|
6
|
+
Overall heat transfer coefficient for a composite wall.
|
|
7
|
+
U = 1 / ΣR
|
|
8
|
+
"""
|
|
9
|
+
def validate_inputs(self):
|
|
10
|
+
if "resistances" not in self.inputs:
|
|
11
|
+
raise ValueError("Missing required input: resistances")
|
|
12
|
+
|
|
13
|
+
def calculate(self):
|
|
14
|
+
Rs = [self._get_value(r, "thermal_resistance") for r in self.inputs["resistances"]]
|
|
15
|
+
R_total = sum(Rs)
|
|
16
|
+
return HeatTransferCoefficient(1 / R_total)
|