Skip to article frontmatterSkip to article content
Site not loading correctly?

This may be due to an incorrect BASE_URL configuration. See the MyST Documentation for reference.

Advanced Baseline Imager (ABI) data with Satpy

pythia ncar

This notebook is developed during the pythia cook-off at NCAR Mesa-Lab Boulder Colorado, June 12-14, 2024

Participants in the workshop event have the chance to practice collaborative problem-solving and hands-on learning in the field of Python programming.

This notebook is part of the Breakout Topic: Geostationary on AWS, lead by Jorge Humberto Bravo Mendez jbravo2@stevens.edu, from Stevens Institute of Technology

Advanced Baseline Imager (ABI) data with Satpy

Using Satpy to read and Advanced Baseline Imager (ABI) data from GOES-R satellites. Here’s a step-by-step guide:


Imports

import warnings
warnings.filterwarnings('ignore')
warnings.simplefilter('ignore', SyntaxWarning)

from satpy.scene import Scene
from satpy.utils import debug_on

from datetime import datetime

from glob import glob

Starting to create satpy scenes

sat_files = glob("input/G16_ABI-L1b-RadC/*")
sat_files
['input/G16_ABI-L1b-RadC/OR_ABI-L1b-RadC-M6C12_G16_s20232561536173_e20232561538552_c20232561539031.nc', 'input/G16_ABI-L1b-RadC/OR_ABI-L1b-RadC-M6C09_G16_s20232561536173_e20232561538551_c20232561538580.nc', 'input/G16_ABI-L1b-RadC/OR_ABI-L1b-RadC-M6C04_G16_s20232561536173_e20232561538546_c20232561539001.nc', 'input/G16_ABI-L1b-RadC/OR_ABI-L1b-RadC-M6C03_G16_s20232561536173_e20232561538546_c20232561538589.nc', 'input/G16_ABI-L1b-RadC/OR_ABI-L1b-RadC-M6C15_G16_s20232561536173_e20232561538551_c20232561539007.nc', 'input/G16_ABI-L1b-RadC/OR_ABI-L1b-RadC-M6C13_G16_s20232561536173_e20232561538557_c20232561539004.nc', 'input/G16_ABI-L1b-RadC/OR_ABI-L1b-RadC-M6C14_G16_s20232561536173_e20232561538546_c20232561538592.nc', 'input/G16_ABI-L1b-RadC/OR_ABI-L1b-RadC-M6C02_G16_s20232561536173_e20232561538546_c20232561538578.nc', 'input/G16_ABI-L1b-RadC/OR_ABI-L1b-RadC-M6C16_G16_s20232561536173_e20232561538557_c20232561539036.nc', 'input/G16_ABI-L1b-RadC/OR_ABI-L1b-RadC-M6C01_G16_s20232561536173_e20232561538548_c20232561538585.nc', 'input/G16_ABI-L1b-RadC/OR_ABI-L1b-RadC-M6C10_G16_s20232561536173_e20232561538557_c20232561539020.nc', 'input/G16_ABI-L1b-RadC/OR_ABI-L1b-RadC-M6C05_G16_s20232561536173_e20232561538546_c20232561539016.nc', 'input/G16_ABI-L1b-RadC/OR_ABI-L1b-RadC-M6C07_G16_s20232561536173_e20232561538557_c20232561539026.nc', 'input/G16_ABI-L1b-RadC/OR_ABI-L1b-RadC-M6C11_G16_s20232561536173_e20232561538546_c20232561539034.nc', 'input/G16_ABI-L1b-RadC/OR_ABI-L1b-RadC-M6C08_G16_s20232561536173_e20232561538546_c20232561538598.nc', 'input/G16_ABI-L1b-RadC/OR_ABI-L1b-RadC-M6C06_G16_s20232561536173_e20232561538551_c20232561539011.nc']
scn = Scene(filenames = sat_files, reader='abi_l1b')

dataset_names = scn.all_dataset_names()

