1 /**************************************************************************
2 * Todd Hutchinson 4/20/98
3 * tahutchinson@tasc.com (781) 942-2000 x3108
5 * 55 Walkers Brook Drive
8 * Functions in this file are used for decoding grib data. Please see the
9 * headers before each function for a full descrption.
11 * Routines in this file call functions in the Naval Research Lab's grib
12 * library. The grib library is freely available from
13 * http://www-mel.nrlmry.navy.mil/cgi-bin/order_grib. This library should
14 * be installed on your system prior to using the routines in this file.
15 * Documentation for this library is available from
16 * Master Environmental Grib Library user's manual
17 * http://mel.dmso.mil/docs/grib.pdf
18 * Note: the standard NRL grib library does not support
19 * "Little-Endian" platforms such as linux. There is a version of the NRL
20 * grib library within the WxPredictor project which does support linux.
22 * This file references the cfortran.h header file to ease the use of calling
23 * this function from a fortran routine. cfortran.h is a header file that
24 * allows for simple machine-independent calls between c and fortran. The
25 * package is available via anonymous ftp at zebra.desy.de.
27 * The grib document "A GUIDE TO THE CODE FORM FM 92-IX Ext. GRIB" may be
28 * useful to your understanding of this code. This document is available
29 * via anonymous ftp from nic.fb4.noaa.gov. Check the readme file in the
30 * root directory for further instructions.
32 ****************************************************************************/
38 #define EARTH_RADIUS 6371.229 /* in km */
39 #define PI 3.141592654
40 #define PI_OVER_180 PI/180.
49 #include "gribfuncs.h"
50 #include "gribsize.incl"
51 #include "read_grib.h"
60 /* Function Declarations */
62 void remove_element(int array
[],int index
, int size
);
63 int advance_time(int *century
, int year
, int month
, int day
, int hour
,
64 int amount
, int unit
);
65 char *advance_time_str(char startdatein
[], int amount
, char enddate
[]);
66 int date_diff(int date1
,int century1
,int date2
,int century2
);
67 int hours_since_1900(int date
,int century
);
68 int isLeapYear(int year
);
69 int get_factor2(int unit
);
70 int compare_record(GribInfo
*gribinfo
, FindGrib
*findgrib
, int gribnum
);
73 *These lines allow fortran routines to call the c routines. They are
74 * used by macros defined in cfortran.h
76 #define get_pressure_levels_STRV_A1 TERM_CHARS(' ',1)
78 FCALLSCFUN6(INT, get_pressure_levels,GET_PRESSURE_LEVELS,
79 get_pressure_levels,STRINGV,INTV,INTV,INTV,INT,INT)
80 #define setup_gribinfo_STRV_A1 TERM_CHARS(' ',1)
81 FCALLSCFUN2(INT,setup_gribinfo,SETUP_GRIBINFO,setup_gribinfo,STRINGV,INT)
82 #define get_msl_indices_STRV_A1 TERM_CHARS(' ',1)
83 FCALLSCFUN9(INT, get_msl_indices,GET_MSL_INDICES,get_msl_indices,
84 STRINGV,INTV,INTV,INTV,INTV,INTV,INT,INTV,INTV)
85 FCALLSCFUN5(INT, get_index,GET_INDEX,get_index,INT,INT,INT,INT,INT)
86 #define read_grib_STRV_A1 TERM_CHARS(' ',1)
87 FCALLSCFUN7(INT,get_dates,GET_DATES,get_dates,INTV,INTV,INTV,INT,INTV,
89 FCALLSCFUN7(INT, read_grib,READ_GRIB,read_grib,
90 STRINGV,INT,INT,INT,INT,FLOATVV,PVOID)
91 FCALLSCFUN8(INT, get_index_near_date,GET_INDEX_NEAR_DATE,get_index_near_date,
92 STRING,INT,INT,INT,INTV,INTV,INTV,INT)
94 /* The value for usLevel_id for isobaric levels */
95 #define ISOBARIC_LEVEL_ID 100
97 /*************************************************************************
98 * This function reads and decodes grib records in a list of input files
99 * and stores information about each grib record in the gribinfo array
100 * structure. The gribinfo structure can then be accessed by any function
105 * gribinfo - pointer to a previously allocated gribinfo structure. The
106 * gribinfo structure is filled in this function.
107 * files - a string array containing the names of the files containing
108 * the grib data. If called from a fortran routine, the
109 * fortran routine must set the character size of the array to
110 * be STRINGSIZE-1. The last filled element in the array should
112 * use_fcst - if TRUE, forecast fields will be included in the gribinfo
113 * structure, otherwise, only analysis fields will be included.
116 * 1 - successful call to setup_gribinfo
117 * -1 - call to setup_gribinfo failed
119 ***************************************************************************/
121 int rg_setup_gribinfo(GribInfo
*gribinfo
, char files
[][STRINGSIZE
],
131 /* Loop through input files */
133 while ((strcmp(files
[filenum
], "end") != 0 ) &&
134 (strcmp(files
[filenum
], "END") != 0 )) {
137 * This forces gribinfo to be fully initialized.
141 gribinfo
->num_elements
= 0;
144 start_elem
= gribinfo
->num_elements
;
146 fp
= fopen(files
[filenum
],"r");
149 fprintf(stderr
,"Could not open %s\n",files
[filenum
]);
154 status
= rg_setup_gribinfo_f(gribinfo
, fp
, use_fcst
);
158 "rg_setup_gribinfo_f returned non-zero status (%d), skipping %s\n",
159 status
,files
[filenum
]);
163 for (idx
=start_elem
; idx
< gribinfo
->num_elements
; idx
++)
165 strcpy(gribinfo
->elements
[idx
].filename
,
179 /*************************************************************************
181 * Similar to rg_setup_gribinfo, except, a unix file descriptor is passed in,
182 * rather than a list of files to open.
184 *************************************************************************/
186 int rg_setup_gribinfo_i(GribInfo
*gribinfo
, int fid
, int use_fcst
)
191 fp
= fdopen(fid
,"r");
194 fprintf(stderr
,"Could not open file descriptor %d\n",fid
);
199 /* This forces gribinfo to be initialized for the first time */
200 gribinfo
->num_elements
= 0;
202 status
= rg_setup_gribinfo_f(gribinfo
, fp
, use_fcst
);
206 "rg_setup_gribinfo_f returned non-zero status (%d)\n",
213 /*************************************************************************
215 * Similar to rg_setup_gribinfo, except, a file pointer is passed in, rather
216 * than a list of files to open.
218 * If gribinfo->num_elements is 0, gribinfo is initialized, otherwise,
219 * gribinfo is appended to.
221 *************************************************************************/
223 int rg_setup_gribinfo_f(GribInfo
*gribinfo
, FILE *fp
, int use_fcst
)
225 char errmsg
[ERRSIZE
];
238 /* Set the number of elements to be zero initially */
239 if (gribinfo
->num_elements
<= 0)
241 /* Allocate space for gribinfo */
242 gribinfo
->elements
= (Elements
*)calloc(ALLOCSIZE
,sizeof(Elements
));
243 if (gribinfo
->elements
== NULL
) {
244 sprintf(errmsg
,"Could not allocate %d bytes for gribinfo->elements\n",
245 ALLOCSIZE
*sizeof(Elements
));
250 /* Make storage for Grib Header */
251 nReturn
= init_gribhdr(&gh1
, errmsg
);
253 * The grib library is setup such that, when init_gribhdr == 0, it was
254 * successful. If it is 1, it failed.
256 if (nReturn
== 1) goto bail_out
;
258 /* Scan through message */
259 for (offset
= 0L; nReturn
== 0; offset
+= gh1
->msg_length
) {
260 if ((gribinfo
->num_elements
> 0) &&
261 (gribinfo
->num_elements
%ALLOCSIZE
== 0))
263 (Elements
*)realloc(gribinfo
->elements
,
264 (gribinfo
->num_elements
+ALLOCSIZE
)*
267 if (gribinfo
->elements
== NULL
) {
268 sprintf(errmsg
,"Could not allocate %d bytes for gribinfo\n",
269 (gribinfo
->num_elements
+ ALLOCSIZE
)*sizeof(Elements
));
273 /* Setup the File pointer */
274 gribinfo
->elements
[gribinfo
->num_elements
].fp
= fp
;
276 gribinfo
->elements
[gribinfo
->num_elements
].pds
=
277 (PDS_INPUT
*)malloc(1*sizeof(PDS_INPUT
));
278 gribinfo
->elements
[gribinfo
->num_elements
].gds
=
279 (grid_desc_sec
*)malloc(1*sizeof(grid_desc_sec
));
280 gribinfo
->elements
[gribinfo
->num_elements
].bms
=
281 (BMS_INPUT
*)malloc(1*sizeof(BMS_INPUT
));
282 gribinfo
->elements
[gribinfo
->num_elements
].bds_head
=
283 (BDS_HEAD_INPUT
*)malloc(1*sizeof(BDS_HEAD_INPUT
));
286 grib_fseek(fp
,&offset
, Rd_Indexfile
, gh1
, errmsg
);
288 if (nReturn
== 2) break; /* End of file error */
290 fprintf(stderr
, "Grib_fseek returned non zero status (%d)\n",
295 if (errmsg
[0] != '\0')
296 { /* NO errors but got a Warning msg from seek */
297 fprintf(stderr
,"%s; Skip Decoding...\n",errmsg
);
299 gh1
->msg_length
= 1L; /* set to 1 to bump offset up */
303 if (gh1
->msg_length
< 0) {
304 fprintf(stderr
, "Error: message returned had bad length (%ld)\n",
308 else if (gh1
->msg_length
== 0) {
309 fprintf(stderr
, "msg_length is Zero\n");
310 gh1
->msg_length
= 1L;
313 init_dec_struct(gribinfo
->elements
[gribinfo
->num_elements
].pds
,
314 gribinfo
->elements
[gribinfo
->num_elements
].gds
,
315 gribinfo
->elements
[gribinfo
->num_elements
].bms
,
316 gribinfo
->elements
[gribinfo
->num_elements
].bds_head
);
319 * gribgetpds is an undocumented function within the grib library.
320 * gribgetpds grabs the pds section from the grib message without
321 * decoding the entire grib message. The interface is as follows:
322 * first input param: a pointer to the beginning of the pds
324 * second input param: a pointer to a structure which will hold
325 * the pds information
326 * third param: the error message.
328 * If gribgetpds ever fails, it can be replaced with the following
329 * nReturn = grib_dec((char *)gh1->entire_msg, &pds, &gds, &bds_head,
330 * &bms, &grib_data, errmsg);
332 * This will degrade performance since this grib_dec decodes the
333 * entire grib message.
336 nReturn
= gribgetpds((char*)(gh1
->entire_msg
+ 8),
337 gribinfo
->elements
[gribinfo
->num_elements
].pds
,
339 if (nReturn
!= 0) goto bail_out
;
341 /* Get gds if present */
342 if (gribinfo
->elements
[gribinfo
->num_elements
].pds
->usGds_bms_id
>> 7
347 gribinfo
->elements
[gribinfo
->num_elements
].pds
->uslength
),
348 gribinfo
->elements
[gribinfo
->num_elements
].gds
,errmsg
);
349 if (nReturn
!= 0) goto bail_out
;
352 /* Get bms section if present */
353 if (gribinfo
->elements
[gribinfo
->num_elements
].pds
->usGds_bms_id
>> 6
356 fprintf(stderr,"grids with bms section not currently supported\n");
361 gribinfo
->elements
[gribinfo
->num_elements
].usGrid_id
=
362 gribinfo
->elements
[gribinfo
->num_elements
].pds
->usGrid_id
;
363 gribinfo
->elements
[gribinfo
->num_elements
].usParm_id
=
364 gribinfo
->elements
[gribinfo
->num_elements
].pds
->usParm_id
;
365 gribinfo
->elements
[gribinfo
->num_elements
].usLevel_id
=
366 gribinfo
->elements
[gribinfo
->num_elements
].pds
->usLevel_id
;
367 gribinfo
->elements
[gribinfo
->num_elements
].usHeight1
=
368 gribinfo
->elements
[gribinfo
->num_elements
].pds
->usHeight1
;
369 gribinfo
->elements
[gribinfo
->num_elements
].usHeight2
=
370 gribinfo
->elements
[gribinfo
->num_elements
].pds
->usHeight2
;
371 gribinfo
->elements
[gribinfo
->num_elements
].center_id
=
372 gribinfo
->elements
[gribinfo
->num_elements
].pds
->usCenter_id
;
373 gribinfo
->elements
[gribinfo
->num_elements
].parmtbl
=
374 gribinfo
->elements
[gribinfo
->num_elements
].pds
->usParm_tbl
;
375 gribinfo
->elements
[gribinfo
->num_elements
].proc_id
=
376 gribinfo
->elements
[gribinfo
->num_elements
].pds
->usProc_id
;
377 gribinfo
->elements
[gribinfo
->num_elements
].subcenter_id
=
378 gribinfo
->elements
[gribinfo
->num_elements
].pds
->usCenter_sub
;
379 gribinfo
->elements
[gribinfo
->num_elements
].offset
= offset
;
380 gribinfo
->elements
[gribinfo
->num_elements
].end
=
381 offset
+ gh1
->msg_length
- 1;
384 century
= gribinfo
->elements
[gribinfo
->num_elements
].pds
->usCentury
;
386 if (gribinfo
->elements
[gribinfo
->num_elements
].pds
->usTime_range
== 10)
388 fcsttime1
= gribinfo
->elements
[gribinfo
->num_elements
].pds
->usP1
*256 +
389 gribinfo
->elements
[gribinfo
->num_elements
].pds
->usP2
;
392 else if (gribinfo
->elements
[gribinfo
->num_elements
].pds
->usTime_range
394 /* This is the WSI extension to grib. 203 indicates "duration" */
395 fcsttime1
= gribinfo
->elements
[gribinfo
->num_elements
].pds
->usP1
;
396 fcsttime2
= gribinfo
->elements
[gribinfo
->num_elements
].pds
->usP1
+
397 gribinfo
->elements
[gribinfo
->num_elements
].pds
->usP2
;
399 fcsttime1
= gribinfo
->elements
[gribinfo
->num_elements
].pds
->usP1
;
400 fcsttime2
= gribinfo
->elements
[gribinfo
->num_elements
].pds
->usP2
;
403 gribinfo
->elements
[gribinfo
->num_elements
].date
=
404 advance_time(¢ury
,
405 gribinfo
->elements
[gribinfo
->num_elements
].pds
->usYear
,
406 gribinfo
->elements
[gribinfo
->num_elements
].pds
->usMonth
,
407 gribinfo
->elements
[gribinfo
->num_elements
].pds
->usDay
,
408 gribinfo
->elements
[gribinfo
->num_elements
].pds
->usHour
,
410 gribinfo
->elements
[gribinfo
->num_elements
].pds
->usFcst_unit_id
);
413 gribinfo
->elements
[gribinfo
->num_elements
].date
=
414 gribinfo
->elements
[gribinfo
->num_elements
].pds
->usHour
*1 +
415 gribinfo
->elements
[gribinfo
->num_elements
].pds
->usDay
*100 +
416 gribinfo
->elements
[gribinfo
->num_elements
].pds
->usMonth
*10000 +
417 gribinfo
->elements
[gribinfo
->num_elements
].pds
->usYear
*1000000;
419 gribinfo
->elements
[gribinfo
->num_elements
].century
=
420 gribinfo
->elements
[gribinfo
->num_elements
].pds
->usCentury
;
423 (gribinfo
->elements
[gribinfo
->num_elements
].pds
->usCentury
- 1) * 100
424 + gribinfo
->elements
[gribinfo
->num_elements
].pds
->usYear
;
426 sprintf(gribinfo
->elements
[gribinfo
->num_elements
].initdate
,
427 "%04d%02d%02d%02d%02d%02d",
429 gribinfo
->elements
[gribinfo
->num_elements
].pds
->usMonth
,
430 gribinfo
->elements
[gribinfo
->num_elements
].pds
->usDay
,
431 gribinfo
->elements
[gribinfo
->num_elements
].pds
->usHour
,
432 gribinfo
->elements
[gribinfo
->num_elements
].pds
->usMinute
,
436 get_factor2(gribinfo
->elements
[gribinfo
->num_elements
].pds
->usFcst_unit_id
);
437 gribinfo
->elements
[gribinfo
->num_elements
].fcsttime1
=
439 gribinfo
->elements
[gribinfo
->num_elements
].fcsttime2
=
442 advance_time_str(gribinfo
->elements
[gribinfo
->num_elements
].initdate
,
443 gribinfo
->elements
[gribinfo
->num_elements
].fcsttime1
,
444 gribinfo
->elements
[gribinfo
->num_elements
].valid_time
);
446 gribinfo
->num_elements
++;
452 /* The error condition */
454 if (errmsg
[0] != '\0') fprintf(stderr
,"\n***ERROR: %s: %s\n",
455 "setup_grib",errmsg
);
456 if (gribinfo
->elements
!= NULL
) free(gribinfo
->elements
);
457 perror("System Error ");
461 /*****************************************************************************
463 * Retrieve pressure levels from grib data. This function will pass the
464 * pressure levels for which the input parameter is available at all input
465 * times back to the calling routine.
469 * gribinfo - pointer to a previously allocated gribinfo structure.
470 * The gribinfo structure is filled in this function.
471 * dates: an array of dates to check for data
473 * If called from a fortran routine, the fortran routine must
474 * set the character size of the array to be STRINGSIZE-1
475 * centuries: an array holding the centuries for each of the
476 * dates in the array dates.
477 * parm_id: the input parameter id. From table 2 of the grib manual.
479 * finallevels: an array of pressure levels which are contained in
480 * the grib data at all input times.
482 * the number of levels in the levels array. The levels are listing
483 * in descending (by value) order, i.e., the value with the highest
484 * pressure (lowest vertical level) is the first element.
486 ****************************************************************************/
488 int rg_get_pressure_levels(GribInfo
*gribinfo
, int dates
[], int centuries
[],
489 int parm_id
[], int finallevels
[],int min_pres
,
499 int numfinallevels
= 0;
504 levelnum
= (int *)calloc(numparms
,sizeof(int));
505 tmplevels
= (int **)calloc(numparms
,sizeof(int *));
506 for (j
= 0; j
< numparms
; j
++) {
507 tmplevels
[j
] = (int *)calloc(1000,sizeof(int));
508 if (tmplevels
[j
] == NULL
) {
513 if ((levelnum
== NULL
) || (tmplevels
== NULL
)) {
515 "get_pressure_levels: Allocation of space failed, returning\n");
519 /* Loop through all parameters */
520 for (parmnum
= 0; parmnum
< numparms
; parmnum
++) {
522 levelnum
[parmnum
] = 0;
524 /* Get the array of pressure levels available at the first input time */
526 for (gribnum
= 0; gribnum
< gribinfo
->num_elements
; gribnum
++) {
527 if (gribinfo
->elements
[gribnum
].date
== dates
[datenum
]) {
528 if (gribinfo
->elements
[gribnum
].century
== centuries
[datenum
]) {
529 if (gribinfo
->elements
[gribnum
].usLevel_id
== ISOBARIC_LEVEL_ID
) {
530 if (gribinfo
->elements
[gribnum
].usParm_id
== parm_id
[parmnum
]) {
531 if (gribinfo
->elements
[gribnum
].usHeight1
>= min_pres
) {
533 for (j
=0; j
< levelnum
[parmnum
]; j
++) {
534 if (tmplevels
[parmnum
][j
] ==
535 gribinfo
->elements
[gribnum
].usHeight1
) {
540 if (levelincluded
== 0) {
541 tmplevels
[parmnum
][levelnum
[parmnum
]] =
542 gribinfo
->elements
[gribnum
].usHeight1
;
552 /* Remove levels that are not contained at all subsequent times */
554 while (dates
[datenum
] != -99){
555 for (j
= 0; j
< levelnum
[parmnum
]; j
++) {
557 for (gribnum
= 0; gribnum
< gribinfo
->num_elements
; gribnum
++) {
558 if (gribinfo
->elements
[gribnum
].date
== dates
[datenum
]) {
559 if (gribinfo
->elements
[gribnum
].century
== centuries
[datenum
]) {
560 if (gribinfo
->elements
[gribnum
].usLevel_id
== ISOBARIC_LEVEL_ID
)
562 if (gribinfo
->elements
[gribnum
].usParm_id
==
564 if (tmplevels
[parmnum
][j
] ==
565 gribinfo
->elements
[gribnum
].usHeight1
)
572 if (!(contains_level
)) {
573 remove_element(tmplevels
[parmnum
],j
,levelnum
[parmnum
]);
582 * Put the values for levels into an array. Remove any levels that
583 * were not found at all other levels
586 for (j
= 0; j
< levelnum
[parmnum
]; j
++) {
587 finallevels
[j
] = tmplevels
[parmnum
][j
];
591 for (i
=0; i
<numfinallevels
; i
++) {
593 for (j
=0; j
<levelnum
[parmnum
]; j
++) {
594 if (finallevels
[i
] == tmplevels
[parmnum
][j
]) {
599 if (!contains_level
) {
600 remove_element(finallevels
,i
,numfinallevels
);
610 * Sort the numfinallevels array into descending order. Use straight
613 for (j
=1; j
<numfinallevels
; j
++) {
614 tmpval
= finallevels
[j
];
615 for (i
=j
-1; i
>= 0; i
--) {
616 if (finallevels
[i
] >= tmpval
) break;
617 finallevels
[i
+1] = finallevels
[i
];
619 finallevels
[i
+1] = tmpval
;
622 return numfinallevels
;
625 /****************************************************************************
627 * Returns an array of grib indices that correspond to particular grib fields
628 * to use as sea level pressure. There will be exactly one element for each
629 * input time. If a field was not found, then this function returns NULL
633 * gribinfo - pointer to a previously allocated gribinfo structure. The
634 * gribinfo structure is filled in this function.
635 * dates: a string array of dates to check for data.
637 * If called from a fortran routine, the fortran routine must
638 * set the character size of the array to be STRINGSIZE-1
639 * centuries: an array holding the centuries for each of the
640 * dates in the array dates.
641 * usParm_id: an array of parameter identifiers that could be
642 * used as a sea level pressure field (From table 2 of
643 * grib documentation)
644 * usLevel_id: the level id that could be used as a sea level pressure
645 * field (from table 3 of the grib documentation)
646 * usHeight1: the height for the particular parameter and level
647 * (in units described by the parameter index)
648 * numparms: the number of parameters in each of the usParm_id,
649 * usLevel_id, and usHeight1 arrays.
651 * grib_index: an array of grib indices to use for the sea level
652 * pressure. The index to grib_index corresponds to
653 * the time, i.e., the first array element of grib_index
654 * corresponds to the first time, the second element to
655 * the second time, etc.
657 * Note: Values in the input arrays, usParm_id, usLevel_id, and
658 * usHeight with the same array index must correspond.
662 * -1 if no field was found.
663 ***************************************************************************/
665 int rg_get_msl_indices(GribInfo
*gribinfo
, char dates
[][STRINGSIZE
],
666 int centuries
[], int usParm_id
[],int usLevel_id
[],
667 int usHeight1
[],int infactor
[],int numparms
,
668 int grib_index
[],int outfactor
[])
675 for (parmindex
= 0; parmindex
< numparms
; parmindex
++) {
678 while ((strcmp(dates
[datenum
], "end") != 0 ) &&
679 (strcmp(dates
[datenum
], "END") != 0 )) {
681 for (gribnum
= 0; gribnum
< gribinfo
->num_elements
; gribnum
++) {
682 if (gribinfo
->elements
[gribnum
].date
== atoi(dates
[datenum
])) {
683 if (gribinfo
->elements
[gribnum
].century
== centuries
[datenum
]) {
684 if ((gribinfo
->elements
[gribnum
].usParm_id
==
685 usParm_id
[parmindex
]) &&
686 (gribinfo
->elements
[gribnum
].usLevel_id
==
687 usLevel_id
[parmindex
]) &&
688 (gribinfo
->elements
[gribnum
].usHeight1
==
689 usHeight1
[parmindex
])) {
690 grib_index
[datenum
] = gribnum
;
691 outfactor
[datenum
] = infactor
[parmindex
];
702 * Break out of loop and continue on to next parameter if the current
703 * parameter was missing from a date.
706 if (foundfield
!= datenum
) break;
710 * Break out of the parameter loop once we've found a field available at all
713 if (foundfield
== datenum
) {
719 if (foundfield
== datenum
)
727 /***************************************************************************
729 * This function takes an index as input and returns a 2d grib data field
733 * gribinfo - pointer to a previously allocated gribinfo structure. The
734 * gribinfo structure is filled in this function.
735 * index - the index of gribinfo for which data is to be retrieved
736 * scale - the scale factor to multiply data by, i.e., if -2,
737 * data will be multiplied by 10^-2.
739 * grib_out - the 2 dimensional output grib data
740 * Warning: This 2d array is setup with i being the vertical
741 * dimension and j being the horizontal dimension. This
742 * is the convention used in mesoscale numerical modeling
743 * (the MM5 in particular), so it is used here.
747 ***************************************************************************/
749 int rg_get_grib(GribInfo
*gribinfo
, int index
,int scale
,
750 float **grib_out
,int *vect_comp_flag
,
751 GRIB_PROJECTION_INFO_DEF
*Proj
, BDS_HEAD_INPUT
*bds_head
)
753 char errmsg
[ERRSIZE
];
759 BDS_HEAD_INPUT dummy
;
766 /* Initialize Variables */
769 grib_data
= (float *)NULL
;
771 /* Make storage for Grib Header */
772 nReturn
= init_gribhdr (&gh1
, errmsg
);
773 if (nReturn
== 1) goto bail_out
;
775 /* Seek to the position in the grib data */
776 offset
= gribinfo
->elements
[index
].offset
;
777 nReturn
= grib_fseek(gribinfo
->elements
[index
].fp
,&offset
,
778 Rd_Indexfile
,gh1
,errmsg
);
780 fprintf(stderr
,"Grib_fseek returned error status (%d)\n",nReturn
);
783 if (errmsg
[0] != '\0')
784 { /* NO errors but got a Warning msg from seek */
785 fprintf(stderr
,"%s: Skip Decoding...\n",errmsg
);
788 if (gh1
->msg_length
<= 0) {
789 fprintf(stderr
,"Error: message returned had bad length (%ld)\n",
793 init_dec_struct(&pds
, &gds
, &bms
, &dummy
);
795 nReturn
= grib_dec((char *)gh1
->entire_msg
, &pds
, &gds
,
797 &bms
, &grib_data
, errmsg
);
799 if (nReturn
!= 0) goto bail_out
;
801 if (bms
.uslength
> 0) {
802 nReturn
= apply_bitmap(&bms
, &grib_data
, FILL_VALUE
, bds_head
,
804 if (nReturn
!= 0) goto bail_out
;
807 switch(gds
.head
.usData_type
) {
810 strcpy(Proj
->prjnmm
,"latlon");
811 Proj
->colcnt
= gds
.llg
.usNi
;
812 Proj
->rowcnt
= gds
.llg
.usNj
;
813 Proj
->origlat
= gds
.llg
.lLat1
/1000.;
814 Proj
->origlon
= gds
.llg
.lLon1
/1000.;
815 Proj
->xintdis
= (gds
.llg
.iDi
/1000.)*EARTH_RADIUS
*PI_OVER_180
;
816 Proj
->yintdis
= (gds
.llg
.iDj
/1000.)*EARTH_RADIUS
*PI_OVER_180
;
819 if ((gds
.llg
.usRes_flag
>> 3) & 1) *vect_comp_flag
= 1;
820 else *vect_comp_flag
= 0;
822 /* If the grid is a global grid, we want to set the expandlon flag
823 * so that the number of columns in the array is expanded by one and
824 * the first column of data is copied to the last column. This
825 * allows calling routines to interpolate between first and last columns
829 if (gds
.llg
.usNi
*gds
.llg
.iDi
/1000. == 360)
836 strcpy(Proj
->prjnmm
,"mercator");
837 Proj
->colcnt
= gds
.merc
.cols
;
838 Proj
->rowcnt
= gds
.merc
.rows
;
839 Proj
->origlat
= gds
.merc
.first_lat
/1000.;
840 Proj
->origlon
= gds
.merc
.first_lon
/1000.;
841 Proj
->xintdis
= gds
.merc
.lon_inc
/1000.;
842 Proj
->yintdis
= gds
.merc
.lat_inc
/1000.;
843 Proj
->parm1
= gds
.merc
.latin
/1000.;
844 Proj
->parm2
= (gds
.merc
.Lo2
/1000. - Proj
->origlon
)/gds
.merc
.cols
;
845 if ((gds
.merc
.usRes_flag
>> 3) & 1) *vect_comp_flag
= 1;
846 else *vect_comp_flag
= 0;
849 strcpy(Proj
->prjnmm
,"lambert");
850 Proj
->colcnt
= gds
.lam
.iNx
;
851 Proj
->rowcnt
= gds
.lam
.iNy
;
852 Proj
->origlat
= gds
.lam
.lLat1
/1000.;
853 Proj
->origlon
= gds
.lam
.lLon1
/1000.;
854 Proj
->xintdis
= gds
.lam
.ulDx
/1000.;
855 Proj
->yintdis
= gds
.lam
.ulDy
/1000.;
856 Proj
->parm1
= gds
.lam
.lLat_cut1
/1000.;
857 Proj
->parm2
= gds
.lam
.lLat_cut2
/1000.;
858 Proj
->parm3
= gds
.lam
.lLon_orient
/1000.;
859 if ((gds
.lam
.usRes_flag
>> 3) & 1) *vect_comp_flag
= 1;
860 else *vect_comp_flag
= 0;
863 strcpy(Proj
->prjnmm
,"polar_stereo");
864 Proj
->colcnt
= gds
.pol
.usNx
;
865 Proj
->rowcnt
= gds
.pol
.usNy
;
866 Proj
->origlat
= gds
.pol
.lLat1
/1000.;
867 Proj
->origlon
= gds
.pol
.lLon1
/1000.;
868 Proj
->xintdis
= gds
.pol
.ulDx
/1000.;
869 Proj
->yintdis
= gds
.pol
.ulDy
/1000.;
871 Proj
->parm2
= gds
.pol
.lLon_orient
/1000.;
872 if ((gds
.pol
.usRes_flag
>> 3) & 1) *vect_comp_flag
= 1;
873 else *vect_comp_flag
= 0;
876 fprintf(stderr
,"Grid not supported, gds.head.usData_type = %d\n",
877 gds
.head
.usData_type
);
878 fprintf(stderr
,"Exiting\n");
883 strcpy(Proj
->stordsc
,"+y_in_+x");
887 for (j
=0; j
< (Proj
->rowcnt
); j
++) {
888 for (i
=0; i
<(Proj
->colcnt
); i
++) {
889 grib_out
[j
][i
] = grib_data
[i
+j
*Proj
->colcnt
]*pow(10,scale
);
895 for (j
= 0; j
< Proj
->rowcnt
; j
++) {
896 grib_out
[j
][Proj
->colcnt
-1] = grib_out
[j
][0];
901 * You only reach here when there is no error, so return successfully.
906 if (grib_data
!= NULL
) {
913 /* The error condition */
915 if (errmsg
[0] != '\0') fprintf(stderr
,"\n***ERROR: %s %s\n",
917 if (grib_data
!= NULL
)
923 /***************************************************************************
925 * This function takes an index as input and returns a 2d grib data field
929 * gribinfo - pointer to a previously allocated gribinfo structure. The
930 * gribinfo structure is filled in this function.
931 * index - the index of gribinfo for which data is to be retrieved
933 * data - the 2 dimensional output grib data
934 * Warning: This 2d array is setup with i being the vertical
935 * dimension and j being the horizontal dimension. This
936 * is the convention used in mesoscale numerical modeling
937 * (the MM5 in particular), so it is used here.
941 ***************************************************************************/
943 int rg_get_data(GribInfo
*gribinfo
, int index
, float **data
)
950 numrows
= rg_get_numrows(gribinfo
,index
);
951 numcols
= rg_get_numcols(gribinfo
,index
);
953 data_1d
= (float *)calloc(numrows
*numcols
,sizeof(float));
956 fprintf(stderr
,"Allocating space for data_1d failed, index: %d\n",index
);
960 status
= rg_get_data_1d(gribinfo
, index
, data_1d
);
966 for (j
=0; j
< numrows
; j
++) {
967 for (i
=0; i
< numcols
; i
++) {
968 data
[j
][i
] = data_1d
[i
+j
*numcols
];
978 /***************************************************************************
980 * This function takes an index as input and returns a 1d grib data field
984 * gribinfo - pointer to a previously allocated gribinfo structure. The
985 * gribinfo structure is filled in this function.
986 * index - the index of gribinfo for which data is to be retrieved
988 * data - 1 dimensional output grib data
989 * Warning: This 2d array is setup with i being the vertical
990 * dimension and j being the horizontal dimension. This
991 * is the convention used in mesoscale numerical modeling
992 * (the MM5 in particular), so it is used here.
996 ***************************************************************************/
998 int rg_get_data_1d(GribInfo
*gribinfo
, int index
, float *data
)
1000 char errmsg
[ERRSIZE
];
1006 BDS_HEAD_INPUT bds_head
;
1010 int numcols
, numrows
;
1013 /* Initialize Variables */
1016 grib_data
= (float *)NULL
;
1018 /* Make storage for Grib Header */
1019 nReturn
= init_gribhdr (&gh1
, errmsg
);
1020 if (nReturn
== 1) goto bail_out
;
1022 /* Seek to the position in the grib data */
1023 offset
= gribinfo
->elements
[index
].offset
;
1024 nReturn
= grib_fseek(gribinfo
->elements
[index
].fp
,&offset
,
1025 Rd_Indexfile
,gh1
,errmsg
);
1027 fprintf(stderr
,"Grib_fseek returned non-zero status (%d)\n",nReturn
);
1030 if (errmsg
[0] != '\0')
1031 { /* NO errors but got a Warning msg from seek */
1032 fprintf(stderr
,"%s: Skip Decoding...\n",errmsg
);
1035 if (gh1
->msg_length
<= 0) {
1036 fprintf(stderr
,"Error: message returned had bad length (%ld)\n",
1041 init_dec_struct(&pds
, &gds
, &bms
, &bds_head
);
1043 nReturn
= grib_dec((char *)gh1
->entire_msg
, &pds
, &gds
,
1045 &bms
, &grib_data
, errmsg
);
1047 if (nReturn
!= 0) goto bail_out
;
1049 if (bms
.uslength
> 0) {
1050 nReturn
= apply_bitmap(&bms
, &grib_data
, FILL_VALUE
, &bds_head
,
1052 if (nReturn
!= 0) goto bail_out
;
1056 * Copy the data into the permanent array
1058 numcols
= rg_get_numcols(gribinfo
,index
);
1059 numrows
= rg_get_numrows(gribinfo
,index
);
1060 memcpy(data
,grib_data
,numcols
*numrows
*sizeof(float));
1063 * You only reach here when there is no error, so return successfully.
1068 if (grib_data
!= NULL
) {
1075 /* The error condition */
1077 if (errmsg
[0] != '\0') fprintf(stderr
,"\n***ERROR: %s %s\n",
1079 if (grib_data
!= NULL
)
1085 /****************************************************************************
1086 * Returns the index of gribinfo corresponding to the input date, level,
1087 * height, and parameter.
1091 * gribinfo - pointer to a previously populated gribinfo structure.
1092 * initdate - initialization date in the form yyyymmdd[HHMMSS]. If any
1093 * part of HHMMSS is not specified, it will be set to 0.
1094 * parmid - the parameter id in the grib file
1095 * leveltype - the leveltype id from table 3/3a of the grib document.
1096 * level1 - First level of the data in units described by leveltype.
1097 * level2 - Second level of the data in units described by leveltype.
1098 * fcsttime1 - First forecast time in seconds.
1099 * fcsttime2 - Second forecast time in seconds.
1100 * Note: If an input variable is set set to -INT_MAX, then any value
1101 * will be considered a match.
1103 * if >= 0 The index of the gribinfo data that corresponds to the
1105 * if < 0 No field corresponding to the input parms was found.
1107 ***************************************************************************/
1109 int rg_get_index(GribInfo
*gribinfo
, FindGrib
*findgrib
)
1114 for (gribnum
= 0; gribnum
< gribinfo
->num_elements
; gribnum
++) {
1115 if (compare_record(gribinfo
, findgrib
, gribnum
) == 1)
1117 grib_index
= gribnum
;
1125 /****************************************************************************
1126 * Same as rg_get_index, except that a guess for the record number is given.
1127 * This "guess" record is first checked to see if it matches, if so,
1128 * that grib record number is just returned. If it does not match,
1129 * full searching ensues.
1130 * Returns the index of gribinfo corresponding to the input date, level,
1131 * height, and parameter.
1135 * Same is rg_get_index, except:
1136 * guess_index - The index to check first.
1138 * Same as rg_get_index
1140 ***************************************************************************/
1142 int rg_get_index_guess(GribInfo
*gribinfo
, FindGrib
*findgrib
, int guess_index
)
1146 if (compare_record(gribinfo
, findgrib
, guess_index
) == 1) {
1147 retval
= guess_index
;
1149 retval
= rg_get_index(gribinfo
, findgrib
);
1156 /****************************************************************************
1157 * Sets all values in FindGrib to missing.
1161 * findgrib - pointer to a previously allocated findgrib structure.
1167 ***************************************************************************/
1168 int rg_init_findgrib(FindGrib
*findgrib
)
1170 strcpy(findgrib
->initdate
,"*");
1171 strcpy(findgrib
->validdate
,"*");
1172 findgrib
->parmid
= -INT_MAX
;
1173 findgrib
->parmid
= -INT_MAX
;
1174 findgrib
->leveltype
= -INT_MAX
;
1175 findgrib
->level1
= -INT_MAX
;
1176 findgrib
->level2
= -INT_MAX
;
1177 findgrib
->fcsttime1
= -INT_MAX
;
1178 findgrib
->fcsttime2
= -INT_MAX
;
1179 findgrib
->center_id
= -INT_MAX
;
1180 findgrib
->subcenter_id
= -INT_MAX
;
1181 findgrib
->parmtbl_version
= -INT_MAX
;
1186 /****************************************************************************
1187 * Returns the indices of all gribinfo entries that match the input date,
1188 * level, height, and parameter.
1192 * gribinfo - pointer to a previously populated gribinfo structure.
1193 * initdate - initialization date in the form yyyymmdd[HHMMSS]. If any
1194 * part of HHMMSS is not specified, it will be set to 0.
1195 * parmid - the parameter id in the grib file
1196 * leveltype - the leveltype id from table 3/3a of the grib document.
1197 * level1 - First level of the data in units described by leveltype.
1198 * level2 - Second level of the data in units described by leveltype.
1199 * fcsttime1 - First forecast time in seconds.
1200 * fcsttime2 - Second forecast time in seconds.
1201 * indices - an array of indices that match
1202 * num_indices - the number of matches and output indices
1204 * Note: If an input variable is set set to -INT_MAX, then any value
1205 * will be considered a match.
1207 * The number of matching indices.
1209 ***************************************************************************/
1211 int rg_get_indices(GribInfo
*gribinfo
, FindGrib
*findgrib
, int indices
[])
1216 for (gribnum
= 0; gribnum
< gribinfo
->num_elements
; gribnum
++) {
1217 if (compare_record(gribinfo
, findgrib
, gribnum
) == 1) {
1218 indices
[matchnum
] = gribnum
;
1225 /*************************************************************************
1227 * Returns an array of dates that correspond to particular input grib fields.
1228 * The dates will be sorted so that the dates increase as the index increases.
1232 * gribinfo - pointer to a previously allocated gribinfo structure.
1233 * The gribinfo structure is filled in this function.
1234 * usParm_id: an array of parameter identifiers that could be
1235 * used as a sea level pressure field (From table 2 of
1236 * grib documentation)
1237 * usLevel_id: the level id that could be used as a sea level pressure
1238 * field (from table 3 of the grib documentation)
1239 * usHeight1: the height for the particular parameter and level
1240 * (in units described by the parameter index)
1241 * numparms: the number of parameters in each of the usParm_id,
1242 * usLevel_id, and usHeight1 arrays.
1244 * dates: the dates for which the input fields are available.
1246 * Note: Values in the input arrays, usParm_id, usLevel_id, and
1247 * usHeight with the same array index must correspond.
1250 * The number of dates found.
1251 *************************************************************************/
1253 int rg_get_dates(GribInfo
*gribinfo
,int usParm_id
[],int usLevel_id
[],
1254 int usHeight1
[],int numparms
,int dates
[],int century
[],
1260 int already_included
;
1262 int tmpval
,tmpval2
,tmpval3
;
1264 /* Get the dates for the given parameters */
1266 for (parmindex
= 0; parmindex
< numparms
; parmindex
++) {
1267 for (gribnum
= 0; gribnum
< gribinfo
->num_elements
; gribnum
++) {
1268 if ((gribinfo
->elements
[gribnum
].usParm_id
== usParm_id
[parmindex
]) &&
1269 (gribinfo
->elements
[gribnum
].usLevel_id
== usLevel_id
[parmindex
]) &&
1270 (gribinfo
->elements
[gribnum
].usHeight1
== usHeight1
[parmindex
])) {
1271 already_included
= 0;
1272 for (i
= 0; i
< datenum
; i
++){
1273 if ((dates
[datenum
] == gribinfo
->elements
[gribnum
].date
) &&
1274 (century
[datenum
] == gribinfo
->elements
[gribnum
].century
)) {
1275 already_included
= 1;
1279 if (!already_included
) {
1280 dates
[datenum
] = gribinfo
->elements
[gribnum
].date
;
1281 century
[datenum
] = gribinfo
->elements
[gribnum
].century
;
1282 indices
[datenum
] = gribnum
;
1289 /* Sort the dates into increasing order */
1290 for (j
= 1; j
< datenum
; j
++) {
1292 tmpval2
= indices
[j
];
1293 tmpval3
= century
[j
];
1294 for (i
=j
-1; i
>= 0; i
--) {
1295 if (dates
[i
] <= tmpval
) break;
1296 dates
[i
+1] = dates
[i
];
1297 indices
[i
+1] = indices
[i
];
1298 century
[i
+1] = century
[i
];
1300 dates
[i
+1] = tmpval
;
1301 indices
[i
+1] = tmpval2
;
1302 century
[i
+1] = tmpval3
;
1308 /****************************************************************************
1309 * This function returns the pds, gds, bms, and bms_head section of the
1313 * gribinfo - pointer to a previously allocated gribinfo structure. The
1314 * gribinfo structure is filled in this function.
1315 * index - the index of the grib record to access as indexed by
1319 * *pds - a pointer to a structure holding the pds information
1320 * *gds - a pointer to a structure holding the gds information
1321 * *bms - a pointer to a structure holding the bms information
1322 * *bds_head - a pointer to a structure holding the binary data section
1323 * header information
1325 ***************************************************************************
1327 int rg_get_grib_header(GribInfo
*gribinfo
, int index
, PDS_INPUT
*pds
,
1328 grid_desc_sec
*gds
,BMS_INPUT
*bms
)
1332 memcpy(pds
,gribinfo
->elements
[index
].pds
,sizeof(PDS_INPUT
));
1333 memcpy(gds
,gribinfo
->elements
[index
].gds
,sizeof(grid_desc_sec
));
1334 memcpy(bms
,gribinfo
->elements
[index
].bms
,sizeof(BMS_INPUT
));
1336 /* Reset the dimensions for thinned grids */
1337 if (gribinfo
->elements
[index
].gds
->head
.thin
!= NULL
) {
1338 if (gds
->head
.thin
!= NULL
) {
1339 if ((gds
->head
.usData_type
== LATLON_PRJ
) ||
1340 (gds
->head
.usData_type
== GAUSS_PRJ
) ||
1341 (gds
->head
.usData_type
== ROT_LATLON_PRJ
) ||
1342 (gds
->head
.usData_type
== ROT_GAUSS_PRJ
) ||
1343 (gds
->head
.usData_type
== STR_LATLON_PRJ
) ||
1344 (gds
->head
.usData_type
== STR_GAUSS_PRJ
) ||
1345 (gds
->head
.usData_type
== STR_ROT_LATLON_PRJ
) ||
1346 (gds
->head
.usData_type
== STR_ROT_GAUSS_PRJ
)) {
1347 ysize
= gds
->llg
.usNj
;
1348 } else if (gds
->head
.usData_type
== MERC_PRJ
) {
1349 ysize
= gds
->merc
.rows
;
1350 } else if (gds
->head
.usData_type
== POLAR_PRJ
) {
1351 ysize
= gds
->pol
.usNy
;
1352 } else if ((gds
->head
.usData_type
== LAMB_PRJ
) ||
1353 (gds
->head
.usData_type
== ALBERS_PRJ
) ||
1354 (gds
->head
.usData_type
== OBLIQ_LAMB_PRJ
)) {
1355 ysize
= gds
->lam
.iNy
;
1359 for (j
= 0; j
<ysize
; j
++) {
1360 if (gds
->head
.thin
[j
] > xsize
) {
1361 xsize
= gds
->head
.thin
[j
];
1366 if ((gds
->head
.usData_type
== LATLON_PRJ
) ||
1367 (gds
->head
.usData_type
== GAUSS_PRJ
) ||
1368 (gds
->head
.usData_type
== ROT_LATLON_PRJ
) ||
1369 (gds
->head
.usData_type
== ROT_GAUSS_PRJ
) ||
1370 (gds
->head
.usData_type
== STR_LATLON_PRJ
) ||
1371 (gds
->head
.usData_type
== STR_GAUSS_PRJ
) ||
1372 (gds
->head
.usData_type
== STR_ROT_LATLON_PRJ
) ||
1373 (gds
->head
.usData_type
== STR_ROT_GAUSS_PRJ
)) {
1374 gds
->llg
.usNi
= xsize
;
1375 gds
->llg
.iDi
= abs(gds
->llg
.lLat2
- gds
->llg
.lLat1
)/(xsize
-1);
1376 } else if (gds
->head
.usData_type
== MERC_PRJ
) {
1377 gds
->merc
.cols
= xsize
;
1378 } else if (gds
->head
.usData_type
== POLAR_PRJ
) {
1379 gds
->pol
.usNx
= xsize
;
1380 } else if ((gds
->head
.usData_type
== LAMB_PRJ
) ||
1381 (gds
->head
.usData_type
== ALBERS_PRJ
) ||
1382 (gds
->head
.usData_type
== OBLIQ_LAMB_PRJ
)) {
1383 gds
->lam
.iNx
= xsize
;
1391 /****************************************************************************
1392 * This returns the index of the gribdata for paramaters which match the input
1393 * parameters and for the date closest to the input targetdate. If dates are
1394 * not found either within hours_before or hours_after the time, then a missing
1395 * value is returned.
1399 * gribinfo - pointer to a previously allocated gribinfo structure. The
1400 * gribinfo structure is filled in this function.
1401 * targetdate: This is the date which dates in the grib data will be
1402 * compared to. (format: integer yymmddhh)
1403 * hours_before: The maximum difference in time prior to the targetdate
1404 * for which data should be searched for.
1405 * hours_after: The maximum difference in time after the targetdate for
1406 * which data should be searched for.
1407 * usParm_id: an array of parameter identifiers that could be
1408 * used as a sea level pressure field (From table 2 of
1409 * grib documentation)
1410 * usLevel_id: the level id that could be used as a sea level pressure
1411 * field (from table 3 of the grib documentation)
1412 * usHeight1: the height for the particular parameter and level
1413 * (in units described by the parameter index)
1414 * numparms: the number of parameters in each of the usParm_id,
1415 * usLevel_id, and usHeight1 arrays.
1417 * the index of the gribdata with a time closest to the target date.
1418 * -1 if there is no time within the input time limits.
1420 ****************************************************************************/
1421 int rg_get_index_near_date(GribInfo
*gribinfo
,char targetdate
[STRINGSIZE
],
1422 int century
,int hours_before
,int hours_after
,
1423 int usParm_id
[],int usLevel_id
[],int usHeight1
[],
1426 int dates
[500],indices
[500],centuries
[500];
1427 int date_before
= MISSING
;
1428 int date_after
= MISSING
;
1429 int century_before
,century_after
;
1430 int date_diff_before
= MISSING
;
1431 int date_diff_after
= MISSING
;
1432 int index_before
,index_after
;
1433 int numdates
,datenum
;
1437 itargetdate
= atoi(targetdate
);
1439 numdates
= rg_get_dates(gribinfo
,usParm_id
,usLevel_id
,usHeight1
,numparms
,
1440 dates
,centuries
,indices
);
1441 if (numdates
<= 0) {
1442 fprintf(stderr
,"get_index_near_date: No dates were found\n");
1446 for (datenum
= 0; datenum
< numdates
; datenum
++) {
1447 if ((dates
[datenum
] > itargetdate
) && (centuries
[datenum
] >= century
)) {
1448 century_after
= centuries
[datenum
];
1449 date_after
= dates
[datenum
];
1450 index_after
= indices
[datenum
];
1453 century_before
= centuries
[datenum
];
1454 date_before
= dates
[datenum
];
1455 index_before
= indices
[datenum
];
1459 if (date_after
!= MISSING
)
1460 date_diff_after
= date_diff(date_after
,century_after
,itargetdate
,century
);
1461 if (date_before
!= MISSING
)
1463 date_diff(itargetdate
,century
,date_before
,century_before
);
1465 if ((date_after
!= MISSING
) && (date_before
!= MISSING
)) {
1466 if ((date_diff_after
<= hours_after
) &&
1467 (date_diff_before
<= hours_before
)) {
1468 if (date_diff_after
< date_diff_before
)
1469 index
= index_before
;
1471 index
= index_after
;
1472 } else if (date_diff_after
<= hours_after
) {
1473 index
= index_after
;
1474 } else if (date_diff_before
<= hours_before
) {
1475 index
= index_before
;
1479 } else if (date_after
!= MISSING
) {
1480 if (date_diff_after
<= hours_after
)
1481 index
= index_after
;
1484 } else if (date_before
!= MISSING
) {
1485 if (date_diff_before
<= hours_before
)
1486 index
= index_before
;
1497 /*****************************************************************************
1499 * returns valid time ( = init time + forecast time)
1502 * gribinfo - pointer to a previously allocated gribinfo structure. The
1503 * gribinfo structure is filled in this function.
1504 * index - index number of record to get valid time from
1507 * valid_time - yyyymmddhhmmss
1513 *****************************************************************************/
1514 int rg_get_valid_time(GribInfo
*gribinfo
, int index
, char valid_time
[])
1516 strcpy(valid_time
, gribinfo
->elements
[index
].valid_time
);
1520 /*****************************************************************************
1522 * returns generating center id
1525 * gribinfo - pointer to a previously allocated gribinfo structure. The
1526 * gribinfo structure is filled in this function.
1527 * index - index number of record to get valid time from
1530 * generating center id
1533 *****************************************************************************/
1534 int rg_get_center_id(GribInfo
*gribinfo
, int index
)
1536 return gribinfo
->elements
[index
].center_id
;
1539 /*****************************************************************************
1541 * returns parameter table version number
1544 * gribinfo - pointer to a previously allocated gribinfo structure. The
1545 * gribinfo structure is filled in this function.
1546 * index - index number of record to get valid time from
1549 * parameter table version number
1552 *****************************************************************************/
1553 int rg_get_parmtbl(GribInfo
*gribinfo
, int index
)
1555 return gribinfo
->elements
[index
].parmtbl
;
1558 /*****************************************************************************
1560 * returns generating process id
1563 * gribinfo - pointer to a previously allocated gribinfo structure. The
1564 * gribinfo structure is filled in this function.
1565 * index - index number of record to get valid time from
1568 * generating process id
1571 *****************************************************************************/
1572 int rg_get_proc_id(GribInfo
*gribinfo
, int index
)
1574 return gribinfo
->elements
[index
].proc_id
;
1577 /*****************************************************************************
1579 * returns sub center id
1582 * gribinfo - pointer to a previously allocated gribinfo structure. The
1583 * gribinfo structure is filled in this function.
1584 * index - index number of record to get valid time from
1590 *****************************************************************************/
1591 int rg_get_subcenter_id(GribInfo
*gribinfo
, int index
)
1593 return gribinfo
->elements
[index
].subcenter_id
;
1596 /**************************************************************************
1598 * Interpolates grib grid data to a point location.
1602 * gribinfo - pointer to a previously allocated gribinfo structure. The
1603 * gribinfo structure is filled in this function.
1604 * index - the index of gribinfo for which data is to be retrieved.
1605 * the first grib record is number 1.
1606 * column - the column of the point in grid coordinates (can be
1607 * floating point number). leftmost column is 1.
1608 * row - the row of the point in grid coordinates (can be
1609 * floating point number). bottommost row is 1.
1612 * on success - the interpolated value at the column,row location.
1613 * on failure - -99999
1615 ***************************************************************************/
1617 float rg_get_point(GribInfo
*gribinfo
, int index
, float column
, float row
)
1620 GRIB_PROJECTION_INFO_DEF Proj
;
1621 BDS_HEAD_INPUT bds_head
;
1625 int numrows
, numcols
;
1626 int top
, left
, right
, bottom
;
1629 numrows
= rg_get_numrows(gribinfo
, index
);
1630 numcols
= rg_get_numcols(gribinfo
, index
);
1632 grib_out
= (float **)alloc_float_2d(numrows
,numcols
);
1633 if (grib_out
== NULL
) {
1634 fprintf(stderr
,"rg_get_point: Could not allocate space for grib_out\n");
1638 status
= rg_get_data(gribinfo
, index
, grib_out
);
1640 fprintf(stderr
,"rg_get_point: rg_get_data failed\n");
1644 /* Do the interpolation here */
1645 bottom
= floor(row
);
1647 left
= floor(column
);
1648 right
= floor(column
+1);
1650 y1
= (row
- bottom
) * (grib_out
[top
][left
] - grib_out
[bottom
][left
]) +
1651 grib_out
[bottom
][left
];
1652 y2
= (row
- bottom
) * (grib_out
[top
][right
] - grib_out
[bottom
][right
]) +
1653 grib_out
[bottom
][right
];
1654 outval
= (y2
- y1
) * (column
- left
) + y1
;
1656 free_float_2d(grib_out
,numrows
,numcols
);
1662 /**************************************************************************
1664 * Interpolates grib grid data to a point location.
1668 * gribinfo - pointer to a previously allocated gribinfo structure. The
1669 * gribinfo structure is filled in this function.
1670 * index - the index of gribinfo for which data is to be retrieved.
1671 * the first grib record is number 1.
1673 * pointdata- array of pointdata structures. Only the column and
1674 * row values in the structures need to be filled. On
1675 * output, the 'value' member of pointdata is filled.
1677 * numpoints- number of pointdata structures in the array.
1680 * on success - the interpolated value at the column,row location.
1681 * on failure - -99999
1683 ***************************************************************************/
1684 int rg_get_points(GribInfo
*gribinfo
, int index
, PointData pointdata
[],
1690 int numrows
, numcols
;
1691 int top
, left
, right
, bottom
;
1695 numrows
= rg_get_numrows(gribinfo
, index
);
1696 numcols
= rg_get_numcols(gribinfo
, index
);
1698 grib_out
= (float **)alloc_float_2d(numrows
,numcols
);
1699 if (grib_out
== NULL
) {
1700 fprintf(stderr
,"rg_get_points: Could not allocate space for grib_out\n");
1704 status
= rg_get_data(gribinfo
, index
, grib_out
);
1706 fprintf(stderr
,"rg_get_points: rg_get_data failed\n");
1710 for (idx
= 0; idx
< numpoints
; idx
++) {
1712 /* Change from 1 based to 0 based col/row */
1713 row
= pointdata
[idx
].row
;
1714 column
= pointdata
[idx
].column
;
1716 /* Do the interpolation here */
1717 bottom
= floor(row
);
1719 left
= floor(column
);
1720 right
= floor(column
+1);
1722 y1
= (row
- bottom
) * (grib_out
[top
][left
] - grib_out
[bottom
][left
]) +
1723 grib_out
[bottom
][left
];
1724 y2
= (row
- bottom
) * (grib_out
[top
][right
] - grib_out
[bottom
][right
]) +
1725 grib_out
[bottom
][right
];
1726 pointdata
[idx
].value
= (y2
- y1
) * (column
- left
) + y1
;
1730 free_float_2d(grib_out
,numrows
,numcols
);
1735 /**************************************************************************
1737 * Remove an element from an array and decrease, by one, indices of all
1738 * elements with an index greater than the index of the element to remove.
1742 * array - the integer array to manipulate
1743 * index - the index of the element to remove
1744 * size - the number of elements in the array
1746 ***************************************************************************/
1747 void remove_element(int array
[],int index
, int size
)
1751 for (j
= index
; j
< size
-1; j
++) {
1752 array
[j
] = array
[j
+1];
1757 /****************************************************************************
1758 * Advance the time by the input amount
1762 * century - an integer value for the century (20 for 1900's)
1763 * If the century is advanced, this value is advanced
1764 * and output to the calling routine.
1765 * year - a 2 digit value for the year.
1766 * month - a 2 digit value for the month.
1767 * day - the day of the month
1768 * hour - the hour of the day
1769 * amount - the amount to advance the time by.
1770 * unit - the units for the amount. These are values from table 4
1771 * of the grib manual.
1773 * a date in the form yymmddhh
1774 ****************************************************************************/
1776 int advance_time(int *century
, int year
, int month
, int day
, int hour
,
1777 int amount
, int unit
)
1779 int daysinmonth
[] = {31,28,31,30,31,30,31,31,30,31,30,31};
1784 hour
+= (int)((amount
/60.)+0.5);
1817 hour
+= (int)((amount
/12.)+0.5);
1819 hour
+= (int)((amount
/(60.*60.))+0.5);
1822 fprintf(stderr
,"WARNING: Could not advance time, incorrect unit: %d\n",
1827 while (hour
>= 24) {
1831 while (month
> 12) {
1836 /* if it is a leap year, change days in month for Feb now. */
1837 if (isLeapYear(year
)) daysinmonth
[1] = 29;
1839 while (day
> daysinmonth
[month
-1]) {
1840 day
-= daysinmonth
[month
-1];
1845 if (isLeapYear(year
))
1846 daysinmonth
[1] = 29;
1848 daysinmonth
[1] = 28;
1860 date
= hour
*1 + day
*100 + month
*10000 + year
*1000000;
1865 /****************************************************************************
1866 * Advance the time by the input amount
1870 * startdate - initialization date in the form yyyymmdd[HHMMSS]. If any
1871 * part of HHMMSS is not specified, it will be set to 0.
1872 * amount - the amount (in seconds) to advance the time by.
1875 * enddate[] - the time advanced to: yyyymmddHHMMSS format.
1881 ****************************************************************************/
1882 char *advance_time_str(char startdatein
[], int amount
, char enddate
[])
1889 strcpy(startdate
,startdatein
);
1890 while (strlen(startdate
) < 14) {
1891 strcpy(startdate
+(strlen(startdate
)),"0");
1894 /* This forces all calculations to use GMT time */
1898 sscanf(startdate
,"%4d%2d%2d%2d%2d%2d",&(starttp
.tm_year
),&(starttp
.tm_mon
),
1899 &(starttp
.tm_mday
),&(starttp
.tm_hour
),&(starttp
.tm_min
),
1901 starttp
.tm_mon
-= 1;
1902 starttp
.tm_year
-= 1900;
1903 time
= mktime(&starttp
);
1906 localtime_s(&endtp
, &time
);
1908 localtime_r(&time
, &endtp
);
1910 strftime(enddate
,15,"%Y%m%d%H%M%S",&endtp
);
1915 /****************************************************************************
1916 * Returns the difference in time in hours between date1 and date2
1921 * date1,date2: dates in yymmddhh format (integers)
1922 * century1,century2: centuries for each date (20 for 1900's).
1924 * the difference in time between the first and second dates in hours.
1925 ****************************************************************************/
1926 int date_diff(int date1
,int century1
,int date2
,int century2
)
1928 return (hours_since_1900(date1
,century1
) -
1929 hours_since_1900(date2
,century2
));
1932 /****************************************************************************
1933 * Returns the number of hours since Jan 1, at 00:00 1900.
1937 * date: integer in form yymmddhh
1938 * century: 2 digit century (20 for 1900's)
1940 * the number of hours since 00:00 Jan1, 1900.
1942 ****************************************************************************/
1943 int hours_since_1900(int date
,int century
)
1945 int daysinmonth
[] = {31,28,31,30,31,30,31,31,30,31,30,31};
1946 int hour
,day
,month
,year
;
1947 int days_since_1900
= 0;
1951 day
= (date
%10000)/100;
1952 month
= (date
%1000000)/10000;
1953 year
= (date
%100000000)/1000000;
1955 days_since_1900
+= day
;
1957 if (isLeapYear((century
-1)*100 + year
))
1958 daysinmonth
[1] = 29;
1960 daysinmonth
[1] = 28;
1962 for (i
= 0; i
< (month
- 1); i
++)
1963 days_since_1900
+= daysinmonth
[i
];
1965 for (i
=0; i
< (year
+ ((century
- 20)*100) - 1); i
++) {
1966 if (isLeapYear((century
- 1)*100 + year
))
1967 days_since_1900
+= 366;
1969 days_since_1900
+= 365;
1972 return days_since_1900
*24 + hour
;
1976 /****************************************************************************
1978 * Returns true if the input year is a leap year, otherwise returns false
1980 ****************************************************************************/
1981 int isLeapYear(int year
)
1983 if ( (((year
% 4) == 0) && ((year
% 100) != 0))
1984 || ((year
% 400) == 0) )
1991 /*****************************************************************************
1993 * Returns the number of grib elements (gribinfo->num_elements) processsed
1995 * gribinfo - pointer to a previously allocated gribinfo structure. The
1996 * gribinfo structure is filled in this function.
1999 * the number of elements in the gribinfo structure
2000 ****************************************************************************/
2002 int rg_num_elements(GribInfo
*gribinfo
){
2004 return gribinfo
->num_elements
;
2008 /*****************************************************************************
2010 * Deallocates the elements in the gribinfo structure and closes the files.
2013 * gribinfo - pointer to a previously allocated gribinfo structure. The
2014 * gribinfo structure is filled in this function.
2016 *****************************************************************************/
2017 void rg_free_gribinfo_elements(GribInfo
*gribinfo
)
2021 for (i
=0; i
<gribinfo
->num_elements
; i
++) {
2022 free(gribinfo
->elements
[i
].pds
);
2023 free(gribinfo
->elements
[i
].gds
);
2024 free(gribinfo
->elements
[i
].bms
);
2025 free(gribinfo
->elements
[i
].bds_head
);
2026 fclose(gribinfo
->elements
[i
].fp
);
2028 free(gribinfo
->elements
);
2031 /*****************************************************************************
2033 * Returns the value for level1 (gribinfo->usHeight1)
2035 * gribinfo - pointer to a previously allocated gribinfo structure. The
2036 * gribinfo structure is filled in this function.
2040 ****************************************************************************/
2042 int rg_get_level1(GribInfo
*gribinfo
, int index
)
2044 return gribinfo
->elements
[index
].usHeight1
;
2047 /*****************************************************************************
2049 * Returns the value for level2 (gribinfo->usHeight2)
2051 * gribinfo - pointer to a previously allocated gribinfo structure. The
2052 * gribinfo structure is filled in this function.
2056 ****************************************************************************/
2058 int rg_get_level2(GribInfo
*gribinfo
, int index
)
2060 return gribinfo
->elements
[index
].usHeight2
;
2063 /*****************************************************************************
2065 * returns number of rows in grid
2068 * gribinfo - pointer to a previously allocated gribinfo structure. The
2069 * gribinfo structure is filled in this function.
2072 * number of rows in grid
2073 *****************************************************************************/
2074 int rg_get_numrows(GribInfo
*gribinfo
,int index
)
2076 if ((gribinfo
->elements
[index
].gds
->head
.usData_type
== LATLON_PRJ
) ||
2077 (gribinfo
->elements
[index
].gds
->head
.usData_type
== GAUSS_PRJ
) ||
2078 (gribinfo
->elements
[index
].gds
->head
.usData_type
== ROT_LATLON_PRJ
) ||
2079 (gribinfo
->elements
[index
].gds
->head
.usData_type
== ROT_GAUSS_PRJ
) ||
2080 (gribinfo
->elements
[index
].gds
->head
.usData_type
== STR_LATLON_PRJ
) ||
2081 (gribinfo
->elements
[index
].gds
->head
.usData_type
== STR_GAUSS_PRJ
) ||
2082 (gribinfo
->elements
[index
].gds
->head
.usData_type
== STR_ROT_LATLON_PRJ
)||
2083 (gribinfo
->elements
[index
].gds
->head
.usData_type
== STR_ROT_GAUSS_PRJ
))
2085 return gribinfo
->elements
[index
].gds
->llg
.usNj
;
2086 } else if (gribinfo
->elements
[index
].gds
->head
.usData_type
== MERC_PRJ
) {
2087 return gribinfo
->elements
[index
].gds
->merc
.rows
;
2088 } else if (gribinfo
->elements
[index
].gds
->head
.usData_type
== LAMB_PRJ
) {
2089 return gribinfo
->elements
[index
].gds
->lam
.iNy
;
2090 } else if (gribinfo
->elements
[index
].gds
->head
.usData_type
== POLAR_PRJ
) {
2091 return gribinfo
->elements
[index
].gds
->pol
.usNy
;
2095 /*****************************************************************************
2097 * returns number of columns in grid
2100 * gribinfo - pointer to a previously allocated gribinfo structure. The
2101 * gribinfo structure is filled in this function.
2104 * number of columns in grid
2105 *****************************************************************************/
2106 int rg_get_numcols(GribInfo
*gribinfo
,int index
)
2108 if ((gribinfo
->elements
[index
].gds
->head
.usData_type
== LATLON_PRJ
) ||
2109 (gribinfo
->elements
[index
].gds
->head
.usData_type
== GAUSS_PRJ
) ||
2110 (gribinfo
->elements
[index
].gds
->head
.usData_type
== ROT_LATLON_PRJ
) ||
2111 (gribinfo
->elements
[index
].gds
->head
.usData_type
== ROT_GAUSS_PRJ
) ||
2112 (gribinfo
->elements
[index
].gds
->head
.usData_type
== STR_LATLON_PRJ
) ||
2113 (gribinfo
->elements
[index
].gds
->head
.usData_type
== STR_GAUSS_PRJ
) ||
2114 (gribinfo
->elements
[index
].gds
->head
.usData_type
== STR_ROT_LATLON_PRJ
)||
2115 (gribinfo
->elements
[index
].gds
->head
.usData_type
== STR_ROT_GAUSS_PRJ
))
2117 return gribinfo
->elements
[index
].gds
->llg
.usNi
;
2118 } else if (gribinfo
->elements
[index
].gds
->head
.usData_type
== MERC_PRJ
) {
2119 return gribinfo
->elements
[index
].gds
->merc
.cols
;
2120 } else if (gribinfo
->elements
[index
].gds
->head
.usData_type
== LAMB_PRJ
) {
2121 return gribinfo
->elements
[index
].gds
->lam
.iNx
;
2122 } else if (gribinfo
->elements
[index
].gds
->head
.usData_type
== POLAR_PRJ
) {
2123 return gribinfo
->elements
[index
].gds
->pol
.usNx
;
2127 /*****************************************************************************
2129 * returns the offset (in bytes) from the beginning of the file.
2132 * gribinfo - pointer to a filled gribinfo structure.
2135 * offset (in bytes) from beginning of file
2136 *****************************************************************************/
2137 int rg_get_offset(GribInfo
*gribinfo
,int index
)
2139 return gribinfo
->elements
[index
].offset
;
2141 /*****************************************************************************
2143 * returns the grib record ending position (in bytes) from the beginning of
2147 * gribinfo - pointer to a filled gribinfo structure.
2150 * position (in bytes) of the end of the grib record within the file.
2151 *****************************************************************************/
2152 int rg_get_end(GribInfo
*gribinfo
,int index
)
2154 return gribinfo
->elements
[index
].end
;
2156 /*****************************************************************************
2158 * returns grib id of input grid
2161 * gribinfo - pointer to a previously allocated gribinfo structure. The
2162 * gribinfo structure is filled in this function.
2165 * grib id of input grid
2166 *****************************************************************************/
2167 int rg_get_gridnum(GribInfo
*gribinfo
,int index
)
2169 return gribinfo
->elements
[index
].pds
->usGrid_id
;
2171 /*****************************************************************************
2176 * gribinfo - pointer to a previously allocated gribinfo structure. The
2177 * gribinfo structure is filled in this function.
2180 * date (yymmddhh) in integer type
2181 *****************************************************************************/
2182 int rg_get_date(GribInfo
*gribinfo
,int index
)
2184 return gribinfo
->elements
[index
].date
;
2186 /*****************************************************************************
2191 * gribinfo - pointer to a previously allocated gribinfo structure. The
2192 * gribinfo structure is filled in this function.
2195 * century in integer type
2196 *****************************************************************************/
2197 int rg_get_century(GribInfo
*gribinfo
,int index
)
2199 return gribinfo
->elements
[index
].century
;
2201 /*****************************************************************************
2203 * returns forecast time
2206 * gribinfo - pointer to a previously allocated gribinfo structure. The
2207 * gribinfo structure is filled in this function.
2210 * forecast time in units described by usFcst_unit_id
2211 *****************************************************************************/
2212 int rg_get_forecast_time(GribInfo
*gribinfo
,int index
)
2214 return gribinfo
->elements
[index
].pds
->usP1
;
2217 /*****************************************************************************
2219 * reads the gribmap file, and stores the information in the GribParameters
2223 * gribmap - pointer to a previously allocated GribParameters structure.
2224 * The gribmap structure is filled in this function.
2225 * file - the name of the gribmap file to read.
2228 * 1 - successful call to setup_gribinfo
2229 * -1 - call to setup_gribinfo failed
2231 *****************************************************************************/
2232 int rg_setup_gribmap(GribParameters
*gribmap
, char filename
[])
2236 int id
, center
, subcenter
, table
;
2239 fid
= fopen(filename
,"r");
2242 fprintf(stderr
,"Could not open %s\n",filename
);
2246 gribmap
->parms
= (GribTableEntry
*)malloc(sizeof(GribTableEntry
));
2249 while (fgets(line
,500,fid
) != NULL
)
2251 /* Skip over comments at begining of gribmap file */
2252 if (line
[0] == '#') continue;
2254 sscanf(line
,"%d:",&id
);
2257 sscanf(line
,"%d:%d:%d:%d",&id
,¢er
,&subcenter
,&table
);
2262 (GribTableEntry
*)realloc(gribmap
->parms
,
2263 (idx
+1)*sizeof(GribTableEntry
));
2264 gribmap
->parms
[idx
].center
= center
;
2265 gribmap
->parms
[idx
].subcenter
= subcenter
;
2266 gribmap
->parms
[idx
].table
= table
;
2267 sscanf(line
,"%d:%[^:]:%[^:]",&(gribmap
->parms
[idx
].parmid
),
2268 gribmap
->parms
[idx
].name
,
2269 gribmap
->parms
[idx
].comment
);
2275 gribmap
->num_entries
= idx
;
2281 /*****************************************************************************
2283 * finds the gribmap entry described by the gribmap file, and stores the information in the GribParameters
2287 * gribmap - pointer to structure that was filled by a call to
2289 * table - if set to -1, the first table the valid name will be used.
2290 * Otherwise, the table id must match as well.
2291 * name - name of the parameter to find.
2293 * gribmap_parms - pointer to GribTableEntry structure containing
2294 * information about the parameter that was found.
2297 * 1 - successful call to setup_gribinfo
2298 * -1 - call to setup_gribinfo failed
2300 *****************************************************************************/
2301 int rg_gribmap_parameter(GribParameters
*gribmap
, char name
[], int table
,
2302 GribTableEntry
*gribmap_parms
)
2308 for (idx
= 0; idx
< gribmap
->num_entries
; idx
++)
2311 if (strcmp(gribmap
->parms
[idx
].name
,name
) == 0)
2313 if ((table
== -1) || (table
== gribmap
->parms
[idx
].table
))
2315 /* We found a match! */
2324 memcpy(gribmap_parms
,&(gribmap
->parms
[idx
]),sizeof(GribTableEntry
));
2333 /*****************************************************************************
2335 * Deallocates the elements in the gribmap structure.
2338 * gribmap - pointer to a previously allocated gribmap structure. The
2339 * gribmap structure is filled in this function.
2341 *****************************************************************************/
2342 void rg_free_gribmap_elements(GribParameters
*gribmap
)
2344 free(gribmap
->parms
);
2347 /*****************************************************************************
2349 * Compares the elements in a findgrib structure with the elements in the
2350 * gribinfo structure for the input index. If they match, returns 1,
2351 * otherwise, returns 0.
2356 * index - the index of the grib record in gribinfo to compare to.
2358 *****************************************************************************/
2359 int compare_record(GribInfo
*gribinfo
, FindGrib
*findgrib
, int gribnum
)
2363 * Note (6/20/05): This searching is very inefficient. We may need to
2364 * improve this, since, for WRF, when searching through boundary data,
2365 * each search is slower that the previous, since the record to be
2366 * found turns out to be farther into the list.
2371 if ((findgrib
->center_id
== -INT_MAX
) ||
2372 findgrib
->center_id
== gribinfo
->elements
[gribnum
].center_id
) {
2373 if ((findgrib
->subcenter_id
== -INT_MAX
) ||
2374 findgrib
->subcenter_id
== gribinfo
->elements
[gribnum
].subcenter_id
) {
2375 if ((findgrib
->parmtbl_version
== -INT_MAX
) ||
2376 findgrib
->parmtbl_version
== gribinfo
->elements
[gribnum
].parmtbl
) {
2377 if ((strcmp(findgrib
->initdate
,"*") == 0) ||
2378 (strncmp(gribinfo
->elements
[gribnum
].initdate
,findgrib
->initdate
,
2379 strlen(findgrib
->initdate
)) == 0)) {
2380 if ((strcmp(findgrib
->validdate
,"*") == 0) ||
2381 (strncmp(gribinfo
->elements
[gribnum
].valid_time
,
2382 findgrib
->validdate
,
2383 strlen(findgrib
->validdate
)) == 0)) {
2384 if ((findgrib
->parmid
== -INT_MAX
) ||
2385 (findgrib
->parmid
==
2386 gribinfo
->elements
[gribnum
].usParm_id
)) {
2387 if ((findgrib
->leveltype
== -INT_MAX
) ||
2388 (findgrib
->leveltype
==
2389 gribinfo
->elements
[gribnum
].usLevel_id
)) {
2390 if ((findgrib
->level1
== -INT_MAX
) ||
2391 (findgrib
->level1
==
2392 gribinfo
->elements
[gribnum
].usHeight1
)) {
2393 if ((findgrib
->level2
== -INT_MAX
) ||
2394 (findgrib
->level2
==
2395 gribinfo
->elements
[gribnum
].usHeight2
)) {
2396 if ((findgrib
->fcsttime1
== -INT_MAX
) ||
2397 (findgrib
->fcsttime1
==
2398 gribinfo
->elements
[gribnum
].fcsttime1
)) {
2399 if ((findgrib
->fcsttime2
== -INT_MAX
) ||
2400 (findgrib
->fcsttime2
==
2401 gribinfo
->elements
[gribnum
].fcsttime2
)) {
2419 /*****************************************************************************
2421 * returns the multiplication factor to convert grib forecast times to
2425 * unit_id - grib forecast unit id, from Table 4.
2429 *****************************************************************************/
2430 int get_factor2(int unit
)
2454 /* This is a WSI (non-standard) time unit of 5 minutes */
2461 fprintf(stderr
,"Invalid unit for forecast time: %d\n",unit
);