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
Beispiel #2
0
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)
Beispiel #4
0
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)
Beispiel #5
0
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)
Beispiel #6
0
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
Beispiel #8
0
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])
Beispiel #9
0
    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)
Beispiel #10
0
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
Beispiel #11
0
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)
Beispiel #19
0
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
Beispiel #20
0
 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()
Beispiel #22
0
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)
Beispiel #23
0
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)
Beispiel #24
0
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)
Beispiel #26
0
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)
Beispiel #29
0
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)
Beispiel #30
0
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)