Source code for watertap.examples.flowsheets.full_treatment_train.flowsheet_components.costing

###############################################################################
# WaterTAP Copyright (c) 2021, 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 pyomo.environ import (
    Block,
    ConcreteModel,
    Constraint,
    Expression,
    Var,
    Param,
    value,
    TransformationFactory,
    units as pyunits,
)
from idaes.core import UnitModelCostingBlock
from watertap.costing import (
    WaterTAPCosting,
    PumpType,
    EnergyRecoveryDeviceType,
    MixerType,
    ROType,
)

from watertap.examples.flowsheets.full_treatment_train.flowsheet_components import (
    feed_block,
)
from watertap.examples.flowsheets.full_treatment_train.model_components import (
    unit_separator,
    unit_0DRO,
    unit_1DRO,
    property_models,
)

from watertap.examples.flowsheets.full_treatment_train.flowsheet_components.desalination import (
    build_desalination,
    solve_desalination,
    scale_desalination,
    initialize_desalination,
    display_desalination,
)

import idaes.core.util.scaling as iscale


[docs]def build_costing(m, costing_package=WaterTAPCosting, **kwargs): """Add costing to a given flowsheet Args: m: model costing_package : FlowsheetCostingBlock """ # call get_costing for each unit model m.fs.costing = costing_package() # the full_treatment_train uses a lower than default value # for factor_maintenance_labor_chemical m.fs.costing.factor_maintenance_labor_chemical.fix(0.02) crf = m.fs.costing.factor_capital_annualization # Nanofiltration if hasattr(m.fs, "NF"): if kwargs["NF_type"] == "ZO": m.fs.NF.costing = UnitModelCostingBlock( flowsheet_costing_block=m.fs.costing ) elif kwargs["NF_type"] == "Sep": raise NotImplementedError( "get_costing will not be implemented for the NF separator model." ) if hasattr(m.fs, "pump_NF"): m.fs.pump_NF.costing = UnitModelCostingBlock( flowsheet_costing_block=m.fs.costing, costing_method_arguments={"pump_type": PumpType.low_pressure}, ) # Reverse Osmosis if hasattr(m.fs, "RO"): if kwargs["RO_type"] == "0D" or kwargs["RO_type"] == "1D": m.fs.RO.costing = UnitModelCostingBlock( flowsheet_costing_block=m.fs.costing ) elif kwargs["RO_type"] == "Sep": raise NotImplementedError( "get_costing will not be implemented for the RO separator model." ) # Stage 2 RO if hasattr(m.fs, "RO2"): m.fs.RO2.costing = UnitModelCostingBlock( flowsheet_costing_block=m.fs.costing, costing_method_arguments={"ro_type": ROType.high_pressure}, ) # Pump if hasattr(m.fs, "pump_RO"): m.fs.pump_RO.costing = UnitModelCostingBlock( flowsheet_costing_block=m.fs.costing, costing_method_arguments={"pump_type": PumpType.high_pressure}, ) # Stage 2 pump if hasattr(m.fs, "pump_RO2"): m.fs.pump_RO2.costing = UnitModelCostingBlock( flowsheet_costing_block=m.fs.costing, costing_method_arguments={"pump_type": PumpType.high_pressure}, ) # ERD if hasattr(m.fs, "ERD"): m.fs.ERD.costing = UnitModelCostingBlock( flowsheet_costing_block=m.fs.costing, costing_method_arguments={ "energy_recovery_device_type": EnergyRecoveryDeviceType.pressure_exchanger }, ) # Pretreatment if hasattr(m.fs, "stoich_softening_mixer_unit"): m.fs.stoich_softening_mixer_unit.costing = UnitModelCostingBlock( flowsheet_costing_block=m.fs.costing, costing_method_arguments={ "mixer_type": MixerType.CaOH2, "dosing_rate": m.fs.stoich_softening_mixer_unit.dosing_rate, }, ) # Post-treatment if hasattr(m.fs, "ideal_naocl_mixer_unit"): # print('FOUND CHLORINATION UNIT') m.fs.ideal_naocl_mixer_unit.costing = UnitModelCostingBlock( flowsheet_costing_block=m.fs.costing, costing_method_arguments={ "mixer_type": MixerType.NaOCl, "dosing_rate": m.fs.ideal_naocl_mixer_unit.dosing_rate, }, ) if hasattr(m.fs, "mixer_permeate"): m.fs.mixer_permeate.costing = UnitModelCostingBlock( flowsheet_costing_block=m.fs.costing, costing_method_arguments={"mixer_type": MixerType.default}, ) # call get_system_costing for whole flowsheet m.fs.costing.cost_process() m.fs.costing.add_annual_water_production(m.fs.treated_flow_vol) m.fs.costing.add_LCOW(m.fs.treated_flow_vol) if hasattr(m.fs, "stoich_softening_mixer_unit"): m.fs.lime_softening_unit_capex = Expression( expr=m.fs.stoich_softening_mixer_unit.costing.capital_cost / m.fs.costing.annual_water_production * crf ) else: m.fs.lime_softening_unit_capex = Expression(expr=0) if hasattr(m.fs, "ideal_naocl_mixer_unit"): m.fs.chlorination_unit_capex = Expression( expr=m.fs.ideal_naocl_mixer_unit.costing.capital_cost / m.fs.costing.annual_water_production * crf ) else: m.fs.chlorination_unit_capex = Expression(expr=0) # apply scaling to cost variables and constraints scale_costing(m)
def scale_costing(self): for b_unit in self.component_objects(Block, descend_into=True): if hasattr(b_unit, "costing"): base = b_unit.costing for var in base.component_objects(Var): if iscale.get_scaling_factor(var) is None: iscale.set_scaling_factor(var, 1e-3) for con in base.component_data_objects(Constraint): iscale.constraint_scaling_transform(con, 1e-3) def display_costing(m): crf = m.fs.costing.factor_capital_annualization if not hasattr(m.fs, "pump_RO2"): m.fs.pump_RO2 = Block() m.fs.pump_RO2.costing = Block() m.fs.pump_RO2.costing.fixed_operating_cost = Param(initialize=0) if not hasattr(m.fs, "NF"): m.fs.NF = Block() m.fs.NF.costing = Block() m.fs.NF.costing.fixed_operating_cost = Param(initialize=0) if not hasattr(m.fs, "RO2"): m.fs.RO2 = Block() m.fs.RO2.costing = Block() m.fs.RO2.costing.fixed_operating_cost = Param(initialize=0) # UNITS FOR ALL COST COMPONENTS [=] $/m3 of permeate water produced cost_dict = { "LCOW": m.fs.costing.LCOW, # Total LCOW "Total CAPEX": m.fs.costing.total_capital_cost * crf / m.fs.costing.annual_water_production, # Direct + Indirect CAPEX "Direct CAPEX": m.fs.costing.aggregate_capital_cost * crf / m.fs.costing.annual_water_production, # Direct CAPEX for all system components "Indirect CAPEX": ( m.fs.costing.total_capital_cost - m.fs.costing.aggregate_capital_cost ) * crf / m.fs.costing.annual_water_production, # Indirect CAPEX for miscellaneous items "Total OPEX": m.fs.costing.total_operating_cost / m.fs.costing.annual_water_production, # Total OPEX "Labor & Maintenance Costs": m.fs.costing.maintenance_labor_chemical_operating_cost / m.fs.costing.annual_water_production, "Total Electricity Cost": m.fs.costing.aggregate_flow_costs["electricity"] / m.fs.costing.annual_water_production if "electricity" in m.fs.costing.aggregate_flow_costs else 0.0, "Total Membrane Replacement Cost": ( m.fs.NF.costing.fixed_operating_cost + m.fs.RO.costing.fixed_operating_cost + m.fs.RO2.costing.fixed_operating_cost ) / m.fs.costing.annual_water_production, "Lime softener CAPEX": m.fs.lime_softening_unit_capex, "Lime softener OPEX": m.fs.costing.aggregate_flow_costs["CaOH2"] / m.fs.costing.annual_water_production if "CaOH2" in m.fs.costing.aggregate_flow_costs else 0.0, "Chlorination CAPEX": m.fs.chlorination_unit_capex, "Chlorination OPEX": m.fs.costing.aggregate_flow_costs["NaOCl"] / m.fs.costing.annual_water_production if "NaOCl" in m.fs.costing.aggregate_flow_costs else 0.0, } for item, val in cost_dict.items(): print(f"{item} = {value(val)}") return cost_dict