Beispiel #1
0
 def rotation_plane(self, Fperp, Fperp_old, Nold):
     if self.rotationOpt == 'sd':
         self.T = vunit(Fperp)
     elif self.rotationOpt == 'cg':
         # determine self.T (big theta in the paper) with CG method
         a = abs(np.vdot(Fperp, Fperp_old))
         b = np.vdot(Fperp_old, Fperp_old)
         if a <= 0.5 * b and b != 0:
             gamma = np.vdot(Fperp, Fperp - Fperp_old) / b
         else:
             gamma = 0
         try:
             self.Tnorm
         except:
             self.Tnorm = 0.0
         Ttmp = Fperp + gamma * self.T * self.Tnorm
         Ttmp = Ttmp - np.vdot(Ttmp, self.N) * self.N
         self.Tnorm = np.linalg.norm(Ttmp)
         self.T = vunit(Ttmp)
     elif self.rotationOpt == 'bfgs':
         ## BFGS from wiki
         Binv = self.Binv
         #s       =  (self.N - Nold).flatten()  * self.dR
         #g1      =  -Fperp.flatten()
         #g0      =  -Fperp_old.flatten()
         s = (self.N - Nold).flatten()
         g1 = -Fperp.flatten() / self.dR
         g0 = -Fperp_old.flatten() / self.dR
         y = g1 - g0
         '''
         ## updating the inverse Hessian
         a = np.dot(s, y)
         b = np.dot(y, Binv.dot(y))
         c = np.outer(s, s)
         d = np.outer(y, s) 
         print "a, b:", a, b
         Binv      = Binv + (a+b) * c / a**2 - (Binv.dot(d) + d.T.dot(Binv)) / a
         self.Binv = Binv
         dr        = (Binv.dot(-g1)).reshape((-1, 3))
         '''
         ## updating Hessian rather than the inverse Hessian, see ase.optimize.BFGS
         a = np.dot(s, y)
         dg = np.dot(self.B, s)
         b = np.dot(s, dg)
         #print "a, b", a, b
         self.B += np.outer(y, y) / a - np.outer(dg, dg) / b
         omega, V = np.linalg.eigh(self.B)
         dr = np.dot(V, np.dot(-g1, V) / np.fabs(omega)).reshape((-1, 3))
         vd = np.vdot(vunit(dr), vunit(Fperp))
         if vd < 0.05:
             #print "////reset BFGS in rotation////"
             dr = Fperp
             self.B = self.B0
         dr -= np.vdot(dr, self.N) * self.N
         self.T = vunit(dr)
Beispiel #2
0
 def project_translt_rott(self, N, R0):
     if not self.noZeroModes: return N
     # Project out rigid translational mode
     for axisx in range(3):
         transVec = np.zeros((self.natom + 3, 3))
         transVec[:, axisx] = 1.0
         transVec = vunit(transVec)
         N -= np.vdot(N, transVec) * transVec
     # Project out rigid rotational mode
     for axisx in ['x', 'y', 'z']:
         ptmp = R0.copy()
         # rotate a small angle around the center of mass
         ptmp.rotate(axisx, 0.02, center='COM', rotate_cell=False)
         rottVec = ptmp.get_positions() - R0.get_positions()
         rottVec = vunit(rottVec)
         #if np.vdot(N[:-3], rottVec) > 0.1: print "mainly rotation around "+axisx
         N[:-3] -= np.vdot(N[:-3], rottVec) * rottVec
     return N
Beispiel #3
0
 def rotation_plane(self, Fperp, Fperp_old, mode):
     # determine self.T (big theta in the paper) with CG method
     a = abs(np.vdot(Fperp, Fperp_old))
     b = np.vdot(Fperp_old, Fperp_old)
     if a <= 0.5*b and b != 0:  
         gamma = np.vdot(Fperp, Fperp-Fperp_old) / b
     else:
         gamma = 0
     Ttmp       = Fperp + gamma * self.T * self.Tnorm
     Ttmp       = Ttmp - np.vdot(Ttmp, mode) * mode
     self.Tnorm = np.linalg.norm(Ttmp)
     self.T     = vunit(Ttmp)
