Skip to content

Commit

Permalink
Merge branch 'main' into dev
Browse files Browse the repository at this point in the history
  • Loading branch information
joyxyz1994 committed Aug 13, 2024
2 parents f0809e2 + 9ce5a7f commit 15c596e
Show file tree
Hide file tree
Showing 13 changed files with 317 additions and 137 deletions.
1 change: 1 addition & 0 deletions docs/source/api/sanunits/_index.rst
Original file line number Diff line number Diff line change
Expand Up @@ -39,6 +39,7 @@ Individual Unit Operations
DynamicInfluent
ElectrochemicalCell
Excretion
facilities
Flash
heat_exchanging
hydroprocessing
Expand Down
4 changes: 4 additions & 0 deletions docs/source/api/sanunits/facilities.rst
Original file line number Diff line number Diff line change
@@ -0,0 +1,4 @@
Distillation
============
.. automodule:: qsdsan.sanunits._facilities
:members:
2 changes: 1 addition & 1 deletion docs/source/tutorials/3_WasteStream.ipynb
Original file line number Diff line number Diff line change
Expand Up @@ -57,7 +57,7 @@
"source": [
"---\n",
"### Note\n",
"`qsdsan` can work with three main stream classes: `Stream`, `SanStream`, and `WasteStream`. `Stream` is from the package `thermosteam` while `SanStream` and `WasteStream` are created in `qsdsan`. The following tutorial is focused on `WasteStream` as it is one of the core classes of `qsdsan`. You can learn more about the different classes in the [documentation](https://qsdsan.readthedocs.io/en/latest/Streams.html).\n",
"`qsdsan` can work with three main stream classes: `Stream`, `SanStream`, and `WasteStream`. `Stream` is from the package `thermosteam` while `SanStream` and `WasteStream` are created in `qsdsan`. The following tutorial is focused on `WasteStream` as it is one of the core classes of `qsdsan`. You can learn more about the different classes in the [documentation](https://qsdsan.readthedocs.io/en/latest/api/streams.html).\n",
"\n",
"In the future, it is likely that the `SanStream` class will be merged into `thermosteam` so that LCA can be implemented for systems developed using `BioSTEAM`."
]
Expand Down
274 changes: 180 additions & 94 deletions qsdsan/_lca.py

Large diffs are not rendered by default.

7 changes: 6 additions & 1 deletion qsdsan/_sanunit.py
Original file line number Diff line number Diff line change
Expand Up @@ -19,7 +19,7 @@

# %%

import numpy as np
import numpy as np, biosteam as bst
from collections import defaultdict
from collections.abc import Iterable
from warnings import warn
Expand Down Expand Up @@ -208,6 +208,11 @@ def __init__(self, ID='', ins=None, outs=(), thermo=None, init_with='WasteStream
#: value.
self.parallel: dict[str, int] = {}

#: Unit design decisions that must be solved to satisfy specifications.
#: While adding responses is optional, simulations benefit from responses
#: by being able to predict better guesses.
self.responses: set[bst.GenericResponse] = set()

if not kwargs.get('skip_property_package_check'):
self._assert_compatible_property_package()

Expand Down
3 changes: 3 additions & 0 deletions qsdsan/sanunits/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -52,6 +52,7 @@ def dydt_cstr(QC_ins, QC, V, _dstate):
from ._dynamic_influent import *
from ._electrochemical_cell import *
from ._excretion import *
from ._facilities import *
from ._heat_exchanging import *
from ._junction import *
from ._membrane_gas_extraction import *
Expand Down Expand Up @@ -102,6 +103,7 @@ def dydt_cstr(QC_ins, QC, V, _dstate):
_dynamic_influent,
_electrochemical_cell,
_excretion,
_facilities,
_flash,
_heat_exchanging,
_hydroprocessing,
Expand Down Expand Up @@ -147,6 +149,7 @@ def dydt_cstr(QC_ins, QC, V, _dstate):
*_dynamic_influent.__all__,
*_electrochemical_cell.__all__,
*_excretion.__all__,
*_facilities.__all__,
*_flash.__all__,
*_heat_exchanging.__all__,
*_hydroprocessing.__all__,
Expand Down
22 changes: 18 additions & 4 deletions qsdsan/sanunits/_distillation.py
Original file line number Diff line number Diff line change
Expand Up @@ -17,11 +17,14 @@

import biosteam as bst, qsdsan as qs

__all__ = ('BinaryDistillation',)
__all__ = (
'BinaryDistillation',
'ShortcutColumn',
)

_lb_to_kg = qs.utils.auom('lb').conversion_factor('kg')

class BinaryDistillation(bst.units.BinaryDistillation):
class BinaryDistillation(bst.units.BinaryDistillation, qs.SanUnit):
'''
Similar to biosteam.units.BinaryDistillation, but can include construction impact calculation.
Expand All @@ -30,7 +33,7 @@ class BinaryDistillation(bst.units.BinaryDistillation):
`biosteam.units.BinaryDistillation <https://biosteam.readthedocs.io/en/latest/API/units/distillation.html>`_
'''

include_construction = False
include_construction = True

def _design(self):
super()._design()
Expand All @@ -42,4 +45,15 @@ def _design(self):
self.construction = [
qs.Construction('carbon_steel', linked_unit=self, item='Carbon_steel',
quantity=(D['Rectifier weight'] + D['Stripper weight'])*_lb_to_kg, quantity_unit='kg'),
]
]



