Coverage for backend/ahuora-compounds/ahuora_property_packages/component_metadata.py: 83%

27 statements  

« prev     ^ index     » next       coverage.py v7.10.7, created at 2026-07-22 05:22 +0000

1"""Read component metadata from the property packages used by IDAES.""" 

2 

3from functools import lru_cache 

4 

5from pyomo.environ import ConcreteModel, units as pyunits, value 

6 

7from ahuora_property_packages.build_package import build_package 

8 

9 

10@lru_cache(maxsize=128) 

11def _molecular_weights_for_package( 

12 package_name: str, 

13 compounds: tuple[str, ...], 

14) -> dict[str, float]: 

15 """Build a package once and return its molecular weights in g/mol.""" 

16 model = ConcreteModel() 

17 model.properties = build_package(package_name, list(compounds)) # type: ignore[arg-type] 

18 parameter_block = model.properties 

19 

20 molecular_weights: dict[str, float] = {} 

21 for component_name in parameter_block.component_list: 

22 if hasattr(parameter_block, "mw_comp"): 

23 molecular_weight = parameter_block.mw_comp[component_name] 

24 else: 

25 component = parameter_block.get_component(component_name) 

26 molecular_weight = getattr(component, "mw", None) 

27 

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

29 continue 

30 source_units = pyunits.get_units(molecular_weight) 

31 if source_units is None: 31 ↛ 32line 31 didn't jump to line 32 because the condition on line 31 was never true

32 raise ValueError( 

33 f"Molecular weight for component {component_name!r} in property " 

34 f"package {package_name!r} has no units." 

35 ) 

36 molecular_weights[str(component_name)] = pyunits.convert_value( 

37 value(molecular_weight), 

38 from_units=source_units, 

39 to_units=pyunits.g / pyunits.mol, 

40 ) 

41 

42 return molecular_weights 

43 

44 

45def get_component_molecular_weight( 

46 package_name: str, 

47 compounds: tuple[str, ...], 

48 component_name: str, 

49) -> float: 

50 """Return canonical package component molecular weight in g/mol.""" 

51 molecular_weights = _molecular_weights_for_package( 

52 package_name, 

53 tuple(sorted(compounds)), 

54 ) 

55 try: 

56 return molecular_weights[component_name] 

57 except KeyError as error: 

58 raise ValueError( 

59 f"Property package {package_name!r} does not expose a molecular " 

60 f"weight for component {component_name!r}." 

61 ) from error