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"]))
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()