Example #1
0
def _atoms_to_charmm22_psf(system):
    result = ['{:8d} !NATOM'.format(system.natom)]
    for iatom in xrange(system.natom):
        ffatype = system.get_ffatype(iatom)
        if len(ffatype) > 4:
            log.warning(
                'Atom type too long for CHARMM PSF file: {}'.format(ffatype))
        result.append(
            '{:8d} A    1    MOL  {:4} {:4} {:10.6f} {:13.4f}           0'.
            format(iatom + 1, ffatype, ffatype, system.charges[iatom],
                   system.masses[iatom] / amu))
    return '\n'.join(result)
Example #2
0
File: io.py Project: molmod/QuickFF
def _atoms_to_charmm22_psf(system):
    result = ['{:8d} !NATOM'.format(system.natom)]
    for iatom in range(system.natom):
        ffatype = system.get_ffatype(iatom)
        if len(ffatype) > 4:
            log.warning('Atom type too long for CHARMM PSF file: {}'.format(ffatype))
        if system.charges is None:
            charge = 0.0
        else:
            charge = system.charges[iatom]
        result.append('{:8d} A    1    MOL  {:4} {:4} {:10.6f} {:13.4f}           0'.format(
            iatom+1, ffatype, ffatype, charge, system.masses[iatom]/amu))
    return '\n'.join(result)
Example #3
0
 def update_trajectory_terms(self):
     '''
         Routine to make ``self.valence.terms`` and the term attribute of each
         trajectory in ``self.trajectories`` consistent again. This is usefull
         if the trajectory were read from a file and the ``valenceFF`` instance
         was modified.
     '''
     log.dump('Updating terms of trajectories to current valenceFF terms')
     with log.section('PTUPD', 3):
         #update the terms in the trajectories to match the terms in
         #self.valence
         for traj in self.trajectories:
             found = False
             for term in self.valence.iter_terms():
                 if traj.term.get_atoms() == term.get_atoms():
                     if found:
                         raise ValueError(
                             'Found two terms for trajectory %s with atom indices %s'
                             % (traj.term.basename,
                                str(traj.term.get_atoms())))
                     traj.term = term
                     if 'PT_ALL' not in term.tasks:
                         log.dump(
                             'PT_ALL not in tasks of %s-%i, deactivated PT'
                             % (term.basename, term.index))
                         traj.active = False
                     found = True
             if not found:
                 log.warning(
                     'No term found for trajectory %s with atom indices %s, deactivating trajectory'
                     % (traj.term.basename, str(traj.term.get_atoms())))
                 traj.active = False
         #check if every term with task PT_ALL has a trajectory associated
         #with it. It a trajectory is missing, generate it.
         for term in self.valence.iter_terms():
             if 'PT_ALL' not in term.tasks: continue
             found = False
             for traj in self.trajectories:
                 if term.get_atoms() == traj.term.get_atoms():
                     if found:
                         raise ValueError(
                             'Found two trajectories for term %s with atom indices %s'
                             % (term.basename, str(term.get_atoms())))
                     found = True
             if not found:
                 log.warning(
                     'No trajectory found for term %s with atom indices %s. Generating it now.'
                     % (term.basename, str(term.get_atoms())))
                 trajectory = self.perturbation.prepare([term])[0]
                 self.perturbation.generate(trajectory)
                 self.trajectories.append(trajectory)
Example #4
0
def _check_charmm22(valence):
    """Print warnings for all kinds of energy terms not supported by CHARMM22.

       **Arguments**

       valence
            Instance of ValenceFF, which defines the force field.
    """
    # First report all types of terms not supported by CHARMM22.
    skipped = set([])
    supported_kinds = set(['BONDHARM', 'BENDAHARM', 'TORSION', 'TORSCHEBY1', 'TORSCHEBY2', 'TORSCHEBY3', 'TORSCHEBY4', 'TORSCHEBY6'])
    for term in valence.iter_terms():
        kind = term.basename[:term.basename.find('/')].upper()
        if kind not in supported_kinds and kind not in skipped:
            log.warning('Not writing {} term to CHARMM22 parameter file.'.format(kind))
            skipped.add(kind)
