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

Merged
merged 17 commits into from
Jan 22, 2025
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
17 commits
Select commit Hold shift + click to select a range
ee0b31f
feature : Add the flash_age compositor into the /etc/composites/li.ya…
ClementLaplace Sep 3, 2024
2ffffc3
feature : Add the flash_age composite for li datas
ClementLaplace Sep 4, 2024
1e7db42
feature : Add the satpy/composites/lightning.py that enables flash_ag…
ClementLaplace Sep 4, 2024
efe81f2
modify : use the end_time attributes instead of the maximum values
ClementLaplace Sep 4, 2024
6b59245
test : Add the test related to the flash_age compositor
ClementLaplace Sep 20, 2024
0ebb1fe
feat : Handles case where xarray data is empty for flash_age composites.
ClementLaplace Sep 20, 2024
27eac75
typo : Correct operator multi lines error in test_lightning.py file
ClementLaplace Sep 20, 2024
aae6b98
test : Add test related to empty array after being filtered
ClementLaplace Sep 20, 2024
5897431
test : Add test concerning the missing data
ClementLaplace Sep 20, 2024
3edf893
typo : Erase useless comment
ClementLaplace Sep 23, 2024
a008f9f
correction : Apllied corrections asked in this MR https://github.com/…
ClementLaplace Jan 10, 2025
7676013
test: Correct the test_lightning.py::test_empty_array_error
ClementLaplace Jan 14, 2025
ad90c56
Merge branch 'main' into add_flash_age_compositor
ClementLaplace Jan 15, 2025
407c609
Merge branch 'main' into add_flash_age_compositor to avoid dask issues
ClementLaplace Jan 20, 2025
f202054
fix : fix the handling to drop date with dask array that is introduce…
ClementLaplace Jan 21, 2025
4c25948
fix: Correct the test by replacing numpy array to dask array to simul…
ClementLaplace Jan 21, 2025
01237e2
feat: Add the component element true_color_with_night_ir105_flash_age
ClementLaplace Jan 22, 2025
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
108 changes: 108 additions & 0 deletions satpy/composites/lightning.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,108 @@
#!/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 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."""
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_attr = self.attrs["reference_time"]


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

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_attr]))
# 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
condition_time = data >= begin_time
condition_time_computed = condition_time.compute()
data = data.where(condition_time_computed, 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}")
raise ValueError(f"Invalid data: data size is zero. All flash_age "
f"events occurred before the specified start time ({begin_time})."
)
# 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)


@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
# 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)
149 changes: 78 additions & 71 deletions satpy/etc/composites/fci.yaml
Original file line number Diff line number Diff line change
@@ -1,17 +1,17 @@
sensor_name: visir/fci

composites:
### L2
### L2
binary_cloud_mask:
# This will set all clear pixels to '0', all pixels with cloudy features (meteorological/dust/ash clouds) to '1' and
# missing/undefined pixels to 'nan'. This can be used for the official EUMETSAT cloud mask product (CLM).
compositor: !!python/name:satpy.composites.CategoricalDataCompositor
prerequisites:
- name: 'cloud_state'
lut: [ .nan, 0, 1, 1, 1, 1, 1, 1, 0, .nan ]
- name: "cloud_state"
lut: [.nan, 0, 1, 1, 1, 1, 1, 1, 0, .nan]
standard_name: binary_cloud_mask

### Night Layers
### Night Layers
night_ir105:
compositor: !!python/name:satpy.composites.SingleBandCompositor
prerequisites:
Expand Down Expand Up @@ -41,7 +41,7 @@ composites:
- night_ir_alpha
- _night_background_hires

### Green Corrections
### Green Corrections
ndvi_hybrid_green:
description: >
The FCI green band at 0.51 µm deliberately misses the chlorophyll band, such that
Expand All @@ -58,7 +58,7 @@ composites:
- name: vis_06
modifiers: [sunz_corrected, rayleigh_corrected, sunz_reduced]
- name: vis_08
modifiers: [sunz_corrected, sunz_reduced ]
modifiers: [sunz_corrected, sunz_reduced]
standard_name: toa_bidirectional_reflectance

