Exemple #1
0
 def covDeriv(self, scalarField, gaugeField, cpt):
     scalarFieldShifted = self.shiftScalarField(scalarField, cpt, +1)
     lieAlgField = scalarField * FieldTools.pauliMatrix(3)
     lieAlgFieldShifted = scalarFieldShifted * FieldTools.pauliMatrix(3)
     covDeriv = gaugeField[:,:,:,cpt,:,:] @ lieAlgFieldShifted @\
         tf.linalg.adjoint(gaugeField[:,:,:,cpt,:,:]) - lieAlgField
     return covDeriv
def interp1d(scalarField, gaugeField, axis, theory):
    inputLatShape = tf.shape(scalarField)[0:3]
    outputLatShape = inputLatShape
    outputLatShape = tf.tensor_scatter_nd_update(outputLatShape, [[axis]], [2*outputLatShape[axis]])

    outputScalarField = tf.zeros(tf.concat([outputLatShape, [1, 1]], 0), dtype=tf.complex128)
    outputGaugeField = tf.zeros(tf.concat([outputLatShape, [3, 2, 2]], 0), dtype=tf.complex128)

    inputIndexVectors = [tf.range(inputLatShape[0]), tf.range(inputLatShape[1]), tf.range(inputLatShape[2])]
    inputIndices = tf.stack(tf.meshgrid(inputIndexVectors[0], inputIndexVectors[1], inputIndexVectors[2], indexing="ij"), -1)

    outputIndexVectorsOdd = inputIndexVectors.copy()
    outputIndexVectorsOdd[axis] = 2*inputIndexVectors[axis] + 1
    outputIndicesOdd = tf.stack(tf.meshgrid(outputIndexVectorsOdd[0], outputIndexVectorsOdd[1], outputIndexVectorsOdd[2], indexing="ij"), -1)
    originalScalarVals = tf.gather_nd(scalarField, inputIndices)
    originalGaugeVals = tf.gather_nd(gaugeField, inputIndices)
    outputScalarField = tf.tensor_scatter_nd_update(outputScalarField, outputIndicesOdd, originalScalarVals)
    outputGaugeField = tf.tensor_scatter_nd_update(outputGaugeField, outputIndicesOdd, originalGaugeVals)

    scalarFieldShifted = theory.shiftScalarField(scalarField, axis, -1)
    gaugeFieldShifted = theory.shiftGaugeField(gaugeField, axis, -1)
    avgScalarField = 0.5*(scalarField + scalarFieldShifted)
    avgGaugeField = FieldTools.linearAverage(gaugeField, gaugeFieldShifted)

    interpScalarVals = tf.gather_nd(avgScalarField, inputIndices)
    interpGaugeVals = tf.gather_nd(avgGaugeField, inputIndices)
    outputIndexVectorsEven = inputIndexVectors.copy()
    outputIndexVectorsEven[axis] = 2*inputIndexVectors[axis]
    outputIndicesEven = tf.stack(tf.meshgrid(outputIndexVectorsEven[0], outputIndexVectorsEven[1], outputIndexVectorsEven[2], indexing="ij"), -1)
    outputScalarField = tf.tensor_scatter_nd_update(outputScalarField, outputIndicesEven, interpScalarVals)
    outputGaugeField = tf.tensor_scatter_nd_update(outputGaugeField, outputIndicesEven, interpGaugeVals)

    return outputScalarField, outputGaugeField
    def shiftPlaquette(self, plaquette, plaqDir1, plaqDir2, shiftDir, sign):
        # Moving one site forwards is equivalent to shifting the whole field
        # backwards, hence the minus sign (active/passive transform)
        plaquetteShifted = tf.roll(plaquette, -sign, shiftDir)

        if shiftDir != 0:
            return plaquetteShifted

        indices = FieldTools.boundaryIndices(self.latShape, shiftDir, sign)

        if sign == -1 and (plaqDir1 == 0 or plaqDir2 == 0):
            # Set the plaquettes straddling the origin to the identity
            updates = tf.eye(2,
                             batch_shape=tf.shape(indices)[0:-1],
                             dtype=tf.complex128)
            plaquetteShifted = tf.tensor_scatter_nd_update(
                plaquetteShifted, indices, updates)
        else:
            # Apply reflecting BC's by setting links at the boundary to
            # corresponding values from unshifted field
            updates = tf.gather_nd(plaquette, indices)
            plaquetteShifted = tf.tensor_scatter_nd_update(
                plaquetteShifted, indices, updates)

        return plaquetteShifted
    def shiftGaugeField(self, gaugeField, cpt, sign):
        gaugeFieldShifted = tf.roll(gaugeField, -sign, cpt)

        pauliMatNum = self.boundaryConditions[cpt]

        if pauliMatNum == 0:
            return gaugeFieldShifted

        latShape = tf.shape(gaugeField)[0:3]
        indices = FieldTools.boundaryIndices(latShape, cpt, sign)

        updates = tf.gather_nd(gaugeFieldShifted, indices)
        updates = FieldTools.pauliMatrix(pauliMatNum) @\
            updates @ FieldTools.pauliMatrix(pauliMatNum)

        gaugeFieldShifted = tf.tensor_scatter_nd_update(
            gaugeFieldShifted, indices, updates)
        return gaugeFieldShifted
    def processGradients(self, grads, fields):
        processedGrads = grads

        processedGrads[0] = grads[0] / (2 * np.pi * tf.cast(
            tf.reshape(self.metric, tf.concat([self.latShape, [1, 1]], 0)),
            tf.complex128))
        processedGrads[1] = FieldTools.projectSu2Gradients(grads[1], fields[1])
        processedGrads[1] = processedGrads[1] / (2 * np.pi * tf.cast(
            tf.reshape(self.metric, tf.concat([self.latShape, [1, 1, 1]], 0)),
            tf.complex128))

        return processedGrads
    def shiftGaugeField(self, gaugeField, cpt, sign):
        # Moving one site forwards is equivalent to shifting the whole field
        # backwards, hence the minus sign (active/passive transform)
        gaugeFieldShifted = tf.roll(gaugeField, -sign, cpt)

        if cpt != 0:
            return gaugeFieldShifted

        # Apply reflecting BC's by setting links at the boundary to
        # corresponding values from unshifted field
        if sign == +1:
            slicePos = self.latShape[cpt] - 2
        else:
            slicePos = 1
        # For gathering from the shifted field (gathering from the variable is slow)
        indices = FieldTools.sliceIndices(self.latShape, cpt, slicePos)
        # For scattering onto the boundary
        boundaryIndices = FieldTools.boundaryIndices(self.latShape, cpt, sign)
        updates = tf.gather_nd(gaugeFieldShifted, indices)
        boundaryUpdates = tf.gather_nd(gaugeField, boundaryIndices)

        gaugeFieldShifted = tf.tensor_scatter_nd_update(
            gaugeFieldShifted, boundaryIndices, updates)

        if sign == -1:
            # Set the r-links at the origin to the identity
            rOriginIndices = tf.stack(
                tf.meshgrid(0,
                            tf.range(self.latShape[1]),
                            tf.range(self.latShape[2]),
                            0,
                            indexing="ij"), -1)
            rOriginUpdates = tf.eye(2,
                                    batch_shape=tf.shape(rOriginIndices)[0:-1],
                                    dtype=tf.complex128)
            gaugeFieldShifted = tf.tensor_scatter_nd_update(
                gaugeFieldShifted, rOriginIndices, rOriginUpdates)

        return gaugeFieldShifted
    def shiftScalarField(self, scalarField, cpt, sign):
        # Moving one site forwards is equivalent to shifting the whole field
        # backwards, hence the minus sign (active/passive transform)
        scalarFieldShifted = tf.roll(scalarField, -sign, cpt)

        if cpt != 0:
            return scalarFieldShifted

        # Apply reflecting BC's by setting links at the boundary to
        # corresponding values from unshifted field
        if sign == +1:
            slicePos = self.latShape[cpt] - 2
        else:
            slicePos = 1
        # For gathering from the shifted field (gathering from the variable is slow)
        indices = FieldTools.sliceIndices(self.latShape, cpt, slicePos)
        # For scattering onto the boundary
        boundaryIndices = FieldTools.boundaryIndices(self.latShape, cpt, sign)
        updates = tf.gather_nd(scalarFieldShifted, indices)
        scalarFieldShifted = tf.tensor_scatter_nd_update(
            scalarFieldShifted, boundaryIndices, updates)

        return scalarFieldShifted
