Пример #1
0
class Strain(ForceField):
    def __init__(self, system, term, other_terms, cart_penalty=1e-3*angstrom):
        '''
            A class deriving from the Yaff ForceField class to implement the
            strain of a molecular geometry associated with the term defined by
            term_index.

            **Arguments**

            system
                A Yaff System instance containing all system information.

            term
                a Term instance representing the term of the perturbation
                trajectory of the current strain

            other_terms
                a list of Term instances representing all other terms for ICs
                for which a strain contribution should be added

            **Keyword Arguments**

            cart_penalty
                Magnitude of an extra term added to the strain that penalises
                a deviation of the cartesian coordinates of each atom with
                respect to the equilibrium coordinates. This penalty is equal
                to norm(R-R_eq)**2/(2.0*3*Natoms*cart_penalty**2) and prevents
                global translations, global rotations as well as rotations of
                molecular fragments far from the IC under consideration.
        '''
        self.coords0 = system.pos.copy()
        self.ndof = np.prod(self.coords0.shape)
        self.cart_penalty = cart_penalty
        self.cons_ic_atindexes = term.get_atoms()
        #construct main strain
        strain = ForcePartValence(system)
        for other in other_terms:
            if other.kind == 3: continue #no cross terms
            strain.add_term(Harmonic(1.0, None, other.ics[0]))
        #set the rest values to the equilibrium values
        strain.dlist.forward()
        strain.iclist.forward()
        for iterm in range(strain.vlist.nv):
            vterm = strain.vlist.vtab[iterm]
            ic = strain.iclist.ictab[vterm['ic0']]
            vterm['par1'] = ic['value']
        ForceField.__init__(self, system, [strain])
        #Abuse the Chebychev1 polynomial to simply get the value of q-1 and
        #implement the contraint
        constraint = ForcePartValence(system)
        constraint.add_term(Chebychev1(-2.0,term.ics[0]))
        self.constraint = ForceField(system, [constraint])
        self.constrain_target = None
        self.constrain_value = None
        self.value = None

    def gradient(self, X):
        '''
            Compute the gradient of the strain w.r.t. Cartesian coordinates of
            the system. For the ic that needs to be constrained, a Lagrange
            multiplier is included.
        '''
        #initialize return value
        grad = np.zeros((len(X),))
        #compute strain gradient
        gstrain = np.zeros(self.coords0.shape)
        self.update_pos(self.coords0 + X[:self.ndof].reshape((-1,3)))
        self.value = self.compute(gpos=gstrain)
        #compute constraint gradient
        gconstraint = np.zeros(self.coords0.shape)
        self.constraint.update_pos(self.coords0 + X[:self.ndof].reshape((-1,3)))
        self.constrain_value = self.constraint.compute(gpos=gconstraint) + 1.0
        #construct gradient
        grad[:self.ndof] = gstrain.reshape((-1,)) + X[self.ndof]*gconstraint.reshape((-1,))
        grad[self.ndof] = self.constrain_value - self.constrain_target
        #cartesian penalty, i.e. extra penalty for deviation w.r.t. cartesian equilibrium coords
        indices = np.array([[3*i,3*i+1,3*i+2] for i in range(self.ndof//3) if i not in self.cons_ic_atindexes]).ravel()
        if len(indices)>0:
            grad[indices] += X[indices]/(self.ndof*self.cart_penalty**2)
        with log.section('PTGEN', 4, timer='PT Generate'):
            log.dump('      Gradient:  rms = %.3e  max = %.3e  cnstr = %.3e' %(np.sqrt((grad[:self.ndof]**2).mean()), max(grad[:self.ndof]), grad[self.ndof]))
        return grad
Пример #2
0
class Strain(ForceField):
    def __init__(self,
                 system,
                 cons_ic,
                 cons_ic_atindexes,
                 ics,
                 cart_penalty=1e-3 * angstrom):
        '''
            A class deriving from the Yaff ForceField class to implement the
            strain of a molecular geometry associated with the term defined by
            term_index.

            **Arguments**

            system
                A Yaff System instance containing all system information.

            cons_ic
                An instance of Yaff Internal Coordinate representing the
                constrained term in the strain.

            cons_ic_atindexes
                A list of the atoms involved in the constrained IC. This is
                required for the implementation of the cartesian penalty. In
                principle this could be extracted from the information stored
                in cons_ic, but this is the lazy solution.

            ics
                A list of Yaff Internal Coordinate instances for which the
                strain needs to be minimized.

            cart_penalty
                Magnitude of an extra term added to the strain that penalises
                a deviation of the cartesian coordinates of each atom with
                respect to the equilibrium coordinates. This penalty is equal
                to norm(R-R_eq)**2/(2.0*3*Natoms*cart_penalty**2) and prevents
                global translations, global rotations as well as rotations of
                molecular fragments far from the IC under consideration.
        '''
        self.coords0 = system.pos.copy()
        self.ndof = np.prod(self.coords0.shape)
        self.cart_penalty = cart_penalty
        self.cons_ic_atindexes = cons_ic_atindexes
        part = ForcePartValence(system)
        for ic in ics:
            part.add_term(Harmonic(1.0, None, ic))
        #set the rest values to the equilibrium values
        part.dlist.forward()
        part.iclist.forward()
        for iterm in xrange(part.vlist.nv):
            term = part.vlist.vtab[iterm]
            ic = part.iclist.ictab[term['ic0']]
            term['par1'] = ic['value']
        ForceField.__init__(self, system, [part])
        #Abuse the Chebychev1 polynomial to simply get the value of q-1 and
        #implement the contraint
        part = ForcePartValence(system)
        part.add_term(Chebychev1(-2.0, cons_ic))
        self.constraint = ForceField(system, [part])
        self.constrain_target = None
        self.constrain_value = None
        self.value = None

    def gradient(self, X):
        '''
            Compute the gradient of the strain wrt Cartesian coordinates of the
            system. For every ic that needs to be constrained, a Lagrange multiplier
            is included.
        '''
        #small check
        #assert X.shape[0] ==  self.ndof + 1
        #initialize return value
        grad = np.zeros((len(X), ))
        #compute strain gradient
        gstrain = np.zeros(self.coords0.shape)
        self.update_pos(self.coords0 + X[:self.ndof].reshape((-1, 3)))
        self.value = self.compute(gpos=gstrain)
        #compute constraint gradient
        gconstraint = np.zeros(self.coords0.shape)
        self.constraint.update_pos(self.coords0 +
                                   X[:self.ndof].reshape((-1, 3)))
        self.constrain_value = self.constraint.compute(gpos=gconstraint) + 1.0
        #construct gradient
        grad[:self.ndof] = gstrain.reshape(
            (-1, )) + X[self.ndof] * gconstraint.reshape((-1, ))
        grad[self.ndof] = self.constrain_value - self.constrain_target
        #cartesian penalty, i.e. extra penalty for deviation w.r.t. cartesian equilibrium coords
        indices = np.array([[3 * i, 3 * i + 1, 3 * i + 2]
                            for i in xrange(self.ndof / 3)
                            if i not in self.cons_ic_atindexes]).ravel()
        if len(indices) > 0:
            grad[indices] += X[indices] / (self.ndof * self.cart_penalty**2)
        with log.section('PTGEN', 4, timer='PT Generate'):
            log.dump('      Gradient:  rms = %.3e  max = %.3e  cnstr = %.3e' %
                     (np.sqrt(
                         (grad[:self.ndof]**2).mean()), max(
                             grad[:self.ndof]), grad[self.ndof]))
        return grad
Пример #3
0
class Strain(ForceField):
    def __init__(self, system, term, other_terms, cart_penalty=1e-3*angstrom):
        '''
            A class deriving from the Yaff ForceField class to implement the
            strain of a molecular geometry associated with the term defined by
            term_index.

            **Arguments**

            system
                A Yaff System instance containing all system information.

            term
                a Term instance representing the term of the perturbation
                trajectory of the current strain

            other_terms
                a list of Term instances representing all other terms for ICs
                for which a strain contribution should be added

            **Keyword Arguments**

            cart_penalty
                Magnitude of an extra term added to the strain that penalises
                a deviation of the cartesian coordinates of each atom with
                respect to the equilibrium coordinates. This penalty is equal
                to norm(R-R_eq)**2/(2.0*3*Natoms*cart_penalty**2) and prevents
                global translations, global rotations as well as rotations of
                molecular fragments far from the IC under consideration.
        '''
        self.coords0 = system.pos.copy()
        self.ndof = np.prod(self.coords0.shape)
        self.cart_penalty = cart_penalty
        self.cons_ic_atindexes = term.get_atoms()
        #construct main strain
        strain = ForcePartValence(system)
        for other in other_terms:
            if other.kind == 3: continue #no cross terms
            strain.add_term(Harmonic(1.0, None, other.ics[0]))
        #set the rest values to the equilibrium values
        strain.dlist.forward()
        strain.iclist.forward()
        for iterm in range(strain.vlist.nv):
            vterm = strain.vlist.vtab[iterm]
            ic = strain.iclist.ictab[vterm['ic0']]
            vterm['par1'] = ic['value']
        ForceField.__init__(self, system, [strain])
        #Abuse the Chebychev1 polynomial to simply get the value of q-1 and
        #implement the contraint
        constraint = ForcePartValence(system)
        constraint.add_term(Chebychev1(-2.0,term.ics[0]))
        self.constraint = ForceField(system, [constraint])
        self.constrain_target = None
        self.constrain_value = None
        self.value = None

    def gradient(self, X):
        '''
            Compute the gradient of the strain w.r.t. Cartesian coordinates of
            the system. For the ic that needs to be constrained, a Lagrange
            multiplier is included.
        '''
        #initialize return value
        grad = np.zeros((len(X),))
        #compute strain gradient
        gstrain = np.zeros(self.coords0.shape)
        self.update_pos(self.coords0 + X[:self.ndof].reshape((-1,3)))
        self.value = self.compute(gpos=gstrain)
        #compute constraint gradient
        gconstraint = np.zeros(self.coords0.shape)
        self.constraint.update_pos(self.coords0 + X[:self.ndof].reshape((-1,3)))
        self.constrain_value = self.constraint.compute(gpos=gconstraint) + 1.0
        #construct gradient
        grad[:self.ndof] = gstrain.reshape((-1,)) + X[self.ndof]*gconstraint.reshape((-1,))
        grad[self.ndof] = self.constrain_value - self.constrain_target
        #cartesian penalty, i.e. extra penalty for deviation w.r.t. cartesian equilibrium coords
        indices = np.array([[3*i,3*i+1,3*i+2] for i in range(self.ndof//3) if i not in self.cons_ic_atindexes]).ravel()
        if len(indices)>0:
            grad[indices] += X[indices]/(self.ndof*self.cart_penalty**2)
        with log.section('PTGEN', 4, timer='PT Generate'):
            log.dump('      Gradient:  rms = %.3e  max = %.3e  cnstr = %.3e' %(np.sqrt((grad[:self.ndof]**2).mean()), max(grad[:self.ndof]), grad[self.ndof]))
        return grad