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

Add ability to clip AMI negative radiances #2806

Merged
merged 12 commits into from
Jul 20, 2024
2 changes: 1 addition & 1 deletion doc/source/config.rst
Original file line number Diff line number Diff line change
Expand Up @@ -272,7 +272,7 @@ If ``clip_negative_radiances=False``, pixels with negative radiances will have

Clipping of negative radiances is currently implemented for the following readers:

* ``abi_l1b``
* ``abi_l1b``, ``ami_l1b``


Temporary Directory
Expand Down
27 changes: 21 additions & 6 deletions satpy/readers/ami_l1b.py
Original file line number Diff line number Diff line change
Expand Up @@ -27,6 +27,7 @@
import xarray as xr
from pyspectral.blackbody import blackbody_wn_rad2temp as rad2temp

import satpy
from satpy.readers import open_file_or_filename
from satpy.readers._geos_area import get_area_definition, get_area_extent
from satpy.readers.file_handlers import BaseFileHandler
Expand Down Expand Up @@ -92,29 +93,33 @@

def __init__(self, filename, filename_info, filetype_info,
calib_mode="PYSPECTRAL", allow_conditional_pixels=False,
user_calibration=None):
user_calibration=None, clip_negative_radiances=None):
"""Open the NetCDF file with xarray and prepare the Dataset for reading."""
super(AMIL1bNetCDF, self).__init__(filename, filename_info, filetype_info)
f_obj = open_file_or_filename(self.filename)
self.nc = xr.open_dataset(f_obj,
decode_cf=True,
mask_and_scale=False,
chunks={"dim_image_x": CHUNK_SIZE, "dim_image_y": CHUNK_SIZE})
self.nc = self.nc.rename({"dim_image_x": "x", "dim_image_y": "y"})

platform_shortname = self.nc.attrs["satellite_name"]
self.platform_name = PLATFORM_NAMES.get(platform_shortname)
self.sensor = "ami"
self.band_name = filetype_info["file_type"].upper()
self.allow_conditional_pixels = allow_conditional_pixels
calib_mode_choices = ("FILE", "PYSPECTRAL", "GSICS")
if calib_mode.upper() not in calib_mode_choices:
raise ValueError("Invalid calibration mode: {}. Choose one of {}".format(
calib_mode, calib_mode_choices))

self.calib_mode = calib_mode.upper()
self.user_calibration = user_calibration

if clip_negative_radiances is None:
clip_negative_radiances = satpy.config.get("readers.clip_negative_radiances")
self.clip_negative_radiances = clip_negative_radiances

Check notice on line 121 in satpy/readers/ami_l1b.py

View check run for this annotation

CodeScene Delta Analysis / CodeScene Cloud Delta Analysis (main)

ℹ Getting worse: Excess Number of Function Arguments

AMIL1bNetCDF.__init__ increases from 6 to 7 arguments, threshold = 4. This function has too many arguments, indicating a lack of encapsulation. Avoid adding more arguments.

@property
def start_time(self):
"""Get observation start time."""
Expand Down Expand Up @@ -196,7 +201,7 @@
qf = data & 0b1100000000000000

# mask DQF bits
bits = attrs["number_of_valid_bits_per_pixel"]
bits = attrs["number_of_valid_bits_per_pixel"].astype(data.dtype)
data &= 2**bits - 1
# only take "no error" pixels as valid
data = data.where(qf == 0)
Expand All @@ -207,6 +212,7 @@

if dataset_id["calibration"] in ("radiance", "reflectance", "brightness_temperature"):
data = gain * data + offset
data = self._clip_negative_radiance(data, gain, offset)
if self.calib_mode == "GSICS":
data = self._apply_gsics_rad_correction(data)
elif isinstance(self.user_calibration, dict):
Expand All @@ -231,6 +237,16 @@
data.attrs = attrs
return data

def _clip_negative_radiance(self, data, gain, offset):
"""If requested, clip negative radiance from Rad DataArray."""
if self.clip_negative_radiances:
count_zero_rad = - offset / gain
# We need floor here as the scale factor for AMI is negative (unlike ABI)
count_pos = np.floor(count_zero_rad)
min_rad = count_pos * gain + offset
data = data.clip(min=min_rad)
return data

def _calibrate_ir(self, dataset_id, data):
"""Calibrate radiance data to BTs using either pyspectral or in-file coefficients."""
if self.calib_mode == "PYSPECTRAL":
Expand All @@ -242,10 +258,9 @@
bt_data = rad2temp(wn, data.data * 1e-5)
if isinstance(bt_data, np.ndarray):
# old versions of pyspectral produce numpy arrays
data.data = da.from_array(bt_data, chunks=data.data.chunks)
else:
# new versions of pyspectral can do dask arrays
data.data = bt_data
bt_data = da.from_array(bt_data, chunks=data.data.chunks)

Check warning on line 261 in satpy/readers/ami_l1b.py

View check run for this annotation

Codecov / codecov/patch

satpy/readers/ami_l1b.py#L261

Added line #L261 was not covered by tests
# new versions of pyspectral can do dask arrays
data.data = bt_data
else:
# IR coefficients from the file
# Channel specific
Expand Down
Loading
Loading