def SaveITPFile(path, mol, pmol=None): print("Saving molecule %s to ITP file at path %s." % (mol.GetName(), str(os.path.join(os.getcwd(), path)))) path = Path(path) h_mass = ix.GetPeriodicTable()["H"].GetAtomicMass() path.parent.mkdir(parents=True, exist_ok=True) file = path.open('w') # header printing header = """; File generated by the indigox package ; No guarantees are provided for the usefulness of this file [ moleculetype ] ; Name nrexcl TEST 3 [ atoms ]""" print(header, file=file) # atom printing atm_fmt_str = "{index:>5} {type:>6} {residx:>5} {resname:>8} {name:>7} {chargegroup:>5} {charge:>11.5f} {mass:>9.4f} {extra}" for atom in mol.GetAtoms(): atm_dat = { "index": atom.GetIndex() + 1, "type": atom.GetType().GetName() if atom.HasType() else "%%%", "residx": atom.GetResidueID(), "resname": atom.GetResidueName(), "name": atom.GetName(), "chargegroup": atom.GetChargeGroupID() + 1, "charge": atom.GetPartialCharge(), "mass": atom.GetElement().GetAtomicMass() + atom.GetImplicitCount() * h_mass, "extra": "" } if pmol is not None: patom = pmol.GetAtom(atom) extra_info = ";" if not len(patom.GetMappedCharges()): extra_info += " UNMAPPED" else: mu = patom.MeanCharge() eta = patom.MedianCharge() sigma = patom.StandardDeviationCharge() delta = patom.RedistributedChargeAdded() to_add = [] if round(mu, 5) != round(eta, 5) or round(sigma, 5) != 0.0: to_add.append("mean: {:.5f}".format(mu)) to_add.append("median: {:.5f}".format(eta)) to_add.append("stdev: {:.5f}".format(sigma)) if round(delta, 5) != 0.0: to_add.append("added: {:.5f}".format(delta)) extra_info += " " + ','.join(to_add) if extra_info == ";": atm_dat["extra"] = "" else: atm_dat["extra"] = extra_info print(atm_fmt_str.format(**atm_dat), file=file) # bond printing print("\n[ bonds ]", file=file) bnd_fmt_str = "{atoma:>5} {atomb:>5} {typecode:>5} gb_{typeid} {extra}" for bond in sorted(mol.GetBonds(), key=lambda x: x.HasType()): bnd_dat = { "atoma": bond.GetAtoms()[0].GetIndex() + 1, "atomb": bond.GetAtoms()[1].GetIndex() + 1, "typecode": 2, "typeid": bond.GetType().GetID() if bond.HasType() else "UNMAPPED" } if pmol is not None and bond.HasType(): pbond = pmol.GetBond(bond) other = [ "gb_{}".format(tm.GetID()) for tm in pbond.GetMappedTypeCounts() ] bnd_dat["extra"] = ", ".join( x for x in other if x != "gb_{}".format(bnd_dat["typeid"])) else: bnd_dat["extra"] = "" if bnd_dat["extra"]: bnd_dat["extra"] = "; Other terms: " + bnd_dat["extra"] print(bnd_fmt_str.format(**bnd_dat), file=file) # pairs printing print("\n[ pairs ]", file=file) pair_fmt_str = "{atoma:>5} {atomb:>5} 1" for dhd in mol.GetDihedrals(): atoms = dhd.GetAtoms() if not mol.HasBond(atoms[0], atoms[1]): continue if not mol.HasBond(atoms[1], atoms[2]): continue if not mol.HasBond(atoms[2], atoms[3]): continue if ((mol.GetBond(atoms[0], atoms[1]).GetOrder() == ix.BondOrder.Aromatic) and (mol.GetBond( atoms[1], atoms[2]).GetOrder() == ix.BondOrder.Aromatic) and (mol.GetBond(atoms[2], atoms[3]).GetOrder() == ix.BondOrder.Aromatic)): continue if atoms[0].GetIndex() > atoms[3].GetIndex(): pair_dat = { "atoma": atoms[3].GetIndex() + 1, "atomb": atoms[0].GetIndex() + 1 } else: pair_dat = { "atoma": atoms[0].GetIndex() + 1, "atomb": atoms[3].GetIndex() + 1 } print(pair_fmt_str.format(**pair_dat), file=file) # angle printing print("\n[ angles ]", file=file) ang_fmt_str = "{atoma:>5} {atomb:>5} {atomc:>5} {typecode:>5} ga_{typeid} {extra}" for angle in sorted(mol.GetAngles(), key=lambda x: x.HasType()): atoms = angle.GetAtoms() ang_dat = { "atoma": atoms[0].GetIndex() + 1, "atomb": atoms[1].GetIndex() + 1, "atomc": atoms[2].GetIndex() + 1, "typecode": 2, "typeid": angle.GetType().GetID() if angle.HasType() else "UNMAPPED", "extra": "" } if pmol is not None and angle.HasType(): pangle = pmol.GetAngle(angle) other = [ "ga_{}".format(tm.GetID()) for tm in pangle.GetMappedTypeCounts() ] ang_dat["extra"] = ", ".join( x for x in other if x != "ga_{}".format(ang_dat["typeid"])) if ang_dat["extra"]: ang_dat["extra"] = "; Other terms: " + ang_dat["extra"] print(ang_fmt_str.format(**ang_dat), file=file) # dihedral printing print("\n[ dihedrals ]", file=file) dhd_fmt_str = "{atoma:>5} {atomb:>5} {atomc:>5} {atomd:>5} {typecode:>5} {typeid} {extra}" done_dhds = [] for bnd in mol.GetBonds(): dhds = _GetBondDihedrals(bnd) if not dhds: continue param_dhd = [x for x in dhds if x.HasType()] if not param_dhd: done_dhds.append(dhds[0]) else: done_dhds.extend(param_dhd) for dhd in mol.GetDihedrals(): if dhd.HasType() and dhd not in done_dhds: done_dhds.append(dhd) for dhd in sorted(done_dhds, key=lambda x: x.HasType()): atoms = dhd.GetAtoms() if not dhd.HasType(): dhd_dat = { "atoma": atoms[0].GetIndex() + 1, "atomb": atoms[1].GetIndex() + 1, "atomc": atoms[2].GetIndex() + 1, "atomd": atoms[3].GetIndex() + 1, "extra": "", "typecode": "", "typeid": "UNMAPPED" } print(dhd_fmt_str.format(**dhd_dat), file=file) else: for t in dhd.GetTypes(): dhd_dat = { "atoma": atoms[0].GetIndex() + 1, "atomb": atoms[1].GetIndex() + 1, "atomc": atoms[2].GetIndex() + 1, "atomd": atoms[3].GetIndex() + 1, "extra": "" } if t.GetType() == ix.DihedralType.Proper: dhd_dat["typecode"] = 1 dhd_dat["typeid"] = "gd_{}".format(t.GetID()) else: dhd_dat["typecode"] = 2 dhd_dat["typeid"] = "gi_{}".format(t.GetID()) print(dhd_fmt_str.format(**dhd_dat), file=file) file.close()
def LoadIFPFile(path): pt = ix.GetPeriodicTable() data = list(ix.LoadFile(path.expanduser())) blocks = [data[0]] for i in range(len(data) - 1): if data[i] == 'END': blocks.append(data[i + 1]) ff = ix.Forcefield(ix.FFFamily.GROMOS, path.stem) for b in blocks: start = data.index(b) + 1 end = data[start:].index('END') + start if b == 'BONDSTRETCHTYPECODE': ff.ReserveBondTypes(ix.BondType.Harmonic, int(data[start].split()[0])) ff.ReserveBondTypes(ix.BondType.Quartic, int(data[start].split()[0])) for line in data[start + 1:end]: idx, kq, kh, b0 = map(float, line.split()) ff.LinkBondTypes( ff.NewBondType(ix.BondType.Harmonic, int(idx), kh, b0), ff.NewBondType(ix.BondType.Quartic, int(idx), kq, b0)) elif b == 'BONDANGLEBENDTYPECODE': ff.ReserveAngleTypes(ix.AngleType.Harmonic, int(data[start].split()[0])) ff.ReserveAngleTypes(ix.AngleType.CosineHarmonic, int(data[start].split()[0])) for line in data[start + 1:end]: idx, kch, kh, t0 = map(float, line.split()) ff.LinkAngleTypes( ff.NewAngleType(ix.AngleType.Harmonic, int(idx), kh, t0), ff.NewAngleType(ix.AngleType.CosineHarmonic, int(idx), kch, t0)) elif b == 'IMPDIHEDRALTYPECODE': ff.ReserveDihedralTypes(ix.DihedralType.Improper, int(data[start].split()[0])) for line in data[start + 1:end]: idx, k, epsilon = map(float, line.split()) ff.NewDihedralType(ix.DihedralType.Improper, int(idx), k, epsilon) elif b == 'TORSDIHEDRALTYPECODE': ff.ReserveDihedralTypes(ix.DihedralType.Proper, int(data[start].split()[0])) for line in data[start + 1:end]: idx, k, phase, m = map(float, line.split()) ff.NewDihedralType(ix.DihedralType.Proper, int(idx), k, phase, int(m)) elif b == 'SINGLEATOMLJPAIR': num_lines = int((end - start - 1) / int(data[start])) atm_count = int(data[start]) ff.ReserveAtomTypes(atm_count) for i in range(atm_count): lines = [] for j in range(num_lines): lines.append(data[start + 1 + j + i * num_lines]) dat = " ".join(x for x in lines).split() atm_dat = { 'int_code': int(dat[0]), 'name': dat[1], 'c6': float(dat[2])**2, 'c12': [ float(dat[3])**2, float(dat[4])**2, float(dat[5])**2, ], 'c6_1_4': float(dat[6])**2, 'c12_1_4': float(dat[7])**2, 'interactions': dict(), } ff.NewAtomType(int(dat[0]), dat[1], pt[dat[1][0]]) return ff
def SaveRTPFile(path, mol, pmol=None): print("Saving molecule %s to RTP file at path %s." % (mol.GetName(), str(os.path.join(os.getcwd(), path)))) path = Path(path) h_mass = ix.GetPeriodicTable()["H"].GetAtomicMass() path.parent.mkdir(parents=True, exist_ok=True) file = path.open('w') # header printing header = """; File generated by the indigox package ; No guarantees are provided for the usefulness of this file [ {} ] [ atoms ]""" print(header.format(mol.GetAtoms()[0].GetResidueName()), file=file) # atom printing atm_fmt_str = "{name:>5} {type:>6} {charge:>11.5f} {chargegroup:>5} {extra}" for atom in mol.GetAtoms(): atm_dat = { "type": atom.GetType().GetName() if atom.HasType() else "%%%", "name": atom.GetName(), "chargegroup": atom.GetChargeGroupID() + 1, "charge": atom.GetPartialCharge(), "extra": "" } if pmol is not None: patom = pmol.GetAtom(atom) extra_info = ";" if not len(patom.GetMappedCharges()): extra_info += " UNMAPPED" else: mu = patom.MeanCharge() eta = patom.MedianCharge() sigma = patom.StandardDeviationCharge() delta = patom.RedistributedChargeAdded() to_add = [] if round(mu, 5) != round(eta, 5) or round(sigma, 5) != 0.0: to_add.append("mean: {:.5f}".format(mu)) to_add.append("median: {:.5f}".format(eta)) to_add.append("stdev: {:.5f}".format(sigma)) if round(delta, 5) != 0.0: to_add.append("added: {:.5f}".format(delta)) extra_info += " " + ", ".join(to_add) if extra_info == ";": atm_dat["extra"] = "" else: atm_dat["extra"] = extra_info print(atm_fmt_str.format(**atm_dat), file=file) # bond printing print(" [ bonds ]", file=file) bnd_fmt_str = "{atoma:>5} {atomb:>5} {typeid} {extra}" for bond in sorted(mol.GetBonds(), key=lambda x: x.HasType()): bnd_dat = { "atoma": bond.GetAtoms()[0].GetName(), "atomb": bond.GetAtoms()[1].GetName(), "extra": "" } if not bond.HasType(): bnd_dat["typeid"] = "UNMAPPED" else: t = bond.GetType() if t.GetType() != ix.BondType.Quartic: t = t.GetLinkedType() bnd_dat["typeid"] = "{:>.4f} {:>.4e}".format( t.GetIdealLength(), t.GetForceConstant()) if pmol is not None and bond.HasType(): pbond = pmol.GetBond(bond) other = [ "gb_{}".format(tm.GetID()) for tm in pbond.GetMappedTypeCounts() ] bnd_dat["extra"] = ", ".join( x for x in other if x != "gb_{}".format(bond.GetType().GetID())) else: bnd_dat["extra"] = "" if bnd_dat["extra"]: bnd_dat["extra"] = "; Other terms: " + bnd_dat["extra"] print(bnd_fmt_str.format(**bnd_dat), file=file) # exclusions printing print(" [ exclusions ]", file=file) pair_fmt_str = "{atoma:>5} {atomb:>5}" for dhd in mol.GetDihedrals(): atoms = dhd.GetAtoms() if not mol.HasBond(atoms[0], atoms[1]): continue if not mol.HasBond(atoms[1], atoms[2]): continue if not mol.HasBond(atoms[2], atoms[3]): continue rot_bond = mol.GetBond(atoms[1], atoms[2]) if rot_bond.GetOrder() == ix.BondOrder.Aromatic: pair_dat = { "atoma": atoms[3].GetName(), "atomb": atoms[0].GetName() } print(pair_fmt_str.format(**pair_dat), file=file) # angle printing print(" [ angles ]", file=file) ang_fmt_str = "{atoma:>5} {atomb:>5} {atomc:>5} {typeid} {extra}" for angle in sorted(mol.GetAngles(), key=lambda x: x.HasType()): atoms = angle.GetAtoms() ang_dat = { "atoma": atoms[0].GetName(), "atomb": atoms[1].GetName(), "atomc": atoms[2].GetName(), "extra": "" } if not angle.HasType(): ang_dat["typeid"] = "UNMAPPED" else: t = angle.GetType() if t.GetType() != ix.AngleType.CosineHarmonic: t = t.GetLinkedType() ang_dat["typeid"] = "{:>.2f} {:>.2f}".format( t.GetIdealAngle(), t.GetForceConstant()) if pmol is not None and angle.HasType(): pangle = pmol.GetAngle(angle) other = [ "ga_{}".format(tm.GetID()) for tm in pangle.GetMappedTypeCounts() ] ang_dat["extra"] = ", ".join( x for x in other if x != "ga_{}".format(angle.GetType().GetID())) if ang_dat["extra"]: ang_dat["extra"] = "; Other terms: " + ang_dat["extra"] print(ang_fmt_str.format(**ang_dat), file=file) # improper printing done_dhds = [] print(" [ impropers ]", file=file) dhd_fmt_str = "{atoma:>5} {atomb:>5} {atomc:>5} {atomd:>5} {typeid} {extra}" for imp in mol.GetDihedrals(): if not imp.HasType(): continue for t in imp.GetTypes(): if t.GetType() != ix.DihedralType.Improper: continue atoms = imp.GetAtoms() imp_dat = { "atoma": atoms[0].GetName(), "atomb": atoms[1].GetName(), "atomc": atoms[2].GetName(), "atomd": atoms[3].GetName(), "typeid": "{:>.5f} {:>.5f}".format( t.GetIdealAngle(), t.GetForceConstant() * improper_correction), "extra": "" } print(dhd_fmt_str.format(**imp_dat), file=file) # dihedral printing print(" [ dihedrals ]", file=file) for bnd in mol.GetBonds(): dhds = _GetBondDihedrals(bnd) if not dhds: continue param_dhd = [x for x in dhds if x.HasType()] if not param_dhd: done_dhds.append(dhds[0]) else: done_dhds.extend(param_dhd) for dhd in mol.GetDihedrals(): if dhd.HasType() and dhd not in done_dhds: done_dhds.append(dhd) for dhd in sorted(done_dhds, key=lambda x: x.HasType()): atoms = dhd.GetAtoms() if not dhd.HasType(): dhd_dat = { "atoma": atoms[0].GetName(), "atomb": atoms[1].GetName(), "atomc": atoms[2].GetName(), "atomd": atoms[3].GetName(), "extra": "", "typeid": "UNMAPPED" } print(dhd_fmt_str.format(**dhd_dat), file=file) else: for t in dhd.GetTypes(): dhd_dat = { "atoma": atoms[0].GetName(), "atomb": atoms[1].GetName(), "atomc": atoms[2].GetName(), "atomd": atoms[3].GetName(), "extra": "" } if t.GetType() == ix.DihedralType.Proper: dhd_dat["typeid"] = "{:.4f} {:.4f} {}".format( t.GetPhaseShift(), t.GetForceConstant(), t.GetMultiplicity()) print(dhd_fmt_str.format(**dhd_dat), file=file) file.close()