Beispiel #1
0
def test_power_law_equil_no_order():
    m = ConcreteModel()

    # # Add a test thermo package for validation
    m.pparams = PhysicalParameterTestBlock()

    # Add a solid phase for testing
    m.pparams.sol = SolidPhase()

    m.thermo = m.pparams.build_state_block([1])

    # Create a dummy reaction parameter block
    m.rparams = GenericReactionParameterBlock(
        default={
            "property_package": m.pparams,
            "base_units": {
                "time": pyunits.s,
                "mass": pyunits.kg,
                "amount": pyunits.mol,
                "length": pyunits.m,
                "temperature": pyunits.K
            },
            "equilibrium_reactions": {
                "r1": {
                    "stoichiometry": {
                        ("p1", "c1"): -1,
                        ("p1", "c2"): 2,
                        ("sol", "c1"): -3,
                        ("sol", "c2"): 4
                    },
                    "equilibrium_form": power_law_equil,
                    "concentration_form": ConcentrationForm.moleFraction
                }
            }
        })

    # Create a dummy state block
    m.rxn = Block([1])
    add_object_reference(m.rxn[1], "phase_component_set",
                         m.pparams._phase_component_set)
    add_object_reference(m.rxn[1], "params", m.rparams)
    add_object_reference(m.rxn[1], "state_ref", m.thermo[1])

    m.rxn[1].k_eq = Var(["r1"], initialize=1)

    power_law_equil.build_parameters(
        m.rparams.reaction_r1, m.rparams.config.equilibrium_reactions["r1"])

    # Check parameter construction
    assert isinstance(m.rparams.reaction_r1.reaction_order, Var)
    assert len(m.rparams.reaction_r1.reaction_order) == 6

    assert m.rparams.reaction_r1.reaction_order["p1", "c1"].value == -1
    assert m.rparams.reaction_r1.reaction_order["p1", "c2"].value == 2
    assert m.rparams.reaction_r1.reaction_order["p2", "c1"].value == 0
    assert m.rparams.reaction_r1.reaction_order["p2", "c2"].value == 0
    # Solids should have zero order, as they are excluded
    assert m.rparams.reaction_r1.reaction_order["sol", "c1"].value == 0
    assert m.rparams.reaction_r1.reaction_order["sol", "c2"].value == 0

    # Check reaction form
    rform = power_law_equil.return_expression(m.rxn[1], m.rparams.reaction_r1,
                                              "r1", 300)

    assert str(rform) == str(m.rxn[1].k_eq["r1"] == (
        m.thermo[1].mole_frac_phase_comp[
            "p1", "c1"]**m.rparams.reaction_r1.reaction_order["p1", "c1"] *
        m.thermo[1].mole_frac_phase_comp[
            "p1", "c2"]**m.rparams.reaction_r1.reaction_order["p1", "c2"]))
