Esempio n. 1
0
 def adjust_positions(self, atoms, new):
     p1, p2 = atoms.positions[self.indices]
     d, p = find_mic(np.array([p2 - p1]), atoms._cell, atoms._pbc)
     q1, q2 = new[self.indices]
     d, q = find_mic(np.array([q2 - q1]), atoms._cell, atoms._pbc)
     d *= 0.5 * (p - q) / q
     new[self.indices] = (q1 - d[0], q2 + d[0])
Esempio n. 2
0
    def adjust_positions(self, atoms, new):
        p1, p2 = atoms.positions[self.indices]
        d_old, p_old = find_mic(np.array([p2 - p1]), atoms._cell, pbc=False)
        d_old = d_old[0]
        
        q1, q2 = new[self.indices]
        d_new, p_new = find_mic(np.array([q2 - q1]), atoms._cell, pbc=False)
        d_new = d_new[0]
        
        if self.direction is None:
            # amount to put back distance to old value
            delta_d = 0.5 * d_new * (p_old - p_new) / p_new
            # desired increase amount
            sbit = 0.5 * d_new / p_new * self.bond_speed
        else:
            self.adjust_direction(atoms)
            p_old = np.abs(np.dot(d_old, self.direction))
            p_new = np.dot(d_new, self.direction)
            swapsign = np.sign(p_new)
            length_new = np.abs(p_new)
            # amount to put back distance to old value by resizing distance vector d_new
            delta_d = 0.5 * (p_old - p_new) * self.direction * swapsign
            # desired increase amount
            sbit = 0.5 * self.direction * self.bond_speed * swapsign

        new[self.indices] = (q1 - delta_d - sbit, q2 + delta_d + sbit)
        self.distance = p_old + self.bond_speed
Esempio n. 3
0
def fit0(E, F, R, cell=None, pbc=None):
    """Constructs curve parameters from the NEB images."""
    E = np.array(E) - E[0]
    n = len(E)
    Efit = np.empty((n - 1) * 20 + 1)
    Sfit = np.empty((n - 1) * 20 + 1)

    s = [0]
    dR = np.zeros_like(R)
    for i in range(n):
        if i < n - 1:
            dR[i] = R[i + 1] - R[i]
            if cell is not None and pbc is not None:
                dR[i], _ = find_mic(dR[i], cell, pbc)
            s.append(s[i] + sqrt((dR[i]**2).sum()))
        else:
            dR[i] = R[i] - R[i - 1]
            if cell is not None and pbc is not None:
                dR[i], _ = find_mic(dR[i], cell, pbc)

    lines = []
    dEds0 = None
    for i in range(n):
        d = dR[i]
        if i == 0:
            ds = 0.5 * s[1]
        elif i == n - 1:
            ds = 0.5 * (s[-1] - s[-2])
        else:
            ds = 0.25 * (s[i + 1] - s[i - 1])

        d = d / sqrt((d**2).sum())
        dEds = -(F[i] * d).sum()
        x = np.linspace(s[i] - ds, s[i] + ds, 3)
        y = E[i] + dEds * (x - s[i])
        lines.append((x, y))

        if i > 0:
            s0 = s[i - 1]
            s1 = s[i]
            x = np.linspace(s0, s1, 20, endpoint=False)
            c = np.linalg.solve(np.array([(1, s0, s0**2, s0**3),
                                          (1, s1, s1**2, s1**3),
                                          (0, 1, 2 * s0, 3 * s0**2),
                                          (0, 1, 2 * s1, 3 * s1**2)]),
                                np.array([E[i - 1], E[i], dEds0, dEds]))
            y = c[0] + x * (c[1] + x * (c[2] + x * c[3]))
            Sfit[(i - 1) * 20:i * 20] = x
            Efit[(i - 1) * 20:i * 20] = y

        dEds0 = dEds

    Sfit[-1] = s[-1]
    Efit[-1] = E[-1]
    return s, E, Sfit, Efit, lines
