예제 #1
0
    def minimize(self, cluster: Cluster, *args, **kwargs) -> Cluster:
        """
        Method to locally minimise a cluster of Lennard-Jones particles.
        Uses the L-BFGS-B method implemented within scipy.minimize.

        Attributes:
            coordinates: np.array(shape=(number_of_particles, 3), dtype=float) array of coordinates
            kwargs: Dict containing any other keyword arguments to be passed to the scipy optimizer
            molecules: list(int), optional,

        Returns
        -------
        result_dict{'coordinates': optimised structure coordinates,
                    'energy': final energy of the cluster,
                    'success': True if successfully minimised}

        """
        positions = list(cluster.get_particle_positions())
        coordinates = positions[0].flatten()

        # args = {"sigma": self.sigma, "epsilon": self.epsilon4, "base_exp": 6}

        result = scipy.optimize.minimize(
            fun=self.get_energy,
            x0=coordinates,  # , args=args,
            method='L-BFGS-B',
            jac=self.get_jacobian)

        positions = (result.x.reshape(
            (self.n_atoms, 3)), positions[1], positions[2])
        cluster.set_particle_positions(positions)
        cluster.cost = result.fun
        return cluster
예제 #2
0
    def minimize(self, cluster: Cluster, *args, **kwargs) -> Cluster:
        """
        Method to locally minimise a cluster of Lennard-Jones particles.
        Uses the L-BFGS-B method implemented within scipy.minimize.


        Args:
            cluster: Cluster instance, required, cluster instance to be minimized
            kwargs: Dict containing any other keyword arguments to be passed to the scipy optimizer

        Returns:
            result_dict{'coordinates': optimised structure coordinates,
                    'energy': final energy of the cluster,
                    'success': True if successfully minimised}

        """
        coords, ids, labels = cluster.get_particle_positions()
        coordinates = coords

        result = minimize(fun=self.get_energy,
                          x0=coordinates.flatten(),
                          method='L-BFGS-B',
                          jac=self.get_jacobian,
                          *args,
                          **kwargs)

        if not result.success:
            print("Optimization failed")

        cluster.set_particle_positions(
            (result.x.reshape(coordinates.shape), ids, labels))
        cluster.cost = result.fun
        return cluster
예제 #3
0
def align_clusters(c1: Cluster, c2: Cluster) -> None:
    """Employs the Kabsch algorithm to align two clusters.

    c1 and c2 will be modified in-place

    See:

    Kabsch, Wolfgang, (1976) "A solution of the best rotation to relate two sets of vectors",
    Acta Crystallographica 32:922

    Args:
        c1, (Cluster): required
        c2, (Cluster): required

    Returns:
        None

    """
    # Transform both clusters CoM to the origin.
    c1.center()
    c2.center()

    coords_mols_labels_c1 = c1.get_particle_positions()
    coords_c1 = coords_mols_labels_c1[0]
    coords_mols_labels_c2 = c2.get_particle_positions()
    coords_c2 = coords_mols_labels_c2[0]

    # Calculate covarience matrix
    A = np.dot(coords_c2.transpose(), coords_c1)
    # Single value decomp
    u, s, v = np.linalg.svd(A)

    if np.linalg.det(u) * np.linalg.det(v) + 1.0 < 1e-8:
        s[-1] = -s[-1]
        u[:, -1] = -u[:, -1]

    rot_mat = np.dot(u, v).transpose()

    new_coordinates = []
    for c in coords_c2:
        new_coordinates.append(np.dot(c, rot_mat))
    new_coordinates = np.array(new_coordinates)
    c2.set_particle_positions(
        (new_coordinates, coords_mols_labels_c2[1], coords_mols_labels_c2[2]))
예제 #4
0
    def minimize(self, cluster: Cluster) -> Cluster:

        self.step_size = self.initial_step
        step = 0

        _ = cluster.get_particle_positions()
        # n_coords = len(_[1])
        self.coords = _[0]

        np.random.shuffle(self.coords)

        last_energy = self.pot.get_energy(cluster)

        converged = False
        while step <= self.max_steps and not converged:
            converged = True
            step += 1

            for idx in range(len(self.coords)):
                self._take_step(self.coords[idx])

            cluster.set_particle_positions((self.coords, _[1], _[2]))
            new_energy = self.pot.get_energy(cluster)
            # print(new_energy, last_energy)
            dE = new_energy - last_energy
            last_energy = new_energy
            self.update()

            if abs(dE) >= self.convergence_gradient:
                converged = False

        # print(f"Exiting in {step} steps")
        # for i in self.coords:
        #     print("Cl   " + "   ".join([str(a) for a in i]))
        cluster.minimum = True
        return cluster
