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("");
}
Exemplo n.º 2
0
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);

}