def set_matches(fname, libs, reslist, orphaned_res, mol, force=False): ''' Find whether any units defined by a lib are required; if they are, update the liblist to include that lib and remove the units it defines from orphaned_res ''' units = util.get_units(fname) matches = set(units).intersection(reslist) #TODO: make this work for prep and check bonds as well as atoms. #require that atom names and connectivity match before adding lib libatoms = [] ext = os.path.splitext(fname)[-1][0:4] if ext != 'prep': with open(fname, 'r') as f: atomcopy = False for line in f: if line.startswith('!'): if line.split()[0].split('.')[-1] == 'atoms': atomcopy = True else: atomcopy = False elif atomcopy: aname = line.split()[0].strip('"') if not aname.startswith("H"): #ignore hydrogen libatoms.append(aname) molatoms = set([name.strip() for name in mol.mol_data['atomname']]) if not set(libatoms).issubset(molatoms) or ext == 'prep' and not force: matches = set([]) print( "Unit(s) %s defines atoms that differ from undefined residue: %s" % (' '.join(units), ' '.join(set(libatoms) - molatoms))) if matches: #redefine a unit iff found in a user-provided lib, but warn the user about the #duplication. don't redefine if found locally. if not matches.intersection(orphaned_res) and not force: print('Unit %s found in %s defined previously, \ skipping to avoid redefinition\n' % (' '.join(match for match in matches), fname)) else: if not matches.intersection(orphaned_res): print('Unit %s found in %s defined previously, \ adding user-provided lib but redefinition may cause problems\n' \ % (' '.join(match for match in matches), fname)) libs.add(fname) frcmod = util.get_base(fname) + '.frcmod' if os.path.isfile(frcmod): libs.add(frcmod) orphaned_res -= matches
def do_antechamber(fname, net_charge, ff, molname, base=''): ''' Run antechamber and get correctly named versions of the following: mol2 with bcc charges, frcmod, lib, prmtop, inpcrd ''' if not base: base = util.get_base(fname) ext = os.path.splitext(fname)[-1] ext = ext.lstrip('.') mol2 = base + '_amber.mol2' #TODO: known issues with phosphates (see PDB: 2PQC) when getting the net #charge from Gasteiger charges computed with Open Babel try: command = antechamber['-i', fname, '-fi', ext, '-o', mol2, '-fo', 'mol2', '-c', 'bcc', '-nc', str(net_charge), '-s', '2'] runfile.writeln(command) command() except Exception as e: passed = False charges = [] if net_charge != 0: charges.append(0) if net_charge != -1: charges.append(-1) for charge in charges: try: command = antechamber['-i', fname, '-fi', ext, '-o', mol2, '-fo', 'mol2', '-c', 'bcc', '-nc', str(charge), '-s', '2'] runfile.writeln(command) command() passed = True break except Exception as e: pass if not passed: print('Antechamber failed. Check {0} structure. Aborting...\n'. format(fname)) sys.exit() frcmod = base + '.frcmod' parmchk['-i', mol2, '-f', 'mol2', '-o', frcmod]() make_amber_parm(mol2, base, ff, molname=molname, frcmod=frcmod)
#pdb4amber seems to delete mercury (HG) along with hydrogens; for now my #hacky fix is to store the relevant atom info if mercury is present and add #the mercury back in after stripping...I'm preemptively doing this for #hafnium too metal_info = {} #if any structure was not provided in PDB format, we will attempt to create #one from what was provided using obabel, choosing a filename that will not #overwrite anything in the directory (optionally) for structure in args.structures: net_charge = None #the "structure" string in the args.structure list will be updated so #that it corresponds to the PDB we should use for subsequent steps assert os.path.isfile(structure), '%s does not exist\n' % structure #"base" is the base filename (no extension) from which others will be derived base = util.get_base(structure) ext = os.path.splitext(structure)[-1] if 'pdb' not in ext: #if it's a mol2, store the net_charge from the input because #conversion to a pdb and back to a mol2 with openbabel is not #guaranteed to result in the same partial charges if args.net_charge: net_charge = args.net_charge elif 'mol2' in ext: net_charge = util.get_charge(structure) outpdb = base + '.pdb' if not args.overwrite: outpdb = util.get_fname(outpdb) try: obabel[structure, '-O', outpdb, '-xn']() except Exception as e:
def reparm(ligands, base): print( '**Running reparameterization of ligand(s) using open force fields\'s SMIRNOFF with openff 2.0.0**' ) # Load already parm'd system in_prmtop = base + '.prmtop' in_crd = base + '.inpcrd' # Create parmed strucuture orig_structure = parmed.amber.AmberParm(in_prmtop, in_crd) # Split orig_stucuture into unique structure instances e.g. protein, water, ligand, etc. pieces = orig_structure.split() for piece in pieces: # TODO: Figure out how to know which piece is which print(f"There are {len(piece[1])} instance(s) of {piece[0]}") # Generate an openff topology for the ligand # Openff Molecule does not support mol2 so conversion is needed ligs_w_sdf = [] for ligand in ligands: obabel[ligand[0], '-O', util.get_base(ligand[0]) + '.sdf']() ligs_w_sdf.append( (ligand[0], ligand[1], util.get_base(ligand[0]) + '.sdf')) # Keep track of ligands that were successfully reparmed so we know to skip them when putting the pieces back together reparmed_pieces = [] complex_structure = parmed.Structure() force_field = ForceField("openff_unconstrained-2.0.0.offxml") for lig in ligs_w_sdf: # Set up openff topology ligand_off_molecule = Molecule(lig[2]) ligand_pdbfile = PDBFile(lig[0]) ligand_off_topology = Topology.from_openmm( ligand_pdbfile.topology, unique_molecules=[ligand_off_molecule], ) # Parameterizing the ligand # Find ligand "piece", reparm, add to the new structure for piece in pieces: new_ligand_structure = None # TODO: Figure out how to know which piece is which if (ligand_off_molecule.n_atoms == len(piece[0].atoms)): if (ligand_off_molecule.n_bonds == len(piece[0].bonds)): if ([ atom.atomic_number for atom in ligand_off_molecule.atoms ] == [atom.element for atom in piece[0].atoms]): print('Found ligand piece', piece) try: # Since the method of matching the piece to ligand is imperfect, ligands that are isomers could mess things up. # So try any piece that matches and see if we get an error print('Reparameterizing ligand using SMIRNOFF') ligand_system = force_field.create_openmm_system( ligand_off_topology) new_ligand_structure = parmed.openmm.load_topology( ligand_off_topology.to_openmm(), ligand_system, xyz=piece[0].positions, ) # A quick check to make sure things were not messed up during param if check_discrepencies(new_ligand_structure, piece): # Add the newly parameterized ligand the complex structure reparmed_pieces.append(piece) new_ligand_structure *= len(piece[1]) complex_structure += parmed.amber.AmberParm.from_structure( new_ligand_structure) break except: pass # Stick all the pieces back together for piece in pieces: if (piece not in reparmed_pieces): curr_structure = parmed.Structure() curr_structure += piece[0] curr_structure *= len(piece[1]) complex_structure += parmed.amber.AmberParm.from_structure( curr_structure) # print("Unique atom names:",sorted(list({atom.atom_type.name for atom in complex_structure})),) # print("Number of unique atom types:", len({atom.atom_type for atom in complex_structure})) # print("Number of unique epsilons:", len({atom.epsilon for atom in complex_structure})) # print("Number of unique sigmas:", len({atom.sigma for atom in complex_structure})) # # Copy over the original coordinates and box vectors complex_structure.coordinates = orig_structure.coordinates complex_structure.box_vectors = orig_structure.box_vectors # Save the newly parameterized system complex_structure.save(base + ".prmtop", overwrite=True) complex_structure.save(base + ".inpcrd", overwrite=True)