OB.DAAC Logo
NASA Logo
Ocean Color Science Software

ocssw V2022
nccmp.cpp
Go to the documentation of this file.
1 /*
2  Copyright (C) 2004-2007,2009,2010,2012 Remik Ziemlinski @ noaa gov
3 
4  This program is free software; you can redistribute it and/or modify
5  it under the terms of the GNU General Public License as published by
6  the Free Software Foundation; either version 2, or (at your option)
7  any later version.
8 
9  This program is distributed in the hope that it will be useful,
10  but WITHOUT ANY WARRANTY; without even the implied warranty of
11  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12  GNU General Public License for more details.
13 
14  You should have received a copy of the GNU General Public License
15  along with this program; see the file COPYING.
16  If not, write to the Free Software Foundation,
17  59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
18  **
19  Converted to C++ and generalized compare using templates
20  January 2015 by R. Healy (richard.healy@nasa.gov)
21 
22  9/3/2015 - Added call to freestringlist in makecmpvarlist to
23  make number of variables to compare calculated correctly.
24  Previously, if there was more than one group in the file
25  then the value to compare was always from the first group.
26  Also added uint16_t(ushort) and ubyte to the types of netcdf variables
27 
28  1/6/2015 - In the case where type is not supported limited INFO message
29 
30  9/29/2016 - Added ability to compare compound types - rjh
31 
32  */
33 
34 #include "nccmp.hpp"
35 #include "ncinfo.h"
36 #include "strlist.h"
37 #include <stdint.h>
38 #include <float.h>
39 #include "strlist.c"
40 #include "ncinfo.c"
41 #include "opt.c"
42 
43 #include <cmath>
44 #include <string>
45 #include <vector>
46 #include <algorithm>
47 
48 #define NC_MAX_TYPES 64
49 
50 using namespace std;
51 
52 varstruct vars1[(int) NC_MAX_VARS], vars2[(int) NC_MAX_VARS];
53 dimstruct dims1[(int) NC_MAX_DIMS], dims2[(int) NC_MAX_DIMS];
54 static int notsupported[NC_MAX_TYPES];
55 
56 size_t nrec1, nrec2;
58 
59 vector<string> groupPath;
60 
61 #define NCFORMATSTR(f) \
62  (f == NC_FORMAT_CLASSIC ? "NC_FORMAT_CLASSIC" : \
63  (f == NC_FORMAT_64BIT ? "NC_FORMAT_64BIT" : \
64  (f == NC_FORMAT_NETCDF4 ? "NC_FORMAT_NETCDF4" : \
65  "NC_FORMAT_NETCDF4_CLASSIC"))) \
66 
67 const char* getGroupPath() {
68  static string path;
69 
70  if(groupPath.empty())
71  return "";
72 
73  path = "/";
74  for(vector<string>::iterator it = groupPath.begin(); it != groupPath.end(); ++it) {
75  path += *it;
76  path += "/";
77  }
78  return path.c_str();
79 }
80 
81 template <typename T> int cmp_(T* in1, T* in2) {
82  T const *p1, *p2;
83  for (p1 = in1, p2 = in2; *p1 == *p2; ++p1, ++p2)
84  continue;
85  return p1 - in1;
86 }
87 
88 template <typename T> int cmp_missing(T* in1, T* in2, T m1, T m2) {
89  T const *p1, *p2;
90  for (p1 = in1, p2 = in2; (*p1 == *p2) || ((*p1 == m1) && (*p2 == m2)); ++p1, ++p2)
91  continue;
92  return p1 - in1;
93 }
94 
95 template <typename T> int cmp_nanequal(T* in1, T* in2) {
96  T const *p1, *p2;
97  for (p1 = in1, p2 = in2; (*p1 == *p2) || (std::isnan(*p1) && std::isnan(*p2)); ++p1, ++p2)
98  continue;
99  return p1 - in1;
100 }
101 
102 template <typename T> int cmp_missing_nanequal(T* in1, T* in2, T m1, T m2) {
103  T const *p1, *p2;
104  for (p1 = in1, p2 = in2; (*p1 == *p2) || ((*p1 == m1) && (*p2 == m2)) || (std::isnan(*p1) && std::isnan(*p2)); ++p1, ++p2)
105  continue;
106  return p1 - in1;
107 }
108 
109 template <typename T> void ToHex(T v, char* out) { \
110  unsigned char *p = (unsigned char*) &v;
111  int i;
112  char tmp[3];
113 
114  strcpy(out, "0x");
115 
116  for (i = 0; i < (int) sizeof (T); ++i) {
117  sprintf(tmp, "%02X", p[i]);
118  strcat(out, tmp);
119  }
120 }
121 
122 template <typename T> void ToString(T v, char* out, char* formatprec) { \
123  sprintf(out, formatprec, v);
124 }
125 
126 template <typename T> int cmp_var(int ncid1, int ncid2, nccmpopts* opts, int rec, size_t *odomax,
127  off_t nitems, size_t *count, size_t *start, varstruct *v1, varstruct *v2, T M1, T M2) {
128 
129  void getidxstr(varstruct* var, size_t* start, int curidx, char* out);
130  void getidxstr_fortran(varstruct* var, size_t* start, int curidx, char* out);
131  int status, cmplen, do_missing = 0, diffstatus = EXIT_SUCCESS;
132  char idxstr[256];
133  string message("DIFFER : VARIABLE : %s%s : POSITION : %s : VALUES : %s <> %s\n");
134  char value1str[32], value2str[32];
135  char printHex = strchr(opts->precision, 'X') || strchr(opts->precision, 'x');
136 
137  T *P1, *P2;
138  T value1, value2;
139  int diff;
140 
141  if (opts->missing && v1->hasmissing && v2->hasmissing) {
142  do_missing = 1;
143  }
144 
145  P1 = (T *) malloc(sizeof (T) * (nitems + 1));
146  P2 = (T *) malloc(sizeof (T) * (nitems + 1));
147 
148  do {
149  /* printf("start = %d %d %d %d, count = %d %d %d %d\n", (int)start[0], (int)start[1], (int)start[2], (int)start[3], (int)count[0], (int)count[1], (int)count[2], (int)count[3]); */ \
150  status = nc_get_vara(ncid1, v1->varid, start, count, P1);
151  status = nc_get_vara(ncid2, v2->varid, start, count, P2);
153  /* Sentinels. */
154  P1[nitems] = 0;
155  P2[nitems] = 1;
156 
157  cmplen = nitems;
158  /* for(i=0; i<nitems; ++i) { \
159  printf("nitems = %d, rec = %d, P1[%d] = %g, P2[%d] = %g\n", nitems, rec, i, P1[i], i, P2[i]); \
160  } */
161  if (do_missing)
162  if (opts->nanequal)
163  diff = cmp_missing_nanequal<T>(P1, P2, M1, M2);
164  else
165  diff = cmp_missing<T>(P1, P2, M1, M2);
166  else
167  if (opts->nanequal)
168  diff = cmp_nanequal<T>(P1, P2);
169  else
170  diff = cmp_<T>(P1, P2);
171 
172  while (diff < cmplen && (opts->maxdiff == 0 || opts->diffcount < opts->maxdiff)) {
173  // printf("RJH: maxdiff=%ld cnt=%ld\n",opts->maxdiff,opts->diffcount);
174  if (!opts->warn[NCCMP_W_ALL])
175  diffstatus = EXIT_DIFFER;
176  else
177  diffstatus = EXIT_SUCCESS;
178 
179  if (opts->fortran)
180  getidxstr_fortran(v1, start, nitems - cmplen + diff, idxstr);
181  else
182  getidxstr(v1, start, nitems - cmplen + diff, idxstr);
183 
184  value1 = P1[nitems - cmplen + diff];
185  value2 = P2[nitems - cmplen + diff];
186  //printf("1)Forcing...%d %d \n",P1[+nitems-cmplen+diff],P2[nitems-cmplen+diff]);
187  if (printHex) {
188  ToHex((T) value1, value1str);
189  ToHex((T) value2, value2str);
190  } else {
191  ToString((T) value1, value1str, opts->tprintf);
192  ToString((T) value2, value2str, opts->tprintf);
193  }
194  opts->diffcount++;
195  //fprintf(stderr, message.c_str(), v1->name, idxstr, value1str, value2str);
196  printf(message.c_str(), getGroupPath(), v1->name, idxstr, value1str, value2str);
197  //printf("%d nitems=%d, cmplen=%d, diff=%d do_missing=%d\n", __LINE__, nitems, cmplen, diff, opts->missing);
198  if (opts->force) {
199  cmplen = cmplen - (diff + 1);
200  diff = cmp_<T>((P1 + diff + 1), (P2 + diff + 1));
201  //printf("Forcing...%d %d \n",P1[nitems-cmplen+diff],P2[nitems-cmplen+diff]);
202  } else
203  goto break_it;
204  }
205  /* Increment all but first (if record) and last dimensions. */
206  } while (odometer(start, odomax, (int) (rec >= 0), (int) v1->ndims - 2));
207 break_it:
208  free(P1);
209  free(P2);
210  return diffstatus;
211 }
212 
213 template <typename T> int cmp_vartol(int ncid1, int ncid2, nccmpopts* opts, int rec, size_t *odomax,
214  off_t nitems, size_t *count, size_t *start, varstruct *v1, varstruct *v2, T M1, T M2) {
215  void getidxstr_fortran(varstruct* var, size_t* start, int curidx, char* out);
216  void getidxstr(varstruct* var, size_t* start, int curidx, char* out);
217 
218  T *P1, *P2;
219 
220  int i, status, do_missing = 0, diffstatus = EXIT_SUCCESS;
221  char idxstr[256];
222  string message("DIFFER : VARIABLE : %s%s : POSITION : %s : VALUES : %s <> %s : PERCENT : %g\n");
223  char value1str[32], value2str[32];
224  char printHex = strchr(opts->precision, 'X') || strchr(opts->precision, 'x');
225  double absdelta;
226 
227  T value1, value2;
228 
229  P1 = (T *) malloc(sizeof (T) * (nitems + 1));
230  P2 = (T *) malloc(sizeof (T) * (nitems + 1));
231 
232  if (opts->missing && v1->hasmissing && v2->hasmissing) {
233  do_missing = 1;
234  }
235 
236  do {
237  /* printf("start = %d %d %d %d, count = %d %d %d %d\n", (int)start[0], (int)start[1], (int)start[2], (int)start[3], (int)count[0], (int)count[1], (int)count[2], (int)count[3]); */ \
238  status = nc_get_vara(ncid1, v1->varid, start, count, P1);
240  status = nc_get_vara(ncid2, v2->varid, start, count, P2);
242 
243  /* for(i=0; i<nitems; ++i) {
244  printf("nitems = %d, rec = %d, P1[%d] = %g, P2[%d] = %g\n", nitems, rec, i, P1[i], i, P2[i]); \
245  } */
246  for (i = 0; i < nitems && (opts->maxdiff == 0 || opts->diffcount < opts->maxdiff); ++i) {
247  if (do_missing) {
248  if ((M1 == P1[i]) && (M2 == P2[i])) continue;
249  }
250 
251  absdelta = fabs((double) (P1[i] - P2[i]));
252  if (opts->abstolerance ? (absdelta > opts->tolerance) : (double) absdelta * 100. / (fabs((double) P1[i]) > fabs((double) P2[i]) ? fabs((double) P1[i]) : fabs((double) P2[i])) > opts->tolerance) \
253  {
254  if (!opts->warn[NCCMP_W_ALL])
255  diffstatus = EXIT_DIFFER;
256  else
257  diffstatus = EXIT_SUCCESS;
258 
259  if ((v1->ndims == 1) && (v1->hasrec)) {
260  if (opts->fortran)
261  getidxstr_fortran(v1, start, rec, idxstr);
262  else
263  getidxstr(v1, start, rec, idxstr);
264  } else {
265  if (opts->fortran)
266  getidxstr_fortran(v1, start, i, idxstr);
267  else
268  getidxstr(v1, start, i, idxstr);
269  }
270  value1 = P1[i];
271  value2 = P2[i];
272  if (printHex) {
273  ToHex(value1, value1str);
274  ToHex(value2, value2str);
275  } else {
276  ToString(value1, value1str, opts->tprintf);
277  ToString(value2, value2str, opts->tprintf);
278  }
279  fprintf(stderr, message.c_str(), getGroupPath(), v1->name, idxstr, value1str, value2str, (double) absdelta * 100. / (fabs((double) P1[i]) > fabs((double) P2[i]) ? fabs((double) P1[i]) : fabs((double) P2[i])));
280  opts->diffcount++;
281  if (!opts->force) {
282  goto break_;
283  }
284  }
285  }
286  } while (odometer(start, odomax, (rec >= 0), v1->ndims - 2));
287 break_:
288  free(P1);
289  free(P2);
290 
291  return diffstatus;
292 }
293 
294 template <typename T> int cmp_var_ut(int ncid1, int ncid2, nccmpopts* opts, int rec, size_t *odomax,
295  off_t nitems, size_t *count, size_t *start, varstruct *v1, varstruct *v2, T M1, T M2) {
296 
297  void getidxstr(varstruct* var, size_t* start, int curidx, char* out);
298  void getidxstr_fortran(varstruct* var, size_t* start, int curidx, char* out);
299  int status, cmplen, do_missing = 0, diffstatus = EXIT_SUCCESS;
300  char idxstr[256];
301  string message("DIFFER : VARIABLE : %s%s : POSITION : %s : VALUES : %s <> %s\n");
302  char value1str[32], value2str[32];
303  char printHex = strchr(opts->precision, 'X') || strchr(opts->precision, 'x');
304 
305  T *P1, *P2;
306  T value1, value2;
307  int diff;
308 
309  if (opts->missing && v1->hasmissing && v2->hasmissing) {
310  do_missing = 1;
311  }
312 
313  P1 = (T *) malloc(sizeof (T) * (nitems + 1));
314  P2 = (T *) malloc(sizeof (T) * (nitems + 1));
315 
316  do {
317  /* printf("start = %d %d %d %d, count = %d %d %d %d\n", (int)start[0], (int)start[1], (int)start[2], (int)start[3], (int)count[0], (int)count[1], (int)count[2], (int)count[3]); */ \
318  status = nc_get_vara(ncid1, v1->varid, start, count, P1);
319  status = nc_get_vara(ncid2, v2->varid, start, count, P2);
321  /* Sentinels. */
322  P1[nitems] = 0;
323  P2[nitems] = 1;
324 
325  cmplen = nitems;
326  /* for(i=0; i<nitems; ++i) { \
327  printf("nitems = %d, rec = %d, P1[%d] = %g, P2[%d] = %g\n", nitems, rec, i, P1[i], i, P2[i]); \
328  } */
329  if (do_missing)
330  if (opts->nanequal)
331  diff = cmp_missing_nanequal<T>(P1, P2, M1, M2);
332  else
333  diff = cmp_missing<T>(P1, P2, M1, M2);
334  else
335  if (opts->nanequal)
336  diff = cmp_nanequal<T>(P1, P2);
337  else
338  diff = cmp_<T>(P1, P2);
339 
340  while (diff < cmplen && (opts->maxdiff == 0 || opts->diffcount < opts->maxdiff)) {
341  // printf("RJH: maxdiff=%ld cnt=%ld\n",opts->maxdiff,opts->diffcount);
342  if (!opts->warn[NCCMP_W_ALL])
343  diffstatus = EXIT_DIFFER;
344  else
345  diffstatus = EXIT_SUCCESS;
346 
347  if (opts->fortran)
348  getidxstr_fortran(v1, start, nitems - cmplen + diff, idxstr);
349  else
350  getidxstr(v1, start, nitems - cmplen + diff, idxstr);
351 
352  value1 = P1[nitems - cmplen + diff];
353  value2 = P2[nitems - cmplen + diff];
354  //printf("1)Forcing...%d %d \n",P1[+nitems-cmplen+diff],P2[nitems-cmplen+diff]);
355  if (printHex) {
356  ToHex((T) value1, value1str);
357  ToHex((T) value2, value2str);
358  } else {
359  ToString((T) value1, value1str, opts->tprintf);
360  ToString((T) value2, value2str, opts->tprintf);
361  }
362  opts->diffcount++;
363  //fprintf(stderr, message.c_str(), v1->name, idxstr, value1str, value2str);
364  printf(message.c_str(), getGroupPath(), v1->name, idxstr, value1str, value2str);
365  //printf("%d nitems=%d, cmplen=%d, diff=%d do_missing=%d\n", __LINE__, nitems, cmplen, diff, opts->missing);
366  if (opts->force) {
367  cmplen = cmplen - (diff + 1);
368  diff = cmp_<T>((P1 + diff + 1), (P2 + diff + 1));
369  //printf("Forcing...%d %d \n",P1[nitems-cmplen+diff],P2[nitems-cmplen+diff]);
370  } else
371  goto break_it;
372  }
373  /* Increment all but first (if record) and last dimensions. */
374  } while (odometer(start, odomax, (int) (rec >= 0), (int) v1->ndims - 2));
375 break_it:
376  free(P1);
377  free(P2);
378  return diffstatus;
379 }
380 
381 template <typename T> int cmp_vartol_ut(void *P1, void *P2, int offset1, int offset2, int size1, int size2, char* name, nccmpopts* opts, int rec, size_t *odomax,
382  off_t nitems, size_t *count, size_t *start, varstruct *v1, varstruct *v2, T M1, T M2) {
383 
384  void getidxstr_fortran(varstruct* var, size_t* start, int curidx, char* out);
385  void getidxstr(varstruct* var, size_t* start, int curidx, char* out);
386 
387 
388  int i, do_missing = 0, diffstatus = EXIT_SUCCESS;
389  char idxstr[256];
390  string message("DIFFER : VARIABLE : %s%s(%s) : POSITION : %s : VALUES : %s <> %s : PERCENT : %g\n");
391  char value1str[32], value2str[32];
392  char printHex = strchr(opts->precision, 'X') || strchr(opts->precision, 'x');
393  double absdelta;
394 
395  T value1, value2;
396 
397  if (opts->missing && v1->hasmissing && v2->hasmissing) {
398  do_missing = 1;
399  }
400 
401  do {
402 
403  /* for(i=0; i<nitems; ++i) {
404  printf("nitems = %d, rec = %d, P1[%d] = %g, P2[%d] = %g\n", nitems, rec, i, P1[i], i, P2[i]); \
405  } */
406  for (i = 0; i < nitems && (opts->maxdiff == 0 || opts->diffcount < opts->maxdiff); ++i) {
407  value1 = *((T *) ((unsigned char*) P1 + offset1) + i);
408  value2 = *((T *) ((unsigned char*) P2 + offset2) + i);
409  if (do_missing) {
410  if ((M1 == value1) && (M2 == value2)) continue;
411  }
412 
413  absdelta = fabs((double) (value1 - value2));
414  if (opts->abstolerance ? (absdelta > opts->tolerance) : (double) absdelta * 100. / (fabs((double) value1) > fabs((double) value2) ? fabs((double) value1) : fabs((double) value2)) > opts->tolerance) \
415  {
416  if (!opts->warn[NCCMP_W_ALL])
417  diffstatus = EXIT_DIFFER;
418  else
419  diffstatus = EXIT_SUCCESS;
420 
421  if ((v1->ndims == 1) && (v1->hasrec)) {
422  if (opts->fortran)
423  getidxstr_fortran(v1, start, rec, idxstr);
424  else
425  getidxstr(v1, start, rec, idxstr);
426  } else {
427  if (opts->fortran)
428  getidxstr_fortran(v1, start, i, idxstr);
429  else
430  getidxstr(v1, start, i, idxstr);
431  }
432  if (printHex) {
433  ToHex(value1, value1str);
434  ToHex(value2, value2str);
435  } else {
436  ToString(value1, value1str, opts->tprintf);
437  ToString(value2, value2str, opts->tprintf);
438  }
439  fprintf(stderr, message.c_str(), getGroupPath(), v1->name, name, idxstr, value1str, value2str, (double) absdelta * 100. / (fabs((double) value1) > fabs((double) value2) ? fabs((double) value1) : fabs((double) value2)));
440  opts->diffcount++;
441  if (!opts->force) {
442  goto break_;
443  }
444  }
445  }
446  } while (odometer(start, odomax, (rec >= 0), v1->ndims - 2));
447 break_:
448 
449  return diffstatus;
450 }
451 
452 /* *********************************************************** */
453 
454 /* Returns formatted string of dimension indices.
455  Intended to print out locations of value differences.
456  'out' should be pre-allocated large enough for output. */
457 void getidxstr(varstruct* var, size_t* start, int curidx, char* out) {
458  int i;
459  char tmp[8];
460  memset(out, '\0', 32);
461  for (i = 0; i < var->ndims - 1; ++i) {
462  sprintf(tmp, "%d ", (int) start[i]);
463  strcat(out, tmp);
464  }
465  sprintf(tmp, "%d", curidx);
466  strcat(out, tmp);
467 }
468 /* *********************************************************** */
469 
470 /* Same as above but with fortran style indices, which means they're
471  1-based (i.e. first index is 1, not 0) and fast-varying dimension is
472  printed first (reverse order compared with C-style indices) */
473 void getidxstr_fortran(varstruct* var, size_t* start, int curidx, char* out) {
474  int i;
475  char tmp[8];
476  memset(out, '\0', 32);
477  sprintf(tmp, "%d", curidx + 1);
478  strcat(out, tmp);
479 
480  for (i = var->ndims - 2; i >= 0; --i) {
481  sprintf(tmp, " %d", (int) start[i] + 1);
482  strcat(out, tmp);
483  }
484 }
485 
486 /* *********************************************************** */
487 int
488 excludevars(int ncid1, int ncid2, char** finallist,
489  int nfinal, char** excludelist, int nexclude) {
490  int nvars, nmaxvars = NC_MAX_VARS;
491  char** vars = NULL;
492  int status = EXIT_SUCCESS;
493 
494  vars = NULL;
495 
496  if (nexclude == 0)
497  return EXIT_SUCCESS;
498 
499  /* printf("%d: creating temporary var list array.\n", __LINE__); */
500  /* get simple difference */
501  if (newstringlist(&vars, &nvars, nmaxvars))
502  status = EXIT_FATAL;
503 
504  /* printf("%d: getting all variables names from both input files.\n", __LINE__); */
505  if (allvarnames(vars, nvars, ncid1, ncid2))
506  status = EXIT_FATAL;
507 
508  /*printf("vars=");
509  printstrlist(vars, nvars, stdout);
510  */
511 
512  if (strlistsd(vars, excludelist, finallist,
513  nvars, nexclude, nfinal))
514  status = EXIT_FATAL;
515 
516  /*printf("excludelist=");
517  printstrlist(excludelist, nexclude, stdout);
518  */
519 
520  /*printf("finallist=");
521  printstrlist(finallist, nfinal, stdout);
522  */
523 
524  freestringlist(&vars, nvars);
525 
526  return status;
527 }
528 
529 /* *********************************************************** */
530 void handle_error(int status) {
531  if (status != NC_NOERR) {
532  fprintf(stderr, "%s\n", nc_strerror(status));
533  exit(-1);
534  }
535 }
536 
537 /* *********************************************************** */
538 
539 /*
540  Mimics incrementing odometer.
541  Returns 0 if rolled-over.
542 
543  @param odo: the counters that are updated.
544  @param limits: the maximum values allowed per counter.
545  @param first: index of first counter to update.
546  @param last: index of last counter to update.
547  */
548 int odometer(size_t* odo, size_t* limits, int first, int last) {
549  int i = last;
550  while (i >= first) {
551  odo[i] += 1;
552  if (odo[i] > limits[i])
553  odo[i] = 0;
554  else
555  break;
556 
557  --i;
558  }
559 
560 #ifdef __DEBUG__
561  printf("DEBUG : %d : odo = ", __LINE__);
562  for (i = first; i <= last; ++i) {
563  printf("%d ", odo[i]);
564  }
565  printf("\n");
566 #endif
567 
568  /* Test for roll over. */
569  for (i = first; i <= last; ++i) {
570  if (odo[i] != 0)
571  return 1;
572  }
573 
574  /* If we get here then rolled over. */
575  return 0;
576 }
577 /* *********************************************************** */
578 
579 /* Pretty prints attribute values into a string.
580  Assumes 'str' is pre-allocated large enough to hold output string.
581  */
582 void prettyprintatt(int ncid, char* varname, int varid, char* name, char* str) {
583  int status, i;
584  nc_type type;
585  size_t len;
586  char* pc;
587  char charpr[3];
588  int8_t* puc;
589  uint8_t* upuc;
590  short* ps;
591  uint16_t* ups;
592  int* pi;
593  uint* upi;
594  long* pl;
595  uint64_t* upl;
596  float* pf;
597  double* pd;
598  char tmpstr[32];
599 
600 
601  strcpy(charpr, "%c");
602 
603  status = nc_inq_att(ncid, varid, name, &type, &len);
604  if (status != NC_NOERR) {
605  if (varid == NC_GLOBAL)
606  fprintf(stderr, "ERROR : QUERYING GLOBAL ATTRIBUTE \"%s\"\n", name);
607  else
608  fprintf(stderr, "ERROR : QUERYING ATTRIBUTE \"%s\" FOR VARIABLE \"%s%s\"\n", name, getGroupPath(), varname);
609  return;
610  }
611 
612  str[0] = '\0';
613  if (len < 1) {
614  return;
615  }
616 
617  switch (type) {
618  case NC_BYTE:
619  puc = XMALLOC(int8_t, len);
620 
621  status = nc_get_att(ncid, varid, name, puc);
622  if (status != NC_NOERR) {
623  XFREE(puc);
624  return;
625  }
626 
627  for (i = 0; i < (int) len; ++i) {
628  ToString<unsigned char> (puc[i], str + 2 * i, charpr);
629  str[2 * i + 1] = ',';
630  }
631 
632  XFREE(puc);
633  str[2 * (int) len - 1] = '\0';
634  break;
635 
636  case NC_UBYTE:
637  upuc = XMALLOC(uint8_t, len);
638 
639  status = nc_get_att_ubyte(ncid, varid, name, upuc);
640  if (status != NC_NOERR) {
641  XFREE(upuc);
642  return;
643  }
644 
645  for (i = 0; i < (int) len; ++i) {
646  ToString<unsigned char> (upuc[i], str + 2 * i, charpr);
647  str[2 * i + 1] = ',';
648  }
649 
650  XFREE(upuc);
651  str[2 * (int) len - 1] = '\0';
652  break;
653 
654 
655  case NC_CHAR:
656  pc = XMALLOC(char, len);
657  status = nc_get_att_text(ncid, varid, name, pc);
658  if (status != NC_NOERR) {
659  XFREE(pc);
660  return;
661  }
662 
663  for (i = 0; i < (int) len; ++i)
664  ToString<char>(pc[i], str + i, charpr);
665 
666  XFREE(pc);
667  str[(int) len] = '\0';
668  break;
669 
670  case NC_SHORT:
671  ps = XMALLOC(short, len);
672  status = nc_get_att_short(ncid, varid, name, ps);
673  if (status != NC_NOERR) {
674  XFREE(ps);
675  return;
676  }
677 
678  for (i = 0; i < (int) len; ++i) {
679  sprintf(tmpstr, "%d,", ps[i]);
680  strcat(str, tmpstr);
681  }
682 
683  XFREE(ps);
684  str[strlen(str) - 1] = '\0'; // Remove last comma.
685  break;
686 
687  case NC_USHORT:
688  ups = XMALLOC(uint16_t, len);
689  status = nc_get_att_ushort(ncid, varid, name, ups);
690  if (status != NC_NOERR) {
691  XFREE(ups);
692  return;
693  }
694 
695  for (i = 0; i < (int) len; ++i) {
696  sprintf(tmpstr, "%d,", ups[i]);
697  strcat(str, tmpstr);
698  }
699 
700  XFREE(ups);
701  str[strlen(str) - 1] = '\0'; // Remove last comma.
702  break;
703 
704  case NC_INT:
705  pi = XMALLOC(int, len);
706  status = nc_get_att_int(ncid, varid, name, pi);
707  if (status != NC_NOERR) {
708  XFREE(pi);
709  return;
710  }
711 
712  for (i = 0; i < (int) len; ++i) {
713  sprintf(tmpstr, "%d,", pi[i]);
714  strcat(str, tmpstr);
715  }
716 
717  XFREE(pi);
718  str[strlen(str) - 1] = '\0'; // Remove last comma.
719  break;
720 
721  case NC_UINT:
722  upi = XMALLOC(uint, len);
723  status = nc_get_att_uint(ncid, varid, name, upi);
724  if (status != NC_NOERR) {
725  XFREE(upi);
726  return;
727  }
728 
729  for (i = 0; i < (int) len; ++i) {
730  sprintf(tmpstr, "%d,", upi[i]);
731  strcat(str, tmpstr);
732  }
733 
734  XFREE(upi);
735  str[strlen(str) - 1] = '\0'; // Remove last comma.
736  break;
737 
738  case NC_INT64:
739  pl = XMALLOC(long, len);
740  status = nc_get_att_long(ncid, varid, name, pl);
741  if (status != NC_NOERR) {
742  XFREE(pl);
743  return;
744  }
745 
746  for (i = 0; i < (int) len; ++i) {
747  sprintf(tmpstr, "%ld,", pl[i]);
748  strcat(str, tmpstr);
749  }
750 
751  XFREE(pl);
752  str[strlen(str) - 1] = '\0'; // Remove last comma.
753  break;
754 
755  case NC_UINT64:
756  upl = XMALLOC(uint64_t, len);
757  status = nc_get_att_long(ncid, varid, name, (long*)upl);
758  if (status != NC_NOERR) {
759  XFREE(upl);
760  return;
761  }
762 
763  for (i = 0; i < (int) len; ++i) {
764  sprintf(tmpstr, "%llu,", (long long unsigned int)upl[i]);
765  strcat(str, tmpstr);
766  }
767 
768  XFREE(upl);
769  str[strlen(str) - 1] = '\0'; // Remove last comma.
770  break;
771 
772  case NC_FLOAT:
773  pf = XMALLOC(float, len);
774  status = nc_get_att_float(ncid, varid, name, pf);
775  if (status != NC_NOERR) {
776  XFREE(pf);
777  return;
778  }
779 
780  for (i = 0; i < (int) len; ++i) {
781  sprintf(tmpstr, "%.9g,", pf[i]);
782  strcat(str, tmpstr);
783  }
784 
785  XFREE(pf);
786  str[strlen(str) - 1] = '\0'; // Remove last comma.
787  break;
788 
789  case NC_DOUBLE:
790  pd = XMALLOC(double, len);
791  status = nc_get_att_double(ncid, varid, name, pd);
792  if (status != NC_NOERR) {
793  XFREE(pd);
794  return;
795  }
796 
797  for (i = 0; i < (int) len; ++i) {
798  sprintf(tmpstr, "%.17g,", pd[i]);
799  strcat(str, tmpstr);
800  }
801 
802  XFREE(pd);
803  str[strlen(str) - 1] = '\0'; // Remove last comma.
804  break;
805  }
806 }
807 
808 /* *********************************************************** */
809 int cmpatt(int ncid1, int ncid2, int varid1, int varid2,
810  char* name, char* varname, nccmpopts* opts) {
811  int ncstatus, status;
812  nc_type type1, type2;
813  size_t lenp1, lenp2;
814  char typestr1[4096];
815  char typestr2[4096];
816 
818  ncstatus = nc_inq_att(ncid1, varid1, name, &type1, &lenp1);
819  if (ncstatus != NC_NOERR) {
820  fprintf(stderr, "DIFFER : VARIABLE \"%s%s\" IS MISSING ATTRIBUTE WITH NAME \"%s\" IN FILE \"%s\"\n", getGroupPath(), varname, name, opts->file1);
821 
822  if (!opts->warn[NCCMP_W_ALL])
824 
825  return status;
826  }
827 
828  ncstatus = nc_inq_att(ncid2, varid2, name, &type2, &lenp2);
829  if (ncstatus != NC_NOERR) {
830  fprintf(stderr, "DIFFER : VARIABLE \"%s%s\" IS MISSING ATTRIBUTE WITH NAME \"%s\" IN FILE \"%s\"\n", getGroupPath(), varname, name, opts->file2);
831 
832  if (!opts->warn[NCCMP_W_ALL])
834 
835  return status;
836  }
837 
838  if (type1 != type2) {
839  type2string(type1, typestr1);
840  type2string(type2, typestr2);
841  fprintf(stderr, "DIFFER : TYPES : ATTRIBUTE : %s : VARIABLE : %s%s : %s <> %s\n", name, getGroupPath(), varname, typestr1, typestr2);
842 
843  if (!opts->warn[NCCMP_W_ALL])
845 
846  return status;
847  }
848 
849  if (lenp1 != lenp2) {
850  prettyprintatt(ncid1, varname, varid1, name, typestr1);
851  prettyprintatt(ncid2, varname, varid2, name, typestr2);
852 
853  fprintf(stderr, "DIFFER : LENGTHS : ATTRIBUTE : %s : VARIABLE : %s%s : %lu <> %lu : VALUES : ", name, getGroupPath(), varname, (unsigned long) lenp1, (unsigned long) lenp2);
854 
855  switch (type1) {
856  case NC_CHAR:
857  /* Quote strings. */
858  fprintf(stderr, "\"%s\" : \"%s\"\n", typestr1, typestr2);
859  if (strcmp(typestr1, typestr2) == 0) {
860  /* Same text, but invisible trailing nulls because lengths differ. */
861  if (opts->warn[NCCMP_W_EOS] || opts->warn[NCCMP_W_ALL]) {
862  /* Pass */
863  } else {
865  return status;
866  }
867  }
868  break;
869  default:
870  /* Unquoted. */
871  fprintf(stderr, "%s : %s\n", typestr1, typestr2);
872  if (!opts->warn[NCCMP_W_ALL]) {
874  return status;
875  }
876  break;
877  }
878  } else if (cmpattval(ncid1, ncid2, varid1, varid2, name, lenp1, type1) != NC_NOERR) {
879  prettyprintatt(ncid1, varname, varid1, name, typestr1);
880  prettyprintatt(ncid2, varname, varid2, name, typestr2);
881  fprintf(stderr, "DIFFER : VARIABLE : %s%s : ATTRIBUTE : %s : VALUES : ", getGroupPath(), varname, name);
882 
883  switch (type1) {
884  case NC_CHAR:
885  /* Quote strings. */
886  fprintf(stderr, "\"%s\" <> \"%s\"\n", typestr1, typestr2);
887  break;
888  default:
889  /* Unquoted. */
890  fprintf(stderr, "%s <> %s\n", typestr1, typestr2);
891  break;
892  }
893 
894  if (!opts->warn[NCCMP_W_ALL]) {
896  return status;
897  }
898  }
899 
900  return EXIT_SUCCESS;
901 }
902 
903 
904 /* *********************************************************** */
905 
906 /* Assumes that both attributes have same length.
907  */
908 int cmpattval(int nc1, int nc2, int varid1, int varid2, char* name, int len, nc_type type) {
909  char* c1;
910  int8_t* uc1;
911  uint8_t* uuc1;
912  short* s1;
913  uint16_t* us1;
914  int* i1;
915  uint* ui1;
916  long* l1;
917  uint64_t* ul1;
918  float* f1;
919  double* d1;
920  char* c2;
921  int8_t* uc2;
922  uint8_t* uuc2;
923  short* s2;
924  uint16_t* us2;
925  int* i2;
926  uint* ui2;
927  long* l2;
928  uint64_t* ul2;
929  float* f2;
930  double* d2;
931  int status;
932  int i;
933 
934  if (name == NULL) return NC_EINVAL;
935 
936  switch (type) {
937  case NC_BYTE:
938  uc1 = XMALLOC(int8_t, len);
939  uc2 = XMALLOC(int8_t, len);
940  status = nc_get_att(nc1, varid1, name, uc1);
941  if (status != NC_NOERR) {
942  XFREE(uc1);
943  XFREE(uc2);
944  return NC_EINVAL;
945  }
946  status = nc_get_att(nc2, varid2, name, uc2);
947  if (status != NC_NOERR) {
948  XFREE(uc1);
949  XFREE(uc2);
950  return NC_EINVAL;
951  }
952  for (i = 0; i < len; ++i) {
953  if (uc1[i] != uc2[i]) {
954  XFREE(uc1);
955  XFREE(uc2);
956  return EXIT_DIFFER;
957  }
958  }
959  XFREE(uc1);
960  XFREE(uc2);
961  break;
962  case NC_UBYTE:
963  uuc1 = XMALLOC(uint8_t, len);
964  uuc2 = XMALLOC(uint8_t, len);
965  status = nc_get_att_ubyte(nc1, varid1, name, uuc1);
966  if (status != NC_NOERR) {
967  XFREE(uuc1);
968  XFREE(uuc2);
969  return NC_EINVAL;
970  }
971  status = nc_get_att_ubyte(nc2, varid2, name, uuc2);
972  if (status != NC_NOERR) {
973  XFREE(uuc1);
974  XFREE(uuc2);
975  return NC_EINVAL;
976  }
977  for (i = 0; i < len; ++i) {
978  if (uuc1[i] != uuc2[i]) {
979  XFREE(uuc1);
980  XFREE(uuc2);
981  return EXIT_DIFFER;
982  }
983  }
984  XFREE(uuc1);
985  XFREE(uuc2);
986  break;
987  case NC_CHAR:
988  c1 = XMALLOC(char, len);
989  c2 = XMALLOC(char, len);
990  status = nc_get_att_text(nc1, varid1, name, c1);
991  if (status != NC_NOERR) {
992  XFREE(c1);
993  XFREE(c2);
994  return NC_EINVAL;
995  }
996  status = nc_get_att_text(nc2, varid2, name, c2);
997  if (status != NC_NOERR) {
998  XFREE(c1);
999  XFREE(c2);
1000  return NC_EINVAL;
1001  }
1002  if (strncmp(c1, c2, len) != 0) {
1003  XFREE(c1);
1004  XFREE(c2);
1005  return EXIT_DIFFER;
1006  }
1007  XFREE(c1);
1008  XFREE(c2);
1009  break;
1010  case NC_SHORT:
1011  s1 = XMALLOC(short, len);
1012  s2 = XMALLOC(short, len);
1013  status = nc_get_att_short(nc1, varid1, name, s1);
1014  if (status != NC_NOERR) {
1015  XFREE(s1);
1016  XFREE(s2);
1017  return NC_EINVAL;
1018  }
1019  status = nc_get_att_short(nc2, varid2, name, s2);
1020  if (status != NC_NOERR) {
1021  XFREE(s1);
1022  XFREE(s2);
1023  return NC_EINVAL;
1024  }
1025  for (i = 0; i < len; ++i) {
1026  if (s1[i] != s2[i]) {
1027  XFREE(s1);
1028  XFREE(s2);
1029  return EXIT_DIFFER;
1030  }
1031  }
1032  XFREE(s1);
1033  XFREE(s2);
1034  break;
1035  case NC_USHORT:
1036  us1 = XMALLOC(uint16_t, len);
1037  us2 = XMALLOC(uint16_t, len);
1038  status = nc_get_att_ushort(nc1, varid1, name, us1);
1039  if (status != NC_NOERR) {
1040  XFREE(us1);
1041  XFREE(us2);
1042  return NC_EINVAL;
1043  }
1044  status = nc_get_att_ushort(nc2, varid2, name, us2);
1045  if (status != NC_NOERR) {
1046  XFREE(us1);
1047  XFREE(us2);
1048  return NC_EINVAL;
1049  }
1050  for (i = 0; i < len; ++i) {
1051  if (us1[i] != us2[i]) {
1052  XFREE(us1);
1053  XFREE(us2);
1054  return EXIT_DIFFER;
1055  }
1056  }
1057  XFREE(us1);
1058  XFREE(us2);
1059  break;
1060  case NC_INT:
1061  i1 = XMALLOC(int, len);
1062  i2 = XMALLOC(int, len);
1063  status = nc_get_att_int(nc1, varid1, name, i1);
1064  if (status != NC_NOERR) {
1065  XFREE(i1);
1066  XFREE(i2);
1067  return NC_EINVAL;
1068  }
1069  status = nc_get_att_int(nc2, varid2, name, i2);
1070  if (status != NC_NOERR) {
1071  XFREE(i1);
1072  XFREE(i2);
1073  return NC_EINVAL;
1074  }
1075  for (i = 0; i < len; ++i) {
1076  if (i1[i] != i2[i]) {
1077  XFREE(i1);
1078  XFREE(i2);
1079  return EXIT_DIFFER;
1080  }
1081  }
1082  XFREE(i1);
1083  XFREE(i2);
1084  break;
1085  case NC_UINT:
1086  ui1 = XMALLOC(uint, len);
1087  ui2 = XMALLOC(uint, len);
1088  status = nc_get_att_uint(nc1, varid1, name, ui1);
1089  if (status != NC_NOERR) {
1090  XFREE(ui1);
1091  XFREE(ui2);
1092  return NC_EINVAL;
1093  }
1094  status = nc_get_att_uint(nc2, varid2, name, ui2);
1095  if (status != NC_NOERR) {
1096  XFREE(ui1);
1097  XFREE(ui2);
1098  return NC_EINVAL;
1099  }
1100  for (i = 0; i < len; ++i) {
1101  if (ui1[i] != ui2[i]) {
1102  XFREE(ui1);
1103  XFREE(ui2);
1104  return EXIT_DIFFER;
1105  }
1106  }
1107  XFREE(ui1);
1108  XFREE(ui2);
1109  break;
1110  case NC_INT64:
1111  l1 = XMALLOC(long, len);
1112  l2 = XMALLOC(long, len);
1113  status = nc_get_att_long(nc1, varid1, name, l1);
1114  if (status != NC_NOERR) {
1115  XFREE(l1);
1116  XFREE(l2);
1117  return NC_EINVAL;
1118  }
1119  status = nc_get_att_long(nc2, varid2, name, l2);
1120  if (status != NC_NOERR) {
1121  XFREE(l1);
1122  XFREE(l2);
1123  return NC_EINVAL;
1124  }
1125  for (i = 0; i < len; ++i) {
1126  if (l1[i] != l2[i]) {
1127  XFREE(l1);
1128  XFREE(l2);
1129  return EXIT_DIFFER;
1130  }
1131  }
1132  XFREE(l1);
1133  XFREE(l2);
1134  break;
1135  case NC_UINT64:
1136  ul1 = XMALLOC(uint64_t, len);
1137  ul2 = XMALLOC(uint64_t, len);
1138  status = nc_get_att_long(nc1, varid1, name, (long*)ul1);
1139  if (status != NC_NOERR) {
1140  XFREE(ul1);
1141  XFREE(ul2);
1142  return NC_EINVAL;
1143  }
1144  status = nc_get_att_long(nc2, varid2, name, (long*)ul2);
1145  if (status != NC_NOERR) {
1146  XFREE(ul1);
1147  XFREE(ul2);
1148  return NC_EINVAL;
1149  }
1150  for (i = 0; i < len; ++i) {
1151  if (ul1[i] != ul2[i]) {
1152  XFREE(ul1);
1153  XFREE(ul2);
1154  return EXIT_DIFFER;
1155  }
1156  }
1157  XFREE(ul1);
1158  XFREE(ul2);
1159  break;
1160  case NC_FLOAT:
1161  f1 = XMALLOC(float, len);
1162  f2 = XMALLOC(float, len);
1163  status = nc_get_att_float(nc1, varid1, name, f1);
1164  if (status != NC_NOERR) {
1165  XFREE(f1);
1166  XFREE(f2);
1167  return NC_EINVAL;
1168  }
1169  status = nc_get_att_float(nc2, varid2, name, f2);
1170  if (status != NC_NOERR) {
1171  XFREE(f1);
1172  XFREE(f2);
1173  return NC_EINVAL;
1174  }
1175  for (i = 0; i < len; ++i) {
1176  if (f1[i] != f2[i]) {
1177  XFREE(f1);
1178  XFREE(f2);
1179  return EXIT_DIFFER;
1180  }
1181  }
1182  XFREE(f1);
1183  XFREE(f2);
1184  break;
1185  case NC_DOUBLE:
1186  d1 = XMALLOC(double, len);
1187  d2 = XMALLOC(double, len);
1188  status = nc_get_att_double(nc1, varid1, name, d1);
1189  if (status != NC_NOERR) {
1190  XFREE(d1);
1191  XFREE(d2);
1192  return NC_EINVAL;
1193  }
1194  status = nc_get_att_double(nc2, varid2, name, d2);
1195  if (status != NC_NOERR) {
1196  XFREE(d1);
1197  XFREE(d2);
1198  return NC_EINVAL;
1199  }
1200  for (i = 0; i < len; ++i) {
1201  if (d1[i] != d2[i]) {
1202  XFREE(d1);
1203  XFREE(d2);
1204  return EXIT_DIFFER;
1205  }
1206  }
1207  XFREE(d1);
1208  XFREE(d2);
1209  break;
1210  }
1211 
1212  return EXIT_SUCCESS;
1213 }
1214 
1215 /* *********************************************************** */
1216 void type2string(nc_type type, char* str) {
1217  switch (type) {
1218  case NC_BYTE:
1219  strcpy(str, "BYTE");
1220  break;
1221  case NC_UBYTE:
1222  strcpy(str, "UBYTE");
1223  break;
1224  case NC_CHAR:
1225  strcpy(str, "CHAR");
1226  break;
1227  case NC_SHORT:
1228  strcpy(str, "SHORT");
1229  break;
1230  case NC_USHORT:
1231  strcpy(str, "USHORT");
1232  break;
1233  case NC_INT:
1234  strcpy(str, "INT");
1235  break;
1236  case NC_UINT:
1237  strcpy(str, "UINT");
1238  break;
1239  case NC_INT64:
1240  strcpy(str, "LONG");
1241  break;
1242  case NC_UINT64:
1243  strcpy(str, "ULONG");
1244  break;
1245  case NC_FLOAT:
1246  strcpy(str, "FLOAT");
1247  break;
1248  case NC_DOUBLE:
1249  strcpy(str, "DOUBLE");
1250  break;
1251  default:
1252  strcpy(str, "");
1253  break;
1254  }
1255 }
1256 
1257 /* *********************************************************** */
1258 int openfiles(nccmpopts* opts, int *ncid1, int *ncid2) {
1259  int status;
1260 
1261  status = nc_open(opts->file1, NC_NOWRITE, ncid1);
1263 
1264  status = nc_open(opts->file2, NC_NOWRITE, ncid2);
1266 
1267  return 0;
1268 }
1269 /* *********************************************************** */
1270 
1271 /* Compares record names and lengths. */
1272 int
1273 nccmprecinfo(nccmpopts* opts, int ncid1, int ncid2) {
1274  char name1[256], name2[256];
1275  int status;
1276 
1277  status = EXIT_SUCCESS;
1278 
1279  if (opts->verbose)
1280  printf("INFO: Comparing record information.\n");
1281 
1282  status = nc_inq_unlimdim(ncid1, &recid1);
1284 
1285  if (recid1 != -1) {
1286  status = nc_inq_dim(ncid1, recid1, name1, &nrec1);
1288  } else {
1289  nrec1 = 0;
1290  }
1291 
1292  status = nc_inq_unlimdim(ncid2, &recid2);
1294 
1295  if (recid2 != -1) {
1296  status = nc_inq_dim(ncid2, recid2, name2, &nrec2);
1298  } else {
1299  nrec2 = 0;
1300  }
1301 
1302  if (instringlist(opts->excludelist, name1, opts->nexclude) ||
1303  instringlist(opts->excludelist, name2, opts->nexclude) ||
1304  !instringlist(opts->variablelist, name1, opts->nvariable) ||
1305  !instringlist(opts->variablelist, name2, opts->nvariable))
1306  return EXIT_SUCCESS;
1307 
1308  if (strcmp(name1, name2)) {
1309  fprintf(stderr, "DIFFER : NAMES OF RECORDS : %s <> %s\n", name1, name2);
1310  if (!opts->warn[NCCMP_W_ALL])
1311  status = EXIT_DIFFER;
1312 
1313  if (!opts->force) return status;
1314  }
1315 
1316  if (nrec1 != nrec2) {
1317  fprintf(stderr, "DIFFER : LENGTHS OF RECORDS : %s (%d) <> %s (%d)\n", name1, (int) nrec1, name2, (int) nrec2);
1318  if (!opts->warn[NCCMP_W_ALL])
1319  status = EXIT_DIFFER;
1320 
1321  if (!opts->force) return status;
1322  }
1323 
1324  return status;
1325 }
1326 
1327 void getgroupinfo(int ncid, vector<string> names, GROUP_NODE *groups) {
1328  int *gids;
1329  size_t i;
1330  size_t index;
1331  int numGroups;
1332  char name[NC_MAX_NAME];
1333  vector<string> groupNames;
1334 
1335  nc_inq_grps(ncid, &numGroups, NULL);
1336  gids = (int *) malloc(sizeof (int) * numGroups);
1337  nc_inq_grps(ncid, NULL, gids);
1338 
1339  for (i = 0; i < (size_t)numGroups; i++) {
1340  nc_inq_grpname(gids[i], name);
1341  groupNames.push_back(name);
1342  }
1343 
1344  for (index = 0; index < names.size(); index++) {
1345  for (i = 0; i < groupNames.size(); i++) {
1346  if(groupNames[i] == names[index]) {
1347  groups[index].groupID = gids[i];
1348  strcpy(groups[index].groupName, names[index].c_str());
1349  break;
1350  }
1351  }
1352  }
1353  free(gids);
1354 }
1355 
1356 /* *********************************************************** */
1357 
1358 /* Get dim info for file. */
1359 void getdiminfo(int ncid, dimstruct* dims, int* ndims) {
1360  int status, i;
1361 
1362  status = nc_inq_ndims(ncid, ndims);
1364 
1365  // Query all dimids, which may not be from 0..N-1 in a HDF file.
1366  int dimids[(int) NC_MAX_DIMS];
1367  int include_parents = 1;
1368  status = nc_inq_dimids(ncid, ndims, dimids, include_parents);
1370 
1371  for (i = 0; i < *ndims; ++i) {
1372  dims[i].dimid = dimids[i];
1373  status = nc_inq_dim(ncid, dimids[i], dims[i].name, &dims[i].len);
1375  }
1376 }
1377 /* *********************************************************** */
1378 
1379 /* Copy attribute type to same type as var, just in case of mismatch. */
1380 void broadcast_missing(nc_type var_type, nc_type att_type, missing_struct *values) {
1381 #define BROADCAST_MISSING(T) { \
1382  switch(att_type) { \
1383  case NC_CHAR: values->T = values->c; break; \
1384  case NC_BYTE: values->T = values->b; break; \
1385  case NC_UBYTE: values->T = values->ub; break; \
1386  case NC_SHORT: values->T = values->s; break; \
1387  case NC_USHORT: values->T = values->us; break; \
1388  case NC_INT: values->T = values->i; break; \
1389  case NC_UINT: values->T = values->ui; break; \
1390  case NC_INT64: values->T = values->l; break; \
1391  case NC_UINT64: values->T = values->ul; break; \
1392  case NC_FLOAT: values->T = values->f; break; \
1393  case NC_DOUBLE: values->T = values->d; break; \
1394  } \
1395  }
1396 
1397  switch (var_type) {
1398  case NC_CHAR: BROADCAST_MISSING(c);
1399  break;
1400  case NC_BYTE: BROADCAST_MISSING(b);
1401  break;
1402  case NC_SHORT: BROADCAST_MISSING(s);
1403  break;
1404  case NC_UBYTE: BROADCAST_MISSING(ub);
1405  break;
1406  case NC_USHORT: BROADCAST_MISSING(us);
1407  break;
1408  case NC_INT: BROADCAST_MISSING(i);
1409  break;
1410  case NC_UINT: BROADCAST_MISSING(ui);
1411  break;
1412  case NC_INT64: BROADCAST_MISSING(l);
1413  break;
1414  case NC_UINT64: BROADCAST_MISSING(ul);
1415  break;
1416  case NC_FLOAT: BROADCAST_MISSING(f);
1417  break;
1418  case NC_DOUBLE: BROADCAST_MISSING(d);
1419  break;
1420  }
1421 }
1422 
1423 /* *********************************************************** */
1424 char get_missing(int ncid, varstruct * var, const char* attname) {
1425  nc_type att_type;
1426  int status;
1427 
1428  status = nc_inq_atttype(ncid, var->varid, attname, &att_type);
1429  if (status != NC_NOERR) return 0;
1430 
1431  var->missing.type = att_type;
1432 
1433  switch (att_type) {
1434  case NC_CHAR:
1435  status = nc_get_att_text(ncid, var->varid, attname, &var->missing.c);
1436  if (status != NC_NOERR) return 0;
1437  break;
1438  case NC_BYTE:
1439  status = nc_get_att(ncid, var->varid, attname, &var->missing.b);
1440  if (status != NC_NOERR) return 0;
1441  break;
1442  case NC_UBYTE:
1443  status = nc_get_att_ubyte(ncid, var->varid, attname, &var->missing.ub);
1444  if (status != NC_NOERR) return 0;
1445  break;
1446  case NC_SHORT:
1447  status = nc_get_att_short(ncid, var->varid, attname, &var->missing.s);
1448  if (status != NC_NOERR) return 0;
1449  break;
1450  case NC_USHORT:
1451  status = nc_get_att_ushort(ncid, var->varid, attname, &var->missing.us);
1452  if (status != NC_NOERR) return 0;
1453  break;
1454  case NC_INT:
1455  status = nc_get_att_int(ncid, var->varid, attname, &var->missing.i);
1456  if (status != NC_NOERR) return 0;
1457  break;
1458  case NC_UINT:
1459  status = nc_get_att_uint(ncid, var->varid, attname, &var->missing.ui);
1460  if (status != NC_NOERR) return 0;
1461  break;
1462  case NC_INT64:
1463  status = nc_get_att_longlong(ncid, var->varid, attname, (long long *)&var->missing.l);
1464  if (status != NC_NOERR) return 0;
1465  break;
1466  case NC_UINT64:
1467  status = nc_get_att_ulonglong(ncid, var->varid, attname, (unsigned long long *)&var->missing.ul);
1468  if (status != NC_NOERR) return 0;
1469  break;
1470  case NC_FLOAT:
1471  status = nc_get_att_float(ncid, var->varid, attname, &var->missing.f);
1472  if (status != NC_NOERR) return 0;
1473  break;
1474  case NC_DOUBLE:
1475  status = nc_get_att_double(ncid, var->varid, attname, &var->missing.d);
1476  if (status != NC_NOERR) return 0;
1477  break;
1478  default: return 0;
1479  }
1480 
1481  var->hasmissing = 1;
1482  broadcast_missing(var->type, att_type, &var->missing);
1483 
1484  return 1;
1485 }
1486 /* *****************************s****************************** */
1487 
1488 /* Read all the file's metadata for variables. */
1489 nccmp_user_type_t* getvarinfo(int ncid, varstruct* vars, int* nvars, int verbose, int *nuser_types) {
1490  int status, i, j, recid;
1491  nccmp_user_type_t* comp_types = NULL;
1492 
1493  status = nc_inq_nvars(ncid, nvars);
1495 
1496  // see if it has any compound types
1497  comp_types = nccmp_load_group_usertype_array(ncid, nuser_types);
1498 
1499  status = nc_inq_unlimdim(ncid, &recid);
1501 
1502  for (i = 0; i < *nvars; ++i) {
1503  vars[i].varid = i;
1504  status = nc_inq_var(ncid, i, vars[i].name, &vars[i].type,
1505  &vars[i].ndims, vars[i].dimids, &vars[i].natts);
1506 
1507  vars[i].user_type_idx = -1;
1508 
1509  if (*nuser_types > 0) {
1510  for (j = 0; j<*nuser_types; j++) {
1511  if (vars[i].type == comp_types[j].type_id)
1512  vars[i].user_type_idx = j;
1513  }
1514  }
1516 
1517  vars[i].len = 1;
1518  for (j = 0; j < vars[i].ndims; ++j) {
1519  status = nc_inq_dimlen(ncid, vars[i].dimids[j], &vars[i].dimlens[j]);
1521 #ifdef __DEBUG__
1522  printf("DEBUG : %d : %s dimid %d, len %d\n", __LINE__, vars[i].name, j, vars[i].dimlens[j]);
1523 #endif
1524  vars[i].len *= vars[i].dimlens[j];
1525  }
1526 
1527  vars[i].hasrec = (vars[i].dimids[0] == recid);
1528 
1529  /* Get missing_value or _FillValue. */
1530  if (get_missing(ncid, &vars[i], "missing_value") == 0)
1531  get_missing(ncid, &vars[i], "_FillValue");
1532 
1533  if (verbose) {
1534  if (vars[i].hasmissing) {
1535  printf("INFO: \"%s\" missing value: ", vars[i].name);
1536  switch (vars[i].missing.type) {
1537  case NC_BYTE: printf("%hhd (byte)\n", vars[i].missing.b);
1538  break;
1539  case NC_UBYTE: printf("%hhu (ubyte)\n", vars[i].missing.ub);
1540  break;
1541  case NC_CHAR: printf("%c (char)\n", vars[i].missing.c);
1542  break;
1543  case NC_SHORT: printf("%hd (short)\n", vars[i].missing.s);
1544  break;
1545  case NC_USHORT: printf("%hu (ushort)\n", vars[i].missing.us);
1546  break;
1547  case NC_INT: printf("%d (int)\n", vars[i].missing.i);
1548  break;
1549  case NC_UINT: printf("%u (uint)\n", vars[i].missing.ui);
1550  break;
1551  case NC_INT64: printf("%lld (int64)\n", (long long)vars[i].missing.l);
1552  break;
1553  case NC_UINT64: printf("%llu (uint64)\n", (unsigned long long)vars[i].missing.ul);
1554  break;
1555  case NC_FLOAT: printf("%g (float)\n", vars[i].missing.f);
1556  break;
1557  case NC_DOUBLE: printf("%g (double)\n", vars[i].missing.d);
1558  break;
1559  }
1560  }
1561  }
1562  }
1563  return comp_types;
1564 }
1565 /* *********************************************************** */
1566 
1567 /* free all the file's metadata for variables. */
1568 void freevarinfo(int nuser_types, nccmp_user_type_t* comp_types) {
1569  int i;
1570  nccmp_user_type_t* ptr = comp_types;
1571 
1572  for(i=0; i<nuser_types; i++) {
1573  free(ptr->fields);
1574  ptr++;
1575  }
1576 
1577  free(comp_types);
1578 }
1579 /* *********************************************************** */
1580 
1581 /* Returns index to varstruct in list, otherwise -1. */
1582 int isinvarstructlist(char* name, varstruct* vars, int nvars) {
1583  int i;
1584 
1585  for (i = 0; i < nvars; ++i) {
1586  if (strcmp(name, vars[i].name) == 0)
1587  return i;
1588  }
1589 
1590  return -1;
1591 }
1592 /* *********************************************************** */
1593 
1594 /* Get vars to use to do cmp based on input and exclusion lists. */
1595 int makecmpvarlist(nccmpopts* opts, int ncid1, int ncid2) {
1596  int status, i;
1597 
1598  // opts->ncmpvarlist = (int)NC_MAX_VARS;
1599  freestringlist(&opts->cmpvarlist, opts->ncmpvarlist);
1600 
1601  newstringlist(&opts->cmpvarlist, &opts->ncmpvarlist, (int) NC_MAX_VARS);
1602  if (opts->variable) {
1603  if (opts->verbose)
1604  printf("INFO: Using variables provided in list.\n");
1605 
1606  status = strlistu(opts->variablelist, opts->cmpvarlist, opts->cmpvarlist,
1607  opts->nvariable, opts->ncmpvarlist, opts->ncmpvarlist);
1608  } else if (opts->exclude) {
1609  if (opts->verbose)
1610  printf("INFO: Excluding variables in provided list.\n");
1611 
1612  status = excludevars(ncid1, ncid2, opts->cmpvarlist, opts->ncmpvarlist, opts->excludelist, opts->nexclude);
1613  } else {
1614  if (opts->verbose)
1615  printf("INFO: Using all variables.\n");
1616 
1617  status = allvarnames(opts->cmpvarlist, opts->ncmpvarlist, ncid1, ncid2);
1618  }
1619 
1620  opts->ncmpvarlist = getnumstrlist(opts->cmpvarlist, (int) NC_MAX_VARS);
1621  if (opts->verbose) {
1622  printf("INFO: Variables to compare (%d):\n", opts->ncmpvarlist);
1623  for (i = 0; i < opts->ncmpvarlist - 1; ++i)
1624  printf("%s, ", opts->cmpvarlist[i]);
1625 
1626  if (opts->ncmpvarlist)
1627  printf("%s\n", opts->cmpvarlist[i]);
1628  }
1629 
1630  return status;
1631 }
1632 /* *********************************************************** */
1633 
1634 /* Gets list of all variable names in both input files. */
1635 int
1636 allvarnames(char** list, int nvars, int ncid1, int ncid2) {
1637  char** tmplist = NULL;
1638  int ntmp;
1639 
1640  newstringlist(&tmplist, &ntmp, NC_MAX_VARS);
1641 
1642  if (ncallvars(ncid1, tmplist, ntmp))
1643  return 1;
1644 
1645  /* printf("%d: ncallvars returned.\n", __LINE__); */
1646 
1647  if (strlistu(tmplist, list, list, ntmp, nvars, nvars))
1648  return 1;
1649 
1650  /* printf("%d: Variable names from file 1 collected.\n", __LINE__); */
1651  clearstringlist(tmplist, NC_MAX_VARS);
1652 
1653  if (ncallvars(ncid2, tmplist, ntmp))
1654  return 1;
1655 
1656  if (strlistu(tmplist, list, list, ntmp, nvars, nvars))
1657  return 1;
1658 
1659  /* printf("%d: Variable names from file 2 collected.\n", __LINE__); */
1660  freestringlist(&tmplist, ntmp);
1661 
1662  return EXIT_SUCCESS;
1663 }
1664 
1665 /* *********************************************************** */
1666 
1667 int
1668 nccmpformats(nccmpopts* opts, int ncid1, int ncid2) {
1669  int status, fmt1, fmt2;
1670 
1671  status = nc_inq_format(ncid1, &fmt1);
1673 
1674  status = nc_inq_format(ncid2, &fmt2);
1676 
1677  if (fmt1 != fmt2) {
1678  fprintf(stderr, "DIFFER : FILE FORMATS : %s <> %s\n", NCFORMATSTR(fmt1), NCFORMATSTR(fmt2));
1679 
1680  if (!opts->warn[NCCMP_W_ALL] &&
1681  !opts->warn[NCCMP_W_FORMAT])
1682  return EXIT_DIFFER;
1683  }
1684 
1685  return EXIT_SUCCESS;
1686 }
1687 
1688 /* *********************************************************** */
1689 
1690 int
1691 nccmpglobalatts(nccmpopts* opts, int ncid1, int ncid2) {
1692  int ngatts1, ngatts2, nattsex1, nattsex2, i, status, status2, attid1, attid2;
1693  nc_type type1, type2;
1694  size_t len1, len2;
1695  char name1[NC_MAX_NAME], name2[NC_MAX_NAME];
1696  char** processedatts = NULL;
1697  char typestr1[4096], typestr2[4096];
1698  const string hstry("history");
1699 
1700  status = EXIT_SUCCESS;
1701  status2 = status;
1702  if (!opts->global)
1703  return status;
1704 
1705  if (opts->history == 0)
1706  appendstringtolist(&opts->globalexclude, hstry.c_str(), &opts->nglobalexclude);
1707 
1708  /*
1709  printf("globalexclude =");
1710  printstrlist(opts->globalexclude, opts->nglobalexclude, stdout);
1711  */
1712 
1713  /* Number of global atts to compare with exclusion taken into account. */
1714  nattsex1 = 0;
1715  nattsex2 = 0;
1716 
1717  status = nc_inq_natts(ncid1, &ngatts1);
1719 
1720  status = nc_inq_natts(ncid2, &ngatts2);
1722 
1723  for (i = 0; i < ngatts1; ++i) {
1724  attid1 = i;
1725  status = nc_inq_attname(ncid1, NC_GLOBAL, attid1, name1);
1727 
1728  if (!instringlist(opts->globalexclude, name1, opts->nglobalexclude)) {
1729  ++nattsex1;
1730  }
1731  }
1732 
1733  for (i = 0; i < ngatts2; ++i) {
1734  attid2 = i;
1735  status = nc_inq_attname(ncid2, NC_GLOBAL, attid2, name2);
1737 
1738  if (!instringlist(opts->globalexclude, name2, opts->nglobalexclude)) {
1739  ++nattsex2;
1740  }
1741  }
1742 
1743  if (nattsex1 != nattsex2) {
1744  fprintf(stderr, "DIFFER : NUMBER OF GLOBAL ATTRIBUTES : %d <> %d\n", nattsex1, nattsex2);
1745 
1746  if (!opts->warn[NCCMP_W_ALL])
1747  status2 = EXIT_DIFFER;
1748 
1749  if (!opts->force) return status2;
1750  }
1751 
1752  if (newstringlist(&processedatts, &i, NC_MAX_VARS)) {
1753  fprintf(stderr, "ERROR: Failed to allocated string list for comparing global attributes.\n");
1754  return EXIT_FATAL;
1755  }
1756 
1757  for (i = 0; i < ngatts1; ++i) {
1758  attid1 = i;
1759  status = nc_inq_attname(ncid1, NC_GLOBAL, attid1, name1);
1761 
1762  /* Log that this gatt was processed. */
1763  addstringtolist(processedatts, name1, NC_MAX_VARS);
1764 
1765  if (instringlist(opts->globalexclude, name1, opts->nglobalexclude))
1766  continue;
1767 
1768  status = nc_inq_att(ncid1, NC_GLOBAL, name1, &type1, &len1);
1769  if (status != NC_NOERR) {
1770  fprintf(stderr, "Query failed on global attribute in %s\n", opts->file1);
1771  if (!opts->warn[NCCMP_W_ALL])
1772  status2 = EXIT_DIFFER;
1773 
1774  if (opts->force) continue;
1775  else return status2;
1776  }
1777 
1778  status = nc_inq_att(ncid2, NC_GLOBAL, name1, &type2, &len2);
1779  if (status != NC_NOERR) {
1780  fprintf(stderr, "DIFFER : NAME OF GLOBAL ATTRIBUTE : %s : GLOBAL ATTRIBUTE DOESN'T EXIST IN \"%s\"\n", name1, opts->file2);
1781  if (!opts->warn[NCCMP_W_ALL])
1782  status2 = EXIT_DIFFER;
1783 
1784  if (opts->force) continue;
1785  else return status2;
1786  }
1787 
1788  if (type1 != type2) {
1789  type2string(type1, typestr1);
1790  type2string(type2, typestr2);
1791  fprintf(stderr, "DIFFER : GLOBAL ATTRIBUTE TYPES : %s : %s <> %s\n", name1, typestr1, typestr2);
1792  if (!opts->warn[NCCMP_W_ALL])
1793  status2 = EXIT_DIFFER;
1794 
1795  if (opts->force) continue;
1796  else return status2;
1797  }
1798 
1799  if (len1 != len2) {
1800  prettyprintatt(ncid1, NULL, NC_GLOBAL, name1, typestr1);
1801  prettyprintatt(ncid2, NULL, NC_GLOBAL, name1, typestr2);
1802  fprintf(stderr, "DIFFER : LENGTHS OF GLOBAL ATTRIBUTE : %s : %lu <> %lu : VALUES : %s <> %s\n", name1,
1803  (unsigned long) len1, (unsigned long) len2, typestr1, typestr2);
1804  if (!opts->warn[NCCMP_W_ALL])
1805  status2 = EXIT_DIFFER;
1806 
1807  if (opts->force) continue;
1808  else return status2;
1809  }
1810 
1811  if (cmpattval(ncid1, ncid2, NC_GLOBAL, NC_GLOBAL, name1, len1, type1) != NC_NOERR) {
1812  /* Pretty print values. */
1813  prettyprintatt(ncid1, NULL, NC_GLOBAL, name1, typestr1);
1814  prettyprintatt(ncid2, NULL, NC_GLOBAL, name1, typestr2);
1815  fprintf(stderr, "DIFFER : VALUES OF GLOBAL ATTRIBUTE : %s : %s <> %s\n", name1, typestr1, typestr2);
1816  if (!opts->warn[NCCMP_W_ALL])
1817  status2 = EXIT_DIFFER;
1818 
1819  if (opts->force) continue;
1820  else return status2;
1821  }
1822  }
1823 
1824  for (i = 0; i < ngatts2; ++i) {
1825  attid2 = i;
1826  status = nc_inq_attname(ncid2, NC_GLOBAL, attid2, name2);
1827  if (status != NC_NOERR) {
1828  fprintf(stderr, "Query failed for global attribute name in %s\n", opts->file2);
1829  if (!opts->warn[NCCMP_W_ALL])
1830  status2 = EXIT_DIFFER;
1831 
1832  if (opts->force) continue;
1833  else return status2;
1834  }
1835 
1836  /* Skip if already processed (or excluded). */
1837  if (instringlist(processedatts, name2, NC_MAX_VARS))
1838  continue;
1839 
1840  /* Log that this att was processed. */
1841  addstringtolist(processedatts, name2, NC_MAX_VARS);
1842 
1843  status = nc_inq_att(ncid2, NC_GLOBAL, name2, &type2, &len2);
1844  if (status != NC_NOERR) {
1845  fprintf(stderr, "Query failed on global attribute in %s\n", opts->file2);
1846  if (!opts->warn[NCCMP_W_ALL])
1847  status2 = EXIT_DIFFER;
1848 
1849  if (opts->force) continue;
1850  else return status2;
1851  }
1852 
1853  status = nc_inq_att(ncid1, NC_GLOBAL, name2, &type1, &len1);
1854  if (status != NC_NOERR) {
1855  fprintf(stderr, "DIFFER : NAME OF GLOBAL ATTRIBUTE : %s : GLOBAL ATTRIBUTE DOESN'T EXIST IN %s\n", name2, opts->file1);
1856  if (!opts->warn[NCCMP_W_ALL])
1857  status2 = EXIT_DIFFER;
1858 
1859  if (opts->force) continue;
1860  else return status2;
1861  }
1862 
1863  if (type1 != type2) {
1864  type2string(type1, typestr1);
1865  type2string(type2, typestr2);
1866  fprintf(stderr, "DIFFER : GLOBAL ATTRIBUTE TYPE : %s : %s <> %s\n", name1, typestr1, typestr2);
1867  if (!opts->warn[NCCMP_W_ALL])
1868  status2 = EXIT_DIFFER;
1869 
1870  if (opts->force) continue;
1871  else return status2;
1872  }
1873 
1874  if (len1 != len2) {
1875  prettyprintatt(ncid1, NULL, NC_GLOBAL, name1, typestr1);
1876  prettyprintatt(ncid2, NULL, NC_GLOBAL, name1, typestr2);
1877 
1878  fprintf(stderr, "DIFFER : LENGTHS OF GLOBAL ATTRIBUTE : %s : %lu <> %lu : VALUES : ", name1, (unsigned long) len1, (unsigned long) len2);
1879 
1880  switch (type1) {
1881  case NC_CHAR:
1882  /* Quote strings. */
1883  fprintf(stderr, "\"%s\" : \"%s\"\n", typestr1, typestr2);
1884  if (strcmp(typestr1, typestr2) == 0) {
1885  /* Same text, but invisible trailing nulls because lengths differ. */
1886  if (opts->warn[NCCMP_W_EOS] || opts->warn[NCCMP_W_ALL]) {
1887  /* Pass */
1888  } else {
1889  status2 = EXIT_DIFFER;
1890  if (opts->force) continue;
1891  else return status2;
1892  }
1893  }
1894  break;
1895  default:
1896  /* No quotes. */
1897  fprintf(stderr, "%s : %s\n", typestr1, typestr2);
1898  if (!opts->warn[NCCMP_W_ALL]) {
1899  status2 = EXIT_DIFFER;
1900  if (opts->force) continue;
1901  else return status2;
1902  }
1903  break;
1904  }
1905  }
1906 
1907  if (cmpattval(ncid1, ncid2, NC_GLOBAL, NC_GLOBAL, name1, len1, type1) != NC_NOERR) {
1908  /* Pretty print values. */
1909  prettyprintatt(ncid1, NULL, NC_GLOBAL, name1, typestr1);
1910  prettyprintatt(ncid2, NULL, NC_GLOBAL, name1, typestr2);
1911  fprintf(stderr, "DIFFER : VALUES OF GLOBAL ATTRIBUTE : %s : %s <> %s\n", name1, typestr1, typestr2);
1912  if (!opts->warn[NCCMP_W_ALL])
1913  status2 = EXIT_DIFFER;
1914 
1915  if (opts->force) continue;
1916  else return status2;
1917  }
1918  }
1919 
1920  /* Clear the list. */
1921  freestringlist(&processedatts, NC_MAX_VARS);
1922  processedatts = NULL;
1923 
1924  return status2;
1925 }
1926 
1927 /* *********************************************************** */
1928 int
1929 nccmpmetadata(nccmpopts *opts, int ncid1, int ncid2) {
1930  int i, j, j1, j2, status, ncstatus, dimid1, dimid2, tmp1, tmp2, attid1, attid2, natts1, natts2;
1931  size_t len1, len2;
1932  char name1[NC_MAX_NAME], name2[NC_MAX_NAME], recname1[NC_MAX_NAME], recname2[NC_MAX_NAME], typestr1[1024], typestr2[1024];
1933  char** processedatts = NULL;
1934 
1935  status = EXIT_SUCCESS;
1936 
1937  if (opts->verbose)
1938  printf("INFO: Comparing metadata.\n");
1939 
1940  if (opts->verbose)
1941  printf("INFO: Comparing number of dimensions.\n");
1942 
1943  if (ndims1 != ndims2) {
1944  fprintf(stderr, "DIFFER : NUMBER OF DIMENSIONS IN FILES : %d <> %d\n", ndims1, ndims2);
1945  if (!opts->warn[NCCMP_W_ALL])
1946  status = EXIT_DIFFER;
1947 
1948  if (!opts->force)
1949  return status;
1950  }
1951 
1952  if (opts->verbose)
1953  printf("INFO: Getting record dimension names, if they exist.\n");
1954 
1955  if (recid1 != -1) {
1956  ncstatus = nc_inq_dimname(ncid1, recid1, recname1);
1957  handle_error(ncstatus);
1958  } else
1959  strcpy(recname1, "");
1960 
1961  if (recid2 != -1) {
1962  ncstatus = nc_inq_dimname(ncid2, recid2, recname2);
1963  handle_error(ncstatus);
1964  } else
1965  strcpy(recname2, "");
1966 
1967  /* Dimensions */
1968  if (opts->verbose)
1969  printf("INFO: Comparing dimension lengths.\n");
1970 
1971  for (i = 0; i < ndims1; ++i) {
1972  dimid1 = dims1[i].dimid;
1973  ncstatus = nc_inq_dim(ncid1, dimid1, name1, &len1);
1974  if (ncstatus != NC_NOERR) {
1975  if (!opts->warn[NCCMP_W_ALL])
1976  status = EXIT_DIFFER;
1977 
1978  fprintf(stderr, "Failed to query dimension id %d in file %s.\n", dimid1, opts->file1);
1979  if (opts->force) continue;
1980  else return status;
1981  }
1982 
1983  ncstatus = nc_inq_dimid(ncid2, name1, &dimid2);
1984  if (ncstatus != NC_NOERR) {
1985  fprintf(stderr, "DIFFER : NAME : DIMENSION : %s : DIMENSION DOESN'T EXIST IN \"%s\"\n", name1, opts->file2);
1986 
1987  if (!opts->warn[NCCMP_W_ALL])
1988  status = EXIT_DIFFER;
1989 
1990  if (opts->force) continue;
1991  else return status;
1992  }
1993 
1994  ncstatus = nc_inq_dim(ncid2, dimid2, name2, &len2);
1995  if (ncstatus != NC_NOERR) {
1996  if (!opts->warn[NCCMP_W_ALL])
1997  status = EXIT_DIFFER;
1998 
1999  fprintf(stderr, "Failed to query dimension \"%s\" in file \"%s\".\n", name1, opts->file2);
2000  if (opts->force) continue;
2001  else return status;
2002  }
2003 
2004  if (len1 != len2) {
2005  fprintf(stderr, "DIFFER : LENGTHS : DIMENSION : %s : %lu <> %lu\n", name1,
2006  (unsigned long) len1, (unsigned long) len2);
2007 
2008  if (!opts->warn[NCCMP_W_ALL])
2009  status = EXIT_DIFFER;
2010 
2011  if (opts->force) continue;
2012  else return status;
2013  }
2014  }
2015 
2016  /* Variables */
2017  if (opts->verbose)
2018  printf("INFO: Comparing variable datatypes and rank.\n");
2019 
2020  for (i = 0; i < opts->ncmpvarlist; ++i) {
2021  j1 = findvar(opts->cmpvarlist[i], vars1);
2022  if (j1 == -1) {
2023  fprintf(stderr, "DIFFER : NAME : VARIABLE : %s%s : VARIABLE DOESN'T EXIST IN \"%s\"\n", getGroupPath(), opts->cmpvarlist[i], opts->file1);
2024 
2025  if (!opts->warn[NCCMP_W_ALL])
2026  status = EXIT_DIFFER;
2027 
2028  if (opts->force) continue;
2029  else goto recover;
2030  }
2031 
2032  j2 = findvar(opts->cmpvarlist[i], vars2);
2033  if (j2 == -1) {
2034  fprintf(stderr, "DIFFER : NAME : VARIABLE : %s%s : VARIABLE DOESN'T EXIST IN \"%s\"\n", getGroupPath(), opts->cmpvarlist[i], opts->file2);
2035 
2036  if (!opts->warn[NCCMP_W_ALL])
2037  status = EXIT_DIFFER;
2038 
2039  if (opts->force) continue;
2040  else goto recover;
2041  }
2042 
2043  if (vars1[j1].type != vars2[j2].type) {
2044  type2string(vars1[j1].type, typestr1);
2045  type2string(vars2[j2].type, typestr2);
2046  fprintf(stderr, "DIFFER : TYPES : VARIABLE : %s%s : %s <> %s\n", getGroupPath(), opts->cmpvarlist[i], typestr1, typestr2);
2047 
2048  if (!opts->warn[NCCMP_W_ALL])
2049  status = EXIT_DIFFER;
2050 
2051  if (opts->force) continue;
2052  else goto recover;
2053  }
2054 
2055  if (vars1[j1].ndims != vars2[j2].ndims) {
2056  fprintf(stderr, "DIFFER : NUMBER : DIMENSIONS : VARIABLE : %s%s : %d <> %d\n", getGroupPath(), opts->cmpvarlist[i], ndims1, ndims2);
2057 
2058  if (!opts->warn[NCCMP_W_ALL])
2059  status = EXIT_DIFFER;
2060 
2061  if (opts->force) continue;
2062  else goto recover;
2063  }
2064  }
2065 
2066  /*printf("DEBUG : %d : \n", __LINE__);*/
2067  if (opts->verbose)
2068  printf("INFO: Comparing variables' dimension names.\n");
2069 
2070  for (i = 0; i < opts->ncmpvarlist; ++i) {
2071  j1 = findvar(opts->cmpvarlist[i], vars1);
2072  j2 = findvar(opts->cmpvarlist[i], vars2);
2073 
2074  if ((j1 == -1) || (j2 == -1))
2075  continue;
2076 
2077  /* dimensions */
2078  for (j = 0; j < vars1[j1].ndims; ++j) {
2079  dimid1 = vars1[j1].dimids[j];
2080 
2081  if (j < vars2[j2].ndims)
2082  dimid2 = vars2[j2].dimids[j];
2083  else
2084  break;
2085 
2086  /*printf("DEBUG : %d : %s, %s, %s\n", __LINE__, opts->cmpvarlist[i], dims1[dimid1].name, dims2[dimid2].name);*/
2087 
2088  if (strcmp(dims1[dimid1].name, dims2[dimid2].name) != 0) {
2089  fprintf(stderr, "DIFFER : DIMENSION NAMES FOR VARIABLE %s%s : %s <> %s\n", getGroupPath(), opts->cmpvarlist[i], dims1[dimid1].name, dims2[dimid2].name);
2090 
2091  if (!opts->warn[NCCMP_W_ALL])
2092  status = EXIT_DIFFER;
2093 
2094  if (opts->force) continue;
2095  else goto recover;
2096  }
2097 
2098  tmp1 = strcmp(dims1[dimid1].name, recname1);
2099  tmp2 = strcmp(dims2[dimid2].name, recname2);
2100 
2101  if ((tmp1 == 0) && (tmp2 != 0)) {
2102  fprintf(stderr, "DIFFER : VARIABLE : %s%s : DIMENSION %s IS RECORD IN FILE \"%s\" BUT NOT IN \"%s\"\n", getGroupPath(), vars1[j1].name, dims1[dimid1].name, opts->file1, opts->file2);
2103 
2104  if (!opts->warn[NCCMP_W_ALL])
2105  status = EXIT_DIFFER;
2106 
2107  if (opts->force) continue;
2108  else goto recover;
2109  } else if ((tmp1 != 0) && (tmp2 == 0)) {
2110  fprintf(stderr, "DIFFER : VARIABLE : %s%s : DIMENSION %s IS RECORD IN FILE \"%s\" BUT NOT IN \"%s\"\n", getGroupPath(), vars1[j1].name, dims2[dimid2].name, opts->file2, opts->file1);
2111 
2112  if (!opts->warn[NCCMP_W_ALL])
2113  status = EXIT_DIFFER;
2114 
2115  if (opts->force) continue;
2116  else goto recover;
2117  }
2118  }
2119  }
2120 
2121  if (opts->verbose)
2122  printf("INFO: Comparing variables' attributes.\n");
2123 
2124  /*printf("DEBUG : %d : \n", __LINE__);*/
2125  /* Pass in 'i' as dummy. */
2126  if (newstringlist(&processedatts, &i, NC_MAX_VARS)) {
2127  fprintf(stderr, "ERROR: Failed to allocate string list for comparing attributes.\n");
2128  return EXIT_FATAL;
2129  }
2130  /*printf("DEBUG : %d : \n", __LINE__); fflush(stdout);*/
2131 
2132  for (i = 0; i < opts->ncmpvarlist; ++i) {
2133  /*printf("DEBUG : %d : i = %d\n", __LINE__, i); fflush(stdout);*/
2134  j1 = findvar(opts->cmpvarlist[i], vars1);
2135  j2 = findvar(opts->cmpvarlist[i], vars2);
2136 
2137  if ((j1 == -1) || (j2 == -1))
2138  continue;
2139 
2140  natts1 = natts2 = 0;
2141  clearstringlist(processedatts, NC_MAX_VARS);
2142 
2143  /*printf("DEBUG : %d : var=%s\n", __LINE__, opts->cmpvarlist[i]); fflush(stdout);*/
2144 
2145  /* Attributes */
2146  for (attid1 = 0; attid1 < vars1[j1].natts; ++attid1) {
2147  ncstatus = nc_inq_attname(ncid1, vars1[j1].varid, attid1, name1);
2148  if (ncstatus != NC_NOERR) {
2149  if (!opts->warn[NCCMP_W_ALL])
2150  status = EXIT_DIFFER;
2151 
2152  if (opts->force) continue;
2153  else goto recover;
2154  }
2155 
2156  if (instringlist(opts->excludeattlist, name1, opts->nexcludeatt) || instringlist(processedatts, name1, NC_MAX_VARS))
2157  continue;
2158 
2159  /* Log that this att was processed. */
2160  addstringtolist(processedatts, name1, NC_MAX_VARS);
2161  ++natts1;
2162  /*printf("natts1 %s, %d\n", name1, natts1);*/
2163  ncstatus = cmpatt(ncid1, ncid2, vars1[j1].varid, vars2[j2].varid, name1, vars1[j1].name, opts);
2164  if (ncstatus == EXIT_DIFFER) {
2165  status = ncstatus;
2166  if (opts->force) continue;
2167  else goto recover;
2168  }
2169  }
2170 
2171  /*printf("DEBUG : %d : \n", __LINE__);*/
2172  for (attid2 = 0; attid2 < vars2[j2].natts; ++attid2) {
2173  ncstatus = nc_inq_attname(ncid2, vars2[j2].varid, attid2, name2);
2174  if (ncstatus != NC_NOERR) {
2175  fprintf(stderr, "Failed to query variable %s%s attribute in file \"%s\"\n", getGroupPath(), vars2[j2].name, opts->file2);
2176 
2177  if (!opts->warn[NCCMP_W_ALL])
2178  status = EXIT_DIFFER;
2179 
2180  if (opts->force) continue;
2181  else goto recover;
2182  }
2183 
2184  if (instringlist(opts->excludeattlist, name2, opts->nexcludeatt))
2185  continue;
2186 
2187  /* Count non-excluded attribute. */
2188  ++natts2;
2189  /*printf("natts2 %s, %d\n", name2, natts2);*/
2190  if (instringlist(processedatts, name2, NC_MAX_VARS))
2191  continue;
2192 
2193  /* Log that this att was processed. */
2194  addstringtolist(processedatts, name2, NC_MAX_VARS);
2195 
2196  /* Do comparison. */
2197  ncstatus = cmpatt(ncid1, ncid2, vars1[j1].varid, vars2[j2].varid, name2, vars2[j2].name, opts);
2198  if (ncstatus == EXIT_DIFFER) {
2199  status = ncstatus;
2200  if (opts->force) continue;
2201  else goto recover;
2202  }
2203  }
2204 
2205  if (natts1 != natts2) {
2206  fprintf(stderr, "DIFFER : NUMBER OF ATTRIBUTES : VARIABLE : %s%s : %d <> %d\n", getGroupPath(), opts->cmpvarlist[i], natts1, natts2);
2207  if (!opts->warn[NCCMP_W_ALL])
2208  status = EXIT_DIFFER;
2209 
2210  if (opts->force) continue;
2211  else goto recover;
2212  }
2213  }
2214 
2215 recover:
2216  freestringlist(&processedatts, NC_MAX_VARS);
2217  processedatts = NULL;
2218 
2219 
2220  return status;
2221 }
2222 /* *********************************************************** */
2223 
2224 /* Returns index into varstruct array if found using name otherwise -1. */
2225 int findvar(char * name, varstruct *vars) {
2226  int i;
2227  for (i = 0; i < NC_MAX_VARS; ++i) {
2228  if (strcmp(name, vars[i].name) == 0)
2229  return i;
2230  }
2231 
2232  return -1;
2233 }
2234 
2235 /* *********************************************************** */
2236 
2237 /* Do the comparision of variables.
2238  Record index (rec) is optional; -1 if not applicable.
2239  Returns comparison result success or failure.
2240  */
2241 int cmpvar(char* name, int rec, nccmpopts* opts, int ncid1, int ncid2, nccmp_user_type_t *user_types1, nccmp_user_type_t *user_types2) {
2242 
2243  varstruct *v1, *v2;
2244  size_t idx1, idx2, status, i;
2245  int j;
2246  size_t start[NC_MAX_DIMS], count[NC_MAX_DIMS];
2247  off_t nitems;
2248  size_t odomax[NC_MAX_DIMS];
2249  int diffstatus = EXIT_SUCCESS;
2250  unsigned char *data1 = NULL, *data2 = NULL;
2251 
2252  idx1 = findvar(name, vars1);
2253  idx2 = findvar(name, vars2);
2254 
2255  v1 = &vars1[idx1];
2256  v2 = &vars2[idx2];
2257 
2258  /*printf("DEBUG : %s len : %d <> %d\n", name, v1->len, v2->len); */
2259 
2260  if (v1->len != v2->len) {
2261  fprintf(stderr, "DIFFER : SIZE OF VARIABLE \"%s%s\" : %d <> %d\n", getGroupPath(), name, (int) v1->len, (int) v2->len);
2262 
2263  if (!opts->warn[NCCMP_W_ALL]) \
2264  return EXIT_DIFFER;
2265  else
2266  return EXIT_SUCCESS;
2267  }
2268 
2269  // no need to compare if the length is 0, since netCDF will blow up
2270  if(v1->len == 0) {
2271  if (opts->verbose)
2272  printf("INFO: 0 length variables are equal.\n");
2273  return 0;
2274  }
2275 
2276  for (j = 0; j < v1->ndims; ++j) {
2277  start[j] = 0;
2278  odomax[j] = v1->dimlens[j] - 1;
2279  }
2280 
2281 #ifdef __DEBUG__
2282  printf("DEBUG : %d : odomax = ", __LINE__);
2283  for (i = 0; i < v1->ndims; ++i) {
2284  printf("%d ", odomax[i]);
2285  }
2286  printf("\n");
2287 #endif
2288 
2289  /* If has record dim. */
2290  if (v1->hasrec && (rec >= 0))
2291  start[0] = rec;
2292 
2293  /* Read in slab for last dimension at-a-time only.
2294 We'll then loop over all the other outer dimensions. */
2295  for (j = 0; j < v1->ndims - 1; ++j) {
2296  count[j] = 1;
2297  }
2298 
2299  /* We'll always read in entire last dimension
2300  except if only dimension is record. */
2301  if ((v1->ndims == 1) && (v1->hasrec)) {
2302  nitems = 1;
2303  } else
2304  nitems = v1->dimlens[v1->ndims - 1];
2305 
2306  count[v1->ndims - 1] = nitems;
2307 
2308  /*printf("DEBUG : %d : nitems = %d\n", __LINE__, nitems);\*/
2309  int ut_nidx1 = v1->user_type_idx;
2310  int ut_nidx2 = v2->user_type_idx;
2311  int offset1, offset2, size1, size2;
2312 
2313  if (ut_nidx1 < 0) {
2314 
2315  switch (v1->type) {
2316  case NC_BYTE:
2317  strcpy(opts->tprintf, "%d");
2318  //cmp_var<int8_t>(ncid1, ncid2, opts, rec, odomax, nitems, count, start, v1, v2, v1->missing.b, v2->missing.b);
2319  opts->tolerance = 0.0;
2320  diffstatus = cmp_vartol<int8_t>(ncid1, ncid2, opts, rec, odomax, nitems, count, start, v1, v2, v1->missing.f, v2->missing.f);
2321  break;
2322 
2323  case NC_CHAR:
2324  strcpy(opts->tprintf, "%c");
2325  // cmp_var<char>(ncid1, ncid2, opts, rec, odomax, nitems, count, start, v1, v2, v1->missing.c, v2->missing.c);
2326  opts->tolerance = 0.0;
2327  diffstatus = cmp_vartol<char>(ncid1, ncid2, opts, rec, odomax, nitems, count, start, v1, v2, v1->missing.f, v2->missing.f);
2328  break;
2329 
2330  case NC_SHORT:
2331  strcpy(opts->tprintf, "%d");
2332  // cmp_var<short>(ncid1, ncid2, opts, rec, odomax, nitems, count, start, v1, v2, v1->missing.s, v2->missing.s);
2333  opts->tolerance = 0.0;
2334  diffstatus = cmp_vartol<short>(ncid1, ncid2, opts, rec, odomax, nitems, count, start, v1, v2, v1->missing.f, v2->missing.f);
2335  break;
2336 
2337  case NC_USHORT:
2338  strcpy(opts->tprintf, "%d");
2339  // cmp_var<short>(ncid1, ncid2, opts, rec, odomax, nitems, count, start, v1, v2, v1->missing.s, v2->missing.s);
2340  opts->tolerance = 0.0;
2341  diffstatus = cmp_vartol<uint16_t>(ncid1, ncid2, opts, rec, odomax, nitems, count, start, v1, v2, v1->missing.f, v2->missing.f);
2342  break;
2343 
2344  case NC_UBYTE:
2345  strcpy(opts->tprintf, "%d");
2346  // cmp_var<short>(ncid1, ncid2, opts, rec, odomax, nitems, count, start, v1, v2, v1->missing.s, v2->missing.s);
2347  opts->tolerance = 0.0;
2348  diffstatus = cmp_vartol<uint8_t>(ncid1, ncid2, opts, rec, odomax, nitems, count, start, v1, v2, v1->missing.f, v2->missing.f);
2349  break;
2350 
2351  case NC_INT:
2352  strcpy(opts->tprintf, "%d");
2353  opts->tolerance = 0.0;
2354  diffstatus = cmp_vartol<int>(ncid1, ncid2, opts, rec, odomax, nitems, count, start, v1, v2, v1->missing.i, v2->missing.i);
2355  break;
2356 
2357  case NC_UINT:
2358  strcpy(opts->tprintf, "%d");
2359  opts->tolerance = 0.0;
2360  diffstatus = cmp_vartol<uint>(ncid1, ncid2, opts, rec, odomax, nitems, count, start, v1, v2, v1->missing.ui, v2->missing.ui);
2361  break;
2362 
2363  case NC_INT64:
2364  strcpy(opts->tprintf, "%ld");
2365  opts->tolerance = 0.0;
2366  diffstatus = cmp_vartol<long>(ncid1, ncid2, opts, rec, odomax, nitems, count, start, v1, v2, v1->missing.l, v2->missing.l);
2367  break;
2368 
2369  case NC_UINT64:
2370  strcpy(opts->tprintf, "%ld");
2371  opts->tolerance = 0.0;
2372  diffstatus = cmp_vartol<uint64_t>(ncid1, ncid2, opts, rec, odomax, nitems, count, start, v1, v2, v1->missing.ul, v2->missing.ul);
2373  break;
2374 
2375  case NC_FLOAT:
2376  strcpy(opts->tprintf, opts->precision);
2377  if (opts->notolerance) {
2378  opts->tolerance = 0.0;
2379  diffstatus = cmp_vartol<float>(ncid1, ncid2, opts, rec, odomax, nitems, count, start, v1, v2, v1->missing.f, v2->missing.f);
2380  } else {
2381  if (opts->verbose)
2382  printf("INFO: Using maximum tolerance of 0.0001 for float comparisons.\n");
2383  opts->tolerance = 0.0001;
2384  diffstatus = cmp_vartol<float>(ncid1, ncid2, opts, rec, odomax, nitems, count, start, v1, v2, v1->missing.f, v2->missing.f);
2385  opts->tolerance = 0;
2386  }
2387  break;
2388 
2389  case NC_DOUBLE:
2390  strcpy(opts->tprintf, opts->precision);
2391  if (opts->notolerance) {
2392  diffstatus = cmp_var<double>(ncid1, ncid2, opts, rec, odomax, nitems, count, start, v1, v2, v1->missing.d, v2->missing.d);
2393  } else {
2394  if (opts->verbose)
2395  printf("INFO: Using maximum tolerance of 0.0001 for double comparisons.\n");
2396  opts->tolerance = 0.0001;
2397  diffstatus = cmp_vartol<double>(ncid1, ncid2, opts, rec, odomax, nitems, count, start, v1, v2, v1->missing.d, v2->missing.d);
2398  opts->tolerance = 0;
2399  }
2400  break;
2401  default:
2402  if (v1->type < NC_MAX_TYPES && !notsupported[v1->type]) {
2403  printf("INFO: This Type (%d) not supported .\n", v1->type);
2404  notsupported[v1->type] = 1;
2405  } else {
2406  if (v1->type >= NC_MAX_TYPES) {
2407  printf("INFO: This Type (%d) not supported ... ", v1->type);
2408  printf("INFO: Increase NC_MAX_TYPES > %d to avoid this message. \n", v1->type);
2409  }
2410  }
2411  diffstatus = -1;
2412  break;
2413 
2414  }
2415  } else {
2416  data1 = (unsigned char *) malloc(sizeof (unsigned char)*user_types1[ut_nidx1].size * (nitems + 1));
2417  data2 = (unsigned char *) malloc(sizeof (unsigned char)*user_types2[ut_nidx2].size * (nitems + 1));
2418  status = nc_get_vara(ncid1, v1->varid, start, count, data1);
2420  status = nc_get_vara(ncid2, v2->varid, start, count, data2);
2422 
2423  size1 = user_types1[ut_nidx1].root_size;
2424  size2 = user_types2[ut_nidx2].root_size;
2425  for (i = 0; i < user_types1[ut_nidx1].num_fields; ++i) {
2426  offset1 = user_types1[ut_nidx1].fields[i].offset;
2427  offset2 = user_types2[ut_nidx2].fields[i].offset;
2428  switch (user_types1[ut_nidx1].fields[i].type_id) {
2429  case NC_BYTE:
2430  strcpy(opts->tprintf, "%d");
2431  //cmp_var<int8_t>(ncid1, ncid2, opts, rec, odomax, nitems, count, start, v1, v2, v1->missing.b, v2->missing.b);
2432  opts->tolerance = 0.0;
2433  diffstatus = cmp_vartol_ut<int8_t>(data1, data2, offset1, offset2, size1, size2, user_types1[ut_nidx1].fields[i].name, opts, rec, odomax, nitems, count, start, v1, v2, v1->missing.b, v2->missing.b);
2434  break;
2435 
2436  case NC_CHAR:
2437  strcpy(opts->tprintf, "%c");
2438  // cmp_var<char>(ncid1, ncid2, opts, rec, odomax, nitems, count, start, v1, v2, v1->missing.c, v2->missing.c);
2439  opts->tolerance = 0.0;
2440  diffstatus = cmp_vartol_ut<char>(data1, data2, offset1, offset2, size1, size2, user_types1[ut_nidx1].fields[i].name, opts, rec, odomax, nitems, count, start, v1, v2, v1->missing.c, v2->missing.c);
2441  break;
2442 
2443  case NC_SHORT:
2444  strcpy(opts->tprintf, "%d");
2445  // cmp_var<short>(ncid1, ncid2, opts, rec, odomax, nitems, count, start, v1, v2, v1->missing.s, v2->missing.s);
2446  opts->tolerance = 0.0;
2447  diffstatus = cmp_vartol<short>(ncid1, ncid2, opts, rec, odomax, nitems, count, start, v1, v2, v1->missing.s, v2->missing.s);
2448  break;
2449 
2450  case NC_USHORT:
2451  strcpy(opts->tprintf, "%d");
2452  // cmp_var<short>(ncid1, ncid2, opts, rec, odomax, nitems, count, start, v1, v2, v1->missing.s, v2->missing.s);
2453  opts->tolerance = 0.0;
2454  diffstatus = cmp_vartol<uint16_t>(ncid1, ncid2, opts, rec, odomax, nitems, count, start, v1, v2, v1->missing.us, v2->missing.us);
2455  break;
2456 
2457  case NC_UBYTE:
2458  strcpy(opts->tprintf, "%d");
2459  // cmp_var<short>(ncid1, ncid2, opts, rec, odomax, nitems, count, start, v1, v2, v1->missing.s, v2->missing.s);
2460  opts->tolerance = 0.0;
2461  diffstatus = cmp_vartol_ut<uint8_t>(data1, data2, offset1, offset2, size1, size2, user_types1[ut_nidx1].fields[i].name, opts, rec, odomax, nitems, count, start, v1, v2, v1->missing.ub, v2->missing.ub);
2462  break;
2463 
2464  case NC_INT:
2465  strcpy(opts->tprintf, "%d");
2466  opts->tolerance = 0.0;
2467  diffstatus = cmp_vartol_ut<int>(data1, data2, offset1, offset2, size1, size2, user_types1[ut_nidx1].fields[i].name, opts, rec, odomax, nitems, count, start, v1, v2, v1->missing.i, v2->missing.i);
2468  break;
2469 
2470  case NC_UINT:
2471  strcpy(opts->tprintf, "%d");
2472  opts->tolerance = 0.0;
2473  diffstatus = cmp_vartol_ut<uint>(data1, data2, offset1, offset2, size1, size2, user_types1[ut_nidx1].fields[i].name, opts, rec, odomax, nitems, count, start, v1, v2, v1->missing.ui, v2->missing.ui);
2474  break;
2475 
2476  case NC_INT64:
2477  strcpy(opts->tprintf, "%ld");
2478  opts->tolerance = 0.0;
2479  diffstatus = cmp_vartol_ut<long>(data1, data2, offset1, offset2, size1, size2, user_types1[ut_nidx1].fields[i].name, opts, rec, odomax, nitems, count, start, v1, v2, v1->missing.l, v2->missing.l);
2480  break;
2481 
2482  case NC_UINT64:
2483  strcpy(opts->tprintf, "%ld");
2484  opts->tolerance = 0.0;
2485  diffstatus = cmp_vartol_ut<uint64_t>(data1, data2, offset1, offset2, size1, size2, user_types1[ut_nidx1].fields[i].name, opts, rec, odomax, nitems, count, start, v1, v2, v1->missing.ul, v2->missing.ul);
2486  break;
2487 
2488  case NC_FLOAT:
2489  strcpy(opts->tprintf, opts->precision);
2490  if (opts->notolerance) {
2491  opts->tolerance = 0.0;
2492  diffstatus = cmp_vartol_ut<float>(data1, data2, offset1, offset2, size1, size2, user_types1[ut_nidx1].fields[i].name, opts, rec, odomax, nitems, count, start, v1, v2, v1->missing.f, v2->missing.f);
2493  } else {
2494  if (opts->verbose)
2495  printf("INFO: Using maximum tolerance of 0.0001 for float comparisons.\n");
2496  opts->tolerance = 0.0001;
2497  diffstatus = cmp_vartol_ut<float>(data1, data2, offset1, offset2, size1, size2, user_types1[ut_nidx1].fields[i].name, opts, rec, odomax, nitems, count, start, v1, v2, v1->missing.f, v2->missing.f);
2498  opts->tolerance = 0;
2499  }
2500  break;
2501 
2502  case NC_DOUBLE:
2503  strcpy(opts->tprintf, opts->precision);
2504  if (opts->notolerance) {
2505  diffstatus = cmp_vartol_ut<double>(data1, data2, offset1, offset2, size1, size2, user_types1[ut_nidx1].fields[i].name, opts, rec, odomax, nitems, count, start, v1, v2, v1->missing.d, v2->missing.d);
2506  } else {
2507  if (opts->verbose)
2508  printf("INFO: Using maximum tolerance of 0.0001 for double comparisons.\n");
2509  opts->tolerance = 0.0001;
2510  diffstatus = cmp_vartol_ut<double>(data1, data2, offset1, offset2, size1, size2, user_types1[ut_nidx1].fields[i].name, opts, rec, odomax, nitems, count, start, v1, v2, v1->missing.d, v2->missing.d);
2511  opts->tolerance = 0;
2512  }
2513  break;
2514  default:
2515  if (v1->type < NC_MAX_TYPES && !notsupported[user_types1[ut_nidx1].fields[i].type_id]) {
2516  printf("INFO: This Type (%d) not supported .\n", user_types1[ut_nidx1].fields[i].type_id);
2517  notsupported[v1->type] = 1;
2518  } else {
2519  if (v1->type >= NC_MAX_TYPES) {
2520  printf("INFO: This Type (%d) not supported ... ", user_types1[ut_nidx1].fields[i].type_id);
2521  printf("INFO: Increase NC_MAX_TYPES > %d to avoid this message. \n", user_types1[ut_nidx1].fields[i].type_id);
2522  }
2523  }
2524  diffstatus = -1;
2525  break;
2526 
2527  }
2528  }
2529  }
2530  return diffstatus;
2531 }
2532 /* *********************************************************** */
2533 
2534 /* Do the comparision of variables.
2535  Record index (rec) is optional; -1 if not applicable.
2536  Returns comparison result success or failure.
2537  */
2538 int cmpvartol(char* name, int rec, nccmpopts* opts, int ncid1, int ncid2, nccmp_user_type_t *user_types1, nccmp_user_type_t *user_types2) {
2539 
2540  varstruct *v1, *v2;
2541  size_t idx1, idx2, status, i;
2542  int j;
2543  size_t start[NC_MAX_DIMS], count[NC_MAX_DIMS];
2544  off_t nitems;
2545  size_t odomax[NC_MAX_DIMS];
2546  int diffstatus = EXIT_SUCCESS;
2547  unsigned char *data1 = NULL, *data2 = NULL;
2548 
2549  if (opts->verbose) {
2550  if (rec != -1)
2551  printf("INFO: Comparing data for variable \"%s%s\" at record %d.\n", getGroupPath(), name, (int) rec);
2552  else
2553  printf("INFO: Comparing non-record data for variable \"%s%s\".\n", getGroupPath(), name);
2554  }
2555 
2556  idx1 = findvar(name, vars1);
2557  idx2 = findvar(name, vars2);
2558 
2559  if (idx1 < 0) {
2560  if (!opts->metadata) /* This gets reported in cmpmeta. */
2561  fprintf(stderr, "DIFFER : Failed to find variable \"%s%s\" in file \"%s\".\n", getGroupPath(), name, opts->file1);
2562 
2563  if (!opts->warn[NCCMP_W_ALL])
2564  return EXIT_DIFFER;
2565  else
2566  return EXIT_SUCCESS;
2567  }
2568 
2569  if (idx2 < 0) {
2570  if (!opts->metadata) /* This gets reported in cmpmeta. */
2571  fprintf(stderr, "DIFFER : Failed to find variable \"%s%s\" in file \"%s\".\n", getGroupPath(), name, opts->file2);
2572 
2573  if (!opts->warn[NCCMP_W_ALL])
2574  return EXIT_DIFFER;
2575  else
2576  return EXIT_SUCCESS;
2577  }
2578 
2579  v1 = &vars1[idx1];
2580  v2 = &vars2[idx2];
2581 
2582  if (v1->len != v2->len) {
2583  fprintf(stderr, "DIFFER : SIZE OF VARIABLE \"%s%s\" : %d <> %d\n", getGroupPath(), name, (int) v1->len, (int) v2->len);
2584 
2585  if (!opts->warn[NCCMP_W_ALL]) \
2586  return EXIT_DIFFER;
2587  else
2588  return EXIT_SUCCESS;
2589  }
2590 
2591  int ut_nidx1 = v1->user_type_idx;
2592  int ut_nidx2 = v2->user_type_idx;
2593  int offset1, offset2, size1, size2;
2594 
2595  for (j = 0; j < v1->ndims; ++j) {
2596  start[j] = 0;
2597  odomax[j] = v1->dimlens[j] - 1;
2598  }
2599 
2600  /* If has record dim. */
2601  if (v1->hasrec && (rec >= 0))
2602  start[0] = rec;
2603 
2604  /* Read in slab for last dimension at-a-time only.
2605  We'll then loop over all the other outer dimensions. */
2606  for (j = 0; j < v1->ndims - 1; ++j) {
2607  count[j] = 1;
2608  }
2609 
2610  /* We'll always read in entire last dimension
2611  except if only dimension is record. */
2612  if ((v1->ndims == 1) && (v1->hasrec)) {
2613  nitems = 1;
2614  } else
2615  nitems = v1->dimlens[v1->ndims - 1];
2616 
2617  count[v1->ndims - 1] = nitems;
2618 
2619  /* todo: make cmpvar and cmpvartol same function to re-use code immediately above; just use conditional to choose CMP_VAR or CMP_VARTOL macro. */
2620 
2621  if (ut_nidx1 < 0) {
2622  switch (v1->type) {
2623  case NC_BYTE:
2624  strcpy(opts->tprintf, "%d");
2625  diffstatus = cmp_vartol<int8_t>(ncid1, ncid2, opts, rec, odomax, nitems, count, start, v1, v2, v1->missing.b, v2->missing.b);
2626  break;
2627 
2628  case NC_UBYTE:
2629  strcpy(opts->tprintf, "%d");
2630  diffstatus = cmp_vartol<uint8_t>(ncid1, ncid2, opts, rec, odomax, nitems, count, start, v1, v2, v1->missing.ub, v2->missing.ub);
2631  break;
2632 
2633  case NC_CHAR:
2634  strcpy(opts->tprintf, "%c");
2635  diffstatus = cmp_vartol<char>(ncid1, ncid2, opts, rec, odomax, nitems, count, start, v1, v2, v1->missing.c, v2->missing.c);
2636  break;
2637 
2638  case NC_SHORT:
2639  strcpy(opts->tprintf, "%d");
2640  diffstatus = cmp_vartol<short>(ncid1, ncid2, opts, rec, odomax, nitems, count, start, v1, v2, v1->missing.s, v2->missing.s);
2641  break;
2642 
2643  case NC_USHORT:
2644  strcpy(opts->tprintf, "%d");
2645  diffstatus = cmp_vartol<uint16_t>(ncid1, ncid2, opts, rec, odomax, nitems, count, start, v1, v2, v1->missing.us, v2->missing.us);
2646  break;
2647 
2648  case NC_INT:
2649  strcpy(opts->tprintf, "%d");
2650  diffstatus = cmp_vartol<int>(ncid1, ncid2, opts, rec, odomax, nitems, count, start, v1, v2, v1->missing.i, v2->missing.i);
2651  break;
2652 
2653  case NC_UINT:
2654  strcpy(opts->tprintf, "%d");
2655  diffstatus = cmp_vartol<uint>(ncid1, ncid2, opts, rec, odomax, nitems, count, start, v1, v2, v1->missing.ui, v2->missing.ui);
2656  break;
2657 
2658  case NC_INT64:
2659  strcpy(opts->tprintf, "%ld");
2660  diffstatus = cmp_vartol<long>(ncid1, ncid2, opts, rec, odomax, nitems, count, start, v1, v2, v1->missing.l, v2->missing.l);
2661  break;
2662 
2663  case NC_UINT64:
2664  strcpy(opts->tprintf, "%ld");
2665  diffstatus = cmp_vartol<uint64_t>(ncid1, ncid2, opts, rec, odomax, nitems, count, start, v1, v2, v1->missing.ul, v2->missing.ul);
2666  break;
2667 
2668  case NC_FLOAT:
2669  strcpy(opts->tprintf, "%g");
2670  diffstatus = cmp_vartol<float>(ncid1, ncid2, opts, rec, odomax, nitems, count, start, v1, v2, v1->missing.f, v2->missing.f);
2671  break;
2672 
2673  case NC_DOUBLE:
2674  strcpy(opts->tprintf, "%g");
2675  diffstatus = cmp_vartol<double>(ncid1, ncid2, opts, rec, odomax, nitems, count, start, v1, v2, v1->missing.d, v2->missing.d);
2676  break;
2677  default:
2678  if (v1->type < NC_MAX_TYPES && !notsupported[v1->type]) {
2679  printf("INFO: This Type (%d) not supported .\n", v1->type);
2680  notsupported[v1->type] = 1;
2681  } else {
2682  if (v1->type >= NC_MAX_TYPES) {
2683  printf("INFO: This Type (%d) not supported ... ", v1->type);
2684  printf("INFO: Increase NC_MAX_TYPES > %d to avoid this message. \n", v1->type);
2685  }
2686  }
2687  diffstatus = -1;
2688  break;
2689 
2690  }
2691  } else {
2692  data1 = (unsigned char *) malloc(sizeof (unsigned char)*user_types1[ut_nidx1].size * (nitems + 1));
2693  data2 = (unsigned char *) malloc(sizeof (unsigned char)*user_types2[ut_nidx2].size * (nitems + 1));
2694  status = nc_get_vara(ncid1, v1->varid, start, count, data1);
2696  status = nc_get_vara(ncid2, v2->varid, start, count, data2);
2698 
2699  size1 = user_types1[ut_nidx1].root_size;
2700  size2 = user_types2[ut_nidx2].root_size;
2701  for (i = 0; i < user_types1[ut_nidx1].num_fields; ++i) {
2702  offset1 = user_types1[ut_nidx1].fields[i].offset;
2703  offset2 = user_types2[ut_nidx2].fields[i].offset;
2704 
2705  switch (user_types1[ut_nidx1].fields[i].type_id) {
2706  case NC_BYTE:
2707  strcpy(opts->tprintf, "%d");
2708  diffstatus = cmp_vartol_ut<int8_t>(data1, data2, offset1, offset2, size1, size2, user_types1[ut_nidx1].fields[i].name, opts, rec, odomax, nitems, count, start, v1, v2, v1->missing.b, v2->missing.b);
2709 
2710  break;
2711 
2712  case NC_UBYTE:
2713  strcpy(opts->tprintf, "%d");
2714  diffstatus = cmp_vartol_ut<uint8_t>(data1, data2, offset1, offset2, size1, size2, user_types1[ut_nidx1].fields[i].name, opts, rec, odomax, nitems, count, start, v1, v2, v1->missing.ub, v2->missing.ub);
2715 
2716  break;
2717 
2718  case NC_CHAR:
2719  strcpy(opts->tprintf, "%c");
2720  diffstatus = cmp_vartol_ut<char>(data1, data2, offset1, offset2, size1, size2, user_types1[ut_nidx1].fields[i].name, opts, rec, odomax, nitems, count, start, v1, v2, v1->missing.c, v2->missing.c);
2721  break;
2722 
2723  case NC_SHORT:
2724  strcpy(opts->tprintf, "%d");
2725  diffstatus = cmp_vartol_ut<short>(data1, data2, offset1, offset2, size1, size2, user_types1[ut_nidx1].fields[i].name, opts, rec, odomax, nitems, count, start, v1, v2, v1->missing.s, v2->missing.s);
2726  break;
2727 
2728  case NC_USHORT:
2729  strcpy(opts->tprintf, "%d");
2730  diffstatus = cmp_vartol_ut<uint16_t>(data1, data2, offset1, offset2, size1, size2, user_types1[ut_nidx1].fields[i].name, opts, rec, odomax, nitems, count, start, v1, v2, v1->missing.us, v2->missing.us);
2731  break;
2732 
2733  case NC_INT:
2734  strcpy(opts->tprintf, "%d");
2735  diffstatus = cmp_vartol_ut<int>(data1, data2, offset1, offset2, size1, size2, user_types1[ut_nidx1].fields[i].name, opts, rec, odomax, nitems, count, start, v1, v2, v1->missing.i, v2->missing.i);
2736  break;
2737 
2738  case NC_UINT:
2739  strcpy(opts->tprintf, "%d");
2740  diffstatus = cmp_vartol_ut<uint>(data1, data2, offset1, offset2, size1, size2, user_types1[ut_nidx1].fields[i].name, opts, rec, odomax, nitems, count, start, v1, v2, v1->missing.ui, v2->missing.ui);
2741  break;
2742 
2743  case NC_INT64:
2744  strcpy(opts->tprintf, "%ld");
2745  diffstatus = cmp_vartol_ut<long>(data1, data2, offset1, offset2, size1, size2, user_types1[ut_nidx1].fields[i].name, opts, rec, odomax, nitems, count, start, v1, v2, v1->missing.l, v2->missing.l);
2746  break;
2747 
2748  case NC_UINT64:
2749  strcpy(opts->tprintf, "%ld");
2750  diffstatus = cmp_vartol_ut<uint64_t>(data1, data2, offset1, offset2, size1, size2, user_types1[ut_nidx1].fields[i].name, opts, rec, odomax, nitems, count, start, v1, v2, v1->missing.ul, v2->missing.ul);
2751  break;
2752 
2753  case NC_FLOAT:
2754  strcpy(opts->tprintf, "%g");
2755  diffstatus = cmp_vartol_ut<float>(data1, data2, offset1, offset2, size1, size2, user_types1[ut_nidx1].fields[i].name, opts, rec, odomax, nitems, count, start, v1, v2, v1->missing.f, v2->missing.f);
2756  break;
2757 
2758  case NC_DOUBLE:
2759  strcpy(opts->tprintf, "%g");
2760  diffstatus = cmp_vartol_ut<double>(data1, data2, offset1, offset2, size1, size2, user_types1[ut_nidx1].fields[i].name, opts, rec, odomax, nitems, count, start, v1, v2, v1->missing.d, v2->missing.d);
2761  break;
2762  default:
2763  if (v1->type < NC_MAX_TYPES && !notsupported[user_types1[ut_nidx1].fields[i].type_id]) {
2764  printf("INFO: This Type (%d) not supported .\n", user_types1[ut_nidx1].fields[i].type_id);
2765  notsupported[v1->type] = 1;
2766  } else {
2767  if (v1->type >= NC_MAX_TYPES) {
2768  printf("INFO: This Type (%d) not supported ... ", user_types1[ut_nidx1].fields[i].type_id);
2769  printf("INFO: Increase NC_MAX_TYPES > %d to avoid this message. \n", user_types1[ut_nidx1].fields[i].type_id);
2770  }
2771  }
2772  diffstatus = -1;
2773  break;
2774 
2775  }
2776  }
2777  }
2778  return diffstatus;
2779 }
2780 
2781 /* *********************************************************** */
2782 int
2783 nccmpdatarecvartol(int ncid1, int ncid2, char* varname, nccmpopts* opts,
2784  size_t recstart, size_t recend, nccmp_user_type_t *user_types1, nccmp_user_type_t *user_types2) {
2785  int cmpstatus;
2786  int status = EXIT_SUCCESS;
2787 
2788  for (; recstart <= recend; ++recstart) {
2789  cmpstatus = cmpvartol(varname, recstart, opts, ncid1, ncid2, user_types1, user_types2) || status;
2790  if (cmpstatus != EXIT_SUCCESS) {
2791  status = cmpstatus;
2792  if (opts->force)
2793  continue;
2794  else
2795  break;
2796  }
2797  }
2798 
2799  return status;
2800 }
2801 
2802 /* *********************************************************** */
2803 int
2804 nccmpdatarecvar(int ncid1, int ncid2, char* varname, nccmpopts* opts,
2805  size_t recstart, size_t recend, nccmp_user_type_t *user_types1, nccmp_user_type_t *user_types2) {
2806  int cmpstatus;
2807  int status = EXIT_SUCCESS;
2808 
2809  for (; recstart <= recend; ++recstart) {
2810  cmpstatus = cmpvar(varname, recstart, opts, ncid1, ncid2, user_types1, user_types2) || status;
2811  if (cmpstatus != EXIT_SUCCESS) {
2812  status = cmpstatus;
2813  if (opts->force)
2814  continue;
2815  else
2816  break;
2817  }
2818  }
2819 
2820  return status;
2821 }
2822 
2823 /* *********************************************************** */
2824 int nccmpdatatol(int ncid1, int ncid2, nccmpopts* opts, nccmp_user_type_t *user_types1, nccmp_user_type_t *user_types2) {
2825  int i, idx1;
2826  int status, cmpstatus, nprocessed;
2827  char** processed = NULL;
2828 
2829  status = EXIT_SUCCESS;
2830 
2831  if (opts->verbose)
2832  printf("INFO: Comparing data with tolerance.\n");
2833 
2834  if (newstringlist(&processed, &nprocessed, NC_MAX_VARS)) {
2835  fprintf(stderr, "ERROR: Failed to allocated string list for comparing data.\n");
2836  return EXIT_FATAL;
2837  }
2838 
2839  for (i = 0; i < opts->ncmpvarlist; ++i) {
2840  if (instringlist(processed, opts->cmpvarlist[i], nprocessed))
2841  /* Skip varnames already processed. */
2842  continue;
2843 
2844  if (opts->verbose)
2845  printf("INFO: Comparing data for variable \"%s%s\".\n", getGroupPath(), opts->cmpvarlist[i]);
2846 
2847  addstringtolist(processed, opts->cmpvarlist[i], nprocessed);
2848 
2849  /* Has rec? */
2850  idx1 = findvar(opts->cmpvarlist[i], vars1);
2851  if (vars1[idx1].hasrec) {
2852 
2853  /* Compare only if # recs are equal and not zero. */
2854  if ((nrec1 == nrec2) && (nrec1 + nrec2)) {
2855  cmpstatus = nccmpdatarecvartol(ncid1, ncid2, opts->cmpvarlist[i], opts, 0, nrec1 - 1, user_types1, user_types2);
2856  if (cmpstatus) {
2857  status = cmpstatus;
2858  if (opts->force)
2859  continue;
2860  else
2861  break;
2862  }
2863  }
2864  } else {
2865  cmpstatus = cmpvartol(opts->cmpvarlist[i], -1, opts, ncid1, ncid2, user_types1, user_types2);
2866  if (cmpstatus) {
2867  status = cmpstatus;
2868  if (opts->force)
2869  continue;
2870  else
2871  break;
2872  }
2873  }
2874  }
2875 
2876  if (opts->verbose)
2877  printf("INFO: Finished comparing data.\n");
2878 
2879  return status;
2880 }
2881 
2882 /* *********************************************************** */
2883 int nccmpdata(nccmpopts* opts, int ncid1, int ncid2, nccmp_user_type_t *user_types1, nccmp_user_type_t *user_types2) {
2884  int i, idx1, idx2;
2885  int status, cmpstatus, nprocessed;
2886  char** processed = NULL;
2887  char str1[32], str2[32];
2888 
2889  status = EXIT_SUCCESS;
2890 
2891  if (opts->verbose)
2892  printf("INFO: Comparing data.\n");
2893 
2894  if (opts->tolerance != 0)
2895  return nccmpdatatol(ncid1, ncid2, opts, user_types1, user_types2);
2896 
2897  if (newstringlist(&processed, &nprocessed, NC_MAX_VARS)) {
2898  fprintf(stderr, "ERROR: Failed to allocated string list for comparing data.\n");
2899  return EXIT_FATAL;
2900  }
2901 
2902  for (i = 0; i < opts->ncmpvarlist; ++i) {
2903 
2904  // reset diff counter for each variable
2905  opts->diffcount = 0;
2906 
2907  if (instringlist(processed, opts->cmpvarlist[i], nprocessed))
2908  /* Skip varnames already processed. */
2909  continue;
2910 
2911  if (opts->verbose)
2912  printf("INFO: Comparing data for variable \"%s%s\".\n", getGroupPath(), opts->cmpvarlist[i]);
2913 
2914  addstringtolist(processed, opts->cmpvarlist[i], nprocessed);
2915 
2916  idx1 = findvar(opts->cmpvarlist[i], vars1);
2917  idx2 = findvar(opts->cmpvarlist[i], vars2);
2918 
2919  if (idx1 < 0) {
2920  if (!opts->metadata) /* This gets reported in cmpmeta. */
2921  fprintf(stderr, "DIFFER : Failed to find variable \"%s%s\" in file \"%s\".\n", getGroupPath(), opts->cmpvarlist[i], opts->file1);
2922 
2923  if (!opts->warn[NCCMP_W_ALL])
2924  status = EXIT_DIFFER;
2925  if (opts->force)
2926  continue;
2927  else
2928  break;
2929  }
2930 
2931  if (idx2 < 0) {
2932  if (!opts->metadata) /* This gets reported in cmpmeta. */
2933  fprintf(stderr, "DIFFER : Failed to find variable \"%s%s\" in file \"%s\".\n", getGroupPath(), opts->cmpvarlist[i], opts->file2);
2934 
2935  if (!opts->warn[NCCMP_W_ALL])
2936  status = EXIT_DIFFER;
2937  if (opts->force)
2938  continue;
2939  else
2940  break;
2941  }
2942 
2943  if (vars1[idx1].len != vars2[idx2].len) {
2944  fprintf(stderr, "DIFFER : SIZE OF VARIABLE \"%s%s\" : %d <> %d\n", getGroupPath(), opts->cmpvarlist[i], (int) vars1[idx1].len, (int) vars2[idx2].len);
2945 
2946  if (!opts->warn[NCCMP_W_ALL])
2947  status = EXIT_DIFFER;
2948  if (opts->force)
2949  continue;
2950  else
2951  break;
2952  }
2953 
2954  if (vars1[idx1].type != vars2[idx2].type) {
2955  type2string(vars1[idx1].type, str1);
2956  type2string(vars2[idx2].type, str2);
2957  fprintf(stderr, "DIFFER : TYPE OF VARIABLE \"%s%s\" : %s <> %s\n", getGroupPath(), opts->cmpvarlist[i], str1, str2);
2958 
2959  if (!opts->warn[NCCMP_W_ALL])
2960  status = EXIT_DIFFER;
2961 
2962  if (opts->force)
2963  continue;
2964  else
2965  break;
2966  }
2967 
2968  /* Has rec? */
2969  if (vars1[idx1].hasrec) {
2970 
2971  /* Compare only if # recs are equal and not zero. */
2972  if ((nrec1 == nrec2) && (nrec1 + nrec2)) {
2973  /* TODO: Check if ignorem missing. */
2974  cmpstatus = nccmpdatarecvar(ncid1, ncid2, opts->cmpvarlist[i], opts, 0, nrec1 - 1, user_types1, user_types2);
2975  if (cmpstatus) {
2976  status = cmpstatus;
2977  if (opts->force)
2978  continue;
2979  else
2980  break;
2981  }
2982  }
2983  } else {
2984  /* TODO: Check if ignorem missing. */
2985  cmpstatus = cmpvar(opts->cmpvarlist[i], -1, opts, ncid1, ncid2, user_types1, user_types2);
2986  if (cmpstatus) {
2987  status = EXIT_FAILURE;
2988  if (opts->force)
2989  continue;
2990  else
2991  break;
2992  }
2993  }
2994  }
2995 
2996  if (opts->verbose)
2997  printf("INFO: Finished comparing data.\n");
2998 
2999  freestringlist(&processed, nprocessed);
3000  return status;
3001 }
3002 
3003 /* *********************************************************** */
3004 int
3005 nccmp(nccmpopts* opts) {
3006  int ncid1, ncid2;
3007  int status;
3008  int nuser_types1, nuser_types2;
3009  nccmp_user_type_t *user_types1, *user_types2;
3010  if (opts->verbose)
3011  printf("INFO: Opening input files.\n");
3012 
3013  status = openfiles(opts, &ncid1, &ncid2);
3014  if (status)
3015  return status;
3016 
3017  if (opts->verbose)
3018  printf("INFO: Creating variable comparison list.\n");
3019 
3020  if (opts->verbose)
3021  printf("INFO: Comparing file formats.\n");
3022 
3023  status += nccmpformats(opts, ncid1, ncid2);
3024  if (status && !opts->force)
3025  return status;
3026 
3027  if (opts->verbose)
3028  printf("INFO: Comparing global attributes.\n");
3029  status += nccmpglobalatts(opts, ncid1, ncid2);
3030 
3031  if (status && !opts->force)
3032  return status;
3033 
3034  if (opts->verbose)
3035  printf("INFO: Collecting dimension information for first file.\n");
3036 
3037  getdiminfo(ncid1, dims1, &ndims1);
3038 
3039  if (opts->verbose)
3040  printf("INFO: Collecting dimension information for second file.\n");
3041 
3042  getdiminfo(ncid2, dims2, &ndims2);
3043  status += compareGroup(opts, ncid1, ncid2);
3044  if (status && !opts->force)
3045  return status;
3046 
3047  // Check root group
3048  status += makecmpvarlist(opts, ncid1, ncid2);
3049  if (status && !opts->force)
3050  return status;
3051 
3052  if (opts->verbose)
3053  printf("INFO: Collecting variable information for first file.\n");
3054 
3055  user_types1 = getvarinfo(ncid1, vars1, &nvars1, opts->verbose, &nuser_types1);
3056 
3057  if (opts->verbose)
3058  printf("INFO: Collecting variable information for second file.\n");
3059 
3060  user_types2 = getvarinfo(ncid2, vars2, &nvars2, opts->verbose, &nuser_types2);
3061 
3062  if (nuser_types1 != nuser_types2)
3063  status++;
3064 
3065  if (status && !opts->force)
3066  return status;
3067 
3068  status += nccmprecinfo(opts, ncid1, ncid2);
3069  if (status && !opts->force)
3070  return status;
3071 
3072  if (opts->metadata) {
3073  status += nccmpmetadata(opts, ncid1, ncid2);
3074  }
3075 
3076  if (status && !opts->force)
3077  return status;
3078 
3079  if (opts->data) {
3080  status += nccmpdata(opts, ncid1, ncid2, user_types1, user_types2);
3081  }
3082 
3083  freevarinfo(nuser_types1, user_types1);
3084  freevarinfo(nuser_types2, user_types2);
3085 
3086  if (status && !opts->force)
3087  return status;
3088 
3089  if (opts->verbose)
3090  printf("INFO: Comparisons complete. Freeing memory.\n");
3091 
3092  return status;
3093 }
3094 
3095 int compareGroup(nccmpopts* opts, int ncid1, int ncid2) {
3096 
3097  int numgrps1, numgrps2;
3098  int i, status=0;
3099  GROUP_NODE *groups1 = NULL;
3100  GROUP_NODE *groups2 = NULL;
3101  int nuser_types1, nuser_types2;
3102  nccmp_user_type_t *user_types1, *user_types2;
3103 
3104  vector<string> groupNames1;
3105  vector<string> groupNames2;
3106  char name[NC_MAX_NAME];
3107  int *gids;
3108 
3109  // find the common list of group names
3110  nc_inq_grps(ncid1, &numgrps1, NULL);
3111  if (numgrps1 > 0) {
3112  gids = (int *) malloc(sizeof (int) * numgrps1);
3113  nc_inq_grps(ncid1, NULL, gids);
3114 
3115  for (i = 0; i < numgrps1; i++) {
3116  nc_inq_grpname(gids[i], name);
3117  groupNames1.push_back(name);
3118  }
3119  free(gids);
3120  }
3121  nc_inq_grps(ncid2, &numgrps2, NULL);
3122  if (numgrps2 > 0) {
3123  gids = (int *) malloc(sizeof (int) * numgrps2);
3124  nc_inq_grps(ncid2, NULL, gids);
3125 
3126  for (i = 0; i < numgrps2; i++) {
3127  nc_inq_grpname(gids[i], name);
3128  groupNames2.push_back(name);
3129  }
3130  free(gids);
3131  }
3132 
3133  // make sure names1 only has group names in it that are also in names2
3134  vector<string>::iterator it;
3135  for(i=0; i < (int)groupNames1.size(); i++) {
3136  it = find(groupNames2.begin(), groupNames2.end(), groupNames1[i]);
3137  if(it == groupNames2.end()) {
3138  printf("DIFFER : GROUP : %s%s : Does not exist in file 2\n", getGroupPath(), groupNames1[i].c_str());
3139  status++;
3140  if (status && !opts->force) {
3141  free(groups1);
3142  free(groups2);
3143  return status;
3144  }
3145  groupNames1.erase(groupNames1.begin() + i);
3146  i--;
3147  }
3148  }
3149 
3150  // check to see if that are groups in file2 that are not in file1
3151  for(i=0; i < (int)groupNames2.size(); i++) {
3152  it = find(groupNames1.begin(), groupNames1.end(), groupNames2[i]);
3153  if(it == groupNames1.end()) {
3154  printf("DIFFER : GROUP : %s%s : Does not exist in file 1\n", getGroupPath(), groupNames1[i].c_str());
3155  status++;
3156  if (status && !opts->force) {
3157  free(groups1);
3158  free(groups2);
3159  return status;
3160  }
3161  }
3162  }
3163 
3164  numgrps1 = groupNames1.size();
3165 
3166  if(numgrps1 > 0) {
3167  groups1 = (GROUP_NODE *) malloc(sizeof (GROUP_NODE) * numgrps1);
3168  getgroupinfo(ncid1, groupNames1, groups1);
3169  groups2 = (GROUP_NODE *) malloc(sizeof (GROUP_NODE) * numgrps1);
3170  getgroupinfo(ncid2, groupNames1, groups2);
3171 
3172  for (i = 0; i < numgrps1; i++) {
3173  groupPath.push_back(groupNames1[i]);
3174  if (opts->verbose)
3175  printf("INFO: Comparing group %s:\n", getGroupPath());
3176  status += makecmpvarlist(opts, groups1[i].groupID, groups2[i].groupID);
3177  if (status && !opts->force) {
3178  free(groups1);
3179  free(groups2);
3180  return status;
3181  } else {
3182  // Recursively call groups within groups
3183  status += compareGroup(opts, groups1[i].groupID, groups2[i].groupID);
3184  }
3185 
3186  if (opts->verbose)
3187  printf("INFO: Comparing group attributes [%s]:\n", getGroupPath());
3188  status += nccmpglobalatts(opts, groups1[i].groupID, groups2[i].groupID);
3189  if (status && !opts->force) {
3190  free(groups1);
3191  free(groups2);
3192  return status;
3193  }
3194 
3195  if (opts->verbose)
3196  printf("INFO: Collecting variable information for first file.\n");
3197 
3198  user_types1 = getvarinfo(groups1[i].groupID, vars1, &nvars1, opts->verbose, &nuser_types1);
3199 
3200  if (opts->verbose)
3201  printf("INFO: Collecting variable information for second file.\n");
3202 
3203  user_types2 = getvarinfo(groups2[i].groupID, vars2, &nvars2, opts->verbose, &nuser_types2);
3204  status += (nuser_types1 != nuser_types2);
3205  if (status && !opts->force) {
3206  free(groups1);
3207  free(groups2);
3208  freevarinfo(nuser_types1, user_types1);
3209  freevarinfo(nuser_types2, user_types2);
3210  return (status);
3211  }
3212 
3213 
3214  status += nccmprecinfo(opts, groups1[i].groupID, groups2[i].groupID);
3215  if (status && !opts->force) {
3216  free(groups1);
3217  free(groups2);
3218  freevarinfo(nuser_types1, user_types1);
3219  freevarinfo(nuser_types2, user_types2);
3220  return status;
3221  }
3222 
3223  if (opts->metadata) {
3224  status += nccmpmetadata(opts, groups1[i].groupID, groups2[i].groupID);
3225  }
3226 
3227  if (status && !opts->force) {
3228  free(groups1);
3229  free(groups2);
3230  freevarinfo(nuser_types1, user_types1);
3231  freevarinfo(nuser_types2, user_types2);
3232  return status;
3233  }
3234 
3235  if (opts->data) {
3236  status += nccmpdata(opts, groups1[i].groupID, groups2[i].groupID, user_types1, user_types2);
3237  }
3238 
3239  freevarinfo(nuser_types1, user_types1);
3240  freevarinfo(nuser_types2, user_types2);
3241 
3242  if (status && !opts->force) {
3243  free(groups1);
3244  free(groups2);
3245  return status;
3246  }
3247 
3248  clearstringlist(opts->cmpvarlist, opts->ncmpvarlist);
3249  groupPath.pop_back();
3250  }
3251  }
3252  free(groups1);
3253  free(groups2);
3254  return status;
3255 }
3256 
3257 /* *********************************************************** */
3258 
3259 int
3260 main(int argc, char** argv) {
3261  int status;
3262  nccmpopts opts;
3263 
3264  status = EXIT_SUCCESS;
3265 
3266  initnccmpopts(&opts);
3267 
3268  /* parse command-line args. & options */
3269  status = getnccmpopts(argc, argv, &opts);
3270 
3271  if (status != EXIT_SUCCESS)
3272  goto end;
3273 
3274  if (opts.verbose)
3275  printf("INFO: Command-line options parsed.\n");
3276 
3277  status = nccmp(&opts);
3278 
3279 end:
3280  if (opts.report_identical) {
3281  if (!(opts.help || opts.version) &&
3282  (status == EXIT_SUCCESS)) {
3283  printf("Files \"%s\" and \"%s\" are identical.\n",
3284  opts.file1, opts.file2);
3285  }
3286  }
3287 
3288  freenccmpopts(&opts);
3289 
3290  exit(status);
3291 }
an array had not been initialized Several spelling and grammar corrections were which is read from the appropriate MCF the above metadata values were hard coded A problem calculating the average background DN for SWIR bands when the moon is in the space view port was corrected The new algorithm used to calculate the average background DN for all reflective bands when the moon is in the space view port is now the same as the algorithm employed by the thermal bands For non SWIR changes in the averages are typically less than Also for non SWIR the black body DNs remain a backup in case the SV DNs are not available For SWIR the changes in computed averages were larger because the old which used the black body suffered from contamination by the micron leak As a consequence of the if SV DNs are not available for the SWIR the EV pixels will not be the granule time is used to identify the appropriate tables within the set given for one LUT the first two or last two tables respectively will be used for the interpolation If there is only one LUT in the set of it will be treated as a constant LUT The manner in which Earth View data is checked for saturation was changed Previously the raw Earth View DNs and Space View DNs were checked against the lookup table values contained in the table dn_sat The change made is to check the raw Earth and Space View DNs to be sure they are less than the maximum saturation value and to check the Space View subtracted Earth View dns against a set of values contained in the new lookup table dn_sat_ev The metadata configuration and ASSOCIATEDINSTRUMENTSHORTNAME from the MOD02HKM product The same metatdata with extensions and were removed from the MOD021KM and MOD02OBC products ASSOCIATEDSENSORSHORTNAME was set to MODIS in all products These changes are reflected in new File Specification which users may consult for exact the pow functions were eliminated in Emissive_Cal and Emissive bands replaced by more efficient code Other calculations throughout the code were also made more efficient Aside from a few round off there was no difference to the product The CPU time decreased by about for a day case and for a night case A minor bug in calculating the uncertainty index for emissive bands was corrected The frame index(0-based) was previously being used the frame number(1-based) should have been used. There were only a few minor changes to the uncertainty index(maximum of 1 digit). 3. Some inefficient arrays(Sigma_RVS_norm_sq) were eliminated and some code lines in Preprocess_L1A_Data were moved into Process_OBCEng_Emiss. There were no changes to the product. Required RAM was reduced by 20 MB. Now
int addstringtolist(char **list, char *string, int nitems)
Definition: strlist.c:129
int cmp_vartol_ut(void *P1, void *P2, int offset1, int offset2, int size1, int size2, char *name, nccmpopts *opts, int rec, size_t *odomax, off_t nitems, size_t *count, size_t *start, varstruct *v1, varstruct *v2, T M1, T M2)
Definition: nccmp.cpp:381
int cmp_var_ut(int ncid1, int ncid2, nccmpopts *opts, int rec, size_t *odomax, off_t nitems, size_t *count, size_t *start, varstruct *v1, varstruct *v2, T M1, T M2)
Definition: nccmp.cpp:294
int nccmpmetadata(nccmpopts *opts, int ncid1, int ncid2)
Definition: nccmp.cpp:1929
int strlistsd(char **list1, char **list2, char **listdiff, int n1, int n2, int nsd)
Definition: strlist.c:198
int openfiles(nccmpopts *opts, int *ncid1, int *ncid2)
Definition: nccmp.cpp:1258
#define EXIT_SUCCESS
Definition: GEO_basic.h:72
int j
Definition: decode_rs.h:73
int status
Definition: l1_czcs_hdf.c:32
void ToString(T v, char *out, char *formatprec)
Definition: nccmp.cpp:122
list(APPEND LIBS ${PGSTK_LIBRARIES}) add_executable(atteph_info_modis atteph_info_modis.c) target_link_libraries(atteph_info_modis $
Definition: CMakeLists.txt:7
int nccmpformats(nccmpopts *opts, int ncid1, int ncid2)
Definition: nccmp.cpp:1668
float f1(float x)
int findvar(char *name, varstruct *vars)
Definition: nccmp.cpp:2225
int compareGroup(nccmpopts *opts, int ncid1, int ncid2)
Definition: nccmp.cpp:3095
void initnccmpopts(nccmpopts *popts)
Definition: opt.c:65
void freevarinfo(int nuser_types, nccmp_user_type_t *comp_types)
Definition: nccmp.cpp:1568
#define NCFORMATSTR(f)
Definition: nccmp.cpp:61
int clearstringlist(char **list, int n)
Definition: strlist.c:36
#define NULL
Definition: decode_rs.h:63
int cmpvar(char *name, int rec, nccmpopts *opts, int ncid1, int ncid2, nccmp_user_type_t *user_types1, nccmp_user_type_t *user_types2)
Definition: nccmp.cpp:2241
no change in intended resolving MODur00064 Corrected handling of bad ephemeris attitude resolving resolving GSFcd00179 Corrected handling of fill values for[Sensor|Solar][Zenith|Azimuth] resolving MODxl01751 Changed to validate LUT version against a value retrieved from the resolving MODxl02056 Changed to calculate Solar Diffuser angles without adjustment for estimated post launch changes in the MODIS orientation relative to incidentally resolving defects MODxl01766 Also resolves MODxl01947 Changed to ignore fill values in SCI_ABNORM and SCI_STATE rather than treating them as resolving MODxl01780 Changed to use spacecraft ancillary data to recognise when the mirror encoder data is being set by side A or side B and to change calculations accordingly This removes the need for seperate LUTs for Side A and Side B data it makes the new LUTs incompatible with older versions of the and vice versa Also resolves MODxl01685 A more robust GRing algorithm is being which will create a non default GRing anytime there s even a single geolocated pixel in a granule Removed obsolete messages from seed as required for compatibility with version of the SDP toolkit Corrected test output file names to end in out
Definition: HISTORY.txt:422
size_t nrec2
Definition: nccmp.cpp:56
void ToHex(T v, char *out)
Definition: nccmp.cpp:109
vector< string > groupPath
Definition: nccmp.cpp:59
int odometer(size_t *odo, size_t *limits, int first, int last)
Definition: nccmp.cpp:548
int nccmpglobalatts(nccmpopts *opts, int ncid1, int ncid2)
Definition: nccmp.cpp:1691
int getnumstrlist(char **list, int nlist)
Definition: strlist.c:242
const double pi
int main(int argc, char **argv)
Definition: nccmp.cpp:3260
int ndims1
Definition: nccmp.cpp:57
int newstringlist(char ***list, int *n, int size)
Definition: strlist.c:22
nccmp_user_type_t * getvarinfo(int ncid, varstruct *vars, int *nvars, int verbose, int *nuser_types)
Definition: nccmp.cpp:1489
void freenccmpopts(nccmpopts *popts)
Definition: opt.c:54
int excludevars(int ncid1, int ncid2, char **finallist, int nfinal, char **excludelist, int nexclude)
Definition: nccmp.cpp:488
#define NCCMP_W_ALL
Definition: opt.h:98
int nvars1
Definition: nccmp.cpp:57
int nccmpdatarecvartol(int ncid1, int ncid2, char *varname, nccmpopts *opts, size_t recstart, size_t recend, nccmp_user_type_t *user_types1, nccmp_user_type_t *user_types2)
Definition: nccmp.cpp:2783
size_t nrec1
Definition: nccmp.cpp:56
void freestringlist(char ***list, int nitems)
Definition: strlist.c:88
#define NCCMP_W_EOS
Definition: opt.h:100
const char * getGroupPath()
Definition: nccmp.cpp:67
int nccmpdatarecvar(int ncid1, int ncid2, char *varname, nccmpopts *opts, size_t recstart, size_t recend, nccmp_user_type_t *user_types1, nccmp_user_type_t *user_types2)
Definition: nccmp.cpp:2804
float f2(float y)
int ndims2
Definition: nccmp.cpp:57
int instringlist(char **list, char *str, int nitems)
Definition: strlist.c:107
void getidxstr(varstruct *var, size_t *start, int curidx, char *out)
Definition: nccmp.cpp:457
double precision function f(R1)
Definition: tmd.lp.f:1454
#define NCCMP_W_FORMAT
Definition: opt.h:99
int cmp_missing(T *in1, T *in2, T m1, T m2)
Definition: nccmp.cpp:88
int nccmpdatatol(int ncid1, int ncid2, nccmpopts *opts, nccmp_user_type_t *user_types1, nccmp_user_type_t *user_types2)
Definition: nccmp.cpp:2824
data_t tmp
Definition: decode_rs.h:74
int cmpattval(int nc1, int nc2, int varid1, int varid2, char *name, int len, nc_type type)
Definition: nccmp.cpp:908
int getnccmpopts(int argc, char **argv, nccmpopts *popts)
Definition: opt.c:121
int cmpatt(int ncid1, int ncid2, int varid1, int varid2, char *name, char *varname, nccmpopts *opts)
Definition: nccmp.cpp:809
string path
Definition: color_dtdb.py:221
struct nccmp_user_type_t * fields
int ncallvars(int ncid, char **list, int nlist)
Definition: ncinfo.c:94
void getidxstr_fortran(varstruct *var, size_t *start, int curidx, char *out)
Definition: nccmp.cpp:473
void prettyprintatt(int ncid, char *varname, int varid, char *name, char *str)
Definition: nccmp.cpp:582
int nccmpdata(nccmpopts *opts, int ncid1, int ncid2, nccmp_user_type_t *user_types1, nccmp_user_type_t *user_types2)
Definition: nccmp.cpp:2883
void getgroupinfo(int ncid, vector< string > names, GROUP_NODE *groups)
Definition: nccmp.cpp:1327
int appendstringtolist(char ***list, const char *string, int *nitems)
Definition: strlist.c:152
varstruct vars1[(int) NC_MAX_VARS]
Definition: nccmp.cpp:52
int nccmprecinfo(nccmpopts *opts, int ncid1, int ncid2)
Definition: nccmp.cpp:1273
instead the metadata field ProcessingEnvinronment is filled in from the output of a call to the POSIX compliant function uname from within the L1B code A small bug in L1B_Tables an incorrect comparison of RVS coefficients for TEBs to RVS coefficients for RSBs was being made This was replaced with a comparison between TEB coefficients This error never resulted in an incorrect RVS correction but did lead to recalculating the coefficients for each detector in a thermal band even if the coefficients were the same for all detectors To reduce to overall size of the reflective LUT HDF fill values were eliminated from all LUTs previously dimensioned where and where NUM_TIMES is the number of time dependent table pieces In Preprocess a small error where the trailing dropped scan counter was incremented when the leading dropped scan counter should have been was fixed This counter is internal only and is not yet used for any chiefly to casting of were added to make it LINUX compatible Output of code run on LINUX machines displays differences of at most scaled sector incalculable values of the Emissive calibration factor and incalculable values of SV or BB averages was moved outside the loop over frames in Emissive_Cal c since none of these quantities are frame dependent Initialization of b1 and XMS values in Preprocess c routine Process_OBCENG_Emiss was moved inside the detector loops The code was altered so that if up to five scans are dropped between the leading middle or middle trailing the leading or trailing granule will still be used in emissive calibration to form a cross granule average QA bits and are set for a gap between the leading middle and middle trailing granules respectively This may in rare instances lead to a change in emissive calibration coefficients for scans at the beginning or end of a granule A small bug in the Band correction algorithm was corrected an uncertainty value was being checked against an upper bound whereas the proper quantity to be checked was the corresponding which is the product of the Band radiance times the ratio of the Band to Band scaling factors times the LUT correction value for that detector In addition a new LUT which allows for a frame offset with regard to the Band radiance was added A LUT which switches the correction off or on was also added Changes which do not affect scientific output of the the pixel is flagged with the newly created flag and the number of pixels for which this occurs is counted in the QA_common table The array of b1s in Preprocess c was being initialized to outside the loop over which meant that if b1 could not be the value of b1 from the previous band for that scan detector combination was used The initialization was moved inside the band loop Minor code changes were made to eliminate compiler warnings when the code is compiled in bit mode Temperature equations were upgraded to be MODIS AQUA or MODIS TERRA specific and temperature conversion coefficients for AQUA were MOD_PR02 will not cease execution if the value of this parameter is not but will print a message
Definition: HISTORY.txt:644
no change in intended resolving MODur00064 Corrected handling of bad ephemeris attitude resolving resolving GSFcd00179 Corrected handling of fill values for[Sensor|Solar][Zenith|Azimuth] resolving MODxl01751 Changed to validate LUT version against a value retrieved from the resolving MODxl02056 Changed to calculate Solar Diffuser angles without adjustment for estimated post launch changes in the MODIS orientation relative to incidentally resolving defects MODxl01766 Also resolves MODxl01947 Changed to ignore fill values in SCI_ABNORM and SCI_STATE fields
Definition: HISTORY.txt:400
int cmp_missing_nanequal(T *in1, T *in2, T m1, T m2)
Definition: nccmp.cpp:102
int recid2
Definition: nccmp.cpp:57
int cmpvartol(char *name, int rec, nccmpopts *opts, int ncid1, int ncid2, nccmp_user_type_t *user_types1, nccmp_user_type_t *user_types2)
Definition: nccmp.cpp:2538
int nccmp(nccmpopts *opts)
Definition: nccmp.cpp:3005
subroutine diff(x, conec, n, dconecno, dn, dconecmk, units, u, inno, i, outno, o, input, deriv)
Definition: ffnet.f:205
int allvarnames(char **list, int nvars, int ncid1, int ncid2)
Definition: nccmp.cpp:1636
nccmp_user_type_t * nccmp_load_group_usertype_array(int group_id, int *nuser_types)
int groupID
Definition: nccmp.h:63
dimstruct dims2[(int) NC_MAX_DIMS]
Definition: nccmp.cpp:53
#define XFREE(stale)
Definition: xmalloc.h:42
#define BROADCAST_MISSING(T)
void type2string(nc_type type, char *str)
Definition: nccmp.cpp:1216
data_t b[NROOTS+1]
Definition: decode_rs.h:77
const char * str
Definition: l1c_msi.cpp:35
HISTORY txt for MOD_PR01(step one of PGE01) History follows the following convention needed due to new Aqua ReprocessingActual and the expected LUT revision number from PCF Changed to use PGE version for ProductionHistory Added Archive including ProcessingEnvironment Corrected handling of bad to resovle GSFcd02514 Changed to check staged LUT revision number versus the expected LUT revision number from thereby resolving defect report MODxl02056 This change also avoids the memory access violation reported in MODur00039 Changed the way output arrays were initialized with fill values
Definition: HISTORY.txt:162
int isinvarstructlist(char *name, varstruct *vars, int nvars)
Definition: nccmp.cpp:1582
int nvars2
Definition: nccmp.cpp:57
Definition: names.f90:1
an array had not been initialized Several spelling and grammar corrections were which is read from the appropriate MCF the above metadata values were hard coded A problem calculating the average background DN for SWIR bands when the moon is in the space view port was corrected The new algorithm used to calculate the average background DN for all reflective bands when the moon is in the space view port is now the same as the algorithm employed by the thermal bands For non SWIR changes in the averages are typically less than Also for non SWIR the black body DNs remain a backup in case the SV DNs are not available For SWIR the changes in computed averages were larger because the old which used the black body suffered from contamination by the micron leak As a consequence of the if SV DNs are not available for the SWIR the EV pixels will not be the granule time is used to identify the appropriate tables within the set given for one LUT the first two or last two tables respectively will be used for the interpolation If there is only one LUT in the set of it will be treated as a constant LUT The manner in which Earth View data is checked for saturation was changed Previously the raw Earth View DNs and Space View DNs were checked against the lookup table values contained in the table dn_sat The change made is to check the raw Earth and Space View DNs to be sure they are less than the maximum saturation value and to check the Space View subtracted Earth View dns against a set of values contained in the new lookup table dn_sat_ev The metadata configuration and ASSOCIATEDINSTRUMENTSHORTNAME from the MOD02HKM product The same metatdata with extensions and were removed from the MOD021KM and MOD02OBC products ASSOCIATEDSENSORSHORTNAME was set to MODIS in all products These changes are reflected in new File Specification which users may consult for exact the pow functions were eliminated in Emissive_Cal and Emissive bands replaced by more efficient code Other calculations throughout the code were also made more efficient Aside from a few round off there was no difference to the product The CPU time decreased by about for a day case and for a night case A minor bug in calculating the uncertainty index for emissive bands was corrected The frame the required RAM for each execution is MB on the DEC ALPHA and MB on the SGI Octane v2
Definition: HISTORY.txt:728
#define fabs(a)
Definition: misc.h:93
#define XMALLOC(type, num)
Definition: xmalloc.h:36
dimstruct dims1[(int) NC_MAX_DIMS]
Definition: nccmp.cpp:53
int cmp_var(int ncid1, int ncid2, nccmpopts *opts, int rec, size_t *odomax, off_t nitems, size_t *count, size_t *start, varstruct *v1, varstruct *v2, T M1, T M2)
Definition: nccmp.cpp:126
data_t s[NROOTS]
Definition: decode_rs.h:75
void getdiminfo(int ncid, dimstruct *dims, int *ndims)
Definition: nccmp.cpp:1359
no change in intended resolving MODur00064 Corrected handling of bad ephemeris attitude resolving resolving GSFcd00179 Corrected handling of fill values for[Sensor|Solar][Zenith|Azimuth] resolving MODxl01751 Changed to validate LUT version against a value retrieved from the resolving MODxl02056 Changed to calculate Solar Diffuser angles without adjustment for estimated post launch changes in the MODIS orientation relative to incidentally resolving defects MODxl01766 Also resolves MODxl01947 Changed to ignore fill values in SCI_ABNORM and SCI_STATE rather than treating them as resolving MODxl01780 Changed to use spacecraft ancillary data to recognise when the mirror encoder data is being set by side A or side B and to change calculations accordingly This removes the need for seperate LUTs for Side A and Side B data it makes the new LUTs incompatible with older versions of the and vice versa Also resolves MODxl01685 A more robust GRing algorithm is being which will create a non default GRing anytime there s even a single geolocated pixel in a granule Removed obsolete messages from seed as required for compatibility with version of the SDP toolkit Corrected test output file names to end in per delivery and then split off a new MYD_PR03 pcf file for Aqua Added AssociatedPlatformInstrumentSensor to the inventory metadata in MOD01 mcf and MOD03 mcf Created new versions named MYD01 mcf and MYD03 where AssociatedPlatformShortName is rather than Terra The program itself has been changed to read the Satellite Instrument validate it against the input L1A and LUT and to use it determine the correct files to retrieve the ephemeris and attitude data from Changed to produce a LocalGranuleID starting with MYD03 if run on Aqua data Added the Scan Type file attribute to the Geolocation copied from the L1A and attitude_angels to radians rather than degrees The accumulation of Cumulated gflags was moved from GEO_validate_earth_location c to GEO_locate_one_scan c
Definition: HISTORY.txt:464
int makecmpvarlist(nccmpopts *opts, int ncid1, int ncid2)
Definition: nccmp.cpp:1595
#define EXIT_DIFFER
Definition: common.h:84
#define EXIT_FATAL
Definition: common.h:85
int cmp_(T *in1, T *in2)
Definition: nccmp.cpp:81
varstruct vars2[(int) NC_MAX_VARS]
Definition: nccmp.cpp:52
int strlistu(char **list1, char **list2, char **listunion, int n1, int n2, int nu)
Definition: strlist.c:171
char get_missing(int ncid, varstruct *var, const char *attname)
Definition: nccmp.cpp:1424
int i
Definition: decode_rs.h:71
void broadcast_missing(nc_type var_type, nc_type att_type, missing_struct *values)
Definition: nccmp.cpp:1380
How many dimensions is the output array Default is Not sure if anything above will work correctly strcpy(l2prod->title, "no title yet")
int recid1
Definition: nccmp.cpp:57
int verbose
Definition: fmt_check.c:6
int cmp_vartol(int ncid1, int ncid2, nccmpopts *opts, int rec, size_t *odomax, off_t nitems, size_t *count, size_t *start, varstruct *v1, varstruct *v2, T M1, T M2)
Definition: nccmp.cpp:213
float p[MODELMAX]
Definition: atrem_corl1.h:131
int cmp_nanequal(T *in1, T *in2)
Definition: nccmp.cpp:95
void handle_error(int status)
Definition: nccmp.cpp:530
#define NC_MAX_TYPES
Definition: nccmp.cpp:48
int count
Definition: decode_rs.h:79