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