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 flash age compositor for li instruments #2895

Open
wants to merge 10 commits into
base: main
Choose a base branch
from
Open
106 changes: 106 additions & 0 deletions satpy/composites/lightning.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,106 @@
#!/usr/bin/env python
# -*- coding: utf-8 -*-
# Copyright (c) 2019 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/>.
"""Composite classes for the LI instrument."""

import logging
import sys

import numpy as np
import xarray as xr

from satpy.composites import CompositeBase

LOG = logging.getLogger(__name__)


class LightningTimeCompositor(CompositeBase):
"""Class used to create the flash_age compositor usefull for lighting event visualisation.

The datas used are dates related to the lightning event that should be normalised between
0 and 1. The value 1 corresponds to the latest lightning event and the value 0 corresponds
to the latest lightning event - time_range. The time_range is defined in the satpy/etc/composites/li.yaml
and is in minutes.
"""
def __init__(self, name, prerequisites=None, optional_prerequisites=None, **kwargs):
"""Initialisation of the class."""
self.name = name
super().__init__(name, prerequisites, optional_prerequisites, **kwargs)
Comment on lines +41 to +42
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Suggested change
self.name = name
super().__init__(name, prerequisites, optional_prerequisites, **kwargs)
super().__init__(name, prerequisites, optional_prerequisites, **kwargs)

# Get the time_range which is in minute
self.time_range = self.attrs["time_range"]
self.standard_name = self.attrs["standard_name"]
self.reference_time = self.attrs["reference_time"]
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This is actually the name of the attribute in the DataArray.attrs, right? Could this be renamed reference_time_attr or something?



def _normalize_time(self,data:xr.DataArray,attrs:dict)->xr.DataArray:
"""Normalised the time in the range between [end_time,end_time - time_range].
Comment on lines +49 to +50
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Suggested change
def _normalize_time(self,data:xr.DataArray,attrs:dict)->xr.DataArray:
"""Normalised the time in the range between [end_time,end_time - time_range].
def _normalize_time(self, data:xr.DataArray,attrs:dict) -> xr.DataArray:
"""Normalize the time in the range between [end_time, end_time - time_range].

I'm not sure why the linter isn't marking the spaces or the docstring first word. Ruff must not be able to do that yet.


The range of the normalised data is between 0 and 1 where 0 corresponds to the date end_time - time_range
and 1 to the end_time. Where end_times represent the latest lightning event and time_range is the range of
time you want to see the event.The dates that are earlier to end_time - time_range are removed.

Args:
data (xr.DataArray): datas containing dates to be normalised
attrs (dict): Attributes suited to the flash_age composite

Returns:
xr.DataArray: Normalised time
"""
# Compute the maximum time value
end_time = np.array(np.datetime64(data.attrs[self.reference_time]))
# Compute the minimum time value based on the time range
begin_time = end_time - np.timedelta64(self.time_range, "m")
# Drop values that are bellow begin_time
data = data.where(data >= begin_time, drop=True)
# exit if data is empty afer filtering
if data.size == 0 :
LOG.error(f"All the flash_age events happened before {begin_time}")
sys.exit(1)
Comment on lines +70 to +72
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Composites should not be exiting the system. Some exception should be raised or an empty image/composite should be the result.

# Normalize the time values
normalized_data = (data - begin_time) / (end_time - begin_time)
# Ensure the result is still an xarray.DataArray
return xr.DataArray(normalized_data, dims=data.dims, coords=data.coords,attrs=attrs)
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Suggested change
return xr.DataArray(normalized_data, dims=data.dims, coords=data.coords,attrs=attrs)
return xr.DataArray(normalized_data, dims=data.dims, coords=data.coords, attrs=attrs)



@staticmethod
def _update_missing_metadata(existing_attrs, new_attrs):
for key, val in new_attrs.items():
if key not in existing_attrs and val is not None:
existing_attrs[key] = val

def _redefine_metadata(self,attrs:dict)->dict:
"""Modify the standard_name and name metadatas.

Args:
attrs (dict): data's attributes

Returns:
dict: atualised attributes
"""
attrs["name"] = self.standard_name
attrs["standard_name"] =self.standard_name
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Suggested change
attrs["standard_name"] =self.standard_name
attrs["standard_name"] = self.standard_name

# Attributes to describe the values range
return attrs


def __call__(self,projectables, nonprojectables=None, **attrs):
"""Normalise the dates."""
data = projectables[0]
new_attrs = data.attrs.copy()
self._update_missing_metadata(new_attrs, attrs)
new_attrs = self._redefine_metadata(new_attrs)
return self._normalize_time(data,new_attrs)
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Suggested change
return self._normalize_time(data,new_attrs)
return self._normalize_time(data, new_attrs)

31 changes: 20 additions & 11 deletions satpy/etc/composites/li.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -10,69 +10,78 @@ composites:
compositor: !!python/name:satpy.composites.SingleBandCompositor
standard_name: acc_flash
prerequisites:
- flash_accumulation
- flash_accumulation
acc_flash_alpha:
description: Composite to colorise the AF product using the flash accumulation with transparency
compositor: !!python/name:satpy.composites.SingleBandCompositor
standard_name: acc_flash_alpha
prerequisites:
- flash_accumulation
- flash_accumulation

acc_flash_area:
description: Composite to colorise the AFA product using the flash area
compositor: !!python/name:satpy.composites.SingleBandCompositor
standard_name: acc_flash_area
prerequisites:
- accumulated_flash_area
- accumulated_flash_area
acc_flash_area_alpha:
description: Composite to colorise the AFA product using the flash area with transparency
compositor: !!python/name:satpy.composites.SingleBandCompositor
standard_name: acc_flash_area_alpha
prerequisites:
- accumulated_flash_area
- accumulated_flash_area

