qsd-group / qsdsan Goto Github PK
View Code? Open in Web Editor NEWQuantitative Sustainable Design (QSD) of sanitation and resource recovery systems.
Home Page: https://qsdsan.com
License: Other
Quantitative Sustainable Design (QSD) of sanitation and resource recovery systems.
Home Page: https://qsdsan.com
License: Other
Need a live website to guide users/contributors on how to use the package, how to contribute to this project, etc., probably on readthedocs
Need to add WasteStream
-specific methods for molar flow and related thermodynamic properties. Generally, Component
can be measured as something other than the chemical itself (e.g., COD, N). But this difference is not yet taken into account when getting thermodynamic properties of a WasteStream
as a mixture of components.
QSDsan/qsdsan/sanunits/_grinder.py
Line 94 in e9fdbf1
price_ratio
needed here?Thanks to everyone (@haclohman in particular for leading and going through the codes for each system), we are close to merging the systems in the gates
branchinto
main`, just want to document some changes I'd like to make before pulling those in:
QSDsan/qsdsan/sanunits/_ion_exchange_NH3.py
Line 142 in e9fdbf1
QSDsan/qsdsan/sanunits/_ion_exchange_NH3.py
Line 115 in e9fdbf1
QSDsan/qsdsan/sanunits/_ion_exchange_NH3.py
Line 121 in e9fdbf1
The price_ratio
attribute should be used for
Anything related to the parts/materials of the system, but no labor
Not sure if this has been used consistently, need to double-check
Currently almost all of the subclasses ofDecay
have the following module in _run
:
def _run(self):
waste, salt, HCl_acid = self.ins
treated, CH4, N2O = self.outs
treated.copy_like(waste)
CH4.phase = N2O.phase = 'g'
# COD decay
COD_deg = waste.COD*waste.F_vol/1e3*self.COD_removal # kg/hr
treated._COD = waste.COD * (1-self.COD_removal)
CH4_prcd = COD_deg * self.MCF_decay * self.max_CH4_emission
CH4.imass['CH4'] = CH4_prcd
# N decay
N_loss = self.first_order_decay(k=self.decay_k_N, t=self.tau/365, max_decay=self.N_max_decay)
N_loss_tot = N_loss*waste.TN/1e3*waste.F_vol
NH3_rmd, NonNH3_rmd = \
self.allocate_N_removal(N_loss_tot, waste.imass['NH3'])
treated.imass['NH3'] = waste.imass['NH3'] - NH3_rmd
treated.imass['NonNH3'] = waste.imass['NonNH3'] - NonNH3_rmd
N2O.imass['N2O'] = N_loss_tot * self.N2O_EF_decay * 44/28
It'll be good to put this part in Decay
so that any future updates can be propagated throughout, would also be good if it can be written to include a sludge
effluent with consideration of the sludge moisture content
See here:
https://github.com/QSD-Group/QSDsan/runs/5955204241?check_suite_focus=true
Looks like it's related to the S_O
and S_N2
without VolumeLiquid._extrapolation_min
(thermo/utils/t_dependent_property.py, line 3659) in thermo==0.2.19
Major features that will be included in this release:
Process
class @joyxyz1994 bfa51a6Equipment
class to account for the different equipment in a SanUnit
d80e791In StruvitePrecipitation
(won't b surprising if there are similar situations in other units), there are many attributes that are constant, it'll be better to just hard code those since they won't change, e.g., we know the molecular weight of P, there's no need for an attribute like MW_P
(but it'll be good to add a note in the code about what that 30.97 means)
However, for attributes such as P_rec_1
, it still might be better to add them as attributes, as they could change
On this end, why the attribute is called P_rec_1
? What does that 1
stand for? Similarly for K_rec_1
. Without a reason, it's confusing
Additionally, if want the mol, use imol
instead of imass
This would enable the use of impact item objs with the same ID but different properties
Currently _init_ins
and _init_outs
only take Stream
/SanStream
/WasteStream
, need to allow MultiStream
Many thanks to @GaYeongKim who prepared a tutorial doc on ADM1 model. I'm opening an issue here to remind myself to merge it in
Just a list of the things I see QSDsan will benefit from and will be working on:
8b96dae
(EXPOsan commit), the numbers are not checked against anything, but the system runsisdynamic
is set to False)
- Post treatment units including UV, chlorination, and granular activated carbon
- Timeline: Q1 2022
- Initial tutorial is added in 919637a, pending review by Eva and Philipp
Inherit from biosteam's HXN
Currently qsdsan
is tested for both python 3.7 and 3.8. However, with biosteam
moving to python 3.8 (BioSTEAMDevelopmentGroup/biosteam#56), qsdsan
may be only compatible with python 3.8 and higher.
I'm trying to sort this out, but if you are using python 3.7 and lower (like me), the best solution might be to make a new environment and install python 3.8 (conda instruction).
I will follow up if I find out that qsdsan
is incompatible with python 3.7 and lower, and I'll post instructions on how to upgrade.
Based on the code below, needed Mg is based on the amount of P in the influent, not the amount of P precipitated (otherwise should've used P_recovered
). I think this assumption is OK, but just want to confirm
Hi!
Just a heads up, I think the latest qsdsan merge had some name changes that stop BioSTEAM's QDSsan test from running.
To Reproduce
Input:
def test_dyn_sys():
from qsdsan import processes as pc, sanunits as su, set_thermo, System
import numpy as np
from numpy.testing import assert_allclose
cmps = pc.load_asm1_cmps()
test_dyn_sys()
Output:
AttributeError: module 'qsdsan.processes' has no attribute 'load_asm1_cmps'
Environment
Windows 11, latest github versions of all the following:
- QSDsan
- EXPOsan
- BioSTEAM
- Thermosteam
Not sure if @philAteawag is actively working on this, but will keep this open until we have the tutorial finished - maybe I'll finish it with some fake numbers.
It does not recognize a purchase cost correctly setting the BM factor to one.
Based on the description, the OilHeatExchanger
should something to burn to generate the heat, the stream is currently not included in the unit.
Some units (e.g., PitLatrine
) required specific Component
and/or ImpactItem
to run, such requirements should be added to the class-level docs
E.g., consider adding:
The following components should be included in system thermo object for simulation: H2O, Polyacrylamide. The following impact items should be pre-constructed for life cycle assessment: Steel.
I recently installed exposan with the intent to simulate the BSM1 WWTF process. I used pip install exposan --user
to avoid needing to uninstall other libraries.
Upon attempting to run from exposan import bsm1
I received the following error:
ModuleNotFoundError Traceback (most recent call last)
Cell In[1], line 1
----> 1 from exposan import bsm1
File ~\AppData\Roaming\Python\Python310\site-packages\exposan\__init__.py:25
22 es_path = os.path.dirname(__file__)
23 del os, pkg_resources
---> 25 from . import utils
File ~\AppData\Roaming\Python\Python310\site-packages\exposan\utils.py:23
21 from chaospy import distributions as shape
22 from thermosteam.functional import rho_to_V
---> 23 from qsdsan import ImpactItem, sanunits as su
24 from qsdsan.utils import time_printer, AttrSetter
25 from . import es_path
File ~\AppData\Roaming\Python\Python310\site-packages\qsdsan\__init__.py:72
68 from ._tea import *
69 from ._lca import *
---> 72 from . import (
73 _component,
74 _components,
75 _construction,
76 _equipment,
77 _impact_indicator,
78 _impact_item,
79 _lca,
80 _process,
81 _sanstream,
82 _sanunit,
83 _tea,
84 _transportation,
85 _waste_stream,
86 equipments,
87 processes,
88 sanunits,
89 stats,
90 )
92 utils._secondary_importing()
93 for _slot in utils.doc_examples.__all__:
File ~\AppData\Roaming\Python\Python310\site-packages\qsdsan\sanunits\__init__.py:44
42 from ._encapsulation_bioreactor import *
43 from ._excretion import *
---> 44 from ._heat_exchanging import *
45 from ._junction import *
46 from ._non_reactive import *
File ~\AppData\Roaming\Python\Python310\site-packages\qsdsan\sanunits\_heat_exchanging.py:27
25 from math import ceil, pi
26 from biosteam.units import HXprocess as HXP, HXutility as HXU
---> 27 from biosteam.units.facilities import HeatExchangerNetwork as HXN
28 from biosteam.units.design_tools.specification_factors import material_densities_lb_per_ft3
29 from biosteam.exceptions import bounds_warning, DesignWarning
ModuleNotFoundError: No module named 'biosteam.units.facilities'
Looking at the native _heat_exchanging.py file in QSDsan, it looks like the import lines do not match with the version installed through original pip command.
Native QSDsan File:
from warnings import warn
from math import ceil, pi
from biosteam import HeatExchangerNetwork as HXN, HXprocess as HXP, HXutility as HXU
from biosteam.units.design_tools.specification_factors import material_densities_lb_per_ft3
from biosteam.exceptions import bounds_warning, DesignWarning
from biosteam.units.design_tools import flash_vessel_design
from .. import SanUnit, Construction
from ..utils import auom
Pip download File:
import biosteam as bst
from warnings import warn
from math import ceil, pi
from biosteam.units import HXprocess as HXP, HXutility as HXU
from biosteam.units.facilities import HeatExchangerNetwork as HXN
from biosteam.units.design_tools.specification_factors import material_densities_lb_per_ft3
from biosteam.exceptions import bounds_warning, DesignWarning
from biosteam.units.design_tools import flash_vessel_design
from .. import SanUnit, Construction
from ..utils import auom
Replacing the downloaded block with the native block fixes the error, and I was able to reproduce the dynamic simulation example, though I have not yet tested additional simulations.
Versions of the following packages:
- QSDsan: 1.2.5
- EXPOsan: 1.2.5
- BioSTEAM: 2.37.3
- Thermosteam: 0.35.0
Operating on windows 11
Hi QSDSan team! I am wondering if there is any way to export the information from a components object or compiled components into a pandas dataframe or directly into a text file. I ask because I've made a custom set of components using the qs.Components
command with the built-in search_ID
functionality, and I would like to avoid copying and pasting this large code block between multiple files.
I've seen in the documentation that we can load in components from a file, then compile from there, but I wasn't sure how this text file was made in the first place or if it was possible to do that process in reverse.
Thanks!
Hello,
I was going through this QSDSAN tutorial and am trying to run the following:
`
# Make three random influents, I'm deliberately using different ways to make these streams
# as a recap previous tutorials
# Method 1: by directly providing the flow rates of select components
ins1 = qs.WasteStream(H2O=100)
# Method 2: using copy
and adjust flow rates later
ins2 = ins1.copy()
ins2.imol['X_GAO_Gly'] = ins2.imol['X_GAO_PHA'] = 0.01
# Method 3: using default models
ins3 = qs.WasteStream.codstates_inf_model('', flow_tot=50)
# Use a shorthand to make our lives easier
su = qs.sanunits
# This is the actual line used to initialize the instance,
# and we can pass the influents through the ins
argument
M1 = su.Mixer(ins=(ins3))
`
I am getting the following error:
--------------------------------------------------------------------------- AttributeError Traceback (most recent call last) Input In [22], in <cell line: 19>() 15 su = qs.sanunits 17 # This is the actual line used to initialize the instance, 18 # and we can pass the influents through the
ins` argument
---> 19 M1 = su.Mixer(ins=(ins3))
File ~/.local/share/virtualenvs/energy_inflows-sTQfUhBs/lib/python3.9/site-packages/qsdsan/sanunits/_abstract.py:48, in Mixer.init(self, ID, ins, outs, thermo, init_with, F_BM_default, isdynamic, rigorous)
45 def init(self, ID='', ins=None, outs=(), thermo=None,
46 init_with='WasteStream', F_BM_default=None, isdynamic=False,
47 rigorous=False):
---> 48 SanUnit.init(self, ID, ins, outs, thermo, init_with,
49 F_BM_default=F_BM_default, isdynamic=isdynamic)
50 self.rigorous = rigorous
File ~/.local/share/virtualenvs/energy_inflows-sTQfUhBs/lib/python3.9/site-packages/qsdsan/_sanunit.py:161, in SanUnit.init(self, ID, ins, outs, thermo, init_with, construction, transportation, equipments, add_OPEX, uptime_ratio, lifetime, F_BM_default, isdynamic, **kwargs)
159 self._init_with = init_with
160 self._init_ins(ins, init_with)
--> 161 self._init_outs(outs, init_with)
162 self._init_utils()
163 self._init_results()
File ~/.local/share/virtualenvs/energy_inflows-sTQfUhBs/lib/python3.9/site-packages/qsdsan/_sanunit.py:256, in SanUnit._init_outs(self, outs, init_with)
254 def _init_outs(self, outs, init_with):
255 super()._init_outs(outs)
--> 256 converted, missing = self._convert_stream(outs, self.outs, init_with, 'outs')
257 _outs = self._outs = Outlets(self, self._N_outs, converted, self._thermo,
258 self._outs_size_is_fixed, self._stacklevel)
259 _replace_missing_streams(_outs, missing)
File ~/.local/share/virtualenvs/energy_inflows-sTQfUhBs/lib/python3.9/site-packages/qsdsan/_sanunit.py:217, in SanUnit._convert_stream(self, strm_inputs, streams, init_with, ins_or_outs)
215 converted.append(SanStream.from_stream(SanStream, s))
216 else:
--> 217 converted.append(WasteStream.from_stream(WasteStream, s))
219 diff = len(converted) + len(missing) - len(streams)
220 if diff != 0:
File ~/.local/share/virtualenvs/energy_inflows-sTQfUhBs/lib/python3.9/site-packages/qsdsan/_waste_stream.py:359, in WasteStream.from_stream(cls, stream, ID, **kwargs)
356 return new
358 # An actual stream
--> 359 new = SanStream.from_stream(cls, stream, ID)
360 for attr, val in kwargs.items():
361 setattr(new, attr, val)
File ~/.local/share/virtualenvs/energy_inflows-sTQfUhBs/lib/python3.9/site-packages/qsdsan/_sanstream.py:344, in SanStream.from_stream(cls, stream, ID, **kwargs)
341 new_ID = ''
342 new.init(ID=new_ID)
--> 344 new._islinked = stream._islinked
346 source = new._source = stream._source
347 if source:
AttributeError: 'Stream' object has no attribute '_islinked'
`
I am using version 1.1.4. Maybe this is a bug in the newest version? Should I use an older version while it is being fixed?
Thank you!
In HousingBiogenicRefinery, labor is included as a capital cost because it is for the construction of the unit, need to make sure there is no other implications
Should it be adjusted for price_ratio
?
Major features that will be included in this release:
Process
class @joyxyz1994QSDsan
, BioSTEAM
orQSDsan
@yalinli2
bwaise
system, Uncertainpy
, which was built on Chaospy
and SALib
, might consider using this package in the future, but for now, still plan to use SALib
Uncertainpy
seems to be geared toward neuroscience, Chaospy
and SALib
are sufficientget_normalized_impacts
method in LCA
with something like get_allocated_impacts
, and allow users to allocate the impacts based on mass, value, energy, or a ratio/function provided by the user @yalinli2
Because of the historical origin of the branch (see the thread, and salient examples of master NOT being used in the "master copy" way), I think it'll be good to rename the default branch following the broad movement, including Git.
I'm opening this issue here for any comments, and will execute it in the following month or so following the renaming guidance if folks see so problem, thanks!
Need to to addressed or removed if it's outdated, listed by units in following posts
General ones:
There are multiple IX units used in the different systems (e.g., IonExchangeNH3, IonExchangeReclaimer, IonExchangeNEWgenerator), are they all different?
Updates to be included in v0.3.0 release
EXPOsan
68f21e2Stream
and WasteStream
4acc8d7
SanStream
class (tmo.Stream
plus with impact_item
), now SanUnit
can be initialized by any of these three classes, and they can be mixed.BW2QSD
, though will definitely need more testing to make sure it works, and add support for databases other than ecoinvent.There are several similar units in different systems (e.g., IndustrialControlPanel
, SystemControls
), I'd like to consolidate them into fewer modules with some renaming for consistency and better organization, specifically
The following units will go into qsdsan/sanunits/_ion_exchange.py (see #55):
IonExchangeNH3
IonExchangeReclaimer
IonExchangeNEWgenerator
The following units will go into qsdsan/sanunits/_controlling.py:
IndustrialControlPanel
(renamed to ControlBoxOP
)SystemControls
(this one is diff from others, maybe leave this out)SCGZyclonicControlBox
RecyclingControls
ControlSystem
The following units will go into qsdsan/sanunits/_hxs.py:
OilHeatExchanger
HydronicHeatExchanger
DryerFromHHX
(renamed to HHXdryer
)This is due to BioSTEAM's announcement for moving to Python 3.10 in August: BioSTEAMDevelopmentGroup/biosteam#159
We'll still test for 3.9 for compatibility, and I'll try to maintain the compatibility if it's possible, I'll note here if we have to move to 3.10 as well.
Open an issue here so I don't forget! Refer to the internal email for details, but the idea is to have a page that shows what is currently in QSDsan. In the past we have a page for the developed processes, unit operations, and systems, but I haven't updated it for quite some time.
Additionally, since we are developing the benchmarking configurations, it'll be great if we can have one page dedicated to it (or add to existing pages).
Many of the the __init__
methods are error-prone, e.g.,
def __init__(self, ID='', ins=None, outs=(), **kwargs):
SanUnit.__init__(self, ID, ins, outs, F_BM_default=1)
This won't allow the unit to init with the correct thermo
object and stream types, please update those to be
def __init__(self, ID='', ins=None, outs=(), thermo=None, init_with='WasteStream',
**kwargs):
SanUnit.__init__(self, ID, ins, outs, thermo=thermo, init_with=init_with,
F_BM_default=1)
Please DO modify this based on your units - e.g., some units' might other other attributes (e.g., lifetime
, CAPEX_over_OPEX
that need to be included)
@smitimittal @akogler , as we discussed, these classes should have algorithms for 0th/1st/2nd order reactions, I'm hoping to get this done in 1-2 weeks
Hey @joyxyz1994, I got some errors while making the tutorial, I think IDs of some of the Component
have been updated, but not yet reflected in the models (e.g., SU_Inf
below should probably be S_U_Inf
).
QSDsan/qsdsan/_waste_stream.py
Line 1253 in dc5b7b7
Can you take a look and update as needed? Thanks!
Heads up, I just deprecated the _is_linked
attribute of Stream objects. I think all what needs to be done for qsdsan is to remove lines where it is copied (e.g., from_stream).
Thanks!
Many of the new units does not have documentation/references, some that stands out:
ScrewPress
, not sure what the "Additional Questions" is, and what that "dewatering_energy_demand_old" is doingThere probably will be needed at some stage to convert Stream
to SanStream
/WasteStream
and/or vice versa
Hey @joyxyz1994 , I made the updates as we discussed, can you have a look at the commit b47e36c and make updates as you see fit? I added doc and updated tests accordingly.
Note that commit didn't pass the test because I used functions (aliases) that haven't been released in the existing thermosteam, I reverted it in the next commit 8b61f59 and the all tests are passed now
Thank you!
It'll be good to add examples in docs, which would also serve as a test on the functions, listing functions to add docs on (non-exhaustive, just whatever I saw):
Process
:
Hey @joyxyz1994 I think I managed to implemented the concentration indexer through 87aec8f
import qsdsan as qs
qs.set_thermo(qs.Components.load_default())
ws1 = qs.WasteStream.codbased_inf_model(flow_tot=100)
ws1.conc
ws1.iconc['S_F']
Can you take a look at the changes to _waste_stream.py
and see whether it makes sense? I think with it we might not need the get_mass_concentration
method (or let it just return self.conc)
Thanks!
Code first system following the Scenario B in Trimmer et al., 2020, developing the Component
and WasteStream
classes along the way.
Items I can think of to release 0.0.1 version in PyPI:
Component
class (subclass of thermosteam Chemical
) (structure & basic functions โ
) @joyxyz1994 @yalinli2WasteStream
class (subclass of thermosteam Stream
) (structure & basic functions โ
) @joyxyz1994 @yalinli2We need to standardize the codes before I'm comfortable with including them into the main branch and on PyPI, I'm doing this myself for the BR_OmniProcessor
because it is the closest (i.e., least behind) among all, but I'd really appreciate help, specifically
Make sure no error and no warning (i.e., related to F_BM
) when running the system
Clean up legacy comments, breakpoints, "#!!!", "TODO", etc.
If you copy something from another module, make sure you update the variable names, comments, etc. to the existing module
If there are codes that you don't understand, try to find who wrote that, if you can't figure it out, open an issue here on GitHub
Check the data sheet and make sure they look good, remove legacy data like "XXX_old", see #58
Add documentation, at the minimum you should provide description of the unit (including what components and impact items are needed for the unit, see #51) as well as the reference.
Rerun the corresponding systems and make sure the results match
Hi @joyxyz1994 , I was pulling your changes on processes and found some minor issues, can you review the following and see if they look good to you? If it's good then I'll push to the main branch.
set_flow_by_concentration
in _waste_stream.py, lines 855 and 865ID
instead of CAS
now, because there might be cases where people want to have two components fixed at different phases of the same chemical (just had a call with Shion and she wanted to have a gas phase CH4 and soluble CH4. If using CAS then the soluble CH4 won't be added in the Components
.Thanks!
Currently (Feb 24, 2022) only a bit over 50% of the package is covered by test, let's aim to get it up to ~80%.
See the codecov report for priorities. Adding doc examples would probably be a good solution way to deal with it as it also helps users.
I'll include our tutorial examples in the test after dyn-enabled BioSTEAM is out, hopefully that will also bump up coverage.
Open this issue to remind myself about a question from this week's office hour (3/6/23). The question is about why the truck trip increases when increasing PitLatrine.emptying_ratio
A declarative, efficient, and flexible JavaScript library for building user interfaces.
๐ Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.
TypeScript is a superset of JavaScript that compiles to clean JavaScript output.
An Open Source Machine Learning Framework for Everyone
The Web framework for perfectionists with deadlines.
A PHP framework for web artisans
Bring data to life with SVG, Canvas and HTML. ๐๐๐
JavaScript (JS) is a lightweight interpreted programming language with first-class functions.
Some thing interesting about web. New door for the world.
A server is a program made to process requests and deliver data to clients.
Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.
Some thing interesting about visualization, use data art
Some thing interesting about game, make everyone happy.
We are working to build community through open source technology. NB: members must have two-factor auth.
Open source projects and samples from Microsoft.
Google โค๏ธ Open Source for everyone.
Alibaba Open Source for everyone
Data-Driven Documents codes.
China tencent open source team.