Beispiel #1
0
def cross(vec1, vec2):
    vec1_cross_vec2 = ixp.zerorank1()
    LeviCivitaSymbol = ixp.LeviCivitaSymbol_dim3_rank3()
    for i in range(3):
        for j in range(3):
            for k in range(3):
                vec1_cross_vec2[
                    i] += LeviCivitaSymbol[i][j][k] * vec1[j] * vec2[k]
    return vec1_cross_vec2
Beispiel #2
0
def ValenciavU_func_AR(**params):
    LeviCivitaSymbolDDD = ixp.LeviCivitaSymbol_dim3_rank3()

    unit_zU = ixp.zerorank1()
    unit_zU[2] = sp.sympify(1)

    r = rfm.xxSph[0]

    ValenciavU = ixp.zerorank1()
    for i in range(3):
        for j in range(3):
            for k in range(3):
                ValenciavU[i] += noif.coord_leq_bound(
                    r, R_NS_aligned_rotator) * LeviCivitaSymbolDDD[i][j][
                        k] * Omega_aligned_rotator * unit_zU[j] * rfm.xx[k]

    return ValenciavU
def compute_ValenciavU_from_EU_and_BU(EU, BU):
    # <a id='step3'></a>
    # ### Calculate $v^i$
    #
    # Now, we calculate $$\mathbf{v} = \frac{\mathbf{E} \times \mathbf{B}}{B^2},$$ which is equivalent to $$v^i = [ijk] \frac{E^j B^k}{B^2},$$ where $[ijk]$ is the Levi-Civita symbol and $B^2 = \gamma_{ij} B^i B^j$ is a trivial dot product in flat space.
    # $$\label{step3}$$
    LeviCivitaSymbolDDD = ixp.LeviCivitaSymbol_dim3_rank3()

    B2 = sp.sympify(0)
    for i in range(3):
        # In flat spacetime, gamma_{ij} is just a Kronecker delta
        B2 += BU[i]**2  # This is trivial to extend to curved spacetime

    ValenciavU = ixp.zerorank1()
    for i in range(3):
        for j in range(3):
            for k in range(3):
                ValenciavU[
                    i] += LeviCivitaSymbolDDD[i][j][k] * EU[j] * BU[k] / B2

    return ValenciavU
def GiRaFFEfood_NRPy_Aligned_Rotator():
    r = rfm.xxSph[0]
    varpi = sp.sqrt(rfm.xxCart[0]**2 + rfm.xxCart[1]**2)

    mu = B_p_aligned_rotator * R_NS_aligned_rotator**3 / 2

    ASphD = ixp.zerorank1()

    ASphD[2] = mu * varpi**2 / (
        r**3)  # The other components were already declared to be 0.

    # <a id='step3'></a>
    #
    # ### Step 3: Use the Jacobian matrix to transform the vectors to Cartesian coordinates.
    # $$\label{step3}$$
    #
    # \[Back to [top](#top)\]
    #
    # Now, we will use the coordinate transformation definitions provided by reference_metric.py to build the Jacobian
    # $$
    # \frac{\partial x_{\rm Sph}^j}{\partial x_{\rm Cart}^i},
    # $$
    # where $x_{\rm Sph}^j \in \{r,\theta,\phi\}$ and $x_{\rm Cart}^i \in \{x,y,z\}$. We would normally compute its inverse, but since none of the quantities we need to transform have upper indices, it is not necessary. Then, since $A_i$ and has one lower index, it will need to be multiplied by the Jacobian:
    #
    # $$
    # A_i^{\rm Cart} = A_j^{\rm Sph} \frac{\partial x_{\rm Sph}^j}{\partial x_{\rm Cart}^i},
    # $$

    # Step 3: Use the Jacobian matrix to transform the vectors to Cartesian coordinates.
    drrefmetric__dx_0UDmatrix = sp.Matrix([[
        sp.diff(rfm.xxSph[0], rfm.xx[0]),
        sp.diff(rfm.xxSph[0], rfm.xx[1]),
        sp.diff(rfm.xxSph[0], rfm.xx[2])
    ],
                                           [
                                               sp.diff(rfm.xxSph[1],
                                                       rfm.xx[0]),
                                               sp.diff(rfm.xxSph[1],
                                                       rfm.xx[1]),
                                               sp.diff(rfm.xxSph[1], rfm.xx[2])
                                           ],
                                           [
                                               sp.diff(rfm.xxSph[2],
                                                       rfm.xx[0]),
                                               sp.diff(rfm.xxSph[2],
                                                       rfm.xx[1]),
                                               sp.diff(rfm.xxSph[2], rfm.xx[2])
                                           ]])
    #dx__drrefmetric_0UDmatrix = drrefmetric__dx_0UDmatrix.inv() # We don't actually need this in this case.

    global AD
    AD = ixp.zerorank1(DIM=3)
    for i in range(3):
        for j in range(3):
            AD[i] = drrefmetric__dx_0UDmatrix[(j, i)] * ASphD[j]

    # <a id='step4'></a>
    #
    # ### Step 4: Calculate $v^i$
    # $$\label{step4}$$
    #
    # \[Back to [top](#top)\]
    #
    # Here, we will calculate the drift velocity $v^i = \Omega \textbf{e}_z \times \textbf{r} = [ijk] \Omega \textbf{e}^j_z x^k$, where $[ijk]$ is the Levi-Civita permutation symbol and $\textbf{e}^i_z = (0,0,1)$. Conveniently, in flat space, the drift velocity reduces to the Valencia velocity because $\alpha = 1$ and $\beta^i = 0$.

    # Step 4: Calculate v^i
    LeviCivitaSymbolDDD = ixp.LeviCivitaSymbol_dim3_rank3()

    import Min_Max_and_Piecewise_Expressions as noif

    unit_zU = ixp.zerorank1()
    unit_zU[2] = sp.sympify(1)

    global ValenciavU
    ValenciavU = ixp.zerorank1()
    for i in range(3):
        for j in range(3):
            for k in range(3):
                ValenciavU[i] += noif.coord_leq_bound(
                    r, R_NS_aligned_rotator) * LeviCivitaSymbolDDD[i][j][
                        k] * Omega_aligned_rotator * unit_zU[j] * rfm.xx[k]