예제 #5
0
    def minimize(self, cluster: Cluster, *args, **kwargs) -> Cluster:

        name = self.get_directory()

        raw_coordinates = cluster.get_particle_positions()
        coordinates = self.format_XYZ(raw_coordinates[0], raw_coordinates[2])

        tag_dict = {"<XYZ>": coordinates, "<NAME>": name}

        run_dir = self.work_dir + name

        input_file_name = run_dir + "/input.nw"
        output_file_name = run_dir + "/output.out"

        self.insert_to_template(template=self.minimize_template,
                                out_file=input_file_name,
                                target_dict=tag_dict)

        commands = [
            self.run_string, f"{input_file_name}", f"> {output_file_name}"
        ]
        commands = ' '.join(commands)

        self.log.info(f"Starting NWChem with commands: {commands}")

        nwchem_process = subprocess.Popen(commands, cwd=run_dir, shell=True)

        exit_code = nwchem_process.wait()

        if exit_code == 134:
            try:
                raise DFTExitedUnexpectedlyError(
                    f"NWChem exited unexpectedly with exitcode: {exit_code}\n")
            except DFTExitedUnexpectedlyError as error:
                self.log.exception(error)
                raise

        if exit_code != 0:
            try:
                raise DFTExitedUnexpectedlyError(
                    f"NWChem exited unexpectedly with exitcode: {exit_code}\n")
            except DFTExitedUnexpectedlyError as error:
                self.log.exception(error)
                raise
        else:
            self.log.info(
                f"NWChem exited successfully. Exit code: {exit_code}")

        output_parser = NWChemOutputParser(output_file_name)

        output_parser.parse()

        final_structure = output_parser.final_structure

        try:
            assert all(raw_coordinates[2]) == all(final_structure[0])
        except AssertionError as error:
            self.log.exception(
                f"Atoms out of order! {raw_coordinates[2]} != {final_structure[0]}\n{error}"
            )
        cluster.set_particle_positions(
            (final_structure[1], raw_coordinates[1], final_structure[0]))

        return cluster
예제 #6
0
    def run_DeMonNano(
            self,
            cluster: Cluster,
            dir_name: str,
            optimize: bool = False):  # TODO move minimize and energy to here
        """Common interface to DeMonNano"""

        if dir_name is not None:
            dir_name = os.path.abspath(dir_name)
        else:
            dir_name = os.path.abspath(self.get_directory())

        inp_fname = dir_name + "/deMon.inp"
        out_fname = dir_name + "/deMon.out"

        shutil.copyfile("SCC-SLAKO", dir_name + "/SCC-SLAKO")
        shutil.copyfile("SLAKO", dir_name + "/SLAKO")

        coords, molecule_ids, atom_labels = cluster.get_particle_positions()

        Natoms = len(molecule_ids)

        xyz_formatted_coordinates = self.format_XYZ(coords, atom_labels)

        with work_dir():

            os.chdir(dir_name)  # Change into the scratch dir.

            tag_dict = {"<XYZ>": xyz_formatted_coordinates}

            if optimize:
                template = self.minimize_template
            else:
                template = self.energy_template

            self.insert_to_template(template=self.work_dir + template,
                                    out_file=inp_fname,
                                    target_dict=tag_dict)

            with open("error_file", "w") as ef:
                # self.run_string should just be the location of the deMonNano executable
                dftb_process = subprocess.Popen([self.run_string],
                                                cwd=dir_name,
                                                shell=True,
                                                stderr=ef,
                                                stdout=ef)

            exit_code = dftb_process.wait()

            # check exit code
            if exit_code != 0:
                try:
                    raise DFTBError(
                        f"DFTB+ exited unexpectedly with exitcode: {exit_code}\n"
                    )
                except DFTBError as error:
                    self.log.exception(error)
                    raise
            else:
                self.log.debug(
                    f"DFTB+ exited successfully. Exit code: {exit_code}")

            if optimize:

                # noinspection PyTypeChecker
                parser = DeMonNanoParser(out_fname,
                                         natoms=Natoms,
                                         logger=self.log)

                result_dict = parser.parse_DeMonNano_output()
                new_coords = result_dict["coordinates"]
                cluster.set_particle_positions(
                    (new_coords, molecule_ids, atom_labels))

            else:

                # noinspection PyTypeChecker
                parser = DeMonNanoParser(out_fname,
                                         natoms=Natoms,
                                         geometry_opt=False,
                                         logger=self.log)

                result_dict = parser.parse_DeMonNano_output()

            energy = result_dict["energy"]
            cluster.cost = energy
            # os.chdir("..")  # Come back out of the scratch dir.

            return cluster