IllinoisGRMHD
¶Notebook Status: Self-Validated; induction equation not yet implemented
Validation Notes: This tutorial notebook has been confirmed to be self-consistent with its corresponding NRPy+ module, as documented below. Additional validation tests may have been performed, but are as yet, undocumented. (TODO)
We write the equations of general relativistic magnetohydrodynamics in conservative form as follows (Eqs. 41-44 of Duez et al:
∂tρ∗+∂j(ρ∗vj)=0∂t˜τ+∂j(α2√γT0j−ρ∗vj)=s∂t˜Si+∂j(α√γTji)=12α√γTμνgμν,i∂t˜Bi+∂j(vj˜Bi−vi˜Bj)=0,where
s=α√γ[(T00βiβj+2T0iβj+Tij)Kij−(T00βi+T0i)∂iα].We represent Tμν as the sum of the stress-energy tensor of a perfect fluid TμνGRHD, plus the stress-energy associated with the electromagnetic fields in the force-free electrodynamics approximation TμνGRFFE (equivalently, Tμνem in Duez et al):
Tμν=TμνGRHD+TμνGRFFE,where
All quantities can be written in terms of the full GRMHD stress-energy tensor Tμν in precisely the same way they are defined in the GRHD equations. *Therefore, we will not define special functions for generating these quantities, and instead refer the user to the appropriate functions in the GRHD module* Namely,
GRHD.compute_rho_star(alpha, sqrtgammaDET, rho_b,u4U)
GRHD.compute_tau_tilde(alpha, sqrtgammaDET, T4UU,rho_star)
GRHD.compute_S_tildeD(alpha, sqrtgammaDET, T4UD)
GRHD.compute_rho_star_fluxU(vU, rho_star)
GRHD.compute_tau_tilde_fluxU(alpha, sqrtgammaDET, vU,T4UU,rho_star)
GRHD.compute_S_tilde_fluxUD(alpha, sqrtgammaDET, T4UD)
GRHD.compute_s_source_term(KDD,betaU,alpha, sqrtgammaDET,alpha_dD, T4UU)
GRHD.compute_S_tilde_source_termD(alpha, sqrtgammaDET,g4DD_zerotimederiv_dD, T4UU)
In summary, all terms in the GRMHD equations can be constructed once the full GRMHD stress energy tensor Tμν=TμνGRHD+TμνGRFFE is constructed. For completeness, the full set of input variables include:
As is standard in NRPy+,
For instance, in calculating the first term of b2uμuν, we use Greek indices:
T4EMUU = ixp.zerorank2(DIM=4)
for mu in range(4):
for nu in range(4):
# Term 1: b^2 u^{\mu} u^{\nu}
T4EMUU[mu][nu] = smallb2*u4U[mu]*u4U[nu]
When we calculate βi=γijβj, we use Latin indices:
betaD = ixp.zerorank1(DIM=3)
for i in range(3):
for j in range(3):
betaD[i] += gammaDD[i][j] * betaU[j]
As a corollary, any expressions involving mixed Greek and Latin indices will need to offset one set of indices by one: A Latin index in a four-vector will be incremented and a Greek index in a three-vector will be decremented (however, the latter case does not occur in this tutorial notebook). This can be seen when we handle 12α√γTμνEM∂igμν:
# \alpha \sqrt{\gamma} T^{\mu \nu}_{\rm EM} \partial_i g_{\mu \nu} / 2
for i in range(3):
for mu in range(4):
for nu in range(4):
S_tilde_rhsD[i] += alpsqrtgam * T4EMUU[mu][nu] * g4DD_zerotimederiv_dD[mu][nu][i+1] / 2
Each family of quantities is constructed within a given function (boldfaced below). This notebook is organized as follows
GRMHD.equations
NRPy+ module# Step 1: Import needed core NRPy+ modules
import sympy as sp # SymPy: The Python computer algebra package upon which NRPy+ depends
import indexedexp as ixp # NRPy+: Symbolic indexed expression (e.g., tensors, vectors, etc.) support
Recall from above that
Tμν=TμνGRHD+TμνGRFFE,where
GRHD.compute_T4UU(gammaDD,betaU,alpha, rho_b,P,epsilon,u4U)
GRHD (tutorial) function, andGRFFE.compute_TEM4UU(gammaDD,betaU,alpha, smallb4U, smallbsquared,u4U)
GRFFE (tutorial) functionSince a lowering operation on a sum of tensors is equivalent to the lowering operation applied to the individual tensors in the sum,
Tμν=TμνGRHD+TμνGRFFE,where
GRHD.compute_T4UD(gammaDD,betaU,alpha, T4UU)
GRHD (tutorial) function, andGRFFE.compute_TEM4UD(gammaDD,betaU,alpha, TEM4UU)
GRFFE (tutorial) function.import GRHD.equations as GRHD
import GRFFE.equations as GRFFE
# Step 2.a: Define the GRMHD T^{mu nu} (a 4-dimensional tensor)
def compute_GRMHD_T4UU(gammaDD,betaU,alpha, rho_b,P,epsilon,u4U, smallb4U, smallbsquared):
global GRHDT4UU
global GRFFET4UU
global T4UU
GRHD.compute_T4UU( gammaDD,betaU,alpha, rho_b,P,epsilon,u4U)
GRFFE.compute_TEM4UU(gammaDD,betaU,alpha, smallb4U, smallbsquared,u4U)
GRHDT4UU = ixp.zerorank2(DIM=4)
GRFFET4UU = ixp.zerorank2(DIM=4)
T4UU = ixp.zerorank2(DIM=4)
for mu in range(4):
for nu in range(4):
GRHDT4UU[mu][nu] = GRHD.T4UU[mu][nu]
GRFFET4UU[mu][nu] = GRFFE.TEM4UU[mu][nu]
T4UU[mu][nu] = GRHD.T4UU[mu][nu] + GRFFE.TEM4UU[mu][nu]
# Step 2.b: Define T^{mu}_{nu} (a 4-dimensional tensor)
def compute_GRMHD_T4UD(gammaDD,betaU,alpha, GRHDT4UU,GRFFET4UU):
global T4UD
GRHD.compute_T4UD( gammaDD,betaU,alpha, GRHDT4UU)
GRFFE.compute_TEM4UD(gammaDD,betaU,alpha, GRFFET4UU)
T4UD = ixp.zerorank2(DIM=4)
for mu in range(4):
for nu in range(4):
T4UD[mu][nu] = GRHD.T4UD[mu][nu] + GRFFE.TEM4UD[mu][nu]
# First define hydrodynamical quantities
u4U = ixp.declarerank1("u4U", DIM=4)
rho_b,P,epsilon = sp.symbols('rho_b P epsilon',real=True)
B_tildeU = ixp.declarerank1("B_tildeU", DIM=3)
# Then ADM quantities
gammaDD = ixp.declarerank2("gammaDD","sym01",DIM=3)
KDD = ixp.declarerank2("KDD" ,"sym01",DIM=3)
betaU = ixp.declarerank1("betaU", DIM=3)
alpha = sp.symbols('alpha', real=True)
# Then numerical constant
sqrt4pi = sp.symbols('sqrt4pi', real=True)
# First compute smallb4U & smallbsquared from BtildeU, which are needed
# for GRMHD stress-energy tensor T4UU and T4UD:
GRHD.compute_sqrtgammaDET(gammaDD)
GRFFE.compute_B_notildeU(GRHD.sqrtgammaDET, B_tildeU)
GRFFE.compute_smallb4U( gammaDD,betaU,alpha, u4U,GRFFE.B_notildeU, sqrt4pi)
GRFFE.compute_smallbsquared(gammaDD,betaU,alpha, GRFFE.smallb4U)
# Then compute the GRMHD stress-energy tensor:
compute_GRMHD_T4UU(gammaDD,betaU,alpha, rho_b,P,epsilon,u4U, GRFFE.smallb4U, GRFFE.smallbsquared)
compute_GRMHD_T4UD(gammaDD,betaU,alpha, GRHDT4UU,GRFFET4UU)
# Compute conservative variables in terms of primitive variables
GRHD.compute_rho_star( alpha, GRHD.sqrtgammaDET, rho_b,u4U)
GRHD.compute_tau_tilde(alpha, GRHD.sqrtgammaDET, T4UU,GRHD.rho_star)
GRHD.compute_S_tildeD( alpha, GRHD.sqrtgammaDET, T4UD)
# Then compute v^i from u^mu
GRHD.compute_vU_from_u4U__no_speed_limit(u4U)
# Next compute fluxes of conservative variables
GRHD.compute_rho_star_fluxU( GRHD.vU, GRHD.rho_star)
GRHD.compute_tau_tilde_fluxU(alpha, GRHD.sqrtgammaDET, GRHD.vU,T4UU,GRHD.rho_star)
GRHD.compute_S_tilde_fluxUD( alpha, GRHD.sqrtgammaDET, T4UD)
# Then declare derivatives & compute g4DD_zerotimederiv_dD
gammaDD_dD = ixp.declarerank3("gammaDD_dD","sym01",DIM=3)
betaU_dD = ixp.declarerank2("betaU_dD" ,"nosym",DIM=3)
alpha_dD = ixp.declarerank1("alpha_dD" ,DIM=3)
GRHD.compute_g4DD_zerotimederiv_dD(gammaDD,betaU,alpha, gammaDD_dD,betaU_dD,alpha_dD)
# Then compute source terms on tau_tilde and S_tilde equations
GRHD.compute_s_source_term(KDD,betaU,alpha, GRHD.sqrtgammaDET,alpha_dD, T4UU)
GRHD.compute_S_tilde_source_termD( alpha, GRHD.sqrtgammaDET,GRHD.g4DD_zerotimederiv_dD, T4UU)
GRMHD.equations
NRPy+ module [Back to top]¶As a code validation check, we verify agreement in the SymPy expressions for the GRHD equations generated in
import GRMHD.equations as GRMHD
# Compute stress-energy tensor T4UU and T4UD:
GRMHD.compute_GRMHD_T4UU(gammaDD,betaU,alpha, rho_b,P,epsilon,u4U, GRFFE.smallb4U, GRFFE.smallbsquared)
GRMHD.compute_GRMHD_T4UD(gammaDD,betaU,alpha, GRMHD.GRHDT4UU,GRMHD.GRFFET4UU)
all_passed=True
def comp_func(expr1,expr2,basename,prefixname2="Ge."):
if str(expr1-expr2)!="0":
print(basename+" - "+prefixname2+basename+" = "+ str(expr1-expr2))
all_passed=False
def gfnm(basename,idx1,idx2=None,idx3=None):
if idx2 is None:
return basename+"["+str(idx1)+"]"
if idx3 is None:
return basename+"["+str(idx1)+"]["+str(idx2)+"]"
return basename+"["+str(idx1)+"]["+str(idx2)+"]["+str(idx3)+"]"
expr_list = []
exprcheck_list = []
namecheck_list = []
for mu in range(4):
for nu in range(4):
namecheck_list.extend([gfnm("GRMHD.GRHDT4UU",mu,nu),gfnm("GRMHD.GRFFET4UU",mu,nu),
gfnm("GRMHD.T4UU", mu,nu),gfnm("GRMHD.T4UD", mu,nu)])
exprcheck_list.extend([GRMHD.GRHDT4UU[mu][nu],GRMHD.GRFFET4UU[mu][nu],
GRMHD.T4UU[mu][nu], GRMHD.T4UD[mu][nu]])
expr_list.extend([GRHDT4UU[mu][nu],GRFFET4UU[mu][nu],
T4UU[mu][nu], T4UD[mu][nu]])
for i in range(len(expr_list)):
comp_func(expr_list[i],exprcheck_list[i],namecheck_list[i])
import sys
if all_passed:
print("ALL TESTS PASSED!")
else:
print("ERROR: AT LEAST ONE TEST DID NOT PASS")
sys.exit(1)
ALL TESTS PASSED!
The following code cell converts this Jupyter notebook into a proper, clickable LATEX-formatted PDF file. After the cell is successfully run, the generated PDF may be found in the root NRPy+ tutorial directory, with filename Tutorial-GRMHD_Equations-Cartesian.pdf (Note that clicking on this link may not work; you may need to open the PDF file through another means.)
import cmdline_helper as cmd # NRPy+: Multi-platform Python command-line interface
cmd.output_Jupyter_notebook_to_LaTeXed_PDF("Tutorial-GRMHD_Equations-Cartesian")
Created Tutorial-GRMHD_Equations-Cartesian.tex, and compiled LaTeX file to PDF file Tutorial-GRMHD_Equations-Cartesian.pdf