static PyObject* bloch(PyObject *self, PyObject *args){ //Arguement declarations double t1, t2; int nf, mode, n_pos; PyObject *py_b1_real, *py_b1_imag, *py_grx, *py_gry, *py_grz, *py_tp, *py_df, *py_dx, *py_dy, *py_dz; PyObject *py_mx, *py_my, *py_mz; //Bloch sim arugments declarations PyObject *b1_real_arr, *b1_imag_arr, *grx_arr, *gry_arr, *grz_arr, *tp_arr, *df_arr, *dx_arr, *dy_arr, *dz_arr, *mx_arr, *my_arr, *mz_arr; int ntime; double *b1_real, *b1_imag, *grx, *gry, *grz, *tp, *df, *dx, *dy, *dz, *mx, *my, *mz; if (!PyArg_ParseTuple(args, "OOOOOOiddOiOOOiiOOO", &py_b1_real, &py_b1_imag, &py_grx, &py_gry, &py_grz, &py_tp, &ntime, &t1, &t2, &py_df, &nf, &py_dx, &py_dy, &py_dz, &n_pos, &mode, &py_mx, &py_my, &py_mz)){ return NULL; } b1_real_arr = PyArray_FROM_OTF(py_b1_real, NPY_DOUBLE, NPY_IN_ARRAY); b1_imag_arr = PyArray_FROM_OTF(py_b1_imag, NPY_DOUBLE, NPY_IN_ARRAY); grx_arr = PyArray_FROM_OTF(py_grx, NPY_DOUBLE, NPY_IN_ARRAY); gry_arr = PyArray_FROM_OTF(py_gry, NPY_DOUBLE, NPY_IN_ARRAY); grz_arr = PyArray_FROM_OTF(py_grz, NPY_DOUBLE, NPY_IN_ARRAY); tp_arr = PyArray_FROM_OTF(py_tp, NPY_DOUBLE, NPY_IN_ARRAY); df_arr = PyArray_FROM_OTF(py_df, NPY_DOUBLE, NPY_IN_ARRAY); dx_arr = PyArray_FROM_OTF(py_dx, NPY_DOUBLE, NPY_IN_ARRAY); dy_arr = PyArray_FROM_OTF(py_dy, NPY_DOUBLE, NPY_IN_ARRAY); dz_arr = PyArray_FROM_OTF(py_dz, NPY_DOUBLE, NPY_IN_ARRAY); mx_arr = PyArray_FROM_OTF(py_mx, NPY_DOUBLE, NPY_INOUT_ARRAY); my_arr = PyArray_FROM_OTF(py_my, NPY_DOUBLE, NPY_INOUT_ARRAY); mz_arr = PyArray_FROM_OTF(py_mz, NPY_DOUBLE, NPY_INOUT_ARRAY); b1_real = (double *) PyArray_DATA(b1_real_arr); b1_imag = (double *) PyArray_DATA(b1_imag_arr); grx = (double *) PyArray_DATA(grx_arr); gry = (double *) PyArray_DATA(gry_arr); grz = (double *) PyArray_DATA(grz_arr); tp = (double *) PyArray_DATA(tp_arr); df = (double *) PyArray_DATA(df_arr); dx = (double *) PyArray_DATA(dx_arr); dy = (double *) PyArray_DATA(dy_arr); dz = (double *) PyArray_DATA(dz_arr); mx = (double *) PyArray_DATA(mx_arr); my = (double *) PyArray_DATA(my_arr); mz = (double *) PyArray_DATA(mz_arr); blochsimfz(b1_real, b1_imag, grx, gry, grz, tp, ntime, t1, t2, df, nf, dx, dy, dz, n_pos, mx, my, mz, mode); Py_DECREF(b1_real_arr); Py_DECREF(b1_imag_arr); Py_DECREF(grx_arr); Py_DECREF(gry_arr); Py_DECREF(grz_arr); Py_DECREF(tp_arr); Py_DECREF(df_arr); Py_DECREF(dx_arr); Py_DECREF(dy_arr); Py_DECREF(dz_arr); Py_DECREF(mx_arr); Py_DECREF(my_arr); Py_DECREF(mz_arr); return Py_BuildValue(""); }
void mexFunction(int nlhs, mxArray *plhs[], int nrhs, const mxArray *prhs[]) /* bloch(b1,gradxyz,dt,t1,t2,df,dx,dy,dz,mode,mx,my,mz) */ { double *b1r; /* Real-part of B1 field. */ double *b1i; /* Imag-part of B1 field. */ double *gx; /* X-axis gradient. */ double *gy; /* Y-axis gradient. */ double *gz; /* Z-axis gradient. */ double *tp; /* Time steps (s) */ double *ti; /* Time intervals (s) */ double t1; /* T1 time constant (s) */ double t2; /* T2 time constant (s) */ double *df; /* Off-resonance Frequencies (Hz) */ double *dx; /* X Positions (cm) */ double *dy; /* Y Positions (cm) */ double *dz; /* Z Positions (cm) */ int md; /* Mode - 0=from M0, 1=steady-state */ double tstep; /* Time step, if single parameter */ double *mxin; /* Input points */ double *myin; double *mzin; double *mxout; /* Input points */ double *myout; double *mzout; double *mx; /* Output Arrays */ double *my; double *mz; int gyaflag=0; /* 1 if gy was allocated. */ int gzaflag=0; /* 1 if gy was allocated. */ int dyaflag=0; /* 1 if dy was allocated. */ int dzaflag=0; /* 1 if dy was allocated. */ int ntime; /* Number of time points. */ int ntout; /* Number of time poitns at output. */ int outsize[3]; /* Output matrix sizes */ int ngrad; /* Number of gradient dimensions */ int nf; int npos; /* Number of positions. Calculated from nposN and nposM, depends on them. */ int nposM; /* Height of passed position matrix. */ int nposN; /* Width of passed position matrix. */ int nfnpos; /* Number of frequencies * number of positions. */ int ntnfnpos; /* Number of output times *frequencies*number of positions. */ int count; #ifdef DEBUG printf("---------------------------------------\n"); printf("3D-position + frequency Bloch Simulator\n"); printf("---------------------------------------\n\n"); #endif ntime = mxGetM(prhs[0]) * mxGetN(prhs[0]); /* Number of Time, RF, and Grad points */ /* ====================== RF (B1) ========================= * : If complex, split up. If real, allocate an imaginary part. ==== */ if (mxIsComplex(prhs[0])) { b1r = mxGetPr(prhs[0]); b1i = mxGetPi(prhs[0]); } else { b1r = mxGetPr(prhs[0]); b1i = (double *)malloc(ntime * sizeof(double)); for (count=0; count < ntime; count++) b1i[count]=0.0; } #ifdef DEBUG printf("%d B1 points.\n",ntime); #endif /* ======================= Gradients ========================= */ ngrad = mxGetM(prhs[1]) * mxGetN(prhs[1]); /* Number of Time, RF, and Grad points */ gx = mxGetPr(prhs[1]); /* X-gradient is first N points. */ if (ngrad < 2*ntime) /* Need to allocate Y-gradient. */ { #ifdef DEBUG printf("Assuming 1-Dimensional Gradient\n"); #endif gy = (double *)malloc(ntime * sizeof(double)); gyaflag=1; for (count=0; count < ntime; count++) gy[count]=0.0; } else { #ifdef DEBUG printf("Assuming (at least) 2-Dimensional Gradient\n"); #endif gy = gx + ntime; /* Assign from Nx3 input array. */ } if (ngrad < 3*ntime) /* Need to allocate Z-gradient. */ { gz = (double *)malloc(ntime * sizeof(double)); gzaflag=1; for (count=0; count < ntime; count++) gz[count]=0.0; } else { #ifdef DEBUG printf("Assuming 3-Dimensional Gradient\n"); #endif gz = gx + 2*ntime; /* Assign from Nx3 input array. */ } /* Warning if Gradient length is not 1x, 2x, or 3x RF length. */ #ifdef DEBUG printf("%d Gradient Points (total) \n",ngrad); #endif if ( (ngrad != ntime) && (ngrad != 2*ntime) && (ngrad != 3*ntime) ) printf("Gradient length differs from B1 length\n"); if (gx == NULL) printf("ERROR: gx is not allocated. \n"); if (gy == NULL) printf("ERROR: gy is not allocated. \n"); if (gz == NULL) printf("ERROR: gz is not allocated. \n"); /* === Time points ===== */ /* THREE Cases: 1) Single value given -> this is the interval length for all. 2) List of intervals given. 3) Monotonically INCREASING list of end times given. For all cases, the goal is for tp to have the intervals. */ ti = NULL; tp = mxGetPr(prhs[2]); if (mxGetM(prhs[2]) * mxGetN(prhs[2]) == 1) /* === Case 1 === */ { tp = (double *)malloc(ntime * sizeof(double)); tstep = *(mxGetPr(prhs[2])); for (count =0; count < ntime; count++) tp[count]=tstep; } else if (mxGetM(prhs[2]) * mxGetN(prhs[2]) != ntime) printf("Time-point length differs from B1 length\n"); else { tp = mxGetPr(prhs[2]); ti = (double *)malloc(ntime * sizeof(double)); if (( times2intervals( tp, ti, ntime ))) { printf("Times are monotonically increasing. \n"); tp = ti; } } /* === Relaxation Times ===== */ t1 = *mxGetPr(prhs[3]); t2 = *mxGetPr(prhs[4]); /* === Frequency Points ===== */ df = mxGetPr(prhs[5]); nf = mxGetM(prhs[5]) * mxGetN(prhs[5]); #ifdef DEBUG printf("%d Frequency points.\n",nf); #endif /* === Position Points ===== */ nposM = mxGetM(prhs[6]); nposN = mxGetN(prhs[6]); #ifdef DEBUG printf("Position vector is %d x %d. \n",nposM,nposN); #endif if (nposN==3) /* Assume 3 position dimensions given */ { npos = nposM; #ifdef DEBUG printf("Assuming %d 3-Dimensional Positions\n",npos); #endif dx = mxGetPr(prhs[6]); dy = dx + npos; dz = dy + npos; } else if (nposN==2) /* Assume only 2 position dimensions given */ { npos = nposM; #ifdef DEBUG printf("Assuming %d 2-Dimensional Positions\n",npos); #endif dx = mxGetPr(prhs[6]); dy = dx + npos; dz = (double *)malloc(npos * sizeof(double)); dzaflag=1; for (count=0; count < npos; count++) dz[count]=0.0; } else /* Either 1xN, Nx1 or something random. In all these cases we assume that 1 position is given, because it is too much work to try to figure out anything else! */ { npos = nposM * nposN; #ifdef DEBUG printf("Assuming %d 1-Dimensional Positions\n",npos); #endif dx = mxGetPr(prhs[6]); dy = (double *)malloc(npos * sizeof(double)); dz = (double *)malloc(npos * sizeof(double)); dyaflag=1; dzaflag=1; for (count=0; count < npos; count++) { dy[count]=0.0; dz[count]=0.0; } #ifdef DEBUG if ((nposM !=1) && (nposN!=1)) { printf("Position vector should be 1xN, Nx1, Nx2 or Nx3. \n"); printf(" -> Assuming 1 position dimension is given. \n"); } #endif } if (dx == NULL) printf("ERROR: dx is not allocated. \n"); if (dy == NULL) printf("ERROR: dy is not allocated. \n"); if (dz == NULL) printf("ERROR: dz is not allocated. \n"); nfnpos = nf*npos; /* Just used to speed things up below. */ /* ===== Mode, defaults to 0 (simulate single endpoint, transient). ==== */ if (nrhs > 7) md = (int)(*mxGetPr(prhs[7])); else md = 0; if (md & 2) ntout = ntime; /* Include time points. */ else ntout = 1; #ifdef DEBUG printf("Mode = %d, %d Output Time Points \n",md,ntout); #endif ntnfnpos = ntout*nfnpos; #ifdef DEBUG if ((md & 1)==0) printf("Simulation from Initial Condition.\n"); else printf("Simulation of Steady-State.\n"); if ((md & 2)==0) printf("Simulation to Endpoint. \n"); else printf("Simulation over Time.\n"); #endif /* ===== Allocate Output Magnetization vectors arrays. */ plhs[0] = mxCreateDoubleMatrix(ntnfnpos,1,mxREAL); /* Mx, output. */ plhs[1] = mxCreateDoubleMatrix(ntnfnpos,1,mxREAL); /* My, output. */ plhs[2] = mxCreateDoubleMatrix(ntnfnpos,1,mxREAL); /* Mz, output. */ mx = mxGetPr(plhs[0]); my = mxGetPr(plhs[1]); mz = mxGetPr(plhs[2]); mxout = mx; myout = my; mzout = mz; /* ===== If Initial Magnetization is given... */ if ( (nrhs > 10) && (mxGetM(prhs[8]) * mxGetN(prhs[8]) == nfnpos) && (mxGetM(prhs[9]) * mxGetN(prhs[9]) == nfnpos) && (mxGetM(prhs[10]) * mxGetN(prhs[10]) == nfnpos) ) /* Set output magnetization to that passed. If multiple time points, then just the first is set. */ { #ifdef DEBUG printf("Using Specified Initial Magnetization.\n"); #endif mxin = mxGetPr(prhs[8]); myin = mxGetPr(prhs[9]); mzin = mxGetPr(prhs[10]); for (count =0; count < nfnpos; count++) { *mxout = *mxin++; *myout = *myin++; *mzout = *mzin++; mxout += ntout; myout += ntout; mzout += ntout; } } else { #ifdef DEBUG if (nrhs > 10) /* Magnetization given, but wrong size! */ { printf("Initial magnetization passed, but not Npositions x Nfreq. \n"); } printf(" --> Using [0; 0; 1] for initial magnetization. \n"); #endif for (count =0; count < nfnpos; count++) { *mxout = 0; /* Set magnetization to Equilibrium */ *myout = 0; *mzout = 1; mxout += ntout; myout += ntout; mzout += ntout; } } /* ======= Do The Simulation! ====== */ #ifdef DEBUG printf("Calling blochsimfz() function in Mex file.\n"); #endif blochsimfz(b1r,b1i,gx,gy,gz,tp,ntime,t1,t2,df,nf,dx,dy,dz,npos,mx,my,mz,md); /* ======= Reshape Output Matrices ====== */ if ((ntout > 1) && (nf > 1) && (npos > 1)) { outsize[0]=ntout; outsize[1]=npos; outsize[2]=nf; mxSetDimensions(plhs[0],outsize,3); /* Set to 3D array. */ mxSetDimensions(plhs[1],outsize,3); /* Set to 3D array. */ mxSetDimensions(plhs[2],outsize,3); /* Set to 3D array. */ } else /* Basically "squeeze" the matrix. */ { if (ntout > 1) { outsize[0]=ntout; outsize[1]=npos*nf; } else { outsize[0]=npos; outsize[1]=nf; } mxSetDimensions(plhs[0],outsize,2); /* Set to 2D array. */ mxSetDimensions(plhs[1],outsize,2); /* Set to 2D array. */ mxSetDimensions(plhs[2],outsize,2); /* Set to 2D array. */ } /* ====== Free up allocated memory, if necessary. ===== */ if (!mxIsComplex(prhs[0])) free(b1i); /* We had to allocate this before. */ if (mxGetM(prhs[2]) * mxGetN(prhs[2]) == 1) free(tp); /* We had to allocate this. */ if (ti != NULL) free(ti); if (dyaflag==1) free(dy); if (dzaflag==1) free(dz); if (gyaflag==1) free(gy); if (gzaflag==1) free(gz); }