Coverage for tests/test_fracture.py: 0%
121 statements
« prev ^ index » next coverage.py v7.9.1, created at 2025-09-11 16:23 +0200
« prev ^ index » next coverage.py v7.9.1, created at 2025-09-11 16:23 +0200
1import pathlib
2from typing import Sequence
4import numpy as np
5import pytest
7import swiift.lib.phase_shift as ps
8import swiift.model.frac_handlers as fh
9import swiift.model.model as model
10from swiift.model.model import DiscreteSpectrum, Domain, Floe, Ice, Ocean
11from tests.utils import fracture_handler_types
13scattering_handler_types = (
14 ps.ContinuousScatteringHandler,
15 ps.UniformScatteringHandler,
16 ps.PerturbationScatteringHandler,
17)
19# Data for stability tests
20PATH_FRACTURE_TARGETS = pathlib.Path("tests/target/fracture")
21binary_energy_no_growth_target = np.loadtxt(
22 PATH_FRACTURE_TARGETS.joinpath("binary_fracture.ssv")
23)
24binary_energy_with_growth_target = np.loadtxt(
25 PATH_FRACTURE_TARGETS.joinpath("binary_fracture_with_growth.ssv")
26)
27binary_strain_no_growth_target = np.loadtxt(
28 PATH_FRACTURE_TARGETS.joinpath("binary_strain_fracture.ssv")
29)
30binary_strain_with_growth_target = np.loadtxt(
31 PATH_FRACTURE_TARGETS.joinpath("binary_strain_fracture_with_growth.ssv")
32)
33multi_strain_no_growth_archive = np.load(
34 PATH_FRACTURE_TARGETS.joinpath("multi_strain_fracture.npz")
35)
36multi_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)
40multi_strain_with_growth_archive = np.load(
41 PATH_FRACTURE_TARGETS.joinpath("multi_strain_fracture_with_growth.npz")
42)
43multi_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)
49def 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
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]
80def 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()
88@pytest.mark.parametrize("fracture_handler_type", fracture_handler_types)
89@pytest.mark.parametrize("scattering_spec_type", scattering_handler_types)
90def 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
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")
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)
115def 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
125# Stability tests
126@pytest.mark.slow
127@pytest.mark.parametrize("row", binary_energy_no_growth_target)
128def test_binary_energy_no_growth(row: np.ndarray):
129 growth_params = None
130 an_sol = True
131 fracture_handler = fh.BinaryFracture()
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])
142@pytest.mark.slow
143@pytest.mark.parametrize("row", binary_energy_with_growth_target)
144def 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
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])
158@pytest.mark.parametrize("row", binary_strain_no_growth_target)
159def test_binary_strain_no_growth(row: np.ndarray):
160 growth_params = None
161 an_sol = True
162 fracture_handler = fh.BinaryStrainFracture()
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])
173@pytest.mark.parametrize("row", binary_strain_with_growth_target)
174def 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
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])
188@pytest.mark.parametrize("row, target", multi_strain_no_growth_target)
189def test_multi_strain_no_growth(row: np.ndarray, target: np.ndarray):
190 growth_params = None
191 an_sol = True
192 fracture_handler = fh.MultipleStrainFracture()
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)
203@pytest.mark.parametrize("row, target", multi_strain_with_growth_target)
204def 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
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)