Пример #1
0
def update_mass(ff_file, silent=True):
    for i in ff_file:
        # no need to read the ff_file again.
        if i in loaded_ff:
            continue

        # read
        if not silent: print("Updating atom mass with %s" % i)
        FF = dreiding.loadFF(i)
        atominfo = dreiding.loadAtomTypes(FF)
        for key in atominfo.keys():
            atom_mass[key] = atominfo[key]['MASS']
        loaded_ff.append(i)
Пример #2
0
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
Пример #3
0
            bgfFile = value
        elif option in ('-f', '--forcefield'):
            ffFile = value
        elif option in ('-s', '--suffix'):
            suffix = value
        elif option in (''):
            print usage
            sys.exit(0)

    ##### Initialize
    output = ""
    if suffix == "": suffix = "lammps"

    ##### Open a new data file
    myBGF = BgfFile(bgfFile)
    forcefield = dreiding.loadFF(ffFile)

    ##### Description of the file
    output += "Created by lammps.py\n"
    output += "\n"

    ##### the number of atoms
    output += "{0:8d}".format(len(myBGF.a)) + " atoms" + "\n"

    ##### the number of bonds
    output += "{0:8d}".format(len(getAtomBondsID(myBGF))) + " bonds" + "\n"

    ##### the number of angles
    output += "{0:8d}".format(len(
        getAtomAnglePairsID(myBGF))) + " angles" + "\n"