def GiRaFFEfood_NRPy_1D_tests(stagger=False):
    gammamu = sp.sympify(1) / sp.sqrt(sp.sympify(1) - mu_AW**2)

    # We'll use reference_metric.py to define x and y
    x = rfm.xxCart[0]
    y = rfm.xxCart[1]
    if stagger:
        x_p_half = x + sp.Rational(1, 2) * gri.dxx[0]
        y_p_half = y + sp.Rational(1, 2) * gri.dxx[1]

    if stagger:
        g_AW = sp.cos(sp.sympify(5) * M_PI * gammamu * x_p_half) / M_PI
    else:
        g_AW = sp.cos(sp.sympify(5) * M_PI * gammamu * x) / M_PI

    # Now, we can define the vector potential. We will create three copies of this variable, because the potential is uniquely defined in three zones. Data for $x \leq -0.1/\gamma_\mu$ shall be referred to as "left", data for $-0.1/\gamma_\mu \leq x \leq 0.1/\gamma_\mu$ as "center", and data for $x \geq 0.1/\gamma_\mu$ as "right".

    global AD
    AD = ixp.zerorank1()

    import Min_Max_and_Piecewise_Expressions as noif
    bound = sp.Rational(1, 10) / gammamu

    if stagger:
        Ayleft = gammamu * x_p_half - sp.Rational(15, 1000)
        Aycenter = sp.Rational(115, 100) * gammamu * x_p_half - sp.Rational(
            3, 100) * g_AW
        Ayright = sp.Rational(13, 10) * gammamu * x_p_half - sp.Rational(
            15, 1000)
    else:
        Ayleft = gammamu * x - sp.Rational(15, 1000)
        Aycenter = sp.Rational(115, 100) * gammamu * x - sp.Rational(
            3, 100) * g_AW
        Ayright = sp.Rational(13, 10) * gammamu * x - sp.Rational(15, 1000)

    AD[0] = sp.sympify(0)
    AD[1] = noif.coord_leq_bound(x,-bound)*Ayleft\
           +noif.coord_greater_bound(x,-bound)*noif.coord_leq_bound(x,bound)*Aycenter\
           +noif.coord_greater_bound(x,bound)*Ayright
    if stagger:
        AD[2] = y_p_half - gammamu * (sp.sympify(1) -
                                      mu_AW) * x_p_half  # <a id='step2'></a>
    else:
        AD[2] = y - gammamu * (sp.sympify(1) - mu_AW) * x  # <a id='step2'></a>
    # ### Set the vectors $B^i$ and $E^i$ for the velocity
    #
    # Now, we will set the magnetic and electric fields that we will need to define the initial velocities. First, we need to define $$f(x)=1+\sin (5\pi x);$$ note that in the definition of $B^i$, we need $f(x')$ where $x'=\gamma_\mu x$.
    # $$\label{step2}$$

    xprime = gammamu * x
    f_AW = 1 + sp.sin(5 * M_PI * xprime)

    # We will now set the magnetic field in the wave frame:
    # \begin{align}
    # B'^{x'}(x') = &\ 1.0,\ B'^y(x') = 1.0, \\
    # B'^z(x') = &\ \left \{ \begin{array}{lll} 1.0 & \mbox{if} & x' \leq -0.1 \\
    # 				1.0+0.15 f(x') & \mbox{if} & -0.1 \leq x' \leq 0.1 \\
    # 				1.3 & \mbox{if} & x' \geq 0.1 \end{array} \right. .
    # \end{align}
    #

    Bzleft = sp.sympify(1)
    Bzcenter = sp.sympify(1) + sp.Rational(15, 100) * f_AW
    Bzright = sp.Rational(13, 10)

    BpU = ixp.zerorank1()
    BpU[0] = sp.sympify(1)
    BpU[1] = sp.sympify(1)
    BpU[2] = noif.coord_leq_bound(x,-bound)*Bzleft\
            +noif.coord_greater_bound(x,-bound)*noif.coord_leq_bound(x,bound)*Bzcenter\
            +noif.coord_greater_bound(x,bound)*Bzright

    # Now, we will set the electric field in the wave frame:
    # \begin{align}
    # E'^{x'}(x') &= -B'^z(0,x'), \\
    # E'^y(x') &= 0.0, \\
    # E'^z(x') &= 1.0  .
    # \end{align}

    EpU = ixp.zerorank1()
    EpU[0] = -BpU[2]
    EpU[1] = sp.sympify(0)
    EpU[2] = sp.sympify(1)

    # Next, we must transform the the fields into the grid frame. We'll do the magnetic fields first.
    # \begin{align}
    #   B^x(0,x) = &\ B'^{x'}(\gamma_\mu x) , \\
    #   B^y(0,x) = &\ \gamma_\mu [ B'^y(\gamma_\mu x) - \mu E'^z(\gamma_\mu x) ] , \\
    #   B^z(0,x) = &\ \gamma_\mu [ B'^z(\gamma_\mu x) + \mu E'^y(\gamma_\mu x) ] ,
    # \end{align}
    #

    global BU
    BU = ixp.zerorank1()
    BU[0] = BpU[0]
    BU[1] = gammamu * (BpU[1] - mu_AW * EpU[2])
    BU[2] = gammamu * (BpU[2] + mu_AW * EpU[1])

    # And now the electric fields:
    # \begin{align}
    #   E^x(0,x) = &\ E'^{x'}(\gamma_\mu x) , \\
    #   E^y(0,x) = &\ \gamma_\mu [ E'^y(\gamma_\mu x) + \mu B'^z(\gamma_\mu x) ] ,\\
    #   E^z(0,x) = &\ \gamma_\mu [ E'^z(\gamma_\mu x) - \mu B'^y(\gamma_\mu x) ],
    # \end{align}
    #

    EU = ixp.zerorank1()
    EU[0] = EpU[0]
    EU[1] = gammamu * (EpU[1] + mu_AW * BpU[2])
    EU[2] = gammamu * (EpU[2] - mu_AW * BpU[1])

    # <a id='step3'></a>
    # ### Calculate $v^i$
    #
    # Now, we calculate $$\mathbf{v} = \frac{\mathbf{E} \times \mathbf{B}}{B^2},$$ which is equivalent to $$v^i = [ijk] \frac{E^j B^k}{B^2},$$ where $[ijk]$ is the Levi-Civita symbol and $B^2 = \gamma_{ij} B^i B^j$ is a trivial dot product in flat space.
    # $$\label{step3}$$

    LeviCivitaSymbolDDD = ixp.LeviCivitaSymbol_dim3_rank3()

    B2 = sp.sympify(0)
    for i in range(3):
        # In flat spacetime, gamma_{ij} is just a Kronecker delta
        B2 += BU[i]**2  # This is trivial to extend to curved spacetime

    global ValenciavU
    ValenciavU = ixp.zerorank1()
    for i in range(3):
        for j in range(3):
            for k in range(3):
                ValenciavU[
                    i] += LeviCivitaSymbolDDD[i][j][k] * EU[j] * BU[k] / B2
