Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

TEMPO NO2 reader #188

Merged
merged 25 commits into from
Sep 9, 2024
Merged
Show file tree
Hide file tree
Changes from 1 commit
Commits
Show all changes
25 commits
Select commit Hold shift + click to select a range
e0c9e3b
TEMPO NO2 reader
blychs Aug 23, 2024
cd55cf3
Update monetio/sat/_tempo_l2_no2_mm.py
blychs Aug 25, 2024
b2fa316
Update monetio/sat/_tempo_l2_no2_mm.py
blychs Aug 25, 2024
5344ddc
Update monetio/sat/_tempo_l2_no2_mm.py
blychs Aug 25, 2024
69abb32
Fix bug with flags and add options for vars
blychs Aug 28, 2024
662c5d2
Debug min/max/quality_flag being NaN, decode time
blychs Aug 28, 2024
8c9f93a
Make "minimum" and "maximum" flags mask array
blychs Aug 28, 2024
b31b6f7
Better handle pressure, convert from hPa to Pa
blychs Aug 28, 2024
9d5c8a9
format with pre-commit hooks
blychs Aug 28, 2024
335fd7c
add TEMPO L2 NO2 test
blychs Aug 28, 2024
1098330
Fix always trying to find surface_pressure
blychs Aug 29, 2024
7107e8b
make sure test catches expected warning
blychs Aug 29, 2024
88d9593
Remove unnecesary print and warn statements
blychs Aug 29, 2024
fb4f571
remove lat and lon masking
blychs Aug 29, 2024
b1e7837
Remove (wrong) _FillValue guard
blychs Aug 29, 2024
35179de
Manage time whithoug xr.decode_cf()
blychs Aug 30, 2024
95a106d
Make more consistent with the TROPOMI reader
blychs Aug 30, 2024
6cd1fc9
Update tests/test_tempo_l2.py
blychs Aug 30, 2024
34ad51c
Fix bug in change of dim order for press
blychs Aug 30, 2024
91ab75b
Test also order of dimensions of pressure
blychs Aug 30, 2024
c3e1252
Fix order of __all__
blychs Aug 30, 2024
3152402
Update monetio/sat/_tempo_l2_no2_mm.py
blychs Aug 31, 2024
8b969b1
Merge branch 'feature/_tempo_l2_mm_only' of github.com:NCAR/monetio i…
blychs Aug 31, 2024
74fbc2d
Update monetio/sat/_tempo_l2_no2_mm.py
blychs Sep 5, 2024
4adc279
Update monetio/sat/_tempo_l2_no2_mm.py
blychs Sep 5, 2024
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 2 additions & 0 deletions monetio/sat/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@
_mopitt_l3_mm,
_omps_l3_mm,
_omps_nadir_mm,
_tempo_l2_no2_mm,
_tropomi_l2_no2_mm,
goes,
modis_ornl,
Expand All @@ -13,6 +14,7 @@
)

