earthsciencekit 0.2.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.
- earthsciencekit/__init__.py +6 -0
- earthsciencekit/_validation.py +62 -0
- earthsciencekit/atmosphere/__init__.py +57 -0
- earthsciencekit/atmosphere/core/__init__.py +5 -0
- earthsciencekit/atmosphere/core/base.py +10 -0
- earthsciencekit/atmosphere/systems/__init__.py +1 -0
- earthsciencekit/atmosphere/systems/dynamics.py +208 -0
- earthsciencekit/atmosphere/systems/hydrostatics.py +214 -0
- earthsciencekit/atmosphere/systems/moisture.py +162 -0
- earthsciencekit/atmosphere/systems/thermodynamics.py +222 -0
- earthsciencekit/atmosphere/tests/__init__.py +0 -0
- earthsciencekit/atmosphere/tests/test_models.py +741 -0
- earthsciencekit/atmosphere/tests/test_physics.py +81 -0
- earthsciencekit/atmosphere/visualizers/__init__.py +9 -0
- earthsciencekit/climate/__init__.py +63 -0
- earthsciencekit/climate/core/__init__.py +5 -0
- earthsciencekit/climate/core/base.py +10 -0
- earthsciencekit/climate/systems/__init__.py +1 -0
- earthsciencekit/climate/systems/carbon.py +76 -0
- earthsciencekit/climate/systems/forcing.py +124 -0
- earthsciencekit/climate/systems/radiation.py +214 -0
- earthsciencekit/climate/systems/response.py +402 -0
- earthsciencekit/climate/systems/sea_level.py +77 -0
- earthsciencekit/climate/tests/__init__.py +0 -0
- earthsciencekit/climate/tests/test_models.py +1015 -0
- earthsciencekit/climate/tests/test_physics.py +16 -0
- earthsciencekit/climate/visualizers/__init__.py +9 -0
- earthsciencekit/constants/__init__.py +23 -0
- earthsciencekit/geophysics/__init__.py +77 -0
- earthsciencekit/geophysics/core/__init__.py +5 -0
- earthsciencekit/geophysics/core/base.py +10 -0
- earthsciencekit/geophysics/systems/__init__.py +1 -0
- earthsciencekit/geophysics/systems/deformation.py +161 -0
- earthsciencekit/geophysics/systems/dynamo.py +159 -0
- earthsciencekit/geophysics/systems/figure.py +292 -0
- earthsciencekit/geophysics/systems/gravity.py +235 -0
- earthsciencekit/geophysics/systems/magnetism.py +354 -0
- earthsciencekit/geophysics/tests/__init__.py +0 -0
- earthsciencekit/geophysics/tests/test_models.py +898 -0
- earthsciencekit/geophysics/tests/test_physics.py +171 -0
- earthsciencekit/geophysics/visualizers/__init__.py +9 -0
- earthsciencekit/integrators/__init__.py +62 -0
- earthsciencekit/oceanography/__init__.py +61 -0
- earthsciencekit/oceanography/core/__init__.py +5 -0
- earthsciencekit/oceanography/core/base.py +10 -0
- earthsciencekit/oceanography/systems/__init__.py +1 -0
- earthsciencekit/oceanography/systems/circulation.py +388 -0
- earthsciencekit/oceanography/systems/hydrography.py +212 -0
- earthsciencekit/oceanography/systems/inertial.py +86 -0
- earthsciencekit/oceanography/systems/waves.py +281 -0
- earthsciencekit/oceanography/tests/__init__.py +0 -0
- earthsciencekit/oceanography/tests/test_models.py +916 -0
- earthsciencekit/oceanography/tests/test_physics.py +102 -0
- earthsciencekit/oceanography/visualizers/__init__.py +9 -0
- earthsciencekit/plate_tectonics/__init__.py +59 -0
- earthsciencekit/plate_tectonics/core/__init__.py +5 -0
- earthsciencekit/plate_tectonics/core/base.py +10 -0
- earthsciencekit/plate_tectonics/systems/__init__.py +1 -0
- earthsciencekit/plate_tectonics/systems/boundaries.py +201 -0
- earthsciencekit/plate_tectonics/systems/cooling.py +238 -0
- earthsciencekit/plate_tectonics/systems/isostasy.py +157 -0
- earthsciencekit/plate_tectonics/systems/kinematics.py +290 -0
- earthsciencekit/plate_tectonics/tests/__init__.py +0 -0
- earthsciencekit/plate_tectonics/tests/test_models.py +920 -0
- earthsciencekit/plate_tectonics/tests/test_physics.py +94 -0
- earthsciencekit/plate_tectonics/visualizers/__init__.py +9 -0
- earthsciencekit/py.typed +0 -0
- earthsciencekit/results.py +73 -0
- earthsciencekit/seismology/__init__.py +59 -0
- earthsciencekit/seismology/core/__init__.py +5 -0
- earthsciencekit/seismology/core/base.py +10 -0
- earthsciencekit/seismology/systems/__init__.py +1 -0
- earthsciencekit/seismology/systems/interfaces.py +102 -0
- earthsciencekit/seismology/systems/rays.py +221 -0
- earthsciencekit/seismology/systems/sources.py +249 -0
- earthsciencekit/seismology/systems/waves.py +268 -0
- earthsciencekit/seismology/tests/__init__.py +0 -0
- earthsciencekit/seismology/tests/test_models.py +852 -0
- earthsciencekit/seismology/tests/test_physics.py +100 -0
- earthsciencekit/seismology/visualizers/__init__.py +9 -0
- earthsciencekit/tests/__init__.py +0 -0
- earthsciencekit/tests/test_core.py +181 -0
- earthsciencekit/tests/test_relations.py +36 -0
- earthsciencekit/units/__init__.py +66 -0
- earthsciencekit/visualizers/__init__.py +45 -0
- earthsciencekit/volcanology/__init__.py +61 -0
- earthsciencekit/volcanology/core/__init__.py +5 -0
- earthsciencekit/volcanology/core/base.py +10 -0
- earthsciencekit/volcanology/systems/__init__.py +1 -0
- earthsciencekit/volcanology/systems/eruptions.py +161 -0
- earthsciencekit/volcanology/systems/geochemistry.py +226 -0
- earthsciencekit/volcanology/systems/geochronology.py +304 -0
- earthsciencekit/volcanology/systems/magma.py +190 -0
- earthsciencekit/volcanology/tests/__init__.py +0 -0
- earthsciencekit/volcanology/tests/test_models.py +485 -0
- earthsciencekit/volcanology/tests/test_physics.py +176 -0
- earthsciencekit/volcanology/visualizers/__init__.py +9 -0
- earthsciencekit-0.2.0.dist-info/METADATA +127 -0
- earthsciencekit-0.2.0.dist-info/RECORD +102 -0
- earthsciencekit-0.2.0.dist-info/WHEEL +5 -0
- earthsciencekit-0.2.0.dist-info/licenses/LICENSE +15 -0
- earthsciencekit-0.2.0.dist-info/top_level.txt +1 -0
|
@@ -0,0 +1,162 @@
|
|
|
1
|
+
"""Moisture: saturation vapour pressure, mixing ratio, specific and relative humidity and virtual temperature.
|
|
2
|
+
|
|
3
|
+
SI units unless stated otherwise.
|
|
4
|
+
"""
|
|
5
|
+
|
|
6
|
+
import numpy as np
|
|
7
|
+
|
|
8
|
+
from earthsciencekit._validation import model, quantity, require
|
|
9
|
+
from earthsciencekit.constants import EPSILON_WATER, R_VAPOR
|
|
10
|
+
|
|
11
|
+
__all__ = [
|
|
12
|
+
"saturation_vapor_pressure",
|
|
13
|
+
"mixing_ratio",
|
|
14
|
+
"specific_humidity",
|
|
15
|
+
"virtual_temperature",
|
|
16
|
+
"relative_humidity",
|
|
17
|
+
]
|
|
18
|
+
|
|
19
|
+
|
|
20
|
+
@model
|
|
21
|
+
def saturation_vapor_pressure(temperature):
|
|
22
|
+
"""Integrated Clausius-Clapeyron approximation.
|
|
23
|
+
|
|
24
|
+
Phase equilibrium makes saturation vapor pressure strongly temperature dependent.
|
|
25
|
+
|
|
26
|
+
Parameters
|
|
27
|
+
----------
|
|
28
|
+
temperature : float or array_like
|
|
29
|
+
K; constraint: temperature.
|
|
30
|
+
|
|
31
|
+
Returns
|
|
32
|
+
-------
|
|
33
|
+
numpy scalar or ndarray
|
|
34
|
+
Model value [kg/m^3]. Scalar input returns a NumPy scalar; arrays broadcast.
|
|
35
|
+
|
|
36
|
+
Notes
|
|
37
|
+
-----
|
|
38
|
+
Liquid-water reference with constant latent heat; restricted to 180-330 K, not an ice saturation formula.
|
|
39
|
+
Equation: ``611.2 * np.exp((2.5e6 / R_VAPOR) * (1 / 273.15 - 1 / temperature))``.
|
|
40
|
+
Invalid, empty, nonreal or nonfinite inputs raise ValueError.
|
|
41
|
+
NumPy broadcasting applies; singular and overflowing outputs raise ValueError.
|
|
42
|
+
"""
|
|
43
|
+
temperature = quantity("temperature", temperature, lower=180, upper=330)
|
|
44
|
+
return 611.2 * np.exp((2.5e6 / R_VAPOR) * (1 / 273.15 - 1 / temperature))
|
|
45
|
+
|
|
46
|
+
|
|
47
|
+
@model
|
|
48
|
+
def mixing_ratio(vapor_pressure, total_pressure):
|
|
49
|
+
"""Water-vapor mass mixing ratio.
|
|
50
|
+
|
|
51
|
+
Partial pressure determines water mass per unit dry-air mass.
|
|
52
|
+
|
|
53
|
+
Parameters
|
|
54
|
+
----------
|
|
55
|
+
vapor_pressure : float or array_like
|
|
56
|
+
Pa; constraint: nonnegative.
|
|
57
|
+
total_pressure : float or array_like
|
|
58
|
+
Pa; constraint: positive.
|
|
59
|
+
|
|
60
|
+
Returns
|
|
61
|
+
-------
|
|
62
|
+
numpy scalar or ndarray
|
|
63
|
+
Model value [kg/m^3]. Scalar input returns a NumPy scalar; arrays broadcast.
|
|
64
|
+
|
|
65
|
+
Notes
|
|
66
|
+
-----
|
|
67
|
+
Ideal vapor mixture; vapor pressure must be below total pressure.
|
|
68
|
+
Equation: ``EPSILON_WATER * vapor_pressure / (total_pressure - vapor_pressure)``.
|
|
69
|
+
Invalid, empty, nonreal or nonfinite inputs raise ValueError.
|
|
70
|
+
NumPy broadcasting applies; singular and overflowing outputs raise ValueError.
|
|
71
|
+
"""
|
|
72
|
+
vapor_pressure = quantity("vapor_pressure", vapor_pressure, lower=0)
|
|
73
|
+
total_pressure = quantity("total_pressure", total_pressure, lower=0, strict_lower=True)
|
|
74
|
+
require(vapor_pressure < total_pressure, "vapor pressure must be below total pressure")
|
|
75
|
+
return EPSILON_WATER * vapor_pressure / (total_pressure - vapor_pressure)
|
|
76
|
+
|
|
77
|
+
|
|
78
|
+
@model
|
|
79
|
+
def specific_humidity(mixing_ratio):
|
|
80
|
+
"""Specific humidity from mixing ratio.
|
|
81
|
+
|
|
82
|
+
Changing the denominator connects two moisture conventions.
|
|
83
|
+
|
|
84
|
+
Parameters
|
|
85
|
+
----------
|
|
86
|
+
mixing_ratio : float or array_like
|
|
87
|
+
kg/kg dry air; constraint: nonnegative.
|
|
88
|
+
|
|
89
|
+
Returns
|
|
90
|
+
-------
|
|
91
|
+
numpy scalar or ndarray
|
|
92
|
+
Model value [kg/m^3]. Scalar input returns a NumPy scalar; arrays broadcast.
|
|
93
|
+
|
|
94
|
+
Notes
|
|
95
|
+
-----
|
|
96
|
+
Output is water mass per total moist-air mass.
|
|
97
|
+
Equation: ``mixing_ratio / (1 + mixing_ratio)``.
|
|
98
|
+
Invalid, empty, nonreal or nonfinite inputs raise ValueError.
|
|
99
|
+
NumPy broadcasting applies; singular and overflowing outputs raise ValueError.
|
|
100
|
+
"""
|
|
101
|
+
mixing_ratio = quantity("mixing_ratio", mixing_ratio, lower=0)
|
|
102
|
+
return mixing_ratio / (1 + mixing_ratio)
|
|
103
|
+
|
|
104
|
+
|
|
105
|
+
@model
|
|
106
|
+
def virtual_temperature(temperature, specific_humidity):
|
|
107
|
+
"""Virtual-temperature buoyancy correction.
|
|
108
|
+
|
|
109
|
+
Moist air is less dense than dry air at the same pressure and temperature.
|
|
110
|
+
|
|
111
|
+
Parameters
|
|
112
|
+
----------
|
|
113
|
+
temperature : float or array_like
|
|
114
|
+
K; constraint: positive.
|
|
115
|
+
specific_humidity : float or array_like
|
|
116
|
+
kg/kg moist air; constraint: fraction.
|
|
117
|
+
|
|
118
|
+
Returns
|
|
119
|
+
-------
|
|
120
|
+
numpy scalar or ndarray
|
|
121
|
+
Model value [kg/m^3]. Scalar input returns a NumPy scalar; arrays broadcast.
|
|
122
|
+
|
|
123
|
+
Notes
|
|
124
|
+
-----
|
|
125
|
+
Ideal vapor mixture without suspended liquid or ice.
|
|
126
|
+
Equation: ``temperature * (1 + (1 / EPSILON_WATER - 1) * specific_humidity)``.
|
|
127
|
+
Invalid, empty, nonreal or nonfinite inputs raise ValueError.
|
|
128
|
+
NumPy broadcasting applies; singular and overflowing outputs raise ValueError.
|
|
129
|
+
"""
|
|
130
|
+
temperature = quantity("temperature", temperature, lower=0, strict_lower=True)
|
|
131
|
+
specific_humidity = quantity("specific_humidity", specific_humidity, lower=0, upper=1)
|
|
132
|
+
return temperature * (1 + (1 / EPSILON_WATER - 1) * specific_humidity)
|
|
133
|
+
|
|
134
|
+
|
|
135
|
+
@model
|
|
136
|
+
def relative_humidity(vapor_pressure, saturation_pressure):
|
|
137
|
+
"""Relative humidity fraction.
|
|
138
|
+
|
|
139
|
+
Humidity compares actual vapor pressure to a saturation reference.
|
|
140
|
+
|
|
141
|
+
Parameters
|
|
142
|
+
----------
|
|
143
|
+
vapor_pressure : float or array_like
|
|
144
|
+
Pa; constraint: nonnegative.
|
|
145
|
+
saturation_pressure : float or array_like
|
|
146
|
+
Pa; constraint: positive.
|
|
147
|
+
|
|
148
|
+
Returns
|
|
149
|
+
-------
|
|
150
|
+
numpy scalar or ndarray
|
|
151
|
+
Model value [kg/m^3]. Scalar input returns a NumPy scalar; arrays broadcast.
|
|
152
|
+
|
|
153
|
+
Notes
|
|
154
|
+
-----
|
|
155
|
+
Returned fraction may exceed one during supersaturation; no clipping.
|
|
156
|
+
Equation: ``vapor_pressure / saturation_pressure``.
|
|
157
|
+
Invalid, empty, nonreal or nonfinite inputs raise ValueError.
|
|
158
|
+
NumPy broadcasting applies; singular and overflowing outputs raise ValueError.
|
|
159
|
+
"""
|
|
160
|
+
vapor_pressure = quantity("vapor_pressure", vapor_pressure, lower=0)
|
|
161
|
+
saturation_pressure = quantity("saturation_pressure", saturation_pressure, lower=0, strict_lower=True)
|
|
162
|
+
return vapor_pressure / saturation_pressure
|
|
@@ -0,0 +1,222 @@
|
|
|
1
|
+
"""Dry thermodynamics: potential temperature, the dry adiabat, static stability, the Richardson number and parcel ascent.
|
|
2
|
+
|
|
3
|
+
SI units unless stated otherwise.
|
|
4
|
+
"""
|
|
5
|
+
|
|
6
|
+
from earthsciencekit._validation import model, quantity, require, safe_arithmetic
|
|
7
|
+
from earthsciencekit.constants import CP_DRY_AIR, R_DRY_AIR
|
|
8
|
+
|
|
9
|
+
__all__ = [
|
|
10
|
+
"potential_temperature",
|
|
11
|
+
"temperature_from_potential",
|
|
12
|
+
"dry_adiabatic_lapse_rate",
|
|
13
|
+
"brunt_vaisala_squared",
|
|
14
|
+
"richardson_number",
|
|
15
|
+
"simulate_dry_ascent",
|
|
16
|
+
]
|
|
17
|
+
|
|
18
|
+
|
|
19
|
+
@model
|
|
20
|
+
def potential_temperature(temperature, pressure, reference_pressure):
|
|
21
|
+
"""Poisson potential temperature.
|
|
22
|
+
|
|
23
|
+
Adiabatic temperature adjustment permits comparisons across pressure levels.
|
|
24
|
+
|
|
25
|
+
Parameters
|
|
26
|
+
----------
|
|
27
|
+
temperature : float or array_like
|
|
28
|
+
K; constraint: positive.
|
|
29
|
+
pressure : float or array_like
|
|
30
|
+
Pa; constraint: positive.
|
|
31
|
+
reference_pressure : float or array_like
|
|
32
|
+
Pa; constraint: positive.
|
|
33
|
+
|
|
34
|
+
Returns
|
|
35
|
+
-------
|
|
36
|
+
numpy scalar or ndarray
|
|
37
|
+
Model value [kg/m^3]. Scalar input returns a NumPy scalar; arrays broadcast.
|
|
38
|
+
|
|
39
|
+
Notes
|
|
40
|
+
-----
|
|
41
|
+
Dry ideal gas with constant heat capacity; not equivalent potential temperature.
|
|
42
|
+
Equation: ``temperature * (reference_pressure / pressure)**(R_DRY_AIR / CP_DRY_AIR)``.
|
|
43
|
+
Invalid, empty, nonreal or nonfinite inputs raise ValueError.
|
|
44
|
+
NumPy broadcasting applies; singular and overflowing outputs raise ValueError.
|
|
45
|
+
"""
|
|
46
|
+
temperature = quantity("temperature", temperature, lower=0, strict_lower=True)
|
|
47
|
+
pressure = quantity("pressure", pressure, lower=0, strict_lower=True)
|
|
48
|
+
reference_pressure = quantity("reference_pressure", reference_pressure, lower=0, strict_lower=True)
|
|
49
|
+
return temperature * (reference_pressure / pressure) ** (R_DRY_AIR / CP_DRY_AIR)
|
|
50
|
+
|
|
51
|
+
|
|
52
|
+
@model
|
|
53
|
+
def temperature_from_potential(potential_temperature, pressure, reference_pressure):
|
|
54
|
+
"""Inverse potential temperature.
|
|
55
|
+
|
|
56
|
+
Potential-temperature inversion recovers the local dry-air temperature.
|
|
57
|
+
|
|
58
|
+
Parameters
|
|
59
|
+
----------
|
|
60
|
+
potential_temperature : float or array_like
|
|
61
|
+
K; constraint: positive.
|
|
62
|
+
pressure : float or array_like
|
|
63
|
+
Pa; constraint: positive.
|
|
64
|
+
reference_pressure : float or array_like
|
|
65
|
+
Pa; constraint: positive.
|
|
66
|
+
|
|
67
|
+
Returns
|
|
68
|
+
-------
|
|
69
|
+
numpy scalar or ndarray
|
|
70
|
+
Model value [kg/m^3]. Scalar input returns a NumPy scalar; arrays broadcast.
|
|
71
|
+
|
|
72
|
+
Notes
|
|
73
|
+
-----
|
|
74
|
+
Uses the same dry-air heat capacity and reference pressure convention.
|
|
75
|
+
Equation: ``potential_temperature * (pressure / reference_pressure)**(R_DRY_AIR / CP_DRY_AIR)``.
|
|
76
|
+
Invalid, empty, nonreal or nonfinite inputs raise ValueError.
|
|
77
|
+
NumPy broadcasting applies; singular and overflowing outputs raise ValueError.
|
|
78
|
+
"""
|
|
79
|
+
potential_temperature = quantity("potential_temperature", potential_temperature, lower=0, strict_lower=True)
|
|
80
|
+
pressure = quantity("pressure", pressure, lower=0, strict_lower=True)
|
|
81
|
+
reference_pressure = quantity("reference_pressure", reference_pressure, lower=0, strict_lower=True)
|
|
82
|
+
return potential_temperature * (pressure / reference_pressure) ** (R_DRY_AIR / CP_DRY_AIR)
|
|
83
|
+
|
|
84
|
+
|
|
85
|
+
@model
|
|
86
|
+
def dry_adiabatic_lapse_rate(gravity, heat_capacity):
|
|
87
|
+
"""Dry adiabatic lapse rate.
|
|
88
|
+
|
|
89
|
+
Rising dry parcels cool as they perform expansion work.
|
|
90
|
+
|
|
91
|
+
Parameters
|
|
92
|
+
----------
|
|
93
|
+
gravity : float or array_like
|
|
94
|
+
m/s^2; constraint: positive.
|
|
95
|
+
heat_capacity : float or array_like
|
|
96
|
+
J/(kg K); constraint: positive.
|
|
97
|
+
|
|
98
|
+
Returns
|
|
99
|
+
-------
|
|
100
|
+
numpy scalar or ndarray
|
|
101
|
+
Model value [kg/m^3]. Scalar input returns a NumPy scalar; arrays broadcast.
|
|
102
|
+
|
|
103
|
+
Notes
|
|
104
|
+
-----
|
|
105
|
+
Returned positive lapse magnitude in K per metre; temperature decreases upward.
|
|
106
|
+
Equation: ``gravity / heat_capacity``.
|
|
107
|
+
Invalid, empty, nonreal or nonfinite inputs raise ValueError.
|
|
108
|
+
NumPy broadcasting applies; singular and overflowing outputs raise ValueError.
|
|
109
|
+
"""
|
|
110
|
+
gravity = quantity("gravity", gravity, lower=0, strict_lower=True)
|
|
111
|
+
heat_capacity = quantity("heat_capacity", heat_capacity, lower=0, strict_lower=True)
|
|
112
|
+
return gravity / heat_capacity
|
|
113
|
+
|
|
114
|
+
|
|
115
|
+
@model
|
|
116
|
+
def brunt_vaisala_squared(potential_temperature, vertical_gradient, gravity):
|
|
117
|
+
"""Dry static stability.
|
|
118
|
+
|
|
119
|
+
A potential-temperature gradient determines dry stratification stability.
|
|
120
|
+
|
|
121
|
+
Parameters
|
|
122
|
+
----------
|
|
123
|
+
potential_temperature : float or array_like
|
|
124
|
+
K; constraint: positive.
|
|
125
|
+
vertical_gradient : float or array_like
|
|
126
|
+
K/m; constraint: real.
|
|
127
|
+
gravity : float or array_like
|
|
128
|
+
m/s^2; constraint: positive.
|
|
129
|
+
|
|
130
|
+
Returns
|
|
131
|
+
-------
|
|
132
|
+
numpy scalar or ndarray
|
|
133
|
+
Model value [kg/m^3]. Scalar input returns a NumPy scalar; arrays broadcast.
|
|
134
|
+
|
|
135
|
+
Notes
|
|
136
|
+
-----
|
|
137
|
+
Returns signed N squared; negative values represent instability rather than an imaginary frequency.
|
|
138
|
+
Equation: ``gravity * vertical_gradient / potential_temperature``.
|
|
139
|
+
Invalid, empty, nonreal or nonfinite inputs raise ValueError.
|
|
140
|
+
NumPy broadcasting applies; singular and overflowing outputs raise ValueError.
|
|
141
|
+
"""
|
|
142
|
+
potential_temperature = quantity("potential_temperature", potential_temperature, lower=0, strict_lower=True)
|
|
143
|
+
vertical_gradient = quantity("vertical_gradient", vertical_gradient)
|
|
144
|
+
gravity = quantity("gravity", gravity, lower=0, strict_lower=True)
|
|
145
|
+
return gravity * vertical_gradient / potential_temperature
|
|
146
|
+
|
|
147
|
+
|
|
148
|
+
@model
|
|
149
|
+
def richardson_number(brunt_vaisala_squared, shear):
|
|
150
|
+
"""Gradient Richardson number.
|
|
151
|
+
|
|
152
|
+
Stratification suppresses the turbulence that vertical wind shear generates.
|
|
153
|
+
|
|
154
|
+
Parameters
|
|
155
|
+
----------
|
|
156
|
+
brunt_vaisala_squared : float or array_like
|
|
157
|
+
1/s^2; constraint: real.
|
|
158
|
+
shear : float or array_like
|
|
159
|
+
1/s; constraint: nonzero.
|
|
160
|
+
|
|
161
|
+
Returns
|
|
162
|
+
-------
|
|
163
|
+
numpy scalar or ndarray
|
|
164
|
+
Model value [1]. Scalar input returns a NumPy scalar; arrays broadcast.
|
|
165
|
+
|
|
166
|
+
Notes
|
|
167
|
+
-----
|
|
168
|
+
Signed; stratified shear flow can become unstable only where it falls below 1/4 (Miles-Howard).
|
|
169
|
+
Equation: ``brunt_vaisala_squared / shear**2``.
|
|
170
|
+
Invalid, empty, nonreal or nonfinite inputs raise ValueError.
|
|
171
|
+
NumPy broadcasting applies; singular and overflowing outputs raise ValueError.
|
|
172
|
+
"""
|
|
173
|
+
brunt_vaisala_squared = quantity("brunt_vaisala_squared", brunt_vaisala_squared)
|
|
174
|
+
shear = quantity("shear", shear)
|
|
175
|
+
require(shear != 0, "shear must be nonzero")
|
|
176
|
+
return brunt_vaisala_squared / shear**2
|
|
177
|
+
|
|
178
|
+
|
|
179
|
+
@safe_arithmetic
|
|
180
|
+
def simulate_dry_ascent(initial_temperature, initial_pressure, vertical_speed, time):
|
|
181
|
+
"""Follow an ideal dry parcel along a hydrostatic constant-speed ascent.
|
|
182
|
+
|
|
183
|
+
Parameters
|
|
184
|
+
----------
|
|
185
|
+
initial_temperature : float
|
|
186
|
+
Positive scalar initial temperature [K].
|
|
187
|
+
initial_pressure : float
|
|
188
|
+
Positive scalar initial pressure [Pa].
|
|
189
|
+
vertical_speed : float
|
|
190
|
+
Finite scalar vertical velocity [m/s], positive upward.
|
|
191
|
+
time : array_like
|
|
192
|
+
Nonnegative strictly increasing sampled times [s].
|
|
193
|
+
|
|
194
|
+
Returns
|
|
195
|
+
-------
|
|
196
|
+
TimeSeries
|
|
197
|
+
Parcel temperature [K] and pressure [Pa].
|
|
198
|
+
|
|
199
|
+
Notes
|
|
200
|
+
-----
|
|
201
|
+
Dry lapse and hydrostatic pressure equations use constant standard gravity
|
|
202
|
+
and dry-air heat capacity. Potential temperature should remain constant.
|
|
203
|
+
The parcel is unsaturated; condensation and environmental entrainment are
|
|
204
|
+
excluded. Reject trajectories whose predicted temperature reaches zero.
|
|
205
|
+
"""
|
|
206
|
+
from earthsciencekit._validation import time_grid
|
|
207
|
+
from earthsciencekit.constants import GRAVITY
|
|
208
|
+
from earthsciencekit.integrators import integrate_ode
|
|
209
|
+
|
|
210
|
+
temperature = quantity("initial_temperature", initial_temperature, lower=0, strict_lower=True)
|
|
211
|
+
pressure = quantity("initial_pressure", initial_pressure, lower=0, strict_lower=True)
|
|
212
|
+
speed = quantity("vertical_speed", vertical_speed)
|
|
213
|
+
require(temperature.ndim == pressure.ndim == speed.ndim == 0, "parcel parameters must be scalars")
|
|
214
|
+
time = time_grid(time)
|
|
215
|
+
require(temperature - GRAVITY / CP_DRY_AIR * speed * (time[-1] - time[0]) > 0, "trajectory reaches nonpositive temperature")
|
|
216
|
+
return integrate_ode(
|
|
217
|
+
lambda t, y: [-GRAVITY / CP_DRY_AIR * speed, -GRAVITY * y[1] * speed / (R_DRY_AIR * y[0])],
|
|
218
|
+
[temperature, pressure],
|
|
219
|
+
time,
|
|
220
|
+
names=("temperature", "pressure"),
|
|
221
|
+
units=("K", "Pa"),
|
|
222
|
+
)
|
|
File without changes
|