Example #1
0
    def createSystem(self, nonbondedMethod=ff.NoCutoff,
                     nonbondedCutoff=1.0*u.nanometer,
                     constraints=None,
                     rigidWater=True,
                     implicitSolvent=None,
                     implicitSolventKappa=None,
                     implicitSolventSaltConc=0.0*u.moles/u.liter,
                     temperature=298.15*u.kelvin,
                     soluteDielectric=1.0,
                     solventDielectric=78.5,
                     removeCMMotion=True,
                     hydrogenMass=None,
                     ewaldErrorTolerance=0.0005,
                     flexibleConstraints=True,
                     verbose=False):
        """
        Construct an OpenMM System representing the topology described by the
        prmtop file.

        Parameters:
         -  nonbondedMethod (object=NoCutoff) The method to use for nonbonded
               interactions. Allowed values are NoCutoff, CutoffNonPeriodic,
               CutoffPeriodic, Ewald, or PME.
         -  nonbondedCutoff (distance=1*nanometer) The cutoff distance to use
               for nonbonded interactions.
         -  constraints (object=None) Specifies which bonds or angles should be
               implemented with constraints. Allowed values are None, HBonds,
               AllBonds, or HAngles.
         -  rigidWater (boolean=True) If true, water molecules will be fully
               rigid regardless of the value passed for the constraints argument
         -  implicitSolvent (object=None) If not None, the implicit solvent
               model to use. Allowed values are HCT, OBC1, OBC2, or GBn
         -  implicitSolventKappa (float=None): Debye screening parameter to
               model salt concentrations in GB solvent.
         -  implicitSolventSaltConc (float=0.0*u.moles/u.liter): Salt
               concentration for GB simulations. Converted to Debye length
               `kappa'
         -  temperature (float=298.15*u.kelvin): Temperature used in the salt
               concentration-to-kappa conversion for GB salt concentration term
         -  soluteDielectric (float=1.0) The solute dielectric constant to use
               in the implicit solvent model.
         -  solventDielectric (float=78.5) The solvent dielectric constant to
               use in the implicit solvent model.
         -  removeCMMotion (boolean=True) If true, a CMMotionRemover will be
               added to the System.
         -  hydrogenMass (mass=None) The mass to use for hydrogen atoms bound to
               heavy atoms. Any mass added to a hydrogen is subtracted from the
               heavy atom to keep their total mass the same.
         -  ewaldErrorTolerance (float=0.0005) The error tolerance to use if the
               nonbonded method is Ewald or PME.
         -  flexibleConstraints (bool=True) Are our constraints flexible or not?
         -  verbose (bool=False) Optionally prints out a running progress report
        """
        # Rebuild the topology file if necessary, and flush the atom property
        # data to the atom list
        if self._topology_changed():
            self.remake_parm()
        else:
            self.atom_list.refresh_data()
        LJ_radius, LJ_depth = self.openmm_LJ() # Get our LJ parameters
        LJ_14_radius, LJ_14_depth = self.openmm_14_LJ()

        # Set the cutoff distance in nanometers
        cutoff = None
        if nonbondedMethod is not ff.NoCutoff:
            cutoff = nonbondedCutoff
            # Remove units from cutoff
            if u.is_quantity(cutoff):
                cutoff = cutoff.value_in_unit(u.nanometers)

        if nonbondedMethod not in (ff.NoCutoff, ff.CutoffNonPeriodic,
                                   ff.CutoffPeriodic, ff.Ewald, ff.PME):
            raise ValueError('Illegal value for nonbonded method')
        if self.ptr('ifbox') == 0 and nonbondedMethod in (ff.CutoffPeriodic,
                                                          ff.Ewald, ff.PME):
            raise ValueError('Illegal nonbonded method for a '
                             'non-periodic system')
        if implicitSolvent not in (HCT, OBC1, OBC2, GBn, GBn2, None):
            raise ValueError('Illegal implicit solvent model choice.')
        if not constraints in (None, ff.HAngles, ff.HBonds, ff.AllBonds):
            raise ValueError('Illegal constraints choice')
      
        # Define conversion factors
        length_conv = u.angstrom.conversion_factor_to(u.nanometer)
        _ambfrc = u.kilocalorie_per_mole/(u.angstrom*u.angstrom)
        _openmmfrc = u.kilojoule_per_mole/(u.nanometer*u.nanometer)
        bond_frc_conv = _ambfrc.conversion_factor_to(_openmmfrc)
        _ambfrc = u.kilocalorie_per_mole/(u.radians*u.radians)
        _openmmfrc = u.kilojoule_per_mole/(u.radians*u.radians)
        angle_frc_conv = _ambfrc.conversion_factor_to(_openmmfrc)
        dihe_frc_conv = u.kilocalorie_per_mole.conversion_factor_to(
                            u.kilojoule_per_mole)
        ene_conv = dihe_frc_conv
      
        # Create the system
        system = mm.System()
        if verbose: print('Adding particles...')
        for mass in self.parm_data['MASS']:
            system.addParticle(mass)
        # Set up the constraints
        if verbose and (constraints is not None and not rigidWater):
            print('Adding constraints...')
        if constraints in (ff.HBonds, ff.AllBonds, ff.HAngles):
            for bond in self.bonds_inc_h:
                system.addConstraint(bond.atom1.starting_index,
                                     bond.atom2.starting_index,
                                     bond.bond_type.req*length_conv)
        if constraints in (ff.AllBonds, ff.HAngles):
            for bond in self.bonds_without_h:
                system.addConstraint(bond.atom1.starting_index,
                                     bond.atom2.starting_index,
                                     bond.bond_type.req*length_conv)
        if rigidWater and constraints is None:
            for bond in self.bonds_inc_h:
                if (bond.atom1.residue.resname in WATNAMES and
                    bond.atom2.residue.resname in WATNAMES):
                    system.addConstraint(bond.atom1.starting_index,
                                         bond.atom2.starting_index,
                                         bond.bond_type.req*length_conv)
        # Add Bond forces
        if verbose: print('Adding bonds...')
        force = mm.HarmonicBondForce()
        force.setForceGroup(self.BOND_FORCE_GROUP)
        if flexibleConstraints or (constraints not in (ff.HBonds, ff.AllBonds,
                                                       ff.HAngles)):
            for bond in self.bonds_inc_h:
                force.addBond(bond.atom1.starting_index,
                              bond.atom2.starting_index,
                              bond.bond_type.req*length_conv,
                              2*bond.bond_type.k*bond_frc_conv)
        if flexibleConstraints or (constraints not in (ff.AllBonds,ff.HAngles)):
            for bond in self.bonds_without_h:
                force.addBond(bond.atom1.starting_index,
                              bond.atom2.starting_index,
                              bond.bond_type.req*length_conv,
                              2*bond.bond_type.k*bond_frc_conv)
        system.addForce(force)
        # Add Angle forces
        if verbose: print('Adding angles...')
        force = mm.HarmonicAngleForce()
        force.setForceGroup(self.ANGLE_FORCE_GROUP)
        if constraints is ff.HAngles:
            num_constrained_bonds = system.getNumConstraints()
            atom_constraints = [[]] * system.getNumParticles()
            for i in range(num_constrained_bonds):
                c = system.getConstraintParameters(i)
                dist = c[2].value_in_unit(u.nanometer)
                atom_constraints[c[0]].append((c[1], dist))
                atom_constraints[c[1]].append((c[0], dist))
        for angle in self.angles_inc_h:
            if constraints is ff.HAngles:
                a1 = angle.atom1.element
                a2 = angle.atom2.element
                a3 = angle.atom3.element
                nh = int(a1==1) + int(a2==1) + int(a3==1)
                constrained = (nh >= 2 or (nh == 1 and a2 == 8))
            else:
                constrained = False # no constraints
            if constrained:
                l1 = l2 = None
                for bond in angle.atom2.bonds:
                    if bond.atom1 is angle.atom1 or bond.atom2 is angle.atom1:
                        l1 = bond.bond_type.req * length_conv
                    elif bond.atom1 is angle.atom3 or bond.atom2 is angle.atom3:
                        l2 = bond.bond_type.req * length_conv
                # Compute the distance between the atoms and add a constraint
                length = sqrt(l1*l1 + l2*l2 - 2*l1*l2*
                              cos(angle.angle_type.theteq))
                system.addConstraint(bond.atom1.starting_index,
                                     bond.atom2.starting_index, length)
            if flexibleConstraints or not constrained:
                force.addAngle(angle.atom1.starting_index,
                               angle.atom2.starting_index,
                               angle.atom3.starting_index,
                               angle.angle_type.theteq,
                               2*angle.angle_type.k*angle_frc_conv)
        for angle in self.angles_without_h:
            force.addAngle(angle.atom1.starting_index,
                           angle.atom2.starting_index,
                           angle.atom3.starting_index,
                           angle.angle_type.theteq,
                           2*angle.angle_type.k*angle_frc_conv)
        system.addForce(force)
        # Add dihedral forces
        if verbose: print('Adding torsions...')
        force = mm.PeriodicTorsionForce()
        force.setForceGroup(self.DIHEDRAL_FORCE_GROUP)
        for tor in self.dihedrals_inc_h + self.dihedrals_without_h:
            force.addTorsion(tor.atom1.starting_index,
                             tor.atom2.starting_index,
                             tor.atom3.starting_index,
                             tor.atom4.starting_index,
                             int(tor.dihed_type.per),
                             tor.dihed_type.phase,
                             tor.dihed_type.phi_k*dihe_frc_conv)
        system.addForce(force)

        # Add nonbonded terms now
        if verbose: print('Adding nonbonded interactions...')
        force = mm.NonbondedForce()
        force.setForceGroup(self.NONBONDED_FORCE_GROUP)
        if self.ptr('ifbox') == 0: # non-periodic
            if nonbondedMethod is ff.NoCutoff:
                force.setNonbondedMethod(mm.NonbondedForce.NoCutoff)
            elif nonbondedMethod is ff.CutoffNonPeriodic:
                if cutoff is None:
                    raise ValueError('No cutoff value specified')
                force.setNonbondedMethod(mm.NonbondedForce.CutoffNonPeriodic)
                force.setCutoffDistance(cutoff)
            else:
                raise ValueError('Illegal nonbonded method for non-periodic '
                                 'system')
        else: # periodic
            # Set up box vectors (from inpcrd if available, or fall back to
            # prmtop definitions
            system.setDefaultPeriodicBoxVectors(*self.box_vectors)

            # Set cutoff
            if cutoff is None:
                # Compute cutoff automatically
                box = self.box_lengths
                min_box_width = min((box[0]/u.nanometers,
                                     box[1]/u.nanometers,
                                     box[2]/u.nanometers))
                CLEARANCE_FACTOR = 0.97
                cutoff = u.Quantity((min_box_width*CLEARANCE_FACTOR)/2.0,
                                    u.nanometers)
            if nonbondedMethod is not ff.NoCutoff:
                force.setCutoffDistance(cutoff)

            # Set nonbonded method.
            if nonbondedMethod is ff.NoCutoff:
                force.setNonbondedMethod(mm.NonbondedForce.NoCutoff)
            elif nonbondedMethod is ff.CutoffNonPeriodic:
                force.setNonbondedMethod(mm.NonbondedForce.CutoffNonPeriodic)
            elif nonbondedMethod is ff.CutoffPeriodic:
                force.setNonbondedMethod(mm.NonbondedForce.CutoffPeriodic)
            elif nonbondedMethod is ff.Ewald:
                force.setNonbondedMethod(mm.NonbondedForce.Ewald)
            elif nonbondedMethod is ff.PME:
                force.setNonbondedMethod(mm.NonbondedForce.PME)
            else:
                raise ValueError('Cutoff method is not understood')

            if ewaldErrorTolerance is not None:
                force.setEwaldErrorTolerance(ewaldErrorTolerance)

        # Add per-particle nonbonded parameters (LJ params)
        sigma_scale = 2**(-1/6) * 2
        for i, atm in enumerate(self.atom_list):
            force.addParticle(atm.charge,
                              sigma_scale*LJ_radius[atm.nb_idx-1]*length_conv,
                              LJ_depth[atm.nb_idx-1]*ene_conv)

        # Add 1-4 interactions
        excluded_atom_pairs = set() # save these pairs so we don't zero them out
        sigma_scale = 2**(-1/6)
        for tor in self.dihedrals_inc_h + self.dihedrals_without_h:
            if min(tor.signs) < 0: continue # multi-terms and impropers
            charge_prod = (tor.atom1.charge * tor.atom4.charge /
                           tor.dihed_type.scee)
            epsilon = (sqrt(LJ_14_depth[tor.atom1.nb_idx-1] * ene_conv *
                            LJ_14_depth[tor.atom4.nb_idx-1] * ene_conv) /
                            tor.dihed_type.scnb)
            sigma = (LJ_14_radius[tor.atom1.nb_idx-1] +
                     LJ_14_radius[tor.atom4.nb_idx-1])*length_conv*sigma_scale
            force.addException(tor.atom1.starting_index,
                               tor.atom4.starting_index,
                               charge_prod, sigma, epsilon)
            excluded_atom_pairs.add(
                    min( (tor.atom1.starting_index, tor.atom4.starting_index),
                         (tor.atom4.starting_index, tor.atom1.starting_index) )
            )

        # Add excluded atoms
        for atom in self.atom_list:
            # Exclude all bonds and angles
            for atom2 in atom.bond_partners:
                if atom2.starting_index > atom.starting_index:
                    force.addException(atom.starting_index,
                                       atom2.starting_index, 0.0, 0.1, 0.0)
            for atom2 in atom.angle_partners:
                if atom2.starting_index > atom.starting_index:
                    force.addException(atom.starting_index,
                                       atom2.starting_index, 0.0, 0.1, 0.0)
            for atom2 in atom.exclusion_partners:
                if atom2.starting_index > atom.starting_index:
                    force.addException(atom.starting_index,
                                       atom2.starting_index, 0.0, 0.1, 0.0)
            for atom2 in atom.dihedral_partners:
                if atom2.starting_index <= atom.starting_index: continue
                if ((atom.starting_index, atom2.starting_index) in
                    excluded_atom_pairs):
                    continue
                force.addException(atom.starting_index,
                                   atom2.starting_index, 0.0, 0.1, 0.0)
        system.addForce(force)

        # Add virtual sites for water
        # First tag the residues that have an extra point in them
        for res in self.residue_list: res.has_ep = False
        ep = [atom for atom in self.atom_list if atom.atname in EPNAMES]
        for atom in ep: atom.residue.has_ep = True
        if len(ep) > 0:
            numRes = ep[-1].residue.idx + 1
            waterO = [[] for i in range(numRes)]
            waterH = [[] for i in range(numRes)]
            waterEP = [[] for i in range(numRes)]
            for atom in self.atom_list:
                if atom.residue.has_ep:
                    if atom.element == 8:
                        waterO[res].append(atom)
                    elif atom.element == 1:
                        waterH[res].append(atom)
                    elif atom.element == 0:
                        waterEP[res].append(atom)
            # Record bond lengths for faster access
            distOH = [None] * numRes
            distHH = [None] * numRes
            distOE = [None] * numRes
            for bond in self.bonds_inc_h + self.bonds_without_h:
                a1 = bond.atom1
                a2 = bond.atom2
                if a1.residue.has_ep:
                    res = a1.residue.idx
                    if a1.element == 1 or a2.element == 1:
                        if a1.element == 1 and a2.element == 1:
                            distHH[res] = bond.bond_type.req * u.angstroms
                        if a1.element == 8 or a2.element == 8:
                            distOH[res] = bond.bond_type.req * u.angstroms
                    elif ((a1.element == 8 or a2.element == 8) and
                          (a1.element == 0 or a2.element == 0)):
                        distOE[res] = bond.bond_type.req * u.angstroms
            # Loop over residues and add the virtual points
            out_of_plane_angle = 54.735 * u.degrees
            cosOOP = u.cos(out_of_plane_angle)
            sinOOP = u.sin(out_of_plane_angle)
            for residue in self.residue_list:
                if not residue.has_ep: continue
                res = residue.idx
                if len(waterO[res]) == 1 and len(waterH[res]) == 2:
                    if len(waterEP[res]) == 1:
                        # 4-point water
                        weightH = distOE[res] / sqrt(distOH[res] * distOH[res] -
                                               0.25 * distHH[res] * distHH[res])
                        system.setVirtualSite(
                                waterEP[res][0],
                                mm.ThreeParticleAverageSite(waterO[res][0],
                                waterH[res][0], waterH[res][1],
                                1-weightH, weightH/2, weightH/2)
                        )
                elif len(waterEP[res]) == 2:
                    # 5-point water
                    weightH = (cosOOP * distOE[res] /
                               sqrt(distOH[res] * distOH[res] -
                                 0.25 * distHH[res] * distHH[res])
                    )
                    angleHOH = 2 * asin(0.5 * distHH[res] / distOH[res])
                    lenCross = distOH[res] * distOH[res] * sin(angleHOH)
                    weightCross = sinOOP * distOE[res] / lenCross
                    site1 = mm.OutOfPlaneSite(waterO[res][0], waterH[res][0],
                            waterH[res][1], weightH/2, weightH/2, weightCross)
                    site2 = mm.OutOfPlaneSite(waterO[res][0], waterH[res][0],
                            waterH[res][1], weightH/2, weightH/2, -weightCross)
                    system.setVirtualSite(waterEP[res][0], site1)
                    system.setVirtualSite(waterEP[res][1], site2)

        # Add GB model if we're doing one
        if implicitSolvent is not None:
            if verbose: print('Adding GB parameters...')
            gb_parms = self._get_gb_params(implicitSolvent)

            # If implicitSolventKappa is None, compute it from salt
            # concentration
            if implicitSolventKappa is None:
                if u.is_quantity(implicitSolventSaltConc):
                    sc = implicitSolventSaltConc.value_in_unit(u.moles/u.liter)
                    implicitSolventSaltConc = sc
                if u.is_quantity(temperature):
                    temperature = temperature.value_in_unit(u.kelvin)
                # The constant is 1 / sqrt( epsilon_0 * kB / (2 * NA * q^2 *
                # 1000) ) where NA is avogadro's number, epsilon_0 is the
                # permittivity of free space, q is the elementary charge (this
                # number matches sander/pmemd's kappa conversion factor)
                implicitSolventKappa = 50.33355 * sqrt(implicitSolventSaltConc /
                                                solventDielectric / temperature)
                # Multiply by 0.73 to account for ion exclusions, and multiply
                # by 10 to convert to 1/nm from 1/angstroms
                implicitSolventKappa *= 7.3
            elif implicitSolvent is None:
                implicitSolventKappa = 0.0

            if u.is_quantity(implicitSolventKappa):
                implicitSolventKappa = implicitSolventKappa.value_in_unit(
                                            (1.0/u.nanometer).unit)
            if implicitSolvent is HCT:
                gb = GBSAHCTForce(solventDielectric, soluteDielectric, None,
                                  cutoff, kappa=implicitSolventKappa)
            elif implicitSolvent is OBC1:
                gb = GBSAOBC1Force(solventDielectric, soluteDielectric, None,
                                   cutoff, kappa=implicitSolventKappa)
            elif implicitSolvent is OBC2:
                gb = GBSAOBC2Force(solventDielectric, soluteDielectric, None,
                                   cutoff, kappa=implicitSolventKappa)
            elif implicitSolvent is GBn:
                gb = GBSAGBnForce(solventDielectric, soluteDielectric, None,
                                  cutoff, kappa=implicitSolventKappa)
            elif implicitSolvent is GBn2:
                gb = GBSAGBn2Force(solventDielectric, soluteDielectric, None,
                                   cutoff, kappa=implicitSolventKappa)
            for i, atom in enumerate(self.atom_list):
                gb.addParticle([atom.charge] + list(gb_parms[i]))
            # Set cutoff method
            if nonbondedMethod is ff.NoCutoff:
                gb.setNonbondedMethod(mm.NonbondedForce.NoCutoff)
            elif nonbondedMethod is ff.CutoffNonPeriodic:
                gb.setNonbondedMethod(mm.NonbondedForce.CutoffNonPeriodic)
                gb.setCutoffDistance(cutoff)
            elif nonbondedMethod is ff.CutoffPeriodic:
                gb.setNonbondedMethod(mm.NonbondedForce.CutoffPeriodic)
                gb.setCutoffDistance(cutoff)
            else:
                raise ValueError('Illegal nonbonded method for use with GBSA')
            gb.setForceGroup(self.GB_FORCE_GROUP)
            system.addForce(gb)
            force.setReactionFieldDielectric(1.0) # applies to NonbondedForce

        # See if we repartition the hydrogen masses
        if hydrogenMass is not None:
            for bond in self.bonds_inc_h:
                atom1, atom2 = bond.atom1, bond.atom2
                if atom1.element == 1:
                    atom1, atom2 = atom2, atom1 # now atom2 is hydrogen for sure
                if atom1.element != 1:
                    transfer_mass = hydrogenMass - atom2.mass
                    new_mass1 = (system.getParticleMass(atom1.index) -
                                 transfer_mass)
                    system.setParticleMass(atom2.index, hydrogenMass)
                    system.setParticleMass(atom1.index, new_mass1)
        # See if we want to remove COM motion
        if removeCMMotion:
            system.addForce(mm.CMMotionRemover())

        # Cache our system for easy access
        self._system = system

        return system
    def createSystem(self,
                     nonbondedMethod=ff.NoCutoff,
                     nonbondedCutoff=1.0 * nanometer,
                     ewaldErrorTolerance=0.0005,
                     removeCMMotion=True,
                     hydrogenMass=None,
                     OPLS=False,
                     implicitSolvent=None,
                     AGBNPVersion=1):
        """Construct an OpenMM System representing the topology described by this
        DMS file

        Parameters
        ----------
        nonbondedMethod : object=NoCutoff
            The method to use for nonbonded interactions.  Allowed values are
            NoCutoff, CutoffNonPeriodic, CutoffPeriodic, Ewald, PME, or LJPME.
        nonbondedCutoff : distance=1*nanometer
            The cutoff distance to use for nonbonded interactions
        ewaldErrorTolerance : float=0.0005
            The error tolerance to use if nonbondedMethod is Ewald, PME, or LJPME.
        removeCMMotion : boolean=True
            If true, a CMMotionRemover will be added to the System
        hydrogenMass : mass=None
            The mass to use for hydrogen atoms bound to heavy atoms.  Any mass
            added to a hydrogen is subtracted from the heavy atom to keep their
            total mass the same.
        OPLS : boolean=False
            If True, forces OPLS combining rules
        implicitSolvent: string=None
            If not None, creates implicit solvent force of the given name
            Allowed values are: HCT and 'AGBNP'
            (the corresponding tables must be present in the DMS file)
        AGBNPVersion: int=1
            AGBNP implicit solvent version
        """
        self._checkForUnsupportedTerms()
        sys = mm.System()

        # Build the box dimensions
        boxSize = self.topology.getUnitCellDimensions()
        if boxSize is not None:
            sys.setDefaultPeriodicBoxVectors(
                (boxSize[0], 0, 0), (0, boxSize[1], 0), (0, 0, boxSize[2]))
        elif nonbondedMethod in (ff.CutoffPeriodic, ff.Ewald, ff.PME,
                                 ff.LJPME):
            raise ValueError(
                'Illegal nonbonded method for a non-periodic system')

        # Create all of the particles
        for (fcounter, conn, tables, offset) in self._localVars():
            for mass in conn.execute('SELECT mass FROM particle ORDER BY id'):
                sys.addParticle(mass[0] * dalton)

        # Add all of the forces
        self._addBondsToSystem(sys)
        self._addAnglesToSystem(sys)
        self._addConstraintsToSystem(sys)
        self._addPeriodicTorsionsToSystem(sys, OPLS)
        self._addImproperHarmonicTorsionsToSystem(sys)
        self._addCMAPToSystem(sys)
        self._addVirtualSitesToSystem(sys)
        self._addPositionalHarmonicRestraints(sys)
        nb, cnb = self._addNonbondedForceToSystem(sys, OPLS)

        # Finish configuring the NonbondedForce.
        methodMap = {
            ff.NoCutoff: mm.NonbondedForce.NoCutoff,
            ff.CutoffNonPeriodic: mm.NonbondedForce.CutoffNonPeriodic,
            ff.CutoffPeriodic: mm.NonbondedForce.CutoffPeriodic,
            ff.Ewald: mm.NonbondedForce.Ewald,
            ff.PME: mm.NonbondedForce.PME,
            ff.LJPME: mm.NonbondedForce.LJPME
        }
        nb.setNonbondedMethod(methodMap[nonbondedMethod])
        nb.setCutoffDistance(nonbondedCutoff)
        nb.setEwaldErrorTolerance(ewaldErrorTolerance)
        if cnb is not None:
            nb.setUseDispersionCorrection(False)
            if nonbondedMethod in (ff.CutoffPeriodic, ff.Ewald, ff.PME,
                                   ff.LJPME):
                cnb.setNonbondedMethod(methodMap[ff.CutoffPeriodic])
                cnb.setCutoffDistance(nonbondedCutoff)
            elif nonbondedMethod == ff.CutoffNonPeriodic:
                cnb.setNonbondedMethod(methodMap[ff.CutoffNonPeriodic])
                cnb.setCutoffDistance(nonbondedCutoff)
            else:
                cnb.setNonbondedMethod(methodMap[ff.NoCutoff])
            cnb.setUseSwitchingFunction(False)
            cnb.setUseLongRangeCorrection(False)

        #add implicit solvent model.
        if implicitSolvent is not None:

            if not (implicitSolvent in (HCT, 'AGBNP', 'GVolSA', 'AGBNP3')):
                raise ValueError('Illegal implicit solvent method')

            if self._verbose:
                print('Adding implicit solvent ...')

            #with implicit solvent turn off native reaction field
            #However note that this does not affect the shifted Coulomb potential of the Nonbonded force
            #(it affects the only the energy, not the forces and equation of motion)
            nb.setReactionFieldDielectric(1.0)

            if implicitSolvent is HCT:
                gb_parms = self._get_gb_params()

                if gb_parms:
                    if self._verbose:
                        print('Adding HCT GB force ...')
                    gb = GBSAHCTForce(SA='ACE')
                    for i in range(len(gb_parms)):
                        gb.addParticle(list(gb_parms[i]))
                    gb.finalize()
                    sys.addForce(gb)
                else:
                    raise IOError("No HCT parameters found in DMS file")

            if implicitSolvent is 'AGBNP3':
                #load AGBNP3 plugin if available
                try:
                    from AGBNP3plugin import AGBNP3Force
                except ImportError:
                    raise NotImplementedError(
                        'AGBNP3 is not supported in this version')
                #sets up AGBNP3
                gb_parms = self._get_agbnp2_params()
                if gb_parms:
                    if self._verbose:
                        print('Adding AGBNP3 force ...')
                    gb = AGBNP3Force()
                    # add particles
                    for i in range(len(gb_parms)):
                        p = gb_parms[i]
                        gb.addParticle(p[0], p[1], p[2], p[3], p[4], p[5],
                                       p[6])
                    # connection table (from bonds)
                    self._add_agbnp2_ct(gb)
                    sys.addForce(gb)
                else:
                    raise IOError("No AGBNP parameters found in DMS file")

            if implicitSolvent is 'GVolSA':
                #implemented as AGBNP version 0
                implicitSolvent = 'AGBNP'
                AGBNPVersion = 0
                if self._verbose:
                    print('Using GVolSA')

            if implicitSolvent is 'AGBNP':
                #load AGBNP plugin if available
                try:
                    from AGBNPplugin import AGBNPForce
                except ImportError:
                    raise NotImplementedError(
                        'AGBNP is not supported in this version')
                #sets up AGBNP
                gb_parms = self._get_agbnp2_params()
                if gb_parms:
                    gb = AGBNPForce()
                    gb.setNonbondedMethod(methodMap[nonbondedMethod])
                    gb.setCutoffDistance(nonbondedCutoff)
                    gb.setVersion(AGBNPVersion)
                    if self._verbose:
                        print('Using AGBNP force version %d ...' %
                              AGBNPVersion)
                    # add particles
                    for i in range(len(gb_parms)):
                        [
                            radiusN, chargeN, gammaN, alphaN, hbtype, hbwN,
                            ishydrogenN
                        ] = gb_parms[i]
                        h_flag = ishydrogenN > 0
                        gb.addParticle(radiusN, gammaN, alphaN, chargeN,
                                       h_flag)
                    sys.addForce(gb)
                    self.gb_parms = gb_parms
                    self.agbnp = gb
                else:
                    raise IOError("No AGBNP parameters found in DMS file")

        # Adjust masses.
        if hydrogenMass is not None:
            for atom1, atom2 in self.topology.bonds():

                if atom1.element == hydrogen:
                    (atom1, atom2) = (atom2, atom1)
                if atom2.element == hydrogen and atom1.element not in (
                        hydrogen, None):
                    transferMass = hydrogenMass - sys.getParticleMass(
                        atom2.index)
                    sys.setParticleMass(atom2.index, hydrogenMass)
                    sys.setParticleMass(
                        atom1.index,
                        sys.getParticleMass(atom1.index) - transferMass)

        # Add a CMMotionRemover.
        if removeCMMotion:
            sys.addForce(mm.CMMotionRemover())

        return sys
    def createSystem(self, nonbondedMethod=ff.NoCutoff, nonbondedCutoff=1.0*nanometer,
                     ewaldErrorTolerance=0.0005, removeCMMotion=True, hydrogenMass=None, OPLS=False, implicitSolvent=None):
        """Construct an OpenMM System representing the topology described by this dms file

        Parameters:
         - nonbondedMethod (object=NoCutoff) The method to use for nonbonded interactions.  Allowed values are
           NoCutoff, CutoffNonPeriodic, CutoffPeriodic, Ewald, or PME.
         - nonbondedCutoff (distance=1*nanometer) The cutoff distance to use for nonbonded interactions
         - ewaldErrorTolerance (float=0.0005) The error tolerance to use if nonbondedMethod is Ewald or PME.
         - removeCMMotion (boolean=True) If true, a CMMotionRemover will be added to the System
         - hydrogenMass (mass=None) The mass to use for hydrogen atoms bound to heavy atoms.  Any mass added to a hydrogen is
           subtracted from the heavy atom to keep their total mass the same.
         - OPLS (boolean=False) If True, force field parameters are interpreted as OPLS parameters; OPLS variants of 
           torsional and non-bonded forces are constructed.
     - implicitSolvent (object=None) if not None, the implicit solvent model to use, the only allowed value is HCT
        """
        self._checkForUnsupportedTerms()
        sys = mm.System()

        # Buld the box dimensions
        sys = mm.System()
        boxSize = self.topology.getUnitCellDimensions()
        if boxSize is not None:
            sys.setDefaultPeriodicBoxVectors((boxSize[0], 0, 0), (0, boxSize[1], 0), (0, 0, boxSize[2]))
        elif nonbondedMethod in (ff.CutoffPeriodic, ff.Ewald, ff.PME):
            raise ValueError('Illegal nonbonded method for a non-periodic system')

        # Create all of the particles
        for mass in self._conn.execute('SELECT mass FROM particle ORDER BY id'):
            sys.addParticle(mass[0]*dalton)

        # Add all of the forces
        self._addBondsToSystem(sys)
        self._addAnglesToSystem(sys)
        self._addConstraintsToSystem(sys)
        self._addPeriodicTorsionsToSystem(sys, OPLS)
        self._addImproperHarmonicTorsionsToSystem(sys)
        self._addCMAPToSystem(sys)
        self._addVirtualSitesToSystem(sys)
        nb, cnb = self._addNonbondedForceToSystem(sys, OPLS)
        
        # Finish configuring the NonbondedForce.
        methodMap = {ff.NoCutoff:mm.NonbondedForce.NoCutoff,
                     ff.CutoffNonPeriodic:mm.NonbondedForce.CutoffNonPeriodic,
                     ff.CutoffPeriodic:mm.NonbondedForce.CutoffPeriodic,
                     ff.Ewald:mm.NonbondedForce.Ewald,
                     ff.PME:mm.NonbondedForce.PME}
        nb.setNonbondedMethod(methodMap[nonbondedMethod])
        nb.setCutoffDistance(nonbondedCutoff)
        nb.setEwaldErrorTolerance(ewaldErrorTolerance)
        if cnb is not None:
            cnb.setNonbondedMethod(methodMap[nonbondedMethod])
            cnb.setCutoffDistance(nonbondedCutoff)
        
    #add implicit solvent model. Right now, only HCT model is considered.
        if implicitSolvent is not None:

            print('Adding implicit solvent ...')

            if implicitSolvent is HCT:
                gb_parms = self._get_gb_params()
                if gb_parms:
                    print('Adding HCT GB force ...')
                    gb = GBSAHCTForce(SA='ACE')
                    for i in range(len(gb_parms)):          
                        gb.addParticle(list(gb_parms[i]))
                    sys.addForce(gb)
            
            if implicitSolvent is 'AGBNP':
                #load AGBNP3 plugin if available
                try:
                    from AGBNP3plugin import AGBNP3Force
                    AGBNP3enabled = True
                except ImportError:
                    AGBNP3enabled = False
                #sets up AGBNP3
                if AGBNP3enabled:
                    gb_parms = self._get_agbnp2_params()
                    if gb_parms:
                        print('Adding AGBNP3 force ...')
                        gb = AGBNP3Force()
                        # add particles
                        for i in range(len(gb_parms)):
                            p = gb_parms[i]
                            gb.addParticle(p[0],p[1],p[2],p[3],p[4],p[5],p[6])
                        # connection table (from bonds)
                        self._add_agbnp2_ct(gb)
                        sys.addForce(gb)
                else:
                    print('Warning: AGBNP is not supported in this version')
                
            if implicitSolvent is 'GVolSA':
                #load Gaussvol plugin if available
                try:
                    from GVolplugin import GVolForce
                    GVolEnabled = True
                except ImportError:
                    GVolEnabled = False
                #sets up GVol
                if GVolEnabled:
                    gb_parms = self._get_agbnp2_params()
                    if gb_parms:
                        print('Adding GVol force ...')
                        gb = GVolForce()
                        gb.setNonbondedMethod(methodMap[nonbondedMethod])
                        gb.setCutoffDistance(nonbondedCutoff)
                        # add particles
                        for i in range(len(gb_parms)):
                            [radiusN,chargeN,gammaN,alphaN,hbtype,hbwN,ishydrogenN] = gb_parms[i]
                            h_flag = ishydrogenN > 0
                            Roffset = 0.05;
                            radiusN += Roffset;
                            gb.addParticle(radiusN, gammaN, h_flag)
                            #print "Adding", radiusN, gammaN, h_flag
                        print ("Adding GVolforce ...")
                        sys.addForce(gb)
                        print ("Done")
                else:
                    print('Warning: GVol is not supported in this version')

        # Adjust masses.
        if hydrogenMass is not None:
            for atom1, atom2 in self.topology.bonds():
                
                if atom1.element == hydrogen:
                    (atom1, atom2) = (atom2, atom1)
                if atom2.element == hydrogen and atom1.element not in (hydrogen, None):
                    transferMass = hydrogenMass-sys.getParticleMass(atom2.index)
                    sys.setParticleMass(atom2.index, hydrogenMass)
                    sys.setParticleMass(atom1.index, sys.getParticleMass(atom1.index)-transferMass)
        
        # Add a CMMotionRemover.
        if removeCMMotion:
            sys.addForce(mm.CMMotionRemover())

        return sys
    def createSystem(self, nonbondedMethod=ff.NoCutoff, nonbondedCutoff=1.0*nanometer,
                     ewaldErrorTolerance=0.0005, removeCMMotion=True, hydrogenMass=None, OPLS=False, implicitSolvent=None):
        """Construct an OpenMM System representing the topology described by this dms file

        Parameters:
         - nonbondedMethod (object=NoCutoff) The method to use for nonbonded interactions.  Allowed values are
           NoCutoff, CutoffNonPeriodic, CutoffPeriodic, Ewald, or PME.
         - nonbondedCutoff (distance=1*nanometer) The cutoff distance to use for nonbonded interactions
         - ewaldErrorTolerance (float=0.0005) The error tolerance to use if nonbondedMethod is Ewald or PME.
         - removeCMMotion (boolean=True) If true, a CMMotionRemover will be added to the System
         - hydrogenMass (mass=None) The mass to use for hydrogen atoms bound to heavy atoms.  Any mass added to a hydrogen is
           subtracted from the heavy atom to keep their total mass the same.
         - OPLS (boolean=False) If True, force field parameters are interpreted as OPLS parameters; OPLS variants of 
           torsional and non-bonded forces are constructed.
	 - implicitSolvent (object=None) if not None, the implicit solvent model to use, the only allowed value is HCT
        """
        self._checkForUnsupportedTerms()
        sys = mm.System()

        # Buld the box dimensions
        sys = mm.System()
        boxSize = self.topology.getUnitCellDimensions()
        if boxSize is not None:
            sys.setDefaultPeriodicBoxVectors((boxSize[0], 0, 0), (0, boxSize[1], 0), (0, 0, boxSize[2]))
        elif nonbondedMethod in (ff.CutoffPeriodic, ff.Ewald, ff.PME):
            raise ValueError('Illegal nonbonded method for a non-periodic system')

        # Create all of the particles
        for mass in self._conn.execute('SELECT mass FROM particle ORDER BY id'):
            sys.addParticle(mass[0]*dalton)

        # Add all of the forces
        self._addBondsToSystem(sys)
        self._addAnglesToSystem(sys)
        self._addConstraintsToSystem(sys)
        self._addPeriodicTorsionsToSystem(sys, OPLS)
        self._addImproperHarmonicTorsionsToSystem(sys)
        self._addCMAPToSystem(sys)
        self._addVirtualSitesToSystem(sys)
        nb, cnb = self._addNonbondedForceToSystem(sys, OPLS)
        
        # Finish configuring the NonbondedForce.
        methodMap = {ff.NoCutoff:mm.NonbondedForce.NoCutoff,
                     ff.CutoffNonPeriodic:mm.NonbondedForce.CutoffNonPeriodic,
                     ff.CutoffPeriodic:mm.NonbondedForce.CutoffPeriodic,
                     ff.Ewald:mm.NonbondedForce.Ewald,
                     ff.PME:mm.NonbondedForce.PME}
        nb.setNonbondedMethod(methodMap[nonbondedMethod])
        nb.setCutoffDistance(nonbondedCutoff)
        nb.setEwaldErrorTolerance(ewaldErrorTolerance)
        if cnb is not None:
            cnb.setNonbondedMethod(methodMap[nonbondedMethod])
            cnb.setCutoffDistance(nonbondedCutoff)
        
	#add implicit solvent model. Right now, only HCT model is considered.
	if implicitSolvent is not None:

            print('Adding implicit solvent ...')

            if implicitSolvent is HCT:
                gb_parms = self._get_gb_params()
                if gb_parms:
                    print('Adding HCT GB force ...')
                    gb = GBSAHCTForce(SA='ACE')
                    for i in range(len(gb_parms)):	      
                        gb.addParticle(list(gb_parms[i]))
                    sys.addForce(gb)
            
            if implicitSolvent is 'AGBNP':
                #load AGBNP3 plugin if available
                try:
                    from AGBNP3plugin import AGBNP3Force
                    AGBNP3enabled = True
                except ImportError:
                    AGBNP3enabled = False
                #sets up AGBNP3
                if AGBNP3enabled:
                    gb_parms = self._get_agbnp2_params()
                    if gb_parms:
                        print('Adding AGBNP3 force ...')
                        gb = AGBNP3Force()
                        # add particles
                        for i in range(len(gb_parms)):
                            p = gb_parms[i]
                            gb.addParticle(p[0],p[1],p[2],p[3],p[4],p[5],p[6])
                        # connection table (from bonds)
                        self._add_agbnp2_ct(gb)
                        sys.addForce(gb)
                else:
                    print('Warning: AGBNP is not supported in this version')
                
            if implicitSolvent is 'GVolSA':
                #load Gaussvol plugin if available
                try:
                    from GVolplugin import GVolForce
                    GVolEnabled = True
                except ImportError:
                    GVolEnabled = False
                #sets up GVol
                if GVolEnabled:
                    gb_parms = self._get_agbnp2_params()
                    if gb_parms:
                        print('Adding GVol force ...')
                        gb = GVolForce()
                        gb.setNonbondedMethod(methodMap[nonbondedMethod])
                        gb.setCutoffDistance(nonbondedCutoff)
                        # add particles
                        for i in range(len(gb_parms)):
                            [radiusN,chargeN,gammaN,alphaN,hbtype,hbwN,ishydrogenN] = gb_parms[i]
                            h_flag = ishydrogenN > 0
                            Roffset = 0.05;
                            radiusN += Roffset;
                            gb.addParticle(radiusN, gammaN, h_flag)
                            #print "Adding", radiusN, gammaN, h_flag
                        print "Adding GVolforce ..."
                        sys.addForce(gb)
                        print "Done"
                else:
                    print('Warning: GVol is not supported in this version')

        # Adjust masses.
        if hydrogenMass is not None:
            for atom1, atom2 in self.topology.bonds():
                
                if atom1.element == hydrogen:
                    (atom1, atom2) = (atom2, atom1)
                if atom2.element == hydrogen and atom1.element not in (hydrogen, None):
                    transferMass = hydrogenMass-sys.getParticleMass(atom2.index)
                    sys.setParticleMass(atom2.index, hydrogenMass)
                    sys.setParticleMass(atom1.index, sys.getParticleMass(atom1.index)-transferMass)
		
        # Add a CMMotionRemover.
        if removeCMMotion:
            sys.addForce(mm.CMMotionRemover())

        return sys