disdrodb 0.1.2__py3-none-any.whl → 0.1.4__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.
- disdrodb/__init__.py +68 -34
- disdrodb/_config.py +5 -4
- disdrodb/_version.py +16 -3
- disdrodb/accessor/__init__.py +20 -0
- disdrodb/accessor/methods.py +125 -0
- disdrodb/api/checks.py +177 -24
- disdrodb/api/configs.py +3 -3
- disdrodb/api/info.py +13 -13
- disdrodb/api/io.py +281 -22
- disdrodb/api/path.py +184 -195
- disdrodb/api/search.py +18 -9
- disdrodb/cli/disdrodb_create_summary.py +103 -0
- disdrodb/cli/disdrodb_create_summary_station.py +91 -0
- disdrodb/cli/disdrodb_run_l0.py +1 -1
- disdrodb/cli/disdrodb_run_l0_station.py +1 -1
- disdrodb/cli/disdrodb_run_l0a_station.py +1 -1
- disdrodb/cli/disdrodb_run_l0b.py +1 -1
- disdrodb/cli/disdrodb_run_l0b_station.py +3 -3
- disdrodb/cli/disdrodb_run_l0c.py +1 -1
- disdrodb/cli/disdrodb_run_l0c_station.py +3 -3
- disdrodb/cli/disdrodb_run_l1_station.py +2 -2
- disdrodb/cli/disdrodb_run_l2e_station.py +2 -2
- disdrodb/cli/disdrodb_run_l2m_station.py +2 -2
- disdrodb/configs.py +149 -4
- disdrodb/constants.py +61 -0
- disdrodb/data_transfer/download_data.py +127 -11
- disdrodb/etc/configs/attributes.yaml +339 -0
- disdrodb/etc/configs/encodings.yaml +473 -0
- disdrodb/etc/products/L1/global.yaml +13 -0
- disdrodb/etc/products/L2E/10MIN.yaml +12 -0
- disdrodb/etc/products/L2E/1MIN.yaml +1 -0
- disdrodb/etc/products/L2E/global.yaml +22 -0
- disdrodb/etc/products/L2M/10MIN.yaml +12 -0
- disdrodb/etc/products/L2M/GAMMA_ML.yaml +8 -0
- disdrodb/etc/products/L2M/NGAMMA_GS_LOG_ND_MAE.yaml +6 -0
- disdrodb/etc/products/L2M/NGAMMA_GS_ND_MAE.yaml +6 -0
- disdrodb/etc/products/L2M/NGAMMA_GS_Z_MAE.yaml +6 -0
- disdrodb/etc/products/L2M/global.yaml +26 -0
- disdrodb/issue/writer.py +2 -0
- disdrodb/l0/__init__.py +13 -0
- disdrodb/l0/configs/LPM/l0b_cf_attrs.yml +4 -4
- disdrodb/l0/configs/PARSIVEL/l0b_cf_attrs.yml +1 -1
- disdrodb/l0/configs/PARSIVEL/l0b_encodings.yml +3 -3
- disdrodb/l0/configs/PARSIVEL/raw_data_format.yml +1 -1
- disdrodb/l0/configs/PARSIVEL2/l0b_cf_attrs.yml +5 -5
- disdrodb/l0/configs/PARSIVEL2/l0b_encodings.yml +3 -3
- disdrodb/l0/configs/PARSIVEL2/raw_data_format.yml +1 -1
- disdrodb/l0/configs/PWS100/l0b_cf_attrs.yml +4 -4
- disdrodb/l0/configs/PWS100/raw_data_format.yml +1 -1
- disdrodb/l0/l0a_processing.py +37 -32
- disdrodb/l0/l0b_nc_processing.py +118 -8
- disdrodb/l0/l0b_processing.py +30 -65
- disdrodb/l0/l0c_processing.py +369 -259
- disdrodb/l0/readers/LPM/ARM/ARM_LPM.py +7 -0
- disdrodb/l0/readers/LPM/NETHERLANDS/DELFT_LPM_NC.py +66 -0
- disdrodb/l0/readers/LPM/SLOVENIA/{CRNI_VRH.py → UL.py} +3 -0
- disdrodb/l0/readers/LPM/SWITZERLAND/INNERERIZ_LPM.py +195 -0
- disdrodb/l0/readers/PARSIVEL/GPM/PIERS.py +0 -2
- disdrodb/l0/readers/PARSIVEL/JAPAN/JMA.py +4 -1
- disdrodb/l0/readers/PARSIVEL/NCAR/PECAN_MOBILE.py +1 -1
- disdrodb/l0/readers/PARSIVEL/NCAR/VORTEX2_2009.py +1 -1
- disdrodb/l0/readers/PARSIVEL2/ARM/ARM_PARSIVEL2.py +4 -0
- disdrodb/l0/readers/PARSIVEL2/BELGIUM/ILVO.py +168 -0
- disdrodb/l0/readers/PARSIVEL2/CANADA/UQAM_NC.py +69 -0
- disdrodb/l0/readers/PARSIVEL2/DENMARK/DTU.py +165 -0
- disdrodb/l0/readers/PARSIVEL2/FINLAND/FMI_PARSIVEL2.py +69 -0
- disdrodb/l0/readers/PARSIVEL2/FRANCE/ENPC_PARSIVEL2.py +255 -134
- disdrodb/l0/readers/PARSIVEL2/FRANCE/OSUG.py +525 -0
- disdrodb/l0/readers/PARSIVEL2/FRANCE/SIRTA_PARSIVEL2.py +1 -1
- disdrodb/l0/readers/PARSIVEL2/GPM/GCPEX.py +9 -7
- disdrodb/l0/readers/PARSIVEL2/KIT/BURKINA_FASO.py +1 -1
- disdrodb/l0/readers/PARSIVEL2/KIT/TEAMX.py +123 -0
- disdrodb/l0/readers/PARSIVEL2/{NETHERLANDS/DELFT.py → MPI/BCO_PARSIVEL2.py} +41 -71
- disdrodb/l0/readers/PARSIVEL2/MPI/BOWTIE.py +220 -0
- disdrodb/l0/readers/PARSIVEL2/NASA/APU.py +120 -0
- disdrodb/l0/readers/PARSIVEL2/NASA/LPVEX.py +109 -0
- disdrodb/l0/readers/PARSIVEL2/NCAR/FARM_PARSIVEL2.py +1 -0
- disdrodb/l0/readers/PARSIVEL2/NCAR/PECAN_FP3.py +1 -1
- disdrodb/l0/readers/PARSIVEL2/NCAR/PERILS_MIPS.py +126 -0
- disdrodb/l0/readers/PARSIVEL2/NCAR/PERILS_PIPS.py +165 -0
- disdrodb/l0/readers/PARSIVEL2/NCAR/VORTEX_SE_2016_P2.py +1 -1
- disdrodb/l0/readers/PARSIVEL2/NCAR/VORTEX_SE_2016_PIPS.py +20 -12
- disdrodb/l0/readers/PARSIVEL2/NETHERLANDS/DELFT_NC.py +5 -0
- disdrodb/l0/readers/PARSIVEL2/SPAIN/CENER.py +144 -0
- disdrodb/l0/readers/PARSIVEL2/SPAIN/CR1000DL.py +201 -0
- disdrodb/l0/readers/PARSIVEL2/SPAIN/LIAISE.py +137 -0
- disdrodb/l0/readers/PARSIVEL2/USA/C3WE.py +146 -0
- disdrodb/l0/readers/PWS100/FRANCE/ENPC_PWS100.py +105 -99
- disdrodb/l0/readers/PWS100/FRANCE/ENPC_PWS100_SIRTA.py +151 -0
- disdrodb/l1/__init__.py +5 -0
- disdrodb/l1/fall_velocity.py +46 -0
- disdrodb/l1/filters.py +34 -20
- disdrodb/l1/processing.py +46 -45
- disdrodb/l1/resampling.py +77 -66
- disdrodb/l1_env/routines.py +18 -3
- disdrodb/l2/__init__.py +7 -0
- disdrodb/l2/empirical_dsd.py +58 -10
- disdrodb/l2/processing.py +268 -117
- disdrodb/metadata/checks.py +132 -125
- disdrodb/metadata/standards.py +3 -1
- disdrodb/psd/fitting.py +631 -345
- disdrodb/psd/models.py +9 -6
- disdrodb/routines/__init__.py +54 -0
- disdrodb/{l0/routines.py → routines/l0.py} +316 -355
- disdrodb/{l1/routines.py → routines/l1.py} +76 -116
- disdrodb/routines/l2.py +1019 -0
- disdrodb/{routines.py → routines/wrappers.py} +98 -10
- disdrodb/scattering/__init__.py +16 -4
- disdrodb/scattering/axis_ratio.py +61 -37
- disdrodb/scattering/permittivity.py +504 -0
- disdrodb/scattering/routines.py +746 -184
- disdrodb/summary/__init__.py +17 -0
- disdrodb/summary/routines.py +4196 -0
- disdrodb/utils/archiving.py +434 -0
- disdrodb/utils/attrs.py +68 -125
- disdrodb/utils/cli.py +5 -5
- disdrodb/utils/compression.py +30 -1
- disdrodb/utils/dask.py +121 -9
- disdrodb/utils/dataframe.py +61 -7
- disdrodb/utils/decorators.py +31 -0
- disdrodb/utils/directories.py +35 -15
- disdrodb/utils/encoding.py +37 -19
- disdrodb/{l2 → utils}/event.py +15 -173
- disdrodb/utils/logger.py +14 -7
- disdrodb/utils/manipulations.py +81 -0
- disdrodb/utils/routines.py +166 -0
- disdrodb/utils/subsetting.py +214 -0
- disdrodb/utils/time.py +35 -177
- disdrodb/utils/writer.py +20 -7
- disdrodb/utils/xarray.py +5 -4
- disdrodb/viz/__init__.py +13 -0
- disdrodb/viz/plots.py +398 -0
- {disdrodb-0.1.2.dist-info → disdrodb-0.1.4.dist-info}/METADATA +4 -3
- {disdrodb-0.1.2.dist-info → disdrodb-0.1.4.dist-info}/RECORD +139 -98
- {disdrodb-0.1.2.dist-info → disdrodb-0.1.4.dist-info}/entry_points.txt +2 -0
- disdrodb/l1/encoding_attrs.py +0 -642
- disdrodb/l2/processing_options.py +0 -213
- disdrodb/l2/routines.py +0 -868
- /disdrodb/l0/readers/PARSIVEL/SLOVENIA/{UL_FGG.py → UL.py} +0 -0
- {disdrodb-0.1.2.dist-info → disdrodb-0.1.4.dist-info}/WHEEL +0 -0
- {disdrodb-0.1.2.dist-info → disdrodb-0.1.4.dist-info}/licenses/LICENSE +0 -0
- {disdrodb-0.1.2.dist-info → disdrodb-0.1.4.dist-info}/top_level.txt +0 -0
|
@@ -0,0 +1,504 @@
|
|
|
1
|
+
# -----------------------------------------------------------------------------.
|
|
2
|
+
# Copyright (c) 2021-2023 DISDRODB developers
|
|
3
|
+
#
|
|
4
|
+
# temperaturehis program is free software: you can redistribute it and/or modify
|
|
5
|
+
# it under the terms of the GNU General Public License as published by
|
|
6
|
+
# the Free Software Foundation, either version 3 of the License, or
|
|
7
|
+
# (at your option) any later version.
|
|
8
|
+
#
|
|
9
|
+
# temperaturehis program is distributed in the hope that it will be useful,
|
|
10
|
+
# but WItemperatureHOUtemperature ANY WARRANtemperatureY; without even the implied warranty of
|
|
11
|
+
# MERCHANtemperatureABILItemperatureY or FItemperatureNESS FOR A PARtemperatureICULAR PURPOSE. See the
|
|
12
|
+
# GNU General Public License for more details.
|
|
13
|
+
#
|
|
14
|
+
# You should have received a copy of the GNU General Public License
|
|
15
|
+
# along with this program. If not, see <http://www.gnu.org/licenses/>.
|
|
16
|
+
# -----------------------------------------------------------------------------.
|
|
17
|
+
"""Implement particle permittivity models."""
|
|
18
|
+
import numpy as np
|
|
19
|
+
import xarray as xr
|
|
20
|
+
|
|
21
|
+
# Definitions
|
|
22
|
+
# - Complex_refractive_index: m
|
|
23
|
+
# - Complex dielectric constant = complex relative permittivity: eps
|
|
24
|
+
# - Rayleigh dielectric factor: Kw_sqr
|
|
25
|
+
|
|
26
|
+
# Other useful codes for ice/snow future extension:
|
|
27
|
+
# - pytmatrix: https://github.com/ltelab/pytmatrix-lte/blob/main/pytmatrix/refractive.py#L66
|
|
28
|
+
# - pyradsim: https://github.com/wolfidan/pyradsim/blob/master/pyradsim/permittivity_models.py
|
|
29
|
+
# - cosmo_pol: https://github.com/wolfidan/cosmo_pol/blob/master/cosmo_pol/hydrometeors/dielectric.py#L49
|
|
30
|
+
# - m_func for snow, melting: https://github.com/wolfidan/cosmo_pol/blob/master/cosmo_pol/hydrometeors/hydrometeors.py#L544
|
|
31
|
+
|
|
32
|
+
####-------------------------------------------------------------------------------------.
|
|
33
|
+
#### Wrappers
|
|
34
|
+
|
|
35
|
+
|
|
36
|
+
def available_permittivity_models():
|
|
37
|
+
"""Return a list of the available raindrops complex refractive index models."""
|
|
38
|
+
return list(REFRACTIVE_INDEX_MODELS)
|
|
39
|
+
|
|
40
|
+
|
|
41
|
+
def get_refractive_index_function(permittivity_model):
|
|
42
|
+
"""Return the specified model estimating the complex refractive index of rain drops.
|
|
43
|
+
|
|
44
|
+
The complex refractive index of a hydrometeor (e.g., water droplet, ice particle, graupel)
|
|
45
|
+
governs how radar waves interact with it.
|
|
46
|
+
The real part determines how much the radar wave slows down inside the particle (phase shift)
|
|
47
|
+
The imaginary part determines how much the radar wave is absorbed and attenuated by the particle
|
|
48
|
+
The imaginary part thus describes how much energy is lost as the wave travels through the particle.
|
|
49
|
+
The imaginary part thus controls radar attenuation and depolarization effects.
|
|
50
|
+
A large imaginary part leads to weaker returned signals, especially at shorter wavelengths.
|
|
51
|
+
|
|
52
|
+
The square root of the complex refractive index corresponds to the complex relative permittivity,
|
|
53
|
+
also known as the complex dielectric constant.
|
|
54
|
+
|
|
55
|
+
Parameters
|
|
56
|
+
----------
|
|
57
|
+
model : str
|
|
58
|
+
The model to use for calculating the complex refractive index. Available models are:
|
|
59
|
+
'Liebe1991', 'Liebe1991v2', 'Ellison2005', 'Turner2016', 'Turner2016SLC'.
|
|
60
|
+
|
|
61
|
+
Returns
|
|
62
|
+
-------
|
|
63
|
+
callable
|
|
64
|
+
A function which compute the complex refractive index for given temperature and frequency.
|
|
65
|
+
|
|
66
|
+
Notes
|
|
67
|
+
-----
|
|
68
|
+
This function serves as a wrapper to various complex refractive index models for raindrops.
|
|
69
|
+
It returns the appropriate model based on the `model` parameter.
|
|
70
|
+
|
|
71
|
+
"""
|
|
72
|
+
permittivity_model = check_permittivity_model(permittivity_model)
|
|
73
|
+
return REFRACTIVE_INDEX_MODELS[permittivity_model]
|
|
74
|
+
|
|
75
|
+
|
|
76
|
+
def check_permittivity_model(permittivity_model):
|
|
77
|
+
"""Check validity of the specified complex refractive index model."""
|
|
78
|
+
available_models = available_permittivity_models()
|
|
79
|
+
if permittivity_model not in available_models:
|
|
80
|
+
raise ValueError(f"{permittivity_model} is an invalid permittivity model. Valid models: {available_models}.")
|
|
81
|
+
return permittivity_model
|
|
82
|
+
|
|
83
|
+
|
|
84
|
+
def get_refractive_index(temperature, frequency, permittivity_model):
|
|
85
|
+
"""
|
|
86
|
+
Compute the complex refractive index of raindrops using the specified permittivity model.
|
|
87
|
+
|
|
88
|
+
The complex refractive index of a hydrometeor (e.g., water droplet, ice particle, graupel)
|
|
89
|
+
governs how radar waves interact with it.
|
|
90
|
+
The real part determines how much the radar wave slows down inside the particle (phase shift)
|
|
91
|
+
The imaginary part determines how much the radar wave is absorbed and attenuated by the particle
|
|
92
|
+
The imaginary part thus describes how much energy is lost as the wave travels through the particle.
|
|
93
|
+
The imaginary part thus controls radar attenuation and depolarization effects.
|
|
94
|
+
A large imaginary part leads to weaker returned signals, especially at shorter wavelengths.
|
|
95
|
+
|
|
96
|
+
The square root of the complex refractive index corresponds to the complex relative permittivity,
|
|
97
|
+
also known as the complex dielectric constant.
|
|
98
|
+
|
|
99
|
+
Parameters
|
|
100
|
+
----------
|
|
101
|
+
temperature : array-like
|
|
102
|
+
Temperature in degree Celsius.
|
|
103
|
+
frequency: float
|
|
104
|
+
Frequency in GHz.
|
|
105
|
+
permittivity_model : str
|
|
106
|
+
The permittivity model to use for calculating the complex refractive index.
|
|
107
|
+
Available models are: 'Liebe1991', 'Liebe1991v2', 'Ellison2005', 'Turner2016', 'Turner2016SLC'.
|
|
108
|
+
See available models with ``disdrodb.scattering.available_permittivity_models()``.
|
|
109
|
+
|
|
110
|
+
Returns
|
|
111
|
+
-------
|
|
112
|
+
m : array-like
|
|
113
|
+
Complex refractive index of raindrop at given temperature and frequency.
|
|
114
|
+
|
|
115
|
+
Notes
|
|
116
|
+
-----
|
|
117
|
+
This function serves as a wrapper to various permittivity models for raindrops.
|
|
118
|
+
It selects and applies the appropriate model based on the `permittivity_model` parameter.
|
|
119
|
+
|
|
120
|
+
Examples
|
|
121
|
+
--------
|
|
122
|
+
>>> temperature = np.array([0.5, 1.0, 2.0, 3.0])
|
|
123
|
+
>>> frequency = 5.6 # GhZ (C band)
|
|
124
|
+
>>> m = get_refractive_index(temperature=temperature, frequency=frequency, permittivity_model="Liebe1991")
|
|
125
|
+
|
|
126
|
+
"""
|
|
127
|
+
# Ensure input is numpy array or xr.DataArray
|
|
128
|
+
frequency = ensure_array(frequency)
|
|
129
|
+
temperature = ensure_array(temperature)
|
|
130
|
+
|
|
131
|
+
# If both inputs are numpy (or dask) arrays with size > 1 → raise error
|
|
132
|
+
if (
|
|
133
|
+
not isinstance(temperature, xr.DataArray)
|
|
134
|
+
and not isinstance(frequency, xr.DataArray)
|
|
135
|
+
and np.size(temperature) > 1
|
|
136
|
+
and np.size(frequency) > 1
|
|
137
|
+
):
|
|
138
|
+
raise ValueError(
|
|
139
|
+
"get_refractive_index does not support broadcasting plain numpy/dask arrays "
|
|
140
|
+
"when both `temperature` and `frequency` have size > 1. "
|
|
141
|
+
"Please provide both input as xarray.DataArray objects "
|
|
142
|
+
"with different dimensions to enable labeled broadcasting.",
|
|
143
|
+
)
|
|
144
|
+
|
|
145
|
+
# Retrieve refractive_index function
|
|
146
|
+
func = get_refractive_index_function(permittivity_model)
|
|
147
|
+
|
|
148
|
+
# Retrieve refractive_index
|
|
149
|
+
refractive_index = func(temperature=temperature, frequency=frequency)
|
|
150
|
+
return refractive_index
|
|
151
|
+
|
|
152
|
+
|
|
153
|
+
####----------------------------------------------------------------------------------------
|
|
154
|
+
#### Liquid Water Refractive Index Models
|
|
155
|
+
|
|
156
|
+
|
|
157
|
+
def ensure_array(arr):
|
|
158
|
+
"""Ensure data to be a numpy array or xarray DataArray."""
|
|
159
|
+
if isinstance(arr, xr.DataArray):
|
|
160
|
+
return arr
|
|
161
|
+
return np.asanyarray(arr)
|
|
162
|
+
|
|
163
|
+
|
|
164
|
+
def check_temperature_validity_range(temperature, vmin, vmax, permittivity_model):
|
|
165
|
+
"""Check temperature validity range."""
|
|
166
|
+
if np.logical_or(temperature < vmin, temperature > vmax).any():
|
|
167
|
+
raise ValueError(
|
|
168
|
+
f"The {permittivity_model} refractive index model is only valid between {vmin} and {vmax} degree Celsius.",
|
|
169
|
+
)
|
|
170
|
+
return temperature
|
|
171
|
+
|
|
172
|
+
|
|
173
|
+
def check_frequency_validity_range(frequency, vmin, vmax, permittivity_model):
|
|
174
|
+
"""Check frequency validity range."""
|
|
175
|
+
if np.logical_or(frequency < vmin, frequency > vmax).any():
|
|
176
|
+
raise ValueError(
|
|
177
|
+
f"The {permittivity_model} refractive index model is only valid between {vmin} and {vmax} GHz.",
|
|
178
|
+
)
|
|
179
|
+
return frequency
|
|
180
|
+
|
|
181
|
+
|
|
182
|
+
def get_rain_refractive_index_liebe1991_single(temperature, frequency):
|
|
183
|
+
"""Compute the complex refractive index according to the single Debye model of Liebe et al. (1991).
|
|
184
|
+
|
|
185
|
+
Parameters
|
|
186
|
+
----------
|
|
187
|
+
temperature : array-like
|
|
188
|
+
Temperature in degree Celsius.
|
|
189
|
+
frequency : array-like
|
|
190
|
+
Frequency in GHz.
|
|
191
|
+
|
|
192
|
+
Returns
|
|
193
|
+
-------
|
|
194
|
+
m : array-like
|
|
195
|
+
Complex refractive index at requested temperature and frequency.
|
|
196
|
+
|
|
197
|
+
Notes
|
|
198
|
+
-----
|
|
199
|
+
- The code of this function has been derived from RainSense code of Thomas van Leth available at
|
|
200
|
+
https://github.com/temperatureCvanLeth/RainSense/blob/master/rainsense/scattering.py#L149
|
|
201
|
+
|
|
202
|
+
References
|
|
203
|
+
----------
|
|
204
|
+
H. J. Liebe, G. A. Hufford, and T. Manabe (1991).
|
|
205
|
+
A model for the complex permittivity of water at frequencies below 1 THz.
|
|
206
|
+
Journal of Atmospheric and Oceanic Technology, 27(2), 333-344.
|
|
207
|
+
Int. J. Infrared Millim. Waves, 12(7), 659-675.
|
|
208
|
+
https://doi.org/10.1007/BF01008897
|
|
209
|
+
"""
|
|
210
|
+
# Ensure input is numpy array or xr.DataArray
|
|
211
|
+
frequency = ensure_array(frequency)
|
|
212
|
+
temperature = ensure_array(temperature)
|
|
213
|
+
|
|
214
|
+
# Check frequency and temperature within validity range
|
|
215
|
+
temperature = check_temperature_validity_range(temperature, vmin=0, vmax=100, permittivity_model="Liebe1991single")
|
|
216
|
+
frequency = check_frequency_validity_range(frequency, vmin=0, vmax=100, permittivity_model="Liebe1991single")
|
|
217
|
+
|
|
218
|
+
# Conversion of temperature to Kelvin
|
|
219
|
+
temperature = temperature + 273.15
|
|
220
|
+
|
|
221
|
+
# Compute static dielectric constant (eq. 1)
|
|
222
|
+
theta = 1 - 300 / temperature
|
|
223
|
+
eps_0 = 77.66 - 103.3 * theta
|
|
224
|
+
|
|
225
|
+
# Compute the complex dielectric constant (eq. 2)
|
|
226
|
+
eps_1 = 0.066 * eps_0
|
|
227
|
+
gamma_D = 20.27 + 146.5 * theta + 314 * theta**2
|
|
228
|
+
eps = (eps_0 - eps_1) / (1 - 1j * frequency / gamma_D) + eps_1
|
|
229
|
+
|
|
230
|
+
# Compute the refractive index
|
|
231
|
+
m = np.sqrt(eps)
|
|
232
|
+
return m
|
|
233
|
+
|
|
234
|
+
|
|
235
|
+
def get_rain_refractive_index_liebe1991(temperature, frequency):
|
|
236
|
+
"""Compute the complex refractive index according to the double Debye model of Liebe et al. (1991).
|
|
237
|
+
|
|
238
|
+
Parameters
|
|
239
|
+
----------
|
|
240
|
+
temperature : array-like
|
|
241
|
+
Temperature in degree Celsius.
|
|
242
|
+
frequency : array-like
|
|
243
|
+
Frequency in GHz.
|
|
244
|
+
|
|
245
|
+
Returns
|
|
246
|
+
-------
|
|
247
|
+
m : array-like
|
|
248
|
+
Complex refractive index at requested temperature and frequency.
|
|
249
|
+
|
|
250
|
+
Notes
|
|
251
|
+
-----
|
|
252
|
+
- The code of this function has been derived from pyradsim code of Daniel Wolfensberger available at
|
|
253
|
+
https://github.com/wolfidan/pyradsim/blob/master/pyradsim/permittivity_models.py#L37
|
|
254
|
+
- The Liebe et al. (1991) replaces the work of Ray et al. (1972).
|
|
255
|
+
|
|
256
|
+
References
|
|
257
|
+
----------
|
|
258
|
+
H. J. Liebe, G. A. Hufford, and T. Manabe (1991).
|
|
259
|
+
A model for the complex permittivity of water at frequencies below 1 THz.
|
|
260
|
+
Journal of Atmospheric and Oceanic Technology, 27(2), 333-344.
|
|
261
|
+
Int. J. Infrared Millim. Waves, 12(7), 659-675.
|
|
262
|
+
https://doi.org/10.1007/BF01008897
|
|
263
|
+
|
|
264
|
+
Peter S. Ray (1972).
|
|
265
|
+
Broadband Complex Refractive Indices of Ice and Water.
|
|
266
|
+
Applied Optics, 11(8), 1836-1844.
|
|
267
|
+
https://doi.org/10.1364/AO.11.001836
|
|
268
|
+
"""
|
|
269
|
+
# Ensure input is numpy array or xr.DataArray
|
|
270
|
+
frequency = ensure_array(frequency)
|
|
271
|
+
temperature = ensure_array(temperature)
|
|
272
|
+
|
|
273
|
+
# Check frequency and temperature within validity range
|
|
274
|
+
temperature = check_temperature_validity_range(temperature, vmin=0, vmax=40, permittivity_model="Liebe1991")
|
|
275
|
+
frequency = check_frequency_validity_range(frequency, vmin=0, vmax=1000, permittivity_model="Liebe1991")
|
|
276
|
+
|
|
277
|
+
# Conversion of temperature to Kelvin
|
|
278
|
+
temperature = temperature + 273.15
|
|
279
|
+
|
|
280
|
+
# Compute static dielectric constant (eq. 1)
|
|
281
|
+
theta = 1 - 300 / temperature
|
|
282
|
+
eps_0 = 77.66 - 103.3 * theta
|
|
283
|
+
|
|
284
|
+
# Compute the complex dielectric constant (e4, eq5)
|
|
285
|
+
eps_1 = 0.0671 * eps_0
|
|
286
|
+
eps_2 = 3.52 + 7.52 * theta
|
|
287
|
+
gamma_1 = 20.20 + 146.5 * theta + 316 * theta**2
|
|
288
|
+
gamma_2 = 39.8 * gamma_1
|
|
289
|
+
|
|
290
|
+
term1 = eps_0 - eps_1
|
|
291
|
+
term2 = 1 + (frequency / gamma_1) ** 2
|
|
292
|
+
term3 = 1 + (frequency / gamma_2) ** 2
|
|
293
|
+
term4 = eps_1 - eps_2
|
|
294
|
+
term5 = eps_2
|
|
295
|
+
|
|
296
|
+
eps_real = term1 / term2 + term4 / term3 + term5
|
|
297
|
+
eps_imag = (term1 / term2) * (frequency / gamma_1) + (term4 / term3) * (frequency / gamma_2)
|
|
298
|
+
|
|
299
|
+
eps = eps_real + 1j * eps_imag
|
|
300
|
+
|
|
301
|
+
# Compute the refractive index
|
|
302
|
+
m = np.sqrt(eps)
|
|
303
|
+
return m
|
|
304
|
+
|
|
305
|
+
|
|
306
|
+
def get_rain_refractive_index_ellison2005(temperature, frequency):
|
|
307
|
+
"""Compute the complex refractive index according to Ellison (2005) model.
|
|
308
|
+
|
|
309
|
+
Parameters
|
|
310
|
+
----------
|
|
311
|
+
temperature : array-like
|
|
312
|
+
Temperature in degree Celsius.
|
|
313
|
+
frequency : array-like
|
|
314
|
+
Frequency in GHz.
|
|
315
|
+
|
|
316
|
+
Returns
|
|
317
|
+
-------
|
|
318
|
+
m : array-like
|
|
319
|
+
Complex refractive index at requested temperature and frequency.
|
|
320
|
+
|
|
321
|
+
Notes
|
|
322
|
+
-----
|
|
323
|
+
- The model is designed to operate only up to 1000 GHz and temperature ranging from 0 degC to 100 degC.
|
|
324
|
+
- The code of this function has been derived from Davide Ori raincoat code available at
|
|
325
|
+
https://github.com/OPTIMICe-team/raincoat/blob/master/raincoat/scatTable/water.py#L160
|
|
326
|
+
|
|
327
|
+
References
|
|
328
|
+
----------
|
|
329
|
+
W. J. Ellison (2007).
|
|
330
|
+
Permittivity of Pure Water, at Standard Atmospheric Pressure, over the
|
|
331
|
+
Frequency Range 0-25 THz and the Temperature Range 0-100 °C.
|
|
332
|
+
J. Phys. Chem. Ref. Data, 36, 1-18.
|
|
333
|
+
https://doi.org/10.1063/1.2360986
|
|
334
|
+
"""
|
|
335
|
+
# Ensure input is numpy array or xr.DataArray
|
|
336
|
+
frequency = ensure_array(frequency)
|
|
337
|
+
temperature = ensure_array(temperature)
|
|
338
|
+
|
|
339
|
+
# Check frequency and temperature within validity range
|
|
340
|
+
temperature = check_temperature_validity_range(temperature, vmin=0, vmax=100, permittivity_model="Ellison2005")
|
|
341
|
+
frequency = check_frequency_validity_range(frequency, vmin=0, vmax=1000, permittivity_model="Ellison2005")
|
|
342
|
+
|
|
343
|
+
# Conversion of frequency to Hz
|
|
344
|
+
frequency = frequency / 1e-9
|
|
345
|
+
|
|
346
|
+
# Here below we assume temperature in Celsius, frequency in Hz
|
|
347
|
+
T = temperature
|
|
348
|
+
|
|
349
|
+
# Compute the complex dielectric constant
|
|
350
|
+
a0 = 5.7230
|
|
351
|
+
a1 = 2.2379e-2
|
|
352
|
+
a2 = -7.1237e-4
|
|
353
|
+
a3 = 5.0478
|
|
354
|
+
a4 = -7.0315e-2
|
|
355
|
+
a5 = 6.0059e-4
|
|
356
|
+
a6 = 3.6143
|
|
357
|
+
a7 = 2.8841e-2
|
|
358
|
+
a8 = 1.3652e-1
|
|
359
|
+
a9 = 1.4825e-3
|
|
360
|
+
a10 = 2.4166e-4
|
|
361
|
+
|
|
362
|
+
es = (37088.6 - 82.168 * T) / (421.854 + T)
|
|
363
|
+
einf = a6 + a7 * T
|
|
364
|
+
e1 = a0 + T * (a1 + T * a2) # a0+a1*T+a2*T*T
|
|
365
|
+
ni1 = (45.0 + T) / (a3 + T * (a4 + T * a5)) # (a3+a4*T+a5*T*T)
|
|
366
|
+
ni2 = (45.0 + T) / (a8 + T * (a9 + T * a10)) # (a8+a9*T+a10*T*T)
|
|
367
|
+
A1 = frequency * 1.0e-9 / ni1
|
|
368
|
+
A2 = frequency * 1.0e-9 / ni2
|
|
369
|
+
|
|
370
|
+
eps_real = (es - e1) / (1 + A1 * A1) + (e1 - einf) / (1 + A2 * A2) + einf
|
|
371
|
+
eps_imag = (es * A1 - e1 * A1) / (1 + A1 * A1) + (e1 * A2 - einf * A2) / (1 + A2 * A2)
|
|
372
|
+
|
|
373
|
+
eps = eps_real + 1j * eps_imag
|
|
374
|
+
|
|
375
|
+
# Compute the refractive index
|
|
376
|
+
m = np.sqrt(eps)
|
|
377
|
+
return m
|
|
378
|
+
|
|
379
|
+
|
|
380
|
+
def get_rain_refractive_index_turner2016(frequency, temperature):
|
|
381
|
+
"""Compute the complex refractive index using the Turner-Kneifel-Cadeddu (TKC) model.
|
|
382
|
+
|
|
383
|
+
The TKC supercooled liquid water absorption model was built using both laboratory observations
|
|
384
|
+
(primarily at warm temperature) and field data observed by MWRs at multiple frequency at
|
|
385
|
+
supercool temperature. The field data were published in Kneifel et al. (2014).
|
|
386
|
+
|
|
387
|
+
The strength of the TKC model is the use of an optimal estimation framework to
|
|
388
|
+
determine the empirical coefficients of the double-Debye model.
|
|
389
|
+
A full description of this model is given in Turner et al. (2016).
|
|
390
|
+
|
|
391
|
+
Parameters
|
|
392
|
+
----------
|
|
393
|
+
temperature : array-like
|
|
394
|
+
Temperature in degree Celsius.
|
|
395
|
+
frequency : array-like
|
|
396
|
+
Frequency in GHz.
|
|
397
|
+
|
|
398
|
+
Returns
|
|
399
|
+
-------
|
|
400
|
+
m : array-like
|
|
401
|
+
Complex refractive index at given temperature and frequency.
|
|
402
|
+
|
|
403
|
+
Notes
|
|
404
|
+
-----
|
|
405
|
+
- The code of this function has been checked against Joseph Hardin pyDSD and Davide Ori raincoat codes
|
|
406
|
+
available at:
|
|
407
|
+
https://github.com/josephhardinee/PyDSD/blob/main/pydsd/utility/dielectric.py#L36
|
|
408
|
+
https://github.com/OPTIMICe-team/raincoat/blob/master/raincoat/scatTable/water.py#L54
|
|
409
|
+
|
|
410
|
+
References
|
|
411
|
+
----------
|
|
412
|
+
Turner, D.D., S. Kneifel, and M.P. Cadeddu (2016).
|
|
413
|
+
An improved liquid water absorption model in the microwave for supercooled liquid clouds.
|
|
414
|
+
J. Atmos. Oceanic Technol., 33(1), 33-44.
|
|
415
|
+
https://doi.org/10.1175/JTECH-D-15-0074.1.
|
|
416
|
+
|
|
417
|
+
Kneifel, S., S. Redl, E. Orlandi, U. Löhnert, M. P. Cadeddu, D. D. Turner, and M. Chen (2014).
|
|
418
|
+
Absorption Properties of Supercooled Liquid Water between 31 and 225 GHz:
|
|
419
|
+
Evaluation of Absorption Models Using Ground-Based Observations.
|
|
420
|
+
J. Appl. Meteor. Climatol., 53, 1028-1045.
|
|
421
|
+
https://doi.org/10.1175/JAMC-D-13-0214.1
|
|
422
|
+
"""
|
|
423
|
+
# Ensure input is numpy array or xr.DataArray
|
|
424
|
+
frequency = ensure_array(frequency)
|
|
425
|
+
temperature = ensure_array(temperature)
|
|
426
|
+
|
|
427
|
+
# Check frequency and temperature within validity range
|
|
428
|
+
temperature = check_temperature_validity_range(temperature, vmin=-40, vmax=50, permittivity_model="Turner2016")
|
|
429
|
+
frequency = check_frequency_validity_range(frequency, vmin=0.5, vmax=500, permittivity_model="Turner2016")
|
|
430
|
+
|
|
431
|
+
# Conversion of frequency to Hz
|
|
432
|
+
frequency = frequency / 1e-9
|
|
433
|
+
|
|
434
|
+
# Define coefficients
|
|
435
|
+
a = [8.111e01, 2.025]
|
|
436
|
+
b = [4.434e-3, 1.073e-2]
|
|
437
|
+
c = [1.302e-13, 1.012e-14]
|
|
438
|
+
d = [6.627e02, 6.089e02]
|
|
439
|
+
tc = 1.342e2
|
|
440
|
+
s = [8.79144e1, -4.04399e-1, 9.58726e-4, -1.32802e-6]
|
|
441
|
+
|
|
442
|
+
def A_i(i, temperature, frequency):
|
|
443
|
+
"""Compute the relaxation terms A_i (Eq 7) of the double Debye model."""
|
|
444
|
+
delta = a[i] * np.exp(-1 * b[i] * temperature) # (Eq 9)
|
|
445
|
+
tau = c[i] * np.exp(d[i] / (temperature + tc)) # (Eq 10)
|
|
446
|
+
|
|
447
|
+
return (tau**2 * delta) / (1 + (2 * np.pi * frequency * tau) ** 2) # (Eq 7)
|
|
448
|
+
|
|
449
|
+
def B_i(i, temperature, frequency):
|
|
450
|
+
"""Compute the relaxation terms B_i (Eq 7) of the double Debye model."""
|
|
451
|
+
delta = a[i] * np.exp(-1 * b[i] * temperature) # (Eq 9)
|
|
452
|
+
tau = c[i] * np.exp(d[i] / (temperature + tc)) # (Eq 10)
|
|
453
|
+
|
|
454
|
+
return (tau * delta) / (1 + (2 * np.pi * frequency * tau) ** 2) # (Eq 8)
|
|
455
|
+
|
|
456
|
+
# Compute the static dielectric permittivity (Eq 6)
|
|
457
|
+
es = s[0] + s[1] * temperature + s[2] * temperature**2 + s[3] * temperature**3
|
|
458
|
+
|
|
459
|
+
# Compute the complex dielectric constant
|
|
460
|
+
eps_real = es - (2 * np.pi * frequency) ** 2 * (
|
|
461
|
+
A_i(0, temperature, frequency) + A_i(1, temperature, frequency)
|
|
462
|
+
) # (Eq 4)
|
|
463
|
+
eps_imag = 2 * np.pi * frequency * (B_i(0, temperature, frequency) + B_i(1, temperature, frequency)) # (Eq 5)
|
|
464
|
+
|
|
465
|
+
eps = eps_real + 1j * eps_imag
|
|
466
|
+
|
|
467
|
+
# Compute the refractive index
|
|
468
|
+
m = np.sqrt(eps)
|
|
469
|
+
return m
|
|
470
|
+
|
|
471
|
+
|
|
472
|
+
####----------------------------------------------------------------------------------------
|
|
473
|
+
def get_rayleigh_dielectric_factor(m):
|
|
474
|
+
"""Compute the Rayleigh dielectric factor |K|**2 from the complex refractive index.
|
|
475
|
+
|
|
476
|
+
The magnitude squared of the complex dielectric contrast factor for liquid water,
|
|
477
|
+
relative to the surrounding medium (typically air).
|
|
478
|
+
|
|
479
|
+
This factor is used to compute the radar reflectivity.
|
|
480
|
+
|
|
481
|
+
Parameters
|
|
482
|
+
----------
|
|
483
|
+
m : complex
|
|
484
|
+
Complex refractive index.
|
|
485
|
+
|
|
486
|
+
Returns
|
|
487
|
+
-------
|
|
488
|
+
float
|
|
489
|
+
Dielectric factor |K|^2 used in Rayleigh scattering.
|
|
490
|
+
Often also called the radar dieletric factor.
|
|
491
|
+
In pytmatrix, correspond to the Kw_sqr argument of the Scatterer object.
|
|
492
|
+
"""
|
|
493
|
+
eps = m**2
|
|
494
|
+
K_complex = (eps - 1.0) / (eps + 2.0)
|
|
495
|
+
return np.abs(K_complex) ** 2
|
|
496
|
+
|
|
497
|
+
|
|
498
|
+
####-------------------------------------------------------------------------------------.
|
|
499
|
+
REFRACTIVE_INDEX_MODELS = {
|
|
500
|
+
"Liebe1991": get_rain_refractive_index_liebe1991,
|
|
501
|
+
"Liebe1991single": get_rain_refractive_index_liebe1991_single,
|
|
502
|
+
"Ellison2005": get_rain_refractive_index_ellison2005,
|
|
503
|
+
"Turner2016": get_rain_refractive_index_turner2016,
|
|
504
|
+
}
|