Ejemplo n.º 1
0
    def calculate(self, coords):
        # Update atom coordinates from line array
        coord_count = 0
        for a in self.atoms:
            a.x, a.y, a.z = coords[coord_count:coord_count + 3]
            coord_count += 3

        # Set gradients to 0
        self.gradient = [
            np.array([0., 0., 0.]) for i in range(len(self.atoms))
        ]

        # Loop through the atoms
        self.energy = np.float128(0.)
        energy_hold = []
        for i, aa in enumerate(self.atoms):
            a = np.array([aa.x, aa.y, aa.z])
            gx, gy, gz = [], [], []
            for j, bb in enumerate(self.atoms):
                # If comparing against same atom, skip
                if i == j:
                    continue

                b = np.array([bb.x, bb.y, bb.z])
                dist = np.linalg.norm(a - b)
                direction = (a - b) / dist

                # Equations from http://www.phys.ubbcluj.ro/~tbeu/MD/C2_for.pdf
                calc_F = np.float128(
                    direction * 48.0 * self.epsilon / np.power(dist, 2) *
                    (np.power((self.sigma / dist), 12) - 0.5 * np.power(
                        (self.sigma / dist), 6)))
                calc_E = np.float128(4.0 * self.epsilon * (np.power(
                    (self.sigma / dist), 12) - np.power(
                        (self.sigma / dist), 6)))

                gx.append(np.float128(-calc_F[0]))
                gy.append(np.float128(-calc_F[1]))
                gz.append(np.float128(-calc_F[2]))
                energy_hold.append(np.float128(calc_E))

            x, y, z = fsum(gx), fsum(gy), fsum(gz)
            self.gradient[i] = np.array([x, y, z])

        self.energy = fsum(energy_hold)

        self.energy /= np.float128(2.0)  # Remove double counts

        self.gradient = np.array(self.gradient).flatten()
        force_mags = (self.gradient.reshape((-1, 3))**2).sum(axis=1)
        self.RMS_force = geometry.rms(force_mags)
        self.MAX_force = max(force_mags)
        self.error = self.RMS_force

        print("%d\t%.4f\t%.4f\t%.4f" %
              (self.step, self.RMS_force, self.MAX_force, self.energy))

        self.step += 1
