processpi 0.0.0__py3-none-any.whl

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (96) hide show
  1. processpi/__init__.py +1 -0
  2. processpi/calculations/__init__.py +3 -0
  3. processpi/calculations/base.py +55 -0
  4. processpi/calculations/engine.py +69 -0
  5. processpi/calculations/fluids/__init__.py +13 -0
  6. processpi/calculations/fluids/cool_brook_white.py +49 -0
  7. processpi/calculations/fluids/flow_type.py +37 -0
  8. processpi/calculations/fluids/optimium_pipe_dia.py +45 -0
  9. processpi/calculations/fluids/pressure_drop_darcy.py +25 -0
  10. processpi/calculations/fluids/pressure_drop_fanning.py +25 -0
  11. processpi/calculations/fluids/pump_power.py +34 -0
  12. processpi/calculations/fluids/reynolds_number.py +24 -0
  13. processpi/calculations/fluids/velocity.py +36 -0
  14. processpi/calculations/heat_transfer/__init__.py +4 -0
  15. processpi/calculations/heat_transfer/conduction_heat_loss.py +26 -0
  16. processpi/calculations/heat_transfer/convection_heat_loss.py +23 -0
  17. processpi/calculations/heat_transfer/heat_exchanger_area.py +26 -0
  18. processpi/calculations/mass_transfer/__init__.py +3 -0
  19. processpi/calculations/mass_transfer/distillation_stage_count.py +346 -0
  20. processpi/calculations/mass_transfer/drying_rate.py +132 -0
  21. processpi/calculations/reaction_engineering/__init__.py +4 -0
  22. processpi/calculations/reaction_engineering/catalyst_activity.py +109 -0
  23. processpi/calculations/reaction_engineering/reaction_rate.py +143 -0
  24. processpi/calculations/reaction_engineering/residence_time.py +80 -0
  25. processpi/calculations/thermodynamics/__init__.py +4 -0
  26. processpi/calculations/thermodynamics/enthalpy_change.py +23 -0
  27. processpi/calculations/thermodynamics/entropy_change.py +25 -0
  28. processpi/calculations/thermodynamics/heat_of_vaporization.py +20 -0
  29. processpi/components/__init__.py +5 -0
  30. processpi/components/aceticacid.py +19 -0
  31. processpi/components/acetone.py +20 -0
  32. processpi/components/acrylicacid.py +19 -0
  33. processpi/components/air.py +20 -0
  34. processpi/components/ammonia.py +19 -0
  35. processpi/components/base.py +85 -0
  36. processpi/components/benzene.py +40 -0
  37. processpi/components/benzoicacid.py +19 -0
  38. processpi/components/bromine.py +19 -0
  39. processpi/components/butane.py +19 -0
  40. processpi/components/carbondioxide.py +19 -0
  41. processpi/components/carbonmonoxide.py +17 -0
  42. processpi/components/carbontetrachloride.py +17 -0
  43. processpi/components/chlorine.py +17 -0
  44. processpi/components/chlorobenzene.py +17 -0
  45. processpi/components/chloroform.py +17 -0
  46. processpi/components/chloromethane.py +17 -0
  47. processpi/components/cyanogen.py +17 -0
  48. processpi/components/cyclohexene.py +17 -0
  49. processpi/components/ethane.py +17 -0
  50. processpi/components/ethanol.py +20 -0
  51. processpi/components/ethylacetate.py +17 -0
  52. processpi/components/methanol.py +20 -0
  53. processpi/components/toluene.py +22 -0
  54. processpi/components/water.py +24 -0
  55. processpi/pipelines/__init__.py +0 -0
  56. processpi/pipelines/base.py +76 -0
  57. processpi/pipelines/design_rules.py +91 -0
  58. processpi/pipelines/engine.py +718 -0
  59. processpi/pipelines/equipment.py +32 -0
  60. processpi/pipelines/fittings.py +76 -0
  61. processpi/pipelines/insulation.py +0 -0
  62. processpi/pipelines/materials.py +102 -0
  63. processpi/pipelines/network.py +277 -0
  64. processpi/pipelines/pipelineresults.py +95 -0
  65. processpi/pipelines/pipes.py +84 -0
  66. processpi/pipelines/pumps.py +83 -0
  67. processpi/pipelines/selection.py +89 -0
  68. processpi/pipelines/standards.py +279 -0
  69. processpi/pipelines/vessel.py +34 -0
  70. processpi/units/__init__.py +38 -0
  71. processpi/units/area.py +51 -0
  72. processpi/units/base.py +57 -0
  73. processpi/units/density.py +47 -0
  74. processpi/units/diameter.py +58 -0
  75. processpi/units/dimensionless.py +42 -0
  76. processpi/units/heat_flux.py +46 -0
  77. processpi/units/heat_of_vaporization.py +47 -0
  78. processpi/units/heat_transfer_coefficient.py +45 -0
  79. processpi/units/length.py +47 -0
  80. processpi/units/mass.py +50 -0
  81. processpi/units/mass_flowrate.py +50 -0
  82. processpi/units/pressure.py +57 -0
  83. processpi/units/specific_heat.py +47 -0
  84. processpi/units/strings.py +31 -0
  85. processpi/units/temperature.py +51 -0
  86. processpi/units/thermal_conductivity.py +45 -0
  87. processpi/units/thermal_resistance.py +46 -0
  88. processpi/units/velocity.py +45 -0
  89. processpi/units/viscosity.py +78 -0
  90. processpi/units/volume.py +50 -0
  91. processpi/units/volumetric_flowrate.py +52 -0
  92. processpi-0.0.0.dist-info/METADATA +5 -0
  93. processpi-0.0.0.dist-info/RECORD +96 -0
  94. processpi-0.0.0.dist-info/WHEEL +5 -0
  95. processpi-0.0.0.dist-info/licenses/LICENSE +21 -0
  96. processpi-0.0.0.dist-info/top_level.txt +1 -0