Esempio n. 4
0
    def get_forces(self,atoms):
        # Scale MD forces to match QM elasticity
        tot_force = self.mm_calc.get_forces(atoms)/self.beta

        # make system object and center atoms in box
        qm_system = atoms.copy()
        del qm_system.constraints
        qm_force = np.zeros(tot_force.shape)
        qm_system = qm_system[self.dft_atoms]

        qm_positions = qm_system.get_positions()
        scaled_qm_positions = qm_positions*self.alpha + self.qm_shift

        qm_system.set_positions(scaled_qm_positions.copy())
        qm_system.set_cell(self.cell.copy())

        dft_atom_count = np.sum(self.dft_atoms)
        tmp_qmf = self.qm_calc.get_forces(qm_system)
        qm_force[self.dft_atoms] = tmp_qmf

        # Reindexing check - will occur when we have multiple species
        if np.linalg.norm(scaled_qm_positions-qm_system.get_positions()) > 1e-9:
            #print "ATOMS REINDEXING IN QM CALC!"
            remap = np.zeros(dft_atom_count).astype(int)
            for i in range(len(remap)):
                remap[i] = find_mic(np.linalg.norm(qm_system.get_positions()-scaled_qm_positions[i],self.cell,pbc=self.pbc))
            qm_force[self.dft_atoms] = tmp_qmf[remap]

        tot_force[self.qm_region] = qm_force[self.qm_region]
        return tot_force
Esempio n. 5
0
 def adjust_forces(self, atoms, forces):
     d = np.subtract.reduce(atoms.positions[self.indices])
     d, p = find_mic(np.array([d]), atoms._cell, atoms._pbc)
     d = d[0]
     d *= 0.5 * np.dot(np.subtract.reduce(forces[self.indices]), d) / p**2
     self.constraint_force = d
     forces[self.indices] += (-d, d)
Esempio n. 6
0
    def get_forces(self,atoms):
        # Scale MD forces to match QM elasticity
        tot_force = self.mm_calc.get_forces(atoms)/self.beta

        # make system object and center atoms in box
        qm_system = atoms.copy()
        del qm_system.constraints
        qm_force = np.zeros(tot_force.shape)
        qm_system = qm_system[self.dft_atoms]

        qm_positions = qm_system.get_positions()
        scaled_qm_positions = qm_positions*self.alpha + self.qm_shift

        qm_system.set_positions(scaled_qm_positions.copy())
        qm_system.set_cell(self.cell.copy())

        dft_atom_count = np.sum(self.dft_atoms)
        tmp_qmf = self.qm_calc.get_forces(qm_system)
        qm_force[self.dft_atoms] = tmp_qmf

        # Reindexing check - will occur when we have multiple species
        if np.linalg.norm(scaled_qm_positions-qm_system.get_positions()) > 1e-9:
            #print "ATOMS REINDEXING IN QM CALC!"
            remap = np.zeros(dft_atom_count).astype(int)
            for i in range(len(remap)):
                remap[i] = find_mic(np.linalg.norm(qm_system.get_positions()-scaled_qm_positions[i],self.cell,pbc=self.pbc))
            qm_force[self.dft_atoms] = tmp_qmf[remap]

        tot_force[self.qm_region] = qm_force[self.qm_region]
        return tot_force
Esempio n. 7
0
 def get_potential_energies(self):
     _tmp_E = np.zeros(self.nimages)
     al, spl_E = self.force_integrator()
     _tmp_E[0]=0.
     _tmp_E[-1] = spl_E[-1]
     tot_d = np.linalg.norm(find_mic(self.images[-1].get_positions() -
                         self.images[0].get_positions(),
                         self.images[0].get_cell(), self.images[0].pbc)[0])
     for i in range(1,self.nimages - 1):
         _d = find_mic(self.images[i].get_positions() -
                     self.images[0].get_positions(),
                     self.images[0].get_cell(), self.images[0].pbc)[0]
         _d_b = np.linalg.norm(find_mic(self.images[i].get_positions() -
                     self.images[-1].get_positions(),
                     self.images[-1].get_cell(), self.images[-1].pbc)[0])
         _dist = .5*np.linalg.norm(_d)/tot_d + .5-.5*_d_b/tot_d
         _ind = min(int(len(spl_E)*_dist),len(spl_E)-1)
         _tmp_E[i] = spl_E[_ind]
     return _tmp_E