Ejemplo n.º 2
0
    def calculate(self, coords):
        self.calls_to_calculate += 1

        # Update coordinates in states. This won't change anything on
        # the first run through, but will on subsequent ones
        coord_count = 0
        for s in self.states[1:-1]:
            for a in s:
                a.x, a.y, a.z = coords[coord_count:coord_count + 3]
                coord_count += 3

        # Start DFT jobs
        running_jobs = []
        for i, state in enumerate(self.states):
            if (i == 0 or i == len(self.states) - 1) and self.step > 0:
                # No need to calculate anything for first and last states
                # after the first step
                pass
            else:
                running_jobs.append(
                    self.start_job(self, i, state, self.charge,
                                   self.multiplicity, self.procs, self.queue,
                                   self.initial_guess, self.extra_section,
                                   self.mem, self.priority,
                                   self.extra_keywords))
        # Wait for jobs to finish
        if self.job_hang_time is not None:
            time.sleep(self.job_hang_time)
        for j in running_jobs:
            j.wait()
        if self.job_hang_time is not None:
            time.sleep(self.job_hang_time)

        # Get forces and energies from DFT calculations
        if not self.no_energy:
            energies = []
        for i, state in enumerate(self.states):
            # State 0 and state N-1 don't change, so just use result
            # from self.step == 0
            if (i == 0 or i == len(self.states) - 1):
                step_to_use = 0
            else:
                step_to_use = self.step

            new_energy, new_atoms = self.get_results(self, step_to_use, i,
                                                     state)
            if not self.no_energy:
                energies.append(new_energy)

        # V = potential energy from DFT. energies = V+springs
        if not self.no_energy:
            V = copy.deepcopy(energies)

        # In climbing image neb, after a few iterations we take the highest
        # energy image and use that.
        if self.ci_neb and self.ci_img is None and self.step > self.ci_N:
            self.ci_img = V.index(max(V))
            if self.ci_img in [0, len(self.states) - 1]:
                raise Exception("CI found endpoint. Is your band correct?")

        # Get positions in a flat array
        def get_positions(image):
            pos = np.array([np.empty([3]) for j in image])
            for j, atom in enumerate(image):
                if j not in self.spring_atoms:
                    continue
                pos[j] = np.array([atom.x, atom.y, atom.z])
            return pos.flatten()

        # Add spring forces to atoms
        for i in range(1, len(self.states) - 1):
            a = get_positions(self.states[i - 1])
            b = get_positions(self.states[i])
            c = get_positions(self.states[i + 1])

            real_force = np.array([np.empty([3]) for j in self.states[i]])
            for j, atom in enumerate(self.states[i]):
                if j not in self.spring_atoms:
                    continue
                real_force[j] = np.array([atom.fx, atom.fy, atom.fz])
            real_force = real_force.flatten()

            # Find tangent
            tplus = c - b
            tminus = b - a
            if not self.no_energy:
                dVmin = min(abs(V[i + 1] - V[i]), abs(V[i - 1] - V[i]))
                dVmax = max(abs(V[i + 1] - V[i]), abs(V[i - 1] - V[i]))

            if self.no_energy:
                tangent = (c.copy() - b.copy()) / np.linalg.norm(c.copy() - b.copy()) + \
                          (b.copy() - a.copy()) / np.linalg.norm(b.copy() - a.copy())
                tangent = tangent / np.linalg.norm(tangent)
            else:
                if V[i + 1] > V[i] and V[i] > V[i - 1]:
                    tangent = tplus.copy()
                elif V[i + 1] < V[i] and V[i] < V[i - 1]:
                    tangent = tminus.copy()
                elif V[i + 1] > V[i - 1]:
                    tangent = tplus * dVmax + tminus * dVmin
                else:
                    tangent = tplus * dVmin + tminus * dVmax

            # Normalize tangent
            tangent_norm = np.sqrt(np.vdot(tangent, tangent))
            if tangent_norm != 0:
                tangent /= tangent_norm

            F_spring_parallel = self.k * (np.linalg.norm(tplus) -
                                          np.linalg.norm(tminus)) * tangent

            F_real_perpendicular = real_force -\
                (np.vdot(real_force, tangent) * tangent)

            # Set NEB forces
            # Note, in climbing image we have the formula:
            #    F = F_real - 2*F_real*tau*tau
            # Vs the normal:
            #    F = F_spring_parallel + F_real_perpendicular
            if self.ci_img is not None and i == self.ci_img:
                forces = real_force - 2.0 * np.vdot(real_force,
                                                    tangent) * tangent
            else:
                forces = F_spring_parallel + F_real_perpendicular
            forces = forces.reshape((-1, 3))
            for j, atom in enumerate(self.states[i]):
                if j not in self.spring_atoms:
                    continue
                atom.fx, atom.fy, atom.fz = forces[j]

        # Remove net translation forces from the gradient
        if self.fit_rigid:
            net_translation_force = []
            for state in self.states[1:-1]:
                net_force = np.zeros(3)
                for a in state:
                    net_force += (a.fx, a.fy, a.fz)
                net_trans = np.sqrt((net_force**2).sum()) / len(state)
                net_translation_force.append(net_trans)
                for a in state:
                    a.fx -= net_force[0] / len(state)
                    a.fy -= net_force[1] / len(state)
                    a.fz -= net_force[2] / len(state)

        # Set gradient
        self.gradient = []
        for state in self.states[1:-1]:
            for a in state:
                # Gradient of self.error
                self.gradient += [-a.fx, -a.fy, -a.fz]

        # Calculate RMS Force and Max force
        force_mags = [(a.fx**2 + a.fy**2 + a.fz**2)**0.5
                      for state in self.states[1:-1] for a in state]
        RMS_force = geometry.rms(force_mags)
        self.RMS_force = RMS_force
        MAX_force = max(force_mags)
        self.MAX_force = MAX_force

        # Print data
        if not self.no_energy:
            V = V[:1] + [
                units.convert_energy("Ha", "kT_300", e - V[0]) for e in V[1:]
            ]
        if not self.no_energy:
            MAX_energy = max(V)
        else:
            MAX_energy = float('inf')

        if self.prv_RMS is None or self.prv_RMS > RMS_force:
            rms = print_helper.color_set(
                float("%.4f" % units.convert_energy("Ha", "eV", RMS_force)),
                'GREEN')
        else:
            rms = print_helper.color_set(
                float("%.4f" % units.convert_energy("Ha", "eV", RMS_force)),
                'RED')
        if self.prv_MAX is None or self.prv_MAX > MAX_force:
            max_f = print_helper.color_set(
                float("%.4f" % units.convert_energy("Ha", "eV", MAX_force)),
                'GREEN')
        else:
            max_f = print_helper.color_set(
                float("%.4f" % units.convert_energy("Ha", "eV", MAX_force)),
                'RED')

        if not self.no_energy:
            if self.prv_MAX_E is None or self.prv_MAX_E > MAX_energy:
                max_e = print_helper.color_set(float("%.1f" % MAX_energy),
                                               'GREEN')
            else:
                max_e = print_helper.color_set(float("%.1f" % MAX_energy),
                                               'RED')

        if not self.no_energy:
            if self.step == 0:
                print("Step\tRMS_F (eV/Ang)\tMAX_F (eV/Ang)\tMAX_E (kT_300)\
\tEnergies (kT_300)\n----")
            print("%d\t%s\t\t%s\t\t%s" % (self.step, rms, max_f, max_e)),
            print '    \t\t\t\t', '%7.5g +'\
                  % V[0], ('%5.1f ' * len(V[1:])) % tuple(V[1:])
        else:
            if self.step == 0:
                print("Step\tRMS_F (eV/Ang)\tMAX_F (eV/Ang)\n----")
            print("%d\t%s\t\t%s" % (self.step, rms, max_f))

        sys.stdout.flush()

        if self.prv_RMS is None:
            self.prv_RMS = RMS_force
        self.prv_RMS = min(RMS_force, self.prv_RMS)

        if self.prv_MAX is None:
            self.prv_MAX = MAX_force
        self.prv_MAX = min(MAX_force, self.prv_MAX)

        if not self.no_energy:
            if self.prv_MAX_E is None:
                self.prv_MAX_E = MAX_energy
            self.prv_MAX_E = min(MAX_energy, self.prv_MAX_E)

        # Set error
        self.error = RMS_force

        # Increment step
        self.step += 1

        if self.callback is not None:
            self.callback(self.states)
