Coverage for tests/test_fracture.py: 0%

1 import pathlib

2 from typing import Sequence

3

4 import numpy as np

5 import pytest

6

7 import swiift.lib.phase_shift as ps

8 import swiift.model.frac_handlers as fh

9 import swiift.model.model as model

10 from swiift.model.model import DiscreteSpectrum, Domain, Floe, Ice, Ocean

11 from tests.utils import fracture_handler_types

12

13 scattering_handler_types = (

14 ps.ContinuousScatteringHandler,

15 ps.UniformScatteringHandler,

16 ps.PerturbationScatteringHandler,

17)

18

19# Data for stability tests

20 PATH_FRACTURE_TARGETS = pathlib.Path("tests/target/fracture")

21 binary_energy_no_growth_target = np.loadtxt(

22 PATH_FRACTURE_TARGETS.joinpath("binary_fracture.ssv")

23)

24 binary_energy_with_growth_target = np.loadtxt(

25 PATH_FRACTURE_TARGETS.joinpath("binary_fracture_with_growth.ssv")

26)

27 binary_strain_no_growth_target = np.loadtxt(

28 PATH_FRACTURE_TARGETS.joinpath("binary_strain_fracture.ssv")

29)

30 binary_strain_with_growth_target = np.loadtxt(

31 PATH_FRACTURE_TARGETS.joinpath("binary_strain_fracture_with_growth.ssv")

32)

33 multi_strain_no_growth_archive = np.load(

34 PATH_FRACTURE_TARGETS.joinpath("multi_strain_fracture.npz")

35)

36 multi_strain_no_growth_target = (

37 (row, multi_strain_no_growth_archive[f"res{i:02d}"])

38 for i, row in enumerate(multi_strain_no_growth_archive["params"])

39)

40 multi_strain_with_growth_archive = np.load(

41 PATH_FRACTURE_TARGETS.joinpath("multi_strain_fracture_with_growth.npz")

42)

43 multi_strain_with_growth_target = (

44 (row, multi_strain_with_growth_archive[f"res{i:02d}"])

45 for i, row in enumerate(multi_strain_with_growth_archive["params"])

46)

47

48

49 def make_wuf(array: np.ndarray, growth_params: tuple | None) -> model.WavesUnderFloe:

50 (

51 frac_toughness,

52 strain_threshold,

53 thickness,

54 youngs_modulus,

55 depth,

56 gravity,

57 amplitude,

58 frequency,

59 length,

60 left_edge,

61 phase,

62 ) = array

63

64 ice = Ice(

65 frac_toughness=frac_toughness,

66 strain_threshold=strain_threshold,

67 thickness=thickness,

68 youngs_modulus=youngs_modulus,

69 )

70 ocean = Ocean(depth=depth)

71 spectrum = DiscreteSpectrum(

72 amplitudes=amplitude, frequencies=frequency, phases=phase

73 )

74 domain = Domain.from_discrete(gravity, spectrum, ocean, None, growth_params)

75 floe = Floe(left_edge=left_edge, length=length, ice=ice)

76 domain.add_floes(floe)

77 return domain.subdomains[0]

78

79

80 def test_abstract():

81 # Abstract classes, should not be instantiated

82 with pytest.raises(TypeError):

83 fh._FractureHandler()

84 with pytest.raises(TypeError):

85 fh._StrainFracture()

86

87

88@pytest.mark.parametrize("fracture_handler_type", fracture_handler_types)

89@pytest.mark.parametrize("scattering_spec_type", scattering_handler_types)

90 def test_initialisation_scattering(

91 fracture_handler_type: type[fh._FractureHandler],

92 scattering_spec_type: type[ps._ScatteringHandler],

93):

94 def make_handler_from_spec(scattering_spec_type):

95 rng_seed = 13

96 loc, scale = 0.3, 0.005

97

98 match scattering_spec_type:

99 case ps.ContinuousScatteringHandler:

100 return scattering_spec_type()

101 case ps.UniformScatteringHandler:

102 return scattering_spec_type.from_seed(rng_seed)

103 case ps.PerturbationScatteringHandler:

104 return scattering_spec_type.from_seed(rng_seed, loc, scale)

105 case _: # pragma: no cover

106 raise TypeError("Unsupported scattering handler")

107

108 fracture_handler: fh._FractureHandler = fracture_handler_type(

109 scattering_handler=make_handler_from_spec(scattering_spec_type)

110 )

