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"
32 int index_metadata(GribInfo
*gribinfo
, MetaData
*metadata
, int fid
);
33 int index_times(GribInfo
*gribinfo
, Times
*times
);
34 int find_time(Times
*times
, char valid_time
[15]);
35 int get_gridnav_projection(int wrf_projection
);
36 int get_byte(int input_int
, int bytenum
);
37 int grib_time_format(char *DateStr
, char *DateStrIn
);
40 * Allocate space for the fileindex structure
43 int ALLOC_INDEX_FILE(FileIndex
*fileindex
)
47 fileindex
->gribinfo
= (GribInfo
*)malloc(sizeof(GribInfo
));
48 if (fileindex
->gribinfo
== NULL
) {
49 fprintf(stderr
,"Allocating fileindex->gribinfo failed.\n");
54 fileindex
->metadata
= (MetaData
*)malloc(sizeof(MetaData
));
55 if (fileindex
->metadata
== NULL
) {
56 fprintf(stderr
,"Allocating fileindex->metadata failed.\n");
60 fileindex
->metadata
->elements
= NULL
;
62 fileindex
->times
= (Times
*)malloc(sizeof(Times
));
63 if (fileindex
->times
== NULL
) {
64 fprintf(stderr
,"Allocating fileindex->times failed.\n");
68 fileindex
->times
->elements
= NULL
;
74 void FREE_INDEX_FILE(FileIndex
*fileindex
)
78 rg_free_gribinfo_elements(fileindex
->gribinfo
);
79 free(fileindex
->gribinfo
);
81 free(fileindex
->metadata
->elements
);
82 free(fileindex
->metadata
);
84 free(fileindex
->times
->elements
);
85 free(fileindex
->times
);
90 int INDEX_FILE(int *fid
, FileIndex
*fileindex
)
94 /* Index the grib records */
96 status
= rg_setup_gribinfo_i(fileindex
->gribinfo
,*fid
,1);
98 fprintf(stderr
,"Error setting up gribinfo structure.\n");
102 /* Index the metadata section */
104 status
= index_metadata(fileindex
->gribinfo
, fileindex
->metadata
, *fid
);
106 fprintf(stderr
,"Error setting up metadata structure.\n");
110 /* Setup a list of times based on times in grib records */
112 status
= index_times(fileindex
->gribinfo
, fileindex
->times
);
114 fprintf(stderr
,"Error indexing times in grib file.\n");
122 int GET_FILEINDEX_SIZE(int *size
)
124 *size
= sizeof(FileIndex
);
129 int GET_NUM_TIMES(FileIndex
*fileindex
, int *numtimes
)
131 *numtimes
= (fileindex
->times
)->num_elements
;
136 int GET_TIME(FileIndex
*fileindex
, int *idx
, char time
[])
139 int year
, month
, day
, minute
, hour
, second
;
142 num_times
= GET_NUM_TIMES(fileindex
,&num_times
);
143 if (*idx
> num_times
)
145 fprintf(stderr
,"Tried to get time %d, but only %d times exist\n",
150 strcpy(time
,fileindex
->times
->elements
[*idx
-1].valid_time
);
152 /* Reformat time to meet WRF time format */
154 sscanf(time
, "%4d%2d%2d%2d%2d%2d",
155 &year
, &month
, &day
, &hour
, &minute
, &second
);
156 sprintf(time2
, "%04d-%02d-%02d_%02d:%02d:%02d",
157 year
, month
, day
, hour
, minute
, second
);
158 strncpy(time
,time2
,19);
164 int GET_LEVEL1(FileIndex
*fileindex
, int *idx
, int *level1
)
167 *level1
= (fileindex
->gribinfo
)->elements
[*idx
].usHeight1
;
174 int GET_LEVEL2(FileIndex
*fileindex
, int *idx
, int *level2
)
177 *level2
= (fileindex
->gribinfo
)->elements
[*idx
].usHeight2
;
184 int index_metadata(GribInfo
*gribinfo
, MetaData
*metadata
, int fid
)
189 int found_metadata
=0;
196 char element
[100],datestr
[100],varname
[100];
204 /* Associate a FILE *stream with the file id */
205 stream
= fdopen(fid
,"r");
208 perror("Error associating stream with file descriptor");
214 * First, set the position to end of grib data (the
215 * metadata section comes after the grib data).
217 idx
= rg_num_elements(gribinfo
) - 1;
218 end
= rg_get_end(gribinfo
,idx
);
220 fileend
= lseek(fid
,0,SEEK_END
);
223 * Now, start searching for metadata
225 while (pos
< (fileend
- 10))
228 pos
= lseek(fid
,seekpos
,SEEK_SET
);
231 fprintf(stderr
,"Error seeking %d bytes in file\n",end
);
236 bytesread
= read(fid
,string
,10);
239 fprintf(stderr
,"Invalid read, pos: %d :\n",pos
);
245 if (strncmp(string
,"<METADATA>",10) == 0)
247 /* We found it, so break out ! */
255 /* Now, read metadata, line by line */
257 while(fgets(line
,1000,stream
) != NULL
)
261 /* Set comment flag, if we found a comment */
262 if (strncmp(line
,"<!--",4) == 0)
268 /* Search for end of comment */
272 while (charidx
< strlen(line
))
275 if (strncmp(line
+charidx
,"-->",3) == 0)
277 strcpy(line
,line
+charidx
+3);
288 if (incomment
) continue;
291 /* Check for end of metadata */
292 if (strncmp(line
,"</METADATA>",11) == 0)
294 /* We found end of data, so, break out */
298 /* Skip blank lines */
299 if (strlen(line
) == 0) continue;
304 strcpy(element
,"none");
305 strcpy(datestr
,"none");
306 strcpy(varname
,"none");
307 strcpy(value
,"none");
308 if (sscanf(line
,"%[^;=];%[^;=];%[^;=]=%[^\n]",varname
,datestr
,
312 else if (sscanf(line
,"%[^;=];%[^;=]=%[^\n]",datestr
,element
,value
) == 3)
314 strcpy(varname
,"none");
316 else if (sscanf(line
,"%[^;=]=%[^\n]",element
,value
) == 2)
318 strcpy(varname
,"none");
319 strcpy(datestr
,"none");
323 strcpy(varname
,"none");
324 strcpy(datestr
,"none");
325 strcpy(element
,"none");
326 strcpy(value
,"none");
327 fprintf(stderr
,"Invalid line in metadata: \n%s",line
);
336 (MetaData_Elements
*)realloc( metadata
->elements
,
337 (elemidx
+1)*sizeof(MetaData_Elements
) );
338 strcpy(metadata
->elements
[elemidx
].VarName
,varname
);
339 strcpy(metadata
->elements
[elemidx
].DateStr
,datestr
);
340 strcpy(metadata
->elements
[elemidx
].Element
,element
);
341 strcpy(metadata
->elements
[elemidx
].Value
,value
);
347 metadata
->num_elements
= elemidx
;
355 int index_times(GribInfo
*gribinfo
, Times
*times
)
365 times
->num_elements
= 0;
367 /* Loop through elements, and build list of times */
369 for (idx
=0; idx
< gribinfo
->num_elements
; idx
++)
371 /* Calculate valid time */
372 status
= rg_get_valid_time(gribinfo
,idx
,valid_time
);
375 fprintf(stderr
,"Could not retrieve valid time for index: %d\n",idx
);
380 * Check if this time is already contained in times
381 * If not, allocate space for it, and add it to list
383 if (find_time(times
,valid_time
) < 0)
385 times
->num_elements
++;
388 realloc(times
->elements
,times
->num_elements
*sizeof(Times_Elements
));
389 if (times
->elements
== NULL
)
391 fprintf(stderr
,"Allocating times->elements failed.\n");
395 strcpy(times
->elements
[times
->num_elements
- 1].valid_time
,valid_time
);
404 for (idx
=1; idx
< times
->num_elements
; idx
++)
406 if (strcmp(times
->elements
[idx
-1].valid_time
,
407 times
->elements
[idx
].valid_time
) > 0)
409 strcpy(tmp
,times
->elements
[idx
-1].valid_time
);
410 strcpy(times
->elements
[idx
-1].valid_time
,
411 times
->elements
[idx
].valid_time
);
412 strcpy(times
->elements
[idx
].valid_time
, tmp
);
423 int find_time(Times
*times
, char valid_time
[15])
428 for (idx
= 0; idx
< times
->num_elements
; idx
++)
430 if (strcmp(times
->elements
[idx
].valid_time
,valid_time
) == 0)
442 int GET_METADATA_VALUE(FileIndex
*fileindex
, char ElementIn
[],
443 char DateStrIn
[], char VarNameIn
[], char Value
[],
444 int *stat
, int strlen1
, int strlen2
, int strlen3
,
445 int strlen4
, int strlen5
)
456 strncpy(Element
,ElementIn
,strlen2
);
457 Element
[strlen2
] = '\0';
458 strncpy(DateStr
,DateStrIn
,strlen3
);
459 DateStr
[strlen3
] = '\0';
460 strncpy(VarName
,VarNameIn
,strlen4
);
461 VarName
[strlen4
] = '\0';
465 for (elemidx
= 0; elemidx
< fileindex
->metadata
->num_elements
; elemidx
++)
467 if (strcmp(Element
,fileindex
->metadata
->elements
[elemidx
].Element
) == 0)
469 if (strcmp(DateStr
,fileindex
->metadata
->elements
[elemidx
].DateStr
)
473 fileindex
->metadata
->elements
[elemidx
].VarName
) == 0)
484 strncpy(Value
, fileindex
->metadata
->elements
[elemnum
].Value
, Value_Len
);
488 strncpy(Value
, "none", Value_Len
);
493 * Pad end of string with one space. This allows Fortran internal
494 * read function to work properly.
496 if (strlen(Value
) < Value_Len
)
498 strcpy(Value
+ strlen(Value
), " ");
505 int GET_GRIB_INDEX(FileIndex
*fileindex
, int *center
, int *subcenter
,
506 int *parmtbl
, int *parmid
, char DateStrIn
[],
507 int *leveltype
, int *level1
, int *level2
, int *fcsttime1
,
508 int *fcsttime2
, int *index
, int strlen1
, int strlen2
)
513 strncpy(DateStr
,DateStrIn
,strlen2
);
514 DateStr
[strlen2
] = '\0';
515 grib_time_format(DateStr
,DateStr
);
517 rg_init_findgrib(&findgrib
);
519 strncpy(findgrib
.initdate
,DateStrIn
,strlen2
);
520 findgrib
.initdate
[strlen2
] = '\0';
521 findgrib
.parmid
= *parmid
;
522 findgrib
.leveltype
= *leveltype
;
523 findgrib
.level1
= *level1
;
524 findgrib
.level2
= *level2
;
525 findgrib
.fcsttime1
= *fcsttime1
;
526 findgrib
.fcsttime2
= *fcsttime2
;
527 findgrib
.center_id
= *center
;
528 findgrib
.subcenter_id
= *subcenter
;
529 findgrib
.parmtbl_version
= *parmtbl
;
531 *index
= rg_get_index(fileindex
->gribinfo
, &findgrib
);
538 int GET_GRIB_INDEX_GUESS(FileIndex
*fileindex
, int *center
, int *subcenter
,
539 int *parmtbl
, int *parmid
, char DateStrIn
[],
540 int *leveltype
, int *level1
, int *level2
,
541 int *fcsttime1
,int *fcsttime2
, int *guessidx
,
542 int *index
, int strlen1
, int strlen2
)
547 strncpy(DateStr
,DateStrIn
,strlen2
);
548 DateStr
[strlen2
] = '\0';
549 grib_time_format(DateStr
,DateStr
);
551 rg_init_findgrib(&findgrib
);
553 strncpy(findgrib
.initdate
,DateStrIn
,strlen2
);
554 findgrib
.initdate
[strlen2
] = '\0';
555 findgrib
.parmid
= *parmid
;
556 findgrib
.leveltype
= *leveltype
;
557 findgrib
.level1
= *level1
;
558 findgrib
.level2
= *level2
;
559 findgrib
.fcsttime1
= *fcsttime1
;
560 findgrib
.fcsttime2
= *fcsttime2
;
561 findgrib
.center_id
= *center
;
562 findgrib
.subcenter_id
= *subcenter
;
563 findgrib
.parmtbl_version
= *parmtbl
;
565 *index
= rg_get_index_guess(fileindex
->gribinfo
, &findgrib
, *guessidx
);
572 int GET_GRIB_CENTER(FileIndex
*fileindex
, int *parmid
, int *center
)
575 *center
= rg_get_center_id(fileindex
->gribinfo
,*parmid
);
582 int GET_GRIB_SUBCENTER(FileIndex
*fileindex
, int *parmid
, int *subcenter
)
585 *subcenter
= rg_get_subcenter_id(fileindex
->gribinfo
,*parmid
);
592 int GET_GRIB_TBLVERSION(FileIndex
*fileindex
, int *parmid
, int *parmtbl
)
595 *parmtbl
= rg_get_parmtbl(fileindex
->gribinfo
,*parmid
);
602 int GET_GRIB_PROCID(FileIndex
*fileindex
, int *parmid
, int *proc_id
)
605 *proc_id
= rg_get_proc_id(fileindex
->gribinfo
,*parmid
);
612 int GET_GRIB_INDEX_VALIDTIME(FileIndex
*fileindex
, int *center
,
613 int *subcenter
, int *parmtbl
, int *parmid
,
614 char DateStrIn
[], int *leveltype
, int *level1
, int *level2
,
615 int *index
, int strlen1
, int strlen2
)
620 strncpy(DateStr
,DateStrIn
,strlen2
);
621 DateStr
[strlen2
] = '\0';
622 grib_time_format(DateStr
,DateStr
);
624 rg_init_findgrib(&findgrib
);
626 strncpy(findgrib
.validdate
,DateStr
,strlen2
);
627 findgrib
.initdate
[strlen2
] = '\0';
628 findgrib
.parmid
= *parmid
;
629 findgrib
.leveltype
= *leveltype
;
630 findgrib
.level1
= *level1
;
631 findgrib
.level2
= *level2
;
632 findgrib
.center_id
= *center
;
633 findgrib
.subcenter_id
= *subcenter
;
634 findgrib
.parmtbl_version
= *parmtbl
;
636 *index
= rg_get_index(fileindex
->gribinfo
, &findgrib
);
642 int GET_GRIB_INDEX_VALIDTIME_GUESS(FileIndex
*fileindex
, int *center
,
643 int *subcenter
, int *parmtbl
, int *parmid
,
644 char DateStrIn
[], int *leveltype
,
645 int *level1
, int *level2
, int *guessidx
,
646 int *index
, int strlen1
, int strlen2
)
651 strncpy(DateStr
,DateStrIn
,strlen2
);
652 DateStr
[strlen2
] = '\0';
653 grib_time_format(DateStr
,DateStr
);
655 rg_init_findgrib(&findgrib
);
657 strncpy(findgrib
.validdate
,DateStr
,strlen2
);
658 findgrib
.initdate
[strlen2
] = '\0';
659 findgrib
.parmid
= *parmid
;
660 findgrib
.leveltype
= *leveltype
;
661 findgrib
.level1
= *level1
;
662 findgrib
.level2
= *level2
;
663 findgrib
.center_id
= *center
;
664 findgrib
.subcenter_id
= *subcenter
;
665 findgrib
.parmtbl_version
= *parmtbl
;
667 *index
= rg_get_index_guess(fileindex
->gribinfo
, &findgrib
, *guessidx
);
673 int GET_GRIB_INDICES(FileIndex
*fileindex
, int *center
, int *subcenter
,
674 int *parmtbl
,int *parmid
, char DateStrIn
[],
675 int *leveltype
, int *level1
, int *level2
, int *fcsttime1
,
676 int *fcsttime2
, int *indices
, int *num_indices
,
677 int strlen1
, int strlen2
)
683 strncpy(DateStr
,DateStrIn
,strlen2
);
684 DateStr
[strlen2
] = '\0';
685 grib_time_format(DateStr
,DateStr
);
687 rg_init_findgrib(&findgrib
);
689 strncpy(findgrib
.initdate
,DateStrIn
,strlen2
);
690 findgrib
.initdate
[strlen2
] = '\0';
691 trim(findgrib
.initdate
);
692 findgrib
.parmid
= *parmid
;
693 findgrib
.leveltype
= *leveltype
;
694 findgrib
.level1
= *level1
;
695 findgrib
.level2
= *level2
;
696 findgrib
.fcsttime1
= *fcsttime1
;
697 findgrib
.fcsttime2
= *fcsttime2
;
698 findgrib
.center_id
= *center
;
699 findgrib
.subcenter_id
= *subcenter
;
700 findgrib
.parmtbl_version
= *parmtbl
;
702 *num_indices
= rg_get_indices(fileindex
->gribinfo
, &findgrib
, indices
);
704 return (*num_indices
);
709 int GET_GRID_INFO_SIZE(int *size
)
712 *size
= sizeof(Grid_Info
);
719 int LOAD_GRID_INFO(char *varnameIn
, char *initdateIn
, int *leveltype
,
720 int *level1
, int *level2
, float *fcst_time
,
721 int *accum_period
, int *grid_id
, int *projection
,
722 int *xpoints
, int *ypoints
, float *center_lat
,
723 float *center_lon
, float *Di
, float *Dj
,float *central_lon
,
724 int *proj_center_flag
, float *latin1
,
725 float *latin2
, Grib1_Tables
*grib_tables
,
726 Grid_Info
*grid_info
, int strlen1
, int strlen2
)
729 char varname
[1000], initdate
[1000];
731 strncpy(varname
,varnameIn
,strlen1
);
732 varname
[strlen1
] = '\0';
733 strncpy(initdate
,initdateIn
,strlen2
);
734 initdate
[strlen2
] = '\0';
736 strcpy(grid_info
->varname
, varname
);
737 strcpy(grid_info
->initdate
, initdate
);
738 grid_info
->leveltype
= *leveltype
;
739 grid_info
->level1
= *level1
;
740 grid_info
->level2
= *level2
;
741 grid_info
->fcst_time
= *fcst_time
;
742 grid_info
->accum_period
= *accum_period
;
743 grid_info
->grid_id
= *grid_id
;
744 grid_info
->projection
= *projection
;
745 grid_info
->xpoints
= *xpoints
;
746 grid_info
->ypoints
= *ypoints
;
747 grid_info
->center_lat
= *center_lat
;
748 grid_info
->center_lon
= *center_lon
;
749 grid_info
->Di
= *Di
;
750 grid_info
->Dj
= *Dj
;
751 grid_info
->central_lon
= *central_lon
;
752 grid_info
->proj_center_flag
= *proj_center_flag
;
753 grid_info
->latin1
= *latin1
;
754 grid_info
->latin2
= *latin2
;
755 grid_info
->grib_tables
= copy_grib_tables(grib_tables
);
761 int PRINT_GRID_INFO(Grid_Info
*grid_info
)
764 fprintf(stdout
,"varname =%s\n",grid_info
->varname
);
765 fprintf(stdout
,"initdate =%s\n",grid_info
->initdate
);
766 fprintf(stdout
,"leveltype =%d\n",grid_info
->leveltype
);
767 fprintf(stdout
,"level1 =%d\n",grid_info
->level1
);
768 fprintf(stdout
,"level2 =%d\n",grid_info
->level2
);
769 fprintf(stdout
,"fcst_time =%f\n",grid_info
->fcst_time
);
770 fprintf(stdout
,"accum_period =%d\n",grid_info
->accum_period
);
771 fprintf(stdout
,"grid_id =%d\n",grid_info
->grid_id
);
772 fprintf(stdout
,"projection =%d\n",grid_info
->projection
);
773 fprintf(stdout
,"xpoints =%d\n",grid_info
->xpoints
);
774 fprintf(stdout
,"ypoints =%d\n",grid_info
->ypoints
);
775 fprintf(stdout
,"center_lat =%f\n",grid_info
->center_lat
);
776 fprintf(stdout
,"center_lon =%f\n",grid_info
->center_lon
);
777 fprintf(stdout
,"Di =%f\n",grid_info
->Di
);
778 fprintf(stdout
,"Dj =%f\n",grid_info
->Dj
);
779 fprintf(stdout
,"central_lon =%f\n",grid_info
->central_lon
);
780 fprintf(stdout
,"proj_center_flag =%d\n",grid_info
->proj_center_flag
);
781 fprintf(stdout
,"latin1 =%f\n",grid_info
->latin1
);
782 fprintf(stdout
,"latin2 =%f\n",grid_info
->latin2
);
789 int GET_SIZEOF_GRID(FileIndex
*fileindex
, int *index
, int *numcols
,
793 *numcols
= rg_get_numcols(fileindex
->gribinfo
,*index
);
795 *numrows
= rg_get_numrows(fileindex
->gribinfo
,*index
);
797 return (*numcols
)*(*numrows
);
802 void FREE_GRID_INFO(Grid_Info
*grid_info
)
804 FREE_GRIBMAP(grid_info
->grib_tables
);
808 int READ_GRIB(FileIndex
*fileindex
, int *fid
, int *index
, float *data
)
812 status
= rg_get_data_1d(fileindex
->gribinfo
,*index
,data
);
819 #define SECS_IN_SEC 1
820 #define SECS_IN_MIN 60
821 #define MINS_IN_HOUR 60
822 #define MINS_IN_5MINS 5
823 #define HOURS_IN_DAY 24
825 #define MAX_FCST 65535
826 #define MAX_FCST_SECS MAX_FCST*SECS_IN_SEC
827 #define MAX_FCST_MINS MAX_FCST*SECS_IN_MIN
828 #define MAX_FCST_5MINS MAX_FCST*MINS_IN_5MINS*SECS_IN_MIN
829 #define MAX_FCST_HOURS MAX_FCST*MINS_IN_HOUR*SECS_IN_MIN
830 #define MAX_FCST_DAYS MAX_FCST*HOURS_IN_DAY*MINS_IN_HOUR*SECS_IN_MIN
832 #define MAX1B_FCST 256
833 #define MAX1B_FCST_SECS MAX1B_FCST*SECS_IN_SEC
834 #define MAX1B_FCST_MINS MAX1B_FCST*SECS_IN_MIN
835 #define MAX1B_FCST_5MINS MAX1B_FCST*MINS_IN_5MINS*SECS_IN_MIN
836 #define MAX1B_FCST_HOURS MAX1B_FCST*MINS_IN_HOUR*SECS_IN_MIN
837 #define MAX1B_FCST_DAYS MAX1B_FCST*HOURS_IN_DAY*MINS_IN_HOUR*SECS_IN_MIN
852 int get_fcst_time(int accum_period
, int fcst_secs
, FcstTimeStruct
*fcst_time
);
854 /****************************************************************************
856 * This function takes in metadata in the grid_info structure, output data in
857 * the *data array, and calls routines to write the metadata and data
858 * in grib version 1 format the open file descriptor filefd.
860 ****************************************************************************/
862 int WRITE_GRIB(Grid_Info
*grid_info
, int *filefd
, float *data
)
866 DATA_INPUT data_input
;
868 USER_INPUT user_input
;
871 float x_center
, y_center
;
873 float first_lat
, first_lon
, last_lat
, last_lon
;
874 int year
, month
, day
, hour
, minute
;
881 int fcst_unit_ext_1
, fcst_unit_ext_2
;
885 int center
, subcenter
, parmtbl
;
888 FcstTimeStruct fcst_time
;
890 strcpy(varname2
,grid_info
->varname
);
893 sscanf(grid_info
->initdate
,"%d-%d-%d_%d:%d:%f",
894 &year
,&month
,&day
,&hour
,&minute
,&second
);
896 /* Get coords of center of grid */
897 x_center
= (grid_info
->xpoints
+ 1)/2.;
898 y_center
= (grid_info
->ypoints
+ 1)/2.;
900 grid_projection
= get_gridnav_projection(grid_info
->projection
);
902 /* Convert grid spacing to degrees for LATLON projection */
904 if ( (grid_info
->projection
== WRF_LATLON
) ||
905 (grid_info
->projection
== WRF_CASSINI
) )
907 dx
= grid_info
->Di
* KM_TO_DEGREES
;
908 dy
= grid_info
->Dj
* KM_TO_DEGREES
;
916 /* Initialize grid structure */
918 status
= GRID_init(grid_info
->center_lat
, grid_info
->central_lon
,
920 grid_info
->latin1
, grid_info
->latin2
,
921 grid_info
->xpoints
, grid_info
->ypoints
,
923 grid_info
->center_lat
, grid_info
->center_lon
,
928 fprintf(stderr
,"write_grib: error from GRID_init\n");
931 /* get lat/lon of lower left corner */
932 status
= GRID_to_latlon(&gridnav
, 1, 1, &first_lat
, &first_lon
);
936 "write_grib: error from GRID_to_latlon for first lat/lon\n");
939 /* get lat/lon of upper right corner */
940 status
= GRID_to_latlon(&gridnav
, grid_info
->xpoints
, grid_info
->ypoints
,
941 &last_lat
, &last_lon
);
945 "write_grib: error from GRID_to_latlon for last lat/lon\n");
948 /* Read the grib parameter table */
949 status
= GET_GRIB_PARAM(grid_info
->grib_tables
, varname2
, ¢er
,
950 &subcenter
, &parmtbl
, &tablenum
, &table_index
,
955 "Skipping %s, Could not find parameter for %s in gribmap.txt\n",\
961 * We skip any parameters that are listed in parameter 255 in gribmap.txt.
962 * Parameter 255 is used to indicate that a WRF parameter should not be
963 * output. It is useful for parameters that are requested to be output in
964 * the WRF Registry, but are already implicitly output in grib.
967 if (table_index
== 255)
973 * Setup the geom_in structure for the grib library. Here, we set
974 * the generic parms. Below, we set the projection specific parms
976 geom_in
.nx
= grid_info
->xpoints
;
977 geom_in
.ny
= grid_info
->ypoints
;
978 geom_in
.first_lat
= first_lat
;
979 geom_in
.first_lon
= first_lon
;
980 geom_in
.last_lat
= last_lat
;
981 geom_in
.last_lon
= last_lon
;
984 switch (grid_info
->projection
)
988 strcpy(geom_in
.prjn_name
,"spherical");
992 geom_in
.usRes_flag
= 0; /*
993 * Set to 0 here, MEL grib library will reset
994 * to 128 to indicate that direction
995 * increments are given.
999 strcpy(geom_in
.prjn_name
,"mercator");
1000 geom_in
.parm_1
= grid_info
->latin1
;
1001 geom_in
.parm_2
= dx
;
1002 geom_in
.parm_3
= dy
;
1003 geom_in
.usRes_flag
= 136;
1006 strcpy(geom_in
.prjn_name
,"lambert");
1007 geom_in
.usRes_flag
= 0; /* Set to 0 here, MEL grib library will reset
1010 geom_in
.parm_3
= grid_info
->central_lon
;
1011 geom_in
.x_int_dis
= dx
;
1012 geom_in
.y_int_dis
= dy
;
1013 geom_in
.parm_1
= grid_info
->latin1
;
1014 geom_in
.parm_2
= grid_info
->latin2
;
1016 case WRF_POLAR_STEREO
:
1017 strcpy(geom_in
.prjn_name
,"polar_stereo");
1018 geom_in
.usRes_flag
= 0; /* Set to 0 here, MEL grib library will reset
1022 geom_in
.parm_3
= -1;
1023 geom_in
.x_int_dis
= dx
*(1.+sin(60. * PI
/180.))
1024 / (1.+sin(abs(grid_info
->latin1
) * PI
/180.));
1025 geom_in
.y_int_dis
= dy
*(1.+sin(60. * PI
/180.))
1026 / (1.+sin(abs(grid_info
->latin1
) * PI
/180.));
1027 geom_in
.parm_1
= -1;
1028 geom_in
.parm_2
= grid_info
->central_lon
;
1031 fprintf(stderr
,"Error, invalid projection: %d\n",grid_info
->projection
);
1036 * Setup the data_input structure.
1038 data_input
.nDec_sc_fctr
=
1039 grid_info
->grib_tables
->grib_table_info
[tablenum
].dec_sc_factor
[table_index
];
1040 data_input
.usProc_id
= 220;
1041 data_input
.usGrid_id
= grid_info
->grid_id
;
1042 data_input
.usParm_id
=
1043 grid_info
->grib_tables
->grib_table_info
[tablenum
].parm_id
[table_index
];
1044 data_input
.usParm_sub_id
=
1045 grid_info
->grib_tables
->grib_table_info
[tablenum
].subcenter
;
1046 data_input
.usLevel_id
= grid_info
->leveltype
;
1048 if (grid_info
->leveltype
== 112) {
1049 data_input
.nLvl_1
= grid_info
->level2
;
1050 data_input
.nLvl_2
= grid_info
->level1
;
1052 data_input
.nLvl_1
= grid_info
->level1
;
1053 data_input
.nLvl_2
= grid_info
->level2
;
1056 data_input
.nYear
= year
;
1057 data_input
.nMonth
= month
;
1058 data_input
.nDay
= day
;
1059 data_input
.nHour
= hour
;
1060 data_input
.nMinute
= minute
;
1061 data_input
.nSecond
= second
;
1063 status
= get_fcst_time(grid_info
->accum_period
, grid_info
->fcst_time
,
1066 data_input
.usFcst_id
= fcst_time
.fcst_unit
;
1067 data_input
.usFcst_per1
= fcst_time
.P1
;
1068 data_input
.usFcst_per2
= fcst_time
.P2
;
1069 data_input
.usTime_range_id
= fcst_time
.time_range
;
1070 data_input
.usTime_range_avg
= 0;
1071 data_input
.usTime_range_mis
= 0;
1073 * This is for WSI's extended PDS section
1075 data_input
.PDS_41
= fcst_time
.fcst_unit_ext_1
;
1076 data_input
.PDS_42
= fcst_time
.P1_ext
;
1077 data_input
.PDS_46
= fcst_time
.fcst_unit_ext_2
;
1078 data_input
.PDS_47
= fcst_time
.P2_ext
;
1079 data_input
.PDS_51
= fcst_time
.time_range_ext
;
1080 data_input
.PDS_52
= 0;
1083 data_input
.nDec_sc_fctr
=
1084 grid_info
->grib_tables
->grib_table_info
[tablenum
].dec_sc_factor
[table_index
];
1085 user_input
.usCenter_id
=
1086 grid_info
->grib_tables
->grib_table_info
[tablenum
].center
;
1087 user_input
.usParm_tbl
=
1088 grid_info
->grib_tables
->grib_table_info
[tablenum
].parmtbl
;
1089 user_input
.chCase_id
='0';
1090 user_input
.usSub_tbl
= 0;
1091 user_input
.usCenter_sub
=
1092 grid_info
->grib_tables
->grib_table_info
[tablenum
].subcenter
;
1093 user_input
.usTrack_num
= 0;
1094 user_input
.usGds_bms_id
= 128;
1095 user_input
.usBDS_flag
= 0;
1096 user_input
.usBit_pack_num
= 0;
1098 status
= init_gribhdr(&gh
,errmsg
);
1100 fprintf (stderr
,"write_grib: Error writing %s: \n\t%s\n",varname2
,errmsg
);
1104 status
= grib_enc(data_input
,user_input
,geom_in
,data
,gh
,errmsg
);
1106 fprintf (stderr
,"write_grib: Error writing %s: \n\t%s\n",varname2
,errmsg
);
1107 fprintf (stderr
,"\tCheck precision for %s in gribmap.txt.\n",
1112 status
= gribhdr2filed(gh
,*filefd
,errmsg
);
1114 fprintf (stderr
,"write_grib: Error writing %s: \n\t%s\n",varname2
,errmsg
);
1123 /***************************************************************************
1124 * Function to set up a structure containing forecast time parameters
1125 * This encodes the standard grib forecast time parameters as well
1126 * as WSI's extended forecast time parameters.
1127 ***************************************************************************/
1129 int get_fcst_time(int accum_period
, int fcst_secs
, FcstTimeStruct
*ft
)
1132 * Added ability to output a "5-minute" forecast time unit for the
1133 * sake of WxProducer. This allows WxPro to ingest data beyond
1134 * 18 hours, and accumulation data beyond 255 units.
1144 ft
->fcst_unit_ext_1
= 0;
1145 ft
->fcst_unit_ext_2
= 0;
1148 ft
->time_range_ext
= 0;
1150 if (accum_period
== 0)
1152 if (fcst_secs
< MAX_FCST_SECS
)
1154 ft
->time_range
= 10;
1155 ft
->fcst_unit
= 254;
1156 ft
->P1
= get_byte(fcst_secs
,2);
1157 ft
->P2
= get_byte(fcst_secs
,1);
1159 else if (((fcst_secs
% SECS_IN_MIN
) == 0) &&
1160 (fcst_secs
< MAX_FCST_MINS
))
1162 ft
->time_range
= 10;
1164 ft
->P1
= get_byte(fcst_secs
/SECS_IN_MIN
,2);
1165 ft
->P2
= get_byte(fcst_secs
/SECS_IN_MIN
,1);
1167 else if (((fcst_secs
% SECS_IN_MIN
*MINS_IN_HOUR
) == 0) &&
1168 (fcst_secs
< MAX_FCST_HOURS
))
1170 ft
->time_range
= 10;
1172 ft
->P1
= get_byte(fcst_secs
/(SECS_IN_MIN
*MINS_IN_HOUR
),2);
1173 ft
->P2
= get_byte(fcst_secs
/(SECS_IN_MIN
*MINS_IN_HOUR
),1);
1176 * MAX_FCST_DAYS is causing an integer overflow, so, we'll just skip
1177 * the check here. It's very unlikely that someone would exceed this
1178 * anyway (5.6 million days!)
1181 else if (((fcst_secs % SECS_IN_MIN*MINS_IN_HOUR*HOURS_IN_DAY) == 0) &&
1182 (fcst_secs < MAX_FCST_DAYS))
1184 else if (((fcst_secs
% SECS_IN_MIN
*MINS_IN_HOUR
*HOURS_IN_DAY
) == 0))
1186 ft
->time_range
= 10;
1189 get_byte(fcst_secs
/(SECS_IN_MIN
*MINS_IN_HOUR
*HOURS_IN_DAY
),2);
1191 get_byte(fcst_secs
/(SECS_IN_MIN
*MINS_IN_HOUR
*HOURS_IN_DAY
),1);
1193 else if (((fcst_secs
% SECS_IN_MIN
*MINS_IN_5MINS
) == 0)
1194 && (fcst_secs
< MAX_FCST_5MINS
))
1196 ft
->time_range
= 10;
1198 ft
->P1
= get_byte(fcst_secs
/(SECS_IN_MIN
*MINS_IN_5MINS
),2);
1199 ft
->P2
= get_byte(fcst_secs
/(SECS_IN_MIN
*MINS_IN_5MINS
),1);
1203 ft
->time_range
= 255;
1208 ft
->fcst_unit_ext_1
= 254;
1209 ft
->fcst_unit_ext_2
= 254;
1210 ft
->P1_ext
= fcst_secs
;
1212 ft
->time_range_ext
= 0;
1215 else /* Accumulation period is not 0 */
1217 if ((fcst_secs
< MAX1B_FCST_HOURS
) &&
1218 (fcst_secs
%(SECS_IN_MIN
*MINS_IN_HOUR
) == 0) &&
1219 (accum_period
%(SECS_IN_MIN
*MINS_IN_HOUR
) == 0))
1223 ft
->P1
= (fcst_secs
-accum_period
)/(SECS_IN_MIN
*MINS_IN_HOUR
);
1224 ft
->P2
= fcst_secs
/(SECS_IN_MIN
*MINS_IN_HOUR
);
1226 else if ((fcst_secs
< MAX1B_FCST_MINS
) &&
1227 ((fcst_secs
-accum_period
)%SECS_IN_MIN
== 0) &&
1228 (fcst_secs
%SECS_IN_MIN
== 0))
1232 ft
->P1
= (fcst_secs
-accum_period
)/SECS_IN_MIN
;
1233 ft
->P2
= fcst_secs
/SECS_IN_MIN
;
1235 else if (fcst_secs
< MAX1B_FCST_SECS
)
1238 ft
->fcst_unit
= 254;
1239 ft
->P1
= fcst_secs
-accum_period
;
1242 else if ((fcst_secs
< MAX1B_FCST_5MINS
) &&
1243 (fcst_secs
%(SECS_IN_MIN
*MINS_IN_5MINS
) == 0) &&
1244 (accum_period
%(SECS_IN_MIN
*MINS_IN_5MINS
) == 0))
1248 ft
->P1
= (fcst_secs
-accum_period
)/(SECS_IN_MIN
*MINS_IN_5MINS
);
1249 ft
->P2
= fcst_secs
/(SECS_IN_MIN
*MINS_IN_5MINS
);
1253 ft
->time_range
= 255;
1258 ft
->fcst_unit_ext_1
= 254;
1259 ft
->fcst_unit_ext_2
= 254;
1260 ft
->P1_ext
= fcst_secs
- accum_period
;
1261 ft
->P2_ext
= accum_period
;
1262 ft
->time_range_ext
= 203; /* Duration */
1269 /******************************************************************************
1270 * returns a byt from an input integer
1271 *****************************************************************************/
1273 int get_byte(int input_int
, int bytenum
)
1276 out
= ((input_int
>> (bytenum
-1)*8) & ~(~0 <<8));
1280 /*************************************************************************
1281 * Converts from WRF time format to time format required by grib routines
1282 *************************************************************************/
1283 int grib_time_format(char *DateStr
, char *DateStrIn
)
1285 int year
,month
,day
,hour
,minute
,second
;
1288 if (DateStrIn
[0] == '*') {
1289 strcpy(DateStr
,"*");
1293 sscanf(DateStrIn
,"%04d-%02d-%02d_%02d:%02d:%02d",
1294 &year
,&month
,&day
,&hour
,&minute
,&second
);
1295 sprintf(DateStr
,"%04d%02d%02d%02d%02d%02d",
1296 year
,month
,day
,hour
,minute
,second
);