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 |
|
|
#define DEBUG 1 |
29 |
|
|
|
30 |
|
|
/* |
31 |
|
|
** HEY: this has to be threadsafe, at least threadsafe when there |
32 |
|
|
** are no errors, because this can now be called from multiple |
33 |
|
|
** tasks during population control |
34 |
|
|
*/ |
35 |
|
|
pullPoint * |
36 |
|
|
pullPointNew(pullContext *pctx) { |
37 |
|
|
static const char me[]="pullPointNew"; |
38 |
|
|
pullPoint *pnt; |
39 |
|
|
unsigned int ii; |
40 |
|
|
size_t pntSize; |
41 |
|
|
pullPtrPtrUnion pppu; |
42 |
|
|
|
43 |
|
|
if (!pctx) { |
44 |
|
|
biffAddf(PULL, "%s: got NULL pointer", me); |
45 |
|
|
return NULL; |
46 |
|
|
} |
47 |
|
|
if (!pctx->infoTotalLen) { |
48 |
|
|
biffAddf(PULL, "%s: can't allocate points w/out infoTotalLen set\n", me); |
49 |
|
|
return NULL; |
50 |
|
|
} |
51 |
|
|
/* Allocate the pullPoint so that it has pctx->infoTotalLen doubles. |
52 |
|
|
The pullPoint declaration has info[1], hence the "- 1" below */ |
53 |
|
|
pntSize = sizeof(pullPoint) + sizeof(double)*(pctx->infoTotalLen - 1); |
54 |
|
|
pnt = AIR_CAST(pullPoint *, calloc(1, pntSize)); |
55 |
|
|
if (!pnt) { |
56 |
|
|
biffAddf(PULL, "%s: couldn't allocate point (info len %u)\n", me, |
57 |
|
|
pctx->infoTotalLen - 1); |
58 |
|
|
return NULL; |
59 |
|
|
} |
60 |
|
|
|
61 |
|
|
pnt->idtag = pctx->idtagNext++; |
62 |
|
|
pnt->idCC = 0; |
63 |
|
|
pnt->neighPoint = NULL; |
64 |
|
|
pnt->neighPointNum = 0; |
65 |
|
|
pppu.points = &(pnt->neighPoint); |
66 |
|
|
pnt->neighPointArr = airArrayNew(pppu.v, &(pnt->neighPointNum), |
67 |
|
|
sizeof(pullPoint *), |
68 |
|
|
PULL_POINT_NEIGH_INCR); |
69 |
|
|
pnt->neighPointArr->noReallocWhenSmaller = AIR_TRUE; |
70 |
|
|
pnt->neighDistMean = 0; |
71 |
|
|
ELL_10V_ZERO_SET(pnt->neighCovar); |
72 |
|
|
pnt->stability = 0.0; |
73 |
|
|
#if PULL_TANCOVAR |
74 |
|
|
ELL_6V_ZERO_SET(pnt->neighTanCovar); |
75 |
|
|
#endif |
76 |
|
|
pnt->neighInterNum = 0; |
77 |
|
|
pnt->stuckIterNum = 0; |
78 |
|
|
#if PULL_PHIST |
79 |
|
|
pnt->phist = NULL; |
80 |
|
|
pnt->phistNum = 0; |
81 |
|
|
pnt->phistArr = airArrayNew(AIR_CAST(void**, &(pnt->phist)), |
82 |
|
|
&(pnt->phistNum), |
83 |
|
|
_PHN*sizeof(double), 32); |
84 |
|
|
#endif |
85 |
|
|
pnt->status = 0; |
86 |
|
|
ELL_4V_SET(pnt->pos, AIR_NAN, AIR_NAN, AIR_NAN, AIR_NAN); |
87 |
|
|
pnt->energy = AIR_NAN; |
88 |
|
|
ELL_4V_SET(pnt->force, AIR_NAN, AIR_NAN, AIR_NAN, AIR_NAN); |
89 |
|
|
pnt->stepEnergy = pctx->sysParm.stepInitial; |
90 |
|
|
pnt->stepConstr = pctx->sysParm.stepInitial; |
91 |
|
|
for (ii=0; ii<pctx->infoTotalLen; ii++) { |
92 |
|
|
pnt->info[ii] = AIR_NAN; |
93 |
|
|
} |
94 |
|
|
return pnt; |
95 |
|
|
} |
96 |
|
|
|
97 |
|
|
pullPoint * |
98 |
|
|
pullPointNix(pullPoint *pnt) { |
99 |
|
|
|
100 |
|
|
pnt->neighPointArr = airArrayNuke(pnt->neighPointArr); |
101 |
|
|
#if PULL_PHIST |
102 |
|
|
pnt->phistArr = airArrayNuke(pnt->phistArr); |
103 |
|
|
#endif |
104 |
|
|
airFree(pnt); |
105 |
|
|
return NULL; |
106 |
|
|
} |
107 |
|
|
|
108 |
|
|
#if PULL_PHIST |
109 |
|
|
void |
110 |
|
|
_pullPointHistInit(pullPoint *point) { |
111 |
|
|
|
112 |
|
|
airArrayLenSet(point->phistArr, 0); |
113 |
|
|
return; |
114 |
|
|
} |
115 |
|
|
|
116 |
|
|
void |
117 |
|
|
_pullPointHistAdd(pullPoint *point, int cond, double val) { |
118 |
|
|
static const char me[]="_pullPointHistAdd"; |
119 |
|
|
unsigned int phistIdx; |
120 |
|
|
|
121 |
|
|
phistIdx = airArrayLenIncr(point->phistArr, 1); |
122 |
|
|
ELL_4V_COPY(point->phist + _PHN*phistIdx, point->pos); |
123 |
|
|
|
124 |
|
|
fprintf(stderr, "!%s: point %p pos = %.17g %.17g %.17g %.17g (%g)\n", me, |
125 |
|
|
point, point->pos[0], point->pos[1], point->pos[2], point->pos[3], |
126 |
|
|
val); |
127 |
|
|
|
128 |
|
|
(point->phist + _PHN*phistIdx)[4] = cond; |
129 |
|
|
(point->phist + _PHN*phistIdx)[5] = val; |
130 |
|
|
return; |
131 |
|
|
} |
132 |
|
|
#endif |
133 |
|
|
|
134 |
|
|
/* |
135 |
|
|
** HEY: there should be something like a "map" over all the points, |
136 |
|
|
** which could implement all these redundant functions |
137 |
|
|
*/ |
138 |
|
|
|
139 |
|
|
unsigned int |
140 |
|
|
pullPointNumberFilter(const pullContext *pctx, |
141 |
|
|
unsigned int idtagMin, |
142 |
|
|
unsigned int idtagMax) { |
143 |
|
|
unsigned int binIdx, pointNum; |
144 |
|
|
const pullBin *bin; |
145 |
|
|
const pullPoint *point; |
146 |
|
|
|
147 |
|
|
pointNum = 0; |
148 |
|
|
for (binIdx=0; binIdx<pctx->binNum; binIdx++) { |
149 |
|
|
unsigned int pointIdx; |
150 |
|
|
bin = pctx->bin + binIdx; |
151 |
|
|
if (0 == idtagMin && 0 == idtagMax) { |
152 |
|
|
pointNum += bin->pointNum; |
153 |
|
|
} else { |
154 |
|
|
for (pointIdx=0; pointIdx<bin->pointNum; pointIdx++) { |
155 |
|
|
point = bin->point[pointIdx]; |
156 |
|
|
pointNum += (idtagMin <= point->idtag |
157 |
|
|
&& (0 == idtagMax |
158 |
|
|
|| point->idtag <= idtagMax)); |
159 |
|
|
} |
160 |
|
|
} |
161 |
|
|
} |
162 |
|
|
return pointNum; |
163 |
|
|
} |
164 |
|
|
|
165 |
|
|
unsigned int |
166 |
|
|
pullPointNumber(const pullContext *pctx) { |
167 |
|
|
|
168 |
|
|
return pullPointNumberFilter(pctx, 0, 0); |
169 |
|
|
} |
170 |
|
|
|
171 |
|
|
double |
172 |
|
|
_pullEnergyTotal(const pullContext *pctx) { |
173 |
|
|
unsigned int binIdx, pointIdx; |
174 |
|
|
const pullBin *bin; |
175 |
|
|
const pullPoint *point; |
176 |
|
|
double sum; |
177 |
|
|
|
178 |
|
|
sum = 0; |
179 |
|
|
for (binIdx=0; binIdx<pctx->binNum; binIdx++) { |
180 |
|
|
bin = pctx->bin + binIdx; |
181 |
|
|
for (pointIdx=0; pointIdx<bin->pointNum; pointIdx++) { |
182 |
|
|
point = bin->point[pointIdx]; |
183 |
|
|
sum += point->energy; |
184 |
|
|
} |
185 |
|
|
} |
186 |
|
|
return sum; |
187 |
|
|
} |
188 |
|
|
|
189 |
|
|
void |
190 |
|
|
_pullPointStepEnergyScale(pullContext *pctx, double scale) { |
191 |
|
|
unsigned int binIdx, pointIdx; |
192 |
|
|
const pullBin *bin; |
193 |
|
|
pullPoint *point; |
194 |
|
|
|
195 |
|
|
for (binIdx=0; binIdx<pctx->binNum; binIdx++) { |
196 |
|
|
bin = pctx->bin + binIdx; |
197 |
|
|
for (pointIdx=0; pointIdx<bin->pointNum; pointIdx++) { |
198 |
|
|
point = bin->point[pointIdx]; |
199 |
|
|
point->stepEnergy *= scale; |
200 |
|
|
point->stepEnergy = AIR_MIN(point->stepEnergy, |
201 |
|
|
_PULL_STEP_ENERGY_MAX); |
202 |
|
|
} |
203 |
|
|
} |
204 |
|
|
return; |
205 |
|
|
} |
206 |
|
|
|
207 |
|
|
double |
208 |
|
|
_pullStepInterAverage(const pullContext *pctx) { |
209 |
|
|
unsigned int binIdx, pointIdx, pointNum; |
210 |
|
|
const pullBin *bin; |
211 |
|
|
const pullPoint *point; |
212 |
|
|
double sum, avg; |
213 |
|
|
|
214 |
|
|
sum = 0; |
215 |
|
|
pointNum = 0; |
216 |
|
|
for (binIdx=0; binIdx<pctx->binNum; binIdx++) { |
217 |
|
|
bin = pctx->bin + binIdx; |
218 |
|
|
pointNum += bin->pointNum; |
219 |
|
|
for (pointIdx=0; pointIdx<bin->pointNum; pointIdx++) { |
220 |
|
|
point = bin->point[pointIdx]; |
221 |
|
|
sum += point->stepEnergy; |
222 |
|
|
} |
223 |
|
|
} |
224 |
|
|
avg = (!pointNum ? AIR_NAN : sum/pointNum); |
225 |
|
|
return avg; |
226 |
|
|
} |
227 |
|
|
/* ^^^ vvv HEY HEY HEY: COPY + PASTE COPY + PASTE COPY + PASTE */ |
228 |
|
|
double |
229 |
|
|
_pullStepConstrAverage(const pullContext *pctx) { |
230 |
|
|
unsigned int binIdx, pointIdx, pointNum; |
231 |
|
|
const pullBin *bin; |
232 |
|
|
const pullPoint *point; |
233 |
|
|
double sum, avg; |
234 |
|
|
|
235 |
|
|
sum = 0; |
236 |
|
|
pointNum = 0; |
237 |
|
|
for (binIdx=0; binIdx<pctx->binNum; binIdx++) { |
238 |
|
|
bin = pctx->bin + binIdx; |
239 |
|
|
pointNum += bin->pointNum; |
240 |
|
|
for (pointIdx=0; pointIdx<bin->pointNum; pointIdx++) { |
241 |
|
|
point = bin->point[pointIdx]; |
242 |
|
|
sum += point->stepConstr; |
243 |
|
|
} |
244 |
|
|
} |
245 |
|
|
avg = (!pointNum ? AIR_NAN : sum/pointNum); |
246 |
|
|
return avg; |
247 |
|
|
} |
248 |
|
|
|
249 |
|
|
/* |
250 |
|
|
** convenience function for learning a scalar AND its gradient or hessian |
251 |
|
|
** |
252 |
|
|
*/ |
253 |
|
|
double |
254 |
|
|
pullPointScalar(const pullContext *pctx, const pullPoint *point, int sclInfo, |
255 |
|
|
/* output */ |
256 |
|
|
double grad[3], double hess[9]) { |
257 |
|
|
static const char me[]="pullPointScalar"; |
258 |
|
|
double scl; |
259 |
|
|
const pullInfoSpec *ispec; |
260 |
|
|
int gradInfo[1+PULL_INFO_MAX] = { |
261 |
|
|
0, /* pullInfoUnknown */ |
262 |
|
|
0, /* pullInfoTensor */ |
263 |
|
|
0, /* pullInfoTensorInverse */ |
264 |
|
|
0, /* pullInfoHessian */ |
265 |
|
|
pullInfoInsideGradient, /* pullInfoInside */ |
266 |
|
|
0, /* pullInfoInsideGradient */ |
267 |
|
|
pullInfoHeightGradient, /* pullInfoHeight */ |
268 |
|
|
0, /* pullInfoHeightGradient */ |
269 |
|
|
0, /* pullInfoHeightHessian */ |
270 |
|
|
0, /* pullInfoHeightLaplacian */ |
271 |
|
|
0, /* pullInfoSeedPreThresh */ |
272 |
|
|
0, /* pullInfoSeedThresh */ |
273 |
|
|
0, /* pullInfoLiveThresh */ |
274 |
|
|
0, /* pullInfoLiveThresh2 */ |
275 |
|
|
0, /* pullInfoLiveThresh3 */ |
276 |
|
|
0, /* pullInfoTangent1 */ |
277 |
|
|
0, /* pullInfoTangent2 */ |
278 |
|
|
0, /* pullInfoNegativeTangent1 */ |
279 |
|
|
0, /* pullInfoNegativeTangent2 */ |
280 |
|
|
pullInfoIsovalueGradient, /* pullInfoIsovalue */ |
281 |
|
|
0, /* pullInfoIsovalueGradient */ |
282 |
|
|
0, /* pullInfoIsovalueHessian */ |
283 |
|
|
0, /* pullInfoStrength */ |
284 |
|
|
}; |
285 |
|
|
int hessInfo[1+PULL_INFO_MAX] = { |
286 |
|
|
0, /* pullInfoUnknown */ |
287 |
|
|
0, /* pullInfoTensor */ |
288 |
|
|
0, /* pullInfoTensorInverse */ |
289 |
|
|
0, /* pullInfoHessian */ |
290 |
|
|
0, /* pullInfoInside */ |
291 |
|
|
0, /* pullInfoInsideGradient */ |
292 |
|
|
pullInfoHeightHessian, /* pullInfoHeight */ |
293 |
|
|
0, /* pullInfoHeightGradient */ |
294 |
|
|
0, /* pullInfoHeightHessian */ |
295 |
|
|
0, /* pullInfoHeightLaplacian */ |
296 |
|
|
0, /* pullInfoSeedPreThresh */ |
297 |
|
|
0, /* pullInfoSeedThresh */ |
298 |
|
|
0, /* pullInfoLiveThresh */ |
299 |
|
|
0, /* pullInfoLiveThresh2 */ |
300 |
|
|
0, /* pullInfoLiveThresh3 */ |
301 |
|
|
0, /* pullInfoTangent1 */ |
302 |
|
|
0, /* pullInfoTangent2 */ |
303 |
|
|
0, /* pullInfoNegativeTangent1 */ |
304 |
|
|
0, /* pullInfoNegativeTangent2 */ |
305 |
|
|
pullInfoIsovalueHessian, /* pullInfoIsovalue */ |
306 |
|
|
0, /* pullInfoIsovalueGradient */ |
307 |
|
|
0, /* pullInfoIsovalueHessian */ |
308 |
|
|
0, /* pullInfoStrength */ |
309 |
|
|
}; |
310 |
|
|
const unsigned int *infoIdx; |
311 |
|
|
|
312 |
|
|
infoIdx = pctx->infoIdx; |
313 |
|
|
ispec = pctx->ispec[sclInfo]; |
314 |
|
|
/* NB: this "scl" is not scale-space scale; its the scaling |
315 |
|
|
of the scalar. this is getting confusing ... */ |
316 |
|
|
scl = point->info[infoIdx[sclInfo]]; |
317 |
|
|
scl = (scl - ispec->zero)*ispec->scale; |
318 |
|
|
/* if (289 == pctx->iter) { |
319 |
|
|
fprintf(stderr, "!%s(%04u,%s)@(%g,%g): (%g - %g)*%g == %g\n", |
320 |
|
|
me, point->idtag, airEnumStr(pullInfo, sclInfo), |
321 |
|
|
point->pos[0], point->pos[1], |
322 |
|
|
point->info[infoIdx[sclInfo]], ispec->zero, ispec->scale, scl); |
323 |
|
|
} */ |
324 |
|
|
if (0 && _pullVerbose) { |
325 |
|
|
if (pullInfoSeedThresh == sclInfo) { |
326 |
|
|
printf("!%s: seed thresh (%g - %g)*%g == %g\n", me, |
327 |
|
|
point->info[infoIdx[sclInfo]], ispec->zero, ispec->scale, scl); |
328 |
|
|
} |
329 |
|
|
} |
330 |
|
|
/* |
331 |
|
|
learned: this wasn't thought through: the idea was that the height |
332 |
|
|
*laplacian* answer should be transformed by the *height* zero and |
333 |
|
|
scale. scale might make sense, but not zero. This cost a few |
334 |
|
|
hours of tracking down the fact that the first zero-crossing |
335 |
|
|
detection phase of the lapl constraint was failing because the |
336 |
|
|
laplacian was vacillating around hspec->zero, not 0.0 . . . |
337 |
|
|
if (pullInfoHeightLaplacian == sclInfo) { |
338 |
|
|
const pullInfoSpec *hspec; |
339 |
|
|
hspec = pctx->ispec[pullInfoHeight]; |
340 |
|
|
scl = (scl - hspec->zero)*hspec->scale; |
341 |
|
|
} else { |
342 |
|
|
scl = (scl - ispec->zero)*ispec->scale; |
343 |
|
|
} |
344 |
|
|
*/ |
345 |
|
|
/* |
346 |
|
|
fprintf(stderr, "!%s: %s = (%g - %g)*%g = %g*%g = %g = %g\n", me, |
347 |
|
|
airEnumStr(pullInfo, sclInfo), |
348 |
|
|
point->info[infoIdx[sclInfo]], |
349 |
|
|
ispec->zero, ispec->scale, |
350 |
|
|
point->info[infoIdx[sclInfo]] - ispec->zero, ispec->scale, |
351 |
|
|
(point->info[infoIdx[sclInfo]] - ispec->zero)*ispec->scale, |
352 |
|
|
scl); |
353 |
|
|
*/ |
354 |
|
|
if (grad && gradInfo[sclInfo]) { |
355 |
|
|
const double *ptr = point->info + infoIdx[gradInfo[sclInfo]]; |
356 |
|
|
ELL_3V_SCALE(grad, ispec->scale, ptr); |
357 |
|
|
} |
358 |
|
|
if (hess && hessInfo[sclInfo]) { |
359 |
|
|
const double *ptr = point->info + infoIdx[hessInfo[sclInfo]]; |
360 |
|
|
ELL_3M_SCALE(hess, ispec->scale, ptr); |
361 |
|
|
} |
362 |
|
|
return scl; |
363 |
|
|
} |
364 |
|
|
|
365 |
|
|
int |
366 |
|
|
pullProbe(pullTask *task, pullPoint *point) { |
367 |
|
|
static const char me[]="pullProbe"; |
368 |
|
|
unsigned int ii, gret=0; |
369 |
|
|
int edge; |
370 |
|
|
/* |
371 |
|
|
fprintf(stderr, "!%s: task->probeSeedPreThreshOnly = %d\n", me, |
372 |
|
|
task->probeSeedPreThreshOnly); |
373 |
|
|
*/ |
374 |
|
|
#if 0 |
375 |
|
|
static int opened=AIR_FALSE; |
376 |
|
|
static FILE *flog; |
377 |
|
|
#endif |
378 |
|
|
|
379 |
|
|
/* |
380 |
|
|
fprintf(stderr, "%s(%u,%u): A volNum = %u\n", me, task->pctx->iter, point->idtag,task->pctx->volNum); |
381 |
|
|
*/ |
382 |
|
|
#if 0 |
383 |
|
|
static int logIdx=0, logDone=AIR_FALSE, logStarted=AIR_FALSE; |
384 |
|
|
static Nrrd *nlog; |
385 |
|
|
static double *log=NULL; |
386 |
|
|
if (!logStarted) { |
387 |
|
|
if (81 == point->idtag) { |
388 |
|
|
printf("\n\n%s: ###### HELLO begin logging . . .\n\n\n", me); |
389 |
|
|
/* knowing the logIdx at the end of logging . . . */ |
390 |
|
|
nlog = nrrdNew(); |
391 |
|
|
nrrdMaybeAlloc_va(nlog, nrrdTypeDouble, 2, |
392 |
|
|
AIR_CAST(size_t, 25), |
393 |
|
|
AIR_CAST(size_t, 2754)); |
394 |
|
|
log = AIR_CAST(double*, nlog->data); |
395 |
|
|
logStarted = AIR_TRUE; |
396 |
|
|
} |
397 |
|
|
} |
398 |
|
|
#endif |
399 |
|
|
|
400 |
|
|
if (!ELL_4V_EXISTS(point->pos)) { |
401 |
|
|
fprintf(stderr, "%s: pnt %u non-exist pos (%g,%g,%g,%g)\n\n!!!\n\n\n", |
402 |
|
|
me, point->idtag, point->pos[0], point->pos[1], |
403 |
|
|
point->pos[2], point->pos[3]); |
404 |
|
|
biffAddf(PULL, "%s: pnt %u non-exist pos (%g,%g,%g,%g)", |
405 |
|
|
me, point->idtag, point->pos[0], point->pos[1], |
406 |
|
|
point->pos[2], point->pos[3]); |
407 |
|
|
return 1; |
408 |
|
|
/* can't probe, but make it go away as quickly as possible */ |
409 |
|
|
/* |
410 |
|
|
ELL_4V_SET(point->pos, 0, 0, 0, 0); |
411 |
|
|
point->status |= PULL_STATUS_NIXME_BIT; |
412 |
|
|
return 0; |
413 |
|
|
*/ |
414 |
|
|
} |
415 |
|
|
if (task->pctx->verbose > 3) { |
416 |
|
|
printf("%s: hello; probing %u volumes\n", me, task->pctx->volNum); |
417 |
|
|
} |
418 |
|
|
edge = AIR_FALSE; |
419 |
|
|
task->pctx->count[pullCountProbe] += 1; |
420 |
|
|
/* |
421 |
|
|
fprintf(stderr, "%s(%u,%u): B volNum = %u\n", me, task->pctx->iter, point->idtag,task->pctx->volNum); |
422 |
|
|
*/ |
423 |
|
|
for (ii=0; ii<task->pctx->volNum; ii++) { |
424 |
|
|
pullVolume *vol; |
425 |
|
|
vol = task->vol[ii]; |
426 |
|
|
if (task->probeSeedPreThreshOnly |
427 |
|
|
&& !(vol->forSeedPreThresh)) { |
428 |
|
|
/* we're here *only* to probe SeedPreThresh, |
429 |
|
|
and this volume isn't used for that */ |
430 |
|
|
continue; |
431 |
|
|
} |
432 |
|
|
if (task->pctx->iter && vol->seedOnly) { |
433 |
|
|
/* its after the 1st iteration (#0), and this vol is only for seeding */ |
434 |
|
|
continue; |
435 |
|
|
} |
436 |
|
|
/* HEY should task->vol[ii]->scaleNum be the using-scale-space test? */ |
437 |
|
|
if (!task->vol[ii]->ninScale) { |
438 |
|
|
gret = gageProbeSpace(task->vol[ii]->gctx, |
439 |
|
|
point->pos[0], point->pos[1], point->pos[2], |
440 |
|
|
AIR_FALSE /* index-space */, |
441 |
|
|
AIR_TRUE /* clamp */); |
442 |
|
|
} else { |
443 |
|
|
if (task->pctx->verbose > 3) { |
444 |
|
|
printf("%s: vol[%u] has scale (%u)-> " |
445 |
|
|
"gageStackProbeSpace(%p) (v %d)\n", |
446 |
|
|
me, ii, task->vol[ii]->scaleNum, |
447 |
|
|
AIR_VOIDP(task->vol[ii]->gctx), |
448 |
|
|
task->vol[ii]->gctx->verbose); |
449 |
|
|
} |
450 |
|
|
/* |
451 |
|
|
if (81 == point->idtag) { |
452 |
|
|
printf("%s: probing vol[%u] @ %g %g %g %g\n", me, ii, |
453 |
|
|
point->pos[0], point->pos[1], point->pos[2], point->pos[3]); |
454 |
|
|
} |
455 |
|
|
*/ |
456 |
|
|
gret = gageStackProbeSpace(task->vol[ii]->gctx, |
457 |
|
|
point->pos[0], point->pos[1], point->pos[2], |
458 |
|
|
(task->pctx->flag.scaleIsTau |
459 |
|
|
? gageSigOfTau(point->pos[3]) |
460 |
|
|
: point->pos[3]), |
461 |
|
|
AIR_FALSE /* index-space */, |
462 |
|
|
AIR_TRUE /* clamp */); |
463 |
|
|
} |
464 |
|
|
if (gret) { |
465 |
|
|
biffAddf(PULL, "%s: probe failed on vol %u/%u: (%d) %s", me, |
466 |
|
|
ii, task->pctx->volNum, |
467 |
|
|
task->vol[ii]->gctx->errNum, task->vol[ii]->gctx->errStr); |
468 |
|
|
return 1; |
469 |
|
|
} |
470 |
|
|
/* |
471 |
|
|
if (!edge |
472 |
|
|
&& AIR_ABS(point->pos[1] - 67) < 1 |
473 |
|
|
&& AIR_ABS(point->pos[2] - 67) < 1 |
474 |
|
|
&& point->pos[3] > 3.13 |
475 |
|
|
&& !!task->vol[ii]->gctx->edgeFrac) { |
476 |
|
|
fprintf(stderr, "!%s(%u @ %g,%g,%g,%g): " |
477 |
|
|
"vol[%u]->gctx->edgeFrac %g => edge bit on\n", |
478 |
|
|
me, point->idtag, |
479 |
|
|
point->pos[0], point->pos[1], |
480 |
|
|
point->pos[2], point->pos[3], |
481 |
|
|
ii, task->vol[ii]->gctx->edgeFrac); |
482 |
|
|
} |
483 |
|
|
*/ |
484 |
|
|
edge |= !!task->vol[ii]->gctx->edgeFrac; |
485 |
|
|
} |
486 |
|
|
if (edge) { |
487 |
|
|
point->status |= PULL_STATUS_EDGE_BIT; |
488 |
|
|
} else { |
489 |
|
|
point->status &= ~PULL_STATUS_EDGE_BIT; |
490 |
|
|
} |
491 |
|
|
|
492 |
|
|
/* maybe is a little stupid to have the infos indexed this way, |
493 |
|
|
since it means that we always have to loop through all indices, |
494 |
|
|
but at least the compiler can unroll it . . . */ |
495 |
|
|
for (ii=0; ii<=PULL_INFO_MAX; ii++) { |
496 |
|
|
unsigned int alen, aidx; |
497 |
|
|
const pullInfoSpec *ispec; |
498 |
|
|
ispec = task->pctx->ispec[ii]; |
499 |
|
|
if (ispec) { |
500 |
|
|
alen = _pullInfoLen[ii]; |
501 |
|
|
aidx = task->pctx->infoIdx[ii]; |
502 |
|
|
if (pullSourceGage == ispec->source) { |
503 |
|
|
_pullInfoCopy[alen](point->info + aidx, task->ans[ii]); |
504 |
|
|
/* if (289 == task->pctx->iter) { |
505 |
|
|
fprintf(stderr, "!%s(%u): copied info %u (%s) len %u\n", me, point->idtag, |
506 |
|
|
ii, airEnumStr(pullInfo, ii), alen); |
507 |
|
|
if (1 == alen) { |
508 |
|
|
fprintf(stderr, "!%s(%u): (point->info + %u)[0] = %g\n", me, point->idtag, |
509 |
|
|
aidx, (point->info + aidx)[0]); |
510 |
|
|
} |
511 |
|
|
} */ |
512 |
|
|
/* |
513 |
|
|
if (81 == point->idtag) { |
514 |
|
|
pullVolume *vol; |
515 |
|
|
pullInfoSpec *isp; |
516 |
|
|
isp = task->pctx->ispec[ii]; |
517 |
|
|
vol = task->pctx->vol[isp->volIdx]; |
518 |
|
|
if (1 == alen) { |
519 |
|
|
printf("!%s: info[%u] %s: %s(\"%s\") = %g\n", me, |
520 |
|
|
ii, airEnumStr(pullInfo, ii), |
521 |
|
|
airEnumStr(vol->kind->enm, isp->item), |
522 |
|
|
vol->name, task->ans[ii][0]); |
523 |
|
|
} else { |
524 |
|
|
unsigned int vali; |
525 |
|
|
printf("!%s: info[%u] %s: %s(\"%s\") =\n", me, |
526 |
|
|
ii, airEnumStr(pullInfo, ii), |
527 |
|
|
airEnumStr(vol->kind->enm, isp->item), vol->name); |
528 |
|
|
for (vali=0; vali<alen; vali++) { |
529 |
|
|
printf("!%s: [%u] %g\n", me, vali, |
530 |
|
|
task->ans[ii][vali]); |
531 |
|
|
} |
532 |
|
|
} |
533 |
|
|
} |
534 |
|
|
*/ |
535 |
|
|
} else if (pullSourceProp == ispec->source) { |
536 |
|
|
switch (ispec->prop) { |
537 |
|
|
case pullPropIdtag: |
538 |
|
|
point->info[aidx] = point->idtag; |
539 |
|
|
break; |
540 |
|
|
case pullPropIdCC: |
541 |
|
|
point->info[aidx] = point->idCC; |
542 |
|
|
break; |
543 |
|
|
case pullPropEnergy: |
544 |
|
|
point->info[aidx] = point->energy; |
545 |
|
|
break; |
546 |
|
|
case pullPropStepEnergy: |
547 |
|
|
point->info[aidx] = point->stepEnergy; |
548 |
|
|
break; |
549 |
|
|
case pullPropStepConstr: |
550 |
|
|
point->info[aidx] = point->stepConstr; |
551 |
|
|
break; |
552 |
|
|
case pullPropStuck: |
553 |
|
|
point->info[aidx] = ((point->status & PULL_STATUS_STUCK_BIT) |
554 |
|
|
? point->stuckIterNum |
555 |
|
|
: 0); |
556 |
|
|
break; |
557 |
|
|
case pullPropPosition: |
558 |
|
|
ELL_4V_COPY(point->info + aidx, point->pos); |
559 |
|
|
break; |
560 |
|
|
case pullPropForce: |
561 |
|
|
ELL_4V_COPY(point->info + aidx, point->force); |
562 |
|
|
break; |
563 |
|
|
case pullPropNeighDistMean: |
564 |
|
|
point->info[aidx] = point->neighDistMean; |
565 |
|
|
break; |
566 |
|
|
case pullPropScale: |
567 |
|
|
point->info[aidx] = point->pos[3]; |
568 |
|
|
break; |
569 |
|
|
case pullPropNeighCovar: |
570 |
|
|
ELL_10V_COPY(point->info + aidx, point->neighCovar); |
571 |
|
|
break; |
572 |
|
|
case pullPropNeighCovar7Ten: |
573 |
|
|
TEN_T_SET(point->info + aidx, 1.0f, |
574 |
|
|
point->neighCovar[0], |
575 |
|
|
point->neighCovar[1], |
576 |
|
|
point->neighCovar[2], |
577 |
|
|
point->neighCovar[4], |
578 |
|
|
point->neighCovar[5], |
579 |
|
|
point->neighCovar[7]); |
580 |
|
|
break; |
581 |
|
|
#if PULL_TANCOVAR |
582 |
|
|
case pullPropNeighTanCovar: |
583 |
|
|
TEN_T_SET(point->info + aidx, 1.0f, |
584 |
|
|
point->neighTanCovar[0], |
585 |
|
|
point->neighTanCovar[1], |
586 |
|
|
point->neighTanCovar[2], |
587 |
|
|
point->neighTanCovar[3], |
588 |
|
|
point->neighTanCovar[4], |
589 |
|
|
point->neighTanCovar[5]); |
590 |
|
|
break; |
591 |
|
|
#endif |
592 |
|
|
case pullPropStability: |
593 |
|
|
point->info[aidx] = point->stability; |
594 |
|
|
break; |
595 |
|
|
default: |
596 |
|
|
break; |
597 |
|
|
} |
598 |
|
|
} |
599 |
|
|
} |
600 |
|
|
} |
601 |
|
|
|
602 |
|
|
#if 0 |
603 |
|
|
if (logStarted && !logDone) { |
604 |
|
|
unsigned int ai; |
605 |
|
|
/* the actual logging */ |
606 |
|
|
log[0] = point->idtag; |
607 |
|
|
ELL_4V_COPY(log + 1, point->pos); |
608 |
|
|
for (ai=0; ai<20; ai++) { |
609 |
|
|
log[5 + ai] = point->info[ai]; |
610 |
|
|
} |
611 |
|
|
log += nlog->axis[0].size; |
612 |
|
|
logIdx++; |
613 |
|
|
if (1 == task->pctx->iter && 81 == point->idtag) { |
614 |
|
|
printf("\n\n%s: ###### OKAY done logging (%u). . .\n\n\n", me, logIdx); |
615 |
|
|
nrrdSave("probelog.nrrd", nlog, NULL); |
616 |
|
|
nlog = nrrdNuke(nlog); |
617 |
|
|
logDone = AIR_TRUE; |
618 |
|
|
} |
619 |
|
|
} |
620 |
|
|
#endif |
621 |
|
|
|
622 |
|
|
|
623 |
|
|
#if 0 |
624 |
|
|
if (!opened) { |
625 |
|
|
flog = fopen("flog.txt", "w"); |
626 |
|
|
opened = AIR_TRUE; |
627 |
|
|
} |
628 |
|
|
if (opened) { |
629 |
|
|
fprintf(flog, "%s(%u): spthr(%g,%g,%g,%g) = %g\n", me, point->idtag, |
630 |
|
|
point->pos[0], point->pos[1], point->pos[2], point->pos[3], |
631 |
|
|
point->info[task->pctx->infoIdx[pullInfoSeedPreThresh]]); |
632 |
|
|
} |
633 |
|
|
#endif |
634 |
|
|
|
635 |
|
|
return 0; |
636 |
|
|
} |
637 |
|
|
|
638 |
|
|
static int |
639 |
|
|
_threshFail(const pullContext *pctx, const pullPoint *point, int info) { |
640 |
|
|
/* static const char me[]="_threshFail"; */ |
641 |
|
|
double val; |
642 |
|
|
int ret; |
643 |
|
|
|
644 |
|
|
if (pctx->ispec[info]) { |
645 |
|
|
val = pullPointScalar(pctx, point, info, NULL, NULL); |
646 |
|
|
ret = (val < 0); |
647 |
|
|
/* |
648 |
|
|
fprintf(stderr, "%s(%s): val=%g -> ret=%d\n", me, |
649 |
|
|
airEnumStr(pullInfo, info), val, ret); |
650 |
|
|
*/ |
651 |
|
|
} else { |
652 |
|
|
ret = AIR_FALSE; |
653 |
|
|
} |
654 |
|
|
return ret; |
655 |
|
|
} |
656 |
|
|
|
657 |
|
|
int |
658 |
|
|
pullPointInitializePerVoxel(const pullContext *pctx, |
659 |
|
|
const unsigned int pointIdx, |
660 |
|
|
pullPoint *point, pullVolume *scaleVol, |
661 |
|
|
/* output */ |
662 |
|
|
int *createFailP) { |
663 |
|
|
static const char me[]="pullPointInitializePerVoxel"; |
664 |
|
|
unsigned int vidx[3], pix; |
665 |
|
|
double iPos[3]; |
666 |
|
|
airRandMTState *rng; |
667 |
|
|
pullVolume *seedVol; |
668 |
|
|
gageShape *seedShape; |
669 |
|
|
int reject, rejectEdge, constrFail; |
670 |
|
|
unsigned int k; |
671 |
|
|
|
672 |
|
|
seedVol = pctx->vol[pctx->ispec[pullInfoSeedThresh]->volIdx]; |
673 |
|
|
seedShape = seedVol->gctx->shape; |
674 |
|
|
rng = pctx->task[0]->rng; |
675 |
|
|
|
676 |
|
|
/* Obtain voxel and indices from pointIdx */ |
677 |
|
|
/* axis ordering for this is x, y, z, scale */ |
678 |
|
|
pix = pointIdx; |
679 |
|
|
if (pctx->initParm.pointPerVoxel > 0) { |
680 |
|
|
pix /= pctx->initParm.pointPerVoxel; |
681 |
|
|
} else { |
682 |
|
|
pix *= -pctx->initParm.pointPerVoxel; |
683 |
|
|
} |
684 |
|
|
vidx[0] = pix % seedShape->size[0]; |
685 |
|
|
pix = (pix - vidx[0])/seedShape->size[0]; |
686 |
|
|
vidx[1] = pix % seedShape->size[1]; |
687 |
|
|
pix = (pix - vidx[1])/seedShape->size[1]; |
688 |
|
|
if (pctx->initParm.ppvZRange[0] <= pctx->initParm.ppvZRange[1]) { |
689 |
|
|
unsigned int zrn; |
690 |
|
|
zrn = pctx->initParm.ppvZRange[1] - pctx->initParm.ppvZRange[0] + 1; |
691 |
|
|
vidx[2] = (pix % zrn) + pctx->initParm.ppvZRange[0]; |
692 |
|
|
pix = (pix - (pix % zrn))/zrn; |
693 |
|
|
} else { |
694 |
|
|
vidx[2] = pix % seedShape->size[2]; |
695 |
|
|
pix = (pix - vidx[2])/seedShape->size[2]; |
696 |
|
|
} |
697 |
|
|
for (k=0; k<=2; k++) { |
698 |
|
|
iPos[k] = vidx[k] + pctx->initParm.jitter*(airDrandMT_r(rng)-0.5); |
699 |
|
|
} |
700 |
|
|
gageShapeItoW(seedShape, point->pos, iPos); |
701 |
|
|
if (pctx->flag.zeroZ) { |
702 |
|
|
point->pos[2] = 0.0; |
703 |
|
|
} |
704 |
|
|
|
705 |
|
|
if (0 && _pullVerbose) { |
706 |
|
|
printf("!%s: pointIdx %u -> vidx %u %u %u (%u)\n" |
707 |
|
|
" -> iPos %g %g %g -> wPos %g %g %g\n", |
708 |
|
|
me, pointIdx, vidx[0], vidx[1], vidx[2], pix, |
709 |
|
|
iPos[0], iPos[1], iPos[2], |
710 |
|
|
point->pos[0], point->pos[1], point->pos[2]); |
711 |
|
|
} |
712 |
|
|
|
713 |
|
|
/* Compute sigma coordinate from pix */ |
714 |
|
|
if (pctx->haveScale) { |
715 |
|
|
int outside; |
716 |
|
|
double aidx, bidx; |
717 |
|
|
/* pix should already be integer in [0, pctx->samplesAlongScaleNum-1)]. */ |
718 |
|
|
aidx = pix + pctx->initParm.jitter*(airDrandMT_r(rng)-0.5); |
719 |
|
|
bidx = AIR_AFFINE(-0.5, aidx, pctx->initParm.samplesAlongScaleNum-0.5, |
720 |
|
|
0.0, scaleVol->scaleNum-1); |
721 |
|
|
point->pos[3] = gageStackItoW(scaleVol->gctx, bidx, &outside); |
722 |
|
|
if (pctx->flag.scaleIsTau) { |
723 |
|
|
point->pos[3] = gageTauOfSig(point->pos[3]); |
724 |
|
|
} |
725 |
|
|
if (0 && _pullVerbose) { |
726 |
|
|
printf("!%s(%u): pix %u -> a %g b %g -> wpos %g\n", me, point->idtag, |
727 |
|
|
pix, aidx, bidx, point->pos[3]); |
728 |
|
|
} |
729 |
|
|
} else { |
730 |
|
|
point->pos[3] = 0; |
731 |
|
|
} |
732 |
|
|
|
733 |
|
|
if (pctx->ispec[pullInfoSeedPreThresh]) { |
734 |
|
|
/* we first do a special-purpose probe just for SeedPreThresh */ |
735 |
|
|
pctx->task[0]->probeSeedPreThreshOnly = AIR_TRUE; |
736 |
|
|
if (pullProbe(pctx->task[0], point)) { |
737 |
|
|
biffAddf(PULL, "%s: pre-probing pointIdx %u of world", me, pointIdx); |
738 |
|
|
return 1; |
739 |
|
|
} |
740 |
|
|
pctx->task[0]->probeSeedPreThreshOnly = AIR_FALSE; |
741 |
|
|
if (_threshFail(pctx, point, pullInfoSeedPreThresh)) { |
742 |
|
|
reject = AIR_TRUE; |
743 |
|
|
/* HEY! this obviously need to be re-written */ |
744 |
|
|
goto finish; |
745 |
|
|
} |
746 |
|
|
} |
747 |
|
|
/* else, we didn't have a SeedPreThresh, or we did, and we passed |
748 |
|
|
it. Now we REDO the probe, including possibly re-learning |
749 |
|
|
SeedPreThresh, which is silly, but the idea is that this is a |
750 |
|
|
small price compared to what has been saved by avoiding all the |
751 |
|
|
gageProbe()s on volumes unrelated to SeedPreThresh */ |
752 |
|
|
if (pullProbe(pctx->task[0], point)) { |
753 |
|
|
biffAddf(PULL, "%s: probing pointIdx %u of world", me, pointIdx); |
754 |
|
|
return 1; |
755 |
|
|
} |
756 |
|
|
|
757 |
|
|
constrFail = AIR_FALSE; |
758 |
|
|
reject = AIR_FALSE; |
759 |
|
|
|
760 |
|
|
/* Check we pass pre-threshold */ |
761 |
|
|
if (!reject) reject |= _threshFail(pctx, point, pullInfoSeedPreThresh); |
762 |
|
|
|
763 |
|
|
if (!pctx->flag.constraintBeforeSeedThresh) { |
764 |
|
|
/* we should be guaranteed to have a seed thresh info */ |
765 |
|
|
if (!reject) reject |= _threshFail(pctx, point, pullInfoSeedThresh); |
766 |
|
|
if (pctx->initParm.liveThreshUse) { |
767 |
|
|
if (!reject) reject |= _threshFail(pctx, point, pullInfoLiveThresh); |
768 |
|
|
if (!reject) reject |= _threshFail(pctx, point, pullInfoLiveThresh2); |
769 |
|
|
if (!reject) reject |= _threshFail(pctx, point, pullInfoLiveThresh3); |
770 |
|
|
} |
771 |
|
|
} |
772 |
|
|
|
773 |
|
|
if (!reject && pctx->constraint) { |
774 |
|
|
if (_pullConstraintSatisfy(pctx->task[0], point, |
775 |
|
|
10*_PULL_CONSTRAINT_TRAVEL_MAX, |
776 |
|
|
&constrFail)) { |
777 |
|
|
biffAddf(PULL, "%s: on pnt %u", |
778 |
|
|
me, pointIdx); |
779 |
|
|
return 1; |
780 |
|
|
} |
781 |
|
|
reject |= constrFail; |
782 |
|
|
/* post constraint-satisfaction, we certainly have to assert thresholds */ |
783 |
|
|
if (!reject) reject |= _threshFail(pctx, point, pullInfoSeedThresh); |
784 |
|
|
if (pctx->initParm.liveThreshUse) { |
785 |
|
|
if (!reject) reject |= _threshFail(pctx, point, pullInfoLiveThresh); |
786 |
|
|
if (!reject) reject |= _threshFail(pctx, point, pullInfoLiveThresh2); |
787 |
|
|
if (!reject) reject |= _threshFail(pctx, point, pullInfoLiveThresh3); |
788 |
|
|
} |
789 |
|
|
if (pctx->flag.nixAtVolumeEdgeSpace |
790 |
|
|
&& (point->status & PULL_STATUS_EDGE_BIT)) { |
791 |
|
|
rejectEdge = AIR_TRUE; |
792 |
|
|
} else { |
793 |
|
|
rejectEdge = AIR_FALSE; |
794 |
|
|
} |
795 |
|
|
reject |= rejectEdge; |
796 |
|
|
if (pctx->verbose > 1) { |
797 |
|
|
fprintf(stderr, "%s(%u): constr %d, seed %d, thresh %d %d %d, edge %d\n", |
798 |
|
|
me, point->idtag, constrFail, |
799 |
|
|
_threshFail(pctx, point, pullInfoSeedThresh), |
800 |
|
|
_threshFail(pctx, point, pullInfoLiveThresh), |
801 |
|
|
_threshFail(pctx, point, pullInfoLiveThresh2), |
802 |
|
|
_threshFail(pctx, point, pullInfoLiveThresh3), rejectEdge); |
803 |
|
|
} |
804 |
|
|
} else { |
805 |
|
|
constrFail = AIR_FALSE; |
806 |
|
|
} |
807 |
|
|
|
808 |
|
|
finish: |
809 |
|
|
/* Gather consensus */ |
810 |
|
|
if (reject) { |
811 |
|
|
*createFailP = AIR_TRUE; |
812 |
|
|
} else { |
813 |
|
|
*createFailP = AIR_FALSE; |
814 |
|
|
} |
815 |
|
|
|
816 |
|
|
return 0; |
817 |
|
|
} |
818 |
|
|
|
819 |
|
|
static void |
820 |
|
|
_pullUnitToWorld(const pullContext *pctx, const pullVolume *scaleVol, |
821 |
|
|
double wrld[4], const double unit[4]) { |
822 |
|
|
/* static const char me[]="_pullUnitToWorld"; */ |
823 |
|
|
|
824 |
|
|
wrld[0] = AIR_AFFINE(0.0, unit[0], 1.0, pctx->bboxMin[0], pctx->bboxMax[0]); |
825 |
|
|
wrld[1] = AIR_AFFINE(0.0, unit[1], 1.0, pctx->bboxMin[1], pctx->bboxMax[1]); |
826 |
|
|
wrld[2] = AIR_AFFINE(0.0, unit[2], 1.0, pctx->bboxMin[2], pctx->bboxMax[2]); |
827 |
|
|
if (pctx->haveScale) { |
828 |
|
|
double sridx; |
829 |
|
|
int outside; |
830 |
|
|
sridx = AIR_AFFINE(0.0, unit[3], 1.0, 0, scaleVol->scaleNum-1); |
831 |
|
|
wrld[3] = gageStackItoW(scaleVol->gctx, sridx, &outside); |
832 |
|
|
if (pctx->flag.scaleIsTau) { |
833 |
|
|
wrld[3] = gageTauOfSig(wrld[3]); |
834 |
|
|
} |
835 |
|
|
} else { |
836 |
|
|
wrld[3] = 0.0; |
837 |
|
|
} |
838 |
|
|
/* |
839 |
|
|
fprintf(stderr, "!%s: (%g,%g,%g,%g) -- [%g,%g]x[%g,%g]x[%g,%g]--> (%g,%g,%g,%g)\n", me, |
840 |
|
|
unit[0], unit[1], unit[2], unit[3], |
841 |
|
|
pctx->bboxMin[0], pctx->bboxMin[1], pctx->bboxMin[2], |
842 |
|
|
pctx->bboxMax[0], pctx->bboxMax[1], pctx->bboxMax[2], |
843 |
|
|
wrld[0], wrld[1], wrld[2], wrld[3]); |
844 |
|
|
*/ |
845 |
|
|
return; |
846 |
|
|
} |
847 |
|
|
|
848 |
|
|
int |
849 |
|
|
pullPointInitializeRandomOrHalton(pullContext *pctx, |
850 |
|
|
const unsigned int pointIdx, |
851 |
|
|
pullPoint *point, pullVolume *scaleVol) { |
852 |
|
|
static const char me[]="pullPointInitializeRandomOrHalton"; |
853 |
|
|
int reject, verbo; |
854 |
|
|
airRandMTState *rng; |
855 |
|
|
unsigned int tryCount = 0, threshFailCount = 0, spthreshFailCount = 0, |
856 |
|
|
constrFailCount = 0; |
857 |
|
|
rng = pctx->task[0]->rng; |
858 |
|
|
|
859 |
|
|
do { |
860 |
|
|
double rpos[4]; |
861 |
|
|
/* fprintf(stderr, "!%s: starting doooo (tryCount %u)!\n", me, tryCount); */ |
862 |
|
|
tryCount++; |
863 |
|
|
reject = AIR_FALSE; |
864 |
|
|
_pullPointHistInit(point); |
865 |
|
|
/* Populate tentative random point */ |
866 |
|
|
if (pullInitMethodHalton == pctx->initParm.method) { |
867 |
|
|
/* we generate all 4 coordinates, even if we don't need them all */ |
868 |
|
|
airHalton(rpos, (pointIdx + threshFailCount + constrFailCount |
869 |
|
|
+ pctx->haltonOffset + pctx->initParm.haltonStartIndex), |
870 |
|
|
airPrimeList, 4); |
871 |
|
|
/* |
872 |
|
|
fprintf(stderr, "!%s(%u/%u): halton(%u=%u+%u+%u+%u+%u) => %g %g %g %g\n", |
873 |
|
|
me, pointIdx, pctx->idtagNext, |
874 |
|
|
(pointIdx + threshFailCount + constrFailCount + |
875 |
|
|
pctx->haltonOffset + pctx->initParm.haltonStartIndex), |
876 |
|
|
pointIdx, threshFailCount, constrFailCount, |
877 |
|
|
pctx->haltonOffset, pctx->initParm.haltonStartIndex, |
878 |
|
|
rpos[0], rpos[1], rpos[2], rpos[3]); |
879 |
|
|
*/ |
880 |
|
|
/* |
881 |
|
|
fprintf(stderr, "%g %g %g %g ", |
882 |
|
|
rpos[0], rpos[1], rpos[2], rpos[3]); |
883 |
|
|
*/ |
884 |
|
|
if (!pctx->haveScale) { |
885 |
|
|
rpos[3] = 0; |
886 |
|
|
} |
887 |
|
|
} else { |
888 |
|
|
ELL_3V_SET(rpos, airDrandMT_r(rng), airDrandMT_r(rng), airDrandMT_r(rng)); |
889 |
|
|
if (pctx->haveScale) { |
890 |
|
|
rpos[3] = airDrandMT_r(rng); |
891 |
|
|
} else { |
892 |
|
|
rpos[3] = 0; |
893 |
|
|
} |
894 |
|
|
} |
895 |
|
|
_pullUnitToWorld(pctx, scaleVol, point->pos, rpos); |
896 |
|
|
if (pctx->flag.zeroZ) { |
897 |
|
|
point->pos[2] = 0.0; |
898 |
|
|
} |
899 |
|
|
/* |
900 |
|
|
verbo = (AIR_ABS(-0.246015 - point->pos[0]) < 0.1 && |
901 |
|
|
AIR_ABS(-144.78 - point->pos[0]) < 0.1 && |
902 |
|
|
AIR_ABS(-85.3813 - point->pos[0]) < 0.1); |
903 |
|
|
*/ |
904 |
|
|
verbo = AIR_FALSE; |
905 |
|
|
if (verbo) { |
906 |
|
|
fprintf(stderr, "%s: verbo on for point %u at %g %g %g %g\n", me, |
907 |
|
|
point->idtag, point->pos[0], point->pos[1], |
908 |
|
|
point->pos[2], point->pos[3]); |
909 |
|
|
} |
910 |
|
|
_pullPointHistAdd(point, pullCondOld, AIR_NAN); |
911 |
|
|
|
912 |
|
|
/* HEY copy and paste */ |
913 |
|
|
if (pctx->ispec[pullInfoSeedPreThresh]) { |
914 |
|
|
/* we first do a special-purpose probe just for SeedPreThresh */ |
915 |
|
|
pctx->task[0]->probeSeedPreThreshOnly = AIR_TRUE; |
916 |
|
|
if (pullProbe(pctx->task[0], point)) { |
917 |
|
|
biffAddf(PULL, "%s: pre-probing pointIdx %u of world", me, pointIdx); |
918 |
|
|
return 1; |
919 |
|
|
} |
920 |
|
|
pctx->task[0]->probeSeedPreThreshOnly = AIR_FALSE; |
921 |
|
|
if (_threshFail(pctx, point, pullInfoSeedPreThresh)) { |
922 |
|
|
threshFailCount++; |
923 |
|
|
spthreshFailCount++; |
924 |
|
|
reject = AIR_TRUE; |
925 |
|
|
goto reckoning; |
926 |
|
|
} |
927 |
|
|
} |
928 |
|
|
if (pullProbe(pctx->task[0], point)) { |
929 |
|
|
biffAddf(PULL, "%s: probing pointIdx %u of world", me, pointIdx); |
930 |
|
|
return 1; |
931 |
|
|
} |
932 |
|
|
/* Check we pass pre-threshold */ |
933 |
|
|
#define THRESH_TEST(INFO) \ |
934 |
|
|
if (pctx->ispec[INFO] && _threshFail(pctx, point, INFO)) { \ |
935 |
|
|
threshFailCount++; \ |
936 |
|
|
reject = AIR_TRUE; \ |
937 |
|
|
goto reckoning; \ |
938 |
|
|
} |
939 |
|
|
/* fprintf(stderr, "!%s: bi ngo 0 (%d) %d %p\n", me, |
940 |
|
|
!pctx->flag.constraintBeforeSeedThresh, |
941 |
|
|
pctx->initParm.liveThreshUse, pctx->ispec[pullInfoLiveThresh]); */ |
942 |
|
|
if (!pctx->flag.constraintBeforeSeedThresh) { |
943 |
|
|
THRESH_TEST(pullInfoSeedThresh); |
944 |
|
|
if (pctx->initParm.liveThreshUse) { |
945 |
|
|
THRESH_TEST(pullInfoLiveThresh); |
946 |
|
|
THRESH_TEST(pullInfoLiveThresh2); |
947 |
|
|
THRESH_TEST(pullInfoLiveThresh3); |
948 |
|
|
} |
949 |
|
|
} |
950 |
|
|
/* fprintf(stderr, "!%s: bi ngo 1\n", me); */ |
951 |
|
|
|
952 |
|
|
if (pctx->constraint) { |
953 |
|
|
int constrFail; |
954 |
|
|
/* fprintf(stderr, "!%s: calling _pullConstraintSatisfy(%u)\n", me, pointIdx); */ |
955 |
|
|
if (_pullConstraintSatisfy(pctx->task[0], point, |
956 |
|
|
_PULL_CONSTRAINT_TRAVEL_MAX, |
957 |
|
|
&constrFail)) { |
958 |
|
|
biffAddf(PULL, "%s: trying constraint on point %u", me, pointIdx); |
959 |
|
|
return 1; |
960 |
|
|
} |
961 |
|
|
#if PULL_PHIST |
962 |
|
|
if (DEBUG) { |
963 |
|
|
Nrrd *nhist; |
964 |
|
|
FILE *fhist; |
965 |
|
|
char fname[AIR_STRLEN_SMALL]; |
966 |
|
|
nhist = nrrdNew(); |
967 |
|
|
if (pullPositionHistoryNrrdGet(nhist, pctx, point)) { |
968 |
|
|
biffAddf(PULL, "%s: trouble", me); |
969 |
|
|
return 1; |
970 |
|
|
} |
971 |
|
|
sprintf(fname, "%04u-%04u-%04u-phist.nrrd", pctx->iter, |
972 |
|
|
point->idtag, tryCount); |
973 |
|
|
if ((fhist = fopen(fname, "w"))) { |
974 |
|
|
if (nrrdSave(fname, nhist, NULL)) { |
975 |
|
|
biffMovef(PULL, NRRD, "%s: trouble", me); |
976 |
|
|
return 1; |
977 |
|
|
} |
978 |
|
|
fclose(fhist); |
979 |
|
|
} |
980 |
|
|
nrrdNuke(nhist); |
981 |
|
|
} |
982 |
|
|
#endif |
983 |
|
|
if (constrFail) { |
984 |
|
|
constrFailCount++; |
985 |
|
|
reject = AIR_TRUE; |
986 |
|
|
goto reckoning; |
987 |
|
|
} |
988 |
|
|
/* fprintf(stderr, "!%s: bi ngo 2\n", me); */ |
989 |
|
|
/* post constraint-satisfaction, we certainly have to assert thresholds */ |
990 |
|
|
THRESH_TEST(pullInfoSeedThresh); |
991 |
|
|
if (pctx->initParm.liveThreshUse) { |
992 |
|
|
THRESH_TEST(pullInfoLiveThresh); |
993 |
|
|
THRESH_TEST(pullInfoLiveThresh2); |
994 |
|
|
THRESH_TEST(pullInfoLiveThresh3); |
995 |
|
|
} |
996 |
|
|
/* fprintf(stderr, "!%s: bi ngo 3 (reject=%d)\n", me, reject); */ |
997 |
|
|
} |
998 |
|
|
|
999 |
|
|
reckoning: |
1000 |
|
|
if (reject) { |
1001 |
|
|
if (threshFailCount + constrFailCount >= _PULL_RANDOM_SEED_TRY_MAX) { |
1002 |
|
|
/* Very bad luck; we've too many times */ |
1003 |
|
|
biffAddf(PULL, "%s: failed too often (%u times) placing point %u: " |
1004 |
|
|
"%u fails on thresh (%u on pre-thresh), %u on constr", |
1005 |
|
|
me, _PULL_RANDOM_SEED_TRY_MAX, pointIdx, |
1006 |
|
|
threshFailCount, spthreshFailCount, constrFailCount); |
1007 |
|
|
return 1; |
1008 |
|
|
} |
1009 |
|
|
} |
1010 |
|
|
} while (reject); |
1011 |
|
|
|
1012 |
|
|
if (pullInitMethodHalton == pctx->initParm.method) { |
1013 |
|
|
pctx->haltonOffset += threshFailCount + constrFailCount; |
1014 |
|
|
} |
1015 |
|
|
|
1016 |
|
|
return 0; |
1017 |
|
|
} |
1018 |
|
|
|
1019 |
|
|
int |
1020 |
|
|
pullPointInitializeGivenPos(pullContext *pctx, |
1021 |
|
|
const double *posData, |
1022 |
|
|
const unsigned int pointIdx, |
1023 |
|
|
pullPoint *point, |
1024 |
|
|
/* output */ |
1025 |
|
|
int *createFailP) { |
1026 |
|
|
static const char me[]="pullPointInitializeGivenPos"; |
1027 |
|
|
int reject, rejectEdge; |
1028 |
|
|
|
1029 |
|
|
/* Copy nrrd point into pullPoint */ |
1030 |
|
|
ELL_4V_COPY(point->pos, posData + 4*pointIdx); |
1031 |
|
|
if (pctx->flag.zeroZ) { |
1032 |
|
|
point->pos[2] = 0.0; |
1033 |
|
|
} |
1034 |
|
|
|
1035 |
|
|
/* |
1036 |
|
|
if (AIR_ABS(247.828 - point->pos[0]) < 0.1 && |
1037 |
|
|
AIR_ABS(66.8817 - point->pos[1]) < 0.1 && |
1038 |
|
|
AIR_ABS(67.0031 - point->pos[2]) < 0.1) { |
1039 |
|
|
fprintf(stderr, "%s: --------- point %u at %g %g %g %g\n", me, |
1040 |
|
|
point->idtag, |
1041 |
|
|
point->pos[0], point->pos[1], |
1042 |
|
|
point->pos[2], point->pos[3]); |
1043 |
|
|
} |
1044 |
|
|
*/ |
1045 |
|
|
|
1046 |
|
|
/* we're dictating positions, but still have to do initial probe, |
1047 |
|
|
and possibly liveThresholding */ |
1048 |
|
|
if (pullProbe(pctx->task[0], point)) { |
1049 |
|
|
biffAddf(PULL, "%s: probing pointIdx %u of npos", me, pointIdx); |
1050 |
|
|
return 1; |
1051 |
|
|
} |
1052 |
|
|
reject = AIR_FALSE; |
1053 |
|
|
if (pctx->flag.nixAtVolumeEdgeSpace |
1054 |
|
|
&& (point->status & PULL_STATUS_EDGE_BIT)) { |
1055 |
|
|
rejectEdge = AIR_TRUE; |
1056 |
|
|
} else { |
1057 |
|
|
rejectEdge = AIR_FALSE; |
1058 |
|
|
} |
1059 |
|
|
reject |= rejectEdge; |
1060 |
|
|
if (pctx->initParm.liveThreshUse) { |
1061 |
|
|
if (!reject) reject |= _threshFail(pctx, point, pullInfoLiveThresh); |
1062 |
|
|
if (!reject) reject |= _threshFail(pctx, point, pullInfoLiveThresh2); |
1063 |
|
|
if (!reject) reject |= _threshFail(pctx, point, pullInfoLiveThresh3); |
1064 |
|
|
} |
1065 |
|
|
/* |
1066 |
|
|
if (reject) { |
1067 |
|
|
fprintf(stderr, "!%s(%u): edge %d thresh %d %d %d\n", |
1068 |
|
|
me, point->idtag, rejectEdge, |
1069 |
|
|
_threshFail(pctx, point, pullInfoLiveThresh), |
1070 |
|
|
_threshFail(pctx, point, pullInfoLiveThresh2), |
1071 |
|
|
_threshFail(pctx, point, pullInfoLiveThresh3)); |
1072 |
|
|
} |
1073 |
|
|
*/ |
1074 |
|
|
if (reject) { |
1075 |
|
|
*createFailP = AIR_TRUE; |
1076 |
|
|
} else { |
1077 |
|
|
*createFailP = AIR_FALSE; |
1078 |
|
|
} |
1079 |
|
|
|
1080 |
|
|
return 0; |
1081 |
|
|
} |
1082 |
|
|
|
1083 |
|
|
/* |
1084 |
|
|
** _pullPointSetup sets: |
1085 |
|
|
** |
1086 |
|
|
** This is only called by the master thread |
1087 |
|
|
** |
1088 |
|
|
** this should set stuff to be like after an update stage and |
1089 |
|
|
** just before the rebinning |
1090 |
|
|
*/ |
1091 |
|
|
int |
1092 |
|
|
_pullPointSetup(pullContext *pctx) { |
1093 |
|
|
static const char me[]="_pullPointSetup"; |
1094 |
|
|
char doneStr[AIR_STRLEN_SMALL]; |
1095 |
|
|
unsigned int pointIdx, binIdx, tick, pn; |
1096 |
|
|
pullPoint *point; |
1097 |
|
|
pullBin *bin; |
1098 |
|
|
int createFail,added; |
1099 |
|
|
airArray *mop; |
1100 |
|
|
Nrrd *npos; |
1101 |
|
|
pullVolume *seedVol, *scaleVol; |
1102 |
|
|
gageShape *seedShape; |
1103 |
|
|
double factor, *posData; |
1104 |
|
|
unsigned int totalNumPoints, voxNum, ii; |
1105 |
|
|
|
1106 |
|
|
/* on using pullBinsPointMaybeAdd: This is used only in the context |
1107 |
|
|
of constraints; it makes sense to be a little more selective |
1108 |
|
|
about adding points, so that they aren't completely piled on top |
1109 |
|
|
of each other. This relies on _PULL_BINNING_MAYBE_ADD_THRESH: its |
1110 |
|
|
tempting to set this value high, to more aggressively limit the |
1111 |
|
|
number of points added, but that's really the job of population |
1112 |
|
|
control, and we can't always guarantee that constraint manifolds |
1113 |
|
|
will be well-sampled (with respect to pctx->radiusSpace and |
1114 |
|
|
pctx->radiusScale) to start with */ |
1115 |
|
|
|
1116 |
|
|
if (pctx->verbose) { |
1117 |
|
|
printf("%s: beginning (%s). . . ", me, |
1118 |
|
|
airEnumStr(pullInitMethod, pctx->initParm.method)); |
1119 |
|
|
fflush(stdout); |
1120 |
|
|
} |
1121 |
|
|
mop = airMopNew(); |
1122 |
|
|
switch (pctx->initParm.method) { |
1123 |
|
|
case pullInitMethodGivenPos: |
1124 |
|
|
npos = nrrdNew(); |
1125 |
|
|
airMopAdd(mop, npos, (airMopper)nrrdNuke, airMopAlways); |
1126 |
|
|
/* even if npos came in as double, we have to copy it */ |
1127 |
|
|
if (nrrdConvert(npos, pctx->initParm.npos, nrrdTypeDouble)) { |
1128 |
|
|
biffMovef(PULL, NRRD, "%s: trouble converting npos", me); |
1129 |
|
|
airMopError(mop); return 1; |
1130 |
|
|
} |
1131 |
|
|
posData = AIR_CAST(double *, npos->data); |
1132 |
|
|
if (pctx->initParm.numInitial || pctx->initParm.pointPerVoxel) { |
1133 |
|
|
printf("%s: with npos, overriding both numInitial (%u) " |
1134 |
|
|
"and pointPerVoxel (%d)\n", me, pctx->initParm.numInitial, |
1135 |
|
|
pctx->initParm.pointPerVoxel); |
1136 |
|
|
} |
1137 |
|
|
totalNumPoints = AIR_CAST(unsigned int, npos->axis[1].size); |
1138 |
|
|
break; |
1139 |
|
|
case pullInitMethodPointPerVoxel: |
1140 |
|
|
npos = NULL; |
1141 |
|
|
posData = NULL; |
1142 |
|
|
if (pctx->initParm.numInitial && pctx->verbose) { |
1143 |
|
|
printf("%s: pointPerVoxel %d overrides numInitial (%u)\n", me, |
1144 |
|
|
pctx->initParm.pointPerVoxel, pctx->initParm.numInitial); |
1145 |
|
|
} |
1146 |
|
|
/* Obtain number of voxels */ |
1147 |
|
|
seedVol = pctx->vol[pctx->ispec[pullInfoSeedThresh]->volIdx]; |
1148 |
|
|
seedShape = seedVol->gctx->shape; |
1149 |
|
|
if (pctx->initParm.ppvZRange[0] <= pctx->initParm.ppvZRange[1]) { |
1150 |
|
|
unsigned int zrn; |
1151 |
|
|
if (!( pctx->initParm.ppvZRange[0] < seedShape->size[2] |
1152 |
|
|
&& pctx->initParm.ppvZRange[1] < seedShape->size[2] )) { |
1153 |
|
|
biffAddf(PULL, "%s: ppvZRange[%u,%u] outside volume [0,%u]", me, |
1154 |
|
|
pctx->initParm.ppvZRange[0], pctx->initParm.ppvZRange[1], |
1155 |
|
|
seedShape->size[2]-1); |
1156 |
|
|
airMopError(mop); return 1; |
1157 |
|
|
} |
1158 |
|
|
zrn = pctx->initParm.ppvZRange[1] - pctx->initParm.ppvZRange[0] + 1; |
1159 |
|
|
voxNum = seedShape->size[0]*seedShape->size[1]*zrn; |
1160 |
|
|
if (pctx->verbose) { |
1161 |
|
|
printf("%s: vol size %u %u [%u,%u] -> voxNum %u\n", me, |
1162 |
|
|
seedShape->size[0], seedShape->size[1], |
1163 |
|
|
pctx->initParm.ppvZRange[0], pctx->initParm.ppvZRange[1], |
1164 |
|
|
voxNum); |
1165 |
|
|
} |
1166 |
|
|
} else { |
1167 |
|
|
voxNum = seedShape->size[0]*seedShape->size[1]*seedShape->size[2]; |
1168 |
|
|
if (pctx->verbose) { |
1169 |
|
|
printf("%s: vol size %u %u %u -> voxNum %u\n", me, |
1170 |
|
|
seedShape->size[0], seedShape->size[1], seedShape->size[2], |
1171 |
|
|
voxNum); |
1172 |
|
|
} |
1173 |
|
|
} |
1174 |
|
|
|
1175 |
|
|
/* Compute total number of points */ |
1176 |
|
|
if (pctx->initParm.pointPerVoxel > 0) { |
1177 |
|
|
factor = pctx->initParm.pointPerVoxel; |
1178 |
|
|
} else { |
1179 |
|
|
factor = -1.0/pctx->initParm.pointPerVoxel; |
1180 |
|
|
} |
1181 |
|
|
if (pctx->haveScale) { |
1182 |
|
|
unsigned int sasn; |
1183 |
|
|
sasn = pctx->initParm.samplesAlongScaleNum; |
1184 |
|
|
totalNumPoints = AIR_CAST(unsigned int, voxNum * factor * sasn); |
1185 |
|
|
} else { |
1186 |
|
|
totalNumPoints = AIR_CAST(unsigned int, voxNum * factor); |
1187 |
|
|
} |
1188 |
|
|
break; |
1189 |
|
|
case pullInitMethodRandom: |
1190 |
|
|
case pullInitMethodHalton: |
1191 |
|
|
npos = NULL; |
1192 |
|
|
posData = NULL; |
1193 |
|
|
totalNumPoints = pctx->initParm.numInitial; |
1194 |
|
|
break; |
1195 |
|
|
default: |
1196 |
|
|
biffAddf(PULL, "%s: pullInitMethod %d not handled!", me, |
1197 |
|
|
pctx->initParm.method); |
1198 |
|
|
airMopError(mop); return 1; |
1199 |
|
|
break; |
1200 |
|
|
} |
1201 |
|
|
if (pctx->verbose) { |
1202 |
|
|
printf("%s: initializing/seeding %u pts. . . ", me, totalNumPoints); |
1203 |
|
|
fflush(stdout); |
1204 |
|
|
} |
1205 |
|
|
|
1206 |
|
|
/* find first scale volume, if there is one; this is used by some |
1207 |
|
|
seeders to determine placement along the scale axis */ |
1208 |
|
|
scaleVol = NULL; |
1209 |
|
|
for (ii=0; ii<pctx->volNum; ii++) { |
1210 |
|
|
if (pctx->vol[ii]->ninScale) { |
1211 |
|
|
scaleVol = pctx->vol[ii]; |
1212 |
|
|
break; |
1213 |
|
|
} |
1214 |
|
|
} |
1215 |
|
|
|
1216 |
|
|
/* Start adding points */ |
1217 |
|
|
tick = totalNumPoints/1000; |
1218 |
|
|
point = NULL; |
1219 |
|
|
unsigned int initRorHack = 0; |
1220 |
|
|
/* This loop would normally be: |
1221 |
|
|
for (pointIdx = 0; pointIdx < totalNumPoints; pointIdx++) { |
1222 |
|
|
but because of pctx->flag.nixAtVolumeEdgeSpaceInitRorH we |
1223 |
|
|
need to be able to decrement pointIdx to force another redo, |
1224 |
|
|
even if pointIdx==0. So loop index is actually one greater |
1225 |
|
|
than the index value actually used */ |
1226 |
|
|
for (pointIdx = 1; pointIdx <= totalNumPoints; pointIdx++) { |
1227 |
|
|
int E; |
1228 |
|
|
if (pctx->verbose) { |
1229 |
|
|
if (tick < 100 || 0 == (pointIdx-1) % tick) { |
1230 |
|
|
printf("%s", airDoneStr(0, pointIdx-1, totalNumPoints, doneStr)); |
1231 |
|
|
fflush(stdout); |
1232 |
|
|
} |
1233 |
|
|
} |
1234 |
|
|
if (pctx->verbose > 5) { |
1235 |
|
|
printf("\n%s: setting up point = %u/%u\n", me, |
1236 |
|
|
pointIdx-1, totalNumPoints); |
1237 |
|
|
} |
1238 |
|
|
/* Create point */ |
1239 |
|
|
if (!point) { |
1240 |
|
|
point = pullPointNew(pctx); |
1241 |
|
|
} |
1242 |
|
|
/* Filling array according to initialization method */ |
1243 |
|
|
E = 0; |
1244 |
|
|
switch(pctx->initParm.method) { |
1245 |
|
|
case pullInitMethodRandom: |
1246 |
|
|
case pullInitMethodHalton: |
1247 |
|
|
/* point index passed here always increments, even if |
1248 |
|
|
we failed last time because of being at edge */ |
1249 |
|
|
E = pullPointInitializeRandomOrHalton(pctx, pointIdx-1 + initRorHack, |
1250 |
|
|
point, scaleVol); |
1251 |
|
|
if (pctx->flag.nixAtVolumeEdgeSpaceInitRorH) { |
1252 |
|
|
createFail = !!(point->status & PULL_STATUS_EDGE_BIT); |
1253 |
|
|
if (createFail) { |
1254 |
|
|
initRorHack++; |
1255 |
|
|
if (initRorHack > 10*totalNumPoints) { |
1256 |
|
|
biffAddf(PULL, "%s: (point %u) handling nixAtVolumeEdgeSpaceInitRorH, " |
1257 |
|
|
"have failed so often (%u > 10*#pnts = %u); something " |
1258 |
|
|
"must be wrong", me, point->idtag, initRorHack, |
1259 |
|
|
totalNumPoints); |
1260 |
|
|
airMopError(mop); return 1; |
1261 |
|
|
} |
1262 |
|
|
/* this is a for-loop, post-body increment will always happen; |
1263 |
|
|
we need to subvert it. */ |
1264 |
|
|
pointIdx--; |
1265 |
|
|
} |
1266 |
|
|
} else { |
1267 |
|
|
createFail = AIR_FALSE; |
1268 |
|
|
} |
1269 |
|
|
break; |
1270 |
|
|
case pullInitMethodPointPerVoxel: |
1271 |
|
|
E = pullPointInitializePerVoxel(pctx, pointIdx-1, point, scaleVol, |
1272 |
|
|
&createFail); |
1273 |
|
|
break; |
1274 |
|
|
case pullInitMethodGivenPos: |
1275 |
|
|
E = pullPointInitializeGivenPos(pctx, posData, pointIdx-1, point, |
1276 |
|
|
&createFail); |
1277 |
|
|
break; |
1278 |
|
|
} |
1279 |
|
|
if (E) { |
1280 |
|
|
biffAddf(PULL, "%s: trouble trying point %u (id %u)", me, |
1281 |
|
|
pointIdx-1, point->idtag); |
1282 |
|
|
airMopError(mop); return 1; |
1283 |
|
|
} |
1284 |
|
|
if (createFail) { |
1285 |
|
|
/* We were not successful in creating a point; not an error */ |
1286 |
|
|
continue; |
1287 |
|
|
} |
1288 |
|
|
|
1289 |
|
|
/* else, the point is ready for binning */ |
1290 |
|
|
if (pctx->constraint) { |
1291 |
|
|
if (pullBinsPointMaybeAdd(pctx, point, NULL, &added)) { |
1292 |
|
|
biffAddf(PULL, "%s: trouble binning point %u", me, point->idtag); |
1293 |
|
|
airMopError(mop); return 1; |
1294 |
|
|
} |
1295 |
|
|
/* |
1296 |
|
|
if (4523 == point->idtag) { |
1297 |
|
|
fprintf(stderr, "!%s(%u): ----- added=%d at %g %g %g %g\n", |
1298 |
|
|
me, point->idtag, added, |
1299 |
|
|
point->pos[0], point->pos[1], point->pos[2], point->pos[3]); |
1300 |
|
|
} |
1301 |
|
|
*/ |
1302 |
|
|
if (added) { |
1303 |
|
|
point = NULL; |
1304 |
|
|
} |
1305 |
|
|
} else { |
1306 |
|
|
if (pullBinsPointAdd(pctx, point, NULL)) { |
1307 |
|
|
biffAddf(PULL, "%s: trouble binning point %u", me, point->idtag); |
1308 |
|
|
airMopError(mop); return 1; |
1309 |
|
|
} |
1310 |
|
|
point = NULL; |
1311 |
|
|
} |
1312 |
|
|
} /* Done looping through total number of points */ |
1313 |
|
|
if (pctx->verbose) { |
1314 |
|
|
printf("%s\n", airDoneStr(0, pointIdx-1, totalNumPoints, |
1315 |
|
|
doneStr)); |
1316 |
|
|
} |
1317 |
|
|
if (point) { |
1318 |
|
|
/* we created a new test point, but it was never placed in the volume */ |
1319 |
|
|
/* so, HACK: undo pullPointNew . . . */ |
1320 |
|
|
point = pullPointNix(point); |
1321 |
|
|
/* pctx->idtagNext -= 1; */ |
1322 |
|
|
} |
1323 |
|
|
|
1324 |
|
|
/* Final check: do we have any points? */ |
1325 |
|
|
pn = pullPointNumber(pctx); |
1326 |
|
|
if (!pn) { |
1327 |
|
|
char stmp1[AIR_STRLEN_MED], stmp2[AIR_STRLEN_MED]; |
1328 |
|
|
int guess=AIR_FALSE; |
1329 |
|
|
sprintf(stmp1, "%s: seeded 0 points", me); |
1330 |
|
|
if (pctx->ispec[pullInfoSeedThresh]) { |
1331 |
|
|
guess=AIR_TRUE; |
1332 |
|
|
sprintf(stmp2, " (? bad seedthresh %g ?)", |
1333 |
|
|
pctx->ispec[pullInfoSeedThresh]->zero); |
1334 |
|
|
strcat(stmp1, stmp2); |
1335 |
|
|
} |
1336 |
|
|
if (pctx->flag.nixAtVolumeEdgeSpace) { |
1337 |
|
|
guess=AIR_TRUE; |
1338 |
|
|
sprintf(stmp2, " (? flag.nixAtVolumeEdgeSpace true ?)"); |
1339 |
|
|
strcat(stmp1, stmp2); |
1340 |
|
|
} |
1341 |
|
|
if (!guess) { |
1342 |
|
|
sprintf(stmp2, " (no guess as to why)"); |
1343 |
|
|
strcat(stmp1, stmp2); |
1344 |
|
|
} |
1345 |
|
|
biffAddf(PULL, "%s", stmp1); |
1346 |
|
|
airMopError(mop); return 1; |
1347 |
|
|
} |
1348 |
|
|
if (pctx->verbose) { |
1349 |
|
|
fprintf(stderr, "%s: initialized to %u points (idtagNext = %u)\n", |
1350 |
|
|
me, pn, pctx->idtagNext); |
1351 |
|
|
} |
1352 |
|
|
/* */ |
1353 |
|
|
if (1) { |
1354 |
|
|
Nrrd *ntmp; |
1355 |
|
|
ntmp = nrrdNew(); |
1356 |
|
|
pullOutputGet(ntmp, NULL, NULL, NULL, 0.0, pctx); |
1357 |
|
|
nrrdSave("pos-init.nrrd", ntmp, NULL); |
1358 |
|
|
nrrdNuke(ntmp); |
1359 |
|
|
} |
1360 |
|
|
/* */ |
1361 |
|
|
pctx->tmpPointPtr = AIR_CAST(pullPoint **, |
1362 |
|
|
calloc(pn, sizeof(pullPoint*))); |
1363 |
|
|
pctx->tmpPointPerm = AIR_CAST(unsigned int *, |
1364 |
|
|
calloc(pn, sizeof(unsigned int))); |
1365 |
|
|
if (!( pctx->tmpPointPtr && pctx->tmpPointPerm )) { |
1366 |
|
|
biffAddf(PULL, "%s: couldn't allocate tmp buffers %p %p", me, |
1367 |
|
|
AIR_VOIDP(pctx->tmpPointPtr), AIR_VOIDP(pctx->tmpPointPerm)); |
1368 |
|
|
airMopError(mop); return 1; |
1369 |
|
|
} |
1370 |
|
|
pctx->tmpPointNum = pn; |
1371 |
|
|
|
1372 |
|
|
/* now that all points have been added, set their energy to help |
1373 |
|
|
inspect initial state */ |
1374 |
|
|
for (binIdx=0; binIdx<pctx->binNum; binIdx++) { |
1375 |
|
|
bin = pctx->bin + binIdx; |
1376 |
|
|
for (pointIdx=0; pointIdx<bin->pointNum; pointIdx++) { |
1377 |
|
|
point = bin->point[pointIdx]; |
1378 |
|
|
point->energy = _pullPointEnergyTotal(pctx->task[0], bin, point, |
1379 |
|
|
/* ignoreImage */ |
1380 |
|
|
!pctx->haveScale, |
1381 |
|
|
point->force); |
1382 |
|
|
} |
1383 |
|
|
} |
1384 |
|
|
|
1385 |
|
|
if (pctx->verbose) { |
1386 |
|
|
printf("%s: all done. ", me); |
1387 |
|
|
fflush(stdout); |
1388 |
|
|
} |
1389 |
|
|
airMopOkay(mop); |
1390 |
|
|
return 0; |
1391 |
|
|
} |
1392 |
|
|
|
1393 |
|
|
void |
1394 |
|
|
_pullPointFinish(pullContext *pctx) { |
1395 |
|
|
|
1396 |
|
|
airFree(pctx->tmpPointPtr); |
1397 |
|
|
airFree(pctx->tmpPointPerm); |
1398 |
|
|
return ; |
1399 |
|
|
} |