def test_build_flowsheet(): model = run_chlorination_block_example(fix_free_chlorine=True) property_models.build_prop(model, base="TDS") build_translator_from_RO_to_chlorination_block(model) # Here, we set 'has_feed' to True because RO is our first block in the flowsheet kwargs_desal = { "has_desal_feed": True, "is_twostage": False, "has_ERD": False, "RO_type": "0D", "RO_base": "TDS", "RO_level": "detailed", } desal_port = desalination.build_desalination(model, **kwargs_desal) desalination.scale_desalination(model, **kwargs_desal) desalination.initialize_desalination(model, **kwargs_desal) # Add the connecting arcs model.fs.S1 = Arc(source=desal_port["out"], destination=model.fs.RO_to_Chlor.inlet) model.fs.S2 = Arc( source=model.fs.RO_to_Chlor.outlet, destination=model.fs.ideal_naocl_mixer_unit.inlet_stream, ) TransformationFactory("network.expand_arcs").apply_to(model) # Unfix inlet stream for mixer unfix_ideal_naocl_mixer_inlet_stream(model) check_dof(model)
def solve_flowsheet(**desal_kwargs): if desal_kwargs == {}: desal_kwargs = flowsheet_two_stage.desal_kwargs m = ConcreteModel() m.fs = FlowsheetBlock(default={"dynamic": False}) build(m, **desal_kwargs) TransformationFactory("network.expand_arcs").apply_to(m) # scale scale(m, **desal_kwargs) calculate_scaling_factors(m) # initialize initialize(m, **desal_kwargs) check_dof(m) solve_block(m, tee=False, fail_flag=True) # report print("===================================" "\n Simulation ") report(m, **desal_kwargs) return m
def solve_flowsheet(**desal_kwargs): m = ConcreteModel() m.fs = FlowsheetBlock(default={"dynamic": False}) build(m, **desal_kwargs) TransformationFactory("network.expand_arcs").apply_to(m) # scale calculate_scaling_factors(m.fs.tb_pretrt_to_desal) scale(m, **desal_kwargs) calculate_scaling_factors(m) # initialize m.fs.feed.initialize() propagate_state(m.fs.s_pretrt_tb) optarg = {'nlp_scaling_method': 'user-scaling'} m.fs.tb_pretrt_to_desal.initialize(optarg=optarg) initialize(m, **desal_kwargs) check_dof(m) solve_block(m, tee=False, fail_flag=True) # report report(m, **desal_kwargs) return m
def run_ideal_naocl_mixer_example(fixed_dosage=False): model = ConcreteModel() model.fs = FlowsheetBlock(default={"dynamic": False}) # Add properties to model build_ideal_naocl_prop(model) # Add mixer to the model build_ideal_naocl_mixer_unit(model) # Set some inlet values set_ideal_naocl_mixer_inlets(model) # Fix the inlets for a solve fix_ideal_naocl_mixer_inlets(model) # unfix the flow_mol for the naocl_stream and fix dosing rate (alt form) if fixed_dosage == True: model.fs.ideal_naocl_mixer_unit.naocl_stream.flow_mol[0].unfix() model.fs.ideal_naocl_mixer_unit.dosing_rate.fix() check_dof(model) # initializer mixer initialize_ideal_naocl_mixer(model.fs.ideal_naocl_mixer_unit) solve_block(model, tee=True) display_results_of_ideal_naocl_mixer(model.fs.ideal_naocl_mixer_unit) return model
def solve_RO(base="TDS", level="simple"): m = ConcreteModel() m.fs = FlowsheetBlock(default={"dynamic": False}) property_models.build_prop(m, base="TDS") build_RO(m, base=base, level=level) # specify feed property_models.specify_feed(m.fs.RO.feed_side.properties[0, 0], base="TDS") m.fs.RO.feed_side.properties[0, 0].pressure.fix(50e5) # scaling calculate_scaling_factors(m) # initialize m.fs.RO.initialize(optarg={"nlp_scaling_method": "user-scaling"}) m.fs.RO.display() check_dof(m) solve_block(m) m.fs.RO.report() return m
def run_chlorination_block_example(fix_free_chlorine=False): model = ConcreteModel() model.fs = FlowsheetBlock(default={"dynamic": False}) # Build the partial flowsheet of a mixer and chlorination unit build_ideal_naocl_chlorination_block(model, expand_arcs=True) # test the naocl_chlorination_costing model.fs.treated_flow_vol = Expression(expr=0.85 * pyunits.m**3 / pyunits.s) costing.build_costing(model) # set some values (using defaults for testing) set_ideal_naocl_mixer_inlets( model, dosing_rate_of_NaOCl_mg_per_s=0.4, inlet_water_density_kg_per_L=1, inlet_temperature_K=298, inlet_pressure_Pa=101325, inlet_flow_mol_per_s=25, ) set_ideal_naocl_chlorination_inlets(model) # fix only the inlets for the mixer fix_ideal_naocl_mixer_inlets(model) initialize_ideal_naocl_mixer(model.fs.ideal_naocl_mixer_unit) # scale and initialize the chlorination unit state_args = scale_ideal_naocl_chlorination( model.fs.ideal_naocl_chlorination_unit, model.fs.ideal_naocl_rxn_params, model.fs.ideal_naocl_thermo_params, ideal_naocl_reaction_config, ) # initialize the unit initialize_ideal_naocl_chlorination(model.fs.ideal_naocl_chlorination_unit, state_args, debug_out=False) check_dof(model) # Scale the full model and call the seq_decomp_initializer seq_decomp_initializer(model) if fix_free_chlorine: setup_block_to_solve_naocl_dosing_rate(model) model.fs.costing.initialize() results = solver.solve(model, tee=True) assert_optimal_termination(results) display_results_of_ideal_naocl_mixer(model.fs.ideal_naocl_mixer_unit) display_results_of_chlorination_unit( model.fs.ideal_naocl_chlorination_unit) return model
def test_build_and_scale(): m = ConcreteModel() m.fs = FlowsheetBlock(default={"dynamic": False}) # check_build(m, build_func=pretreatment_softening.build) # assert_units_consistent fails for stoich_reactor pretreatment_softening.build(m) TransformationFactory("network.expand_arcs").apply_to(m) check_dof(m) m.fs.feed.display()
def solve_pretreatment_NF(**kwargs): m = ConcreteModel() m.fs = FlowsheetBlock(default={"dynamic": False}) property_models.build_prop(m, base=kwargs["NF_base"]) build_pretreatment_NF(m, **kwargs) TransformationFactory("network.expand_arcs").apply_to(m) scale_pretreatment_NF(m, **kwargs) initialize_pretreatment_NF(m, **kwargs) check_dof(m) solve_block(m, tee=True, fail_flag=True) display_pretreatment_NF(m, **kwargs)
def solve_SepRO(base="TDS"): m = ConcreteModel() m.fs = FlowsheetBlock(default={"dynamic": False}) property_models.build_prop(m, base=base) build_SepRO(m, base=base) property_models.specify_feed(m.fs.RO.mixed_state[0], base=base) check_dof(m) calculate_scaling_factors(m) solve_block(m) m.fs.RO.inlet.display() m.fs.RO.permeate.display() m.fs.RO.retentate.display() return m
def solve_SepNF(base="ion"): m = ConcreteModel() m.fs = FlowsheetBlock(default={"dynamic": False}) property_models.build_prop(m, base=base) build_SepNF(m, base=base) property_models.specify_feed(m.fs.NF.mixed_state[0], base=base) m.fs.NF.mixed_state[0].mass_frac_phase_comp # touching for tests check_dof(m) calculate_scaling_factors(m) solve_block(m) m.fs.NF.inlet.display() m.fs.NF.permeate.display() m.fs.NF.retentate.display() return m
def solve_ZONF(base="ion"): m = ConcreteModel() m.fs = FlowsheetBlock(default={"dynamic": False}) property_models.build_prop(m, base=base) build_ZONF(m, base=base) property_models.specify_feed(m.fs.NF.feed_side.properties_in[0], base="ion") check_dof(m) calculate_scaling_factors(m) solve_block(m) m.fs.NF.inlet.display() m.fs.NF.permeate.display() m.fs.NF.retentate.display() return m
def solve_desalination(**kwargs): m = ConcreteModel() m.fs = FlowsheetBlock(default={"dynamic": False}) property_models.build_prop(m, base="TDS") build_desalination(m, **kwargs) TransformationFactory("network.expand_arcs").apply_to(m) scale_desalination(m, **kwargs) initialize_desalination(m, **kwargs) check_dof(m) solve_block(m) display_desalination(m, **kwargs) return m
def solve_flowsheet_mvp_NF(**kwargs): m = ConcreteModel() m.fs = FlowsheetBlock(default={"dynamic": False}) build_flowsheet_mvp_NF(m, **kwargs) TransformationFactory("network.expand_arcs").apply_to(m) # scale pretreatment_NF.scale_pretreatment_NF(m, **kwargs) calculate_scaling_factors(m.fs.tb_pretrt_to_desal) desalination.scale_desalination(m, **kwargs) calculate_scaling_factors(m) # initialize optarg = {"nlp_scaling_method": "user-scaling"} pretreatment_NF.initialize_pretreatment_NF(m, **kwargs) m.fs.pretrt_saturation.properties.initialize(optarg=optarg) propagate_state(m.fs.s_pretrt_tb) m.fs.tb_pretrt_to_desal.initialize(optarg=optarg) propagate_state(m.fs.s_tb_desal) desalination.initialize_desalination(m, **kwargs) m.fs.desal_saturation.properties.initialize() m.fs.costing.initialize() # check_build(m) # check_scaling(m) check_dof(m) solve_block(m, tee=False, fail_flag=True) pretreatment_NF.display_pretreatment_NF(m, **kwargs) m.fs.tb_pretrt_to_desal.report() desalination.display_desalination(m, **kwargs) print( "desalination solubility index:", value(m.fs.desal_saturation.saturation_index) ) print( "pretreatment solubility index:", value(m.fs.pretrt_saturation.saturation_index) ) print("water recovery:", value(m.fs.system_recovery)) print("LCOW:", value(m.fs.costing.LCOW)) print("CP modulus:", value(m.fs.desal_saturation.cp_modulus)) return m
def solve(): m = ConcreteModel() m.fs = FlowsheetBlock(default={"dynamic": False}) build(m) TransformationFactory("network.expand_arcs").apply_to(m) scale(m) initialize(m) check_dof(m) # solve solve_block(m) # display display(m) return m
def solve_flowsheet(has_bypass=True): m = ConcreteModel() m.fs = FlowsheetBlock(default={"dynamic": False}) build(m, has_bypass=has_bypass) TransformationFactory("network.expand_arcs").apply_to(m) # scale scale(m, has_bypass=has_bypass) calculate_scaling_factors(m) # initialize initialize(m, has_bypass=has_bypass) check_dof(m) solve_block(m, tee=True, fail_flag=True) # report report(m, has_bypass=has_bypass) return m
def run_ideal_naocl_chlorination_example(): model = ConcreteModel() model.fs = FlowsheetBlock(default={"dynamic": False}) # add properties to model build_ideal_naocl_prop(model) # add equilibrium unit build_ideal_naocl_chlorination_unit(model) # Set some inlet values set_ideal_naocl_chlorination_inlets(model) # fix the inlets fix_ideal_naocl_chlorination_inlets(model) check_dof(model) # scale the chlorination unit state_args = scale_ideal_naocl_chlorination( model.fs.ideal_naocl_chlorination_unit, model.fs.ideal_naocl_rxn_params, model.fs.ideal_naocl_thermo_params, ideal_naocl_reaction_config, ) # initialize the unit initialize_ideal_naocl_chlorination(model.fs.ideal_naocl_chlorination_unit, state_args, debug_out=False) results = solver.solve(model, tee=True) assert_optimal_termination(results) display_results_of_chlorination_unit( model.fs.ideal_naocl_chlorination_unit) return model
def solve_flowsheet(**desal_kwargs): m = ConcreteModel() m.fs = FlowsheetBlock(default={"dynamic": False}) build(m, **desal_kwargs) TransformationFactory("network.expand_arcs").apply_to(m) # scale scale(m, **desal_kwargs) calculate_scaling_factors(m) # initialize m.fs.feed.initialize() propagate_state(m.fs.s_pretrt_tb) initialize(m, **desal_kwargs) check_dof(m) solve_block(m, tee=False, fail_flag=True) # report print('===================================' '\n Simulation ') report(m, **desal_kwargs) return m
def solve_RO(base='TDS', level='simple'): m = ConcreteModel() m.fs = FlowsheetBlock(default={"dynamic": False}) property_models.build_prop(m, base='TDS') build_RO(m, base=base, level=level) # specify feed property_models.specify_feed(m.fs.RO.feed_side.properties_in[0], base='TDS') m.fs.RO.feed_side.properties_in[0].pressure.fix(50e5) # scaling calculate_scaling_factors(m) # initialize m.fs.RO.initialize(optarg={'nlp_scaling_method': 'user-scaling'}) check_dof(m) solve_block(m) m.fs.RO.report() return m
def set_up_optimization(m, system_recovery=0.50, **kwargs): set_optimization_components(m, system_recovery, **kwargs) check_dof(m, 6)
def test_property_seawater_ions(): m = ConcreteModel() m.fs = FlowsheetBlock(default={"dynamic": False}) m.fs.properties = property_seawater_ions.PropParameterBlock() m.fs.stream = m.fs.properties.build_state_block([0], default={}) # specify feed_flow_mass = 1 feed_mass_frac = { "Na": 11122e-6, "Ca": 382e-6, "Mg": 1394e-6, "SO4": 2136e-6, "Cl": 20300e-6, } m.fs.stream[0].flow_mass_phase_comp["Liq", "H2O"].fix( feed_flow_mass * (1 - sum(x for x in feed_mass_frac.values()))) for s in feed_mass_frac: m.fs.stream[0].flow_mass_phase_comp["Liq", s].fix(feed_flow_mass * feed_mass_frac[s]) m.fs.stream[0].temperature.fix(273.15 + 25) m.fs.stream[0].pressure.fix(101325) m.fs.stream[0].mass_frac_phase_comp m.fs.stream[0].flow_mol_phase_comp # scaling m.fs.properties.set_default_scaling("flow_mass_phase_comp", 1, index=("Liq", "H2O")) m.fs.properties.set_default_scaling("flow_mass_phase_comp", 1e2, index=("Liq", "Na")) m.fs.properties.set_default_scaling("flow_mass_phase_comp", 1e4, index=("Liq", "Ca")) m.fs.properties.set_default_scaling("flow_mass_phase_comp", 1e3, index=("Liq", "Mg")) m.fs.properties.set_default_scaling("flow_mass_phase_comp", 1e3, index=("Liq", "SO4")) m.fs.properties.set_default_scaling("flow_mass_phase_comp", 1e2, index=("Liq", "Cl")) iscale.calculate_scaling_factors(m.fs) # checking state block assert_units_consistent(m) check_dof(m) # initialize m.fs.stream.initialize(optarg={"nlp_scaling_method": "user-scaling"}) # solve solve_block(m) # check values assert value(m.fs.stream[0].mass_frac_phase_comp["Liq", "H2O"]) == pytest.approx( 0.9647, rel=1e-3) assert value(m.fs.stream[0].flow_mol_phase_comp["Liq", "Na"]) == pytest.approx( 0.4838, rel=1e-3) assert value(m.fs.stream[0].flow_mol_phase_comp["Liq", "Ca"]) == pytest.approx( 9.531e-3, rel=1e-3)
def set_up_optimization(m, system_recovery=0.50, **kwargs): set_optimization_components(m, system_recovery, **kwargs) calculate_scaling_factors(m) check_dof(m, 7)
def set_up_optimization(m, system_recovery=0.7, **kwargs_flowsheet): is_twostage = kwargs_flowsheet["is_twostage"] # scale calculate_scaling_factors(m) # unfix variables m.fs.splitter.split_fraction[0, "bypass"].unfix() m.fs.splitter.split_fraction[0, "bypass"].setlb(0.001) m.fs.splitter.split_fraction[0, "bypass"].setub(0.99) m.fs.NF.area.unfix() m.fs.NF.area.setlb(10) m.fs.NF.area.setub(1000) m.fs.pump_RO.control_volume.properties_out[0].pressure.unfix() m.fs.pump_RO.control_volume.properties_out[0].pressure.setlb(20e5) m.fs.pump_RO.control_volume.properties_out[0].pressure.setub(75e5) m.fs.RO.area.unfix() m.fs.RO.area.setlb(10) m.fs.RO.area.setub(300) # Set lower bound for water flux at the RO outlet, based on a minimum net driving pressure, NDPmin m.fs.RO.NDPmin = Param(initialize=1e5, mutable=True, units=pyunits.Pa) m.fs.RO.flux_mass_phase_comp[0, 1, "Liq", "H2O"].setlb( value(m.fs.RO.A_comp[0, "H2O"] * m.fs.RO.dens_solvent * m.fs.RO.NDPmin) ) if is_twostage: m.fs.max_allowable_pressure = Param( initialize=120e5, mutable=True, units=pyunits.pascal ) m.fs.pump_RO2.control_volume.properties_out[0].pressure.unfix() m.fs.pump_RO2.control_volume.properties_out[0].pressure.setlb(20e5) m.fs.pump_RO2.control_volume.properties_out[0].pressure.setub( m.fs.max_allowable_pressure ) m.fs.RO2.area.unfix() m.fs.RO2.area.setlb(10) m.fs.RO2.area.setub(300) # Set lower bound for water flux at the RO outlet, based on a minimum net driving pressure, NDPmin m.fs.RO2.NDPmin = Param(initialize=1e5, mutable=True, units=pyunits.Pa) m.fs.RO2.flux_mass_phase_comp[0, 1, "Liq", "H2O"].setlb( value(m.fs.RO2.A_comp[0, "H2O"] * m.fs.RO2.dens_solvent * m.fs.RO2.NDPmin) ) # add additional constraints # fixed system recovery m.fs.system_recovery_target = Param(initialize=system_recovery, mutable=True) m.fs.system_recovery_tol = Param(initialize=5e-3, mutable=True) m.fs.eq_system_recovery = Constraint( expr=( m.fs.system_recovery_target, m.fs.system_recovery, m.fs.system_recovery_target + m.fs.system_recovery_tol, ) ) # saturation index m.fs.max_saturation_index = Param(initialize=1.0, mutable=True) m.fs.eq_max_saturation_index_desal = Constraint( expr=m.fs.desal_saturation.saturation_index <= m.fs.max_saturation_index ) m.fs.max_conc_factor_target = Param(initialize=3.5, mutable=True) m.fs.eq_max_conc_NF = Constraint( expr=m.fs.NF.feed_side.properties_out[0].mass_frac_phase_comp["Liq", "Ca"] <= m.fs.max_conc_factor_target * m.fs.feed.properties[0].mass_frac_phase_comp["Liq", "Ca"] ) # set objective m.fs.objective = Objective(expr=m.fs.costing.LCOW) # set additional constraints to limit local minima # NOTE: doesn't seem necessary with new objective if False: m.fs.inequality_RO_area = Constraint(expr=m.fs.RO.area >= m.fs.RO2.area) min_pressure_increase = 1e5 m.fs.inequality_RO_pressure = Constraint( expr=m.fs.pump_RO.control_volume.properties_out[0].pressure + min_pressure_increase <= m.fs.pump_RO2.control_volume.properties_out[0].pressure ) m.fs.inequality_RO_permeate = Constraint( expr=m.fs.RO.permeate_side.properties_mixed[0].flow_vol_phase["Liq"] >= m.fs.RO2.permeate_side.properties_mixed[0].flow_vol_phase["Liq"] ) check_dof(m, dof_expected=6 if is_twostage else 4)