def countMoleculeNum(bgf_file, silent=True): n_water = 0 l_molecule = bgftools.getMoleculeList(bgf_file) natom = len(nu.flatten(l_molecule)) nmol = len(l_molecule) l_molecule_atoms = [] for cluster in l_molecule: l_molecule_atoms.append(len(cluster)) if len(cluster) == 3: n_water += 1 if not silent: print( str(nmol) + " Molecules (" + str(natom) + " atoms) exists in the BGF file.") if not silent: print("Number of water molecules (i.e. natoms = 3): " + str(n_water)) #if not silent: print("Size of molecules: " + str(l_molecule_atoms)) return nmol
print(usage) sys.exit(0) # variables result = [] # inner functions def get_line(file): with open(file, 'r') as f: for line in f: yield line # 1. Load BGF mybgf = bgf.BgfFile(bgf_file) N_BGF_ATOMS = len(mybgf.a) atom_frags = bt.getMoleculeList(mybgf) type = "gra" for atom in mybgf.a: if "Mo" in atom.ffType: type = "mos" # 2. Read LAMMPS Trajectory mytrj = lt.lammpstrj(trj_file) mytrj.load() timesteps = sorted(mytrj.timesteps) N_HEADER = mytrj.nheader N_ATOMS = mytrj.natoms[timesteps[0]] N_BUFFER = N_HEADER + N_ATOMS if N_BGF_ATOMS != N_ATOMS: nu.die( "Number of atoms in trajectory file does not match with BGF file.")
def getHbond(bgf_file, trj_file, ff_file='', selection='', out_file='', n=0): '''analyze something within a timestep in a series of lammps trajectory. ''' # variables result = dict() # inner functions def get_line(file): with open(file, 'r') as f: for line in f: yield line # 1. Load BGF mybgf = bgf.BgfFile(bgf_file) N_BGF_ATOMS = len(mybgf.a) atom_frags = bt.getMoleculeList(mybgf) # 2. Read LAMMPS Trajectory mytrj = lt.lammpstrj(trj_file) timesteps = mytrj.load() N_HEADER = mytrj.nheader N_ATOMS = mytrj.natoms[timesteps[0]] N_BUFFER = N_HEADER + N_ATOMS if N_BGF_ATOMS != N_ATOMS: nu.die( "Number of atoms in trajectory file does not match with BGF file.") # 3. Determine dump style dump_keywords = mytrj.dumpstyle yes_scale = False if 'xs' in dump_keywords: yes_scale = True # 4. Update coordinates from the snapshot dump = get_line(trj_file) requested_t = sorted(timesteps)[-n:] for t in tqdm.tqdm(timesteps, ncols=120, desc="Analyzing HBonds", miniters=1): chunk = [next(dump) for i in range(N_BUFFER)] if not t in requested_t: continue mybgf = update_coord(chunk, mybgf, mytrj.pbc[t], scaled=yes_scale) mybgf = bt.periodicMoleculeSort(mybgf, mybgf.CRYSTX, fragments=atom_frags, ff_file=ff_file, silent=True) ### collect data def calc_hbonds(): # variables A = [] D = [] hbond_angles = [] d_crit = 3.5 a_crit = 30.0 for atom in mybgf.a: if selection: if "O" in atom.ffType and eval(selection): A.append(atom) if "O" in atom.ffType and eval(selection): D.append(atom) else: if "O" in atom.ffType: A.append(atom) if "O" in atom.ffType: D.append(atom) if not len(A) or not len(D): nu.die( "There are no atoms which can make H_bond (O atoms so far)!" ) # calculate hbonds for d_atom in D: d = np.array([d_atom.x, d_atom.y, d_atom.z]) # donor coord neigh_anos = bt.get_neighbors_aNo(A, d, r=d_crit, k=6) neigh_hbonded_coord = [] for ano in neigh_anos: a_atom = mybgf.getAtom(ano) a = np.array([a_atom.x, a_atom.y, a_atom.z]) # acceptor coord if bt.is_hbonded(mybgf, d_atom, a_atom): neigh_hbonded_coord.append(a) for i, j in itertools.combinations(neigh_hbonded_coord, 2): angle = nu.angle(i, d, j, radians=False) hbond_angles.append(angle) return hbond_angles hbonds = calc_hbonds() result[t] = hbonds #break; # tester # 5. Analyze if not out_file: out_file = trj_file + ".hbonds.angles." pickle_file = out_file + ".pickle" with open(pickle_file, 'wb') as f: pickle.dump(result, f, protocol=pickle.HIGHEST_PROTOCOL) print("Success to save the result to a pickle file %s" % pickle_file)
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 getHbond(bgf_file, trj_file, ff_file='', selection='', out_file=''): '''analyze something within a timestep in a series of lammps trajectory. ''' # variables result = dict() # inner functions def get_line(file): with open(file, 'r') as f: for line in f: yield line # 1. Load BGF mybgf = bgf.BgfFile(bgf_file) N_BGF_ATOMS = len(mybgf.a) atom_frags = bt.getMoleculeList(mybgf) type = "gra" for atom in mybgf.a: if "Mo" in atom.ffType: type = "mos" # 2. Read LAMMPS Trajectory mytrj = lt.lammpstrj(trj_file) mytrj.load() timesteps = sorted(mytrj.timesteps) N_HEADER = mytrj.nheader N_ATOMS = mytrj.natoms[timesteps[0]] N_BUFFER = N_HEADER + N_ATOMS if N_BGF_ATOMS != N_ATOMS: nu.die( "Number of atoms in trajectory file does not match with BGF file.") # 3. Determine dump style dump_keywords = mytrj._dump_style yes_scale = False if 'xs' in dump_keywords: yes_scale = True # 4. Update coordinates from the snapshot dump = get_line(trj_file) #for t in tqdm.tqdm(timesteps, ncols=120, desc="Analyzing HBonds"): for t in timesteps: chunk = [next(dump) for i in range(N_BUFFER)] #-----------------# def hard_work(mybgf, chunk): mybgf = update_coord(chunk, mybgf, mytrj.pbc[t], scaled=yes_scale) mybgf = bt.periodicMoleculeSort(mybgf, mybgf.CRYSTX, fragments=atom_frags, ff_file=ff_file, silent=True) ''' # find inwater boundary swr = 3.270615945/2 gwr = 3.057430885/2 margin = 5.0 gwa_y = bt.atoms_average(mybgf, 'atom.y', selection="'GWA' in atom.rName") gwb_y = bt.atoms_average(mybgf, 'atom.y', selection="'GWB' in atom.rName") if type == "gra": avg_z1 = bt.atoms_average(mybgf, 'atom.z', selection="'C_R' in atom.ffType and 'GRA' in atom.rName") # gra bottom avg_z2 = bt.atoms_average(mybgf, 'atom.z', selection="'C_R' in atom.ffType and 'GRB' in atom.rName") # gra top actual_distance = avg_z2 - avg_z1 elif type == "mos": avg_s3a_z2 = bt.atoms_average(mybgf, 'atom.z', selection="'S_3a' in atom.ffType and atom.rNo == 2") # mos2 top avg_s3b_z1 = bt.atoms_average(mybgf, 'atom.z', selection="'S_3b' in atom.ffType and atom.rNo == 1") # mos2 bottom actual_distance = avg_s3a_z2 - avg_s3b_z1 inwater_x = pbc[0] inwater_y = gwb_y - gwa_y + 2 * gwr - 2 * margin inwater_z = actual_distance - 2 * swr selection = "atom.y > {gwa_y} + {margin} and atom.y < {gwb_y} - {margin}".format(**vars()) ''' ### collect data def calc_hbonds(): # variables A = [] D = [] hbonds = [] d_crit = 3.5 a_crit = 30.0 for atom in mybgf.a: if selection: if "O" in atom.ffType and eval(selection): A.append(atom) if "O" in atom.ffType and eval(selection): D.append(atom) else: if "O" in atom.ffType: A.append(atom) if "O" in atom.ffType: D.append(atom) if not len(A) or not len(D): nu.die( "There are no atoms which can make H_bond (O atoms so far)!" ) # calculate hbonds for d_atom in D: d = np.array([d_atom.x, d_atom.y, d_atom.z]) # donor coord neigh_anos = bt.get_neighbors_aNo(A, d, r=d_crit, pbc=mytrj.pbc[t], k=6) donors = [d_atom.aNo] + d_atom.CONECT for ano in neigh_anos: a_atom = mybgf.getAtom(ano) a = np.array([a_atom.x, a_atom.y, a_atom.z]) # acceptor coord acceptors = [a_atom.aNo] + a_atom.CONECT for ano in d_atom.CONECT: h_atom = mybgf.getAtom(ano) h = np.array([h_atom.x, h_atom.y, h_atom.z]) u = h - d v = a - d theta = np.dot(u, v) / norm(u) / norm(v) theta = np.degrees(arccos(theta)) if theta < a_crit: # HBond exists dist = nu.pbc_dist(a, d, mytrj.pbc[t]) dist_ah = nu.pbc_dist(d, h, mytrj.pbc[t]) # E_vdw sigma_r = O_sigma / dist sigma_r_6 = sigma_r**6 sigma_r_12 = sigma_r**12 E_vdw = 4.0 * O_epsilon * (sigma_r_12 - sigma_r_6) # E_vdw in kcal/mol # E_coul E_coul = 0.0 for i, j in itertools.product( donors, acceptors): atom1 = mybgf.getAtom(i) atom2 = mybgf.getAtom(j) a1 = [atom1.x, atom1.y, atom1.z] a2 = [atom2.x, atom2.y, atom2.z] dist_ij = nu.pbc_dist(a1, a2, mytrj.pbc[t]) E_coul += 332.06371 * atom1.charge * atom2.charge / dist_ij # E_coul in kcal/mol # E_hbond E_hbond = E_coul + E_vdw # E_hbond = E_vdw + E_coul # update for v4 # angle between H-O-H plane and O..O vector H1 = mybgf.getAtom(d_atom.CONECT[0]) h1 = [H1.x, H1.y, H1.z] # H1 H2 = mybgf.getAtom(d_atom.CONECT[1]) h2 = [H2.x, H2.y, H2.z] # H2 p = d - h1 q = d - h2 n = np.cross( p, q) # normal vector of the H1-O-H2 plane m = a - d # O..O vector alpha = np.dot(n, m) / norm(n) / norm(m) alpha = np.degrees( arcsin(alpha) ) # angle between H-O-H plane and O..O vector hbonds.append([ d_atom.aNo, a_atom.aNo, d, a, dist, theta, [E_coul, E_vdw, E_hbond], dist_ah, alpha ]) # v4 return hbonds hb = calc_hbonds() return hb #-----------------# with concurrent.futures.ProcessPoolExecutor( max_workers=workers) as exe: for i in exe.map(functools.partial(hard_work), (mybgf, chunk)): result[t] = i # 5. Analyze if not out_file: out_file = trj_file + ".kwac.hbonds." pickle_file = out_file + ".pickle" with open(pickle_file, 'wb') as f: pickle.dump(result, f, protocol=pickle.HIGHEST_PROTOCOL) print("Success to save the result to a pickle file %s" % pickle_file)
def main(bgf_filename, grps_filename, margin): # initialization grps_original_filename = grps_filename + ".original" warn = "" # keep original grps file at the first run if not os.path.exists(grps_original_filename): shutil.copy(grps_filename, grps_original_filename) # read atoms from bgf file mybgf = bgf.BgfFile(bgf_filename) pbc = mybgf.CRYSTX[:3] swr = 3.270615945 / 2 # (wwr + swr) / 2 (defined by eq. from Pradeep Kumar's 2005 PRL) gwr = 3.057430885 / 2 # (wwr + cwr) / 2 # wrap water molecules #mybgf = bt.periodicMoleculeSort(mybgf, pbc, selection="'WAT' in atom.rName", silent=False) #mybgf.saveBGF(bgf_filename + '.wrap') warn += "* Volume assignment from %s to %s" % (bgf_filename, grps_filename) ''' Overall structure of MoS2 ------------------------- -----------Gra S_3b ---- Mo :rNo 2 S_3a ---- < layer_distance > S_3b ---- Mo :rNo 1 S_3a ---- -----------Gra ''' # configure regions pbc_x = mybgf.CRYSTX[0] pbc_y = mybgf.CRYSTX[1] pbc_z = mybgf.CRYSTX[2] # group 1: MoS2 avg_s3a_z1 = bt.atoms_average( mybgf, 'atom.z', selection="'S_3a' in atom.ffType and atom.rNo == 1") # mos2 bottom avg_s3b_z1 = bt.atoms_average( mybgf, 'atom.z', selection="'S_3b' in atom.ffType and atom.rNo == 1") # mos2 bottom avg_s3a_z2 = bt.atoms_average( mybgf, 'atom.z', selection="'S_3a' in atom.ffType and atom.rNo == 2") # mos2 top avg_s3b_z2 = bt.atoms_average( mybgf, 'atom.z', selection="'S_3b' in atom.ffType and atom.rNo == 2") # mos2 top mos2_x = pbc_x mos2_y = pbc_y mos2_z = avg_s3b_z1 - avg_s3a_z1 + 2 * swr warn += "\t** MoS2 region **" warn += "\t\t- Effective MoS2 region dimensions: %8.3f %8.3f %8.3f" % ( mos2_x, mos2_y, mos2_z) # group 2: graphene walls gwa_y = bt.atoms_average(mybgf, 'atom.y', selection="'GWA' in atom.rName") gwb_y = bt.atoms_average(mybgf, 'atom.y', selection="'GWB' in atom.rName") graphene_x = pbc_x graphene_y = gwb_y - gwa_y + 2 * gwr # group 3: "real" inwater actual_distance = avg_s3a_z2 - avg_s3b_z1 inwater_x = pbc_x inwater_y = graphene_y - 2 * margin inwater_z = actual_distance - 2 * swr # effective interlayer distance graphene_z = pbc_z - mos2_z * 2 - inwater_z # graphene warn += "\t** In-water region **" warn += "\t\t- Actual interlayer distance: %8.3f" % actual_distance warn += "\t\t- Effective water region dimensions: %8.3f %8.3f %8.3f" % ( inwater_x, inwater_y, inwater_z) # group 4: marginal inwater marginal_inwater_x = inwater_x marginal_inwater_y = 2 * margin marginal_inwater_z = inwater_z # group 5: marginal reservoir marginal_outwater_x = pbc_x marginal_outwater_y = 2 * margin marginal_outwater_z = pbc_z # group 6: "real" reservoir outwater_x = pbc_x outwater_y = pbc_y - graphene_y - 2 * margin outwater_z = pbc_z warn += "\t** Reservoir water region **" warn += "\t\t- dimensions: %8.3f %8.3f %8.3f" % (outwater_x, outwater_y, outwater_z) # find water locations all_molecules = bt.getMoleculeList(mybgf) all_ow = [ atom.aNo for atom in mybgf.a if 'OW' in atom.ffType or 'HW' in atom.ffType ] inwaters_ow = [ atom.aNo for atom in mybgf.a if (atom.y > gwa_y + margin and atom.y < gwb_y - margin and 'OW' in atom.ffType) ] marginal_inwaters_ow = [ atom.aNo for atom in mybgf.a if ((atom.y > gwa_y and atom.y < gwa_y + margin) or (atom.y > gwb_y - margin and atom.y < gwb_y)) and 'OW' in atom.ffType ] # marginal inwater inwaters_ow_nomargin = [ atom.aNo for atom in mybgf.a if (atom.y > gwa_y and atom.y < gwb_y and 'OW' in atom.ffType) ] marginal_outwaters_ow = [ atom.aNo for atom in mybgf.a if ((atom.y > gwa_y - margin and atom.y < gwa_y) or (atom.y > gwb_y and atom.y < gwb_y + margin)) and 'OW' in atom.ffType ] # marginal outwater outwaters_ow = [ atom.aNo for atom in mybgf.a if not atom.aNo in inwaters_ow and not atom.aNo in marginal_outwaters_ow and not atom.aNo in marginal_inwaters_ow and 'OW' in atom.ffType ] # real outwater print( "inwaters_vmd: same residue as (y > {gwa_y} + {margin} and y < {gwb_y} - {margin} and type OW)" .format(**vars())) print( "marginal_inwaters_vmd: same residue as (((y > {gwa_y} and y < {gwa_y} + {margin}) or (y > {gwb_y} - {margin} and y < {gwb_y})) and type OW)" .format(**vars())) print( "inwaters_vmd_nomargin: same residue as (y > {gwa_y} and y < {gwb_y} and type OW)" .format(**vars())) print( "marginal_outwaters_vmd: same residue as (((y > {gwa_y} - {margin} and y < {gwa_y}) or (y > {gwb_y} and y < {gwb_y} + {margin})) and type OW)" .format(**vars())) if len(inwaters_ow_nomargin ) != len(inwaters_ow) + len(marginal_inwaters_ow): nu.warn( "\t- About %s water molecules are discarded out of %s atoms located near the border." % (diff, len(inwaters_ow_nomargin))) warn += "\t- Margin specified: %8.3f\n" % margin # record aNo def get_atoms(lst): result = [] for ano in lst: atom = mybgf.getAtom(ano) result.append(atom.aNo) for i in atom.CONECT: result.append(i) return result inwaters = get_atoms(inwaters_ow) marginal_inwaters = get_atoms(marginal_inwaters_ow) marginal_outwaters = get_atoms(marginal_outwaters_ow) outwaters = get_atoms(outwaters_ow) if not (len(inwaters) % 3 == 0 and len(marginal_inwaters) % 3 == 0 and len(marginal_outwaters) % 3 == 0 and len(outwaters) % 3 == 0): warn += "----- Suspicious water molecules division found!!!! -----\n" # calculate volume vol_mos2 = mos2_x * mos2_y * mos2_z vol_graphene = graphene_x * graphene_y * graphene_z vol_inwater = inwater_x * inwater_y * inwater_z vol_marginal_inwater = marginal_inwater_x * marginal_inwater_y * marginal_inwater_z vol_outwater = outwater_x * outwater_y * outwater_z vol_marginal_outwater = marginal_outwater_x * marginal_outwater_y * marginal_outwater_z vol_total = pbc_x * pbc_y * pbc_z vol_sum = vol_mos2 + vol_graphene + vol_inwater + vol_marginal_inwater + vol_outwater + vol_marginal_outwater ''' # compute stats nu.warn("** Stats for confined water **") mass_inwater = 18.0154 * len(inwaters_ow) density_inwater = mass_inwater / vol_inwater / 6.022 * 10 nu.warn("\t- Number: %d" % len(inwaters_ow)) nu.warn("\t- Density: %8.5f" % density_inwater) ''' # compute stats warn += "\n\n\t**** Stats for confined water ****\n" warn += "\t- Number:\n" warn += "\t\t real inwater / marginal inwater / marginal outwater / real outwater: %d %d %d %d\n" % ( len(inwaters_ow), len(marginal_inwaters_ow), len(marginal_outwaters_ow), len(outwaters_ow)) warn += "\t\t (%5.1f %% %5.1f %% %5.1f %% %5.1f %%)\n" % ( float(len(inwaters_ow)) / len(all_ow) * 100, float(len(marginal_inwaters_ow)) / len(all_ow) * 100, float(len(marginal_outwaters_ow)) / len(all_ow) * 100, float(len(outwaters_ow)) / len(all_ow) * 100) warn += "\t- Volumes: \n" warn += "\t\tvol_mos2: %.3f = %.3f * %.3f * %.3f\n" % (vol_mos2, mos2_x, mos2_y, mos2_z) warn += "\t\tvol_graphene: %.3f = %.3f * %.3f * %.3f\n" % ( vol_graphene, graphene_x, graphene_y, graphene_z) warn += "\t\tvol_inwater: %.3f = %.3f * %.3f * %.3f\n" % ( vol_inwater, inwater_x, inwater_y, inwater_z) warn += "\t\tvol_marginal_inwater: %.3f = %.3f * %.3f * %.3f\n" % ( vol_marginal_inwater, marginal_inwater_x, marginal_inwater_y, marginal_inwater_z) warn += "\t\tvol_marginal_outwater: %.3f = %.3f * %.3f * %.3f\n" % ( vol_marginal_outwater, marginal_outwater_x, marginal_outwater_y, marginal_outwater_z) warn += "\t\tvol_outwater: %.3f = %.3f * %.3f * %.3f\n" % ( vol_outwater, outwater_x, outwater_y, outwater_z) if vol_sum != vol_total: warn += "\n\t\t----- Suspicious volume division found!!!! Density might be different -----\n" warn += "\t\tTotal volume: %8.3f, Sum of divisions: %8.3f\n" % ( vol_total, vol_sum) warn += "\t- Density:\n" density_inwater = 18.0154 * len(inwaters_ow) / vol_inwater / 6.022 * 10 density_marginal_inwater = 18.0154 * len( marginal_inwaters_ow) / vol_marginal_inwater / 6.022 * 10 density_marginal_outwater = 18.0154 * len( marginal_outwaters_ow) / vol_marginal_outwater / 6.022 * 10 density_outwater = 18.0154 * len(outwaters_ow) / vol_outwater / 6.022 * 10 warn += "\t\t real inwater / marginal inwater / marginal outwater / real outwater: %.3f %.3f %.3f %.3f\n" % ( density_inwater, density_marginal_inwater, density_marginal_outwater, density_outwater) # separate water group into inwater and outwater warn += "\tModifying grps file %s.." % sys.argv[0] g = grpfile(grps_original_filename) #new_group_no = g.split_group(2, outwaters) marginal_inwater_group_no = g.split_group(2, marginal_inwaters) marginal_outwater_group_no = g.split_group(2, marginal_outwaters) outwater_group_no = g.split_group(2, outwaters) g.grp[1]['volume'] = vol_mos2 + vol_graphene g.grp[2]['volume'] = vol_inwater g.grp[marginal_inwater_group_no]['volume'] = vol_marginal_inwater g.grp[marginal_outwater_group_no]['volume'] = vol_marginal_outwater g.grp[outwater_group_no]['volume'] = vol_outwater #g.write(grps_filename, zip=False) g.write(grps_filename, zip=True) warn += "%s: Done." % sys.argv[0] print( "Numbers: real inwater / marginal inwater / marginal outwater / real outwater: %d %d %d %d" % (len(inwaters_ow), len(marginal_inwaters_ow), len(marginal_outwaters_ow), len(outwaters_ow))) print( "Density: real inwater / marginal inwater / marginal outwater / real outwater: %.3f %.3f %.3f %.3f" % (density_inwater, density_marginal_inwater, density_marginal_outwater, density_outwater))
def main(bgf_filename, grps_filename, margin=0.0): # initialization grps_original_filename = grps_filename + ".original" # keep original grps file at the first run if not os.path.exists(grps_original_filename): shutil.copy(grps_filename, grps_original_filename) # read atoms from bgf file mybgf = bgf.BgfFile(bgf_filename) pbc = mybgf.CRYSTX[:3] swr = 3.270615945 / 2 # (wwr + swr) / 2 (defined by eq. from Pradeep Kumar's 2005 PRL) gwr = 3.057430885 / 2 # (wwr + cwr) / 2 # wrap water molecules #mybgf = bt.periodicMoleculeSort(mybgf, pbc, selection="'WAT' in atom.rName", silent=False) #mybgf.saveBGF(bgf_filename + '.wrap') nu.warn("* Volume assignment from %s to %s" % (bgf_filename, grps_filename)) ''' Overall structure of MoS2 ------------------------- -----------Gra S_3b ---- Mo :rNo 2 S_3a ---- < layer_distance > S_3b ---- Mo :rNo 1 S_3a ---- -----------Gra ''' # configure regions pbc_x = mybgf.CRYSTX[0] pbc_y = mybgf.CRYSTX[1] pbc_z = mybgf.CRYSTX[2] # group 1: MoS2 avg_s3a_z1 = bt.atoms_average( mybgf, 'atom.z', selection="'S_3a' in atom.ffType and atom.rNo == 1") # mos2 bottom avg_s3b_z1 = bt.atoms_average( mybgf, 'atom.z', selection="'S_3b' in atom.ffType and atom.rNo == 1") # mos2 bottom avg_s3a_z2 = bt.atoms_average( mybgf, 'atom.z', selection="'S_3a' in atom.ffType and atom.rNo == 2") # mos2 top avg_s3b_z2 = bt.atoms_average( mybgf, 'atom.z', selection="'S_3b' in atom.ffType and atom.rNo == 2") # mos2 top mos2_x = pbc_x mos2_y = pbc_y mos2_z = avg_s3b_z1 - avg_s3a_z1 + 2 * swr nu.warn("\t** MoS2 region **") nu.warn("\t\t- Effective MoS2 region dimensions: %8.3f %8.3f %8.3f" % (mos2_x, mos2_y, mos2_z)) # group 2: graphene walls gwa_y = bt.atoms_average(mybgf, 'atom.y', selection="'GWA' in atom.rName") gwb_y = bt.atoms_average(mybgf, 'atom.y', selection="'GWB' in atom.rName") graphene_x = pbc_x graphene_y = gwb_y - gwa_y + 2 * gwr # group 3: inwater actual_distance = avg_s3a_z2 - avg_s3b_z1 inwater_x = pbc_x inwater_y = graphene_y - 2 * margin inwater_z = actual_distance - 2 * swr # effective interlayer distance graphene_z = pbc_z - mos2_z * 2 - inwater_z # graphene nu.warn("\t** In-water region **") nu.warn("\t\t- Actual interlayer distance: %8.3f" % actual_distance) nu.warn("\t\t- Effective water region dimensions: %8.3f %8.3f %8.3f" % (inwater_x, inwater_y, inwater_z)) # group 4: reservoir outwater_x = pbc_x outwater_y = pbc_y - graphene_y outwater_z = pbc_z nu.warn("\t** Reservoir water region **") nu.warn("\t\t- dimensions: %8.3f %8.3f %8.3f" % (outwater_x, outwater_y, outwater_z)) # find water locations all_molecules = bt.getMoleculeList(mybgf) all_ow = [ atom.aNo for atom in mybgf.a if 'OW' in atom.ffType or 'HW' in atom.ffType ] inwaters_ow = [ atom.aNo for atom in mybgf.a if (atom.y > gwa_y + margin and atom.y < gwb_y - margin and 'OW' in atom.ffType) ] inwaters_ow_nomargin = [ atom.aNo for atom in mybgf.a if (atom.y > gwa_y and atom.y < gwb_y and 'OW' in atom.ffType) ] if margin: nu.warn("\t- Margin specified: %8.3f" % margin) diff = len(inwaters_ow_nomargin) - len(inwaters_ow) if diff: nu.warn( "\t- About %s water molecules are discarded out of %s atoms located near the border." % (diff, len(inwaters_ow_nomargin))) # record inwater aNo inwaters = [] for ano in inwaters_ow: atom = mybgf.getAtom(ano) inwaters.append(atom.aNo) for i in atom.CONECT: inwaters.append(i) outwaters = [i for i in all_ow if not i in inwaters] nu.warn("** Distinguishing water positions **") nu.warn("\t- Found %d atoms in in-water region (%8.3f molecules)" % (len(inwaters), (len(inwaters) / 3.0))) nu.warn("\t- Found %d atoms in reservoir region (%8.3f molecules)" % (len(outwaters), (len(outwaters) / 3.0))) debug_selection = "same residue as (y > %8.3f and y < %8.3f and type OW)" % ( gwa_y, gwb_y) nu.warn("VMD selection for inwaters: %s" % debug_selection) # calculate volume vol_mos2 = mos2_x * mos2_y * mos2_z vol_graphene = graphene_x * graphene_y * graphene_z vol_inwater = inwater_x * inwater_y * inwater_z vol_outwater = outwater_x * outwater_y * outwater_z # compute stats nu.warn("** Stats for confined water **") mass_inwater = 18.0154 * len(inwaters_ow) density_inwater = mass_inwater / vol_inwater / 6.022 * 10 nu.warn("\t- Number: %d" % len(inwaters_ow)) nu.warn("\t- Density: %8.5f" % density_inwater) # separate water group into inwater and outwater nu.warn("\tModifying grps file %s.." % sys.argv[0]) g = grpfile(grps_original_filename) if len(g.grp) == 3: new_group_no = g.split_group(3, outwaters) g.grp[1]['volume'] = vol_mos2 g.grp[2]['volume'] = vol_graphene g.grp[3]['volume'] = vol_inwater g.grp[4]['volume'] = vol_outwater elif len(g.grp) == 2: new_group_no = g.split_group(2, outwaters) g.grp[1]['volume'] = vol_mos2 + vol_graphene g.grp[2]['volume'] = vol_inwater g.grp[3]['volume'] = vol_outwater else: nu.die("Error on group numbers on %s" % grps_original_filename) #g.write(grps_filename, zip=False) g.write(grps_filename, zip=True) nu.warn("%s: Done." % sys.argv[0])
usage = """ avoid.py bgffile outfile fffile """ if len(sys.argv) < 2: print usage sys.exit(0) print(sys.argv) b = bgf.BgfFile(sys.argv[1]) if len(sys.argv) <= 3: ff = os.environ['FF_CNT'].replace("'", "") else: ff = sys.argv[3] mols = bgftools.getMoleculeList(b) # GRA 1 : bottom sheet # GRA 2 : top sheet top = 0.0 bottom = 0.0 for atom in b.a: if "GRA" in atom.rName: if atom.rNo == 1: bottom = atom.z elif atom.rNo == 2: top = atom.z if top and bottom: print("Found two graphene sheets.") else:
def dipole(bgf_file, trj_file, ff_file, out_file, avg_timestep, silent=False): ### init timestep = 0 l_timestep = [] line = [] n_header = 0 t1 = 0 t2 = 0 # clock vector = [0, 0, 1] # the axis of interest. in the acetone-water case, z direction. atominfo = dict() # atom data extracted from ff_file result = dict() axis = 2 # for orientational distribution of dipole moments. 1: x-axis, 2: y-axis, 3: z-axis ### unit conversion for debye elementary_q = 1.602176487e-19 # elementary charge in C debye_conv = 3.33564e-30 # 1 Debye in C*m k = elementary_q * 1e-10 / debye_conv ### open files myBGF = bgf.BgfFile(bgf_file) myTRJ = open(trj_file) myTRJ.seek(0) myOUT = open(out_file + ".dat", 'w') #myOUT2 = open(out_file + ".angle.dat", 'w') myRESULT = open(out_file + ".pickle", 'w') myRESULT2 = open(out_file + ".histo.pickle", 'w') ### read residues from bgf_file residueNames = set() # kind of residues in BGF file residueNumbers = set() dict_residue = dict() # stores residue numbers per each residue. RES1: [1, 2, ..], RES2: [6, 7, ..] for i in myBGF.a: rname = string.strip(i.rName) residueNames.add(rname) rno = i.rNo residueNumbers.add(rno) temp = "" for i in residueNames: temp += i + " " dict_residue[i] = [] if not silent: print("Found " + str(len(residueNames)) + " residues in BGF file: " + str(temp)) ### bookkeep residue numbers for each residue molecules = bgftools.getMoleculeList(myBGF) for molecule in molecules: # get an atom atom = myBGF.getAtom(molecule[0]) atomresname = string.strip(atom.rName) atomresno = atom.rNo # check if all molecule has same residue name and numbers for ano in molecule: atom2 = myBGF.getAtom(ano) temp_rno = atom2.rNo temp_rname = string.strip(atom2.rName) if temp_rno != atomresno or temp_rname != atomresname: nu.die( "Different residue name or residue number in a same molecule: " + str(atom2.aNo)) # record resid for resnames dict_residue[atomresname].append(atom.rNo) ### read mass from ff_file try: parse = ff_file.split(" ") except: nu.die( "Error occurred when reading the force field file.. Check your " + str(ff_file)) else: if not silent: print("Found " + str(len(parse)) + " Cerius2 Force Fields.") for i in parse: FF = dreiding.loadFF(i) temp_atominfo = dreiding.loadAtomTypes(FF) atominfo.update(temp_atominfo) ### read trajectory file # how many steps to go? wc_trj_file = popen("grep -A 1 TIMESTEP " + trj_file).read() wc_trj_file = wc_trj_file.split() l_timestep = [] for i in wc_trj_file: if "ITEM" in i or "TIME" in i or "--" in i: pass else: l_timestep.append(i) l_timestep = [int(i) for i in l_timestep] l_timestep.sort() n_timestep = len(l_timestep) if not silent: print("The trajectory contains " + str(n_timestep) + " timesteps.") l_requested_timesteps = l_timestep[-avg_timestep:] # requested timesteps if not silent: print("Only requested the last " + str(avg_timestep) + " timesteps. ") # Find header of the trajectory file while 1: templine = myTRJ.readline() line.append(templine.strip('\n').strip('ITEM: ')) n_header += 1 if "ITEM: ATOMS" in templine: break # INITIAL trajectory information timestep = int(line[1]) natoms = int(line[3]) boxsize = [ line[5].split(' ')[0], line[5].split(' ')[1], line[6].split(' ')[0], line[6].split(' ')[1], line[7].split(' ')[0], line[7].split(' ')[1] ] boxsize = [float(i) for i in boxsize] keywords = line[8].strip('ATOMS ') # for every shot in the trajectory file update BGF and manipulate dumpatom = get_line(trj_file) processed_step = 0 t1 = t2 = 0 elapsed_time = 0 while 1: try: chunk = [next(dumpatom) for i in range(natoms + n_header)] except StopIteration: break timestep = int(chunk[1]) if not timestep in l_requested_timesteps: continue #l_timestep.append(timestep) natoms = int(chunk[3]) boxsize = [ chunk[5].split(' ')[0], chunk[5].split(' ')[1], chunk[6].split(' ')[0], chunk[6].split(' ')[1], chunk[7].split(' ')[0], chunk[7].split(' ')[1] ] boxsize = [float(i) for i in boxsize] boxsize = [(boxsize[1] - boxsize[0]), (boxsize[3] - boxsize[2]), (boxsize[5] - boxsize[4])] keywords = chunk[8].split('ATOMS ')[1].strip('\n').split(' ') ### Show progress t1 = time.time() remaining_time = elapsed_time * (len(l_requested_timesteps) - processed_step) sys.stdout.write('\r' + "Reading timestep.. " + str(timestep) + " (Elapsed time for the previous step: " + "{0:4.1f}".format(elapsed_time) + " seconds, Remaining time: " + "{0:4.1f}".format(remaining_time) + " seconds = " + "{0:4.1f} minutes".format(remaining_time / 60) + ")") sys.stdout.flush() processed_step += 1 ### update myBGF with trajectory information ### natom_bgf = len(myBGF.a) # number of atoms in BGF file if not natom_bgf == natoms: nu.die( "Number of atoms in trajectory file does not match with BGF file." ) mode = "" if 'xs' in keywords or 'ys' in keywords or 'zs' in keywords: mode = 'scaled' elif 'x' in keywords or 'y' in keywords or 'z' in keywords: mode = 'normal' elif 'xu' in keywords or 'yu' in keywords or 'zu' in keywords: mode = 'unwrapped' # actual coordinate coordinfo = chunk[9:] # assume that coordinfo is similar to ['id', 'type', 'xs', 'ys', 'zs', 'ix', 'iy', 'iz'] for atomline in coordinfo: atomcoord = atomline.split(' ') atom = myBGF.getAtom(int(atomcoord[0])) if mode == 'scaled': atom.x = float(atomcoord[2]) * boxsize[0] atom.y = float(atomcoord[3]) * boxsize[1] atom.z = float(atomcoord[4]) * boxsize[2] elif mode == 'unwrapped': atom.x = float(atomcoord[2]) atom.y = float(atomcoord[3]) atom.z = float(atomcoord[4]) elif mode == 'normal': try: ix_index = keywords.index('ix') iy_index = keywords.index('iy') iz_index = keywords.index('iz') except ValueError: nu.warn( "No image information no the trajectory file. Will be treated as unwrapped." ) atom.x = float(atomcoord[2]) atom.y = float(atomcoord[3]) atom.z = float(atomcoord[4]) else: atom.x = (int(atomcoord[ix_index]) * boxsize[0]) + float( atomcoord[2]) atom.y = (int(atomcoord[iy_index]) * boxsize[1]) + float( atomcoord[3]) atom.z = (int(atomcoord[iz_index]) * boxsize[2]) + float( atomcoord[4]) try: for i in range(0, 3): myBGF.CRYSTX[i] = boxsize[i] except: pass #nu.warn("Crystal information error: is this file not periodic?") # apply periodic condition myBGF = bgftools.periodicMoleculeSort(myBGF, 0) ### DONE for updating trj on BGF file ### ### Now Dipole Moment Calculation # list of all molecules in BGF dipole_moments = dict() abs_dipole_moments = dict() angles = dict() temp_dict = dict() output_dipole = str(timestep) + "\t" output_abs_dipole = str(timestep) + "\t" output_angle = str(timestep) + "\t" ### find bin for orientational distribution of dipole moment min = 100000 max = -100000 for atom in myBGF.a: coord = [atom.x, atom.y, atom.z] if coord[axis] < min: min = coord[axis] if coord[axis] > max: max = coord[axis] if boxsize[axis] > max: max = boxsize[axis] if 0 < min: min = 0 bins = np.arange(math.floor(min), math.ceil(max), 1.0) binned_rNo = dict() for r in residueNames: binned_rNo[r] = [[] for b in bins] # space for binned residue numbers (= molecules) binned_mu = copy.deepcopy(binned_rNo) ### For every molecule for molecule in molecules: n_atom = len(molecule) # number of atoms in the molecule residue_no = myBGF.getAtom(molecule[0]).rNo # residue number of the molecule residue_name = myBGF.getAtom(molecule[0]).rName # residue name of the molecule m = bgftools.getMass(myBGF, molecule, ff_file) # molecule mass cm = [0, 0, 0] # center of mass mu = [0, 0, 0] # dipole moment coord = [0, 0, 0] # atom x, y, z for aNo in molecule: atom = myBGF.getAtom(aNo) coord = [atom.x, atom.y, atom.z] # error if residue numbers are different if atom.rNo != residue_no: nu.die( "Residue numbers in a same molecule are not consistent. Please check your BGF file." ) # error if mass is unreadable ffType = string.strip(atom.ffType) try: aMass = atominfo[ffType]['MASS'] except: nu.die("Cannot read the atom type " + str(atom.ffType) + " in the data file.") # calculate CM for index, i in enumerate(coord): cm[index] += i * aMass cm = [i / m for i in cm] # center of mass #print(str(residue_no) + '\t' + str(cm)) # REMARK: it seems to be okay without this process. """ # translate the molecule to CM for aNo in molecule: atom = myBGF.getAtom(aNo) atom.x -= cm[0] atom.y -= cm[1] atom.z -= cm[2] """ # calculate dipole moment sum(qi * di) mu_i = [] for aNo in molecule: atom = myBGF.getAtom(aNo) coord = [atom.x, atom.y, atom.z] mu_i.append([i * atom.charge * k for i in coord]) # sum up mu = [0, 0, 0] for i in mu_i: mu[0] += i[0] mu[1] += i[1] mu[2] += i[2] # for acetone case #len_mu = math.sqrt(dot(mu, mu)) #len_vector = math.sqrt(dot(vector, vector)) len_mu = math.sqrt(dot(mu, mu)) len_vector = 1.0 #angle = dot(mu, vector) / ( len_mu * len_vector ) angle = mu[2] / (len_mu * len_vector) # for ACETONE case # results dipole_moments[residue_no] = mu abs_dipole_moments[residue_no] = len_mu angles[residue_no] = angle ### Orientational distribution of dipole moments # binning according to molecule's CM and store to binned_rNo for index, bin in enumerate(bins): try: if bin < cm[axis] and bins[index + 1] > cm[axis]: binned_rNo[residue_name][index].append(residue_no) except: continue # binning is perfect so far! residueNumbers = list(residueNumbers) residueNames = list(residueNames) residueNumbers.sort() temp_dict = dict() temp_dict2 = dict() temp_dict2['MU'] = dipole_moments temp_dict2['ABSMU'] = abs_dipole_moments temp_dict2['ANGLES'] = angles temp_dict['TOTAL'] = temp_dict2 ### paperworks per residue for resname in residueNames: temp_dict2 = dict() res_dipole_moments = dict() res_abs_dipole_moments = dict() res_angles = dict() # load residue numbers per residue type resnumbers = dict_residue[resname] for rno in resnumbers: res_dipole_moments[rno] = dipole_moments[rno] res_abs_dipole_moments[rno] = abs_dipole_moments[rno] res_angles[rno] = angles[rno] temp_dict2['MU'] = res_dipole_moments temp_dict2['ABSMU'] = res_abs_dipole_moments temp_dict2['ANGLES'] = res_angles temp_dict2['BIN'] = bins # for analyze #temp_dict2['RNO_DISTR'] = binned_rNo[resname] temp_dict2['DISTR_ANGLES'] = binned_mu[resname] temp_dict2['DISTR_ABSMU'] = binned_mu[resname] # write dipole moments for index, item in enumerate(binned_rNo[resname]): if len(item) == 0: continue for i in item: temp_dict2['DISTR_ANGLES'][index].append( temp_dict2['ANGLES'][i]) #temp_dict2['DISTR_ABSMU'][index].append(temp_dict2['ABSMU'][i]) temp_dict[resname] = temp_dict2 # result: timestep - residue - MU, ANGLES, NATOMS result[timestep] = temp_dict t2 = time.time() # time mark elapsed_time = t2 - t1 ### Averaging orientational distribution of dipole moments over timesteps #del temp_dict1 del temp_dict2 temp_dict1 = dict() # angles with keys: bin temp_dict2 = dict() # |mu| with keys: bin # append for r in residueNames: temp_dict1[r] = dict() temp_dict2[r] = dict() for t in l_requested_timesteps: for index, b in enumerate(result[t][r]['BIN']): if not temp_dict1[r].has_key(b): temp_dict1[r][b] = [] if not temp_dict2[r].has_key(b): temp_dict2[r][b] = [] # append averaged values avg, std = meanstdv(result[t][r]['DISTR_ANGLES'][index]) temp_dict1[r][b].append(avg) for i in result[t][r]['DISTR_ANGLES'][index]: temp_dict2[r][b].append(i) #for i in result[t][r]['DISTR_ABSMU'][index]: # temp_dict2[b].append(i) # average avg_angles = dict() avg_absmu = dict() avg_angles_stdev = dict() avg_absmu_stdev = dict() for r in residueNames: avg_angles[r] = dict() avg_absmu[r] = dict() avg_angles_stdev[r] = dict() avg_absmu_stdev[r] = dict() temp = temp_dict1[r].keys() temp.sort() for i in temp: avg_angles[r][i], avg_angles_stdev[r][i] = meanstdv( temp_dict1[r][i]) avg_absmu[r][i], avg_absmu_stdev[r][i] = meanstdv(temp_dict2[r][i]) # print for average print("") print("Averaged " + str(avg_timestep) + " timesteps out of " + str(n_timestep)) for r in residueNames: print(r) for i in temp: #print(str(i) + '\t' + str(temp_dict1[i])) print( str(i) + '\t' + str(avg_angles[r][i]) + '\t' + str(avg_angles_stdev[r][i])) print("") # save for debug output = "" for r in residueNames: for i in temp: output += str(i) + '\t' + str(temp_dict1[r][i]) + '\n' myOUT.write(output) myOUT.close() # save the pickle object pkl.dump(result, myRESULT) myRESULT.close() pkl.dump(temp_dict2, myRESULT2) myRESULT2.close() print('') return 1
"_temp.bgf", ff_file, "_temp.bgf") nu.shutup() os.system(addsolvent_cmd) nu.say() # empty center water result = bgf.BgfFile('_temp.bgf') min_mo_x1, max_mo_x1 = bt.atoms_minmax( result, 'atom.x', selection="'Mo' in atom.ffType and atom.rNo == 1") min_mo_y1, max_mo_y1 = bt.atoms_minmax( result, 'atom.y', selection="'Mo' in atom.ffType and atom.rNo == 1") avg_s3a_z1 = bt.atoms_average( result, 'atom.z', selection="'S_3a' in atom.ffType and atom.rNo == 1") avg_s3b_z2 = bt.atoms_average( result, 'atom.z', selection="'S_3b' in atom.ffType and atom.rNo == 2") all_molecules = bt.getMoleculeList(result) del_list = [] mos2_coords = [] for atom in result.a: if "MOS" in atom.rName: mos2_coords.append([atom.x, atom.y, atom.z]) mos2_tree = scipy.spatial.KDTree(mos2_coords, leafsize=len(mos2_coords) + 1) for molecule in tqdm.tqdm(all_molecules, ncols=120, desc='Removing bad contacts'): if not len(molecule) == 3: continue # applies only to water cx, cy, cz = bt.getCom(result, ff_file=ff_file,
def getHbond(bgf_file, trj_file, ff_file='', selection='', out_file=''): '''analyze something within a timestep in a series of lammps trajectory. ''' # variables result = dict() # inner functions def get_line(file): with open(file, 'r') as f: for line in f: yield line # 1. Load BGF mybgf = bgf.BgfFile(bgf_file) N_BGF_ATOMS = len(mybgf.a) atom_frags = bt.getMoleculeList(mybgf) # 2. Read LAMMPS Trajectory mytrj = lt.lammpstrj(trj_file) mytrj.load() timesteps = sorted(mytrj.timesteps) N_HEADER = mytrj.nheader N_ATOMS = mytrj.natoms[timesteps[0]] N_BUFFER = N_HEADER + N_ATOMS if N_BGF_ATOMS != N_ATOMS: nu.die( "Number of atoms in trajectory file does not match with BGF file.") # 3. Determine dump style dump_keywords = mytrj._dump_style yes_scale = False if 'xs' in dump_keywords: yes_scale = True # 4. Update coordinates from the snapshot dump = get_line(trj_file) for t in tqdm.tqdm(timesteps, ncols=120, desc="Analyzing HBonds"): chunk = [next(dump) for i in range(N_BUFFER)] mybgf = update_coord(chunk, mybgf, mytrj.pbc[t], scaled=yes_scale) mybgf = bt.periodicMoleculeSort(mybgf, mybgf.CRYSTX, fragments=atom_frags, ff_file=ff_file, silent=True) ### collect data def calc_hbonds(): # variables A = [] D = [] hbonds = [] d_crit = 3.5 a_crit = 30.0 for atom in mybgf.a: if selection: if "O" in atom.ffType and eval(selection): A.append(atom) if "O" in atom.ffType and eval(selection): D.append(atom) else: if "O" in atom.ffType: A.append(atom) if "O" in atom.ffType: D.append(atom) if not len(A) or not len(D): nu.die( "There are no atoms which can make H_bond (O atoms so far)!" ) # calculate hbonds for d_atom in D: d = np.array([d_atom.x, d_atom.y, d_atom.z]) # donor coord neigh_anos = bt.get_neighbors_aNo(A, d, r=d_crit, pbc=mytrj.pbc[t], k=6) donors = [d_atom.aNo] + d_atom.CONECT for ano in neigh_anos: a_atom = mybgf.getAtom(ano) a = np.array([a_atom.x, a_atom.y, a_atom.z]) # acceptor coord acceptors = [a_atom.aNo] + a_atom.CONECT for ano in d_atom.CONECT: h_atom = mybgf.getAtom(ano) h = np.array([h_atom.x, h_atom.y, h_atom.z]) u = h - d v = a - d theta = np.dot(u, v) / norm(u) / norm(v) theta = np.degrees(arccos(theta)) if theta < a_crit: # HBond exists dist = nu.pbc_dist(a, d, mytrj.pbc[t]) dist_ah = nu.pbc_dist(d, h, mytrj.pbc[t]) # E_vdw sigma_r = O_sigma / dist sigma_r_6 = sigma_r**6 sigma_r_12 = sigma_r**12 E_vdw = 4.0 * O_epsilon * (sigma_r_12 - sigma_r_6) # E_vdw in kcal/mol # E_coul E_coul = 0.0 for i, j in itertools.product(donors, acceptors): atom1 = mybgf.getAtom(i) atom2 = mybgf.getAtom(j) a1 = [atom1.x, atom1.y, atom1.z] a2 = [atom2.x, atom2.y, atom2.z] dist_ij = nu.pbc_dist(a1, a2, mytrj.pbc[t]) E_coul += 332.06371 * atom1.charge * atom2.charge / dist_ij # E_coul in kcal/mol # E_hbond E_hbond = E_coul + E_vdw # E_hbond = E_vdw + E_coul # update for v4 # angle between H-O-H plane and O..O vector H1 = mybgf.getAtom(d_atom.CONECT[0]) h1 = [H1.x, H1.y, H1.z] # H1 H2 = mybgf.getAtom(d_atom.CONECT[1]) h2 = [H2.x, H2.y, H2.z] # H2 p = d - h1 q = d - h2 n = np.cross( p, q) # normal vector of the H1-O-H2 plane m = a - d # O..O vector alpha = np.dot(n, m) / norm(n) / norm(m) alpha = np.degrees( arcsin(alpha) ) # angle between H-O-H plane and O..O vector #hbonds.append([d_atom.aNo, a_atom.aNo, d, a, dist, theta, [E_coul, E_vdw, E_hbond]]) # v2 #hbonds.append([d_atom.aNo, a_atom.aNo, d, a, dist, theta, [E_coul, E_vdw, E_hbond], dist_ah]) # v3 hbonds.append([ d_atom.aNo, a_atom.aNo, d, a, dist, theta, [E_coul, E_vdw, E_hbond], dist_ah, alpha ]) # v4 return hbonds hbonds = calc_hbonds() result[t] = hbonds #break; # tester # 5. Analyze if not out_file: out_file = trj_file + ".hbonds.v4" pickle_file = out_file + ".pickle" with open(pickle_file, 'wb') as f: pickle.dump(result, f, protocol=pickle.HIGHEST_PROTOCOL) print("Success to save the result to a pickle file %s" % pickle_file)
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
def main(bgf_file, out_file, ff_file="", n=0, density=0.9, r=1.0): n_total_trial = 0 # if molecule numbers are not specified, create the box with the existing molecules in the BGF file. # if molecule numbers specified, copy the molecules in the box as many as the number specified. if n: import copy mybgf = bgf.BgfFile() id = 0 for i in tqdm.tqdm(range(int(n)), desc="Cloaning molecules", ncols=120): id += 1 mybgf2 = bgf.BgfFile(bgf_file) for i in mybgf2.a: i.rNo = id mybgf = mybgf.merge(mybgf2) else: mybgf = bgf.BgfFile(bgf_file) # calculate cubic size mass = bt.getMass(mybgf, ff_file=ff_file) target_density = density volume = mass / target_density / 6.022 * 10 cell_x = math.pow(volume, 1.0 / 3) print("The script will generate a cubic with dimensions %f^3" % cell_x) mybgf.CRYSTX = [cell_x, cell_x, cell_x, 90.0, 90.0, 90.0] # get com redefined_coords = [] molecules = bt.getMoleculeList(mybgf) for mol in tqdm.tqdm(molecules, ncols=120): #for index, mol in enumerate(molecules): n_trial = 0 while True: n_trial += 1 n_total_trial += 1 cx, cy, cz = bt.getCom(mybgf, ff_file=ff_file, aNo_list=mol) new_pos = [random.uniform(0, cell_x) for i in range(3)] new_rot = [random.uniform(0, 2 * math.pi) for i in range(3)] U = mathtools.rotate_matrix(new_rot[0], new_rot[1], new_rot[2]) # check the room before lying mol_coords = [] for ano in sorted(mol): atom = mybgf.getAtom(ano) x = atom.x y = atom.y z = atom.z x -= cx y -= cy z -= cz # rotate v = np.matrix([x, y, z]).T Uv = U * v x = float(Uv[0]) y = float(Uv[1]) z = float(Uv[2]) # move CM to new position x += new_pos[0] y += new_pos[1] z += new_pos[2] mol_coords.append([x, y, z]) # only successful trials can quit the while loop if query_safe_coords(redefined_coords, mol_coords, r=r): for index, ano in enumerate(sorted(mol)): atom = mybgf.getAtom(ano) atom.x = mol_coords[index][0] atom.y = mol_coords[index][1] atom.z = mol_coords[index][2] redefined_coords += mol_coords break else: # fail if too many trials performed if n_trial > 1000: print( "Failed to find a suitable coordinates to insert a molecule %s" % mol) sys.exit(0) # check print("Checking bad contacts..") t = scipy.spatial.KDTree(redefined_coords) d = t.query_pairs(r) if not d: print("There are no bad contacts with distance < %.2f" % r) else: print("Looks there're %d bad contacts" % len(d)) # save mybgf.saveBGF(out_file) print("File saved to %s" % out_file) print("\n** Stats **") print("Total generated coordinates: %d" % n_total_trial) print("Number of last trials: %d" % n_trial) print("Done.")
def densityProfile(bgf_file, trj_file, ff_file, pickle_file, out_file, avg_timestep, silent=False): nu.warn( "LAMMPS trajectory with NPT simulations will give you the wrong result." ) ### init timestep = 0 l_timestep = [] line = [] n_header = 0 t1 = 0 t2 = 0 # clock atominfo = dict() # atom data extracted from ff_file result = dict() axis = 2 # 1: x-axis, 2: y-axis, 3: z-axis ### open files myBGF = bgf.BgfFile(bgf_file) myTRJ = open(trj_file) myTRJ.seek(0) myPickle = open(pickle_file) f_debug = open("debug.dat", 'w') if not silent: print("Pickling..") Dipole = pickle.load(myPickle) # dipole data ### read residues from bgf_file residue = set() # kind of residues in BGF file dict_residue = dict() # stores residue numbers per each residue. RES1: [1, 2, ..], RES2: [6, 7, ..] for i in myBGF.a: rname = string.strip(i.rName) residue.add(rname) output = "" for i in residue: output += i + " " dict_residue[i] = [] if not silent: print("Found " + str(len(residue)) + " residues in BGF file: " + str(output)) residue = list(residue) #residue.append('TOTAL') n_residue = len(residue) # number of residues (including total) ### bookkeep residue numbers for each residue molecules = bgftools.getMoleculeList(myBGF) dict_rNo2rName = dict() for molecule in molecules: # get an atom atom = myBGF.getAtom(molecule[0]) atomresname = string.strip(atom.rName) atomresno = atom.rNo # check if all molecule has same residue name and numbers for ano in molecule: atom2 = myBGF.getAtom(ano) temp_rno = atom2.rNo temp_rname = string.strip(atom2.rName) if temp_rno != atomresno or temp_rname != atomresname: nu.die( "Different residue name or residue number in a same molecule: " + str(atom2.aNo)) # record resid for resnames dict_residue[atomresname].append(atom.rNo) dict_rNo2rName[atom.rNo] = atomresname #print(dict_residue) #print(dict_rNo2rName) ### read mass from ff_file try: parse = ff_file.split(" ") except: nu.die( "Error occurred when reading the force field file.. Check your " + str(ff_file)) else: if not silent: print("Found " + str(len(parse)) + " Cerius2 Force Fields.") for i in parse: FF = dreiding.loadFF(i) temp_atominfo = dreiding.loadAtomTypes(FF) atominfo.update(temp_atominfo) ### read trajectory file # how many steps to go? wc_trj_file = popen("grep TIMESTEP " + trj_file + " | wc -l ").read() n_timestep = int(wc_trj_file.split()[0]) print("The trajectory contains " + str(n_timestep) + " timesteps.") # Find header of the trajectory file while 1: templine = myTRJ.readline() line.append(templine.strip('\n').strip('ITEM: ')) n_header += 1 if "ITEM: ATOMS" in templine: break # INITIAL trajectory information timestep = int(line[1]) natoms = int(line[3]) boxsize = [ line[5].split(' ')[0], line[5].split(' ')[1], line[6].split(' ')[0], line[6].split(' ')[1], line[7].split(' ')[0], line[7].split(' ')[1] ] boxsize = [float(i) for i in boxsize] keywords = line[8].strip('ATOMS ') # for every shot in the trajectory file update BGF and manipulate dumpatom = get_line(trj_file) processed_step = 0 t1 = t2 = 0 elapsed_time = 0 while 1: try: chunk = [next(dumpatom) for i in range(natoms + n_header)] except StopIteration: break timestep = int(chunk[1]) l_timestep.append(timestep) natoms = int(chunk[3]) boxsize = [ chunk[5].split(' ')[0], chunk[5].split(' ')[1], chunk[6].split(' ')[0], chunk[6].split(' ')[1], chunk[7].split(' ')[0], chunk[7].split(' ')[1] ] boxsize = [float(i) for i in boxsize] boxsize = [(boxsize[1] - boxsize[0]), (boxsize[3] - boxsize[2]), (boxsize[5] - boxsize[4])] keywords = chunk[8].split('ATOMS ')[1].strip('\n').split(' ') ######## if timestep < avg_timestep: continue if timestep % 10000 != 0: continue ######## ### Show progress t1 = time.time() remaining_time = elapsed_time * (n_timestep - processed_step) sys.stdout.write('\r' + "Reading timestep.. " + str(timestep) + " (Elapsed time for the previous step: " + "{0:4.1f}".format(elapsed_time) + " seconds, Remaining time: " + "{0:4.1f}".format(remaining_time) + " seconds = " + "{0:4.1f} minutes".format(remaining_time / 60) + ")") sys.stdout.flush() processed_step += 1 ### update myBGF with trajectory information ### natom_bgf = len(myBGF.a) # number of atoms in BGF file if not natom_bgf == natoms: nu.die( "Number of atoms in trajectory file does not match with BGF file." ) mode = "" if 'xs' in keywords or 'ys' in keywords or 'zs' in keywords: mode = 'scaled' elif 'x' in keywords or 'y' in keywords or 'z' in keywords: mode = 'normal' elif 'xu' in keywords or 'yu' in keywords or 'zu' in keywords: mode = 'unwrapped' # actual coordinate coordinfo = chunk[9:] # assume that coordinfo is similar to ['id', 'type', 'xs', 'ys', 'zs', 'ix', 'iy', 'iz'] for atomline in coordinfo: atomcoord = atomline.split(' ') atom = myBGF.getAtom(int(atomcoord[0])) if mode == 'scaled': atom.x = float(atomcoord[2]) * boxsize[0] atom.y = float(atomcoord[3]) * boxsize[1] atom.z = float(atomcoord[4]) * boxsize[2] elif mode == 'unwrapped': atom.x = float(atomcoord[2]) atom.y = float(atomcoord[3]) atom.z = float(atomcoord[4]) elif mode == 'normal': try: ix_index = keywords.index('ix') iy_index = keywords.index('iy') iz_index = keywords.index('iz') except ValueError: nu.warn( "No image information no the trajectory file. Will be treated as unwrapped." ) atom.x = float(atomcoord[2]) atom.y = float(atomcoord[3]) atom.z = float(atomcoord[4]) else: atom.x = (int(atomcoord[ix_index]) * boxsize[0]) + float( atomcoord[2]) atom.y = (int(atomcoord[iy_index]) * boxsize[1]) + float( atomcoord[3]) atom.z = (int(atomcoord[iz_index]) * boxsize[2]) + float( atomcoord[4]) try: for i in range(0, 3): myBGF.CRYSTX[i] = boxsize[i] except: pass #nu.warn("Crystal information error: is this file not periodic?") # apply periodic condition myBGF = bgftools.periodicMoleculeSort(myBGF, 0) ### DONE for updating trj on BGF file ### ### find bin ## CAUTION: only for NVT min = 100000 max = -100000 for atom in myBGF.a: coord = [atom.x, atom.y, atom.z] if coord[axis] < min: min = coord[axis] if coord[axis] > max: max = coord[axis] if boxsize[axis] > max: max = boxsize[axis] if 0 < min: min = 0 bins = np.arange(math.floor(min), math.ceil(max), interval) #print("Bins....:") #print(bins) ### find CM of every molecule res_z = [] residues = [] for molecule in molecules: n_atom = len(molecule) # number of atoms in the molecule residue_no = myBGF.getAtom(molecule[0]).rNo # residue number of the molecule m = bgftools.getMass(myBGF, molecule, ff_file) # molecule mass cm = [0, 0, 0] # center of mass coord = [0, 0, 0] # atom x, y, z residues.append(residue_no) # store residue numbers of molecules for aNo in molecule: atom = myBGF.getAtom(aNo) coord = [atom.x, atom.y, atom.z] # error if residue numbers are different if atom.rNo != residue_no: nu.die( "Residue numbers in a same molecule are not consistent. Please check your BGF file." ) # error if mass is unreadable ffType = string.strip(atom.ffType) try: aMass = atominfo[ffType]['MASS'] except: nu.die("Cannot read the atom type " + str(atom.ffType) + " in the data file.") # calculate CM for index, i in enumerate(coord): cm[index] += i * aMass cm = [i / m for i in cm] # center of mass res_z.append([residue_no, cm[2]]) ### binning according to z-axis bin_resno = [] for index, bin in enumerate(bins): temp_resno = [] for i in res_z: try: if bin < i[1] and bins[index + 1] > i[1]: temp_resno.append(i[0]) except: continue bin_resno.append([bin, temp_resno]) ### refinement for residues bin_avg = [] for r in residue: temp_per_r = [] for b in bin_resno: temp_bin_res = [] for i in b[1]: if dict_rNo2rName[i] == r: temp_bin_res.append(i) temp_per_r.append([b[0], temp_bin_res]) bin_avg.append([r, temp_per_r]) ### average #result = []; result_t = dict() for rdata in bin_avg: temp_per_r = [] for b in rdata[1]: temp_bin_res = [] avg_mag = 0 avg_angle_cos = 0 for i in b[1]: avg_mag += Dipole[timestep][rdata[0]]['ABSMU'][i] mu = Dipole[timestep][rdata[0]]['MU'][i] # angle btwn z-axis and mu angle_cos = mu[2] / math.sqrt(mu[0]**2 + mu[1]**2 + mu[2]**2) f_debug.write( str(timestep) + '\t' + str(mu) + '\t' + str(Dipole[timestep][rdata[0]]['ABSMU'][i]) + '\t' + str(angle_cos) + '\n') avg_angle_cos += angle_cos if not len(b[1]) == 0: avg_mag /= len(b[1]) if not len(b[1]) == 0: avg_angle_cos /= len(b[1]) temp_per_r.append([b[0], avg_angle_cos, avg_mag]) #result.append(temp_per_r) result_t[rdata[0]] = temp_per_r result[timestep] = result_t ### end of loop: check elapsed time t2 = time.time() # time mark elapsed_time = t2 - t1 ### write pickle o = open(out_file + ".pickle", 'w') pickle.dump(result, o) ### return print('') return 1