Beispiel #1
0
    def water_model(self):
        model = ConcreteModel()
        model.fs = FlowsheetBlock(default={"dynamic": False})
        model.fs.thermo_params = GenericParameterBlock(
            default=water_thermo_config)
        model.fs.rxn_params = GenericReactionParameterBlock(
            default={
                "property_package": model.fs.thermo_params,
                **reaction_config
            })
        model.fs.unit = EquilibriumReactor(
            default={
                "property_package": model.fs.thermo_params,
                "reaction_package": model.fs.rxn_params,
                "has_rate_reactions": False,
                "has_equilibrium_reactions": False,
                "has_heat_transfer": False,
                "has_heat_of_reaction": False,
                "has_pressure_change": False,
            })

        # NOTE: ENRTL model cannot initialize if the inlet values are 0
        zero = 1e-20
        model.fs.unit.inlet.mole_frac_comp[0, "H_+"].fix(zero)
        model.fs.unit.inlet.mole_frac_comp[0, "OH_-"].fix(zero)
        model.fs.unit.inlet.mole_frac_comp[0, "H2O"].fix(1.0 - 2 * zero)
        model.fs.unit.inlet.pressure.fix(101325.0)
        model.fs.unit.inlet.temperature.fix(298.0)
        model.fs.unit.inlet.flow_mol.fix(10)

        return model
    def sapon(self):
        m = ConcreteModel()
        m.fs = FlowsheetBlock(default={"dynamic": False})

        m.fs.properties = SaponificationParameterBlock()
        m.fs.reactions = SaponificationReactionParameterBlock(default={
                                "property_package": m.fs.properties})

        m.fs.unit = EquilibriumReactor(
                default={"property_package": m.fs.properties,
                         "reaction_package": m.fs.reactions,
                         "has_equilibrium_reactions": False,
                         "has_heat_transfer": True,
                         "has_heat_of_reaction": True,
                         "has_pressure_change": True})

        m.fs.unit.inlet.flow_vol.fix(1.0e-03)
        m.fs.unit.inlet.conc_mol_comp[0, "H2O"].fix(55388.0)
        m.fs.unit.inlet.conc_mol_comp[0, "NaOH"].fix(100.0)
        m.fs.unit.inlet.conc_mol_comp[0, "EthylAcetate"].fix(100.0)
        m.fs.unit.inlet.conc_mol_comp[0, "SodiumAcetate"].fix(0.0)
        m.fs.unit.inlet.conc_mol_comp[0, "Ethanol"].fix(0.0)

        m.fs.unit.inlet.temperature.fix(303.15)
        m.fs.unit.inlet.pressure.fix(101325.0)

        m.fs.unit.heat_duty.fix(0)
        m.fs.unit.deltaP.fix(0)

        return m
    def model(self, thermo_config, variant: Variant, water_reaction_config):
        if variant.is_equilibrium:
            thermo_config = _get_without_inherent_reactions(thermo_config)
        model = ConcreteModel()
        model.fs = FlowsheetBlock(default={"dynamic": False})
        model.fs.thermo_params = GenericParameterBlock(default=thermo_config)
        print(water_reaction_config)
        model.fs.rxn_params = GenericReactionParameterBlock(
            default={
                "property_package": model.fs.thermo_params,
                **water_reaction_config
            })
        model.fs.unit = EquilibriumReactor(
            default={
                "property_package": model.fs.thermo_params,
                "reaction_package": model.fs.rxn_params,
                "has_rate_reactions": False,
                "has_equilibrium_reactions": variant.is_equilibrium,
                "has_heat_transfer": False,
                "has_heat_of_reaction": False,
                "has_pressure_change": False,
            })

        model.fs.unit.inlet.mole_frac_comp[0, "H_+"].fix(0.0)
        model.fs.unit.inlet.mole_frac_comp[0, "OH_-"].fix(0.0)
        model.fs.unit.inlet.mole_frac_comp[0, "H2O"].fix(1.0)
        model.fs.unit.inlet.pressure.fix(101325.0)
        model.fs.unit.inlet.temperature.fix(298.0)
        model.fs.unit.inlet.flow_mol.fix(10)

        return model
