1 /*
2 Teem: Tools to process and visualize scientific data and images .
3 Copyright (C) 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 "ten.h"
25 #include "privateTen.h"
26
27 tenGradientParm *
tenGradientParmNew(void)28 tenGradientParmNew(void) {
29 tenGradientParm *ret;
30
31 ret = (tenGradientParm *)calloc(1, sizeof(tenGradientParm));
32 if (ret) {
33 ret->initStep = 1.0;
34 ret->jitter = 0.2;
35 ret->minVelocity = 0.000000001;
36 ret->minPotentialChange = 0.000000001;
37 ret->minMean = 0.0001;
38 ret->minMeanImprovement = 0.00005;
39 ret->single = AIR_FALSE;
40 ret->insertZeroVec = AIR_FALSE;
41 ret->verbose = 1;
42 ret->snap = 0;
43 ret->report = 400;
44 ret->expo = 1;
45 ret->expo_d = 0;
46 ret->seed = 42;
47 ret->maxEdgeShrink = 20;
48 ret->minIteration = 0;
49 ret->maxIteration = 1000000;
50 ret->step = 0;
51 ret->nudge = 0;
52 ret->itersUsed = 0;
53 ret->potential = 0;
54 ret->potentialNorm = 0;
55 ret->angle = 0;
56 ret->edge = 0;
57 }
58 return ret;
59 }
60
61 tenGradientParm *
tenGradientParmNix(tenGradientParm * tgparm)62 tenGradientParmNix(tenGradientParm *tgparm) {
63
64 airFree(tgparm);
65 return NULL;
66 }
67
68 int
tenGradientCheck(const Nrrd * ngrad,int type,unsigned int minnum)69 tenGradientCheck(const Nrrd *ngrad, int type, unsigned int minnum) {
70 static const char me[]="tenGradientCheck";
71
72 if (nrrdCheck(ngrad)) {
73 biffMovef(TEN, NRRD, "%s: basic validity check failed", me);
74 return 1;
75 }
76 if (!( 3 == ngrad->axis[0].size && 2 == ngrad->dim )) {
77 char stmp[AIR_STRLEN_SMALL];
78 biffAddf(TEN, "%s: need a 3xN 2-D array (not a %sx? %u-D array)", me,
79 airSprintSize_t(stmp, ngrad->axis[0].size), ngrad->dim);
80 return 1;
81 }
82 if (nrrdTypeDefault != type && type != ngrad->type) {
83 biffAddf(TEN, "%s: requested type %s but got type %s", me,
84 airEnumStr(nrrdType, type), airEnumStr(nrrdType, ngrad->type));
85 return 1;
86 }
87 if (nrrdTypeBlock == ngrad->type) {
88 biffAddf(TEN, "%s: sorry, can't use %s type", me,
89 airEnumStr(nrrdType, nrrdTypeBlock));
90 return 1;
91 }
92 if (!( minnum <= ngrad->axis[1].size )) {
93 char stmp[AIR_STRLEN_SMALL];
94 biffAddf(TEN, "%s: have only %s gradients, need at least %d", me,
95 airSprintSize_t(stmp, ngrad->axis[1].size), minnum);
96 return 1;
97 }
98
99 return 0;
100 }
101
102 /*
103 ******** tenGradientRandom
104 **
105 ** generates num random unit vectors of type double
106 */
107 int
tenGradientRandom(Nrrd * ngrad,unsigned int num,unsigned int seed)108 tenGradientRandom(Nrrd *ngrad, unsigned int num, unsigned int seed) {
109 static const char me[]="tenGradientRandom";
110 double *grad, len;
111 unsigned int gi;
112
113 if (nrrdMaybeAlloc_va(ngrad, nrrdTypeDouble, 2,
114 AIR_CAST(size_t, 3), AIR_CAST(size_t, num))) {
115 biffMovef(TEN, NRRD, "%s: couldn't allocate output", me);
116 return 1;
117 }
118 airSrandMT(seed);
119 grad = AIR_CAST(double*, ngrad->data);
120 for (gi=0; gi<num; gi++) {
121 do {
122 grad[0] = AIR_AFFINE(0, airDrandMT(), 1, -1, 1);
123 grad[1] = AIR_AFFINE(0, airDrandMT(), 1, -1, 1);
124 grad[2] = AIR_AFFINE(0, airDrandMT(), 1, -1, 1);
125 len = ELL_3V_LEN(grad);
126 } while (len > 1 || !len);
127 ELL_3V_SCALE(grad, 1.0/len, grad);
128 grad += 3;
129 }
130 return 0;
131 }
132
133 /*
134 ******** tenGradientIdealEdge
135 **
136 ** edge length of delauney triangulation of idealized distribution of
137 ** N gradients (2*N points), but also allowing a boolean "single" flag
138 ** saying that we actually care about N points
139 */
140 double
tenGradientIdealEdge(unsigned int N,int single)141 tenGradientIdealEdge(unsigned int N, int single) {
142
143 return sqrt((!single ? 4 : 8)*AIR_PI/(sqrt(3)*N));
144 }
145
146 /*
147 ******** tenGradientJitter
148 **
149 ** moves all gradients by amount dist on tangent plane, in a random
150 ** direction, and then renormalizes. The distance is a fraction
151 ** of the ideal edge length (via tenGradientIdealEdge)
152 */
153 int
tenGradientJitter(Nrrd * nout,const Nrrd * nin,double dist)154 tenGradientJitter(Nrrd *nout, const Nrrd *nin, double dist) {
155 static const char me[]="tenGradientJitter";
156 double *grad, perp0[3], perp1[3], len, theta, cc, ss, edge;
157 unsigned int gi, num;
158
159 if (nrrdConvert(nout, nin, nrrdTypeDouble)) {
160 biffMovef(TEN, NRRD, "%s: trouble converting input to double", me);
161 return 1;
162 }
163 if (tenGradientCheck(nout, nrrdTypeDouble, 3)) {
164 biffAddf(TEN, "%s: didn't get valid gradients", me);
165 return 1;
166 }
167 grad = AIR_CAST(double*, nout->data);
168 num = AIR_UINT(nout->axis[1].size);
169 /* HEY: possible confusion between single and not */
170 edge = tenGradientIdealEdge(num, AIR_FALSE);
171 for (gi=0; gi<num; gi++) {
172 ELL_3V_NORM(grad, grad, len);
173 ell_3v_perp_d(perp0, grad);
174 ELL_3V_CROSS(perp1, perp0, grad);
175 theta = AIR_AFFINE(0, airDrandMT(), 1, 0, 2*AIR_PI);
176 cc = dist*edge*cos(theta);
177 ss = dist*edge*sin(theta);
178 ELL_3V_SCALE_ADD3(grad, 1.0, grad, cc, perp0, ss, perp1);
179 ELL_3V_NORM(grad, grad, len);
180 grad += 3;
181 }
182
183 return 0;
184 }
185
186 void
tenGradientMeasure(double * pot,double * minAngle,double * minEdge,const Nrrd * npos,tenGradientParm * tgparm,int edgeNormalize)187 tenGradientMeasure(double *pot, double *minAngle, double *minEdge,
188 const Nrrd *npos, tenGradientParm *tgparm,
189 int edgeNormalize) {
190 /* static const char me[]="tenGradientMeasure"; */
191 double diff[3], *pos, atmp=0, ptmp, edge, len;
192 unsigned int ii, jj, num;
193
194 /* allow minAngle NULL */
195 if (!(pot && npos && tgparm )) {
196 return;
197 }
198
199 num = AIR_UINT(npos->axis[1].size);
200 pos = AIR_CAST(double *, npos->data);
201 edge = (edgeNormalize
202 ? tenGradientIdealEdge(num, tgparm->single)
203 : 1.0);
204 *pot = 0;
205 if (minAngle) {
206 *minAngle = AIR_PI;
207 }
208 if (minEdge) {
209 *minEdge = 2;
210 }
211 for (ii=0; ii<num; ii++) {
212 for (jj=0; jj<ii; jj++) {
213 ELL_3V_SUB(diff, pos + 3*ii, pos + 3*jj);
214 len = ELL_3V_LEN(diff);
215 if (minEdge) {
216 *minEdge = AIR_MIN(*minEdge, len);
217 }
218 if (tgparm->expo) {
219 ptmp = airIntPow(edge/len, tgparm->expo);
220 } else {
221 ptmp = pow(edge/len, tgparm->expo_d);
222 }
223 *pot += ptmp;
224 if (minAngle) {
225 atmp = ell_3v_angle_d(pos + 3*ii, pos + 3*jj);
226 *minAngle = AIR_MIN(atmp, *minAngle);
227 }
228 if (!tgparm->single) {
229 *pot += ptmp;
230 ELL_3V_ADD2(diff, pos + 3*ii, pos + 3*jj);
231 len = ELL_3V_LEN(diff);
232 if (minEdge) {
233 *minEdge = AIR_MIN(*minEdge, len);
234 }
235 if (tgparm->expo) {
236 *pot += 2*airIntPow(edge/len, tgparm->expo);
237 } else {
238 *pot += 2*pow(edge/len, tgparm->expo_d);
239 }
240 if (minAngle) {
241 *minAngle = AIR_MIN(AIR_PI-atmp, *minAngle);
242 }
243 }
244 }
245 }
246 return;
247 }
248
249 /*
250 ** Do asynchronous update of positions in "npos', based on force
251 ** calculations wherein the distances are normalized "edge". Using a
252 ** small "edge" allows forces to either underflow to zero, or be
253 ** finite, instead of exploding to infinity, for high exponents.
254 **
255 ** The smallest seen edge length is recorded in "*edgeMin", which is
256 ** initialized to the given "edge". This allows, for example, the
257 ** caller to try again with a smaller edge normalization.
258 **
259 ** The mean velocity of the points through the update is recorded in
260 ** "*meanVel".
261 **
262 ** Based on the observation that when using large exponents, numerical
263 ** difficulties arise from the (force-based) update of the positions
264 ** of the two (or few) closest particles, this function puts a speed
265 ** limit (variable "limit") on the distance a particle may move during
266 ** update, expressed as a fraction of the normalizing edge length.
267 ** "limit" has been set heuristically, according to the exponent (we
268 ** have to clamp speeds more aggresively with higher exponents), as
269 ** well as (even more heuristically) according to the number of times
270 ** the step size has been decreased. This latter factor has to be
271 ** bounded, so that the update is not unnecessarily bounded when the
272 ** step size gets very small at the last stages of computation.
273 ** Without the step-size-based speed limit, the step size would
274 ** sometimes (e.g. num=200, expo=300) have to reduced to a miniscule
275 ** value, which slows subsequent convergence terribly.
276 **
277 ** this function is not static, though it could be, so that mac's
278 ** "Sampler" app can profile this
279 */
280 int
_tenGradientUpdate(double * meanVel,double * edgeMin,Nrrd * npos,double edge,tenGradientParm * tgparm)281 _tenGradientUpdate(double *meanVel, double *edgeMin,
282 Nrrd *npos, double edge, tenGradientParm *tgparm) {
283 /* static const char me[]="_tenGradientUpdate"; */
284 double *pos, newpos[3], grad[3], ngrad[3],
285 dir[3], len, rep, step, diff[3], limit, expo;
286 int num, ii, jj, E;
287
288 E = 0;
289 pos = AIR_CAST(double *, npos->data);
290 num = AIR_UINT(npos->axis[1].size);
291 *meanVel = 0;
292 *edgeMin = edge;
293 expo = tgparm->expo ? tgparm->expo : tgparm->expo_d;
294 limit = expo*AIR_MIN(sqrt(expo),
295 log(1 + tgparm->initStep/tgparm->step));
296 for (ii=0; ii<num; ii++) {
297 ELL_3V_SET(grad, 0, 0, 0);
298 for (jj=0; jj<num; jj++) {
299 if (ii == jj) {
300 continue;
301 }
302 ELL_3V_SUB(dir, pos + 3*ii, pos + 3*jj);
303 ELL_3V_NORM(dir, dir, len);
304 *edgeMin = AIR_MIN(*edgeMin, len);
305 if (tgparm->expo) {
306 rep = airIntPow(edge/len, tgparm->expo+1);
307 } else {
308 rep = pow(edge/len, tgparm->expo_d+1);
309 }
310 ELL_3V_SCALE_INCR(grad, rep/num, dir);
311 if (!tgparm->single) {
312 ELL_3V_ADD2(dir, pos + 3*ii, pos + 3*jj);
313 ELL_3V_NORM(dir, dir, len);
314 *edgeMin = AIR_MIN(*edgeMin, len);
315 if (tgparm->expo) {
316 rep = airIntPow(edge/len, tgparm->expo+1);
317 } else {
318 rep = pow(edge/len, tgparm->expo_d+1);
319 }
320 ELL_3V_SCALE_INCR(grad, rep/num, dir);
321 }
322 }
323 ELL_3V_NORM(ngrad, grad, len);
324 if (!( AIR_EXISTS(len) )) {
325 /* things blew up, either in incremental force
326 additions, or in the attempt at normalization */
327 E = 1;
328 *meanVel = AIR_NAN;
329 break;
330 }
331 if (0 == len) {
332 /* if the length of grad[] underflowed to zero, we can
333 legitimately zero out ngrad[] */
334 ELL_3V_SET(ngrad, 0, 0, 0);
335 }
336 step = AIR_MIN(len*tgparm->step, edge/limit);
337 ELL_3V_SCALE_ADD2(newpos,
338 1.0, pos + 3*ii,
339 step, ngrad);
340 ELL_3V_NORM(newpos, newpos, len);
341 ELL_3V_SUB(diff, pos + 3*ii, newpos);
342 *meanVel += ELL_3V_LEN(diff);
343 ELL_3V_COPY(pos + 3*ii, newpos);
344 }
345 *meanVel /= num;
346
347 return E;
348 }
349
350 /*
351 ** assign random signs to the vectors and measures the length of their
352 ** mean, as quickly as possible
353 */
354 static double
party(Nrrd * npos,airRandMTState * rstate)355 party(Nrrd *npos, airRandMTState *rstate) {
356 double *pos, mean[3];
357 unsigned int ii, num, rnd, rndBit;
358
359 pos = (double *)(npos->data);
360 num = AIR_UINT(npos->axis[1].size);
361 rnd = airUIrandMT_r(rstate);
362 rndBit = 0;
363 ELL_3V_SET(mean, 0, 0, 0);
364 for (ii=0; ii<num; ii++) {
365 if (32 == rndBit) {
366 rnd = airUIrandMT_r(rstate);
367 rndBit = 0;
368 }
369 if (rnd & (1 << rndBit++)) {
370 ELL_3V_SCALE(pos + 3*ii, -1, pos + 3*ii);
371 }
372 ELL_3V_INCR(mean, pos + 3*ii);
373 }
374 ELL_3V_SCALE(mean, 1.0/num, mean);
375 return ELL_3V_LEN(mean);
376 }
377
378 /*
379 ** parties until the gradients settle down
380 */
381 int
tenGradientBalance(Nrrd * nout,const Nrrd * nin,tenGradientParm * tgparm)382 tenGradientBalance(Nrrd *nout, const Nrrd *nin,
383 tenGradientParm *tgparm) {
384 static const char me[]="tenGradientBalance";
385 double len, lastLen, improv;
386 airRandMTState *rstate;
387 Nrrd *ncopy;
388 unsigned int iter, maxIter;
389 int done;
390 airArray *mop;
391
392 if (!nout || tenGradientCheck(nin, nrrdTypeUnknown, 2) || !tgparm) {
393 biffAddf(TEN, "%s: got NULL pointer (%p,%p) or invalid nin", me,
394 AIR_VOIDP(nout), AIR_VOIDP(tgparm));
395 return 1;
396 }
397 if (nrrdConvert(nout, nin, nrrdTypeDouble)) {
398 biffMovef(TEN, NRRD, "%s: can't initialize output with input", me);
399 return 1;
400 }
401
402 mop = airMopNew();
403 ncopy = nrrdNew();
404 airMopAdd(mop, ncopy, (airMopper)nrrdNuke, airMopAlways);
405 rstate = airRandMTStateNew(tgparm->seed);
406 airMopAdd(mop, rstate, (airMopper)airRandMTStateNix, airMopAlways);
407 /* HEY: factor of 100 is an approximate hack */
408 maxIter = 100*tgparm->maxIteration;
409
410 lastLen = 1.0;
411 done = AIR_FALSE;
412 do {
413 iter = 0;
414 do {
415 iter++;
416 len = party(nout, rstate);
417 } while (len > lastLen && iter < maxIter);
418 if (iter >= maxIter) {
419 if (tgparm->verbose) {
420 fprintf(stderr, "%s: stopping at max iter %u\n", me, maxIter);
421 }
422 if (nrrdCopy(nout, ncopy)) {
423 biffMovef(TEN, NRRD, "%s: trouble copying", me);
424 airMopError(mop); return 1;
425 }
426 done = AIR_TRUE;
427 } else {
428 if (nrrdCopy(ncopy, nout)) {
429 biffMovef(TEN, NRRD, "%s: trouble copying", me);
430 airMopError(mop); return 1;
431 }
432 improv = lastLen - len;
433 lastLen = len;
434 if (tgparm->verbose) {
435 fprintf(stderr, "%s: (iter %u) improvement: %g (mean length = %g)\n",
436 me, iter, improv, len);
437 }
438 done = (improv <= tgparm->minMeanImprovement
439 || len < tgparm->minMean);
440 }
441 } while (!done);
442
443 airMopOkay(mop);
444 return 0;
445 }
446
447 /*
448 ******** tenGradientDistribute
449 **
450 ** Takes the given list of gradients, normalizes their lengths,
451 ** optionally jitters their positions, does point repulsion, and then
452 ** (optionally) selects a combination of directions with minimum vector sum.
453 **
454 ** The complicated part of this is the point repulsion, which uses a
455 ** gradient descent with variable set size. The progress of the system
456 ** is measured by decrease in potential (when its measurement doesn't
457 ** overflow to infinity) or an increase in the minimum angle. When a
458 ** step results in negative progress, the step size is halved, and the
459 ** iteration is attempted again. Based on the observation that at
460 ** some points the step size must be made very small to get progress,
461 ** the step size is cautiously increased ("nudged") at every
462 ** iteration, to try to avoid using an overly small step. The amount
463 ** by which the step is nudged is halved everytime the step is halved,
464 ** to avoid endless cycling through step sizes.
465 */
466 int
tenGradientDistribute(Nrrd * nout,const Nrrd * nin,tenGradientParm * tgparm)467 tenGradientDistribute(Nrrd *nout, const Nrrd *nin,
468 tenGradientParm *tgparm) {
469 static const char me[]="tenGradientDistribute";
470 char filename[AIR_STRLEN_SMALL];
471 unsigned int ii, num, iter, oldIdx, newIdx, edgeShrink;
472 airArray *mop;
473 Nrrd *npos[2];
474 double *pos, len, meanVelocity, pot, potNew, potD,
475 edge, edgeMin, angle, angleNew;
476 int E;
477
478 if (!nout || tenGradientCheck(nin, nrrdTypeUnknown, 2) || !tgparm) {
479 biffAddf(TEN, "%s: got NULL pointer or invalid input", me);
480 return 1;
481 }
482
483 num = AIR_UINT(nin->axis[1].size);
484 mop = airMopNew();
485 npos[0] = nrrdNew();
486 npos[1] = nrrdNew();
487 airMopAdd(mop, npos[0], (airMopper)nrrdNuke, airMopAlways);
488 airMopAdd(mop, npos[1], (airMopper)nrrdNuke, airMopAlways);
489 if (nrrdConvert(npos[0], nin, nrrdTypeDouble)
490 || nrrdConvert(npos[1], nin, nrrdTypeDouble)) {
491 biffMovef(TEN, NRRD, "%s: trouble allocating temp buffers", me);
492 airMopError(mop); return 1;
493 }
494
495 pos = (double*)(npos[0]->data);
496 for (ii=0; ii<num; ii++) {
497 ELL_3V_NORM(pos, pos, len);
498 pos += 3;
499 }
500 if (tgparm->jitter) {
501 if (tenGradientJitter(npos[0], npos[0], tgparm->jitter)) {
502 biffAddf(TEN, "%s: problem jittering input", me);
503 airMopError(mop); return 1;
504 }
505 }
506
507 /* initialize things prior to first iteration; have to
508 make sure that loop body tests pass 1st time around */
509 meanVelocity = 2*tgparm->minVelocity;
510 potD = -2*tgparm->minPotentialChange;
511 oldIdx = 0;
512 newIdx = 1;
513 tgparm->step = tgparm->initStep;
514 tgparm->nudge = 0.1;
515 tenGradientMeasure(&pot, &angle, NULL,
516 npos[oldIdx], tgparm, AIR_TRUE);
517 for (iter = 0;
518 ((!!tgparm->minIteration && iter < tgparm->minIteration)
519 ||
520 (iter < tgparm->maxIteration
521 && (!tgparm->minPotentialChange
522 || !AIR_EXISTS(potD)
523 || -potD > tgparm->minPotentialChange)
524 && (!tgparm->minVelocity
525 || meanVelocity > tgparm->minVelocity)
526 && tgparm->step > FLT_MIN));
527 iter++) {
528 /* copy positions from old to new */
529 memcpy(npos[newIdx]->data, npos[oldIdx]->data, 3*num*sizeof(double));
530 edge = tenGradientIdealEdge(num, tgparm->single);
531 edgeShrink = 0;
532 /* try to do a position update, which will fail if repulsion values
533 explode, from having an insufficiently small edge normalization,
534 so retry with smaller edge next time */
535 do {
536 E = _tenGradientUpdate(&meanVelocity, &edgeMin,
537 npos[newIdx], edge, tgparm);
538 if (E) {
539 if (edgeShrink > tgparm->maxEdgeShrink) {
540 biffAddf(TEN, "%s: %u > %u edge shrinks (%g), update still failed",
541 me, edgeShrink, tgparm->maxEdgeShrink, edge);
542 airMopError(mop); return 1;
543 }
544 edgeShrink++;
545 /* re-initialize positions (HEY ugly code logic) */
546 memcpy(npos[newIdx]->data, npos[oldIdx]->data, 3*num*sizeof(double));
547 edge = edgeMin;
548 }
549 } while (E);
550 tenGradientMeasure(&potNew, &angleNew, NULL,
551 npos[newIdx], tgparm, AIR_TRUE);
552 if ((AIR_EXISTS(pot) && AIR_EXISTS(potNew) && potNew <= pot)
553 || angleNew >= angle) {
554 /* there was progress of some kind, either through potential
555 decrease, or angle increase */
556 potD = 2*(potNew - pot)/(potNew + pot);
557 if (!(iter % tgparm->report) && tgparm->verbose) {
558 fprintf(stderr, "%s(%d): . . . . . . step = %g, edgeShrink = %u\n"
559 " velo = %g<>%g, phi = %g ~ %g<>%g, angle = %g ~ %g\n",
560 me, iter, tgparm->step, edgeShrink,
561 meanVelocity, tgparm->minVelocity,
562 pot, potD, tgparm->minPotentialChange,
563 angle, angleNew - angle);
564 }
565 if (tgparm->snap && !(iter % tgparm->snap)) {
566 sprintf(filename, "%05d.nrrd", iter/tgparm->snap);
567 if (tgparm->verbose) {
568 fprintf(stderr, "%s(%d): . . . . . . saving %s\n",
569 me, iter, filename);
570 }
571 if (nrrdSave(filename, npos[newIdx], NULL)) {
572 char *serr;
573 serr = biffGetDone(NRRD);
574 if (tgparm->verbose) { /* perhaps shouldn't have this check */
575 fprintf(stderr, "%s: iter=%d, couldn't save snapshot:\n%s"
576 "continuing ...\n", me, iter, serr);
577 }
578 free(serr);
579 }
580 }
581 tgparm->step *= 1 + tgparm->nudge;
582 tgparm->step = AIR_MIN(tgparm->initStep, tgparm->step);
583 pot = potNew;
584 angle = angleNew;
585 /* swap buffers */
586 newIdx = 1 - newIdx;
587 oldIdx = 1 - oldIdx;
588 } else {
589 /* oops, did not make progress; back off and try again */
590 if (tgparm->verbose) {
591 fprintf(stderr, "%s(%d): ######## step %g --> %g\n"
592 " phi = %g --> %g ~ %g, angle = %g --> %g\n",
593 me, iter, tgparm->step, tgparm->step/2,
594 pot, potNew, potD, angle, angleNew);
595 }
596 tgparm->step /= 2;
597 tgparm->nudge /= 2;
598 }
599 }
600
601 /* when the for-loop test fails, we stop before computing the next
602 iteration (which starts with copying from npos[oldIdx] to
603 npos[newIdx]) ==> the final results are in npos[oldIdx] */
604
605 if (tgparm->verbose) {
606 fprintf(stderr, "%s: .......................... done distribution:\n"
607 " (%d && %d) || (%d \n"
608 " && (%d || %d || %d) \n"
609 " && (%d || %d) \n"
610 " && %d) is false\n", me,
611 !!tgparm->minIteration, iter < tgparm->minIteration,
612 iter < tgparm->maxIteration,
613 !tgparm->minPotentialChange,
614 !AIR_EXISTS(potD), AIR_ABS(potD) > tgparm->minPotentialChange,
615 !tgparm->minVelocity, meanVelocity > tgparm->minVelocity,
616 tgparm->step > FLT_MIN);
617 fprintf(stderr, " iter=%d, velo = %g<>%g, phi = %g ~ %g<>%g;\n",
618 iter, meanVelocity, tgparm->minVelocity, pot,
619 potD, tgparm->minPotentialChange);
620 fprintf(stderr, " minEdge = %g; idealEdge = %g\n",
621 2*sin(angle/2), tenGradientIdealEdge(num, tgparm->single));
622 }
623
624 tenGradientMeasure(&pot, NULL, NULL, npos[oldIdx], tgparm, AIR_FALSE);
625 tgparm->potential = pot;
626 tenGradientMeasure(&pot, &angle, &edge, npos[oldIdx], tgparm, AIR_TRUE);
627 tgparm->potentialNorm = pot;
628 tgparm->angle = angle;
629 tgparm->edge = edge;
630 tgparm->itersUsed = iter;
631
632 if ((tgparm->minMeanImprovement || tgparm->minMean)
633 && !tgparm->single) {
634 if (tgparm->verbose) {
635 fprintf(stderr, "%s: optimizing balance:\n", me);
636 }
637 if (tenGradientBalance(nout, npos[oldIdx], tgparm)) {
638 biffAddf(TEN, "%s: failed to minimize vector sum of gradients", me);
639 airMopError(mop); return 1;
640 }
641 if (tgparm->verbose) {
642 fprintf(stderr, "%s: .......................... done balancing.\n", me);
643 }
644 } else {
645 if (tgparm->verbose) {
646 fprintf(stderr, "%s: .......................... (no balancing)\n", me);
647 }
648 if (nrrdConvert(nout, npos[oldIdx], nrrdTypeDouble)) {
649 biffMovef(TEN, NRRD, "%s: couldn't set output", me);
650 airMopError(mop); return 1;
651 }
652 }
653
654 airMopOkay(mop);
655 return 0;
656 }
657
658 /*
659 ** note that if tgparm->insertZeroVec, there will be one sample more
660 ** along axis 1 of nout than the requested #gradients "num"
661 */
662 int
tenGradientGenerate(Nrrd * nout,unsigned int num,tenGradientParm * tgparm)663 tenGradientGenerate(Nrrd *nout, unsigned int num, tenGradientParm *tgparm) {
664 static const char me[]="tenGradientGenerate";
665 Nrrd *nin;
666 airArray *mop;
667
668 if (!(nout && tgparm)) {
669 biffAddf(TEN, "%s: got NULL pointer", me);
670 return 1;
671 }
672 if (!( num >= 3 )) {
673 biffAddf(TEN, "%s: can generate minimum of 3 gradient directions "
674 "(not %d)", me, num);
675 return 1;
676 }
677 mop = airMopNew();
678 nin = nrrdNew();
679 airMopAdd(mop, nin, (airMopper)nrrdNuke, airMopAlways);
680
681 if (tenGradientRandom(nin, num, tgparm->seed)
682 || tenGradientDistribute(nout, nin, tgparm)) {
683 biffAddf(TEN, "%s: trouble", me);
684 airMopError(mop); return 1;
685 }
686 if (tgparm->insertZeroVec) {
687 /* this is potentially confusing: the second axis (axis 1)
688 is going to come back one longer than the requested
689 number of gradients! */
690 Nrrd *ntmp;
691 ptrdiff_t padMin[2] = {0, -1}, padMax[2];
692 padMax[0] = AIR_CAST(ptrdiff_t, nout->axis[0].size-1);
693 padMax[1] = AIR_CAST(ptrdiff_t, num-1);
694 ntmp = nrrdNew();
695 airMopAdd(mop, ntmp, (airMopper)nrrdNuke, airMopAlways);
696 if (nrrdPad_nva(ntmp, nout, padMin, padMax,
697 nrrdBoundaryPad, 0.0)
698 || nrrdCopy(nout, ntmp)) {
699 biffMovef(TEN, NRRD, "%s: trouble adding zero vector", me);
700 airMopError(mop); return 1;
701 }
702 }
703
704 airMopOkay(mop);
705 return 0;
706 }
707