Java NetCDF: агрегирование существующих файлов: проблема с измерением времени не найдена

Для своей головоломки я некоторое время просматривал документы и архивы списков рассылки, и мне трудно собрать воедино шаги, которые мне нужны, чтобы справиться с этой агрегацией.

Данные CFSR за 1 час. Файлы данных отсюда: http://rda.ucar.edu/datasets/ds094.0/

cdas_20161215_0000_f00000_G4.grib2
cdas_20161215_0000_f00100_G4
cdas_20161215_0000_f00200_G4
cdas_20161215_0000_f00300_G4
etc...

Почасовые файлы декларируют 2 измерения времени: одно с установленными границами, а другое - без.

cdas_20161215_0000_f00300_G4.grib2
double time(time=1);
  :units = "Hour since 2016-12-15T00:00:00Z";
  :standard_name = "time";
  :long_name = "GRIB forecast or observation time";
  :calendar = "proleptic_gregorian";
  :bounds = "time_bounds";
double time_bounds(time=1, 2);
  :units = "Hour since 2016-12-15T00:00:00Z";
  :long_name = "bounds for time";
double time1(time1=1);
  :units = "Hour since 2016-12-15T00:00:00Z";
  :standard_name = "time";
  :long_name = "GRIB forecast or observation time";
  :calendar = "proleptic_gregorian";

Проблема в том, что при создании каждого набора данных разные ежечасные файлы меняют имена на имена двух измерений времени. Таким образом, AggregationExisting не может найти имя измерения «время» для определенных файлов, например в переменной u-component_of_wind_isobaric в файле 0300, потому что вместо этого было объявлено time1.

Код, который я звоню:

List<String> variableNames = Arrays.asList("u-component_of_wind_isobaric","u-component_of_wind_height_above_ground","v-component_of_wind_isobaric","v-component_of_wind_height_above_ground","Pressure_reduced_to_MSL_msl","Geopotential_height_isobaric");
NetcdfDataset netcdfDataset = new NetcdfDataset();
//here i'm trying to aggregate on a dimension called 'time'
AggregationExisting aggregationExisting = new AggregationExisting(netcdfDataset, "time", null);
aggregationExisting.addDatasetScan(null,
                   "/cfsr-gribs/201612/",
                    "G4.grib2",
                    null,
                    null,
                    NetcdfDataset.getDefaultEnhanceMode(),
                    "false",
                    null);
aggregationExisting.persistWrite();
aggregationExisting.finish(new CancelTaskImpl());
GridDataset gridDataset = new GridDataset(netcdfDataset);
writer.setRedefineMode(true);
CFGridWriter2.writeFile(gridDataset, variableNames, gridDataset.getBoundingBox(), null, 1, null, null, 1, true, writer);

Проблема с именем измерения времени проиллюстрирована в 2 файлах:

//cdas_20161215_0000_f00300_G4.grib2

float u-component_of_wind_isobaric(time1=1, isobaric3=37, lat=361, lon=720);
  :long_name = "u-component of wind @ Isobaric surface";
  :units = "m/s";
  :abbreviation = "UGRD";
  :missing_value = NaNf; // float
  :grid_mapping = "LatLon_Projection";
  :coordinates = "reftime time1 isobaric3 lat lon ";
  :Grib_Variable_Id = "VAR_0-2-2_L100";
  :Grib2_Parameter = 0, 2, 2; // int
  :Grib2_Parameter_Discipline = "Meteorological products";
  :Grib2_Parameter_Category = "Momentum";
  :Grib2_Parameter_Name = "u-component of wind";
  :Grib2_Level_Type = "Isobaric surface";
  :Grib2_Generating_Process_Type = "Forecast";


//cdas_20161215_0000_f00200_G4.grib2

float u-component_of_wind_isobaric(time=1, isobaric3=37, lat=361, lon=720);
  :long_name = "u-component of wind @ Isobaric surface";
  :units = "m/s";
  :abbreviation = "UGRD";
  :missing_value = NaNf; // float
  :grid_mapping = "LatLon_Projection";
  :coordinates = "reftime time isobaric3 lat lon ";
  :Grib_Variable_Id = "VAR_0-2-2_L100";
  :Grib2_Parameter = 0, 2, 2; // int
  :Grib2_Parameter_Discipline = "Meteorological products";
  :Grib2_Parameter_Category = "Momentum";
  :Grib2_Parameter_Name = "u-component of wind";
  :Grib2_Level_Type = "Isobaric surface";
  :Grib2_Generating_Process_Type = "Forecast";