Ejemplo n.º 3
0
    def calculate(self, coords):
        self.calls_to_calculate += 1

        # Update coordinates in states. This won't change anything on
        # the first run through, but will on subsequent ones
        coord_count = 0
        for s in self.states[1:-1]:
            for a in s:
                a.x, a.y, a.z = coords[coord_count:coord_count + 3]
                coord_count += 3

        # Start DFT jobs
        running_jobs = []
        if self.initialize == True:
            # Run a single point calculation to determine energies before main curve-smoothing begins
            for i, state in enumerate(self.states):
                running_jobs.append(
                    self.start_job(self, i, state, self.charge, self.procs,
                                   self.queue, self.initial_guess,
                                   self.extra_section, self.mem,
                                   self.priority))
        else:
            # Once initialization is complete, run main spline_NEB simulation for curve smoothing
            for i, state in enumerate(self.states):
                if (i == 0 or i == self.peak
                        or i == len(self.states) - 1) and self.step > 0:
                    # No need to calculate anything for first and last states
                    # after the first step
                    pass
                else:
                    running_jobs.append(
                        self.start_job(self, i, state, self.charge, self.procs,
                                       self.queue, self.initial_guess,
                                       self.extra_section, self.mem,
                                       self.priority))
        # Wait for jobs to finish
        for j in running_jobs:
            j.wait()

        # Get forces and energies from DFT calculations
        energies = []
        for i, state in enumerate(self.states):
            # State 0 and state N-1 don't change, so just use result
            # from self.step == 0
            if (i == 0 or i == self.peak or i == len(self.states) - 1):
                step_to_use = 0
            else:
                step_to_use = self.step

            new_energy, new_atoms = self.get_results(self, step_to_use, i,
                                                     state)
            energies.append(new_energy)

        # V = potential energy from DFT. energies = V+springs
        V = copy.deepcopy(energies)

        # Get positions in a flat array
        def get_positions(image):
            pos = np.array([np.empty([3]) for j in image])
            for j, atom in enumerate(image):
                if j not in self.spring_atoms:
                    continue
                pos[j] = np.array([atom.x, atom.y, atom.z])
            return pos.flatten()

        if self.initialize == True:
            # During initialization phase, use single point energies previously calculated to
            # determine highest energy frame (peak) and generate spring constants between frames
            # Peak of reaction coordinate is highest energy frame
            self.peak = energies.index(max(energies))

            #Calculate spring constants for smoothing curve
            d_before = np.linalg.norm(
                get_positions(self.states[self.peak]) -
                get_positions(self.states[0]))
            d_after = np.linalg.norm(
                get_positions(self.states[self.peak]) -
                get_positions(self.states[-1]))

            l_before = -d_before**2 / np.log(self.gamma)
            l_after = -d_after**2 / np.log(self.gamma)

            x1, x2 = [], []
            for i in range(self.peak):
                v = (get_positions(self.states[i]) +
                     get_positions(self.states[i+1])) / 2.0 - \
                     get_positions(self.states[0])
                x1.append(np.linalg.norm(v))

            for i in range(self.peak, len(self.states) - 1):
                v = (get_positions(self.states[i]) +
                     get_positions(self.states[i+1])) / 2.0 - \
                     get_positions(self.states[0])
                x2.append(np.linalg.norm(v))

            for x in x1:
                self.k.append(self.k_max *
                              exp(-((x - d_before)**2) / l_before))
            for x in x2:
                self.k.append(self.k_max * exp(-((x - d_after)**2) / l_after))

        # Add spring forces to atoms
        for i in range(1, len(self.states) - 1):
            if i == self.peak:
                # Set NEB forces at peak to 0
                for j, atom in enumerate(self.states[i]):
                    if j not in self.spring_atoms:
                        continue
                    atom.fx, atom.fy, atom.fz = [0, 0, 0]
            else:
                a = get_positions(self.states[i - 1])
                b = get_positions(self.states[i])
                c = get_positions(self.states[i + 1])

                real_force = np.array([np.empty([3]) for j in self.states[i]])
                for j, atom in enumerate(self.states[i]):
                    if j not in self.spring_atoms:
                        continue
                    real_force[j] = np.array([atom.fx, atom.fy, atom.fz])
                real_force = real_force.flatten()

                # Find tangent
                tplus = c - b
                tminus = b - a
                dVmin = min(abs(V[i + 1] - V[i]), abs(V[i - 1] - V[i]))
                dVmax = max(abs(V[i + 1] - V[i]), abs(V[i - 1] - V[i]))

                if V[i + 1] > V[i] and V[i] > V[i - 1]:
                    tangent = tplus.copy()
                elif V[i + 1] < V[i] and V[i] < V[i - 1]:
                    tangent = tminus.copy()
                elif V[i + 1] > V[i - 1]:
                    tangent = tplus * dVmax + tminus * dVmin
                else:
                    tangent = tplus * dVmin + tminus * dVmax

                # Normalize tangent
                tangent_norm = np.sqrt(np.vdot(tangent, tangent))
                if tangent_norm != 0:
                    tangent /= tangent_norm

