Coverage for backend/idaes_service/solver/build_state.py: 95%

36 statements  

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

1from typing import Any 

2from idaes.core import FlowsheetBlock 

3 

4from common.models.idaes.flowsheet_schema import PropertyPackageType 

5from common.models.idaes.payloads import BuildStateRequestSchema 

6from common.models.idaes.unit_model_schema import SolvedPropertyValueSchema 

7from .property_package_manager import create_property_package 

8from .methods.adapter import fix_block, serialize_properties_map, deactivate_fixed_guesses 

9from .methods.BlockContext import BlockContext 

10from pyomo.environ import ConcreteModel 

11from .properties_manager import PropertiesManager 

12from pyomo.environ import Block, assert_optimal_termination, SolverFactory 

13from pyomo.core.base.constraint import ScalarConstraint 

14from .flowsheet_manager import build_flowsheet 

15from idaes.core.util.model_statistics import degrees_of_freedom, number_unused_variables, number_activated_equalities, number_unfixed_variables, number_unfixed_variables_in_activated_equalities 

16from idaes.core.util.model_diagnostics import DiagnosticsToolbox 

17 

18def solve_state_block(schema: BuildStateRequestSchema) -> list[SolvedPropertyValueSchema]: 

19 m, sb = build_state(schema.property_package) 

20 # if there's only one compound in the property package, remove the mole_frac_comp (as it's over specified) 

21 if len(schema.property_package.compounds) == 1: 

22 del schema.properties["mole_frac_comp"] 

23 

24 block_ctx = BlockContext(m.fs) 

25 fix_block(sb, schema.properties, m.fs, block_ctx) 

26 

27 # If the degrees of freedom are not zero, don't try solve. 

28 # However, the degree of freedom logic ignores any variables that aren't actually used. So if temperature  

29 # and pressure are both not specified, and there are no constraints for them either, it decides that 

30 # they are not part of the solution, and says there's 0 degrees of freedom. 

31 # so instead, we actually check there are unfixed variables that are not in activated equalities. 

32 # TODO: Check why adding and degrees_of_freedom(sb) == 0 makes pr fail (python manage.py test core.auxiliary.tests.test_Compounds) 

33 if number_unfixed_variables(sb) - number_unfixed_variables_in_activated_equalities(sb) != 0: 33 ↛ 34line 33 didn't jump to line 34 because the condition on line 33 was never true

34 return [] # This means no properties are returned, so the backend won't update anything. 

35 block_ctx.apply_elimination() 

36 

37 # initialise the state block, which will perform a solve 

38 sb.initialize(outlvl=1) 

39 deactivate_fixed_guesses(m.fs.guess_vars) 

40 

41 return serialize_properties_map(m.fs) 

42 

43 

44def build_state(schema: PropertyPackageType) -> Any: # PropertyPackageSchema 

45 m = build_flowsheet(dynamic=False) 

46 # create the property package and state block 

47 property_package = create_property_package(schema, m) 

48 state_block = property_package.build_state_block(m.fs.time, defined_state=True) 

49 m.fs.add_component(f"PP_{schema.id}_state", state_block) 

50 

51 return m, state_block 

52 

53 

54def get_state_vars(schema: PropertyPackageType) -> Any: 

55 _, state_block = build_state(schema) 

56 

57 return state_block[0].define_state_vars()