/* ******** gageQuerySet() ** ** sets a query in a pervolume. Does recursive expansion of query ** to cover all prerequisite measures. ** ** Sets: pvl->query ** ** the gageContext is not actually used here, but I'm cautiously ** including it in case its used in the future. */ int gageQuerySet(gageContext *ctx, gagePerVolume *pvl, gageQuery query) { char me[]="gageQuerySet", err[BIFF_STRLEN]; gageQuery lastQuery; int pi, ii; AIR_UNUSED(ctx); if (!( pvl )) { sprintf(err, "%s: got NULL pointer", me); biffAdd(GAGE, err); return 1; } GAGE_QUERY_COPY(pvl->query, query); if (pvl->verbose) { fprintf(stderr, "%s: original ", me); gageQueryPrint(stderr, pvl->kind, pvl->query); } /* recursive expansion of prerequisites */ do { GAGE_QUERY_COPY(lastQuery, pvl->query); ii = pvl->kind->itemMax+1; do { ii--; if (GAGE_QUERY_ITEM_TEST(pvl->query, ii)) { for (pi=0; pi<GAGE_ITEM_PREREQ_MAXNUM; pi++) { if (0 != pvl->kind->table[ii].prereq[pi]) { GAGE_QUERY_ITEM_ON(pvl->query, pvl->kind->table[ii].prereq[pi]); } } } } while (ii); } while (!GAGE_QUERY_EQUAL(pvl->query, lastQuery)); if (pvl->verbose) { fprintf(stderr, "%s: expanded ", me); gageQueryPrint(stderr, pvl->kind, pvl->query); } /* doing this kind of error checking here is not really the way gage should work-- it should be done at the time of gageUpdate()-- but the novelty of pvl->data encourages putting new smarts at superficial levels instead of deeper levels */ if (!pvl->data) { for (ii=1; ii<=pvl->kind->itemMax; ii++) { if (GAGE_QUERY_ITEM_TEST(pvl->query, ii) && pvl->kind->table[ii].needData) { sprintf(err, "%s: item %d (%s) needs data, but pvl->data is NULL", me, ii, airEnumStr(pvl->kind->enm, ii)); biffAdd(GAGE, err); return 1; } } } pvl->flag[gagePvlFlagQuery] = AIR_TRUE; return 0; }
/* ** for each pvl: pvl's query --> pvl's needD */ void _gagePvlNeedDUpdate(gageContext *ctx) { static const char me[]="_gagePvlNeedDUpdate"; gagePerVolume *pvl; int que, needD[GAGE_DERIV_MAX+1]; unsigned int pvlIdx, di; if (ctx->verbose) fprintf(stderr, "%s: hello\n", me); for (pvlIdx=0; pvlIdx<ctx->pvlNum; pvlIdx++) { pvl = ctx->pvl[pvlIdx]; if (pvl->flag[gagePvlFlagQuery]) { GAGE_DV_SET(needD, 0, 0, 0); que = pvl->kind->itemMax+1; do { que--; if (GAGE_QUERY_ITEM_TEST(pvl->query, que)) { needD[pvl->kind->table[que].needDeriv] = 1; } } while (que); if (!GAGE_DV_EQUAL(needD, pvl->needD)) { if (ctx->verbose) { fprintf(stderr, "%s: updating pvl[%d]'s needD to (", me, pvlIdx); for (di=0; di<=GAGE_DERIV_MAX; di++) { fprintf(stderr, "%s%d", di ? "," : "", needD[di]); } fprintf(stderr, "\n"); } GAGE_DV_COPY(pvl->needD, needD); pvl->flag[gagePvlFlagNeedD] = AIR_TRUE; } } } if (ctx->verbose) fprintf(stderr, "%s: bye\n", me); return; }
/* ** for each pvl: pvl's query --> pvl's needD */ void _gagePvlNeedDUpdate(gageContext *ctx) { char me[]="_gagePvlNeedDUpdate"; gagePerVolume *pvl; int que, needD[3]; unsigned int pvlIdx; if (ctx->verbose) fprintf(stderr, "%s: hello\n", me); for (pvlIdx=0; pvlIdx<ctx->pvlNum; pvlIdx++) { pvl = ctx->pvl[pvlIdx]; if (pvl->flag[gagePvlFlagQuery]) { ELL_3V_SET(needD, 0, 0, 0); que = pvl->kind->itemMax+1; do { que--; if (GAGE_QUERY_ITEM_TEST(pvl->query, que)) { needD[pvl->kind->table[que].needDeriv] = 1; } } while (que); if (!ELL_3V_EQUAL(needD, pvl->needD)) { if (ctx->verbose) { fprintf(stderr, "%s: updating pvl[%d]'s needD to (%d,%d,%d)\n", me, pvlIdx, needD[0], needD[1], needD[2]); } ELL_3V_COPY(pvl->needD, needD); pvl->flag[gagePvlFlagNeedD] = AIR_TRUE; } } } if (ctx->verbose) fprintf(stderr, "%s: bye\n", me); return; }
void _tenDwiGageAnswer(gageContext *ctx, gagePerVolume *pvl) { AIR_UNUSED(ctx); AIR_UNUSED(pvl); #if 0 char me[]="_tenDwiGageAnswer"; unsigned int dwiIdx; tenDwiGageKindData *kindData; gage_t *dwiAll, dwiMean=0; kindData = AIR_CAST(tenDwiGageKindData *, pvl->kind->data); dwiAll = pvl->directAnswer[tenDwiGageAll]; if (GAGE_QUERY_ITEM_TEST(pvl->query, tenDwiGageAll)) { /* done if doV */ if (ctx->verbose) { for (dwiIdx=0; dwiIdx<kindData->num; dwiIdx++) { fprintf(stderr, "%s: dwi[%u] = %g\n", me, dwiIdx, dwiAll[dwiIdx]); } } } /* if (GAGE_QUERY_ITEM_TEST(pvl->query, tenDwiGageB0)) { done if doV } */ if (GAGE_QUERY_ITEM_TEST(pvl->query, tenDwiGageMeanDwiValue)) { dwiMean = 0; for (dwiIdx=1; dwiIdx<kindData->num; dwiIdx++) { dwiMean += dwiAll[dwiIdx]; } dwiMean /= 1.0f/(kindData->num - 1); pvl->directAnswer[tenDwiGageMeanDwiValue][0] = dwiMean; } if (GAGE_QUERY_ITEM_TEST(pvl->query, tenDwiGageTensorLLS)) { #if GAGE_TYPE_FLOAT tenEstimateLinearSingle_f #else tenEstimateLinearSingle_d #endif (pvl->directAnswer[tenDwiGageTensorLLS], NULL, dwiAll, AIR_CAST(double *, kindData->nemat->data), /* pvlData->vbuf */ NULL, kindData->num, AIR_TRUE, kindData->dwiConfThresh, kindData->dwiConfSoft, kindData->bval); }
void gageQueryPrint(FILE *file, const gageKind *kind, gageQuery query) { int ii; fprintf(file, "%s query = ...\n", kind->name); ii = kind->itemMax+1; do { ii--; if (GAGE_QUERY_ITEM_TEST(query, ii)) { fprintf(file, " %3d: %s\n", ii, airEnumStr(kind->enm, ii)); } } while (ii); }
void _gageVecAnswer(gageContext *ctx, gagePerVolume *pvl) { char me[]="_gageVecAnswer"; double cmag, tmpMat[9], mgevec[9], mgeval[3]; double symm[9], asym[9], tran[9], eval[3], tmpVec[3], norm; gage_t *vecAns, *normAns, *jacAns, *curlAns, *hesAns, *curlGradAns, *helGradAns, *dirHelDirAns, *curlnormgradAns; /* int asw; */ vecAns = pvl->directAnswer[gageVecVector]; normAns = pvl->directAnswer[gageVecNormalized]; jacAns = pvl->directAnswer[gageVecJacobian]; curlAns = pvl->directAnswer[gageVecCurl]; hesAns = pvl->directAnswer[gageVecHessian]; curlGradAns = pvl->directAnswer[gageVecCurlGradient]; curlnormgradAns = pvl->directAnswer[gageVecCurlNormGrad]; helGradAns = pvl->directAnswer[gageVecHelGradient]; dirHelDirAns = pvl->directAnswer[gageVecDirHelDeriv]; if (GAGE_QUERY_ITEM_TEST(pvl->query, gageVecVector)) { /* done if doV */ if (ctx->verbose) { fprintf(stderr, "vec = "); ell_3v_PRINT(stderr, vecAns); } } /* done if doV if (GAGE_QUERY_ITEM_TEST(pvl->query, gageVecVector{0,1,2})) { } */ if (GAGE_QUERY_ITEM_TEST(pvl->query, gageVecLength)) { pvl->directAnswer[gageVecLength][0] = AIR_CAST(gage_t, ELL_3V_LEN(vecAns)); } if (GAGE_QUERY_ITEM_TEST(pvl->query, gageVecNormalized)) { if (pvl->directAnswer[gageVecLength][0]) { ELL_3V_SCALE_TT(normAns, gage_t, 1.0/pvl->directAnswer[gageVecLength][0], vecAns); } else { ELL_3V_COPY(normAns, gageZeroNormal); } } if (GAGE_QUERY_ITEM_TEST(pvl->query, gageVecJacobian)) { /* done if doD1 */ /* 0:dv_x/dx 1:dv_x/dy 2:dv_x/dz 3:dv_y/dx 4:dv_y/dy 5:dv_y/dz 6:dv_z/dx 7:dv_z/dy 8:dv_z/dz */ if (ctx->verbose) { fprintf(stderr, "%s: jac = \n", me); ell_3m_PRINT(stderr, jacAns); } } if (GAGE_QUERY_ITEM_TEST(pvl->query, gageVecDivergence)) { pvl->directAnswer[gageVecDivergence][0] = jacAns[0] + jacAns[4] + jacAns[8]; if (ctx->verbose) { fprintf(stderr, "%s: div = %g + %g + %g = %g\n", me, jacAns[0], jacAns[4], jacAns[8], pvl->directAnswer[gageVecDivergence][0]); } } if (GAGE_QUERY_ITEM_TEST(pvl->query, gageVecCurl)) { ELL_3V_SET(curlAns, jacAns[7] - jacAns[5], jacAns[2] - jacAns[6], jacAns[3] - jacAns[1]); } if (GAGE_QUERY_ITEM_TEST(pvl->query, gageVecCurlNorm)) { pvl->directAnswer[gageVecCurlNorm][0] = AIR_CAST(gage_t, ELL_3V_LEN(curlAns)); } if (GAGE_QUERY_ITEM_TEST(pvl->query, gageVecHelicity)) { pvl->directAnswer[gageVecHelicity][0] = ELL_3V_DOT(vecAns, curlAns); } if (GAGE_QUERY_ITEM_TEST(pvl->query, gageVecNormHelicity)) { cmag = ELL_3V_LEN(curlAns); pvl->directAnswer[gageVecNormHelicity][0] = AIR_CAST(gage_t, cmag ? ELL_3V_DOT(normAns, curlAns)/cmag : 0); } if (GAGE_QUERY_ITEM_TEST(pvl->query, gageVecLambda2)) { ELL_3M_TRANSPOSE(tran, jacAns); /* symmetric part */ ELL_3M_SCALE_ADD2(symm, 0.5, jacAns, 0.5, tran); /* antisymmetric part */ ELL_3M_SCALE_ADD2(asym, 0.5, jacAns, -0.5, tran); /* square symmetric part */ ELL_3M_MUL(tmpMat, symm, symm); ELL_3M_COPY(symm, tmpMat); /* square antisymmetric part */ ELL_3M_MUL(tmpMat, asym, asym); /* sum of both */ ELL_3M_ADD2(symm, symm, tmpMat); /* get eigenvalues in sorted order */ /* asw = */ ell_3m_eigenvalues_d(eval, symm, AIR_TRUE); pvl->directAnswer[gageVecLambda2][0] = AIR_CAST(gage_t, eval[1]); } if (GAGE_QUERY_ITEM_TEST(pvl->query, gageVecImaginaryPart)) { pvl->directAnswer[gageVecImaginaryPart][0] = AIR_CAST(gage_t, gage_imaginary_part_eigenvalues(jacAns)); } /* 2nd order vector derivative continued */ if (GAGE_QUERY_ITEM_TEST(pvl->query, gageVecHessian)) { /* done if doD2 */ /* the ordering is induced by the scalar hessian computation : 0:d2v_x/dxdx 1:d2v_x/dxdy 2:d2v_x/dxdz 3:d2v_x/dydx 4:d2v_x/dydy 5:d2v_x/dydz 6:d2v_x/dzdx 7:d2v_x/dzdy 8:d2v_x/dzdz 9:d2v_y/dxdx [...] [...] 24:dv2_z/dzdx 25:d2v_z/dzdy 26:d2v_z/dzdz */ if (ctx->verbose) { fprintf(stderr, "%s: hes = \n", me); ell_3m_PRINT(stderr, hesAns); /* ?? */ } } if (GAGE_QUERY_ITEM_TEST(pvl->query, gageVecDivGradient)) { pvl->directAnswer[gageVecDivGradient][0] = hesAns[0] + hesAns[12] + hesAns[24]; pvl->directAnswer[gageVecDivGradient][1] = hesAns[1] + hesAns[13] + hesAns[25]; pvl->directAnswer[gageVecDivGradient][2] = hesAns[2] + hesAns[14] + hesAns[26]; } if (GAGE_QUERY_ITEM_TEST(pvl->query, gageVecCurlGradient)) { pvl->directAnswer[gageVecCurlGradient][0] = hesAns[21]-hesAns[15]; pvl->directAnswer[gageVecCurlGradient][1] = hesAns[22]-hesAns[16]; pvl->directAnswer[gageVecCurlGradient][2] = hesAns[23]-hesAns[17]; pvl->directAnswer[gageVecCurlGradient][3] = hesAns[ 6]-hesAns[18]; pvl->directAnswer[gageVecCurlGradient][4] = hesAns[ 7]-hesAns[19]; pvl->directAnswer[gageVecCurlGradient][5] = hesAns[ 8]-hesAns[20]; pvl->directAnswer[gageVecCurlGradient][6] = hesAns[ 9]-hesAns[ 1]; pvl->directAnswer[gageVecCurlGradient][7] = hesAns[10]-hesAns[ 2]; pvl->directAnswer[gageVecCurlGradient][8] = hesAns[11]-hesAns[ 3]; } if (GAGE_QUERY_ITEM_TEST(pvl->query, gageVecCurlNormGrad)) { norm = 1./ELL_3V_LEN(curlAns); tmpVec[0] = hesAns[21] - hesAns[15]; tmpVec[1] = hesAns[ 6] - hesAns[18]; tmpVec[2] = hesAns[ 9] - hesAns[ 3]; pvl->directAnswer[gageVecCurlNormGrad][0]= AIR_CAST(gage_t, norm*ELL_3V_DOT(tmpVec, curlAns)); tmpVec[0] = hesAns[22] - hesAns[16]; tmpVec[1] = hesAns[ 7] - hesAns[19]; tmpVec[2] = hesAns[10] - hesAns[ 4]; pvl->directAnswer[gageVecCurlNormGrad][1]= AIR_CAST(gage_t, norm*ELL_3V_DOT(tmpVec, curlAns)); tmpVec[0] = hesAns[23] - hesAns[17]; tmpVec[1] = hesAns[ 8] - hesAns[20]; tmpVec[2] = hesAns[11] - hesAns[ 5]; pvl->directAnswer[gageVecCurlNormGrad][2]= AIR_CAST(gage_t, norm*ELL_3V_DOT(tmpVec, curlAns)); } if (GAGE_QUERY_ITEM_TEST(pvl->query, gageVecNCurlNormGrad)) { norm = 1./ELL_3V_LEN(curlnormgradAns); ELL_3V_SCALE_TT(pvl->directAnswer[gageVecNCurlNormGrad], gage_t, norm, pvl->directAnswer[gageVecCurlNormGrad]); } if (GAGE_QUERY_ITEM_TEST(pvl->query, gageVecHelGradient)) { pvl->directAnswer[gageVecHelGradient][0] = jacAns[0]*curlAns[0]+ jacAns[3]*curlAns[1]+ jacAns[6]*curlAns[2]+ curlGradAns[0]*vecAns[0]+ curlGradAns[3]*vecAns[1]+ curlGradAns[6]*vecAns[2]; pvl->directAnswer[gageVecHelGradient][1] = jacAns[1]*curlAns[0]+ jacAns[4]*curlAns[1]+ jacAns[7]*curlAns[2]+ curlGradAns[1]*vecAns[0]+ curlGradAns[4]*vecAns[1]+ curlGradAns[7]*vecAns[2]; pvl->directAnswer[gageVecHelGradient][0] = jacAns[2]*curlAns[0]+ jacAns[5]*curlAns[1]+ jacAns[8]*curlAns[2]+ curlGradAns[2]*vecAns[0]+ curlGradAns[5]*vecAns[1]+ curlGradAns[8]*vecAns[2]; } if (GAGE_QUERY_ITEM_TEST(pvl->query, gageVecDirHelDeriv)) { pvl->directAnswer[gageVecDirHelDeriv][0] = ELL_3V_DOT(normAns, helGradAns); } if (GAGE_QUERY_ITEM_TEST(pvl->query, gageVecProjHelGradient)) { pvl->directAnswer[gageVecDirHelDeriv][0] = helGradAns[0]-dirHelDirAns[0]*normAns[0]; pvl->directAnswer[gageVecDirHelDeriv][1] = helGradAns[1]-dirHelDirAns[0]*normAns[1]; pvl->directAnswer[gageVecDirHelDeriv][2] = helGradAns[2]-dirHelDirAns[0]*normAns[2]; } if (GAGE_QUERY_ITEM_TEST(pvl->query, gageVecGradient0)) { ELL_3V_SET(pvl->directAnswer[gageVecGradient0], jacAns[0], jacAns[1], jacAns[2]); } if (GAGE_QUERY_ITEM_TEST(pvl->query, gageVecGradient1)) { ELL_3V_SET(pvl->directAnswer[gageVecGradient1], jacAns[3], jacAns[4], jacAns[5]); } if (GAGE_QUERY_ITEM_TEST(pvl->query, gageVecGradient2)) { ELL_3V_SET(pvl->directAnswer[gageVecGradient2], jacAns[6], jacAns[7], jacAns[8]); } if (GAGE_QUERY_ITEM_TEST(pvl->query, gageVecMultiGrad)) { ELL_3M_IDENTITY_SET(pvl->directAnswer[gageVecMultiGrad]); ELL_3MV_OUTER_ADD(pvl->directAnswer[gageVecMultiGrad], pvl->directAnswer[gageVecGradient0], pvl->directAnswer[gageVecGradient0]); ELL_3MV_OUTER_ADD(pvl->directAnswer[gageVecMultiGrad], pvl->directAnswer[gageVecGradient1], pvl->directAnswer[gageVecGradient1]); ELL_3MV_OUTER_ADD(pvl->directAnswer[gageVecMultiGrad], pvl->directAnswer[gageVecGradient2], pvl->directAnswer[gageVecGradient2]); } if (GAGE_QUERY_ITEM_TEST(pvl->query, gageVecMGFrob)) { pvl->directAnswer[gageVecMGFrob][0] = AIR_CAST(gage_t, ELL_3M_FROB(pvl->directAnswer[gageVecMultiGrad])); } if (GAGE_QUERY_ITEM_TEST(pvl->query, gageVecMGEval)) { ELL_3M_COPY(tmpMat, pvl->directAnswer[gageVecMultiGrad]); /* HEY: look at the return value for root multiplicity? */ ell_3m_eigensolve_d(mgeval, mgevec, tmpMat, AIR_TRUE); ELL_3V_COPY_TT(pvl->directAnswer[gageVecMGEval], gage_t, mgeval); } if (GAGE_QUERY_ITEM_TEST(pvl->query, gageVecMGEvec)) { ELL_3M_COPY_TT(pvl->directAnswer[gageVecMGEvec], gage_t, mgevec); } return; }
double miteSample(miteThread *mtt, miteRender *mrr, miteUser *muu, int num, double rayT, int inside, double samplePosWorld[3], double samplePosIndex[3]) { static const char me[]="miteSample"; mite_t R, G, B, A; double *NN; double NdotV, kn[3], knd[3], ref[3], len, *dbg=NULL; if (!inside) { return mtt->rayStep; } if (mtt->skip) { /* we have one verbose pixel, but we're not on it */ return 0.0; } /* early ray termination */ if (1-mtt->TT >= muu->opacNear1) { mtt->TT = 0.0; return 0.0; } /* set (fake) view based on fake from */ if (AIR_EXISTS(muu->fakeFrom[0])) { ELL_3V_SUB(mtt->V, samplePosWorld, muu->fakeFrom); ELL_3V_NORM(mtt->V, mtt->V, len); } /* do probing at this location to determine values of everything that might appear in the txf domain */ if (gageProbe(mtt->gctx, samplePosIndex[0], samplePosIndex[1], samplePosIndex[2])) { biffAddf(MITE, "%s: gage trouble: %s (%d)", me, mtt->gctx->errStr, mtt->gctx->errNum); return AIR_NAN; } if (mrr->queryMiteNonzero) { /* There is some optimal trade-off between slowing things down with too many branches on all possible checks of queryMite, and slowing things down with doing the work of setting them all. This code has not been profiled whatsoever */ mtt->directAnsMiteVal[miteValXw][0] = samplePosWorld[0]; mtt->directAnsMiteVal[miteValXi][0] = samplePosIndex[0]; mtt->directAnsMiteVal[miteValYw][0] = samplePosWorld[1]; mtt->directAnsMiteVal[miteValYi][0] = samplePosIndex[1]; mtt->directAnsMiteVal[miteValZw][0] = samplePosWorld[2]; mtt->directAnsMiteVal[miteValZi][0] = samplePosIndex[2]; mtt->directAnsMiteVal[miteValRw][0] = ELL_3V_LEN(samplePosWorld); mtt->directAnsMiteVal[miteValRi][0] = ELL_3V_LEN(samplePosIndex); mtt->directAnsMiteVal[miteValTw][0] = rayT; mtt->directAnsMiteVal[miteValTi][0] = num; ELL_3V_COPY(mtt->directAnsMiteVal[miteValView], mtt->V); NN = mtt->directAnsMiteVal[miteValNormal]; if (mtt->_normal) { if (1 == muu->normalSide) { ELL_3V_SCALE(NN, -1, mtt->_normal); } else { ELL_3V_COPY(NN, mtt->_normal); } } if ((GAGE_QUERY_ITEM_TEST(mrr->queryMite, miteValNdotV) || GAGE_QUERY_ITEM_TEST(mrr->queryMite, miteValNdotL) || GAGE_QUERY_ITEM_TEST(mrr->queryMite, miteValVrefN))) { mtt->directAnsMiteVal[miteValNdotV][0] = ELL_3V_DOT(NN, mtt->V); mtt->directAnsMiteVal[miteValNdotL][0] = ELL_3V_DOT(NN, muu->lit->dir[0]); if (!muu->normalSide) { mtt->directAnsMiteVal[miteValNdotV][0] = AIR_ABS(mtt->directAnsMiteVal[miteValNdotV][0]); mtt->directAnsMiteVal[miteValNdotL][0] = AIR_ABS(mtt->directAnsMiteVal[miteValNdotL][0]); } NdotV = mtt->directAnsMiteVal[miteValNdotV][0]; ELL_3V_SCALE_ADD2(ref, 2*NdotV, NN, -1, mtt->V); ELL_3V_NORM(mtt->directAnsMiteVal[miteValVrefN], ref, len); } if (GAGE_QUERY_ITEM_TEST(mrr->queryMite, miteValGTdotV)) { ELL_3MV_MUL(kn, mtt->nPerp, mtt->V); ELL_3V_NORM(kn, kn, len); ELL_3MV_MUL(knd, mtt->geomTens, kn); mtt->directAnsMiteVal[miteValGTdotV][0] = ELL_3V_DOT(knd, kn); } } /* initialize txf range quantities, and apply all txfs */ if (mtt->verbose) { muu->debugIdx = airArrayLenIncr(muu->debugArr, muu->ndebug->axis[0].size); } memcpy(mtt->range, muu->rangeInit, MITE_RANGE_NUM*sizeof(mite_t)); _miteStageRun(mtt, muu); /* if there's opacity, do shading and compositing */ if (mtt->range[miteRangeAlpha]) { /* fprintf(stderr, "%s: mtt->TT = %g\n", me, mtt->TT); */ /* if (mtt->verbose) { fprintf(stderr, "%s: before compositing: RGBT = %g,%g,%g,%g\n", me, mtt->RR, mtt->GG, mtt->BB, mtt->TT); } */ _miteRGBACalc(&R, &G, &B, &A, mtt, mrr, muu); mtt->RR += mtt->TT*A*R; mtt->GG += mtt->TT*A*G; mtt->BB += mtt->TT*A*B; mtt->TT *= 1-A; /* if (mtt->verbose) { fprintf(stderr, "%s: after compositing: RGBT = %g,%g,%g,%g\n", me, mtt->RR, mtt->GG, mtt->BB, mtt->TT); } */ /* fprintf(stderr, "%s: mtt->TT = %g\n", me, mtt->TT); */ } else { R = G = B = A = 0; } if (mtt->verbose) { dbg = muu->debug + muu->debugIdx; dbg[0 + 2*mtt->stageNum] = R; dbg[1 + 2*mtt->stageNum] = G; dbg[2 + 2*mtt->stageNum] = B; dbg[3 + 2*mtt->stageNum] = A; dbg[4 + 2*mtt->stageNum] = rayT; } /* set Z if it hasn't been set already */ if (1-mtt->TT >= muu->opacMatters && !AIR_EXISTS(mtt->ZZ)) { mtt->ZZ = rayT; } /* this is used to index mtt->debug */ mtt->raySample += 1; return mtt->rayStep; }
void _gageSclAnswer (gageContext *ctx, gagePerVolume *pvl) { char me[]="_gageSclAnswer"; double gmag=0, *hess, *norm, *gvec, *gten, *k1, *k2, curv=0, sHess[9]={0,0,0,0,0,0,0,0,0}; double tmpMat[9], tmpVec[3], hevec[9], heval[3]; double len, gp1[3], gp2[3], *nPerp, ncTen[9], nProj[9]={0,0,0,0,0,0,0,0,0}; double alpha = 0.5; double beta = 0.5; double gamma = 5; double cc = 1e-6; #define FD_MEDIAN_MAX 16 int fd, nidx, xi, yi, zi; double *fw, iv3wght[2*FD_MEDIAN_MAX*FD_MEDIAN_MAX*FD_MEDIAN_MAX], wghtSum, wght; /* convenience pointers for work below */ hess = pvl->directAnswer[gageSclHessian]; gvec = pvl->directAnswer[gageSclGradVec]; norm = pvl->directAnswer[gageSclNormal]; nPerp = pvl->directAnswer[gageSclNPerp]; gten = pvl->directAnswer[gageSclGeomTens]; k1 = pvl->directAnswer[gageSclK1]; k2 = pvl->directAnswer[gageSclK2]; if (GAGE_QUERY_ITEM_TEST(pvl->query, gageSclValue)) { /* done if doV */ if (ctx->verbose) { fprintf(stderr, "%s: val = % 15.7f\n", me, (double)(pvl->directAnswer[gageSclValue][0])); } } if (GAGE_QUERY_ITEM_TEST(pvl->query, gageSclGradVec)) { /* done if doD1 */ if (ctx->verbose) { fprintf(stderr, "%s: gvec = ", me); ell_3v_print_d(stderr, gvec); } } if (GAGE_QUERY_ITEM_TEST(pvl->query, gageSclGradMag)) { /* this is the true value of gradient magnitude */ gmag = pvl->directAnswer[gageSclGradMag][0] = sqrt(ELL_3V_DOT(gvec, gvec)); } /* NB: it would seem that gageParmGradMagMin is completely ignored ... */ if (GAGE_QUERY_ITEM_TEST(pvl->query, gageSclNormal)) { if (gmag) { ELL_3V_SCALE(norm, 1/gmag, gvec); /* polishing ... len = sqrt(ELL_3V_DOT(norm, norm)); ELL_3V_SCALE(norm, 1/len, norm); */ } else { ELL_3V_COPY(norm, gageZeroNormal); } } if (GAGE_QUERY_ITEM_TEST(pvl->query, gageSclNPerp)) { /* nPerp = I - outer(norm, norm) */ /* NB: this sets both nPerp and nProj */ ELL_3MV_OUTER(nProj, norm, norm); ELL_3M_SCALE(nPerp, -1, nProj); nPerp[0] += 1; nPerp[4] += 1; nPerp[8] += 1; } if (GAGE_QUERY_ITEM_TEST(pvl->query, gageSclHessian)) { /* done if doD2 */ if (ctx->verbose) { fprintf(stderr, "%s: hess = \n", me); ell_3m_print_d(stderr, hess); } } if (GAGE_QUERY_ITEM_TEST(pvl->query, gageSclLaplacian)) { pvl->directAnswer[gageSclLaplacian][0] = hess[0] + hess[4] + hess[8]; if (ctx->verbose) { fprintf(stderr, "%s: lapl = %g + %g + %g = %g\n", me, hess[0], hess[4], hess[8], pvl->directAnswer[gageSclLaplacian][0]); } } if (GAGE_QUERY_ITEM_TEST(pvl->query, gageSclHessFrob)) { pvl->directAnswer[gageSclHessFrob][0] = ELL_3M_FROB(hess); } if (GAGE_QUERY_ITEM_TEST(pvl->query, gageSclHessEval)) { /* HEY: look at the return value for root multiplicity? */ ell_3m_eigensolve_d(heval, hevec, hess, AIR_TRUE); ELL_3V_COPY(pvl->directAnswer[gageSclHessEval], heval); } if (GAGE_QUERY_ITEM_TEST(pvl->query, gageSclHessEvec)) { ELL_3M_COPY(pvl->directAnswer[gageSclHessEvec], hevec); } if (GAGE_QUERY_ITEM_TEST(pvl->query, gageSclHessRidgeness)) { double A, B, S; if (heval[1] >0 || heval[2]>0) { pvl->directAnswer[gageSclHessRidgeness][0] = 0; } else if (AIR_ABS(heval[1])<1e-10 || AIR_ABS(heval[2])<1e-10) { pvl->directAnswer[gageSclHessRidgeness][0] = 0; } else { double *ans; A = AIR_ABS(heval[1])/AIR_ABS(heval[2]); B = AIR_ABS(heval[0])/sqrt(AIR_ABS(heval[1]*heval[2])); S = sqrt(heval[0]*heval[0] + heval[1]*heval[1] + heval[2]*heval[2]); ans = pvl->directAnswer[gageSclHessRidgeness]; ans[0] = (1-exp(-A*A/(2*alpha*alpha))) * exp(-B*B/(2*beta*beta)) * (1-exp(-S*S/(2*gamma*gamma))) * exp(-2*cc*cc/(AIR_ABS(heval[1])*heval[2]*heval[2])); } } if (GAGE_QUERY_ITEM_TEST(pvl->query, gageSclHessValleyness)) { double A, B, S; if (heval[0] <0 || heval[1]<0) { pvl->directAnswer[gageSclHessValleyness][0] = 0; } else if (AIR_ABS(heval[0])<1e-10 || AIR_ABS(heval[1])<1e-10) { pvl->directAnswer[gageSclHessValleyness][0] = 0; } else { double *ans; A = AIR_ABS(heval[1])/AIR_ABS(heval[0]); B = AIR_ABS(heval[2])/sqrt(AIR_ABS(heval[1]*heval[0])); S = sqrt(heval[0]*heval[0] + heval[1]*heval[1] + heval[2]*heval[2]); ans = pvl->directAnswer[gageSclHessValleyness]; ans[0] = (1-exp(-A*A/(2*alpha*alpha))) * exp(-B*B/(2*beta*beta)) * (1-exp(-S*S/(2*gamma*gamma))) * exp(-2*cc*cc/(AIR_ABS(heval[1])*heval[0]*heval[0])); } } if (GAGE_QUERY_ITEM_TEST(pvl->query, gageSclHessMode)) { pvl->directAnswer[gageSclHessMode][0] = airMode3_d(heval); } if (GAGE_QUERY_ITEM_TEST(pvl->query, gageScl2ndDD)) { ELL_3MV_MUL(tmpVec, hess, norm); pvl->directAnswer[gageScl2ndDD][0] = ELL_3V_DOT(norm, tmpVec); } if (GAGE_QUERY_ITEM_TEST(pvl->query, gageSclGeomTens)) { if (gmag > ctx->parm.gradMagCurvMin) { /* parm.curvNormalSide applied here to determine the sense of the normal when doing all curvature calculations */ ELL_3M_SCALE(sHess, -(ctx->parm.curvNormalSide)/gmag, hess); /* gten = nPerp * sHess * nPerp */ ELL_3M_MUL(tmpMat, sHess, nPerp); ELL_3M_MUL(gten, nPerp, tmpMat); if (ctx->verbose) { fprintf(stderr, "%s: gten: \n", me); ell_3m_print_d(stderr, gten); ELL_3MV_MUL(tmpVec, gten, norm); len = ELL_3V_LEN(tmpVec); fprintf(stderr, "%s: should be small: %30.15f\n", me, (double)len); ell_3v_perp_d(gp1, norm); ELL_3MV_MUL(tmpVec, gten, gp1); len = ELL_3V_LEN(tmpVec); fprintf(stderr, "%s: should be bigger: %30.15f\n", me, (double)len); ELL_3V_CROSS(gp2, gp1, norm); ELL_3MV_MUL(tmpVec, gten, gp2); len = ELL_3V_LEN(tmpVec); fprintf(stderr, "%s: should (also) be bigger: %30.15f\n", me, (double)len); } } else { ELL_3M_ZERO_SET(gten); } } if (GAGE_QUERY_ITEM_TEST(pvl->query, gageSclTotalCurv)) { curv = pvl->directAnswer[gageSclTotalCurv][0] = ELL_3M_FROB(gten); } if (GAGE_QUERY_ITEM_TEST(pvl->query, gageSclShapeTrace)) { pvl->directAnswer[gageSclShapeTrace][0] = (curv ? ELL_3M_TRACE(gten)/curv : 0); } if ( (GAGE_QUERY_ITEM_TEST(pvl->query, gageSclK1)) || (GAGE_QUERY_ITEM_TEST(pvl->query, gageSclK2)) ){ double T, N, D; T = ELL_3M_TRACE(gten); N = curv; D = 2*N*N - T*T; /* if (D < -0.0000001) { fprintf(stderr, "%s: %g %g\n", me, T, N); fprintf(stderr, "%s: !!! D curv determinant % 22.10f < 0.0\n", me, D); fprintf(stderr, "%s: gten: \n", me); ell_3m_print_d(stderr, gten); } */ D = AIR_MAX(D, 0); D = sqrt(D); k1[0] = 0.5*(T + D); k2[0] = 0.5*(T - D); } if (GAGE_QUERY_ITEM_TEST(pvl->query, gageSclMeanCurv)) { pvl->directAnswer[gageSclMeanCurv][0] = (*k1 + *k2)/2; } if (GAGE_QUERY_ITEM_TEST(pvl->query, gageSclGaussCurv)) { pvl->directAnswer[gageSclGaussCurv][0] = (*k1)*(*k2); } if (GAGE_QUERY_ITEM_TEST(pvl->query, gageSclShapeIndex)) { pvl->directAnswer[gageSclShapeIndex][0] = -(2/AIR_PI)*atan2(*k1 + *k2, *k1 - *k2); } if (GAGE_QUERY_ITEM_TEST(pvl->query, gageSclCurvDir1)) { /* HEY: this only works when K1, K2, 0 are all well mutually distinct, since these are the eigenvalues of the geometry tensor, and this code assumes that the eigenspaces are all one-dimensional */ ELL_3M_COPY(tmpMat, gten); ELL_3M_DIAG_SET(tmpMat, gten[0] - *k1, gten[4]- *k1, gten[8] - *k1); ell_3m_1d_nullspace_d(tmpVec, tmpMat); ELL_3V_COPY(pvl->directAnswer[gageSclCurvDir1], tmpVec); } if (GAGE_QUERY_ITEM_TEST(pvl->query, gageSclCurvDir2)) { /* HEY: this only works when K1, K2, 0 are all well mutually distinct, since these are the eigenvalues of the geometry tensor, and this code assumes that the eigenspaces are all one-dimensional */ ELL_3M_COPY(tmpMat, gten); ELL_3M_DIAG_SET(tmpMat, gten[0] - *k2, gten[4] - *k2, gten[8] - *k2); ell_3m_1d_nullspace_d(tmpVec, tmpMat); ELL_3V_COPY(pvl->directAnswer[gageSclCurvDir2], tmpVec); } if (GAGE_QUERY_ITEM_TEST(pvl->query, gageSclFlowlineCurv)) { if (gmag >= ctx->parm.gradMagCurvMin) { /* because of the gageSclGeomTens prerequisite, sHess, nPerp, and nProj are all already set */ /* ncTen = nPerp * sHess * nProj */ ELL_3M_MUL(tmpMat, sHess, nProj); ELL_3M_MUL(ncTen, nPerp, tmpMat); } else { ELL_3M_ZERO_SET(ncTen); } /* there used to be a wrong extra sqrt() here */ pvl->directAnswer[gageSclFlowlineCurv][0] = ELL_3M_FROB(ncTen); } if (GAGE_QUERY_ITEM_TEST(pvl->query, gageSclMedian)) { /* this item is currently a complete oddball in that it does not benefit from anything done in the "filter" stage, which is in fact a waste of time if the query consists only of this item */ fd = 2*ctx->radius; if (fd > FD_MEDIAN_MAX) { fprintf(stderr, "%s: PANIC: current filter diameter = %d " "> FD_MEDIAN_MAX = %d\n", me, fd, FD_MEDIAN_MAX); exit(1); } fw = ctx->fw + fd*3*gageKernel00; /* HEY: this needs some optimization help */ wghtSum = 0; nidx = 0; for (xi=0; xi<fd; xi++) { for (yi=0; yi<fd; yi++) { for (zi=0; zi<fd; zi++) { iv3wght[0 + 2*nidx] = pvl->iv3[nidx]; iv3wght[1 + 2*nidx] = fw[xi + 0*fd]*fw[yi + 1*fd]*fw[zi + 2*fd]; wghtSum += iv3wght[1 + 2*nidx]; nidx++; } } } qsort(iv3wght, fd*fd*fd, 2*sizeof(double), nrrdValCompare[nrrdTypeDouble]); wght = 0; for (nidx=0; nidx<fd*fd*fd; nidx++) { wght += iv3wght[1 + 2*nidx]; if (wght > wghtSum/2) { break; } } pvl->directAnswer[gageSclMedian][0] = iv3wght[0 + 2*nidx]; } return; }
void _tenGageAnswer (gageContext *ctx, gagePerVolume *pvl) { /* char me[]="_tenGageAnswer"; */ gage_t epsilon=1.0E-10f; gage_t *tenAns, *evalAns, *evecAns, *vecTmp=NULL, *gradDtA=NULL, *gradDtB=NULL, *gradDtC=NULL, *gradDtD=NULL, *gradDtE=NULL, *gradDtF=NULL, gradDdXYZ[21]={0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0}, *gradCbS=NULL, *gradCbB=NULL, *gradCbQ=NULL, *gradCbR=NULL; gage_t tmp0, tmp1, magTmp=0, gradCbA[3]={0,0,0}, gradCbC[3]={0,0,0}, dtA=0, dtB=0, dtC=0, dtD=0, dtE=0, dtF=0, cbQQQ=0, cbQ=0, cbR=0, cbA=0, cbB=0, cbC=0, cbS=0; #if !GAGE_TYPE_FLOAT int ci; float evalAnsF[3], aniso[TEN_ANISO_MAX+1]; #endif tenAns = pvl->directAnswer[tenGageTensor]; evalAns = pvl->directAnswer[tenGageEval]; evecAns = pvl->directAnswer[tenGageEvec]; if (GAGE_QUERY_ITEM_TEST(pvl->query, tenGageTensor)) { /* done if doV */ tenAns[0] = AIR_CLAMP(0.0f, tenAns[0], 1.0f); dtA = tenAns[1]; dtB = tenAns[2]; dtC = tenAns[3]; dtD = tenAns[4]; dtE = tenAns[5]; dtF = tenAns[6]; if (ctx->verbose) { fprintf(stderr, "tensor = (%g) %g %g %g %g %g %g\n", tenAns[0], dtA, dtB, dtC, dtD, dtE, dtF); } } /* done if doV if (GAGE_QUERY_ITEM_TEST(pvl->query, tenGageConfidence)) { } */ if (GAGE_QUERY_ITEM_TEST(pvl->query, tenGageTrace)) { cbA = -(pvl->directAnswer[tenGageTrace][0] = dtA + dtD + dtF); } if (GAGE_QUERY_ITEM_TEST(pvl->query, tenGageB)) { cbB = pvl->directAnswer[tenGageB][0] = dtA*dtD + dtA*dtF + dtD*dtF - dtB*dtB - dtC*dtC - dtE*dtE; } if (GAGE_QUERY_ITEM_TEST(pvl->query, tenGageDet)) { cbC = -(pvl->directAnswer[tenGageDet][0] = 2.0f*dtB*dtC*dtE + dtA*dtD*dtF - dtC*dtC*dtD - dtA*dtE*dtE - dtB*dtB*dtF); } if (GAGE_QUERY_ITEM_TEST(pvl->query, tenGageS)) { cbS = (pvl->directAnswer[tenGageS][0] = dtA*dtA + dtD*dtD + dtF*dtF + 2.0f*dtB*dtB + 2.0f*dtC*dtC + 2.0f*dtE*dtE); } if (GAGE_QUERY_ITEM_TEST(pvl->query, tenGageQ)) { cbQ = pvl->directAnswer[tenGageQ][0] = (cbS - cbB)/9.0f; } if (GAGE_QUERY_ITEM_TEST(pvl->query, tenGageFA)) { pvl->directAnswer[tenGageFA][0] = AIR_CAST(gage_t, 3*sqrt(cbQ/(epsilon + cbS))); } if (GAGE_QUERY_ITEM_TEST(pvl->query, tenGageR)) { cbR = pvl->directAnswer[tenGageR][0] = (5.0f*cbA*cbB - 27.0f*cbC - 2.0f*cbA*cbS)/54.0f; } if (GAGE_QUERY_ITEM_TEST(pvl->query, tenGageTheta)) { cbQQQ = cbQ*cbQ*cbQ; tmp0 = AIR_CAST(gage_t, cbR/(epsilon + sqrt(cbQQQ))); tmp0 = AIR_CLAMP(-1.0f, tmp0, 1.0f); pvl->directAnswer[tenGageTheta][0] = AIR_CAST(gage_t, acos(tmp0)/AIR_PI); } if (GAGE_QUERY_ITEM_TEST(pvl->query, tenGageEvec)) { /* we do the longer process to get eigenvectors, and in the process we always find the eigenvalues, whether or not they were asked for */ #if GAGE_TYPE_FLOAT tenEigensolve_f(evalAns, evecAns, tenAns); #else tenEigensolve_d(evalAns, evecAns, tenAns); #endif } else if (GAGE_QUERY_ITEM_TEST(pvl->query, tenGageEval)) { /* else eigenvectors are NOT needed, but eigenvalues ARE needed */ #if GAGE_TYPE_FLOAT tenEigensolve_f(evalAns, NULL, tenAns); #else tenEigensolve_d(evalAns, NULL, tenAns); #endif } if (GAGE_QUERY_ITEM_TEST(pvl->query, tenGageTensorGrad)) { /* done if doD1 */ /* still have to set up pointer variables that item answers below will rely on as short-cuts */ vecTmp = pvl->directAnswer[tenGageTensorGrad]; gradDtA = vecTmp + 1*3; gradDtB = vecTmp + 2*3; gradDtC = vecTmp + 3*3; gradDtD = vecTmp + 4*3; gradDtE = vecTmp + 5*3; gradDtF = vecTmp + 6*3; TEN_T_SET(gradDdXYZ + 0*7, tenAns[0], gradDtA[0], gradDtB[0], gradDtC[0], gradDtD[0], gradDtE[0], gradDtF[0]); TEN_T_SET(gradDdXYZ + 1*7, tenAns[0], gradDtA[1], gradDtB[1], gradDtC[1], gradDtD[1], gradDtE[1], gradDtF[1]); TEN_T_SET(gradDdXYZ + 2*7, tenAns[0], gradDtA[2], gradDtB[2], gradDtC[2], gradDtD[2], gradDtE[2], gradDtF[2]); } if (GAGE_QUERY_ITEM_TEST(pvl->query, tenGageTensorGradMag)) { vecTmp = pvl->directAnswer[tenGageTensorGradMag]; vecTmp[0] = AIR_CAST(gage_t, sqrt(TEN_T_DOT(gradDdXYZ + 0*7, gradDdXYZ + 0*7))); vecTmp[1] = AIR_CAST(gage_t, sqrt(TEN_T_DOT(gradDdXYZ + 1*7, gradDdXYZ + 1*7))); vecTmp[2] = AIR_CAST(gage_t, sqrt(TEN_T_DOT(gradDdXYZ + 2*7, gradDdXYZ + 2*7))); } if (GAGE_QUERY_ITEM_TEST(pvl->query, tenGageTensorGradMag)) { pvl->directAnswer[tenGageTensorGradMagMag][0] = AIR_CAST(gage_t, ELL_3V_LEN(vecTmp)); } /* --- Trace --- */ if (GAGE_QUERY_ITEM_TEST(pvl->query, tenGageTraceGradVec)) { vecTmp = pvl->directAnswer[tenGageTraceGradVec]; ELL_3V_ADD3(vecTmp, gradDtA, gradDtD, gradDtF); ELL_3V_SCALE(gradCbA, -1, vecTmp); } if (GAGE_QUERY_ITEM_TEST(pvl->query, tenGageTraceGradMag)) { magTmp = pvl->directAnswer[tenGageTraceGradMag][0] = AIR_CAST(gage_t, ELL_3V_LEN(vecTmp)); } if (GAGE_QUERY_ITEM_TEST(pvl->query, tenGageTraceNormal)) { ELL_3V_SCALE(pvl->directAnswer[tenGageTraceNormal], 1.0f/(epsilon + magTmp), vecTmp); } /* --- B --- */ if (GAGE_QUERY_ITEM_TEST(pvl->query, tenGageBGradVec)) { gradCbB = vecTmp = pvl->directAnswer[tenGageBGradVec]; ELL_3V_SCALE_ADD6(vecTmp, dtD + dtF, gradDtA, -2.0f*dtB, gradDtB, -2.0f*dtC, gradDtC, dtA + dtF, gradDtD, -2.0f*dtE, gradDtE, dtA + dtD, gradDtF); } if (GAGE_QUERY_ITEM_TEST(pvl->query, tenGageBGradMag)) { magTmp = pvl->directAnswer[tenGageBGradMag][0] = AIR_CAST(gage_t, ELL_3V_LEN(vecTmp)); } if (GAGE_QUERY_ITEM_TEST(pvl->query, tenGageBNormal)) { ELL_3V_SCALE(pvl->directAnswer[tenGageBNormal], 1.0f/(epsilon + magTmp), vecTmp); } /* --- Det --- */ if (GAGE_QUERY_ITEM_TEST(pvl->query, tenGageDetGradVec)) { vecTmp = pvl->directAnswer[tenGageDetGradVec]; ELL_3V_SCALE_ADD6(vecTmp, dtD*dtF - dtE*dtE, gradDtA, 2.0f*(dtC*dtE - dtB*dtF), gradDtB, 2.0f*(dtB*dtE - dtC*dtD), gradDtC, dtA*dtF - dtC*dtC, gradDtD, 2.0f*(dtB*dtC - dtA*dtE), gradDtE, dtA*dtD - dtB*dtB, gradDtF); ELL_3V_SCALE(gradCbC, -1, vecTmp); } if (GAGE_QUERY_ITEM_TEST(pvl->query, tenGageDetGradMag)) { magTmp = pvl->directAnswer[tenGageDetGradMag][0] = AIR_CAST(float, ELL_3V_LEN(vecTmp)); }
int _miteUserCheck(miteUser *muu) { char me[]="miteUserCheck", err[BIFF_STRLEN]; int T, gotOpac; gageItemSpec isp; gageQuery queryScl, queryVec, queryTen, queryMite; miteShadeSpec *shpec; airArray *mop; unsigned int axi; if (!muu) { sprintf(err, "%s: got NULL pointer", me); biffAdd(MITE, err); return 1; } mop = airMopNew(); if (!( muu->ntxfNum >= 1 )) { sprintf(err, "%s: need at least one transfer function", me); biffAdd(MITE, err); airMopError(mop); return 1; } gotOpac = AIR_FALSE; GAGE_QUERY_RESET(queryScl); GAGE_QUERY_RESET(queryVec); GAGE_QUERY_RESET(queryTen); GAGE_QUERY_RESET(queryMite); /* not actually used here */ /* add on all queries associated with transfer functions */ for (T=0; T<muu->ntxfNum; T++) { if (miteNtxfCheck(muu->ntxf[T])) { sprintf(err, "%s: ntxf[%d] (%d of %d) can't be used as a txf", me, T, T+1, muu->ntxfNum); biffAdd(MITE, err); airMopError(mop); return 1; } /* NOTE: no error checking because miteNtxfCheck succeeded */ for (axi=1; axi<muu->ntxf[T]->dim; axi++) { miteVariableParse(&isp, muu->ntxf[T]->axis[axi].label); miteQueryAdd(queryScl, queryVec, queryTen, queryMite, &isp); } gotOpac |= !!strchr(muu->ntxf[T]->axis[0].label, 'A'); } if (!gotOpac) { fprintf(stderr, "\n\n%s: ****************************************" "************************\n", me); fprintf(stderr, "%s: !!! WARNING !!! opacity (\"A\") not set " "by any transfer function\n", me); fprintf(stderr, "%s: ****************************************" "************************\n\n\n", me); } /* add on "normal"-based queries */ if (airStrlen(muu->normalStr)) { miteVariableParse(&isp, muu->normalStr); if (miteValGageKind == isp.kind) { sprintf(err, "%s: normalStr \"%s\" refers to a miteVal " "(normal must be data-intrinsic)", me, muu->normalStr); biffAdd(MITE, err); airMopError(mop); return 1; } if (3 != isp.kind->table[isp.item].answerLength) { sprintf(err, "%s: %s not a vector: can't be used as normal", me, muu->normalStr); biffAdd(MITE, err); return 1; } miteQueryAdd(queryScl, queryVec, queryTen, queryMite, &isp); } /* add on shading-based queries */ shpec = miteShadeSpecNew(); airMopAdd(mop, shpec, (airMopper)miteShadeSpecNix, airMopAlways); if (miteShadeSpecParse(shpec, muu->shadeStr)) { sprintf(err, "%s: couldn't parse shading spec \"%s\"", me, muu->shadeStr); biffAdd(MITE, err); airMopError(mop); return 1; } miteShadeSpecQueryAdd(queryScl, queryVec, queryTen, queryMite, shpec); /* see if anyone asked for an unspecified normal */ if ((GAGE_QUERY_ITEM_TEST(queryMite, miteValNdotV) || GAGE_QUERY_ITEM_TEST(queryMite, miteValNdotL) || GAGE_QUERY_ITEM_TEST(queryMite, miteValVrefN)) && !airStrlen(muu->normalStr)) { sprintf(err, "%s: txf or shading requested a miteVal's use of the " "\"normal\", but one has not been specified in muu->normalStr", me); biffAdd(MITE, err); airMopError(mop); return 1; } /* see if we have volumes for requested queries */ if (GAGE_QUERY_NONZERO(queryScl) && !(muu->nsin)) { sprintf(err, "%s: txf or shading require %s volume, but don't have one", me, gageKindScl->name); biffAdd(MITE, err); airMopError(mop); return 1; } if (GAGE_QUERY_NONZERO(queryVec) && !(muu->nvin)) { sprintf(err, "%s: txf or shading require %s volume, but don't have one", me, gageKindVec->name); biffAdd(MITE, err); airMopError(mop); return 1; } if (GAGE_QUERY_NONZERO(queryTen) && !(muu->ntin)) { sprintf(err, "%s: txf or shading require %s volume, but don't have one", me, tenGageKind->name); biffAdd(MITE, err); airMopError(mop); return 1; } /* check appropriateness of given volumes */ if (muu->nsin) { if (gageVolumeCheck(muu->gctx0, muu->nsin, gageKindScl)) { sprintf(err, "%s: trouble with input %s volume", me, gageKindScl->name); biffMove(MITE, err, GAGE); airMopError(mop); return 1; } } if (muu->nvin) { if (gageVolumeCheck(muu->gctx0, muu->nvin, gageKindVec)) { sprintf(err, "%s: trouble with input %s volume", me, gageKindVec->name); biffMove(MITE, err, GAGE); airMopError(mop); return 1; } } if (muu->ntin) { if (gageVolumeCheck(muu->gctx0, muu->ntin, tenGageKind)) { sprintf(err, "%s: trouble with input %s volume", me, tenGageKind->name); biffMove(MITE, err, GAGE); airMopError(mop); return 1; } } if (!muu->nout) { sprintf(err, "%s: rendered image nrrd is NULL", me); biffAdd(MITE, err); airMopError(mop); return 1; } airMopOkay(mop); return 0; }
void _tenDwiGageAnswer(gageContext *ctx, gagePerVolume *pvl) { char me[]="_tenDwiGageAnswer"; unsigned int dwiIdx; tenDwiGageKindData *kindData; tenDwiGagePvlData *pvlData; double *dwiAll, dwiMean=0, tentmp[7]; kindData = AIR_CAST(tenDwiGageKindData *, pvl->kind->data); pvlData = AIR_CAST(tenDwiGagePvlData *, pvl->data); dwiAll = pvl->directAnswer[tenDwiGageAll]; if (GAGE_QUERY_ITEM_TEST(pvl->query, tenDwiGageAll)) { /* done if doV */ if (ctx->verbose) { for (dwiIdx=0; dwiIdx<pvl->kind->valLen; dwiIdx++) { fprintf(stderr, "%s(%d+%g,%d+%g,%d+%g): dwi[%u] = %g\n", me, ctx->point.xi, ctx->point.xf, ctx->point.yi, ctx->point.yf, ctx->point.zi, ctx->point.zf, dwiIdx, dwiAll[dwiIdx]); } fprintf(stderr, "%s: type(ngrad) = %d = %s\n", me, kindData->ngrad->type, airEnumStr(nrrdType, kindData->ngrad->type)); } } /* if (GAGE_QUERY_ITEM_TEST(pvl->query, tenDwiGageB0)) { if (GAGE_QUERY_ITEM_TEST(pvl->query, tenDwiGageJustDWI)) { done if doV } */ /* HEY this isn't valid for multiple b-values */ if (GAGE_QUERY_ITEM_TEST(pvl->query, tenDwiGageADC)) { double logdwi, logb0; logb0 = log(AIR_MAX(kindData->valueMin, pvl->directAnswer[tenDwiGageB0][0])); for (dwiIdx=1; dwiIdx<pvl->kind->valLen; dwiIdx++) { logdwi = log(AIR_MAX(kindData->valueMin, pvl->directAnswer[tenDwiGageJustDWI][dwiIdx-1])); pvl->directAnswer[tenDwiGageADC][dwiIdx-1] = (logb0 - logdwi)/kindData->bval; } } if (GAGE_QUERY_ITEM_TEST(pvl->query, tenDwiGageMeanDWIValue)) { dwiMean = 0; for (dwiIdx=1; dwiIdx<pvl->kind->valLen; dwiIdx++) { dwiMean += dwiAll[dwiIdx]; } dwiMean /= pvl->kind->valLen; pvl->directAnswer[tenDwiGageMeanDWIValue][0] = dwiMean; } /* note: the gage interface to tenEstimate functionality allows you exactly one kind of tensor estimation (per kind), so the function call to do the estimation is actually repeated over and over again; the copy into the answer buffer is what changes... */ if (GAGE_QUERY_ITEM_TEST(pvl->query, tenDwiGageTensorLLS)) { tenEstimate1TensorSingle_d(pvlData->tec1, tentmp, dwiAll); TEN_T_COPY(pvl->directAnswer[tenDwiGageTensorLLS], tentmp); } if (GAGE_QUERY_ITEM_TEST(pvl->query, tenDwiGageTensorLLSError)) { pvl->directAnswer[tenDwiGageTensorLLSError][0] = pvlData->tec1->errorDwi; } if (GAGE_QUERY_ITEM_TEST(pvl->query, tenDwiGageTensorLLSErrorLog)) { pvl->directAnswer[tenDwiGageTensorLLSErrorLog][0] = pvlData->tec1->errorLogDwi; } if (GAGE_QUERY_ITEM_TEST(pvl->query, tenDwiGageTensorWLS)) { tenEstimate1TensorSingle_d(pvlData->tec1, tentmp, dwiAll); TEN_T_COPY(pvl->directAnswer[tenDwiGageTensorWLS], tentmp); } if (GAGE_QUERY_ITEM_TEST(pvl->query, tenDwiGageTensorNLS)) { tenEstimate1TensorSingle_d(pvlData->tec1, tentmp, dwiAll); TEN_T_COPY(pvl->directAnswer[tenDwiGageTensorNLS], tentmp); } if (GAGE_QUERY_ITEM_TEST(pvl->query, tenDwiGageTensorMLE)) { tenEstimate1TensorSingle_d(pvlData->tec1, tentmp, dwiAll); TEN_T_COPY(pvl->directAnswer[tenDwiGageTensorMLE], tentmp); } /* HEY: have to implement all the different kinds of errors */ /* BEGIN sneakiness ........ */ if (GAGE_QUERY_ITEM_TEST(pvl->query, tenDwiGageTensor)) { gageItemEntry *item; item = pvl->kind->table + tenDwiGageTensor; TEN_T_COPY(pvl->directAnswer[tenDwiGageTensor], pvl->directAnswer[item->prereq[0]]); } if (GAGE_QUERY_ITEM_TEST(pvl->query, tenDwiGageTensorError)) { gageItemEntry *item; item = pvl->kind->table + tenDwiGageTensorError; pvl->directAnswer[tenDwiGageTensorError][0] = pvl->directAnswer[item->prereq[0]][0]; } if (GAGE_QUERY_ITEM_TEST(pvl->query, tenDwiGageTensorErrorLog)) { gageItemEntry *item; item = pvl->kind->table + tenDwiGageTensorErrorLog; pvl->directAnswer[tenDwiGageTensorErrorLog][0] = pvl->directAnswer[item->prereq[0]][0]; } if (GAGE_QUERY_ITEM_TEST(pvl->query, tenDwiGageTensorLikelihood)) { gageItemEntry *item; item = pvl->kind->table + tenDwiGageTensorLikelihood; pvl->directAnswer[tenDwiGageTensorLikelihood][0] = pvl->directAnswer[item->prereq[0]][0]; } /* END sneakiness ........ */ if (GAGE_QUERY_ITEM_TEST(pvl->query, tenDwiGageFA)) { pvl->directAnswer[tenDwiGageFA][0] = pvl->directAnswer[tenDwiGageTensor][0] * tenAnisoTen_d(pvl->directAnswer[tenDwiGageTensor], tenAniso_FA); } if (GAGE_QUERY_ITEM_TEST(pvl->query, tenDwiGageTensorAllDWIError)) { const double *grads; int gradcount; double *ten, d; int i; /* HEY: should switch to tenEstimate-based DWI simulation */ ten = pvl->directAnswer[tenDwiGageTensor]; gradcount = pvl->kind->valLen -1; /* Dont count b0 */ grads = ((const double*) kindData->ngrad->data) +3; /* Ignore b0 grad */ for( i=0; i < gradcount; i++ ) { d = dwiAll[0]*exp(- pvlData->tec1->bValue * TEN_T3V_CONTR(ten, grads + 3*i)); pvl->directAnswer[tenDwiGageTensorAllDWIError][i] = dwiAll[i+1] - d; } } if (GAGE_QUERY_ITEM_TEST(pvl->query, tenDwiGage2TensorQSeg)) { const double *grads; int gradcount; double *twoten; unsigned int valIdx, E; twoten = pvl->directAnswer[tenDwiGage2TensorQSeg]; gradcount = pvl->kind->valLen -1; /* Dont count b0 */ grads = ((const double*) kindData->ngrad->data) +3; /* Ignore b0 grad */ if (dwiAll[0] != 0) { /* S0 = 0 */ _tenQball(pvlData->tec2->bValue, gradcount, dwiAll, grads, pvlData->qvals); _tenQvals2points(gradcount, pvlData->qvals, grads, pvlData->qpoints); _tenSegsamp2(gradcount, pvlData->qvals, grads, pvlData->qpoints, pvlData->wght + 1, pvlData->dists ); } else { /* stupid; should really return right here since data is garbage */ for (valIdx=1; valIdx < AIR_CAST(unsigned int, gradcount+1); valIdx++) { pvlData->wght[valIdx] = valIdx % 2; } } E = 0; for (valIdx=1; valIdx<pvl->kind->valLen; valIdx++) { if (!E) E |= tenEstimateSkipSet(pvlData->tec2, valIdx, pvlData->wght[valIdx]); } if (!E) E |= tenEstimateUpdate(pvlData->tec2); if (!E) E |= tenEstimate1TensorSingle_d(pvlData->tec2, twoten + 0, dwiAll); for (valIdx=1; valIdx<pvl->kind->valLen; valIdx++) { if (!E) E |= tenEstimateSkipSet(pvlData->tec2, valIdx, 1 - pvlData->wght[valIdx]); } if (!E) E |= tenEstimateUpdate(pvlData->tec2); if (!E) E |= tenEstimate1TensorSingle_d(pvlData->tec2, twoten + 7, dwiAll); if (E) { fprintf(stderr, "!%s: (trouble) %s\n", me, biffGetDone(TEN)); } /* hack: confidence for two-tensor fit */ twoten[0] = (twoten[0] + twoten[7])/2; twoten[7] = 0.5; /* fraction that is the first tensor (initial value) */ /* twoten[1 .. 6] = first tensor */ /* twoten[8 .. 13] = second tensor */ /* Compute fraction between tensors if not garbage in this voxel */ if (twoten[0] > 0.5) { double exp0,exp1,d,e=0,g=0, a=0,b=0; int i; for( i=0; i < gradcount; i++ ) { exp0 = exp(-pvlData->tec2->bValue * TEN_T3V_CONTR(twoten + 0, grads + 3*i)); exp1 = exp(-pvlData->tec2->bValue * TEN_T3V_CONTR(twoten + 7, grads + 3*i)); d = dwiAll[i+1] / dwiAll[0]; e = exp0 - exp1; g = d - exp1; a += .5*e*e; b += e*g; } twoten[7] = AIR_CLAMP(0, 0.5*(b/a), 1); } } if (GAGE_QUERY_ITEM_TEST(pvl->query, tenDwiGage2TensorQSegError)) { const double *grads; int gradcount; double *twoten, d; int i; /* HEY: should switch to tenEstimate-based DWI simulation */ if (dwiAll[0] != 0) { /* S0 = 0 */ twoten = pvl->directAnswer[tenDwiGage2TensorQSeg]; gradcount = pvl->kind->valLen -1; /* Dont count b0 */ grads = ((const double*) kindData->ngrad->data) +3; /* Ignore b0 grad */ pvl->directAnswer[tenDwiGage2TensorQSegError][0] = 0; for( i=0; i < gradcount; i++ ) { d = twoten[7]*exp(-pvlData->tec2->bValue * TEN_T3V_CONTR(twoten + 0, grads + 3*i)); d += (1 - twoten[7])*exp(-pvlData->tec2->bValue *TEN_T3V_CONTR(twoten + 7, grads + 3*i)); d = dwiAll[i+1]/dwiAll[0] - d; pvl->directAnswer[tenDwiGage2TensorQSegError][0] += d*d; } pvl->directAnswer[tenDwiGage2TensorQSegError][0] = sqrt( pvl->directAnswer[tenDwiGage2TensorQSegError][0] ); } else { /* HEY: COMPLETELY WRONG!! An error is not defined! */ pvl->directAnswer[tenDwiGage2TensorQSegError][0] = 0; } /* printf("%f\n",pvl->directAnswer[tenDwiGage2TensorQSegError][0]); */ } if (GAGE_QUERY_ITEM_TEST(pvl->query, tenDwiGage2TensorQSegAndError)) { double *twoten, *err, *twotenerr; twoten = pvl->directAnswer[tenDwiGage2TensorQSeg]; err = pvl->directAnswer[tenDwiGage2TensorQSegError]; twotenerr = pvl->directAnswer[tenDwiGage2TensorQSegAndError]; TEN_T_COPY(twotenerr + 0, twoten + 0); TEN_T_COPY(twotenerr + 7, twoten + 7); twotenerr[14] = err[0]; } if (GAGE_QUERY_ITEM_TEST(pvl->query, tenDwiGage2TensorPeled)) { #if TEEM_LEVMAR #define PARAMS 4 double *twoTen, Cp /* , residual, AICSingFit, AICTwoFit */; /* Vars for the NLLS */ double guess[PARAMS], loBnd[PARAMS], upBnd[PARAMS], opts[LM_OPTS_SZ], *grad, *egrad, tenA[7], tenB[7], matA[9], matB[9], matTmp[9], rott[9]; unsigned int gi; int lmret; /* Pointer to the location where the two tensor will be written */ twoTen = pvl->directAnswer[tenDwiGage2TensorPeled]; /* Estimate the DWI error, error is given as standard deviation */ pvlData->tec2->recordErrorDwi = AIR_FALSE; /* Estimate the single tensor */ tenEstimate1TensorSingle_d(pvlData->tec2, pvlData->ten1, dwiAll); /* Get the eigenValues and eigen vectors for this tensor */ tenEigensolve_d(pvlData->ten1Eval, pvlData->ten1Evec, pvlData->ten1); /* Get westins Cp */ Cp = tenAnisoEval_d(pvlData->ten1Eval, tenAniso_Cp1); /* Calculate the residual, need the variance to sqr it */ /* residual = pvlData->tec2->errorDwi*pvlData->tec2->errorDwi; */ /* Calculate the AIC for single tensor fit */ /* AICSingFit = _tenComputeAIC(residual, pvlData->tec2->dwiNum, 6); */ /* the CP-based test is gone; caller's responsibility */ /* rotate DW gradients by inverse of eigenvector column matrix and place into pvlData->nten1EigenGrads (which has been allocated by _tenDwiGagePvlDataNew()) */ grad = AIR_CAST(double *, kindData->ngrad->data); egrad = AIR_CAST(double *, pvlData->nten1EigenGrads->data); for (gi=0; gi<kindData->ngrad->axis[1].size; gi++) { /* yes, this is also transforming some zero-length (B0) gradients; that's harmless */ ELL_3MV_MUL(egrad, pvlData->ten1Evec, grad); grad += 3; egrad += 3; } /* Lower and upper bounds for the NLLS routine */ loBnd[0] = 0.0; loBnd[1] = 0.0; loBnd[2] = -AIR_PI/2; loBnd[3] = -AIR_PI/2; upBnd[0] = pvlData->ten1Eval[0]*5; upBnd[1] = 1.0; upBnd[2] = AIR_PI/2; upBnd[3] = AIR_PI/2; /* Starting point for the NLLS */ guess[0] = pvlData->ten1Eval[0]; guess[1] = 0.5; guess[2] = AIR_PI/4; guess[3] = -AIR_PI/4; /* guess[2] = AIR_AFFINE(0, airDrandMT_r(pvlData->randState), 1, AIR_PI/6, AIR_PI/3); guess[3] = AIR_AFFINE(0, airDrandMT_r(pvlData->randState), 1, -AIR_PI/6, -AIR_PI/3); */ /* Fill in the constraints for the LM optimization, the threshold of error difference */ opts[0] = pvlData->levmarTau; opts[1] = pvlData->levmarEps1; opts[2] = pvlData->levmarEps2; opts[3] = pvlData->levmarEps3; /* Very imp to set this opt, note that only forward differences are used to approx Jacobian */ opts[4] = pvlData->levmarDelta; /* run NLLS, results are stored back into guess[] */ pvlData->levmarUseFastExp = AIR_FALSE; lmret = dlevmar_bc_dif(_tenLevmarPeledCB, guess, pvlData->tec2->dwi, PARAMS, pvlData->tec2->dwiNum, loBnd, upBnd, pvlData->levmarMaxIter, opts, pvlData->levmarInfo, NULL, NULL, pvlData); if (-1 == lmret) { ctx->errNum = 1; sprintf(ctx->errStr, "%s: dlevmar_bc_dif() failed!", me); } else { /* Get the AIC for the two tensor fit, use the levmarinfo to get the residual */ /* residual = pvlData->levmarInfo[1]/pvlData->tec2->dwiNum; AICTwoFit = _tenComputeAIC(residual, pvlData->tec2->dwiNum, 12); */ /* Form the tensors using the estimated pp, returned in guess */ _tenPeledRotate2D(tenA, guess[0], pvlData->ten1Eval[2], guess[2]); _tenPeledRotate2D(tenB, guess[0], pvlData->ten1Eval[2], guess[3]); TEN_T2M(matA, tenA); TEN_T2M(matB, tenB); ELL_3M_TRANSPOSE(rott, pvlData->ten1Evec); ELL_3M_MUL(matTmp, matA, pvlData->ten1Evec); ELL_3M_MUL(matA, rott, matTmp); ELL_3M_MUL(matTmp, matB, pvlData->ten1Evec); ELL_3M_MUL(matB, rott, matTmp); /* Copy two two tensors */ /* guess[1] is population fraction of first tensor */ if (guess[1] > 0.5) { twoTen[7] = guess[1]; TEN_M2T(twoTen + 0, matA); TEN_M2T(twoTen + 7, matB); } else { twoTen[7] = 1 - guess[1]; TEN_M2T(twoTen + 0, matB); TEN_M2T(twoTen + 7, matA); } twoTen[0] = 1; } #undef PARAMS #else double *twoTen; twoTen = pvl->directAnswer[tenDwiGage2TensorPeled]; TEN_T_SET(twoTen + 0, AIR_NAN, AIR_NAN, AIR_NAN, AIR_NAN, AIR_NAN, AIR_NAN, AIR_NAN); TEN_T_SET(twoTen + 7, AIR_NAN, AIR_NAN, AIR_NAN, AIR_NAN, AIR_NAN, AIR_NAN, AIR_NAN); fprintf(stderr, "%s: sorry, not compiled with TEEM_LEVMAR\n", me); #endif }