diff --git a/docs/source/tutorials/11_Dynamic_Simulation.ipynb b/docs/source/tutorials/11_Dynamic_Simulation.ipynb
index eae3822e..aed3ea92 100644
--- a/docs/source/tutorials/11_Dynamic_Simulation.ipynb
+++ b/docs/source/tutorials/11_Dynamic_Simulation.ipynb
@@ -47,7 +47,7 @@
"name": "stdout",
"output_type": "stream",
"text": [
- "This tutorial was made with qsdsan v1.2.2 and exposan v1.2.3\n"
+ "This tutorial was made with qsdsan v1.2.5 and exposan v1.2.5\n"
]
}
],
diff --git a/docs/source/tutorials/Tutorial_11.ipynb b/docs/source/tutorials/Tutorial_11.ipynb
new file mode 100644
index 00000000..545c1773
--- /dev/null
+++ b/docs/source/tutorials/Tutorial_11.ipynb
@@ -0,0 +1,401 @@
+{
+ "cells": [
+ {
+ "cell_type": "code",
+ "execution_count": 1,
+ "id": "9b7ba848",
+ "metadata": {
+ "scrolled": true
+ },
+ "outputs": [
+ {
+ "name": "stdout",
+ "output_type": "stream",
+ "text": [
+ "This tutorial was made with qsdsan v1.2.5 and exposan v1.2.5\n"
+ ]
+ }
+ ],
+ "source": [
+ "import qsdsan as qs, exposan\n",
+ "print(f'This tutorial was made with qsdsan v{qs.__version__} and exposan v{exposan.__version__}')"
+ ]
+ },
+ {
+ "cell_type": "code",
+ "execution_count": 2,
+ "id": "a31c8f69",
+ "metadata": {},
+ "outputs": [
+ {
+ "name": "stdout",
+ "output_type": "stream",
+ "text": [
+ "System: bsm1_sys\n",
+ "ins...\n",
+ "[0] wastewater\n",
+ " phase: 'l', T: 293.15 K, P: 101325 Pa\n",
+ " flow (kmol/hr): S_I 23.1\n",
+ " S_S 53.4\n",
+ " X_I 39.4\n",
+ " X_S 155\n",
+ " X_BH 21.7\n",
+ " S_NH 1.34\n",
+ " S_ND 0.381\n",
+ " ... 4.26e+04\n",
+ "outs...\n",
+ "[0] effluent\n",
+ " phase: 'l', T: 293.15 K, P: 101325 Pa\n",
+ " flow: 0\n",
+ "[1] WAS\n",
+ " phase: 'l', T: 293.15 K, P: 101325 Pa\n",
+ " flow: 0\n"
+ ]
+ }
+ ],
+ "source": [
+ "# Let's load the BSM1 system first\n",
+ "from exposan import bsm1\n",
+ "bsm1.load()\n",
+ "sys = bsm1.sys\n",
+ "sys.show()"
+ ]
+ },
+ {
+ "cell_type": "code",
+ "execution_count": 3,
+ "id": "5fe1776f",
+ "metadata": {},
+ "outputs": [
+ {
+ "data": {
+ "image/svg+xml": [
+ ""
+ ],
+ "text/plain": [
+ ""
+ ]
+ },
+ "metadata": {},
+ "output_type": "display_data"
+ }
+ ],
+ "source": [
+ "# The BSM1 system is composed of 5 CSTRs in series,\n",
+ "# followed by a flat-bottom circular clarifier.\n",
+ "sys.diagram()\n",
+ "# sys.units"
+ ]
+ },
+ {
+ "cell_type": "code",
+ "execution_count": 4,
+ "id": "98d2662c",
+ "metadata": {},
+ "outputs": [
+ {
+ "data": {
+ "text/plain": [
+ "True"
+ ]
+ },
+ "execution_count": 4,
+ "metadata": {},
+ "output_type": "execute_result"
+ }
+ ],
+ "source": [
+ "# We can verify that by\n",
+ "sys.isdynamic"
+ ]
+ },
+ {
+ "cell_type": "code",
+ "execution_count": 5,
+ "id": "e2c64ce0",
+ "metadata": {},
+ "outputs": [
+ {
+ "data": {
+ "text/plain": [
+ "{: True,\n",
+ " : True,\n",
+ " : True,\n",
+ " : True,\n",
+ " : True,\n",
+ " : True}"
+ ]
+ },
+ "execution_count": 5,
+ "metadata": {},
+ "output_type": "execute_result"
+ }
+ ],
+ "source": [
+ "# This is because the system contains at least one dynamic SanUnit\n",
+ "{u: u.isdynamic for u in sys.units}\n",
+ "\n",
+ "# If we disable dynamic simulation, then `simulate` would work as usual\n",
+ "# sys.isdynamic = False\n",
+ "# sys.simulate()"
+ ]
+ },
+ {
+ "cell_type": "code",
+ "execution_count": null,
+ "id": "d8cc6e48",
+ "metadata": {},
+ "outputs": [
+ {
+ "name": "stderr",
+ "output_type": "stream",
+ "text": [
+ "C:\\Users\\joy_c\\anaconda3\\envs\\tut\\lib\\site-packages\\qsdsan\\sanunits\\_suspended_growth_bioreactor.py:44: NumbaPerformanceWarning: \u001b[1m\u001b[1m'@' is faster on contiguous arrays, called on (array(float64, 1d, A), array(float64, 2d, A))\u001b[0m\u001b[0m\n",
+ " flow_in = Q_ins @ C_ins / V_arr\n",
+ "C:\\Users\\joy_c\\anaconda3\\envs\\tut\\lib\\site-packages\\numba\\core\\typing\\npydecl.py:913: NumbaPerformanceWarning: \u001b[1m'@' is faster on contiguous arrays, called on (array(float64, 1d, A), array(float64, 2d, A))\u001b[0m\n",
+ " warnings.warn(NumbaPerformanceWarning(msg))\n"
+ ]
+ }
+ ],
+ "source": [
+ "# Let's try simulating the BSM1 system from day 0 to day 50\n",
+ "sys.simulate(t_span=(0, 50), method='BDF', state_reset_hook='reset_cache')\n",
+ "sys.show()"
+ ]
+ },
+ {
+ "cell_type": "code",
+ "execution_count": null,
+ "id": "ba51c0b9",
+ "metadata": {},
+ "outputs": [],
+ "source": [
+ "# This shows the units/streams whose state variables are kept track of\n",
+ "# during dynamic simulations.\n",
+ "sys.scope.subjects"
+ ]
+ },
+ {
+ "cell_type": "code",
+ "execution_count": null,
+ "id": "c4c0bdfd",
+ "metadata": {},
+ "outputs": [],
+ "source": []
+ },
+ {
+ "cell_type": "code",
+ "execution_count": null,
+ "id": "f1d690bf",
+ "metadata": {},
+ "outputs": [],
+ "source": []
+ },
+ {
+ "cell_type": "code",
+ "execution_count": null,
+ "id": "c05808bc",
+ "metadata": {},
+ "outputs": [],
+ "source": []
+ },
+ {
+ "cell_type": "code",
+ "execution_count": null,
+ "id": "37df12a9",
+ "metadata": {},
+ "outputs": [],
+ "source": []
+ }
+ ],
+ "metadata": {
+ "kernelspec": {
+ "display_name": "Python [conda env:tut]",
+ "language": "python",
+ "name": "conda-env-tut-py"
+ },
+ "language_info": {
+ "codemirror_mode": {
+ "name": "ipython",
+ "version": 3
+ },
+ "file_extension": ".py",
+ "mimetype": "text/x-python",
+ "name": "python",
+ "nbconvert_exporter": "python",
+ "pygments_lexer": "ipython3",
+ "version": "3.9.0"
+ }
+ },
+ "nbformat": 4,
+ "nbformat_minor": 5
+}
diff --git a/qsdsan/equipments/__init__.py b/qsdsan/equipments/__init__.py
index ba0f6633..9a10c458 100644
--- a/qsdsan/equipments/__init__.py
+++ b/qsdsan/equipments/__init__.py
@@ -16,20 +16,16 @@
from ._aeration import *
from ._column import *
from ._electrode import *
-from ._encapsulation import *
from ._machine import*
from ._membrane import *
-from ._vacuum_pump import *
from ._vertical_mixer import *
from . import (
_aeration,
_column,
_electrode,
- _encapsulation,
_machine,
_membrane,
- _vacuum_pump,
_vertical_mixer,
)
@@ -38,9 +34,7 @@
*_aeration.__all__,
*_column.__all__,
*_electrode.__all__,
- *_encapsulation.__all__,
*_machine.__all__,
*_membrane.__all__,
- *_vacuum_pump.__all__,
*_vertical_mixer.__all__,
)
\ No newline at end of file
diff --git a/qsdsan/equipments/_encapsulation.py b/qsdsan/equipments/_encapsulation.py
deleted file mode 100644
index cba95529..00000000
--- a/qsdsan/equipments/_encapsulation.py
+++ /dev/null
@@ -1,44 +0,0 @@
-# -*- coding: utf-8 -*-
-'''
-QSDsan: Quantitative Sustainable Design for sanitation and resource recovery systems
-
-This module is developed by:
- Joy Zhang
-
-Part of this module is based on the BioSTEAM package:
-https://github.com/BioSTEAMDevelopmentGroup/biosteam
-
-This module is under the University of Illinois/NCSA Open Source License.
-Please refer to https://github.com/QSD-Group/QSDsan/blob/main/LICENSE.txt
-for license details.
-'''
-
-from .. import Equipment
-
-__all__ = ('Beads',)
-
-class Beads(Equipment):
-
- def __init__(self, linked_unit=None, ID=None,
- units={'Diameter': 'mm',
- 'Density': 'kg/m3',
- 'Unit cost': 'USD/kg',
- 'Bead total mass': 'kg'},
- F_BM=1.15, F_D=1., F_P=1., F_M=1.,
- lifetime=0.5, lifetime_unit='yr',
- d_bead=1.0, rho_bead=265, p_bead=1440,
- **kwargs):
-
- Equipment.__init__(self, linked_unit, ID, units, F_BM, F_D, F_P, F_M,
- lifetime, lifetime_unit, **kwargs)
- self.d_bead = d_bead
- self.rho_bead = rho_bead
- self.p_bead = p_bead
-
- def _design(self):
- V_bead = self.linked_unit.design_results['Bead total volume']
- return {'Bead total mass': V_bead * self.rho_bead}
-
- def _cost(self):
- m = self._design()['Bead total mass']
- return m * self.p_bead
\ No newline at end of file
diff --git a/qsdsan/equipments/_membrane.py b/qsdsan/equipments/_membrane.py
index 8f88e31a..527bb2f8 100644
--- a/qsdsan/equipments/_membrane.py
+++ b/qsdsan/equipments/_membrane.py
@@ -19,7 +19,7 @@
from .. import Equipment
# from .utils import auom
-__all__ = ('Membrane', 'HollowFiberMembrane')
+__all__ = ('Membrane', )
class Membrane(Equipment):
@@ -80,50 +80,4 @@ def N(self):
return self._N
@N.setter
def N(self, i):
- self._N = int(i)
-
-
-class HollowFiberMembrane(Equipment):
-
- _PermSelect_pricing = {
- # model: (area [cm^2], price [USD], min Q_gas [scfm], max Q_gas [scfm])
- 'PDMSXA-10': (10, 117, 4e-5, 4e-3),
- 'PDMSXA-1000': (1000, 304, 4e-3, 0.4),
- 'PDMSXA-7500': (7500, 541, 2e-2, 1.0),
- 'PDMSXA-2.1': (2.1e4, 1045, 4e-2, 2.0)
- }
-
- scfm_to_kmolphr = 0.002641 * 453.59237 * 60 / 1000
-
- def __init__(self, ID='', linked_unit=None,
- units=dict(), F_BM=1.15, lifetime=5, lifetime_unit='yr',
- material='polydimethylsiloxane'):
- Equipment.__init__(self=self, ID=ID, linked_unit=linked_unit, units=units,
- F_BM=F_BM, lifetime=lifetime, lifetime_unit=lifetime_unit)
- self.material = material
-
- def _design(self):
- for ws in self.linked_unit.outs:
- if ws.phase == 'g':
- Q_mol = ws.F_mol # kmol/hr
- break
- key = None
- N = 0
- while not key:
- N += 1
- Q = Q_mol / N
- for md, data in self._PermSelect_pricing.items():
- Q_max = data[-1] * self.scfm_to_kmolphr
- if Q < Q_max:
- key = md
- return {'Material': self.material,
- 'Number of membrane units': N,
- 'Membrane unit model':key}
-
- def _cost(self):
- design = self._design()
- N = design['Number of membrane units']
- key = design['Membrane unit model']
- p = self._PermSelect_pricing[key][1]
- return N * p
-
\ No newline at end of file
+ self._N = int(i)
\ No newline at end of file
diff --git a/qsdsan/equipments/_vacuum_pump.py b/qsdsan/equipments/_vacuum_pump.py
deleted file mode 100644
index 5d3db1bb..00000000
--- a/qsdsan/equipments/_vacuum_pump.py
+++ /dev/null
@@ -1,65 +0,0 @@
-# -*- coding: utf-8 -*-
-'''
-QSDsan: Quantitative Sustainable Design for sanitation and resource recovery systems
-
-This module is developed by:
- Joy Zhang
-
-Part of this module is based on the BioSTEAM package:
-https://github.com/BioSTEAMDevelopmentGroup/biosteam
-
-This module is under the University of Illinois/NCSA Open Source License.
-Please refer to https://github.com/QSD-Group/QSDsan/blob/main/LICENSE.txt
-for license details.
-'''
-
-from .. import Equipment
-from math import log
-
-__all__ = ('VacuumPump',)
-
-class VacuumPump(Equipment):
-
- def __init__(self, linked_unit=None, ID=None,
- units={'P_suction': 'torr', 'Vacuum power': 'kW'},
- F_BM=1., F_D=1., F_P=1., F_M=1.,
- lifetime=20, lifetime_unit='yr',
- P_suction=100, **kwargs):
-
- Equipment.__init__(self, linked_unit, ID, units, F_BM, F_D, F_P, F_M,
- lifetime, lifetime_unit, **kwargs)
- self.P_suction = P_suction
-
- @property
- def P_vacuum(self):
- P_break = 21.4 * self._SF()**0.924
- e_motor = 0.8 + 0.0319*log(P_break, 10) - 0.00182 * log(P_break, 10)**2
- return P_break/e_motor # in kW
-
- def _SF(self, for_cost=False):
- # P_sunction in torr, Qm in kg/hr
- for ws in self.linked_unit.outs:
- if ws.phase == 'g':
- Qm = ws.F_mass # kg/hr
- break
- Ps = self.P_suction # torr
- if for_cost:
- return Qm/Ps*2.2 # convert Qm to lb/hr
- else:
- return min(16, max(0.2, Qm/Ps))
-
- def _design(self):
- return {'Vacuum power': self.P_vacuum}
-
- def _cost(self):
- SF = self._SF(True)
- return 1915 * SF**0.41
-
- @property
- def P_suction(self):
- return self._Ps
-
- @P_suction.setter
- def P_suction(self, P):
- if P <= 0: raise ValueError(f'Suction pressure [torr] must be positive, not {P}')
- self._Ps = P
\ No newline at end of file
diff --git a/qsdsan/processes/_adm1.py b/qsdsan/processes/_adm1.py
index 9c0457f6..32d99819 100644
--- a/qsdsan/processes/_adm1.py
+++ b/qsdsan/processes/_adm1.py
@@ -315,7 +315,7 @@ def rhos_adm1(state_arr, params):
# =============================================================================
class TempState:
def __init__(self):
- self.data = []
+ self.data = {}
# def append(self, value):
# self.data += [value]
@@ -531,6 +531,7 @@ class ADM1(CompiledProcesses):
('HAc', 'Ac-'), ('HPr', 'Pr-'),
('HBu', 'Bu-'), ('HVa', 'Va-'))
_biogas_IDs = ('S_h2', 'S_ch4', 'S_IC')
+ _biomass_IDs = ('X_su', 'X_aa', 'X_fa', 'X_c4', 'X_pro', 'X_ac', 'X_h2')
def __new__(cls, components=None, path=None, N_xc=2.686e-3, N_I=4.286e-3, N_aa=7e-3,
f_ch_xc=0.2, f_pr_xc=0.2, f_li_xc=0.3, f_xI_xc=0.2,
@@ -591,7 +592,6 @@ def __new__(cls, components=None, path=None, N_xc=2.686e-3, N_I=4.286e-3, N_aa=7
Ka_base = np.array([10**(-pKa) for pKa in pKa_base])
Ka_dH = np.array(Ka_dH)
root = TempState()
- # root.data = 10**(-7.4655)
dct = self.__dict__
dct.update(kwargs)
diff --git a/qsdsan/sanunits/__init__.py b/qsdsan/sanunits/__init__.py
index 6b0ebccc..625ad879 100644
--- a/qsdsan/sanunits/__init__.py
+++ b/qsdsan/sanunits/__init__.py
@@ -41,7 +41,6 @@
from ._crop_application import *
from ._dynamic_influent import *
from ._electrochemical_cell import *
-from ._encapsulation_bioreactor import *
from ._excretion import *
from ._heat_exchanging import *
from ._junction import *
@@ -89,7 +88,6 @@
_distillation,
_dynamic_influent,
_electrochemical_cell,
- _encapsulation_bioreactor,
_excretion,
_flash,
_heat_exchanging,
@@ -133,7 +131,6 @@
*_distillation.__all__,
*_dynamic_influent.__all__,
*_electrochemical_cell.__all__,
- *_encapsulation_bioreactor.__all__,
*_excretion.__all__,
*_flash.__all__,
*_heat_exchanging.__all__,
diff --git a/qsdsan/sanunits/_encapsulation_bioreactor.py b/qsdsan/sanunits/_encapsulation_bioreactor.py
deleted file mode 100644
index 365b200f..00000000
--- a/qsdsan/sanunits/_encapsulation_bioreactor.py
+++ /dev/null
@@ -1,338 +0,0 @@
-# -*- coding: utf-8 -*-
-'''
-QSDsan: Quantitative Sustainable Design for sanitation and resource recovery systems
-
-This module is developed by:
- Joy Zhang
-
-Part of this module is based on the BioSTEAM package:
-https://github.com/BioSTEAMDevelopmentGroup/biosteam
-
-This module is under the University of Illinois/NCSA Open Source License.
-Please refer to https://github.com/QSD-Group/QSDsan/blob/main/LICENSE.txt
-for license details.
-'''
-
-from .. import SanUnit
-from ..equipments import VerticalMixer, VacuumPump, HollowFiberMembrane, Beads
-from ..utils import auom
-from warnings import warn
-from math import pi
-
-__all__ = ('H2E', 'CH4E')
-
-class H2E(SanUnit):
-
- _N_ins = 1
- _N_outs = 2
- _N_heat_utilities = 1
- A = 265
- b = 0.513
- _Vmin = 1e4 # gal
- _Vmax = 1e6 # gal
- _rho_bead = 265 # kg/m3
-
-
- def __init__(self, ID='', ins=None, outs=(), thermo=None,
- init_with='WasteStream', equipments=(), lifetime=20,
- COD_removal=0.2, H2_yield=4e-4, CH4_yield=0.0, frac_H2=0.28,
- tau=1, T=273.15+35, safety_factor=1.3,
- V_frac_beads=0.09, e_heat=0.8, p_treatment=0.24, **kwargs):
- SanUnit.__init__(self, ID, ins, outs, thermo, init_with,
- equpiments=equipments, lifetime=lifetime, F_BM_default=1)
- self.COD_removal = COD_removal
- self.H2_yield = H2_yield
- self.CH4_yield = CH4_yield
- self.frac_H2 = frac_H2
- self.tau = tau
- self.T = T
- self.safety_factor = safety_factor
- self.V_frac_beads = V_frac_beads
- self.e_heat = e_heat
- self.p_treatment = p_treatment
- for attr, value in kwargs.items():
- setattr(self, attr, value)
- self._init_equip(lifetime)
-
- def _init_equip(self, lifetime):
- if self.equipments:
- isa = isinstance
- equips = list(self.equipments)
- vm = None
- vp = None
- mb = None
- encap = None
- for i in equips:
- if isa(i, VerticalMixer):
- vm = i
- equips.remove(i)
- elif isa(i, VacuumPump):
- vp = i
- equips.remove(i)
- elif isa(i, HollowFiberMembrane):
- mb = i
- equips.remove(i)
- elif isa(i, Beads):
- encap = i
- equips.remove(i)
- if not vm:
- warn('lacking vertical mixer as equipment, will use a default one')
- vm = VerticalMixer(linked_unit=self, ID='mixer', lifetime=lifetime)
- if not vp:
- warn('lacking vacuum pump as equipment, will use a default one')
- vp = VacuumPump(linked_unit=self, ID='vacuum', lifetime=lifetime)
- if not mb:
- warn('lacking hollow fiber membrane as equipment, will use a default one')
- mb = HollowFiberMembrane(linked_unit=self, ID='membrane', lifetime=10)
- if not encap:
- warn('lacking encapsulation beads as equipment, will use a default one')
- encap = Beads(linked_unit=self, ID='beads', lifetime=0.5)
- self.equipments = (vm, vp, mb, encap, *equips)
- else:
- vm = VerticalMixer(linked_unit=self, ID='mixer', lifetime=lifetime)
- vp = VacuumPump(linked_unit=self, ID='vacuum', lifetime=lifetime)
- mb = HollowFiberMembrane(linked_unit=self, ID='membrane', lifetime=10)
- encap = Beads(linked_unit=self, ID='beads', lifetime=0.5)
- self.equipments = (vm, vp, mb, encap)
-
- def _run(self):
- waste, = self.ins
- eff, biogas = self.outs
- eff.copy_like(waste)
- biogas.phase = 'g'
-
- # COD removal
- COD_rmv = eff.imass['COD'] * self.COD_removal
- eff.imass['COD'] -= COD_rmv
- biogas.imass['H2'] = h2 = COD_rmv*self.H2_yield
- biogas.imass['CH4'] = ch4 = COD_rmv*self.CH4_yield
- biogas.imass['N2'] = h2/self.frac_H2 - h2 - ch4
-
- _units = {
- 'Residence time': 'd',
- 'Reactor volume': 'm3',
- 'Bead total volume': 'm3'
- }
-
- def _design(self):
- Q = self.ins[0].F_vol * 24 #m3/d
- design = self.design_results
- design['Residence time'] = t = self.tau
- design['Reactor volume'] = V = t * Q * self.safety_factor
- design['Bead total volume'] = V * self.V_frac_beads
- self.add_equipment_design()
- mixer, vacuum = self.equipments[:2]
- P_mix = mixer.power * mixer.N_mix
- P_vcm = vacuum.P_vacuum
- self.power_utility(rate=P_mix+P_vcm)
- hu = self.heat_utilities[0]
- hu.heat_transfer_efficiency = self.e_heat
- inf = self.ins[0]
- T_in = inf.T
- T_target = self.T
- unit_duty = inf.F_mass * inf.Cp * (T_target - T_in) #kJ/hr
- hu(unit_duty, T_in, T_target)
-
- def _cost(self):
- D, C = self.design_results, self.baseline_purchase_costs
- V = D['Reactor volume'] * auom('m3').conversion_factor('gal')
- C['Reactor'] = self.A * min(self._Vmax, max(self._Vmin, V)) ** self.b # cone-roof carbon steel storage tank
- self.add_equipment_cost()
- eff = self.outs[0]
- if eff.isproduct():
- self.add_OPEX = {'Effluent treatment': self.p_treatment * eff.imass['COD']} # USD/hr
-
- @property
- def COD_removal(self):
- return self._rcod
-
- @COD_removal.setter
- def COD_removal(self, r):
- if r > 1 or r < 0:
- raise ValueError(f'COD removal must be in [0, 1], not {r}')
- self._rcod = r
-
- @property
- def H2_yield(self):
- return self._yh2
-
- @H2_yield.setter
- def H2_yield(self, y):
- if y > 8 or y < 0:
- raise ValueError(f'H2 yield must be in [0, 8] g-H2/g-COD-removed, not {y}')
- self._yh2 = y
-
- @property
- def CH4_yield(self):
- return self._ych4
-
- @CH4_yield.setter
- def CH4_yield(self, y):
- if y > 4 or y < 0:
- raise ValueError(f'H2 yield must be in [0, 4] g-CH4/g-COD-removed, not {y}')
- self._ych4 = y
-
- @property
- def frac_H2(self):
- return self._fh2
- @frac_H2.setter
- def frac_H2(self, f):
- if f > 1 or f < 0:
- raise ValueError(f'H2 mass fraction in biogas must be in [0, 1], not {f}')
- self._fh2 = f
-
- @property
- def tau(self):
- return self._tau
-
- @tau.setter
- def tau(self, t):
- if t < 0: raise ValueError(f'residence time tau cannot be negative: {t}')
- self._tau = t
-
- @property
- def T(self):
- return self._T
- @T.setter
- def T(self, i):
- if i < self.ins[0].T:
- warn('Operating temperature should not be lower than influent temperature {self.ins[0].T}')
- i = self.ins[0].T
- self._T = i
-
- @property
- def safety_factor(self):
- return self._sf
- @safety_factor.setter
- def safety_factor(self, sf):
- if sf < 1: raise ValueError(f'safety factor cannot be less than 1: {sf}')
- self._sf = sf
-
- @property
- def V_frac_beads(self):
- return self._f_Vb
- @V_frac_beads.setter
- def V_frac_beads(self, f):
- if f > 1 or f < 0:
- raise ValueError(f'Volume fraction of beads in the reactor must be in [0, 1], not {f}')
- self._f_Vb = f
-
- @property
- def e_heat(self):
- return self._eh
- @e_heat.setter
- def e_heat(self, e):
- if e > 1 or e < 0:
- raise ValueError(f'Heat transfer efficiency must be in [0, 1], not {e}')
- self._eh = e
-
- @property
- def p_treatment(self):
- return self._ptreat
- @p_treatment.setter
- def p_treatment(self, p):
- self._ptreat = p # USD/kg-COD
-
-class CH4E(H2E):
-
- def __init__(self, ID='', ins=None, outs=(), thermo=None, init_with='WasteStream',
- equipments=(), lifetime=20, COD_removal=0.55, CH4_yield=0.135,
- frac_CH4=0.62, tau=15, T=273.15+35, d_wall=0.1, d_slab=0.1,
- safety_factor=1.3, V_frac_beads=0.09, e_heat=0.8,
- p_treatment=0.24, p_wall_concrete=497.25,
- p_slab_concrete=267.75, p_steel=1203, **kwargs):
- H2E.__init__(self, ID, ins, outs, thermo, init_with, equipments, lifetime,
- COD_removal, 0, CH4_yield, 0, tau, T, safety_factor,
- V_frac_beads, e_heat, p_treatment, **kwargs)
- self.frac_CH4 = frac_CH4
- self.d_wall = d_wall
- self.d_slab = d_slab
- self.p_wall_concrete = p_wall_concrete
- self.p_slab_concrete = p_slab_concrete
- self.p_steel = p_steel
-
- def _run(self):
- waste, = self.ins
- eff, biogas = self.outs
- eff.copy_like(waste)
- biogas.phase = 'g'
-
- # COD removal
- COD_rmv = eff.imass['COD'] * self.COD_removal
- eff.imass['COD'] -= COD_rmv
- biogas.imass['H2'] = h2 = COD_rmv*self.H2_yield
- biogas.imass['CH4'] = ch4 = COD_rmv*self.CH4_yield
- biogas.imass['N2'] = ch4/self.frac_CH4 - h2 - ch4
-
- _units = {
- 'Wall concrete volume': 'm3',
- 'Slab concrete volume': 'm3',
- 'Steel cover area': 'm2',
- **H2E._units
- }
-
- def _design(self):
- H2E._design(self)
- design = self.design_results
- V = design['Reactor volume']
- design['Wall concrete volume'] = 2 * pi**(1/3) * V**(2/3) * self.d_wall
- design['Slab concrete volume'] = pi**(1/3) * V**(2/3) * self.d_slab
- design['Steel cover area'] = 5**(1/2) / 2 * pi**(1/3) * V**(2/3)
-
- def _cost(self):
- D, C = self.design_results, self.baseline_purchase_costs
- C['Wall concrete'] = D['Wall concrete volume'] * self.p_wall_concrete
- C['Slab concrete'] = D['Slab concrete volume'] * self.p_slab_concrete
- C['Steel cover'] = D['Steel cover area'] * self.p_steel
- self.add_equipment_cost()
- eff = self.outs[0]
- if eff.isproduct():
- self.add_OPEX = {'Effluent treatment': self.p_treatment * eff.imass['COD']} # USD/hr
-
- @property
- def frac_CH4(self):
- return self._fch4
- @frac_CH4.setter
- def frac_CH4(self, f):
- if f > 1 or f < 0:
- raise ValueError(f'CH4 mass fraction in biogas must be in [0, 1], not {f}')
- self._fch4 = f
-
- @property
- def d_wall(self):
- return self._dw
-
- @d_wall.setter
- def d_wall(self, d):
- if d < 0: raise ValueError(f'wall thickness cannot be negative: {d}')
- self._dw = d
-
- @property
- def d_slab(self):
- return self._ds
-
- @d_slab.setter
- def d_slab(self, d):
- if d < 0: raise ValueError(f'slab thickness cannot be negative: {d}')
- self._ds = d
-
- @property
- def p_wall_concrete(self):
- return self._pwall
- @p_wall_concrete.setter
- def p_wall_concrete(self, p):
- self._pwall = p # USD/m3
-
- @property
- def p_slab_concrete(self):
- return self._pslab
- @p_slab_concrete.setter
- def p_slab_concrete(self, p):
- self._pslab = p # USD/m3
-
- @property
- def p_steel(self):
- return self._pstl
- @p_steel.setter
- def p_steel(self, p):
- self._pstl = p # USD/m2
\ No newline at end of file