Coverage for tests/conftest.py: 97%
37 statements
« prev ^ index » next coverage.py v7.9.1, created at 2025-07-18 14:20 +0200
« 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
4from swiift.lib.constants import PI_2
5from swiift.model.model import DiscreteSpectrum, Floe, Ice, Ocean
7# Generic float options
8float_kw = {
9 "allow_nan": False,
10 "allow_subnormal": False,
11}
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
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
30@st.composite
31def floe_length(draw, ice: Ice) -> float:
32 return draw(st.floats(2 * draw(ice).thickness, 1000e3, **float_kw))
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}
69physical_strategies["floe"]["length"] = floe_length
70physical_strategies["ice"]["density_coupled"] = ice_density
71physical_strategies["ice"]["thickness_coupled"] = ice_thickness
74@st.composite
75def spec_mono(draw):
76 return DiscreteSpectrum( 1b
77 draw(st.just(0.5)), draw(physical_strategies["wave"]["frequency"])
78 )
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
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}
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}
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}
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}
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
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}