Beispiel #4
0
    def carbonic_acid_model(self):
        model = ConcreteModel()
        model.fs = FlowsheetBlock(default={"dynamic": False})
        model.fs.thermo_params = GenericParameterBlock(default=carbonic_thermo_config)
        model.fs.rxn_params = GenericReactionParameterBlock(
                default={"property_package": model.fs.thermo_params, **reaction_config})
        model.fs.unit = EquilibriumReactor(default={
                "property_package": model.fs.thermo_params,
                "reaction_package": model.fs.rxn_params,
                "has_rate_reactions": False,
                "has_equilibrium_reactions": False,
                "has_heat_transfer": False,
                "has_heat_of_reaction": False,
                "has_pressure_change": False})

        #NOTE: ENRTL model cannot initialize if the inlet values are 0
        zero = 1e-20
        acid = 0.00206/(55.2+0.00206)
        model.fs.unit.inlet.mole_frac_comp[0, "H_+"].fix( zero )
        model.fs.unit.inlet.mole_frac_comp[0, "OH_-"].fix( zero )

        # Added as conjugate base form
        model.fs.unit.inlet.mole_frac_comp[0, "CO3_2-"].fix( zero )
        model.fs.unit.inlet.mole_frac_comp[0, "HCO3_-"].fix( acid )
        model.fs.unit.inlet.mole_frac_comp[0, "H2CO3"].fix( zero )
        model.fs.unit.inlet.mole_frac_comp[0, "Na_+"].fix( acid )

        model.fs.unit.inlet.mole_frac_comp[0, "H2O"].fix( 1.-4*zero-acid- \
                        value(model.fs.unit.inlet.mole_frac_comp[0, "Na_+"]) )
        model.fs.unit.inlet.pressure.fix(101325.0)
        model.fs.unit.inlet.temperature.fix(298.)
        model.fs.unit.inlet.flow_mol.fix(10)

        return model
def test_config():
    m = ConcreteModel()
    m.fs = FlowsheetBlock(default={"dynamic": False})

    m.fs.properties = PhysicalParameterTestBlock()
    m.fs.reactions = ReactionParameterTestBlock(default={
                            "property_package": m.fs.properties})

    m.fs.unit = EquilibriumReactor(default={
            "property_package": m.fs.properties,
            "reaction_package": m.fs.reactions})

    # Check unit config arguments
    assert len(m.fs.unit.config) == 15

    assert not m.fs.unit.config.dynamic
    assert not m.fs.unit.config.has_holdup
    assert m.fs.unit.config.material_balance_type == \
        MaterialBalanceType.useDefault
    assert m.fs.unit.config.energy_balance_type == \
        EnergyBalanceType.useDefault
    assert m.fs.unit.config.momentum_balance_type == \
        MomentumBalanceType.pressureTotal
    assert m.fs.unit.config.has_rate_reactions
    assert not m.fs.unit.config.has_heat_transfer
    assert not m.fs.unit.config.has_pressure_change
    assert m.fs.unit.config.has_equilibrium_reactions
    assert not m.fs.unit.config.has_phase_equilibrium
    assert not m.fs.unit.config.has_heat_of_reaction
    assert m.fs.unit.config.property_package is m.fs.properties
    assert m.fs.unit.config.reaction_package is m.fs.reactions
Beispiel #6
0
def build_ideal_naocl_chlorination_unit(model):
    model.fs.ideal_naocl_chlorination_unit = EquilibriumReactor(
        default={
            "property_package": model.fs.ideal_naocl_thermo_params,
            "reaction_package": model.fs.ideal_naocl_rxn_params,
            "has_rate_reactions": False,
            "has_equilibrium_reactions": True,
            "has_heat_transfer": False,
            "has_heat_of_reaction": False,
            "has_pressure_change": False
        })

    # new var includes an initial calculation (will be overwritten later)
    fc = model.fs.ideal_naocl_chlorination_unit.inlet.mole_frac_comp[
        0, "HOCl"].value * 55.6
    fc += model.fs.ideal_naocl_chlorination_unit.inlet.mole_frac_comp[
        0, "OCl_-"].value * 55.6
    fc = fc * 70900

    model.fs.ideal_naocl_chlorination_unit.free_chlorine = Var(initialize=fc)

    def _free_chlorine_cons(blk):
        return blk.free_chlorine == ((blk.control_volume.properties_out[0.0].conc_mol_phase_comp["Liq","HOCl"]/1000) \
                                    + (blk.control_volume.properties_out[0.0].conc_mol_phase_comp["Liq","OCl_-"]/1000)) \
                                    * 70900

    model.fs.ideal_naocl_chlorination_unit.chlorine_cons = Constraint(
        rule=_free_chlorine_cons)
