Coverage for backend/ahuora-compounds/ahuora_compounds/packages/chemsep.py: 96%

90 statements  

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

1import xml.etree.ElementTree as ET 

2from pydantic import BaseModel 

3from typing import Dict 

4from ahuora_compounds.PropertyPackage import PropertyPackage 

5from ahuora_compounds.CompoundRegistry import CompoundRegistry 

6import os 

7 

8ChemsepCompoundData: Dict[str, "ChemsepCompound"] = {} 

9 

10 

11def register(registry: CompoundRegistry) -> None: 

12 registry.register_package(PropertyPackage("peng-robinson")) 

13 

14 for file in os.listdir(os.path.dirname(__file__) + "/data/chemsep/"): 

15 if file.endswith(".xml"): 15 ↛ 14line 15 didn't jump to line 14 because the condition on line 15 was always true

16 compound_name = file[:-4] 

17 compound = load_compound(compound_name) 

18 ChemsepCompoundData[compound_name] = compound 

19 registry.bind(compound_name, "peng-robinson") 

20 

21 

22def convert_string_to_float(string: str) -> float | str: 

23 try: 

24 return float(string) 

25 except (AttributeError, ValueError): 

26 # TODO: Why are we doing this again? 

27 return string 

28 

29 

30class UnitValuePair(BaseModel): 

31 name: str | None 

32 value: float | str | None 

33 unit: str | None 

34 

35 

36# Helper functions 

37def parse_element(elem: ET.Element | None): 

38 if elem is None: 

39 return None 

40 try: 

41 return UnitValuePair(name=elem.get('name'), value=convert_string_to_float(elem.get('value')), unit=elem.get('units')) 

42 except (AttributeError, ValueError): 

43 #TODO: Why are we catching these errors here? This is not really good practice. Is there a good reason for it? 

44 return None 

45 

46 

47Coefficients = Dict[str, float | str] 

48 

49 

50def parse_coeff(element: ET.Element | None) -> Coefficients: 

51 if element is None: 

52 return {} 

53 self = {} 

54 for child in element: 

55 value = child.get('value') 

56 if value is not None: 56 ↛ 54line 56 didn't jump to line 54 because the condition on line 56 was always true

57 self[child.tag] = convert_string_to_float(value) 

58 return self 

59 

60class ChemsepCompound(BaseModel): 

61 LibraryIndex: UnitValuePair | None = None 

62 CompoundID: UnitValuePair | None = None 

63 StructureFormula: UnitValuePair | None = None 

64 Family: UnitValuePair | None = None 

65 CriticalTemperature: UnitValuePair | None = None 

66 CriticalPressure: UnitValuePair | None = None 

67 CriticalVolume: UnitValuePair | None = None 

68 CriticalCompressibility: UnitValuePair | None = None 

69 NormalBoilingPointTemperature: UnitValuePair | None = None 

70 NormalMeltingPointTemperature: UnitValuePair | None = None 

71 TriplePointTemperature: UnitValuePair | None = None 

72 TriplePointPressure: UnitValuePair | None = None 

73 MolecularWeight: UnitValuePair | None = None 

74 LiquidVolumeAtNormalBoilingPoint: UnitValuePair | None = None 

75 AcentricityFactor: UnitValuePair | None = None 

76 RadiusOfGyration: UnitValuePair | None = None 

77 SolubilityParameter: UnitValuePair | None = None 

78 DipoleMoment: UnitValuePair | None = None 

79 VanDerWaalsVolume: UnitValuePair | None = None 

80 VanDerWaalsArea: UnitValuePair | None = None 

81 HeatOfFormation: UnitValuePair | None = None 

82 GibbsEnergyOfFormation: UnitValuePair | None = None 

83 AbsEntropy: UnitValuePair | None = None 

84 HeatOfFusionAtMeltingPoint: UnitValuePair | None = None 

85 MatthiasCopemanC1: UnitValuePair | None = None 

86 HeatOfCombustion: UnitValuePair | None = None 

87 SolidDensity: Coefficients | None = None 

88 LiquidDensity: Coefficients | None = None 

89 VaporPressure: Coefficients | None = None 

90 HeatOfVaporization: Coefficients | None = None 

91 SolidHeatCapacityCp: Coefficients | None = None 

92 LiquidHeatCapacityCp: Coefficients | None = None 

93 IdealGasHeatCapacityCp: Coefficients | None = None 

94 SecondVirialCoefficient: Coefficients | None = None 

95 LiquidViscosity: Coefficients | None = None 

96 VaporViscosity: Coefficients | None = None 

97 LiquidThermalConductivity: Coefficients | None = None 

98 VaporThermalConductivity: Coefficients | None = None 

