#!/usr/bin/env python # coding: utf-8 # # # # # Tutorial-IllinoisGRMHD: `convert_ADM_to_BSSN__enforce_detgtij_eq_1__and_compute_gtupij.C` # # ## Authors: Leo Werneck & Zach Etienne # # **This module is currently under development** # # ## This tutorial module explains the algorithm used to get the BSSN variables from the ADM variables. Further, it outlines how to impose the constraint that the conformal metric has a unit determinant. # # ### Required and recommended citations: # # * **(Required)** Etienne, Z. B., Paschalidis, V., Haas R., Mösta P., and Shapiro, S. L. IllinoisGRMHD: an open-source, user-friendly GRMHD code for dynamical spacetimes. Class. Quantum Grav. 32 (2015) 175009. ([arxiv:1501.07276](http://arxiv.org/abs/1501.07276)). # * **(Required)** Noble, S. C., Gammie, C. F., McKinney, J. C., Del Zanna, L. Primitive Variable Solvers for Conservative General Relativistic Magnetohydrodynamics. Astrophysical Journal, 641, 626 (2006) ([astro-ph/0512420](https://arxiv.org/abs/astro-ph/0512420)). # * **(Recommended)** Del Zanna, L., Bucciantini N., Londrillo, P. An efficient shock-capturing central-type scheme for multidimensional relativistic flows - II. Magnetohydrodynamics. A&A 400 (2) 397-413 (2003). DOI: 10.1051/0004-6361:20021641 ([astro-ph/0210618](https://arxiv.org/abs/astro-ph/0210618)). # # # # Table of Contents # $$\label{toc}$$ # # This module is organized as follows # # 0. [Step 0](#src_dir): **Source directory creation** # 1. [Step 1](#introduction): **Introduction** # 1. [Step 2](#convert_adm_to_bssn__det_gammabar_eq_1): **`convert_ADM_to_BSSN__enforce_detgtij_eq_1__and_compute_gtupij.C`** # 1. [Step 2.a](#physical_metric_and_its_determinant): *Loading the physical metric $\gamma_{ij}$ and computing $\gamma = \det\left(\gamma_{ij}\right)$* # 1. [Step 2.b](#phi_and_psi): *Computing $\phi$ and $\psi$* # 1. [Step 2.c](#enforce_det_gammabar_eq_1): *Enforcing the constraint $\bar\gamma = 1$* # 1. [Step 2.d](#update_gfs): *Updating the gridfunctions* # 1. [Step 3](#code_validation): **Code validation** # 1. [Step 4](#latex_pdf_output): **Output this notebook to $\LaTeX$-formatted PDF file** # # # # Step 0: Source directory creation \[Back to [top](#toc)\] # $$\label{src_dir}$$ # # We will now use the [cmdline_helper.py NRPy+ module](Tutorial-Tutorial-cmdline_helper.ipynb) to create the source directory within the `IllinoisGRMHD` NRPy+ directory if it does not exist yet. # In[1]: # Step 0: Creation of the IllinoisGRMHD source directory # Step 0a: Add NRPy's directory to the path # https://stackoverflow.com/questions/16780014/import-file-from-parent-directory import os,sys nrpy_dir_path = os.path.join("..","..") if nrpy_dir_path not in sys.path: sys.path.append(nrpy_dir_path) # Step 0b: Load up cmdline_helper and create the directory import cmdline_helper as cmd IGM_src_dir_path = os.path.join("..","src") cmd.mkdir(IGM_src_dir_path) # Step 0c: Create the output file path outfile_path__ADM_to_BSSN__det_gammabar_eq_1__C = os.path.join(IGM_src_dir_path,"convert_ADM_to_BSSN__enforce_detgtij_eq_1__and_compute_gtupij.C") # # # # Step 1: Introduction \[Back to [top](#toc)\] # $$\label{introduction}$$ # # In this module, we will explain the procedure used within `IllinoisGRMHD` to compute the conformal metric, $\bar\gamma_{ij}$, and its inverse, $\bar\gamma^{ij}$, from the physical metric $\gamma_{ij}$. We will also describe how to compute $\phi$, the conformal factor, and $\psi\equiv e^{\phi}$. Finally, we also explain the procedure used to enforce the constraint $\bar\gamma = \det\left(\bar\gamma_{ij}\right) = 1$. # # **A note on notation**: The notation used throughout the NRPy tutorial notebooks for the conformal metric is $\bar\gamma_{ij}$. However, in the literature, the notation $\tilde\gamma_{ij}$ is also used to represent the conformal metric. It is important to note that in `IllinoisGRMHD` we refer to the conformal metric using the *latter* notation, i.e. ${\rm gtij} := \tilde\gamma_{ij}$ and ${\rm gtupij} := \tilde\gamma^{ij}$. To keep the discussion consistent with the other notebooks, however, we will still present the discussion using the notation $\tilde\gamma_{ij} \to \bar\gamma_{ij}$. Bottom line, here $\tilde\gamma_{ij}$ and $\bar\gamma_{ij}$ represent exactly the same quantity, the conformal metric. # # # # Step 2: `convert_ADM_to_BSSN__enforce_detgtij_eq_1__and_compute_gtupij.C` \[Back to [top](#toc)\] # $$\label{convert_adm_to_bssn__det_gammabar_eq_1}$$ # # # # ## Step 2.a: Loading the physical metric $\gamma_{ij}$ and computing $\gamma = \det\left(\gamma_{ij}\right)$ \[Back to [top](#toc)\] # $$\label{physical_metric_and_its_determinant}$$ # # We start by reading in the physical metric ${\rm gij\_physL} := \gamma_{ij}$ and computing its determinant # # $$ # \boxed{ # \begin{align} # \gamma = \det\left(\gamma_{ij}\right) # &= \gamma_{xx}\gamma_{yy}\gamma_{zz} + \gamma_{xy}\gamma_{yz}\gamma_{xz} + \gamma_{xz}\gamma_{xy}\gamma_{yz}\\ # &- \gamma_{xz}\gamma_{yy}\gamma_{xz} - \gamma_{xy}\gamma_{xy}\gamma_{zz} - \gamma_{xx}\gamma_{yz}\gamma_{yz} # \end{align} # }\ . # $$ # # Notice that we have used the fact that $\gamma_{ij}$ is symmetric above, i.e. $\gamma_{ij}=\gamma_{ji}$. # In[2]: get_ipython().run_cell_magic('writefile', '$outfile_path__ADM_to_BSSN__det_gammabar_eq_1__C', '#include \n#include \n#include \n#ifndef ENABLE_STANDALONE_IGM_C2P_SOLVER\n#include "cctk.h"\n#include "cctk_Parameters.h"\n#endif\n\nvoid IllinoisGRMHD_convert_ADM_to_BSSN__enforce_detgtij_eq_1__and_compute_gtupij\n(const cGH *cctkGH,const int *cctk_lsh,\n CCTK_REAL *gxx,CCTK_REAL *gxy,CCTK_REAL *gxz,CCTK_REAL *gyy,CCTK_REAL *gyz,CCTK_REAL *gzz,CCTK_REAL *alp,\n CCTK_REAL *gtxx,CCTK_REAL *gtxy,CCTK_REAL *gtxz,CCTK_REAL *gtyy,CCTK_REAL *gtyz,CCTK_REAL *gtzz,\n CCTK_REAL *gtupxx,CCTK_REAL *gtupxy,CCTK_REAL *gtupxz,CCTK_REAL *gtupyy,CCTK_REAL *gtupyz,CCTK_REAL *gtupzz,\n CCTK_REAL *phi,CCTK_REAL *psi,CCTK_REAL *lapm1) {\n\n#ifndef ENABLE_STANDALONE_IGM_C2P_SOLVER\n DECLARE_CCTK_PARAMETERS;\n#endif\n\n\n#pragma omp parallel for\n for(int k=0;k # # ## Step 2.b: Computing $\phi$ and $\psi$ \[Back to [top](#toc)\] # $$\label{phi_and_psi}$$ # # The BSSN formalism relates the physical metric, $\gamma_{ij}$, to a conformal metric, $\bar\gamma{ij}$, via the relation # # $$ # \boxed{\bar\gamma_{ij} = e^{-4\phi}\gamma_{ij}}\ , # $$ # # with the constraint that $\bar\gamma \equiv \det\left(\bar\gamma_{ij}\right) = 1$. This immediately implies that # # $$ # e^{-12\phi} \gamma = \bar\gamma = 1 \implies -12\phi = \log\left(\frac{1}{\gamma}\right) = - \log\gamma # \implies \boxed{\phi = \frac{1}{12}\log\gamma}\ . # $$ # # Useful quantities to compute are # # $$ # \boxed{ # \begin{align} # \psi &\equiv e^{\phi}\\ # \psi^{-4} &\equiv e^{-4\phi} # \end{align} # }\ . # $$ # # All the boxed quantities above are evaluated below. # In[3]: get_ipython().run_cell_magic('writefile', '-a $outfile_path__ADM_to_BSSN__det_gammabar_eq_1__C', '\n\n CCTK_REAL phiL = (1.0/12.0) * log(gijdet);\n CCTK_REAL psiL = exp(phiL);\n\n CCTK_REAL Psim4 = 1.0/(psiL*psiL*psiL*psiL);\n CCTK_REAL gtxxL = gxx_physL*Psim4;\n CCTK_REAL gtxyL = gxy_physL*Psim4;\n CCTK_REAL gtxzL = gxz_physL*Psim4;\n CCTK_REAL gtyyL = gyy_physL*Psim4;\n CCTK_REAL gtyzL = gyz_physL*Psim4;\n CCTK_REAL gtzzL = gzz_physL*Psim4;\n') # # # ## Step 2.c: Enforcing the constraint $\bar\gamma = 1$ \[Back to [top](#toc)\] # $$\label{enforce_det_gammabar_eq_1}$$ # # The BSSN formalism evolves the determinant of the conformal metric through $\partial_{t}\bar\gamma = 0$. Since initially $\bar\gamma=1$, one would expect that $\bar\gamma=1$ at all times. However, numerical errors can cause the value of the determinant of the conformal metric to drift away from unity. To remedy this, we enforce the constraint $\bar\gamma=1$ by transforming the conformal metric according to the algebraic condition (cf. eq. 53 of [Ruchlin, Etienne, and Baumgarte (2018)](https://arxiv.org/pdf/1712.07658.pdf) with $\hat\gamma = 1$). # # $$ # \boxed{\bar{\gamma}_{ij} \to \left(\frac{1}{\bar{\gamma}}\right)^{1/3} \bar{\gamma}_{ij}}\ . # $$ # # We then start by evaluating # # $$ # \boxed{ # \begin{align} # \bar\gamma = \det\left(\bar\gamma_{ij}\right) # &= \bar\gamma_{xx}\bar\gamma_{yy}\bar\gamma_{zz} + \bar\gamma_{xy}\bar\gamma_{yz}\bar\gamma_{xz} + \bar\gamma_{xz}\bar\gamma_{xy}\bar\gamma_{yz}\\ # &- \bar\gamma_{xz}\bar\gamma_{yy}\bar\gamma_{xz} - \bar\gamma_{xy}\bar\gamma_{xy}\bar\gamma_{zz} - \bar\gamma_{xx}\bar\gamma_{yz}\bar\gamma_{yz} # \end{align} # }\ . # $$ # # In the code below we also define # # $$ # \boxed{{\rm gtijdet\_Fm1o3} = \left(\frac{1}{\bar{\gamma}}\right)^{1/3}}\ . # $$ # In[4]: get_ipython().run_cell_magic('writefile', '-a $outfile_path__ADM_to_BSSN__det_gammabar_eq_1__C', '\n\n /*********************************\n * Apply det gtij = 1 constraint *\n *********************************/\n CCTK_REAL gtijdet = gtxxL * gtyyL * gtzzL + gtxyL * gtyzL * gtxzL + gtxzL * gtxyL * gtyzL -\n gtxzL * gtyyL * gtxzL - gtxyL * gtxyL * gtzzL - gtxxL * gtyzL * gtyzL;\n\n CCTK_REAL gtijdet_Fm1o3 = fabs(1.0/cbrt(gtijdet));\n\n gtxxL = gtxxL * gtijdet_Fm1o3;\n gtxyL = gtxyL * gtijdet_Fm1o3;\n gtxzL = gtxzL * gtijdet_Fm1o3;\n gtyyL = gtyyL * gtijdet_Fm1o3;\n gtyzL = gtyzL * gtijdet_Fm1o3;\n gtzzL = gtzzL * gtijdet_Fm1o3;\n\n if(gtijdet<0.0) {\n#ifndef ENABLE_STANDALONE_IGM_C2P_SOLVER\n CCTK_VWarn(CCTK_WARN_ALERT,__LINE__, __FILE__, CCTK_THORNSTRING,\n#else\n fprintf(stderr,\n#endif\n"WARNING: det[3-metric]<0.0 at point %d %d %d | cctk_lsh: %d %d %d. Hopefully this is occurring in gz\'s! gtij_phys = %.2e %.2e %.2e %.2e %.2e %.2e gtij_new = %.2e %.2e %.2e %.2e %.2e %.2e | gijdet = %.2e | gtijdet = %.2e\\n",\ni,j,k,cctk_lsh[0],cctk_lsh[1],cctk_lsh[2],gxx_physL,gxy_physL,gxz_physL,gyy_physL,gyz_physL,gzz_physL,gtxxL,gtxyL,gtxzL,gtyyL,gtyzL,gtzzL,-gijdet,gtijdet);\n}\n') # # # ## Step 2.d: Updating the gridfunctions \[Back to [top](#toc)\] # $$\label{update_gfs}$$ # # Finally, we update the gridfunctions for $\phi$, $\psi$, $\bar\gamma_{ij}$, $\gamma_{ij}$, and $\bar\gamma^{ij}$, respectively, in the code below. # # If $\mathcal{M}$ is a $3\times3$ symmetric matrix and $\det(\mathcal{M})\neq0$, [recall that we have](https://en.wikipedia.org/wiki/Invertible_matrix#Inversion_of_3_%C3%97_3_matrices) # # $$ # \mathcal{M}^{-1} = # \begin{pmatrix} # a & b & c\\ # b & d & e\\ # c & e & f # \end{pmatrix}^{-1} # = # \frac{1}{\det(\mathcal{M})} # \begin{pmatrix} # A & B & C\\ # B & D & E\\ # C & E & F # \end{pmatrix}\ , # $$ # # where # # $$ # \boxed{ # \begin{align} # A &= \ \ \left(df - ee\right)\\ # B &= -\left(bf - ce\right)\\ # C &= \ \ \left(be - cd\right)\\ # D &= \ \ \left(af - cc\right)\\ # E &= -\left(ae - bc\right)\\ # F &= \ \ \left(ad - bb\right) # \end{align} # }\ . # $$ # # Notice that if we replace $\mathcal{M}\to\bar\gamma_{ij}$, then we have also $\det(\mathcal{M})\to1$. # In[5]: get_ipython().run_cell_magic('writefile', '-a $outfile_path__ADM_to_BSSN__det_gammabar_eq_1__C', '\n\n CCTK_REAL Psi4 = psiL*psiL*psiL*psiL;\n /*****************************************\n * Set all the needed BSSN gridfunctions *\n *****************************************/\n phi[index] = phiL;\n psi[index] = psiL;\n\n lapm1[index] = alp[index] - 1.0;\n\n gtxx[index] = gtxxL;\n gtxy[index] = gtxyL;\n gtxz[index] = gtxzL;\n gtyy[index] = gtyyL;\n gtyz[index] = gtyzL;\n gtzz[index] = gtzzL;\n\n gxx[index] = gtxxL*Psi4;\n gxy[index] = gtxyL*Psi4;\n gxz[index] = gtxzL*Psi4;\n gyy[index] = gtyyL*Psi4;\n gyz[index] = gtyzL*Psi4;\n gzz[index] = gtzzL*Psi4;\n\n gtupxx[index] = ( gtyyL * gtzzL - gtyzL * gtyzL );\n gtupxy[index] = - ( gtxyL * gtzzL - gtyzL * gtxzL );\n gtupxz[index] = ( gtxyL * gtyzL - gtyyL * gtxzL );\n gtupyy[index] = ( gtxxL * gtzzL - gtxzL * gtxzL );\n gtupyz[index] = - ( gtxxL * gtyzL - gtxyL * gtxzL );\n gtupzz[index] = ( gtxxL * gtyyL - gtxyL * gtxyL );\n }\n}\n\n') # # # # Step 3: Code validation \[Back to [top](#toc)\] # $$\label{code_validation}$$ # # First, we download the original `IllinoisGRMHD` source code and then compare it to the source code generated by this tutorial notebook. # In[6]: # Verify if the code generated by this tutorial module # matches the original IllinoisGRMHD source code # First download the original IllinoisGRMHD source code import urllib from os import path original_IGM_file_url = "https://bitbucket.org/zach_etienne/wvuthorns/raw/5611b2f0b17135538c9d9d17c7da062abe0401b6/IllinoisGRMHD/src/convert_ADM_to_BSSN__enforce_detgtij_eq_1__and_compute_gtupij.C" original_IGM_file_name = "convert_ADM_to_BSSN__enforce_detgtij_eq_1__and_compute_gtupij-original.C" original_IGM_file_path = os.path.join(IGM_src_dir_path,original_IGM_file_name) # Then download the original IllinoisGRMHD source code # We try it here in a couple of ways in an attempt to keep # the code more portable try: original_IGM_file_code = urllib.request.urlopen(original_IGM_file_url).read().decode("utf-8") # Write down the file the original IllinoisGRMHD source code with open(original_IGM_file_path,"w") as file: file.write(original_IGM_file_code) except: try: original_IGM_file_code = urllib.urlopen(original_IGM_file_url).read().decode("utf-8") # Write down the file the original IllinoisGRMHD source code with open(original_IGM_file_path,"w") as file: file.write(original_IGM_file_code) except: # If all else fails, hope wget does the job get_ipython().system('wget -O $original_IGM_file_path $original_IGM_file_url') # Perform validation Validation__ADM_to_BSSN__det_gammabar_eq_1__C = get_ipython().getoutput('diff $original_IGM_file_path $outfile_path__ADM_to_BSSN__det_gammabar_eq_1__C') if Validation__ADM_to_BSSN__det_gammabar_eq_1__C == []: # If the validation passes, we do not need to store the original IGM source code file get_ipython().system('rm $original_IGM_file_path') print("Validation test for convert_ADM_to_BSSN__enforce_detgtij_eq_1__and_compute_gtupij.C: PASSED!") else: # If the validation fails, we keep the original IGM source code file print("Validation test for convert_ADM_to_BSSN__enforce_detgtij_eq_1__and_compute_gtupij.C: FAILED!") # We also print out the difference between the code generated # in this tutorial module and the original IGM source code print("Diff:") for diff_line in Validation__ADM_to_BSSN__det_gammabar_eq_1__C: print(diff_line) # # # # 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-IllinoisGRMHD__convert_ADM_to_BSSN__enforce_detgtij_eq_1__and_compute_gtupij.pdf](Tutorial-IllinoisGRMHD__convert_ADM_to_BSSN__enforce_detgtij_eq_1__and_compute_gtupij.pdf) (Note that clicking on this link may not work; you may need to open the PDF file through another means). # In[7]: latex_nrpy_style_path = os.path.join(nrpy_dir_path,"latex_nrpy_style.tplx") #!jupyter nbconvert --to latex --template $latex_nrpy_style_path --log-level='WARN' Tutorial-IllinoisGRMHD__convert_ADM_to_BSSN__enforce_detgtij_eq_1__and_compute_gtupij.ipynb #!pdflatex -interaction=batchmode Tutorial-IllinoisGRMHD__convert_ADM_to_BSSN__enforce_detgtij_eq_1__and_compute_gtupij.tex #!pdflatex -interaction=batchmode Tutorial-IllinoisGRMHD__convert_ADM_to_BSSN__enforce_detgtij_eq_1__and_compute_gtupij.tex #!pdflatex -interaction=batchmode Tutorial-IllinoisGRMHD__convert_ADM_to_BSSN__enforce_detgtij_eq_1__and_compute_gtupij.tex get_ipython().system('rm -f Tut*.out Tut*.aux Tut*.log')