ndvi_hybrid_green_raw:
Expand All @@ -76,18 +76,18 @@ composites:
ndvi_hybrid_green_fully_sunzencorrected:
description: Same as ndvi_hybrid_green, but without Sun-zenith reduction
compositor: !!python/name:satpy.composites.spectral.NDVIHybridGreen
limits: [ 0.15, 0.05 ]
limits: [0.15, 0.05]
strength: 3.0
prerequisites:
- name: vis_05
modifiers: [ sunz_corrected, rayleigh_corrected ]
modifiers: [sunz_corrected, rayleigh_corrected]
- name: vis_06
modifiers: [ sunz_corrected, rayleigh_corrected ]
modifiers: [sunz_corrected, rayleigh_corrected]
- name: vis_08
modifiers: [ sunz_corrected ]
modifiers: [sunz_corrected]
standard_name: toa_bidirectional_reflectance

### True Color
### True Color
true_color:
compositor: !!python/name:satpy.composites.SelfSharpenedRGB
description: >
Expand Down Expand Up @@ -190,7 +190,7 @@ composites:
- name: vis_04
standard_name: true_color_reproduction_color_stretch

### True Color with LI lightning
### True Color with LI lightning

true_color_with_night_ir105_acc_flash:
compositor: !!python/name:satpy.composites.BackgroundCompositor
Expand Down Expand Up @@ -227,74 +227,81 @@ composites:
- group_radiance_alpha
- true_color_with_night_ir105

### GeoColor
true_color_with_night_ir105_flash_age:
compositor: !!python/name:satpy.composites.BackgroundCompositor
standard_name: imager_with_lightning
prerequisites:
- flash_age
- true_color_with_night_ir105

### GeoColor
geo_color:
compositor: !!python/name:satpy.composites.DayNightCompositor
description: >
GeoColor is a multi-layer blended RGB composite where the day-time part of the image is represented by true
color imagery and the nighttime part of the image by a three layer vertically blended stack composed of a
high-level cloud layer (single IR window channel), a low-level cloud layer (IR split window) and a static
surface terrain layer with city lights (NASA Black Marble).
references:
Research Article: https://journals.ametsoc.org/view/journals/atot/37/3/JTECH-D-19-0134.1.xml
lim_low: 78
lim_high: 88
standard_name: geo_color_day_night_blend
prerequisites:
- true_color
- geo_color_night
compositor: !!python/name:satpy.composites.DayNightCompositor
description: >
GeoColor is a multi-layer blended RGB composite where the day-time part of the image is represented by true
color imagery and the nighttime part of the image by a three layer vertically blended stack composed of a
high-level cloud layer (single IR window channel), a low-level cloud layer (IR split window) and a static
surface terrain layer with city lights (NASA Black Marble).
references:
Research Article: https://journals.ametsoc.org/view/journals/atot/37/3/JTECH-D-19-0134.1.xml
lim_low: 78
lim_high: 88
standard_name: geo_color_day_night_blend
prerequisites:
- true_color
- geo_color_night

geo_color_high_clouds:
standard_name: geo_color_high_clouds
compositor: !!python/name:satpy.composites.HighCloudCompositor
prerequisites:
- name: ir_105
standard_name: geo_color_high_clouds
compositor: !!python/name:satpy.composites.HighCloudCompositor
prerequisites:
- name: ir_105

