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); } }
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); } } } }
///////////////////////////////////////////////////////////////////////////////////// // 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; }