class ShortcutColumn(bst.units.ShortcutColumn, qs.SanUnit):
'''
biosteam.units.ShortcutColumn with QSDsan properties.
See Also
--------
`biosteam.units.ShortcutColumn <https://biosteam.readthedocs.io/en/latest/API/units/distillation.html>`_
'''
29 changes: 29 additions & 0 deletions qsdsan/sanunits/_facilities.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,29 @@
#!/usr/bin/env python3
# -*- coding: utf-8 -*-

'''
QSDsan: Quantitative Sustainable Design for sanitation and resource recovery systems
This module is developed by:
Yalin Li <mailto.yalin.li@gmail.com>
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.
'''

import biosteam as bst, qsdsan as qs

__all__ = (
'ProcessWaterCenter',
)

class ProcessWaterCenter(bst.facilities.ProcessWaterCenter, qs.SanUnit):
'''
biosteam.facilities.ProcessWaterCenter with QSDsan properties.
See Also
--------
`biosteam.facilities.ProcessWaterCenter <https://biosteam.readthedocs.io/en/latest/API/facilities/ProcessWaterCenter.html>`_
'''
4 changes: 2 additions & 2 deletions qsdsan/sanunits/_flash.py
Original file line number Diff line number Diff line change
Expand Up @@ -21,7 +21,7 @@

_lb_to_kg = qs.utils.auom('lb').conversion_factor('kg')

class Flash(bst.units.Flash):
class Flash(bst.units.Flash, qs.SanUnit):
'''
Similar to biosteam.units.Flash, but can include construction impact calculation.
Expand All @@ -30,7 +30,7 @@ class Flash(bst.units.Flash):
`biosteam.units.Flash <https://biosteam.readthedocs.io/en/latest/API/units/Flash.html>`_
'''

include_construction = False
include_construction = True

def _design(self):
super()._design()
Expand Down
68 changes: 50 additions & 18 deletions qsdsan/sanunits/_heat_exchanging.py
Original file line number Diff line number Diff line change
Expand Up @@ -106,16 +106,21 @@ class HXprocess(SanUnit, HXP):
_N_ins = HXP._N_ins
_N_outs = HXP._N_outs

def __init__(self, ID='', ins=None, outs=(), thermo=None,
init_with='Stream', F_BM_default=None,
*, U=None, dT=5., T_lim0=None, T_lim1=None,
material="Carbon steel/carbon steel",
heat_exchanger_type="Floating head",
N_shells=2, ft=None,
phase0=None,
phase1=None,
H_lim0=None,
H_lim1=None):
def __init__(
self, ID='', ins=None, outs=(), thermo=None,
init_with='Stream', F_BM_default=None, *,
U=None, dT=5., T_lim0=None, T_lim1=None,
material="Carbon steel/carbon steel",
heat_exchanger_type="Floating head",
N_shells=2, ft=None,
phase0=None,
phase1=None,
H_lim0=None,
H_lim1=None,
inner_fluid_pressure_drop=None,
outer_fluid_pressure_drop=None,
neglect_pressure_drop=True,
):
SanUnit.__init__(self, ID, ins, outs, thermo,
init_with=init_with, F_BM_default=F_BM_default)

