OB.DAAC Logo
NASA Logo
Ocean Color Science Software

ocssw V2022
nccmp.c
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 
20 #include "nccmp.h"
21 #include "ncinfo.h"
22 #include "strlist.h"
23 #include <stdint.h>
24 #include <float.h>
25 
26 varstruct vars1[(int)NC_MAX_VARS], vars2[(int)NC_MAX_VARS];
27 dimstruct dims1[(int)NC_MAX_DIMS], dims2[(int)NC_MAX_DIMS];
28 size_t nrec1, nrec2;
30 
31 #define NCFORMATSTR(f) \
32  (f == NC_FORMAT_CLASSIC ? "NC_FORMAT_CLASSIC" : \
33  (f == NC_FORMAT_64BIT ? "NC_FORMAT_64BIT" : \
34  (f == NC_FORMAT_NETCDF4 ? "NC_FORMAT_NETCDF4" : \
35  "NC_FORMAT_NETCDF4_CLASSIC"))) \
36 
37 /* *********************************************************** */
38 /* Returns formatted string of dimension indices.
39  Intended to print out locations of value differences.
40  'out' should be pre-allocated large enough for output. */
41 void getidxstr(varstruct* var, size_t* start, int curidx, char* out)
42 {
43  int i;
44  char tmp[8];
45  memset(out,'\0',32);
46  for(i=0; i < var->ndims-1; ++i) {
47  sprintf(tmp, "%d ", (int)start[i]);
48  strcat(out, tmp);
49  }
50  sprintf(tmp, "%d", curidx);
51  strcat(out, tmp);
52 }
53 /* *********************************************************** */
54 /* Same as above but with fortran style indices, which means they're
55  1-based (i.e. first index is 1, not 0) and fast-varying dimension is
56  printed first (reverse order compared with C-style indices) */
57 void getidxstr_fortran(varstruct* var, size_t* start, int curidx, char* out)
58 {
59  int i;
60  char tmp[8];
61  memset(out,'\0',32);
62  sprintf(tmp, "%d", curidx + 1);
63  strcat(out, tmp);
64 
65  for(i = var->ndims-2; i >= 0; --i) {
66  sprintf(tmp, " %d", (int)start[i]+1);
67  strcat(out, tmp);
68  }
69 }
70 /* *********************************************************** */
71 /* Creates a string representation of a value into pre-allocated char array. */
72 void doubleToString(double v, char* out, char* formatprec) { \
73  sprintf(out, formatprec, v);
74 }
75 /* *********************************************************** */
76 void floatToString(float v, char* out, char* formatprec) { \
77  sprintf(out, formatprec, (double)v);
78 }
79 /* *********************************************************** */
80 void intToString(int v, char* out, char* ignore) { \
81  sprintf(out, "%d", v);
82 }
83 /* *********************************************************** */
84 void shortToString(short v, char* out, char* ignore) { \
85  sprintf(out, "%d", (int)v);
86 }
87 /* *********************************************************** */
88 void byteToString(unsigned char v, char* out, char* ignore) { \
89  sprintf(out, "%c", v);
90 }
91 /* *********************************************************** */
92 void textToString(char v, char* out, char* ignore) { \
93  sprintf(out, "%c", v);
94 }
95 /* *********************************************************** */
96 /* Creates a hex representation of a value into pre-allocated char array. */
97 void doubleToHex(double v, char* out) { \
98  unsigned char *p = (unsigned char*)&v;
99  int i;
100  char tmp[3];
101 
102  strcpy(out, "0x");
103 
104  for(i = 0; i < sizeof(double); ++i) {
105  sprintf(tmp, "%02X", p[i]);
106  strcat(out, tmp);
107  }
108 }
109 /* *********************************************************** */
110 void floatToHex(float v, char* out) { \
111  unsigned char *p = (unsigned char*)&v;
112  int i;
113  char tmp[3];
114 
115  strcpy(out, "0x");
116 
117  for(i = 0; i < sizeof(float); ++i) {
118  sprintf(tmp, "%02X", p[i]);
119  strcat(out, tmp);
120  }
121 }
122 /* *********************************************************** */
123 void intToHex(int v, char* out) { \
124  unsigned char *p = (unsigned char*)&v;
125  int i;
126  char tmp[3];
127 
128  strcpy(out, "0x");
129 
130  for(i = 0; i < sizeof(int); ++i) {
131  sprintf(tmp, "%02X", p[i]);
132  strcat(out, tmp);
133  }
134 }
135 /* *********************************************************** */
136 void shortToHex(short v, char* out) { \
137  unsigned char *p = (unsigned char*)&v;
138  int i;
139  char tmp[3];
140 
141  strcpy(out, "0x");
142 
143  for(i = 0; i < sizeof(short); ++i) {
144  sprintf(tmp, "%02X", p[i]);
145  strcat(out, tmp);
146  }
147 }
148 /* *********************************************************** */
149 void byteToHex(int8_t v, char* out) { \
150  unsigned char *p = (unsigned char*)&v;
151  int i;
152  char tmp[3];
153 
154  strcpy(out, "0x");
155 
156  for(i = 0; i < sizeof(int8_t); ++i) {
157  sprintf(tmp, "%02X", p[i]);
158  strcat(out, tmp);
159  }
160 }
161 /* *********************************************************** */
162 void textToHex(char v, char* out) { \
163  unsigned char *p = (unsigned char*)&v;
164  int i;
165  char tmp[3];
166 
167  strcpy(out, "0x");
168 
169  for(i = 0; i < sizeof(char); ++i) {
170  sprintf(tmp, "%02X", p[i]);
171  strcat(out, tmp);
172  }
173 }
174 /* *********************************************************** */
175 int
176 excludevars(int ncid1, int ncid2, char** finallist,
177  int nfinal, char** excludelist, int nexclude)
178 {
179  int nvars;
180  char** vars = NULL;
181  int status = EXIT_SUCCESS;
182 
183  vars = NULL;
184 
185  if ( (nexclude == 0)
186  )
187  return EXIT_SUCCESS;
188 
189  /* printf("%d: creating temporary var list array.\n", __LINE__); */
190  /* get simple difference */
191  if(newstringlist(&vars, &nvars, NC_MAX_VARS))
192  status = EXIT_FATAL;
193 
194  /* printf("%d: getting all variables names from both input files.\n", __LINE__); */
195  if(allvarnames(vars, nvars, ncid1, ncid2))
196  status = EXIT_FATAL;
197 
198  /*printf("vars=");
199  printstrlist(vars, nvars, stdout);
200  */
201 
202  if(strlistsd( vars, excludelist, finallist,
203  nvars, nexclude, nfinal))
204  status = EXIT_FATAL;
205 
206  /*printf("excludelist=");
207  printstrlist(excludelist, nexclude, stdout);
208  */
209 
210  /*printf("finallist=");
211  printstrlist(finallist, nfinal, stdout);
212  */
213 
214  freestringlist(&vars, nvars);
215 
216  return status;
217 }
218 /* *********************************************************** */
219 void handle_error(int status) {
220  if (status != NC_NOERR) {
221  fprintf(stderr, "%s\n", nc_strerror(status));
222  exit(-1);
223  }
224  }
225 
226 /* *********************************************************** */
227 /*
228  Mimics incrementing odometer.
229  Returns 0 if rolled-over.
230 
231  @param odo: the counters that are updated.
232  @param limits: the maximum values allowed per counter.
233  @param first: index of first counter to update.
234  @param last: index of last counter to update.
235  */
236 int odometer(size_t* odo, size_t* limits, int first, int last)
237 {
238  int i = last;
239  while (i >= first) {
240  odo[i] += 1;
241  if (odo[i] > limits[i])
242  odo[i] = 0;
243  else
244  break;
245 
246  --i;
247  }
248 
249 #ifdef __DEBUG__
250  printf("DEBUG : %d : odo = ", __LINE__);
251  for(i=first; i <= last; ++i) {
252  printf("%d ", odo[i]);
253  }
254  printf("\n");
255 #endif
256 
257  /* Test for roll over. */
258  for(i=first; i <= last; ++i) {
259  if (odo[i] != 0)
260  return 1;
261  }
262 
263  /* If we get here then rolled over. */
264  return 0;
265 }
266 /* *********************************************************** */
267 /* Pretty prints attribute values into a string.
268  Assumes 'str' is pre-allocated large enough to hold output string.
269 */
270 void prettyprintatt(int ncid, char* varname, int varid, char* name, char* str)
271 {
272  int status, i;
273  nc_type type;
274  size_t len;
275  char* pc;
276  int8_t* puc;
277  short* ps;
278  int* pi;
279  float* pf;
280  double* pd;
281  char tmpstr[32];
282 
283  status = nc_inq_att(ncid, varid, name, &type, &len);
284  if (status != NC_NOERR) {
285  if (varid == NC_GLOBAL)
286  fprintf(stderr, "ERROR : QUERYING GLOBAL ATTRIBUTE \"%s\"\n", name);
287  else
288  fprintf(stderr, "ERROR : QUERYING ATTRIBUTE \"%s\" FOR VARIABLE \"%s\"\n", name, varname);
289  return;
290  }
291 
292  str[0] = '\0';
293  if (len < 1) {
294  return;
295  }
296 
297  switch(type)
298  {
299  case NC_BYTE:
300  puc = XMALLOC(int8_t,len);
301 
302  status = nc_get_att(ncid, varid, name, puc);
303  if (status != NC_NOERR)
304  {
305  XFREE(puc); return;
306  }
307 
308  for(i=0; i < (int)len; ++i) {
309  byteToString(puc[i], str+2*i, NULL);
310  str[2*i+1] = ',';
311  }
312 
313  XFREE(puc);
314  str[2*(int)len-1] = '\0';
315  break;
316 
317  case NC_CHAR:
318  pc = XMALLOC(char,len);
319  status = nc_get_att_text(ncid, varid, name, pc);
320  if (status != NC_NOERR)
321  {
322  XFREE(pc); return;
323  }
324 
325  for(i=0; i < (int)len; ++i)
326  textToString(pc[i], str+i, NULL);
327 
328  XFREE(pc);
329  str[(int)len] = '\0';
330  break;
331 
332  case NC_SHORT:
333  ps = XMALLOC(short,len);
334  status = nc_get_att_short(ncid, varid, name, ps);
335  if (status != NC_NOERR)
336  {
337  XFREE(ps); return;
338  }
339 
340  for(i=0; i < (int)len; ++i) {
341  sprintf(tmpstr, "%d,", ps[i]);
342  strcat(str, tmpstr);
343  }
344 
345  XFREE(ps);
346  str[strlen(str)-1] = '\0'; // Remove last comma.
347  break;
348 
349  case NC_INT:
350  pi = XMALLOC(int,len);
351  status = nc_get_att_int(ncid, varid, name, pi);
352  if (status != NC_NOERR)
353  {
354  XFREE(pi); return;
355  }
356 
357  for(i=0; i < (int)len; ++i) {
358  sprintf(tmpstr, "%d,", pi[i]);
359  strcat(str, tmpstr);
360  }
361 
362  XFREE(pi);
363  str[strlen(str)-1] = '\0'; // Remove last comma.
364  break;
365 
366  case NC_FLOAT:
367  pf = XMALLOC(float,len);
368  status = nc_get_att_float(ncid, varid, name, pf);
369  if (status != NC_NOERR)
370  {
371  XFREE(pf); return;
372  }
373 
374  for(i=0; i < (int)len; ++i) {
375  sprintf(tmpstr, "%.9g,", pf[i]);
376  strcat(str, tmpstr);
377  }
378 
379  XFREE(pf);
380  str[strlen(str)-1] = '\0'; // Remove last comma.
381  break;
382 
383  case NC_DOUBLE:
384  pd = XMALLOC(double,len);
385  status = nc_get_att_double(ncid, varid, name, pd);
386  if (status != NC_NOERR)
387  {
388  XFREE(pd); return;
389  }
390 
391  for(i=0; i < (int)len; ++i) {
392  sprintf(tmpstr, "%.17g,", pd[i]);
393  strcat(str, tmpstr);
394  }
395 
396  XFREE(pd);
397  str[strlen(str)-1] = '\0'; // Remove last comma.
398  break;
399  }
400 }
401 /* *********************************************************** */
402 int cmpatt(int ncid1, int ncid2, int varid1, int varid2,
403  char* name, char* varname, nccmpopts* opts)
404 {
405  int ncstatus, status, attid1, attid2;
406  nc_type type1, type2;
407  size_t lenp1, lenp2;
408  char typestr1[256];
409  char typestr2[256];
410 
412  ncstatus = nc_inq_att(ncid1, varid1, name, &type1, &lenp1);
413  if (ncstatus != NC_NOERR) {
414  fprintf(stderr, "DIFFER : VARIABLE \"%s\" IS MISSING ATTRIBUTE WITH NAME \"%s\" IN FILE \"%s\"\n", varname, name, opts->file1);
415 
416  if (!opts->warn[NCCMP_W_ALL])
418 
419  return status;
420  }
421 
422  ncstatus = nc_inq_att(ncid2, varid2, name, &type2, &lenp2);
423  if (ncstatus != NC_NOERR) {
424  fprintf(stderr, "DIFFER : VARIABLE \"%s\" IS MISSING ATTRIBUTE WITH NAME \"%s\" IN FILE \"%s\"\n", varname, name, opts->file2);
425 
426  if (!opts->warn[NCCMP_W_ALL])
428 
429  return status;
430  }
431 
432  if (type1 != type2) {
433  type2string(type1, typestr1);
434  type2string(type2, typestr2);
435  fprintf(stderr, "DIFFER : TYPES : ATTRIBUTE : %s : VARIABLE : %s : %s <> %s\n", name, varname, typestr1, typestr2);
436 
437  if (!opts->warn[NCCMP_W_ALL])
439 
440  return status;
441  }
442 
443  if (lenp1 != lenp2) {
444  prettyprintatt(ncid1, varname, varid1, name, typestr1);
445  prettyprintatt(ncid2, varname, varid2, name, typestr2);
446 
447  fprintf(stderr, "DIFFER : LENGTHS : ATTRIBUTE : %s : VARIABLE : %s : %lu <> %lu : VALUES : ", name, varname, (unsigned long)lenp1, (unsigned long)lenp2);
448 
449  switch(type1) {
450  case NC_CHAR:
451  /* Quote strings. */
452  fprintf(stderr, "\"%s\" : \"%s\"\n", typestr1, typestr2);
453  if (strcmp(typestr1,typestr2) == 0) {
454  /* Same text, but invisible trailing nulls because lengths differ. */
455  if (opts->warn[NCCMP_W_EOS] || opts->warn[NCCMP_W_ALL]) {
456  /* Pass */
457  } else {
459  return status;
460  }
461  }
462  break;
463  default:
464  /* Unquoted. */
465  fprintf(stderr, "%s : %s\n", typestr1, typestr2);
466  if (!opts->warn[NCCMP_W_ALL]) {
468  return status;
469  }
470  break;
471  }
472  }
473 
474  if (cmpattval(ncid1, ncid2, varid1, varid2, name, lenp1, type1) != NC_NOERR) {
475  prettyprintatt(ncid1, varname, varid1, name, typestr1);
476  prettyprintatt(ncid2, varname, varid2, name, typestr2);
477  fprintf(stderr, "DIFFER : VARIABLE : %s : ATTRIBUTE : %s : VALUES : ", varname, name);
478 
479  switch(type1) {
480  case NC_CHAR:
481  /* Quote strings. */
482  fprintf(stderr, "\"%s\" <> \"%s\"\n", typestr1, typestr2);
483  break;
484  default:
485  /* Unquoted. */
486  fprintf(stderr, "%s <> %s\n", typestr1, typestr2);
487  break;
488  }
489 
490  if (!opts->warn[NCCMP_W_ALL]) {
492  return status;
493  }
494  }
495 
496  return EXIT_SUCCESS;
497 }
498 
499 
500 /* *********************************************************** */
501 /* Assumes that both attributes have same length.
502  */
503 int cmpattval(int nc1, int nc2, int varid1, int varid2, char* name, int len, nc_type type)
504 {
505  char* c1;
506  int8_t* uc1;
507  short* s1;
508  int* i1;
509  float* f1;
510  double* d1;
511  char* c2;
512  int8_t* uc2;
513  short* s2;
514  int* i2;
515  float* f2;
516  double* d2;
517  int status;
518  int i;
519 
520  if (name == NULL) return NC_EINVAL;
521 
522  switch(type)
523  {
524  case NC_BYTE:
525  uc1 = XMALLOC(int8_t,len);
526  uc2 = XMALLOC(int8_t,len);
527  status = nc_get_att(nc1, varid1, name, uc1);
528  if (status != NC_NOERR)
529  {
530  XFREE(uc1); XFREE(uc2); return NC_EINVAL;
531  }
532  status = nc_get_att(nc2, varid2, name, uc2);
533  if (status != NC_NOERR)
534  {
535  XFREE(uc1); XFREE(uc2); return NC_EINVAL;
536  }
537  for(i = 0; i < len; ++i)
538  {
539  if (uc1[i] != uc2[i])
540  {
541  XFREE(uc1); XFREE(uc2); return EXIT_DIFFER;
542  }
543  }
544  XFREE(uc1);
545  XFREE(uc2);
546  break;
547  case NC_CHAR:
548  c1 = XMALLOC(char,len);
549  c2 = XMALLOC(char,len);
550  status = nc_get_att_text(nc1, varid1, name, c1);
551  if (status != NC_NOERR)
552  {
553  XFREE(c1); XFREE(c2); return NC_EINVAL;
554  }
555  status = nc_get_att_text(nc2, varid2, name, c2);
556  if (status != NC_NOERR)
557  {
558  XFREE(c1); XFREE(c2); return NC_EINVAL;
559  }
560  if (strncmp(c1,c2,len) != 0)
561  {
562  XFREE(c1); XFREE(c2); return EXIT_DIFFER;
563  }
564  XFREE(c1);
565  XFREE(c2);
566  break;
567  case NC_SHORT:
568  s1 = XMALLOC(short,len);
569  s2 = XMALLOC(short,len);
570  status = nc_get_att_short(nc1, varid1, name, s1);
571  if (status != NC_NOERR)
572  {
573  XFREE(s1); XFREE(s2); return NC_EINVAL;
574  }
575  status = nc_get_att_short(nc2, varid2, name, s2);
576  if (status != NC_NOERR)
577  {
578  XFREE(s1); XFREE(s2); return NC_EINVAL;
579  }
580  for(i = 0; i < len; ++i)
581  {
582  if (s1[i] != s2[i])
583  {
584  XFREE(s1); XFREE(s2); return EXIT_DIFFER;
585  }
586  }
587  XFREE(s1);
588  XFREE(s2);
589  break;
590  case NC_INT:
591  i1 = XMALLOC(int,len);
592  i2 = XMALLOC(int,len);
593  status = nc_get_att_int(nc1, varid1, name, i1);
594  if (status != NC_NOERR)
595  {
596  XFREE(i1); XFREE(i2); return NC_EINVAL;
597  }
598  status = nc_get_att_int(nc2, varid2, name, i2);
599  if (status != NC_NOERR)
600  {
601  XFREE(i1); XFREE(i2); return NC_EINVAL;
602  }
603  for(i = 0; i < len; ++i)
604  {
605  if (i1[i] != i2[i])
606  {
607  XFREE(i1); XFREE(i2); return EXIT_DIFFER;
608  }
609  }
610  XFREE(i1);
611  XFREE(i2);
612  break;
613  case NC_FLOAT:
614  f1 = XMALLOC(float,len);
615  f2 = XMALLOC(float,len);
616  status = nc_get_att_float(nc1, varid1, name, f1);
617  if (status != NC_NOERR)
618  {
619  XFREE(f1); XFREE(f2); return NC_EINVAL;
620  }
621  status = nc_get_att_float(nc2, varid2, name, f2);
622  if (status != NC_NOERR)
623  {
624  XFREE(f1); XFREE(f2); return NC_EINVAL;
625  }
626  for(i = 0; i < len; ++i)
627  {
628  if (f1[i] != f2[i])
629  {
630  XFREE(f1); XFREE(f2); return EXIT_DIFFER;
631  }
632  }
633  XFREE(f1);
634  XFREE(f2);
635  break;
636  case NC_DOUBLE:
637  d1 = XMALLOC(double,len);
638  d2 = XMALLOC(double,len);
639  status = nc_get_att_double(nc1, varid1, name, d1);
640  if (status != NC_NOERR)
641  {
642  XFREE(d1); XFREE(d2); return NC_EINVAL;
643  }
644  status = nc_get_att_double(nc2, varid2, name, d2);
645  if (status != NC_NOERR)
646  {
647  XFREE(d1); XFREE(d2); return NC_EINVAL;
648  }
649  for(i = 0; i < len; ++i)
650  {
651  if (d1[i] != d2[i])
652  {
653  XFREE(d1); XFREE(d2); return EXIT_DIFFER;
654  }
655  }
656  XFREE(d1);
657  XFREE(d2);
658  break;
659  }
660 
661  return EXIT_SUCCESS;
662 }
663 /* *********************************************************** */
664 void type2string(nc_type type, char* str)
665 {
666  switch(type)
667  {
668  case NC_BYTE:
669  strcpy(str, "BYTE");
670  break;
671  case NC_CHAR:
672  strcpy(str, "CHAR");
673  break;
674  case NC_SHORT:
675  strcpy(str, "SHORT");
676  break;
677  case NC_INT:
678  strcpy(str, "INT");
679  break;
680  case NC_FLOAT:
681  strcpy(str, "FLOAT");
682  break;
683  case NC_DOUBLE:
684  strcpy(str, "DOUBLE");
685  break;
686  default:
687  strcpy(str, "");
688  break;
689  }
690 }
691 /* *********************************************************** */
692 int openfiles(nccmpopts* opts, int *ncid1, int *ncid2)
693 {
694  int status;
695 
696  status = nc_open(opts->file1, NC_NOWRITE, ncid1);
698 
699  status = nc_open(opts->file2, NC_NOWRITE, ncid2);
701 
702  return 0;
703 }
704 /* *********************************************************** */
705 /* Compares record names and lengths. */
706 int
707 nccmprecinfo(nccmpopts* opts, int ncid1, int ncid2)
708 {
709  char name1[256], name2[256];
710  int status;
711 
713 
714  if (opts->verbose)
715  printf("INFO: Comparing record information.\n");
716 
717  status = nc_inq_unlimdim(ncid1, &recid1);
719 
720  if (recid1 != -1) {
721  status = nc_inq_dim(ncid1, recid1, name1, &nrec1);
723  } else {
724  nrec1 = 0;
725  }
726 
727  status = nc_inq_unlimdim(ncid2, &recid2);
729 
730  if (recid2 != -1) {
731  status = nc_inq_dim(ncid2, recid2, name2, &nrec2);
733  } else {
734  nrec2 = 0;
735  }
736 
737  if (instringlist(opts->excludelist, name1, opts->nexclude) ||
738  instringlist(opts->excludelist, name2, opts->nexclude) ||
739  !instringlist(opts->variablelist, name1, opts->nvariable) ||
740  !instringlist(opts->variablelist, name2, opts->nvariable))
741  return EXIT_SUCCESS;
742 
743  if (strcmp(name1, name2)) {
744  fprintf(stderr, "DIFFER : NAMES OF RECORDS : %s <> %s\n", name1, name2);
745  if (!opts->warn[NCCMP_W_ALL])
747 
748  if(!opts->force) return status;
749  }
750 
751  if (nrec1 != nrec2) {
752  fprintf(stderr, "DIFFER : LENGTHS OF RECORDS : %s (%d) <> %s (%d)\n", name1, (int)nrec1, name2, (int)nrec2);
753  if (!opts->warn[NCCMP_W_ALL])
755 
756  if(!opts->force) return status;
757  }
758 
759  return status;
760 }
761 
762 int getgroupinfo (int ncid, int numgroups,GROUP_NODE *groups) {
763  int *gids;
764  int res, i;
765 
766  gids = malloc(sizeof(int) * numgroups);
767  res = nc_inq_grps(ncid, NULL, gids);
768 
769  for (i=0; i<numgroups; i++){
770  groups[i].groupID = gids[i];
771  nc_inq_grpname(gids[i],groups[i].groupName);
772  }
773  return numgroups;
774 }
775 
776 /* *********************************************************** */
777 /* Get dim info for file. */
778 void getdiminfo(int ncid, dimstruct* dims, int* ndims)
779 {
780  int status, i;
781 
782  status = nc_inq_ndims(ncid, ndims);
784 
785  // Query all dimids, which may not be from 0..N-1 in a HDF file.
786  int dimids[(int)NC_MAX_DIMS];
787  int include_parents = 1;
788  status = nc_inq_dimids(ncid, ndims, dimids, include_parents);
790 
791  for(i=0; i < *ndims; ++i) {
792  dims[i].dimid = dimids[i];
793  status = nc_inq_dim(ncid, dimids[i], dims[i].name, &dims[i].len);
795  }
796 }
797 /* *********************************************************** */
798 /* Copy attribute type to same type as var, just in case of mismatch. */
799 void broadcast_missing(nc_type var_type, nc_type att_type, missing_struct *values) {
800  #define BROADCAST_MISSING(T) { \
801  switch(att_type) { \
802  case NC_CHAR: values->T = values->c; break; \
803  case NC_BYTE: values->T = values->b; break; \
804  case NC_SHORT: values->T = values->s; break; \
805  case NC_INT: values->T = values->i; break; \
806  case NC_FLOAT: values->T = values->f; break; \
807  case NC_DOUBLE: values->T = values->d; break; \
808  } \
809  }
810 
811  switch(var_type) {
812  case NC_CHAR: BROADCAST_MISSING(c); break;
813  case NC_BYTE: BROADCAST_MISSING(b); break;
814  case NC_SHORT: BROADCAST_MISSING(s); break;
815  case NC_INT: BROADCAST_MISSING(i); break;
816  case NC_FLOAT: BROADCAST_MISSING(f); break;
817  case NC_DOUBLE: BROADCAST_MISSING(d); break;
818  }
819 }
820 /* *********************************************************** */
821 char get_missing(int ncid, varstruct * var, const char* attname) {
822  nc_type att_type;
823  int status;
824 
825  status = nc_inq_atttype(ncid, var->varid, attname, &att_type);
826  if (status != NC_NOERR) return 0;
827 
828  var->missing.type = att_type;
829 
830  switch(att_type) {
831  case NC_CHAR:
832  status = nc_get_att_text(ncid, var->varid, attname, &var->missing.c);
833  if (status != NC_NOERR) return 0;
834  break;
835  case NC_BYTE:
836  status = nc_get_att(ncid, var->varid, attname, &var->missing.b);
837  if (status != NC_NOERR) return 0;
838  break;
839  case NC_SHORT:
840  status = nc_get_att_short(ncid, var->varid, attname, &var->missing.s);
841  if (status != NC_NOERR) return 0;
842  break;
843  case NC_INT:
844  status = nc_get_att_int(ncid, var->varid, attname, &var->missing.i);
845  if (status != NC_NOERR) return 0;
846  break;
847  case NC_FLOAT:
848  status = nc_get_att_float(ncid, var->varid, attname, &var->missing.f);
849  if (status != NC_NOERR) return 0;
850  break;
851  case NC_DOUBLE:
852  status = nc_get_att_double(ncid, var->varid, attname, &var->missing.d);
853  if (status != NC_NOERR) return 0;
854  break;
855  default: return 0;
856  }
857 
858  var->hasmissing = 1;
859  broadcast_missing(var->type, att_type, &var->missing);
860 
861  return 1;
862 }
863 /* *****************************s****************************** */
864 /* Read all the file's metadata for variables. */
865 void getvarinfo(int ncid, varstruct* vars, int* nvars, int verbose)
866 {
867  int status, i, j, recid;
868  char name[NC_MAX_NAME];
869  nc_type att_type;
870 
871  status = nc_inq_nvars(ncid, nvars);
873 
874  status = nc_inq_unlimdim(ncid, &recid);
876 
877  for(i=0; i < *nvars; ++i) {
878  vars[i].varid = i;
879 
880  status = nc_inq_var(ncid, i, vars[i].name, &vars[i].type,
881  &vars[i].ndims, vars[i].dimids, &vars[i].natts);
883 
884  vars[i].len = 1;
885  for(j=0; j < vars[i].ndims; ++j) {
886  status = nc_inq_dimlen(ncid, vars[i].dimids[j], &vars[i].dimlens[j]);
888 #ifdef __DEBUG__
889  printf("DEBUG : %d : %s dimid %d, len %d\n", __LINE__, vars[i].name, j, vars[i].dimlens[j]);
890 #endif
891  vars[i].len *= vars[i].dimlens[j];
892  }
893 
894  vars[i].hasrec = (vars[i].dimids[0] == recid);
895 
896  /* Get missing_value or _FillValue. */
897  if (get_missing(ncid, &vars[i], "missing_value") == 0)
898  get_missing(ncid, &vars[i], "_FillValue");
899 
900  if (verbose) {
901  if (vars[i].hasmissing) {
902  printf("INFO: \"%s\" missing value: ", vars[i].name);
903  switch(vars[i].missing.type) {
904  case NC_BYTE: printf("%d (byte)\n", vars[i].missing.b); break;
905  case NC_CHAR: printf("%d (char)\n", vars[i].missing.c); break;
906  case NC_SHORT: printf("%d (short)\n", vars[i].missing.s); break;
907  case NC_INT: printf("%d (int)\n", vars[i].missing.i); break;
908  case NC_FLOAT: printf("%g (float)\n", vars[i].missing.f); break;
909  case NC_DOUBLE: printf("%g (double)\n", vars[i].missing.d); break;
910  }
911  }
912  }
913  }
914 }
915 /* *********************************************************** */
916 /* Returns index to varstruct in list, otherwise -1. */
917 int isinvarstructlist(char* name, varstruct* vars, int nvars)
918 {
919  int i;
920 
921  for(i=0; i < nvars; ++i) {
922  if (strcmp(name, vars[i].name) == 0)
923  return i;
924  }
925 
926  return -1;
927 }
928 /* *********************************************************** */
929 /* Get vars to use to do cmp based on input and exclusion lists. */
930 int makecmpvarlist(nccmpopts* opts, int ncid1, int ncid2)
931 {
932  int status, i;
933 
934  newstringlist(&opts->cmpvarlist, &opts->ncmpvarlist, (int)NC_MAX_VARS);
935  if(opts->variable) {
936  if (opts->verbose)
937  printf("INFO: Using variables provided in list.\n");
938 
939  status = strlistu(opts->variablelist, opts->cmpvarlist, opts->cmpvarlist,
940  opts->nvariable, opts->ncmpvarlist, opts->ncmpvarlist);
941  } else if (opts->exclude) {
942  if (opts->verbose)
943  printf("INFO: Excluding variables in provided list.\n");
944 
945  status = excludevars(ncid1, ncid2, opts->cmpvarlist, opts->ncmpvarlist, opts->excludelist, opts->nexclude);
946  } else {
947  if (opts->verbose)
948  printf("INFO: Using all variables.\n");
949 
950  status = allvarnames(opts->cmpvarlist, opts->ncmpvarlist, ncid1, ncid2);
951  }
952 
953  opts->ncmpvarlist = getnumstrlist(opts->cmpvarlist, (int)NC_MAX_VARS);
954  if (opts->verbose) {
955  printf("INFO: Variables to compare (%d):\n", opts->ncmpvarlist);
956  for(i=0; i < opts->ncmpvarlist-1; ++i)
957  printf("%s, ", opts->cmpvarlist[i]);
958 
959  if (opts->ncmpvarlist)
960  printf("%s\n", opts->cmpvarlist[i]);
961  }
962 
963  return status;
964 }
965 /* *********************************************************** */
966 /* Gets list of all variable names in both input files. */
967 int
968 allvarnames(char** list, int nvars, int ncid1, int ncid2)
969 {
970  char** tmplist = NULL;
971  int ntmp;
972 
973  newstringlist(&tmplist, &ntmp, NC_MAX_VARS);
974 
975  if( ncallvars(ncid1, tmplist, ntmp) )
976  return 1;
977 
978  /* printf("%d: ncallvars returned.\n", __LINE__); */
979 
980  if( strlistu(tmplist, list, list, ntmp, nvars, nvars) )
981  return 1;
982 
983  /* printf("%d: Variable names from file 1 collected.\n", __LINE__); */
984  clearstringlist(tmplist, NC_MAX_VARS);
985 
986  if( ncallvars(ncid2, tmplist, ntmp) )
987  return 1;
988 
989  if( strlistu(tmplist, list, list, ntmp, nvars, nvars) )
990  return 1;
991 
992  /* printf("%d: Variable names from file 2 collected.\n", __LINE__); */
993  freestringlist(&tmplist, ntmp);
994 
995  return EXIT_SUCCESS;
996 }
997 /* *********************************************************** */
998 
999 int
1000 nccmpformats(nccmpopts* opts, int ncid1, int ncid2)
1001 {
1002  int status, fmt1, fmt2;
1003 
1004  status = nc_inq_format(ncid1, &fmt1);
1006 
1007  status = nc_inq_format(ncid2, &fmt2);
1009 
1010  if (fmt1 != fmt2) {
1011  fprintf(stderr, "DIFFER : FILE FORMATS : %s <> %s\n", NCFORMATSTR(fmt1), NCFORMATSTR(fmt2));
1012 
1013  if (!opts->warn[NCCMP_W_ALL] &&
1014  !opts->warn[NCCMP_W_FORMAT])
1015  return EXIT_DIFFER;
1016  }
1017 
1018  return EXIT_SUCCESS;
1019 }
1020 /* *********************************************************** */
1021 
1022 int
1023 nccmpglobalatts(nccmpopts* opts, int ncid1, int ncid2)
1024 {
1025  int ngatts1, ngatts2, nattsex1, nattsex2, i, status, status2, attid1, attid2, nprocessedatts;
1026  nc_type type1, type2;
1027  size_t len1, len2;
1028  char name1[NC_MAX_NAME], name2[NC_MAX_NAME];
1029  char** processedatts = NULL;
1030  char typestr1[1024], typestr2[1024];
1031 
1032  status = EXIT_SUCCESS;
1033  status2 = status;
1034  if (!opts->global)
1035  return status;
1036 
1037  if (opts->history == 0)
1038  appendstringtolist(&opts->globalexclude, "history", &opts->nglobalexclude);
1039 
1040  /*
1041  printf("globalexclude =");
1042  printstrlist(opts->globalexclude, opts->nglobalexclude, stdout);
1043  */
1044 
1045  /* Number of global atts to compare with exclusion taken into account. */
1046  nattsex1 = 0;
1047  nattsex2 = 0;
1048 
1049  status = nc_inq_natts(ncid1, &ngatts1);
1051 
1052  status = nc_inq_natts(ncid2, &ngatts2);
1054 
1055  for(i = 0; i < ngatts1; ++i) {
1056  attid1 = i;
1057  status = nc_inq_attname(ncid1, NC_GLOBAL, attid1, name1);
1059 
1060  if (!instringlist(opts->globalexclude, name1, opts->nglobalexclude)) {
1061  ++nattsex1;
1062  }
1063  }
1064 
1065  for(i = 0; i < ngatts2; ++i) {
1066  attid2 = i;
1067  status = nc_inq_attname(ncid2, NC_GLOBAL, attid2, name2);
1069 
1070  if (!instringlist(opts->globalexclude, name2, opts->nglobalexclude)) {
1071  ++nattsex2;
1072  }
1073  }
1074 
1075  if(nattsex1 != nattsex2) {
1076  fprintf(stderr, "DIFFER : NUMBER OF GLOBAL ATTRIBUTES : %d <> %d\n", nattsex1, nattsex2);
1077 
1078  if (!opts->warn[NCCMP_W_ALL])
1079  status2 = EXIT_DIFFER;
1080 
1081  if(!opts->force) return status2;
1082  }
1083 
1084  if(newstringlist(&processedatts, &i, NC_MAX_VARS)) {
1085  fprintf(stderr, "ERROR: Failed to allocated string list for comparing global attributes.\n");
1086  return EXIT_FATAL;
1087  }
1088 
1089  for(i = 0; i < ngatts1; ++i) {
1090  attid1 = i;
1091  status = nc_inq_attname(ncid1, NC_GLOBAL, attid1, name1);
1093 
1094  /* Log that this gatt was processed. */
1095  addstringtolist(processedatts, name1, NC_MAX_VARS);
1096 
1097  if (instringlist(opts->globalexclude, name1, opts->nglobalexclude))
1098  continue;
1099 
1100  status = nc_inq_att(ncid1, NC_GLOBAL, name1, &type1, &len1);
1101  if (status != NC_NOERR) {
1102  fprintf(stderr, "Query failed on global attribute in %s\n", opts->file1);
1103  if (!opts->warn[NCCMP_W_ALL])
1104  status2 = EXIT_DIFFER;
1105 
1106  if(opts->force) continue; else return status2;
1107  }
1108 
1109  status = nc_inq_att(ncid2, NC_GLOBAL, name1, &type2, &len2);
1110  if (status != NC_NOERR) {
1111  fprintf(stderr, "DIFFER : NAME OF GLOBAL ATTRIBUTE : %s : GLOBAL ATTRIBUTE DOESN'T EXIST IN \"%s\"\n", name1, opts->file2);
1112  if (!opts->warn[NCCMP_W_ALL])
1113  status2 = EXIT_DIFFER;
1114 
1115  if(opts->force) continue; else return status2;
1116  }
1117 
1118  if (type1 != type2) {
1119  type2string(type1, typestr1);
1120  type2string(type2, typestr2);
1121  fprintf(stderr, "DIFFER : GLOBAL ATTRIBUTE TYPES : %s : %s <> %s\n", name1, typestr1, typestr2);
1122  if (!opts->warn[NCCMP_W_ALL])
1123  status2 = EXIT_DIFFER;
1124 
1125  if(opts->force) continue; else return status2;
1126  }
1127 
1128  if (len1 != len2) {
1129  prettyprintatt(ncid1, NULL, NC_GLOBAL, name1, typestr1);
1130  prettyprintatt(ncid2, NULL, NC_GLOBAL, name1, typestr2);
1131  fprintf(stderr, "DIFFER : LENGTHS OF GLOBAL ATTRIBUTE : %s : %lu <> %lu : VALUES : %s <> %s\n", name1,
1132  (unsigned long)len1, (unsigned long)len2, typestr1, typestr2);
1133  if (!opts->warn[NCCMP_W_ALL])
1134  status2 = EXIT_DIFFER;
1135 
1136  if(opts->force) continue; else return status2;
1137  }
1138 
1139  if (cmpattval(ncid1,ncid2,NC_GLOBAL,NC_GLOBAL,name1,len1,type1) != NC_NOERR) {
1140  /* Pretty print values. */
1141  prettyprintatt(ncid1, NULL, NC_GLOBAL, name1, typestr1);
1142  prettyprintatt(ncid2, NULL, NC_GLOBAL, name1, typestr2);
1143  fprintf(stderr, "DIFFER : VALUES OF GLOBAL ATTRIBUTE : %s : %s <> %s\n", name1, typestr1, typestr2);
1144  if (!opts->warn[NCCMP_W_ALL])
1145  status2 = EXIT_DIFFER;
1146 
1147  if(opts->force) continue; else return status2;
1148  }
1149  }
1150 
1151  for(i = 0; i < ngatts2; ++i) {
1152  attid2 = i;
1153  status = nc_inq_attname(ncid2, NC_GLOBAL, attid2, name2);
1154  if (status != NC_NOERR) {
1155  fprintf(stderr, "Query failed for global attribute name in %s\n", opts->file2);
1156  if (!opts->warn[NCCMP_W_ALL])
1157  status2 = EXIT_DIFFER;
1158 
1159  if(opts->force) continue; else return status2;
1160  }
1161 
1162  /* Skip if already processed (or excluded). */
1163  if (instringlist(processedatts, name2, NC_MAX_VARS))
1164  continue;
1165 
1166  /* Log that this att was processed. */
1167  addstringtolist(processedatts, name2, NC_MAX_VARS);
1168 
1169  status = nc_inq_att(ncid2, NC_GLOBAL, name2, &type2, &len2);
1170  if (status != NC_NOERR) {
1171  fprintf(stderr, "Query failed on global attribute in %s\n", opts->file2);
1172  if (!opts->warn[NCCMP_W_ALL])
1173  status2 = EXIT_DIFFER;
1174 
1175  if(opts->force) continue; else return status2;
1176  }
1177 
1178  status = nc_inq_att(ncid1, NC_GLOBAL, name2, &type1, &len1);
1179  if (status != NC_NOERR) {
1180  fprintf(stderr, "DIFFER : NAME OF GLOBAL ATTRIBUTE : %s : GLOBAL ATTRIBUTE DOESN'T EXIST IN %s\n", name2, opts->file1);
1181  if (!opts->warn[NCCMP_W_ALL])
1182  status2 = EXIT_DIFFER;
1183 
1184  if(opts->force) continue; else return status2;
1185  }
1186 
1187  if (type1 != type2) {
1188  type2string(type1, typestr1);
1189  type2string(type2, typestr2);
1190  fprintf(stderr, "DIFFER : GLOBAL ATTRIBUTE TYPE : %s : %s <> %s\n", name1, typestr1, typestr2);
1191  if (!opts->warn[NCCMP_W_ALL])
1192  status2 = EXIT_DIFFER;
1193 
1194  if(opts->force) continue; else return status2;
1195  }
1196 
1197  if (len1 != len2) {
1198  prettyprintatt(ncid1, NULL, NC_GLOBAL, name1, typestr1);
1199  prettyprintatt(ncid2, NULL, NC_GLOBAL, name1, typestr2);
1200 
1201  fprintf(stderr, "DIFFER : LENGTHS OF GLOBAL ATTRIBUTE : %s : %lu <> %lu : VALUES : ", name1, (unsigned long)len1, (unsigned long)len2);
1202 
1203  switch(type1) {
1204  case NC_CHAR:
1205  /* Quote strings. */
1206  fprintf(stderr, "\"%s\" : \"%s\"\n", typestr1, typestr2);
1207  if (strcmp(typestr1,typestr2) == 0) {
1208  /* Same text, but invisible trailing nulls because lengths differ. */
1209  if (opts->warn[NCCMP_W_EOS] || opts->warn[NCCMP_W_ALL]) {
1210  /* Pass */
1211  } else {
1212  status2 = EXIT_DIFFER;
1213  if(opts->force) continue; else return status2;
1214  }
1215  }
1216  break;
1217  default:
1218  /* No quotes. */
1219  fprintf(stderr, "%s : %s\n", typestr1, typestr2);
1220  if (!opts->warn[NCCMP_W_ALL]) {
1221  status2 = EXIT_DIFFER;
1222  if(opts->force) continue; else return status2;
1223  }
1224  break;
1225  }
1226  }
1227 
1228  if (cmpattval(ncid1,ncid2,NC_GLOBAL,NC_GLOBAL,name1,len1,type1) != NC_NOERR) {
1229  /* Pretty print values. */
1230  prettyprintatt(ncid1, NULL, NC_GLOBAL, name1, typestr1);
1231  prettyprintatt(ncid2, NULL, NC_GLOBAL, name1, typestr2);
1232  fprintf(stderr, "DIFFER : VALUES OF GLOBAL ATTRIBUTE : %s : %s <> %s\n", name1, typestr1, typestr2);
1233  if (!opts->warn[NCCMP_W_ALL])
1234  status2 = EXIT_DIFFER;
1235 
1236  if(opts->force) continue; else return status2;
1237  }
1238  }
1239 
1240  /* Clear the list. */
1241  freestringlist(&processedatts, NC_MAX_VARS);
1242  processedatts = NULL;
1243 
1244  return status2;
1245 }
1246 /* *********************************************************** */
1247 int
1248 nccmpmetadata(nccmpopts *opts, int ncid1, int ncid2)
1249 {
1250  int i, j, j1, j2, status, ncstatus, dimid1, dimid2, tmp1, tmp2, attid1, attid2, natts1, natts2;
1251  size_t len1, len2;
1252  char name1[NC_MAX_NAME], name2[NC_MAX_NAME], recname1[NC_MAX_NAME], recname2[NC_MAX_NAME], typestr1[1024], typestr2[1024];
1253  char** processedatts = NULL;
1254 
1255  status = EXIT_SUCCESS;
1256 
1257  if (opts->verbose)
1258  printf("INFO: Comparing metadata.\n");
1259 
1260  if (opts->verbose)
1261  printf("INFO: Comparing number of dimensions.\n");
1262 
1263  if (ndims1 != ndims2) {
1264  fprintf(stderr, "DIFFER : NUMBER OF DIMENSIONS IN FILES : %d <> %d\n", ndims1, ndims2);
1265  if (!opts->warn[NCCMP_W_ALL])
1266  status = EXIT_DIFFER;
1267 
1268  if (!opts->force)
1269  return status;
1270  }
1271 
1272  if (opts->verbose)
1273  printf("INFO: Getting record dimension names, if they exist.\n");
1274 
1275  if (recid1 != -1) {
1276  ncstatus = nc_inq_dimname(ncid1, recid1, recname1);
1277  handle_error(ncstatus);
1278  } else
1279  strcpy(recname1, "");
1280 
1281  if (recid2 != -1) {
1282  ncstatus = nc_inq_dimname(ncid2, recid2, recname2);
1283  handle_error(ncstatus);
1284  } else
1285  strcpy(recname1, "");
1286 
1287  /* Dimensions */
1288  if (opts->verbose)
1289  printf("INFO: Comparing dimension lengths.\n");
1290 
1291  for(i = 0; i < ndims1; ++i) {
1292  dimid1 = dims1[i].dimid;
1293  ncstatus = nc_inq_dim(ncid1, dimid1, name1, &len1);
1294  if (ncstatus != NC_NOERR) {
1295  if (!opts->warn[NCCMP_W_ALL])
1296  status = EXIT_DIFFER;
1297 
1298  fprintf(stderr, "Failed to query dimension id %d in file %s.\n", dimid1, opts->file1);
1299  if(opts->force) continue; else return status;
1300  }
1301 
1302  ncstatus = nc_inq_dimid(ncid2, name1, &dimid2);
1303  if (ncstatus != NC_NOERR) {
1304  fprintf(stderr, "DIFFER : NAME : DIMENSION : %s : DIMENSION DOESN'T EXIST IN \"%s\"\n", name1, opts->file2);
1305 
1306  if (!opts->warn[NCCMP_W_ALL])
1307  status = EXIT_DIFFER;
1308 
1309  if(opts->force) continue; else return status;
1310  }
1311 
1312  ncstatus = nc_inq_dim(ncid2, dimid2, name2, &len2);
1313  if (ncstatus != NC_NOERR) {
1314  if (!opts->warn[NCCMP_W_ALL])
1315  status = EXIT_DIFFER;
1316 
1317  fprintf(stderr, "Failed to query dimension \"%s\" in file \"%s\".\n", name1, opts->file2);
1318  if(opts->force) continue; else return status;
1319  }
1320 
1321  if (len1 != len2) {
1322  fprintf(stderr, "DIFFER : LENGTHS : DIMENSION : %s : %lu <> %lu\n", name1,
1323  (unsigned long)len1, (unsigned long)len2);
1324 
1325  if (!opts->warn[NCCMP_W_ALL])
1326  status = EXIT_DIFFER;
1327 
1328  if(opts->force) continue; else return status;
1329  }
1330  }
1331 
1332  /* Variables */
1333  if (opts->verbose)
1334  printf("INFO: Comparing variable datatypes and rank.\n");
1335 
1336  for(i=0; i < opts->ncmpvarlist; ++i) {
1337  j1 = findvar(opts->cmpvarlist[i], vars1);
1338  if (j1 == -1) {
1339  fprintf(stderr, "DIFFER : NAME : VARIABLE : %s : VARIABLE DOESN'T EXIST IN \"%s\"\n", opts->cmpvarlist[i], opts->file1);
1340 
1341  if (!opts->warn[NCCMP_W_ALL])
1342  status = EXIT_DIFFER;
1343 
1344  if(opts->force) continue; else goto recover;
1345  }
1346 
1347  j2 = findvar(opts->cmpvarlist[i], vars2);
1348  if (j2 == -1) {
1349  fprintf(stderr, "DIFFER : NAME : VARIABLE : %s : VARIABLE DOESN'T EXIST IN \"%s\"\n", opts->cmpvarlist[i], opts->file2);
1350 
1351  if (!opts->warn[NCCMP_W_ALL])
1352  status = EXIT_DIFFER;
1353 
1354  if(opts->force) continue; else goto recover;
1355  }
1356 
1357  if(vars1[j1].type != vars2[j2].type) {
1358  type2string(vars1[j1].type, typestr1);
1359  type2string(vars2[j2].type, typestr2);
1360  fprintf(stderr, "DIFFER : TYPES : VARIABLE : %s : %s <> %s\n", opts->cmpvarlist[i], typestr1, typestr2);
1361 
1362  if (!opts->warn[NCCMP_W_ALL])
1363  status = EXIT_DIFFER;
1364 
1365  if(opts->force) continue; else goto recover;
1366  }
1367 
1368  if(vars1[j1].ndims != vars2[j2].ndims) {
1369  fprintf(stderr, "DIFFER : NUMBER : DIMENSIONS : VARIABLE : %s : %d <> %d\n", opts->cmpvarlist[i], ndims1, ndims2);
1370 
1371  if (!opts->warn[NCCMP_W_ALL])
1372  status = EXIT_DIFFER;
1373 
1374  if(opts->force) continue; else goto recover;
1375  }
1376  }
1377 
1378  /*printf("DEBUG : %d : \n", __LINE__);*/
1379  if (opts->verbose)
1380  printf("INFO: Comparing variables' dimension names.\n");
1381 
1382  for(i=0; i < opts->ncmpvarlist; ++i) {
1383  j1 = findvar(opts->cmpvarlist[i], vars1);
1384  j2 = findvar(opts->cmpvarlist[i], vars2);
1385 
1386  if ((j1 == -1) || (j2 == -1))
1387  continue;
1388 
1389  /* dimensions */
1390  for(j = 0; j < vars1[j1].ndims; ++j) {
1391  dimid1 = vars1[j1].dimids[j];
1392 
1393  if (j < vars2[j2].ndims)
1394  dimid2 = vars2[j2].dimids[j];
1395  else
1396  break;
1397 
1398  /*printf("DEBUG : %d : %s, %s, %s\n", __LINE__, opts->cmpvarlist[i], dims1[dimid1].name, dims2[dimid2].name);*/
1399 
1400  if (strcmp(dims1[dimid1].name, dims2[dimid2].name) != 0) {
1401  fprintf(stderr, "DIFFER : DIMENSION NAMES FOR VARIABLE %s : %s <> %s\n", opts->cmpvarlist[i], dims1[dimid1].name, dims2[dimid2].name);
1402 
1403  if (!opts->warn[NCCMP_W_ALL])
1404  status = EXIT_DIFFER;
1405 
1406  if(opts->force) continue; else goto recover;
1407  }
1408 
1409  tmp1 = strcmp(dims1[dimid1].name, recname1);
1410  tmp2 = strcmp(dims2[dimid2].name, recname2);
1411 
1412  if ( (tmp1 == 0) && (tmp2 != 0) ) {
1413  fprintf(stderr, "DIFFER : VARIABLE : %s : DIMENSION %s IS RECORD IN FILE \"%s\" BUT NOT IN \"%s\"\n", vars1[j1].name, dims1[dimid1].name, opts->file1, opts->file2);
1414 
1415  if (!opts->warn[NCCMP_W_ALL])
1416  status = EXIT_DIFFER;
1417 
1418  if(opts->force) continue; else goto recover;
1419  } else if ( (tmp1 != 0) && (tmp2 == 0) ) {
1420  fprintf(stderr, "DIFFER : VARIABLE : %s : DIMENSION %s IS RECORD IN FILE \"%s\" BUT NOT IN \"%s\"\n", vars1[j1].name, dims2[dimid2].name, opts->file2, opts->file1);
1421 
1422  if (!opts->warn[NCCMP_W_ALL])
1423  status = EXIT_DIFFER;
1424 
1425  if(opts->force) continue; else goto recover;
1426  }
1427  }
1428  }
1429 
1430  if (opts->verbose)
1431  printf("INFO: Comparing variables' attributes.\n");
1432 
1433  /*printf("DEBUG : %d : \n", __LINE__);*/
1434  /* Pass in 'i' as dummy. */
1435  if (newstringlist(&processedatts, &i, NC_MAX_VARS)) {
1436  fprintf(stderr, "ERROR: Failed to allocate string list for comparing attributes.\n");
1437  return EXIT_FATAL;
1438  }
1439  /*printf("DEBUG : %d : \n", __LINE__); fflush(stdout);*/
1440 
1441  for(i=0; i < opts->ncmpvarlist; ++i) {
1442  /*printf("DEBUG : %d : i = %d\n", __LINE__, i); fflush(stdout);*/
1443  j1 = findvar(opts->cmpvarlist[i], vars1);
1444  j2 = findvar(opts->cmpvarlist[i], vars2);
1445 
1446  if ((j1 == -1) || (j2 == -1))
1447  continue;
1448 
1449  natts1 = natts2 = 0;
1450  clearstringlist(processedatts, NC_MAX_VARS);
1451 
1452  /*printf("DEBUG : %d : var=%s\n", __LINE__, opts->cmpvarlist[i]); fflush(stdout);*/
1453 
1454  /* Attributes */
1455  for(attid1=0; attid1 < vars1[j1].natts; ++attid1) {
1456  ncstatus = nc_inq_attname(ncid1, vars1[j1].varid, attid1, name1);
1457  if (ncstatus != NC_NOERR) {
1458  if (!opts->warn[NCCMP_W_ALL])
1459  status = EXIT_DIFFER;
1460 
1461  if(opts->force) continue; else goto recover;
1462  }
1463 
1464  if (instringlist(opts->excludeattlist, name1, opts->nexcludeatt) || instringlist(processedatts, name1, NC_MAX_VARS))
1465  continue;
1466 
1467  /* Log that this att was processed. */
1468  addstringtolist(processedatts, name1, NC_MAX_VARS);
1469  ++natts1;
1470  /*printf("natts1 %s, %d\n", name1, natts1);*/
1471  ncstatus = cmpatt(ncid1, ncid2, vars1[j1].varid, vars2[j2].varid, name1, vars1[j1].name, opts);
1472  if (ncstatus == EXIT_DIFFER) {
1473  status = ncstatus;
1474  if(opts->force) continue; else goto recover;
1475  }
1476  }
1477 
1478  /*printf("DEBUG : %d : \n", __LINE__);*/
1479  for(attid2=0; attid2 < vars2[j2].natts; ++attid2) {
1480  ncstatus = nc_inq_attname(ncid2, vars2[j2].varid, attid2, name2);
1481  if (ncstatus != NC_NOERR) {
1482  fprintf(stderr, "Failed to query variable %s attribute in file \"%s\"\n", vars2[j2].name, opts->file2);
1483 
1484  if (!opts->warn[NCCMP_W_ALL])
1485  status = EXIT_DIFFER;
1486 
1487  if(opts->force) continue; else goto recover;
1488  }
1489 
1490  if (instringlist(opts->excludeattlist, name2, opts->nexcludeatt))
1491  continue;
1492 
1493  /* Count non-excluded attribute. */
1494  ++natts2;
1495  /*printf("natts2 %s, %d\n", name2, natts2);*/
1496  if (instringlist(processedatts, name2, NC_MAX_VARS))
1497  continue;
1498 
1499  /* Log that this att was processed. */
1500  addstringtolist(processedatts, name2, NC_MAX_VARS);
1501 
1502  /* Do comparison. */
1503  ncstatus = cmpatt(ncid1, ncid2, vars1[j1].varid, vars2[j2].varid, name2, vars2[j2].name, opts);
1504  if (ncstatus == EXIT_DIFFER) {
1505  status = ncstatus;
1506  if(opts->force) continue; else goto recover;
1507  }
1508  }
1509 
1510  if(natts1 != natts2) {
1511  fprintf(stderr, "DIFFER : NUMBER OF ATTRIBUTES : VARIABLE : %s : %d <> %d\n", opts->cmpvarlist[i], natts1, natts2);
1512  if (!opts->warn[NCCMP_W_ALL])
1513  status = EXIT_DIFFER;
1514 
1515  if(opts->force) continue; else goto recover;
1516  }
1517  }
1518 
1519  recover:
1520  freestringlist(&processedatts, NC_MAX_VARS);
1521  processedatts = NULL;
1522 
1523  return status;
1524 }
1525 /* *********************************************************** */
1526 /* Returns index into varstruct array if found using name otherwise -1. */
1527 int findvar(char * name, varstruct *vars)
1528 {
1529  int i;
1530  for(i=0; i < NC_MAX_VARS; ++i) {
1531  if (strcmp(name, vars[i].name) == 0)
1532  return i;
1533  }
1534 
1535  return -1;
1536 }
1537 /* *********************************************************** */
1538 /* Element compare and return first offset that differs.
1539  Arrays should have sentinals at end that are guaranteed to differ.
1540 */
1541 off_t cmp_text(char* in1, char* in2) {
1542  char const *p1, *p2;
1543  for(p1 = in1, p2 = in2; *p1 == *p2; ++p1, ++p2)
1544  continue;
1545  return p1 - in1;
1546 }
1547 off_t cmp_text_missing(char* in1, char* in2, char m1, char m2) {
1548  char const *p1, *p2;
1549  for(p1 = in1, p2 = in2; (*p1 == *p2) || ((*p1 == m1) && (*p2 == m2)); ++p1, ++p2)
1550  continue;
1551  return p1 - in1;
1552 }
1553 off_t cmp_byte(int8_t* in1, int8_t* in2) {
1554  int8_t const *p1, *p2;
1555  for(p1 = in1, p2 = in2; *p1 == *p2; ++p1, ++p2)
1556  continue;
1557  return p1 - in1;
1558 }
1559 off_t cmp_byte_missing(int8_t* in1, int8_t* in2, int8_t m1, int8_t m2) {
1560  int8_t const *p1, *p2;
1561  for(p1 = in1, p2 = in2; (*p1 == *p2) || ((*p1 == m1) && (*p2 == m2)); ++p1, ++p2)
1562  continue;
1563  return p1 - in1;
1564 }
1565 off_t cmp_short(short* in1, short* in2) {
1566  short const *p1, *p2;
1567  for(p1 = in1, p2 = in2; *p1 == *p2; ++p1, ++p2)
1568  continue;
1569  return p1 - in1;
1570 }
1571 off_t cmp_short_missing(short* in1, short* in2, short m1, short m2) {
1572  short const *p1, *p2;
1573  for(p1 = in1, p2 = in2; (*p1 == *p2) || ((*p1 == m1) && (*p2 == m2)); ++p1, ++p2)
1574  continue;
1575  return p1 - in1;
1576 }
1577 off_t cmp_int(int* in1, int* in2) {
1578  int const *p1, *p2;
1579  for(p1 = in1, p2 = in2; *p1 == *p2; ++p1, ++p2)
1580  continue;
1581  return p1 - in1;
1582 }
1583 off_t cmp_int_missing(int* in1, int* in2, int m1, int m2) {
1584  int const *p1, *p2;
1585  for(p1 = in1, p2 = in2; (*p1 == *p2) || ((*p1 == m1) && (*p2 == m2)); ++p1, ++p2)
1586  continue;
1587  return p1 - in1;
1588 }
1589 off_t cmp_float(float* in1, float* in2) {
1590  float const *p1, *p2;
1591  for(p1 = in1, p2 = in2; fabs(*p1 - *p2)< FLT_EPSILON; ++p1, ++p2)
1592  continue;
1593  return p1 - in1;
1594 }
1595 off_t cmp_float_missing(float* in1, float* in2, float m1, float m2) {
1596  float const *p1, *p2;
1597  for(p1 = in1, p2 = in2; (fabs(*p1 - *p2)< FLT_EPSILON) || ((fabs(*p1 - m1)< FLT_EPSILON) && (fabs(*p2 - m2)< FLT_EPSILON)); ++p1, ++p2)
1598  continue;
1599  return p1 - in1;
1600 }
1601 off_t cmp_double(double* in1, double* in2) {
1602  double const *p1, *p2;
1603  for(p1 = in1, p2 = in2; fabs(*p1 - *p2)< DBL_EPSILON; ++p1, ++p2)
1604  continue;
1605  return p1 - in1;
1606 }
1607 off_t cmp_double_missing(double* in1, double* in2, double m1, double m2) {
1608  double const *p1, *p2;
1609  for(p1 = in1, p2 = in2; (fabs(*p1 - *p2)< DBL_EPSILON) || ((fabs(*p1 - m1)< DBL_EPSILON) && (fabs(*p2 - m2)< DBL_EPSILON)); ++p1, ++p2)
1610  continue;
1611  return p1 - in1;
1612 }
1613 
1614 /* *********************************************************** */
1615 /* Do the comparision of variables.
1616  Record index (rec) is optional; -1 if not applicable.
1617  Returns comparison result success or failure.
1618 */
1619 int cmpvar(char* name, int rec, nccmpopts* opts, int ncid1, int ncid2)
1620 {
1621  int8_t *b1,*b2;
1622  char *c1,*c2;
1623  short *s1,*s2;
1624  int *i1,*i2;
1625  float *f1,*f2;
1626  double *d1,*d2;
1627  varstruct *v1,*v2;
1628  int idx1, idx2, status, i;
1629  size_t start[NC_MAX_DIMS], count[NC_MAX_DIMS];
1630  char tmpstr1[256], tmpstr2[256], idxstr[256];
1631  off_t nitems, diff, cmplen;
1632  size_t odomax[NC_MAX_DIMS];
1633  int diffstatus = EXIT_SUCCESS;
1634  char *message = "DIFFER : VARIABLE : %s : POSITION : %s : VALUES : %s <> %s\n";
1635  char value1str[32], value2str[32];
1636  double doublevalue1, doublevalue2;
1637  int intvalue1, intvalue2;
1638  short shortvalue1, shortvalue2;
1639  float floatvalue1, floatvalue2;
1640  char textvalue1, textvalue2;
1641  int8_t bytevalue1, bytevalue2;
1642  char printHex = strchr(opts->precision, 'X') || strchr(opts->precision, 'x');
1643  char do_missing = 0;
1644 
1645  if (opts->verbose) {
1646  if (rec != -1)
1647  printf("INFO: Comparing data for variable \"%s\" at record %d.\n", name, (int)rec);
1648  else
1649  printf("INFO: Comparing non-record data for variable \"%s\".\n", name);
1650  }
1651 
1652  idx1 = findvar(name, vars1);
1653  idx2 = findvar(name, vars2);
1654 
1655  v1 = &vars1[idx1];
1656  v2 = &vars2[idx2];
1657 
1658  /* Setup missing mode. */
1659  if (opts->missing && v1->hasmissing && v2->hasmissing) {
1660  do_missing = 1;
1661  }
1662 
1663  /*printf("DEBUG : %s len : %d <> %d\n", name, v1->len, v2->len); */
1664 
1665  if (v1->len != v2->len) {
1666  fprintf(stderr, "DIFFER : SIZE OF VARIABLE \"%s\" : %d <> %d\n", name, (int)v1->len, (int)v2->len);
1667 
1668  if (!opts->warn[NCCMP_W_ALL]) \
1669  return EXIT_DIFFER;
1670  else
1671  return EXIT_SUCCESS;
1672  }
1673 
1674  for(i=0; i < v1->ndims; ++i) {
1675  start[i] = 0;
1676  odomax[i] = v1->dimlens[i] - 1;
1677  }
1678 
1679 #ifdef __DEBUG__
1680  printf("DEBUG : %d : odomax = ", __LINE__);
1681  for(i=0; i < v1->ndims; ++i) {
1682  printf("%d ", odomax[i]);
1683  }
1684  printf("\n");
1685 #endif
1686 
1687  /* If has record dim. */
1688  if (v1->hasrec && (rec >= 0))
1689  start[0] = rec;
1690 
1691  /* Read in slab for last dimension at-a-time only.
1692  We'll then loop over all the other outer dimensions. */
1693  for(i=0; i < v1->ndims-1; ++i) {
1694  count[i] = 1;
1695  }
1696 
1697  /* We'll always read in entire last dimension
1698  except if only dimension is record. */
1699  if ((v1->ndims == 1) && (v1->hasrec)) {
1700  nitems = 1;
1701  } else
1702  nitems = v1->dimlens[v1->ndims-1];
1703 
1704  count[v1->ndims-1] = nitems;
1705 
1706  /*printf("DEBUG : %d : nitems = %d\n", __LINE__, nitems);\*/
1707 
1708 #define CMP_VAR(TYPE, NCFUNTYPE, ncid1, ncid2, P1, P2, M) {\
1709  P1 = (TYPE*)malloc(sizeof(TYPE) * (nitems + 1)); \
1710  P2 = (TYPE*)malloc(sizeof(TYPE) * (nitems + 1)); \
1711  \
1712  do { \
1713  /* 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]); */ \
1714  status = nc_get_vara(ncid1, v1->varid, start, count, P1); \
1715  handle_error(status); \
1716  status = nc_get_vara(ncid2, v2->varid, start, count, P2); \
1717  handle_error(status); \
1718  /* Sentinels. */ \
1719  P1[nitems] = 0; \
1720  P2[nitems] = 1; \
1721  \
1722  cmplen = nitems; \
1723  /* for(i=0; i<nitems; ++i) { \
1724  printf("nitems = %d, rec = %d, P1[%d] = %g, P2[%d] = %g\n", nitems, rec, i, P1[i], i, P2[i]); \
1725  } */ \
1726  if (do_missing) \
1727  diff = cmp_##NCFUNTYPE##_missing(P1, P2, v1->missing.M, v2->missing.M); \
1728  else \
1729  diff = cmp_##NCFUNTYPE(P1, P2); \
1730  \
1731  while (diff < cmplen) { \
1732  if (!opts->warn[NCCMP_W_ALL]) \
1733  diffstatus = EXIT_DIFFER; \
1734  else \
1735  diffstatus = EXIT_SUCCESS; \
1736  \
1737  if (opts->fortran) \
1738  getidxstr_fortran(v1, start, nitems-cmplen+diff, idxstr); \
1739  else \
1740  getidxstr(v1, start, nitems-cmplen+diff, idxstr); \
1741  \
1742  NCFUNTYPE##value1 = P1[nitems-cmplen+diff]; \
1743  NCFUNTYPE##value2 = P2[nitems-cmplen+diff]; \
1744  if (printHex) {\
1745  NCFUNTYPE##ToHex(NCFUNTYPE##value1, value1str); \
1746  NCFUNTYPE##ToHex(NCFUNTYPE##value2, value2str); \
1747  } else { \
1748  NCFUNTYPE##ToString(NCFUNTYPE##value1, value1str, opts->precision); \
1749  NCFUNTYPE##ToString(NCFUNTYPE##value2, value2str, opts->precision); \
1750  } \
1751  fprintf(stderr, message, v1->name, idxstr, value1str, value2str); \
1752  /* printf("%d nitems=%d, cmplen=%d, diff=%d\n", __LINE__, nitems, cmplen, diff); */\
1753  if (opts->force) { \
1754  cmplen = cmplen - (diff+1); \
1755  diff = cmp_##NCFUNTYPE(P1+diff+1, P2+diff+1); \
1756  } else \
1757  goto break_##NCFUNTYPE; \
1758  } \
1759  /* Increment all but first (if record) and last dimensions. */\
1760  } while(odometer(start, odomax, (rec >= 0), v1->ndims-2)); \
1761  break_##NCFUNTYPE:\
1762  free(P1); \
1763  free(P2); \
1764  }
1765 
1766  switch(v1->type) {
1767  case NC_BYTE:
1768  CMP_VAR(int8_t,
1769  byte, ncid1, ncid2,
1770  b1, b2, b);
1771  break;
1772 
1773  case NC_CHAR:
1774  CMP_VAR( char,
1775  text, ncid1, ncid2,
1776  c1, c2, c);
1777  break;
1778 
1779  case NC_SHORT:
1780  CMP_VAR(short, short, ncid1, ncid2,s1, s2, s)
1781  break;
1782 
1783  case NC_INT:
1784  CMP_VAR(int, int, ncid1, ncid2,i1, i2, i)
1785  break;
1786 
1787  case NC_FLOAT:
1788  CMP_VAR(float, float, ncid1, ncid2,f1, f2, f);
1789  break;
1790 
1791  case NC_DOUBLE:
1792  CMP_VAR(double, double,ncid1, ncid2, d1, d2, d);
1793  break;
1794  }
1795 
1796  return diffstatus;
1797 }
1798 /* *********************************************************** */
1799 /* Do the comparision of variables.
1800  Record index (rec) is optional; -1 if not applicable.
1801  Returns comparison result success or failure.
1802 */
1803 int cmpvartol(char* name, int rec, nccmpopts* opts, int ncid1, int ncid2)
1804 {
1805  int8_t *b1,*b2;
1806  char *c1,*c2;
1807  short *s1,*s2;
1808  int *i1,*i2;
1809  float *f1,*f2;
1810  double *d1,*d2;
1811  varstruct *v1,*v2;
1812  int idx1, idx2, status, i;
1813  size_t start[NC_MAX_DIMS], count[NC_MAX_DIMS];
1814  char tmpstr1[256], tmpstr2[256], idxstr[256];
1815  off_t nitems, diff, cmplen;
1816  size_t odomax[NC_MAX_DIMS];
1817  int diffstatus = EXIT_SUCCESS;
1818  char *message = "DIFFER : VARIABLE : %s : POSITION : %s : VALUES : %s <> %s : PERCENT : %g\n";
1819  char value1str[32], value2str[32];
1820  double absdelta;
1821  double doublevalue1, doublevalue2;
1822  int intvalue1, intvalue2;
1823  short shortvalue1, shortvalue2;
1824  float floatvalue1, floatvalue2;
1825  char textvalue1, textvalue2;
1826  int8_t bytevalue1, bytevalue2;
1827  char printHex = strchr(opts->precision, 'X') || strchr(opts->precision, 'x');
1828  char do_missing = 0;
1829 
1830  if (opts->verbose) {
1831  if (rec != -1)
1832  printf("INFO: Comparing data for variable \"%s\" at record %d.\n", name, (int)rec);
1833  else
1834  printf("INFO: Comparing non-record data for variable \"%s\".\n", name);
1835  }
1836 
1837  idx1 = findvar(name, vars1);
1838  idx2 = findvar(name, vars2);
1839 
1840  if (idx1 < 0) {
1841  if (! opts->metadata) /* This gets reported in cmpmeta. */
1842  fprintf(stderr, "DIFFER : Failed to find variable \"%s\" in file \"%s\".\n", name, opts->file1);
1843 
1844  if (!opts->warn[NCCMP_W_ALL])
1845  return EXIT_DIFFER;
1846  else
1847  return EXIT_SUCCESS;
1848  }
1849 
1850  if (idx2 < 0) {
1851  if (! opts->metadata) /* This gets reported in cmpmeta. */
1852  fprintf(stderr, "DIFFER : Failed to find variable \"%s\" in file \"%s\".\n", name, opts->file2);
1853 
1854  if (!opts->warn[NCCMP_W_ALL])
1855  return EXIT_DIFFER;
1856  else
1857  return EXIT_SUCCESS;
1858  }
1859 
1860  v1 = &vars1[idx1];
1861  v2 = &vars2[idx2];
1862 
1863  /* Setup missing mode. */
1864  if (opts->missing && v1->hasmissing && v2->hasmissing) {
1865  do_missing = 1;
1866  }
1867 
1868  for(i=0; i < v1->ndims; ++i) {
1869  start[i] = 0;
1870  odomax[i] = v1->dimlens[i] - 1;
1871  }
1872 
1873  /* If has record dim. */
1874  if (v1->hasrec && (rec >= 0))
1875  start[0] = rec;
1876 
1877  /* Read in slab for last dimension at-a-time only.
1878  We'll then loop over all the other outer dimensions. */
1879  for(i=0; i < v1->ndims-1; ++i) {
1880  count[i] = 1;
1881  }
1882 
1883  /* We'll always read in entire last dimension
1884  except if only dimension is record. */
1885  if ((v1->ndims == 1) && (v1->hasrec)) {
1886  nitems = 1;
1887  } else
1888  nitems = v1->dimlens[v1->ndims-1];
1889 
1890  count[v1->ndims-1] = nitems;
1891 
1892  /* todo: make cmpvar and cmpvartol same function to re-use code immediately above; just use conditional to choose CMP_VAR or CMP_VARTOL macro. */
1893 #define CMP_VARTOL(TYPE, NCFUNTYPE, ncid1, ncid2, P1, P2, M) { \
1894  P1 = (TYPE*)malloc(sizeof(TYPE) * nitems); \
1895  P2 = (TYPE*)malloc(sizeof(TYPE) * nitems); \
1896  \
1897  do { \
1898  /* 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]); */ \
1899  status = nc_get_vara(ncid1, v1->varid, start, count, P1); \
1900  handle_error(status); \
1901  status = nc_get_vara(ncid2, v2->varid, start, count, P2); \
1902  handle_error(status); \
1903  \
1904  /* for(i=0; i<nitems; ++i) { \
1905  printf("nitems = %d, rec = %d, P1[%d] = %g, P2[%d] = %g\n", nitems, rec, i, P1[i], i, P2[i]); \
1906  } */ \
1907  for(i=0; i < nitems; ++i) \
1908  { \
1909  if (do_missing) { \
1910  if ((v1->missing.M == P1[i]) && (v2->missing.M == P2[i])) continue; \
1911  } \
1912  \
1913  absdelta = fabs((double)(P1[i]-P2[i])); \
1914  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) \
1915  { \
1916  if (!opts->warn[NCCMP_W_ALL]) \
1917  diffstatus = EXIT_DIFFER; \
1918  else \
1919  diffstatus = EXIT_SUCCESS; \
1920  \
1921  if ((v1->ndims == 1) && (v1->hasrec)) {\
1922  if (opts->fortran) \
1923  getidxstr_fortran(v1, start, rec, idxstr); \
1924  else \
1925  getidxstr(v1, start, rec, idxstr); \
1926  } else {\
1927  if (opts->fortran) \
1928  getidxstr_fortran(v1, start, i, idxstr); \
1929  else \
1930  getidxstr(v1, start, i, idxstr); \
1931  }\
1932  NCFUNTYPE##value1 = P1[i]; \
1933  NCFUNTYPE##value2 = P2[i]; \
1934  if (printHex) {\
1935  NCFUNTYPE##ToHex(NCFUNTYPE##value1, value1str); \
1936  NCFUNTYPE##ToHex(NCFUNTYPE##value2, value2str); \
1937  } else {\
1938  NCFUNTYPE##ToString(NCFUNTYPE##value1, value1str, opts->precision); \
1939  NCFUNTYPE##ToString(NCFUNTYPE##value2, value2str, opts->precision); \
1940  } \
1941  fprintf(stderr, message, v1->name, idxstr, value1str, value2str, (double)absdelta*100./(fabs((double)P1[i]) > fabs((double)P2[i]) ? fabs((double)P1[i]) : fabs((double)P2[i])) ); \
1942  if (! opts->force) \
1943  { \
1944  goto break_##NCFUNTYPE; \
1945  } \
1946  } \
1947  } \
1948  } while(odometer(start, odomax, (rec >= 0), v1->ndims-2)); \
1949  break_##NCFUNTYPE:\
1950  free(P1); \
1951  free(P2); \
1952 }
1953 
1954  switch (v1->type) {
1955  case NC_BYTE:
1956  CMP_VARTOL(int8_t,
1957  byte, ncid1, ncid2,
1958  b1, b2, b);
1959  break;
1960 
1961  case NC_CHAR:
1962  CMP_VARTOL(char,
1963  text, ncid1, ncid2,
1964  c1, c2, c);
1965  break;
1966 
1967  case NC_SHORT:
1968  CMP_VARTOL(short, short, ncid1, ncid2, s1, s2, s)
1969  break;
1970 
1971  case NC_INT:
1972  CMP_VARTOL(int, int, ncid1, ncid2, i1, i2, i)
1973  break;
1974 
1975  case NC_FLOAT:
1976  CMP_VARTOL(float, float, ncid1, ncid2, f1, f2, f);
1977  break;
1978 
1979  case NC_DOUBLE:
1980  CMP_VARTOL(double, double, ncid1, ncid2, d1, d2, d);
1981  break;
1982  }
1983 
1984  return diffstatus;
1986 
1987 /* *********************************************************** */
1988 int
1989 nccmpdatarecvartol(int ncid1, int ncid2, char* varname, nccmpopts* opts,
1990  size_t recstart, size_t recend) {
1991  int cmpstatus;
1992  int status = EXIT_SUCCESS;
1993 
1994  for (; recstart <= recend; ++recstart) {
1995  cmpstatus = cmpvartol(varname, recstart, opts, ncid1, ncid2) || status;
1996  if (cmpstatus != EXIT_SUCCESS) {
1997  status = cmpstatus;
1998  if (opts->force)
1999  continue;
2000  else
2001  break;
2002  }
2003  }
2004 
2005  return status;
2007 
2008 /* *********************************************************** */
2009 int
2010 nccmpdatarecvar(int ncid1, int ncid2, char* varname, nccmpopts* opts,
2011  size_t recstart, size_t recend) {
2012  int cmpstatus;
2013  int status = EXIT_SUCCESS;
2014 
2015  for (; recstart <= recend; ++recstart) {
2016  cmpstatus = cmpvar(varname, recstart, opts, ncid1, ncid2) || status;
2017  if (cmpstatus != EXIT_SUCCESS) {
2018  status = cmpstatus;
2019  if (opts->force)
2020  continue;
2021  else
2022  break;
2023  }
2024  }
2025 
2026  return status;
2027 }
2028 
2029 /* *********************************************************** */
2030 int nccmpdatatol(int ncid1, int ncid2, nccmpopts* opts) {
2031  int i, idx1, idx2;
2032  int status, cmpstatus, nprocessed;
2033  char** processed = NULL;
2034 
2035  status = EXIT_SUCCESS;
2036 
2037  if (opts->verbose)
2038  printf("INFO: Comparing data with tolerance.\n");
2039 
2040  if (newstringlist(&processed, &nprocessed, NC_MAX_VARS)) {
2041  fprintf(stderr, "ERROR: Failed to allocated string list for comparing data.\n");
2042  return EXIT_FATAL;
2043  }
2044 
2045  for (i = 0; i < opts->ncmpvarlist; ++i) {
2046  if (instringlist(processed, opts->cmpvarlist[i], nprocessed))
2047  /* Skip varnames already processed. */
2048  continue;
2049 
2050  if (opts->verbose)
2051  printf("INFO: Comparing data for variable \"%s\".\n", opts->cmpvarlist[i]);
2052 
2053  addstringtolist(processed, opts->cmpvarlist[i], nprocessed);
2054 
2055  /* Has rec? */
2056  idx1 = findvar(opts->cmpvarlist[i], vars1);
2057  if (vars1[idx1].hasrec) {
2058 
2059  /* Compare only if # recs are equal and not zero. */
2060  if ((nrec1 == nrec2) && (nrec1 + nrec2)) {
2061  cmpstatus = nccmpdatarecvartol(ncid1, ncid2, opts->cmpvarlist[i], opts, 0, nrec1 - 1);
2062  if (cmpstatus) {
2063  status = cmpstatus;
2064  if (opts->force)
2065  continue;
2066  else
2067  break;
2068  }
2069  }
2070  } else {
2071  cmpstatus = cmpvartol(opts->cmpvarlist[i], -1, opts, ncid1, ncid2);
2072  if (cmpstatus) {
2073  status = cmpstatus;
2074  if (opts->force)
2075  continue;
2076  else
2077  break;
2078  }
2079  }
2080  }
2081 
2082  if (opts->verbose)
2083  printf("INFO: Finished comparing data.\n");
2084 
2085  return status;
2086 }
2087 
2088 /* *********************************************************** */
2089 int nccmpdata(nccmpopts* opts, int ncid1, int ncid2) {
2090  int i, idx1, idx2;
2091  int status, cmpstatus, nprocessed;
2092  char** processed = NULL;
2093  char str1[32], str2[32];
2094 
2095  status = EXIT_SUCCESS;
2096 
2097  if (opts->verbose)
2098  printf("INFO: Comparing data.\n");
2099 
2100  if (opts->tolerance != 0)
2101  return nccmpdatatol(ncid1, ncid2, opts);
2102 
2103  if (newstringlist(&processed, &nprocessed, NC_MAX_VARS)) {
2104  fprintf(stderr, "ERROR: Failed to allocated string list for comparing data.\n");
2105  return EXIT_FATAL;
2106  }
2107 
2108  for (i = 0; i < opts->ncmpvarlist; ++i) {
2109  if (instringlist(processed, opts->cmpvarlist[i], nprocessed))
2110  /* Skip varnames already processed. */
2111  continue;
2112 
2113  if (opts->verbose)
2114  printf("INFO: Comparing data for variable \"%s\".\n", opts->cmpvarlist[i]);
2115 
2116  addstringtolist(processed, opts->cmpvarlist[i], nprocessed);
2117 
2118  idx1 = findvar(opts->cmpvarlist[i], vars1);
2119  idx2 = findvar(opts->cmpvarlist[i], vars2);
2120 
2121  if (idx1 < 0) {
2122  if (!opts->metadata) /* This gets reported in cmpmeta. */
2123  fprintf(stderr, "DIFFER : Failed to find variable \"%s\" in file \"%s\".\n", opts->cmpvarlist[i], opts->file1);
2124 
2125  if (!opts->warn[NCCMP_W_ALL])
2126  status = EXIT_DIFFER;
2127  if (opts->force)
2128  continue;
2129  else
2130  break;
2131  }
2132 
2133  if (idx2 < 0) {
2134  if (!opts->metadata) /* This gets reported in cmpmeta. */
2135  fprintf(stderr, "DIFFER : Failed to find variable \"%s\" in file \"%s\".\n", opts->cmpvarlist[i], opts->file2);
2136 
2137  if (!opts->warn[NCCMP_W_ALL])
2138  status = EXIT_DIFFER;
2139  if (opts->force)
2140  continue;
2141  else
2142  break;
2143  }
2144 
2145  if (vars1[idx1].len != vars2[idx2].len) {
2146  fprintf(stderr, "DIFFER : SIZE OF VARIABLE \"%s\" : %d <> %d\n", opts->cmpvarlist[i], (int) vars1[idx1].len, (int) vars2[idx2].len);
2147 
2148  if (!opts->warn[NCCMP_W_ALL])
2149  status = EXIT_DIFFER;
2150  if (opts->force)
2151  continue;
2152  else
2153  break;
2154  }
2155 
2156  if (vars1[idx1].type != vars2[idx2].type) {
2157  type2string(vars1[idx1].type, str1);
2158  type2string(vars2[idx2].type, str2);
2159  fprintf(stderr, "DIFFER : TYPE OF VARIABLE \"%s\" : %s <> %s\n", opts->cmpvarlist[i], str1, str2);
2160 
2161  if (!opts->warn[NCCMP_W_ALL])
2162  status = EXIT_DIFFER;
2163 
2164  if (opts->force)
2165  continue;
2166  else
2167  break;
2168  }
2169 
2170  /* Has rec? */
2171  if (vars1[idx1].hasrec) {
2172 
2173  /* Compare only if # recs are equal and not zero. */
2174  if ((nrec1 == nrec2) && (nrec1 + nrec2)) {
2175  /* TODO: Check if ignorem missing. */
2176  cmpstatus = nccmpdatarecvar(ncid1, ncid2, opts->cmpvarlist[i], opts, 0, nrec1 - 1);
2177  if (cmpstatus) {
2178  status = cmpstatus;
2179  if (opts->force)
2180  continue;
2181  else
2182  break;
2183  }
2184  }
2185  } else {
2186  /* TODO: Check if ignorem missing. */
2187  cmpstatus = cmpvar(opts->cmpvarlist[i], -1, opts, ncid1, ncid2);
2188  if (cmpstatus) {
2189  status = cmpstatus;
2190  if (opts->force)
2191  continue;
2192  else
2193  break;
2194  }
2195  }
2196  }
2197 
2198  if (opts->verbose)
2199  printf("INFO: Finished comparing data.\n");
2200 
2201  return status;
2203 
2204 /* *********************************************************** */
2205 int
2206 nccmp(nccmpopts* opts) {
2207  int ncid1, ncid2;
2208  int numgrps1, numgrps2;
2209  int *gids1, *gids2;
2210  int i, status;
2211 
2212  if (opts->verbose)
2213  printf("INFO: Opening input files.\n");
2214 
2215  status = openfiles(opts, &ncid1, &ncid2);
2216  if (status)
2217  return status;
2218 
2219  if (opts->verbose)
2220  printf("INFO: Creating variable comparison list.\n");
2221 
2222  GROUP_NODE *groups1 = NULL;
2223  GROUP_NODE *groups2 = NULL;
2224 
2225  if (opts->verbose)
2226  printf("INFO: Comparing file formats.\n");
2227 
2228  status += nccmpformats(opts, ncid1, ncid2);
2229  if (status && !opts->force)
2230  return status;
2231 
2232  if (opts->verbose)
2233  printf("INFO: Comparing global attributes.\n");
2234  status += nccmpglobalatts(opts, ncid1, ncid2);
2235 
2236  if (status && !opts->force)
2237  return status;
2238 
2239  if (opts->verbose)
2240  printf("INFO: Collecting dimension information for first file.\n");
2241 
2242  getdiminfo(ncid1, dims1, &ndims1);
2243 
2244  if (opts->verbose)
2245  printf("INFO: Collecting dimension information for second file.\n");
2246 
2247  getdiminfo(ncid2, dims2, &ndims2);
2248 
2249  nc_inq_grps(ncid1, &numgrps1, NULL);
2250  if (numgrps1 > 0) {
2251  groups1 = malloc(sizeof (GROUP_NODE) * numgrps1);
2252  getgroupinfo(ncid1, numgrps1, groups1);
2253  }
2254  nc_inq_grps(ncid2, &numgrps2, NULL);
2255  if (numgrps2 > 0) {
2256  groups2 = malloc(sizeof (GROUP_NODE) * numgrps2);
2257  getgroupinfo(ncid2, numgrps2, groups2);
2258  }
2259 
2260  if (numgrps1 == numgrps2 && numgrps1 > 0) {
2261 
2262  for (i = 0; i < numgrps1; i++) {
2263  status += makecmpvarlist(opts, groups1[i].groupID, groups2[i].groupID);
2264  if (status && !opts->force)
2265  return status;
2266 
2267  if (opts->verbose)
2268  printf("INFO: Comparing group attributes [%s]:\n", groups1[i].groupName);
2269  status += nccmpglobalatts(opts, groups1[i].groupID, groups2[i].groupID);
2270  if (status && !opts->force)
2271  return status;
2272 
2273  if (opts->verbose)
2274  printf("INFO: Collecting variable information for first file.\n");
2275 
2276  getvarinfo(groups1[i].groupID, vars1, &nvars1, opts->verbose);
2277 
2278  if (opts->verbose)
2279  printf("INFO: Collecting variable information for second file.\n");
2280 
2281  getvarinfo(groups2[i].groupID, vars2, &nvars2, opts->verbose);
2282 
2283  status += nccmprecinfo(opts, groups1[i].groupID, groups2[i].groupID);
2284  if (status && !opts->force)
2285  return status;
2286 
2287  if (opts->metadata) {
2288  status += nccmpmetadata(opts, groups1[i].groupID, groups2[i].groupID);
2289  }
2290 
2291  if (status && !opts->force)
2292  return status;
2293 
2294  if (opts->data) {
2295  status += nccmpdata(opts, groups1[i].groupID, groups2[i].groupID);
2296  }
2297  if (status && !opts->force)
2298  return status;
2299 
2300  clearstringlist(opts->cmpvarlist, opts->ncmpvarlist);
2301  }
2302  }
2303  // Check root group
2304  status += makecmpvarlist(opts, ncid1, ncid2);
2305  if (status && !opts->force)
2306  return status;
2307 
2308  if (opts->verbose)
2309  printf("INFO: Collecting variable information for first file.\n");
2310 
2311  getvarinfo(ncid1, vars1, &nvars1, opts->verbose);
2312 
2313  if (opts->verbose)
2314  printf("INFO: Collecting variable information for second file.\n");
2315 
2316  getvarinfo(ncid2, vars2, &nvars2, opts->verbose);
2317 
2318  status += nccmprecinfo(opts, ncid1, ncid2);
2319  if (status && !opts->force)
2320  return status;
2321 
2322  if (opts->metadata) {
2323  status += nccmpmetadata(opts, ncid1, ncid2);
2324  }
2325 
2326  if (status && !opts->force)
2327  return status;
2328 
2329  if (opts->data) {
2330  status += nccmpdata(opts, ncid1, ncid2);
2331  }
2332  if (status && !opts->force)
2333  return status;
2334 
2335  if (opts->verbose)
2336  printf("INFO: Comparisons complete. Freeing memory.\n");
2337 
2338  return status;
2339 }
2341 /* *********************************************************** */
2342 
2343 int
2344 main(int argc, char** argv) {
2345  int status;
2346  nccmpopts opts;
2347 
2348  status = EXIT_SUCCESS;
2349 
2350  initnccmpopts(&opts);
2351 
2352  /* parse command-line args. & options */
2353  status = getnccmpopts(argc, argv, &opts);
2354 
2355  if (status != EXIT_SUCCESS)
2356  goto end;
2357 
2358  if (opts.verbose)
2359  printf("INFO: Command-line options parsed.\n");
2360 
2361  status = nccmp(&opts);
2362 
2363 end:
2364  if (opts.report_identical) {
2365  if (!(opts.help || opts.version) &&
2366  (status == EXIT_SUCCESS)) {
2367  printf("Files \"%s\" and \"%s\" are identical.\n",
2368  opts.file1, opts.file2);
2369  }
2370  }
2371 
2372  freenccmpopts(&opts);
2373 
2374  exit(status);
2375 }
int addstringtolist(char **list, char *string, int nitems)
Definition: strlist.c:129
int cmpvar(char *name, int rec, nccmpopts *opts, int ncid1, int ncid2)
Definition: nccmp.c:1619
int strlistsd(char **list1, char **list2, char **listdiff, int n1, int n2, int nsd)
Definition: strlist.c:198
#define EXIT_SUCCESS
Definition: GEO_basic.h:72
int j
Definition: decode_rs.h:73
int cmpatt(int ncid1, int ncid2, int varid1, int varid2, char *name, char *varname, nccmpopts *opts)
Definition: nccmp.c:402
void shortToString(short v, char *out, char *ignore)
Definition: nccmp.c:84
int status
Definition: l1_czcs_hdf.c:32
list(APPEND LIBS ${PGSTK_LIBRARIES}) add_executable(atteph_info_modis atteph_info_modis.c) target_link_libraries(atteph_info_modis $
Definition: CMakeLists.txt:7
void getidxstr_fortran(varstruct *var, size_t *start, int curidx, char *out)
Definition: nccmp.c:57
void byteToString(unsigned char v, char *out, char *ignore)
Definition: nccmp.c:88
float f1(float x)
off_t cmp_double(double *in1, double *in2)
Definition: nccmp.c:1601
int ndims1
Definition: nccmp.c:29
void byteToHex(int8_t v, char *out)
Definition: nccmp.c:149
void initnccmpopts(nccmpopts *popts)
Definition: opt.c:65
int clearstringlist(char **list, int n)
Definition: strlist.c:36
#define NULL
Definition: decode_rs.h:63
int nvars1
Definition: nccmp.c:29
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
void getvarinfo(int ncid, varstruct *vars, int *nvars, int verbose)
Definition: nccmp.c:865
#define NCFORMATSTR(f)
Definition: nccmp.c:31
int nvars2
Definition: nccmp.c:29
int nccmpformats(nccmpopts *opts, int ncid1, int ncid2)
Definition: nccmp.c:1000
int odometer(size_t *odo, size_t *limits, int first, int last)
Definition: nccmp.c:236
int getnumstrlist(char **list, int nlist)
Definition: strlist.c:242
const double pi
int newstringlist(char ***list, int *n, int size)
Definition: strlist.c:22
void textToString(char v, char *out, char *ignore)
Definition: nccmp.c:92
void freenccmpopts(nccmpopts *popts)
Definition: opt.c:54
int excludevars(int ncid1, int ncid2, char **finallist, int nfinal, char **excludelist, int nexclude)
Definition: nccmp.c:176
#define NCCMP_W_ALL
Definition: opt.h:98
int recid2
Definition: nccmp.c:29
void freestringlist(char ***list, int nitems)
Definition: strlist.c:88
#define NCCMP_W_EOS
Definition: opt.h:100
void doubleToHex(double v, char *out)
Definition: nccmp.c:97
void getidxstr(varstruct *var, size_t *start, int curidx, char *out)
Definition: nccmp.c:41
void type2string(nc_type type, char *str)
Definition: nccmp.c:664
int recid1
Definition: nccmp.c:29
#define BROADCAST_MISSING(T)
float f2(float y)
int nccmpmetadata(nccmpopts *opts, int ncid1, int ncid2)
Definition: nccmp.c:1248
int instringlist(char **list, char *str, int nitems)
Definition: strlist.c:107
void floatToString(float v, char *out, char *formatprec)
Definition: nccmp.c:76
char get_missing(int ncid, varstruct *var, const char *attname)
Definition: nccmp.c:821
int nccmpdata(nccmpopts *opts, int ncid1, int ncid2)
Definition: nccmp.c:2085
int cmpvartol(char *name, int rec, nccmpopts *opts, int ncid1, int ncid2)
Definition: nccmp.c:1801
double precision function f(R1)
Definition: tmd.lp.f:1454
#define NCCMP_W_FORMAT
Definition: opt.h:99
int getgroupinfo(int ncid, int numgroups, GROUP_NODE *groups)
Definition: nccmp.c:762
off_t cmp_byte(int8_t *in1, int8_t *in2)
Definition: nccmp.c:1553
data_t tmp
Definition: decode_rs.h:74
off_t cmp_int(int *in1, int *in2)
Definition: nccmp.c:1577
off_t cmp_float(float *in1, float *in2)
Definition: nccmp.c:1589
int main(int argc, char **argv)
Definition: nccmp.c:2340
void getdiminfo(int ncid, dimstruct *dims, int *ndims)
Definition: nccmp.c:778
int getnccmpopts(int argc, char **argv, nccmpopts *popts)
Definition: opt.c:121
int nccmpdatarecvartol(int ncid1, int ncid2, char *varname, nccmpopts *opts, size_t recstart, size_t recend)
Definition: nccmp.c:1985
int ndims2
Definition: nccmp.c:29
void prettyprintatt(int ncid, char *varname, int varid, char *name, char *str)
Definition: nccmp.c:270
off_t cmp_double_missing(double *in1, double *in2, double m1, double m2)
Definition: nccmp.c:1607
void shortToHex(short v, char *out)
Definition: nccmp.c:136
off_t cmp_int_missing(int *in1, int *in2, int m1, int m2)
Definition: nccmp.c:1583
int ncallvars(int ncid, char **list, int nlist)
Definition: ncinfo.c:94
#define CMP_VARTOL(TYPE, NCFUNTYPE, ncid1, ncid2, P1, P2, M)
int nccmpdatarecvar(int ncid1, int ncid2, char *varname, nccmpopts *opts, size_t recstart, size_t recend)
Definition: nccmp.c:2006
int appendstringtolist(char ***list, const char *string, int *nitems)
Definition: strlist.c:152
int openfiles(nccmpopts *opts, int *ncid1, int *ncid2)
Definition: nccmp.c:692
off_t cmp_text_missing(char *in1, char *in2, char m1, char m2)
Definition: nccmp.c:1547
int cmpattval(int nc1, int nc2, int varid1, int varid2, char *name, int len, nc_type type)
Definition: nccmp.c:503
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
void broadcast_missing(nc_type var_type, nc_type att_type, missing_struct *values)
Definition: nccmp.c:799
void intToString(int v, char *out, char *ignore)
Definition: nccmp.c:80
void intToHex(int v, char *out)
Definition: nccmp.c:123
subroutine diff(x, conec, n, dconecno, dn, dconecmk, units, u, inno, i, outno, o, input, deriv)
Definition: ffnet.f:205
integer, parameter double
int groupID
Definition: nccmp.h:63
#define XFREE(stale)
Definition: xmalloc.h:42
#define CMP_VAR(TYPE, NCFUNTYPE, ncid1, ncid2, P1, P2, M)
int isinvarstructlist(char *name, varstruct *vars, int nvars)
Definition: nccmp.c:917
void floatToHex(float v, char *out)
Definition: nccmp.c:110
int nccmpdatatol(int ncid1, int ncid2, nccmpopts *opts)
Definition: nccmp.c:2026
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 b1
Definition: HISTORY.txt:576
void doubleToString(double v, char *out, char *formatprec)
Definition: nccmp.c:72
off_t cmp_byte_missing(int8_t *in1, int8_t *in2, int8_t m1, int8_t m2)
Definition: nccmp.c:1559
data_t b[NROOTS+1]
Definition: decode_rs.h:77
void textToHex(char v, char *out)
Definition: nccmp.c:162
const char * str
Definition: l1c_msi.cpp:35
HISTORY txt for MOD_PR01(step one of PGE01) History follows the following convention needed due to new Aqua ReprocessingActual and the expected LUT revision number from PCF Changed to use PGE version for ProductionHistory Added Archive including ProcessingEnvironment Corrected handling of bad to resovle GSFcd02514 Changed to check staged LUT revision number versus the expected LUT revision number from thereby resolving defect report MODxl02056 This change also avoids the memory access violation reported in MODur00039 Changed the way output arrays were initialized with fill values
Definition: HISTORY.txt:162
int allvarnames(char **list, int nvars, int ncid1, int ncid2)
Definition: nccmp.c:968
varstruct vars2[(int) NC_MAX_VARS]
Definition: nccmp.c:26
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
off_t cmp_text(char *in1, char *in2)
Definition: nccmp.c:1541
#define fabs(a)
Definition: misc.h:93
void handle_error(int status)
Definition: nccmp.c:219
#define XMALLOC(type, num)
Definition: xmalloc.h:36
varstruct vars1[(int) NC_MAX_VARS]
Definition: nccmp.c:26
int nccmprecinfo(nccmpopts *opts, int ncid1, int ncid2)
Definition: nccmp.c:707
int findvar(char *name, varstruct *vars)
Definition: nccmp.c:1527
data_t s[NROOTS]
Definition: decode_rs.h:75
off_t cmp_short_missing(short *in1, short *in2, short m1, short m2)
Definition: nccmp.c:1571
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
#define EXIT_DIFFER
Definition: common.h:84
dimstruct dims2[(int) NC_MAX_DIMS]
Definition: nccmp.c:27
size_t nrec1
Definition: nccmp.c:28
#define EXIT_FATAL
Definition: common.h:85
int nccmpglobalatts(nccmpopts *opts, int ncid1, int ncid2)
Definition: nccmp.c:1023
size_t nrec2
Definition: nccmp.c:28
int strlistu(char **list1, char **list2, char **listunion, int n1, int n2, int nu)
Definition: strlist.c:171
dimstruct dims1[(int) NC_MAX_DIMS]
Definition: nccmp.c:27
int i
Definition: decode_rs.h:71
How many dimensions is the output array Default is Not sure if anything above will work correctly strcpy(l2prod->title, "no title yet")
int nccmp(nccmpopts *opts)
Definition: nccmp.c:2202
int makecmpvarlist(nccmpopts *opts, int ncid1, int ncid2)
Definition: nccmp.c:930
int verbose
Definition: fmt_check.c:6
off_t cmp_short(short *in1, short *in2)
Definition: nccmp.c:1565
float p[MODELMAX]
Definition: atrem_corl1.h:131
off_t cmp_float_missing(float *in1, float *in2, float m1, float m2)
Definition: nccmp.c:1595
int count
Definition: decode_rs.h:79