# Set NEB forces
                forces = (self.k[i] * np.linalg.norm(tplus) -
                          self.k[i - 1] * np.linalg.norm(tminus)) * tangent
                forces = forces.reshape((-1, 3))
                for j, atom in enumerate(self.states[i]):
                    if j not in self.spring_atoms:
                        continue
                    atom.fx, atom.fy, atom.fz = forces[j]

        # Remove net translation forces from the gradient
        if self.fit_rigid:
            net_translation_force = []
            for state in self.states[1:-1]:
                net_force = np.zeros(3)
                for a in state:
                    net_force += (a.fx, a.fy, a.fz)
                net_trans = np.sqrt((net_force**2).sum()) / len(state)
                net_translation_force.append(net_trans)
                for a in state:
                    a.fx -= net_force[0] / len(state)
                    a.fy -= net_force[1] / len(state)
                    a.fz -= net_force[2] / len(state)
            max_translation_force = units.convert("Ha/Ang", "eV/Ang",
                                                  max(net_translation_force))
        else:
            max_translation_force = 0

        # Set gradient
        self.gradient = []
        for state in self.states[1:-1]:
            for a in state:
                # Gradient of self.error
                self.gradient += [-a.fx, -a.fy, -a.fz]

        # Calculate RMS Force and Max force
        force_mags = [(a.fx**2 + a.fy**2 + a.fz**2)**0.5
                      for state in self.states[1:-1] for a in state]
        RMS_force = geometry.rms(force_mags)
        self.RMS_force = RMS_force
        MAX_force = max(force_mags)
        self.MAX_force = MAX_force

        # Print data
        V = V[:1] + [
            units.convert_energy("Ha", "kT_300", e - V[0]) for e in V[1:]
        ]
        MAX_energy = max(V)
        if self.prv_RMS is None or self.prv_RMS > RMS_force:
            rms = print_helper.color_set(
                float("%.4f" % units.convert_energy("Ha", "eV", RMS_force)),
                'GREEN')
        else:
            rms = print_helper.color_set(
                float("%.4f" % units.convert_energy("Ha", "eV", RMS_force)),
                'RED')
        if self.prv_MAX is None or self.prv_MAX > MAX_force:
            max_f = print_helper.color_set(
                float("%.4f" % units.convert_energy("Ha", "eV", MAX_force)),
                'GREEN')
        else:
            max_f = print_helper.color_set(
                float("%.4f" % units.convert_energy("Ha", "eV", MAX_force)),
                'RED')
        if self.prv_MAX_E is None or self.prv_MAX_E > MAX_energy:
            max_e = print_helper.color_set(float("%.1f" % MAX_energy), 'GREEN')
        else:
            max_e = print_helper.color_set(float("%.1f" % MAX_energy), 'RED')
        if self.step == 0 and self.initialize == False:
            print("Step\tRMS_F (eV/Ang)\tMAX_F (eV/Ang)\tMAX_E (kT_300)\
\tMAX Translational Force (eV/Ang)\tEnergies (kT_300)\n----")
        print("%d\t%s\t\t%s\t\t%s\t\t%.4f" %
              (self.step, rms, max_f, max_e, max_translation_force)),

        print '    \t\t\t\t', '%7.5g +'\
              % V[0], ('%5.1f ' * len(V[1:])) % tuple(V[1:])

        sys.stdout.flush()

        if self.prv_RMS is None:
            self.prv_RMS = RMS_force
        self.prv_RMS = min(RMS_force, self.prv_RMS)

        if self.prv_MAX is None:
            self.prv_MAX = MAX_force
        self.prv_MAX = min(MAX_force, self.prv_MAX)

        if self.prv_MAX_E is None:
            self.prv_MAX_E = MAX_energy
        self.prv_MAX_E = min(MAX_energy, self.prv_MAX_E)

        # Set error
        self.error = RMS_force

        # Increment step
        self.step += 1

        # End initialization phase
        self.initialize = False

        if self.callback is not None:
            self.callback(self.states)