Coverage for tests/conftest.py: 97%

37 statements  

« prev     ^ index     » next       coverage.py v7.9.1, created at 2025-07-18 14:20 +0200

1from hypothesis import strategies as st 

2import numpy as np 

3 

4from swiift.lib.constants import PI_2 

5from swiift.model.model import DiscreteSpectrum, Floe, Ice, Ocean 

6 

7# Generic float options 

8float_kw = { 

9 "allow_nan": False, 

10 "allow_subnormal": False, 

11} 

12 

13 

14# For the composite strategies, set somewhat stricter upper bounds than plain 

15# inequality to avoid head-scratching floating point innacuracies 

16@st.composite 

17def ice_density(draw, ocean_density): 

18 ex = draw(ocean_density) 1b

19 return draw(st.floats(10, 0.9999 * ex, **float_kw)) 1b

20 

21 

22@st.composite 

23def ice_thickness(draw, ocean_density, ocean_depth, ice_density): 

24 kwgs = {"rhow": ocean_density, "rhoi": ice_density, "H": ocean_depth} 1b

25 ex = {k: draw(v) for k, v in kwgs.items()} 1b

26 upper_bound = 0.9999 * ex["rhow"] / ex["rhoi"] * ex["H"] 1b

27 return draw(st.floats(0.1e-3, min(1000, upper_bound), exclude_max=True, **float_kw)) 1b

28 

29 

30@st.composite 

31def floe_length(draw, ice: Ice) -> float: 

32 return draw(st.floats(2 * draw(ice).thickness, 1000e3, **float_kw)) 

33 

34 

35# All SI units 

36physical_strategies = { 

37 "floe": { 

38 "left_edge": st.floats(0, 5e3, **float_kw), 

39 }, 

40 "ocean": { 

41 "depth": ( 

42 st.floats(min_value=1e-3, max_value=1000e3, **float_kw) | st.just(np.inf) 

43 ), 

44 "density": st.floats(500, 5e3, **float_kw), 

45 }, 

46 "ice": { 

47 "frac_toughness": st.floats(1e3, 1e7, **float_kw), 

48 "poissons_ratio": st.floats(-0.999, 0.5, **float_kw), 

49 "strain_threshold": st.floats(1e-7, 1e-3, **float_kw), 

50 "thickness": st.floats(1e-3, 1e3, **float_kw), 

51 "youngs_modulus": st.floats(1e6, 100e9, **float_kw), 

52 "elastic_length": st.floats( 

53 5e-4, 3e4, **float_kw 

54 ), # derived from the bounds on its constituents 

55 }, 

56 "wave": { 

57 "amplitude": st.floats(1e-6, 1e3, **float_kw), 

58 "period": st.floats(min_value=1e-1, max_value=1e4, **float_kw), 

59 "frequency": st.floats(min_value=1e-4, max_value=10, **float_kw), 

60 "phase": st.floats(0, PI_2, exclude_max=True, **float_kw), 

61 "wavenumber": st.floats( 

62 7e-4, 600, **float_kw 

63 ), # covers waves from about 10 cm to 10 km 

64 }, 

65 "gravity": st.floats(0.1, 30, **float_kw), 

66} 

67 

68 

69physical_strategies["floe"]["length"] = floe_length 

70physical_strategies["ice"]["density_coupled"] = ice_density 

71physical_strategies["ice"]["thickness_coupled"] = ice_thickness 

72 

73 

74@st.composite 

75def spec_mono(draw): 

76 return DiscreteSpectrum( 1b

77 draw(st.just(0.5)), draw(physical_strategies["wave"]["frequency"]) 

78 ) 

79 

80 

81@st.composite 

82def spec_poly(draw): 

83 n = draw(st.integers(min_value=2, max_value=10)) 1b

84 amplitudes = draw( 1b

85 st.lists( 

86 physical_strategies["wave"]["amplitude"], 

87 min_size=n, 

88 max_size=n, 

89 unique=True, 

90 ) 

91 ) 