Beispiel #4
0
    def step(self):
        if self.steps == 0:
            if self.ss:
                self.V = np.zeros((self.natom + 3, 3))
            else:
                self.V = np.zeros((self.natom, 3))
        self.steps += 1
        Ftrans = self.get_forces()
        print "Ftrans", vmag(Ftrans)
        dV = Ftrans * self.dT
        if np.vdot(self.V, Ftrans) > 0:
            self.V = dV * (1.0 + np.vdot(dV, self.V) / np.vdot(dV, dV))
        else:
            self.V = dV

        step = self.V * self.dT
        if vmag(step) > self.maxStep:
            step = self.maxStep * vunit(step)

        self.set_positions(self.get_positions() + step)
        self.E = self.get_potential_energy()
Beispiel #5
0
mode[-3:] = pfin.get_cell() - p.get_cell()
icell = np.linalg.inv(p.get_cell())
mode[-3:] = np.dot(icell, mode[-3:]) * jacob

#######################################
# set the initial mode randomly
#mode = np.zeros((len(p1)+3,3))
#mode = vrand(mode)
#constrain 3 redundant freedoms
#mode[0]    *=0
#mode[-3,1:]*=0
#mode[-2,2] *=0
#######################################

# displace along the initial mode direction
mode = vunit(mode)
cellt = p.get_cell() + np.dot(p.get_cell(), mode[-3:] / jacob)
p.set_cell(cellt, scale_atoms=True)
p.set_positions(p.get_positions() + mode[:-3])

# set a ssdimer_atoms object
d = ssdimer.SSDimer_atoms(p, mode=mode, rotationMax=4, phi_tol=15)

#################################################
# use quickmin optimizer in ssdimer
d.search(minForce=0.0001, movie="dimer2.movie", interval=20)
#################################################
# use MDMin optimizer in ase
#dyn = MDMin(d)
#dyn.run(fmax=0.0001)
#################################################
Beispiel #6
0
    def minmodesearch(self):
        # rotate dimer to the minimum mode direction
        # self.N, the dimer direction;
        # self.T, the rotation direction, spans the rotation plane with self.N.

        # project out any rigid translation and rotation
        if not self.ss: self.N = self.project_translt_rott(self.N, self.R0)

        F0 = self.update_general_forces(self.R0)
        F1 = self.rotation_update()

        phi_min = 1.5
        Fperp = F1 * 0.0  # avoid Fperp_old asignment error
        iteration = 0
        while abs(phi_min) > self.phi_tol and iteration < self.rotationMax:

            if iteration == 0:
                F0perp = F0 - np.vdot(F0, self.N) * self.N
                F1perp = F1 - np.vdot(F1, self.N) * self.N
                Fperp = 2.0 * (F1perp - F0perp)
                self.T = vunit(Fperp)

            # project out any rigid translation and rotation
            if not self.ss: self.T = self.project_translt_rott(self.T, self.R0)

            # curvature and its derivative
            c0 = np.vdot(F0 - F1, self.N) / self.dR
            c0d = np.vdot(F0 - F1, self.T) / self.dR * 2.0
            phi_1 = -0.5 * atan(c0d / (2.0 * abs(c0)))
            if abs(phi_1) <= self.phi_tol: break

            # calculate F_prime: force after rotating the dimer by phi_prime
            N1_prime = vunit(self.N * cos(phi_1) + self.T * sin(phi_1))
            self.iset_endpoint_pos(N1_prime, self.R0, self.R1_prime)
            F1_prime = self.update_general_forces(self.R1_prime)
            c0_prime = np.vdot(F0 - F1_prime, N1_prime) / self.dR

            # calculate phi_min
            b1 = 0.5 * c0d
            a1 = (c0 - c0_prime + b1 * sin(2 * phi_1)) / (1 - cos(2 * phi_1))
            a0 = 2 * (c0 - a1)
            phi_min = 0.5 * atan(b1 / a1)
            c0_min = 0.5 * a0 + a1 * cos(2.0 * phi_min) + b1 * sin(2 * phi_min)

            # check whether it is minimum or maximum
            if c0_min > c0:
                phi_min += pi * 0.5
                c0_min = 0.5 * a0 + a1 * cos(2.0 * phi_min) + b1 * sin(
                    2 * phi_min)
            ## for accurate BFGS s
            if phi_min > pi * 0.5: phi_min -= pi

            # update self.N
            Nold = self.N
            self.N = vunit(self.N * cos(phi_min) + self.T * sin(phi_min))
            # project out any rigid translation and rotation
            if not self.ss: self.N = self.project_translt_rott(self.N, self.R0)
            c0 = c0_min

            # update F1 by linear extropolation
            F1 = F1 * (sin(phi_1 - phi_min) / sin(phi_1)) + F1_prime * (sin(phi_min) / sin(phi_1)) \
                 + F0 * (1.0 - cos(phi_min) - sin(phi_min) * tan(phi_1 * 0.5))

            F0perp = F0 - np.vdot(F0, self.N) * self.N
            F1perp = F1 - np.vdot(F1, self.N) * self.N
            Fperp_old = Fperp
            Fperp = 2.0 * (F1perp - F0perp)
            # update self.T
            self.rotation_plane(Fperp, Fperp_old, Nold)

            iteration += 1
        self.curvature = c0
        return F0
