_TEN_PARM_ALLOC _TEN_PARM_RAND _TEN_PARM_STEP _TEN_PARM_DIST _TEN_PARM_COPY static int parmConvert(double *parmDst, const double *parmSrc, const tenModel *modelSrc) { int ret; if (modelSrc == tenModelBall) { TEN_T_SET(parmDst, parmSrc[0], parmSrc[1], 0, 0, parmSrc[1], 0, parmSrc[1]); ret = 0; } else if (modelSrc == tenModel1Stick) { double ten[7]; TEN_T3V_OUTER(ten, parmSrc + 2); TEN_T_SCALE(parmDst, parmSrc[1], ten); parmDst[0] = parmSrc[0]; ret = 0; } else if (modelSrc == tenModelBall1Stick) { double stick[7], ball[7], diff, frac; diff = parmSrc[1]; frac = parmSrc[2]; TEN_T3V_OUTER(stick, parmSrc + 3); TEN_T_SCALE(stick, diff, stick); TEN_T_SET(ball, 1, diff, 0, 0, diff, 0, diff); TEN_T_LERP(parmDst, frac, ball, stick); parmDst[0] = parmSrc[0]; ret = 1; } else if (modelSrc == tenModel1Cylinder) { double stick[7], ball[7], len, rad; len = parmSrc[1]; rad = parmSrc[2]; TEN_T3V_OUTER(stick, parmSrc + 3); TEN_T_SCALE(stick, len-rad, stick); TEN_T_SET(ball, 1, rad, 0, 0, rad, 0, rad); TEN_T_ADD(parmDst, ball, stick); parmDst[0] = parmSrc[0]; ret = 0; } else if (modelSrc == tenModel1Tensor2) { parmCopy(parmDst, parmSrc); ret = 0; } else { unsigned int ii; for (ii=0; ii<PARM_NUM; ii++) { parmDst[ii] = AIR_NAN; } ret = 2; } return ret; }
/* Form a 2D tensor from the parameters */ void _tenPeledRotate2D(double ten[7], double lam1, double lam3, double phi) { double cc, ss, d3, d1, d2; cc = cos(phi); ss = sin(phi); d1 = cc*cc*lam1 + ss*ss*lam3; d3 = cc*ss*(lam1 - lam3); d2 = ss*ss*lam1 + cc*cc*lam3; TEN_T_SET(ten, 1.0, d1, d3, 0, d2, 0, lam3); return; }
/* ** the reason to take the pushContext *pctx argument is to allow ** doling out the ttaagg ID */ pushPoint * pushPointNew(pushContext *pctx) { pushPoint *pnt; if (pctx) { pnt = AIR_CAST(pushPoint *, calloc(1, sizeof(pushPoint))); if (pnt) { pnt->ttaagg = pctx->ttaagg++; ELL_3V_SET(pnt->pos, AIR_NAN, AIR_NAN, AIR_NAN); ELL_3V_SET(pnt->frc, AIR_NAN, AIR_NAN, AIR_NAN); TEN_T_SET(pnt->ten, AIR_NAN, AIR_NAN, AIR_NAN, AIR_NAN, AIR_NAN, AIR_NAN, AIR_NAN); TEN_T_SET(pnt->inv, AIR_NAN, AIR_NAN, AIR_NAN, AIR_NAN, AIR_NAN, AIR_NAN, AIR_NAN); ELL_3V_SET(pnt->cnt, AIR_NAN, AIR_NAN, AIR_NAN); pnt->grav = AIR_NAN; ELL_3V_SET(pnt->gravGrad, AIR_NAN, AIR_NAN, AIR_NAN); pnt->seedThresh = AIR_NAN; pnt->enr = DBL_MAX; /* any finite quantity will be less than this */ pnt->neighArr = airArrayNew((void**)&(pnt->neigh), &(pnt->neighNum), sizeof(pushPoint *), 10); } } else {
int tend_estimThresholdFind(double *threshP, Nrrd *nbmat, Nrrd *nin4d) { char me[]="tend_estimThresholdFind", err[BIFF_STRLEN]; Nrrd **ndwi; airArray *mop; unsigned int slIdx, slNum, dwiAx, dwiNum, rangeAxisNum, rangeAxisIdx[NRRD_DIM_MAX]; double *bmat, bten[7], bnorm; int dwiIdx; mop = airMopNew(); if (!(threshP && nbmat && nin4d)) { sprintf(err, "%s: got NULL pointer", me); biffAdd(TEN, err); airMopError(mop); return 1; } if (tenBMatrixCheck(nbmat, nrrdTypeDouble, 6)) { sprintf(err, "%s: problem within given b-matrix", me); biffAdd(TEN, err); airMopError(mop); return 1; } /* HEY: copied from tenEpiRegister4D() */ rangeAxisNum = nrrdRangeAxesGet(nin4d, rangeAxisIdx); if (0 == rangeAxisNum) { /* we fall back on old behavior */ dwiAx = 0; } else if (1 == rangeAxisNum) { /* thankfully there's exactly one range axis */ dwiAx = rangeAxisIdx[0]; } else { sprintf(err, "%s: have %u range axes instead of 1, don't know which " "is DWI axis", me, rangeAxisNum); biffAdd(TEN, err); airMopError(mop); return 1; } slNum = nin4d->axis[dwiAx].size; bmat = AIR_CAST(double *, nbmat->data); dwiNum = 0; for (slIdx=0; slIdx<slNum; slIdx++) { TEN_T_SET(bten, 1.0, bmat[0], bmat[1], bmat[2], bmat[3], bmat[4], bmat[5]); bnorm = TEN_T_NORM(bten); dwiNum += bnorm > 0.0; bmat += 6; } if (0 == dwiNum) { sprintf(err, "%s: somehow got zero DWIs", me); biffAdd(TEN, err); airMopError(mop); return 1; } ndwi = AIR_CAST(Nrrd **, calloc(dwiNum, sizeof(Nrrd *))); airMopAdd(mop, ndwi, (airMopper)airFree, airMopAlways); bmat = AIR_CAST(double *, nbmat->data); dwiIdx = -1; for (slIdx=0; slIdx<slNum; slIdx++) { TEN_T_SET(bten, 1.0, bmat[0], bmat[1], bmat[2], bmat[3], bmat[4], bmat[5]); bnorm = TEN_T_NORM(bten); if (bnorm > 0.0) { dwiIdx++; ndwi[dwiIdx] = nrrdNew(); airMopAdd(mop, ndwi[dwiIdx], (airMopper)nrrdNuke, airMopAlways); if (nrrdSlice(ndwi[dwiIdx], nin4d, dwiAx, slIdx)) { sprintf(err, "%s: trouble slicing DWI at index %u", me, slIdx); biffMove(TEN, err, NRRD); airMopError(mop); return 1; } } bmat += 6; } if (_tenEpiRegThresholdFind(threshP, ndwi, dwiNum, AIR_FALSE, 1.5)) { sprintf(err, "%s: trouble finding thresh", me); biffAdd(TEN, err); airMopError(mop); return 1; } airMopOkay(mop); return 0; }
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)); }
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 }
static int csimDo(double tm[7], double tcov[21], double rm[3], double rv[3], Nrrd *ntbuff, tenEstimateContext *tec, double *dwibuff, double sigma, double bvalue, double B0, unsigned int NN, int randrot, double _tenOrig[7]) { char me[]="csimDo", err[BIFF_STRLEN]; double *tbuff; unsigned int II, taa, tbb, cc; if (!(ntbuff && ntbuff->data && 2 == ntbuff->dim && 7 == ntbuff->axis[0].size && NN == ntbuff->axis[1].size)) { sprintf(err, "%s: ntbuff not allocated for 2-by-%u array of %s", me, NN, airEnumStr(nrrdType, nrrdTypeDouble)); biffAdd(TEN, err); return 1; } /* find all tensors from simulated DWIs */ tbuff = AIR_CAST(double *, ntbuff->data); for (II=0; II<NN; II++) { double tenOrig[7], rotf[9], rotb[9], matA[9], matB[9], qq[4], tmp; ELL_3M_IDENTITY_SET(rotf); /* sssh warnings */ ELL_3M_IDENTITY_SET(rotb); /* sssh warnings */ if (randrot) { if (1) { double eval[3], evec[9], eps, ma[9], mb[9], rf[9], rb[9]; tenEigensolve_d(eval, evec, _tenOrig); airNormalRand(&eps, NULL); ell_aa_to_3m_d(rf, 0*eps/20, evec + 0); TEN_T_SCALE_INCR(_tenOrig, 0*eps/30, _tenOrig); TEN_T2M(ma, _tenOrig); ELL_3M_TRANSPOSE(rb, rf); ELL_3M_MUL(mb, ma, rf); ELL_3M_MUL(ma, rb, mb); TEN_M2T(_tenOrig, ma); } TEN_T2M(matA, _tenOrig); airNormalRand(qq+0, qq+1); airNormalRand(qq+2, qq+3); ELL_4V_NORM(qq, qq, tmp); ell_q_to_3m_d(rotf, qq); ELL_3M_TRANSPOSE(rotb, rotf); ELL_3M_MUL(matB, matA, rotf); ELL_3M_MUL(matA, rotb, matB); TEN_M2T(tenOrig, matA); } else { TEN_T_COPY(tenOrig, _tenOrig); } if (tenEstimate1TensorSimulateSingle_d(tec, dwibuff, sigma, bvalue, B0, tenOrig) || tenEstimate1TensorSingle_d(tec, tbuff, dwibuff)) { sprintf(err, "%s: trouble on exp %u/%u", me, II, NN); biffAdd(TEN, err); return 1; } if (randrot) { TEN_T2M(matA, tbuff); ELL_3M_MUL(matB, matA, rotb); ELL_3M_MUL(matA, rotf, matB); TEN_M2T(tbuff, matA); } /* else we leave tbuff as it is */ /* if (_tenOrig[0] > 0.5) { double tdiff[7]; TEN_T_SUB(tdiff, _tenOrig, tbuff); fprintf(stderr, "!%s: %g\n" " (%g) %g,%g,%g %g,%g %g\n" " (%g) %g,%g,%g %g,%g %g\n", me, TEN_T_NORM(tdiff), _tenOrig[0], _tenOrig[1], _tenOrig[2], _tenOrig[3], _tenOrig[4], _tenOrig[5], _tenOrig[6], tbuff[0], tbuff[1], tbuff[2], tbuff[3], tbuff[4], tbuff[5], tbuff[6]); } */ tbuff += 7; } /* find mean tensor, and mean R_i */ tbuff = AIR_CAST(double *, ntbuff->data); TEN_T_SET(tm, 0, 0, 0, 0, 0, 0, 0); ELL_3V_SET(rm, 0, 0, 0); for (II=0; II<NN; II++) { TEN_T_INCR(tm, tbuff); rm[0] += sqrt(_tenAnisoTen_d[tenAniso_S](tbuff)); rm[1] += _tenAnisoTen_d[tenAniso_FA](tbuff); rm[2] += _tenAnisoTen_d[tenAniso_Mode](tbuff); tbuff += 7; } rm[0] /= NN; rm[1] /= NN; rm[2] /= NN; TEN_T_SCALE(tm, 1.0/NN, tm); /* accumulate covariance tensor, and R_i variances */ for (cc=0; cc<21; cc++) { tcov[cc] = 0; } ELL_3V_SET(rv, 0, 0, 0); tbuff = AIR_CAST(double *, ntbuff->data); for (II=0; II<NN; II++) { double r[3]; r[0] = sqrt(_tenAnisoTen_d[tenAniso_S](tbuff)); r[1] = _tenAnisoTen_d[tenAniso_FA](tbuff); r[2] = _tenAnisoTen_d[tenAniso_Mode](tbuff); cc = 0; rv[0] += (r[0] - rm[0])*(r[0] - rm[0])/(NN-1); rv[1] += (r[1] - rm[1])*(r[1] - rm[1])/(NN-1); rv[2] += (r[2] - rm[2])*(r[2] - rm[2])/(NN-1); for (taa=0; taa<6; taa++) { for (tbb=taa; tbb<6; tbb++) { tcov[cc] += (10000*(tbuff[taa+1]-tm[taa+1]) *10000*(tbuff[tbb+1]-tm[tbb+1])/(NN-1)); cc++; } } tbuff += 7; } return 0; }