Beispiel #7
0
    def equilibrium_reactions_config(self):
        model = ConcreteModel()
        model.fs = FlowsheetBlock(default={"dynamic": False})
        model.fs.thermo_params = GenericParameterBlock(
            default=thermo_only_config)
        model.fs.rxn_params = GenericReactionParameterBlock(
            default={
                "property_package": model.fs.thermo_params,
                **water_reaction_config
            })
        model.fs.unit = EquilibriumReactor(
            default={
                "property_package": model.fs.thermo_params,
                "reaction_package": model.fs.rxn_params,
                "has_rate_reactions": False,
                "has_equilibrium_reactions": True,
                "has_heat_transfer": False,
                "has_heat_of_reaction": False,
                "has_pressure_change": False
            })

        model.fs.unit.inlet.mole_frac_comp[0, "H_+"].fix(0.)
        model.fs.unit.inlet.mole_frac_comp[0, "OH_-"].fix(0.)
        model.fs.unit.inlet.mole_frac_comp[0, "H2O"].fix(1.)
        model.fs.unit.inlet.pressure.fix(101325.0)
        model.fs.unit.inlet.temperature.fix(298.)
        model.fs.unit.inlet.flow_mol.fix(10)

        return model
    def chlorination_obj(self):
        model = ConcreteModel()
        model.fs = FlowsheetBlock(default={"dynamic": False})
        model.fs.thermo_params = GenericParameterBlock(default=thermo_config)
        model.fs.rxn_params = GenericReactionParameterBlock(
            default={
                "property_package": model.fs.thermo_params,
                **reaction_config
            })
        model.fs.unit = EquilibriumReactor(
            default={
                "property_package": model.fs.thermo_params,
                "reaction_package": model.fs.rxn_params,
                "has_rate_reactions": False,
                "has_equilibrium_reactions": True,
                "has_heat_transfer": False,
                "has_heat_of_reaction": False,
                "has_pressure_change": False
            })

        model.fs.unit.inlet.mole_frac_comp[0, "H_+"].fix(0.)
        model.fs.unit.inlet.mole_frac_comp[0, "OH_-"].fix(0.)
        model.fs.unit.inlet.mole_frac_comp[0, "OCl_-"].fix(0.)
        model.fs.unit.inlet.mole_frac_comp[0, "NH4_+"].fix(0.)

        model.fs.unit.inlet.mole_frac_comp[0, "NH2Cl"].fix(0.)
        model.fs.unit.inlet.mole_frac_comp[0, "NHCl2"].fix(0.)
        model.fs.unit.inlet.mole_frac_comp[0, "NCl3"].fix(0.)

        waste_stream_ammonia = 1  #mg/L
        total_molar_density = 54.8  #mol/L
        total_ammonia_inlet = waste_stream_ammonia / 17000  # mol/L
        total_molar_density += total_ammonia_inlet

        # Free Chlorine (mg-Cl2/L) = total_chlorine_inlet (mol/L) * 70,900
        free_chlorine_added = 15  #mg/L as Cl2
        total_chlorine_inlet = free_chlorine_added / 70900  # mol/L
        total_molar_density += total_chlorine_inlet

        model.fs.unit.inlet.mole_frac_comp[0, "NH3"].fix(total_ammonia_inlet /
                                                         total_molar_density)
        model.fs.unit.inlet.mole_frac_comp[0, "HOCl"].fix(
            total_chlorine_inlet / total_molar_density)

        # Perform a summation of all non-H2O molefractions to find the H2O molefraction
        sum = 0
        for i in model.fs.unit.inlet.mole_frac_comp:
            # NOTE: i will be a tuple with format (time, component)
            if i[1] != "H2O":
                sum += value(model.fs.unit.inlet.mole_frac_comp[i[0], i[1]])

        model.fs.unit.inlet.mole_frac_comp[0, "H2O"].fix(1 - sum)

        model.fs.unit.inlet.pressure.fix(101325.0)
        model.fs.unit.inlet.temperature.fix(300.)
        model.fs.unit.inlet.flow_mol.fix(10)

        return model
    def equilibrium_reactions_config(self):
        model = ConcreteModel()
        model.fs = FlowsheetBlock(default={"dynamic": False})
        model.fs.thermo_params = GenericParameterBlock(
            default=thermo_only_config)
        model.fs.rxn_params = GenericReactionParameterBlock(
            default={
                "property_package": model.fs.thermo_params,
                **reaction_config
            })
        model.fs.unit = EquilibriumReactor(
            default={
                "property_package": model.fs.thermo_params,
                "reaction_package": model.fs.rxn_params,
                "has_rate_reactions": False,
                "has_equilibrium_reactions": True,
                "has_heat_transfer": False,
                "has_heat_of_reaction": False,
                "has_pressure_change": False
            })

        model.fs.unit.inlet.mole_frac_comp[0, "H_+"].fix(0.)
        model.fs.unit.inlet.mole_frac_comp[0, "OH_-"].fix(0.)
        model.fs.unit.inlet.mole_frac_comp[0, "HCO3_-"].fix(0.)
        model.fs.unit.inlet.mole_frac_comp[0, "CO3_2-"].fix(0.)

        total_nacl_inlet = 0.55  # mol/L
        total_carbonate_inlet = 0.00206  # mol/L
        frac_CO3_to_NaHCO3 = 1

        model.fs.unit.inlet.mole_frac_comp[0,
                                           "Na_+"].fix(total_nacl_inlet / 54.8)
        model.fs.unit.inlet.mole_frac_comp[0,
                                           "Cl_-"].fix(total_nacl_inlet / 54.8)

        model.fs.unit.inlet.mole_frac_comp[0, "NaHCO3"].fix(
            (total_carbonate_inlet * frac_CO3_to_NaHCO3) / 54.8)
        model.fs.unit.inlet.mole_frac_comp[0, "H2CO3"].fix(
            (total_carbonate_inlet * (1 - frac_CO3_to_NaHCO3)) / 54.8)

        # Perform a summation of all non-H2O molefractions to find the H2O molefraction
        sum = 0
        for i in model.fs.unit.inlet.mole_frac_comp:
            # NOTE: i will be a tuple with format (time, component)
            if i[1] != "H2O":
                sum += value(model.fs.unit.inlet.mole_frac_comp[i[0], i[1]])

        model.fs.unit.inlet.mole_frac_comp[0, "H2O"].fix(1 - sum)

        model.fs.unit.inlet.pressure.fix(101325.0)
        model.fs.unit.inlet.temperature.fix(298.)
        model.fs.unit.inlet.flow_mol.fix(10)

        return model
