def trK_AbarDD_aDD(gammaDD, KDD): global trK, AbarDD, aDD if gammaDD == None: gammaDD = ixp.declarerank2("gammaDD", "sym01") if KDD == None: KDD = ixp.declarerank2("KDD", "sym01") if rfm.have_already_called_reference_metric_function == False: print( "BSSN.BSSN_in_terms_of_ADM.trK_AbarDD(): Must call reference_metric() first!" ) sys.exit(1) # \bar{gamma}_{ij} = (\frac{\bar{gamma}}{gamma})^{1/3}*gamma_{ij}. gammaUU, gammaDET = ixp.symm_matrix_inverter3x3(gammaDD) # K = gamma^{ij} K_{ij}, and # \bar{A}_{ij} &= (\frac{\bar{gamma}}{gamma})^{1/3}*(K_{ij} - \frac{1}{3}*gamma_{ij}*K) trK = sp.sympify(0) for i in range(DIM): for j in range(DIM): trK += gammaUU[i][j] * KDD[i][j] AbarDD = ixp.zerorank2() aDD = ixp.zerorank2() for i in range(DIM): for j in range(DIM): AbarDD[i][j] = (rfm.detgammahat / gammaDET)**(sp.Rational( 1, 3)) * (KDD[i][j] - sp.Rational(1, 3) * gammaDD[i][j] * trK) aDD[i][j] = AbarDD[i][j] / rfm.ReDD[i][j]
def compute_TEM4UU(gammaDD,betaU,alpha, smallb4U, smallbsquared,u4U,gammaUU=None): global TEM4UU # Then define g^{mu nu} in terms of the ADM quantities: if gammaUU is None: import BSSN.ADMBSSN_tofrom_4metric as AB4m AB4m.g4UU_ito_BSSN_or_ADM("ADM",gammaDD,betaU,alpha) # Finally compute T^{mu nu} TEM4UU = ixp.zerorank2(DIM=4) for mu in range(4): for nu in range(4): TEM4UU[mu][nu] = smallbsquared*u4U[mu]*u4U[nu] \ + sp.Rational(1,2)*smallbsquared*AB4m.g4UU[mu][nu] \ - smallb4U[mu]*smallb4U[nu] else: g4UU = ixp.zerorank4(DIM=4) g4UU[0][0] = -1 / alpha**2 for mu in range(1,4): g4UU[0][mu] = g4UU[mu][0] = betaU[mu-1]/alpha**2 for mu in range(1,4): for nu in range(1,4): g4UU[mu][nu] = gammaUU[mu-1][nu-1] - betaU[mu-1]*betaU[nu-1]/alpha**2 # Finally compute T^{mu nu} TEM4UU = ixp.zerorank2(DIM=4) for mu in range(4): for nu in range(4): TEM4UU[mu][nu] = smallbsquared*u4U[mu]*u4U[nu] \ + sp.Rational(1,2)*smallbsquared*g4UU[mu][nu] \ - smallb4U[mu]*smallb4U[nu]
def g4UU_ito_BSSN_or_ADM(inputvars, gammaDD=None, betaU=None, alpha=None, gammaUU=None): # Step 0: Declare g4UU as globals, to make interfacing with other modules/functions easier global g4UU # Step 1: Set gammaDD, betaU, and alpha if not already input. if gammaDD == None and betaU == None and alpha == None: gammaDD, betaU, alpha = setup_ADM_quantities(inputvars) # Step 2: Compute g4UU = g_{mu nu}: # To get \gamma^{\mu \nu} = gamma4UU[mu][nu], we'll need to use Eq. 2.119 in B&S. g4UU = ixp.zerorank2(DIM=4) # Step 3: Construct g4UU = g^{mu nu} # Step 3.a: Compute gammaUU based on provided gammaDD: if gammaUU == None: gammaUU, gammaDET = ixp.symm_matrix_inverter3x3(gammaDD) # Then evaluate g4UU: g4UU = ixp.zerorank2(DIM=4) g4UU[0][0] = -1 / alpha**2 for mu in range(1, 4): g4UU[0][mu] = g4UU[mu][0] = betaU[mu - 1] / alpha**2 for mu in range(1, 4): for nu in range(1, 4): g4UU[mu][nu] = gammaUU[mu - 1][ nu - 1] - betaU[mu - 1] * betaU[nu - 1] / alpha**2
def detgammabar_and_derivs(): # Step 5.a: Declare as globals all expressions that may be used # outside this function, declare BSSN gridfunctions # if not defined already, and set DIM=3. global detgammabar,detgammabar_dD,detgammabar_dDD hDD, aDD, lambdaU, vetU, betU, trK, cf, alpha = declare_BSSN_gridfunctions_if_not_declared_already() DIM = 3 detgbarOverdetghat = sp.sympify(1) detgbarOverdetghat_dD = ixp.zerorank1() detgbarOverdetghat_dDD = ixp.zerorank2() if par.parval_from_str(thismodule + "::detgbarOverdetghat_equals_one") == "False": print("Error: detgbarOverdetghat_equals_one=\"False\" is not fully implemented yet.") exit(1) ## Approach for implementing detgbarOverdetghat_equals_one=False: # detgbarOverdetghat = gri.register_gridfunctions("AUX", ["detgbarOverdetghat"]) # detgbarOverdetghatInitial = gri.register_gridfunctions("AUX", ["detgbarOverdetghatInitial"]) # detgbarOverdetghat_dD = ixp.declarerank1("detgbarOverdetghat_dD") # detgbarOverdetghat_dDD = ixp.declarerank2("detgbarOverdetghat_dDD", "sym01") # Step 8d: Define detgammabar, detgammabar_dD, and detgammabar_dDD (needed for \partial_t \bar{\Lambda}^i below) detgammabar = detgbarOverdetghat * rfm.detgammahat detgammabar_dD = ixp.zerorank1() for i in range(DIM): detgammabar_dD[i] = detgbarOverdetghat_dD[i] * rfm.detgammahat + detgbarOverdetghat * rfm.detgammahatdD[i] detgammabar_dDD = ixp.zerorank2() for i in range(DIM): for j in range(DIM): detgammabar_dDD[i][j] = detgbarOverdetghat_dDD[i][j] * rfm.detgammahat + \ detgbarOverdetghat_dD[i] * rfm.detgammahatdD[j] + \ detgbarOverdetghat_dD[j] * rfm.detgammahatdD[i] + \ detgbarOverdetghat * rfm.detgammahatdDD[i][j]
def betaU_derivs(): # Step 8.i: Declare as globals all expressions that may be used # outside this function, declare BSSN gridfunctions # if not defined already, and set DIM=3. global betaU_dD, betaU_dupD, betaU_dDD hDD, aDD, lambdaU, vetU, betU, trK, cf, alpha = declare_BSSN_gridfunctions_if_not_declared_already( ) DIM = 3 # Step 8.ii: Compute the unrescaled shift vector beta^i = ReU[i]*vet^i vetU_dD = ixp.declarerank2("vetU_dD", "nosym") vetU_dupD = ixp.declarerank2("vetU_dupD", "nosym") # Needed for upwinded \beta^i_{,j} vetU_dDD = ixp.declarerank3("vetU_dDD", "sym12") # Needed for \beta^i_{,j} betaU_dD = ixp.zerorank2() betaU_dupD = ixp.zerorank2() # Needed for, e.g., \beta^i RHS betaU_dDD = ixp.zerorank3() # Needed for, e.g., \bar{\Lambda}^i RHS for i in range(DIM): for j in range(DIM): betaU_dD[i][ j] = vetU_dD[i][j] * rfm.ReU[i] + vetU[i] * rfm.ReUdD[i][j] betaU_dupD[i][j] = vetU_dupD[i][j] * rfm.ReU[i] + vetU[ i] * rfm.ReUdD[i][j] # Needed for \beta^i RHS for k in range(DIM): # Needed for, e.g., \bar{\Lambda}^i RHS: betaU_dDD[i][j][k] = vetU_dDD[i][j][k] * rfm.ReU[i] + vetU_dD[i][j] * rfm.ReUdD[i][k] + \ vetU_dD[i][k] * rfm.ReUdD[i][j] + vetU[i] * rfm.ReUdDD[i][j][k]
def TOV_ADM_T4UUmunu(ComputeADMT4UUmunuGlobalsOnly=False): global Sph_r_th_ph, r, th, ph, gammaSphDD, KSphDD, alphaSph, betaSphU, BSphU, T4UU # All gridfunctions will be written in terms of spherical coordinates (r, th, ph): r, th, ph = sp.symbols('r th ph', real=True) thismodule = "TOV" DIM = 3 par.set_parval_from_str("grid::DIM", DIM) # Input parameters read in from the TOV data file: rbar, expnu, exp4phi, P, rho = par.Cparameters( "REAL", thismodule, ["rbar", "expnu", "exp4phi", "P", "rho"], [1e300, 1e300, 1e300, 1e300, 1e300]) # Must be read from TOV data # file; set to crazy values to ensure this # Step 4.2: Construct ADM quantities: # *** The physical spatial metric in spherical basis *** # In isotropic coordinates, # gamma_{ij} = e^{4 phi} eta_{ij}, # where eta is the flat-space 3-metric in spherical coordinates gammaSphDD = ixp.zerorank2() gammaSphDD[0][0] = exp4phi gammaSphDD[1][1] = exp4phi * rbar**2 gammaSphDD[2][2] = exp4phi * rbar**2 * sp.sin(th)**2 # *** The extrinsic curvature in spherical basis *** # K_{ij} = 0 for the TOV solution KSphDD = ixp.zerorank2() # *** The lapse and shift in spherical basis *** # alpha = exp^{nu/2} for the TOV solution # \beta^i = 0 for the TOV solution alphaSph = sp.sqrt(expnu) betaSphU = ixp.zerorank1() BSphU = ixp.zerorank1() # Step 4.3: Construct T^{mu nu}: T4UU = ixp.zerorank2(DIM=4) # T^tt = e^(-nu) * rho T4UU[0][0] = rho / expnu # T^{ii} = P / gamma_{ii} for i in range(3): T4UU[i + 1][i + 1] = P / gammaSphDD[i][i] if ComputeADMT4UUmunuGlobalsOnly == True: return Sph_r_th_ph = [r, th, ph] cf, hDD, lambdaU, aDD, trK, alpha, vetU, betU = \ AtoB.Convert_Spherical_or_Cartesian_ADM_to_BSSN_curvilinear("Spherical", Sph_r_th_ph, gammaSphDD, KSphDD, alphaSph, betaSphU, BSphU) sDD, sD, S, rho = \ AtoB.Convert_Spherical_or_Cartesian_T4UUmunu_to_BSSN_curvilinear("Spherical", Sph_r_th_ph, T4UU) global returnfunction returnfunction = bIDf.BSSN_ID_function_string(cf, hDD, lambdaU, aDD, trK, alpha, vetU, betU)
def BSSN_basic_tensors(): # Step 3.a: Declare as globals all variables that may be used # outside this function, declare BSSN gridfunctions # if not defined already, and set DIM=3. global gammabarDD, AbarDD, LambdabarU, betaU, BU hDD, aDD, lambdaU, vetU, betU, trK, cf, alpha = declare_BSSN_gridfunctions_if_not_declared_already( ) DIM = 3 # Step 3.a.i: gammabarDD and AbarDD: gammabarDD = ixp.zerorank2() AbarDD = ixp.zerorank2() for i in range(DIM): for j in range(DIM): # gammabar_{ij} = h_{ij}*ReDD[i][j] + gammahat_{ij} gammabarDD[i][j] = hDD[i][j] * rfm.ReDD[i][j] + rfm.ghatDD[i][j] # Abar_{ij} = a_{ij}*ReDD[i][j] AbarDD[i][j] = aDD[i][j] * rfm.ReDD[i][j] # Step 3.a.ii: LambdabarU, betaU, and BU: LambdabarU = ixp.zerorank1() betaU = ixp.zerorank1() BU = ixp.zerorank1() for i in range(DIM): LambdabarU[i] = lambdaU[i] * rfm.ReU[i] betaU[i] = vetU[i] * rfm.ReU[i] BU[i] = betU[i] * rfm.ReU[i]
def ADM_to_four_metric(gammaDD, betaU, alpha, returng4DD=True, returng4UU=False): # The ADM formulation decomposes Einstein's 4D equations into 3+1 dimensional form, with # the 3 spatial dimensions separated from the 1 temporal dimension. DIM here refers to # the spatial dimension. DIM = 3 # Eq 4.47 in [Gourgoulhon](https://arxiv.org/pdf/gr-qc/0703035.pdf): # g_{tt} = -\alpha^2 + \beta^k \beta_k # g_{ti} = \beta_i # g_{ij} = \gamma_{ij} # Eq. 2.121 in B&S betaD = ixp.zerorank1() for i in range(DIM): for j in range(DIM): betaD[i] += gammaDD[i][j] * betaU[j] # Now compute the beta contraction. beta2 = sp.sympify(0) for i in range(DIM): beta2 += betaU[i] * betaD[i] g4DD = ixp.zerorank2(DIM=4) g4DD[0][0] = -alpha**2 + beta2 for i in range(DIM): g4DD[i + 1][0] = g4DD[0][i + 1] = betaD[i] for j in range(DIM): g4DD[i + 1][j + 1] = gammaDD[i][j] if returng4DD == True and returng4UU == False: return g4DD gammaUU, gammaDET = ixp.symm_matrix_inverter3x3(gammaDD) # Eq. 4.49 in [Gourgoulhon](https://arxiv.org/pdf/gr-qc/0703035.pdf): # g^{tt} = -1 / alpha^2 # g^{ti} = beta^i / alpha^2 # g^{ij} = gamma^{ij} - beta^i beta^j / alpha^2 g4UU = ixp.zerorank2(DIM=4) g4UU[0][0] = -1 / alpha**2 for i in range(DIM): g4UU[i + 1][0] = g4UU[0][i + 1] = betaU[i] / alpha**2 for j in range(DIM): g4UU[i + 1][j + 1] = gammaUU[i][j] - betaU[i] * betaU[j] / alpha**2 if returng4DD == True and returng4UU == True: return g4DD, g4UU if returng4DD == False and returng4UU == True: return g4UU print( "Error: ADM_to_four_metric() called without requesting anything being returned!" ) exit(1)
def BSSN_source_terms_for_BSSN_RHSs(custom_T4UU=None): global sourceterm_trK_rhs, sourceterm_a_rhsDD, sourceterm_lambda_rhsU, sourceterm_Lambdabar_rhsU # Step 3.a: Call BSSN_source_terms_ito_T4UU to get SDD, SD, S, & rho if custom_T4UU == "unrescaled BSSN source terms already given": SDD = ixp.declarerank2("SDD", "sym01") SD = ixp.declarerank1("SD") S = sp.symbols("S", real=True) rho = sp.symbols("rho", real=True) else: SDD, SD, S, rho = stress_energy_source_terms_ito_T4UU_and_ADM_or_BSSN_metricvars( "BSSN", custom_T4UU) PI = par.Cparameters("REAL", thismodule, ["PI"], "3.14159265358979323846264338327950288") alpha = sp.symbols("alpha", real=True) # Step 3.b: trK_rhs sourceterm_trK_rhs = 4 * PI * alpha * (rho + S) # Step 3.c: Abar_rhsDD: # Step 3.c.i: Compute trace-free part of S_{ij}: import BSSN.BSSN_quantities as Bq Bq.BSSN_basic_tensors() # Sets gammabarDD gammabarUU, dummydet = ixp.symm_matrix_inverter3x3( Bq.gammabarDD) # Set gammabarUU tracefree_SDD = ixp.zerorank2() for i in range(3): for j in range(3): tracefree_SDD[i][j] = SDD[i][j] for i in range(3): for j in range(3): for k in range(3): for m in range(3): tracefree_SDD[i][j] += -sp.Rational(1, 3) * Bq.gammabarDD[ i][j] * gammabarUU[k][m] * SDD[k][m] # Step 3.c.ii: Define exp_m4phi = e^{-4 phi} Bq.phi_and_derivs() # Step 3.c.iii: Evaluate stress-energy part of AbarDD's RHS sourceterm_a_rhsDD = ixp.zerorank2() for i in range(3): for j in range(3): Abar_rhsDDij = -8 * PI * alpha * Bq.exp_m4phi * tracefree_SDD[i][j] sourceterm_a_rhsDD[i][j] = Abar_rhsDDij / rfm.ReDD[i][j] # Step 3.d: Stress-energy part of Lambdabar_rhsU = stressenergy_Lambdabar_rhsU sourceterm_Lambdabar_rhsU = ixp.zerorank1() for i in range(3): for j in range(3): sourceterm_Lambdabar_rhsU[ i] += -16 * PI * alpha * gammabarUU[i][j] * SD[j] sourceterm_lambda_rhsU = ixp.zerorank1() for i in range(3): sourceterm_lambda_rhsU[i] = sourceterm_Lambdabar_rhsU[i] / rfm.ReU[i]
def BrillLindquist(ComputeADMGlobalsOnly=False, include_NRPy_basic_defines_and_pickle=False): # Step 2: Setting up Brill-Lindquist initial data # Step 2.a: Set spatial dimension (must be 3 for BSSN) DIM = 3 par.set_parval_from_str("grid::DIM", DIM) global Cartxyz, gammaCartDD, KCartDD, alphaCart, betaCartU, BCartU Cartxyz = ixp.declarerank1("Cartxyz") # Step 2.b: Set psi, the conformal factor: psi = sp.sympify(1) psi += BH1_mass / (2 * sp.sqrt((Cartxyz[0] - BH1_posn_x)**2 + (Cartxyz[1] - BH1_posn_y)**2 + (Cartxyz[2] - BH1_posn_z)**2)) psi += BH2_mass / (2 * sp.sqrt((Cartxyz[0] - BH2_posn_x)**2 + (Cartxyz[1] - BH2_posn_y)**2 + (Cartxyz[2] - BH2_posn_z)**2)) # Step 2.c: Set all needed ADM variables in Cartesian coordinates gammaCartDD = ixp.zerorank2() KCartDD = ixp.zerorank2() # K_{ij} = 0 for these initial data for i in range(DIM): gammaCartDD[i][i] = psi**4 alphaCart = 1 / psi**2 betaCartU = ixp.zerorank1( ) # We generally choose \beta^i = 0 for these initial data BCartU = ixp.zerorank1( ) # We generally choose B^i = 0 for these initial data if ComputeADMGlobalsOnly == True: return cf,hDD,lambdaU,aDD,trK,alpha,vetU,betU = \ AtoB.Convert_Spherical_or_Cartesian_ADM_to_BSSN_curvilinear("Cartesian",Cartxyz, gammaCartDD,KCartDD,alphaCart,betaCartU,BCartU) import BSSN.BSSN_ID_function_string as bIDf # Generates initial_data() C function & stores to outC_function_dict["initial_data"] bIDf.BSSN_ID_function_string( cf, hDD, lambdaU, aDD, trK, alpha, vetU, betU, include_NRPy_basic_defines=include_NRPy_basic_defines_and_pickle) if include_NRPy_basic_defines_and_pickle: return pickle_NRPy_env()
def AbarUU_AbarUD_trAbar_AbarDD_dD(): # Step 6.a: Declare as globals all expressions that may be used # outside this function, declare BSSN gridfunctions # if not defined already, and set DIM=3. global AbarUU, AbarUD, trAbar, AbarDD_dD, AbarDD_dupD hDD, aDD, lambdaU, vetU, betU, trK, cf, alpha = declare_BSSN_gridfunctions_if_not_declared_already( ) DIM = 3 # Define AbarDD and gammabarDD in terms of BSSN gridfunctions BSSN_basic_tensors() # Define gammabarUU in terms of BSSN gridfunctions gammabar__inverse_and_derivs() # Step 6.a.i: Compute Abar^{ij} in terms of Abar_{ij} and gammabar^{ij} AbarUU = ixp.zerorank2() for i in range(DIM): for j in range(DIM): for k in range(DIM): for l in range(DIM): # Abar^{ij} = gammabar^{ik} gammabar^{jl} Abar_{kl} AbarUU[i][j] += gammabarUU[i][k] * gammabarUU[j][ l] * AbarDD[k][l] # Step 6.a.ii: Compute Abar^i_j in terms of Abar_{ij} and gammabar^{ij} AbarUD = ixp.zerorank2() for i in range(DIM): for j in range(DIM): for k in range(DIM): # Abar^i_j = gammabar^{ik} Abar_{kj} AbarUD[i][j] += gammabarUU[i][k] * AbarDD[k][j] # Step 6.a.iii: Compute Abar^k_k = trace of Abar: trAbar = sp.sympify(0) for k in range(DIM): for j in range(DIM): # Abar^k_k = gammabar^{kj} Abar_{jk} trAbar += gammabarUU[k][j] * AbarDD[j][k] # Step 6.a.iv: Compute Abar_{ij,k} AbarDD_dD = ixp.zerorank3() AbarDD_dupD = ixp.zerorank3() aDD_dD = ixp.declarerank3("aDD_dD", "sym01") aDD_dupD = ixp.declarerank3("aDD_dupD", "sym01") for i in range(DIM): for j in range(DIM): for k in range(DIM): AbarDD_dupD[i][j][k] = rfm.ReDDdD[i][j][k] * aDD[i][ j] + rfm.ReDD[i][j] * aDD_dupD[i][j][k] AbarDD_dD[i][j][k] = rfm.ReDDdD[i][j][k] * aDD[i][ j] + rfm.ReDD[i][j] * aDD_dD[i][j][k]
def BrillLindquist(ComputeADMGlobalsOnly=False): global Cartxyz, gammaCartDD, KCartDD, alphaCart, betaCartU, BCartU # Step 2: Setting up Brill-Lindquist initial data thismodule = "Brill-Lindquist" BH1_posn_x, BH1_posn_y, BH1_posn_z = par.Cparameters( "REAL", thismodule, ["BH1_posn_x", "BH1_posn_y", "BH1_posn_z"]) BH1_mass = par.Cparameters("REAL", thismodule, ["BH1_mass"]) BH2_posn_x, BH2_posn_y, BH2_posn_z = par.Cparameters( "REAL", thismodule, ["BH2_posn_x", "BH2_posn_y", "BH2_posn_z"]) BH2_mass = par.Cparameters("REAL", thismodule, ["BH2_mass"]) # Step 2.a: Set spatial dimension (must be 3 for BSSN) DIM = 3 par.set_parval_from_str("grid::DIM", DIM) global Cartxyz, gammaCartDD, KCartDD, alphaCart, betaCartU, BCartU Cartxyz = ixp.declarerank1("Cartxyz") # Step 2.b: Set psi, the conformal factor: psi = sp.sympify(1) psi += BH1_mass / (2 * sp.sqrt((Cartxyz[0] - BH1_posn_x)**2 + (Cartxyz[1] - BH1_posn_y)**2 + (Cartxyz[2] - BH1_posn_z)**2)) psi += BH2_mass / (2 * sp.sqrt((Cartxyz[0] - BH2_posn_x)**2 + (Cartxyz[1] - BH2_posn_y)**2 + (Cartxyz[2] - BH2_posn_z)**2)) # Step 2.c: Set all needed ADM variables in Cartesian coordinates gammaCartDD = ixp.zerorank2() KCartDD = ixp.zerorank2() # K_{ij} = 0 for these initial data for i in range(DIM): gammaCartDD[i][i] = psi**4 alphaCart = 1 / psi**2 betaCartU = ixp.zerorank1( ) # We generally choose \beta^i = 0 for these initial data BCartU = ixp.zerorank1( ) # We generally choose B^i = 0 for these initial data if ComputeADMGlobalsOnly == True: return cf,hDD,lambdaU,aDD,trK,alpha,vetU,betU = \ AtoB.Convert_Spherical_or_Cartesian_ADM_to_BSSN_curvilinear("Cartesian",Cartxyz, gammaCartDD,KCartDD,alphaCart,betaCartU,BCartU) global returnfunction returnfunction = bIDf.BSSN_ID_function_string(cf, hDD, lambdaU, aDD, trK, alpha, vetU, betU)
def g4DD_ito_BSSN_or_ADM(inputvars, gammaDD=None, betaU=None, alpha=None): # Step 0: Declare g4DD as globals, to make interfacing with other modules/functions easier global g4DD # Step 1: Set gammaDD, betaU, and alpha if not already input. if gammaDD == None and betaU == None and alpha == None: gammaDD, betaU, alpha = setup_ADM_quantities(inputvars) # Step 2: Compute g4DD = g_{mu nu}: # To get \gamma_{\mu \nu} = gamma4DD[mu][nu], we'll need to construct the 4-metric, using Eq. 2.122 in B&S: g4DD = ixp.zerorank2(DIM=4) # Step 2.a: Compute beta_i via Eq. 2.121 in B&S betaD = ixp.zerorank1() for i in range(3): for j in range(3): betaD[i] += gammaDD[i][j] * betaU[j] # Step 2.b: Compute beta_i beta^i, the beta contraction. beta2 = sp.sympify(0) for i in range(3): beta2 += betaU[i] * betaD[i] # Step 2.c: Construct g4DD via Eq. 2.122 in B&S g4DD[0][0] = -alpha**2 + beta2 for mu in range(1, 4): g4DD[mu][0] = g4DD[0][mu] = betaD[mu - 1] for mu in range(1, 4): for nu in range(1, 4): g4DD[mu][nu] = gammaDD[mu - 1][nu - 1]
def ValenciavU_func_EW(**params): M = params["M"] gammaDD = params["gammaDD"] # Note that this must use a Cartesian basis! sqrtgammaDET = params["sqrtgammaDET"] KerrSchild_radial_shift = params["KerrSchild_radial_shift"] r = rfm.xxSph[ 0] + KerrSchild_radial_shift # We are setting the data up in Shifted Kerr-Schild coordinates theta = rfm.xxSph[1] LeviCivitaTensorUUU = ixp.LeviCivitaTensorUUU_dim3_rank3(sqrtgammaDET) AD = gfcf.Axyz_func_spherical(Ar_EW, Ath_EW, Aph_EW, False, **params) # For the initial data, we can analytically take the derivatives of A_i ADdD = ixp.zerorank2() for i in range(3): for j in range(3): ADdD[i][j] = sp.simplify(sp.diff(AD[i], rfm.xx_to_Cart[j])) BU = ixp.zerorank1() for i in range(3): for j in range(3): for k in range(3): BU[i] += LeviCivitaTensorUUU[i][j][k] * ADdD[k][j] EsphD = ixp.zerorank1() # 2 M ( 1+ 2M/r )^{-1/2} \sin^2 \theta EsphD[2] = 2 * M * sp.sin(theta)**2 / sp.sqrt(1 + 2 * M / r) ED = rfm.basis_transform_vectorD_from_rfmbasis_to_Cartesian( gfcf.Jac_dUrfm_dDCartUD, EsphD) return gfcf.compute_ValenciavU_from_ED_and_BU(ED, BU, gammaDD)
def compute_ValenciavU_from_ED_and_BU(ED, BU, gammaDD=None): # Now, we calculate v^i = ([ijk] E_j B_k) / B^2, # where [ijk] is the Levi-Civita symbol and B^2 = \gamma_{ij} B^i B^j$ is a trivial dot product in flat space. # In flat spacetime, use the Minkowski metric; otherwise, use the input metric. if gammaDD is None: gammaDD = ixp.zerorank2() for i in range(3): gammaDD[i][i] = sp.sympify(1) unused_gammaUU, gammaDET = ixp.symm_matrix_inverter3x3(gammaDD) sqrtgammaDET = sp.sqrt(gammaDET) LeviCivitaTensorUUU = ixp.LeviCivitaTensorUUU_dim3_rank3(sqrtgammaDET) BD = ixp.zerorank1() for i in range(3): for j in range(3): BD[i] += gammaDD[i][j] * BU[j] B2 = sp.sympify(0) for i in range(3): B2 += BU[i] * BD[i] ValenciavU = ixp.zerorank1() for i in range(3): for j in range(3): for k in range(3): ValenciavU[ i] += LeviCivitaTensorUUU[i][j][k] * ED[j] * BD[k] / B2 return ValenciavU
def compute_g4DD_zerotimederiv_dD(gammaDD,betaU,alpha, gammaDD_dD,betaU_dD,alpha_dD): global g4DD_zerotimederiv_dD # Eq. 2.121 in B&S betaD = ixp.zerorank1() for i in range(3): for j in range(3): betaD[i] += gammaDD[i][j]*betaU[j] # gammaDD_dD = ixp.declarerank3("gammaDD_dDD","sym12",DIM=3) # betaU_dD = ixp.declarerank2("betaU_dD" ,"nosym",DIM=3) betaDdD = ixp.zerorank2() for i in range(3): for j in range(3): for k in range(3): # Recall that betaD[i] = gammaDD[i][j]*betaU[j] (Eq. 2.121 in B&S) betaDdD[i][k] += gammaDD_dD[i][j][k]*betaU[j] + gammaDD[i][j]*betaU_dD[j][k] # Eq. 2.122 in B&S g4DD_zerotimederiv_dD = ixp.zerorank3(DIM=4) for k in range(3): # Recall that g4DD[0][0] = -alpha^2 + betaU[j]*betaD[j] g4DD_zerotimederiv_dD[0][0][k+1] += -2*alpha*alpha_dD[k] for j in range(3): g4DD_zerotimederiv_dD[0][0][k+1] += betaU_dD[j][k]*betaD[j] + betaU[j]*betaDdD[j][k] for i in range(3): for k in range(3): # Recall that g4DD[i][0] = g4DD[0][i] = betaD[i] g4DD_zerotimederiv_dD[i+1][0][k+1] = g4DD_zerotimederiv_dD[0][i+1][k+1] = betaDdD[i][k] for i in range(3): for j in range(3): for k in range(3): # Recall that g4DD[i][j] = gammaDD[i][j] g4DD_zerotimederiv_dD[i+1][j+1][k+1] = gammaDD_dD[i][j][k]
def ScalarField_Tmunu(): global T4UU # Step 1.c: Set spatial dimension (must be 3 for BSSN, as BSSN is # a 3+1-dimensional decomposition of the general # relativistic field equations) DIM = 3 # Step 1.d: Given the chosen coordinate system, set up # corresponding reference metric and needed # reference metric quantities # The following function call sets up the reference metric # and related quantities, including rescaling matrices ReDD, # ReU, and hatted quantities. rfm.reference_metric() # Step 1.e: Import all basic (unrescaled) BSSN scalars & tensors Bq.BSSN_basic_tensors() alpha = Bq.alpha betaU = Bq.betaU # Step 1.g: Define ADM quantities in terms of BSSN quantities BtoA.ADM_in_terms_of_BSSN() gammaDD = BtoA.gammaDD gammaUU = BtoA.gammaUU # Step 1.h: Define scalar field quantitites sf_dD = ixp.declarerank1("sf_dD") Pi = sp.Symbol("sfM", real=True) # Step 2a: Set up \partial^{t}\varphi = Pi/alpha sf4dU = ixp.zerorank1(DIM=4) sf4dU[0] = Pi / alpha # Step 2b: Set up \partial^{i}\varphi = -Pi*beta^{i}/alpha + gamma^{ij}\partial_{j}\varphi for i in range(DIM): sf4dU[i + 1] = -Pi * betaU[i] / alpha for j in range(DIM): sf4dU[i + 1] += gammaUU[i][j] * sf_dD[j] # Step 2c: Set up \partial^{i}\varphi\partial_{i}\varphi = -Pi**2 + gamma^{ij}\partial_{i}\varphi\partial_{j}\varphi sf4d2 = -Pi**2 for i in range(DIM): for j in range(DIM): sf4d2 += gammaUU[i][j] * sf_dD[i] * sf_dD[j] # Step 3a: Setting up g^{\mu\nu} ADMg.g4UU_ito_BSSN_or_ADM("ADM", gammaDD=gammaDD, betaU=betaU, alpha=alpha, gammaUU=gammaUU) g4UU = ADMg.g4UU # Step 3b: Setting up T^{\mu\nu} for a massless scalar field T4UU = ixp.zerorank2(DIM=4) for mu in range(4): for nu in range(4): T4UU[mu][nu] = sf4dU[mu] * sf4dU[nu] - g4UU[mu][nu] * sf4d2 / 2
def BSSN_or_ADM_ito_g4DD(inputvars, g4DD=None): # Step 0: Declare output variables as globals, to make interfacing with other modules/functions easier if inputvars == "ADM": global gammaDD, betaU, alpha elif inputvars == "BSSN": global hDD, cf, vetU, alpha else: print("inputvars = " + str(inputvars) + " not supported. Please choose ADM or BSSN.") sys.exit(1) # Step 1: declare g4DD as symmetric rank-4 tensor: g4DD_is_input_into_this_function = True if g4DD == None: g4DD = ixp.declarerank2("g4DD", "sym01", DIM=4) g4DD_is_input_into_this_function = False # Step 2: Compute gammaDD & betaD betaD = ixp.zerorank1() gammaDD = ixp.zerorank2() for i in range(3): betaD[i] = g4DD[0][i] for j in range(3): gammaDD[i][j] = g4DD[i + 1][j + 1] # Step 3: Compute betaU # Step 3.a: Compute gammaUU based on provided gammaDD gammaUU, gammaDET = ixp.symm_matrix_inverter3x3(gammaDD) # Step 3.b: Use gammaUU to raise betaU betaU = ixp.zerorank1() for i in range(3): for j in range(3): betaU[i] += gammaUU[i][j] * betaD[j] # Step 4: Compute alpha = sqrt(beta^2 - g_{00}): # Step 4.a: Compute beta^2 = beta^k beta_k: beta_squared = sp.sympify(0) for k in range(3): beta_squared += betaU[k] * betaD[k] # Step 4.b: alpha = sqrt(beta^2 - g_{00}): if g4DD_is_input_into_this_function == False: alpha = sp.sqrt(sp.simplify(beta_squared) - g4DD[0][0]) else: alpha = sp.sqrt(beta_squared - g4DD[0][0]) # Step 5: If inputvars == "ADM", we are finished. Return. if inputvars == "ADM": return # Step 6: If inputvars == "BSSN", convert ADM to BSSN import BSSN.BSSN_in_terms_of_ADM as BitoA dummyBU = ixp.zerorank1() BitoA.gammabarDD_hDD(gammaDD) BitoA.cf_from_gammaDD(gammaDD) BitoA.betU_vetU(betaU, dummyBU) hDD = BitoA.hDD cf = BitoA.cf vetU = BitoA.vetU
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]
def Enforce_Detgammabar_Constraint_symb_expressions(): # Set spatial dimension (must be 3 for BSSN) DIM = 3 # Then we set the coordinate system for the numerical grid rfm.reference_metric( ) # Create ReU, ReDD needed for rescaling B-L initial data, generating BSSN RHSs, etc. # We will need the h_{ij} quantities defined within BSSN_RHSs # below when we enforce the gammahat=gammabar constraint # Step 1: All barred quantities are defined in terms of BSSN rescaled gridfunctions, # which we declare here in case they haven't yet been declared elsewhere. Bq.declare_BSSN_gridfunctions_if_not_declared_already() hDD = Bq.hDD Bq.BSSN_basic_tensors() gammabarDD = Bq.gammabarDD # First define the Kronecker delta: KroneckerDeltaDD = ixp.zerorank2() for i in range(DIM): KroneckerDeltaDD[i][i] = sp.sympify(1) # The detgammabar in BSSN_RHSs is set to detgammahat when BSSN_RHSs::detgbarOverdetghat_equals_one=True (default), # so we manually compute it here: dummygammabarUU, detgammabar = ixp.symm_matrix_inverter3x3(gammabarDD) # Next apply the constraint enforcement equation above. hprimeDD = ixp.zerorank2() for i in range(DIM): for j in range(DIM): hprimeDD[i][j] = \ (nrpyAbs(rfm.detgammahat) / detgammabar) ** (sp.Rational(1, 3)) * (KroneckerDeltaDD[i][j] + hDD[i][j]) \ - KroneckerDeltaDD[i][j] enforce_detg_constraint_symb_expressions = [ lhrh(lhs=gri.gfaccess("in_gfs", "hDD00"), rhs=hprimeDD[0][0]), lhrh(lhs=gri.gfaccess("in_gfs", "hDD01"), rhs=hprimeDD[0][1]), lhrh(lhs=gri.gfaccess("in_gfs", "hDD02"), rhs=hprimeDD[0][2]), lhrh(lhs=gri.gfaccess("in_gfs", "hDD11"), rhs=hprimeDD[1][1]), lhrh(lhs=gri.gfaccess("in_gfs", "hDD12"), rhs=hprimeDD[1][2]), lhrh(lhs=gri.gfaccess("in_gfs", "hDD22"), rhs=hprimeDD[2][2]) ] return enforce_detg_constraint_symb_expressions
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]
def gammabarDD_hDD(gammaDD): global gammabarDD, hDD if gammaDD == None: gammaDD = ixp.declarerank2("gammaDD", "sym01") if rfm.have_already_called_reference_metric_function == False: print( "BSSN.BSSN_in_terms_of_ADM.hDD_given_ADM(): Must call reference_metric() first!" ) sys.exit(1) # \bar{gamma}_{ij} = (\frac{\bar{gamma}}{gamma})^{1/3}*gamma_{ij}. gammaUU, gammaDET = ixp.symm_matrix_inverter3x3(gammaDD) gammabarDD = ixp.zerorank2() hDD = ixp.zerorank2() for i in range(DIM): for j in range(DIM): gammabarDD[i][j] = (rfm.detgammahat / gammaDET)**(sp.Rational( 1, 3)) * gammaDD[i][j] hDD[i][j] = (gammabarDD[i][j] - rfm.ghatDD[i][j]) / rfm.ReDD[i][j]
def compute_TEM4UD(gammaDD, betaU, alpha, TEM4UU): global TEM4UD # Next compute T^mu_nu = T^{mu delta} g_{delta nu}, needed for S_tilde flux. # First we'll need g_{alpha nu} in terms of ADM quantities: import BSSN.ADMBSSN_tofrom_4metric as AB4m AB4m.g4DD_ito_BSSN_or_ADM("ADM", gammaDD, betaU, alpha) TEM4UD = ixp.zerorank2(DIM=4) for mu in range(4): for nu in range(4): for delta in range(4): TEM4UD[mu][nu] += TEM4UU[mu][delta] * AB4m.g4DD[delta][nu]
def compute_T4UU(gammaDD,betaU,alpha, rho_b,P,epsilon,u4U): global T4UU compute_enthalpy(rho_b,P,epsilon) # Then define g^{mu nu} in terms of the ADM quantities: import BSSN.ADMBSSN_tofrom_4metric as AB4m AB4m.g4UU_ito_BSSN_or_ADM("ADM",gammaDD,betaU,alpha) # Finally compute T^{mu nu} T4UU = ixp.zerorank2(DIM=4) for mu in range(4): for nu in range(4): T4UU[mu][nu] = rho_b * h * u4U[mu]*u4U[nu] + P*AB4m.g4UU[mu][nu]
def compute_TEM4UU(gammaDD, betaU, alpha, smallb4U, smallbsquared, u4U): global TEM4UU # Then define g^{mu nu} in terms of the ADM quantities: import BSSN.ADMBSSN_tofrom_4metric as AB4m AB4m.g4UU_ito_BSSN_or_ADM("ADM", gammaDD, betaU, alpha) # Finally compute T^{mu nu} TEM4UU = ixp.zerorank2(DIM=4) for mu in range(4): for nu in range(4): TEM4UU[mu][nu] = smallbsquared*u4U[mu]*u4U[nu] \ + sp.Rational(1,2)*smallbsquared*AB4m.g4UU[mu][nu] \ - smallb4U[mu]*smallb4U[nu]
def Convert_to_Cartesian_basis(VU): # Coordinate transformation from original basis to Cartesian rfm.reference_metric() VU_Cart = ixp.zerorank1() Jac_dxCartU_dxOrigD = ixp.zerorank2() for i in range(DIM): for j in range(DIM): Jac_dxCartU_dxOrigD[i][j] = sp.diff(rfm.xxCart[i], rfm.xx[j]) for i in range(DIM): for j in range(DIM): VU_Cart[i] += Jac_dxCartU_dxOrigD[i][j] * VU[j] return VU_Cart
def four_metric_to_ADM(g4DD): # The ADM formulation decomposes Einstein's 4D equations into 3+1 dimensional form, with # the 3 spatial dimensions separated from the 1 temporal dimension. DIM here refers to # the spatial dimension. DIM = 3 # Eq 4.47 in [Gourgoulhon](https://arxiv.org/pdf/gr-qc/0703035.pdf): # g_{ij} = \gamma_{ij} gammaDD = ixp.zerorank2() for i in range(DIM): for j in range(DIM): gammaDD[i][j] = g4DD[i + 1][j + 1] # Eq 4.47 in [Gourgoulhon](https://arxiv.org/pdf/gr-qc/0703035.pdf): # g_{ti} = \beta_i betaD = ixp.zerorank1() for i in range(DIM): betaD[i] = g4DD[i + 1][0] #Eq. 2.121 in B&S: # beta^i = gamma^{ij} beta_j betaU = ixp.zerorank1() gammaUU, gammaDET = ixp.symm_matrix_inverter3x3(gammaDD) for i in range(DIM): for j in range(DIM): betaU[i] += gammaUU[i][j] * betaD[j] # Eq 4.47 in [Gourgoulhon](https://arxiv.org/pdf/gr-qc/0703035.pdf): # g_{tt} = -\alpha^2 + \beta^k \beta_k # -> alpha = sqrt(beta^2 - g_tt) # Now compute the beta contraction. beta2 = sp.sympify(0) for i in range(DIM): beta2 += betaU[i] * betaD[i] alpha = sp.sqrt(beta2 - g4DD[0][0]) return gammaDD, betaU, alpha
def parity_conditions_symbolic_dot_products(): parity = ixp.zerorank1(DIM=10) UnitVectors_inner = ixp.zerorank2() xx0_inbounds,xx1_inbounds,xx2_inbounds = sp.symbols("xx0_inbounds xx1_inbounds xx2_inbounds", real=True) for i in range(3): for j in range(3): UnitVectors_inner[i][j] = rfm.UnitVectors[i][j].subs(rfm.xx[0],xx0_inbounds).subs(rfm.xx[1],xx1_inbounds).subs(rfm.xx[2],xx2_inbounds) # Type 0: scalar parity[0] = sp.sympify(1) # Type 1: i0-direction vector or one-form # Type 2: i1-direction vector or one-form # Type 3: i2-direction vector or one-form for i in range(3): for Type in range(1,4): parity[Type] += rfm.UnitVectors[Type-1][i]*UnitVectors_inner[Type-1][i] # Type 4: i0i0-direction rank-2 tensor # parity[4] = parity[1]*parity[1] # Type 5: i0i1-direction rank-2 tensor # Type 6: i0i2-direction rank-2 tensor # Type 7: i1i1-direction rank-2 tensor # Type 8: i1i2-direction rank-2 tensor # Type 9: i2i2-direction rank-2 tensor count = 4 for i in range(3): for j in range(i,3): parity[count] = parity[i+1]*parity[j+1] count = count + 1 lhs_strings = [] for i in range(10): lhs_strings.append("REAL_parity_array["+str(i)+"]") outstr = """ // NRPy+ Curvilinear Boundary Conditions: Unit vector dot products for all // ten parity conditions, in given coordinate system. // Needed for automatically determining sign of tensor across coordinate boundary. // Documented in: Tutorial-Start_to_Finish-Curvilinear_BCs.ipynb """ return outstr + outputC(parity, lhs_strings, filename="returnstring", params="preindent=4")
def StaticTrumpet(ComputeADMGlobalsOnly = False): global Sph_r_th_ph,r,th,ph, gammaSphDD, KSphDD, alphaSph, betaSphU, BSphU # All gridfunctions will be written in terms of spherical coordinates (r, th, ph): r,th,ph = sp.symbols('r th ph', real=True) # Step 0: Set spatial dimension (must be 3 for BSSN) DIM = 3 par.set_parval_from_str("grid::DIM",DIM) # Step 1: Set psi, the conformal factor: # Auxiliary variables: psi0 = sp.symbols('psi0', real=True) # *** The StaticTrumpet conformal factor *** # Dennison and Baumgarte (2014) Eq. 13 # https://arxiv.org/pdf/1403.5484.pdf # psi = sqrt{1 + M/r } psi0 = sp.sqrt(1 + M/r) # *** The physical spatial metric in spherical basis *** # Set the upper-triangle of the matrix... # Eq. 15 # gamma_{ij} = psi^4 * eta_{ij} # eta_00 = 1, eta_11 = r^2, eta_22 = r^2 * sin^2 (theta) gammaSphDD = ixp.zerorank2() gammaSphDD[0][0] = psi0**4 gammaSphDD[1][1] = psi0**4 * r**2 gammaSphDD[2][2] = psi0**4 * r**2*sp.sin(th)**2 # ... then apply symmetries to get the other components # *** The physical trace-free extrinsic curvature in spherical basis *** # Set the upper-triangle of the matrix... # Eq.19 and 20 KSphDD = ixp.zerorank2() # K_{rr} = M / r^2 KSphDD[0][0] = -M / r**2 # K_{theta theta} = K_{phi phi} / sin^2 theta = M KSphDD[1][1] = M KSphDD[2][2] = M * sp.sin(th)**2 # ... then apply symmetries to get the other components # Lapse function and shift vector # Eq. 15 # alpha = r / (r+M) alphaSph = r / (r + M) betaSphU = ixp.zerorank1() # beta^r = Mr / (r + M)^2 betaSphU[0] = M*r / (r + M)**2 BSphU = ixp.zerorank1() if ComputeADMGlobalsOnly == True: return # Validated against original SENR: #print(sp.mathematica_code(gammaSphDD[1][1])) Sph_r_th_ph = [r,th,ph] cf,hDD,lambdaU,aDD,trK,alpha,vetU,betU = \ AtoB.Convert_Spherical_or_Cartesian_ADM_to_BSSN_curvilinear("Spherical", Sph_r_th_ph, gammaSphDD,KSphDD,alphaSph,betaSphU,BSphU) import BSSN.BSSN_ID_function_string as bIDf global returnfunction returnfunction = bIDf.BSSN_ID_function_string(cf, hDD, lambdaU, aDD, trK, alpha, vetU, betU)
def ShiftedKerrSchild(ComputeADMGlobalsOnly = False): global Sph_r_th_ph,r,th,ph, rho2, gammaSphDD, KSphDD, alphaSph, betaSphU, BSphU # All gridfunctions will be written in terms of spherical coordinates (r, th, ph): r,th,ph = sp.symbols('r th ph', real=True) thismodule = "ShiftedKerrSchild" DIM = 3 par.set_parval_from_str("grid::DIM",DIM) # Input parameters: M, a, r0 = par.Cparameters("REAL", thismodule, ["M", "a", "r0"]) # Auxiliary variables: rho2 = sp.symbols('rho2', real=True) # r_{KS} = r + r0 rKS = r+r0 # rho^2 = rKS^2 + a^2*cos^2(theta) rho2 = rKS*rKS + a*a*sp.cos(th)**2 # alpha = 1/sqrt{1 + M*rKS/rho^2} alphaSph = 1/(sp.sqrt(1 + 2*M*rKS/rho2)) # Initialize the shift vector, \beta^i, to zero. betaSphU = ixp.zerorank1() # beta^r = alpha^2*2Mr/rho^2 betaSphU[0] = alphaSph*alphaSph*2*M*rKS/rho2 # Time derivative of shift vector beta^i, B^i, is zero. BSphU = ixp.zerorank1() # Initialize \gamma_{ij} to zero. gammaSphDD = ixp.zerorank2() # gammaDD{rKS rKS} = 1 +2M*rKS/rho^2 gammaSphDD[0][0] = 1 + 2*M*rKS/rho2 # gammaDD{rKS phi} = -a*gammaDD{r r}*sin^2(theta) gammaSphDD[0][2] = gammaSphDD[2][0] = -a*gammaSphDD[0][0]*sp.sin(th)**2 # gammaDD{theta theta} = rho^2 gammaSphDD[1][1] = rho2 # gammaDD{phi phi} = (rKS^2 + a^2 + 2Mr/rho^2*a^2*sin^2(theta))*sin^2(theta) gammaSphDD[2][2] = (rKS*rKS + a*a + 2*M*rKS*a*a*sp.sin(th)**2/rho2)*sp.sin(th)**2 # *** Define Useful Quantities A, B, D *** # A = (a^2*cos^2(2theta) + a^2 + 2r^2) A = (a*a*sp.cos(2*th) + a*a + 2*rKS*rKS) # B = A + 4M*rKS B = A + 4*M*rKS # D = \sqrt(2M*rKS/(a^2cos^2(theta) + rKS^2) + 1) D = sp.sqrt(2*M*rKS/(a*a*sp.cos(th)**2 + rKS*rKS) + 1) # *** The extrinsic curvature in spherical polar coordinates *** # Establish the 3x3 zero-matrix KSphDD = ixp.zerorank2() # *** Fill in the nonzero components *** # *** This will create an upper-triangular matrix *** # K_{r r} = D(A+2Mr)/(A^2*B)[4M(a^2*cos(2theta) + a^2 - 2r^2)] KSphDD[0][0] = D*(A+2*M*rKS)/(A*A*B)*(4*M*(a*a*sp.cos(2*th)+a*a-2*rKS*rKS)) # K_{r theta} = D/(AB)[8a^2*Mr*sin(theta)cos(theta)] KSphDD[0][1] = KSphDD[1][0] = D/(A*B)*(8*a*a*M*rKS*sp.sin(th)*sp.cos(th)) # K_{r phi} = D/A^2[-2aMsin^2(theta)(a^2cos(2theta)+a^2-2r^2)] KSphDD[0][2] = KSphDD[2][0] = D/(A*A)*(-2*a*M*sp.sin(th)**2*(a*a*sp.cos(2*th)+a*a-2*rKS*rKS)) # K_{theta theta} = D/B[4Mr^2] KSphDD[1][1] = D/B*(4*M*rKS*rKS) # K_{theta phi} = D/(AB)*(-8*a^3*Mr*sin^3(theta)cos(theta)) KSphDD[1][2] = KSphDD[2][1] = D/(A*B)*(-8*a**3*M*rKS*sp.sin(th)**3*sp.cos(th)) # K_{phi phi} = D/(A^2*B)[2Mr*sin^2(theta)(a^4(M+3r) # +4a^2r^2(2r-M)+4a^2r*cos(2theta)(a^2+r(M+2r))+8r^5)] KSphDD[2][2] = D/(A*A*B)*(2*M*rKS*sp.sin(th)**2*(a**4*(rKS-M)*sp.cos(4*th)\ + a**4*(M+3*rKS)+4*a*a*rKS*rKS*(2*rKS-M)\ + 4*a*a*rKS*sp.cos(2*th)*(a*a + rKS*(M + 2*rKS)) + 8*rKS**5)) if ComputeADMGlobalsOnly == True: return # Validated against original SENR: #print(sp.mathematica_code(gammaSphDD[1][1])) Sph_r_th_ph = [r,th,ph] cf,hDD,lambdaU,aDD,trK,alpha,vetU,betU = \ AtoB.Convert_Spherical_or_Cartesian_ADM_to_BSSN_curvilinear("Spherical", Sph_r_th_ph, gammaSphDD,KSphDD,alphaSph,betaSphU,BSphU) global returnfunction returnfunction = bIDf.BSSN_ID_function_string(cf,hDD,lambdaU,aDD,trK,alpha,vetU,betU)