99 SurfaceTension: Coefficients | None = None 

100 RPPHeatCapacityCp: Coefficients | None = None 

101 RelativeStaticPermittivity: Coefficients | None = None 

102 AntoineVaporPressure: Coefficients | None = None 

103 LiquidViscosityRPS: Coefficients | None = None 

104 

105 

106def load_compound(name: str) -> ChemsepCompound: 

107 """ 

108 Parses the XML string and populates the object's attributes. 

109 

110 Args: 

111 name (str): The XML data as a string. 

112 """ 

113 with open(os.path.dirname(__file__) + "/data/chemsep/" + name.lower() + ".xml", 'r') as file: 

114 file = ''.join(file.readlines()) 

115 

116 root = ET.fromstring(file) 

117 

118 return ChemsepCompound( 

119 LibraryIndex=parse_element(root.find('LibraryIndex')), 

120 CompoundID=parse_element(root.find('CompoundID')), 

121 StructureFormula=parse_element(root.find('StructureFormula')), 

122 Family=parse_element(root.find('Family')), 

123 CriticalTemperature=parse_element(root.find('CriticalTemperature')), 

124 CriticalPressure=parse_element(root.find('CriticalPressure')), 

125 CriticalVolume=parse_element(root.find('CriticalVolume')), 

126 CriticalCompressibility=parse_element(root.find('CriticalCompressibility')), 

127 NormalBoilingPointTemperature=parse_element(root.find('NormalBoilingPointTemperature')), 

128 NormalMeltingPointTemperature=parse_element(root.find('NormalMeltingPointTemperature')), 

129 TriplePointTemperature=parse_element(root.find('TriplePointTemperature')), 

130 TriplePointPressure=parse_element(root.find('TriplePointPressure')), 

131 MolecularWeight=parse_element(root.find('MolecularWeight')), 

132 LiquidVolumeAtNormalBoilingPoint=parse_element(root.find('LiquidVolumeAtNormalBoilingPoint')), 

133 AcentricityFactor=parse_element(root.find('AcentricityFactor')), 

134 RadiusOfGyration=parse_element(root.find('RadiusOfGyration')), 

135 SolubilityParameter=parse_element(root.find('SolubilityParameter')), 

136 DipoleMoment=parse_element(root.find('DipoleMoment')), 

137 VanDerWaalsVolume=parse_element(root.find('VanDerWaalsVolume')), 

138 VanDerWaalsArea=parse_element(root.find('VanDerWaalsArea')), 

139 HeatOfFormation=parse_element(root.find('HeatOfFormation')), 

140 GibbsEnergyOfFormation=parse_element(root.find('GibbsEnergyOfFormation')), 

141 AbsEntropy=parse_element(root.find('AbsEntropy')), 

142 HeatOfFusionAtMeltingPoint=parse_element(root.find('HeatOfFusionAtMeltingPoint')), 

143 MatthiasCopemanC1=parse_element(root.find('MatthiasCopemanC1')), 

144 HeatOfCombustion=parse_element(root.find('HeatOfCombustion')), 

145 SolidDensity=parse_coeff(root.find('SolidDensity')), 

146 LiquidDensity=parse_coeff(root.find('LiquidDensity')), 

147 VaporPressure=parse_coeff(root.find('VaporPressure')), 

148 HeatOfVaporization=parse_coeff(root.find('HeatOfVaporization')), 

149 SolidHeatCapacityCp=parse_coeff(root.find('SolidHeatCapacityCp')), 

150 LiquidHeatCapacityCp=parse_coeff(root.find('LiquidHeatCapacityCp')), 

151 IdealGasHeatCapacityCp=parse_coeff(root.find('IdealGasHeatCapacityCp')), 

152 SecondVirialCoefficient=parse_coeff(root.find('SecondVirialCoefficient')), 

153 LiquidViscosity=parse_coeff(root.find('LiquidViscosity')), 

154 VaporViscosity=parse_coeff(root.find('VaporViscosity')), 

155 LiquidThermalConductivity=parse_coeff(root.find('LiquidThermalConductivity')), 

156 VaporThermalConductivity=parse_coeff(root.find('VaporThermalConductivity')), 

157 SurfaceTension=parse_coeff(root.find('SurfaceTension')), 

158 RPPHeatCapacityCp=parse_coeff(root.find('RPPHeatCapacityCp')), 

159 RelativeStaticPermittivity=parse_coeff(root.find('RelativeStaticPermittivity')), 

160 AntoineVaporPressure=parse_coeff(root.find('AntoineVaporPressure')), 

161 LiquidViscosityRPS=parse_coeff(root.find('LiquidViscosityRPS')), 

162 )