Estrazione di valori a latitudine specifica, longitudine dai dati dell'andana MODIS


9

Sto cercando di determinare la quantità di vapore acqueo precipitabile (PWV), ozono e aerosol in funzione del tempo su punti specifici della Terra, vale a dire i nostri osservatori astronomici. Per fare questo, ho già ottenuto un codice Python modapsclientche utilizza per scaricare i prodotti MODIS Aqua e Terra MYDATML2 e MODATML2 due volte al giorno che coprono la specifica latitudine e longitudine a cui sono interessato.

Ciò di cui non sono sicuro è come estrarre le quantità specifiche che desidero, ad esempio il tempo in cui sono stati acquisiti i dati MODIS e il PWV per la particolare posizione di latitudine e longitudine del mio osservatorio per trasformarli in una serie temporale di valori. I prodotti MYDATML2 sembrano contenere griglie di latitudine e longitudine 2D di Cell_Along_Swath_5kme Cell_Across_Swath_5kmquindi immagino che questo renda i dati dell'andana piuttosto che i dati di piastrella o griglia? Le quantità che desidero, come quelle, Precipitable_Water_Infrared_ClearSkysembrano anche essere in contrasto con Cell_Along_Swath_5kme Cell_Across_Swath_5kmma non sono sicuro di come ottenere quel valore PWV al lat specifico, a lungo sono interessato. Aiuto per favore?


Potete per favore fornire un link alle immagini o un campione di esso?
Andrea Massetti,

Certo, ecco un file di esempio nell'archivio MODIS: ladsweb.modaps.eosdis.nasa.gov/archive/allData/61/MODATML2/2018/…
astrosnapper,

Ciao, hai avuto la possibilità di provare la mia risposta?
Andrea Massetti,

1
Mi dispiace, sono stato via a una conferenza presentando lavori basati su determinazioni PWV simili da dati sat ... Il tuo codice aggiornato mi dà gli stessi valori che vedo in PanoplyJ per la stessa cella (tenendo conto di un diverso ordine di indice dell'array e un inizia la differenza 'off by 1' nell'indice di array)
astrosnapper

Risposte:


1

[EDIT 1 - Ho cambiato la ricerca delle coordinate pixel]

Utilizzando questo esempio di MODATML fornito e utilizzando la libreria gdal. Apriamo l'hdf con gdal:

import gdal
dataset = gdal.Open(r"E:\modis\MODATML2.A2018182.0800.061.2018182195418.hdf")

Quindi vogliamo vedere come vengono denominati i sotto-dataset per importare correttamente quelli di cui abbiamo bisogno:

datasets_meta = dataset.GetMetadata("SUBDATASETS")

Questo restituisce un dizionario:

datasets_meta
>>>{'SUBDATASET_1_NAME': 'HDF4_EOS:EOS_SWATH:"E:\\modis\\MODATML2.A2018182.0800.061.2018182195418.hdf":atml2:Cloud_Optical_Thickness', 
'SUBDATASET_1_DESC': '[406x271] Cloud_Optical_Thickness atml2 (16-bit integer)',
'SUBDATASET_2_NAME':'HDF4_EOS:EOS_SWATH:"E:\\modis\\MODATML2.A2018182.0800.061.2018182195418.hdf":atml2:Cloud_Effective_Radius',
'SUBDATASET_2_DESC': '[406x271] Cloud_Effective_Radius atml2 (16-bit integer)',
[....]}

Diciamo che vogliamo ottenere la prima variabile, lo spessore ottico della nuvola, possiamo accedere al suo nome tramite:

datasets_meta['SUBDATASET_1_NAME']
>>>'HDF4_EOS:EOS_SWATH:"E:\\modis\\MODATML2.A2018182.0800.061.2018182195418.hdf":atml2:Cloud_Optical_Thickness'

Ora possiamo caricare nuovamente la variabile in memoria chiamando il metodo .Open ():

Cloud_opt_th = gdal.Open(datasets_meta['SUBDATASET_1_NAME'])

Ad esempio, puoi accedere a Precipitable_Water_Infrared_ClearSky a cui sei interessato fornendo "SUBDATASET_20_NAME". Dai un'occhiata al dizionario datasets_meta.

Tuttavia, la variabile estratta non ha una geoproiezione (var.GetGeoprojection ()) come ci si aspetterebbe da altri tipi di file come GeoTiff. È possibile caricare la variabile come una matrice numpy e tracciare la variabile 2d senza proiezione:

Cloud_opt_th_array = Cloud_opt_th.ReadAsArray()
import matplotlib.pyplot as plt
plt.imshow(Cloud_opt_th_array)

