BioSTEAMDevelopmentGroup / Bioindustrial-Park

BioSTEAM's Premier Repository for Biorefinery Models and Results
MIT License
38 stars 18 forks source link

Refactor system factories #54

Closed yoelcortes closed 1 year ago

yoelcortes commented 1 year ago

@yalinli2, @sarangbhagwat,

This pull request refactors system factory code from the sugarcane and oilcane modules to a new cane module as follows:

image

General code for ethanol and biodiesel production was refactored to new modules as well:

image

image

The cornstover module is also refactored to a new cellulosic module as follows:

image

The sugarcane, oilcane, and cornstover modules all work exactly as before (I believe, but please double check). All biorefinery tests passing. Very minor changes were made to the tests regarding cooling and heating duty due to a bug in HXN when the option to replace heat utilities of HXutility objects is on.

If you would like to try this branch, you'll need to use the refactor branch of BioSTEAM and the enhancement branch of thermosteam. I still plan on adding documentation and tests for each system factory, but that will come later in January.

Looking forward to your review, Thanks!

yalinli2 commented 1 year ago

thanks @yoelcortes ! I will take a look this week and get back to you by Wed!

yoelcortes commented 1 year ago

@yalinli2, excellent! Please feel to take more time if needed, no rush.

yalinli2 commented 1 year ago

Hey @yoelcortes , I pulled the master branch in so that I can run my analyses, then one bug here for the oilcane models:

>>> from biorefineries import oilcane as oc
>>> oc.load('O1') # I believe running O2 will trigger the same bug as well
>>> oc.model.metrics_at_baseline()

image

With regard to results, all of them are similar except the cellulosic sugarcane configuration (when I implemented the new wastewater treatment configuration) - I'll look into it, thanks!

yoelcortes commented 1 year ago

@yalinli2, thanks for looking into this so early! I'll check it out.

Regarding the results of the cellulosic biorefineries, I think it comes from a change with the boiler efficiency, which was 0.89 when the publication was release. Unfortunately, this value may only be accurate for burning dry bagasse and not for lignin (Humbird uses 0.85). So I added an "if" statement to only use 0.89 if the biorefinery is not cellulosic.

if number not in cellulosic_configurations:
    BT.boiler_efficiency = 0.89

If you feel it is better, we can set BT.boiler_efficiency = 0.89 for consistency with the publication.

yalinli2 commented 1 year ago

thanks @yoelcortes for the tip! It's probably not the boiler efficiency since it's quite different, might coming from a mis-connection somewhere.

