1/*********************************************************************
2 *   Copyright 1996, UCAR/Unidata
3 *   See netcdf/COPYRIGHT file for copying and redistribution conditions.
4 *   $Id: util.c 2792 2014-10-27 06:02:59Z wkliao $
5 *********************************************************************/
6
7#include "tests.h"
8#include <math.h>
9void
10print_nok(int nok)
11{
12    if (verbose || nfails > 0)
13        print("\n");
14    print(" %d good comparisons. ", nok);
15}
16
17
18/* Is value within external type range? */
19int
20inRange(const double value, const nc_type datatype)
21{
22    double minmax;
23
24    switch (datatype) {
25        case NC_CHAR:   return value >= X_CHAR_MIN   && value <= X_CHAR_MAX;
26        case NC_BYTE:   return value >= X_BYTE_MIN   && value <= X_BYTE_MAX;
27        case NC_SHORT:  return value >= X_SHORT_MIN  && value <= X_SHORT_MAX;
28        case NC_INT:    return value >= X_INT_MIN    && value <= X_INT_MAX;
29        case NC_FLOAT:  return value >= X_FLOAT_MIN  && value <= X_FLOAT_MAX;
30        case NC_DOUBLE: return value >= X_DOUBLE_MIN && value <= X_DOUBLE_MAX;
31        case NC_UBYTE:  return value >= 0            && value <= X_UCHAR_MAX;
32        case NC_USHORT: return value >= 0            && value <= X_USHORT_MAX;
33        case NC_UINT:   return value >= 0            && value <= X_UINT_MAX;
34        case NC_INT64:  return value >= X_INT64_MIN  && value <= X_INT64_MAX;
35        case NC_UINT64: return value >= 0            && value <= X_UINT64_MAX;
36 default:  assert(0);
37    }
38    return value >= min && value <= max;
39}
40
41static int
42inRange_uchar(const double value, const nc_type datatype)
43{
44    if (datatype == NC_BYTE) {
45 return(value >= 0 && value <= 255);
46    }
47    /* else */
48    return inRange(valuedatatype);
49}
50
51static int
52inRange_schar(const double value, const nc_type datatype)
53{
54    /* check value of type datatype if within schar range */
55
56    if (datatype == NC_UBYTE) {
57        /* netCDF specification make a special case for type conversion between
58         * uchar and scahr: do not check for range error. See
59         * http://www.unidata.ucar.edu/software/netcdf/docs_rc/data_type.html#type_conversion
60         */
61        return(value >= X_CHAR_MIN && value <= X_CHAR_MAX);
62    }
63    /* else */
64    return inRange(valuedatatype);
65}
66
67static int
68inRange_float(const double value, const nc_type datatype)
69{
70    double minmax;
71
72    switch (datatype) {
73 case NC_CHAR:   min = X_CHAR_MIN;   max = X_CHAR_MAX; break;
74 case NC_BYTE:   min = X_BYTE_MIN;   max = X_BYTE_MAX; break;
75 case NC_SHORT:  min = X_SHORT_MIN;  max = X_SHORT_MAX; break;
76 case NC_INT:   min = X_INT_MIN;   max = X_INT_MAX; break;
77 case NC_FLOAT:
78 if(FLT_MAX < X_FLOAT_MAX) {
79 min = (-FLT_MAX);
80 max = FLT_MAX;
81 } else {
82 min = X_FLOAT_MIN;
83 max = X_FLOAT_MAX;
84 }
85 break;
86 case NC_DOUBLE:
87 if(FLT_MAX < X_DOUBLE_MAX) {
88 min = (-FLT_MAX);
89 max = FLT_MAX;
90 } else {
91 min = X_DOUBLE_MIN;
92 max = X_DOUBLE_MAX;
93 }
94 break;
95        case NC_UBYTE:  min = 0;            max = X_UCHAR_MAX;  break;
96        case NC_USHORTmin = 0;            max = X_USHORT_MAX; break;
97        case NC_UINT:   min = 0;            max = X_UINT_MAX;   break;
98        case NC_INT64:  min = X_INT64_MIN;  max = X_INT64_MAX;  break;
99        case NC_UINT64min = 0;            max = X_UINT64_MAX; break;
100 default:  assert(0);
101    }
102    if(!( value >= min && value <= max)) {
103#if 0 /* DEBUG */
104 if(datatype == NC_FLOAT) {
105 fprintf(stderr, "\n");
106 fprintf(stderr, "min   % .17e\n", min);
107 fprintf(stderr, "value % .17e\n", value);
108 fprintf(stderr, "max   % .17e\n", max);
109 }
110#endif
111 return 0;
112    }
113#if FLT_MANT_DIG != DBL_MANT_DIG
114    /* else */
115    {
116 const float fvalue = value;
117 return fvalue >= min && fvalue <= max;
118    }
119#else
120    return 1;
121#endif
122}
123
124/* wrapper for inRange to handle special NC_BYTE/uchar adjustment */
125int
126inRange3(
127    const double value,
128    const nc_type datatype,
129    const nct_itype itype)
130{
131    switch (itype) {
132        case NCT_SCHAR:
133        case NCT_CHAR:
134            return inRange_schar(valuedatatype);
135    case NCT_UCHAR:
136 return inRange_uchar(valuedatatype);
137    case NCT_FLOAT:
138 return inRange_float(valuedatatype);
139    default:
140 break;
141    }
142    return inRange(valuedatatype);
143}
144
145
146/*
147 *  Does x == y, where one is internal and other external (netCDF)?
148 *  Use tolerant comparison based on IEEE FLT_EPSILON or DBL_EPSILON.
149 */
150int
151equal(
152    const double x,
153    const double y,
154    nc_type extType,  /* external data type */
155    nct_itype itype)
156{
157    const double flt_epsilon = 1.19209290E-07;
158    const double dbl_epsilon = 2.2204460492503131E-16;
159    double epsilon;
160
161    epsilon = extType == NC_FLOAT || itype == NCT_FLOAT ? flt_epsilon : dbl_epsilon;
162    return ABS(x-y) <= epsilon * MAX( ABS(x), ABS(y));
163}
164
165/* Test whether two int vectors are equal. If so return 1, else 0  */
166int
167int_vec_eq(const int *v1, const int *v2, const int n)
168{
169    int i;
170    for (i= 0; i < n && v1[i] == v2[i]; i++)
171 ;
172    return i == n;
173}
174
175
176/*
177 *  Generate random integer from 0 to n-1
178 *  Like throwing an n-sided dice marked 0, 1, 2, ..., n-1
179 */
180int roll( int n )
181{
182    int  r;
183
184    do
185 /*
186  * Compute a pseudo-random value between 0.0 and 1.0, multiply
187  * it by n-1, and then find the nearest integer.
188  *
189  * We don't use RAND_MAX here because not all compilation
190  * environments define it (e.g. gcc(1) under SunOS 4.1.4).
191  */
192 r = ((rand() % 32768) / 32767.0) * (n - 1) + 0.5;
193    while (r >= n);
194
195    return r;
196}
197
198
199/*
200 *      Convert number to mixed base
201 *
202 *      E.g. to convert 41 inches to yards, feet and inches:
203 *      size_t base[] = {1, 3, 12};
204 *      size_t result[3];
205 *      status = toMixedBase(41, 3, base, result);
206 *
207 *      Author: Harvey Davies, Unidata/UCAR, Boulder, Colorado
208 */
209int
210toMixedBase(
211    size_t number,        /* number to be converted to mixed base */
212    size_t length,
213    const size_t base[],        /* dimensioned [length], base[0] ignored */
214    size_t result[])      /* dimensioned [length] */
215{
216    size_t i;
217
218    if (length > 0) {
219 for (i = length - 1; i > 0; i--) {
220     if (base[i] == 0)
221 return 1;
222     result[i] = number % base[i];
223     number = number / base[i];
224 }
225        result[0] = number;
226    }
227    return 0;
228}
229
230/*
231 *      Convert number from mixed base
232 *
233 *      E.g. to convert 1 yard, 0 feet, 5 inches to inches:
234 *      size_t number[] = {1, 0, 5};
235 *      size_t base[] = {1, 3, 12};
236 *      inches = fromMixedBase(3, number, base);
237 *
238 *      Author: Harvey Davies, Unidata/UCAR, Boulder, Colorado
239 */
240size_t
241fromMixedBase(
242    size_t length,
243    size_t number[],      /* dimensioned [length] */
244    size_t base[])        /* dimensioned [length], base[0] ignored */
245{
246    size_t i;
247    size_t result = 0;
248
249    for (i = 1; i < lengthi++) {
250        result += number[i-1];
251        result *= base[i];
252    }
253    if (length > 0)
254        result += number[i-1];
255    return result;
256}
257
258
259/* Convert any nc_type to double */
260int nc2dbl ( const nc_type datatype, const void *p, double *result)
261{
262    if ( ! p ) return 2;
263    if ( ! result ) return 3;
264    switch (datatype) {
265        case NC_BYTE: *result = *((signed char *) p); break;
266        case NC_CHAR: *result = *((signed char *) p); break;
267        case NC_SHORT: *result = *((short *) p); break;
268        case NC_INT:
269#if INT_MAX >= X_INT_MAX
270 *result = *((int *) p); break;
271#else
272 *result = *((long *) p); break;
273#endif
274        case NC_FLOAT: *result = *((float *) p); break;
275        case NC_DOUBLE: *result = *((double *) p); break;
276        case NC_UBYTE:  *result = *((unsigned char *)  p); break;
277        case NC_USHORT: *result = *((unsigned short *) p); break;
278        case NC_UINT:
279#if UINT_MAX >= X_UINT_MAX
280            *result = *((unsigned int *) p); break;
281#else
282            *result = *((unsigned long *) p); break;
283#endif
284        case NC_INT64:  *result = *((long long *)          p); break;
285        case NC_UINT64: *result = *((unsigned long long *) p); break;
286        default: return 1;
287    }
288    return 0;
289}
290
291
292/* Convert double to any nc_type */
293int dbl2nc ( const double d, const nc_type datatype, void *p)
294{
295    double r;   /* rounded value */
296
297    if (p) {
298        switch (datatype) {
299            case NC_BYTE:
300                r = floor(0.5+d);
301                if ( r < schar_min  ||  r > schar_max )  return 2;
302                *((signed char *) p) = r;
303                break;
304            case NC_CHAR:
305              r = floor(0.5+d);
306              if ( r < text_min  ||  r > text_max )  return 2;
307#ifndef __CHAR_UNSIGNED__
308              *((char   *) p) = r;
309#else
310              *((signed char*) p) = r;
311#endif
312              break;
313            case NC_SHORT:
314                r = floor(0.5+d);
315                if ( r < short_min  ||  r > short_max )  return 2;
316                *((short  *) p) = r;
317                break;
318            case NC_INT:
319                r = floor(0.5+d);
320                if ( r < long_min  ||  r > long_max )  return 2;
321#if INT_MAX >= X_INT_MAX
322                *((int   *) p) = r;
323#else
324                *((long   *) p) = r;
325#endif
326                break;
327            case NC_FLOAT:
328                if ( fabs(d) > float_max )  return 2;
329                *((float  *) p) = d;
330                break;
331            case NC_DOUBLE:
332                *((double *) p) = d;
333                break;
334        case NC_UBYTE:
335            r = floor(0.5+d);
336            if ( r < 0.0  ||  r > uchar_max )  return 2;
337            *((unsigned char *) p) = r;
338            break;
339        case NC_USHORT:
340            r = floor(0.5+d);
341            if ( r < 0.0  ||  r > ushort_max )  return 2;
342            *((unsigned short *) p) = r;
343            break;
344        case NC_UINT:
345            r = floor(0.5+d);
346            if ( r < 0.0  ||  r > uint_max )  return 2;
347#if UINT_MAX >= X_UINT_MAX
348            *((unsigned int  *) p) = r;
349#else
350            *((unsigned long *) p) = r;
351#endif
352            break;
353        case NC_INT64:
354            r = floor(0.5+d);
355            if ( r < int64_min  ||  r > int64_max )  return 2;
356            *((long long *) p) = r;
357            break;
358        case NC_UINT64:
359            r = floor(0.5+d);
360            if ( r < 0.0  ||  r > uint64_max )  return 2;
361            *((unsigned long long *) p) = r;
362            break;
363            default:
364                return 1;
365        }
366 return 0;
367    } else {
368 return 1;
369    }
370}
371
372#define FUZZ (1.19209290E-07)
373
374#ifdef USE_EXTREME_NUMBERS
375/* Generate data values as function of type, rank (-1 for attribute), index */
376double
377hash( const nc_type type, const int rank, const size_t *index )
378{
379    double base;
380    double result;
381    int  d;       /* index of dimension */
382
383 /* If vector then elements 0 & 1 are min & max. Elements 2 & 3 are */
384 /* just < min & > max (except for NC_CHAR & NC_DOUBLE) */
385    if (abs(rank) == 1 && index[0] <= 3) {
386 switch (index[0]) {
387     case 0:
388 switch (type) {
389     case NC_CHAR:   return X_CHAR_MIN;
390     case NC_BYTE:   return X_BYTE_MIN;
391     case NC_SHORT:  return X_SHORT_MIN;
392     case NC_INT:   return X_INT_MIN;
393     case NC_FLOAT:  return X_FLOAT_MIN;
394     case NC_DOUBLE: return X_DOUBLE_MIN;
395                    case NC_UBYTE:  return 0;
396                    case NC_USHORT: return 0;
397                    case NC_UINT:   return 0;
398                    case NC_INT64:  return X_INT_MIN - 128.0; /* slight smaller
399                                                                 than INT_MIN */
400                    case NC_UINT64: return 0;
401     default:  assert(0);
402 }
403     case 1:
404 switch (type) {
405     case NC_CHAR:   return X_CHAR_MAX;
406     case NC_BYTE:   return X_BYTE_MAX;
407     case NC_SHORT:  return X_SHORT_MAX;
408     case NC_INT:   return X_INT_MAX;
409     case NC_FLOAT:  return X_FLOAT_MAX;
410     case NC_DOUBLE: return X_DOUBLE_MAX;
411                    case NC_UBYTE:  return X_UCHAR_MAX;
412                    case NC_USHORT: return X_USHORT_MAX;
413                    case NC_UINT:   return X_UINT_MAX;
414                    case NC_INT64:  return X_INT_MAX + 128.0;
415                                    /* slightly bigger than INT_MAX */
416                    case NC_UINT64: return X_UINT_MAX + 128.0;
417                                    /* slightly bigger than UINT_MAX */
418     default:  assert(0);
419 }
420     case 2:
421 switch (type) {
422     case NC_CHAR:   return 'A';
423     case NC_BYTE:   return X_BYTE_MIN-1.0;
424     case NC_SHORT:  return X_SHORT_MIN-1.0;
425     case NC_INT:   return X_INT_MIN-1.0;
426     case NC_FLOAT:  return X_FLOAT_MIN * (1.0 + FUZZ);
427     case NC_DOUBLE: return -1.0;
428                    case NC_UBYTE:  return -1.0;
429                    case NC_USHORT: return -1.0;
430                    case NC_UINT:   return -1.0;
431                    case NC_INT64:  return -1.0;  /* skip test */
432                    case NC_UINT64: return -1.0;
433     default:  assert(0);
434 }
435     case 3:
436 switch (type) {
437     case NC_CHAR:   return 'Z';
438     case NC_BYTE:   return X_BYTE_MAX+1.0;
439     case NC_SHORT:  return X_SHORT_MAX+1.0;
440     case NC_INT:   return X_INT_MAX+1.0;
441     case NC_FLOAT:  return X_FLOAT_MAX * (1.0 + FUZZ);
442     case NC_DOUBLE: return 1.0;
443                    case NC_UBYTE:  return X_UCHAR_MAX +1.0;
444                    case NC_USHORT: return X_USHORT_MAX+1.0;
445                    case NC_UINT:   return X_UINT_MAX  +1.0;
446                    case NC_INT64:  return 1.0;    /* skip test */
447                    case NC_UINT64: return 1.0;    /* skip test */
448     default:  assert(0);
449 }
450 }
451    } else {
452 switch (type) {
453     case NC_CHARbase = 2; break;
454     case NC_BYTEbase = -2; break;
455     case NC_SHORTbase = -5; break;
456     case NC_INTbase = -20; break;
457     case NC_FLOATbase = -9; break;
458     case NC_DOUBLEbase = -10; break;
459
460            /* not sure what right values are */
461            case NC_UBYTE:   base =   2;  break;
462            case NC_USHORT:  base =   5;  break;
463            case NC_UINT:    base =  20;  break;
464            case NC_INT64:   base = -20;  break;
465            case NC_UINT64:  base =  20;  break;
466     default:  assert(0);
467 }
468 result = rank < 0 ? base * 7 : base * (rank + 1);
469 for (d = 0; d < abs(rank); d++)
470     result = base * (result + index[d]);
471    }
472    return result;
473}
474#else /* USE_EXTREME_NUMBERS */
475#define SANE_SHORT 3333
476#define SANE_INT 2222
477#define SANE_FLOAT 300.0
478#define SANE_DOUBLE 1000.0
479
480/* Generate data values as function of type, rank (-1 for attribute), index */
481double
482hash( const nc_type type, const int rank, const size_t *index )
483{
484    double base;
485    double result;
486    int  d;       /* index of dimension */
487
488 /* If vector then elements 0 & 1 are min & max. Elements 2 & 3 are */
489 /* just < min & > max (except for NC_CHAR & NC_DOUBLE) */
490    if (abs(rank) == 1 && index[0] <= 3) {
491 switch (index[0]) {
492     case 0:
493 switch (type) {
494     case NC_CHAR:   return X_CHAR_MIN;
495     case NC_BYTE:   return X_BYTE_MIN;
496     case NC_SHORT:  return SANE_SHORT;
497     case NC_INT:   return SANE_INT;
498     case NC_FLOAT:  return SANE_FLOAT;
499     case NC_DOUBLE: return SANE_DOUBLE;
500                    case NC_UBYTE:  return 0;
501                    case NC_USHORT: return 0;
502                    case NC_UINT:   return 0;
503                    case NC_INT64:  return X_INT_MIN - 128.0; /* slight smaller
504                                                                 than INT_MIN */
505                    case NC_UINT64: return 0;
506     default:  assert(0);
507 }
508     case 1:
509 switch (type) {
510     case NC_CHAR:   return X_CHAR_MAX;
511     case NC_BYTE:   return X_BYTE_MAX;
512     case NC_SHORT:  return SANE_SHORT;
513     case NC_INT:   return SANE_INT;
514     case NC_FLOAT:  return SANE_FLOAT;
515     case NC_DOUBLE: return SANE_DOUBLE;
516                    case NC_UBYTE:  return X_UCHAR_MAX;
517                    case NC_USHORT: return X_USHORT_MAX;
518                    case NC_UINT:   return X_UINT_MAX;
519                    case NC_INT64:  return X_INT_MAX + 128.0;
520                                    /* slightly bigger than INT_MAX */
521                    case NC_UINT64: return X_UINT_MAX + 128.0;
522                                    /* slightly bigger than UINT_MAX */
523     default:  assert(0);
524 }
525     case 2:
526 switch (type) {
527     case NC_CHAR:   return 'A';
528     case NC_BYTE:   return X_BYTE_MIN-1.0;
529     case NC_SHORT:  return SANE_SHORT-1.0;
530     case NC_INT:   return SANE_INT-1.0;
531     case NC_FLOAT:  return SANE_FLOAT * (1.0 + FUZZ);
532     case NC_DOUBLE: return -1.0;
533                    case NC_UBYTE:  return -1.0;
534                    case NC_USHORT: return -1.0;
535                    case NC_UINT:   return -1.0;
536                    case NC_INT64:  return -1.0;  /* skip test */
537                    case NC_UINT64: return -1.0;
538     default:  assert(0);
539 }
540     case 3:
541 switch (type) {
542     case NC_CHAR:   return 'Z';
543     case NC_BYTE:   return X_BYTE_MAX+1.0;
544     case NC_SHORT:  return SANE_SHORT+1.0;
545     case NC_INT:   return SANE_INT+1.0;
546     case NC_FLOAT:  return SANE_FLOAT * (1.0 + FUZZ);
547     case NC_DOUBLE: return 1.0;
548                    case NC_UBYTE:  return X_UCHAR_MAX +1.0;
549                    case NC_USHORT: return X_USHORT_MAX+1.0;
550                    case NC_UINT:   return X_UINT_MAX  +1.0;
551                    case NC_INT64:  return 1.0;    /* skip test */
552                    case NC_UINT64: return 1.0;    /* skip test */
553     default:  assert(0);
554 }
555 }
556    } else {
557 switch (type) {
558     case NC_CHARbase = 2; break;
559     case NC_BYTEbase = -2; break;
560     case NC_SHORTbase = -5; break;
561     case NC_INTbase = -20; break;
562     case NC_FLOATbase = -9; break;
563     case NC_DOUBLEbase = -10; break;
564
565            /* not sure what right values are */
566            case NC_UBYTE:   base =   2;  break;
567            case NC_USHORT:  base =   5;  break;
568            case NC_UINT:    base =  20;  break;
569            case NC_INT64:   base = -20;  break;
570            case NC_UINT64:  base =  20;  break;
571     default:  assert(0);
572 }
573 result = rank < 0 ? base * 7 : base * (rank + 1);
574 for (d = 0; d < abs(rank); d++)
575     result = base * (result + index[d]);
576    }
577    return result;
578}
579#endif
580/* wrapper for hash to handle special NC_BYTE/uchar adjustment */
581double
582hash4(
583    const nc_type type,
584    const int rank,
585    const size_t *index,
586    const nct_itype itype)
587{
588    double result;
589
590    result = hashtyperankindex );
591    if (itype == NCT_UCHAR && type == NC_BYTE && result >= -128 && result < 0)
592 result += 256;
593    return result;
594}
595
596static nc_type
597char2type(char letter) {
598    switch (letter) {
599        case 'c': return NC_CHAR;
600        case 'b': return NC_BYTE;
601        case 's': return NC_SHORT;
602        case 'i': return NC_INT;
603        case 'f': return NC_FLOAT;
604        case 'd': return NC_DOUBLE;
605        case 'y': return NC_UBYTE;
606        case 't': return NC_USHORT;
607        case 'u': return NC_UINT;
608        case 'x': return NC_INT64;
609        case 'z': return NC_UINT64;
610        default:  assert(0);
611    }
612    return NC_CHAR;  /* Just to keep compiler happy */
613}
614
615
616static void
617init_dims(const char *digit)
618{
619 int dimid; /* index of dimension */
620 for (dimid = 0; dimid < NDIMSdimid++)
621 {
622 dim_len[dimid] = dimid == 0 ? NRECS : dimid;
623 dim_name[dimid][0] = 'D';
624 dim_name[dimid][1] = digit[dimid];
625 dim_name[dimid][2] = '\0';
626 }
627}
628
629static void
630init_gatts(const char *type_letter)
631{
632 int attid;
633 for (attid = 0; attid < numGattsattid++)
634 {
635 gatt_name[attid][0] = 'G';
636 gatt_name[attid][1] = type_letter[attid];
637 gatt_name[attid][2] = '\0';
638 gatt_len[attid] = 1 + attid;
639 gatt_type[attid] = char2type (type_letter[attid]);
640 }
641}
642
643static size_t
644product(size_t nn, const size_t *sp)
645{
646 size_t result = 1;
647 while(nn-- > 0)
648 result *= *sp++;
649 return result;
650}
651
652/*
653   define global variables:
654   dim_name, dim_len,
655   var_name, var_type, var_rank, var_shape, var_natts, var_dimid, var_nels
656   att_name, gatt_name, att_type, gatt_type, att_len, gatt_len
657 */
658void
659init_gvars (void)
660{
661 const size_t max_dim_len[MAX_RANK] = {
662 MAX_DIM_LEN +1,
663 MAX_DIM_LEN,
664 MAX_DIM_LEN
665 };
666    const char type_letter[] = "cbsifdytuxz";
667    /* c:char, b:byte, s:short, i:int, f:float, d:double, y:ubyte, t:ushort,
668     * u:uint, x:int64, z:uint64
669     */
670 const char digit[] = "r123456789";
671
672 size_t rank;
673 int vn; /* var number */
674 int xtype; /* index of type */
675 int an; /* attribute number */
676
677 assert(sizeof(max_dim_len)/sizeof(max_dim_len[0]) >= MAX_RANK);
678
679 init_dims(digit);
680
681 for (vn=0; vn<numVarsvn++)
682     memset(var_name[vn], 0, 2+MAX_RANK);
683
684 for (rank = 0, vn = 0, xtype = 0, an = 0;  rank <= MAX_RANKrank++)
685 {
686 /* number variables of a type and rank */
687 const size_t nvars = product(rankmax_dim_len);
688 int jj;
689
690 for (jj = 0; jj < nvarsjj++)
691 {
692 /* number types of this shape */
693 const int ntypes = rank < 2 ? numTypes : 1;
694
695 int tc;
696 for (tc = 0; tc < ntypes;
697      tc++, vn++, xtype = (xtype + 1) % numTypes)
698 {
699 size_t tmp[MAX_RANK];
700
701 var_name[vn][0] = type_letter[xtype];
702 var_type[vn] = char2type (type_letter[xtype]);
703 var_rank[vn] = rank;
704 var_natts[vn] = rank == 0 ? vn % (MAX_NATTS + 1) : 0;
705 {
706 int ac;
707 for (ac = 0; ac < var_natts[vn]; ac++, an++)
708 {
709 att_name[vn][ac][0] = type_letter[an % numTypes];
710 att_name[vn][ac][1] = '\0';
711 att_len[vn][ac] = an;
712 att_type[vn][ac] = char2type (type_letter[an % numTypes]);
713 }
714 } /* ac block */
715#ifndef NDEBUG
716 assert(toMixedBase (jjrankmax_dim_lentmp) == 0);
717#else
718 (void) toMixedBase (jjrankmax_dim_lentmp);
719#endif
720 {
721 int dn; /* dimension number */
722 for (dn = 0; dn < rankdn++)
723 var_dimid[vn][dn] = (int)tmp[dn];
724 for (dn = 0, var_nels[vn] = 1; dn < rankdn++)
725 {
726 var_dimid[vn][dn] += dn > 0;
727 assert (var_dimid[vn][dn] <= 9);
728 var_name[vn][dn + 1] = digit[var_dimid[vn][dn]];
729 var_shape[vn][dn] = var_dimid[vn][dn] ?
730 var_dimid[vn][dn] : NRECS;
731 var_nels[vn] *= var_shape[vn][dn];
732 }
733 } /* dn block */
734 }
735 }
736 }
737
738 init_gatts(type_letter);
739}
740
741
742/* define dims defined by global variables */
743void
744def_dims(int ncid)
745{
746    int  err;             /* status */
747    int  i;
748    int  dimid; /* dimension id */
749
750    for (i = 0; i < NDIMSi++) {
751 err = nc_def_dim(nciddim_name[i], i==0 ? NC_UNLIMITED : dim_len[i],
752     &dimid);
753 IF (errerror("nc_def_dim: %s", nc_strerror(err));
754    }
755}
756
757
758/* define vars defined by global variables */
759void
760def_vars(int ncid)
761{
762    int  err;             /* status */
763    int  i;
764    int var_id;
765
766    for (i = 0; i < numVarsi++) {
767 err = nc_def_var(ncidvar_name[i], var_type[i], var_rank[i],
768     var_dimid[i], &var_id);
769 IF (errerror("nc_def_var: %s", nc_strerror(err));
770    }
771}
772
773
774/* put attributes defined by global variables */
775void
776put_atts(int ncid)
777{
778    int  err;             /* status */
779    int  i;
780    size_t  k;
781    int  j; /* index of attribute */
782    int  allInRange;
783    double att[MAX_NELS];
784    signed char catt[MAX_NELS];
785
786    for (i = -1; i < numVarsi++) {
787 for (j = 0; j < NATTS(i); j++) {
788     if (ATT_TYPE(i,j) == NC_CHAR) {
789 for (k = 0; k < ATT_LEN(i,j); k++) {
790     catt[k] = hash(ATT_TYPE(i,j), -1, &k);
791 }
792 err = nc_put_att_text(ncidiATT_NAME(i,j),
793     ATT_LEN(i,j), catt);
794 IF (err)
795     error("nc_put_att_text: %s", nc_strerror(err));
796     } else {
797 for (allInRange = 1, k = 0; k < ATT_LEN(i,j); k++) {
798     att[k] = hash(ATT_TYPE(i,j), -1, &k);
799     allInRange = allInRange && inRange(att[k], ATT_TYPE(i,j));
800 }
801 err = nc_put_att_double(ncidiATT_NAME(i,j),
802     ATT_TYPE(i,j), ATT_LEN(i,j), att);
803                if (allInRange) {
804                    IF (err)
805                        error("nc_put_att_double: %s", nc_strerror(err));
806                } else {
807                    IF (err != NC_ERANGE)
808 error("type-conversion range error: status = %d", err);
809                }
810     }
811        }
812    }
813}
814
815/* put variables defined by global variables */
816void
817put_vars(int ncid)
818{
819    size_t start[MAX_RANK];
820    size_t index[MAX_RANK];
821    int  err;             /* status */
822    int  i;
823    size_t  j;
824    double value[MAX_NELS];
825    signed char text[MAX_NELS];
826    int  allInRange;
827
828    for (j = 0; j < MAX_RANKj++)
829 start[j] = 0;
830    for (i = 0; i < numVarsi++) {
831 for (allInRange = 1, j = 0; j < var_nels[i]; j++) {
832     err = toMixedBase(jvar_rank[i], var_shape[i], index);
833     IF (errerror("toMixedBase");
834     if (var_name[i][0] == 'c') {
835 text[j] = hash(var_type[i], var_rank[i], index);
836     } else {
837 value[j]  = hash(var_type[i], var_rank[i], index);
838 allInRange = allInRange && inRange(value[j], var_type[i]);
839     }
840 }
841 if (var_name[i][0] == 'c') {
842     err = nc_put_vara_text(ncidistartvar_shape[i], text);
843     IF (err)
844 error("nc_put_vara_text: %s", nc_strerror(err));
845 } else {
846     err = nc_put_vara_double(ncidistartvar_shape[i], value);
847     if (allInRange) {
848 IF (err)
849     error("nc_put_vara_double: %s", nc_strerror(err));
850     } else {
851 IF (err != NC_ERANGE)
852     error("type-conversion range error: status = %d", err);
853     }
854 }
855    }
856}
857
858
859/* Create & write all of specified file using global variables */
860void
861write_file(char *filename)
862{
863    int  ncid; /* netCDF id */
864    int  err;  /* status */
865    err = file_create(filenameNC_CLOBBER, &ncid);
866    IF (err)
867 error("nc_create: %s", nc_strerror(err));
868
869    def_dims(ncid);
870    def_vars(ncid);
871    put_atts(ncid);
872    err = nc_enddef(ncid);
873    IF (err)
874 error("nc_enddef: %s", nc_strerror(err));
875
876#ifdef USE_PNETCDF
877    { int i,format;
878    nc_inq_format_extended(ncid, &formatNULL);
879    if (format == NC_FORMATX_PNETCDF) {
880        for (i = 0; i < numVarsi++) {
881            err = nc_var_par_access(ncidiNC_COLLECTIVE);
882     IF (errerror("nc_var_par_access: %s", nc_strerror(err));
883        }
884    }}
885#endif
886
887    put_vars(ncid);
888
889    err = nc_close (ncid);
890    IF (err)
891 error("nc_close: %s", nc_strerror(err));
892}
893
894
895/*
896 * check dimensions of specified file have expected name & length
897 */
898void
899check_dims(int  ncid)
900{
901    char name[NC_MAX_NAME];
902    size_t length;
903    int  i;
904    int  err;           /* status */
905
906    for (i = 0; i < NDIMSi++) {
907 err = nc_inq_dim(ncidiname, &length);
908 IF (err)
909     error("nc_inq_dim: %s", nc_strerror(err));
910 IF (strcmp(namedim_name[i]) != 0)
911     error("Unexpected name of dimension %d: '%s', expected: '%s'", inamedim_name[i]);
912 IF (length != dim_len[i])
913     error("Unexpected length %d of dimension %d, expected %zu", lengthidim_len[i]);
914    }
915}
916
917
918/*
919 * check variables of specified file have expected name, type, shape & values
920 */
921void
922check_vars(int  ncid)
923{
924    size_t index[MAX_RANK];
925    int  err; /* status */
926    int  i;
927    size_t  j;
928    signed char  text;
929    double value;
930    nc_type datatype;
931    int ndims;
932    int dimids[MAX_RANK];
933    int isChar;
934    double expect;
935    char name[NC_MAX_NAME];
936    size_t length;
937    int nok = 0;      /* count of valid comparisons */
938
939    for (i = 0; i < numVarsi++) {
940        isChar = var_type[i] == NC_CHAR;
941 err = nc_inq_var(ncidiname, &datatype, &ndimsdimidsNULL);
942 IF (err)
943     error("nc_inq_var: %s", nc_strerror(err));
944 IF (strcmp(namevar_name[i]) != 0)
945     error("Unexpected var_name");
946 IF (datatype != var_type[i])
947     error("Unexpected type");
948 IF (ndims != var_rank[i])
949     error("Unexpected rank");
950 for (j = 0; j < ndimsj++) {
951     err = nc_inq_dim(nciddimids[j], 0, &length);
952     IF (err)
953 error("nc_inq_dim: %s", nc_strerror(err));
954     IF (length != var_shape[i][j])
955 error("Unexpected shape");
956 }
957 for (j = 0; j < var_nels[i]; j++) {
958     err = toMixedBase(jvar_rank[i], var_shape[i], index);
959     IF (err)
960 error("error in toMixedBase 2");
961     expect = hashvar_type[i], var_rank[i], index );
962     if (isChar) {
963          err = nc_get_var1_text(ncidiindex, &text);
964          IF (err)
965     error("nc_get_var1_text: %s", nc_strerror(err));
966 IF (text != expect) {
967     error("Var %s value read 0x%02x not that expected 0x%02x ",
968 var_name[i], text, (char)expect);
969 print_n_size_t(var_rank[i], index);
970 } else {
971#if 0
972 print("\nOk %s ", var_name[i]);
973 print_n_size_t(var_rank[i], index);
974#endif
975     nok++;
976 }
977     } else {
978 err = nc_get_var1_double(ncidiindex, &value);
979 if (inRange(expect,var_type[i])) {
980     IF (err) {
981 error("nc_get_var1_double: %s", nc_strerror(err));
982     } else {
983 IF (!equal(value,expect,var_type[i], NCT_DOUBLE)) {
984     value = 0;
985        err = nc_get_var1_double(ncidiindex, &value);
986     error("Var %s value read % 12.5e not that expected % 12.7e ",
987 var_name[i], valueexpect);
988     print_n_size_t(var_rank[i], index);
989 } else {
990#if 0
991 print("\nOk %s ", var_name[i]);
992 print_n_size_t(var_rank[i], index);
993#endif
994     nok++;
995 }
996     }
997 }
998     }
999 }
1000    }
1001    print_nok(nok);
1002}
1003
1004
1005/*
1006 * check attributes of specified file have expected name, type, length & values
1007 */
1008void
1009check_atts(int  ncid)
1010{
1011    int  err; /* status */
1012    int  i;
1013    int  j;
1014    size_t  k;
1015    nc_type datatype;
1016    char name[NC_MAX_NAME];
1017    size_t length;
1018    signed char text[MAX_NELS];
1019    double value[MAX_NELS];
1020    double expect;
1021    int nok = 0;      /* count of valid comparisons */
1022
1023    for (i = -1; i < numVarsi++) {
1024 for (j = 0; j < NATTS(i); j++) {
1025            err = nc_inq_attname(ncidijname);
1026            IF (err)
1027                error("nc_inq_attname: %s", nc_strerror(err));
1028            IF (strcmp(nameATT_NAME(i,j)) != 0)
1029                error("nc_inq_attname: unexpected name");
1030     err = nc_inq_att(ncidiname, &datatype, &length);
1031     IF (err)
1032 error("nc_inq_att: %s", nc_strerror(err));
1033     IF (datatype != ATT_TYPE(i,j))
1034 error("nc_inq_att: unexpected type");
1035     IF (length != ATT_LEN(i,j))
1036 error("nc_inq_att: unexpected length");
1037     if (datatype == NC_CHAR) {
1038 err = nc_get_att_text(ncidinametext);
1039 IF (err)
1040     error("nc_get_att_text: %s", nc_strerror(err));
1041 for (k = 0; k < ATT_LEN(i,j); k++) {
1042     IF (text[k] != hash(datatype, -1, &k)) {
1043 error("nc_get_att_text: unexpected value");
1044            } else {
1045              nok++;
1046            }
1047 }
1048     } else {
1049 err = nc_get_att_double(ncidinamevalue);
1050 for (k = 0; k < ATT_LEN(i,j); k++) {
1051     expect = hash(datatype, -1, &k);
1052     if (inRange(expect,ATT_TYPE(i,j))) {
1053 IF (err)
1054     error("nc_get_att_double: %s", nc_strerror(err));
1055 IF (!equal(value[k], expectATT_TYPE(i,j), NCT_DOUBLE)) {
1056     error("Att value read not that expected");
1057 } else {
1058     nok++;
1059 }
1060     }
1061 }
1062     }
1063 }
1064    }
1065    print_nok(nok);
1066}
1067
1068
1069/* Check file (dims, vars, atts) corresponds to global variables */
1070void
1071check_file(char *filename)
1072{
1073    int  ncid; /* netCDF id */
1074    int  err; /* status */
1075
1076    err = file_open(filenameNC_NOWRITE, &ncid);
1077    IF (err) {
1078        error("nc_open: %s", nc_strerror(err));
1079    } else {
1080 check_dims(ncid);
1081 check_vars(ncid);
1082 check_atts(ncid);
1083 err = nc_close (ncid);
1084 IF (err)
1085     error("nc_close: %s", nc_strerror(err));
1086    }
1087}
1088
1089/* TODO: Maybe this function belongs in the netcdf library. */
1090const char *
1091s_nc_type(nc_type type)
1092{
1093 switch((int)type){
1094        case NC_CHAR:   return "NC_CHAR";
1095        case NC_BYTE:   return "NC_BYTE";
1096        case NC_UBYTE:  return "NC_UBYTE";
1097        case NC_SHORT:  return "NC_SHORT";
1098        case NC_USHORT: return "NC_USHORT";
1099        case NC_INT:    return "NC_INT";
1100        case NC_UINT:   return "NC_UINT";
1101        case NC_FLOAT:  return "NC_FLOAT";
1102        case NC_DOUBLE: return "NC_DOUBLE";
1103        case NC_INT64:  return "NC_INT64";
1104        case NC_UINT64: return "NC_UINT64";
1105 }
1106 return "";
1107}
1108
1109
1110int file_create(const char *filename, int cmode, int *ncid)
1111{
1112    int err;
1113
1114    /* get the default file format */
1115    int default_format;
1116    nc_set_default_format(NC_FORMAT_CLASSIC, &default_format);
1117    /* set it back to the default */
1118    nc_set_default_format(default_formatNULL);
1119
1120#ifdef USE_PNETCDF
1121    if (default_format == NC_FORMAT_CLASSIC ||
1122        default_format == NC_FORMAT_64BIT_OFFSET ||
1123        default_format == NC_FORMAT_64BIT_DATA)
1124        err = nc_create_par(filenamecmode|NC_PNETCDFMPI_COMM_WORLDMPI_INFO_NULLncid);
1125    else
1126#endif
1127        err = nc_create(filenamecmodencid);
1128
1129    return err;
1130}
1131
1132int file_open(const char *filename, int omode, int *ncid)
1133{
1134    int err;
1135
1136    /* get the default file format */
1137    int default_format;
1138    err = nc_set_default_format(NC_FORMAT_CLASSIC, &default_format);
1139    /* set it back to the default */
1140    err = nc_set_default_format(default_formatNULL);
1141
1142#ifdef USE_PNETCDF
1143    if (default_format == NC_FORMAT_CLASSIC ||
1144        default_format == NC_FORMAT_64BIT_OFFSET ||
1145        default_format == NC_FORMAT_64BIT_DATA)
1146        err = nc_open_par(filenameomode|NC_PNETCDFMPI_COMM_WORLDMPI_INFO_NULLncid);
1147    else
1148#endif
1149        err = nc_open(filenameomodencid);
1150
1151    return err;
1152}


HyperKWIC - Version 7.20DA executed at 11:37 on 27 Oct 2017 | Polyhedron Solutions - INTERNAL USE | COMMERCIAL (Any O/S) SN 4AKIed