Рассчитать среднее значение переменных в селективной области, в файле netCDF с сеткой

Допустим, у нас есть данные об осадках TRMM, каждый файл представляет данные за каждый месяц. Например, файлы в папке:

     3B42.1998.01.01.7A.nc,
     3B42.1998.02.01.7A.nc, 
     3B42.1998.03.01.7A.nc, 
     3B42.1998.04.01.7A.nc, 
     3B42.1998.05.01.7A.nc, 
     ......
     ......
     3B42.2010.11.01.7A.nc,         
     3B42.2010.12.01.7A.nc.

Эти файлы имеют следующие размеры: Xsize=1440, Ysize=400, Zsize=1,Tsize=1. Долгота установлена ​​от 0 до 360, а широта установлена ​​от -50 до 50. Я хочу рассчитать количество осадков в определенном регионе, скажем, между lon=98.5, lon=100 and lat=4, lat=6.5, Это означает, что читать переменные только в этом регионе -:

-------------------- |lon:98.5 lat:6.5| | | |lat:4 lon:100 | ---------------------

Я делал это в GrADS (система анализа и отображения сетки). В GrADS это можно сделать так: (упрощенная версия)

      yy=1998
      while yr < 2011
        'sdfopen f:\data\trmm\3B42.'yy'.12.01.7A.nc'
        'd aave(pcp,lon=98.5,lon=100.0,lat=4.0,lat=6.5)'
         res=subwrd(result,4)
         rec=write('d:\precip.sp.TRMM3B42.1.'yy'.csv',res,append)   
         yy = yy+1
      endwhile

Я пытался сделать то же самое в Python, но что-то пошло не так. После нескольких предложений вот и я:

     import csv
     import netCDF4 as nc 
     import numpy as np

     #calculating december only
     f = nc.MFDataset('d:/data/trmm/3B43.????.12.01.7A.nc')#maybe I shouldn't do MFDataset?
     pcpt = f.variables['pcp']
     lon = f.variables['longitude']
     lat = f.variables['latitude']
     # Determine which longitudes
     latidx1 = (lat >=4.0 ) & (lat <=6.5 ) 
     lonidx1 = (lon >=98.5 ) & (lon <=100.0 ) 

     rainf1 = pcpt[:]
     rainf1 = rainf1[:, latidx1][..., lonidx1]
     rainf_1 = rainf1

     with open('d:/trmmtest.csv', 'wb') as fp:
          a = csv.writer(fp)
          for i in rainf_1:
              a.writerow([i])

Этот скрипт создает список (в моем случае) 15 значений в CSV-файле. Но когда я пытаюсь получить значения для другого региона и настроить то, что считаю необходимым, скажем:

     latidx2 = (lat >=1.0 ) & (lat <=1.5 ) 
     lonidx2 = (lon >=102.75 ) & (lon <=103.25 ) 

     rainf2 = pcpt[:]
     rainf2 = rainf2[:, latidx2][..., lonidx2]
     rainf_2 = rainf2

Я получаю те же значения, что и первый.

firstarea=[0.511935,1.0771,0.613548,1.48839,0.445161,1.39161,1.03548,0.452903, 3.07725,2.84613 0.701613,2.10581,2.47839,3.84097,2.41065,1.38387]

secondarea=[0.511935,1.0771,0.613548,1.48839,0.445161,1.39161,1.03548,0.452903, 3.07725,2.84613,0.701613,2.10581,2.47839,3.84097,2.41065,1.38387]

Я проводил тестирование по отдельным сценариям, они по-прежнему дают те же значения Я проверил на карте (построенной ранее), значения в этих двух регионах разные (в среднем за декабрь).

Есть идеи почему? Есть ли другой элегантный способ написать это? Спасибо.

4 ответа

Решение

Через некоторое время мне снова удалось взглянуть на эту проблему, и, по-видимому, описанный выше метод почти верен. После нескольких настроек, протестированных в одном файле данных и перепроверенных с помощью решения GrADS, я получил что-то вроде этого:

    f = nc.Dataset('~/data/TRMM3H/3B42.19980101.12.7A.nc')
    pcpt = f.variables['pcp'][:]
    lon = f.variables['longitude'][:]
    lat = f.variables['latitude'][:]

    #select two regions
    latidx1 = (lat >=4. ) & (lat <=6.5 ) 
    lonidx1 = (lon >=100.5 ) & (lon <=101.5 ) 
    latidx2 = (lat >=2.5 ) & (lat <=5.0 ) 
    lonidx2 = (lon >=101. ) & (lon <=102. ) 

    rainf = pcpt[:]
    #these basically listing the values in an array (2 in this case)
    rainf1 = rainf[:, latidx1][..., lonidx1]
    rainf2 = rainf[:, latidx2][..., lonidx2]
    rainf_1 = rainf1
    rainf_2 = rainf2

    #time to get the mean values
    print np.mean(rainf_1)
    print "............."
    print np.mean(rainf_2)
    print "............."

это дало мне такие результаты:

    >>> execfile('find_percentile.py')
    0.7830327034
    .............
    1.56235361099
    .............

Результаты совпадают при расчете с GrADS.

