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
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
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
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
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