diff --git a/satpy/etc/readers/goesr_netcdficare.yaml b/satpy/etc/readers/goesr_netcdficare.yaml new file mode 100644 index 0000000000..4b36914b67 --- /dev/null +++ b/satpy/etc/readers/goesr_netcdficare.yaml @@ -0,0 +1,306 @@ +# References: +# - GOES Level 1.5 Image Data Format Description +# - Radiometric Calibration of GOESR ABI Level 1.5 Image Data in Equivalent +# Spectral Blackbody Radiance +# Netcdf built by Icare and Meteo France. Stored at Icare. + +reader: + name: goesr_netcdficare + short_name: goesr_NETCDF_ICARE + long_name: METEOFRANCE GEOSTATIONARY NETCDF BUILD for ICARE (Lille) + description: A reader for L1b NETCDF for all GEOSTATIONNARY retrieved from the ICARE service. + status: Defunct + supports_fsspec: false + sensors: [abi] + default_channels: [VIS_004, VIS_006, VIS_008, VIS_014, VIS_016, VIS_022, IR_039, IR_062, IR_069, IR_073, IR_085, IR_096, IR_103, IR_112, IR_123, IR_133] + reader: !!python/name:satpy.readers.yaml_reader.FileYAMLReader + +file_types: + + GOES500m : + file_reader: !!python/name:satpy.readers.geos_netcdficare.NETCDF_ICARE + file_patterns: ['Emultic500mNC4_{platform_shortname:6s}_{start_time:%Y%m%d%H%M}.nc', + 'Wmultic500mNC4_{platform_shortname:6s}_{start_time:%Y%m%d%H%M}.nc', + 'Emultic500mNC4_{platform_shortname:6s}_{start_time:%Y%m%d_%H%M}.nc', + 'Wmultic500mNC4_{platform_shortname:6s}_{start_time:%Y%m%d_%H%M}.nc'] + + GOES1km : + file_reader: !!python/name:satpy.readers.geos_netcdficare.NETCDF_ICARE + file_patterns: ['Emultic1kmNC4_{platform_shortname:6s}_{start_time:%Y%m%d%H%M}.nc', + 'Wmultic1kmNC4_{platform_shortname:6s}_{start_time:%Y%m%d%H%M}.nc', + 'Emultic1kmNC4_{platform_shortname:6s}_{start_time:%Y%m%d_%H%M}.nc', + 'Wmultic1kmNC4_{platform_shortname:6s}_{start_time:%Y%m%d_%H%M}.nc'] + + GOES2km : + file_reader: !!python/name:satpy.readers.geos_netcdficare.NETCDF_ICARE + file_patterns: ['Emultic2kmNC4_{platform_shortname:6s}_{start_time:%Y%m%d%H%M}.nc', + 'Wmultic2kmNC4_{platform_shortname:6s}_{start_time:%Y%m%d%H%M}.nc', + 'Emultic2kmNC4_{platform_shortname:6s}_{start_time:%Y%m%d_%H%M}.nc', + 'Wmultic2kmNC4_{platform_shortname:6s}_{start_time:%Y%m%d_%H%M}.nc'] + + +datasets: + + VIS_004 : + name: C01 + wavelength: [0.450, 0.470, 0.490] + resolution: + 1000: { file_type: GOES1km } + 2000: { file_type: GOES2km } + calibration: + radiance: + standard_name: toa_outgoing_radiance_per_unit_wavelength + units: W m-2 um-1 sr-1 + reflectance: + standard_name: toa_bidirectional_reflectance + units: "%" + counts: + standard_name: counts + units: "1" + file_type: [GOES2km, GOES1km] + + VIS_006 : + name: C02 + wavelength: [0.590, 0.640, 0.690] + resolution: + 500: { file_type: GOES500m } + 2000: { file_type: GOES2km } + calibration: + radiance: + standard_name: toa_outgoing_radiance_per_unit_wavelength + units: W m-2 um-1 sr-1 + reflectance: + standard_name: toa_bidirectional_reflectance + units: "%" + counts: + standard_name: counts + units: "1" + file_type: [GOES2km, GOES500m] + + VIS_008 : + name: C03 + wavelength: [0.8455, 0.865, 0.8845] + resolution: + 1000: { file_type: GOES1km } + 2000: { file_type: GOES2km } + calibration: + radiance: + standard_name: toa_outgoing_radiance_per_unit_wavelength + units: W m-2 um-1 sr-1 + reflectance: + standard_name: toa_bidirectional_reflectance + units: "%" + counts: + standard_name: counts + units: "1" + file_type: [GOES2km, GOES1km] + + VIS_014 : + name: C04 + wavelength: [1.3705, 1.378, 1.3855] + resolution: 2000 + calibration: + radiance: + standard_name: toa_outgoing_radiance_per_unit_wavelength + units: W m-2 um-1 sr-1 + reflectance: + standard_name: toa_bidirectional_reflectance + units: "%" + counts: + standard_name: counts + units: "1" + file_type: GOES2km + + VIS_016 : + name: C05 + wavelength: [1.580, 1.610, 1.640] + resolution: + 1000: { file_type: GOES1km } + 2000: { file_type: GOES2km } + calibration: + radiance: + standard_name: toa_outgoing_radiance_per_unit_wavelength + units: W m-2 um-1 sr-1 + reflectance: + standard_name: toa_bidirectional_reflectance + units: "%" + counts: + standard_name: counts + units: "1" + file_type: [GOES2km, GOES1km] + + VIS_022 : + name: C06 + wavelength: [2.225, 2.250, 2.275] + resolution: 2000 + calibration: + radiance: + standard_name: toa_outgoing_radiance_per_unit_wavelength + units: W m-2 um-1 sr-1 + reflectance: + standard_name: toa_bidirectional_reflectance + units: "%" + counts: + standard_name: counts + units: "1" + file_type: GOES2km + + IR_039 : + name: C07 + wavelength: [3.80, 3.90, 4.00] + resolution: 2000 + calibration: + radiance: + standard_name: toa_outgoing_radiance_per_unit_wavenumber + units: mW m-2 sr-1 (cm-1)-1 + brightness_temperature: + standard_name: toa_brightness_temperature + units: K + counts: + standard_name: counts + units: "1" + file_type: GOES2km + + IR_062 : + name: C08 + wavelength: [5.770, 6.185, 6.600] + resolution: 2000 + calibration: + radiance: + standard_name: toa_outgoing_radiance_per_unit_wavenumber + units: mW m-2 sr-1 (cm-1)-1 + brightness_temperature: + standard_name: toa_brightness_temperature + units: K + counts: + standard_name: counts + units: "1" + file_type: GOES2km + + IR_069 : + name: C09 + wavelength: [6.75, 6.95, 7.15] + resolution: 2000 + calibration: + radiance: + standard_name: toa_outgoing_radiance_per_unit_wavenumber + units: mW m-2 sr-1 (cm-1)-1 + brightness_temperature: + standard_name: toa_brightness_temperature + units: K + counts: + standard_name: counts + units: "1" + file_type: GOES2km + + IR_073 : + name: C10 + wavelength: [7.24, 7.34, 7.44] + resolution: 2000 + calibration: + radiance: + standard_name: toa_outgoing_radiance_per_unit_wavenumber + units: mW m-2 sr-1 (cm-1)-1 + brightness_temperature: + standard_name: toa_brightness_temperature + units: K + counts: + standard_name: counts + units: "1" + file_type: GOES2km + + IR_085 : + name: C11 + wavelength: [8.30, 8.50, 8.70] + resolution: 2000 + calibration: + radiance: + standard_name: toa_outgoing_radiance_per_unit_wavenumber + units: mW m-2 sr-1 (cm-1)-1 + brightness_temperature: + standard_name: toa_brightness_temperature + units: K + counts: + standard_name: counts + units: "1" + file_type: GOES2km + + IR_096 : + name: C12 + wavelength: [9.42, 9.61, 9.80] + resolution: 2000 + calibration: + radiance: + standard_name: toa_outgoing_radiance_per_unit_wavenumber + units: mW m-2 sr-1 (cm-1)-1 + brightness_temperature: + standard_name: toa_brightness_temperature + units: K + counts: + standard_name: counts + units: "1" + file_type: GOES2km + + IR_103 : + name: C13 + wavelength: [10.10, 10.35, 10.60] + resolution: 2000 + calibration: + radiance: + standard_name: toa_outgoing_radiance_per_unit_wavenumber + units: mW m-2 sr-1 (cm-1)-1 + brightness_temperature: + standard_name: toa_brightness_temperature + units: K + counts: + standard_name: counts + units: "1" + file_type: GOES2km + + IR_112 : + name: C14 + wavelength: [10.80, 11.20, 11.60] + resolution: 2000 + calibration: + radiance: + standard_name: toa_outgoing_radiance_per_unit_wavenumber + units: mW m-2 sr-1 (cm-1)-1 + brightness_temperature: + standard_name: toa_brightness_temperature + units: K + counts: + standard_name: counts + units: "1" + file_type: GOES2km + + IR_123 : + name: C15 + wavelength: [11.80, 12.30, 12.80] + resolution: 2000 + calibration: + radiance: + standard_name: toa_outgoing_radiance_per_unit_wavenumber + units: mW m-2 sr-1 (cm-1)-1 + brightness_temperature: + standard_name: toa_brightness_temperature + units: K + counts: + standard_name: counts + units: "1" + file_type: GOES2km + + IR_133 : + name: C16 + wavelength: [13.00, 13.30, 13.60] + resolution: 2000 + calibration: + radiance: + standard_name: toa_outgoing_radiance_per_unit_wavenumber + units: mW m-2 sr-1 (cm-1)-1 + brightness_temperature: + standard_name: toa_brightness_temperature + units: K + counts: + standard_name: counts + units: "1" + file_type: GOES2km diff --git a/satpy/etc/readers/hima_netcdficare.yaml b/satpy/etc/readers/hima_netcdficare.yaml new file mode 100644 index 0000000000..bd3bd70f92 --- /dev/null +++ b/satpy/etc/readers/hima_netcdficare.yaml @@ -0,0 +1,260 @@ +# References: +# - Himawari Level 1.5 Image Data Format Description +# - Radiometric Calibration of Himawari Level 1.5 Image Data in Equivalent +# Spectral Blackbody Radiance +# Netcdf built by Icare and Meteo France. Stored at Icare. + +reader: + name: hima_netcdficare + short_name: hima_NETCDF_ICARE + long_name: METEOFRANCE GEOSTATIONARY NETCDF BUILD for ICARE (Lille) + description: A reader for L1b NETCDF for all GEOSTATIONNARY retrieved from the ICARE service. + status: Defunct + supports_fsspec: false + sensors: [ahi] + default_channels: [VIS004, VIS005, VIS006, VIS008, IR_016, IR_022, IR_038, WV_062, WV_069, WV_073, IR_085, IR_096, IR_104, IR_112, IR_123, IR_132] + reader: !!python/name:satpy.readers.yaml_reader.FileYAMLReader + +file_types: + + HIMA500m : + file_reader: !!python/name:satpy.readers.geos_netcdficare.NETCDF_ICARE + file_patterns: ['Jmultic500mNC4_{platform_shortname:6s}_{start_time:%Y%m%d%H%M}.nc', + 'Jmultic500mNC4_{platform_shortname:6s}_{start_time:%Y%m%d_%H%M}.nc'] + + HIMA1km : + file_reader: !!python/name:satpy.readers.geos_netcdficare.NETCDF_ICARE + file_patterns: ['Jmultic1kmNC4_{platform_shortname:6s}_{start_time:%Y%m%d%H%M}.nc', + 'Jmultic1kmNC4_{platform_shortname:6s}_{start_time:%Y%m%d_%H%M}.nc'] + + HIMA2km : + file_reader: !!python/name:satpy.readers.geos_netcdficare.NETCDF_ICARE + file_patterns: ['Jmultic2kmNC4_{platform_shortname:6s}_{start_time:%Y%m%d%H%M}.nc', + 'Jmultic2kmNC4_{platform_shortname:6s}_{start_time:%Y%m%d_%H%M}.nc'] + +datasets: + + VIS004: + name: B01 + sensor: ahi + wavelength: [0.45,0.47,0.49] + resolution: [2000] + calibration: + reflectance: + standard_name: toa_bidirectional_reflectance + units: "%" + counts: + standard_name: counts + units: 1 + file_type: [HIMA2km] + + VIS005: + name: B02 + sensor: ahi + wavelength: [0.49,0.51,0.53] + resolution: [2000] + calibration: + reflectance: + standard_name: toa_bidirectional_reflectance + units: "%" + counts: + standard_name: counts + units: 1 + file_type: [HIMA2km] + + VIS006: + name: B03 + sensor: ahi + wavelength: [0.62,0.64,0.66] + resolution: [500, 2000] + calibration: + reflectance: + standard_name: toa_bidirectional_reflectance + units: "%" + counts: + standard_name: counts + units: 1 + file_type: [HIMA500m, HIMA2km] + + VIS008 : + name: B04 + sensor: ahi + wavelength: [0.83, 0.85, 0.87] + resolution: [1000, 2000] + calibration: + reflectance: + standard_name: toa_bidirectional_reflectance + units: "%" + counts: + standard_name: counts + units: 1 + file_type: [HIMA1km, HIMA2km] + + IR_016 : + name: B05 + sensor: ahi + wavelength: [1.5, 1.6, 1.7] + resolution: 2000 + calibration: + reflectance: + standard_name: toa_bidirectional_reflectance + units: "%" + counts: + standard_name: counts + units: 1 + file_type: [HIMA2km] + + IR_022 : + name: B06 + sensor: ahi + wavelength: [2.2, 2.3, 2.4] + resolution: 2000 + calibration: + reflectance: + standard_name: toa_bidirectional_reflectance + units: "%" + counts: + standard_name: counts + units: 1 + file_type: [HIMA2km] + + IR_038 : + name: B07 + resolution: 2000 + sensor: ahi + wavelength: [3.7, 3.9, 4.1] + calibration: + brightness_temperature: + standard_name: toa_brightness_temperature + units: "K" + counts: + standard_name: counts + units: 1 + # FUTURE: Split this in to multiple resolutions so each can be loaded + file_type: [HIMA2km] + + WV_062 : + name: B08 + sensor: ahi + wavelength: [6.0, 6.2, 6.4] + resolution: 2000 + calibration: + brightness_temperature: + standard_name: toa_brightness_temperature + units: "K" + counts: + standard_name: counts + units: 1 + file_type: [HIMA2km] + + WV_069 : + name: B09 + sensor: ahi + wavelength: [6.7, 6.9, 7.1] + resolution: 2000 + calibration: + brightness_temperature: + standard_name: toa_brightness_temperature + units: "K" + counts: + standard_name: counts + units: 1 + file_type: [HIMA2km] + + WV_073 : + name: B10 + sensor: ahi + wavelength: [7.1, 7.3, 7.5] + resolution: 2000 + calibration: + brightness_temperature: + standard_name: toa_brightness_temperature + units: "K" + counts: + standard_name: counts + units: 1 + file_type: [HIMA2km] + + IR_085 : + name: B11 + sensor: ahi + wavelength: [8.4, 8.6, 8.8] + resolution: 2000 + calibration: + brightness_temperature: + standard_name: toa_brightness_temperature + units: "K" + counts: + standard_name: counts + units: 1 + file_type: [HIMA2km] + + IR_096 : + name: B12 + sensor: ahi + wavelength: [9.4, 9.6, 9.8] + resolution: 2000 + calibration: + brightness_temperature: + standard_name: toa_brightness_temperature + units: "K" + counts: + standard_name: counts + units: 1 + file_type: [HIMA2km] + + IR_104 : + name: B13 + sensor: ahi + wavelength: [10.2, 10.4, 10.6] + resolution: 2000 + calibration: + brightness_temperature: + standard_name: toa_brightness_temperature + units: "K" + counts: + standard_name: counts + units: 1 + file_type: [HIMA2km] + + IR_112 : + name: B14 + sensor: ahi + wavelength: [11.0, 11.2, 11.4] + resolution: 2000 + calibration: + brightness_temperature: + standard_name: toa_brightness_temperature + units: "K" + counts: + standard_name: counts + units: 1 + file_type: [HIMA2km] + + IR_123 : + name: B15 + sensor: ahi + wavelength: [12.2, 12.4, 12.6] + resolution: 2000 + calibration: + brightness_temperature: + standard_name: toa_brightness_temperature + units: "K" + counts: + standard_name: counts + units: 1 + file_type: [HIMA2km] + + IR_132 : + name: B16 + sensor: ahi + wavelength: [13.1, 13.3, 13.5] + resolution: 2000 + calibration: + brightness_temperature: + standard_name: toa_brightness_temperature + units: "K" + counts: + standard_name: counts + units: 1 + file_type: [HIMA2km] diff --git a/satpy/etc/readers/msg_netcdficare.yaml b/satpy/etc/readers/msg_netcdficare.yaml new file mode 100644 index 0000000000..8a64c7ed01 --- /dev/null +++ b/satpy/etc/readers/msg_netcdficare.yaml @@ -0,0 +1,174 @@ +# References: +# - MSG Level 1.5 Image Data Format Description +# - Radiometric Calibration of MSG SEVIRI Level 1.5 Image Data in Equivalent +# Spectral Blackbody Radiance + +reader: + name: msg_netcdficare + short_name: MSG L1B NETCDF ICARE METEO-FRANCE + long_name: METEOFRANCE GEOSTATIONARY NETCDF BUILD for ICARE (Lille) + description: A reader for L1b NETCDF for all GEOSTATIONNARY retrieved from the ICARE service. + status: Defunct + supports_fsspec: false + sensors: [seviri] + default_channels: [HRV, IR_016, IR_039, IR_087, IR_097, IR_108, IR_120, IR_134, VIS006, VIS008, WV_062, WV_073] + reader: !!python/name:satpy.readers.yaml_reader.FileYAMLReader + +file_types: + + MSG3km : + file_reader: !!python/name:satpy.readers.geos_netcdficare.NETCDF_ICARE + file_patterns: ['Mmultic3kmNC4_{platform_shortname:5s}_{start_time:%Y%m%d%H%M}.nc', + 'Imultic3kmNC4_{platform_shortname:5s}_{start_time:%Y%m%d%H%M}.nc', + 'Mrsmultic3kmNC4_{platform_shortname:5s}_{start_time:%Y%m%d%H%M}.nc', + 'Mmultic3kmNC4_{platform_shortname:5s}_{start_time:%Y%m%d_%H%M}.nc', + 'Imultic3kmNC4_{platform_shortname:5s}_{start_time:%Y%m%d_%H%M}.nc', + 'Mrsmultic3kmNC4_{platform_shortname:5s}_{start_time:%Y%m%d_%H%M}.nc'] + + # platform_shortname:5s : msg01, ..., msg04 + + MSG1km : + file_reader: !!python/name:satpy.readers.geos_netcdficare.NETCDF_ICARE + file_patterns: ['Mmultic1kmNC4_{platform_shortname:5s}_{start_time:%Y%m%d%H%M}.nc', + 'Imultic1kmNC4_{platform_shortname:5s}_{start_time:%Y%m%d%H%M}.nc', + 'Mrsmultic1kmNC4_{platform_shortname:5s}_{start_time:%Y%m%d%H%M}.nc', + 'Mmultic1kmNC4_{platform_shortname:5s}_{start_time:%Y%m%d_%H%M}.nc', + 'Imultic1kmNC4_{platform_shortname:5s}_{start_time:%Y%m%d_%H%M}.nc', + 'Mrsmultic1kmNC4_{platform_shortname:5s}_{start_time:%Y%m%d_%H%M}.nc'] + # platform_shortname:5s : msg01, ..., msg04 + +datasets: + + HRV: + name: HRV + sensor: seviri + resolution: 1000.134348869 + wavelength: [0.5, 0.7, 0.9] + calibration: + reflectance: + standard_name: toa_bidirectional_reflectance + units: "%" + file_type: MSG1km + + IR_016: + name: IR_016 + sensor: seviri + resolution: 3000.403165817 + wavelength: [1.5, 1.64, 1.78] + calibration: + reflectance: + standard_name: toa_bidirectional_reflectance + units: "%" + file_type: MSG3km + + IR_039: + name: IR_039 + sensor: seviri + resolution: 3000.403165817 + wavelength: [3.48, 3.92, 4.36] + calibration: + brightness_temperature: + standard_name: brightness_temperature + units: "K" + file_type: MSG3km + + IR_087: + name: IR_087 + sensor: seviri + resolution: 3000.403165817 + wavelength: [8.3, 8.7, 9.1] + calibration: + brightness_temperature: + standard_name: brightness_temperature + units: "K" + file_type: MSG3km + + IR_097: + name: IR_097 + sensor: seviri + resolution: 3000.403165817 + wavelength: [9.38, 9.66, 9.94] + calibration: + brightness_temperature: + standard_name: brightness_temperature + units: "K" + file_type: MSG3km + + IR_108: + name: IR_108 + sensor: seviri + resolution: 3000.403165817 + wavelength: [9.8, 10.8, 11.8] + calibration: + brightness_temperature: + standard_name: brightness_temperature + units: "K" + file_type: MSG3km + + IR_120: + name: IR_120 + sensor: seviri + resolution: 3000.403165817 + wavelength: [11.0, 12.0, 13.0] + calibration: + brightness_temperature: + standard_name: brightness_temperature + units: "K" + file_type: MSG3km + + IR_134: + name: IR_134 + sensor: seviri + resolution: 3000.403165817 + wavelength: [12.4, 13.4, 14.4] + calibration: + brightness_temperature: + standard_name: brightness_temperature + units: "K" + file_type: MSG3km + + VIS006: + name: VIS006 + sensor: seviri + resolution: 3000.403165817 + wavelength: [0.56, 0.635, 0.71] + calibration: + reflectance: + standard_name: toa_bidirectional_reflectance + units: "%" + file_type: MSG3km + + VIS008: + name: VIS008 + sensor: seviri + resolution: 3000.403165817 + wavelength: [0.74, 0.81, 0.88] + calibration: + reflectance: + standard_name: toa_bidirectional_reflectance + units: "%" + file_type: MSG3km + + WV_062: + name: WV_062 + sensor: seviri + resolution: 3000.403165817 + wavelength: [5.35, 6.25, 7.15] + calibration: + brightness_temperature: + standard_name: brightness_temperature + units: "K" + file_type: MSG3km + + WV_073: + name: WV_073 + sensor: seviri + resolution: 3000.403165817 + wavelength: [6.85, 7.35, 7.85] + calibration: + brightness_temperature: + standard_name: brightness_temperature + units: "K" + file_type: MSG3km + + diff --git a/satpy/etc/readers/mtg_netcdficare.yaml b/satpy/etc/readers/mtg_netcdficare.yaml new file mode 100644 index 0000000000..9b8db1478c --- /dev/null +++ b/satpy/etc/readers/mtg_netcdficare.yaml @@ -0,0 +1,333 @@ +# References: +# - MTG Level 1.5 Image Data Format Description +# - Radiometric Calibration of MSG SEVIRI Level 1.5 Image Data in Equivalent +# Spectral Blackbody Radiance +# Netcdf built by Icare and Meteo France. Stored at Icare. + +reader: + name: mtg_netcdficare + short_name: mtg_NETCDF_ICARE + long_name: METEOFRANCE GEOSTATIONARY NETCDF BUILD for ICARE (Lille) + description: A reader for L1b NETCDF for all GEOSTATIONNARY retrieved from the ICARE service. + status: Defunct + supports_fsspec: false + sensors: [fci] + default_channels: [VIS004, VIS005, VIS006, VIS008, VIS009, IR_013, IR_016, IR_022, IR_038, WV_063, WV_073, IR_087, IR_097, IR_105, IR_123, IR_133] + reader: !!python/name:satpy.readers.yaml_reader.FileYAMLReader + +file_types: + + MTG500m : + file_reader: !!python/name:satpy.readers.geos_netcdficare.NETCDF_ICARE + file_patterns: ['Multic500m_{platform_shortname:5s}_{start_time:%Y%m%d%H%M}.nc', + 'Multic500m_{platform_shortname:5s}_{start_time:%Y%m%d_%H%M%S}.nc', + 'Mmultic500mNC4_{platform_shortname:5s}_{start_time:%Y%m%d%H%M}.nc', + 'Mmultic500mNC4_{platform_shortname:5s}_{start_time:%Y%m%d_%H%M%S}.nc'] + + MTG1km : + file_reader: !!python/name:satpy.readers.geos_netcdficare.NETCDF_ICARE + file_patterns: ['Multic1km_{platform_shortname:5s}_{start_time:%Y%m%d%H%M}.nc', + 'Multic1km_{platform_shortname:5s}_{start_time:%Y%m%d_%H%M%S}.nc', + 'Mmultic1kmNC4_{platform_shortname:5s}_{start_time:%Y%m%d%H%M}.nc', + 'Mmultic1kmNC4_{platform_shortname:5s}_{start_time:%Y%m%d_%H%M%S}.nc'] + + MTG2km : + file_reader: !!python/name:satpy.readers.geos_netcdficare.NETCDF_ICARE + file_patterns: ['Multic2km_{platform_shortname:5s}_{start_time:%Y%m%d%H%M}.nc', + 'Multic2km_{platform_shortname:5s}_{start_time:%Y%m%d_%H%M%S}.nc', + 'Mmultic2kmNC4_{platform_shortname:5s}_{start_time:%Y%m%d%H%M}.nc', + 'Mmultic2kmNC4_{platform_shortname:5s}_{start_time:%Y%m%d_%H%M%S}.nc'] + +datasets: + + VIS004: + name: vis_04 + sensor: fci + wavelength: [ 0.384, 0.444, 0.504 ] + resolution: + 1000: { file_type: MTG1km } + 2000: { file_type: MTG2km } + calibration: + counts: + standard_name: counts + units: "count" + radiance: + standard_name: toa_outgoing_radiance_per_unit_wavenumber + units: mW m-2 sr-1 (cm-1)-1 + reflectance: + standard_name: toa_bidirectional_reflectance + units: "%" + file_type: [MTG2km, MTG1km] + # file_type: abi_ahi_seviri_fci_netcdficare + # file_type: [mtg2km__netcdficare, mtg1km__netcdficare] + + VIS005: + name: vis_05 + sensor: fci + wavelength: [0.470, 0.510, 0.550] + resolution: + 1000: { file_type: MTG1km } + 2000: { file_type: MTG2km } + calibration: + counts: + standard_name: counts + units: "count" + radiance: + standard_name: toa_outgoing_radiance_per_unit_wavenumber + units: mW m-2 sr-1 (cm-1)-1 + reflectance: + standard_name: toa_bidirectional_reflectance + units: "%" + file_type: [MTG2km, MTG1km] + + VIS006: + name: vis_06 + sensor: fci + wavelength: [0.590, 0.640, 0.690] + resolution: + 500: { file_type: MTG500m } + 1000: { file_type: MTG1km } + 2000: { file_type: MTG2km } + calibration: + counts: + standard_name: counts + units: "count" + radiance: + standard_name: toa_outgoing_radiance_per_unit_wavenumber + units: mW m-2 sr-1 (cm-1)-1 + reflectance: + standard_name: toa_bidirectional_reflectance + units: "%" + file_type: [MTG2km, MTG1km, MTG500m] + + VIS008 : + name: vis_08 + sensor: fci + wavelength: [0.815, 0.865, 0.915] + resolution: + 1000: { file_type: MTG1km } + 2000: { file_type: MTG2km } + calibration: + counts: + standard_name: counts + units: "count" + radiance: + standard_name: toa_outgoing_radiance_per_unit_wavenumber + units: mW m-2 sr-1 (cm-1)-1 + reflectance: + standard_name: toa_bidirectional_reflectance + units: "%" + file_type: [MTG2km, MTG1km] + + VIS009 : + name: vis_09 + sensor: fci + wavelength: [0.894, 0.914, 0.934] + resolution: + 1000: { file_type: MTG1km } + 2000: { file_type: MTG2km } + calibration: + counts: + standard_name: counts + units: "count" + radiance: + standard_name: toa_outgoing_radiance_per_unit_wavenumber + units: mW m-2 sr-1 (cm-1)-1 + reflectance: + standard_name: toa_bidirectional_reflectance + units: "%" + + IR_013 : + name: nir_13 + sensor: fci + wavelength: [1.350, 1.380, 1.410] + resolution: + 1000: { file_type: MTG1km } + 2000: { file_type: MTG2km } + calibration: + counts: + standard_name: counts + units: "count" + radiance: + standard_name: toa_outgoing_radiance_per_unit_wavenumber + units: mW m-2 sr-1 (cm-1)-1 + reflectance: + standard_name: toa_bidirectional_reflectance + units: "%" + + IR_016 : + name: nir_16 + sensor: fci + wavelength: [1.560, 1.610, 1.660] + resolution: + 1000: { file_type: MTG1km } + 2000: { file_type: MTG2km } + calibration: + counts: + standard_name: counts + units: "count" + radiance: + standard_name: toa_outgoing_radiance_per_unit_wavenumber + units: mW m-2 sr-1 (cm-1)-1 + reflectance: + standard_name: toa_bidirectional_reflectance + units: "%" + file_type: [MTG2km, MTG1km] + + IR_022 : + name: nir_22 + sensor: fci + wavelength: [2.200, 2.250, 2.300] + resolution: + 500: { file_type: MTG500m } + 1000: { file_type: MTG1km } + 2000: { file_type: MTG2km } + calibration: + counts: + standard_name: counts + units: "count" + radiance: + standard_name: toa_outgoing_radiance_per_unit_wavenumber + units: mW m-2 sr-1 (cm-1)-1 + reflectance: + standard_name: toa_bidirectional_reflectance + units: "%" + + IR_038 : + name: ir_38 + sensor: fci + wavelength: [3.400, 3.800, 4.200] + resolution: + 1000: { file_type: MTG1km } + 2000: { file_type: MTG2km } + calibration: + counts: + standard_name: counts + units: "count" + radiance: + standard_name: toa_outgoing_radiance_per_unit_wavenumber + units: mW m-2 sr-1 (cm-1)-1 + brightness_temperature: + standard_name: toa_brightness_temperature + units: "K" + file_type: [MTG2km, MTG1km] + + WV_063 : + name: wv_63 + sensor: fci + wavelength: [5.300, 6.300, 7.300] + resolution: + 2000: { file_type: MTG2km } + calibration: + counts: + standard_name: counts + units: "count" + radiance: + standard_name: toa_outgoing_radiance_per_unit_wavenumber + units: mW m-2 sr-1 (cm-1)-1 + brightness_temperature: + standard_name: toa_brightness_temperature + units: "K" + + WV_073 : + name: wv_73 + sensor: fci + wavelength: [6.850, 7.350, 7.850] + resolution: + 2000: { file_type: MTG2km } + calibration: + counts: + standard_name: counts + units: "count" + radiance: + standard_name: toa_outgoing_radiance_per_unit_wavenumber + units: mW m-2 sr-1 (cm-1)-1 + brightness_temperature: + standard_name: toa_brightness_temperature + units: "K" + + IR_087 : + name: ir_87 + sensor: fci + wavelength: [8.300, 8.700, 9.100] + resolution: + 2000: { file_type: MTG2km } + calibration: + counts: + standard_name: counts + units: "count" + radiance: + standard_name: toa_outgoing_radiance_per_unit_wavenumber + units: mW m-2 sr-1 (cm-1)-1 + brightness_temperature: + standard_name: toa_brightness_temperature + units: "K" + + IR_097 : + name: ir_97 + sensor: fci + wavelength: [9.360, 9.660, 9.960] + resolution: + 2000: { file_type: MTG2km } + calibration: + counts: + standard_name: counts + units: "count" + radiance: + standard_name: toa_outgoing_radiance_per_unit_wavenumber + units: mW m-2 sr-1 (cm-1)-1 + brightness_temperature: + standard_name: toa_brightness_temperature + units: "K" + + IR_105 : + name: ir_105 + sensor: fci + wavelength: [9.800, 10.500, 11.200] + resolution: + 1000: { file_type: MTG1km } + 2000: { file_type: MTG2km } + calibration: + counts: + standard_name: counts + units: "count" + radiance: + standard_name: toa_outgoing_radiance_per_unit_wavenumber + units: mW m-2 sr-1 (cm-1)-1 + brightness_temperature: + standard_name: toa_brightness_temperature + units: "K" + + IR_123 : + name: ir_123 + sensor: fci + wavelength: [11.800, 12.300, 12.800] + resolution: + 2000: { file_type: MTG2km } + calibration: + counts: + standard_name: counts + units: "count" + radiance: + standard_name: toa_outgoing_radiance_per_unit_wavenumber + units: mW m-2 sr-1 (cm-1)-1 + brightness_temperature: + standard_name: toa_brightness_temperature + units: "K" + + IR_133 : + name: ir_133 + sensor: fci + wavelength: [12.700, 13.300, 13.900] + resolution: + 2000: { file_type: MTG2km } + calibration: + counts: + standard_name: counts + units: "count" + radiance: + standard_name: toa_outgoing_radiance_per_unit_wavenumber + units: mW m-2 sr-1 (cm-1)-1 + brightness_temperature: + standard_name: toa_brightness_temperature + units: "K" diff --git a/satpy/readers/geos_netcdficare.py b/satpy/readers/geos_netcdficare.py new file mode 100644 index 0000000000..39fbef1030 --- /dev/null +++ b/satpy/readers/geos_netcdficare.py @@ -0,0 +1,765 @@ +#!/usr/bin/env python +# -*- coding: utf-8 -*- +# Copyright (c) 2019 Satpy developers +# +# This file is part of satpy. Written by Meteo France in august 2024. +# +# 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 . + +"""Interface to GEOSTATIONNARY L1B NETCDF data from ICARE (Lille). + +Introduction +------------ + +The ``geos_netcdficare`` reader reads some geostationnary netcdf build by +Meteo France and stored at Icare. + +The brightness temperature and albedo are calibrated. + +That has been stored by the ICARE Data and Services Center +Data can be accessed via: http://www.icare.univ-lille1.fr + +This reader concerns the following netcdfs : + +. msg with a longitude near 0° : +Mmultic3kmNC4_msg03_20231113_111500.nc +Mmultic1kmNC4_msg03_20231113_111500.nc + +. Msg rapid scan with a longitude near 9.5° : +Mrsmultic3kmNC4_msg03_20231113_111500.nc +Mrsmultic1kmNC4_msg03_20231113_111500.nc + +. Msg with a longitude near 42° : +Imultic3kmNC4_msg03_20231113_111500.nc +Imultic1kmNC4_msg03_20231113_111500.nc + +. Himawari : +Jmultic2kmNC4_hima09_20231113_111500.nc +Jmultic1kmNC4_hima09_20231113_111500.nc +Jmultic500mNC4_hima09_20231113_111500.nc + +. Goesr near -137° : +Wmultic2kmNC4_goes16_202406281000.nc. +The better resolution are not built at Lannion, only at Tahiti. + +. Goesr in -75° : +Emultic2kmNC4_goes16_202406281000.nc +Emultic1kmNC4_goes16_202406281000.nc +Emultic500mNC4_goes16_202406281000.nc + +. Mtg : +Mmultic2km_mtgi1_20240104_090000.nc +Mmultic1km_mtgi1_20240104_090000.nc +Mmultic500m_mtgi1_20240104_090000.nc + + +Example: +-------- +Here is an example how to read the data in satpy: + + from satpy import Scene + import glob + + filenames = glob.glob('data/*2019-03-01T12-00-00*.hdf') + scn = Scene(filenames = filenames, reader = 'hima_netcdficare') + scn.load(['true_color']) # scn.load(['VIS006']) + + my_area = AreaDefinition( + 'my_area', 'zone', 'my_area', + '+proj=latlong +lon_0=0 +a=6378169 +b=6356583 +h=35785831 +x_0=0 + +y_0=0 +pm=0', + 8500, 4000, + [-180., -80., 180., 80], + nprocs=16) + + natscn = scn.resample(my_area, resampler='nearest') + natscn.save_dataset(composite_name, filename = filename_image_out) + +EXECUTION TIME : + 50 seconds for a 2 kms goesr airmass rgb disk. +DATE OF CREATION : + 2024 16th october. +LAST VERSIONS : + +AUTHOR : + Meteo France. + +""" + +import datetime as dt + +import numpy as np + +from satpy.readers._geos_area import get_area_definition, get_area_extent + +import xarray as xr + +from satpy.readers.file_handlers import BaseFileHandler + +import logging +logger = logging.getLogger('netcdficare') + +# Planck : +C1 = 1.1910427e-5 +C2 = 1.4387752 + + +class NETCDF_ICARE(BaseFileHandler) : + # Cf readers/file_handlers.py. + + def __init__(self, filename, filename_info, filetype_info) : + """Init the file handler.""" + + super().__init__(filename, filename_info, filetype_info) + + self.nc = xr.open_dataset( + self.filename, decode_cf=True, mask_and_scale=False, + chunks={"xc": "auto", "yc": "auto"}) + self.metadata = {} + + self.metadata["start_time"] = self.get_endOrStartTime( + "time_coverage_start") + self.metadata["end_time"] = self.get_endOrStartTime( + "time_coverage_end") + + # message = "Reading: " + filename + # message += " start: " + format(self.start_time) + # message += " end: " + format(self.end_time) + # logger.info(message) + + self.netcdfCommonAttributReading() + # __init__() + + def netcdfCommonAttributReading(self) : + self.sensor = self.sensor_name() + # seviri + + self.platform = self.platform_name() + # Meteosat-10 + + self.res() + # Resolution : 3000.4 m + + self.actualLongitude = self.satlon() + self.projectionLongitude = self.projlon() + + self.zone = self.nc.attrs["Area_of_acquisition"] + # globe. + + def sensor_name(self) : + """Get the sensor name seviri, fci, abi, ahi. + """ + variable = self.nc["satellite"] + platform = variable.attrs["id"] # msg1, msg01, MSG1... + platform = platform[:3] # msg, MSG + platform = platform.lower() # msg + + pdict = {} + pdict["msg"] = "seviri" + pdict["mtg"] = "fci" + pdict["goe"] = "abi" + pdict["him"] = "ahi" + + if platform in pdict : + sensor = pdict[platform] + else : + message = "Unsupported satellite platform : " + message += self.platform + raise NotImplementedError(message) + return sensor + + def platform_name(self) : + # Icare and météo france use non-standard platform names. + # Change is needed for pyspectral : + # pyspectral/rsr_seviri_Meteosat-10.h5 in the call + # Calculator(platform_name, sensor, name). + + variable = self.nc["satellite"] + platform = variable.attrs["id"] # msg1, msg01, MSG1... + + pdict = {} + pdict["msg1"] = "Meteosat-08" + pdict["msg01"] = "Meteosat-08" + pdict["MSG1"] = "Meteosat-08" + pdict["msg2"] = "Meteosat-09" + pdict["msg02"] = "Meteosat-09" + pdict["MSG2"] = "Meteosat-09" + pdict["msg3"] = "Meteosat-10" + pdict["msg03"] = "Meteosat-10" + pdict["MSG3"] = "Meteosat-10" + pdict["msg4"] = "Meteosat-11" + pdict["msg04"] = "Meteosat-11" + pdict["MSG4"] = "Meteosat-11" + pdict["mtgi1"] = "Meteosat-12" + pdict["mtg1"] = "Meteosat-12" + pdict["MTG01"] = "Meteosat-12" + pdict["goes16"] = "GOES-16" + pdict["goes17"] = "GOES-17" + pdict["goes18"] = "GOES-18" + pdict["goes19"] = "GOES-19" + pdict["hima08"] = "Himawari-8" + pdict["hima09"] = "Himawari-9" + + if platform in pdict : + platform = pdict[platform] + else : + message = "Unsupported satellite platform : " + platform + raise NotImplementedError(message) + return platform + # platform_name() + + def satlon(self) : + """Get the satellite longitude.""" + variable = self.nc["satellite"] + actualLongitude = variable.attrs["lon"] + return actualLongitude + + def projlon(self): + """Get the projection longitude.""" + variable = self.nc["geos"] + projectionLongitude = variable.attrs["longitude_of_projection_origin"] + return projectionLongitude + + @property + def projection(self): + """Get the projection.""" + return "geos" + + def res(self) : + """Get the resolution. + The resolution can be read in the attribute geotransform + of the following variables : + GeosCoordinateSystem500m, GeosCoordinateSystem_h, + GeosCoordinateSystem1km, GeosCoordinateSystem2km, + GeosCoordinateSystem. + cfac, lfac, coff, loff can be read in the variables ImageNavigationxxx. + """ + + if "GeosCoordinateSystem500m" in self.nc : + # Mtg, himawari, goesr. + variable = self.nc["GeosCoordinateSystem500m"] + Xvariable = self.nc["X500m"] + Yvariable = self.nc["Y500m"] + navigationString = "ImageNavigation500m" + + elif "GeosCoordinateSystem_h" in self.nc : + # Hrv from msg. + variable = self.nc["GeosCoordinateSystem_h"] + Xvariable = self.nc["X_h"] + Yvariable = self.nc["Y_h"] + navigationString = "ImageNavigation_h" + + elif "GeosCoordinateSystem1km" in self.nc : + # Mtg, himawari, goesr. + variable = self.nc["GeosCoordinateSystem1km"] + Xvariable = self.nc["X1km"] + Yvariable = self.nc["Y1km"] + navigationString = "ImageNavigation1km" + + elif "GeosCoordinateSystem2km" in self.nc : + # Mtg, himawari, goesr. + variable = self.nc["GeosCoordinateSystem2km"] + Xvariable = self.nc["X2km"] + Yvariable = self.nc["Y2km"] + navigationString = "ImageNavigation2km" + + elif "GeosCoordinateSystem" in self.nc : + # Msg in 3 kms. + variable = self.nc["GeosCoordinateSystem"] + Xvariable = self.nc["X"] + Yvariable = self.nc["Y"] + navigationString = "ImageNavigation" + + else : + message = "Variables GeosCoordinateSystemXX not founded." + raise NotImplementedError(message) + + geotransform = variable.attrs["GeoTransform"] + # geotransform = -5570254, 3000.40604, 0, 5570254, 0, -3000.40604 + + chunksGeotransform = geotransform.split(", ") + self.resolution = float(chunksGeotransform[1]) + # 3000.40604 + + self.X = Xvariable[:] + self.nbpix = self.X.shape[0] + self.Y = Yvariable[:] + self.nblig = self.Y.shape[0] + + variable = self.nc[navigationString] + self.cfac = float(variable.attrs["CFAC"]) + self.lfac = float(variable.attrs["LFAC"]) + self.coff = float(variable.attrs["COFF"]) + self.loff = float(variable.attrs["LOFF"]) + # res() + + def get_endOrStartTime(self, AttributeName) : + """Get the end or the start time. Global attribute of the netcdf. + AttributName : "time_coverage_start", "time_coverage_end" + """ + attr = self.nc.attrs[AttributeName] + # YYYY-MM-DDTHH:MM:SSZNNN or YYYY-MM-DDTHH:MM:SSZ + # In some versions milliseconds are present, sometimes not. + lengthString = len(attr) + if lengthString == 22 : + # Goesr : 2024-06-28T10:00:21.1Z + stacq = dt.datetime.strptime(attr, "%Y-%m-%dT%H:%M:%S.%fZ") + elif lengthString == 20 : + # Mtg. + stacq = dt.datetime.strptime(attr, "%Y-%m-%dT%H:%M:%SZ") + else : + # Msg, hima. + stacq = dt.datetime.strptime(attr, "%Y-%m-%dT%H:%M:%SZ%f") + return stacq + # get_endOrStartTime() + + @property + def start_time(self) : + return(self.metadata["start_time"]) + + @property + def end_time(self) : + return(self.metadata["end_time"]) + + @property + def alt(self) : + """Get the altitude.""" + variable = self.nc["satellite"] + altitude = variable.attrs["dst"] # 36000000 meters. + altitude += 6378169. # equatorial radius of the earth. + return altitude + + def prepare_metadata(self, variable) : + """Get the metadata for a channel variable. + Add the global attributes.""" + mda = {} + + attributs = variable.attrs + for name in attributs : + mda.update({name: attributs.get(name)}) + + mda.update({ + "start_time": self.start_time, + "end_time": self.end_time, + "platform_name": self.platform, + "sensor": self.sensor, + "zone": self.zone, + "projection_altitude": self.alt, + "cfac": self.cfac, + "lfac": self.lfac, + "coff": self.coff, + "loff": self.loff, + "resolution": self.resolution, + "satellite_actual_longitude": self.actualLongitude, + "projection_longitude": self.projectionLongitude, + "projection_type": self.projection + }) + + mda.update(self.orbital_param()) + return mda + # prepare_metadata(). + + def buildChannelCorrespondanceName(self) : + pdict = {} + + # For mtg. + # vis_04 is the name in satpy. + # VIS004 is the icare/meteofrance netcdf name. + pdict["vis_04"] = "VIS004" + pdict["vis_05"] = "VIS005" + pdict["vis_06"] = "VIS006" + pdict["vis_08"] = "VIS008" + pdict["vis_09"] = "VIS009" + pdict["nir_13"] = "IR_013" + pdict["nir_16"] = "IR_016" + pdict["nir_22"] = "IR_022" + pdict["ir_38"] = "IR_038" + pdict["wv_63"] = "WV_063" + pdict["wv_73"] = "WV_073" + pdict["ir_87"] = "IR_087" + pdict["ir_97"] = "IR_097" + pdict["ir_105"] = "IR_105" + pdict["ir_123"] = "IR_123" + pdict["ir_133"] = "IR_133" + + # For msg, the satpy and icare channel names are the same. + pdict["VIS006"] = "VIS006" + pdict["VIS008"] = "VIS008" + pdict["HRV"] = "HRV" + pdict["IR_016"] = "IR_016" + pdict["IR_039"] = "IR_039" + pdict["WV_062"] = "WV_062" + pdict["WV_073"] = "WV_073" + pdict["IR_087"] = "IR_087" + pdict["IR_097"] = "IR_097" + pdict["IR_108"] = "IR_108" + pdict["IR_120"] = "IR_120" + pdict["IR_134"] = "IR_134" + + # For the goesr satellites : + pdict["C01"] = "VIS_004" + pdict["C02"] = "VIS_006" + pdict["C03"] = "VIS_008" + pdict["C04"] = "VIS_014" + pdict["C05"] = "VIS_016" + pdict["C06"] = "VIS_022" + pdict["C07"] = "IR_039" + pdict["C08"] = "IR_062" + pdict["C09"] = "IR_069" + pdict["C10"] = "IR_073" + pdict["C11"] = "IR_085" + pdict["C12"] = "IR_096" + pdict["C13"] = "IR_103" + pdict["C14"] = "IR_114" + pdict["C15"] = "IR_123" + pdict["C16"] = "IR_133" + + # For himawari. + # BO1 : name in satpy. VIS004 : name in icare/meteofrance netcdf. + pdict["B01"] = "VIS004" + pdict["B02"] = "VIS005" + pdict["B03"] = "VIS006" + pdict["B04"] = "VIS008" + pdict["B05"] = "IR_016" + pdict["B06"] = "IR_022" + pdict["B07"] = "IR_038" + pdict["B08"] = "WV_062" + pdict["B09"] = "WV_069" + pdict["B10"] = "WV_073" + pdict["B11"] = "IR_085" + pdict["B12"] = "IR_096" + pdict["B13"] = "IR_104" + pdict["B14"] = "IR_112" + pdict["B15"] = "IR_123" + pdict["B16"] = "IR_132" + return pdict + # buildChannelCorrespondanceName() + + def _get_dsname(self, ds_id) : + """Return the correct dataset name based on requested band. + ds_id = DataID(name='vis_08', + wavelength=WavelengthRange(...), + resolution=2000, calibration=, + modifiers=()) + """ + pdict = self.buildChannelCorrespondanceName() + + satpyName = ds_id["name"] + if satpyName in pdict : + icareName = pdict[satpyName] + else : + message = "Soft not adaptated for this channel : ds_id = " + message += satpyName + raise NotImplementedError(message) + + return icareName + # _get_dsname() + + def channelAttributs(self, ds_get_name) : + if ds_get_name not in self.nc : + message = "Channel " + ds_get_name + "not founded " + message += "in the netcdf." + raise NotImplementedError(message) + + self.mda = {} + self.scale_factor = {} + self.offset = {} + self.alpha = {} + self.beta = {} + self.nuc = {} + self.bandfactor = {} + self.backtocountVariable = {} + + variable = self.nc[ds_get_name] + attributs = variable.attrs + + self.scale_factor[ds_get_name] = attributs["scale_factor"] + self.offset[ds_get_name] = attributs["add_offset"] + + if "nuc" in attributs : + # Brightness temperature. + self.alpha[ds_get_name] = attributs["alpha"] + self.beta[ds_get_name] = attributs["beta"] + self.nuc[ds_get_name] = attributs["nuc"] + + backtocountName = "Temp_to_Native_count_" + ds_get_name + + elif "bandfactor" in attributs : + # Albedo. + self.bandfactor[ds_get_name] = attributs["bandfactor"] + backtocountName = "Albedo_to_Native_count_" + ds_get_name + + else : + message = "Nuc or bandfactor not founded in the attributs" + message += " of " + ds_get_name + raise NotImplementedError(message) + + self.backtocountVariable[ds_get_name] = self.nc[backtocountName] + # (65536). Correspondence from 0 to 65535 towards + # the original spatial agency counts. + + self.mda[ds_get_name] = self.prepare_metadata(variable) + # channelAttributs(ds_get_name) + + def comebacktoNativeData(self, ds_get_name) : + """ Come back to the original counts of the hrit. + ds_get_name : meteo france name of a channel : IR_108. """ + + variable = self.nc[ds_get_name] + # Variable is between -9000 to 4000 (temperature) + # or between 0 to 10000 (albedo). + + offset = self.offset[ds_get_name] # 0 or 273.15 + variable += 32768 # 0 to 65535 + + if offset == 0. : + # Albedo. + name = "Albedo_to_Native_count_" + ds_get_name + else : + name = "Temp_to_Native_count_" + ds_get_name + """ Temp_to_Native_count_IR_062 """ + + backtocountVariable = self.nc[name] # (65536). + # Correspondence from 0 to 65535 + # towards the original spatial agency counts. + + arrayTableConversion = xr.DataArray.to_numpy(backtocountVariable) + + tableContents = arrayTableConversion[variable[:]] + """ Come back to the original counts of the hrit. + tableau : 0 to 4095 if native datas coded with 12 bits. """ + + variable[:] = tableContents + return(variable) + # comebacktoNativeData(self, ds_get_name) + + def comebacktoRadiance(self, ds_get_name) : + """ Come back to the radiance. + ds_get_name : meteo france name of a channel : IR_108. """ + + variable = self.nc[ds_get_name] + # Variable is between -9000 to 4000 (temperature) + # or between 0 to 10000 (albedo). + + scale_factor = self.scale_factor[ds_get_name] # 0.01 + offset = self.offset[ds_get_name] # 0 or 273.15 + + if offset == 0. : + # Visible channel. + bandfactor = self.bandfactor[ds_get_name] + + # Variable is an albedo from 0 to 10000. + variable = variable * scale_factor / 100. * bandfactor + # => variable is a reflectance between 0 and 1. + # radiance in mWm-2sr-1(cm-1)-1 + else : + # Brightness temperature. + nuc = self.nuc[ds_get_name] + alpha = self.alpha[ds_get_name] + beta = self.beta[ds_get_name] + + variable = variable * scale_factor + offset + # variable becomes Kelvin. + + variable = variable * alpha + beta + resul1 = C1 * np.power(nuc, 3.) + resul2 = C2 * nuc + val2 = np.exp(resul2 / variable) - 1. + variable = resul1 / val2 + # Radiance in mWm-2sr-1(cm-1)-1 + return(variable) + # comebacktoRadiance(self, ds_get_name) + + def get_dataset(self, ds_id, ds_info) : + """Get the dataset. + ds_id["calibration"] = key["calibration"] = + ["brightness_temperature", "reflectance", "radiance", "counts"] + """ + ds_get_name = self._get_dsname(ds_id) + # ds_get_name is the meteo France Icare name of the channel : IR_096. + + self.channelAttributs(ds_get_name) + + mda = self.mda[ds_get_name] + mda.update(ds_info) + + calibration = ds_id["calibration"] + + if calibration == "counts" : + # Come back to the original counts of the hrit... + variable = self.comebacktoNativeData(ds_get_name) + + elif calibration == "radiance" : + # Come back to the radiance. + variable = self.comebacktoRadiance(ds_get_name) + + elif calibration == "brightness_temperature" : + variable = self.nc[ds_get_name] + # WV_062 calibration.brightness_temperature, from -9000 to 4000 + scale_factor = self.scale_factor[ds_get_name] + offset = self.offset[ds_get_name] + if offset != 273.15 : + message = "Soft not intended for a reflectance " + message += "with a wave length more than 3 microns. " + message += ds_get_name + " offset = " + str(offset) + raise NotImplementedError(message) + + variable = variable * scale_factor + offset + # variable becomes Kelvin. + + elif calibration == "reflectance" : + variable = self.nc[ds_get_name] + # VIS006 calibration.reflectance, from 0 to 10000 + scale_factor = self.scale_factor[ds_get_name] + offset = self.offset[ds_get_name] + if offset != 0. : + message = "Soft not intended " + message += "for a brightness temperature " + message += "with a wave length less than 3 microns. " + message += ds_get_name + " offset = " + str(offset) + raise NotImplementedError(message) + + variable = variable * scale_factor + # variable becomes an albedo between 0 and 100. + + else : + message = "Calibration mode not expected : " + calibration + raise NotImplementedError(message) + + variable = variable.rename( + {variable.dims[0] : "y", variable.dims[1] : "x"}) + variable.attrs.update(mda) + return variable + # get_dataset() + + def orbital_param(self) : + orb_param_dict = { + "orbital_parameters": { + "satellite_actual_longitude": self.actualLongitude, + "satellite_actual_latitude": 0., + "satellite_actual_altitude": self.alt, + "satellite_nominal_longitude": self.projectionLongitude, + "satellite_nominal_latitude": 0, + "satellite_nominal_altitude": self.alt, + "projection_longitude": self.projectionLongitude, + "projection_latitude": 0., + "projection_altitude": self.alt, + } + } + return orb_param_dict + + def channelType(self, pdict, pdictResoAdesc, pdictResoPid, satellite) : + strNbpix = str(self.nbpix) + if strNbpix in pdictResoAdesc : + pdict["a_desc"] = pdictResoAdesc[strNbpix] + pdict["p_id"] = pdictResoPid[strNbpix] + else : + message = "Resolution " + str(self.nbpix) + message += " not expected for " + satellite + raise NotImplementedError(message) + + return(pdict) + + def get_area_def(self, ds_id) : + """Get the area def.""" + + pdict = {} + pdict["cfac"] = np.int32(self.cfac) + pdict["lfac"] = np.int32(self.lfac) + pdict["coff"] = np.float32(self.coff) + pdict["loff"] = np.float32(self.loff) + + pdict["a"] = 6378169 + pdict["b"] = 6356583.8 + pdict["h"] = self.alt - pdict["a"] + # 36000000 mètres. + pdict["ssp_lon"] = self.projectionLongitude + pdict["ncols"] = self.nblig + pdict["nlines"] = self.nbpix + pdict["sweep"] = "y" + + # Force scandir to SEVIRI default, not known from file + pdict["scandir"] = "S2N" + pdict["a_name"] = "geosmsg" + + pdictResoAdesc = {} + pdictResoPid = {} + + if self.sensor == "seviri" : + # msg. + pdict["scandir"] = "N2S" + pdict["a_name"] = "geosmsg" + + pdictResoAdesc["3712"] = "MSG/SEVIRI low resolution channel area" + pdictResoPid["3712"] = "msg_lowres" + pdictResoAdesc["11136"] = "MSG/SEVIRI HRV channel area" + pdictResoPid["11136"] = "msg_hires" + + pdict = self.channelType( + pdict, pdictResoAdesc, pdictResoPid, "msg") + + elif self.sensor == "fci" : + # mtg. + pdict["scandir"] = "N2S" + pdict["a_name"] = "geosmtg" + + pdictResoAdesc["5568"] = "MTG 2km channel area" + pdictResoPid["5568"] = "mtg_lowres" + pdictResoAdesc["11136"] = "MTG 1km channel area" + pdictResoPid["11136"] = "mtg_midres" + pdictResoAdesc["22272"] = "MTG 500m channel area" + pdictResoPid["22272"] = "mtg_hires" + + pdict = self.channelType( + pdict, pdictResoAdesc, pdictResoPid, "mtg") + + elif self.sensor == "ahi" : + # Himawari. + pdict["scandir"] = "N2S" + pdict["a_name"] = "geoshima" + + pdictResoAdesc["5500"] = "HIMA 2km channel area" + pdictResoPid["5500"] = "hima_lowres" + pdictResoAdesc["11000"] = "HIMA 1km channel area" + pdictResoPid["11000"] = "hima_midres" + pdictResoAdesc["22000"] = "HIMA 500m channel area" + pdictResoPid["22000"] = "hima_hires" + + pdict = self.channelType( + pdict, pdictResoAdesc, pdictResoPid, "hima") + + elif self.sensor == "abi" : + # Goesr. + pdict["scandir"] = "N2S" + pdict["a_name"] = "geosgoesr" + pdict["sweep"] = "x" + + pdictResoAdesc["5424"] = "GOESR 2km channel area" + pdictResoPid["5424"] = "goesr_lowres" + pdictResoAdesc["10848"] = "GOESR 1km channel area" + pdictResoPid["10848"] = "goesr_midres" + pdictResoAdesc["21696"] = "GOESR 500m channel area" + pdictResoPid["21696"] = "goesr_hires" + + pdict = self.channelType( + pdict, pdictResoAdesc, pdictResoPid, "goesr") + + else : + message = "Sensor " + self.sensor + " not expected." + raise NotImplementedError(message) + + aex = get_area_extent(pdict) + area = get_area_definition(pdict, aex) + + return area + # get_area_def() diff --git a/satpy/tests/reader_tests/test_geos_netcdficare.py b/satpy/tests/reader_tests/test_geos_netcdficare.py new file mode 100644 index 0000000000..f0157e6ec3 --- /dev/null +++ b/satpy/tests/reader_tests/test_geos_netcdficare.py @@ -0,0 +1,589 @@ +#!/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 . + +"""Tests for the Icare MeteoFrance netcdfs reader, + satpy/readers/geos_netcdficare.py. + +SYNTAXE : + pytest + + Before, copy the satpy/tests/reader_tests/test_geos_netcdfcare.py file + into the pytest directory pytest_projec. + +EXECUTION TIME : + 4 minutes. +DATE OF CREATION : + 2024 11th october. +LAST VERSIONS : + +AUTHOR : + Météo France. +""" + +import os + +import numpy as np + +from satpy.scene import Scene +from satpy import find_files_and_readers + +from datetime import datetime +from netCDF4 import Dataset + +import logging +logger = logging.getLogger('netcdficare') + + +class TestGeosNetcdfIcareReader() : + # Test of the geos_netcdficare reader. + # This reader has been build for the Icare Meteo France netcdfs. + ''' + def test_mtg_netcdficare(self, tmp_path) : + """ A dummy netcdf is built. + A scene self.scn for the nir_16 product for the same date + is built. We check that the scene parameters are the same + as thoses in the dummy netcdf. + This procedure is called by pytest. + """ + self.initMtg(tmp_path) + self.scn.load(['nir_16']) + self.values = self.scn.values() + self.checkingSceneParameter("nir_16") + # test_mtg_netcdficare() + + def test_msg_netcdficare(self, tmp_path) : + self.initMsgHrv(tmp_path) + self.scn.load(['HRV']) + self.values = self.scn.values() + self.checkingSceneParameter("HRV") + + self.initMsg(tmp_path) + self.scn.load(['convection']) + self.values = self.scn.values() + self.checkingSceneParameter("convection") + # test_msg_netcdficare() + ''' + def test_hima_netcdficare(self, tmp_path) : + self.initHima(tmp_path) + self.scn.load(['B10']) + self.values = self.scn.values() + self.checkingSceneParameter("B10") + # test_hima_netcdficare() + + ''' + def test_goesr_netcdficare(self, tmp_path) : + self.initGoesr(tmp_path) + self.scn.load(['C02']) + self.values = self.scn.values() + self.checkingSceneParameter("C02") + # test_goesr_netcdficare() + ''' + # ----------------------------------------------------- # + # typeImage : convection, airmass... + # ----------------------------------------------------- # + def checkingSceneParameter(self, typeImage) : + startTime = self.scn.start_time + startTimeString = startTime.strftime('%Y-%m-%dT%H:%M:%S') + # 2024-06-28T10:00:40 + assert startTimeString == self.expectedStartTime + + endTime = self.scn.end_time + endTimeString = endTime.strftime('%Y-%m-%dT%H:%M:%S') + # 2024-06-28T10:12:41 + assert endTimeString == self.expectedEndTime + + sensor = self.scn.sensor_names + for isensor in sensor : + capteur = isensor + assert capteur == self.expectedSensor + + platform = "error" + altitude = -1. + longitude = 999. + + for data_arr in self.values : + # values come from the scene. + if "platform_name" in data_arr.attrs : + platform = data_arr.attrs["platform_name"] + if "orbital_parameters" in data_arr.attrs : + subAttr = data_arr.attrs["orbital_parameters"] + if "satellite_actual_altitude" in subAttr : + altitude = subAttr["satellite_actual_altitude"] + if "satellite_actual_longitude" in data_arr.attrs : + longitude = data_arr.attrs["satellite_actual_longitude"] + + longitude = float(int(longitude * 10.)) / 10. + assert platform == self.expectedPlatform + assert longitude == self.expectedLongitude + assert altitude == self.expectedAltitude + + xr = self.scn.to_xarray_dataset() + matrice = xr[typeImage] + nbdim = len(matrice.shape) + if nbdim == 3 : + # RGB. + nblin = matrice.shape[1] + nbpix = matrice.shape[2] + elif nbdim == 2 : + # PGM. + nblin = matrice.shape[0] + nbpix = matrice.shape[1] + else : + print("Dimension of shape not expected : ", nbdim) + exit(1) + + assert nblin == self.expectedNblin + assert nbpix == self.expectedNbpix + + cfac = xr.attrs["cfac"] + assert cfac == self.expectedCfac + lfac = xr.attrs["lfac"] + assert lfac == self.expectedLfac + coff = xr.attrs["coff"] + assert coff == self.expectedCoff + loff = xr.attrs["loff"] + assert loff == self.expectedLoff + + satpyId = xr.attrs["_satpy_id"] + # DataID(name='convection', resolution=3000.403165817) + # Cf satpy/dataset/dataid.py. + + resolution = satpyId.get("resolution") + resolution = float(int(resolution * 10.)) / 10. + assert resolution == self.expectedResolution + # checkingSceneParameter() + + def initMsg(self, tmp_path) : + """ + A fake netcdf is built. + A scene is built with the reader to be tested, applied to this netcdf. + Called by test_msg_netcdficare(). + """ + self.netcdfName = tmp_path / "Mmultic3kmNC4_msg03_202406281000.nc" + self.filepath = tmp_path + + listIR = { + "IR_039", "WV_062", "WV_073", "IR_087", "IR_097", + "IR_108", "IR_120", "IR_134" + } + + self.buildNetcdf( + self.netcdfName, 3712, "msg03", x0=-5570254, dx=3000.40604, + y0=5570254, cfac=1.3642337E7, coff=1857.0, + listVisible={"VIS006", "VIS008", "IR_016"}, listIR=listIR, + coordinateSystemName="GeosCoordinateSystem", + nomImageNavigation="ImageNavigation", + nomX="X", nomY="Y", time_coverage_end="2024-06-28T10:12:41Z365") + + # We will check that the parameters written in the dummy netcdf + # can be read. + self.expectedStartTime = "2024-06-28T10:00:09" + self.expectedEndTime = "2024-06-28T10:12:41" + actualAltitude = 35786691 + 6378169 # 42164860.0 + actualLongitude = 0.1 + self.expectedPlatform = "Meteosat-10" + self.expectedSensor = "seviri" + self.expectedAltitude = actualAltitude + self.expectedLongitude = actualLongitude + self.expectedCfac = 1.3642337E7 + self.expectedLfac = 1.3642337E7 + self.expectedCoff = 1857.0 + self.expectedLoff = 1857.0 + self.expectedResolution = 3000.4 + self.expectedNblin = 3712 + self.expectedNbpix = 3712 + + # To build a scene at the date 20240628_100000, + # a netcdf corresponding to msg_netcdficare + # is looked for in the filepath directory. + yaml_file = 'msg_netcdficare' + myfiles = find_files_and_readers( + base_dir=self.filepath, start_time=datetime(2024, 6, 28, 10, 0), + end_time=datetime(2024, 6, 28, 10, 0), reader=yaml_file) + logger.info("Found myfiles = ", myfiles) + # {'msg_netcdficare': ['/tmp/Mmultic3kmNC4_msg03_202406281000.nc']} + + self.scn = Scene(filenames=myfiles, reader=yaml_file) + # initMsg() + + def initMsgHrv(self, tmp_path) : + """ + A fake netcdf is built. + A scene is built with the reader to be tested, applied to this netcdf. + Called by test_msg_netcdficare(). + """ + self.netcdfName = tmp_path / "Mmultic1kmNC4_msg03_202406281000.nc" + self.filepath = tmp_path + + self.buildNetcdf( + self.netcdfName, 11136, "msg03", x0=-5571254., dx=1000.135, + y0=5570254., cfac=40927014, coff=5566.0, listVisible={"HRV"}, + listIR={}, coordinateSystemName="GeosCoordinateSystem_h", + nomImageNavigation="ImageNavigation_h", nomX="X_h", nomY="Y_h", + time_coverage_end="2024-06-28T10:12:41Z365") + + # We will check that the parameters written in the dummy netcdf + # can be read. + self.expectedStartTime = "2024-06-28T10:00:09" + self.expectedEndTime = "2024-06-28T10:12:41" + actualAltitude = 35786691 + 6378169 # 42164860.0 + actualLongitude = 0.1 + self.expectedPlatform = "Meteosat-10" + self.expectedSensor = "seviri" + self.expectedAltitude = actualAltitude + self.expectedLongitude = actualLongitude + self.expectedCfac = 40927014 + self.expectedLfac = 40927014 + self.expectedCoff = 5566.0 + self.expectedLoff = 5566.0 + self.expectedResolution = 1000.1 + self.expectedNblin = 11136 + self.expectedNbpix = 11136 + + # To build a scene at the date 20240628_100000, + # a netcdf corresponding to msg_netcdficare + # is looked for, in the filepath directory. + yaml_file = 'msg_netcdficare' + myfiles = find_files_and_readers( + base_dir=self.filepath, start_time=datetime(2024, 6, 28, 10, 0), + end_time=datetime(2024, 6, 28, 10, 0), reader=yaml_file) + # logger.info("Found myfiles = ", myfiles) + # {'msg_netcdficare': ['/tmp/Mmultic3kmNC4_msg03_202406281000.nc']} + + self.scn = Scene(filenames=myfiles, reader=yaml_file) + # initMsgHrv() + + def initHima(self, tmp_path) : + """ + A fake netcdf is built. + A scene is built with the reader to be tested, applied to this netcdf. + Called by test_hima_netcdficare(). + """ + self.netcdfName = tmp_path / "Jmultic2kmNC4_hima09_202406281000.nc" + self.filepath = tmp_path + + listVisible = { + "VIS004", "VIS005", "VIS006", "VIS008", "IR_016", "IR_022" + } + listIR = { + "IR_038", "WV_062", "WV_069", "WV_073", "IR_085", "IR_096", + "IR_104", "IR_112", "IR_123", "IR_132" + } + self.buildNetcdf( + self.netcdfName, 5500, "hima09", x0=-5500000, dx=2000.0000047, + y0=5500000, cfac=20466275., coff=2750.5, + listVisible=listVisible, listIR=listIR, + coordinateSystemName="GeosCoordinateSystem2km", + nomImageNavigation="ImageNavigation2km", + nomX="X2km", nomY="Y2km", + time_coverage_end="2024-06-28T10:08:41Z365") + + # We will check that the parameters written in the dummy netcdf + # can be read. + self.expectedStartTime = "2024-06-28T10:00:09" + self.expectedEndTime = "2024-06-28T10:08:41" + actualAltitude = 35786691 + 6378169 # 42164860.0 + actualLongitude = 0.1 + self.expectedPlatform = "Himawari-9" + self.expectedSensor = "ahi" + self.expectedAltitude = actualAltitude + self.expectedLongitude = actualLongitude + self.expectedCfac = 20466275. + self.expectedLfac = 20466275. + self.expectedCoff = 2750.5 + self.expectedLoff = 2750.5 + self.expectedResolution = 2000. + self.expectedNblin = 5500 + self.expectedNbpix = 5500 + + # To build a scene at the date 20240628_100000, + # a netcdf corresponding to msg_netcdficare + # is looked for in the filepath directory. + yaml_file = 'hima_netcdficare' + myfiles = find_files_and_readers( + base_dir=self.filepath, start_time=datetime(2024, 6, 28, 10, 0), + end_time=datetime(2024, 6, 28, 10, 0), reader=yaml_file) + # logger.info("Found myfiles = ", myfiles) + # {'msg_netcdficare': ['/tmp/Mmultic3kmNC4_msg03_202406281000.nc']} + + self.scn = Scene(filenames=myfiles, reader=yaml_file) + # initHima() + + def initMtg(self, tmp_path) : + """ + A fake netcdf is built. + A scene is built with the reader to be tested, applied to this netcdf. + Called by test_mtg_netcdficare(). + """ + self.netcdfName = tmp_path / "Mmultic1kmNC4_mtgi1_202406281000.nc" + self.filepath = tmp_path + + # self.buildNetcdf( + # self.netcdfName, 5568, "mtgi1", + # x0 = -5568000, dx = 2000.0000047, y0 = 5568000, cfac = 13642337, coff = 2784.5, + # listVisible= {"VIS004", "VIS005", "VIS006", "VIS008", "VIS009", + # "IR_013", "IR_016", "IR_022"}, + # listIR={"IR_038", "WV_062", "WV_073", "IR_087", + # "IR_097", "IR_105", "IR_123", "IR_133"}, + # coordinateSystemName = "GeosCoordinateSystem2km", + # nomImageNavigation = "ImageNavigation2km", + # nomX = "X2km", nomY = "Y2km", + # time_coverage_end = "2024-06-28T10:08:41Z365") + + listVisible = { + "VIS004", "VIS005", "VIS006", "VIS008", + "VIS009", "IR_013", "IR_016", "IR_022" + } + + self.buildNetcdf( + self.netcdfName, 11136, "mtgi1", + x0=-5568000, dx=1000.0000047, y0=5568000, + cfac=4.093316350596011E7, coff=5568.5, + listVisible=listVisible, listIR={"IR_038", "IR_105"}, + coordinateSystemName="GeosCoordinateSystem1km", + nomImageNavigation="ImageNavigation1km", + nomX="X1km", nomY="Y1km", time_coverage_end="2024-06-28T10:08:41Z") + + # We will check that the parameters written in the dummy netcdf + # can be read. + self.expectedStartTime = "2024-06-28T10:00:09" + self.expectedEndTime = "2024-06-28T10:08:41" + actualAltitude = 35786691 + 6378169 # 42164860.0 + actualLongitude = 0.1 + self.expectedPlatform = "Meteosat-12" + self.expectedSensor = "fci" + self.expectedAltitude = actualAltitude + self.expectedLongitude = actualLongitude + self.expectedCfac = 4.093316350596011E7 # 13642337. + self.expectedLfac = 4.093316350596011E7 # 13642337. + self.expectedCoff = 5568.5 # 2784.5 + self.expectedLoff = 5568.5 # 2784.5 + self.expectedResolution = 1000. + self.expectedNblin = 11136 # 5568 + self.expectedNbpix = 11136 # 5568 + + # To build a scene at the date 20240628_100000, + # a netcdf corresponding to msg_netcdficare + # is looked for in the filepath directory. + yaml_file = 'mtg_netcdficare' + myfiles = find_files_and_readers( + base_dir=self.filepath, start_time=datetime(2024, 6, 28, 10, 0), + end_time=datetime(2024, 6, 28, 10, 0), reader=yaml_file) + # logger.info("Found myfiles = ", myfiles) + # {'msg_netcdficare': ['/tmp/Mmultic3kmNC4_msg03_202406281000.nc']} + + self.scn = Scene(filenames=myfiles, reader=yaml_file) + # initMtg() + + def initGoesr(self, tmp_path) : + """ + A fake netcdf is built. + A scene is built with the reader to be tested, applied to this netcdf. + Called by test_goesr_netcdficare(). + """ + self.netcdfName = tmp_path / "Emultic2kmNC4_goes16_202406281000.nc" + self.filepath = tmp_path + + listVisible = { + "VIS_004", "VIS_006", "VIS_008", "VIS_014", "VIS_016", "VIS_022" + } + listIR = { + "IR_039", "IR_062", "IR_069", "IR_073", "IR_085", + "IR_096", "IR_103", "IR_114", "IR_123", "IR_133" + } + self.buildNetcdf( + self.netcdfName, 5424, "goes16", + x0=-5434894.8, dx=2004.017288, y0=5434894.8, + cfac=20425338.9, coff=2712.5, + listVisible=listVisible, listIR=listIR, + coordinateSystemName="GeosCoordinateSystem2km", + nomImageNavigation="ImageNavigation2km", + nomX="X2km", nomY="Y2km", + time_coverage_end="2024-06-28T10:08:41.1Z") + + # We will check that the parameters written in the dummy netcdf + # can be read. + self.expectedStartTime = "2024-06-28T10:00:09" + self.expectedEndTime = "2024-06-28T10:08:41" + actualAltitude = 35786691 + 6378169 # 42164860.0 + actualLongitude = 0.1 + self.expectedPlatform = "GOES-16" + self.expectedSensor = "abi" + self.expectedAltitude = actualAltitude + self.expectedLongitude = actualLongitude + self.expectedCfac = 20425338.9 + self.expectedLfac = 20425338.9 + self.expectedCoff = 2712.5 + self.expectedLoff = 2712.5 + self.expectedResolution = 2000. + self.expectedNblin = 5424 + self.expectedNbpix = 5424 + + # To build a scene at the date 20240628_100000, + # a netcdf corresponding to msg_netcdficare + # is looked for in the filepath directory. + yaml_file = 'goesr_netcdficare' + myfiles = find_files_and_readers( + base_dir=self.filepath, start_time=datetime(2024, 6, 28, 10, 0), + end_time=datetime(2024, 6, 28, 10, 0), reader=yaml_file) + + self.scn = Scene(filenames=myfiles, reader=yaml_file) + # initGoesr() + + def buildNetcdf( + self, ncName, nbpix=3712, nomSatellite="msg03", + x0=-5570254, dx=3000.40604, y0=5570254, + cfac=1.3642337E7, coff=1857.0, + listVisible={}, listIR={}, + coordinateSystemName="GeosCoordinateSystem", + nomImageNavigation="ImageNavigation", + nomX="X", nomY="Y", + time_coverage_end="2024-06-28T10:12:41Z365") : + """ + ncName : tmp_path / Mmultic3kmNC4_msg03_202406281000.nc + A dummy icare Meteo France netcdf is built here. + Called by initMsg... + listVisible = {"VIS006", "VIS008", "IR_016"} + listIR = {"IR_039", "WV_062", "WV_073", "IR_087", "IR_097", "IR_108", + "IR_120", "IR_134"} + """ + if os.path.exists(ncName) : + os.remove(ncName) + ncfileOut = Dataset( + ncName, mode="w", clobber=True, + diskless=False, persist=False, format='NETCDF4') + + ncfileOut.createDimension(u'ny', nbpix) + ncfileOut.createDimension(u'nx', nbpix) + ncfileOut.createDimension(u'numerical_count', 65536) + ncfileOut.setncattr("time_coverage_start", "2024-06-28T10:00:09Z383") + ncfileOut.setncattr("time_coverage_end", time_coverage_end) + ncfileOut.setncattr("Area_of_acquisition", "globe") + + fill_value = -32768 + var = ncfileOut.createVariable( + "satellite", "c", zlib=True, complevel=4, + shuffle=True, fletcher32=False, contiguous=False, + chunksizes=None, endian='native', least_significant_digit=None) + + var.setncattr("id", nomSatellite) + var.setncattr("dst", 35786691.) + var.setncattr("lon", float(0.1)) + + var = ncfileOut.createVariable( + "geos", "c", zlib=True, complevel=4, shuffle=True, + fletcher32=False, contiguous=False, chunksizes=None, + endian='native', least_significant_digit=None) + var.setncattr("longitude_of_projection_origin", 0.) + + var = ncfileOut.createVariable( + coordinateSystemName, "c", zlib=True, complevel=4, + shuffle=True, fletcher32=False, contiguous=False, + chunksizes=None, endian='native', least_significant_digit=None) + + stringGeotransform = str(x0) + ", " + str(dx) + ", 0, " + stringGeotransform += str(-x0) + ", 0, " + str(-dx) + # -5570254, 3000.40604, 0, 5570254, 0, -3000.40604 + var.setncattr("GeoTransform", stringGeotransform) + + var = ncfileOut.createVariable( + nomImageNavigation, "c", zlib=True, complevel=4, + shuffle=True, fletcher32=False, contiguous=False, + chunksizes=None, endian='native', least_significant_digit=None) + var.setncattr("CFAC", cfac) + var.setncattr("LFAC", cfac) + var.setncattr("COFF", coff) + var.setncattr("LOFF", coff) + + var = ncfileOut.createVariable( + nomX, 'float32', u'nx', zlib=True, complevel=4, + shuffle=True, fletcher32=False, contiguous=False, + chunksizes=None, endian='native', least_significant_digit=None) + var[:] = np.array(([(x0 + dx * i) for i in range(nbpix)])) + + var = ncfileOut.createVariable( + nomY, 'float32', u'ny', zlib=True, complevel=4, + shuffle=True, fletcher32=False, contiguous=False, + chunksizes=None, endian='native', least_significant_digit=None) + y0 = -x0 + dy = -dx + var[:] = np.array(([(y0 + dy * i) for i in range(nbpix)])) + + self.visibleChannelsCreation( + ncfileOut, fill_value, listVisible, nbpix, coordinateSystemName) + self.infrarougeChannelsCreation( + ncfileOut, fill_value, listIR, nbpix, coordinateSystemName) + ncfileOut.close + # buildNetcdf() + + def visibleChannelsCreation( + self, ncfileOut, fill_value, listVisible, nbpix, coordinateSystemName) : + + for channel in listVisible : + var = ncfileOut.createVariable( + channel, 'short', ('ny', 'nx'), zlib=True, complevel=4, + shuffle=True, fletcher32=False, contiguous=False, + chunksizes=None, endian='native', + least_significant_digit=None, fill_value=fill_value) + var[:] = np.array( + ([[i * 2 for i in range(nbpix)] for j in range(nbpix)])) + # Hundredths of albedo between 0 and 10000. + var.setncattr("scale_factor", 0.01) + var.setncattr("add_offset", 0.) + var.setncattr("bandfactor", 20.76) + var.setncattr("_CoordinateSystems", coordinateSystemName) + + var = ncfileOut.createVariable( + "Albedo_to_Native_count_" + channel, 'short', + 'numerical_count', zlib=True, complevel=4, shuffle=True, + fletcher32=False, contiguous=False, chunksizes=None, + endian='native', least_significant_digit=None, + fill_value=-9999) + var[:] = np.array(([-9999 for i in range(65536)])) + # In order to come back to the native datas on 10, 12 or 16 bits. + + def infrarougeChannelsCreation( + self, ncfileOut, fill_value, listIR, nbpix, coordinateSystemName) : + + for channel in listIR : + var = ncfileOut.createVariable( + channel, 'short', ('ny', 'nx'), zlib=True, complevel=4, + shuffle=True, fletcher32=False, contiguous=False, + chunksizes=None, endian='native', + least_significant_digit=None, fill_value=fill_value) + var[:] = np.array( + ([[-9000 + j * 4 for i in range(nbpix)] for j in range(nbpix)]) + ) + # Hundredths of celcius degrees. + var.setncattr("scale_factor", 0.01) + var.setncattr("add_offset", 273.15) + var.setncattr("nuc", 1600.548) + var.setncattr("alpha", 0.9963) + var.setncattr("beta", 2.185) + var.setncattr("_CoordinateSystems", coordinateSystemName) + + var = ncfileOut.createVariable( + "Temp_to_Native_count_" + channel, 'short', + 'numerical_count', zlib=True, complevel=4, shuffle=True, + fletcher32=False, contiguous=False, chunksizes=None, + endian='native', least_significant_digit=None, + fill_value=-9999) + var[:] = np.array(([-9999 for i in range(65536)])) + # In order to come back to the native datas on 10, 12 or 16 bits. + + # class TestGeosNetcdfIcareReader.