void addMatrixAsVectorVector(Pool& p, const string& key, const TNT::Array2D<Real>& mat) {
    for (int i=0; i<int(mat.dim1()); ++i) {
        vector<Real> v(mat.dim1());
        for (int j=0; j<int(mat.dim2()); ++j) {
            v[j] = mat[i][j];
        }
        p.add(key, v);
    }
}
Exemple #2
0
int
initialise_maes (TNT::Array2D < unk > mesh,
		 TNT::Array2D < double >faceBx,
		 TNT::Array2D < double >faceBy,
		 MPI_Comm new_comm, int ndims, int *dim_size,
		 double *xsize, double *ysize)
{
  double minpressure = 9e99;
  double mindensity = 9e99;
  double maxdensity = (-9e99);

  std::cout << "Initialise Magnetised Accretion-Ejection Structure " << std::
    endl;

  const int nx = mesh.dim1 ();
  const int ny = mesh.dim2 ();
  const double gammam1i = 1 / (PhysConsts::gamma - 1);
  const double gammam1 = (PhysConsts::gamma - 1);
  double r0, r, z, h;
  double r2, z2, h2;
  double r02;
  // ms is a parameter smaller than unity 
  // which then ensures an initial subsonic poloidal 
  // inflow
  double ms = 0.3;
  double rho, vtheta, vz, vr, bz, br, btheta;
  // plasma beta parameter measuring the ratio of the 
  // thermal pressure to the magnetic pressure at Z = 0
  double beta = 1.0;

  double pressure = 0;
  // Disk Aspect Ratio
  double eps = 0.1;

  int coords[] = { 0, 0 };

  int myid = 99;

  MPI_Comm_rank (MPI_COMM_WORLD, &myid);

  MPI_Cart_coords (new_comm, myid, ndims, coords);
  int dims[] = { 0, 0 };
  MPI_Cartdim_get (new_comm, dims);

  int xmax = 0;
  int ymax = 0;
  MPI_Allreduce (coords, &xmax, 1, MPI_INT, MPI_MAX, new_comm);
  MPI_Allreduce (coords + 1, &ymax, 1, MPI_INT, MPI_MAX, new_comm);
  xmax++;
  ymax++;

  std::cout << "Proc" << myid << " " << xmax << " " << ymax << std::endl;
  int myaddress[] = { 0, 0 };
  myaddress[0] = (nx - 2 * NGC) * coords[0];
  myaddress[1] = (ny - 2 * NGC) * coords[1];


  *xsize = 40;
  // Initialise the face-centred magnetic field
  for (int jj = 0; jj < ny + 1; jj++)
    for (int ii = 0; ii < nx + 1; ii++)
      {
	//
	int gg = std::max (ii - NGC, 0);
	float myx = 0;
	float myy = 0;
	myx = (float) myaddress[0] + gg;
	float delta_x = *xsize / ((nx - 2 * NGC) * xmax);
	//std::cout << delta_x << " " <<delta_y << std::endl;
	r = (40.0 * myx) / (dim_size[0] * nx) + delta_x * 0.5;
	h = eps * r;
	h2 = h * h;
	r2 = r * r;
	r0 = 4;
	r02 = r0 * r0;
	bz = pow (r0, 2.5) / (pow ((r02 + r2), 1.25) * sqrt (beta));
	faceBx[ii][jj] = 0.0;
	faceBy[ii][jj] = bz;
	if (isnan (bz))
	  {
	    MPI_Abort (MPI_COMM_WORLD, 33333333);
	    exit (0);
	  }
//      faceBy[ii][jj] = 3.0;
      }

  for (int jj = 0; jj < ny + 1; jj++)
      {
	faceBy[nx][jj] = 
	faceBy[nx-1][jj] = 
	faceBy[nx-2][jj]  ;

		}

#undef PROBS_WITH_B
#ifdef PROBS_WITH_B
  for (int hh = 0; hh < ny + 1; hh++)
    for (int gg = 0; gg < nx + 1; gg++)
      {
	faceBy[hh][gg] = 3.0;
      }
#endif

  *xsize = 40;
  *ysize = 80;

  for (int jj = 2; jj < ny; jj++)
    for (int ii = 2; ii < nx; ii++)
      {
	// Mass Density
	int gg = ii - NGC;
	int hh = jj - NGC;
	float myx = 0;
	float myy = 0;
	myx = (float) myaddress[0] + gg;
	myy = (float) myaddress[1] + hh;
	float delta_x = *xsize / ((nx - 2 * NGC) * xmax);
	float delta_y = *ysize / ((ny - 2 * NGC) * ymax);
	//std::cout << delta_x << " " <<delta_y << std::endl;
	z = (80.0 * myy) / (dim_size[1] * ny) + delta_y * 0.5;
	r = (40.0 * myx) / (dim_size[0] * nx) + delta_x * 0.5;
	r = std::max (r, delta_x * 0.5);
	z = std::max (z, delta_y * 0.5);
	h = eps * r;
	h2 = h * h;
	z2 = z * z;
	r2 = r * r;
	/* R0 is a constant set equal to 4 in our runs. 
	 * This offset radius in the denominator makes the 
	 * density regular up to R = 0. 
	 */
	r0 = 4;
	r02 = r0 * r0;
	rho =
	  std::max (1e-6, (pow (r0, 1.5) / pow ((r0 * r0 + r * r), 0.75))) *
	  std::pow (std::max (1e-6, (1 - 0.5 * (gammam1) * z2 / h2)), gammam1i);
	//mesh[ii][jj] _MASS= (pow(r0,1.5)/pow((r0*r0+r*r),0.75))*pow (max(1e-6,  (1- 0.5* (gammam1) * z2/h2 )), gammam1i ) ;
	rho = std::max (1e-6, rho);
	/*
	std::cout 
	<< rho 
	<< " " << ii << " " << jj 
	<< " " << r 
	<< " " <<  
	  std::pow (std::max (1e-6, (1 - 0.5 * (gammam1) * z2 / h2)), gammam1i)

	<< std::endl;
	*/
	

	mesh[ii][jj] _MASS = rho;
	/*
	   mesh[ii][jj] _MASS =  0.2 * ( 
	   mesh[ii][jj] _MASS  +
	   mesh[ std::min(ii+1,nx-1)    ][jj] _MASS  +
	   mesh[ std::max(ii-1,0)       ][jj] _MASS  +
	   mesh[ii                                                      ][std::min (jj+1, ny-1) ] _MASS  +
	   mesh[ii                                                      ][std ::max(jj-1,0)] _MASS  
	   );
	 */

	// Rotation Profile
	vtheta =
	  (1 -
	   eps * eps) * sqrt (r0) * exp (-2 * z2 / h2) / (eps *
							  pow ((r02 + r2),
							       0.25));
	mesh[ii][jj] _MOMZ = mesh[ii][jj] _MASS *vtheta;
	if (isnan (mesh[ii][jj] _MOMZ))
	  {
	    std::cout << "z-momentum is nan" << std::endl;
	    MPI_Abort (MPI_COMM_WORLD, 0);
	    exit (0);
	  }

	// Poloidal Velocity
	vr =
	  (-ms) * sqrt (r0) * exp (-2 * z2 / h2) / (pow ((r02 + r2), 0.25));
	mesh[ii][jj] _MOMX = mesh[ii][jj] _MASS *vr;
	if (isnan (mesh[ii][jj] _MOMX))
	  {
	    std::cout << "x-momentum is nan" << std::endl;
	    MPI_Abort (MPI_COMM_WORLD, 99);
	    exit (0);
	  }

	vz = vr * z / r;
	mesh[ii][jj] _MOMY = mesh[ii][jj] _MOMX *z / r;
	if (isnan (mesh[ii][jj] _MOMY))
	  {
	    std::cout << "y-momentum is nan" << std::endl;
	    MPI_Abort (MPI_COMM_WORLD, 101);
	    exit (0);
	  }

	// Magnetic Field
	bz = pow (r0, 2.5) / (pow ((r02 + r2), 1.25) * sqrt (beta));
	bz = 0.5 * (faceBy[ii][jj] + faceBy[ii][jj + 1]);
	br = 0;
	btheta = 0;

	// Pressure = rho ^ gamma
	pressure = pow (rho, PhysConsts::gamma);

	// Energy
	mesh[ii][jj] _B_X = 0.;
	mesh[ii][jj] _B_Y = bz;
	mesh[ii][jj] _B_Z = 0.;
	double vv2 = vz * vz + vr * vr + vtheta * vtheta;
	double b2 = bz * bz + br * br + btheta * btheta;
	mesh[ii][jj] _ENER =
	  (0.5 * rho * vv2) + (0.5 * b2) + pressure * gammam1i
	  ;
	if (mesh[ii][jj] _ENER < 0)
	  {

	    std::cout
	      << " Neg init energy"
	      << " (" << ii << " , " << jj << " )" << std::endl;
	  }

	mesh[ii][jj].temperature = myid;

	minpressure = std::min (pressure, minpressure);
	mindensity = std::min (rho, mindensity);
	maxdensity = std::max (rho, maxdensity);
      }




  std::cout << "Min pressure " << minpressure << std::endl;
  std::cout << "Min density " << mindensity << std::endl;
  std::cout << "Max density " << maxdensity << std::endl;

  //



}
int
emf_exchange (TNT::Array2D < double >faceEx,
	      TNT::Array2D < double >faceEy,
	      int myNorth, int mySouth, int myEast, int myWest, int myid)
{


	int nx=faceEx.dim1();
	int ny=faceEy.dim2();
  MPI_Status stat;

  int fnx = faceEx.dim1 ();
  int fny = faceEy.dim2 ();

  int xfnx = faceEx.dim1 ();
  int xfny = faceEx.dim2 ();

  int yfnx = faceEy.dim1 ();
  int yfny = faceEy.dim2 ();

  int ne = NE;

  unk test;


  double gammam1 = PhysConsts::gamma - 1;
  double gammam1i = 1.0 / gammam1;


  MPI_Datatype FaceCol;
  MPI_Datatype FaceRowt;

  MPI_Datatype xFaceCol;
  MPI_Datatype xFaceRow;
  MPI_Datatype yFaceCol;
  MPI_Datatype yFaceRow;








  MPI_Type_vector (fnx,		/* # column elements */
		   1,		/* 1 column only */
		   fny,		/* skip ny elements */
		   MPI_DOUBLE,	/* elements are double */
		   &FaceCol);	/* MPI derived datatype */

  MPI_Type_vector (1,		/* # row elements */
		   fny,		/* 1 row only */
		   0,		/* skip ny elements */
		   //    myrow,   /* elements are double */
		   MPI_DOUBLE,	/* elements are double */
		   &FaceRowt);	/* MPI derived datatype */



  MPI_Type_vector (xfnx,	/* # column elements */
		   1,		/* 1 column only */
		   xfny,	/* skip ny elements */
		   MPI_DOUBLE,	/* elements are double */
		   &xFaceCol);	/* MPI derived datatype */

  MPI_Type_vector (1,		/* # row elements */
		   xfny,	/* 1 row only */
		   0,		/* skip ny elements */
		   //    myrow,   /* elements are double */
		   MPI_DOUBLE,	/* elements are double */
		   &xFaceRow);	/* MPI derived datatype */



  MPI_Type_vector (yfnx,	/* # column elements */
		   1,		/* 1 column only */
		   yfny,	/* skip ny elements */
		   MPI_DOUBLE,	/* elements are double */
		   &yFaceCol);	/* MPI derived datatype */

  MPI_Type_vector (1,		/* # row elements */
		   yfny,	/* 1 row only */
		   0,		/* skip ny elements */
		   //    myrow,   /* elements are double */
		   MPI_DOUBLE,	/* elements are double */
		   &yFaceRow);	/* MPI derived datatype */


  MPI_Type_commit (&FaceCol);
  MPI_Type_commit (&FaceRowt);
  MPI_Type_commit (&yFaceCol);
  MPI_Type_commit (&yFaceRow);
  MPI_Type_commit (&xFaceCol);
  MPI_Type_commit (&xFaceRow);



#define DEBUG
#ifdef DEBUG1
  std::cout << "Proc " << myid << " okay to here " << std::endl;
#endif


  //========== FACE CENTRED ELECTRIC FIELD EXCHANGE ===============

  // Send Columns

#define OLDWAY
#ifdef OLDWAY

  MPI_Send (&faceEx[0][xfny - 3], 1, xFaceCol, myNorth, myid, MWULD);
  MPI_Recv (&faceEx[0][1], 1, xFaceCol, mySouth, mySouth, MWULD, &stat);
  MPI_Barrier (MWULD);
  MPI_Send (&faceEx[0][2], 1, xFaceCol, mySouth, myid, MWULD);
  MPI_Recv (&faceEx[0][xfny - 2], 1, xFaceCol, myNorth, myNorth, MWULD, &stat);
  MPI_Barrier (MWULD);
  MPI_Send (&faceEy[2][0], 1, yFaceRow, myWest, myid, MWULD);
  MPI_Recv (&faceEy[yfnx - 2][0], 1, yFaceRow, myEast, myEast, MWULD, &stat);
  MPI_Barrier (MWULD);
  MPI_Send (&faceEy[yfnx - 3][0], 1, yFaceRow, myEast, myid, MWULD);
  MPI_Recv (&faceEy[1][0], 1, yFaceRow, myWest, myWest, MWULD, &stat);
  MPI_Barrier (MWULD);


#else


#ifdef PERIODIC
  for (int i = 2; i < nx-1 ; ++i)
  {
     faceEx[i][ny-2]=faceEx[i][2] ;
     faceEx[i][1]= (faceEx[i][ny-3]) ;

  }
  for (int j = 2; j < ny - 1; ++j)
  {
     faceEy[nx-2][j]= faceEy[2][j];
     faceEy[1][j]= (faceEy[nx-3][j]) ;
  }
#else

  for (int i = 2; i < nx-1 ; ++i)
  {
     faceEx[i][ny-2]=faceEx[i][ny-3] ;
     faceEx[i][1]= (faceEx[i][2]) ;
  }
  for (int j = 2; j < ny - 1; ++j)
  {
     faceEy[nx-2][j]= faceEy[nx-3][j];
     faceEy[1][j]= (-faceEy[2][j]) ;
  }

#endif

#endif


#ifdef CYLINDRICAL


if (myNorth == MPI_PROC_NULL)
{
  for (int i = 0; i < nx ; ++i)
  {
     faceEx[i][ny-2]=faceEx[i][ny-3] ;
  }
}

if (mySouth == MPI_PROC_NULL)
{
  for (int i = 0; i < nx ; ++i)
  {
     faceEx[i][1]= (faceEx[i][2]) ;
  }
}

if (myEast == MPI_PROC_NULL)
{
  for (int j = 0; j < ny ; ++j)
  {
     faceEy[nx-2][j]= faceEy[nx-3][j];
  }
}


if (myWest == MPI_PROC_NULL)
{
  for (int j = 0; j < ny ; ++j)
  {
     faceEy[1][j]= (-faceEy[2][j]) ;
  }
}
#endif

#ifdef MAES


  if (mySouth == MPI_PROC_NULL)
    {
      if (myWest == MPI_PROC_NULL)
   {
		int diskheight=8;
		int boxwidth=8;
     for (int j = 0; j < diskheight; ++j)
       {
         for (int i = 0; i < boxwidth; ++i)
      {
        faceEx[i][diskheight-1] = faceEx[i][diskheight];
        faceEx[i][j] = faceEx[i][diskheight];
        faceEy[i][j] = faceEy[i][diskheight];
      }
       }
     for (int j = 0; j < diskheight; ++j)
       {
        faceEy[boxwidth-1][j] = faceEy[boxwidth][j];
		 }
   }
    }


#endif



  return 0;
}
int
initialise_jet (TNT::Array2D < unk > mesh,
                TNT::Array2D < double >faceBx,
                TNT::Array2D < double >faceBy,
                MPI_Comm new_comm, int ndims, int *dim_size,
                double *xsize, double *ysize)
{

    std::cout << "Initialise Jet Problem" << std::endl;
    const int nx = mesh.dim1 ();
    const int ny = mesh.dim2 ();
    const double gammam1i = 1 / (PhysConsts::gamma - 1);
    const double gammam1 = (PhysConsts::gamma - 1);
    double r0, r, z, h;
    double r2, z2, h2;
    double r02;
    // ms is a parameter smaller than unity
    // which then ensures an initial subsonic poloidal
    // inflow
    double ms = 0.3;
    double rho, vtheta, vz, vr, bz, br, btheta;
    // plasma beta parameter measuring the ratio of the thermal pressure to the magnetic pressure at Z = 0
    double beta = 1.0;

    double pressure = 0;
    // Disk Aspect Ratio
    double eps = 0.1;
    double bx = 10;
    double by = 10;


    int coords[] = { 0, 0 };

    int myid = 99;

    MPI_Comm_rank (MPI_COMM_WORLD, &myid);

    MPI_Cart_coords (new_comm, myid, ndims, coords);
    int dims[] = { 0, 0 };
    MPI_Cartdim_get (new_comm, dims);

    int xmax = 0;
    int ymax = 0;
    MPI_Allreduce (coords, &xmax, 1, MPI_INT, MPI_MAX, new_comm);
    MPI_Allreduce (coords + 1, &ymax, 1, MPI_INT, MPI_MAX, new_comm);
    xmax++;
    ymax++;

    std::cout << "Proc" << myid << " " << xmax << " " << ymax << std::endl;
    int myaddress[] = { 0, 0 };
    myaddress[0] = (nx - 2 * NGC) * coords[0];
    myaddress[1] = (ny - 2 * NGC) * coords[1];

    xmax *= (nx - 2 * NGC);
    ymax *= (ny - 2 * NGC);

    *xsize = 100.0;
    *ysize = 200.0;
    // Initialise face-centered B fields
    for (int ii = 0; ii < nx + 1; ii++)
        for (int jj = 0; jj < ny + 1; jj++)
        {
            int gg = ii - NGC;
            int hh = jj - NGC;
            double myx = (float) myaddress[0] + (ii - NGC);
            double myy = (float) myaddress[1] + (jj - NGC);
            //faceBx[ii][jj] =  -sin( 2*PhysConsts::pi * myy / ymax) ;
            //faceBy[ii][jj] =  sin( 4*PhysConsts::pi * myx / xmax);
            faceBx[ii][jj] = 0.0;
            faceBy[ii][jj] = 1.0;
        }

    for (int jj = 0; jj < ny; jj++)
        for (int ii = 0; ii < nx; ii++)
        {
            // Mass Density
            bx = 0.5 * (faceBx[ii][jj] + faceBx[ii + 1][jj]);
            by = 0.5 * (faceBy[ii][jj] + faceBy[ii][jj + 1]);
            bz = 0.0;
            rho = 0.25;
            double myx = (float) myaddress[0] + (ii - NGC);
            double myy = (float) myaddress[1] + (jj - NGC);
            double vx = 0.0;
            double vy = 0.0;
            double vz = 0.0;
            if ( 0 &&  myx <40 && myy<40)
            {
                vy=10.0;
                if ( myx >30)
                {
                    vy= (40 - 30 )*(myx - 40)/(0-10);
                }
            }
            //if (  myy<40) vy=10.0;

            double bsqr = 0.5 * (bx * bx + by * by + bz * bz);
            double ke = 0.5 * rho * (vx * vx + vy * vy + vz * vz);
            double rmax2=nx*nx;
            pressure = 0.5+(1.- myx*myx / rmax2);
            pressure = 0.0004;
            mesh[ii][jj] _MASS = rho;
            mesh[ii][jj] _MOMX = rho * vx;
            mesh[ii][jj] _MOMY = rho * vy;
            mesh[ii][jj] _MOMZ = rho * vz;
            mesh[ii][jj] _ENER = pressure * gammam1i + bsqr + ke;
            mesh[ii][jj] _B_X = bx;
            mesh[ii][jj] _B_Y = by;
            mesh[ii][jj] _B_Z = bz*myx/nx;
            mesh[ii][jj].temperature = myid;
        }


}
int
parflux (TNT::Array2D < unk > mesh,
	 TNT::Array2D < flux > fx,
	 TNT::Array2D < flux > fy,
	 TNT::Array2D < double >xjx,
	 TNT::Array2D < double >xjy,
	 TNT::Array2D < double >xjz,
	 TNT::Array2D < double >yjx,
	 TNT::Array2D < double >yjy,
	 TNT::Array2D < double >yjz,
	 double *delta_x, double *delta_y, int *myaddress, MPI_Comm Cart_comm)
{

  double eps = 0.1;
  double gammam1 = PhysConsts::gamma - 1.;
  double gammam1i = 1. / gammam1;

  int nx = mesh.dim1 ();
  int ny = mesh.dim2 ();
  // Current arrays

  int myid = 99999;
  MPI_Comm_rank (MPI_COMM_WORLD, &myid);
  int ndims = 2;
  int coords[2];


  int remain_dims[] = { 0, 1 };
  MPI_Comm Sub_comm;
  MPI_Cart_sub (Cart_comm, remain_dims, &Sub_comm);
  int lowest = 99999;
  coords[1] = 1;
  MPI_Cart_coords (Cart_comm, myid, ndims, coords);
  MPI_Cart_rank (Cart_comm, coords, &lowest);
  // Check my position in the Cartesian grid
  // Then bcast my id to the Sub_comm
  // Then all print out the id
  // Grab the coords of the processor
  double tmpbuf;
  tmpbuf = myid;
  TNT::Array1D < double >pressure_buf (nx);
  MPI_Bcast (&tmpbuf, 1, MPI_DOUBLE, 0, Sub_comm);

#ifdef DEBUG_SUB_COMM
  std::cout
    << "myid = " << myid
    << "coords = (" << coords[0] << "," << coords[1] << ")"
    << " lowest = " << tmpbuf << std::endl;
#endif



  // Sweep for fluxes 
  for (int ii = 1; ii <= nx - 2; ii++)
    {
      for (int jj = 1; jj <= ny - 2; jj++)
	{

	  double rr = mesh[ii][jj] _MASS;
	  if (rr < 0)
	  {
		  std::cout 
			  << __FUNCTION__ << ": "
			  << "Negative density at"
			  << " (" << ii << " , " << jj <<" )"
			  <<std::endl;
		  MPI_Abort(MPI_COMM_WORLD, 1234);
		  exit(0);
	  }
	  double px = mesh[ii][jj] _MOMX;
	  double py = mesh[ii][jj] _MOMY;
	  double pz = mesh[ii][jj] _MOMZ;
	  double et = mesh[ii][jj] _ENER;
	  double bx = mesh[ii][jj] _B_X;
	  double by = mesh[ii][jj] _B_Y;
	  double bz = mesh[ii][jj] _B_Z;

	  double ri = 1.0 / rr;
	  double vx = px * ri;
	  double vy = py * ri;
	  double vz = pz * ri;
	  double ke = 0.5 * rr * (vx * vx + vy * vy);
	  double b2 = 0.5 * (bx * bx + by * by + bz * bz);
	  double vdotb = (vx * bx + vy * by + vz * bz);
	  double p = et - ke - b2;
	  double ptot = et - ke;
	  p = p * gammam1;


	  if (isnan (p))
	    {
	      std::cout
		<< __FUNCTION__
		<< " ("
		<< ii << "," << jj
		<< ") bx " << bx << " by " << by << " bz " << bz << std::endl;
			MPI_Abort (MPI_COMM_WORLD, 44444);
			exit(0);
	    }

	  // Work out current at each cell face and add to energy flux
	  // xflux current
	  double idx = 1.0 / (*delta_x);
	  double idy = 1.0 / (*delta_y);


	  xjx[ii][jj] =
	    0.5 * idy * ((mesh[ii][jj + 1] _B_Z + mesh[ii - 1][jj + 1] _B_Z) -
			 (mesh[ii][jj - 1] _B_Z + mesh[ii - 1][jj - 1] _B_Z));

	  if (isnan (xjx[ii][jj]))
	    {
	      std::cout
		<< "xjx"
		<< " " << *delta_y
		<< " " << idy
		<< " " << *delta_x
		<< " " << idx
		<< " " << mesh[ii][jj + 1] _B_Z
		<< " " << mesh[ii - 1][jj + 1] _B_Z << std::endl;
	      MPI_Abort (MPI_COMM_WORLD, 666666);
	      exit (0);
	    }

	  xjy[ii][jj] =
	    (-idx) * ((mesh[ii][jj] _B_Z - mesh[ii - 1][jj] _B_Z));
	  xjz[ii][jj] =
	    (idx) * ((mesh[ii][jj] _B_Y - mesh[ii - 1][jj] _B_Y)) -
	    0.5 * idy * ((mesh[ii][jj + 1] _B_X + mesh[ii - 1][jj + 1] _B_X) -
			 (mesh[ii][jj - 1] _B_X + mesh[ii - 1][jj - 1] _B_X));

	  // yflux current
	  yjx[ii][jj] = idy * (mesh[ii][jj] _B_Z - mesh[ii][jj - 1] _B_Z);
	  yjy[ii][jj] =
	    0.5 * (-idx) *
	    ((mesh[ii + 1][jj] _B_Z + mesh[ii + 1][jj - 1] _B_Z) -
	     (mesh[ii - 1][jj] _B_Z + mesh[ii - 1][jj - 1] _B_Z));
	  yjz[ii][jj] =
	    0.5 * (idx) *
	    ((mesh[ii + 1][jj] _B_Y + mesh[ii + 1][jj - 1] _B_Y) -
	     (mesh[ii - 1][jj] _B_Y + mesh[ii - 1][jj - 1] _B_Y)) -
	    idy * (mesh[ii][jj] _B_X - mesh[ii][jj - 1] _B_X);



	  fx[ii][jj] _MASS = rr * vx;
	  fx[ii][jj] _MOMX = rr * vx * vx + ptot - bx * bx;
	  fx[ii][jj] _MOMY = rr * vx * vy - bx * by;
	  fx[ii][jj] _MOMZ = rr * vx * vz - bx * bz;
	  fx[ii][jj] _ENER = (et + ptot) * vx - bx * vdotb;
	  fx[ii][jj] _B_X = 0;
	  fx[ii][jj] _B_Y = by * bx - bx * vy;
	  fx[ii][jj] _B_Z = bz * vx - bx * vz;

	  fy[ii][jj] _MASS = rr * vy;
	  fy[ii][jj] _MOMX = rr * vx * vy - by * bx;
	  fy[ii][jj] _MOMY = rr * vy * vy + ptot - by * by;
	  fy[ii][jj] _MOMZ = rr * vz * vy - by * bz;
	  fy[ii][jj] _ENER = (et + ptot) * vy - by * vdotb;
	  fy[ii][jj] _B_X = bx * vy - by * vx;
	  fy[ii][jj] _B_Y = 0;
	  fy[ii][jj] _B_Z = bz * vy - by * vz;


	  if (isnan (fy[ii][jj] _ENER))
	    {
	      std::cout
		<< __FUNCTION__
		<< " Flux ("
		<< ii << "," << jj
		<< ") et " << et
		<< " ptot " << ptot
		<< " p " << p
		<< " vy " << vy
		<< " by " << by
		<< " vdotb " << vdotb << " rr " << rr << std::endl;
	      MPI_Abort (MPI_COMM_WORLD, 1222);
	      exit (0);
	    }

	  // Gravity Term
	  // r and z are distances from (0,0) in global grid
	  double myx = (double) myaddress[0] + ii;
	  double myy = (double) myaddress[1] + jj;
	  double r = myx * *delta_x;
	  double z = myy * *delta_y;
#define GRAVITY
#ifdef GRAVITY
	  double GM = 1.0 / (eps * eps);
	  double gravity =
	    (-GM) / std::sqrt (std::pow (r, 2.0) + std::pow (z, 2.0));
	  double grav_en = mesh[ii][jj] _MOMX * gravity;
	  //      std::cout << " r " << r << " z " << z << std::endl;
	  gravity = mesh[ii][jj] _MASS *gravity;
	  fx[ii][jj] _MOMX += gravity;
	  fx[ii][jj] _ENER += grav_en;

	  grav_en = mesh[ii][jj] _MOMY *gravity;
	  gravity = mesh[ii][jj] _MASS *gravity;
	  fy[ii][jj] _MOMY += gravity;
	  fy[ii][jj] _ENER += grav_en;
#else
	  std::cout << "Gravity disabled" << std::endl;

#endif
	  //double etam=alpham * Va * H *exp(-2*zz*zz/(H*H));
	  double etam = 0.1;
	  double alpham = 0.1;
	  // H is the thermal heightscale of the disk
	  // cs is soundspeed at disk midplane
	  // cs = sqrt (gamma *P/ rho);
	  // double cs=0;
	  // omegaK is keplerian velocity at disk midplane
	  double omegaK = 0;
	  omegaK = sqrt (GM / r * r * r);
	  double H = eps * r;
	  double Va =
	    std::sqrt (bx * bx + by * by + bz * bz) / std::sqrt (rr);
	  etam = alpham * H * Va * exp (-2 * z * z / (H * H));
	  double chim = 1.0;
	  double etamdash = chim * etam;
	  double etaR = etamdash;
	  double etaZ = etamdash;
	  double etaPhi = etam;

	  // Resistive Terms (See Toth 2000)
	  // add a -B X (eta J)
	  fx[ii][jj] _ENER +=
	    (by * etaPhi * xjz[ii][jj] - bz * etaZ * xjy[ii][jj]);
	  fy[ii][jj] _ENER +=
	    (-bx * etaPhi * yjz[ii][jj] + bz * etaR * yjx[ii][jj]);
	  if (isnan (fy[ii][jj] _ENER))
	    {
	      std::cout
		<< __FUNCTION__
		<< " Flux ("
		<< ii << "," << jj
		<< ")" 
		<< " bx " << bx
		<< " by " << by
		<< " bz " << bz
		<< " rr " << rr
		<< " etaPhi " << etaPhi
		<< " yjz " << yjz[ii][jj]
		<< " etaR " << etaR << " yjx " << yjx[ii][jj] << std::endl;
	      MPI_Abort (MPI_COMM_WORLD, 1222);
	      exit (0);
	    }



	}
    }

}
Exemple #6
0
/////////////////////////////////////////////////////////////////////////////////////
			// We now calculate the diffusion tensor and its eigenvalues and eigenvectors 
			// The method and the following explanation is from dSimFitTensor.m:
			//	Fit the Stejskal-Tanner equation: S(b) = S(0) exp(-b ADC),
			//	where S(b) is the image acquired at non-zero b-value, and S(0) is
			//	the image acquired at b=0. Thus, we can find ADC with the
			//	following:
			//		ADC = -1/b * log( S(b) / S(0) )
			// 	But, to avoid divide-by-zero, we need to add a small offset to
			//	S(0). We also need to add a small offset to avoid log(0).
			//
			// Note: Using floats in JAMA::SVD causes numerical inaccuracies, so we compute 
			//	everything in double format.
			/////////////////////////////////////////////////////////////////////////////////////