Отредактировано после предложения:

    f = nc.Dataset('~/data/TRMM3H/3B42.19980101.12.7A.nc')
    pcpt = f.variables['pcp'][:]
    lon = f.variables['longitude'][:]
    lat = f.variables['latitude'][:]

    #select two regions
    latidx1 = (lat >=4. ) & (lat <=6.5 ) 
    lonidx1 = (lon >=100.5 ) & (lon <=101.5 ) 
    latidx2 = (lat >=2.5 ) & (lat <=5.0 ) 
    lonidx2 = (lon >=101. ) & (lon <=102. ) 

    #these basically listing the values in an array (2 in this case)
    rainf1 = pcpt[:, latidx1][..., lonidx1]
    rainf2 = pcpt[:, latidx2][..., lonidx2]
    rainf_1 = rainf1
    rainf_2 = rainf2

    #time to get the mean values
    print np.mean(rainf_1)
    print "............."
    print np.mean(rainf_2)
    print "............."

Вернемся к исходному вопросу, делая это в нескольких файлах и печатая его в файле txt/csv, все еще в стадии разработки (и тестирования).

Я просто хочу отметить, что решение Fir Nor неверно, так как вы не можете просто использовать среднее арифметическое (np.mean) при работе с пространственными данными на регулярной решетке широта / долгота, как здесь, так как сетка размер клетки меняется по мере движения к полюсам!

Куда лучше не беспокоиться об этом и делать операцию с CDO:

cdo fldmean -sellonlatbox,98.5,100,4.5,6 3B42.1998.05.01.7A.nc boxav.nc

Если вы работаете в Linux, эту проблему можно решить с помощью nctoolkit (http://nctoolkit.readthedocs.io/en/latest/). Все должно делать следующее:

import nctoolkit as nc
ff = '~/data/TRMM3H/3B42.19980101.12.7A.nc'
data = nc.open_data(ff)
data.clip(lon = [98.5, 100], lat = [4, 6.5])
data.spatial_mean()

Примечание: здесь в качестве бэкэнда используется CDO, а Space_mean вычисляет среднее значение, взвешенное по площади каждой ячейки сетки.

Я считаю, что это легко сделать с помощью пакета easymore.

Первый шаг - это создание шейп-файла. Это может быть любая форма (например, точка, подбассейн или прямоугольник). В вашем случае это будет прямоугольный шейп-файл с одной формой, определяющей границу. Это можно сделать в QGIS, ArcGIS или на Python:

Создание файла формы из списка координат ограничивающей рамки

Затем нужно вызвать пакет easymore python и переназначить переменную в интересующий шейп-файл, выполнив следующие простые действия:

      # loading EASYMORE
from easymore.easymore import easymore

# initializing EASYMORE object
esmr = easymore()

# specifying EASYMORE objects
# name of the case
esmr.case_name                = 'CMIP6_3B43'              
# temporary path that the EASYMORE generated GIS files and remapped file will be saved
esmr.temp_dir                 = 'path/temporary/'
# name of target shapefile that the source netcdf files should be remapped to;
# it was created in the first step
esmr.target_shp               = 'path/target_shapefiles/box.shp'
# name of netCDF file(s); multiple files can be specified with *
esmr.source_nc                = ' d:/data/trmm/3B43*.nc'
# name of variables from source netCDF file(s) to be remapped
esmr.var_names                = ['pcp']
# name of variable longitude in source netCDF files
esmr.var_lon                  = 'longitude'
# name of variable latitude in source netCDF files
esmr.var_lat                  = 'latitude'
# name of variable time in source netCDF file; should be always time
esmr.var_time                 = 'time'
# location where the remapped netCDF, csv file will be saved
esmr.output_dir               = 'path/output/'
# if required that the remapped values to be saved as csv as well
esmr.save_csv                 = True

# execute EASYMORE nc remapper
esmr.nc_remapper()

Этот код будет генерировать как переназначенные файлы nc, так и его версию csv в выходном каталоге для каждого исходного файла nc. Переназначенные файлы будут представлять собой среднее по площади количество осадков по интересующей форме (ам) с исходным разрешением по времени (например, день). Затем вы можете легко увеличить их до ежемесячного временного шага и сравнить.

Преимущества:

1- С помощью этого пакета вы можете предоставить шейп-файл с несколькими формами (интересующими областями), который выполняет переназначение за один раз. В качестве примера вы можете вместо этого предоставить шейп-файл стран мира.

2- Если ваше поле меньше, чем сетка (многоугольник) или точка, возвращаемое значение будет сеткой, в которой находится маленький прямоугольник или точка.

3- Переназначение и взвешивание выполняются в равной области для учета различных сеток одинаковой площади в WGS84 в более высоких латах.

4- Код достаточно умен, поэтому вам не нужно беспокоиться о формате от 0 до 360 lon и о целевом шейп-файле в формате от -180 до 180 lon. Например, если поле находится в NA, отрицательное значение lon, шейп-файл может быть задан в отрицательном формате lon от -180 до 180, а файл NC - с неотрицательными значениями lon (от 0 до 360).

Страница GitHub с дополнительными примерами:

https://github.com/ShervanGharari/EASYMORE

Другие вопросы по тегам