Skip to content

Commit

Permalink
Add reader for ASTER/MODIS CAMEL emissivity datasets.
Browse files Browse the repository at this point in the history
  • Loading branch information
simonrp84 committed Dec 28, 2024
1 parent 7a0dc1a commit b2765d4
Show file tree
Hide file tree
Showing 2 changed files with 253 additions and 0 deletions.
147 changes: 147 additions & 0 deletions satpy/etc/readers/camel_l3_nc.yaml
Original file line number Diff line number Diff line change
@@ -0,0 +1,147 @@
reader:
name: camel_l3_nc
short_name: CAMEL L3
long_name: CAMEL emissivity level 3 data in netCDF4 format.
description: >
Reader for the CAMEL emissivity product, produced from various L2/L3
datasets on a monthly basis. More details
`here <https://lpdaac.usgs.gov/products/cam5k30emv002/>`_.
status: Nominal
supports_fsspec: false
sensors: [combined]
reader: !!python/name:satpy.readers.yaml_reader.FileYAMLReader

file_types:
camel_emis_file:
file_reader: !!python/name:satpy.readers.camel_l3_nc.CAMELL3NCFileHandler
file_patterns:
- 'CAM5K30EM_emis_{start_time:%Y%m}_V{version:3s}.nc'


datasets:
# QA products
aster_ndvi:
name: aster_ndvi
file_key: aster_ndvi
file_type: [ camel_emis_file ]
aster_qflag:
name: aster_qflag
file_key: aster_qflag
file_type: [ camel_emis_file ]
bfemis_qflag:
name: bfemis_qflag
file_key: bfemis_qflag
file_type: [ camel_emis_file ]
camel_qflag:
name: camel_qflag
file_key: camel_qflag
file_type: [ camel_emis_file ]
snow_fraction:
name: snow_fraction
file_key: snow_fraction
file_type: [ camel_emis_file ]

# Emissivity bands
camel_emis_b1:
name: camel_emis_b1
file_key: camel_emis
band_id: 0
file_type: [ camel_emis_file ]
wavelength: 3.6
resolution: 0.05

camel_emis_b2:
name: camel_emis_b2
file_key: camel_emis
band_id: 1
file_type: [ camel_emis_file ]
wavelength: 4.3
resolution: 0.05

camel_emis_b3:
name: camel_emis_b3
file_key: camel_emis
band_id: 2
file_type: [ camel_emis_file ]
wavelength: 5.0
resolution: 0.05

camel_emis_b4:
name: camel_emis_b4
file_key: camel_emis
band_id: 3
file_type: [ camel_emis_file ]
wavelength: 5.8
resolution: 0.05

camel_emis_b5:
name: camel_emis_b5
file_key: camel_emis
band_id: 4
file_type: [ camel_emis_file ]
wavelength: 7.6
resolution: 0.05

camel_emis_b6:
name: camel_emis_b6
file_key: camel_emis
band_id: 5
file_type: [ camel_emis_file ]
wavelength: 8.3
resolution: 0.05

camel_emis_b7:
name: camel_emis_b7
file_key: camel_emis
band_id: 6
file_type: [ camel_emis_file ]
wavelength: 8.6
resolution: 0.05

camel_emis_b8:
name: camel_emis_b8
file_key: camel_emis
band_id: 7
file_type: [ camel_emis_file ]
wavelength: 9.1
resolution: 0.05

camel_emis_b9:
name: camel_emis_b9
file_key: camel_emis
band_id: 8
file_type: [ camel_emis_file ]
wavelength: 10.6
resolution: 0.05

camel_emis_b10:
name: camel_emis_b10
file_key: camel_emis
band_id: 9
file_type: [ camel_emis_file ]
wavelength: 10.8
resolution: 0.05

camel_emis_b11:
name: camel_emis_b11
file_key: camel_emis
band_id: 10
file_type: [ camel_emis_file ]
wavelength: 11.3
resolution: 0.05