Esempio n. 8
0
 def adjust_direction(self, atoms):
     if not self.adjust:
         return
     p1, p2 = atoms.positions[self.indices]
     direction, _ = find_mic(np.array([p2 - p1]), atoms._cell, pbc=False)
     direction = direction[0]                                                       
     direction[2] = 0.
     distance = np.linalg.norm(direction)
     direction /= distance
     self.direction = direction
     self.distance = distance
Esempio n. 9
0
def calculate_constraint(at, tipatoms):
    f = at.get_array('force')
    cnstr = SlowGrowthBondLength(*tipatoms, bond_speed=0., direction=tipatoms)
    cnstr.adjust_forces(at, f)

    p1, p2 = at.positions[tipatoms]
    d, _ = find_mic(np.array([p2 - p1]), at._cell, pbc=False)
    d = d[0]
    d = np.dot(d, cnstr.direction)
    f_cnstr = np.dot(cnstr.get_constraint_force(), cnstr.direction)
    return np.abs(d), f_cnstr
Esempio n. 10
0
    def force_integrator(self,force=False,spline_points=100):
        tot_d = np.linalg.norm(find_mic(self.images[-1].get_positions() -
                            self.images[0].get_positions(),
                            self.images[0].get_cell(), self.images[0].pbc)[0])
        knot_dist = np.zeros(self.nimages)
        _U = np.zeros((self.nimages,3*self.natoms))
        _F = np.zeros((self.nimages,3*self.natoms))
        _U[0] = self.images[0].get_positions().reshape(3* self.natoms)
        _F[0] = self.forces[0].reshape(3*self.natoms)
        for _i,img in enumerate(self.images[1:]):
            _d = find_mic(img.get_positions() -
                        self.images[0].get_positions(),
                        self.images[0].get_cell(), self.images[0].pbc)[0]
            _d_b = np.linalg.norm(find_mic(img.get_positions() -
                        self.images[-1].get_positions(),
                        self.images[-1].get_cell(), self.images[-1].pbc)[0])
            knot_dist[_i+1] = .5*np.linalg.norm(_d)/tot_d + .5-.5*_d_b/tot_d
            _d += self.images[0].get_positions()
            _U[_i+1] = _d.reshape(3* self.natoms)
            _F[_i+1] = self.forces[_i+1].reshape(3*self.natoms)

        print 'knot_dist = ', list(knot_dist)
        U_spl = interp1d(knot_dist, _U.T, 'cubic')
        F_spl = interp1d(knot_dist, _F.T, 'cubic')

        #r = np.linspace(0., 1.+1./(spline_points-1), spline_points+1, endpoint=False)
        r = np.linspace(0., 1.0, spline_points, endpoint=True)
        dU_spl = U_spl._spline.derivative()
        dU = dU_spl(r)
        F = F_spl(r).T
        #dU = spleval(U_spl._spline, r, deriv=1)
        #F = spleval(F_spl._spline, r, deriv=0)

        splined_force = (dU * F).sum(axis=1)
        splined_energy = -cumtrapz(splined_force, r)

        if force:
            return r[:-1], splined_energy, splined_force[:-1]
        else:
            return r[:-1], splined_energy
Esempio n. 11
0
 def adjust_forces(self, atoms, forces):
     d = np.subtract.reduce(atoms.positions[self.indices])
     d, p = find_mic(np.array([d]), atoms._cell, pbc=False)
     d = d[0]
     if self.direction is None:
         f = 0.5 * d * np.dot(np.subtract.reduce(forces[self.indices]), d) / p**2
     else:
         if self.adjust:
             self.adjust_direction(atoms)
             f = 0.5 * np.dot(np.subtract.reduce(forces[self.indices]), self.direction) * self.direction
         else:
             f = 0.5 * np.dot(np.subtract.reduce(forces[self.indices]), self.direction) * np.sign(np.dot(d, self.direction)) * self.direction
     self.constraint_force = f
     forces[self.indices] += (-f, f)
