cloudnetpy 1.82.0__tar.gz → 1.82.2__tar.gz

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 (132) hide show
  1. {cloudnetpy-1.82.0/cloudnetpy.egg-info → cloudnetpy-1.82.2}/PKG-INFO +1 -1
  2. {cloudnetpy-1.82.0 → cloudnetpy-1.82.2}/cloudnetpy/categorize/falling.py +3 -2
  3. {cloudnetpy-1.82.0 → cloudnetpy-1.82.2}/cloudnetpy/categorize/melting.py +3 -1
  4. {cloudnetpy-1.82.0 → cloudnetpy-1.82.2}/cloudnetpy/categorize/model.py +1 -1
  5. {cloudnetpy-1.82.0 → cloudnetpy-1.82.2}/cloudnetpy/instruments/pollyxt.py +2 -1
  6. {cloudnetpy-1.82.0 → cloudnetpy-1.82.2}/cloudnetpy/instruments/rpg_reader.py +5 -0
  7. {cloudnetpy-1.82.0 → cloudnetpy-1.82.2}/cloudnetpy/instruments/weather_station.py +12 -0
  8. {cloudnetpy-1.82.0 → cloudnetpy-1.82.2}/cloudnetpy/output.py +38 -32
  9. {cloudnetpy-1.82.0 → cloudnetpy-1.82.2}/cloudnetpy/products/epsilon.py +5 -0
  10. {cloudnetpy-1.82.0 → cloudnetpy-1.82.2}/cloudnetpy/utils.py +1 -1
  11. {cloudnetpy-1.82.0 → cloudnetpy-1.82.2}/cloudnetpy/version.py +1 -1
  12. {cloudnetpy-1.82.0 → cloudnetpy-1.82.2/cloudnetpy.egg-info}/PKG-INFO +1 -1
  13. {cloudnetpy-1.82.0 → cloudnetpy-1.82.2}/LICENSE +0 -0
  14. {cloudnetpy-1.82.0 → cloudnetpy-1.82.2}/MANIFEST.in +0 -0
  15. {cloudnetpy-1.82.0 → cloudnetpy-1.82.2}/README.md +0 -0
  16. {cloudnetpy-1.82.0 → cloudnetpy-1.82.2}/cloudnetpy/__init__.py +0 -0
  17. {cloudnetpy-1.82.0 → cloudnetpy-1.82.2}/cloudnetpy/categorize/__init__.py +0 -0
  18. {cloudnetpy-1.82.0 → cloudnetpy-1.82.2}/cloudnetpy/categorize/atmos_utils.py +0 -0
  19. {cloudnetpy-1.82.0 → cloudnetpy-1.82.2}/cloudnetpy/categorize/attenuation.py +0 -0
  20. {cloudnetpy-1.82.0 → cloudnetpy-1.82.2}/cloudnetpy/categorize/attenuations/__init__.py +0 -0
  21. {cloudnetpy-1.82.0 → cloudnetpy-1.82.2}/cloudnetpy/categorize/attenuations/gas_attenuation.py +0 -0
  22. {cloudnetpy-1.82.0 → cloudnetpy-1.82.2}/cloudnetpy/categorize/attenuations/liquid_attenuation.py +0 -0
  23. {cloudnetpy-1.82.0 → cloudnetpy-1.82.2}/cloudnetpy/categorize/attenuations/melting_attenuation.py +0 -0
  24. {cloudnetpy-1.82.0 → cloudnetpy-1.82.2}/cloudnetpy/categorize/attenuations/rain_attenuation.py +0 -0
  25. {cloudnetpy-1.82.0 → cloudnetpy-1.82.2}/cloudnetpy/categorize/categorize.py +0 -0
  26. {cloudnetpy-1.82.0 → cloudnetpy-1.82.2}/cloudnetpy/categorize/classify.py +0 -0
  27. {cloudnetpy-1.82.0 → cloudnetpy-1.82.2}/cloudnetpy/categorize/containers.py +0 -0
  28. {cloudnetpy-1.82.0 → cloudnetpy-1.82.2}/cloudnetpy/categorize/disdrometer.py +0 -0
  29. {cloudnetpy-1.82.0 → cloudnetpy-1.82.2}/cloudnetpy/categorize/droplet.py +0 -0
  30. {cloudnetpy-1.82.0 → cloudnetpy-1.82.2}/cloudnetpy/categorize/freezing.py +0 -0
  31. {cloudnetpy-1.82.0 → cloudnetpy-1.82.2}/cloudnetpy/categorize/insects.py +0 -0
  32. {cloudnetpy-1.82.0 → cloudnetpy-1.82.2}/cloudnetpy/categorize/itu.py +0 -0
  33. {cloudnetpy-1.82.0 → cloudnetpy-1.82.2}/cloudnetpy/categorize/lidar.py +0 -0
  34. {cloudnetpy-1.82.0 → cloudnetpy-1.82.2}/cloudnetpy/categorize/mwr.py +0 -0
  35. {cloudnetpy-1.82.0 → cloudnetpy-1.82.2}/cloudnetpy/categorize/radar.py +0 -0
  36. {cloudnetpy-1.82.0 → cloudnetpy-1.82.2}/cloudnetpy/cli.py +0 -0
  37. {cloudnetpy-1.82.0 → cloudnetpy-1.82.2}/cloudnetpy/cloudnetarray.py +0 -0
  38. {cloudnetpy-1.82.0 → cloudnetpy-1.82.2}/cloudnetpy/concat_lib.py +0 -0
  39. {cloudnetpy-1.82.0 → cloudnetpy-1.82.2}/cloudnetpy/constants.py +0 -0
  40. {cloudnetpy-1.82.0 → cloudnetpy-1.82.2}/cloudnetpy/datasource.py +0 -0
  41. {cloudnetpy-1.82.0 → cloudnetpy-1.82.2}/cloudnetpy/exceptions.py +0 -0
  42. {cloudnetpy-1.82.0 → cloudnetpy-1.82.2}/cloudnetpy/instruments/__init__.py +0 -0
  43. {cloudnetpy-1.82.0 → cloudnetpy-1.82.2}/cloudnetpy/instruments/basta.py +0 -0
  44. {cloudnetpy-1.82.0 → cloudnetpy-1.82.2}/cloudnetpy/instruments/bowtie.py +0 -0
  45. {cloudnetpy-1.82.0 → cloudnetpy-1.82.2}/cloudnetpy/instruments/ceilo.py +0 -0
  46. {cloudnetpy-1.82.0 → cloudnetpy-1.82.2}/cloudnetpy/instruments/ceilometer.py +0 -0
  47. {cloudnetpy-1.82.0 → cloudnetpy-1.82.2}/cloudnetpy/instruments/cl61d.py +0 -0
  48. {cloudnetpy-1.82.0 → cloudnetpy-1.82.2}/cloudnetpy/instruments/cloudnet_instrument.py +0 -0
  49. {cloudnetpy-1.82.0 → cloudnetpy-1.82.2}/cloudnetpy/instruments/copernicus.py +0 -0
  50. {cloudnetpy-1.82.0 → cloudnetpy-1.82.2}/cloudnetpy/instruments/disdrometer/__init__.py +0 -0
  51. {cloudnetpy-1.82.0 → cloudnetpy-1.82.2}/cloudnetpy/instruments/disdrometer/common.py +0 -0
  52. {cloudnetpy-1.82.0 → cloudnetpy-1.82.2}/cloudnetpy/instruments/disdrometer/parsivel.py +0 -0
  53. {cloudnetpy-1.82.0 → cloudnetpy-1.82.2}/cloudnetpy/instruments/disdrometer/thies.py +0 -0
  54. {cloudnetpy-1.82.0 → cloudnetpy-1.82.2}/cloudnetpy/instruments/fd12p.py +0 -0
  55. {cloudnetpy-1.82.0 → cloudnetpy-1.82.2}/cloudnetpy/instruments/galileo.py +0 -0
  56. {cloudnetpy-1.82.0 → cloudnetpy-1.82.2}/cloudnetpy/instruments/hatpro.py +0 -0
  57. {cloudnetpy-1.82.0 → cloudnetpy-1.82.2}/cloudnetpy/instruments/instruments.py +0 -0
  58. {cloudnetpy-1.82.0 → cloudnetpy-1.82.2}/cloudnetpy/instruments/lufft.py +0 -0
  59. {cloudnetpy-1.82.0 → cloudnetpy-1.82.2}/cloudnetpy/instruments/mira.py +0 -0
  60. {cloudnetpy-1.82.0 → cloudnetpy-1.82.2}/cloudnetpy/instruments/mrr.py +0 -0
  61. {cloudnetpy-1.82.0 → cloudnetpy-1.82.2}/cloudnetpy/instruments/nc_lidar.py +0 -0
  62. {cloudnetpy-1.82.0 → cloudnetpy-1.82.2}/cloudnetpy/instruments/nc_radar.py +0 -0
  63. {cloudnetpy-1.82.0 → cloudnetpy-1.82.2}/cloudnetpy/instruments/radiometrics.py +0 -0
  64. {cloudnetpy-1.82.0 → cloudnetpy-1.82.2}/cloudnetpy/instruments/rain_e_h3.py +0 -0
  65. {cloudnetpy-1.82.0 → cloudnetpy-1.82.2}/cloudnetpy/instruments/rpg.py +0 -0
  66. {cloudnetpy-1.82.0 → cloudnetpy-1.82.2}/cloudnetpy/instruments/toa5.py +0 -0
  67. {cloudnetpy-1.82.0 → cloudnetpy-1.82.2}/cloudnetpy/instruments/vaisala.py +0 -0
  68. {cloudnetpy-1.82.0 → cloudnetpy-1.82.2}/cloudnetpy/metadata.py +0 -0
  69. {cloudnetpy-1.82.0 → cloudnetpy-1.82.2}/cloudnetpy/model_evaluation/__init__.py +0 -0
  70. {cloudnetpy-1.82.0 → cloudnetpy-1.82.2}/cloudnetpy/model_evaluation/file_handler.py +0 -0
  71. {cloudnetpy-1.82.0 → cloudnetpy-1.82.2}/cloudnetpy/model_evaluation/metadata.py +0 -0
  72. {cloudnetpy-1.82.0 → cloudnetpy-1.82.2}/cloudnetpy/model_evaluation/model_metadata.py +0 -0
  73. {cloudnetpy-1.82.0 → cloudnetpy-1.82.2}/cloudnetpy/model_evaluation/plotting/__init__.py +0 -0
  74. {cloudnetpy-1.82.0 → cloudnetpy-1.82.2}/cloudnetpy/model_evaluation/plotting/plot_meta.py +0 -0
  75. {cloudnetpy-1.82.0 → cloudnetpy-1.82.2}/cloudnetpy/model_evaluation/plotting/plot_tools.py +0 -0
  76. {cloudnetpy-1.82.0 → cloudnetpy-1.82.2}/cloudnetpy/model_evaluation/plotting/plotting.py +0 -0
  77. {cloudnetpy-1.82.0 → cloudnetpy-1.82.2}/cloudnetpy/model_evaluation/products/__init__.py +0 -0
  78. {cloudnetpy-1.82.0 → cloudnetpy-1.82.2}/cloudnetpy/model_evaluation/products/advance_methods.py +0 -0
  79. {cloudnetpy-1.82.0 → cloudnetpy-1.82.2}/cloudnetpy/model_evaluation/products/grid_methods.py +0 -0
  80. {cloudnetpy-1.82.0 → cloudnetpy-1.82.2}/cloudnetpy/model_evaluation/products/model_products.py +0 -0
  81. {cloudnetpy-1.82.0 → cloudnetpy-1.82.2}/cloudnetpy/model_evaluation/products/observation_products.py +0 -0
  82. {cloudnetpy-1.82.0 → cloudnetpy-1.82.2}/cloudnetpy/model_evaluation/products/product_resampling.py +0 -0
  83. {cloudnetpy-1.82.0 → cloudnetpy-1.82.2}/cloudnetpy/model_evaluation/products/tools.py +0 -0
  84. {cloudnetpy-1.82.0 → cloudnetpy-1.82.2}/cloudnetpy/model_evaluation/statistics/__init__.py +0 -0
  85. {cloudnetpy-1.82.0 → cloudnetpy-1.82.2}/cloudnetpy/model_evaluation/statistics/statistical_methods.py +0 -0
  86. {cloudnetpy-1.82.0 → cloudnetpy-1.82.2}/cloudnetpy/model_evaluation/tests/__init__.py +0 -0
  87. {cloudnetpy-1.82.0 → cloudnetpy-1.82.2}/cloudnetpy/model_evaluation/tests/e2e/__init__.py +0 -0
  88. {cloudnetpy-1.82.0 → cloudnetpy-1.82.2}/cloudnetpy/model_evaluation/tests/e2e/conftest.py +0 -0
  89. {cloudnetpy-1.82.0 → cloudnetpy-1.82.2}/cloudnetpy/model_evaluation/tests/e2e/process_cf/__init__.py +0 -0
  90. {cloudnetpy-1.82.0 → cloudnetpy-1.82.2}/cloudnetpy/model_evaluation/tests/e2e/process_cf/main.py +0 -0
  91. {cloudnetpy-1.82.0 → cloudnetpy-1.82.2}/cloudnetpy/model_evaluation/tests/e2e/process_cf/tests.py +0 -0
  92. {cloudnetpy-1.82.0 → cloudnetpy-1.82.2}/cloudnetpy/model_evaluation/tests/e2e/process_iwc/__init__.py +0 -0
  93. {cloudnetpy-1.82.0 → cloudnetpy-1.82.2}/cloudnetpy/model_evaluation/tests/e2e/process_iwc/main.py +0 -0
  94. {cloudnetpy-1.82.0 → cloudnetpy-1.82.2}/cloudnetpy/model_evaluation/tests/e2e/process_iwc/tests.py +0 -0
  95. {cloudnetpy-1.82.0 → cloudnetpy-1.82.2}/cloudnetpy/model_evaluation/tests/e2e/process_lwc/__init__.py +0 -0
  96. {cloudnetpy-1.82.0 → cloudnetpy-1.82.2}/cloudnetpy/model_evaluation/tests/e2e/process_lwc/main.py +0 -0
  97. {cloudnetpy-1.82.0 → cloudnetpy-1.82.2}/cloudnetpy/model_evaluation/tests/e2e/process_lwc/tests.py +0 -0
  98. {cloudnetpy-1.82.0 → cloudnetpy-1.82.2}/cloudnetpy/model_evaluation/tests/unit/__init__.py +0 -0
  99. {cloudnetpy-1.82.0 → cloudnetpy-1.82.2}/cloudnetpy/model_evaluation/tests/unit/conftest.py +0 -0
  100. {cloudnetpy-1.82.0 → cloudnetpy-1.82.2}/cloudnetpy/model_evaluation/tests/unit/test_advance_methods.py +0 -0
  101. {cloudnetpy-1.82.0 → cloudnetpy-1.82.2}/cloudnetpy/model_evaluation/tests/unit/test_grid_methods.py +0 -0
  102. {cloudnetpy-1.82.0 → cloudnetpy-1.82.2}/cloudnetpy/model_evaluation/tests/unit/test_model_products.py +0 -0
  103. {cloudnetpy-1.82.0 → cloudnetpy-1.82.2}/cloudnetpy/model_evaluation/tests/unit/test_observation_products.py +0 -0
  104. {cloudnetpy-1.82.0 → cloudnetpy-1.82.2}/cloudnetpy/model_evaluation/tests/unit/test_plot_tools.py +0 -0
  105. {cloudnetpy-1.82.0 → cloudnetpy-1.82.2}/cloudnetpy/model_evaluation/tests/unit/test_plotting.py +0 -0
  106. {cloudnetpy-1.82.0 → cloudnetpy-1.82.2}/cloudnetpy/model_evaluation/tests/unit/test_statistical_methods.py +0 -0
  107. {cloudnetpy-1.82.0 → cloudnetpy-1.82.2}/cloudnetpy/model_evaluation/tests/unit/test_tools.py +0 -0
  108. {cloudnetpy-1.82.0 → cloudnetpy-1.82.2}/cloudnetpy/model_evaluation/utils.py +0 -0
  109. {cloudnetpy-1.82.0 → cloudnetpy-1.82.2}/cloudnetpy/plotting/__init__.py +0 -0
  110. {cloudnetpy-1.82.0 → cloudnetpy-1.82.2}/cloudnetpy/plotting/plot_meta.py +0 -0
  111. {cloudnetpy-1.82.0 → cloudnetpy-1.82.2}/cloudnetpy/plotting/plotting.py +0 -0
  112. {cloudnetpy-1.82.0 → cloudnetpy-1.82.2}/cloudnetpy/products/__init__.py +0 -0
  113. {cloudnetpy-1.82.0 → cloudnetpy-1.82.2}/cloudnetpy/products/classification.py +0 -0
  114. {cloudnetpy-1.82.0 → cloudnetpy-1.82.2}/cloudnetpy/products/der.py +0 -0
  115. {cloudnetpy-1.82.0 → cloudnetpy-1.82.2}/cloudnetpy/products/drizzle.py +0 -0
  116. {cloudnetpy-1.82.0 → cloudnetpy-1.82.2}/cloudnetpy/products/drizzle_error.py +0 -0
  117. {cloudnetpy-1.82.0 → cloudnetpy-1.82.2}/cloudnetpy/products/drizzle_tools.py +0 -0
  118. {cloudnetpy-1.82.0 → cloudnetpy-1.82.2}/cloudnetpy/products/ier.py +0 -0
  119. {cloudnetpy-1.82.0 → cloudnetpy-1.82.2}/cloudnetpy/products/iwc.py +0 -0
  120. {cloudnetpy-1.82.0 → cloudnetpy-1.82.2}/cloudnetpy/products/lwc.py +0 -0
  121. {cloudnetpy-1.82.0 → cloudnetpy-1.82.2}/cloudnetpy/products/mie_lu_tables.nc +0 -0
  122. {cloudnetpy-1.82.0 → cloudnetpy-1.82.2}/cloudnetpy/products/mwr_tools.py +0 -0
  123. {cloudnetpy-1.82.0 → cloudnetpy-1.82.2}/cloudnetpy/products/product_tools.py +0 -0
  124. {cloudnetpy-1.82.0 → cloudnetpy-1.82.2}/cloudnetpy/py.typed +0 -0
  125. {cloudnetpy-1.82.0 → cloudnetpy-1.82.2}/cloudnetpy.egg-info/SOURCES.txt +0 -0
  126. {cloudnetpy-1.82.0 → cloudnetpy-1.82.2}/cloudnetpy.egg-info/dependency_links.txt +0 -0
  127. {cloudnetpy-1.82.0 → cloudnetpy-1.82.2}/cloudnetpy.egg-info/entry_points.txt +0 -0
  128. {cloudnetpy-1.82.0 → cloudnetpy-1.82.2}/cloudnetpy.egg-info/requires.txt +0 -0
  129. {cloudnetpy-1.82.0 → cloudnetpy-1.82.2}/cloudnetpy.egg-info/top_level.txt +0 -0
  130. {cloudnetpy-1.82.0 → cloudnetpy-1.82.2}/docs/source/conf.py +0 -0
  131. {cloudnetpy-1.82.0 → cloudnetpy-1.82.2}/pyproject.toml +0 -0
  132. {cloudnetpy-1.82.0 → cloudnetpy-1.82.2}/setup.cfg +0 -0
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: cloudnetpy
3
- Version: 1.82.0
3
+ Version: 1.82.2
4
4
  Summary: Python package for Cloudnet processing
