sasze  0.0-0.dev0.dirty.el6
 All Data Structures Files Functions Variables Typedefs Enumerations Enumerator Groups
sas_utils.c
Go to the documentation of this file.
1 /*******************************************************************************
2 *
3 * COPYRIGHT (C) 2012 Battelle Memorial Institute. All Rights Reserved.
4 *
5 ********************************************************************************
6 *
7 * Authors:
8 *
9 * name: Brian D. Ermold
10 * phone: (509) 375-2277
11 * email: brian.ermold@pnnl.gov
12 *
13 *******************************************************************************/
14 
15 /** @file sas_utils.c
16  * SAS Ingest Utility Functions.
17  */
18 
19 #include <math.h>
20 
21 #include "sas_utils.h"
22 
23 /**
24  * Add a file to a SasFileList structure.
25  *
26  * If an error occurs in this function it will be appended to the log and
27  * error mail messages, and the process status will be set appropriately.
28  *
29  * @param list pointer to the SasFileList structure
30  * @param file_name the name of the file
31  *
32  * @retval 1 if successful
33  * @retval 0 if an error occurred
34  */
35 int sas_add_file_to_list(SasFileList *list, const char *file_name)
36 {
37  int new_nalloced;
38  char **new_files;
39 
40  if (list->nfiles == list->nalloced) {
41 
42  new_nalloced = list->nalloced + 128;
43  new_files = (char **)realloc(list->files,
44  new_nalloced * sizeof(char *));
45 
46  if (!new_files) {
48  "Could not allocate memory for file list.\n");
49  return(0);
50  }
51 
52  list->nalloced = new_nalloced;
53  list->files = new_files;
54  }
55 
56  list->files[list->nfiles] = strdup(file_name);
57  if (!list->files[list->nfiles]) {
59  "Could not allocate memory for file name.\n");
60  return(0);
61  }
62 
63  list->nfiles += 1;
64  return(1);
65 }
66 
67 /**
68  * Reset a SasFileList structure back to 0 files.
69  *
70  * @param list pointer to the SasFileList structure
71  */
73 {
74  int fi;
75 
76  if (list &&
77  list->files) {
78 
79  for (fi = 0; fi < list->nfiles; ++fi) {
80  free(list->files[fi]);
81  list->files[fi] = (char *)NULL;
82  }
83 
84  list->nfiles = 0;
85  }
86 }
87 
88 /**
89  * Create a new SasFileList structure.
90  *
91  * If an error occurs in this function it will be appended to the log and
92  * error mail messages, and the process status will be set appropriately.
93  *
94  * @retval list pointer to the new SasFileList structure
95  * @retval NULL if an error occurred
96  */
98 {
99  SasFileList *list = calloc(1, sizeof(SasFileList));
100  if (!list) {
102  "Failed to allocate memory for SasFileList structure.\n");
103  return ((void *)NULL);
104  }
105 
106  return(list);
107 }
108 
109 /**
110  * Get the time from a SASHE or SASZE config file name.
111  *
112  * @param file_name the name of the raw file
113  *
114  * @retval time seconds since 1970
115  * @retval 0 if an error occurred
116  */
117 time_t sas_conf_file_name_time(const char *file_name)
118 {
119  int YYYY, MM, DD;
120  char *chrp;
121 
122  /* File names look like: SSSsashenirFF.YYYYMMDD.* */
123 
124  chrp = strchr(file_name, '.');
125  if (!chrp) return(0);
126 
127  YYYY = MM = DD = 0;
128 
129  sscanf(++chrp, "%4d%2d%2d", &YYYY, &MM, &DD);
130 
131  return(get_secs1970(YYYY, MM, DD, 0, 0, 0));
132 }
133 
134 /**
135  * Function used to sort a list of config file names by file name time.
136  *
137  * @param str1 void pointer to pointer to file name 1
138  * @param str2 void pointer to pointer to file name 2
139  *
140  * @retval 1 str1 > str2
141  * @retval 0 str1 == str2
142  * @retval -1 str1 < str2
143  */
144 int sas_conf_file_name_time_compare(const void *str1, const void *str2)
145 {
146  const char *s1 = *(const char **)str1;
147  const char *s2 = *(const char **)str2;
148  time_t t1 = sas_conf_file_name_time(s1);
149  time_t t2 = sas_conf_file_name_time(s2);
150 
151  if (t1 < t2) { return(-1); }
152  if (t1 > t2) { return(1); }
153 
154  return(0);
155 }
156 
157 /**
158  * Find the index of a value in an array of doubles.
159  *
160  * This function will find the index of the value in an array of monotonically
161  * increasing or decreasing values that is closest to the specified value.
162  *
163  * @param n number of values in the array
164  * @param x array of monotonically increasing or decreasing values
165  * @param v the value to look for
166  *
167  * @return The index of the value that is closest to the specified value.
168  */
169 int sas_find_nearest_double(int n, double *x, double v)
170 {
171  int bi = 0;
172  int ei = n - 1;
173  int mi;
174 
175  if (n < 2) return(0);
176 
177  if (x[bi] < x[ei]) {
178 
179  /* monotonically increasing values */
180 
181  if (v <= x[0]) return(0);
182  if (v >= x[n-1]) return(n-1);
183 
184  while (ei > bi + 1) {
185  mi = (bi + ei)/2;
186  if (v < x[mi]) ei = mi;
187  else bi = mi;
188  }
189 
190  return(((v - x[bi]) < (x[bi+1] - v)) ? bi : bi + 1);
191  }
192  else {
193 
194  /* monotonically decreasing values */
195 
196  if (v >= x[0]) return(0);
197  if (v <= x[n-1]) return(n-1);
198 
199  while (ei > bi + 1) {
200  mi = (bi + ei)/2;
201  if (v > x[mi]) ei = mi;
202  else bi = mi;
203  }
204 
205  return(((x[bi] - v) < (v - x[bi+1])) ? bi : bi + 1);
206  }
207 }
208 
209 /**
210  * Find the index of a value in an array of floats.
211  *
212  * This function will find the index of the value in an array of monotonically
213  * increasing or decreasing values that is closest to the specified value.
214  *
215  * @param n number of values in the array
216  * @param x array of monotonically increasing or decreasing values
217  * @param v the value to look for
218  *
219  * @return The index of the value that is closest to the specified value.
220  */
221 int sas_find_nearest_float(int n, float *x, float v)
222 {
223  int bi = 0;
224  int ei = n - 1;
225  int mi;
226 
227  if (n < 2) return(0);
228 
229  if (x[bi] < x[ei]) {
230 
231  /* monotonically increasing values */
232 
233  if (v <= x[0]) return(0);
234  if (v >= x[n-1]) return(n-1);
235 
236  while (ei > bi + 1) {
237  mi = (bi + ei)/2;
238  if (v < x[mi]) ei = mi;
239  else bi = mi;
240  }
241 
242  return(((v - x[bi]) < (x[bi+1] - v)) ? bi : bi + 1);
243  }
244  else {
245 
246  /* monotonically decreasing values */
247 
248  if (v >= x[0]) return(0);
249  if (v <= x[n-1]) return(n-1);
250 
251  while (ei > bi + 1) {
252  mi = (bi + ei)/2;
253  if (v > x[mi]) ei = mi;
254  else bi = mi;
255  }
256 
257  return(((x[bi] - v) < (v - x[bi+1])) ? bi : bi + 1);
258  }
259 }
260 
261 /**
262  * Free the memory used by a SasConfigTable.
263  *
264  * @param table pointer to the SasConfigTable
265  */
267 {
268  size_t col;
269 
270  if (table) {
271  if (table->cols) {
272  for (col = 0; col < table->cols_alloced; ++col) {
273  if (table->cols[col]) free(table->cols[col]);
274  }
275  free(table->cols);
276  }
277  if (table->buffer) free(table->buffer);
278  free(table);
279  }
280 }
281 
282 /**
283  * Free the memory used by a SasFileList structure.
284  *
285  * @param list pointer to the SasFileList structure
286  */
288 {
289  if (list) {
290  if (list->files) {
291  sas_clear_file_list(list);
292  free(list->files);
293  }
294  free(list);
295  }
296 }
297 
298 /**
299  * Free the memory used by a SasRawData structure.
300  *
301  * @param raw pointer to the SasRawData
302  */
304 {
305  int i;
306 
307  if (raw) {
308  if (raw->records) {
309  for (i = 0; i < raw->nrecs; ++i) {
310  free(raw->records[i].spec);
311  }
312  free(raw->records);
313  }
314 
315  if (raw->times) free(raw->times);
316  if (raw->tags) free(raw->tags);
317 
318  /* SASHE Data */
319 
320  if (raw->recsets) free(raw->recsets);
321  if (raw->rs_times) free(raw->rs_times);
322  if (raw->rs_sza) free(raw->rs_sza);
323  if (raw->rs_cossza) free(raw->rs_cossza);
324  if (raw->rs_coscor) free(raw->rs_coscor);
326 
327  /* SASZE Data */
328 
330  if (raw->cal_times) free(raw->cal_times);
331 
332  free(raw);
333  }
334 }
335 
336 /**
337  * Function used to get a list of configuration files.
338  *
339  * The memory used by the returned structure is dynamically allocated
340  * and must be freed using the dirlist_free() function.
341  *
342  * If an error occurs in this function it will be appended to the log and
343  * error mail messages, and the process status will be set appropriately.
344  *
345  * @param conf_dir full path to the configuration files directory
346  * @param pattern the file pattern to look for
347  *
348  * @retval list pointer to the DirList structure
349  * @retval NULL if an error occured
350  */
352  const char *conf_dir,
353  const char *pattern)
354 {
355  int debug = dsproc_get_debug_level();
356  int nfiles;
357  DirList *dirlist;
358  char **file_list;
359 
361  "Loading config file list:\n"
362  " -> path: %s\n"
363  " -> pattern: %s\n",
364  conf_dir, pattern);
365 
366  /* Initialize the directory list structure. */
367 
368  dirlist = dirlist_create(conf_dir, 0);
369  if (!dirlist ||
370  !dirlist_add_patterns(dirlist, 1, &pattern, 0)) {
371 
372  DSPROC_ERROR( NULL,
373  "Could Not Create Configuration Files List For: %s\n",
374  conf_dir);
375 
376  if (dirlist) dirlist_free(dirlist);
377 
378  return((DirList *)NULL);
379  }
380 
381  nfiles = dirlist_get_file_list(dirlist, &file_list);
382  if (nfiles < 0) {
383 
384  DSPROC_ERROR( NULL,
385  "Could Not Get Configuration Files List For: %s\n",
386  conf_dir);
387 
388  dirlist_free(dirlist);
389  return((DirList *)NULL);
390  }
391  else if (nfiles == 0) {
392 
393  DSPROC_ERROR( NULL,
394  "Could Not Find Required Configuration Files:\n"
395  " -> search path: %s\n"
396  " -> search pattern: %s\n",
397  conf_dir, pattern);
398 
399  dirlist_free(dirlist);
400  return((DirList *)NULL);
401  }
402 
403  if (debug) {
404  int fi;
405  for (fi = 0; fi < dirlist->nfiles; ++fi) {
407  " -> found: %s\n", dirlist->file_list[fi]);
408  }
409  }
410 
411  return(dirlist);
412 }
413 
414 /**
415  * Get values from a configuration table.
416  *
417  * @param table pointer to the configuration table
418  * @param x_col table column containing the independent values
419  * @param x_nvals number of independent values to lookup
420  * @param x_vals array of independent values to lookup
421  * @param y_col table column containing the dependent values
422  * @param y_vals array to store the dependent values in
423  */
425  SasConfigTable *table,
426  int x_col,
427  size_t x_nvals,
428  double *x_vals,
429  int y_col,
430  double *y_vals)
431 {
432  double *xcol = table->cols[x_col];
433  double *ycol = table->cols[y_col];
434  double x, x0, x1;
435  size_t vi, ri;
436 
437  ri = 0;
438 
439  for (vi = 0; vi < x_nvals; vi++) {
440 
441  x = x_vals[vi];
442 
443  if (x <= xcol[0]) {
444  ri = 0;
445  }
446  else if (x >= xcol[table->nrows-1]) {
447  ri = table->nrows-1;
448  }
449  else if (x > xcol[ri]) {
450  for (ri++; x >= xcol[ri]; ri++);
451  x0 = xcol[ri-1];
452  x1 = xcol[ri];
453  ri = ((x - x0) < (x1 - x)) ? ri - 1 : ri;
454  }
455  else if (x < xcol[ri]) {
456  for (ri--; x <= xcol[ri]; ri--);
457  x0 = xcol[ri];
458  x1 = xcol[ri+1];
459  ri = ((x - x0) < (x1 - x)) ? ri : ri + 1;
460  }
461 
462  if (finite(ycol[ri])) {
463  y_vals[vi] = ycol[ri];
464  }
465  else {
466  y_vals[vi] = -9999.0;
467  }
468  }
469 }
470 
471 /**
472  * Get values from a configuration table.
473  *
474  * @param table pointer to the configuration table
475  * @param x_col table column containing the independent values
476  * @param x_nvals number of independent values to lookup
477  * @param x_vals array of independent values to lookup
478  * @param y_col table column containing the dependent values
479  * @param y_vals array to store the dependent values in
480  */
482  SasConfigTable *table,
483  int x_col,
484  size_t x_nvals,
485  float *x_vals,
486  int y_col,
487  float *y_vals)
488 {
489  double *xcol = table->cols[x_col];
490  double *ycol = table->cols[y_col];
491  double x, x0, x1;
492  size_t vi, ri;
493 
494  ri = 0;
495 
496  for (vi = 0; vi < x_nvals; vi++) {
497 
498  x = (double)x_vals[vi];
499 
500  if (x <= xcol[0]) {
501  ri = 0;
502  }
503  else if (x >= xcol[table->nrows-1]) {
504  ri = table->nrows-1;
505  }
506  else if (x > xcol[ri]) {
507  for (ri++; x >= xcol[ri]; ri++);
508  x0 = xcol[ri-1];
509  x1 = xcol[ri];
510  ri = ((x - x0) < (x1 - x)) ? ri - 1 : ri;
511  }
512  else if (x < xcol[ri]) {
513  for (ri--; x <= xcol[ri]; ri--);
514  x0 = xcol[ri];
515  x1 = xcol[ri+1];
516  ri = ((x - x0) < (x1 - x)) ? ri : ri + 1;
517  }
518 
519  if (finite(ycol[ri])) {
520  y_vals[vi] = (float)ycol[ri];
521  }
522  else {
523  y_vals[vi] = -9999.0;
524  }
525  }
526 }
527 
528 /**
529  * Get values from a configuration table using interpolation.
530  *
531  * @param table pointer to the configuration table
532  * @param x_col table column containing the independent values
533  * @param x_nvals number of independent values to lookup
534  * @param x_vals array of independent values to lookup
535  * @param y_col table column containing the dependent values
536  * @param y_vals array to store the dependent values in
537  */
539  SasConfigTable *table,
540  int x_col,
541  size_t x_nvals,
542  double *x_vals,
543  int y_col,
544  double *y_vals)
545 {
546  double *xcol = table->cols[x_col];
547  double *ycol = table->cols[y_col];
548  double x, x0, x1, y0, y1;
549  size_t vi, ri;
550 
551  x0 = x1 = y0 = y1 = 0;
552  ri = 0;
553 
554  for (vi = 0; vi < x_nvals; vi++) {
555 
556  x = x_vals[vi];
557 
558  if (x == xcol[ri]) {
559 
560  if (finite(ycol[ri])) {
561  y_vals[vi] = ycol[ri];
562  }
563  else {
564  y_vals[vi] = -9999.0;
565  }
566 
567  continue;
568  }
569 
570  if (x <= xcol[0]) {
571  ri = 0;
572  x0 = xcol[0];
573  x1 = xcol[1];
574  y0 = ycol[0];
575  y1 = ycol[1];
576  }
577  else if (x >= xcol[table->nrows-1]) {
578  ri = table->nrows-1;
579  x0 = xcol[table->nrows-2];
580  x1 = xcol[table->nrows-1];
581  y0 = ycol[table->nrows-2];
582  y1 = ycol[table->nrows-1];
583  }
584  else if (x > xcol[ri]) {
585  for (ri++; x >= xcol[ri]; ri++);
586  x0 = xcol[ri-1];
587  x1 = xcol[ri];
588  y0 = ycol[ri-1];
589  y1 = ycol[ri];
590  }
591  else if (x < xcol[ri]) {
592  for (ri--; x <= xcol[ri]; ri--);
593  x0 = xcol[ri];
594  x1 = xcol[ri+1];
595  y0 = ycol[ri];
596  y1 = ycol[ri+1];
597  }
598 
599  if (finite(y0) && finite(y1)) {
600  y_vals[vi] = INTERPOLATE(x,x0,y0,x1,y1);
601  }
602  else {
603  y_vals[vi] = -9999.0;
604  }
605  }
606 }
607 
608 /**
609  * Get values from a configuration table using interpolation.
610  *
611  * @param table pointer to the configuration table
612  * @param x_col table column containing the independent values
613  * @param x_nvals number of independent values to lookup
614  * @param x_vals array of independent values to lookup
615  * @param y_col table column containing the dependent values
616  * @param y_vals array to store the dependent values in
617  */
619  SasConfigTable *table,
620  int x_col,
621  size_t x_nvals,
622  float *x_vals,
623  int y_col,
624  float *y_vals)
625 {
626  double *xcol = table->cols[x_col];
627  double *ycol = table->cols[y_col];
628  double x, x0, x1, y0, y1;
629  size_t vi, ri;
630 
631  x0 = x1 = y0 = y1 = 0;
632  ri = 0;
633 
634  for (vi = 0; vi < x_nvals; vi++) {
635 
636  x = (double)x_vals[vi];
637 
638  if (x == xcol[ri]) {
639 
640  if (finite(ycol[ri])) {
641  y_vals[vi] = (float)ycol[ri];
642  }
643  else {
644  y_vals[vi] = -9999.0;
645  }
646 
647  continue;
648  }
649 
650  if (x <= xcol[0]) {
651  ri = 0;
652  x0 = xcol[0];
653  x1 = xcol[1];
654  y0 = ycol[0];
655  y1 = ycol[1];
656  }
657  else if (x >= xcol[table->nrows-1]) {
658  ri = table->nrows-1;
659  x0 = xcol[table->nrows-2];
660  x1 = xcol[table->nrows-1];
661  y0 = ycol[table->nrows-2];
662  y1 = ycol[table->nrows-1];
663  }
664  else if (x > xcol[ri]) {
665  for (ri++; x >= xcol[ri]; ri++);
666  x0 = xcol[ri-1];
667  x1 = xcol[ri];
668  y0 = ycol[ri-1];
669  y1 = ycol[ri];
670  }
671  else if (x < xcol[ri]) {
672  for (ri--; x <= xcol[ri]; ri--);
673  x0 = xcol[ri];
674  x1 = xcol[ri+1];
675  y0 = ycol[ri];
676  y1 = ycol[ri+1];
677  }
678 
679  if (finite(y0) && finite(y1)) {
680  y_vals[vi] = INTERPOLATE(x,x0,y0,x1,y1);
681  }
682  else {
683  y_vals[vi] = -9999.0;
684  }
685  }
686 }
687 
688 /**
689  * Initialize a new SasRawData structure.
690  *
691  * If an error occurs in this function it will be appended to the log and
692  * error mail messages, and the process status will be set appropriately.
693  *
694  * @param type raw data file type
695  *
696  * @retval sas_raw pointer to SasRawData structure
697  * @retval NULL if an error occurs
698  */
700 {
701  SasRawData *raw = (SasRawData *)calloc(1, sizeof(SasRawData));
702  if (!raw) return((SasRawData *)NULL);
703  raw->file_type = type;
704  return(raw);
705 }
706 
707 /**
708  * Read in the values from a SAS configuration table file.
709  *
710  * The memory used by the returned structure is dynamically allocated
711  * and must be freed using the sas_free_config_table() function.
712  *
713  * If an error occurs in this function it will be appended to the log and
714  * error mail messages, and the process status will be set appropriately.
715  *
716  * @param conf_dir full path to the configuration files directory
717  * @param conf_file name of the configuration table file
718  * @param ncols number of columns to read in
719  * @param table the table structure to use
720  * or NULL to create a new table.
721  *
722  * @retval table the configuration table
723  * @retval NULL if an error occurred
724  */
726  const char *conf_dir,
727  const char *conf_file,
728  size_t ncols,
729  SasConfigTable *table)
730 {
731  int alloced_table = 0;
732  FILE *fp = (FILE *)NULL;
733  char full_path[PATH_MAX];
734  char line[1024];
735  int linenum;
736  char *strp;
737  size_t col;
738  size_t nvals;
739 
741  "Loading config file:\n"
742  " -> path: %s\n"
743  " -> file: %s\n",
744  conf_dir, conf_file);
745 
746  if (table) {
747 
748  /* Check if we have already loaded this table file */
749 
750  if ((strcmp(table->conf_dir, conf_dir) == 0) &&
751  (strcmp(table->conf_file, conf_file) == 0)) {
752 
753  return(table);
754  }
755  }
756  else {
757 
758  /* Allocate memory for the table structure */
759 
760  table = (SasConfigTable *)calloc(1, sizeof(SasConfigTable));
761  if (!table) goto MEMORY_ERROR;
762 
763  alloced_table = 1;
764  }
765 
766  /* Allocate memory for the column vectors */
767 
768  if (ncols > table->cols_alloced) {
769 
770  table->buffer = (double *)realloc(table->buffer, ncols * sizeof(double));
771  if (!table->buffer) goto MEMORY_ERROR;
772 
773  table->cols = (double **)realloc(table->cols, ncols * sizeof(double *));
774  if (!table->cols) goto MEMORY_ERROR;
775 
776  for (col = table->cols_alloced; col < ncols; ++col) {
777  table->cols[col] = (double *)NULL;
778  }
779 
780  for (col = table->cols_alloced; col < ncols; ++col) {
781 
782  table->cols[col] = (double *)malloc(
783  table->rows_alloced * sizeof(double));
784 
785  if (!table->cols[col]) {
786  goto MEMORY_ERROR;
787  }
788  }
789 
790  table->cols_alloced = ncols;
791  }
792 
793  table->nrows = 0;
794  table->ncols = ncols;
795  table->header[0] = '\0';
796 
797  /* Open the file */
798 
799  snprintf(full_path, PATH_MAX, "%s/%s", conf_dir, conf_file);
800 
801  fp = fopen(full_path, "r");
802  if (!fp) {
803  DSPROC_ERROR( NULL,
804  "Could Not Open Configuration File: %s\n"
805  " -> %s\n", full_path, strerror(errno));
806  goto ERROR_EXIT;
807  }
808 
809  /* Read the file */
810 
811  linenum = 0;
812 
813  while(fgets(line, 1024, fp)) {
814 
815  linenum++;
816 
817  /* Skip header and comment lines */
818 
819  if (line[0] == '!' ||
820  line[0] == '/' ||
821  line[0] == '#' ||
822  line[0] == '%') {
823 
824  strcat(table->header, line);
825  continue;
826  }
827 
828  /* Skip blank lines */
829 
830  for (strp = line; *strp == ' ' || *strp == '\t'; ++strp);
831  if (isspace(*strp) || *strp == '\0') {
832  continue;
833  }
834 
835  /* Parse line into an array of doubles */
836 
837  nvals = sas_string_to_doubles(line, ncols, table->buffer);
838 
839  if (nvals < ncols) {
840  DSPROC_ERROR(
841  "Bad Line Found In Configuration File",
842  "Bad line found on line %d in config file: %s\n"
843  " -> expected %d values but found: %d\n",
844  linenum, full_path, ncols, nvals);
845  goto ERROR_EXIT;
846  }
847 
848  /* Allocate memory for more rows if necessary */
849 
850  if (table->nrows == table->rows_alloced) {
851 
852  if (table->rows_alloced) {
853  table->rows_alloced *= 2;
854  }
855  else {
856  table->rows_alloced = 128;
857  }
858 
859  for (col = 0; col < table->cols_alloced; ++col) {
860 
861  table->cols[col] = (double *)realloc(table->cols[col],
862  table->rows_alloced * sizeof(double));
863 
864  if (!table->cols[col]) {
865  goto MEMORY_ERROR;
866  }
867  }
868  }
869 
870  /* Set the column values */
871 
872  for (col = 0; col < ncols; ++col) {
873  table->cols[col][table->nrows] = table->buffer[col];
874  }
875 
876  table->nrows++;
877 
878  } /* end get next line loop */
879 
880  if (ferror(fp)) {
881  DSPROC_ERROR( NULL,
882  "Could Not Read Configuration File: %s\n"
883  " -> %s\n",
884  full_path, strerror(errno));
885  goto ERROR_EXIT;
886  }
887 
888  /* Close the file and return */
889 
890  fclose(fp);
891 
892  strcpy(table->conf_dir, conf_dir);
893  strcpy(table->conf_file, conf_file);
894 
895 //fprintf(stderr, "\n\n*** Dumping resp_func file: %s\n\n", conf_file);
896 //sas_print_config_table(conf_file, table);
897 
898  return(table);
899 
900 MEMORY_ERROR:
901 
903  "Could not allocate memory for config table: %s\n", full_path);
904 
905 ERROR_EXIT:
906 
907  if (fp) fclose(fp);
908  if (alloced_table) sas_free_config_table(table);
909  return((SasConfigTable *)NULL);
910 }
911 
912 /**
913  * Print a configuration table.
914  *
915  * @param file name of the output file
916  * @param table pointer to the configuration table
917  *
918  * @retval 1 if successful
919  * @retval 0 if an error occurred
920  */
921 int sas_print_config_table(const char *file, SasConfigTable *table)
922 {
923  FILE *fp;
924  size_t col;
925  size_t row;
926 
927  fp = fopen(file, "w");
928  if (!fp) {
929  fprintf(stderr,
930  "Could not open file: %s\n"
931  " -> %s\n", file, strerror(errno));
932  return(0);
933  }
934 
935  for (row = 0; row < table->nrows; ++row) {
936 
937  fprintf(fp, "%g", table->cols[0][row]);
938 
939  for (col = 1; col < table->ncols; ++col) {
940  fprintf(fp, "\t%g", table->cols[col][row]);
941  }
942 
943  fprintf(fp, "\n");
944  }
945 
946  fclose(fp);
947  return(1);
948 }
949 
950 /**
951  * Get the time from a SASHE or SASZE raw data file name.
952  *
953  * @param file_name the name of the raw file
954  *
955  * @retval time seconds since 1970
956  * @retval 0 if an error occurred
957  */
958 time_t sas_raw_file_name_time(const char *file_name)
959 {
960  int YYYY, MM, DD, hh, mm, ss;
961  char *chrp;
962 
963  /* File names look like: *.YYYYMMDD_hhmmss.csv */
964 
965  chrp = strrchr(file_name, '.');
966  if (!chrp) return(0);
967 
968  if (chrp != file_name) {
969  for (--chrp; *chrp != '.' && chrp != file_name; --chrp);
970  }
971 
972  YYYY = MM = DD = hh = mm = ss = 0;
973 
974  sscanf(++chrp, "%4d%2d%2d_%2d%2d%2d",
975  &YYYY, &MM, &DD, &hh, &mm, &ss);
976 
977  return(get_secs1970(YYYY, MM, DD, hh, mm, ss));
978 }
979 
980 /**
981  * Function used to sort a list of raw file names by file name time.
982  *
983  * @param str1 void pointer to pointer to file name 1
984  * @param str2 void pointer to pointer to file name 2
985  *
986  * @retval 1 str1 > str2
987  * @retval 0 str1 == str2
988  * @retval -1 str1 < str2
989  */
990 int sas_raw_file_name_time_compare(const void *str1, const void *str2)
991 {
992  const char *s1 = *(const char **)str1;
993  const char *s2 = *(const char **)str2;
994  time_t t1 = sas_raw_file_name_time(s1);
995  time_t t2 = sas_raw_file_name_time(s2);
996 
997  if (t1 < t2) { return(-1); }
998  if (t1 > t2) { return(1); }
999 
1000  if (strstr(s1, "nir")) { return(-1); }
1001  if (strstr(s2, "nir")) { return(1); }
1002 
1003  return(0);
1004 }
1005 
1006 /**
1007  * Set the default attribute values in an output dataset.
1008  *
1009  * @param dataset pointer to the output dataset
1010  *
1011  * @retval 1 if successful
1012  * @retval 0 if an error occurred
1013  */
1015 {
1016  CDSVar *var;
1017  const char *var_name;
1018  double value;
1019  int di;
1020 
1021  struct {
1022  const char *var_name;
1023  double min;
1024  double max;
1025  } default_limits[] = {
1026 
1027  { "ad_temperature", 10.0, 20.0},
1028  { "ad_temperature_nir", 10.0, 20.0},
1029  { "ad_temperature_vis", 10.0, 20.0},
1030  { "bench_temperature", 5.0, 15.0},
1031  { "bench_temperature_nir", 5.0, 15.0},
1032  { "bench_temperature_vis", 5.0, 15.0},
1033  { "chiller_temperature", -10.0, 35.0},
1034  { "collector_x_tilt", -2.0, 2.0},
1035  { "collector_y_tilt", -2.0, 2.0},
1036  { NULL, 0.0, 0.0}
1037  };
1038 
1039  for (di = 0; (var_name = default_limits[di].var_name); ++di) {
1040 
1041  if ((var = dsproc_get_var(dataset, var_name))) {
1042 
1043  value = default_limits[di].min;
1044 
1046  "valid_min", CDS_DOUBLE, 1, &value)) {
1047 
1048  return(0);
1049  }
1050 
1051  value = default_limits[di].max;
1052 
1054  "valid_max", CDS_DOUBLE, 1, &value)) {
1055 
1056  return(0);
1057  }
1058  }
1059  }
1060 
1061  return(1);
1062 }
1063 
1064 /**
1065  * Parse a string into an array of doubles.
1066  *
1067  * This function will read all the numerical values from a string
1068  * and store them in the specified buffer.
1069  *
1070  * @param string pointer to the string
1071  * @param buflen the maximum number of values the buffer can hold
1072  * @param buffer output buffer
1073  *
1074  * @retval nvals The number of values read from the string or the number
1075  * of values that would have been read from the string if
1076  * the buffer had been large enough.
1077  */
1078 int sas_string_to_doubles(char *string, int buflen, double *buffer)
1079 {
1080  int nvals = 0;
1081  char *endp = (char *)NULL;
1082  char *strp;
1083  double value;
1084 
1085  for (strp = string; *strp != '\0'; ++strp) {
1086 
1087  value = strtod(strp, &endp);
1088 
1089  if (endp != strp) {
1090 
1091  if (nvals < buflen)
1092  buffer[nvals] = value;
1093 
1094  nvals++;
1095  strp = endp;
1096  if (*strp == '\0') break;
1097  }
1098  }
1099 
1100  return(nvals);
1101 }