{
 "cells": [
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "<script async src=\"https://www.googletagmanager.com/gtag/js?id=UA-59152712-8\"></script>\n",
    "<script>\n",
    "  window.dataLayer = window.dataLayer || [];\n",
    "  function gtag(){dataLayer.push(arguments);}\n",
    "  gtag('js', new Date());\n",
    "\n",
    "  gtag('config', 'UA-59152712-8');\n",
    "</script>\n",
    "\n",
    "# Start-to-Finish Example: `GiRaFFE_NRPy` 1D tests\n",
    "\n",
    "### Authors: Terrence Pierre Jacques\n",
    "\n",
    "### Adapted from [Start-to-Finish Example: Head-On Black Hole Collision](../Tutorial-Start_to_Finish-BSSNCurvilinear-Two_BHs_Collide.ipynb)\n",
    "\n",
    "## This module compiles and runs code tests for all 1D initial data options available in GiRaFFE-NRPy+, evolving one-dimensional GRFFE waves.\n",
    "\n",
    "### NRPy+ Source Code for this module: \n",
    "\n",
    "* Main python module for all 1D initial data: [GiRaFFEfood_NRPy/GiRaFFEfood_NRPy_1D_tests.py](../../edit/in_progress/GiRaFFEfood_NRPy/GiRaFFEfood_NRPy_1D_tests.py) __Options:__\n",
    "    1. [Fast Wave](Tutorial-GiRaFFEfood_NRPy_1D_tests-fast_wave.ipynb)\n",
    "    1. [Alfven Wave](Tutorial-GiRaFFEfood_NRPy_1D_alfven_wave.ipynb)\n",
    "    1. [Degenerate Alfven Wave](Tutorial-GiRaFFEfood_NRPy_1D_tests-degen_Alfven_wave.ipynb)\n",
    "    1. [Three Alfven Waves](Tutorial-GiRaFFEfood_NRPy_1D_tests-three_waves.ipynb)\n",
    "    1. [FFE Breakdown](Tutorial-GiRaFFEfood_NRPy_1D_tests-FFE_breakdown.ipynb)"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "<a id='toc'></a>\n",
    "\n",
    "# Table of Contents\n",
    "$$\\label{toc}$$\n",
    "\n",
    "This notebook is organized as follows\n",
    "\n",
    "1. [Step 1](#initializenrpy): Set core NRPy+ parameters for numerical grids\n",
    "1. [Step 2](#grffe): Output C code for GRFFE evolution\n",
    "    1. [Step 2.a](#mol): Output macros for Method of Lines timestepping\n",
    "1. [Step 3](#gf_id): Import `GiRaFFEfood_NRPy` initial data modules\n",
    "1. [Step 4](#cparams): Output C codes needed for declaring and setting Cparameters; also set `free_parameters.h`\n",
    "1. [Step 5](#mainc): `GiRaFFE_NRPy_standalone.c`: The Main C Code\n",
    "1. [Step 6](#compileexec): Compile and execute C codes\n",
    "1. [Step 7](#plots): Data Visualization\n",
    "1. [Step 8](#latex_pdf_output): Output this notebook to $\\LaTeX$-formatted PDF file"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "<a id='setup'></a>\n",
    "\n",
    "# Step 1: Set up core functions and parameters for solving  GRFFE equations \\[Back to [top](#toc)\\]\n",
    "$$\\label{setup}$$\n"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 1,
   "metadata": {
    "execution": {
     "iopub.execute_input": "2020-12-17T02:16:18.636228Z",
     "iopub.status.busy": "2020-12-17T02:16:18.635743Z",
     "iopub.status.idle": "2020-12-17T02:16:18.864857Z",
     "shell.execute_reply": "2020-12-17T02:16:18.864334Z"
    }
   },
   "outputs": [],
   "source": [
    "import os, sys           # Standard Python modules for multiplatform OS-level functions\n",
    "# First, we'll add the parent directory to the list of directories Python will check for modules.\n",
    "nrpy_dir_path = os.path.join(\"..\")\n",
    "if nrpy_dir_path not in sys.path:\n",
    "    sys.path.append(nrpy_dir_path)\n",
    "\n",
    "# Import needed Python modules\n",
    "import NRPy_param_funcs as par   # NRPy+: Parameter interface\n",
    "import indexedexp as ixp         # NRPy+: Symbolic indexed expression (e.g., tensors, vectors, etc.) support\n",
    "import reference_metric as rfm   # NRPy+: Reference metric support\n",
    "import sympy as sp                # SymPy: The Python computer algebra package upon which NRPy+ depends\n",
    "\n",
    "#Step 0: Set the spatial dimension parameter to 3.\n",
    "par.set_parval_from_str(\"grid::DIM\", 3)\n",
    "DIM = par.parval_from_str(\"grid::DIM\")\n",
    "\n",
    "# TINYDOUBLE = par.Cparameters(\"REAL\", \"TINYDOUBLE\", 1e-100)\n",
    "\n",
    "\n",
    "# Choices are: Spherical, SinhSpherical, SinhSphericalv2, Cylindrical, SinhCylindrical,\n",
    "#              SymTP, SinhSymTP\n",
    "dst_basis = \"Cartesian\"\n",
    "\n",
    "# Set coordinate system to dst_basis\n",
    "par.set_parval_from_str(\"reference_metric::CoordSystem\",dst_basis)\n",
    "rfm.reference_metric()"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "<a id='gf_id'></a>\n",
    "\n",
    "# Step 3: Import `GiRaFFEfood_NRPy` initial data modules \\[Back to [top](#toc)\\]\n",
    "$$\\label{gf_id}$$\n",
    "\n",
    "With the preliminaries out of the way, we will write the C functions to set up initial data. There are two categories of initial data that must be set: the spacetime metric variables, and the GRFFE plasma variables. We will set up the spacetime first, namely the Minkowski spacetime."
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "Now, we will write out the initials data function for the GRFFE variables."
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 2,
   "metadata": {
    "execution": {
     "iopub.execute_input": "2020-12-17T02:16:31.788778Z",
     "iopub.status.busy": "2020-12-17T02:16:31.788338Z",
     "iopub.status.idle": "2020-12-17T02:16:31.933819Z",
     "shell.execute_reply": "2020-12-17T02:16:31.933356Z"
    }
   },
   "outputs": [],
   "source": [
    "ID_opts = [\"AlfvenWave\", \"ThreeAlfvenWaves\", \"DegenAlfvenWave\", \"FastWave\", \"FFEBD\"]\n",
    "\n",
    "# for initial_data in ID_opts:\n",
    "initial_data = \"FFEBD\"\n",
    "\n",
    "if initial_data==\"AlfvenWave\":\n",
    "    import GiRaFFEfood_NRPy.GiRaFFEfood_NRPy_1D_tests as gid\n",
    "    gid.GiRaFFEfood_NRPy_1D_tests(stagger = True)\n",
    "    desc = \"Generate Alfven wave 1D initial data for GiRaFFEfood_NRPy.\"\n",
    "elif initial_data==\"ThreeAlfvenWaves\":\n",
    "    import GiRaFFEfood_NRPy.GiRaFFEfood_NRPy_1D_tests_three_waves as gid\n",
    "    gid.GiRaFFEfood_NRPy_1D_tests_three_waves(stagger = True)\n",
    "    desc = \"Generate three Alfven wave 1D initial data for GiRaFFEfood_NRPy.\"\n",
    "elif initial_data==\"DegenAlfvenWave\":\n",
    "    import GiRaFFEfood_NRPy.GiRaFFEfood_NRPy_1D_tests_degen_Alfven_wave as gid\n",
    "    gid.GiRaFFEfood_NRPy_1D_tests_degen_Alfven_wave(stagger = True)\n",
    "    desc = \"Generate degenerate Alfven wave 1D initial data for GiRaFFEfood_NRPy.\"\n",
    "elif initial_data==\"FastWave\":\n",
    "    import GiRaFFEfood_NRPy.GiRaFFEfood_NRPy_1D_tests_fast_wave as gid\n",
    "    gid.GiRaFFEfood_NRPy_1D_tests_fast_wave(stagger = True)\n",
    "    desc = \"Generate fast wave 1D initial data for GiRaFFEfood_NRPy.\"\n",
    "elif initial_data==\"FFEBD\":\n",
    "    import GiRaFFEfood_NRPy.GiRaFFEfood_NRPy_1D_tests_FFE_breakdown as gid\n",
    "    gid.GiRaFFEfood_NRPy_1D_tests_FFE_breakdown(stagger = True)\n",
    "    desc = \"Generate FFE breakdown 1D initial data for GiRaFFEfood_NRPy.\"\n"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "We define Jacobians relative to the center of the destination grid, at a point $x^j_{\\rm dst}=$(`xx0,xx1,xx2`)${}_{\\rm dst}$ on the destination grid:\n",
    "$$\n",
    "{\\rm Jac\\_dUCart\\_dDdstUD[i][j]} = \\frac{\\partial x^i_{\\rm Cart}}{\\partial x^j_{\\rm dst}},\n",
    "$$\n",
    "\n",
    "via exact differentiation (courtesy SymPy), and the inverse Jacobian\n",
    "$$\n",
    "{\\rm Jac\\_dUdst\\_dDCartUD[i][j]} = \\frac{\\partial x^i_{\\rm dst}}{\\partial x^j_{\\rm Cart}},\n",
    "$$\n",
    "\n",
    "using NRPy+'s `generic_matrix_inverter3x3()` function. In terms of these, the transformation of BSSN tensors from Cartesian to the destination grid's `\"reference_metric::CoordSystem\"` coordinates may be written:\n",
    "\n",
    "$$\n",
    "B^i_{\\rm dst} = \\frac{\\partial x^i_{\\rm dst}}{\\partial x^\\ell_{\\rm Cart}} B^\\ell_{\\rm Cart},\n",
    "$$\n",
    "\n",
    "while for lowered indices we have\n",
    "\n",
    "$$\n",
    "A^{\\rm dst}_{i} = \n",
    "\\frac{\\partial x^\\ell_{\\rm Cart}}{\\partial x^i_{\\rm dst}} A^{\\rm Cart}_{\\ell}\\\\\n",
    "$$\n"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 3,
   "metadata": {},
   "outputs": [],
   "source": [
    "# Step 3: Transform BSSN tensors in Cartesian basis to destination grid basis, using center of dest. grid as origin\n",
    "\n",
    "# Step 3.a: Next construct Jacobian and inverse Jacobian matrices:\n",
    "Jac_dUCart_dDrfmUD,Jac_dUrfm_dDCartUD = rfm.compute_Jacobian_and_inverseJacobian_tofrom_Cartesian()\n",
    "\n",
    "# Step 3.b: Convert basis of all BSSN *vectors* from Cartesian to destination basis\n",
    "BU_dst = rfm.basis_transform_vectorU_from_Cartesian_to_rfmbasis(Jac_dUrfm_dDCartUD, gid.BU)\n",
    "\n",
    "ValenciavU_dst = rfm.basis_transform_vectorU_from_Cartesian_to_rfmbasis(Jac_dUrfm_dDCartUD, gid.ValenciavU)\n",
    "\n",
    "# Note that the below the function should really be \"...basis_transform_vectorUDfrom_Cartesian_to_rfmbasis..\"\n",
    "AD_dst = rfm.basis_transform_vectorU_from_Cartesian_to_rfmbasis(Jac_dUCart_dDrfmUD, gid.AD)"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 4,
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "Initial data type = FFEBD\n",
      "0\n",
      "0\n",
      "0\n",
      "0\n",
      "0\n",
      "0\n",
      "0\n",
      "0\n",
      "0\n"
     ]
    }
   ],
   "source": [
    "print(\"Initial data type = \"+ initial_data)\n",
    "for i in range(DIM):\n",
    "    print(gid.ValenciavU[i] - ValenciavU_dst[i])\n",
    "    print(gid.BU[i] - BU_dst[i])\n",
    "    print(gid.AD[i] - AD_dst[i])"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 5,
   "metadata": {},
   "outputs": [],
   "source": [
    "# Choices are: Spherical, SinhSpherical, SinhSphericalv2, Cylindrical, SinhCylindrical,\n",
    "#              SymTP, SinhSymTP\n",
    "dst_basis = \"SymTP\"\n",
    "\n",
    "# Set coordinate system to dst_basis\n",
    "par.set_parval_from_str(\"reference_metric::CoordSystem\",dst_basis)\n",
    "rfm.reference_metric()\n",
    "\n",
    "# Step 3: Transform BSSN tensors in Cartesian basis to destination grid basis, using center of dest. grid as origin\n",
    "\n",
    "# Step 3.a: Next construct Jacobian and inverse Jacobian matrices:\n",
    "Jac_dUCart_dDrfmUD,Jac_dUrfm_dDCartUD = rfm.compute_Jacobian_and_inverseJacobian_tofrom_Cartesian()\n",
    "\n",
    "# Step 3.b: Convert basis of all BSSN *vectors* from Cartesian to destination basis\n",
    "BU_dst = rfm.basis_transform_vectorU_from_Cartesian_to_rfmbasis(Jac_dUrfm_dDCartUD, gid.BU)\n",
    "\n",
    "ValenciavU_dst = rfm.basis_transform_vectorU_from_Cartesian_to_rfmbasis(Jac_dUrfm_dDCartUD, gid.ValenciavU)\n",
    "\n",
    "# Note that the below the function should really be \"...basis_transform_vectorUDfrom_Cartesian_to_rfmbasis..\"\n",
    "AD_dst = rfm.basis_transform_vectorU_from_Cartesian_to_rfmbasis(Jac_dUCart_dDrfmUD, gid.AD)"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 6,
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "Consistency check between GiRaFFEfood_NRPy tutorial and NRPy+ module:\n",
      "ValenciavU0 is in agreement!\n",
      "AD0 is in agreement!\n",
      "BU0 is in agreement!\n",
      "ValenciavU1 is in agreement!\n",
      "AD1 is in agreement!\n",
      "BU1 is in agreement!\n",
      "ValenciavU2 is in agreement!\n",
      "AD2 is in agreement!\n",
      "BU2 is in agreement!\n"
     ]
    }
   ],
   "source": [
    "import GiRaFFEfood_NRPy.BasisTransform as BT\n",
    "BT.basis_transform(dst_basis, gid.AD, gid.ValenciavU, gid.BU)\n",
    "\n",
    "def consistency_check(quantity1,quantity2,string):\n",
    "    if quantity1-quantity2==0:\n",
    "        print(string+\" is in agreement!\")\n",
    "    else:\n",
    "        print(string+\" does not agree!\")\n",
    "        sys.exit(1)\n",
    "\n",
    "print(\"Consistency check between GiRaFFEfood_NRPy tutorial and NRPy+ module:\")\n",
    "\n",
    "for i in range(3):\n",
    "    consistency_check(ValenciavU_dst[i],BT.ValenciavU_dst[i],\"ValenciavU\"+str(i))\n",
    "    consistency_check(AD_dst[i],BT.AD_dst[i],\"AD\"+str(i))\n",
    "    consistency_check(BU_dst[i],BT.BU_dst[i],\"BU\"+str(i))"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "<a id='latex_pdf_output'></a>\n",
    "\n",
    "# Step 8: Output this notebook to $\\LaTeX$-formatted PDF file \\[Back to [top](#toc)\\]\n",
    "$$\\label{latex_pdf_output}$$\n",
    "\n",
    "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\n",
    "[Tutorial-Start_to_Finish-GiRaFFE_NRPy-1D_tests-staggered.pdf](Tutorial-Start_to_Finish-GiRaFFE_NRPy-1D_tests-staggered.pdf) (Note that clicking on this link may not work; you may need to open the PDF file through another means.)"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 7,
   "metadata": {
    "execution": {
     "iopub.execute_input": "2020-12-17T02:16:40.992437Z",
     "iopub.status.busy": "2020-12-17T02:16:40.991903Z",
     "iopub.status.idle": "2020-12-17T02:16:44.098639Z",
     "shell.execute_reply": "2020-12-17T02:16:44.098104Z"
    }
   },
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "Created Tutorial-Start_to_Finish-GiRaFFE_NRPy-1D_tests-staggered.tex, and\n",
      "    compiled LaTeX file to PDF file Tutorial-Start_to_Finish-\n",
      "    GiRaFFE_NRPy-1D_tests-staggered.pdf\n"
     ]
    }
   ],
   "source": [
    "import cmdline_helper as cmd    # NRPy+: Multi-platform Python command-line interface\n",
    "cmd.output_Jupyter_notebook_to_LaTeXed_PDF(\"Tutorial-Start_to_Finish-GiRaFFE_NRPy-1D_tests-staggered\",location_of_template_file=os.path.join(\"..\"))"
   ]
  }
 ],
 "metadata": {
  "kernelspec": {
   "display_name": "Python 3",
   "language": "python",
   "name": "python3"
  },
  "language_info": {
   "codemirror_mode": {
    "name": "ipython",
    "version": 3
   },
   "file_extension": ".py",
   "mimetype": "text/x-python",
   "name": "python",
   "nbconvert_exporter": "python",
   "pygments_lexer": "ipython3",
   "version": "3.8.10"
  }
 },
 "nbformat": 4,
 "nbformat_minor": 2
}