Beispiel #7
0
    def __init__(self,
                 R0=None,
                 mode=None,
                 maxStep=0.2,
                 dT=0.1,
                 dR=0.001,
                 phi_tol=5,
                 rotationMax=4,
                 ss=False,
                 express=np.zeros((3, 3)),
                 rotationOpt='cg',
                 weight=1,
                 noZeroModes=True):
        """
        Parameters:
        R0      - an atoms object, which gives the starting point
        mode    - initial mode (will be randomized if one is not provided)
        maxStep - longest distance dimer can move in a single iteration
        dT      - quickmin timestep
        dR      - separation between the two images for rotation
        phi_tol - rotation converging tolerence, degree
        rotationMax - max rotations per translational step
        ss      - boolean, solid-state dimer or not
        express - 3*3 matrix, external stress tensor. Columns are the stress vectors. Needs to be in lower triangular form to avoid rigid rotation. 
        rotation_opt - the optimization method for the rotation part: choose from "sd" (steepest descent), "cg" (conjugate gradient), and "bfgs".
        noZeroModes  - boolean, project out the six zero modes or not. For some 2D analytical potential, it needs to be False.
        weight  - extra weight to put on the cell degrees of freedom.
                 
        """
        self.steps = 0
        self.dT = dT
        self.dR = dR
        self.phi_tol = phi_tol / 180.0 * pi
        self.R0 = R0
        self.N = mode
        self.natom = self.R0.get_number_of_atoms()
        if self.N == None:
            print "radomly initialize the lowest eigenvector"
            self.N = vrand(np.zeros((self.natom + 3, 3)))
            self.N[-3:] *= 0.0
        elif len(self.N) == self.natom:
            self.N = np.vstack((mode, np.zeros((3, 3))))
        self.N = vunit(self.N)
        self.maxStep = maxStep
        self.Ftrans = None
        self.forceCalls = 0
        self.R1 = self.R0.copy()
        self.R1_prime = self.R0.copy()
        calc = self.R0.get_calculator()
        self.R1.set_calculator(calc)
        self.R1_prime.set_calculator(calc)
        self.rotationMax = rotationMax
        self.rotationOpt = rotationOpt
        self.noZeroModes = noZeroModes  # Set to False for 2D model potentials
        self.ss = ss
        self.express = express

        vol = self.R0.get_volume()
        avglen = (vol / self.natom)**(1.0 / 3.0)
        self.weight = weight
        self.jacobian = avglen * self.natom**0.5 * self.weight

        if self.rotationOpt == 'bfgs':
            ## BFGS for rotation: initial (inverse) Hessian
            ndim = (self.natom + 3) * 3
            self.Binv0 = np.eye(ndim) / 60
            self.Binv = self.Binv0
            self.B0 = np.eye(ndim) * 60
            self.B = self.B0