Example #5
0
 def update_trajectory_terms(self):
     '''
         Routine to make ``self.valence.terms`` and the term attribute of each
         trajectory in ``self.trajectories`` consistent again. This is usefull
         if the trajectory were read from a file and the ``valenceFF`` instance
         was modified.
     '''
     log.dump('Updating terms of trajectories to current valenceFF terms')
     with log.section('PTUPD', 3):
         #update the terms in the trajectories to match the terms in
         #self.valence
         for traj in self.trajectories:
             found = False
             for term in self.valence.iter_terms():
                 if traj.term.get_atoms()==term.get_atoms():
                     if found: raise ValueError('Found two terms for trajectory %s with atom indices %s' %(traj.term.basename, str(traj.term.get_atoms())))
                     traj.term = term
                     if 'PT_ALL' not in term.tasks:
                         log.dump('PT_ALL not in tasks of %s-%i, deactivated PT' %(term.basename, term.index))
                         traj.active = False
                     found = True
             if not found:
                 log.warning('No term found for trajectory %s with atom indices %s, deactivating trajectory' %(traj.term.basename, str(traj.term.get_atoms())))
                 traj.active = False
         #check if every term with task PT_ALL has a trajectory associated
         #with it. It a trajectory is missing, generate it.
         for term in self.valence.iter_terms():
             if 'PT_ALL' not in term.tasks: continue
             found = False
             for traj in self.trajectories:
                 if term.get_atoms()==traj.term.get_atoms():
                     if found: raise ValueError('Found two trajectories for term %s with atom indices %s' %(term.basename, str(term.get_atoms())))
                     found =True
             if not found:
                 log.warning('No trajectory found for term %s with atom indices %s. Generating it now.' %(term.basename, str(term.get_atoms())))
                 trajectory = self.perturbation.prepare([term])[term.index]
                 self.perturbation.generate(trajectory)
                 self.trajectories.append(trajectory)
Example #6
0
    def generate(self, trajectory, remove_com=True):
        '''
            Method to calculate the perturbation trajectory, i.e. the trajectory
            that scans the geometry along the direction of the ic figuring in
            the term with the given index (should be a diagonal term). This
            method should be implemented in the derived classes.

            **Arguments**

            trajectory
                instance of Trajectory class representing the perturbation
                trajectory

            **Optional Arguments**

            remove_com
                if set to True, removes the center of mass translation from the
                resulting perturbation trajectories [default=True].
        '''
        index = trajectory.term.index
        with log.section('PTGEN', 3, timer='PT Generate'):
            log.dump('  Generating %s(atoms=%s)' %
                     (self.valence.terms[index].basename,
                      trajectory.term.get_atoms()))
            strain = self.strains[index]
            natom = self.system.natom
            if strain is None:
                log.warning(
                    'Strain for term %i (%s) is not initialized, skipping.' %
                    (index, self.valence.terms[index].basename))
                return
            q0 = self.valence.iclist.ictab[self.valence.vlist.vtab[index]
                                           ['ic0']]['value']
            diag = np.ones([strain.ndof + 1], float)
            diag[:strain.ndof] *= 0.1 * angstrom
            diag[strain.ndof] *= abs(q0 - trajectory.targets[0])
            sol = None
            for iq, target in enumerate(trajectory.targets):
                log.dump('    Frame %i (target=%.3f)' % (iq, target))
                strain.constrain_target = target
                if abs(target - q0) < 1e-6:
                    sol = np.zeros([strain.ndof + 1], float)
                    strain.gradient(sol)
                else:
                    if sol is not None:
                        init = sol.copy()
                    else:
                        init = np.zeros([strain.ndof + 1], float)
                    init[-1] = np.sign(q0 - target)
                    sol, infodict, ier, mesg = scipy.optimize.fsolve(
                        strain.gradient,
                        init,
                        xtol=1e-3,
                        full_output=True,
                        diag=diag)
                    if ier != 1:
                        #fsolve did not converge, flag this frame for deletion
                        log.dump('      %s' % mesg.replace('\n', ' '))
                        log.dump(
                            '    Frame %i (target=%.3f) %s(%s) did not converge. Trying again with slightly perturbed initial conditions.'
                            % (iq, target, self.valence.terms[index].basename,
                               trajectory.term.get_atoms()))
                        #try one more time
                        init = sol.copy()
                        init[:3 * natom] += np.random.normal(
                            0.0, 0.01, [3 * natom]) * angstrom
                        sol, infodict, ier, mesg = scipy.optimize.fsolve(
                            strain.gradient,
                            init,
                            xtol=1e-3,
                            full_output=True,
                            diag=diag)
                        if ier != 1:
                            log.dump('      %s' % mesg.replace('\n', ' '))
                            log.dump(
                                '    Frame %i (target=%.3f) %s(%s) STILL did not converge.'
                                % (iq, target,
                                   self.valence.terms[index].basename,
                                   trajectory.term.get_atoms()))
                            trajectory.targets[iq] = np.nan
                            continue
                x = strain.coords0 + sol[:3 * natom].reshape((-1, 3))
                trajectory.values[iq] = strain.constrain_value
                log.dump('    Converged (value=%.3f, lagmult=%.3e)' %
                         (strain.constrain_value, sol[3 * natom]))
                if remove_com:
                    com = (x.T * self.system.masses).sum(
                        axis=1) / self.system.masses.sum()
                    for i in xrange(natom):
                        x[i, :] -= com
                trajectory.coords[iq, :, :] = x
            #delete flagged frames
            targets = []
            values = []
            coords = []
            for target, value, coord in zip(trajectory.targets,
                                            trajectory.values,
                                            trajectory.coords):
                if not np.isnan(target):
                    targets.append(target)
                    values.append(value)
                    coords.append(coord)
            trajectory.targets = np.array(targets)
            trajectory.values = np.array(values)
            trajectory.coords = np.array(coords)
            return trajectory