Beispiel #2
0
    def build(self):
        '''
        Callable method for Block construction.
        '''
        super(ReactionParameterBlock, self).build()

        self._reaction_block_class = ReactionBlock

        # Create Phase objects
        self.Vap = VaporPhase()
        self.Sol = SolidPhase()

        # Create Component objects
        self.CH4 = Component()
        self.CO2 = Component()
        self.H2O = Component()
        self.Fe2O3 = Component()
        self.Fe3O4 = Component()
        self.Al2O3 = Component()

        # Component list subsets
        self.gas_component_list = Set(initialize=['CO2', 'H2O', 'CH4'])
        self.sol_component_list = Set(initialize=['Fe2O3', 'Fe3O4', 'Al2O3'])

        # Reaction Index
        self.rate_reaction_idx = Set(initialize=["R1"])

        # Gas Constant
        self.gas_const = Param(within=PositiveReals,
                               mutable=False,
                               default=8.314459848e-3,
                               doc='Gas Constant [kJ/mol.K]')

        # Smoothing factor
        self.eps = Param(mutable=True, default=1e-8, doc='Smoothing Factor')
        # Reaction rate scale factor
        self._scale_factor_rxn = Param(mutable=True,
                                       default=1,
                                       doc='Scale Factor for reaction eqn.'
                                       'Used to help initialization routine')

        # Reaction Stoichiometry
        self.rate_reaction_stoichiometry = {
            ("R1", "Vap", "CH4"): -1,
            ("R1", "Vap", "CO2"): 1,
            ("R1", "Vap", "H2O"): 2,
            ("R1", "Sol", "Fe2O3"): -12,
            ("R1", "Sol", "Fe3O4"): 8,
            ("R1", "Sol", "Al2O3"): 0
        }

        # Reaction stoichiometric coefficient
        self.rxn_stoich_coeff = Param(self.rate_reaction_idx,
                                      default=12,
                                      mutable=True,
                                      doc='Reaction stoichiometric'
                                      'coefficient [-]')

        # Standard Heat of Reaction - kJ/mol_rxn
        dh_rxn_dict = {"R1": 136.5843}
        self.dh_rxn = Param(self.rate_reaction_idx,
                            initialize=dh_rxn_dict,
                            doc="Heat of reaction [kJ/mol]")

        # -------------------------------------------------------------------------
        """ Reaction properties that can be estimated"""

        # Particle grain radius within OC particle
        self.grain_radius = Var(domain=Reals,
                                initialize=2.6e-7,
                                doc='Representative particle grain'
                                'radius within OC particle [m]')
        self.grain_radius.fix()

        # Molar density OC particle
        self.dens_mol_sol = Var(domain=Reals,
                                initialize=32811,
                                doc='Molar density of OC particle [mol/m^3]')
        self.dens_mol_sol.fix()

        # Available volume for reaction - from EPAT report (1-ep)'
        self.a_vol = Var(domain=Reals,
                         initialize=0.28,
                         doc='Available reaction vol. per vol. of OC')
        self.a_vol.fix()

        # Activation Energy
        self.energy_activation = Var(self.rate_reaction_idx,
                                     domain=Reals,
                                     initialize=4.9e1,
                                     doc='Activation energy [kJ/mol]')
        self.energy_activation.fix()

        # Reaction order
        self.rxn_order = Var(self.rate_reaction_idx,
                             domain=Reals,
                             initialize=1.3,
                             doc='Reaction order in gas species [-]')
        self.rxn_order.fix()

        # Pre-exponential factor
        self.k0_rxn = Var(self.rate_reaction_idx,
                          domain=Reals,
                          initialize=8e-4,
                          doc='Pre-exponential factor'
                          '[mol^(1-N_reaction)m^(3*N_reaction -2)/s]')
        self.k0_rxn.fix()