Beispiel #8
0
    def minmodesearch(self):
        F0 = self.update_general_forces(self.R0)
        F1 = self.rotation_update()
        dphi = 100

        ## only for atom degree of freedoms
        #u = self.N[:-3].flatten()
        ## include cell too
        u = self.N.flatten()
        beta = vmag(u)
        size = (self.natom + 3) * 3
        #size = self.natom * 3
        T = np.zeros((size, size))
        Q = np.zeros((size, size))

        #while dphi > self.phi_tol and iteration < self.rotationMax:
        for i in range(size):
            Q[:, i] = u / beta
            Hv = -(F1 - F0) / self.dR
            #u       = Hv[:-3].flatten()
            u = Hv.flatten()
            if i > 0:
                u = u - beta * Q[:, i - 1]
            alpha = np.vdot(Q[:, i], u)
            u = u - alpha * Q[:, i]
            # re-orthogonalize
            u = u - np.dot(Q, np.dot(Q.T, u))

            T[i, i] = alpha
            if i > 0:
                T[i - 1, i] = beta
                T[i, i - 1] = beta

            beta = vmag(u)

            newN = np.reshape(u / beta, (-1, 3))
            #self.N[:-3] = newN
            self.N = newN
            F1 = self.rotation_update()

            ##Check Eigenvalues
            if i > 0:
                eigenValues, eigenVectors = np.linalg.eig(T[:i + 1, :i + 1])
                idx = eigenValues.argsort()
                ew = eigenValues[idx][0]
                evT = eigenVectors[:, idx][:, 0]
                ##Convert eigenvector of T matrix to eigenvector of full Hessian
                evEst = Q[:, :i + 1].dot(evT)
                evEst = vunit(evEst)
                evAtom_old = copy.copy(evAtom)
                evAtom = np.reshape(evEst, (-1, 3))
                c0 = ew
                ## check with pi/2
                dotp = np.vdot(evAtom, evAtom_old)
                if dotp > 1: dotp = 1
                elif dotp < -1: dotp = -1
                dphi = np.arccos(dotp)
                if dphi > np.pi / 2.0: dphi = np.pi - dphi
            else:
                #evAtom  = self.N[:-3]
                #c0      = np.vdot(Hv[:-3], evAtom)
                evAtom = self.N
                c0 = np.vdot(Hv, evAtom)
            #print "i, Curvature, dphi:", i, c0, dphi
            if dphi < self.phi_tol or i == size - 1 or i >= self.rotationMax:
                #self.N[:-3] = evAtom
                self.N = evAtom
                break

        self.curvature = c0
        return F0
