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 anneal(bgf_dir, ff_file, suffix, out_file): # *** variables *** # used for log file output output = "" # initialization #t1 = 0; t2 = 0; # clock for measuring time for a cycle curr_dir = os.path.abspath(bgf_dir) temp_dir = curr_dir + "/anneal/" # LAMMPS executive command: defined in ~/scripts/clusterSettings.py #lammps_parallel = mpi_command + " -np 8 " + lammps_command lammps_parallel = "/home/tpascal/codes/openmpi/1.4.3/bin/mpirun -np 8 " + lammps_command # Annealing procedure anneal_proc = "/home/noische/script/dat/in.lammps.anneal" # get BGF file list in the directory pei_files = glob.glob(bgf_dir + "/*.bgf") pei_files.sort() os.chdir(bgf_dir) #print("pei_files: ", pei_files) # for file in the directory for file in pei_files: ### working filename print("*** Working on %s" % file) filename = file.split(".bgf")[0] print("filename: " + filename) # centerBGF print("Centering %s" % file) cmd_centerbgf = "/home/tpascal/scripts/centerBGF.pl -b " + file + " -f " + ff_file + " -s " + filename + ".center.bgf" + " -c com_center" nu.shutup() os.system(cmd_centerbgf) nu.say() filename = filename.split("/")[-1] print("filename: " + filename) # createLammps: with finite options # Note that the script refers /home/noische/script/data/in.lammps.anneal for the annealing process cmd_createLammpsInput = "/home/tpascal/scripts/createLammpsInput.pl -b " + filename + ".center.bgf" + " -f " + ff_file + " -t /home/noische/script/data/in.lammps.anneal " + " -s " + filename + " -o finite " nu.shutup() os.system(cmd_createLammpsInput) nu.say() # patch in.lammps file print("Patching infile") cmd_sed = "sed -i 's/2 5.0 90/2 4.5 5.0 90/' in." + filename nu.shutup() os.system(cmd_sed) nu.say() # patch data.lammps file print("Patching datafile") cmd_mv = "mv data." + filename + " data." + filename + ".bak" os.system(cmd_mv) file1 = open("data." + filename, "w") file2 = open("data." + filename + ".bak") while 1: line = file2.readline() if not line: break if "xlo" in line: line = "-50.0 50.0 xlo xhi\n" file1.write(line) elif "ylo" in line: line = "-50.0 50.0 ylo yhi\n" file1.write(line) elif "zlo" in line: line = "-50.0 50.0 zlo zhi\n" file1.write(line) elif "# X N_3 C_3 X" in line: line = line.replace("# X N_3 C_3 X", "0 # X N_3 C_3 X") file1.write(line) elif "# X C_3 C_3 X" in line: line = line.replace("# X C_3 C_3 X", "0 # X C_3 C_3 X") file1.write(line) else: file1.write(line) # run print("Running simulation") lammps_thermo_log_file = filename + ".anneal.log" cmd_lammps = lammps_parallel + " -log " + lammps_thermo_log_file nu.shutup() os.system(cmd_lammps) nu.say() # read potential energy from file # in in.lammps.anneal: "poteng" is the averaged value of potential energy after cooldown print("Treating Potential Energy") poteng = [] poteng_files = glob.glob(filename + "*poteng") for poteng_file in poteng_files: f_poteng_file = open(poteng_file) while 1: line = f_poteng_file.readline() if not line: break if not line[0] == "#": parse = line.split() poteng.append([parse[0], float(parse[1])]) poteng = nu.removeRepeat(poteng) ### print potential energy for i in poteng: print(i) # when is the minimum energy during annealing? min_poteng = 0 min_poteng_step = 0 # usually poteng < 0 for i in poteng: if i[1] < min_poteng: min_poteng_step = i[0] min_poteng = i[1] # convert that timestep into BGF trj_file = filename + ".lammpstrj" anneal_output_bgf_file = filename + ".annealed.bgf" result = LAMMPS_trj2bgf.getLAMMPSTrajectory(pei_file, trj_file, anneal_output_bgf_file, min_poteng_step, False) print("The lowest potential energy structure found") # create LAMMPS input for annealed BGF file # run the NVT simulation at 300 K # average the potential energy # average Rg # write data: filename, the minimum structure, avr_poteng, avr_Rg """
def periodicMoleculeSort(bgf_file, boxinfo, fragments=[], selection='', out_file='', ff_file="", silent=False, recursion_limit=10000): """ def periodicMoleculeSort(bgf_file, out_file, boxinfo, silent=True, recursion_limit=10000): read a BGF format from bgf_file and write the periodic information to out_file fragments = [ [atom no. of molecule 1], [atom no. of molecule 2], ... ] """ # open bgf if isinstance(bgf_file, bgf.BgfFile): if not silent: print("bgftools.periodicMoleculeSort: Got a tossed BGF format ..") myBGF = bgf_file else: if not silent: print("bgftools.periodicMoleculeSort: Reading " + bgf_file + " ..") myBGF = bgf.BgfFile(bgf_file) # if there is a requesting box size, assign if boxinfo: myBGF.CRYSTX = boxinfo # assign requsted boxinfo to CRYSTX # get periodic information of bgf file l_myBGFbox = [] # box size if myBGF.CRYSTX == []: if not silent: nu.die( "bgftools.periodicMoleculeSort: ERROR: This BGF file is not periodic. Exiting." ) else: print( "bgftools.periodicMoleculeSort: ERROR: This BGF file is not periodic. Exiting." ) sys.exit(0) else: l_myBGFbox = copy.deepcopy(myBGF.CRYSTX) # get molecules information if fragments: l_all_molecules = fragments else: l_all_molecules = getMoleculeList(myBGF, recursion_limit) if selection: selected_atoms = [atom.aNo for atom in myBGF.a if eval(selection)] new_molecules_list = [ mol for mol in l_all_molecules for ano in selected_atoms if ano in mol ] new_molecules_list = nu.removeRepeat(new_molecules_list) else: new_molecules_list = l_all_molecules # for every molecules.. for molecule in new_molecules_list: # calculate COM cx, cy, cz = getCom(myBGF, ff_file=ff_file, aNo_list=molecule, silent=True) # if COM is out of the box then take the residue qx, _ = divmod(cx, l_myBGFbox[0]) qy, _ = divmod(cy, l_myBGFbox[1]) qz, _ = divmod(cz, l_myBGFbox[2]) for aNo in molecule: atom = myBGF.getAtom(aNo) atom.x = atom.x - l_myBGFbox[0] * qx atom.y = atom.y - l_myBGFbox[1] * qy atom.z = atom.z - l_myBGFbox[2] * qz # save if out_file: if not silent: print("saving information to " + out_file + " ..") myBGF.saveBGF(out_file) return myBGF
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