Ejemplo n.º 1
0
def get_dos(
        model,
        posinp,
        device="cpu",
        supercell=(6, 6, 6),
        qpoints=[30, 30, 30],
        npts=1000,
        width=0.004,
):
    if isinstance(posinp, str):
        atoms = posinp_to_ase_atoms(Posinp.from_file(posinp))
    elif isinstance(posinp, Posinp):
        atoms = posinp_to_ase_atoms(posinp)
    else:
        raise ValueError("The posinp variable is not recognized.")

    if isinstance(model, str):
        model = load_model(model, map_location=device)
    elif isinstance(model, torch.nn.Module):
        pass
    else:
        raise ValueError("The model variable is not recognized.")

    # Bugfix to make older models work with PyTorch 1.6
    # Hopefully temporary
    for mod in model.modules():
        if not hasattr(mod, "_non_persistent_buffers_set"):
            mod._non_persistent_buffers_set = set()

    assert len(supercell) == 3, "Supercell should be a length 3 object."
    assert len(qpoints) == 3, "Qpoints should be a length 3 object."
    supercell = tuple(supercell)

    cutoff = float(model.state_dict()
                   ["representation.interactions.0.cutoff_network.cutoff"])
    calculator = SpkCalculator(
        model,
        device=device,
        energy="energy",
        forces="forces",
        environment_provider=AseEnvironmentProvider(cutoff),
    )
    ph = Phonons(atoms, calculator, supercell=supercell, delta=0.02)
    ph.run()
    ph.read(acoustic=True)
    dos = ph.get_dos(kpts=qpoints).sample_grid(npts=npts, width=width)
    ph.clean()
    return Dos(dos.energy * 8065.6, dos.weights[0])
Ejemplo n.º 2
0
def main(args):
    function = get_function(args.function)
    distances = np.linspace(args.range[0], args.range[1], args.ndata)
    with connect(args.dbname) as db:
        for d in distances:
            pos_dict = {
                "units":
                "angstroem",
                "boundary_conditions":
                "free",
                "positions": [
                    {
                        args.element: [0, 0, 0]
                    },
                    {
                        args.element: [d, 0, 0]
                    },
                ],
            }
            posinp = Posinp.from_dict(pos_dict)
            atoms = posinp_to_ase_atoms(posinp)
            energy = function.value(d)
            forces = np.array([
                [-1.0 * function.first_derivative(-d), 0, 0],
                [-1.0 * function.first_derivative(d), 0, 0],
            ])
            db.write(atoms, data={"energy": energy, "forces": forces})
def determine_unique_configurations(configurations):

    cutoff = float(np.max(configurations[0].cell.array) / 2 + 1)

    unique_reps, unique_config, reps, count_configs = [], [], [], []
    schnet = SchNet(n_atom_basis=32,
                    n_filters=32,
                    n_interactions=1,
                    cutoff=cutoff,
                    cutoff_network=CosineCutoff)
    env = AseEnvironmentProvider(cutoff=cutoff)

    data = [posinp_to_ase_atoms(pos) for pos in configurations]
    data = SchnetPackData(data=data,
                          environment_provider=env,
                          collect_triples=False)
    data_loader = AtomsLoader(data, batch_size=1)

    for batch in data_loader:
        reps.append(torch.squeeze(schnet(batch)))

    for i, rep in enumerate(reps):
        for j, uni in enumerate(unique_reps):
            if compare_reps(rep, uni):
                count_configs[j] += 1
                break
        else:
            unique_reps.append(rep)
            unique_config.append(configurations[i])
            count_configs.append(1)
    return unique_config, count_configs
Ejemplo n.º 4
0
def main(args):
    with connect(args.dbname) as db:
        db.metadata = DEFAULT_METADATA
        if args.run_mode == "bigdft":
            files = [f for f in os.listdir() if f.endswith(".xyz")]
            for f in files:
                atoms = posinp_to_ase_atoms(Posinp.from_file(f))
                with open(f, "r") as posinp_file:
                    energy = float(
                        posinp_file.readline().split()[2]) * 27.21138602
                    forces = None
                    for line in posinp_file:
                        if "forces" not in line:
                            continue
                        else:
                            forces = []
                            for _ in range(len(atoms)):
                                forces.append([
                                    float(force) for force in
                                    posinp_file.readline().split()[-3:]
                                ])
                            forces = np.array(
                                forces) * 27.21138602 / 0.529177249
                            break
                db.write(atoms, data={"energy": energy, "forces": forces})

        elif args.run_mode == "abinit":
            files = [f for f in os.listdir() if f.endswith(".out")]
            for f in files:
                atoms = read(f, format="abinit-out")
                about = AbinitOutputFile(f)
                energy = float(about.final_vars_global["etotal"]) * 27.21138602
                forces = (np.array([
                    float(g) for g in about.final_vars_global["fcart"].split()
                ]).reshape(-1, 3) * 27.21138602 / 0.529177249)
                db.write(atoms, data={"energy": energy, "forces": forces})
