Skip to content

Commit e9aece7

Browse files
committed
Fix tests
1 parent 0e49696 commit e9aece7

36 files changed

+1542
-1371
lines changed

docs/source/00_introduction.rst

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -32,7 +32,7 @@ The reference sensors for the GPM mission are the:
3232
The :ref:`GPM Data Archive <gpm_data_archive>` currently includes satellite data records that extend back to 1987.
3333
This extensive archive is the result of contributions from two spaceborne radars and a fleet of 26 passive microwave (PMW) sensors that forms the so-called GPM constellation.
3434

35-
The data are organized into various :ref:` product levels <gpm_product_levels>`,
35+
The data are organized into various :ref:`product levels <gpm_product_levels>`,
3636
encompassing raw and calibrated observations (Level 1), intermediate geophysical retrieval products (Level 2),
3737
and spatio-temporally integrated datasets from single and multiple satellites (Level 3).
3838

@@ -732,9 +732,9 @@ examination of land surface effects on radar, radiometer, or combined-sensor pre
732732

733733
For detailed information on the TRMM/GPM-CloudSat Coincidence dataset, please
734734
refer to the corresponding `journal article <https://www.mdpi.com/2072-4292/13/12/2264>`_
735-
and the `Algorithm Theoretical Basis Document (ATBD) <https://gpm.nasa.gov/resources/documents/cloudsat-gpm-coincidence-dataset-version-1c>`_.
735+
and the `Algorithm Theoretical Basis Document (ATBD) <https://arthurhou.pps.eosdis.nasa.gov/Documents/CSAT_TRMM_GPM_COIN_ATBD_V05.pdf>`_.
736736

737-
The coincidence dataset can be downloaded with GPM-API using the ``2B-GPM-CSAT`` and ``2B-TRMM-CSAT`` product acronyms.
737+
The TRMM/GPM-CloudSat Coincidence dataset V5 can be downloaded with GPM-API using the ``2B-GPM-CSAT`` and ``2B-TRMM-CSAT`` product acronyms.
738738

739739
The figure below displays a quick-look radar time-height profile imagery from the GPM - CloudSat Coincidence dataset.
740740

docs/source/03_quickstart.rst

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -133,7 +133,7 @@ specific time periods:
133133
.. code-block:: python
134134
135135
gpm.available_products(end_time="1995-01-31") # from the start of the mission to 1995-01-31
136-
gpm.available_products(start_time="2014-01-01", end_time="2016", product_categories="PMW")
136+
gpm.available_products(start_time="2014-01-01", end_time="2016-01-01", product_categories="PMW")
137137
gpm.available_products(start_time="2019-01-01") # from 2019-01-01 to the present
138138
139139

gpm/configs.py

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -187,12 +187,14 @@ def _get_config_key(key):
187187
def get_base_dir(base_dir=None):
188188
"""Return the GPM base directory."""
189189
import gpm
190+
from gpm.io.checks import check_base_dir
190191

191192
if base_dir is None:
192193
base_dir = gpm.config.get("base_dir")
193194
if base_dir is None:
194195
raise ValueError("The 'base_dir' is not specified in the GPM-API configuration file.")
195-
return str(base_dir) # convert Path to str
196+
base_dir = check_base_dir(base_dir) # convert Path to str
197+
return base_dir
196198

197199

198200
def get_username_pps():

gpm/dataset/dataset.py

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -30,6 +30,7 @@
3030

3131
import xarray as xr
3232

