示例#1
0
    def __init__(self, radgrid: RadialGrid, prec: int) -> None:
        self._dtype = radgrid.dtype
        self._device = radgrid.device

        assert (prec % 2 == 1) and (3 <= prec <= 131),\
            "Precision must be an odd number between 3 and 131"

        # load the Lebedev grid points
        lebedev_dsets = torch.tensor(LebedevLoader.load(prec),
                                     dtype=self._dtype,
                                     device=self._device)
        wphitheta = lebedev_dsets[:, -1]  # (nphitheta)
        phi = lebedev_dsets[:, 0]
        theta = lebedev_dsets[:, 1]

        # get the radial grid
        assert radgrid.coord_type == "radial"
        r = radgrid.get_rgrid().unsqueeze(-1)  # (nr, 1)

        # get the cartesian coordinate
        rsintheta = r * torch.sin(theta)
        x = (rsintheta * torch.cos(phi)).view(-1, 1)  # (nr * nphitheta, 1)
        y = (rsintheta * torch.sin(phi)).view(-1, 1)
        z = (r * torch.cos(theta)).view(-1, 1)
        xyz = torch.cat((x, y, z), dim=-1)  # (nr * nphitheta, ndim)
        self._xyz = xyz

        # calculate the dvolume (integration weights)
        dvol_rad = radgrid.get_dvolume().unsqueeze(-1)  # (nr, 1)
        self._dvolume = (dvol_rad * wphitheta).view(-1)  # (nr * nphitheta)
示例#2
0
def test_radial_grid_dvol(grid_integrator, grid_transform):
    ngrid = 40
    dtype = torch.float64
    radgrid = RadialGrid(ngrid, grid_integrator, grid_transform, dtype=dtype)

    dvol = radgrid.get_dvolume()  # (ngrid,)
    rgrid = radgrid.get_rgrid()  # (ngrid, ndim)
    r = rgrid[:, 0]

    # test gaussian integration
    fcn = torch.exp(-r * r * 0.5)  # (ngrid,)
    int1 = (fcn * dvol).sum()
    val1 = 2 * np.sqrt(2 * np.pi) * np.pi
    assert torch.allclose(int1, int1 * 0 + val1)
示例#3
0
def get_atomic_grid(grid_inp: Union[int, str],
                    atomz: int,
                    dtype: torch.dtype = _dtype,
                    device: torch.device = _device) -> BaseGrid:
    """
    Returns an individual atomic grid centered at (0, 0, 0) given the grid input description.
    """
    if isinstance(grid_inp, int):
        # grid_inp as an int is deprecated (TODO: put a warning here)
        #        0,  1,  2,  3,  4,  5
        nr = [20, 40, 60, 75, 100, 125][grid_inp]
        prec = [13, 17, 21, 29, 41, 59][grid_inp]
        radgrid = RadialGrid(nr,
                             "chebyshev",
                             "logm3",
                             dtype=dtype,
                             device=device)
        return LebedevGrid(radgrid, prec=prec)

    elif isinstance(grid_inp, str):
        grid_str = grid_inp.lower().replace("-", "")
        grid_cls = _get_grid_cls(grid_str)
        return grid_cls(atomz, dtype=dtype, device=device)
    else:
        raise TypeError("Unknown type of grid_inp: %s" % type(grid_inp))
示例#4
0
    def __init__(self,
                 atomz: int,
                 dtype: torch.dtype = _dtype,
                 device: torch.device = _device):
        # prepare the whole radial grid
        ratom = get_atomic_radius(atomz)
        grid_transform = DE2Transformation(alpha=self.de2_alphas.get(
            atomz, 1.0),
                                           rmin=1e-7,
                                           rmax=15 * ratom)
        radgrid = RadialGrid(self.nr,
                             grid_integrator="uniform",
                             grid_transform=grid_transform,
                             dtype=dtype,
                             device=device)

        is_truncated = self._is_truncated(atomz)
        if is_truncated:
            # truncated
            slices = self._get_truncate_slices(atomz)
            precs = self._get_truncate_precs(atomz)
            assert len(slices) == len(
                precs), "Please report this bug to the github page"
            # list of radial grid slices
            radgrids: List[BaseGrid] = [radgrid[sl] for sl in slices]
        else:
            # not truncated
            radgrids = [radgrid]
            precs = [self.prec]
        super().__init__(radgrids, precs)
