示例#1
0
def is_hbonded2(mybgf, atom1, atom2, d_crit=2.2):
    """
    returns True if two atoms are h-bonded by a geometric definition.
    This definition is introduced in Grishina, N., & Buch, V. (2004). J. Chem. Phys., 120(11), 5217.
    20160608: Works only for O atoms.
    """

    if not "O" in atom1.ffType or not "O" in atom2.ffType:
        return False

    d = np.array([atom1.x, atom1.y, atom1.z])
    a = np.array([atom2.x, atom2.y, atom2.z])

    if mybgf.CRYSTX:
        pbc = mybgf.CRYSTX[:3]
    else:
        pbc = 0

    # A1-H ... A2
    for ano in atom1.CONECT:
        atom = mybgf.getAtom(ano)  # this should be an H atom
        x = np.array([atom.x, atom.y, atom.z])
        if pbc:
            dist = nu.pbc_dist(x, a, pbc)
        else:
            dist = nu.dist(x, a)
        if 1e-5 < dist < d_crit:
            return x

    # A1 ... H-A2
    for ano in atom2.CONECT:
        atom = mybgf.getAtom(ano)  # this should be an H atom
        x = np.array([atom.x, atom.y, atom.z])
        if pbc:
            dist = nu.pbc_dist(x, a, pbc)
        else:
            dist = nu.dist(x, a)
        if 1e-5 < dist < d_crit:
            return x

    return []
示例#2
0
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
示例#3
0
def getHBond(bgf_file, trj_file, selection='', silent=False):

    # init
    timestep = 0
    l_timestep = []
    line = []
    n_header = 0
    t1 = 0
    t2 = 0
    # clock
    hbond_dat = dict()
    d_crit = 3.5
    a_crit = 30.0

    myBGF = bgf.BgfFile(bgf_file)
    myTRJ = open(trj_file)
    myTRJ.seek(0)
    myPickle_file = bgf_file[:-4] + ".hbond.pickle"
    myDAT = open(bgf_file[:-4] + ".hbond.count.dat", "w")
    myDAT.write(str(sys.argv) + "\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.")

    # 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_timestep - 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(' ')

        ### 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?")

        pbc = myBGF.CRYSTX[:3]

        # apply periodic condition
        myBGF = bgftools.periodicMoleculeSort(myBGF, myBGF.CRYSTX, silent=True)

        ### myBGF update complete! ###

        # get donor and acceptor
        # donors: O in ACT
        A = []
        D = []
        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 (especially O atoms)!"
            )

        ### find hydrogen bonds
        # for all pairs of OC-HW
        sys.stdout.write('Hbonds.. ')
        sys.stdout.flush()

        hbonds = []
        donors = []
        acceptors = []
        hydrogens = []
        angles = []
        distances = []

        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])
                dist = nu.dist(d, a)
                #dist = bgf.distance(d_atom, a_atom)
                if 0.001 < dist < d_crit:
                    # check H angle
                    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))
                        #theta = bgf.angle(h_atom, d_atom, a_atom, radians=False)
                        if theta < a_crit:
                            hbonds.append([d_atom.aNo, a_atom.aNo])
                            donors.append(d_atom.aNo)
                            acceptors.append(a_atom.aNo)
                            hydrogens.append(h_atom.aNo)
                            distances.append(dist)
                            angles.append(theta)
                            #n_hbond += 1
                            #print("%s %s" % (d_atom.rNo, a_atom.rNo))

        hbond_dat[timestep] = hbonds
        sys.stdout.write(
            'Done                                                        ')
        sys.stdout.flush()

        print("")
        for i in zip(donors, acceptors, hydrogens, distances, angles):
            print i
        sys.exit(0)

        myDAT.write("%d %d\n" % (timestep, len(hbonds)))

        # write output
        #myBGF.saveBGF(bgf_file[:-4] + "." + str(timestep) + ".bgf")
        #myBGF2.saveBGF(bgf_file[:-4] + "." + str(timestep) + ".bgf")

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

    pickle_f = open(myPickle_file, 'w')
    pickle.dump(hbond_dat, pickle_f)
    print('')

    myDAT.close()

    return 1
示例#4
0
for atom in tqdm.tqdm(moslayer.a, ncols=120, desc='Assigning ffTypes'):
    if "S" in atom.ffType:
        if atom.z > avg_mo_z:
            atom.ffType = "S_3a"
        else:
            atom.ffType = "S_3b"

