ctao-calibpipe 0.1.0__py3-none-any.whl

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.

Potentially problematic release.


This version of ctao-calibpipe might be problematic. Click here for more details.

Files changed (93) hide show
  1. calibpipe/__init__.py +5 -0
  2. calibpipe/_dev_version/__init__.py +9 -0
  3. calibpipe/_version.py +21 -0
  4. calibpipe/atmosphere/__init__.py +1 -0
  5. calibpipe/atmosphere/atmosphere_containers.py +109 -0
  6. calibpipe/atmosphere/meteo_data_handlers.py +485 -0
  7. calibpipe/atmosphere/models/README.md +14 -0
  8. calibpipe/atmosphere/models/__init__.py +1 -0
  9. calibpipe/atmosphere/models/macobac.ecsv +23 -0
  10. calibpipe/atmosphere/models/reference_MDPs/__init__.py +1 -0
  11. calibpipe/atmosphere/models/reference_MDPs/ref_density_at_15km_ctao-north_intermediate.ecsv +8 -0
  12. calibpipe/atmosphere/models/reference_MDPs/ref_density_at_15km_ctao-north_summer.ecsv +8 -0
  13. calibpipe/atmosphere/models/reference_MDPs/ref_density_at_15km_ctao-north_winter.ecsv +8 -0
  14. calibpipe/atmosphere/models/reference_MDPs/ref_density_at_15km_ctao-south_summer.ecsv +8 -0
  15. calibpipe/atmosphere/models/reference_MDPs/ref_density_at_15km_ctao-south_winter.ecsv +8 -0
  16. calibpipe/atmosphere/models/reference_atmospheres/__init__.py +1 -0
  17. calibpipe/atmosphere/models/reference_atmospheres/reference_atmo_model_v0_ctao-north_intermediate.ecsv +73 -0
  18. calibpipe/atmosphere/models/reference_atmospheres/reference_atmo_model_v0_ctao-north_summer.ecsv +73 -0
  19. calibpipe/atmosphere/models/reference_atmospheres/reference_atmo_model_v0_ctao-north_winter.ecsv +73 -0
  20. calibpipe/atmosphere/models/reference_atmospheres/reference_atmo_model_v0_ctao-south_summer.ecsv +73 -0
  21. calibpipe/atmosphere/models/reference_atmospheres/reference_atmo_model_v0_ctao-south_winter.ecsv +73 -0
  22. calibpipe/atmosphere/models/reference_rayleigh_scattering_profiles/__init__.py +1 -0
  23. calibpipe/atmosphere/models/reference_rayleigh_scattering_profiles/reference_rayleigh_extinction_profile_v0_ctao-north_intermediate.ecsv +857 -0
  24. calibpipe/atmosphere/models/reference_rayleigh_scattering_profiles/reference_rayleigh_extinction_profile_v0_ctao-north_summer.ecsv +857 -0
  25. calibpipe/atmosphere/models/reference_rayleigh_scattering_profiles/reference_rayleigh_extinction_profile_v0_ctao-north_winter.ecsv +857 -0
  26. calibpipe/atmosphere/models/reference_rayleigh_scattering_profiles/reference_rayleigh_extinction_profile_v0_ctao-south_summer.ecsv +857 -0
  27. calibpipe/atmosphere/models/reference_rayleigh_scattering_profiles/reference_rayleigh_extinction_profile_v0_ctao-south_winter.ecsv +857 -0
  28. calibpipe/atmosphere/templates/request_templates/__init__.py +1 -0
  29. calibpipe/atmosphere/templates/request_templates/copernicus.json +11 -0
  30. calibpipe/atmosphere/templates/request_templates/gdas.json +12 -0
  31. calibpipe/core/__init__.py +39 -0
  32. calibpipe/core/common_metadata_containers.py +195 -0
  33. calibpipe/core/exceptions.py +87 -0
  34. calibpipe/database/__init__.py +24 -0
  35. calibpipe/database/adapter/__init__.py +23 -0
  36. calibpipe/database/adapter/adapter.py +80 -0
  37. calibpipe/database/adapter/database_containers/__init__.py +61 -0
  38. calibpipe/database/adapter/database_containers/atmosphere.py +199 -0
  39. calibpipe/database/adapter/database_containers/common_metadata.py +148 -0
  40. calibpipe/database/adapter/database_containers/container_map.py +59 -0
  41. calibpipe/database/adapter/database_containers/observatory.py +61 -0
  42. calibpipe/database/adapter/database_containers/table_version_manager.py +39 -0
  43. calibpipe/database/adapter/database_containers/version_control.py +17 -0
  44. calibpipe/database/connections/__init__.py +28 -0
  45. calibpipe/database/connections/calibpipe_database.py +60 -0
  46. calibpipe/database/connections/postgres_utils.py +97 -0
  47. calibpipe/database/connections/sql_connection.py +103 -0
  48. calibpipe/database/connections/user_confirmation.py +19 -0
  49. calibpipe/database/interfaces/__init__.py +71 -0
  50. calibpipe/database/interfaces/hashable_row_data.py +54 -0
  51. calibpipe/database/interfaces/queries.py +180 -0
  52. calibpipe/database/interfaces/sql_column_info.py +67 -0
  53. calibpipe/database/interfaces/sql_metadata.py +6 -0
  54. calibpipe/database/interfaces/sql_table_info.py +131 -0
  55. calibpipe/database/interfaces/table_handler.py +351 -0
  56. calibpipe/database/interfaces/types.py +96 -0
  57. calibpipe/tests/data/atmosphere/molecular_atmosphere/__init__.py +0 -0
  58. calibpipe/tests/data/atmosphere/molecular_atmosphere/contemporary_MDP.ecsv +34 -0
  59. calibpipe/tests/data/atmosphere/molecular_atmosphere/macobac.csv +852 -0
  60. calibpipe/tests/data/atmosphere/molecular_atmosphere/macobac.ecsv +23 -0
  61. calibpipe/tests/data/atmosphere/molecular_atmosphere/merged_file.ecsv +1082 -0
  62. calibpipe/tests/data/atmosphere/molecular_atmosphere/meteo_data_copernicus.ecsv +1082 -0
  63. calibpipe/tests/data/atmosphere/molecular_atmosphere/meteo_data_gdas.ecsv +66 -0
  64. calibpipe/tests/data/atmosphere/molecular_atmosphere/observatory_configurations.json +71 -0
  65. calibpipe/tests/data/utils/__init__.py +0 -0
  66. calibpipe/tests/data/utils/meteo_data_winter_and_summer.ecsv +12992 -0
  67. calibpipe/tests/unittests/atmosphere/astral_testing.py +107 -0
  68. calibpipe/tests/unittests/atmosphere/test_meteo_data_handler.py +775 -0
  69. calibpipe/tests/unittests/atmosphere/test_molecular_atmosphere.py +327 -0
  70. calibpipe/tests/unittests/database/test_table_handler.py +66 -0
  71. calibpipe/tests/unittests/database/test_types.py +38 -0
  72. calibpipe/tests/unittests/test_bootstrap_db.py +79 -0
  73. calibpipe/tests/unittests/utils/test_observatory.py +309 -0
  74. calibpipe/tools/atmospheric_base_tool.py +78 -0
  75. calibpipe/tools/atmospheric_model_db_loader.py +181 -0
  76. calibpipe/tools/basic_tool_with_db.py +38 -0
  77. calibpipe/tools/contemporary_mdp_producer.py +87 -0
  78. calibpipe/tools/init_db.py +37 -0
  79. calibpipe/tools/macobac_calculator.py +82 -0
  80. calibpipe/tools/molecular_atmospheric_model_producer.py +197 -0
  81. calibpipe/tools/observatory_data_db_loader.py +71 -0
  82. calibpipe/tools/reference_atmospheric_model_selector.py +201 -0
  83. calibpipe/utils/__init__.py +10 -0
  84. calibpipe/utils/observatory.py +486 -0
  85. calibpipe/utils/observatory_containers.py +26 -0
  86. calibpipe/version.py +24 -0
  87. ctao_calibpipe-0.1.0.dist-info/METADATA +86 -0
  88. ctao_calibpipe-0.1.0.dist-info/RECORD +93 -0
  89. ctao_calibpipe-0.1.0.dist-info/WHEEL +5 -0
  90. ctao_calibpipe-0.1.0.dist-info/entry_points.txt +8 -0
  91. ctao_calibpipe-0.1.0.dist-info/licenses/AUTHORS.md +13 -0
  92. ctao_calibpipe-0.1.0.dist-info/licenses/LICENSE +21 -0
  93. ctao_calibpipe-0.1.0.dist-info/top_level.txt +1 -0
