[docs]classPotential(torch.nn.Module):r""" Base interface for a pair potential energy function between monopoles. The class provides the interface to compute a short-range and long-range functions in real space (such that :math:`V(r)=V_{\mathrm{SR}}(r)+V_{\mathrm{LR}}(r)` ), as well as a reciprocal-space version of the long-range component :math:`\hat{V}_{\mathrm{LR}}(k))` ). Derived classes can decide to implement a subset of these functionalities (e.g. providing only the real-space potential :math:`V(r)`). Internal state variables and parameters in derived classes should be defined in the ``__init__`` method. This base class also provides parameters to set the length scale associated with the range separation (``smearing``), and a cutoff function that can be optionally set to zero out the potential *inside* a short-range ``exclusion_radius``. This is often useful when combining ``torch-pme``-based ML models with local models that are better suited to describe the structure within a local cutoff. Note that a :class:`Potential` class can also be used inside a :class:`KSpaceFilter`, see :func:`Potential.kernel_from_k_sq`. :param smearing: The length scale associated with the switching between :math:`V_{\mathrm{SR}}(r)` and :math:`V_{\mathrm{LR}}(r)` :param exclusion_radius: A length scale that defines a *local environment* within which the potential should be smoothly zeroed out, as it will be described by a separate model. """def__init__(self,smearing:Optional[float]=None,exclusion_radius:Optional[float]=None,):super().__init__()ifsmearingisnotNone:self.register_buffer("smearing",torch.tensor(smearing,dtype=torch.float64))else:self.smearing=Noneself.exclusion_radius=exclusion_radius
[docs]@torch.jit.exportdeff_cutoff(self,dist:torch.Tensor)->torch.Tensor:r""" Default cutoff function defining the *local* region that should be excluded from the computation of a long-range model. Defaults to a shifted cosine :math:`(1+\cos \pi r/r_\mathrm{cut})/2`. :param dist: a torc.Tensor containing the interatomic distances over which the cutoff function should be computed. """ifself.exclusion_radiusisNone:raiseValueError("Cannot compute cutoff function when `exclusion_radius` is not set")returntorch.where(dist<self.exclusion_radius,(1+torch.cos(dist*(torch.pi/self.exclusion_radius)))*0.5,0.0,)
[docs]@torch.jit.exportdeffrom_dist(self,dist:torch.Tensor)->torch.Tensor:""" Computes a pair potential given a tensor of interatomic distances. :param dist: torch.tensor containing the distances at which the potential is to be evaluated. """raiseNotImplementedError(f"from_dist is not implemented for {self.__class__.__name__}")
[docs]@torch.jit.exportdefsr_from_dist(self,dist:torch.Tensor)->torch.Tensor:r""" Short-range (SR) part of the pair potential in real space. Even though one can provide a custom version, this is usually evaluated as :math:`V_{\mathrm{SR}}(r)=V(r)-V_{\mathrm{LR}}(r)`, based on the full and long-range parts of the potential. If the parameter ``exclusion_radius`` is defined, it computes this part as :math:`V_{\mathrm{SR}}(r)=-V_{\mathrm{LR}}(r)*f_\mathrm{cut}(r)` so that, when added to the part of the potential computed in the Fourier domain, the potential within the local region goes smoothly to zero. :param dist: torch.tensor containing the distances at which the potential is to be evaluated. """ifself.smearingisNone:raiseValueError("Cannot compute range-separated potential when `smearing` is not specified.")ifself.exclusion_radiusisNone:returnself.from_dist(dist)-self.lr_from_dist(dist)return-self.lr_from_dist(dist)*self.f_cutoff(dist)
[docs]@torch.jit.exportdeflr_from_dist(self,dist:torch.Tensor)->torch.Tensor:r""" Computes the long-range part of the pair potential :math:`V_\mathrm{LR}(r)`. in real space, given a tensor of interatomic distances. :param dist: torch.tensor containing the distances at which the potential is to be evaluated. """raiseNotImplementedError(f"lr_from_dist is not implemented for {self.__class__.__name__}")
[docs]@torch.jit.exportdeflr_from_k_sq(self,k_sq:torch.Tensor)->torch.Tensor:r""" Computes the Fourier-domain version of the long-range part of the pair potential :math:`\hat{V}_\mathrm{LR}(k)`. The function is expressed in terms of :math:`k^2`, as that avoids, in several important cases, an unnecessary square root operation. :param k_sq: torch.tensor containing the squared norm of the Fourier domain vectors at which :math:`\hat{V}_\mathrm{LR}` must be evaluated. """raiseNotImplementedError(f"lr_from_k_sq is not implemented for {self.__class__.__name__}")
[docs]@torch.jit.exportdefkernel_from_k_sq(self,k_sq:torch.Tensor)->torch.Tensor:""" Compatibility function with the interface of :class:`KSpaceKernel`, so that potentials can be used as kernels for :class:`KSpaceFilter`. """returnself.lr_from_k_sq(k_sq)
[docs]@torch.jit.exportdefself_contribution(self)->torch.Tensor:""" A correction that depends exclusively on the "charge" on every particle and on the range splitting parameter. Foe example, in the case of a Coulomb potential, this is the potential generated at the origin by the fictituous Gaussian charge density in order to split the potential into a SR and LR part. """raiseNotImplementedError(f"self_contribution is not implemented for {self.__class__.__name__}")
[docs]@torch.jit.exportdefbackground_correction(self)->torch.Tensor:""" A correction designed to compensate for the presence of divergent terms. For instance, the energy of a periodic electrostatic system is infinite when the cell is not charge-neutral. This term then implicitly assumes that a homogeneous background charge of the opposite sign is present to make the cell neutral. """raiseNotImplementedError(f"background_correction is not implemented for {self.__class__.__name__}")