Exemple #8
0
    def shiftScalarField(self, scalarField, cpt, sign):
        scalarFieldShifted = tf.roll(scalarField, -sign, cpt)

        pauliMatNum = self.boundaryConditions[cpt]

        # Only requires flipping if third pauli matrix is used
        if pauliMatNum != 3:
            return scalarFieldShifted

        latShape = tf.shape(scalarField)[0:-2]
        indices = FieldTools.boundaryIndices(latShape, cpt, +1)
        updates = -1.0 * tf.gather_nd(scalarFieldShifted, indices)

        scalarFieldShifted = tf.tensor_scatter_nd_update(
            scalarFieldShifted, indices, updates)

        return scalarFieldShifted
    def shiftCovDeriv(self, covDeriv, cpt, sign):
        covDerivShifted = tf.roll(covDeriv, -sign, cpt)

        if cpt != 0:
            return covDerivShifted

        indices = FieldTools.boundaryIndices(self.latShape, cpt, sign)

        if sign == -1:
            updates = tf.zeros(tf.concat([tf.shape(indices)[0:-1], [2, 2]], 0),
                               dtype=tf.complex128)
        else:
            updates = tf.gather_nd(covDeriv, indices)

        covDerivShifted = tf.tensor_scatter_nd_update(covDerivShifted, indices,
                                                      updates)

        return covDerivShifted
    def covDerivTerm(self, higgsField, isospinField, hyperchargeField):
        energyDensity = tf.zeros(tf.shape(higgsField)[0:3], dtype=tf.float64)
        higgsMagnitude = tf.linalg.trace(
            self.higgsMagnitude(tf.math.real(higgsField)))
        numDims = 3

        # This is only valid in the unitary gauge, but it keeps the isospin
        # gradients symmetric which is good for convergence to the saddle
        for ii in range(numDims):
            higgsFieldShifted = self.shiftHiggsField(higgsField, ii, +1)
            higgsMagnitudeShifted = tf.linalg.trace(
                self.higgsMagnitude(tf.math.real(higgsFieldShifted)))
            energyDensity += higgsMagnitude**2
            energyDensity += higgsMagnitudeShifted**2
            energyDensity -= higgsMagnitude * higgsMagnitudeShifted *\
                tf.math.real(tf.linalg.trace(isospinField[:,:,:,ii,:,:])) *\
                tf.math.real(tf.linalg.trace(hyperchargeField[:,:,:,ii,:,:]))
            energyDensity += higgsMagnitude * higgsMagnitudeShifted *\
                tf.math.imag(tf.linalg.trace(isospinField[:,:,:,ii,:,:] @\
                FieldTools.pauliMatrix(3))) *\
                tf.math.imag(tf.linalg.trace(hyperchargeField[:,:,:,ii,:,:]))

        return energyDensity
