GCC Code Coverage Report
Directory: ./ Exec Total Coverage
File: src/pull/contextPull.c Lines: 0 417 0.0 %
Date: 2017-05-26 Branches: 0 276 0.0 %

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
25
#include "pull.h"
26
#include "privatePull.h"
27
28
pullContext *
29
pullContextNew(void) {
30
  pullContext *pctx;
31
  unsigned int ii;
32
33
  pctx = (pullContext *)calloc(1, sizeof(pullContext));
34
  if (!pctx) {
35
    return NULL;
36
  }
37
38
  _pullInitParmInit(&(pctx->initParm));
39
  _pullIterParmInit(&(pctx->iterParm));
40
  _pullSysParmInit(&(pctx->sysParm));
41
  _pullFlagInit(&(pctx->flag));
42
  pctx->verbose = 0;
43
  pctx->threadNum = 1;
44
  pctx->rngSeed = 42;
45
  pctx->progressBinMod = 50;
46
  pctx->iter_cb = NULL;
47
  pctx->data_cb = NULL;
48
49
  for (ii=0; ii<PULL_VOLUME_MAXNUM; ii++) {
50
    pctx->vol[ii] = NULL;
51
  }
52
  pctx->volNum = 0;
53
  for (ii=0; ii<=PULL_INFO_MAX; ii++) {
54
    pctx->ispec[ii] = NULL;
55
    pctx->infoIdx[ii] = UINT_MAX;
56
  }
57
  pctx->interType = pullInterTypeUnknown;
58
  pctx->energySpecR = pullEnergySpecNew();
59
  pctx->energySpecS = pullEnergySpecNew();
60
  pctx->energySpecWin = pullEnergySpecNew();
61
62
  pctx->haltonOffset = 0;
63
  ELL_4V_SET(pctx->bboxMin, AIR_NAN, AIR_NAN, AIR_NAN, AIR_NAN);
64
  ELL_4V_SET(pctx->bboxMax, AIR_NAN, AIR_NAN, AIR_NAN, AIR_NAN);
65
  pctx->infoTotalLen = 0; /* will be set later */
66
  pctx->idtagNext = 0;
67
  pctx->haveScale = AIR_FALSE;
68
  pctx->constraint = 0;
69
  pctx->constraintDim = -1;
70
  pctx->targetDim = -1;
71
  pctx->finished = AIR_FALSE;
72
  pctx->maxDistSpace = AIR_NAN;
73
  pctx->maxDistScale = AIR_NAN;
74
  pctx->voxelSizeSpace = AIR_NAN;
75
  pctx->voxelSizeScale = AIR_NAN;
76
  pctx->eipScale = 1.0;
77
78
  pctx->bin = NULL;
79
  ELL_4V_SET(pctx->binsEdge, 0, 0, 0, 0);
80
  pctx->binNum = 0;
81
  pctx->binNextIdx = 0;
82
83
  pctx->tmpPointPerm = NULL;
84
  pctx->tmpPointPtr = NULL;
85
  pctx->tmpPointNum = 0;
86
87
  /* pctx->binMutex setup my pullStart */
88
  pctx->task = NULL;
89
  pctx->iterBarrierA = NULL;
90
  pctx->iterBarrierB = NULL;
91
#if PULL_HINTER
92
  pctx->nhinter  = nrrdNew();
93
#endif
94
  pctx->logAdd = NULL;
95
96
  pctx->timeIteration = 0;
97
  pctx->timeRun = 0;
98
  pctx->energy = AIR_NAN;
99
  pctx->addNum = 0;
100
  pctx->nixNum = 0;
101
  pctx->stuckNum = 0;
102
  pctx->pointNum = 0;
103
  pctx->iter = 0;
104
  for (ii=pullCountUnknown; ii<pullCountLast; ii++) {
105
    pctx->count[ii] = 0;
106
  }
107
  return pctx;
108
}
109
110
/*
111
** this should only nix things created by pullContextNew, or the things
112
** (vols and ispecs) that were explicitly added to this context
113
*/
114
pullContext *
115
pullContextNix(pullContext *pctx) {
116
  unsigned int ii;
117
118
  if (pctx) {
119
    for (ii=0; ii<pctx->volNum; ii++) {
120
      pctx->vol[ii] = pullVolumeNix(pctx->vol[ii]);
121
    }
122
    pctx->volNum = 0;
123
    for (ii=0; ii<=PULL_INFO_MAX; ii++) {
124
      if (pctx->ispec[ii]) {
125
        pctx->ispec[ii] = pullInfoSpecNix(pctx->ispec[ii]);
126
      }
127
    }
128
    pctx->energySpecR = pullEnergySpecNix(pctx->energySpecR);
129
    pctx->energySpecS = pullEnergySpecNix(pctx->energySpecS);
130
    pctx->energySpecWin = pullEnergySpecNix(pctx->energySpecWin);
131
#if PULL_HINTER
132
    nrrdNuke(pctx->nhinter);
133
#endif
134
    /* handled elsewhere: bin, task, iterBarrierA, iterBarrierB */
135
    airFree(pctx);
136
  }
137
  return NULL;
138
}
139
140
int
141
_pullMiscParmCheck(pullContext *pctx) {
142
  static const char me[]="_pullMiscParmCheck";
143
  double denr;
144
145
  if (!( AIR_IN_CL(1, pctx->threadNum, PULL_THREAD_MAXNUM) )) {
146
    biffAddf(PULL, "%s: pctx->threadNum (%d) outside valid range [1,%d]", me,
147
             pctx->threadNum, PULL_THREAD_MAXNUM);
148
    return 1;
149
  }
150
  if (airEnumValCheck(pullInterType, pctx->interType)) {
151
    biffAddf(PULL, "%s: pctx->interType %d not a valid %s", me,
152
             pctx->interType, pullInterType->name);
153
    return 1;
154
  }
155
  /* HEY: error checking on energySpec's seems rather spotty . . . */
156
  if (pullEnergyUnknown == pctx->energySpecR->energy) {
157
    biffAddf(PULL, "%s: need to set space energy", me);
158
    return 1;
159
  }
160
  if (pullInterTypeJustR == pctx->interType
161
      || pullInterTypeUnivariate == pctx->interType) {
162
    if (pullEnergyZero != pctx->energySpecS->energy) {
163
      biffAddf(PULL, "%s: can't use scale energy %s with inter type %s", me,
164
               pctx->energySpecS->energy->name,
165
               airEnumStr(pullInterType, pctx->interType));
166
      return 1;
167
    }
168
  } else {
169
    if (pullEnergyZero == pctx->energySpecS->energy) {
170
      biffAddf(PULL, "%s: need a non-zero scale energy for inter type %s", me,
171
               airEnumStr(pullInterType, pctx->interType));
172
      return 1;
173
    }
174
  }
175
  /* make sure that spatial repulsion is really repulsive at r=0 */
176
  pctx->energySpecR->energy->eval(&denr, 0.0000001, pctx->energySpecR->parm);
177
  if (!( denr < 0 )) {
178
    biffAddf(PULL, "%s: spatial energy doesn't have negative slope near r=0",
179
             me);
180
    return 1;
181
  }
182
183
  return 0;
184
}
185
186
int
187
_pullContextCheck(pullContext *pctx) {
188
  static const char me[]="_pullContextCheck";
189
  unsigned int ii, ccount;
190
  int gotIspec, gotConstr;
191
  const pullInfoSpec *lthr, *strn;
192
193
  if (!pctx) {
194
    biffAddf(PULL, "%s: got NULL pointer", me);
195
    return 1;
196
  }
197
  if (_pullInitParmCheck(&(pctx->initParm))
198
      || _pullIterParmCheck(&(pctx->iterParm))
199
      || _pullSysParmCheck(&(pctx->sysParm))
200
      || _pullMiscParmCheck(pctx)) {
201
    biffAddf(PULL, "%s: problem with parameters", me);
202
    return 1;
203
  }
204
205
  if (!pctx->volNum) {
206
    biffAddf(PULL, "%s: have no volumes set", me);
207
    return 1;
208
  }
209
  gotConstr = 0;
210
  gotIspec = AIR_FALSE;
211
  for (ii=0; ii<=PULL_INFO_MAX; ii++) {
212
    if (pctx->ispec[ii]) {
213
      if (pctx->ispec[ii]->constraint) {
214
        if (1 != pullInfoLen(ii)) {
215
          biffAddf(PULL, "%s: can't use non-scalar (len %u) %s as constraint",
216
                   me, pullInfoLen(ii), airEnumStr(pullInfo, ii));
217
          return 1;
218
        }
219
        if (pullSourceGage != pctx->ispec[ii]->source) {
220
          biffAddf(PULL, "%s: sorry, constraints can currently only "
221
                   "come from %s", me,
222
                   airEnumStr(pullSource, pullSourceGage));
223
          return 1;
224
        }
225
        if (gotConstr) {
226
          biffAddf(PULL, "%s: can't also have %s constraint, already have "
227
                   "constraint on %s ", me, airEnumStr(pullInfo, ii),
228
                   airEnumStr(pullInfo, gotConstr));
229
          return 1;
230
        }
231
        /* elso no problems having constraint on ii */
232
        gotConstr = ii;
233
      }
234
      /* make sure we have extra info as necessary */
235
      switch (ii) {
236
      case pullInfoInside:
237
      case pullInfoHeight:
238
      case pullInfoHeightLaplacian:
239
      case pullInfoSeedThresh:
240
      case pullInfoLiveThresh:
241
      case pullInfoLiveThresh2:
242
      case pullInfoLiveThresh3:
243
      case pullInfoIsovalue:
244
      case pullInfoStrength:
245
        if (!( AIR_EXISTS(pctx->ispec[ii]->scale)
246
               && AIR_EXISTS(pctx->ispec[ii]->zero) )) {
247
          biffAddf(PULL, "%s: %s info needs scale (%g) and zero (%g)", me,
248
                   airEnumStr(pullInfo, ii),
249
                   pctx->ispec[ii]->scale, pctx->ispec[ii]->zero);
250
          return 1;
251
        }
252
        break;
253
      }
254
      gotIspec = AIR_TRUE;
255
    }
256
  }
257
258
  if (!gotIspec) {
259
    biffAddf(PULL, "%s: have no infos set", me);
260
    return 1;
261
  }
262
  if (pctx->ispec[pullInfoStrength]) {
263
    if (pullSourceGage != pctx->ispec[pullInfoStrength]->source) {
264
      biffAddf(PULL, "%s: %s info must come from %s (not %s)", me,
265
               airEnumStr(pullInfo, pullInfoStrength),
266
               airEnumStr(pullSource, pullSourceGage),
267
               airEnumStr(pullSource, pctx->ispec[pullInfoStrength]->source));
268
      return 1;
269
    }
270
  }
271
  if (pctx->ispec[pullInfoInside]) {
272
    if (!pctx->ispec[pullInfoInsideGradient]) {
273
      biffAddf(PULL, "%s: want %s but don't have %s set", me,
274
               airEnumStr(pullInfo, pullInfoInside),
275
               airEnumStr(pullInfo, pullInfoInsideGradient));
276
      return 1;
277
    }
278
  }
279
  if (pctx->ispec[pullInfoTangent2]) {
280
    if (!pctx->ispec[pullInfoTangent1]) {
281
      biffAddf(PULL, "%s: want %s but don't have %s set", me,
282
               airEnumStr(pullInfo, pullInfoTangent2),
283
               airEnumStr(pullInfo, pullInfoTangent1));
284
      return 1;
285
    }
286
  }
287
  if (pctx->ispec[pullInfoNegativeTangent2]) {
288
    if (!pctx->ispec[pullInfoNegativeTangent1]) {
289
      biffAddf(PULL, "%s: want %s but don't have %s set", me,
290
               airEnumStr(pullInfo, pullInfoNegativeTangent2),
291
               airEnumStr(pullInfo, pullInfoNegativeTangent1));
292
      return 1;
293
    }
294
  }
295
  ccount = 0;
296
  ccount += !!(pctx->ispec[pullInfoTangent1]);
297
  ccount += !!(pctx->ispec[pullInfoTangent2]);
298
  ccount += !!(pctx->ispec[pullInfoNegativeTangent1]);
299
  ccount += !!(pctx->ispec[pullInfoNegativeTangent2]);
300
  if (4 == ccount) {
301
    biffAddf(PULL, "%s: can't specify all 4 tangents together", me);
302
    return 1;
303
  }
304
  if (3 == ccount && !pctx->flag.allowCodimension3Constraints) {
305
    biffAddf(PULL, "%s: must turn on allowCodimension3Constraints "
306
             "with 3 tangents", me);
307
    return 1;
308
  }
309
  if (pctx->ispec[pullInfoHeight]) {
310
    if (!( pctx->ispec[pullInfoHeightGradient] )) {
311
      biffAddf(PULL, "%s: want %s but don't have %s set", me,
312
               airEnumStr(pullInfo, pullInfoHeight),
313
               airEnumStr(pullInfo, pullInfoHeightGradient));
314
      return 1;
315
    }
316
    if (pctx->ispec[pullInfoHeight]->constraint) {
317
      if (!pctx->ispec[pullInfoHeightHessian]) {
318
        biffAddf(PULL, "%s: want constrained %s but don't have %s set", me,
319
                 airEnumStr(pullInfo, pullInfoHeight),
320
                 airEnumStr(pullInfo, pullInfoHeightHessian));
321
        return 1;
322
      }
323
      if (!( pctx->ispec[pullInfoTangent1]
324
             || pctx->ispec[pullInfoNegativeTangent1] )) {
325
        if (!pctx->flag.allowCodimension3Constraints) {
326
          biffAddf(PULL, "%s: want constrained %s but need (at least) "
327
                   "%s or %s set (maybe enable "
328
                   "pullFlagAllowCodimension3Constraints?)",
329
                   me,
330
                   airEnumStr(pullInfo, pullInfoHeight),
331
                   airEnumStr(pullInfo, pullInfoTangent1),
332
                   airEnumStr(pullInfo, pullInfoNegativeTangent1));
333
          return 1;
334
        }
335
      }
336
    }
337
  }
338
  if (pctx->ispec[pullInfoHeightLaplacian]) {
339
    if (!( pctx->ispec[pullInfoHeight] )) {
340
      biffAddf(PULL, "%s: want %s but don't have %s set", me,
341
               airEnumStr(pullInfo, pullInfoHeightLaplacian),
342
               airEnumStr(pullInfo, pullInfoHeight));
343
      return 1;
344
    }
345
  }
346
  if (pctx->ispec[pullInfoIsovalue]) {
347
    if (!( pctx->ispec[pullInfoIsovalueGradient]
348
           && pctx->ispec[pullInfoIsovalueHessian] )) {
349
      biffAddf(PULL, "%s: want %s but don't have %s and %s set", me,
350
               airEnumStr(pullInfo, pullInfoIsovalue),
351
               airEnumStr(pullInfo, pullInfoIsovalueGradient),
352
               airEnumStr(pullInfo, pullInfoIsovalueHessian));
353
      return 1;
354
    }
355
  }
356
  if ((lthr = pctx->ispec[pullInfoLiveThresh])
357
      && (strn = pctx->ispec[pullInfoStrength])
358
      && lthr->volIdx == strn->volIdx
359
      && lthr->item == strn->item
360
      && lthr->scale*strn->scale < 0) {
361
    biffAddf(PULL, "%s: %s and %s refer to same item (%s in %s), but have "
362
             "scaling factors with different signs (%g and %g); really?", me,
363
             airEnumStr(pullInfo, pullInfoLiveThresh),
364
             airEnumStr(pullInfo, pullInfoStrength),
365
             airEnumStr(pctx->vol[lthr->volIdx]->kind->enm, lthr->item),
366
             lthr->volName, lthr->scale, strn->scale);
367
    return 1;
368
  }
369
  if (pullInitMethodPointPerVoxel == pctx->initParm.method) {
370
    if (!( pctx->ispec[pullInfoSeedThresh] )) {
371
      biffAddf(PULL, "%s: sorry, need to have %s info set with %s init",
372
               me, airEnumStr(pullInfo, pullInfoSeedThresh),
373
               "point-per-voxel" /* HEY no airEnum for this */);
374
      return 1;
375
    }
376
  }
377
378
  return 0;
379
}
380
381
/*
382
** the API for this is most certainly going to change; the
383
** tensor output at this point is a hack created for vis purposes
384
*/
385
int
386
pullOutputGetFilter(Nrrd *nPosOut, Nrrd *nTenOut, Nrrd *nStrengthOut,
387
                    const double _scaleVec[3], double scaleRad,
388
                    pullContext *pctx,
389
                    unsigned int idtagMin, unsigned int idtagMax) {
390
  static const char me[]="pullOutputGetFilter";
391
  unsigned int binIdx, pointNum, pointIdx, outIdx;
392
  int E;
393
  double *posOut, *tenOut, *strnOut, scaleVec[3], scaleDir[3], scaleMag;
394
  pullBin *bin;
395
  pullPoint *point;
396
397
  if (!pctx) {
398
    biffAddf(PULL, "%s: got NULL pointer", me);
399
    return 1;
400
  }
401
  if (nStrengthOut && !pctx->ispec[pullInfoStrength]) {
402
    biffAddf(PULL, "%s: can't save out %s info that hasn't been set",
403
             me, airEnumStr(pullInfo, pullInfoStrength));
404
    return 1;
405
  }
406
  if (!AIR_EXISTS(scaleRad)) {
407
    biffAddf(PULL, "%s: got non-existent scaleRad %g", me, scaleRad);
408
    return 1;
409
  }
410
  if (!_scaleVec) {
411
    ELL_3V_SET(scaleVec, 0, 0, 0);
412
    ELL_3V_SET(scaleDir, 0, 0, 0);
413
    scaleMag = 0;
414
  } else {
415
    ELL_3V_COPY(scaleVec, _scaleVec);
416
    if (ELL_3V_LEN(scaleVec)) {
417
      ELL_3V_NORM(scaleDir, scaleVec, scaleMag);
418
    } else {
419
      ELL_3V_SET(scaleDir, 0, 0, 0);
420
      scaleMag = 0;
421
    }
422
  }
423
  pointNum = pullPointNumberFilter(pctx, idtagMin, idtagMax);
424
  E = AIR_FALSE;
425
  if (nPosOut) {
426
    E |= nrrdMaybeAlloc_va(nPosOut, nrrdTypeDouble, 2,
427
                           AIR_CAST(size_t, 4),
428
                           AIR_CAST(size_t, pointNum));
429
  }
430
  if (nTenOut) {
431
    E |= nrrdMaybeAlloc_va(nTenOut, nrrdTypeDouble, 2,
432
                           AIR_CAST(size_t, 7),
433
                           AIR_CAST(size_t, pointNum));
434
  }
435
  if (nStrengthOut) {
436
    E |= nrrdMaybeAlloc_va(nStrengthOut, nrrdTypeDouble, 1,
437
                           AIR_CAST(size_t, pointNum));
438
  }
439
  if (E) {
440
    biffMovef(PULL, NRRD, "%s: trouble allocating outputs", me);
441
    return 1;
442
  }
443
  posOut = nPosOut ? (double*)(nPosOut->data) : NULL;
444
  tenOut = nTenOut ? (double*)(nTenOut->data) : NULL;
445
  strnOut = nStrengthOut ? (double*)(nStrengthOut->data) : NULL;
446
447
  outIdx = 0;
448
  for (binIdx=0; binIdx<pctx->binNum; binIdx++) {
449
    bin = pctx->bin + binIdx;
450
    for (pointIdx=0; pointIdx<bin->pointNum; pointIdx++) {
451
      point = bin->point[pointIdx];
452
      if (!( idtagMin <= point->idtag
453
             && (0 == idtagMax
454
                 || point->idtag <= idtagMax) )) {
455
        continue;
456
      }
457
      /** to find idtag of point at particular location **/
458
      /*
459
      if (AIR_ABS(514.113  - point->pos[0]) < 0.5 &&
460
          AIR_ABS(453.519 - point->pos[1]) < 0.5 &&
461
          AIR_ABS(606.723  - point->pos[ 2 ]) < 0.5) {
462
        printf("!%s: point %u at (%g,%g,%g,%g) ##############\n",
463
               me, point->idtag,
464
               point->pos[0], point->pos[1],
465
               point->pos[2], point->pos[3]);
466
      }
467
      */
468
      if (nPosOut) {
469
        ELL_4V_COPY(posOut + 4*outIdx, point->pos);
470
        if (pctx->haveScale && scaleMag) {
471
          double *tpos, tvec[3], sc;
472
          tpos = posOut + 4*outIdx;
473
          sc = ELL_3V_DOT(tpos, scaleDir);
474
          ELL_3V_SCALE(tvec, sc, scaleDir);
475
          ELL_3V_SUB(tpos, tpos, tvec);
476
          ELL_3V_SCALE(tvec, scaleMag*tpos[3], scaleDir);
477
          ELL_3V_ADD2(tpos, tpos, tvec);
478
        }
479
        /*
480
        if (4523 == point->idtag) {
481
          fprintf(stderr, "!%s: point %u at index %u and pos %g %g %g %g\n",
482
                  me, point->idtag, outIdx,
483
                  (posOut + 4*outIdx)[0], (posOut + 4*outIdx)[1],
484
                  (posOut + 4*outIdx)[2], (posOut + 4*outIdx)[3]);
485
        }
486
        */
487
      }
488
      if (nStrengthOut) {
489
        strnOut[outIdx] = pullPointScalar(pctx, point, pullInfoStrength,
490
                                          NULL, NULL);
491
      }
492
      if (nTenOut) {
493
        double scl, tout[7];
494
        scl = 1;
495
        if (pctx->ispec[pullInfoTensor]) {
496
          TEN_T_COPY(tout, point->info + pctx->infoIdx[pullInfoTensor]);
497
        } else if (pctx->ispec[pullInfoHeightHessian]) {
498
          double *hess, eval[3], evec[9], eceil, maxeval, elen;
499
          unsigned int maxi;
500
          hess = point->info + pctx->infoIdx[pullInfoHeightHessian];
501
          if (0) {
502
            /* do this if using general symmetric tensor glyphs */
503
            TEN_M2T(tout, hess);
504
            tout[0] = 1.0;
505
          } if (0) {
506
            /* for spheres and only spheres */
507
            TEN_T_SET(tout, 1, 1, 0, 0, 1, 0, 1);
508
          } else {
509
            ell_3m_eigensolve_d(eval, evec, hess, 10);
510
            eval[0] = AIR_ABS(eval[0]);
511
            eval[1] = AIR_ABS(eval[1]);
512
            eval[2] = AIR_ABS(eval[2]);
513
            /* elen = ELL_3V_LEN(eval); */
514
            elen = (eval[0]+eval[1]+eval[2]);
515
            eceil = elen ? 10/elen : 10;
516
            eval[0] = eval[0] ? AIR_MIN(eceil, 1.0/eval[0]) : eceil;
517
            eval[1] = eval[1] ? AIR_MIN(eceil, 1.0/eval[1]) : eceil;
518
            eval[2] = eval[2] ? AIR_MIN(eceil, 1.0/eval[2]) : eceil;
519
            maxi = ELL_MAX3_IDX(eval[0], eval[1], eval[2]);
520
            maxeval = eval[maxi];
521
            ELL_3V_SCALE(eval, 1/maxeval, eval);
522
            tenMakeSingle_d(tout, 1, eval, evec);
523
            if (scaleRad && pctx->ispec[pullInfoHeight]->constraint) {
524
              double emin, sig;
525
              if (pctx->flag.scaleIsTau) {
526
                sig = gageSigOfTau(point->pos[3]);
527
              } else {
528
                sig = point->pos[3];
529
              }
530
              tenEigensolve_d(eval, evec, tout);  /* lazy way to sort */
531
              emin = eval[2];
532
              if (1 == pctx->constraintDim) {
533
                eval[1] = scaleRad*sig + emin/2;
534
                eval[2] = scaleRad*sig + emin/2;
535
              } if (2 == pctx->constraintDim) {
536
                double eavg;
537
                eavg = (2*eval[0] + eval[2])/3;
538
                eval[0] = eavg;
539
                eval[1] = eavg;
540
                eval[2] = scaleRad*sig + emin/2;
541
              }
542
              tenMakeSingle_d(tout, 1, eval, evec);
543
            }
544
          }
545
        } else if (0   /* another hack for general symmetric tensor glyphs */
546
                   && pctx->constraint
547
                   && (pctx->ispec[pullInfoIsovalueHessian])) {
548
          double *hess;
549
          hess = point->info + pctx->infoIdx[pullInfoIsovalueHessian];
550
          TEN_M2T(tout, hess);
551
          tout[0] = 1.0;
552
        } else if (pctx->constraint
553
                   && (pctx->ispec[pullInfoHeightGradient]
554
                       || pctx->ispec[pullInfoIsovalueGradient])) {
555
          double *grad, norm[3], len, mat[9], out[9];
556
          grad = point->info + (pctx->ispec[pullInfoHeightGradient]
557
                                ? pctx->infoIdx[pullInfoHeightGradient]
558
                                : pctx->infoIdx[pullInfoIsovalueGradient]);
559
          ELL_3V_NORM(norm, grad, len);
560
          ELL_3MV_OUTER(out, norm, norm);
561
          ELL_3M_IDENTITY_SET(mat);
562
          ELL_3M_SCALE_INCR(mat, -0.95, out);
563
          TEN_M2T(tout, mat);
564
          tout[0] = 1;
565
        } else {
566
          TEN_T_SET(tout, 1, 1, 0, 0, 1, 0, 1);
567
        }
568
        TEN_T_SCALE(tout, scl, tout);
569
        TEN_T_COPY(tenOut + 7*outIdx, tout);
570
        /*
571
        if (4523 == point->idtag) {
572
          fprintf(stderr, "!%s: point %u at index %u and ten (%g) %g %g %g %g %g %g\n",
573
                  me, point->idtag, outIdx,
574
                  tout[0], tout[1], tout[2], tout[3],
575
                  tout[4], tout[5], tout[6]);
576
        }
577
        */
578
      } /* if (nTenOut) */
579
      ++outIdx;
580
    }
581
  }
582
583
  return 0;
584
}
585
586
int
587
pullOutputGet(Nrrd *nPosOut, Nrrd *nTenOut, Nrrd *nStrengthOut,
588
              const double scaleVec[3], double scaleRad,
589
              pullContext *pctx) {
590
  static const char me[]="pullOutputGet";
591
592
  if (pullOutputGetFilter(nPosOut, nTenOut, nStrengthOut, scaleVec, scaleRad, pctx, 0, 0)) {
593
    biffAddf(PULL, "%s: trouble", me);
594
    return 1;
595
  }
596
  return 0;
597
}
598
599
600
int
601
pullPropGet(Nrrd *nprop, int prop, pullContext *pctx) {
602
  static const char me[]="pullPropGet";
603
  int typeOut;
604
  size_t size[2];
605
  unsigned int dim, pointNum, pointIdx, binIdx, *out_ui, outIdx;
606
  double *out_d, covar[16];
607
  float *out_f, *pnc;
608
  unsigned char *out_uc;
609
  pullBin *bin;
610
  pullPoint *point;
611
612
  pointNum = pullPointNumber(pctx);
613
  switch(prop) {
614
  case pullPropEnergy:
615
  case pullPropStepEnergy:
616
  case pullPropStepConstr:
617
  case pullPropScale:
618
  case pullPropNeighCovarTrace:
619
  case pullPropNeighCovarDet:
620
  case pullPropStability:
621
    dim = 1;
622
    size[0] = pointNum;
623
    typeOut = nrrdTypeDouble;
624
    break;
625
  case pullPropIdtag:
626
  case pullPropIdCC:
627
  case pullPropNeighInterNum:
628
    dim = 1;
629
    size[0] = pointNum;
630
    typeOut = nrrdTypeUInt;
631
    break;
632
  case pullPropStuck:
633
    dim = 1;
634
    size[0] = pointNum;
635
    /* HEY should be nrrdTypeUInt, no? */
636
    typeOut = nrrdTypeUChar;
637
    break;
638
  case pullPropPosition:
639
  case pullPropForce:
640
    dim = 2;
641
    size[0] = 4;
642
    size[1] = pointNum;
643
    typeOut = nrrdTypeDouble;
644
    break;
645
  case pullPropNeighDistMean:
646
    dim = 1;
647
    size[0] = pointNum;
648
    typeOut = nrrdTypeDouble;
649
    break;
650
  case pullPropNeighCovar:
651
    dim = 2;
652
    size[0] = 10;
653
    size[1] = pointNum;
654
    typeOut = nrrdTypeFloat;
655
    break;
656
  case pullPropNeighCovar7Ten:
657
  case pullPropNeighTanCovar:
658
    dim = 2;
659
    size[0] = 7;
660
    size[1] = pointNum;
661
    typeOut = nrrdTypeFloat;
662
    break;
663
  default:
664
    biffAddf(PULL, "%s: prop %d unrecognized", me, prop);
665
    return 1;
666
    break;
667
  }
668
  if (nrrdMaybeAlloc_nva(nprop, typeOut, dim, size)) {
669
    biffMovef(PULL, NRRD, "%s: trouble allocating output", me);
670
    return 1;
671
  }
672
  out_d = AIR_CAST(double *, nprop->data);
673
  out_f = AIR_CAST(float *, nprop->data);
674
  out_ui = AIR_CAST(unsigned int *, nprop->data);
675
  out_uc = AIR_CAST(unsigned char *, nprop->data);
676
677
  outIdx = 0;
678
  for (binIdx=0; binIdx<pctx->binNum; binIdx++) {
679
    bin = pctx->bin + binIdx;
680
    for (pointIdx=0; pointIdx<bin->pointNum; pointIdx++) {
681
      point = bin->point[pointIdx];
682
      pnc = point->neighCovar;
683
      switch(prop) {
684
      case pullPropEnergy:
685
        out_d[outIdx] = point->energy;
686
        break;
687
      case pullPropStepEnergy:
688
        out_d[outIdx] = point->stepEnergy;
689
        break;
690
      case pullPropStepConstr:
691
        out_d[outIdx] = point->stepConstr;
692
        break;
693
      case pullPropIdtag:
694
        out_ui[outIdx] = point->idtag;
695
        break;
696
      case pullPropIdCC:
697
        out_ui[outIdx] = point->idCC;
698
        break;
699
      case pullPropNeighInterNum:
700
        out_ui[outIdx] = point->neighInterNum;
701
        break;
702
      case pullPropStuck:
703
        out_uc[outIdx] = ((point->status & PULL_STATUS_STUCK_BIT)
704
                          ? point->stuckIterNum
705
                          : 0);
706
        break;
707
      case pullPropPosition:
708
        ELL_4V_COPY(out_d + 4*outIdx, point->pos);
709
        break;
710
      case pullPropForce:
711
        ELL_4V_COPY(out_d + 4*outIdx, point->force);
712
        break;
713
      case pullPropNeighDistMean:
714
        out_d[outIdx] = point->neighDistMean;
715
        break;
716
      case pullPropScale:
717
        out_d[outIdx] = (pctx->flag.scaleIsTau
718
                         ? gageSigOfTau(point->pos[3])
719
                         : point->pos[3]);
720
        break;
721
        /*
722
          0:xx 1:xy 2:xz 3:xs
723
          1    4:yy 5:yz 6:ys
724
          2    5    7:zz 8:zs
725
          3    6    8    9:ss
726
        */
727
      case pullPropNeighCovar:
728
        ELL_10V_COPY(out_f + 10*outIdx, point->neighCovar);
729
        break;
730
      case pullPropNeighCovar7Ten:
731
        TEN_T_SET(out_f + 7*outIdx, 1.0f,
732
                  pnc[0],
733
                  pnc[1],
734
                  pnc[2],
735
                  pnc[4],
736
                  pnc[5],
737
                  pnc[7]);
738
        break;
739
      case pullPropNeighTanCovar:
740
#if PULL_TANCOVAR
741
        TEN_T_SET(out_f + 7*outIdx, 1.0f,
742
                  point->neighTanCovar[0],
743
                  point->neighTanCovar[1],
744
                  point->neighTanCovar[2],
745
                  point->neighTanCovar[3],
746
                  point->neighTanCovar[4],
747
                  point->neighTanCovar[5]);
748
#else
749
        TEN_T_SET(out_f + 7*outIdx, 0.0f,
750
                  0.0f, 0.0f, 0.0f,
751
                  0.0f, 0.0f,
752
                  0.0f);
753
#endif
754
        break;
755
      case pullPropNeighCovarTrace:
756
        out_d[outIdx] = pnc[0] + pnc[4] + pnc[7] + pnc[9];
757
        break;
758
      case pullPropNeighCovarDet:
759
        if (pctx->haveScale) {
760
          ELL_4V_SET(covar +  0, pnc[0], pnc[1], pnc[2], pnc[3]);
761
          ELL_4V_SET(covar +  4, pnc[1], pnc[4], pnc[5], pnc[6]);
762
          ELL_4V_SET(covar +  8, pnc[2], pnc[5], pnc[7], pnc[8]);
763
          ELL_4V_SET(covar + 12, pnc[3], pnc[6], pnc[8], pnc[9]);
764
          out_d[outIdx] = ELL_4M_DET(covar);
765
        } else {
766
          ELL_3V_SET(covar +  0, pnc[0], pnc[1], pnc[2]);
767
          ELL_3V_SET(covar +  3, pnc[1], pnc[4], pnc[5]);
768
          ELL_3V_SET(covar +  6, pnc[2], pnc[5], pnc[7]);
769
          out_d[outIdx] = ELL_3M_DET(covar);
770
        }
771
        break;
772
      case pullPropStability:
773
        out_d[outIdx] = point->stability;
774
        break;
775
      default:
776
        biffAddf(PULL, "%s: prop %d unrecognized", me, prop);
777
        return 1;
778
        break;
779
      }
780
      ++outIdx;
781
    } /* for (pointIdx) */
782
  }
783
784
  return 0;
785
}
786
787
/*
788
** extract history as single array, possibly specific to only a single point0
789
*/
790
int
791
pullPositionHistoryNrrdGet(Nrrd *nhist, pullContext *pctx, pullPoint *point0) {
792
  static const char me[]="pullPositionHistoryNrrdGet";
793
#if PULL_PHIST
794
  pullBin *bin;
795
  unsigned int binIdx, pointIdx, stepNum, stepIdx, phistIdx, phistNum, ii;
796
  double *hist;
797
798
  if (!(nhist && pctx)) {
799
    biffAddf(PULL, "%s: got NULL pointer", me);
800
    return 1;
801
  }
802
803
  if (!point0) {
804
    stepNum = 0;
805
    for (binIdx=0; binIdx<pctx->binNum; binIdx++) {
806
      bin = pctx->bin + binIdx;
807
      for (pointIdx=0; pointIdx<bin->pointNum; pointIdx++) {
808
        pullPoint *point;
809
        point = bin->point[pointIdx];
810
        stepNum += point->phistArr->len;
811
      }
812
    }
813
  } else {
814
    stepNum = point0->phistArr->len;
815
  }
816
  if (nrrdMaybeAlloc_va(nhist, nrrdTypeDouble, 2,
817
                        AIR_CAST(size_t, 1 + _PHN),
818
                        AIR_CAST(size_t, stepNum))) {
819
    biffMovef(PULL, NRRD, "%s: couldn't allocate output", me);
820
    return 1;
821
  }
822
  hist = AIR_CAST(double *, nhist->data);
823
  stepIdx = 0;
824
  if (!point0) {
825
    for (binIdx=0; binIdx<pctx->binNum; binIdx++) {
826
      bin = pctx->bin + binIdx;
827
      for (pointIdx=0; pointIdx<bin->pointNum; pointIdx++) {
828
        pullPoint *point;
829
        point = bin->point[pointIdx];
830
        phistNum = point->phistArr->len;
831
        for (phistIdx=0; phistIdx<phistNum; phistIdx++) {
832
          double *hh;
833
          hh = hist + stepIdx*(1 + _PHN);
834
          hh[0] = AIR_CAST(double, point->idtag);
835
          for (ii=0; ii<_PHN; ii++) {
836
            hh[ii+1] = (point->phist + _PHN*phistIdx)[ii];
837
          }
838
          stepIdx++;
839
        }
840
      }
841
    }
842
  } else {
843
    for (stepIdx=0; stepIdx<stepNum; stepIdx++) {
844
      double *hh;
845
      hh = hist + stepIdx*(1 + _PHN);
846
      hh[0] = AIR_CAST(double, point0->idtag);
847
      for (ii=0; ii<_PHN; ii++) {
848
        hh[ii+1] = (point0->phist + _PHN*stepIdx)[ii];
849
      }
850
    }
851
  }
852
853
  return 0;
854
#else
855
  AIR_UNUSED(nhist);
856
  AIR_UNUSED(pctx);
857
  AIR_UNUSED(point0);
858
  biffAddf(PULL, "%s: sorry, not compiled with PULL_PHIST", me);
859
  return 1;
860
#endif
861
}
862
863
int
864
pullPositionHistoryPolydataGet(limnPolyData *pld, pullContext *pctx) {
865
  static const char me[]="pullPositionHistoryPolydataGet";
866
#if PULL_PHIST
867
  pullBin *bin;
868
  pullPoint *point;
869
  unsigned int binIdx, pointIdx, pointNum, vertNum, vertIdx,
870
    primIdx, phistIdx, phistNum;
871
872
  if (!(pld && pctx)) {
873
    biffAddf(PULL, "%s: got NULL pointer", me);
874
    return 1;
875
  }
876
877
  pointNum = 0;
878
  vertNum = 0;
879
  for (binIdx=0; binIdx<pctx->binNum; binIdx++) {
880
    bin = pctx->bin + binIdx;
881
    for (pointIdx=0; pointIdx<bin->pointNum; pointIdx++) {
882
      point = bin->point[pointIdx];
883
      vertNum += point->phistArr->len;
884
      pointNum++;
885
    }
886
  }
887
  if (limnPolyDataAlloc(pld, 1 << limnPolyDataInfoRGBA,
888
                        vertNum, vertNum, pointNum)) {
889
    biffMovef(PULL, LIMN, "%s: couldn't allocate output", me);
890
    return 1;
891
  }
892
  primIdx = 0;
893
  vertIdx = 0;
894
  for (binIdx=0; binIdx<pctx->binNum; binIdx++) {
895
    bin = pctx->bin + binIdx;
896
    for (pointIdx=0; pointIdx<bin->pointNum; pointIdx++) {
897
      point = bin->point[pointIdx];
898
      phistNum = point->phistArr->len;
899
      for (phistIdx=0; phistIdx<phistNum; phistIdx++) {
900
        int cond;
901
        unsigned char rgb[3];
902
        ELL_3V_SET(rgb, 0, 0, 0);
903
        ELL_3V_COPY(pld->xyzw + 4*vertIdx, point->phist + 5*phistIdx);
904
        (pld->xyzw + 4*vertIdx)[3] = 1;
905
        cond = AIR_CAST(int, (point->phist + 5*phistIdx)[4]);
906
        switch (cond) {
907
        case pullCondOld:
908
          ELL_3V_SET(rgb, 128, 128, 128);
909
          break;
910
        case pullCondConstraintSatA:
911
          ELL_3V_SET(rgb, 0, 255, 0);
912
          break;
913
        case pullCondConstraintSatB:
914
          ELL_3V_SET(rgb, 0, 0, 255);
915
          break;
916
        case pullCondEnergyTry:
917
          ELL_3V_SET(rgb, 255, 255, 255);
918
          break;
919
        case pullCondEnergyBad:
920
          ELL_3V_SET(rgb, 255, 0, 0);
921
          break;
922
        case pullCondConstraintFail:
923
          ELL_3V_SET(rgb, 255, 0, 255);
924
          break;
925
        case pullCondNew:
926
          ELL_3V_SET(rgb, 128, 255, 128);
927
          break;
928
        }
929
        ELL_4V_SET(pld->rgba + 4*vertIdx, rgb[0], rgb[1], rgb[2], 255);
930
        pld->indx[vertIdx] = vertIdx;
931
        vertIdx++;
932
      }
933
      pld->type[primIdx] = limnPrimitiveLineStrip;
934
      pld->icnt[primIdx] = phistNum;
935
      primIdx++;
936
    }
937
  }
938
939
  return 0;
940
#else
941
  AIR_UNUSED(pld);
942
  AIR_UNUSED(pctx);
943
  biffAddf(PULL, "%s: sorry, not compiled with PULL_PHIST", me);
944
  return 1;
945
#endif
946
}
947