Ejemplo n.º 5
0
    def run(
        self,
        property,
        posinp=None,
        batch_size=128,
    ):
        r"""
        Central method to use when making a calculation with
        the calculator.

        Parameters
        ----------
        property : str
            Property to be predicted by the calculator
        posinp : Posinp
            Atomic configuration to pass to the model
        batch_size : int
            Batch sizes. Default is 128.

        Returns
        -------
        predictions : :class:`numpy.ndarray`
            Corresponding prediction by the model.
        """
        init_property, out_name, derivative, wrt = get_derivative_names(
            property, self.available_properties)
        if abs(derivative) >= 1:
            self.model.output_modules[0].create_graph = True

        if len(posinp) > 1 and derivative:
            batch_size = 1

        data = [posinp_to_ase_atoms(pos) for pos in posinp]
        pbc = True if any(pos.pbc.any() for pos in data) else False
        environment_provider = (AseEnvironmentProvider(
            cutoff=self.cutoff) if pbc else SimpleEnvironmentProvider())
        data = SchnetPackData(
            data=data,
            environment_provider=environment_provider,
            collect_triples=self.model_type == "wacsf",
        )
        data_loader = AtomsLoader(data, batch_size=batch_size)

        pred = []
        if derivative == 0:
            if self.model.output_modules[0].derivative is not None:
                for batch in data_loader:
                    batch = {k: v.to(self.device) for k, v in batch.items()}
                    pred.append(self.model(batch))
            else:
                with torch.no_grad():
                    for batch in data_loader:
                        batch = {
                            k: v.to(self.device)
                            for k, v in batch.items()
                        }
                        pred.append(self.model(batch))
        if abs(derivative) == 1:
            for batch in data_loader:
                batch = {k: v.to(self.device) for k, v in batch.items()}
                batch[wrt[0]].requires_grad_()
                results = self.model(batch)
                deriv1 = torch.unsqueeze(
                    torch_derivative(results[init_property], batch[wrt[0]]), 0)
                if derivative < 0:
                    deriv1 = -1.0 * deriv1
                pred.append({out_name: deriv1})
        if abs(derivative) == 2:
            for batch in data_loader:
                batch = {k: v.to(self.device) for k, v in batch.items()}
                for inp in set(wrt):
                    batch[inp].requires_grad_()
                results = self.model(batch)
                deriv2 = torch.unsqueeze(
                    torch_derivative(
                        torch_derivative(
                            results[init_property],
                            batch[wrt[0]],
                            create_graph=True,
                        ),
                        batch[wrt[0]],
                    ),
                    0,
                )
                if derivative < 0:
                    deriv2 = -1.0 * deriv2
                pred.append({out_name: deriv2})

        predictions = {}
        if self.md:
            for p in ["energy", "forces"]:
                predictions[p] = np.concatenate(
                    [batch[p].cpu().detach().numpy() for batch in pred])
        else:
            if derivative:
                predictions[property] = np.concatenate(
                    [batch[out_name].cpu().detach().numpy() for batch in pred])
            else:
                predictions[property] = np.concatenate([
                    batch[init_property].cpu().detach().numpy()
                    for batch in pred
                ])
        return predictions