Beispiel #6
0
def GiRaFFEfood_NRPy_1D_tests_FFE_breakdown(stagger=False):

    # We'll use reference_metric.py to define x and y
    x = rfm.xxCart[0]
    y = rfm.xxCart[1]
    if stagger:
        x_p_half = x + sp.Rational(1, 2) * gri.dxx[0]
        y_p_half = y + sp.Rational(1, 2) * gri.dxx[1]

    # Now, we can define the vector potential. We will create three copies of this variable, because the potential is uniquely defined in three zones. Data for $x \leq -0.1/\gamma_\mu$ shall be referred to as "left", data for $-0.1/\gamma_\mu \leq x \leq 0.1/\gamma_\mu$ as "center", and data for $x \geq 0.1/\gamma_\mu$ as "right".

    global AD
    AD = ixp.zerorank1(DIM=3)

    import Min_Max_and_Piecewise_Expressions as noif
    boundL = sp.sympify(0)
    boundR = sp.Rational(1, 5)

    if stagger:
        Ayleft = x_p_half - sp.Rational(1, 5)
        Aycenter = -sp.sympify(5) * x_p_half**2 + x_p_half - sp.Rational(1, 5)
        Ayright = -x_p_half
    else:
        Ayleft = x - sp.Rational(1, 5)
        Aycenter = -sp.sympify(5) * x**2 + x - sp.Rational(1, 5)
        Ayright = -x

    AD[0] = sp.sympify(0)
    AD[1] = noif.coord_leq_bound(x,boundL)*Ayleft\
           +noif.coord_greater_bound(x,boundL)*noif.coord_leq_bound(x,boundR)*Aycenter\
           +noif.coord_greater_bound(x,boundR)*Ayright
    if stagger:
        AD[2] = y_p_half - AD[1]
    else:
        AD[2] = y - AD[1]
    # ### Set the vectors $B^i$ and $E^i$ for the velocity
    #
    # Now, we will set the magnetic and electric fields that we will need to define the initial velocities. First, we need to define $$f(x)=1+\sin (5\pi x);$$ note that in the definition of $B^i$, we need $f(x')$ where $x'=\gamma_\mu x$.
    # $$\label{step2}$$

    zfunc = -sp.sympify(10) * x + sp.sympify(
        1
    )  # Naming it like this to avoid any possible confusion with the coordinate.

    # We will now set the magnetic field in the wave frame:
    # \begin{align}
    # B'^{x'}(x') = &\ 1.0,\ B'^y(x') = 1.0, \\
    # B'^z(x') = &\ \left \{ \begin{array}{lll} 1.0 & \mbox{if} & x' \leq -0.1 \\
    # 				1.0+0.15 f(x') & \mbox{if} & -0.1 \leq x' \leq 0.1 \\
    # 				1.3 & \mbox{if} & x' \geq 0.1 \end{array} \right. .
    # \end{align}
    #

    global BU
    BU = ixp.zerorank1(DIM=3)

    BU[0] = sp.sympify(1)
    BU[1] = BU[2] = noif.coord_leq_bound(x,boundL)                                   * sp.sympify(1)\
                   +noif.coord_greater_bound(x,boundL)*noif.coord_leq_bound(x,boundR)* zfunc\
                   +noif.coord_greater_bound(x,boundR)                               * -sp.sympify(1)
    # Now, we will set the electric field in the wave frame:
    # \begin{align}
    # E'^{x'}(x') &= -B'^z(0,x'), \\
    # E'^y(x') &= 0.0, \\
    # E'^z(x') &= 1.0  .
    # \end{align}

    EU = ixp.zerorank1()
    EU[0] = sp.sympify(0)
    EU[1] = sp.Rational(1, 2)
    EU[2] = -sp.Rational(1, 2)

    # <a id='step3'></a>
    # ### Calculate $v^i$
    #
    # Now, we calculate $$\mathbf{v} = \frac{\mathbf{E} \times \mathbf{B}}{B^2},$$ which is equivalent to $$v^i = [ijk] \frac{E^j B^k}{B^2},$$ where $[ijk]$ is the Levi-Civita symbol and $B^2 = \gamma_{ij} B^i B^j$ is a trivial dot product in flat space.
    # $$\label{step3}$$

    LeviCivitaSymbolDDD = ixp.LeviCivitaSymbol_dim3_rank3()

    B2 = sp.sympify(0)
    for i in range(3):
        # In flat spacetime, gamma_{ij} is just a Kronecker delta
        B2 += BU[i]**2  # This is trivial to extend to curved spacetime

    global ValenciavU
    ValenciavU = ixp.zerorank1()
    for i in range(3):
        for j in range(3):
            for k in range(3):
                ValenciavU[
                    i] += LeviCivitaSymbolDDD[i][j][k] * EU[j] * BU[k] / B2