92 frequencies = draw( 1b

93 st.lists( 

94 physical_strategies["wave"]["frequency"], 

95 min_size=n, 

96 max_size=n, 

97 unique=True, 

98 ) 

99 ) 

100 # phases = draw( 

101 # st.lists( 

102 # physical_strategies["wave"]["phase"], 

103 # min_size=n, 

104 # max_size=n, 

105 # unique=True, 

106 # ) 

107 # ) 

108 return DiscreteSpectrum(amplitudes, frequencies) 1b

109 

110 

111ocean_and_mono_spectrum = { 

112 "ocean": st.builds( 

113 Ocean, 

114 depth=physical_strategies["ocean"]["depth"], 

115 density=physical_strategies["ocean"]["density"], 

116 ), 

117 "spectrum": spec_mono(), 

118 "gravity": physical_strategies["gravity"], 

119} 

120 

121ocean_and_poly_spectrum = { 

122 "ocean": st.builds( 

123 Ocean, 

124 depth=physical_strategies["ocean"]["depth"], 

125 density=physical_strategies["ocean"]["density"], 

126 ), 

127 "spectrum": spec_poly(), 

128 "gravity": physical_strategies["gravity"], 

129} 

130 

131ocean_and_spectrum = { 

132 "ocean": st.builds( 

133 Ocean, 

134 depth=physical_strategies["ocean"]["depth"], 

135 density=physical_strategies["ocean"]["density"], 

136 ), 

137 "spectrum": spec_mono() | spec_poly(), 

138 "gravity": physical_strategies["gravity"], 

139} 

140 

141coupled_ocean_ice = { 

142 "ocean": st.builds( 

143 Ocean, 

144 depth=st.shared(physical_strategies["ocean"]["depth"], key="H"), 

145 density=st.shared(physical_strategies["ocean"]["density"], key="rhow"), 

146 ), 

147 "ice": st.shared( 

148 st.builds( 

149 Ice, 

150 density=st.shared( 

151 physical_strategies["ice"]["density_coupled"]( 

152 st.shared(physical_strategies["ocean"]["density"], key="rhow") 

153 ), 

154 key="rhoi", 

155 ), 

156 frac_toughness=physical_strategies["ice"]["frac_toughness"], 

157 poissons_ratio=physical_strategies["ice"]["poissons_ratio"], 

158 thickness=physical_strategies["ice"]["thickness_coupled"]( 

159 ocean_depth=st.shared(physical_strategies["ocean"]["depth"], key="H"), 

160 ocean_density=st.shared( 

161 physical_strategies["ocean"]["density"], key="rhow" 

162 ), 

163 ice_density=st.shared( 

164 physical_strategies["ice"]["density_coupled"]( 

165 st.shared(physical_strategies["ocean"]["density"], key="rhow") 

166 ), 

167 key="rhoi", 

168 ), 

169 ), 

170 youngs_modulus=physical_strategies["ice"]["youngs_modulus"], 

171 ), 

172 key="ice", 

173 ), 

174 "gravity": physical_strategies["gravity"], 

175} 

176 

177coupled_floe = { 

178 "floe": st.builds( 

179 Floe, 

180 left_edge=physical_strategies["floe"]["left_edge"], 

181 length=physical_strategies["floe"]["length"]( 

182 st.shared(coupled_ocean_ice["ice"], key="ice") 

183 ), 

184 ice=st.shared(coupled_ocean_ice["ice"], key="ice"), 

185 ) 

186} | coupled_ocean_ice 

187 

188simple_objects = { 

189 "ocean": Ocean(), 

190 "ice": Ice(), 

191 "spec_mono": DiscreteSpectrum(0.5, 1 / 7), 

192 "spec_poly": DiscreteSpectrum((0.1, 0.2), (1 / 7, 1 / 5)), 

193 "gravity": 9.8, 

194 "length": 101.5, 

195 "left_edge": 13.8, 

196}