Beispiel #10
0
def run_the_basics_dummy_rxn_with_mockdb(db):
    base_obj = grab_base_thermo_config(db)

    (base_obj,
     comp_list) = get_components_and_add_to_idaes_config(db,
                                                         base_obj,
                                                         by_elements=True)

    # Add reactions to the thermo base as 'inherent'
    base_obj = get_reactions_return_object(db,
                                           base_obj,
                                           comp_list,
                                           is_inherent=True)

    # Create a reaction config
    react_base = grab_base_reaction_config(db)

    # If no reactions are in the reaction base, this will cause an error in IDAES.
    #   However, we can add a 'dummy' reaction just to satisfy the IDAES code base.
    react_obj = db.get_reactions(reaction_names=["dummy"])
    for r in react_obj:
        print("Found reaction: " + str(r.name))
        react_base.add(r)

    # IDAES will throw an exception when we try to do this if something is wrong
    thermo_config = base_obj.idaes_config
    reaction_config = react_base.idaes_config
    model = ConcreteModel()
    model.fs = FlowsheetBlock(default={"dynamic": False})
    model.fs.thermo_params = GenericParameterBlock(default=thermo_config)
    model.fs.rxn_params = GenericReactionParameterBlock(
        default={
            "property_package": model.fs.thermo_params,
            **reaction_config
        })

    model.fs.unit = EquilibriumReactor(
        default={
            "property_package": model.fs.thermo_params,
            "reaction_package": model.fs.rxn_params,
            "has_rate_reactions": False,
            "has_equilibrium_reactions": False,
            "has_heat_transfer": False,
            "has_heat_of_reaction": False,
            "has_pressure_change": False,
        })

    # If all goes well, this function returns true
    return is_thermo_reaction_pair_valid(base_obj.idaes_config,
                                         react_base.idaes_config)
    def sapon(self):
        m = ConcreteModel()
        m.fs = FlowsheetBlock(default={"dynamic": False})

        m.fs.properties = SaponificationParameterBlock()
        m.fs.reactions = SaponificationReactionParameterBlock(default={
                                "property_package": m.fs.properties})

        m.fs.unit = EquilibriumReactor(
                default={"property_package": m.fs.properties,
                         "reaction_package": m.fs.reactions,
                         "has_equilibrium_reactions": False,
                         "has_heat_transfer": True,
                         "has_heat_of_reaction": True,
                         "has_pressure_change": True})

        return m