33+
from gpm.configs import get_base_dir
3334
from gpm.dataset.conventions import finalize_dataset
3435
from gpm.dataset.granule import _multi_file_closer, get_scan_modes_datasets
3536
from gpm.io.checks import (
@@ -237,6 +238,7 @@ def open_dataset(
237238
238239
"""
239240
## Check valid product and variables
241+
base_dir = get_base_dir(base_dir=base_dir)
240242
product = check_product(product, product_type=product_type)
241243
variables = check_variables(variables)
242244
groups = check_groups(groups)
@@ -415,7 +417,7 @@ def open_datatree(
415417
product = check_product(product, product_type=product_type)
416418
variables = check_variables(variables)
417419
groups = check_groups(groups)
418-
420+
base_dir = get_base_dir(base_dir=base_dir)
419421
# Check scan_modes
420422
scan_modes = check_scan_modes(scan_modes=scan_modes, product=product, version=version)
421423

gpm/dataset/decoding/coordinates.py

Lines changed: 50 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -26,21 +26,31 @@
2626
# -----------------------------------------------------------------------------.
2727
"""This module contains functions to sanitize GPM-API Dataset coordinates."""
2828
import numpy as np
29+
import xarray as xr
2930

3031

3132
def ensure_valid_coords(ds, raise_error=False):
3233
"""Ensure geographic coordinates are within expected range."""
33-
invalid_coords = np.logical_or(
34-
np.logical_or(ds["lon"].data < -180, ds["lon"].data > 180),
35-
np.logical_or(ds["lat"].data < -90, ds["lat"].data > 90),
34+
ds["lon"] = ds["lon"].compute()
35+
ds["lat"] = ds["lat"].compute()
36+
da_invalid_coords = np.logical_or(
37+
np.logical_or(ds["lon"] < -180, ds["lon"] > 180),
38+
np.logical_or(ds["lat"] < -90, ds["lat"] > 90),
3639
)
37-
if np.any(invalid_coords):
40+
if np.any(da_invalid_coords.data):
3841
if raise_error:
3942
raise ValueError("Invalid geographic coordinate in the granule.")
40-
da_invalid_coords = ds["lon"].copy()
41-
da_invalid_coords.data = invalid_coords
42-
# For each variable, set NaN value where invalid coordinates
43-
ds = ds.where(~da_invalid_coords)
43+
44+
# # Add valid_geolocation flag
45+
# ds = ds.assign_coords({"valid_geolocation": da_invalid_coords})
46+
47+
# # For each variable, set NaN value where invalid coordinates
48+
# # --> Only if variable has at the 2 dimensions of ds["lon"]
49+
# # --> Not good practice because it might mask quality flags DataArrays !
50+
# for var in ds.data_vars:
51+
# if set(ds["lon"].dims).issubset(set(ds[var].dims)):
52+
# ds[var] = ds[var].where(~da_invalid_coords)
53+
4454
# Add NaN to longitude and latitude
4555
ds["lon"] = ds["lon"].where(~da_invalid_coords)
4656
ds["lat"] = ds["lat"].where(~da_invalid_coords)
@@ -180,12 +190,37 @@ def _add_1c_pmw_frequency(ds, product, scan_mode):
180190

181191
def _add_pmw_coordinates(ds, product, scan_mode):
182192
"""Add coordinates to PMW products."""
183-
if product.startswith("1C"):
184-
ds = _add_1c_pmw_frequency(ds, product, scan_mode)
193+
ds = _add_1c_pmw_frequency(ds, product, scan_mode)
194+
return ds
195+
196+
197+
def _deal_with_pmw_incidence_angle_index(ds):
198+
if "incidenceAngleIndex" in ds:
199+
if "incidence_angle" in ds.dims and ds.sizes["incidence_angle"] > 1:
200+
idx_incidence_angle = ds["incidenceAngleIndex"].isel(along_track=0).astype(int).compute() - 1
201+
else:
202+
# Some 1C files have bad incidenceAngleIndex values ( )
203+
idx_incidence_angle = xr.zeros_like(ds["Tc"].isel(cross_track=0), dtype=int).compute()
204+
205+
if "incidenceAngle" in ds:
206+
ds["incidenceAngle"] = ds["incidenceAngle"].isel(incidence_angle=idx_incidence_angle)
207+
if "sunGlintAngle" in ds:
208+
ds["sunGlintAngle"] = ds["sunGlintAngle"].isel(incidence_angle=idx_incidence_angle)
209+
ds = ds.drop_vars("incidenceAngleIndex")
210+
211+
# if "incidenceAngle" in ds:
212+
# ds["incidenceAngle"] = ds["incidenceAngle"].isel(incidence_angle=idx_incidence_angle)
213+
# if "sunGlintAngle" in ds:
214+
# ds["sunGlintAngle"] = ds["sunGlintAngle"].isel(incidence_angle=idx_incidence_angle)
215+
# ds = ds.drop_vars("incidenceAngleIndex")
185216
return ds
186217

187218

188219
def set_coordinates(ds, product, scan_mode):
220+
# Compute spatial coordinates in memory
221+
ds["lon"] = ds["lon"].compute()
222+
ds["lat"] = ds["lat"].compute()
223+
189224
# ORBIT objects
190225
if "cross_track" in list(ds.dims):
191226
# Ensure valid coordinates
@@ -211,10 +246,12 @@ def set_coordinates(ds, product, scan_mode):
211246
ds = ds.set_coords("sunLocalTime")
212247

213248
#### PMW
214-
# - 1C products
215-
if product.startswith("1C"):
249+
# - 1B and 1C products
250+
if product.startswith("1C") or product.startswith("1B"):
216251
ds = _add_pmw_coordinates(ds, product, scan_mode)
217-
252+
# - Deal with incidenceAngleIndex in PMW 1C products
253+
if product.startswith("1C"):
254+
ds = _deal_with_pmw_incidence_angle_index(ds)
218255
#### RADAR
219256
if product in ["2A-DPR", "2A-Ku", "2A-Ka", "2A-PR", "2A-ENV-DPR", "2A-ENV-PR", "2A-ENV-Ka", "2A-ENV-Ku"]:
220257
ds = _add_radar_coordinates(ds, product, scan_mode)

gpm/dataset/groups_variables.py

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -35,6 +35,7 @@
3535
"Quality", # 1C-PMW
3636
"L1CqualityFlag", # 2A-PMW --> copy of Quality
3737
"dataQuality", # 2A-DPR, 1B-GMI/TMI, 2B-CMB
38+
"incidenceAngleIndex", # to deal with TMI S1 scan mode ... dropped variable !
3839
]
3940

4041

gpm/etc/pmw/composites/AMSR2.yaml

Lines changed: 115 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,115 @@
1+
10 + 18 GHz:
2+
R:
3+
name: 18.7V
4+
vmin: 65
5+
vmax: 320
6+
vmin_dynamic: false
7+
vmax_dynamic: false
8+
invert: true
9+
G:
10+
name: 18.7H
11+
vmin: 65
12+
vmax: 320
13+
vmin_dynamic: false
14+
vmax_dynamic: false
15+
invert: true
16+
B:
17+
name: 10.65H
18+
vmin: 65
19+
vmax: 320
20+
vmin_dynamic: false
21+
vmax_dynamic: false
22+
invert: true
23+
global_normalization: false
24+
18 + 23 GHz:
25+
R:
26+
name: 23.8V
27+
vmin: 65
28+
vmax: 320
29+
vmin_dynamic: false
30+
vmax_dynamic: false
31+
invert: true
32+
G:
33+
name: 18.7V
34+
vmin: 65
35+
vmax: 320
36+
vmin_dynamic: false
37+
vmax_dynamic: false
38+
invert: true
39+
B:
40+
name: 18.7H
41+
vmin: 65
42+
vmax: 320
43+
vmin_dynamic: false
44+
vmax_dynamic: false
45+
invert: true
46+
global_normalization: false
47+
37 + 89 GHz:
48+
R:
49+
name: 89V
50+
vmin: 65
51+
vmax: 320
52+
vmin_dynamic: false
53+
vmax_dynamic: false
54+
invert: true
55+
G:
56+
name: 89H
57+
vmin: 65
58+
vmax: 320
59+
vmin_dynamic: false
60+
vmax_dynamic: false
61+
invert: true
62+
B:
63+
name: 36.5H
64+
vmin: 65
65+
vmax: 320
66+
vmin_dynamic: false
67+
vmax_dynamic: false
68+
invert: true
69+
global_normalization: false
70+
NRL_36.5:
71+
R:
72+
name: PCT_36.5
73+
vmin: 260
74+
vmax: 280
75+
vmin_dynamic: false
76+
vmax_dynamic: false
77+
invert: true
78+
G:
79+
name: 36.5V
80+
vmin: 160
81+
vmax: 300
82+
vmin_dynamic: false
83+
vmax_dynamic: false
84+
invert: false
85+
B:
86+
name: 36.5H
87+
vmin: 180
88+
vmax: 300
89+
vmin_dynamic: false
90+
vmax_dynamic: false
91+
invert: false
92+
global_normalization: false
93+
NRL_89:
94+
R:
95+
name: PCT_89
96+
vmin: 230
97+
vmax: 290
98+
vmin_dynamic: false
99+
vmax_dynamic: false
100+
invert: true
101+
G:
102+
name: 89H
103+
vmin: 255
104+
vmax: 290
105+
vmin_dynamic: false
106+
vmax_dynamic: false
107+
invert: false
108+
B:
109+
name: 89V
110+
vmin: 275
111+
vmax: 290
112+
vmin_dynamic: false
113+
vmax_dynamic: false
114+
invert: false
115+
global_normalization: false

0 commit comments

Comments
 (0)