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

27 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). 

5# 

6# Copyright (c) 2018-2024 by the software owners: The Regents of the 

7# University of California, through Lawrence Berkeley National Laboratory, 

8# National Technology & Engineering Solutions of Sandia, LLC, Carnegie Mellon 

9# University, West Virginia University Research Corporation, et al. 

10# All rights reserved. Please see the files COPYRIGHT.md and LICENSE.md 

11# for full copyright and license information. 

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

13""" 

14Base class for unit models 

15""" 

16 

17from pyomo.environ import check_optimal_termination 

18from pyomo.common.config import ConfigValue 

19from pyomo.network import Port 

20 

21from idaes.core.base.process_base import ( 

22 declare_process_block_class, 

23 ProcessBlockData, 

24 useDefault, 

25) 

26from idaes.core.base.property_base import StateBlock 

27from idaes.core.base.control_volume_base import ( 

28 ControlVolumeBlockData, 

29 FlowDirection, 

30 MaterialBalanceType, 

31) 

32from idaes.core.util.exceptions import ( 

33 BurntToast, 

34 ConfigurationError, 

35 BalanceTypeNotSupportedError, 

36 InitializationError, 

37) 

38from idaes.core.util.tables import create_stream_table_dataframe 

39import idaes.logger as idaeslog 

40from idaes.core.solvers import get_solver 

41from idaes.core.util.config import DefaultBool 

42from idaes.core.initialization import SingleControlVolumeUnitInitializer 

43from pyomo.environ import Var, units, Expression 

44from pyomo.dae import Integral 

45 

46 

47# Set up logger 

48_log = idaeslog.getLogger(__name__) 

49 

50 

51@declare_process_block_class("IntegrationBlock") 

52class IntegrationBlockData(ProcessBlockData): 

53 """ 

54 This block has no inlets or outlets, but one value that you can get the integral for. 

55 """ 

56 

57 # Create Class ConfigBlock 

58 CONFIG = ProcessBlockData.CONFIG() 

59 CONFIG.declare( 

60 "dynamic", 

61 ConfigValue( 

62 default=useDefault, 

63 domain=DefaultBool, 

64 description="Dynamic model flag", 

65 doc="""Indicates whether this model will be dynamic or not, 

66**default** = useDefault. 

67**Valid values:** { 

68**useDefault** - get flag from parent (default = False), 

69**True** - set as a dynamic model, 

70**False** - set as a steady-state model.}""", 

71 ), 

72 ) 

73 

74 def build(self): 

75 """ 

76  

77 """ 

78 super(IntegrationBlockData, self).build() 

79 

80 self.variable = Var( 

81 self.flowsheet().time 

82 ) 

83 

84 #self.time = self.flowsheet().time 

85 

86 

87 

88 def _integral(m): 

89 time_steps = sorted(self.flowsheet().time) 

90 value = m.variable 

91 return sum([ 

92 # Trapezium rule 

93 # average the value at the current and next time step, then multiply by the time difference 

94 0.5 * (value[time_steps[i]] + value[time_steps[i+1]]) * (time_steps[i+1] - time_steps[i]) 

95 for i in range(len(time_steps)-1) 

96 ]) 

97 

98 self.integral = Expression( 

99 rule=_integral 

100 ) 

101 

102 

103 # if self.config.dynamic: 

104 # # create a variable to hold the normal value, and one to hold the integral value 

105 # else: 

106