def assignWaterResidue(bgf_file, out_file, silent=True): mybgf = bgf.BgfFile(bgf_file) for atom in mybgf.a: for i in bgftools.is_water(mybgf, atom.aNo): mybgf.getAtom(i).rName = "WAT" mybgf.saveBGF(out_file)
def removebadcontacts(bgf_file, out_file, thresh, silent=True): if isinstance(bgf_file, bgf.BgfFile): myBGF = bgf_file else: if not silent: print(sys.argv[0] + ": Removing bad contacts from " + bgf_file + " with distance threshold " + str(thresh) + " A and saving to " + out_file + ".") myBGF = bgf.BgfFile(bgf_file) delete_list = [] if not silent: print("removeBadContacts will remove water molecules within " + str(thresh) + " Angstrom from the solute.") for solute_aNo in bgftools.listSoluteAtoms(myBGF): solute = myBGF.getAtom(solute_aNo) for oxygen_aNo in bgftools.listOxygenAtoms(myBGF): water = bgftools.is_water(myBGF, oxygen_aNo) if water != [] or type(water) != NoneType: if len(water) == 3: # if water is a water molecule, # calculate the distance between solute atoms and the molecule O = myBGF.getAtom(water[0]) H1 = myBGF.getAtom(water[1]) H2 = myBGF.getAtom(water[2]) dist_O_sol = bgf.distance(solute, O) dist_H1_sol = bgf.distance(solute, H1) dist_H2_sol = bgf.distance(solute, H2) if dist_O_sol < thresh or dist_H1_sol < thresh or dist_H2_sol < thresh: if oxygen_aNo not in delete_list: delete_list.append(oxygen_aNo) delete_list.sort() ##if water not in delete_list: ##delete_list.append(water) if delete_list != []: delete_list.reverse() # reverse sort for delAtoms for oxygen_index in delete_list: bgftools.deleteWaterAtoms(myBGF, oxygen_index) myBGF.renumber() if not silent: print("removeBadContacts: " + str(len(delete_list)) + " water molecules are removed.") else: if not silent: print( "There are no water molecules that corresponds to the criteria." ) if isinstance(out_file, bgf.BgfFile): return myBGF else: myBGF.saveBGF(out_file) return 1
def addsolvent(bgf_file, solvent_bgf, size, margin, out_file, ff_file, silent=True): ### initialize water = False ### load the solute bgf file if not silent: print("Initializing..") myBGF = bgf.BgfFile(bgf_file) # str #solventBGF = bgf.BgfFile("/home/noische/scripts/dat/WAT/f3c_box.bgf") # F3C waterbox if not silent: print("Loading the solvent file " + solvent_bgf + " ..") solventBGF = bgf.BgfFile(solvent_bgf) ### Generate error when the solvent box is not periodic: if not solventBGF.PERIOD: nu.die( "addSolvent: The solvent file is not periodic. Use a box full of solvent." ) ### Check the type of solvent if not silent: print("(the solvent box seems to be full of " + os.path.basename(solvent_file)[:-4] + " )") if "f3c" in solvent_bgf: water = True # this flag is used to remove the bad contacts with the molecule. if "spc" in solvent_bgf: water = True # this flag is used to remove the bad contacts with the molecule. if "tip" in solvent_bgf: water = True # this flag is used to remove the bad contacts with the molecule. ### calculate the box size if not silent: print("Analyzing box information..") if len(myBGF.CRYSTX) > 2: strsize = [myBGF.CRYSTX[0], myBGF.CRYSTX[1], myBGF.CRYSTX[2]] else: box = bgf.getBGFSize(myBGF, 0) # [xlo, xhi, ylo, yhi, zlo, zhi] strsize = [box[1] - box[0], box[3] - box[2], box[5] - box[4]] ### if size == "" and margin != "": strsize = [ strsize[0] + 2 * margin[0], strsize[1] + 2 * margin[1], strsize[2] + 2 * margin[2] ] # add margin on str size elif size != "" and margin == "": strsize = size waterboxsize = solventBGF.CRYSTX[:3] # REMARK: This is a kind of constant. copyNumber = [0, 0, 0] for index, i in enumerate(copyNumber): copyNumber[index] = math.ceil( strsize[index] / waterboxsize[index]) # how many times to replicate the water box if not silent: print("Creating box information: " + str(strsize)) ### replicate the solvent box bigboxBGF = bgftools.replicateCell(solventBGF, copyNumber, True) bigboxBGF.saveBGF("_replicate.bgf") if not silent: print("- Number of atoms in the created box: " + str(len(bigboxBGF.a))) ### trim the water box if water: if not silent: print("Generating water box.. Calculating water molecules") delatom = [] delwater = [] delwaterindex = [] for atom in bigboxBGF.a: if atom.x > strsize[0] or atom.y > strsize[1] or atom.z > strsize[ 2]: delatom.append(atom.aNo) for aNo in delatom: water_molecule = bgftools.is_water(bigboxBGF, aNo) if not water_molecule in delwater: delwater.append(water_molecule) delwater = nu.flatten(delwater) delwater = nu.removeRepeat(delwater) delwater.sort() delwater.reverse() for aNo in delwater: delwaterindex.append(bigboxBGF.getAtomIndex(aNo)) del (delwater) if not silent: print("Generating water box.. Trimming") bigboxBGF.delAtoms(delwaterindex, False) bigboxBGF.renumber() elif not water: if not silent: print("Generating solvent box.. Extracting solvent molecules") delatom = [] delsolvent = [] delsolventindex = [] for atom in bigboxBGF.a: if atom.x > strsize[0] or atom.y > strsize[1] or atom.z > strsize[ 2]: delatom.append(atom.aNo) for aNo in delatom: molecule_list = [] molecule = bgftools.getmolecule(bigboxBGF, bigboxBGF.getAtom(aNo), molecule_list) for number in molecule_list: if not number in delsolvent: delsolvent.append(number) delsolvent = nu.flatten(delsolvent) delsolvent = nu.removeRepeat(delsolvent) delsolvent.sort() delsolvent.reverse() for aNo in delsolvent: delsolventindex.append(bigboxBGF.getAtomIndex(aNo)) if not silent: print("Generating solvent box.. Trimming") bigboxBGF.delAtoms(delsolventindex, False) bigboxBGF.renumber() ### merge two structure # REMARK: it is natural to have the periodic information of water box for the output BGF file. # REMARK: HETATOM should be located on the first of the BGF file. So use dummy for merging. if not silent: print("\nAdding trimmed solvent box to the structure..") bigboxcenter = [strsize[0] / 2, strsize[1] / 2, strsize[2] / 2] a, b, c = bgftools.getCom(myBGF, ff_file) bgf.moveBGF(myBGF, bigboxcenter[0] - a, bigboxcenter[1] - b, bigboxcenter[2] - c) ## remove bad contacts between solutes and solvents if not silent: print("Atom distance calculation for contacts..") delatom = [] delsolvent = [] delsolventindex = [] for atom1 in myBGF.a: for atom2 in bigboxBGF.a: # if the distance between atom1 and atom2 is less than 2.8, add to a delete list dist_sq = (atom1.x - atom2.x)**2 + (atom1.y - atom2.y)**2 + ( atom1.z - atom2.z)**2 if dist_sq < 7.84: delatom.append(atom2.aNo) # delete bad atoms! if not silent: print("Removing bad contacts..") for aNo in delatom: molecule_list = [] molecule = bgftools.getmolecule(bigboxBGF, bigboxBGF.getAtom(aNo), molecule_list) for number in molecule_list: if not number in delsolvent: delsolvent.append(number) delsolvent = nu.flatten(delsolvent) delsolvent = nu.removeRepeat(delsolvent) delsolvent.sort() delsolvent.reverse() for aNo in delsolvent: delsolventindex.append(bigboxBGF.getAtomIndex(aNo)) bigboxBGF.delAtoms(delsolventindex, False) bigboxBGF.renumber() ## compute stats for adding solvents if not silent: print("\nComputing stats..") mol_list = bgftools.getMoleculeList(bigboxBGF) n_mol = len(mol_list) n_atom = len(nu.flatten(mol_list)) if not silent: print( str(n_mol) + " molecules (" + str(n_atom) + " atoms) will be added.") ## merge bigboxBGF = myBGF.merge(bigboxBGF, True) if not silent: print("Total atoms in the file: " + str(len(bigboxBGF.a))) ## some paperworking for periodic box bigboxBGF.OTHER = solventBGF.OTHER bigboxBGF.PERIOD = solventBGF.PERIOD bigboxBGF.AXES = solventBGF.AXES bigboxBGF.SGNAME = solventBGF.SGNAME bigboxBGF.CRYSTX = solventBGF.CRYSTX bigboxBGF.CELLS = solventBGF.CELLS ## adjust the size of the box bigboxBGF.CRYSTX = [ strsize[0], strsize[1], strsize[2], solventBGF.CRYSTX[3], solventBGF.CRYSTX[4], solventBGF.CRYSTX[5] ] """ ### remove bad contacts and save if water: if not silent: print("Removing bad contacts: distance criteria is 2.8 A") bigboxBGF = removebadcontacts(bigboxBGF, bigboxBGF, 2.8) ### renumber residue numbers # RULE: all rNos for water molecules will be renumbered from 2. (for createLammpsInput.pl) if not silent: print("Renumbering water molecules..") max_rNo_in_hetatm = 0; oxygen_list = bgftools.listOxygenAtoms(bigboxBGF) ### find the biggest rNo among HETATM for atom in bigboxBGF.a: if atom.aTag == 1: if max_rNo_in_hetatm < atom.rNo: max_rNo_in_hetatm = atom.rNo ### update rNo in water molecules rNo_for_water = max_rNo_in_hetatm + 500; for aNo in oxygen_list: water_aNo = bgftools.is_water(bigboxBGF, aNo) # get aNo in a water molecule by checking the oxygen atom if water_aNo != []: for atom_aNo in water_aNo: bigboxBGF.getAtom(atom_aNo).rNo = rNo_for_water rNo_for_water += 1 """ ### record BGF remarks bigboxBGF.REMARK.insert( 0, "Solvents added by " + os.path.basename(sys.argv[0]) + " by " + os.environ["USER"] + " on " + time.asctime(time.gmtime())) bigboxBGF.REMARK.insert(0, "Solvents: " + str(solvent_file)) ### save BGF if not silent: print("Saving the file.. see " + str(out_file)) bigboxBGF.saveBGF(out_file) return 1
def addsolvent(bgf_file, solvent_bgf, min, max, n_solvent, out_file, ff_file, margin, mark, silent=True): ### initialize water = False default_margin = 1.0 x_margin = 0.0 y_margin = 0.0 z_margin = 0.0 if "x" in margin.lower(): x_margin = default_margin if "y" in margin.lower(): y_margin = default_margin if "z" in margin.lower(): z_margin = default_margin ### load the solute bgf file if not silent: print("Initializing..") myBGF = bgf.BgfFile(bgf_file) # str myBGF.renumber() if not silent: print("Loading the solvent file " + solvent_bgf + " ..") solventBGF = bgf.BgfFile(solvent_bgf) ### Generate error when the solvent box is not periodic: if not solventBGF.PERIOD: nu.die( "addSolvent: The solvent file is not periodic. Use a box full of solvent." ) ### Check the type of solvent if not silent: print("(the solvent box seems to be full of " + os.path.basename(solvent_file)[:-4] + " )") if "f3c" in solvent_bgf: water = True # this flag is used to remove the bad contacts with the molecule. if "spc" in solvent_bgf: water = True # this flag is used to remove the bad contacts with the molecule. if "tip" in solvent_bgf: water = True # this flag is used to remove the bad contacts with the molecule. ### calculate the box size if not silent: print("Analyzing box information..") if not min: min = [0.0, 0.0, 0.0] if not max: max = myBGF.CRYSTX[:3] strsize = [ max[0] - min[0] - x_margin, max[1] - min[1] - y_margin, max[2] - min[2] - z_margin ] waterboxsize = solventBGF.CRYSTX[:3] # REMARK: This is a kind of constant. copyNumber = [0, 0, 0] for index, i in enumerate(copyNumber): copyNumber[index] = math.ceil( strsize[index] / waterboxsize[index]) # how many times to replicate the water box if not silent: print("Creating box information: " + str(strsize)) ### replicate the solvent box if not silent: print("Creating box.. this may take some time.") bigboxBGF = bgftools.replicateCell(solventBGF, copyNumber, True) bigboxBGF.saveBGF("_replicate.bgf") if not silent: print("- Number of atoms in the created box: " + str(len(bigboxBGF.a))) delatom = [] delsolvent = [] delsolventindex = [] delwater = [] delwaterindex = [] bigboxBGF = bgf.BgfFile("_replicate.bgf") bigboxBGF.renumber() ### trim the water box if water: if not silent: print("Generating water box.. Calculating water molecules") for atom in bigboxBGF.a: if atom.x > strsize[0] or atom.y > strsize[1] or atom.z > strsize[ 2]: delatom.append(atom.aNo) for aNo in delatom: water_molecule = bgftools.is_water(bigboxBGF, aNo) if not water_molecule in delwater: delwater.append(water_molecule) delwater = nu.flatten(delwater) delwater = nu.removeRepeat(delwater) for aNo in delwater: delwaterindex.append(bigboxBGF.a2i[aNo]) if not silent: print("Generating water box.. Trimming") bigboxBGF.delAtoms(delwaterindex, False) bigboxBGF.renumber() elif not water: if not silent: print("Generating solvent box.. Extracting solvent molecules") for atom in tqdm.tqdm(bigboxBGF.a, desc='Iterating', ncols=120): if atom.x > strsize[0] or atom.y > strsize[1] or atom.z > strsize[ 2]: delatom.append(atom.aNo) molecule = bgftools.getMoleculeList(bigboxBGF) for aNo in tqdm.tqdm(delatom, desc='Appending atoms to remove', ncols=120): for i in molecule: if aNo in i: delsolvent += i break delsolvent = list(set(delsolvent)) for aNo in delsolvent: delsolventindex.append(bigboxBGF.a2i[aNo]) if not silent: print("Generating solvent box.. Trimming") delsolventindex.sort() #delsolventindex.reverse() bigboxBGF.delAtoms(delsolventindex, False) bigboxBGF.renumber() bigboxBGF.saveBGF("_temp.bgf") ## debug ### remain n molecules and delete residues bigboxBGF = bgftools.renumberMolecules(bigboxBGF, 0, False) # renumber rNo if n_solvent: residues = set() for atom in bigboxBGF.a: residues.add(atom.rNo) # scan molecule rNo residues = list(residues) if not silent: print("Found %d water molecules." % len(residues)) if len(residues) < n_solvent: nu.die("Too few solvent molecules to choose %d molecules." % n_solvent) rNos = random.sample(residues, n_solvent) # select n molecules if not silent: print("%d water molecules are chosen." % n_solvent) # delete molecules delist = [] for atom in bigboxBGF.a: if not atom.rNo in rNos: delist.append(bigboxBGF.a2i[atom.aNo]) # if not chosen, delete delist.sort() bigboxBGF.delAtoms(delist, False) bigboxBGF.renumber() bigboxBGF = bgftools.renumberMolecules(bigboxBGF, 0, False) ### move the water box to min position for atom in bigboxBGF.a: atom.x += min[0] + x_margin / 2 atom.y += min[1] + y_margin / 2 atom.z += min[2] + z_margin / 2 ### add mark to the solvents if mark: for atom in bigboxBGF.a: atom.chain = mark bigboxBGF.saveBGF('_temp.bgf') # REMARK: it is natural to have the periodic information of water box for the output BGF file. # REMARK: HETATOM should be located on the first of the BGF file. So use dummy for merging. ## compute stats for adding solvents if not silent: print("\nComputing stats..") mol_list = bgftools.getMoleculeList(bigboxBGF) n_mol = len(mol_list) n_atom = len(nu.flatten(mol_list)) if not silent: print( str(n_mol) + " molecules (" + str(n_atom) + " atoms) will be added.") ## merge #bigboxBGF = myBGF.merge(bigboxBGF, True) myBGF = bgf.BgfFile(bgf_file) bigboxBGF = bgf.BgfFile("_temp.bgf") bigboxBGF2 = myBGF.merge(bigboxBGF) if not silent: print("Total atoms in the file: " + str(len(bigboxBGF.a))) ## some paperworking for periodic box bigboxBGF2.OTHER = myBGF.OTHER bigboxBGF2.PERIOD = myBGF.PERIOD bigboxBGF2.AXES = myBGF.AXES bigboxBGF2.SGNAME = myBGF.SGNAME bigboxBGF2.CRYSTX = myBGF.CRYSTX bigboxBGF2.CELLS = myBGF.CELLS ### record BGF remarks bigboxBGF2.REMARK.insert( 0, "Solvents added by " + os.path.basename(sys.argv[0]) + " by " + os.environ["USER"] + " on " + time.asctime(time.gmtime())) bigboxBGF2.REMARK.insert(0, "Solvents: " + str(solvent_file)) ### save BGF if not silent: print("Saving the file.. see " + str(out_file)) bigboxBGF2.saveBGF(out_file) return 1