print(dataset_names)
['C01', 'C02', 'C03', 'C04', 'C05', 'C06', 'C07', 'C08', 'C09', 'C10', 'C11', 'C12', 'C13', 'C14', 'C15', 'C16']
scn.load([f'C{x:02d}' for x in range(1, 17)])
print(scn.available_composite_names())
['24h_microphysics', 'airmass', 'ash', 'cimss_cloud_type', 'cimss_cloud_type_raw', 'cimss_green', 'cimss_green_sunz', 'cimss_green_sunz_rayleigh', 'cimss_true_color', 'cimss_true_color_sunz', 'cimss_true_color_sunz_rayleigh', 'cira_day_convection', 'cira_fire_temperature', 'cloud_phase', 'cloud_phase_distinction', 'cloud_phase_distinction_raw', 'cloud_phase_raw', 'cloudtop', 'color_infrared', 'colorized_ir_clouds', 'convection', 'day_blowing_snow', 'day_cloud_type', 'day_cloud_type_distinction', 'day_cloud_type_distinction_raw', 'day_microphysics', 'day_microphysics_abi', 'day_microphysics_eum', 'day_severe_storms', 'day_severe_storms_tropical', 'dust', 'fire_temperature_awips', 'fog', 'geo_color', 'geo_color_background_with_low_clouds', 'geo_color_high_clouds', 'geo_color_low_clouds', 'geo_color_night', 'green', 'green_crefl', 'green_nocorr', 'green_raw', 'green_snow', 'highlight_C14', 'ir108_3d', 'ir_cloud_day', 'land_cloud', 'land_cloud_fire', 'natural_color', 'natural_color_nocorr', 'natural_color_raw', 'natural_color_raw_with_night_ir', 'night_fog', 'night_ir_alpha', 'night_ir_with_background', 'night_ir_with_background_hires', 'night_microphysics', 'night_microphysics_eum', 'night_microphysics_tropical', 'overshooting_tops', 'overview', 'overview_raw', 'rocket_plume_day', 'rocket_plume_night', 'simple_water_vapor', 'snow', 'snow_fog', 'so2', 'tropical_airmass', 'true_color', 'true_color_crefl', 'true_color_nocorr', 'true_color_raw', 'true_color_reproduction', 'true_color_reproduction_corr', 'true_color_reproduction_uncorr', 'true_color_with_night_fires', 'true_color_with_night_fires_nocorr', 'true_color_with_night_ir', 'true_color_with_night_ir_hires', 'volcanic_emissions', 'water_vapors1', 'water_vapors2']
rgb_im = 'airmass'

scn.load([rgb_im])
### Uncomment to show it
#scn.show(rgb_im)
result = scn[rgb_im]

#result
keys = scn.keys()

#keys
area_info = scn["C13"].area

#area_info
area_info = scn["C01"].area

#area_info
area_info = scn["C02"].area

#area_info
scn.load(["natural_color"])
The following datasets were not created and may require resampling to be generated: DataID(name='natural_color')
rs = scn["C13"].area

lscn = scn.resample(rs)
lscn.load(["natural_color"])

### Uncomment to show it
#lscn.show("natural_color")
lscn.load(['true_color'])

### Uncomment to show it
#lscn.show('true_color')
0kB [00:00, ?kB/s]
1kB [00:00, 14716.86kB/s]

---------------------------------------------------------------------------
ReadError                                 Traceback (most recent call last)
Cell In[16], line 1
----> 1 lscn.load(['true_color'])
      3 ### Uncomment to show it
      4 #lscn.show('true_color')

File ~/micromamba/envs/geostationary-cookbook/lib/python3.14/site-packages/satpy/scene.py:1484, in Scene.load(self, wishlist, calibration, resolution, polarization, level, modifiers, generate, unload, **kwargs)
   1482 self._read_datasets_from_storage(**kwargs)
   1483 if generate:
-> 1484     self.generate_possible_composites(unload)

File ~/micromamba/envs/geostationary-cookbook/lib/python3.14/site-packages/satpy/scene.py:1547, in Scene.generate_possible_composites(self, unload)
   1540 def generate_possible_composites(self, unload):
   1541     """See which composites can be generated and generate them.
   1542 
   1543     Args:
   1544         unload (bool): if the dependencies of the composites
   1545                        should be unloaded after successful generation.
   1546     """
-> 1547     keepables = self._generate_composites_from_loaded_datasets()
   1549     if self.missing_datasets:
   1550         self._remove_failed_datasets(keepables)

File ~/micromamba/envs/geostationary-cookbook/lib/python3.14/site-packages/satpy/scene.py:1566, in Scene._generate_composites_from_loaded_datasets(self)
   1563 trunk_nodes = self._dependency_tree.trunk(limit_nodes_to=self.missing_datasets,
   1564                                           limit_children_to=self._datasets.keys())
   1565 needed_comp_nodes = set(self._filter_loaded_datasets_from_trunk_nodes(trunk_nodes))