Beispiel #12
0
def build_equilibrium_model(thermo_config, reaction_config):
    model = ConcreteModel()
    model.fs = FlowsheetBlock(default={"dynamic": False})
    model.fs.thermo_params = GenericParameterBlock(default=thermo_config)
    model.fs.rxn_params = GenericReactionParameterBlock(
        default={
            "property_package": model.fs.thermo_params,
            **reaction_config
        })

    model.fs.unit = EquilibriumReactor(
        default={
            "property_package": model.fs.thermo_params,
            "reaction_package": model.fs.rxn_params,
            "has_rate_reactions": False,
            "has_equilibrium_reactions": True,
            "has_heat_transfer": False,
            "has_heat_of_reaction": False,
            "has_pressure_change": False,
        })

    return model
    def equilibrium_config(self):
        # Create a pyomo model object
        model = ConcreteModel()
        model.fs = FlowsheetBlock(default={"dynamic": False})
        model.fs.thermo_params = GenericParameterBlock(default=thermo_config)

        model.fs.rxn_params = GenericReactionParameterBlock(
            default={
                "property_package": model.fs.thermo_params,
                **reaction_config
            })

        model.fs.unit = EquilibriumReactor(
            default={
                "property_package": model.fs.thermo_params,
                "reaction_package": model.fs.rxn_params,
                "has_rate_reactions": False,
                "has_equilibrium_reactions": True,
                "has_heat_transfer": False,
                "has_heat_of_reaction": False,
                "has_pressure_change": False,
            })

        model.fs.unit.inlet.pressure.fix(101325.0)
        model.fs.unit.inlet.temperature.fix(298.0)

        model.fs.unit.inlet.flow_mol_phase_comp[0, "Liq", "H_+"].fix(0.0)
        model.fs.unit.inlet.flow_mol_phase_comp[0, "Liq", "OH_-"].fix(0.0)
        model.fs.unit.inlet.flow_mol_phase_comp[0, "Liq", "H2CO3"].fix(0.0)
        model.fs.unit.inlet.flow_mol_phase_comp[0, "Liq", "HCO3_-"].fix(0.0)
        model.fs.unit.inlet.flow_mol_phase_comp[0, "Liq", "CO3_2-"].fix(0.0)
        model.fs.unit.inlet.flow_mol_phase_comp[0, "Vap",
                                                "CO2"].fix(0.0005 * 10)
        model.fs.unit.inlet.flow_mol_phase_comp[0, "Liq", "CO2"].fix(0.0)
        model.fs.unit.inlet.flow_mol_phase_comp[0, "Vap", "H2O"].fix(0.0)
        model.fs.unit.inlet.flow_mol_phase_comp[0, "Liq", "H2O"].fix(
            (1 - 0.0005) * 10)

        return model
