# Generating C code for the right-hand sides of Maxwell's equations, in ***curvilinear*** coordinates, using a reference metric formalism

## Author: Ian Ruchlin
### Formatting improvements courtesy Brandon Clark

[comment]: <> (Abstract: TODO)

### The following formulations of Maxwell's equations, called System I and System II, are described in [Illustrating Stability Properties of Numerical Relativity in Electrodynamics](https://arxiv.org/abs/gr-qc/0201051) by Knapp et al.

**Notebook Status:**  In progress

**Validation Notes:** This module has not yet undergone validation testing. Do ***not*** use it until after appropriate validation testing has been performed.

## Introduction:
[Maxwell's equations](https://en.wikipedia.org/wiki/Maxwell%27s_equations) are subject to the Gauss' law constraint
$$\mathcal{C} \equiv \hat{D}_{i} E^{i} - 4 \pi \rho = 0 \; ,$$
where $E^{i}$ is the electric vector field, $\hat{D}_{i}$ is the [covariant derivative](https://en.wikipedia.org/wiki/Covariant_derivative) associated with the reference metric $\hat{\gamma}_{i j}$ (which is taken to represent flat space), and $\rho$ is the electric charge density. We use $\mathcal{C}$ as a measure of numerical error. Maxwell's equations are also required to satisfy $\hat{D}_{i} B^{i} = 0$, where $B^{i}$ is the magnetic vector field. The magnetic constraint implies that the magnetic field can be expressed as
$$B_{i} = \epsilon_{i j k} \hat{D}^{j} A^{k} \; ,$$
where $\epsilon_{i j k}$ is the totally antisymmetric [Levi-Civita tensor](https://en.wikipedia.org/wiki/Levi-Civita_symbol) and $A^{i}$ is the vector potential field. Together with the scalar potential $\psi$, the electric field can be expressed in terms of the potential fields as
$$E_{i} = -\hat{D}_{i} \psi - \partial_{t} A_{i} \; .$$
For now, we work in vacuum, where the electric charge density and the electric current density vector both vanish ($\rho = 0$ and $j_{i} = 0$).

In addition to the Gauss constraints, the electric and magnetic fields obey two independent [electromagnetic invariants](https://en.wikipedia.org/wiki/Classification_of_electromagnetic_fields#Invariants)
\begin{align}
\mathcal{P} &\equiv B_{i} B^{i} - E_{i} E^{i} \; , \\
\mathcal{Q} &\equiv E_{i} B^{i} \; .
\end{align}
In vacuum, these satisfy $\mathcal{P} = \mathcal{Q} = 0$.

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

This notebook is organized as follows

1. [Step 1](#sys1): System I
1. [Step 2](#sys2): System II
1. [Step 3](#latex_pdf_output): Output this notebook to $\LaTeX$-formatted PDF file

# Step 1: System I \[Back to [top](#toc)\]
$$\label{sys1}$$

In terms of the above definitions, the evolution Maxwell's equations take the form
\begin{align}
\partial_{t} A_{i} &= -E_{i} - \hat{D}_{i} \psi \; , \\
\partial_{t} E_{i} &= -\hat{D}_{j} \hat{D}^{j} A_{i} + \hat{D}_{i} \hat{D}_{j} A^{j}\; , \\
\partial_{t} \psi &= -\hat{D}_{i} A^{i} \; .
\end{align}
Note that this coupled system contains mixed second derivatives in the second term on the right hand side of the $E^{i}$ evolution equation. We will revisit this fact when building System II.

It can be shown that the Gauss constraint satisfies the evolution equation
$$\partial_{t} \mathcal{C} = 0 \; .$$
This implies that any constraint violating numerical error remains fixed in place during the evolution. This becomes problematic when the violations grow large and spoil the physics of the simulation.

```python
import NRPy_param_funcs as par   # NRPy+: parameter interface
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
import finite_difference as fin  # NRPy+: Finite difference C code generation module
import reference_metric as rfm   # NRPy+: Reference metric support
from outputC import lhrh         # NRPy+: Core C code output module

par.set_parval_from_str("reference_metric::CoordSystem", "Spherical")
par.set_parval_from_str("grid::DIM", 3)

rfm.reference_metric()

# The name of this module ("maxwell") is given by __name__:
thismodule = __name__

# Step 0: Read the spatial dimension parameter as DIM.
DIM = par.parval_from_str("grid::DIM")

# Step 1: Set the finite differencing order to 4.
par.set_parval_from_str("finite_difference::FD_CENTDERIVS_ORDER", 4)

# Step 2: Register gridfunctions that are needed as input.
psi = gri.register_gridfunctions("EVOL", ["psi"])

# Step 3a: Declare the rank-1 indexed expressions E_{i}, A_{i},
#          and \partial_{i} \psi. Derivative variables like these
#          must have an underscore in them, so the finite
#          difference module can parse the variable name properly.
ED = ixp.register_gridfunctions_for_single_rank1("EVOL", "ED")
AD = ixp.register_gridfunctions_for_single_rank1("EVOL", "AD")
psi_dD = ixp.declarerank1("psi_dD")

# Step 3b: Declare the rank-2 indexed expression \partial_{j} A_{i},
#          which is not symmetric in its indices.
#          Derivative variables like these must have an underscore
#          in them, so the finite difference module can parse the
#          variable name properly.
AD_dD = ixp.declarerank2("AD_dD", "nosym")

# Step 3c: Declare the rank-3 indexed expression \partial_{jk} A_{i},
#          which is symmetric in the two {jk} indices.
AD_dDD = ixp.declarerank3("AD_dDD", "sym12")

# Step 4: Calculate first and second covariant derivatives, and the
#         necessary contractions.
# First covariant derivative
# D_{j} A_{i} = A_{i,j} - \Gamma^{k}_{ij} A_{k}
AD_dHatD = ixp.zerorank2()
for i in range(DIM):
    for j in range(DIM):
        AD_dHatD[i][j] = AD_dD[i][j]
        for k in range(DIM):
            AD_dHatD[i][j] -= rfm.GammahatUDD[k][i][j] * AD[k]

# Second covariant derivative
# D_{k} D_{j} A_{i} = \partial_{k} D_{j} A_{i} - \Gamma^{l}_{jk} D_{l} A_{i}
#                    - \Gamma^{l}_{ik} D_{j} A_{l}
#                   =  A_{i,jk}
#                    - \Gamma^{l}_{ij,k} A_{l}
#                    - \Gamma^{l}_{ij}   A_{l,k}
#                    - \Gamma^{l}_{jk}   A_{i;\hat{l}}
#                    - \Gamma^{l}_{ik}   A_{l;\hat{j}}
AD_dHatDD = ixp.zerorank3()
for i in range(DIM):
    for j in range(DIM):
        for k in range(DIM):
            AD_dHatDD[i][j][k] = AD_dDD[i][j][k]
            for l in range(DIM):
                AD_dHatDD[i][j][k] += - rfm.GammahatUDDdD[l][i][j][k]  * AD[l]  \
                                      - rfm.GammahatUDD[l][i][j] *    AD_dD[l][k] \
                                      - rfm.GammahatUDD[l][j][k] * AD_dHatD[i][l] \
                                      - rfm.GammahatUDD[l][i][k] * AD_dHatD[l][j]

# Covariant divergence
# D_{i} A^{i} = ghat^{ij} D_{j} A_{i}
DivA = 0
# Gradient of covariant divergence
# DivA_dD_{i} = ghat^{jk} A_{k;\hat{j}\hat{i}}
DivA_dD = ixp.zerorank1()
# Covariant Laplacian
# LapAD_{i} = ghat^{jk} A_{i;\hat{j}\hat{k}}
LapAD = ixp.zerorank1()
for i in range(DIM):
    for j in range(DIM):
        DivA += rfm.ghatUU[i][j] * AD_dHatD[i][j]
        for k in range(DIM):
            DivA_dD[i] += rfm.ghatUU[j][k] * AD_dHatDD[k][j][i]
            LapAD[i]   += rfm.ghatUU[j][k] * AD_dHatDD[i][j][k]

# Step 5: Define right-hand sides for the evolution.
AD_rhs = ixp.zerorank1()
ED_rhs = ixp.zerorank1()
for i in range(DIM):
    AD_rhs[i] = -ED[i] - psi_dD[i]
    ED_rhs[i] = -LapAD[i] + DivA_dD[i]
psi_rhs = -DivA

# Step 6: Generate C code for System I Maxwell's evolution equations,
#         print output to the screen (standard out, or stdout).
lhrh_list = []
for i in range(DIM):
    lhrh_list.append(lhrh(lhs=gri.gfaccess("rhs_gfs", "AD" + str(i)), rhs=AD_rhs[i]))
    lhrh_list.append(lhrh(lhs=gri.gfaccess("rhs_gfs", "ED" + str(i)), rhs=ED_rhs[i]))
lhrh_list.append(lhrh(lhs=gri.gfaccess("rhs_gfs", "psi"), rhs=psi_rhs))

fin.FD_outputC("stdout", lhrh_list)
```

    {
       /*
        * NRPy+ Finite Difference Code Generation, Step 1 of 2: Read from main memory and compute finite difference stencils:
        */
       /*
        *  Original SymPy expressions:
        *  "[const double AD_dD00 = invdx0*(-2*AD0_i0m1_i1_i2/3 + AD0_i0m2_i1_i2/12 + 2*AD0_i0p1_i1_i2/3 - AD0_i0p2_i1_i2/12),
        *    const double AD_dD01 = invdx1*(-2*AD0_i0_i1m1_i2/3 + AD0_i0_i1m2_i2/12 + 2*AD0_i0_i1p1_i2/3 - AD0_i0_i1p2_i2/12),
        *    const double AD_dD02 = invdx2*(-2*AD0_i0_i1_i2m1/3 + AD0_i0_i1_i2m2/12 + 2*AD0_i0_i1_i2p1/3 - AD0_i0_i1_i2p2/12),
        *    const double AD_dD10 = invdx0*(-2*AD1_i0m1_i1_i2/3 + AD1_i0m2_i1_i2/12 + 2*AD1_i0p1_i1_i2/3 - AD1_i0p2_i1_i2/12),
        *    const double AD_dD11 = invdx1*(-2*AD1_i0_i1m1_i2/3 + AD1_i0_i1m2_i2/12 + 2*AD1_i0_i1p1_i2/3 - AD1_i0_i1p2_i2/12),
        *    const double AD_dD12 = invdx2*(-2*AD1_i0_i1_i2m1/3 + AD1_i0_i1_i2m2/12 + 2*AD1_i0_i1_i2p1/3 - AD1_i0_i1_i2p2/12),
        *    const double AD_dD20 = invdx0*(-2*AD2_i0m1_i1_i2/3 + AD2_i0m2_i1_i2/12 + 2*AD2_i0p1_i1_i2/3 - AD2_i0p2_i1_i2/12),
        *    const double AD_dD21 = invdx1*(-2*AD2_i0_i1m1_i2/3 + AD2_i0_i1m2_i2/12 + 2*AD2_i0_i1p1_i2/3 - AD2_i0_i1p2_i2/12),
        *    const double AD_dD22 = invdx2*(-2*AD2_i0_i1_i2m1/3 + AD2_i0_i1_i2m2/12 + 2*AD2_i0_i1_i2p1/3 - AD2_i0_i1_i2p2/12),
        *    const double AD_dDD001 = invdx0*invdx1*(4*AD0_i0m1_i1m1_i2/9 - AD0_i0m1_i1m2_i2/18 - 4*AD0_i0m1_i1p1_i2/9 + AD0_i0m1_i1p2_i2/18 - AD0_i0m2_i1m1_i2/18 + AD0_i0m2_i1m2_i2/144 + AD0_i0m2_i1p1_i2/18 - AD0_i0m2_i1p2_i2/144 - 4*AD0_i0p1_i1m1_i2/9 + AD0_i0p1_i1m2_i2/18 + 4*AD0_i0p1_i1p1_i2/9 - AD0_i0p1_i1p2_i2/18 + AD0_i0p2_i1m1_i2/18 - AD0_i0p2_i1m2_i2/144 - AD0_i0p2_i1p1_i2/18 + AD0_i0p2_i1p2_i2/144),
        *    const double AD_dDD002 = invdx0*invdx2*(4*AD0_i0m1_i1_i2m1/9 - AD0_i0m1_i1_i2m2/18 - 4*AD0_i0m1_i1_i2p1/9 + AD0_i0m1_i1_i2p2/18 - AD0_i0m2_i1_i2m1/18 + AD0_i0m2_i1_i2m2/144 + AD0_i0m2_i1_i2p1/18 - AD0_i0m2_i1_i2p2/144 - 4*AD0_i0p1_i1_i2m1/9 + AD0_i0p1_i1_i2m2/18 + 4*AD0_i0p1_i1_i2p1/9 - AD0_i0p1_i1_i2p2/18 + AD0_i0p2_i1_i2m1/18 - AD0_i0p2_i1_i2m2/144 - AD0_i0p2_i1_i2p1/18 + AD0_i0p2_i1_i2p2/144),
        *    const double AD_dDD011 = invdx1**2*(-5*AD0/2 + 4*AD0_i0_i1m1_i2/3 - AD0_i0_i1m2_i2/12 + 4*AD0_i0_i1p1_i2/3 - AD0_i0_i1p2_i2/12),
        *    const double AD_dDD022 = invdx2**2*(-5*AD0/2 + 4*AD0_i0_i1_i2m1/3 - AD0_i0_i1_i2m2/12 + 4*AD0_i0_i1_i2p1/3 - AD0_i0_i1_i2p2/12),
        *    const double AD_dDD100 = invdx0**2*(-5*AD1/2 + 4*AD1_i0m1_i1_i2/3 - AD1_i0m2_i1_i2/12 + 4*AD1_i0p1_i1_i2/3 - AD1_i0p2_i1_i2/12),
        *    const double AD_dDD101 = invdx0*invdx1*(4*AD1_i0m1_i1m1_i2/9 - AD1_i0m1_i1m2_i2/18 - 4*AD1_i0m1_i1p1_i2/9 + AD1_i0m1_i1p2_i2/18 - AD1_i0m2_i1m1_i2/18 + AD1_i0m2_i1m2_i2/144 + AD1_i0m2_i1p1_i2/18 - AD1_i0m2_i1p2_i2/144 - 4*AD1_i0p1_i1m1_i2/9 + AD1_i0p1_i1m2_i2/18 + 4*AD1_i0p1_i1p1_i2/9 - AD1_i0p1_i1p2_i2/18 + AD1_i0p2_i1m1_i2/18 - AD1_i0p2_i1m2_i2/144 - AD1_i0p2_i1p1_i2/18 + AD1_i0p2_i1p2_i2/144),
        *    const double AD_dDD112 = invdx1*invdx2*(4*AD1_i0_i1m1_i2m1/9 - AD1_i0_i1m1_i2m2/18 - 4*AD1_i0_i1m1_i2p1/9 + AD1_i0_i1m1_i2p2/18 - AD1_i0_i1m2_i2m1/18 + AD1_i0_i1m2_i2m2/144 + AD1_i0_i1m2_i2p1/18 - AD1_i0_i1m2_i2p2/144 - 4*AD1_i0_i1p1_i2m1/9 + AD1_i0_i1p1_i2m2/18 + 4*AD1_i0_i1p1_i2p1/9 - AD1_i0_i1p1_i2p2/18 + AD1_i0_i1p2_i2m1/18 - AD1_i0_i1p2_i2m2/144 - AD1_i0_i1p2_i2p1/18 + AD1_i0_i1p2_i2p2/144),
        *    const double AD_dDD122 = invdx2**2*(-5*AD1/2 + 4*AD1_i0_i1_i2m1/3 - AD1_i0_i1_i2m2/12 + 4*AD1_i0_i1_i2p1/3 - AD1_i0_i1_i2p2/12),
        *    const double AD_dDD200 = invdx0**2*(-5*AD2/2 + 4*AD2_i0m1_i1_i2/3 - AD2_i0m2_i1_i2/12 + 4*AD2_i0p1_i1_i2/3 - AD2_i0p2_i1_i2/12),
        *    const double AD_dDD202 = invdx0*invdx2*(4*AD2_i0m1_i1_i2m1/9 - AD2_i0m1_i1_i2m2/18 - 4*AD2_i0m1_i1_i2p1/9 + AD2_i0m1_i1_i2p2/18 - AD2_i0m2_i1_i2m1/18 + AD2_i0m2_i1_i2m2/144 + AD2_i0m2_i1_i2p1/18 - AD2_i0m2_i1_i2p2/144 - 4*AD2_i0p1_i1_i2m1/9 + AD2_i0p1_i1_i2m2/18 + 4*AD2_i0p1_i1_i2p1/9 - AD2_i0p1_i1_i2p2/18 + AD2_i0p2_i1_i2m1/18 - AD2_i0p2_i1_i2m2/144 - AD2_i0p2_i1_i2p1/18 + AD2_i0p2_i1_i2p2/144),
        *    const double AD_dDD211 = invdx1**2*(-5*AD2/2 + 4*AD2_i0_i1m1_i2/3 - AD2_i0_i1m2_i2/12 + 4*AD2_i0_i1p1_i2/3 - AD2_i0_i1p2_i2/12),
        *    const double AD_dDD212 = invdx1*invdx2*(4*AD2_i0_i1m1_i2m1/9 - AD2_i0_i1m1_i2m2/18 - 4*AD2_i0_i1m1_i2p1/9 + AD2_i0_i1m1_i2p2/18 - AD2_i0_i1m2_i2m1/18 + AD2_i0_i1m2_i2m2/144 + AD2_i0_i1m2_i2p1/18 - AD2_i0_i1m2_i2p2/144 - 4*AD2_i0_i1p1_i2m1/9 + AD2_i0_i1p1_i2m2/18 + 4*AD2_i0_i1p1_i2p1/9 - AD2_i0_i1p1_i2p2/18 + AD2_i0_i1p2_i2m1/18 - AD2_i0_i1p2_i2m2/144 - AD2_i0_i1p2_i2p1/18 + AD2_i0_i1p2_i2p2/144),
        *    const double psi_dD0 = invdx0*(-2*psi_i0m1_i1_i2/3 + psi_i0m2_i1_i2/12 + 2*psi_i0p1_i1_i2/3 - psi_i0p2_i1_i2/12),
        *    const double psi_dD1 = invdx1*(-2*psi_i0_i1m1_i2/3 + psi_i0_i1m2_i2/12 + 2*psi_i0_i1p1_i2/3 - psi_i0_i1p2_i2/12),
        *    const double psi_dD2 = invdx2*(-2*psi_i0_i1_i2m1/3 + psi_i0_i1_i2m2/12 + 2*psi_i0_i1_i2p1/3 - psi_i0_i1_i2p2/12)]"
        */
       const double psi_i0_i1_i2m2 = in_gfs[IDX4(PSIGF, i0,i1,i2-2)];
       const double psi_i0_i1_i2m1 = in_gfs[IDX4(PSIGF, i0,i1,i2-1)];
       const double psi_i0_i1m2_i2 = in_gfs[IDX4(PSIGF, i0,i1-2,i2)];
       const double psi_i0_i1m1_i2 = in_gfs[IDX4(PSIGF, i0,i1-1,i2)];
       const double psi_i0m2_i1_i2 = in_gfs[IDX4(PSIGF, i0-2,i1,i2)];
       const double psi_i0m1_i1_i2 = in_gfs[IDX4(PSIGF, i0-1,i1,i2)];
       const double psi_i0p1_i1_i2 = in_gfs[IDX4(PSIGF, i0+1,i1,i2)];
       const double psi_i0p2_i1_i2 = in_gfs[IDX4(PSIGF, i0+2,i1,i2)];
       const double psi_i0_i1p1_i2 = in_gfs[IDX4(PSIGF, i0,i1+1,i2)];
       const double psi_i0_i1p2_i2 = in_gfs[IDX4(PSIGF, i0,i1+2,i2)];
       const double psi_i0_i1_i2p1 = in_gfs[IDX4(PSIGF, i0,i1,i2+1)];
       const double psi_i0_i1_i2p2 = in_gfs[IDX4(PSIGF, i0,i1,i2+2)];
       const double ED0 = in_gfs[IDX4(ED0GF, i0,i1,i2)];
       const double ED1 = in_gfs[IDX4(ED1GF, i0,i1,i2)];
       const double ED2 = in_gfs[IDX4(ED2GF, i0,i1,i2)];
       const double AD0_i0m2_i1_i2m2 = in_gfs[IDX4(AD0GF, i0-2,i1,i2-2)];
       const double AD0_i0m1_i1_i2m2 = in_gfs[IDX4(AD0GF, i0-1,i1,i2-2)];
       const double AD0_i0_i1_i2m2 = in_gfs[IDX4(AD0GF, i0,i1,i2-2)];
       const double AD0_i0p1_i1_i2m2 = in_gfs[IDX4(AD0GF, i0+1,i1,i2-2)];
       const double AD0_i0p2_i1_i2m2 = in_gfs[IDX4(AD0GF, i0+2,i1,i2-2)];
       const double AD0_i0m2_i1_i2m1 = in_gfs[IDX4(AD0GF, i0-2,i1,i2-1)];
       const double AD0_i0m1_i1_i2m1 = in_gfs[IDX4(AD0GF, i0-1,i1,i2-1)];
       const double AD0_i0_i1_i2m1 = in_gfs[IDX4(AD0GF, i0,i1,i2-1)];
       const double AD0_i0p1_i1_i2m1 = in_gfs[IDX4(AD0GF, i0+1,i1,i2-1)];
       const double AD0_i0p2_i1_i2m1 = in_gfs[IDX4(AD0GF, i0+2,i1,i2-1)];
       const double AD0_i0m2_i1m2_i2 = in_gfs[IDX4(AD0GF, i0-2,i1-2,i2)];
       const double AD0_i0m1_i1m2_i2 = in_gfs[IDX4(AD0GF, i0-1,i1-2,i2)];
       const double AD0_i0_i1m2_i2 = in_gfs[IDX4(AD0GF, i0,i1-2,i2)];
       const double AD0_i0p1_i1m2_i2 = in_gfs[IDX4(AD0GF, i0+1,i1-2,i2)];
       const double AD0_i0p2_i1m2_i2 = in_gfs[IDX4(AD0GF, i0+2,i1-2,i2)];
       const double AD0_i0m2_i1m1_i2 = in_gfs[IDX4(AD0GF, i0-2,i1-1,i2)];
       const double AD0_i0m1_i1m1_i2 = in_gfs[IDX4(AD0GF, i0-1,i1-1,i2)];
       const double AD0_i0_i1m1_i2 = in_gfs[IDX4(AD0GF, i0,i1-1,i2)];
       const double AD0_i0p1_i1m1_i2 = in_gfs[IDX4(AD0GF, i0+1,i1-1,i2)];
       const double AD0_i0p2_i1m1_i2 = in_gfs[IDX4(AD0GF, i0+2,i1-1,i2)];
       const double AD0_i0m2_i1_i2 = in_gfs[IDX4(AD0GF, i0-2,i1,i2)];
       const double AD0_i0m1_i1_i2 = in_gfs[IDX4(AD0GF, i0-1,i1,i2)];
       const double AD0 = in_gfs[IDX4(AD0GF, i0,i1,i2)];
       const double AD0_i0p1_i1_i2 = in_gfs[IDX4(AD0GF, i0+1,i1,i2)];
       const double AD0_i0p2_i1_i2 = in_gfs[IDX4(AD0GF, i0+2,i1,i2)];
       const double AD0_i0m2_i1p1_i2 = in_gfs[IDX4(AD0GF, i0-2,i1+1,i2)];
       const double AD0_i0m1_i1p1_i2 = in_gfs[IDX4(AD0GF, i0-1,i1+1,i2)];
       const double AD0_i0_i1p1_i2 = in_gfs[IDX4(AD0GF, i0,i1+1,i2)];
       const double AD0_i0p1_i1p1_i2 = in_gfs[IDX4(AD0GF, i0+1,i1+1,i2)];
       const double AD0_i0p2_i1p1_i2 = in_gfs[IDX4(AD0GF, i0+2,i1+1,i2)];
       const double AD0_i0m2_i1p2_i2 = in_gfs[IDX4(AD0GF, i0-2,i1+2,i2)];
       const double AD0_i0m1_i1p2_i2 = in_gfs[IDX4(AD0GF, i0-1,i1+2,i2)];
       const double AD0_i0_i1p2_i2 = in_gfs[IDX4(AD0GF, i0,i1+2,i2)];
       const double AD0_i0p1_i1p2_i2 = in_gfs[IDX4(AD0GF, i0+1,i1+2,i2)];
       const double AD0_i0p2_i1p2_i2 = in_gfs[IDX4(AD0GF, i0+2,i1+2,i2)];
       const double AD0_i0m2_i1_i2p1 = in_gfs[IDX4(AD0GF, i0-2,i1,i2+1)];
       const double AD0_i0m1_i1_i2p1 = in_gfs[IDX4(AD0GF, i0-1,i1,i2+1)];
       const double AD0_i0_i1_i2p1 = in_gfs[IDX4(AD0GF, i0,i1,i2+1)];
       const double AD0_i0p1_i1_i2p1 = in_gfs[IDX4(AD0GF, i0+1,i1,i2+1)];
       const double AD0_i0p2_i1_i2p1 = in_gfs[IDX4(AD0GF, i0+2,i1,i2+1)];
       const double AD0_i0m2_i1_i2p2 = in_gfs[IDX4(AD0GF, i0-2,i1,i2+2)];
       const double AD0_i0m1_i1_i2p2 = in_gfs[IDX4(AD0GF, i0-1,i1,i2+2)];
       const double AD0_i0_i1_i2p2 = in_gfs[IDX4(AD0GF, i0,i1,i2+2)];
       const double AD0_i0p1_i1_i2p2 = in_gfs[IDX4(AD0GF, i0+1,i1,i2+2)];
       const double AD0_i0p2_i1_i2p2 = in_gfs[IDX4(AD0GF, i0+2,i1,i2+2)];
       const double AD1_i0_i1m2_i2m2 = in_gfs[IDX4(AD1GF, i0,i1-2,i2-2)];
       const double AD1_i0_i1m1_i2m2 = in_gfs[IDX4(AD1GF, i0,i1-1,i2-2)];
       const double AD1_i0_i1_i2m2 = in_gfs[IDX4(AD1GF, i0,i1,i2-2)];
       const double AD1_i0_i1p1_i2m2 = in_gfs[IDX4(AD1GF, i0,i1+1,i2-2)];
       const double AD1_i0_i1p2_i2m2 = in_gfs[IDX4(AD1GF, i0,i1+2,i2-2)];
       const double AD1_i0_i1m2_i2m1 = in_gfs[IDX4(AD1GF, i0,i1-2,i2-1)];
       const double AD1_i0_i1m1_i2m1 = in_gfs[IDX4(AD1GF, i0,i1-1,i2-1)];
       const double AD1_i0_i1_i2m1 = in_gfs[IDX4(AD1GF, i0,i1,i2-1)];
       const double AD1_i0_i1p1_i2m1 = in_gfs[IDX4(AD1GF, i0,i1+1,i2-1)];
       const double AD1_i0_i1p2_i2m1 = in_gfs[IDX4(AD1GF, i0,i1+2,i2-1)];
       const double AD1_i0m2_i1m2_i2 = in_gfs[IDX4(AD1GF, i0-2,i1-2,i2)];
       const double AD1_i0m1_i1m2_i2 = in_gfs[IDX4(AD1GF, i0-1,i1-2,i2)];
       const double AD1_i0_i1m2_i2 = in_gfs[IDX4(AD1GF, i0,i1-2,i2)];
       const double AD1_i0p1_i1m2_i2 = in_gfs[IDX4(AD1GF, i0+1,i1-2,i2)];
       const double AD1_i0p2_i1m2_i2 = in_gfs[IDX4(AD1GF, i0+2,i1-2,i2)];
       const double AD1_i0m2_i1m1_i2 = in_gfs[IDX4(AD1GF, i0-2,i1-1,i2)];
       const double AD1_i0m1_i1m1_i2 = in_gfs[IDX4(AD1GF, i0-1,i1-1,i2)];
       const double AD1_i0_i1m1_i2 = in_gfs[IDX4(AD1GF, i0,i1-1,i2)];
       const double AD1_i0p1_i1m1_i2 = in_gfs[IDX4(AD1GF, i0+1,i1-1,i2)];
       const double AD1_i0p2_i1m1_i2 = in_gfs[IDX4(AD1GF, i0+2,i1-1,i2)];
       const double AD1_i0m2_i1_i2 = in_gfs[IDX4(AD1GF, i0-2,i1,i2)];
       const double AD1_i0m1_i1_i2 = in_gfs[IDX4(AD1GF, i0-1,i1,i2)];
       const double AD1 = in_gfs[IDX4(AD1GF, i0,i1,i2)];
       const double AD1_i0p1_i1_i2 = in_gfs[IDX4(AD1GF, i0+1,i1,i2)];
       const double AD1_i0p2_i1_i2 = in_gfs[IDX4(AD1GF, i0+2,i1,i2)];
       const double AD1_i0m2_i1p1_i2 = in_gfs[IDX4(AD1GF, i0-2,i1+1,i2)];
       const double AD1_i0m1_i1p1_i2 = in_gfs[IDX4(AD1GF, i0-1,i1+1,i2)];
       const double AD1_i0_i1p1_i2 = in_gfs[IDX4(AD1GF, i0,i1+1,i2)];
       const double AD1_i0p1_i1p1_i2 = in_gfs[IDX4(AD1GF, i0+1,i1+1,i2)];
       const double AD1_i0p2_i1p1_i2 = in_gfs[IDX4(AD1GF, i0+2,i1+1,i2)];
       const double AD1_i0m2_i1p2_i2 = in_gfs[IDX4(AD1GF, i0-2,i1+2,i2)];
       const double AD1_i0m1_i1p2_i2 = in_gfs[IDX4(AD1GF, i0-1,i1+2,i2)];
       const double AD1_i0_i1p2_i2 = in_gfs[IDX4(AD1GF, i0,i1+2,i2)];
       const double AD1_i0p1_i1p2_i2 = in_gfs[IDX4(AD1GF, i0+1,i1+2,i2)];
       const double AD1_i0p2_i1p2_i2 = in_gfs[IDX4(AD1GF, i0+2,i1+2,i2)];
       const double AD1_i0_i1m2_i2p1 = in_gfs[IDX4(AD1GF, i0,i1-2,i2+1)];
       const double AD1_i0_i1m1_i2p1 = in_gfs[IDX4(AD1GF, i0,i1-1,i2+1)];
       const double AD1_i0_i1_i2p1 = in_gfs[IDX4(AD1GF, i0,i1,i2+1)];
       const double AD1_i0_i1p1_i2p1 = in_gfs[IDX4(AD1GF, i0,i1+1,i2+1)];
       const double AD1_i0_i1p2_i2p1 = in_gfs[IDX4(AD1GF, i0,i1+2,i2+1)];
       const double AD1_i0_i1m2_i2p2 = in_gfs[IDX4(AD1GF, i0,i1-2,i2+2)];
       const double AD1_i0_i1m1_i2p2 = in_gfs[IDX4(AD1GF, i0,i1-1,i2+2)];
       const double AD1_i0_i1_i2p2 = in_gfs[IDX4(AD1GF, i0,i1,i2+2)];
       const double AD1_i0_i1p1_i2p2 = in_gfs[IDX4(AD1GF, i0,i1+1,i2+2)];
       const double AD1_i0_i1p2_i2p2 = in_gfs[IDX4(AD1GF, i0,i1+2,i2+2)];
       const double AD2_i0_i1m2_i2m2 = in_gfs[IDX4(AD2GF, i0,i1-2,i2-2)];
       const double AD2_i0_i1m1_i2m2 = in_gfs[IDX4(AD2GF, i0,i1-1,i2-2)];
       const double AD2_i0m2_i1_i2m2 = in_gfs[IDX4(AD2GF, i0-2,i1,i2-2)];
       const double AD2_i0m1_i1_i2m2 = in_gfs[IDX4(AD2GF, i0-1,i1,i2-2)];
       const double AD2_i0_i1_i2m2 = in_gfs[IDX4(AD2GF, i0,i1,i2-2)];
       const double AD2_i0p1_i1_i2m2 = in_gfs[IDX4(AD2GF, i0+1,i1,i2-2)];
       const double AD2_i0p2_i1_i2m2 = in_gfs[IDX4(AD2GF, i0+2,i1,i2-2)];
       const double AD2_i0_i1p1_i2m2 = in_gfs[IDX4(AD2GF, i0,i1+1,i2-2)];
       const double AD2_i0_i1p2_i2m2 = in_gfs[IDX4(AD2GF, i0,i1+2,i2-2)];
       const double AD2_i0_i1m2_i2m1 = in_gfs[IDX4(AD2GF, i0,i1-2,i2-1)];
       const double AD2_i0_i1m1_i2m1 = in_gfs[IDX4(AD2GF, i0,i1-1,i2-1)];
       const double AD2_i0m2_i1_i2m1 = in_gfs[IDX4(AD2GF, i0-2,i1,i2-1)];
       const double AD2_i0m1_i1_i2m1 = in_gfs[IDX4(AD2GF, i0-1,i1,i2-1)];
       const double AD2_i0_i1_i2m1 = in_gfs[IDX4(AD2GF, i0,i1,i2-1)];
       const double AD2_i0p1_i1_i2m1 = in_gfs[IDX4(AD2GF, i0+1,i1,i2-1)];
       const double AD2_i0p2_i1_i2m1 = in_gfs[IDX4(AD2GF, i0+2,i1,i2-1)];
       const double AD2_i0_i1p1_i2m1 = in_gfs[IDX4(AD2GF, i0,i1+1,i2-1)];
       const double AD2_i0_i1p2_i2m1 = in_gfs[IDX4(AD2GF, i0,i1+2,i2-1)];
       const double AD2_i0_i1m2_i2 = in_gfs[IDX4(AD2GF, i0,i1-2,i2)];
       const double AD2_i0_i1m1_i2 = in_gfs[IDX4(AD2GF, i0,i1-1,i2)];
       const double AD2_i0m2_i1_i2 = in_gfs[IDX4(AD2GF, i0-2,i1,i2)];
       const double AD2_i0m1_i1_i2 = in_gfs[IDX4(AD2GF, i0-1,i1,i2)];
       const double AD2 = in_gfs[IDX4(AD2GF, i0,i1,i2)];
       const double AD2_i0p1_i1_i2 = in_gfs[IDX4(AD2GF, i0+1,i1,i2)];
       const double AD2_i0p2_i1_i2 = in_gfs[IDX4(AD2GF, i0+2,i1,i2)];
       const double AD2_i0_i1p1_i2 = in_gfs[IDX4(AD2GF, i0,i1+1,i2)];
       const double AD2_i0_i1p2_i2 = in_gfs[IDX4(AD2GF, i0,i1+2,i2)];
       const double AD2_i0_i1m2_i2p1 = in_gfs[IDX4(AD2GF, i0,i1-2,i2+1)];
       const double AD2_i0_i1m1_i2p1 = in_gfs[IDX4(AD2GF, i0,i1-1,i2+1)];
       const double AD2_i0m2_i1_i2p1 = in_gfs[IDX4(AD2GF, i0-2,i1,i2+1)];
       const double AD2_i0m1_i1_i2p1 = in_gfs[IDX4(AD2GF, i0-1,i1,i2+1)];
       const double AD2_i0_i1_i2p1 = in_gfs[IDX4(AD2GF, i0,i1,i2+1)];
       const double AD2_i0p1_i1_i2p1 = in_gfs[IDX4(AD2GF, i0+1,i1,i2+1)];
       const double AD2_i0p2_i1_i2p1 = in_gfs[IDX4(AD2GF, i0+2,i1,i2+1)];
       const double AD2_i0_i1p1_i2p1 = in_gfs[IDX4(AD2GF, i0,i1+1,i2+1)];
       const double AD2_i0_i1p2_i2p1 = in_gfs[IDX4(AD2GF, i0,i1+2,i2+1)];
       const double AD2_i0_i1m2_i2p2 = in_gfs[IDX4(AD2GF, i0,i1-2,i2+2)];
       const double AD2_i0_i1m1_i2p2 = in_gfs[IDX4(AD2GF, i0,i1-1,i2+2)];
       const double AD2_i0m2_i1_i2p2 = in_gfs[IDX4(AD2GF, i0-2,i1,i2+2)];
       const double AD2_i0m1_i1_i2p2 = in_gfs[IDX4(AD2GF, i0-1,i1,i2+2)];
       const double AD2_i0_i1_i2p2 = in_gfs[IDX4(AD2GF, i0,i1,i2+2)];
       const double AD2_i0p1_i1_i2p2 = in_gfs[IDX4(AD2GF, i0+1,i1,i2+2)];
       const double AD2_i0p2_i1_i2p2 = in_gfs[IDX4(AD2GF, i0+2,i1,i2+2)];
       const double AD2_i0_i1p1_i2p2 = in_gfs[IDX4(AD2GF, i0,i1+1,i2+2)];
       const double AD2_i0_i1p2_i2p2 = in_gfs[IDX4(AD2GF, i0,i1+2,i2+2)];
       const double FDPart1_Rational_2_3 = 2.0/3.0;
       const double FDPart1_Rational_1_12 = 1.0/12.0;
       const double FDPart1_Rational_4_9 = 4.0/9.0;
       const double FDPart1_Rational_1_18 = 1.0/18.0;
       const double FDPart1_Rational_1_144 = 1.0/144.0;
       const double FDPart1_Rational_5_2 = 5.0/2.0;
       const double FDPart1_Rational_4_3 = 4.0/3.0;
       const double FDPart1_1 = -AD0_i0_i1_i2p2;
       const double FDPart1_9 = -AD0*FDPart1_Rational_5_2;
       const double FDPart1_12 = -AD1*FDPart1_Rational_5_2;
       const double FDPart1_14 = -AD2*FDPart1_Rational_5_2;
       const double AD_dD00 = invdx0*(FDPart1_Rational_1_12*(AD0_i0m2_i1_i2 - AD0_i0p2_i1_i2) + FDPart1_Rational_2_3*(-AD0_i0m1_i1_i2 + AD0_i0p1_i1_i2));
       const double AD_dD01 = invdx1*(FDPart1_Rational_1_12*(AD0_i0_i1m2_i2 - AD0_i0_i1p2_i2) + FDPart1_Rational_2_3*(-AD0_i0_i1m1_i2 + AD0_i0_i1p1_i2));
       const double AD_dD02 = invdx2*(FDPart1_Rational_1_12*(AD0_i0_i1_i2m2 + FDPart1_1) + FDPart1_Rational_2_3*(-AD0_i0_i1_i2m1 + AD0_i0_i1_i2p1));
       const double AD_dD10 = invdx0*(FDPart1_Rational_1_12*(AD1_i0m2_i1_i2 - AD1_i0p2_i1_i2) + FDPart1_Rational_2_3*(-AD1_i0m1_i1_i2 + AD1_i0p1_i1_i2));
       const double AD_dD11 = invdx1*(FDPart1_Rational_1_12*(AD1_i0_i1m2_i2 - AD1_i0_i1p2_i2) + FDPart1_Rational_2_3*(-AD1_i0_i1m1_i2 + AD1_i0_i1p1_i2));
       const double AD_dD12 = invdx2*(FDPart1_Rational_1_12*(AD1_i0_i1_i2m2 - AD1_i0_i1_i2p2) + FDPart1_Rational_2_3*(-AD1_i0_i1_i2m1 + AD1_i0_i1_i2p1));
       const double AD_dD20 = invdx0*(FDPart1_Rational_1_12*(AD2_i0m2_i1_i2 - AD2_i0p2_i1_i2) + FDPart1_Rational_2_3*(-AD2_i0m1_i1_i2 + AD2_i0p1_i1_i2));
       const double AD_dD21 = invdx1*(FDPart1_Rational_1_12*(AD2_i0_i1m2_i2 - AD2_i0_i1p2_i2) + FDPart1_Rational_2_3*(-AD2_i0_i1m1_i2 + AD2_i0_i1p1_i2));
       const double AD_dD22 = invdx2*(FDPart1_Rational_1_12*(AD2_i0_i1_i2m2 - AD2_i0_i1_i2p2) + FDPart1_Rational_2_3*(-AD2_i0_i1_i2m1 + AD2_i0_i1_i2p1));
       const double AD_dDD001 = invdx0*invdx1*(FDPart1_Rational_1_144*(AD0_i0m2_i1m2_i2 - AD0_i0m2_i1p2_i2 - AD0_i0p2_i1m2_i2 + AD0_i0p2_i1p2_i2) + FDPart1_Rational_1_18*(-AD0_i0m1_i1m2_i2 + AD0_i0m1_i1p2_i2 - AD0_i0m2_i1m1_i2 + AD0_i0m2_i1p1_i2 + AD0_i0p1_i1m2_i2 - AD0_i0p1_i1p2_i2 + AD0_i0p2_i1m1_i2 - AD0_i0p2_i1p1_i2) + FDPart1_Rational_4_9*(AD0_i0m1_i1m1_i2 - AD0_i0m1_i1p1_i2 - AD0_i0p1_i1m1_i2 + AD0_i0p1_i1p1_i2));
       const double AD_dDD002 = invdx0*invdx2*(FDPart1_Rational_1_144*(AD0_i0m2_i1_i2m2 - AD0_i0m2_i1_i2p2 - AD0_i0p2_i1_i2m2 + AD0_i0p2_i1_i2p2) + FDPart1_Rational_1_18*(-AD0_i0m1_i1_i2m2 + AD0_i0m1_i1_i2p2 - AD0_i0m2_i1_i2m1 + AD0_i0m2_i1_i2p1 + AD0_i0p1_i1_i2m2 - AD0_i0p1_i1_i2p2 + AD0_i0p2_i1_i2m1 - AD0_i0p2_i1_i2p1) + FDPart1_Rational_4_9*(AD0_i0m1_i1_i2m1 - AD0_i0m1_i1_i2p1 - AD0_i0p1_i1_i2m1 + AD0_i0p1_i1_i2p1));
       const double AD_dDD011 = ((invdx1)*(invdx1))*(FDPart1_9 + FDPart1_Rational_1_12*(-AD0_i0_i1m2_i2 - AD0_i0_i1p2_i2) + FDPart1_Rational_4_3*(AD0_i0_i1m1_i2 + AD0_i0_i1p1_i2));
       const double AD_dDD022 = ((invdx2)*(invdx2))*(FDPart1_9 + FDPart1_Rational_1_12*(-AD0_i0_i1_i2m2 + FDPart1_1) + FDPart1_Rational_4_3*(AD0_i0_i1_i2m1 + AD0_i0_i1_i2p1));
       const double AD_dDD100 = ((invdx0)*(invdx0))*(FDPart1_12 + FDPart1_Rational_1_12*(-AD1_i0m2_i1_i2 - AD1_i0p2_i1_i2) + FDPart1_Rational_4_3*(AD1_i0m1_i1_i2 + AD1_i0p1_i1_i2));
       const double AD_dDD101 = invdx0*invdx1*(FDPart1_Rational_1_144*(AD1_i0m2_i1m2_i2 - AD1_i0m2_i1p2_i2 - AD1_i0p2_i1m2_i2 + AD1_i0p2_i1p2_i2) + FDPart1_Rational_1_18*(-AD1_i0m1_i1m2_i2 + AD1_i0m1_i1p2_i2 - AD1_i0m2_i1m1_i2 + AD1_i0m2_i1p1_i2 + AD1_i0p1_i1m2_i2 - AD1_i0p1_i1p2_i2 + AD1_i0p2_i1m1_i2 - AD1_i0p2_i1p1_i2) + FDPart1_Rational_4_9*(AD1_i0m1_i1m1_i2 - AD1_i0m1_i1p1_i2 - AD1_i0p1_i1m1_i2 + AD1_i0p1_i1p1_i2));
       const double AD_dDD112 = invdx1*invdx2*(FDPart1_Rational_1_144*(AD1_i0_i1m2_i2m2 - AD1_i0_i1m2_i2p2 - AD1_i0_i1p2_i2m2 + AD1_i0_i1p2_i2p2) + FDPart1_Rational_1_18*(-AD1_i0_i1m1_i2m2 + AD1_i0_i1m1_i2p2 - AD1_i0_i1m2_i2m1 + AD1_i0_i1m2_i2p1 + AD1_i0_i1p1_i2m2 - AD1_i0_i1p1_i2p2 + AD1_i0_i1p2_i2m1 - AD1_i0_i1p2_i2p1) + FDPart1_Rational_4_9*(AD1_i0_i1m1_i2m1 - AD1_i0_i1m1_i2p1 - AD1_i0_i1p1_i2m1 + AD1_i0_i1p1_i2p1));
       const double AD_dDD122 = ((invdx2)*(invdx2))*(FDPart1_12 + FDPart1_Rational_1_12*(-AD1_i0_i1_i2m2 - AD1_i0_i1_i2p2) + FDPart1_Rational_4_3*(AD1_i0_i1_i2m1 + AD1_i0_i1_i2p1));
       const double AD_dDD200 = ((invdx0)*(invdx0))*(FDPart1_14 + FDPart1_Rational_1_12*(-AD2_i0m2_i1_i2 - AD2_i0p2_i1_i2) + FDPart1_Rational_4_3*(AD2_i0m1_i1_i2 + AD2_i0p1_i1_i2));
       const double AD_dDD202 = invdx0*invdx2*(FDPart1_Rational_1_144*(AD2_i0m2_i1_i2m2 - AD2_i0m2_i1_i2p2 - AD2_i0p2_i1_i2m2 + AD2_i0p2_i1_i2p2) + FDPart1_Rational_1_18*(-AD2_i0m1_i1_i2m2 + AD2_i0m1_i1_i2p2 - AD2_i0m2_i1_i2m1 + AD2_i0m2_i1_i2p1 + AD2_i0p1_i1_i2m2 - AD2_i0p1_i1_i2p2 + AD2_i0p2_i1_i2m1 - AD2_i0p2_i1_i2p1) + FDPart1_Rational_4_9*(AD2_i0m1_i1_i2m1 - AD2_i0m1_i1_i2p1 - AD2_i0p1_i1_i2m1 + AD2_i0p1_i1_i2p1));
       const double AD_dDD211 = ((invdx1)*(invdx1))*(FDPart1_14 + FDPart1_Rational_1_12*(-AD2_i0_i1m2_i2 - AD2_i0_i1p2_i2) + FDPart1_Rational_4_3*(AD2_i0_i1m1_i2 + AD2_i0_i1p1_i2));
       const double AD_dDD212 = invdx1*invdx2*(FDPart1_Rational_1_144*(AD2_i0_i1m2_i2m2 - AD2_i0_i1m2_i2p2 - AD2_i0_i1p2_i2m2 + AD2_i0_i1p2_i2p2) + FDPart1_Rational_1_18*(-AD2_i0_i1m1_i2m2 + AD2_i0_i1m1_i2p2 - AD2_i0_i1m2_i2m1 + AD2_i0_i1m2_i2p1 + AD2_i0_i1p1_i2m2 - AD2_i0_i1p1_i2p2 + AD2_i0_i1p2_i2m1 - AD2_i0_i1p2_i2p1) + FDPart1_Rational_4_9*(AD2_i0_i1m1_i2m1 - AD2_i0_i1m1_i2p1 - AD2_i0_i1p1_i2m1 + AD2_i0_i1p1_i2p1));
       const double psi_dD0 = invdx0*(FDPart1_Rational_1_12*(psi_i0m2_i1_i2 - psi_i0p2_i1_i2) + FDPart1_Rational_2_3*(-psi_i0m1_i1_i2 + psi_i0p1_i1_i2));
       const double psi_dD1 = invdx1*(FDPart1_Rational_1_12*(psi_i0_i1m2_i2 - psi_i0_i1p2_i2) + FDPart1_Rational_2_3*(-psi_i0_i1m1_i2 + psi_i0_i1p1_i2));
       const double psi_dD2 = invdx2*(FDPart1_Rational_1_12*(psi_i0_i1_i2m2 - psi_i0_i1_i2p2) + FDPart1_Rational_2_3*(-psi_i0_i1_i2m1 + psi_i0_i1_i2p1));
       /*
        * NRPy+ Finite Difference Code Generation, Step 2 of 2: Evaluate SymPy expressions and write to main memory:
        */
       /*
        *  Original SymPy expressions:
        *  "[rhs_gfs[IDX4(AD0GF, i0, i1, i2)] = -ED0 - psi_dD0,
        *    rhs_gfs[IDX4(ED0GF, i0, i1, i2)] = (AD0 + AD_dD00*xx0 + AD_dDD101 - 2*(AD0*xx0 + AD_dD11)/xx0)/xx0**2 - (AD_dD00*xx0 - AD_dD11/xx0 + AD_dDD011 - (AD0*xx0 + AD_dD11)/xx0)/xx0**2 + (AD0*sin(xx1)**2 + AD_dD00*xx0*sin(xx1)**2 + AD_dD10*sin(2*xx1)/2 + AD_dDD202 - 2*(AD0*xx0*sin(xx1)**2 + AD1*sin(2*xx1)/2 + AD_dD22)/xx0)/(xx0**2*sin(xx1)**2) - (AD_dD00*xx0*sin(xx1)**2 - AD_dD22/xx0 + AD_dDD022 + (-AD1/xx0 + AD_dD01)*sin(2*xx1)/2 - (AD0*xx0*sin(xx1)**2 + AD1*sin(2*xx1)/2 + AD_dD22)/xx0)/(xx0**2*sin(xx1)**2),
        *    rhs_gfs[IDX4(AD1GF, i0, i1, i2)] = -ED1 - psi_dD1,
        *    rhs_gfs[IDX4(ED1GF, i0, i1, i2)] = -AD1/xx0**2 + AD_dD10/xx0 + AD_dDD001 - AD_dDD100 - (-AD1/xx0 + AD_dD01)/xx0 - (-AD_dD22*sin(2*xx1)/(2*sin(xx1)**2) + AD_dDD122 + xx0*(-AD1/xx0 + AD_dD10)*sin(xx1)**2 + (AD0*xx0 + AD_dD11)*sin(2*xx1)/2 - (AD0*xx0*sin(xx1)**2 + AD1*sin(2*xx1)/2 + AD_dD22)*sin(2*xx1)/(2*sin(xx1)**2))/(xx0**2*sin(xx1)**2) + (2*AD0*xx0*sin(xx1)*cos(xx1) + AD1*cos(2*xx1) + AD_dD01*xx0*sin(xx1)**2 + AD_dD11*sin(2*xx1)/2 + AD_dDD212 - (AD0*xx0*sin(xx1)**2 + AD1*sin(2*xx1)/2 + AD_dD22)*sin(2*xx1)/sin(xx1)**2)/(xx0**2*sin(xx1)**2),
        *    rhs_gfs[IDX4(AD2GF, i0, i1, i2)] = -ED2 - psi_dD2,
        *    rhs_gfs[IDX4(ED2GF, i0, i1, i2)] = -AD2/xx0**2 + AD_dD20/xx0 + AD_dDD002 - AD_dDD200 - (-AD2/xx0 + AD_dD02)/xx0 + (AD_dD02*xx0 + AD_dDD112 - (-AD2*sin(2*xx1)/(2*sin(xx1)**2) + AD_dD12)*sin(2*xx1)/(2*sin(xx1)**2) - (-AD2*sin(2*xx1)/(2*sin(xx1)**2) + AD_dD21)*sin(2*xx1)/(2*sin(xx1)**2))/xx0**2 - (AD2*(-cos(2*xx1)/sin(xx1)**2 + sin(2*xx1)*cos(xx1)/sin(xx1)**3) - AD_dD21*sin(2*xx1)/(2*sin(xx1)**2) + AD_dDD211 + xx0*(-AD2/xx0 + AD_dD20) - (-AD2*sin(2*xx1)/(2*sin(xx1)**2) + AD_dD21)*sin(2*xx1)/(2*sin(xx1)**2))/xx0**2,
        *    rhs_gfs[IDX4(PSIGF, i0, i1, i2)] = -AD_dD00 - (AD0*xx0 + AD_dD11)/xx0**2 - (AD0*xx0*sin(xx1)**2 + AD1*sin(2*xx1)/2 + AD_dD22)/(xx0**2*sin(xx1)**2)]"
        */
       const double FDPart3_0 = (1.0/((xx0)*(xx0)));
       const double FDPart3_1 = AD_dD00*xx0;
       const double FDPart3_2 = (1.0/(xx0));
       const double FDPart3_3 = AD0*xx0;
       const double FDPart3_4 = AD_dD11 + FDPart3_3;
       const double FDPart3_6 = sin(xx1);
       const double FDPart3_7 = ((FDPart3_6)*(FDPart3_6));
       const double FDPart3_9 = sin(2*xx1);
       const double FDPart3_10 = (1.0/2.0)*FDPart3_9;
       const double FDPart3_12 = AD1*FDPart3_10 + AD_dD22 + FDPart3_3*FDPart3_7;
       const double FDPart3_14 = (1.0/(FDPart3_7));
       const double FDPart3_15 = FDPart3_0*FDPart3_14;
       const double FDPart3_16 = -AD1*FDPart3_2;
       const double FDPart3_18 = cos(2*xx1);
       const double FDPart3_20 = cos(xx1);
       const double FDPart3_22 = FDPart3_10*FDPart3_14;
       const double FDPart3_23 = -AD2*FDPart3_2;
       const double FDPart3_24 = -AD2*FDPart3_22;
       const double FDPart3_25 = -FDPart3_22*(AD_dD21 + FDPart3_24);
       rhs_gfs[IDX4(AD0GF, i0, i1, i2)] = -ED0 - psi_dD0;
       rhs_gfs[IDX4(ED0GF, i0, i1, i2)] = FDPart3_0*(AD0 + AD_dDD101 + FDPart3_1 - 2*FDPart3_2*FDPart3_4) - FDPart3_0*(-AD_dD11*FDPart3_2 + AD_dDD011 + FDPart3_1 - FDPart3_2*FDPart3_4) + FDPart3_15*(AD0*FDPart3_7 + AD_dD10*FDPart3_10 + AD_dDD202 + FDPart3_1*FDPart3_7 - 2*FDPart3_12*FDPart3_2) - FDPart3_15*(-AD_dD22*FDPart3_2 + AD_dDD022 + FDPart3_1*FDPart3_7 + FDPart3_10*(AD_dD01 + FDPart3_16) - FDPart3_12*FDPart3_2);
       rhs_gfs[IDX4(AD1GF, i0, i1, i2)] = -ED1 - psi_dD1;
       rhs_gfs[IDX4(ED1GF, i0, i1, i2)] = -AD1*FDPart3_0 + AD_dD10*FDPart3_2 + AD_dDD001 - AD_dDD100 - FDPart3_15*(-AD_dD22*FDPart3_22 + AD_dDD122 - FDPart3_10*FDPart3_12*FDPart3_14 + FDPart3_10*FDPart3_4 + FDPart3_7*xx0*(AD_dD10 + FDPart3_16)) + FDPart3_15*(AD1*FDPart3_18 + AD_dD01*FDPart3_7*xx0 + AD_dD11*FDPart3_10 + AD_dDD212 - FDPart3_12*FDPart3_14*FDPart3_9 + 2*FDPart3_20*FDPart3_3*FDPart3_6) - FDPart3_2*(AD_dD01 + FDPart3_16);
       rhs_gfs[IDX4(AD2GF, i0, i1, i2)] = -ED2 - psi_dD2;
       rhs_gfs[IDX4(ED2GF, i0, i1, i2)] = -AD2*FDPart3_0 + AD_dD20*FDPart3_2 + AD_dDD002 - AD_dDD200 + FDPart3_0*(AD_dD02*xx0 + AD_dDD112 - FDPart3_22*(AD_dD12 + FDPart3_24) + FDPart3_25) - FDPart3_0*(AD2*(-FDPart3_14*FDPart3_18 + FDPart3_20*FDPart3_9/((FDPart3_6)*(FDPart3_6)*(FDPart3_6))) - AD_dD21*FDPart3_22 + AD_dDD211 + FDPart3_25 + xx0*(AD_dD20 + FDPart3_23)) - FDPart3_2*(AD_dD02 + FDPart3_23);
       rhs_gfs[IDX4(PSIGF, i0, i1, i2)] = -AD_dD00 - FDPart3_0*FDPart3_4 - FDPart3_12*FDPart3_15;
    }

# Step 2: System II \[Back to [top](#toc)\]
$$\label{sys2}$$

Define the auxiliary variable
$$\Gamma \equiv \hat{D}_{i} A^{i} \; .$$
Substituting this into Maxwell's equations yields the system
\begin{align}
\partial_{t} A_{i} &= -E_{i} - \hat{D}_{i} \psi \; , \\
\partial_{t} E_{i} &= -\hat{D}_{j} \hat{D}^{j} A_{i} + \hat{D}_{i} \Gamma \; , \\
\partial_{t} \psi &= -\Gamma \; , \\
\partial_{t} \Gamma &= -\hat{D}_{i} \hat{D}^{i} \psi \; .
\end{align}

It can be shown that the Gauss constraint now satisfies the wave equation
$$\partial_{t}^{2} \mathcal{C} = \hat{D}_{i} \hat{D}^{i} \mathcal{C} \; .$$
Thus, any constraint violation introduced by numerical error propagates away at the speed of light. This property increases the stability of of the simulation, compared to System I above. A similar trick is used in the [BSSN formulation](Tutorial-BSSNCurvilinear.ipynb) of Einstein's equations.

```python
# We inherit here all of the definitions from System I, above

# Step 7a: Register the scalar auxiliary variable \Gamma
Gamma = gri.register_gridfunctions("EVOL", ["Gamma"])

# Step 7b: Declare the ordinary gradient \partial_{i} \Gamma
Gamma_dD = ixp.declarerank1("Gamma_dD")

# Step 8a: Construct the second covariant derivative of the scalar \psi
# \psi_{;\hat{i}\hat{j}} = \psi_{,i;\hat{j}}
#                        = \psi_{,ij} - \Gamma^{k}_{ij} \psi_{,k}
psi_dDD = ixp.declarerank2("psi_dDD", "sym01")
psi_dHatDD = ixp.zerorank2()
for i in range(DIM):
    for j in range(DIM):
        psi_dHatDD[i][j] = psi_dDD[i][j]
        for k in range(DIM):
            psi_dHatDD[i][j] += - rfm.GammahatUDD[k][i][j] * psi_dD[k]

# Step 8b: Construct the covariant Laplacian of \psi
# Lappsi = ghat^{ij} D_{j} D_{i} \psi
Lappsi = 0
for i in range(DIM):
    for j in range(DIM):
        Lappsi += rfm.ghatUU[i][j] * psi_dHatDD[i][j]

# Step 9: Define right-hand sides for the evolution.
AD_rhs = ixp.zerorank1()
ED_rhs = ixp.zerorank1()
for i in range(DIM):
    AD_rhs[i] = -ED[i] - psi_dD[i]
    ED_rhs[i] = -LapAD[i] + Gamma_dD[i]
psi_rhs = -Gamma
Gamma_rhs = -Lappsi

# Step 10: Generate C code for System II Maxwell's evolution equations,
#          print output to the screen (standard out, or stdout).
lhrh_list = []
for i in range(DIM):
    lhrh_list.append(lhrh(lhs=gri.gfaccess("rhs_gfs", "AD" + str(i)), rhs=AD_rhs[i]))
    lhrh_list.append(lhrh(lhs=gri.gfaccess("rhs_gfs", "ED" + str(i)), rhs=ED_rhs[i]))
lhrh_list.append(lhrh(lhs=gri.gfaccess("rhs_gfs", "psi"), rhs=psi_rhs))
lhrh_list.append(lhrh(lhs=gri.gfaccess("rhs_gfs", "Gamma"), rhs=Gamma_rhs))

fin.FD_outputC("stdout", lhrh_list)
```

    {
       /*
        * NRPy+ Finite Difference Code Generation, Step 1 of 2: Read from main memory and compute finite difference stencils:
        */
       /*
        *  Original SymPy expressions:
        *  "[const double AD_dD00 = invdx0*(-2*AD0_i0m1_i1_i2/3 + AD0_i0m2_i1_i2/12 + 2*AD0_i0p1_i1_i2/3 - AD0_i0p2_i1_i2/12),
        *    const double AD_dD01 = invdx1*(-2*AD0_i0_i1m1_i2/3 + AD0_i0_i1m2_i2/12 + 2*AD0_i0_i1p1_i2/3 - AD0_i0_i1p2_i2/12),
        *    const double AD_dD02 = invdx2*(-2*AD0_i0_i1_i2m1/3 + AD0_i0_i1_i2m2/12 + 2*AD0_i0_i1_i2p1/3 - AD0_i0_i1_i2p2/12),
        *    const double AD_dD10 = invdx0*(-2*AD1_i0m1_i1_i2/3 + AD1_i0m2_i1_i2/12 + 2*AD1_i0p1_i1_i2/3 - AD1_i0p2_i1_i2/12),
        *    const double AD_dD11 = invdx1*(-2*AD1_i0_i1m1_i2/3 + AD1_i0_i1m2_i2/12 + 2*AD1_i0_i1p1_i2/3 - AD1_i0_i1p2_i2/12),
        *    const double AD_dD12 = invdx2*(-2*AD1_i0_i1_i2m1/3 + AD1_i0_i1_i2m2/12 + 2*AD1_i0_i1_i2p1/3 - AD1_i0_i1_i2p2/12),
        *    const double AD_dD20 = invdx0*(-2*AD2_i0m1_i1_i2/3 + AD2_i0m2_i1_i2/12 + 2*AD2_i0p1_i1_i2/3 - AD2_i0p2_i1_i2/12),
        *    const double AD_dD21 = invdx1*(-2*AD2_i0_i1m1_i2/3 + AD2_i0_i1m2_i2/12 + 2*AD2_i0_i1p1_i2/3 - AD2_i0_i1p2_i2/12),
        *    const double AD_dD22 = invdx2*(-2*AD2_i0_i1_i2m1/3 + AD2_i0_i1_i2m2/12 + 2*AD2_i0_i1_i2p1/3 - AD2_i0_i1_i2p2/12),
        *    const double AD_dDD000 = invdx0**2*(-5*AD0/2 + 4*AD0_i0m1_i1_i2/3 - AD0_i0m2_i1_i2/12 + 4*AD0_i0p1_i1_i2/3 - AD0_i0p2_i1_i2/12),
        *    const double AD_dDD011 = invdx1**2*(-5*AD0/2 + 4*AD0_i0_i1m1_i2/3 - AD0_i0_i1m2_i2/12 + 4*AD0_i0_i1p1_i2/3 - AD0_i0_i1p2_i2/12),
        *    const double AD_dDD022 = invdx2**2*(-5*AD0/2 + 4*AD0_i0_i1_i2m1/3 - AD0_i0_i1_i2m2/12 + 4*AD0_i0_i1_i2p1/3 - AD0_i0_i1_i2p2/12),
        *    const double AD_dDD100 = invdx0**2*(-5*AD1/2 + 4*AD1_i0m1_i1_i2/3 - AD1_i0m2_i1_i2/12 + 4*AD1_i0p1_i1_i2/3 - AD1_i0p2_i1_i2/12),
        *    const double AD_dDD111 = invdx1**2*(-5*AD1/2 + 4*AD1_i0_i1m1_i2/3 - AD1_i0_i1m2_i2/12 + 4*AD1_i0_i1p1_i2/3 - AD1_i0_i1p2_i2/12),
        *    const double AD_dDD122 = invdx2**2*(-5*AD1/2 + 4*AD1_i0_i1_i2m1/3 - AD1_i0_i1_i2m2/12 + 4*AD1_i0_i1_i2p1/3 - AD1_i0_i1_i2p2/12),
        *    const double AD_dDD200 = invdx0**2*(-5*AD2/2 + 4*AD2_i0m1_i1_i2/3 - AD2_i0m2_i1_i2/12 + 4*AD2_i0p1_i1_i2/3 - AD2_i0p2_i1_i2/12),
        *    const double AD_dDD211 = invdx1**2*(-5*AD2/2 + 4*AD2_i0_i1m1_i2/3 - AD2_i0_i1m2_i2/12 + 4*AD2_i0_i1p1_i2/3 - AD2_i0_i1p2_i2/12),
        *    const double AD_dDD222 = invdx2**2*(-5*AD2/2 + 4*AD2_i0_i1_i2m1/3 - AD2_i0_i1_i2m2/12 + 4*AD2_i0_i1_i2p1/3 - AD2_i0_i1_i2p2/12),
        *    const double Gamma_dD0 = invdx0*(-2*Gamma_i0m1_i1_i2/3 + Gamma_i0m2_i1_i2/12 + 2*Gamma_i0p1_i1_i2/3 - Gamma_i0p2_i1_i2/12),
        *    const double Gamma_dD1 = invdx1*(-2*Gamma_i0_i1m1_i2/3 + Gamma_i0_i1m2_i2/12 + 2*Gamma_i0_i1p1_i2/3 - Gamma_i0_i1p2_i2/12),
        *    const double Gamma_dD2 = invdx2*(-2*Gamma_i0_i1_i2m1/3 + Gamma_i0_i1_i2m2/12 + 2*Gamma_i0_i1_i2p1/3 - Gamma_i0_i1_i2p2/12),
        *    const double psi_dD0 = invdx0*(-2*psi_i0m1_i1_i2/3 + psi_i0m2_i1_i2/12 + 2*psi_i0p1_i1_i2/3 - psi_i0p2_i1_i2/12),
        *    const double psi_dD1 = invdx1*(-2*psi_i0_i1m1_i2/3 + psi_i0_i1m2_i2/12 + 2*psi_i0_i1p1_i2/3 - psi_i0_i1p2_i2/12),
        *    const double psi_dD2 = invdx2*(-2*psi_i0_i1_i2m1/3 + psi_i0_i1_i2m2/12 + 2*psi_i0_i1_i2p1/3 - psi_i0_i1_i2p2/12),
        *    const double psi_dDD00 = invdx0**2*(-5*psi/2 + 4*psi_i0m1_i1_i2/3 - psi_i0m2_i1_i2/12 + 4*psi_i0p1_i1_i2/3 - psi_i0p2_i1_i2/12),
        *    const double psi_dDD11 = invdx1**2*(-5*psi/2 + 4*psi_i0_i1m1_i2/3 - psi_i0_i1m2_i2/12 + 4*psi_i0_i1p1_i2/3 - psi_i0_i1p2_i2/12),
        *    const double psi_dDD22 = invdx2**2*(-5*psi/2 + 4*psi_i0_i1_i2m1/3 - psi_i0_i1_i2m2/12 + 4*psi_i0_i1_i2p1/3 - psi_i0_i1_i2p2/12)]"
        */
       const double psi_i0_i1_i2m2 = in_gfs[IDX4(PSIGF, i0,i1,i2-2)];
       const double psi_i0_i1_i2m1 = in_gfs[IDX4(PSIGF, i0,i1,i2-1)];
       const double psi_i0_i1m2_i2 = in_gfs[IDX4(PSIGF, i0,i1-2,i2)];
       const double psi_i0_i1m1_i2 = in_gfs[IDX4(PSIGF, i0,i1-1,i2)];
       const double psi_i0m2_i1_i2 = in_gfs[IDX4(PSIGF, i0-2,i1,i2)];
       const double psi_i0m1_i1_i2 = in_gfs[IDX4(PSIGF, i0-1,i1,i2)];
       const double psi = in_gfs[IDX4(PSIGF, i0,i1,i2)];
       const double psi_i0p1_i1_i2 = in_gfs[IDX4(PSIGF, i0+1,i1,i2)];
       const double psi_i0p2_i1_i2 = in_gfs[IDX4(PSIGF, i0+2,i1,i2)];
       const double psi_i0_i1p1_i2 = in_gfs[IDX4(PSIGF, i0,i1+1,i2)];
       const double psi_i0_i1p2_i2 = in_gfs[IDX4(PSIGF, i0,i1+2,i2)];
       const double psi_i0_i1_i2p1 = in_gfs[IDX4(PSIGF, i0,i1,i2+1)];
       const double psi_i0_i1_i2p2 = in_gfs[IDX4(PSIGF, i0,i1,i2+2)];
       const double ED0 = in_gfs[IDX4(ED0GF, i0,i1,i2)];
       const double ED1 = in_gfs[IDX4(ED1GF, i0,i1,i2)];
       const double ED2 = in_gfs[IDX4(ED2GF, i0,i1,i2)];
       const double AD0_i0_i1_i2m2 = in_gfs[IDX4(AD0GF, i0,i1,i2-2)];
       const double AD0_i0_i1_i2m1 = in_gfs[IDX4(AD0GF, i0,i1,i2-1)];
       const double AD0_i0_i1m2_i2 = in_gfs[IDX4(AD0GF, i0,i1-2,i2)];
       const double AD0_i0_i1m1_i2 = in_gfs[IDX4(AD0GF, i0,i1-1,i2)];
       const double AD0_i0m2_i1_i2 = in_gfs[IDX4(AD0GF, i0-2,i1,i2)];
       const double AD0_i0m1_i1_i2 = in_gfs[IDX4(AD0GF, i0-1,i1,i2)];
       const double AD0 = in_gfs[IDX4(AD0GF, i0,i1,i2)];
       const double AD0_i0p1_i1_i2 = in_gfs[IDX4(AD0GF, i0+1,i1,i2)];
       const double AD0_i0p2_i1_i2 = in_gfs[IDX4(AD0GF, i0+2,i1,i2)];
       const double AD0_i0_i1p1_i2 = in_gfs[IDX4(AD0GF, i0,i1+1,i2)];
       const double AD0_i0_i1p2_i2 = in_gfs[IDX4(AD0GF, i0,i1+2,i2)];
       const double AD0_i0_i1_i2p1 = in_gfs[IDX4(AD0GF, i0,i1,i2+1)];
       const double AD0_i0_i1_i2p2 = in_gfs[IDX4(AD0GF, i0,i1,i2+2)];
       const double AD1_i0_i1_i2m2 = in_gfs[IDX4(AD1GF, i0,i1,i2-2)];
       const double AD1_i0_i1_i2m1 = in_gfs[IDX4(AD1GF, i0,i1,i2-1)];
       const double AD1_i0_i1m2_i2 = in_gfs[IDX4(AD1GF, i0,i1-2,i2)];
       const double AD1_i0_i1m1_i2 = in_gfs[IDX4(AD1GF, i0,i1-1,i2)];
       const double AD1_i0m2_i1_i2 = in_gfs[IDX4(AD1GF, i0-2,i1,i2)];
       const double AD1_i0m1_i1_i2 = in_gfs[IDX4(AD1GF, i0-1,i1,i2)];
       const double AD1 = in_gfs[IDX4(AD1GF, i0,i1,i2)];
       const double AD1_i0p1_i1_i2 = in_gfs[IDX4(AD1GF, i0+1,i1,i2)];
       const double AD1_i0p2_i1_i2 = in_gfs[IDX4(AD1GF, i0+2,i1,i2)];
       const double AD1_i0_i1p1_i2 = in_gfs[IDX4(AD1GF, i0,i1+1,i2)];
       const double AD1_i0_i1p2_i2 = in_gfs[IDX4(AD1GF, i0,i1+2,i2)];
       const double AD1_i0_i1_i2p1 = in_gfs[IDX4(AD1GF, i0,i1,i2+1)];
       const double AD1_i0_i1_i2p2 = in_gfs[IDX4(AD1GF, i0,i1,i2+2)];
       const double AD2_i0_i1_i2m2 = in_gfs[IDX4(AD2GF, i0,i1,i2-2)];
       const double AD2_i0_i1_i2m1 = in_gfs[IDX4(AD2GF, i0,i1,i2-1)];
       const double AD2_i0_i1m2_i2 = in_gfs[IDX4(AD2GF, i0,i1-2,i2)];
       const double AD2_i0_i1m1_i2 = in_gfs[IDX4(AD2GF, i0,i1-1,i2)];
       const double AD2_i0m2_i1_i2 = in_gfs[IDX4(AD2GF, i0-2,i1,i2)];
       const double AD2_i0m1_i1_i2 = in_gfs[IDX4(AD2GF, i0-1,i1,i2)];
       const double AD2 = in_gfs[IDX4(AD2GF, i0,i1,i2)];
       const double AD2_i0p1_i1_i2 = in_gfs[IDX4(AD2GF, i0+1,i1,i2)];
       const double AD2_i0p2_i1_i2 = in_gfs[IDX4(AD2GF, i0+2,i1,i2)];
       const double AD2_i0_i1p1_i2 = in_gfs[IDX4(AD2GF, i0,i1+1,i2)];
       const double AD2_i0_i1p2_i2 = in_gfs[IDX4(AD2GF, i0,i1+2,i2)];
       const double AD2_i0_i1_i2p1 = in_gfs[IDX4(AD2GF, i0,i1,i2+1)];
       const double AD2_i0_i1_i2p2 = in_gfs[IDX4(AD2GF, i0,i1,i2+2)];
       const double Gamma_i0_i1_i2m2 = in_gfs[IDX4(GAMMAGF, i0,i1,i2-2)];
       const double Gamma_i0_i1_i2m1 = in_gfs[IDX4(GAMMAGF, i0,i1,i2-1)];
       const double Gamma_i0_i1m2_i2 = in_gfs[IDX4(GAMMAGF, i0,i1-2,i2)];
       const double Gamma_i0_i1m1_i2 = in_gfs[IDX4(GAMMAGF, i0,i1-1,i2)];
       const double Gamma_i0m2_i1_i2 = in_gfs[IDX4(GAMMAGF, i0-2,i1,i2)];
       const double Gamma_i0m1_i1_i2 = in_gfs[IDX4(GAMMAGF, i0-1,i1,i2)];
       const double Gamma = in_gfs[IDX4(GAMMAGF, i0,i1,i2)];
       const double Gamma_i0p1_i1_i2 = in_gfs[IDX4(GAMMAGF, i0+1,i1,i2)];
       const double Gamma_i0p2_i1_i2 = in_gfs[IDX4(GAMMAGF, i0+2,i1,i2)];
       const double Gamma_i0_i1p1_i2 = in_gfs[IDX4(GAMMAGF, i0,i1+1,i2)];
       const double Gamma_i0_i1p2_i2 = in_gfs[IDX4(GAMMAGF, i0,i1+2,i2)];
       const double Gamma_i0_i1_i2p1 = in_gfs[IDX4(GAMMAGF, i0,i1,i2+1)];
       const double Gamma_i0_i1_i2p2 = in_gfs[IDX4(GAMMAGF, i0,i1,i2+2)];
       const double FDPart1_Rational_2_3 = 2.0/3.0;
       const double FDPart1_Rational_1_12 = 1.0/12.0;
       const double FDPart1_Rational_5_2 = 5.0/2.0;
       const double FDPart1_Rational_4_3 = 4.0/3.0;
       const double FDPart1_1 = -AD0_i0_i1p2_i2;
       const double FDPart1_9 = ((invdx0)*(invdx0));
       const double FDPart1_10 = -AD0*FDPart1_Rational_5_2;
       const double FDPart1_11 = ((invdx1)*(invdx1));
       const double FDPart1_12 = ((invdx2)*(invdx2));
       const double FDPart1_13 = -AD1*FDPart1_Rational_5_2;
       const double FDPart1_14 = -AD2*FDPart1_Rational_5_2;
       const double FDPart1_18 = -FDPart1_Rational_5_2*psi;
       const double AD_dD00 = invdx0*(FDPart1_Rational_1_12*(AD0_i0m2_i1_i2 - AD0_i0p2_i1_i2) + FDPart1_Rational_2_3*(-AD0_i0m1_i1_i2 + AD0_i0p1_i1_i2));
       const double AD_dD01 = invdx1*(FDPart1_Rational_1_12*(AD0_i0_i1m2_i2 + FDPart1_1) + FDPart1_Rational_2_3*(-AD0_i0_i1m1_i2 + AD0_i0_i1p1_i2));
       const double AD_dD02 = invdx2*(FDPart1_Rational_1_12*(AD0_i0_i1_i2m2 - AD0_i0_i1_i2p2) + FDPart1_Rational_2_3*(-AD0_i0_i1_i2m1 + AD0_i0_i1_i2p1));
       const double AD_dD10 = invdx0*(FDPart1_Rational_1_12*(AD1_i0m2_i1_i2 - AD1_i0p2_i1_i2) + FDPart1_Rational_2_3*(-AD1_i0m1_i1_i2 + AD1_i0p1_i1_i2));
       const double AD_dD11 = invdx1*(FDPart1_Rational_1_12*(AD1_i0_i1m2_i2 - AD1_i0_i1p2_i2) + FDPart1_Rational_2_3*(-AD1_i0_i1m1_i2 + AD1_i0_i1p1_i2));
       const double AD_dD12 = invdx2*(FDPart1_Rational_1_12*(AD1_i0_i1_i2m2 - AD1_i0_i1_i2p2) + FDPart1_Rational_2_3*(-AD1_i0_i1_i2m1 + AD1_i0_i1_i2p1));
       const double AD_dD20 = invdx0*(FDPart1_Rational_1_12*(AD2_i0m2_i1_i2 - AD2_i0p2_i1_i2) + FDPart1_Rational_2_3*(-AD2_i0m1_i1_i2 + AD2_i0p1_i1_i2));
       const double AD_dD21 = invdx1*(FDPart1_Rational_1_12*(AD2_i0_i1m2_i2 - AD2_i0_i1p2_i2) + FDPart1_Rational_2_3*(-AD2_i0_i1m1_i2 + AD2_i0_i1p1_i2));
       const double AD_dD22 = invdx2*(FDPart1_Rational_1_12*(AD2_i0_i1_i2m2 - AD2_i0_i1_i2p2) + FDPart1_Rational_2_3*(-AD2_i0_i1_i2m1 + AD2_i0_i1_i2p1));
       const double AD_dDD000 = FDPart1_9*(FDPart1_10 + FDPart1_Rational_1_12*(-AD0_i0m2_i1_i2 - AD0_i0p2_i1_i2) + FDPart1_Rational_4_3*(AD0_i0m1_i1_i2 + AD0_i0p1_i1_i2));
       const double AD_dDD011 = FDPart1_11*(FDPart1_10 + FDPart1_Rational_1_12*(-AD0_i0_i1m2_i2 + FDPart1_1) + FDPart1_Rational_4_3*(AD0_i0_i1m1_i2 + AD0_i0_i1p1_i2));
       const double AD_dDD022 = FDPart1_12*(FDPart1_10 + FDPart1_Rational_1_12*(-AD0_i0_i1_i2m2 - AD0_i0_i1_i2p2) + FDPart1_Rational_4_3*(AD0_i0_i1_i2m1 + AD0_i0_i1_i2p1));
       const double AD_dDD100 = FDPart1_9*(FDPart1_13 + FDPart1_Rational_1_12*(-AD1_i0m2_i1_i2 - AD1_i0p2_i1_i2) + FDPart1_Rational_4_3*(AD1_i0m1_i1_i2 + AD1_i0p1_i1_i2));
       const double AD_dDD111 = FDPart1_11*(FDPart1_13 + FDPart1_Rational_1_12*(-AD1_i0_i1m2_i2 - AD1_i0_i1p2_i2) + FDPart1_Rational_4_3*(AD1_i0_i1m1_i2 + AD1_i0_i1p1_i2));
       const double AD_dDD122 = FDPart1_12*(FDPart1_13 + FDPart1_Rational_1_12*(-AD1_i0_i1_i2m2 - AD1_i0_i1_i2p2) + FDPart1_Rational_4_3*(AD1_i0_i1_i2m1 + AD1_i0_i1_i2p1));
       const double AD_dDD200 = FDPart1_9*(FDPart1_14 + FDPart1_Rational_1_12*(-AD2_i0m2_i1_i2 - AD2_i0p2_i1_i2) + FDPart1_Rational_4_3*(AD2_i0m1_i1_i2 + AD2_i0p1_i1_i2));
       const double AD_dDD211 = FDPart1_11*(FDPart1_14 + FDPart1_Rational_1_12*(-AD2_i0_i1m2_i2 - AD2_i0_i1p2_i2) + FDPart1_Rational_4_3*(AD2_i0_i1m1_i2 + AD2_i0_i1p1_i2));
       const double AD_dDD222 = FDPart1_12*(FDPart1_14 + FDPart1_Rational_1_12*(-AD2_i0_i1_i2m2 - AD2_i0_i1_i2p2) + FDPart1_Rational_4_3*(AD2_i0_i1_i2m1 + AD2_i0_i1_i2p1));
       const double Gamma_dD0 = invdx0*(FDPart1_Rational_1_12*(Gamma_i0m2_i1_i2 - Gamma_i0p2_i1_i2) + FDPart1_Rational_2_3*(-Gamma_i0m1_i1_i2 + Gamma_i0p1_i1_i2));
       const double Gamma_dD1 = invdx1*(FDPart1_Rational_1_12*(Gamma_i0_i1m2_i2 - Gamma_i0_i1p2_i2) + FDPart1_Rational_2_3*(-Gamma_i0_i1m1_i2 + Gamma_i0_i1p1_i2));
       const double Gamma_dD2 = invdx2*(FDPart1_Rational_1_12*(Gamma_i0_i1_i2m2 - Gamma_i0_i1_i2p2) + FDPart1_Rational_2_3*(-Gamma_i0_i1_i2m1 + Gamma_i0_i1_i2p1));
       const double psi_dD0 = invdx0*(FDPart1_Rational_1_12*(psi_i0m2_i1_i2 - psi_i0p2_i1_i2) + FDPart1_Rational_2_3*(-psi_i0m1_i1_i2 + psi_i0p1_i1_i2));
       const double psi_dD1 = invdx1*(FDPart1_Rational_1_12*(psi_i0_i1m2_i2 - psi_i0_i1p2_i2) + FDPart1_Rational_2_3*(-psi_i0_i1m1_i2 + psi_i0_i1p1_i2));
       const double psi_dD2 = invdx2*(FDPart1_Rational_1_12*(psi_i0_i1_i2m2 - psi_i0_i1_i2p2) + FDPart1_Rational_2_3*(-psi_i0_i1_i2m1 + psi_i0_i1_i2p1));
       const double psi_dDD00 = FDPart1_9*(FDPart1_18 + FDPart1_Rational_1_12*(-psi_i0m2_i1_i2 - psi_i0p2_i1_i2) + FDPart1_Rational_4_3*(psi_i0m1_i1_i2 + psi_i0p1_i1_i2));
       const double psi_dDD11 = FDPart1_11*(FDPart1_18 + FDPart1_Rational_1_12*(-psi_i0_i1m2_i2 - psi_i0_i1p2_i2) + FDPart1_Rational_4_3*(psi_i0_i1m1_i2 + psi_i0_i1p1_i2));
       const double psi_dDD22 = FDPart1_12*(FDPart1_18 + FDPart1_Rational_1_12*(-psi_i0_i1_i2m2 - psi_i0_i1_i2p2) + FDPart1_Rational_4_3*(psi_i0_i1_i2m1 + psi_i0_i1_i2p1));
       /*
        * NRPy+ Finite Difference Code Generation, Step 2 of 2: Evaluate SymPy expressions and write to main memory:
        */
       /*
        *  Original SymPy expressions:
        *  "[rhs_gfs[IDX4(AD0GF, i0, i1, i2)] = -ED0 - psi_dD0,
        *    rhs_gfs[IDX4(ED0GF, i0, i1, i2)] = -AD_dDD000 + Gamma_dD0 - (AD_dD00*xx0 - AD_dD11/xx0 + AD_dDD011 - (AD0*xx0 + AD_dD11)/xx0)/xx0**2 - (AD_dD00*xx0*sin(xx1)**2 - AD_dD22/xx0 + AD_dDD022 + (-AD1/xx0 + AD_dD01)*sin(2*xx1)/2 - (AD0*xx0*sin(xx1)**2 + AD1*sin(2*xx1)/2 + AD_dD22)/xx0)/(xx0**2*sin(xx1)**2),
        *    rhs_gfs[IDX4(AD1GF, i0, i1, i2)] = -ED1 - psi_dD1,
        *    rhs_gfs[IDX4(ED1GF, i0, i1, i2)] = -AD1/xx0**2 + AD_dD10/xx0 - AD_dDD100 + Gamma_dD1 + (-AD1/xx0 + AD_dD10)/xx0 - (AD_dD01*xx0 + AD_dDD111 + xx0*(-AD1/xx0 + AD_dD01) + xx0*(-AD1/xx0 + AD_dD10))/xx0**2 - (-AD_dD22*sin(2*xx1)/(2*sin(xx1)**2) + AD_dDD122 + xx0*(-AD1/xx0 + AD_dD10)*sin(xx1)**2 + (AD0*xx0 + AD_dD11)*sin(2*xx1)/2 - (AD0*xx0*sin(xx1)**2 + AD1*sin(2*xx1)/2 + AD_dD22)*sin(2*xx1)/(2*sin(xx1)**2))/(xx0**2*sin(xx1)**2),
        *    rhs_gfs[IDX4(AD2GF, i0, i1, i2)] = -ED2 - psi_dD2,
        *    rhs_gfs[IDX4(ED2GF, i0, i1, i2)] = -AD2/xx0**2 + AD_dD20/xx0 - AD_dDD200 + Gamma_dD2 + (-AD2/xx0 + AD_dD20)/xx0 - (AD2*(-cos(2*xx1)/sin(xx1)**2 + sin(2*xx1)*cos(xx1)/sin(xx1)**3) - AD_dD21*sin(2*xx1)/(2*sin(xx1)**2) + AD_dDD211 + xx0*(-AD2/xx0 + AD_dD20) - (-AD2*sin(2*xx1)/(2*sin(xx1)**2) + AD_dD21)*sin(2*xx1)/(2*sin(xx1)**2))/xx0**2 - (AD_dD02*xx0*sin(xx1)**2 + AD_dD12*sin(2*xx1)/2 + AD_dDD222 + xx0*(-AD2/xx0 + AD_dD02)*sin(xx1)**2 + xx0*(-AD2/xx0 + AD_dD20)*sin(xx1)**2 + (-AD2*sin(2*xx1)/(2*sin(xx1)**2) + AD_dD12)*sin(2*xx1)/2 + (-AD2*sin(2*xx1)/(2*sin(xx1)**2) + AD_dD21)*sin(2*xx1)/2)/(xx0**2*sin(xx1)**2),
        *    rhs_gfs[IDX4(PSIGF, i0, i1, i2)] = -Gamma,
        *    rhs_gfs[IDX4(GAMMAGF, i0, i1, i2)] = -psi_dDD00 - (psi_dD0*xx0 + psi_dDD11)/xx0**2 - (psi_dD0*xx0*sin(xx1)**2 + psi_dD1*sin(2*xx1)/2 + psi_dDD22)/(xx0**2*sin(xx1)**2)]"
        */
       const double FDPart3_0 = (1.0/((xx0)*(xx0)));
       const double FDPart3_2 = (1.0/(xx0));
       const double FDPart3_4 = AD0*xx0 + AD_dD11;
       const double FDPart3_5 = sin(xx1);
       const double FDPart3_6 = ((FDPart3_5)*(FDPart3_5));
       const double FDPart3_7 = -AD1*FDPart3_2;
       const double FDPart3_10 = sin(2*xx1);
       const double FDPart3_11 = (1.0/2.0)*FDPart3_10;
       const double FDPart3_12 = AD0*FDPart3_6*xx0 + AD1*FDPart3_11 + AD_dD22;
       const double FDPart3_13 = (1.0/(FDPart3_6));
       const double FDPart3_14 = FDPart3_0*FDPart3_13;
       const double FDPart3_16 = xx0*(AD_dD10 + FDPart3_7);
       const double FDPart3_17 = FDPart3_11*FDPart3_13;
       const double FDPart3_18 = -AD2*FDPart3_2;
       const double FDPart3_20 = xx0*(AD_dD20 + FDPart3_18);
       const double FDPart3_21 = -AD2*FDPart3_17;
       const double FDPart3_22 = FDPart3_11*(AD_dD21 + FDPart3_21);
       rhs_gfs[IDX4(AD0GF, i0, i1, i2)] = -ED0 - psi_dD0;
       rhs_gfs[IDX4(ED0GF, i0, i1, i2)] = -AD_dDD000 - FDPart3_0*(AD_dD00*xx0 - AD_dD11*FDPart3_2 + AD_dDD011 - FDPart3_2*FDPart3_4) - FDPart3_14*(AD_dD00*FDPart3_6*xx0 - AD_dD22*FDPart3_2 + AD_dDD022 + FDPart3_11*(AD_dD01 + FDPart3_7) - FDPart3_12*FDPart3_2) + Gamma_dD0;
       rhs_gfs[IDX4(AD1GF, i0, i1, i2)] = -ED1 - psi_dD1;
       rhs_gfs[IDX4(ED1GF, i0, i1, i2)] = -AD1*FDPart3_0 + AD_dD10*FDPart3_2 - AD_dDD100 - FDPart3_0*(AD_dD01*xx0 + AD_dDD111 + FDPart3_16 + xx0*(AD_dD01 + FDPart3_7)) - FDPart3_14*(-AD_dD22*FDPart3_17 + AD_dDD122 + FDPart3_11*FDPart3_4 - FDPart3_12*FDPart3_17 + FDPart3_16*FDPart3_6) + FDPart3_2*(AD_dD10 + FDPart3_7) + Gamma_dD1;
       rhs_gfs[IDX4(AD2GF, i0, i1, i2)] = -ED2 - psi_dD2;
       rhs_gfs[IDX4(ED2GF, i0, i1, i2)] = -AD2*FDPart3_0 + AD_dD20*FDPart3_2 - AD_dDD200 - FDPart3_0*(AD2*(FDPart3_10*cos(xx1)/((FDPart3_5)*(FDPart3_5)*(FDPart3_5)) - FDPart3_13*cos(2*xx1)) - AD_dD21*FDPart3_17 + AD_dDD211 - FDPart3_13*FDPart3_22 + FDPart3_20) - FDPart3_14*(AD_dD02*FDPart3_6*xx0 + AD_dD12*FDPart3_11 + AD_dDD222 + FDPart3_11*(AD_dD12 + FDPart3_21) + FDPart3_20*FDPart3_6 + FDPart3_22 + FDPart3_6*xx0*(AD_dD02 + FDPart3_18)) + FDPart3_2*(AD_dD20 + FDPart3_18) + Gamma_dD2;
       rhs_gfs[IDX4(PSIGF, i0, i1, i2)] = -Gamma;
       rhs_gfs[IDX4(GAMMAGF, i0, i1, i2)] = -FDPart3_0*(psi_dD0*xx0 + psi_dDD11) - FDPart3_14*(FDPart3_11*psi_dD1 + FDPart3_6*psi_dD0*xx0 + psi_dDD22) - psi_dDD00;
    }

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

```python
import cmdline_helper as cmd    # NRPy+: Multi-platform Python command-line interface
cmd.output_Jupyter_notebook_to_LaTeXed_PDF("Tutorial-MaxwellCurvilinear")
```

    Created Tutorial-MaxwellCurvilinear.tex, and compiled LaTeX file to PDF
        file Tutorial-MaxwellCurvilinear.pdf


# **MAC023 - Mecânica das Estruturas**
# ME-01 - Primeira Avaliação de Conhecimentos

**ATENÇÃO:** Não edite este arquivo!!! Faça uma cópia deste arquivo para o seu Drive. Para isso, no próprio colab, vá em **File -> Save a copy in Drive**

---

Alunos:

Brian Maia

Mathews Edwirds

# Condições Gerais

Esta avaliação tem como objetivo avaliar os conhecimentos adquiridos na primeira parte da disciplina de Mecânica das Estruturas.

---

As condicões abaixo devem ser observadas:

1. Serão formadas equipes e cada uma delas com no mínimo **2** e no máximo **3** integrantes.

2. A avaliação será realizada por meio da entrega de uma cópia deste notebook com as soluções desenvolvidas até a data estipulada de entrega.

3. Da entrega da avaliação.
  * Os documentos necessários para a entrega do trabalho são (1) os códigos  desenvolvidos pela equipe e (2) vídeo com a descrição da solução.
  * A equipe deve usar este modelo de notebook para desenvolver os códigos.
  * Os códigos podem ser desenvolvidos combinado a linguagem LaTeX e computação simbólica ou computação numérica quando necessário.
  * Os gráficos necessários para a apresentação da solução devem estar embutidos no notebook.

4. Da distribuição das questões.
  * A quantidade de questões será a mesma para cada grupo.
  * Serão atribuídas as mesmas questões para todos os grupos.
  * A pontuacão referente a cada questão será igualitária e o valor total da avaliação será 100 pontos.

5. As equipes devem ser formadas até às **23:59 horas o dia 10/12/2021** por meio do preenchimento da planilha [[MAC023] Formação das Equipes](https://docs.google.com/spreadsheets/d/1Dlftymao970nnrE4mu958iP8nMqKqSuhHiiLH91BKpQ/edit?usp=sharing).

6. A formação das equipes pode ser acompanhada arquivo indicado acima. Cada equipe será indentificada por uma letra em ordem alfabética seguida do número 1 (A1, B1, C1, e assim por diante). O arquivo está aberto para edição e pode ser alterado pelos alunos até a data estipulada.

7. Equipes formadas após a data estabelecida para a formação das equipes terão a nota da avaliação multiplicada por um coeficiente de **0.80**.

8. A equipe deve indicar no arquivo de indicação de equipes um responsável pela entrega do projeto.
  * Somente o responsável pela entrega deve fazer o upload do arquivo na plataforma

9. A entrega dos projetos deve ocorrer até às **23:59 do dia 21/12/2021** na plataforma da disciplina pelo responsável pela entrega.
  * Caso a entrega seja feita por outro integrante diferente daquele indicado pela pela equipe a avaliação será desconsiderada e não será corrigida até que a a condição de entrega seja satisfeita.

10. Quaisquer dúvidas ou esclarecimentos devem ser encaminhadas pela sala de aula virtual.

# Questão Q1
---
Considere a estrutura mostrada abaixo.

As barras são feitas com um material com módulo de elasticidade E e têm seções transversais com área A.

---

---

Recorde-se que as condições de compatibilidade entre deslocamentos e deformações são condições geométricas que devem ser satisfeitas para garantir que a estrutura, ao se deformar, permaneça contínua (sem vazios ou sobreposição de pontos) e compatível com seus vínculos externos.

## Implementação
---

Implemente um modelo considerando as condições básicas de análise estrutural e realize as seguintes entregas:

a. (10 pontos) Escreva as posições dos nós nas configurações indeformada e deformada.

b. (10 pontos) Determine as condições de compatibilidade para a estrutura na configuração deformada. Escreva as equações das deformações nas barras em função

* (a) dos deslocamentos nos nós livres para se deslocar e
* (b) as informações geométricas da estrutura.

Use uma notação vetorial para as condições de compatibilidade.

c. (20 pontos) Linearize as condições de compatibilidade em função dos deslocamentos. Reescreve-as usando a matriz jacobiana da forma vetorial das condições de compatibilidade. Neste caso, a transformação linear representada pela Jacobiana ${\bf J(p)}$ é a aproximação linear da função vetorial ${\bf f(u)}$ nas proximidades do ponto ${\bf p}$, e pode ser representada pela expressão $$ {\bf f(u)} - {\bf f(p)} = {\bf J(p)} {\bf (u-p)} $$
onde ${\bf u}$ é um ponto de interesse na vizinhança de ${\bf p}$.

d. (10 pontos) Responda à seguinte questão: Qual a hipótese envolvida no processo de linearização e por que a linearização é necessária?

e. (20 pontos) Escreva as condições de equilíbrio na configuração **indeformada**. Use uma notação vetorial para as equações de equilíbrio.

f. (10 pontos) Usando as relações constitutivas, reescreva as forças internas em função dos deslocamentos e reescreva as equações de equilíbrio em função dos deslocamentos.

g. (10 pontos) Resolva o sistema de equações de equilíbrio para os deslocamentos. Assuma valores unitários para as áreas das seções transversais (A). O módulo de elasticidade (E) tem valor igual 150000 N/m$^2$.

h. (10 pontos) Compare o resultado encontrado com o pacote anastruct.

---

#Alternativa A)
Escreva as posições dos nós nas configurações indeformada e deformada.

```
# Importa as bibliotecas gráficas, numéricas e de computação simbólica
import pylab as pl
import numpy as np
import sympy as sp

sp.init_printing(use_latex='mathjax')
a,b,l,P,u= sp.var('a b l P u', real=True, positive=True)
P=-40000
```

```
#--# Posição dos nós na configuração indeformada#--
conf_indeformada=sp.Matrix([[0,0], [a,0], [a,b], [2*a,b]]) # A, B, C, D

print("Configuração Indeformada")
conf_indeformada
```

    Configuração Indeformada

$\displaystyle \left[\begin{matrix}0 & 0\\a & 0\\a & b\\2 a & b\end{matrix}\right]$

```
#--# Posição dos nós na configuração deformada #--
desloc_xb, desloc_yb, desloc_xc, desloc_yc = sp.var('desloc_xb desloc_yb desloc_xc desloc_yc', real=True, positive=True)
matriz_deslocamentos = sp.Matrix([desloc_xb, desloc_yb, desloc_xc, desloc_yc])

# Matrizes de posições e deslocamentos para a configuração deformada
conf_deformada = conf_indeformada + sp.Matrix([
[0,0],     # A
[desloc_xb, -desloc_yb],     # B
[desloc_xc, -desloc_yc],     # C
[0,0],   # D
])

print("Matrizes de posições e deslocamentos para a configuração deformada")
conf_deformada, matriz_deslocamentos
```

    Matrizes de posições e deslocamentos para a configuração deformada

$\displaystyle \left( \left[\begin{matrix}0 & 0\\a + desloc_{xb} & - desloc_{yb}\\a + desloc_{xc} & b - desloc_{yc}\\2 a & b\end{matrix}\right], \  \left[\begin{matrix}desloc_{xb}\\desloc_{yb}\\desloc_{xc}\\desloc_{yc}\end{matrix}\right]\right)$

```
identifica_barra = [[0, 2], [0, 1], [2, 1], [2, 3], [1, 3]] #AC, AB, CB, CD, BD

print("Identificação da barra")
print("  AC,    AB,    CB,    CD,    BD")
identifica_barra
```

    Identificação da barra
      AC,    AB,    CB,    CD,    BD

$\displaystyle \left[ \left[ 0, \  2\right], \  \left[ 0, \  1\right], \  \left[ 2, \  1\right], \  \left[ 2, \  3\right], \  \left[ 1, \  3\right]\right]$

#Alternativa B)

Determine as condições de compatibilidade para a estrutura na configuração deformada. Escreva as equações das deformações nas barras em função

* (a) dos deslocamentos nos nós livres para se deslocar e

* (b) as informações geométricas da estrutura.

Use uma notação vetorial para as condições de compatibilidade.

```
epsilon = []
for pos, nos in enumerate(identifica_barra):
  # Auxiliares para salvar o valor dos nós barras
  primeiro_no_lista = nos[0]
  ultimo_no_lista = nos[1]
  # Cálculo das condições de compatibilidade
  comp_f = conf_deformada[ultimo_no_lista,:] - conf_deformada[primeiro_no_lista,:]
  comp_i = conf_indeformada[ultimo_no_lista,:] - conf_indeformada[primeiro_no_lista,:]
  epsilon.insert(pos, ((comp_f.norm() - comp_i.norm())/comp_i.norm()))

# Lista de compatibilidades
print("Condições de compatibilidade para a estrutura deformada em forma de lista e matriz")
print("\n\t\t\tAC, \t\t\t\t\tAB, \t\t\t\t\t\tCB, \t\t\t\t\tCD, \t\t\t\t\tBD")
display(epsilon)
print("\n")

# Conversão da lista de condições de compatibilidade para uma matriz de compatibilidade
matriz_epsilon=[]
for item in epsilon:
  matriz_epsilon.append(sp.Matrix([item]))
matriz_epsilon = sp.Matrix(matriz_epsilon)
display(matriz_epsilon)
```

    Condições de compatibilidade para a estrutura deformada em forma de lista e matriz

    			AC, 					AB, 						CB, 					CD, 					BD

$\displaystyle \left[ \frac{- \sqrt{a^{2} + b^{2}} + \sqrt{\left(a + desloc_{xc}\right)^{2} + \left(b - desloc_{yc}\right)^{2}}}{\sqrt{a^{2} + b^{2}}}, \  \frac{- a + \sqrt{desloc_{yb}^{2} + \left(a + desloc_{xb}\right)^{2}}}{a}, \  \frac{- b + \sqrt{\left(desloc_{xb} - desloc_{xc}\right)^{2} + \left(b + desloc_{yb} - desloc_{yc}\right)^{2}}}{b}, \  \frac{- a + \sqrt{desloc_{yc}^{2} + \left(a - desloc_{xc}\right)^{2}}}{a}, \  \frac{- \sqrt{a^{2} + b^{2}} + \sqrt{\left(a - desloc_{xb}\right)^{2} + \left(b + desloc_{yb}\right)^{2}}}{\sqrt{a^{2} + b^{2}}}\right]$

$\displaystyle \left[\begin{matrix}\frac{- \sqrt{a^{2} + b^{2}} + \sqrt{\left(a + desloc_{xc}\right)^{2} + \left(b - desloc_{yc}\right)^{2}}}{\sqrt{a^{2} + b^{2}}}\\\frac{- a + \sqrt{desloc_{yb}^{2} + \left(a + desloc_{xb}\right)^{2}}}{a}\\\frac{- b + \sqrt{\left(desloc_{xb} - desloc_{xc}\right)^{2} + \left(b + desloc_{yb} - desloc_{yc}\right)^{2}}}{b}\\\frac{- a + \sqrt{desloc_{yc}^{2} + \left(a - desloc_{xc}\right)^{2}}}{a}\\\frac{- \sqrt{a^{2} + b^{2}} + \sqrt{\left(a - desloc_{xb}\right)^{2} + \left(b + desloc_{yb}\right)^{2}}}{\sqrt{a^{2} + b^{2}}}\end{matrix}\right]$

#Alternativa C)
Linearize as condições de compatibilidade em função dos deslocamentos. Reescreva-as usando a matriz jacobiana da forma vetorial das condições de compatibilidade. Neste caso, a transformação linear representada pela Jacobiana ${\bf J(p)}$ é a aproximação linear da função vetorial ${\bf f(u)}$ nas proximidades do ponto ${\bf p}$, e pode ser representada pela expressão $$ {\bf f(u)} - {\bf f(p)} = {\bf J(p)} {\bf (u-p)} $$
onde ${\bf u}$ é um ponto de interesse na vizinhança de ${\bf p}$.

$ {\bf f(u)} - {\bf f(p)} = {\bf J(p)} {\bf (u-p)} \Rightarrow$

$ {\bf f(u)} = {\bf J(p)} {\bf (u-p) + {\bf f(p)}} \Rightarrow$

$ {\bf f(u)} = {\bf J(0)} {\bf (u-0)} + {\bf f(0)}$

```
from sympy import latex, Eq                               #Linearização das condições de compatibilidade

Jacobiano = matriz_epsilon.jacobian(matriz_deslocamentos) #Calculo do Jacobiano
print("J(p) = ")
display(Jacobiano)

print("\nJ(0) = ")                                        #Substituição das posições iniciais no jacobiano
Jacobiano_0 = Jacobiano.subs([(desloc_xb, 0), (desloc_xc, 0), (desloc_yb, 0), (desloc_yc, 0)])
display(Jacobiano_0)

print("\nf(0) = ")                                        #Função vetorial no ponto inicial
funcaoVetorial = matriz_epsilon.subs([(desloc_xb, 0), (desloc_xc, 0), (desloc_yb, 0), (desloc_yc, 0)])
display(funcaoVetorial)

print("\nf(u) = ")                                        #Transformação linear
epsilon_linearizado = Jacobiano_0 * matriz_deslocamentos + funcaoVetorial
display(epsilon_linearizado)
```

    J(p) =

$\displaystyle \left[\begin{matrix}0 & 0 & \frac{a + desloc_{xc}}{\sqrt{a^{2} + b^{2}} \sqrt{\left(a + desloc_{xc}\right)^{2} + \left(b - desloc_{yc}\right)^{2}}} & \frac{- b + desloc_{yc}}{\sqrt{a^{2} + b^{2}} \sqrt{\left(a + desloc_{xc}\right)^{2} + \left(b - desloc_{yc}\right)^{2}}}\\\frac{a + desloc_{xb}}{a \sqrt{desloc_{yb}^{2} + \left(a + desloc_{xb}\right)^{2}}} & \frac{desloc_{yb}}{a \sqrt{desloc_{yb}^{2} + \left(a + desloc_{xb}\right)^{2}}} & 0 & 0\\\frac{desloc_{xb} - desloc_{xc}}{b \sqrt{\left(desloc_{xb} - desloc_{xc}\right)^{2} + \left(b + desloc_{yb} - desloc_{yc}\right)^{2}}} & \frac{b + desloc_{yb} - desloc_{yc}}{b \sqrt{\left(desloc_{xb} - desloc_{xc}\right)^{2} + \left(b + desloc_{yb} - desloc_{yc}\right)^{2}}} & \frac{- desloc_{xb} + desloc_{xc}}{b \sqrt{\left(desloc_{xb} - desloc_{xc}\right)^{2} + \left(b + desloc_{yb} - desloc_{yc}\right)^{2}}} & \frac{- b - desloc_{yb} + desloc_{yc}}{b \sqrt{\left(desloc_{xb} - desloc_{xc}\right)^{2} + \left(b + desloc_{yb} - desloc_{yc}\right)^{2}}}\\0 & 0 & \frac{- a + desloc_{xc}}{a \sqrt{desloc_{yc}^{2} + \left(a - desloc_{xc}\right)^{2}}} & \frac{desloc_{yc}}{a \sqrt{desloc_{yc}^{2} + \left(a - desloc_{xc}\right)^{2}}}\\\frac{- a + desloc_{xb}}{\sqrt{a^{2} + b^{2}} \sqrt{\left(a - desloc_{xb}\right)^{2} + \left(b + desloc_{yb}\right)^{2}}} & \frac{b + desloc_{yb}}{\sqrt{a^{2} + b^{2}} \sqrt{\left(a - desloc_{xb}\right)^{2} + \left(b + desloc_{yb}\right)^{2}}} & 0 & 0\end{matrix}\right]$

    J(0) =

$\displaystyle \left[\begin{matrix}0 & 0 & \frac{a}{a^{2} + b^{2}} & - \frac{b}{a^{2} + b^{2}}\\\frac{1}{a} & 0 & 0 & 0\\0 & \frac{1}{b} & 0 & - \frac{1}{b}\\0 & 0 & - \frac{1}{a} & 0\\- \frac{a}{a^{2} + b^{2}} & \frac{b}{a^{2} + b^{2}} & 0 & 0\end{matrix}\right]$

    f(0) =

$\displaystyle \left[\begin{matrix}0\\0\\0\\0\\0\end{matrix}\right]$

    f(u) =

$\displaystyle \left[\begin{matrix}\frac{a desloc_{xc}}{a^{2} + b^{2}} - \frac{b desloc_{yc}}{a^{2} + b^{2}}\\\frac{desloc_{xb}}{a}\\\frac{desloc_{yb}}{b} - \frac{desloc_{yc}}{b}\\- \frac{desloc_{xc}}{a}\\- \frac{a desloc_{xb}}{a^{2} + b^{2}} + \frac{b desloc_{yb}}{a^{2} + b^{2}}\end{matrix}\right]$

# Alternativa D)
Responda à seguinte questão: Qual a hipótese envolvida no processo de linearização e por que a linearização é necessária?

R - A hipótese envolvida é de que as deformações são pequenas. Dito isso, o processo de linearização é importante para facilitar os cálculos, já que passamos a usar equações lineares ao invés de equações não lineares. De modo geral, o objetivo é simplificar a resolução do problema.

#Alternativa E)

Escreva as condições de equilíbrio na configuração indeformada. Use uma notação vetorial para as equações de equilíbrio.

Considerando que $ \sum Y = 0 $ e $ \sum X = 0 $, temos:

```
Nac, Nab, Ncb, Ncd, Nbd = sp.var('N_{ac} N_{ab} N_{cb} N_{cd} N_{bd}', real=True, positive=True)
Normais_nos = [Nac, Nab, Ncb, Ncd, Nbd]

#Condições de equilibrio para o eixo X
BX = Nbd*(a/sp.sqrt(a**2 + b**2)) - Nab
CX = Ncd - Nac*a/(sp.sqrt(a**2 + b**2))

#Condições de equilibrio para o eixo Y
BY = Ncb + Nbd*b/(sp.sqrt(a**2 + b**2))
CY = - Ncb - Nac*b/(sp.sqrt(a**2 + b**2)) + P

print("Condições de equilibrio para os pontos B e C das direções X e Y:\n")
print("\tBX     \t\tBY   \t\tCX   \t\t\tCY")
display([BX, BY, CX, CY])
```

    Condições de equilibrio para os pontos B e C das direções X e Y:

    	BX     		BY   		CX   			CY

$\displaystyle \left[ - N_{ab} + \frac{N_{bd} a}{\sqrt{a^{2} + b^{2}}}, \  \frac{N_{bd} b}{\sqrt{a^{2} + b^{2}}} + N_{cb}, \  - \frac{N_{ac} a}{\sqrt{a^{2} + b^{2}}} + N_{cd}, \  - \frac{N_{ac} b}{\sqrt{a^{2} + b^{2}}} - N_{cb} - 40000\right]$

#Alternativa F)

Usando as relações constitutivas, reescreva as forças internas em função dos deslocamentos e reescreva as equações de equilíbrio em função dos deslocamentos.

Equação Constitutiva:

$\frac{N}{A} = E \epsilon \Rightarrow$

$N = E \epsilon A$

```
Normais_nos = [Nac, Nab, Ncb, Ncd, Nbd]
Normais_nos
```

$\displaystyle \left[ N_{ac}, \  N_{ab}, \  N_{cb}, \  N_{cd}, \  N_{bd}\right]$

```
A, E = sp.var('A E', real=True, positive=True)

equacoesEquilibrio = []
for item in range(len(Normais_nos)):
  equacoesEquilibrio.append(E * epsilon[item] * A) #epsilon

print("\t\t\tAC, \t\t\t\t\t\tAB, \t\t\t\t\t\t\tCB, \t\t\t\t\t\t\tCD, \t\t\t\t\tBD")
display(equacoesEquilibrio)
```

    			AC, 						AB, 							CB, 							CD, 					BD

$\displaystyle \left[ \frac{A E \left(- \sqrt{a^{2} + b^{2}} + \sqrt{\left(a + desloc_{xc}\right)^{2} + \left(b - desloc_{yc}\right)^{2}}\right)}{\sqrt{a^{2} + b^{2}}}, \  \frac{A E \left(- a + \sqrt{desloc_{yb}^{2} + \left(a + desloc_{xb}\right)^{2}}\right)}{a}, \  \frac{A E \left(- b + \sqrt{\left(desloc_{xb} - desloc_{xc}\right)^{2} + \left(b + desloc_{yb} - desloc_{yc}\right)^{2}}\right)}{b}, \  \frac{A E \left(- a + \sqrt{desloc_{yc}^{2} + \left(a - desloc_{xc}\right)^{2}}\right)}{a}, \  \frac{A E \left(- \sqrt{a^{2} + b^{2}} + \sqrt{\left(a - desloc_{xb}\right)^{2} + \left(b + desloc_{yb}\right)^{2}}\right)}{\sqrt{a^{2} + b^{2}}}\right]$

```
normal = []
for pos, nos in enumerate(identifica_barra):
  # Auxiliares para salvar o valor dos nós das barras
  primeiro_no_lista = nos[0]
  ultimo_no_lista = nos[1]

  # Cálculo das condições de compatibilidade
  comp_f = conf_deformada[ultimo_no_lista,:] - conf_deformada[primeiro_no_lista,:]
  comp_f /= comp_f.norm()
  normal.append(comp_f)

# Calculo da matriz normal
normal_mat = sp.Matrix(normal)
display(normal_mat)
display(normal_mat.subs([(desloc_xb, 0), (desloc_xc, 0), (desloc_yb, 0), (desloc_yc, 0)]))
```

$\displaystyle \left[\begin{matrix}\frac{a + desloc_{xc}}{\sqrt{\left(a + desloc_{xc}\right)^{2} + \left(b - desloc_{yc}\right)^{2}}} & \frac{b - desloc_{yc}}{\sqrt{\left(a + desloc_{xc}\right)^{2} + \left(b - desloc_{yc}\right)^{2}}}\\\frac{a + desloc_{xb}}{\sqrt{desloc_{yb}^{2} + \left(a + desloc_{xb}\right)^{2}}} & - \frac{desloc_{yb}}{\sqrt{desloc_{yb}^{2} + \left(a + desloc_{xb}\right)^{2}}}\\\frac{desloc_{xb} - desloc_{xc}}{\sqrt{\left(desloc_{xb} - desloc_{xc}\right)^{2} + \left(b + desloc_{yb} - desloc_{yc}\right)^{2}}} & \frac{- b - desloc_{yb} + desloc_{yc}}{\sqrt{\left(desloc_{xb} - desloc_{xc}\right)^{2} + \left(b + desloc_{yb} - desloc_{yc}\right)^{2}}}\\\frac{a - desloc_{xc}}{\sqrt{desloc_{yc}^{2} + \left(a - desloc_{xc}\right)^{2}}} & \frac{desloc_{yc}}{\sqrt{desloc_{yc}^{2} + \left(a - desloc_{xc}\right)^{2}}}\\\frac{a - desloc_{xb}}{\sqrt{\left(a - desloc_{xb}\right)^{2} + \left(b + desloc_{yb}\right)^{2}}} & \frac{b + desloc_{yb}}{\sqrt{\left(a - desloc_{xb}\right)^{2} + \left(b + desloc_{yb}\right)^{2}}}\end{matrix}\right]$

$\displaystyle \left[\begin{matrix}\frac{a}{\sqrt{a^{2} + b^{2}}} & \frac{b}{\sqrt{a^{2} + b^{2}}}\\1 & 0\\0 & -1\\1 & 0\\\frac{a}{\sqrt{a^{2} + b^{2}}} & \frac{b}{\sqrt{a^{2} + b^{2}}}\end{matrix}\right]$

#Alternativa G)

Resolva o sistema de equações de equilíbrio para os deslocamentos. Assuma valores unitários para as áreas das seções transversais (A). O módulo de elasticidade (E) tem valor igual 150000 N/m 2 .

```
sistema = []
for eq in equacoesEquilibrio:
  sistema.append(eq.subs([(a, 4),(b, 3),(A, 1),(E, 150000)]))
display(sistema)
#display(sp.linsolve(sistema, [desloc_xc, desloc_xb, desloc_yc, desloc_yb]))
```

$\displaystyle \left[ 30000 \sqrt{\left(3 - desloc_{yc}\right)^{2} + \left(desloc_{xc} + 4\right)^{2}} - 150000, \  37500 \sqrt{desloc_{yb}^{2} + \left(desloc_{xb} + 4\right)^{2}} - 150000, \  50000 \sqrt{\left(desloc_{xb} - desloc_{xc}\right)^{2} + \left(desloc_{yb} - desloc_{yc} + 3\right)^{2}} - 150000, \  37500 \sqrt{desloc_{yc}^{2} + \left(4 - desloc_{xc}\right)^{2}} - 150000, \  30000 \sqrt{\left(4 - desloc_{xb}\right)^{2} + \left(desloc_{yb} + 3\right)^{2}} - 150000\right]$

Ao usar a função *linsolve* na célula acima, nós recebemos a seguinte mensagem de erro: "*During handling of the above exception, another exception occurred:*". Aparentemente, esse problema tem relação com as raízes quadradas das equações de equilíbrio que encontramos. Mesmo pesquisando, não conseguimos encontrar uma solução para esse problema. Dessa forma, deixamos a linha comentada.

#Alternativa H)
Compare o resultado encontrado com o pacote anastruct.

```
! pip install anastruct
```

    Collecting anastruct
      Downloading anastruct-1.2.0-py3-none-any.whl (69 kB)
         |████████████████████████████████| 69 kB 3.7 MB/s
    Requirement already satisfied: numpy>=1.15.4 in /usr/local/lib/python3.7/dist-packages (from anastruct) (1.19.5)
    Requirement already satisfied: matplotlib>=3.0 in /usr/local/lib/python3.7/dist-packages (from anastruct) (3.2.2)
    Requirement already satisfied: scipy>=1.1.0 in /usr/local/lib/python3.7/dist-packages (from anastruct) (1.4.1)
    Requirement already satisfied: kiwisolver>=1.0.1 in /usr/local/lib/python3.7/dist-packages (from matplotlib>=3.0->anastruct) (1.3.2)
    Requirement already satisfied: python-dateutil>=2.1 in /usr/local/lib/python3.7/dist-packages (from matplotlib>=3.0->anastruct) (2.8.2)
    Requirement already satisfied: cycler>=0.10 in /usr/local/lib/python3.7/dist-packages (from matplotlib>=3.0->anastruct) (0.11.0)
    Requirement already satisfied: pyparsing!=2.0.4,!=2.1.2,!=2.1.6,>=2.0.1 in /usr/local/lib/python3.7/dist-packages (from matplotlib>=3.0->anastruct) (3.0.6)
    Requirement already satisfied: six>=1.5 in /usr/local/lib/python3.7/dist-packages (from python-dateutil>=2.1->matplotlib>=3.0->anastruct) (1.15.0)
    Installing collected packages: anastruct
    Successfully installed anastruct-1.2.0

```
# importando os pacotes
import numpy as np
import matplotlib.pyplot as plt
from anastruct import SystemElements

E, A = 150000,1
ss = SystemElements(EA=E*A)

# Define e posiciona os nós da estrutura
node={"A":(0,0), "B":(4,0), "C":(4,3), "D":(8,3)}

# # Define as conectividades/membros entre os nós
ss.add_element(location=[node['A'], node['B']], spring={2:0})
ss.add_element(location=[node['A'], node['C']], spring={2:0})
ss.add_element(location=[node['D'], node['B']], spring={2:0})
ss.add_element(location=[node['D'], node['C']], spring={2:0})
ss.add_element(location=[node['B'], node['C']], spring={1:0, 2:0})

# Adiciona os suportes fixos
node_id = ss.find_node_id(node['A'])
ss.add_support_hinged(node_id=node_id)
node_id = ss.find_node_id(node['D'])
ss.add_support_hinged(node_id=node_id)

#Adiciona a carga pontual
F=-40000 #=-40kn
node_C = ss.find_node_id(node['C'])
ss.point_load(node_id=node_C, Fy=F, rotation=0) # Add um carregamento ao nó "C" da estrutura

ss.solve()

ss.show_structure(scale=0.7, figsize=(7, 4.5), offset=(0, 0))
ss.show_displacement(scale=0.7, figsize=(7,4.5), offset=(0,0))
print("Nó A: \nDeslocamento em x= " + str(ss.get_node_displacements()[0][1]) + "\nDeslocamento em y= " + str(ss.get_node_displacements()[0][2]), "\nphi_y = " + str(ss.get_node_displacements()[0][3]) + "\n")
print("Nó B: \nDeslocamento em x= " + str(ss.get_node_displacements()[1][1]) + "\nDeslocamento em y= " + str(ss.get_node_displacements()[1][2]), "\nphi_y = " + str(ss.get_node_displacements()[1][3]) + "\n")
print("Nó C: \nDeslocamento em x= " + str(ss.get_node_displacements()[2][1]) + "\nDeslocamento em y= " + str(ss.get_node_displacements()[2][2]), "\nphi_y = " + str(ss.get_node_displacements()[2][3]) + "\n")
print("Nó D: \nDeslocamento em x= " + str(ss.get_node_displacements()[3][1]) + "\nDeslocamento em y= " + str(ss.get_node_displacements()[3][2]), "\nphi_y = " + str(ss.get_node_displacements()[3][3]) + "\n")
```

```

```