Пример #4
0
def dipole(bgf_file, trj_file, ff_file, out_file, avg_timestep, silent=False):

    ### init
    timestep = 0
    l_timestep = []
    line = []
    n_header = 0
    t1 = 0
    t2 = 0
    # clock
    vector = [0, 0, 1]
    # the axis of interest. in the acetone-water case, z direction.
    atominfo = dict()
    # atom data extracted from ff_file
    result = dict()
    axis = 2
    # for orientational distribution of dipole moments. 1: x-axis, 2: y-axis, 3: z-axis

    ### unit conversion for debye
    elementary_q = 1.602176487e-19  # elementary charge in C
    debye_conv = 3.33564e-30  # 1 Debye in C*m
    k = elementary_q * 1e-10 / debye_conv

    ### open files
    myBGF = bgf.BgfFile(bgf_file)
    myTRJ = open(trj_file)
    myTRJ.seek(0)
    myOUT = open(out_file + ".dat", 'w')
    #myOUT2 = open(out_file + ".angle.dat", 'w')
    myRESULT = open(out_file + ".pickle", 'w')
    myRESULT2 = open(out_file + ".histo.pickle", 'w')

    ### read residues from bgf_file
    residueNames = set()
    # kind of residues in BGF file
    residueNumbers = set()
    dict_residue = dict()
    # stores residue numbers per each residue. RES1: [1, 2, ..], RES2: [6, 7, ..]
    for i in myBGF.a:
        rname = string.strip(i.rName)
        residueNames.add(rname)

        rno = i.rNo
        residueNumbers.add(rno)

    temp = ""
    for i in residueNames:
        temp += i + " "
        dict_residue[i] = []

    if not silent:
        print("Found " + str(len(residueNames)) + " residues in BGF file: " +
              str(temp))

    ### bookkeep residue numbers for each residue
    molecules = bgftools.getMoleculeList(myBGF)
    for molecule in molecules:
        # get an atom
        atom = myBGF.getAtom(molecule[0])
        atomresname = string.strip(atom.rName)
        atomresno = atom.rNo

        # check if all molecule has same residue name and numbers
        for ano in molecule:
            atom2 = myBGF.getAtom(ano)
            temp_rno = atom2.rNo
            temp_rname = string.strip(atom2.rName)
            if temp_rno != atomresno or temp_rname != atomresname:
                nu.die(
                    "Different residue name or residue number in a same molecule: "
                    + str(atom2.aNo))

        # record resid for resnames
        dict_residue[atomresname].append(atom.rNo)

    ### read mass from ff_file
    try:
        parse = ff_file.split(" ")
    except:
        nu.die(
            "Error occurred when reading the force field file.. Check your " +
            str(ff_file))
    else:
        if not silent:
            print("Found " + str(len(parse)) + " Cerius2 Force Fields.")

    for i in parse:
        FF = dreiding.loadFF(i)
        temp_atominfo = dreiding.loadAtomTypes(FF)
        atominfo.update(temp_atominfo)

    ### read trajectory file
    # how many steps to go?
    wc_trj_file = popen("grep -A 1 TIMESTEP " + trj_file).read()
    wc_trj_file = wc_trj_file.split()
    l_timestep = []

    for i in wc_trj_file:
        if "ITEM" in i or "TIME" in i or "--" in i:
            pass
        else:
            l_timestep.append(i)

    l_timestep = [int(i) for i in l_timestep]
    l_timestep.sort()

    n_timestep = len(l_timestep)
    if not silent:
        print("The trajectory contains " + str(n_timestep) + " timesteps.")

    l_requested_timesteps = l_timestep[-avg_timestep:]  # requested timesteps
    if not silent:
        print("Only requested the last " + str(avg_timestep) + " timesteps. ")

    # Find header of the trajectory file
    while 1:
        templine = myTRJ.readline()
        line.append(templine.strip('\n').strip('ITEM: '))
        n_header += 1
        if "ITEM: ATOMS" in templine:
            break

    # INITIAL trajectory information
    timestep = int(line[1])
    natoms = int(line[3])
    boxsize = [
        line[5].split(' ')[0], line[5].split(' ')[1], line[6].split(' ')[0],
        line[6].split(' ')[1], line[7].split(' ')[0], line[7].split(' ')[1]
    ]
    boxsize = [float(i) for i in boxsize]
    keywords = line[8].strip('ATOMS ')

    # for every shot in the trajectory file update BGF and manipulate
    dumpatom = get_line(trj_file)
    processed_step = 0

    t1 = t2 = 0
    elapsed_time = 0

    while 1:
        try:
            chunk = [next(dumpatom) for i in range(natoms + n_header)]
        except StopIteration:
            break

        timestep = int(chunk[1])

        if not timestep in l_requested_timesteps:
            continue

        #l_timestep.append(timestep)
        natoms = int(chunk[3])
        boxsize = [
            chunk[5].split(' ')[0], chunk[5].split(' ')[1],
            chunk[6].split(' ')[0], chunk[6].split(' ')[1],
            chunk[7].split(' ')[0], chunk[7].split(' ')[1]
        ]
        boxsize = [float(i) for i in boxsize]
        boxsize = [(boxsize[1] - boxsize[0]), (boxsize[3] - boxsize[2]),
                   (boxsize[5] - boxsize[4])]
        keywords = chunk[8].split('ATOMS ')[1].strip('\n').split(' ')

        ### Show progress
        t1 = time.time()
        remaining_time = elapsed_time * (len(l_requested_timesteps) -
                                         processed_step)
        sys.stdout.write('\r' + "Reading timestep.. " + str(timestep) +
                         " (Elapsed time for the previous step: " +
                         "{0:4.1f}".format(elapsed_time) +
                         " seconds, Remaining time: " +
                         "{0:4.1f}".format(remaining_time) + " seconds = " +
                         "{0:4.1f} minutes".format(remaining_time / 60) + ")")
        sys.stdout.flush()

        processed_step += 1

        ### update myBGF with trajectory information ###
        natom_bgf = len(myBGF.a)  # number of atoms in BGF file

        if not natom_bgf == natoms:
            nu.die(
                "Number of atoms in trajectory file does not match with BGF file."
            )

        mode = ""
        if 'xs' in keywords or 'ys' in keywords or 'zs' in keywords:
            mode = 'scaled'
        elif 'x' in keywords or 'y' in keywords or 'z' in keywords:
            mode = 'normal'
        elif 'xu' in keywords or 'yu' in keywords or 'zu' in keywords:
            mode = 'unwrapped'

        # actual coordinate
        coordinfo = chunk[9:]

        # assume that coordinfo is similar to ['id', 'type', 'xs', 'ys', 'zs', 'ix', 'iy', 'iz']
        for atomline in coordinfo:
            atomcoord = atomline.split(' ')
            atom = myBGF.getAtom(int(atomcoord[0]))

            if mode == 'scaled':
                atom.x = float(atomcoord[2]) * boxsize[0]
                atom.y = float(atomcoord[3]) * boxsize[1]
                atom.z = float(atomcoord[4]) * boxsize[2]

            elif mode == 'unwrapped':
                atom.x = float(atomcoord[2])
                atom.y = float(atomcoord[3])
                atom.z = float(atomcoord[4])

            elif mode == 'normal':
                try:
                    ix_index = keywords.index('ix')
                    iy_index = keywords.index('iy')
                    iz_index = keywords.index('iz')
                except ValueError:
                    nu.warn(
                        "No image information no the trajectory file. Will be treated as unwrapped."
                    )
                    atom.x = float(atomcoord[2])
                    atom.y = float(atomcoord[3])
                    atom.z = float(atomcoord[4])
                else:
                    atom.x = (int(atomcoord[ix_index]) * boxsize[0]) + float(
                        atomcoord[2])
                    atom.y = (int(atomcoord[iy_index]) * boxsize[1]) + float(
                        atomcoord[3])
                    atom.z = (int(atomcoord[iz_index]) * boxsize[2]) + float(
                        atomcoord[4])

            try:
                for i in range(0, 3):
                    myBGF.CRYSTX[i] = boxsize[i]
            except:
                pass
                #nu.warn("Crystal information error: is this file not periodic?")

        # apply periodic condition
        myBGF = bgftools.periodicMoleculeSort(myBGF, 0)

        ### DONE for updating trj on BGF file ###

        ### Now Dipole Moment Calculation
        # list of all molecules in BGF
        dipole_moments = dict()
        abs_dipole_moments = dict()
        angles = dict()
        temp_dict = dict()
        output_dipole = str(timestep) + "\t"
        output_abs_dipole = str(timestep) + "\t"
        output_angle = str(timestep) + "\t"

        ### find bin for orientational distribution of dipole moment
        min = 100000
        max = -100000
        for atom in myBGF.a:
            coord = [atom.x, atom.y, atom.z]
            if coord[axis] < min:
                min = coord[axis]
            if coord[axis] > max:
                max = coord[axis]

        if boxsize[axis] > max:
            max = boxsize[axis]
        if 0 < min:
            min = 0

        bins = np.arange(math.floor(min), math.ceil(max), 1.0)
        binned_rNo = dict()
        for r in residueNames:
            binned_rNo[r] = [[] for b in bins]
            # space for binned residue numbers (= molecules)
        binned_mu = copy.deepcopy(binned_rNo)

        ### For every molecule
        for molecule in molecules:
            n_atom = len(molecule)  # number of atoms in the molecule
            residue_no = myBGF.getAtom(molecule[0]).rNo
            # residue number of the molecule
            residue_name = myBGF.getAtom(molecule[0]).rName
            # residue name of the molecule
            m = bgftools.getMass(myBGF, molecule, ff_file)
            # molecule mass
            cm = [0, 0, 0]
            # center of mass
            mu = [0, 0, 0]
            # dipole moment
            coord = [0, 0, 0]
            # atom x, y, z

            for aNo in molecule:
                atom = myBGF.getAtom(aNo)
                coord = [atom.x, atom.y, atom.z]

                # error if residue numbers are different
                if atom.rNo != residue_no:
                    nu.die(
                        "Residue numbers in a same molecule are not consistent. Please check your BGF file."
                    )

                # error if mass is unreadable
                ffType = string.strip(atom.ffType)
                try:
                    aMass = atominfo[ffType]['MASS']
                except:
                    nu.die("Cannot read the atom type " + str(atom.ffType) +
                           " in the data file.")

                # calculate CM
                for index, i in enumerate(coord):
                    cm[index] += i * aMass

            cm = [i / m for i in cm]
            # center of mass
            #print(str(residue_no) + '\t' + str(cm))

            # REMARK: it seems to be okay without this process.
            """
			# translate the molecule to CM
			for aNo in molecule:
				atom = myBGF.getAtom(aNo)
				atom.x -= cm[0]
				atom.y -= cm[1]
				atom.z -= cm[2]
			"""

            # calculate dipole moment sum(qi * di)
            mu_i = []
            for aNo in molecule:
                atom = myBGF.getAtom(aNo)
                coord = [atom.x, atom.y, atom.z]
                mu_i.append([i * atom.charge * k for i in coord])

            # sum up
            mu = [0, 0, 0]
            for i in mu_i:
                mu[0] += i[0]
                mu[1] += i[1]
                mu[2] += i[2]

            # for acetone case
            #len_mu = math.sqrt(dot(mu, mu))
            #len_vector = math.sqrt(dot(vector, vector))
            len_mu = math.sqrt(dot(mu, mu))
            len_vector = 1.0

            #angle = dot(mu, vector) / ( len_mu * len_vector )
            angle = mu[2] / (len_mu * len_vector)  # for ACETONE case

            # results
            dipole_moments[residue_no] = mu
            abs_dipole_moments[residue_no] = len_mu
            angles[residue_no] = angle

            ### Orientational distribution of dipole moments
            # binning according to molecule's CM and store to binned_rNo
            for index, bin in enumerate(bins):
                try:
                    if bin < cm[axis] and bins[index + 1] > cm[axis]:
                        binned_rNo[residue_name][index].append(residue_no)
                except:
                    continue
            # binning is perfect so far!

        residueNumbers = list(residueNumbers)
        residueNames = list(residueNames)
        residueNumbers.sort()

        temp_dict = dict()
        temp_dict2 = dict()
        temp_dict2['MU'] = dipole_moments
        temp_dict2['ABSMU'] = abs_dipole_moments
        temp_dict2['ANGLES'] = angles
        temp_dict['TOTAL'] = temp_dict2

        ### paperworks per residue
        for resname in residueNames:
            temp_dict2 = dict()
            res_dipole_moments = dict()
            res_abs_dipole_moments = dict()
            res_angles = dict()

            # load residue numbers per residue type
            resnumbers = dict_residue[resname]
            for rno in resnumbers:
                res_dipole_moments[rno] = dipole_moments[rno]
                res_abs_dipole_moments[rno] = abs_dipole_moments[rno]
                res_angles[rno] = angles[rno]

            temp_dict2['MU'] = res_dipole_moments
            temp_dict2['ABSMU'] = res_abs_dipole_moments
            temp_dict2['ANGLES'] = res_angles
            temp_dict2['BIN'] = bins

            # for analyze
            #temp_dict2['RNO_DISTR'] = binned_rNo[resname]
            temp_dict2['DISTR_ANGLES'] = binned_mu[resname]
            temp_dict2['DISTR_ABSMU'] = binned_mu[resname]

            # write dipole moments
            for index, item in enumerate(binned_rNo[resname]):
                if len(item) == 0:
                    continue
                for i in item:
                    temp_dict2['DISTR_ANGLES'][index].append(
                        temp_dict2['ANGLES'][i])
                    #temp_dict2['DISTR_ABSMU'][index].append(temp_dict2['ABSMU'][i])

            temp_dict[resname] = temp_dict2

        # result: timestep - residue - MU, ANGLES, NATOMS
        result[timestep] = temp_dict

        t2 = time.time()  # time mark
        elapsed_time = t2 - t1

    ### Averaging orientational distribution of dipole moments over timesteps
    #del temp_dict1
    del temp_dict2
    temp_dict1 = dict()
    # angles with keys: bin
    temp_dict2 = dict()
    # |mu| with keys: bin

    # append
    for r in residueNames:
        temp_dict1[r] = dict()
        temp_dict2[r] = dict()

        for t in l_requested_timesteps:
            for index, b in enumerate(result[t][r]['BIN']):
                if not temp_dict1[r].has_key(b):
                    temp_dict1[r][b] = []
                if not temp_dict2[r].has_key(b):
                    temp_dict2[r][b] = []

                # append averaged values
                avg, std = meanstdv(result[t][r]['DISTR_ANGLES'][index])
                temp_dict1[r][b].append(avg)

                for i in result[t][r]['DISTR_ANGLES'][index]:
                    temp_dict2[r][b].append(i)

                #for i in result[t][r]['DISTR_ABSMU'][index]:
                #	temp_dict2[b].append(i)

    # average
    avg_angles = dict()
    avg_absmu = dict()
    avg_angles_stdev = dict()
    avg_absmu_stdev = dict()

    for r in residueNames:
        avg_angles[r] = dict()
        avg_absmu[r] = dict()
        avg_angles_stdev[r] = dict()
        avg_absmu_stdev[r] = dict()
        temp = temp_dict1[r].keys()
        temp.sort()
        for i in temp:
            avg_angles[r][i], avg_angles_stdev[r][i] = meanstdv(
                temp_dict1[r][i])
            avg_absmu[r][i], avg_absmu_stdev[r][i] = meanstdv(temp_dict2[r][i])

    # print for average
    print("")
    print("Averaged " + str(avg_timestep) + " timesteps out of " +
          str(n_timestep))
    for r in residueNames:
        print(r)
        for i in temp:
            #print(str(i) + '\t' + str(temp_dict1[i]))
            print(
                str(i) + '\t' + str(avg_angles[r][i]) + '\t' +
                str(avg_angles_stdev[r][i]))
        print("")

    # save for debug
    output = ""
    for r in residueNames:
        for i in temp:
            output += str(i) + '\t' + str(temp_dict1[r][i]) + '\n'

    myOUT.write(output)
    myOUT.close()

    # save the pickle object
    pkl.dump(result, myRESULT)
    myRESULT.close()

    pkl.dump(temp_dict2, myRESULT2)
    myRESULT2.close()

    print('')
    return 1