Beispiel #7
0
def WeylScalars_Cartesian():
    # Step 3.a: Set spatial dimension (must be 3 for BSSN)
    DIM = 3
    par.set_parval_from_str("grid::DIM", DIM)

    # Step 3.b: declare the additional gridfunctions (i.e., functions whose values are declared
    #          at every grid point, either inside or outside of our SymPy expressions) needed
    #         for this thorn:
    #           * the physical metric $\gamma_{ij}$,
    #           * the extrinsic curvature $K_{ij}$,
    #           * the real and imaginary components of $\psi_4$, and
    #           * the Weyl curvature invariants:
    gammaDD = ixp.register_gridfunctions_for_single_rank2(
        "AUX", "gammaDD", "sym01")  # The AUX or EVOL designation is *not*
    # used in diagnostic modules.
    kDD = ixp.register_gridfunctions_for_single_rank2("AUX", "kDD", "sym01")
    x, y, z = gri.register_gridfunctions("AUX", ["x", "y", "z"])
    global psi4r, psi4i, psi3r, psi3i, psi2r, psi2i, psi1r, psi1i, psi0r, psi0i
    psi4r, psi4i, psi3r, psi3i, psi2r, psi2i, psi1r, psi1i, psi0r, psi0i = gri.register_gridfunctions(
        "AUX", [
            "psi4r", "psi4i", "psi3r", "psi3i", "psi2r", "psi2i", "psi1r",
            "psi1i", "psi0r", "psi0i"
        ])

    # Step 4: Set which tetrad is used; at the moment, only one supported option

    # The tetrad depends in general on the inverse 3-metric gammaUU[i][j]=\gamma^{ij}
    #          and the determinant of the 3-metric (detgamma), which are defined in
    #          the following line of code from gammaDD[i][j]=\gamma_{ij}.
    tmpgammaUU, detgamma = ixp.symm_matrix_inverter3x3(gammaDD)
    detgamma = sp.simplify(detgamma)
    gammaUU = ixp.zerorank2()
    for i in range(3):
        for j in range(3):
            gammaUU[i][j] = sp.simplify(tmpgammaUU[i][j])

    if par.parval_from_str("WeylScal4NRPy.WeylScalars_Cartesian::TetradChoice"
                           ) == "Approx_QuasiKinnersley":
        # Eqs 5.6 in https://arxiv.org/pdf/gr-qc/0104063.pdf
        xmoved = x  # - xorig
        ymoved = y  # - yorig
        zmoved = z  # - zorig

        # Step 5.a: Choose 3 orthogonal vectors. Here, we choose one in the azimuthal
        #          direction, one in the radial direction, and the cross product of the two.
        # Eqs 5.7
        v1U = ixp.zerorank1()
        v2U = ixp.zerorank1()
        v3U = ixp.zerorank1()
        v1U[0] = -ymoved
        v1U[1] = xmoved  # + offset
        v1U[2] = sp.sympify(0)
        v2U[0] = xmoved  # + offset
        v2U[1] = ymoved
        v2U[2] = zmoved
        LeviCivitaSymbol_rank3 = ixp.LeviCivitaSymbol_dim3_rank3()
        for a in range(DIM):
            for b in range(DIM):
                for c in range(DIM):
                    for d in range(DIM):
                        v3U[a] += sp.sqrt(
                            detgamma) * gammaUU[a][d] * LeviCivitaSymbol_rank3[
                                d][b][c] * v1U[b] * v2U[c]

        for a in range(DIM):
            v3U[a] = sp.simplify(v3U[a])

        # Step 5.b: Gram-Schmidt orthonormalization of the vectors.
        # The w_i^a vectors here are used to temporarily hold values on the way to the final vectors e_i^a

        # e_1^a &= \frac{v_1^a}{\omega_{11}}
        # e_2^a &= \frac{v_2^a - \omega_{12} e_1^a}{\omega_{22}}
        # e_3^a &= \frac{v_3^a - \omega_{13} e_1^a - \omega_{23} e_2^a}{\omega_{33}},

        # Normalize the first vector
        w1U = ixp.zerorank1()
        for a in range(DIM):
            w1U[a] = v1U[a]
        omega11 = sp.sympify(0)
        for a in range(DIM):
            for b in range(DIM):
                omega11 += w1U[a] * w1U[b] * gammaDD[a][b]
        e1U = ixp.zerorank1()
        for a in range(DIM):
            e1U[a] = w1U[a] / sp.sqrt(omega11)

        # Subtract off the portion of the first vector along the second, then normalize
        omega12 = sp.sympify(0)
        for a in range(DIM):
            for b in range(DIM):
                omega12 += e1U[a] * v2U[b] * gammaDD[a][b]
        w2U = ixp.zerorank1()
        for a in range(DIM):
            w2U[a] = v2U[a] - omega12 * e1U[a]
        omega22 = sp.sympify(0)
        for a in range(DIM):
            for b in range(DIM):
                omega22 += w2U[a] * w2U[b] * gammaDD[a][b]
        e2U = ixp.zerorank1()
        for a in range(DIM):
            e2U[a] = w2U[a] / sp.sqrt(omega22)

        # Subtract off the portion of the first and second vectors along the third, then normalize
        omega13 = sp.sympify(0)
        for a in range(DIM):
            for b in range(DIM):
                omega13 += e1U[a] * v3U[b] * gammaDD[a][b]
        omega23 = sp.sympify(0)
        for a in range(DIM):
            for b in range(DIM):
                omega23 += e2U[a] * v3U[b] * gammaDD[a][b]
        w3U = ixp.zerorank1()
        for a in range(DIM):
            w3U[a] = v3U[a] - omega13 * e1U[a] - omega23 * e2U[a]
        omega33 = sp.sympify(0)
        for a in range(DIM):
            for b in range(DIM):
                omega33 += w3U[a] * w3U[b] * gammaDD[a][b]
        e3U = ixp.zerorank1()
        for a in range(DIM):
            e3U[a] = w3U[a] / sp.sqrt(omega33)

        # Step 5.c: Construct the tetrad itself.
        # Eqs. 5.6:
        # l^a &= \frac{1}{\sqrt{2}} e_2^a \\
        # n^a &= -\frac{1}{\sqrt{2}} e_2^a \\
        # m^a &= \frac{1}{\sqrt{2}} (e_3^a + i e_1^a) \\
        # \overset{*}{m}{}^a &= \frac{1}{\sqrt{2}} (e_3^a - i e_1^a)
        isqrt2 = 1 / sp.sqrt(2)
        ltetU = ixp.zerorank1()
        ntetU = ixp.zerorank1()
        # mtetU = ixp.zerorank1()
        # mtetccU = ixp.zerorank1()
        remtetU = ixp.zerorank1(
        )  # SymPy did not like trying to take the real/imaginary parts of such a
        immtetU = ixp.zerorank1(
        )  # complicated expression, so we do it ourselves.
        for i in range(DIM):
            ltetU[i] = isqrt2 * e2U[i]
            ntetU[i] = -isqrt2 * e2U[i]
            remtetU[i] = isqrt2 * e3U[i]
            immtetU[i] = isqrt2 * e1U[i]
        nn = isqrt2

    else:
        print("Error: TetradChoice == " + par.parval_from_str("TetradChoice") +
              " unsupported!")
        sys.exit(1)

    # Step 5: Declare and construct the second derivative of the metric.
    gammaDD_dD = ixp.declarerank3("gammaDD_dD", "sym01")

    # Define the Christoffel symbols
    GammaUDD = ixp.zerorank3(DIM)
    for i in range(DIM):
        for k in range(DIM):
            for l in range(DIM):
                for m in range(DIM):
                    GammaUDD[i][k][l] += (sp.Rational(1, 2)) * gammaUU[i][m] * \
                                         (gammaDD_dD[m][k][l] + gammaDD_dD[m][l][k] - gammaDD_dD[k][l][m])

    # Step 6.a: Declare and construct the Riemann curvature tensor:
    # R_{abcd} = \frac{1}{2} (\gamma_{ad,cb}+\gamma_{bc,da}-\gamma_{ac,bd}-\gamma_{bd,ac})
    #            + \gamma_{je} \Gamma^{j}_{bc}\Gamma^{e}_{ad} - \gamma_{je} \Gamma^{j}_{bd} \Gamma^{e}_{ac}
    gammaDD_dDD = ixp.declarerank4("gammaDD_dDD", "sym01_sym23")
    RiemannDDDD = ixp.zerorank4()
    for a in range(DIM):
        for b in range(DIM):
            for c in range(DIM):
                for d in range(DIM):
                    RiemannDDDD[a][b][c][d] = (gammaDD_dDD[a][d][c][b] + \
                                               gammaDD_dDD[b][c][d][a] - \
                                               gammaDD_dDD[a][c][b][d] - \
                                               gammaDD_dDD[b][d][a][c]) / 2
                    for e in range(DIM):
                        for j in range(DIM):
                            RiemannDDDD[a][b][c][d] +=  gammaDD[j][e] * GammaUDD[j][b][c] * GammaUDD[e][a][d] - \
                                                        gammaDD[j][e] * GammaUDD[j][b][d] * GammaUDD[e][a][c]

    # Step 6.b: We also need the extrinsic curvature tensor $K_{ij}$.
    # In Cartesian coordinates, we already made the components gridfunctions.
    # We will, however, need to calculate the trace of K seperately:
    trK = sp.sympify(0)
    for i in range(DIM):
        for j in range(DIM):
            trK += gammaUU[i][j] * kDD[i][j]

    # Step 7: Build the formula for \psi_4.
    # Gauss equation: involving the Riemann tensor and extrinsic curvature.
    # GaussDDDD[i][j][k][l] =& R_{ijkl} + 2K_{i[k}K_{l]j}
    GaussDDDD = ixp.zerorank4()
    for i in range(DIM):
        for j in range(DIM):
            for k in range(DIM):
                for l in range(DIM):
                    GaussDDDD[i][j][k][l] = RiemannDDDD[i][j][k][
                        l] + kDD[i][k] * kDD[l][j] - kDD[i][l] * kDD[k][j]

    # Codazzi equation: involving partial derivatives of the extrinsic curvature.
    # We will first need to declare derivatives of kDD
    # CodazziDDD[j][k][l] =& -2 (K_{j[k,l]} + \Gamma^p_{j[k} K_{l]p})
    kDD_dD = ixp.declarerank3("kDD_dD", "sym01")
    CodazziDDD = ixp.zerorank3()
    for j in range(DIM):
        for k in range(DIM):
            for l in range(DIM):
                CodazziDDD[j][k][l] = kDD_dD[j][l][k] - kDD_dD[j][k][l]
                for p in range(DIM):
                    CodazziDDD[j][k][l] += GammaUDD[p][j][l] * kDD[k][
                        p] - GammaUDD[p][j][k] * kDD[l][p]

    # Another piece. While not associated with any particular equation,
    # this is still useful for organizational purposes.
    # RojoDD[j][l]} = & R_{jl} - K_{jp} K^p_l + KK_{jl} \\
    #               = & \gamma^{pd} R_{jpld} - K_{jp} K^p_l + KK_{jl}
    RojoDD = ixp.zerorank2()
    for j in range(DIM):
        for l in range(DIM):
            RojoDD[j][l] = trK * kDD[j][l]
            for p in range(DIM):
                for d in range(DIM):
                    RojoDD[j][l] += gammaUU[p][d] * RiemannDDDD[j][p][l][
                        d] - kDD[j][p] * gammaUU[p][d] * kDD[d][l]

    # Now we can calculate $\psi_4$ itself! We assume l^0 = n^0 = \frac{1}{\sqrt{2}}
    # and m^0 = \overset{*}{m}{}^0 = 0 to simplify these equations.
    # We calculate the Weyl scalars as defined in https://arxiv.org/abs/gr-qc/0104063
    # In terms of the above-defined quantites, the psis are defined as:
    # \psi_4 =&\ (\text{GaussDDDD[i][j][k][l]}) n^i \overset{*}{m}{}^j n^k \overset{*}{m}{}^l \\
    #         &+2 (\text{CodazziDDD[j][k][l]}) n^{0} \overset{*}{m}{}^{j} n^k \overset{*}{m}{}^l \\
    #         &+ (\text{RojoDD[j][l]}) n^{0} \overset{*}{m}{}^{j} n^{0} \overset{*}{m}{}^{l}.
    # \psi_3 =&\ (\text{GaussDDDD[i][j][k][l]}) l^i n^j \overset{*}{m}{}^k n^l \\
    #         &+ (\text{CodazziDDD[j][k][l]}) (l^{0} n^{j} \overset{*}{m}{}^k n^l - l^{j} n^{0} \overset{*}{m}{}^k n^l - l^k n^j\overset{*}{m}{}^l n^0) \\
    #         &- (\text{RojoDD[j][l]}) l^{0} n^{j} \overset{*}{m}{}^l n^0 - l^{j} n^{0} \overset{*}{m}{}^l n^0 \\
    # \psi_2 =&\ (\text{GaussDDDD[i][j][k][l]}) l^i m^j \overset{*}{m}{}^k n^l \\
    #         &+ (\text{CodazziDDD[j][k][l]}) (l^{0} m^{j} \overset{*}{m}{}^k n^l - l^{j} m^{0} \overset{*}{m}{}^k n^l - l^k m^l \overset{*}{m}{}^l n^0) \\
    #         &- (\text{RojoDD[j][l]}) l^0 m^j \overset{*}{m}{}^l n^0 \\
    # \psi_1 =&\ (\text{GaussDDDD[i][j][k][l]}) n^i l^j m^k l^l \\
    #         &+ (\text{CodazziDDD[j][k][l]}) (n^{0} l^{j} m^k l^l - n^{j} l^{0} m^k l^l - n^k l^l m^j l^0) \\
    #         &- (\text{RojoDD[j][l]}) (n^{0} l^{j} m^l l^0 - n^{j} l^{0} m^l l^0) \\
    # \psi_0 =&\ (\text{GaussDDDD[i][j][k][l]}) l^i m^j l^k m^l \\
    #         &+2 (\text{CodazziDDD[j][k][l]}) (l^0 m^j l^k m^l + l^k m^l l^0 m^j) \\
    #         &+ (\text{RojoDD[j][l]}) l^0 m^j l^0 m^j. \\

    psi4r = sp.sympify(0)
    psi4i = sp.sympify(0)
    psi3r = sp.sympify(0)
    psi3i = sp.sympify(0)
    psi2r = sp.sympify(0)
    psi2i = sp.sympify(0)
    psi1r = sp.sympify(0)
    psi1i = sp.sympify(0)
    psi0r = sp.sympify(0)
    psi0i = sp.sympify(0)
    for l in range(DIM):
        for j in range(DIM):
            psi4r += RojoDD[j][l] * nn * nn * (remtetU[j] * remtetU[l] -
                                               immtetU[j] * immtetU[l])
            psi4i += RojoDD[j][l] * nn * nn * (-remtetU[j] * immtetU[l] -
                                               immtetU[j] * remtetU[l])
            psi3r += -RojoDD[j][l] * nn * nn * (ntetU[j] -
                                                ltetU[j]) * remtetU[l]
            psi3i += RojoDD[j][l] * nn * nn * (ntetU[j] -
                                               ltetU[j]) * immtetU[l]
            psi2r += -RojoDD[j][l] * nn * nn * (remtetU[l] * remtetU[j] +
                                                immtetU[j] * immtetU[l])
            psi2i += -RojoDD[j][l] * nn * nn * (immtetU[l] * remtetU[j] -
                                                remtetU[j] * immtetU[l])
            psi1r += RojoDD[j][l] * nn * nn * (ntetU[j] * remtetU[l] -
                                               ltetU[j] * remtetU[l])
            psi1i += RojoDD[j][l] * nn * nn * (ntetU[j] * immtetU[l] -
                                               ltetU[j] * immtetU[l])
            psi0r += RojoDD[j][l] * nn * nn * (remtetU[j] * remtetU[l] -
                                               immtetU[j] * immtetU[l])
            psi0i += RojoDD[j][l] * nn * nn * (remtetU[j] * immtetU[l] +
                                               immtetU[j] * remtetU[l])

    for l in range(DIM):
        for j in range(DIM):
            for k in range(DIM):
                psi4r += 2 * CodazziDDD[j][k][l] * ntetU[k] * nn * (
                    remtetU[j] * remtetU[l] - immtetU[j] * immtetU[l])
                psi4i += 2 * CodazziDDD[j][k][l] * ntetU[k] * nn * (
                    -remtetU[j] * immtetU[l] - immtetU[j] * remtetU[l])
                psi3r += 1 * CodazziDDD[j][k][l] * nn * (
                    (ntetU[j] - ltetU[j]) * remtetU[k] * ntetU[l] -
                    remtetU[j] * ltetU[k] * ntetU[l])
                psi3i += -1 * CodazziDDD[j][k][l] * nn * (
                    (ntetU[j] - ltetU[j]) * immtetU[k] * ntetU[l] -
                    immtetU[j] * ltetU[k] * ntetU[l])
                psi2r += 1 * CodazziDDD[j][k][l] * nn * (
                    ntetU[l] *
                    (remtetU[j] * remtetU[k] + immtetU[j] * immtetU[k]) -
                    ltetU[k] *
                    (remtetU[j] * remtetU[l] + immtetU[j] * immtetU[l]))
                psi2i += 1 * CodazziDDD[j][k][l] * nn * (
                    ntetU[l] *
                    (immtetU[j] * remtetU[k] - remtetU[j] * immtetU[k]) -
                    ltetU[k] *
                    (remtetU[j] * immtetU[l] - immtetU[j] * remtetU[l]))
                psi1r += 1 * CodazziDDD[j][k][l] * nn * (
                    ltetU[j] * remtetU[k] * ltetU[l] - remtetU[j] * ntetU[k] *
                    ltetU[l] - ntetU[j] * remtetU[k] * ltetU[l])
                psi1i += 1 * CodazziDDD[j][k][l] * nn * (
                    ltetU[j] * immtetU[k] * ltetU[l] - immtetU[j] * ntetU[k] *
                    ltetU[l] - ntetU[j] * immtetU[k] * ltetU[l])
                psi0r += 2 * CodazziDDD[j][k][l] * nn * ltetU[k] * (
                    remtetU[j] * remtetU[l] - immtetU[j] * immtetU[l])
                psi0i += 2 * CodazziDDD[j][k][l] * nn * ltetU[k] * (
                    remtetU[j] * immtetU[l] + immtetU[j] * remtetU[l])

    for l in range(DIM):
        for j in range(DIM):
            for k in range(DIM):
                for i in range(DIM):
                    psi4r += GaussDDDD[i][j][k][l] * ntetU[i] * ntetU[k] * (
                        remtetU[j] * remtetU[l] - immtetU[j] * immtetU[l])
                    psi4i += GaussDDDD[i][j][k][l] * ntetU[i] * ntetU[k] * (
                        -remtetU[j] * immtetU[l] - immtetU[j] * remtetU[l])
                    psi3r += GaussDDDD[i][j][k][l] * ltetU[i] * ntetU[
                        j] * remtetU[k] * ntetU[l]
                    psi3i += -GaussDDDD[i][j][k][l] * ltetU[i] * ntetU[
                        j] * immtetU[k] * ntetU[l]
                    psi2r += GaussDDDD[i][j][k][l] * ltetU[i] * ntetU[l] * (
                        remtetU[j] * remtetU[k] + immtetU[j] * immtetU[k])
                    psi2i += GaussDDDD[i][j][k][l] * ltetU[i] * ntetU[l] * (
                        immtetU[j] * remtetU[k] - remtetU[j] * immtetU[k])
                    psi1r += GaussDDDD[i][j][k][l] * ntetU[i] * ltetU[
                        j] * remtetU[k] * ltetU[l]
                    psi1i += GaussDDDD[i][j][k][l] * ntetU[i] * ltetU[
                        j] * immtetU[k] * ltetU[l]
                    psi0r += GaussDDDD[i][j][k][l] * ltetU[i] * ltetU[k] * (
                        remtetU[j] * remtetU[l] - immtetU[j] * immtetU[l])
                    psi0i += GaussDDDD[i][j][k][l] * ltetU[i] * ltetU[k] * (
                        remtetU[j] * immtetU[l] + immtetU[j] * remtetU[l])
