| 
     1 #include <stdio.h>  | 
         | 
     2 #include <unistd.h>  | 
         | 
     3 #include <stdlib.h>  | 
         | 
     4 #include <string.h>  | 
         | 
     5 #include <math.h>  | 
         | 
     6 #include "netcdf.h"  | 
         | 
     7   | 
         | 
     8 /*  | 
         | 
     9  * Loop through one month of hourly history tapes from the Community Land Model  | 
         | 
    10  * and generate monthly statistics (means and standard deviations) of fields  | 
         | 
    11  * by hour of day.  | 
         | 
    12  */  | 
         | 
    13   | 
         | 
    14 #define	MEAN_TYPE	0  | 
         | 
    15 #define STDDEV_TYPE	1  | 
         | 
    16 #define NUM_TYPES	2  | 
         | 
    17   | 
         | 
    18 #define HOURS_PER_DAY	24  | 
         | 
    19 #define MIN_PER_HOUR	60  | 
         | 
    20 #define SEC_PER_MIN	60  | 
         | 
    21 #define SEC_PER_HOUR	(MIN_PER_HOUR * SEC_PER_MIN)  | 
         | 
    22   | 
         | 
    23 static char *metadata_vars[] = { | 
         | 
    24 	"lon",  | 
         | 
    25 	"lat",  | 
         | 
    26 	"lonrof",  | 
         | 
    27 	"latrof",  | 
         | 
    28 	"time",  | 
         | 
    29 	"hour", /* new metadata variable to be added to output files */  | 
         | 
    30 	"levsoi",  | 
         | 
    31 	"levlak",  | 
         | 
    32 	"edgen",  | 
         | 
    33 	"edgee",  | 
         | 
    34 	"edges",  | 
         | 
    35 	"edgew",  | 
         | 
    36 	"longxy",  | 
         | 
    37 	"latixy",  | 
         | 
    38 	"area",  | 
         | 
    39 	"areaupsc",  | 
         | 
    40 	"topo",  | 
         | 
    41 	"topodnsc",  | 
         | 
    42 	"landfrac",  | 
         | 
    43 	"landmask",  | 
         | 
    44 	"pftmask",  | 
         | 
    45 	"indxupsc",  | 
         | 
    46 	"mcdate",  | 
         | 
    47 	"mcsec",  | 
         | 
    48 	"mdcur",  | 
         | 
    49 	"mscur",  | 
         | 
    50 	"nstep",  | 
         | 
    51 	"time_bounds",  | 
         | 
    52 	"date_written",  | 
         | 
    53 	"time_written"  | 
         | 
    54 };  | 
         | 
    55   | 
         | 
    56 struct text_att { | 
         | 
    57 	char *name;  | 
         | 
    58 	char *value;  | 
         | 
    59 	struct text_att *next;  | 
         | 
    60 	struct text_att *prev;  | 
         | 
    61 };  | 
         | 
    62   | 
         | 
    63 struct dim { | 
         | 
    64 	int dimid;  | 
         | 
    65 	char *name;  | 
         | 
    66 	size_t len;  | 
         | 
    67 	struct dim *next;  | 
         | 
    68 	struct dim *prev;  | 
         | 
    69 };  | 
         | 
    70   | 
         | 
    71 struct var { | 
         | 
    72 	int ncvarid;  | 
         | 
    73 	char *name;  | 
         | 
    74 	nc_type nctype;  | 
         | 
    75 	int ndims;  | 
         | 
    76 	int *dimids;  | 
         | 
    77 	int natts;  | 
         | 
    78 	char metadata;  | 
         | 
    79 	char FillFlag;  | 
         | 
    80 	float FillValue;  | 
         | 
    81 	struct var *next;  | 
         | 
    82 	struct var *prev;  | 
         | 
    83 };  | 
         | 
    84   | 
         | 
    85 static char *time_name = "time";  | 
         | 
    86 static char *time_bounds_attname = "bounds";  | 
         | 
    87 static char *time_bounds_name = "time_bounds";  | 
         | 
    88 static char *climatology_bounds_attname = "climatology";  | 
         | 
    89 static char *climatology_bounds_name = "climatology_bounds";  | 
         | 
    90 static char *mcdate_name = "mcdate";  | 
         | 
    91 static char *mcsec_name = "mcsec";  | 
         | 
    92 static char *history_name = "history";  | 
         | 
    93 static char *nsamples_name = "nsamples";  | 
         | 
    94 static char *cell_method_name = "cell_method";  | 
         | 
    95 static char *cell_methods_prefix[] = { "time: mean within days time: mean over days", "time: mean within days times: standard_deviation over days" }; | 
         | 
    96 /* input stuff */  | 
         | 
    97 static int nmvars = sizeof(metadata_vars)/sizeof(*metadata_vars);  | 
         | 
    98 static int input_ncid, input_ndims, input_nvars, input_ngatts, input_unlimdimid;  | 
         | 
    99 static struct text_att *input_gatt_head = NULL;  | 
         | 
   100 static struct dim *input_dim_head = NULL, **input_dim_idx;  | 
         | 
   101 static struct var *input_var_head = NULL;  | 
         | 
   102 /* translation stuff */  | 
         | 
   103 static int *idid2mdid, *idid2sdid; /* dimension IDs */  | 
         | 
   104 /* output stuff */  | 
         | 
   105 static int mean_ncid, mean_ndims, mean_nvars, mean_ngatts, mean_unlimdimid;  | 
         | 
   106 static struct dim *mean_dim_head = NULL;  | 
         | 
   107 static struct var *mean_var_head = NULL;  | 
         | 
   108 static int stddev_ncid, stddev_ndims, stddev_nvars, stddev_ngatts, stddev_unlimdimid;  | 
         | 
   109 static struct dim *stddev_dim_head = NULL;  | 
         | 
   110 static struct var *stddev_var_head = NULL;  | 
         | 
   111 /* output values */  | 
         | 
   112 static double *times;  | 
         | 
   113 static double *tbounds;  | 
         | 
   114 static int *mcdate;  | 
         | 
   115 static int *mcsec;  | 
         | 
   116   | 
         | 
   117 char is_metadata(char *name)  | 
         | 
   118 { | 
         | 
   119 	int i;  | 
         | 
   120   | 
         | 
   121 	for (i = 0; i < nmvars && strcmp(name, metadata_vars[i]); i++);  | 
         | 
   122   | 
         | 
   123 	if (i < nmvars)  | 
         | 
   124 		return 1;  | 
         | 
   125 	else  | 
         | 
   126 		return 0;  | 
         | 
   127 }  | 
         | 
   128   | 
         | 
   129 #if 0  | 
         | 
   130 struct dim *dimlist_find_by_name(struct dim *head, char *name)  | 
         | 
   131 { | 
         | 
   132 	int i;  | 
         | 
   133 	struct dim *p = NULL;  | 
         | 
   134   | 
         | 
   135 	if (head) { | 
         | 
   136 		node = head;  | 
         | 
   137 		for (i = 0 ; i == 0 || node != head; i++) { | 
         | 
   138 			if (!strcmp(node->name, name))  | 
         | 
   139 				p = node;  | 
         | 
   140 			node = node->next;  | 
         | 
   141 		}  | 
         | 
   142 		return p;  | 
         | 
   143 	}  | 
         | 
   144 	else  | 
         | 
   145 		return NULL;  | 
         | 
   146 }  | 
         | 
   147 #endif  | 
         | 
   148   | 
         | 
   149 struct var *varlist_find_by_name(struct var *head, char *name)  | 
         | 
   150 { | 
         | 
   151 	int i;  | 
         | 
   152 	struct var *node;  | 
         | 
   153   | 
         | 
   154 	if (head) { | 
         | 
   155 		node = head;  | 
         | 
   156 		for (i = 0 ; (i == 0 || node != head) && strcmp(node->name, name); i++)  | 
         | 
   157 			node = node->next;  | 
         | 
   158 		if (i && node == head)  | 
         | 
   159 			return NULL;  | 
         | 
   160 		else  | 
         | 
   161 			return node;  | 
         | 
   162 	}  | 
         | 
   163 	else  | 
         | 
   164 		return NULL;  | 
         | 
   165 }  | 
         | 
   166   | 
         | 
   167 void gattlist_add_node(struct text_att **headp, char *name, char *value)  | 
         | 
   168 { | 
         | 
   169 	struct text_att *head, *node;  | 
         | 
   170   | 
         | 
   171 	head = *headp;  | 
         | 
   172   | 
         | 
   173 	if (!(node = (struct text_att *)malloc(sizeof(struct text_att)))) { | 
         | 
   174 		perror("gattlist_add_node"); | 
         | 
   175 		exit(2);  | 
         | 
   176 	}  | 
         | 
   177   | 
         | 
   178 	if (!(node->name = strdup(name))) { | 
         | 
   179 		perror("gattlist_add_node"); | 
         | 
   180 		exit(2);  | 
         | 
   181 	}  | 
         | 
   182 	if (!(node->value = strdup(value))) { | 
         | 
   183 		perror("gattlist_add_node"); | 
         | 
   184 		exit(2);  | 
         | 
   185 	}  | 
         | 
   186   | 
         | 
   187 	if (head == NULL) { | 
         | 
   188 		/* first one */  | 
         | 
   189 		*headp = node;  | 
         | 
   190 		node->next = node;  | 
         | 
   191 		node->prev = node;  | 
         | 
   192 	}  | 
         | 
   193 	else { | 
         | 
   194 		node->next = head;  | 
         | 
   195 		node->prev = head->prev;  | 
         | 
   196 		/* set this after setting node->prev from here */  | 
         | 
   197 		head->prev = node;  | 
         | 
   198 		/* set this after having set node->prev */  | 
         | 
   199 		node->prev->next = node;  | 
         | 
   200 	}  | 
         | 
   201   | 
         | 
   202 	return;  | 
         | 
   203 }  | 
         | 
   204   | 
         | 
   205 struct dim *dimlist_add_node(struct dim **headp, int dimid, char *name, size_t len)  | 
         | 
   206 { | 
         | 
   207 	struct dim *head, *node;  | 
         | 
   208   | 
         | 
   209 	head = *headp;  | 
         | 
   210   | 
         | 
   211 	if (!(node = (struct dim *)malloc(sizeof(struct dim)))) { | 
         | 
   212 		perror("dimlist_add_node"); | 
         | 
   213 		exit(2);  | 
         | 
   214 	}  | 
         | 
   215   | 
         | 
   216 	node->dimid = dimid;  | 
         | 
   217 	if (!(node->name = strdup(name))) { | 
         | 
   218 		perror("dimlist_add_node"); | 
         | 
   219 		exit(2);  | 
         | 
   220 	}  | 
         | 
   221 	node->len = len;  | 
         | 
   222 	  | 
         | 
   223 	if (head == NULL) { | 
         | 
   224 		/* first one */  | 
         | 
   225 		*headp = node;  | 
         | 
   226 		node->next = node;  | 
         | 
   227 		node->prev = node;  | 
         | 
   228 	}  | 
         | 
   229 	else { | 
         | 
   230 		node->next = head;  | 
         | 
   231 		node->prev = head->prev;  | 
         | 
   232 		/* set this after setting node->prev from here */  | 
         | 
   233 		head->prev = node;  | 
         | 
   234 		/* set this after having set node->prev */  | 
         | 
   235 		node->prev->next = node;  | 
         | 
   236 	}  | 
         | 
   237   | 
         | 
   238 	return node;  | 
         | 
   239 }  | 
         | 
   240   | 
         | 
   241 void varlist_add_node(struct var **headp, int ncvarid, char *name,  | 
         | 
   242 	nc_type nctype, int ndims, int *dimids, int natts, char FillFlag,  | 
         | 
   243 	float FillValue)  | 
         | 
   244 { | 
         | 
   245 	int i;  | 
         | 
   246 	struct var *head, *node;  | 
         | 
   247   | 
         | 
   248 	head = *headp;  | 
         | 
   249   | 
         | 
   250 	if (!(node = (struct var *)malloc(sizeof(struct var)))) { | 
         | 
   251 		perror("varlist_add_node"); | 
         | 
   252 		exit(3);  | 
         | 
   253 	}  | 
         | 
   254   | 
         | 
   255 	node->ncvarid = ncvarid;  | 
         | 
   256 	if (!(node->name = strdup(name))) { | 
         | 
   257 		perror("varlist_add_node"); | 
         | 
   258 		exit(3);  | 
         | 
   259 	}  | 
         | 
   260 	node->nctype = nctype;  | 
         | 
   261 	node->ndims = ndims;  | 
         | 
   262 	if (!(node->dimids = (int *)malloc(ndims * sizeof(int)))) { | 
         | 
   263 		perror("varlist_add_node"); | 
         | 
   264 		exit(3);  | 
         | 
   265 	}  | 
         | 
   266 	for (i = 0; i < ndims; i++) node->dimids[i] = dimids[i];  | 
         | 
   267 	node->natts = natts;  | 
         | 
   268 	node->metadata = is_metadata(name);  | 
         | 
   269 	node->FillFlag = FillFlag;  | 
         | 
   270 	node->FillValue = FillValue;  | 
         | 
   271 	  | 
         | 
   272 	if (head == NULL) { | 
         | 
   273 		/* first one */  | 
         | 
   274 		*headp = node;  | 
         | 
   275 		node->next = node;  | 
         | 
   276 		node->prev = node;  | 
         | 
   277 	}  | 
         | 
   278 	else { | 
         | 
   279 		node->next = head;  | 
         | 
   280 		node->prev = head->prev;  | 
         | 
   281 		/* set this after setting node->prev from here */  | 
         | 
   282 		head->prev = node;  | 
         | 
   283 		/* set this after having set node->prev */  | 
         | 
   284 		node->prev->next = node;  | 
         | 
   285 	}  | 
         | 
   286   | 
         | 
   287 	return;  | 
         | 
   288 }  | 
         | 
   289   | 
         | 
   290 void varlist_print(struct var *headp)  | 
         | 
   291 { | 
         | 
   292 	int i, j;  | 
         | 
   293 	struct var *node;  | 
         | 
   294   | 
         | 
   295 	printf("Beginning of Variable List\n"); | 
         | 
   296   | 
         | 
   297 	if (headp) { | 
         | 
   298 		node = headp;  | 
         | 
   299 		for (j = 0; j == 0 || node != headp; j++) { | 
         | 
   300 			printf("Variable %d (ptr=%ld):\n", j, (long)node); | 
         | 
   301 			printf("\tncvarid = %d\n", node->ncvarid); | 
         | 
   302 			printf("\tname = %s\n",  node->name); | 
         | 
   303 			printf("\tnctype = %d\n", node->nctype); | 
         | 
   304 			printf("\tndims = %d\n", node->ndims); | 
         | 
   305 			printf("\tdimids ="); | 
         | 
   306 			for (i = 0; i < node->ndims; i++)  | 
         | 
   307 				printf(" %d", node->dimids[i]); | 
         | 
   308 			printf("\n"); | 
         | 
   309 			printf("\tnatts = %d\n", node->natts); | 
         | 
   310 			printf("\tmetadata = %d\n", (int)node->metadata); | 
         | 
   311 			printf("\tnext = %ld\n", (long)node->next); | 
         | 
   312 			printf("\tprev = %ld\n", (long)node->prev); | 
         | 
   313 			node = node->next;  | 
         | 
   314 		}  | 
         | 
   315 	}  | 
         | 
   316 	else { | 
         | 
   317 		printf("\tList undefined\n"); | 
         | 
   318 	}  | 
         | 
   319   | 
         | 
   320 	printf("End of Variable List\n"); | 
         | 
   321   | 
         | 
   322 	return;  | 
         | 
   323 }  | 
         | 
   324   | 
         | 
   325 void wrap_nc(int status)  | 
         | 
   326 { | 
         | 
   327 	if (status != NC_NOERR) { | 
         | 
   328 		fprintf(stderr, "netCDF error: %s\n", nc_strerror(status));  | 
         | 
   329 		exit(1);  | 
         | 
   330 	}  | 
         | 
   331   | 
         | 
   332 	return;  | 
         | 
   333 }  | 
         | 
   334   | 
         | 
   335 void get_dimensions(int ncid, int ndims, struct dim **dim_headp, struct dim ***in_dim_idxp)  | 
         | 
   336 { | 
         | 
   337 	int i;  | 
         | 
   338 	char name[NC_MAX_NAME+1];  | 
         | 
   339 	size_t len;  | 
         | 
   340 	struct dim **in_dim_idx;  | 
         | 
   341   | 
         | 
   342 	if (!(*in_dim_idxp = (struct dim **)malloc(ndims * sizeof(struct dim *)))) { | 
         | 
   343 		perror("*in_dim_idxp"); | 
         | 
   344 		exit(3);  | 
         | 
   345 	}  | 
         | 
   346 	in_dim_idx = *in_dim_idxp;  | 
         | 
   347   | 
         | 
   348 	for (i = 0; i < ndims; i++) { | 
         | 
   349 		wrap_nc(nc_inq_dim(ncid, i, name, &len));  | 
         | 
   350 		in_dim_idx[i] = dimlist_add_node(dim_headp, i, name, len);  | 
         | 
   351 	}  | 
         | 
   352   | 
         | 
   353 	return;  | 
         | 
   354 }  | 
         | 
   355 void get_gatts(int ncid, int ngatts, struct text_att **gatt_headp)  | 
         | 
   356 { | 
         | 
   357 	int i;  | 
         | 
   358 	char name[NC_MAX_NAME+1], *value;  | 
         | 
   359 	nc_type xtype;  | 
         | 
   360 	size_t len;  | 
         | 
   361   | 
         | 
   362 	for (i = 0; i < ngatts; i++) { | 
         | 
   363 		wrap_nc(nc_inq_attname(ncid, NC_GLOBAL, i, name));  | 
         | 
   364 		wrap_nc(nc_inq_att(ncid, NC_GLOBAL, name, &xtype, &len));  | 
         | 
   365 		if (xtype != NC_CHAR) { | 
         | 
   366 			fprintf(stderr, "Global attribute %s is not of type NC_CHAR\n", name);  | 
         | 
   367 			exit(2);  | 
         | 
   368 		}  | 
         | 
   369 		if (!(value = (char *)malloc((len+1)*sizeof(char)))) { | 
         | 
   370 			perror("get_gatts: value"); | 
         | 
   371 			exit(3);  | 
         | 
   372 		}  | 
         | 
   373 		wrap_nc(nc_get_att_text(ncid, NC_GLOBAL, name, value));  | 
         | 
   374 		value[(len+1-1)] = '\0';  | 
         | 
   375 		gattlist_add_node(gatt_headp, name, value);  | 
         | 
   376 		free(value); /* because gattlist_add_node() duplicates it */  | 
         | 
   377 	}  | 
         | 
   378   | 
         | 
   379 	return;  | 
         | 
   380 }  | 
         | 
   381   | 
         | 
   382 void get_vars(int ncid, int nvars, struct var **var_headp)  | 
         | 
   383 { | 
         | 
   384 	int i, ndims, dimids[NC_MAX_VAR_DIMS], natts;  | 
         | 
   385 	size_t len;  | 
         | 
   386 	float FillValue;  | 
         | 
   387 	char name[NC_MAX_NAME+1], *fill_att_name = "_FillValue", FillFlag;  | 
         | 
   388 	nc_type xtype, atype;  | 
         | 
   389   | 
         | 
   390 	for (i = 0; i < nvars; i++) { | 
         | 
   391 		wrap_nc(nc_inq_var(ncid, i, name, &xtype, &ndims, dimids,  | 
         | 
   392 			&natts));  | 
         | 
   393 		/* Check for _FillValue */  | 
         | 
   394 		FillFlag = 0;  | 
         | 
   395 		FillValue = 0.;  | 
         | 
   396 		if (nc_inq_att(ncid, i, fill_att_name, &atype, &len)  | 
         | 
   397 			== NC_NOERR) { | 
         | 
   398 			if (atype == NC_FLOAT && len) { | 
         | 
   399 				wrap_nc(nc_get_att_float(ncid, i,  | 
         | 
   400 					fill_att_name, &FillValue));  | 
         | 
   401 				FillFlag = 1;  | 
         | 
   402 			}  | 
         | 
   403 		}  | 
         | 
   404 		varlist_add_node(var_headp, i, name, xtype, ndims, dimids,  | 
         | 
   405 			natts, FillFlag, FillValue);  | 
         | 
   406 	}  | 
         | 
   407   | 
         | 
   408 	return;  | 
         | 
   409 }  | 
         | 
   410   | 
         | 
   411 int put_dimensions(struct dim *in_dim_head, int in_ndims, int in_unlimdimid,  | 
         | 
   412 	size_t nsamples, int **in2outp, int out_ncid,  | 
         | 
   413 	struct dim **out_dim_headp, int *out_unlimdimidp)  | 
         | 
   414 { | 
         | 
   415 	/*  | 
         | 
   416 	 * Define dimensions on new files and build translation tables between  | 
         | 
   417 	 * dimension IDs.  | 
         | 
   418 	 */  | 
         | 
   419 	int j, dimid, ndims, *in2out;  | 
         | 
   420 	size_t len;  | 
         | 
   421 	struct dim *dnode;  | 
         | 
   422   | 
         | 
   423 	ndims = 0;  | 
         | 
   424   | 
         | 
   425 	if (!(*in2outp = (int *)malloc((in_ndims+1)*sizeof(int)))) { | 
         | 
   426 		perror("put_dimensions:in2outp"); | 
         | 
   427 		exit(3);  | 
         | 
   428 	}  | 
         | 
   429 	in2out = *in2outp;  | 
         | 
   430   | 
         | 
   431 	if (in_dim_head) { | 
         | 
   432 		dnode = in_dim_head;  | 
         | 
   433 		for (j = 0; j == 0 || dnode != in_dim_head; j++) { | 
         | 
   434 			if (dnode->dimid == in_unlimdimid)  | 
         | 
   435 				len = NC_UNLIMITED;  | 
         | 
   436 			else  | 
         | 
   437 				len = dnode->len;  | 
         | 
   438 			wrap_nc(nc_def_dim(out_ncid, dnode->name, len, &dimid));  | 
         | 
   439 			dimlist_add_node(out_dim_headp, dimid, dnode->name, len);  | 
         | 
   440 			++ndims;  | 
         | 
   441 			in2out[dnode->dimid] = dimid;  | 
         | 
   442 			if (dnode->dimid == in_unlimdimid)  | 
         | 
   443 				*out_unlimdimidp = dimid;  | 
         | 
   444 			/* Just after the "time" dimension, add the new  | 
         | 
   445 			 * "nsamples" dimension. */  | 
         | 
   446 			if (!strcmp(dnode->name, time_name)) { | 
         | 
   447 				wrap_nc(nc_def_dim(out_ncid, nsamples_name, nsamples, &dimid));  | 
         | 
   448 				dimlist_add_node(out_dim_headp, dimid, nsamples_name, nsamples);  | 
         | 
   449 				++ndims;  | 
         | 
   450 			}  | 
         | 
   451 			dnode = dnode->next;  | 
         | 
   452 		}  | 
         | 
   453 	}  | 
         | 
   454 	else { | 
         | 
   455 		fprintf(stderr, "WARNING: No dimensions defined!\n");  | 
         | 
   456 	}  | 
         | 
   457   | 
         | 
   458 	return ndims;  | 
         | 
   459 }  | 
         | 
   460   | 
         | 
   461 int put_gatts(struct text_att *in_gatt_head, int out_ncid, char *out_history)  | 
         | 
   462 { | 
         | 
   463 	/*  | 
         | 
   464 	 * Write out global attributes matching those of the input file.  | 
         | 
   465 	 * Change history attribute to the string passed in as an argument.  | 
         | 
   466 	 */  | 
         | 
   467 	int j, hflag = 0, ngatts;  | 
         | 
   468 	char *value;  | 
         | 
   469 	struct text_att *anode;  | 
         | 
   470   | 
         | 
   471 	ngatts = 0;  | 
         | 
   472   | 
         | 
   473 	if (in_gatt_head) { | 
         | 
   474 		anode = in_gatt_head;  | 
         | 
   475 		for (j = 0; j == 0 || anode != in_gatt_head; j++) { | 
         | 
   476 			if (!strcmp(anode->name, history_name)) { | 
         | 
   477 				value = out_history;  | 
         | 
   478 				++hflag;  | 
         | 
   479 			}  | 
         | 
   480 			else  | 
         | 
   481 				value = anode->value;  | 
         | 
   482 			wrap_nc(nc_put_att_text(out_ncid, NC_GLOBAL, anode->name, strlen(value), value));  | 
         | 
   483 			++ngatts;  | 
         | 
   484 			anode = anode->next;  | 
         | 
   485 		}  | 
         | 
   486 		/* If no history attribute on input, add one to the output */  | 
         | 
   487 		if (!hflag) { | 
         | 
   488 			wrap_nc(nc_put_att_text(out_ncid, NC_GLOBAL, history_name, strlen(out_history), out_history));  | 
         | 
   489 			++ngatts;  | 
         | 
   490 		}  | 
         | 
   491 	}  | 
         | 
   492 	else { | 
         | 
   493 		fprintf(stderr, "WARNING: No global attributes defined!\n");  | 
         | 
   494 	}  | 
         | 
   495   | 
         | 
   496 	return ngatts;  | 
         | 
   497 }  | 
         | 
   498   | 
         | 
   499 int translate_dimids(int in_ndims, int *in_dimids, int *in2out, int *out_dimids)  | 
         | 
   500 { | 
         | 
   501 	/*  | 
         | 
   502 	 * Translate between input dimension IDs and those for the output file.  | 
         | 
   503 	 */  | 
         | 
   504 	int i, ndims;  | 
         | 
   505   | 
         | 
   506 	for (i = ndims = 0; i < in_ndims; i++, ndims++)  | 
         | 
   507 		out_dimids[ndims] = in2out[in_dimids[i]];  | 
         | 
   508   | 
         | 
   509 	return ndims;  | 
         | 
   510 }  | 
         | 
   511   | 
         | 
   512 int copy_att(char metadata, int stat_type, int in_natts, int in_ncid,  | 
         | 
   513 	int in_varid, int out_ncid, int out_varid, char **cell_methods)  | 
         | 
   514 { | 
         | 
   515 	/*   | 
         | 
   516 	 * Copy the attributes of the input variable to those of the output  | 
         | 
   517 	 * variable. If the variable is not a metadata variable, ensure that  | 
         | 
   518 	 * the cell_method attribute is set correctly, depending on the output  | 
         | 
   519 	 * file type.  | 
         | 
   520 	 */  | 
         | 
   521   | 
         | 
   522 	int i, natts;  | 
         | 
   523 	char name[NC_MAX_NAME+1], cmflag = 0;  | 
         | 
   524   | 
         | 
   525 	for (i = natts = 0; i < in_natts; i++, natts++) { | 
         | 
   526 		wrap_nc(nc_inq_attname(in_ncid, in_varid, i, name));  | 
         | 
   527 		if (!strcmp(name, cell_method_name) && !metadata) { | 
         | 
   528 			wrap_nc(nc_put_att_text(out_ncid, out_varid, cell_method_name, strlen(cell_methods[stat_type]), cell_methods[stat_type]));  | 
         | 
   529 			cmflag = 1;  | 
         | 
   530 		}  | 
         | 
   531 		else if (!strcmp(name, time_bounds_attname))  | 
         | 
   532 			/* Change time_bounds to climatology_bounds */  | 
         | 
   533 			wrap_nc(nc_put_att_text(out_ncid, out_varid, climatology_bounds_attname, strlen(climatology_bounds_name), climatology_bounds_name));  | 
         | 
   534 		else  | 
         | 
   535 			wrap_nc(nc_copy_att(in_ncid, in_varid, name, out_ncid, out_varid));  | 
         | 
   536 	}  | 
         | 
   537 	/*  | 
         | 
   538 	 * If no cell_method attribute was specified for a non-metadata  | 
         | 
   539 	 * variable on the input file, add the appropriate cell_method anyway  | 
         | 
   540 	 * on the output file.  | 
         | 
   541 	 */  | 
         | 
   542 	if (!cmflag && !metadata) { | 
         | 
   543 		wrap_nc(nc_put_att_text(out_ncid, out_varid, cell_method_name, strlen(cell_methods[stat_type]), cell_methods[stat_type]));  | 
         | 
   544 		natts++;  | 
         | 
   545 	}  | 
         | 
   546   | 
         | 
   547 	return natts;  | 
         | 
   548 }  | 
         | 
   549   | 
         | 
   550 int define_vars(int in_ncid, struct dim **in_dim_idx, struct var *in_var_head,  | 
         | 
   551 	int *in2out, int out_ncid, struct var **out_var_headp,  | 
         | 
   552 	char **cell_methods, int stat_type)  | 
         | 
   553 { | 
         | 
   554 	/*  | 
         | 
   555 	 * Define variables on output file and copy attributes from input file.  | 
         | 
   556 	 * Return number of variables defined.  | 
         | 
   557 	 */  | 
         | 
   558 	int j, varid, nvars, ndims, dimids[NC_MAX_VAR_DIMS], natts;  | 
         | 
   559 	struct var *vnode;  | 
         | 
   560   | 
         | 
   561 	nvars = 0;  | 
         | 
   562   | 
         | 
   563 	if (in_var_head) { | 
         | 
   564 		vnode = in_var_head;  | 
         | 
   565 		/*  | 
         | 
   566 		 * March through input variables creating (mostly) the same  | 
         | 
   567 		 * variables on the output file.  | 
         | 
   568 		 */  | 
         | 
   569 		for (j = 0; j == 0 || vnode != in_var_head; j++) { | 
         | 
   570 			ndims = translate_dimids(vnode->ndims, vnode->dimids, in2out, dimids);  | 
         | 
   571 			/* Create all normal data variables, but only the four  | 
         | 
   572 			 * time-based metadata variables: time,  | 
         | 
   573 			 * climatology_bounds, mcdate, and mcsec. */  | 
         | 
   574 			if (!strcmp(vnode->name, time_name)) { | 
         | 
   575 				/* Magically promote "time" variable to  | 
         | 
   576 				 * double precision on output file */  | 
         | 
   577 				wrap_nc(nc_def_var(out_ncid, vnode->name, NC_DOUBLE, ndims, dimids, &varid));  | 
         | 
   578 				natts = copy_att(vnode->metadata, stat_type, vnode->natts, in_ncid, vnode->ncvarid, out_ncid, varid, cell_methods);  | 
         | 
   579 				varlist_add_node(out_var_headp, varid, vnode->name, NC_DOUBLE, ndims, dimids, natts, vnode->FillFlag, vnode->FillValue);  | 
         | 
   580 				++nvars;  | 
         | 
   581 				/* Create "climatology_bounds" right after  | 
         | 
   582 				 * time and instead of "time_bounds", with no  | 
         | 
   583 				 * attributes */  | 
         | 
   584 				wrap_nc(nc_def_var(out_ncid, climatology_bounds_name, NC_DOUBLE, ndims, dimids, &varid));  | 
         | 
   585 				natts = 0;  | 
         | 
   586 				varlist_add_node(out_var_headp, varid, climatology_bounds_name, NC_DOUBLE, ndims, dimids, natts, vnode->FillFlag, vnode->FillValue);  | 
         | 
   587 				++nvars;  | 
         | 
   588 			}  | 
         | 
   589 			else if (!vnode->metadata || !strcmp(vnode->name, mcdate_name) || !strcmp(vnode->name, mcsec_name) || (vnode->metadata && strcmp((in_dim_idx[vnode->dimids[0]])->name, time_name))) { | 
         | 
   590 				/* If it is not a metadata variable OR it is  | 
         | 
   591 				 * mcdate OR it is mcsec OR (it is a metadata  | 
         | 
   592 				 * variable that does not have time as its  | 
         | 
   593 				 * first dimension), then create it */  | 
         | 
   594 				wrap_nc(nc_def_var(out_ncid, vnode->name, vnode->nctype, ndims, dimids, &varid));  | 
         | 
   595 				natts = copy_att(vnode->metadata, stat_type, vnode->natts, in_ncid, vnode->ncvarid, out_ncid, varid, cell_methods);  | 
         | 
   596 				varlist_add_node(out_var_headp, varid, vnode->name, vnode->nctype, ndims, dimids, natts, vnode->FillFlag, vnode->FillValue);  | 
         | 
   597 				++nvars;  | 
         | 
   598 			}  | 
         | 
   599 			vnode = vnode->next;  | 
         | 
   600 		}  | 
         | 
   601 	}  | 
         | 
   602 	else { | 
         | 
   603 		fprintf(stderr, "WARNING: No variables defined!\n");  | 
         | 
   604 	}  | 
         | 
   605   | 
         | 
   606 	return nvars;  | 
         | 
   607 }  | 
         | 
   608   | 
         | 
   609 void *alloc_var(nc_type nctype, size_t len)  | 
         | 
   610 { | 
         | 
   611 	void *val;  | 
         | 
   612   | 
         | 
   613 	switch (nctype) { | 
         | 
   614 		case NC_FLOAT:  | 
         | 
   615 			if (!(val = (float *)malloc((len) * sizeof(float)))) { | 
         | 
   616 				perror("alloc_var: val"); | 
         | 
   617 				exit(3);  | 
         | 
   618 			}  | 
         | 
   619 			break;  | 
         | 
   620 		case NC_INT:  | 
         | 
   621 			if (!(val = (int *)malloc((len) * sizeof(int)))) { | 
         | 
   622 				perror("alloc_var: val"); | 
         | 
   623 				exit(3);  | 
         | 
   624 			}  | 
         | 
   625 			break;  | 
         | 
   626 		case NC_DOUBLE:  | 
         | 
   627 			if (!(val = (double *)malloc((len) * sizeof(double)))) { | 
         | 
   628 				perror("alloc_var: val"); | 
         | 
   629 				exit(3);  | 
         | 
   630 			}  | 
         | 
   631 			break;  | 
         | 
   632 		case NC_CHAR:  | 
         | 
   633 			if (!(val = (char *)malloc(((len)+1) * sizeof(char)))) { | 
         | 
   634 				perror("alloc_var: val"); | 
         | 
   635 				exit(3);  | 
         | 
   636 			}  | 
         | 
   637 			break;  | 
         | 
   638 		default:  | 
         | 
   639 			fprintf(stderr, "netCDF external data type %d not supported\n", nctype);  | 
         | 
   640 			exit(3);  | 
         | 
   641 	}  | 
         | 
   642   | 
         | 
   643 	return val;  | 
         | 
   644 }  | 
         | 
   645   | 
         | 
   646 void *read_var(int ncid, int varid, nc_type nctype, int ndims, int *dimids, struct dim **dim_idx)  | 
         | 
   647 { | 
         | 
   648 	int i;  | 
         | 
   649 	size_t len = (size_t)1;  | 
         | 
   650 	void *val;  | 
         | 
   651   | 
         | 
   652 	/* Figure out the total size */  | 
         | 
   653 	for (i = 0; i < ndims; i++) len *= (dim_idx[dimids[i]])->len;  | 
         | 
   654   | 
         | 
   655 	val = alloc_var(nctype, len);  | 
         | 
   656   | 
         | 
   657 	switch (nctype) { | 
         | 
   658 		case NC_FLOAT:  | 
         | 
   659 			wrap_nc(nc_get_var_float(ncid, varid, val));  | 
         | 
   660 			break;  | 
         | 
   661 		case NC_INT:  | 
         | 
   662 			wrap_nc(nc_get_var_int(ncid, varid, val));  | 
         | 
   663 			break;  | 
         | 
   664 		case NC_DOUBLE:  | 
         | 
   665 			wrap_nc(nc_get_var_double(ncid, varid, val));  | 
         | 
   666 			break;  | 
         | 
   667 		case NC_CHAR:  | 
         | 
   668 			wrap_nc(nc_get_var_text(ncid, varid, val));  | 
         | 
   669 			break;  | 
         | 
   670 		default:  | 
         | 
   671 			fprintf(stderr, "netCDF external data type %d not supported\n", nctype);  | 
         | 
   672 			exit(3);  | 
         | 
   673 	}  | 
         | 
   674   | 
         | 
   675 	return val;  | 
         | 
   676 }  | 
         | 
   677   | 
         | 
   678 void *read_timeslice(int ncid, int varid, nc_type nctype, int ndims, int *dimids, struct dim **dim_idx, size_t tslice)  | 
         | 
   679 { | 
         | 
   680 	int i;  | 
         | 
   681 	size_t len = (size_t)1, start[NC_MAX_VAR_DIMS], count[NC_MAX_VAR_DIMS];  | 
         | 
   682 	void *val;  | 
         | 
   683   | 
         | 
   684 	/* Make sure time is really the first dimension */  | 
         | 
   685 	if (strcmp((dim_idx[dimids[0]])->name, time_name)) { | 
         | 
   686 		fprintf(stderr, "read_timeslice: %s is not first dimension of variable!\n", time_name);  | 
         | 
   687 		exit(3);  | 
         | 
   688 	}   | 
         | 
   689 	/*  | 
         | 
   690 	 * Figure out the total size for the slice (start at second dimension)  | 
         | 
   691 	 * and build start/count vectors.  | 
         | 
   692 	 */  | 
         | 
   693 	start[0] = tslice;  | 
         | 
   694 	count[0] = 1;  | 
         | 
   695 	for (i = 1; i < ndims; i++) { | 
         | 
   696 		start[i] = 0;  | 
         | 
   697 		count[i] = (dim_idx[dimids[i]])->len;  | 
         | 
   698 		len *= (dim_idx[dimids[i]])->len;  | 
         | 
   699 	}  | 
         | 
   700   | 
         | 
   701 	val = alloc_var(nctype, len);  | 
         | 
   702 	  | 
         | 
   703 	switch (nctype) { | 
         | 
   704 		case NC_FLOAT:  | 
         | 
   705 			wrap_nc(nc_get_vara_float(ncid, varid, start, count, val));  | 
         | 
   706 			break;  | 
         | 
   707 		case NC_INT:  | 
         | 
   708 			wrap_nc(nc_get_vara_int(ncid, varid, start, count, val));  | 
         | 
   709 			break;  | 
         | 
   710 		case NC_DOUBLE:  | 
         | 
   711 			wrap_nc(nc_get_vara_double(ncid, varid, start, count, val));  | 
         | 
   712 			break;  | 
         | 
   713 		case NC_CHAR:  | 
         | 
   714 			wrap_nc(nc_get_vara_text(ncid, varid, start, count, val));  | 
         | 
   715 			break;  | 
         | 
   716 		default:  | 
         | 
   717 			fprintf(stderr, "netCDF external data type %d not supported\n", nctype);  | 
         | 
   718 			exit(3);  | 
         | 
   719 	}  | 
         | 
   720   | 
         | 
   721 	return val;  | 
         | 
   722 }  | 
         | 
   723   | 
         | 
   724 void write_var(int ncid, int varid, nc_type nctype, void *val)  | 
         | 
   725 { | 
         | 
   726 	switch (nctype) { | 
         | 
   727 		case NC_FLOAT:  | 
         | 
   728 			wrap_nc(nc_put_var_float(ncid, varid, val));  | 
         | 
   729 			break;  | 
         | 
   730 		case NC_INT:  | 
         | 
   731 			wrap_nc(nc_put_var_int(ncid, varid, val));  | 
         | 
   732 			break;  | 
         | 
   733 		case NC_DOUBLE:  | 
         | 
   734 			wrap_nc(nc_put_var_double(ncid, varid, val));  | 
         | 
   735 			break;  | 
         | 
   736 		case NC_CHAR:  | 
         | 
   737 			wrap_nc(nc_put_var_text(ncid, varid, val));  | 
         | 
   738 			break;  | 
         | 
   739 		default:  | 
         | 
   740 			fprintf(stderr, "netCDF external data type %d not supported\n", nctype);  | 
         | 
   741 			exit(3);  | 
         | 
   742 	}  | 
         | 
   743   | 
         | 
   744 	return;  | 
         | 
   745 }  | 
         | 
   746   | 
         | 
   747 void write_timeslice(int ncid, int varid, nc_type nctype, int ndims, int *dimids, struct dim **dim_idx, void *val, size_t tslice)  | 
         | 
   748 { | 
         | 
   749 	int i;  | 
         | 
   750 	size_t start[NC_MAX_VAR_DIMS], count[NC_MAX_VAR_DIMS];  | 
         | 
   751   | 
         | 
   752 	/* Make sure time is really the first dimension */  | 
         | 
   753 	if (strcmp((dim_idx[dimids[0]])->name, time_name)) { | 
         | 
   754 		fprintf(stderr, "write_timeslice: %s is not first dimension of variable!\n", time_name);  | 
         | 
   755 		exit(3);  | 
         | 
   756 	}  | 
         | 
   757 	  | 
         | 
   758 	/* Build start/count vectors */  | 
         | 
   759 	start[0] = tslice;  | 
         | 
   760 	count[0] = 1;  | 
         | 
   761 	for (i = 1; i < ndims; i++) { | 
         | 
   762 		start[i] = 0;  | 
         | 
   763 		count[i] = (dim_idx[dimids[i]])->len;  | 
         | 
   764 	}  | 
         | 
   765   | 
         | 
   766 	switch (nctype) { | 
         | 
   767 		case NC_FLOAT:  | 
         | 
   768 			wrap_nc(nc_put_vara_float(ncid, varid, start, count, val));  | 
         | 
   769 			break;  | 
         | 
   770 		case NC_INT:  | 
         | 
   771 			wrap_nc(nc_put_vara_int(ncid, varid, start, count, val));  | 
         | 
   772 			break;  | 
         | 
   773 		case NC_DOUBLE:  | 
         | 
   774 			wrap_nc(nc_put_vara_double(ncid, varid, start, count, val));  | 
         | 
   775 			break;  | 
         | 
   776 		case NC_CHAR:  | 
         | 
   777 			wrap_nc(nc_put_vara_text(ncid, varid, start, count, val));  | 
         | 
   778 			break;  | 
         | 
   779 		default:  | 
         | 
   780 			fprintf(stderr, "netCDF external data type %d not supported\n", nctype);  | 
         | 
   781 			exit(3);  | 
         | 
   782 	}  | 
         | 
   783   | 
         | 
   784 	return;  | 
         | 
   785 }  | 
         | 
   786   | 
         | 
   787 void write_time_var(int ncid, int varid, nc_type nctype, void *time_var)  | 
         | 
   788 { | 
         | 
   789 	size_t start[1], count[1];  | 
         | 
   790   | 
         | 
   791 	start[0] = 0;  | 
         | 
   792 	count[0] = 24;  | 
         | 
   793   | 
         | 
   794 	switch (nctype) { | 
         | 
   795 		case NC_FLOAT:  | 
         | 
   796 			wrap_nc(nc_put_vara_float(ncid, varid, start, count, time_var));  | 
         | 
   797 			break;  | 
         | 
   798 		case NC_INT:  | 
         | 
   799 			wrap_nc(nc_put_vara_int(ncid, varid, start, count, time_var));  | 
         | 
   800 			break;  | 
         | 
   801 		case NC_DOUBLE:  | 
         | 
   802 			wrap_nc(nc_put_vara_double(ncid, varid, start, count, time_var));  | 
         | 
   803 			break;  | 
         | 
   804 		case NC_CHAR:  | 
         | 
   805 			wrap_nc(nc_put_vara_text(ncid, varid, start, count, time_var));  | 
         | 
   806 			break;  | 
         | 
   807 		default:  | 
         | 
   808 			fprintf(stderr, "netCDF external data type %d not supported\n", nctype);  | 
         | 
   809 			exit(3);  | 
         | 
   810 	}  | 
         | 
   811   | 
         | 
   812 	return;  | 
         | 
   813 }  | 
         | 
   814   | 
         | 
   815 void write_tbounds(int ncid, int varid, double *tbounds)  | 
         | 
   816 { | 
         | 
   817 	size_t start[2], count[2];  | 
         | 
   818   | 
         | 
   819 	start[0] = start[1] = 0;  | 
         | 
   820 	count[0] = 24; count[1] = 2;  | 
         | 
   821   | 
         | 
   822 	wrap_nc(nc_put_vara_double(ncid, varid, start, count, tbounds));  | 
         | 
   823   | 
         | 
   824 	return;  | 
         | 
   825 }  | 
         | 
   826   | 
         | 
   827 void copy_metadata(int in_ncid, struct var *in_var_head,  | 
         | 
   828 	struct dim **in_dim_idx, int out_ncid, struct var *out_var_head,  | 
         | 
   829 	double *times, double *tbounds, int *mcdate, int *mcsec)  | 
         | 
   830 { | 
         | 
   831 	int i;  | 
         | 
   832 	struct var *in_vnode, *out_vnode;  | 
         | 
   833 	void *val;  | 
         | 
   834   | 
         | 
   835 	if (!in_var_head) return;  | 
         | 
   836   | 
         | 
   837 	in_vnode = in_var_head;  | 
         | 
   838 	/*  | 
         | 
   839 	 * March through input variables to stuff metadata values into  | 
         | 
   840 	 * the new output files. NOTE: The only time-based metadata  | 
         | 
   841 	 * variables, explicitly handled, are: time, climatology_bounds,  | 
         | 
   842 	 * mcdate, and mcsec.  These are passed in.  | 
         | 
   843 	 */  | 
         | 
   844 	for (i = 0; i == 0 || in_vnode != in_var_head; i++) { | 
         | 
   845 		if (in_vnode->metadata) { | 
         | 
   846 			/* Find the corresponding output variable */  | 
         | 
   847 			if (!strcmp(in_vnode->name, time_bounds_name))  | 
         | 
   848 				out_vnode = varlist_find_by_name(out_var_head, climatology_bounds_name);  | 
         | 
   849 			else  | 
         | 
   850 				out_vnode = varlist_find_by_name(out_var_head, in_vnode->name);  | 
         | 
   851 			if (out_vnode) { | 
         | 
   852 				/* Read values from input and write to output */  | 
         | 
   853 				if (strcmp((in_dim_idx[in_vnode->dimids[0]])->name, time_name)) { | 
         | 
   854 					/* "time" is not the first dimension,  | 
         | 
   855 					 * so just copy the variable values */  | 
         | 
   856 #ifdef DEBUG  | 
         | 
   857 					printf("Copying metadata variable %s\n", | 
         | 
   858 						in_vnode->name);  | 
         | 
   859 #endif /* DEBUG */  | 
         | 
   860 					val = read_var(in_ncid, in_vnode->ncvarid, in_vnode->nctype, in_vnode->ndims, in_vnode->dimids, in_dim_idx);  | 
         | 
   861 					write_var(out_ncid, out_vnode->ncvarid, out_vnode->nctype, val);  | 
         | 
   862 					free(val);  | 
         | 
   863 				}  | 
         | 
   864 				else { | 
         | 
   865 					/* "time" is the first dimension, so  | 
         | 
   866 					 * explicitly handle the "time",  | 
         | 
   867 					 * "climatology_bounds", "mcdate", and  | 
         | 
   868 					 * "mcsec" while dropping all others */  | 
         | 
   869 					if (!strcmp(out_vnode->name, time_name)) { | 
         | 
   870 						/* Force time stamps to be  | 
         | 
   871 						 * those computed previously,  | 
         | 
   872 						 * and remember these are now  | 
         | 
   873 						 * double precision. */  | 
         | 
   874 #ifdef DEBUG  | 
         | 
   875 						printf("Writing metadata variable %s\n", out_vnode->name); | 
         | 
   876 #endif /* DEBUG */  | 
         | 
   877 						write_time_var(out_ncid, out_vnode->ncvarid, out_vnode->nctype, times);  | 
         | 
   878 					}  | 
         | 
   879 					if (!strcmp(out_vnode->name, climatology_bounds_name)) { | 
         | 
   880 						/* time_bounds are now  | 
         | 
   881 						 * climatology_bounds and have  | 
         | 
   882 						 * pre-computed values */  | 
         | 
   883 #ifdef DEBUG  | 
         | 
   884 						printf("Writing metadata variable %s\n", out_vnode->name); | 
         | 
   885 #endif /* DEBUG */  | 
         | 
   886 						write_tbounds(out_ncid, out_vnode->ncvarid, tbounds);  | 
         | 
   887 					}  | 
         | 
   888 					else if (!strcmp(out_vnode->name, mcdate_name)) { | 
         | 
   889 						/* mcdate is pre-computed */  | 
         | 
   890 #ifdef DEBUG  | 
         | 
   891 						printf("Writing metadata variable %s\n", out_vnode->name); | 
         | 
   892 #endif /* DEBUG */  | 
         | 
   893 						write_time_var(out_ncid, out_vnode->ncvarid, out_vnode->nctype, mcdate);  | 
         | 
   894 					}  | 
         | 
   895 					else if (!strcmp(out_vnode->name, mcsec_name)) { | 
         | 
   896 						/* mcsec is pre-computed */  | 
         | 
   897 #ifdef DEBUG  | 
         | 
   898 						printf("Writing metadata variable %s\n", out_vnode->name); | 
         | 
   899 #endif /* DEBUG */  | 
         | 
   900 						write_time_var(out_ncid, out_vnode->ncvarid, out_vnode->nctype, mcsec);  | 
         | 
   901 					}  | 
         | 
   902 				}  | 
         | 
   903 			}  | 
         | 
   904 			else { | 
         | 
   905 #ifdef DEBUG  | 
         | 
   906 				printf("Dropping metadata variable %s\n", in_vnode->name); | 
         | 
   907 #endif /* DEBUG */  | 
         | 
   908 			}  | 
         | 
   909 		}  | 
         | 
   910 		else { | 
         | 
   911 #ifdef DEBUG  | 
         | 
   912 			printf("Skipping non-metadata variable %s\n", | 
         | 
   913 				in_vnode->name);  | 
         | 
   914 #endif /* DEBUG */  | 
         | 
   915 		}  | 
         | 
   916 #ifdef DEBUG  | 
         | 
   917 		printf ("Done\n"); | 
         | 
   918 #endif /* DEBUG */  | 
         | 
   919 		in_vnode = in_vnode->next;  | 
         | 
   920 	}  | 
         | 
   921   | 
         | 
   922 	return;  | 
         | 
   923 }  | 
         | 
   924   | 
         | 
   925 void get_time_bounds(char *first_fname, char *last_fname, double *times, double *tbounds, int *mcdate, int *mcsec)  | 
         | 
   926 { | 
         | 
   927 	int i, time_dimid, time_bounds_varid, mcdate_varid, mcsec_varid;  | 
         | 
   928 	size_t time_len, time_bounds_start[2], time_bounds_count[2],  | 
         | 
   929 		mc_start[1], mc_count[1];  | 
         | 
   930 	double bnd1[24], bnd2[24], day1, day2;  | 
         | 
   931   | 
         | 
   932 	/* Open first input file */  | 
         | 
   933 	wrap_nc(nc_open(first_fname, NC_NOWRITE, &input_ncid));  | 
         | 
   934 	/* Get dimension ID of the time dimension */  | 
         | 
   935 	wrap_nc(nc_inq_dimid(input_ncid, time_name, &time_dimid));  | 
         | 
   936 	/* Get length of time dimension */  | 
         | 
   937 	wrap_nc(nc_inq_dimlen(input_ncid, time_dimid, &time_len));  | 
         | 
   938 	/* Get variable ID of time_bounds variable */  | 
         | 
   939 	wrap_nc(nc_inq_varid(input_ncid, time_bounds_name, &time_bounds_varid));  | 
         | 
   940 	/* Set start/count for reading the left values of time_bounds from the  | 
         | 
   941 	 * first 24 timeslices of the first file */  | 
         | 
   942 	time_bounds_start[0] = time_bounds_start[1] = 0;  | 
         | 
   943 	time_bounds_count[0] = 24; time_bounds_count[1] = 1;  | 
         | 
   944 	/* Read the values */  | 
         | 
   945 	wrap_nc(nc_get_vara_double(input_ncid, time_bounds_varid,  | 
         | 
   946 		time_bounds_start, time_bounds_count, bnd1));  | 
         | 
   947 	/* If the first and last file are not the same, close the first one and  | 
         | 
   948 	 * open the second one */  | 
         | 
   949 	if (strcmp(first_fname, last_fname)) { | 
         | 
   950 		/* Close the first input file */  | 
         | 
   951 		wrap_nc(nc_close(input_ncid));  | 
         | 
   952 		/* Open the last input file */  | 
         | 
   953 		wrap_nc(nc_open(last_fname, NC_NOWRITE, &input_ncid));  | 
         | 
   954 		/* Get dimension ID of the time dimension */  | 
         | 
   955 		wrap_nc(nc_inq_dimid(input_ncid, time_name, &time_dimid));  | 
         | 
   956 		/* Get length of time dimension */  | 
         | 
   957 		wrap_nc(nc_inq_dimlen(input_ncid, time_dimid, &time_len));  | 
         | 
   958 		/* Get variable ID of time_bounds variable */  | 
         | 
   959 		wrap_nc(nc_inq_varid(input_ncid, time_bounds_name,  | 
         | 
   960 			&time_bounds_varid));  | 
         | 
   961 	}  | 
         | 
   962 	/* Set start/count for reading the right values of time_bounds from the  | 
         | 
   963 	 * last 24 timeslices of the last file */  | 
         | 
   964 	time_bounds_start[0] = time_len - 24; time_bounds_start[1] = 1;  | 
         | 
   965 	time_bounds_count[0] = 24; time_bounds_count[1] = 1;  | 
         | 
   966 	/* Read the value */  | 
         | 
   967 	wrap_nc(nc_get_vara_double(input_ncid, time_bounds_varid,  | 
         | 
   968 		time_bounds_start, time_bounds_count, bnd2));  | 
         | 
   969 	/* Read the last 24 mcdate and mcsec values */  | 
         | 
   970 	wrap_nc(nc_inq_varid(input_ncid, mcdate_name, &mcdate_varid));  | 
         | 
   971 	wrap_nc(nc_inq_varid(input_ncid, mcsec_name, &mcsec_varid));  | 
         | 
   972 	mc_start[0] = time_len - 24;  | 
         | 
   973 	mc_count[0] = 24;  | 
         | 
   974 	wrap_nc(nc_get_vara_int(input_ncid, mcdate_varid, mc_start, mc_count,  | 
         | 
   975 		mcdate));  | 
         | 
   976 	wrap_nc(nc_get_vara_int(input_ncid, mcsec_varid, mc_start, mc_count,  | 
         | 
   977 		mcsec));  | 
         | 
   978   | 
         | 
   979 	/* Close the last input file */  | 
         | 
   980 	wrap_nc(nc_close(input_ncid));  | 
         | 
   981   | 
         | 
   982 	/* Store time bounds and compute new time stamps as midpoints */  | 
         | 
   983 	for (i = 0; i < 24; i++) { | 
         | 
   984 		tbounds[(i*2)] = bnd1[i];  | 
         | 
   985 		tbounds[(i*2+1)] = bnd2[i];  | 
         | 
   986 		/* Pick one (integer) day near the midpoint of the bounds and  | 
         | 
   987 		 * add in the fraction from the right bounds, so for January  | 
         | 
   988 		 * the first hour-of-day value would be 15.0 (plus some year  | 
         | 
   989 		 * offset) */  | 
         | 
   990 		day1 = floor(bnd1[i]);  | 
         | 
   991 		day2 = floor(bnd2[i]);  | 
         | 
   992 		times[i] = floor((day1 + day2) / 2.0) + (bnd2[i]-day2);  | 
         | 
   993 	}  | 
         | 
   994   | 
         | 
   995 	return;  | 
         | 
   996 }  | 
         | 
   997   | 
         | 
   998 char **make_cell_methods(size_t nsamples)  | 
         | 
   999 { | 
         | 
  1000 	int i;  | 
         | 
  1001 	size_t len;  | 
         | 
  1002 	char **cell_methods;  | 
         | 
  1003   | 
         | 
  1004 	if (!(cell_methods = (char **)malloc((NUM_TYPES * sizeof(char *))))) { | 
         | 
  1005 		perror("make_cell_methods:cell_methods"); | 
         | 
  1006 		exit(2);  | 
         | 
  1007 	}  | 
         | 
  1008 	for (i = 0; i < NUM_TYPES; i++) { | 
         | 
  1009 		len = strlen(cell_methods_prefix[i]) + 48;  | 
         | 
  1010 		if (!(cell_methods[i] = (char *)malloc((len * sizeof(char))))) { | 
         | 
  1011 			perror("make_cell_methods:cell_methods[i]"); | 
         | 
  1012 			exit(2);  | 
         | 
  1013 		}  | 
         | 
  1014 		sprintf(cell_methods[i], "%s (comment: %ld samples)",  | 
         | 
  1015 			cell_methods_prefix[i], (long)nsamples);  | 
         | 
  1016 	}  | 
         | 
  1017 	return cell_methods;  | 
         | 
  1018 }  | 
         | 
  1019   | 
         | 
  1020 void open_inout(char *first_fname, char *last_fname, char *mean_fname, char *stddev_fname, char *flist, size_t nsamples)  | 
         | 
  1021 { | 
         | 
  1022 	int i;  | 
         | 
  1023 	char *mean_history_gatt, *stddev_history_gatt,  | 
         | 
  1024 		*mean_prefix="Statistical means from history files:",  | 
         | 
  1025 		*stddev_prefix="Statistical standard deviations from history files:",  | 
         | 
  1026 		**cell_methods;  | 
         | 
  1027   | 
         | 
  1028 	/*  | 
         | 
  1029 	 * Construct strings for history global attributes for the two output  | 
         | 
  1030 	 * files.  | 
         | 
  1031 	 */  | 
         | 
  1032 	if (!(mean_history_gatt = (char *)malloc((strlen(mean_prefix) + strlen(flist)+1)*sizeof(char)))) { | 
         | 
  1033 		perror("open_inout:mean_history_gatt"); | 
         | 
  1034 		exit(2);  | 
         | 
  1035 	}  | 
         | 
  1036 	if (!(stddev_history_gatt = (char *)malloc((strlen(stddev_prefix) + strlen(flist)+1)*sizeof(char)))) { | 
         | 
  1037 		perror("open_inout:stddev_history_gatt"); | 
         | 
  1038 		exit(2);  | 
         | 
  1039 	}  | 
         | 
  1040 	sprintf(mean_history_gatt, "%s%s", mean_prefix, flist);  | 
         | 
  1041 	sprintf(stddev_history_gatt, "%s%s", stddev_prefix, flist);  | 
         | 
  1042   | 
         | 
  1043 	/* Allocate space for time values for each hour of the day */  | 
         | 
  1044 	if (!(times = (double *)malloc((24 * sizeof(double))))) { | 
         | 
  1045 		perror("open_inout:times"); | 
         | 
  1046 		exit(2);  | 
         | 
  1047 	}  | 
         | 
  1048 	/* Allocate space for two time bounds values for each hour of the day */  | 
         | 
  1049 	if (!(tbounds = (double *)malloc((24 * 2 * sizeof(double))))) { | 
         | 
  1050 		perror("open_inout:tbounds"); | 
         | 
  1051 		exit(2);  | 
         | 
  1052 	}  | 
         | 
  1053 	/* Allocate space for current date and seconds for each hour of day */  | 
         | 
  1054 	if (!(mcdate = (int *)malloc((24 * sizeof(int))))) { | 
         | 
  1055 		perror("open_inout:mcdate"); | 
         | 
  1056 		exit(2);  | 
         | 
  1057 	}  | 
         | 
  1058 	if (!(mcsec = (int *)malloc((24 * sizeof(int))))) { | 
         | 
  1059 		perror("open_inout:mcsec"); | 
         | 
  1060 		exit(2);  | 
         | 
  1061 	}  | 
         | 
  1062   | 
         | 
  1063   | 
         | 
  1064 	/*   | 
         | 
  1065 	 * Explicitly handle "time", "time_bounds" -> "climatology_bounds",  | 
         | 
  1066 	 * mcdate, and mcsec metadata variables by constructing their values  | 
         | 
  1067 	 * before doing anything else.  | 
         | 
  1068 	 */  | 
         | 
  1069 	get_time_bounds(first_fname, last_fname, times, tbounds, mcdate, mcsec);  | 
         | 
  1070 #ifdef DEBUG  | 
         | 
  1071 	for (i = 0; i < 24; i++)  | 
         | 
  1072 		fprintf(stderr, "Hour of day=%d, time=%lf, tbounds=%lf,%lf mcdate=%d mcsec=%d\n", i, times[i], tbounds[(i*2)], tbounds[(i*2+1)], mcdate[i], mcsec[i]);  | 
         | 
  1073 #endif /* DEBUG */  | 
         | 
  1074   | 
         | 
  1075 	/* Open last input file */  | 
         | 
  1076 	wrap_nc(nc_open(last_fname, NC_NOWRITE, &input_ncid));  | 
         | 
  1077 	/* Inquire about number of dimensions, variables, global attributes  | 
         | 
  1078 	 * and the ID of the unlimited dimension  | 
         | 
  1079 	 */  | 
         | 
  1080 	wrap_nc(nc_inq(input_ncid, &input_ndims, &input_nvars, &input_ngatts,  | 
         | 
  1081 		&input_unlimdimid));  | 
         | 
  1082 	/* Grab dimension IDs and lengths from input file */  | 
         | 
  1083 	get_dimensions(input_ncid, input_ndims, &input_dim_head, &input_dim_idx);  | 
         | 
  1084 	/* Grab desired global attributes from input file */  | 
         | 
  1085 	get_gatts(input_ncid, input_ngatts, &input_gatt_head);  | 
         | 
  1086 	/* Grab variable IDs and attributes from input file */  | 
         | 
  1087 	get_vars(input_ncid, input_nvars, &input_var_head);  | 
         | 
  1088 #ifdef DEBUG  | 
         | 
  1089 	varlist_print(input_var_head);  | 
         | 
  1090 #endif /* DEBUG */  | 
         | 
  1091 	/* Create netCDF files for monthly means and standard deviations */  | 
         | 
  1092 	/* Create new netCDF files */  | 
         | 
  1093 	wrap_nc(nc_create(mean_fname, NC_NOCLOBBER, &mean_ncid));  | 
         | 
  1094 	wrap_nc(nc_create(stddev_fname, NC_NOCLOBBER, &stddev_ncid));  | 
         | 
  1095 	/* Define dimensions */  | 
         | 
  1096 	mean_ndims = put_dimensions(input_dim_head, input_ndims,  | 
         | 
  1097 		input_unlimdimid, nsamples, &idid2mdid, mean_ncid,  | 
         | 
  1098 		&mean_dim_head, &mean_unlimdimid);  | 
         | 
  1099 	stddev_ndims = put_dimensions(input_dim_head, input_ndims,  | 
         | 
  1100 		input_unlimdimid, nsamples, &idid2sdid, stddev_ncid,  | 
         | 
  1101 		&stddev_dim_head, &stddev_unlimdimid);  | 
         | 
  1102 	/* Define cell_methods[], including number of samples */  | 
         | 
  1103 	cell_methods = make_cell_methods(nsamples);  | 
         | 
  1104 	/* Define variables and their attributes */  | 
         | 
  1105 	mean_nvars = define_vars(input_ncid, input_dim_idx, input_var_head,  | 
         | 
  1106 		idid2mdid, mean_ncid, &mean_var_head, cell_methods,  | 
         | 
  1107 		MEAN_TYPE);  | 
         | 
  1108 	stddev_nvars = define_vars(input_ncid, input_dim_idx, input_var_head,  | 
         | 
  1109 		idid2sdid, stddev_ncid, &stddev_var_head, cell_methods,  | 
         | 
  1110 		STDDEV_TYPE);  | 
         | 
  1111 #ifdef DEBUG  | 
         | 
  1112 	printf("Mean variables:\n"); | 
         | 
  1113 	varlist_print(mean_var_head);  | 
         | 
  1114 	printf("Stddev variables:\n"); | 
         | 
  1115 	varlist_print(stddev_var_head);  | 
         | 
  1116 #endif /* DEBUG */  | 
         | 
  1117 	/* Store global attributes */  | 
         | 
  1118 	mean_ngatts = put_gatts(input_gatt_head, mean_ncid, mean_history_gatt);  | 
         | 
  1119 	stddev_ngatts = put_gatts(input_gatt_head, stddev_ncid,  | 
         | 
  1120 		stddev_history_gatt);  | 
         | 
  1121 	/* End define mode */  | 
         | 
  1122 	wrap_nc(nc_enddef(mean_ncid));  | 
         | 
  1123 	wrap_nc(nc_enddef(stddev_ncid));  | 
         | 
  1124 	/* Write out metdata variables that do not depend on "time" */  | 
         | 
  1125 	copy_metadata(input_ncid, input_var_head, input_dim_idx, mean_ncid,  | 
         | 
  1126 		mean_var_head, times, tbounds, mcdate, mcsec);  | 
         | 
  1127 	copy_metadata(input_ncid, input_var_head, input_dim_idx, stddev_ncid,  | 
         | 
  1128 		stddev_var_head, times, tbounds, mcdate, mcsec);  | 
         | 
  1129   | 
         | 
  1130 	wrap_nc(nc_close(input_ncid));  | 
         | 
  1131   | 
         | 
  1132 	return;  | 
         | 
  1133 }  | 
         | 
  1134   | 
         | 
  1135 size_t count_samples(int nifnames, char **input_fnames)  | 
         | 
  1136 { | 
         | 
  1137 	int i;  | 
         | 
  1138 	char name[NC_MAX_NAME+1];  | 
         | 
  1139 	size_t len, cnt = 0;  | 
         | 
  1140   | 
         | 
  1141 	for (i = 0; i < nifnames; i++) { | 
         | 
  1142 		/* Open input file */  | 
         | 
  1143 		wrap_nc(nc_open(input_fnames[i], NC_NOWRITE, &input_ncid));  | 
         | 
  1144 		/*  | 
         | 
  1145 		 * Inquire about number of dimensions, variables, global  | 
         | 
  1146 		 * attributes and the ID of the unlimited dimension  | 
         | 
  1147 		 */  | 
         | 
  1148 		wrap_nc(nc_inq(input_ncid, &input_ndims, &input_nvars,  | 
         | 
  1149 			&input_ngatts, &input_unlimdimid));  | 
         | 
  1150 		wrap_nc(nc_inq_dim(input_ncid, input_unlimdimid, name, &len));  | 
         | 
  1151 		if (strcmp(name, time_name)) { | 
         | 
  1152 			fprintf(stderr, "%s is not the unlimited dimension for file %s!\n", time_name, input_fnames[i]);  | 
         | 
  1153 			exit(4);  | 
         | 
  1154 		}  | 
         | 
  1155 #ifdef DEBUG  | 
         | 
  1156 		printf("%ld samples in %s\n", (long)len, input_fnames[i]); | 
         | 
  1157 #endif /* DEBUG */  | 
         | 
  1158 		wrap_nc(nc_close(input_ncid));  | 
         | 
  1159 		cnt += len;  | 
         | 
  1160 	}  | 
         | 
  1161 	return cnt;  | 
         | 
  1162 }  | 
         | 
  1163   | 
         | 
  1164 void alloc_means_stddevs(size_t d1, size_t d2, double ***meansp, double ***stddevsp, size_t ***cell_samplesp)  | 
         | 
  1165 { | 
         | 
  1166 	/*  | 
         | 
  1167 	 * Allocate space for arrays of means and standard deviations by  | 
         | 
  1168 	 * hour of day.  | 
         | 
  1169 	 */  | 
         | 
  1170 	int i;  | 
         | 
  1171 	size_t **cell_samples;  | 
         | 
  1172 	double **means, **stddevs;  | 
         | 
  1173   | 
         | 
  1174 	if (!(*meansp = (double **)malloc(HOURS_PER_DAY * sizeof(double *)))) { | 
         | 
  1175 		perror("alloc_means_stddevs:*meansp"); | 
         | 
  1176 		exit(2);  | 
         | 
  1177 	}  | 
         | 
  1178 	if (!(*stddevsp = (double **)malloc(HOURS_PER_DAY * sizeof(double *)))) { | 
         | 
  1179 		perror("alloc_means_stddevs:*stddevsp"); | 
         | 
  1180 		exit(2);  | 
         | 
  1181 	}  | 
         | 
  1182 	if (!(*cell_samplesp = (size_t **)malloc(HOURS_PER_DAY * sizeof(size_t *)))) { | 
         | 
  1183 		perror("alloc_means_stddevs:*cell_samplesp"); | 
         | 
  1184 		exit(2);  | 
         | 
  1185 	}  | 
         | 
  1186   | 
         | 
  1187 	means = *meansp;  | 
         | 
  1188 	stddevs = *stddevsp;  | 
         | 
  1189 	cell_samples = *cell_samplesp;  | 
         | 
  1190   | 
         | 
  1191 	for (i = 0; i < HOURS_PER_DAY; i++) { | 
         | 
  1192 		if (!(means[i] = (double *)malloc(d1 * d2 * sizeof(double)))) { | 
         | 
  1193 			perror("alloc_means_stddevs:means[i]"); | 
         | 
  1194 			exit(2);  | 
         | 
  1195 		}  | 
         | 
  1196 		if (!(stddevs[i] = (double *)malloc(d1 * d2 * sizeof(double)))) { | 
         | 
  1197 			perror("alloc_means_stddevs:stddevs[i]"); | 
         | 
  1198 			exit(2);  | 
         | 
  1199 		}  | 
         | 
  1200 		if (!(cell_samples[i] = (size_t *)malloc(d1 * d2 * sizeof(size_t)))) { | 
         | 
  1201 			perror("alloc_means_stddevs:cell_samples[i]"); | 
         | 
  1202 			exit(2);  | 
         | 
  1203 		}  | 
         | 
  1204 	}  | 
         | 
  1205   | 
         | 
  1206 	return;  | 
         | 
  1207 }  | 
         | 
  1208   | 
         | 
  1209 void init_means_stddevs(size_t d1, size_t d2, double **means, double **stddevs, size_t **cell_samples, float FillValue)  | 
         | 
  1210 { | 
         | 
  1211 	int hr, i, j, pos;  | 
         | 
  1212   | 
         | 
  1213 	for (hr = 0; hr < HOURS_PER_DAY; hr++) { | 
         | 
  1214 		for (i = 0; i < d1; i++) { | 
         | 
  1215 #pragma _CRI concurrent  | 
         | 
  1216 			for (j = 0; j < d2; j++) { | 
         | 
  1217 				pos = i*d2+j;  | 
         | 
  1218 				means[hr][pos] = FillValue;  | 
         | 
  1219 				stddevs[hr][pos] = FillValue;  | 
         | 
  1220 				cell_samples[hr][pos] = 0;  | 
         | 
  1221 			}  | 
         | 
  1222 		}  | 
         | 
  1223 	}  | 
         | 
  1224   | 
         | 
  1225 	return;  | 
         | 
  1226 }  | 
         | 
  1227   | 
         | 
  1228 void reset_cell_samples(size_t d1, size_t d2, size_t **cell_samples)  | 
         | 
  1229 { | 
         | 
  1230 	int i, j, hr, pos;  | 
         | 
  1231   | 
         | 
  1232 	for (hr = 0; hr < HOURS_PER_DAY; hr++) { | 
         | 
  1233 		for (i = 0; i < d1; i++) { | 
         | 
  1234 #pragma _CRI concurrent  | 
         | 
  1235 			for (j = 0; j < d2; j++) { | 
         | 
  1236 				pos = i*d2+j;  | 
         | 
  1237 				cell_samples[hr][pos] = 0;  | 
         | 
  1238 			}  | 
         | 
  1239 		}  | 
         | 
  1240 	}  | 
         | 
  1241   | 
         | 
  1242 	return;  | 
         | 
  1243 }  | 
         | 
  1244   | 
         | 
  1245 void free_means_stddevs(double **means, double **stddevs, size_t **cell_samples)  | 
         | 
  1246 { | 
         | 
  1247 	/*  | 
         | 
  1248 	 * Free space from arrays of means and standard deviations by  | 
         | 
  1249 	 * hour of day.  | 
         | 
  1250 	 */  | 
         | 
  1251 	int i;  | 
         | 
  1252   | 
         | 
  1253 	for (i = 0; i < HOURS_PER_DAY; i++) { | 
         | 
  1254 		free(means[i]);  | 
         | 
  1255 		free(stddevs[i]);  | 
         | 
  1256 		free(cell_samples[i]);  | 
         | 
  1257 	}  | 
         | 
  1258   | 
         | 
  1259 	free(means);  | 
         | 
  1260 	free(stddevs);  | 
         | 
  1261 	free(cell_samples);  | 
         | 
  1262   | 
         | 
  1263 	return;  | 
         | 
  1264 }  | 
         | 
  1265   | 
         | 
  1266 void add_to_means_float(float *val, int sec, size_t d1, size_t d2,  | 
         | 
  1267 	char FillFlag, float FillValue, double **means, size_t **cell_samples)  | 
         | 
  1268 { | 
         | 
  1269 	int i, j, hr, pos;  | 
         | 
  1270   | 
         | 
  1271 	hr = (int)floor((double)sec/(double)SEC_PER_HOUR);  | 
         | 
  1272   | 
         | 
  1273 	for (i = 0; i < d1; i++) { | 
         | 
  1274 #pragma _CRI concurrent  | 
         | 
  1275 		for (j = 0; j < d2; j++) { | 
         | 
  1276 			pos = i*d2+j;  | 
         | 
  1277 			if (!FillFlag || (FillFlag && val[pos] != FillValue)) { | 
         | 
  1278 				if (cell_samples[hr][pos] == 0)  | 
         | 
  1279 					means[hr][pos] = (double)val[pos];  | 
         | 
  1280 				else  | 
         | 
  1281 					means[hr][pos] += (double)val[pos];  | 
         | 
  1282 				++cell_samples[hr][pos];  | 
         | 
  1283 			}  | 
         | 
  1284 		}  | 
         | 
  1285 	}  | 
         | 
  1286   | 
         | 
  1287 	return;  | 
         | 
  1288 }  | 
         | 
  1289   | 
         | 
  1290 void add_to_means_double(double *val, int sec, size_t d1, size_t d2,  | 
         | 
  1291 	char FillFlag, float FillValue, double **means, size_t **cell_samples)  | 
         | 
  1292 { | 
         | 
  1293 	int i, j, hr, pos;  | 
         | 
  1294   | 
         | 
  1295 	hr = (int)floor((double)sec/(double)SEC_PER_HOUR);  | 
         | 
  1296   | 
         | 
  1297 	for (i = 0; i < d1; i++) { | 
         | 
  1298 #pragma _CRI concurrent  | 
         | 
  1299 		for (j = 0; j < d2; j++) { | 
         | 
  1300 			pos = i*d2+j;  | 
         | 
  1301 			if (!FillFlag || (FillFlag && val[pos] != FillValue)) { | 
         | 
  1302 				if (cell_samples[hr][pos] == 0)  | 
         | 
  1303 					means[hr][pos] = val[pos];  | 
         | 
  1304 				else  | 
         | 
  1305 					means[hr][pos] += val[pos];  | 
         | 
  1306 				++cell_samples[hr][pos];  | 
         | 
  1307 			}  | 
         | 
  1308 		}  | 
         | 
  1309 	}  | 
         | 
  1310   | 
         | 
  1311 	return;  | 
         | 
  1312 }  | 
         | 
  1313   | 
         | 
  1314   | 
         | 
  1315 void divide_means(size_t d1, size_t d2, double **means, size_t **cell_samples)  | 
         | 
  1316 { | 
         | 
  1317 	int i, j, hr, pos;  | 
         | 
  1318   | 
         | 
  1319 	for (hr = 0; hr < HOURS_PER_DAY; hr++) { | 
         | 
  1320 		for (i = 0; i < d1; i++) { | 
         | 
  1321 #pragma _CRI concurrent  | 
         | 
  1322 			for (j = 0; j < d2; j++) { | 
         | 
  1323 				pos = i*d2+j;  | 
         | 
  1324 				if (cell_samples[hr][pos] != 0) { | 
         | 
  1325 					means[hr][pos] /= (double)cell_samples[hr][pos];  | 
         | 
  1326 				}  | 
         | 
  1327 			}  | 
         | 
  1328 		}  | 
         | 
  1329 	}  | 
         | 
  1330   | 
         | 
  1331 	return;  | 
         | 
  1332 }  | 
         | 
  1333   | 
         | 
  1334 void add_to_stddevs_float(float *val, int sec, size_t d1, size_t d2,  | 
         | 
  1335 	char FillFlag, float FillValue, double **means, double **stddevs,  | 
         | 
  1336 	size_t **cell_samples)  | 
         | 
  1337 { | 
         | 
  1338 	int i, j, hr, pos;  | 
         | 
  1339 	double delta;  | 
         | 
  1340   | 
         | 
  1341 	hr = (int)floor((double)sec/(double)SEC_PER_HOUR);  | 
         | 
  1342   | 
         | 
  1343 	for (i = 0; i < d1; i++) { | 
         | 
  1344 #pragma _CRI concurrent  | 
         | 
  1345 		for (j = 0; j < d2; j++) { | 
         | 
  1346 			pos = i*d2+j;  | 
         | 
  1347 			if (!FillFlag || (FillFlag && val[pos] != FillValue  | 
         | 
  1348 				&& means[hr][pos] != FillValue)) { | 
         | 
  1349 				delta = means[hr][pos] - (double)val[pos];  | 
         | 
  1350 				if (cell_samples[hr][pos] == 0)  | 
         | 
  1351 					stddevs[hr][pos] = delta * delta;  | 
         | 
  1352 				else  | 
         | 
  1353 					stddevs[hr][pos] += delta * delta;  | 
         | 
  1354 				++cell_samples[hr][pos];  | 
         | 
  1355 			}  | 
         | 
  1356 		}  | 
         | 
  1357 	}  | 
         | 
  1358   | 
         | 
  1359 	return;  | 
         | 
  1360 }  | 
         | 
  1361   | 
         | 
  1362 void add_to_stddevs_double(double *val, int sec, size_t d1, size_t d2,  | 
         | 
  1363 	char FillFlag, float FillValue, double **means, double **stddevs,  | 
         | 
  1364 	size_t **cell_samples)  | 
         | 
  1365 { | 
         | 
  1366 	int i, j, hr, pos;  | 
         | 
  1367 	double delta;  | 
         | 
  1368   | 
         | 
  1369 	hr = (int)floor((double)sec/(double)SEC_PER_HOUR);  | 
         | 
  1370   | 
         | 
  1371 	for (i = 0; i < d1; i++) { | 
         | 
  1372 #pragma _CRI concurrent  | 
         | 
  1373 		for (j = 0; j < d2; j++) { | 
         | 
  1374 			pos = i*d2+j;  | 
         | 
  1375 			if (!FillFlag || (FillFlag && val[pos] != FillValue  | 
         | 
  1376 				&& means[hr][pos] != FillValue)) { | 
         | 
  1377 				delta = means[hr][pos] - val[pos];  | 
         | 
  1378 				if (cell_samples[hr][pos] == 0)  | 
         | 
  1379 					stddevs[hr][pos] = delta * delta;  | 
         | 
  1380 				else  | 
         | 
  1381 					stddevs[hr][pos] += delta * delta;  | 
         | 
  1382 				++cell_samples[hr][pos];  | 
         | 
  1383 			}  | 
         | 
  1384 		}  | 
         | 
  1385 	}  | 
         | 
  1386   | 
         | 
  1387 	return;  | 
         | 
  1388 }  | 
         | 
  1389   | 
         | 
  1390   | 
         | 
  1391 void divide_sqrt_stddevs(size_t d1, size_t d2, double **stddevs, size_t **cell_samples)  | 
         | 
  1392 { | 
         | 
  1393 	int i, j, hr, pos;  | 
         | 
  1394   | 
         | 
  1395 	for (hr = 0; hr < HOURS_PER_DAY; hr++) { | 
         | 
  1396 		for (i = 0; i < d1; i++) { | 
         | 
  1397 #pragma _CRI concurrent  | 
         | 
  1398 			for (j = 0; j < d2; j++) { | 
         | 
  1399 				pos = i*d2+j;  | 
         | 
  1400 				if (cell_samples[hr][pos] != 0) { | 
         | 
  1401 					stddevs[hr][pos] /= (double)cell_samples[hr][pos];  | 
         | 
  1402 					stddevs[hr][pos] = sqrt(stddevs[hr][pos]);  | 
         | 
  1403 				}  | 
         | 
  1404 			}  | 
         | 
  1405 		}  | 
         | 
  1406 	}  | 
         | 
  1407   | 
         | 
  1408 	return;  | 
         | 
  1409 }  | 
         | 
  1410   | 
         | 
  1411 void read_and_compute(int nifnames, char **input_fnames, size_t d1, size_t d2, char *var_name, nc_type nctype, int level, int ndims, char FillFlag, float FillValue, int stat_type, double **means, double **stddevs, size_t **cell_samples)  | 
         | 
  1412 { | 
         | 
  1413 	int i, ts;  | 
         | 
  1414 	int varid, *mcsec;  | 
         | 
  1415 	size_t len, start[NC_MAX_VAR_DIMS], count[NC_MAX_VAR_DIMS];  | 
         | 
  1416 	char name[NC_MAX_NAME+1];  | 
         | 
  1417 	void *val;  | 
         | 
  1418   | 
         | 
  1419 	/* Allocate space for timeslice */  | 
         | 
  1420 	val = alloc_var(nctype, (d1 * d2));  | 
         | 
  1421   | 
         | 
  1422 	for (i = 0; i < nifnames; i++) { | 
         | 
  1423 #ifdef DEBUG  | 
         | 
  1424 		printf("\tOpening %s", input_fnames[i]); | 
         | 
  1425 		if (ndims > 3) printf(" to retrieve level %d", level); | 
         | 
  1426 		if (stat_type == MEAN_TYPE)  | 
         | 
  1427 			printf(" for computing means\n"); | 
         | 
  1428 		else  | 
         | 
  1429 			printf(" for computing stddevs\n"); | 
         | 
  1430 #endif /* DEBUG */  | 
         | 
  1431 		/* Open input file */  | 
         | 
  1432 		wrap_nc(nc_open(input_fnames[i], NC_NOWRITE, &input_ncid));  | 
         | 
  1433 		/*  | 
         | 
  1434 		 * Inquire about number of dimensions, variables, global  | 
         | 
  1435 		 * attributes and the ID of the unlimited dimension  | 
         | 
  1436 		 */  | 
         | 
  1437 		wrap_nc(nc_inq(input_ncid, &input_ndims, &input_nvars,  | 
         | 
  1438 			&input_ngatts, &input_unlimdimid));  | 
         | 
  1439 		wrap_nc(nc_inq_dim(input_ncid, input_unlimdimid, name, &len));  | 
         | 
  1440 		if (strcmp(name, time_name)) { | 
         | 
  1441 			fprintf(stderr, "%s is not the unlimited dimension for file %s!\n", time_name, input_fnames[i]);  | 
         | 
  1442 			exit(4);  | 
         | 
  1443 		}  | 
         | 
  1444 		/* Get seconds of day variable */  | 
         | 
  1445 		wrap_nc(nc_inq_varid(input_ncid, mcsec_name, &varid));  | 
         | 
  1446 		if (!(mcsec = (int *)malloc(len * sizeof(int)))) { | 
         | 
  1447 			perror("read_and_compute:mcsec"); | 
         | 
  1448 			exit(2);  | 
         | 
  1449 		}  | 
         | 
  1450 		wrap_nc(nc_get_var_int(input_ncid, varid, mcsec));  | 
         | 
  1451 		/* Get variable ID for requested variable */  | 
         | 
  1452 		wrap_nc(nc_inq_varid(input_ncid, var_name, &varid));  | 
         | 
  1453 		/* Retrieve time slice of desired variable */  | 
         | 
  1454 		for (ts = 0; ts < len; ts++) { | 
         | 
  1455 			start[0] = ts;  | 
         | 
  1456 			count[0] = 1;  | 
         | 
  1457 			start[(ndims-2)] = 0;  | 
         | 
  1458 			count[(ndims-2)] = d1;  | 
         | 
  1459 			start[(ndims-1)] = 0;  | 
         | 
  1460 			count[(ndims-1)] = d2;  | 
         | 
  1461 			if (ndims == 4) { | 
         | 
  1462 				start[1] = level;  | 
         | 
  1463 				count[1] = 1;  | 
         | 
  1464 			}  | 
         | 
  1465 			switch(nctype) { | 
         | 
  1466 				case NC_FLOAT:  | 
         | 
  1467 					wrap_nc(nc_get_vara_float(input_ncid, varid, start, count, val));  | 
         | 
  1468 					if (stat_type == MEAN_TYPE)  | 
         | 
  1469 						add_to_means_float(val, mcsec[ts], d1, d2, FillFlag, FillValue, means, cell_samples);  | 
         | 
  1470 					else  | 
         | 
  1471 						add_to_stddevs_float(val, mcsec[ts], d1, d2, FillFlag, FillValue, means, stddevs, cell_samples);  | 
         | 
  1472 					break;  | 
         | 
  1473 				case NC_DOUBLE:  | 
         | 
  1474 					wrap_nc(nc_get_vara_double(input_ncid, varid, start, count, val));  | 
         | 
  1475 					if (stat_type == MEAN_TYPE)  | 
         | 
  1476 						add_to_means_double(val, mcsec[ts], d1, d2, FillFlag, FillValue, means, cell_samples);  | 
         | 
  1477 					else  | 
         | 
  1478 						add_to_stddevs_double(val, mcsec[ts], d1, d2, FillFlag, FillValue, means, stddevs, cell_samples);  | 
         | 
  1479 					break;  | 
         | 
  1480 				default:  | 
         | 
  1481 					fprintf(stderr, "netCDF external data type %d not supported\n", nctype);  | 
         | 
  1482 					exit(3);  | 
         | 
  1483 			}  | 
         | 
  1484 		}  | 
         | 
  1485   | 
         | 
  1486 		/* Free mcsec vector */  | 
         | 
  1487 		free(mcsec);  | 
         | 
  1488 		/* Close input file */  | 
         | 
  1489 		wrap_nc(nc_close(input_ncid));  | 
         | 
  1490 	}  | 
         | 
  1491 	/* Divide sums by number of samples */  | 
         | 
  1492 	if (stat_type == MEAN_TYPE)  | 
         | 
  1493 		divide_means(d1, d2, means, cell_samples);  | 
         | 
  1494 	else  | 
         | 
  1495 		divide_sqrt_stddevs(d1, d2, stddevs, cell_samples);  | 
         | 
  1496   | 
         | 
  1497 	/* Free working variable array */  | 
         | 
  1498 	free(val);  | 
         | 
  1499   | 
         | 
  1500 	return;  | 
         | 
  1501 }  | 
         | 
  1502   | 
         | 
  1503 float *double_to_float(size_t len, double *dvar)  | 
         | 
  1504 { | 
         | 
  1505 	int i;  | 
         | 
  1506 	float *fvar;  | 
         | 
  1507   | 
         | 
  1508 	if (!(fvar = (float *)malloc(len * sizeof(float)))) { | 
         | 
  1509 		perror("double_to_float:fvar"); | 
         | 
  1510 		exit(2);  | 
         | 
  1511 	}  | 
         | 
  1512   | 
         | 
  1513 	for (i = 0; i < len; i++)  | 
         | 
  1514 		fvar[i] = (float)dvar[i];  | 
         | 
  1515   | 
         | 
  1516 	return fvar;  | 
         | 
  1517 }  | 
         | 
  1518   | 
         | 
  1519 void write_var_hours(int ncid, int varid, nc_type nctype, size_t d1, size_t d2,  | 
         | 
  1520 	int level, int ndims, double **var_hours)  | 
         | 
  1521 { | 
         | 
  1522 	/* Output dimensions should be one larger than input dimensions */  | 
         | 
  1523 	int i, hr;  | 
         | 
  1524 	size_t start[NC_MAX_VAR_DIMS], count[NC_MAX_VAR_DIMS];  | 
         | 
  1525 	float *fvar = NULL;  | 
         | 
  1526   | 
         | 
  1527 	if (nctype == NC_FLOAT) { | 
         | 
  1528 		if (!(fvar = (float *)malloc(d1 * d2 * sizeof(float)))) { | 
         | 
  1529 			perror("write_var_hours:fvar"); | 
         | 
  1530 			exit(2);  | 
         | 
  1531 		}  | 
         | 
  1532 	}  | 
         | 
  1533   | 
         | 
  1534 	for (hr = 0; hr < HOURS_PER_DAY; hr++) { | 
         | 
  1535 		start[0] = hr;  | 
         | 
  1536 		count[0] = 1; /* time */  | 
         | 
  1537 		start[(ndims-2)] = 0;  | 
         | 
  1538 		count[(ndims-2)] = d1;  | 
         | 
  1539 		start[(ndims-1)] = 0;  | 
         | 
  1540 		count[(ndims-1)] = d2;  | 
         | 
  1541 		if (ndims == 4) { | 
         | 
  1542 			start[1] = level;  | 
         | 
  1543 			count[1] = 1;  | 
         | 
  1544 		}  | 
         | 
  1545 		switch (nctype) { | 
         | 
  1546 			case NC_FLOAT:  | 
         | 
  1547 				for (i = 0; i < (d1 * d2); i++)  | 
         | 
  1548 					fvar[i] = (float)var_hours[hr][i];  | 
         | 
  1549 				wrap_nc(nc_put_vara_float(ncid, varid, start, count, fvar));  | 
         | 
  1550 				break;  | 
         | 
  1551 			case NC_DOUBLE:  | 
         | 
  1552 				wrap_nc(nc_put_vara_double(ncid, varid, start, count, var_hours[hr]));  | 
         | 
  1553 				break;  | 
         | 
  1554 			default:  | 
         | 
  1555 				fprintf(stderr, "netCDF external data type %d not supported\n", nctype);  | 
         | 
  1556 				exit(3);  | 
         | 
  1557 		}  | 
         | 
  1558 	}  | 
         | 
  1559   | 
         | 
  1560 	if (nctype == NC_FLOAT)  | 
         | 
  1561 		free(fvar);  | 
         | 
  1562   | 
         | 
  1563 	return;  | 
         | 
  1564 }  | 
         | 
  1565   | 
         | 
  1566 void compute_stats(int nifnames, char **input_fnames)  | 
         | 
  1567 { | 
         | 
  1568 	int j, k, nlevels;  | 
         | 
  1569 	size_t d1, d2, **cell_samples;  | 
         | 
  1570 	double **means, **stddevs;  | 
         | 
  1571 	struct var *in_vnode, *out_vnode;  | 
         | 
  1572   | 
         | 
  1573 	if (input_var_head) { | 
         | 
  1574 		in_vnode = input_var_head;  | 
         | 
  1575 		/* March through non-metadata variables to compute stats */  | 
         | 
  1576 		for (j = 0; j == 0 || in_vnode != input_var_head; j++) { | 
         | 
  1577 			if (!in_vnode->metadata) { | 
         | 
  1578 				/* Make sure time is really the first dimension */  | 
         | 
  1579 				if (strcmp((input_dim_idx[in_vnode->dimids[0]])->name, time_name)) { | 
         | 
  1580 					fprintf(stderr, "compute_stats: %s is not first dimension of variable %s!\n", time_name, in_vnode->name);  | 
         | 
  1581 					exit(3);  | 
         | 
  1582 				}  | 
         | 
  1583 				/* Figure out input dimensions */  | 
         | 
  1584 				if (in_vnode->ndims < 3 || in_vnode->ndims > 4) { | 
         | 
  1585 					fprintf(stderr, "compute_stats: %s has %d dimensions!\n", in_vnode->name, in_vnode->ndims);  | 
         | 
  1586 					exit(3);  | 
         | 
  1587 				}  | 
         | 
  1588 				/* Assume 2D output; find dimensions */  | 
         | 
  1589 				d1 = (input_dim_idx[in_vnode->dimids[(in_vnode->ndims-2)]])->len;  | 
         | 
  1590 				d2 = (input_dim_idx[in_vnode->dimids[(in_vnode->ndims-1)]])->len;  | 
         | 
  1591 				if (in_vnode->ndims == 3)  | 
         | 
  1592 					nlevels = 1;  | 
         | 
  1593 				else  | 
         | 
  1594 					nlevels = (input_dim_idx[in_vnode->dimids[1]])->len;  | 
         | 
  1595 				/* Allocate working space for means and stddevs */  | 
         | 
  1596 				alloc_means_stddevs(d1, d2, &means, &stddevs, &cell_samples);  | 
         | 
  1597 				init_means_stddevs(d1, d2, means, stddevs, cell_samples, in_vnode->FillValue);  | 
         | 
  1598 				printf("Computing statistics for %s\n", | 
         | 
  1599 					in_vnode->name);  | 
         | 
  1600 				/* Compute means and stddevs, then write them */  | 
         | 
  1601 				for (k = 0; k < nlevels; k++) { | 
         | 
  1602 					/* Read and compute means */  | 
         | 
  1603 					read_and_compute(nifnames, input_fnames, d1, d2, in_vnode->name, in_vnode->nctype, k, in_vnode->ndims, in_vnode->FillFlag, in_vnode->FillValue, MEAN_TYPE, means, stddevs, cell_samples);  | 
         | 
  1604 					/* Find corresponding output variable on the mean output file */  | 
         | 
  1605 					out_vnode = varlist_find_by_name(mean_var_head, in_vnode->name);  | 
         | 
  1606 					/* Write out the means for this variable */  | 
         | 
  1607 					write_var_hours(mean_ncid, out_vnode->ncvarid, out_vnode->nctype, d1, d2, k, out_vnode->ndims, means);  | 
         | 
  1608 					/* Zero out cell_samples so they can be used as a flag again for computing stddevs */  | 
         | 
  1609 					reset_cell_samples(d1, d2, cell_samples);  | 
         | 
  1610 					/* Read and compute stddevs using means */  | 
         | 
  1611 					read_and_compute(nifnames, input_fnames, d1, d2, in_vnode->name, in_vnode->nctype, k, in_vnode->ndims, in_vnode->FillFlag, in_vnode->FillValue, STDDEV_TYPE, means, stddevs, cell_samples);  | 
         | 
  1612 					/* Find corresponding output variable on the stddev output file */  | 
         | 
  1613 					out_vnode = varlist_find_by_name(stddev_var_head, in_vnode->name);  | 
         | 
  1614 					/* Write out stddevs for this variable */  | 
         | 
  1615 					write_var_hours(stddev_ncid, out_vnode->ncvarid, out_vnode->nctype, d1, d2, k, out_vnode->ndims, stddevs);  | 
         | 
  1616 				}  | 
         | 
  1617   | 
         | 
  1618 				/* Free working space for means and stddevs */  | 
         | 
  1619 				free_means_stddevs(means, stddevs, cell_samples);  | 
         | 
  1620 			}  | 
         | 
  1621 			in_vnode = in_vnode->next;  | 
         | 
  1622 		}  | 
         | 
  1623 	}  | 
         | 
  1624 	return;  | 
         | 
  1625 }  | 
         | 
  1626   | 
         | 
  1627 void usage(char *program)  | 
         | 
  1628 { | 
         | 
  1629 	fprintf(stderr, "Usage: %s -m mean.nc -s stddev.nc hist_file1.nc [ hist_file2.nc ... ]\n", program);  | 
         | 
  1630 	fprintf(stderr, "WARNING: It is assumed that the list of input files is specified in time order!\n");  | 
         | 
  1631 	exit(4);  | 
         | 
  1632 }  | 
         | 
  1633   | 
         | 
  1634 int main(int argc, char **argv)  | 
         | 
  1635 { | 
         | 
  1636 	int i, ic, nifnames;  | 
         | 
  1637 	size_t len, pos, nsamples;  | 
         | 
  1638 	char *mfname, *sfname, **ifnames, *flist;  | 
         | 
  1639   | 
         | 
  1640 	ifnames = NULL;  | 
         | 
  1641 	mfname = sfname = flist = NULL;  | 
         | 
  1642 	nifnames = 0;  | 
         | 
  1643   | 
         | 
  1644 #ifdef DEBUG  | 
         | 
  1645 	printf("Number of metadata variables (nmvars) = %d\n", nmvars); | 
         | 
  1646 	fflush(stdout);  | 
         | 
  1647 #endif /* DEBUG */  | 
         | 
  1648   | 
         | 
  1649 	/* check command-line flags and switches */  | 
         | 
  1650 	while ((ic = getopt(argc, argv, "m:s:")) != -1) { | 
         | 
  1651 		switch(ic) { | 
         | 
  1652 			case 'm':  | 
         | 
  1653 				if (!(mfname = strdup(optarg))) { | 
         | 
  1654 					perror("mfname"); | 
         | 
  1655 					exit(2);  | 
         | 
  1656 				}  | 
         | 
  1657 				break;  | 
         | 
  1658 			case 's':  | 
         | 
  1659 				if (!(sfname = strdup(optarg))) { | 
         | 
  1660 					perror("sfname"); | 
         | 
  1661 					exit(2);  | 
         | 
  1662 				}  | 
         | 
  1663 				break;  | 
         | 
  1664 		}  | 
         | 
  1665 	}  | 
         | 
  1666   | 
         | 
  1667 	if (!mfname) { | 
         | 
  1668 		fprintf(stderr, "Output file name for writing means required.\n");  | 
         | 
  1669 		usage(argv[0]);  | 
         | 
  1670 	}  | 
         | 
  1671 	if (!sfname) { | 
         | 
  1672 		fprintf(stderr, "Output file name for writing standard deviations required.\n");  | 
         | 
  1673 		usage(argv[0]);  | 
         | 
  1674 	}  | 
         | 
  1675   | 
         | 
  1676 	if (optind < argc) { | 
         | 
  1677 		if (!(ifnames = (char **)malloc((argc-optind+1)*sizeof(char *)))) { | 
         | 
  1678 			perror("ifnames"); | 
         | 
  1679 			exit(2);  | 
         | 
  1680 		}  | 
         | 
  1681 		for (i = optind; i < argc; i++) { | 
         | 
  1682 			if (!(ifnames[nifnames++] = strdup(argv[i]))) { | 
         | 
  1683 				perror("ifnames[nifnames++]"); | 
         | 
  1684 				exit(2);  | 
         | 
  1685 			}  | 
         | 
  1686 		}  | 
         | 
  1687 	}  | 
         | 
  1688 	else { | 
         | 
  1689 		fprintf(stderr, "At least one input file name is required.\n");  | 
         | 
  1690 		usage(argv[0]);  | 
         | 
  1691 	}  | 
         | 
  1692   | 
         | 
  1693   | 
         | 
  1694 	/*  | 
         | 
  1695 	 * Build list of input files to be included in the global history  | 
         | 
  1696 	 * attribute on the two outputs files.  | 
         | 
  1697 	 */  | 
         | 
  1698 	for (i = len = 0; i < nifnames; i++)  | 
         | 
  1699 		len += strlen(ifnames[i]);  | 
         | 
  1700 	len += nifnames + 1; /* space in front of every name + null terminator */  | 
         | 
  1701 	if (!(flist = (char *)malloc(len * sizeof(char)))) { | 
         | 
  1702 		perror("flist"); | 
         | 
  1703 		exit(2);  | 
         | 
  1704 	}  | 
         | 
  1705 	for (i = pos = 0; i < nifnames; pos += (strlen(ifnames[i])+1), i++)  | 
         | 
  1706 		sprintf(&flist[pos], " %s", ifnames[i]);  | 
         | 
  1707 #ifdef DEBUG  | 
         | 
  1708 	printf("flist=%s\n", flist); | 
         | 
  1709 	fflush(stdout);  | 
         | 
  1710 #endif /* DEBUG */  | 
         | 
  1711   | 
         | 
  1712 	/* Open every file to count up the number of time samples. */  | 
         | 
  1713 	nsamples = count_samples(nifnames, ifnames);  | 
         | 
  1714 #ifdef DEBUG  | 
         | 
  1715 	printf("Number of samples across all files = %ld\n", (long)nsamples); | 
         | 
  1716 	fflush(stdout);  | 
         | 
  1717 #endif /* DEBUG */  | 
         | 
  1718   | 
         | 
  1719 	/*  | 
         | 
  1720 	 * Open the *last* input file and the two output files (for mean and  | 
         | 
  1721 	 * standard deviation).  Define dimensions, variables, and attributes  | 
         | 
  1722 	 * for the two output files based on the *last* input files.  The  | 
         | 
  1723 	 * last file is used because some metadata variables will contain  | 
         | 
  1724 	 * only values from the last time slice from the period over which  | 
         | 
  1725 	 * the statistics are computed.  | 
         | 
  1726 	 */  | 
         | 
  1727 	open_inout(ifnames[0], ifnames[(nifnames-1)], mfname, sfname, flist,  | 
         | 
  1728 		nsamples);  | 
         | 
  1729   | 
         | 
  1730 	compute_stats(nifnames, ifnames);  | 
         | 
  1731   | 
         | 
  1732 	/* Close the two output files */  | 
         | 
  1733 	wrap_nc(nc_close(mean_ncid));  | 
         | 
  1734 	wrap_nc(nc_close(stddev_ncid));  | 
         | 
  1735   | 
         | 
  1736 	return 0;  | 
         | 
  1737 }  |