Beispiel #9
0
    def minmodesearch(self, minoriso):
        # rotate dimer to the minimum mode direction
        # self.N, the dimer direction; 
        # self.T, the rotation direction, spans the rotation plane with self.N.

        ## self.N or self.Contour
        if minoriso == "min":
            self.F0 = self.update_general_forces(self.R0)
            mode    = self.N.copy()
        else:
            F0unit  = vunit(self.F0)
            mode    = self.Contour.copy()
            mode    = mode - np.vdot(mode, F0unit) * F0unit

        # project out any rigid translation and rotation
        if not self.ss: mode    = self.project_translt_rott(mode, self.R0)

        F0    = self.F0
        F1    = self.rotation_update(mode)

        phi_min = 1.5
        Fperp   = F1 * 0.0 # avoid Fperp_old asignment error
        iteration = 0
            
        while iteration < self.rotationMax:
            
            ## self.N or self.Contour
            if minoriso == "min":
                if phi_min <= self.phi_tol: break
                F0perp    = F0 - np.vdot(F0, mode) * mode
                F1perp    = F1 - np.vdot(F1, mode) * mode
            else:
                if phi_min <= self.phi_iso: break
                mode      = mode - np.vdot(mode, F0unit) * F0unit
                F0perp    = F0 * 0.0
                F1iso     = F1 - np.vdot(F1, F0unit) * F0unit
                F1perp    = F1iso - np.vdot(F1iso, mode) * mode

            Fperp_old = Fperp
            Fperp     = 2.0 * (F1perp - F0perp)
            if iteration == 0: 
                Fperp_old = Fperp
                self.T    = mode * 0.0
                self.Tnorm= 0.0
            # update self.T
            self.rotation_plane(Fperp, Fperp_old, mode)
            if minoriso == "iso": 
                self.T = self.T - np.vdot(self.T, F0unit) * F0unit
                self.T = vunit(self.T)

            # project out any rigid translation and rotation
            if not self.ss: self.T = self.project_translt_rott(self.T, self.R0)

            # curvature and its derivative
            c0     = np.vdot(F0-F1, mode) / self.dR
            c0d    = np.vdot(F0-F1, self.T) / self.dR * 2.0
            phi_1  = -0.5 * atan(c0d / (2.0 * abs(c0)))

            if abs(phi_1) <= self.phi_tol: break
            # calculate F_prime: force after rotating the dimer by phi_prime
            N1_prime = vunit(mode * cos(phi_1) + self.T * sin(phi_1))
            self.iset_endpoint_pos(N1_prime, self.R0, self.R1_prime)
            F1_prime = self.update_general_forces(self.R1_prime)
            c0_prime = np.vdot(F0-F1_prime, N1_prime) / self.dR 
            
            # calculate phi_min
            b1 = 0.5 * c0d
            a1 = (c0 - c0_prime + b1 * sin(2 * phi_1)) / (1 - cos(2 * phi_1))
            a0 = 2 * (c0 - a1)
            phi_min = 0.5 * atan(b1 / a1)
            c0_min  = 0.5 * a0 + a1 * cos(2.0 * phi_min) + b1 * sin(2 * phi_min)

            # check whether it is minimum or maximum
            if c0_min > c0 :
                phi_min += pi * 0.5
                c0_min   = 0.5 * a0 + a1 * cos(2.0 * phi_min) + b1 * sin(2 * phi_min)
                 
            # update self.N
            mode = vunit(mode * cos(phi_min) + self.T * sin(phi_min))
            c0 = c0_min
            # update F1 by linear extropolation
            F1 = F1 * (sin(phi_1 - phi_min) / sin(phi_1)) + F1_prime * (sin(phi_min) / sin(phi_1)) \
                 + F0 * (1.0 - cos(phi_min) - sin(phi_min) * tan(phi_1 * 0.5))
            #print "phi_min:", phi_min, "toque:", vmag(Fperp)
            iteration += 1

        if minoriso == "min":
            self.curvature = c0
            self.N         = mode.copy()
            '''
            ## estimate the curvature of the isophote (isoenergy curve)
            Fg = vunit(F0)
            cosalpha = abs(np.vdot(Fg, self.N)) 
            print "cosalpha", cosalpha
            if cosalpha > 0.01 and cosalpha < 0.999:
                N1_prime = vunit(self.N - np.vdot(Fg, self.N)*Fg)
                self.iset_endpoint_pos(N1_prime, self.R0, self.R1_prime)
                F1_prime = self.update_general_forces(self.R1_prime)
                c0_prime = np.vdot(F0-F1_prime, N1_prime) / self.dR 
                self.kappa = -c0_prime/vmag(F0)
            else: 
                self.kappa = -0.25
            '''
        else:
            self.isocurv   = -c0/vmag(F0)
            self.Contour   = mode.copy()
            print "isocurv iteration:", iteration
        return F0