def writeRTF(mol, parameters, netcharge, filename): from moleculekit.periodictable import periodictable_by_number f = open(filename, "w") print("* Charmm RTF built by HTMD parameterize version {}".format( version()), file=f) print("* ", file=f) print(" 22 0", file=f) types = getSortedAndUniqueTypes(mol.atomtype, "atom_types") for type in types: val = parameters.atom_types[type] print( "MASS %5d %s %8.5f %s" % ( val.number, type, val.mass, periodictable_by_number[val.atomic_number].symbol, ), file=f, ) print("\nAUTO ANGLES DIHE\n", file=f) assert (np.unique(mol.resname).size == 1 ) # Check if all atoms have the same residue name print("RESI %s %8.5f" % (mol.resname[0], netcharge), file=f) print("GROUP", file=f) maxnamelen = max(4, np.max([len(na) for na in mol.name])) # Minimum field size of 4 maxatomtypelen = max(6, np.max([len(at) for at in mol.atomtype ])) # Minimum field size of 6 for n, a, c in zip(mol.name, mol.atomtype, mol.charge): print( "ATOM {0:>{1}s} {2:>{3}s} {4:8.6f}".format(n, maxnamelen, a, maxatomtypelen, c), file=f, ) for a in mol.bonds: print( "BOND {:>4s} {:>4s}".format( *sorted([mol.name[a[0]], mol.name[a[1]]])), file=f, ) for a in mol.impropers: print( "IMPR %4s %4s %4s %4s" % (mol.name[a[0]], mol.name[a[1]], mol.name[a[2]], mol.name[a[3]]), file=f, ) print("PATCH FIRST NONE LAST NONE", file=f) print("\nEND", file=f) f.close()
def getArgumentParser(): parser = argparse.ArgumentParser( description="Acellera small molecule parameterization tool") parser.add_argument("filename", help="Molecule file in MOL2 format") parser.add_argument( "-c", "--charge", type=int, help="Total charge of the molecule (default: sum of partial charges)", ) parser.add_argument("-l", "--list", action="store_true", help="List parameterizable dihedral angles") parser.add_argument("--rtf-prm", nargs=2, metavar="<filename>", help="CHARMM RTF and PRM files") parser.add_argument( "-ff", "--forcefield", default="GAFF2", choices=fftypemethods, help= "Initial atom type and parameter assignment (default: %(default)s)", ) parser.add_argument( "--fix-charge", nargs="+", default=[], metavar="<atom name>", help="Fix atomic charge during charge fitting (default: none)", ) parser.add_argument( "-d", "--dihedral", nargs="+", default=[], metavar="A1-A2-A3-A4", help= "Select dihedral angle to parameterize (default: all parameterizable dihedral angles)", ) parser.add_argument( "--code", default="Psi4", choices=["Psi4", "Gaussian"], help="QM code (default: %(default)s)", ) parser.add_argument( "--theory", default="wB97X-D", choices=["HF", "B3LYP", "wB97X-D"], help="QM level of theory (default: %(default)s)", ) parser.add_argument( "--basis", default="6-311++G**", choices=[ "6-31G*", "6-31+G*", "6-311G**", "6-311++G**", "cc-pVDZ", "aug-cc-pVDZ", ], help="QM basis set (default: %(default)s)", ) parser.add_argument( "--environment", default="vacuum", choices=["vacuum", "PCM"], help="QM environment (default: %(default)s)", ) parser.add_argument( "--min-type", default="mm", dest="min_type", choices=["None", "qm", "mm"], help="Type of initial structure optimization (default: %(default)s)", ) parser.add_argument( "--charge-type", default="AM1-BCC", choices=["None", "Gasteiger", "AM1-BCC", "ESP"], help="Partial atomic charge type (default: %(default)s)", ) parser.add_argument( "--no-dihed", action="store_false", dest="fit_dihedral", help="Do not perform QM scanning of dihedral angles", ) parser.add_argument( "--scan-type", default="mm", dest="dihed_opt_type", choices=["None", "qm", "mm"], help= "Type of structure optimization when scanning dihedral angles (default: %(default)s)", ) parser.add_argument( "--dihed-num-iterations", default=3, type=int, help="Number of iterations during the dihedral parameter fitting", ) parser.add_argument( "--dihed-fit-type", default="iterative", choices=["iterative", "NRS"], help= "Dihedral fitting method. Can be either iterative or naive random search (NRS).", ) parser.add_argument( "-q", "--queue", default="local", choices=["local", "Slurm", "LSF"], help="QM queue (default: %(default)s)", ) parser.add_argument( "-n", "--ncpus", default=None, type=int, help="Number of CPU per QM job (default: queue defaults)", ) parser.add_argument( "-m", "--memory", default=None, type=int, help="Maximum amount of memory in MB to use.", ) parser.add_argument("--groupname", default=None, help=argparse.SUPPRESS) parser.add_argument("-o", "--outdir", default="./", help="Output directory (default: %(default)s)") parser.add_argument( "--seed", default=20170920, type=int, help="Random number generator seed (default: %(default)s)", ) parser.add_argument("--version", action="version", version=version()) # Enable replacement of any real QM class with FakeQM. # This is intedended for debugging only and should be kept hidden. parser.add_argument( "--fake-qm", action="store_true", default=False, dest="fake_qm", help=argparse.SUPPRESS, ) # NNP module name parser.add_argument("--nnp", help=argparse.SUPPRESS) # PlayQueue arguments parser.add_argument("--pm-token", help=argparse.SUPPRESS) parser.add_argument("--max-jobs", type=int, default=sys.maxsize, help=argparse.SUPPRESS) # Debug mode parser.add_argument( "--debug", action="store_true", default=False, dest="debug", help=argparse.SUPPRESS, ) return parser
def writeFRCMOD(mol, parameters, filename, typemap=None): if typemap is not None: parameters = mapAtomTypesParameterSet(parameters, typemap) atomtypes = np.vectorize(typemap.get)(mol.atomtype) else: atomtypes = mol.atomtype f = open(filename, "w") f.write("Frcmod generated by HTMD parameterize version {}\n".format( version())) f.write("MASS\n") for at in np.unique(atomtypes): f.write("{:<2s} {:>8.3f} {:>10.2f}\n".format( at, parameters.atom_types[at].mass, 0.0)) f.write("\nBOND\n") types = getSortedAndUniqueTypes(atomtypes[mol.bonds], "bond_types") for type in types: val = getParameter(type, parameters.bond_types) f.write("{:<2s}-{:<2s} {:>10.3f}{:>8.3f}\n".format( type[0], type[1], val.k, val.req)) f.write("\nANGL\n") types = getSortedAndUniqueTypes(atomtypes[mol.angles], "angle_types") for type in types: val = getParameter(type, parameters.angle_types) f.write("{:<2s}-{:<2s}-{:<2s} {:>10.3f}{:>9.3f}\n".format( type[0], type[1], type[2], val.k, val.theteq)) f.write("\nDIHE\n") types = getSortedAndUniqueTypes(atomtypes[mol.dihedrals], "dihedral_types") for type in types: val = getParameter(type, parameters.dihedral_types) toprint = [] for term in val: if term.phi_k < 1e-6: continue toprint.append(term) # HACK: print at least one dihedral, even if the force constant is 0, otherwise "tleap" is not happy! if len(toprint) == 0: toprint.append(val[0]) for i, term in enumerate(toprint): # All terms of the same dihedral except the last one should be negative. http://ambermd.org/formats.html#frcmod per = term.per if i != len(toprint) - 1: per = -per fmt = "{:<2s}-{:<2s}-{:<2s}-{:<2s} {:>4d}{:>15.8f}{:>9.3f}{:>6.1f} SCEE={:1.1f} SCNB={:1.1f}\n" f.write( fmt.format( type[0], type[1], type[2], type[3], 1, term.phi_k, term.phase, per, term.scee, term.scnb, )) f.write("\nIMPR\n") types = getSortedAndUniqueTypes(atomtypes[mol.impropers], "improper_types") for type in types: type, field = findImproperType(type, parameters) val = parameters.__dict__[field][type] fmt = "{:<2s}-{:<2s}-{:<2s}-{:<2s} {:>10.8f}{:>9.3f}{:>6.1f}\n" if field == "improper_periodic_types": if val.phi_k < 1e-6: continue f.write( fmt.format(type[0], type[1], type[2], type[3], val.phi_k, val.phase, val.per)) elif field == "improper_types": if val.psi_k < 1e-6: continue f.write( fmt.format(type[0], type[1], type[2], type[3], val.psi_k, val.psi_eq, 1)) f.write("\nNONB\n") # Have to iterate over the types in use, which include cloned types, and map them back # to original type (which has the same vdw params), because a copy of a copy won't be in self.nonbonded. types = getSortedAndUniqueTypes(atomtypes, "atom_types") for type in types: val = parameters.atom_types[type] f.write("{:<2s} {:>10.8f} {:>10.8f}\n".format( type, val.rmin, val.epsilon)) f.write("\n") f.close()
def writePRM(mol, parameters, filename): from parameterize.util import ensurelist # for type, val in parameters.atom_types.items(): # if val.epsilon_14 != 1.0: # raise ValueError("Can't express 1-4 electrostatic scaling in Charmm file format") f = open(filename, "w") print("* prm file built by HTMD parameterize version {}".format(version()), file=f) print("*\n", file=f) print("BONDS", file=f) types = getSortedAndUniqueTypes(mol.atomtype[mol.bonds], "bond_types") for type in types: val = getParameter(type, parameters.bond_types) print("%-6s %-6s %8.2f %8.4f" % (type[0], type[1], val.k, val.req), file=f) print("\nANGLES", file=f) types = getSortedAndUniqueTypes(mol.atomtype[mol.angles], "angle_types") for type in types: val = getParameter(type, parameters.angle_types) print( "%-6s %-6s %-6s %8.2f %8.2f" % (type[0], type[1], type[2], val.k, val.theteq), file=f, ) print("\nDIHEDRALS", file=f) types = getSortedAndUniqueTypes(mol.atomtype[mol.dihedrals], "dihedral_types") for type in types: val = getParameter(type, parameters.dihedral_types) for term in val: print( "%-6s %-6s %-6s %-6s %12.8f %d %12.8f" % ( type[0], type[1], type[2], type[3], term.phi_k, term.per, term.phase, ), file=f, ) print("\nIMPROPER", file=f) types = getSortedAndUniqueTypes(mol.atomtype[mol.impropers], "improper_types") for type in types: type, field = findImproperType(type, parameters) val = parameters.__dict__[field][type] if field == "improper_periodic_types": for term in ensurelist(val): print( "%-6s %-6s %-6s %-6s %12.8f %d %12.8f" % ( type[0], type[1], type[2], type[3], term.phi_k, term.per, term.phase, ), file=f, ) elif field == "improper_types": print( "%-6s %-6s %-6s %-6s %12.8f %d %12.8f" % (type[0], type[1], type[2], type[3], val.psi_k, 0, val.psi_eq), file=f, ) print("\nNONBONDED nbxmod 5 atom cdiel shift vatom vdistance vswitch -", file=f) print("cutnb 14.0 ctofnb 12.0 ctonnb 10.0 eps 1.0 e14fac 1.0 wmin 1.5", file=f) types = getSortedAndUniqueTypes(mol.atomtype, "atom_types") for type in types: val = parameters.atom_types[type] if val.epsilon_14 != val.epsilon: print( "%-6s 0.0000 %8.4f %8.4f 0.0000 %8.4f %8.4f" % (type, val.epsilon, val.rmin, val.epsilon_14, val.rmin_14), file=f, ) else: print("%-6s 0.0000 %8.4f %8.4f" % (type, val.epsilon, val.rmin), file=f) f.close()