def Enforce_Detgammabar_Constraint_symb_expressions(): # Set spatial dimension (must be 3 for BSSN) DIM = 3 # Then we set the coordinate system for the numerical grid rfm.reference_metric( ) # Create ReU, ReDD needed for rescaling B-L initial data, generating BSSN RHSs, etc. # We will need the h_{ij} quantities defined within BSSN_RHSs # below when we enforce the gammahat=gammabar constraint # Step 1: All barred quantities are defined in terms of BSSN rescaled gridfunctions, # which we declare here in case they haven't yet been declared elsewhere. Bq.declare_BSSN_gridfunctions_if_not_declared_already() hDD = Bq.hDD Bq.BSSN_basic_tensors() gammabarDD = Bq.gammabarDD # First define the Kronecker delta: KroneckerDeltaDD = ixp.zerorank2() for i in range(DIM): KroneckerDeltaDD[i][i] = sp.sympify(1) # The detgammabar in BSSN_RHSs is set to detgammahat when BSSN_RHSs::detgbarOverdetghat_equals_one=True (default), # so we manually compute it here: dummygammabarUU, detgammabar = ixp.symm_matrix_inverter3x3(gammabarDD) # Next apply the constraint enforcement equation above. hprimeDD = ixp.zerorank2() for i in range(DIM): for j in range(DIM): hprimeDD[i][j] = \ (nrpyAbs(rfm.detgammahat) / detgammabar) ** (sp.Rational(1, 3)) * (KroneckerDeltaDD[i][j] + hDD[i][j]) \ - KroneckerDeltaDD[i][j] enforce_detg_constraint_symb_expressions = [ lhrh(lhs=gri.gfaccess("in_gfs", "hDD00"), rhs=hprimeDD[0][0]), lhrh(lhs=gri.gfaccess("in_gfs", "hDD01"), rhs=hprimeDD[0][1]), lhrh(lhs=gri.gfaccess("in_gfs", "hDD02"), rhs=hprimeDD[0][2]), lhrh(lhs=gri.gfaccess("in_gfs", "hDD11"), rhs=hprimeDD[1][1]), lhrh(lhs=gri.gfaccess("in_gfs", "hDD12"), rhs=hprimeDD[1][2]), lhrh(lhs=gri.gfaccess("in_gfs", "hDD22"), rhs=hprimeDD[2][2]) ] return enforce_detg_constraint_symb_expressions
def BSSN_constraints(add_T4UUmunu_source_terms=False): # Step 1.a: 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.b: 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 2: Hamiltonian constraint. # First declare all needed variables Bq.declare_BSSN_gridfunctions_if_not_declared_already() # Sets trK Bq.BSSN_basic_tensors() # Sets AbarDD Bq.gammabar__inverse_and_derivs() # Sets gammabarUU Bq.AbarUU_AbarUD_trAbar_AbarDD_dD() # Sets AbarUU and AbarDD_dD Bq.RicciBar__gammabarDD_dHatD__DGammaUDD__DGammaU() # Sets RbarDD Bq.phi_and_derivs() # Sets phi_dBarD & phi_dBarDD ############################### ############################### # HAMILTONIAN CONSTRAINT ############################### ############################### # Term 1: 2/3 K^2 global H H = sp.Rational(2, 3) * Bq.trK**2 # Term 2: -A_{ij} A^{ij} for i in range(DIM): for j in range(DIM): H += -Bq.AbarDD[i][j] * Bq.AbarUU[i][j] # Term 3a: trace(Rbar) Rbartrace = sp.sympify(0) for i in range(DIM): for j in range(DIM): Rbartrace += Bq.gammabarUU[i][j] * Bq.RbarDD[i][j] # Term 3b: -8 \bar{\gamma}^{ij} \bar{D}_i \phi \bar{D}_j \phi = -8*phi_dBar_times_phi_dBar # Term 3c: -8 \bar{\gamma}^{ij} \bar{D}_i \bar{D}_j \phi = -8*phi_dBarDD_contraction phi_dBar_times_phi_dBar = sp.sympify(0) # Term 3b phi_dBarDD_contraction = sp.sympify(0) # Term 3c for i in range(DIM): for j in range(DIM): phi_dBar_times_phi_dBar += Bq.gammabarUU[i][j] * Bq.phi_dBarD[ i] * Bq.phi_dBarD[j] phi_dBarDD_contraction += Bq.gammabarUU[i][j] * Bq.phi_dBarDD[i][j] # Add Term 3: H += Bq.exp_m4phi * (Rbartrace - 8 * (phi_dBar_times_phi_dBar + phi_dBarDD_contraction)) if add_T4UUmunu_source_terms: M_PI = par.Cparameters("#define", thismodule, "M_PI", "") # M_PI is pi as defined in C BTmunu.define_BSSN_T4UUmunu_rescaled_source_terms() rho = BTmunu.rho H += -16 * M_PI * rho # FIXME: ADD T4UUmunu SOURCE TERMS TO MOMENTUM CONSTRAINT! # Step 3: M^i, the momentum constraint ############################### ############################### # MOMENTUM CONSTRAINT ############################### ############################### # SEE Tutorial-BSSN_constraints.ipynb for full documentation. global MU MU = ixp.zerorank1() # Term 2: 6 A^{ij} \partial_j \phi: for i in range(DIM): for j in range(DIM): MU[i] += 6 * Bq.AbarUU[i][j] * Bq.phi_dD[j] # Term 3: -2/3 \bar{\gamma}^{ij} K_{,j} trK_dD = ixp.declarerank1( "trK_dD") # Not defined in BSSN_RHSs; only trK_dupD is defined there. for i in range(DIM): for j in range(DIM): MU[i] += -sp.Rational(2, 3) * Bq.gammabarUU[i][j] * trK_dD[j] # First define aDD_dD: aDD_dD = ixp.declarerank3("aDD_dD", "sym01") # Then evaluate the conformal covariant derivative \bar{D}_j \bar{A}_{lm} AbarDD_dBarD = ixp.zerorank3() for i in range(DIM): for j in range(DIM): for k in range(DIM): AbarDD_dBarD[i][j][k] = Bq.AbarDD_dD[i][j][k] for l in range(DIM): AbarDD_dBarD[i][j][ k] += -Bq.GammabarUDD[l][k][i] * Bq.AbarDD[l][j] AbarDD_dBarD[i][j][ k] += -Bq.GammabarUDD[l][k][j] * Bq.AbarDD[i][l] # Term 1: Contract twice with the metric to make \bar{D}_{j} \bar{A}^{ij} for i in range(DIM): for j in range(DIM): for k in range(DIM): for l in range(DIM): MU[i] += Bq.gammabarUU[i][k] * Bq.gammabarUU[j][ l] * AbarDD_dBarD[k][l][j] # Finally, we multiply by e^{-4 phi} and rescale the momentum constraint: for i in range(DIM): MU[i] *= Bq.exp_m4phi / rfm.ReU[i]
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 output_Enforce_Detgammabar_Constraint_Ccode(): # Set spatial dimension (must be 3 for BSSN) DIM = 3 # Then we set the coordinate system for the numerical grid rfm.reference_metric( ) # Create ReU, ReDD needed for rescaling B-L initial data, generating BSSN RHSs, etc. # We will need the h_{ij} quantities defined within BSSN_RHSs # below when we enforce the gammahat=gammabar constraint # Step 1: All barred quantities are defined in terms of BSSN rescaled gridfunctions, # which we declare here in case they haven't yet been declared elsewhere. Bq.declare_BSSN_gridfunctions_if_not_declared_already() hDD = Bq.hDD Bq.BSSN_basic_tensors() gammabarDD = Bq.gammabarDD # First define the Kronecker delta: KroneckerDeltaDD = ixp.zerorank2() for i in range(DIM): KroneckerDeltaDD[i][i] = sp.sympify(1) # The detgammabar in BSSN_RHSs is set to detgammahat when BSSN_RHSs::detgbarOverdetghat_equals_one=True (default), # so we manually compute it here: dummygammabarUU, detgammabar = ixp.symm_matrix_inverter3x3(gammabarDD) # Next apply the constraint enforcement equation above. hprimeDD = ixp.zerorank2() for i in range(DIM): for j in range(DIM): hprimeDD[i][j] = \ (sp.Abs(rfm.detgammahat) / detgammabar) ** (sp.Rational(1, 3)) * (KroneckerDeltaDD[i][j] + hDD[i][j]) \ - KroneckerDeltaDD[i][j] enforce_detg_constraint_vars = [ \ lhrh(lhs=gri.gfaccess("in_gfs", "hDD00"), rhs=hprimeDD[0][0]), lhrh(lhs=gri.gfaccess("in_gfs", "hDD01"), rhs=hprimeDD[0][1]), lhrh(lhs=gri.gfaccess("in_gfs", "hDD02"), rhs=hprimeDD[0][2]), lhrh(lhs=gri.gfaccess("in_gfs", "hDD11"), rhs=hprimeDD[1][1]), lhrh(lhs=gri.gfaccess("in_gfs", "hDD12"), rhs=hprimeDD[1][2]), lhrh(lhs=gri.gfaccess("in_gfs", "hDD22"), rhs=hprimeDD[2][2])] enforce_gammadet_string = fin.FD_outputC( "returnstring", enforce_detg_constraint_vars, params="outCverbose=False,preindent=0,includebraces=False") with open("BSSN/enforce_detgammabar_constraint.h", "w") as file: indent = " " file.write( "void enforce_detgammabar_constraint(const int Nxx_plus_2NGHOSTS[3],REAL *xx[3], REAL *in_gfs) {\n\n" ) file.write( lp.loop(["i2", "i1", "i0"], ["0", "0", "0"], [ "Nxx_plus_2NGHOSTS[2]", "Nxx_plus_2NGHOSTS[1]", "Nxx_plus_2NGHOSTS[0]" ], ["1", "1", "1"], [ "#pragma omp parallel for", " const REAL xx2 = xx[2][i2];", " const REAL xx1 = xx[1][i1];" ], "", "const REAL xx0 = xx[0][i0];\n" + enforce_gammadet_string)) file.write("}\n") print( "Output C implementation of det(gammabar) constraint to file BSSN/enforce_detgammabar_constraint.h" )
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!") 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 as input parameters # and v_1^a, v_2^a, and v_3^a tetrads, # as well as detgamma and gammaUU from # BSSN.ADM_in_terms_of_BSSN x, y, z = par.Cparameters("REAL", thismodule, ["x", "y", "z"]) v1UCart = ixp.zerorank1() v2UCart = ixp.zerorank1() detgamma = AB.detgamma gammaUU = AB.gammaUU # Step 2.b: Define v1U and v2U v1UCart = [-y, x, sp.sympify(0)] v2UCart = [x, y, z] # Step 2.c: 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.diff(rfm.xxCart[i], rfm.xx[j]) # Step 2.d: 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: 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.f: Define the rank-3 version of the Levi-Civita symbol. Amongst # other uses, this is needed for the construction of the approximate # quasi-Kinnersley tetrad. def define_LeviCivitaSymbol_rank3(DIM=-1): if DIM == -1: DIM = par.parval_from_str("DIM") LeviCivitaSymbol = ixp.zerorank3() for i in range(DIM): for j in range(DIM): for k in range(DIM): # From https://codegolf.stackexchange.com/questions/160359/levi-civita-symbol : LeviCivitaSymbol[i][j][k] = (i - j) * (j - k) * (k - i) / 2 return LeviCivitaSymbol # Step 2.g: Define v3U v3U = ixp.zerorank1() LeviCivitaSymbolDDD = define_LeviCivitaSymbol_rank3(DIM=3) 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.h: Define omega_{ij} omegaDD = ixp.zerorank2() gammaDD = AB.gammaDD def v_vectorDU(v1U, v2U, v3U, i, a): if i == 0: return v1U[a] elif i == 1: return v2U[a] elif i == 2: return v3U[a] else: print("ERROR: unknown vector!") exit(1) def update_omega(omegaDD, v1U, v2U, v3U, gammaDD): for i in range(DIM): for j in range(DIM): omegaDD[i][j] = sp.sympify(0) for i in range(DIM): for j in range(DIM): 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. e1U = ixp.zerorank1() e2U = ixp.zerorank1() e3U = ixp.zerorank1() update_omega(omegaDD, v1U, v2U, v3U, gammaDD) for a in range(DIM): e1U[a] = v1U[a] / sp.sqrt(omegaDD[0][0]) update_omega(omegaDD, e1U, v2U, v3U, gammaDD) for a in range(DIM): e2U[a] = (v2U[a] - omegaDD[0][1] * e1U[a]) / sp.sqrt(omegaDD[1][1]) update_omega(omegaDD, e1U, e2U, v3U, gammaDD) for a in range(DIM): e3U[a] = (v3U[a] - omegaDD[0][2] * e1U[a] - omegaDD[1][2] * e2U[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) isqrt2 = 1 / sp.sqrt(2) 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]