Coverage for backend/idaes_service/solver/custom/hda_reaction.py: 74%

40 statements  

« prev     ^ index     » next       coverage.py v7.10.7, created at 2025-11-06 23:27 +0000

1################################################################################# 

2# The Institute for the Design of Advanced Energy Systems Integrated Platform 

3# Framework (IDAES IP) was produced under the DOE Institute for the 

4# Design of Advanced Energy Systems (IDAES), and is copyright (c) 2018-2022 

5# by the software owners: The Regents of the University of California, through 

6# Lawrence Berkeley National Laboratory, National Technology & Engineering 

7# Solutions of Sandia, LLC, Carnegie Mellon University, West Virginia University 

8# Research Corporation, et al. All rights reserved. 

9# 

10# Please see the files COPYRIGHT.md and LICENSE.md for full copyright and 

11# license information. 

12################################################################################# 

13""" 

14Property package for the hydrodealkylation of toluene to form benzene 

15""" 

16 

17# Import Python libraries 

18import logging 

19 

20# Import Pyomo libraries 

21from pyomo.environ import Constraint, exp, Set, Var, Param, units as pyunits 

22 

23# Import IDAES cores 

24from idaes.core import ( 

25 declare_process_block_class, 

26 MaterialFlowBasis, 

27 ReactionParameterBlock, 

28 ReactionBlockDataBase, 

29 ReactionBlockBase, 

30) 

31from idaes.core.util.constants import Constants as const 

32from idaes.core.util.misc import add_object_reference 

33 

34# Set up logger 

35_log = logging.getLogger(__name__) 

36 

37 

38@declare_process_block_class("HDAReactionParameterBlock") 

39class HDAReactionParameterData(ReactionParameterBlock): 

40 """ 

41 Property Parameter Block Class 

42 Contains parameters and indexing sets associated with properties for 

43 superheated steam. 

44 """ 

45 

46 def build(self): 

47 """ 

48 Callable method for Block construction. 

49 """ 

50 super(HDAReactionParameterData, self).build() 

51 

52 self._reaction_block_class = HDAReactionBlock 

53 

54 # List of valid phases in property package 

55 self.phase_list = Set(initialize=["Vap"]) 

56 

57 # Component list - a list of component identifiers 

58 self.component_list = Set( 

59 initialize=["benzene", "toluene", "hydrogen", "methane"] 

60 ) 

61 

62 # Reaction Index 

63 self.rate_reaction_idx = Set(initialize=["R1"]) 

64 

65 # Reaction Stoichiometry 

66 self.rate_reaction_stoichiometry = { 

67 ("R1", "Vap", "benzene"): 1, 

68 ("R1", "Vap", "toluene"): -1, 

69 ("R1", "Vap", "hydrogen"): -1, 

70 ("R1", "Vap", "methane"): 1, 

71 ("R1", "Liq", "benzene"): 0, 

72 ("R1", "Liq", "toluene"): 0, 

73 ("R1", "Liq", "hydrogen"): 0, 

74 ("R1", "Liq", "methane"): 0, 

75 } 

76 

77 # Arrhenius Constant 

78 self.arrhenius = Var( 

79 initialize=6.3e10, 

80 units=pyunits.mol * pyunits.m**-3 * pyunits.s**-1 * pyunits.Pa**-1, 

81 doc="Arrhenius pre-exponential factor", 

82 ) 

83 self.arrhenius.fix() 

84 

85 # Activation Energy 

86 self.energy_activation = Var( 

87 initialize=217.6e3, units=pyunits.J / pyunits.mol, doc="Activation energy" 

88 ) 

89 self.energy_activation.fix() 

90 

91 # Heat of Reaction 

92 dh_rxn_dict = {"R1": -1.08e5} 

93 self.dh_rxn = Param( 

94 self.rate_reaction_idx, 

95 initialize=dh_rxn_dict, 

96 units=pyunits.J / pyunits.mol, 

97 doc="Heat of reaction", 

98 ) 

99 

100 @classmethod 

101 def define_metadata(cls, obj): 

102 obj.add_properties( 

103 { 

104 "k_rxn": {"method": None, "units": "m^3/mol.s"}, 

105 "reaction_rate": {"method": None, "units": "mol/m^3.s"}, 

106 } 

107 ) 

108 obj.add_default_units( 

109 { 

110 "time": pyunits.s, 

111 "length": pyunits.m, 

112 "mass": pyunits.kg, 

113 "amount": pyunits.mol, 

114 "temperature": pyunits.K, 

115 } 

116 ) 

117 

118 

119class ReactionBlock(ReactionBlockBase): 

120 """ 

121 This Class contains methods which should be applied to Reaction Blocks as a 

122 whole, rather than individual elements of indexed Reaction Blocks. 

123 """ 

124 

125 def initialize(blk, outlvl=0, **kwargs): 

126 """ 

127 Initialization routine for reaction package. 

128 Keyword Arguments: 

129 outlvl : sets output level of initialization routine 

130 * 0 = no output (default) 

131 * 1 = report after each step 

132 Returns: 

133 None 

134 """ 

135 if outlvl > 0: 

136 _log.info("{} Initialization Complete.".format(blk.name)) 

137 

138 

139@declare_process_block_class("HDAReactionBlock", block_class=ReactionBlock) 

140class HDAReactionBlockData(ReactionBlockDataBase): 

141 """ 

142 An example reaction package for saponification of ethyl acetate 

143 """ 

144 

145 def build(self): 

146 """ 

147 Callable method for Block construction 

148 """ 

149 super(HDAReactionBlockData, self).build() 

150 

151 # Heat of reaction - no _ref as this is the actual property 

152 add_object_reference(self, "dh_rxn", self.config.parameters.dh_rxn) 

153 

154 self.k_rxn = Var( 

155 initialize=0.2, 

156 units=pyunits.mol * pyunits.m**-3 * pyunits.s**-1 * pyunits.Pa**-1, 

157 ) 

158 

159 self.reaction_rate = Var( 

160 self.params.rate_reaction_idx, 

161 initialize=1, 

162 units=pyunits.mol / pyunits.m**3 / pyunits.s, 

163 ) 

164 

165 self.arrhenus_equation = Constraint( 

166 expr=self.k_rxn 

167 == self.params.arrhenius 

168 * exp( 

169 -self.params.energy_activation 

170 / (const.gas_constant * self.state_ref.temperature) 

171 ) 

172 ) 

173 

174 self.rate_expression = Constraint( 

175 expr=self.reaction_rate["R1"] 

176 == self.k_rxn 

177 * self.state_ref.pressure 

178 * self.state_ref.mole_frac_phase_comp["Vap", "toluene"] 

179 ) 

180 

181 def get_reaction_rate_basis(b): 

182 return MaterialFlowBasis.molar