Ejemplo n.º 6
0
    def run(
        self,
        property,
        posinp=None,
        batch_size=1,
    ):
        r"""
        Central method to use when making a calculation with
        the calculator.

        Parameters
        ----------
        property : str
            Property to be predicted by the calculator
        posinp : Posinp
            Atomic configuration to pass to the model

        Returns
        -------
        predictions : :class:`numpy.ndarray`
            Corresponding prediction by the model.
        """

        # Initial setup
        assert (
            len(posinp) == 1
        ), "Use the PatchSPCalculator for one configuration at a time."
        atoms = posinp_to_ase_atoms(posinp[0])

        if property == "hessian" and any(self.subgrid == 2):
            raise warnings.warn(
                """
            The hessian matrix can have some bad values with a grid of
            size 2 because the same atom can be copied multiple times
            in the buffers of the same subcell. Use a larger grid.
            """
            )

        init_property, out_name, derivative, wrt = get_derivative_names(
            property, self.available_properties
        )
        if abs(derivative) >= 1:
            self.model.output_modules[0].create_graph = True

        pbc = True if atoms.pbc.any() else False
        environment_provider = (
            AseEnvironmentProvider(cutoff=self.cutoff)
            if pbc
            else SimpleEnvironmentProvider()
        )

        # Split the configuration according to the subgrid
        at_to_patches = AtomsToPatches(
            cutoff=self.cutoff, n_interaction=self.n_interaction, grid=self.subgrid
        )
        (
            subcells,
            subcells_main_idx,
            original_cell_idx,
            complete_subcell_copy_idx,
        ) = at_to_patches.split_atoms(atoms)

        # Pass each subcell independantly
        results = []
        for subcell in subcells:
            data = SchnetPackData(
                data=[subcell],
                environment_provider=environment_provider,
                collect_triples=self.model_type == "wacsf",
            )
            data_loader = AtomsLoader(data, batch_size=1)

            if derivative == 0:
                if self.model.output_modules[0].derivative is not None:
                    for batch in data_loader:
                        batch = {k: v.to(self.device) for k, v in batch.items()}
                        results.append(self.model(batch))
                else:
                    with torch.no_grad():
                        for batch in data_loader:
                            batch = {k: v.to(self.device) for k, v in batch.items()}
                            results.append(self.model(batch))

            if abs(derivative) == 1:
                for batch in data_loader:
                    batch = {k: v.to(self.device) for k, v in batch.items()}
                    batch[wrt[0]].requires_grad_()
                    forward_results = self.model(batch)
                    deriv1 = torch_derivative(
                        forward_results[init_property], batch[wrt[0]]
                    )
                    if derivative < 0:
                        deriv1 = -1.0 * deriv1
                    results.append({out_name: deriv1})

            if abs(derivative) == 2:
                raise NotImplementedError()

        predictions = {}
        if property == "energy":
            predictions["energy"] = np.sum(
                [
                    patch["individual_energy"][subcells_main_idx[i]]
                    .detach()
                    .cpu()
                    .numpy()
                    for i, patch in enumerate(results)
                ]
            )

        elif property == "forces":
            forces = np.zeros((len(atoms), 3))
            for i in range(len(results)):
                forces[original_cell_idx[i]] = (
                    results[i]["forces"]
                    .detach()
                    .squeeze()
                    .cpu()
                    .numpy()[subcells_main_idx[i]]
                )
            predictions["forces"] = forces

        elif property == "hessian":
            hessian = np.zeros((3 * len(atoms), 3 * len(atoms)))

            for i in range(len(results)):

                (
                    hessian_original_cell_idx_0,
                    hessian_original_cell_idx_1,
                ) = prepare_hessian_indices(
                    original_cell_idx[i], complete_subcell_copy_idx[i]
                )

                (
                    hessian_subcells_main_idx_0,
                    hessian_subcells_main_idx_1,
                ) = prepare_hessian_indices(
                    subcells_main_idx[i],
                    np.arange(0, len(complete_subcell_copy_idx[i])),
                )

                hessian[hessian_original_cell_idx_0, hessian_original_cell_idx_1] = (
                    results[i]["hessian"]
                    .detach()
                    .squeeze()
                    .cpu()
                    .numpy()[hessian_subcells_main_idx_0, hessian_subcells_main_idx_1]
                )
            predictions["hessian"] = hessian

        else:
            raise NotImplementedError()

        return predictions
Ejemplo n.º 7
0
 def test_periodic(self):
     pos1 = Posinp.from_file(os.path.join(pos_folder, "periodic.xyz"))
     atoms = posinp_to_ase_atoms(pos1)
     pos2 = Posinp.from_ase(atoms)
     assert pos1 == pos2
Ejemplo n.º 8
0
 def test_surface(self):
     pos1 = Posinp.from_file(os.path.join(pos_folder, "surface2.xyz"))
     atoms = posinp_to_ase_atoms(pos1)
     pos2 = Posinp.from_ase(atoms)
     assert pos1 == pos2