/* * Copyright 2005-2015 ECMWF. * * This software is licensed under the terms of the Apache Licence Version 2.0 * which can be obtained at http://www.apache.org/licenses/LICENSE-2.0. * * In applying this licence, ECMWF does not waive the privileges and immunities granted to it by * virtue of its status as an intergovernmental organisation nor does it submit to any jurisdiction. */ /* * * Description: Check the geometry of a global GRIB field * with a Gaussian Grid (reduced or regular) * */ #include #include #include #include #include "eccodes.h" #define STR_EQUAL(s1, s2) (strcmp((s1), (s2)) == 0) int exit_on_error = 1; /* By default exit if any check fails */ int error_count = 0; int DBL_EQUAL(double d1, double d2, double tolerance) { return fabs(d1-d2) <= tolerance; } void usage(const char* prog) { printf("usage: %s [-f] grib_file grib_file ...\n\n",prog); printf("-f Do not exit on first error\n"); exit(1); } /* Print an error message and die */ void error(const char* fmt, ...) { va_list list; va_start(list,fmt); vfprintf(stderr, fmt, list); va_end(list); ++error_count; if (exit_on_error) { exit(1); } } double get_precision(long edition) { if (edition == 1) return 1.0/1000.0; /* milli degrees */ if (edition == 2) return 1.0/1000000.0; /* micro degrees */ assert(!"Invalid edition"); return 0.0; } int process_file(const char* filename) { int err = 0, msg_num = 0; codes_handle *h = NULL; FILE* in = fopen(filename, "r"); if(!in) { error("ERROR: unable to open input file %s\n",filename); } printf("Checking file %s\n", filename); while ((h = codes_handle_new_from_file(0,in,&err)) != NULL ) { int is_reduced = 0, is_regular = 0, grid_ok = 0; long edition = 0, N = 0, Nj = 0, numberOfDataPoints; size_t len = 0, numberOfValues = 0; double *lats = NULL; long *pl = NULL; char gridType[32] = {0,}; double angular_tolerance, lat1, lon1, lat2, lon2, expected_lon2; double iDirectionIncrementInDegrees; if (err != CODES_SUCCESS) CODES_CHECK(err,0); ++msg_num; printf("\tProcessing GRIB message #%d\n", msg_num); len = 32; CODES_CHECK(codes_get_string(h,"gridType",gridType,&len),0); is_regular = STR_EQUAL(gridType, "regular_gg"); is_reduced = STR_EQUAL(gridType, "reduced_gg"); grid_ok = is_regular || is_reduced; if( !grid_ok ) { /*error("ERROR: gridType should be Reduced or Regular Gaussian Grid!\n");*/ printf("\tWARNING: gridType should be Reduced or Regular Gaussian Grid! Ignoring\n"); codes_handle_delete(h); continue; } CODES_CHECK(codes_get_long(h,"edition",&edition),0); CODES_CHECK(codes_get_long(h,"N",&N),0); CODES_CHECK(codes_get_long(h,"Nj",&Nj),0); CODES_CHECK(codes_get_long(h,"numberOfDataPoints",&numberOfDataPoints),0); CODES_CHECK(codes_get_double(h,"latitudeOfFirstGridPointInDegrees", &lat1),0); CODES_CHECK(codes_get_double(h,"longitudeOfFirstGridPointInDegrees",&lon1),0); CODES_CHECK(codes_get_double(h,"latitudeOfLastGridPointInDegrees", &lat2),0); CODES_CHECK(codes_get_double(h,"longitudeOfLastGridPointInDegrees", &lon2),0); CODES_CHECK(codes_get_double(h,"iDirectionIncrementInDegrees",&iDirectionIncrementInDegrees),0); angular_tolerance = get_precision(edition); if ( Nj != 2*N ) { error("ERROR: Nj is %ld but should be 2*N (%ld)!\n", Nj, 2*N); } if (lon1 != 0) { error("ERROR: latitudeOfFirstGridPointInDegrees=%f but should be 0!\n", lon1); } expected_lon2 = 360.0 - 90.0/N; if (fabs(lon2 - expected_lon2) > angular_tolerance) { error("ERROR: longitudeOfLastGridPointInDegrees=%f but should be %f!\n", lon2, expected_lon2); } /* Check first and last latitudes */ if (lat1 != -lat2) { error("First latitude must be = last latitude but opposite in sign: lat1=%f, lat2=%f\n", lat1, lat2); } lats = (double*)malloc(sizeof(double)*Nj); CODES_CHECK(codes_get_gaussian_latitudes(N,lats), 0); if (!DBL_EQUAL(lats[0], lat1, angular_tolerance)) { error("First latitude %f must be %f\n", lat1, lats[0]); } if (!DBL_EQUAL(lats[Nj-1], lat2, angular_tolerance)) { error("Last latitude %f must be %f\n", lat2, lats[Nj-1]); } if (is_reduced) { int pl_sum = 0; size_t i = 0, pl_len = 0; int is_missing = codes_is_missing(h, "Ni", &err); assert(err == CODES_SUCCESS); if (!is_missing) { error("ERROR: Ni should be missing!\n"); } CODES_CHECK(codes_get_size(h, "pl", &pl_len),0); if (pl_len != 2*N) { error("ERROR: Length of pl array is %ld but should be 2*N (%ld)!\n", pl_len, 2*N); } pl = (long*)malloc(pl_len*sizeof(long)); assert(pl); CODES_CHECK(codes_get_long_array(h, "pl", pl, &pl_len),0); /* Check pl is symmetric */ for(i=0; i