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 initialize_system(m): prtrt = m.fs.pretreatment desal = m.fs.desalination psttrt = m.fs.posttreatment # initialize feed solve(m.fs.feed) # initialize pretreatment propagate_state(m.fs.s_feed) flags = fix_state_vars(prtrt.intake.properties) solve(prtrt) revert_state_vars(prtrt.intake.properties, flags) # initialize desalination propagate_state(m.fs.s_prtrt_tb) m.fs.tb_prtrt_desal.properties_out[0].flow_mass_phase_comp["Liq", "H2O"] = value( m.fs.tb_prtrt_desal.properties_in[0].flow_mass_comp["H2O"] ) m.fs.tb_prtrt_desal.properties_out[0].flow_mass_phase_comp["Liq", "TDS"] = value( m.fs.tb_prtrt_desal.properties_in[0].flow_mass_comp["tds"] ) desal.RO.feed_side.properties_in[0].flow_mass_phase_comp["Liq", "H2O"] = value( m.fs.feed.properties[0].flow_mass_comp["H2O"] ) desal.RO.feed_side.properties_in[0].flow_mass_phase_comp["Liq", "TDS"] = value( m.fs.feed.properties[0].flow_mass_comp["tds"] ) desal.RO.feed_side.properties_in[0].temperature = value( m.fs.tb_prtrt_desal.properties_out[0].temperature ) desal.RO.feed_side.properties_in[0].pressure = value( desal.P1.control_volume.properties_out[0].pressure ) desal.RO.initialize() propagate_state(m.fs.s_tb_desal) if m.erd_type == "pressure_exchanger": flags = fix_state_vars(desal.S1.mixed_state) solve(desal) revert_state_vars(desal.S1.mixed_state, flags) elif m.erd_type == "pump_as_turbine": flags = fix_state_vars(desal.P1.control_volume.properties_in) solve(desal) revert_state_vars(desal.P1.control_volume.properties_in, flags) # initialize posttreatment propagate_state(m.fs.s_desal_tb) m.fs.tb_desal_psttrt.properties_out[0].flow_mass_comp["H2O"] = value( m.fs.tb_desal_psttrt.properties_in[0].flow_mass_phase_comp["Liq", "H2O"] ) m.fs.tb_desal_psttrt.properties_out[0].flow_mass_comp["tds"] = value( m.fs.tb_desal_psttrt.properties_in[0].flow_mass_phase_comp["Liq", "TDS"] ) propagate_state(m.fs.s_tb_psttrt) flags = fix_state_vars(psttrt.storage_tank_2.properties) solve(psttrt) revert_state_vars(psttrt.storage_tank_2.properties, flags)
def initialize_flowsheet(m): m.fs.M01.initialize(outlvl=idaeslog.WARNING) propagate_state(m.fs.s01) m.fs.H02.initialize(outlvl=idaeslog.WARNING) propagate_state(m.fs.s02) m.fs.F03.initialize(outlvl=idaeslog.WARNING)
def initialize(m, has_bypass=True): optarg = {'nlp_scaling_method': 'user-scaling'} pretreatment_NF.initialize_pretreatment_NF(m, NF_type='ZO', NF_base='ion', has_bypass=has_bypass) m.fs.pretrt_saturation.properties.initialize(optarg=optarg) propagate_state(m.fs.s_pretrt_tb) m.fs.tb_pretrt_to_desal.initialize(optarg=optarg)
def initialize(m, has_bypass=True): optarg = {"nlp_scaling_method": "user-scaling"} pretreatment_NF.initialize_pretreatment_NF(m, NF_type="ZO", NF_base="ion", has_bypass=has_bypass) m.fs.pretrt_saturation.properties.initialize(optarg=optarg) propagate_state(m.fs.s_pretrt_tb) m.fs.tb_pretrt_to_desal.initialize(optarg=optarg)
def copy_port_values(destination=None, source=None, arc=None, direction="forward"): """ Moved to idaes.core.util.initialization.propagate_state. Leaving redirection function here for deprecation warning. """ _log.warning("DEPRECATED: copy_port_values has been deprecated. " "The same functionality can be found in " "idaes.core.util.initialization.propagate_state.") from idaes.core.util.initialization import propagate_state propagate_state(destination=destination, source=source, arc=arc, direction=direction)
def test_propagate_state_indexed_fixed(): m = ConcreteModel() def block_rule(b): b.s = Set(initialize=[1, 2]) b.v1 = Var() b.v2 = Var(b.s) b.p = Port(b.s) b.p[1].add(b.v1, "V1") b.p[2].add(b.v2, "V2") return m.b1 = Block(rule=block_rule) m.b2 = Block(rule=block_rule) def arc_rule(m, i): return {'source': m.b1.p[i], 'destination': m.b2.p[i]} m.s1 = Arc([1, 2], rule=arc_rule) # Set values on first block m.b1.v1.value = 10 m.b1.v2[1].value = 20 m.b1.v2[2].value = 30 # Make sure vars in block 2 haven't been changed accidentally assert m.b2.v1.value is None assert m.b2.v2[1].value is None assert m.b2.v2[2].value is None # Fix v1 in block 2 m.b2.v1.fix(500) propagate_state(m.s1[1]) # Check that values were propagated correctly assert m.b2.v1.value == 500 assert m.b1.v1.fixed is False assert m.b2.v1.fixed is True propagate_state(m.s1[2]) # Check that values were propagated correctly assert m.b2.v2[1].value == m.b1.v2[1].value assert m.b2.v2[2].value == m.b1.v2[2].value assert m.b1.v2[1].fixed is False assert m.b1.v2[2].fixed is False assert m.b2.v2[1].fixed is False assert m.b2.v2[2].fixed is False
def do_backwards_initialization_pass(m, optarg): first_stage = m.fs.StageSet.first() for stage in reversed(m.fs.NonFinal_StageSet): m.fs.Mixers[stage].initialize(optarg=optarg) propagate_state(m.fs.mixer_to_stage[stage]) m.fs.ROUnits[stage].initialize(optarg=optarg) propagate_state(m.fs.stage_to_pump[stage]) if stage == first_stage: propagate_state(m.fs.primary_RO_to_product) else: propagate_state(m.fs.stage_to_eq_pump[stage]) m.fs.BoosterPumps[stage].initialize(optarg=optarg) propagate_state(m.fs.eq_pump_to_mixer[stage])
def initialize(self, state_args=None, solver=None, optarg=None, outlvl=idaeslog.NOTSET): init_log = idaeslog.getInitLogger(self.name, outlvl, tag="unit") solver = get_solver(solver=solver, options=optarg) self.compressor.initialize(state_args=state_args, outlvl=outlvl) propagate_state(self.comp_to_reactor) self.stoic_reactor.initialize(outlvl=outlvl) propagate_state(self.reactor_to_turbine) self.turbine.initialize(outlvl=outlvl)
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 initialize(m): m.fs.evaporator.inlet_condenser.flow_mass_phase_comp[0, "Vap", "H2O"].fix(0.5) m.fs.evaporator.inlet_condenser.flow_mass_phase_comp[0, "Liq", "H2O"].fix(1e-8) m.fs.evaporator.inlet_condenser.temperature[0].fix(400) # K m.fs.evaporator.inlet_condenser.pressure[0].fix(0.5e5) # Pa m.fs.evaporator.initialize(outlvl=idaeslog.INFO_HIGH) m.fs.evaporator.inlet_condenser.flow_mass_phase_comp[0, "Vap", "H2O"].unfix() m.fs.evaporator.inlet_condenser.flow_mass_phase_comp[0, "Liq", "H2O"].unfix() m.fs.evaporator.inlet_condenser.temperature[0].unfix() # K m.fs.evaporator.inlet_condenser.pressure[0].unfix() # Pa propagate_state(m.fs.s01) m.fs.compressor.initialize(outlvl=idaeslog.INFO_HIGH)
def test_propagate_state_invalid_direction(): m = ConcreteModel() def block_rule(b): b.s = Set(initialize=[1, 2]) b.v1 = Var() b.v2 = Var(b.s) b.p = Port() b.p.add(b.v1, "V1") b.p.add(b.v2, "V2") return m.b1 = Block(rule=block_rule) m.b2 = Block(rule=block_rule) m.s1 = Arc(source=m.b1.p, destination=m.b2.p) with pytest.raises(ValueError): propagate_state(m.s1, direction="foo")
def test_propagate_state_reverse(): m = ConcreteModel() def block_rule(b): b.s = Set(initialize=[1, 2]) b.v1 = Var() b.v2 = Var(b.s) b.p = Port() b.p.add(b.v1, "V1") b.p.add(b.v2, "V2") return m.b1 = Block(rule=block_rule) m.b2 = Block(rule=block_rule) m.s1 = Arc(source=m.b1.p, destination=m.b2.p) # Test reverse propogation - set values on second block m.b2.v1.value = 100 m.b2.v2[1].value = 200 m.b2.v2[2].value = 300 # Make sure vars in block 1 haven't been changed accidentally assert m.b1.v1.value is None assert m.b1.v2[1].value is None assert m.b1.v2[2].value is None propagate_state(m.s1, direction="backward") # Check that values were propagated correctly assert m.b2.v1.value == m.b1.v1.value assert m.b2.v2[1].value == m.b1.v2[1].value assert m.b2.v2[2].value == m.b1.v2[2].value assert m.b1.v1.fixed is False assert m.b1.v2[1].fixed is False assert m.b1.v2[2].fixed is False assert m.b2.v1.fixed is False assert m.b2.v2[1].fixed is False assert m.b2.v2[2].fixed is False
def initialize(self, state_args=None, solver=None, optarg=None, outlvl=idaeslog.NOTSET): init_log = idaeslog.getInitLogger(self.name, outlvl, tag="unit") solver = get_solver(solver=solver, options=optarg) self.compressor.initialize(state_args=state_args, outlvl=outlvl) propagate_state(self.comp_to_reactor) self.stoic_reactor.initialize(outlvl=outlvl) propagate_state(self.reactor_to_turbine) self.turbine.initialize(outlvl=outlvl) with idaeslog.solver_log(init_log, idaeslog.DEBUG) as slc: res = solver.solve(self, tee=slc.tee) init_log.info("Hydrogen Turbine initialization status {}.".format( idaeslog.condition(res)))
def test_propagate_state_Expression(): m = ConcreteModel() def block_rule(b): b.s = Set(initialize=[1, 2]) b.v1 = Var() b.v2 = Var(b.s) b.e = Expression(expr=b.v1) b.p = Port() b.p.add(b.e, "E") b.p.add(b.v2, "V2") return m.b1 = Block(rule=block_rule) m.b2 = Block(rule=block_rule) m.s1 = Arc(source=m.b1.p, destination=m.b2.p) with pytest.raises(TypeError): propagate_state(m.s1)
def test_propagate_state_indexed(): m = ConcreteModel() def block_rule(b): b.s = Set(initialize=[1, 2]) b.v1 = Var() b.v2 = Var(b.s) b.p = Port(b.s) b.p[1].add(b.v1, "V1") b.p[2].add(b.v2, "V2") return m.b1 = Block(rule=block_rule) m.b2 = Block(rule=block_rule) def arc_rule(m, i): return {'source': m.b1.p[i], 'destination': m.b2.p[i]} m.s1 = Arc([1, 2], rule=arc_rule) with pytest.raises(AttributeError): propagate_state(m.s1)
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 initialize(m): # initialize feed m.fs.feed.initialize() propagate_state(m.fs.s_prtrt_feed_mixer) # initializer mixer pssb.initialize_stoich_softening_mixer(m.fs.stoich_softening_mixer_unit, debug_out=False) # initializer reactor propagate_state(m.fs.stoich_softening_arc_mixer_to_reactor) pssb.initialize_stoich_softening_reactor(m.fs.stoich_softening_reactor_unit, debug_out=False) # initializer separator propagate_state(m.fs.stoich_softening_arc_reactor_to_separator) pssb.initialize_stoich_softening_separator(m.fs.stoich_softening_separator_unit, debug_out=False)
def initialize_model(m): m.fs.pem.initialize() propagate_state(m.fs.pem_to_translator) m.fs.translator.initialize() # Initialize mixer propagate_state(m.fs.translator_to_mixer) m.fs.mixer.initialize() # Begin Initialization and solve for the system. propagate_state(m.fs.mixer_to_turbine) m.fs.h2_turbine.initialize() return m
def _init_section( self, stages, splits, disconnects, prev_port, outlvl, solver, optarg, copy_disconneted_flow, copy_disconneted_pressure, ): """ Reuse the initializtion for HP, IP and, LP sections. """ if 0 in splits: propagate_state(splits[0].inlet, prev_port) splits[0].initialize(outlvl=outlvl, solver=solver, optarg=optarg) prev_port = splits[0].outlet_1 for i in stages: if i - 1 not in disconnects: propagate_state(stages[i].inlet, prev_port) else: if copy_disconneted_flow: for t in stages[i].inlet.flow_mol: stages[i].inlet.flow_mol[t] = pyo.value( prev_port.flow_mol[t]) if copy_disconneted_pressure: for t in stages[i].inlet.pressure: stages[i].inlet.pressure[t] = pyo.value( prev_port.pressure[t]) stages[i].initialize(outlvl=outlvl, solver=solver, optarg=optarg) prev_port = stages[i].outlet if i in splits: propagate_state(splits[i].inlet, prev_port) splits[i].initialize(outlvl=outlvl, solver=solver, optarg=optarg) prev_port = splits[i].outlet_1 return prev_port
def initialize(m, **kwargs): propagate_state(m.fs.s_tb_desal) desalination.initialize_desalination(m, **kwargs) m.fs.desal_saturation.properties.initialize()
def initialize_pretreatment_NF(m, **kwargs): optarg = {"nlp_scaling_method": "user-scaling"} if kwargs["has_bypass"]: m.fs.feed.initialize(optarg=optarg) propagate_state(m.fs.s_pretrt_feed_splitter) m.fs.splitter.initialize(optarg=optarg) propagate_state(m.fs.s_pretrt_splitter_mixer) if kwargs["NF_type"] == "ZO": propagate_state(m.fs.s_pretrt_splitter_pumpNF) m.fs.pump_NF.initialize(optarg=optarg) propagate_state(m.fs.s_pretrt_pumpNF_NF) m.fs.NF.initialize(optarg=optarg) else: # NF_type == 'Sep' propagate_state(m.fs.s_pretrt_splitter_NF) # m.fs.NF.initialize(optarg=optarg) # IDAES error when NF is a separator TODO: address in IDAES propagate_state(m.fs.s_pretrt_NF_mixer) m.fs.mixer.initialize(optarg=optarg) else: # no bypass m.fs.feed.initialize(optarg=optarg) if kwargs["NF_type"] == "ZO": propagate_state(m.fs.s_pretrt_feed_pumpNF) m.fs.pump_NF.initialize(optarg=optarg) propagate_state(m.fs.s_pretrt_pumpNF_NF) m.fs.NF.initialize(optarg=optarg) else: # NF_type == 'Sep' propagate_state(m.fs.s_pretrt_feed_NF)
def do_initialization_pass(m, optarg, guess_mixers): # start with the feed m.fs.feed.initialize(optarg=optarg) propagate_state(m.fs.feed_to_pump) last_stage = m.fs.StageSet.last() first_stage = m.fs.StageSet.first() for stage in m.fs.StageSet: m.fs.PrimaryPumps[stage].initialize(optarg=optarg) if stage == last_stage: propagate_state(m.fs.pump_to_stage) else: propagate_state(m.fs.pump_to_mixer[stage]) if guess_mixers: _lsrro_mixer_guess_initializer( m.fs.Mixers[stage], solvent_multiplier=0.5, solute_multiplier=0.2, optarg=optarg ) else: m.fs.Mixers[stage].initialize(optarg=optarg) propagate_state(m.fs.mixer_to_stage[stage]) m.fs.ROUnits[stage].initialize(optarg=optarg) if stage == first_stage: propagate_state(m.fs.primary_RO_to_product) else: propagate_state(m.fs.stage_to_eq_pump[stage]) m.fs.BoosterPumps[stage].initialize(optarg=optarg) propagate_state(m.fs.eq_pump_to_mixer[stage]) if stage == last_stage: propagate_state(m.fs.stage_to_erd) else: propagate_state(m.fs.stage_to_pump[stage]) # for the end stage propagate_state(m.fs.erd_to_disposal)
def initialize_system(m, solver_dict=None): solver_str = solver_dict['solver_str'] solver_opt = solver_dict['solver_opt'] solver = solver_dict['solver'] # ---initialize feed block--- m.fs.feed.initialize(solver=solver_str, optarg=solver_opt) # ---initialize splitter and pressure exchanger--- # pressure exchanger high pressure inlet propagate_state( m.fs.s06) # propagate to PXR high pressure inlet from RO retentate m.fs.PXR.high_pressure_side.properties_in.initialize(solver=solver_str, optarg=solver_opt) # splitter inlet propagate_state(m.fs.s01) # propagate to splitter inlet from feed m.fs.S1.mixed_state[ 0].mass_frac_phase_comp # touch property, so that it is built and can be solved for m.fs.S1.mixed_state.initialize(solver=solver_str, optarg=solver_opt) # splitter outlet to PXR, enforce same flow_vol as PXR high pressure inlet m.fs.S1.PXR_state[0].pressure.fix(value(m.fs.S1.mixed_state[0].pressure)) m.fs.S1.PXR_state[0].temperature.fix( value(m.fs.S1.mixed_state[0].temperature)) m.fs.S1.PXR_state[0].flow_vol_phase['Liq'].fix( value(m.fs.PXR.high_pressure_side.properties_in[0]. flow_vol_phase['Liq'])) m.fs.S1.PXR_state[0].mass_frac_phase_comp['Liq', 'NaCl'].fix( value(m.fs.S1.mixed_state[0].mass_frac_phase_comp['Liq', 'NaCl'])) check_dof(m.fs.S1.PXR_state[0]) results = solve_indexed_blocks(solver, [m.fs.S1.PXR_state]) check_solve(results) # unfix PXR_state state variables and properties m.fs.S1.PXR_state[0].pressure.unfix() m.fs.S1.PXR_state[0].temperature.unfix() m.fs.S1.PXR_state[0].flow_vol_phase['Liq'].unfix() m.fs.S1.PXR_state[0].mass_frac_phase_comp['Liq', 'NaCl'].unfix() m.fs.S1.PXR_state[0].flow_mass_phase_comp['Liq', 'NaCl'].fix() # splitter initialization m.fs.S1.initialize(solver=solver_str, optarg=solver_opt) m.fs.S1.PXR_state[0].flow_mass_phase_comp['Liq', 'NaCl'].unfix() # pressure exchanger low pressure inlet propagate_state(m.fs.s08) # pressure exchanger initialization m.fs.PXR.initialize(solver=solver_str, optarg=solver_opt) # ---initialize pump 1--- propagate_state(m.fs.s02) m.fs.P1.initialize(solver=solver_str, optarg=solver_opt) # ---initialize pump 2--- propagate_state(m.fs.s09) m.fs.P2.control_volume.properties_out[0].pressure.fix( value(m.fs.P2.control_volume.properties_out[0].pressure)) m.fs.P2.initialize(solver=solver_str, optarg=solver_opt) m.fs.P2.control_volume.properties_out[0].pressure.unfix() # ---initialize mixer--- propagate_state(m.fs.s03) propagate_state(m.fs.s10) m.fs.M1.initialize(solver=solver_str, optarg=solver_opt, outlvl=idaeslog.INFO)
def test_propagate_state_invalid_stream(): m = ConcreteModel() with pytest.raises(RuntimeError): propagate_state(m)
def create_model( time_set=None, time_units=pyo.units.s, nfe=5, tee=False, calc_integ=True, ): """Create a test model and solver Args: time_set (list): The beginning and end point of the time domain time_units (Pyomo Unit object): Units of time domain nfe (int): Number of finite elements argument for the DAE transformation. calc_integ (bool): If True, calculate in the initial condition for the integral term, else use a fixed variable (fs.ctrl.err_i0), False is the better option if you have a value from a previous time period Returns (tuple): (ConcreteModel, Solver) """ fs_cfg = {"dynamic": True, "time_set": time_set, "time_units": time_units} model_name = "Steam Tank, Dynamic" if time_set is None: time_set = [0, 3] m = pyo.ConcreteModel(name=model_name) m.fs = FlowsheetBlock(default=fs_cfg) # Create a property parameter block m.fs.prop_water = iapws95.Iapws95ParameterBlock( default={"phase_presentation": iapws95.PhaseType.LG}) # Create the valve and tank models m.fs.valve_1 = Valve( default={ "dynamic": False, "has_holdup": False, "pressure_flow_callback": _valve_pressure_flow_cb, "material_balance_type": MaterialBalanceType.componentTotal, "property_package": m.fs.prop_water, }) m.fs.tank = Heater( default={ "has_holdup": True, "material_balance_type": MaterialBalanceType.componentTotal, "property_package": m.fs.prop_water, }) m.fs.valve_2 = Valve( default={ "dynamic": False, "has_holdup": False, "pressure_flow_callback": _valve_pressure_flow_cb, "material_balance_type": MaterialBalanceType.componentTotal, "property_package": m.fs.prop_water, }) # Add a controller m.fs.ctrl = PIDController( default={ "process_var": m.fs.tank.control_volume.properties_out[:].pressure, "manipulated_var": m.fs.valve_1.valve_opening, "calculate_initial_integral": calc_integ, "mv_bound_type": ControllerMVBoundType.SMOOTH_BOUND, "type": ControllerType.PI, # rather use PI, but testing all terms }) # The control volume block doesn't assume the two phases are in equilibrium # by default, so I'll make that assumption here, I don't actually expect # liquid to form but who knows. The phase_fraction in the control volume is # volumetric phase fraction hence the densities. @m.fs.tank.Constraint(m.fs.time) def vol_frac_vap(b, t): return (b.control_volume.properties_out[t].phase_frac["Vap"] * b.control_volume.properties_out[t].dens_mol / b.control_volume.properties_out[t].dens_mol_phase["Vap"]) == ( b.control_volume.phase_fraction[t, "Vap"]) # Connect the models m.fs.v1_to_tank = Arc(source=m.fs.valve_1.outlet, destination=m.fs.tank.inlet) m.fs.tank_to_v2 = Arc(source=m.fs.tank.outlet, destination=m.fs.valve_2.inlet) # Add the stream constraints and do the DAE transformation pyo.TransformationFactory("network.expand_arcs").apply_to(m.fs) pyo.TransformationFactory("dae.finite_difference").apply_to( m.fs, nfe=nfe, wrt=m.fs.time, scheme="BACKWARD") # Fix the derivative variables to zero at time 0 (steady state assumption) m.fs.fix_initial_conditions() # Fix the input variables m.fs.valve_1.inlet.enth_mol.fix(50000) m.fs.valve_1.inlet.pressure.fix(5e5) m.fs.valve_2.outlet.pressure.fix(101325) m.fs.valve_1.Cv.fix(0.001) m.fs.valve_2.Cv.fix(0.001) m.fs.valve_1.valve_opening.fix(1) m.fs.valve_2.valve_opening.fix(1) m.fs.tank.heat_duty.fix(0) m.fs.tank.control_volume.volume.fix(2.0) #Fix controller settings m.fs.ctrl.gain_p.fix(1e-6) m.fs.ctrl.gain_i.fix(1e-5) #m.fs.ctrl.gain_d.fix(1e-6) #m.fs.ctrl.derivative_of_error[m.fs.time.first()].fix(0) m.fs.ctrl.setpoint.fix(3e5) m.fs.ctrl.mv_ref.fix(0) m.fs.ctrl.mv_lb = 0.0 m.fs.ctrl.mv_ub = 1.0 for t in m.fs.time: m.fs.valve_1.inlet.flow_mol[t] = 100 # initial guess on flow # simple initialize m.fs.valve_1.initialize() propagate_state(m.fs.v1_to_tank) m.fs.tank.initialize() propagate_state(m.fs.tank_to_v2) # Can't specify both flow and outlet pressure so free the outlet pressure # for initialization and refix it after. Inlet flow gets fixed in init, but # is unfixed for the final problem m.fs.valve_2.outlet.pressure.unfix() m.fs.valve_2.initialize() m.fs.valve_2.outlet.pressure.fix(101325) m.fs.valve_1.valve_opening.unfix() m.fs.valve_1.valve_opening[m.fs.time.first()].fix() # Return the model and solver return m
def fix_dof_and_initialize(m, **kwargs): """ This function fixes the degrees of freedom of each unit and initializes it np_power_output : Power output from nuclear power plant in kW pem_outlet_pressure : Outlet pressure of hydrogen from PEM in bar pem_outlet_temperature: Outlet temperature of hydrogen from PEM in K air_h2_ratio : Ratio of molar flowrate of air to molar flowrate of hydrogen entering the hydrogen turbine compressor_dp : Pressure difference (in bar) between the outlet and the inlet of the hydrogen turbine's compressor. The same pressure difference is used for hydrogen turbine's turbine. """ options = kwargs.get("options", {}) np_power_output = options.get("np_power_output", 1000 * 1e3) pem_outlet_pressure = options.get("pem_outlet_pressure", 1.01325) pem_outlet_temperature = options.get("pem_outlet_temperature", 300) air_h2_ratio = options.get("air_h2_ratio", 10.76) compressor_dp = options.get("compressor_dp", 24.01) # Fix the dof of the electrical splitter and initialize m.fs.np_power_split.electricity[0].fix(np_power_output) # in kW m.fs.np_power_split.split_fraction["np_to_grid", 0].fix(0.8) m.fs.np_power_split.initialize() # Fix the dof of the electrolyzer and initialize # Conversion of kW to mol/sec of H2 based on H-tec design of 54.517kW-hr/kg m.fs.pem.electricity_to_mol.fix(0.002527406) m.fs.pem.outlet.pressure.fix(pem_outlet_pressure * 1e5) m.fs.pem.outlet.temperature.fix(pem_outlet_temperature) propagate_state(m.fs.arc_np_to_pem) m.fs.pem.initialize() # Fix the dof of the tank and initialize m.fs.h2_tank.dt.fix(3600) m.fs.h2_tank.tank_holdup_previous.fix(0) m.fs.h2_tank.outlet_to_turbine.flow_mol.fix(10) m.fs.h2_tank.outlet_to_pipeline.flow_mol.fix(10) m.fs.h2_tank.outlet_to_turbine.mole_frac_comp[0, "hydrogen"].fix(1) m.fs.h2_tank.outlet_to_pipeline.mole_frac_comp[0, "hydrogen"].fix(1) propagate_state(m.fs.arc_pem_to_h2_tank) m.fs.h2_tank.initialize() # Fix the dof of the translator block and initialize m.fs.translator.outlet.mole_frac_comp[0, "hydrogen"].fix(0.99) m.fs.translator.outlet.mole_frac_comp[0, "oxygen"].fix(0.01 / 4) m.fs.translator.outlet.mole_frac_comp[0, "argon"].fix(0.01 / 4) m.fs.translator.outlet.mole_frac_comp[0, "nitrogen"].fix(0.01 / 4) m.fs.translator.outlet.mole_frac_comp[0, "water"].fix(0.01 / 4) propagate_state(m.fs.arc_h2_tank_to_translator) m.fs.translator.initialize() # Fix the degrees of freedom of mixer and initialize m.fs.mixer.air_feed.flow_mol[0].fix( m.fs.h2_tank.outlet_to_turbine.flow_mol[0].value * air_h2_ratio ) m.fs.mixer.air_feed.temperature[0].fix(pem_outlet_temperature) m.fs.mixer.air_feed.pressure[0].fix(pem_outlet_pressure * 1e5) m.fs.mixer.air_feed.mole_frac_comp[0, "oxygen"].fix(0.2054) m.fs.mixer.air_feed.mole_frac_comp[0, "argon"].fix(0.0032) m.fs.mixer.air_feed.mole_frac_comp[0, "nitrogen"].fix(0.7672) m.fs.mixer.air_feed.mole_frac_comp[0, "water"].fix(0.0240) m.fs.mixer.air_feed.mole_frac_comp[0, "hydrogen"].fix(2e-4) propagate_state(m.fs.arc_translator_to_mixer) m.fs.mixer.initialize() # Fix the degrees of freedom of H2 turbine and initialize m.fs.h2_turbine.compressor.deltaP.fix(compressor_dp * 1e5) m.fs.h2_turbine.compressor.efficiency_isentropic.fix(0.86) m.fs.h2_turbine.stoic_reactor.conversion.fix(0.99) m.fs.h2_turbine.turbine.deltaP.fix(-compressor_dp * 1e5) m.fs.h2_turbine.turbine.efficiency_isentropic.fix(0.89) propagate_state(m.fs.arc_mixer_to_h2_turbine) m.fs.h2_turbine.initialize() return
def test_propagate_state(): m = ConcreteModel() def block_rule(b): b.s = Set(initialize=[1, 2]) b.v1 = Var() b.v2 = Var(b.s) b.e1 = Expression(expr=b.v1) @b.Expression(b.s) def e2(blk, i): return b.v2[i] * b.v1 b.p1 = Param(mutable=True, initialize=5) b.p2 = Param(b.s, mutable=True, initialize=6) b.port1 = Port() b.port1.add(b.v1, "V1") b.port1.add(b.v2, "V2") b.port2 = Port() b.port2.add(b.v1, "V1") b.port2.add(b.e2, "V2") b.port3 = Port() b.port3.add(b.e1, "V1") b.port3.add(b.v2, "V2") b.port4 = Port() b.port4.add(b.p1, "V1") b.port4.add(b.v2, "V2") b.port5 = Port() b.port5.add(b.v1, "V1") b.port5.add(b.p2, "V2") b.port6 = Port() b.port6.add(b.v1, "V1") b.port6.add(b.v1, "V2") return m.b1 = Block(rule=block_rule) m.b2 = Block(rule=block_rule) m.s1 = Arc(source=m.b1.port1, destination=m.b2.port1) m.s2 = Arc(source=m.b1.port1, destination=m.b2.port2) m.s3 = Arc(source=m.b1.port1, destination=m.b2.port3) m.s4 = Arc(source=m.b1.port1, destination=m.b2.port4) m.s5 = Arc(source=m.b1.port1, destination=m.b2.port5) m.s6 = Arc(source=m.b1.port2, destination=m.b2.port1) m.s7 = Arc(source=m.b1.port3, destination=m.b2.port1) m.s8 = Arc(source=m.b1.port4, destination=m.b2.port1) m.s9 = Arc(source=m.b1.port5, destination=m.b2.port1) m.s10 = Arc(source=m.b1.port6, destination=m.b2.port1) m.s11 = Arc(source=m.b2.port6, destination=m.b1.port1) # Set values on first block m.b1.v1.value = 10 m.b1.v2[1].value = 20 m.b1.v2[2].value = 30 # Make sure vars in block 2 haven't been changed accidentally assert m.b2.v1.value is None assert m.b2.v2[1].value is None assert m.b2.v2[2].value is None propagate_state(m.s1) # Check that values were propagated correctly assert m.b2.v1.value == m.b1.v1.value assert m.b2.v2[1].value == m.b1.v2[1].value assert m.b2.v2[2].value == m.b1.v2[2].value assert m.b1.v1.fixed is False assert m.b1.v2[1].fixed is False assert m.b1.v2[2].fixed is False assert m.b2.v1.fixed is False assert m.b2.v2[1].fixed is False assert m.b2.v2[2].fixed is False with pytest.raises(TypeError): propagate_state(m.s2) with pytest.raises(TypeError): propagate_state(m.s3) with pytest.raises(TypeError): propagate_state(m.s4) with pytest.raises(TypeError): propagate_state(m.s5) propagate_state(m.s6) assert value(m.b1.v1) == value(m.b2.v1) assert value(m.b1.e2[1]) == value(m.b2.v2[1]) assert value(m.b1.e2[2]) == value(m.b2.v2[2]) propagate_state(m.s7) assert value(m.b1.e1) == value(m.b2.v1) assert value(m.b1.v2[1]) == value(m.b2.v2[1]) assert value(m.b1.v2[2]) == value(m.b2.v2[2]) propagate_state(m.s8) assert value(m.b1.p1) == value(m.b2.v1) assert value(m.b1.v2[1]) == value(m.b2.v2[1]) assert value(m.b1.v2[2]) == value(m.b2.v2[2]) propagate_state(m.s9) assert value(m.b1.v1) == value(m.b2.v1) assert value(m.b1.p2[1]) == value(m.b2.v2[1]) assert value(m.b1.p2[2]) == value(m.b2.v2[2]) with pytest.raises(KeyError): propagate_state(m.s10) with pytest.raises(KeyError): propagate_state(m.s11)
def test_ASM1_reactor(): m = pyo.ConcreteModel() m.fs = FlowsheetBlock(default={"dynamic": False}) m.fs.props = ASM1ParameterBlock() m.fs.rxn_props = ASM1ReactionParameterBlock( default={"property_package": m.fs.props}) m.fs.R1 = CSTR(default={ "property_package": m.fs.props, "reaction_package": m.fs.rxn_props, }) m.fs.R2 = CSTR(default={ "property_package": m.fs.props, "reaction_package": m.fs.rxn_props, }) m.fs.R3 = CSTR(default={ "property_package": m.fs.props, "reaction_package": m.fs.rxn_props, }) m.fs.R4 = CSTR(default={ "property_package": m.fs.props, "reaction_package": m.fs.rxn_props, }) m.fs.R5 = CSTR(default={ "property_package": m.fs.props, "reaction_package": m.fs.rxn_props, }) # Link units m.fs.stream1 = Arc(source=m.fs.R1.outlet, destination=m.fs.R2.inlet) m.fs.stream2 = Arc(source=m.fs.R2.outlet, destination=m.fs.R3.inlet) m.fs.stream3 = Arc(source=m.fs.R3.outlet, destination=m.fs.R4.inlet) m.fs.stream4 = Arc(source=m.fs.R4.outlet, destination=m.fs.R5.inlet) pyo.TransformationFactory("network.expand_arcs").apply_to(m) assert_units_consistent(m) # Feed conditions based on manual mass balance of inlet and recycle streams m.fs.R1.inlet.flow_vol.fix(92230 * pyo.units.m**3 / pyo.units.day) m.fs.R1.inlet.temperature.fix(298.15 * pyo.units.K) m.fs.R1.inlet.pressure.fix(1 * pyo.units.atm) m.fs.R1.inlet.conc_mass_comp[0, "S_I"].fix(30 * pyo.units.g / pyo.units.m**3) m.fs.R1.inlet.conc_mass_comp[0, "S_S"].fix(14.6112 * pyo.units.g / pyo.units.m**3) m.fs.R1.inlet.conc_mass_comp[0, "X_I"].fix(1149 * pyo.units.g / pyo.units.m**3) m.fs.R1.inlet.conc_mass_comp[0, "X_S"].fix(89.324 * pyo.units.g / pyo.units.m**3) m.fs.R1.inlet.conc_mass_comp[0, "X_BH"].fix(2542.03 * pyo.units.g / pyo.units.m**3) m.fs.R1.inlet.conc_mass_comp[0, "X_BA"].fix(148.6 * pyo.units.g / pyo.units.m**3) m.fs.R1.inlet.conc_mass_comp[0, "X_P"].fix(448 * pyo.units.g / pyo.units.m**3) m.fs.R1.inlet.conc_mass_comp[0, "S_O"].fix(0.3928 * pyo.units.g / pyo.units.m**3) m.fs.R1.inlet.conc_mass_comp[0, "S_NO"].fix(8.32 * pyo.units.g / pyo.units.m**3) m.fs.R1.inlet.conc_mass_comp[0, "S_NH"].fix(7.696 * pyo.units.g / pyo.units.m**3) m.fs.R1.inlet.conc_mass_comp[0, "S_ND"].fix(1.9404 * pyo.units.g / pyo.units.m**3) m.fs.R1.inlet.conc_mass_comp[0, "X_ND"].fix(5.616 * pyo.units.g / pyo.units.m**3) m.fs.R1.inlet.alkalinity.fix(4.704 * pyo.units.mol / pyo.units.m**3) m.fs.R1.volume.fix(1000 * pyo.units.m**3) m.fs.R2.volume.fix(1000 * pyo.units.m**3) m.fs.R3.volume.fix(1333 * pyo.units.m**3) m.fs.R4.volume.fix(1333 * pyo.units.m**3) m.fs.R5.volume.fix(1333 * pyo.units.m**3) assert degrees_of_freedom(m) == 0 # Initialize flowsheet m.fs.R1.initialize() propagate_state(m.fs.stream1) m.fs.R2.initialize() propagate_state(m.fs.stream2) m.fs.R3.initialize() propagate_state(m.fs.stream3) m.fs.R4.initialize() propagate_state(m.fs.stream4) m.fs.R5.initialize() # For aerobic reactors, need to fix the oxygen concentration in outlet # To do this, we also need to deactivate the constraint linking O2 from # the previous unit # Doing this before initialization will cause issues with DoF however m.fs.R3.outlet.conc_mass_comp[0, "S_O"].fix(1.72 * pyo.units.g / pyo.units.m**3) m.fs.stream2.expanded_block.conc_mass_comp_equality[0, "S_O"].deactivate() m.fs.R4.outlet.conc_mass_comp[0, "S_O"].fix(2.43 * pyo.units.g / pyo.units.m**3) m.fs.stream3.expanded_block.conc_mass_comp_equality[0, "S_O"].deactivate() m.fs.R5.outlet.conc_mass_comp[0, "S_O"].fix(0.491 * pyo.units.g / pyo.units.m**3) m.fs.stream4.expanded_block.conc_mass_comp_equality[0, "S_O"].deactivate() solver = get_solver() results = solver.solve(m, tee=True) assert pyo.check_optimal_termination(results) # Verify results against reference # First reactor (anoxic) assert pyo.value(m.fs.R1.outlet.flow_vol[0]) == pytest.approx(1.0675, rel=1e-4) assert pyo.value(m.fs.R1.outlet.temperature[0]) == pytest.approx(298.15, rel=1e-4) assert pyo.value(m.fs.R1.outlet.pressure[0]) == pytest.approx(101325, rel=1e-4) assert pyo.value(m.fs.R1.outlet.conc_mass_comp[0, "S_I"]) == pytest.approx( 30e-3, rel=1e-5) assert pyo.value(m.fs.R1.outlet.conc_mass_comp[0, "S_S"]) == pytest.approx( 2.81e-3, rel=1e-2) assert pyo.value(m.fs.R1.outlet.conc_mass_comp[0, "X_I"]) == pytest.approx( 1149e-3, rel=1e-3) assert pyo.value(m.fs.R1.outlet.conc_mass_comp[0, "X_S"]) == pytest.approx( 82.1e-3, rel=1e-2) assert pyo.value( m.fs.R1.outlet.conc_mass_comp[0, "X_BH"]) == pytest.approx(2552e-3, rel=1e-3) assert pyo.value( m.fs.R1.outlet.conc_mass_comp[0, "X_BA"]) == pytest.approx(149e-3, rel=1e-2) assert pyo.value(m.fs.R1.outlet.conc_mass_comp[0, "X_P"]) == pytest.approx( 449e-3, rel=1e-2) assert pyo.value(m.fs.R1.outlet.conc_mass_comp[0, "S_O"]) == pytest.approx( 4.3e-6, rel=1e-2) assert pyo.value( m.fs.R1.outlet.conc_mass_comp[0, "S_NO"]) == pytest.approx(5.36e-3, rel=1e-2) assert pyo.value( m.fs.R1.outlet.conc_mass_comp[0, "S_NH"]) == pytest.approx(7.92e-3, rel=1e-2) assert pyo.value( m.fs.R1.outlet.conc_mass_comp[0, "S_ND"]) == pytest.approx(1.22e-3, rel=1e-2) assert pyo.value( m.fs.R1.outlet.conc_mass_comp[0, "X_ND"]) == pytest.approx(5.29e-3, rel=1e-2) assert pyo.value(m.fs.R1.outlet.alkalinity[0]) == pytest.approx(4.93e-3, rel=1e-2) # Second reactor (anoixic) assert pyo.value(m.fs.R2.outlet.flow_vol[0]) == pytest.approx(1.0675, rel=1e-4) assert pyo.value(m.fs.R2.outlet.temperature[0]) == pytest.approx(298.15, rel=1e-4) assert pyo.value(m.fs.R2.outlet.pressure[0]) == pytest.approx(101325, rel=1e-4) assert pyo.value(m.fs.R2.outlet.conc_mass_comp[0, "S_I"]) == pytest.approx( 30e-3, rel=1e-5) assert pyo.value(m.fs.R2.outlet.conc_mass_comp[0, "S_S"]) == pytest.approx( 1.46e-3, rel=1e-2) assert pyo.value(m.fs.R2.outlet.conc_mass_comp[0, "X_I"]) == pytest.approx( 1149e-3, rel=1e-3) assert pyo.value(m.fs.R2.outlet.conc_mass_comp[0, "X_S"]) == pytest.approx( 76.4e-3, rel=1e-2) assert pyo.value( m.fs.R2.outlet.conc_mass_comp[0, "X_BH"]) == pytest.approx(2553e-3, rel=1e-3) assert pyo.value( m.fs.R2.outlet.conc_mass_comp[0, "X_BA"]) == pytest.approx(148e-3, rel=1e-2) assert pyo.value(m.fs.R2.outlet.conc_mass_comp[0, "X_P"]) == pytest.approx( 449e-3, rel=1e-2) assert pyo.value(m.fs.R2.outlet.conc_mass_comp[0, "S_O"]) == pytest.approx( 6.31e-8, rel=1e-2) assert pyo.value( m.fs.R2.outlet.conc_mass_comp[0, "S_NO"]) == pytest.approx(3.65e-3, rel=1e-2) assert pyo.value( m.fs.R2.outlet.conc_mass_comp[0, "S_NH"]) == pytest.approx(8.34e-3, rel=1e-2) assert pyo.value( m.fs.R2.outlet.conc_mass_comp[0, "S_ND"]) == pytest.approx(0.882e-3, rel=1e-2) assert pyo.value( m.fs.R2.outlet.conc_mass_comp[0, "X_ND"]) == pytest.approx(5.03e-3, rel=1e-2) assert pyo.value(m.fs.R2.outlet.alkalinity[0]) == pytest.approx(5.08e-3, rel=1e-2) # Third reactor (aerobic) assert pyo.value(m.fs.R3.outlet.flow_vol[0]) == pytest.approx(1.0675, rel=1e-4) assert pyo.value(m.fs.R3.outlet.temperature[0]) == pytest.approx(298.15, rel=1e-4) assert pyo.value(m.fs.R3.outlet.pressure[0]) == pytest.approx(101325, rel=1e-4) assert pyo.value(m.fs.R3.outlet.conc_mass_comp[0, "S_I"]) == pytest.approx( 30e-3, rel=1e-5) assert pyo.value(m.fs.R3.outlet.conc_mass_comp[0, "S_S"]) == pytest.approx( 1.15e-3, rel=1e-2) assert pyo.value(m.fs.R3.outlet.conc_mass_comp[0, "X_I"]) == pytest.approx( 1149e-3, rel=1e-3) assert pyo.value(m.fs.R3.outlet.conc_mass_comp[0, "X_S"]) == pytest.approx( 64.9e-3, rel=1e-2) assert pyo.value( m.fs.R3.outlet.conc_mass_comp[0, "X_BH"]) == pytest.approx(2557e-3, rel=1e-3) assert pyo.value( m.fs.R3.outlet.conc_mass_comp[0, "X_BA"]) == pytest.approx(149e-3, rel=1e-2) assert pyo.value(m.fs.R3.outlet.conc_mass_comp[0, "X_P"]) == pytest.approx( 450e-3, rel=1e-2) assert pyo.value(m.fs.R3.outlet.conc_mass_comp[0, "S_O"]) == pytest.approx( 1.72e-3, rel=1e-2) assert pyo.value( m.fs.R3.outlet.conc_mass_comp[0, "S_NO"]) == pytest.approx(6.54e-3, rel=1e-2) assert pyo.value( m.fs.R3.outlet.conc_mass_comp[0, "S_NH"]) == pytest.approx(5.55e-3, rel=1e-2) assert pyo.value( m.fs.R3.outlet.conc_mass_comp[0, "S_ND"]) == pytest.approx(0.829e-3, rel=1e-2) assert pyo.value( m.fs.R3.outlet.conc_mass_comp[0, "X_ND"]) == pytest.approx(4.39e-3, rel=1e-2) assert pyo.value(m.fs.R3.outlet.alkalinity[0]) == pytest.approx(4.67e-3, rel=1e-2) # Fourth reactor (aerobic) assert pyo.value(m.fs.R4.outlet.flow_vol[0]) == pytest.approx(1.0675, rel=1e-4) assert pyo.value(m.fs.R4.outlet.temperature[0]) == pytest.approx(298.15, rel=1e-4) assert pyo.value(m.fs.R4.outlet.pressure[0]) == pytest.approx(101325, rel=1e-4) assert pyo.value(m.fs.R4.outlet.conc_mass_comp[0, "S_I"]) == pytest.approx( 30e-3, rel=1e-5) assert pyo.value(m.fs.R4.outlet.conc_mass_comp[0, "S_S"]) == pytest.approx( 0.995e-3, rel=1e-2) assert pyo.value(m.fs.R4.outlet.conc_mass_comp[0, "X_I"]) == pytest.approx( 1149e-3, rel=1e-3) assert pyo.value(m.fs.R4.outlet.conc_mass_comp[0, "X_S"]) == pytest.approx( 55.7e-3, rel=1e-2) assert pyo.value( m.fs.R4.outlet.conc_mass_comp[0, "X_BH"]) == pytest.approx(2559e-3, rel=1e-3) assert pyo.value( m.fs.R4.outlet.conc_mass_comp[0, "X_BA"]) == pytest.approx(150e-3, rel=1e-2) assert pyo.value(m.fs.R4.outlet.conc_mass_comp[0, "X_P"]) == pytest.approx( 451e-3, rel=1e-2) assert pyo.value(m.fs.R4.outlet.conc_mass_comp[0, "S_O"]) == pytest.approx( 2.43e-3, rel=1e-2) assert pyo.value( m.fs.R4.outlet.conc_mass_comp[0, "S_NO"]) == pytest.approx(9.30e-3, rel=1e-2) assert pyo.value( m.fs.R4.outlet.conc_mass_comp[0, "S_NH"]) == pytest.approx(2.97e-3, rel=1e-2) assert pyo.value( m.fs.R4.outlet.conc_mass_comp[0, "S_ND"]) == pytest.approx(0.767e-3, rel=1e-2) assert pyo.value( m.fs.R4.outlet.conc_mass_comp[0, "X_ND"]) == pytest.approx(3.88e-3, rel=1e-2) assert pyo.value(m.fs.R4.outlet.alkalinity[0]) == pytest.approx(4.29e-3, rel=1e-2) # Fifth reactor (aerobic) assert pyo.value(m.fs.R5.outlet.flow_vol[0]) == pytest.approx(1.0675, rel=1e-4) assert pyo.value(m.fs.R5.outlet.temperature[0]) == pytest.approx(298.15, rel=1e-4) assert pyo.value(m.fs.R5.outlet.pressure[0]) == pytest.approx(101325, rel=1e-4) assert pyo.value(m.fs.R5.outlet.conc_mass_comp[0, "S_I"]) == pytest.approx( 30e-3, rel=1e-5) assert pyo.value(m.fs.R5.outlet.conc_mass_comp[0, "S_S"]) == pytest.approx( 0.889e-3, rel=1e-2) assert pyo.value(m.fs.R5.outlet.conc_mass_comp[0, "X_I"]) == pytest.approx( 1149e-3, rel=1e-3) assert pyo.value(m.fs.R5.outlet.conc_mass_comp[0, "X_S"]) == pytest.approx( 49.3e-3, rel=1e-2) assert pyo.value( m.fs.R5.outlet.conc_mass_comp[0, "X_BH"]) == pytest.approx(2559e-3, rel=1e-3) assert pyo.value( m.fs.R5.outlet.conc_mass_comp[0, "X_BA"]) == pytest.approx(150e-3, rel=1e-2) assert pyo.value(m.fs.R5.outlet.conc_mass_comp[0, "X_P"]) == pytest.approx( 452e-3, rel=1e-2) assert pyo.value(m.fs.R5.outlet.conc_mass_comp[0, "S_O"]) == pytest.approx( 0.491e-3, rel=1e-2) assert pyo.value( m.fs.R5.outlet.conc_mass_comp[0, "S_NO"]) == pytest.approx(10.4e-3, rel=1e-2) assert pyo.value( m.fs.R5.outlet.conc_mass_comp[0, "S_NH"]) == pytest.approx(1.73e-3, rel=1e-2) assert pyo.value( m.fs.R5.outlet.conc_mass_comp[0, "S_ND"]) == pytest.approx(0.688e-3, rel=1e-2) assert pyo.value( m.fs.R5.outlet.conc_mass_comp[0, "X_ND"]) == pytest.approx(3.53e-3, rel=1e-2) assert pyo.value(m.fs.R5.outlet.alkalinity[0]) == pytest.approx(4.13e-3, rel=1e-2)
def initialize_desalination(m, **kwargs): """ Initialized the model created by build_desalination. Arguments: m: pyomo concrete model with a built desalination train **kwargs: same keywords as provided to the build_desalination function """ optarg = {"nlp_scaling_method": "user-scaling"} if kwargs["has_desal_feed"]: m.fs.feed.initialize(optarg=optarg) if kwargs["RO_type"] == "Sep": if kwargs["has_desal_feed"]: propagate_state(m.fs.s_desal_feed_RO) m.fs.RO.mixed_state[ 0].mass_frac_phase_comp # touch properties to have a constraint on stateblock m.fs.RO.permeate_state[0].mass_frac_phase_comp m.fs.RO.retentate_state[0].mass_frac_phase_comp # m.fs.RO.initialize(optarg=optarg) # IDAES error on initializing separators, simple enough to not need it elif kwargs["RO_type"] == "0D" or kwargs["RO_type"] == "1D": if kwargs["has_desal_feed"]: propagate_state(m.fs.s_desal_feed_pumpRO) m.fs.pump_RO.initialize(optarg=optarg) propagate_state(m.fs.s_desal_pumpRO_RO) m.fs.RO.initialize(optarg=optarg) if kwargs["is_twostage"]: propagate_state(m.fs.s_desal_RO_pumpRO2) m.fs.pump_RO2.initialize(optarg=optarg) propagate_state(m.fs.s_desal_pumpRO2_RO2) m.fs.RO2.initialize(optarg=optarg) propagate_state(m.fs.s_desal_permeateRO_mixer) propagate_state(m.fs.s_desal_permeateRO2_mixer) m.fs.mixer_permeate.initialize(optarg=optarg) if kwargs["has_ERD"]: if kwargs["is_twostage"]: propagate_state(m.fs.s_desal_RO2_ERD) else: propagate_state(m.fs.s_desal_RO_ERD) m.fs.ERD.initialize(optarg=optarg)