Пример #1
0
/*
******** 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;
}
Пример #2
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;
}
Пример #3
0
/*
** 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);
  }
Пример #5
0
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);
}
Пример #6
0
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;
}
Пример #7
0
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;
}
Пример #8
0
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;
}
Пример #9
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));
  }
Пример #10
0
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;
}
Пример #11
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
  }