def loadFF(file): if file == "": #nu.warn("Forcefield type is not specified. Using DREIDING 2 as default.") file = "/home/noische/ff/DREIDING2.21.ff" file = file.strip() lines = [] try: ffFile = open(file) while 1: line = ffFile.readline() if line == "": break line = line.strip() line = line.rstrip('\n') line = re.split('\s*', line) lines.append(line) except IOError: nu.die("Force Field File " + file + " open failed") else: pass; #print("Force Field Dreiding loaded") start_index = lines.index(["VERSION"]) stop_index = lines.index(["END"], start_index) temp = nu.flatten(lines[start_index + 1 : stop_index]) for i in temp: if "CERIUS" in i: return lines nu.die("Forcefield file " + file + " is not a CERIUS2 type file.")
def analyze(bgf_file, trj_file, ff_file='', out_file=''): '''analyze something within a timestep in a series of lammps trajectory. ''' # variables # 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) # 2. Read LAMMPS Trajectory #timesteps, N_HEADER, N_ATOMS = lt.getTrjInfo(trj_file) mytrj = lt.lammpstrj(trj_file) timesteps = mytrj.load() N_HEADER = mytrj.nheader N_ATOMS = mytrj.natoms[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) for t in tqdm.tqdm(timesteps, ncols=120, desc="Analyzing"): chunk = [next(dump) for i in range(N_BUFFER)] t = int(chunk[1]) mybgf.CRYSTX = mytrj.pbc[t] + [90.0, 90.0, 90.0] coords = chunk[9:] for c in coords: c = c.split(' ') atom = mybgf.getAtom(int(c[0])) if yes_scale: atom.x = float(c[2]) * pbc[0] atom.y = float(c[3]) * pbc[1] atom.z = float(c[4]) * pbc[2] else: atom.x = float(c[2]) atom.y = float(c[3]) atom.z = float(c[4]) mybgf = bt.periodicMoleculeSort(mybgf, mybgf.CRYSTX, ff_file=ff_file, silent=True)
def set_coord(self, coord): if len(coord) != len(self.bgfmodel.a): nu.die("Number of coordinates != number of BGF atoms") for index, i in enumerate(coord): self.bgfmodel.a[index].x = i[0] self.bgfmodel.a[index].y = i[1] self.bgfmodel.a[index].z = i[2]
def dat2bgf(bgf_file, dat_file, out_file): # init mybgf = bgf.BgfFile(bgf_file) f_dat_file = open(dat_file) temp = f_dat_file.read().split('\n') f_dat_file.close() temp = [i.partition('#')[0].rstrip() for i in temp if i != ""] # PBC for i in temp: if 'xlo' in i: line = i.split() mybgf.CRYSTX[0] = float(line[1]) - float(line[0]) if 'ylo' in i: line = i.split() mybgf.CRYSTX[1] = float(line[1]) - float(line[0]) if 'zlo' in i: line = i.split() mybgf.CRYSTX[2] = float(line[1]) - float(line[0]) # Coordinates dat_atom_start = temp.index('Atoms') dat_atom_end = temp.index('Bonds') if 'Velocities' in temp: dat_atom_end = temp.index('Velocities') # if data file is from write_restart command, Velocities are also written in the file.:w temp = temp[dat_atom_start + 1:dat_atom_end] n_dat_atoms = len(temp) n_bgf_atoms = len(mybgf.a) if n_dat_atoms != n_bgf_atoms: nu.die("Number of atoms mismatch between bgf and LAMMPS data file.") coords = [] # coords = id type molid charge x y z ix iy iz for i in temp: line = i.split() coords.append(line) for i in coords: id = int(i[0]) atom = mybgf.a[mybgf.a2i[id]] # getAtom atom.x = float(i[4]) atom.y = float(i[5]) atom.z = float(i[6]) if out_file == "": out_file = bgf_file.split(".bgf")[0] + "_mod.bgf" mybgf.REMARK.append("Coordinates updated on %s" % time.asctime(time.gmtime())) mybgf.REMARK.append("Coordinates updated with data file %s" % os.path.abspath(dat_file)) mybgf.saveBGF(out_file) print('Done. Check %s ' % out_file) return 1
def computeLatticeParam(self, lv): if not len(lv) == 3: nu.die("Proper lattice vectors are not provided.") x = lv[0] y = lv[1] z = lv[2] A, B, C = [veclength(v) for v in lv] alpha = angle(y, z) beta = angle(x, z) gamma = angle(x, y) return [A, B, C, alpha, beta, gamma]
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)!" ) # find nearest neighbor from D atom # calculate hbonds for d_atom in D: d = np.array([d_atom.x, d_atom.y, d_atom.z]) for a_atom in A: a = np.array([a_atom.x, a_atom.y, a_atom.z]) if 1e-5 < nu.pbc_dist(a, d, mytrj.pbc[t]) < d_crit: 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: hbonds.append([ d_atom.aNo, a_atom.aNo, d_atom.z, a_atom.z ]) #donors.append(d_atom.aNo) #acceptors.append(a_atom.aNo) #hydrogens.append(h_atom.aNo) #distances.append(dist) return hbonds
def getCom(myBGF, ff_file='', aNo_list=[], silent=False): """ getCom(myBGF): Returns a (x, y, z) of the center of mass of the molecule. """ # init mrx = 0 mry = 0 mrz = 0 m = 0 # if aNo_list not specified, CoM of whole molecule will be returned. if not aNo_list: for atom in myBGF.a: aNo_list.append(atom.aNo) # read atom mass from the dictionary for i in aNo_list: atom = myBGF.getAtom(i) fftype_key = atom.ffType.strip() if not fftype_key in atom_mass: parse = ff_file.split() update_mass(parse, silent=silent) if not fftype_key in atom_mass: nu.die( "No ffType %s found in the atom mass dictionary. You have to specify a ff_file to countinue." % fftype_key) mrx += (atom.x * float(atom_mass[fftype_key])) mry += (atom.y * float(atom_mass[fftype_key])) mrz += (atom.z * float(atom_mass[fftype_key])) m += float(atom_mass[fftype_key]) try: x = mrx / m y = mry / m z = mrz / m except: nu.warn( "Total mass is zero for the molecule while calculating center of mass!" ) x = 0 y = 0 z = 0 return (x, y, z)
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]) neigh_anos = bt.get_neighbors_aNo(A, d, r=d_crit, pbc=mytrj.pbc[t]) for ano in neigh_anos: a_atom = mybgf.getAtom(ano) h = bt.is_hbonded2(mybgf, d_atom, a_atom) # returns hbonded H coord if len(h) != 0: a = np.array([a_atom.x, a_atom.y, a_atom.z]) dist = nu.pbc_dist(a, d, mytrj.pbc[t]) u = h - d v = a - d theta = np.dot(u, v) / norm(u) / norm(v) theta = np.degrees(arccos(theta)) hbonds.append( [d_atom.aNo, a_atom.aNo, d, a, dist, theta]) return hbonds
def count_layer(bgf_file, trj_file, ff_file='', out_file=''): '''counts number of O atoms in each layer. ''' # variables result = dict() # 1. Load BGF mybgf = bgf.BgfFile(bgf_file) N_BGF_ATOMS = len(mybgf.a) r_vdw_C = 3.38383824 / 2 # 2. Read LAMMPS Trajectory mytrj = lt.lammpstrj(trj_file) timesteps = mytrj.load() N_ATOMS = mytrj.natoms[0] if N_BGF_ATOMS != N_ATOMS: nu.die( "Number of atoms in trajectory file does not match with BGF file.") # 4. Update coordinates from the snapshot for t in tqdm.tqdm(timesteps, ncols=120, desc="Calculating graphene z positions"): mybgf = get_timestep(mybgf, trj_file, t) avg_gra_z1 = bt.atoms_average( mybgf, 'atom.z', selection="'C_2G' in atom.ffType and atom.rNo == 1") avg_gra_z2 = bt.atoms_average( mybgf, 'atom.z', selection="'C_2G' in atom.ffType and atom.rNo == 2") dist = avg_gra_z2 - avg_gra_z1 eff_dist = avg_gra_z2 - avg_gra_z1 - 2 * r_vdw_C result[t] = [avg_gra_z1, avg_gra_z2, dist, eff_dist] # 5. Analyze timesteps = sorted(result.keys()) with open('z_position.test.dat', 'w') as f: output = '' for t in timesteps: output += "%d " % t output += "%8.3f %8.3f %8.3f %8.3f\n" % result[t] f.write(output)
def stress_cell(bgf_file, ratio, out_file=''): ''' scales the cell to the ratio. ''' # initialization if not isinstance(bgf_file, bgf.BgfFile): myBGF = bgf.BgfFile(bgf_file) else: myBGF = bgf_file if not myBGF.CRYSTX: nu.die("No pbc information to stress the cell.") xs = ys = zs = 1.0 parse = ratio.split() if len(parse) == 1: xs = ys = zs = float(parse[0]) elif len(parse) == 3: xs = float(parse[0]) ys = float(parse[1]) zs = float(parse[2]) else: nu.die("Error on specifying cell inflation ratio %s: must be 1 or 3" % ratio) for atom in myBGF.a: atom.x *= xs atom.y *= ys atom.z *= zs myBGF.CRYSTX[0] *= xs myBGF.CRYSTX[1] *= ys myBGF.CRYSTX[2] *= zs # returns if not out_file: return myBGF else: myBGF.saveBGF(out_file) if not silent: print("File saved to %s" % out_file) return 1
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
def dot(a, b): """ Calculate dot product of a and b """ try: na = len(a) nb = len(b) except: nu.die("List required for dot product calculation.") na = len(a) nb = len(b) temp = [a[i] * b[i] for i in range(na)] temp2 = 0 for i in temp: temp2 += i return temp2
def atoms_minmax(mybgf, attr, selection=''): min = 1e10 max = -1e10 # conditions if not attr: nu.die("You have to specify BgfAtom attribute to get minmax!") if not 'atom.' in attr: attr = "atom." + attr if not attr in possible_atom_attr: nu.die("Impossible to get minmax of %s!" % attr) if not "atom" in selection: nu.die("You have to specify a proper selection!") # get minmax for atom in mybgf.a: if selection: if eval(selection): if eval(attr) < min: min = eval(attr) if eval(attr) > max: max = eval(attr) else: if eval(attr) < min: min = eval(attr) if eval(attr) > max: max = eval(attr) return min, max
def atoms_average(mybgf, attr, selection=''): ''' attr: e.g.) x, y, z or atom.x, atom.y, ... selection: e.g.) "'Mo' in atom.ffType" ''' # init avg = 0.0 n = 0 # conditions if not attr: nu.die("You have to specify BgfAtom attribute to average!") if not 'atom.' in attr: attr = "atom." + attr if not attr in possible_atom_attr: nu.die("Impossible to get average of %s!" % attr) if not "atom" in selection: nu.die("You have to specify a proper selection!") # get average for atom in mybgf.a: if selection: if eval(selection): avg += eval(attr) n += 1 else: avg += eval(attr) n += 1 return avg / float(n)
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 compile(self, filename="compile.bgf"): """ generate random hyperbranched polymer structure according to the graph. returns a BgfFile object. """ # LAMMPS preparation lammps_command = os.environ["EXEC"] curr_dir = os.path.abspath(".") temp_dir = curr_dir + ("/scratch/") if not os.path.isdir(temp_dir): os.makedirs(temp_dir) os.chdir(temp_dir) # REMARK: make sure self.Terminal/Linear/Dendron is properly assigned. if self.Terminal == "" or self.Linear == "" or self.Dendron == "": nu.die("BGF file for monomers are not properly set.") return False # for i in nodes: for i in self.nodes(): ## introduce a monomer ### count a number of branches connected to a node n_branch = 0 parent_monomer = 0 for j in self[i]: if i < j: n_branch += 1 elif i > j: parent_monomer = j if n_branch == 0: new_monomer = bgf.BgfFile(self.Terminal) elif n_branch == 1: new_monomer = bgf.BgfFile(self.Linear) elif n_branch == 2: new_monomer = bgf.BgfFile(self.Dendron) for atom in new_monomer.a: atom.rNo = i # set the residue number to the node id ## connect the monomer to the body if i == 0: self.bgfmodel = self.bgfmodel.merge(new_monomer) self.bgfmodel.renumber() continue ### for headnode, no connection is required. else: ### head: in monomer (C) // tail: in the body (N) for atom in self.bgfmodel.a: if ("B" in atom.chain or "T" in atom.chain) and atom.rNo == parent_monomer: tail_atom_ano = atom.aNo for atom in new_monomer.a: if "H" in atom.chain and atom.rNo == i: head_atom_ano = atom.aNo head_atom = new_monomer.getAtom(head_atom_ano) tail_atom = self.bgfmodel.getAtom(tail_atom_ano) # choose a random H atom to detach from the tail (N) bonding_candidate_body = [] for ano in tail_atom.CONECT: atom = self.bgfmodel.getAtom(ano) if "H" in atom.ffType and "H" in atom.aName: bonding_candidate_body.append(ano) bonding_candidate_body = random.choice(bonding_candidate_body) bonding_candidate_body_atom = self.bgfmodel.getAtom( bonding_candidate_body) # translate (x, y, z) = (bonding_candidate_body_atom.x, bonding_candidate_body_atom.y, bonding_candidate_body_atom.z) for atom in new_monomer.a: atom.x += x atom.y += y atom.z += z # merge self.bgfmodel = self.bgfmodel.merge(new_monomer) self.bgfmodel.renumber() # choose a random H atom to detach from the head (C) bonding_candidate_monomer = [] for ano in head_atom.CONECT: atom = self.bgfmodel.getAtom(ano) if "H" in atom.ffType and "H" in atom.aName: # any H atoms are exposed to detachment bonding_candidate_monomer.append(ano) bonding_candidate_monomer = random.choice( bonding_candidate_monomer) bonding_candidate_monomer_atom = self.bgfmodel.getAtom( bonding_candidate_monomer) # connect tail_atom.connect(head_atom) head_atom.connect(tail_atom) tail_atom.charge += bonding_candidate_body_atom.charge head_atom.charge += bonding_candidate_monomer_atom.charge delatoms = [ self.bgfmodel.a2i[bonding_candidate_body], self.bgfmodel.a2i[bonding_candidate_monomer] ] self.bgfmodel.delAtoms(delatoms) self.bgfmodel.renumber() # translate _ = bgftools.getCom(self.bgfmodel, self.ff) for atom in self.bgfmodel.a: atom.x -= _[0] atom.y -= _[1] atom.z -= _[2] # save temp_suffix = "_polymer_" + str(i) temp_file = temp_suffix + ".bgf" # ex) _polymer_1.bgf self.bgfmodel.CRYSTX = [50.0, 50.0, 50.0, 90.0, 90.0, 90.0] self.bgfmodel.PERIOD = "111" self.bgfmodel.AXES = "ZYX" self.bgfmodel.SGNAME = "P 1 1 1" self.bgfmodel.CELLS = [-1, 1, -1, 1, -1, 1] self.bgfmodel.saveBGF(temp_file) # Minimization on LAMMPS createLammpsInput = "~tpascal/scripts/createLammpsInput.pl" + " -b " + temp_file + " -f " + self.ff + " -s " + temp_suffix + " -o 'no shake' -t min " + " > /dev/null" os.system(createLammpsInput) in_file = "in." + temp_suffix data_file = "data." + temp_suffix # LAMMPS input patch #os.system("sed -i 's/' " + in_file) os.system("sed -i 's/dielectric 1/dielectric 72/' " + in_file) os.system( "sed -i 's/kspace_style pppm 0.0001/kspace_style none/' " + in_file) os.system( "sed -i 's/boundary p p p/boundary s s s/' " + in_file) os.system( "sed -i 's/lj\/charmm\/coul\/long\/opt 7.5 8.50000/lj\/cut\/coul\/debye 0.142 10/' " + in_file) # LAMMPS data patch os.system( "sed -i 's/0.000000 50.000000/-50.000000 50.000000/' " + data_file) os.system("sed -i 's/0 # X/0 0 # X/' " + data_file) os.system("sed -i 's/Impropers//' " + data_file) t1 = time.time() runLammps = lammps_command + " -in in." + temp_suffix + " -log " + temp_suffix + ".log " + "-screen none" #print("Running " + runLammps) os.system(runLammps) t2 = time.time() #print("Elapsed time for minimization: " + str(t2 - t1) + " sec") # update coordinates trj_file = temp_suffix + ".min.lammpstrj" LAMMPS_trj2bgf.getLAMMPSTrajectory(temp_file, trj_file, temp_file, -1, False, True) self.bgfmodel = bgf.BgfFile(temp_file) # compile success! self.bgfmodel.saveBGF(curr_dir + '/' + filename)
def getVelocity(bgf_file, trj_file, n_step, silent=False): # const PI = math.pi vdw_r_C = 1.7 # init timestep = 0 l_timestep = [] line = [] n_header = 0 t1 = 0 t2 = 0 # clock l_data = [] # stores vz l_avg_radius_CNT = [] myBGF = bgf.BgfFile(bgf_file) myTRJ = open(trj_file) myTRJ.seek(0) ftemp = open("countWater42.profile", 'w') ftemp.write(str(sys.argv) + "\n") curr_dir = os.path.abspath(".") temp_dir = curr_dir + "/CountWAT42/" if not os.path.isdir(temp_dir): os.makedirs(temp_dir) # how many steps to go? n_timestep = len(lt.getTrjInfo(trj_file)) if n_step == 0: n_step = n_timestep print(" ..The trajectory contains " + str(n_timestep) + " timesteps.") print("The script will proceed for the last " + str(n_step) + " timesteps.") # extract aNos of CNT in the BGF file aNo_CNT = [] aNo_WAT_O = [] aNo_WAT_all = [] for atom in myBGF.a: # Carbons in CNT or atoms in BNNT if "NT" in atom.rName: aNo_CNT.append(atom.aNo) # Oxygen in water if "WAT" in atom.rName and "O" in atom.aName: aNo_WAT_O.append(atom.aNo) N_CNT = len(aNo_CNT) # the number of CNT atoms # check if there exists water properly if len(aNo_WAT_O) == 0: nu.die("No water molecules in the BGF file.") if len(aNo_CNT) == 0: nu.die("No CNT molecules in the BGF file.") # 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: ### Show progress t1 = time.time() remaining_time = elapsed_time * (n_step - processed_step) sys.stdout.write('\r' + "Reading timestep.. " + str(timestep) + " (Remaining time: " + "{0:4.1f}".format(remaining_time) + " seconds, " + "{0:4.1f} minutes".format(remaining_time / 60) + ")") sys.stdout.flush() if processed_step == n_step: break ### Read try: chunk = [next(dumpatom) for i in range(natoms + n_header)] except StopIteration: break timestep = int(chunk[1]) 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(' ') ### 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 = 'unwrapped' # assume that "dump 1 all custom 100 ${sname}${rtemp}K.nvt.lammps id type xu yu zu vx vy vz" in lammps input # actual coordinate coordinfo = chunk[9:] # modified for fast treatment for atomline in coordinfo: atomcoord = atomline.split(' ') atom = myBGF.getAtom(int(atomcoord[0])) atom.x = float(atomcoord[2]) atom.y = float(atomcoord[3]) atom.z = float(atomcoord[4]) atom.vx = float(atomcoord[5]) atom.vy = float(atomcoord[6]) atom.vz = float(atomcoord[7]) if myBGF.CRYSTX != []: for i in range(0, 3): myBGF.CRYSTX[i] = boxsize[i] else: nu.warn("Crystal information error: is this file not periodic?") for i in range(0, 3): myBGF.CRYSTX.append(boxsize[i]) ### myBGF update complete! ### ### align CNT to z axis # initialize for the moment of inertia and the center of mass calculation U = 0 Ut = 0 Uv = 0 Ixx = 0 Ixy = 0 Ixz = 0 Iyx = 0 Iyy = 0 Iyz = 0 Izx = 0 Izy = 0 Izz = 0 Mx = 0 My = 0 Mz = 0 # set COM of CNT as origin Mx = 0 My = 0 Mz = 0 # Center of mass of CNT for atom in myBGF.a: if "NT" in atom.rName: Mx += atom.x / N_CNT My += atom.y / N_CNT Mz += atom.z / N_CNT for atom in myBGF.a: atom.x -= Mx # move atom.y -= My atom.z -= Mz # calculate the moment of inertia (MI) and the center of mass (COM) of CNT from "myBGF" for aNo in aNo_CNT: atom = myBGF.getAtom(aNo) Ixx += (atom.y**2 + atom.z**2) / N_CNT Iyy += (atom.x**2 + atom.z**2) / N_CNT Izz += (atom.x**2 + atom.y**2) / N_CNT Ixy -= (atom.x * atom.y) / N_CNT Ixz -= (atom.x * atom.z) / N_CNT Iyz -= (atom.y * atom.z) / N_CNT # the moment of inertia tensor I = np.array([[Ixx, Ixy, Ixz], [Ixy, Iyy, Iyz], [Ixz, Iyz, Izz]]) # eigenvalue & eigenvector calculation eigval, eigvec = np.linalg.eig( I) # eigval[0] is the minimum among the values. # rearrange the U vector U = np.matrix(eigvec) Ut = U.T # "myBGF" rotation for atom in myBGF.a: v = np.matrix([atom.x, atom.y, atom.z]).T Uv = Ut * v atom.x = float(Uv[2]) atom.y = float(Uv[1]) atom.z = float(Uv[0]) #dimension = np.matrix(boxsize).T #boxsize_prime = np.array(np.dot(Ut, dimension).T) boxsize_prime = np.transpose( np.dot(Ut, np.transpose(np.array(boxsize)))) # new pbc from jackjack5 print(boxsize) print(boxsize_prime) # move atoms to box center for atom in myBGF.a: atom.x -= boxsize_prime[0] / 2 atom.y -= boxsize_prime[1] / 2 atom.z -= boxsize_prime[2] / 2 myBGF.saveBGF(temp_dir + bgf_file.split(".bgf")[0] + "." + str(timestep) + ".beforepbc.bgf") myBGF = bgftools.periodicMoleculeSort(myBGF, 0, myBGF.CRYSTX) myBGF.saveBGF(temp_dir + bgf_file.split(".bgf")[0] + "." + str(timestep) + ".bgf") # for CNT atoms, calculate some properties min_x_CNT = 1000.0 max_x_CNT = -1000.0 radius_CNT = 0.0 height_CNT = 0.0 min_y_CNT = 1000.0 max_y_CNT = -1000.0 min_z_CNT = 1000.0 max_z_CNT = -1000.0 l_radius_CNT = [] l_x_CNT = [] l_y_CNT = [] for aNo in aNo_CNT: atom = myBGF.getAtom(aNo) # center of CNT l_x_CNT.append(atom.x) l_y_CNT.append(atom.y) # height if atom.z < min_z_CNT: min_z_CNT = atom.z if atom.z > max_z_CNT: max_z_CNT = atom.z x_CNT, a = nu.meanstdv(l_x_CNT) y_CNT, a = nu.meanstdv(l_y_CNT) z_diff = max_z_CNT - min_z_CNT height_CNT = z_diff # radius of CNT for aNo in aNo_CNT: atom = myBGF.getAtom(aNo) l_radius_CNT.append( math.sqrt((atom.x - x_CNT)**2 + (atom.y - y_CNT)**2)) radius_CNT, a = nu.meanstdv(l_radius_CNT) l_avg_radius_CNT.append(radius_CNT) ### get water molecules in CNT # inside the CNT := min_z_CNT <= z <= max_z_CNT and (x - (x_diff/2))**2 + (y - (y_diff/2))**2 < radius_CNT**2 # aNo_WAT_O_atoms: molecules which O atom is within CNT # we don't need to calculate H atoms. Let's consider only O atoms margin = 0.0 # water molecules far from the margin will be only considered aNo_WAT_O_in_CNT = [] for aNo in aNo_WAT_O: atom = myBGF.getAtom(aNo) dist_sq = (atom.x - x_CNT)**2 + (atom.y - y_CNT)**2 if "WAT" in atom.rName and "O" in atom.ffType and min_z_CNT + margin <= atom.z and atom.z <= max_z_CNT - margin and dist_sq < radius_CNT**2: aNo_WAT_O_in_CNT.append(aNo) else: pass ### record number of water molecules in CNT #l_data.append([timestep, len(aNo_WAT_O_in_CNT), radius_CNT, z_diff]) #output = str(timestep) + '\t' + str(len(aNo_WAT_O_in_CNT)) + '\t' + str(radius_CNT) + '\t' + str(z_diff) + '\n' output = str(timestep) + '\t' + str( len(aNo_WAT_O_in_CNT)) + '\t' + str(radius_CNT) + '\t' + str( min_z_CNT) + '\t' + str(max_z_CNT) + '\t' + str( z_diff) + '\t' + str(height_CNT) + '\t' + str( len(aNo_CNT)) + '\n' # debug ftemp.write(output) #sys.stdout.write('Done ') sys.stdout.flush() t2 = time.time() # time mark elapsed_time = t2 - t1 processed_step += 1 print('') ftemp.close() print( "numbers of water molecules are written in countWater.profile ..Done.") return 1
def calc_hbonds(mybgf, selection=""): # 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
elif option in ('-r', '--ratio'): r = [float(i) for i in str.split(value)] elif option in ('-m', '--mw'): M = float(value) elif option in ('-o', '--output'): out_file = value elif option in ('-f', '--ff'): ff = str(value) elif option in ('-n', '--n'): n = int(value) elif option in ('-a', '--force'): isForce = True elif option in (''): print usage sys.exit(0) # check ratio if np.array(r).sum() == 100: r = [float(i / 100) for i in r] elif np.array(r).sum() != 1: nu.die("Ratio sum should be 1 (fraction) or 100 (percentage)") # defaults if ff == "": ff = "/home/noische/ff/DREIDING2.21.ff" if n == 0: n = 1 # main run main(T, L, D, r, M, out_file, ff, n, isForce, silent)
def getLogData(log_file, out_file, requested_key, silent=True): """ getLogData: GET thermodynamic data from a LAMMPS log file If getLogData is called from the main function, then getLogData will write the parsed data into keyword.log.parsed Otherwise, the list of [step, value(keyword)] will be returned. """ # initialization n_count = 0 TICK = 10000 # parse section and extract all thermodynamic data #pat1 = re.compile(r"Step\s*(\S*)\s-+") # (old) pat1 = re.compile( r"Step[-= ]*(\d*)" ) # step. modified in case with /qcfs/dongshin/lis/test/reaxff/trial01/reaxtest/reaxtest.log pat2 = re.compile(r"([A-z]+)\s+=\s*-*\d+\.\d+") # keywords pat3 = re.compile(r"[A-z]+\s+=\s*(-*\d+\.\d+)") # numbers # log file loading myLOG = open(log_file) myLOG_output = [] # preprocessing if not silent: print("\n== Step 1. Preprocessing the LAMMPS log file") wc_log_file = os.popen("wc -l " + log_file).read() # file newline counts log_file_length = int(wc_log_file.split()[0]) str_log_file_length = str(log_file_length) t1 = time.time() t2 = 0 while 1: try: line = myLOG.readline() if not line: break line = line.replace("\n", "") n_count += 1 if not silent: if n_count % TICK == 0 or n_count == log_file_length: # estimated time calculation t2 = time.time() elapsed = t2 - t1 estimated = elapsed * ((log_file_length - n_count) // TICK) # string conversion str_n_count = str(n_count) str_estimated = "{0:4.1f}".format(estimated) sys.stdout.write("\rPreprocessing.. " + str_n_count + " / " + str_log_file_length + ".. " + "(" + str_estimated + " sec remain)") sys.stdout.flush() # reassigning time t1 = t2 # keyword checking """ ### ORIGINAL version if "angle_coeff" in line or "angle_style" in line or "atom_modify" in line or "atom_style" in line or \ "bond_coeff" in line or "bond_style" in line or "boundary" in line or "change_box" in line or \ "variable" in line or "data" in line or "group" in line or "dump" in line or \ "clear" in line or "communicate" in line or "compute" in line or "compute_modify" in line or \ "create_atoms" in line or "create_box" in line or "delete_atoms" in line or "delete_bonds" in line or \ "dielectric" in line or "dihedral_coeff" in line or "dihedral_style" in line or "dimension" in line or \ "displace_atoms" in line or "displace_box" in line or "dump" in line or "dump" in line or "image" in line or \ "dump_modify" in line or "echo" in line or "fix" in line or "fix_modify" in line or \ "group" in line or "if" in line or "improper_coeff" in line or "improper_style" in line or \ "include" in line or "jump" in line or "kspace_modify" in line or "kspace_style" in line or \ "label" in line or "lattice" in line or "log" in line or "mass" in line or \ "minimize" in line or "min_modify" in line or "min_style" in line or "neb" in line or \ "neigh_modify" in line or "neighbor" in line or "newton" in line or "next" in line or \ "package" in line or "pair_coeff" in line or "pair_modify" in line or "pair_style" in line or \ "pair_write" in line or "partition" in line or "prd" in line or "print" in line or \ "processors" in line or "read_data" in line or "read_restart" in line or "region" in line or \ "replicate" in line or "reset_timestep" in line or "restart" in line or "run" in line or \ "run_style" in line or "set" in line or "shell" in line or "special_bonds" in line or \ "suffix" in line or "tad" in line or "temper" in line or "thermo" in line or \ "thermo_modify" in line or "thermo_style" in line or "timestep" in line or "uncompute" in line or \ "undump" in line or "unfix" in line or "units" in line or "variable" in line or \ "velocity" in line or "write_restart" in line: pass; """ ### 2nd version if "coeff" in line or "modify" in line or "style" in line or \ "boundary" in line or "change_box" in line or \ "variable" in line or "data" in line or "group" in line or "dump" in line or \ "clear" in line or "communicate" in line or "compute" in line or \ "create" in line or "delete" in line or \ "dielectric" in line or "dimension" in line or \ "displace_atoms" in line or "displace_box" in line or "image" in line or \ "echo" in line or "fix" in line or \ "group" in line or "if" in line or \ "include" in line or "jump" in line or \ "label" in line or "lattice" in line or "log" in line or "mass" in line or \ "minimize" in line or "neb" in line or \ "neighbor" in line or "newton" in line or "next" in line or \ "package" in line or \ "write" in line or "partition" in line or "prd" in line or "print" in line or \ "processors" in line or "read" in line or "region" in line or \ "replicate" in line or "time" in line or "restart" in line or "run" in line or \ "set" in line or "shell" in line or "special_bonds" in line or \ "tad" in line or "temper" in line or "thermo" in line or \ "uncompute" in line or \ "units" in line or "variable" in line or \ "velocity" in line: pass elif "Step" in line or "TotEng" in line or "PotEng" in line or "E_dihed" in line or "E_coul" in line or \ "Temp" in line or "Volume" in line: myLOG_output.append(line) elif "KinEng" in line or "E_bond" in line or "E_impro" in line or "E_long" in line or \ "E_angle" in line or "E_vdwl" in line or "Press" in line or \ "v_" in line or "c_" in line: myLOG_output.append(line) except KeyboardInterrupt: nu.die("Keyboard Break.. Exiting.") #print(myLOG_output) # Preprocessed data # find the number of last step templist = copy.deepcopy(myLOG_output) laststep = "" while 1: l = templist.pop() if "Step" in l: laststep = l break laststep = int(re.search(pat1, laststep).group(1)) # last step str_laststep = str(laststep) if not silent: sys.stdout.write("\nDone.\n") if not silent: print("\n== Step 2. Getting Thermodynamic Properties") if out_file != "": myLOG_parse = open(out_file, "w") # output file section = "" thermo_data = [] line = "" # first line: pass!! section = myLOG_output[0] myLOG_output = myLOG_output[1:] t1 = time.time() t2 = 0 try: for line in myLOG_output: section_full = False if "Step" in line: section_full = True # for ONE step if section_full == True: step = int(re.search(pat1, section).group(1)) # steps keyword = re.findall(pat2, section) # keywords value = re.findall(pat3, section) # numbers # display step progress if not silent: if step % TICK == 0 or step == laststep: # estimated time calculation t2 = time.time() elapsed = t2 - t1 estimated = elapsed * ((laststep - step) // TICK) str_step = str(step) str_estimated = "{0:4.1f}".format(estimated) sys.stdout.write("\rParsing the Step " + str_step + " / " + str_laststep + ".. " + "(" + str_estimated + " sec remain)") sys.stdout.flush() # reassign time t1 = t2 if len(keyword) != len(value): nu.warn("Suspicious parsing at " + str(step) + ".. Exiting.") break # check if keyword is a filename if out_file != "": # Write thermodynamic data to a new file for further use output_myLOG_parse = "Step\t" + str(step) + "\t" for asdf in range(0, len(keyword)): output_myLOG_parse += keyword[asdf] + "\t" + str( value[asdf]) + "\t" output_myLOG_parse += "\n" myLOG_parse.write(output_myLOG_parse) # keyword check if requested_key == "": # no option: return the whole data [keyword value keyword value ...] temp = [] temp.append("Step") temp.append(step) for i in range(0, len(keyword)): temp.append(keyword[i]) temp.append(value[i]) thermo_data.append(temp) else: # with keyword: append to the result list try: temp = keyword.index(requested_key) except: #nu.warn("Keyword " + str(keyword) + " is not found in the log file.. Exiting.") pass else: thermo_data.append([step, value[temp]]) # empty bin section = line section_full = False else: section += line except KeyboardInterrupt: nu.die("Keyboard Break.. Exiting.") if out_file != "": if not silent: print("\nParsed thermodynamic data is saved on " + out_file + " ..") myLOG_parse.close() if not silent: sys.stdout.write("Done.\n") return thermo_data
def countWater(bgf_file, trj_file, n_step, watercopy, ff_file, silent=False): ### const PI = math.pi vdw_r_C = 1.7 ### init timestep = 0 l_timestep = [] line = [] n_header = 0 t1 = 0 t2 = 0 # clock myBGF = bgf.BgfFile(bgf_file) myTRJ = open(trj_file) myTRJ.seek(0) global out_file if out_file == "": out_file = "countWater5.profile" print("The result will be recorded to the file " + out_file + " ...") ftemp = open(out_file, 'w') ftemp.write(str(sys.argv) + "\n") ftemp.write("t" + '\t' + "n_O" + '\t' + "r_CNT" + '\t' + "std_r" + '\t' + "min_x" + '\t' + "max_x" + '\t' + "min_y" + '\t' + "max_y" + '\t' + "min_z" + '\t' + "max_z" + '\t' + "l_NT" + '\t' + "replNum" + '\t' + "copyNum" + '\t' + "n_WAT" + '\t' + "remark" + '\n') curr_dir = os.path.abspath(".") temp_dir = curr_dir + "/countWAT5/" print(temp_dir) if not os.path.isdir(temp_dir): os.makedirs(temp_dir) ### how many steps to go? n_timestep = len(lt.getTrjInfo(trj_file)) if n_step == 0: n_step = n_timestep print(" ..The trajectory contains " + str(n_timestep) + " timesteps.") print("The script will proceed for the first " + str(n_step) + " timesteps.") ### read mass from ff_file atominfo = dict() 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) ### extract aNos of CNT in the BGF file aNo_CNT = [] aNo_WAT_O = [] aNo_WAT_all = [] mass_CNT = [] for atom in myBGF.a: # Carbons in CNT or atoms in BNNT if "NT" in atom.rName: aNo_CNT.append(atom.aNo) 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.") mass_CNT.append(aMass) # Oxygen in water if "WAT" in atom.rName and "O" in atom.aName: aNo_WAT_O.append(atom.aNo) N_CNT = len(aNo_CNT) # the number of CNT atoms ### check if there exists water properly if len(aNo_WAT_O) == 0: nu.die("No water molecules in the BGF file.") if len(aNo_CNT) == 0: nu.die("No CNT molecules in the BGF file.") ### 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: ### Show progress t1 = time.time() remaining_time = elapsed_time * (n_step - processed_step) sys.stdout.write('\r' + "Reading timestep.. " + str(timestep) + " (Remaining time: " + "{0:4.1f}".format(remaining_time) + " seconds, " + "{0:4.1f} minutes".format(remaining_time / 60) + ")") sys.stdout.flush() if processed_step == n_step: break ### Read myBGF = bgf.BgfFile(bgf_file) try: chunk = [next(dumpatom) for i in range(natoms + n_header)] except StopIteration: break timestep = int(chunk[1]) 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(' ') mode = 'unwrapped' # assume that "dump 1 all custom 100 ${sname}${rtemp}K.nvt.lammps id type xu yu zu vx vy vz" in lammps input # actual coordinate coordinfo = chunk[9:] # load atom coordinates from chunk for atomline in coordinfo: atomcoord = atomline.split(' ') atom = myBGF.getAtom(int(atomcoord[0])) atom.x = float(atomcoord[2]) atom.y = float(atomcoord[3]) atom.z = float(atomcoord[4]) ### convert atom coordinates to lists CNT = [] WATER = [] for atom in myBGF.a: if "NT" in atom.rName: CNT.append([atom.x, atom.y, atom.z]) if "WAT" in atom.rName and "O" in atom.ffType: WATER.append([atom.x, atom.y, atom.z]) CNT = np.array(CNT) n_CNT = len(CNT) # CNT coordinates WATER = np.array(WATER) # Water coordinates WATERONLY = np.copy(WATER) boxsize = np.array(boxsize) ### initialize for the moment of inertia and the center of mass calculation U = 0 Ut = 0 Uv = 0 Ixx = 0 Ixy = 0 Ixz = 0 Iyx = 0 Iyy = 0 Iyz = 0 Izx = 0 Izy = 0 Izz = 0 Mx = 0 My = 0 Mz = 0 ### transpose "all atoms in BGF": move COM of CNT as origin Mx, My, Mz = np.average(CNT, axis=0, weights=mass_CNT) # CoM of CNT COM = np.array([[Mx, My, Mz]]) CNT = CNT - COM + boxsize / 2.0 # move WATER = WATER - COM + boxsize / 2.0 ### apply PBC WATER = np.mod(WATER, boxsize) ### save coordinates to BGF before rotation myBGF2 = bgf.BgfFile() for index, i in enumerate(CNT): newatom = bgf.BgfAtom() newatom.x, newatom.y, newatom.z = i newatom.aNo = index newatom.aName = 'C' + str(index) newatom.rName = 'CNT' newatom.ffType = 'C_' newatom.chain = 'A' newatom.rNo = 1 myBGF2.addAtom(newatom) for index, i in enumerate(WATER): newatom = bgf.BgfAtom() newatom.x, newatom.y, newatom.z = i newatom.aNo = index + n_CNT newatom.aName = 'O' newatom.rName = 'WAT' newatom.ffType = 'OW' newatom.chain = 'O' newatom.rNo = 100 myBGF2.addAtom(newatom) myBGF2.REMARK.append('TIMESTEP ' + str(timestep)) myBGF2.PERIOD = "111" myBGF2.AXES = "ZYX" myBGF2.SGNAME = "P 1 1 1" myBGF2.CELLS = [-1, 1, -1, 1, -1, 1] myBGF2.CRYSTX = [boxsize[0], boxsize[1], boxsize[2], 90.0, 90.0, 90.0] myBGF2.saveBGF(temp_dir + bgf_file.split(".bgf")[0] + "." + str(timestep) + ".bgf") ### move CM of CNT to origin CNT = CNT - boxsize / 2.0 WATER = WATER - boxsize / 2.0 ### how the CNT is lying across the periodic box? for atom in CNT: min_x_CNT, min_y_CNT, min_z_CNT = CNT.min(axis=0) max_x_CNT, max_y_CNT, max_z_CNT = CNT.max(axis=0) margin = 5.0 ### copy water molecules max_x_axis = int(round((max_x_CNT + margin) / boxsize[0])) min_x_axis = int(round((min_x_CNT - margin) / boxsize[0])) max_y_axis = int(round((max_y_CNT + margin) / boxsize[1])) min_y_axis = int(round((min_y_CNT - margin) / boxsize[1])) max_z_axis = int(round((max_z_CNT + margin) / boxsize[2])) min_z_axis = int(round((min_z_CNT - margin) / boxsize[2])) replNum = (min_x_axis, max_x_axis, min_y_axis, max_y_axis, min_z_axis, max_z_axis) copyNum = 0 remark = "" if watercopy: for x in range(min_x_axis, max_x_axis + 1): remark += "x: " if x != 0: WATER2 = np.copy(WATERONLY) dx = np.array([[boxsize[0] * x, 0, 0]]) WATER2 = WATER2 + dx WATER = np.concatenate((WATER, WATER2)) copyNum += 1 remark += str(x) + " " for y in range(min_y_axis, max_y_axis + 1): remark += "y: " if y != 0: WATER2 = np.copy(WATERONLY) dy = np.array([[0, boxsize[1] * y, 0]]) WATER2 = WATER2 + dy WATER = np.concatenate((WATER, WATER2)) copyNum += 1 remark += str(y) + " " for z in range(min_z_axis, max_z_axis + 1): remark += "z: " if z != 0: WATER2 = np.copy(WATERONLY) dz = np.array([[0, 0, boxsize[2] * z]]) WATER2 = WATER2 + dz WATER = np.concatenate((WATER, WATER2)) copyNum += 1 remark += str(z) + " " ''' ### WATER distribution check x_axis = np.linspace(WATER[:,0].min(), WATER[:,0].max(), 10) y_axis = np.linspace(WATER[:,1].min(), WATER[:,1].max(), 10) z_axis = np.linspace(WATER[:,2].min(), WATER[:,2].max(), 10) x_hist, _ = np.histogram(WATER[:,0], x_axis, normed=True) y_hist, _ = np.histogram(WATER[:,1], y_axis, normed=True) z_hist, _ = np.histogram(WATER[:,2], z_axis, normed=True) remark += " xdist: " for i in x_hist: remark += "{0:6.3f}".format(i) remark += " ydist: " for i in y_hist: remark += "{0:6.3f}".format(i) remark += " zdist: " for i in z_hist: remark += "{0:6.3f}".format(i) ''' ### MI of CNT calculation for atom in CNT: Ixx += (atom[1]**2 + atom[2]**2) / N_CNT Iyy += (atom[0]**2 + atom[2]**2) / N_CNT Izz += (atom[0]**2 + atom[1]**2) / N_CNT Ixy -= (atom[0] * atom[1]) / N_CNT Ixz -= (atom[0] * atom[2]) / N_CNT Iyz -= (atom[1] * atom[2]) / N_CNT I = np.array([[Ixx, Ixy, Ixz], [Ixy, Iyy, Iyz], [Ixz, Iyz, Izz]]) # the moment of inertia tensor eigval, eigvec = np.linalg.eig( I) # eigval[0] is the minimum among the values. U = np.matrix(eigvec) Ut = U.T ### box rotation for atom in CNT: v = np.matrix([atom[0], atom[1], atom[2]]).T Uv = Ut * v atom[0] = float(Uv[2]) atom[1] = float(Uv[1]) atom[2] = float(Uv[0]) # CNT rotation for atom in WATER: v = np.matrix([atom[0], atom[1], atom[2]]).T Uv = Ut * v atom[0] = float(Uv[2]) atom[1] = float(Uv[1]) atom[2] = float(Uv[0]) # water rotation ### save coordinates to BGF after rotation myBGF2 = bgf.BgfFile() for index, i in enumerate(CNT): newatom = bgf.BgfAtom() newatom.x, newatom.y, newatom.z = i newatom.aNo = index newatom.aName = 'C' + str(index) newatom.rName = 'CNT' newatom.ffType = 'C_' newatom.chain = 'A' newatom.rNo = 1 myBGF2.addAtom(newatom) for index, i in enumerate(WATER): newatom = bgf.BgfAtom() newatom.x, newatom.y, newatom.z = i newatom.aNo = index + n_CNT newatom.aName = 'O' newatom.rName = 'WAT' newatom.ffType = 'OW' newatom.chain = 'O' newatom.rNo = 100 myBGF2.addAtom(newatom) myBGF2.REMARK.append('TIMESTEP ' + str(timestep)) myBGF2.PERIOD = "111" myBGF2.AXES = "ZYX" myBGF2.SGNAME = "P 1 1 1" myBGF2.CELLS = [-1, 1, -1, 1, -1, 1] myBGF2.CRYSTX = [boxsize[0], boxsize[1], boxsize[2], 90.0, 90.0, 90.0] myBGF2.saveBGF(temp_dir + bgf_file.split(".bgf")[0] + "." + str(timestep) + ".rot.bgf") ### CNT height _, _, min_z_CNT = CNT.min(axis=0) _, _, max_z_CNT = CNT.max(axis=0) height_CNT = max_z_CNT - min_z_CNT ### CNT radius x_CNT, y_CNT, z_CNT = np.mean(CNT, axis=0) x_std_CNT, y_std_CNT, z_std_CNT = np.std(CNT, axis=0) if x_std_CNT > 1.0 or y_std_CNT > 1.0: remark += "" ### radius of CNT l_r_CNT = [] for atom in CNT: l_r_CNT.append( math.sqrt((atom[0] - x_CNT)**2 + (atom[1] - y_CNT)**2)) r_CNT = np.mean(l_r_CNT) std_r_CNT = np.std(l_r_CNT) ### get water molecules in CNT # inside the CNT := min_z_CNT <= z <= max_z_CNT and (x - (x_diff/2))**2 + (y - (y_diff/2))**2 < r_CNT**2 # aNo_WAT_O_atoms: molecules which O atom is within CNT # we don't need to calculate H atoms. Let's consider only O atoms ##### margin = 0.0 # water molecules far from the margin will be only considered WAT_in_CNT = [] for atom in WATER: dist_sq = (atom[0] - x_CNT)**2 + (atom[1] - y_CNT)**2 if min_z_CNT + margin <= atom[2] and atom[ 2] <= max_z_CNT - margin and dist_sq < r_CNT**2: WAT_in_CNT.append(atom) n_WAT_in_CNT = len(WAT_in_CNT) ''' ### WATER bad contact check: copy-failure-proof: NEED CORRECTION WAT1 = []; WAT2 = []; for index1, i in enumerate(WAT_in_CNT): for j in WATER[index1:]: WAT1.append(i); WAT2.append(j); WAT1 = np.array(WAT1); WAT2 = np.array(WAT2) min_dists = np.min(np.dstack(((WAT1 - WAT2) % boxsize, (WAT2 - WAT1) % boxsize)), axis = 2) dists = np.sqrt(np.sum(min_dists ** 2, axis = 1)) for d in dists: if d > 0 and d < 1.0: remark += "Bad contacts" + str(d) continue; ''' d = "{0:8.3f}" e = "{0:6.1f}" output = "{0:<10}".format(timestep) + str( n_WAT_in_CNT ) + ' | ' + d.format(r_CNT) + d.format(std_r_CNT) + ' | ' + e.format( boxsize[0] ) + e.format(boxsize[1]) + e.format(boxsize[2]) + ' | ' + e.format( min_x_CNT) + e.format(max_x_CNT) + e.format(min_y_CNT) + e.format( max_y_CNT) + e.format(min_z_CNT) + e.format( max_z_CNT) + ' | ' + e.format(height_CNT) + ' | ' + str( replNum) + '\t' + str(copyNum) + '\t' + str( len(WATER)) + '\t' + str(remark) + '\n' ftemp.write(output) sys.stdout.flush() t2 = time.time() # time mark elapsed_time = t2 - t1 processed_step += 1 print('') ftemp.close() print("Numbers of water molecules are written in " + out_file + " ..Done.") return 1
def countWaterCNT(bgf_file, trj_file, step, doSave, silent=False): # init timestep = 0 l_timestep = [] line = [] n_header = 0 t1 = 0 t2 = 0 # clock myBGF = bgf.BgfFile(bgf_file) myTRJ = open(trj_file) myTRJ.seek(0) myDAT = open(bgf_file[:-4] + ".count.dat", "w") myDAT.write("Time\tmin_X\tmax_X\tHeight\tRadius\tNumber\n") # 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.") # extract aNos of CNT in the BGF file aNo_CNT = [] aNo_MtOH_C = [] for atom in myBGF.a: # Carbons in CNT if "CNT" in atom.rName: aNo_CNT.append(atom.aNo) # Carbons in MeOH if "MET" in atom.rName and "C" in atom.aName: aNo_MtOH_C.append(atom.aNo) N_CNT = len(aNo_CNT) # the number of CNT atoms # 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]) 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 * (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 ### if step is specified, then save only for that step. if step != 0: if timestep == step: pass else: continue else: pass ### 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) #myBGF.saveBGF(bgf_file[:-4] + "." + str(timestep) + ".trjupdated.bgf") ### myBGF update complete! ### aNo_MtOH_C_in_CNT = copy.deepcopy(aNo_MtOH_C) # initialize for the moment of inertia and the center of mass calculation U = 0 Ut = 0 Uv = 0 Ixx = 0 Ixy = 0 Ixz = 0 Iyx = 0 Iyy = 0 Iyz = 0 Izx = 0 Izy = 0 Izz = 0 Mx = 0 My = 0 Mz = 0 # transpose for "all atoms in BGF": move COM of CNT as origin # com of CNT Mx = 0 My = 0 Mz = 0 for atom in myBGF.a: if "CNT" in atom.rName: Mx += atom.x / N_CNT My += atom.y / N_CNT Mz += atom.z / N_CNT # move for atom in myBGF.a: atom.x -= Mx atom.y -= My atom.z -= Mz # calculate the moment of inertia (MI) and the center of mass (COM) of CNT from "myBGF" for aNo in aNo_CNT: atom = myBGF.getAtom(aNo) Ixx += (atom.y**2 + atom.z**2) / N_CNT Iyy += (atom.x**2 + atom.z**2) / N_CNT Izz += (atom.x**2 + atom.y**2) / N_CNT Ixy -= (atom.x * atom.y) / N_CNT Ixz -= (atom.x * atom.z) / N_CNT Iyz -= (atom.y * atom.z) / N_CNT # the moment of inertia tensor I = numpy.array([[Ixx, Ixy, Ixz], [Ixy, Iyy, Iyz], [Ixz, Iyz, Izz]]) # eigenvalue & eigenvector calculation eigval, eigvec = numpy.linalg.eig( I) # eigval[0] is the minimum among the values. # rearrange the U vector U = numpy.matrix(eigvec) Ut = U.T # "myBGF" rotation for atom in myBGF.a: v = numpy.matrix([atom.x, atom.y, atom.z]).T Uv = Ut * v atom.x = float(Uv[0]) atom.y = float(Uv[1]) atom.z = float(Uv[2]) """ # com of CNT Mx = 0; My = 0; Mz = 0; for atom in myBGF.a: if "CNT" in atom.rName: Mx += atom.x / N_CNT My += atom.y / N_CNT Mz += atom.z / N_CNT # transpose for "all atoms in BGF": move COM of CNT as origin for atom in myBGF.a: atom.x -= Mx atom.y -= My atom.z -= Mz """ # for CNT atoms, calculate some properties min_x_CNT = 0.0 max_x_CNT = 0.0 radius_CNT = 0.0 height_CNT = 0.0 aNo_MtOH_C_not_in_CNT = [] temp = [] min_y_CNT = 0.0 max_y_CNT = 0.0 min_z_CNT = 0.0 max_z_CNT = 0.0 CNT_orientation = "" # check the orientation of CNT for aNo in aNo_CNT: atom = myBGF.getAtom(aNo) # minimum and maximum x coord of CNT: this will be the height of CNT if atom.x < min_x_CNT: min_x_CNT = atom.x if atom.x > max_x_CNT: max_x_CNT = atom.x if atom.y < min_y_CNT: min_y_CNT = atom.y if atom.y > max_y_CNT: max_y_CNT = atom.y if atom.z < min_z_CNT: min_z_CNT = atom.z if atom.z > max_z_CNT: max_z_CNT = atom.z x_diff = max_x_CNT - min_x_CNT y_diff = max_y_CNT - min_y_CNT z_diff = max_z_CNT - min_z_CNT if x_diff > y_diff and x_diff > z_diff: # CNT is aligned along x axis height_CNT = x_diff CNT_orientation = "x" elif y_diff > x_diff and y_diff > z_diff: # CNT is aligned along y axis height_CNT = y_diff CNT_orientation = "y" elif z_diff > x_diff and z_diff > y_diff: # CNT is aligned along z axis height_CNT = z_diff CNT_orientation = "z" if CNT_orientation == "x": for aNo in aNo_CNT: atom = myBGF.getAtom(aNo) radius_CNT += math.sqrt(atom.y**2 + atom.z**2) # average radius of CNT elif CNT_orientation == "y": for aNo in aNo_CNT: atom = myBGF.getAtom(aNo) radius_CNT += math.sqrt(atom.x**2 + atom.z**2) # average radius of CNT elif CNT_orientation == "z": for aNo in aNo_CNT: atom = myBGF.getAtom(aNo) radius_CNT += math.sqrt(atom.x**2 + atom.y**2) # average radius of CNT radius_CNT = radius_CNT / N_CNT # determine whether C in MtOH is in the CNT Cylinder if doSave: myBGF2 = copy.deepcopy(myBGF) for aNo in aNo_MtOH_C: atom = myBGF.getAtom(aNo) if CNT_orientation == "x": dist = math.sqrt(atom.y**2 + atom.z**2) if atom.x > min_x_CNT and atom.x < max_x_CNT and dist < radius_CNT: # inside of the CNT pass else: # delete atoms delete_list = [] dummy = bgftools.getmolecule(myBGF, myBGF.getAtom(aNo), delete_list) for i in delete_list: aNo_MtOH_C_not_in_CNT.append(myBGF.a2i[i]) # outside of the CNT aNo_MtOH_C_in_CNT.remove(aNo) elif CNT_orientation == "y": dist = math.sqrt(atom.x**2 + atom.z**2) if atom.y > min_y_CNT and atom.y < max_y_CNT and dist < radius_CNT: pass else: # delete atoms delete_list = [] dummy = bgftools.getmolecule(myBGF, myBGF.getAtom(aNo), delete_list) for i in delete_list: aNo_MtOH_C_not_in_CNT.append(myBGF.a2i[i]) # outside of the CNT aNo_MtOH_C_in_CNT.remove(aNo) elif CNT_orientation == "z": dist = math.sqrt(atom.x**2 + atom.y**2) if atom.z > min_z_CNT and atom.z < max_z_CNT and dist < radius_CNT: pass else: # delete atoms delete_list = [] dummy = bgftools.getmolecule(myBGF, myBGF.getAtom(aNo), delete_list) for i in delete_list: aNo_MtOH_C_not_in_CNT.append(myBGF.a2i[i]) # outside of the CNT aNo_MtOH_C_in_CNT.remove(aNo) myBGF2.delAtoms(aNo_MtOH_C_not_in_CNT) myBGF2.renumber() myDAT.write(str(timestep) + "\t") myDAT.write(str("{0:<8.3f}".format(min_x_CNT))) myDAT.write(str("{0:<8.3f}".format(max_x_CNT))) myDAT.write(str("{0:<8.3f}".format(min_y_CNT))) myDAT.write(str("{0:<8.3f}".format(max_y_CNT))) myDAT.write(str("{0:<8.3f}".format(min_z_CNT))) myDAT.write(str("{0:<8.3f}".format(max_z_CNT))) myDAT.write(str("{0:<8.3f}".format(height_CNT))) myDAT.write(str("{0:<8.3f}".format(radius_CNT))) myDAT.write(str(len(aNo_MtOH_C_in_CNT)) + "\n") #myDAT.write(str(aNo_MtOH_C_in_CNT) + "\n") # write output if doSave: myBGF2.saveBGF(bgf_file[:-4] + "." + str(timestep) + ".bgf") t2 = time.time() # time mark elapsed_time = t2 - t1 print('') return 1
def getVelocity(bgf_file, trj_file, n_step, silent=False): # const PI = math.pi vdw_r_C = 1.7 # init timestep = 0 l_timestep = [] line = [] n_header = 0 t1 = 0 t2 = 0 # clock l_data = [] # stores vz l_avg_radius_CNT = [] myBGF = bgf.BgfFile(bgf_file) myTRJ = open(trj_file) myTRJ.seek(0) # how many steps to go? n_timestep = len(lt.getTrjInfo(trj_file)) if n_step == 0: n_step = n_timestep print("The trajectory contains " + str(n_timestep) + " timesteps.") print("The script will proceed for the last " + str(n_step) + " timesteps.") # extract aNos of CNT in the BGF file aNo_CNT = [] aNo_WAT_O = [] aNo_WAT_all = [] for atom in myBGF.a: # Carbons in CNT if "CNT" in atom.rName: aNo_CNT.append(atom.aNo) # Oxygen in water if "WAT" in atom.rName and "O" in atom.aName: aNo_WAT_O.append(atom.aNo) N_CNT = len(aNo_CNT) # the number of CNT atoms # check if there exists water properly if len(aNo_WAT_O) == 0: nu.die("No water molecules in the BGF file.") if len(aNo_CNT) == 0: nu.die("No CNT molecules in the BGF file.") # 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: ### Show progress t1 = time.time() remaining_time = elapsed_time * (n_step - processed_step) sys.stdout.write('\r' + "Reading timestep.. " + str(timestep) + " (Remaining time: " + "{0:4.1f}".format(remaining_time) + " seconds, " + "{0:4.1f} minutes".format(remaining_time / 60) + ")") sys.stdout.flush() if processed_step == n_step: break ### Read try: chunk = [next(dumpatom) for i in range(natoms + n_header)] except StopIteration: break timestep = int(chunk[1]) 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(' ') ### 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 = 'unwrapped' # assume that "dump 1 all custom 100 ${sname}${rtemp}K.nvt.lammps id type xu yu zu vx vy vz" in lammps input # actual coordinate coordinfo = chunk[9:] del (chunk) # modified for fast treatment for atomline in coordinfo: atomcoord = atomline.split(' ') atom = myBGF.getAtom(int(atomcoord[0])) atom.x = float(atomcoord[2]) atom.y = float(atomcoord[3]) atom.z = float(atomcoord[4]) atom.vx = float(atomcoord[5]) atom.vy = float(atomcoord[6]) atom.vz = float(atomcoord[7]) 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, True) ### myBGF update complete! ### #aNo_WAT_O_in_CNT = copy.deepcopy(aNo_WAT_O) # for CNT atoms, calculate some properties min_x_CNT = 1000.0 max_x_CNT = -1000.0 radius_CNT = 0.0 height_CNT = 0.0 temp = [] min_y_CNT = 1000.0 max_y_CNT = -1000.0 min_z_CNT = 1000.0 max_z_CNT = -1000.0 CNT_orientation = "" l_radius_CNT = [] l_x_CNT = [] l_y_CNT = [] for aNo in aNo_CNT: atom = myBGF.getAtom(aNo) # center of CNT l_x_CNT.append(atom.x) l_y_CNT.append(atom.y) # height if atom.z < min_z_CNT: min_z_CNT = atom.z if atom.z > max_z_CNT: max_z_CNT = atom.z x_CNT, a = nu.meanstdv(l_x_CNT) y_CNT, a = nu.meanstdv(l_y_CNT) z_diff = max_z_CNT - min_z_CNT # radius of CNT for aNo in aNo_CNT: atom = myBGF.getAtom(aNo) l_radius_CNT.append( math.sqrt((atom.x - x_CNT)**2 + (atom.y - y_CNT)**2)) radius_CNT, a = nu.meanstdv(l_radius_CNT) l_avg_radius_CNT.append(radius_CNT) ### get water molecules in CNT # inside the CNT := min_z_CNT <= z <= max_z_CNT and (x - (x_diff/2))**2 + (y - (y_diff/2))**2 < radius_CNT**2 # aNo_WAT_O_atoms: molecules which O atom is within CNT # we don't need to calculate H atoms. Let's consider only O atoms margin = 0.0 # water molecules far from the margin will be only considered aNo_WAT_O_in_CNT = [] for aNo in aNo_WAT_O: atom = myBGF.getAtom(aNo) dist_sq = (atom.x - x_CNT)**2 + (atom.y - y_CNT)**2 if "WAT" in atom.rName and "O" in atom.ffType and min_z_CNT + margin <= atom.z and atom.z <= max_z_CNT - margin and dist_sq < radius_CNT**2: aNo_WAT_O_in_CNT.append(aNo) else: pass ### record number of water molecules in CNT l_data.append([timestep, len(aNo_WAT_O_in_CNT), radius_CNT, z_diff]) #sys.stdout.write('Done ') #sys.stdout.flush() t2 = time.time() # time mark elapsed_time = t2 - t1 processed_step += 1 print('') ftemp = open("countWater.profile", 'w') ftemp.write(str(sys.argv)) for i in l_data: output = str(i[0]) + '\t' + str(i[1]) + '\t' + str(i[2]) + '\t' + str( i[3]) + '\n' ftemp.write(output) ftemp.close() print( "numbers of water molecules are written in countWater.profile ..Done.") return 1
def getBestShot(bgf_file, dat_file, trj_file, log_file, ff_file, keyword, saveBgfFlag, n_sample, silent=False): ### init timestep = 0 l_timestep = [] line = [] n_header = 0 yes_velocity = False yes_image = False mode = "" t1 = 0 t2 = 0 # clock myBGF = bgf.BgfFile(bgf_file) myTRJ = open(trj_file) myTRJ.seek(0) ### LAMMPS Trajectory # how many steps to go? if not silent: print("** Loading LAMMPS Trajectory **\n") if not os.path.exists(trj_file): nu.die("Please check the LAMMPS trajectory file.") l_timestep = lt.getTrjInfo(trj_file) n_timestep = len(l_timestep) if not silent: print("\nThe 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 ') # Find modes if 'vx' in keywords: if not silent: print("Found velocities information from the trajectory.") yes_velocity = True 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' if 'ix' in keywords or 'iy' in keywords or 'iz' in keywords: yes_image = True # scan trajectory to get timesteps dumpatom = get_line(trj_file) # get working path workingpath = os.getcwd() if not silent: print( '\n** Analyzing LAMMPS Log to find the timestep closest to the average "' + keyword + '" **\n') # read keywords from log file logdata = LAMMPS_getLogData.getLogData(log_file, "", keyword, silent=False) logdata2 = [] for i in logdata: if i[0] in l_timestep: logdata2.append(i) logdata2.sort(key=sortkey) # truncate if not silent: print("Only the last " + str(n_sample) + " snapshots will be used to calculate the average.") logdata2 = logdata2[-n_sample:] # average temp_avg = 0 for i in logdata2: temp_avg += float(i[1]) temp_avg /= len(logdata2) # deviation dev = [] for i in logdata2: dev.append([i[0], abs(float(i[1]) - temp_avg)]) dev.sort(key=sortkeymin) if not silent: print("Found the timestep " + str(dev[0][0]) + " has the value closest to the average " + keyword + " (value: " + str(temp_avg) + ", deviation: " + str(dev[0][1]) + ")") ### REMARK: dev[0] has the smallest deviation from the average # get trajectory myTRJ.seek(0) dumpatom = get_line(trj_file) while 1: try: chunk = [next(dumpatom) for i in range(natoms + n_header)] except StopIteration: break # only treat the designated timestep timestep = int(chunk[1]) if timestep != int(dev[0][0]): continue 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(' ') ### 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." ) # actual coordinate coordinfo = chunk[9:] info = hash() # assume that coordinfo is similar to ['id', 'type', 'xs', 'ys', 'zs', 'ix', 'iy', 'iz'] for atomline in coordinfo: atomcoord = atomline.split(' ') atomNo = int(atomcoord[0]) if mode == 'scaled': info[atomNo]['x'] = float(atomcoord[2]) * boxsize[0] info[atomNo]['y'] = float(atomcoord[3]) * boxsize[1] info[atomNo]['z'] = float(atomcoord[4]) * boxsize[2] elif mode == 'unwrapped': info[atomNo]['x'] = float(atomcoord[2]) info[atomNo]['y'] = float(atomcoord[3]) info[atomNo]['z'] = float(atomcoord[4]) elif mode == 'normal': # images if yes_image: ix_index = keywords.index('ix') iy_index = keywords.index('iy') iz_index = keywords.index('iz') info[atomNo]['x'] = (int(atomcoord[ix_index]) * boxsize[0]) + float(atomcoord[2]) info[atomNo]['y'] = (int(atomcoord[iy_index]) * boxsize[1]) + float(atomcoord[3]) info[atomNo]['z'] = (int(atomcoord[iz_index]) * boxsize[2]) + float(atomcoord[4]) else: info[atomNo]['x'] = float(atomcoord[2]) info[atomNo]['y'] = float(atomcoord[3]) info[atomNo]['z'] = float(atomcoord[4]) # velocities if yes_velocity: vx_index = keywords.index('vx') vy_index = keywords.index('vy') vz_index = keywords.index('vz') info[atomNo]['vx'] = float(atomcoord[vx_index]) info[atomNo]['vy'] = float(atomcoord[vy_index]) info[atomNo]['vz'] = float(atomcoord[vz_index]) print("") if not silent: print("** New system size: %12.6f %12.6f %12.6f" % (boxsize[0], boxsize[1], boxsize[2])) for i in range(0, 3): myBGF.CRYSTX[i] = boxsize[i] if saveBgfFlag: myBGF.REMARK.append("From the " + str(timestep) + " of " + trj_file + " in " + workingpath + " and " + bgf_file + " by " + str(sys.argv[0])) myBGF.REMARK.append( "n_samples: %d / %s average: %8.3f / stdev of the snapshot: %8.3f" % (n_sample, keyword, temp_avg, dev[0][1])) new_bgf_filename = bgf_file[:-4] + "." + str(timestep) + ".bgf" for atom in myBGF.a: atom.x = info[atom.aNo]['x'] atom.y = info[atom.aNo]['y'] atom.z = info[atom.aNo]['z'] #myBGF = bgftools.periodicMoleculeSort(myBGF, 0, [], ff_file=ff_file, silent=True) # pbc wrap myBGF.saveBGF(new_bgf_filename) if not silent: print("The snapshot is saved in BGF file " + new_bgf_filename) if dat_file: ### LAMMPS Data dat_atoms = [] if not silent: print("** Loading LAMMPS Data **\n") if not os.path.exists(dat_file): nu.die("Please check the LAMMPS data file.") f_dat_file = open(dat_file) temp = f_dat_file.read().split('\n') dat_atom_start = temp.index('Atoms') dat_atom_end = temp.index('Bonds') dat_atoms = temp[dat_atom_start + 1:dat_atom_end] f_dat_file.close() ### update LAMMPS data file ### myDAT = open(dat_file) new_dat_filename = dat_file + "." + keyword + "." + str(timestep) myNewDAT = open(new_dat_filename, 'w') linecount = 0 while 1: line = myDAT.readline() if not line: break if linecount == 0: output = line.strip( "\n") + " and updated with timestep " + str( timestep) + " in " + trj_file + "\n" linecount += 1 myNewDAT.write(output) continue if "xlo " in line: output = "\t" + " {0:>10.6f} {1:>10.6f}".format( 0.0, boxsize[0]) + " xlo xhi\n" myNewDAT.write(output) continue elif "ylo " in line: output = "\t" + " {0:>10.6f} {1:>10.6f}".format( 0.0, boxsize[1]) + " ylo yhi\n" myNewDAT.write(output) continue elif "zlo " in line: output = "\t" + " {0:>10.6f} {1:>10.6f}".format( 0.0, boxsize[2]) + " zlo zhi\n" myNewDAT.write(output) continue if not "Atoms" in line: myNewDAT.write(line) else: myNewDAT.write("Atoms\n\n") for i in dat_atoms: if len(i) == 0: continue parse = i.split() atomNo = int(parse[0]) molNo = int(parse[1]) atomTypeNo = int(parse[2]) atom = myBGF.getAtom(atomNo) if atom.aNo != atomNo or atom.rNo != molNo: nu.die( "BGF and data file mismatch. Please check both files." ) else: output = "{0:>8} {1:>8} {2:>8} {3:10.5f} {4:10.5f} {5:10.5f} {6:10.5f} {7:10.5f} {8:10.5f} {9:10.5f}".format( atom.aNo, atom.rNo, atomTypeNo, atom.charge, atom.x, atom.y, atom.z, float(parse[7]), float(parse[8]), float(parse[9])) + "\n" myNewDAT.write(output) # Write velocities if yes_velocity: myNewDAT.write("\n\nVelocities\n\n") for i in dat_atoms: if len(i) == 0: continue parse = i.split() atomNo = int(parse[0]) output = "{0:>8} {1:12.8f} {2:12.8f} {3:12.8f}\n".format( atomNo, info[atomNo]['vx'], info[atomNo]['vy'], info[atomNo]['vz']) myNewDAT.write(output) # consume for i in range(len(dat_atoms)): line = myDAT.readline() myNewDAT.write("\n") if not silent: print("The snapshot is saved in LAMMPS data file " + new_dat_filename) print('') return 1
dat_file = value elif option in ('-t', '--trj'): trj_file = value elif option in ('-l', '--log'): log_file = value elif option in ('-f', '--ff'): ff_file = value elif option in ('-k', '--keyword'): keyword = value elif option in ('-s', '--save'): saveBgfFlag = True elif option in ('-n', '--sample'): n_sample = int(value) elif option == NULL: print(usage) sys.exit(0) ### default options if not bgf_file: nu.die("No BGF file specified.") if not trj_file: nu.die("No LAMMPS trajectory file specified.") if not log_file: nu.die("No LAMMPS log file specified.") if not keyword: keyword = "Volume" # main call getBestShot(bgf_file, dat_file, trj_file, log_file, ff_file, keyword, saveBgfFlag, n_sample)
elif option in ('-d', '--direction'): direction = value elif option in ('-i', '--interval'): interval = float(value) elif option in ('-a', '--average'): avg_timestep = int(value) elif option == NULL: print(usage) sys.exit(0) direction = string.split(direction) if len(direction) == 1: if "x" in direction or "y" in direction or "z" in direction: pass else: nu.die("Please specify the direction to see the density profile.") else: nu.die("Please specify the correct direction.") if out_file == "": out_file = bgf_file[:-4] + ".densityProfile" # main call densityProfile(bgf_file, trj_file, out_file, interval, avg_timestep, direction=direction)
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) chunks = dict() for t in tqdm.tqdm(timesteps, ncols=120, desc="Updating coordinates"): chunk = [next(dump) for i in range(N_BUFFER)] chunks[t] = chunk ''' single processor usage for t in tqdm.tqdm(chunks, ncols=120):
def densityProfile(bgf_file, trj_file, out_file, interval, avg_timestep, direction='z', ff_file='', 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 vector = [0, 0, 1] # the axis of interest. in the acetone-water case, z direction. atominfo = bgftools.atom_mass # atom data extracted from ff_file result = dict() axis = 0 # 1: x-axis, 2: y-axis, 3: z-axis ### direction if "x" in direction: axis = 0 elif "y" in direction: axis = 1 elif "z" in direction: axis = 2 else: nu.die("Error on reading direction.") ### open files myBGF = bgf.BgfFile(bgf_file) myTRJ = open(trj_file) myTRJ.seek(0) f_out_file = open(out_file + ".dat", 'w') f_avg_out_file = open(out_file + ".average.dat", 'w') f_pickle = open(out_file + ".pickle", 'w') f_avg_pickle = open(out_file + ".average.pickle", 'w') ### read residues from bgf_file:: residue is replaced by ffTypes 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.ffType) residue.add(rname) output = "" for i in residue: output += i + " " if not silent: print("Found " + str(len(residue)) + " residues in BGF file: " + str(output)) residue = list(residue) residue.append('TOTAL') for index, i in enumerate(residue): dict_residue[i] = index n_residue = len(residue) # number of residues (including total) if ff_file: bgftools.update_mass(ff_file) ### read trajectory file # how many steps to go? #l_timestep = lt.getTrjInfo(trj_file) #mytrj = trj.lammpstrj(trj_file) mytrj = Trj(trj_file) l_timestep = mytrj.load() n_timestep = len(l_timestep) if not silent: print("\nThe trajectory contains %d timesteps." % n_timestep) # 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(' ') ### 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, myBGF.CRYSTX, silent=True) ### DONE for updating trj on BGF file ### ### Do whatever I want: density profile ### upper and lower bound min = -3.0 max = boxsize[axis] + 3.0 ### make a bin bin = np.arange(math.floor(min), math.ceil(max), interval) ### for every atoms, get atom coordinate and its type positions = [] # atom positions. [ res1, res2, ..., total ] masses = [] # used for a weight for histogram. [ res1, res2, ..., total ] hist = [] bin_edges = [] for i in range(n_residue): positions.append([]) masses.append([]) hist.append([]) bin_edges.append([]) for atom in myBGF.a: coord = [atom.x, atom.y, atom.z] # total positions[-1].append(coord[axis]) masses[-1].append(atominfo[atom.ffType]) # residues positions[dict_residue[atom.ffType.strip()]].append(coord[axis]) masses[dict_residue[atom.ffType.strip()]].append( atominfo[atom.ffType]) ### calculate volume area = 0 if axis == 0: area = boxsize[1] * boxsize[2] elif axis == 1: area = boxsize[0] * boxsize[2] elif axis == 2: area = boxsize[0] * boxsize[1] vol = area * interval ### histogram for i in range(n_residue): hist[i], bin_edges[i] = np.histogram(positions[i], bins=bin, weights=masses[i]) hist[i] = hist[i] / 6.022 / vol * 10 # density ### store temp = dict() for i in range(n_residue): temp2 = dict() temp2['HIST'] = hist[i] temp2['BIN_EDGES'] = bin_edges[i] temp[residue[i]] = temp2 result[timestep] = temp ### end of loop: check elapsed time t2 = time.time() # time mark elapsed_time = t2 - t1 ### calculate average values if not silent: print("\nAveraging the last %d timesteps.." % avg_timestep) avg_timesteps = l_timestep[-avg_timestep:] avg_hist = [] avg_bin_edges = [] for i in range(n_residue): avg_hist.append( np.zeros(len(result[l_timestep[-avg_timestep]]['TOTAL']['HIST']))) #avg_bin_edges.append(np.zeros(len(result[-avg_timestep]['TOTAL']['BIN_EDGES']))); for t in avg_timesteps: for r in result[t]: avg_hist[dict_residue[r]] += result[t][r]['HIST'] for i in range(n_residue): avg_hist[i] /= len(avg_timesteps) # normalize temp_avg = dict() # residue --- HIST, BIN_EDGES for i in residue: temp2 = dict() temp2['HIST'] = avg_hist[dict_residue[i]] temp2['BIN_EDGES'] = bin_edges[0] temp_avg[i] = temp2 ### write up a average data to file output = str(avg_timestep) + "\n" for r in temp_avg: output += str(r) + "\n" for index, i in enumerate(temp_avg[r]['HIST']): output += str( temp_avg[r]['BIN_EDGES'][index]) + "\t" + str(i) + "\n" output += "\n" f_avg_out_file.write(output) ### write up a whole data to file output = "" tkey = result.keys() tkey.sort() for t in tkey: output += str(t) + "\n" rkey = result[t].keys() rkey.sort() for r in rkey: output += str(r) + "\n" for index, i in enumerate(result[t][r]['HIST']): output += str( result[t][r]['BIN_EDGES'][index]) + "\t" + str(i) + "\n" output += "\n" output += "\n" f_out_file.write(output) ### write up a pickle object if not silent: print("Writing pickle object..") pickle.dump(result, f_pickle) f_pickle.close() pickle.dump(temp, f_avg_pickle) f_avg_pickle.close() ### return print('') return 1
def getSlipLength(bgf_file, trj_file, ff_file, interval, n_step, n_avg_step, silent=False): """ This calculates the profile of averaged velocity according to r. NOTE: This is different from averaged velocity profile according to r. """ # const PI = math.pi vdw_r_C = 1.7 # init timestep = 0 l_timestep = [] line = [] n_header = 0 output = "" t1 = 0 t2 = 0 # clock myBGF = bgf.BgfFile(bgf_file) myTRJ = open(trj_file) myTRJ.seek(0) myPkl = open( trj_file + ".profile.r_ave_vel-s" + str(n_step) + "k" + str(n_skip) + ".pickle", 'w') #f_dump = open(trj_file + ".profile.r_ave_vel.dump", 'w') #dump = ""; # how many steps to go? n_timestep = len(lt.getTrjInfo(trj_file, silent=False)) if n_step == 0: n_step = n_timestep if not silent: print("The trajectory contains " + str(n_timestep) + " timesteps.") # extract aNos of CNT in the BGF file aNo_CNT = [] aNo_WAT_O = [] aNo_WAT_all = [] for atom in myBGF.a: # Carbons in CNT if "CNT" in atom.rName: aNo_CNT.append(atom.aNo) # Oxygen in water if "WAT" in atom.rName and "O" in atom.aName: aNo_WAT_O.append(atom.aNo) N_CNT = len(aNo_CNT) # the number of CNT atoms # check if there exists water properly if len(aNo_WAT_O) == 0: nu.die("No water molecules in the BGF file.") if len(aNo_CNT) == 0: nu.die("No CNT molecules in the BGF file.") # 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 # calculate radius_CNT avg_radius_CNT = 0.0 x_CNT = 0.0 y_CNT = 0.0 if not silent: print( "Calculating the average radius of CNT throughout the averaging steps" ) while 1: ### Show progress t1 = time.time() remaining_time = elapsed_time * (n_step - processed_step) ### Read try: chunk = [next(dumpatom) for i in range(natoms + n_header)] except StopIteration: break # skip if necessary if processed_step <= n_skip: processed_step += 1 continue 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(' ') sys.stdout.write('\r' + "Fetched timestep: " + str(timestep) + " (Remaining time: " + "{0:4.1f}".format(remaining_time) + " seconds, " + "{0:4.1f} minutes".format(remaining_time / 60) + ")") sys.stdout.flush() ### update myBGF with trajectory information ### natom_bgf = len(myBGF.a) # number of atoms in BGF file mode = 'unwrapped' # assume that "dump 1 all custom 100 ${sname}${rtemp}K.nvt.lammps id type xu yu zu vx vy vz" in lammps input # actual coordinate coordinfo = chunk[9:] # modified for fast treatment for atomline in coordinfo: atomcoord = atomline.split(' ') atom = myBGF.getAtom(int(atomcoord[0])) atom.x = float(atomcoord[2]) atom.y = float(atomcoord[3]) atom.z = float(atomcoord[4]) try: for i in range(0, 3): myBGF.CRYSTX[i] = boxsize[i] except: pass # apply periodic condition #myBGF = bgftools.periodicMoleculeSort(myBGF, 0, True) ### myBGF update complete! ### # for CNT atoms, calculate some properties min_x_CNT = 0.0 max_x_CNT = 0.0 radius_CNT = 0.0 height_CNT = 0.0 aNo_WAT_O_not_in_CNT = [] temp = [] min_y_CNT = 0.0 max_y_CNT = 0.0 min_z_CNT = 0.0 max_z_CNT = 0.0 CNT_orientation = "" l_radius_CNT = [] l_x_CNT = [] l_y_CNT = [] for aNo in aNo_CNT: atom = myBGF.getAtom(aNo) # center of CNT l_x_CNT.append(atom.x) l_y_CNT.append(atom.y) # height if atom.z < min_z_CNT: min_z_CNT = atom.z if atom.z > max_z_CNT: max_z_CNT = atom.z x_CNT, a = nu.meanstdv(l_x_CNT) y_CNT, a = nu.meanstdv(l_y_CNT) z_diff = max_z_CNT - min_z_CNT # radius of CNT for aNo in aNo_CNT: atom = myBGF.getAtom(aNo) l_radius_CNT.append( math.sqrt((atom.x - x_CNT)**2 + (atom.y - y_CNT)**2)) radius_CNT, a = nu.meanstdv(l_radius_CNT) l_avg_radius_CNT.append(radius_CNT) if processed_step > 3: break avg_radius_CNT, s = nu.meanstdv(l_avg_radius_CNT) bins = np.arange(0.0, math.ceil(radius_CNT), interval) l_radial_vz_profile = np.zeros(len(bins) - 1) if not silent: print("\nAveraged CNT radius: " + str(avg_radius_CNT) + " A") if not silent: print("CNT center: " + str([x_CNT, y_CNT])) # calculate properties myTRJ.close() myTRJ = open(trj_file) myTRJ.seek(0) dumpatom = get_line(trj_file) processed_step = 0 r = [] vz = [] # data container while 1: data = dict() # stores [r vz] for a timestep ### Show progress t1 = time.time() remaining_time = elapsed_time * (n_step - processed_step) ### Read try: chunk = [next(dumpatom) for i in range(natoms + n_header)] except StopIteration: break if processed_step <= n_skip: processed_step += 1 continue 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(' ') sys.stdout.write('\r' + "Fetched timestep: " + str(timestep) + " (Remaining time: " + "{0:4.1f}".format(remaining_time) + " seconds, " + "{0:4.1f} minutes".format(remaining_time / 60) + ")") sys.stdout.flush() ### 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 = 'unwrapped' # assume that "dump 1 all custom 100 ${sname}${rtemp}K.nvt.lammps id type xu yu zu vx vy vz" in lammps input # actual coordinate coordinfo = chunk[9:] # modified for fast treatment for atomline in coordinfo: atomcoord = atomline.split(' ') atom = myBGF.getAtom(int(atomcoord[0])) atom.x = float(atomcoord[2]) atom.y = float(atomcoord[3]) atom.z = float(atomcoord[4]) atom.vx = float(atomcoord[5]) atom.vy = float(atomcoord[6]) atom.vz = float(atomcoord[7]) 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, True) ### myBGF update complete! ### # calculate z-directional velocity of water molecules wrt r vcm = sum vi mi / sum mi atom = myBGF.getAtom(aNo_WAT_O[0]) mass_O = bgftools.getMass(myBGF, [aNo_WAT_O[0]], ff_file) atom = myBGF.getAtom(atom.CONECT[0]) mass_H = bgftools.getMass(myBGF, [atom.aNo], ff_file) mass_H2O = mass_O + 2 * mass_H # H2O mass for ano in aNo_WAT_O: atom = myBGF.getAtom(ano) # oxygen # com & velocity calculation cmx = atom.x * mass_O cmy = atom.y * mass_O vcmz = atom.vz * mass_O for ano2 in atom.CONECT: atom2 = myBGF.getAtom(ano2) cmx += atom2.x * mass_H cmy += atom2.y * mass_H vcmz += atom2.vz * mass_H cmx /= mass_H2O cmy /= mass_H2O vcmz /= mass_H2O dist = math.sqrt((x_CNT - cmx)**2 + (y_CNT - cmy)**2) r.append(dist) vz.append(vcmz * 10**5) # LAMMPS real unit conversion for velocity # timestep mark for starting average if l_avg_count == []: n_avg_count_step = timestep l_avg_count.append(timestep) # if the time has come.. average! if len(l_avg_count) == n_avg_step or processed_step == n_timestep - 1: if not silent: print(" Averaging invoked at timestep " + str(timestep) + " (" + str(len(l_avg_count)) + " points)") # binning vz = np.array(vz) sum_vz = np.ma.array(np.histogram(r, bins, weights=vz)[0]) sum_vz2 = np.ma.array(np.histogram(r, bins, weights=vz * vz)[0]) n_vz = np.ma.array(np.histogram(r, bins)[0]) #mask_n = ma.masked_values(n_vz, 0) mean = sum_vz / n_vz std = np.sqrt(sum_vz2 / n_vz - mean * mean) mean = np.ma.fix_invalid(mean, fill_value=0.0).data std = np.ma.fix_invalid(std, fill_value=0.0).data n_vz = np.ma.fix_invalid(n_vz, fill_value=0).data if len(mean) != len(bins) - 1 or len(std) != len(bins) - 1: nu.die("on numpy masked_array calculation!") l_result.append([l_avg_count, bins, n_vz, mean, std]) # reset r = [] vz = [] l_radial_vz_profile = np.zeros(len(bins) - 1) l_avg_count = [] t2 = time.time() # time mark elapsed_time = t2 - t1 processed_step += 1 #f_dump.write(dump) pkl.dump(l_result, myPkl) print('') return 1
def countWaterCNT(bgf_file, trj_file, d_crit=3.5, selection='', nsample=0, silent=False): ### init # constants deg_109p47 = math.radians(109.47) # variables timestep = 0 l_timestep = [] line = [] n_header = 0 avg_angles = [] avg_diheds = [] bin = np.arange(0.0, 181.0, 1.0) t1 = 0 t2 = 0 # clock myBGF = bgf.BgfFile(bgf_file) myTRJ = open(trj_file) myTRJ.seek(0) myDAT = open(bgf_file[:-4] + ".AOP.dat", "w") myDAT.write("#timestep\tAOP\tF4\n") # how many steps to go? #mytrj = lt.lammpstrj(trj_file) mytrj = Trj(trj_file) l_timestep = mytrj.load() n_timestep = len(l_timestep) l_timestep.sort() requested_timesteps = l_timestep[-nsample:] print( "Using neighboring water distance criteria %4.1f A (should be consistent with the coordination number)" % d_crit) 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: ### Show progress t1 = time.time() remaining_time = elapsed_time * (len(requested_timesteps) - processed_step) sys.stdout.write('\r' + "Reading timestep.. " + str(timestep) + " (Remaining time: " + "{0:4.1f}".format(remaining_time) + " seconds, " + "{0:4.1f} minutes".format(remaining_time / 60) + ")") sys.stdout.flush() ### Read try: chunk = [next(dumpatom) for i in range(natoms + n_header)] except StopIteration: break timestep = int(chunk[1]) 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 not timestep in requested_timesteps: continue ### 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 # apply periodic condition myBGF = bgftools.periodicMoleculeSort(myBGF, myBGF.CRYSTX, silent=True) ### myBGF update complete! ### # get water OW O = [] anos_O = [] for atom in myBGF.a: if selection: if "O" in atom.ffType and eval(selection): O.append(atom) anos_O.append(atom.aNo) else: if "O" in atom.ffType: O.append(atom) anos_O.append(atom.aNo) if not len(O): nu.die("There are no O atoms which satisfies %s!" % selection) ### calculate AOP and F4 sys.stdout.write('AOP..... ') sys.stdout.flush() coords = [] anos = [] for atom in O: coords.append([atom.x, atom.y, atom.z]) anos.append(atom.aNo) pbc = np.array(myBGF.CRYSTX[:3]) coords = np.array(coords) tree = pkdtree.PeriodicKDTree( pbc, coords) # KDtree for distance calculation # analyze local water structures for a timestep n_neighbors = [] angles = [] diheds = [] for atom in O: # local variables # find neighbors neighbors = [] # list of O atoms near centerO centerO = np.array([atom.x, atom.y, atom.z]) d, ndx = tree.query(centerO, k=6) index = np.where((d >= 1e-4) & (d <= d_crit)) # discard self for i in ndx[index]: neighbors.append(myBGF.getAtom(anos[i])) # calculate O1-O-O2 angle for i, j in itertools.combinations(neighbors, 2): if not "O" in i.ffType or not "O" in j.ffType: nu.die("Wrong atom found.") x = [i.x, i.y, i.z] y = [j.x, j.y, j.z] pbc_dist = nu.pbc_dist(x, y, pbc) dist = nu.dist(x, y) if abs(pbc_dist - dist) > 0.1: continue # discard atoms over pbc boundaries # angle angle = nu.angle(x, centerO, y, radians=False) angles.append(angle) n_neighbors.append( len(neighbors)) # number of neighboring water molecules # calculate dihedral for i in neighbors: # find aNos of H located farthest among all combinations hO_anos = atom.CONECT hi_anos = i.CONECT max_dist_pair = [] max_dist = 0.0 for k, l in itertools.product(hO_anos, hi_anos): h1 = myBGF.getAtom(k) # H atom connected with atom h2 = myBGF.getAtom(l) # H atom connected with i dist = bgf.distance(h1, h2) if dist > max_dist: max_dist = dist max_dist_pair = [ h1, h2 ] # now we have two H atoms in maximum distance connected with atom and i # dihedral angle phi = bgf.dihedral(max_dist_pair[0], atom, i, max_dist_pair[1], radians=False) diheds.append(phi) hist_angle, _ = np.histogram(angles, bins=bin, normed=True) hist_dihed, _ = np.histogram(diheds, bins=bin, normed=True) avg_angles.append(hist_angle) avg_diheds.append(hist_dihed) sys.stdout.write( 'Done ') sys.stdout.flush() # write output processed_step += 1 t2 = time.time() # time mark elapsed_time = t2 - t1 avg_angles = np.mean(np.array(avg_angles), axis=0) avg_diheds = np.mean(np.array(avg_diheds), axis=0) #print(avg_diheds) myDAT.write("#angles population\n") for index, i in enumerate(avg_angles): myDAT.write("%8.2f %8.5f\n" % (_[index], avg_angles[index])) myDAT.write("\n\n") myDAT.write("#diheds population\n") for index, i in enumerate(avg_diheds): myDAT.write("%8.2f %8.5f\n" % (_[index], avg_diheds[index])) myDAT.close() print('') return 1