def densityProfile(bgf_file,
                   trj_file,
                   ff_file,
                   out_file,
                   direction,
                   cnt_direction,
                   interval,
                   avg_timestep,
                   silent=False):

    nu.warn(
        "LAMMPS trajectory with NPT simulations will give you the wrong result."
    )

    ### init
    timestep = 0
    l_timestep = []
    line = []
    n_header = 0
    t1 = 0
    t2 = 0
    # clock
    vector = [0, 0, 1]
    # the axis of interest. in the acetone-water case, z direction.
    atominfo = dict()
    # atom data extracted from ff_file
    result = dict()
    axis = 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.")

    ### CNT direction
    if "x" in cnt_direction:
        cnt_direction = 0
    elif "y" in cnt_direction:
        cnt_direction = 1
    elif "z" in cnt_direction:
        cnt_direction = 2
    else:
        nu.die("Error on reading CNT 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 = set()
    # kind of residues in BGF file
    dict_residue = dict()
    # stores residue numbers per each residue. RES1: [1, 2, ..], RES2: [6, 7, ..]
    for i in myBGF.a:
        rname = string.strip(i.rName)
        residue.add(rname)
    output = ""
    for i in residue:
        output += i + " "

    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 no CNT the die
    if "CNT" not in residue:
        nu.die(
            "It seems that the BGF file does not contain any CNT atoms. Exiting."
        )

    ### extract aNos of CNT in the BGF file
    aNo_CNT = []

    for atom in myBGF.a:
        # Carbons in CNT
        if "CNT" in atom.rName:
            aNo_CNT.append(atom.aNo)

    ### read mass from ff_file
    try:
        parse = ff_file.split(" ")
    except:
        nu.die(
            "Error occurred when reading the force field file.. Check your " +
            str(ff_file))
    else:
        if not silent:
            print("Found " + str(len(parse)) + " Cerius2 Force Fields.")

    for i in parse:
        FF = dreiding.loadFF(i)
        temp_atominfo = dreiding.loadAtomTypes(FF)
        atominfo.update(temp_atominfo)

    ### read trajectory file
    # how many steps to go?
    n_timestep = len(lt.getTrjInfo(trj_file))
    if not silent:
        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]
    boxsize = [(boxsize[1] - boxsize[0]), (boxsize[3] - boxsize[2]),
               (boxsize[5] - boxsize[4])]
    keywords = line[8].strip('ATOMS ')

    initial_boxsize = copy.deepcopy(boxsize)

    # for every shot in the trajectory file update BGF and manipulate
    dumpatom = get_line(trj_file)
    processed_step = 0

    t1 = t2 = 0
    elapsed_time = 0

    while 1:
        try:
            chunk = [next(dumpatom) for i in range(natoms + n_header)]
        except StopIteration:
            break

        timestep = int(chunk[1])
        l_timestep.append(timestep)
        natoms = int(chunk[3])
        boxsize = [
            chunk[5].split(' ')[0], chunk[5].split(' ')[1],
            chunk[6].split(' ')[0], chunk[6].split(' ')[1],
            chunk[7].split(' ')[0], chunk[7].split(' ')[1]
        ]
        boxsize = [float(i) for i in boxsize]
        boxsize = [(boxsize[1] - boxsize[0]), (boxsize[3] - boxsize[2]),
                   (boxsize[5] - boxsize[4])]
        keywords = chunk[8].split('ATOMS ')[1].strip('\n').split(' ')

        ### if the box size changes, then stop (only takes NVT trajectory)
        for i in range(3):
            if abs(initial_boxsize[i] - boxsize[i]) > 0.1:
                nu.die(
                    "Simulation box change detected in the trajectory file. NVT trajectory is required to continue."
                )

        ### Show progress
        t1 = time.time()
        remaining_time = elapsed_time * (n_timestep - processed_step)
        sys.stdout.write('\r' + "Reading timestep.. " + str(timestep) +
                         " (Elapsed time for the previous step: " +
                         "{0:4.1f}".format(elapsed_time) +
                         " seconds, Remaining time: " +
                         "{0:4.1f}".format(remaining_time) + " seconds = " +
                         "{0:4.1f} minutes".format(remaining_time / 60) + ")")
        sys.stdout.flush()

        processed_step += 1

        ### update myBGF with trajectory information ###
        natom_bgf = len(myBGF.a)  # number of atoms in BGF file

        if not natom_bgf == natoms:
            nu.die(
                "Number of atoms in trajectory file does not match with BGF file."
            )

        mode = ""
        if 'xs' in keywords or 'ys' in keywords or 'zs' in keywords:
            mode = 'scaled'
        elif 'x' in keywords or 'y' in keywords or 'z' in keywords:
            mode = 'normal'
        elif 'xu' in keywords or 'yu' in keywords or 'zu' in keywords:
            mode = 'unwrapped'

        # actual coordinate
        coordinfo = chunk[9:]

        # assume that coordinfo is similar to ['id', 'type', 'xs', 'ys', 'zs', 'ix', 'iy', 'iz']
        for atomline in coordinfo:
            atomcoord = atomline.split(' ')
            atom = myBGF.getAtom(int(atomcoord[0]))

            if mode == 'scaled':
                atom.x = float(atomcoord[2]) * boxsize[0]
                atom.y = float(atomcoord[3]) * boxsize[1]
                atom.z = float(atomcoord[4]) * boxsize[2]

            elif mode == 'unwrapped':
                atom.x = float(atomcoord[2])
                atom.y = float(atomcoord[3])
                atom.z = float(atomcoord[4])

            elif mode == 'normal':
                try:
                    ix_index = keywords.index('ix')
                    iy_index = keywords.index('iy')
                    iz_index = keywords.index('iz')
                except ValueError:
                    nu.warn(
                        "No image information no the trajectory file. Will be treated as unwrapped."
                    )
                    atom.x = float(atomcoord[2])
                    atom.y = float(atomcoord[3])
                    atom.z = float(atomcoord[4])
                else:
                    atom.x = (int(atomcoord[ix_index]) * boxsize[0]) + float(
                        atomcoord[2])
                    atom.y = (int(atomcoord[iy_index]) * boxsize[1]) + float(
                        atomcoord[3])
                    atom.z = (int(atomcoord[iz_index]) * boxsize[2]) + float(
                        atomcoord[4])

            try:
                for i in range(0, 3):
                    myBGF.CRYSTX[i] = boxsize[i]
            except:
                pass
                #nu.warn("Crystal information error: is this file not periodic?")

        # apply periodic condition
        myBGF = bgftools.periodicMoleculeSort(myBGF, 0)

        ### DONE for updating trj on BGF file ###
        ### Do whatever I want: density profile

        ### find the CNT center
        radius_CNT = 0
        cntx = cnty = cntz = 0
        natoms_CNT = len(aNo_CNT)
        for aNo in aNo_CNT:
            atom = myBGF.getAtom(aNo)
            cntx += atom.x
            cnty += atom.y
            cntz += atom.z
        cntx /= natoms_CNT
        cnty /= natoms_CNT
        cntz = natoms_CNT

        ### make a bin
        diagonal_length = 0.0
        box_height = boxsize[cnt_direction]
        radial_bin_length = 0.0
        x_length = boxsize[0] / 2
        y_length = boxsize[1] / 2
        z_length = boxsize[2] / 2

        if cnt_direction == 0:
            diagonal_length = math.sqrt(boxsize[1]**2 + boxsize[2]**2) / 2
            radial_bin_length = min(diagonal_length, y_length, z_length)
        elif cnt_direction == 1:
            diagonal_length = math.sqrt(boxsize[0]**2 + boxsize[2]**2) / 2
            radial_bin_length = min(diagonal_length, x_length, z_length)
        elif cnt_direction == 2:
            diagonal_length = math.sqrt(boxsize[0]**2 + boxsize[1]**2) / 2
            radial_bin_length = min(diagonal_length, y_length, z_length)

        # choose the shortest length among diagonal and half size of the box length
        #radial_bin_length = min(diagonal_length, boxsize[0]/2, boxsize[1]/2, boxsize[2]/2)
        bin = np.arange(0.0, math.ceil(radial_bin_length), 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]
            dist = 0
            # calculate radial distance from CNT center to atom
            if cnt_direction == 0:
                dist = math.sqrt((atom.y - cnty)**2 + (atom.z - cntz)**2)
            elif cnt_direction == 1:
                dist = math.sqrt((atom.x - cntx)**2 + (atom.z - cntz)**2)
            elif cnt_direction == 2:
                dist = math.sqrt((atom.x - cntx)**2 + (atom.y - cnty)**2)

            # total
            positions[-1].append(dist)
            masses[-1].append(atominfo[atom.ffType]['MASS'])

            # residues
            positions[dict_residue[atom.rName.strip()]].append(dist)
            masses[dict_residue[atom.rName.strip()]].append(
                atominfo[atom.ffType]['MASS'])

        ### histogram
        for i in range(n_residue):
            hist[i], bin_edges[i] = np.histogram(positions[i],
                                                 bins=bin,
                                                 weights=masses[i])

        ### divide by volume for density
        vol = []
        for j in range(len(hist[0])):
            vol.append(math.pi *
                       (bin_edges[0][j + 1]**2 - bin_edges[0][j]**2) *
                       box_height)

        for i in range(n_residue):
            hist[i] = hist[i] / 6.022 / vol * 10.0  # 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 " + str(avg_timestep) + " timesteps..")
    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
