// Get pressure
// Note this is quite inefficient since operating per-point get same pressure for entire line multiple times
// (GODMARK: no accounting of magnetic field)
void getPressure(FTYPE **yrealpl, FTYPE *P)
{
  int mm;

  // need pressure over full range from -3..3
  for(mm=-interporder[PARAFLAT]/2;mm<=interporder[PARAFLAT]/2;mm++){
    P[mm] = pressure_rho0_u(yrealpl[RHO][mm],yrealpl[UU][mm]);
  }

}
Beispiel #2
0
static int Utoprim_new_body(FTYPE U[NPR], FTYPE gcov[NDIM][NDIM], 
			    FTYPE gcon[NDIM][NDIM], FTYPE gdet,  FTYPE prim[NPR])
{

  FTYPE x_1d[1];
  FTYPE QdotB,Bcon[NDIM],Bcov[NDIM],Qcov[NDIM],Qcon[NDIM],ncov[NDIM],ncon[NDIM],Qsq,Qtcon[NDIM];
  FTYPE rho0,u,p,w,gammasq,gamma,gtmp,W_last,W,utsq,vsq,tmpdiff,aco, bco, cco, pevar, agame, the;
    FTYPE alpha, ucovt, utsqp1;
    FTYPE dummy;


  int    i,j, retval, retval2, i_increase ;


  // Assume ok initially:
  retval = 0 ;

  for(i = BCON1; i <= BCON3; i++) prim[i] = U[i] ;

  // Calculate various scalars (Q.B, Q^2, etc)  from the conserved variables:
  Bcon[0] = 0. ;
  for(i=1;i<4;i++) Bcon[i] = U[BCON1+i-1] ;

  lower_g(Bcon,gcov,Bcov) ;

  for(i=0;i<4;i++) Qcov[i] = U[QCOV0+i] ;
  raise_g(Qcov,gcon,Qcon) ;


  Bsq = 0. ;
  for(i=1;i<4;i++) Bsq += Bcon[i]*Bcov[i] ;

  QdotB = 0. ;
  for(i=0;i<4;i++) QdotB += Qcov[i]*Bcon[i] ;
  QdotBsq = QdotB*QdotB ;

  ncov_calc(gcon,ncov) ;
  raise_g(ncov,gcon,ncon);

  Qdotn = Qcon[0]*ncov[0] ;

  Qsq = 0. ;
  for(i=0;i<4;i++) Qsq += Qcov[i]*Qcon[i] ;

  Qtsq = Qsq + Qdotn*Qdotn ;

  D = U[RHO] ;

  /* calculate W from last timestep and use  for guess */
  utsq = 0. ;
  for(i=1;i<4;i++)
    for(j=1;j<4;j++) utsq += gcov[i][j]*prim[UTCON1+i-1]*prim[UTCON1+j-1] ;


  if( (utsq < 0.) && (fabs(utsq) < 1.0e-13) ) { 
    utsq = fabs(utsq);
  }
  if(utsq < 0. || utsq > UTSQ_TOO_BIG) {
    retval = 2;
    return(retval) ;
  }

  gammasq = 1. + utsq ;
  gamma  = sqrt(gammasq);
	
  // Always calculate rho from D and gamma so that using D in EOS remains consistent
  //   i.e. you don't get positive values for dP/d(vsq) . 
  rho0 = D / gamma ;
  u = prim[UU] ;
  p = pressure_rho0_u(rho0,u) ;
  w = rho0 + u + p ;

  W_last = w*gammasq ;


  // Initialize independent variables for Newton-Raphson:
  x_1d[0] = 1. - 1. / gammasq ; 


  // Find vsq via Newton-Raphson:
  retval = general_newton_raphson( x_1d, 1, func_1d_gnr) ; 

  /* Problem with solver, so return denoting error before doing anything further */
  if( retval != 0 ) { 
    retval = retval*100+1;
    return(retval);
  }

  // Calculate v^2 :
  vsq = x_1d[0];
  if( (vsq >= 1.) || (vsq < 0.) ) {
    retval = 4;
    return(retval) ;
  }

  // Find W from this vsq:
  W = W_of_vsq(vsq, &p, &rho0, &u);


  // Recover the primitive variables from the scalars and conserved variables:
  gtmp = sqrt(1. - vsq);
  gamma = 1./gtmp ;

  w = W * (1. - vsq) ;


  // User may want to handle this case differently, e.g. do NOT return upon 
  // a negative rho/u, calculate v^i so that rho/u can be floored by other routine:
  if( (rho0 <= 0.) || (u <= 0.) ) { 
    retval = 5;
    return(retval) ;
  }

    
    prim[RHO] = rho0 ;
    prim[UU] = u ;
    
  for(i=1;i<4;i++)  Qtcon[i] = Qcon[i] + ncon[i] * Qdotn;
  for(i=1;i<4;i++) prim[UTCON1+i-1] = gamma/(W+Bsq) * ( Qtcon[i] + QdotB*Bcon[i]/W ) ;
	
    
    
  /* set field components */
  for(i = BCON1; i <= BCON3; i++) prim[i] = U[i] ;


  /* done! */
  return(retval) ;
    
}
Beispiel #3
0
static int Utoprim_new_body(FTYPE U[NPR], FTYPE gcov[NDIM][NDIM], 
			    FTYPE gcon[NDIM][NDIM], FTYPE gdet,  FTYPE prim[NPR])
{

  FTYPE x_2d[NEWT_DIM];
  FTYPE QdotB,Bcon[NDIM],Bcov[NDIM],Qcov[NDIM],Qcon[NDIM],ncov[NDIM],ncon[NDIM],Qsq,Qtcon[NDIM];
  FTYPE rho0,u,p,w,gammasq,gamma,gtmp,W_last,W,utsq,vsq,tmpdiff ;
  int i,j, n, retval, i_increase ;

  FTYPE local_Bsq,local_QdotBsq,local_Qtsq,local_Qdotn,local_D ; // added by jdsteve2 for OpenMP

  n = NEWT_DIM ;

  // Assume ok initially:
  retval = 0;

  for(i = BCON1; i <= BCON3; i++) prim[i] = U[i] ;

  // Calculate various scalars (Q.B, Q^2, etc)  from the conserved variables:
  Bcon[0] = 0. ;
  for(i=1;i<4;i++) Bcon[i] = U[BCON1+i-1] ;

  lower_g(Bcon,gcov,Bcov) ;

  for(i=0;i<4;i++) Qcov[i] = U[QCOV0+i] ;
  raise_g(Qcov,gcon,Qcon) ;

  local_Bsq = 0. ;

  for(i=1;i<4;i++) local_Bsq += Bcon[i]*Bcov[i] ;

  QdotB = 0. ; 
  for(i=0;i<4;i++) QdotB += Qcov[i]*Bcon[i] ;

  local_QdotBsq = QdotB*QdotB ;

  ncov_calc(gcon,ncov) ;
  raise_g(ncov,gcon,ncon);

  local_Qdotn = Qcon[0]*ncov[0] ;

  Qsq = 0. ;
  for(i=0;i<4;i++) Qsq += Qcov[i]*Qcon[i] ;

  local_Qtsq = Qsq + local_Qdotn*local_Qdotn ; 
  local_D = U[RHO] ; 

  /* calculate W from last timestep and use for guess */
  utsq = 0. ;
  for(i=1;i<4;i++)
    for(j=1;j<4;j++) utsq += gcov[i][j]*prim[UTCON1+i-1]*prim[UTCON1+j-1] ;

  if( (utsq < 0.) && (fabs(utsq) < 1.0e-13) ) { 
    utsq = fabs(utsq);
  }

  if(utsq < 0. || utsq > UTSQ_TOO_BIG) {
    retval = 2;
    return(retval) ;
  }

  gammasq = 1. + utsq ;
  gamma  = sqrt(gammasq);
	
  // Always calculate rho from D and gamma so that using D in EOS remains consistent
  //   i.e. you don't get positive values for dP/d(vsq) . 
  rho0 = local_D / gamma ;
  u = prim[UU] ;
  p = pressure_rho0_u(rho0,u) ;
  w = rho0 + u + p ;

  W_last = w*gammasq ;

  // Make sure that W is large enough so that v^2 < 1 : 
  i_increase = 0;
  while( (( W_last*W_last*W_last * ( W_last + 2.*local_Bsq ) 
	    - local_QdotBsq*(2.*W_last + local_Bsq) ) <= W_last*W_last*(local_Qtsq-local_Bsq*local_Bsq))
	 && (i_increase < 10) ) {
    W_last *= 10.;
    i_increase++;
  }

  // Calculate W and vsq: 
  x_2d[0] =  fabs( W_last );
  x_2d[1] = x1_of_x0_omp( W_last, local_Bsq, local_QdotBsq, local_Qtsq ) ; // modified by jdsteve2

  retval = general_newton_raphson_omp( x_2d, n, func_vsq_omp, local_Bsq, local_QdotBsq, local_Qtsq, local_Qdotn, local_D) ;  

  W = x_2d[0];
  vsq = x_2d[1];

  /* Problem with solver, so return denoting error before doing anything further */
  if( (retval != 0) || (W == FAIL_VAL) ) {
    retval = retval*100+1;
    return(retval);
  }
  else{
    if(W <= 0. || W > W_TOO_BIG) {
      retval = 3;
      return(retval) ;
    }
  }

  // Calculate v^2:
  if( vsq >= 1. ) {
    retval = 4;
    return(retval) ;
  }

  // Recover the primitive variables from the scalars and conserved variables:
  gtmp = sqrt(1. - vsq);
  gamma = 1./gtmp ;
  rho0 = local_D * gtmp;

  w = W * (1. - vsq) ;
  p = pressure_rho0_w(rho0,w) ;
  u = w - (rho0 + p) ;

  // User may want to handle this case differently, e.g. do NOT return upon 
  // a negative rho/u, calculate v^i so that rho/u can be floored by other routine:
  if( (rho0 <= 0.) || (u <= 0.) ) { 
    retval = 5;
    return(retval) ;
  }

  prim[RHO] = rho0 ;
  prim[UU] = u ;


  for(i=1;i<4;i++)  Qtcon[i] = Qcon[i] + ncon[i] * local_Qdotn;
  for(i=1;i<4;i++) prim[UTCON1+i-1] = gamma/(W+local_Bsq) * ( Qtcon[i] + QdotB*Bcon[i]/W ) ;
	
  /* set field components */
  for(i = BCON1; i <= BCON3; i++) prim[i] = U[i] ;

  /* done! */

  return(retval) ;

}
Beispiel #4
0
int dump_content(int i, int j, int k, MPI_Datatype datatype,void *writebuf)
{
  int pl;
  FTYPE r, th, vmin[NDIM], vmax[NDIM];
  int ignorecourant;
  struct of_geom geom;
  struct of_state q;
  FTYPE X[NDIM],V[NDIM];
  FTYPE divb;
  FTYPE b[NDIM],ucon[NDIM];
  FTYPE U[NPR];
  FTYPE ftemp;
  FTYPE jcov[NDIM];
  FTYPE fcov[NUMFARADAY];
  FTYPE rho,u,pressure,cs2,Sden;
  int dir,l,m,n,o;


  //////////////
  //
  // some calculations
  //

  coord(i, j, k, CENT, X);
  bl_coord(X, V);
  // if failed, then data output for below invalid, but columns still must exist    

  get_geometry(i, j, k, CENT, &geom);

  if (!failed) {
    if (get_state(pdump[i][j][k], &geom, &q) >= 1)
      FAILSTATEMENT("dump.c:dump()", "get_state() dir=0", 1);
    if (vchar(pdump[i][j][k], &q, 1, &geom, &vmax[1], &vmin[1],&ignorecourant) >= 1)
      FAILSTATEMENT("dump.c:dump()", "vchar() dir=1or2", 1);
    if (vchar(pdump[i][j][k], &q, 2, &geom, &vmax[2], &vmin[2],&ignorecourant) >= 1)
      FAILSTATEMENT("dump.c:dump()", "vchar() dir=1or2", 2);
    if (vchar(pdump[i][j][k], &q, 3, &geom, &vmax[3], &vmin[3],&ignorecourant) >= 1)
      FAILSTATEMENT("dump.c:dump()", "vchar() dir=1or2", 3);
  }
  else {// do a per zone check, otherwise set to 0
    whocalleducon=1; // force no failure mode, just return like failure, and don't return if failure, just set to 0 and continue
    if (get_state(pdump[i][j][k], &geom, &q) >= 1){
      for (pl = 0; pl < NDIM; pl++)
	q.ucon[pl]=0;
      for (pl = 0; pl < NDIM; pl++)
	q.ucov[pl]=0;
      for (pl = 0; pl < NDIM; pl++)
	q.bcon[pl]=0;
      for (pl = 0; pl < NDIM; pl++)
	q.bcov[pl]=0;
    }
    if (vchar(pdump[i][j][k], &q, 1, &geom, &vmax[1], &vmin[1],&ignorecourant) >= 1){
      vmax[1]=vmin[1]=0;
    }
    
    if (vchar(pdump[i][j][k], &q, 2, &geom, &vmax[2], &vmin[2],&ignorecourant) >= 1){
      vmax[2]=vmin[2]=0;
    }

    if (vchar(pdump[i][j][k], &q, 3, &geom, &vmax[3], &vmin[3],&ignorecourant) >= 1){
      vmax[3]=vmin[3]=0;
    }

    whocalleducon=0; // return to normal state
    
  }


  setfdivb(&divb, pdump, udump, i, j, k); // udump also set externally GODMARK

  //////////////////////////
  //
  // do the assignments
  //
  // if you change # of outputted vars, remember to change numcolumns


  //static
  if(!GAMMIEDUMP){
    ftemp=(FTYPE)(i+startpos[1]);
    myset(datatype,&ftemp,0,1,writebuf);
    ftemp=(FTYPE)(j+startpos[2]);
    myset(datatype,&ftemp,0,1,writebuf);
    ftemp=(FTYPE)(k+startpos[3]);
    myset(datatype,&ftemp,0,1,writebuf);
  }
  myset(datatype,X,1,3,writebuf);
  myset(datatype,V,1,3,writebuf);
  // 9

  ////////////////////////
  //
  // rest dynamic

  // primitives
  // must use PDUMPLOOP() since may be any order unlike NPR loop
  PDUMPLOOP(pl) myset(datatype,&(pdump[i][j][k][pl]),0,1,writebuf); // NPRDUMP

  ////////////
  //
  // output some EOS stuff since in general not simple function of rho0,u
  rho = pdump[i][j][k][RHO];
  u = pdump[i][j][k][UU];


  pressure = pressure_rho0_u(rho,u);
  cs2 = cs2_compute(rho,u);
  Sden = compute_entropy(rho,u);
  //  dUdtau = compute_qdot(rho,u);
  
  myset(datatype,&pressure,0,1,writebuf); // 1
  myset(datatype,&cs2,0,1,writebuf); // 1
  myset(datatype,&Sden,0,1,writebuf); // 1
  //  myset(datatype,&dUdtau,0,1,writebuf); // 1

  //////////////////////
  //
  // output the conserved quantities since not easily inverted and at higher order aren't invertable from point primitives
  PDUMPLOOP(pl) myset(datatype,&(udump[i][j][k][pl]),0,1,writebuf); // NPRDUMP
  myset(datatype,&divb,0,1,writebuf); // 1

  for (pl = 0; pl < NDIM; pl++)
    myset(datatype,&(q.ucon[pl]),0,1,writebuf);
  for (pl = 0; pl < NDIM; pl++)
    myset(datatype,&(q.ucov[pl]),0,1,writebuf);
  for (pl = 0; pl < NDIM; pl++)
    myset(datatype,&(q.bcon[pl]),0,1,writebuf);
  for (pl = 0; pl < NDIM; pl++)
    myset(datatype,&(q.bcov[pl]),0,1,writebuf);
  // 4*4
    
  myset(datatype,&vmin[1],0,1,writebuf);
  myset(datatype,&vmax[1],0,1,writebuf);
  myset(datatype,&vmin[2],0,1,writebuf);
  myset(datatype,&vmax[2],0,1,writebuf);
  myset(datatype,&vmin[3],0,1,writebuf);
  myset(datatype,&vmax[3],0,1,writebuf);
  // 6

  // one static term
  myset(datatype,&geom.g,0,1,writebuf); // 1


#if(CALCFARADAYANDCURRENTS) // NIM*2+6*2 = 8+12=20
  // updated 11/16/2003
  // new 10/23/2003
  // current density 
  lower_vec(jcon[i][j][k],&geom,jcov); 
  myset(datatype,jcon[i][j][k],0,NDIM,writebuf); // (NDIM)
  myset(datatype,jcov,0,NDIM,writebuf);// (NDIM)
  // faraday (2*6)
  lowerf(fcon[i][j][k],&geom,fcov);
  myset(datatype,fcon[i][j][k],0,NUMFARADAY,writebuf); //  (6)
  myset(datatype,fcov,0,NUMFARADAY,writebuf); // (6)
#endif

  if(FLUXB==FLUXCTSTAG && 0){ // DEBUG (change corresponding code in dump.c)
    // uses jrdp3dudebug in gtwod.m that assumes CALCFARADAYANDCURRENTS==0
    for(l=1;l<=COMPDIM;l++) myset(datatype,gp_l[l][i][j][k],0,NPR2INTERP,writebuf); // 3*8 = 24
    for(l=1;l<=COMPDIM;l++) myset(datatype,gp_r[l][i][j][k],0,NPR2INTERP,writebuf); // 3*8 = 24
    myset(datatype,pstagscratch[i][j][k],0,NPR,writebuf); // 8
    for(dir=1;dir<=COMPDIM;dir++) for(pl=B1;pl<=B3;pl++) for(n=0;n<=1;n++) myset(datatype,&pbcorninterp[dir][pl][n][i][j][k],0,1,writebuf); // 3*3*2 = 18
    for(dir=1;dir<=COMPDIM;dir++) for(pl=U1;pl<=U3;pl++) for(n=0;n<=1;n++) for(o=0;o<=1;o++) myset(datatype,&pvcorninterp[dir][pl][n][o][i][j][k],0,1,writebuf); // 3*3*2*2 = 36
  }

  return (0);
}
/* pr *MUST* contain initial guess */
int Utoprim(int whichcons, FTYPE *U, struct of_geom *ptrgeom, PFTYPE *lpflag, FTYPE *pr, FTYPE *pressure, struct of_newtonstats *newtonstats)
{
  FTYPE U_target[NPR];
  FTYPE pr0[NPR];
  int numnormterms;
  int primtoUcons;
  //
  FTYPE priter[NPR];
  FTYPE prguess[NPR];
  FTYPE tolx, tolf,tolxallowed, tolfallowed, tolxreport, tolfreport;
  int ntrial, mnewtfailed,mintrial;
  int pl,pliter;
  FTYPE Ustart[NPR];
  FTYPE dU[NPR];
  struct of_state q;
  int i,j,k,loc;
  int nutoprims,countutoprims;
  FTYPE frac,SUPERFRAC;
  int faildebug1(int numnormterms, int whichcons, FTYPE *U_target, FTYPE *EOSextra, FTYPE *pr0, struct of_geom *ptrgeom);
  int faildebug2(int numnormterms, int whichcons, FTYPE *U_target, FTYPE *EOSextra, FTYPE *pr0, struct of_geom *ptrgeom);
  void fixUtarget(int which,FTYPE *Ui,FTYPE *Uf);
  extern int mnewt(FTYPE *U_target,FTYPE *pr0,int numnormterms,int whichcons, int primtoUcons, struct of_geom *ptrgeom, int whethertoreport,int ntrial, int mintrial, FTYPE x[], int n, int startp, FTYPE tolx, FTYPE tolf, FTYPE tolxallowed, FTYPE tolfallowed, FTYPE tolxreport, FTYPE tolfreport, struct of_newtonstats *newtonstats);
  int usrfun(FTYPE *U_target,FTYPE *pr0,int numnormterms,int whichcons, int primtoUcons, struct of_geom *ptrgeom, FTYPE *prguess, int n, FTYPE *beta, FTYPE **alpha,FTYPE*norm);
  int Utoprim_nonrel(FTYPE *U, struct of_geom *ptrgeom, FTYPE *pr);
  FTYPE prnonrel[NPR];
  FTYPE prrel[NPR];
  int flagifnonrel;
  int whethertoreport;
  FTYPE bsq;
  int entropyversion;


  i=ptrgeom->i;
  j=ptrgeom->j;
  k=ptrgeom->k;
  loc=ptrgeom->p;


#if(EOMTYPE==EOMGRMHD||EOMTYPE==EOMENTROPYGRMHD)
#define INVERTNPR (5) // always same
#define STARTPINVERT (RHO) // where to start in primitive space
#elif(EOMTYPE==EOMCOLDGRMHD)
#define INVERTNPR (4) // always same
#define STARTPINVERT (RHO) // where to start in primitive space
  // need to skip UU if using this (SUPERGODMARK -- not done yet)
#elif(EOMTYPE==EOMFFDE)
#define INVERTNPR (3) // always same
#define STARTPINVERT (U1) // where to start in primitive space
#endif



  *lpflag= UTOPRIMNOFAIL; // set as no failure at first
  // assume normally do not want special messages
  whethertoreport=0;


  /////////////
  //
  // check (disabled since should allow negative density so RK can recover)
  //
  ////////////
  if(0&&( (EOMTYPE==EOMGRMHD||EOMTYPE==EOMENTROPYGRMHD)||(EOMTYPE==EOMCOLDGRMHD) )){ // don't check for now, just fail later
    if (U[RHO] < 0.) {
      if (fail(i,j,k,loc,FAIL_UTOPRIM_NEG) >= 1)
        return (1);
    }
  }
  
  ////////////////
  //
  // evolve B before (also better than initial guess)
  /* solution is known for B, so best guess is solution (from point of view of other variables) */
  //
  ///////////////
  for (pl = B1; pl <= B3; pl++) pr[pl] = U[pl];




  //////////////////////
  //
  // rest determines rho,u,u^i for GRMHD or u^i for FFDE
  //


#if(PRECISEINVERSION)
  ntrial = 200;
  mintrial = 3;
  tolx = tolf = 1.e-11; // 1E-11 is best mnewt() can do with DODAMP=2
  tolxallowed = tolfallowed = 1.e-8 ;
  tolxreport=1.e4*tolx;
  tolfreport=1.e4*tolf;
  
#else
  // choice
  ntrial = 20;
  mintrial=2;
  tolx = 1.e-10;
  tolf = 1.e-10;
  tolxallowed=tolfallowed=1.e-4;
  tolxreport=1.e3*tolx;
  tolfreport=1.e3*tolf;
#endif



  /////////////
  //
  // Setup inversion
  //
  ////////////


  // store initial guess and U as target
  PLOOP(pliter,pl) pr0[pl]=priter[pl]=pr[pl];


  entropyversion=0;

#if(EOMTYPE==EOMGRMHD||EOMTYPE==EOMENTROPYGRMHD)
  PLOOP(pliter,pl) U_target[pl] = U[pl];

  //#define NORMMETHOD (-1)
#define NORMMETHOD (1)
  // -1: no normalization
  // 0=use Utarget[RHO]
  // 1=use generaleralized mean so matrix stays well conditioned

  // assume normally want special messages
  whethertoreport=1;
  entropyversion=0;

  if((whichcons==EVOLVENOENTROPY)||(whichcons==EVOLVESIMPLEENTROPY)){
    primtoUcons=UNOTHING;
    // normal total energy inversion
    // if evolvesimpleentropy, then just invert in utoprim() after mnewt succeeds
  }
  else if(whichcons==EVOLVEFULLENTROPY){
    entropyversion=1;
    primtoUcons=UENTROPY; // implicit UNOTHING with entropy cons. quant. assigned to UU cons. quant.
    // overwrite total energy EOM with entropy EOM
    U_target[UU]=U_target[ENTROPY];
    // assumes dudp_calc replaces total energy equation with entropy equation

#if(ENTROPY==-100)
    dualfprintf(fail_file,"Should not be here in utoprim() ENTROPY variable defined\n");
    myexit(2486726);
#endif

  }


#if(1)
  // No, now further assume if not getting inversion within short trials, not going to happen and reduces to other method for "inversion"
  // No, now assuming want accurate dissipation tracking and avoidance of problems in strong shocks
  // assume don't want special messages if just using entropy evolution for comparison and not primary evolution
  if(whichcons==EVOLVEFULLENTROPY){
    whethertoreport=0;
    // then simplify inversion a bit
    ntrial = 20;
    mintrial=2;
    tolx = 1.e-6;
    tolf = 1.e-6;
    tolxallowed=tolfallowed=1.e-4;
    tolxreport=1.e3*tolx;
    tolfreport=1.e3*tolf;
  }
#endif


#elif(EOMTYPE==EOMCOLDGRMHD)

  // SUPERGODMARK: Not done yet

#define NORMMETHOD (1)  // no choice
#define WHICHFFDEINVERSION 0 // choice (see below)

  primtoUcons=UNOTHING;

  fixUtarget(WHICHFFDEINVERSION,U,U_target);

  // zero internal energy density so can use standard dU/dp
  priter[UU]=0;

#elif(EOMTYPE==EOMFFDE)

#define NORMMETHOD (1)  // no choice
#define WHICHFFDEINVERSION 0 // choice (see below)

  primtoUcons=UNOTHING;

  fixUtarget(WHICHFFDEINVERSION,U,U_target);

  // zero densities so can use standard dU/dp
  priter[RHO]=priter[UU]=0;

#endif










  /////////////
  //
  // checks if initial pr gives good u^t and determines U(pr)
  //
  ////////////

  if (get_state(pr, ptrgeom, &q) >= 1){
    //    dualfprintf(fail_file,"bad guess: i=%d j=%d k=%d\n",ptrgeom->i,ptrgeom->j,ptrgeom->k);
    //    PLOOP(pliter,pl) dualfprintf(fail_file,"bad guess: pr=%21.15g\n",pr[pl]);
    // then guess bad, adjust guess
    set_atmosphere(0,WHICHVEL,ptrgeom,prguess);
    for(pl=U1;pl<=U3;pl++) pr[pl]=prguess[pl]; // only reset velocities
    // try again
    if (get_state(pr, ptrgeom, &q) >= 1)
      FAILSTATEMENT("utoprim.c:utoprim()", "get_state()", 1);
    //    PLOOP(pliter,pl) dualfprintf(fail_file,"good guess: pr=%21.15g\n",pr[pl]);
  }
  if (primtoU(primtoUcons,pr, &q, ptrgeom, Ustart) >= 1)
    FAILSTATEMENT("utoprim.c:utoprim()", "primtoU()", 1);
  // now we have U(pr)



  // only try non-rel inversion if normal inversion (not entropy-based since not setup)
  ////////////////////
  //
  // if u^t=1, then can do non-relativistic inversion
  //
  ////////////////////

  flagifnonrel=0;

#define DONONRELINV 1

  if(entropyversion==0){


#if(DONONRELINV&&( (EOMTYPE==EOMGRMHD||EOMTYPE==EOMENTROPYGRMHD)||(EOMTYPE==EOMCOLDGRMHD) ) )

    // get b^2 to check if b^2/rho_0<<1
    bsq = dot(q.bcon, q.bcov);

    flagifnonrel=0;
    if(
       (fabs(q.ucon[TT]-1.0)*fabs(q.ucon[TT]-1.0)<NUMEPSILON*5.0)
       ||(fabs(bsq/(SMALL+fabs(pr[RHO])))<NUMEPSILON*5.0)
       ||(fabs(fabs(pr[UU])/(SMALL+fabs(pr[RHO])))<NUMEPSILON*5.0)
       ){
      flagifnonrel=1;

      if(Utoprim_nonrel(U_target,ptrgeom,pr)>0){
        *lpflag= UTOPRIMFAILRHONEG;
        flagifnonrel=0; //then can't trust non-rel inversion
      }
      else{
    
        // report if failure.  Only negative densities can occur with non-relativistic inversion
        if((pr[RHO]<=0.)&&(pr[UU]>=0.)) *lpflag= UTOPRIMFAILRHONEG;
        if((pr[RHO]>=0.)&&(pr[UU]<=0.)) *lpflag= UTOPRIMFAILUNEG;
        if((pr[RHO]<=0.)&&(pr[UU]<=0.)) *lpflag= UTOPRIMFAILRHOUNEG;

        if(IFUTOPRIMNOFAILORFIXED(*lpflag)){
          //    PLOOP(pliter,pl) dualfprintf(fail_file,"U[%d]=%21.15g pr0[%d]=%21.15g pr[%d]=%21.15g\n",pl,U_target[pl],pl,pr0[pl],pl,pr[pl]);
        }
        PLOOP(pliter,pl) prnonrel[pl]=pr[pl];
      
        /////////////
        //
        // checks if initial pr gives good u^t and determines U(pr)
        //
        ////////////
        if (get_state(pr, ptrgeom, &q) >= 1)
          FAILSTATEMENT("utoprim.c:utoprim()", "get_state()", 1);
        if(fabs(q.ucon[TT]-1.0)>NUMEPSILON*5.0) flagifnonrel=0;
      }
    }
    else{
      flagifnonrel=0;
      PLOOP(pliter,pl) prnonrel[pl]=-1.0;
    }
#else
    flagifnonrel=0;
    PLOOP(pliter,pl) prnonrel[pl]=-1.0;
#endif

    //  dualfprintf(fail_file,"uu0diff1=%21.15g flagifnonrel=%d\n",fabs(q.ucon[TT]-1.0),flagifnonrel);
  } // end if not doing entropy inversion
  else{
    flagifnonrel=0;
    PLOOP(pliter,pl) prnonrel[pl]=-1.0;
  }












  if(flagifnonrel==0){
    //////////////////
    //
    // setup mnewt
    //
    //////////////////
    mnewtfailed=1; // assume failed
    nutoprims=1; // >1 usually, but 1 means directly to static if failed (with one chance for SUPERFRAC)
    countutoprims=nutoprims;
    frac=1.0/((FTYPE)nutoprims); // so that by nutoprims adjustments we are back at U_target=Ustart
    SUPERFRAC=0.0001;
    PLOOP(pliter,pl) dU[pl]=U_target[pl]-Ustart[pl];


    //  PLOOP(pliter,pl) dualfprintf(fail_file,"IN: i=%d j=%d k=%d :: pr0[%d]=%21.15g U[%d]=%21.15g\n",ptrgeom->i,ptrgeom->j,ptrgeom->k,pl,pr0[pl],pl,U_target[pl]);
    //////////////////
    //
    // mnewt (loop)
    //
    //////////////////
    while(mnewtfailed){
      if(mnewtfailed){
        if(countutoprims==-1){
          // forced to use static solution. Probably better ways than a
          // linear approx, but better than nothing.  Must improve flux,
          // or lower courant factor to otherwise improve this situation
          break;
        }
        if(countutoprims==0){
          // force to be nearly identical instead of exactly identical, last hope!
          PLOOP(pliter,pl) U_target[pl]=Ustart[pl]+dU[pl]*SUPERFRAC;
        }
        else{
          // Only failed because U_target is trying to send u^t to imaginary values, or densities to negative values
          // try backup up towards original solution in conservative variable space
          PLOOP(pliter,pl) U_target[pl]=Ustart[pl]+dU[pl]*(FTYPE)countutoprims*frac;
        }
      }

      // mnewt is set to only take 5 entries and deal with pl=0-4 in the inversion.
      //
      // notice that priter is used.  Assumes setup Utarget to be consistent with priter and INVERTNPR
      //
      mnewtfailed = mnewt(U_target, pr0, numnormterms, whichcons, primtoUcons, ptrgeom, whethertoreport,ntrial, mintrial, priter - 1, INVERTNPR , STARTPINVERT, tolx, tolf, tolxallowed, tolfallowed, tolxreport, tolfreport,newtonstats);



      if(mnewtfailed) countutoprims--;
      if(nutoprims==1){
        break; // if failed, static immediately if failure since apparently goes that way anyways
        // if good, then break cause we are done
      }

    }

    /////////////////////
    //
    // convert the priter->pr
    //
    /////////////////////
    PLOOP(pliter,pl) prrel[pl]=priter[pl];


  }
  else{
    mnewtfailed=0; // don't trigger debug stuff for mnewt if not using it
    PLOOP(pliter,pl) prrel[pl]=-1;
  }



  /////////////////////
  //
  // ASSIGN ANSWER from mnewt or non-rel inversion
  //
  /////////////////////

#if(EOMTYPE==EOMGRMHD||EOMTYPE==EOMENTROPYGRMHD || EOMTYPE==EOMCOLDGRMHD)



#if(0)
  //  PLOOP(pliter,pl)  dualfprintf(fail_file,"%ld %d %d inversions prnonrel[%d]=%21.15g prrel[%d]=%21.15g\n",nstep,steppart,ptrgeom->i,pl,prnonrel[pl],pl,prrel[pl]);
  //  if(flagifnonrel)  PLOOP(pliter,pl)  if(fabs(prnonrel[pl]-prrel[pl])>0.0) dualfprintf(fail_file,"%ld %d %d inversions prnonrel[%d]=%21.15g prrel[%d]=%21.15g diff=%21.15g\n",nstep,steppart,ptrgeom->i,pl,prnonrel[pl],pl,prrel[pl],prnonrel[pl]-prrel[pl]);
  if(flagifnonrel)  PLOOP(pliter,pl)  if(fabs(prnonrel[pl]-prrel[pl])/fabs(fabs(prnonrel[pl])+fabs(prrel[pl])+SMALL)>0.0) dualfprintf(fail_file,"%ld %d %d inversions prnonrel[%d]=%21.15g prrel[%d]=%21.15g diff=%21.15g\n",nstep,steppart,ptrgeom->i,pl,prnonrel[pl],pl,prrel[pl],prnonrel[pl]-prrel[pl]);
#endif

  // default is to use nonrel if was good solution
  if(flagifnonrel)  PLOOP(pliter,pl) pr[pl]=prnonrel[pl];
  else PLOOP(pliter,pl) pr[pl]=prrel[pl];

#elif(EOMTYPE==EOMFFDE)
  // v^i
  // don't overwrite rest
  pr[U1]=prrel[U1];
  pr[U2]=prrel[U2];
  pr[U3]=prrel[U3];
#endif


  if(whichcons==EVOLVEFULLENTROPY){
    // in case user wants internal energy from entropy evolution in pr[ENTROPY]
    pr[ENTROPY]=pr[UU];
  }



  //////////////////
  //
  // check if mnewt failed or got negative densities
  //
  //////////////////
  if(mnewtfailed){



    //    PLOOP(pliter,pl) dualfprintf(fail_file,"U_target[%d]=%21.15g\n",pl,U_target[pl]);



    // reset to initial pr since new pr is bad
    PLOOP(pliter,pl) pr[pl]=pr0[pl];

    // report failure
    *lpflag= UTOPRIMFAILCONV;

    // then old p should be new p, do nothing since initial guess must be final solution
    if(whethertoreport && debugfail>=1) dualfprintf(fail_file,"static solution at t=%21.15g step=%ld i=%d j=%d k=%d wtf=%d\n",t,realnstep,ptrgeom->i,ptrgeom->j,ptrgeom->k,debugfail);

    // no need to continue unless want debug info, then pflag is messed up
    return(0); 
    // remove above return if want to get debug below
  }// otherwise got good solution
  else{
    // check densities for positivity
    if( ( (EOMTYPE==EOMGRMHD||EOMTYPE==EOMENTROPYGRMHD)||(EOMTYPE==EOMCOLDGRMHD))&&((pr[RHO]<0.0)||(pr[UU]<0.0))){
      // it doesn't seem reasonable to just "fix" negative densities since they could be arbitrarily negative and the other primitive variables depend on the negativity of the density which is unphysical.  So we fail if negative.  Could fail for a lower threshold on density than the floor to avoid those numbers as well.
      if((pr[RHO]<=0.)&&(pr[UU]>=0.)) *lpflag= UTOPRIMFAILRHONEG;
      if((pr[RHO]>=0.)&&(pr[UU]<=0.)) *lpflag= UTOPRIMFAILUNEG;
      if((pr[RHO]<=0.)&&(pr[UU]<=0.)) *lpflag= UTOPRIMFAILRHOUNEG;

      // mostly we hit pr[UU]<0, or maybe never pr[RHO]<0 and pr[UU]<0 alot
      if(debugfail>=2) dualfprintf(fail_file,"utoprim found negative density: t=%21.15g step=%ld i=%d j=%d k=%d %21.15g %21.15g\n",t,realnstep,ptrgeom->i,ptrgeom->j,ptrgeom->k,pr[RHO],pr[UU]);
      return(0);
    }
  }



  ////////////////////
  //
  // make sure solution is valid
  //
  ////////////////////
#if(WHICHVEL==VEL3)
  // this is just a check, fixup() will soon do both in step_ch.c

  // currently need to check this since last iteration may lead to bad pr
  if(jonchecks) fixup1zone(pr,ptrgeom,0); // actually this is done in a general fixup call soon after this point in step_ch.c
  // check and see if u^t is actually a good solution now we think we have the solution? or fix it if u^t is bad
  if(jonchecks) if(check_pr(pr,pr0,ptrgeom,0)>=1)
                  FAILSTATEMENT("utoprim.c:Utoprim()", "mnewt check:check_pr()", 1);
#endif



  ////////////////////
  //
  // determine entropy inversion if not doing full entropy evolution
  //
  ///////////////////

  if(whichcons==EVOLVESIMPLEENTROPY){
    // if evolvesimpleentropy, then just invert in utoprim() after mnewt succeeds
    if (get_state(pr, ptrgeom, &q) >= 1) FAILSTATEMENT("utoprim.c:utoprim()", "get_state()", 2);
    invertentropyflux_calc(ptrgeom,U_target[ENTROPY],0,&q,pr);// doesn't use pr[UU], but uses rest of updated primitives
    
  }// otherwise no entropy evolution or direct full entropy evolution




  /////////////////////////////
  //
  // debug stuff
  // don't fail anymore even if failed-static solution
  //
  /////////////////////////////
  if ((debugfail>=2)&&(mnewtfailed >= 1)) {

    //    faildebug1(numnormterms,whichcons,U_target,GLOBALMAC(EOSextraglobal,i,j,k),pr0,ptrgeom);
    faildebug2(numnormterms,whichcons,U_target,GLOBALMAC(EOSextraglobal,i,j,k),pr0,ptrgeom);

    if (fail(i,j,k,loc,FAIL_UTOPRIM_TEST) >= 1)
      return (1);

    
    if(!jonchecks){
      if (fail(i,j,k,loc,FAIL_UTOPRIM_TEST) >= 1)
        return (1);
    }
  }



  *pressure=pressure_rho0_u(WHICHEOS,GLOBALMAC(EOSextraglobal,i,j,k),pr[RHO],pr[UU]);



  ////////////////////
  //
  // otherwise just safely fail or succeed
  //
  ////////////////////
  *lpflag = UTOPRIMNOFAIL;
  return (0);


}
static int Utoprim_new_body( FTYPE U[NPR], FTYPE gcov[NDIM][NDIM], 
			     FTYPE gcon[NDIM][NDIM], FTYPE gdet,  FTYPE prim[NPR])
{
  static void func_1d_dbl( FTYPE x[], FTYPE dx[], FTYPE resid[], 
			   FTYPE jac[][NEWT_DIM], FTYPE *f, FTYPE *df, int n);
  
  static int general_newton_raphson( FTYPE x[], int n, 
				     void (*funcd) (FTYPE [], FTYPE [], 
						    FTYPE [], FTYPE [][NEWT_DIM], 
						    FTYPE *, FTYPE *, int) );

  FTYPE x_1d[1];
  FTYPE QdotB,Bcon[NDIM],Bcov[NDIM],Qcov[NDIM],Qcon[NDIM],ncov[NDIM],ncon[NDIM],Qsq,Qtcon[NDIM];
  FTYPE rho0,u,p,w,gammasq,gamma,gtmp,W_last,W,utsq,vsq,tmpdiff ;
  int i,j, retval, i_increase ;

  // Assume ok initially:
  retval = 0;

  for(i = BCON1; i <= BCON3; i++) prim[i] = U[i] ;

  // Calculate various scalars (Q.B, Q^2, etc)  from the conserved variables:
  Bcon[0] = 0. ;
  for(i=1;i<4;i++) Bcon[i] = U[BCON1+i-1] ;

  lower_g(Bcon,gcov,Bcov) ;

  for(i=0;i<4;i++) Qcov[i] = U[QCOV0+i] ;
  raise_g(Qcov,gcon,Qcon) ;

  Bsq = 0. ;
  for(i=1;i<4;i++) Bsq += Bcon[i]*Bcov[i] ;

  QdotB = 0. ;
  for(i=0;i<4;i++) QdotB += Qcov[i]*Bcon[i] ;
  QdotBsq = QdotB*QdotB ;

  ncov_calc(gcon,ncov) ;
  raise_g(ncov,gcon,ncon);

  Qdotn = Qcon[0]*ncov[0] ;

  Qsq = 0. ;
  for(i=0;i<4;i++) Qsq += Qcov[i]*Qcon[i] ;

  Qtsq = Qsq + Qdotn*Qdotn ;

  D = Dc = U[RHO] ;
  Ec = -Qdotn;
  Ssq = QdotBsq;
  igam1 = (GAMMA - 1.)/GAMMA ;

  /* calculate W from last timestep and use for guess */
  utsq = 0. ;
  for(i=1;i<4;i++)
    for(j=1;j<4;j++) utsq += gcov[i][j]*prim[UTCON1+i-1]*prim[UTCON1+j-1] ;


  if( (utsq < 0.) && (fabs(utsq) < 1.0e-13) ) { 
    utsq = fabs(utsq);
  }
  if(utsq < 0. || utsq > UTSQ_TOO_BIG) {
    retval = 2;
    return(retval) ;
  }

  gammasq = 1. + utsq ;
  gamma  = sqrt(gammasq);
	
  // Always calculate rho from D and gamma so that using D in EOS remains consistent
  //   i.e. you don't get positive values for dP/d(vsq) . 
  rho0 = D / gamma ;
  u = prim[UU] ;
  p = pressure_rho0_u(rho0,u) ;
  w = rho0 + u + p ;

  W_last = w*gammasq ;


  // Make sure that W is large enough so that v^2 < 1 : 
  i_increase = 0;
  while( (( W_last*W_last*W_last * ( W_last + 2.*Bsq ) 
	    - QdotBsq*(2.*W_last + Bsq) ) <= W_last*W_last*(Qtsq-Bsq*Bsq))
	 && (i_increase < 10) ) {
    W_last *= 10.;
    i_increase++;
  }
  
  // METHOD specific:
  Wc = W_last;
  x_1d[0] = 1. - 1. / gammasq ; 

  // Find vsq : 
  retval = general_newton_raphson( x_1d, 1, func_1d_dbl ) ; 

  // Find W from this vsq:
  vsq = x_1d[0] ; 
  W = Wc;


  /* Problem with solver, so return denoting error before doing anything further */
  if( (retval != 0) || (W == FAIL_VAL) ) {
    retval = retval*100+1;
    return(retval);
  }
  else{
    if(W <= 0. || W > W_TOO_BIG) {
      retval = 3;
      return(retval) ;
    }
  }


  // Calculate utsq
  // calculated from above:
  if( vsq >= 1. ) {
    retval = 4;
    return(retval) ;
  }

  // Recover the primitive variables from the scalars and conserved variables:
  gtmp = sqrt(1. - vsq);
  gamma = 1./gtmp ;
  rho0 = D * gtmp;

  w = W * (1. - vsq) ;
  p = pressure_rho0_w(rho0,w) ;
  u = w - (rho0 + p) ;

  // User may want to handle this case differently, e.g. do NOT return upon 
  // a negative rho/u, calculate v^i so that rho/u can be floored by other routine:
  if( (rho0 <= 0.) || (u <= 0.) ) { 
    retval = 5;
    return(retval) ;
  }

  prim[RHO] = rho0 ;
  prim[UU] = u ;


  for(i=1;i<4;i++)  Qtcon[i] = Qcon[i] + ncon[i] * Qdotn;
  for(i=1;i<4;i++) prim[UTCON1+i-1] = gamma/(W+Bsq) * ( Qtcon[i] + QdotB*Bcon[i]/W ) ;
	
  /* set field components */
  for(i = BCON1; i <= BCON3; i++) prim[i] = U[i] ;


  /* done! */
  return(retval) ;

}
static int Utoprim_new_body(FTYPE U[NPR], struct of_geom *ptrgeom,  FTYPE prim[NPR])
{
  FTYPE Wtest;

  FTYPE x_1d[1];
  FTYPE QdotB,Bcon[4],Bcov[4],Qcov[4],Qcon[4],ncov[4],ncon[4],Qsq,Qtcon[4];
  FTYPE rho0,u,p,w,gammasq,gamma,gtmp,W_last,W,utsq,vsq,tmpdiff ;
  int i,j, retval, retval2, i_increase ;
   
  static void raise_g(FTYPE vcov[], FTYPE gcon[][4], FTYPE vcon[]);
  static void lower_g(FTYPE vcon[], FTYPE gcov[][4], FTYPE vcov[]);
  static void ncov_calc(FTYPE gcon[][4],FTYPE ncov[]) ;
  static FTYPE pressure_rho0_u(FTYPE rho0, FTYPE u);
  static FTYPE pressure_rho0_w(FTYPE rho0, FTYPE w);


  static int find_root_2D_gen(FTYPE x0, FTYPE *xnew) ;

  const int ltrace = 0;
  const int ltrace2 = 0;

  /* TEMPORARY */
  /*
    primtoU_g(prim,gcov,gcon,U) ;
  */

#if(!OPTIMIZED)
  if( ltrace ) {
    for(i=0;i<8;i++) dualfprintf(fail_file,"%d %21.15g %21.15g\n",i,prim[i],U[i]) ;
    
  }
#endif
  // Assume ok initially:
  pflag[ptrgeom->i][ptrgeom->j][FLAGUTOPRIMFAIL]= UTOPRIMNOFAIL;

  for(i = BCON1; i <= BCON3; i++) prim[i] = U[i] ;

  Bcon[0] = 0. ;
  for(i=1;i<4;i++) Bcon[i] = U[BCON1+i-1] ;

  lower_g(Bcon,ptrgeom->gcov,Bcov) ;

  for(i=0;i<4;i++) Qcov[i] = U[QCOV0+i] ;
  raise_g(Qcov,ptrgeom->gcon,Qcon) ;


  Bsq = 0. ;
  for(i=1;i<4;i++) Bsq += Bcon[i]*Bcov[i] ;

  QdotB = 0. ;
  for(i=0;i<4;i++) QdotB += Qcov[i]*Bcon[i] ;
  QdotBsq = QdotB*QdotB ;

  ncov_calc(ptrgeom->gcon,ncov) ;
  raise_g(ncov,ptrgeom->gcon,ncon);

  Qdotn = Qcon[0]*ncov[0] ;

  Qsq = 0. ;
  for(i=0;i<4;i++) Qsq += Qcov[i]*Qcon[i] ;

  Qtsq = Qsq + Qdotn*Qdotn ;

  D = U[RHO] ;

  /* calculate W from last timestep and use 
     for guess */
  utsq = 0. ;
  for(i=1;i<4;i++)
    for(j=1;j<4;j++) utsq += ptrgeom->gcov[i][j]*prim[UTCON1+i-1]*prim[UTCON1+j-1] ;


  if( (utsq < 0.) && (fabs(utsq) < MAXNEGUTSQ) ) { 
    utsq = 0.0;
  }
  if(utsq < 0. || utsq > UTSQ_TOO_BIG) {
    if( debugfail>=2 ) dualfprintf(fail_file,"Utoprim_new(): utsq < 0 in utoprim_1d attempt, utsq = %21.15g \n", utsq) ;
    pflag[ptrgeom->i][ptrgeom->j][FLAGUTOPRIMFAIL]= UTOPRIMFAILCONVUTSQ;
    return(1) ;
  }

  gammasq = 1. + utsq ;
  gamma  = sqrt(gammasq);
	
  // Always calculate rho from D and gamma so that using D in EOS remains consistent
  //   i.e. you don't get positive values for dP/d(vsq) . 
  rho0 = D / gamma ;
  u = prim[UU] ;
  p = pressure_rho0_u(rho0,u) ;
  w = rho0 + u + p ;

  W_last = w*gammasq ;


  // Make sure that W is large enough so that v^2 < 1 : 
  i_increase = 0;
  while( (( W_last*W_last*W_last * ( W_last + 2.*Bsq ) - QdotBsq*(2.*W_last + Bsq) ) <= W_last*W_last*(Qtsq-Bsq*Bsq))
	 && (i_increase < 10) ) {
    W_last *= 10.;
    i_increase++;
#if(!OPTIMIZED)
    dualfprintf(fail_file,"badval :  W = %21.15g, i_increase = %d \n", W_last, i_increase); 
#endif
  }
#if(!OPTIMIZED)
  if( i_increase >= 10 ) { 
    dualfprintf(fail_file,"i_increase is too large, i_increase = %d , W = %21.15g \n", i_increase, W_last);
  }
#endif
  

#if(!OPTIMIZED)
  if( ltrace ) {
    dualfprintf(fail_file,"u = %21.15g,  p = %21.15g,  Bsq = %21.15g, Qsq = %21.15g \n",u,p,Bsq,Qsq);
    dualfprintf(fail_file,"Bcon[0-3] = %21.15g   %21.15g   %21.15g   %21.15g   \n", Bcon[0],Bcon[1],Bcon[2],Bcon[3]);
    dualfprintf(fail_file,"Bcov[0-3] = %21.15g   %21.15g   %21.15g   %21.15g   \n", Bcov[0],Bcov[1],Bcov[2],Bcov[3]);
    dualfprintf(fail_file,"Qcon[0-3] = %21.15g   %21.15g   %21.15g   %21.15g   \n", Qcon[0],Qcon[1],Qcon[2],Qcon[3]);
    dualfprintf(fail_file,"Qcov[0-3] = %21.15g   %21.15g   %21.15g   %21.15g   \n", Qcov[0],Qcov[1],Qcov[2],Qcov[3]);
    dualfprintf(fail_file,"call find_root\n") ; 	
    
  }
#endif

  // METHOD specific:
  wglobal=w; // used to validate normalized version of W
  retval = find_root_2D_gen(W_last, &W)  ; 
	
  /* Problem with solver, so return denoting error before doing anything further */
  if( (retval != 0) || (W == FAIL_VAL) ) {
    if( debugfail>=2 ) {
      dualfprintf(fail_file, "Failed to find a prim. var. solution!! %21.15g %21.15g %21.15g %21.15g %21.15g %21.15g \n",W_last,Bsq,QdotBsq,Qdotn,D,Qtsq);
      dualfprintf(fail_file, "Utoprim_new_body(): bad newt failure, t,i,j, p[0-7], U[0-7] = %21.15g %d %d ", t, ptrgeom->i, ptrgeom->j );  
      for( i = 0 ; i < NPR; i++ ) {
	dualfprintf(fail_file, "%21.15g ", prim[i]);
      }
      for( i = 0 ; i < NPR; i++ ) {
	dualfprintf(fail_file, "%21.15g ", U[i]);
      }
      dualfprintf(fail_file, "\n");
    }      
    pflag[ptrgeom->i][ptrgeom->j][FLAGUTOPRIMFAIL]= retval*100+1;// related to UTOPRIMFAILCONVRET
    return(retval);
  }
  else{
    Wtest=W/wglobal; // normalize to old densities

    if(Wtest <= 0. || Wtest > GAMMASQ_TOO_BIG) {
      //if(Wtest <= 0.) {
      if( debugfail>=2 ) {
		dualfprintf(fail_file,"Wtest failure %21.15g \n",Wtest) ;
	dualfprintf(fail_file, "Utoprim_new_body(): Wtest<0 or Wtest=toobig failure, t,i,j, p[0-7], U[0-7] = %21.15g %d %d ", t, ptrgeom->i, ptrgeom->j );  
	for( i = 0 ; i < NPR; i++ ) {
	  dualfprintf(fail_file, "%21.15g ", prim[i]);
	}
	for( i = 0 ; i < NPR; i++ ) {
	  dualfprintf(fail_file, "%21.15g ", U[i]);
	}
	dualfprintf(fail_file, "\n");
      }      

      pflag[ptrgeom->i][ptrgeom->j][FLAGUTOPRIMFAIL]=  UTOPRIMFAILCONVW;
      return(retval) ;
    }
  }


#if(!OPTIMIZED)
  if( ltrace ) {
    dualfprintf(fail_file,"(W,W_last,Bsq,Qtsq,QdotB,gammasq,Qdotn) %21.15g %21.15g %21.15g %21.15g %21.15g %21.15g %21.15g\n",
	    W,W_last,
	    Bsq,Qtsq,QdotB,gammasq,Qdotn) ;
    dualfprintf(fail_file,"done find_root\n") ;	
  }
  if( ltrace2 ) {
    dualfprintf(fail_file, "\n <--------- %21.15g %21.15g %21.15g %21.15g %21.15g  \n", Bsq,QdotBsq,Qdotn,D,Qtsq);
    
  }
#endif

  /*
  if( nstep == 3 ) { 
    if( ((ptrgeom->i==89) && (ptrgeom->j==88||ptrgeom->j==111)) || (ptrgeom->i==92&&(ptrgeom->j==86||ptrgeom->j==113)) 
	|| (ptrgeom->i==92&&(ptrgeom->j==86||ptrgeom->j==113) ) || (ptrgeom->i==94&&(ptrgeom->j==84||ptrgeom->j==115) ) 
	|| (ptrgeom->i==105&&(ptrgeom->j==84||ptrgeom->j==115) ) || (ptrgeom->i==107&&(ptrgeom->j==86||ptrgeom->j==113) ) 
	|| (ptrgeom->i==110&&(ptrgeom->j==88||ptrgeom->j==111) ) ) {
      dualfprintf(fail_file, "\n <--------- %21.15g %21.15g %21.15g %21.15g %21.15g  \n", Bsq,QdotBsq,Qdotn,D,Qtsq);
    }
  }
  */

  // Calculate vsq

  vsq = vsq_calc(W) ;
  if( (vsq < 0.) && (fabs(vsq) < MAXNEGVSQ) ) { 
    vsq = 0.0;
  }
  // no check for vsq>1 since looking for failure to fix that's not just simple like above
  //else if(vsq>=1.0){
  //  if(vsq<1.0+MAXNEGVSQ) vsq=VSQ_TOO_BIG;
  // }
  if( (vsq > VSQ_TOO_BIG)||(vsq<0.0) ) {
    if( debugfail>=2 ) { 
      dualfprintf(fail_file,"vsq failure:  vsq = %21.15g , W = %21.15g \n",vsq, W) ;
      dualfprintf(fail_file, "Utoprim_new_body(): utsq==bad failure, t,i,j, p[0-7], U[0-7] = %21.15g %d %d ", t, ptrgeom->i, ptrgeom->j );  
      for( i = 0 ; i < NPR; i++ ) {
	dualfprintf(fail_file, "%21.15g ", prim[i]);
      }
      for( i = 0 ; i < NPR; i++ ) {
	dualfprintf(fail_file, "%21.15g ", U[i]);
      }
      dualfprintf(fail_file, "\n");
    }      

    pflag[ptrgeom->i][ptrgeom->j][FLAGUTOPRIMFAIL]=  UTOPRIMFAILCONVUTSQ2;
    return(retval) ;
  }

  gtmp = sqrt(1. - vsq);
  gamma = 1./gtmp ;
  rho0 = D * gtmp;

  w = W * (1. - vsq) ;
  p = pressure_rho0_w(rho0,w) ;
  u = w - (rho0 + p) ;

  if( (rho0 <= 0.) || (u < 0.) ) { 
    if( debugfail>=2 ) {
      tmpdiff = w - rho0;
      dualfprintf(fail_file,
		  "rho or uu < 0 failure: rho,w,(w-rho),p,u  = %21.15g %21.15g %21.15g %21.15g %21.15g \n",
		  rho0,w,tmpdiff,p,u) ;
      dualfprintf(fail_file,
		  "rho or uu < 0 failure: gamma,utsq = %21.15g %21.15g  \n",  gamma, utsq) ;
    }
       if((rho0<=0.)&&(u>=0.)) pflag[ptrgeom->i][ptrgeom->j][FLAGUTOPRIMFAIL]=  UTOPRIMFAILRHONEG;
    if((rho0>0.)&&(u<0.)) pflag[ptrgeom->i][ptrgeom->j][FLAGUTOPRIMFAIL]= UTOPRIMFAILUNEG;
    if((rho0<=0.)&&(u<0.)) pflag[ptrgeom->i][ptrgeom->j][FLAGUTOPRIMFAIL]= UTOPRIMFAILRHOUNEG;
    if(UTOPRIMFAILRETURNTYPE==UTOPRIMRETURNNOTADJUSTED) return(retval) ; // else let assign -- used to check how bad failure is.
  }

  prim[RHO] = rho0 ;
  prim[UU] = u ;


  for(i=1;i<4;i++)  Qtcon[i] = Qcon[i] + ncon[i] * Qdotn;
  for(i=1;i<4;i++) prim[UTCON1+i-1] = gamma/(W+Bsq) * ( Qtcon[i] + QdotB*Bcon[i]/W ) ;
	
  /* set field components */
  for(i = BCON1; i <= BCON3; i++) prim[i] = U[i] ;


#if(!OPTIMIZED)
  if( ltrace ) {
    dualfprintf(fail_file," rho final = %21.15g ,  u final = %21.15g \n", rho0, u);
  }
#endif

  /* done! */
  return(retval) ;

}