# remove infinite boundary
n_del = 0
for atom in tqdm.tqdm(moslayer.a, ncols=120, desc='Removing pbc bonds'):
    a = [atom.x, atom.y, atom.z]
    connected_ano = atom.CONECT
    for ano in connected_ano:
        atom2 = moslayer.getAtom(ano)
        a2 = [atom2.x, atom2.y, atom2.z]
        dist = nu.dist(a, a2)
        pbc_dist = nu.pbc_dist(a, a2, moslayer.CRYSTX[:3])
        if dist != pbc_dist:
            moslayer.disconnect(moslayer.a2i[atom.aNo],
                                moslayer.a2i[atom2.aNo])
            n_del += 1
print("%d bonds are disconnected." % n_del)

# remove infinite boundary
n_del = 0
for atom in tqdm.tqdm(moslayer.a, ncols=120, desc='Removing pbc bonds 2'):
    a = [atom.x, atom.y, atom.z]
    connected_ano = atom.CONECT
    for ano in connected_ano:
        atom2 = moslayer.getAtom(ano)
        a2 = [atom2.x, atom2.y, atom2.z]
示例#5
0
def analyze(bgf_file, trj_file, ff_file='', name='', selection='', d_crit=3.5):
    '''analyze something within a timestep in a series of lammps trajectory.
    '''
    # variables
    result_angles = dict()
    result_diheds = dict()
    print(
        "Using neighboring water distance criteria %4.1f A (should be consistent with the coordination number)"
        % d_crit)

    # 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)

        # Calculate Angles and Dihedrals for Water Structure
        O = []
        for atom in mybgf.a:
            if selection:
                if "O" in atom.ffType and eval(selection):
                    O.append(atom)
            else:
                if "O" in atom.ffType:
                    O.append(atom)

        if not len(O):
            nu.warn("There are no O atoms which satisfies %s!" % selection)

        coords = []
        anos = []
        for atom in O:
            coords.append([atom.x, atom.y, atom.z])
            anos.append(atom.aNo)

        coords = np.array(coords)
        #tree = pkdtree.PeriodicKDTree(mytrj.pbc[t], coords)    # KDTree with pbc
        tree = scipy.spatial.KDTree(
            coords, leafsize=len(coords) +
            1)  # REMARK: normal KDTree -- do not consider over pbc

        angles = []
        diheds = []
        for atom in O:
            # Find neighbors
            coord = np.array([atom.x, atom.y, atom.z])
            neighbor_O = []
            # list of O atoms near centerO
            d, ndx = tree.query(coord, k=5)
            index = np.where((d >= 1e-4) & (d <= d_crit))  # discard self
            for i in ndx[index]:
                neighbor_O.append(mybgf.getAtom(anos[i]))

            # Angles
            for i, j in itertools.combinations(neighbor_O, 2):
                x = [i.x, i.y, i.z]
                y = [j.x, j.y, j.z]
                angle = nu.angle(x, coord, y, radians=False)
                angles.append([angle, i.z, atom.z,
                               j.z])  # angles: result_angle data structure

            # Dihedrals: farthest H-O...O-H for all neighboring O-O pairs
            for atom2 in neighbor_O:
                # are they have an hydrogen bond?
                if bt.is_hbonded(mybgf, atom, atom2):
                    hO_anos = atom.CONECT  # H connected to center O
                    hO2_anos = atom2.CONECT  # H connected to neighboring O
                    max_dist_pair = []
                    max_dist = 0.0
                    for k, l in itertools.product(hO_anos, hO2_anos):
                        h1 = mybgf.getAtom(k)
                        h2 = mybgf.getAtom(l)
                        dist = nu.dist([h1.x, h1.y, h1.z], [h2.x, h2.y, h2.z])
                        if dist > max_dist:
                            max_dist = dist
                            max_dist_pair = [h1, h2]

                phi = bgf.dihedral(max_dist_pair[0],
                                   atom,
                                   atom2,
                                   max_dist_pair[1],
                                   radians=False)
                diheds.append([phi, atom.z,
                               atom2.z])  # diheds: result_dihed data structure

        result_angles[t] = angles
        result_diheds[t] = diheds

    # Write-ups
    if name:
        out_file = name + '.aop'
    else:
        out_file = 'aop'

    angle_out_file = out_file + ".angle.pickle"
    dihed_out_file = out_file + ".dihed.pickle"

    with open(angle_out_file, 'wb') as f:
        pickle.dump(result_angles, f, protocol=pickle.HIGHEST_PROTOCOL)
        print("Success to save the angle result to a pickle file %s" %
              angle_out_file)

    with open(dihed_out_file, 'wb') as f:
        pickle.dump(result_diheds, f, protocol=pickle.HIGHEST_PROTOCOL)
        print("Success to save the dihed result to a pickle file %s" %
              dihed_out_file)

    print("Done.")