Source code for tdg.LegoSphere

#!/usr/bin/env python3

import torch
from tdg.h5 import H5able

[docs]class LegoSphere(H5able): r''' Translationally-invariant potentials in the :math:`A_1` representations of the lattice :math:`D_4` symmetry can be written as a sum of LegoSpheres, .. math:: \begin{align} \tilde{V}_{a,a+r} &= \tilde{V}_{0,r} & \tilde{V}_{0,r} &= \mathcal{V} \sum_R \tilde{C}_R \mathcal{S}^R_{0,r} \end{align} where each LegoSphere :math:`\mathcal{S}` has a radius :math:`R`. To be in the :math:`A_1` representation each LegoSphere is a uniformly-weighted stencil with no phases, .. math:: \begin{align} \mathcal{S}^R_{0,r} &= \frac{1}{\mathcal{N}_R^2} \sum_{g\in D_4} \delta_{r,gR} & \mathcal{S}^R_{ab} &= \frac{1}{\mathcal{N}_R^2} \sum_{g\in D_4} \delta_{b-a,gR} \end{align} where :math:`g` acts to rotate spatial displacements on the lattice. Parameters ---------- r: list or tuple the radius given as a vector ``[x, y]``. The magnitude is insufficient information, because two radii with the same magnitude might yield different LegoSpheres (consider ``[3, 4]`` and ``[0, 5]``, for example). c: float or a torch.tensor-wrapped number the Wilson coefficient :math:`\tilde{C}_R`. LegoSpheres may be multiplied by coefficients on either side to give new LegoSpheres with c changed appropriately, >>> sphere = LegoSphere([0,1], 1.23) >>> stronger = 2*sphere >>> stronger.c tensor(2.4600) ''' def __init__(self, r, c=1): x = r[0] y = r[1] self.r = torch.tensor([x, y]) # Precompute the D4-symmetric set of points. # Use the set built-in to eliminate duplicates. if x ==0 and y==0: self.points = torch.tensor([[0,0]]) elif x == 0: self.points = torch.tensor([ [+x,+y], [+x,-y], [+y,+x], [-y,+x] ]) elif x == y: self.points = torch.tensor([ [+x,+y], [+x,-y], [-x,+y], [-x,-y], ]) else: self.points = torch.tensor([ [+x,+y], [+x,-y], [-x,+y], [-x,-y], [+y,+x], [+y,-x], [-y,+x], [-y,-x], ]) # The canonical normalization is 1/(the number of points) self.norm = 1./len(self.points) self.c = torch.tensor(1) * c def __str__(self): return f'LegoSphere({self.r}, {self.c})' def __repr__(self): return str(self)
[docs] def spatial(self, Lattice): r''' Parameters ---------- lattice: tdg.Lattice a spatial lattice on which to construct :math:`\tilde{C}_R \mathcal{S}^R_{ab}` Returns ------- torch.tensor: a square matrix of dimension ``[lattice.sites, lattice.sites]`` where the first index is the superindex :math:`a` and the second index is the superindex :math:`b`. ''' S = torch.zeros(Lattice.sites, Lattice.sites) for i,x in enumerate(Lattice.coordinates): for j,y in enumerate(Lattice.coordinates): for p in self.points: if Lattice.distance_squared(x-y, p) == 0: S[i,j] += self.c * self.norm return S
def __mul__(self, c): return LegoSphere(self.r, self.c * c) __rmul__ = __mul__
if __name__ == "__main__": import doctest doctest.testmod()