Это мое первое использование библиотеки NetCDF, поэтому я покупаю некоторые инструменты предварительной обработки, чтобы объединить эти наборы данных с этой особенностью. Могу ли я, например, переместить все переменные в одно измерение времени и переименовать его? Была бы полезна даже ссылка на пример, который я пропустил. В противном случае я предполагаю, что я займусь удалением размеров вручную и использованием readDataSlice () для ручного копирования данных в новый объединенный файл.


person Tom H    schedule 05.01.2017    source источник


Ответы (2)


Если вы заинтересованы в использовании инструментов, отличных от Java, я рекомендую проверить NCO.

Во-первых, вам нужно преобразовать grib в netcdf, возможно, используя wgrib2 (пример преобразования находится здесь) или ncl_convert2nc.

Во-вторых, вы можете разработать простой сценарий, который просматривает рассматриваемые файлы netcdf, проверяет, существует ли time1 в качестве имени измерения, и если да, то измените имя на time. Инструмент унтер-офицера ncrename может сделать это:

ncrename -d time1,time file.nc file.nc 

В-третьих, убедитесь, что time (который теперь должен существовать во всех файлах) является измерением записи. Если нет, давайте сделаем это с помощью инструмента NCO ncks:

ncks --mk_rec_dmn time file.nc 

Наконец, используйте ncrcat NCO для объединения файлов по измерению записи (time):

ncrcat cdas*.nc all_files.nc 

Примечание: вам не обязательно использовать подстановочный знак в строке выше, вы можете просто включить список файлов, которые хотите объединить, например

ncrcat cdas_20161215_0000_f00000_G4.nc cdas_20161215_0000_f00100_G4.nc all_files.nc 
person N1B4    schedule 06.01.2017
comment
Спасибо за ответ! Это будет в конвейере Java, поэтому мне пришлось придерживаться подхода Netcdf-java. - person Tom H; 09.01.2017

Итак, я получил ответ от Ucar, что Grib2 - это другой зверь, который в настоящее время не будет работать с AggregationExisting. Их серверный продукт THREDDS имеет функциональность для файлов Grib2, поэтому это несколько разных классов, например GribCollectionImmutable.

Вот что они рекомендовали для этого подхода, который отлично сработал для меня:

        List<String> variableNames = Arrays.asList("u-component_of_wind_isobaric","u-component_of_wind_height_above_ground","v-component_of_wind_isobaric","v-component_of_wind_height_above_ground","Pressure_reduced_to_MSL_msl","Geopotential_height_isobaric");
        FeatureCollectionType fcType = FeatureCollectionType.GRIB2;
        Path outputPath = Paths.get("/cfsr/Netcdf4/201612/Cfsr_201612_Monthly.nc");
        String dataDir = "/cfsr-gribs/201612/";
        String spec = dataDir + ".*grib2$";
        String timePartition = "file";
        String dateFormatMark = null;
        String olderThan = null;
        Element innerNcml = null;
        String path = dataDir;
        String name = "cfsr";
        String collectionName = "cfsrCollection";

        //find and configure the folder as a grib collection
        FeatureCollectionConfig fcc = new FeatureCollectionConfig(name, path, fcType, spec,
                collectionName, dateFormatMark, olderThan, timePartition, innerNcml);

        try (GribCollectionImmutable gc = GribCdmIndex.openGribCollection(fcc, null, log)) {
            //had to breakpoint and see the dataset typenames to choose 'TP', could be different for each dataset
            GribCollectionImmutable.Dataset ds = gc.getDatasetByTypeName("TP");
            String fullCollectionIndexFilePath = dataDir + name + ".ncx3";
            // now we open the collection index file, which catalogs all of the grib
            //  records in your collection
            NetcdfDataset ncd = gc.getNetcdfDataset(ds, ds.getGroup(0), fullCollectionIndexFilePath,
                    fcc, null, log);
            try (NetcdfFileWriter writer = NetcdfFileWriter.createNew(NetcdfFileWriter.Version.netcdf4,
                    outputPath.toString(), new Nc4ChunkingDefault())) {
                GridDataset gridDataset = new GridDataset(ncd);
                for (String variableName : variableNames) {
                    GeoGrid grid = gridDataset.findGridByShortName(variableName);
                    //Check that the time dimension is the length you'd expect
                    log.info(String.format("Found grid for : %s = %s, with dimension length %s", variableName, grid != null, grid != null ? grid.getDimension(0).getLength() : 0));
                }
                writer.setRedefineMode(true);
                //write the aggregated variables to my output file
                CFGridWriter2.writeFile(gridDataset, variableNames, gridDataset.getBoundingBox(), null, 1, null, null, 1, true, writer);
            } catch (Exception exc) {
                exc.printStackTrace();
            }
        } catch (IOException e) {
            e.printStackTrace();
        }
person Tom H    schedule 09.01.2017