diff --git a/setup.py b/setup.py index 52faf5a767..9bdfe9e265 100644 --- a/setup.py +++ b/setup.py @@ -153,20 +153,7 @@ "nf_with_bypass = watertap.examples.flowsheets.nf_dspmde.nf_with_bypass_ui", "bsm2 = watertap.examples.flowsheets.case_studies.full_water_resource_recovery_facility.BSM2_ui", "bsm2_P_extension = watertap.examples.flowsheets.case_studies.full_water_resource_recovery_facility.BSM2_P_extension_ui", - "metab = watertap.examples.flowsheets.case_studies.wastewater_resource_recovery.metab.metab_ui", - "suboxic_ASM = watertap.examples.flowsheets.case_studies.wastewater_resource_recovery.suboxic_activated_sludge_process.suboxic_ASM_ui", - "Magprex = watertap.examples.flowsheets.case_studies.wastewater_resource_recovery.amo_1575_magprex.magprex_ui", - "biomembrane_filtration = watertap.examples.flowsheets.case_studies.wastewater_resource_recovery.biomembrane_filtration.biomembrane_filtration_ui", - "ENR = watertap.examples.flowsheets.case_studies.wastewater_resource_recovery.electrochemical_nutrient_removal.electrochemical_nutrient_removal_ui", - "CANDO_P = watertap.examples.flowsheets.case_studies.wastewater_resource_recovery.amo_1595_photothermal_membrane_candoP.amo_1595_ui", - "supercritical_sludge_to_gas = watertap.examples.flowsheets.case_studies.wastewater_resource_recovery.supercritical_sludge_to_gas.supercritical_sludge_to_gas_ui", - "PAA = watertap.examples.flowsheets.case_studies.wastewater_resource_recovery.peracetic_acid_disinfection.peracetic_acid_disinfection_ui", - "AMO 1690 = watertap.examples.flowsheets.case_studies.wastewater_resource_recovery.amo_1690.amo_1690_ui", - "HRCS = watertap.examples.flowsheets.case_studies.wastewater_resource_recovery.amo_1575_hrcs.hrcs_ui", - "groundwater_treatment = watertap.examples.flowsheets.case_studies.wastewater_resource_recovery.groundwater_treatment.groundwater_treatment_ui", "dye_desalination = watertap.examples.flowsheets.case_studies.wastewater_resource_recovery.dye_desalination.dye_desalination_ui", - "swine_wwt = watertap.examples.flowsheets.case_studies.wastewater_resource_recovery.swine_wwt.swine_wwt_ui", - "GLSD anaerobic digestion = watertap.examples.flowsheets.case_studies.wastewater_resource_recovery.GLSD_anaerobic_digester.GLSD_anaerobic_digestion_ui", "mvc = watertap.examples.flowsheets.mvc.mvc_single_stage_ui", "RO = watertap.examples.flowsheets.RO_with_energy_recovery.RO_with_energy_recovery_ui", "OARO = watertap.examples.flowsheets.oaro.oaro_multi_ui", diff --git a/watertap/examples/flowsheets/case_studies/wastewater_resource_recovery/GLSD_anaerobic_digester/GLSD_anaerobic_digestion_ui.png b/watertap/examples/flowsheets/case_studies/wastewater_resource_recovery/GLSD_anaerobic_digester/GLSD_anaerobic_digestion_ui.png deleted file mode 100644 index 56426fd6eb..0000000000 Binary files a/watertap/examples/flowsheets/case_studies/wastewater_resource_recovery/GLSD_anaerobic_digester/GLSD_anaerobic_digestion_ui.png and /dev/null differ diff --git a/watertap/examples/flowsheets/case_studies/wastewater_resource_recovery/GLSD_anaerobic_digester/GLSD_anaerobic_digestion_ui.py b/watertap/examples/flowsheets/case_studies/wastewater_resource_recovery/GLSD_anaerobic_digester/GLSD_anaerobic_digestion_ui.py deleted file mode 100644 index 89a486e042..0000000000 --- a/watertap/examples/flowsheets/case_studies/wastewater_resource_recovery/GLSD_anaerobic_digester/GLSD_anaerobic_digestion_ui.py +++ /dev/null @@ -1,452 +0,0 @@ -################################################################################# -# WaterTAP Copyright (c) 2020-2024, The Regents of the University of California, -# through Lawrence Berkeley National Laboratory, Oak Ridge National Laboratory, -# National Renewable Energy Laboratory, and National Energy Technology -# Laboratory (subject to receipt of any required approvals from the U.S. Dept. -# of Energy). All rights reserved. -# -# Please see the files COPYRIGHT.md and LICENSE.md for full copyright and license -# information, respectively. These files are also available online at the URL -# "https://github.com/watertap-org/watertap/" -################################################################################# -from watertap.ui.fsapi import FlowsheetInterface -from watertap.core.util.initialization import assert_degrees_of_freedom -from watertap.examples.flowsheets.case_studies.wastewater_resource_recovery.GLSD_anaerobic_digester.GLSD_anaerobic_digestion import ( - build, - set_operating_conditions, - initialize_system, - solve, - add_costing, -) -from pyomo.environ import units as pyunits, assert_optimal_termination -from pyomo.util.check_units import assert_units_consistent - - -def export_to_ui(): - return FlowsheetInterface( - name="GLSD Anaerobic Digestion", - do_export=export_variables, - do_build=build_flowsheet, - do_solve=solve_flowsheet, - ) - - -def export_variables(flowsheet=None, exports=None, build_options=None, **kwargs): - fs = flowsheet - # --- Input data --- - # Feed conditions - exports.add( - obj=fs.feed.flow_vol[0], - name="Volumetric flow rate", - ui_units=pyunits.m**3 / pyunits.hr, - display_units="m3/h", - rounding=1, - description="Inlet volumetric flow rate", - is_input=True, - input_category="Feed", - is_output=True, - output_category="Feed", - ) - exports.add( - obj=fs.feed.conc_mass_comp[0, "tss"], - name="TSS concentration", - ui_units=pyunits.g / pyunits.L, - display_units="g/L", - rounding=1, - description="Inlet total suspended solids (TSS) concentration", - is_input=True, - input_category="Feed", - is_output=True, - output_category="Feed", - ) - - # Unit model data, anaerobic digester - exports.add( - obj=fs.AD.recovery_frac_mass_H2O[0], - name="Water recovery", - ui_units=pyunits.dimensionless, - display_units="fraction", - rounding=2, - description="Water recovery [g-H2O treated/g-H2O inlet]", - is_input=True, - input_category="Anaerobic digester", - is_output=False, - ) - exports.add( - obj=fs.AD.reaction_conversion[0, "tss_reaction"], - name="TSS conversion", - ui_units=pyunits.dimensionless, - display_units="fraction", - rounding=2, - description="TSS conversion [g-TSS reacted/g-TSS inlet]", - is_input=True, - input_category="Anaerobic digester", - is_output=False, - ) - exports.add( - obj=fs.AD.generation_ratio["tss_reaction", "methane"], - name="CH4 conversion ratio", - ui_units=pyunits.dimensionless, - display_units="fraction", - rounding=4, - description="CH4 mass conversion ratio with respect to TSS [g-CH4 produced/g-TSS" - " reacted]", - is_input=True, - input_category="Anaerobic digester", - is_output=False, - ) - exports.add( - obj=fs.AD.generation_ratio["tss_reaction", "carbon_dioxide"], - name="CO2 conversion ratio", - ui_units=pyunits.dimensionless, - display_units="fraction", - rounding=4, - description="CO2 mass conversion ratio with respect to TSS [g-CO2 produced/g-TSS" - " reacted]", - is_input=True, - input_category="Anaerobic digester", - is_output=False, - ) - exports.add( - obj=fs.AD.generation_ratio["tss_reaction", "nitrogen"], - name="N2 conversion ratio", - ui_units=pyunits.dimensionless, - display_units="fraction", - rounding=4, - description="N2 mass conversion ratio with respect to TSS [g-N2 produced/g-TSS" - " reacted]", - is_input=True, - input_category="Anaerobic digester", - is_output=False, - ) - exports.add( - obj=fs.AD.generation_ratio["tss_reaction", "oxygen"], - name="O2 conversion ratio", - ui_units=pyunits.dimensionless, - display_units="fraction", - rounding=4, - description="O2 mass conversion ratio with respect to TSS [g-O2 produced/g-TSS" - " reacted]", - is_input=True, - input_category="Anaerobic digester", - is_output=False, - ) - exports.add( - obj=fs.AD.HRT, - name="HRT", - ui_units=pyunits.hr, - display_units="h", - rounding=0, - description="Hydraulic retention time", - is_input=True, - input_category="Anaerobic digester", - is_output=False, - ) - exports.add( - obj=fs.AD.energy_electric_flow_vol_inlet, - name="Specific power", - ui_units=pyunits.kWh / pyunits.m**3, - display_units="kWh/m3", - rounding=2, - description="Specific power relating the power to the inlet flow", - is_input=True, - input_category="Anaerobic digester", - is_output=False, - ) - - # System costing - exports.add( - obj=fs.costing.utilization_factor, - name="Utilization factor", - ui_units=pyunits.dimensionless, - display_units="fraction", - rounding=2, - description="Utilization factor - [annual use hours/total hours in year]", - is_input=True, - input_category="System costing", - is_output=False, - ) - exports.add( - obj=fs.costing.TIC, - name="Practical investment factor", - ui_units=pyunits.dimensionless, - display_units="fraction", - rounding=1, - description="Practical investment factor - [total investment cost/direct " - "capital costs]", - is_input=True, - input_category="System costing", - is_output=False, - ) - exports.add( - obj=fs.costing.plant_lifetime, - name="Plant lifetime", - ui_units=pyunits.year, - display_units="years", - rounding=1, - description="Plant lifetime", - is_input=True, - input_category="System costing", - is_output=False, - ) - exports.add( - obj=fs.costing.wacc, - name="Discount rate", - ui_units=pyunits.dimensionless, - display_units="fraction", - rounding=2, - description="Discount rate used in calculating the capital annualization", - is_input=True, - input_category="System costing", - is_output=False, - ) - exports.add( - obj=fs.costing.maintenance_costs_percent_FCI, - name="Fixed operating cost factor", - ui_units=1 / pyunits.year, - display_units="fraction/year", - rounding=2, - description="Fixed operating cost factor - [annual fixed operating cost/total " - "investment cost]", - is_input=True, - input_category="System costing", - is_output=False, - ) - exports.add( - obj=fs.costing.electricity_cost, - name="Electricity cost", - ui_units=fs.costing.base_currency / pyunits.kWh, - display_units="$/kWh", - rounding=3, - description="Electricity cost", - is_input=True, - input_category="System costing", - is_output=False, - ) - - # Outlets - exports.add( - obj=fs.product_H2O.properties[0].flow_vol, - name="Product water flow rate", - ui_units=pyunits.m**3 / pyunits.hr, - display_units="m3/h", - rounding=2, - description="Outlet product water flow rate", - is_input=False, - is_output=True, - output_category="Outlets", - ) - exports.add( - obj=fs.product_H2O.properties[0].conc_mass_comp["tss"], - name="Product water TSS concentration", - ui_units=pyunits.g / pyunits.L, - display_units="g/L", - rounding=2, - description="Outlet product water total suspended solids concentration", - is_input=False, - is_output=True, - output_category="Outlets", - ) - - # System metrics - exports.add( - obj=fs.costing.LCOT, - name="Levelized cost of treatment", - ui_units=fs.costing.base_currency / pyunits.m**3, - display_units="$/m3 of feed", - rounding=2, - description="Levelized cost of treatment including operating and capital costs", - is_input=False, - is_output=True, - output_category="Levelized cost metrics", - ) - exports.add( - obj=fs.costing.LCOW, - name="Levelized cost of water", - ui_units=fs.costing.base_currency / pyunits.m**3, - display_units="$/m3 of product", - rounding=2, - description="Levelized cost of water including operating and capital costs", - is_input=False, - is_output=True, - output_category="Levelized cost metrics", - ) - - # Normalized metrics - total_capital_norm = fs.costing.total_capital_cost / fs.feed.properties[0].flow_vol - exports.add( - obj=total_capital_norm, - name="Total capital", - ui_units=fs.costing.base_currency / (pyunits.m**3 / pyunits.day), - display_units="$/(m3/day)", - rounding=1, - description="Normalized total capital costs accounting for indirect " - "capital and installation - [total capital costs/feed flow rate]", - is_input=False, - is_output=True, - output_category="Normalized cost metrics", - ) - direct_capital_norm = ( - fs.AD.costing.direct_capital_cost + fs.P1.costing.direct_capital_cost - ) / fs.feed.properties[0].flow_vol - exports.add( - obj=direct_capital_norm, - name="Direct capital", - ui_units=fs.costing.base_currency / (pyunits.m**3 / pyunits.day), - display_units="$/(m3/day)", - rounding=1, - description="Normalized direct capital costs - [total direct capital " - "costs/feed flow rate] ", - is_input=False, - is_output=True, - output_category="Normalized cost metrics", - ) - elec_operating_norm = ( - fs.costing.aggregate_flow_costs["electricity"] / fs.costing.annual_water_inlet - ) - exports.add( - obj=elec_operating_norm, - name="Electricity", - ui_units=fs.costing.base_currency / pyunits.m**3, - display_units="$/m3 of feed", - rounding=2, - description="Normalized electricity cost - [annual electricity costs/annual " - "feed flow rate]", - is_input=False, - is_output=True, - output_category="Normalized cost metrics", - ) - - # performance metrics - recovery_vol = ( - fs.product_H2O.properties[0].flow_vol / fs.feed.properties[0].flow_vol - ) - exports.add( - obj=recovery_vol, - name="Volumetric recovery", - ui_units=pyunits.dimensionless, - display_units="m3 of product/m3 of feed", - rounding=4, - description="Normalized heating cost - [annual heating costs/annual feed " - "flow rate]", - is_input=False, - is_output=True, - output_category="Normalized performance metrics", - ) - removal_tss = ( - 1 - - fs.product_H2O.properties[0].flow_mass_comp["tss"] - / fs.feed.properties[0].flow_mass_comp["tss"] - ) - exports.add( - obj=removal_tss, - name="TSS removal", - ui_units=pyunits.dimensionless, - display_units="fraction", - rounding=2, - description="TSS removal fraction [1 - outlet TSS flow/inlet TSS flow]", - is_input=False, - is_output=True, - output_category="Normalized performance metrics", - ) - - # Capital costs - exports.add( - obj=fs.costing.total_capital_cost, - name="Total", - ui_units=fs.costing.base_currency, - display_units="$", - rounding=0, - description="Total capital costs - including investment factor to account " - "for indirect capital", - is_input=False, - is_output=True, - output_category="Capital costs", - ) - exports.add( - obj=fs.AD.costing.capital_cost, - name="Anaerobic digester", - ui_units=fs.costing.base_currency, - display_units="$", - rounding=0, - description="Anaerobic digester", - is_input=False, - is_output=True, - output_category="Capital costs", - ) - exports.add( - obj=fs.P1.costing.capital_cost, - name="Pump", - ui_units=fs.costing.base_currency, - display_units="$", - rounding=0, - description="Pump", - is_input=False, - is_output=True, - output_category="Capital costs", - ) - - # Operating costs - exports.add( - obj=fs.costing.total_operating_cost, - name="Total", - ui_units=fs.costing.base_currency / pyunits.year, - display_units="$/year", - rounding=0, - description="Total annual operating costs - including electricity, heating, " - "and fixed", - is_input=False, - is_output=True, - output_category="Operating costs", - ) - exports.add( - obj=fs.costing.aggregate_flow_costs["electricity"], - name="Electricity", - ui_units=fs.costing.base_currency / pyunits.year, - display_units="$/year", - rounding=0, - description="Annual electricity costs ", - is_input=False, - is_output=True, - output_category="Operating costs", - ) - exports.add( - obj=fs.costing.total_fixed_operating_cost, - name="Fixed", - ui_units=fs.costing.base_currency / pyunits.year, - display_units="$/year", - rounding=0, - description="Annual fixed operating costs - these costs include material " - "replacement, maintenance, and labor", - is_input=False, - is_output=True, - output_category="Operating costs", - ) - - -def build_flowsheet(build_options=None, **kwargs): - # build and solve initial flowsheet - m = build() - - set_operating_conditions(m) - assert_degrees_of_freedom(m, 0) - assert_units_consistent(m) - - initialize_system(m) - - results = solve(m) - assert_optimal_termination(results) - - add_costing(m) - assert_degrees_of_freedom(m, 0) - m.fs.costing.initialize() - - results = solve(m) - assert_optimal_termination(results) - return m - - -def solve_flowsheet(flowsheet=None): - fs = flowsheet - results = solve(fs) - return results diff --git a/watertap/examples/flowsheets/case_studies/wastewater_resource_recovery/amo_1575_hrcs/hrcs_ui.png b/watertap/examples/flowsheets/case_studies/wastewater_resource_recovery/amo_1575_hrcs/hrcs_ui.png deleted file mode 100644 index 40118b4d16..0000000000 Binary files a/watertap/examples/flowsheets/case_studies/wastewater_resource_recovery/amo_1575_hrcs/hrcs_ui.png and /dev/null differ diff --git a/watertap/examples/flowsheets/case_studies/wastewater_resource_recovery/amo_1575_hrcs/hrcs_ui.py b/watertap/examples/flowsheets/case_studies/wastewater_resource_recovery/amo_1575_hrcs/hrcs_ui.py deleted file mode 100644 index 9991b8a0f6..0000000000 --- a/watertap/examples/flowsheets/case_studies/wastewater_resource_recovery/amo_1575_hrcs/hrcs_ui.py +++ /dev/null @@ -1,788 +0,0 @@ -################################################################################# -# WaterTAP Copyright (c) 2020-2024, The Regents of the University of California, -# through Lawrence Berkeley National Laboratory, Oak Ridge National Laboratory, -# National Renewable Energy Laboratory, and National Energy Technology -# Laboratory (subject to receipt of any required approvals from the U.S. Dept. -# of Energy). All rights reserved. -# -# Please see the files COPYRIGHT.md and LICENSE.md for full copyright and license -# information, respectively. These files are also available online at the URL -# "https://github.com/watertap-org/watertap/" -################################################################################# -from watertap.ui.fsapi import FlowsheetInterface -from watertap.core.util.initialization import assert_degrees_of_freedom -from watertap.examples.flowsheets.case_studies.wastewater_resource_recovery.amo_1575_hrcs.hrcs import ( - build, - set_operating_conditions, - initialize_system, - solve, - add_costing, -) -from pyomo.environ import units as pyunits, assert_optimal_termination -from pyomo.util.check_units import assert_units_consistent - - -def export_to_ui(): - return FlowsheetInterface( - name="HRCS", - do_export=export_variables, - do_build=build_flowsheet, - do_solve=solve_flowsheet, - ) - - -def export_variables(flowsheet=None, exports=None, build_options=None, **kwargs): - fs = flowsheet - - def _base_curr(x): - return pyunits.convert(x, to_units=fs.costing.base_currency) - - # --- Input data --- - # Feed conditions - exports.add( - obj=fs.feed.flow_vol[0], - name="Volumetric flow rate", - ui_units=pyunits.m**3 / pyunits.hr, - display_units="m3/h", - rounding=2, - description="Inlet volumetric flow rate", - is_input=True, - input_category="Feed", - is_output=True, - output_category="Feed", - ) - exports.add( - obj=fs.feed.conc_mass_comp[0, "tss"], - name="TSS concentration", - ui_units=pyunits.mg / pyunits.L, - display_units="mg/L", - rounding=2, - description="Inlet total suspended solids concentration", - is_input=True, - input_category="Feed", - is_output=True, - output_category="Feed", - ) - exports.add( - obj=fs.feed.properties[0].flow_mass_comp["cod"], - name="COD mass flow", - ui_units=pyunits.ton / pyunits.day, - display_units="ton/day", - rounding=2, - description="Inlet COD mass flow", - is_input=True, - input_category="Feed", - is_output=True, - output_category="Feed", - ) - exports.add( - obj=fs.feed.properties[0].flow_mass_comp["oxygen"], - name="O2 mass flow", - ui_units=pyunits.ton / pyunits.day, - display_units="ton/day", - rounding=2, - description="Inlet oxygen mass flow", - is_input=True, - input_category="Feed", - is_output=True, - output_category="Feed", - ) - exports.add( - obj=fs.feed.conc_mass_comp[0, "carbon_dioxide"], - name="CO2 concentration", - ui_units=pyunits.mg / pyunits.L, - display_units="mg/L", - rounding=2, - description="Inlet carbon dioxide concentration", - is_input=True, - input_category="Feed", - is_output=True, - output_category="Feed", - ) - # Unit model data, HRCS - exports.add( - obj=fs.HRCS.recovery_frac_mass_H2O[0], - name="Water recovery", - ui_units=pyunits.dimensionless, - display_units="fraction", # we should change to % - rounding=2, - description="Water recovery [g-H2O treated/g-H2O inlet]", - is_input=True, - input_category="HRCS", - is_output=False, - ) - exports.add( - obj=fs.HRCS.reaction_conversion[0, "oxidation"], - name="COD conversion", - ui_units=pyunits.dimensionless, - display_units="fraction", # we should change to % - rounding=2, - description="COD conversion [g-COD reacted/g-COD inlet]", - is_input=True, - input_category="HRCS", - is_output=False, - ) - exports.add( - obj=fs.HRCS.removal_frac_mass_comp[0, "tss"], - name="TSS removal", - ui_units=pyunits.dimensionless, - display_units="fraction", # we should change to % - rounding=2, - description="Total suspended solids removal [g-TSS removed/g-TSS inlet]", - is_input=True, - input_category="HRCS", - is_output=False, - ) - exports.add( - obj=fs.HRCS.energy_electric_flow_vol_inlet, - name="Aeration energy", - ui_units=pyunits.kWh / pyunits.m**3, - display_units="kWh/m3", - rounding=2, - description="Specific aeration energy relating the energy to the volume of treated water", - is_input=True, - input_category="HRCS", - is_output=False, - ) - - # Unit cost data, HRCS - exports.add( - obj=fs.costing.hrcs.SRT[None], - name="SRT", - ui_units=pyunits.hr, - display_units="h", - rounding=1, - description="Solids retention time", - is_input=True, - input_category="HRCS costing", - is_output=False, - ) - exports.add( - obj=fs.costing.hrcs.sizing_cost[None], - name="HRCS cost", - ui_units=fs.costing.base_currency / pyunits.m**3, - display_units="$/m3 of HRCS", - rounding=0, - description="HRCS capital cost parameter", - is_input=True, - input_category="HRCS costing", - is_output=False, - ) - - # Unit model data, clarifier - exports.add( - obj=fs.clarifier.recovery_frac_mass_H2O[0], - name="Water recovery", - ui_units=pyunits.dimensionless, - display_units="fraction", # we should change to % - rounding=2, - description="Water recovery [g-H2O treated/g-H2O inlet]", - is_input=True, - input_category="Clarifier", - is_output=False, - ) - exports.add( - obj=fs.clarifier.removal_frac_mass_comp[0, "tss"], - name="TSS removal", - ui_units=pyunits.dimensionless, - display_units="fraction", # we should change to % - rounding=3, - description="Total suspended solids removal [g-TSS removed/g-TSS inlet]", - is_input=True, - input_category="Clarifier", - is_output=False, - ) - exports.add( - obj=fs.clarifier.removal_frac_mass_comp[0, "cod"], - name="COD removal", - ui_units=pyunits.dimensionless, - display_units="fraction", # we should change to % - rounding=3, - description="Total COD [g-COD removed/g-COD inlet]", - is_input=True, - input_category="Clarifier", - is_output=False, - ) - exports.add( - obj=fs.clarifier.energy_electric_flow_vol_inlet, - name="Electricity intensity", - ui_units=pyunits.kWh / pyunits.m**3, - display_units="kWh/m3", - rounding=2, - description="Clarifier electricity intensity relating the energy to the volume of treated water", - is_input=True, - input_category="Clarifier", - is_output=False, - ) - exports.add( - obj=fs.clarifier.ferric_chloride_dose[0], - name="FeCl3 dosage", - ui_units=pyunits.mg / pyunits.L, - display_units="mg FeCl3/L sludge treated", - rounding=2, - description="Ferric chloride dosage per L of sludge treated", - is_input=True, - input_category="Clarifier", - is_output=False, - ) - # Unit cost data, clarifier - exports.add( - obj=fs.costing.clarifier.HRT["HRCS_clarifier"], - name="HRT", - ui_units=pyunits.hr, - display_units="h", - rounding=1, - description="Hydraulic retention time", - is_input=True, - input_category="Clarifier costing", - is_output=False, - ) - exports.add( - obj=fs.costing.clarifier.sizing_cost["HRCS_clarifier"], - name="Clarifier cost", - ui_units=fs.costing.base_currency / pyunits.m**3, - display_units="$/m3 of clarifier", - rounding=0, - description="Clarifier capital cost parameter", - is_input=True, - input_category="Clarifier costing", - is_output=False, - ) - - # Unit model data, primary separator - exports.add( - obj=fs.sep.recovery_frac_mass_H2O[0], - name="Water recovery", - ui_units=pyunits.dimensionless, - display_units="fraction", # we should change to % - rounding=2, - description="Water recovery in purge stream [g-H2O treated/g-H2O inlet]", - is_input=True, - input_category="Separator", - is_output=False, - ) - exports.add( - obj=fs.sep.removal_frac_mass_comp[0, "tss"], - name="TSS removal", - ui_units=pyunits.dimensionless, - display_units="fraction", # we should change to % - rounding=3, - description="Total suspended solids removal to recycle [g-TSS removed/g-TSS inlet]", - is_input=True, - input_category="Separator", - is_output=False, - ) - exports.add( - obj=fs.sep.removal_frac_mass_comp[0, "cod"], - name="COD removal", - ui_units=pyunits.dimensionless, - display_units="fraction", # we should change to % - rounding=3, - description="COD removal to recycle [g-COD removed/g-COD inlet]", - is_input=True, - input_category="Separator", - is_output=False, - ) - exports.add( - obj=fs.sep.energy_electric_flow_vol_inlet, - name="Electricity intensity", - ui_units=pyunits.kWh / pyunits.m**3, - display_units="kWh/m3", - rounding=2, - description="Separator electricity intensity relating the energy to the volume of treated water", - is_input=True, - input_category="Separator", - is_output=False, - ) - - # Unit cost data, separator - uses default costing parameters - - # System costing - exports.add( - obj=fs.costing.utilization_factor, - name="Utilization factor", - ui_units=pyunits.dimensionless, - display_units="fraction", - rounding=2, - description="Utilization factor - [annual use hours/total hours in year]", - is_input=True, - input_category="System costing", - is_output=False, - ) - exports.add( - obj=fs.costing.TIC, - name="Practical investment factor", - ui_units=pyunits.dimensionless, - display_units="fraction", - rounding=1, - description="Practical investment factor - [total investment cost/direct " - "capital costs]", - is_input=True, - input_category="System costing", - is_output=False, - ) - exports.add( - obj=fs.costing.plant_lifetime, - name="Plant lifetime", - ui_units=pyunits.year, - display_units="years", - rounding=1, - description="Plant lifetime", - is_input=True, - input_category="System costing", - is_output=False, - ) - exports.add( - obj=fs.costing.wacc, - name="Discount rate", - ui_units=pyunits.dimensionless, - display_units="fraction", - rounding=2, - description="Discount rate used in calculating the capital annualization", - is_input=True, - input_category="System costing", - is_output=False, - ) - exports.add( - obj=fs.costing.maintenance_costs_percent_FCI, - name="Fixed operating cost factor", - ui_units=1 / pyunits.year, - display_units="fraction/year", - rounding=2, - description="Fixed operating cost factor - [annual fixed operating cost/total " - "investment cost]", - is_input=True, - input_category="System costing", - is_output=False, - ) - exports.add( - obj=fs.costing.electricity_cost, - name="Electricity cost", - ui_units=fs.costing.base_currency / pyunits.kWh, - display_units="$/kWh", - rounding=3, - description="Electricity cost", - is_input=True, - input_category="System costing", - is_output=False, - ) - exports.add( - obj=fs.costing.ferric_chloride_cost, - name="FeCl3 cost", - ui_units=fs.costing.base_currency / pyunits.kg, - display_units="$/kg", - rounding=3, - description="Ferric chloride cost", - is_input=True, - input_category="System costing", - is_output=False, - ) - - # Outlets - exports.add( - obj=fs.product.properties[0].flow_vol, - name="Product water flow rate", - ui_units=pyunits.m**3 / pyunits.hr, - display_units="m3/h", - rounding=2, - description="Outlet product water flow rate", - is_input=False, - is_output=True, - output_category="Outlets", - ) - exports.add( - obj=fs.product.properties[0].conc_mass_comp["tss"], - name="Product water TSS concentration", - ui_units=pyunits.mg / pyunits.L, - display_units="mg/L", - rounding=5, - description="Outlet product water total suspended solids concentration", - is_input=False, - is_output=True, - output_category="Outlets", - ) - exports.add( - obj=fs.product.properties[0].flow_mass_comp["cod"], - name="Product water COD mass flow", - ui_units=pyunits.ton / pyunits.day, - display_units="ton/day", - rounding=5, - description="Outlet product water COD mass flow", - is_input=False, - is_output=True, - output_category="Outlets", - ) - exports.add( - obj=fs.WAS_product.properties[0].flow_vol, - name="WAS flow rate", - ui_units=pyunits.m**3 / pyunits.hr, - display_units="m3/h", - rounding=2, - description="Outlet waste activated sludge flow rate", - is_input=False, - is_output=True, - output_category="Outlets", - ) - exports.add( - obj=fs.WAS_product.properties[0].conc_mass_comp["H2O"], - name="WAS H2O concentration", - ui_units=pyunits.mg / pyunits.L, - display_units="mg/L", - rounding=5, - description="Outlet waste activated sludge water concentration", - is_input=False, - is_output=True, - output_category="Outlets", - ) - exports.add( - obj=fs.WAS_product.properties[0].conc_mass_comp["tss"], - name="WAS TSS concentration", - ui_units=pyunits.mg / pyunits.L, - display_units="mg/L", - rounding=5, - description="Outlet waste activated sludge total suspended solids concentration", - is_input=False, - is_output=True, - output_category="Outlets", - ) - exports.add( - obj=fs.WAS_product.properties[0].flow_mass_comp["cod"], - name="WAS COD mass flow", - ui_units=pyunits.ton / pyunits.day, - display_units="ton/day", - rounding=5, - description="Outlet waste activated sludge COD mass flow", - is_input=False, - is_output=True, - output_category="Outlets", - ) - exports.add( - obj=fs.disposal.properties[0].flow_vol, - name="Gaseous release flow rate", - ui_units=pyunits.m**3 / pyunits.hr, - display_units="m3/h", - rounding=2, - description="Outlet gaseous release flow rate", - is_input=False, - is_output=True, - output_category="Outlets", - ) - exports.add( - obj=fs.disposal.properties[0].flow_mass_comp["carbon_dioxide"], - name="Gaseous CO2 flow rate", - ui_units=pyunits.ton / pyunits.day, - display_units="ton/day", - rounding=5, - description="Outlet gaseous carbon dioxide release mass flow", - is_input=False, - is_output=True, - output_category="Outlets", - ) - exports.add( - obj=fs.disposal.properties[0].flow_mass_comp["oxygen"], - name="Gaseous O2 flow rate", - ui_units=pyunits.ton / pyunits.day, - display_units="ton/day", - rounding=5, - description="Outlet gaseous oxygen release mass flow", - is_input=False, - is_output=True, - output_category="Outlets", - ) - - # System metrics - exports.add( - obj=fs.costing.LCOT, - name="LCOT", - ui_units=fs.costing.base_currency / pyunits.m**3, - display_units="$/m3 of feed", - rounding=3, - description="Levelized cost of treatment including operating and capital costs", - is_input=False, - is_output=True, - output_category="Levelized cost metrics", - ) - exports.add( - obj=fs.costing.LCOT_with_revenue, - name="LCOT with revenue", - ui_units=fs.costing.base_currency / pyunits.m**3, - display_units="$/m3 of feed", - rounding=3, - description="Levelized cost of treatment including consumption costs for FeCl3", - is_input=False, - is_output=True, - output_category="Levelized cost metrics", - ) - exports.add( - obj=fs.costing.LCOW, - name="LCOW", - ui_units=fs.costing.base_currency / pyunits.m**3, - display_units="$/m3 of centrate", - rounding=3, - description="Levelized cost of water including operating and capital costs", - is_input=False, - is_output=True, - output_category="Levelized cost metrics", - ) - exports.add( - obj=fs.costing.LCOW_with_revenue, - name="LCOW with revenue", - ui_units=fs.costing.base_currency / pyunits.m**3, - display_units="$/m3 of centrate", - rounding=3, - description="Levelized cost of water including consumption costs for FeCl3", - is_input=False, - is_output=True, - output_category="Levelized cost metrics", - ) - - # Normalized metrics - total_capital_norm = ( - fs.costing.total_capital_cost - + _base_curr(fs.watertap_costing.total_capital_cost) - ) / fs.feed.properties[0].flow_vol - exports.add( - obj=total_capital_norm, - name="Total capital", - ui_units=fs.costing.base_currency / (pyunits.m**3 / pyunits.day), - display_units="$/(m3/day)", - rounding=1, - description="Normalized total capital costs accounting for indirect " - "capital and installation - [total capital costs/feed flow rate]", - is_input=False, - is_output=True, - output_category="Normalized cost metrics", - ) - direct_capital_norm = ( - fs.HRCS.costing.direct_capital_cost - + fs.clarifier.costing.direct_capital_cost - + fs.sep.costing.direct_capital_cost - # In WaterTAPCosting package `capital_cost` doesn't have any adders - + _base_curr(fs.mixer.costing.capital_cost) - ) / fs.feed.properties[0].flow_vol - exports.add( - obj=direct_capital_norm, - name="Direct capital", - ui_units=fs.costing.base_currency / (pyunits.m**3 / pyunits.day), - display_units="$/(m3/day)", - rounding=1, - description="Normalized direct capital costs - [total direct capital " - "costs/feed flow rate] ", - is_input=False, - is_output=True, - output_category="Normalized cost metrics", - ) - elec_operating_norm = ( - fs.costing.aggregate_flow_costs["electricity"] / fs.costing.annual_water_inlet - ) - exports.add( - obj=elec_operating_norm, - name="Electricity", - ui_units=fs.costing.base_currency / pyunits.m**3, - display_units="$/m3 of feed", - rounding=2, - description="Normalized electricity cost - [annual electricity costs/annual " - "feed flow rate]", - is_input=False, - is_output=True, - output_category="Normalized cost metrics", - ) - - # performance metrics - recovery_vol = fs.product.properties[0].flow_vol / fs.feed.properties[0].flow_vol - exports.add( - obj=recovery_vol, - name="Volumetric recovery", - ui_units=pyunits.dimensionless, - display_units="m3 of product/m3 of feed", - rounding=3, - description="Normalized volumetric recovery", - is_input=False, - is_output=True, - output_category="Normalized performance metrics", - ) - carbon_capture = ( - 100 - * ( - fs.WAS_product.flow_mass_comp[0, "cod"] - + fs.product.flow_mass_comp[0, "cod"] - ) - / fs.feed.flow_mass_comp[0, "cod"] - ) - exports.add( - obj=carbon_capture, - name="Carbon capture", - ui_units=pyunits.dimensionless, - display_units="%", - rounding=3, - description="Normalized carbon capture (WAS captured COD + effluent biomass COD + effluent non-biomass COD", - is_input=False, - is_output=True, - output_category="Normalized performance metrics", - ) - removal_COD = ( - 1 - - fs.product.properties[0].flow_mass_comp["cod"] - / fs.feed.properties[0].flow_mass_comp["cod"] - ) - exports.add( - obj=removal_COD, - name="COD removal", - ui_units=pyunits.dimensionless, - display_units="fraction", - rounding=3, - description="COD removal fraction [1 - outlet COD flow/inlet COD flow]", - is_input=False, - is_output=True, - output_category="Normalized performance metrics", - ) - removal_TSS = ( - 1 - - fs.product.properties[0].flow_mass_comp["tss"] - / fs.feed.properties[0].flow_mass_comp["tss"] - ) - exports.add( - obj=removal_TSS, - name="TSS removal", - ui_units=pyunits.dimensionless, - display_units="fraction", - rounding=3, - description="TSS removal fraction [1 - outlet TSS flow/inlet TSS flow]", - is_input=False, - is_output=True, - output_category="Normalized performance metrics", - ) - - # Capital costs - total_capital = fs.costing.total_capital_cost + _base_curr( - fs.watertap_costing.total_capital_cost - ) - exports.add( - obj=total_capital, - name="Total", - ui_units=fs.costing.base_currency, - display_units="$", - rounding=0, - description="Total capital costs - including investment factor to account " - "for indirect capital", - is_input=False, - is_output=True, - output_category="Capital costs", - ) - exports.add( - obj=fs.HRCS.costing.capital_cost, - name="HRCS", - ui_units=fs.costing.base_currency, - display_units="$", - rounding=0, - description="HRCS", - is_input=False, - is_output=True, - output_category="Capital costs", - ) - exports.add( - obj=fs.clarifier.costing.capital_cost, - name="Clarifier", - ui_units=fs.costing.base_currency, - display_units="$", - rounding=0, - description="Clarifier", - is_input=False, - is_output=True, - output_category="Capital costs", - ) - exports.add( - obj=fs.sep.costing.capital_cost, - name="Separator", - ui_units=fs.costing.base_currency, - display_units="$", - rounding=0, - description="Separator", - is_input=False, - is_output=True, - output_category="Capital costs", - ) - exports.add( - obj=_base_curr(fs.mixer.costing.capital_cost), - name="Mixer", - ui_units=fs.costing.base_currency, - display_units="$", - rounding=0, - description="Mixer", - is_input=False, - is_output=True, - output_category="Capital costs", - ) - - # Operating costs - total_operating = ( - fs.costing.total_fixed_operating_cost - + fs.costing.total_variable_operating_cost - + pyunits.convert( - fs.watertap_costing.total_operating_cost, - to_units=fs.costing.base_currency / pyunits.year, - ) - ) - exports.add( - obj=total_operating, - name="Total", - ui_units=fs.costing.base_currency / pyunits.year, - display_units="$/year", - rounding=0, - description="Total annual operating costs - including electricity, heating, " - "and fixed", - is_input=False, - is_output=True, - output_category="Operating costs", - ) - exports.add( - obj=fs.costing.aggregate_flow_costs["electricity"], - name="Electricity", - ui_units=fs.costing.base_currency / pyunits.year, - display_units="$/year", - rounding=0, - description="Annual electricity costs ", - is_input=False, - is_output=True, - output_category="Operating costs", - ) - exports.add( - obj=fs.costing.total_fixed_operating_cost, - name="Fixed", - ui_units=fs.costing.base_currency / pyunits.year, - display_units="$/year", - rounding=0, - description="Annual fixed operating costs - these costs include material " - "replacement, maintenance, and labor", - is_input=False, - is_output=True, - output_category="Operating costs", - ) - - -def build_flowsheet(build_options=None, **kwargs): - # build and solve initial flowsheet - m = build() - - set_operating_conditions(m) - assert_degrees_of_freedom(m, 0) - assert_units_consistent(m) - - initialize_system(m) - - results = solve(m) - assert_optimal_termination(results) - - add_costing(m) - assert_degrees_of_freedom(m, 0) - m.fs.costing.initialize() - - results = solve(m) - assert_optimal_termination(results) - return m - - -def solve_flowsheet(flowsheet=None): - fs = flowsheet - results = solve(fs) - return results diff --git a/watertap/examples/flowsheets/case_studies/wastewater_resource_recovery/amo_1575_magprex/magprex_ui.png b/watertap/examples/flowsheets/case_studies/wastewater_resource_recovery/amo_1575_magprex/magprex_ui.png deleted file mode 100644 index fa43bc834d..0000000000 Binary files a/watertap/examples/flowsheets/case_studies/wastewater_resource_recovery/amo_1575_magprex/magprex_ui.png and /dev/null differ diff --git a/watertap/examples/flowsheets/case_studies/wastewater_resource_recovery/amo_1575_magprex/magprex_ui.py b/watertap/examples/flowsheets/case_studies/wastewater_resource_recovery/amo_1575_magprex/magprex_ui.py deleted file mode 100644 index 8bd73526ab..0000000000 --- a/watertap/examples/flowsheets/case_studies/wastewater_resource_recovery/amo_1575_magprex/magprex_ui.py +++ /dev/null @@ -1,722 +0,0 @@ -################################################################################# -# WaterTAP Copyright (c) 2020-2024, The Regents of the University of California, -# through Lawrence Berkeley National Laboratory, Oak Ridge National Laboratory, -# National Renewable Energy Laboratory, and National Energy Technology -# Laboratory (subject to receipt of any required approvals from the U.S. Dept. -# of Energy). All rights reserved. -# -# Please see the files COPYRIGHT.md and LICENSE.md for full copyright and license -# information, respectively. These files are also available online at the URL -# "https://github.com/watertap-org/watertap/" -################################################################################# -from watertap.ui.fsapi import FlowsheetInterface -from watertap.core.util.initialization import assert_degrees_of_freedom -from watertap.examples.flowsheets.case_studies.wastewater_resource_recovery.amo_1575_magprex.magprex import ( - build, - set_operating_conditions, - initialize_system, - solve, - add_costing, -) -from pyomo.environ import units as pyunits, assert_optimal_termination -from pyomo.util.check_units import assert_units_consistent - - -def export_to_ui(): - return FlowsheetInterface( - name="Magprex", - do_export=export_variables, - do_build=build_flowsheet, - do_solve=solve_flowsheet, - ) - - -def export_variables(flowsheet=None, exports=None, build_options=None, **kwargs): - fs = flowsheet - # --- Input data --- - # Feed conditions - exports.add( - obj=fs.feed.flow_vol[0], - name="Volumetric flow rate", - ui_units=pyunits.m**3 / pyunits.hr, - display_units="m3/h", - rounding=2, - description="Inlet volumetric flow rate", - is_input=True, - input_category="Feed", - is_output=True, - output_category="Feed", - ) - exports.add( - obj=fs.feed.conc_mass_comp[0, "phosphates"], - name="OP concentration", - ui_units=pyunits.g / pyunits.L, - display_units="g/L", - rounding=2, - description="Inlet orthophosphate concentration", - is_input=True, - input_category="Feed", - is_output=True, - output_category="Feed", - ) - exports.add( - obj=fs.feed.conc_mass_comp[0, "struvite"], - name="Struvite concentration", - ui_units=pyunits.g / pyunits.L, - display_units="g/L", - rounding=2, - description="Inlet struvite concentration", - is_input=True, - input_category="Feed", - is_output=True, - output_category="Feed", - ) - - # Unit model data, Magprex reactor - exports.add( - obj=fs.magprex.recovery_frac_mass_H2O[0], - name="Water recovery", - ui_units=pyunits.dimensionless, - display_units="fraction", # we should change to % - rounding=2, - description="Water recovery [g-H2O treated/g-H2O inlet]", - is_input=True, - input_category="Magprex reactor", - is_output=False, - ) - exports.add( - obj=fs.magprex.reaction_conversion[0, "struvite_precip"], - name="OP conversion", - ui_units=pyunits.dimensionless, - display_units="fraction", # we should change to % - rounding=2, - description="Orthophosphate conversion [g-OP reacted/g-OP inlet]", - is_input=True, - input_category="Magprex reactor", - is_output=False, - ) - exports.add( - obj=fs.magprex.energy_electric_flow_vol_inlet, - name="Aeration energy", - ui_units=pyunits.kWh / pyunits.m**3, - display_units="kWh/m3", - rounding=2, - description="Specific aeration energy relating the energy to the volume of feed", - is_input=True, - input_category="Magprex reactor", - is_output=False, - ) - exports.add( - obj=fs.magprex.magnesium_chloride_dosage, - name="MgCl2 Dosage", - ui_units=pyunits.dimensionless, - display_units="kg MgCl2/kg phosphates", - rounding=2, - description="MgCl2 Dosage per kg of influent phosphates", - is_input=True, - input_category="Magprex reactor", - is_output=False, - ) - - # Unit cost data, Magprex reactor - exports.add( - obj=fs.costing.magprex.HRT[None], - name="HRT", - ui_units=pyunits.hr, - display_units="h", - rounding=1, - description="Hydraulic retention time", - is_input=True, - input_category="Magprex reactor costing", - is_output=False, - ) - exports.add( - obj=fs.costing.magprex.sizing_cost[None], - name="Magprex reactor cost", - ui_units=fs.costing.base_currency / pyunits.m**3, - display_units="$/m3 of reactor", - rounding=0, - description="Magprex reactor capital cost parameter", - is_input=True, - input_category="Magprex reactor costing", - is_output=False, - ) - - # Unit model data, centrifuge - exports.add( - obj=fs.centrifuge.recovery_frac_mass_H2O[0], - name="Water recovery", - ui_units=pyunits.dimensionless, - display_units="fraction", # we should change to % - rounding=2, - description="Water recovery [g-H2O treated/g-H2O inlet]", - is_input=True, - input_category="Centrifuge", - is_output=False, - ) - exports.add( - obj=fs.centrifuge.removal_frac_mass_comp[0, "phosphates"], - name="OP removal", - ui_units=pyunits.dimensionless, - display_units="fraction", # we should change to % - rounding=2, - description="Orthophosphate removal [g-OP removed/g-OP inlet]", - is_input=True, - input_category="Centrifuge", - is_output=False, - ) - exports.add( - obj=fs.centrifuge.energy_electric_flow_vol_inlet, - name="Specific power", - ui_units=pyunits.kWh / pyunits.m**3, - display_units="kWh/m3", - rounding=2, - description="Centrifuge specific power relating the power to the volume of feed", - is_input=True, - input_category="Centrifuge", - is_output=False, - ) - exports.add( - obj=fs.centrifuge.polymer_dose[0], - name="Polymer Dosage", - ui_units=pyunits.mg / pyunits.L, - display_units="mg/L", - rounding=2, - description="Polymer Dosage per liter of sludge treated", - is_input=True, - input_category="Centrifuge", - is_output=False, - ) - - # Unit cost data, centrifuge - exports.add( - obj=fs.costing.centrifuge.HRT[None], - name="HRT", - ui_units=pyunits.hr, - display_units="h", - rounding=1, - description="Hydraulic retention time", - is_input=True, - input_category="Centrifuge costing", - is_output=False, - ) - exports.add( - obj=fs.costing.centrifuge.sizing_cost[None], - name="Centrifuge cost", - ui_units=fs.costing.base_currency / pyunits.m**3, - display_units="$/m3 of centrifuge", - rounding=0, - description="Centrifuge capital cost parameter", - is_input=True, - input_category="Centrifuge costing", - is_output=False, - ) - - # Unit model data, struvite classifier - exports.add( - obj=fs.classifier.energy_electric_flow_vol_inlet, - name="Specific power", - ui_units=pyunits.kWh / pyunits.m**3, - display_units="kWh/m3", - rounding=2, - description="Classifier specific power relating the power to the volume of feed", - is_input=True, - input_category="Classifier", - is_output=False, - ) - - # Unit cost data, struvite classifier - exports.add( - obj=fs.costing.struvite_classifier.HRT[None], - name="HRT", - ui_units=pyunits.hr, - display_units="h", - rounding=1, - description="Hydraulic retention time", - is_input=True, - input_category="Classifier costing", - is_output=False, - ) - exports.add( - obj=fs.costing.struvite_classifier.sizing_cost[None], - name="Classifier cost", - ui_units=fs.costing.base_currency / pyunits.m**3, - display_units="$/m3 of classifier", - rounding=0, - description="Classifier capital cost parameter", - is_input=True, - input_category="Classifier costing", - is_output=False, - ) - - # System costing - exports.add( - obj=fs.costing.utilization_factor, - name="Utilization factor", - ui_units=pyunits.dimensionless, - display_units="fraction", - rounding=2, - description="Utilization factor - [annual use hours/total hours in year]", - is_input=True, - input_category="System costing", - is_output=False, - ) - exports.add( - obj=fs.costing.TIC, - name="Practical investment factor", - ui_units=pyunits.dimensionless, - display_units="fraction", - rounding=1, - description="Practical investment factor - [total investment cost/direct " - "capital costs]", - is_input=True, - input_category="System costing", - is_output=False, - ) - exports.add( - obj=fs.costing.plant_lifetime, - name="Plant lifetime", - ui_units=pyunits.year, - display_units="years", - rounding=1, - description="Plant lifetime", - is_input=True, - input_category="System costing", - is_output=False, - ) - exports.add( - obj=fs.costing.wacc, - name="Discount rate", - ui_units=pyunits.dimensionless, - display_units="fraction", - rounding=2, - description="Discount rate used in calculating the capital annualization", - is_input=True, - input_category="System costing", - is_output=False, - ) - exports.add( - obj=fs.costing.maintenance_costs_percent_FCI, - name="Fixed operating cost factor", - ui_units=1 / pyunits.year, - display_units="fraction/year", - rounding=2, - description="Fixed operating cost factor - [annual fixed operating cost/total " - "investment cost]", - is_input=True, - input_category="System costing", - is_output=False, - ) - exports.add( - obj=fs.costing.electricity_cost, - name="Electricity cost", - ui_units=fs.costing.base_currency / pyunits.kWh, - display_units="$/kWh", - rounding=3, - description="Electricity cost", - is_input=True, - input_category="System costing", - is_output=False, - ) - exports.add( - obj=fs.costing.magnesium_chloride_cost, - name="MgCl2 cost", - ui_units=fs.costing.base_currency / pyunits.kg, - display_units="$/kg", - rounding=3, - description="Magnesium chloride cost", - is_input=True, - input_category="System costing", - is_output=False, - ) - exports.add( - obj=fs.costing.polymer_cost, - name="Polymer cost", - ui_units=fs.costing.base_currency / pyunits.kg, - display_units="$/kg", - rounding=3, - description="Dry Polymer cost", - is_input=True, - input_category="System costing", - is_output=False, - ) - exports.add( - obj=fs.costing.struvite_product_cost, - name="Struvite cost", - ui_units=fs.costing.base_currency / pyunits.kg, - display_units="$/kg", - rounding=3, - description="Struvite cost is negative because it is sold", - is_input=True, - input_category="System costing", - is_output=False, - ) - - # Outlets - exports.add( - obj=fs.centrate.properties[0].flow_vol, - name="Centrate flow rate", - ui_units=pyunits.m**3 / pyunits.hr, - display_units="m3/h", - rounding=2, - description="Outlet centrate flow rate", - is_input=False, - is_output=True, - output_category="Outlets", - ) - exports.add( - obj=fs.centrate.properties[0].conc_mass_comp["phosphates"], - name="Centrate OP concentration", - ui_units=pyunits.g / pyunits.L, - display_units="g/L", - rounding=5, - description="Outlet centrate orthophosphate concentration", - is_input=False, - is_output=True, - output_category="Outlets", - ) - exports.add( - obj=fs.centrate.properties[0].conc_mass_comp["H2O"], - name="Centrate H2O concentration", - ui_units=pyunits.g / pyunits.L, - display_units="g/L", - rounding=2, - description="Outlet product water concentration", - is_input=False, - is_output=True, - output_category="Outlets", - ) - exports.add( - obj=fs.biosolid_product.properties[0].flow_mass_comp["phosphates"], - name="Biosolid product flow rate", - ui_units=pyunits.kg / pyunits.hr, - display_units="kg-OP/h", - rounding=5, - description="Outlet orthophosphate biosolid product flow rate", - is_input=False, - is_output=True, - output_category="Outlets", - ) - exports.add( - obj=fs.struvite_product.properties[0].flow_mass_comp["struvite"], - name="Struvite product flow rate", - ui_units=pyunits.kg / pyunits.hr, - display_units="kg-struvite/h", - rounding=3, - description="Outlet struvite product flow rate", - is_input=False, - is_output=True, - output_category="Outlets", - ) - - # System metrics - exports.add( - obj=fs.costing.LCOT, - name="LCOT", - ui_units=fs.costing.base_currency / pyunits.m**3, - display_units="$/m3 of feed", - rounding=3, - description="Levelized cost of treatment including operating and capital costs", - is_input=False, - is_output=True, - output_category="Levelized cost metrics", - ) - exports.add( - obj=fs.costing.LCOT_with_revenue, - name="LCOT with revenue", - ui_units=fs.costing.base_currency / pyunits.m**3, - display_units="$/m3 of feed", - rounding=3, - description="Levelized cost of treatment including revenue of struvite and consumption costs for MgCl2 and polymer", - is_input=False, - is_output=True, - output_category="Levelized cost metrics", - ) - exports.add( - obj=fs.costing.LCOW, - name="LCOW", - ui_units=fs.costing.base_currency / pyunits.m**3, - display_units="$/m3 of centrate", - rounding=3, - description="Levelized cost of water including operating and capital costs", - is_input=False, - is_output=True, - output_category="Levelized cost metrics", - ) - exports.add( - obj=fs.costing.LCOW_with_revenue, - name="LCOW with revenue", - ui_units=fs.costing.base_currency / pyunits.m**3, - display_units="$/m3 of centrate", - rounding=3, - description="Levelized cost of water including revenue of struvite and consumption costs for MgCl2 and polymer", - is_input=False, - is_output=True, - output_category="Levelized cost metrics", - ) - exports.add( - obj=fs.costing.LCOS, - name="Levelized cost of struvite", - ui_units=fs.costing.base_currency / pyunits.kg, - display_units="$/kg-struvite", - rounding=3, - description="Levelized cost of struvite including operating and capital costs", - is_input=False, - is_output=True, - output_category="Levelized cost metrics", - ) - # Normalized metrics - total_capital_norm = fs.costing.total_capital_cost / fs.feed.properties[0].flow_vol - exports.add( - obj=total_capital_norm, - name="Total capital", - ui_units=fs.costing.base_currency / (pyunits.m**3 / pyunits.day), - display_units="$/(m3/day)", - rounding=1, - description="Normalized total capital costs accounting for indirect " - "capital and installation - [total capital costs/feed flow rate]", - is_input=False, - is_output=True, - output_category="Normalized cost metrics", - ) - direct_capital_norm = ( - fs.magprex.costing.direct_capital_cost - + fs.centrifuge.costing.direct_capital_cost - + fs.classifier.costing.direct_capital_cost - ) / fs.feed.properties[0].flow_vol - exports.add( - obj=direct_capital_norm, - name="Direct capital", - ui_units=fs.costing.base_currency / (pyunits.m**3 / pyunits.day), - display_units="$/(m3/day)", - rounding=1, - description="Normalized direct capital costs - [total direct capital " - "costs/feed flow rate] ", - is_input=False, - is_output=True, - output_category="Normalized cost metrics", - ) - elec_operating_norm = ( - fs.costing.aggregate_flow_costs["electricity"] / fs.costing.annual_water_inlet - ) - exports.add( - obj=elec_operating_norm, - name="Electricity", - ui_units=fs.costing.base_currency / pyunits.m**3, - display_units="$/m3 of feed", - rounding=2, - description="Normalized electricity cost - [annual electricity costs/annual " - "feed flow rate]", - is_input=False, - is_output=True, - output_category="Normalized cost metrics", - ) - - # performance metrics - recovery_vol = fs.centrate.properties[0].flow_vol / fs.feed.properties[0].flow_vol - exports.add( - obj=recovery_vol, - name="Volumetric recovery", - ui_units=pyunits.dimensionless, - display_units="m3 of product/m3 of feed", - rounding=3, - description="Normalized volumetric recovery", - is_input=False, - is_output=True, - output_category="Normalized performance metrics", - ) - removal_OP = ( - 1 - - fs.centrate.properties[0].flow_mass_comp["phosphates"] - / fs.feed.properties[0].flow_mass_comp["phosphates"] - ) - exports.add( - obj=removal_OP, - name="OP removal", - ui_units=pyunits.dimensionless, - display_units="fraction", - rounding=3, - description="Orthophosphate removal fraction [1 - outlet OP flow/inlet OP flow]", - is_input=False, - is_output=True, - output_category="Normalized performance metrics", - ) - struvite_production = ( - fs.struvite_product.properties[0].flow_mass_comp["struvite"] - / fs.feed.properties[0].flow_vol - ) - exports.add( - obj=struvite_production, - name="Struvite production", - ui_units=pyunits.kg / pyunits.m**3, - display_units="kg-struvite/m3 of feed", - rounding=3, - description="Struvite production [Struvite product flow rate/feed flow rate]", - is_input=False, - is_output=True, - output_category="Normalized performance metrics", - ) - - # Capital costs - exports.add( - obj=fs.costing.total_capital_cost, - name="Total", - ui_units=fs.costing.base_currency, - display_units="$", - rounding=0, - description="Total capital costs - including investment factor to account " - "for indirect capital", - is_input=False, - is_output=True, - output_category="Capital costs", - ) - exports.add( - obj=fs.magprex.costing.capital_cost, - name="Magprex reactor", - ui_units=fs.costing.base_currency, - display_units="$", - rounding=0, - description="Magprex reactor", - is_input=False, - is_output=True, - output_category="Capital costs", - ) - exports.add( - obj=fs.centrifuge.costing.capital_cost, - name="Centrifuge", - ui_units=fs.costing.base_currency, - display_units="$", - rounding=0, - description="Centrifuge", - is_input=False, - is_output=True, - output_category="Capital costs", - ) - exports.add( - obj=fs.classifier.costing.capital_cost, - name="Classifier", - ui_units=fs.costing.base_currency, - display_units="$", - rounding=0, - description="Classifier", - is_input=False, - is_output=True, - output_category="Capital costs", - ) - - # Operating costs - exports.add( - obj=fs.costing.total_operating_cost, - name="Total", - ui_units=fs.costing.base_currency / pyunits.year, - display_units="$/year", - rounding=0, - description="Total annual operating costs - including electricity, heating, " - "and fixed", - is_input=False, - is_output=True, - output_category="Operating costs", - ) - exports.add( - obj=fs.costing.aggregate_flow_costs["electricity"], - name="Electricity", - ui_units=fs.costing.base_currency / pyunits.year, - display_units="$/year", - rounding=0, - description="Annual electricity costs ", - is_input=False, - is_output=True, - output_category="Operating costs", - ) - exports.add( - obj=fs.costing.total_fixed_operating_cost, - name="Fixed", - ui_units=fs.costing.base_currency / pyunits.year, - display_units="$/year", - rounding=0, - description="Annual fixed operating costs - these costs include material " - "replacement, maintenance, and labor", - is_input=False, - is_output=True, - output_category="Operating costs", - ) - - # Revenue - total_revenue = -( - fs.costing.aggregate_flow_costs["struvite_product"] - + fs.costing.aggregate_flow_costs["magnesium_chloride"] - + fs.costing.aggregate_flow_costs["polymer"] - ) - exports.add( - obj=total_revenue, - name="Net", - ui_units=fs.costing.base_currency / pyunits.year, - display_units="$/year", - rounding=0, - description="Net revenue - including the sale of struvite and purchase of MgCl2 and dry polymer", - is_input=False, - is_output=True, - output_category="Revenue", - ) - - exports.add( - obj=-fs.costing.aggregate_flow_costs["struvite_product"], - name="Struvite", - ui_units=fs.costing.base_currency / pyunits.year, - display_units="$/year", - rounding=0, - description="Revenue from selling struvite", - is_input=False, - is_output=True, - output_category="Revenue", - ) - exports.add( - obj=-fs.costing.aggregate_flow_costs["magnesium_chloride"], - name="Magnesium chloride", - ui_units=fs.costing.base_currency / pyunits.year, - display_units="$/year", - rounding=0, - description="Cost from buying magnesium chloride", - is_input=False, - is_output=True, - output_category="Revenue", - ) - exports.add( - obj=-fs.costing.aggregate_flow_costs["polymer"], - name="Polymer", - ui_units=fs.costing.base_currency / pyunits.year, - display_units="$/year", - rounding=0, - description="Cost from buying polymer", - is_input=False, - is_output=True, - output_category="Revenue", - ) - - -def build_flowsheet(build_options=None, **kwargs): - # build and solve initial flowsheet - m = build() - - set_operating_conditions(m) - assert_degrees_of_freedom(m, 0) - assert_units_consistent(m) - - initialize_system(m) - - results = solve(m) - assert_optimal_termination(results) - - add_costing(m) - assert_degrees_of_freedom(m, 0) - m.fs.costing.initialize() - - results = solve(m) - assert_optimal_termination(results) - return m - - -def solve_flowsheet(flowsheet=None): - fs = flowsheet - results = solve(fs) - return results diff --git a/watertap/examples/flowsheets/case_studies/wastewater_resource_recovery/amo_1595_photothermal_membrane_candoP/amo_1595_ui.png b/watertap/examples/flowsheets/case_studies/wastewater_resource_recovery/amo_1595_photothermal_membrane_candoP/amo_1595_ui.png deleted file mode 100644 index db8f04b04c..0000000000 Binary files a/watertap/examples/flowsheets/case_studies/wastewater_resource_recovery/amo_1595_photothermal_membrane_candoP/amo_1595_ui.png and /dev/null differ diff --git a/watertap/examples/flowsheets/case_studies/wastewater_resource_recovery/amo_1595_photothermal_membrane_candoP/amo_1595_ui.py b/watertap/examples/flowsheets/case_studies/wastewater_resource_recovery/amo_1595_photothermal_membrane_candoP/amo_1595_ui.py deleted file mode 100644 index 2da59ca579..0000000000 --- a/watertap/examples/flowsheets/case_studies/wastewater_resource_recovery/amo_1595_photothermal_membrane_candoP/amo_1595_ui.py +++ /dev/null @@ -1,835 +0,0 @@ -################################################################################# -# WaterTAP Copyright (c) 2020-2024, The Regents of the University of California, -# through Lawrence Berkeley National Laboratory, Oak Ridge National Laboratory, -# National Renewable Energy Laboratory, and National Energy Technology -# Laboratory (subject to receipt of any required approvals from the U.S. Dept. -# of Energy). All rights reserved. -# -# Please see the files COPYRIGHT.md and LICENSE.md for full copyright and license -# information, respectively. These files are also available online at the URL -# "https://github.com/watertap-org/watertap/" -################################################################################# -from watertap.ui.fsapi import FlowsheetInterface -from watertap.core.util.initialization import assert_degrees_of_freedom -from watertap.examples.flowsheets.case_studies.wastewater_resource_recovery.amo_1595_photothermal_membrane_candoP.amo_1595 import ( - build, - set_operating_conditions, - initialize_system, - solve, - add_costing, -) -from pyomo.environ import units as pyunits, assert_optimal_termination -from pyomo.util.check_units import assert_units_consistent - - -def export_to_ui(): - return FlowsheetInterface( - name="Photothermal Membrane CANDO_P", - do_export=export_variables, - do_build=build_flowsheet, - do_solve=solve_flowsheet, - ) - - -def export_variables(flowsheet=None, exports=None, build_options=None, **kwargs): - fs = flowsheet - # --- Input data --- - # Feed conditions - exports.add( - obj=fs.feed.flow_vol[0], - name="Volumetric flow rate", - ui_units=pyunits.m**3 / pyunits.hr, - display_units="m3/h", - rounding=3, - description="Inlet volumetric flow rate", - is_input=True, - input_category="Feed", - is_output=True, - output_category="Feed", - ) - exports.add( - obj=fs.feed.conc_mass_comp[0, "nitrogen"], - name="Nitrogen concentration", - ui_units=pyunits.g / pyunits.L, - display_units="g/L", - rounding=3, - description="Inlet nitrogen concentration", - is_input=True, - input_category="Feed", - is_output=True, - output_category="Feed", - ) - exports.add( - obj=fs.feed.conc_mass_comp[0, "phosphates"], - name="Phosphates concentration", - ui_units=pyunits.g / pyunits.L, - display_units="g/L", - rounding=3, - description="Inlet phosphates concentration", - is_input=True, - input_category="Feed", - is_output=True, - output_category="Feed", - ) - exports.add( - obj=fs.feed.conc_mass_comp[0, "bioconcentrated_phosphorous"], - name="Bioconcentrated phosphorous concentration", - ui_units=pyunits.g / pyunits.L, - display_units="g/L", - rounding=3, - description="Inlet bioconcentrated phosphorous concentration", - is_input=True, - input_category="Feed", - is_output=True, - output_category="Feed", - ) - exports.add( - obj=fs.feed.conc_mass_comp[0, "nitrous_oxide"], - name="Nitrous oxide concentration", - ui_units=pyunits.g / pyunits.L, - display_units="g/L", - rounding=2, - description="Inlet nitrous oxide concentration", - is_input=True, - input_category="Feed", - is_output=True, - output_category="Feed", - ) - - # Unit model data, pump - exports.add( - obj=fs.pump.lift_height, - name="Lift height", - ui_units=pyunits.m, - display_units="m", - rounding=2, - description="Lift height for pump", - is_input=True, - input_category="Pump", - is_output=False, - ) - exports.add( - obj=fs.pump.eta_pump, - name="Pump efficiency", - ui_units=pyunits.dimensionless, - display_units="fraction", - rounding=2, - description="Efficiency of pump", - is_input=True, - input_category="Pump", - is_output=False, - ) - exports.add( - obj=fs.pump.eta_motor, - name="Motor efficiency", - ui_units=pyunits.dimensionless, - display_units="fraction", - rounding=2, - description="Efficiency of motor", - is_input=True, - input_category="Pump", - is_output=False, - ) - - # Unit cost data, pump - exports.add( - obj=fs.costing.pump_electricity.pump_cost[None], - name="Pump cost", - ui_units=fs.costing.base_currency / (pyunits.m**3 / pyunits.hr), - display_units="$/(m^3/hr)", - rounding=0, - description="Pump capital cost parameter", - is_input=True, - input_category="Pump costing", - is_output=False, - ) - - # Unit model data, photothermal membrane - exports.add( - obj=fs.photothermal.recovery_frac_mass_H2O[0], - name="Water recovery", - ui_units=pyunits.dimensionless, - display_units="fraction", # we should change to % - rounding=2, - description="Water recovery [g-H2O treated/g-H2O inlet]", - is_input=True, - input_category="Photothermal membrane", - is_output=False, - ) - exports.add( - obj=fs.photothermal.removal_frac_mass_comp[0, "phosphates"], - name="Phosphates removal", - ui_units=pyunits.dimensionless, - display_units="fraction", # we should change to % - rounding=2, - description="Phosphates removal [g-P removed/g-P inlet]", - is_input=True, - input_category="Photothermal membrane", - is_output=False, - ) - exports.add( - obj=fs.photothermal.removal_frac_mass_comp[0, "nitrogen"], - name="Nitrogen removal", - ui_units=pyunits.dimensionless, - display_units="fraction", # we should change to % - rounding=2, - description="Nitrogen removal [g-N2 removed/g-N2 inlet]", - is_input=True, - input_category="Photothermal membrane", - is_output=False, - ) - exports.add( - obj=fs.photothermal.water_flux, - name="Water flux", - ui_units=pyunits.kg / pyunits.m**2 / pyunits.hr, - display_units="kg/(m2/h)", - rounding=2, - description="Water flux through membrane", - is_input=True, - input_category="Photothermal membrane", - is_output=False, - ) - # Unit cost data, photothermal membrane - exports.add( - obj=fs.costing.photothermal_membrane.membrane_cost[None], - name="Membrane", - ui_units=fs.costing.base_currency / pyunits.m**2, - display_units="$/m2 of photothermal membrane", - rounding=0, - description="Membrane cost", - is_input=True, - input_category="Photothermal membrane costing", - is_output=False, - ) - - # Unit model data, CANDO+P reactor - exports.add( - obj=fs.candop.recovery_frac_mass_H2O[0], - name="Water recovery", - ui_units=pyunits.dimensionless, - display_units="fraction", # we should change to % - rounding=2, - description="Water recovery [g-H2O treated/g-H2O inlet]", - is_input=True, - input_category="CANDO+P reactor", - is_output=False, - ) - exports.add( - obj=fs.candop.reaction_conversion[0, "n_reaction"], - name="Nitrogen conversion", - ui_units=pyunits.dimensionless, - display_units="fraction", # we should change to % - rounding=2, - description="Nitrogen conversion [g-N2 reacted/g-N2 inlet]", - is_input=True, - input_category="CANDO+P reactor", - is_output=False, - ) - exports.add( - obj=fs.candop.reaction_conversion[0, "p_reaction"], - name="Phosphorus conversion", - ui_units=pyunits.dimensionless, - display_units="fraction", # we should change to % - rounding=2, - description="Phosphorus conversion [g-P reacted/g-P inlet]", - is_input=True, - input_category="CANDO+P reactor", - is_output=False, - ) - exports.add( - obj=fs.candop.electricity_intensity_N, - name="Specific energy", - ui_units=pyunits.kWh / pyunits.kg, - display_units="kWh/kg", - rounding=2, - description="Specific energy relating the energy to the mass of product", - is_input=True, - input_category="CANDO+P reactor", - is_output=False, - ) - exports.add( - obj=fs.candop.oxygen_nitrogen_ratio, - name="O2:N2 ratio", - ui_units=pyunits.dimensionless, - display_units="fraction", - rounding=2, - description="Oxygen:Nitrogen ratio", - is_input=True, - input_category="CANDO+P reactor", - is_output=False, - ) - # Unit cost data, CANDO+P reactor - exports.add( - obj=fs.costing.CANDO_P.sizing_parameter[None], - name="HRT", - ui_units=pyunits.hr, - display_units="h", - rounding=1, - description="Hydraulic retention time", - is_input=True, - input_category="CANDO+P reactor costing", - is_output=False, - ) - exports.add( - obj=fs.costing.CANDO_P.sizing_cost[None], - name="CANDO+P reactor cost", - ui_units=fs.costing.base_currency / pyunits.m**3, - display_units="$/m3 of reactor", - rounding=0, - description="CANDO+P reactor capital cost parameter", - is_input=True, - input_category="CANDO+P reactor costing", - is_output=False, - ) - # System costing - exports.add( - obj=fs.costing.utilization_factor, - name="Utilization factor", - ui_units=pyunits.dimensionless, - display_units="fraction", - rounding=2, - description="Utilization factor - [annual use hours/total hours in year]", - is_input=True, - input_category="System costing", - is_output=False, - ) - exports.add( - obj=fs.costing.TIC, - name="Practical investment factor", - ui_units=pyunits.dimensionless, - display_units="fraction", - rounding=1, - description="Practical investment factor - [total investment cost/direct " - "capital costs]", - is_input=True, - input_category="System costing", - is_output=False, - ) - exports.add( - obj=fs.costing.plant_lifetime, - name="Plant lifetime", - ui_units=pyunits.year, - display_units="years", - rounding=1, - description="Plant lifetime", - is_input=True, - input_category="System costing", - is_output=False, - ) - exports.add( - obj=fs.costing.wacc, - name="Discount rate", - ui_units=pyunits.dimensionless, - display_units="fraction", - rounding=2, - description="Discount rate used in calculating the capital annualization", - is_input=True, - input_category="System costing", - is_output=False, - ) - exports.add( - obj=fs.costing.maintenance_costs_percent_FCI, - name="Fixed operating cost factor", - ui_units=1 / pyunits.year, - display_units="fraction/year", - rounding=2, - description="Fixed operating cost factor - [annual fixed operating cost/total " - "investment cost]", - is_input=True, - input_category="System costing", - is_output=False, - ) - exports.add( - obj=fs.costing.electricity_cost, - name="Electricity cost", - ui_units=fs.costing.base_currency / pyunits.kWh, - display_units="$/kWh", - rounding=3, - description="Electricity cost", - is_input=True, - input_category="System costing", - is_output=False, - ) - exports.add( - obj=fs.costing.bcp_cost, - name="Bioconcentrated phosphorous cost", - ui_units=fs.costing.base_currency / pyunits.kg, - display_units="$/kg", - rounding=3, - description="Bioconcentrated phosphorous cost", - is_input=True, - input_category="System costing", - is_output=False, - ) - exports.add( - obj=fs.costing.water_cost, - name="Water cost", - ui_units=fs.costing.base_currency / pyunits.m**3, - display_units="$/m3", - rounding=13, - description="Water cost", - is_input=True, - input_category="System costing", - is_output=False, - ) - exports.add( - obj=fs.costing.nitrous_oxide_cost, - name="Nitrous oxide cost", - ui_units=fs.costing.base_currency / pyunits.kg, - display_units="$/kg", - rounding=3, - description="Nitrous oxide cost", - is_input=True, - input_category="System costing", - is_output=False, - ) - - # Outlets - exports.add( - obj=fs.photothermal_water.properties[0].flow_vol, - name="Photothermal membrane product water flow rate", - ui_units=pyunits.m**3 / pyunits.hr, - display_units="m3/h", - rounding=2, - description="Photothermal membrane outlet water flow rate", - is_input=False, - is_output=True, - output_category="Outlets", - ) - exports.add( - obj=fs.candop_byproduct.properties[0].flow_mass_comp["nitrous_oxide"], - name="CANDO_P N2O byproduct flow rate", - ui_units=pyunits.kg / pyunits.hr, - display_units="kg-N2O/h", - rounding=5, - description="CANDO+P outlet nitrous oxide byproduct flow rate", - is_input=False, - is_output=True, - output_category="Outlets", - ) - exports.add( - obj=fs.candop_treated.properties[0].flow_vol, - name="CANDO+P product flow rate", - ui_units=pyunits.m**3 / pyunits.hr, - display_units="m3/h", - rounding=2, - description="CANDO+P outlet product flow rate", - is_input=False, - is_output=True, - output_category="Outlets", - ) - exports.add( - obj=fs.candop_treated.properties[0].conc_mass_comp["H2O"], - name="CANDO+P product H2O concentration", - ui_units=pyunits.g / pyunits.L, - display_units="g/L", - rounding=2, - description="Outlet product water concentration", - is_input=False, - is_output=True, - output_category="Outlets", - ) - exports.add( - obj=fs.candop_treated.properties[0].conc_mass_comp["nitrogen"], - name="CANDO+P product N2 concentration", - ui_units=pyunits.g / pyunits.L, - display_units="g/L", - rounding=2, - description="Outlet product nitrogen concentration", - is_input=False, - is_output=True, - output_category="Outlets", - ) - exports.add( - obj=fs.candop_treated.properties[0].conc_mass_comp["phosphates"], - name="CANDO+P product phosphates concentration", - ui_units=pyunits.g / pyunits.L, - display_units="g/L", - rounding=2, - description="Outlet product phosphates concentration", - is_input=False, - is_output=True, - output_category="Outlets", - ) - exports.add( - obj=fs.candop_treated.properties[0].conc_mass_comp[ - "bioconcentrated_phosphorous" - ], - name="CANDO+P product BCP concentration", - ui_units=pyunits.g / pyunits.L, - display_units="g/L", - rounding=2, - description="Outlet product bioconcentrated_phosphorous concentration", - is_input=False, - is_output=True, - output_category="Outlets", - ) - - # System metrics - exports.add( - obj=fs.costing.LCOT, - name="LCOT", - ui_units=fs.costing.base_currency / pyunits.m**3, - display_units="$/m3 of feed", - rounding=3, - description="Levelized cost of treatment including operating and capital costs", - is_input=False, - is_output=True, - output_category="Levelized cost metrics", - ) - exports.add( - obj=fs.costing.LCOT_with_revenue, - name="LCOT with revenue", - ui_units=fs.costing.base_currency / pyunits.m**3, - display_units="$/m3 of feed", - rounding=3, - description="Levelized cost of treatment including revenue of bcp recovery, N2O byproduct and treated water ", - is_input=False, - is_output=True, - output_category="Levelized cost metrics", - ) - exports.add( - obj=fs.costing.LCOW, - name="LCOW", - ui_units=fs.costing.base_currency / pyunits.m**3, - display_units="$/m3 of photothermal membrane water", - rounding=3, - description="Levelized cost of water including operating and capital costs", - is_input=False, - is_output=True, - output_category="Levelized cost metrics", - ) - exports.add( - obj=fs.costing.LCOW_with_revenue, - name="LCOW with revenue", - ui_units=fs.costing.base_currency / pyunits.m**3, - display_units="$/m3 of photothermal membrane water", - rounding=3, - description="Levelized cost of water including revenue of revenue of BCP recovery and N2O byproduct", - is_input=False, - is_output=True, - output_category="Levelized cost metrics", - ) - exports.add( - obj=fs.costing.LC_BCP, - name="Levelized cost of BCP", - ui_units=fs.costing.base_currency / pyunits.kg, - display_units="$/kg-BCP", - rounding=3, - description="Levelized cost of bioconcentrated phosphorous including operating and capital costs", - is_input=False, - is_output=True, - output_category="Levelized cost metrics", - ) - exports.add( - obj=fs.costing.LC_N2O, - name="Levelized cost of nitrous oxide", - ui_units=fs.costing.base_currency / pyunits.kg, - display_units="$/kg-nitrous oxide", - rounding=3, - description="Levelized cost of nitrous oxide including operating and capital costs", - is_input=False, - is_output=True, - output_category="Levelized cost metrics", - ) - # Normalized metrics - total_capital_norm = fs.costing.total_capital_cost / fs.feed.properties[0].flow_vol - exports.add( - obj=total_capital_norm, - name="Total capital", - ui_units=fs.costing.base_currency / (pyunits.m**3 / pyunits.day), - display_units="$/(m3/day)", - rounding=1, - description="Normalized total capital costs accounting for indirect " - "capital and installation - [total capital costs/feed flow rate]", - is_input=False, - is_output=True, - output_category="Normalized cost metrics", - ) - direct_capital_norm = ( - fs.pump.costing.direct_capital_cost - + fs.photothermal.costing.direct_capital_cost - + fs.candop.costing.direct_capital_cost - ) / fs.feed.properties[0].flow_vol - exports.add( - obj=direct_capital_norm, - name="Direct capital", - ui_units=fs.costing.base_currency / (pyunits.m**3 / pyunits.day), - display_units="$/(m3/day)", - rounding=1, - description="Normalized direct capital costs - [total direct capital " - "costs/feed flow rate] ", - is_input=False, - is_output=True, - output_category="Normalized cost metrics", - ) - elec_operating_norm = ( - fs.costing.aggregate_flow_costs["electricity"] / fs.costing.annual_water_inlet - ) - exports.add( - obj=elec_operating_norm, - name="Electricity", - ui_units=fs.costing.base_currency / pyunits.m**3, - display_units="$/m3 of feed", - rounding=2, - description="Normalized electricity cost - [annual electricity costs/annual " - "feed flow rate]", - is_input=False, - is_output=True, - output_category="Normalized cost metrics", - ) - - # performance metrics - recovery_vol = ( - fs.candop_treated.properties[0].flow_vol / fs.feed.properties[0].flow_vol - ) - exports.add( - obj=recovery_vol, - name="Volumetric recovery", - ui_units=pyunits.dimensionless, - display_units="m3 of product/m3 of feed", - rounding=3, - description="Normalized volumetric recovery", - is_input=False, - is_output=True, - output_category="Normalized performance metrics", - ) - removal_H2O = ( - 1 - - fs.candop_treated.properties[0].flow_mass_comp["H2O"] - / fs.feed.properties[0].flow_mass_comp["H2O"] - ) - exports.add( - obj=removal_H2O, - name="H2O removal", - ui_units=pyunits.dimensionless, - display_units="fraction", - rounding=3, - description="Water removal fraction [1 - outlet H2O flow/inlet H2O flow]", - is_input=False, - is_output=True, - output_category="Normalized performance metrics", - ) - removal_N2 = ( - 1 - - fs.candop_treated.properties[0].flow_mass_comp["nitrogen"] - / fs.feed.properties[0].flow_mass_comp["nitrogen"] - ) - exports.add( - obj=removal_N2, - name="N2 removal", - ui_units=pyunits.dimensionless, - display_units="fraction", - rounding=3, - description="Nitrogen removal fraction [1 - outlet N2 flow/inlet N2 flow]", - is_input=False, - is_output=True, - output_category="Normalized performance metrics", - ) - removal_P = ( - 1 - - fs.candop_treated.properties[0].flow_mass_comp["phosphates"] - / fs.feed.properties[0].flow_mass_comp["phosphates"] - ) - exports.add( - obj=removal_P, - name="Phosphates removal", - ui_units=pyunits.dimensionless, - display_units="fraction", - rounding=3, - description="Phosphates removal fraction [1 - outlet P flow/inlet P flow]", - is_input=False, - is_output=True, - output_category="Normalized performance metrics", - ) - removal_BCP = fs.candop.removal_frac_mass_comp[0, "bioconcentrated_phosphorous"] - exports.add( - obj=removal_BCP, - name="BCP removal", - ui_units=pyunits.dimensionless, - display_units="fraction", - rounding=3, - description="Bioconcentrated phosphorous removal fraction", - is_input=False, - is_output=True, - output_category="Normalized performance metrics", - ) - N2O_production = ( - fs.candop_byproduct.properties[0].flow_mass_comp["nitrous_oxide"] - / fs.feed.properties[0].flow_vol - ) - exports.add( - obj=N2O_production, - name="N2O production", - ui_units=pyunits.kg / pyunits.m**3, - display_units="kg-N2O/m3 of feed", - rounding=3, - description="Nitrous oxide production [N2O product flow rate/feed flow rate]", - is_input=False, - is_output=True, - output_category="Normalized performance metrics", - ) - - # Capital costs - exports.add( - obj=fs.costing.total_capital_cost, - name="Total", - ui_units=fs.costing.base_currency, - display_units="$", - rounding=0, - description="Total capital costs - including investment factor to account " - "for indirect capital", - is_input=False, - is_output=True, - output_category="Capital costs", - ) - exports.add( - obj=fs.pump.costing.capital_cost, - name="Pump", - ui_units=fs.costing.base_currency, - display_units="$", - rounding=0, - description="Pump", - is_input=False, - is_output=True, - output_category="Capital costs", - ) - exports.add( - obj=fs.photothermal.costing.capital_cost, - name="Photothermal membrane", - ui_units=fs.costing.base_currency, - display_units="$", - rounding=0, - description="Photothermal membrane", - is_input=False, - is_output=True, - output_category="Capital costs", - ) - exports.add( - obj=fs.candop.costing.capital_cost, - name="CANDO_P", - ui_units=fs.costing.base_currency, - display_units="$", - rounding=0, - description="CANDO_P", - is_input=False, - is_output=True, - output_category="Capital costs", - ) - - # Operating costs - exports.add( - obj=fs.costing.total_operating_cost, - name="Total", - ui_units=fs.costing.base_currency / pyunits.year, - display_units="$/year", - rounding=0, - description="Total annual operating costs - including electricity, heating, " - "and fixed", - is_input=False, - is_output=True, - output_category="Operating costs", - ) - exports.add( - obj=fs.costing.aggregate_flow_costs["electricity"], - name="Electricity", - ui_units=fs.costing.base_currency / pyunits.year, - display_units="$/year", - rounding=0, - description="Annual electricity costs ", - is_input=False, - is_output=True, - output_category="Operating costs", - ) - exports.add( - obj=fs.costing.total_fixed_operating_cost, - name="Fixed", - ui_units=fs.costing.base_currency / pyunits.year, - display_units="$/year", - rounding=0, - description="Annual fixed operating costs - these costs include material " - "replacement, maintenance, and labor", - is_input=False, - is_output=True, - output_category="Operating costs", - ) - - # Revenue - total_revenue = ( - fs.costing.value_bcp_recovery - + fs.costing.value_N2O_byproduct - + fs.costing.value_water_byproduct - ) - exports.add( - obj=total_revenue, - name="Total", - ui_units=fs.costing.base_currency / pyunits.year, - display_units="$/year", - rounding=0, - description="Total revenue - including the sale of BCP, N2O, and water", - is_input=False, - is_output=True, - output_category="Revenue", - ) - - exports.add( - obj=fs.costing.value_bcp_recovery, - name="BCP", - ui_units=fs.costing.base_currency / pyunits.year, - display_units="$/year", - rounding=0, - description="Revenue from selling bioconcentrated phosphorous", - is_input=False, - is_output=True, - output_category="Revenue", - ) - exports.add( - obj=fs.costing.value_N2O_byproduct, - name="Nitrous oxide", - ui_units=fs.costing.base_currency / pyunits.year, - display_units="$/year", - rounding=0, - description="Revenue from selling nitrous oxide", - is_input=False, - is_output=True, - output_category="Revenue", - ) - exports.add( - obj=fs.costing.value_water_byproduct, - name="Water", - ui_units=fs.costing.base_currency / pyunits.year, - display_units="$/year", - rounding=0, - description="Revenue from selling treated water", - is_input=False, - is_output=True, - output_category="Revenue", - ) - - -def build_flowsheet(build_options=None, **kwargs): - # build and solve initial flowsheet - m = build() - - set_operating_conditions(m) - assert_degrees_of_freedom(m, 0) - assert_units_consistent(m) - - initialize_system(m) - - results = solve(m) - assert_optimal_termination(results) - - add_costing(m) - assert_degrees_of_freedom(m, 0) - m.fs.costing.initialize() - - results = solve(m) - assert_optimal_termination(results) - return m - - -def solve_flowsheet(flowsheet=None): - fs = flowsheet - results = solve(fs) - return results diff --git a/watertap/examples/flowsheets/case_studies/wastewater_resource_recovery/amo_1690/amo_1690_ui.png b/watertap/examples/flowsheets/case_studies/wastewater_resource_recovery/amo_1690/amo_1690_ui.png deleted file mode 100644 index 8cdb98a72a..0000000000 Binary files a/watertap/examples/flowsheets/case_studies/wastewater_resource_recovery/amo_1690/amo_1690_ui.png and /dev/null differ diff --git a/watertap/examples/flowsheets/case_studies/wastewater_resource_recovery/amo_1690/amo_1690_ui.py b/watertap/examples/flowsheets/case_studies/wastewater_resource_recovery/amo_1690/amo_1690_ui.py deleted file mode 100644 index 105138f354..0000000000 --- a/watertap/examples/flowsheets/case_studies/wastewater_resource_recovery/amo_1690/amo_1690_ui.py +++ /dev/null @@ -1,934 +0,0 @@ -################################################################################# -# WaterTAP Copyright (c) 2020-2024, The Regents of the University of California, -# through Lawrence Berkeley National Laboratory, Oak Ridge National Laboratory, -# National Renewable Energy Laboratory, and National Energy Technology -# Laboratory (subject to receipt of any required approvals from the U.S. Dept. -# of Energy). All rights reserved. -# -# Please see the files COPYRIGHT.md and LICENSE.md for full copyright and license -# information, respectively. These files are also available online at the URL -# "https://github.com/watertap-org/watertap/" -################################################################################# -from watertap.ui.fsapi import FlowsheetInterface -from watertap.core.util.initialization import assert_degrees_of_freedom -from watertap.examples.flowsheets.case_studies.wastewater_resource_recovery.amo_1690.amo_1690 import ( - build, - set_operating_conditions, - initialize_system, - solve, - add_costing, -) -from pyomo.environ import units as pyunits, assert_optimal_termination -from pyomo.util.check_units import assert_units_consistent - - -def export_to_ui(): - return FlowsheetInterface( - name="AMO 1690", - do_export=export_variables, - do_build=build_flowsheet, - do_solve=solve_flowsheet, - ) - - -def export_variables(flowsheet=None, exports=None, build_options=None, **kwargs): - fs = flowsheet - # --- Input data --- - # Feed conditions - exports.add( - obj=fs.feed.flow_vol[0], - name="Volumetric flow rate", - ui_units=pyunits.gal / pyunits.day, - display_units="gal/day", - rounding=2, - description="Inlet volumetric flow rate", - is_input=True, - input_category="Feed", - is_output=True, - output_category="Feed", - ) - exports.add( - obj=fs.feed.conc_mass_comp[0, "tss"], - name="TSS concentration", - ui_units=pyunits.mg / pyunits.L, - display_units="mg/L", - rounding=2, - description="Inlet total suspended solids concentration", - is_input=True, - input_category="Feed", - is_output=True, - output_category="Feed", - ) - exports.add( - obj=fs.feed.conc_mass_comp[0, "cod"], - name="COD concentration", - ui_units=pyunits.mg / pyunits.L, - display_units="mg/L", - rounding=2, - description="Inlet COD concentration", - is_input=True, - input_category="Feed", - is_output=True, - output_category="Feed", - ) - exports.add( - obj=fs.feed.conc_mass_comp[0, "tkn"], - name="TKN concentration", - ui_units=pyunits.mg / pyunits.L, - display_units="mg/L", - rounding=2, - description="Inlet TKN concentration", - is_input=True, - input_category="Feed", - is_output=True, - output_category="Feed", - ) - exports.add( - obj=fs.feed.conc_mass_comp[0, "acetic_acid"], - name="Acetic acid concentration", - ui_units=pyunits.mg / pyunits.L, - display_units="mg/L", - rounding=2, - description="Inlet acetic acid concentration", - is_input=True, - input_category="Feed", - is_output=True, - output_category="Feed", - ) - exports.add( - obj=fs.feed.conc_mass_comp[0, "ammonium_as_nitrogen"], - name="NH4 concentration", - ui_units=pyunits.mg / pyunits.L, - display_units="mg/L", - rounding=2, - description="Inlet ammonium concentration", - is_input=True, - input_category="Feed", - is_output=True, - output_category="Feed", - ) - - # Unit model data, cloth media filtration - exports.add( - obj=fs.cmf.recovery_frac_mass_H2O[0], - name="Water recovery", - ui_units=pyunits.dimensionless, - display_units="fraction", # we should change to % - rounding=2, - description="Water recovery [g-H2O treated/g-H2O inlet]", - is_input=True, - input_category="Cloth media filtration", - is_output=False, - ) - exports.add( - obj=fs.cmf.energy_electric_flow_vol_inlet, - name="Electricity intensity", - ui_units=pyunits.kWh / pyunits.m**3, - display_units="kWh/m3", - rounding=2, - description="Specific electricity intensity relating the intensity to the volume of product", - is_input=True, - input_category="Cloth media filtration", - is_output=False, - ) - exports.add( - obj=fs.cmf.removal_frac_mass_comp[0, "tss"], - name="TSS removal", - ui_units=pyunits.dimensionless, - display_units="fraction", # we should change to % - rounding=2, - description="Total suspended solids removal [g-TSS removed/g-TSS inlet]", - is_input=True, - input_category="Cloth media filtration", - is_output=False, - ) - exports.add( - obj=fs.cmf.removal_frac_mass_comp[0, "cod"], - name="COD removal", - ui_units=pyunits.dimensionless, - display_units="fraction", # we should change to % - rounding=2, - description="COD removal [g-COD removed/g-COD inlet]", - is_input=True, - input_category="Cloth media filtration", - is_output=False, - ) - exports.add( - obj=fs.cmf.removal_frac_mass_comp[0, "tkn"], - name="TKN removal", - ui_units=pyunits.dimensionless, - display_units="fraction", # we should change to % - rounding=2, - description="TKN removal [g-TKN removed/g-TKN inlet]", - is_input=True, - input_category="Cloth media filtration", - is_output=False, - ) - - # Unit cost data, cloth media filtration - exports.add( - obj=fs.costing.cloth_media_filtration.sizing_cost[None], - name="Cloth media filtration cost", - ui_units=(fs.costing.base_currency * pyunits.day) / pyunits.gal, - display_units="($ * day)/gal", - rounding=0, - description="Cloth media filtration capital cost parameter", - is_input=True, - input_category="Cloth media filtration costing", - is_output=False, - ) - - # Unit model data, anaerobic digestion - exports.add( - obj=fs.ad.recovery_frac_mass_H2O[0], - name="Water recovery", - ui_units=pyunits.dimensionless, - display_units="fraction", # we should change to % - rounding=2, - description="Water recovery [g-H2O treated/g-H2O inlet]", - is_input=True, - input_category="Anaerobic digestion", - is_output=False, - ) - exports.add( - obj=fs.ad.reaction_conversion[0, "tss_reaction"], - name="TSS conversion", - ui_units=pyunits.dimensionless, - display_units="fraction", # we should change to % - rounding=2, - description="Total suspended solids conversion [g-TSS reacted/g-TSS inlet]", - is_input=True, - input_category="Anaerobic digestion", - is_output=False, - ) - exports.add( - obj=fs.ad.reaction_conversion[0, "cod_reaction"], - name="COD conversion", - ui_units=pyunits.dimensionless, - display_units="fraction", # we should change to % - rounding=2, - description="COD conversion [g-COD reacted/g-COD inlet]", - is_input=True, - input_category="Anaerobic digestion", - is_output=False, - ) - exports.add( - obj=fs.ad.reaction_conversion[0, "tkn_reaction"], - name="TKN conversion", - ui_units=pyunits.dimensionless, - display_units="fraction", # we should change to % - rounding=2, - description="TKN conversion [g-TKN reacted/g-TKN inlet]", - is_input=True, - input_category="Anaerobic digestion", - is_output=False, - ) - exports.add( - obj=fs.ad.energy_electric_flow_vol_inlet, - name="Electricity intensity", - ui_units=pyunits.kWh / pyunits.m**3, - display_units="kWh/m3", - rounding=2, - description="Specific electricity intensity relating the intensity to the volume of product", - is_input=True, - input_category="Anaerobic digestion", - is_output=False, - ) - exports.add( - obj=fs.ad.biogas_tss_ratio, - name="Biogas:TSS ratio", - ui_units=pyunits.m**3 / pyunits.kg, - display_units="m3/kg", - rounding=2, - description="Ratio of biogas volume to total suspended solids mass", - is_input=True, - input_category="Anaerobic digestion", - is_output=False, - ) - - # Unit model data, membrane evaporator - exports.add( - obj=fs.me.recovery_frac_mass_H2O[0], - name="Water recovery", - ui_units=pyunits.dimensionless, - display_units="fraction", # we should change to % - rounding=2, - description="Water recovery [g-H2O treated/g-H2O inlet]", - is_input=True, - input_category="Membrane evaporator", - is_output=False, - ) - exports.add( - obj=fs.me.removal_frac_mass_comp[0, "ammonium_as_nitrogen"], - name="NH4 removal", - ui_units=pyunits.dimensionless, - display_units="fraction", # we should change to % - rounding=2, - description="Ammonium removal [g-NH4 removed/g-NH4 inlet]", - is_input=True, - input_category="Membrane evaporator", - is_output=False, - ) - exports.add( - obj=fs.me.removal_frac_mass_comp[0, "acetic_acid"], - name="Acetic acid removal", - ui_units=pyunits.dimensionless, - display_units="fraction", # we should change to % - rounding=2, - description="Acetic acid removal [g-CH3COOH removed/g-CH3COOH inlet]", - is_input=True, - input_category="Membrane evaporator", - is_output=False, - ) - exports.add( - obj=fs.me.energy_electric_flow_vol_inlet, - name="Electricity intensity", - ui_units=pyunits.kWh / pyunits.m**3, - display_units="kWh/m3", - rounding=2, - description="Specific electricity intensity relating the intensity to the volume of product", - is_input=True, - input_category="Membrane evaporator", - is_output=False, - ) - exports.add( - obj=fs.me.water_flux, - name="Water flux", - ui_units=pyunits.m / pyunits.hr, - display_units="m/h", - rounding=2, - description="Water flux", - is_input=True, - input_category="Membrane evaporator", - is_output=False, - ) - - # Unit cost data, membrane evaporator - exports.add( - obj=fs.costing.membrane_evaporator.membrane_cost[None], - name="Membrane cost", - ui_units=fs.costing.base_currency / pyunits.m**2, - display_units="$/m2 of membrane", - rounding=0, - description="Membrane evaporator capital cost parameter", - is_input=True, - input_category="Membrane evaporator costing", - is_output=False, - ) - - # System costing - exports.add( - obj=fs.costing.utilization_factor, - name="Utilization factor", - ui_units=pyunits.dimensionless, - display_units="fraction", - rounding=2, - description="Utilization factor - [annual use hours/total hours in year]", - is_input=True, - input_category="System costing", - is_output=False, - ) - exports.add( - obj=fs.costing.TIC, - name="Practical investment factor", - ui_units=pyunits.dimensionless, - display_units="fraction", - rounding=1, - description="Practical investment factor - [total investment cost/direct " - "capital costs]", - is_input=True, - input_category="System costing", - is_output=False, - ) - exports.add( - obj=fs.costing.plant_lifetime, - name="Plant lifetime", - ui_units=pyunits.year, - display_units="years", - rounding=1, - description="Plant lifetime", - is_input=True, - input_category="System costing", - is_output=False, - ) - exports.add( - obj=fs.costing.wacc, - name="Discount rate", - ui_units=pyunits.dimensionless, - display_units="fraction", - rounding=2, - description="Discount rate used in calculating the capital annualization", - is_input=True, - input_category="System costing", - is_output=False, - ) - exports.add( - obj=fs.costing.maintenance_costs_percent_FCI, - name="Fixed operating cost factor", - ui_units=1 / pyunits.year, - display_units="fraction/year", - rounding=2, - description="Fixed operating cost factor - [annual fixed operating cost/total " - "investment cost]", - is_input=True, - input_category="System costing", - is_output=False, - ) - exports.add( - obj=fs.costing.electricity_cost, - name="Electricity cost", - ui_units=fs.costing.base_currency / pyunits.kWh, - display_units="$/kWh", - rounding=3, - description="Electricity cost", - is_input=True, - input_category="System costing", - is_output=False, - ) - exports.add( - obj=fs.costing.biogas_cost, - name="Biogas cost", - ui_units=fs.costing.base_currency / pyunits.m**3, - display_units="$/m3", - rounding=3, - description="Biogas cost", - is_input=True, - input_category="System costing", - is_output=False, - ) - exports.add( - obj=fs.costing.fertilizer_cost, - name="Fertilizer cost", - ui_units=fs.costing.base_currency / pyunits.kg, - display_units="$/kg", - rounding=3, - description="Fertilizer cost", - is_input=True, - input_category="System costing", - is_output=False, - ) - - # Outlets - exports.add( - obj=fs.filtered_water.properties[0].flow_vol, - name="Filtered water flow rate", - ui_units=pyunits.m**3 / pyunits.hr, - display_units="m3/h", - rounding=2, - description="Outlet filtered water flow rate", - is_input=False, - is_output=True, - output_category="Outlets", - ) - exports.add( - obj=fs.filtered_water.properties[0].conc_mass_comp["tss"], - name="Filtered water TSS concentration", - ui_units=pyunits.mg / pyunits.L, - display_units="mg/L", - rounding=5, - description="Outlet filtered water total suspended solids concentration", - is_input=False, - is_output=True, - output_category="Outlets", - ) - exports.add( - obj=fs.filtered_water.properties[0].conc_mass_comp["cod"], - name="Filtered water COD concentration", - ui_units=pyunits.mg / pyunits.L, - display_units="mg/L", - rounding=5, - description="Outlet filtered water COD concentration", - is_input=False, - is_output=True, - output_category="Outlets", - ) - exports.add( - obj=fs.filtered_water.properties[0].conc_mass_comp["tkn"], - name="Filtered water TKN concentration", - ui_units=pyunits.mg / pyunits.L, - display_units="mg/L", - rounding=5, - description="Outlet filtered water TKN concentration", - is_input=False, - is_output=True, - output_category="Outlets", - ) - exports.add( - obj=fs.ad_byproduct.properties[0].flow_vol, - name="AD byproduct flow rate", - ui_units=pyunits.m**3 / pyunits.hr, - display_units="m3/h", - rounding=2, - description="Outlet anaerobic digestion byproduct flow rate", - is_input=False, - is_output=True, - output_category="Outlets", - ) - exports.add( - obj=fs.ad_byproduct.properties[0].conc_mass_comp["H2O"], - name="AD byproduct water concentration", - ui_units=pyunits.mg / pyunits.L, - display_units="mg/L", - rounding=5, - description="Outlet AD byproduct water concentration", - is_input=False, - is_output=True, - output_category="Outlets", - ) - exports.add( - obj=fs.ad_byproduct.properties[0].conc_mass_comp["tss"], - name="AD byproduct TSS concentration", - ui_units=pyunits.mg / pyunits.L, - display_units="mg/L", - rounding=5, - description="Outlet AD byproduct total suspended solids concentration", - is_input=False, - is_output=True, - output_category="Outlets", - ) - exports.add( - obj=fs.ad_byproduct.properties[0].conc_mass_comp["cod"], - name="AD byproduct COD concentration", - ui_units=pyunits.mg / pyunits.L, - display_units="mg/L", - rounding=5, - description="Outlet AD byproduct COD concentration", - is_input=False, - is_output=True, - output_category="Outlets", - ) - exports.add( - obj=fs.ad_byproduct.properties[0].conc_mass_comp["tkn"], - name="AD byproduct TKN concentration", - ui_units=pyunits.mg / pyunits.L, - display_units="mg/L", - rounding=5, - description="Outlet AD byproduct TKN concentration", - is_input=False, - is_output=True, - output_category="Outlets", - ) - exports.add( - obj=fs.me_byproduct.properties[0].flow_vol, - name="Membrane evaporator byproduct flow rate", - ui_units=pyunits.m**3 / pyunits.hr, - display_units="m3/h", - rounding=2, - description="Outlet membrane evaporator byproduct flow rate", - is_input=False, - is_output=True, - output_category="Outlets", - ) - exports.add( - obj=fs.me_byproduct.properties[0].conc_mass_comp["acetic_acid"], - name="Membrane evaporator byproduct acetic acid concentration", - ui_units=pyunits.mg / pyunits.L, - display_units="mg/L", - rounding=5, - description="Outlet membrane evaporator byproduct acetic acid concentration", - is_input=False, - is_output=True, - output_category="Outlets", - ) - exports.add( - obj=fs.me_byproduct.properties[0].conc_mass_comp["ammonium_as_nitrogen"], - name="Membrane evaporator byproduct ammonium concentration", - ui_units=pyunits.mg / pyunits.L, - display_units="mg/L", - rounding=5, - description="Outlet membrane evaporator byproduct ammonium concentration", - is_input=False, - is_output=True, - output_category="Outlets", - ) - exports.add( - obj=fs.me_treated.properties[0].flow_vol, - name="Membrane evaporator treated flow rate", - ui_units=pyunits.m**3 / pyunits.hr, - display_units="m3/h", - rounding=2, - description="Outlet membrane evaporator treated flow rate", - is_input=False, - is_output=True, - output_category="Outlets", - ) - exports.add( - obj=fs.me_treated.properties[0].conc_mass_comp["acetic_acid"], - name="Membrane evaporator treated acetic_acid concentration", - ui_units=pyunits.mg / pyunits.L, - display_units="mg/L", - rounding=5, - description="Outlet membrane evaporator treated acetic acid concentration", - is_input=False, - is_output=True, - output_category="Outlets", - ) - exports.add( - obj=fs.me_treated.properties[0].conc_mass_comp["ammonium_as_nitrogen"], - name="Membrane evaporator treated ammonium concentration", - ui_units=pyunits.mg / pyunits.L, - display_units="mg/L", - rounding=5, - description="Outlet membrane evaporator treated ammonium concentration", - is_input=False, - is_output=True, - output_category="Outlets", - ) - - # System metrics - exports.add( - obj=fs.costing.LCOT, - name="LCOT", - ui_units=fs.costing.base_currency / pyunits.m**3, - display_units="$/m3 of feed water", - rounding=3, - description="Levelized cost of treatment including operating and capital costs", - is_input=False, - is_output=True, - output_category="Levelized cost metrics", - ) - exports.add( - obj=fs.costing.LCOT_with_revenue, - name="LCOT with revenue", - ui_units=fs.costing.base_currency / pyunits.m**3, - display_units="$/m3 of feed water", - rounding=3, - description="Levelized cost of treatment including revenue of biogas and fertilizer", - is_input=False, - is_output=True, - output_category="Levelized cost metrics", - ) - exports.add( - obj=fs.costing.LC_biogas, - name="LCOB", - ui_units=fs.costing.base_currency / pyunits.m**3, - display_units="$/m3 of biogas", - rounding=3, - description="Levelized cost of biogas including operating and capital costs", - is_input=False, - is_output=True, - output_category="Levelized cost metrics", - ) - exports.add( - obj=fs.costing.LC_biogas_with_revenue, - name="LCOB with revenue", - ui_units=fs.costing.base_currency / pyunits.m**3, - display_units="$/m3 of biogas", - rounding=3, - description="Levelized cost of biogas including revenue of fertilizer", - is_input=False, - is_output=True, - output_category="Levelized cost metrics", - ) - exports.add( - obj=fs.costing.LC_fertilizer, - name="LCOF", - ui_units=fs.costing.base_currency / pyunits.kg, - display_units="$/kg of fertilizer", - rounding=3, - description="Levelized cost of fertilizer including operating and capital costs", - is_input=False, - is_output=True, - output_category="Levelized cost metrics", - ) - exports.add( - obj=fs.costing.LC_fertilizer_with_revenue, - name="LCOF with revenue", - ui_units=fs.costing.base_currency / pyunits.kg, - display_units="$/kg of fertilizer", - rounding=3, - description="Levelized cost of fertilizer including revenue of biogas", - is_input=False, - is_output=True, - output_category="Levelized cost metrics", - ) - - # Normalized metrics - total_capital_norm = fs.costing.total_capital_cost / fs.feed.properties[0].flow_vol - exports.add( - obj=total_capital_norm, - name="Total capital", - ui_units=fs.costing.base_currency / (pyunits.m**3 / pyunits.day), - display_units="$/(m3/day)", - rounding=1, - description="Normalized total capital costs accounting for indirect " - "capital and installation - [total capital costs/feed flow rate]", - is_input=False, - is_output=True, - output_category="Normalized cost metrics", - ) - direct_capital_norm = ( - fs.cmf.costing.direct_capital_cost - + fs.ad.costing.direct_capital_cost - + fs.me.costing.direct_capital_cost - ) / fs.feed.properties[0].flow_vol - exports.add( - obj=direct_capital_norm, - name="Direct capital", - ui_units=fs.costing.base_currency / (pyunits.m**3 / pyunits.day), - display_units="$/(m3/day)", - rounding=1, - description="Normalized direct capital costs - [total direct capital " - "costs/feed flow rate] ", - is_input=False, - is_output=True, - output_category="Normalized cost metrics", - ) - elec_operating_norm = ( - fs.costing.aggregate_flow_costs["electricity"] / fs.costing.annual_water_inlet - ) - exports.add( - obj=elec_operating_norm, - name="Electricity", - ui_units=fs.costing.base_currency / pyunits.m**3, - display_units="$/m3 of feed", - rounding=2, - description="Normalized electricity cost - [annual electricity costs/annual " - "feed flow rate]", - is_input=False, - is_output=True, - output_category="Normalized cost metrics", - ) - - # performance metrics - recovery_vol = ( - fs.filtered_water.properties[0].flow_vol / fs.feed.properties[0].flow_vol - ) - exports.add( - obj=recovery_vol, - name="Volumetric recovery", - ui_units=pyunits.dimensionless, - display_units="m3 of filtered water/m3 of feed", - rounding=3, - description="Normalized volumetric recovery", - is_input=False, - is_output=True, - output_category="Normalized performance metrics", - ) - removal_TSS = ( - 1 - - fs.filtered_water.properties[0].flow_mass_comp["tss"] - / fs.feed.properties[0].flow_mass_comp["tss"] - ) - exports.add( - obj=removal_TSS, - name="TSS removal", - ui_units=pyunits.dimensionless, - display_units="fraction", - rounding=3, - description="Total suspended solids removal fraction [1 - outlet TSS flow/inlet TSS flow]", - is_input=False, - is_output=True, - output_category="Normalized performance metrics", - ) - removal_COD = ( - 1 - - fs.filtered_water.properties[0].flow_mass_comp["cod"] - / fs.feed.properties[0].flow_mass_comp["cod"] - ) - exports.add( - obj=removal_COD, - name="COD removal", - ui_units=pyunits.dimensionless, - display_units="fraction", - rounding=3, - description="COD removal fraction [1 - outlet COD flow/inlet COD flow]", - is_input=False, - is_output=True, - output_category="Normalized performance metrics", - ) - removal_TKN = ( - 1 - - fs.filtered_water.properties[0].flow_mass_comp["tkn"] - / fs.feed.properties[0].flow_mass_comp["tkn"] - ) - exports.add( - obj=removal_TKN, - name="TKN removal", - ui_units=pyunits.dimensionless, - display_units="fraction", - rounding=3, - description="TKN removal fraction [1 - outlet TKN flow/inlet TKN flow]", - is_input=False, - is_output=True, - output_category="Normalized performance metrics", - ) - biogas_recovery_volume = fs.costing.utilization_factor * fs.ad.biogas_production[0] - exports.add( - obj=biogas_recovery_volume, - name="Biogas recovery", - ui_units=pyunits.m**3 / pyunits.year, - display_units="m3-biogas/year", - rounding=0, - description="Biogas recovery volume", - is_input=False, - is_output=True, - output_category="Normalized performance metrics", - ) - fertilizer_recovery_mass = fs.costing.utilization_factor * ( - fs.me_byproduct.flow_mass_comp[0, "ammonium_as_nitrogen"] - + fs.me_byproduct.flow_mass_comp[0, "acetic_acid"] - ) - exports.add( - obj=fertilizer_recovery_mass, - name="Fertilizer recovery", - ui_units=pyunits.kg / pyunits.year, - display_units="kg-fertilizer/year", - rounding=0, - description="Fertilizer recovery mass", - is_input=False, - is_output=True, - output_category="Normalized performance metrics", - ) - - # Capital costs - exports.add( - obj=fs.costing.total_capital_cost, - name="Total", - ui_units=fs.costing.base_currency, - display_units="$", - rounding=0, - description="Total capital costs - including investment factor to account " - "for indirect capital", - is_input=False, - is_output=True, - output_category="Capital costs", - ) - exports.add( - obj=fs.cmf.costing.capital_cost, - name="Cloth media filtration", - ui_units=fs.costing.base_currency, - display_units="$", - rounding=0, - description="Cloth media filtration", - is_input=False, - is_output=True, - output_category="Capital costs", - ) - exports.add( - obj=fs.ad.costing.capital_cost, - name="Anaerobic digestion", - ui_units=fs.costing.base_currency, - display_units="$", - rounding=0, - description="Anaerobic digestion", - is_input=False, - is_output=True, - output_category="Capital costs", - ) - exports.add( - obj=fs.me.costing.capital_cost, - name="Membrane evaporator", - ui_units=fs.costing.base_currency, - display_units="$", - rounding=0, - description="Membrane evaporator", - is_input=False, - is_output=True, - output_category="Capital costs", - ) - - # Operating costs - exports.add( - obj=fs.costing.total_operating_cost, - name="Total", - ui_units=fs.costing.base_currency / pyunits.year, - display_units="$/year", - rounding=0, - description="Total annual operating costs - including electricity, heating, " - "and fixed", - is_input=False, - is_output=True, - output_category="Operating costs", - ) - exports.add( - obj=fs.costing.aggregate_flow_costs["electricity"], - name="Electricity", - ui_units=fs.costing.base_currency / pyunits.year, - display_units="$/year", - rounding=0, - description="Annual electricity costs ", - is_input=False, - is_output=True, - output_category="Operating costs", - ) - exports.add( - obj=fs.costing.total_fixed_operating_cost, - name="Fixed", - ui_units=fs.costing.base_currency / pyunits.year, - display_units="$/year", - rounding=0, - description="Annual fixed operating costs - these costs include material " - "replacement, maintenance, and labor", - is_input=False, - is_output=True, - output_category="Operating costs", - ) - - # Revenue - total_revenue = (biogas_recovery_volume * fs.costing.biogas_cost) + ( - fertilizer_recovery_mass * fs.costing.fertilizer_cost - ) - exports.add( - obj=total_revenue, - name="Total", - ui_units=fs.costing.base_currency / pyunits.year, - display_units="$/year", - rounding=0, - description="Total revenue - including the sale of struvite and purchase of MgCl2 and dry polymer", - is_input=False, - is_output=True, - output_category="Revenue", - ) - biogas_revenue = biogas_recovery_volume * fs.costing.biogas_cost - exports.add( - obj=biogas_revenue, - name="Biogas", - ui_units=fs.costing.base_currency / pyunits.year, - display_units="$/year", - rounding=0, - description="Revenue from selling biogas", - is_input=False, - is_output=True, - output_category="Revenue", - ) - fertilizer_revenue = fertilizer_recovery_mass * fs.costing.fertilizer_cost - exports.add( - obj=fertilizer_revenue, - name="Fertilizer", - ui_units=fs.costing.base_currency / pyunits.year, - display_units="$/year", - rounding=0, - description="Revenue from selling fertilizer", - is_input=False, - is_output=True, - output_category="Revenue", - ) - - -def build_flowsheet(build_options=None, **kwargs): - # build and solve initial flowsheet - m = build() - - set_operating_conditions(m) - assert_degrees_of_freedom(m, 0) - assert_units_consistent(m) - - initialize_system(m) - - results = solve(m) - assert_optimal_termination(results) - - add_costing(m) - assert_degrees_of_freedom(m, 0) - m.fs.costing.initialize() - - results = solve(m) - assert_optimal_termination(results) - return m - - -def solve_flowsheet(flowsheet=None): - fs = flowsheet - results = solve(fs) - return results diff --git a/watertap/examples/flowsheets/case_studies/wastewater_resource_recovery/biomembrane_filtration/biomembrane_filtration_ui.png b/watertap/examples/flowsheets/case_studies/wastewater_resource_recovery/biomembrane_filtration/biomembrane_filtration_ui.png deleted file mode 100644 index 340d7ea293..0000000000 Binary files a/watertap/examples/flowsheets/case_studies/wastewater_resource_recovery/biomembrane_filtration/biomembrane_filtration_ui.png and /dev/null differ diff --git a/watertap/examples/flowsheets/case_studies/wastewater_resource_recovery/biomembrane_filtration/biomembrane_filtration_ui.py b/watertap/examples/flowsheets/case_studies/wastewater_resource_recovery/biomembrane_filtration/biomembrane_filtration_ui.py deleted file mode 100644 index df396ace7e..0000000000 --- a/watertap/examples/flowsheets/case_studies/wastewater_resource_recovery/biomembrane_filtration/biomembrane_filtration_ui.py +++ /dev/null @@ -1,685 +0,0 @@ -################################################################################# -# WaterTAP Copyright (c) 2020-2024, The Regents of the University of California, -# through Lawrence Berkeley National Laboratory, Oak Ridge National Laboratory, -# National Renewable Energy Laboratory, and National Energy Technology -# Laboratory (subject to receipt of any required approvals from the U.S. Dept. -# of Energy). All rights reserved. -# -# Please see the files COPYRIGHT.md and LICENSE.md for full copyright and license -# information, respectively. These files are also available online at the URL -# "https://github.com/watertap-org/watertap/" -################################################################################# -from watertap.ui.fsapi import FlowsheetInterface -from watertap.core.util.initialization import assert_degrees_of_freedom -from watertap.examples.flowsheets.case_studies.wastewater_resource_recovery.biomembrane_filtration.biomembrane_filtration import ( - build, - set_operating_conditions, - initialize_system, - solve, - add_costing, -) -from pyomo.environ import units as pyunits, assert_optimal_termination -from pyomo.util.check_units import assert_units_consistent - - -def export_to_ui(): - return FlowsheetInterface( - name="Biomembrane filtration", - do_export=export_variables, - do_build=build_flowsheet, - do_solve=solve_flowsheet, - ) - - -def export_variables(flowsheet=None, exports=None, build_options=None, **kwargs): - fs = flowsheet - # --- Input data --- - # Feed conditions - exports.add( - obj=fs.feed.flow_vol[0], - name="Volumetric flow rate", - ui_units=pyunits.m**3 / pyunits.hr, - display_units="m3/h", - rounding=1, - description="Inlet volumetric flow rate", - is_input=True, - input_category="Feed", - is_output=True, - output_category="Feed", - ) - exports.add( - obj=fs.feed.conc_mass_comp[0, "bod"], - name="BOD concentration", - ui_units=pyunits.mg / pyunits.L, - display_units="mg/L", - rounding=1, - description="Inlet biochemical oxygen demand (BOD) concentration", - is_input=True, - input_category="Feed", - is_output=True, - output_category="Feed", - ) - exports.add( - obj=fs.feed.conc_mass_comp[0, "tss"], - name="TSS concentration", - ui_units=pyunits.mg / pyunits.L, - display_units="mg/L", - rounding=1, - description="Inlet total suspended solids (TSS) concentration", - is_input=True, - input_category="Feed", - is_output=True, - output_category="Feed", - ) - exports.add( - obj=fs.feed.conc_mass_comp[0, "ammonium_as_nitrogen"], - name="NH4-N concentration", - ui_units=pyunits.mg / pyunits.L, - display_units="mg/L", - rounding=1, - description="Inlet ammonium as nitrogen (NH4-N) concentration", - is_input=True, - input_category="Feed", - is_output=True, - output_category="Feed", - ) - exports.add( - obj=fs.feed.conc_mass_comp[0, "nitrate"], - name="NO3-N concentration", - ui_units=pyunits.mg / pyunits.L, - display_units="mg/L", - rounding=1, - description="Inlet nitrate (NO3-N) concentration", - is_input=True, - input_category="Feed", - is_output=True, - output_category="Feed", - ) - - # Unit model data, mabr - exports.add( - obj=fs.mabr.recovery_frac_mass_H2O[0], - name="Water recovery", - ui_units=pyunits.dimensionless, - display_units="fraction", # we should change to % - rounding=2, - description="Water recovery [g-H2O treated/g-H2O inlet]", - is_input=True, - input_category="MABR", - is_output=False, - ) - exports.add( - obj=fs.mabr.removal_frac_mass_comp[0, "tss"], - name="TSS removal", - ui_units=pyunits.dimensionless, - display_units="fraction", # we should change to % - rounding=2, - description="TSS removal [g-TSS byproduct/g-TSS inlet]", - is_input=True, - input_category="MABR", - is_output=False, - ) - exports.add( - obj=fs.mabr.reaction_conversion[0, "ammonium_to_nitrate"], - name="NH4-N conversion", - ui_units=pyunits.dimensionless, - display_units="fraction", # we should change to % - rounding=2, - description="NH4-N conversion [g-NH4-N reacted/g-NH4-N inlet]", - is_input=True, - input_category="MABR", - is_output=False, - ) - exports.add( - obj=fs.mabr.generation_ratio["ammonium_to_nitrate", "bod"], - name="BOD conversion ratio", - ui_units=pyunits.dimensionless, - display_units="fraction", - rounding=2, - description="BOD mass conversion ratio with respect to NH4-N [g-BOD produced/g-NH4-N" - " reacted]", - is_input=True, - input_category="MABR", - is_output=False, - ) - exports.add( - obj=fs.mabr.generation_ratio["ammonium_to_nitrate", "nitrate"], - name="NO3-N conversion ratio", - ui_units=pyunits.dimensionless, - display_units="fraction", - rounding=2, - description="NO3-N mass conversion ratio with respect to NH4-N [g-NO3-N produced/g-NH4-N" - " reacted]", - is_input=True, - input_category="MABR", - is_output=False, - ) - exports.add( - obj=fs.mabr.nitrogen_removal_rate, - name="Nitrogen removal rate", - ui_units=pyunits.g / pyunits.m**2 / pyunits.day, - display_units="g/m2/day", - rounding=1, - description="Nitrogen removal rate", - is_input=True, - input_category="MABR", - is_output=False, - ) - exports.add( - obj=fs.mabr.air_flow_rate[0], - name="Air flow rate", - ui_units=pyunits.m**3 / pyunits.hr / pyunits.m**2, - display_units="m3 of air/h/m2", - rounding=3, - description="Air flow rate", - is_input=True, - input_category="MABR", - is_output=False, - ) - exports.add( - obj=fs.mabr.energy_electric_flow_vol_inlet, - name="Blower specific power", - ui_units=pyunits.kWh / pyunits.m**3, - display_units="kWh/m3 of air", - rounding=5, - description="Blower specific power relating the power to the volume of the " - "air", - is_input=True, - input_category="MABR", - is_output=False, - ) - - # Unit cost data, mabr - exports.add( - obj=fs.costing.mabr.reactor_cost[None], - name="Reactor cost", - ui_units=fs.costing.base_currency / pyunits.m**2, - display_units="$/m2 of reactor", - rounding=0, - description="Reactor capital cost parameter", - is_input=True, - input_category="MABR costing", - is_output=False, - ) - exports.add( - obj=fs.costing.mabr.blower_cost[None], - name="Blower cost", - ui_units=fs.costing.base_currency / (pyunits.m**3 / pyunits.hr), - display_units="$/(m3/h)", - rounding=0, - description="Blower capital cost parameter", - is_input=True, - input_category="MABR costing", - is_output=False, - ) - - # Unit model data, dmbr - exports.add( - obj=fs.dmbr.recovery_frac_mass_H2O[0], - name="Water recovery", - ui_units=pyunits.dimensionless, - display_units="fraction", # we should change to % - rounding=2, - description="Water recovery [g-H2O treated/g-H2O inlet]", - is_input=True, - input_category="DMBR", - is_output=False, - ) - exports.add( - obj=fs.dmbr.removal_frac_mass_comp[0, "tss"], - name="TSS removal", - ui_units=pyunits.dimensionless, - display_units="fraction", # we should change to % - rounding=2, - description="TSS removal [g-TSS byproduct/g-TSS inlet]", - is_input=True, - input_category="DMBR", - is_output=False, - ) - exports.add( - obj=fs.dmbr.reaction_conversion[0, "nitrate_to_nitrogen"], - name="NO3-N conversion", - ui_units=pyunits.dimensionless, - display_units="fraction", # we should change to % - rounding=2, - description="NO3-N conversion [g-NO3-N reacted/g-NO3-N inlet]", - is_input=True, - input_category="DMBR", - is_output=False, - ) - exports.add( - obj=fs.dmbr.generation_ratio["nitrate_to_nitrogen", "nitrogen"], - name="N2 conversion ratio", - ui_units=pyunits.dimensionless, - display_units="fraction", - rounding=2, - description="N2 mass conversion ratio with respect to NO3-N [g-N2 " - "produced/g-NO3-N reacted]", - is_input=True, - input_category="DMBR", - is_output=False, - ) - exports.add( - obj=fs.dmbr.reaction_conversion[0, "BOD_usage"], - name="BOD conversion", - ui_units=pyunits.dimensionless, - display_units="fraction", # we should change to % - rounding=2, - description="BOD conversion [g-BOD reacted/g-BOD inlet]", - is_input=True, - input_category="DMBR", - is_output=False, - ) - exports.add( - obj=fs.dmbr.energy_electric_flow_vol_inlet, - name="Electricity specific power", - ui_units=pyunits.kWh / pyunits.m**3, - display_units="kWh/m3 of reactor", - rounding=2, - description="Electricity specific power relating the power to the volume of the " - "reactor", - is_input=True, - input_category="DMBR", - is_output=False, - ) - - # Unit cost data, dmbr - exports.add( - obj=fs.costing.dmbr.water_flux[None], - name="Water flux", - ui_units=pyunits.L / pyunits.m**2 / pyunits.hr, - display_units="$/m2/h", - rounding=0, - description="Reactor sizing parameter - water flux", - is_input=True, - input_category="DMBR costing", - is_output=False, - ) - exports.add( - obj=fs.costing.dmbr.reactor_cost[None], - name="Reactor cost", - ui_units=fs.costing.base_currency / pyunits.m**2, - display_units="$/m2 of reactor", - rounding=1, - description="Reactor capital cost parameter", - is_input=True, - input_category="DMBR costing", - is_output=False, - ) - - # System costing - exports.add( - obj=fs.costing.utilization_factor, - name="Utilization factor", - ui_units=pyunits.dimensionless, - display_units="fraction", - rounding=2, - description="Utilization factor - [annual use hours/total hours in year]", - is_input=True, - input_category="System costing", - is_output=False, - ) - exports.add( - obj=fs.costing.TIC, - name="Practical investment factor", - ui_units=pyunits.dimensionless, - display_units="fraction", - rounding=1, - description="Practical investment factor - [total investment cost/direct " - "capital costs]", - is_input=True, - input_category="System costing", - is_output=False, - ) - exports.add( - obj=fs.costing.plant_lifetime, - name="Plant lifetime", - ui_units=pyunits.year, - display_units="years", - rounding=1, - description="Plant lifetime", - is_input=True, - input_category="System costing", - is_output=False, - ) - exports.add( - obj=fs.costing.wacc, - name="Discount rate", - ui_units=pyunits.dimensionless, - display_units="fraction", - rounding=2, - description="Discount rate used in calculating the capital annualization", - is_input=True, - input_category="System costing", - is_output=False, - ) - exports.add( - obj=fs.costing.maintenance_costs_percent_FCI, - name="Fixed operating cost factor", - ui_units=1 / pyunits.year, - display_units="fraction/year", - rounding=2, - description="Fixed operating cost factor - [annual fixed operating cost/total " - "investment cost]", - is_input=True, - input_category="System costing", - is_output=False, - ) - exports.add( - obj=fs.costing.electricity_cost, - name="Electricity cost", - ui_units=fs.costing.base_currency / pyunits.kWh, - display_units="$/kWh", - rounding=3, - description="Electricity cost", - is_input=True, - input_category="System costing", - is_output=False, - ) - - # Outlets - exports.add( - obj=fs.product_H2O.properties[0].flow_vol, - name="Product water flow rate", - ui_units=pyunits.m**3 / pyunits.hr, - display_units="m3/h", - rounding=2, - description="Outlet product water flow rate", - is_input=False, - is_output=True, - output_category="Outlets", - ) - exports.add( - obj=fs.product_H2O.properties[0].conc_mass_comp["bod"], - name="Product water BOD concentration", - ui_units=pyunits.g / pyunits.L, - display_units="g/L", - rounding=4, - description="Outlet product water biological oxygen demand concentration", - is_input=False, - is_output=True, - output_category="Outlets", - ) - exports.add( - obj=fs.product_H2O.properties[0].conc_mass_comp["tss"], - name="Product water TSS concentration", - ui_units=pyunits.g / pyunits.L, - display_units="g/L", - rounding=4, - description="Outlet product water total suspended solids concentration", - is_input=False, - is_output=True, - output_category="Outlets", - ) - exports.add( - obj=fs.product_H2O.properties[0].conc_mass_comp["ammonium_as_nitrogen"], - name="Product water NH4-N concentration", - ui_units=pyunits.g / pyunits.L, - display_units="g/L", - rounding=4, - description="Outlet product water NH4-N concentration", - is_input=False, - is_output=True, - output_category="Outlets", - ) - exports.add( - obj=fs.product_H2O.properties[0].conc_mass_comp["nitrate"], - name="Product water NO3-N concentration", - ui_units=pyunits.g / pyunits.L, - display_units="g/L", - rounding=4, - description="Outlet product water NO3-N concentration", - is_input=False, - is_output=True, - output_category="Outlets", - ) - - # System metrics - exports.add( - obj=fs.costing.LCOT, - name="Levelized cost of treatment", - ui_units=fs.costing.base_currency / pyunits.m**3, - display_units="$/m3 of feed", - rounding=2, - description="Levelized cost of treatment including operating and capital costs", - is_input=False, - is_output=True, - output_category="Levelized cost metrics", - ) - exports.add( - obj=fs.costing.LCOW, - name="Levelized cost of water", - ui_units=fs.costing.base_currency / pyunits.m**3, - display_units="$/m3 of product", - rounding=2, - description="Levelized cost of water including operating and capital costs", - is_input=False, - is_output=True, - output_category="Levelized cost metrics", - ) - - # Normalized metrics - total_capital_norm = fs.costing.total_capital_cost / fs.feed.properties[0].flow_vol - exports.add( - obj=total_capital_norm, - name="Total capital", - ui_units=fs.costing.base_currency / (pyunits.m**3 / pyunits.day), - display_units="$/(m3/day)", - rounding=1, - description="Normalized total capital costs accounting for indirect " - "capital and installation - [total capital costs/feed flow rate]", - is_input=False, - is_output=True, - output_category="Normalized cost metrics", - ) - direct_capital_norm = ( - fs.mabr.costing.direct_capital_cost - + fs.dmbr.costing.direct_capital_cost - + fs.P1.costing.direct_capital_cost - ) / fs.feed.properties[0].flow_vol - exports.add( - obj=direct_capital_norm, - name="Direct capital", - ui_units=fs.costing.base_currency / (pyunits.m**3 / pyunits.day), - display_units="$/(m3/day)", - rounding=1, - description="Normalized direct capital costs - [total direct capital " - "costs/feed flow rate] ", - is_input=False, - is_output=True, - output_category="Normalized cost metrics", - ) - elec_operating_norm = ( - fs.costing.aggregate_flow_costs["electricity"] / fs.costing.annual_water_inlet - ) - exports.add( - obj=elec_operating_norm, - name="Electricity", - ui_units=fs.costing.base_currency / pyunits.m**3, - display_units="$/m3 of feed", - rounding=2, - description="Normalized electricity cost - [annual electricity costs/annual " - "feed flow rate]", - is_input=False, - is_output=True, - output_category="Normalized cost metrics", - ) - - # performance metrics - recovery_vol = ( - fs.product_H2O.properties[0].flow_vol / fs.feed.properties[0].flow_vol - ) - exports.add( - obj=recovery_vol, - name="Volumetric recovery", - ui_units=pyunits.dimensionless, - display_units="m3 of product/m3 of feed", - rounding=3, - description="Normalized heating cost - [annual heating costs/annual feed " - "flow rate]", - is_input=False, - is_output=True, - output_category="Normalized performance metrics", - ) - removal_bod = ( - 1 - - fs.product_H2O.properties[0].flow_mass_comp["bod"] - / fs.feed.properties[0].flow_mass_comp["bod"] - ) - exports.add( - obj=removal_bod, - name="BOD removal", - ui_units=pyunits.dimensionless, - display_units="fraction", - rounding=3, - description="BOD removal fraction [1 - outlet BOD flow/inlet BOD flow]", - is_input=False, - is_output=True, - output_category="Normalized performance metrics", - ) - removal_tss = ( - 1 - - fs.product_H2O.properties[0].flow_mass_comp["tss"] - / fs.feed.properties[0].flow_mass_comp["tss"] - ) - exports.add( - obj=removal_tss, - name="TSS removal", - ui_units=pyunits.dimensionless, - display_units="fraction", - rounding=3, - description="TSS removal fraction [1 - outlet TSS flow/inlet TSS flow]", - is_input=False, - is_output=True, - output_category="Normalized performance metrics", - ) - removal_TN = 1 - ( - fs.product_H2O.properties[0].flow_mass_comp["ammonium_as_nitrogen"] - + fs.product_H2O.properties[0].flow_mass_comp["nitrate"] - ) / ( - fs.feed.properties[0].flow_mass_comp["ammonium_as_nitrogen"] - + fs.feed.properties[0].flow_mass_comp["nitrate"] - ) - exports.add( - obj=removal_TN, - name="Total N removal", - ui_units=pyunits.dimensionless, - display_units="fraction", - rounding=3, - description="Total N removal fraction [1 - outlet total N flow/inlet total N flow]", - is_input=False, - is_output=True, - output_category="Normalized performance metrics", - ) - - # Capital costs - exports.add( - obj=fs.costing.total_capital_cost, - name="Total", - ui_units=fs.costing.base_currency, - display_units="$", - rounding=0, - description="Total capital costs - including investment factor to account " - "for indirect capital", - is_input=False, - is_output=True, - output_category="Capital costs", - ) - exports.add( - obj=fs.mabr.costing.capital_cost, - name="MABR", - ui_units=fs.costing.base_currency, - display_units="$", - rounding=0, - description="MABR", - is_input=False, - is_output=True, - output_category="Capital costs", - ) - exports.add( - obj=fs.dmbr.costing.capital_cost, - name="DMBR", - ui_units=fs.costing.base_currency, - display_units="$", - rounding=0, - description="DMBR", - is_input=False, - is_output=True, - output_category="Capital costs", - ) - exports.add( - obj=fs.P1.costing.capital_cost, - name="Pump", - ui_units=fs.costing.base_currency, - display_units="$", - rounding=0, - description="Pump", - is_input=False, - is_output=True, - output_category="Capital costs", - ) - - # Operating costs - exports.add( - obj=fs.costing.total_operating_cost, - name="Total", - ui_units=fs.costing.base_currency / pyunits.year, - display_units="$/year", - rounding=0, - description="Total annual operating costs - including electricity, heating, " - "and fixed", - is_input=False, - is_output=True, - output_category="Operating costs", - ) - exports.add( - obj=fs.costing.aggregate_flow_costs["electricity"], - name="Electricity", - ui_units=fs.costing.base_currency / pyunits.year, - display_units="$/year", - rounding=0, - description="Annual electricity costs ", - is_input=False, - is_output=True, - output_category="Operating costs", - ) - exports.add( - obj=fs.costing.total_fixed_operating_cost, - name="Fixed", - ui_units=fs.costing.base_currency / pyunits.year, - display_units="$/year", - rounding=0, - description="Annual fixed operating costs - these costs include material " - "replacement, maintenance, and labor", - is_input=False, - is_output=True, - output_category="Operating costs", - ) - - -def build_flowsheet(build_options=None, **kwargs): - # build and solve initial flowsheet - m = build() - - set_operating_conditions(m) - assert_degrees_of_freedom(m, 0) - assert_units_consistent(m) - - initialize_system(m) - - results = solve(m) - assert_optimal_termination(results) - - add_costing(m) - assert_degrees_of_freedom(m, 0) - m.fs.costing.initialize() - - results = solve(m) - assert_optimal_termination(results) - return m - - -def solve_flowsheet(flowsheet=None): - fs = flowsheet - results = solve(fs) - return results diff --git a/watertap/examples/flowsheets/case_studies/wastewater_resource_recovery/electrochemical_nutrient_removal/electrochemical_nutrient_removal_ui.png b/watertap/examples/flowsheets/case_studies/wastewater_resource_recovery/electrochemical_nutrient_removal/electrochemical_nutrient_removal_ui.png deleted file mode 100644 index 4fd7c7d059..0000000000 Binary files a/watertap/examples/flowsheets/case_studies/wastewater_resource_recovery/electrochemical_nutrient_removal/electrochemical_nutrient_removal_ui.png and /dev/null differ diff --git a/watertap/examples/flowsheets/case_studies/wastewater_resource_recovery/electrochemical_nutrient_removal/electrochemical_nutrient_removal_ui.py b/watertap/examples/flowsheets/case_studies/wastewater_resource_recovery/electrochemical_nutrient_removal/electrochemical_nutrient_removal_ui.py deleted file mode 100644 index 6a4313f203..0000000000 --- a/watertap/examples/flowsheets/case_studies/wastewater_resource_recovery/electrochemical_nutrient_removal/electrochemical_nutrient_removal_ui.py +++ /dev/null @@ -1,569 +0,0 @@ -################################################################################# -# WaterTAP Copyright (c) 2020-2024, The Regents of the University of California, -# through Lawrence Berkeley National Laboratory, Oak Ridge National Laboratory, -# National Renewable Energy Laboratory, and National Energy Technology -# Laboratory (subject to receipt of any required approvals from the U.S. Dept. -# of Energy). All rights reserved. -# -# Please see the files COPYRIGHT.md and LICENSE.md for full copyright and license -# information, respectively. These files are also available online at the URL -# "https://github.com/watertap-org/watertap/" -################################################################################# -from watertap.ui.fsapi import FlowsheetInterface -from watertap.core.util.initialization import assert_degrees_of_freedom -from watertap.examples.flowsheets.case_studies.wastewater_resource_recovery.electrochemical_nutrient_removal.electrochemical_nutrient_removal import ( - build, - set_operating_conditions, - initialize_system, - solve, - add_costing, -) -from pyomo.environ import units as pyunits, assert_optimal_termination -from pyomo.util.check_units import assert_units_consistent - - -def export_to_ui(): - return FlowsheetInterface( - name="Electrochemical nutrient removal", - do_export=export_variables, - do_build=build_flowsheet, - do_solve=solve_flowsheet, - ) - - -def export_variables(flowsheet=None, exports=None, build_options=None, **kwargs): - fs = flowsheet - # --- Input data --- - # Feed conditions - exports.add( - obj=fs.feed.flow_vol[0], - name="Volumetric flow rate", - ui_units=pyunits.m**3 / pyunits.hr, - display_units="m3/h", - rounding=2, - description="Inlet volumetric flow rate", - is_input=True, - input_category="Feed", - is_output=True, - output_category="Feed", - ) - exports.add( - obj=fs.feed.conc_mass_comp[0, "nitrogen"], - name="Nitrogen concentration", - ui_units=pyunits.g / pyunits.L, - display_units="g/L", - rounding=2, - description="Inlet nitrogen concentration", - is_input=True, - input_category="Feed", - is_output=True, - output_category="Feed", - ) - exports.add( - obj=fs.feed.conc_mass_comp[0, "calcium"], - name="Calcium concentration", - ui_units=pyunits.g / pyunits.L, - display_units="g/L", - rounding=2, - description="Inlet calcium concentration", - is_input=True, - input_category="Feed", - is_output=True, - output_category="Feed", - ) - exports.add( - obj=fs.feed.conc_mass_comp[0, "phosphorus"], - name="Phosphorus concentration", - ui_units=pyunits.g / pyunits.L, - display_units="g/L", - rounding=2, - description="Inlet phosphorus concentration", - is_input=True, - input_category="Feed", - is_output=True, - output_category="Feed", - ) - - # Unit model data, pump - exports.add( - obj=fs.pump.lift_height, - name="Lift height", - ui_units=pyunits.m, - display_units="m", - rounding=2, - description="Lift height for pump", - is_input=True, - input_category="Pump", - is_output=False, - ) - exports.add( - obj=fs.pump.eta_pump, - name="Pump efficiency", - ui_units=pyunits.dimensionless, - display_units="fraction", - rounding=2, - description="Efficiency of pump", - is_input=True, - input_category="Pump", - is_output=False, - ) - exports.add( - obj=fs.pump.eta_motor, - name="Motor efficiency", - ui_units=pyunits.dimensionless, - display_units="fraction", - rounding=2, - description="Efficiency of motor", - is_input=True, - input_category="Pump", - is_output=False, - ) - - # Unit cost data, pump - exports.add( - obj=fs.costing.pump_electricity.pump_cost["default"], - name="Pump cost", - ui_units=fs.costing.base_currency / (pyunits.m**3 / pyunits.hr), - display_units="$/(m^3/hr)", - rounding=0, - description="Pump capital cost parameter", - is_input=True, - input_category="Pump costing", - is_output=False, - ) - # Unit model data, electroNP - exports.add( - obj=fs.electroNP.recovery_frac_mass_H2O[0], - name="Water recovery", - ui_units=pyunits.dimensionless, - display_units="fraction", # we should change to % - rounding=2, - description="Water recovery [g-H2O treated/g-H2O inlet]", - is_input=True, - input_category="ElectroNP", - is_output=False, - ) - exports.add( - obj=fs.electroNP.energy_electric_flow_mass, - name="Specific energy", - ui_units=pyunits.kWh / pyunits.kg, - display_units="kWh/kg of phosphorus removal", - rounding=2, - description="ElectroNP specific energy relating the energy to the mass of phosphorus removal", - is_input=True, - input_category="ElectroNP", - is_output=False, - ) - exports.add( - obj=fs.electroNP.magnesium_chloride_dosage, - name="MgCl2 Dosage", - ui_units=pyunits.dimensionless, - display_units="g MgCl2/g P", - rounding=2, - description="MgCl2 dosage per g of P removal", - is_input=True, - input_category="ElectroNP", - is_output=False, - ) - - # Unit cost data, electroNP - exports.add( - obj=fs.costing.electrochemical_nutrient_removal.HRT[None], - name="HRT", - ui_units=pyunits.hr, - display_units="h", - rounding=1, - description="Hydraulic retention time", - is_input=True, - input_category="ElectroNP costing", - is_output=False, - ) - exports.add( - obj=fs.costing.electrochemical_nutrient_removal.sizing_cost[None], - name="ElectroNP cost", - ui_units=fs.costing.base_currency / pyunits.m**3, - display_units="$/m3 of electroNP", - rounding=0, - description="ElectroNP capital cost parameter", - is_input=True, - input_category="ElectroNP costing", - is_output=False, - ) - # System costing - exports.add( - obj=fs.costing.utilization_factor, - name="Utilization factor", - ui_units=pyunits.dimensionless, - display_units="fraction", - rounding=2, - description="Utilization factor - [annual use hours/total hours in year]", - is_input=True, - input_category="System costing", - is_output=False, - ) - exports.add( - obj=fs.costing.TIC, - name="Practical investment factor", - ui_units=pyunits.dimensionless, - display_units="fraction", - rounding=1, - description="Practical investment factor - [total investment cost/direct " - "capital costs]", - is_input=True, - input_category="System costing", - is_output=False, - ) - exports.add( - obj=fs.costing.plant_lifetime, - name="Plant lifetime", - ui_units=pyunits.year, - display_units="years", - rounding=1, - description="Plant lifetime", - is_input=True, - input_category="System costing", - is_output=False, - ) - exports.add( - obj=fs.costing.wacc, - name="Discount rate", - ui_units=pyunits.dimensionless, - display_units="fraction", - rounding=2, - description="Discount rate used in calculating the capital annualization", - is_input=True, - input_category="System costing", - is_output=False, - ) - exports.add( - obj=fs.costing.maintenance_costs_percent_FCI, - name="Fixed operating cost factor", - ui_units=1 / pyunits.year, - display_units="fraction/year", - rounding=2, - description="Fixed operating cost factor - [annual fixed operating cost/total " - "investment cost]", - is_input=True, - input_category="System costing", - is_output=False, - ) - exports.add( - obj=fs.costing.electricity_cost, - name="Electricity cost", - ui_units=fs.costing.base_currency / pyunits.kWh, - display_units="$/kWh", - rounding=3, - description="Electricity cost", - is_input=True, - input_category="System costing", - is_output=False, - ) - exports.add( - obj=fs.costing.magnesium_chloride_cost, - name="MgCl2 cost", - ui_units=fs.costing.base_currency / pyunits.kg, - display_units="$/kg", - rounding=3, - description="Magnesium chloride cost", - is_input=True, - input_category="System costing", - is_output=False, - ) - - # Outlets - exports.add( - obj=fs.product_H2O.properties[0].flow_vol, - name="Product H2O flow rate", - ui_units=pyunits.m**3 / pyunits.hr, - display_units="m3/h", - rounding=2, - description="Outlet product H2O flow rate", - is_input=False, - is_output=True, - output_category="Outlets", - ) - exports.add( - obj=fs.product_H2O.properties[0].conc_mass_comp["nitrogen"], - name="Product water N2 concentration", - ui_units=pyunits.g / pyunits.L, - display_units="g/L", - rounding=3, - description="Outlet product water nitrogen concentration", - is_input=False, - is_output=True, - output_category="Outlets", - ) - exports.add( - obj=fs.product_H2O.properties[0].conc_mass_comp["phosphorus"], - name="Product water P concentration", - ui_units=pyunits.g / pyunits.L, - display_units="g/L", - rounding=3, - description="Outlet product water phosphorus concentration", - is_input=False, - is_output=True, - output_category="Outlets", - ) - - # System metrics - exports.add( - obj=fs.costing.LCOT, - name="LCOT", - ui_units=fs.costing.base_currency / pyunits.m**3, - display_units="$/m3 of feed", - rounding=3, - description="Levelized cost of treatment including operating and capital costs", - is_input=False, - is_output=True, - output_category="Levelized cost metrics", - ) - exports.add( - obj=fs.costing.LCOT_with_revenue, - name="LCOT with revenue", - ui_units=fs.costing.base_currency / pyunits.m**3, - display_units="$/m3 of feed", - rounding=3, - description="Levelized cost of treatment including consumption costs for MgCl2", - is_input=False, - is_output=True, - output_category="Levelized cost metrics", - ) - exports.add( - obj=fs.costing.LCOW, - name="LCOW", - ui_units=fs.costing.base_currency / pyunits.m**3, - display_units="$/m3 of centrate", - rounding=3, - description="Levelized cost of water including operating and capital costs", - is_input=False, - is_output=True, - output_category="Levelized cost metrics", - ) - exports.add( - obj=fs.costing.LCOW_with_revenue, - name="LCOW with revenue", - ui_units=fs.costing.base_currency / pyunits.m**3, - display_units="$/m3 of centrate", - rounding=3, - description="Levelized cost of water including consumption costs for MgCl2", - is_input=False, - is_output=True, - output_category="Levelized cost metrics", - ) - exports.add( - obj=fs.costing.LCOP, - name="Levelized cost of phosphorus recovery", - ui_units=fs.costing.base_currency / pyunits.kg, - display_units="$/kg-P", - rounding=3, - description="Levelized cost of phosphorus recovery including operating and capital costs", - is_input=False, - is_output=True, - output_category="Levelized cost metrics", - ) # Normalized metrics - total_capital_norm = fs.costing.total_capital_cost / fs.feed.properties[0].flow_vol - exports.add( - obj=total_capital_norm, - name="Total capital", - ui_units=fs.costing.base_currency / (pyunits.m**3 / pyunits.day), - display_units="$/(m3/day)", - rounding=1, - description="Normalized total capital costs accounting for indirect " - "capital and installation - [total capital costs/feed flow rate]", - is_input=False, - is_output=True, - output_category="Normalized cost metrics", - ) - direct_capital_norm = ( - (fs.pump.costing.capital_cost + fs.electroNP.costing.capital_cost) - / fs.costing.TIC - / fs.feed.properties[0].flow_vol - ) - exports.add( - obj=direct_capital_norm, - name="Direct capital", - ui_units=fs.costing.base_currency / (pyunits.m**3 / pyunits.day), - display_units="$/(m3/day)", - rounding=1, - description="Normalized direct capital costs - [total direct capital " - "costs/feed flow rate] ", - is_input=False, - is_output=True, - output_category="Normalized cost metrics", - ) - elec_operating_norm = ( - fs.costing.aggregate_flow_costs["electricity"] / fs.costing.annual_water_inlet - ) - exports.add( - obj=elec_operating_norm, - name="Electricity", - ui_units=fs.costing.base_currency / pyunits.m**3, - display_units="$/m3 of feed", - rounding=2, - description="Normalized electricity cost - [annual electricity costs/annual " - "feed flow rate]", - is_input=False, - is_output=True, - output_category="Normalized cost metrics", - ) - - # performance metrics - recovery_vol = ( - fs.product_H2O.properties[0].flow_vol / fs.feed.properties[0].flow_vol - ) - exports.add( - obj=recovery_vol, - name="Volumetric recovery", - ui_units=pyunits.dimensionless, - display_units="m3 of product/m3 of feed", - rounding=3, - description="Normalized volumetric recovery", - is_input=False, - is_output=True, - output_category="Normalized performance metrics", - ) - removal_nitrogen = ( - 1 - - fs.product_H2O.properties[0].flow_mass_comp["nitrogen"] - / fs.feed.properties[0].flow_mass_comp["nitrogen"] - ) - exports.add( - obj=removal_nitrogen, - name="Nitrogen removal", - ui_units=pyunits.dimensionless, - display_units="fraction", - rounding=3, - description="Nitrogen removal fraction [1 - outlet N2 flow/inlet N2 flow]", - is_input=False, - is_output=True, - output_category="Normalized performance metrics", - ) - removal_phosphorus = ( - 1 - - fs.product_H2O.properties[0].flow_mass_comp["phosphorus"] - / fs.feed.properties[0].flow_mass_comp["phosphorus"] - ) - exports.add( - obj=removal_phosphorus, - name="Phosphorus removal", - ui_units=pyunits.dimensionless, - display_units="fraction", - rounding=3, - description="Phosphorus removal fraction [1 - outlet P flow/inlet P flow]", - is_input=False, - is_output=True, - output_category="Normalized performance metrics", - ) - - # Capital costs - exports.add( - obj=fs.costing.total_capital_cost, - name="Total", - ui_units=fs.costing.base_currency, - display_units="$", - rounding=0, - description="Total capital costs - including investment factor to account " - "for indirect capital", - is_input=False, - is_output=True, - output_category="Capital costs", - ) - exports.add( - obj=fs.pump.costing.capital_cost, - name="Pump", - ui_units=fs.costing.base_currency, - display_units="$", - rounding=0, - description="Pump", - is_input=False, - is_output=True, - output_category="Capital costs", - ) - exports.add( - obj=fs.electroNP.costing.capital_cost, - name="ElectroNP", - ui_units=fs.costing.base_currency, - display_units="$", - rounding=0, - description="ElectroNP", - is_input=False, - is_output=True, - output_category="Capital costs", - ) - # Operating costs - exports.add( - obj=fs.costing.total_operating_cost, - name="Total", - ui_units=fs.costing.base_currency / pyunits.year, - display_units="$/year", - rounding=0, - description="Total annual operating costs - including electricity, heating, " - "and fixed", - is_input=False, - is_output=True, - output_category="Operating costs", - ) - exports.add( - obj=fs.costing.aggregate_flow_costs["electricity"], - name="Electricity", - ui_units=fs.costing.base_currency / pyunits.year, - display_units="$/year", - rounding=0, - description="Annual electricity costs ", - is_input=False, - is_output=True, - output_category="Operating costs", - ) - exports.add( - obj=fs.costing.total_fixed_operating_cost, - name="Fixed", - ui_units=fs.costing.base_currency / pyunits.year, - display_units="$/year", - rounding=0, - description="Annual fixed operating costs - these costs include material " - "replacement, maintenance, and labor", - is_input=False, - is_output=True, - output_category="Operating costs", - ) - - # Cost - exports.add( - obj=-fs.costing.aggregate_flow_costs["magnesium_chloride"], - name="Magnesium chloride", - ui_units=fs.costing.base_currency / pyunits.year, - display_units="$/year", - rounding=0, - description="Cost from buying magnesium chloride", - is_input=False, - is_output=True, - output_category="Revenue", - ) - - -def build_flowsheet(build_options=None, **kwargs): - # build and solve initial flowsheet - m = build() - - set_operating_conditions(m) - assert_degrees_of_freedom(m, 0) - assert_units_consistent(m) - - initialize_system(m) - - results = solve(m) - assert_optimal_termination(results) - - add_costing(m) - assert_degrees_of_freedom(m, 0) - m.fs.costing.initialize() - - results = solve(m) - assert_optimal_termination(results) - return m - - -def solve_flowsheet(flowsheet=None): - fs = flowsheet - results = solve(fs) - return results diff --git a/watertap/examples/flowsheets/case_studies/wastewater_resource_recovery/groundwater_treatment/groundwater_treatment_ui.png b/watertap/examples/flowsheets/case_studies/wastewater_resource_recovery/groundwater_treatment/groundwater_treatment_ui.png deleted file mode 100644 index 545a3ed91c..0000000000 Binary files a/watertap/examples/flowsheets/case_studies/wastewater_resource_recovery/groundwater_treatment/groundwater_treatment_ui.png and /dev/null differ diff --git a/watertap/examples/flowsheets/case_studies/wastewater_resource_recovery/groundwater_treatment/groundwater_treatment_ui.py b/watertap/examples/flowsheets/case_studies/wastewater_resource_recovery/groundwater_treatment/groundwater_treatment_ui.py deleted file mode 100644 index 4e806df373..0000000000 --- a/watertap/examples/flowsheets/case_studies/wastewater_resource_recovery/groundwater_treatment/groundwater_treatment_ui.py +++ /dev/null @@ -1,753 +0,0 @@ -################################################################################# -# WaterTAP Copyright (c) 2020-2024, The Regents of the University of California, -# through Lawrence Berkeley National Laboratory, Oak Ridge National Laboratory, -# National Renewable Energy Laboratory, and National Energy Technology -# Laboratory (subject to receipt of any required approvals from the U.S. Dept. -# of Energy). All rights reserved. -# -# Please see the files COPYRIGHT.md and LICENSE.md for full copyright and license -# information, respectively. These files are also available online at the URL -# "https://github.com/watertap-org/watertap/" -################################################################################# -from watertap.ui.fsapi import FlowsheetInterface -from watertap.core.util.initialization import assert_degrees_of_freedom -from watertap.examples.flowsheets.case_studies.wastewater_resource_recovery.groundwater_treatment.groundwater_treatment import ( - build, - set_operating_conditions, - initialize_system, - solve, - add_costing, -) -from pyomo.environ import units as pyunits, assert_optimal_termination -from pyomo.util.check_units import assert_units_consistent - - -def export_to_ui(): - return FlowsheetInterface( - name="Groundwater treatment", - do_export=export_variables, - do_build=build_flowsheet, - do_solve=solve_flowsheet, - ) - - -def export_variables(flowsheet=None, exports=None, build_options=None, **kwargs): - fs = flowsheet - # --- Input data --- - # Feed conditions - exports.add( - obj=fs.feed.flow_vol[0], - name="Volumetric flow rate", - ui_units=pyunits.m**3 / pyunits.hr, - display_units="m3/h", - rounding=2, - description="Inlet volumetric flow rate", - is_input=True, - input_category="Feed", - is_output=True, - output_category="Feed", - ) - exports.add( - obj=fs.feed.conc_mass_comp[0, "arsenic"], - name="Arsenic concentration", - ui_units=pyunits.mg / pyunits.L, - display_units="mg/L", - rounding=2, - description="Inlet arsenic concentration", - is_input=True, - input_category="Feed", - is_output=True, - output_category="Feed", - ) - exports.add( - obj=fs.feed.conc_mass_comp[0, "uranium"], - name="Uranium concentration", - ui_units=pyunits.mg / pyunits.L, - display_units="mg/L", - rounding=2, - description="Inlet uranium concentration", - is_input=True, - input_category="Feed", - is_output=True, - output_category="Feed", - ) - exports.add( - obj=fs.feed.conc_mass_comp[0, "nitrate"], - name="Nitrate concentration", - ui_units=pyunits.mg / pyunits.L, - display_units="mg/L", - rounding=2, - description="Inlet nitrate concentration", - is_input=True, - input_category="Feed", - is_output=True, - output_category="Feed", - ) - exports.add( - obj=fs.feed.conc_mass_comp[0, "phosphates"], - name="Phosphates concentration", - ui_units=pyunits.mg / pyunits.L, - display_units="mg/L", - rounding=2, - description="Inlet phosphates concentration", - is_input=True, - input_category="Feed", - is_output=True, - output_category="Feed", - ) - exports.add( - obj=fs.feed.conc_mass_comp[0, "iron"], - name="Iron concentration", - ui_units=pyunits.mg / pyunits.L, - display_units="mg/L", - rounding=2, - description="Inlet iron concentration", - is_input=True, - input_category="Feed", - is_output=True, - output_category="Feed", - ) - exports.add( - obj=fs.feed.conc_mass_comp[0, "filtration_media"], - name="Filtration media concentration", - ui_units=pyunits.mg / pyunits.L, - display_units="mg/L", - rounding=2, - description="Inlet filtration media concentration", - is_input=True, - input_category="Feed", - is_output=True, - output_category="Feed", - ) - - # Unit model data, pump - exports.add( - obj=fs.pump.lift_height, - name="Lift height", - ui_units=pyunits.m, - display_units="m", - rounding=2, - description="Lift height for pump", - is_input=True, - input_category="Pump", - is_output=False, - ) - exports.add( - obj=fs.pump.eta_pump, - name="Pump efficiency", - ui_units=pyunits.dimensionless, - display_units="fraction", - rounding=2, - description="Efficiency of pump", - is_input=True, - input_category="Pump", - is_output=False, - ) - exports.add( - obj=fs.pump.eta_motor, - name="Motor efficiency", - ui_units=pyunits.dimensionless, - display_units="fraction", - rounding=2, - description="Efficiency of motor", - is_input=True, - input_category="Pump", - is_output=False, - ) - - # Unit cost data, pump - exports.add( - obj=fs.costing.pump_electricity.pump_cost[None], - name="Pump cost", - ui_units=fs.costing.base_currency / (pyunits.m**3 / pyunits.hr), - display_units="$/(m^3/hr)", - rounding=0, - description="Pump capital cost parameter", - is_input=True, - input_category="Pump costing", - is_output=False, - ) - - # Unit model data, microbial battery - exports.add( - obj=fs.micbatt.recovery_frac_mass_H2O[0], - name="Water recovery", - ui_units=pyunits.dimensionless, - display_units="fraction", # we should change to % - rounding=2, - description="Water recovery [g-H2O treated/g-H2O inlet]", - is_input=True, - input_category="Microbial battery", - is_output=False, - ) - exports.add( - obj=fs.micbatt.reaction_conversion[0, "iron_precipitation"], - name="Iron conversion", - ui_units=pyunits.dimensionless, - display_units="fraction", # we should change to % - rounding=2, - description="Iron conversion [g-Fe reacted/g-Fe inlet]", - is_input=True, - input_category="Microbial battery", - is_output=False, - ) - exports.add( - obj=fs.micbatt.removal_frac_mass_comp[0, "arsenic"], - name="Arsenic removal", - ui_units=pyunits.dimensionless, - display_units="fraction", # we should change to % - rounding=2, - description="Arsenic removal [g-As removed/g-As inlet]", - is_input=True, - input_category="Microbial battery", - is_output=False, - ) - exports.add( - obj=fs.micbatt.removal_frac_mass_comp[0, "uranium"], - name="Uranium removal", - ui_units=pyunits.dimensionless, - display_units="fraction", # we should change to % - rounding=2, - description="Uranium removal [g-U removed/g-U inlet]", - is_input=True, - input_category="Microbial battery", - is_output=False, - ) - exports.add( - obj=fs.micbatt.removal_frac_mass_comp[0, "nitrate"], - name="Nitrate removal", - ui_units=pyunits.dimensionless, - display_units="fraction", # we should change to % - rounding=2, - description="Nitrate removal [g-nitrate removed/g-nitrate inlet]", - is_input=True, - input_category="Microbial battery", - is_output=False, - ) - exports.add( - obj=fs.micbatt.removal_frac_mass_comp[0, "phosphates"], - name="Phosphates removal", - ui_units=pyunits.dimensionless, - display_units="fraction", # we should change to % - rounding=2, - description="Phosphates removal [g-P removed/g-P inlet]", - is_input=True, - input_category="Microbial battery", - is_output=False, - ) - exports.add( - obj=fs.micbatt.energy_electric_flow_vol_inlet, - name="Electricity intensity", - ui_units=pyunits.kWh / pyunits.m**3, - display_units="kWh/m3", - rounding=2, - description="Electricity intensity relating the intensity to the product volume", - is_input=True, - input_category="Microbial battery", - is_output=False, - ) - exports.add( - obj=fs.micbatt.HRT, - name="HRT", - ui_units=pyunits.hr, - display_units="h", - rounding=1, - description="Hydraulic retention time", - is_input=True, - input_category="Microbial battery", - is_output=False, - ) - # Unit cost data, microbial battery - exports.add( - obj=fs.costing.microbial_battery.sizing_cost[None], - name="Microbial battery cost", - ui_units=(fs.costing.base_currency * pyunits.day) / pyunits.m**3, - display_units="($ * day)/m3 of microbial battery", - rounding=0, - description="Microbial battery capital cost parameter", - is_input=True, - input_category="Microbial battery costing", - is_output=False, - ) - # System costing - exports.add( - obj=fs.costing.utilization_factor, - name="Utilization factor", - ui_units=pyunits.dimensionless, - display_units="fraction", - rounding=2, - description="Utilization factor - [annual use hours/total hours in year]", - is_input=True, - input_category="System costing", - is_output=False, - ) - exports.add( - obj=fs.costing.TIC, - name="Practical investment factor", - ui_units=pyunits.dimensionless, - display_units="fraction", - rounding=1, - description="Practical investment factor - [total investment cost/direct " - "capital costs]", - is_input=True, - input_category="System costing", - is_output=False, - ) - exports.add( - obj=fs.costing.plant_lifetime, - name="Plant lifetime", - ui_units=pyunits.year, - display_units="years", - rounding=1, - description="Plant lifetime", - is_input=True, - input_category="System costing", - is_output=False, - ) - exports.add( - obj=fs.costing.wacc, - name="Discount rate", - ui_units=pyunits.dimensionless, - display_units="fraction", - rounding=2, - description="Discount rate used in calculating the capital annualization", - is_input=True, - input_category="System costing", - is_output=False, - ) - exports.add( - obj=fs.costing.maintenance_costs_percent_FCI, - name="Fixed operating cost factor", - ui_units=1 / pyunits.year, - display_units="fraction/year", - rounding=2, - description="Fixed operating cost factor - [annual fixed operating cost/total " - "investment cost]", - is_input=True, - input_category="System costing", - is_output=False, - ) - exports.add( - obj=fs.costing.electricity_cost, - name="Electricity cost", - ui_units=fs.costing.base_currency / pyunits.kWh, - display_units="$/kWh", - rounding=3, - description="Electricity cost", - is_input=True, - input_category="System costing", - is_output=False, - ) - exports.add( - obj=fs.costing.filtration_media_cost, - name="Filtration media cost", - ui_units=fs.costing.base_currency / pyunits.kg, - display_units="$/kg", - rounding=3, - description="Filtration media cost", - is_input=True, - input_category="System costing", - is_output=False, - ) - exports.add( - obj=fs.costing.filtration_media_disposal_cost, - name="Filtration media disposal cost", - ui_units=fs.costing.base_currency / pyunits.kg, - display_units="$/kg", - rounding=3, - description="Filtration media disposal cost", - is_input=True, - input_category="System costing", - is_output=False, - ) - # Outlets - exports.add( - obj=fs.filtered_water.properties[0].flow_vol, - name="Filtered water flow rate", - ui_units=pyunits.m**3 / pyunits.hr, - display_units="m3/h", - rounding=2, - description="Outlet filtered water flow rate", - is_input=False, - is_output=True, - output_category="Outlets", - ) - exports.add( - obj=fs.filtered_water.properties[0].conc_mass_comp["arsenic"], - name="Filtered water arsenic concentration", - ui_units=pyunits.mg / pyunits.L, - display_units="mg/L", - rounding=3, - description="Outlet filtered water arsenic concentration", - is_input=False, - is_output=True, - output_category="Outlets", - ) - exports.add( - obj=fs.filtered_water.properties[0].conc_mass_comp["uranium"], - name="Filtered water uranium concentration", - ui_units=pyunits.mg / pyunits.L, - display_units="mg/L", - rounding=3, - description="Outlet filtered water uranium concentration", - is_input=False, - is_output=True, - output_category="Outlets", - ) - exports.add( - obj=fs.filtered_water.properties[0].conc_mass_comp["nitrate"], - name="Filtered water nitrate concentration", - ui_units=pyunits.mg / pyunits.L, - display_units="mg/L", - rounding=3, - description="Outlet filtered water nitrate concentration", - is_input=False, - is_output=True, - output_category="Outlets", - ) - exports.add( - obj=fs.filtered_water.properties[0].conc_mass_comp["phosphates"], - name="Filtered water phosphates concentration", - ui_units=pyunits.mg / pyunits.L, - display_units="mg/L", - rounding=3, - description="Outlet filtered water phosphates concentration", - is_input=False, - is_output=True, - output_category="Outlets", - ) - exports.add( - obj=fs.byproduct.properties[0].flow_mass_comp["arsenic"], - name="Byproduct arsenic flow rate", - ui_units=pyunits.mg / pyunits.day, - display_units="mg-arsenic/day", - rounding=5, - description="Outlet byproduct arsenic flow rate", - is_input=False, - is_output=True, - output_category="Outlets", - ) - exports.add( - obj=fs.byproduct.properties[0].flow_mass_comp["uranium"], - name="Byproduct uranium flow rate", - ui_units=pyunits.mg / pyunits.day, - display_units="mg-uranium/day", - rounding=5, - description="Outlet byproduct uranium flow rate", - is_input=False, - is_output=True, - output_category="Outlets", - ) - exports.add( - obj=fs.byproduct.properties[0].flow_mass_comp["nitrate"], - name="Byproduct nitrate flow rate", - ui_units=pyunits.mg / pyunits.day, - display_units="mg-nitrate/day", - rounding=5, - description="Outlet byproduct nitrate flow rate", - is_input=False, - is_output=True, - output_category="Outlets", - ) - exports.add( - obj=fs.byproduct.properties[0].flow_mass_comp["phosphates"], - name="Byproduct phosphates flow rate", - ui_units=pyunits.mg / pyunits.day, - display_units="mg-phosphates/day", - rounding=5, - description="Outlet byproduct phosphates flow rate", - is_input=False, - is_output=True, - output_category="Outlets", - ) - exports.add( - obj=fs.byproduct.properties[0].flow_mass_comp["filtration_media"], - name="Byproduct filtration media flow rate", - ui_units=pyunits.mg / pyunits.day, - display_units="mg-media/day", - rounding=5, - description="Outlet byproduct filtration media flow rate", - is_input=False, - is_output=True, - output_category="Outlets", - ) - # System metrics - exports.add( - obj=fs.costing.LCOT, - name="LCOT", - ui_units=fs.costing.base_currency / pyunits.m**3, - display_units="$/m3 of feed", - rounding=3, - description="Levelized cost of treatment including operating and capital costs", - is_input=False, - is_output=True, - output_category="Levelized cost metrics", - ) - exports.add( - obj=fs.costing.LCOW, - name="LCOW", - ui_units=fs.costing.base_currency / pyunits.m**3, - display_units="$/m3 of treated water", - rounding=3, - description="Levelized cost of water including operating and capital costs", - is_input=False, - is_output=True, - output_category="Levelized cost metrics", - ) - # Normalized metrics - total_capital_norm = fs.costing.total_capital_cost / fs.feed.properties[0].flow_vol - exports.add( - obj=total_capital_norm, - name="Total capital", - ui_units=fs.costing.base_currency / (pyunits.m**3 / pyunits.day), - display_units="$/(m3/day)", - rounding=1, - description="Normalized total capital costs accounting for indirect " - "capital and installation - [total capital costs/feed flow rate]", - is_input=False, - is_output=True, - output_category="Normalized cost metrics", - ) - direct_capital_norm = ( - (fs.pump.costing.capital_cost + fs.micbatt.costing.capital_cost) - / fs.costing.TIC - / fs.feed.properties[0].flow_vol - ) - exports.add( - obj=direct_capital_norm, - name="Direct capital", - ui_units=fs.costing.base_currency / (pyunits.m**3 / pyunits.day), - display_units="$/(m3/day)", - rounding=1, - description="Normalized direct capital costs - [total direct capital " - "costs/feed flow rate] ", - is_input=False, - is_output=True, - output_category="Normalized cost metrics", - ) - elec_operating_norm = ( - fs.costing.aggregate_flow_costs["electricity"] / fs.costing.annual_water_inlet - ) - exports.add( - obj=elec_operating_norm, - name="Electricity", - ui_units=fs.costing.base_currency / pyunits.m**3, - display_units="$/m3 of feed", - rounding=2, - description="Normalized electricity cost - [annual electricity costs/annual " - "feed flow rate]", - is_input=False, - is_output=True, - output_category="Normalized cost metrics", - ) - - # performance metrics - recovery_vol = ( - fs.filtered_water.properties[0].flow_vol / fs.feed.properties[0].flow_vol - ) - exports.add( - obj=recovery_vol, - name="Volumetric recovery", - ui_units=pyunits.dimensionless, - display_units="m3 of product/m3 of feed", - rounding=3, - description="Normalized volumetric recovery", - is_input=False, - is_output=True, - output_category="Normalized performance metrics", - ) - removal_arsenic = ( - 1 - - fs.filtered_water.properties[0].flow_mass_comp["arsenic"] - / fs.feed.properties[0].flow_mass_comp["arsenic"] - ) - exports.add( - obj=removal_arsenic, - name="Arsenic removal", - ui_units=pyunits.dimensionless, - display_units="fraction", - rounding=3, - description="Arsenic removal fraction [1 - outlet As flow/inlet As flow]", - is_input=False, - is_output=True, - output_category="Normalized performance metrics", - ) - removal_uranium = ( - 1 - - fs.filtered_water.properties[0].flow_mass_comp["uranium"] - / fs.feed.properties[0].flow_mass_comp["uranium"] - ) - exports.add( - obj=removal_uranium, - name="Uranium removal", - ui_units=pyunits.dimensionless, - display_units="fraction", - rounding=3, - description="Uranium removal fraction [1 - outlet U flow/inlet U flow]", - is_input=False, - is_output=True, - output_category="Normalized performance metrics", - ) - removal_nitrate = ( - 1 - - fs.filtered_water.properties[0].flow_mass_comp["nitrate"] - / fs.feed.properties[0].flow_mass_comp["nitrate"] - ) - exports.add( - obj=removal_nitrate, - name="Nitrate removal", - ui_units=pyunits.dimensionless, - display_units="fraction", - rounding=3, - description="Nitrate removal fraction [1 - outlet NO3 flow/inlet NO3 flow]", - is_input=False, - is_output=True, - output_category="Normalized performance metrics", - ) - removal_phosphates = ( - 1 - - fs.filtered_water.properties[0].flow_mass_comp["phosphates"] - / fs.feed.properties[0].flow_mass_comp["phosphates"] - ) - exports.add( - obj=removal_phosphates, - name="Phosphates removal", - ui_units=pyunits.dimensionless, - display_units="fraction", - rounding=3, - description="Phosphates removal fraction [1 - outlet P flow/inlet P flow]", - is_input=False, - is_output=True, - output_category="Normalized performance metrics", - ) - removal_iron = ( - 1 - - fs.filtered_water.properties[0].flow_mass_comp["iron"] - / fs.feed.properties[0].flow_mass_comp["iron"] - ) - exports.add( - obj=removal_iron, - name="Iron removal", - ui_units=pyunits.dimensionless, - display_units="fraction", - rounding=3, - description="Iron removal fraction [1 - outlet Fe flow/inlet Fe flow]", - is_input=False, - is_output=True, - output_category="Normalized performance metrics", - ) - removal_filtration_media = ( - 1 - - fs.filtered_water.properties[0].flow_mass_comp["filtration_media"] - / fs.feed.properties[0].flow_mass_comp["filtration_media"] - ) - exports.add( - obj=removal_filtration_media, - name="Filtration media removal", - ui_units=pyunits.dimensionless, - display_units="fraction", - rounding=3, - description="Filtration media removal fraction [1 - outlet media flow/inlet media flow]", - is_input=False, - is_output=True, - output_category="Normalized performance metrics", - ) - # Capital costs - exports.add( - obj=fs.costing.total_capital_cost, - name="Total", - ui_units=fs.costing.base_currency, - display_units="$", - rounding=0, - description="Total capital costs - including investment factor to account " - "for indirect capital", - is_input=False, - is_output=True, - output_category="Capital costs", - ) - exports.add( - obj=fs.pump.costing.capital_cost, - name="Pump", - ui_units=fs.costing.base_currency, - display_units="$", - rounding=0, - description="Pump", - is_input=False, - is_output=True, - output_category="Capital costs", - ) - exports.add( - obj=fs.micbatt.costing.capital_cost, - name="Microbial battery", - ui_units=fs.costing.base_currency, - display_units="$", - rounding=0, - description="Microbial battery", - is_input=False, - is_output=True, - output_category="Capital costs", - ) - # Operating costs - exports.add( - obj=fs.costing.total_operating_cost, - name="Total", - ui_units=fs.costing.base_currency / pyunits.year, - display_units="$/year", - rounding=0, - description="Total annual operating costs - including electricity, heating, " - "and fixed", - is_input=False, - is_output=True, - output_category="Operating costs", - ) - exports.add( - obj=fs.costing.aggregate_flow_costs["electricity"], - name="Electricity", - ui_units=fs.costing.base_currency / pyunits.year, - display_units="$/year", - rounding=0, - description="Annual electricity costs ", - is_input=False, - is_output=True, - output_category="Operating costs", - ) - exports.add( - obj=fs.costing.total_fixed_operating_cost, - name="Fixed", - ui_units=fs.costing.base_currency / pyunits.year, - display_units="$/year", - rounding=0, - description="Annual fixed operating costs - these costs include material " - "replacement, maintenance, and labor", - is_input=False, - is_output=True, - output_category="Operating costs", - ) - - -def build_flowsheet(build_options=None, **kwargs): - # build and solve initial flowsheet - m = build() - - set_operating_conditions(m) - assert_degrees_of_freedom(m, 0) - assert_units_consistent(m) - - initialize_system(m) - - results = solve(m) - assert_optimal_termination(results) - - add_costing(m) - assert_degrees_of_freedom(m, 0) - m.fs.costing.initialize() - - results = solve(m) - assert_optimal_termination(results) - return m - - -def solve_flowsheet(flowsheet=None): - fs = flowsheet - results = solve(fs) - return results diff --git a/watertap/examples/flowsheets/case_studies/wastewater_resource_recovery/metab/metab.py b/watertap/examples/flowsheets/case_studies/wastewater_resource_recovery/metab/metab.py index 2f39e8e7f5..f3c4303466 100644 --- a/watertap/examples/flowsheets/case_studies/wastewater_resource_recovery/metab/metab.py +++ b/watertap/examples/flowsheets/case_studies/wastewater_resource_recovery/metab/metab.py @@ -480,42 +480,6 @@ def rule_LCOCR_comp(b, c): m.fs.costing.LCOCR_comp = Expression(m.fs.costing.LC_comp, rule=rule_LCOCR_comp) -def adjust_default_parameters(m): - m.fs.metab_hydrogen.hydraulic_retention_time.fix(6) # default - 12 hours, 0.5x - m.fs.metab_hydrogen.generation_ratio["cod_to_hydrogen", "hydrogen"].set_value( - 0.05 - ) # default - 0.005, 10x - m.fs.costing.metab.bead_bulk_density["hydrogen"].fix(7.17) # default 23.9, 0.3x - m.fs.costing.metab.bead_replacement_factor["hydrogen"].fix(1) # default 3.376, 0.3x - m.fs.metab_hydrogen.energy_electric_mixer_vol.fix(0.049875) # default 0.049875 - m.fs.metab_hydrogen.energy_electric_vacuum_flow_vol_byproduct.fix( - 9.190 - ) # default 9190, 0.001x - m.fs.metab_hydrogen.energy_thermal_flow_vol_inlet.fix(7875) # default 78750, 0.1x - m.fs.costing.metab.bead_cost["hydrogen"].fix(14.40) # default 1440, 0.01x - m.fs.costing.metab.reactor_cost["hydrogen"].fix(78.9) # default 789, 0.1x - m.fs.costing.metab.vacuum_cost["hydrogen"].fix(5930) # default 59300, 0.1x - m.fs.costing.metab.mixer_cost["hydrogen"].fix(27.40) # default 2740, 0.01x - m.fs.costing.metab.membrane_cost["hydrogen"].fix(498) # default 498 - - m.fs.metab_methane.hydraulic_retention_time.fix(15) # default 150, 0.1x - m.fs.metab_methane.generation_ratio["cod_to_methane", "methane"].set_value( - 0.101 - ) # default 0.101, no change - m.fs.costing.metab.bead_bulk_density["methane"].fix(7.17) # default 23.9, 0.3x - m.fs.costing.metab.bead_replacement_factor["methane"].fix(1) # default 3.376, 0.3x - m.fs.metab_methane.energy_electric_mixer_vol.fix(0.049875) # default 0.049875 - m.fs.metab_methane.energy_electric_vacuum_flow_vol_byproduct.fix( - 1.53 - ) # default 15.3, 0.1x - m.fs.metab_methane.energy_thermal_flow_vol_inlet.fix(0) # default 0 - m.fs.costing.metab.bead_cost["methane"].fix(14.40) # default 1440, 0.01x - m.fs.costing.metab.reactor_cost["methane"].fix(78.9) # default 789, 0.1x - m.fs.costing.metab.vacuum_cost["methane"].fix(136.0) # default 1360, 0.1x - m.fs.costing.metab.mixer_cost["methane"].fix(27.40) # default 2740, 0.01x - m.fs.costing.metab.membrane_cost["methane"].fix(498) # default 498 - - def display_metrics_results(m): print("----------Levelized costs----------") LCOT = value( diff --git a/watertap/examples/flowsheets/case_studies/wastewater_resource_recovery/metab/metab_ui.png b/watertap/examples/flowsheets/case_studies/wastewater_resource_recovery/metab/metab_ui.png deleted file mode 100644 index 7ec95cf85b..0000000000 Binary files a/watertap/examples/flowsheets/case_studies/wastewater_resource_recovery/metab/metab_ui.png and /dev/null differ diff --git a/watertap/examples/flowsheets/case_studies/wastewater_resource_recovery/metab/metab_ui.py b/watertap/examples/flowsheets/case_studies/wastewater_resource_recovery/metab/metab_ui.py deleted file mode 100644 index 33b4827c5c..0000000000 --- a/watertap/examples/flowsheets/case_studies/wastewater_resource_recovery/metab/metab_ui.py +++ /dev/null @@ -1,917 +0,0 @@ -################################################################################# -# WaterTAP Copyright (c) 2020-2024, The Regents of the University of California, -# through Lawrence Berkeley National Laboratory, Oak Ridge National Laboratory, -# National Renewable Energy Laboratory, and National Energy Technology -# Laboratory (subject to receipt of any required approvals from the U.S. Dept. -# of Energy). All rights reserved. -# -# Please see the files COPYRIGHT.md and LICENSE.md for full copyright and license -# information, respectively. These files are also available online at the URL -# "https://github.com/watertap-org/watertap/" -################################################################################# -from watertap.ui.fsapi import FlowsheetInterface -from watertap.core.util.initialization import assert_degrees_of_freedom -from watertap.examples.flowsheets.case_studies.wastewater_resource_recovery.metab.metab import ( - build, - set_operating_conditions, - initialize_system, - solve, - add_costing, - adjust_default_parameters, -) -from pyomo.environ import units as pyunits, assert_optimal_termination -from pyomo.util.check_units import assert_units_consistent - - -def export_to_ui(): - return FlowsheetInterface( - name="Metab", - do_export=export_variables, - do_build=build_flowsheet, - do_solve=solve_flowsheet, - ) - - -def export_variables(flowsheet=None, exports=None, build_options=None, **kwargs): - fs = flowsheet - # --- Input data --- - # Feed conditions - exports.add( - obj=fs.feed.flow_vol[0], - name="Volumetric flow rate", - ui_units=pyunits.m**3 / pyunits.hr, - display_units="m3/h", - rounding=2, - description="Inlet volumetric flow rate", - is_input=True, - input_category="Feed", - is_output=True, - output_category="Feed", - ) - exports.add( - obj=fs.feed.conc_mass_comp[0, "cod"], - name="COD concentration", - ui_units=pyunits.g / pyunits.L, - display_units="g/L", # can this be done by default? - rounding=2, - description="Inlet chemical oxygen demand (COD) concentration", - is_input=True, - input_category="Feed", - is_output=True, - output_category="Feed", - ) - - # Unit model data, hydrogen reactor - exports.add( - obj=fs.metab_hydrogen.recovery_frac_mass_H2O[0], - name="Water recovery", - ui_units=pyunits.dimensionless, - display_units="fraction", # we should change to % - rounding=2, - description="Water recovery [g-H2O treated/g-H2O inlet]", - is_input=True, - input_category="Hydrogen reactor", - is_output=False, - ) - exports.add( - obj=fs.metab_hydrogen.reaction_conversion[0, "cod_to_hydrogen"], - name="COD conversion", - ui_units=pyunits.dimensionless, - display_units="fraction", # we should change to % - rounding=2, - description="COD conversion [g-COD reacted/g-COD inlet]", - is_input=True, - input_category="Hydrogen reactor", - is_output=False, - ) - exports.add( - obj=fs.metab_hydrogen.generation_ratio["cod_to_hydrogen", "hydrogen"], - name="H2 conversion ratio", - ui_units=pyunits.dimensionless, - display_units="fraction", - rounding=2, - description="H2 mass conversion ratio with respect to COD [g-H2 produced/g-COD" - " reacted]", - is_input=True, - input_category="Hydrogen reactor", - is_output=False, - ) - exports.add( - obj=fs.metab_hydrogen.hydraulic_retention_time, - name="HRT", - ui_units=pyunits.hr, - display_units="h", - rounding=1, - description="Hydraulic retention time", - is_input=True, - input_category="Hydrogen reactor", - is_output=False, - ) - exports.add( - obj=fs.metab_hydrogen.energy_electric_mixer_vol, - name="Mixer specific power", - ui_units=pyunits.kW / pyunits.m**3, - display_units="kW/m3 of reactor", - rounding=3, - description="Mixer specific power relating the power to the volume of the " - "reactor", - is_input=True, - input_category="Hydrogen reactor", - is_output=False, - ) - exports.add( - obj=fs.metab_hydrogen.energy_electric_vacuum_flow_vol_byproduct, - name="Vacuum specific power", - ui_units=pyunits.kW / (pyunits.kg / pyunits.hr), - display_units="kW/(kg-H2/h)", - rounding=2, - description="Vacuum specific power relating the power to the production of H2", - is_input=True, - input_category="Hydrogen reactor", - is_output=False, - ) - exports.add( - obj=fs.metab_hydrogen.energy_thermal_flow_vol_inlet, - name="Specific heating", - ui_units=pyunits.MJ / pyunits.m**3, - display_units="MJ/m3 of water", - rounding=2, - description="Specific heating relating the thermal energy input to water " - "volume", - is_input=True, - input_category="Hydrogen reactor", - is_output=False, - ) - exports.add( - obj=fs.costing.metab.bead_bulk_density["hydrogen"], - name="Bead bulk density", - ui_units=pyunits.kg / pyunits.m**3, - display_units="kg/m3 of reactor", - rounding=1, - description="Bead bulk density [kg-beads/m3 of reactor]", - is_input=True, - input_category="Hydrogen reactor", - is_output=False, - ) - - # Unit cost data, hydrogen reactor - exports.add( - obj=fs.costing.metab.reactor_cost["hydrogen"], - name="Reactor cost", - ui_units=fs.costing.base_currency / pyunits.m**3, - display_units="$/m3 of reactor", - rounding=0, - description="Reactor capital cost parameter", - is_input=True, - input_category="Hydrogen reactor costing", - is_output=False, - ) - exports.add( - obj=fs.costing.metab.mixer_cost["hydrogen"], - name="Mixer cost", - ui_units=fs.costing.base_currency / pyunits.kW, - display_units="$/kW of mixer", - rounding=0, - description="Mixer capital cost parameter", - is_input=True, - input_category="Hydrogen reactor costing", - is_output=False, - ) - exports.add( - obj=fs.costing.metab.bead_cost["hydrogen"], - name="Bead cost", - ui_units=fs.costing.base_currency / pyunits.kg, - display_units="$/kg", - rounding=1, - description="Bead cost parameter", - is_input=True, - input_category="Hydrogen reactor costing", - is_output=False, - ) - exports.add( - obj=fs.costing.metab.bead_replacement_factor["hydrogen"], - name="Bead replacement factor", - ui_units=1 / pyunits.year, - display_units="1/year", - rounding=2, - description="Bead replacement factor - amount of initial beads replaced per " - "year", - is_input=True, - input_category="Hydrogen reactor costing", - is_output=False, - ) - exports.add( - obj=fs.costing.metab.membrane_sidestream_fraction["hydrogen"], - name="Membrane side stream", - ui_units=pyunits.dimensionless, - display_units="fraction", - rounding=2, - description="Fraction of reactor volumetric flow that recirculates in membrane " - "side stream", - is_input=True, - input_category="Hydrogen reactor costing", - is_output=False, - ) - exports.add( - obj=fs.costing.metab.membrane_specific_size["hydrogen"], - name="Membrane specific size", - ui_units=pyunits.m**2 / (pyunits.m**3 / pyunits.hr), - display_units="m2/(m3/h of side stream)", - rounding=2, - description="Membrane specific size relating membrane area to side stream " - "flow rate", - is_input=True, - input_category="Hydrogen reactor costing", - is_output=False, - ) - exports.add( - obj=fs.costing.metab.membrane_cost["hydrogen"], - name="Membrane cost", - ui_units=fs.costing.base_currency / pyunits.m**2, - display_units="$/m2", - rounding=0, - description="Membrane cost parameter", - is_input=True, - input_category="Hydrogen reactor costing", - is_output=False, - ) - exports.add( - obj=fs.costing.metab.vacuum_cost["hydrogen"], - name="Vacuum cost", - ui_units=fs.costing.base_currency / (pyunits.kg / pyunits.hr), - display_units="$/(kg-H2/h)", - rounding=0, - description="Vacuum cost parameter", - is_input=True, - input_category="Hydrogen reactor costing", - is_output=False, - ) - - # Unit model data, methane reactor - exports.add( - obj=fs.metab_methane.recovery_frac_mass_H2O[0], - name="Water recovery", - ui_units=pyunits.dimensionless, - display_units="fraction", # we should change to % - rounding=2, - description="Water recovery [g-H2O treated/g-H2O inlet]", - is_input=True, - input_category="Methane reactor", - is_output=False, - ) - exports.add( - obj=fs.metab_methane.reaction_conversion[0, "cod_to_methane"], - name="COD conversion", - ui_units=pyunits.dimensionless, - display_units="fraction", # we should change to % - rounding=2, - description="COD conversion [g-COD reacted/g-COD inlet]", - is_input=True, - input_category="Methane reactor", - is_output=False, - ) - exports.add( - obj=fs.metab_methane.generation_ratio["cod_to_methane", "methane"], - name="CH4 conversion ratio", - ui_units=pyunits.dimensionless, - display_units="fraction", - rounding=2, - description="CH4 mass conversion ratio with respect to COD [g-CH4 " - "produced/g-COD reacted]", - is_input=True, - input_category="Methane reactor", - is_output=False, - ) - exports.add( - obj=fs.metab_methane.hydraulic_retention_time, - name="HRT", - ui_units=pyunits.hr, - display_units="h", - rounding=1, - description="Hydraulic retention time", - is_input=True, - input_category="Methane reactor", - is_output=False, - ) - exports.add( - obj=fs.metab_methane.energy_electric_mixer_vol, - name="Mixer specific power", - ui_units=pyunits.kW / pyunits.m**3, - display_units="kW/m3 of reactor", - rounding=3, - description="Mixer specific power relating the power to the volume of the " - "reactor", - is_input=True, - input_category="Methane reactor", - is_output=False, - ) - exports.add( - obj=fs.metab_methane.energy_electric_vacuum_flow_vol_byproduct, - name="Vacuum specific power", - ui_units=pyunits.kW / (pyunits.kg / pyunits.hr), - display_units="kW/(kg-H2/h)", - rounding=2, - description="Vacuum specific power relating the power to the production of H2", - is_input=True, - input_category="Methane reactor", - is_output=False, - ) - exports.add( - obj=fs.metab_methane.energy_thermal_flow_vol_inlet, - name="Specific heating", - ui_units=pyunits.MJ / pyunits.m**3, - display_units="MJ/m3 of water", - rounding=2, - description="Specific heating relating the thermal energy input to water " - "volume", - is_input=True, - input_category="Methane reactor", - is_output=False, - ) - exports.add( - obj=fs.costing.metab.bead_bulk_density["methane"], - name="Bead bulk density", - ui_units=pyunits.kg / pyunits.m**3, - display_units="kg/m3 of reactor", - rounding=1, - description="Bead bulk density [kg-beads/m3 of reactor]", - is_input=True, - input_category="Methane reactor", - is_output=False, - ) - - # Unit cost data, methane reactor - exports.add( - obj=fs.costing.metab.reactor_cost["methane"], - name="Reactor cost", - ui_units=fs.costing.base_currency / pyunits.m**3, - display_units="$/m3 of reactor", - rounding=0, - description="Reactor capital cost parameter", - is_input=True, - input_category="Methane reactor costing", - is_output=False, - ) - exports.add( - obj=fs.costing.metab.mixer_cost["methane"], - name="Mixer cost", - ui_units=fs.costing.base_currency / pyunits.kW, - display_units="$/kW of mixer", - rounding=0, - description="Mixer capital cost parameter", - is_input=True, - input_category="Methane reactor costing", - is_output=False, - ) - exports.add( - obj=fs.costing.metab.bead_cost["methane"], - name="Bead cost", - ui_units=fs.costing.base_currency / pyunits.kg, - display_units="$/kg", - rounding=1, - description="Bead cost parameter", - is_input=True, - input_category="Methane reactor costing", - is_output=False, - ) - exports.add( - obj=fs.costing.metab.bead_replacement_factor["methane"], - name="Bead replacement factor", - ui_units=1 / pyunits.year, - display_units="1/year", - rounding=2, - description="Bead replacement factor - amount of initial beads replaced per " - "year", - is_input=True, - input_category="Methane reactor costing", - is_output=False, - ) - exports.add( - obj=fs.costing.metab.membrane_sidestream_fraction["methane"], - name="Membrane side stream", - ui_units=pyunits.dimensionless, - display_units="fraction", - rounding=2, - description="Fraction of reactor volumetric flow that recirculates in membrane " - "side stream", - is_input=True, - input_category="Methane reactor costing", - is_output=False, - ) - exports.add( - obj=fs.costing.metab.membrane_specific_size["methane"], - name="Membrane specific size", - ui_units=pyunits.m**2 / (pyunits.m**3 / pyunits.hr), - display_units="m2/(m3/h of side stream)", - rounding=2, - description="Membrane specific size relating membrane area to side stream " - "flow rate", - is_input=True, - input_category="Methane reactor costing", - is_output=False, - ) - exports.add( - obj=fs.costing.metab.membrane_cost["methane"], - name="Membrane cost", - ui_units=fs.costing.base_currency / pyunits.m**2, - display_units="$/m2", - rounding=0, - description="Membrane cost parameter", - is_input=True, - input_category="Methane reactor costing", - is_output=False, - ) - exports.add( - obj=fs.costing.metab.vacuum_cost["methane"], - name="Vacuum cost", - ui_units=fs.costing.base_currency / (pyunits.kg / pyunits.hr), - display_units="$/(kg-CH4/h)", - rounding=0, - description="Vacuum cost parameter", - is_input=True, - input_category="Methane reactor costing", - is_output=False, - ) - - # System costing - exports.add( - obj=fs.costing.utilization_factor, - name="Utilization factor", - ui_units=pyunits.dimensionless, - display_units="fraction", - rounding=2, - description="Utilization factor - [annual use hours/total hours in year]", - is_input=True, - input_category="System costing", - is_output=False, - ) - exports.add( - obj=fs.costing.TIC, - name="Practical investment factor", - ui_units=pyunits.dimensionless, - display_units="fraction", - rounding=1, - description="Practical investment factor - [total investment cost/direct " - "capital costs]", - is_input=True, - input_category="System costing", - is_output=False, - ) - exports.add( - obj=fs.costing.plant_lifetime, - name="Plant lifetime", - ui_units=pyunits.year, - display_units="years", - rounding=1, - description="Plant lifetime", - is_input=True, - input_category="System costing", - is_output=False, - ) - exports.add( - obj=fs.costing.wacc, - name="Discount rate", - ui_units=pyunits.dimensionless, - display_units="fraction", - rounding=2, - description="Discount rate used in calculating the capital annualization", - is_input=True, - input_category="System costing", - is_output=False, - ) - exports.add( - obj=fs.costing.maintenance_costs_percent_FCI, - name="Fixed operating cost factor", - ui_units=1 / pyunits.year, - display_units="fraction/year", - rounding=2, - description="Fixed operating cost factor - [annual fixed operating cost/total " - "investment cost]", - is_input=True, - input_category="System costing", - is_output=False, - ) - exports.add( - obj=fs.costing.electricity_cost, - name="Electricity cost", - ui_units=fs.costing.base_currency / pyunits.kWh, - display_units="$/kWh", - rounding=3, - description="Electricity cost", - is_input=True, - input_category="System costing", - is_output=False, - ) - exports.add( - obj=fs.costing.heat_cost, - name="Heating cost", - ui_units=fs.costing.base_currency / pyunits.MJ, - display_units="$/MJ", - rounding=3, - description="Heating cost", - is_input=True, - input_category="System costing", - is_output=False, - ) - exports.add( - obj=fs.costing.hydrogen_product_cost, - name="Hydrogen cost", - ui_units=fs.costing.base_currency / pyunits.kg, - display_units="$/kg", - rounding=3, - description="Hydrogen cost is negative because it is sold", - is_input=True, - input_category="System costing", - is_output=False, - ) - exports.add( - obj=fs.costing.methane_product_cost, - name="Methane cost", - ui_units=fs.costing.base_currency / pyunits.kg, - display_units="$/kg", - rounding=3, - description="Methane cost is negative because it is sold", - is_input=True, - input_category="System costing", - is_output=False, - ) - - # Outlets - exports.add( - obj=fs.product_H2O.properties[0].flow_vol, - name="Product water flow rate", - ui_units=pyunits.m**3 / pyunits.hr, - display_units="m3/h", - rounding=2, - description="Outlet product water flow rate", - is_input=False, - is_output=True, - output_category="Outlets", - ) - exports.add( - obj=fs.product_H2O.properties[0].conc_mass_comp["cod"], - name="Product water COD concentration", - ui_units=pyunits.g / pyunits.L, - display_units="g/L", - rounding=2, - description="Outlet product water chemical oxygen demand concentration", - is_input=False, - is_output=True, - output_category="Outlets", - ) - exports.add( - obj=fs.product_hydrogen.properties[0].flow_mass_comp["hydrogen"], - name="Hydrogen product flow rate", - ui_units=pyunits.kg / pyunits.hr, - display_units="kg-H2/h", - rounding=3, - description="Outlet hydrogen product flow rate", - is_input=False, - is_output=True, - output_category="Outlets", - ) - exports.add( - obj=fs.product_methane.properties[0].flow_mass_comp["methane"], - name="Methane product flow rate", - ui_units=pyunits.kg / pyunits.hr, - display_units="kg-CH4/h", - rounding=3, - description="Outlet methane product flow rate", - is_input=False, - is_output=True, - output_category="Outlets", - ) - - # System metrics - exports.add( - obj=fs.costing.LCOT, - name="Levelized cost of treatment", - ui_units=fs.costing.base_currency / pyunits.m**3, - display_units="$/m3 of feed", - rounding=2, - description="Levelized cost of treatment including operating and capital costs", - is_input=False, - is_output=True, - output_category="Levelized cost metrics", - ) - exports.add( - obj=fs.costing.LCOW, - name="Levelized cost of water", - ui_units=fs.costing.base_currency / pyunits.m**3, - display_units="$/m3 of product", - rounding=2, - description="Levelized cost of water including operating and capital costs", - is_input=False, - is_output=True, - output_category="Levelized cost metrics", - ) - exports.add( - obj=fs.costing.LCOH, - name="Levelized cost of hydrogen", - ui_units=fs.costing.base_currency / pyunits.kg, - display_units="$/kg-H2", - rounding=2, - description="Levelized cost of hydrogen including operating and capital costs", - is_input=False, - is_output=True, - output_category="Levelized cost metrics", - ) - exports.add( - obj=fs.costing.LCOM, - name="Levelized cost of methane", - ui_units=fs.costing.base_currency / pyunits.kg, - display_units="$/kg-CH4", - rounding=2, - description="Levelized cost of methane including operating and capital costs", - is_input=False, - is_output=True, - output_category="Levelized cost metrics", - ) - exports.add( - obj=fs.costing.LCOCR, - name="Levelized cost of COD removal", - ui_units=fs.costing.base_currency / pyunits.kg, - display_units="$/kg-COD removed", - rounding=2, - description="Levelized cost of chemical oxygen demand removal including " - "operating and capital costs", - is_input=False, - is_output=True, - output_category="Levelized cost metrics", - ) - # Normalized metrics - total_capital_norm = fs.costing.total_capital_cost / fs.feed.properties[0].flow_vol - exports.add( - obj=total_capital_norm, - name="Total capital", - ui_units=fs.costing.base_currency / (pyunits.m**3 / pyunits.day), - display_units="$/(m3/day)", - rounding=1, - description="Normalized total capital costs accounting for indirect " - "capital and installation - [total capital costs/feed flow rate]", - is_input=False, - is_output=True, - output_category="Normalized cost metrics", - ) - direct_capital_norm = ( - fs.metab_hydrogen.costing.direct_capital_cost - + fs.metab_methane.costing.direct_capital_cost - ) / fs.feed.properties[0].flow_vol - exports.add( - obj=direct_capital_norm, - name="Direct capital", - ui_units=fs.costing.base_currency / (pyunits.m**3 / pyunits.day), - display_units="$/(m3/day)", - rounding=1, - description="Normalized direct capital costs - [total direct capital " - "costs/feed flow rate] ", - is_input=False, - is_output=True, - output_category="Normalized cost metrics", - ) - elec_operating_norm = ( - fs.costing.aggregate_flow_costs["electricity"] / fs.costing.annual_water_inlet - ) - exports.add( - obj=elec_operating_norm, - name="Electricity", - ui_units=fs.costing.base_currency / pyunits.m**3, - display_units="$/m3 of feed", - rounding=2, - description="Normalized electricity cost - [annual electricity costs/annual " - "feed flow rate]", - is_input=False, - is_output=True, - output_category="Normalized cost metrics", - ) - heat_operating_norm = ( - fs.costing.aggregate_flow_costs["heat"] / fs.costing.annual_water_inlet - ) - exports.add( - obj=heat_operating_norm, - name="Heating", - ui_units=fs.costing.base_currency / pyunits.m**3, - display_units="$/m3 of feed", - rounding=2, - description="Normalized heating cost - [annual heating costs/annual " - "feed flow rate]", - is_input=False, - is_output=True, - output_category="Normalized cost metrics", - ) - - # performance metrics - recovery_vol = ( - fs.product_H2O.properties[0].flow_vol / fs.feed.properties[0].flow_vol - ) - exports.add( - obj=recovery_vol, - name="Volumetric recovery", - ui_units=pyunits.dimensionless, - display_units="m3 of product/m3 of feed", - rounding=3, - description="Volumetric recovery of product water", - is_input=False, - is_output=True, - output_category="Normalized performance metrics", - ) - removal_cod = ( - 1 - - fs.product_H2O.properties[0].flow_mass_comp["cod"] - / fs.feed.properties[0].flow_mass_comp["cod"] - ) - exports.add( - obj=removal_cod, - name="COD removal", - ui_units=pyunits.dimensionless, - display_units="fraction", - rounding=3, - description="COD removal fraction [1 - outlet COD flow/inlet COD flow]", - is_input=False, - is_output=True, - output_category="Normalized performance metrics", - ) - hydrogen_production = ( - fs.product_hydrogen.properties[0].flow_mass_comp["hydrogen"] - / fs.feed.properties[0].flow_vol - ) - exports.add( - obj=hydrogen_production, - name="Hydrogen production", - ui_units=pyunits.kg / pyunits.m**3, - display_units="kg-H2/m3 of feed", - rounding=3, - description="Hydrogen production [hydrogen product flow rate/feed flow rate]", - is_input=False, - is_output=True, - output_category="Normalized performance metrics", - ) - - methane_production = ( - fs.product_methane.properties[0].flow_mass_comp["methane"] - / fs.feed.properties[0].flow_vol - ) - exports.add( - obj=methane_production, - name="Methane production", - ui_units=pyunits.kg / pyunits.m**3, - display_units="kg-CH4/m3 of feed", - rounding=3, - description="Methane production [methane product flow rate/feed flow rate]", - is_input=False, - is_output=True, - output_category="Normalized performance metrics", - ) - - # Capital costs - exports.add( - obj=fs.costing.total_capital_cost, - name="Total", - ui_units=fs.costing.base_currency, - display_units="$", - rounding=0, - description="Total capital costs - including investment factor to account " - "for indirect capital", - is_input=False, - is_output=True, - output_category="Capital costs", - ) - exports.add( - obj=fs.metab_hydrogen.costing.capital_cost, - name="Hydrogen reactor", - ui_units=fs.costing.base_currency, - display_units="$", - rounding=0, - description="Hydrogen reactor", - is_input=False, - is_output=True, - output_category="Capital costs", - ) - exports.add( - obj=fs.metab_methane.costing.capital_cost, - name="Methane reactor", - ui_units=fs.costing.base_currency, - display_units="$", - rounding=0, - description="Methane reactor", - is_input=False, - is_output=True, - output_category="Capital costs", - ) - - # Operating costs - exports.add( - obj=fs.costing.total_operating_cost, - name="Total", - ui_units=fs.costing.base_currency / pyunits.year, - display_units="$/year", - rounding=0, - description="Total annual operating costs - including electricity, heating, " - "and fixed", - is_input=False, - is_output=True, - output_category="Operating costs", - ) - exports.add( - obj=fs.costing.aggregate_flow_costs["electricity"], - name="Electricity", - ui_units=fs.costing.base_currency / pyunits.year, - display_units="$/year", - rounding=0, - description="Annual electricity costs ", - is_input=False, - is_output=True, - output_category="Operating costs", - ) - exports.add( - obj=fs.costing.aggregate_flow_costs["heat"], - name="Heating", - ui_units=fs.costing.base_currency / pyunits.year, - display_units="$/year", - rounding=0, - description="Annual heating costs ", - is_input=False, - is_output=True, - output_category="Operating costs", - ) - exports.add( - obj=fs.costing.total_fixed_operating_cost, - name="Fixed", - ui_units=fs.costing.base_currency / pyunits.year, - display_units="$/year", - rounding=0, - description="Annual fixed operating costs - these costs include material " - "replacement, maintenance, and labor", - is_input=False, - is_output=True, - output_category="Operating costs", - ) - - # Revenue - total_revenue = -( - fs.costing.aggregate_flow_costs["hydrogen_product"] - + fs.costing.aggregate_flow_costs["methane_product"] - ) - exports.add( - obj=total_revenue, - name="Total", - ui_units=fs.costing.base_currency / pyunits.year, - display_units="$/year", - rounding=0, - description="Total revenue - including the sale of hydrogen and methane", - is_input=False, - is_output=True, - output_category="Revenue", - ) - exports.add( - obj=-fs.costing.aggregate_flow_costs["hydrogen_product"], - name="Hydrogen", - ui_units=fs.costing.base_currency / pyunits.year, - display_units="$/year", - rounding=0, - description="Revenue from selling hydrogen", - is_input=False, - is_output=True, - output_category="Revenue", - ) - exports.add( - obj=-fs.costing.aggregate_flow_costs["methane_product"], - name="Methane", - ui_units=fs.costing.base_currency / pyunits.year, - display_units="$/year", - rounding=0, - description="Revenue from selling methane", - is_input=False, - is_output=True, - output_category="Revenue", - ) - - -def build_flowsheet(build_options=None, **kwargs): - # build and solve initial flowsheet - m = build() - - set_operating_conditions(m) - assert_degrees_of_freedom(m, 0) - assert_units_consistent(m) - - initialize_system(m) - - results = solve(m) - assert_optimal_termination(results) - - add_costing(m) - assert_degrees_of_freedom(m, 0) - m.fs.costing.initialize() - - adjust_default_parameters(m) - - results = solve(m) - assert_optimal_termination(results) - return m - - -def solve_flowsheet(flowsheet=None): - fs = flowsheet - results = solve(fs) - return results diff --git a/watertap/examples/flowsheets/case_studies/wastewater_resource_recovery/peracetic_acid_disinfection/peracetic_acid_disinfection_ui.png b/watertap/examples/flowsheets/case_studies/wastewater_resource_recovery/peracetic_acid_disinfection/peracetic_acid_disinfection_ui.png deleted file mode 100644 index eeb9b15b0c..0000000000 Binary files a/watertap/examples/flowsheets/case_studies/wastewater_resource_recovery/peracetic_acid_disinfection/peracetic_acid_disinfection_ui.png and /dev/null differ diff --git a/watertap/examples/flowsheets/case_studies/wastewater_resource_recovery/peracetic_acid_disinfection/peracetic_acid_disinfection_ui.py b/watertap/examples/flowsheets/case_studies/wastewater_resource_recovery/peracetic_acid_disinfection/peracetic_acid_disinfection_ui.py deleted file mode 100644 index a305fe32ff..0000000000 --- a/watertap/examples/flowsheets/case_studies/wastewater_resource_recovery/peracetic_acid_disinfection/peracetic_acid_disinfection_ui.py +++ /dev/null @@ -1,490 +0,0 @@ -################################################################################# -# WaterTAP Copyright (c) 2020-2024, The Regents of the University of California, -# through Lawrence Berkeley National Laboratory, Oak Ridge National Laboratory, -# National Renewable Energy Laboratory, and National Energy Technology -# Laboratory (subject to receipt of any required approvals from the U.S. Dept. -# of Energy). All rights reserved. -# -# Please see the files COPYRIGHT.md and LICENSE.md for full copyright and license -# information, respectively. These files are also available online at the URL -# "https://github.com/watertap-org/watertap/" -################################################################################# -from watertap.ui.fsapi import FlowsheetInterface -from watertap.core.util.initialization import assert_degrees_of_freedom -from watertap.examples.flowsheets.case_studies.wastewater_resource_recovery.peracetic_acid_disinfection.peracetic_acid_disinfection import ( - build, - set_operating_conditions, - initialize_system, - solve, - add_costing, -) -from pyomo.environ import units as pyunits, assert_optimal_termination -from pyomo.util.check_units import assert_units_consistent - - -def export_to_ui(): - return FlowsheetInterface( - name="Peracetic acid disinfection", - do_export=export_variables, - do_build=build_flowsheet, - do_solve=solve_flowsheet, - ) - - -def export_variables(flowsheet=None, exports=None, build_options=None, **kwargs): - fs = flowsheet - # --- Input data --- - # Feed conditions - exports.add( - obj=fs.feed.flow_vol[0], - name="Volumetric flow rate", - ui_units=pyunits.m**3 / pyunits.hr, - display_units="m3/h", - rounding=2, - description="Inlet volumetric flow rate", - is_input=True, - input_category="Feed", - is_output=True, - output_category="Feed", - ) - exports.add( - obj=fs.feed.conc_mass_comp[0, "peracetic_acid"], - name="Peracetic acid concentration", - ui_units=pyunits.mg / pyunits.L, - display_units="mg/L", - rounding=2, - description="Inlet peracetic acid concentration", - is_input=True, - input_category="Feed", - is_output=True, - output_category="Feed", - ) - exports.add( - obj=fs.feed.conc_mass_comp[0, "total_coliforms_fecal_ecoli"], - name="Ecoli concentration", - ui_units=pyunits.mg / pyunits.L, - display_units="mg/L", - rounding=7, - description="Inlet total coliforms fecal ecoli concentration", - is_input=True, - input_category="Feed", - is_output=True, - output_category="Feed", - ) - - # Unit model data, peracetic acid disinfection - exports.add( - obj=fs.PAA.recovery_frac_mass_H2O[0], - name="Water recovery", - ui_units=pyunits.dimensionless, - display_units="fraction", # we should change to % - rounding=2, - description="Water recovery [g-H2O treated/g-H2O inlet]", - is_input=True, - input_category="Peracetic acid disinfection", - is_output=False, - ) - exports.add( - obj=fs.PAA.reaction_conversion[0, "paa_decomposition"], - name="PAA decomposition", - ui_units=pyunits.dimensionless, - display_units="fraction", # we should change to % - rounding=2, - description="Peracetic acid decomposition [g-PAA decomposed/g-PAA inlet]", - is_input=True, - input_category="Peracetic acid disinfection", - is_output=False, - ) - exports.add( - obj=fs.PAA.reaction_conversion[0, "ecoli_inactivation"], - name="Ecoli inactivation", - ui_units=pyunits.dimensionless, - display_units="fraction", # we should change to % - rounding=2, - description="Ecoli (total coliforms fecal ecoli) inactivation [g-ecoli inactivated/g-ecoli inlet]", - is_input=True, - input_category="Peracetic acid disinfection", - is_output=False, - ) - exports.add( - obj=fs.PAA.energy_electric_flow_vol_inlet, - name="Electricity intensity", - ui_units=pyunits.kWh / pyunits.m**3, - display_units="fraction", - rounding=2, - description="Electricity intensity with respect to inlet flow rate of unit", - is_input=True, - input_category="Peracetic acid disinfection", - is_output=False, - ) - exports.add( - obj=fs.PAA.ecoli_cell_mass, - name="Ecoli mass", - ui_units=pyunits.kg, - display_units="kg", - rounding=16, - description="Ecoli cell mass", - is_input=True, - input_category="Peracetic acid disinfection", - is_output=False, - ) - exports.add( - obj=fs.PAA.disinfection_solution_wt_frac_PAA, - name="PAA weight fraction of disinfection solution", - ui_units=pyunits.dimensionless, - display_units="fraction", - rounding=3, - description="Disinfection solution weight fraction of peracetic acid", - is_input=True, - input_category="Peracetic acid disinfection", - is_output=False, - ) - exports.add( - obj=fs.PAA.disinfection_solution_density, - name="Disinfection solution density", - ui_units=pyunits.kg / pyunits.L, - display_units="kg/L", - rounding=3, - description="Disinfection solution density", - is_input=True, - input_category="Peracetic acid disinfection", - is_output=False, - ) - exports.add( - obj=fs.PAA.HRT, - name="HRT", - ui_units=pyunits.hr, - display_units="h", - rounding=0, - description="Hydraulic retention time", - is_input=True, - input_category="Peracetic acid disinfection", - is_output=False, - ) - - # Unit cost data, peracetic acid disinfection - exports.add( - obj=fs.costing.peracetic_acid_disinfection.sizing_cost[None], - name="Peracetic acid disinfection cost", - ui_units=(fs.costing.base_currency * pyunits.day) / pyunits.m**3, - display_units="($*day)/m3 of PAA", - rounding=0, - description="Peracetic acid disinfection capital cost parameter", - is_input=True, - input_category="Peracetic acid disinfection costing", - is_output=False, - ) - - # System costing - exports.add( - obj=fs.costing.utilization_factor, - name="Utilization factor", - ui_units=pyunits.dimensionless, - display_units="fraction", - rounding=2, - description="Utilization factor - [annual use hours/total hours in year]", - is_input=True, - input_category="System costing", - is_output=False, - ) - exports.add( - obj=fs.costing.TIC, - name="Practical investment factor", - ui_units=pyunits.dimensionless, - display_units="fraction", - rounding=1, - description="Practical investment factor - [total investment cost/direct " - "capital costs]", - is_input=True, - input_category="System costing", - is_output=False, - ) - exports.add( - obj=fs.costing.plant_lifetime, - name="Plant lifetime", - ui_units=pyunits.year, - display_units="years", - rounding=1, - description="Plant lifetime", - is_input=True, - input_category="System costing", - is_output=False, - ) - exports.add( - obj=fs.costing.wacc, - name="Discount rate", - ui_units=pyunits.dimensionless, - display_units="fraction", - rounding=2, - description="Discount rate used in calculating the capital annualization", - is_input=True, - input_category="System costing", - is_output=False, - ) - exports.add( - obj=fs.costing.maintenance_costs_percent_FCI, - name="Fixed operating cost factor", - ui_units=1 / pyunits.year, - display_units="fraction/year", - rounding=2, - description="Fixed operating cost factor - [annual fixed operating cost/total " - "investment cost]", - is_input=True, - input_category="System costing", - is_output=False, - ) - exports.add( - obj=fs.costing.electricity_cost, - name="Electricity cost", - ui_units=fs.costing.base_currency / pyunits.kWh, - display_units="$/kWh", - rounding=3, - description="Electricity cost", - is_input=True, - input_category="System costing", - is_output=False, - ) - exports.add( - obj=fs.costing.disinfection_solution_cost, - name="Disinfection solution cost", - ui_units=fs.costing.base_currency / pyunits.gal, - display_units="$/gal", - rounding=3, - description="Disinfection cost", - is_input=True, - input_category="System costing", - is_output=False, - ) - - # Outlets - exports.add( - obj=fs.treated_water.properties[0].flow_vol, - name="Treated water flow rate", - ui_units=pyunits.m**3 / pyunits.hr, - display_units="m3/h", - rounding=2, - description="Outlet treated water flow rate", - is_input=False, - is_output=True, - output_category="Outlets", - ) - exports.add( - obj=fs.treated_water.properties[0].conc_mass_comp["peracetic_acid"], - name="Treated water PAA concentration", - ui_units=pyunits.mg / pyunits.L, - display_units="mg/L", - rounding=5, - description="Outlet treated water peracetic acid concentration", - is_input=False, - is_output=True, - output_category="Outlets", - ) - exports.add( - obj=fs.treated_water.properties[0].conc_mass_comp[ - "total_coliforms_fecal_ecoli" - ], - name="Treated water Ecoli concentration", - ui_units=pyunits.mg / pyunits.L, - display_units="mg/L", - rounding=7, - description="Outlet treated water ecoli concentration", - is_input=False, - is_output=True, - output_category="Outlets", - ) - - # System metrics - exports.add( - obj=fs.costing.LCOT, - name="LCOT", - ui_units=fs.costing.base_currency / pyunits.m**3, - display_units="$/m3 of feed", - rounding=3, - description="Levelized cost of treatment including operating and capital costs", - is_input=False, - is_output=True, - output_category="Levelized cost metrics", - ) - - # Normalized metrics - total_capital_norm = fs.costing.total_capital_cost / fs.feed.properties[0].flow_vol - exports.add( - obj=total_capital_norm, - name="Total capital", - ui_units=fs.costing.base_currency / (pyunits.m**3 / pyunits.day), - display_units="$/(m3/day)", - rounding=1, - description="Normalized total capital costs accounting for indirect " - "capital and installation - [total capital costs/feed flow rate]", - is_input=False, - is_output=True, - output_category="Normalized cost metrics", - ) - direct_capital_norm = (fs.PAA.costing.direct_capital_cost) / fs.feed.properties[ - 0 - ].flow_vol - exports.add( - obj=direct_capital_norm, - name="Direct capital", - ui_units=fs.costing.base_currency / (pyunits.m**3 / pyunits.day), - display_units="$/(m3/day)", - rounding=1, - description="Normalized direct capital costs - [total direct capital " - "costs/feed flow rate] ", - is_input=False, - is_output=True, - output_category="Normalized cost metrics", - ) - elec_operating_norm = ( - fs.costing.aggregate_flow_costs["electricity"] / fs.costing.annual_water_inlet - ) - exports.add( - obj=elec_operating_norm, - name="Electricity", - ui_units=fs.costing.base_currency / pyunits.m**3, - display_units="$/m3 of feed", - rounding=2, - description="Normalized electricity cost - [annual electricity costs/annual " - "feed flow rate]", - is_input=False, - is_output=True, - output_category="Normalized cost metrics", - ) - # - # performance metrics - recovery_vol = ( - fs.treated_water.properties[0].flow_vol / fs.feed.properties[0].flow_vol - ) - exports.add( - obj=recovery_vol, - name="Volumetric recovery", - ui_units=pyunits.dimensionless, - display_units="m3 of product/m3 of feed", - rounding=3, - description="Normalized volumetric recovery", - is_input=False, - is_output=True, - output_category="Normalized performance metrics", - ) - removal_PAA = ( - 1 - - fs.treated_water.properties[0].flow_mass_comp["peracetic_acid"] - / fs.feed.properties[0].flow_mass_comp["peracetic_acid"] - ) - exports.add( - obj=removal_PAA, - name="PAA removal", - ui_units=pyunits.dimensionless, - display_units="fraction", - rounding=3, - description="Peracetic acid removal fraction [1 - outlet PAA flow/inlet PAA flow]", - is_input=False, - is_output=True, - output_category="Normalized performance metrics", - ) - removal_Ecoli = ( - 1 - - fs.treated_water.properties[0].flow_mass_comp["total_coliforms_fecal_ecoli"] - / fs.feed.properties[0].flow_mass_comp["total_coliforms_fecal_ecoli"] - ) - exports.add( - obj=removal_Ecoli, - name="Ecoli removal", - ui_units=pyunits.dimensionless, - display_units="fraction", - rounding=3, - description="Ecoli removal fraction [1 - outlet Ecoli flow/inlet Ecoli flow]", - is_input=False, - is_output=True, - output_category="Normalized performance metrics", - ) - - # Capital costs - exports.add( - obj=fs.costing.total_capital_cost, - name="Total", - ui_units=fs.costing.base_currency, - display_units="$", - rounding=0, - description="Total capital costs - including investment factor to account " - "for indirect capital", - is_input=False, - is_output=True, - output_category="Capital costs", - ) - exports.add( - obj=fs.PAA.costing.capital_cost, - name="Peracetic acid disinfection", - ui_units=fs.costing.base_currency, - display_units="$", - rounding=0, - description="Peracetic acid disinfection", - is_input=False, - is_output=True, - output_category="Capital costs", - ) - - # Operating costs - exports.add( - obj=fs.costing.total_operating_cost, - name="Total", - ui_units=fs.costing.base_currency / pyunits.year, - display_units="$/year", - rounding=0, - description="Total annual operating costs - including electricity, heating, " - "and fixed", - is_input=False, - is_output=True, - output_category="Operating costs", - ) - exports.add( - obj=fs.costing.aggregate_flow_costs["electricity"], - name="Electricity", - ui_units=fs.costing.base_currency / pyunits.year, - display_units="$/year", - rounding=0, - description="Annual electricity costs ", - is_input=False, - is_output=True, - output_category="Operating costs", - ) - exports.add( - obj=fs.costing.total_fixed_operating_cost, - name="Fixed", - ui_units=fs.costing.base_currency / pyunits.year, - display_units="$/year", - rounding=0, - description="Annual fixed operating costs - these costs include material " - "replacement, maintenance, and labor", - is_input=False, - is_output=True, - output_category="Operating costs", - ) - - -def build_flowsheet(build_options=None, **kwargs): - # build and solve initial flowsheet - m = build() - - set_operating_conditions(m) - assert_degrees_of_freedom(m, 0) - assert_units_consistent(m) - - initialize_system(m) - - results = solve(m) - assert_optimal_termination(results) - - add_costing(m) - assert_degrees_of_freedom(m, 0) - m.fs.costing.initialize() - - results = solve(m) - assert_optimal_termination(results) - return m - - -def solve_flowsheet(flowsheet=None): - fs = flowsheet - results = solve(fs) - return results diff --git a/watertap/examples/flowsheets/case_studies/wastewater_resource_recovery/suboxic_activated_sludge_process/suboxic_ASM_ui.png b/watertap/examples/flowsheets/case_studies/wastewater_resource_recovery/suboxic_activated_sludge_process/suboxic_ASM_ui.png deleted file mode 100644 index b83bf00bf6..0000000000 Binary files a/watertap/examples/flowsheets/case_studies/wastewater_resource_recovery/suboxic_activated_sludge_process/suboxic_ASM_ui.png and /dev/null differ diff --git a/watertap/examples/flowsheets/case_studies/wastewater_resource_recovery/suboxic_activated_sludge_process/suboxic_ASM_ui.py b/watertap/examples/flowsheets/case_studies/wastewater_resource_recovery/suboxic_activated_sludge_process/suboxic_ASM_ui.py deleted file mode 100644 index b7a609fad6..0000000000 --- a/watertap/examples/flowsheets/case_studies/wastewater_resource_recovery/suboxic_activated_sludge_process/suboxic_ASM_ui.py +++ /dev/null @@ -1,566 +0,0 @@ -################################################################################# -# WaterTAP Copyright (c) 2020-2024, The Regents of the University of California, -# through Lawrence Berkeley National Laboratory, Oak Ridge National Laboratory, -# National Renewable Energy Laboratory, and National Energy Technology -# Laboratory (subject to receipt of any required approvals from the U.S. Dept. -# of Energy). All rights reserved. -# -# Please see the files COPYRIGHT.md and LICENSE.md for full copyright and license -# information, respectively. These files are also available online at the URL -# "https://github.com/watertap-org/watertap/" -################################################################################# -from watertap.ui.fsapi import FlowsheetInterface -from watertap.core.util.initialization import assert_degrees_of_freedom -from watertap.examples.flowsheets.case_studies.wastewater_resource_recovery.suboxic_activated_sludge_process.suboxic_activated_sludge_process import ( - build, - set_operating_conditions, - initialize_system, - solve, - add_costing, -) -from pyomo.environ import units as pyunits, assert_optimal_termination -from pyomo.util.check_units import assert_units_consistent - - -def export_to_ui(): - return FlowsheetInterface( - name="Suboxic ASM", - do_export=export_variables, - do_build=build_flowsheet, - do_solve=solve_flowsheet, - ) - - -def export_variables(flowsheet=None, exports=None, build_options=None, **kwargs): - fs = flowsheet - # --- Input data --- - # Feed conditions - exports.add( - obj=fs.feed.flow_vol[0], - name="Volumetric flow rate", - ui_units=pyunits.m**3 / pyunits.hr, - display_units="m3/h", - rounding=1, - description="Inlet volumetric flow rate", - is_input=True, - input_category="Feed", - is_output=True, - output_category="Feed", - ) - exports.add( - obj=fs.feed.conc_mass_comp[0, "bod"], - name="BOD concentration", - ui_units=pyunits.mg / pyunits.L, - display_units="mg/L", - rounding=1, - description="Inlet biological oxygen demand (BOD) concentration", - is_input=True, - input_category="Feed", - is_output=True, - output_category="Feed", - ) - exports.add( - obj=fs.feed.conc_mass_comp[0, "tss"], - name="TSS concentration", - ui_units=pyunits.mg / pyunits.L, - display_units="mg/L", - rounding=1, - description="Inlet total suspended solids (TSS) concentration", - is_input=True, - input_category="Feed", - is_output=True, - output_category="Feed", - ) - exports.add( - obj=fs.feed.conc_mass_comp[0, "tkn"], - name="TKN concentration", - ui_units=pyunits.mg / pyunits.L, - display_units="mg/L", - rounding=1, - description="Inlet total Kjeldahl nitrogen (TKN) concentration", - is_input=True, - input_category="Feed", - is_output=True, - output_category="Feed", - ) - exports.add( - obj=fs.feed.conc_mass_comp[0, "phosphorus"], - name="Total P concentration", - ui_units=pyunits.mg / pyunits.L, - display_units="mg/L", - rounding=1, - description="Inlet total phosphorus (TP) concentration", - is_input=True, - input_category="Feed", - is_output=True, - output_category="Feed", - ) - - # Unit model data, suboxic ASM - exports.add( - obj=fs.suboxicASM.recovery_frac_mass_H2O[0], - name="Water recovery", - ui_units=pyunits.dimensionless, - display_units="fraction", # we should change to % - rounding=2, - description="Water recovery [g-H2O treated/g-H2O inlet]", - is_input=True, - input_category="Suboxic ASM", - is_output=False, - ) - exports.add( - obj=fs.suboxicASM.removal_frac_mass_comp[0, "bod"], - name="BOD removal", - ui_units=pyunits.dimensionless, - display_units="fraction", - rounding=4, - description="BOD removal [g-BOD reacted/g-BOD byproduct]", - is_input=True, - input_category="Suboxic ASM", - is_output=False, - ) - exports.add( - obj=fs.suboxicASM.removal_frac_mass_comp[0, "tss"], - name="TSS removal", - ui_units=pyunits.dimensionless, - display_units="fraction", - rounding=4, - description="TSS removal [g-TSS reacted/g-TSS byproduct]", - is_input=True, - input_category="Suboxic ASM", - is_output=False, - ) - exports.add( - obj=fs.suboxicASM.removal_frac_mass_comp[0, "tkn"], - name="TKN removal", - ui_units=pyunits.dimensionless, - display_units="fraction", - rounding=4, - description="TKN removal [g-TKN reacted/g-TKN byproduct]", - is_input=True, - input_category="Suboxic ASM", - is_output=False, - ) - exports.add( - obj=fs.suboxicASM.removal_frac_mass_comp[0, "phosphorus"], - name="TP removal", - ui_units=pyunits.dimensionless, - display_units="fraction", - rounding=4, - description="TP removal [g-TP reacted/g-TP byproduct]", - is_input=True, - input_category="Suboxic ASM", - is_output=False, - ) - exports.add( - obj=fs.suboxicASM.energy_electric_flow_vol_inlet, - name="Electricity specific power", - ui_units=pyunits.kWh / pyunits.m**3, - display_units="kWh/m3", - rounding=1, - description="Specific power relating the power to the inlet flow rate", - is_input=True, - input_category="Suboxic ASM", - is_output=False, - ) - - # Unit cost data, suboxic ASM - exports.add( - obj=fs.costing.suboxic_activated_sludge_process.aeration_basin_cost[None], - name="Aeration basin cost", - ui_units=fs.costing.base_currency / (pyunits.m**3 / pyunits.hr), - display_units="$/(m3/h)", - rounding=1, - description="Aeration basin capital cost parameter", - is_input=True, - input_category="Suboxic ASM costing", - is_output=False, - ) - exports.add( - obj=fs.costing.suboxic_activated_sludge_process.other_equipment_cost[None], - name="Other equipment cost", - ui_units=fs.costing.base_currency / (pyunits.m**3 / pyunits.hr), - display_units="$/(m3/h)", - rounding=1, - description="Other equipment capital cost parameter", - is_input=True, - input_category="Suboxic ASM costing", - is_output=False, - ) - exports.add( - obj=fs.costing.suboxic_activated_sludge_process.control_system_cost[None], - name="Control system cost", - ui_units=fs.costing.base_currency / (pyunits.m**3 / pyunits.hr), - display_units="$/(m3/h)", - rounding=1, - description="Control system capital cost parameter", - is_input=True, - input_category="Suboxic ASM costing", - is_output=False, - ) - - # System costing - exports.add( - obj=fs.costing.utilization_factor, - name="Utilization factor", - ui_units=pyunits.dimensionless, - display_units="fraction", - rounding=2, - description="Utilization factor - [annual use hours/total hours in year]", - is_input=True, - input_category="System costing", - is_output=False, - ) - exports.add( - obj=fs.costing.TIC, - name="Practical investment factor", - ui_units=pyunits.dimensionless, - display_units="fraction", - rounding=1, - description="Practical investment factor - [total investment cost/direct " - "capital costs]", - is_input=True, - input_category="System costing", - is_output=False, - ) - exports.add( - obj=fs.costing.plant_lifetime, - name="Plant lifetime", - ui_units=pyunits.year, - display_units="years", - rounding=1, - description="Plant lifetime", - is_input=True, - input_category="System costing", - is_output=False, - ) - exports.add( - obj=fs.costing.wacc, - name="Discount rate", - ui_units=pyunits.dimensionless, - display_units="fraction", - rounding=2, - description="Discount rate used in calculating the capital annualization", - is_input=True, - input_category="System costing", - is_output=False, - ) - exports.add( - obj=fs.costing.maintenance_costs_percent_FCI, - name="Fixed operating cost factor", - ui_units=1 / pyunits.year, - display_units="fraction/year", - rounding=2, - description="Fixed operating cost factor - [annual fixed operating cost/total " - "investment cost]", - is_input=True, - input_category="System costing", - is_output=False, - ) - exports.add( - obj=fs.costing.electricity_cost, - name="Electricity cost", - ui_units=fs.costing.base_currency / pyunits.kWh, - display_units="$/kWh", - rounding=3, - description="Electricity cost", - is_input=True, - input_category="System costing", - is_output=False, - ) - - # Outlets - exports.add( - obj=fs.product_H2O.properties[0].flow_vol, - name="Product water flow rate", - ui_units=pyunits.m**3 / pyunits.hr, - display_units="m3/h", - rounding=2, - description="Outlet product water flow rate", - is_input=False, - is_output=True, - output_category="Outlets", - ) - exports.add( - obj=fs.product_H2O.properties[0].conc_mass_comp["bod"], - name="Product water BOD concentration", - ui_units=pyunits.g / pyunits.L, - display_units="g/L", - rounding=2, - description="Outlet product water biological oxygen demand (BOD) concentration", - is_input=False, - is_output=True, - output_category="Outlets", - ) - exports.add( - obj=fs.product_H2O.properties[0].conc_mass_comp["tss"], - name="Product water TSS concentration", - ui_units=pyunits.g / pyunits.L, - display_units="g/L", - rounding=2, - description="Outlet product water total suspended solids (TSS) concentration", - is_input=False, - is_output=True, - output_category="Outlets", - ) - exports.add( - obj=fs.product_H2O.properties[0].conc_mass_comp["tkn"], - name="Product water TKN concentration", - ui_units=pyunits.g / pyunits.L, - display_units="g/L", - rounding=2, - description="Outlet product water total Kjeldahl nitrogen (TKN) concentration", - is_input=False, - is_output=True, - output_category="Outlets", - ) - exports.add( - obj=fs.product_H2O.properties[0].conc_mass_comp["phosphorus"], - name="Product water TP concentration", - ui_units=pyunits.g / pyunits.L, - display_units="g/L", - rounding=2, - description="Outlet product water total phosphorus (TP) concentration", - is_input=False, - is_output=True, - output_category="Outlets", - ) - - # System metrics - exports.add( - obj=fs.costing.LCOT, - name="Levelized cost of treatment", - ui_units=fs.costing.base_currency / pyunits.m**3, - display_units="$/m3 of feed", - rounding=2, - description="Levelized cost of treatment including operating and capital costs", - is_input=False, - is_output=True, - output_category="Levelized cost metrics", - ) - exports.add( - obj=fs.costing.LCOW, - name="Levelized cost of water", - ui_units=fs.costing.base_currency / pyunits.m**3, - display_units="$/m3 of product", - rounding=2, - description="Levelized cost of water including operating and capital costs", - is_input=False, - is_output=True, - output_category="Levelized cost metrics", - ) - - # Normalized metrics - total_capital_norm = fs.costing.total_capital_cost / fs.feed.properties[0].flow_vol - exports.add( - obj=total_capital_norm, - name="Total capital", - ui_units=fs.costing.base_currency / (pyunits.m**3 / pyunits.day), - display_units="$/(m3/day)", - rounding=1, - description="Normalized total capital costs accounting for indirect " - "capital and installation - [total capital costs/feed flow rate]", - is_input=False, - is_output=True, - output_category="Normalized cost metrics", - ) - direct_capital_norm = ( - fs.suboxicASM.costing.direct_capital_cost / fs.feed.properties[0].flow_vol - ) - exports.add( - obj=direct_capital_norm, - name="Direct capital", - ui_units=fs.costing.base_currency / (pyunits.m**3 / pyunits.day), - display_units="$/(m3/day)", - rounding=1, - description="Normalized direct capital costs - [total direct capital " - "costs/feed flow rate] ", - is_input=False, - is_output=True, - output_category="Normalized cost metrics", - ) - elec_operating_norm = ( - fs.costing.aggregate_flow_costs["electricity"] / fs.costing.annual_water_inlet - ) - exports.add( - obj=elec_operating_norm, - name="Electricity", - ui_units=fs.costing.base_currency / pyunits.m**3, - display_units="$/m3 of feed", - rounding=4, - description="Normalized electricity cost - [annual electricity costs/annual " - "feed flow rate]", - is_input=False, - is_output=True, - output_category="Normalized cost metrics", - ) - - # performance metrics - recovery_vol = ( - fs.product_H2O.properties[0].flow_vol / fs.feed.properties[0].flow_vol - ) - exports.add( - obj=recovery_vol, - name="Volumetric recovery", - ui_units=pyunits.dimensionless, - display_units="m3 of product/m3 of feed", - rounding=4, - description="Normalized volumetric recovery" "flow rate]", - is_input=False, - is_output=True, - output_category="Normalized performance metrics", - ) - removal_bod = ( - 1 - - fs.product_H2O.properties[0].flow_mass_comp["bod"] - / fs.feed.properties[0].flow_mass_comp["bod"] - ) - exports.add( - obj=removal_bod, - name="BOD removal", - ui_units=pyunits.dimensionless, - display_units="fraction", - rounding=4, - description="BOD removal fraction [1 - outlet BOD flow/inlet BOD flow]", - is_input=False, - is_output=True, - output_category="Normalized performance metrics", - ) - removal_tss = ( - 1 - - fs.product_H2O.properties[0].flow_mass_comp["tss"] - / fs.feed.properties[0].flow_mass_comp["tss"] - ) - exports.add( - obj=removal_tss, - name="TSS removal", - ui_units=pyunits.dimensionless, - display_units="fraction", - rounding=4, - description="TSS removal fraction [1 - outlet TSS flow/inlet TSS flow]", - is_input=False, - is_output=True, - output_category="Normalized performance metrics", - ) - removal_tkn = ( - 1 - - fs.product_H2O.properties[0].flow_mass_comp["tkn"] - / fs.feed.properties[0].flow_mass_comp["tkn"] - ) - exports.add( - obj=removal_tkn, - name="TKN removal", - ui_units=pyunits.dimensionless, - display_units="fraction", - rounding=4, - description="TKN removal fraction [1 - outlet TKN flow/inlet TKN flow]", - is_input=False, - is_output=True, - output_category="Normalized performance metrics", - ) - removal_tp = ( - 1 - - fs.product_H2O.properties[0].flow_mass_comp["phosphorus"] - / fs.feed.properties[0].flow_mass_comp["phosphorus"] - ) - exports.add( - obj=removal_tp, - name="TP removal", - ui_units=pyunits.dimensionless, - display_units="fraction", - rounding=4, - description="TP removal fraction [1 - outlet TP flow/inlet TP flow]", - is_input=False, - is_output=True, - output_category="Normalized performance metrics", - ) - - # Capital costs - exports.add( - obj=fs.costing.total_capital_cost, - name="Total", - ui_units=fs.costing.base_currency, - display_units="$", - rounding=0, - description="Total capital costs - including investment factor to account " - "for indirect capital", - is_input=False, - is_output=True, - output_category="Capital costs", - ) - exports.add( - obj=fs.suboxicASM.costing.capital_cost, - name="Suboxic ASM", - ui_units=fs.costing.base_currency, - display_units="$", - rounding=0, - description="Suboxic ASM", - is_input=False, - is_output=True, - output_category="Capital costs", - ) - - # Operating costs - exports.add( - obj=fs.costing.total_operating_cost, - name="Total", - ui_units=fs.costing.base_currency / pyunits.year, - display_units="$/year", - rounding=0, - description="Total annual operating costs - including electricity, heating, " - "and fixed", - is_input=False, - is_output=True, - output_category="Operating costs", - ) - exports.add( - obj=fs.costing.aggregate_flow_costs["electricity"], - name="Electricity", - ui_units=fs.costing.base_currency / pyunits.year, - display_units="$/year", - rounding=0, - description="Annual electricity costs ", - is_input=False, - is_output=True, - output_category="Operating costs", - ) - exports.add( - obj=fs.costing.total_fixed_operating_cost, - name="Fixed", - ui_units=fs.costing.base_currency / pyunits.year, - display_units="$/year", - rounding=0, - description="Annual fixed operating costs - these costs include material " - "replacement, maintenance, and labor", - is_input=False, - is_output=True, - output_category="Operating costs", - ) - - -def build_flowsheet(build_options=None, **kwargs): - # build and solve initial flowsheet - m = build() - - set_operating_conditions(m) - assert_degrees_of_freedom(m, 0) - assert_units_consistent(m) - - initialize_system(m) - - results = solve(m) - assert_optimal_termination(results) - - add_costing(m) - assert_degrees_of_freedom(m, 0) - m.fs.costing.initialize() - - results = solve(m) - assert_optimal_termination(results) - return m - - -def solve_flowsheet(flowsheet=None): - fs = flowsheet - results = solve(fs) - return results diff --git a/watertap/examples/flowsheets/case_studies/wastewater_resource_recovery/supercritical_sludge_to_gas/supercritical_sludge_to_gas_ui.png b/watertap/examples/flowsheets/case_studies/wastewater_resource_recovery/supercritical_sludge_to_gas/supercritical_sludge_to_gas_ui.png deleted file mode 100644 index 2650e27a37..0000000000 Binary files a/watertap/examples/flowsheets/case_studies/wastewater_resource_recovery/supercritical_sludge_to_gas/supercritical_sludge_to_gas_ui.png and /dev/null differ diff --git a/watertap/examples/flowsheets/case_studies/wastewater_resource_recovery/supercritical_sludge_to_gas/supercritical_sludge_to_gas_ui.py b/watertap/examples/flowsheets/case_studies/wastewater_resource_recovery/supercritical_sludge_to_gas/supercritical_sludge_to_gas_ui.py deleted file mode 100644 index 5d793d1c35..0000000000 --- a/watertap/examples/flowsheets/case_studies/wastewater_resource_recovery/supercritical_sludge_to_gas/supercritical_sludge_to_gas_ui.py +++ /dev/null @@ -1,636 +0,0 @@ -################################################################################# -# WaterTAP Copyright (c) 2020-2024, The Regents of the University of California, -# through Lawrence Berkeley National Laboratory, Oak Ridge National Laboratory, -# National Renewable Energy Laboratory, and National Energy Technology -# Laboratory (subject to receipt of any required approvals from the U.S. Dept. -# of Energy). All rights reserved. -# -# Please see the files COPYRIGHT.md and LICENSE.md for full copyright and license -# information, respectively. These files are also available online at the URL -# "https://github.com/watertap-org/watertap/" -################################################################################# -from watertap.ui.fsapi import FlowsheetInterface -from watertap.core.util.initialization import assert_degrees_of_freedom -from watertap.examples.flowsheets.case_studies.wastewater_resource_recovery.supercritical_sludge_to_gas.supercritical_sludge_to_gas import ( - build, - set_operating_conditions, - initialize_system, - solve, - add_costing, -) -from pyomo.environ import units as pyunits, assert_optimal_termination -from pyomo.util.check_units import assert_units_consistent - - -def export_to_ui(): - return FlowsheetInterface( - name="Supercritical sludge to gas", - do_export=export_variables, - do_build=build_flowsheet, - do_solve=solve_flowsheet, - ) - - -def export_variables(flowsheet=None, exports=None, build_options=None, **kwargs): - fs = flowsheet - # --- Input data --- - # Feed conditions - flow_mass = ( - fs.feed.flow_mass_comp[0, "H2O"] - + fs.feed.flow_mass_comp[0, "organic_solid"] - + fs.feed.flow_mass_comp[0, "inorganic_solid"] - + fs.feed.flow_mass_comp[0, "organic_liquid"] - + fs.feed.flow_mass_comp[0, "carbon_dioxide"] - ) - exports.add( - obj=flow_mass, - name="Mass flow rate", - ui_units=pyunits.metric_ton / pyunits.day, - display_units="ton/day", - rounding=1, - description="Inlet mass flow rate", - is_input=True, - input_category="Feed", - is_output=True, - output_category="Feed", - ) - exports.add( - obj=fs.feed.flow_mass_comp[0, "organic_solid"], - name="Organics(s) mass flow", - ui_units=pyunits.metric_ton / pyunits.day, - display_units="ton/day", - rounding=1, - description="Inlet organics(solid) mass flow", - is_input=True, - input_category="Feed", - is_output=True, - output_category="Feed", - ) - exports.add( - obj=fs.feed.flow_mass_comp[0, "inorganic_solid"], - name="Inorganics(s) mass flow", - ui_units=pyunits.metric_ton / pyunits.day, - display_units="ton/day", - rounding=1, - description="Inlet inorganics(solid) mass flow", - is_input=True, - input_category="Feed", - is_output=True, - output_category="Feed", - ) - - # Unit model data, AT-HTL - exports.add( - obj=fs.ATHTL.recovery_frac_mass_H2O[0], - name="Water recovery", - ui_units=pyunits.dimensionless, - display_units="fraction", - rounding=2, - description="Water recovery [g-H2O treated/g-H2O inlet]", - is_input=True, - input_category="AT-HTL", - is_output=False, - ) - exports.add( - obj=fs.ATHTL.reaction_conversion[0, "hydrothermal_liquefaction"], - name="Organics(s) conversion", - ui_units=pyunits.dimensionless, - display_units="fraction", # we should change to % - rounding=2, - description="Organics(s) conversion [g-organics(s) reacted/g-organics(s) inlet]", - is_input=True, - input_category="AT-HTL", - is_output=False, - ) - exports.add( - obj=fs.ATHTL.generation_ratio["hydrothermal_liquefaction", "organic_liquid"], - name="Organics(l) conversion ratio", - ui_units=pyunits.dimensionless, - display_units="fraction", - rounding=4, - description="Organics(l) mass conversion ratio with respect to organics(s) [g-organics(l) produced" - "/g-organics(s) reacted]", - is_input=True, - input_category="AT-HTL", - is_output=False, - ) - exports.add( - obj=fs.ATHTL.generation_ratio["hydrothermal_liquefaction", "carbon_dioxide"], - name="CO2 conversion ratio", - ui_units=pyunits.dimensionless, - display_units="fraction", - rounding=4, - description="CO2 mass conversion ratio with respect to organics(s) [g-CO2 produced" - "/g-organics(s) reacted]", - is_input=True, - input_category="AT-HTL", - is_output=False, - ) - exports.add( - obj=fs.ATHTL.energy_electric_flow_mass, - name="Electricity specific power", - ui_units=pyunits.kWh / pyunits.metric_ton, - display_units="kWh/ton of inlet flow rate", - rounding=2, - description="Specific energy consumption with respect to influent mass", - is_input=True, - input_category="AT-HTL", - is_output=False, - ) - exports.add( - obj=fs.ATHTL.catalyst_dosage, - name="Catalyst dosing", - ui_units=pyunits.pound / pyunits.metric_ton, - display_units="lb/ton of inlet flow rate", - rounding=2, - description="Catalyst dosing", - is_input=True, - input_category="AT-HTL", - is_output=False, - ) - - # Unit model data, supercritical salt precipitation - exports.add( - obj=fs.salt_precipitation.recovery_frac_mass_H2O[0], - name="Water recovery", - ui_units=pyunits.dimensionless, - display_units="fraction", - rounding=2, - description="Water recovery [g-H2O treated/g-H2O inlet]", - is_input=True, - input_category="Supercritical salt precipitation", - is_output=False, - ) - exports.add( - obj=fs.salt_precipitation.removal_frac_mass_comp[0, "organic_solid"], - name="Organics(s) removal", - ui_units=pyunits.dimensionless, - display_units="fraction", - rounding=0, - description="Organics(s) removal", - is_input=True, - input_category="Supercritical salt precipitation", - is_output=False, - ) - exports.add( - obj=fs.salt_precipitation.removal_frac_mass_comp[0, "inorganic_solid"], - name="Inorganics(s) removal", - ui_units=pyunits.dimensionless, - display_units="fraction", - rounding=4, - description="Inorganics(s) removal", - is_input=True, - input_category="Supercritical salt precipitation", - is_output=False, - ) - exports.add( - obj=fs.salt_precipitation.removal_frac_mass_comp[0, "organic_liquid"], - name="Organics(l) removal", - ui_units=pyunits.dimensionless, - display_units="fraction", - rounding=0, - description="Organics(l) removal", - is_input=True, - input_category="Supercritical salt precipitation", - is_output=False, - ) - exports.add( - obj=fs.salt_precipitation.energy_electric_flow_mass, - name="Electricity specific power", - ui_units=pyunits.kWh / pyunits.metric_ton, - display_units="kWh/ton of inlet flow rate", - rounding=2, - description="Specific power relating the power to inlet mass flow rate", - is_input=True, - input_category="Supercritical salt precipitation", - is_output=False, - ) - - # Unit model data, HTG & WWT units - exports.add( - obj=fs.HTG.recovery_frac_mass_H2O[0], - name="Water recovery", - ui_units=pyunits.dimensionless, - display_units="fraction", - rounding=2, - description="Water recovery [g-H2O treated/g-H2O inlet]", - is_input=True, - input_category="HTG", - is_output=False, - ) - exports.add( - obj=fs.HTG.reaction_conversion[0, "hydrothermal_gasification"], - name="Organics(l) conversion", - ui_units=pyunits.dimensionless, - display_units="fraction", # we should change to % - rounding=2, - description="Organics(l) conversion [g-organics(l) reacted/g-organics(l) inlet]", - is_input=True, - input_category="HTG", - is_output=False, - ) - exports.add( - obj=fs.HTG.generation_ratio["hydrothermal_gasification", "carbon_dioxide"], - name="CO2 conversion ratio", - ui_units=pyunits.dimensionless, - display_units="fraction", - rounding=4, - description="CO2 mass conversion ratio with respect to organics(l) [g-CO2 produced" - "/g-organics(l) reacted]", - is_input=True, - input_category="HTG", - is_output=False, - ) - exports.add( - obj=fs.HTG.energy_electric_flow_mass, - name="Electricity specific power", - ui_units=pyunits.kWh / pyunits.metric_ton, - display_units="kWh/ton of inlet flow rate", - rounding=2, - description="Specific power relating the power to inlet mass flow rate", - is_input=True, - input_category="HTG", - is_output=False, - ) - exports.add( - obj=fs.HTG.catalyst_dosage, - name="Catalyst dosing", - ui_units=pyunits.pound / pyunits.metric_ton, - display_units="lb/ton of inlet flow rate", - rounding=2, - description="Catalyst dosing", - is_input=True, - input_category="HTG", - is_output=False, - ) - - # System costing - exports.add( - obj=fs.costing.utilization_factor, - name="Utilization factor", - ui_units=pyunits.dimensionless, - display_units="fraction", - rounding=2, - description="Utilization factor - [annual use hours/total hours in year]", - is_input=True, - input_category="System costing", - is_output=False, - ) - exports.add( - obj=fs.costing.TIC, - name="Practical investment factor", - ui_units=pyunits.dimensionless, - display_units="fraction", - rounding=1, - description="Practical investment factor - [total investment cost/direct " - "capital costs]", - is_input=True, - input_category="System costing", - is_output=False, - ) - exports.add( - obj=fs.costing.plant_lifetime, - name="Plant lifetime", - ui_units=pyunits.year, - display_units="years", - rounding=1, - description="Plant lifetime", - is_input=True, - input_category="System costing", - is_output=False, - ) - exports.add( - obj=fs.costing.wacc, - name="Discount rate", - ui_units=pyunits.dimensionless, - display_units="fraction", - rounding=2, - description="Discount rate used in calculating the capital annualization", - is_input=True, - input_category="System costing", - is_output=False, - ) - exports.add( - obj=fs.costing.maintenance_costs_percent_FCI, - name="Fixed operating cost factor", - ui_units=1 / pyunits.year, - display_units="fraction/year", - rounding=2, - description="Fixed operating cost factor - [annual fixed operating cost/total " - "investment cost]", - is_input=True, - input_category="System costing", - is_output=False, - ) - exports.add( - obj=fs.costing.electricity_cost, - name="Electricity cost", - ui_units=fs.costing.base_currency / pyunits.kWh, - display_units="$/kWh", - rounding=3, - description="Electricity cost", - is_input=True, - input_category="System costing", - is_output=False, - ) - - # Outlets - exports.add( - obj=fs.product_H2O.properties[0].flow_vol, - name="Product water flow rate", - ui_units=pyunits.m**3 / pyunits.hr, - display_units="m3/h", - rounding=2, - description="Outlet product water flow rate", - is_input=False, - is_output=True, - output_category="Outlets", - ) - exports.add( - obj=fs.product_H2O.properties[0].conc_mass_comp["organic_solid"], - name="Product water organics(s) concentration", - ui_units=pyunits.g / pyunits.L, - display_units="g/L", - rounding=2, - description="Outlet product water organics(s) concentration", - is_input=False, - is_output=True, - output_category="Outlets", - ) - exports.add( - obj=fs.product_H2O.properties[0].conc_mass_comp["organic_liquid"], - name="Product water organics(l) concentration", - ui_units=pyunits.g / pyunits.L, - display_units="g/L", - rounding=2, - description="Outlet product water organics(l) concentration", - is_input=False, - is_output=True, - output_category="Outlets", - ) - exports.add( - obj=fs.product_H2O.properties[0].conc_mass_comp["inorganic_solid"], - name="Product water inorganics(s) concentration", - ui_units=pyunits.g / pyunits.L, - display_units="g/L", - rounding=2, - description="Outlet product water inorganics(s) concentration", - is_input=False, - is_output=True, - output_category="Outlets", - ) - - # System metrics - exports.add( - obj=fs.costing.LCOT, - name="Levelized cost of treatment", - ui_units=fs.costing.base_currency / pyunits.m**3, - display_units="$/m3 of feed", - rounding=2, - description="Levelized cost of treatment including operating and capital costs", - is_input=False, - is_output=True, - output_category="Levelized cost metrics", - ) - exports.add( - obj=fs.costing.LCOW, - name="Levelized cost of water", - ui_units=fs.costing.base_currency / pyunits.m**3, - display_units="$/m3 of product", - rounding=2, - description="Levelized cost of water including operating and capital costs", - is_input=False, - is_output=True, - output_category="Levelized cost metrics", - ) - - # Normalized metrics - total_capital_norm = fs.costing.total_capital_cost / fs.feed.properties[0].flow_vol - exports.add( - obj=total_capital_norm, - name="Total capital", - ui_units=fs.costing.base_currency / (pyunits.m**3 / pyunits.day), - display_units="$/(m3/day)", - rounding=1, - description="Normalized total capital costs accounting for indirect " - "capital and installation - [total capital costs/feed flow rate]", - is_input=False, - is_output=True, - output_category="Normalized cost metrics", - ) - direct_capital_norm = ( - fs.ATHTL.costing.direct_capital_cost - + fs.salt_precipitation.costing.direct_capital_cost - + fs.HTG.costing.direct_capital_cost - ) / fs.feed.properties[0].flow_vol - exports.add( - obj=direct_capital_norm, - name="Direct capital", - ui_units=fs.costing.base_currency / (pyunits.m**3 / pyunits.day), - display_units="$/(m3/day)", - rounding=1, - description="Normalized direct capital costs - [total direct capital " - "costs/feed flow rate] ", - is_input=False, - is_output=True, - output_category="Normalized cost metrics", - ) - elec_operating_norm = ( - fs.costing.aggregate_flow_costs["electricity"] / fs.costing.annual_water_inlet - ) - exports.add( - obj=elec_operating_norm, - name="Electricity", - ui_units=fs.costing.base_currency / pyunits.m**3, - display_units="$/m3 of feed", - rounding=2, - description="Normalized electricity cost - [annual electricity costs/annual " - "feed flow rate]", - is_input=False, - is_output=True, - output_category="Normalized cost metrics", - ) - - # performance metrics - recovery_vol = ( - fs.product_H2O.properties[0].flow_vol / fs.feed.properties[0].flow_vol - ) - exports.add( - obj=recovery_vol, - name="Volumetric recovery", - ui_units=pyunits.dimensionless, - display_units="m3 of product/m3 of feed", - rounding=3, - description="Normalized volumetric recovery " "flow rate]", - is_input=False, - is_output=True, - output_category="Normalized performance metrics", - ) - removal_organics = 1 - ( - fs.product_H2O.properties[0].flow_mass_comp["organic_solid"] - + fs.product_H2O.properties[0].flow_mass_comp["organic_liquid"] - ) / ( - fs.feed.properties[0].flow_mass_comp["organic_solid"] - + fs.feed.properties[0].flow_mass_comp["organic_liquid"] - ) - exports.add( - obj=removal_organics, - name="Organics removal", - ui_units=pyunits.dimensionless, - display_units="fraction", - rounding=3, - description="Organics removal fraction [1 - outlet organics flow/inlet organics flow]", - is_input=False, - is_output=True, - output_category="Normalized performance metrics", - ) - removal_inorganics = ( - 1 - - fs.product_H2O.properties[0].flow_mass_comp["inorganic_solid"] - / fs.feed.properties[0].flow_mass_comp["inorganic_solid"] - ) - exports.add( - obj=removal_inorganics, - name="Inorganics removal", - ui_units=pyunits.dimensionless, - display_units="fraction", - rounding=3, - description="Inorganics removal fraction [1 - outlet inorganics flow/inlet inorganics flow]", - is_input=False, - is_output=True, - output_category="Normalized performance metrics", - ) - - # Capital costs - exports.add( - obj=fs.costing.total_capital_cost, - name="Total", - ui_units=fs.costing.base_currency, - display_units="$", - rounding=0, - description="Total capital costs - including investment factor to account " - "for indirect capital", - is_input=False, - is_output=True, - output_category="Capital costs", - ) - exports.add( - obj=fs.ATHTL.costing.capital_cost, - name="AT-HTL", - ui_units=fs.costing.base_currency, - display_units="$", - rounding=0, - description="Autothermal hydrothermal liquefaction (AT-HTL)", - is_input=False, - is_output=True, - output_category="Capital costs", - ) - exports.add( - obj=fs.salt_precipitation.costing.capital_cost, - name="Supercritical salt precipitation", - ui_units=fs.costing.base_currency, - display_units="$", - rounding=0, - description="Supercritical salt precipitation", - is_input=False, - is_output=True, - output_category="Capital costs", - ) - exports.add( - obj=fs.HTG.costing.capital_cost, - name="HTG", - ui_units=fs.costing.base_currency, - display_units="$", - rounding=0, - description="Hydrothermal gasification (HTG)", - is_input=False, - is_output=True, - output_category="Capital costs", - ) - - # Operating costs - exports.add( - obj=fs.costing.total_operating_cost, - name="Total", - ui_units=fs.costing.base_currency / pyunits.year, - display_units="$/year", - rounding=0, - description="Total annual operating costs - including electricity, heating, " - "and fixed", - is_input=False, - is_output=True, - output_category="Operating costs", - ) - exports.add( - obj=fs.costing.aggregate_flow_costs["electricity"], - name="Electricity", - ui_units=fs.costing.base_currency / pyunits.year, - display_units="$/year", - rounding=0, - description="Annual electricity costs ", - is_input=False, - is_output=True, - output_category="Operating costs", - ) - exports.add( - obj=fs.costing.aggregate_flow_costs["catalyst_ATHTL"], - name="Catalyst for AT-HTL", - ui_units=fs.costing.base_currency / pyunits.year, - display_units="$/year", - rounding=0, - description="Annual catalyst cost for AT-HTL", - is_input=False, - is_output=True, - output_category="Operating costs", - ) - exports.add( - obj=fs.costing.aggregate_flow_costs["catalyst_HTG"], - name="Catalyst for HTG", - ui_units=fs.costing.base_currency / pyunits.year, - display_units="$/year", - rounding=0, - description="Annual catalyst cost for HTG", - is_input=False, - is_output=True, - output_category="Operating costs", - ) - exports.add( - obj=fs.costing.total_fixed_operating_cost, - name="Fixed", - ui_units=fs.costing.base_currency / pyunits.year, - display_units="$/year", - rounding=0, - description="Annual fixed operating costs - these costs include material " - "replacement, maintenance, and labor", - is_input=False, - is_output=True, - output_category="Operating costs", - ) - - -def build_flowsheet(build_options=None, **kwargs): - # build and solve initial flowsheet - m = build() - - set_operating_conditions(m) - assert_degrees_of_freedom(m, 0) - assert_units_consistent(m) - - initialize_system(m) - - results = solve(m) - assert_optimal_termination(results) - - add_costing(m) - assert_degrees_of_freedom(m, 0) - m.fs.costing.initialize() - - results = solve(m) - assert_optimal_termination(results) - return m - - -def solve_flowsheet(flowsheet=None): - fs = flowsheet - results = solve(fs) - return results diff --git a/watertap/examples/flowsheets/case_studies/wastewater_resource_recovery/swine_wwt/swine_wwt_ui.png b/watertap/examples/flowsheets/case_studies/wastewater_resource_recovery/swine_wwt/swine_wwt_ui.png deleted file mode 100644 index 616945304f..0000000000 Binary files a/watertap/examples/flowsheets/case_studies/wastewater_resource_recovery/swine_wwt/swine_wwt_ui.png and /dev/null differ diff --git a/watertap/examples/flowsheets/case_studies/wastewater_resource_recovery/swine_wwt/swine_wwt_ui.py b/watertap/examples/flowsheets/case_studies/wastewater_resource_recovery/swine_wwt/swine_wwt_ui.py deleted file mode 100644 index afdcd48e20..0000000000 --- a/watertap/examples/flowsheets/case_studies/wastewater_resource_recovery/swine_wwt/swine_wwt_ui.py +++ /dev/null @@ -1,1182 +0,0 @@ -################################################################################# -# WaterTAP Copyright (c) 2020-2024, The Regents of the University of California, -# through Lawrence Berkeley National Laboratory, Oak Ridge National Laboratory, -# National Renewable Energy Laboratory, and National Energy Technology -# Laboratory (subject to receipt of any required approvals from the U.S. Dept. -# of Energy). All rights reserved. -# -# Please see the files COPYRIGHT.md and LICENSE.md for full copyright and license -# information, respectively. These files are also available online at the URL -# "https://github.com/watertap-org/watertap/" -################################################################################# -from watertap.ui.fsapi import FlowsheetInterface -from watertap.core.util.initialization import assert_degrees_of_freedom -from watertap.examples.flowsheets.case_studies.wastewater_resource_recovery.swine_wwt.swine_wwt import ( - build, - set_operating_conditions, - initialize_system, - solve, - add_costing, -) -from pyomo.environ import units as pyunits, assert_optimal_termination -from pyomo.util.check_units import assert_units_consistent - - -def export_to_ui(): - return FlowsheetInterface( - name="Swine wastewater treatment", - do_export=export_variables, - do_build=build_flowsheet, - do_solve=solve_flowsheet, - ) - - -def export_variables(flowsheet=None, exports=None, build_options=None, **kwargs): - fs = flowsheet - # --- Input data --- - # Feed conditions - exports.add( - obj=fs.feed.flow_vol[0], - name="Volumetric flow rate", - ui_units=pyunits.L / pyunits.day, - display_units="L/day", - rounding=0, - description="Inlet volumetric flow rate", - is_input=True, - input_category="Feed", - is_output=True, - output_category="Feed", - ) - exports.add( - obj=fs.feed.conc_mass_comp[0, "cod"], - name="COD concentration", - ui_units=pyunits.mg / pyunits.L, - display_units="mg/L", - rounding=0, - description="Inlet chemical oxygen demand (COD) concentration", - is_input=True, - input_category="Feed", - is_output=True, - output_category="Feed", - ) - exports.add( - obj=fs.feed.conc_mass_comp[0, "ammonium_as_nitrogen"], - name="NH4-N concentration", - ui_units=pyunits.mg / pyunits.L, - display_units="mg/L", - rounding=0, - description="Inlet NH4-N concentration", - is_input=True, - input_category="Feed", - is_output=True, - output_category="Feed", - ) - exports.add( - obj=fs.feed.conc_mass_comp[0, "phosphates"], - name="PO4 concentration", - ui_units=pyunits.mg / pyunits.L, - display_units="mg/L", - rounding=0, - description="Inlet PO4 concentration", - is_input=True, - input_category="Feed", - is_output=True, - output_category="Feed", - ) - exports.add( - obj=fs.food_waste.conc_mass_comp[0, "cod"], - name="COD concentration", - ui_units=pyunits.mg / pyunits.L, - display_units="mg/L", - rounding=0, - description="Food waste chemical oxygen demand (COD) concentration", - is_input=True, - input_category="Food waste", - is_output=True, - output_category="Food waste", - ) - - # Unit model data, anaerobic MBR-MEC - exports.add( - obj=fs.mbr_mec.recovery_frac_mass_H2O[0], - name="Water recovery", - ui_units=pyunits.dimensionless, - display_units="fraction", - rounding=2, - description="Water recovery [g-H2O treated/g-H2O inlet]", - is_input=True, - input_category="Anaerobic MBR-MEC", - is_output=False, - ) - exports.add( - obj=fs.mbr_mec.reaction_conversion[0, "cod_to_nonbiodegradable_cod"], - name="COD conversion", - ui_units=pyunits.dimensionless, - display_units="fraction", - rounding=1, - description="COD conversion [g-COD reacted/g-COD inlet]", - is_input=True, - input_category="Anaerobic MBR-MEC", - is_output=False, - ) - exports.add( - obj=fs.mbr_mec.generation_ratio[ - "cod_to_nonbiodegradable_cod", "nonbiodegradable_cod" - ], - name="Nonbiodigradable COD conversion ratio", - ui_units=pyunits.dimensionless, - display_units="fraction", - rounding=2, - description="Nonbiodigradable COD mass conversion ratio with respect to COD " - "[g-Nonbiodigradable COD produced/g-COD reacted]", - is_input=True, - input_category="Anaerobic MBR-MEC", - is_output=False, - ) - - # Unit cost data, anaerobic MBR-MEC - exports.add( - obj=fs.costing.anaerobic_mbr_mec.unit_capex[None], - name="Unit capital expenditure", - ui_units=fs.costing.base_currency / (pyunits.L / pyunits.day), - display_units="$/(L/day)", - rounding=2, - description="Unit capital expenditure cost parameter", - is_input=True, - input_category="Anaerobic MBR-MEC costing", - is_output=False, - ) - exports.add( - obj=fs.costing.anaerobic_mbr_mec.unit_opex[None], - name="Unit operational expenditure", - ui_units=fs.costing.base_currency / pyunits.m**3, - display_units="$/m3", - rounding=2, - description="Unit operational expenditure cost parameter", - is_input=True, - input_category="Anaerobic MBR-MEC costing", - is_output=False, - ) - - # Unit model data, gas-sparged membrane - exports.add( - obj=fs.gas_sparged_membrane.recovery_frac_mass_H2O[0], - name="Water recovery", - ui_units=pyunits.dimensionless, - display_units="fraction", - rounding=2, - description="Water recovery [g-H2O treated/g-H2O inlet]", - is_input=True, - input_category="Gas-sparged membrane", - is_output=False, - ) - exports.add( - obj=fs.gas_sparged_membrane.gas_mass_influent_ratio[0], - name="Gas mass influent ratio", - ui_units=pyunits.dimensionless, - display_units="fraction", - rounding=8, - description="Gas mass influent ratio", - is_input=True, - input_category="Gas-sparged membrane", - is_output=False, - ) - - # Unit model data, VFA separation - exports.add( - obj=fs.vfa_recovery.recovery_frac_mass_H2O[0], - name="Water recovery", - ui_units=pyunits.dimensionless, - display_units="fraction", - rounding=2, - description="Water recovery [g-H2O treated/g-H2O inlet]", - is_input=True, - input_category="VFA separation", - is_output=False, - ) - exports.add( - obj=fs.vfa_recovery.removal_frac_mass_comp[0, "nonbiodegradable_cod"], - name="Nonbiodegradable COD removal", - ui_units=pyunits.dimensionless, - display_units="fraction", - rounding=2, - description="Nonbiodegradable COD removal [g-nonbiodegradable COD byproduct/ g-nonbiodegradable COD inlet]", - is_input=True, - input_category="VFA separation", - is_output=False, - ) - exports.add( - obj=fs.vfa_recovery.heat_required_per_vfa_mass[0], - name="Heat demand", - ui_units=pyunits.kJ / pyunits.kg, - display_units="kJ/kg", - rounding=9, - description="Heat demand per VFA mass", - is_input=True, - input_category="VFA separation", - is_output=False, - ) - - # Unit cost data, VFA separation - exports.add( - obj=fs.costing.vfa_recovery.unit_capex[None], - name="Unit capital expenditure", - ui_units=fs.costing.base_currency / (pyunits.L / pyunits.day), - display_units="$/(L/day)", - rounding=2, - description="Unit capital expenditure cost parameter", - is_input=True, - input_category="VFA separation costing", - is_output=False, - ) - - # Unit model data, co-fermentation - exports.add( - obj=fs.cofermentation.recovery_frac_mass_H2O[0], - name="Water recovery", - ui_units=pyunits.dimensionless, - display_units="fraction", - rounding=2, - description="Water recovery [g-H2O treated/g-H2O inlet]", - is_input=True, - input_category="Co-fermentation", - is_output=False, - ) - exports.add( - obj=fs.cofermentation.reaction_conversion[0, "cod_to_nonbiodegradable_cod"], - name="COD conversion", - ui_units=pyunits.dimensionless, - display_units="fraction", - rounding=1, - description="COD conversion [g-COD reacted/g-COD inlet]", - is_input=True, - input_category="Co-fermentation", - is_output=False, - ) - exports.add( - obj=fs.cofermentation.generation_ratio[ - "cod_to_nonbiodegradable_cod", "nonbiodegradable_cod" - ], - name="Nonbiodigradable COD conversion ratio", - ui_units=pyunits.dimensionless, - display_units="fraction", - rounding=2, - description="Nonbiodigradable COD mass conversion ratio with respect to COD " - "[g-Nonbiodigradable COD produced/g-COD reacted]", - is_input=True, - input_category="Co-fermentation", - is_output=False, - ) - - # Unit cost data, co-fermentation - exports.add( - obj=fs.costing.cofermentation.unit_capex[None], - name="Unit capital expenditure", - ui_units=fs.costing.base_currency / (pyunits.L / pyunits.day), - display_units="$/(L/day)", - rounding=2, - description="Unit capital expenditure cost parameter", - is_input=True, - input_category="Co-fermentation costing", - is_output=False, - ) - exports.add( - obj=fs.costing.cofermentation.unit_opex[None], - name="Unit operational expenditure", - ui_units=fs.costing.base_currency / pyunits.m**3, - display_units="$/m3", - rounding=2, - description="Unit operational expenditure cost parameter", - is_input=True, - input_category="Co-fermentation costing", - is_output=False, - ) - - # Unit model data, ion exchange - exports.add( - obj=fs.ion_exchange.recovery_frac_mass_H2O[0], - name="Water recovery", - ui_units=pyunits.dimensionless, - display_units="fraction", - rounding=3, - description="Water recovery [g-H2O treated/g-H2O inlet]", - is_input=True, - input_category="Ion exchange", - is_output=False, - ) - exports.add( - obj=fs.ion_exchange.removal_frac_mass_comp[0, "ammonium_as_nitrogen"], - name="NH4-N removal", - ui_units=pyunits.dimensionless, - display_units="fraction", - rounding=3, - description="NH4-N removal [g-NH4-N byproduct/ g-NH4-N inlet]", - is_input=True, - input_category="Ion exchange", - is_output=False, - ) - exports.add( - obj=fs.ion_exchange.nitrogen_clay_ratio[0], - name="Nitrogen clay ratio", - ui_units=pyunits.dimensionless, - display_units="fraction", - rounding=3, - description="Mass fraction of nitrogen in clay mixture", - is_input=True, - input_category="Ion exchange", - is_output=False, - ) - exports.add( - obj=fs.ion_exchange.NaCl_dose, - name="Dosage of NaCl addition", - ui_units=pyunits.kg / pyunits.m**3, - display_units="kg/m3", - rounding=2, - description="Dosage of NaCl addition", - is_input=True, - input_category="Ion exchange", - is_output=False, - ) - exports.add( - obj=fs.ion_exchange.resin_replacement, - name="Resin replacement as a function of flow", - ui_units=pyunits.kg / pyunits.m**3, - display_units="kg/m3", - rounding=2, - description="Resin replacement as a function of flow", - is_input=True, - input_category="Ion exchange", - is_output=False, - ) - - # Unit cost data, ion exchange - exports.add( - obj=fs.costing.ion_exchange.unit_capex["clinoptilolite"], - name="Unit capital expenditure", - ui_units=fs.costing.base_currency / (pyunits.L / pyunits.day), - display_units="$/(L/day)", - rounding=2, - description="Unit capital expenditure cost parameter", - is_input=True, - input_category="Ion exchange costing", - is_output=False, - ) - exports.add( - obj=fs.costing.ion_exchange.unit_opex["clinoptilolite"], - name="Unit operational expenditure", - ui_units=fs.costing.base_currency / pyunits.m**3, - display_units="$/m3", - rounding=2, - description="Unit operational expenditure cost parameter", - is_input=True, - input_category="Ion exchange costing", - is_output=False, - ) - - # Unit model data, sedimentation - exports.add( - obj=fs.sedimentation.recovery_frac_mass_H2O[0], - name="Water recovery", - ui_units=pyunits.dimensionless, - display_units="fraction", - rounding=3, - description="Water recovery [g-H2O treated/g-H2O inlet]", - is_input=True, - input_category="Sedimentation", - is_output=False, - ) - exports.add( - obj=fs.sedimentation.removal_frac_mass_comp[0, "phosphates"], - name="PO4 removal", - ui_units=pyunits.dimensionless, - display_units="fraction", - rounding=3, - description="PO4 removal [g-PO4 byproduct/ g-PO4 inlet]", - is_input=True, - input_category="Sedimentation", - is_output=False, - ) - exports.add( - obj=fs.sedimentation.settling_velocity[0], - name="Particle settling velocity", - ui_units=pyunits.m / pyunits.s, - display_units="m/s", - rounding=3, - description="Particle settling velocity", - is_input=True, - input_category="Sedimentation", - is_output=False, - ) - exports.add( - obj=fs.sedimentation.phosphorus_solids_ratio[0], - name="Phosphorus solids ratio", - ui_units=pyunits.dimensionless, - display_units="fraction", - rounding=2, - description="Mass fraction of phosphorus in settleable solids", - is_input=True, - input_category="Sedimentation", - is_output=False, - ) - exports.add( - obj=fs.sedimentation.energy_electric_flow_vol_inlet, - name="Electricity intensity", - ui_units=pyunits.kWh / pyunits.m**3, - display_units="fraction", - rounding=2, - description="Electricity intensity with respect to inlet flowrate of unit", - is_input=True, - input_category="Sedimentation", - is_output=False, - ) - - # Unit cost data, sedimentation - exports.add( - obj=fs.costing.sedimentation.unit_capex["phosphorus_capture"], - name="Unit capital expenditure", - ui_units=fs.costing.base_currency / (pyunits.L / pyunits.day), - display_units="$/(L/day)", - rounding=2, - description="Unit capital expenditure cost parameter", - is_input=True, - input_category="Sedimentation costing", - is_output=False, - ) - exports.add( - obj=fs.costing.sedimentation.unit_opex["phosphorus_capture"], - name="Unit operational expenditure", - ui_units=fs.costing.base_currency / pyunits.m**3, - display_units="$/m3", - rounding=2, - description="Unit operational expenditure cost parameter", - is_input=True, - input_category="Sedimentation costing", - is_output=False, - ) - - # Unit model data, constructed wetlands - exports.add( - obj=fs.constructed_wetlands.recovery_frac_mass_H2O[0], - name="Water recovery", - ui_units=pyunits.dimensionless, - display_units="fraction", - rounding=3, - description="Water recovery [g-H2O treated/g-H2O inlet]", - is_input=True, - input_category="Constructed wetlands", - is_output=False, - ) - exports.add( - obj=fs.constructed_wetlands.removal_frac_mass_comp[0, "ammonium_as_nitrogen"], - name="NH4-N removal", - ui_units=pyunits.dimensionless, - display_units="fraction", - rounding=3, - description="NH4-N removal [g-NH4-N byproduct/ g-NH4-N inlet]", - is_input=True, - input_category="Constructed wetlands", - is_output=False, - ) - - # Unit cost data, constructed wetlands - exports.add( - obj=fs.costing.constructed_wetlands.unit_capex[None], - name="Unit capital expenditure", - ui_units=fs.costing.base_currency / (pyunits.L / pyunits.day), - display_units="$/(L/day)", - rounding=2, - description="Unit capital expenditure cost parameter", - is_input=True, - input_category="Constructed wetlands costing", - is_output=False, - ) - - # System costing - exports.add( - obj=fs.costing.utilization_factor, - name="Utilization factor", - ui_units=pyunits.dimensionless, - display_units="fraction", - rounding=2, - description="Utilization factor - [annual use hours/total hours in year]", - is_input=True, - input_category="System costing", - is_output=False, - ) - exports.add( - obj=fs.costing.TIC, - name="Practical investment factor", - ui_units=pyunits.dimensionless, - display_units="fraction", - rounding=1, - description="Practical investment factor - [total investment cost/direct " - "capital costs]", - is_input=True, - input_category="System costing", - is_output=False, - ) - exports.add( - obj=fs.costing.plant_lifetime, - name="Plant lifetime", - ui_units=pyunits.year, - display_units="years", - rounding=1, - description="Plant lifetime", - is_input=True, - input_category="System costing", - is_output=False, - ) - exports.add( - obj=fs.costing.wacc, - name="Discount rate", - ui_units=pyunits.dimensionless, - display_units="fraction", - rounding=2, - description="Discount rate used in calculating the capital annualization", - is_input=True, - input_category="System costing", - is_output=False, - ) - exports.add( - obj=fs.costing.maintenance_costs_percent_FCI, - name="Fixed operating cost factor", - ui_units=1 / pyunits.year, - display_units="fraction/year", - rounding=2, - description="Fixed operating cost factor - [annual fixed operating cost/total " - "investment cost]", - is_input=True, - input_category="System costing", - is_output=False, - ) - exports.add( - obj=fs.costing.electricity_cost, - name="Electricity cost", - ui_units=fs.costing.base_currency / pyunits.kWh, - display_units="$/kWh", - rounding=3, - description="Electricity cost", - is_input=True, - input_category="System costing", - is_output=False, - ) - exports.add( - obj=fs.costing.heat_cost, - name="Heating cost", - ui_units=fs.costing.base_currency / pyunits.kWh, - display_units="$/kWh", - rounding=3, - description="Heating cost", - is_input=True, - input_category="System costing", - is_output=False, - ) - exports.add( - obj=fs.costing.waste_disposal_cost, - name="Waste disposal cost", - ui_units=fs.costing.base_currency / pyunits.m**3, - display_units="$/m3", - rounding=1, - description="Waste disposal cost", - is_input=True, - input_category="System costing", - is_output=False, - ) - exports.add( - obj=-fs.costing.hydrogen_product_cost, - name="Hydrogen cost", - ui_units=fs.costing.base_currency / pyunits.kg, - display_units="$/kg", - rounding=0, - description="Hydrogen cost is negative because it is sold", - is_input=True, - input_category="System costing", - is_output=False, - ) - exports.add( - obj=-fs.costing.ammonia_product_cost, - name="Ammonia cost", - ui_units=fs.costing.base_currency / pyunits.short_ton, - display_units="$/tn", - rounding=0, - description="Ammonia cost is negative because it is sold", - is_input=True, - input_category="System costing", - is_output=False, - ) - exports.add( - obj=-fs.costing.phosphorus_product_cost, - name="Phosphorus cost", - ui_units=fs.costing.base_currency / pyunits.kg, - display_units="$/kg", - rounding=0, - description="Phosphorus cost is negative because it is sold", - is_input=True, - input_category="System costing", - is_output=False, - ) - exports.add( - obj=-fs.costing.vfa_product_cost, - name="VFA cost", - ui_units=fs.costing.base_currency / pyunits.metric_ton, - display_units="$/t", - rounding=0, - description="VFA cost is negative because it is sold", - is_input=True, - input_category="System costing", - is_output=False, - ) - exports.add( - obj=-fs.costing.water_product_cost, - name="Water cost", - ui_units=fs.costing.base_currency / pyunits.m**3, - display_units="$/m3", - rounding=0, - description="Water cost is negative because it is sold", - is_input=True, - input_category="System costing", - is_output=False, - ) - exports.add( - obj=-fs.costing.food_waste_tipping_fee_cost, - name="Food waste tipping fee", - ui_units=fs.costing.base_currency / pyunits.m**3, - display_units="$/m3", - rounding=0, - description="Food waste tipping fee cost is negative because it is revenue", - is_input=True, - input_category="System costing", - is_output=False, - ) - - # Outlets - exports.add( - obj=fs.product_water.properties[0].flow_vol, - name="Product water flow rate", - ui_units=pyunits.m**3 / pyunits.hr, - display_units="m3/h", - rounding=4, - description="Outlet product water flow rate", - is_input=False, - is_output=True, - output_category="Outlets", - ) - exports.add( - obj=fs.product_water.properties[0].conc_mass_comp["cod"], - name="Product water COD concentration", - ui_units=pyunits.mg / pyunits.L, - display_units="mg/L", - rounding=4, - description="Outlet product water chemical oxygen demand (COD) concentration", - is_input=False, - is_output=True, - output_category="Outlets", - ) - exports.add( - obj=fs.product_water.properties[0].conc_mass_comp["phosphates"], - name="Product water total P concentration", - ui_units=pyunits.mg / pyunits.L, - display_units="mg/L", - rounding=4, - description="Outlet product water total P concentration", - is_input=False, - is_output=True, - output_category="Outlets", - ) - exports.add( - obj=fs.product_water.properties[0].conc_mass_comp["ammonium_as_nitrogen"], - name="Product water total N concentration", - ui_units=pyunits.mg / pyunits.L, - display_units="mg/L", - rounding=4, - description="Outlet product water total N concentration", - is_input=False, - is_output=True, - output_category="Outlets", - ) - exports.add( - obj=fs.product_ammonia.properties[0].flow_mass_comp["ammonium_as_nitrogen"], - name="Ammonia product flow rate", - ui_units=pyunits.kg / pyunits.hr, - display_units="kg-N/h", - rounding=4, - description="Outlet ammonia product flow rate", - is_input=False, - is_output=True, - output_category="Outlets", - ) - exports.add( - obj=fs.product_phosphate.properties[0].flow_mass_comp["phosphates"], - name="Phosphate product flow rate", - ui_units=pyunits.kg / pyunits.hr, - display_units="kg-PO4/h", - rounding=4, - description="Outlet phosphate product flow rate", - is_input=False, - is_output=True, - output_category="Outlets", - ) - - # System metrics - exports.add( - obj=fs.costing.levelized_costs.LCOT, - name="Levelized cost of treatment", - ui_units=fs.costing.base_currency / pyunits.m**3, - display_units="$/m3 of feed", - rounding=2, - description="Levelized cost of treatment with revenue from products", - is_input=False, - is_output=True, - output_category="Levelized cost metrics", - ) - exports.add( - obj=fs.costing.levelized_costs.LCOW, - name="Levelized cost of water", - ui_units=fs.costing.base_currency / pyunits.m**3, - display_units="$/m3 of feed", - rounding=2, - description="Levelized cost of product water with revenue from products", - is_input=False, - is_output=True, - output_category="Levelized cost metrics", - ) - exports.add( - obj=fs.costing.levelized_costs.LCOH2, - name="Levelized cost of hydrogen", - ui_units=fs.costing.base_currency / pyunits.kg, - display_units="$/kg", - rounding=2, - description="Levelized cost of hydrogen with revenue from products", - is_input=False, - is_output=True, - output_category="Levelized cost metrics", - ) - exports.add( - obj=fs.costing.levelized_costs.LCON, - name="Levelized cost of nitrogen", - ui_units=fs.costing.base_currency / pyunits.kg, - display_units="$/kg", - rounding=2, - description="Levelized cost of nitrogen with revenue from products", - is_input=False, - is_output=True, - output_category="Levelized cost metrics", - ) - exports.add( - obj=fs.costing.levelized_costs.LCOVFA, - name="Levelized cost of VFA", - ui_units=fs.costing.base_currency / pyunits.kg, - display_units="$/kg", - rounding=2, - description="Levelized cost of VFA with revenue from products", - is_input=False, - is_output=True, - output_category="Levelized cost metrics", - ) - exports.add( - obj=fs.costing.levelized_costs.LCOP, - name="Levelized cost of phosphate", - ui_units=fs.costing.base_currency / pyunits.kg, - display_units="$/kg", - rounding=2, - description="Levelized cost of phosphate with revenue from products", - is_input=False, - is_output=True, - output_category="Levelized cost metrics", - ) - exports.add( - obj=fs.costing.levelized_costs.LCOCOD, - name="Levelized cost of COD removal", - ui_units=fs.costing.base_currency / pyunits.kg, - display_units="$/kg", - rounding=2, - description="Levelized cost of COD removal with revenue from products", - is_input=False, - is_output=True, - output_category="Levelized cost metrics", - ) - - # Normalized metrics - total_capital_norm = fs.costing.total_capital_cost / fs.feed.properties[0].flow_vol - exports.add( - obj=total_capital_norm, - name="Total capital", - ui_units=fs.costing.base_currency / (pyunits.m**3 / pyunits.day), - display_units="$/(m3/day)", - rounding=1, - description="Normalized total capital costs accounting for indirect " - "capital and installation - [total capital costs/feed flow rate]", - is_input=False, - is_output=True, - output_category="Normalized cost metrics", - ) - direct_capital_norm = ( - fs.mbr_mec.costing.direct_capital_cost - + fs.vfa_recovery.costing.direct_capital_cost - + fs.ion_exchange.costing.direct_capital_cost - + fs.sedimentation.costing.direct_capital_cost - + fs.cofermentation.costing.direct_capital_cost - + fs.constructed_wetlands.costing.direct_capital_cost - ) / fs.feed.properties[0].flow_vol - exports.add( - obj=direct_capital_norm, - name="Direct capital", - ui_units=fs.costing.base_currency / (pyunits.m**3 / pyunits.day), - display_units="$/(m3/day)", - rounding=1, - description="Normalized direct capital costs - [total direct capital " - "costs/feed flow rate] ", - is_input=False, - is_output=True, - output_category="Normalized cost metrics", - ) - elec_operating_norm = ( - fs.costing.aggregate_flow_costs["electricity"] - / fs.costing.annual_production.annual_water_inlet - ) - exports.add( - obj=elec_operating_norm, - name="Electricity", - ui_units=fs.costing.base_currency / pyunits.m**3, - display_units="$/m3 of feed", - rounding=2, - description="Normalized electricity cost - [annual electricity costs/annual " - "feed flow rate]", - is_input=False, - is_output=True, - output_category="Normalized cost metrics", - ) - heat_operating_norm = ( - fs.costing.aggregate_flow_costs["heat"] - / fs.costing.annual_production.annual_water_inlet - ) - exports.add( - obj=heat_operating_norm, - name="Heating", - ui_units=fs.costing.base_currency / pyunits.m**3, - display_units="$/m3 of feed", - rounding=2, - description="Normalized heating cost - [annual heating costs/annual " - "feed flow rate]", - is_input=False, - is_output=True, - output_category="Normalized cost metrics", - ) - - # performance metrics - recovery_vol = ( - fs.product_water.properties[0].flow_vol / fs.feed.properties[0].flow_vol - ) - exports.add( - obj=recovery_vol, - name="Volumetric recovery", - ui_units=pyunits.dimensionless, - display_units="m3 of product/m3 of feed", - rounding=3, - description="Volumetric recovery", - is_input=False, - is_output=True, - output_category="Normalized performance metrics", - ) - removal_cod = ( - 1 - - fs.product_water.properties[0].flow_mass_comp["cod"] - / fs.feed.properties[0].flow_mass_comp["cod"] - ) - exports.add( - obj=removal_cod, - name="COD removal", - ui_units=pyunits.dimensionless, - display_units="fraction", - rounding=1, - description="COD removal fraction [1 - outlet COD flow/inlet COD flow]", - is_input=False, - is_output=True, - output_category="Normalized performance metrics", - ) - removal_TP = ( - 1 - - fs.product_water.properties[0].flow_mass_comp["phosphates"] - / fs.feed.properties[0].flow_mass_comp["phosphates"] - ) - exports.add( - obj=removal_TP, - name="Total P removal", - ui_units=pyunits.dimensionless, - display_units="fraction", - rounding=4, - description="Total P (TP) removal fraction [1 - outlet TP flow/inlet TP flow]", - is_input=False, - is_output=True, - output_category="Normalized performance metrics", - ) - removal_TN = ( - 1 - - fs.product_water.properties[0].flow_mass_comp["ammonium_as_nitrogen"] - / fs.feed.properties[0].flow_mass_comp["ammonium_as_nitrogen"] - ) - exports.add( - obj=removal_TN, - name="Total N removal", - ui_units=pyunits.dimensionless, - display_units="fraction", - rounding=4, - description="Total N (TN) removal fraction [1 - outlet TN flow/inlet TN flow]", - is_input=False, - is_output=True, - output_category="Normalized performance metrics", - ) - - # Capital costs - exports.add( - obj=fs.costing.total_capital_cost, - name="Total", - ui_units=fs.costing.base_currency, - display_units="$", - rounding=0, - description="Total capital costs - including investment factor to account " - "for indirect capital", - is_input=False, - is_output=True, - output_category="Capital costs", - ) - exports.add( - obj=fs.mbr_mec.costing.capital_cost, - name="Anaerobic MBR-MEC", - ui_units=fs.costing.base_currency, - display_units="$", - rounding=0, - description="Anaerobic MBR-MEC", - is_input=False, - is_output=True, - output_category="Capital costs", - ) - exports.add( - obj=fs.vfa_recovery.costing.capital_cost, - name="VFA separation", - ui_units=fs.costing.base_currency, - display_units="$", - rounding=0, - description="VFA separation", - is_input=False, - is_output=True, - output_category="Capital costs", - ) - exports.add( - obj=fs.ion_exchange.costing.capital_cost, - name="Ion exchange", - ui_units=fs.costing.base_currency, - display_units="$", - rounding=0, - description="Ion exchange", - is_input=False, - is_output=True, - output_category="Capital costs", - ) - exports.add( - obj=fs.sedimentation.costing.capital_cost, - name="Sedimentation", - ui_units=fs.costing.base_currency, - display_units="$", - rounding=0, - description="Sedimentation", - is_input=False, - is_output=True, - output_category="Capital costs", - ) - exports.add( - obj=fs.cofermentation.costing.capital_cost, - name="Co-fermentation", - ui_units=fs.costing.base_currency, - display_units="$", - rounding=0, - description="Co-fermentation", - is_input=False, - is_output=True, - output_category="Capital costs", - ) - exports.add( - obj=fs.constructed_wetlands.costing.capital_cost, - name="Constructed Wetlands", - ui_units=fs.costing.base_currency, - display_units="$", - rounding=0, - description="Constructed Wetlands", - is_input=False, - is_output=True, - output_category="Capital costs", - ) - - # Operating costs - exports.add( - obj=fs.costing.total_operating_cost, - name="Total", - ui_units=fs.costing.base_currency / pyunits.year, - display_units="$/year", - rounding=0, - description="Total annual operating costs - including electricity, heating, " - "and fixed", - is_input=False, - is_output=True, - output_category="Operating costs", - ) - exports.add( - obj=fs.costing.aggregate_flow_costs["electricity"], - name="Electricity", - ui_units=fs.costing.base_currency / pyunits.year, - display_units="$/year", - rounding=0, - description="Annual electricity costs ", - is_input=False, - is_output=True, - output_category="Operating costs", - ) - exports.add( - obj=fs.costing.aggregate_flow_costs["heat"], - name="Heating", - ui_units=fs.costing.base_currency / pyunits.year, - display_units="$/year", - rounding=0, - description="Annual heating costs ", - is_input=False, - is_output=True, - output_category="Operating costs", - ) - exports.add( - obj=fs.costing.annual_costs_revenues.annual_disposal_cost, - name="Waste disposal", - ui_units=fs.costing.base_currency / pyunits.year, - display_units="$/year", - rounding=0, - description="Annual waste disposal costs ", - is_input=False, - is_output=True, - output_category="Operating costs", - ) - exports.add( - obj=fs.costing.total_fixed_operating_cost, - name="Fixed", - ui_units=fs.costing.base_currency / pyunits.year, - display_units="$/year", - rounding=0, - description="Annual fixed operating costs - these costs include material " - "replacement, maintenance, and labor", - is_input=False, - is_output=True, - output_category="Operating costs", - ) - - # Revenue - total_revenue = ( - fs.costing.annual_costs_revenues.annual_hydrogen_revenue - + fs.costing.annual_costs_revenues.annual_water_revenue - + fs.costing.annual_costs_revenues.annual_ammonia_revenue - + fs.costing.annual_costs_revenues.annual_phosphorus_revenue - + fs.costing.annual_costs_revenues.annual_vfa_revenue - + fs.costing.annual_costs_revenues.annual_food_waste_revenue - ) - exports.add( - obj=total_revenue, - name="Total", - ui_units=fs.costing.base_currency / pyunits.year, - display_units="$/year", - rounding=0, - description="Total revenue", - is_input=False, - is_output=True, - output_category="Revenue", - ) - exports.add( - obj=fs.costing.annual_costs_revenues.annual_hydrogen_revenue, - name="Hydrogen", - ui_units=fs.costing.base_currency / pyunits.year, - display_units="$/year", - rounding=0, - description="Revenue from selling hydrogen", - is_input=False, - is_output=True, - output_category="Revenue", - ) - exports.add( - obj=fs.costing.annual_costs_revenues.annual_water_revenue, - name="Water", - ui_units=fs.costing.base_currency / pyunits.year, - display_units="$/year", - rounding=0, - description="Revenue from selling water", - is_input=False, - is_output=True, - output_category="Revenue", - ) - exports.add( - obj=fs.costing.annual_costs_revenues.annual_vfa_revenue, - name="VFA", - ui_units=fs.costing.base_currency / pyunits.year, - display_units="$/year", - rounding=0, - description="Revenue from selling VFA", - is_input=False, - is_output=True, - output_category="Revenue", - ) - exports.add( - obj=fs.costing.annual_costs_revenues.annual_ammonia_revenue, - name="Ammonia", - ui_units=fs.costing.base_currency / pyunits.year, - display_units="$/year", - rounding=0, - description="Revenue from selling ammonia", - is_input=False, - is_output=True, - output_category="Revenue", - ) - exports.add( - obj=fs.costing.annual_costs_revenues.annual_phosphorus_revenue, - name="Phosphate", - ui_units=fs.costing.base_currency / pyunits.year, - display_units="$/year", - rounding=0, - description="Revenue from selling phosphate", - is_input=False, - is_output=True, - output_category="Revenue", - ) - exports.add( - obj=fs.costing.annual_costs_revenues.annual_food_waste_revenue, - name="Food waste", - ui_units=fs.costing.base_currency / pyunits.year, - display_units="$/year", - rounding=0, - description="Revenue from food waste tipping fee", - is_input=False, - is_output=True, - output_category="Revenue", - ) - - -def build_flowsheet(build_options=None, **kwargs): - # build and solve initial flowsheet - m = build() - - set_operating_conditions(m) - assert_degrees_of_freedom(m, 0) - assert_units_consistent(m) - - initialize_system(m) - - results = solve(m) - assert_optimal_termination(results) - - add_costing(m) - assert_degrees_of_freedom(m, 0) - m.fs.costing.initialize() - - results = solve(m) - assert_optimal_termination(results) - return m - - -def solve_flowsheet(flowsheet=None): - fs = flowsheet - results = solve(fs) - return results diff --git a/watertap/ui/tests/test_fsapi.py b/watertap/ui/tests/test_fsapi.py index b2ac55b3ca..d9a7124072 100644 --- a/watertap/ui/tests/test_fsapi.py +++ b/watertap/ui/tests/test_fsapi.py @@ -24,8 +24,8 @@ from watertap.examples.flowsheets.case_studies.seawater_RO_desalination import ( seawater_RO_desalination as RO, ) -from watertap.examples.flowsheets.case_studies.wastewater_resource_recovery.metab import ( - metab_ui as MU, +from watertap.examples.flowsheets.case_studies.wastewater_resource_recovery.dye_desalination import ( + dye_desalination_ui as DD, ) from watertap.ui import fsapi @@ -366,7 +366,7 @@ def test_empty_solve(): @pytest.mark.unit def test_nonoptimal_termination(): - fsi = MU.export_to_ui() + fsi = DD.export_to_ui() fsi.build() # pick a crazy value