void omxCallGREMLFitFunction(omxFitFunction *oo, int want, FitContext *fc){ if (want & (FF_COMPUTE_PREOPTIMIZE)) return; //Recompute Expectation: omxExpectation* expectation = oo->expectation; omxExpectationCompute(expectation, NULL); omxGREMLFitState *gff = (omxGREMLFitState*)oo->argStruct; //<--Cast generic omxFitFunction to omxGREMLFitState //Ensure that the pointer in the GREML fitfunction is directed at the right FreeVarGroup //(not necessary for most compute plans): if(fc && gff->varGroup != fc->varGroup){ gff->buildParamMap(fc->varGroup); } //Declare local variables used in more than one scope in this function: const double Scale = fabs(Global->llScale); //<--absolute value of loglikelihood scale const double NATLOG_2PI = 1.837877066409345483560659472811; //<--log(2*pi) int i; Eigen::Map< Eigen::MatrixXd > Eigy(omxMatrixDataColumnMajor(gff->y), gff->y->cols, 1); Eigen::Map< Eigen::MatrixXd > Vinv(omxMatrixDataColumnMajor(gff->invcov), gff->invcov->rows, gff->invcov->cols); EigenMatrixAdaptor EigX(gff->X); Eigen::MatrixXd P, Py; P.setZero(gff->invcov->rows, gff->invcov->cols); double logdetV=0, logdetquadX=0; if(want & (FF_COMPUTE_FIT | FF_COMPUTE_GRADIENT | FF_COMPUTE_HESSIAN | FF_COMPUTE_IHESSIAN)){ if(gff->usingGREMLExpectation){ omxGREMLExpectation* oge = (omxGREMLExpectation*)(expectation->argStruct); //Check that factorizations of V and the quadratic form in X succeeded: if(oge->cholV_fail_om->data[0]){ oo->matrix->data[0] = NA_REAL; if (fc) fc->recordIterationError("expected covariance matrix is non-positive-definite"); return; } if(oge->cholquadX_fail){ oo->matrix->data[0] = NA_REAL; if (fc) fc->recordIterationError("Cholesky factorization failed; possibly, the matrix of covariates is rank-deficient"); return; } //Log determinant of V: logdetV = oge->logdetV_om->data[0]; //Log determinant of quadX: for(i=0; i < gff->X->cols; i++){ logdetquadX += log(oge->cholquadX_vectorD[i]); } logdetquadX *= 2; gff->REMLcorrection = Scale*0.5*logdetquadX; //Finish computing fit (negative loglikelihood): P.triangularView<Eigen::Lower>() = Vinv.selfadjointView<Eigen::Lower>() * (Eigen::MatrixXd::Identity(Vinv.rows(), Vinv.cols()) - (EigX * oge->quadXinv.selfadjointView<Eigen::Lower>() * oge->XtVinv)); //Vinv * (I-Hatmat) Py = P.selfadjointView<Eigen::Lower>() * Eigy; oo->matrix->data[0] = gff->REMLcorrection + Scale*0.5*( (((double)gff->y->cols) * NATLOG_2PI) + logdetV + ( Eigy.transpose() * Py )(0,0)); gff->nll = oo->matrix->data[0]; } else{ //If not using GREML expectation, deal with means and cov in a general way to compute fit... //Declare locals: EigenMatrixAdaptor yhat(gff->means); EigenMatrixAdaptor EigV(gff->cov); double logdetV=0, logdetquadX=0; Eigen::MatrixXd Vinv, quadX; Eigen::LLT< Eigen::MatrixXd > cholV(gff->cov->rows); Eigen::LLT< Eigen::MatrixXd > cholquadX(gff->X->cols); Eigen::VectorXd cholV_vectorD, cholquadX_vectorD; //Cholesky factorization of V: cholV.compute(EigV); if(cholV.info() != Eigen::Success){ omxRaiseErrorf("expected covariance matrix is non-positive-definite"); oo->matrix->data[0] = NA_REAL; return; } //Log determinant of V: cholV_vectorD = (( Eigen::MatrixXd )(cholV.matrixL())).diagonal(); for(i=0; i < gff->X->rows; i++){ logdetV += log(cholV_vectorD[i]); } logdetV *= 2; Vinv = cholV.solve(Eigen::MatrixXd::Identity( EigV.rows(), EigV.cols() )); //<-- V inverse quadX = EigX.transpose() * Vinv * EigX; //<--Quadratic form in X cholquadX.compute(quadX); //<--Cholesky factorization of quadX if(cholquadX.info() != Eigen::Success){ omxRaiseErrorf("Cholesky factorization failed; possibly, the matrix of covariates is rank-deficient"); oo->matrix->data[0] = NA_REAL; return; } cholquadX_vectorD = (( Eigen::MatrixXd )(cholquadX.matrixL())).diagonal(); for(i=0; i < gff->X->cols; i++){ logdetquadX += log(cholquadX_vectorD[i]); } logdetquadX *= 2; gff->REMLcorrection = Scale*0.5*logdetquadX; //Finish computing fit: oo->matrix->data[0] = gff->REMLcorrection + Scale*0.5*( ((double)gff->y->rows * NATLOG_2PI) + logdetV + ( Eigy.transpose() * Vinv * (Eigy - yhat) )(0,0)); gff->nll = oo->matrix->data[0]; return; } } if(want & (FF_COMPUTE_GRADIENT | FF_COMPUTE_HESSIAN | FF_COMPUTE_IHESSIAN)){ //This part requires GREML expectation: omxGREMLExpectation* oge = (omxGREMLExpectation*)(expectation->argStruct); //Declare local variables for this scope: int numChildren = fc->childList.size(); int __attribute__((unused)) parallelism = (numChildren == 0) ? 1 : numChildren; fc->grad.resize(gff->dVlength); //<--Resize gradient in FitContext //Set up new HessianBlock: HessianBlock *hb = new HessianBlock; if(want & (FF_COMPUTE_HESSIAN | FF_COMPUTE_IHESSIAN)){ hb->vars.resize(gff->dVlength); hb->mat.resize(gff->dVlength, gff->dVlength); } //Begin looping thru free parameters: #pragma omp parallel for num_threads(parallelism) for(i=0; i < gff->dVlength; i++){ //Declare locals within parallelized region: int j=0, t1=0, t2=0; Eigen::MatrixXd PdV_dtheta1; Eigen::MatrixXd dV_dtheta1(Eigy.rows(), Eigy.rows()); //<--Derivative of V w/r/t parameter i. Eigen::MatrixXd dV_dtheta2(Eigy.rows(), Eigy.rows()); //<--Derivative of V w/r/t parameter j. t1 = gff->gradMap[i]; //<--Parameter number for parameter i. if(t1 < 0){continue;} if(want & (FF_COMPUTE_HESSIAN | FF_COMPUTE_IHESSIAN)){hb->vars[i] = t1;} if( oge->numcases2drop ){ dropCasesAndEigenize(gff->dV[i], dV_dtheta1, oge->numcases2drop, oge->dropcase, 1); } else{dV_dtheta1 = Eigen::Map< Eigen::MatrixXd >(omxMatrixDataColumnMajor(gff->dV[i]), gff->dV[i]->rows, gff->dV[i]->cols);} //PdV_dtheta1 = P.selfadjointView<Eigen::Lower>() * dV_dtheta1.selfadjointView<Eigen::Lower>(); PdV_dtheta1 = P.selfadjointView<Eigen::Lower>(); PdV_dtheta1 = PdV_dtheta1 * dV_dtheta1.selfadjointView<Eigen::Lower>(); for(j=i; j < gff->dVlength; j++){ if(j==i){ gff->gradient(t1) = Scale*0.5*(PdV_dtheta1.trace() - (Eigy.transpose() * PdV_dtheta1 * Py)(0,0)); fc->grad(t1) += gff->gradient(t1); if(want & (FF_COMPUTE_HESSIAN | FF_COMPUTE_IHESSIAN)){ gff->avgInfo(t1,t1) = Scale*0.5*(Eigy.transpose() * PdV_dtheta1 * PdV_dtheta1 * Py)(0,0); } } else{if(want & (FF_COMPUTE_HESSIAN | FF_COMPUTE_IHESSIAN)){ t2 = gff->gradMap[j]; //<--Parameter number for parameter j. if(t2 < 0){continue;} if( oge->numcases2drop ){ dropCasesAndEigenize(gff->dV[j], dV_dtheta2, oge->numcases2drop, oge->dropcase, 1); } else{dV_dtheta2 = Eigen::Map< Eigen::MatrixXd >(omxMatrixDataColumnMajor(gff->dV[j]), gff->dV[j]->rows, gff->dV[j]->cols);} gff->avgInfo(t1,t2) = Scale*0.5*(Eigy.transpose() * PdV_dtheta1 * P.selfadjointView<Eigen::Lower>() * dV_dtheta2.selfadjointView<Eigen::Lower>() * Py)(0,0); gff->avgInfo(t2,t1) = gff->avgInfo(t1,t2); }}}} //Assign upper triangle elements of avgInfo to the HessianBlock: if(want & (FF_COMPUTE_HESSIAN | FF_COMPUTE_IHESSIAN)){ for (size_t d1=0, h1=0; h1 < gff->dV.size(); ++h1) { for (size_t d2=0, h2=0; h2 <= h1; ++h2) { hb->mat(d2,d1) = gff->avgInfo(h2,h1); ++d2; } ++d1; } fc->queue(hb); }}
/* main routine */ int main(int argc, char *argv[]){ FILELog::ReportingLevel() = logINFO; VARIABLES vars; vars = commandline_input(argc, argv); clock_t init, final; int number_of_particles = vars.num; double timestep = vars.dt; bool use_T2 = vars.use_T2; // = false (no T2 decay), = true (T2 decay) int num_of_repeat = vars.num_of_repeat; //Number of times to repeat simulation. For every repeat all data is flushed and we start the simulation again. int number_of_timesteps; number_of_timesteps = (int)ceil(vars.gs/timestep); double permeability = 0.0; double radius = .00535; double d = sqrt( 2.0*PI*radius*radius/( sqrt(3.0)*.79 ) ); //double lattice_size = 0.00601922026995422789215053328651; double grad_duration = 4.5; double D_extra = 2.5E-6; double D_intra = 1.0E-6; double T2_e = 200; double T2_i = 200; FILE_LOG(logINFO) << "f = " << 2.0*PI*radius*radius/(sqrt(3.0)*d*d) << std::endl; Vector3 xhat(1.0,0.0,0.0); Vector3 yhat(0.0,1.0,0.0); Vector3 zhat(0.0,0.0,1.0); Lattice<Cylinder_XY> lattice(D_extra, T2_e, permeability); lattice.setLatticeVectors(d,2.0*d*0.86602540378443864676372317075294,d,xhat,yhat,zhat); lattice.addBasis(Cylinder_XY(d/2.0, 0.0, radius, T2_i, D_intra, 1)); lattice.addBasis(Cylinder_XY(0.0, d*0.86602540378443864676372317075294, radius, T2_i, D_intra, 2)); lattice.addBasis(Cylinder_XY(d/2.0, 2.0*d*0.86602540378443864676372317075294, radius, T2_i, D_intra, 3)); lattice.addBasis(Cylinder_XY(d, d*0.86602540378443864676372317075294, radius, T2_i, D_intra, 4)); double gspacings [] = { 8.0 , 10.5 , 14.0 , 18.5 , 24.5 , 32.5 , 42.5 , 56.5 }; double bvals [] = {108780, 154720, 219040, 301730, 411980, 558990, 742420, 1000000 }; double G [9]; for (int kk = 0; kk < num_of_repeat; kk++) { vector<PGSE> measurements_x; vector<PGSE> measurements_y; vector<PGSE> measurements_z; for (int i = 0; i < 8; i++){ double echo_time = 2.0*grad_duration + gspacings[i]; G[0] = 0.0; G[i+1] = sqrt(bvals[i]/(GAMMA*GAMMA*grad_duration*grad_duration*(grad_duration + gspacings[i] - (grad_duration/3.0)))); measurements_x.push_back(PGSE(grad_duration,gspacings[i], timestep, G[0], echo_time, number_of_particles, xhat)); measurements_y.push_back(PGSE(grad_duration,gspacings[i], timestep, G[0], echo_time, number_of_particles, yhat)); measurements_z.push_back(PGSE(grad_duration,gspacings[i], timestep, G[0], echo_time, number_of_particles, zhat)); measurements_x.push_back(PGSE(grad_duration,gspacings[i], timestep, G[i+1], echo_time, number_of_particles, xhat)); measurements_y.push_back(PGSE(grad_duration,gspacings[i], timestep, G[i+1], echo_time, number_of_particles, yhat)); measurements_z.push_back(PGSE(grad_duration,gspacings[i], timestep, G[i+1], echo_time, number_of_particles, zhat)); } vector<double> lnsignal(2); vector<double> b(2); cout << " trial = " << kk << endl; Particles ensemble(number_of_particles,timestep, use_T2); lattice.initializeUniformly(ensemble.getGenerator() , ensemble.getEnsemble() ); for (int k = 0; k < measurements_x.size();k++){ measurements_x[k].updatePhase(ensemble.getEnsemble(), 0.0); measurements_y[k].updatePhase(ensemble.getEnsemble(), 0.0); measurements_z[k].updatePhase(ensemble.getEnsemble(), 0.0); } for (int i = 1; i <= number_of_timesteps; i++){ ensemble.updateposition(lattice); for (int k = 0; k < measurements_x.size();k++){ measurements_x[k].updatePhase(ensemble.getEnsemble(), i*timestep); measurements_y[k].updatePhase(ensemble.getEnsemble(), i*timestep); measurements_z[k].updatePhase(ensemble.getEnsemble(), i*timestep); } } for (int i = 0; i < 8*2; i+=2){ double ADCx, ADCy, ADCz, diff_time; lnsignal[0] = log(measurements_x[i].get_signal()); b[0] = measurements_x[i].get_b(); lnsignal[1] = log(measurements_x[i+1].get_signal()); b[1] = measurements_x[i+1].get_b(); ADCx = -1.0*linear_regression(lnsignal,b); //std::cout << b[0] << " " << lnsignal[0] << " " << b[1] << " " << lnsignal[1] << " "; lnsignal[0] = log(measurements_y[i].get_signal()); b[0] = measurements_y[i].get_b(); lnsignal[1] = log(measurements_y[i+1].get_signal()); b[1] = measurements_y[i+1].get_b(); ADCy = -1.0*linear_regression(lnsignal,b); //std::cout << b[0] << " " << lnsignal[0] << " " << b[1] << " " << lnsignal[1] << " "; lnsignal[0] = log(measurements_z[i].get_signal()); b[0] = measurements_z[i].get_b(); lnsignal[1] = log(measurements_z[i+1].get_signal()); b[1] = measurements_z[i+1].get_b(); ADCz = -1.0*linear_regression(lnsignal,b); //std::cout << b[0] << " " << lnsignal[0] << " " << b[1] << " " << lnsignal[1] << std::endl; diff_time = measurements_x[i].get_DT(); std::cout << i << " " << diff_time << " " << ADCx << " " << ADCy << " " << ADCz << " " << b[1] << " " << G[1] << std::endl; } } final= clock()-init; //final time - intial time