def test_parameter_completeness_check(self): """Test that proper exceptions are raised if a force field fails to assign parameters to valence terms in a molecule.""" from openeye import oechem mol = oechem.OEMol() oechem.OEParseSmiles(mol, 'CCC') oechem.OEAddExplicitHydrogens(mol) oechem.OETriposAtomNames(mol) ff = ForceField(get_data_filename('forcefield/Frosst_AlkEtOH.ffxml')) topology = generateTopologyFromOEMol(mol) # Test nonbonded error checking by wiping out required LJ parameter params = ff.getParameter(paramID='n0001') params['smirks'] = '[#136:1]' ff.setParameter(paramID='n0001', params=params) ff.setParameter(paramID='n0002', params=params) with self.assertRaises(Exception): system = ff.createSystem(topology, [mol]) ff = ForceField(get_data_filename('forcefield/Frosst_AlkEtOH.ffxml')) # Test bond error checking by wiping out a required bond parameter params = ff.getParameter(paramID='b0001') params['smirks'] = '[#136:1]~[*:2]' ff.setParameter(paramID='b0001', params=params) with self.assertRaises(Exception): system = ff.createSystem(topology, [mol]) ff = ForceField(get_data_filename('forcefield/Frosst_AlkEtOH.ffxml')) # Test angle error checking by wiping out a required angle parameter params = ff.getParameter(paramID='a0001') params['smirks'] = '[#136:1]~[*:2]~[*:3]' ff.setParameter(paramID='a0001', params=params) with self.assertRaises(Exception): system = ff.createSystem(topology, [mol]) ff = ForceField(get_data_filename('forcefield/Frosst_AlkEtOH.ffxml')) # Test torsion error checking by wiping out a required torsion parameter params = ff.getParameter(paramID='t0001') params['smirks'] = '[#136:1]~[*:2]~[*:3]~[*:4]' ff.setParameter(paramID='t0001', params=params) ff.setParameter(paramID='t0004', params=params) with self.assertRaises(Exception): system = ff.createSystem(topology, [mol]) ff = ForceField(get_data_filename('forcefield/Frosst_AlkEtOH.ffxml'))
def test_change_parameters(verbose=False): """Test modification of forcefield parameters.""" from openeye import oechem # Load simple OEMol ifs = oechem.oemolistream( get_data_filename('molecules/AlkEthOH_c100.mol2')) mol = oechem.OEMol() flavor = oechem.OEIFlavor_Generic_Default | oechem.OEIFlavor_MOL2_Default | oechem.OEIFlavor_MOL2_Forcefield ifs.SetFlavor(oechem.OEFormat_MOL2, flavor) oechem.OEReadMolecule(ifs, mol) oechem.OETriposAtomNames(mol) # Load forcefield file ffxml = get_data_filename('forcefield/Frosst_AlkEtOH.ffxml') ff = ForceField(ffxml) from smarty.forcefield import generateTopologyFromOEMol topology = generateTopologyFromOEMol(mol) # Create initial system system = ff.createSystem(topology, [mol], verbose=verbose) # Get initial energy before parameter modification positions = positions_from_oemol(mol) old_energy = get_energy(system, positions) # Get params for an angle params = ff.getParameter(smirks='[a,A:1]-[#6X4:2]-[a,A:3]') # Modify params params['k'] = '0.0' ff.setParameter(params, smirks='[a,A:1]-[#6X4:2]-[a,A:3]') # Write params ff.writeFile(tempfile.TemporaryFile(suffix='.ffxml')) # Make sure params changed energy! (Test whether they get rebuilt on system creation) system = ff.createSystem(topology, [mol], verbose=verbose) energy = get_energy(system, positions) if verbose: print("New energy/old energy:", energy, old_energy) if np.abs(energy - old_energy) < 0.1: raise Exception("Error: Parameter modification did not change energy.")
def test_change_parameters(verbose=False): """Test modification of forcefield parameters.""" from openeye import oechem # Load simple OEMol ifs = oechem.oemolistream(get_data_filename('molecules/AlkEthOH_c100.mol2')) mol = oechem.OEMol() flavor = oechem.OEIFlavor_Generic_Default | oechem.OEIFlavor_MOL2_Default | oechem.OEIFlavor_MOL2_Forcefield ifs.SetFlavor( oechem.OEFormat_MOL2, flavor) oechem.OEReadMolecule(ifs, mol ) oechem.OETriposAtomNames(mol) # Load forcefield file ffxml = get_data_filename('forcefield/Frosst_AlkEtOH.ffxml') ff = ForceField(ffxml) from smarty.forcefield import generateTopologyFromOEMol topology = generateTopologyFromOEMol(mol) # Create initial system system = ff.createSystem(topology, [mol], verbose=verbose) # Get initial energy before parameter modification positions = positions_from_oemol(mol) old_energy=get_energy(system, positions) # Get params for an angle params = ff.getParameter(smirks='[a,A:1]-[#6X4:2]-[a,A:3]') # Modify params params['k']='0.0' ff.setParameter(params, smirks='[a,A:1]-[#6X4:2]-[a,A:3]') # Write params ff.writeFile( tempfile.TemporaryFile(suffix='.ffxml') ) # Make sure params changed energy! (Test whether they get rebuilt on system creation) system=ff.createSystem(topology, [mol], verbose=verbose) energy=get_energy(system, positions) if verbose: print("New energy/old energy:", energy, old_energy) if np.abs(energy-old_energy)<0.1: raise Exception("Error: Parameter modification did not change energy.")
def convert_frcmod_to_ffxml( infile, inxml, outxml ): """Convert a modified AMBER frcmod (with SMIRKS replacing atom types) to SMIRFF ffxml format by inserting parameters into a template ffxml file. Parameters ---------- infile : str File name of input SMIRKS-ified frcmod file containing parameters inxml : str File name of template SMIRFF FFXML file into which to insert these parameters. outxml : str File name of resulting output SMIRFF FFXML Notes: ------- Input XML file will normally be the template of a SMIRFF XML file without any parameters present (but with requisite force types already specified). """ # Obtain sections from target file file = open(infile, 'r') text = file.readlines() file.close() sections = {} # Section names from frcmod which we will parse secnames = ['NONBON', 'BOND', 'ANGL', 'IMPR', 'DIHE'] # Tags that will be used in the FFXML for these (same order) tag = ['Atom', 'Bond', 'Angle', 'Improper', 'Proper'] # Force names in the FFXML (same order) force_section = ['NonbondedForce', 'HarmonicBondForce', 'HarmonicAngleForce', 'PeriodicTorsionForce', 'PeriodicTorsionForce'] ct = 0 thissec = None # Why is this a while loop and not a for line in text loop? while ct < len(text): line = text[ct] tmp = line.split() # Skip lines starting with comment or which are blank if line[0]=='#' or len(tmp) < 1: ct+=1 continue # Check first entry to see if it's a section name, if so initialize storage if tmp[0] in secnames: thissec = tmp[0] sections[thissec] = [] # Otherwise store else: sections[thissec].append(line) ct+=1 # Read template forcefield file ff = ForceField(inxml) # Use functions to parse sections from target file and add parameters to force field param_id_by_section={} param_prefix_by_sec = {'NONBON':'n' , 'BOND':'b', 'ANGL':'a', 'DIHE':'t', 'IMPR':'i'} for (idx, name) in enumerate(secnames): param_id_by_section[name] = 1 for line in sections[name]: # Parse line for parameters if name=='NONBON': params = _parse_nonbon_line(line) elif name=='BOND': params = _parse_bond_line(line) elif name=='DIHE': params = _parse_dihe_line(line) elif name=='IMPR': params = _parse_impr_line(line) elif name=='ANGL': params = _parse_angl_line(line) # Add parameter ID params['id'] = param_prefix_by_sec[name]+str( param_id_by_section[name] ) smirks = params['smirks'] #Check smirks is valid for chemical enviroment parsing: env = environment.ChemicalEnvironment(smirks) # If it's not a torsion, just store in straightforward way if not (name=='IMPR' or name=='DIHE'): # Check for duplicates first if ff.getParameter( smirks, force_type = force_section[idx] ): raise ValueError("Error: parameter for %s is already present in forcefield." % smirks ) else: ff.addParameter( params, smirks, force_section[idx], tag[idx] ) # Increment parameter id param_id_by_section[name] +=1 # If it's a torsion, check to see if there are already parameters and # if so, add a new term to this torsion else: # If we have parameters already oldparams = ff.getParameter(smirks, force_type=force_section[idx]) if oldparams: # Find what number to use idnr = 1 paramtag = 'k%s' % idnr # This was "while paramtag in params" so it was overwriting k2 etc. while paramtag in oldparams: idnr+=1 paramtag = 'k%s' % idnr # Construct new param object with updated numbers for paramtag in ('periodicity1', 'phase1', 'idivf1', 'k1'): if paramtag in params: val = params.pop(paramtag) oldparams[paramtag[:-1]+str(idnr) ] = val # Store ff.setParameter( oldparams, smirks=smirks, force_type=force_section[idx]) else: # Otherwise, just store new parameters ff.addParameter( params, smirks, force_section[idx], tag[idx]) # Increment parameter ID param_id_by_section[name] += 1 # Write SMIRFF XML file ff.writeFile(outxml) # Roundtrip to fix formatting (for some reason etree won't format it properly on first write after modification) tmp = ForceField(outxml) tmp.writeFile(outxml)