Expand Down Expand Up @@ -155,6 +160,15 @@ def __init__(self, ID='', ins=None, outs=(), thermo=None,
self.material = material
self.heat_exchanger_type = heat_exchanger_type
self.reset_streams_at_setup = False

#: Optional[float] Pressure drop along the inner fluid.
self.inner_fluid_pressure_drop = inner_fluid_pressure_drop

#: Optional[float] Pressure drop along the outer fluid.
self.outer_fluid_pressure_drop = outer_fluid_pressure_drop

#: [bool] Whether to assume a negligible pressure drop.
self.neglect_pressure_drop = neglect_pressure_drop


class HXutility(SanUnit, HXU):
Expand All @@ -176,6 +190,7 @@ class HXutility(SanUnit, HXU):

line = HXU.line
_graphics = HXU._graphics

_units = {'Area': 'ft^2',
'Total tube length': 'ft',
'Inner pipe weight': 'kg',
Expand All @@ -190,14 +205,22 @@ class HXutility(SanUnit, HXU):
'Horizontal vessel diameter': (3, 21),
'Vertical vessel length': (12, 40)}

def __init__(self, ID='', ins=None, outs=(), thermo=None,
init_with='Stream', F_BM_default=None,
include_construction=True,
*, T=None, V=None, rigorous=False, U=None, H=None,
heat_exchanger_type="Floating head",
material="Carbon steel/carbon steel",
N_shells=2, ft=None, heat_only=None, cool_only=None,
heat_transfer_efficiency=None):
def __init__(
self, ID='', ins=None, outs=(), thermo=None,
init_with='Stream', F_BM_default=None,
include_construction=True,
T=None, V=None, rigorous=False, U=None, H=None,
heat_exchanger_type="Floating head",
material="Carbon steel/carbon steel",
N_shells=2,
ft=None,
heat_only=None,
cool_only=None,
heat_transfer_efficiency=None,
inner_fluid_pressure_drop=None,
outer_fluid_pressure_drop=None,
neglect_pressure_drop=True,
):
SanUnit.__init__(self, ID, ins, outs, thermo,
init_with=init_with, F_BM_default=F_BM_default,
include_construction=include_construction,)
Expand Down Expand Up @@ -226,6 +249,15 @@ def __init__(self, ID='', ins=None, outs=(), thermo=None,
self.material = material
self.heat_exchanger_type = heat_exchanger_type

#: Optional[float] Pressure drop along the inner fluid.
self.inner_fluid_pressure_drop = inner_fluid_pressure_drop

#: Optional[float] Pressure drop along the outer fluid.
self.outer_fluid_pressure_drop = outer_fluid_pressure_drop

#: [bool] Whether to assume a negligible pressure drop.
self.neglect_pressure_drop = neglect_pressure_drop

#: [bool] User enforced heat transfer efficiency. A value less than 1
#: means that a fraction of heat transferred is lost to the environment.
#: If value is None, it defaults to the heat transfer efficiency of the
Expand Down
35 changes: 19 additions & 16 deletions qsdsan/sanunits/_hydrothermal.py
Original file line number Diff line number Diff line change
Expand Up @@ -397,6 +397,10 @@ class HydrothermalLiquefaction(Reactor):
HTL effluent temperature, [K].
CAPEX_factor: float
Factor used to adjust CAPEX.
HTL_steel_cost_factor: float
Factor used to adjust the cost of stainless steel.
mositure_adjustment_exist_in_the_system: bool
If a moisture adjustment unit exists, set to true.
References
----------
Expand Down Expand Up @@ -572,13 +576,13 @@ def _run(self):
offgas.P = self.offgas_pre

for stream in self.outs : stream.T = self.heat_exchanger.T

@property
def biocrude_yield(self):
return self.protein_2_biocrude*self.afdw_protein_ratio +\
self.lipid_2_biocrude*self.afdw_lipid_ratio +\
self.carbo_2_biocrude*self.afdw_carbo_ratio

@property
def aqueous_yield(self):
return 0.481*self.afdw_protein_ratio + 0.154*self.afdw_lipid_ratio
Expand All @@ -590,34 +594,33 @@ def hydrochar_yield(self):
@property
def gas_yield(self):
return self.protein_2_gas*self.afdw_protein_ratio + self.carbo_2_gas*self.afdw_carbo_ratio

@property
def biocrude_C_ratio(self):
return (self.WWTP.AOSc*self.biocrude_C_slope + self.biocrude_C_intercept)/100 # [2]

@property
def biocrude_H_ratio(self):
return (self.WWTP.AOSc*self.biocrude_H_slope + self.biocrude_H_intercept)/100 # [2]

@property
def biocrude_N_ratio(self):
return self.biocrude_N_slope*self.WWTP.sludge_dw_protein # [2]

@property
def biocrude_C(self):
return min(self.outs[2].F_mass*self.biocrude_C_ratio, self.WWTP.sludge_C)



@property
def HTLaqueous_C(self):
return min(self.outs[1].F_vol*1000*self.HTLaqueous_C_slope*\
self.WWTP.sludge_dw_protein*100/1000000/self.TOC_TC,
self.WWTP.sludge_C - self.biocrude_C)

@property
def biocrude_H(self):
return self.outs[2].F_mass*self.biocrude_H_ratio

@property
def biocrude_N(self):
return min(self.outs[2].F_mass*self.biocrude_N_ratio, self.WWTP.sludge_N)
Expand All @@ -626,40 +629,40 @@ def biocrude_N(self):
def biocrude_HHV(self):
return 30.74 - 8.52*self.WWTP.AOSc +\
0.024*self.WWTP.sludge_dw_protein # [2]

@property
def energy_recovery(self):
return self.biocrude_HHV*self.outs[2].imass['Biocrude']/\
(self.WWTP.outs[0].F_mass -\
self.WWTP.outs[0].imass['H2O'])/self.WWTP.sludge_HHV # [2]

@property
def offgas_C(self):
carbon = sum(self.outs[3].imass[self.gas_composition]*
[cmp.i_C for cmp in self.components[self.gas_composition]])
return min(carbon, self.WWTP.sludge_C - self.biocrude_C - self.HTLaqueous_C)

@property
def hydrochar_C_ratio(self):
return min(self.hydrochar_C_slope*self.WWTP.sludge_dw_carbo, 0.65) # [2]

@property
def hydrochar_C(self):
return min(self.outs[0].F_mass*self.hydrochar_C_ratio, self.WWTP.sludge_C -\
self.biocrude_C - self.HTLaqueous_C - self.offgas_C)

@property
def hydrochar_P(self):
return min(self.WWTP.sludge_P*self.hydrochar_P_recovery_ratio, self.outs[0].F_mass)

@property
def HTLaqueous_N(self):
return self.WWTP.sludge_N - self.biocrude_N

@property
def HTLaqueous_P(self):
return self.WWTP.sludge_P*(1 - self.hydrochar_P_recovery_ratio)

def _design(self):

Design = self.design_results
Expand Down
4 changes: 3 additions & 1 deletion qsdsan/sanunits/_pumping.py
Original file line number Diff line number Diff line change
Expand Up @@ -972,7 +972,9 @@ class SludgePump(Pump):
_SS_per_pump = 725 * 0.5
_units = {'Pump pipe stainless steel': 'kg',
'Pump stainless steel': 'kg'}


include_construction = True

def _design(self):
super()._design()
pipe, pumps, hdpe = self.design_sludge()
Expand Down
1 change: 1 addition & 0 deletions requirements.txt
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@ SALib>=1.4.5
seaborn
sympy>=1.8
matplotlib<=3.6.0
numpy<2.0.0

# Specifically for docs
sphinx
Expand Down

0 comments on commit 15c596e

Please sign in to comment.