def Psi4_tetrads():
    global l4U, n4U, mre4U, mim4U

    # Step 1.c: Check if tetrad choice is implemented:
    if par.parval_from_str(thismodule + "::TetradChoice") != "QuasiKinnersley":
        print("ERROR: " + thismodule + "::TetradChoice = " +
              par.parval_from_str("TetradChoice") + " currently unsupported!")
        sys.exit(1)

    # Step 1.d: Given the chosen coordinate system, set up
    #           corresponding reference metric and needed
    #           reference metric quantities
    # The following function call sets up the reference metric
    #    and related quantities, including rescaling matrices ReDD,
    #    ReU, and hatted quantities.
    rfm.reference_metric()

    # Step 1.e: Set spatial dimension (must be 3 for BSSN, as BSSN is
    #           a 3+1-dimensional decomposition of the general
    #           relativistic field equations)
    DIM = 3

    # Step 1.f: Import all ADM quantities as written in terms of BSSN quantities
    import BSSN.ADM_in_terms_of_BSSN as AB
    AB.ADM_in_terms_of_BSSN()

    # Step 2.a: Declare the Cartesian x,y,z in terms of
    #           xx0,xx1,xx2.
    x = rfm.xxCart[0]
    y = rfm.xxCart[1]
    z = rfm.xxCart[2]

    # Step 2.b: Declare detgamma and gammaUU from
    #           BSSN.ADM_in_terms_of_BSSN;
    #           simplify detgamma & gammaUU expressions,
    #           which expedites Psi4 codegen.
    detgamma = sp.simplify(AB.detgamma)
    gammaUU = ixp.zerorank2()
    for i in range(DIM):
        for j in range(DIM):
            gammaUU[i][j] = sp.simplify(AB.gammaUU[i][j])

    # Step 2.c: Define v1U and v2U
    v1UCart = [-y, x, sp.sympify(0)]
    v2UCart = [x, y, z]

    # Step 2.d: Construct the Jacobian d x_Cart^i / d xx^j
    Jac_dUCart_dDrfmUD = ixp.zerorank2()
    for i in range(DIM):
        for j in range(DIM):
            Jac_dUCart_dDrfmUD[i][j] = sp.simplify(
                sp.diff(rfm.xxCart[i], rfm.xx[j]))

    # Step 2.e: Invert above Jacobian to get needed d xx^j / d x_Cart^i
    Jac_dUrfm_dDCartUD, dummyDET = ixp.generic_matrix_inverter3x3(
        Jac_dUCart_dDrfmUD)

    # Step 2.e.i: Simplify expressions for d xx^j / d x_Cart^i:
    for i in range(DIM):
        for j in range(DIM):
            Jac_dUrfm_dDCartUD[i][j] = sp.simplify(Jac_dUrfm_dDCartUD[i][j])

    # Step 2.f: Transform v1U and v2U from the Cartesian to the xx^i basis
    v1U = ixp.zerorank1()
    v2U = ixp.zerorank1()
    for i in range(DIM):
        for j in range(DIM):
            v1U[i] += Jac_dUrfm_dDCartUD[i][j] * v1UCart[j]
            v2U[i] += Jac_dUrfm_dDCartUD[i][j] * v2UCart[j]

    # Step 2.g: Define v3U
    v3U = ixp.zerorank1()
    LeviCivitaSymbolDDD = ixp.LeviCivitaSymbol_dim3_rank3()
    for a in range(DIM):
        for b in range(DIM):
            for c in range(DIM):
                for d in range(DIM):
                    v3U[a] += sp.sqrt(detgamma) * gammaUU[a][
                        d] * LeviCivitaSymbolDDD[d][b][c] * v1U[b] * v2U[c]

    # Step 2.g.i: Simplify expressions for v1U,v2U,v3U. This greatly expedites the C code generation (~10x faster)
    #             Drat. Simplification with certain versions of SymPy & coord systems results in a hang. Let's just
    #             evaluate the expressions so the most trivial optimizations can be performed.
    for a in range(DIM):
        v1U[a] = v1U[a].doit()  # sp.simplify(v1U[a])
        v2U[a] = v2U[a].doit()  # sp.simplify(v2U[a])
        v3U[a] = v3U[a].doit()  # sp.simplify(v3U[a])

    # Step 2.h: Define omega_{ij}
    omegaDD = ixp.zerorank2()
    gammaDD = AB.gammaDD

    def v_vectorDU(v1U, v2U, v3U, i, a):
        if i == 0:
            return v1U[a]
        if i == 1:
            return v2U[a]
        if i == 2:
            return v3U[a]
        print("ERROR: unknown vector!")
        sys.exit(1)

    def update_omega(omegaDD, i, j, v1U, v2U, v3U, gammaDD):
        omegaDD[i][j] = sp.sympify(0)
        for a in range(DIM):
            for b in range(DIM):
                omegaDD[i][j] += v_vectorDU(v1U, v2U, v3U, i, a) * v_vectorDU(
                    v1U, v2U, v3U, j, b) * gammaDD[a][b]

    # Step 2.i: Define e^a_i. Note that:
    #           omegaDD[0][0] = \omega_{11} above;
    #           omegaDD[1][1] = \omega_{22} above, etc.
    # First e_1^a: Orthogonalize & normalize:
    e1U = ixp.zerorank1()
    update_omega(omegaDD, 0, 0, v1U, v2U, v3U, gammaDD)
    for a in range(DIM):
        e1U[a] = v1U[a] / sp.sqrt(omegaDD[0][0])

    # Next e_2^a: First orthogonalize:
    e2U = ixp.zerorank1()
    update_omega(omegaDD, 0, 1, e1U, v2U, v3U, gammaDD)
    for a in range(DIM):
        e2U[a] = (v2U[a] - omegaDD[0][1] * e1U[a])
    # Then normalize:
    update_omega(omegaDD, 1, 1, e1U, e2U, v3U, gammaDD)
    for a in range(DIM):
        e2U[a] /= sp.sqrt(omegaDD[1][1])

    # Next e_3^a: First orthogonalize:
    e3U = ixp.zerorank1()
    update_omega(omegaDD, 0, 2, e1U, e2U, v3U, gammaDD)
    update_omega(omegaDD, 1, 2, e1U, e2U, v3U, gammaDD)
    for a in range(DIM):
        e3U[a] = (v3U[a] - omegaDD[0][2] * e1U[a] - omegaDD[1][2] * e2U[a])
    # Then normalize:
    update_omega(omegaDD, 2, 2, e1U, e2U, e3U, gammaDD)
    for a in range(DIM):
        e3U[a] /= sp.sqrt(omegaDD[2][2])

    # Step 2.j: Construct l^mu, n^mu, and m^mu, based on r^mu, theta^mu, phi^mu, and u^mu:
    r4U = ixp.zerorank1(DIM=4)
    u4U = ixp.zerorank1(DIM=4)
    theta4U = ixp.zerorank1(DIM=4)
    phi4U = ixp.zerorank1(DIM=4)

    for a in range(DIM):
        r4U[a + 1] = e2U[a]
        theta4U[a + 1] = e3U[a]
        phi4U[a + 1] = e1U[a]

    # FIXME? assumes alpha=1, beta^i = 0
    if par.parval_from_str(thismodule + "::UseCorrectUnitNormal") == "False":
        u4U[0] = 1
    else:
        # Eq. 2.116 in Baumgarte & Shapiro:
        #  n^mu = {1/alpha, -beta^i/alpha}. Note that n_mu = {alpha,0}, so n^mu n_mu = -1.
        import BSSN.BSSN_quantities as Bq
        Bq.declare_BSSN_gridfunctions_if_not_declared_already()
        Bq.BSSN_basic_tensors()
        u4U[0] = 1 / Bq.alpha
        for i in range(DIM):
            u4U[i + 1] = -Bq.betaU[i] / Bq.alpha

    l4U = ixp.zerorank1(DIM=4)
    n4U = ixp.zerorank1(DIM=4)
    mre4U = ixp.zerorank1(DIM=4)
    mim4U = ixp.zerorank1(DIM=4)

    # M_SQRT1_2 = 1 / sqrt(2) (defined in math.h on Linux)
    M_SQRT1_2 = par.Cparameters("#define", thismodule, "M_SQRT1_2", "")
    isqrt2 = M_SQRT1_2  #1/sp.sqrt(2) <- SymPy drops precision to 15 sig. digits in unit tests
    for mu in range(4):
        l4U[mu] = isqrt2 * (u4U[mu] + r4U[mu])
        n4U[mu] = isqrt2 * (u4U[mu] - r4U[mu])
        mre4U[mu] = isqrt2 * theta4U[mu]
        mim4U[mu] = isqrt2 * phi4U[mu]