示例#5
0
def test_pbc_becke_grid_dvol(rgrid_integrator, rgrid_transform):
    dtype = torch.float64
    nr = 40
    prec = 7
    radgrid = RadialGrid(nr, rgrid_integrator, rgrid_transform, dtype=dtype)
    sphgrid = LebedevGrid(radgrid, prec=prec)
    atompos = torch.tensor([[0.0, 0.0, 0.0], [1.0, 0.0, 0.0]], dtype=dtype)
    natoms = atompos.shape[0]
    lattice = Lattice(torch.eye(3, dtype=dtype) * 3)
    grid = PBCBeckeGrid([sphgrid] * natoms, atompos, lattice=lattice)

    dvol = grid.get_dvolume()  # (ngrid,)
    rgrid = grid.get_rgrid()  # (ngrid, ndim)
    ls = lattice.get_lattice_ls(rcut=5)  # (nls, ndim)
    atomposs = (atompos.unsqueeze(1) + ls).reshape(-1, 1,
                                                   3)  # (natoms * nls, ndim)

    # test gaussian integration
    fcn = torch.exp(-((rgrid - atomposs)**2).sum(dim=-1)).sum(dim=0)  # (ngrid)
    # fcn = rgrid[:, 0] * 0 + 1
    int1 = (fcn * dvol).sum()
    val1 = int1 * 0 + 2 * np.pi**1.5  # analytical function

    # TODO: rtol is relatively large, maybe inspect the Becke integration grid?
    assert torch.allclose(int1, int1 * 0 + val1, rtol=1e-2)
示例#6
0
def test_lebedev_grid_dvol(rgrid_integrator, rgrid_transform):
    dtype = torch.float64
    nr = 40
    prec = 7
    radgrid = RadialGrid(nr, rgrid_integrator, rgrid_transform, dtype=dtype)
    sphgrid = LebedevGrid(radgrid, prec=prec)

    dvol = sphgrid.get_dvolume()  # (ngrid,)
    rgrid = sphgrid.get_rgrid()  # (ngrid, ndim)
    x = rgrid[:, 0]
    y = rgrid[:, 1]
    z = rgrid[:, 2]

    # test gaussian integration
    fcn = torch.exp(-(x * x + y * y + z * z) * 0.5)
    int1 = (fcn * dvol).sum()
    val1 = 2 * np.sqrt(2 * np.pi) * np.pi
    assert torch.allclose(int1, int1 * 0 + val1)
示例#7
0
def test_becke_grid_dvol(rgrid_integrator, rgrid_transform):
    dtype = torch.float64
    nr = 40
    prec = 7
    radgrid = RadialGrid(nr, rgrid_integrator, rgrid_transform, dtype=dtype)
    sphgrid = LebedevGrid(radgrid, prec=prec)
    atompos = torch.tensor([[0.0, 0.0, 0.0], [1.0, 0.0, 0.0]], dtype=dtype)
    natoms = atompos.shape[0]
    grid = BeckeGrid([sphgrid, sphgrid], atompos)

    dvol = grid.get_dvolume()  # (ngrid,)
    rgrid = grid.get_rgrid()  # (ngrid, ndim)
    atompos = atompos.unsqueeze(1)  # (natoms, 1, ndim)

    # test gaussian integration
    fcn = torch.exp(-((rgrid - atompos)**2).sum(dim=-1) * 0.5).sum(
        dim=0)  # (ngrid)
    int1 = (fcn * dvol).sum()
    val1 = 2 * (2 * np.sqrt(2 * np.pi) * np.pi)

    # TODO: rtol is relatively large, maybe inspect the Becke integration grid?
    assert torch.allclose(int1, int1 * 0 + val1, rtol=3e-3)
示例#8
0
    def rad_slices(self, atz: int, radgrid: RadialGrid) -> List[slice]:
        ratom = self._radii_list[atz]
        ralphas = self._alphas * ratom
        rgrid = radgrid.get_rgrid().reshape(-1, 1)  # (nr, 1)
        if atz <= 2:  # H & He
            ralphas_i = ralphas[0]
        elif atz <= 10:
            ralphas_i = ralphas[1]
        else:
            ralphas_i = ralphas[2]
        # place has value from 0 to 4 (inclusive)
        place = torch.sum(rgrid > ralphas_i, dim=-1)  # (nr,)

        # convert it to slice
        pl, counts = torch.unique_consecutive(place, return_counts=True)
        idx = 0
        res: List[slice] = []
        precs = self._get_precs(atz)
        for i in range(len(precs)):
            c = int(counts[i])
            res.append(slice(idx, idx + c, None))
            idx += c
        return res