Пример #6
0
def densityProfile(bgf_file,
                   trj_file,
                   ff_file,
                   pickle_file,
                   out_file,
                   avg_timestep,
                   silent=False):

    nu.warn(
        "LAMMPS trajectory with NPT simulations will give you the wrong result."
    )

    ### init
    timestep = 0
    l_timestep = []
    line = []
    n_header = 0
    t1 = 0
    t2 = 0
    # clock
    atominfo = dict()
    # atom data extracted from ff_file
    result = dict()
    axis = 2
    # 1: x-axis, 2: y-axis, 3: z-axis

    ### open files
    myBGF = bgf.BgfFile(bgf_file)
    myTRJ = open(trj_file)
    myTRJ.seek(0)
    myPickle = open(pickle_file)
    f_debug = open("debug.dat", 'w')
    if not silent: print("Pickling..")
    Dipole = pickle.load(myPickle)  # dipole data

    ### read residues from bgf_file
    residue = set()
    # kind of residues in BGF file
    dict_residue = dict()
    # stores residue numbers per each residue. RES1: [1, 2, ..], RES2: [6, 7, ..]
    for i in myBGF.a:
        rname = string.strip(i.rName)
        residue.add(rname)
    output = ""
    for i in residue:
        output += i + " "
        dict_residue[i] = []

    if not silent:
        print("Found " + str(len(residue)) + " residues in BGF file: " +
              str(output))
    residue = list(residue)
    #residue.append('TOTAL')

    n_residue = len(residue)  # number of residues (including total)

    ### bookkeep residue numbers for each residue
    molecules = bgftools.getMoleculeList(myBGF)
    dict_rNo2rName = dict()

    for molecule in molecules:
        # get an atom
        atom = myBGF.getAtom(molecule[0])
        atomresname = string.strip(atom.rName)
        atomresno = atom.rNo

        # check if all molecule has same residue name and numbers
        for ano in molecule:
            atom2 = myBGF.getAtom(ano)
            temp_rno = atom2.rNo
            temp_rname = string.strip(atom2.rName)
            if temp_rno != atomresno or temp_rname != atomresname:
                nu.die(
                    "Different residue name or residue number in a same molecule: "
                    + str(atom2.aNo))

        # record resid for resnames
        dict_residue[atomresname].append(atom.rNo)
        dict_rNo2rName[atom.rNo] = atomresname

    #print(dict_residue)
    #print(dict_rNo2rName)

    ### read mass from ff_file
    try:
        parse = ff_file.split(" ")
    except:
        nu.die(
            "Error occurred when reading the force field file.. Check your " +
            str(ff_file))
    else:
        if not silent:
            print("Found " + str(len(parse)) + " Cerius2 Force Fields.")

    for i in parse:
        FF = dreiding.loadFF(i)
        temp_atominfo = dreiding.loadAtomTypes(FF)
        atominfo.update(temp_atominfo)

    ### read trajectory file
    # how many steps to go?
    wc_trj_file = popen("grep TIMESTEP " + trj_file + " | wc -l ").read()
    n_timestep = int(wc_trj_file.split()[0])
    print("The trajectory contains " + str(n_timestep) + " timesteps.")

    # Find header of the trajectory file
    while 1:
        templine = myTRJ.readline()
        line.append(templine.strip('\n').strip('ITEM: '))
        n_header += 1
        if "ITEM: ATOMS" in templine:
            break

    # INITIAL trajectory information
    timestep = int(line[1])
    natoms = int(line[3])
    boxsize = [
        line[5].split(' ')[0], line[5].split(' ')[1], line[6].split(' ')[0],
        line[6].split(' ')[1], line[7].split(' ')[0], line[7].split(' ')[1]
    ]
    boxsize = [float(i) for i in boxsize]
    keywords = line[8].strip('ATOMS ')

    # for every shot in the trajectory file update BGF and manipulate
    dumpatom = get_line(trj_file)
    processed_step = 0

    t1 = t2 = 0
    elapsed_time = 0

    while 1:
        try:
            chunk = [next(dumpatom) for i in range(natoms + n_header)]
        except StopIteration:
            break

        timestep = int(chunk[1])
        l_timestep.append(timestep)
        natoms = int(chunk[3])
        boxsize = [
            chunk[5].split(' ')[0], chunk[5].split(' ')[1],
            chunk[6].split(' ')[0], chunk[6].split(' ')[1],
            chunk[7].split(' ')[0], chunk[7].split(' ')[1]
        ]
        boxsize = [float(i) for i in boxsize]
        boxsize = [(boxsize[1] - boxsize[0]), (boxsize[3] - boxsize[2]),
                   (boxsize[5] - boxsize[4])]
        keywords = chunk[8].split('ATOMS ')[1].strip('\n').split(' ')

        ########
        if timestep < avg_timestep:
            continue
        if timestep % 10000 != 0:
            continue
        ########

        ### Show progress
        t1 = time.time()
        remaining_time = elapsed_time * (n_timestep - processed_step)
        sys.stdout.write('\r' + "Reading timestep.. " + str(timestep) +
                         " (Elapsed time for the previous step: " +
                         "{0:4.1f}".format(elapsed_time) +
                         " seconds, Remaining time: " +
                         "{0:4.1f}".format(remaining_time) + " seconds = " +
                         "{0:4.1f} minutes".format(remaining_time / 60) + ")")
        sys.stdout.flush()

        processed_step += 1

        ### update myBGF with trajectory information ###
        natom_bgf = len(myBGF.a)  # number of atoms in BGF file

        if not natom_bgf == natoms:
            nu.die(
                "Number of atoms in trajectory file does not match with BGF file."
            )

        mode = ""
        if 'xs' in keywords or 'ys' in keywords or 'zs' in keywords:
            mode = 'scaled'
        elif 'x' in keywords or 'y' in keywords or 'z' in keywords:
            mode = 'normal'
        elif 'xu' in keywords or 'yu' in keywords or 'zu' in keywords:
            mode = 'unwrapped'

        # actual coordinate
        coordinfo = chunk[9:]

        # assume that coordinfo is similar to ['id', 'type', 'xs', 'ys', 'zs', 'ix', 'iy', 'iz']
        for atomline in coordinfo:
            atomcoord = atomline.split(' ')
            atom = myBGF.getAtom(int(atomcoord[0]))

            if mode == 'scaled':
                atom.x = float(atomcoord[2]) * boxsize[0]
                atom.y = float(atomcoord[3]) * boxsize[1]
                atom.z = float(atomcoord[4]) * boxsize[2]

            elif mode == 'unwrapped':
                atom.x = float(atomcoord[2])
                atom.y = float(atomcoord[3])
                atom.z = float(atomcoord[4])

            elif mode == 'normal':
                try:
                    ix_index = keywords.index('ix')
                    iy_index = keywords.index('iy')
                    iz_index = keywords.index('iz')
                except ValueError:
                    nu.warn(
                        "No image information no the trajectory file. Will be treated as unwrapped."
                    )
                    atom.x = float(atomcoord[2])
                    atom.y = float(atomcoord[3])
                    atom.z = float(atomcoord[4])
                else:
                    atom.x = (int(atomcoord[ix_index]) * boxsize[0]) + float(
                        atomcoord[2])
                    atom.y = (int(atomcoord[iy_index]) * boxsize[1]) + float(
                        atomcoord[3])
                    atom.z = (int(atomcoord[iz_index]) * boxsize[2]) + float(
                        atomcoord[4])

            try:
                for i in range(0, 3):
                    myBGF.CRYSTX[i] = boxsize[i]
            except:
                pass
                #nu.warn("Crystal information error: is this file not periodic?")

        # apply periodic condition
        myBGF = bgftools.periodicMoleculeSort(myBGF, 0)

        ### DONE for updating trj on BGF file ###

        ### find bin  ## CAUTION: only for NVT
        min = 100000
        max = -100000
        for atom in myBGF.a:
            coord = [atom.x, atom.y, atom.z]
            if coord[axis] < min:
                min = coord[axis]
            if coord[axis] > max:
                max = coord[axis]

        if boxsize[axis] > max:
            max = boxsize[axis]
        if 0 < min:
            min = 0

        bins = np.arange(math.floor(min), math.ceil(max), interval)

        #print("Bins....:")
        #print(bins)

        ### find CM of every molecule
        res_z = []
        residues = []
        for molecule in molecules:
            n_atom = len(molecule)  # number of atoms in the molecule
            residue_no = myBGF.getAtom(molecule[0]).rNo
            # residue number of the molecule
            m = bgftools.getMass(myBGF, molecule, ff_file)
            # molecule mass
            cm = [0, 0, 0]
            # center of mass
            coord = [0, 0, 0]
            # atom x, y, z
            residues.append(residue_no)  # store residue numbers of molecules

            for aNo in molecule:
                atom = myBGF.getAtom(aNo)
                coord = [atom.x, atom.y, atom.z]

                # error if residue numbers are different
                if atom.rNo != residue_no:
                    nu.die(
                        "Residue numbers in a same molecule are not consistent. Please check your BGF file."
                    )

                # error if mass is unreadable
                ffType = string.strip(atom.ffType)
                try:
                    aMass = atominfo[ffType]['MASS']
                except:
                    nu.die("Cannot read the atom type " + str(atom.ffType) +
                           " in the data file.")

                # calculate CM
                for index, i in enumerate(coord):
                    cm[index] += i * aMass

            cm = [i / m for i in cm]
            # center of mass

            res_z.append([residue_no, cm[2]])

        ### binning according to z-axis
        bin_resno = []
        for index, bin in enumerate(bins):
            temp_resno = []
            for i in res_z:
                try:
                    if bin < i[1] and bins[index + 1] > i[1]:
                        temp_resno.append(i[0])
                except:
                    continue
            bin_resno.append([bin, temp_resno])

        ### refinement for residues
        bin_avg = []
        for r in residue:
            temp_per_r = []
            for b in bin_resno:
                temp_bin_res = []
                for i in b[1]:
                    if dict_rNo2rName[i] == r:
                        temp_bin_res.append(i)
                temp_per_r.append([b[0], temp_bin_res])
            bin_avg.append([r, temp_per_r])

        ### average
        #result = [];
        result_t = dict()
        for rdata in bin_avg:
            temp_per_r = []
            for b in rdata[1]:
                temp_bin_res = []
                avg_mag = 0
                avg_angle_cos = 0

                for i in b[1]:
                    avg_mag += Dipole[timestep][rdata[0]]['ABSMU'][i]

                    mu = Dipole[timestep][rdata[0]]['MU'][i]
                    # angle btwn z-axis and mu
                    angle_cos = mu[2] / math.sqrt(mu[0]**2 + mu[1]**2 +
                                                  mu[2]**2)
                    f_debug.write(
                        str(timestep) + '\t' + str(mu) + '\t' +
                        str(Dipole[timestep][rdata[0]]['ABSMU'][i]) + '\t' +
                        str(angle_cos) + '\n')
                    avg_angle_cos += angle_cos
                if not len(b[1]) == 0: avg_mag /= len(b[1])
                if not len(b[1]) == 0: avg_angle_cos /= len(b[1])
                temp_per_r.append([b[0], avg_angle_cos, avg_mag])
            #result.append(temp_per_r)
            result_t[rdata[0]] = temp_per_r

        result[timestep] = result_t

        ### end of loop: check elapsed time
        t2 = time.time()  # time mark
        elapsed_time = t2 - t1

    ### write pickle
    o = open(out_file + ".pickle", 'w')
    pickle.dump(result, o)

    ### return

    print('')
    return 1