int Rmhd::PrimToCons(const double *P, double *U) const { const double V2 = P[vx]*P[vx] + P[vy]*P[vy] + P[vz]*P[vz]; const double B2 = P[Bx]*P[Bx] + P[By]*P[By] + P[Bz]*P[Bz]; const double Bv = P[Bx]*P[vx] + P[By]*P[vy] + P[Bz]*P[vz]; const double W2 = 1.0 / (1.0 - V2); const double W = sqrt(W2); const double b0 = W*Bv; const double b2 = (B2 + b0*b0) / W2; const double bx = (P[Bx] + b0 * W*P[vx]) / W; const double by = (P[By] + b0 * W*P[vy]) / W; const double bz = (P[Bz] + b0 * W*P[vz]) / W; const double e = EOS->Internal(P[rho], EOS->Temperature_p(P[rho], P[pre]))/P[rho]; const double e_ = e + 0.5 * b2 / P[rho]; const double p_ = P[pre] + 0.5 * b2; const double h_ = 1 + e_ + p_ / P[rho]; U[ddd] = P[rho] * W; U[tau] = P[rho] * h_ * W2 - p_ - b0*b0 - U[ddd]; U[Sx ] = P[rho] * h_ * W2 * P[vx] - b0*bx; U[Sy ] = P[rho] * h_ * W2 * P[vy] - b0*by; U[Sz ] = P[rho] * h_ * W2 * P[vz] - b0*bz; U[Bx ] = P[Bx ]; U[By ] = P[By ]; U[Bz ] = P[Bz ]; if (V2 >= 1.0) { return RMHD_C2P_PRIM_SUPERLUMINAL; } return rmhd_c2p_check_cons(U); }
int Rmhd::ConsToPrim(const double *U, double *P) const { int error = rmhd_c2p_check_cons(U); if (error) { fprintf(stderr, "[0] %s\n", rmhd_c2p_get_error(error)); std::cerr << PrintCons(U) << std::endl; return error; } else { error = 1; } // This piece of code drives cons to prim inversions for an arbitrary equation // of state. // --------------------------------------------------------------------------- if (typeid(*EOS) != typeid(AdiabaticEos)) { rmhd_c2p_eos_set_eos(EOS); rmhd_c2p_eos_new_state(U); // std::cout << PrintPrim(P) << std::endl; // std::cout << PrintCons(U) << std::endl; if (error) { rmhd_c2p_eos_set_starting_prim(P); error = rmhd_c2p_eos_solve_duffell3d(P); } if (error) { // NOTE: disregarding further c2p trials for debugging purposes return error; // ------------------------------------------------------------ rmhd_c2p_eos_set_starting_prim(P); error = rmhd_c2p_eos_solve_noble2dzt(P); } if (error) { rmhd_c2p_eos_estimate_from_cons(); error = rmhd_c2p_eos_solve_noble2dzt(P); } return error; } // This piece of code drives cons to prim inversions for a gamma-law equation // of state. // --------------------------------------------------------------------------- rmhd_c2p_set_gamma(Mara->GetEos<AdiabaticEos>().Gamma); rmhd_c2p_new_state(U); if (error) { rmhd_c2p_estimate_from_cons(); error = rmhd_c2p_solve_anton2dzw(P); // if (error) fprintf(stderr, "[1] %s\n", rmhd_c2p_get_error(error)); } if (error) { rmhd_c2p_set_starting_prim(P); error = rmhd_c2p_solve_anton2dzw(P); // if (error) fprintf(stderr, "[2] %s\n", rmhd_c2p_get_error(error)); } if (error) { rmhd_c2p_estimate_from_cons(); error = rmhd_c2p_solve_noble1dw(P); // if (error) fprintf(stderr, "[3] %s\n", rmhd_c2p_get_error(error)); } if (error) { rmhd_c2p_set_starting_prim(P); error = rmhd_c2p_solve_noble1dw(P); // if (error) fprintf(stderr, "[4] %s\n", rmhd_c2p_get_error(error)); } return error; }
int Rmhd::ConsCheck(const double *U) const { return rmhd_c2p_check_cons(U); }
// Solution based on Noble et. al. (2006), using Z = rho h W^2 as the single // unkown. Unfortunately, Noble uses 'W' for what I call Z. This function should // really be called '1dz', but I use this name to reflect the name of the // section in which it appears. // ----------------------------------------------------------------------------- int rmhd_c2p_solve_noble1dw(double *P) { int bad_input = rmhd_c2p_check_cons(Cons); if (bad_input) { return bad_input; } // Starting values // --------------------------------------------------------------------------- Iterations = 0; double error = 1.0; double Z = Z_start; double f, g; while (error > Tolerance) { const double Z2 = Z*Z; const double Z3 = Z*Z2; const double a = S2*Z2 + BS2*(B2 + 2*Z); const double b = (B2 + Z)*(B2 + Z)*Z2; const double ap = 2*(S2*Z + BS2); // da/dZ const double bp = 2*Z*(B2 + Z)*(B2 + 2*Z); // db/dZ const double V2 = a / b; const double W2 = 1.0 / (1.0 - V2); const double W = sqrt(W2); const double W3 = W*W2; const double Pre = (D/W) * (Z/(D*W) - 1.0) * gamf; const double dv2dZ = (ap*b - bp*a) / (b*b); // (a'b - b'a) / b^2 const double delPdelZ = gamf/W2; const double delPdelW = gamf*(D/W2 - 2*Z/W3); const double dWdv2 = 0.5*W3; const double dPdZ = delPdelW * dWdv2 * dv2dZ + delPdelZ; f = Tau + D - 0.5*B2*(1+V2) + 0.5*BS2/Z2 - Z + Pre; // equation (29) g = -0.5*B2*dv2dZ - BS2/Z3 - 1.0 + dPdZ; const double dZ = -f/g; // ------------------------------------------------------------------------- double Z_new = Z + dZ; Z_new = (Z_new > smlZ) ? Z_new : -Z_new; Z_new = (Z_new < bigZ) ? Z_new : Z; Z = Z_new; error = fabs(dZ/Z); ++Iterations; if (Iterations == MaxIteration) { return RMHD_C2P_MAXITER; } } // Recover the W value from the converged Z value. // ------------------------------------------------------------------------- const double Z2 = Z*Z; const double a = S2*Z2 + BS2*(B2 + 2*Z); const double b = (B2 + Z)*(B2 + Z)*Z2; const double V2 = a / b; const double W2 = 1.0 / (1.0 - V2); const double W = sqrt(W2); return rmhd_c2p_reconstruct_prim(Z, W, P); }
// Solution based on Anton & Zanotti (2006), equations 84 and 85. // ----------------------------------------------------------------------------- int rmhd_c2p_solve_anton2dzw(double *P) { int bad_input = rmhd_c2p_check_cons(Cons); if (bad_input) { return bad_input; } // Starting values // --------------------------------------------------------------------------- Iterations = 0; double error = 1.0; double W = W_start; double Z = Z_start; while (error > Tolerance) { const double Z2 = Z*Z; const double Z3 = Z*Z2; const double W2 = W*W; const double W3 = W*W2; const double Pre = (D/W) * (Z/(D*W) - 1.0) * gamf; const double df0dZ = 2*(B2+Z)*(BS2*W2 + (W2-1)*Z3) / (W2*Z3); const double df0dW = 2*(B2+Z)*(B2+Z) / W3; const double df1dZ = 1.0 + BS2/Z3 - gamf/W2; const double df1dW = B2/W3 + (2*Z - D*W)/W3 * gamf; double f[2]; double J[4], G[4]; // Evaluation of the function, and its Jacobian // ------------------------------------------------------------------------- f[0] = -S2 + (Z+B2)*(Z+B2)*(W2-1)/W2 - (2*Z+B2)*BS2/Z2; // eqn (84) f[1] = -Tau + Z+B2 - Pre - 0.5*B2/W2 - 0.5*BS2/Z2 - D; // eqn (85) J[0] = df0dZ; J[1] = df0dW; J[2] = df1dZ; J[3] = df1dW; // G in the inverse Jacobian // ------------------------------------------------------------------------- const double det = J[0]*J[3] - J[1]*J[2]; G[0] = J[3]/det; G[1] = -J[1]/det; G[2] = -J[2]/det; G[3] = J[0]/det; // G = J^{-1} const double dZ = -(G[0]*f[0] + G[1]*f[1]); // Matrix multiply, dx = -G . f const double dW = -(G[2]*f[0] + G[3]*f[1]); // Bracketing the root // ------------------------------------------------------------------------- double Z_new = Z + dZ; double W_new = W + dW; Z_new = (Z_new > smlZ) ? Z_new : -Z_new; Z_new = (Z_new < bigZ) ? Z_new : Z; W_new = (W_new > smlW) ? W_new : smlW; W_new = (W_new < bigW) ? W_new : bigW; Z = Z_new; W = W_new; // ------------------------------------------------------------------------- error = fabs(dZ/Z) + fabs(dW/W); ++Iterations; if (Iterations == MaxIteration) { return RMHD_C2P_MAXITER; } } return rmhd_c2p_reconstruct_prim(Z, W, P); }