Exemple #11
0
# Shift the poles around, obeying the BCs
leftGaugeField = inputGaugeField
leftScalarField = inputScalarField
rightGaugeField = inputGaugeField
rightScalarField = inputScalarField
for ii in range(shiftNumLeft):
    leftGaugeField = singlePoleTheory.shiftGaugeField(leftGaugeField, 0, +1)
    leftScalarField = singlePoleTheory.shiftScalarField(leftScalarField, 0, +1)

# Because shiftNumRight > monopoleXCoord, the monopole ends up conjugated
for ii in range(shiftNumRight):
    rightGaugeField = singlePoleTheory.shiftGaugeField(rightGaugeField, 0, +1)
    rightScalarField = singlePoleTheory.shiftScalarField(
        rightScalarField, 0, +1)

gaugeField = FieldTools.linearSuperpose(leftGaugeField, rightGaugeField)
scalarField = 0.5 * (leftScalarField + rightScalarField)

# Shift once more to centre the pair
gaugeField = tf.roll(gaugeField, -1, 0)
scalarField = tf.roll(scalarField, -1, 0)

numFluxQuanta = args.externalField
# Negative flux quanta results in lowering of energy (dipole points along
# negative x axis)
magField = FieldTools.constantMagneticField(X, Y, Z, 0, -numFluxQuanta)
gaugeField = FieldTools.linearSuperpose(gaugeField, magField)

gaugeFieldVar = tf.Variable(gaugeField, trainable=True)
scalarFieldVar = tf.Variable(scalarField, trainable=True)
    def processGradients(self, grads, fields):
        processedGrads = grads
        processedGrads[1] = FieldTools.projectSu2Gradients(grads[1], fields[1])

        return processedGrads
Exemple #13
0
gaugeVec0 = tf.zeros([Nx, Ny, Nz, 3], dtype=tf.float64).numpy()
gaugeVec1 = tf.zeros([Nx, Ny, Nz, 3], dtype=tf.float64).numpy()
gaugeVec2 = tf.zeros([Nx, Ny, Nz, 3], dtype=tf.float64).numpy()