Esempio n. 12
0
def interpolate(images, mic=False):
    """Given a list of images, linearly interpolate the positions of the
    interior images."""
    pos1 = images[0].get_positions()
    pos2 = images[-1].get_positions()
    d = pos2 - pos1
    if mic:
        d = find_mic(d, images[0].get_cell(), images[0].pbc)[0]
    d /= (len(images) - 1.0)
    for i in range(1, len(images) - 1):
        images[i].set_positions(pos1 + i * d)
        # Parallel NEB with Jacapo needs this:
        try:
            images[i].get_calculator().set_atoms(images[i])
        except AttributeError:
            pass
Esempio n. 13
0
def interpolate(images, mic=False):
    """Given a list of images, linearly interpolate the positions of the
    interior images."""
    pos1 = images[0].get_positions()
    pos2 = images[-1].get_positions()
    d = pos2 - pos1
    if mic:
        d = find_mic(d, images[0].get_cell(), images[0].pbc)[0]
    d /= (len(images) - 1.0)
    for i in range(1, len(images) - 1):
        images[i].set_positions(pos1 + i * d)
        # Parallel NEB with Jacapo needs this:
        try:
            images[i].get_calculator().set_atoms(images[i])
        except AttributeError:
            pass
Esempio n. 14
0
 def interpolate(self, initial=0, final=-1, mic=False):
     """Interpolate linearly between initial and final images."""
     if final < 0:
         final = self.nimages + final
     n = final - initial
     pos1 = self.images[initial].get_positions()
     pos2 = self.images[final].get_positions()
     dist = (pos2 - pos1)
     if mic:
         cell = self.images[initial].get_cell()
         assert((cell == self.images[final].get_cell()).all())
         pbc = self.images[initial].get_pbc()
         assert((pbc == self.images[final].get_pbc()).all())
         dist, D_len = find_mic(dist, cell, pbc)
     dist /= n
     for i in range(1, n):
         self.images[initial + i].set_positions(pos1 + i * dist)
Esempio n. 15
0
    def calculate(self, atoms, properties, system_changes):
        Calculator.calculate(self, atoms, properties, system_changes)

        P = atoms.get_positions()
        d = []
        D = []
        for p in P:
            Di = P - p
            if self.mic:
                Di, di = find_mic(Di, atoms.get_cell(), atoms.get_pbc())
            else:
                di = np.sqrt((Di**2).sum(1))
            d.append(di)
            D.append(Di)
        d = np.array(d)
        D = np.array(D)

        dd = d - self.target
        d.ravel()[::len(d) + 1] = 1  # avoid dividing by zero
        d4 = d**4
        e = 0.5 * (dd**2 / d4).sum()
        f = -2 * ((dd * (1 - 2 * dd / d) / d**5)[..., np.newaxis] * D).sum(0)
        self.results = {'energy': e, 'forces': f}
Esempio n. 16
0
    def calculate(self, atoms, properties, system_changes):
        Calculator.calculate(self, atoms, properties, system_changes)

        P = atoms.get_positions()
        d = []
        D = []
        for p in P:
            Di = P - p
            if self.mic:
                Di, di = find_mic(Di, atoms.get_cell(), atoms.get_pbc())
            else:
                di = np.sqrt((Di**2).sum(1))
            d.append(di)
            D.append(Di)
        d = np.array(d)
        D = np.array(D)

        dd = d - self.target
        d.ravel()[::len(d) + 1] = 1  # avoid dividing by zero
        d4 = d**4
        e = 0.5 * (dd**2 / d4).sum()
        f = -2 * ((dd * (1 - 2 * dd / d) / d**5)[..., np.newaxis] * D).sum(0)
        self.results = {'energy': e, 'forces': f}
