# Notebook from philchang/nrpytutorial
Path: Tutorial-Reference_Metric.ipynb

# NRPy+'s Reference Metric Interface

## Author: Zach Etienne
### Formatting improvements courtesy Brandon Clark

### NRPy+ Source Code for this module: [reference_metric.py](../edit/reference_metric.py)

## Introduction:
### Why use a reference metric? Benefits of choosing the best coordinate system for the problem

When solving a partial differential equation on the computer, it is useful to first pick a coordinate system well-suited to the geometry of the problem. For example, if we are modeling a spherically-symmetric star, it would be hugely wasteful to model the star in 3-dimensional Cartesian coordinates ($x$,$y$,$z$). This is because in Cartesian coordinates, we would need to choose high sampling in all three Cartesian directions. If instead we chose to model the star in spherical coordinates  ($r$,$\theta$,$\phi$), so long as the star is centered at $r=0$, we would not need to model the star with more than one point in the $\theta$ and $\phi$ directions!

A similar argument holds for stars that are *nearly* spherically symmetric. Such stars may exhibit density distributions that vary slowly in $\theta$ and $\phi$ directions (e.g., isolated neutron stars or black holes). In these cases the number of points needed to sample the angular directions will still be much smaller than in the radial direction.

Thus choice of an appropriate reference metric may directly mitigate the [Curse of Dimensionality](https://en.wikipedia.org/wiki/Curse_of_dimensionality)._____no_output_____

# Table of Contents
$$\label{toc}$$

This notebook is organized as follow

1. [Step 1](#define_ref_metric): Defining a reference metric, [`reference_metric.py`](../edit/reference_metric.py)
1. [Step 2](#define_geometric): Defining geometric quantities, **`ref_metric__hatted_quantities()`**
1. [Step 3](#prescribed_ref_metric): Prescribed reference metrics in [`reference_metric.py`](../edit/reference_metric.py)
    1. [Step 3.a](#sphericallike): Spherical-like coordinate systems
        1. [Step 3.a.i](#spherical): **`reference_metric::CoordSystem = "Spherical"`**
        1. [Step 3.a.ii](#sinhspherical): **`reference_metric::CoordSystem = "SinhSpherical"`**
        1. [Step 3.a.iii](#sinhsphericalv2): **`reference_metric::CoordSystem = "SinhSphericalv2"`**
    1. [Step 3.b](#cylindricallike): Cylindrical-like coordinate systems
        1. [Step 3.b.i](#cylindrical): **`reference_metric::CoordSystem = "Cylindrical"`**
        1. [Step 3.b.ii](#sinhcylindrical): **`reference_metric::CoordSystem = "SinhCylindrical"`**
        1. [Step 3.b.iii](#sinhcylindricalv2): **`reference_metric::CoordSystem = "SinhCylindricalv2"`**
    1. [Step 3.c](#cartesianlike): Cartesian-like coordinate systems
        1. [Step 3.c.i](#cartesian): **`reference_metric::CoordSystem = "Cartesian"`**
        1. [Step 3.c.ii](#sinhcartesian): **`reference_metric::CoordSystem = "SinhCartesian"`**
    1. [Step 3.d](#prolatespheroidal): Prolate spheroidal coordinates
        1. [Step 3.d.i](#symtp): **`reference_metric::CoordSystem = "SymTP"`**
        1. [Step 3.d.ii](#sinhsymtp): **`reference_metric::CoordSystem = "SinhSymTP"`**
1. [Step 4](#latex_pdf_output): Output this notebook to $\LaTeX$-formatted PDF file_____no_output_____

# Step 1: Defining a reference metric, [`reference_metric.py`](../edit/reference_metric.py) \[Back to [top](#toc)\]
$$\label{define_ref_metric}$$

***Note that currently only orthogonal reference metrics of dimension 3 or fewer are supported. This can be extended if desired.***

NRPy+ assumes all curvilinear coordinate systems map directly from a uniform, Cartesian numerical grid with coordinates $(x,y,z)$=(`xx[0]`,`xx[1]`,`xx[2]`). Thus when defining reference metrics, all defined coordinate quantities must be in terms of the `xx[]` array. As we will see, this adds a great deal of flexibility

For example,  [**reference_metric.py**](../edit/reference_metric.py) requires that the *orthogonal coordinate scale factors* be defined. As described [here](https://en.wikipedia.org/wiki/Curvilinear_coordinates), the $i$th scale factor is the positive root of the metric element $g_{ii}$. In ordinary spherical coordinates $(r,\theta,\phi)$, with line element $ds^2 = g_{ij} dx^i dx^j = dr^2+ r^2 d \theta^2 + r^2 \sin^2\theta \ d\phi^2$, we would first define
* $r = xx_0$
* $\theta = xx_1$
* $\phi = xx_2$,

so that the scale factors are defined as
* `scalefactor_orthog[0]` = $1$
* `scalefactor_orthog[1]` = $r$
* `scalefactor_orthog[2]` = $r \sin \theta$

Here is the corresponding code:_____no_output_____

import sympy as sp               # SymPy: The Python computer algebra package upon which NRPy+ depends
import NRPy_param_funcs as par   # NRPy+: parameter interface
import reference_metric as rfm   # NRPy+: Reference metric support

r = rfm.xx[0]
th = rfm.xx[1]
ph = rfm.xx[2]

rfm.scalefactor_orthog[0] = 1
rfm.scalefactor_orthog[1] = r
rfm.scalefactor_orthog[2] = r*sp.sin(th)

# Notice that the scale factor will be given
#    in terms of the fundamental Cartesian
#    grid variables, and not {r,th,ph}:
print("r*sin(th) = "+str(rfm.scalefactor_orthog[2]))r*sin(th) = xx0*sin(xx1)

Next suppose we wish to modify our radial coordinate $r(xx_0)$ to be an exponentially increasing function, so that our numerical grid $(xx_0,xx_1,xx_2)$ will map to a spherical grid with radial grid spacing ($\Delta r$) that *increases* with $r$. Generally we will find it useful to define $r(xx_0)$ to be an odd function, so let's choose

$$r(xx_0) = a \sinh(xx_0/s),$$

where $a$ is an overall radial scaling factor, and $s$ denotes the scale (in units of $xx_0$) over which exponential growth will take place. In our implementation below, note that we use the relation

$$\sinh(x) = \frac{e^x - e^{-x}}{2},$$

as SymPy finds it easier to evaluate exponentials than hyperbolic trigonometric functions._____no_output_____

a,s = sp.symbols('a s',positive=True)
xx0_rescaled = rfm.xx[0] / s
r = a*(sp.exp(xx0_rescaled) - sp.exp(-xx0_rescaled))/2

# Must redefine the scalefactors since 'r' has been updated!
rfm.scalefactor_orthog[0] = 1
rfm.scalefactor_orthog[1] = r
rfm.scalefactor_orthog[2] = r*sp.sin(th)

print(rfm.scalefactor_orthog[2])a*(exp(xx0/s) - exp(-xx0/s))*sin(xx1)/2

Often we will find it useful to also define the appropriate mappings from (`xx[0]`,`xx[1]`,`xx[2]`) to Cartesian coordinates (for plotting purposes) and ordinary spherical coordinates (e.g., in case initial data when solving a PDE are naturally written in spherical coordinates). For this purpose, reference_metric.py also declares lists **`xx_to_Cart[]`** and **`xxSph[]`**, which in this case are defined as_____no_output_____

rfm.xxSph[0] = r
rfm.xxSph[1] = th
rfm.xxSph[2] = ph

rfm.xx_to_Cart[0] = r*sp.sin(th)*sp.cos(ph)
rfm.xx_to_Cart[1] = r*sp.sin(th)*sp.sin(ph)
rfm.xx_to_Cart[2] = r*sp.cos(th)

# Here we show off SymPy's pretty_print()
#   and simplify() functions. Nice, no?
sp.pretty_print(sp.simplify(rfm.xx_to_Cart[0]))                        ⎛xx₀⎞
a⋅sin(xx₁)⋅cos(xx₂)⋅sinh⎜───⎟
                        ⎝ s ⎠

# Step 2: Define geometric quantities, `ref_metric__hatted_quantities()` \[Back to [top](#toc)\]
$$\label{define_geometric}$$

Once `scalefactor_orthog[]` has been defined, the function **`ref_metric__hatted_quantities()`** within [reference_metric.py](../edit/reference_metric.py) can be called to define a number of geometric quantities useful for solving PDEs in curvilinear coordinate systems.

Adopting the notation of [Baumgarte, Montero, Cordero-Carrión, and Müller, PRD 87, 044026 (2012)](https://arxiv.org/abs/1211.6632), geometric quantities related to the reference metric are named "hatted" quantities, . For example, the reference metric is defined as $\hat{g}_{ij}$=`ghatDD[i][j]`:_____no_output_____

rfm.ref_metric__hatted_quantities()

sp.pretty_print(sp.Matrix(rfm.ghatDD))⎡1           0                         0              ⎤
⎢                                                     ⎥
⎢                     2                               ⎥
⎢      ⎛ xx₀    -xx₀ ⎞                                ⎥
⎢      ⎜ ───    ─────⎟                                ⎥
⎢    2 ⎜  s       s  ⎟                                ⎥
⎢   a ⋅⎝ℯ    - ℯ     ⎠                                ⎥
⎢0  ───────────────────                0              ⎥
⎢            4                                        ⎥
⎢                                                     ⎥
⎢                                          2          ⎥
⎢                           ⎛ xx₀    -xx₀ ⎞           ⎥
⎢                           ⎜ ───    ─────⎟           ⎥
⎢                         2 ⎜  s       s  ⎟     2     ⎥
⎢                        a ⋅⎝ℯ    - ℯ     ⎠ ⋅sin (xx₁)⎥
⎢0           0           ─────────────────────────────⎥
⎣                                      4              ⎦

In addition to $\hat{g}_{ij}$, **`ref_metric__hatted_quantities()`** also provides:
* The rescaling "matrix" `ReDD[i][j]`, used for separating singular (due to chosen coordinate system) pieces of smooth rank-2 tensor components from the smooth parts, so that the smooth parts can be used within temporal and spatial differential operators.
* Inverse reference metric: $\hat{g}^{ij}$=`ghatUU[i][j]`.
* Reference metric determinant: $\det\left(\hat{g}_{ij}\right)$=`detgammahat`.
* First and second derivatives of the reference metric: $\hat{g}_{ij,k}$=`ghatDD_dD[i][j][k]`; $\hat{g}_{ij,kl}$=`ghatDD_dDD[i][j][k][l]`
* Christoffel symbols associated with the reference metric, $\hat{\Gamma}^i_{jk}$ = `GammahatUDD[i][j][k]` and their first derivatives $\hat{\Gamma}^i_{jk,l}$ = `GammahatUDD_dD[i][j][k][l]`

For example, the Christoffel symbol $\hat{\Gamma}^{xx_1}_{xx_2 xx_2}=\hat{\Gamma}^1_{22}$ is given by `GammahatUDD[1][2][2]`:_____no_output_____

sp.pretty_print(sp.simplify(rfm.GammahatUDD[1][2][2]))-sin(2⋅xx₁)
────────────
     2

Given the trigonometric identity $2\sin(x)\cos(x) = \sin(2x)$, notice that the above expression is equivalent to Eq. 18 of [Baumgarte, Montero, Cordero-Carrión, and Müller, PRD 87, 044026 (2012)](https://arxiv.org/abs/1211.6632). This is expected since the sinh-radial spherical coordinate system is equivalent to ordinary spherical coordinates in the angular components._____no_output_____

# Step 3: Prescribed reference metrics in [`reference_metric.py`](../edit/reference_metric.py) \[Back to [top](#toc)\]
$$\label{prescribed_ref_metric}$$

One need not manually define scale factors or other quantities for reference metrics, as a number of prescribed reference metrics are already defined in [reference_metric.py](../edit/reference_metric.py). These can be accessed by first setting the parameter **reference_metric::CoordSystem** to one of the following, and then calling the function **`rfm.reference_metric()`**._____no_output_____

import indexedexp as ixp    # NRPy+: Symbolic indexed expression (e.g., tensors, vectors, etc.) support
import grid as gri          # NRPy+: Functions having to do with numerical grids

# Step 0a: Initialize parameters
thismodule = __name__
par.initialize_param(par.glb_param("char", thismodule, "CoordSystem", "Spherical"))

# Step 0b: Declare global variables
xx = gri.xx
xx_to_Cart = ixp.zerorank1(DIM=4) # Must be set in terms of xx[]s
Cart_to_xx = ixp.zerorank1(DIM=4) # Must be set in terms of xx[]s
Cartx,Carty,Cartz = sp.symbols("Cartx Carty Cartz", real=True)
Cart = [Cartx,Carty,Cartz]
xxSph  = ixp.zerorank1(DIM=4) # Must be set in terms of xx[]s
scalefactor_orthog = ixp.zerorank1(DIM=4) # Must be set in terms of xx[]s
have_already_called_reference_metric_function = False

CoordSystem = par.parval_from_str("reference_metric::CoordSystem")
M_PI,M_SQRT1_2 = par.Cparameters("#define",thismodule,["M_PI","M_SQRT1_2"],"")

global xxmin
global xxmax

global UnitVectors
UnitVectors = ixp.zerorank2(DIM=3)_____no_output_____

We will find the following plotting function useful for analyzing coordinate systems in which the radial coordinate is rescaled._____no_output_____

def create_r_of_xx0_plots(CoordSystem, r_of_xx0,rprime_of_xx0):
    import matplotlib.pyplot as plt  # matplotlib: Python module specializing in plotting capabilities
    plt.clf()
    Nr = 20
    dxx0 = 1.0 / float(Nr)
    xx0s    = []
    rs      = []
    deltars = []
    rprimes = []
    for i in range(Nr):
        xx0 = (float(i) + 0.5)*dxx0
        xx0s.append(xx0)
        rs.append(     sp.sympify(str(r_of_xx0     ).replace("xx0",str(xx0))))
        rprimes.append(sp.sympify(str(rprime_of_xx0).replace("xx0",str(xx0))))
        if i>0:
            deltars.append(sp.log(rs[i]-rs[i-1],10))
        else:
            deltars.append(sp.log(2*rs[0],10))

    # fig, ax = plt.subplots()
    fig = plt.figure(figsize=(12,12)) # 8 in x 8 in

    ax = fig.add_subplot(221)
    ax.set_title('$r(xx_0)$ for '+CoordSystem,fontsize='x-large')
    ax.set_xlabel('$xx_0$',fontsize='x-large')
    ax.set_ylabel('$r(xx_0)$',fontsize='x-large')
    ax.plot(xx0s, rs, 'k.', label='Spacing between\nadjacent gridpoints')
    # legend = ax.legend(loc='lower right', shadow=True, fontsize='x-large')
    # legend.get_frame().set_facecolor('C1')

    ax = fig.add_subplot(222)
    ax.set_title('Grid spacing for '+CoordSystem,fontsize='x-large')
    ax.set_xlabel('$xx_0$',fontsize='x-large')
    ax.set_ylabel('$\log_{10}(\Delta r)$',fontsize='x-large')
    ax.plot(xx0s, deltars, 'k.', label='Spacing between\nadjacent gridpoints\nin $r(xx_0)$ plot')
    legend = ax.legend(loc='lower right', shadow=True, fontsize='x-large')
    legend.get_frame().set_facecolor('C1')

    ax = fig.add_subplot(223)
    ax.set_title('$r\'(xx_0)$ for '+CoordSystem,fontsize='x-large')
    ax.set_xlabel('$xx_0$',fontsize='x-large')
    ax.set_ylabel('$r\'(xx_0)$',fontsize='x-large')
    ax.plot(xx0s, rprimes, 'k.', label='Nr=96')
    # legend = ax.legend(loc='upper left', shadow=True, fontsize='x-large')
    # legend.get_frame().set_facecolor('C1')

    plt.tight_layout(pad=2)
    plt.show()_____no_output_____

## Step 3.a: Spherical-like coordinate systems \[Back to [top](#toc)\]
$$\label{sphericallike}$$_____no_output_____

### Step 3.a.i: **`reference_metric::CoordSystem = "Spherical"`** \[Back to [top](#toc)\]
$$\label{spherical}$$

Standard spherical coordinates, with $(r,\theta,\phi)=(xx_0,xx_1,xx_2)$_____no_output_____

if CoordSystem == "Spherical":
    # Adding assumption real=True can help simplify expressions involving xx[0] & xx[1] below.
    xx[0] = sp.symbols("xx0", real=True)
    xx[1] = sp.symbols("xx1", real=True)

    RMAX = par.Cparameters("REAL", thismodule, ["RMAX"],10.0)
    xxmin = [sp.sympify(0), sp.sympify(0), -M_PI]
    xxmax = [         RMAX,          M_PI,  M_PI]

    r  = xx[0]
    th = xx[1]
    ph = xx[2]

    Cart_to_xx[0] = sp.sqrt(Cartx ** 2 + Carty ** 2 + Cartz ** 2)
    Cart_to_xx[1] = sp.acos(Cartz / Cart_to_xx[0])
    Cart_to_xx[2] = sp.atan2(Carty, Cartx)

    xxSph[0] = r
    xxSph[1] = th
    xxSph[2] = ph

    # Now define xCart, yCart, and zCart in terms of x0,xx[1],xx[2].
    # Note that the relation between r and x0 is not necessarily trivial in SinhSpherical coordinates. See above.
    xx_to_Cart[0] = xxSph[0]*sp.sin(xxSph[1])*sp.cos(xxSph[2])
    xx_to_Cart[1] = xxSph[0]*sp.sin(xxSph[1])*sp.sin(xxSph[2])
    xx_to_Cart[2] = xxSph[0]*sp.cos(xxSph[1])

    scalefactor_orthog[0] = sp.diff(xxSph[0],xx[0])
    scalefactor_orthog[1] = xxSph[0]
    scalefactor_orthog[2] = xxSph[0]*sp.sin(xxSph[1])

    # Set the unit vectors
    UnitVectors = [[ sp.sin(xxSph[1])*sp.cos(xxSph[2]), sp.sin(xxSph[1])*sp.sin(xxSph[2]),  sp.cos(xxSph[1])],
                   [ sp.cos(xxSph[1])*sp.cos(xxSph[2]), sp.cos(xxSph[1])*sp.sin(xxSph[2]), -sp.sin(xxSph[1])],
                   [                 -sp.sin(xxSph[2]),                  sp.cos(xxSph[2]),  sp.sympify(0)   ]]_____no_output_____

Now let's analyze $r(xx_0)$ for **"Spherical"** coordinates._____no_output_____

%matplotlib inline

CoordSystem = "Spherical"
par.set_parval_from_str("reference_metric::CoordSystem",CoordSystem)
rfm.reference_metric()

RMAX     = 10.0
r_of_xx0      = sp.sympify(str(rfm.xxSph[0]                   ).replace("RMAX",str(RMAX)))
rprime_of_xx0 = sp.sympify(str(sp.diff(rfm.xxSph[0],rfm.xx[0])).replace("RMAX",str(RMAX)))

create_r_of_xx0_plots(CoordSystem, r_of_xx0,rprime_of_xx0)_____no_output_____

### Step 3.a.ii: **`reference_metric::CoordSystem = "SinhSpherical"`** \[Back to [top](#toc)\]
$$\label{sinhspherical}$$

Spherical coordinates, but with $$r(xx_0) = \text{AMPL} \frac{\sinh\left(\frac{xx_0}{\text{SINHW}}\right)}{\sinh\left(\frac{1}{\text{SINHW}}\right)}.$$

SinhSpherical uses two parameters: `AMPL` and `SINHW`. `AMPL` sets the outer boundary distance; and `SINHW` sets the focusing of the coordinate points near $r=0$, where a small `SINHW` ($\sim 0.125$) will greatly focus the points near $r=0$ and a large `SINHW` will look more like an ordinary spherical polar coordinate system._____no_output_____

if CoordSystem == "SinhSpherical":
    xxmin = [sp.sympify(0), sp.sympify(0), -M_PI]
    xxmax = [sp.sympify(1),          M_PI,  M_PI]

    AMPL, SINHW = par.Cparameters("REAL",thismodule,["AMPL","SINHW"],[10.0,0.2])
    # Set SinhSpherical radial coordinate by default; overwrite later if CoordSystem == "SinhSphericalv2".
    r = AMPL * (sp.exp(xx[0] / SINHW) - sp.exp(-xx[0] / SINHW)) / \
               (sp.exp(1 / SINHW) - sp.exp(-1 / SINHW))
    th = xx[1]
    ph = xx[2]

    Cart_to_xx[0] = SINHW*sp.asinh(sp.sqrt(Cartx ** 2 + Carty ** 2 + Cartz ** 2)*sp.sinh(1/SINHW)/AMPL)
    Cart_to_xx[1] = sp.acos(Cartz / sp.sqrt(Cartx ** 2 + Carty ** 2 + Cartz ** 2))
    Cart_to_xx[2] = sp.atan2(Carty, Cartx)

    xxSph[0] = r
    xxSph[1] = th
    xxSph[2] = ph

    # Now define xCart, yCart, and zCart in terms of x0,xx[1],xx[2].
    # Note that the relation between r and x0 is not necessarily trivial in SinhSpherical coordinates. See above.
    xx_to_Cart[0] = xxSph[0]*sp.sin(xxSph[1])*sp.cos(xxSph[2])
    xx_to_Cart[1] = xxSph[0]*sp.sin(xxSph[1])*sp.sin(xxSph[2])
    xx_to_Cart[2] = xxSph[0]*sp.cos(xxSph[1])

    scalefactor_orthog[0] = sp.diff(xxSph[0],xx[0])
    scalefactor_orthog[1] = xxSph[0]
    scalefactor_orthog[2] = xxSph[0]*sp.sin(xxSph[1])

    # Set the unit vectors
    UnitVectors = [[ sp.sin(xxSph[1])*sp.cos(xxSph[2]), sp.sin(xxSph[1])*sp.sin(xxSph[2]),  sp.cos(xxSph[1])],
                   [ sp.cos(xxSph[1])*sp.cos(xxSph[2]), sp.cos(xxSph[1])*sp.sin(xxSph[2]), -sp.sin(xxSph[1])],
                   [                 -sp.sin(xxSph[2]),                  sp.cos(xxSph[2]),  sp.sympify(0)   ]]_____no_output_____

Now we explore $r(xx_0)$ for `SinhSpherical` assuming `AMPL=10.0` and `SINHW=0.2`:_____no_output_____

%matplotlib inline

CoordSystem = "SinhSpherical"
par.set_parval_from_str("reference_metric::CoordSystem",CoordSystem)
rfm.reference_metric()

AMPL     = 10.0
SINHW    = 0.2
r_of_xx0      = sp.sympify(str(rfm.xxSph[0]                   ).replace("AMPL",str(AMPL)).replace("SINHW",str(SINHW)))
rprime_of_xx0 = sp.sympify(str(sp.diff(rfm.xxSph[0],rfm.xx[0])).replace("AMPL",str(AMPL)).replace("SINHW",str(SINHW)))

create_r_of_xx0_plots(CoordSystem, r_of_xx0,rprime_of_xx0)_____no_output_____

### Step 3.a.iii: **`reference_metric::CoordSystem = "SinhSphericalv2"`** \[Back to [top](#toc)\]
$$\label{sinhsphericalv2}$$

The same as SinhSpherical coordinates, but with an additional `AMPL*const_dr*xx_0` term:
$$r(xx_0) = \text{AMPL} \left[\text{const_dr}\ xx_0 + \frac{\sinh\left(\frac{xx_0}{\text{SINHW}}\right)}{\sinh\left(\frac{1}{\text{SINHW}}\right)}\right].$$_____no_output_____

if CoordSystem == "SinhSphericalv2":
    # SinhSphericalv2 adds the parameter "const_dr", which allows for a region near xx[0]=0 to have
    # constant radial resolution of const_dr, provided the sinh() term does not dominate near xx[0]=0.
    xxmin = [sp.sympify(0), sp.sympify(0), -M_PI]
    xxmax = [sp.sympify(1),          M_PI,  M_PI]

    AMPL, SINHW = par.Cparameters("REAL",thismodule,["AMPL","SINHW"],[10.0,0.2])
    const_dr = par.Cparameters("REAL",thismodule,["const_dr"],0.0625)

    r = AMPL*( const_dr*xx[0] + (sp.exp(xx[0] / SINHW) - sp.exp(-xx[0] / SINHW)) /
               (sp.exp(1 / SINHW) - sp.exp(-1 / SINHW)) )
    th = xx[1]
    ph = xx[2]

    # NO CLOSED-FORM EXPRESSION FOR RADIAL INVERSION.
    # Cart_to_xx[0] = "NewtonRaphson"
    # Cart_to_xx[1] = sp.acos(Cartz / sp.sqrt(Cartx ** 2 + Carty ** 2 + Cartz ** 2))
    # Cart_to_xx[2] = sp.atan2(Carty, Cartx)

    xxSph[0] = r
    xxSph[1] = th
    xxSph[2] = ph

    # Now define xCart, yCart, and zCart in terms of x0,xx[1],xx[2].
    # Note that the relation between r and x0 is not necessarily trivial in SinhSpherical coordinates. See above.
    xx_to_Cart[0] = xxSph[0]*sp.sin(xxSph[1])*sp.cos(xxSph[2])
    xx_to_Cart[1] = xxSph[0]*sp.sin(xxSph[1])*sp.sin(xxSph[2])
    xx_to_Cart[2] = xxSph[0]*sp.cos(xxSph[1])

    scalefactor_orthog[0] = sp.diff(xxSph[0],xx[0])
    scalefactor_orthog[1] = xxSph[0]
    scalefactor_orthog[2] = xxSph[0]*sp.sin(xxSph[1])

    # Set the unit vectors
    UnitVectors = [[ sp.sin(xxSph[1])*sp.cos(xxSph[2]), sp.sin(xxSph[1])*sp.sin(xxSph[2]),  sp.cos(xxSph[1])],
                   [ sp.cos(xxSph[1])*sp.cos(xxSph[2]), sp.cos(xxSph[1])*sp.sin(xxSph[2]), -sp.sin(xxSph[1])],
                   [                 -sp.sin(xxSph[2]),                  sp.cos(xxSph[2]),  sp.sympify(0)   ]]_____no_output_____

Now we explore $r(xx_0)$ for `SinhSphericalv2` assuming `AMPL=10.0`, `SINHW=0.2`, and `const_dr=0.05`. Notice that the `const_dr` term significantly increases the grid spacing near $xx_0=0$ relative to `SinhSpherical` coordinates._____no_output_____

%matplotlib inline

CoordSystem = "SinhSphericalv2"
par.set_parval_from_str("reference_metric::CoordSystem",CoordSystem)
rfm.reference_metric()

AMPL     = 10.0
SINHW    = 0.2
const_dr = 0.05
r_of_xx0      = sp.sympify(str(rfm.xxSph[0]                   ).replace("AMPL",str(AMPL)).replace("SINHW",str(SINHW)).replace("const_dr",str(const_dr)))
rprime_of_xx0 = sp.sympify(str(sp.diff(rfm.xxSph[0],rfm.xx[0])).replace("AMPL",str(AMPL)).replace("SINHW",str(SINHW)).replace("const_dr",str(const_dr)))

create_r_of_xx0_plots(CoordSystem, r_of_xx0,rprime_of_xx0)_____no_output_____

## Step 3.b: Cylindrical-like coordinate systems \[Back to [top](#toc)\]
$$\label{cylindricallike}$$_____no_output_____

### Step 3.b.i: **`reference_metric::CoordSystem = "Cylindrical"`** \[Back to [top](#toc)\]
$$\label{cylindrical}$$

Standard cylindrical coordinates, with $(\rho,\phi,z)=(xx_0,xx_1,xx_2)$_____no_output_____

if CoordSystem == "Cylindrical":
    # Assuming the cylindrical radial coordinate
    #   is positive makes nice simplifications of
    #   unit vectors possible.
    xx[0] = sp.symbols("xx0", real=True)

    RHOMAX,ZMIN,ZMAX = par.Cparameters("REAL",thismodule,["RHOMAX","ZMIN","ZMAX"],[10.0,-10.0,10.0])
    xxmin = [sp.sympify(0), -M_PI, ZMIN]
    xxmax = [       RHOMAX,  M_PI, ZMAX]

    RHOCYL = xx[0]
    PHICYL = xx[1]
    ZCYL   = xx[2]

    Cart_to_xx[0] = sp.sqrt(Cartx ** 2 + Carty ** 2)
    Cart_to_xx[1] = sp.atan2(Carty, Cartx)
    Cart_to_xx[2] = Cartz

    xx_to_Cart[0] = RHOCYL*sp.cos(PHICYL)
    xx_to_Cart[1] = RHOCYL*sp.sin(PHICYL)
    xx_to_Cart[2] = ZCYL

    xxSph[0] = sp.sqrt(RHOCYL**2 + ZCYL**2)
    xxSph[1] = sp.acos(ZCYL / xxSph[0])
    xxSph[2] = PHICYL

    scalefactor_orthog[0] = sp.diff(RHOCYL,xx[0])
    scalefactor_orthog[1] = RHOCYL
    scalefactor_orthog[2] = sp.diff(ZCYL,xx[2])

    # Set the unit vectors
    UnitVectors = [[ sp.cos(PHICYL), sp.sin(PHICYL), sp.sympify(0)],
                   [-sp.sin(PHICYL), sp.cos(PHICYL), sp.sympify(0)],
                   [ sp.sympify(0),  sp.sympify(0),  sp.sympify(1)]]_____no_output_____

Next let's plot **"Cylindrical"** coordinates._____no_output_____

%matplotlib inline

import numpy as np                  # NumPy: A numerical methods module for Python
import matplotlib.pyplot as plt
from mpl_toolkits.mplot3d import Axes3D

R = np.linspace(0, 2, 24)
h = 2
u = np.linspace(0,  2*np.pi, 24)

x = np.outer(R, np.cos(u))
y = np.outer(R, np.sin(u))
z = h * np.outer(np.ones(np.size(u)), np.ones(np.size(u)))

r = np.arange(0,2,0.25)
theta = 2*np.pi*r*0

fig = plt.figure(figsize=(12,12)) # 8 in x 8 in
fig, (ax1, ax2) = plt.subplots(1, 2)

ax1 = plt.axes(projection='polar')

ax1.set_rmax(2)

ax1.set_rgrids(r,labels=[])

thetas = np.linspace(0,360,24, endpoint=True)
ax1.set_thetagrids(thetas,labels=[])

# ax.grid(True)
ax1.grid(True,linewidth='1.0')
ax1.set_title("Top Down View")
plt.show()

ax2 = plt.axes(projection='3d', xticklabels=[], yticklabels=[], zticklabels=[])
#ax2.plot_surface(x,y,z, alpha=.75, cmap = 'viridis') # z in case of disk which is parallel to XY plane is constant and you can directly use h

x=np.linspace(-2, 2, 100)
z=np.linspace(-2, 2, 100)
Xc, Zc=np.meshgrid(x, z)
Yc = np.sqrt(4-Xc**2)

rstride = 10
cstride = 10
ax2.plot_surface(Xc, Yc, Zc, alpha=1.0, rstride=rstride, cstride=cstride, cmap = 'viridis')
ax2.plot_surface(Xc, -Yc, Zc, alpha=1.0, rstride=rstride, cstride=cstride, cmap = 'viridis')
ax2.set_title("Standard Cylindrical Grid in 3D")
ax2.grid(False)
plt.axis('off')

plt.show()_____no_output_____

### Step 3.b.ii" **`reference_metric::CoordSystem = "SinhCylindrical"`** \[Back to [top](#toc)\]
$$\label{sinhcylindrical}$$

Cylindrical coordinates, but with
$$\rho(xx_0) = \text{AMPLRHO} \frac{\sinh\left(\frac{xx_0}{\text{SINHWRHO}}\right)}{\sinh\left(\frac{1}{\text{SINHWRHO}}\right)}$$
and
$$z(xx_2) = \text{AMPLZ} \frac{\sinh\left(\frac{xx_2}{\text{SINHWZ}}\right)}{\sinh\left(\frac{1}{\text{SINHWZ}}\right)}$$_____no_output_____

if CoordSystem == "SinhCylindrical":
    # Assuming the cylindrical radial coordinate
    #   is positive makes nice simplifications of
    #   unit vectors possible.
    xx[0] = sp.symbols("xx0", real=True)

    xxmin = [sp.sympify(0), -M_PI, sp.sympify(-1)]
    xxmax = [sp.sympify(1),  M_PI, sp.sympify(+1)]

    AMPLRHO, SINHWRHO, AMPLZ, SINHWZ = par.Cparameters("REAL",thismodule,
                                                       ["AMPLRHO","SINHWRHO","AMPLZ","SINHWZ"],
                                                       [     10.0,       0.2,   10.0,    0.2])

    # Set SinhCylindrical radial & z coordinates by default; overwrite later if CoordSystem == "SinhCylindricalv2".
    RHOCYL = AMPLRHO * (sp.exp(xx[0] / SINHWRHO) - sp.exp(-xx[0] / SINHWRHO)) / (sp.exp(1 / SINHWRHO) - sp.exp(-1 / SINHWRHO))
    # phi coordinate remains unchanged.
    PHICYL = xx[1]
    ZCYL   = AMPLZ   * (sp.exp(xx[2] / SINHWZ)   - sp.exp(-xx[2] / SINHWZ))   / (sp.exp(1 / SINHWZ)   - sp.exp(-1 / SINHWZ))
    Cart_to_xx[0] = SINHWRHO*sp.asinh(sp.sqrt(Cartx ** 2 + Carty ** 2)*sp.sinh(1/SINHWRHO)/AMPLRHO)
    Cart_to_xx[1] = sp.atan2(Carty, Cartx)
    Cart_to_xx[2] = SINHWZ*sp.asinh(Cartz*sp.sinh(1/SINHWZ)/AMPLZ)

    xx_to_Cart[0] = RHOCYL*sp.cos(PHICYL)
    xx_to_Cart[1] = RHOCYL*sp.sin(PHICYL)
    xx_to_Cart[2] = ZCYL

    xxSph[0] = sp.sqrt(RHOCYL**2 + ZCYL**2)
    xxSph[1] = sp.acos(ZCYL / xxSph[0])
    xxSph[2] = PHICYL

    scalefactor_orthog[0] = sp.diff(RHOCYL,xx[0])
    scalefactor_orthog[1] = RHOCYL
    scalefactor_orthog[2] = sp.diff(ZCYL,xx[2])

    # Set the unit vectors
    UnitVectors = [[ sp.cos(PHICYL), sp.sin(PHICYL), sp.sympify(0)],
                   [-sp.sin(PHICYL), sp.cos(PHICYL), sp.sympify(0)],
                   [ sp.sympify(0),  sp.sympify(0),  sp.sympify(1)]]_____no_output_____

Next let's plot **"SinhCylindrical"** coordinates._____no_output_____

fig=plt.figure()

plt.clf()

fig = plt.figure()

ax = plt.subplot(1,1,1, projection='polar')

ax.set_rmax(2)

Nr = 20
xx0s = np.linspace(0,2,Nr, endpoint=True) + 1.0/(2.0*Nr)

rs = []
AMPLRHO = 1.0
SINHW = 0.4
for i in range(Nr):
    rs.append(AMPLRHO * (np.exp(xx0s[i] / SINHW) - np.exp(-xx0s[i] / SINHW)) / \
                        (np.exp(1.0 / SINHW) - np.exp(-1.0 / SINHW)))

ax.set_rgrids(rs,labels=[])

thetas = np.linspace(0,360,25, endpoint=True)
ax.set_thetagrids(thetas,labels=[])

# ax.grid(True)
ax.grid(True,linewidth='1.0')

plt.show()

_____no_output_____

### Step 3.b.iii: **`reference_metric::CoordSystem = "SinhCylindricalv2"`** \[Back to [top](#toc)\]
$$\label{sinhcylindricalv2}$$

Cylindrical coordinates, but with
$$\rho(xx_0) = \text{AMPLRHO} \left[\text{const_drho}\ xx_0 + \frac{\sinh\left(\frac{xx_0}{\text{SINHWRHO}}\right)}{\sinh\left(\frac{1}{\text{SINHWRHO}}\right)}\right]$$
and
$$z(xx_2) = \text{AMPLZ} \left[\text{const_dz}\ xx_2 + \frac{\sinh\left(\frac{xx_2}{\text{SINHWZ}}\right)}{\sinh\left(\frac{1}{\text{SINHWZ}}\right)}\right]$$_____no_output_____

if CoordSystem == "SinhCylindricalv2":
    # Assuming the cylindrical radial coordinate
    #   is positive makes nice simplifications of
    #   unit vectors possible.
    xx[0] = sp.symbols("xx0", real=True)

    # SinhCylindricalv2 adds the parameters "const_drho", "const_dz", which allows for regions near xx[0]=0
    # and xx[2]=0 to have constant rho and z resolution of const_drho and const_dz, provided the sinh() terms
    # do not dominate near xx[0]=0 and xx[2]=0.
    xxmin = [sp.sympify(0), -M_PI, sp.sympify(-1)]
    xxmax = [sp.sympify(1),  M_PI, sp.sympify(+1)]
    AMPLRHO, SINHWRHO, AMPLZ, SINHWZ = par.Cparameters("REAL",thismodule,
                                                       ["AMPLRHO","SINHWRHO","AMPLZ","SINHWZ"],
                                                       [     10.0,       0.2,   10.0,    0.2])
    const_drho, const_dz = par.Cparameters("REAL",thismodule,["const_drho","const_dz"],[0.0625,0.0625])

    RHOCYL = AMPLRHO * ( const_drho*xx[0] + (sp.exp(xx[0] / SINHWRHO) - sp.exp(-xx[0] / SINHWRHO)) / (sp.exp(1 / SINHWRHO) - sp.exp(-1 / SINHWRHO)) )
    PHICYL = xx[1]
    ZCYL   = AMPLZ   * ( const_dz  *xx[2] + (sp.exp(xx[2] / SINHWZ  ) - sp.exp(-xx[2] / SINHWZ  )) / (sp.exp(1 / SINHWZ  ) - sp.exp(-1 / SINHWZ  )) )

    # NO CLOSED-FORM EXPRESSION FOR RADIAL OR Z INVERSION.
    # Cart_to_xx[0] = "NewtonRaphson"
    # Cart_to_xx[1] = sp.atan2(Carty, Cartx)
    # Cart_to_xx[2] = "NewtonRaphson"

    xx_to_Cart[0] = RHOCYL*sp.cos(PHICYL)
    xx_to_Cart[1] = RHOCYL*sp.sin(PHICYL)
    xx_to_Cart[2] = ZCYL

    xxSph[0] = sp.sqrt(RHOCYL**2 + ZCYL**2)
    xxSph[1] = sp.acos(ZCYL / xxSph[0])
    xxSph[2] = PHICYL

    scalefactor_orthog[0] = sp.diff(RHOCYL,xx[0])
    scalefactor_orthog[1] = RHOCYL
    scalefactor_orthog[2] = sp.diff(ZCYL,xx[2])

    # Set the unit vectors
    UnitVectors = [[ sp.cos(PHICYL), sp.sin(PHICYL), sp.sympify(0)],
                   [-sp.sin(PHICYL), sp.cos(PHICYL), sp.sympify(0)],
                   [ sp.sympify(0),  sp.sympify(0),  sp.sympify(1)]]_____no_output_____

For example, let's set up **`SinhCylindricalv2`** coordinates and output the Christoffel symbol $\hat{\Gamma}^{xx_2}_{xx_2 xx_2}$, or more simply $\hat{\Gamma}^2_{22}$:_____no_output_____

par.set_parval_from_str("reference_metric::CoordSystem","SinhCylindricalv2")

rfm.reference_metric()

sp.pretty_print(sp.simplify(rfm.GammahatUDD[2][2][2]))                         ⎛ 2⋅xx₂     ⎞    1
                         ⎜ ──────    ⎟  ──────
                         ⎜ SINHWZ    ⎟  SINHWZ
                        -⎝ℯ       - 1⎠⋅ℯ
────────────────────────────────────────────────────────────────────────
       ⎛                  ⎛   2       ⎞   xx₂     ⎛ 2⋅xx₂     ⎞    1   ⎞
       ⎜                  ⎜ ──────    ⎟  ──────   ⎜ ──────    ⎟  ──────⎟
       ⎜                  ⎜ SINHWZ    ⎟  SINHWZ   ⎜ SINHWZ    ⎟  SINHWZ⎟
SINHWZ⋅⎝- SINHWZ⋅const_dz⋅⎝ℯ       - 1⎠⋅ℯ       - ⎝ℯ       + 1⎠⋅ℯ      ⎠

As we will soon see, defining these "hatted" quantities will be quite useful when expressing hyperbolic ([wave-equation](https://en.wikipedia.org/wiki/Wave_equation)-like) PDEs in non-Cartesian coordinate systems._____no_output_____

## Step 3.c: Cartesian-like coordinate systems \[Back to [top](#toc)\]
$$\label{cartesianlike}$$_____no_output_____

### Step 3.c.i: **`reference_metric::CoordSystem = "Cartesian"`** \[Back to [top](#toc)\]
$$\label{cartesian}$$

Standard Cartesian coordinates, with $(x,y,z)=$ `(xx0,xx1,xx2)`_____no_output_____

if CoordSystem == "Cartesian":
    xmin, xmax, ymin, ymax, zmin, zmax = par.Cparameters("REAL",thismodule,
                                                         ["xmin","xmax","ymin","ymax","zmin","zmax"],
                                                         [ -10.0,  10.0, -10.0,  10.0, -10.0,  10.0])
    xxmin = ["xmin", "ymin", "zmin"]
    xxmax = ["xmax", "ymax", "zmax"]

    xx_to_Cart[0] = xx[0]
    xx_to_Cart[1] = xx[1]
    xx_to_Cart[2] = xx[2]

    xxSph[0] = sp.sqrt(xx[0] ** 2 + xx[1] ** 2 + xx[2] ** 2)
    xxSph[1] = sp.acos(xx[2] / xxSph[0])
    xxSph[2] = sp.atan2(xx[1], xx[0])

    Cart_to_xx[0] = Cartx
    Cart_to_xx[1] = Carty
    Cart_to_xx[2] = Cartz

    scalefactor_orthog[0] = sp.sympify(1)
    scalefactor_orthog[1] = sp.sympify(1)
    scalefactor_orthog[2] = sp.sympify(1)

    # Set the transpose of the matrix of unit vectors
    UnitVectors = [[sp.sympify(1), sp.sympify(0), sp.sympify(0)],
                   [sp.sympify(0), sp.sympify(1), sp.sympify(0)],
                   [sp.sympify(0), sp.sympify(0), sp.sympify(1)]]_____no_output_____%matplotlib inline

import numpy as np               # NumPy: A numerical methods module for Python
import matplotlib.pyplot as plt  # matplotlib: Python module specializing in plotting capabilities

plt.clf()

fig = plt.figure()
ax = fig.gca()
Nx = 16
ax.set_xticks(np.arange(0, 1., 1./Nx))
ax.set_yticks(np.arange(0, 1., 1./Nx))

for tick in ax.get_xticklabels():
    tick.set_rotation(60)

# plt.scatter(x, y)
ax.set_aspect('equal')

plt.grid()

# plt.savefig("Cartgrid.png",dpi=300)
plt.show()
# plt.close(fig)_____no_output_____

### Step 3.c.ii: **`reference_metric::CoordSystem = "SinhCartesian"`** \[Back to [top](#toc)\]
$$\label{sinhcartesian}$$

In this coordinate system, all three coordinates behave like the $z$-coordinate in SinhCylindrical coordinates, i.e.

$$
\begin{align}
x(xx_0) &= \text{AMPLXYZ} \left[\frac{\sinh\left(\frac{xx_0}{\text{SINHWXYZ}}\right)}{\sinh\left(\frac{1}{\text{SINHWXYZ}}\right)}\right]\ ,\\
y(xx_1) &= \text{AMPLXYZ} \left[\frac{\sinh\left(\frac{xx_1}{\text{SINHWXYZ}}\right)}{\sinh\left(\frac{1}{\text{SINHWXYZ}}\right)}\right]\ ,\\
z(xx_2) &= \text{AMPLXYZ} \left[\frac{\sinh\left(\frac{xx_2}{\text{SINHWXYZ}}\right)}{\sinh\left(\frac{1}{\text{SINHWXYZ}}\right)}\right]
\end{align}
$$_____no_output_____

if CoordSystem == "SinhCartesian":
    # SinhCartesian coordinates allows us to push the outer boundary of the
    # computational domain a lot further away, while keeping reasonably high
    # resolution towards the center of the computational grid.

    # Set default values for min and max (x,y,z)
    xxmin = [sp.sympify(-1), sp.sympify(-1), sp.sympify(-1)]
    xxmax = [sp.sympify(+1), sp.sympify(+1), sp.sympify(+1)]

    # Declare basic parameters of the coordinate system and their default values
    AMPLXYZ, SINHWXYZ = par.Cparameters("REAL", thismodule,
                                        ["AMPLXYZ", "SINHWXYZ"],
                                        [     10.0,        0.2])

    # Compute (xx_to_Cart0,xx_to_Cart1,xx_to_Cart2) from (xx0,xx1,xx2)
    for ii in [0, 1, 2]:
        xx_to_Cart[ii] = AMPLXYZ*(sp.exp(xx[ii]/SINHWXYZ) - sp.exp(-xx[ii]/SINHWXYZ))/(sp.exp(1/SINHWXYZ) - sp.exp(-1/SINHWXYZ))

    # Compute (r,th,ph) from (xx_to_Cart2,xx_to_Cart1,xx_to_Cart2)
    xxSph[0] = sp.sqrt(xx_to_Cart[0] ** 2 + xx_to_Cart[1] ** 2 + xx_to_Cart[2] ** 2)
    xxSph[1] = sp.acos(xx_to_Cart[2] / xxSph[0])
    xxSph[2] = sp.atan2(xx_to_Cart[1], xx_to_Cart[0])

    # Compute (xx0,xx1,xx2) from (Cartx,Carty,Cartz)
    Cart_to_xx[0] = SINHWXYZ*sp.asinh(Cartx*sp.sinh(1/SINHWXYZ)/AMPLXYZ)
    Cart_to_xx[1] = SINHWXYZ*sp.asinh(Carty*sp.sinh(1/SINHWXYZ)/AMPLXYZ)
    Cart_to_xx[2] = SINHWXYZ*sp.asinh(Cartz*sp.sinh(1/SINHWXYZ)/AMPLXYZ)

    # Compute scale factors
    scalefactor_orthog[0] = sp.diff(xx_to_Cart[0], xx[0])
    scalefactor_orthog[1] = sp.diff(xx_to_Cart[1], xx[1])
    scalefactor_orthog[2] = sp.diff(xx_to_Cart[2], xx[2])

    # Set the transpose of the matrix of unit vectors
    UnitVectors = [[sp.sympify(1), sp.sympify(0), sp.sympify(0)],
                   [sp.sympify(0), sp.sympify(1), sp.sympify(0)],
                   [sp.sympify(0), sp.sympify(0), sp.sympify(1)]]
_____no_output_____%matplotlib inline

import numpy as np               # NumPy: A numerical methods module for Python
import matplotlib.pyplot as plt  # matplotlib: Python module specializing in plotting capabilities

plt.clf()

fig = plt.figure(dpi=160)
ax = fig.gca()

# Set plot title
ax.set_title(r"$z=0$ slice of the 3D grid")

# Set SINH parameters. Here we assume:
#
# AMPLX  = AMPLY  = SINHA
# SINHWX = SINHWY = SINHW
SINHA = 10.0
SINHW = 0.45

# Set number of points. We assume the same point
# distribution along the (x,y)-directions
Nxxs = 24
xxis = np.linspace(-1,1,Nxxs, endpoint=True)

# Compute axis ticks by evaluating x and y using SinhCartesian coordinates
axis_ticks = []
for i in range(Nxxs):
    axis_ticks.append(SINHA * (np.exp(xxis[i] / SINHW) - np.exp(-xxis[i] / SINHW)) / \
                        (np.exp(1.0 / SINHW) - np.exp(-1.0 / SINHW)))

# Set the axis ticks
ax.set_xticks(axis_ticks)
ax.set_yticks(axis_ticks)

# Set x and y labels. Initialize array with empty strings
labelsx = ["" for i in range(Nxxs)]
labelsy = ["" for i in range(Nxxs)]

# Set x_min and x_max tick label
labelsx[0] = r"-AMPLX"
labelsx[-1] = r"AMPLX"

# Set y_min and y_max tick label
labelsy[0] = r"-AMPLY"
labelsy[-1] = r"AMPLY"

# Set tick labels
ax.set_xticklabels(labelsx)
ax.set_yticklabels(labelsy)

# Rotate x labels by 60 degrees
for tick in ax.get_xticklabels():
    tick.set_rotation(60)

# Draw the x=0 and y=0 ticklabel
ax.text(0,-11,"0",ha="center",va="center")
ax.text(-11,0,"0",ha="center",va="center")

# plt.scatter(x, y)
ax.set_aspect('equal')

plt.grid(color='black',linewidth=0.3)

plt.show()
# plt.savefig("Cartgrid.png",dpi=400)
# plt.close(fig)_____no_output_____

## Step 3.d: [Prolate spheroidal](https://en.wikipedia.org/wiki/Prolate_spheroidal_coordinates)-like coordinate systems \[Back to [top](#toc)\]
$$\label{prolatespheroidal}$$_____no_output_____

### Step 3.d.i: **`reference_metric::CoordSystem = "SymTP"`** \[Back to [top](#toc)\]
$$\label{symtp}$$

The Symmetric TwoPuncture (SymTP) coordinate system is obtained by slightly modifying [prolate spheroidal coordinates](https://en.wikipedia.org/wiki/Prolate_spheroidal_coordinates) (PSC). Standard PSC are related to Cartesian coordinates $(x,y,z)$ via

$$
\begin{aligned}
x &= a\sinh\mu\sin\nu\cos\varphi,\\
y &= a\sinh\mu\sin\nu\sin\varphi,\\
z &= a\cosh\mu\cos\nu = \left(a^{2}\sinh^{2}\mu + a^{2}\right)^{1/2}\cos\nu,
\end{aligned}
$$

where $\mu\in[0,\infty)$, $\nu\in[0,\pi]$, and $\varphi\in[0,2\pi]$, and we have used the [identity](https://en.wikipedia.org/wiki/Hyperbolic_functions)

$$
\cosh^{2}\mu - \sinh^{2}\mu = 1.
$$

PSC have two foci located at $z=\pm a$, where the grid lines get more dense and the grid resolution increases. However, note that the parameter $a$ controls both the foci position *and* the grid scaling, which is not a particularly interesting property.

In order to remedy this, we introduce new coordinates $(xx_{0},xx_{1},xx_{2})$, such that

$$
\begin{aligned}
xx_{0} &= \frac{1}{a}\sinh\mu,\\
xx_{1} &= \nu,\\
xx_{2} &= \varphi,
\end{aligned}
$$

and change $a\to \text{bScale}$, so that we obtain

$$
\begin{aligned}
x &= xx_{0}\sin(xx_{1})\cos(xx_{2}),\\
y &= xx_{0}\sin(xx_{1})\sin(xx_{2}),\\
z &= \left(xx_{0}^{2}+\text{bScale}^{2}\right)\cos(xx_{1}),
\end{aligned}
$$

Note that, for numerical convenience, we change the range of $xx_{2}$ to $[-\pi,\pi]$. Comparing SymTP coordinates with Cylindrical coordinates, we find that $(\rho,\phi,z)=(xx_{0}\sin(xx_{1}), xx_{2}, \sqrt{xx_{0}^2 + \text{bScale}^2}\cos(xx_{1}))$._____no_output_____

if CoordSystem == "SymTP":

    var1, var2= sp.symbols('var1 var2',real=True)
    bScale, AW, AMAX, RHOMAX, ZMIN, ZMAX = par.Cparameters("REAL",thismodule,
                                                           ["bScale","AW","AMAX","RHOMAX","ZMIN","ZMAX"],
                                                           [0.5,     0.2,   10.0,    10.0, -10.0,  10.0])

    # Assuming xx0, xx1, and bScale
    #   are positive makes nice simplifications of
    #   unit vectors possible.
    xx[0],xx[1] = sp.symbols("xx0 xx1", real=True)

    xxmin = [sp.sympify(0), sp.sympify(0),-M_PI]
    xxmax = [         AMAX,          M_PI, M_PI]

    AA = xx[0]

    var1 = sp.sqrt(AA**2 + (bScale * sp.sin(xx[1]))**2)
    var2 = sp.sqrt(AA**2 + bScale**2)

    RHOSYMTP = AA*sp.sin(xx[1])
    PHSYMTP = xx[2]
    ZSYMTP = var2*sp.cos(xx[1])

    xx_to_Cart[0] = AA  *sp.sin(xx[1])*sp.cos(xx[2])
    xx_to_Cart[1] = AA  *sp.sin(xx[1])*sp.sin(xx[2])
    xx_to_Cart[2] = ZSYMTP

    xxSph[0] = sp.sqrt(RHOSYMTP**2 + ZSYMTP**2)
    xxSph[1] = sp.acos(ZSYMTP / xxSph[0])
    xxSph[2] = PHSYMTP

    rSph  = sp.sqrt(Cartx ** 2 + Carty ** 2 + Cartz ** 2)
    thSph = sp.acos(Cartz / rSph)
    phSph = sp.atan2(Carty, Cartx)

    # Mathematica script to compute Cart_to_xx[]
    #             AA = x1;
    #             var2 = Sqrt[AA^2 + bScale^2];
    #             RHOSYMTP = AA*Sin[x2];
    #             ZSYMTP = var2*Cos[x2];
    #             Solve[{rSph == Sqrt[RHOSYMTP^2 + ZSYMTP^2],
    #                    thSph == ArcCos[ZSYMTP/Sqrt[RHOSYMTP^2 + ZSYMTP^2]],
    #                    phSph == x3},
    #                   {x1, x2, x3}]
    Cart_to_xx[0] = sp.sqrt(-bScale**2 + rSph**2 +
                            sp.sqrt(bScale**4 + 2*bScale**2*rSph**2 + rSph**4 -
                                    4*bScale**2*rSph**2*sp.cos(thSph)**2))*M_SQRT1_2 # M_SQRT1_2 = 1/sqrt(2); define this way for UnitTesting

    # The sign() function in the following expression ensures the correct root is taken.
    Cart_to_xx[1] = sp.acos(sp.sign(Cartz)*(
                              sp.sqrt(1 + rSph**2/bScale**2 -
                                      sp.sqrt(bScale**4 + 2*bScale**2*rSph**2 + rSph**4 -
                                              4*bScale**2*rSph**2*sp.cos(thSph)**2)/bScale**2)*M_SQRT1_2)) # M_SQRT1_2 = 1/sqrt(2); define this way for UnitTesting

    Cart_to_xx[2] = phSph_____no_output_____%matplotlib inline

Nxxs   = 24
xx0    = np.linspace(-2,2,Nxxs,endpoint=True)
xx1    = np.linspace(0,np.pi,Nxxs,endpoint=True)
xx2    = 0
bScale = 1

def x(xx0,xx1):
    return xx0 * np.sin(xx1)
def z(xx0,xx1,bScale):
    return np.sqrt(xx0**2 + bScale**2) * np.cos(xx1)

import numpy as np               # NumPy: A numerical methods module for Python
import matplotlib.pyplot as plt  # matplotlib: Python module specializing in plotting capabilities

plt.clf()

fig = plt.figure(dpi=160)
ax = fig.gca()

# Set plot title
ax.set_title(r"""SymTP Coordinates: zx-plane ($xx_{2}$=0 and $xx_{2}=\pi$)
Blue (red) lines have constant $xx_{0}$ ($xx_{1}$)""")

ax.set_xlim(-2.5,2.5)
ax.set_ylim(-2.5,2.5)
ax.set_aspect('equal')
ax.axis('off')

for i0 in range(Nxxs):
    plt.plot(x(xx0[i0],xx1),z(xx0[i0],xx1,bScale),'b',lw=0.75)

for i1 in range(Nxxs):
    plt.plot(x(xx0,xx1[i1]),z(xx0,xx1[i1],bScale),'r',lw=0.75)

plt.show()_____no_output_____

### Step 3.d.ii: **`reference_metric::CoordSystem = "SinhSymTP"`** \[Back to [top](#toc)\]
$$\label{sinhsymtp}$$

SinhSymTP coordinates are obtained from SymTP coordinates by making the substitution

$$
xx0 \to \mathcal{A}\frac{\sinh(xx_{0}/w)}{\sinh(1/w)},
$$

with the further modification that $xx_{0}\in[0,1]$. The parameter $\mathcal{A}$ controls the scale of the grid, while the parameter $w$ controls how densily sampled the region around the foci are._____no_output_____

if CoordSystem == "SinhSymTP":

    var1, var2= sp.symbols('var1 var2',real=True)
    bScale, AW, AMAX, RHOMAX, ZMIN, ZMAX = par.Cparameters("REAL",thismodule,
                                                           ["bScale","AW","AMAX","RHOMAX","ZMIN","ZMAX"],
                                                           [0.5,     0.2,   10.0,    10.0, -10.0,  10.0])

    # Assuming xx0, xx1, and bScale
    #   are positive makes nice simplifications of
    #   unit vectors possible.
    xx[0],xx[1] = sp.symbols("xx0 xx1", real=True)

    xxmin = [sp.sympify(0), sp.sympify(0),-M_PI]
    xxmax = [sp.sympify(1),          M_PI, M_PI]

    AA = AMAX * (sp.exp(xx[0]/SINHWAA) - sp.exp(-xx[0]/SINHWAA)) / (sp.exp(1/SINHWAA) - sp.exp(-1/SINHWAA))

    var1 = sp.sqrt(AA**2 + (bScale * sp.sin(xx[1]))**2)
    var2 = sp.sqrt(AA**2 + bScale**2)

    RHOSYMTP = AA*sp.sin(xx[1])
    PHSYMTP = xx[2]
    ZSYMTP = var2*sp.cos(xx[1])

    xx_to_Cart[0] = AA*sp.sin(xx[1])*sp.cos(xx[2])
    xx_to_Cart[1] = AA*sp.sin(xx[1])*sp.sin(xx[2])
    xx_to_Cart[2] = ZSYMTP

    xxSph[0] = sp.sqrt(RHOSYMTP**2 + ZSYMTP**2)
    xxSph[1] = sp.acos(ZSYMTP / xxSph[0])
    xxSph[2] = PHSYMTP

    rSph  = sp.sqrt(Cartx ** 2 + Carty ** 2 + Cartz ** 2)
    thSph = sp.acos(Cartz / rSph)
    phSph = sp.atan2(Carty, Cartx)

    # Mathematica script to compute Cart_to_xx[]
    #             AA = x1;
    #             var2 = Sqrt[AA^2 + bScale^2];
    #             RHOSYMTP = AA*Sin[x2];
    #             ZSYMTP = var2*Cos[x2];
    #             Solve[{rSph == Sqrt[RHOSYMTP^2 + ZSYMTP^2],
    #                    thSph == ArcCos[ZSYMTP/Sqrt[RHOSYMTP^2 + ZSYMTP^2]],
    #                    phSph == x3},
    #                   {x1, x2, x3}]
    Cart_to_xx[0] = sp.sqrt(-bScale**2 + rSph**2 +
                            sp.sqrt(bScale**4 + 2*bScale**2*rSph**2 + rSph**4 -
                                    4*bScale**2*rSph**2*sp.cos(thSph)**2))*M_SQRT1_2 # M_SQRT1_2 = 1/sqrt(2); define this way for UnitTesting

    # The sign() function in the following expression ensures the correct root is taken.
    Cart_to_xx[1] = sp.acos(sp.sign(Cartz)*(
                              sp.sqrt(1 + rSph**2/bScale**2 -
                                      sp.sqrt(bScale**4 + 2*bScale**2*rSph**2 + rSph**4 -
                                              4*bScale**2*rSph**2*sp.cos(thSph)**2)/bScale**2)*M_SQRT1_2)) # M_SQRT1_2 = 1/sqrt(2); define this way for UnitTesting

    Cart_to_xx[2] = phSph

    scalefactor_orthog[0] = sp.diff(AA,xx[0]) * var1 / var2
    scalefactor_orthog[1] = var1
    scalefactor_orthog[2] = AA * sp.sin(xx[1])

    # Set the transpose of the matrix of unit vectors
    UnitVectors = [[sp.sin(xx[1]) * sp.cos(xx[2]) * var2 / var1,
                    sp.sin(xx[1]) * sp.sin(xx[2]) * var2 / var1,
                    AA * sp.cos(xx[1]) / var1],
                   [AA * sp.cos(xx[1]) * sp.cos(xx[2]) / var1,
                    AA * sp.cos(xx[1]) * sp.sin(xx[2]) / var1,
                        -sp.sin(xx[1]) * var2 / var1],
                   [-sp.sin(xx[2]), sp.cos(xx[2]), sp.sympify(0)]]_____no_output_____%matplotlib inline

import numpy as np               # NumPy: A numerical methods module for Python
import matplotlib.pyplot as plt  # matplotlib: Python module specializing in plotting capabilities

Nxx0   = 12
Nxx1   = 24
xx0    = np.linspace(0,1,Nxx0,endpoint=True)
xx1    = np.linspace(0,np.pi,Nxx1,endpoint=True)
xx2    = 0
bScale = 1
sinhA  = 2.2
sinhW  = 0.3

def rtilde(xx0,sinhA,sinhW):
    return sinhA * np.sinh(xx0/sinhW) / np.sinh(1.0/sinhW)
def x(xx0,xx1,sinhA,sinhW):
    return rtilde(xx0,sinhA,sinhW) * np.sin(xx1)
def z(xx0,xx1,bScale,sinhA,sinhW):
    return np.sqrt(rtilde(xx0,sinhA,sinhW)**2 + bScale**2) * np.cos(xx1)

plt.clf()

fig = plt.figure(dpi=160)
ax = fig.gca()

# Set plot title
ax.set_title(r"""SinhSymTP Coordinates: zx-plane ($xx_{2}$=0 and $xx_{2}=\pi$)
Blue (red) lines have constant $xx_{0}$ ($xx_{1}$)""")

ax.set_xlim(-2.5,2.5)
ax.set_ylim(-2.5,2.5)
ax.set_aspect('equal')
ax.axis('off')

for i0 in range(Nxx0):
    plt.plot(x(xx0[i0],xx1,sinhA,sinhW),z(xx0[i0],xx1,bScale,sinhA,sinhW),'b',lw=0.75)
    plt.plot(-x(xx0[i0],xx1,sinhA,sinhW),z(xx0[i0],xx1,bScale,sinhA,sinhW),'b',lw=0.75)

for i1 in range(Nxx1):
    plt.plot(x(xx0,xx1[i1],sinhA,sinhW),z(xx0,xx1[i1],bScale,sinhA,sinhW),'r',lw=0.75)
    plt.plot(-x(xx0,xx1[i1],sinhA,sinhW),z(xx0,xx1[i1],bScale,sinhA,sinhW),'r',lw=0.75)

plt.show()_____no_output_____

# 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-Reference_Metric.pdf](Tutorial-Reference_Metric.pdf) (Note that clicking on this link may not work; you may need to open the PDF file through another means.)_____no_output_____

import cmdline_helper as cmd    # NRPy+: Multi-platform Python command-line interface
cmd.output_Jupyter_notebook_to_LaTeXed_PDF("Tutorial-Reference_Metric")Created Tutorial-Reference_Metric.tex, and compiled LaTeX file to PDF file
    Tutorial-Reference_Metric.pdf


# Notebook from Hallflower20/supernova-spectrum-analysis
Path: SNID_Template_Reader.ipynb

<code>
import numpy as np
import pandas as pd
from astropy.io import fits
import matplotlib.pyplot as plt
from astropy.table import Table
import glob

%matplotlib inline_____no_output_____typeinfo = {
    "Ia":[1,1],
    "Ia-norm":[1,2],
    "Ia-91T":[1,3],
    "Ia-91bg":[1,4],
    "Ia-csm":[1,5],
    "Ia-02cx":[1,6],
    "Ia-03fg":[1,7],
    "Ib":[2,1],
    "Ib-norm":[2,2],
    "IIb":[2,3],
    "Ibn":[2,4],
    "Ic":[3,1],
    "Ic-norm":[3,2],
    "Ic-BL":[3,3],
    "Ic-SLSN":[3,4],
    "II":[4,1],
    "II-norm":[4,2],
    "IIn":[4,3],
    "NotSN":[5,1],
    "AGN":[5,2],
    "Gal":[5,3],
    "LBV":[5,4],
    "M-star":[5,5],
    "QSO":[5,6],
    "C-star":[5,7],
    "TDE":[5,8]
}_____no_output_____Changes = Table.from_pandas(pd.read_csv("/home/xhall/Documents/SNID/changes.csv"))_____no_output_____Changes_____no_output_____counter = 0
for i in Changes:
    f = open("/home/xhall/Documents/SNID/templates-2.0/" + i["snname"] + ".lnw")
    lines = f.readlines()
    string = lines[0]
    start = string.find(i["old_type"])
    if(start != -1):
        replace = i["new_type"]
        back_string = string[start::]
        back_string_len = len(back_string)
        numlist = typeinfo[replace]
        numstring = str(numlist[0]) + "  " + str(numlist[1])
        back_string_new = str(replace) + " " * (back_string_len - len(numstring) - len(replace) - 1) + numstring + "\n"
        forward_string = string[0:start]
        document = forward_string + back_string_new
        for j in lines[1::]:
            document += j

        newfile = open("/home/xhall/Documents/SNID/templates-2.0/" + i["snname"] + ".lnw", "w+")
        newfile.write(document)
        counter += 1_____no_output_____document_____no_output_____yashviTemplates = glob.glob("/home/xhall/Documents/SNID/yashviTemplates/*.lnw")_____no_output_____templates = glob.glob("/home/xhall/Documents/SNID/templates-2.0/*.lnw")_____no_output_____TemplatesClass = Table(
                    names=("Template", "Class"
                    ),
                    meta={"name": "Template Types"},
                    dtype=("U64", "U64"
                          )
                    )

for i in templates:
    f = open(i)
    lines = f.readlines()
    row = [i.split("/")[-1].split(".")[0],lines[0].split()[-3]]
    TemplatesClass.add_row(row)_____no_output_____yashviTemplatesTemplatesClass = Table(
                    names=("Template", "Class"
                    ),
                    meta={"name": "Template Types"},
                    dtype=("U64", "U64"
                          )
                    )

for i in yashviTemplates:
    f = open(i)
    lines = f.readlines()
    row = [i.split("/")[-1].split(".")[0],lines[0].split()[-3]]
    yashviTemplatesTemplatesClass.add_row(row)_____no_output_____TemplatesClass.to_pandas().to_csv("/home/xhall/Documents/NewZTF/Template_Class.csv", index = False)_____no_output_____len(TemplatesClass[TemplatesClass["Class"]=="IIn"]["Template"])_____no_output_____print(len(TemplatesClass))
print(len(yashviTemplatesTemplatesClass))865
856
TemplatesClass[np.where(TemplatesClass["Class"] == "II-pec")]_____no_output_____for i in TemplatesClass:
    if("TDE" in i["Class"]):
        print(i["Template"])PTF09djl
ASASSN14ae
ASASSN14li
PTF09axc
ASASSN15oi
PTF09ge
PS1_10jh
print(len(np.unique(TemplatesClass["Class"])))
print(len(np.unique(yashviTemplatesTemplatesClass["Class"])))21
20
for i in np.unique(TemplatesClass["Class"]): print(i)AGN
C-star
Gal
II-norm
IIb
IIn
Ia-02cx
Ia-03fg
Ia-91T
Ia-91bg
Ia-csm
Ia-norm
Ib-norm
Ibn
Ic-BL
Ic-SLSN
Ic-norm
LBV
M-star
QSO
TDE
for i in np.unique(yashviTemplatesTemplatesClass["Class"]): print(i)AGN
C-star
Gal
II-norm
IIb
IIn
Ia-02cx
Ia-03fg
Ia-91T
Ia-91bg
Ia-csm
Ia-norm
Ib-norm
Ibn
Ic-BL
Ic-SLSN
Ic-norm
LBV
M-star
QSO
PreferredTemplatesClass = Table(
                    names=("Template", "old_type", "new_type"
                    ),
                    meta={"name": "Template Types"},
                    dtype=("U64", "U64", "U64"
                          )
                    )
for i in templates:
    f = open(i)
    lines = f.readlines()
    row = [i.split("/")[-1].split(".")[0]]
    sntype = lines[0].split()[-3]
    row.append(sntype)
    if(sntype == "Ic-broad"):
        sntype = "Ic-BL"
    elif(sntype == "II"):
        sntype = "II-norm"
    elif(sntype == "IIP"):
        sntype = "II-norm"
    elif(sntype == "IIL"):
        sntype = "II-norm"
    elif(sntype == "Ic-SL"):
        sntype = "SLSN-I"
    elif(sntype == "SLSN-I"):
        sntype = "Ic-SLSN"
    elif(sntype == "Ia-99aa"):
        sntype = "Ia-norm"
    row.append(sntype)
    PreferredTemplatesClass.add_row(row)_____no_output_____for i in np.unique(PreferredTemplatesClass["new_type"]): print(i)AGN
C-star
Gal
II-norm
IIb
IIn
Ia-02cx
Ia-03fg
Ia-91T
Ia-91bg
Ia-csm
Ia-norm
Ib-norm
Ibn
Ic-BL
Ic-SLSN
Ic-norm
LBV
M-star
QSO
TDE
counter = 0
for i in PreferredTemplatesClass:
    f = open("/home/xhall/Documents/SNID/templates-2.0/" + i["Template"] + ".lnw")
    lines = f.readlines()
    string = lines[0]
    start = string.find(i["old_type"])
    if(start != -1):
        replace = i["new_type"]
        back_string = string[start::]
        back_string_len = len(back_string)
        numlist = typeinfo[replace]
        numstring = str(numlist[0]) + "  " + str(numlist[1])
        back_string_new = str(replace) + " " * (back_string_len - len(numstring) - len(replace) - 1) + numstring + "\n"
        forward_string = string[0:start]
        document = forward_string + back_string_new
        for j in lines[1::]:
            document += j

        newfile = open("/home/xhall/Documents/SNID/templates-2.0/" + i["Template"] + ".lnw", "w+")
        newfile.write(document)
        counter += 1_____no_output_____string = "  241 1024   2500.00  10000.00     12     sn1987A       -9.99  II-pec      4  3"
start = string.find("II-pec")
replace = "II-norm"
back_string = string[start::]
back_string_len = len(back_string)
numlist = typeinfo[replace]
numstring = str(numlist[0]) + "  " + str(numlist[1])
back_string_new = str(replace) + " " * (back_string_len - len(numstring) - len(replace)) + numstring
forward_string = string[0:start]
new_string = forward_string + back_string_new_____no_output_____len(new_string)_____no_output_____len("\n")_____no_output_____for i in templates:
    f = open(i)
    lines = f.readlines()
    if(len(lines[0]) != 80):
        print(i)_____no_output_____Table.read("/home/xhall/Documents/NewZTF/SNIDoutput/ZTF17aaajnki_20180320_P60_v2_snid.output", format = "ascii", data_start = 39, names = ["no", "sn", "type", "lap", "rlap", "z", "zerr", "age", "age_flag", "grade"])_____no_output_____for i in (PreferredTemplatesClass["Template"]): print(i + ".lnw")sn02cx.lnw
carbonstar2.lnw
sn03ab_bsnip.lnw
sn95al.lnw
sn2008ar.lnw
sn00H.lnw
sn2008R.lnw
sn07it.lnw
sn06or_bsnip.lnw
sn90I.lnw
sn2002bo.lnw
sn2006cc.lnw
sn94S.lnw
sn2007fs.lnw
sn2004eo.lnw
sn2002jg.lnw
sn99gb_bsnip.lnw
sn2002dj.lnw
sn1999ac.lnw
sn06bq_bsnip.lnw
sn97dc.lnw
ASASSN-15lh.lnw
sn2006gr.lnw
sn06sr_bsnip.lnw
PTF09cnd.lnw
PTF09djl.lnw
kcSB2.lnw
sn98bw.lnw
sn04bi_bsnip.lnw
sn09au.lnw
sn08hs_bsnip.lnw
sn08bj_bsnip.lnw
sn1990U.lnw
sn1984L.lnw
sn2004as.lnw
PTF10bzf.lnw
sn02hn_bsnip.lnw
sn1997dd.lnw
sn2005iq.lnw
sn2007bi.lnw
kcSB1.lnw
sn2002er.lnw
sn95J_bsnip.lnw
sn2006el.lnw
sn06cz_bsnip.lnw
sn2012il.lnw
PTF10hgi.lnw
sn2005ek.lnw
sn2003bg.lnw
sn2006cz.lnw
sn01X_bsnip.lnw
sn2002cu.lnw
sn04et_bsnip.lnw
sn03iv_bsnip.lnw
sn2006cf.lnw
sn04ey_bsnip.lnw
sn06Y.lnw
sn2003lw.lnw
sn04aq_bsnip.lnw
sn1995ak.lnw
sn2011dh.lnw
sn2008Z.lnw
sn02kg_bsnip.lnw
sn1999cp.lnw
sn04ez_bsnip.lnw
sn08be_bsnip.lnw
sn06cp_bsnip.lnw
sn2003cg.lnw
sn2000cp.lnw
sn1999gp.lnw
sn2006ot.lnw
sn02bg_bsnip.lnw
SCP06F6.lnw
sn07ag_bsnip.lnw
sn04dd_bsnip.lnw
sn1990aa.lnw
sn2005mf.lnw
PTF12gzk.lnw
sn08A_bsnip.lnw
sn04fx_bsnip.lnw
sn02ic.lnw
sn1995E.lnw
sn99eb_bsnip.lnw
sn2001bf.lnw
sn2011kl.lnw
sn2010ay.lnw
sn98ef_bsnip.lnw
sn2006X.lnw
sn92ar.lnw
sn1996bk.lnw
sn2006fo.lnw
sn90K.lnw
sn04et.lnw
sn2005gj.lnw
sn2001cp.lnw
sn06ke_bsnip.lnw
sn2002dl.lnw
sn84L.lnw
sn2001cj.lnw
sn90N.lnw
sn06ef_bsnip.lnw
sn02cf_bsnip.lnw
sn02ei_bsnip.lnw
sn1999ee.lnw
sn1996bv.lnw
sn2006lf.lnw
sn09bz.lnw
sn95F.lnw
sn2005la.lnw
sn09ao.lnw
sn2005da.lnw
PTF09cwl.lnw
sn2003kc.lnw
sn1996cb.lnw
sn2000E.lnw
lbv99bw.lnw
sn1999da.lnw
sn2008af.lnw
sn05am_bsnip.lnw
sn2007ba.lnw
sn06iw.lnw
PTF09atu.lnw
sn2006bz.lnw
sn08bl_bsnip.lnw
sn90U.lnw
sn2001E.lnw
sn2007ci.lnw
sn06bp_bsnip.lnw
sn1996ai.lnw
sn99ed_bsnip.lnw
sn2004bk.lnw
kcE.lnw
sn05ad_bsnip.lnw
sn02bz_bsnip.lnw
sn1997cn.lnw
ASASSN14ae.lnw
sn2001fh.lnw
sn07fr_bsnip.lnw
sn1997Y.lnw
sn2000fa.lnw
sn2006ac.lnw
sn02ef_bsnip.lnw
sn2007au.lnw
sn04dj_bsnip.lnw
sn93G_bsnip.lnw
sn07bb_bsnip.lnw
sn06dw_bsnip.lnw
sn04er.lnw
sn04bw_bsnip.lnw
sn05bc_bsnip.lnw
sn2001ej.lnw
sn94W_bsnip.lnw
sn98bu.lnw
sn06bz_bsnip.lnw
sn2005hf.lnw
sn99el_bsnip.lnw
sn97Y_bsnip.lnw
sn95E.lnw
sn06cx_bsnip.lnw
sn90aa.lnw
sn2000dk.lnw
sn95D.lnw
LSQ12dlf.lnw
sn02dq_bsnip.lnw
sn2000dm.lnw
sn92H.lnw
sn99dk_bsnip.lnw
sn06ab_bsnip.lnw
sn2005ls.lnw
sn2001gc.lnw
sn01cy_bsnip.lnw
ASASSN14li.lnw
sn2002ha.lnw
sn04fu_bsnip.lnw
sn03iq_bsnip.lnw
DES13S2cmm.lnw
sn2001V.lnw
sn01hg_bsnip.lnw
sn05gj.lnw
sn1996bl.lnw
sn2006ev.lnw
sn2011ke.lnw
PTF11rks.lnw
sn98dt.lnw
sn02bo_bsnip.lnw
sn1990B.lnw
sn00cn_bsnip.lnw
sn2006bw.lnw
sn05bi_bsnip.lnw
sn88Z_bsnip.lnw
sn2001ck.lnw
sn2005be.lnw
sn91A.lnw
sn99aa.lnw
sn2004dj.lnw
sn2007qe.lnw
sn05kc_bsnip.lnw
sn2005A.lnw
sn2007F.lnw
sn2005cf.lnw
sn1991M.lnw
sn1992H.lnw
sn07bc_bsnip.lnw
sn2006gj.lnw
sn2005ar.lnw
sn03ip_bsnip.lnw
sn2002cf.lnw
sn97eg_bsnip.lnw
sn2006br.lnw
sn1996bo.lnw
sn2002jy.lnw
sn2000cf.lnw
sn2006gt.lnw
sn2005kc.lnw
sn1994T.lnw
sn97ei.lnw
sn2004eu.lnw
sn1997dq.lnw
sn2005cs.lnw
sn2002es.lnw
sn93ad_bsnip.lnw
sn2006cq.lnw
sn98aq.lnw
sn2004et.lnw
sn01ef_bsnip.lnw
sn2007Y.lnw
sn2005nb.lnw
sn2008C.lnw
sn2007kk.lnw
kcSB4.lnw
sn2007rz.lnw
m3.lnw
sn2011bm.lnw
sn08ec_bsnip.lnw
sn1997ei.lnw
sn04fc_bsnip.lnw
sn2002cs.lnw
sn06bc.lnw
sn93W_bsnip.lnw
sn2004ge.lnw
sn06ee.lnw
sn91N.lnw
PTF10vgv.lnw
sn02hd_bsnip.lnw
sn99br.lnw
sn2000bh.lnw
sn2007kj.lnw
sn1991A.lnw
sn02fb_bsnip.lnw
sn1997do.lnw
sn2002do.lnw
sn91ar.lnw
sn1987A.lnw
sn2006hb.lnw
sn2004fe.lnw
sn2007ag.lnw
sn08fq_bsnip.lnw
sn2005bc.lnw
sn04fc.lnw
sn94D.lnw
sn05el_bsnip.lnw
sn06ca_bsnip.lnw
sn94ak_bsnip.lnw
sn04bl_bsnip.lnw
sn99dq_bsnip.lnw
sn00dn_bsnip.lnw
sn2007ru.lnw
sn90e.lnw
sn04eo.lnw
sn05dv_bsnip.lnw
sn2003ic.lnw
sn2008an.lnw
sn02ap_bsnip.lnw
sn2004gv.lnw
sn2013dx.lnw
sn06em_bsnip.lnw
sn1998ec.lnw
sn2002kf.lnw
sn98S_bsnip.lnw
sn2002hw.lnw
sn2006bt.lnw
sn2010bh.lnw
sn94T.lnw
sn1993J.lnw
sn04eo_bsnip.lnw
sn2006cj.lnw
sn03U_bsnip.lnw
m1.lnw
sn1999ek.lnw
sn1999cw.lnw
sn1999dq.lnw
sn2005bo.lnw
sn05be_bsnip.lnw
sn98A_bsnip.lnw
sn1999dn.lnw
sn2004bg.lnw
sn04gd_bsnip.lnw
sn2006bp.lnw
PTF09axc.lnw
sn1999ef.lnw
sn05eq_bsnip.lnw
sn2006oa.lnw
sn2006em.lnw
sn97br.lnw
sn1998bu.lnw
sn2008ax.lnw
qso_bal2.lnw
sn1998bw.lnw
sn02ca_bsnip.lnw
sn1994ae.lnw
sn2007D.lnw
sn1997X.lnw
sn93E_bsnip.lnw
sn2007bm.lnw
ASASSN15oi.lnw
sn1990I.lnw
sn2011fu.lnw
sn2015bn.lnw
sn06bu_bsnip.lnw
magneticWD.lnw
sn2006sr.lnw
sn1999gh.lnw
sn96X.lnw
sn98bu_bsnip.lnw
sn1997ef.lnw
sn2006ld.lnw
sn1998aq.lnw
sn2005hj.lnw
sn2006bq.lnw
sn2004fu.lnw
sn07al_bsnip.lnw
sn2008am.lnw
sn2000ce.lnw
sn02ha_bsnip.lnw
sn04fz_bsnip.lnw
sn2008Q.lnw
sn08aw_bsnip.lnw
sn05cs.lnw
sn99em_bsnip.lnw
sn02A_bsnip.lnw
sn08iy_bsnip.lnw
sn03cg.lnw
sn2001ah.lnw
sn03kb_bsnip.lnw
sn2004dt.lnw
sn2006D.lnw
sn07ba_bsnip.lnw
sn2002ck.lnw
sn2005ki.lnw
sn04ef_bsnip.lnw
sn95ac.lnw
sn2005M.lnw
sn1999cl.lnw
sn2009mg.lnw
sn2013dg.lnw
sn2002ic.lnw
sn05bl_bsnip.lnw
sn2002ef.lnw
sn93J.lnw
PTF10qts.lnw
sn2007co.lnw
sn2006cp.lnw
sn98dt_bsnip.lnw
sn08gj_bsnip.lnw
sn1998ef.lnw
sn2001fe.lnw
sn00dg_bsnip.lnw
sn97dq.lnw
carbonstar3.lnw
sn2001G.lnw
sn2006al.lnw
sn1995bd.lnw
DES14X3taz.lnw
sn2011kf.lnw
sn1991bg.lnw
sn2007gr.lnw
sn86G.lnw
sn1996X.lnw
sn2009bb.lnw
sn05dz.lnw
sn2005lu.lnw
sn1979C.lnw
PTF12dam.lnw
sn04dt_bsnip.lnw
sn06gz.lnw
sn91M.lnw
sn1998ab.lnw
sn1999X.lnw
sn79C.lnw
sn03hl_bsnip.lnw
sn2004gc.lnw
sn06os_bsnip.lnw
sn2002bf.lnw
sn05bx_bsnip.lnw
sn02cs_bsnip.lnw
kcSB6.lnw
sn92A.lnw
sn07il.lnw
sn95G_bsnip.lnw
sn2000B.lnw
sn2005hg.lnw
sn1994D.lnw
kcSB3.lnw
sn93ac.lnw
sn1999aa.lnw
sn2007cg.lnw
sn2007al.lnw
sn2000bk.lnw
sn2006nz.lnw
sn2003gn.lnw
sn1992A.lnw
sn97ef.lnw
sn02cr_bsnip.lnw
sn2000cu.lnw
sn1995D.lnw
sn2001ep.lnw
sn01do_bsnip.lnw
sn04bg_bsnip.lnw
sn1994M.lnw
sn02an_bsnip.lnw
sn91av_bsnip.lnw
sn2005U.lnw
sn2002ji.lnw
sn1997dt.lnw
sn03du.lnw
sn96ae_bsnip.lnw
sn95V_bsnip.lnw
sn2003it.lnw
sn04S.lnw
sn97cy.lnw
sn94S_bsnip.lnw
sn07bd_bsnip.lnw
sn2008bf.lnw
sn03Y_bsnip.lnw
sn1990N.lnw
sn2007A.lnw
sn2007cl.lnw
sn99dn.lnw
sn2010ma.lnw
PTF09ge.lnw
sn2005hk.lnw
sn2009jf.lnw
sn2001N.lnw
sn1998S.lnw
sn99em.lnw
agn.lnw
sn06ov_bsnip.lnw
sn01cm_bsnip.lnw
sn01en_bsnip.lnw
sn05gj_bsnip.lnw
sn02ap.lnw
sn2002ao.lnw
sn2011ei.lnw
sn07af_bsnip.lnw
sn1986G.lnw
sn05hj.lnw
sn2006le.lnw
sn1989B.lnw
sn07oc.lnw
sn04gr_bsnip.lnw
sn2006aj.lnw
sn2001ay.lnw
lbv1999bw.lnw
sn98E_bsnip.lnw
sn2006lv.lnw
sn2004gk.lnw
sn2000cw.lnw
sn1998dk.lnw
sn83N.lnw
sn91bg.lnw
qso.lnw
sn2002eu.lnw
sn1995al.lnw
sn2007ca.lnw
sn2007sr.lnw
sn2005am.lnw
sn06aj.lnw
sn04gs_bsnip.lnw
sn90Q_bsnip.lnw
sn2005mc.lnw
sn01K_bsnip.lnw
sn02bu_bsnip.lnw
sn2003hv.lnw
carbonstar1.lnw
sn88a.lnw
sn2001bg.lnw
sn96L.lnw
sn05cf_bsnip.lnw
sn03bn.lnw
sn98es_bsnip.lnw
sn00dm_bsnip.lnw
sn95E_bsnip.lnw
sn1991ar.lnw
sn1996ab.lnw
sn08aq_bsnip.lnw
sn08gf_bsnip.lnw
kcSb.lnw
sn1990K.lnw
sn2007ce.lnw
sn2003iv.lnw
sn01bg_bsnip.lnw
lbv01ac.lnw
sn00E.lnw
sn07C_bsnip.lnw
qso2.lnw
LSQ14bdq.lnw
sn2007bd.lnw
sn05aq_bsnip.lnw
PS1-10awh.lnw
sn06be_bsnip.lnw
sn94Q.lnw
sn00ev_bsnip.lnw
sn05af_bsnip.lnw
sn1995F.lnw
sn95X_bsnip.lnw
sn2005eq.lnw
sn01dk_bsnip.lnw
sn99by_bsnip.lnw
sn2008aq.lnw
sn2006mo.lnw
sn2005hc.lnw
sn07be_bsnip.lnw
sn07gk_bsnip.lnw
SNLS07D2bv.lnw
sn02eu_bsnip.lnw
sn00cp_bsnip.lnw
sn07K_bsnip.lnw
SNLS06D4eu.lnw
sn1980K.lnw
sn1999di.lnw
snls03D3bb.lnw
sn2004gs.lnw
sn2012ap.lnw
sn00dk_bsnip.lnw
sn2005mz.lnw
sn2005ke.lnw
iPTF13ehe.lnw
PS1-10ky.lnw
sn06ev_bsnip.lnw
sn02he_bsnip.lnw
sn08ht_bsnip.lnw
sn96cb.lnw
sn1991N.lnw
PS1_10jh.lnw
sn2000H.lnw
sn1998bp.lnw
sn2008cw.lnw
sn91ao_bsnip.lnw
sn2004L.lnw
sn04cz_bsnip.lnw
sn2006az.lnw
sn94M.lnw
sn2007cq.lnw
sn08in_bsnip.lnw
sn2008ae.lnw
sn1997br.lnw
sn2002fk.lnw
sn2001da.lnw
sn2007nq.lnw
sn2009er.lnw
sn1983V.lnw
sn2007bz.lnw
sn2001br.lnw
sn95D_bsnip.lnw
sn03B_bsnip.lnw
sn97ef_bsnip.lnw
m8.lnw
sn2003W.lnw
sn94ae_bsnip.lnw
sn1999ej.lnw
iPTF13ajg.lnw
sn2004at.lnw
sn03ei_bsnip.lnw
sn06it.lnw
sn06cs_bsnip.lnw
sn07fs_bsnip.lnw
sn05hk_bsnip.lnw
sn92H_bsnip.lnw
sn2008D.lnw
sn2002G.lnw
sn93J_bsnip.lnw
sn99ee.lnw
sn91T_bsnip.lnw
sn06cf_bsnip.lnw
sn06bp.lnw
sn94Y_bsnip.lnw
sn1997E.lnw
sn97da_bsnip.lnw
kcSB5.lnw
sn03ai_bsnip.lnw
sn08bt_bsnip.lnw
sn1999em.lnw
sn1998eg.lnw
sn94I.lnw
qso_bal.lnw
sn98T.lnw
sn1999gi.lnw
sn2006ak.lnw
sn02jy_bsnip.lnw
sn2006S.lnw
sn07A_bsnip.lnw
sn2006kf.lnw
sn1994S.lnw
sn02bx_bsnip.lnw
sn2001ex.lnw
sn1997bq.lnw
sn03G_bsnip.lnw
sn2002hd.lnw
sn04dj.lnw
sn1997cy.lnw
sn91T.lnw
sn06ac_bsnip.lnw
sn07od_bsnip.lnw
sn1998dt.lnw
sn06my_bsnip.lnw
sn2002cx.lnw
PS1-10bzj.lnw
sn02bo.lnw
sn2001eh.lnw
sn06kf_bsnip.lnw
sn01M_bsnip.lnw
iPTF13bvn.lnw
sn2006jc.lnw
L1.lnw
sn1992ar.lnw
sn91C_bsnip.lnw
sn97dd_bsnip.lnw
sn2005kf.lnw
sn2004fz.lnw
sn1981B.lnw
sn2007C.lnw
sn08in.lnw
sn01dw_bsnip.lnw
sn98S.lnw
sn2002he.lnw
sn00cw_bsnip.lnw
sn2008L.lnw
sn2007fb.lnw
sn2004gt.lnw
sn99ac.lnw
sn2002dp.lnw
sn2007le.lnw
sn99da_bsnip.lnw
sn99gi_bsnip.lnw
sn1998co.lnw
sn97br_bsnip.lnw
sn90H_bsnip.lnw
sn2006oz.lnw
sn2007ax.lnw
sn90B.lnw
sn83V.lnw
sn94ae.lnw
sn02er_bsnip.lnw
sn2003dh.lnw
sn1997bp.lnw
sn1999cc.lnw
sn01ad_bsnip.lnw
sn05ay_bsnip.lnw
sn2003hu.lnw
sn07ay_bsnip.lnw
sn1983N.lnw
sn08ds_bsnip.lnw
SSS120810-23.lnw
sn2013cq.lnw
sn01gd_bsnip.lnw
sn1996Z.lnw
sn00fa_bsnip.lnw
sn2004ef.lnw
sn06gt_bsnip.lnw
sn1996L.lnw
sn06T_bsnip.lnw
sn99gd_bsnip.lnw
sn2001az.lnw
sn99gi.lnw
sn05hk.lnw
sn80K.lnw
sn2000dn.lnw
sn2007uy.lnw
sn1996C.lnw
sn2003fa.lnw
sn1999by.lnw
sn94I_bsnip.lnw
sn2006te.lnw
sn96C.lnw
sn98ec_bsnip.lnw
sn05kl.lnw
sn2007bc.lnw
sn05ke_bsnip.lnw
sn2006eq.lnw
sn2002cd.lnw
sn99cp_bsnip.lnw
sn2006et.lnw
sn99di.lnw
sn2006cm.lnw
mstar.lnw
sn2003ch.lnw
sn2007bj.lnw
sn1999gd.lnw
sn2005kl.lnw
sn02eg_bsnip.lnw
sn03gd_bsnip.lnw
sn00fe_bsnip.lnw
sn05kd_bsnip.lnw
sn96an_bsnip.lnw
sn2003Y.lnw
sn1998es.lnw
sn99by.lnw
sn2007jg.lnw
sn1998de.lnw
sn06et_bsnip.lnw
sn06cq_bsnip.lnw
sn2001gd.lnw
sn01el.lnw
sn1994Q.lnw
sn2003jd.lnw
sn03iq.lnw
sn2001en.lnw
sn02hk_bsnip.lnw
sn2006H.lnw
sn2007S.lnw
sn2001ig.lnw
sn08es_bsnip.lnw
sn97cn.lnw
sn2006ax.lnw
sn01ir_bsnip.lnw
sn97dd.lnw
m5.lnw
sn2001ai.lnw
sn87A.lnw
sn1999ex.lnw
lbv2001ac.lnw
lbv03hy.lnw
kcSc.lnw
sn05cs_bsnip.lnw
sn2002fb.lnw
sn06ej_bsnip.lnw
sn96cc_bsnip.lnw
sn2003cq.lnw
sn2004dk.lnw
sn2005ap.lnw
sn89B.lnw
sn1995ac.lnw
sn2009nz.lnw
sn03fg.lnw
sn2007I.lnw
sn98dl_bsnip.lnw
sn04du_bsnip.lnw
sn05ms_bsnip.lnw
sn1998fa.lnw
sn2002ap.lnw
sn2006eu.lnw
sn91bg_bsnip.lnw
kcSa.lnw
sn02J_bsnip.lnw
sn2007ap.lnw
sn2004gq.lnw
sn2005cc.lnw
sn2004S.lnw
sn05de_bsnip.lnw
sn2007ux.lnw
sn1998V.lnw
sn01ey_bsnip.lnw
sn02fk_bsnip.lnw
sn06dm_bsnip.lnw
sn2005cg.lnw
sn02eo_bsnip.lnw
sn08il.lnw
sn2002de.lnw
sn2002cr.lnw
sn03gg_bsnip.lnw
sn04fx.lnw
sn2004dn.lnw
sn07av_bsnip.lnw
sn81B.lnw
sn1990O.lnw
sn02kf_bsnip.lnw
sn2004aw.lnw
sn2008A.lnw
sn99aw.lnw
sn2000dg.lnw
sn06tf_bsnip.lnw
sn2012bz.lnw
sn07cl_bsnip.lnw
sn03gu_bsnip.lnw
sn07fb_bsnip.lnw
sn2004bd.lnw
sn2005na.lnw
sn1994I.lnw
sn1998dx.lnw
sn2002aw.lnw
sn2006T.lnw
sn2007af.lnw
sn2001el.lnw
sn2005el.lnw
sn99Z_bsnip.lnw
sn2009iz.lnw
sn00cu_bsnip.lnw
sn2005az.lnw
LSQ14mo.lnw
sn03he_bsnip.lnw
sn01ep_bsnip.lnw
sn95ac_bsnip.lnw
sn2005bl.lnw
sn07ck_bsnip.lnw
sn02er.lnw
sn1988L.lnw
sn07kk_bsnip.lnw
sn03cq_bsnip.lnw
sn04aw.lnw
sn1984A.lnw
sn1998dm.lnw
sn07aa_bsnip.lnw
sn05ki_bsnip.lnw
sn2000cn.lnw
sn06lf_bsnip.lnw
sn03gq_bsnip.lnw
sn02el_bsnip.lnw
sn05ip_bsnip.lnw
sn2008bo.lnw
sn92ad_bsnip.lnw
sn1998dh.lnw
sn2006lc.lnw
sn2013dk.lnw
sn1998T.lnw
sn01eh_bsnip.lnw
sn2006gz.lnw
sn2004ff.lnw
lbv2003hy.lnw
sn2000er.lnw
sn04as_bsnip.lnw
sn2002hu.lnw
sn07qe_bsnip.lnw
sn90O.lnw
sn06by_bsnip.lnw
PS1-11ap.lnw
sn06N_bsnip.lnw
sn88L.lnw
sn07oc_bsnip.lnw
sn2003du.lnw
sn1991T.lnw
sn08D_bsnip.lnw
PTF10cwr.lnw
sn95bd.lnw
sn2005eu.lnw
sn1993ac.lnw
sn2007ae.lnw
sn1999bh.lnw
sn2006ck.lnw
sn98dx_bsnip.lnw
sn2003kf.lnw
sn07bm_bsnip.lnw
sn04eu_bsnip.lnw
sn1999aw.lnw
kcS0.lnw
sn2003U.lnw
sn06gy_bsnip.lnw
sn2006N.lnw
sn1997dc.lnw
sn2004ao.lnw
sn2007bg.lnw
sn99ex.lnw
sn97ab_bsnip.lnw
sn2006ep.lnw
sn99aa_bsnip.lnw
sn2007hj.lnw

</code>


# Notebook from jchodera/jacs-dataset-analysis
Path: notebook.ipynb

This notebook is an analysis of the errors in relative free energy calculations from the Schrödinger JACS dataset:
> Wang, L., Wu, Y., Deng, Y., Kim, B., Pierce, L., Krilov, G., ... & Romero, D. L. (2015). Accurate and reliable prediction of relative ligand binding potency in prospective drug discovery by way of a modern free-energy calculation protocol and force field. Journal of the American Chemical Society, 137(7), 2695-2703.

http://doi.org/10.1021/ja512751q_____no_output_____

<code>
%matplotlib inline
import pandas as pd
import numpy as np
import seaborn as sns
import matplotlib.pylab as plt_____no_output_____# Read the Excel sheet
df = pd.read_excel('ja512751q_si_003.xlsx', sheet_name='ddG')_____no_output_____# Delete rows with summary statistics
rows_to_drop = list()
for i, row in df.iterrows():
    if str(df.loc[i,'Ligand1']) == 'nan':
        rows_to_drop.append(i)
print('dropping rows: {}'.format(rows_to_drop))
df = df.drop(index=rows_to_drop);dropping rows: [330]
# Populate 'system' field for each entry
system = df.loc[0,'system']
for i, row in df.iterrows():
    if str(df.loc[i,'system']) == 'nan':
        df.loc[i, "system"] = system
    else:
        system = df.loc[i, "system"]_____no_output_____df_____no_output_____def bootstrap_statistic(errors, ci=0.95, statistic='rmse', nbootstrap = 1000):
    """Compute mean and confidence intervals of specified statistic.

    Parameters
    ----------
    errors : ndarray of shape (N,)
        The errors to bootstrap
    ci : float, optional, default=0.95
        Interval for CI
    statistic : str, optional, default='rmse'
        Statistic to compute; one of ['rmse', 'mue']
    nbootstrap : int, optional. default=10000
        Number of bootstrap samples

    Returns
    -------
    mean : float
        The mean statistic for the whole dataset
    stderr : float
        The standard error
    low, high : float
        Low and high ends of CI
    """

    def compute_statistic(errors, statistic):
        if statistic == 'rmse':
            return np.sqrt(np.mean(errors**2))
        elif statistic == 'mue':
            return np.mean(np.abs(errors))
        else:
            raise Exception("unknown statistic '{}'".format(statistic))

    sample_size = len(errors)
    rmse_n = np.zeros([nbootstrap], np.float64)
    for replicate in range(nbootstrap):
        bootstrapped_sample = np.random.choice(np.arange(sample_size), size=[sample_size])
        rmse_n[replicate] = compute_statistic(errors[bootstrapped_sample], statistic)

    rmse_n = np.sort(rmse_n)

    rmse = compute_statistic(errors, statistic)
    drmse = np.std(rmse_n)

    low_frac = (1.0-ci)/2.0
    high_frac = 1.0 - low_frac
    rmse_low = rmse_n[int(np.floor(nbootstrap*low_frac))]
    rmse_high = rmse_n[int(np.ceil(nbootstrap*high_frac))]

    return rmse, drmse, rmse_low, rmse_high_____no_output_____# Collect data by system
def plot_data(rows):
    exp_ddg = rows['exp_ddG'].values
    ccc_ddg = rows['ccc_ddG'].values
    ccc_error = rows['ccc_error'].values
    error = rows['Error_ccc'].values
    xmin = min(exp_ddg.min(), ccc_ddg.min()) - 0.5
    xmax = min(exp_ddg.max(), ccc_ddg.max()) + 0.5
    plt.xlabel('experiment $\Delta \Delta G$ (kcal/mol)');
    plt.ylabel('cycle closure $\Delta \Delta G$ (kcal/mol)');
    plt.plot([xmin, xmax], [xmin, xmax], 'b-');
    plt.plot(exp_ddg, ccc_ddg, 'ko');
    plt.plot([exp_ddg, exp_ddg], [ccc_ddg-2*ccc_error, ccc_ddg+2*ccc_error], 'k-', alpha=0.3);

    rmse, drmse, rmse_low, rmse_high = bootstrap_statistic(error, statistic='rmse')
    mue, dmue, mue_low, mue_high = bootstrap_statistic(error, statistic='mue')
    title = """{} (N = {})
    RMSE {:.1f} [95%: {:.1f}, {:.1f}] kcal/mol
    MUE {:.1f} [95%: {:.1f}, {:.1f}] kcal/mol
    """.format(system, len(exp_ddg), rmse, rmse_low, rmse_high, mue, mue_low, mue_high)
    plt.title(title);

    plt.axis('square');
    plt.xlim(xmin, xmax);
    plt.ylim(xmin, xmax);

systems = df['system'].unique()
nsystems = len(systems)
nx = int(np.ceil(np.sqrt(nsystems)))
ny = int(np.ceil(np.sqrt(nsystems)))
fig = plt.figure(figsize=[12,12])
for plot_index, system in enumerate(systems):
    plt.subplot(ny, nx, plot_index+1)
    rows = df.query("system == '{}'".format(system))
    plot_data(rows)

plt.subplot(ny, nx, nsystems+1)
system = 'all'
plot_data(df)

fig.tight_layout()
fig.savefig('jacs-analysis.pdf');_____no_output_____
</code>


# Notebook from Anantha-Rao12/QuantChaos
Path: notebooks/1dkickedrotor.ipynb

from classical_kickedrotor import KickedRotor1D
import numpy as np
import matplotlib.pyplot as plt
#import seaborn as sns ; sns.set()_____no_output_____

# Classical Kicked Rotor (CKR)

- A classical kicked rotor represents a classical particle constrained to move on a ring and subjected to periodic kicking forces. These kicks are modelled as delta-function potentials that are periodic (also called 'Dirac combs'). Between two successive kicks, the particle undergoes free-particle dynamics.
- The classical kicked rotor is one of the simplest dynamical systems where one can observe chaos in 1-dimension by varying the kicking strength of the external field.
- The dynamics is given by the standard map (aka "[Chirikov Map"](http://www.scholarpedia.org/article/Chirikov_standard_map)"):
$$p_{n+1} = p_n + K\sin{q_n}$$
$$q_{n+1} = q_n + p_{n+1}$$_____no_output_____# Step 1 : A single classical kicked rotor_____no_output_____

# First, we create a classical kicked rotor object
ckr = KickedRotor1D(kicking_strength=0.5,initial_state=[1,2])_____no_output_____# We can then obtain its dynamics by iteratively constructing the phase-space using the chirikov map

pspace_ckr = ckr.get_phasespace(ntimesteps=100,keep_modulus=True)
print('Shape of phasespace elements under time evolution:',pspace_ckr.shape)Shape of phasespace elements under time evolution: (2, 100)
# Now we can plot how the angle and angular momentum respectively change with time

fig,axes = plt.subplots(nrows=2,ncols=1,figsize=(7,5))

p1, = axes[1].plot(pspace_ckr[0,:],'r--',label='Angular momentum (p)')
p2, = axes[0].plot(pspace_ckr[1,:],'ko-',label='Angle (q)')

axes[1].set(xlabel='Time',ylabel='Ang.momentum')
axes[0].set(xlabel='Time',ylabel='Angle (q)')
axes[0].legend(bbox_to_anchor=[1.1,0.6])
axes[1].legend(bbox_to_anchor=[1,0.6])
plt.tight_layout()_____no_output_____# We can plot the phasespace as follows:

plt.plot(pspace_ckr[0,:],pspace_ckr[1,:], '--')
plt.xlabel('Angle (q)')
plt.ylabel('Angular Momentum (p)')
plt.title('Phasespace for CKR ($\\kappa = 0.5$)')
plt.show()_____no_output_____

# Many Rotors each with different kicking strengths

When the kicking strength is beyound a critical value $K_C$(~0.972), we observe a sensitive dependence on initial conditions $\Rightarrow$ Chaos!_____no_output_____

kick = np.linspace(0,6,12) #create kick strength array_____no_output_____fig,axes = plt.subplots(figsize=(12,8),nrows=3,ncols=4)
fig.subplots_adjust(hspace=0.5)
fig.suptitle('Classical Kicked Rotor',fontsize="18")

for index,ax in enumerate(axes.flatten()):
    rotor = KickedRotor1D(kick[index],[1,1])
    phspace = rotor.get_phasespace(1000)
    ax.hist2d(phspace[0,:],phspace[1,:], (100, 100), cmap=plt.cm.jet)
    ax.set_xlabel('Position (q)')
    ax.set_ylabel('Momentum (p)')
    ax.set_title(f'$\kappa$ = {kick[index]:.3}')

plt.tight_layout()_____no_output_____

## Observe diffusive behaviour in Chaotic regime_____no_output_____

rotor1 = KickedRotor1D(kicking_strength=1)
rotor2 = KickedRotor1D(kicking_strength=4)
rotor3 = KickedRotor1D(kicking_strength=6)

rotor1diff = rotor1.get_diffusion(ntimesteps=100,keep_modulus=False)
rotor2diff = rotor2.get_diffusion(ntimesteps=100,keep_modulus=False)
rotor3diff = rotor3.get_diffusion(ntimesteps=100,keep_modulus=False)_____no_output_____fig,axes=plt.subplots(3,1)
axes[0].plot(rotor1diff, label=f'$\\kappa$ = {rotor1.kicking_strength}')
axes[0].set(xlabel='Time', ylabel='D')
axes[0].legend()

axes[1].plot(rotor2diff, label=f'$\\kappa$ = {rotor2.kicking_strength}')
axes[1].set(xlabel='Time', ylabel='D')
axes[1].legend()

axes[2].plot(rotor3diff, label=f'$\\kappa$ = {rotor3.kicking_strength}')
axes[2].set(xlabel='Time', ylabel='D')
axes[2].legend()

plt.suptitle("Diffusive Behaviour in Momentum space (D$\\approx p^2/K$)")
plt.tight_layout()
plt.legend()
plt.show()_____no_output_____