acc_flash_radiance:
description: Composite to colorise the AFR product using the flash radiance
compositor: !!python/name:satpy.composites.SingleBandCompositor
standard_name: lightning_radiance
prerequisites:
- flash_radiance
- flash_radiance
acc_flash_radiance_alpha:
description: Composite to colorise the AFR product using the flash radiance with transparency
compositor: !!python/name:satpy.composites.SingleBandCompositor
standard_name: lightning_radiance_alpha
prerequisites:
- flash_radiance
- flash_radiance

flash_radiance:
description: Composite to colorise the LFL product using the flash radiance
compositor: !!python/name:satpy.composites.SingleBandCompositor
standard_name: lightning_radiance
prerequisites:
- radiance
- radiance
flash_radiance_alpha:
description: Composite to colorise the LFL product using the flash radiance with transparency
compositor: !!python/name:satpy.composites.SingleBandCompositor
standard_name: lightning_radiance_alpha
prerequisites:
- radiance
- radiance

group_radiance:
description: Composite to colorise the LGR product using the flash radiance
compositor: !!python/name:satpy.composites.SingleBandCompositor
standard_name: lightning_radiance
prerequisites:
- radiance
- radiance
group_radiance_alpha:
description: Composite to colorise the LGR product using the flash radiance with transparency
compositor: !!python/name:satpy.composites.SingleBandCompositor
standard_name: lightning_radiance_alpha
prerequisites:
- radiance
- radiance

# DEPRECATED, USE acc_flash_area INSTEAD
flash_area:
compositor: !!python/name:satpy.composites.SingleBandCompositor
standard_name: acc_flash_area
prerequisites:
- accumulated_flash_area
- accumulated_flash_area

flash_age:
description: Composite to colorise the LFL product using the flash time
compositor: !!python/name:satpy.composites.lightning.LightningTimeCompositor
standard_name: lightning_time
time_range: 60 # range for colormap in minutes
reference_time: end_time
prerequisites:
- flash_time
94 changes: 59 additions & 35 deletions satpy/etc/enhancements/li.yaml
Original file line number Diff line number Diff line change
@@ -1,60 +1,84 @@
enhancements:
# note that the colormap parameters are tuned for 5 minutes of files accumulation
# these are tentative recipes that will need to be further tuned as we gain experience with LI data
# note that the colormap parameters are tuned for 5 minutes of files accumulation
# these are tentative recipes that will need to be further tuned as we gain experience with LI data

acc_flash:
standard_name: acc_flash
operations:
- name: colorize
method: !!python/name:satpy.enhancements.colorize
kwargs:
palettes:
- {colors: ylorrd, min_value: 0, max_value: 5}
- name: colorize
method: !!python/name:satpy.enhancements.colorize
kwargs:
palettes:
- { colors: ylorrd, min_value: 0, max_value: 5 }

acc_flash_alpha:
standard_name: acc_flash_alpha
operations:
- name: colorize
method: !!python/name:satpy.enhancements.colorize
kwargs:
palettes:
- {colors: ylorrd, min_value: 0, max_value: 5,
min_alpha: 120, max_alpha: 180}
- name: colorize
method: !!python/name:satpy.enhancements.colorize
kwargs:
palettes:
- {
colors: ylorrd,
min_value: 0,
max_value: 5,
min_alpha: 120,
max_alpha: 180,
}

acc_flash_area:
standard_name: acc_flash_area
operations:
- name: colorize
method: !!python/name:satpy.enhancements.colorize
kwargs:
palettes:
- {colors: ylorrd, min_value: 0, max_value: 20}
- name: colorize
method: !!python/name:satpy.enhancements.colorize
kwargs:
palettes:
- { colors: ylorrd, min_value: 0, max_value: 20 }

acc_flash_area_alpha:
standard_name: acc_flash_area_alpha
operations:
- name: colorize
method: !!python/name:satpy.enhancements.colorize
kwargs:
palettes:
- {colors: ylorrd, min_value: 0, max_value: 20,
min_alpha: 120, max_alpha: 180}
- name: colorize
method: !!python/name:satpy.enhancements.colorize
kwargs:
palettes:
- {
colors: ylorrd,
min_value: 0,
max_value: 20,
min_alpha: 120,
max_alpha: 180,
}

lightning_radiance:
standard_name: lightning_radiance
operations:
- name: colorize
method: !!python/name:satpy.enhancements.colorize
kwargs:
palettes:
- {colors: ylorrd, min_value: 0, max_value: 1000}
- name: colorize
method: !!python/name:satpy.enhancements.colorize
kwargs:
palettes:
- { colors: ylorrd, min_value: 0, max_value: 1000 }

lightning_radiance_alpha:
standard_name: lightning_radiance_alpha
operations:
- name: colorize
method: !!python/name:satpy.enhancements.colorize
kwargs:
palettes:
- {colors: ylorrd, min_value: 0, max_value: 1000,
min_alpha: 120, max_alpha: 180}
- name: colorize
method: !!python/name:satpy.enhancements.colorize
kwargs:
palettes:
- {
colors: ylorrd,
min_value: 0,
max_value: 1000,
min_alpha: 120,
max_alpha: 180,
}

lightning_time:
standard_name: lightning_time
operations:
- name: colorize
method: !!python/name:satpy.enhancements.colorize
kwargs:
palettes:
- { colors: ylorrd, min_value: 0, max_value: 1 }
Loading
Loading