Esempio n. 17
0
    def get_forces(self):
        """Evaluate and return the forces."""
        images = self.images
        forces = np.empty(((self.nimages - 2), self.natoms, 3))
        energies = np.empty(self.nimages - 2)

        if not self.parallel:
            # Do all images - one at a time:
            for i in range(1, self.nimages - 1):
                energies[i - 1] = images[i].get_potential_energy()
                forces[i - 1] = images[i].get_forces()
        elif self.world.size == 1:
            def run(image, energies, forces):
                energies[:] = image.get_potential_energy()
                forces[:] = image.get_forces()
            threads = [threading.Thread(target=run,
                                        args=(images[i],
                                              energies[i - 1:i],
                                              forces[i - 1:i]))
                       for i in range(1, self.nimages - 1)]
            for thread in threads:
                thread.start()
            for thread in threads:
                thread.join()
        else:
            # Parallelize over images:
            i = self.world.rank * (self.nimages - 2) // self.world.size + 1
            try:
                energies[i - 1] = images[i].get_potential_energy()
                forces[i - 1] = images[i].get_forces()
            except:
                # Make sure other images also fail:
                error = self.world.sum(1.0)
                raise
            else:
                error = self.world.sum(0.0)
                if error:
                    raise RuntimeError('Parallel NEB failed!')

            for i in range(1, self.nimages - 1):
                root = (i - 1) * self.world.size // (self.nimages - 2)
                self.world.broadcast(energies[i - 1:i], root)
                self.world.broadcast(forces[i - 1], root)

        imax = 1 + np.argsort(energies)[-1]
        self.emax = energies[imax - 1]

        tangent1 = find_mic(images[1].get_positions() -
                            images[0].get_positions(),
                            images[0].get_cell(), images[0].pbc)[0]
        for i in range(1, self.nimages - 1):
            tangent2 = find_mic(images[i + 1].get_positions() -
                                images[i].get_positions(),
                                images[i].get_cell(),
                                images[i].pbc)[0]
            if i < imax:
                tangent = tangent2
            elif i > imax:
                tangent = tangent1
            else:
                tangent = tangent1 + tangent2

            tt = np.vdot(tangent, tangent)
            f = forces[i - 1]
            ft = np.vdot(f, tangent)
            if i == imax and self.climb:
                f -= 2 * ft / tt * tangent
            else:
                f -= ft / tt * tangent
                f -= np.vdot(tangent1 * self.k[i - 1] -
                             tangent2 * self.k[i], tangent) / tt * tangent

            tangent1 = tangent2

        return forces.reshape((-1, 3))