Beispiel #14
0
def run_case2(xA, xB, xAB=1e-25, scaling=True, rxn_config=None, state="FpcTP"):
    print("==========================================================================")
    print(
        "Case 2 (log form): A and B are aqueous, AB is solid that forms from reaction"
    )
    print("xA = " + str(xA))
    print("xB = " + str(xB))
    print("xAB = " + str(xAB))
    print("scaling = " + str(scaling))
    print("including water = " + str(True))
    print()
    model = ConcreteModel()
    model.fs = FlowsheetBlock(default={"dynamic": False})

    if state == "FpcTP":
        case1_thermo_config["state_definition"] = FpcTP
    elif state == "FTPx":
        case1_thermo_config["state_definition"] = FTPx
        case1_thermo_config["state_bounds"]["flow_mol"] = (0, 50, 100)
    else:
        print("Error! Undefined state...")
        assert False

    model.fs.thermo_params = GenericParameterBlock(default=case1_thermo_config)

    model.fs.rxn_params = GenericReactionParameterBlock(
        default={"property_package": model.fs.thermo_params, **rxn_config}
    )

    model.fs.unit = EquilibriumReactor(
        default={
            "property_package": model.fs.thermo_params,
            "reaction_package": model.fs.rxn_params,
            "has_rate_reactions": False,
            "has_equilibrium_reactions": True,
            "has_heat_transfer": False,
            "has_heat_of_reaction": False,
            "has_pressure_change": False,
            "energy_balance_type": EnergyBalanceType.none,
        }
    )

    total_flow_mol = 10

    # Set flow_mol_phase_comp
    if case1_thermo_config["state_definition"] == FpcTP:

        model.fs.unit.inlet.flow_mol_phase_comp[0, "Liq", "A"].fix(xA * total_flow_mol)
        model.fs.unit.inlet.flow_mol_phase_comp[0, "Liq", "B"].fix(xB * total_flow_mol)
        model.fs.unit.inlet.flow_mol_phase_comp[0, "Sol", "AB"].fix(
            xAB * total_flow_mol
        )
        model.fs.unit.inlet.flow_mol_phase_comp[0, "Liq", "H2O"].fix(
            (1 - xA - xB - xAB) * total_flow_mol
        )

    if case1_thermo_config["state_definition"] == FTPx:
        model.fs.unit.inlet.mole_frac_comp[0, "A"].fix(xA)
        model.fs.unit.inlet.mole_frac_comp[0, "B"].fix(xB)
        model.fs.unit.inlet.mole_frac_comp[0, "AB"].fix(xAB)
        model.fs.unit.inlet.mole_frac_comp[0, "H2O"].fix((1 - xA - xB - xAB))
        model.fs.unit.inlet.flow_mol.fix(total_flow_mol)

    model.fs.unit.inlet.pressure.fix(101325.0)
    model.fs.unit.inlet.temperature.fix(298.0)
    model.fs.unit.outlet.temperature.fix(298.0)

    assert degrees_of_freedom(model) == 0

    assert_units_consistent(model)

    # Scaling
    _set_eps_vals(model.fs.rxn_params, rxn_config)
    _set_equ_rxn_scaling(model.fs.unit, rxn_config)
    if case1_thermo_config["state_definition"] == FpcTP:
        _set_mat_bal_scaling_FpcTP(model.fs.unit)
    if case1_thermo_config["state_definition"] == FTPx:
        _set_mat_bal_scaling_FTPx(model.fs.unit)

    iscale.calculate_scaling_factors(model.fs.unit)
    assert isinstance(model.fs.unit.control_volume.scaling_factor, Suffix)

    # Initialize model

    if case1_thermo_config["state_definition"] == FpcTP:
        state_args = {
            "flow_mol_phase_comp": {
                ("Liq", "H2O"): model.fs.unit.inlet.flow_mol_phase_comp[
                    0, "Liq", "H2O"
                ].value,
                ("Liq", "A"): model.fs.unit.inlet.flow_mol_phase_comp[
                    0, "Liq", "A"
                ].value,
                ("Liq", "B"): model.fs.unit.inlet.flow_mol_phase_comp[
                    0, "Liq", "B"
                ].value,
                ("Sol", "AB"): model.fs.unit.inlet.flow_mol_phase_comp[
                    0, "Sol", "AB"
                ].value,
            },
            "pressure": 101325,
            "temperature": 298,
            "flow_mol": 10,
        }

    if case1_thermo_config["state_definition"] == FTPx:
        state_args = {
            "mole_frac_comp": {
                "H2O": model.fs.unit.inlet.mole_frac_comp[0, "H2O"].value,
                "A": model.fs.unit.inlet.mole_frac_comp[0, "A"].value,
                "B": model.fs.unit.inlet.mole_frac_comp[0, "B"].value,
                "AB": model.fs.unit.inlet.mole_frac_comp[0, "AB"].value,
            },
            "pressure": 101325,
            "temperature": 298,
            "flow_mol": 10,
        }

    flags = fix_state_vars(model.fs.unit.control_volume.properties_out, state_args)
    revert_state_vars(model.fs.unit.control_volume.properties_out, flags)

    model.fs.unit.initialize(optarg=solver.options, outlvl=idaeslog.DEBUG)

    assert degrees_of_freedom(model) == 0

    results = solver.solve(model, tee=True)

    assert results.solver.termination_condition == TerminationCondition.optimal
    assert results.solver.status == SolverStatus.ok

    print("comp\toutlet.tot_molfrac")
    for i in model.fs.unit.control_volume.properties_out[0.0].mole_frac_comp:
        print(
            str(i)
            + "\t"
            + str(
                value(
                    model.fs.unit.control_volume.properties_out[0.0].mole_frac_comp[i]
                )
            )
        )
    print()

    # NOTE: Changed all to mole fraction
    for i in model.fs.unit.control_volume.properties_out[0.0].mole_frac_phase_comp:
        print(
            str(i)
            + "\t"
            + str(
                value(
                    model.fs.unit.control_volume.properties_out[
                        0.0
                    ].mole_frac_phase_comp[i]
                )
            )
        )

    A = value(
        model.fs.unit.control_volume.properties_out[0.0].mole_frac_phase_comp[
            "Liq", "A"
        ]
    )
    B = value(
        model.fs.unit.control_volume.properties_out[0.0].mole_frac_phase_comp[
            "Liq", "B"
        ]
    )
    Ksp = value(model.fs.unit.control_volume.reactions[0.0].k_eq["AB_Ksp"].expr)

    print()
    if Ksp * 1.01 >= A * B:
        print("Constraint is satisfied!")
    else:
        print("Constraint is VIOLATED!")
        print("\tRelative error: " + str(Ksp / A / B) + ">=1")
        assert False
    print("Ksp =\t" + str(Ksp))
    print("A*B =\t" + str(A * B))

    print("==========================================================================")

    return model
