disdrodb 0.1.4__py3-none-any.whl → 0.1.5__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.
Files changed (85) hide show
  1. disdrodb/_version.py +2 -2
  2. disdrodb/api/create_directories.py +0 -2
  3. disdrodb/cli/disdrodb_create_summary.py +10 -0
  4. disdrodb/cli/disdrodb_create_summary_station.py +10 -0
  5. disdrodb/constants.py +1 -1
  6. disdrodb/etc/products/L1/global.yaml +1 -1
  7. disdrodb/etc/products/L2E/5MIN.yaml +1 -0
  8. disdrodb/etc/products/L2E/global.yaml +1 -1
  9. disdrodb/etc/products/L2M/GAMMA_GS_ND_MAE.yaml +6 -0
  10. disdrodb/etc/products/L2M/GAMMA_ML.yaml +1 -1
  11. disdrodb/etc/products/L2M/LOGNORMAL_GS_LOG_ND_MAE.yaml +6 -0
  12. disdrodb/etc/products/L2M/LOGNORMAL_GS_ND_MAE.yaml +6 -0
  13. disdrodb/etc/products/L2M/LOGNORMAL_ML.yaml +8 -0
  14. disdrodb/etc/products/L2M/global.yaml +11 -3
  15. disdrodb/l0/check_configs.py +49 -16
  16. disdrodb/l0/configs/LPM/l0a_encodings.yml +2 -2
  17. disdrodb/l0/configs/LPM/l0b_cf_attrs.yml +2 -2
  18. disdrodb/l0/configs/LPM/l0b_encodings.yml +2 -2
  19. disdrodb/l0/configs/LPM/raw_data_format.yml +2 -2
  20. disdrodb/l0/configs/PWS100/l0b_encodings.yml +1 -0
  21. disdrodb/l0/configs/SWS250/bins_diameter.yml +108 -0
  22. disdrodb/l0/configs/SWS250/bins_velocity.yml +83 -0
  23. disdrodb/l0/configs/SWS250/l0a_encodings.yml +18 -0
  24. disdrodb/l0/configs/SWS250/l0b_cf_attrs.yml +72 -0
  25. disdrodb/l0/configs/SWS250/l0b_encodings.yml +155 -0
  26. disdrodb/l0/configs/SWS250/raw_data_format.yml +148 -0
  27. disdrodb/l0/l0b_processing.py +70 -15
  28. disdrodb/l0/readers/LPM/ARM/ARM_LPM.py +1 -1
  29. disdrodb/l0/readers/LPM/AUSTRALIA/MELBOURNE_2007_LPM.py +2 -2
  30. disdrodb/l0/readers/LPM/BELGIUM/ULIEGE.py +256 -0
  31. disdrodb/l0/readers/LPM/BRAZIL/CHUVA_LPM.py +2 -2
  32. disdrodb/l0/readers/LPM/BRAZIL/GOAMAZON_LPM.py +2 -2
  33. disdrodb/l0/readers/LPM/GERMANY/DWD.py +491 -0
  34. disdrodb/l0/readers/LPM/ITALY/GID_LPM.py +2 -2
  35. disdrodb/l0/readers/LPM/ITALY/GID_LPM_W.py +2 -2
  36. disdrodb/l0/readers/LPM/KIT/CHWALA.py +2 -2
  37. disdrodb/l0/readers/LPM/SLOVENIA/ARSO.py +107 -12
  38. disdrodb/l0/readers/LPM/SLOVENIA/UL.py +3 -3
  39. disdrodb/l0/readers/LPM/SWITZERLAND/INNERERIZ_LPM.py +2 -2
  40. disdrodb/l0/readers/PARSIVEL/NCAR/VORTEX2_2010.py +5 -14
  41. disdrodb/l0/readers/PARSIVEL/NCAR/VORTEX2_2010_UF.py +5 -14
  42. disdrodb/l0/readers/PARSIVEL/SLOVENIA/UL.py +117 -8
  43. disdrodb/l0/readers/PARSIVEL2/BRAZIL/CHUVA_PARSIVEL2.py +10 -14
  44. disdrodb/l0/readers/PARSIVEL2/BRAZIL/GOAMAZON_PARSIVEL2.py +10 -14
  45. disdrodb/l0/readers/PARSIVEL2/DENMARK/DTU.py +8 -14
  46. disdrodb/l0/readers/PARSIVEL2/DENMARK/EROSION_raw.py +382 -0
  47. disdrodb/l0/readers/PARSIVEL2/FINLAND/FMI_PARSIVEL2.py +4 -0
  48. disdrodb/l0/readers/PARSIVEL2/FRANCE/OSUG.py +1 -1
  49. disdrodb/l0/readers/PARSIVEL2/GREECE/NOA.py +127 -0
  50. disdrodb/l0/readers/PARSIVEL2/ITALY/HYDROX.py +239 -0
  51. disdrodb/l0/readers/PARSIVEL2/NCAR/FARM_PARSIVEL2.py +5 -11
  52. disdrodb/l0/readers/PARSIVEL2/NCAR/PERILS_MIPS.py +4 -17
  53. disdrodb/l0/readers/PARSIVEL2/NCAR/RELAMPAGO_PARSIVEL2.py +5 -14
  54. disdrodb/l0/readers/PARSIVEL2/NCAR/SNOWIE_PJ.py +10 -13
  55. disdrodb/l0/readers/PARSIVEL2/NCAR/SNOWIE_SB.py +10 -13
  56. disdrodb/l0/readers/PARSIVEL2/PHILIPPINES/PANGASA.py +232 -0
  57. disdrodb/l0/readers/PARSIVEL2/SPAIN/CENER.py +6 -18
  58. disdrodb/l0/readers/PARSIVEL2/SPAIN/GRANADA.py +120 -0
  59. disdrodb/l0/readers/PARSIVEL2/USA/C3WE.py +7 -25
  60. disdrodb/l0/readers/PWS100/AUSTRIA/HOAL.py +321 -0
  61. disdrodb/l0/readers/SW250/BELGIUM/KMI.py +239 -0
  62. disdrodb/l1/beard_model.py +31 -129
  63. disdrodb/l1/fall_velocity.py +136 -83
  64. disdrodb/l1/filters.py +25 -28
  65. disdrodb/l1/processing.py +11 -13
  66. disdrodb/l1_env/routines.py +46 -17
  67. disdrodb/l2/empirical_dsd.py +6 -0
  68. disdrodb/l2/processing.py +2 -2
  69. disdrodb/metadata/geolocation.py +0 -2
  70. disdrodb/psd/fitting.py +16 -13
  71. disdrodb/routines/l2.py +35 -23
  72. disdrodb/routines/wrappers.py +5 -0
  73. disdrodb/scattering/axis_ratio.py +90 -84
  74. disdrodb/scattering/permittivity.py +6 -0
  75. disdrodb/summary/routines.py +38 -12
  76. disdrodb/utils/attrs.py +2 -0
  77. disdrodb/utils/encoding.py +5 -0
  78. disdrodb/utils/time.py +2 -2
  79. disdrodb/viz/plots.py +24 -1
  80. {disdrodb-0.1.4.dist-info → disdrodb-0.1.5.dist-info}/METADATA +2 -1
  81. {disdrodb-0.1.4.dist-info → disdrodb-0.1.5.dist-info}/RECORD +85 -65
  82. {disdrodb-0.1.4.dist-info → disdrodb-0.1.5.dist-info}/WHEEL +0 -0
  83. {disdrodb-0.1.4.dist-info → disdrodb-0.1.5.dist-info}/entry_points.txt +0 -0
  84. {disdrodb-0.1.4.dist-info → disdrodb-0.1.5.dist-info}/licenses/LICENSE +0 -0
  85. {disdrodb-0.1.4.dist-info → disdrodb-0.1.5.dist-info}/top_level.txt +0 -0
