GCC Code Coverage Report
Directory: ./ Exec Total Coverage
File: src/gage/pvl.c Lines: 108 162 66.7 %
Date: 2017-05-26 Branches: 88 154 57.1 %

Line Branch Exec Source
1
/*
2
  Teem: Tools to process and visualize scientific data and images             .
3
  Copyright (C) 2013, 2012, 2011, 2010, 2009  University of Chicago
4
  Copyright (C) 2008, 2007, 2006, 2005  Gordon Kindlmann
5
  Copyright (C) 2004, 2003, 2002, 2001, 2000, 1999, 1998  University of Utah
6
7
  This library is free software; you can redistribute it and/or
8
  modify it under the terms of the GNU Lesser General Public License
9
  (LGPL) as published by the Free Software Foundation; either
10
  version 2.1 of the License, or (at your option) any later version.
11
  The terms of redistributing and/or modifying this software also
12
  include exceptions to the LGPL that facilitate static linking.
13
14
  This library is distributed in the hope that it will be useful,
15
  but WITHOUT ANY WARRANTY; without even the implied warranty of
16
  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
17
  Lesser General Public License for more details.
18
19
  You should have received a copy of the GNU Lesser General Public License
20
  along with this library; if not, write to Free Software Foundation, Inc.,
21
  51 Franklin Street, Fifth Floor, Boston, MA  02110-1301  USA
22
*/
23
24
#include "gage.h"
25
#include "privateGage.h"
26
27
/*
28
******** gageVolumeCheck()
29
**
30
** checks whether a given volume is valid for the given kind
31
** and the given parameter settings in the context
32
**
33
** Note that ctx is simply passed to _gageShapeSet(), with no NULL-ity
34
** test- which is fine- it just means that the check is not specific
35
** to the parameters that can be set in the gageContext.
36
*/
37
int
38
gageVolumeCheck(const gageContext *ctx, const Nrrd *nin,
39
                const gageKind *kind) {
40
  static const char me[]="gageVolumeCheck";
41
694
  gageShape shape;
42
43
347
  gageShapeReset(&shape);
44
347
  if (_gageShapeSet(ctx, &shape, nin, kind->baseDim)) {
45
    biffAddf(GAGE, "%s: trouble setting volume as %s kind", me, kind->name);
46
    return 1;
47
  }
48
347
  return 0;
49
347
}
50
51
/*
52
******** gagePerVolumeNew()
53
**
54
** creates a new pervolume of a known kind, but nothing besides the
55
** answer array is allocated
56
**
57
** uses biff primarily because of the error checking in gageVolumeCheck()
58
*/
59
gagePerVolume *
60
gagePerVolumeNew(gageContext *ctx, const Nrrd *nin, const gageKind *kind) {
61
  static const char me[]="gagePerVolumeNew";
62
  gagePerVolume *pvl;
63
  int ii;
64
  airArray *mop;
65
66
694
  if (!( nin && kind )) {
67
    biffAddf(GAGE, "%s: got NULL pointer (%p, %p, or %p)", me,
68
             AIR_VOIDP(ctx), AIR_CVOIDP(nin), AIR_CVOIDP(kind));
69
    return NULL;
70
  }
71
  /* Craziness: since circa 2003, the test below was to call gageVolumeCheck,
72
     which is now just a wrapper around _gageShapeSet(), and which never
73
     actually does the important checks of gageKindVolumeCheck (which in turn
74
     eventually calls gageVolumeCheck). This means that basic errors were not
75
     being caught, like having the wrong number of samples along axis 0 for
76
     non-scalar kinds. These various functions need to be simplified soon */
77
347
  if (gageKindVolumeCheck(kind, nin)) {
78
    biffAddf(GAGE, "%s: problem with volume as %s kind", me, kind->name);
79
    return NULL;
80
  }
81
347
  pvl = AIR_CALLOC(1, gagePerVolume);
82
347
  if (!pvl) {
83
    biffAddf(GAGE, "%s: couldn't alloc gagePerVolume", me);
84
    return NULL;
85
  }
86
347
  mop = airMopNew();
87
347
  airMopAdd(mop, pvl, airFree, airMopOnError);
88
347
  pvl->verbose = gageDefVerbose;
89
347
  pvl->kind = kind;
90
347
  GAGE_QUERY_RESET(pvl->query);
91
2776
  for (ii=0; ii<=GAGE_DERIV_MAX; ii++) {
92
1041
    ctx->needD[ii] = AIR_FALSE;
93
  }
94
347
  pvl->nin = nin;
95
2776
  for (ii=gagePvlFlagUnknown+1; ii<gagePvlFlagLast; ii++) {
96
1041
    pvl->flag[ii] = AIR_FALSE;
97
  }
98
347
  pvl->iv3 = pvl->iv2 = pvl->iv1 = NULL;
99
347
  pvl->lup = nrrdDLookup[nin->type];
100
347
  pvl->answer = AIR_CALLOC(gageKindTotalAnswerLength(kind), double);
101
347
  airMopAdd(mop, pvl->answer, airFree, airMopOnError);
102
347
  pvl->directAnswer = AIR_CALLOC(kind->itemMax+1, double*);
103
347
  airMopAdd(mop, pvl->directAnswer, airFree, airMopOnError);
104

694
  if (!(pvl->answer && pvl->directAnswer)) {
105
    biffAddf(GAGE, "%s: couldn't alloc answer and directAnswer arrays", me);
106
    airMopError(mop); return NULL;
107
  }
108
28318
  for (ii=1; ii<=kind->itemMax; ii++) {
109
13812
    pvl->directAnswer[ii] = pvl->answer + gageKindAnswerOffset(kind, ii);
110
  }
111
347
  pvl->flag[gagePvlFlagVolume] = AIR_TRUE;
112
347
  if (kind->pvlDataNew) {
113
16
    if (!(pvl->data = kind->pvlDataNew(kind))) {
114
      biffAddf(GAGE, "%s: double creating gagePerVolume data", me);
115
      airMopError(mop); return NULL;
116
    }
117
  } else {
118
331
    pvl->data = NULL;
119
  }
120
121
347
  airMopOkay(mop);
122
347
  return pvl;
123
347
}
124
125
/*
126
** _gagePerVolumeCopy()
127
**
128
** copies a pervolume for use in a copied context, and probably
129
** should only be called by gageContextCopy()
130
*/
131
gagePerVolume *
132
_gagePerVolumeCopy(gagePerVolume *pvl, unsigned int fd) {
133
  static const char me[]="gagePerVolumeCopy";
134
  gagePerVolume *nvl;
135
  int ii;
136
  airArray *mop;
137
138
616
  nvl = AIR_CALLOC(1, gagePerVolume);
139
308
  if (!nvl) {
140
    biffAddf(GAGE, "%s: couldn't create new pervolume", me);
141
    return NULL;
142
  }
143
308
  mop = airMopNew();
144
308
  airMopAdd(mop, nvl, airFree, airMopOnError);
145
  /* we should probably restrict ourselves to gage API calls, but given the
146
     constant state of gage construction, this seems much simpler.
147
     Pointers to per-pervolume-allocated arrays are fixed below */
148
308
  memcpy(nvl, pvl, sizeof(gagePerVolume));
149
308
  nvl->iv3 = AIR_CALLOC(fd*fd*fd*nvl->kind->valLen, double);
150
308
  nvl->iv2 = AIR_CALLOC(fd*fd*nvl->kind->valLen, double);
151
308
  nvl->iv1 = AIR_CALLOC(fd*nvl->kind->valLen, double);
152
308
  airMopAdd(mop, nvl->iv3, airFree, airMopOnError);
153
308
  airMopAdd(mop, nvl->iv2, airFree, airMopOnError);
154
308
  airMopAdd(mop, nvl->iv1, airFree, airMopOnError);
155
308
  nvl->answer = AIR_CALLOC(gageKindTotalAnswerLength(nvl->kind), double);
156
308
  airMopAdd(mop, nvl->answer, airFree, airMopOnError);
157
308
  nvl->directAnswer = AIR_CALLOC(nvl->kind->itemMax+1, double*);
158
308
  airMopAdd(mop, nvl->directAnswer, airFree, airMopOnError);
159

1232
  if (!( nvl->iv3 && nvl->iv2 && nvl->iv1
160

924
         && nvl->answer && nvl->directAnswer )) {
161
    biffAddf(GAGE, "%s: couldn't allocate all caches "
162
             "(fd=%u, valLen=%u, totAnsLen=%u, itemMax=%u)", me,
163
             fd, nvl->kind->valLen, gageKindTotalAnswerLength(nvl->kind),
164
             nvl->kind->itemMax);
165
    airMopError(mop); return NULL;
166
  }
167
25432
  for (ii=1; ii<=pvl->kind->itemMax; ii++) {
168
12408
    nvl->directAnswer[ii] = nvl->answer + gageKindAnswerOffset(pvl->kind, ii);
169
  }
170
308
  if (pvl->kind->pvlDataCopy) {
171
16
    if (!(nvl->data = pvl->kind->pvlDataCopy(pvl->kind, pvl->data))) {
172
      biffAddf(GAGE, "%s: double copying gagePerVolume data", me);
173
      airMopError(mop); return NULL;
174
    }
175
    /* HEY: pvlDataNix takes 2 arguments; so we can't mop nvl->data,
176
       so its a good thing that we created nvl->data last */
177
  } else {
178
292
    nvl->data = NULL;
179
  }
180
181
308
  airMopOkay(mop);
182
308
  return nvl;
183
308
}
184
185
/*
186
******** gagePerVolumeNix()
187
**
188
** frees all dynamically allocated memory assocated with a pervolume
189
**
190
** does not use biff
191
*/
192
gagePerVolume *
193
gagePerVolumeNix(gagePerVolume *pvl) {
194
195
1110
  if (pvl) {
196
555
    if (pvl->kind->pvlDataNix) {
197
32
      pvl->data = pvl->kind->pvlDataNix(pvl->kind, pvl->data);
198
32
    }
199
555
    pvl->iv3 = (double *)airFree(pvl->iv3);
200
555
    pvl->iv2 = (double *)airFree(pvl->iv2);
201
555
    pvl->iv1 = (double *)airFree(pvl->iv1);
202
555
    pvl->answer = (double *)airFree(pvl->answer);
203
555
    pvl->directAnswer = (double **)airFree(pvl->directAnswer);
204
555
    airFree(pvl);
205
555
  }
206
555
  return NULL;
207
}
208
209
/*
210
******** gageAnswerPointer()
211
**
212
** way of getting a pointer to a specific answer in a pervolume's ans array
213
**
214
** Returns NULL if the item is invalid, but there is no other error checking.
215
** In particular, this does not let you know if the item is actually part
216
** of the current query.
217
**
218
*/
219
const double *
220
gageAnswerPointer(const gageContext *ctx, const gagePerVolume *pvl, int item) {
221
  const double *ret;
222
223
  AIR_UNUSED(ctx);
224

6519
  if (pvl && !airEnumValCheck(pvl->kind->enm, item)) {
225
2173
    ret = pvl->answer + gageKindAnswerOffset(pvl->kind, item);
226
2173
  } else {
227
    ret = NULL;
228
  }
229
2173
  return ret;
230
}
231
232
/* non-const version of the above */
233
double *
234
_gageAnswerPointer(const gageContext *ctx, gagePerVolume *pvl, int item) {
235
  double *ret;
236
237
  AIR_UNUSED(ctx);
238
  if (pvl && !airEnumValCheck(pvl->kind->enm, item)) {
239
    ret = pvl->answer + gageKindAnswerOffset(pvl->kind, item);
240
  } else {
241
    ret = NULL;
242
  }
243
  return ret;
244
}
245
246
unsigned int
247
gageAnswerLength(const gageContext *ctx, const gagePerVolume *pvl, int item) {
248
  unsigned int ret;
249
250
  AIR_UNUSED(ctx);
251

3888
  if (pvl && !airEnumValCheck(pvl->kind->enm, item)) {
252
1296
    ret = gageKindAnswerLength(pvl->kind, item);
253
1296
  } else {
254
    ret = 0;
255
  }
256
1296
  return ret;
257
}
258
259
int
260
gageQueryReset(gageContext *ctx, gagePerVolume *pvl) {
261
  static const char me[]="gageQueryReset";
262
263
  AIR_UNUSED(ctx);
264
  if (!( pvl )) {
265
    biffAddf(GAGE, "%s: got NULL pointer", me);
266
    return 1;
267
  }
268
269
  GAGE_QUERY_RESET(pvl->query);
270
271
  return 0;
272
}
273
274
275
/*
276
******** gageQuerySet()
277
**
278
** sets a query in a pervolume.  Does recursive expansion of query
279
** to cover all prerequisite measures.
280
**
281
** Sets: pvl->query
282
**
283
** the gageContext is not actually used here, but I'm cautiously
284
** including it in case its used in the future.
285
*/
286
int
287
gageQuerySet(gageContext *ctx, gagePerVolume *pvl, gageQuery query) {
288
  static const char me[]="gageQuerySet";
289
  gageQuery lastQuery;
290
  int pi, ii;
291
292
  AIR_UNUSED(ctx);
293
2498
  if (!( pvl )) {
294
    biffAddf(GAGE, "%s: got NULL pointer", me);
295
    return 1;
296
  }
297
1249
  GAGE_QUERY_COPY(pvl->query, query);
298
1249
  if (pvl->verbose) {
299
    fprintf(stderr, "%s: original ", me);
300
    gageQueryPrint(stderr, pvl->kind, pvl->query);
301
  }
302
  /* recursive expansion of prerequisites */
303
  do {
304
1257
    GAGE_QUERY_COPY(lastQuery, pvl->query);
305
1257
    ii = pvl->kind->itemMax+1;
306
1257
    do {
307
54573
      ii--;
308
54573
      if (GAGE_QUERY_ITEM_TEST(pvl->query, ii)) {
309
48420
        for (pi=0; pi<GAGE_ITEM_PREREQ_MAXNUM; pi++) {
310
21520
          if (0 != pvl->kind->table[ii].prereq[pi]) {
311
571
            GAGE_QUERY_ITEM_ON(pvl->query, pvl->kind->table[ii].prereq[pi]);
312
571
          }
313
        }
314
      }
315
54573
    } while (ii);
316
















41233
  } while (!GAGE_QUERY_EQUAL(pvl->query, lastQuery));
317
1249
  if (pvl->verbose) {
318
    fprintf(stderr, "%s: expanded ", me);
319
    gageQueryPrint(stderr, pvl->kind, pvl->query);
320
  }
321
322
  /* doing this kind of error checking here is not really
323
     the way gage should work-- it should be done at the
324
     time of gageUpdate()-- but the novelty of pvl->data
325
     encourages putting new smarts at superficial levels
326
     instead of deeper levels */
327
1249
  if (!pvl->data) {
328
87450
    for (ii=1; ii<=pvl->kind->itemMax; ii++) {
329
45006
      if (GAGE_QUERY_ITEM_TEST(pvl->query, ii)
330
45006
          && pvl->kind->table[ii].needData) {
331
        biffAddf(GAGE, "%s: item %d (%s) needs data, but pvl->data is NULL",
332
                 me, ii, airEnumStr(pvl->kind->enm, ii));
333
        return 1;
334
      }
335
    }
336
  }
337
338
1249
  pvl->flag[gagePvlFlagQuery] = AIR_TRUE;
339
340
1249
  return 0;
341
1249
}
342
343
int
344
gageQueryAdd(gageContext *ctx, gagePerVolume *pvl, gageQuery query) {
345
  static const char me[]="gageQueryAdd";
346
347
  if (!( pvl )) {
348
    biffAddf(GAGE, "%s: got NULL pointer", me);
349
    return 1;
350
  }
351
352
  GAGE_QUERY_ADD(pvl->query, query);
353
  if (gageQuerySet(ctx, pvl, pvl->query)) {
354
    biffAddf(GAGE, "%s: trouble", me);
355
    return 1;
356
  }
357
358
  return 0;
359
}
360
361
int
362
gageQueryItemOn(gageContext *ctx, gagePerVolume *pvl, int item) {
363
  static const char me[]="gageQueryItemOn";
364
365
2498
  if (!( pvl )) {
366
    biffAddf(GAGE, "%s: got NULL pointer", me);
367
    return 1;
368
  }
369
370
1249
  if (airEnumValCheck(pvl->kind->enm, item)) {
371
    biffAddf(GAGE, "%s: %d not a valid %s value", me,
372
             item, pvl->kind->enm->name);
373
    return 1;
374
  }
375
1249
  GAGE_QUERY_ITEM_ON(pvl->query, item);
376
1249
  if (gageQuerySet(ctx, pvl, pvl->query)) {
377
    biffAddf(GAGE, "%s: trouble", me);
378
    return 1;
379
  }
380
381
1249
  return 0;
382
1249
}
383