biosteamdevelopmentgroup / biosteam Goto Github PK
View Code? Open in Web Editor NEWThe Biorefinery Simulation and Techno-Economic Analysis Modules; Life Cycle Assessment; Chemical Process Simulation Under Uncertainty
License: Other
The Biorefinery Simulation and Techno-Economic Analysis Modules; Life Cycle Assessment; Chemical Process Simulation Under Uncertainty
License: Other
Description
First, thanks for adding the _failed_evaluation function!
I found that doing evaluation for my system, there's a certain Monte Carlo sample that won't trigger any error if I just run this sample, but the system won't be able to converge if this sample is run in evaluation, and I suspect it's because of the cache of other samples run before this one, as my system includes multiple distillation columns.
For the following codes for bst.evaluation._model:
biosteam/biosteam/evaluation/_model.py
Lines 162 to 166 in d34c533
I changed to:
try:
self._system.simulate()
return [i() for i in self._getters]
except:
try:
self._system.empty_recycles()
self._system.empty_process_streams()
for i in self._system.units:
if hasattr(i, '_McCabeThiele_args'):
i._McCabeThiele_args[:] = 0 # clear the cache for distillation columns
self._system.simulate()
return [i() for i in self._getters]
except:
return self._failed_evaluation()
And it solved the problem. Though because this clears the cache, results for samples after this one changed 1-2%. However I don't think this is a big deal.
Proposed Feature
So I'll propose for all units that use cache to speed up simulation, we add a clear_cache
function. Then for the system, we also add a clear_system_cache
function to call the clear_clear function of those units. In evaluation, if it fails, we first check if clearing cache and process streams/recycles can solve this.
Additional Notes
Since BioSTEAM now allows failed evaluation, another feature that'll be good is to print a summary at the end of evaluation to show how many simulations are good and how many fail - I didn't notice the failed evaluation at first.
Also, for the failed metrics, now they are recorded as nan
, so spearman results can't be calculated. However for my particular case, I ran 100 samples and only 1 failed, so I think calculating Spearman's rho for the 99 good samples still make sense. So I'm wondering if we can exclude the failed samples in Spearman calculation?
Thanks a lot!!!
Environment
Python: v 3.7.6
BioSTEAM: v 2.20.9
Hope you aren't mad at me bringing this up again haha, but let's consider two scenarios:
I ran 1,000 Monte Carlo, only 1 or 2 failed. In this case, I don't care too much about the failed scenarios, so now how biosteam handles this, which resets the system and goes on with the evaluation works perfect.
I ran 1,000 Monte Carlo, but all of them failed. In this case, there probably was something wrong with my Model
setup, so I would actually want to see the error message.
So to address both scenarios, I propose:
Include an "error_log" attribute to Model
or Model.table
to record the error messages.
Include a kwarg for the evaluate
function to allow users to choose whether they want the evaluation to be interrupted by errors.
Glad to discuss and thanks for considering!
In MEE design, the following line won't work if there is only one evaporator associated with the MEE.
As evap is defined previously in for evap in evaporators[1:]
Related to this, I have a questions regarding the new feature (#45). BioSTEAM now automatically adjusts the number of effects to achieve a given vapor fraction if the set number of effects won't work. But assume I make an MEE with 5 evaporators at V=0.5. In uncertainty analysis, BioSTEAM finds that 5 evaporators won't work for one simulation and reduce the number to 4, then later, assume that 5 evaporators can work for another simulation, will BioSTEAM reverses the number back to 5?
Thanks!
With MultiEffectEvaporator units, some of you may have noticed that at low input values for vapor fraction (V) we get an infeasible region error. Since this is not true for Flash units, I reasoned that this was not a Thermosteam issue and that the problem could be addressed within the MultiEffectEvaporator class. After discussing this with Yoel, we came to the conclusion that the infeasible region errors at low values of V are due to lower pressure effect(s) being unable to achieve that V at a temperature that is within 5-10 degrees C (hard and fast rule) of the effect immediately preceding it. This is a feature request to address that issue by solving by iteratively removing the effect with the lowest pressure if an infeasible region error occurs with all effects.
E.g., with a MultiEffectEvaporator unit having 5 effects with pressure decreasing from 1st to 5th effect, if an infeasible region error occurs with all 5 effects, a solution is attempted again with the last effect taken off. Repeated if an infeasible region occurs with 4 effects, and so forth.
I have almost finished writing the issue and then I have realised how to fix it. You might want to add a more specific error about it.
I have left the issue like it was written in the first place. However, I have added the fix in the end.
I have a weird issue related to the overwriting parameters _N_ins and _N_outs when I am inheriting from a Unit.
Debugging has shown that they both are equal 1 in the moment of the object initiation.
Also, if I use:
def __init__(self, ID, ins=('', ''), outs=('', '')):
self._N_outs = 2
self._N_ins = 2
then everything is OK, but if specify them when I declare the class it crashes.
(because _N_ins==1, _N_outs==1 for some reasons as I already said)
class SprayDryer(bst.Unit):
_N_ins = 2
_N_outs = 2
However, everything is ok, with other parameters like _graphics
also I have created other objects with 1 inlet 2 outs it was usually ok. Yesterday, I had the same, but then it has disappeared...
(importing chemicals is not shown but I can add it if it is relevant)
class SprayDryer(bst.Unit):
_N_ins = 2
_N_outs = 2
node = {'shape': 'invhouse',
'fillcolor': '#90949c',
'style': 'filled',
'gradientangle': '0',
'color': 'black',
'peripheries': '1',
'margin': 'default',
}
single_edge_in = ({'headport': 'c'},)
single_edge_out = ({'tailport': 'c'},)
_graphics = UnitGraphics(single_edge_in, single_edge_out, node)
def __init__(self, ID, ins=('', ''), outs=('', '')):
bst.Unit.__init__(self, ID=ID, ins=ins, outs=outs)
sd = SprayDryer('SD001')
sd.diagram()
---------------------------------------------------------------------------
AssertionError Traceback (most recent call last)
<ipython-input-2-52916b9384b7> in <module>
1 from garage import *
----> 2 sd = SprayDryer('SD001')
3 sd.diagram()
~/PycharmProjects/bioprocess_modelling/Bellossom/garage.py in __init__(self, ID, ins, outs, x)
285
286 def __init__(self, ID, ins=('', ''), outs=('', ''), x=11):
--> 287 bst.Unit.__init__(self, ID=ID, ins=ins, outs=outs)
~/opt/anaconda3/lib/python3.7/site-packages/biosteam/_unit.py in __init__(self, ID, ins, outs, thermo)
170 self._specification = None
171 self._load_thermo(thermo)
--> 172 self._init_ins(ins)
173 self._init_outs(outs)
174 self._init_utils()
~/opt/anaconda3/lib/python3.7/site-packages/biosteam/_unit.py in _init_ins(self, ins)
179 def _init_ins(self, ins):
180 # Ins[:class:`~thermosteam.Stream`] Input streams
--> 181 self._ins = Ins(self, self._N_ins, ins, self._thermo, self._ins_size_is_fixed)
182
183 def _init_outs(self, outs):
~/opt/anaconda3/lib/python3.7/site-packages/biosteam/utils/piping.py in __init__(self, sink, size, streams, thermo, fixed_size)
307 def __init__(self, sink, size, streams, thermo, fixed_size=True):
308 self._sink = sink
--> 309 super().__init__(size, streams, thermo, fixed_size)
310
311 @property
~/opt/anaconda3/lib/python3.7/site-packages/biosteam/utils/piping.py in __init__(self, size, streams, thermo, fixed_size)
174 else:
175 N = len(streams)
--> 176 n_missing(size, N) # Assert size is not too big
177 self._streams[:N] = [redock(i) if isa(i, Stream)
178 else dock(Stream(i, thermo=thermo)) for i in streams]
~/opt/anaconda3/lib/python3.7/site-packages/biosteam/utils/piping.py in n_missing(ub, N)
139
140 def n_missing(ub, N):
--> 141 assert ub >= N, f"size of streams exceeds {ub}"
142 return ub - N
143
AssertionError: size of streams exceeds 1
I have fixed just adding to the class the _run method. Usually, I add it immediately but this time I wanted to play with _graphics first. So after I added this,
def _run(self):
pass
There was no problem and the object was successfully created.
It might be useful to specify the error about this.
Python: anaconda, 3.7
OS: macOS Catalina version 10.15.2
BioSTEAM: v 2.20.5
Description
Currently, if we are doing Monte Carlo evaluation for 5000 scenarios and unfortunately the system runs into some error during the last simulation, BioSTEAM will reports an error and won't return results, I've run into this a couple of times... 😢
So I'm wondering if it is possible to:
I think it's doable using try:... except:...
, but I'm not sure whether using try:... except:...
is good. This change might require some tweaks for spearman
evaluation as well. However the change can be very helpful if the designed system is not very robust, or some combination of parameters are just bad.
Thanks in advance for considering!
In the following code:
biosteam/biosteam/process_tools/utils.py
Line 43 in cca6df5
Will it be better to change to:
return [i for i in heat_utilities if i.heat_exchanger and i.duty != 0]
The original one will cause problem in HXN if there's no duties associated with a HeatUtility
, because this line:
will raise an error since hu.heat_exchanger.ins[0]
is a MissingStream, it doesn't have T
Thanks!
If I just want to change one unit in an established biorefinery (e.g., change fermentation in the Humbird cornstover biorefinery), should I remake the whole biorefinery, or is there an easy way to swap out the original fermentation with the new one?
Is your feature request related to a problem? Please describe.
BioSTEAM is great on calculating TEA metrics like stream price/IRR with a given system design, I'm wondering, would it be possible to/do you see value in letting BioSTEAM automate the design so that a certain price/IRR target can be reached?
For example, let's say for the cornstover biorefinery, we assume a 95% glucose-to-ethanol conversion that gives us an MESP of ~$0.69/kg, so can BioSTEAM calculate how low this conversion can be to give an MESP of $1/kg or less?
Describe the solution you'd like
The fundamental question I'd like to address is: what would it take to reach a TEA target? I consider this question in three different levels based on what I know about BioSTEAM (easiest to hardest to implement), it's kind of similar to Monte Carlo:
Easiest: as I described in the example. We can BioSTEAM calculate what the MESP will be from 0-100% conversion, then select the cutoff conversion to reach the target.
Medium (this might not be a robust solution): we provide a list of parameters with their probable ranges, BioSTEAM runs sensitivity analysis to rank these parameters from most to least impactful, then BioSTEAM changes the most impactful parameter to see if the target can be reached. If not, BioSTEAM will include the second most impactful parameter, run Monte Carlo within the given ranges, then see if the target can be reached, so on and so forth.
Hardest: we provide a list of parameters with their probable ranges (or even better, BioSTEAM loads some default parameters like the biosteam.evaluation.State. load_default_parameters
function), and BioSTEAM calculates the probability at a given value with the distribution of a certain parameter (i.e., the cumulative distribution function). Then BioSTEAM will do Monte Carlo for all the parameters we provided and give each simulation scenario the probability score (maybe by multiplying all probabilities?) and rank these scenarios from most to least probable. This way, we can clearly see:
Look forward to your thoughts, thanks!!!
Describe the bug
if I try to run:
from biorefineries.lipidcane import system
or
from biorefineries.cornstover import system
The output in jupyter notebook is:
---------------------------------------------------------------------------
AttributeError Traceback (most recent call last)
<ipython-input-68-5aca82ca079b> in <module>
----> 1 from biorefineries.lipidcane import system
~/opt/anaconda3/lib/python3.7/site-packages/biorefineries/lipidcane/system.py in <module>
11 from biosteam import units
12 from biorefineries.lipidcane.tea import LipidcaneTEA
---> 13 from biorefineries.lipidcane.chemicals import (pretreatment_chemicals,
14 ethanol_chemicals,
15 biodiesel_chemicals)
~/opt/anaconda3/lib/python3.7/site-packages/biorefineries/lipidcane/chemicals.py in <module>
42 formula="C6H10O5", # Glucose monomer
43 MW=162.14,
---> 44 Hf=-975708.8)
45 Hemicellulose = create_new_chemical('Hemicellulose',
46 formula="C5H8O5", # Xylose monomer
~/opt/anaconda3/lib/python3.7/site-packages/biorefineries/lipidcane/chemicals.py in create_new_chemical(ID, phase, **constants)
34
35 def create_new_chemical(ID, phase='s', **constants):
---> 36 solid = tmo.Chemical.blank(ID, phase=phase, **constants)
37 lipidcane_chemicals.append(solid)
38 return solid
~/.local/lib/python3.7/site-packages/thermosteam/_chemical.py in blank(cls, ID, CAS, phase_ref, phase, **data)
1039 self.phase_ref = phase_ref or phase
1040 self._CAS = CAS or ID
-> 1041 for i,j in data.items(): setfield(self, i , j)
1042 return self
1043
AttributeError: 'Chemical' object has no attribute 'formula'
and in Pycharm Python console it is like this:
In[27]: from biorefineries.cornstover import system
> /Users/dim/.local/lib/python3.7/site-packages/thermosteam/base/thermo_model_handle.py(132)integrate_by_T()
-> for model in self.models:
(Pdb) >?
To Reproduce
run the
if I try to run:
from biorefineries.lipidcane import system
or
from biorefineries.cornstover import system
in jupyter notebook or in the PyCharm Python console
Expected behavior
The one which is described in the documentation, for example, here.
Environment
Description
I believe there's a small bug with the warning message for ConveyingBelt
, currently there's no attribute _lb_warning
defined.
from .decorators import cost
from .._unit import Unit
__all__ = ('ConveyingBelt',)
@cost('Flow rate', CE=567, cost=813, ub=2000, n=0.38, N='Number of conveyors')
class ConveyingBelt(Unit):
length = 40 #: ft
height = 20 #: ft
_N_outs = 1
_has_power_utility = True
_minimum_flow = 120
_units = {'Flow rate': 'ft^3/hr'}
def _design(self):
feed = self.ins[0]
self.design_results['Flow rate'] = F_vol = feed.F_vol*35.315 # ft3/hr
if F_vol < self._minimum_flow:
self._lb_warning('Flow rate', F_vol, self._minimum_flow)
F_mass = feed.F_mass*0.0006124 #lb/s
self.power_utility(0.00058*F_mass**0.82*self.length
+ self.height*0.00182*F_mass * 0.7457) # kW
Proposed fix
This can be easily fixed by importing lb_warning
from bst.utils
:
from .decorators import cost
from .._unit import Unit
from ..utils import lb_warning
__all__ = ('ConveyingBelt',)
@cost('Flow rate', CE=567, cost=813, ub=2000, n=0.38, N='Number of conveyors')
class ConveyingBelt(Unit):
length = 40 #: ft
height = 20 #: ft
_N_outs = 1
_has_power_utility = True
_minimum_flow = 120
_units = {'Flow rate': 'ft^3/hr'}
def _design(self):
feed = self.ins[0]
self.design_results['Flow rate'] = F_vol = feed.F_vol*35.315 # ft3/hr
if F_vol < self._minimum_flow:
lb_warning(source=self, key='Flow rate', value=F_vol,
units='kg/hr', stacklevel=3, lb=self._minimum_flow)
F_mass = feed.F_mass*0.0006124 #lb/s
self.power_utility(0.00058*F_mass**0.82*self.length
+ self.height*0.00182*F_mass * 0.7457) # kW
And it worked for a small test:
A side note: kwargs are aligned in different orders for lb_warning
/ub_warning
(source
is the last) and bounds_warning
(source
is the first), not sure if this is intentional/matters, thanks!!!
Environment
OS: macOS Catalina 10.15.4
Python: v3.7.6
biosteam: v2.18.0
thermosteam: v0.18.0
I'm not sure if we have run into this problem in any of the biorefineries. But suppose we have a biorefinery with a lifetime of 30 years, and we have a piece of equipment that will only last for 15 years. So we'll need to buy another piece of the equipment half way through the project. How can we account for this in TEA?
I don't think we can just multiply the cost by 2 since we need to consider discount, so we probably need to do something to the cashflow table.
Thanks!
Ran into this when I was debugging something else...I think in the following line, it should be not '{type(stream).__name__}'
instead of not '{type(item).__name__}'
Thanks!
biosteam/biosteam/utils/piping.py
Line 249 in e61ab4a
I have to in-streams to the mixer. One contains water and solid stuff, other contains "solid" bacteria.
After running the simulation, I am trying to show F_vol of the out-stream. It causes crash.
If I run the media with only liquid compounds (another stream "bacteria_stream" contains only "solid" bacteria), then I have no problems.
import thermosteam as tmo
import biosteam as bst
def create_fake_chemical(chem_id):
"""
made mostly for bacteria and biomass
:param chem_id:
:return:
"""
chemical = tmo.Chemical.blank(chem_id, MW=1., phase='s')
chemical.default()
return chemical
def introducing_chemicals(chemical_list):
"""
creating chemical objects related to compounds which are a part of bio process
:param chemical_list:
:return:
"""
solid_chemicals_with_problems = ('Na2HPO4', 'KH2PO4', "CaCl2")
chemical_objects = tmo.Chemicals([])
for chemical in chemical_list:
if chemical in solid_chemicals_with_problems:
chemical_objects.append(tmo.Chemical(chemical, phase='s', default=True))
continue
try:
chemical_objects.append(tmo.Chemical(chemical))
except LookupError:
chemical_objects.append(create_fake_chemical(chemical))
return chemical_objects
media = {
'CaCl2': 0.0111,
'Glucose': 20.0,
'MgSO4': 0.012,
'NH4Cl': 1.0,
'NaCl': 0.5,
'Water': 1000,
'thiamine': 6e-06,
# 'Na2HPO4': 7.0,
# "KH2PO4": 3.0
}
other_chemicals = ("Vanillin", "O2", "CO2", "Ecoli")
chemicals = introducing_chemicals([*other_chemicals, *[c for c, _ in media.items()]])
bst.settings.set_thermo(chemicals)
media_stream = bst.Stream('media', T=295, units='kg/hr', **media)
bacteria_stream = bst.Stream('Bacteria', T=295, units='kg/hr', Water=1000)
media_mix = bst.units.Mixer('Mixer')
[media_stream, bacteria_stream] - media_mix
s1 = media_mix.outs[0]
media_mix.simulate()
print(s1.F_vol)
Traceback (most recent call last):
File "/Users/dim/.local/lib/python3.7/site-packages/IPython/core/interactiveshell.py", line 3326, in run_code
exec(code_obj, self.user_global_ns, self.user_ns)
File "<ipython-input-2-ef0394a537f0>", line 1, in <module>
runfile('/Users/dim/PycharmProjects/bioprocess_modelling/Bellossom/upstream.py', wdir='/Users/dim/PycharmProjects/bioprocess_modelling/Bellossom')
File "/Applications/PyCharm CE.app/Contents/plugins/python-ce/helpers/pydev/_pydev_bundle/pydev_umd.py", line 197, in runfile
pydev_imports.execfile(filename, global_vars, local_vars) # execute the script
File "/Applications/PyCharm CE.app/Contents/plugins/python-ce/helpers/pydev/_pydev_imps/_pydev_execfile.py", line 18, in execfile
exec(compile(contents+"\n", file, 'exec'), glob, loc)
File "/Users/dim/PycharmProjects/bioprocess_modelling/Bellossom/upstream.py", line 57, in <module>
print(s1.F_vol)
File "/Users/dim/opt/anaconda3/lib/python3.7/site-packages/thermosteam/_stream.py", line 580, in F_vol
return 1000. * self.mixture.V(self.phase, self.mol, *self._thermal_condition)
File "/Users/dim/opt/anaconda3/lib/python3.7/site-packages/thermosteam/base/phase_handle.py", line 114, in __call__
return getattr(self, phase)(z, T, P)
File "/Users/dim/opt/anaconda3/lib/python3.7/site-packages/thermosteam/mixture/ideal_mixture_model.py", line 56, in __call__
return sum([j * i(T, P) for i, j in zip(self.models, mol) if j])
File "/Users/dim/opt/anaconda3/lib/python3.7/site-packages/thermosteam/mixture/ideal_mixture_model.py", line 56, in <listcomp>
return sum([j * i(T, P) for i, j in zip(self.models, mol) if j])
File "/Users/dim/opt/anaconda3/lib/python3.7/site-packages/thermosteam/base/thermo_model_handle.py", line 370, in __call__
Tmin=self.Tmin, Tmax=self.Tmax,
File "/Users/dim/opt/anaconda3/lib/python3.7/site-packages/thermosteam/base/thermo_model_handle.py", line 275, in Tmin
return min([i.Tmin for i in self._models])
ValueError: min() arg is an empty sequence
Python: anaconda, 3.7
OS: macOS Catalina version 10.15.2
BioSTEAM: v 2.19.15
biorefineries v 2.14.15
I have the same output if I try to run media_stream.F_vol in the same code even before simulation.
The CombinedTEA class is undocumented. Additionally, it would be nice to include the corn stover biorefinery's CombinedTEA as example implementation.
Describe the bug
I didn't update biosteam for a while, but now I have downloaded the last version. For one of my units I used the split function which was also used in other virtual equipment.
To Reproduce
from biosteam.units.design_tools.separations import split
Expected behavior
just usage of the split function
Actual behavior
Traceback (most recent call last):
File "/Library/Frameworks/Python.framework/Versions/3.8/lib/python3.8/site-packages/IPython/core/interactiveshell.py", line 3418, in run_code
exec(code_obj, self.user_global_ns, self.user_ns)
File "<ipython-input-2-ad53f2ea018f>", line 1, in <module>
runfile('/Users/dmitrybachin/PycharmProjects/bioprocess_modelling/tea.py', wdir='/Users/dmitrybachin/PycharmProjects/bioprocess_modelling')
File "/Applications/PyCharm CE.app/Contents/plugins/python-ce/helpers/pydev/_pydev_bundle/pydev_umd.py", line 197, in runfile
pydev_imports.execfile(filename, global_vars, local_vars) # execute the script
File "/Applications/PyCharm CE.app/Contents/plugins/python-ce/helpers/pydev/_pydev_imps/_pydev_execfile.py", line 18, in execfile
exec(compile(contents+"\n", file, 'exec'), glob, loc)
File "/Users/dmitrybachin/PycharmProjects/bioprocess_modelling/tea.py", line 9, in <module>
from general.garage import UniversalFermenter
File "/Applications/PyCharm CE.app/Contents/plugins/python-ce/helpers/pydev/_pydev_bundle/pydev_import_hook.py", line 21, in do_import
module = self._system_import(name, *args, **kwargs)
File "/Users/dmitrybachin/PycharmProjects/bioprocess_modelling/general/garage.py", line 8, in <module>
from biosteam.units.design_tools.separations import split
File "/Applications/PyCharm CE.app/Contents/plugins/python-ce/helpers/pydev/_pydev_bundle/pydev_import_hook.py", line 21, in do_import
module = self._system_import(name, *args, **kwargs)
ModuleNotFoundError: No module named 'biosteam.units.design_tools.separations'
Version
System-wide process results for biorefineries such as electricity, heating and cooling is not trivial to generate in biosteam. This issue proposes implementing a UnitGroup class for generating such process results with data table and plotting capabilities. The outline for the class would look as follows:
class UnitGroup:
__slots__ = ('name', 'units', 'heat_utilities')
def __init__(self, name, units):
self.name = name
self.units = units
self.heat_utilities = get_heat_utilities(units)
def get_cooling_duty(self): ...
def get_heating_duty(self): ...
def get_installed_cost(self): ...
def get_electricity_consumption(self): ...
def get_electricity_production(self): ...
def to_dict(self):
return {'Installed equipment cost [million USD]': self.get_installed_cost(),
'Cooling duty [GJ/hr]': self.get_cooling_duty(),
'Heating duty [GJ/hr]': self.get_heating_duty(),
'Electricity consumption [MW]': self.get_electricity_consumption()}
'Electricity production [MW]': self.get_electricity_production()}
def to_series(self):
return pd.Series(self.to_dict(), name=self.name)
@staticmethod
def create_df(unit_subgroups): ...
@staticmethod
def plot_unit_subgroups(units_subgroups, fraction=True): ...
def __repr__(self):
return f"{type(self).__name__}({self.name}, {self.units})"
This would facilitate generating testing functions for biorefineries, as well as evaluating metrics for scenario grids and Monte Carlo.
Describe the bug
As described in the title, the save_report
function will raise an error for systems without heat utilities, I think that's because how the heat utility table is created by the heat_utilities_table
function in biosteam/report/table. Please make it possible for those systems to have reports. Thank you!
To Reproduce
Any simple systems will do, for example:
import biosteam as bst
bst.settings.set_thermo(bst.Chemicals(('Water', 'Ethanol')))
s1 = bst.Stream(Water=100, Ethanol=50)
s2 = bst.Stream(Water=100, Ethanol=10)
M1 = bst.Mixer(ins=(s1, s2))
S1 = bst.Splitter(ins=M1-0, split=0.1)
sys = bst.System('sys', path=(M1, S1))
sys.save_report('sys.xlsx')
Expected behavior
Excel file as system report
Actual behavior
Note: I think you had an extra space between "**" and "Actual behavior" in your .github/ISSUE_TEMPLTE/bug_report.md, it was not rendered correctly so I changed it myself.
Version
Description
I'm trying to use the Mass Balance
unit, but ran into problem when trying to modify the example provided for two chemicals, Iet's assume I just want the mass balance for ethanol.
To Reproduce
Modified codes below:
from biosteam import System
from biosteam.units import Mixer, Splitter, StorageTank, Pump, Flash, MassBalance
from thermosteam import Chemicals, Stream, settings
chemicals = Chemicals(['Water', 'Ethanol'])
settings.set_thermo(chemicals)
# water = Stream('water',
# Water=40,
# units='lb/s',
# T=350, P=101325)
ethanol = Stream('ethanol',
Ethanol=190,
T=300, P=101325)
target = Stream('target', flow=50)
# T1 = StorageTank('T1')
T2 = StorageTank('T2')
# P1 = Pump('P1', P=101325)
P2 = Pump('P2', P=101325)
M1 = Mixer('M1', outs='s1')
S1 = Splitter('S1', outs=('s2', 's3'), split=0.5)
F1 = Flash('F1', outs=('s4', 's5'), V=0.5, P =101325)
# Connect units
# water-T1-P1
ethanol-T2-P2
[P2-0, S1-0]-M1-F1-1-S1
MB1 = MassBalance('MB1', streams=[0],
chemical_IDs=['Ethanol'],
outs=target,
ins=(ethanol, S1-0))
mixSys = System('mixSys',
recycle=S1-0,
network=(MB1, T2, P2, M1, F1, S1))
# Make diagram to view system
mixSys.diagram()
mixSys.simulate()
MB1.show()
Environment
OS: macOS 10.15.3
biosteam: 2.2.1
thermosteam: 0.2.13
Thanks!!!
I am trying to replicate the PHA production bioprocess on biosteam.
The process is below.
What concerns me is the Homogenisation(H301) and Centrifugation (C401). According to the process, they are doing 3 passes on each of these two pieces of the equipment.
I have tried to find out if it is possible to implement it on biosteam. The only way which I see is to make the new objects with zero purchase costs. Is there more elegant way?
The line below will trigger an error - is warning imported from somewhere? I was using biosteam v 2.20.5, but this isn't urgent, you can patch this up in the next update.
Line 613 in ca825e0
BTW, thanks for considering adding deprecation warning! It'll help a lot!
I think here missing an "f" at the front
biosteam/biosteam/utils/piping.py
Line 378 in 6e05d23
Describe the bug
I am trying to reproduce this part of the documentation
However neither for cornstover nor for lipidcane chemicals are not specified in the documentation. I have tried to take chemicals from the objects inside the packages, but it did not help.
The output is below:
---------------------------------------------------------------------------
AssertionError Traceback (most recent call last)
<ipython-input-27-eb6ddd6d0ca2> in <module>
1 cornstover_sys = bst.find.system.cornstover_sys
----> 2 cornstover_sys.diagram()
~/opt/anaconda3/lib/python3.7/site-packages/biosteam/_system.py in diagram(self, kind, file, format, **graph_attrs)
454 return self._thorough_diagram(file, format, **graph_attrs)
455 elif kind == 'surface':
--> 456 return self._surface_diagram(file, format, **graph_attrs)
457 elif kind == 'minimal':
458 return self._minimal_diagram(file, format, **graph_attrs)
~/opt/anaconda3/lib/python3.7/site-packages/biosteam/_system.py in _surface_diagram(self, file, format, **graph_attrs)
421 else: outs += products
422
--> 423 subsystem_unit = _systemUnit(i.ID, ins, outs)
424 units.add(subsystem_unit)
425
~/opt/anaconda3/lib/python3.7/site-packages/biosteam/_unit.py in __init__(self, ID, ins, outs, thermo)
168 self._init_utils()
169 self._init_results()
--> 170 self._assert_compatible_property_package()
171 self._register(ID)
172
~/opt/anaconda3/lib/python3.7/site-packages/biosteam/_unit.py in _assert_compatible_property_package(self)
201 streams = self.ins + self.outs
202 assert all([s.chemicals.IDs == chemical_IDs for s in streams if s]), (
--> 203 "unit operation chemicals are incompatible with inlet and outlet streams; "
204 "try using the `thermo` keyword argument to initialize unit operation "
205 "with a compatible thermodynamic property package")
AssertionError: unit operation chemicals are incompatible with inlet and outlet streams; try using the `thermo` keyword argument to initialize unit operation with a compatible thermodynamic property package
To Reproduce
import biosteam as bst
from biorefineries.cornstover import system
cornstover_sys = bst.find.system.cornstover_sys
cornstover_sys.diagram()
Expected behavior
The step 4 in the 8th chapter of the documentation
Environment
Description
When using the cost
decorators, the added scaled cost will overwrite the original _cost
functions in the super class, this is normally not a problem (and should be done this way for most cases.
However I ran into this problem: assume I want to design a Flash tank with three items: a tank, an agitator, and a pump. I want to use BioSTEAM's design and cost algorithms for the tank, but since BioSTEAM's Flash
doesn't have agitators and pumps, I want to use cost decorators to add them (scaled based on inlet mass flow rate).
I kind of figured this out using the current cost decorator as below, but not sure if there's a better way to do this, thanks!
import biosteam as bst
from math import ceil
from biosteam.units import Flash
from biosteam.units.decorators import CostItem
# This is the same as the _cost function in biosteam.units.decorators,
# but I cannot import it directly
def add_scaled_costs(self):
D = self.design_results
C = self.purchase_costs
kW = 0
for i, x in self.cost_items.items():
S = D[x._basis]
if x.ub:
D[x.N or '#' + i] = N = ceil(S/x.ub)
q = S/x.S
F = q/N
C[i] = N*bst.CE/x.CE*x.cost*F**x.n
kW += x.kW*q
elif x.N:
N = getattr(self, x.N)
F = S/x.S
C[i] = N*bst.CE/x.CE*x.cost*F**x.n
kW += N*x.kW*F
else:
F = S/x.S
C[i] = bst.CE/x.CE*x.cost*F**x.n
kW += x.kW*F
if kW: self.power_utility(kW)
def add_cost_item(unit, basis, ID=None, *, CE, cost, n, S=1, ub=0, kW=0, BM=1,
units=None, fsize=None, N=None):
if hasattr(unit, 'cost_items'):
cost_items = unit.cost_items
else: cost_items = unit.cost_items = {}
cost_items[ID] = CostItem(basis, units, S, ub, CE, cost, n, kW, BM, N)
class NewFlash(Flash):
_units = Flash._units
_units['Flow rate'] = 'kg/hr'
def _design(self):
Flash._design(self)
self.design_results['Flow rate'] = self.ins[0].F_mass
def _cost(self):
# To avoid adding scaled power_utility repeatedly during simulation
self.power_utility(0)
Flash._cost(self)
designed_kW = self.power_utility.rate
# Adding CostItem will overwrite designed power_utility
add_cost_item(self, ID='Agitator', basis='Flow rate', units='kg/hr',
kW=170, cost=90000, S=252891, CE=521.9, n=0.5, BM=1.5)
add_cost_item(self, ID='Pump', basis='Flow rate', units='kg/hr',
kW=55.9275, cost=30000, S=204390, CE=521.9, n=0.8, BM=2.3)
add_scaled_costs(self)
scaled_kW = self.power_utility.rate
self.power_utility(designed_kW+scaled_kW)
I was trying to create a very simple unit class using biosteam but ran into a lot of questions:
Let's assume I just want to make a tank (name=FakeTank), where there is only 1 ins and 1 outs and cost=0, here are my codes:
Then I try to create a FakeTank unit U101:
When I try to simulate U101, I got an error:
When I check the streams, the ins is what I want, but the outs is empty:
How should I modify the code to make this work?
Thanks!
Describe the bug
I think there is a typo in the example for Splitter
, and the Centrifuge_LLE
example is not working.
To reproduce
Splitter
I think the split should be (0.99, 0.1) instead of (0.99, 0.01) to give the results shown in screenshot 1
Centrifuge_LLE
An error would occur as in screenshot 2
Screenshots
Environment
I really like the find
function in biosteam, but only want to ask something related to its usage (as instructed in the tutorial on managing flowsheets):
Let's assume I create a very simple stream in biosteam and try to find
it:
import biosteam as bst
species = bst.Species('Water', 'Ethanol')
bst.Stream.species = species
s0 = bst.Stream('s0', Water=1, Ethanol=1)
When I try to use find
, I can do:
lost_stream = bst.find('s0')
But I cannot use:
lost_stream = bst.find.stream('s0')
Instead, I should use:
lost_stream = bst.find.stream.s0
Can you explain on the difference between find
and stream
and why this is the case?
Thanks!!!
Recycle systems are currently created by specifying the tear stream and a network of unit operations to run sequentially. This effort takes a ton of time in the biorefinery development process. Automatic creation of a recycle system given a set of unit operations would not only save time but also prevent human error. Any help in spearheading this enhancement is appreciated!
Describe the bug
The attempt to reproduce documentation section TEA tea let to this output
---------------------------------------------------------------------------
ModuleNotFoundError Traceback (most recent call last)
~/.local/lib/python3.7/site-packages/lazypkg/__init__.py in __getattr__(self, name)
52 try:
---> 53 attr = import_module('.'+name, self.__package__)
54 except ModuleNotFoundError as Error:
~/opt/anaconda3/lib/python3.7/importlib/__init__.py in import_module(name, package)
126 level += 1
--> 127 return _bootstrap._gcd_import(name[level:], package, level)
128
~/opt/anaconda3/lib/python3.7/importlib/_bootstrap.py in _gcd_import(name, package, level)
~/opt/anaconda3/lib/python3.7/importlib/_bootstrap.py in _find_and_load(name, import_)
~/opt/anaconda3/lib/python3.7/importlib/_bootstrap.py in _find_and_load_unlocked(name, import_)
ModuleNotFoundError: No module named 'biorefineries.lipidcane.lipidcane_sys'
During handling of the above exception, another exception occurred:
TypeError Traceback (most recent call last)
<ipython-input-4-a199e55e7f85> in <module>
----> 1 lipidcane_tea = LipidcaneTEA(system=lc.lipidcane_sys,
2 IRR=0.15,
3 duration=(2018, 2038),
4 depreciation='MACRS7',
5 income_tax=0.35,
~/.local/lib/python3.7/site-packages/lazypkg/__init__.py in __getattr__(self, name)
60 unsearchable = self.__unsearchable
61 for i in self.__all__:
---> 62 module = getattr(self, i)
63 if (isinstance(module, ModuleType)
64 and i not in unsearchable
~/.local/lib/python3.7/site-packages/lazypkg/__init__.py in __getattr__(self, name)
51 attempts = self.__import_attempts
52 try:
---> 53 attr = import_module('.'+name, self.__package__)
54 except ModuleNotFoundError as Error:
55 if name in attempts:
~/opt/anaconda3/lib/python3.7/importlib/__init__.py in import_module(name, package)
125 break
126 level += 1
--> 127 return _bootstrap._gcd_import(name[level:], package, level)
128
129
~/opt/anaconda3/lib/python3.7/importlib/_bootstrap.py in _gcd_import(name, package, level)
~/opt/anaconda3/lib/python3.7/importlib/_bootstrap.py in _find_and_load(name, import_)
~/opt/anaconda3/lib/python3.7/importlib/_bootstrap.py in _find_and_load_unlocked(name, import_)
~/opt/anaconda3/lib/python3.7/importlib/_bootstrap.py in _load_unlocked(spec)
~/opt/anaconda3/lib/python3.7/importlib/_bootstrap_external.py in exec_module(self, module)
~/opt/anaconda3/lib/python3.7/importlib/_bootstrap.py in _call_with_frames_removed(f, *args, **kwds)
~/opt/anaconda3/lib/python3.7/site-packages/biorefineries/lipidcane/process_settings.py in <module>
42 'Gasoline': 0.756} # 2 USD/gal
43
---> 44 set_lipidcane_process_settings()
~/opt/anaconda3/lib/python3.7/site-packages/biorefineries/lipidcane/process_settings.py in set_lipidcane_process_settings()
15 bst.PowerUtility.price = 0.065
16 HeatUtility = bst.HeatUtility
---> 17 steam_utility = HeatUtility.heating_agents['Low pressure steam']
18 steam_utility.efficiency = 0.85
19 steam_utility.T = 529.2
TypeError: list indices must be integers or slices, not str
To Reproduce
First two steps from the TEA documentation (9.1 and the first step of 9.2)
Environment
Describe the bug
In biosteam v2.0.1, the numbers of ins and outs for BoilerTurbogenerator
are both 3 (in v1.0.8, there are only 2 ins and 2 outs). This seems to be creating empty ins and outs streams.
However, I'm not sure if this unit is currently under development
Environment
I'm not exactly sure whether it's the problem of Python of numpy, but sometimes numbers such as 0.8 will be expressed as 0.8000000001 (I heard because it's recorded as one number divided by another one?). So this sometimes cause problems in reactions because of the material infeasible check. I'm now adding a "1e-6" to some reaction conversions to work around this, but wondering if there are better ways? Thanks!
from biosteam import Stream
from biosteam.units import Centrifuge_LLE
from biorefineries.lipidcane import species
Stream.species = species.biodiesel_species
feed = Stream(Lipid=1, Methanol=51, Glycerol= 9, Biodiesel=27, T=333.15)
C1 = Centrifuge_LLE(ID='C1',ins = feed, outs = ('light', 'heavy'), species_IDs=('Lipid', 'Methanol', 'Biodiesel'), split=(1, 0.5, 1), solvents=('Glycerol',),solvent_split=(0.05))
C1.simulate()
C1.diagram()
C1.show(T='degC', P='atm', fraction=True)
Error -
Traceback (most recent call last):
File "", line 1, in
File "C:\Users\Abhishek D\source\repos\Biorefinery Simulation\env_2_new\lib\site-packages\biosteam\units_centrifuge_LLE.py", line 64, in init
Unit.init(ID, ins, outs)
File "C:\Users\Abhishek D\source\repos\Biorefinery Simulation\env_2_new\lib\site-packages\biosteam_unit.py", line 189, in init
self._init_ins(ins, species)
AttributeError: 'str' object has no attribute '_init_ins'
Describe the bug
I noticed that under certain conditions, the Junction
unit may fail to copy the upstream flow information into downstream flow, but I have not figure out what might be the case.
To reproduce
This can be seen in the cornstover system in biorefineries package. I'll use M601 as an example. Note that in the original code, no ID was assigned so the default ID (U1) was used, there are several other instances like this, I'll compile them and submit another issue under Bioindustrial-Park.
import biosteam as bst
from biorefineries.cornstover import system
M601 = bst.find.unit.U1
M601
# Note that d56 and d57 are empty streams, re-simulate won't fix it
(Screenshot #1)
M601.diagram(radius=1)
# Note that d56 and d57 are rejected_water_and_blowdown and evaporation_and_blowdown,
# and they are not empty
(Screenshot #2)
bst.find.stream.rejected_water_and_blowdown
(Screenshot #3)
bst.find.stream.evaporation_and_blowdown
(Screenshot #4)
Screenshots
#1: M601_flow
#2: M601_diagram
#3: rejected_water_and_blowdown
#4: evaporation_and_blowdown
Environment
Additional context
Unlike Stream and Unit, which have name that we can easily using find
function to locate, Junction does not have IDs and so far I can only use import
to get the Junction unit I want. Is it possible to find them using find
function?
Why want to print these streams? Was that legacies from debugging or serving special purpose? Thanks!
biosteam/biosteam/digraph/digraph.py
Line 186 in 4e1da33
biosteam/biosteam/digraph/digraph.py
Line 205 in 4e1da33
Description
Assume I want to evaluate how minimum product selling price (MPSP) changes with internal rate of return (IRR) under uncertainty, and I want to depict this using a figure where the x-axis is IRR, y-axis is MPSP, and the IRR vs. MPSP correlation is a curve with error band to express uncertainty (similar to Figure 4 in the paper Cortes-Peña et al., ACS Sustainable Chem. Eng. 2020, 8 (8), 3302–3310).
I can use the evaluate_across_coordinate
function for Model
object, but I'm wondering if this is the best practice? I ask because unlike Figure 4 in the paper where the change of feedstock lipid content affects the system, change of TEA parameters like IRR won't affect the system. So for each of the Monte Carlo scenario, there's no need to re-simulate the system to get the MPSP, re-calculating the cashflow should be enough.
My impression from reading the document is that BioSTEAM creates Block
objects that only simulate the system downstream of the change, so I'm wondering if for my question, this means that only the cashflow will be re-calculated when change IRR (which is what we want)?
Thanks!!!
Describe the bug
The script was not updated to work with the new thermosteam functions, leading to a TypeError.
I believe the origin code in biosteam.units.decorators._design of:
moisture = sum([i.get_flow(units, IDs='7732-18-5') for i in ins])
should be replaced with
moisture = sum([i.get_flow(units, key='7732-18-5') for i in ins])
I tried this and it fixed the problem
To Reproduce
I found this when trying to import the cornstover biorefinery:
from biorefineries.cornstover.system import cornstover
Screenshots
Screenshot for error:
Environment
Describe the bug
Sometimes, HeatUtility.flow
and HeatUtility.inlet_utility_stream
/ HeatUtility.outlet_utility_stream
flow information aren't matching, but this doesn't appear to be affecting results, only causing confusion in display.
To Reproduce
This is most easily seen in the cornstover biorefinery. See the screenshot, the flow of low_pressure_steam
should be negative, BT.heat_utilities[1].flow
gives the correct flow, but BT.heat_utilities[1]
gives the opposite.
I think this is because the inlet_utility_stream
and outlet_utility_stream
flows are not correct, which stems from the reverse
function. In that function, inlet_utility_stream
and outlet_utility_stream
are swapped, probably their flow should multiply by -1 instead?
However, I'm not sure whether there are other cache problems with the display
Environment
Thanks!!!
Currently, version testing in BioSTEAM is limited to doctests for all essential unit operations and design methods, but some less-widely used unit operations do not have tests. Several important classes in BioSTEAM do not yet have doctests, including the TEA, System, and Model objects. In addition, system-wide tests of biorefineries are limited to verifying the minimum product selling price and IRR. Other important biorefinery results, including electricity consumption, cooling and heating duty, and excess electricity production are not rigorously tested. This issue introduces two milestones to address these problem:
Any help in developing the following essential unit operations would be greatly appreciated:
Please visit the "Inheriting from Unit" section in the docs for how to create a Unit operation. Make sure to read the "Developer's guide" before making any pull request. Briefly, concise and thorough documentation with full references, and passing biorefinery and unit operation tests are required for every contribution.
Currently split
in bst.Splitter
is just a property without setter:
@property
def split(self):
"""[Array] Componentwise split of feed to 0th outlet stream."""
return self._isplit._data
but can we add a setter function to it? Like:
@property
def split(self):
"""[Array] Componentwise split of feed to 0th outlet stream."""
return self._isplit._data
@split.setter
def split(self, split):
self._isplit = self.thermo.chemicals.isplit(split)
Or we can add a set_split
function to take in the order
arg as in the __init__
, thanks!
The new option to "cluster" units that are in the same recycle systems in a process flow diagram is really cool! I think it would be even more useful if we could pass an argument for which unit should be first (on the left-most part) in each cluster. That way, e.g., in SYS3 of the sugarcane to 3-HP biorefinery flowsheet below, we could have Cofermentation be the “first” unit in the SYS3 cluster to make the process clearer at first glance.
Description
It appears that we can access biosteam native unit operations (e.g., Flash) by using either bst.Flash
or bst.units.Flash
, are there any differences and what is the preferred way?
Additionally, I can access more units in the dropdown menu when I hit tab in Spyder after bst.units.
than after bst.
, but not showing in the dropdown menu in bst.
is not preventing me from calling these units, i.e., bst.Centrifuge_LLE
works as well as bst.units.Centrifuge_LLE
even if Centrifuge_LLE
is only shown in the dropdown menu in bst.units.
I'm not sure whether the dropdown menu thing is a Sypder bug...
Screenshots
Note that the dropdown menu for bst.
only contains Flash
but not Centrifuge_LLE
, and both of them appear in the dropdown menu for bst.units
Looks like the commit history has been reset (and it has been done so in the past), is there a reason for this? Doing so will cause some problem when I try to git pull upstream
. Thanks!
Describe the bug
I found this bug when designing HXs, I wasn't sure if it was due to my codes or biosteam, but then I found the same bug existed in the cornstover biorefinery. The heat_utilities
attribute works for some units but not for others. I'm not sure whether it's from biosteam or biorefineries.
To reproduce
from biorefineries.cornstover.system import *
# This works
R301.heat_utilities
# But this won't work
BT.heat_utilities
Environment
After making a list of chemical objects, I am trying to compile them.
chemical_list = ('Na2HPO4', 'KH2PO4')
chemical_objects = tmo.Chemicals([])
for chemical in chemical_list:
try:
chemical_objects.append(tmo.Chemical(chemical))
except LookupError:
chemical_objects.append(create_fake_chemical(chemical))
chemical_objects.compile()
However, Na2HPO4 and KH2PO4 show the next error:
Traceback (most recent call last):
File "/Users/dim/.local/lib/python3.7/site-packages/IPython/core/interactiveshell.py", line 3326, in run_code
exec(code_obj, self.user_global_ns, self.user_ns)
File "<ipython-input-2-4df983869c2e>", line 1, in <module>
runfile('/Users/dim/PycharmProjects/bioprocess_modelling/Bellossom/initial.py', wdir='/Users/dim/PycharmProjects/bioprocess_modelling/Bellossom')
File "/Applications/PyCharm CE.app/Contents/plugins/python-ce/helpers/pydev/_pydev_bundle/pydev_umd.py", line 197, in runfile
pydev_imports.execfile(filename, global_vars, local_vars) # execute the script
File "/Applications/PyCharm CE.app/Contents/plugins/python-ce/helpers/pydev/_pydev_imps/_pydev_execfile.py", line 18, in execfile
exec(compile(contents+"\n", file, 'exec'), glob, loc)
File "/Users/dim/PycharmProjects/bioprocess_modelling/Bellossom/initial.py", line 77, in <module>
chemicals.compile()
File "/Users/dim/opt/anaconda3/lib/python3.7/site-packages/thermosteam/_chemicals.py", line 159, in compile
CompiledChemicals._compile(self)
File "/Users/dim/opt/anaconda3/lib/python3.7/site-packages/thermosteam/_chemicals.py", line 304, in _compile
f"{chemical} is missing key thermodynamic properties ({missing}); "
RuntimeError: Na2HPO4 is missing key thermodynamic properties (Psat, Tb and Hvap); use the `<Chemical>.get_missing_properties()` to check all missing properties
The same I get for KH2PO4.
chemical.default() doesn't help
Python: anaconda, 3.7
OS: macOS Catalina version 10.15.2
BioSTEAM: v 2.19.15
biorefineries v 2.14.15
I noticed some really cool codes the cornstover biorefinery used to batch-create units using the factories module of biosteam and an Excel spreadsheet:
Can you explain how this works? I couldn't really understand the raw codes in the factories module and additionally, I was baffled by the fact that/I wanted to know:
Sorry I have a ton of questions... I tried to look at the tutorial but still couldn't figure these out. Let me know if the answers were somewhere in the tutorial , thanks!!!
Originally posted by @yalinli2 in #6 (comment)
The value is having an error of about 30%
Description
Suppose I want to simulate a HXutility as follows:
import thermosteam as tmo
from biosteam.units import StorageTank, HXutility
chemicals = tmo.Chemicals(['Water', 'Ethanol'])
tmo.settings.set_thermo(chemicals)
s1 = Stream('s1', Water=100, Ethanol=50)
H1 = HXutility('H1', ins=s1, V=0, rigorous=True)
H1.show() # before simulation
H1.simulate()
H1.show() # after simulation
My question is, how can I select the liquid phase of H1 outs as the ins for a downstream unit? Note that before simulation, H1.outs[0] is a Stream
, not a MultiStream
, so doing:
s1 = tmo.Stream('s1', Water=100, Ethanol=50)
H1 = HXutility('H1', ins=s1, V=0, rigorous=True)
H1_liquid = tmo.Stream('H1_liquid', phase='l')
H1_liquid.mol = H1.outs[0].imol['l']
T1 = StorageTank('T1', ins=H1_liquid)
from biosteam import System
system = System('system', path=(H1, T1))
Also, it is strange to me that the outs of H1 after simulation is at 354.39K - I thought it should remain at 298.15K as the ins?
Thanks!!!
Environment
OS: macOS Catalina 10.15.4
Python: v3.7.6
biosteam: v2.17.7
thermosteam: v.0.17.15
Hi
Biosteam appears to be a very good platform for my research work but I am more comfortable in in a GUI environment (eg Thermoflex) to build models based on Python scripted unit models. I see that this is work in progress and wonder if you could advise an expected timeframe?
Kind regards
Allan
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.