Beispiel #15
0
def run_case1(xA, xB, xAB=1e-25, scaling=True, rxn_config=None):
    print("==========================================================================")
    print("Case 1: A and B are aqueous, AB is solid that forms from reaction")
    print("xA = " + str(xA))
    print("xB = " + str(xB))
    print("xAB = " + str(xAB))
    print("scaling = " + str(scaling))
    print("including water = " + str(True))
    print()
    model = ConcreteModel()
    model.fs = FlowsheetBlock(default={"dynamic": False})
    model.fs.thermo_params = GenericParameterBlock(default=case1_thermo_config)

    model.fs.rxn_params = GenericReactionParameterBlock(
        default={"property_package": model.fs.thermo_params, **rxn_config}
    )

    model.fs.unit = EquilibriumReactor(
        default={
            "property_package": model.fs.thermo_params,
            "reaction_package": model.fs.rxn_params,
            "has_rate_reactions": False,
            "has_equilibrium_reactions": True,
            "has_heat_transfer": False,
            "has_heat_of_reaction": False,
            "has_pressure_change": False,
            "energy_balance_type": EnergyBalanceType.none,
        }
    )

    total_flow_mol = 10

    # Set flow_mol_phase_comp
    model.fs.unit.inlet.flow_mol_phase_comp[0, "Liq", "A"].fix(xA * total_flow_mol)
    model.fs.unit.inlet.flow_mol_phase_comp[0, "Liq", "B"].fix(xB * total_flow_mol)
    model.fs.unit.inlet.flow_mol_phase_comp[0, "Sol", "AB"].fix(xAB * total_flow_mol)
    model.fs.unit.inlet.flow_mol_phase_comp[0, "Liq", "H2O"].fix(
        (1 - xA - xB - xAB) * total_flow_mol
    )

    model.fs.unit.inlet.pressure.fix(101325.0)
    model.fs.unit.inlet.temperature.fix(298.0)
    model.fs.unit.outlet.temperature.fix(298.0)

    assert degrees_of_freedom(model) == 0

    assert_units_consistent(model)

    # Scaling
    _set_eps_vals(model.fs.rxn_params, rxn_config)
    # NOTE: We skip reaction scaling because we are NOT using the log_solubility_product form in this test
    # _set_equ_rxn_scaling(model.fs.unit, rxn_config)
    _set_mat_bal_scaling_FpcTP(model.fs.unit)

    iscale.calculate_scaling_factors(model.fs.unit)
    assert isinstance(model.fs.unit.control_volume.scaling_factor, Suffix)
    assert isinstance(
        model.fs.unit.control_volume.properties_out[0.0].scaling_factor, Suffix
    )
    assert isinstance(
        model.fs.unit.control_volume.properties_in[0.0].scaling_factor, Suffix
    )
    # End scaling if statement

    solver.options["max_iter"] = 200
    init_options = {**solver.options}
    init_options["bound_relax_factor"] = 1.0e-02
    model.fs.unit.initialize(optarg=init_options, outlvl=idaeslog.DEBUG)

    assert degrees_of_freedom(model) == 0

    solver.options["bound_relax_factor"] = 1.0e-02
    results = solver.solve(model, tee=True)
    del solver.options["bound_relax_factor"]

    assert results.solver.termination_condition == TerminationCondition.optimal
    assert results.solver.status == SolverStatus.ok

    print("comp\toutlet.tot_molfrac")
    for i in model.fs.unit.control_volume.properties_out[0.0].mole_frac_comp:
        print(
            str(i)
            + "\t"
            + str(
                value(
                    model.fs.unit.control_volume.properties_out[0.0].mole_frac_comp[i]
                )
            )
        )
    print()

    # NOTE: Changed all to mole fraction
    for i in model.fs.unit.control_volume.properties_out[0.0].mole_frac_phase_comp:
        print(
            str(i)
            + "\t"
            + str(
                value(
                    model.fs.unit.control_volume.properties_out[
                        0.0
                    ].mole_frac_phase_comp[i]
                )
            )
        )

    A = value(
        model.fs.unit.control_volume.properties_out[0.0].mole_frac_phase_comp[
            "Liq", "A"
        ]
    )
    B = value(
        model.fs.unit.control_volume.properties_out[0.0].mole_frac_phase_comp[
            "Liq", "B"
        ]
    )
    Ksp = value(model.fs.unit.control_volume.reactions[0.0].k_eq["AB_Ksp"].expr)

    print()
    if Ksp * 1.01 >= A * B:
        print("Constraint is satisfied!")
    else:
        print("Constraint is VIOLATED!")
        print("\tRelative error: " + str(Ksp / A / B) + ">=1")
        assert False
    print("Ksp =\t" + str(Ksp))
    print("A*B =\t" + str(A * B))

    print("==========================================================================")

    return model
