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.
- processpi/__init__.py +1 -0
- processpi/calculations/__init__.py +3 -0
- processpi/calculations/base.py +55 -0
- processpi/calculations/engine.py +69 -0
- processpi/calculations/fluids/__init__.py +13 -0
- processpi/calculations/fluids/cool_brook_white.py +49 -0
- processpi/calculations/fluids/flow_type.py +37 -0
- processpi/calculations/fluids/optimium_pipe_dia.py +45 -0
- processpi/calculations/fluids/pressure_drop_darcy.py +25 -0
- processpi/calculations/fluids/pressure_drop_fanning.py +25 -0
- processpi/calculations/fluids/pump_power.py +34 -0
- processpi/calculations/fluids/reynolds_number.py +24 -0
- processpi/calculations/fluids/velocity.py +36 -0
- processpi/calculations/heat_transfer/__init__.py +4 -0
- processpi/calculations/heat_transfer/conduction_heat_loss.py +26 -0
- processpi/calculations/heat_transfer/convection_heat_loss.py +23 -0
- processpi/calculations/heat_transfer/heat_exchanger_area.py +26 -0
- processpi/calculations/mass_transfer/__init__.py +3 -0
- processpi/calculations/mass_transfer/distillation_stage_count.py +346 -0
- processpi/calculations/mass_transfer/drying_rate.py +132 -0
- processpi/calculations/reaction_engineering/__init__.py +4 -0
- processpi/calculations/reaction_engineering/catalyst_activity.py +109 -0
- processpi/calculations/reaction_engineering/reaction_rate.py +143 -0
- processpi/calculations/reaction_engineering/residence_time.py +80 -0
- processpi/calculations/thermodynamics/__init__.py +4 -0
- processpi/calculations/thermodynamics/enthalpy_change.py +23 -0
- processpi/calculations/thermodynamics/entropy_change.py +25 -0
- processpi/calculations/thermodynamics/heat_of_vaporization.py +20 -0
- processpi/components/__init__.py +5 -0
- processpi/components/aceticacid.py +19 -0
- processpi/components/acetone.py +20 -0
- processpi/components/acrylicacid.py +19 -0
- processpi/components/air.py +20 -0
- processpi/components/ammonia.py +19 -0
- processpi/components/base.py +85 -0
- processpi/components/benzene.py +40 -0
- processpi/components/benzoicacid.py +19 -0
- processpi/components/bromine.py +19 -0
- processpi/components/butane.py +19 -0
- processpi/components/carbondioxide.py +19 -0
- processpi/components/carbonmonoxide.py +17 -0
- processpi/components/carbontetrachloride.py +17 -0
- processpi/components/chlorine.py +17 -0
- processpi/components/chlorobenzene.py +17 -0
- processpi/components/chloroform.py +17 -0
- processpi/components/chloromethane.py +17 -0
- processpi/components/cyanogen.py +17 -0
- processpi/components/cyclohexene.py +17 -0
- processpi/components/ethane.py +17 -0
- processpi/components/ethanol.py +20 -0
- processpi/components/ethylacetate.py +17 -0
- processpi/components/methanol.py +20 -0
- processpi/components/toluene.py +22 -0
- processpi/components/water.py +24 -0
- processpi/pipelines/__init__.py +0 -0
- processpi/pipelines/base.py +76 -0
- processpi/pipelines/design_rules.py +91 -0
- processpi/pipelines/engine.py +718 -0
- processpi/pipelines/equipment.py +32 -0
- processpi/pipelines/fittings.py +76 -0
- processpi/pipelines/insulation.py +0 -0
- processpi/pipelines/materials.py +102 -0
- processpi/pipelines/network.py +277 -0
- processpi/pipelines/pipelineresults.py +95 -0
- processpi/pipelines/pipes.py +84 -0
- processpi/pipelines/pumps.py +83 -0
- processpi/pipelines/selection.py +89 -0
- processpi/pipelines/standards.py +279 -0
- processpi/pipelines/vessel.py +34 -0
- processpi/units/__init__.py +38 -0
- processpi/units/area.py +51 -0
- processpi/units/base.py +57 -0
- processpi/units/density.py +47 -0
- processpi/units/diameter.py +58 -0
- processpi/units/dimensionless.py +42 -0
- processpi/units/heat_flux.py +46 -0
- processpi/units/heat_of_vaporization.py +47 -0
- processpi/units/heat_transfer_coefficient.py +45 -0
- processpi/units/length.py +47 -0
- processpi/units/mass.py +50 -0
- processpi/units/mass_flowrate.py +50 -0
- processpi/units/pressure.py +57 -0
- processpi/units/specific_heat.py +47 -0
- processpi/units/strings.py +31 -0
- processpi/units/temperature.py +51 -0
- processpi/units/thermal_conductivity.py +45 -0
- processpi/units/thermal_resistance.py +46 -0
- processpi/units/velocity.py +45 -0
- processpi/units/viscosity.py +78 -0
- processpi/units/volume.py +50 -0
- processpi/units/volumetric_flowrate.py +52 -0
- processpi-0.0.0.dist-info/METADATA +5 -0
- processpi-0.0.0.dist-info/RECORD +96 -0
- processpi-0.0.0.dist-info/WHEEL +5 -0
- processpi-0.0.0.dist-info/licenses/LICENSE +21 -0
- 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,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,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 = "C3H4O2"
|
|
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
|