Coverage for tests/physical_strategies.py: 68%

1"""Define strategies for physical scalar variables."""

2

3 from types import MappingProxyType (empty)

4 import typing (empty)

5

6 from hypothesis import strategies as st (empty)

7 import numpy as np (empty)

8

9 from swiift.lib.constants import PI_2 (empty)

10 from swiift.model.model import Ice (empty)

11 from tests.utils import FloatSt, float_kw (empty)

12

13# Exagerated bounds for all independent physical parameters.

14# Allows for testing exotic situations, without going into extremes either.

15 PHYSICAL_STRATEGIES = MappingProxyType( (empty)

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)

36

37

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

39# inequality to avoid head-scratching floating point innacuracies.

40@st.composite (empty)

41 def ice_density(draw: st.DrawFn, ocean_density: FloatSt) -> float: (empty)

42 """Ice density contrained by ocean density.

43

44 We typically want ice to have a lower density for it to float.

45

46 Parameters

47 ----------

48 draw : st.DrawFn

49 Hypothesis dynamic callable.

50 ocean_density : FloatSt

51 Ocean density in kg m**-3.

52

53 Returns

54 -------

55 float

56 Ice density in kg m**-3.

57

58 """

59 ex = draw(ocean_density)

60 return draw(st.floats(10, 0.9999 * ex, allow_nan=False, allow_subnormal=False))

61

62

63@st.composite (empty)

64 def ice_thickness( (empty)

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.

71

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.

74

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.

85

86 Returns

87 -------

88 float

89 Ice thickness in m.

90

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 )

104

105

106@st.composite (empty)

107 def floe_length(draw: st.DrawFn, ice: st.SearchStrategy[Ice]) -> float: (empty)

108 """Floe length constrained by ice thickness.

109

110 We typically want floes to be longer than they are thick for stable buoyancy.

111

112 Parameters

113 ----------

114 draw : st.DrawFn

115 Hypothesis dynamic callable.

116 ice : st.SearchStrategy[Ice]

117 Strategy for an ice object.

118

119 Returns

120 -------

121 float

122 Floe length in m.

123

124 """

125 return draw(

126 st.floats(

127 2 * draw(ice).thickness, 1000e3, allow_nan=False, allow_subnormal=False

128 )

129 )

130

131

132 PHYSICAL_STRATEGIES_COMPOSITE: MappingProxyType[str, typing.Callable[..., FloatSt]] = ( (empty)

133 MappingProxyType(

134 {

135 "floe_length": floe_length,

136 "ice_density": ice_density,

137 "ice_thickness": ice_thickness,

138 }

139 )

140)

141