__all__ = [
"_tempo_l2_no2_mm",
blychs marked this conversation as resolved.
Show resolved Hide resolved
"_gridded_eos_mm",
"_modis_l2_mm",
"_mopitt_l3_mm",
Expand Down
146 changes: 146 additions & 0 deletions monetio/sat/_tempo_l2_no2_mm.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,146 @@
"""TEMPO L2 NO2 data file reader.

History:


"""

import logging
import os
import sys
from collections import OrderedDict
from glob import glob
from pathlib import Path

import numpy as np
import xarray as xr
from netCDF4 import Dataset


def _open_one_dataset(fname, variable_dict):
"""Read locally stored INTELSAT TEMPO NO2 level 2
Parameters
blychs marked this conversation as resolved.
Show resolved Hide resolved
----------
fname: string
fname is local path to netcdf4 (HDF5) file

variable_dict: dict
Returns
-------
ds: xarray dataset
blychs marked this conversation as resolved.
Show resolved Hide resolved
"""
print("reading " + fname)

ds = xr.Dataset()

dso = Dataset(fname, "r")
lon_var = dso.groups["geolocation"]["longitude"]
lat_var = dso.groups["geolocation"]["latitude"]
time_var = dso.groups["geolocation"]["time"]

ds["lon"] = (
("x", "y"),
lon_var[:].squeeze(),
{"long_name": lon_var.long_name, "units": lon_var.units},
)
ds["lat"] = (
("x", "y"),
lat_var[:].squeeze(),
{"long_name": lat_var.long_name, "units": lat_var.units},
)
ds["time"] = (
("time",),
time_var[:].squeeze(),
{"long_name": time_var.long_name, "units": time_var.units},
blychs marked this conversation as resolved.
Show resolved Hide resolved
)
ds["lon"] = ds["lon"].fillna(-999.99)
ds["lat"] = ds["lat"].fillna(-999.99)
blychs marked this conversation as resolved.
Show resolved Hide resolved
ds = ds.set_coords(["time", "lon", "lat"])

ds.attrs["reference_time_string"] = dso.time_coverage_start
ds.attrs["granule_number"] = dso.granule_num
ds.attrs["scan_num"] = dso.scan_num

for varname in variable_dict:
values_var = dso.groups["product"][varname]
values = values_var[:].squeeze()
fv = values_var.getncattr("_FillValue")
if not np.isfinite(fv):
blychs marked this conversation as resolved.
Show resolved Hide resolved
values[:][values[:] == fv] = np.nan
blychs marked this conversation as resolved.
Show resolved Hide resolved

if "scale" in variable_dict[varname]:
values[:] = variable_dict[varname]["scale"] * values[:]

if "minimum" in variable_dict[varname]:
minimum = variable_dict[varname]["minimum"]
values[:][values[:] < minimum] = np.nan

if "maximum" in variable_dict[varname]:
maximum = variable_dict[varname]["maximum"]
values[:][values[:] > maximum] = np.nan

ds[varname] = (("x", "y"), values, values_var.__dict__)

if "quality_flag_max" in variable_dict[varname]:
ds.attrs["quality_flag"] = varname
ds.attrs["quality_thresh_max"] = variable_dict[varname]["quality_flag_max"]

dso.close()

return ds

# time_var = dso.groups["geolocation"]["time"]


def apply_quality_flag(ds):
"""Mask variables in place based on quality flag
Parameters
----------
ds: xr.Dataset
blychs marked this conversation as resolved.
Show resolved Hide resolved
"""
if "quality_flag" in ds.attrs:
quality_flag = ds[ds.attrs["quality_flag"]]
quality_thresh_max = ds.attrs["quality_thresh_max"]

# Apply the quality thersh maximum to all variables in ds
for varname in ds:
if varname != ds.attrs["quality_flag"]:
logging.debug(varname)
values = ds[varname].values
values[quality_flag > quality_thresh_max] = np.nan


def open_dataset(fnames, variable_dict, debug=False):
if debug:
logging_level = logging.DEBUG
logging.basicConfig(strea=sys.stdout, level=logging_level)
blychs marked this conversation as resolved.
Show resolved Hide resolved

if isinstance(fnames, Path):
fnames = fnames.as_posix()
if isinstance(variable_dict, str):
variable_dict = {variable_dict: {}}
elif isinstance(variable_dict, dict):
pass
else: # Assume sequence
variable_dict = {varname: {} for varname in variable_dict}

for subpath in fnames.split("/"):
if "$" in subpath:
envvar = subpath.replace("$", "")
envval = os.getenv(envvar)
if envval is None:
raise Exception("Environment variable not defined: " + subpath)
else:
fnames = fnames.replace(subpath, envval)

print(fnames)
files = sorted(glob(fnames))

granules = OrderedDict()

for file in files:
granule = _open_one_dataset(file, variable_dict)
apply_quality_flag(granule)
granules[granule.attrs["reference_time_string"]] = granule

return granules