-> 1566 return self._generate_composites_nodes_from_loaded_datasets(needed_comp_nodes)

File ~/micromamba/envs/geostationary-cookbook/lib/python3.14/site-packages/satpy/scene.py:1572, in Scene._generate_composites_nodes_from_loaded_datasets(self, compositor_nodes)
   1570 keepables = set()
   1571 for node in compositor_nodes:
-> 1572     self._generate_composite(node, keepables)
   1573 return keepables

File ~/micromamba/envs/geostationary-cookbook/lib/python3.14/site-packages/satpy/scene.py:1630, in Scene._generate_composite(self, comp_node, keepables)
   1627     return
   1629 try:
-> 1630     composite = compositor(prereq_datasets,
   1631                            optional_datasets=optional_datasets,
   1632                            **comp_node.name.to_dict())
   1633     cid = DataID.new_id_from_dataarray(composite)
   1634     self._datasets[cid] = composite

File ~/micromamba/envs/geostationary-cookbook/lib/python3.14/site-packages/satpy/modifiers/atmosphere.py:107, in PSPRayleighReflectance.__call__(self, projectables, optional_datasets, **info)
    102 reduce_strength = np.clip(self.attrs.get("reduce_strength", 0), 0, 1).astype(vis.dtype)
    104 logger.info("Removing Rayleigh scattering with atmosphere '%s' and "
    105             "aerosol type '%s' for '%s'",
    106             atmosphere, aerosol_type, vis.attrs["name"])
--> 107 corrector = Rayleigh(vis.attrs["platform_name"], vis.attrs["sensor"],
    108                      atmosphere=atmosphere,
    109                      aerosol_type=aerosol_type)
    111 try:
    112     refl_cor_band = corrector.get_reflectance(sunz, satz, ssadiff,
    113                                               vis.attrs["name"],
    114                                               red.data)

File ~/micromamba/envs/geostationary-cookbook/lib/python3.14/site-packages/pyspectral/rayleigh.py:173, in Rayleigh.__init__(self, platform_name, sensor, **kwargs)
    171 if not self._lutfiles_version_uptodate and self.do_download:
    172     LOG.info("Will download from internet...")
--> 173     download_luts(aerosol_types=[aerosol_type])
    175 if (not os.path.exists(self.reflectance_lut_filename) or
    176         not os.path.isfile(self.reflectance_lut_filename)):
    177     raise IOError('pyspectral file for Rayleigh scattering correction ' +
    178                   'does not exist! Filename = ' +
    179                   str(self.reflectance_lut_filename))

File ~/micromamba/envs/geostationary-cookbook/lib/python3.14/site-packages/pyspectral/utils.py:393, in download_luts(aerosol_types, dry_run, aerosol_type)
    390     continue
    392 local_tarball_pathname = os.path.join(subdir_path, "pyspectral_rayleigh_correction_luts.tgz")
--> 393 _download_tarball_and_extract(lut_tarball_url, local_tarball_pathname, subdir_path)

File ~/micromamba/envs/geostationary-cookbook/lib/python3.14/site-packages/pyspectral/utils.py:420, in _download_tarball_and_extract(tarball_url, local_pathname, extract_dir)
    415     for data in _tqdm_or_iter(response.iter_content(chunk_size=chunk_size),
    416                               total=(int(total_size / chunk_size + 0.5)),
    417                               unit='kB'):
    418         handle.write(data)
--> 420 tar = tarfile.open(local_pathname)
    421 tar_kwargs = {} if sys.version_info < (3, 12) else {"filter": "data"}
    422 tar.extractall(extract_dir, **tar_kwargs)

File ~/micromamba/envs/geostationary-cookbook/lib/python3.14/tarfile.py:1904, in TarFile.open(cls, name, mode, fileobj, bufsize, **kwargs)
   1902             continue
   1903     error_msgs_summary = '\n'.join(error_msgs)
-> 1904     raise ReadError(f"file could not be opened successfully:\n{error_msgs_summary}")
   1906 elif ":" in mode:
   1907     filemode, comptype = mode.split(":", 1)

ReadError: file could not be opened successfully:
- method gz: ReadError('not a gzip file')
- method bz2: ReadError('not a bzip2 file')
- method xz: ReadError('not an lzma file')
- method zst: ReadError('not a zstd file')
- method tar: ReadError('truncated header')