void computeTensor(uint index, double tensors[][3][3], double eigenvecs[][3][3], float lambdas[][3], float mds[], float fas[], float rds[]){
	double* gradDir = new double[3*numGrads];		// gradDir will contain the gradient components, scaled to have norm 1
	double* bVals = new double[numGrads];			// bVals will contain the b-values
	double offset = 0.000001;				// This offset will be used to avoid divide-by-zero errors
	double norm;						// Will contain the norm of each gradient - used for scaling to norm 1
	double logB0 = 0;					// Will contain the average log value of the measured signal for zero gradients
	double* logDw = new double[numGrads];			// Will contain the log values of the measured signal for non-zero gradients
	uint numZeroGrads = 0, numNonZeroGrads = 0;		// Counters for the number of zero and non-zero gradients	
	uint* nonZeroGradsInd = new uint[numGrads];		

	///////////////////////////////////////////////////////////////////
	// Compute gradDir, bVals, logDw and logB0
	///////////////////////////////////////////////////////////////////
	for (uint j=0; j<numGrads; j++){
		norm = sqrt(gradientDataResults[j*numOutputs+3]*gradientDataResults[j*numOutputs+3]+gradientDataResults[j*numOutputs+4]*gradientDataResults[j*numOutputs+4]+gradientDataResults[j*numOutputs+5]*gradientDataResults[j*numOutputs+5]);
		printf("Signal for gradient %u and compartment %i: %g\n", j+1, index-1, gradientDataResults[j*numOutputs+6+index]);
		if (norm==0){
			gradDir[j*3+0] = 0;
			gradDir[j*3+1] = 0;
			gradDir[j*3+2] = 0;
			logB0 += log(gradientDataResults[j*numOutputs+6+index]+offset);
			numZeroGrads++;
		} else {
			gradDir[j*3+0] = (double) gradientDataResults[j*numOutputs+3]/norm;
			gradDir[j*3+1] = (double) gradientDataResults[j*numOutputs+4]/norm;
			gradDir[j*3+2] = (double) gradientDataResults[j*numOutputs+5]/norm;
			logDw[numNonZeroGrads] = log(gradientDataResults[j*numOutputs+6+index]+offset);
			nonZeroGradsInd[numNonZeroGrads] = j;
			numNonZeroGrads++;
		}

		bVals[j] = pow((2.0*3.1415926535*42576.0)*norm/1000000000*gradientDataResults[j*numOutputs+0],2)*(gradientDataResults[j*numOutputs+1]-gradientDataResults[j*numOutputs+0]/3.0);
	}

	logB0 = logB0/numZeroGrads;

	double* bv = new double[numNonZeroGrads*3];			// bv will contain the normalized components of all non-zero gradients
	double errorMargin = 0.000001;					// We will round off matrices to precision errormargin, to avoid small-value numerical errors
	TNT::Array2D<double> adc(numNonZeroGrads,1);			// ADC for each non-zero gradient according to ADC = -1/b * log( S(b) / S(0) )			
	TNT::Array2D<double> m(numNonZeroGrads,6);			// Rearrangement of normalized non-zero gradient components


	for (uint k=0; k<numNonZeroGrads; k++){
		adc[k][0] = -1/bVals[nonZeroGradsInd[k]]*(logDw[k]-logB0);

		bv[k*3+0] = gradDir[nonZeroGradsInd[k]*3+0];
		bv[k*3+1] = gradDir[nonZeroGradsInd[k]*3+1];
		bv[k*3+2] = gradDir[nonZeroGradsInd[k]*3+2];

		m[k][0] = bv[k*3+0]*bv[k*3+0];
		m[k][1] = bv[k*3+1]*bv[k*3+1];
		m[k][2] = bv[k*3+2]*bv[k*3+2];
		m[k][3] = 2*bv[k*3+0]*bv[k*3+1];
		m[k][4] = 2*bv[k*3+0]*bv[k*3+2];
		m[k][5] = 2*bv[k*3+1]*bv[k*3+2];
	}

	// Round off m to avoid small-value numerical errors
	for (int n=0; n<m.dim1(); n++){
		for(int m1=0; m1<m.dim2(); m1++){
			m[n][m1] = floor(m[n][m1]*1000000.0f + 0.5)/1000000.0f;
		}
	}

	////////////////////////////////////////////////////////////////////////////////////////
	// We now find the pseudo-inverse of m by doing an SVD decomposition
	///////////////////////////////////////////////////////////////////////////////////////
	JAMA::SVD<double> svd(m);
	TNT::Array2D<double> S;
	TNT::Array2D<double> U;
	TNT::Array2D<double> V;

	svd.getS(S);
	svd.getU(U);
	svd.getV(V);

	// Round off S, U and V to avoid small-value numerical errors
	for (int p=0; p<S.dim1(); p++){
		for(int q=0; q<S.dim2(); q++){
			S[p][q] = floor(S[p][q]*1000000.0f + 0.5)/1000000.0f;
		}
	}

	for (int p=0; p<U.dim1(); p++){
		for(int q=0; q<U.dim2(); q++){
			U[p][q] = floor(U[p][q]*1000000.0f + 0.5)/1000000.0f;
		}
	}

	for (int p=0; p<V.dim1(); p++){
		for(int q=0; q<V.dim2(); q++){
			V[p][q] = floor(V[p][q]*1000000.0f + 0.5)/1000000.0f;
		}
	}

	// Find the inverse matrix of S
	TNT::Array2D<double> S_inv(S.dim2(),S.dim1());
	for (int n=0; n<S.dim1(); n++){
		for (int m=0; m<S.dim2(); m++){
			if (S[n][m] == 0){
				S_inv[m][n] = 0;
			} else {
				S_inv[m][n] = 1/S[n][m];
			}
		}
	}

	// Transpose U and V (they are real, so we don't need to take complex conjugates)
	TNT::Array2D<double> Ustar(U.dim2(),U.dim1());
	for (int n=0; n<U.dim1(); n++){
		for (int m=0; m<U.dim2(); m++){
			Ustar[m][n] = U[n][m];
		}
	}

	TNT::Array2D<double> Vstar(V.dim2(),V.dim1());
	for (int n=0; n<V.dim1(); n++){
		for (int m=0; m<V.dim2(); m++){
			Vstar[m][n] = V[n][m];
		}
	}

	// Now calculate the pseudo-inverse of m by m_inv = V*S_inv*Ustar
	TNT::Array2D<double> m_inv(m.dim2(),m.dim1());
	TNT::Array2D<double> S_invUstar(S_inv.dim1(),U.dim1());

	S_invUstar = matmult(S_inv,Ustar);
	m_inv = matmult(V,S_invUstar);

	// Round off m_inv to avoid small-value numerical errors
	for (int p=0; p<m_inv.dim1(); p++){
		for(int q=0; q<m_inv.dim2(); q++){
			m_inv[p][q] = floor(m_inv[p][q]*1000000.0f + 0.5)/1000000.0f;
		}
	}

	// Use the pseudo-inverse to compute the diffusion tensor D
	TNT::Array2D<double> coef(m_inv.dim1(),1);
	TNT::Array2D<double> D(3,3);

	coef = matmult(m_inv,adc);
	D[0][0] = coef[0][0]; D[0][1] = coef[3][0]; D[0][2] = coef[4][0];
	D[1][0] = coef[3][0]; D[1][1] = coef[1][0]; D[1][2] = coef[5][0];
	D[2][0] = coef[4][0]; D[2][1] = coef[5][0]; D[2][2] = coef[2][0];

	// Get the eigenvalues and eigenvectors of the diffusion tensor D
	JAMA::Eigenvalue<double> eig(D);
	TNT::Array1D<double> eigenvalues;
	TNT::Array2D<double> eigenvectors;
	eig.getRealEigenvalues(eigenvalues);
	eig.getV(eigenvectors);

	// l1 to l3 are the largest to the smallest eigenvalues of the diffusion tensor
	float l1 = (float) eigenvalues[2];
	float l2 = (float) eigenvalues[1];
	float l3 = (float) eigenvalues[0];

	// Compute the mean diffusivity, fractional anisotropy and radial diffusivity
	float md = (l1+l2+l3)/3.0f;
	float fa = sqrt(3.0/2.0)*sqrt(pow(l1-md,2)+pow(l2-md,2)+pow(l3-md,2))/sqrt(pow(l1,2)+pow(l2,2)+pow(l3,2));
	float rd = (l2+l3)/2.0f;

	printf("*\n");
	// Compute parameters for plotting ellipsoid if we are looking at total signal
	if (index==0){
		// [ex,ey,ez] is the eigenvector corresponding to the largest eigenvalue (should be pointed in the main diffusion direction)
		ex = (float) eigenvectors[0][2];
		ey = (float) eigenvectors[1][2];
		ez = (float) eigenvectors[2][2];

		printf("Main eigenvector: [%g, %g, %g]\n", ex,ey,ez);


		// Theta is the angle between [ex,ey,ez] and the x-axis
		theta = acos(ex/sqrt(ex*ex+ey*ey+ez*ez))*180/3.1415926535;

		printf("Theta: %g\n", theta);

		// We will plot the ellipsoid with axes ell1, ell2 and ell3, scales by ellipse_scalefactor
		float ellipse_scalefactor = 0.7;
		ell1 = ellipse_scalefactor*1;
		ell2 = ellipse_scalefactor*sqrt(l2/l1);
		ell3 = ellipse_scalefactor*sqrt(l3/l1);

		printf("ell1, ell2, ell3: %g, %g, %g\n", ell1, ell2, ell3);
	}

	// Print out the results
	printf("Eigenvector matrix : \n");
	for (int n=0; n<eigenvectors.dim1(); n++){
		for(int m=0; m<eigenvectors.dim2(); m++){
			printf("%g ",eigenvectors[n][m]);
			eigenvecs[index][n][m] = eigenvectors[n][m];
		}
		printf("\n");
	}

	printf("D = \n");
	for (int n=0; n<3; n++){
		for(int m=0; m<3; m++){
			printf("%g ",D[n][m]);
			tensors[index][n][m] = D[n][m];
		}
		printf("\n");
	}

	printf("l1: %g\n", l1);
	printf("l2: %g\n", l2);
	printf("l3: %g\n", l3);
	printf("md (mean diffusivity): %g\n", md);
	printf("fa (fractional anisotropy): %g\n", fa);
	printf("rd (radial diffusivity): %g\n", rd);
	printf("*\n");
	
	lambdas[index][0] = (float) eigenvalues[0];
	lambdas[index][1] = (float) eigenvalues[1];
	lambdas[index][2] = (float) eigenvalues[2];

	mds[index] = (lambdas[index][0]+lambdas[index][1]+lambdas[index][2])/3.0f;
	fas[index] = sqrt(3.0/2.0)*sqrt(pow(lambdas[index][0]-mds[index],2)+pow(lambdas[index][1]-mds[index],2)+pow(lambdas[index][2]-mds[index],2))/sqrt(pow(lambdas[index][0],2)+pow(lambdas[index][1],2)+pow(lambdas[index][2],2));
	rds[index] = (lambdas[index][0]+lambdas[index][1])/2.0f;

	delete [] gradDir;
	delete [] bVals;
	delete [] logDw;
}