How to implement new gauge fields
It is easy to implement new gauge fields with different internal structures or different parallel computations.
AbstractGaugefields and interfaces
All types of gauge fields belong AbstractGaugefields{NC,Dim}.
The concrete types for gauge fields should have following functions.
LinearAlgebra.mul!(c::T,a::T1,b::T2) where {T<: AbstractGaugefields,T1 <: Abstractfields,T2 <: Abstractfields}LinearAlgebra.mul!(c::T,a::N,b::T2) where {T<: AbstractGaugefields,N <: Number ,T2 <: Abstractfields}LinearAlgebra.mul!(c::T,a::T1,b::T2,α::Ta,β::Tb) where {T<: AbstractGaugefields,T1 <: Abstractfields,T2 <: Abstractfields,Ta <: Number, Tb <: Number}substitute_U!(a::Array{T1,1},b::Array{T2,1}) where {T1 <: AbstractGaugefields,T2 <: AbstractGaugefields}Base.similar(U::T) where T <: AbstractGaugefieldsclear_U!(U::T) where T <: AbstractGaugefieldsset_wing_U!(U::T) where T <: AbstractGaugefieldsBase.size(U::T) where T <: AbstractGaugefieldsadd_U!(c::T,a::T1) where {T<: AbstractGaugefields,T1 <: Abstractfields}add_U!(c::T,α::N,a::T1) where {T<: AbstractGaugefields,T1 <: Abstractfields, N<:Number}LinearAlgebra.tr(a::T) where T<: AbstractfieldsLinearAlgebra.tr(a::T,b::T) where T<: AbstractfieldsBase.setindex!(x::Gaugefields_4D_wing,v,i1,i2,i3,i4,i5,i6)Base.getindex(x::Gaugefields_4D_wing,i1,i2,i3,i4,i5,i6)
matrix-field matrix-field product
LinearAlgebra.mul!(c::T,a::T1,b::T2) where {T<: AbstractGaugefields,T1 <: Abstractfields,T2 <: Abstractfields}
This calculates the matrix-matrix multiplicaetion on each lattice site.
As a mathematical expression, for matrix-valued fields $A(n), B(n)$, we define "matrix-field matrix-field product" as,
\[[A(n)B(n)]_{ij} = \sum_k [A(n)]_{ik} [B(n)]_{kj}\]
for all site index n.
In our package, this is expressed as,
mul!(C,A,B)which means C = A*B on each lattice site. Here $A, B, C$ are same type of $u$.
Several ways to treat periodic boundary.
There are several ways to treat periodic boundary. Now, there are two kinds of methods, halo updates and direct-shift method.
- halo updates: wing-buffer (so-called halo) type implementations for gauge fields. In this type, there are additional halo sites. If
NDW > 0is set, this update is used. - direct-shift method: In
shift_U!function, the data is copied. IfNDW = 0is set, this update is used.
Therefore, the important functions are
set_wing_U!: This is used in halo updates, but not used in direct-shift method (returns nothing).shift_U!: In this function, the data is copied in direct-shift method. This is the lazy evaluation in halo updates.
halo updates
There is a wing-buffer (so-called halo) type implementations for gauge fields. In this type, there are additional halo sites. set_wing_U! function is used for updating halo sites. If you do not want to use halo type implementations for gauge fields, you can write set_wing_U!(U::Yourtype) = nothing.
examples
We have two kinds of $SU(N)$ gauge fields in four dimension.
Serial version:
Gaugefields.AbstractGaugefields_module.Gaugefields_4D_wing — TypeGaugefields_4D_wing{NC} <: Gaugefields_4D{NC}`
SU(N) Gauge fields in four dimensional lattice.
struct Gaugefields_4D_wing{NC} <: Gaugefields_4D{NC}
U::Array{ComplexF64,6}
NX::Int64
NY::Int64
NZ::Int64
NT::Int64
NDW::Int64
NV::Int64
NC::Int64
mpi::Bool
verbose_print::Verbose_print
function Gaugefields_4D_wing(NC::T,NDW::T,NX::T,NY::T,NZ::T,NT::T;verbose_level = 2) where T<: Integer
NV = NX*NY*NZ*NT
U = zeros(ComplexF64,NC,NC,NX+2NDW,NY+2NDW,NZ+2NDW,NT+2NDW)
mpi = false
verbose_print = Verbose_print(verbose_level )
#U = Array{Array{ComplexF64,6}}(undef,4)
#for μ=1:4
# U[μ] = zeros(ComplexF64,NC,NC,NX+2NDW,NY+2NDW,NZ+2NDW,NT+2NDW)
#end
return new{NC}(U,NX,NY,NZ,NT,NDW,NV,NC,mpi,verbose_print)
end
endUsually, we do not consider local SU(N) matrix on each lattice bond. The gauge fields are manupulated like
mul!(C,A,B)
s = tr(C)Details of mul! and tr depends on the gauge field type that we use. In other words, the details which depends on kinds of gauge fields are only in the definitions of mul! or tr. So, we implement kind-dependent mul! like
function LinearAlgebra.mul!(c::Gaugefields_4D_wing{NC},a::T1,b::T2) where {NC,T1 <: Abstractfields,T2 <: Abstractfields}
@assert NC != 2 && NC != 3 "This function is for NC != 2,3"
NT = c.NT
NZ = c.NZ
NY = c.NY
NX = c.NX
@inbounds for it=1:NT
for iz=1:NZ
for iy=1:NY
for ix=1:NX
for k2=1:NC
for k1=1:NC
c[k1,k2,ix,iy,iz,it] = 0
@simd for k3=1:NC
c[k1,k2,ix,iy,iz,it] += a[k1,k3,ix,iy,iz,it]*b[k3,k2,ix,iy,iz,it]
end
end
end
end
end
end
end
set_wing_U!(c)
endIf we want to use MPI parallel computations, we use diffrent type of gauge fields. The definition is
struct Gaugefields_4D_wing_mpi{NC} <: Gaugefields_4D{NC}
U::Array{ComplexF64,6}
NX::Int64
NY::Int64
NZ::Int64
NT::Int64
NDW::Int64
NV::Int64
NC::Int64
PEs::NTuple{4,Int64}
PN::NTuple{4,Int64}
mpiinit::Bool
myrank::Int64
nprocs::Int64
myrank_xyzt::NTuple{4,Int64}
mpi::Bool
verbose_print::Verbose_print
function Gaugefields_4D_wing_mpi(NC::T,NDW::T,NX::T,NY::T,NZ::T,NT::T,PEs;mpiinit=true,
verbose_level = 2) where T<: Integer
NV = NX*NY*NZ*NT
@assert NX % PEs[1] == 0 "NX % PEs[1] should be 0. Now NX = $NX and PEs = $PEs"
@assert NY % PEs[2] == 0 "NY % PEs[2] should be 0. Now NY = $NY and PEs = $PEs"
@assert NZ % PEs[3] == 0 "NZ % PEs[3] should be 0. Now NZ = $NZ and PEs = $PEs"
@assert NT % PEs[4] == 0 "NT % PEs[4] should be 0. Now NT = $NT and PEs = $PEs"
PN = (NX ÷ PEs[1],
NY ÷ PEs[2],
NZ ÷ PEs[3],
NT ÷ PEs[4],
)
if mpiinit == false
MPI.Init()
mpiinit = true
end
comm = MPI.COMM_WORLD
nprocs = MPI.Comm_size(comm)
@assert prod(PEs) == nprocs "num. of MPI process should be prod(PEs). Now nprocs = $nprocs and PEs = $PEs"
myrank = MPI.Comm_rank(comm)
verbose_print = Verbose_print(verbose_level,myid = myrank)
myrank_xyzt = get_myrank_xyzt(myrank,PEs)
#println("Hello world, I am $(MPI.Comm_rank(comm)) of $(MPI.Comm_size(comm))")
U = zeros(ComplexF64,NC,NC,PN[1]+2NDW,PN[2]+2NDW,PN[3]+2NDW,PN[4]+2NDW)
#U = Array{Array{ComplexF64,6}}(undef,4)
#for μ=1:4
# U[μ] = zeros(ComplexF64,NC,NC,NX+2NDW,NY+2NDW,NZ+2NDW,NT+2NDW)
#end
mpi = true
return new{NC}(U,NX,NY,NZ,NT,NDW,NV,NC,Tuple(PEs),PN,mpiinit,myrank,nprocs,myrank_xyzt,mpi,verbose_print)
end
endIts mul! is implemented as
function LinearAlgebra.mul!(c::Gaugefields_4D_wing_mpi{NC},a::T1,b::T2) where {NC,T1 <: Abstractfields,T2 <: Abstractfields}
@assert NC != 2 && NC != 3 "This function is for NC != 2,3"
NT = c.NT
NZ = c.NZ
NY = c.NY
NX = c.NX
PN = c.PN
for it=1:PN[4]
for iz=1:PN[3]
for iy=1:PN[2]
for ix=1:PN[1]
for k2=1:NC
for k1=1:NC
v = 0
setvalue!(c,v,k1,k2,ix,iy,iz,it)
#c[k1,k2,ix,iy,iz,it] = 0
@simd for k3=1:NC
vc = getvalue(c,k1,k2,ix,iy,iz,it) + getvalue(a,k1,k3,ix,iy,iz,it)*getvalue(b,k3,k2,ix,iy,iz,it)
setvalue!(c,vc,k1,k2,ix,iy,iz,it)
#c[k1,k2,ix,iy,iz,it] += a[k1,k3,ix,iy,iz,it]*b[k3,k2,ix,iy,iz,it]
end
end
end
end
end
end
end
#set_wing_U!(c)
end