did you try to fix the bug for oilcane models with the recent commits? I just pulled biosteam@refactor (didn't see change in thermosteam@enhancement) and this repo at cane, but the same bug seems to be still there? Thanks!

yoelcortes commented 1 year ago

@yalinli2, OK, I fixed the bug with MFPP_derivative.

Also, I had a look at the results using the master branches vs. cane/enhancement branches and it looks good overall. Maybe it does have to do with connections with the WWT.

Click me for master branch results ```python >>> from biorefineries import oilcane as oc >>> oc.load('O1') # I believe running O2 will trigger the same bug as well >>> oc.model.metrics_at_baseline() Biorefinery MFPP [USD/MT] 40.8 Feedstock consumption [MT/yr] 1.6e+06 Biodiesel production [L/MT] 18.5 Ethanol production [L/MT] 44.9 Electricity production [kWhr/MT] 431 Natural gas consumption [m3/MT] 0 TCI [10^6*USD] 304 Heat exchanger network error [%] 1.22e-06 Economic allocation GWP [kg*CO2*eq / USD] 0.617 Ethanol GWP [kg*CO2*eq / L] 0.353 Biodiesel GWP [kg*CO2*eq / L] 0.353 Crude glycerol GWP [kg*CO2*eq / kg] 0.0987 Electricity GWP [kg*CO2*eq / MWhr] 39.5 Displacement allocation Ethanol GWP [kg*CO2*eq / L] -3.86 Energy allocation Biofuel GWP [kg*CO2*eq / GGE] 1.47 Ethanol GWP [kg*CO2*eq / L] 0.259 Biodiesel GWP [kg*CO2*eq / L] 0.408 Crude-glycerol GWP [kg*CO2*eq / kg] 0.156 Biorefinery MFPP derivative [USD/MT] 0.5 Biodiesel production derivative [L/MT] 1.85 Ethanol production derivative [L/MT] -4.38 Electricity production derivative [kWhr/MT] 22.2 Natural gas consumption derivative [cf/MT] 0 TCI derivative [10^6*USD] 3.44 Economic allocation GWP derivative [kg*CO2*eq / USD] 0.00442 Ethanol Ethanol GWP derivative [kg*CO2*eq / L] 0.00253 Biodiesel Biodiesel GWP derivative [kg*CO2*eq / L] 0.00253 Crude glycerol Crude glycerol GWP derivative [kg*CO2*eq / kg] 0.000707 Electricity Electricity GWP derivative [kg*CO2*eq / MWhr] 0.283 dtype: float64 @default_settings def test_corn(): from biorefineries import corn as module try: module.load() except: pass feedstock = module.corn product = module.ethanol tea = module.corn_tea units = UnitGroup('Biorefinery', tea.units) assert np.allclose(tea.IRR, 0.05484137947443769, rtol=5e-2) assert np.allclose(feedstock.price, 0.13227735731092652, rtol=5e-2) assert np.allclose(product.price, 0.48547915353569393, rtol=5e-2) assert np.allclose(tea.sales, 74723599.41753717, rtol=5e-2) assert np.allclose(tea.material_cost, 55525177.04024876, rtol=5e-2) assert np.allclose(tea.installed_equipment_cost, 62101158.6567123, rtol=5e-2) assert np.allclose(tea.utility_cost, 7480503.509637095, rtol=5e-2) assert np.allclose(units.get_heating_duty(), 95.08307155629652, rtol=5e-2) assert np.allclose(units.get_cooling_duty(), 114.69704367515685, rtol=5e-2) assert np.allclose(units.get_electricity_consumption(), 1.9369502187665464, rtol=5e-2) assert np.allclose(units.get_electricity_production(), 0.0, rtol=5e-2) @default_settings def test_lipidcane(): from biorefineries import lipidcane as module try: module.load() except: pass feedstock = module.lipidcane product = module.ethanol tea = module.tea units = UnitGroup('Biorefinery', tea.units) assert np.allclose(tea.IRR, 0.2113160935470352, rtol=5e-2) assert np.allclose(feedstock.price, 0.03455, rtol=5e-2) assert np.allclose(product.price, 0.789, rtol=5e-2) assert np.allclose(tea.sales, 103632376.79166704, rtol=5e-2) assert np.allclose(tea.material_cost, 58858510.67200561, rtol=5e-2) assert np.allclose(tea.installed_equipment_cost, 206548409.19150504, rtol=5e-2) assert np.allclose(tea.utility_cost, -28942675.97925947, rtol=5e-2) assert np.allclose(units.get_heating_duty(), 206.98209150873882, rtol=5e-2) assert np.allclose(units.get_cooling_duty(), 217.9662298884939, rtol=5e-2) assert np.allclose(units.get_electricity_consumption(), 7.253708655344464, rtol=5e-2) assert np.allclose(units.get_electricity_production(), 104.44473764590221, rtol=5e-2) @default_settings def test_cornstover(): from biorefineries import cornstover as module try: module.load() except: pass feedstock = module.cornstover product = module.ethanol tea = module.tea units = UnitGroup('Biorefinery', tea.units) assert np.allclose(tea.IRR, 0.1, rtol=5e-2) assert np.allclose(feedstock.price, 0.05158816935126135, rtol=5e-2) assert np.allclose(product.price, 0.7382534422848163, rtol=5e-2) assert np.allclose(tea.sales, 136365493.22877756, rtol=5e-2) assert np.allclose(tea.material_cost, 82338339.40833226, rtol=5e-2) assert np.allclose(tea.installed_equipment_cost, 202809309.16411608, rtol=5e-2) assert np.allclose(tea.utility_cost, -5343615.419122995, rtol=5e-2) assert np.allclose(units.get_heating_duty(), 363.2978269464661, rtol=5e-2) assert np.allclose(units.get_cooling_duty(), 310.1842939866101, rtol=5e-2) assert np.allclose(units.get_electricity_consumption(), 18.964203172291885, rtol=5e-2) assert np.allclose(units.get_electricity_production(), 33.26974052126595, rtol=5e-2) @default_settings def test_sugarcane(): from biorefineries import sugarcane as module try: module.load() except: pass feedstock = module.sugarcane product = module.ethanol tea = module.tea units = UnitGroup('Biorefinery', tea.units) assert np.allclose(tea.IRR, 0.1429580778650529, rtol=5e-2) assert np.allclose(feedstock.price, 0.03455, rtol=5e-2) assert np.allclose(product.price, 0.789, rtol=5e-2) assert np.allclose(tea.sales, 88302442.78606541, rtol=5e-2) assert np.allclose(tea.material_cost, 57277034.59309775, rtol=5e-2) assert np.allclose(tea.installed_equipment_cost, 167497255.2459296, rtol=5e-2) assert np.allclose(tea.utility_cost, -12214721.859830972, rtol=5e-2) assert np.allclose(units.get_heating_duty(), 247.47182596212357, rtol=5e-2) assert np.allclose(units.get_cooling_duty(), 222.97316413184618, rtol=5e-2) assert np.allclose(units.get_electricity_consumption(), 7.4850404017475896, rtol=5e-2) assert np.allclose(units.get_electricity_production(), 51.049620456611784, rtol=5e-2) @default_settings def test_oilcane_S1(): from biorefineries import oilcane as module try: module.load('S1') except: pass feedstock = module.feedstock product = module.ethanol tea = module.tea units = UnitGroup('Biorefinery', tea.units) assert np.allclose(tea.IRR, 0.1, rtol=5e-2) assert np.allclose(feedstock.price, 0.038727864055154645, rtol=5e-2) assert np.allclose(product.price, 0.7256416231373818, rtol=5e-2) assert np.allclose(tea.sales, 81211491.73736511, rtol=5e-2) assert np.allclose(tea.material_cost, 63969076.23320489, rtol=5e-2) assert np.allclose(tea.installed_equipment_cost, 120393463.2993852, rtol=5e-2) assert np.allclose(tea.utility_cost, -16619199.45609998, rtol=5e-2) assert np.allclose(units.get_heating_duty(), 246.43319824149503, rtol=5e-2) assert np.allclose(units.get_cooling_duty(), 245.01879601587152, rtol=5e-2) assert np.allclose(units.get_electricity_consumption(), 7.969452183294074, rtol=5e-2) assert np.allclose(units.get_electricity_production(), 66.46087263831663, rtol=5e-2) @default_settings def test_oilcane_S2(): from biorefineries import oilcane as module try: module.load('S2') except: pass feedstock = module.feedstock product = module.ethanol tea = module.tea units = UnitGroup('Biorefinery', tea.units) assert np.allclose(tea.IRR, 0.1, rtol=5e-2) assert np.allclose(feedstock.price, 0.03132168467589462, rtol=5e-2) assert np.allclose(product.price, 0.789, rtol=5e-2) assert np.allclose(tea.sales, 121082189.94588801, rtol=5e-2) assert np.allclose(tea.material_cost, 59813085.95090494, rtol=5e-2) assert np.allclose(tea.installed_equipment_cost, 220113258.27978796, rtol=5e-2) assert np.allclose(tea.utility_cost, 1403472.9847080822, rtol=5e-2) assert np.allclose(units.get_heating_duty(), 335.7798519684594, rtol=5e-2) assert np.allclose(units.get_cooling_duty(), 309.3471136143859, rtol=5e-2) assert np.allclose(units.get_electricity_consumption(), 21.605729734873215, rtol=5e-2) assert np.allclose(units.get_electricity_production(), 21.605729734873208, rtol=5e-2) @default_settings def test_oilcane_O1(): from biorefineries import oilcane as module try: module.load('O1') except: pass feedstock = module.feedstock product = module.ethanol tea = module.tea units = UnitGroup('Biorefinery', tea.units) assert np.allclose(tea.IRR, 0.1, rtol=5e-2) assert np.allclose(feedstock.price, 0.04239793498410762, rtol=5e-2) assert np.allclose(product.price, 0.7256416231373818, rtol=5e-2) assert np.allclose(tea.sales, 71993360.47703359, rtol=5e-2) assert np.allclose(tea.material_cost, 71398750.85016418, rtol=5e-2) assert np.allclose(tea.installed_equipment_cost, 163349892.86799604, rtol=5e-2) assert np.allclose(tea.utility_cost, -42835361.085534856, rtol=5e-2) assert np.allclose(units.get_heating_duty(), 252.14050678836935, rtol=5e-2) assert np.allclose(units.get_cooling_duty(), 223.61256956220166, rtol=5e-2) assert np.allclose(units.get_electricity_consumption(), 8.962363480558455, rtol=5e-2) assert np.allclose(units.get_electricity_production(), 152.65978522998645, rtol=5e-2) @default_settings def test_oilcane_O2(): from biorefineries import oilcane as module try: module.load('O2') except: pass feedstock = module.feedstock product = module.ethanol tea = module.tea units = UnitGroup('Biorefinery', tea.units) assert np.allclose(tea.IRR, 0.1, rtol=5e-2) assert np.allclose(feedstock.price, 0.035846682002367666, rtol=5e-2) assert np.allclose(product.price, 0.789, rtol=5e-2) assert np.allclose(tea.sales, 136218442.0994864, rtol=5e-2) assert np.allclose(tea.material_cost, 71371009.87114277, rtol=5e-2) assert np.allclose(tea.installed_equipment_cost, 232885996.79195195, rtol=5e-2) assert np.allclose(tea.utility_cost, 1390874.3734458557, rtol=5e-2) assert np.allclose(units.get_heating_duty(), 510.0980788334304, rtol=5e-2) assert np.allclose(units.get_cooling_duty(), 379.0794764483686, rtol=5e-2) assert np.allclose(units.get_electricity_consumption(), 19.604703487377225, rtol=5e-2) assert np.allclose(units.get_electricity_production(), 19.605525074641985, rtol=5e-2) @default_settings def test_oilcane_O3(): from biorefineries import oilcane as module try: module.load('O3') except: pass feedstock = module.feedstock product = module.ethanol tea = module.tea units = UnitGroup('Biorefinery', tea.units) assert np.allclose(tea.IRR, 0.1, rtol=5e-2) assert np.allclose(feedstock.price, 0.03697665089334927, rtol=5e-2) assert np.allclose(product.price, 0.7256416231373818, rtol=5e-2) assert np.allclose(tea.sales, 59505464.74167342, rtol=5e-2) assert np.allclose(tea.material_cost, 60276803.95446354, rtol=5e-2) assert np.allclose(tea.installed_equipment_cost, 155595234.64612105, rtol=5e-2) assert np.allclose(tea.utility_cost, -42135324.82550436, rtol=5e-2) assert np.allclose(units.get_heating_duty(), 246.98009004771708, rtol=5e-2) assert np.allclose(units.get_cooling_duty(), 216.77598585710086, rtol=5e-2) assert np.allclose(units.get_electricity_consumption(), 8.731256311182772, rtol=5e-2) assert np.allclose(units.get_electricity_production(), 150.1534601155833, rtol=5e-2) @default_settings def test_oilcane_O4(): from biorefineries import oilcane as module try: module.load('O4') except: pass feedstock = module.feedstock product = module.ethanol tea = module.tea units = UnitGroup('Biorefinery', tea.units) assert np.allclose(tea.IRR, 0.1, rtol=5e-2) assert np.allclose(feedstock.price, 0.028503844501945857, rtol=5e-2) assert np.allclose(product.price, 0.789, rtol=5e-2) assert np.allclose(tea.sales, 118273243.2145202, rtol=5e-2) assert np.allclose(tea.material_cost, 56200720.802350216, rtol=5e-2) assert np.allclose(tea.installed_equipment_cost, 222700496.14979562, rtol=5e-2) assert np.allclose(tea.utility_cost, 1391380.407897248, rtol=5e-2) assert np.allclose(units.get_heating_duty(), 498.8196371180402, rtol=5e-2) assert np.allclose(units.get_cooling_duty(), 367.03902337598805, rtol=5e-2) assert np.allclose(units.get_electricity_consumption(), 19.1388128880444, rtol=5e-2) assert np.allclose(units.get_electricity_production(), 19.139640674241367, rtol=5e-2) @default_settings def test_oilcane_S1_agile(): from biorefineries import oilcane as module try: module.load('S1*') except: pass feedstock = module.feedstock product = module.ethanol tea = module.tea units = UnitGroup('Biorefinery', tea.units) assert np.allclose(tea.IRR, 0.1, rtol=5e-2) assert np.allclose(feedstock.price, 0.04255755678876426, rtol=5e-2) assert np.allclose(product.price, 0.7256416231373818, rtol=5e-2) assert np.allclose(tea.sales, 103451891.4163145, rtol=5e-2) assert np.allclose(tea.material_cost, 91078765.15813945, rtol=5e-2) assert np.allclose(tea.installed_equipment_cost, 126827608.96577132, rtol=5e-2) assert np.allclose(tea.utility_cost, -23052567.399197612, rtol=5e-2) assert np.allclose(units.get_heating_duty(), 116.58223220714966, rtol=5e-2) assert np.allclose(units.get_cooling_duty(), 194.4210315724837, rtol=5e-2) assert np.allclose(units.get_electricity_consumption(), 8.216905546072427, rtol=5e-2) assert np.allclose(units.get_electricity_production(), 81.18528634869718, rtol=5e-2) @default_settings def test_oilcane_S2_agile(): from biorefineries import oilcane as module try: module.load('S2*') except: pass feedstock = module.feedstock product = module.ethanol tea = module.tea units = UnitGroup('Biorefinery', tea.units) assert np.allclose(tea.IRR, 0.1, rtol=5e-2) assert np.allclose(feedstock.price, 0.03850594196707837, rtol=5e-2) assert np.allclose(product.price, 0.789, rtol=5e-2) assert np.allclose(tea.sales, 158417310.84075725, rtol=5e-2) assert np.allclose(tea.material_cost, 93459863.52661145, rtol=5e-2) assert np.allclose(tea.installed_equipment_cost, 230984688.76025438, rtol=5e-2) assert np.allclose(tea.utility_cost, 1820018.8584757461, rtol=5e-2) assert np.allclose(units.get_heating_duty(), 124.83259313951856, rtol=5e-2) assert np.allclose(units.get_cooling_duty(), 321.28350967657246, rtol=5e-2) assert np.allclose(units.get_electricity_consumption(), 22.95220788093058, rtol=5e-2) assert np.allclose(units.get_electricity_production(), 23.054739674888054, rtol=5e-2) @default_settings def test_oilcane_O1_agile(): from biorefineries import oilcane as module try: module.load('O1*') except: pass feedstock = module.feedstock product = module.ethanol tea = module.tea units = UnitGroup('Biorefinery', tea.units) assert np.allclose(tea.IRR, 0.1, rtol=5e-2) assert np.allclose(feedstock.price, 0.046530878739481224, rtol=5e-2) assert np.allclose(product.price, 0.7256416231373818, rtol=5e-2) assert np.allclose(tea.sales, 92435868.22021642, rtol=5e-2) assert np.allclose(tea.material_cost, 101214917.73920661, rtol=5e-2) assert np.allclose(tea.installed_equipment_cost, 164805803.4008069, rtol=5e-2) assert np.allclose(tea.utility_cost, -52760759.90754023, rtol=5e-2) assert np.allclose(units.get_heating_duty(), 226.99597514720188, rtol=5e-2) assert np.allclose(units.get_cooling_duty(), 199.49601258509207, rtol=5e-2) assert np.allclose(units.get_electricity_consumption(), 8.840388930547743, rtol=5e-2) assert np.allclose(units.get_electricity_production(), 131.17130704544203, rtol=5e-2) @default_settings def test_oilcane_O2_agile(): from biorefineries import oilcane as module try: module.load('O2*') except: pass feedstock = module.feedstock product = module.ethanol tea = module.tea units = UnitGroup('Biorefinery', tea.units) assert np.allclose(tea.IRR, 0.1, rtol=5e-2) assert np.allclose(feedstock.price, 0.0423287895668314, rtol=5e-2) assert np.allclose(product.price, 0.789, rtol=5e-2) assert np.allclose(tea.sales, 171616246.20705056, rtol=5e-2) assert np.allclose(tea.material_cost, 105763143.92419687, rtol=5e-2) assert np.allclose(tea.installed_equipment_cost, 234217725.81525323, rtol=5e-2) assert np.allclose(tea.utility_cost, 1808931.199477415, rtol=5e-2) assert np.allclose(units.get_heating_duty(), 442.8708149022719, rtol=5e-2) assert np.allclose(units.get_cooling_duty(), 209.20490499814076, rtol=5e-2) assert np.allclose(units.get_electricity_consumption(), 19.115345544733955, rtol=5e-2) assert np.allclose(units.get_electricity_production(), 19.205905376852552, rtol=5e-2) @default_settings def test_LAOs(): from biorefineries import LAOs as module try: module.load() except: pass feedstock = module.glucose product = module.octene tea = module.LAOs_tea units = UnitGroup('Biorefinery', tea.units) assert np.allclose(tea.IRR, 0.1, rtol=5e-2) assert np.allclose(feedstock.price, 0.265, rtol=5e-2) assert np.allclose(product.price, 1.2918667227938558, rtol=5e-2) assert np.allclose(tea.sales, 161435883.1972842, rtol=5e-2) assert np.allclose(tea.material_cost, 135658829.45874006, rtol=5e-2) assert np.allclose(tea.installed_equipment_cost, 55049531.41964977, rtol=5e-2) assert np.allclose(tea.utility_cost, 2702388.184876362, rtol=5e-2) assert np.allclose(units.get_heating_duty(), 38.31078344171506, rtol=5e-2) assert np.allclose(units.get_cooling_duty(), 123.69592718862401, rtol=5e-2) assert np.allclose(units.get_electricity_consumption(), 3.527871346094877, rtol=5e-2) assert np.allclose(units.get_electricity_production(), 3.5278713460948787, rtol=5e-2) ```
Click me for results with cane/enhancement branches ```python >>> from biorefineries import oilcane as oc >>> oc.load('O1') # I believe running O2 will trigger the same bug as well >>> oc.model.metrics_at_baseline() Biorefinery MFPP [USD/MT] 40.8 Feedstock consumption [MT/yr] 1.6e+06 Biodiesel production [L/MT] 18.5 Biodiesel yield [L/hc] NaN Ethanol production [L/MT] 44.9 Electricity production [kWhr/MT] 431 Net energy production [GGE/MT] 27.1 Natural gas consumption [m3/MT] 0 TCI [10^6*USD] 304 Heat exchanger network error [%] -9.52e-07 Economic allocation GWP [kg*CO2*eq / USD] 0.62 Ethanol GWP [kg*CO2*eq / L] 0.355 Biodiesel GWP [kg*CO2*eq / L] 0.355 Crude glycerol GWP [kg*CO2*eq / kg] 0.0992 Electricity GWP [kg*CO2*eq / MWhr] 39.7 Displacement allocation Ethanol GWP [kg*CO2*eq / L] -3.86 Biodiesel GWP [kg*CO2*eq / L] -9.38 Energy allocation Biofuel GWP [kg*CO2*eq / GGE] 1.48 Ethanol GWP [kg*CO2*eq / L] 0.26 Biodiesel GWP [kg*CO2*eq / L] 0.41 Crude-glycerol GWP [kg*CO2*eq / kg] 0.157 Biorefinery IRR [%] NaN MFPP derivative [USD/MT] 0.5 Biodiesel production derivative [L/MT] 1.85 Ethanol production derivative [L/MT] -4.38 Electricity production derivative [kWhr/MT] 22.2 Natural gas consumption derivative [cf/MT] 0 TCI derivative [10^6*USD] 3.44 Economic allocation GWP derivative [kg*CO2*eq / USD] 0.00404 Ethanol Ethanol GWP derivative [kg*CO2*eq / L] 0.00232 Biodiesel Biodiesel GWP derivative [kg*CO2*eq / L] 0.00232 Crude glycerol Crude glycerol GWP derivative [kg*CO2*eq / kg] 0.000647 Electricity Electricity GWP derivative [kg*CO2*eq / MWhr] 0.259 dtype: float64 @default_settings def test_corn(): from biorefineries import corn as module try: module.load() except: pass feedstock = module.corn product = module.ethanol tea = module.corn_tea units = UnitGroup('Biorefinery', tea.units) assert np.allclose(tea.IRR, 0.054793135761420905, rtol=5e-2) assert np.allclose(feedstock.price, 0.13227735731092652, rtol=5e-2) assert np.allclose(product.price, 0.48547915353569393, rtol=5e-2) assert np.allclose(tea.sales, 74723596.88174264, rtol=5e-2) assert np.allclose(tea.material_cost, 55525176.94552828, rtol=5e-2) assert np.allclose(tea.installed_equipment_cost, 62093937.0411999, rtol=5e-2) assert np.allclose(tea.utility_cost, 7484262.234701367, rtol=5e-2) assert np.allclose(units.get_heating_duty(), 95.0630956270271, rtol=5e-2) assert np.allclose(units.get_cooling_duty(), 114.83385319881219, rtol=5e-2) assert np.allclose(units.get_electricity_consumption(), 1.9369534237489576, rtol=5e-2) assert np.allclose(units.get_electricity_production(), 0.0, rtol=5e-2) @default_settings def test_lipidcane(): from biorefineries import lipidcane as module try: module.load() except: pass feedstock = module.lipidcane product = module.ethanol tea = module.tea units = UnitGroup('Biorefinery', tea.units) assert np.allclose(tea.IRR, 0.2085406915912631, rtol=5e-2) assert np.allclose(feedstock.price, 0.03455, rtol=5e-2) assert np.allclose(product.price, 0.789, rtol=5e-2) assert np.allclose(tea.sales, 102694047.72636937, rtol=5e-2) assert np.allclose(tea.material_cost, 58856880.18876951, rtol=5e-2) assert np.allclose(tea.installed_equipment_cost, 206545752.4568234, rtol=5e-2) assert np.allclose(tea.utility_cost, -28931835.470725328, rtol=5e-2) assert np.allclose(units.get_heating_duty(), 207.10490688845127, rtol=5e-2) assert np.allclose(units.get_cooling_duty(), 218.17006801938587, rtol=5e-2) assert np.allclose(units.get_electricity_consumption(), 7.2582786002102715, rtol=5e-2) assert np.allclose(units.get_electricity_production(), 104.41456236827366, rtol=5e-2) @default_settings def test_cornstover(): from biorefineries import cornstover as module try: module.load() except: pass feedstock = module.cornstover product = module.ethanol tea = module.tea units = UnitGroup('Biorefinery', tea.units) assert np.allclose(tea.IRR, 0.1, rtol=5e-2) assert np.allclose(feedstock.price, 0.05158816935126135, rtol=5e-2) assert np.allclose(product.price, 0.7333719888983871, rtol=5e-2) assert np.allclose(tea.sales, 135536068.36974084, rtol=5e-2) assert np.allclose(tea.material_cost, 82209367.24874295, rtol=5e-2) assert np.allclose(tea.installed_equipment_cost, 200715685.00584513, rtol=5e-2) assert np.allclose(tea.utility_cost, -5526978.776637238, rtol=5e-2) assert np.allclose(units.get_heating_duty(), 363.3753814500929, rtol=5e-2) assert np.allclose(units.get_cooling_duty(), 267.1471947922442, rtol=5e-2) assert np.allclose(units.get_electricity_consumption(), 18.578785100558147, rtol=5e-2) assert np.allclose(units.get_electricity_production(), 33.26470926469097, rtol=5e-2) @default_settings def test_sugarcane(): from biorefineries import sugarcane as module try: module.load() except: pass feedstock = module.sugarcane product = module.ethanol tea = module.tea units = UnitGroup('Biorefinery', tea.units) assert np.allclose(tea.IRR, 0.1428763497389623, rtol=5e-2) assert np.allclose(feedstock.price, 0.03455, rtol=5e-2) assert np.allclose(product.price, 0.789, rtol=5e-2) assert np.allclose(tea.sales, 88302442.78606105, rtol=5e-2) assert np.allclose(tea.material_cost, 57277062.32223333, rtol=5e-2) assert np.allclose(tea.installed_equipment_cost, 167490968.14053738, rtol=5e-2) assert np.allclose(tea.utility_cost, -12194793.465249695, rtol=5e-2) assert np.allclose(units.get_heating_duty(), 247.72055703822804, rtol=5e-2) assert np.allclose(units.get_cooling_duty(), 223.38600265957052, rtol=5e-2) assert np.allclose(units.get_electricity_consumption(), 7.494504639075067, rtol=5e-2) assert np.allclose(units.get_electricity_production(), 50.99521162967652, rtol=5e-2) @default_settings def test_oilcane_S1(): from biorefineries import oilcane as module try: module.load('S1') except: pass feedstock = module.feedstock product = module.ethanol tea = module.tea units = UnitGroup('Biorefinery', tea.units) assert np.allclose(tea.IRR, 0.1, rtol=5e-2) assert np.allclose(feedstock.price, 0.0387150563598164, rtol=5e-2) assert np.allclose(product.price, 0.7256416231373818, rtol=5e-2) assert np.allclose(tea.sales, 81211491.73735546, rtol=5e-2) assert np.allclose(tea.material_cost, 63948614.35552062, rtol=5e-2) assert np.allclose(tea.installed_equipment_cost, 120388026.76088503, rtol=5e-2) assert np.allclose(tea.utility_cost, -16597694.443256002, rtol=5e-2) assert np.allclose(units.get_heating_duty(), 246.6805648809778, rtol=5e-2) assert np.allclose(units.get_cooling_duty(), 245.42152922165081, rtol=5e-2) assert np.allclose(units.get_electricity_consumption(), 7.978780546507187, rtol=5e-2) assert np.allclose(units.get_electricity_production(), 66.40030690875176, rtol=5e-2) @default_settings def test_oilcane_S2(): from biorefineries import oilcane as module try: module.load('S2') except: pass feedstock = module.feedstock product = module.ethanol tea = module.tea units = UnitGroup('Biorefinery', tea.units) assert np.allclose(tea.IRR, 0.1, rtol=5e-2) assert np.allclose(feedstock.price, 0.03132217680486653, rtol=5e-2) assert np.allclose(product.price, 0.789, rtol=5e-2) assert np.allclose(tea.sales, 121030074.16768698, rtol=5e-2) assert np.allclose(tea.material_cost, 59771930.64294376, rtol=5e-2) assert np.allclose(tea.installed_equipment_cost, 220078597.56212902, rtol=5e-2) assert np.allclose(tea.utility_cost, 1402757.2497524437, rtol=5e-2) assert np.allclose(units.get_heating_duty(), 335.9393189712925, rtol=5e-2) assert np.allclose(units.get_cooling_duty(), 309.64371458799303, rtol=5e-2) assert np.allclose(units.get_electricity_consumption(), 21.607638665145327, rtol=5e-2) assert np.allclose(units.get_electricity_production(), 21.607638665145323, rtol=5e-2) @default_settings def test_oilcane_O1(): from biorefineries import oilcane as module try: module.load('O1') except: pass feedstock = module.feedstock product = module.ethanol tea = module.tea units = UnitGroup('Biorefinery', tea.units) assert np.allclose(tea.IRR, 0.1, rtol=5e-2) assert np.allclose(feedstock.price, 0.04239633790757486, rtol=5e-2) assert np.allclose(product.price, 0.7256416231373818, rtol=5e-2) assert np.allclose(tea.sales, 71993360.47700194, rtol=5e-2) assert np.allclose(tea.material_cost, 71394555.1386085, rtol=5e-2) assert np.allclose(tea.installed_equipment_cost, 163350004.57130826, rtol=5e-2) assert np.allclose(tea.utility_cost, -42831260.10448999, rtol=5e-2) assert np.allclose(units.get_heating_duty(), 252.19630057888367, rtol=5e-2) assert np.allclose(units.get_cooling_duty(), 223.68011855208957, rtol=5e-2) assert np.allclose(units.get_electricity_consumption(), 8.963759583476813, rtol=5e-2) assert np.allclose(units.get_electricity_production(), 152.64785261438897, rtol=5e-2) @default_settings def test_oilcane_O2(): from biorefineries import oilcane as module try: module.load('O2') except: pass feedstock = module.feedstock product = module.ethanol tea = module.tea units = UnitGroup('Biorefinery', tea.units) assert np.allclose(tea.IRR, 0.1, rtol=5e-2) assert np.allclose(feedstock.price, 0.04631588333810243, rtol=5e-2) assert np.allclose(product.price, 0.789, rtol=5e-2) assert np.allclose(tea.sales, 163071076.93074393, rtol=5e-2) assert np.allclose(tea.material_cost, 92970839.48075388, rtol=5e-2) assert np.allclose(tea.installed_equipment_cost, 250788391.83627176, rtol=5e-2) assert np.allclose(tea.utility_cost, 1391860.2352020722, rtol=5e-2) assert np.allclose(units.get_heating_duty(), 390.4598215007492, rtol=5e-2) assert np.allclose(units.get_cooling_duty(), 338.5911289251697, rtol=5e-2) assert np.allclose(units.get_electricity_consumption(), 23.386696906850233, rtol=5e-2) assert np.allclose(units.get_electricity_production(), 23.386696906850258, rtol=5e-2) @default_settings def test_oilcane_O3(): from biorefineries import oilcane as module try: module.load('O3') except: pass feedstock = module.feedstock product = module.ethanol tea = module.tea units = UnitGroup('Biorefinery', tea.units) assert np.allclose(tea.IRR, 0.1, rtol=5e-2) assert np.allclose(feedstock.price, 0.03697502362337885, rtol=5e-2) assert np.allclose(product.price, 0.7256416231373818, rtol=5e-2) assert np.allclose(tea.sales, 59505464.7419263, rtol=5e-2) assert np.allclose(tea.material_cost, 60272559.94946643, rtol=5e-2) assert np.allclose(tea.installed_equipment_cost, 155595541.53343156, rtol=5e-2) assert np.allclose(tea.utility_cost, -42131213.80497987, rtol=5e-2) assert np.allclose(units.get_heating_duty(), 247.03602244311105, rtol=5e-2) assert np.allclose(units.get_cooling_duty(), 216.84363200874702, rtol=5e-2) assert np.allclose(units.get_electricity_consumption(), 8.732652417909573, rtol=5e-2) assert np.allclose(units.get_electricity_production(), 150.14149487418058, rtol=5e-2) @default_settings def test_oilcane_O4(): from biorefineries import oilcane as module try: module.load('O4') except: pass feedstock = module.feedstock product = module.ethanol tea = module.tea units = UnitGroup('Biorefinery', tea.units) assert np.allclose(tea.IRR, 0.1, rtol=5e-2) assert np.allclose(feedstock.price, 0.04017535907850782, rtol=5e-2) assert np.allclose(product.price, 0.789, rtol=5e-2) assert np.allclose(tea.sales, 146687116.13255346, rtol=5e-2) assert np.allclose(tea.material_cost, 79161090.83887991, rtol=5e-2) assert np.allclose(tea.installed_equipment_cost, 241177664.5308826, rtol=5e-2) assert np.allclose(tea.utility_cost, 1397939.8456321156, rtol=5e-2) assert np.allclose(units.get_heating_duty(), 377.19554892676285, rtol=5e-2) assert np.allclose(units.get_cooling_duty(), 325.14475343375193, rtol=5e-2) assert np.allclose(units.get_electricity_consumption(), 22.924499079714145, rtol=5e-2) assert np.allclose(units.get_electricity_production(), 22.924499079714135, rtol=5e-2) @default_settings def test_oilcane_S1_agile(): from biorefineries import oilcane as module try: module.load('S1*') except: pass feedstock = module.feedstock product = module.ethanol tea = module.tea units = UnitGroup('Biorefinery', tea.units) assert np.allclose(tea.IRR, 0.1, rtol=5e-2) assert np.allclose(feedstock.price, 0.04254473585453909, rtol=5e-2) assert np.allclose(product.price, 0.7256416231373818, rtol=5e-2) assert np.allclose(tea.sales, 103451891.41629674, rtol=5e-2) assert np.allclose(tea.material_cost, 91052136.37564361, rtol=5e-2) assert np.allclose(tea.installed_equipment_cost, 126823497.00086044, rtol=5e-2) assert np.allclose(tea.utility_cost, -23025179.192949057, rtol=5e-2) assert np.allclose(units.get_heating_duty(), 116.80745940094549, rtol=5e-2) assert np.allclose(units.get_cooling_duty(), 194.79140976769625, rtol=5e-2) assert np.allclose(units.get_electricity_consumption(), 8.225481568331727, rtol=5e-2) assert np.allclose(units.get_electricity_production(), 81.12965160997803, rtol=5e-2) @default_settings def test_oilcane_S2_agile(): from biorefineries import oilcane as module try: module.load('S2*') except: pass feedstock = module.feedstock product = module.ethanol tea = module.tea units = UnitGroup('Biorefinery', tea.units) assert np.allclose(tea.IRR, 0.1, rtol=5e-2) assert np.allclose(feedstock.price, 0.038500191606569395, rtol=5e-2) assert np.allclose(product.price, 0.789, rtol=5e-2) assert np.allclose(tea.sales, 158349820.94684818, rtol=5e-2) assert np.allclose(tea.material_cost, 93403868.79436304, rtol=5e-2) assert np.allclose(tea.installed_equipment_cost, 230951296.44313276, rtol=5e-2) assert np.allclose(tea.utility_cost, 1818646.9491766377, rtol=5e-2) assert np.allclose(units.get_heating_duty(), 151.82709825682693, rtol=5e-2) assert np.allclose(units.get_cooling_duty(), 302.3056370585559, rtol=5e-2) assert np.allclose(units.get_electricity_consumption(), 22.954406221767783, rtol=5e-2) assert np.allclose(units.get_electricity_production(), 23.063572868095324, rtol=5e-2) @default_settings def test_oilcane_O1_agile(): from biorefineries import oilcane as module try: module.load('O1*') except: pass feedstock = module.feedstock product = module.ethanol tea = module.tea units = UnitGroup('Biorefinery', tea.units) assert np.allclose(tea.IRR, 0.1, rtol=5e-2) assert np.allclose(feedstock.price, 0.046717561330879585, rtol=5e-2) assert np.allclose(product.price, 0.7256416231373818, rtol=5e-2) assert np.allclose(tea.sales, 92435850.58665347, rtol=5e-2) assert np.allclose(tea.material_cost, 101606324.27962075, rtol=5e-2) assert np.allclose(tea.installed_equipment_cost, 164707855.93845895, rtol=5e-2) assert np.allclose(tea.utility_cost, -53124217.0363231, rtol=5e-2) assert np.allclose(units.get_heating_duty(), 227.03389380488375, rtol=5e-2) assert np.allclose(units.get_cooling_duty(), 193.4364294311562, rtol=5e-2) assert np.allclose(units.get_electricity_consumption(), 8.86305410205487, rtol=5e-2) assert np.allclose(units.get_electricity_production(), 133.38171690786592, rtol=5e-2) @default_settings def test_oilcane_O2_agile(): from biorefineries import oilcane as module try: module.load('O2*') except: pass feedstock = module.feedstock product = module.ethanol tea = module.tea units = UnitGroup('Biorefinery', tea.units) assert np.allclose(tea.IRR, 0.1, rtol=5e-2) assert np.allclose(feedstock.price, 0.053799672544449034, rtol=5e-2) assert np.allclose(product.price, 0.789, rtol=5e-2) assert np.allclose(tea.sales, 207226491.06851304, rtol=5e-2) assert np.allclose(tea.material_cost, 135996457.08888236, rtol=5e-2) assert np.allclose(tea.installed_equipment_cost, 254562018.1591063, rtol=5e-2) assert np.allclose(tea.utility_cost, 1312895.6393453965, rtol=5e-2) assert np.allclose(units.get_heating_duty(), 311.2084732587519, rtol=5e-2) assert np.allclose(units.get_cooling_duty(), 265.8831320026464, rtol=5e-2) assert np.allclose(units.get_electricity_consumption(), 23.229887222456313, rtol=5e-2) assert np.allclose(units.get_electricity_production(), 28.321981978881624, rtol=5e-2) @default_settings def test_LAOs(): from biorefineries import LAOs as module try: module.load() except: pass feedstock = module.glucose product = module.octene tea = module.LAOs_tea units = UnitGroup('Biorefinery', tea.units) assert np.allclose(tea.IRR, 0.1, rtol=5e-2) assert np.allclose(feedstock.price, 0.265, rtol=5e-2) assert np.allclose(product.price, 1.2918667227938558, rtol=5e-2) assert np.allclose(tea.sales, 161435883.1972842, rtol=5e-2) assert np.allclose(tea.material_cost, 135658829.45874006, rtol=5e-2) assert np.allclose(tea.installed_equipment_cost, 55049531.41964977, rtol=5e-2) assert np.allclose(tea.utility_cost, 2702388.184876362, rtol=5e-2) assert np.allclose(units.get_heating_duty(), 38.31078344171506, rtol=5e-2) assert np.allclose(units.get_cooling_duty(), 123.69592718862404, rtol=5e-2) assert np.allclose(units.get_electricity_consumption(), 3.527871346094877, rtol=5e-2) assert np.allclose(units.get_electricity_production(), 3.5278713460948787, rtol=5e-2) ```
yalinli2 commented 1 year ago

wonderful, now the two oilcane biorefineries are giving similar results as before, I did need to update some parameter settings, but it was minor and pretty straightforward.

the cellulosic sugarcane biorefineries are weird, directly loading the biorefineries are fine, but for some of my analyses, the results are weird, sometimes they are close but with small-yet-significant deviations, sometimes they are outright not correct. I think I've seen similar things before for the cornstover biorefineries because of some stream connection issues (for the cornstover biorefinery it was due to the auto population of the streams for the wastewater treatment process, which caused inconsistent inlet/outlet indexing between simulations), I should be able to fix it, just need to give a closer look

anyway, I'm good with merging this branch in, thank @yoelcortes !!!

yoelcortes commented 1 year ago

Thanks, @yalinli2! Once I get all the tests passing in the biosteam refractor and thermosteam enhacement branches and get pull requests approved for those, I will go ahead and merge them all at the same time.

By the way, I had a look at your commit and realized that a correction made to unit ID "areas" is probably the source. Would it be helpful to have a constant, alternative ID for a unit operation? This is possible using the register_alias method. Please feel free to set whatever aliases your need for any unit operation or stream.

Here is an example from the tests:

import thermosteam as tmo
tmo.settings.set_thermo(['Water'], cache=True)
s = tmo.Stream('s1', Water=1)
s.register_alias('stream_1')
assert s.registry.stream_1 is s.registry.s1 is s
yalinli2 commented 1 year ago

yep using the alias would be a good idea, thanks for the tip!

yoelcortes commented 1 year ago

@yalinli2, I'd like to update you about the following corrections to the cane biorefineries:

  1. After some reading online and checking with the Humbird 2011 report, I realized that there is heat integration with the flue gas (exit temperature around 140 C) and sensible heats are not typically included in the boiler efficiency calculation. I updated the BoilerTurbogenerator class to only include LHV (now the default) and HHV based calculations. Although tests need to be updated, the overall results of all biorefineries did not change much.

  2. The conventional sugarcane to ethanol biorefinery using oilcane.load('S1') did not include the bagasse drier system (which is needed for better performance of the boiler). This is now fixed.

I also made a bit more refactoring and clean up, but I think it is very minor. Now I'll focus on updating all the tests (including in the tutorial) so that we can get these in the main branches. I'll also try to get the continuous integration tests on github working with that tip you suggested.

Thanks!

yalinli2 commented 1 year ago

Thanks @yoelcortes for the updates, but unfortunately I now ran into troubles using the new biorefineries:

  1. For cane biorefineries with S2 and O2 configuration, I now will run into this error, which didn't occur before and I'm not sure why image
  2. The GWP results for multiple biorefineries have changed in a noticeable way, I think it's because of the changes in BoilerTurbogenerator, I'm OK with it since I like the current way of efficiency setting and energy calculation.

As for the first one, it might come from the restructuring of the cane biorefineries, which used to have a cache dict that I can set to None to enforce creating of two new different systems in the same console (in my analysis I'll modify one of them to have the new wwt module). I had to work around now since the new Biorefinery class is used instead.

Related, I made some minor updates for the cane biorefineries to allow for alternative chemicals to be used (https://github.com/BioSTEAMDevelopmentGroup/Bioindustrial-Park/pull/54/commits/cccdf681e119d9a6be12c8efda48fb3474a74b02) - there are some additional chemicals needed in the new wwt module.

I want to wait till all changes are made and see if the problems will go away. Maybe we don't even need to fix the problem since at some point we will implement the new wwt module and I want to make it so that the user can choose which one they want to use uploading creating the system. Rather than keeping this wwt module to have separate analyses.

yoelcortes commented 1 year ago

@yalinli2, I didn't realize the cache parameter was being used. I went ahead and added it back for consistency too. Hopefully error 1 goes away. Yeah, the changes in BoilerTurbogenerator are more significant for GWP results... but I agree with you that it's for the best.

It would be awesome If you can add the new wwt system creation as an option to the Biorefinery class. I'd be happy to make any changes that you think might be needed for this.

Thanks,

yalinli2 commented 1 year ago

Awesome, the error is gone now, thanks @yoelcortes for adding back the cache arg!!!

I'll open another draft PR on biosteam on the wwt module after we hear back on the manuscript - just want to wait in case the reviewers want us to make any changes.