Coverage for tests / tests_simulation / test_state.py: 100%

89 statements  

« prev     ^ index     » next       coverage.py v7.13.1, created at 2026-01-09 16:40 +0100

1# SPDX-FileCopyrightText: Copyright INRIA 

2# 

3# SPDX-License-Identifier: LGPL-3.0-only 

4# 

5# Copyright INRIA 

6# 

7# This file is part of PhysioBlocks, a library mostly developed by the 

8# [Ananke project-team](https://team.inria.fr/ananke) at INRIA. 

9# 

10# Authors: 

11# - Colin Drieu 

12# - Dominique Chapelle 

13# - François Kimmig 

14# - Philippe Moireau 

15# 

16# PhysioBlocks is free software: you can redistribute it and/or modify it under the 

17# terms of the GNU Lesser General Public License as published by the Free Software 

18# Foundation, version 3 of the License. 

19# 

20# PhysioBlocks is distributed in the hope that it will be useful, but WITHOUT ANY 

21# WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A 

22# PARTICULAR PURPOSE. See the GNU Lesser General Public License for more details. 

23# 

24# You should have received a copy of the GNU Lesser General Public License along with 

25# PhysioBlocks. If not, see <https://www.gnu.org/licenses/>. 

26 

27import numpy as np 

28import pytest 

29from numpy.typing import NDArray 

30 

31from physioblocks.computing.quantities import Quantity 

32from physioblocks.simulation.state import State 

33 

34_X0_ID = "x0" 

35_X1_ID = "x1" 

36_X2_ID = "x2" 

37 

38 

39@pytest.fixture 

40def scalar() -> float: 

41 return 1.0 

42 

43 

44@pytest.fixture 

45def vector() -> NDArray[np.float64]: 

46 return np.array( 

47 [1.0, 1.0], 

48 ) 

49 

50 

51class TestState: 

52 def test_constructor(self): 

53 state = State() 

54 assert state.size == 0 

55 

56 def test_variables(self, scalar, vector): 

57 state = State() 

58 

59 state.add_variable(_X0_ID, scalar) 

60 assert state.size == 1 

61 assert _X0_ID in state 

62 assert state.get_variable_index(_X0_ID) == 0 

63 assert state.get_variable_size(_X0_ID) == 1 

64 assert state.get_variable_id(0) == _X0_ID 

65 

66 message = str.format("No variable at index {0}", 1) 

67 with pytest.raises(KeyError, match=message): 

68 state.get_variable_id(1) 

69 

70 state.add_variable(_X1_ID, vector) 

71 assert state.size == 3 

72 assert _X1_ID in state 

73 assert state.get_variable_index(_X1_ID) == 1 

74 assert state.get_variable_size(_X1_ID) == 2 

75 assert state.get_variable_id(1) == _X1_ID 

76 

77 state.add_variable(_X2_ID, vector) 

78 assert state.size == 5 

79 assert state.get_variable_index(_X2_ID) == 3 

80 

81 assert state.indexes == {_X0_ID: 0, _X1_ID: 1, _X2_ID: 3} 

82 

83 state.remove_variable(_X1_ID) 

84 assert (_X1_ID in state) is False 

85 assert state.size == 3 

86 assert state.get_variable_index(_X0_ID) == 0 

87 assert state.get_variable_index(_X2_ID) == 1 

88 

89 variables = [_X0_ID, _X2_ID] 

90 assert list(state.indexes.keys()) == variables 

91 

92 error_message = str.format("{0} is already registered.", _X0_ID) 

93 with pytest.raises(KeyError, match=error_message): 

94 state.add_variable(_X0_ID, scalar) 

95 

96 def test_set_variable_quantity(self, scalar: float, vector: NDArray[np.float64]): 

97 state = State() 

98 state[_X0_ID] = Quantity(scalar) 

99 state.add_variable(_X1_ID, scalar) 

100 state[_X1_ID] = Quantity(scalar) 

101 

102 assert state[_X0_ID].current == pytest.approx(scalar) 

103 assert state[_X1_ID].current == pytest.approx(scalar) 

104 

105 with pytest.raises(ValueError): 

106 state[_X0_ID] = Quantity(vector) 

107 

108 with pytest.raises(KeyError): 

109 state["unregistered"] 

110 

111 def test_state_vector(self, scalar: float, vector: NDArray[np.float64]): 

112 state = State() 

113 

114 state.add_variable(_X0_ID, 0.0) 

115 state[_X0_ID].initialize(scalar) 

116 state.add_variable(_X1_ID, [0.0, 0.0]) 

117 state[_X1_ID].initialize(vector) 

118 

119 init_ref = np.ones( 

120 shape=3, 

121 ) 

122 update_ref = np.array( 

123 [0.1, 0.2, 0.3], 

124 ) 

125 set_ref = np.zeros( 

126 shape=3, 

127 ) 

128 

129 assert state.state_vector == pytest.approx(init_ref) 

130 

131 with pytest.raises(AttributeError): 

132 state.state_vector = update_ref 

133 

134 state.update_state_vector(update_ref) 

135 assert state.state_vector == pytest.approx(update_ref) 

136 assert state[_X0_ID].new == pytest.approx(update_ref[0]) 

137 assert state[_X0_ID].current == pytest.approx(init_ref[0]) 

138 assert state[_X1_ID].new == pytest.approx(update_ref[1:3]) 

139 assert state[_X1_ID].current == pytest.approx(init_ref[1:3]) 

140 

141 state.set_state_vector(set_ref) 

142 assert state.state_vector == pytest.approx(set_ref) 

143 assert state[_X0_ID].new == pytest.approx(set_ref[0]) 

144 assert state[_X0_ID].current == pytest.approx(set_ref[0]) 

145 assert state[_X1_ID].new == pytest.approx(set_ref[1:3]) 

146 assert state[_X1_ID].current == pytest.approx(set_ref[1:3]) 

147 

148 wrong_size_vector = np.zeros( 

149 shape=5, 

150 ) 

151 with pytest.raises(ValueError): 

152 state.update_state_vector(wrong_size_vector) 

153 

154 with pytest.raises(ValueError): 

155 state.set_state_vector(wrong_size_vector)