def _get_fields(self, fields): U = fields[0:-1] phi = fields[-1] phi_o = g.lattice(self.M.F_grid_eo, phi.otype) phi_e = g.lattice(self.M.F_grid_eo, phi.otype) g.pick_checkerboard(g.odd, phi_o, phi) g.pick_checkerboard(g.even, phi_e, phi) return [U, phi_e, phi_o]
def _Mdiag(self, dst, src): assert dst != src g.pick_checkerboard(g.even, self.src_e, src) g.pick_checkerboard(g.odd, self.src_o, src) self.dst_o @= self.Mooee * self.src_o self.dst_e @= self.Mooee * self.src_e g.set_checkerboard(dst, self.dst_o) g.set_checkerboard(dst, self.dst_e)
def draw(self, fields, rng): U = fields[0:-1] phi = fields[-1] phi_o = g.lattice(self.M.F_grid_eo, phi.otype) g.pick_checkerboard(g.odd, phi_o, phi) act_o = self.two_flavor_evenodd_schur.draw(U + [phi_o], rng) phi[:] = 0 g.set_checkerboard(phi, phi_o) return act_o
def _M(self, dst, src): assert dst != src g.pick_checkerboard(g.even, self.src_e, src) g.pick_checkerboard(g.odd, self.src_o, src) self.dst_o @= self.Meooe * self.src_e + self.Mooee * self.src_o self.dst_e @= self.Meooe * self.src_o + self.Mooee * self.src_e g.set_checkerboard(dst, self.dst_o) g.set_checkerboard(dst, self.dst_e) self.apply_boundaries(dst)
def verify_projected_even_odd(M, Meo, dst_p, src_p, src): src_proj_p = g.lattice(src) src_proj_p[:] = 0 g.set_checkerboard(src_proj_p, src_p) dst_proj_p = g.eval(M * src_proj_p) g.pick_checkerboard(dst_p.checkerboard(), dst_p, dst_proj_p) reference = g.copy(dst_p) dst_p @= Meo * src_p eps = (g.norm2(dst_p - reference) / g.norm2(reference)) ** 0.5 eps_ref = src.grid.precision.eps * finger_print_tolerance g.message(f"Test projected full matrix result versus eo matrix: {eps}") assert eps < eps_ref
def __init__(self, U, params): # initialize full lattice super().__init__(U, params) U = None # do not use anymore / force use including boundary phase # create checkerboard version self.checkerboard = {} # add even/odd functionality grid_eo = self.U[0].grid.checkerboarded(gpt.redblack) for cb in [gpt.even, gpt.odd]: _U = [gpt.lattice(grid_eo, self.U[0].otype) for u in self.U] for mu in range(self.nd): gpt.pick_checkerboard(cb, _U[mu], self.U[mu]) self.checkerboard[cb] = shift_base(_U, None)
def read_openqcd_fermion(fname, cb=None): """ Read a spinor field written by openqcd into a vspincolor object. Extracts only the values on the sites corresponding to 'cb' if this parameter is set. """ g.message(f"Reading spinor from file {fname} with checkerboard = {cb}") # read into numpy array lat, norm, fld = read_sfld(fname) # change the order in numpy and convert to gpt field # openqcd in memory, slow to fast: t x y z, # we in memory, slow to fast: t z y x, # -> need to swap x and z fld = np.swapaxes(fld, 1, 3) grid = g.grid(fdimensions_from_openqcd(lat), g.double) field = g.vspincolor(grid) field[:] = fld.flatten(order="C") norm2_file = norm[0] norm2_field = g.norm2(field) assert fields_agree_openqcd(norm2_file, norm2_field) assert fields_agree(norm2_file, norm2_field, g.double.eps) if not cb: return field assert cb in [g.even, g.odd] cbgrid = g.grid( grid.gdimensions, grid.precision, g.redblack, parent=grid.parent, mpi=grid.mpi, ) cbfield = g.vspincolor(cbgrid) g.pick_checkerboard(cb, cbfield, field) return cbfield
def import_parity(self, i): gpt.pick_checkerboard(self.parity, self.in_p, i) gpt.pick_checkerboard(self.parity.inv(), self.in_np, i)
def project(self, dst, src): gpt.pick_checkerboard(self.checkerboard, dst, src)
def __init__(self, U, params): assert U[0].grid.nd == 4, "Only 4 dimensions implemented for now." # there could be a chiral U(1) field after U shift_eo.__init__(self, U[0:4], params) # stuff that's needed later on Ndim = U[0].otype.Ndim otype = g.ot_vector_color(Ndim) grid = U[0].grid grid_eo = grid.checkerboarded(g.redblack) self.F_grid = grid self.U_grid = grid self.F_grid_eo = grid_eo self.U_grid_eo = grid_eo self.src_e = g.vector_color(grid_eo, Ndim) self.src_o = g.vector_color(grid_eo, Ndim) self.dst_e = g.vector_color(grid_eo, Ndim) self.dst_o = g.vector_color(grid_eo, Ndim) self.dst_e.checkerboard(g.even) self.dst_o.checkerboard(g.odd) self.mass = ( params["mass"] if "mass" in params and params["mass"] != 0.0 else None ) self.mu5 = params["mu5"] if "mu5" in params and params["mu5"] != 0.0 else None self.chiral = params["chiral"] if "chiral" in params else None # matrix operators self.Mooee = g.matrix_operator( lambda dst, src: self._Mooee(dst, src), otype=otype, grid=grid_eo ) self.Meooe = g.matrix_operator( lambda dst, src: self._Meooe(dst, src), otype=otype, grid=grid_eo ) matrix_operator.__init__( self, lambda dst, src: self._M(dst, src), otype=otype, grid=grid ) self.Mdiag = g.matrix_operator( lambda dst, src: self._Mdiag(dst, src), otype=otype, grid=grid ) # staggered phases # see also Grid/Grid/qcd/action/fermion/StaggeredImpl.h _phases = [g.complex(grid) for i in range(4)] for mu in range(4): _phases[mu][:] = 1.0 for x in range(0, grid.fdimensions[0], 2): _phases[1][x + 1, :, :, :] = -1.0 for y in range(0, grid.fdimensions[1], 2): _phases[2][x, y + 1, :, :] = -1.0 _phases[2][x + 1, y, :, :] = -1.0 for z in range(0, grid.fdimensions[2], 2): _phases[3][x, y, z + 1, :] = -1.0 _phases[3][x, y + 1, z, :] = -1.0 _phases[3][x + 1, y, z, :] = -1.0 _phases[3][x + 1, y + 1, z + 1, :] = -1.0 # use stride > 1 once it is implemented: # _phases[1][1::2, :, :, :] = -1.0 # _phases[2][0::2, 1::2, :, :] = -1.0 # _phases[2][1::2, 0::2, :, :] = -1.0 # _phases[3][0::2, 0::2, 1::2, :] = -1.0 # _phases[3][0::2, 1::2, 0::2, :] = -1.0 # _phases[3][1::2, 0::2, 0::2, :] = -1.0 # _phases[3][1::2, 1::2, 1::2, :] = -1.0 self.phases = {} for cb in [g.even, g.odd]: _phases_eo = [g.lattice(grid_eo, _phases[0].otype) for i in range(4)] for mu in range(4): g.pick_checkerboard(cb, _phases_eo[mu], _phases[mu]) self.phases[cb] = _phases_eo # theta is the chiral U(1) gauge field if self.chiral: # for now, allow both mu5 and chiral U(1) field for testing purposes # assert "mu5" not in params, "should not have both mu5 and chiral in params" assert len(U) == 8, "chiral U(1) field missing?" self.theta = {} for cb in [g.even, g.odd]: _theta_eo = [g.lattice(grid_eo, U[4].otype) for i in range(4)] for mu in range(4): g.pick_checkerboard(cb, _theta_eo[mu], U[4 + mu]) self.theta[cb] = _theta_eo # s(x) is defined between (2.2) and (2.3) in # https://link.springer.com/content/pdf/10.1007/JHEP06(2015)094.pdf if self.mu5: self.s = {} _s = g.complex(grid) for y in range(0, grid.fdimensions[1], 2): _s[:, y, :, :] = 1.0 _s[:, y + 1, :, :] = -1.0 for cb in [g.even, g.odd]: _s_eo = g.lattice(grid_eo, _s.otype) g.pick_checkerboard(cb, _s_eo, _s) self.s[cb] = _s_eo
def __init__(self, U, params): shift_eo.__init__(self, U, boundary_phases=params["boundary_phases"]) Nc = U[0].otype.Nc otype = g.ot_vector_spin_color(4, Nc) grid = U[0].grid grid_eo = grid.checkerboarded(g.redblack) self.F_grid = grid self.U_grid = grid self.F_grid_eo = grid_eo self.U_grid_eo = grid_eo self.vector_space_F = g.vector_space.explicit_grid_otype(self.F_grid, otype) self.vector_space_U = g.vector_space.explicit_grid_otype(self.U_grid, otype) self.vector_space_F_eo = g.vector_space.explicit_grid_otype( self.F_grid_eo, otype ) self.src_e = g.vspincolor(grid_eo) self.src_o = g.vspincolor(grid_eo) self.dst_e = g.vspincolor(grid_eo) self.dst_o = g.vspincolor(grid_eo) self.dst_e.checkerboard(g.even) self.dst_o.checkerboard(g.odd) if params["kappa"] is not None: assert params["mass"] is None self.m0 = 1.0 / params["kappa"] / 2.0 - 4.0 else: self.m0 = params["mass"] self.xi_0 = params["xi_0"] self.csw_r = params["csw_r"] / self.xi_0 self.csw_t = params["csw_t"] self.nu = params["nu"] self.kappa = 1.0 / (2.0 * (self.m0 + 1.0 + 3.0 * self.nu / self.xi_0)) self.open_bc = params["boundary_phases"][self.nd - 1] == 0.0 if self.open_bc: assert all( [ self.xi_0 == 1.0, self.nu == 1.0, self.csw_r == self.csw_t, "cF" in params, ] ) # open bc only for isotropic case, require cF passed self.cF = params["cF"] T = self.L[self.nd - 1] # compute field strength tensor if self.csw_r != 0.0 or self.csw_t != 0.0: self.clover = g.mspincolor(grid) self.clover[:] = 0 I = g.identity(self.clover) for mu in range(self.nd): for nu in range(mu + 1, self.nd): if mu == (self.nd - 1) or nu == (self.nd - 1): cp = self.csw_t else: cp = self.csw_r self.clover += ( -0.5 * cp * g.gamma[mu, nu] * I * g.qcd.gauge.field_strength(U, mu, nu) ) if self.open_bc: # set field strength tensor to unity at the temporal boundaries value = -0.5 * self.csw_t self.clover[:, :, :, 0, :, :, :, :] = 0.0 self.clover[:, :, :, T - 1, :, :, :, :] = 0.0 for alpha in range(4): for a in range(Nc): self.clover[:, :, :, 0, alpha, alpha, a, a] = value self.clover[:, :, :, T - 1, alpha, alpha, a, a] = value if self.cF != 1.0: # add improvement coefficients next to temporal boundaries value = self.cF - 1.0 for alpha in range(4): for a in range(Nc): self.clover[:, :, :, 1, alpha, alpha, a, a] += value self.clover[:, :, :, T - 2, alpha, alpha, a, a] += value # integrate kappa into clover matrix for inversion self.clover += 1.0 / 2.0 * 1.0 / self.kappa * I self.clover_inv = g.matrix.inv(self.clover) self.clover_eo = { g.even: g.lattice(grid_eo, self.clover.otype), g.odd: g.lattice(grid_eo, self.clover.otype), } self.clover_inv_eo = { g.even: g.lattice(grid_eo, self.clover.otype), g.odd: g.lattice(grid_eo, self.clover.otype), } for cb in self.clover_eo: g.pick_checkerboard(cb, self.clover_eo[cb], self.clover) g.pick_checkerboard(cb, self.clover_inv_eo[cb], self.clover_inv) else: self.clover = None self.clover_inv = None self.Meooe = g.matrix_operator( mat=lambda dst, src: self._Meooe(dst, src), vector_space=self.vector_space_F_eo, ) self.Mooee = g.matrix_operator( mat=lambda dst, src: self._Mooee(dst, src), inv_mat=lambda dst, src: self._MooeeInv(dst, src), vector_space=self.vector_space_F_eo, ) self.Dhop = g.matrix_operator( mat=lambda dst, src: self._Dhop(dst, src), vector_space=self.vector_space_F ) matrix_operator.__init__( self, lambda dst, src: self._M(dst, src), vector_space=self.vector_space_F ) self.G5M = g.matrix_operator( lambda dst, src: self._G5M(dst, src), vector_space=self.vector_space_F ) self.Mdiag = g.matrix_operator( lambda dst, src: self._Mdiag(dst, src), vector_space=self.vector_space_F ) self.ImportPhysicalFermionSource = g.matrix_operator( lambda dst, src: g.copy(dst, src), vector_space=self.vector_space_F ) self.ExportPhysicalFermionSolution = g.matrix_operator( lambda dst, src: g.copy(dst, src), vector_space=self.vector_space_F ) self.ExportPhysicalFermionSource = g.matrix_operator( lambda dst, src: g.copy(dst, src), vector_space=self.vector_space_F ) self.Dminus = g.matrix_operator( lambda dst, src: g.copy(dst, src), vector_space=self.vector_space_F )
vec_full(), vec_full(), vec_full(), ) src_e, src_o, tmp_e, tmp_o, tmp2_e, tmp2_o, res_e, res_o = ( vec_half(), vec_half(), vec_half(), vec_half(), vec_half(), vec_half(), vec_half(), vec_half(), ) rng.cnormal(src) g.pick_checkerboard(g.even, src_e, src) g.pick_checkerboard(g.odd, src_o, src) # Meo + Moe = Dhop mat.Dhop.mat(ref, src) mat.Meooe.mat(res_o, src_e) mat.Meooe.mat(res_e, src_o) g.set_checkerboard(res, res_e) g.set_checkerboard(res, res_o) rel_dev = g.norm2(ref - res) / g.norm2(ref) g.message(f""" Test: Meo + Moe = Dhop src = {g.norm2(src)} ref = {g.norm2(ref)} res = {g.norm2(res)} rel. dev. = {rel_dev} -> test {'passed' if rel_dev <= 1e-15 else 'failed'}"""
def verify_matrix_element(fermion, dst, src, tag): mat = get_matrix(fermion_dp, tag) src_prime = g.eval(mat * src) dst.checkerboard(src_prime.checkerboard()) X = g.inner_product(dst, src_prime) eps_ref = src.grid.precision.eps * finger_print_tolerance if mat.adj_mat is not None: X_from_adj = g.inner_product(src, g.adj(mat) * dst).conjugate() eps = abs(X - X_from_adj) / abs(X) g.message(f"Test adj({tag}): {eps}") assert eps < eps_ref if mat.inv_mat is not None: eps = (g.norm2(src - mat * g.inv(mat) * src) / g.norm2(src)) ** 0.5 g.message(f"Test inv({tag}): {eps}") assert eps < eps_ref Y = g.inner_product(dst, g.inv(g.adj(mat)) * src) Y_from_adj = g.inner_product(src, g.inv(mat) * dst).conjugate() eps = abs(Y - Y_from_adj) / abs(Y) g.message(f"Test adj(inv({tag})): {eps}") assert eps < eps_ref # do even/odd tests even_odd_operators = {"": ("Mooee", "Meooe")} if tag in even_odd_operators: g.message(f"Test eo versions of {tag}") grid_rb = fermion.F_grid_eo src_p = g.vspincolor(grid_rb) dst_p = g.vspincolor(grid_rb) tag_Mooee, tag_Meooe = even_odd_operators[tag] mat_Mooee = get_matrix(fermion, tag_Mooee) mat_Meooe = get_matrix(fermion, tag_Meooe) for parity in [g.even, g.odd]: g.pick_checkerboard(parity, src_p, src) g.pick_checkerboard(parity, dst_p, src) verify_matrix_element(fermion, dst_p, src_p, tag_Mooee) verify_projected_even_odd(mat, mat_Mooee, dst_p, src_p, src) g.pick_checkerboard(parity.inv(), dst_p, src) verify_matrix_element(fermion, dst_p, src_p, tag_Meooe) verify_projected_even_odd(mat, mat_Meooe, dst_p, src_p, src) # perform derivative tests projected_gradient_operators = {"": "M_projected_gradient"} if tag in projected_gradient_operators and isinstance( fermion, g.qcd.fermion.differentiable_fine_operator ): # Test projected gradient for src^dag M^dag M src g.message(f"Test projected_gradient of {tag} via src^dag M^dag M src") mat_pg = get_matrix(fermion, projected_gradient_operators[tag]) dst_pg = g(mat * src) class df(g.group.differentiable_functional): def __call__(self, Uprime): return g.norm2(get_matrix(fermion.updated(Uprime), tag) * src) def gradient(self, Uprime, dUprime): assert dUprime == Uprime return [ g.qcd.gauge.project.traceless_hermitian(g.eval(a + b)) for a, b in zip(mat_pg(dst_pg, src), mat_pg.adj()(src, dst_pg)) ] dfv = df() dfv.assert_gradient_error(rng, U, U, 1e-3, 1e-6) # Test projected gradient for src^dag G5 M src if isinstance(fermion, g.qcd.fermion.gauge_independent_g5_hermitian): g.message(f"Test projected_gradient of {tag} via src^dag G5 M src") class df(g.group.differentiable_functional): def __call__(self, Uprime): return g.inner_product( src, fermion.G5 * get_matrix(fermion.updated(Uprime), tag) * src ).real def gradient(self, Uprime, dUprime): assert dUprime == Uprime return g.qcd.gauge.project.traceless_hermitian( mat_pg(fermion.G5 * src, src) ) dfv = df() dfv.assert_gradient_error(rng, U, U, 1e-3, 1e-6) g.message(f"Test projected_gradient of {tag} via src^dag M^dag G5 src") class df(g.group.differentiable_functional): def __call__(self, Uprime): return g.inner_product( src, get_matrix(fermion.updated(Uprime), tag).adj() * fermion.G5 * src, ).real def gradient(self, Uprime, dUprime): assert dUprime == Uprime return g.qcd.gauge.project.traceless_hermitian( mat_pg.adj()(src, fermion.G5 * src) ) dfv = df() dfv.assert_gradient_error(rng, U, U, 1e-3, 1e-6) # perform even-odd derivative tests projected_gradient_operators = {"Meooe": "Meooe_projected_gradient"} if tag in projected_gradient_operators and isinstance( fermion, g.qcd.fermion.differentiable_fine_operator ): # Test projected gradient for src_p^dag M^dag M src_p g.message(f"Test projected_gradient of {tag} via src^dag M^dag M src") mat_pg = get_matrix(fermion, projected_gradient_operators[tag]) src_p = g.lattice(fermion.F_grid_eo, fermion.otype) for parity in [g.even, g.odd]: g.pick_checkerboard(parity, src_p, src) dst_p = g(mat * src_p) class df(g.group.differentiable_functional): def __call__(self, Uprime): return g.norm2(get_matrix(fermion.updated(Uprime), tag) * src_p) def gradient(self, Uprime, dUprime): assert dUprime == Uprime R = g.group.cartesian(Uprime) for r, x in zip( R + R, mat_pg(dst_p, src_p) + mat_pg.adj()(src_p, dst_p) ): g.set_checkerboard( r, g.qcd.gauge.project.traceless_hermitian(x) ) return R dfv = df() dfv.assert_gradient_error(rng, U, U, 1e-3, 1e-6) return X
p = { "kappa": 0.13465, "csw_r": 0.0, "csw_t": 0.0, "xi_0": 1, "nu": 1, "isAnisotropic": False, "boundary_phases": [1.0, 1.0, 1.0, 1.0], } M2 = g.qcd.fermion.wilson_clover(U, p) psi = g.vspincolor(M.F_grid) psi_o = g.vspincolor(M.F_grid_eo) rng.normal(psi) g.pick_checkerboard(g.odd, psi_o, psi) inv = g.algorithms.inverter sol = inv.cg({"eps": 1e-10, "maxiter": 1024}) a = g.qcd.pseudofermion.action acts = [] acts += [(a.two_flavor(M, sol), "two_flavor", psi)] acts += [(a.two_flavor_evenodd(M, sol), "two_flavor_evenodd", psi)] acts += [(a.two_flavor_ratio([M, M2], sol), "two_flavor_ratio", psi)] acts += [( a.two_flavor_ratio_evenodd_schur([M, M2], sol), "two_flavor_ratio_evenodd_schur", psi_o, )]