示例#9
0
文件: factory.py 项目: diffqc/dqc
def get_grid(atomzs: Union[List[int], torch.Tensor],
             atompos: torch.Tensor,
             *,
             lattice: Optional[Lattice] = None,
             nr: Union[int, Callable[[int], int]] = 99,
             nang: Union[int, Callable[[int], int]] = 590,
             radgrid_generator: str = "uniform",
             radgrid_transform: str = "sg2-dasgupta",
             atom_radii: str = "expected",
             multiatoms_scheme: str = "becke",
             truncate: Optional[str] = "dasgupta",
             dtype: torch.dtype = _dtype,
             device: torch.device = _device) -> BaseGrid:
    # atompos: (natoms, ndim)
    assert atompos.ndim == 2
    assert atompos.shape[-2] == len(atomzs)

    # convert the atomzs to a list of integers
    if isinstance(atomzs, torch.Tensor):
        assert atomzs.ndim == 1
        atomzs_list = [a.item() for a in atomzs]
    else:
        atomzs_list = list(atomzs)

    # get the atom radii list
    atom_radii_options: Mapping[str, Union[List[float]]] = {
        "expected": atom_expected_radii,
        "bragg": atom_bragg_radii,
    }
    atom_radii_list = get_option("atom radii", atom_radii, atom_radii_options)
    atomradii = torch.tensor([atom_radii_list[atomz] for atomz in atomzs_list],
                             dtype=dtype,
                             device=device)

    # construct the radial grid transformation as a function of atom z
    radgrid_tf_options = {
        "sg2-dasgupta":
        lambda atz: DE2Transformation(alpha=__sg2_dasgupta_alphas[atz],
                                      rmin=1e-7,
                                      rmax=15 * atom_radii_list[atz]),
        "sg3-dasgupta":
        lambda atz: DE2Transformation(alpha=__sg3_dasgupta_alphas[atz],
                                      rmin=1e-7,
                                      rmax=15 * atom_radii_list[atz]),
        "logm3":
        lambda atz: LogM3Transformation(ra=atom_radii_list[atz]),
        "treutlerm4":
        lambda atz: TreutlerM4Transformation(xi=__treutler_xi[atz], alpha=0.6),
    }
    radgrid_tf = get_option("radial grid transformation", radgrid_transform,
                            radgrid_tf_options)

    # get the precisions
    if isinstance(nang, int):
        prec: Union[int,
                    Callable[[int],
                             int]] = get_option("number of angular points",
                                                nang, __nang2prec)
    else:

        def _prec_fcn(atz: int) -> int:
            assert callable(nang)
            return get_option("number of angular points", nang(atz),
                              __nang2prec)

        prec = _prec_fcn

    # wrap up a function to get the nr
    def _get_nr(nr: Union[int, Callable[[int], int]], atz: int):
        if isinstance(nr, int):
            return nr
        else:
            return nr(atz)

    # get the truncation rule as a function to avoid unnecessary evaluation
    trunc_options = {
        "dasgupta":
        lambda: DasguptaTrunc(nr),
        "nwchem":
        lambda: NWChemTrunc(atom_radii_list,
                            prec,
                            list(__nang2prec.values()),
                            dtype=dtype,
                            device=device),
        "no":
        lambda: NoTrunc(),
    }
    truncate_str = truncate if truncate is not None else "no"
    trunc = get_option("truncation rule", truncate_str, trunc_options)()

    sphgrids: List[BaseGrid] = []
    sphgrids_dict: Dict[int, BaseGrid] = {}
    for atz in atomzs_list:
        if atz in sphgrids_dict:
            sphgrids.append(sphgrids_dict[atz])
            continue

        nr_value = _get_nr(nr, atz)
        radgrid = RadialGrid(nr_value,
                             grid_integrator=radgrid_generator,
                             grid_transform=radgrid_tf(atz),
                             dtype=dtype,
                             device=device)
        if trunc.to_truncate(atz):
            rad_slices = trunc.rad_slices(atz, radgrid)
            radgrids: List[BaseGrid] = [radgrid[sl] for sl in rad_slices]
            precs = trunc.precs(atz, radgrid)
            sphgrid = TruncatedLebedevGrid(radgrids, precs)
        else:
            sphgrid = LebedevGrid(radgrid, prec=_get_nr(prec, atz))
        sphgrids_dict[atz] = sphgrid
        sphgrids.append(sphgrid)

    # get the multi atoms grid
    # the values are a function to avoid constructing it unnecessarily
    if lattice is None:
        multiatoms_options: Mapping[str, Callable[[], BaseGrid]] = {
            "becke":
            lambda: BeckeGrid(sphgrids, atompos, atomradii=atomradii),
            "treutler":
            lambda: BeckeGrid(sphgrids,
                              atompos,
                              atomradii=atomradii,
                              ratom_adjust="treutler"),
        }
    else:
        assert isinstance(lattice, Lattice)
        multiatoms_options = {
            "becke":
            lambda: PBCBeckeGrid(sphgrids, atompos, lattice=lattice
                                 ),  # type: ignore
            "treutler":
            lambda: PBCBeckeGrid(
                sphgrids,
                atompos,
                lattice=lattice,  # type: ignore
                ratom_adjust="treutler"),
        }
    grid = get_option("multiatoms scheme", multiatoms_scheme,
                      multiatoms_options)()
    return grid