@@ -0,0 +1,143 @@
1
+ # processpi/calculations/reaction_engineering/reaction_rate.py
2
+
3
+ from typing import Dict, Optional, Mapping
4
+ from ..base import CalculationBase
5
+
6
+
7
+ class ReactionRate(CalculationBase):
8
+ """
9
+ General reaction-rate calculator supporting several kinetic models.
10
+
11
+ Workflows (select with `model`):
12
+ --------------------------------
13
+ 1) Power law (elementary / empirical):
14
+ model = "power_law"
15
+ Inputs:
16
+ C: Mapping[str, float] # species concentrations, mol/L (or consistent units)
17
+ exponents: Mapping[str, float] # reaction orders for each species (e.g., {"A":1, "B":1})
18
+ k: float # rate constant (units consistent with orders & C)
19
+ (optional) A, Ea, T, R # If k not given, compute k via Arrhenius: k = A*exp(-Ea/(R*T))
20
+ Output: {"rate": float}
21
+
22
+ Equation:
23
+ r = k * Π_i C_i^{a_i}
24
+
25
+ 2) Langmuir–Hinshelwood (adsorption + surface reaction):
26
+ model = "langmuir_hinshelwood"
27
+ Inputs:
28
+ k or (A, Ea, T, R) # rate constant or Arrhenius params
29
+ C: Mapping[str, float] # species concentrations (e.g., {"A":..., "B":...})
30
+ K: Mapping[str, float] # adsorption constants for species present
31
+ numerator: Mapping[str, float] # stoich exponents in numerator (default {"A":1})
32
+ denom_power: float = 1.0 # overall power on denominator (default 1)
33
+ Output: {"rate": float}
34
+
35
+ Equation (generic):
36
+ r = k * Π_j (C_j)^{ν_j} / [ 1 + Σ_i K_i C_i ]^{denom_power}
37
+
38
+ 3) Michaelis–Menten (enzymatic form, optional):
39
+ model = "michaelis_menten"
40
+ Inputs:
41
+ Vmax: float
42
+ Km: float
43
+ S: float # substrate concentration
44
+ Output: {"rate": float}
45
+
46
+ Equation:
47
+ r = Vmax * S / (Km + S)
48
+
49
+ Notes
50
+ -----
51
+ * Units are your responsibility; keep them consistent.
52
+ * If both `k` and (A,Ea,T[,R]) are provided, `k` is used and Arrhenius params ignored.
53
+ * Default R = 8.314 if not supplied and Arrhenius is used.
54
+ """
55
+
56
+ def validate_inputs(self):
57
+ model = self.inputs.get("model", "power_law").lower()
58
+ if model not in ("power_law", "langmuir_hinshelwood", "michaelis_menten"):
59
+ raise ValueError("model must be 'power_law', 'langmuir_hinshelwood', or 'michaelis_menten'.")
60
+
61
+ if model == "power_law":
62
+ if "C" not in self.inputs or "exponents" not in self.inputs:
63
+ raise ValueError("power_law requires 'C' and 'exponents'.")
64
+ C = self.inputs["C"]
65
+ exps = self.inputs["exponents"]
66
+ if not isinstance(C, Mapping) or not isinstance(exps, Mapping):
67
+ raise ValueError("'C' and 'exponents' must be mappings.")
68
+ # Either k or Arrhenius parameters:
69
+ if "k" not in self.inputs and not all(k in self.inputs for k in ("A", "Ea", "T")):
70
+ raise ValueError("Provide 'k' or Arrhenius params (A, Ea, T) for power_law.")
71
+
72
+ elif model == "langmuir_hinshelwood":
73
+ for key in ("C", "K"):
74
+ if key not in self.inputs:
75
+ raise ValueError(f"langmuir_hinshelwood requires '{key}'.")
76
+ if "k" not in self.inputs and not all(k in self.inputs for k in ("A", "Ea", "T")):
77
+ raise ValueError("Provide 'k' or Arrhenius params (A, Ea, T) for langmuir_hinshelwood.")
78
+
79
+ elif model == "michaelis_menten":
80
+ for key in ("Vmax", "Km", "S"):
81
+ if key not in self.inputs:
82
+ raise ValueError(f"michaelis_menten requires '{key}'.")
83
+
84
+ def _arrhenius_k(self) -> float:
85
+ """Compute k via Arrhenius if A, Ea, T present. Default R=8.314 unless provided."""
86
+ if all(k in self.inputs for k in ("A", "Ea", "T")):
87
+ import math
88
+ A = float(self.inputs["A"])
89
+ Ea = float(self.inputs["Ea"])
90
+ T = float(self.inputs["T"])
91
+ R = float(self.inputs.get("R", 8.314))
92
+ return A * math.exp(-Ea / (R * T))
93
+ raise ValueError("Arrhenius parameters (A, Ea, T) are required to compute k.")
94
+
95
+ def calculate(self) -> Dict:
96
+ model = self.inputs.get("model", "power_law").lower()
97
+
98
+ if model == "power_law":
99
+ C: Mapping[str, float] = self.inputs["C"]
100
+ exps: Mapping[str, float] = self.inputs["exponents"]
101
+ k = float(self.inputs.get("k", self._arrhenius_k()))
102
+ rate = k
103
+ for sp, a in exps.items():
104
+ c = float(C.get(sp, 0.0))
105
+ if c < 0:
106
+ raise ValueError(f"Negative concentration for species '{sp}'.")
107
+ rate *= c ** float(a)
108
+ return {"rate": rate}
109
+
110
+ if model == "langmuir_hinshelwood":
111
+ C: Mapping[str, float] = self.inputs["C"]
112
+ K: Mapping[str, float] = self.inputs["K"]
113
+ k = float(self.inputs.get("k", self._arrhenius_k()))
114
+ numerator = self.inputs.get("numerator", {"A": 1.0})
115
+ denom_power = float(self.inputs.get("denom_power", 1.0))
116
+
117
+ # numerator term
118
+ num = k
119
+ for sp, nu in numerator.items():
120
+ c = float(C.get(sp, 0.0))
121
+ if c < 0:
122
+ raise ValueError(f"Negative concentration for species '{sp}'.")
123
+ num *= c ** float(nu)
124
+
125
+ # denominator term (1 + Σ K_i C_i)^{denom_power}
126
+ denom_sum = 1.0
127
+ for sp, Ki in K.items():
128
+ c = float(C.get(sp, 0.0))
129
+ if c < 0:
130
+ raise ValueError(f"Negative concentration for species '{sp}'.")
131
+ denom_sum += float(Ki) * c
132
+
133
+ rate = num / (denom_sum ** denom_power)
134
+ return {"rate": rate}
135
+
136
+ # michaelis_menten
137
+ Vmax = float(self.inputs["Vmax"])
138
+ Km = float(self.inputs["Km"])
139
+ S = float(self.inputs["S"])
140
+ if Vmax < 0 or Km < 0 or S < 0:
141
+ raise ValueError("Vmax, Km, and S must be non-negative.")
142
+ rate = Vmax * S / (Km + S) if (Km + S) > 0 else 0.0
143
+ return {"rate": rate}
@@ -0,0 +1,80 @@
1
+ # processpi/calculations/reaction_engineering/residence_time.py
2
+
3
+ from typing import Dict, Literal
4
+ from ..base import CalculationBase
5
+
6
+
7
+ class ResidenceTime(CalculationBase):
8
+ """
9
+ Space time (τ) and conversion relations for ideal reactors.
10
+
11
+ Workflows (select with `mode`):
12
+ -------------------------------
13
+ 1) Space time:
14
+ mode = "tau"
15
+ Inputs:
16
+ V: float # reactor volume
17
+ Q: float # volumetric flow rate
18
+ Output:
19
+ {"tau": float, "space_velocity": float}
20
+ Equations:
21
+ τ = V / Q
22
+ SV = 1 / τ
23
+
24
+ 2) Conversion for first-order kinetics (isothermal, constant density):
25
+ mode = "conversion"
26
+ Inputs:
27
+ reactor: "CSTR" or "PFR"
28
+ k: float # first-order rate constant (1/time)
29
+ tau: float # space time (V/Q)
30
+ Output:
31
+ {"X": float}
32
+ Equations:
33
+ CSTR: X = (k τ) / (1 + k τ)
34
+ PFR: X = 1 - exp(-k τ)
35
+ """
36
+
37
+ def validate_inputs(self):
38
+ mode = self.inputs.get("mode", "tau").lower()
39
+ if mode not in ("tau", "conversion"):
40
+ raise ValueError("mode must be 'tau' or 'conversion'.")
41
+
42
+ if mode == "tau":
43
+ for k in ("V", "Q"):
44
+ if k not in self.inputs:
45
+ raise ValueError(f"Missing required input: {k}")
46
+ if float(self.inputs["V"]) <= 0 or float(self.inputs["Q"]) <= 0:
47
+ raise ValueError("V and Q must be > 0.")
48
+
49
+ else: # conversion
50
+ for k in ("reactor", "k", "tau"):
51
+ if k not in self.inputs:
52
+ raise ValueError(f"Missing required input: {k}")
53
+ reactor = str(self.inputs["reactor"]).upper()
54
+ if reactor not in ("CSTR", "PFR"):
55
+ raise ValueError("reactor must be 'CSTR' or 'PFR'.")
56
+ if float(self.inputs["k"]) < 0 or float(self.inputs["tau"]) < 0:
57
+ raise ValueError("k and tau must be >= 0.")
58
+
59
+ def calculate(self) -> Dict:
60
+ mode = self.inputs.get("mode", "tau").lower()
61
+
62
+ if mode == "tau":
63
+ V = float(self.inputs["V"])
64
+ Q = float(self.inputs["Q"])
65
+ tau = V / Q
66
+ SV = 1.0 / tau
67
+ return {"tau": tau, "space_velocity": SV}
68
+
69
+ # conversion
70
+ import math
71
+ reactor = str(self.inputs["reactor"]).upper()
72
+ k = float(self.inputs["k"])
73
+ tau = float(self.inputs["tau"])
74
+
75
+ if reactor == "CSTR":
76
+ X = (k * tau) / (1.0 + k * tau) if (1.0 + k * tau) > 0 else 0.0
77
+ else: # PFR
78
+ X = 1.0 - math.exp(-k * tau)
79
+
80
+ return {"X": X}
@@ -0,0 +1,4 @@
1
+ from .enthalpy_change import EnthalpyChange
2
+ from .entropy_change import EntropyChange
3
+ from .heat_of_vaporization import HeatOfVaporization
4
+ __all__ = ["EnthalpyChange", "EntropyChange", "HeatOfVaporization"]
@@ -0,0 +1,23 @@
1
+ from ..base import CalculationBase
2
+ from ...units import *
3
+
4
+ class EnthalpyChange(CalculationBase):
5
+ """
6
+ Calculate enthalpy change using:
7
+ ΔH = m * Cp * ΔT
8
+ """
9
+
10
+ def validate_inputs(self):
11
+ required = ["mass", "specific_heat", "temp_initial", "temp_final"]
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"], "mass") # kg
18
+ Cp = self._get_value(self.inputs["specific_heat"], "specific_heat") # J/kg·K
19
+ T1 = self._get_value(self.inputs["temp_initial"], "temp_initial") # °C or K
20
+ T2 = self._get_value(self.inputs["temp_final"], "temp_final") # °C or K
21
+
22
+ ΔH = m * Cp * (T2 - T1)
23
+ return EnthalpyChange(ΔH, "J")
@@ -0,0 +1,25 @@
1
+ from processpi.calculations.base import CalculationBase
2
+ import math
3
+
4
+ class EntropyChange(CalculationBase):
5
+ """
6
+ Calculate entropy change (ideal reversible process):
7
+ ΔS = m * Cp * ln(T2/T1)
8
+ """
9
+
10
+ def validate_inputs(self):
11
+ required = ["mass", "specific_heat", "temp_initial", "temp_final"]
12
+ for key in required:
13
+ if key not in self.inputs:
14
+ raise ValueError(f"Missing required input: {key}")
15
+ if self.inputs["temp_initial"] <= 0 or self.inputs["temp_final"] <= 0:
16
+ raise ValueError("Temperatures must be > 0 K for entropy calculation")
17
+
18
+ def calculate(self):
19
+ m = self._get_value(self.inputs["mass"], "mass") # kg
20
+ Cp = self._get_value(self.inputs["specific_heat"], "specific_heat") # J/kg·K
21
+ T1 = self._get_value(self.inputs["temp_initial"], "temp_initial") # K
22
+ T2 = self._get_value(self.inputs["temp_final"], "temp_final") # K
23
+
24
+ ΔS = m * Cp * math.log(T2 / T1)
25
+ return {"entropy_change_J_per_K": ΔS}
@@ -0,0 +1,20 @@
1
+ from processpi.calculations.base import CalculationBase
2
+
3
+ class HeatOfVaporization(CalculationBase):
4
+ """
5
+ Calculate heat required for vaporization:
6
+ Q = m * ΔHvap
7
+ """
8
+
9
+ def validate_inputs(self):
10
+ required = ["mass", "heat_vaporization"]
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
+ m = self._get_value(self.inputs["mass"], "mass") # kg
17
+ ΔHvap = self._get_value(self.inputs["heat_vaporization"], "heat_vaporization") # J/kg
18
+
19
+ Q = m * ΔHvap
20
+ return {"heat_required_J": Q}
@@ -0,0 +1,5 @@
1
+ from .water import Water
2
+ from .base import Component
3
+
4
+ __all__ = ["Water",
5
+ "Component"]
@@ -0,0 +1,19 @@
1
+ from .base import Component
2
+ from processpi.units import *
3
+
4
+
5
+ class AceticAcid(Component):
6
+ name = "Acetic Acid"
7
+ formula = "CH3COOH"
8
+ molecular_weight = 60.052
9
+ _critical_temperature = Temperature(591.95, "K")
10
+ _critical_pressure = Pressure(5.786, "MPa")
11
+ _critical_volume = Volume(0.177, "m3") # Placeholder for critical volume per Kmole
12
+ _critical_zc = 0.208 # Placeholder for critical compressibility factor
13
+ _critical_acentric_factor = 0.4665 # Placeholder for critical acentric factor
14
+ _density_constants = [1.4486, 0.25892, 591.95, 0.2529]
15
+ _specific_heat_constants = [139640,-320.8,0.8985,0,0]
16
+ _viscosity_constants = [-9.03, 1212.3, -0.322, 0, 0]
17
+ _thermal_conductivity_constants = [0.214, -0.0001834, 0,0,0]
18
+ _vapor_pressure_constants = [53.27, -6304.5, -4.2985, 8.8865E-18, 6]
19
+ _enthalpy_constants = [4.0179E-7, 2.6037, -5.0031,2.7069, 0] # Placeholder for enthalpy constants
@@ -0,0 +1,20 @@
1
+
2
+ from .base import Component
3
+ from processpi.units import *
4
+
5
+
6
+ class Acetone(Component):
7
+ name = "Acetone"
8
+ formula = "C3H6O"
9
+ molecular_weight = 58.080
10
+ _critical_temperature = Temperature(508.1, "K")
11
+ _critical_pressure = Pressure(4.701, "MPa")
12
+ _critical_volume = Volume(0.209, "m3") # Placeholder for critical volume per Kmole
13
+ _critical_zc = 0.233 # Placeholder for critical compressibility factor
14
+ _critical_acentric_factor = 0.3065 # Placeholder for critical acentric factor
15
+ _density_constants = [1.2332, 0.25886, 508.2, 0.2913]
16
+ _specific_heat_constants = [135600,-177,0.2837,0.000689,0]
17
+ _viscosity_constants = [-14.918, 1023.4, 0.5961, 0, 0]
18
+ _thermal_conductivity_constants = [0.2878, -0.000427, 0,0,0]
19
+ _vapor_pressure_constants = [69.006, -5599.6, -7.0985, 0.0000062237, 2]
20
+ _enthalpy_constants = [4.215E-7, 0.3397, 178.45, 3.639, 0] # Placeholder for enthalpy constants
@@ -0,0 +1,19 @@
1
+ from .base import Component
2
+ from processpi.units import *
3
+
4
+
5
+ class AcrylicAcid(Component):
6
+ name = "Acrylic Acid"
7
+ formula = "C3​H4​O2​"
8
+ molecular_weight = 72.063
9
+ _critical_temperature = Temperature(615, "K")
10
+ _critical_pressure = Pressure(5.66, "MPa")
11
+ _critical_volume = Volume(0.208, "m3") # Placeholder for critical volume per Kmole
12
+ _critical_zc = 0.23 # Placeholder for critical compressibility factor
13
+ _critical_acentric_factor = 0.5383 # Placeholder for critical acentric factor
14
+ _density_constants = [1.2414, 0.25822, 615,0.30701]
15
+ _specific_heat_constants = [55300,300,0,0,0]
16
+ _viscosity_constants = [-28.12, 2280.2, 2.3956, 0, 0]
17
+ _thermal_conductivity_constants = [0.2441, -0.0002904, 0,0,0]
18
+ _vapor_pressure_constants = [46.745, -6587.1, -3.2208, 0.00000052253, 2]
19
+ _enthalpy_constants = [4.3756E-7, 2.2571,-4.5116,2.5738, 0] # Placeholder for enthalpy constants
@@ -0,0 +1,20 @@
1
+
2
+ from .base import Component
3
+ from processpi.units import *
4
+
5
+
6
+ class Air(Component):
7
+ name = "Air"
8
+ formula = "Mixture​"
9
+ molecular_weight = 28.96
10
+ _critical_temperature = Temperature(132.45, "K")
11
+ _critical_pressure = Pressure(3.774, "MPa")
12
+ _critical_volume = Volume(0.09147, "m3") # Placeholder for critical volume per Kmole
13
+ _critical_zc = 0.313 # Placeholder for critical compressibility factor
14
+ _critical_acentric_factor = 0 # Placeholder for critical acentric factor
15
+ _density_constants = [0.26733, 132.45, 0.27341,59.15]
16
+ _specific_heat_constants = [-214460,9185.1,-106.12,0.41616,0]
17
+ _viscosity_constants = [-20.077, 285.15, 1.784,-6.2382E-22, 10]
18
+ _thermal_conductivity_constants = [0.28472, -0.0017393, 0,0,0]
19
+ _vapor_pressure_constants = [21.662, -692.39, -0.392, 0.0047574, 1]
20
+ _enthalpy_constants = [0.3822E-7, 59.15,0.6759,132.45, 0] # Placeholder for enthalpy constants
@@ -0,0 +1,19 @@
1
+ from .base import Component
2
+ from processpi.units import *
3
+
4
+
5
+ class Ammonia(Component):
6
+ name = "Ammonia"
7
+ formula = "NH3"
8
+ molecular_weight = 17.031
9
+ _critical_temperature = Temperature(405.65, "K")
10
+ _critical_pressure = Pressure(11.28, "MPa")
11
+ _critical_volume = Volume(0.07247, "m3") # Placeholder for critical volume per Kmole
12
+ _critical_zc = 0.242 # Placeholder for critical compressibility factor
13
+ _critical_acentric_factor = 0.2526 # Placeholder for critical acentric factor
14
+ _density_constants = [3.5383, 0.25443, 405.65, 0.2888]
15
+ _specific_heat_constants = [61.289,80925,799.4,-2651,0]
16
+ _viscosity_constants = [-6.743,598.3,-0.7341,-3.69E-27, 10]
17
+ _thermal_conductivity_constants = [1.169, -0.002314, 0,0,0]
18
+ _vapor_pressure_constants = [90.483, -4,669.70, -11.607, 1.72E-02, 1]
19
+ _enthalpy_constants = [3.1523E-7, 0.3914, -0.2289,0.2309, 0] # Placeholder for enthalpy constants
@@ -0,0 +1,85 @@
1
+ from abc import ABC, abstractmethod
2
+ from processpi.units import *
3
+ from math import exp, log
4
+
5
+ class Component(ABC):
6
+ """
7
+ Base class for a chemical component.
8
+ Each subclass must define its own physical and chemical properties.
9
+ """
10
+
11
+ def __init__(self, temperature: Temperature = None, pressure: Pressure = None):
12
+ self.temperature = temperature or Temperature(35, "C")
13
+ self.pressure = pressure or Pressure(101325, "Pa")
14
+
15
+ @property
16
+ @abstractmethod
17
+ def name(self):
18
+ pass
19
+
20
+ @property
21
+ @abstractmethod
22
+ def formula(self):
23
+ pass
24
+
25
+ @property
26
+ @abstractmethod
27
+ def molecular_weight(self):
28
+ pass
29
+
30
+ # Generic density method (can be overridden in subclasses)
31
+ def density(self, temperature: Temperature = None) -> Density:
32
+ temperature = self._get_temperature(temperature)
33
+ T = temperature.value
34
+ den = self._density_constants[0] / (self._density_constants[1] ** (1 + (1 - (T/self._density_constants[2])**self._density_constants[3])))
35
+ den = den * self.molecular_weight
36
+ return Density(den, "kg/m3")
37
+
38
+ def _get_temperature(self, temperature: Temperature):
39
+ return temperature or self.temperature
40
+
41
+ def specific_heat(self, temperature: Temperature = None):
42
+ temperature = self._get_temperature(temperature)
43
+ T = temperature.value
44
+ cp = (self._specific_heat_constants[0] +
45
+ self._specific_heat_constants[1] * T +
46
+ self._specific_heat_constants[2] * T**2 +
47
+ self._specific_heat_constants[3] * T**3 +
48
+ self._specific_heat_constants[4] * T**4)
49
+ cp = cp * self.molecular_weight
50
+ return SpecificHeat(cp, "J/kgK")
51
+
52
+ def viscosity(self, temperature: Temperature = None):
53
+ temperature = self._get_temperature(temperature)
54
+ T = temperature.value
55
+ po = self._viscosity_constants[0] + (self._viscosity_constants[1] / T) + (self._viscosity_constants[2] * log(T)) + (self._viscosity_constants[3] * (T**self._viscosity_constants[4]))
56
+ vis = exp(po)
57
+ return Viscosity(vis, "Pa·s")
58
+
59
+ def thermal_conductivity(self, temperature: Temperature = None):
60
+ temperature = self._get_temperature(temperature)
61
+ T = temperature.value
62
+ k = (self._thermal_conductivity_constants[0] +
63
+ self._thermal_conductivity_constants[1] * T +
64
+ self._thermal_conductivity_constants[2] * T**2 +
65
+ self._thermal_conductivity_constants[3] * T**3 +
66
+ self._thermal_conductivity_constants[4] * T**4)
67
+ return ThermalConductivity(k, "W/mK")
68
+
69
+ def vapor_pressure(self, temperature: Temperature = None):
70
+ temperature = self._get_temperature(temperature)
71
+ T = temperature.value
72
+ po = (self._vapor_pressure_constants[0] + (self._vapor_pressure_constants[1] / T) +
73
+ (self._vapor_pressure_constants[2] * log(T)) +
74
+ (self._vapor_pressure_constants[3] * (T**self._vapor_pressure_constants[4])))
75
+ vp = exp(po)
76
+ return Pressure(vp, "Pa")
77
+
78
+ def enthalpy(self, temperature: Temperature = None):
79
+ temperature = self._get_temperature(temperature)
80
+ T = temperature.value
81
+ Tr = T / self._critical_temperature.value
82
+ tou = 1 - Tr
83
+ dH = self._enthalpy_constants[0] * (tou**((self._enthalpy_constants[1]) + (self._enthalpy_constants[2] * tou) + (self._enthalpy_constants[3] * (tou**2)) + (self._enthalpy_constants[4] * (tou**3))))
84
+ dH = dH * self.molecular_weight
85
+ return HeatOfVaporization(dH, "J/kg")
@@ -0,0 +1,40 @@
1
+
2
+ from .base import Component
3
+ from processpi.units import *
4
+
5
+
6
+ class Benzene(Component):
7
+ name = "Benzene"
8
+ formula = "C6H6"
9
+ molecular_weight = 78.114
10
+ _critical_temperature = Temperature(562.1, "K")
11
+ _critical_pressure = Pressure(4.895, "MPa")
12
+ _critical_volume = Volume(0.256, "m3") # Placeholder for critical volume per Kmole
13
+ _critical_zc = 0.268 # Placeholder for critical compressibility factor
14
+ _critical_acentric_factor = 0.2103 # Placeholder for critical acentric factor
15
+ _density_constants = [1.0259, 0.26666, 562.05, 0.28394]
16
+ _specific_heat_constants_1 = [129440,-169.5,0.64781,0,0]
17
+ _specific_heat_constants_2 = [162940,-344.94,0.85562,0,0]
18
+ _viscosity_constants = [7.5117, 294.68,-2.794, 0, 0]
19
+ _thermal_conductivity_constants = [0.23444, -0.00030572, 0,0,0]
20
+ _vapor_pressure_constants = [83.107, -6486.2, -9.2194, 0.0000069844, 2]
21
+ _enthalpy_constants = [4.5346E-7, 0.39053, 278.68, 3.4705, 0] # Placeholder for enthalpy constants
22
+ def specific_heat(self, temperature: Temperature):
23
+ """Return specific heat in kJ/kg.K as a function of temperature in °C"""
24
+ Tr = temperature.value / self._critical_temperature.value
25
+ T = temperature.value
26
+ # Using a polynomial fit for specific heat as a function of reduced temperature
27
+ if T <= 353.24:
28
+ constants = self._specific_heat_constants_1
29
+ else:
30
+ constants = self._specific_heat_constants_2
31
+
32
+ cp = (constants[0] +
33
+ constants[1] * T +
34
+ constants[2] * T**2 +
35
+ constants[3] * T**3 +
36
+ constants[4] * T**4)
37
+ # Convert to kJ/kg.K
38
+ #cp /= 1000.0
39
+ cp = cp * self.molecular_weight
40
+ return SpecificHeat(cp, "J/kgK")
@@ -0,0 +1,19 @@
1
+ from .base import Component
2
+ from processpi.units import *
3
+
4
+
5
+ class BenzoicAcid(Component):
6
+ name = "Benzoic Acid"
7
+ formula = "C7H6O"
8
+ molecular_weight = 122.121
9
+ _critical_temperature = Temperature(751, "K")
10
+ _critical_pressure = Pressure(4.47, "MPa")
11
+ _critical_volume = Volume(0.344, "m3") # Placeholder for critical volume per Kmole
12
+ _critical_zc = 0.246 # Placeholder for critical compressibility factor
13
+ _critical_acentric_factor = 0.6028 # Placeholder for critical acentric factor
14
+ _density_constants = [0.71587, 0.24812, 751,0.2857]
15
+ _specific_heat_constants = [-5480,647.12,0,0,0]
16
+ _viscosity_constants = [-12.947,2557.9,0,0, 0]
17
+ _thermal_conductivity_constants = [0.2391, -0.0002325, 0,0,0]
18
+ _vapor_pressure_constants = [88.513, -11829, -8.6826, 2.32E-19, 6]
19
+ _enthalpy_constants = [10.19E-7, 0.478, 395.45,7.1277, 0] # Placeholder for enthalpy constants
@@ -0,0 +1,19 @@
1
+ from .base import Component
2
+ from processpi.units import *
3
+
4
+
5
+ class Bromine(Component):
6
+ name = "Bromine"
7
+ formula = "Br2"
8
+ molecular_weight = 159.808
9
+ _critical_temperature = Temperature(584.15, "K")
10
+ _critical_pressure = Pressure(10.3, "MPa")
11
+ _critical_volume = Volume(0.135, "m3") # Placeholder for critical volume per Kmole
12
+ _critical_zc = 0.286 # Placeholder for critical compressibility factor
13
+ _critical_acentric_factor = 0.129 # Placeholder for critical acentric factor
14
+ _density_constants = [2.1872, 0.29527, 584.15,0.3295]
15
+ _specific_heat_constants = [179400,-667.11,1.0701,0,0]
16
+ _viscosity_constants = [16.775,-314,-3.9763,0, 0]
17
+ _thermal_conductivity_constants = [-0.2185, 0.0042143,-0.000017753,3.10E-08,-2.01E-11]
18
+ _vapor_pressure_constants = [108.26, -6592, -14.16,1.60E-02, 1]
19
+ _enthalpy_constants = [4E-7, 0.351, 265.85,3.2323, 0] # Placeholder for enthalpy constants
@@ -0,0 +1,19 @@
1
+ from .base import Component
2
+ from processpi.units import *
3
+
4
+
5
+ class Butane(Component):
6
+ name = "Butane"
7
+ formula = "C4H10"
8
+ molecular_weight = 58.122
9
+ _critical_temperature = Temperature(425.12, "K")
10
+ _critical_pressure = Pressure(3.796, "MPa")
11
+ _critical_volume = Volume(0.255, "m3") # Placeholder for critical volume per Kmole
12
+ _critical_zc = 0.274 # Placeholder for critical compressibility factor
13
+ _critical_acentric_factor = 0.2002 # Placeholder for critical acentric factor
14
+ _density_constants = [1.0677, 0.27188,425.12,0.28688]
15
+ _specific_heat_constants = [191030,-1675,12.5,-0.03874,4.61E-05]
16
+ _viscosity_constants = [-7.2471,534.82,-0.57469,-4.66E-27, 0]
17
+ _thermal_conductivity_constants = [0.27349, -0.00071267,5.16E-07,0,0]
18
+ _vapor_pressure_constants = [66.343,-4363.20,-7.046,9.45E-06, 2]
19
+ _enthalpy_constants = [3.6238E-7, 0.8337, -0.82274,0.39613, 0] # Placeholder for enthalpy constants
@@ -0,0 +1,19 @@
1
+ from .base import Component
2
+ from processpi.units import *
3
+
4
+
5
+ class Carbondioxide(Component):
6
+ name = "Carbon Dioxide"
7
+ formula = "CO2"
8
+ molecular_weight = 44.01
9
+ _critical_temperature = Temperature(304.21, "K")
10
+ _critical_pressure = Pressure(7.383, "MPa")
11
+ _critical_volume = Volume(0.094, "m3") # Placeholder for critical volume per Kmole
12
+ _critical_zc = 0.274 # Placeholder for critical compressibility factor
13
+ _critical_acentric_factor = 0.2236 # Placeholder for critical acentric factor
14
+ _density_constants = [2.768, 0.26212,304.21,0.2908]
15
+ _specific_heat_constants = [-8304300,104370,-433.33,0.60052,0]
16
+ _viscosity_constants = [18.775,-402.92,-4.6854,-6.92E-26, 10]
17
+ _thermal_conductivity_constants = [0.4406, -0.0012175,0,0,0]
18
+ _vapor_pressure_constants = [140.54,-4735,-21.268,4.09E-02, 1]
19
+ _enthalpy_constants = [2.173E-7, 0.382, -0.4339,0.42213, 0] # Placeholder for enthalpy constants
@@ -0,0 +1,17 @@
1
+ from .base import Component
2
+ from processpi.units import *
3
+ class CarbonMonoxide(Component):
4
+ name = "Carbon Monoxide"
5
+ formula = "CO"
6
+ molecular_weight = 28.01
7
+ _critical_temperature = Temperature(132.92, "K")
8
+ _critical_pressure = Pressure(3.499, "MPa")
9
+ _critical_volume = Volume(0.0944, "m3") # Placeholder for critical volume per Kmole
10
+ _critical_zc = 0.299 # Placeholder for critical compressibility factor
11
+ _critical_acentric_factor = 0.0482 # Placeholder for critical acentric factor
12
+ _density_constants = [2.897, 0.27532,132.92,0.2813]
13
+ _specific_heat_constants = [65.429,28723,-847.39,1,959.60,0]
14
+ _viscosity_constants = [-4.9735,97.67,-1.1088,0, 0]
15
+ _thermal_conductivity_constants = [0.2855, -0.001784,0,0,0]
16
+ _vapor_pressure_constants = [45.698,-1076.60,-4.8814,7.57E-05, 2]
17
+ _enthalpy_constants = [0.8585E-7, 0.4921, -0.326,0.2231, 0] # Placeholder for enthalpy constants
@@ -0,0 +1,17 @@
1
+ from .base import Component
2
+ from processpi.units import *
3
+ class CarbonTetrachloride(Component):
4
+ name = "Carbon Tetrachloride"
5
+ formula = "CO"
6
+ molecular_weight = 153.823
7
+ _critical_temperature = Temperature(556.35, "K")
8
+ _critical_pressure = Pressure(4.56, "MPa")
9
+ _critical_volume = Volume(0.276, "m3") # Placeholder for critical volume per Kmole
10
+ _critical_zc = 0.272 # Placeholder for critical compressibility factor
11
+ _critical_acentric_factor = 0.1926 # Placeholder for critical acentric factor
12
+ _density_constants = [0.99835, 0.274,556.35,0.287]
13
+ _specific_heat_constants = [-752700,8966.10,-30.394,0.034455,0]
14
+ _viscosity_constants = [-8.0738,1121.1,-0.4726,0, 0]
15
+ _thermal_conductivity_constants = [0.1589, -0.0001987,0,0,0]
16
+ _vapor_pressure_constants = [78.441,-6128.10,-8.5766,6.85E-06, 2]
17
+ _enthalpy_constants = [4.3252E-7, 0.37688, 250.33,3.4528, 0] # Placeholder for enthalpy constants