def GiRaFFEfood_NRPy_1D_tests_fast_wave():
    # We'll use reference_metric.py to define x and y
    x = rfm.xxCart[0]
    y = rfm.xxCart[1]

    global AD
    AD = ixp.zerorank1(DIM=3)

    import Min_Max_and_Piecewise_Expressions as noif
    bound = sp.Rational(1, 10)

    # A_x = 0, A_y = 0
    # A_z = y+ (-x-0.0075) if x <= -0.1
    #          (0.75x^2 - 0.85x) if -0.1 < x <= 0.1
    #          (-0.7x-0.0075) if x > 0.1

    Azleft = y - x - sp.Rational(75, 10000)
    Azcenter = y + sp.Rational(75, 100) * x * x - sp.Rational(85, 100) * x
    Azright = y - sp.Rational(7, 10) * x - sp.Rational(75, 10000)

    AD[0] = sp.sympify(0)
    AD[1] = sp.sympify(0)
    AD[2] = noif.coord_leq_bound(x,-bound)*Azleft\
           +noif.coord_greater_bound(x,-bound)*noif.coord_leq_bound(x,bound)*Azcenter\
           +noif.coord_greater_bound(x,bound)*Azright

    # B^x(0,x) = 1.0
    # B^y(0,x) = 1.0 if x <= -0.1
    #            1.0-1.5(x+0.1) if -0.1 < x <= 0.1
    #            0.7 if x > 0.1
    # B^z(0,x) = 0

    Byleft = sp.sympify(1)
    Bycenter = sp.sympify(1) - sp.Rational(15, 10) * (x + sp.Rational(1, 10))
    Byright = sp.Rational(7, 10)

    BU = ixp.zerorank1()
    BU[0] = sp.sympify(1)
    BU[1] = noif.coord_leq_bound(x,-bound)*Byleft\
            +noif.coord_greater_bound(x,-bound)*noif.coord_leq_bound(x,bound)*Bycenter\
            +noif.coord_greater_bound(x,bound)*Byright
    BU[2] = 0

    # E^x(0,x) = 0.0 , E^y(x) = 0.0 , E^z(x) = -B^y(0,x)
    EU = ixp.zerorank1()
    EU[0] = sp.sympify(0)
    EU[1] = sp.sympify(0)
    EU[2] = -BU[1]

    LeviCivitaSymbolDDD = ixp.LeviCivitaSymbol_dim3_rank3()

    B2 = sp.sympify(0)
    for i in range(3):
        # In flat spacetime, gamma_{ij} is just a Kronecker delta
        B2 += BU[i]**2  # This is trivial to extend to curved spacetime

    # v^i = [ijk] (E^j B^k) / (B^2)
    global ValenciavU
    ValenciavU = ixp.zerorank1()
    for i in range(3):
        for j in range(3):
            for k in range(3):
                ValenciavU[
                    i] += LeviCivitaSymbolDDD[i][j][k] * EU[j] * BU[k] / B2