def test_solubility_product_with_order():
    m = ConcreteModel()

    # # Add a test thermo package for validation
    m.pparams = PhysicalParameterTestBlock()

    # Add a solid phase for testing
    m.pparams.sol = SolidPhase()

    m.thermo = m.pparams.build_state_block([1])

    # Create a dummy reaction parameter block
    m.rparams = GenericReactionParameterBlock(
        default={
            "property_package": m.pparams,
            "base_units": {
                "time": pyunits.s,
                "mass": pyunits.kg,
                "amount": pyunits.mol,
                "length": pyunits.m,
                "temperature": pyunits.K
            },
            "equilibrium_reactions": {
                "r1": {
                    "stoichiometry": {
                        ("p1", "c1"): -1,
                        ("p1", "c2"): 2,
                        ("sol", "c1"): -3,
                        ("sol", "c2"): 4
                    },
                    "equilibrium_form": solubility_product,
                    "concentration_form": ConcentrationForm.moleFraction,
                    "parameter_data": {
                        "reaction_order": {
                            ("p1", "c1"): 1,
                            ("p1", "c2"): 2,
                            ("p2", "c1"): 3,
                            ("p2", "c2"): 4,
                            ("sol", "c1"): 5,
                            ("sol", "c2"): 6
                        }
                    }
                }
            }
        })

    # Create a dummy state block
    m.rxn = Block([1])
    add_object_reference(m.rxn[1], "phase_component_set",
                         m.pparams._phase_component_set)
    add_object_reference(m.rxn[1], "params", m.rparams)
    add_object_reference(m.rxn[1], "state_ref", m.thermo[1])

    m.rxn[1].k_eq = Var(["r1"], initialize=1)

    # Check parameter construction
    assert isinstance(m.rparams.reaction_r1.eps, Param)
    assert value(m.rparams.reaction_r1.eps) == 1e-4
    assert isinstance(m.rparams.reaction_r1.reaction_order, Var)
    assert len(m.rparams.reaction_r1.reaction_order) == 6
    assert m.rparams.reaction_r1.reaction_order["p1", "c1"].value == 1
    assert m.rparams.reaction_r1.reaction_order["p1", "c2"].value == 2
    assert m.rparams.reaction_r1.reaction_order["p2", "c1"].value == 3
    assert m.rparams.reaction_r1.reaction_order["p2", "c2"].value == 4
    assert m.rparams.reaction_r1.reaction_order["sol", "c1"].value == 5
    assert m.rparams.reaction_r1.reaction_order["sol", "c2"].value == 6

    # Check reaction form
    rform = solubility_product.return_expression(m.rxn[1],
                                                 m.rparams.reaction_r1, "r1",
                                                 300)

    s = (m.thermo[1].flow_mol_phase_comp["sol", "c1"] +
         m.thermo[1].flow_mol_phase_comp["sol", "c2"])
    Q = (m.rxn[1].k_eq["r1"] -
         (m.thermo[1].mole_frac_phase_comp["p1", "c1"]**
          m.rparams.reaction_r1.reaction_order["p1", "c1"] *
          m.thermo[1].mole_frac_phase_comp["p1", "c2"]**
          m.rparams.reaction_r1.reaction_order["p1", "c2"] *
          m.thermo[1].mole_frac_phase_comp["p2", "c1"]**
          m.rparams.reaction_r1.reaction_order["p2", "c1"] *
          m.thermo[1].mole_frac_phase_comp["p2", "c2"]**
          m.rparams.reaction_r1.reaction_order["p2", "c2"] *
          m.thermo[1].mole_frac_phase_comp["sol", "c1"]**
          m.rparams.reaction_r1.reaction_order["sol", "c1"] *
          m.thermo[1].mole_frac_phase_comp["sol", "c2"]**
          m.rparams.reaction_r1.reaction_order["sol", "c2"]))

    assert str(rform) == str(
        s - smooth_max(0, s - Q, m.rparams.reaction_r1.eps) == 0)
    def build(self):
        '''
        Callable method for Block construction.
        '''
        super(PhysicalParameterData, self).build()

        self._state_block_class = SolidPhaseThermoStateBlock

        # Create Phase object
        self.Sol = SolidPhase()

        # Create Component objects
        self.Fe2O3 = Component()
        self.Fe3O4 = Component()
        self.Al2O3 = Component()

        # -------------------------------------------------------------------------
        """ Pure solid component properties"""

        # Mol. weights of solid components - units = kg/mol. ref: NIST webbook
        mw_comp_dict = {'Fe2O3': 0.15969, 'Fe3O4': 0.231533, 'Al2O3': 0.10196}
        self.mw_comp = Param(
            self.component_list,
            mutable=False,
            initialize=mw_comp_dict,
            doc="Molecular weights of solid components [kg/mol]")

        # Skeletal density of solid components - units = kg/m3. ref: NIST
        dens_mass_comp_skeletal_dict = {
            'Fe2O3': 5250,
            'Fe3O4': 5000,
            'Al2O3': 3987
        }
        self.dens_mass_comp_skeletal = Param(
            self.component_list,
            mutable=False,
            initialize=dens_mass_comp_skeletal_dict,
            doc='Skeletal density of solid components'
            '[kg/m3]')

        # Ideal gas spec. heat capacity parameters(Shomate) of
        # components - ref: NIST webbook. Shomate equations from NIST.
        # Parameters A-E are used for cp calcs while A-H are used for enthalpy
        # calc.
        # 1e3*cp_comp = A + B*T + C*T^2 + D*T^3 + E/(T^2)
        # where T = Temperature (K)/1000, and cp_comp = (kJ/mol.K)
        # H_comp = H - H(298.15) = A*T + B*T^2/2 + C*T^3/3 +
        # D*T^4/4 - E/T + F - H where T = Temp (K)/1000 and H_comp = (kJ/mol)
        cp_param_dict = {
            ('Al2O3', 1): 102.4290,
            ('Al2O3', 2): 38.74980,
            ('Al2O3', 3): -15.91090,
            ('Al2O3', 4): 2.628181,
            ('Al2O3', 5): -3.007551,
            ('Al2O3', 6): -1717.930,
            ('Al2O3', 7): 146.9970,
            ('Al2O3', 8): -1675.690,
            ('Fe3O4', 1): 200.8320000,
            ('Fe3O4', 2): 1.586435e-7,
            ('Fe3O4', 3): -6.661682e-8,
            ('Fe3O4', 4): 9.452452e-9,
            ('Fe3O4', 5): 3.18602e-8,
            ('Fe3O4', 6): -1174.1350000,
            ('Fe3O4', 7): 388.0790000,
            ('Fe3O4', 8): -1120.8940000,
            ('Fe2O3', 1): 110.9362000,
            ('Fe2O3', 2): 32.0471400,
            ('Fe2O3', 3): -9.1923330,
            ('Fe2O3', 4): 0.9015060,
            ('Fe2O3', 5): 5.4336770,
            ('Fe2O3', 6): -843.1471000,
            ('Fe2O3', 7): 228.3548000,
            ('Fe2O3', 8): -825.5032000
        }
        self.cp_param = Param(self.component_list,
                              range(1, 10),
                              mutable=False,
                              initialize=cp_param_dict,
                              doc="Shomate equation heat capacity parameters")

        # Std. heat of formation of comp. - units = kJ/(mol comp) - ref: NIST
        enth_mol_form_comp_dict = {
            'Fe2O3': -825.5032,
            'Fe3O4': -1120.894,
            'Al2O3': -1675.690
        }
        self.enth_mol_form_comp = Param(
            self.component_list,
            mutable=False,
            initialize=enth_mol_form_comp_dict,
            doc="Component molar heats of formation [kJ/mol]")

        # -------------------------------------------------------------------------
        """ Mixed solid properties"""
        # These are setup as fixed vars to allow for parameter estimation

        # Particle size
        self.particle_dia = Var(domain=Reals,
                                initialize=1.5e-3,
                                doc='Diameter of solid particles [m]')
        self.particle_dia.fix()

        # TODO -provide reference
        # Minimum fluidization velocity - EPAT value used for Davidson model
        self.velocity_mf = Var(domain=Reals,
                               initialize=0.039624,
                               doc='Velocity at minimum fluidization [m/s]')
        self.velocity_mf.fix()

        # Minimum fluidization voidage - educated guess as rough
        # estimate from ergun equation results (0.4) are suspicious
        self.voidage_mf = Var(domain=Reals,
                              initialize=0.45,
                              doc='Voidage at minimum fluidization [-]')
        self.voidage_mf.fix()

        # Particle thermal conductivity
        self.therm_cond_sol = Var(domain=Reals,
                                  initialize=12.3e-3,
                                  doc='Thermal conductivity of solid'
                                  'particles [kJ/m.K.s]')
        self.therm_cond_sol.fix()
    def build(self):
        '''
        Callable method for Block construction.
        '''
        super(PhysicalParameterData, self).build()

        self._state_block_class = SolidPhaseStateBlock

        # Create Phase object
        self.Sol = SolidPhase()

        # Create Component objects
        self.Fe2O3 = Component()
        self.Fe3O4 = Component()
        self.Al2O3 = Component()

        # -------------------------------------------------------------------------
        """ Pure solid component properties"""

        # Mol. weights of solid components - units = kg/mol. ref: NIST webbook
        mw_comp_dict = {'Fe2O3': 0.15969, 'Fe3O4': 0.231533, 'Al2O3': 0.10196}
        # Molecular weight should be defined in default units
        # (default mass units)/(default amount units)
        # per the define_meta.add_default_units method below
        self.mw_comp = Param(
            self.component_list,
            mutable=False,
            initialize=mw_comp_dict,
            doc="Molecular weights of solid components [kg/mol]",
            units=pyunits.kg / pyunits.mol)

        # Skeletal density of solid components - units = kg/m3. ref: NIST
        dens_mass_comp_skeletal_dict = {
            'Fe2O3': 5250,
            'Fe3O4': 5000,
            'Al2O3': 3987
        }
        self.dens_mass_comp_skeletal = Param(
            self.component_list,
            mutable=False,
            initialize=dens_mass_comp_skeletal_dict,
            doc='Skeletal density of solid components [kg/m3]',
            units=pyunits.kg / pyunits.m**3)

        # Ideal gas spec. heat capacity parameters(Shomate) of
        # components - ref: NIST webbook. Shomate equations from NIST.
        # Parameters A-E are used for cp calcs while A-H are used for enthalpy
        # calc.
        # cp_comp = A + B*T + C*T^2 + D*T^3 + E/(T^2)
        # where T = Temperature (K)/1000, and cp_comp = (J/mol.K)
        # H_comp = H - H(298.15) = A*T + B*T^2/2 + C*T^3/3 +
        # D*T^4/4 - E/T + F - H where T = Temp (K)/1000 and H_comp = (kJ/mol)
        cp_param_dict = {
            ('Al2O3', 1): 102.4290,
            ('Al2O3', 2): 38.74980,
            ('Al2O3', 3): -15.91090,
            ('Al2O3', 4): 2.628181,
            ('Al2O3', 5): -3.007551,
            ('Al2O3', 6): -1717.930,
            ('Al2O3', 7): 146.9970,
            ('Al2O3', 8): -1675.690,
            ('Fe3O4', 1): 200.8320000,
            ('Fe3O4', 2): 1.586435e-7,
            ('Fe3O4', 3): -6.661682e-8,
            ('Fe3O4', 4): 9.452452e-9,
            ('Fe3O4', 5): 3.18602e-8,
            ('Fe3O4', 6): -1174.1350000,
            ('Fe3O4', 7): 388.0790000,
            ('Fe3O4', 8): -1120.8940000,
            ('Fe2O3', 1): 110.9362000,
            ('Fe2O3', 2): 32.0471400,
            ('Fe2O3', 3): -9.1923330,
            ('Fe2O3', 4): 0.9015060,
            ('Fe2O3', 5): 5.4336770,
            ('Fe2O3', 6): -843.1471000,
            ('Fe2O3', 7): 228.3548000,
            ('Fe2O3', 8): -825.5032000
        }
        self.cp_param_1 = Param(
            self.component_list,
            mutable=False,
            initialize={k: v
                        for (k, j), v in cp_param_dict.items() if j == 1},
            doc="Shomate equation heat capacity coeff 1",
            units=pyunits.J / pyunits.mol / pyunits.K)
        self.cp_param_2 = Param(
            self.component_list,
            mutable=False,
            initialize={k: v
                        for (k, j), v in cp_param_dict.items() if j == 2},
            doc="Shomate equation heat capacity coeff 2",
            units=pyunits.J / pyunits.mol / pyunits.K / pyunits.kK)
        self.cp_param_3 = Param(
            self.component_list,
            mutable=False,
            initialize={k: v
                        for (k, j), v in cp_param_dict.items() if j == 3},
            doc="Shomate equation heat capacity coeff 3",
            units=pyunits.J / pyunits.mol / pyunits.K / pyunits.kK**2)
        self.cp_param_4 = Param(
            self.component_list,
            mutable=False,
            initialize={k: v
                        for (k, j), v in cp_param_dict.items() if j == 4},
            doc="Shomate equation heat capacity coeff 4",
            units=pyunits.J / pyunits.mol / pyunits.K / pyunits.kK**3)
        self.cp_param_5 = Param(
            self.component_list,
            mutable=False,
            initialize={k: v
                        for (k, j), v in cp_param_dict.items() if j == 5},
            doc="Shomate equation heat capacity coeff 5",
            units=pyunits.J / pyunits.mol / pyunits.K * pyunits.kK**2)
        self.cp_param_6 = Param(
            self.component_list,
            mutable=False,
            initialize={k: v
                        for (k, j), v in cp_param_dict.items() if j == 6},
            doc="Shomate equation heat capacity coeff 6",
            units=pyunits.kJ / pyunits.mol)
        self.cp_param_7 = Param(
            self.component_list,
            mutable=False,
            initialize={k: v
                        for (k, j), v in cp_param_dict.items() if j == 7},
            doc="Shomate equation heat capacity coeff 7",
            units=pyunits.J / pyunits.mol / pyunits.K)
        self.cp_param_8 = Param(
            self.component_list,
            mutable=False,
            initialize={k: v
                        for (k, j), v in cp_param_dict.items() if j == 8},
            doc="Shomate equation heat capacity coeff 8",
            units=pyunits.kJ / pyunits.mol)

        # Std. heat of formation of comp. - units = J/(mol comp) - ref: NIST
        enth_mol_form_comp_dict = {
            'Fe2O3': -825.5032E3,
            'Fe3O4': -1120.894E3,
            'Al2O3': -1675.690E3
        }
        self.enth_mol_form_comp = Param(
            self.component_list,
            mutable=False,
            initialize=enth_mol_form_comp_dict,
            doc="Component molar heats of formation [J/mol]",
            units=pyunits.J / pyunits.mol)

        # Set default scaling for mass fractions
        for comp in self.component_list:
            self.set_default_scaling("mass_frac_comp", 1e2, index=comp)

    # -------------------------------------------------------------------------
        """ Mixed solid properties"""
        # These are setup as fixed vars to allow for parameter estimation

        # Particle size
        self.particle_dia = Var(domain=Reals,
                                initialize=1.5e-3,
                                doc='Diameter of solid particles [m]',
                                units=pyunits.m)
        self.particle_dia.fix()

        # TODO -provide reference
        # Minimum fluidization velocity - EPAT value used for Davidson model
        self.velocity_mf = Var(domain=Reals,
                               initialize=0.039624,
                               doc='Velocity at minimum fluidization [m/s]',
                               units=pyunits.m / pyunits.s)
        self.velocity_mf.fix()

        # Minimum fluidization voidage - educated guess as rough
        # estimate from ergun equation results (0.4) are suspicious
        self.voidage_mf = Var(domain=Reals,
                              initialize=0.45,
                              doc='Voidage at minimum fluidization [-]',
                              units=pyunits.m**3 / pyunits.m**3)
        self.voidage_mf.fix()

        # Voidage of the bed
        self.voidage = Var(domain=Reals,
                           initialize=0.35,
                           doc='Voidage [-]',
                           units=pyunits.m**3 / pyunits.m**3)
        self.voidage.fix()

        # Particle thermal conductivity
        self.therm_cond_sol = Var(
            domain=Reals,
            initialize=12.3e-0,
            doc='Thermal conductivity of solid particles [J/m.K.s]',
            units=pyunits.J / pyunits.m / pyunits.K / pyunits.s)
        self.therm_cond_sol.fix()