@@ -0,0 +1,775 @@
1
+ from datetime import datetime
2
+
3
+ import astropy.units as u
4
+ import pytest
5
+ from calibpipe.atmosphere.meteo_data_handlers import (
6
+ CO2DataHandler,
7
+ ECMWFDataHandler,
8
+ GDASDataHandler,
9
+ )
10
+ from calibpipe.utils.observatory import Observatory
11
+ from traitlets.config import Config
12
+
13
+ co2_file_path = "./"
14
+
15
+
16
+ class TestMeteoDataHandler:
17
+ @pytest.fixture()
18
+ def setup_macobac(self):
19
+ macobac = CO2DataHandler()
20
+ return macobac
21
+
22
+ @pytest.fixture()
23
+ def setup_cta_north(self):
24
+ cta_north = {
25
+ "Observatory": {
26
+ "name": "CTAO-North",
27
+ "latitude": 28.761795,
28
+ "longitude": -17.890701,
29
+ "elevation": 2150,
30
+ "seasons": [
31
+ {
32
+ "Season": {
33
+ "name": "spring",
34
+ "start_month": 5,
35
+ "start_day": 1,
36
+ "stop_month": 6,
37
+ "stop_day": 20,
38
+ }
39
+ },
40
+ {
41
+ "Season": {
42
+ "name": "summer",
43
+ "start_month": 6,
44
+ "start_day": 21,
45
+ "stop_month": 10,
46
+ "stop_day": 4,
47
+ }
48
+ },
49
+ {
50
+ "Season": {
51
+ "name": "winter",
52
+ "start_month": 11,
53
+ "start_day": 16,
54
+ "stop_month": 4,
55
+ }
56
+ },
57
+ {
58
+ "Season": {
59
+ "name": "fall",
60
+ "start_month": 10,
61
+ "start_day": 5,
62
+ "stop_month": 11,
63
+ "stop_day": 15,
64
+ }
65
+ },
66
+ ],
67
+ }
68
+ }
69
+ return cta_north
70
+
71
+ @pytest.fixture()
72
+ def setup_cta_south(self):
73
+ cta_south = {
74
+ "Observatory": {
75
+ "name": "CTAO-South",
76
+ "latitude": -24.6272,
77
+ "longitude": -70.4039,
78
+ "elevation": 2200,
79
+ "seasons": [
80
+ {
81
+ "Season": {
82
+ "name": "summer",
83
+ "start_month": 11,
84
+ "start_day": 1,
85
+ "stop_month": 5,
86
+ "stop_day": 1,
87
+ }
88
+ },
89
+ {
90
+ "Season": {
91
+ "name": "winter",
92
+ "start_month": 5,
93
+ "start_day": 2,
94
+ "stop_month": 10,
95
+ "stop_day": 31,
96
+ }
97
+ },
98
+ ],
99
+ }
100
+ }
101
+ return cta_south
102
+
103
+ @pytest.fixture()
104
+ def setup_ecmwf_handler(self):
105
+ ecmwf_data_handler = ECMWFDataHandler()
106
+ return ecmwf_data_handler
107
+
108
+ @pytest.fixture()
109
+ def setup_gdas_handler(self):
110
+ gdas_data_handler = GDASDataHandler()
111
+ return gdas_data_handler
112
+
113
+ @pytest.fixture()
114
+ def setup_south_observatory(self, setup_cta_south):
115
+ south_observatory = Observatory(config=Config(setup_cta_south))
116
+ return south_observatory
117
+
118
+ @pytest.fixture()
119
+ def setup_north_observatory(self, setup_cta_north):
120
+ north_observatory = Observatory(config=Config(setup_cta_north))
121
+ return north_observatory
122
+
123
+ @pytest.mark.ecmwf()
124
+ @pytest.mark.verifies_usecase("UC-120-1.5")
125
+ @pytest.mark.verifies_usecase("UC-120-1.10")
126
+ def test_request_ecmwf_north(
127
+ self, setup_north_observatory, setup_ecmwf_handler, setup_cta_north
128
+ ):
129
+ """Test if the ECMWF requested is reconstructed correctly"""
130
+ timestamp = datetime(2023, 1, 20, 2, 0, 0, 0)
131
+ dusk, dawn = setup_north_observatory.get_astronomical_night(timestamp)
132
+ setup_ecmwf_handler.create_request(
133
+ start=dusk,
134
+ stop=dawn,
135
+ latitude=setup_cta_north["Observatory"]["latitude"] * u.deg,
136
+ longitude=setup_cta_north["Observatory"]["longitude"] * u.deg,
137
+ )
138
+ assert setup_ecmwf_handler.requests == [
139
+ {
140
+ "product_type": "reanalysis",
141
+ "variable": [
142
+ "divergence",
143
+ "geopotential",
144
+ "ozone_mass_mixing_ratio",
145
+ "potential_vorticity",
146
+ "relative_humidity",
147
+ "temperature",
148
+ "u_component_of_wind",
149
+ "v_component_of_wind",
150
+ "vertical_velocity",
151
+ ],
152
+ "pressure_level": [
153
+ "1",
154
+ "2",
155
+ "3",
156
+ "5",
157
+ "7",
158
+ "10",
159
+ "20",
160
+ "30",
161
+ "50",
162
+ "70",
163
+ "100",
164
+ "125",
165
+ "150",
166
+ "175",
167
+ "200",
168
+ "225",
169
+ "250",
170
+ "300",
171
+ "350",
172
+ "400",
173
+ "450",
174
+ "500",
175
+ "550",
176
+ "600",
177
+ "650",
178
+ "700",
179
+ "750",
180
+ "775",
181
+ "800",
182
+ "825",
183
+ "850",
184
+ "875",
185
+ "900",
186
+ "925",
187
+ "950",
188
+ "975",
189
+ "1000",
190
+ ],
191
+ "year": "2023",
192
+ "month": "1",
193
+ "day": "19",
194
+ "time": ["21:00", "22:00", "23:00"],
195
+ "area": [28.75, -18.0, 29.0, -17.75],
196
+ "format": "grib",
197
+ },
198
+ {
199
+ "product_type": "reanalysis",
200
+ "variable": [
201
+ "divergence",
202
+ "geopotential",
203
+ "ozone_mass_mixing_ratio",
204
+ "potential_vorticity",
205
+ "relative_humidity",
206
+ "temperature",
207
+ "u_component_of_wind",
208
+ "v_component_of_wind",
209
+ "vertical_velocity",
210
+ ],
211
+ "pressure_level": [
212
+ "1",
213
+ "2",
214
+ "3",
215
+ "5",
216
+ "7",
217
+ "10",
218
+ "20",
219
+ "30",
220
+ "50",
221
+ "70",
222
+ "100",
223
+ "125",
224
+ "150",
225
+ "175",
226
+ "200",
227
+ "225",
228
+ "250",
229
+ "300",
230
+ "350",
231
+ "400",
232
+ "450",
233
+ "500",
234
+ "550",
235
+ "600",
236
+ "650",
237
+ "700",
238
+ "750",
239
+ "775",
240
+ "800",
241
+ "825",
242
+ "850",
243
+ "875",
244
+ "900",
245
+ "925",
246
+ "950",
247
+ "975",
248
+ "1000",
249
+ ],
250
+ "year": "2023",
251
+ "month": "1",
252
+ "day": "20",
253
+ "time": ["00:00", "01:00", "02:00", "03:00", "04:00", "05:00", "06:00"],
254
+ "area": [28.75, -18.0, 29.0, -17.75],
255
+ "format": "grib",
256
+ },
257
+ ]
258
+
259
+ @pytest.mark.ecmwf()
260
+ @pytest.mark.verifies_usecase("UC-120-1.5")
261
+ @pytest.mark.verifies_usecase("UC-120-1.10")
262
+ def test_request_ecmwf_south(
263
+ self, setup_south_observatory, setup_ecmwf_handler, setup_cta_south
264
+ ):
265
+ """Test if the ECMWF requested is reconstructed correctly"""
266
+ timestamp = datetime(2023, 1, 20, 2, 0, 0, 0)
267
+ dusk, dawn = setup_south_observatory.get_astronomical_night(timestamp)
268
+ setup_ecmwf_handler.create_request(
269
+ start=dusk,
270
+ stop=dawn,
271
+ latitude=setup_cta_south["Observatory"]["latitude"] * u.deg,
272
+ longitude=setup_cta_south["Observatory"]["longitude"] * u.deg,
273
+ )
274
+ assert setup_ecmwf_handler.requests == [
275
+ {
276
+ "product_type": "reanalysis",
277
+ "variable": [
278
+ "divergence",
279
+ "geopotential",
280
+ "ozone_mass_mixing_ratio",
281
+ "potential_vorticity",
282
+ "relative_humidity",
283
+ "temperature",
284
+ "u_component_of_wind",
285
+ "v_component_of_wind",
286
+ "vertical_velocity",
287
+ ],
288
+ "pressure_level": [
289
+ "1",
290
+ "2",
291
+ "3",
292
+ "5",
293
+ "7",
294
+ "10",
295
+ "20",
296
+ "30",
297
+ "50",
298
+ "70",
299
+ "100",
300
+ "125",
301
+ "150",
302
+ "175",
303
+ "200",
304
+ "225",
305
+ "250",
306
+ "300",
307
+ "350",
308
+ "400",
309
+ "450",
310
+ "500",
311
+ "550",
312
+ "600",
313
+ "650",
314
+ "700",
315
+ "750",
316
+ "775",
317
+ "800",
318
+ "825",
319
+ "850",
320
+ "875",
321
+ "900",
322
+ "925",
323
+ "950",
324
+ "975",
325
+ "1000",
326
+ ],
327
+ "year": "2023",
328
+ "month": "1",
329
+ "day": "20",
330
+ "time": [
331
+ "02:00",
332
+ "03:00",
333
+ "04:00",
334
+ "05:00",
335
+ "06:00",
336
+ "07:00",
337
+ "08:00",
338
+ ],
339
+ "area": [-24.75, -70.5, -24.5, -70.25],
340
+ "format": "grib",
341
+ }
342
+ ]
343
+
344
+ # Testing boundary conditions for Copernicus requests
345
+ # Starting with leap years
346
+ @pytest.mark.ecmwf()
347
+ @pytest.mark.verifies_usecase("UC-120-1.5")
348
+ @pytest.mark.verifies_usecase("UC-120-1.10")
349
+ def test_request_ecmwf_leap_year(
350
+ self, setup_north_observatory, setup_ecmwf_handler, setup_cta_north
351
+ ):
352
+ """Test if the ECMWF requested is reconstructed correctly"""
353
+ timestamp = datetime(2020, 2, 28, 23, 56, 28, 0)
354
+ dusk, dawn = setup_north_observatory.get_astronomical_night(timestamp)
355
+ setup_ecmwf_handler.create_request(
356
+ start=dusk,
357
+ stop=dawn,
358
+ latitude=setup_cta_north["Observatory"]["latitude"] * u.deg,
359
+ longitude=setup_cta_north["Observatory"]["longitude"] * u.deg,
360
+ )
361
+ assert setup_ecmwf_handler.requests == [
362
+ {
363
+ "product_type": "reanalysis",
364
+ "variable": [
365
+ "divergence",
366
+ "geopotential",
367
+ "ozone_mass_mixing_ratio",
368
+ "potential_vorticity",
369
+ "relative_humidity",
370
+ "temperature",
371
+ "u_component_of_wind",
372
+ "v_component_of_wind",
373
+ "vertical_velocity",
374
+ ],
375
+ "pressure_level": [
376
+ "1",
377
+ "2",
378
+ "3",
379
+ "5",
380
+ "7",
381
+ "10",
382
+ "20",
383
+ "30",
384
+ "50",
385
+ "70",
386
+ "100",
387
+ "125",
388
+ "150",
389
+ "175",
390
+ "200",
391
+ "225",
392
+ "250",
393
+ "300",
394
+ "350",
395
+ "400",
396
+ "450",
397
+ "500",
398
+ "550",
399
+ "600",
400
+ "650",
401
+ "700",
402
+ "750",
403
+ "775",
404
+ "800",
405
+ "825",
406
+ "850",
407
+ "875",
408
+ "900",
409
+ "925",
410
+ "950",
411
+ "975",
412
+ "1000",
413
+ ],
414
+ "year": "2020",
415
+ "month": "2",
416
+ "day": "28",
417
+ "time": ["21:00", "22:00", "23:00"],
418
+ "area": [28.75, -18.0, 29.0, -17.75],
419
+ "format": "grib",
420
+ },
421
+ {
422
+ "product_type": "reanalysis",
423
+ "variable": [
424
+ "divergence",
425
+ "geopotential",
426
+ "ozone_mass_mixing_ratio",
427
+ "potential_vorticity",
428
+ "relative_humidity",
429
+ "temperature",
430
+ "u_component_of_wind",
431
+ "v_component_of_wind",
432
+ "vertical_velocity",
433
+ ],
434
+ "pressure_level": [
435
+ "1",
436
+ "2",
437
+ "3",
438
+ "5",
439
+ "7",
440
+ "10",
441
+ "20",
442
+ "30",
443
+ "50",
444
+ "70",
445
+ "100",
446
+ "125",
447
+ "150",
448
+ "175",
449
+ "200",
450
+ "225",
451
+ "250",
452
+ "300",
453
+ "350",
454
+ "400",
455
+ "450",
456
+ "500",
457
+ "550",
458
+ "600",
459
+ "650",
460
+ "700",
461
+ "750",
462
+ "775",
463
+ "800",
464
+ "825",
465
+ "850",
466
+ "875",
467
+ "900",
468
+ "925",
469
+ "950",
470
+ "975",
471
+ "1000",
472
+ ],
473
+ "year": "2020",
474
+ "month": "2",
475
+ "day": "29",
476
+ "time": ["00:00", "01:00", "02:00", "03:00", "04:00", "05:00", "06:00"],
477
+ "area": [28.75, -18.0, 29.0, -17.75],
478
+ "format": "grib",
479
+ },
480
+ ]
481
+
482
+ # Continuing with new years eve where all (day, month and year) are changing
483
+ @pytest.mark.ecmwf()
484
+ @pytest.mark.verifies_usecase("UC-120-1.5")
485
+ @pytest.mark.verifies_usecase("UC-120-1.10")
486
+ def test_request_ecmwf_new_year(
487
+ self, setup_north_observatory, setup_ecmwf_handler, setup_cta_north
488
+ ):
489
+ """Test if the ECMWF requested is reconstructed correctly"""
490
+ timestamp = datetime(2023, 1, 1, 0, 0, 0, 0)
491
+ dusk, dawn = setup_north_observatory.get_astronomical_night(timestamp)
492
+ setup_ecmwf_handler.create_request(
493
+ start=dusk,
494
+ stop=dawn,
495
+ latitude=setup_cta_north["Observatory"]["latitude"] * u.deg,
496
+ longitude=setup_cta_north["Observatory"]["longitude"] * u.deg,
497
+ )
498
+ assert setup_ecmwf_handler.requests == [
499
+ {
500
+ "product_type": "reanalysis",
501
+ "variable": [
502
+ "divergence",
503
+ "geopotential",
504
+ "ozone_mass_mixing_ratio",
505
+ "potential_vorticity",
506
+ "relative_humidity",
507
+ "temperature",
508
+ "u_component_of_wind",
509
+ "v_component_of_wind",
510
+ "vertical_velocity",
511
+ ],
512
+ "pressure_level": [
513
+ "1",
514
+ "2",
515
+ "3",
516
+ "5",
517
+ "7",
518
+ "10",
519
+ "20",
520
+ "30",
521
+ "50",
522
+ "70",
523
+ "100",
524
+ "125",
525
+ "150",
526
+ "175",
527
+ "200",
528
+ "225",
529
+ "250",
530
+ "300",
531
+ "350",
532
+ "400",
533
+ "450",
534
+ "500",
535
+ "550",
536
+ "600",
537
+ "650",
538
+ "700",
539
+ "750",
540
+ "775",
541
+ "800",
542
+ "825",
543
+ "850",
544
+ "875",
545
+ "900",
546
+ "925",
547
+ "950",
548
+ "975",
549
+ "1000",
550
+ ],
551
+ "year": "2022",
552
+ "month": "12",
553
+ "day": "31",
554
+ "time": ["20:00", "21:00", "22:00", "23:00"],
555
+ "area": [28.75, -18.0, 29.0, -17.75],
556
+ "format": "grib",
557
+ },
558
+ {
559
+ "product_type": "reanalysis",
560
+ "variable": [
561
+ "divergence",
562
+ "geopotential",
563
+ "ozone_mass_mixing_ratio",
564
+ "potential_vorticity",
565
+ "relative_humidity",
566
+ "temperature",
567
+ "u_component_of_wind",
568
+ "v_component_of_wind",
569
+ "vertical_velocity",
570
+ ],
571
+ "pressure_level": [
572
+ "1",
573
+ "2",
574
+ "3",
575
+ "5",
576
+ "7",
577
+ "10",
578
+ "20",
579
+ "30",
580
+ "50",
581
+ "70",
582
+ "100",
583
+ "125",
584
+ "150",
585
+ "175",
586
+ "200",
587
+ "225",
588
+ "250",
589
+ "300",
590
+ "350",
591
+ "400",
592
+ "450",
593
+ "500",
594
+ "550",
595
+ "600",
596
+ "650",
597
+ "700",
598
+ "750",
599
+ "775",
600
+ "800",
601
+ "825",
602
+ "850",
603
+ "875",
604
+ "900",
605
+ "925",
606
+ "950",
607
+ "975",
608
+ "1000",
609
+ ],
610
+ "year": "2023",
611
+ "month": "1",
612
+ "day": "1",
613
+ "time": ["00:00", "01:00", "02:00", "03:00", "04:00", "05:00", "06:00"],
614
+ "area": [28.75, -18.0, 29.0, -17.75],
615
+ "format": "grib",
616
+ },
617
+ ]
618
+
619
+ # Continuing with new years eve where all (day, month and year) are changing
620
+ @pytest.mark.ecmwf()
621
+ @pytest.mark.verifies_usecase("UC-120-1.5")
622
+ @pytest.mark.verifies_usecase("UC-120-1.10")
623
+ def test_request_ecmwf_day_without_dusk(
624
+ self, setup_south_observatory, setup_ecmwf_handler, setup_cta_south
625
+ ):
626
+ """Test if the ECMWF requested is reconstructed correctly"""
627
+ timestamp = datetime(2023, 9, 22, 2, 0, 0, 0)
628
+ dusk, dawn = setup_south_observatory.get_astronomical_night(timestamp)
629
+ setup_ecmwf_handler.create_request(
630
+ start=dusk,
631
+ stop=dawn,
632
+ latitude=setup_cta_south["Observatory"]["latitude"] * u.deg,
633
+ longitude=setup_cta_south["Observatory"]["longitude"] * u.deg,
634
+ )
635
+ assert setup_ecmwf_handler.requests == [
636
+ {
637
+ "product_type": "reanalysis",
638
+ "variable": [
639
+ "divergence",
640
+ "geopotential",
641
+ "ozone_mass_mixing_ratio",
642
+ "potential_vorticity",
643
+ "relative_humidity",
644
+ "temperature",
645
+ "u_component_of_wind",
646
+ "v_component_of_wind",
647
+ "vertical_velocity",
648
+ ],
649
+ "pressure_level": [
650
+ "1",
651
+ "2",
652
+ "3",
653
+ "5",
654
+ "7",
655
+ "10",
656
+ "20",
657
+ "30",
658
+ "50",
659
+ "70",
660
+ "100",
661
+ "125",
662
+ "150",
663
+ "175",
664
+ "200",
665
+ "225",
666
+ "250",
667
+ "300",
668
+ "350",
669
+ "400",
670
+ "450",
671
+ "500",
672
+ "550",
673
+ "600",
674
+ "650",
675
+ "700",
676
+ "750",
677
+ "775",
678
+ "800",
679
+ "825",
680
+ "850",
681
+ "875",
682
+ "900",
683
+ "925",
684
+ "950",
685
+ "975",
686
+ "1000",
687
+ ],
688
+ "year": "2023",
689
+ "month": "9",
690
+ "day": "22",
691
+ "time": [
692
+ "00:00",
693
+ "01:00",
694
+ "02:00",
695
+ "03:00",
696
+ "04:00",
697
+ "05:00",
698
+ "06:00",
699
+ "07:00",
700
+ "08:00",
701
+ "09:00",
702
+ ],
703
+ "area": [-24.75, -70.5, -24.5, -70.25],
704
+ "format": "grib",
705
+ }
706
+ ]
707
+
708
+ @pytest.mark.verifies_usecase("UC-120-1.5")
709
+ @pytest.mark.verifies_usecase("UC-120-1.10")
710
+ def test_keeling_curve_download(self, setup_macobac):
711
+ setup_macobac.data_path = co2_file_path
712
+ assert setup_macobac.request_data() == 0
713
+
714
+ @pytest.mark.gdas()
715
+ @pytest.mark.verifies_usecase("UC-120-1.5")
716
+ def test_request_gdas_creation(
717
+ self, setup_south_observatory, setup_gdas_handler, setup_cta_south
718
+ ):
719
+ """Test correct GDAS request creation"""
720
+ timestamp = datetime(2023, 1, 20, 2, 0, 0, 0)
721
+ dusk, dawn = setup_south_observatory.get_astronomical_night(timestamp)
722
+ setup_gdas_handler.create_request(
723
+ start=dusk,
724
+ stop=dawn,
725
+ latitude=setup_cta_south["Observatory"]["latitude"] * u.deg,
726
+ longitude=setup_cta_south["Observatory"]["longitude"] * u.deg,
727
+ )
728
+ assert setup_gdas_handler.request == {
729
+ "dataset": "ds083.2",
730
+ "date": "202301200600/to/202301200600",
731
+ "datetype": "init",
732
+ "param": "HGT/PRES/TMP/R H/P WAT/A PCP/U GRD/V GRD/T CDC/LANDN/TOZNE",
733
+ "level": "ISBL:1000/975/950/925/900/850/800/750/700/650/600/550/500/450/400/350/300/250/200/150/100/50/20",
734
+ "nlat": -25.0,
735
+ "slat": -25.0,
736
+ "elon": -70.0,
737
+ "wlon": -70.0,
738
+ "product": "Analysis",
739
+ }
740
+
741
+ @pytest.mark.gdas()
742
+ @pytest.mark.xfail(
743
+ reason="GDAS is rather unstable. Functionality is tested manually"
744
+ )
745
+ @pytest.mark.verifies_usecase("UC-120-1.5")
746
+ def test_gdas_data_retrieval(
747
+ self, setup_north_observatory, setup_gdas_handler, setup_cta_north
748
+ ):
749
+ """Test GDAS data retrieval"""
750
+ timestamp = datetime(2023, 1, 20, 2, 0, 0, 0)
751
+ dusk, dawn = setup_north_observatory.get_astronomical_night(timestamp)
752
+ setup_gdas_handler.create_request(
753
+ start=dusk,
754
+ stop=dawn,
755
+ latitude=setup_cta_north["Observatory"]["latitude"] * u.deg,
756
+ longitude=setup_cta_north["Observatory"]["longitude"] * u.deg,
757
+ )
758
+ assert setup_gdas_handler.request_data() == 0
759
+
760
+ @pytest.mark.ecmwf()
761
+ @pytest.mark.verifies_usecase("UC-120-1.5")
762
+ @pytest.mark.verifies_usecase("UC-120-1.10")
763
+ def test_ecmwf_data_retrieval(
764
+ self, setup_south_observatory, setup_ecmwf_handler, setup_cta_south
765
+ ):
766
+ """Test ECMWF data retrieval"""
767
+ timestamp = datetime(2023, 1, 20, 2, 0, 0, 0)
768
+ dusk, dawn = setup_south_observatory.get_astronomical_night(timestamp)
769
+ setup_ecmwf_handler.create_request(
770
+ start=dusk,
771
+ stop=dawn,
772
+ latitude=setup_cta_south["Observatory"]["latitude"] * u.deg,
773
+ longitude=setup_cta_south["Observatory"]["longitude"] * u.deg,
774
+ )
775
+ assert setup_ecmwf_handler.request_data() == 0