camel_emis_b12:
name: camel_emis_b12
file_key: camel_emis
band_id: 11
file_type: [ camel_emis_file ]
wavelength: 12.1
resolution: 0.05

camel_emis_b13:
name: camel_emis_b13
file_key: camel_emis
band_id: 12
file_type: [ camel_emis_file ]
wavelength: 14.3
resolution: 0.05
106 changes: 106 additions & 0 deletions satpy/readers/camel_l3_nc.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,106 @@
#!/usr/bin/env python
# -*- coding: utf-8 -*-
# Copyright (c) 2024 Satpy developers
#
# This file is part of satpy.
#
# satpy is free software: you can redistribute it and/or modify it under the
# terms of the GNU General Public License as published by the Free Software
# Foundation, either version 3 of the License, or (at your option) any later
# version.
#
# satpy is distributed in the hope that it will be useful, but WITHOUT ANY
# WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR
# A PARTICULAR PURPOSE. See the GNU General Public License for more details.
#
# You should have received a copy of the GNU General Public License along with
# satpy. If not, see <http://www.gnu.org/licenses/>.

"""Reader for CAMEL Level 3 emissivity files in netCDF4 format.
For more information about the data, see: <https://lpdaac.usgs.gov/products/cam5k30emv002/>.
NOTE: This reader only supports the global 0.05 degree grid data.
"""


import datetime as dt
import logging

import xarray as xr
from pyresample import geometry

from satpy.readers.file_handlers import BaseFileHandler

logger = logging.getLogger(__name__)

# Area extent for the CAMEL product (global)
GLOB_AREA_EXT = [-180, -90, 180, 90]


class CAMELL3NCFileHandler(BaseFileHandler):
"""File handler for Himawari L2 NOAA enterprise data in netCDF format."""

def __init__(self, filename, filename_info, filetype_info):
"""Initialize the reader."""
super().__init__(filename, filename_info, filetype_info)
self.nc = xr.open_dataset(self.filename,
decode_cf=True,
mask_and_scale=True,
chunks={"xc": "auto", "yc": "auto"})

if self.nc.attrs["geospatial_lon_resolution"] != "0.05 degree grid ":
raise ValueError("Only 0.05 degree grid data is supported.")
if self.nc.attrs["geospatial_lat_resolution"] != "0.05 degree grid ":
raise ValueError("Only 0.05 degree grid data is supported.")
if self.nc.sizes["spectra"] != 13:
raise ValueError("Only CAMEL files with 13 spectral bands are supported.")

self.nlines = self.nc.sizes["latitude"]
self.ncols = self.nc.sizes["longitude"]
self.area = None


@property
def start_time(self):
"""Start timestamp of the dataset."""
date_str = self.nc.attrs["time_coverage_start"]
return dt.datetime.strptime(date_str, "%Y-%m-%d %H:%M:%SZ")

@property
def end_time(self):
"""End timestamp of the dataset."""
date_str = self.nc.attrs["time_coverage_end"]
return dt.datetime.strptime(date_str, "%Y-%m-%d %H:%M:%SZ")


def get_dataset(self, key, info):
"""Load a dataset."""
var = info["file_key"]
logger.debug("Reading in get_dataset %s.", var)
variable = self.nc[var]

# For the emissivity there are multiple bands, so we need to select the correct one
if var == "camel_emis":
variable = variable[:, :, info["band_id"]]

# Rename the latitude and longitude dimensions to x and y
variable = variable.rename({"latitude": "y", "longitude": "x"})

variable.attrs.update(key.to_dict())
return variable


def get_area_def(self, dsid):
"""Get the area definition, a global lat/lon area for this type of dataset."""
proj_param = "EPSG:4326"

area = geometry.AreaDefinition("gridded_camel",
"A global gridded area",
"longlat",
proj_param,
self.ncols,
self.nlines,
GLOB_AREA_EXT)
self.area = area
return area

0 comments on commit b2765d4

Please sign in to comment.