geo_color_low_clouds:
standard_name: geo_color_low_clouds
compositor: !!python/name:satpy.composites.LowCloudCompositor
values_water: 0
values_land: 100
range_water: [0.0, 4.0]
range_land: [1.5, 4.0]
prerequisites:
- compositor: !!python/name:satpy.composites.DifferenceCompositor
prerequisites:
- name: ir_105
- name: ir_38
- name: ir_105
- compositor: !!python/name:satpy.composites.StaticImageCompositor
standard_name: land_water_mask
url: "https://zenodo.org/records/10076199/files/gshhs_land_water_mask_3km_i.tif"
known_hash: "sha256:96df83c57416217e191f95dde3d3c1ce0373a8fc220e929228873db246ca3569"
standard_name: geo_color_low_clouds
compositor: !!python/name:satpy.composites.LowCloudCompositor
values_water: 0
values_land: 100
range_water: [0.0, 4.0]
range_land: [1.5, 4.0]
prerequisites:
- compositor: !!python/name:satpy.composites.DifferenceCompositor
prerequisites:
- name: ir_105
- name: ir_38
- name: ir_105
- compositor: !!python/name:satpy.composites.StaticImageCompositor
standard_name: land_water_mask
url: "https://zenodo.org/records/10076199/files/gshhs_land_water_mask_3km_i.tif"
known_hash: "sha256:96df83c57416217e191f95dde3d3c1ce0373a8fc220e929228873db246ca3569"

geo_color_background_with_low_clouds:
compositor: !!python/name:satpy.composites.BackgroundCompositor
standard_name: night_ir_with_background
prerequisites:
- geo_color_low_clouds
- _night_background_hires
compositor: !!python/name:satpy.composites.BackgroundCompositor
standard_name: night_ir_with_background
prerequisites:
- geo_color_low_clouds
- _night_background_hires

geo_color_night:
compositor: !!python/name:satpy.composites.BackgroundCompositor
standard_name: night_ir_with_background
prerequisites:
- geo_color_high_clouds
- geo_color_background_with_low_clouds
compositor: !!python/name:satpy.composites.BackgroundCompositor
standard_name: night_ir_with_background
prerequisites:
- geo_color_high_clouds
- geo_color_background_with_low_clouds

### IR-Sandwich
### IR-Sandwich
ir_sandwich:
compositor: !!python/name:satpy.composites.SandwichCompositor
standard_name: ir_sandwich
prerequisites:
- name: 'vis_06'
modifiers: [ sunz_corrected ]
- name: "vis_06"
modifiers: [sunz_corrected]
- name: colorized_ir_clouds

colorized_ir_clouds:
compositor: !!python/name:satpy.composites.SingleBandCompositor
prerequisites:
- name: 'ir_105'
- name: "ir_105"
standard_name: colorized_ir_clouds

ir_sandwich_with_night_colorized_ir_clouds:
Expand All @@ -306,7 +313,7 @@ composites:
- ir_sandwich
- colorized_ir_clouds

### other RGBs
### other RGBs
cloud_type:
description: >
Equal to cimss_cloud_type recipe, but with additional sunz_reducer modifier to avoid saturation at the terminator.
Expand All @@ -316,11 +323,11 @@ composites:
compositor: !!python/name:satpy.composites.GenericCompositor
prerequisites:
- name: nir_13
modifiers: [ sunz_corrected, sunz_reduced ]
modifiers: [sunz_corrected, sunz_reduced]
- name: vis_06
modifiers: [ sunz_corrected, sunz_reduced ]
modifiers: [sunz_corrected, sunz_reduced]
- name: nir_16
modifiers: [ sunz_corrected, sunz_reduced ]
modifiers: [sunz_corrected, sunz_reduced]
standard_name: cimss_cloud_type

cloud_type_with_night_ir105:
Expand Down Expand Up @@ -416,10 +423,10 @@ composites:
Recipe: https://resources.eumetrain.org/RGBguide/recipes/RGB_recipes.pdf
compositor: !!python/name:satpy.composites.GenericCompositor
prerequisites:
- name: vis_08
modifiers: [sunz_corrected]
- name: nir_16
modifiers: [sunz_corrected]
- name: ir_38
modifiers: [nir_reflectance]
- name: vis_08
modifiers: [sunz_corrected]
- name: nir_16
modifiers: [sunz_corrected]
- name: ir_38
modifiers: [nir_reflectance]
standard_name: snow
Loading
Loading