Ora, poiché non esiste alcuna geoproiezione, esamineremo i metadati della variabile:

Cloud_opt_th_meta = Cloud_opt_th.GetMetadata()

Questo è un altro dizionario che include tutte le informazioni necessarie, inclusa una lunga descrizione del sottocampionamento (ho notato che questo è fornito solo con il primo sottodataset), che include la spiegazione di questi Cell_Along_Swath:

Cloud_opt_th_meta['1_km_to_5_km_subsampling_description']
>>>'Each value in this dataset does not represent an average of properties over a 5 x 5 km grid box, but rather a single sample from within each 5 km box. Normally, pixels in across-track rows 4 and 9 (counting in the direction of increasing scan number) out of every set of 10 rows are used for subsampling the 1 km retrievals to a 5 km resolution. If the array contents are determined to be all fill values after selecting the default pixel subset (e.g., from failed detectors), a different pair of pixel rows is used to perform the subsampling. Note that 5 km data sets are centered on rows 3 and 8; the default sampling choice of 4 and 9 is for better data quality and avoidance of dead detectors on Aqua. The row pair used for the 1 km sample is always given by the first number and last digit of the second number of the attribute Cell_Along_Swath_Sampling. The attribute Cell_Across_Swath_Sampling indicates that columns 3 and 8 are used, as they always are, for across-track sampling. Again these values are to be interpreted counting in the direction of the scan, from 1 through 10 inclusively. For example, if the value of attribute Cell_Along_Swath_Sampling is 3, 2028, 5, then the third and eighth pixel rows were used for subsampling. A value of 4, 2029, 5 indicates that the default fourth and ninth rows pair was used.'

Penso che ciò significhi che sulla base di questi pixel da 1km i 5km sono stati costruiti prendendo esattamente i valori dei pixel in una certa posizione nell'array di rilevamento 5x5 (la posizione è indicata nei metadati, penso che questa sia una cosa strumentale per ridurre i guasti).

Ad ogni modo, a questo punto abbiamo una matrice di celle 1x1 km (vedi la descrizione del sottocampionamento sopra, non sono sicuro della scienza dietro di essa). Per ottenere le coordinate di ciascun centroide pixel, è necessario caricare i sottodataset di latitudine e longitudine.

Latitude = gdal.Open(datasets_meta['SUBDATASET_66_NAME']).ReadAsArray()
Longitude = gdal.Open(datasets_meta['SUBDATASET_67_NAME']).ReadAsArray()

Per esempio,

Longitude
>>> array([[-133.92064, -134.1386 , -134.3485 , ..., -154.79303, -154.9963 ,
    -155.20723],
   [-133.9295 , -134.14743, -134.3573 , ..., -154.8107 , -155.01431,
    -155.2256 ],
   [-133.93665, -134.1547 , -134.36465, ..., -154.81773, -155.02109,
    -155.23212],
   ...,
   [-136.54477, -136.80055, -137.04684, ..., -160.59378, -160.82101,
    -161.05663],
   [-136.54944, -136.80536, -137.05179, ..., -160.59897, -160.8257 ,
    -161.06076],
   [-136.55438, -136.81052, -137.05714, ..., -160.6279 , -160.85527,
    -161.09099]], dtype=float32)        

È possibile notare che le coordinate di latitudine e longitudine sono diverse per ciascun pixel.

Supponiamo che il tuo osservatorio si trovi alle coordinate lat_obs, long_obs, quindi minimizzi la differenza di coordinate x, y:

coordinates = np.unravel_index((np.abs(Latitude - lat_obs) + np.abs(Longitude - long_obs)).argmin(), Latitude.shape)

ed estrai il tuo valore

Cloud_opt_th_array[coordinates]

Grazie per le informazioni ma sto riscontrando problemi con la parte di conversione coordinata; la Longitude_pxe Latitude_pxsono entrambe le matrici di lunghezza zero. C'è anche un modo per gestire la conversione usando gdalse stesso? (anziché fare affidamento su un'approssimazione di 1 grado è X n. di miglia e poi ri-approssimando quello a km)
astrosnapper

Latitudine e Longitudine sono fornite come sottodataset, ovvero 66 e 67. Aggiornerò la seconda parte.
Andrea Massetti,

@astrosnapper ora la risposta dovrebbe rispondere completamente alla tua domanda.
Andrea Massetti,
Utilizzando il nostro sito, riconosci di aver letto e compreso le nostre Informativa sui cookie e Informativa sulla privacy.
Licensed under cc by-sa 3.0 with attribution required.