Coverage for backend/ahuora-builder/src/ahuora_builder/methods/build_custom_package.py: 84%

34 statements  

« prev     ^ index     » next       coverage.py v7.10.7, created at 2026-03-26 20:57 +0000

1from idaes.core.base.property_base import PhysicalParameterBlock 

2from ahuora_property_packages.modular.modular_extended import GenericExtendedParameterBlock 

3from ahuora_builder_types.flowsheet_schema import PropertyPackageType, CustomCompoundPropertiesSchema 

4from idaes.core import LiquidPhase, VaporPhase, Component 

5from pyomo.environ import units as pyunits 

6from idaes.models.properties.modular_properties.state_definitions import FTPx 

7from idaes.models.properties.modular_properties.eos.ceos import Cubic, CubicType 

8from idaes.models.properties.modular_properties.phase_equil import ( 

9 CubicComplementarityVLE, 

10) 

11from idaes.models.properties.modular_properties.phase_equil.bubble_dew import ( 

12 LogBubbleDew, 

13) 

14from idaes.models.properties.modular_properties.phase_equil.forms import log_fugacity 

15from idaes.models.properties.modular_properties.pure import RPP4 

16 

17 

18 

19 

20 

21 

22def build_custom_package(property_package_schema: PropertyPackageType) -> PhysicalParameterBlock: 

23 """ 

24 Build a custom property package from a schema 

25 """ 

26 if property_package_schema.custom_compound_properties is None: 26 ↛ 27line 26 didn't jump to line 27 because the condition on line 26 was never true

27 raise ValueError("Custom compound properties must be provided for custom property package") 

28 if property_package_schema.custom_package_properties is None: 28 ↛ 29line 28 didn't jump to line 29 because the condition on line 28 was never true

29 raise ValueError("Custom package properties must be provided for custom property package") 

30 if property_package_schema.custom_kappa_values is None: 30 ↛ 31line 30 didn't jump to line 31 because the condition on line 30 was never true

31 raise ValueError("Custom kappa values must be provided for custom property package") 

32 

33 

34 pp = property_package_schema.custom_package_properties 

35 # assert nothing in pp is None 

36 for key, value in pp.model_dump().items(): 

37 if value is None: 37 ↛ 38line 37 didn't jump to line 38 because the condition on line 37 was never true

38 raise ValueError(f"Custom package property {key} must be provided for custom property package") 

39 

40 return GenericExtendedParameterBlock( 

41 **{ 

42 "components": build_components(property_package_schema.compounds,property_package_schema.custom_compound_properties), 

43 # Specifying phases 

44 "phases": { 

45 "Liq": { 

46 "type": LiquidPhase, 

47 "equation_of_state": Cubic, 

48 "equation_of_state_options": {"type": CubicType.PR}, 

49 }, 

50 "Vap": { 

51 "type": VaporPhase, 

52 "equation_of_state": Cubic, 

53 "equation_of_state_options": {"type": CubicType.PR}, 

54 }, 

55 }, 

56 # Set base units of measurement 

57 "base_units": { 

58 "time": pyunits.s, 

59 "length": pyunits.m, 

60 "mass": pyunits.kg, 

61 "amount": pyunits.mol, 

62 "temperature": pyunits.K, 

63 }, 

64 # Specifying state definition 

65 "state_definition": FTPx, 

66 "state_bounds": { 

67 "flow_mol": (pp.flow_mol_min, pp.flow_mol_nominal, pp.flow_mol_max, pyunits.mol / pyunits.s), 

68 "temperature": (pp.temperature_min, pp.temperature_nominal, pp.temperature_max, pyunits.K), 

69 "pressure": (pp.pressure_min, pp.pressure_nominal, pp.pressure_max, pyunits.Pa), 

70 }, 

71 "pressure_ref": (pp.pressure_ref, pyunits.Pa), 

72 "temperature_ref": (pp.temperature_ref, pyunits.K), 

73 # Defining phase equilibria 

74 "phases_in_equilibrium": [("Vap", "Liq")], 

75 "phase_equilibrium_state": {("Vap", "Liq"): CubicComplementarityVLE}, 

76 "bubble_dew_method": LogBubbleDew, 

77 "parameter_data": { 

78 "PR_kappa": build_kappas(property_package_schema.custom_kappa_values) 

79 }, 

80 } 

81 ) 

82 

83 

84 

85def build_components(compounds: list[str], custom_compound_properties: list[CustomCompoundPropertiesSchema]) -> dict[str, dict]: 

86 compound_configuration: dict[str,dict] = {} 

87 for compound, properties in zip(compounds, custom_compound_properties): 

88 compound_configuration[compound] = { 

89 "type": Component, 

90 "enth_mol_ig_comp": RPP4, 

91 "entr_mol_ig_comp": RPP4, 

92 "pressure_sat_comp": RPP4, 

93 "phase_equilibrium_form": {("Vap", "Liq"): log_fugacity}, 

94 "parameter_data": { 

95 "mw": (properties.mw, pyunits.kg / pyunits.mol), # [1] 

96 "pressure_crit": (properties.pressure_crit, pyunits.Pa), # [1] 

97 "temperature_crit": (properties.temperature_crit, pyunits.K), # [1] 

98 "omega": properties.omega, # [1] 

99 "cp_mol_ig_comp_coeff": { 

100 "A": (properties.cp_mol_ig_comp_coeff_A, pyunits.J / pyunits.mol / pyunits.K), # [1] 

101 "B": (properties.cp_mol_ig_comp_coeff_B, pyunits.J / pyunits.mol / pyunits.K**2), 

102 "C": (properties.cp_mol_ig_comp_coeff_C, pyunits.J / pyunits.mol / pyunits.K**3), 

103 "D": (properties.cp_mol_ig_comp_coeff_D, pyunits.J / pyunits.mol / pyunits.K**4), 

104 }, 

105 "enth_mol_form_vap_comp_ref": (properties.enth_mol_form_vap_comp_ref, pyunits.J / pyunits.mol), # [3] 

106 "entr_mol_form_vap_comp_ref": (properties.entr_mol_form_vap_comp_ref, pyunits.J / pyunits.mol / pyunits.K), # [3] 

107 "pressure_sat_comp_coeff": { 

108 "A": (properties.pressure_sat_comp_coeff_A, None), # [1] 

109 "B": (properties.pressure_sat_comp_coeff_B, None), 

110 "C": (properties.pressure_sat_comp_coeff_C, None), 

111 "D": (properties.pressure_sat_comp_coeff_D, None), 

112 }, 

113 }, 

114 } 

115 return compound_configuration 

116 

117 

118def build_kappas(kappa_values: dict[str,dict[str,float]]) -> dict[tuple[str,str], float]: 

119 kappa_configuration: dict[tuple[str,str], float] = {} 

120 for comp1, values in kappa_values.items(): 

121 for comp2, value in values.items(): 

122 kappa_configuration[(comp1, comp2)] = value 

123 return kappa_configuration