5
5
  Author: Simo Tukiainen
6
6
  License: MIT License
@@ -115,10 +115,11 @@ def _fix_liquid_dominated_radar(
115
115
 
116
116
 
117
117
  def _is_z_missing_above_liquid(z: ma.MaskedArray, ind_top: int) -> bool:
118
- """Checks is z is masked right above the liquid layer top."""
118
+ """Checks if z is masked right above the liquid layer top."""
119
119
  if ind_top == len(z) - 1:
120
120
  return False
121
- return z.mask[ind_top + 1]
121
+ mask = ma.getmaskarray(z)
122
+ return bool(mask[ind_top + 1])
122
123
 
123
124
 
124
125
  def _is_z_increasing(z: ma.MaskedArray, ind_base: int, ind_top: int) -> bool:
@@ -76,7 +76,9 @@ def find_melting_layer(obs: ClassData, *, smooth: bool = True) -> npt.NDArray:
76
76
  ldr_prof = obs.ldr[ind, temp_indices]
77
77
  ldr_dprof = ldr_diff[ind, temp_indices]
78
78
 
79
- if ma.count(ldr_prof) > 3 or ma.count(v_prof) > 3:
79
+ if (ldr_prof is not None and ma.count(ldr_prof) > 3) or (
80
+ v_prof is not None and ma.count(v_prof) > 3
81
+ ):
80
82
  try:
81
83
  if ldr_prof is None or ldr_dprof is None:
82
84
  msg = "ldr_prof or ldr_dprof is None"
@@ -182,4 +182,4 @@ def _find_model_type(file_name: str | PathLike) -> str:
182
182
  def _find_number_of_valid_profiles(array: npt.NDArray) -> int:
183
183
  mask = ma.getmaskarray(array)
184
184
  all_masked_profiles = np.all(mask, axis=1)
185
- return np.count_nonzero(~all_masked_profiles)
185
+ return int(np.count_nonzero(~all_masked_profiles))
@@ -246,7 +246,8 @@ def _read_array_from_file_pair(
246
246
 
247
247
 
248
248
  def _only_zeros_or_masked(data: ma.MaskedArray) -> bool:
249
- return ma.sum(data) == 0 or data.mask.all()
249
+ mask = ma.getmaskarray(data)
250
+ return ma.sum(data) == 0 or mask.all()
250
251
 
251
252
 
252
253
  ATTRIBUTES = {
@@ -326,6 +326,11 @@ class HatproBinCombined:
326
326
  else:
327
327
  msg = "Only implemented up to 2 files"
328
328
  raise NotImplementedError(msg)
329
+
330
+ if arr.dtype.fields is None:
331
+ msg = "Data has no fields"
332
+ raise ValueError(msg)
333
+
329
334
  self.data = {field: arr[field] for field in arr.dtype.fields}
330
335
 
331
336
 
@@ -79,12 +79,14 @@ def ws2nc(
79
79
  ws.add_date()
80
80
  ws.add_site_geolocation()
81
81
  ws.add_data()
82
+ ws.remove_duplicate_timestamps()
82
83
  ws.convert_temperature_and_humidity()
83
84
  ws.convert_pressure()
84
85
  ws.convert_rainfall_rate()
85
86
  ws.convert_rainfall_amount()
86
87
  ws.normalize_cumulative_amount("rainfall_amount")
87
88
  ws.calculate_rainfall_amount()
89
+ ws.wrap_wind_direction()
88
90
  attributes = output.add_time_attribute({}, ws.date)
89
91
  output.update_attributes(ws.data, attributes)
90
92
  output.save_level1b(ws, output_file, uuid)
@@ -148,6 +150,16 @@ class WS(CSVFile):
148
150
  def convert_rainfall_amount(self) -> None:
149
151
  pass
150
152
 
153
+ def wrap_wind_direction(self) -> None:
154
+ if "wind_direction" not in self.data:
155
+ return
156
+ # Wrap values little outside of [0, 360), keep original values
157
+ # otherwise.
158
+ threshold = 2
159
+ values = self.data["wind_direction"].data
160
+ values[(values > -threshold) & (values < 0)] += 360
161
+ values[(values >= 360) & (values < 360 + threshold)] -= 360
162
+
151
163
 
152
164
  class PalaiseauWS(WS):
153
165
  def __init__(self, filenames: Sequence[str | PathLike], site_meta: dict) -> None:
@@ -197,46 +197,52 @@ def get_source_uuids(data: Observations | list[netCDF4.Dataset | DataSource]) ->
197
197
  def merge_history(
198
198
  nc: netCDF4.Dataset, file_type: str, data: Observations | DataSource
199
199
  ) -> None:
200
- """Merges history fields from one or several files and creates a new record.
200
+ """Merges history fields from one or several files and creates a new record."""
201
+
202
+ def extract_history(obj: DataSource | Observations) -> list[str]:
203
+ if hasattr(obj, "dataset") and hasattr(obj.dataset, "history"):
204
+ history = obj.dataset.history
205
+ if isinstance(obj, Model):
206
+ return [history.split("\n")[-1]]
207
+ return history.split("\n")
208
+ return []
209
+
210
+ histories: list[str] = []
211
+ if isinstance(data, DataSource):
212
+ histories.extend(extract_history(data))
213
+ elif isinstance(data, Observations):
214
+ for field in fields(data):
215
+ histories.extend(extract_history(getattr(data, field.name)))
201
216
 
202
- Args:
203
- nc: The netCDF Dataset instance.
204
- file_type: Long description of the file.
205
- data: Dictionary of objects with history attribute.
217
+ # Remove duplicates
218
+ histories = list(dict.fromkeys(histories))
206
219
 
207
- """
220
+ def parse_time(line: str) -> datetime.datetime:
221
+ try:
222
+ return datetime.datetime.strptime(
223
+ line.split(" - ")[0].strip(), "%Y-%m-%d %H:%M:%S %z"
224
+ )
225
+ except ValueError:
226
+ return datetime.datetime.min.replace(
227
+ tzinfo=datetime.timezone.utc
228
+ ) # malformed lines to bottom
229
+
230
+ histories.sort(key=parse_time, reverse=True)
208
231
  new_record = f"{utils.get_time()} - {file_type} file created"
209
- histories = []
210
- if (
211
- isinstance(data, DataSource)
212
- and hasattr(data, "dataset")
213
- and hasattr(data.dataset, "history")
214
- ):
215
- history = data.dataset.history
216
- histories.append(history)
217
- if isinstance(data, Observations):
218
- for field in fields(data):
219
- obj = getattr(data, field.name)
220
- if hasattr(obj, "dataset") and hasattr(obj.dataset, "history"):
221
- history = obj.dataset.history
222
- history = history.split("\n")[-1] if isinstance(obj, Model) else history
223
- histories.append(history)
224
- histories.sort(reverse=True)
225
- old_history = [f"\n{history}" for history in histories]
226
- old_history_str = "".join(old_history)
227
- nc.history = f"{new_record}{old_history_str}"
232
+ nc.history = new_record + "".join(f"\n{h}" for h in histories)
228
233
 
229
234
 
230
235
  def add_source_instruments(nc: netCDF4.Dataset, data: Observations) -> None:
231
236
  """Adds source attribute to categorize file."""
232
- sources = []
233
- for field in fields(data):
234
- obj = getattr(data, field.name)
235
- if hasattr(obj, "source"):
236
- sources.append(obj.source)
237
+ sources = {
238
+ src
239
+ for field in fields(data)
240
+ for obj in [getattr(data, field.name)]
241
+ if hasattr(obj, "source")
242
+ for src in obj.source.split("\n")
243
+ }
237
244
  if sources:
238
- formatted_sources = [sources[0]] + [f"\n{source}" for source in sources[1:]]
239
- nc.source = "".join(formatted_sources)
245
+ nc.source = "\n".join(sorted(sources))
240
246
 
241
247
 
242
248
  def init_file(
@@ -137,6 +137,11 @@ def _horizontal_wind_from_doppler_lidar_file(
137
137
  raise ValidTimeStampError
138
138
  t = np.broadcast_to(time[:, None], mask.shape)[~mask]
139
139
  h = np.broadcast_to(height[None, :], mask.shape)[~mask]
140
+
141
+ if len(np.unique(t)) < 2 or len(np.unique(h)) < 2:
142
+ msg = "Not enough unique values for interpolation"
143
+ raise ValidTimeStampError(msg)
144
+
140
145
  interp_linear = LinearNDInterpolator(list(zip(t, h, strict=False)), V[~mask])
141
146
  interp_nearest = NearestNDInterpolator(list(zip(t, h, strict=False)), V[~mask])
142
147
  T, H = np.meshgrid(time, height, indexing="ij")
@@ -371,7 +371,7 @@ def interpolate_2d_mask(
371
371
  method="linear",
372
372
  )
373
373
  # Preserve mask:
374
- mask_fun = RectBivariateSpline(x, y, z.mask[:], kx=1, ky=1)
374
+ mask_fun = RectBivariateSpline(x, y, ma.getmaskarray(z), kx=1, ky=1)
375
375
  mask = mask_fun(x_new, y_new)
376
376
  mask[mask < 0.5] = 0
377
377
  masked_array = ma.array(data, mask=mask.astype(bool))
@@ -1,4 +1,4 @@
1
1
  MAJOR = 1
2
2
  MINOR = 82
3
- PATCH = 0
3
+ PATCH = 2
4
4
  __version__ = f"{MAJOR}.{MINOR}.{PATCH}"
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: cloudnetpy
3
- Version: 1.82.0
3
+ Version: 1.82.2
4
4
  Summary: Python package for Cloudnet processing
5
5
  Author: Simo Tukiainen
6
6
  License: MIT License
File without changes
File without changes
File without changes
File without changes
File without changes