#!/usr/bin/env python
# coding: utf-8
#
#
#
# # Converting between the 4-metric $g_{\mu\nu}$ and ADM variables $\left\{\gamma_{ij}, \alpha, \beta^i\right\}$ or BSSN variables $\left\{h_{ij}, {\rm cf}, \alpha, {\rm vet}^i\right\}$
# ## Author: Zach Etienne
#
# [comment]: <> (Abstract: TODO)
#
# ### We will often find it useful to convert between the 4-metric $g_{\mu\nu}$ and the ADM or BSSN variables. This notebook documents the NRPy+ Python module [`BSSN.ADMBSSN_tofrom_4metric`](../edit/BSSN/ADMBSSN_tofrom_4metric.py), which provides that functionality.
#
# **Notebook Status:** Self-validated, some additional tests performed
#
# **Validation Notes:** This tutorial notebook has been confirmed to be self-consistent with its corresponding NRPy+ module, as documented [below](#code_validation). In addition, the construction of $g_{\mu\nu}$ and $g^{\mu\nu}$ from BSSN variables has passed the test $g^{\mu\nu}g_{\mu\nu}=4$ [below](#validationcontraction). **Additional validation tests may have been performed, but are as yet, undocumented. (TODO)**
#
# ### NRPy+ Source Code for this module: [BSSN/ADMBSSN_tofrom_4metric.py](../edit/BSSN/ADMBSSN_tofrom_4metric.py)
#
# ## Introduction:
#
#
#
# # Table of Contents
# $$\label{toc}$$
#
# This notebook is organized as follows
#
# 1. [Step 1](#setup_ADM_quantities): `setup_ADM_quantities(inputvars)`: If `inputvars="ADM"` declare ADM quantities $\left\{\gamma_{ij},\beta^i,\alpha\right\}$; if `inputvars="ADM"` define ADM quantities in terms of BSSN quantities
# 1. [Step 2](#admbssn_to_fourmetric): Write 4-metric $g_{\mu\nu}$ and its inverse $g^{\mu\nu}$ in terms of ADM or BSSN quantities
# 1. [Step 2.a](#admbssn_to_fourmetric_lower): 4-metric $g_{\mu\nu}$ in terms of ADM or BSSN quantities
# 1. [Step 2.b](#admbssn_to_fourmetric_inv): 4-metric inverse $g^{\mu\nu}$ in terms of ADM or BSSN quantities
# 1. [Step 2.c](#validationcontraction): Validation check: Confirm $g_{\mu\nu}g^{\mu\nu}=4$
# 1. [Step 3](#fourmetric_to_admbssn): Write ADM/BSSN metric quantities in terms of 4-metric $g_{\mu\nu}$ (Excludes extrinsic curvature $K_{ij}$ or the BSSN $\bar{A}_{ij}$, $K$)
# 1. [Step 3.a](#adm_ito_fourmetric_validate): ADM in terms of 4-metric validation: Confirm $\gamma_{ij}\gamma^{ij}=3$
# 1. [Step 3.b](#bssn_ito_fourmetric_validate): BSSN in terms of 4-metric validation: Confirm $\bar{\gamma}_{ij}\bar{\gamma}^{ij}=3$
# 1. [Step 4](#code_validation): Code Validation against `BSSN.ADMBSSN_tofrom_4metric` NRPy+ module
# 1. [Step 5](#latex_pdf_output): Output this notebook to $\LaTeX$-formatted PDF file
#
#
# # Step 1: `setup_ADM_quantities(inputvars)`: If `inputvars="ADM"` declare ADM quantities $\left\{\gamma_{ij},\beta^i,\alpha\right\}$; if `inputvars="ADM"` define ADM quantities in terms of BSSN quantities \[Back to [top](#toc)\]
# $$\label{setup_ADM_quantities}$$
# In[1]:
import sympy as sp
import NRPy_param_funcs as par
import indexedexp as ixp
import sys
def setup_ADM_quantities(inputvars):
if inputvars == "ADM":
gammaDD = ixp.declarerank2("gammaDD", "sym01")
betaU = ixp.declarerank1("betaU")
alpha = sp.symbols("alpha", real=True)
elif inputvars == "BSSN":
import BSSN.ADM_in_terms_of_BSSN as AitoB
# Construct gamma_{ij} in terms of cf & gammabar_{ij}
AitoB.ADM_in_terms_of_BSSN()
gammaDD = AitoB.gammaDD
# Next construct beta^i in terms of vet^i and reference metric quantities
import BSSN.BSSN_quantities as Bq
Bq.BSSN_basic_tensors()
betaU = Bq.betaU
alpha = sp.symbols("alpha", real=True)
else:
print("inputvars = " + str(inputvars) + " not supported. Please choose ADM or BSSN.")
sys.exit(1)
return gammaDD,betaU,alpha
#
#
# # Step 2: Write 4-metric $g_{\mu\nu}$ and its inverse $g^{\mu\nu}$ in terms of ADM or BSSN variables \[Back to [top](#toc)\]
# $$\label{admbssn_to_fourmetric}$$
#
#
#
# ## Step 2.a: 4-metric $g_{\mu\nu}$ in terms of ADM or BSSN variables \[Back to [top](#toc)\]
# $$\label{admbssn_to_fourmetric_lower}$$
#
# Given ADM variables $\left\{\gamma_{ij},\beta^i,\alpha \right\}$, which themselves may be written in terms of the rescaled BSSN curvilinear variables $\left\{h_{ij},{\rm cf},\mathcal{V}^i,\alpha \right\}$ for our chosen reference metric via simple function calls to `ADM_in_terms_of_BSSN()` and `BSSN_quantities.BSSN_basic_tensors()`, we are to construct the 4-metric $g_{\mu\nu}$.
#
# We accomplish this via Eq. 2.122 (which can be trivially derived from the ADM 3+1 line element) of Baumgarte & Shapiro's *Numerical Relativity* (henceforth B&S):
# $$
# g_{\mu\nu} = \begin{pmatrix}
# -\alpha^2 + \beta^k \beta_k & \beta_i \\
# \beta_j & \gamma_{ij}
# \end{pmatrix},
# $$
# where the shift vector $\beta^i$ is lowered via (Eq. 2.121):
#
# $$\beta_k = \gamma_{ik} \beta^i.$$
# In[2]:
def g4DD_ito_BSSN_or_ADM(inputvars):
# Step 0: Declare g4DD as globals, to make interfacing with other modules/functions easier
global g4DD
# Step 1: Check that inputvars is set to a supported value
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]
#
#
# ## Step 2.b: Inverse 4-metric $g^{\mu\nu}$ in terms of ADM or BSSN variables \[Back to [top](#toc)\]
# $$\label{admbssn_to_fourmetric_inv}$$
#
# B&S also provide a convenient form for the inverse 4-metric (Eq. 2.119; also Eq. 4.49 in [Gourgoulhon](https://arxiv.org/pdf/gr-qc/0703035.pdf)):
# $$
# g^{\mu\nu} = \gamma^{\mu\nu} - n^\mu n^\nu =
# \begin{pmatrix}
# -\frac{1}{\alpha^2} & \frac{\beta^i}{\alpha^2} \\
# \frac{\beta^i}{\alpha^2} & \gamma^{ij} - \frac{\beta^i\beta^j}{\alpha^2}
# \end{pmatrix},
# $$
# where the unit normal vector to the hypersurface is given by $n^{\mu} = \left(\alpha^{-1},-\beta^i/\alpha\right)$.
# In[3]:
def g4UU_ito_BSSN_or_ADM(inputvars):
# Step 0: Declare g4UU as globals, to make interfacing with other modules/functions easier
global g4UU
# Step 1: Check that inputvars is set to a supported value
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:
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
#
#
# ## Step 2.c: Validation check: Confirm $g_{\mu\nu}g^{\mu\nu}=4$ \[Back to [top](#toc)\]
# $$\label{validationcontraction}$$
#
# Next we compute $g^{\mu\nu} g_{\mu\nu}$ as a validation check. It should equal 4:
# In[4]:
g4DD_ito_BSSN_or_ADM("BSSN")
g4UU_ito_BSSN_or_ADM("BSSN")
contraction = 0
for mu in range(4):
for nu in range(4):
contraction += g4DD[mu][nu]*g4UU[mu][nu]
if sp.simplify(contraction) == sp.sympify(4):
print("TEST PASSED!")
else:
print("TEST FAILED: "+str(contraction)+" does not apparently equal 4.")
sys.exit(1)
#
#
# # Step 3: Write ADM/BSSN metric quantities in terms of 4-metric $g_{\mu\nu}$ (Excludes extrinsic curvature $K_{ij}$, the BSSN $a_{ij}$, $K$, and $\lambda^i$) \[Back to [top](#toc)\]
# $$\label{fourmetric_to_admbssn}$$
#
# Given $g_{\mu\nu}$, we now compute ADM/BSSN metric quantities, excluding extrinsic curvature.
#
# Let's start by computing the ADM quantities in terms of the 4-metric $g_{\mu\nu}$
#
# Recall that
# $$
# g_{\mu\nu} = \begin{pmatrix}
# -\alpha^2 + \beta^k \beta_k & \beta_i \\
# \beta_j & \gamma_{ij}
# \end{pmatrix}.
# $$
#
# From this equation we immediately obtain $\gamma_{ij}$. However we need $\beta^i$ and $\alpha$. After computing the inverse of $\gamma_{ij}$, $\gamma^{ij}$, we raise $\beta_j$ via $\beta^i=\gamma^{ij} \beta_j$ and then compute $\alpha$ via $\alpha = \sqrt{\beta^k \beta_k - g_{00}}$. To convert to BSSN variables $\left\{h_{ij},{\rm cf},\mathcal{V}^i,\alpha \right\}$, we need only convert from ADM via function calls to [`BSSN.BSSN_in_terms_of_ADM`](../edit/BSSN/BSSN_in_terms_of_ADM.py) ([**tutorial**](Tutorial-BSSN_in_terms_of_ADM.ipynb)).
# In[5]:
def BSSN_or_ADM_ito_g4DD(inputvars):
# 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 = ixp.declarerank2("g4DD","sym01",DIM=4)
# 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}):
alpha = sp.sqrt(sp.simplify(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 & return hDD, cf,
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
#
#
# ## Step 3.a: ADM in terms of 4-metric validation: Confirm $\gamma_{ij}\gamma^{ij}=3$ \[Back to [top](#toc)\]
# $$\label{adm_ito_fourmetric_validate}$$
#
# Next we compute $\gamma^{ij} \gamma_{ij}$ as a validation check. It should equal 3:
# In[6]:
BSSN_or_ADM_ito_g4DD("ADM")
gammaUU, gammaDET = ixp.symm_matrix_inverter3x3(gammaDD)
contraction = sp.sympify(0)
for i in range(3):
for j in range(3):
contraction += gammaDD[i][j]*gammaUU[i][j]
if sp.simplify(contraction) == sp.sympify(3):
print("TEST PASSED!")
else:
print("TEST FAILED: "+str(contraction)+" does not apparently equal 3.")
sys.exit(1)
#
#
# ## Step 3.b: BSSN in terms of 4-metric validation: Confirm $\bar{\gamma}_{ij}\bar{\gamma}^{ij}=3$ \[Back to [top](#toc)\]
# $$\label{bssn_ito_fourmetric_validate}$$
#
# Next we compute $\bar{\gamma}_{ij}\bar{\gamma}^{ij}$ as a validation check. It should equal 3:
# In[7]:
import reference_metric as rfm
par.set_parval_from_str("reference_metric::CoordSystem","SinhCylindrical")
rfm.reference_metric()
BSSN_or_ADM_ito_g4DD("BSSN")
gammabarDD = ixp.zerorank2()
for i in range(3):
for j in range(3):
# gammabar_{ij} = h_{ij}*ReDD[i][j] + gammahat_{ij}
gammabarDD[i][j] = hDD[i][j] * rfm.ReDD[i][j] + rfm.ghatDD[i][j]
gammabarUU, gammabarDET = ixp.symm_matrix_inverter3x3(gammabarDD)
contraction = sp.sympify(0)
for i in range(3):
for j in range(3):
contraction += gammabarDD[i][j]*gammabarUU[i][j]
if sp.simplify(contraction) == sp.sympify(3):
print("TEST PASSED!")
else:
print("TEST FAILED: "+str(contraction)+" does not apparently equal 3.")
sys.exit(1)
#
#
# ## Step 4: Code Validation against `BSSN.ADMBSSN_tofrom_4metric` NRPy+ module \[Back to [top](#toc)\]
# $$\label{code_validation}$$
#
# Here, as a code validation check, we verify agreement in the SymPy expressions for BrillLindquist initial data between
# 1. this tutorial and
# 2. the NRPy+ [BSSN.ADMBSSN_tofrom_4metric](../edit/BSSN/ADMBSSN_tofrom_4metric.py) module.
#
# By default, we analyze these expressions in SinhCylindrical coordinates, though other coordinate systems may be chosen.
# In[8]:
par.set_parval_from_str("reference_metric::CoordSystem","SinhCylindrical")
rfm.reference_metric()
import BSSN.ADMBSSN_tofrom_4metric as AB4m
for inputvars in ["BSSN","ADM"]:
g4DD_ito_BSSN_or_ADM(inputvars)
AB4m.g4DD_ito_BSSN_or_ADM(inputvars)
for i in range(4):
for j in range(4):
print(inputvars+" input: g4DD["+str(i)+"]["+str(j)+"] - g4DD_mod["+str(i)+"]["
+str(j)+"] = "+str(g4DD[i][j]-AB4m.g4DD[i][j]))
g4UU_ito_BSSN_or_ADM(inputvars)
AB4m.g4UU_ito_BSSN_or_ADM(inputvars)
for i in range(4):
for j in range(4):
print(inputvars+" input: g4UU["+str(i)+"]["+str(j)+"] - g4UU_mod["+str(i)+"]["
+str(j)+"] = "+str(g4UU[i][j]-AB4m.g4UU[i][j]))
BSSN_or_ADM_ito_g4DD("BSSN")
AB4m.BSSN_or_ADM_ito_g4DD("BSSN")
print("BSSN QUANTITIES (ito 4-metric g4DD)")
print("cf - mod_cf = " + str(cf - AB4m.cf))
print("alpha - mod_alpha = " + str(alpha - AB4m.alpha))
for i in range(3):
print("vetU["+str(i)+"] - mod_vetU["+str(i)+"] = " + str(vetU[i] - AB4m.vetU[i]))
for j in range(3):
print("hDD["+str(i)+"]["+str(j)+"] - mod_hDD["+str(i)+"]["+str(j)+"] = "
+ str(hDD[i][j] - AB4m.hDD[i][j]))
BSSN_or_ADM_ito_g4DD("ADM")
AB4m.BSSN_or_ADM_ito_g4DD("ADM")
print("ADM QUANTITIES (ito 4-metric g4DD)")
print("alpha - mod_alpha = " + str(alpha - AB4m.alpha))
for i in range(3):
print("betaU["+str(i)+"] - mod_betaU["+str(i)+"] = " + str(betaU[i] - AB4m.betaU[i]))
for j in range(3):
print("gammaDD["+str(i)+"]["+str(j)+"] - mod_gammaDD["+str(i)+"]["+str(j)+"] = "
+ str(gammaDD[i][j] - AB4m.gammaDD[i][j]))
#
#
# # Step 4: Output this notebook to $\LaTeX$-formatted PDF file \[Back to [top](#toc)\]
# $$\label{latex_pdf_output}$$
#
# 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-ADMBSSN_tofrom_4metric.pdf](Tutorial-ADMBSSN_tofrom_4metric.pdf) (Note that clicking on this link may not work; you may need to open the PDF file through another means.)
# In[9]:
import cmdline_helper as cmd # NRPy+: Multi-platform Python command-line interface
cmd.output_Jupyter_notebook_to_LaTeXed_PDF("Tutorial-ADMBSSN_tofrom_4metric")