def pqr2pdb(line, counter): counter += 1 (aname, anumb_old, resname, chain, resnumb, x, y, z) = read_pdb_line(line) # if chain == "_": # chain = " " if resname in RNA_RESIDUES: resname = RNA_RESIDUES[resname] incorrect_rna_ops = {"OP1": "O1P", "OP2": "O2P"} if aname in incorrect_rna_ops: aname = incorrect_rna_ops[aname] return ( new_pdb_line(counter, aname, resname, resnumb, x, y, z, chain=chain), counter, )
def remove_membrane_n_rna(pdbfile, outfile): protein_lines = "" to_remove = LIPID_RESIDUES + list(Config.pypka_params.LIPIDS.values()) with open(pdbfile) as f: for line in f: if line.startswith("ATOM"): (aname, anumb, resname, chain, resnumb, x, y, z) = read_pdb_line(line) insertion_code = line[26].strip() if insertion_code: continue if aname[0] == "H" and Config.pypka_params["remove_hs"]: continue if Config.pypka_params["ffinput"] == "CHARMM": if resname in ("HSD", "HSE"): resname = "HSP" if resname not in to_remove: if resname in PDB_RNA_RESIDUES: resname = PDB_RNA_RESIDUES[resname] protein_lines += new_pdb_line(anumb, aname, resname, resnumb, x, y, z, chain=chain) elif line.startswith("ENDMDL"): break with open(outfile, "w") as f_new: f_new.write(protein_lines) # rna_fname = None # if rna_lines: # rna_fname = "tmp_rna.pdb" # with open(rna_fname, "w") as f_new: # f_new.write(rna_lines) return # rna_fname
def fix_fixed_sites(molecules, fixed_sites, fname): for chain in fixed_sites: for site, state in list(fixed_sites[chain].items()): if isinstance(site, str) and site[-1] in "NC": del fixed_sites[chain][site] site = int(site[:-1]) + TERMINAL_OFFSET fixed_sites[chain][site] = state for molecule in molecules.values(): chain = molecule.chain for sitenumb, site in list(molecule.sites.items()): if sitenumb in fixed_sites[chain]: del molecule.sites[sitenumb] site_i = molecule.sites_order.index(site) del molecule.sites_order[site_i] new_pdb_content = "" with open(fname) as f: for line in f: if line.startswith("ATOM "): (aname, anumb, resname, chain, resnumb, x, y, z) = read_pdb_line(line) if resnumb in fixed_sites[chain]: resname = "{}{}".format(resname[:-1], str(fixed_sites[chain][resnumb])) new_pdb_content += new_pdb_line(anumb, aname, resname, resnumb, x, y, z, chain=chain) else: new_pdb_content += line with open(fname, "w") as f: f.write(new_pdb_content)
def make_delphi_inputfile(f_in, f_out, molecules): def getMaxCoords(coords, max_coords): x, y, z = coords max_x, max_y, max_z = max_coords if max_x < x: max_x = x if max_y < y: max_y = y if max_z < z: max_z = z return max_x, max_y, max_z def correct_termini(resnumb, resname, aname, ntr_res, ctr_res): if resnumb == ntr_res and aname in Config.pypka_params["NTR_atoms"]: resname = "NTR" resnumb += TERMINAL_OFFSET elif resnumb == ctr_res and aname in Config.pypka_params["CTR_atoms"]: resname = "CTR" resnumb += TERMINAL_OFFSET # if aname == "C": # aname = "CT" return resnumb, resname, aname def correct_res_names(molecule, resnumb, resname, aname): if resnumb in list(molecule.correct_names.keys()): resname = molecule.correct_names[resnumb] if (resnumb in list(molecule.correct_atoms.keys()) and aname in molecule.correct_atoms[resnumb]): aname = molecule.correct_atoms[resnumb][aname] return resnumb, resname, aname def assign_atoms(sites, resnumb, aname, site_Hs, site_positions): ref_tau_name = resname if resnumb in list(sites.keys()) and aname in list( sites[resnumb].getRefTautomer().charge_set.keys()): # ( aname not in ('N', 'H', 'C', 'O', 'CA') or # (aname in ('N', 'H', 'C', 'O', 'CA') and resname == 'NTR')): # change res name to reference tautomer ref_tau_name = sites[resnumb].getRefTautomerName() # add atom to corresponding site sites[resnumb].addAtom(aname, anumb) if chain not in site_positions: site_positions[chain] = {} site_Hs[chain] = {} if resnumb not in site_positions[chain]: site_positions[chain][resnumb] = [] site_Hs[chain][resnumb] = [] if resnumb in site_positions[chain]: site_positions[chain][resnumb].append((x, y, z)) if aname[0] == "H": site_Hs[chain][resnumb].append((x, y, z)) return site_Hs, ref_tau_name, site_positions new_pdb_content = "" site_positions = {} site_Hs = {} max_box = [0.0, 0.0, 0.0] aposition = -1 sequence = {} with open(f_in) as f: for line in f: if line.startswith("ATOM"): aposition += 1 (aname, anumb, resname, chain, resnumb, x, y, z) = read_pdb_line(line) max_box = getMaxCoords([x, y, z], max_box) if chain not in sequence: sequence[chain] = {} if resnumb not in sequence[chain]: sequence[chain][resnumb] = resname if chain in molecules: molecule = molecules[chain] ntr_res = molecule.NTR ctr_res = molecule.CTR sites = molecule.sites if (resname == "HIS" and aname == "HD1" and resnumb not in sites.keys()): aposition -= 1 continue resnumb, resname, aname = correct_termini( resnumb, resname, aname, ntr_res, ctr_res) resnumb, resname, aname = correct_res_names( molecule, resnumb, resname, aname) titrable_res = False if resnumb in sites.keys(): titrable_res = True molecule.addAtom(aname, anumb, aposition, titrable_res) (site_Hs, resname, site_positions) = assign_atoms(sites, resnumb, aname, site_Hs, site_positions) else: if resname == "HIS" and aname == "HD1": aposition -= 1 continue resnumb, resname, aname = correct_res_names( molecule, resnumb, resname, aname) new_pdb_content += new_pdb_line(aposition, aname, resname, resnumb, x, y, z, chain=chain) elif line.startswith("CRYST1"): parts = line.split() box = [float(i) for i in parts[1:4]] if box == [1.0, 1.0, 1.0]: box = max_box if Config.pypka_params["box"]: box = Config.pypka_params["box"] else: Config.pypka_params.setBox(box) if Config.delphi_params["pbc_dim"] == 2: Config.delphi_params.redefineScale() new_pdb_content += "TER\nENDMDL\n" with open(f_out, "w") as f_new: f_new.write(new_pdb_content) # TODO: check terminal_offset has to be bigger than the total number of residues # TODO: delete terminal_offset and use another approach to distinguish between N- and C-ter # TODO: check size xy > config.cutoff * 2 # if so, raise Exception, and ask to change cutoff value # TODO: check if pbc_dim -> set gsizes from pdb size xy and ignore perfil for chain in site_positions.keys(): molecule = molecules[chain] for site in site_positions[chain]: if site in list(molecule.sites.keys()): pos_max = [-9999990, -999999, -999999] pos_min = [999999, 999999, 999999] focus_center = [0, 0, 0] for atom in site_positions[chain][site]: for i in range(3): if pos_max[i] < atom[i]: pos_max[i] = atom[i] if pos_min[i] > atom[i]: pos_min[i] = atom[i] focus_center[0] = (pos_max[0] + pos_min[0]) / 2 focus_center[1] = (pos_max[1] + pos_min[1]) / 2 focus_center[2] = (pos_max[2] + pos_min[2]) / 2 if Config.delphi_params["pbc_dim"] == 2: molecule.sites[site].addCenter(focus_center, boxsize=box[0], box_z=box[2]) else: molecule.sites[site].addCenter(focus_center) hx, hy, hz = 0, 0, 0 nHs = len(site_Hs[chain][site]) if nHs == 0: sitename = molecule.sites[site].getName() raise Exception("Site {1}{0} appears " "to have no Hydrogen atoms".format( site, sitename)) for h in site_Hs[chain][site]: hx += h[0] hy += h[1] hz += h[2] hx /= nHs hy /= nHs hz /= nHs Hcenter = (hx, hy, hz) molecule.sites[site].addCenterH(Hcenter) return sequence
def setDetailsFromTautomer(self): """Set DelPhi parameters to run a calculation of a single site tautomer.""" ( molecule, delphimol, p_atpos, p_rad3, p_chrgv4, atinf, p_iatmed, ) = self.getMoleculeDetails() if Config.delphi_params["pbc_dim"] == 2: ( _, half_box_xy, site_center, offset_x, offset_y, offset_z, box_x, box_y, ) = self.getCenteringDetails() pdb_text = "" site_atom_position = -1 for atom_name, atom_id, atom_position in molecule.iterAtoms(): if atom_id in self.site.getAtomNumbersList(): site_atom_position += 1 p_atpos[site_atom_position] = delphimol.p_atpos[atom_position] p_rad3[site_atom_position] = delphimol.p_rad3[atom_position] p_chrgv4[site_atom_position] = self.getCharge(atom_name) atinf[site_atom_position].value = delphimol.atinf[ atom_position].value # TODO: should be done only once per site if Config.delphi_params["pbc_dim"] == 2: p_atpos[site_atom_position][0] += offset_x p_atpos[site_atom_position][1] += offset_y p_atpos[site_atom_position][2] += offset_z p_atpos[atom_position] = self.putInsideBox( p_atpos[atom_position], box_x, box_y) # p_chrgv4[site_atom_position] = round(p_chrgv4[site_atom_position], 3) # p_rad3[site_atom_position] = round(p_rad3[site_atom_position], 3) aID = int(site_atom_position) aname, resname, chain, resnumb = self.read_atom_details( atinf, site_atom_position) x, y, z = self.read_atom_positions(p_atpos, site_atom_position) pdb_text += new_pdb_line(aID, aname, resname, resnumb, x, y, z, chain=chain) delphimol.changeStructureSize(p_atpos, p_rad3, p_chrgv4, atinf, p_iatmed, natoms=self.natoms) acent = self.getSiteAcent() if Config.debug: filename = "{1}-{0}.pdb".format(self.name, self.site.res_number) with open(filename, "w") as f_new: x, y, z = acent pdb_text += new_pdb_line(-1, "P", "CNT", -1, x, y, z) f_new.write(pdb_text) return delphimol, acent
def setDetailsFromWholeMolecule(self): """Set DelPhi parameters to run a calculation of a whole molecule (all sites neutral, except one).""" ( _, delphimol, p_atpos, p_rad3, p_chrgv4, atinf, p_iatmed, ) = self.getMoleculeDetails() if Config.delphi_params["pbc_dim"] == 2: ( box, _, _, offset_x, offset_y, offset_z, box_x, box_y, ) = self.getCenteringDetails() pdb_text = "" crg = "!crg file created by gen_files.awk\n" "atom__resnumbc_charge_\n" siz = "!siz file created by gen_files.awk\n" "atom__res_radius_\n" new_atoms = [] lookup_atoms_keys = Config.delphi_params.lookup_atoms.keys() for atom_position in range(delphimol.natoms): aID = atom_position + 1 aname, resname, chain, resnumb = self.read_atom_details( atinf, atom_position) x, y, z = self.read_atom_positions(p_atpos, atom_position) pdb_text += new_pdb_line(aID, aname, resname, resnumb, x, y, z, chain=chain) if atom_position in lookup_atoms_keys: atom_id, atom_name = Config.delphi_params.lookup_atoms[ atom_position] if atom_id in self.site.getAtomNumbersList(): p_chrgv4[atom_position] = self.getCharge(atom_name) else: p_chrgv4[atom_position] = 0.0 else: p_chrgv4[atom_position] = 0.0 if float(p_chrgv4[atom_position]) < 0.0: signal = "-" else: signal = " " crg += "{0:<6}{1:<7} {3}{2:0<5} \n".format( aname, resname, round(abs(p_chrgv4[atom_position]), 3), signal) siz += "{0:<6}{1:<4} {2:0<5} \n".format( aname, resname, round(abs(p_rad3[atom_position]), 3)) # TODO: quick fix, should be done only once per site if Config.delphi_params["pbc_dim"] == 2: p_atpos[atom_position][0] += offset_x p_atpos[atom_position][1] += offset_y p_atpos[atom_position][2] += offset_z p_atpos[atom_position] = self.putInsideBox( p_atpos[atom_position], box_x, box_y) # Comment 15 May 2019 # No rounding is better, however, pypka calculations # are no longer comparable to delphiT ones due to this #noregrets # rounding_precision = decimal.Decimal('0.01') # x_dec = decimal.Decimal(p_atpos[atom_position][0]) # y_dec = decimal.Decimal(p_atpos[atom_position][1]) # z_dec = decimal.Decimal(p_atpos[atom_position][2]) # p_atpos[atom_position][0] = float(x_dec.quantize(rounding_precision)) # p_atpos[atom_position][1] = float(y_dec.quantize(rounding_precision)) # p_atpos[atom_position][2] = float(z_dec.quantize(rounding_precision)) pbc_atoms = self.add_pbc( p_atpos[atom_position][0], p_atpos[atom_position][1], p_atpos[atom_position][2], box[0], p_rad3[atom_position], p_chrgv4[atom_position], atinf[atom_position].value, ) # pbc_atoms = [] new_atoms += pbc_atoms natoms = delphimol.changeStructureSize( p_atpos, p_rad3, p_chrgv4, atinf, p_iatmed, extra_atoms=new_atoms, natoms=delphimol.natoms, ) acent = self.getSiteAcent() pdb_text = "" for i in range(natoms): aID = i + 1 aname, resname, chain, resnumb = self.read_atom_details( delphimol.atinf, i) x, y, z = self.read_atom_positions(delphimol.p_atpos, i) if "-" in aname[0]: aname = aname[1:] resname = "PBC" resnumb = -666 pdb_text += new_pdb_line(aID, aname, resname, resnumb, x, y, z, chain=chain) box = Config.pypka_params.box if Config.debug: filename = "P_{1}-{0}.pdb".format(self.name, self.site.res_number) with open(filename, "w") as f_new: x, y, z = acent pdb_text += new_pdb_line(-1, "P", "CNT", -1, x, y, z) pdb_text += new_pdb_line(-2, "P", "PDB", -2, 0, 0, z) pdb_text += new_pdb_line(-2, "P", "PDB", -2, box[0], 0, z) pdb_text += new_pdb_line(-2, "P", "PDB", -2, 0, box[1], z) pdb_text += new_pdb_line(-2, "P", "PDB", -2, box[0], box[1], z) cutoff = box[0] * Config.pypka_params["slice"] pdb_text += new_pdb_line(-3, "P", "PDB", -3, cutoff, cutoff, z) pdb_text += new_pdb_line(-3, "P", "PDB", -3, box[0] - cutoff, cutoff, z) pdb_text += new_pdb_line(-3, "P", "PDB", -3, cutoff, box[1] - cutoff, z) pdb_text += new_pdb_line(-3, "P", "PDB", -3, box[0] - cutoff, box[1] - cutoff, z) pdb_text += new_pdb_line(-4, "P", "PDB", -4, -cutoff, -cutoff, z) pdb_text += new_pdb_line(-4, "P", "PDB", -4, box[0] + cutoff, -cutoff, z) pdb_text += new_pdb_line(-4, "P", "PDB", -4, -cutoff, box[1] + cutoff, z) pdb_text += new_pdb_line(-4, "P", "PDB", -4, box[0] + cutoff, box[1] + cutoff, z) f_new.write(pdb_text) with open("P_{1}-{0}.crg".format(self.name, self.site.res_number), "w") as f_new: f_new.write(crg) with open("P_{1}-{0}.siz".format(self.name, self.site.res_number), "w") as f_new: f_new.write(siz) return delphimol, acent
def write_output_structure(sites, molecules, delphi_input_content): def getProtomerResname(pdb_content, site, pH, ff_protomers): resnumb = site.getResNumber() resname = site.getName() new_state, (state_prob, taut_prob) = site.getMostProbTaut(pH) new_state_i = new_state - 1 for ff_resname, protomers in ff_protomers[resname].items(): if new_state_i in protomers.keys(): new_resname = ff_resname remove_hs = protomers[new_state_i] average_prot = site.getTitrationCurve()[pH] if state_prob < 0.75: warn = ("{0}{1} " "protonation state probability: {2}, " "tautomer probability: {3}".format( resname, resnumb, state_prob, taut_prob)) logger.warning(warn) rounded_sprob = round(state_prob, 2) rounded_tprob = round(taut_prob, 2) rounded_avgprot = round(average_prot, 2) remark_line = ("{0: <5}{1: <6} {2: >1.2f} " "{3: >1.2f} {4: >1.2f}".format( resname, resnumb, rounded_avgprot, rounded_sprob, rounded_tprob, )) pdb_content += "REMARK {text}\n".format(text=remark_line) # print(resnumb, new_state, new_resname, remove_hs, state_prob, taut_prob) return pdb_content, new_state_i, new_resname, remove_hs outputname = Config.pypka_params["f_structure_out"] pH = float(Config.pypka_params["f_structure_out_pH"]) ff_out = Config.pypka_params["ff_structure_out"] ff_protomer = { "amber": AMBER_protomers, "gromos_cph": GROMOS_protomers }[ff_out] pdb_content = ( f"REMARK PypKa assigned protonation states @ pH {pH}\n" "REMARK Residue Avg Prot State Prob Taut Prob\n") new_states = {} for site in sites: resname = site.getName() resnumb = site.res_number molecule = site.molecule chain = molecule.chain (pdb_content, new_state, new_resname, remove_hs) = getProtomerResname(pdb_content, site, pH, ff_protomer) if resname in ("NTR", "CTR"): new_resname = site.termini_resname if chain not in new_states: new_states[chain] = {} new_states[chain][resnumb] = (resname, new_state, new_resname, remove_hs) new_pdb = pdb_content counter = 0 tit_atoms = {} other_atoms = {} for molecule in molecules.values(): for atom_numb in molecule.atoms_tit_res: if molecule.atoms_tit_res[atom_numb]: tit_atoms[atom_numb] = molecule else: other_atoms[atom_numb] = molecule in_delphi_pdb = {} for line in delphi_input_content: if line.startswith("ATOM "): (aname, anumb, resname, chain, resnumb, x, y, z) = read_pdb_line(line) if chain not in in_delphi_pdb: in_delphi_pdb[chain] = {} if resnumb not in in_delphi_pdb[chain]: in_delphi_pdb[chain][resnumb] = [] in_delphi_pdb[chain][resnumb].append(aname) for line in delphi_input_content: if line.startswith("ATOM "): (aname, anumb, resname, chain, resnumb, x, y, z) = read_pdb_line(line) if anumb in tit_atoms.keys(): molecule = tit_atoms[anumb] (oldresname, new_state, resname, removeHs) = new_states[chain][resnumb] if aname in removeHs: continue if (ff_out == "amber" and oldresname in gromos2amber and new_state in gromos2amber[oldresname] and aname in gromos2amber[oldresname][new_state]): aname = gromos2amber[oldresname][new_state][aname] elif anumb in other_atoms: molecule = other_atoms[anumb] else: continue if resnumb > TERMINAL_OFFSET: termini_site = molecule.sites[resnumb] resnumb -= TERMINAL_OFFSET if resnumb in molecule.sites.keys(): _, ter_new_state, resname, ter_removeHs = new_states[ chain][resnumb] else: resname = termini_site.termini_resname # print(new_pdb_line(anumb, aname, resname, resnumb, x, y, z).strip()) if resnumb in molecule.getCYS_bridges(): resname = "CYX" counter += 1 new_pdb += new_pdb_line(counter, aname, resname, resnumb, x, y, z, chain=chain) if chain in mainchain_Hs and resnumb in mainchain_Hs[chain]: while len(mainchain_Hs[chain][resnumb]) > 0: counter += 1 (aname, anumb, oldresname, chain, x, y, z) = mainchain_Hs[chain][resnumb].pop() if (resnumb not in in_delphi_pdb[chain] or aname not in in_delphi_pdb[chain][resnumb]): new_pdb += new_pdb_line(counter, aname, resname, resnumb, x, y, z, chain=chain) del mainchain_Hs[chain][resnumb] elif not line.startswith("ENDMDL"): new_pdb += line outputpqr = "leftovers.pqr" logfile = "LOG_pdb2pqr_nontitrating" if ff_out == "gromos_cph": ff_out = "GROMOS" mend_pdb( Config.pypka_params["pdb2pqr_inputfile"], outputpqr, ff_out, ff_out, logfile=logfile, ) os.system("rm -f input_clean_fixed.pdb") with open(outputpqr) as f: for line in f: if line.startswith("ATOM "): ( aname, anumb, resname, chain, resnumb, x, y, z, charge, radius, ) = read_pqr_line(line) if chain not in mainchain_Hs: counter += 1 new_pdb += new_pdb_line(counter, aname, resname, resnumb, x, y, z, chain=chain) to_remove = (logfile, outputpqr, Config.pypka_params["pdb2pqr_inputfile"]) for f in to_remove: os.remove(f) with open(outputname, "w") as f_new: f_new.write(new_pdb)
def add_non_protein(pdbfile_origin, add_to_pdb, keep_membrane=False, keep_ions=False): new_file_body = "" with open(add_to_pdb) as f: for line in f: if line.startswith("ATOM "): (aname, anumb, resname, chain, resnumb, x, y, z) = read_pdb_line(line) last_anumb = anumb last_resnumb = resnumb # Read the original pdb with the membrane with open(pdbfile_origin) as f: for line in f: if "ATOM " == line[0:5]: (aname, anumb, resname, chain, resnumb, x, y, z) = read_pdb_line(line) if keep_membrane: if resname in LIPID_RESIDUES: last_anumb += 1 new_file_body += new_pdb_line(last_anumb, aname, resname, resnumb, x, y, z, chain=" ") if resname in list(Config.pypka_params.LIPIDS.values()): aname, resname, to_include = convert_FF_atomnames( aname, resname) if to_include: last_anumb += 1 resnumb += last_resnumb new_file_body += new_pdb_line( last_anumb, aname, resname, resnumb, x, y, z, chain=" ", ) if keep_ions and aname in IONS and resname == aname: last_anumb += 1 resnumb += last_resnumb new_file_body += new_pdb_line(last_anumb, aname, resname, resnumb, x, y, z, chain=chain) with open(add_to_pdb, "a") as f_new: f_new.write(new_file_body)