# Symmetric perturbation in the centre of the lattice
gaugeVec1[Nx//2, Ny//2, Nz//2, 0] += 0.01
gaugeVec1[Nx//2 + 1, Ny//2, Nz//2, 0] += 0.01
gaugeVec1[Nx//2, Ny//2, Nz//2 + 1, 0] += 0.01
gaugeVec1[Nx//2 + 1, Ny//2, Nz//2 + 1, 0] += 0.01

gaugeVec2[Nx//2, Ny//2, Nz//2, 1] += 0.01
gaugeVec2[Nx//2 + 1, Ny//2, Nz//2, 1] -= 0.01
gaugeVec2[Nx//2, Ny//2 + 1, Nz//2, 1] += 0.01
gaugeVec2[Nx//2 + 1, Ny//2 + 1, Nz//2, 1] -= 0.01

gaugeMat0 = FieldTools.vecToSu2(gaugeVec0)
gaugeMat1 = FieldTools.vecToSu2(gaugeVec1)
gaugeMat2 = FieldTools.vecToSu2(gaugeVec2)

gaugeMat = tf.stack([gaugeMat0, gaugeMat1, gaugeMat2], -3)

# Convert to tf Variables so gradients can be tracked
scalarField = tf.Variable(scalarMat, trainable=True)
gaugeField = tf.Variable(gaugeMat, trainable=True)

theory = GeorgiGlashowSu2TheoryUnitary(params)

@tf.function
def lossFn():
    return theory.energy(scalarField, gaugeField)
energy = lossFn()
    avgScalarField = 0.5*(scalarField + scalarFieldShifted)
    avgGaugeField = FieldTools.linearAverage(gaugeField, gaugeFieldShifted)

    interpScalarVals = tf.gather_nd(avgScalarField, inputIndices)
    interpGaugeVals = tf.gather_nd(avgGaugeField, inputIndices)
    outputIndexVectorsEven = inputIndexVectors.copy()
    outputIndexVectorsEven[axis] = 2*inputIndexVectors[axis]
    outputIndicesEven = tf.stack(tf.meshgrid(outputIndexVectorsEven[0], outputIndexVectorsEven[1], outputIndexVectorsEven[2], indexing="ij"), -1)
    outputScalarField = tf.tensor_scatter_nd_update(outputScalarField, outputIndicesEven, interpScalarVals)
    outputGaugeField = tf.tensor_scatter_nd_update(outputGaugeField, outputIndicesEven, interpGaugeVals)

    return outputScalarField, outputGaugeField

B = 9
smallMagneticField = FieldTools.constantMagneticField(
    inputR, inputY, inputZ, 0, -B
    )
inputGaugeField = FieldTools.linearSuperpose(
    inputGaugeField, smallMagneticField
    )

outputScalarField, outputGaugeField = interp1d(inputScalarField, inputGaugeField, 0, theory)
outputScalarField, outputGaugeField = interp1d(outputScalarField, outputGaugeField, 1, theory)
outputScalarField, outputGaugeField = interp1d(outputScalarField, outputGaugeField, 2, theory)

outputLatShape = tf.shape(outputScalarField)[0:3]
outputParams = inputParams
outputParams["vev"] /= 2
outputParams["latShape"] = outputLatShape

r = tf.cast(
y = tf.cast(tf.linspace(-(Ny - 1) / 2, (Ny - 1) / 2, Ny), tf.float64)
z = tf.cast(tf.linspace(-(Nz - 1) / 2, (Nz - 1) / 2, Nz), tf.float64)

X, Y, Z = tf.meshgrid(x, y, z, indexing="ij")

# Theory parameters
params = {
    "vev": args.vev,
    "selfCoupling": args.selfCoupling,
    "gaugeCoupling": args.gaugeCoupling
}

# Set up the initial scalar and gauge fields
inputPath = args.inputPath
if inputPath == "":
    scalarField, gaugeField = FieldTools.setMonopoleInitialConditions(
        X, Y, Z, params["vev"])
else:
    scalarField = np.load(inputPath + "/scalarField.npy")
    gaugeField = np.load(inputPath + "/gaugeField.npy")

# Convert to tf Variables so gradients can be tracked
scalarFieldVar = tf.Variable(scalarField, trainable=True)
gaugeFieldVar = tf.Variable(gaugeField, trainable=True)

theory = GeorgiGlashowSu2Theory(params)


@tf.function
def lossFn():
    return theory.energy(scalarFieldVar, gaugeFieldVar)
Exemple #16
0
inputGaugeField = np.load(inputPath + "/gaugeField.npy", allow_pickle=True)
inputParams = np.load(inputPath + "/params.npy", allow_pickle=True).item()

# Halve the lattice and field size
inputShape = tf.shape(inputX)
R = inputX[int(inputShape[0]) // 2:, ...]
Y = inputY[int(inputShape[0]) // 2:, ...]
Z = inputZ[int(inputShape[0]) // 2:, ...]
latShape = tf.shape(R)

scalarField = inputScalarField[int(inputShape[0]) // 2:, ...]
gaugeField = inputGaugeField[int(inputShape[0]) // 2:, ...]

# Add magnetic field if required
numFluxQuanta = args.externalField
magField = FieldTools.constantMagneticField(R, Y, Z, 0, numFluxQuanta)
gaugeField = FieldTools.linearSuperpose(gaugeField, magField)

# Theory parameters
params = {
    "vev": args.vev,
    "selfCoupling": args.selfCoupling,
    "gaugeCoupling": args.gaugeCoupling,
    "latShape": latShape
}

theory = GeorgiGlashowRadialTheory(params)

scalarFieldVar = tf.Variable(scalarField)
gaugeFieldVar = tf.Variable(gaugeField)