tunax 0.1.0__py3-none-any.whl

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
tunax/__init__.py ADDED
@@ -0,0 +1,18 @@
1
+ """
2
+ Importation of Tunax classes and functions for shortcuts.
3
+ """
4
+
5
+
6
+ from .space import Grid, State, Trajectory
7
+ from .case import Case
8
+ from .closure import (
9
+ ClosureParametersAbstract, ClosureStateAbstract, Closure
10
+ )
11
+ from .database import Obs, Database
12
+ from .functions import tridiag_solve, add_boundaries
13
+ from .closures_registry import CLOSURES_REGISTRY
14
+ from .model import (
15
+ SingleColumnModel, step, lmd_swfrac, advance_tra_ed, advance_dyn_cor_ed,
16
+ diffusion_solver
17
+ )
18
+ from .fitter import FittableParameter, FittableParametersSet, Fitter
tunax/case.py ADDED
@@ -0,0 +1,282 @@
1
+ """
2
+ Physical parameters and forcings.
3
+
4
+ This module comes down to Case class. This class can be obtained by the prefix
5
+ :code:`tunax.case.` or directly by :code:`tunax.`.
6
+
7
+ """
8
+
9
+ from __future__ import annotations
10
+
11
+ import equinox as eqx
12
+ import jax.numpy as jnp
13
+ from jax import device_get
14
+
15
+
16
+ _OMEGA = 7.292116e-05
17
+ """float: Rotation rate of the Earth [rad.s-1]."""
18
+ _RAD_DEG = jnp.pi/180.
19
+ """float: Measure of one degree in radiant [rad.°-1]."""
20
+
21
+
22
+ class Case(eqx.Module):
23
+ r"""
24
+ Physical parameters and forcings.
25
+
26
+ This class contains all the physical constants, and the constant forcings
27
+ that definine an experience for the model.
28
+
29
+ Parameters
30
+ ----------
31
+ rho0 : float, default=1024.
32
+ cf. attribute.
33
+ grav : float, default=9.81
34
+ cf. attribute.
35
+ cp : float, default=3985.
36
+ cf. attribute.
37
+ alpha : float, default=2e-4
38
+ cf. attribute.
39
+ beta : float, default=8e-4
40
+ cf. attribute.
41
+ t_rho_ref : float, default=0.
42
+ cf. attribute.
43
+ s_rho_ref : float, default=35.
44
+ cf. attribute.
45
+ vkarmn : float, default=0.384
46
+ cf. attribute.
47
+ fcor : float, default=0.
48
+ cf. attribute.
49
+ ustr_sfc : float, default=0.
50
+ cf. attribute.
51
+ ustr_btm : float, default=0.
52
+ cf. attribute.
53
+ vstr_sfc : float, default=0.
54
+ cf. attribute.
55
+ vstr_btm : float, default=0.
56
+ cf. attribute.
57
+ tflx_sfc : float, default=0.
58
+ cf. attribute.
59
+ tflx_btm : float, default=0.
60
+ cf. attribute.
61
+ sflx_sfc : float, default=0.
62
+ cf. attribute.
63
+ sflx_btm : float, default=0.
64
+ cf. attribute.
65
+ rflx_sfc_max : float, default=0.
66
+ cf. attribute.
67
+
68
+ Attributes
69
+ ----------
70
+ rho0 : float, default=1024.
71
+ Default density of saltwater :math:`[\text{kg} \cdot \text{m}^{-3}]`.
72
+ grav : float, default=9.81
73
+ Gravity acceleration :math:`[\text{m} \cdot \text{s}^{-2}]`.
74
+ cp : float, default=3985.
75
+ Specific heat capacity of saltwater
76
+ :math:`[\text{J} \cdot \text{kg}^{-1} \cdot \text{K}^{-1}]`.
77
+ alpha : float, default=2e-4
78
+ Thermal expansion coefficient :math:`[\text{K}^{-1}]`.
79
+ beta : float, default=8e-4
80
+ Salinity expansion coefficient :math:`[\text{psu}^{-1}]`.
81
+ t_rho_ref : float, default=0.
82
+ Reference temperature for the density computation :math:`[° \text C]`.
83
+ s_rho_ref : float, default=35.
84
+ Reference salinity for the density computation :math:`[\text{psu}]`.
85
+ vkarmn : float, default=0.384
86
+ Von Kármán constant :math:`[\text{dimensionless}]`.
87
+ fcor : float, default=0.
88
+ Coriolis frequency at the water column
89
+ :math:`[\text{rad} \cdot \text{s}^{-1}]`.
90
+ ustr_sfc : float, default=0.
91
+ Zonal wind stress :math:`[\text{m}^{2} \cdot \text{s}^{-2}]`.
92
+ ustr_btm : float, default=0.
93
+ Zonal current stress at the bottom
94
+ :math:`[\text{m}^{2} \cdot \text{s}^{-2}]`.
95
+ vstr_sfc : float, default=0.
96
+ Meridional wind stress :math:`[\text{m}^{2} \cdot \text{s}^{-2}]`.
97
+ vstr_btm : float, default=0.
98
+ Meridional current stress at the bottom
99
+ :math:`[\text{m}^{2} \cdot \text{s}^{-2}]`.
100
+ tflx_sfc : float, default=0.
101
+ Non-penetrative heat flux at the surface
102
+ :math:`[\text{K} \cdot \text{m} \cdot \text{s}^{-1}]`.
103
+ tflx_btm : float, default=0.
104
+ Non-penetrative heat flux at the bottom
105
+ :math:`[\text{K} \cdot \text{m} \cdot \text{s}^{-1}]`.
106
+ sflx_sfc : float, default=0.
107
+ Fresh water flux at the surface
108
+ :math:`[\text{psu} \cdot \text{m} \cdot \text{s}^{-1}]`.
109
+ sflx_btm : float, default=0.
110
+ Fresh water flux at the bottom
111
+ :math:`[\text{psu} \cdot \text{m} \cdot \text{s}^{-1}]`.
112
+ rflx_sfc_max : float, default=0.
113
+ Maximum solar radiation flux at the surface
114
+ :math:`[\text{K} \cdot \text{m} \cdot \text{s}^{-1}]`.
115
+
116
+ """
117
+
118
+ # physcal constants
119
+ rho0: float = 1024.
120
+ grav: float = 9.81
121
+ cp: float = 3985.
122
+ alpha: float = 2e-4
123
+ beta: float = 8e-4
124
+ t_rho_ref: float = 0.
125
+ s_rho_ref: float = 35.
126
+ vkarmn: float = 0.384
127
+ #forcings
128
+ fcor: float = 0.
129
+ ustr_sfc: float = 0.
130
+ ustr_btm: float = 0.
131
+ vstr_sfc: float = 0.
132
+ vstr_btm: float = 0.
133
+ tflx_sfc: float = 0.
134
+ tflx_btm: float = 0.
135
+ sflx_sfc: float = 0.
136
+ sflx_btm: float = 0.
137
+ rflx_sfc_max: float = 0.
138
+
139
+ def set_lat(self, lat: float) -> Case:
140
+ """
141
+ Set the Coriolis frequency from the latitude.
142
+
143
+ Parameters
144
+ ----------
145
+ lat : float
146
+ Latitude of the water column :math:`[°]`.
147
+
148
+ Returns
149
+ -------
150
+ case : Case
151
+ The :code:`self` object with the the new value of :attr:`fcor`.
152
+ """
153
+ fcor = float(device_get(2.*_OMEGA*jnp.sin(_RAD_DEG*lat)))
154
+ print(type(fcor))
155
+ print(fcor)
156
+ case = eqx.tree_at(lambda t: t.fcor, self, fcor)
157
+ return case
158
+
159
+ def set_u_wind(self, u_wind: float) -> Case:
160
+ r"""
161
+ Set the zonal wind stress with the zonal wind speed.
162
+
163
+ Parameters
164
+ ----------
165
+ u_wind : float
166
+ Zonal wind speed :math:`[\text m \cdot \text s ^{-1}]`.
167
+
168
+ Returns
169
+ -------
170
+ case : Case
171
+ The :code:`self` object with the new value of :attr:`ustr_sfc`.
172
+ """
173
+ case = eqx.tree_at(lambda t: t.ustr_sfc, self, u_wind**2)
174
+ return case
175
+
176
+ def set_u_cur(self, u_cur: float) -> Case:
177
+ r"""
178
+ Set the zonal current stress with the zonal current.
179
+
180
+ Parameters
181
+ ----------
182
+ u_cur : float
183
+ Zonal current speed :math:`[\text m \cdot \text s ^{-1}]`.
184
+
185
+ Returns
186
+ -------
187
+ case : Case
188
+ The :code:`self` object with the new value of :attr:`ustr_btm`.
189
+ """
190
+ case = eqx.tree_at(lambda t: t.ustr_btm, self, u_cur**2)
191
+ return case
192
+
193
+ def set_v_wind(self, v_wind: float) -> Case:
194
+ r"""
195
+ Set the meridional wind stress with the meridional wind.
196
+
197
+ Parameters
198
+ ----------
199
+ v_wind : float
200
+ Meridional wind speed :math:`[\text m \cdot \text s ^{-1}]`.
201
+
202
+ Returns
203
+ -------
204
+ case : Case
205
+ The :code:`self` object with the new value of :attr:`vstr_sfc`.
206
+ """
207
+ case = eqx.tree_at(lambda t: t.vstr_sfc, self, v_wind**2)
208
+ return case
209
+
210
+ def set_v_cur(self, v_cur: float) -> Case:
211
+ r"""
212
+ Set the meridional current stress with the meridional current.
213
+
214
+ Parameters
215
+ ----------
216
+ v_cur : float
217
+ Meridional current speed :math:`[\text m \cdot \text s ^{-1}]`.
218
+
219
+ Returns
220
+ -------
221
+ case : Case
222
+ The :code:`self` object with the new value of :attr:`vstr_btm`.
223
+ """
224
+ case = eqx.tree_at(lambda t: t.vstr_btm, self, v_cur**2)
225
+ return case
226
+
227
+ def set_tpw_sfc(self, tpw_sfc: float) -> Case:
228
+ r"""
229
+ Set the heat flux at surface from the heat power.
230
+
231
+ Parameters
232
+ ----------
233
+ tpw_sfc : float
234
+ Non-penetrative heat power at the surface
235
+ :math:`[\text W \cdot \text m ^{-2}]`.
236
+
237
+ Returns
238
+ -------
239
+ case : Case
240
+ The :code:`self` object with the new value of :attr:`tflx_sfc`.
241
+ """
242
+ tflx_sfc = tpw_sfc/(self.rho0*self.cp)
243
+ case = eqx.tree_at(lambda t: t.tflx_sfc, self, tflx_sfc)
244
+ return case
245
+
246
+ def set_tpw_btm(self, tpw_btm: float) -> Case:
247
+ r"""
248
+ Set the heat flux at bottom from the heat power.
249
+
250
+ Parameters
251
+ ----------
252
+ tpw_btm : float
253
+ Non-penetrative heat power at the bottom
254
+ :math:`[\text W \cdot \text m ^{-2}]`.
255
+
256
+ Returns
257
+ -------
258
+ case : Case
259
+ The :code:`self` object with the new value of :attr:`tflx_btm`.
260
+ """
261
+ tflx_btm = tpw_btm/(self.rho0*self.cp)
262
+ case = eqx.tree_at(lambda t: t.tflx_btm, self, tflx_btm)
263
+ return case
264
+
265
+ def set_rpw_sfc_max(self, rpw_sfc_max: float) -> Case:
266
+ r"""
267
+ Set the maximum solar radiation from the solar power
268
+
269
+ Parameters
270
+ ----------
271
+ rpw_sfc_max : float
272
+ Maximum solar radiation power at the surface (penetrative)
273
+ :math:`[\text W \cdot \text m ^{-2}]`.
274
+
275
+ Returns
276
+ -------
277
+ case : Case
278
+ The :code:`self` object with the new value of :attr:`rflx_sfc_max`.
279
+ """
280
+ rflx_sfc_max = rpw_sfc_max/(self.rho0*self.cp)
281
+ case = eqx.tree_at(lambda t: t.rflx_sfc_max, self, rflx_sfc_max)
282
+ return case
tunax/closure.py ADDED
@@ -0,0 +1,165 @@
1
+ """
2
+ Abstractions for defining closures.
3
+
4
+ A closure is a a set of physical equations which determines the sub-mesh
5
+ turbulence of the water column at a specific time. The purpose of Tunax is to
6
+ calibrate the parameters of these equations. This module contains the abstract
7
+ classes required to define a closure, which is done in the folder
8
+ :code:`closures/`. These classes can be obtained by the prefix
9
+ :code:`tunax.closure.` or directly by :code:`tunax.`.
10
+
11
+ """
12
+
13
+ from abc import ABC
14
+ from typing import Callable, Type, TypeVar, Generic
15
+
16
+ import equinox as eqx
17
+ from jaxtyping import Float, Array
18
+
19
+ from tunax.case import Case
20
+ from tunax.space import Grid, State
21
+
22
+
23
+ class ClosureParametersAbstract(eqx.Module, ABC):
24
+ """
25
+ Abstraction for the parameters of a closure.
26
+
27
+ To define a closure, a class that inherits from this one must be created.
28
+ This parent class does not impose anything on the child one. The child
29
+ class should be fill of the parameters involved in the closure which may be
30
+ calibrated. The child class must be the only place where these parameters
31
+ are defined for running a forward model : the instance of this class is
32
+ given to the closure functions to recover the parameters and do the
33
+ computation. For a run of a calibration, the description of the parameters
34
+ to calibration is done from the child class. It can also includes
35
+ parameters that are not dedicated to be calibrated such as physical or
36
+ mathematical constants. The attributes of this class can be used to avoid
37
+ the systematic computation of some values which are independent of the time
38
+ (eg. k-epsilon with the method :code:`__post_init__`).
39
+
40
+ """
41
+
42
+
43
+ # variable that represent a type which contains ClosureParametersAbstract and
44
+ # all its subclasses
45
+ CloParT = TypeVar('CloParT', bound=ClosureParametersAbstract)
46
+
47
+
48
+ class ClosureStateAbstract(eqx.Module, ABC):
49
+ r"""
50
+ Abstraction for the water column state linked to the closure.
51
+
52
+ To define a closure, a class that inherits rom this one must be created.
53
+ This parent class imposes a grid and three variables as attributes : these
54
+ variables are used at each step of the forward model to compute the next
55
+ step of tracers and momentum. The child class should be fill with other
56
+ arrays and scalars that may evolve throught time and necessary for the
57
+ computation of the closure at the next step. The child class is similary
58
+ to the :class:`~space.State` class but for the diffusivity part.
59
+ The :code:`__init__` method can be overwrited to fill the variables with
60
+ initial values.
61
+
62
+ Parameters
63
+ ----------
64
+ grid : Grid
65
+ cf. attribute.
66
+ akt : Float[~jax.Array, 'nz+1']
67
+ cf. attribute.
68
+ akv : Float[~jax.Array, 'nz+1']
69
+ cf. attribute.
70
+
71
+ Attributes
72
+ ----------
73
+ grid : Grid
74
+ Geometry of the water column, should be the same than for the
75
+ :class:`~space.State` instance used in the model.
76
+ akt : Float[~jax.Array, 'nz+1']
77
+ Eddy-diffusivity on the interfaces of the cells
78
+ :math:`\left[\text m ^2 \cdot \text s ^{-1}\right]`.
79
+ akv : Float[~jax.Array, 'nz+1']
80
+ Eddy-viscosity on the interfaces of the cells
81
+ :math:`\left[\text m ^2 \cdot \text s ^{-1}\right]`.
82
+
83
+ """
84
+
85
+ grid: Grid
86
+ akt: Float[Array, 'nz+1']
87
+ akv: Float[Array, 'nz+1']
88
+
89
+
90
+ # variable that represent a type which contains ClosureStateAbstract and
91
+ # all its subclasses
92
+ CloStateT = TypeVar('CloStateT', bound=ClosureStateAbstract)
93
+
94
+
95
+ class Closure(eqx.Module, Generic[CloStateT, CloParT]):
96
+ r"""
97
+ Implementation of a physical closure for computing eddy-diffusivity.
98
+
99
+ This class contains the three parts that defines a closure of a vertical
100
+ physics. These parts will be used in the model to compute the eddy-
101
+ diffusivity and eddy-viscosity at each time-step from the current water
102
+ column :class:`~space.State`, the current water column state of the
103
+ closure (child class of :class:`~ClosureStateAbstract`), the physical
104
+ :class:`~case.Case` and the closure parameters (child class of
105
+ :class:`~ClosureParametersAbstract`).
106
+
107
+ Parameters
108
+ ----------
109
+ name : str
110
+ cf. attribute.
111
+ parameters_class : Type[ClosureParametersAbstract]
112
+ cf. attribute.
113
+ state_class : Type[ClosureStateAbstract]
114
+ cf. attribute.
115
+ step_fun : Callable[[State, CloStateT, float, CloParT, Case], CloStateT]
116
+ cf. attribute.
117
+
118
+ Attributes
119
+ ----------
120
+ name : str
121
+ The name of the closure.
122
+ parameters_class : Type[ClosureParametersAbstract]
123
+ A child class of :class:`~ClosureParametersAbstract` that defines the
124
+ constant parameters used in the computation done by the closure, it
125
+ includes the parameters that may be calibrated.
126
+ state_class : Type[ClosureStateAbstract]
127
+ A child class of :class:`~ClosureStateAbstract` that defines the state
128
+ of the water column for the variables used by the closure computation.
129
+ step_fun : Callable[[State, CloStateT, float, CloParT, Case], CloStateT]
130
+ Ths function is called at every step of the forward model to compute
131
+ the eddy-diffusivity before resolving the equation of the tracers and
132
+ of the momentum.
133
+
134
+ Parameters
135
+ ----------
136
+ state : State
137
+ Current state of the water column.
138
+ closure_state : CloStateT
139
+ Current state of the water column for the variables used by the
140
+ closure.
141
+ dt : float
142
+ Time-step of the forward model :math:`[\text s]`.
143
+ closure_params : CloParT
144
+ Values of the parameters used by the closure (time-independant).
145
+ case : Case
146
+ Physical parameters and forcings of the model run.
147
+
148
+ Returns
149
+ -------
150
+ closure_state : CloStateT
151
+ State of the water column for the variables used by the
152
+ closure at the next time-step.
153
+
154
+ Notes
155
+ -----
156
+ :code:`CloStateT` is the type reprensenting the instances of the child
157
+ classes of :class:`~ClosureStateAbstract` and :code:`CloParT` is the
158
+ same for :class:`~ClosureParametersAbstract`.
159
+
160
+ """
161
+
162
+ name : str
163
+ parameters_class: Type[ClosureParametersAbstract]
164
+ state_class: Type[ClosureStateAbstract]
165
+ step_fun: Callable[[State, CloStateT, float, CloParT, Case], CloStateT]
@@ -0,0 +1,6 @@
1
+ """
2
+ Importation of Tunax classes and functions of closures for shortcuts.
3
+ """
4
+
5
+
6
+ from .k_epsilon import KepsParameters, KepsState, keps_step