111 assert isinstance(fracture_handler, fracture_handler_type)

112 assert isinstance(fracture_handler.scattering_handler, scattering_spec_type)

113

114

115 def check_no_overlap(

116 fracture_handler: fh._FractureHandler,

117 xf: float | Sequence[float],

118 wuf: model.WavesUnderFloe,

119):

120 post_fracture_wufs = fracture_handler.split(wuf, xf)

121 for wuf_left, wuf_right in zip(post_fracture_wufs[:-1], post_fracture_wufs[1:]):

122 assert wuf_left.right_edge == wuf_right.left_edge

123

124

125# Stability tests

126@pytest.mark.slow

127@pytest.mark.parametrize("row", binary_energy_no_growth_target)

128 def test_binary_energy_no_growth(row: np.ndarray):

129 growth_params = None

130 an_sol = True

131 fracture_handler = fh.BinaryFracture()

132

133 wuf = make_wuf(row[:-1], growth_params)

134 xf = fracture_handler.search(wuf, growth_params, an_sol, None)

135 if xf is not None:

136 assert np.allclose(row[-1], xf)

137 check_no_overlap(fracture_handler, xf, wuf)

138 else:

139 assert np.isnan(row[-1])

140

141

142@pytest.mark.slow

143@pytest.mark.parametrize("row", binary_energy_with_growth_target)

144 def test_binary_energy_with_growth(row: np.ndarray):

145 fracture_handler = fh.BinaryFracture()

146 growth_params = np.atleast_2d(row[-3]), row[-2]

147 an_sol = None

148

149 wuf = make_wuf(row[:-3], growth_params)

150 xf = fracture_handler.search(wuf, growth_params, an_sol, None)

151 if xf is not None:

152 assert np.allclose(row[-1], xf)

153 check_no_overlap(fracture_handler, xf, wuf)

154 else:

155 assert np.isnan(row[-1])

156

157

158@pytest.mark.parametrize("row", binary_strain_no_growth_target)

159 def test_binary_strain_no_growth(row: np.ndarray):

160 growth_params = None

161 an_sol = True

162 fracture_handler = fh.BinaryStrainFracture()

163

164 wuf = make_wuf(row[:-1], growth_params)

165 xf = fracture_handler.search(wuf, growth_params, an_sol, None)

166 if xf is not None:

167 assert np.allclose(row[-1], xf)

168 check_no_overlap(fracture_handler, xf, wuf)

169 else:

170 assert np.isnan(row[-1])

171

172

173@pytest.mark.parametrize("row", binary_strain_with_growth_target)

174 def test_binary_strain_with_growth(row: np.ndarray):

175 fracture_handler = fh.BinaryStrainFracture()

176 growth_params = np.atleast_2d(row[-3]), row[-2]

177 an_sol = None

178

179 wuf = make_wuf(row[:-3], growth_params)

180 xf = fracture_handler.search(wuf, growth_params, an_sol, None)

181 if xf is not None:

182 assert np.allclose(row[-1], xf)

183 check_no_overlap(fracture_handler, xf, wuf)

184 else:

185 assert np.isnan(row[-1])

186

187

188@pytest.mark.parametrize("row, target", multi_strain_no_growth_target)

189 def test_multi_strain_no_growth(row: np.ndarray, target: np.ndarray):

190 growth_params = None

191 an_sol = True

192 fracture_handler = fh.MultipleStrainFracture()

193

194 wuf = make_wuf(row, growth_params)

195 xfs = fracture_handler.search(wuf, growth_params, an_sol, None)

196 if xfs is not None:

197 assert np.allclose(target, xfs)

198 check_no_overlap(fracture_handler, xfs, wuf)

199 else:

200 assert np.isnan(target)

201

202

203@pytest.mark.parametrize("row, target", multi_strain_with_growth_target)

204 def test_multi_strain_with_growth(row: np.ndarray, target: np.ndarray):

205 fracture_handler = fh.MultipleStrainFracture()

206 # xf not part of the array here, so slightly different slicing

207 growth_params = np.atleast_2d(row[-2]), row[-1]

208 an_sol = None

209

210 wuf = make_wuf(row[:-2], growth_params)

211 xfs = fracture_handler.search(wuf, growth_params, an_sol, None)

212 if xfs is not None:

213 assert np.allclose(target, xfs)

214 check_no_overlap(fracture_handler, xfs, wuf)

215 else:

216 assert np.isnan(target)