def create_model(thermo_config=None, reaction_config=None):
    # Create a pyomo model object
    model = ConcreteModel()

    # Add an idaes flowsheet object to that model
    model.fs = FlowsheetBlock(default={"dynamic": False})

    # Add the generic properties object to that flowsheet
    #       and pass the custom configuation dictionary to it
    model.fs.thermo_params = GenericParameterBlock(default=thermo_config)

    # Add the generic reactions object to that flowsheet
    #   and pass the corresponding properties/params object to it
    #   along with the reaction_config dictionary
    model.fs.rxn_params = GenericReactionParameterBlock(
        default={
            "property_package": model.fs.thermo_params,
            **reaction_config
        })

    # Add the unit model for an Equilibrium Reactor to the flowsheet
    model.fs.unit = EquilibriumReactor(
        default={
            "property_package": model.fs.thermo_params,
            "reaction_package": model.fs.rxn_params,
            "has_rate_reactions": False,
            "has_equilibrium_reactions": True,
            "has_heat_transfer": False,
            "has_heat_of_reaction": False,
            "has_pressure_change": False
        })

    ## Use this function to ensure the units and unit conversions are all correct
    ##   This will throw an error if things are wrong
    #assert_units_consistent(model)

    print("Degrees of freedom = " + str(degrees_of_freedom(model)))

    # After building this model, there will be 9 degrees of freedom that MUST be
    #   fixed before calling the solver. Those degrees of freedom are based on
    #   the 'state_definition' defined in the 'thermo_config' dictionary and
    #   the number of components declared.
    #
    # For our problem:
    # ---------------
    #   'state_definition' == 'FTPx'
    #           Corresponds to:
    #           ---------------
    #                   model.fs.unit.inlet.flow_mol    -   mol/s
    #                   model.fs.unit.inlet.pressure    -   Pa
    #                   model.fs.unit.inlet.temperature -   K
    #                   model.fs.unit.inlet.mole_frac_comp[0, "name_of_component"]
    #                       (This one is repeated for each named component in 'thermo_config')
    #                       (The first value is the time stamp associated with the inlet,
    #                           which in our case is 0 because we are not a dynamic flowsheet)
    #
    #   'components' == ['H2O', 'H +', 'OH -', 'H2CO3', 'HCO3 -', 'CO3 2-']
    #           Corresponds to:
    #           ---------------
    #                   model.fs.unit.inlet.mole_frac_comp[0, "H2O"]    -   unitless
    #                   model.fs.unit.inlet.mole_frac_comp[0, "CO2"]    -   unitless
    #                       (Sum of all mole_frac_comp should equal 1.)
    model.fs.unit.inlet.flow_mol.fix(10)
    model.fs.unit.inlet.pressure.fix(101325.0)
    model.fs.unit.inlet.temperature.fix(300.0)

    # Set molefractions for ions... (this may change later)
    model.fs.unit.inlet.mole_frac_comp[0, "H +"].fix(0.)
    model.fs.unit.inlet.mole_frac_comp[0, "OH -"].fix(0.)
    model.fs.unit.inlet.mole_frac_comp[0, "HCO3 -"].fix(0.)
    model.fs.unit.inlet.mole_frac_comp[0, "CO3 2-"].fix(0.)

    # To come up with molefractions, we can start be pulling the water density from
    #   our thermo_config as follows (NOTE: it will have same units as before)
    #       [This approximation is valid for all aqueous chemistry]
    #
    #       Units:  kmol/m**3 == mol/L
    total_carbonate = 0.00206
    total_molar_density = calc_water_density(300)

    model.fs.unit.inlet.mole_frac_comp[0, "H2CO3"].fix(total_carbonate /
                                                       total_molar_density)

    # Perform a summation of all non-H2O molefractions to find the H2O molefraction
    sum = 0
    for i in model.fs.unit.inlet.mole_frac_comp:
        # NOTE: i will be a tuple with format (time, component)
        if i[1] != "H2O":
            sum += value(model.fs.unit.inlet.mole_frac_comp[i[0], i[1]])

    # Fix the inlet H2O molefraction based on remaining fraction
    model.fs.unit.inlet.mole_frac_comp[0, "H2O"].fix(1 - sum)

    #Setup scaling factors (optional)

    model.fs.thermo_params.default_scaling_factor[("mole_frac_comp",
                                                   "H +")] = 1e7
    model.fs.thermo_params.default_scaling_factor[("mole_frac_comp",
                                                   "OH -")] = 1e7
    model.fs.thermo_params.default_scaling_factor[("mole_frac_comp",
                                                   "HCO3 -")] = 1e7
    model.fs.thermo_params.default_scaling_factor[("mole_frac_comp",
                                                   "CO3 2-")] = 1e7
    model.fs.thermo_params.default_scaling_factor[("mole_frac_comp",
                                                   "H2CO3")] = 1e7
    model.fs.thermo_params.default_scaling_factor[("mole_frac_comp",
                                                   "H2O")] = 1

    # # TODO: ERROR! Cannot use this simple method to calculate scaling factors
    #           Model does not like it when I do this. I believe I have to give
    #           scaling factors for everything in the model for it to work properly.
    #iscale.calculate_scaling_factors(model.fs.unit)

    print("Degrees of freedom = " + str(degrees_of_freedom(model)))

    return model