Example #7
0
    def init_dihedral_terms(self, thresshold=20 * deg):
        '''
            Initialize the dihedral potentials from the local topology. The
            dihedral potential will be one of the two following possibilities:

                The multiplicity m is determined from the local topology, i.e.
                the number of neighbors of the central two atoms in the dihedral

                If the equilibrium value of all instances of the torsion are
                within `thresshold` of 0 deg or per/2 with per = 180deg/m,
                the following potential will be chosen:

                    0.5*K*(1-cos(m*psi-m*psi0)) with psi0 = 0 or 360/(2*m)
        '''
        with log.section('VAL', 3, 'Initializing'):
            #get all dihedrals
            from molmod.ic import dihed_angle, _dihed_angle_low
            ffatypes = [
                self.system.ffatypes[fid] for fid in self.system.ffatype_ids
            ]
            dihedrals = {}
            for dihedral in self.system.iter_dihedrals():
                dihedral, types = term_sort_atypes(ffatypes, dihedral,
                                                   'dihedral')
                if types in dihedrals.keys():
                    dihedrals[types].append(dihedral)
                else:
                    dihedrals[types] = [dihedral]
            #loop over all distinct dihedral types
            ncos = 0
            for types, diheds in dihedrals.iteritems():
                psi0s = np.zeros(len(diheds), float)
                ms = np.zeros(len(diheds), float)
                for i, dihed in enumerate(diheds):
                    if self.system.cell.nvec > 0:
                        d10 = self.system.pos[dihed[0]] - self.system.pos[
                            dihed[1]]
                        d12 = self.system.pos[dihed[2]] - self.system.pos[
                            dihed[1]]
                        d23 = self.system.pos[dihed[3]] - self.system.pos[
                            dihed[2]]
                        self.system.cell.mic(d10)
                        self.system.cell.mic(d12)
                        self.system.cell.mic(d23)
                        psi0s[i] = _dihed_angle_low(d10, d12, d23, 0)[0]
                    else:
                        rs = np.array([self.system.pos[j] for j in dihed])
                        psi0s[i] = dihed_angle(rs)[0]
                    n1 = len(self.system.neighs1[dihed[1]])
                    n2 = len(self.system.neighs1[dihed[2]])
                    ms[i] = get_multiplicity(n1, n2)
                nan = False
                for m in ms:
                    if np.isnan(m): nan = True
                if nan or None in ms or ms.std() > 1e-3:
                    ms_string = str(ms)
                    if nan: ms_string = 'nan'
                    log.warning('missing dihedral for %s (m is %s)' %
                                ('.'.join(types), ms_string))
                    continue
                m = int(np.round(ms.mean()))
                rv = get_restvalue(psi0s, m, thresshold=thresshold, mode=1)
                if rv is not None:
                    #a regular Cosine term is used for the dihedral potential
                    for dihed in diheds:
                        term = self.add_term(Cosine, [DihedAngle(*dihed)],
                                             types, ['HC_FC_DIAG'],
                                             ['au', 'kjmol', 'deg'])
                        self.set_params(term.index, rv0=rv, m=m)
                        ncos += 1
                else:
                    #no dihedral potential could be determine, hence it is ignored
                    log.warning(
                        'missing dihedral for %s (could not determine rest value from %s)'
                        % ('.'.join(types), str(psi0s / deg)))
                    continue
        log.dump('Added %i Cosine dihedral terms' % ncos)