Wydobywanie wartości na określonej szerokości i długości geograficznej z danych pokosu MODIS

9

Staram się określić ilość opadającej pary wodnej (PWV), ozonu i aerozoli w funkcji czasu nad określonymi punktami na Ziemi, a mianowicie naszymi obserwatoriami astronomicznymi. Aby to zrobić, mam już kod Pythona, modapsclientktóry pobierze dwa razy dziennie produkty MODIS Aqua i Terra MYDATML2 i MODATML2, które obejmują konkretną szerokość i długość geograficzną, którymi jestem zainteresowany.

Nie jestem pewien, jak wyodrębnić określone wielkości, takie jak czas pobrania danych MODIS i PWV dla określonej szerokości i długości geograficznej mojego obserwatorium, aby przekształcić je w szereg czasowy wartości. Produkty MYDATML2 wydają się zawierać 2D szerokości i długości geograficznej siatek Cell_Along_Swath_5kmi Cell_Across_Swath_5kmtak myślę, że to sprawia, że pokos danych w przeciwieństwie do płytek lub sieci danych? Ilości chcę taki jak Precipitable_Water_Infrared_ClearSkyrównież wydają się być przeciw Cell_Along_Swath_5kmi Cell_Across_Swath_5kmbutI'm nie wiem, jak uzyskać tę wartość prędkości fali tętna w konkretnym lat, długo mnie interesują. Pomóc proszę?

astrosnapper
źródło
Czy możesz podać link do zdjęć lub ich próbkę?
Andrea Massetti,
Jasne, oto przykładowy plik w archiwum MODIS: ladsweb.modaps.eosdis.nasa.gov/archive/allData/61/MODATML2/2018/…
astrosnapper
Cześć, masz szansę wypróbować moją odpowiedź?
Andrea Massetti
1
Przepraszam, byłem na konferencji prezentującej pracę opartą na podobnych oznaczeniach PWV na podstawie danych sat ... Twój zaktualizowany kod daje mi te same wartości, co widzę w PanoplyJ dla tej samej komórki (biorąc pod uwagę inną kolejność indeksów tablic i rozpoczyna się różnica „off by 1” w indeksie tablic)
astrosnapper,

Odpowiedzi:

1

[EDYCJA 1 - Zmieniłem wyszukiwanie współrzędnych pikseli]

Korzystając z tego przykładu MODATML , który dostarczyłeś i używając biblioteki gdal. Otwórzmy plik hdf za pomocą gdal:

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

Następnie chcemy zobaczyć, jak nazywane są subdazy, aby poprawnie zaimportować te, których potrzebujemy:

datasets_meta = dataset.GetMetadata("SUBDATASETS")

Zwraca to słownik:

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)',
[....]}

Powiedzmy, że chcemy uzyskać pierwszą zmienną, grubość optyczną chmury, możemy uzyskać dostęp do jej nazwy poprzez:

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

Teraz możemy ponownie załadować zmienną do pamięci, wywołując ponownie metodę .Open ():

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

Na przykład możesz uzyskać dostęp do interesującego Cię Precipitable_Water_Infrared_ClearSky, podając „SUBDATASET_20_NAME”. Wystarczy spojrzeć na słownik datasets_meta.

Jednak wyodrębniona zmienna nie ma geoprojection (var.GetGeoprojection ()), jak można oczekiwać od innych typów plików, takich jak GeoTiff. Możesz załadować zmienną jako tablicę numpy i wykreślić zmienną 2d bez projekcji:

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

Ponieważ nie ma geoprojektów, przyjrzymy się metadanym zmiennej:

Cloud_opt_th_meta = Cloud_opt_th.GetMetadata()

Jest to kolejny słownik, który zawiera wszystkie potrzebne informacje, w tym długi opis podpróbkowania (zauważyłem, że jest on dostarczany tylko z pierwszym zestawem danych podrzędnych), który zawiera wyjaśnienie tych 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.'

Myślę, że to oznacza, że ​​w oparciu o te 1 km piksele zbudowano 5 km, biorąc dokładnie wartości pikseli w pewnej pozycji w matrycy 5x5 (pozycja jest wskazana w metadanych, myślę, że jest to instrument mający na celu zmniejszenie błędów).

W każdym razie, w tym momencie mamy tablicę komórek 1x1 km (patrz opis podpróbkowania powyżej, nie jestem pewien, co za tym stoi). Aby uzyskać współrzędne każdego środka ciężkości piksela, musimy załadować podszeregi szerokości i długości geograficznej.

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

Na przykład,

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)        

Możesz zauważyć, że współrzędne szerokości i długości geograficznej są różne dla każdego piksela.

Powiedz, że twoje obserwatorium znajduje się na współrzędnych lat_obs, long_obs, niż zminimalizujesz różnicę współrzędnych x, y:

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

i wyodrębnij swoją wartość

Cloud_opt_th_array[coordinates]
Andrea Massetti
źródło
Dziękuję za informację, ale mam problemy z częścią dotyczącą konwersji współrzędnych; Longitude_pxi Latitude_pxto zarówno macierze zerowej długości. Czy jest też sposób na samodzielne przetworzenie konwersji gdal? (zamiast polegać na przybliżeniu 1 stopnia to liczba X mil, a następnie ponowne przybliżenie do km)
astrosnapper
Szerokość i długość geograficzna są udostępniane jako subdatasets, mianowicie 66 i 67. Zaktualizuję drugą część.
Andrea Massetti
@astrosnapper teraz odpowiedź powinna całkowicie odpowiedzieć na twoje pytanie.
Andrea Massetti,