Beispiel #10
0
def GiRaFFEfood_NRPy_1D_tests_three_waves(stagger=False):

    # We'll use reference_metric.py to define x and y
    x = rfm.xxCart[0]
    y = rfm.xxCart[1]
    if stagger:
        x_p_half = x + sp.Rational(1, 2) * gri.dxx[0]
        y_p_half = y + sp.Rational(1, 2) * gri.dxx[1]

    # Now, we can define the vector potential. We will create three copies of this variable, because the potential is uniquely defined in three zones. Data for $x \leq -0.1/\gamma_\mu$ shall be referred to as "left", data for $-0.1/\gamma_\mu \leq x \leq 0.1/\gamma_\mu$ as "center", and data for $x \geq 0.1/\gamma_\mu$ as "right".

    global AD
    AD = ixp.zerorank1(DIM=3)

    import Min_Max_and_Piecewise_Expressions as noif

    AD[0] = sp.sympify(0)
    if stagger:
        AD[1] = sp.Rational(7, 2) * x_p_half * noif.coord_greater_bound(
            -x_p_half, 0) + sp.sympify(
                3) * x_p_half * noif.coord_greater_bound(x_p_half, 0)
        AD[2] = y_p_half - sp.Rational(
            3, 2) * x_p_half * noif.coord_greater_bound(
                -x_p_half, 0) - sp.sympify(
                    3) * x_p_half * noif.coord_greater_bound(x_p_half, 0)
    else:
        AD[1] = sp.Rational(7, 2) * x * noif.coord_greater_bound(
            -x, 0) + sp.sympify(3) * x * noif.coord_greater_bound(x, 0)
        AD[2] = y - sp.Rational(3, 2) * x * noif.coord_greater_bound(
            -x, 0) - sp.sympify(3) * x * noif.coord_greater_bound(x, 0)

    # ### Set the vectors $B^i$ and $E^i$ for the velocity
    #
    # Now, we will set the magnetic and electric fields that we will need to define the initial velocities. First, we need to define $$f(x)=1+\sin (5\pi x);$$ note that in the definition of $B^i$, we need $f(x')$ where $x'=\gamma_\mu x$.
    # $$\label{step2}$$

    # We will now set the magnetic field in the wave frame:
    # \begin{align}
    # B'^{x'}(x') = &\ 1.0,\ B'^y(x') = 1.0, \\
    # B'^z(x') = &\ \left \{ \begin{array}{lll} 1.0 & \mbox{if} & x' \leq -0.1 \\
    # 				1.0+0.15 f(x') & \mbox{if} & -0.1 \leq x' \leq 0.1 \\
    # 				1.3 & \mbox{if} & x' \geq 0.1 \end{array} \right. .
    # \end{align}
    #

    B_aU = ixp.zerorank1(DIM=3)
    E_aU = ixp.zerorank1(DIM=3)
    B_pU = ixp.zerorank1(DIM=3)
    E_pU = ixp.zerorank1(DIM=3)
    B_mU = ixp.zerorank1(DIM=3)
    E_mU = ixp.zerorank1(DIM=3)

    #     if stagger:
    #         B_aU[0] = sp.sympify(1)
    #         B_aU[1] = noif.coord_leq_bound(x_p_half,0) * sp.sympify(1) + noif.coord_greater_bound(x_p_half,0) * sp.Rational(3,2)
    #         B_aU[2] = sp.sympify(2)

    #         E_aU[0] = noif.coord_leq_bound(x_p_half,0) * sp.sympify(-1) + noif.coord_greater_bound(x_p_half,0) * sp.Rational(-3,2)
    #         E_aU[1] = sp.sympify(1)
    #         E_aU[2] = sp.sympify(0)

    #         B_pU[0] = sp.sympify(0)
    #         B_pU[1] = noif.coord_leq_bound(x_p_half,0) * sp.sympify(0) + noif.coord_greater_bound(x_p_half,0) * sp.Rational(3,2)
    #         B_pU[2] = noif.coord_leq_bound(x_p_half,0) * sp.sympify(0) + noif.coord_greater_bound(x_p_half,0) * sp.sympify(1)

    #         E_pU[0] = sp.sympify(0)
    #         E_pU[1] = noif.coord_leq_bound(x_p_half,0) * sp.sympify(0) + noif.coord_greater_bound(x_p_half,0) * sp.sympify(1)
    #         E_pU[2] = noif.coord_leq_bound(x_p_half,0) * sp.sympify(0) + noif.coord_greater_bound(x_p_half,0) * sp.Rational(-3,2)

    #         B_mU[0] = sp.sympify(0)
    #         B_mU[1] = noif.coord_leq_bound(x_p_half,0) * sp.Rational(1,2)  + noif.coord_greater_bound(x_p_half,0) * sp.sympify(0)
    #         B_mU[2] = noif.coord_leq_bound(x_p_half,0) * sp.Rational(3,2) + noif.coord_greater_bound(x_p_half,0) * sp.sympify(0)

    #         E_mU[0] = sp.sympify(0)
    #         E_mU[1] = noif.coord_leq_bound(x_p_half,0) * sp.Rational(-3,2) + noif.coord_greater_bound(x_p_half,0) * sp.sympify(0)
    #         E_mU[2] = noif.coord_leq_bound(x_p_half,0) * sp.Rational(1,2)  + noif.coord_greater_bound(x_p_half,0) * sp.sympify(0)
    #     else:
    B_aU[0] = sp.sympify(1)
    B_aU[1] = noif.coord_leq_bound(x, 0) * sp.sympify(
        1) + noif.coord_greater_bound(x, 0) * sp.Rational(3, 2)
    B_aU[2] = sp.sympify(2)

    E_aU[0] = noif.coord_leq_bound(x, 0) * sp.sympify(
        -1) + noif.coord_greater_bound(x, 0) * sp.Rational(-3, 2)
    E_aU[1] = sp.sympify(1)
    E_aU[2] = sp.sympify(0)

    B_pU[0] = sp.sympify(0)
    B_pU[1] = noif.coord_leq_bound(x, 0) * sp.sympify(
        0) + noif.coord_greater_bound(x, 0) * sp.Rational(3, 2)
    B_pU[2] = noif.coord_leq_bound(
        x, 0) * sp.sympify(0) + noif.coord_greater_bound(x, 0) * sp.sympify(1)

    E_pU[0] = sp.sympify(0)
    E_pU[1] = noif.coord_leq_bound(
        x, 0) * sp.sympify(0) + noif.coord_greater_bound(x, 0) * sp.sympify(1)
    E_pU[2] = noif.coord_leq_bound(x, 0) * sp.sympify(
        0) + noif.coord_greater_bound(x, 0) * sp.Rational(-3, 2)

    B_mU[0] = sp.sympify(0)
    B_mU[1] = noif.coord_leq_bound(x, 0) * sp.Rational(
        1, 2) + noif.coord_greater_bound(x, 0) * sp.sympify(0)
    B_mU[2] = noif.coord_leq_bound(x, 0) * sp.Rational(
        3, 2) + noif.coord_greater_bound(x, 0) * sp.sympify(0)

    E_mU[0] = sp.sympify(0)
    E_mU[1] = noif.coord_leq_bound(x, 0) * sp.Rational(
        -3, 2) + noif.coord_greater_bound(x, 0) * sp.sympify(0)
    E_mU[2] = noif.coord_leq_bound(x, 0) * sp.Rational(
        1, 2) + noif.coord_greater_bound(x, 0) * sp.sympify(0)

    global BU
    BU = ixp.zerorank1(DIM=3)
    EU = ixp.zerorank1(DIM=3)
    for i in range(3):
        BU[i] = B_aU[i] + B_pU[i] + B_mU[i]
        EU[i] = E_aU[i] + E_pU[i] + E_mU[i]
# <a id='step3'></a>
# ### Calculate $v^i$
#
# Now, we calculate $$\mathbf{v} = \frac{\mathbf{E} \times \mathbf{B}}{B^2},$$ which is equivalent to $$v^i = [ijk] \frac{E^j B^k}{B^2},$$ where $[ijk]$ is the Levi-Civita symbol and $B^2 = \gamma_{ij} B^i B^j$ is a trivial dot product in flat space.
# $$\label{step3}$$

    LeviCivitaSymbolDDD = ixp.LeviCivitaSymbol_dim3_rank3()

    B2 = sp.sympify(0)
    for i in range(3):
        # In flat spacetime, gamma_{ij} is just a Kronecker delta
        B2 += BU[i]**2  # This is trivial to extend to curved spacetime

    global ValenciavU
    ValenciavU = ixp.zerorank1()
    for i in range(3):
        for j in range(3):
            for k in range(3):
                ValenciavU[
                    i] += LeviCivitaSymbolDDD[i][j][k] * EU[j] * BU[k] / B2