@@ -0,0 +1,239 @@
1
+ #!/usr/bin/env python3
2
+
3
+ # -----------------------------------------------------------------------------.
4
+ # Copyright (c) 2021-2023 DISDRODB developers
5
+ #
6
+ # This program is free software: you can redistribute it and/or modify
7
+ # it under the terms of the GNU General Public License as published by
8
+ # the Free Software Foundation, either version 3 of the License, or
9
+ # (at your option) any later version.
10
+ #
11
+ # This program is distributed in the hope that it will be useful,
12
+ # but WITHOUT ANY WARRANTY; without even the implied warranty of
13
+ # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14
+ # GNU General Public License for more details.
15
+ #
16
+ # You should have received a copy of the GNU General Public License
17
+ # along with this program. If not, see <http://www.gnu.org/licenses/>.
18
+ # -----------------------------------------------------------------------------.
19
+ """DISDRODB reader for KMI Biral SW250 sensors."""
20
+ import pandas as pd
21
+
22
+ from disdrodb.l0.l0_reader import is_documented_by, reader_generic_docstring
23
+ from disdrodb.l0.l0a_processing import read_raw_text_file
24
+
25
+
26
+ def parse_spectrum_line_to_string(line):
27
+ """Parse one M... spectrum line into a zero-padded string with 21 values."""
28
+ # Define number of velocity bins values expected
29
+ n_cols = 21
30
+
31
+ # Split spectrum line
32
+ parts = line.split(",")
33
+
34
+ # Check line validity
35
+ n_values = len(parts)
36
+ if n_values > n_cols:
37
+ raise ValueError(f"Unexpected number of velocity bins: {n_values}.")
38
+
39
+ # Strip 'M' from first bin
40
+ parts[0] = parts[0].replace(":00M", "")
41
+
42
+ # Strip last two letter from last value
43
+ parts[-1] = parts[-1][:3]
44
+
45
+ # Define list of values
46
+ values = [int(x) for x in parts]
47
+ if len(values) < n_cols:
48
+ values.extend([0] * (n_cols - len(values)))
49
+ values = values[:n_cols]
50
+
51
+ # Define comma-separated string
52
+ string = ",".join(str(v) for v in values)
53
+ return string
54
+
55
+
56
+ def parse_spectrum_block(lines):
57
+ """Parse an M-block into a fixed (16 x 21) matrix."""
58
+ n_values = len(lines)
59
+ if n_values != 16:
60
+ raise ValueError(f"Unexpected number of diameter bins: {n_values}.")
61
+ raw_drop_number_string = ",".join([parse_spectrum_line_to_string(line) for line in lines])
62
+ return raw_drop_number_string
63
+
64
+
65
+ def build_spectrum_block(group):
66
+ """Create SWS250 raw spectrum string."""
67
+ try:
68
+ return pd.Series(
69
+ {
70
+ "raw_drop_number": parse_spectrum_block(group["spectrum_line"].tolist()),
71
+ },
72
+ )
73
+ except Exception:
74
+ return pd.Series({"raw_drop_number": "NaN"})
75
+
76
+
77
+ @is_documented_by(reader_generic_docstring)
78
+ def reader(
79
+ filepath,
80
+ logger=None,
81
+ ):
82
+ """Reader."""
83
+ ##------------------------------------------------------------------------.
84
+ #### Define raw data headers
85
+ column_names = ["TO_PARSE"]
86
+
87
+ ##------------------------------------------------------------------------.
88
+ #### Define reader options
89
+ # - For more info: https://pandas.pydata.org/docs/reference/api/pandas.read_csv.html
90
+ reader_kwargs = {}
91
+
92
+ # - Define delimiter
93
+ reader_kwargs["delimiter"] = "\\n"
94
+
95
+ # - Avoid first column to become df index !!!
96
+ reader_kwargs["index_col"] = False
97
+
98
+ # Since column names are expected to be passed explicitly, header is set to None
99
+ reader_kwargs["header"] = None
100
+
101
+ # - Number of rows to be skipped at the beginning of the file
102
+ reader_kwargs["skiprows"] = None
103
+
104
+ # - Define behaviour when encountering bad lines
105
+ reader_kwargs["on_bad_lines"] = "skip"
106
+
107
+ # - Define reader engine
108
+ # - C engine is faster
109
+ # - Python engine is more feature-complete
110
+ reader_kwargs["engine"] = "python"
111
+
112
+ # - Define on-the-fly decompression of on-disk data
113
+ # - Available: gzip, bz2, zip
114
+ reader_kwargs["compression"] = "infer"
115
+
116
+ # - Skip rows with badly encoded data
117
+ reader_kwargs["encoding_errors"] = "replace"
118
+
119
+ # - Strings to recognize as NA/NaN and replace with standard NA flags
120
+ # - Already included: '#N/A', '#N/A N/A', '#NA', '-1.#IND', '-1.#QNAN',
121
+ # '-NaN', '-nan', '1.#IND', '1.#QNAN', '<NA>', 'N/A',
122
+ # 'NA', 'NULL', 'NaN', 'n/a', 'nan', 'null'
123
+ reader_kwargs["na_values"] = ["na", "", "error"]
124
+
125
+ ##------------------------------------------------------------------------.
126
+ #### Read the data
127
+ df = read_raw_text_file(
128
+ filepath=filepath,
129
+ column_names=column_names,
130
+ reader_kwargs=reader_kwargs,
131
+ logger=logger,
132
+ )
133
+
134
+ ##------------------------------------------------------------------------.
135
+ #### Adapt the dataframe to adhere to DISDRODB L0 standards
136
+ # Identify rows with data
137
+ df_params = df[df["TO_PARSE"].str.count(",") == 23]
138
+
139
+ # Identify rows with spectrum matrix
140
+ df_spectrum = df[df["TO_PARSE"].str.startswith(":00M")]
141
+ if len(df_spectrum) == 0:
142
+ raise ValueError("No spectrum available.")
143
+
144
+ df_spectrum = df_spectrum["TO_PARSE"].str.rsplit(",", expand=True, n=2)
145
+ df_spectrum.columns = ["spectrum_line", "date", "time"]
146
+ df_spectrum["datetime"] = pd.to_datetime(
147
+ df_spectrum["date"] + " " + df_spectrum["time"],
148
+ format="%d/%m/%Y %H:%M:%S",
149
+ )
150
+
151
+ # Define groups
152
+ # - Mark new group when time gap > 10 s
153
+ is_new_group = (df_spectrum["datetime"].diff().dt.total_seconds() > 10).fillna(True)
154
+ group_id = is_new_group.cumsum()
155
+ # - Assign the first datetime of each group
156
+ df_spectrum["group_time"] = df_spectrum.groupby(group_id)["datetime"].transform("first")
157
+
158
+ # Group spectrum by timesteps
159
+ df_raw_drop_number = (
160
+ df_spectrum.groupby("group_time", as_index=False)
161
+ .apply(build_spectrum_block, include_groups=False)
162
+ .reset_index(drop=True)
163
+ )
164
+
165
+ # Retrieve 1-min data
166
+ # - Split by ; delimiter (before raw drop number)
167
+ df_data = df_params["TO_PARSE"].str.split(",", expand=True)
168
+
169
+ # - Assign column names
170
+ names = [
171
+ "date",
172
+ "time",
173
+ "sws250",
174
+ "sensor_id",
175
+ "sample_interval",
176
+ "mor_visibility_5min", # remove unit and ensure in meters !
177
+ "weather_code_synop_4680",
178
+ "past_weather1",
179
+ "past_weather2",
180
+ "obstruction_status",
181
+ "weather_code_metar_4678",
182
+ "precipitation_rate",
183
+ "mor_visibility", # remove unit and ensure in meters !
184
+ "total_extinction_coefficient", # [km-1]
185
+ "transmissometer_extinction_coefficient", # [km-1]
186
+ "back_scatter_extinction_coefficient", # [km-1]
187
+ "sensor_temperature", # [degrees] or air_temperature ?
188
+ "ambient_light_sensor_signal", # [cd/m2] # ALS
189
+ "sensor_status",
190
+ "number_particles",
191
+ "precipitation_accumulated", # [mm] over sample_interval
192
+ "ambient_light_sensor_signal_status",
193
+ "date1",
194
+ "time1",
195
+ ]
196
+ df_data.columns = names
197
+
198
+ # Clean out variables
199
+ df_data["mor_visibility_5min"] = df_data["mor_visibility_5min"].str.replace("M", "")
200
+ df_data["mor_visibility"] = df_data["mor_visibility"].str.replace("M", "")
201
+ df_data["sensor_temperature"] = df_data["sensor_temperature"].str.replace("C", "")
202
+ df_data["ambient_light_sensor_signal"] = df_data["ambient_light_sensor_signal"].str.replace("+99999", "NaN")
203
+
204
+ # Define datetime
205
+ df_data["datetime"] = pd.to_datetime(df_data["date1"] + " " + df_data["time1"], format="%d/%m/%Y %H:%M:%S")
206
+
207
+ # Merge df_data on df_raw_drop_number
208
+ # TODO list
209
+ # - should we aggregate variables to 5 min temporal resolution
210
+ # to match raw_drop_number
211
+ # - should we infill df_raw_drop_number with 0 when no time every 5 min?
212
+ df = pd.merge_asof(
213
+ df_raw_drop_number,
214
+ df_data,
215
+ left_on="group_time",
216
+ right_on="datetime",
217
+ direction="nearest",
218
+ tolerance=pd.Timedelta("10s"), # max difference allowed
219
+ )
220
+
221
+ # Define final time
222
+ # TODO list
223
+ # - which time should we take as final time?
224
+ # - raw_drop_number time is end of measurement interval right?
225
+ df["time"] = df["group_time"]
226
+
227
+ # Drop columns not agreeing with DISDRODB L0 standards
228
+ columns_to_drop = [
229
+ "group_time",
230
+ "date",
231
+ "sws250",
232
+ "sample_interval",
233
+ "sensor_id",
234
+ "date1",
235
+ "time1",
236
+ "datetime",
237
+ ]
238
+ df = df.drop(columns=columns_to_drop)
239
+ return df
@@ -456,67 +456,67 @@ def get_raindrop_reynolds_number(diameter, temperature, air_density, water_densi
456
456
  return reynolds_number
457
457
 
458
458
 
459
- def get_fall_velocity_beard_1976(diameter, temperature, air_density, water_density, g):
459
+ def get_drag_coefficient(diameter, air_density, water_density, fall_velocity, g=9.81):
460
460
  """
461
- Computes the terminal fall velocity of a raindrop in still air.
462
-
463
- Reference: Beard 1976; Pruppacher & Klett 1978
461
+ Computes the drag coefficient for a raindrop.
464
462
 
465
463
  Parameters
466
464
  ----------
467
465
  diameter : float
468
466
  Diameter of the raindrop in meters.
469
- temperature : float
470
- Temperature in Kelvin.
471
467
  air_density : float
472
468
  Density of air in kg/m^3.
473
469
  water_density : float
474
470
  Density of water in kg/m^3.
471
+ fall_velocity : float
472
+ Terminal fall velocity of the raindrop in m/s.
475
473
  g : float
476
474
  Gravitational acceleration in m/s^2.
477
475
 
478
476
  Returns
479
477
  -------
480
478
  float
481
- Terminal fall velocity of the raindrop in m/s.
479
+ Drag coefficient of the raindrop.
482
480
  """
483
- air_viscosity = get_air_dynamic_viscosity(temperature)
484
- reynolds_number = get_raindrop_reynolds_number(
485
- diameter=diameter,
486
- temperature=temperature,
487
- air_density=air_density,
488
- water_density=water_density,
489
- g=g,
490
- )
491
- fall_velocity = air_viscosity * reynolds_number / (air_density * diameter)
492
- return fall_velocity
481
+ delta_density = water_density - air_density
482
+ drag_coefficient = 4 * delta_density * g * diameter / (3 * air_density * fall_velocity**2)
483
+ return drag_coefficient
493
484
 
494
485
 
495
- def get_drag_coefficient(diameter, air_density, water_density, fall_velocity, g=9.81):
486
+ def get_fall_velocity_beard_1976(diameter, temperature, air_density, water_density, g):
496
487
  """
497
- Computes the drag coefficient for a raindrop.
488
+ Computes the terminal fall velocity of a raindrop in still air.
489
+
490
+ Reference: Beard 1976; Pruppacher & Klett 1978
498
491
 
499
492
  Parameters
500
493
  ----------
501
494
  diameter : float
502
495
  Diameter of the raindrop in meters.
496
+ temperature : float
497
+ Temperature in Kelvin.
503
498
  air_density : float
504
499
  Density of air in kg/m^3.
505
500
  water_density : float
506
501
  Density of water in kg/m^3.
507
- fall_velocity : float
508
- Terminal fall velocity of the raindrop in m/s.
509
502
  g : float
510
503
  Gravitational acceleration in m/s^2.
511
504
 
512
505
  Returns
513
506
  -------
514
507
  float
515
- Drag coefficient of the raindrop.
508
+ Terminal fall velocity of the raindrop in m/s.
516
509
  """
517
- delta_density = water_density - air_density
518
- drag_coefficient = 4 * delta_density * g * diameter / (3 * air_density * fall_velocity**2)
519
- return drag_coefficient
510
+ air_viscosity = get_air_dynamic_viscosity(temperature)
511
+ reynolds_number = get_raindrop_reynolds_number(
512
+ diameter=diameter,
513
+ temperature=temperature,
514
+ air_density=air_density,
515
+ water_density=water_density,
516
+ g=g,
517
+ )
518
+ fall_velocity = air_viscosity * reynolds_number / (air_density * diameter)
519
+ return fall_velocity
520
520
 
521
521
 
522
522
  def retrieve_fall_velocity(
@@ -573,19 +573,24 @@ def retrieve_fall_velocity(
573
573
  gas_constant_dry_air=gas_constant_dry_air,
574
574
  )
575
575
 
576
+ # else
577
+ # --> Estimate sea_level_air_pressure from air_pressure ?
578
+
576
579
  # Retrieve vapour pressure (from relative humidity)
577
580
  vapor_pressure = get_vapor_actual_pressure(
578
581
  relative_humidity=relative_humidity,
579
582
  temperature=temperature,
580
583
  )
581
584
 
582
- # Retrieve air density and water density
585
+ # Retrieve air density
583
586
  air_density = get_air_density(
584
587
  temperature=temperature,
585
588
  air_pressure=air_pressure,
586
589
  vapor_pressure=vapor_pressure,
587
590
  gas_constant_dry_air=gas_constant_dry_air,
588
591
  )
592
+
593
+ # Retrieve water density
589
594
  water_density = get_water_density(
590
595
  temperature=temperature,
591
596
  air_pressure=air_pressure,
@@ -611,106 +616,3 @@ def retrieve_fall_velocity(
611
616
  # fall_velocity=fall_velocity)
612
617
 
613
618
  return fall_velocity
614
-
615
-
616
- ####-----------------------------------------------------------------------------------------
617
- #### OLD CODE
618
-
619
-
620
- # def get_fall_velocity_beard_1977(diameter):
621
- # """
622
- # Compute the fall velocity of raindrops using the Beard (1977) relationship.
623
-
624
- # Parameters
625
- # ----------
626
- # diameter : array-like
627
- # Diameter of the raindrops in millimeters.
628
- # Valid up to 7 mm (0.7 cm).
629
-
630
- # Returns
631
- # -------
632
- # fall_velocity : array-like
633
- # Fall velocities in meters per second.
634
-
635
- # Notes
636
- # -----
637
- # This method uses an exponential function based on the work of Beard (1977),
638
- # valid at sea level conditions (pressure = 1 atm, temperature = 20°C,
639
- # air density = 1.194 kg/m³).
640
-
641
- # References
642
- # ----------
643
- # Beard, K. V. (1977).
644
- # Terminal velocity adjustment for cloud and precipitation drops aloft.
645
- # Journal of the Atmospheric Sciences, 34(8), 1293-1298.
646
- # https://doi.org/10.1175/1520-0469(1977)034<1293:TVAFCA>2.0.CO;2
647
-
648
- # """
649
- # diameter_cm = diameter/1000
650
- # c = [7.06037, 1.74951, 4.86324, 6.60631, 4.84606, 2.14922, 0.58714, 0.096348, 0.00869209, 0.00033089]
651
- # log_diameter = np.log(diameter_cm)
652
- # y = c[0] + sum(c * log_diameter**i for i, c in enumerate(c[1:], start=1))
653
- # fall_velocity = np.exp(y)
654
- # return fall_velocity
655
-
656
-
657
- # def get_fall_velocity_beard_1977(diameter, temperature, air_pressure, gas_constant_dry_air=287.04):
658
- # """
659
- # Computes the terminal fall velocity of a raindrop in still air.
660
-
661
- # This function is based on the Table 4 coefficients of Kenneth V. Beard (1977),
662
- # "Terminal Velocity and Shape of Cloud and Precipitation Drops Aloft",
663
- # Journal of the Atmospheric Sciences, Vol. 34, pp. 1293-1298.
664
-
665
- # Note: This approximation is valid at sea level with conditions:
666
- # Pressure = 1 atm, Temperature = 20°C, (saturated) air density = 1.194 kg/m³.
667
-
668
- # Parameters
669
- # ----------
670
- # diameter : array-like
671
- # Array of equivolume drop diameters in meters.
672
-
673
- # Returns
674
- # -------
675
- # fall_velocity : array-like
676
- # Array of terminal fall velocity in meters per second (m/s).
677
- # For diameters greater than 7 mm, the function returns NaN.
678
-
679
- # """
680
- # # PROBLEMATIC
681
- # # Compute sea level velocity
682
- # c = [7.06037, 1.74951, 4.86324, 6.60631, 4.84606, 2.14922, 0.58714, 0.096348, 0.00869209, 0.00033089]
683
- # log_diameter = np.log(diameter / 1000 * 10)
684
- # y = c[0] + sum(c * log_diameter**i for i, c in enumerate(c[1:], start=1))
685
- # v0 = np.exp(y)
686
-
687
- # # Compute fall velocity
688
- # t_20 = 273.15 + 20
689
- # eps_s = get_air_dynamic_viscosity(t_20) / get_air_dynamic_viscosity(temperature) - 1
690
- # eps_c = -1 + (
691
- # np.sqrt(
692
- # get_air_density(
693
- # temperature=t_20,
694
- # air_pressure=101325,
695
- # vapor_pressure=0,
696
- # gas_constant_dry_air=gas_constant_dry_air,
697
- # )
698
- # / get_air_density(
699
- # temperature=temperature,
700
- # air_pressure=air_pressure,
701
- # vapor_pressure=0,
702
- # gas_constant_dry_air=gas_constant_dry_air,
703
- # ),
704
- # )
705
- # )
706
- # a = 1.104 * eps_s
707
- # b = (1.058 * eps_c - 1.104 * eps_s) / 5.01
708
- # x = np.log(diameter) + 5.52
709
- # f = (a + b * x) + 1
710
- # fall_velocity = v0 * f
711
- # # fall_velocity.plot()
712
-
713
- # eps = 1.104 * eps_s + (1.058 * eps_c - 1.104 * eps_s) * np.log(diameter / 1e-3) / 5.01
714
- # # eps = 1.104 * eps_s + (1.058 * eps_c - 1.104 * eps_s) * np.log(diameter / 4e-5) / 5.01
715
- # fall_velocity = 0.01 * v0 * (1 + eps)
716
- # return fall_velocity