2 ****************************************************************************
4 * Routines for indexing, reading and writing grib files. Routines
5 * are designed to be called by Fortran.
7 * All routines return 0 for success, 1 for failure, unless otherwise noted.
13 ****************************************************************************
16 #include "grib1_routines.h"
18 #include "wrf_projection.h"
24 char *trim (char *str
);
25 int index_metadata(GribInfo
*gribinfo
, MetaData
*metadata
, int fid
);
26 int index_times(GribInfo
*gribinfo
, Times
*times
);
27 int find_time(Times
*times
, char valid_time
[15]);
28 int get_gridnav_projection(int wrf_projection
);
29 int get_byte(int input_int
, int bytenum
);
32 * Allocate space for the fileindex structure
35 int ALLOC_INDEX_FILE(FileIndex
*fileindex
)
39 fileindex
->gribinfo
= (GribInfo
*)malloc(sizeof(GribInfo
));
40 if (fileindex
->gribinfo
== NULL
) {
41 fprintf(stderr
,"Allocating fileindex->gribinfo failed.\n");
46 fileindex
->metadata
= (MetaData
*)malloc(sizeof(MetaData
));
47 if (fileindex
->metadata
== NULL
) {
48 fprintf(stderr
,"Allocating fileindex->metadata failed.\n");
52 fileindex
->metadata
->elements
= NULL
;
54 fileindex
->times
= (Times
*)malloc(sizeof(Times
));
55 if (fileindex
->times
== NULL
) {
56 fprintf(stderr
,"Allocating fileindex->times failed.\n");
60 fileindex
->times
->elements
= NULL
;
66 void FREE_INDEX_FILE(FileIndex
*fileindex
)
70 rg_free_gribinfo_elements(fileindex
->gribinfo
);
71 free(fileindex
->gribinfo
);
73 free(fileindex
->metadata
->elements
);
74 free(fileindex
->metadata
);
76 free(fileindex
->times
->elements
);
77 free(fileindex
->times
);
82 int INDEX_FILE(int *fid
, FileIndex
*fileindex
)
86 /* Index the grib records */
88 status
= rg_setup_gribinfo_i(fileindex
->gribinfo
,*fid
,1);
90 fprintf(stderr
,"Error setting up gribinfo structure.\n");
94 /* Index the metadata section */
96 status
= index_metadata(fileindex
->gribinfo
, fileindex
->metadata
, *fid
);
98 fprintf(stderr
,"Error setting up metadata structure.\n");
102 /* Setup a list of times based on times in grib records */
104 status
= index_times(fileindex
->gribinfo
, fileindex
->times
);
106 fprintf(stderr
,"Error indexing times in grib file.\n");
114 int GET_FILEINDEX_SIZE(int *size
)
116 *size
= sizeof(FileIndex
);
121 int GET_NUM_TIMES(FileIndex
*fileindex
, int *numtimes
)
123 *numtimes
= (fileindex
->times
)->num_elements
;
128 int GET_TIME(FileIndex
*fileindex
, int *idx
, char time
[])
131 int year
, month
, day
, minute
, hour
, second
;
134 num_times
= GET_NUM_TIMES(fileindex
,&num_times
);
135 if (*idx
> num_times
)
137 fprintf(stderr
,"Tried to get time %d, but only %d times exist\n",
142 strcpy(time
,fileindex
->times
->elements
[*idx
-1].valid_time
);
144 /* Reformat time to meet WRF time format */
146 sscanf(time
, "%4d%2d%2d%2d%2d%2d",
147 &year
, &month
, &day
, &hour
, &minute
, &second
);
148 sprintf(time2
, "%04d-%02d-%02d_%02d:%02d:%02d",
149 year
, month
, day
, hour
, minute
, second
);
150 strncpy(time
,time2
,19);
156 int GET_LEVEL1(FileIndex
*fileindex
, int *idx
, int *level1
)
159 *level1
= (fileindex
->gribinfo
)->elements
[*idx
].usHeight1
;
166 int GET_LEVEL2(FileIndex
*fileindex
, int *idx
, int *level2
)
169 *level2
= (fileindex
->gribinfo
)->elements
[*idx
].usHeight2
;
176 int index_metadata(GribInfo
*gribinfo
, MetaData
*metadata
, int fid
)
181 int found_metadata
=0;
188 char element
[100],datestr
[100],varname
[100];
196 /* Associate a FILE *stream with the file id */
197 stream
= fdopen(fid
,"r");
200 perror("Error associating stream with file descriptor");
206 * First, set the position to end of grib data (the
207 * metadata section comes after the grib data).
209 idx
= rg_num_elements(gribinfo
) - 1;
210 end
= rg_get_end(gribinfo
,idx
);
212 fileend
= lseek(fid
,0,SEEK_END
);
215 * Now, start searching for metadata
217 while (pos
< (fileend
- 10))
220 pos
= lseek(fid
,seekpos
,SEEK_SET
);
223 fprintf(stderr
,"Error seeking %d bytes in file\n",end
);
228 bytesread
= read(fid
,string
,10);
231 fprintf(stderr
,"Invalid read, pos: %d :\n",pos
);
237 if (strncmp(string
,"<METADATA>",10) == 0)
239 /* We found it, so break out ! */
247 /* Now, read metadata, line by line */
249 while(fgets(line
,1000,stream
) != NULL
)
253 /* Set comment flag, if we found a comment */
254 if (strncmp(line
,"<!--",4) == 0)
260 /* Search for end of comment */
264 while (charidx
< strlen(line
))
267 if (strncmp(line
+charidx
,"-->",3) == 0)
269 strcpy(line
,line
+charidx
+3);
280 if (incomment
) continue;
283 /* Check for end of metadata */
284 if (strncmp(line
,"</METADATA>",11) == 0)
286 /* We found end of data, so, break out */
290 /* Skip blank lines */
291 if (strlen(line
) == 0) continue;
296 strcpy(element
,"none");
297 strcpy(datestr
,"none");
298 strcpy(varname
,"none");
299 strcpy(value
,"none");
300 if (sscanf(line
,"%[^;=];%[^;=];%[^;=]=%[^\n]",varname
,datestr
,
304 else if (sscanf(line
,"%[^;=];%[^;=]=%[^\n]",datestr
,element
,value
) == 3)
306 strcpy(varname
,"none");
308 else if (sscanf(line
,"%[^;=]=%[^\n]",element
,value
) == 2)
310 strcpy(varname
,"none");
311 strcpy(datestr
,"none");
315 strcpy(varname
,"none");
316 strcpy(datestr
,"none");
317 strcpy(element
,"none");
318 strcpy(value
,"none");
319 fprintf(stderr
,"Invalid line in metadata: \n%s",line
);
328 (MetaData_Elements
*)realloc( metadata
->elements
,
329 (elemidx
+1)*sizeof(MetaData_Elements
) );
330 strcpy(metadata
->elements
[elemidx
].VarName
,varname
);
331 strcpy(metadata
->elements
[elemidx
].DateStr
,datestr
);
332 strcpy(metadata
->elements
[elemidx
].Element
,element
);
333 strcpy(metadata
->elements
[elemidx
].Value
,value
);
339 metadata
->num_elements
= elemidx
;
347 int index_times(GribInfo
*gribinfo
, Times
*times
)
357 times
->num_elements
= 0;
359 /* Loop through elements, and build list of times */
361 for (idx
=0; idx
< gribinfo
->num_elements
; idx
++)
363 /* Calculate valid time */
364 status
= rg_get_valid_time(gribinfo
,idx
,valid_time
);
367 fprintf(stderr
,"Could not retrieve valid time for index: %d\n",idx
);
372 * Check if this time is already contained in times
373 * If not, allocate space for it, and add it to list
375 if (find_time(times
,valid_time
) < 0)
377 times
->num_elements
++;
380 realloc(times
->elements
,times
->num_elements
*sizeof(Times_Elements
));
381 if (times
->elements
== NULL
)
383 fprintf(stderr
,"Allocating times->elements failed.\n");
387 strcpy(times
->elements
[times
->num_elements
- 1].valid_time
,valid_time
);
396 for (idx
=1; idx
< times
->num_elements
; idx
++)
398 if (strcmp(times
->elements
[idx
-1].valid_time
,
399 times
->elements
[idx
].valid_time
) > 0)
401 strcpy(tmp
,times
->elements
[idx
-1].valid_time
);
402 strcpy(times
->elements
[idx
-1].valid_time
,
403 times
->elements
[idx
].valid_time
);
404 strcpy(times
->elements
[idx
].valid_time
, tmp
);
415 int find_time(Times
*times
, char valid_time
[15])
420 for (idx
= 0; idx
< times
->num_elements
; idx
++)
422 if (strcmp(times
->elements
[idx
].valid_time
,valid_time
) == 0)
434 int GET_METADATA_VALUE(FileIndex
*fileindex
, char ElementIn
[],
435 char DateStrIn
[], char VarNameIn
[], char Value
[],
436 int *stat
, int strlen1
, int strlen2
, int strlen3
,
437 int strlen4
, int strlen5
)
448 strncpy(Element
,ElementIn
,strlen2
);
449 Element
[strlen2
] = '\0';
450 strncpy(DateStr
,DateStrIn
,strlen3
);
451 DateStr
[strlen3
] = '\0';
452 strncpy(VarName
,VarNameIn
,strlen4
);
453 VarName
[strlen4
] = '\0';
457 for (elemidx
= 0; elemidx
< fileindex
->metadata
->num_elements
; elemidx
++)
459 if (strcmp(Element
,fileindex
->metadata
->elements
[elemidx
].Element
) == 0)
461 if (strcmp(DateStr
,fileindex
->metadata
->elements
[elemidx
].DateStr
)
465 fileindex
->metadata
->elements
[elemidx
].VarName
) == 0)
476 strncpy(Value
, fileindex
->metadata
->elements
[elemnum
].Value
, Value_Len
);
480 strncpy(Value
, "none", Value_Len
);
485 * Pad end of string with one space. This allows Fortran internal
486 * read function to work properly.
488 if (strlen(Value
) < Value_Len
)
490 strcpy(Value
+ strlen(Value
), " ");
497 int GET_GRIB_INDEX(FileIndex
*fileindex
, int *center
, int *subcenter
,
498 int *parmtbl
, int *parmid
, char DateStrIn
[],
499 int *leveltype
, int *level1
, int *level2
, int *fcsttime1
,
500 int *fcsttime2
, int *index
, int strlen1
, int strlen2
)
505 strncpy(DateStr
,DateStrIn
,strlen2
);
506 DateStr
[strlen2
] = '\0';
507 grib_time_format(DateStr
,DateStr
);
509 rg_init_findgrib(&findgrib
);
511 strncpy(findgrib
.initdate
,DateStrIn
,strlen2
);
512 findgrib
.initdate
[strlen2
] = '\0';
513 findgrib
.parmid
= *parmid
;
514 findgrib
.leveltype
= *leveltype
;
515 findgrib
.level1
= *level1
;
516 findgrib
.level2
= *level2
;
517 findgrib
.fcsttime1
= *fcsttime1
;
518 findgrib
.fcsttime2
= *fcsttime2
;
519 findgrib
.center_id
= *center
;
520 findgrib
.subcenter_id
= *subcenter
;
521 findgrib
.parmtbl_version
= *parmtbl
;
523 *index
= rg_get_index(fileindex
->gribinfo
, &findgrib
);
530 int GET_GRIB_INDEX_GUESS(FileIndex
*fileindex
, int *center
, int *subcenter
,
531 int *parmtbl
, int *parmid
, char DateStrIn
[],
532 int *leveltype
, int *level1
, int *level2
,
533 int *fcsttime1
,int *fcsttime2
, int *guessidx
,
534 int *index
, int strlen1
, int strlen2
)
539 strncpy(DateStr
,DateStrIn
,strlen2
);
540 DateStr
[strlen2
] = '\0';
541 grib_time_format(DateStr
,DateStr
);
543 rg_init_findgrib(&findgrib
);
545 strncpy(findgrib
.initdate
,DateStrIn
,strlen2
);
546 findgrib
.initdate
[strlen2
] = '\0';
547 findgrib
.parmid
= *parmid
;
548 findgrib
.leveltype
= *leveltype
;
549 findgrib
.level1
= *level1
;
550 findgrib
.level2
= *level2
;
551 findgrib
.fcsttime1
= *fcsttime1
;
552 findgrib
.fcsttime2
= *fcsttime2
;
553 findgrib
.center_id
= *center
;
554 findgrib
.subcenter_id
= *subcenter
;
555 findgrib
.parmtbl_version
= *parmtbl
;
557 *index
= rg_get_index_guess(fileindex
->gribinfo
, &findgrib
, *guessidx
);
564 int GET_GRIB_CENTER(FileIndex
*fileindex
, int *parmid
, int *center
)
567 *center
= rg_get_center_id(fileindex
->gribinfo
,*parmid
);
574 int GET_GRIB_SUBCENTER(FileIndex
*fileindex
, int *parmid
, int *subcenter
)
577 *subcenter
= rg_get_subcenter_id(fileindex
->gribinfo
,*parmid
);
584 int GET_GRIB_TBLVERSION(FileIndex
*fileindex
, int *parmid
, int *parmtbl
)
587 *parmtbl
= rg_get_parmtbl(fileindex
->gribinfo
,*parmid
);
594 int GET_GRIB_PROCID(FileIndex
*fileindex
, int *parmid
, int *proc_id
)
597 *proc_id
= rg_get_proc_id(fileindex
->gribinfo
,*parmid
);
604 int GET_GRIB_INDEX_VALIDTIME(FileIndex
*fileindex
, int *center
,
605 int *subcenter
, int *parmtbl
, int *parmid
,
606 char DateStrIn
[], int *leveltype
, int *level1
, int *level2
,
607 int *index
, int strlen1
, int strlen2
)
612 strncpy(DateStr
,DateStrIn
,strlen2
);
613 DateStr
[strlen2
] = '\0';
614 grib_time_format(DateStr
,DateStr
);
616 rg_init_findgrib(&findgrib
);
618 strncpy(findgrib
.validdate
,DateStr
,strlen2
);
619 findgrib
.initdate
[strlen2
] = '\0';
620 findgrib
.parmid
= *parmid
;
621 findgrib
.leveltype
= *leveltype
;
622 findgrib
.level1
= *level1
;
623 findgrib
.level2
= *level2
;
624 findgrib
.center_id
= *center
;
625 findgrib
.subcenter_id
= *subcenter
;
626 findgrib
.parmtbl_version
= *parmtbl
;
628 *index
= rg_get_index(fileindex
->gribinfo
, &findgrib
);
634 int GET_GRIB_INDEX_VALIDTIME_GUESS(FileIndex
*fileindex
, int *center
,
635 int *subcenter
, int *parmtbl
, int *parmid
,
636 char DateStrIn
[], int *leveltype
,
637 int *level1
, int *level2
, int *guessidx
,
638 int *index
, int strlen1
, int strlen2
)
643 strncpy(DateStr
,DateStrIn
,strlen2
);
644 DateStr
[strlen2
] = '\0';
645 grib_time_format(DateStr
,DateStr
);
647 rg_init_findgrib(&findgrib
);
649 strncpy(findgrib
.validdate
,DateStr
,strlen2
);
650 findgrib
.initdate
[strlen2
] = '\0';
651 findgrib
.parmid
= *parmid
;
652 findgrib
.leveltype
= *leveltype
;
653 findgrib
.level1
= *level1
;
654 findgrib
.level2
= *level2
;
655 findgrib
.center_id
= *center
;
656 findgrib
.subcenter_id
= *subcenter
;
657 findgrib
.parmtbl_version
= *parmtbl
;
659 *index
= rg_get_index_guess(fileindex
->gribinfo
, &findgrib
, *guessidx
);
665 int GET_GRIB_INDICES(FileIndex
*fileindex
, int *center
, int *subcenter
,
666 int *parmtbl
,int *parmid
, char DateStrIn
[],
667 int *leveltype
, int *level1
, int *level2
, int *fcsttime1
,
668 int *fcsttime2
, int *indices
, int *num_indices
,
669 int strlen1
, int strlen2
)
675 strncpy(DateStr
,DateStrIn
,strlen2
);
676 DateStr
[strlen2
] = '\0';
677 grib_time_format(DateStr
,DateStr
);
679 rg_init_findgrib(&findgrib
);
681 strncpy(findgrib
.initdate
,DateStrIn
,strlen2
);
682 findgrib
.initdate
[strlen2
] = '\0';
683 trim(findgrib
.initdate
);
684 findgrib
.parmid
= *parmid
;
685 findgrib
.leveltype
= *leveltype
;
686 findgrib
.level1
= *level1
;
687 findgrib
.level2
= *level2
;
688 findgrib
.fcsttime1
= *fcsttime1
;
689 findgrib
.fcsttime2
= *fcsttime2
;
690 findgrib
.center_id
= *center
;
691 findgrib
.subcenter_id
= *subcenter
;
692 findgrib
.parmtbl_version
= *parmtbl
;
694 *num_indices
= rg_get_indices(fileindex
->gribinfo
, &findgrib
, indices
);
696 return (*num_indices
);
701 int GET_GRID_INFO_SIZE(int *size
)
704 *size
= sizeof(Grid_Info
);
711 int LOAD_GRID_INFO(char *varnameIn
, char *initdateIn
, int *leveltype
,
712 int *level1
, int *level2
, float *fcst_time
,
713 int *accum_period
, int *grid_id
, int *projection
,
714 int *xpoints
, int *ypoints
, float *center_lat
,
715 float *center_lon
, float *Di
, float *Dj
,float *central_lon
,
716 int *proj_center_flag
, float *latin1
,
717 float *latin2
, Grib1_Tables
*grib_tables
,
718 Grid_Info
*grid_info
, int strlen1
, int strlen2
)
721 char varname
[1000], initdate
[1000];
723 strncpy(varname
,varnameIn
,strlen1
);
724 varname
[strlen1
] = '\0';
725 strncpy(initdate
,initdateIn
,strlen2
);
726 initdate
[strlen2
] = '\0';
728 strcpy(grid_info
->varname
, varname
);
729 strcpy(grid_info
->initdate
, initdate
);
730 grid_info
->leveltype
= *leveltype
;
731 grid_info
->level1
= *level1
;
732 grid_info
->level2
= *level2
;
733 grid_info
->fcst_time
= *fcst_time
;
734 grid_info
->accum_period
= *accum_period
;
735 grid_info
->grid_id
= *grid_id
;
736 grid_info
->projection
= *projection
;
737 grid_info
->xpoints
= *xpoints
;
738 grid_info
->ypoints
= *ypoints
;
739 grid_info
->center_lat
= *center_lat
;
740 grid_info
->center_lon
= *center_lon
;
741 grid_info
->Di
= *Di
;
742 grid_info
->Dj
= *Dj
;
743 grid_info
->central_lon
= *central_lon
;
744 grid_info
->proj_center_flag
= *proj_center_flag
;
745 grid_info
->latin1
= *latin1
;
746 grid_info
->latin2
= *latin2
;
747 grid_info
->grib_tables
= copy_grib_tables(grib_tables
);
753 int PRINT_GRID_INFO(Grid_Info
*grid_info
)
756 fprintf(stdout
,"varname =%s\n",grid_info
->varname
);
757 fprintf(stdout
,"initdate =%s\n",grid_info
->initdate
);
758 fprintf(stdout
,"leveltype =%d\n",grid_info
->leveltype
);
759 fprintf(stdout
,"level1 =%d\n",grid_info
->level1
);
760 fprintf(stdout
,"level2 =%d\n",grid_info
->level2
);
761 fprintf(stdout
,"fcst_time =%f\n",grid_info
->fcst_time
);
762 fprintf(stdout
,"accum_period =%d\n",grid_info
->accum_period
);
763 fprintf(stdout
,"grid_id =%d\n",grid_info
->grid_id
);
764 fprintf(stdout
,"projection =%d\n",grid_info
->projection
);
765 fprintf(stdout
,"xpoints =%d\n",grid_info
->xpoints
);
766 fprintf(stdout
,"ypoints =%d\n",grid_info
->ypoints
);
767 fprintf(stdout
,"center_lat =%f\n",grid_info
->center_lat
);
768 fprintf(stdout
,"center_lon =%f\n",grid_info
->center_lon
);
769 fprintf(stdout
,"Di =%f\n",grid_info
->Di
);
770 fprintf(stdout
,"Dj =%f\n",grid_info
->Dj
);
771 fprintf(stdout
,"central_lon =%f\n",grid_info
->central_lon
);
772 fprintf(stdout
,"proj_center_flag =%d\n",grid_info
->proj_center_flag
);
773 fprintf(stdout
,"latin1 =%f\n",grid_info
->latin1
);
774 fprintf(stdout
,"latin2 =%f\n",grid_info
->latin2
);
781 int GET_SIZEOF_GRID(FileIndex
*fileindex
, int *index
, int *numcols
,
785 *numcols
= rg_get_numcols(fileindex
->gribinfo
,*index
);
787 *numrows
= rg_get_numrows(fileindex
->gribinfo
,*index
);
789 return (*numcols
)*(*numrows
);
794 void FREE_GRID_INFO(Grid_Info
*grid_info
)
796 FREE_GRIBMAP(grid_info
->grib_tables
);
800 int READ_GRIB(FileIndex
*fileindex
, int *fid
, int *index
, float *data
)
804 status
= rg_get_data_1d(fileindex
->gribinfo
,*index
,data
);
811 #define SECS_IN_SEC 1
812 #define SECS_IN_MIN 60
813 #define MINS_IN_HOUR 60
814 #define MINS_IN_5MINS 5
815 #define HOURS_IN_DAY 24
817 #define MAX_FCST 65535
818 #define MAX_FCST_SECS MAX_FCST*SECS_IN_SEC
819 #define MAX_FCST_MINS MAX_FCST*SECS_IN_MIN
820 #define MAX_FCST_5MINS MAX_FCST*MINS_IN_5MINS*SECS_IN_MIN
821 #define MAX_FCST_HOURS MAX_FCST*MINS_IN_HOUR*SECS_IN_MIN
822 #define MAX_FCST_DAYS MAX_FCST*HOURS_IN_DAY*MINS_IN_HOUR*SECS_IN_MIN
824 #define MAX1B_FCST 256
825 #define MAX1B_FCST_SECS MAX1B_FCST*SECS_IN_SEC
826 #define MAX1B_FCST_MINS MAX1B_FCST*SECS_IN_MIN
827 #define MAX1B_FCST_5MINS MAX1B_FCST*MINS_IN_5MINS*SECS_IN_MIN
828 #define MAX1B_FCST_HOURS MAX1B_FCST*MINS_IN_HOUR*SECS_IN_MIN
829 #define MAX1B_FCST_DAYS MAX1B_FCST*HOURS_IN_DAY*MINS_IN_HOUR*SECS_IN_MIN
844 int get_fcst_time(int accum_period
, int fcst_secs
, FcstTimeStruct
*fcst_time
);
846 /****************************************************************************
848 * This function takes in metadata in the grid_info structure, output data in
849 * the *data array, and calls routines to write the metadata and data
850 * in grib version 1 format the open file descriptor filefd.
852 ****************************************************************************/
854 int WRITE_GRIB(Grid_Info
*grid_info
, int *filefd
, float *data
)
858 DATA_INPUT data_input
;
860 USER_INPUT user_input
;
863 float x_center
, y_center
;
865 float first_lat
, first_lon
, last_lat
, last_lon
;
866 int year
, month
, day
, hour
, minute
;
873 int fcst_unit_ext_1
, fcst_unit_ext_2
;
877 int center
, subcenter
, parmtbl
;
880 FcstTimeStruct fcst_time
;
882 strcpy(varname2
,grid_info
->varname
);
885 sscanf(grid_info
->initdate
,"%d-%d-%d_%d:%d:%f",
886 &year
,&month
,&day
,&hour
,&minute
,&second
);
888 /* Get coords of center of grid */
889 x_center
= (grid_info
->xpoints
+ 1)/2.;
890 y_center
= (grid_info
->ypoints
+ 1)/2.;
892 grid_projection
= get_gridnav_projection(grid_info
->projection
);
894 /* Convert grid spacing to degrees for LATLON projection */
896 if ( (grid_info
->projection
== WRF_LATLON
) ||
897 (grid_info
->projection
== WRF_CASSINI
) )
899 dx
= grid_info
->Di
* KM_TO_DEGREES
;
900 dy
= grid_info
->Dj
* KM_TO_DEGREES
;
908 /* Initialize grid structure */
910 status
= GRID_init(grid_info
->center_lat
, grid_info
->central_lon
,
912 grid_info
->latin1
, grid_info
->latin2
,
913 grid_info
->xpoints
, grid_info
->ypoints
,
915 grid_info
->center_lat
, grid_info
->center_lon
,
920 fprintf(stderr
,"write_grib: error from GRID_init\n");
923 /* get lat/lon of lower left corner */
924 status
= GRID_to_latlon(&gridnav
, 1, 1, &first_lat
, &first_lon
);
928 "write_grib: error from GRID_to_latlon for first lat/lon\n");
931 /* get lat/lon of upper right corner */
932 status
= GRID_to_latlon(&gridnav
, grid_info
->xpoints
, grid_info
->ypoints
,
933 &last_lat
, &last_lon
);
937 "write_grib: error from GRID_to_latlon for last lat/lon\n");
940 /* Read the grib parameter table */
941 status
= GET_GRIB_PARAM(grid_info
->grib_tables
, varname2
, ¢er
,
942 &subcenter
, &parmtbl
, &tablenum
, &table_index
,
947 "Skipping %s, Could not find parameter for %s in gribmap.txt\n",\
953 * We skip any parameters that are listed in parameter 255 in gribmap.txt.
954 * Parameter 255 is used to indicate that a WRF parameter should not be
955 * output. It is useful for parameters that are requested to be output in
956 * the WRF Registry, but are already implicitly output in grib.
959 if (table_index
== 255)
965 * Setup the geom_in structure for the grib library. Here, we set
966 * the generic parms. Below, we set the projection specific parms
968 geom_in
.nx
= grid_info
->xpoints
;
969 geom_in
.ny
= grid_info
->ypoints
;
970 geom_in
.first_lat
= first_lat
;
971 geom_in
.first_lon
= first_lon
;
972 geom_in
.last_lat
= last_lat
;
973 geom_in
.last_lon
= last_lon
;
976 switch (grid_info
->projection
)
980 strcpy(geom_in
.prjn_name
,"spherical");
984 geom_in
.usRes_flag
= 0; /*
985 * Set to 0 here, MEL grib library will reset
986 * to 128 to indicate that direction
987 * increments are given.
991 strcpy(geom_in
.prjn_name
,"mercator");
992 geom_in
.parm_1
= grid_info
->latin1
;
995 geom_in
.usRes_flag
= 136;
998 strcpy(geom_in
.prjn_name
,"lambert");
999 geom_in
.usRes_flag
= 0; /* Set to 0 here, MEL grib library will reset
1002 geom_in
.parm_3
= grid_info
->central_lon
;
1003 geom_in
.x_int_dis
= dx
;
1004 geom_in
.y_int_dis
= dy
;
1005 geom_in
.parm_1
= grid_info
->latin1
;
1006 geom_in
.parm_2
= grid_info
->latin2
;
1008 case WRF_POLAR_STEREO
:
1009 strcpy(geom_in
.prjn_name
,"polar_stereo");
1010 geom_in
.usRes_flag
= 0; /* Set to 0 here, MEL grib library will reset
1014 geom_in
.parm_3
= -1;
1015 geom_in
.x_int_dis
= dx
*(1.+sin(60. * PI
/180.))
1016 / (1.+sin(abs(grid_info
->latin1
) * PI
/180.));
1017 geom_in
.y_int_dis
= dy
*(1.+sin(60. * PI
/180.))
1018 / (1.+sin(abs(grid_info
->latin1
) * PI
/180.));
1019 geom_in
.parm_1
= -1;
1020 geom_in
.parm_2
= grid_info
->central_lon
;
1023 fprintf(stderr
,"Error, invalid projection: %d\n",grid_info
->projection
);
1028 * Setup the data_input structure.
1030 data_input
.nDec_sc_fctr
=
1031 grid_info
->grib_tables
->grib_table_info
[tablenum
].dec_sc_factor
[table_index
];
1032 data_input
.usProc_id
= 220;
1033 data_input
.usGrid_id
= grid_info
->grid_id
;
1034 data_input
.usParm_id
=
1035 grid_info
->grib_tables
->grib_table_info
[tablenum
].parm_id
[table_index
];
1036 data_input
.usParm_sub_id
=
1037 grid_info
->grib_tables
->grib_table_info
[tablenum
].subcenter
;
1038 data_input
.usLevel_id
= grid_info
->leveltype
;
1040 if (grid_info
->leveltype
== 112) {
1041 data_input
.nLvl_1
= grid_info
->level2
;
1042 data_input
.nLvl_2
= grid_info
->level1
;
1044 data_input
.nLvl_1
= grid_info
->level1
;
1045 data_input
.nLvl_2
= grid_info
->level2
;
1048 data_input
.nYear
= year
;
1049 data_input
.nMonth
= month
;
1050 data_input
.nDay
= day
;
1051 data_input
.nHour
= hour
;
1052 data_input
.nMinute
= minute
;
1053 data_input
.nSecond
= second
;
1055 status
= get_fcst_time(grid_info
->accum_period
, grid_info
->fcst_time
,
1058 data_input
.usFcst_id
= fcst_time
.fcst_unit
;
1059 data_input
.usFcst_per1
= fcst_time
.P1
;
1060 data_input
.usFcst_per2
= fcst_time
.P2
;
1061 data_input
.usTime_range_id
= fcst_time
.time_range
;
1062 data_input
.usTime_range_avg
= 0;
1063 data_input
.usTime_range_mis
= 0;
1065 * This is for WSI's extended PDS section
1067 data_input
.PDS_41
= fcst_time
.fcst_unit_ext_1
;
1068 data_input
.PDS_42
= fcst_time
.P1_ext
;
1069 data_input
.PDS_46
= fcst_time
.fcst_unit_ext_2
;
1070 data_input
.PDS_47
= fcst_time
.P2_ext
;
1071 data_input
.PDS_51
= fcst_time
.time_range_ext
;
1072 data_input
.PDS_52
= 0;
1075 data_input
.nDec_sc_fctr
=
1076 grid_info
->grib_tables
->grib_table_info
[tablenum
].dec_sc_factor
[table_index
];
1077 user_input
.usCenter_id
=
1078 grid_info
->grib_tables
->grib_table_info
[tablenum
].center
;
1079 user_input
.usParm_tbl
=
1080 grid_info
->grib_tables
->grib_table_info
[tablenum
].parmtbl
;
1081 user_input
.chCase_id
='0';
1082 user_input
.usSub_tbl
= 0;
1083 user_input
.usCenter_sub
=
1084 grid_info
->grib_tables
->grib_table_info
[tablenum
].subcenter
;
1085 user_input
.usTrack_num
= 0;
1086 user_input
.usGds_bms_id
= 128;
1087 user_input
.usBDS_flag
= 0;
1088 user_input
.usBit_pack_num
= 0;
1090 status
= init_gribhdr(&gh
,errmsg
);
1092 fprintf (stderr
,"write_grib: Error writing %s: \n\t%s\n",varname2
,errmsg
);
1096 status
= grib_enc(data_input
,user_input
,geom_in
,data
,gh
,errmsg
);
1098 fprintf (stderr
,"write_grib: Error writing %s: \n\t%s\n",varname2
,errmsg
);
1099 fprintf (stderr
,"\tCheck precision for %s in gribmap.txt.\n",
1104 status
= gribhdr2filed(gh
,*filefd
,errmsg
);
1106 fprintf (stderr
,"write_grib: Error writing %s: \n\t%s\n",varname2
,errmsg
);
1115 /***************************************************************************
1116 * Function to set up a structure containing forecast time parameters
1117 * This encodes the standard grib forecast time parameters as well
1118 * as WSI's extended forecast time parameters.
1119 ***************************************************************************/
1121 int get_fcst_time(int accum_period
, int fcst_secs
, FcstTimeStruct
*ft
)
1124 * Added ability to output a "5-minute" forecast time unit for the
1125 * sake of WxProducer. This allows WxPro to ingest data beyond
1126 * 18 hours, and accumulation data beyond 255 units.
1136 ft
->fcst_unit_ext_1
= 0;
1137 ft
->fcst_unit_ext_2
= 0;
1140 ft
->time_range_ext
= 0;
1142 if (accum_period
== 0)
1144 if (fcst_secs
< MAX_FCST_SECS
)
1146 ft
->time_range
= 10;
1147 ft
->fcst_unit
= 254;
1148 ft
->P1
= get_byte(fcst_secs
,2);
1149 ft
->P2
= get_byte(fcst_secs
,1);
1151 else if (((fcst_secs
% SECS_IN_MIN
) == 0) &&
1152 (fcst_secs
< MAX_FCST_MINS
))
1154 ft
->time_range
= 10;
1156 ft
->P1
= get_byte(fcst_secs
/SECS_IN_MIN
,2);
1157 ft
->P2
= get_byte(fcst_secs
/SECS_IN_MIN
,1);
1159 else if (((fcst_secs
% SECS_IN_MIN
*MINS_IN_HOUR
) == 0) &&
1160 (fcst_secs
< MAX_FCST_HOURS
))
1162 ft
->time_range
= 10;
1164 ft
->P1
= get_byte(fcst_secs
/(SECS_IN_MIN
*MINS_IN_HOUR
),2);
1165 ft
->P2
= get_byte(fcst_secs
/(SECS_IN_MIN
*MINS_IN_HOUR
),1);
1168 * MAX_FCST_DAYS is causing an integer overflow, so, we'll just skip
1169 * the check here. It's very unlikely that someone would exceed this
1170 * anyway (5.6 million days!)
1173 else if (((fcst_secs % SECS_IN_MIN*MINS_IN_HOUR*HOURS_IN_DAY) == 0) &&
1174 (fcst_secs < MAX_FCST_DAYS))
1176 else if (((fcst_secs
% SECS_IN_MIN
*MINS_IN_HOUR
*HOURS_IN_DAY
) == 0))
1178 ft
->time_range
= 10;
1181 get_byte(fcst_secs
/(SECS_IN_MIN
*MINS_IN_HOUR
*HOURS_IN_DAY
),2);
1183 get_byte(fcst_secs
/(SECS_IN_MIN
*MINS_IN_HOUR
*HOURS_IN_DAY
),1);
1185 else if (((fcst_secs
% SECS_IN_MIN
*MINS_IN_5MINS
) == 0)
1186 && (fcst_secs
< MAX_FCST_5MINS
))
1188 ft
->time_range
= 10;
1190 ft
->P1
= get_byte(fcst_secs
/(SECS_IN_MIN
*MINS_IN_5MINS
),2);
1191 ft
->P2
= get_byte(fcst_secs
/(SECS_IN_MIN
*MINS_IN_5MINS
),1);
1195 ft
->time_range
= 255;
1200 ft
->fcst_unit_ext_1
= 254;
1201 ft
->fcst_unit_ext_2
= 254;
1202 ft
->P1_ext
= fcst_secs
;
1204 ft
->time_range_ext
= 0;
1207 else /* Accumulation period is not 0 */
1209 if ((fcst_secs
< MAX1B_FCST_HOURS
) &&
1210 (fcst_secs
%(SECS_IN_MIN
*MINS_IN_HOUR
) == 0) &&
1211 (accum_period
%(SECS_IN_MIN
*MINS_IN_HOUR
) == 0))
1215 ft
->P1
= (fcst_secs
-accum_period
)/(SECS_IN_MIN
*MINS_IN_HOUR
);
1216 ft
->P2
= fcst_secs
/(SECS_IN_MIN
*MINS_IN_HOUR
);
1218 else if ((fcst_secs
< MAX1B_FCST_MINS
) &&
1219 ((fcst_secs
-accum_period
)%SECS_IN_MIN
== 0) &&
1220 (fcst_secs
%SECS_IN_MIN
== 0))
1224 ft
->P1
= (fcst_secs
-accum_period
)/SECS_IN_MIN
;
1225 ft
->P2
= fcst_secs
/SECS_IN_MIN
;
1227 else if (fcst_secs
< MAX1B_FCST_SECS
)
1230 ft
->fcst_unit
= 254;
1231 ft
->P1
= fcst_secs
-accum_period
;
1234 else if ((fcst_secs
< MAX1B_FCST_5MINS
) &&
1235 (fcst_secs
%(SECS_IN_MIN
*MINS_IN_5MINS
) == 0) &&
1236 (accum_period
%(SECS_IN_MIN
*MINS_IN_5MINS
) == 0))
1240 ft
->P1
= (fcst_secs
-accum_period
)/(SECS_IN_MIN
*MINS_IN_5MINS
);
1241 ft
->P2
= fcst_secs
/(SECS_IN_MIN
*MINS_IN_5MINS
);
1245 ft
->time_range
= 255;
1250 ft
->fcst_unit_ext_1
= 254;
1251 ft
->fcst_unit_ext_2
= 254;
1252 ft
->P1_ext
= fcst_secs
- accum_period
;
1253 ft
->P2_ext
= accum_period
;
1254 ft
->time_range_ext
= 203; /* Duration */
1261 /******************************************************************************
1262 * returns a byt from an input integer
1263 *****************************************************************************/
1265 int get_byte(int input_int
, int bytenum
)
1268 out
= ((input_int
>> (bytenum
-1)*8) & ~(~0 <<8));
1272 /*************************************************************************
1273 * Converts from WRF time format to time format required by grib routines
1274 *************************************************************************/
1275 int grib_time_format(char *DateStr
, char *DateStrIn
)
1277 int year
,month
,day
,hour
,minute
,second
;
1280 if (DateStrIn
[0] == '*') {
1281 strcpy(DateStr
,"*");
1285 sscanf(DateStrIn
,"%04d-%02d-%02d_%02d:%02d:%02d",
1286 &year
,&month
,&day
,&hour
,&minute
,&second
);
1287 sprintf(DateStr
,"%04d%02d%02d%02d%02d%02d",
1288 year
,month
,day
,hour
,minute
,second
);