Esempio n. 18
0
    def get_forces(self):
        """Evaluate and return the forces."""
        images = self.images
        forces = np.empty(((self.nimages - 2), self.natoms, 3))
        energies = np.empty(self.nimages-2)
        if not self.parallel:
            for i in range(1, self.nimages - 1):
                if self.force_only:
                    energies[i - 1] = 0.
                else:
                    energies[i - 1] = images[i].get_potential_energy()
                forces[i - 1] = images[i].get_forces()

        elif self.world.size == 1:
            def run(image, energies, forces):
                if self.force_only:
                    energies[:] = 0.
                else:
                    energies[:] = image.get_potential_energy()
                forces[:] = image.get_forces()
            threads = [threading.Thread(target=run,
                                        args=(images[i],
                                              energies[i - 1:i],
                                              forces[i - 1:i]))
                       for i in range(1, self.nimages - 1)]
            for thread in threads:
                thread.start()
            for thread in threads:
                thread.join()
        else:
            # Parallelize over images:
            i = self.world.rank * (self.nimages - 2) // self.world.size + 1
            try:
                if self.force_only:
                    energies[i - 1] = 0.
                else:
                    energies[i - 1] = images[i].get_potential_energy()
                forces[i - 1] = images[i].get_forces()
            except:
                # Make sure other images also fail:
                error = self.world.sum(1.0)
                raise
            else:
                error = self.world.sum(0.0)
                if error:
                    raise RuntimeError('Parallel NEB failed!')

            for i in range(1, self.nimages - 1):
                root = (i - 1) * self.world.size // (self.nimages - 2)
                self.world.broadcast(energies[i - 1:i], root)
                self.world.broadcast(forces[i - 1], root)

        for i in range(1, self.nimages - 1):
            self.forces[i] = forces[i-1].copy()
            self.energies[i] = energies[i-1].copy()

        if self.force_only and self.climb:
            self.energies = self.get_potential_energies()
            energies = self.energies[1:-1]

        if self.force_only == True and self.climb == False:
            imax = self.nimages // 2  # just to avoid non-assigned error
        else:
            imax = 1 + np.argsort(energies)[-1]

        self.emax = energies[imax - 1]

        # Backwards tangent
        tangent1 = find_mic(images[1].get_positions() -
                                images[0].get_positions(),
                                images[0].get_cell(), images[0].pbc)[0]
        for i in range(1, self.nimages - 1):
            # Forwards tangent
            tangent2 = find_mic(images[i + 1].get_positions() -
                                images[i].get_positions(),
                                images[i].get_cell(),
                               images[i].pbc)[0]
            if i < imax:
                tangent = tangent2
            elif i > imax:
                tangent = tangent1
            else:
                tangent = tangent1 + tangent2
            if self.modified_neb:
                cos_t = np.vdot(tangent1, tangent2) / \
                    np.linalg.norm(tangent1) / np.linalg.norm(tangent2)
                f_c_t = .5 * (1. + np.cos(np.pi * cos_t))
            else:
                f_c_t = 0.
            tt = np.vdot(tangent, tangent)
            f = forces[i - 1]
            ft = np.vdot(f, tangent)
            if i == imax and self.climb:
                f -= 2 * ft / tt * tangent
            else:
                # -= F.T/|T| * T/|T| perp. MD force
                f -= ft / tt * tangent
                # f -= k(|T2| - |T1|) * (T/|T|) ~ ll spring force
                f -= (self.k[i-1]*np.linalg.norm(tangent1)-self.k[i] * \
                        np.linalg.norm(tangent2)) * tangent / np.sqrt(tt)
                if self.modified_neb:
                    f -= np.vdot(tangent1 * self.k[i - 1] - tangent2 * \
                                 self.k[i], tangent) / tt * tangent * (-f_c_t)
                    f -= (tangent1 * self.k[i - 1] - \
                          tangent2 * self.k[i]) * f_c_t

            tangent1 = tangent2.copy()
        return forces.reshape((-1, 3))
Esempio n. 19
0
try:
    clamp_mask = at.get_array('clamp_mask')
    fix_line_mask = at.get_array('fix_line_mask')
    initial_positions = at.get_array('pos_orig')
except:
    at_help = quippy.Atoms('crack.xyz')
    clamp_mask = at_help.get_array('clamp_mask')
    # fix_line_mask = at_help.get_array('fix_line_mask')
    initial_positions = at_help.get_array('pos_orig')
    at_help = None

at.set_calculator(calc)

# set atoms order
_, dists = find_mic(initial_positions - initial_positions[tipatoms[0]],
                    at.get_cell())
at_order = np.argsort(dists)[:120]

# ***** Setup constraints *****
# springs = [Hookean(a1=i, a2=[0,-1,0,initial_positions[i,1]], k=k_spring, rt=0) for i in np.where(clamp_mask)[0]]
springs = [
    Hookean(a1=i, a2=initial_positions[i], k=params.k_spring, rt=0)
    for i in np.where(clamp_mask)[0]
]

from ase.constraints import FixedLine
left = initial_positions[:, 0].min()
right = initial_positions[:, 0].max()
fix_line_mask = np.logical_or(initial_positions[:, 0] > right - 5.,
                              initial_positions[:, 0] < left + 5.)
fix_line_idx = np.where(fix_line_mask)[0]