Coverage for tests/physical_strategies.py: 68%
22 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
1"""Define strategies for physical scalar variables."""
3from types import MappingProxyType
4import typing
6from hypothesis import strategies as st
7import numpy as np
9from swiift.lib.constants import PI_2
10from swiift.model.model import Ice
11from tests.utils import FloatSt, float_kw
13# Exagerated bounds for all independent physical parameters.
14# Allows for testing exotic situations, without going into extremes either.
15PHYSICAL_STRATEGIES = MappingProxyType(
16 {
17 ("floe", "left_edge"): st.floats(0, 5e3, **float_kw),
18 ("ocean", "depth"): (
19 st.floats(min_value=1e-3, max_value=1000e3, **float_kw) | st.just(np.inf)
20 ),
21 ("ocean", "density"): st.floats(500, 5e3, **float_kw),
22 ("ice", "frac_toughness"): st.floats(1e3, 1e7, **float_kw),
23 ("ice", "poissons_ratio"): st.floats(-0.999, 0.5, **float_kw),
24 ("ice", "strain_threshold"): st.floats(1e-7, 1e-3, **float_kw),
25 ("ice", "thickness"): st.floats(1e-3, 1e3, **float_kw),
26 ("ice", "youngs_modulus"): st.floats(1e6, 100e9, **float_kw),
27 ("ice", "elastic_length"): st.floats(5e-4, 3e4, **float_kw),
28 ("wave", "amplitude"): st.floats(1e-6, 1e3, **float_kw),
29 ("wave", "period"): st.floats(min_value=1e-1, max_value=1e4, **float_kw),
30 ("wave", "frequency"): st.floats(min_value=1e-4, max_value=10, **float_kw),
31 ("wave", "phase"): st.floats(0, PI_2, exclude_max=True, **float_kw),
32 ("wave", "wavenumber"): st.floats(7e-4, 600, **float_kw),
33 ("gravity",): st.floats(0.1, 30, **float_kw),
34 }
35)
38# For the composite strategies, set somewhat stricter upper bounds than plain
39# inequality to avoid head-scratching floating point innacuracies.
40@st.composite
41def ice_density(draw: st.DrawFn, ocean_density: FloatSt) -> float:
42 """Ice density contrained by ocean density.
44 We typically want ice to have a lower density for it to float.
46 Parameters
47 ----------
48 draw : st.DrawFn
49 Hypothesis dynamic callable.
50 ocean_density : FloatSt
51 Ocean density in kg m**-3.
53 Returns
54 -------
55 float
56 Ice density in kg m**-3.
58 """
59 ex = draw(ocean_density)
60 return draw(st.floats(10, 0.9999 * ex, allow_nan=False, allow_subnormal=False))
63@st.composite
64def ice_thickness(
65 draw: st.DrawFn,
66 ocean_density: FloatSt,
67 ocean_depth: FloatSt,
68 ice_density: FloatSt,
69) -> float:
70 """Ice thickness constrained by ocean depth and ice draught.
72 We typically want ice not to be grounded. That is, it must be thin enough
73 that its draught is less than the water depth.
75 Parameters
76 ----------
77 draw : st.DrawFn
78 Hypothesis dynamic callable.
79 ocean_density : FloatSt
80 Strategy for ocean density in kg m**-3.
81 ocean_depth : FloatSt
82 Strategy for ocean depth in m.
83 ice_density : FloatSt
84 Strategy for ice density in kg m**-3.
86 Returns
87 -------
88 float
89 Ice thickness in m.
91 """
92 kwgs = {"rhow": ocean_density, "rhoi": ice_density, "H": ocean_depth}
93 ex = {k: draw(v) for k, v in kwgs.items()}
94 upper_bound = 0.9999 * ex["rhow"] / ex["rhoi"] * ex["H"]
95 return draw(
96 st.floats(
97 0.1e-3,
98 min(1000, upper_bound),
99 exclude_max=True,
100 allow_nan=False,
101 allow_subnormal=False,
102 )
103 )
106@st.composite
107def floe_length(draw: st.DrawFn, ice: st.SearchStrategy[Ice]) -> float:
108 """Floe length constrained by ice thickness.
110 We typically want floes to be longer than they are thick for stable buoyancy.
112 Parameters
113 ----------
114 draw : st.DrawFn
115 Hypothesis dynamic callable.
116 ice : st.SearchStrategy[Ice]
117 Strategy for an ice object.
119 Returns
120 -------
121 float
122 Floe length in m.
124 """
125 return draw(
126 st.floats(
127 2 * draw(ice).thickness, 1000e3, allow_nan=False, allow_subnormal=False
128 )
129 )
132PHYSICAL_STRATEGIES_COMPOSITE: MappingProxyType[str, typing.Callable[..., FloatSt]] = (
133 MappingProxyType(
134 {
135 "floe_length": floe_length,
136 "ice_density": ice_density,
137 "ice_thickness": ice_thickness,
138 }
139 )
140)