예제 #1
0
def countMoleculeNum(bgf_file, silent=True):

    n_water = 0

    l_molecule = bgftools.getMoleculeList(bgf_file)
    natom = len(nu.flatten(l_molecule))
    nmol = len(l_molecule)
    l_molecule_atoms = []
    for cluster in l_molecule:
        l_molecule_atoms.append(len(cluster))
        if len(cluster) == 3:
            n_water += 1

    if not silent:
        print(
            str(nmol) + " Molecules (" + str(natom) +
            " atoms) exists in the BGF file.")
    if not silent:
        print("Number of water molecules (i.e. natoms = 3): " + str(n_water))
    #if not silent: print("Size of molecules: " + str(l_molecule_atoms))

    return nmol
예제 #2
0
            print(usage)
            sys.exit(0)

    # variables
    result = []

    # inner functions
    def get_line(file):
        with open(file, 'r') as f:
            for line in f:
                yield line

    # 1. Load BGF
    mybgf = bgf.BgfFile(bgf_file)
    N_BGF_ATOMS = len(mybgf.a)
    atom_frags = bt.getMoleculeList(mybgf)
    type = "gra"
    for atom in mybgf.a:
        if "Mo" in atom.ffType:
            type = "mos"

    # 2. Read LAMMPS Trajectory
    mytrj = lt.lammpstrj(trj_file)
    mytrj.load()
    timesteps = sorted(mytrj.timesteps)
    N_HEADER = mytrj.nheader
    N_ATOMS = mytrj.natoms[timesteps[0]]
    N_BUFFER = N_HEADER + N_ATOMS
    if N_BGF_ATOMS != N_ATOMS:
        nu.die(
            "Number of atoms in trajectory file does not match with BGF file.")
예제 #3
0
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)
예제 #4
0
def addsolvent(bgf_file,
               solvent_bgf,
               size,
               margin,
               out_file,
               ff_file,
               silent=True):

    ### initialize
    water = False

    ### load the solute bgf file
    if not silent: print("Initializing..")
    myBGF = bgf.BgfFile(bgf_file)  # str

    #solventBGF = bgf.BgfFile("/home/noische/scripts/dat/WAT/f3c_box.bgf")	# F3C waterbox
    if not silent: print("Loading the solvent file " + solvent_bgf + " ..")
    solventBGF = bgf.BgfFile(solvent_bgf)

    ### Generate error when the solvent box is not periodic:
    if not solventBGF.PERIOD:
        nu.die(
            "addSolvent: The solvent file is not periodic. Use a box full of solvent."
        )

    ### Check the type of solvent
    if not silent:
        print("(the solvent box seems to be full of " +
              os.path.basename(solvent_file)[:-4] + " )")
    if "f3c" in solvent_bgf:
        water = True  # this flag is used to remove the bad contacts with the molecule.
    if "spc" in solvent_bgf:
        water = True  # this flag is used to remove the bad contacts with the molecule.
    if "tip" in solvent_bgf:
        water = True  # this flag is used to remove the bad contacts with the molecule.

    ### calculate the box size
    if not silent: print("Analyzing box information..")
    if len(myBGF.CRYSTX) > 2:
        strsize = [myBGF.CRYSTX[0], myBGF.CRYSTX[1], myBGF.CRYSTX[2]]
    else:
        box = bgf.getBGFSize(myBGF, 0)  # [xlo, xhi, ylo, yhi, zlo, zhi]
        strsize = [box[1] - box[0], box[3] - box[2], box[5] - box[4]]

    ###
    if size == "" and margin != "":
        strsize = [
            strsize[0] + 2 * margin[0], strsize[1] + 2 * margin[1],
            strsize[2] + 2 * margin[2]
        ]  # add margin on str size
    elif size != "" and margin == "":
        strsize = size

    waterboxsize = solventBGF.CRYSTX[:3]  # REMARK: This is a kind of constant.
    copyNumber = [0, 0, 0]
    for index, i in enumerate(copyNumber):
        copyNumber[index] = math.ceil(
            strsize[index] /
            waterboxsize[index])  # how many times to replicate the water box

    if not silent: print("Creating box information: " + str(strsize))

    ### replicate the solvent box
    bigboxBGF = bgftools.replicateCell(solventBGF, copyNumber, True)
    bigboxBGF.saveBGF("_replicate.bgf")
    if not silent:
        print("- Number of atoms in the created box: " + str(len(bigboxBGF.a)))

    ### trim the water box
    if water:
        if not silent:
            print("Generating water box.. Calculating water molecules")
        delatom = []
        delwater = []
        delwaterindex = []
        for atom in bigboxBGF.a:
            if atom.x > strsize[0] or atom.y > strsize[1] or atom.z > strsize[
                    2]:
                delatom.append(atom.aNo)
        for aNo in delatom:
            water_molecule = bgftools.is_water(bigboxBGF, aNo)
            if not water_molecule in delwater:
                delwater.append(water_molecule)
        delwater = nu.flatten(delwater)
        delwater = nu.removeRepeat(delwater)
        delwater.sort()
        delwater.reverse()
        for aNo in delwater:
            delwaterindex.append(bigboxBGF.getAtomIndex(aNo))
        del (delwater)
        if not silent: print("Generating water box.. Trimming")
        bigboxBGF.delAtoms(delwaterindex, False)
        bigboxBGF.renumber()
    elif not water:
        if not silent:
            print("Generating solvent box.. Extracting solvent molecules")
        delatom = []
        delsolvent = []
        delsolventindex = []
        for atom in bigboxBGF.a:
            if atom.x > strsize[0] or atom.y > strsize[1] or atom.z > strsize[
                    2]:
                delatom.append(atom.aNo)
        for aNo in delatom:
            molecule_list = []
            molecule = bgftools.getmolecule(bigboxBGF, bigboxBGF.getAtom(aNo),
                                            molecule_list)
            for number in molecule_list:
                if not number in delsolvent: delsolvent.append(number)
        delsolvent = nu.flatten(delsolvent)
        delsolvent = nu.removeRepeat(delsolvent)
        delsolvent.sort()
        delsolvent.reverse()
        for aNo in delsolvent:
            delsolventindex.append(bigboxBGF.getAtomIndex(aNo))
        if not silent: print("Generating solvent box.. Trimming")
        bigboxBGF.delAtoms(delsolventindex, False)
        bigboxBGF.renumber()

    ### merge two structure
    # REMARK: it is natural to have the periodic information of water box for the output BGF file.
    # REMARK: HETATOM should be located on the first of the BGF file. So use dummy for merging.
    if not silent: print("\nAdding trimmed solvent box to the structure..")
    bigboxcenter = [strsize[0] / 2, strsize[1] / 2, strsize[2] / 2]
    a, b, c = bgftools.getCom(myBGF, ff_file)
    bgf.moveBGF(myBGF, bigboxcenter[0] - a, bigboxcenter[1] - b,
                bigboxcenter[2] - c)

    ## remove bad contacts between solutes and solvents
    if not silent: print("Atom distance calculation for contacts..")
    delatom = []
    delsolvent = []
    delsolventindex = []
    for atom1 in myBGF.a:
        for atom2 in bigboxBGF.a:
            # if the distance between atom1 and atom2 is less than 2.8, add to a delete list
            dist_sq = (atom1.x - atom2.x)**2 + (atom1.y - atom2.y)**2 + (
                atom1.z - atom2.z)**2
            if dist_sq < 7.84:
                delatom.append(atom2.aNo)

    # delete bad atoms!
    if not silent: print("Removing bad contacts..")
    for aNo in delatom:
        molecule_list = []
        molecule = bgftools.getmolecule(bigboxBGF, bigboxBGF.getAtom(aNo),
                                        molecule_list)
        for number in molecule_list:
            if not number in delsolvent: delsolvent.append(number)
    delsolvent = nu.flatten(delsolvent)
    delsolvent = nu.removeRepeat(delsolvent)
    delsolvent.sort()
    delsolvent.reverse()
    for aNo in delsolvent:
        delsolventindex.append(bigboxBGF.getAtomIndex(aNo))
    bigboxBGF.delAtoms(delsolventindex, False)
    bigboxBGF.renumber()

    ## compute stats for adding solvents
    if not silent: print("\nComputing stats..")
    mol_list = bgftools.getMoleculeList(bigboxBGF)
    n_mol = len(mol_list)
    n_atom = len(nu.flatten(mol_list))
    if not silent:
        print(
            str(n_mol) + " molecules (" + str(n_atom) +
            " atoms) will be added.")

    ## merge
    bigboxBGF = myBGF.merge(bigboxBGF, True)
    if not silent: print("Total atoms in the file: " + str(len(bigboxBGF.a)))

    ## some paperworking for periodic box
    bigboxBGF.OTHER = solventBGF.OTHER
    bigboxBGF.PERIOD = solventBGF.PERIOD
    bigboxBGF.AXES = solventBGF.AXES
    bigboxBGF.SGNAME = solventBGF.SGNAME
    bigboxBGF.CRYSTX = solventBGF.CRYSTX
    bigboxBGF.CELLS = solventBGF.CELLS

    ## adjust the size of the box
    bigboxBGF.CRYSTX = [
        strsize[0], strsize[1], strsize[2], solventBGF.CRYSTX[3],
        solventBGF.CRYSTX[4], solventBGF.CRYSTX[5]
    ]
    """
	### remove bad contacts and save
	if water:
		if not silent: print("Removing bad contacts: distance criteria is 2.8 A")
		bigboxBGF = removebadcontacts(bigboxBGF, bigboxBGF, 2.8)

		### renumber residue numbers
		# RULE: all rNos for water molecules will be renumbered from 2. (for createLammpsInput.pl)
		if not silent: print("Renumbering water molecules..")
		max_rNo_in_hetatm = 0;
		oxygen_list = bgftools.listOxygenAtoms(bigboxBGF)
	
		### find the biggest rNo among HETATM
		for atom in bigboxBGF.a:
			if atom.aTag == 1:
				if max_rNo_in_hetatm < atom.rNo: max_rNo_in_hetatm = atom.rNo
	
		### update rNo in water molecules
		rNo_for_water = max_rNo_in_hetatm + 500;
		for aNo in oxygen_list:
			water_aNo = bgftools.is_water(bigboxBGF, aNo)	# get aNo in a water molecule by checking the oxygen atom
			if water_aNo != []:
				for atom_aNo in water_aNo:
					bigboxBGF.getAtom(atom_aNo).rNo = rNo_for_water
				rNo_for_water += 1
	"""

    ### record BGF remarks
    bigboxBGF.REMARK.insert(
        0, "Solvents added by " + os.path.basename(sys.argv[0]) + " by " +
        os.environ["USER"] + " on " + time.asctime(time.gmtime()))
    bigboxBGF.REMARK.insert(0, "Solvents: " + str(solvent_file))

    ### save BGF
    if not silent: print("Saving the file.. see " + str(out_file))
    bigboxBGF.saveBGF(out_file)

    return 1
예제 #5
0
def getHbond(bgf_file, trj_file, ff_file='', selection='', out_file=''):
    '''analyze something within a timestep in a series of lammps trajectory.
    '''
    # variables
    result = dict()

    # inner functions
    def get_line(file):
        with open(file, 'r') as f:
            for line in f:
                yield line

    # 1. Load BGF
    mybgf = bgf.BgfFile(bgf_file)
    N_BGF_ATOMS = len(mybgf.a)
    atom_frags = bt.getMoleculeList(mybgf)
    type = "gra"
    for atom in mybgf.a:
        if "Mo" in atom.ffType:
            type = "mos"

    # 2. Read LAMMPS Trajectory
    mytrj = lt.lammpstrj(trj_file)
    mytrj.load()
    timesteps = sorted(mytrj.timesteps)
    N_HEADER = mytrj.nheader
    N_ATOMS = mytrj.natoms[timesteps[0]]
    N_BUFFER = N_HEADER + N_ATOMS
    if N_BGF_ATOMS != N_ATOMS:
        nu.die(
            "Number of atoms in trajectory file does not match with BGF file.")

    # 3. Determine dump style
    dump_keywords = mytrj._dump_style
    yes_scale = False
    if 'xs' in dump_keywords:
        yes_scale = True

    # 4. Update coordinates from the snapshot
    dump = get_line(trj_file)
    #for t in tqdm.tqdm(timesteps, ncols=120, desc="Analyzing HBonds"):
    for t in timesteps:
        chunk = [next(dump) for i in range(N_BUFFER)]

        #-----------------#
        def hard_work(mybgf, chunk):
            mybgf = update_coord(chunk, mybgf, mytrj.pbc[t], scaled=yes_scale)
            mybgf = bt.periodicMoleculeSort(mybgf,
                                            mybgf.CRYSTX,
                                            fragments=atom_frags,
                                            ff_file=ff_file,
                                            silent=True)
            '''
            # find inwater boundary
            swr = 3.270615945/2
            gwr = 3.057430885/2
            margin = 5.0
            gwa_y = bt.atoms_average(mybgf, 'atom.y', selection="'GWA' in atom.rName")
            gwb_y = bt.atoms_average(mybgf, 'atom.y', selection="'GWB' in atom.rName")
            if type == "gra":
                avg_z1 = bt.atoms_average(mybgf, 'atom.z', selection="'C_R' in atom.ffType and 'GRA' in atom.rName")    # gra bottom
                avg_z2 = bt.atoms_average(mybgf, 'atom.z', selection="'C_R' in atom.ffType and 'GRB' in atom.rName")    # gra top
                actual_distance = avg_z2 - avg_z1
            elif type == "mos":
                avg_s3a_z2 = bt.atoms_average(mybgf, 'atom.z', selection="'S_3a' in atom.ffType and atom.rNo == 2")    # mos2 top
                avg_s3b_z1 = bt.atoms_average(mybgf, 'atom.z', selection="'S_3b' in atom.ffType and atom.rNo == 1")    # mos2 bottom
                actual_distance = avg_s3a_z2 - avg_s3b_z1
            inwater_x = pbc[0]
            inwater_y = gwb_y - gwa_y + 2 * gwr - 2 * margin
            inwater_z = actual_distance - 2 * swr
            selection = "atom.y > {gwa_y} + {margin} and atom.y < {gwb_y} - {margin}".format(**vars())
            '''

            ### collect data
            def calc_hbonds():
                # variables
                A = []
                D = []
                hbonds = []
                d_crit = 3.5
                a_crit = 30.0

                for atom in mybgf.a:
                    if selection:
                        if "O" in atom.ffType and eval(selection):
                            A.append(atom)
                        if "O" in atom.ffType and eval(selection):
                            D.append(atom)
                    else:
                        if "O" in atom.ffType:
                            A.append(atom)
                        if "O" in atom.ffType:
                            D.append(atom)
                if not len(A) or not len(D):
                    nu.die(
                        "There are no atoms which can make H_bond (O atoms so far)!"
                    )

                # calculate hbonds
                for d_atom in D:
                    d = np.array([d_atom.x, d_atom.y, d_atom.z])  # donor coord
                    neigh_anos = bt.get_neighbors_aNo(A,
                                                      d,
                                                      r=d_crit,
                                                      pbc=mytrj.pbc[t],
                                                      k=6)
                    donors = [d_atom.aNo] + d_atom.CONECT

                    for ano in neigh_anos:
                        a_atom = mybgf.getAtom(ano)
                        a = np.array([a_atom.x, a_atom.y,
                                      a_atom.z])  # acceptor coord
                        acceptors = [a_atom.aNo] + a_atom.CONECT

                        for ano in d_atom.CONECT:
                            h_atom = mybgf.getAtom(ano)
                            h = np.array([h_atom.x, h_atom.y, h_atom.z])
                            u = h - d
                            v = a - d
                            theta = np.dot(u, v) / norm(u) / norm(v)
                            theta = np.degrees(arccos(theta))
                            if theta < a_crit:  # HBond exists
                                dist = nu.pbc_dist(a, d, mytrj.pbc[t])
                                dist_ah = nu.pbc_dist(d, h, mytrj.pbc[t])

                                # E_vdw
                                sigma_r = O_sigma / dist
                                sigma_r_6 = sigma_r**6
                                sigma_r_12 = sigma_r**12
                                E_vdw = 4.0 * O_epsilon * (sigma_r_12 -
                                                           sigma_r_6)
                                # E_vdw in kcal/mol

                                # E_coul
                                E_coul = 0.0
                                for i, j in itertools.product(
                                        donors, acceptors):
                                    atom1 = mybgf.getAtom(i)
                                    atom2 = mybgf.getAtom(j)
                                    a1 = [atom1.x, atom1.y, atom1.z]
                                    a2 = [atom2.x, atom2.y, atom2.z]
                                    dist_ij = nu.pbc_dist(a1, a2, mytrj.pbc[t])
                                    E_coul += 332.06371 * atom1.charge * atom2.charge / dist_ij  # E_coul in kcal/mol

                                # E_hbond
                                E_hbond = E_coul + E_vdw  # E_hbond = E_vdw + E_coul

                                # update for v4
                                # angle between H-O-H plane and O..O vector
                                H1 = mybgf.getAtom(d_atom.CONECT[0])
                                h1 = [H1.x, H1.y, H1.z]  # H1
                                H2 = mybgf.getAtom(d_atom.CONECT[1])
                                h2 = [H2.x, H2.y, H2.z]  # H2
                                p = d - h1
                                q = d - h2
                                n = np.cross(
                                    p, q)  # normal vector of the H1-O-H2 plane
                                m = a - d
                                # O..O vector
                                alpha = np.dot(n, m) / norm(n) / norm(m)
                                alpha = np.degrees(
                                    arcsin(alpha)
                                )  # angle between H-O-H plane and O..O vector

                                hbonds.append([
                                    d_atom.aNo, a_atom.aNo, d, a, dist, theta,
                                    [E_coul, E_vdw, E_hbond], dist_ah, alpha
                                ])  # v4

                return hbonds

            hb = calc_hbonds()
            return hb

        #-----------------#

        with concurrent.futures.ProcessPoolExecutor(
                max_workers=workers) as exe:
            for i in exe.map(functools.partial(hard_work), (mybgf, chunk)):
                result[t] = i

    # 5. Analyze
    if not out_file:
        out_file = trj_file + ".kwac.hbonds."
    pickle_file = out_file + ".pickle"
    with open(pickle_file, 'wb') as f:
        pickle.dump(result, f, protocol=pickle.HIGHEST_PROTOCOL)
        print("Success to save the result to a pickle file %s" % pickle_file)
예제 #6
0
def main(bgf_filename, grps_filename, margin):

    # initialization
    grps_original_filename = grps_filename + ".original"
    warn = ""

    # keep original grps file at the first run
    if not os.path.exists(grps_original_filename):
        shutil.copy(grps_filename, grps_original_filename)

    # read atoms from bgf file
    mybgf = bgf.BgfFile(bgf_filename)
    pbc = mybgf.CRYSTX[:3]
    swr = 3.270615945 / 2  # (wwr + swr) / 2 (defined by eq. from Pradeep Kumar's 2005 PRL)
    gwr = 3.057430885 / 2  # (wwr + cwr) / 2

    # wrap water molecules
    #mybgf = bt.periodicMoleculeSort(mybgf, pbc, selection="'WAT' in atom.rName", silent=False)
    #mybgf.saveBGF(bgf_filename + '.wrap')

    warn += "* Volume assignment from %s to %s" % (bgf_filename, grps_filename)
    '''
    Overall structure of MoS2
    -------------------------

    -----------Gra
    S_3b ----
    Mo      :rNo 2
    S_3a ----
            < layer_distance >
    S_3b ----
    Mo      :rNo 1
    S_3a ----
    -----------Gra
    '''

    # configure regions
    pbc_x = mybgf.CRYSTX[0]
    pbc_y = mybgf.CRYSTX[1]
    pbc_z = mybgf.CRYSTX[2]

    # group 1: MoS2
    avg_s3a_z1 = bt.atoms_average(
        mybgf, 'atom.z',
        selection="'S_3a' in atom.ffType and atom.rNo == 1")  # mos2 bottom
    avg_s3b_z1 = bt.atoms_average(
        mybgf, 'atom.z',
        selection="'S_3b' in atom.ffType and atom.rNo == 1")  # mos2 bottom
    avg_s3a_z2 = bt.atoms_average(
        mybgf, 'atom.z',
        selection="'S_3a' in atom.ffType and atom.rNo == 2")  # mos2 top
    avg_s3b_z2 = bt.atoms_average(
        mybgf, 'atom.z',
        selection="'S_3b' in atom.ffType and atom.rNo == 2")  # mos2 top
    mos2_x = pbc_x
    mos2_y = pbc_y
    mos2_z = avg_s3b_z1 - avg_s3a_z1 + 2 * swr
    warn += "\t** MoS2 region **"
    warn += "\t\t- Effective MoS2 region dimensions: %8.3f %8.3f %8.3f" % (
        mos2_x, mos2_y, mos2_z)

    # group 2: graphene walls
    gwa_y = bt.atoms_average(mybgf, 'atom.y', selection="'GWA' in atom.rName")
    gwb_y = bt.atoms_average(mybgf, 'atom.y', selection="'GWB' in atom.rName")
    graphene_x = pbc_x
    graphene_y = gwb_y - gwa_y + 2 * gwr

    # group 3: "real" inwater
    actual_distance = avg_s3a_z2 - avg_s3b_z1
    inwater_x = pbc_x
    inwater_y = graphene_y - 2 * margin
    inwater_z = actual_distance - 2 * swr  # effective interlayer distance
    graphene_z = pbc_z - mos2_z * 2 - inwater_z  # graphene
    warn += "\t** In-water region **"
    warn += "\t\t- Actual interlayer distance: %8.3f" % actual_distance
    warn += "\t\t- Effective water region dimensions: %8.3f %8.3f %8.3f" % (
        inwater_x, inwater_y, inwater_z)

    # group 4: marginal inwater
    marginal_inwater_x = inwater_x
    marginal_inwater_y = 2 * margin
    marginal_inwater_z = inwater_z

    # group 5: marginal reservoir
    marginal_outwater_x = pbc_x
    marginal_outwater_y = 2 * margin
    marginal_outwater_z = pbc_z

    # group 6: "real" reservoir
    outwater_x = pbc_x
    outwater_y = pbc_y - graphene_y - 2 * margin
    outwater_z = pbc_z
    warn += "\t** Reservoir water region **"
    warn += "\t\t- dimensions: %8.3f %8.3f %8.3f" % (outwater_x, outwater_y,
                                                     outwater_z)

    # find water locations
    all_molecules = bt.getMoleculeList(mybgf)
    all_ow = [
        atom.aNo for atom in mybgf.a
        if 'OW' in atom.ffType or 'HW' in atom.ffType
    ]
    inwaters_ow = [
        atom.aNo for atom in mybgf.a
        if (atom.y > gwa_y + margin and atom.y < gwb_y -
            margin and 'OW' in atom.ffType)
    ]
    marginal_inwaters_ow = [
        atom.aNo for atom in mybgf.a if
        ((atom.y > gwa_y and atom.y < gwa_y + margin) or
         (atom.y > gwb_y - margin and atom.y < gwb_y)) and 'OW' in atom.ffType
    ]  # marginal inwater
    inwaters_ow_nomargin = [
        atom.aNo for atom in mybgf.a
        if (atom.y > gwa_y and atom.y < gwb_y and 'OW' in atom.ffType)
    ]
    marginal_outwaters_ow = [
        atom.aNo for atom in mybgf.a if
        ((atom.y > gwa_y - margin and atom.y < gwa_y) or
         (atom.y > gwb_y and atom.y < gwb_y + margin)) and 'OW' in atom.ffType
    ]  # marginal outwater
    outwaters_ow = [
        atom.aNo for atom in mybgf.a if not atom.aNo in inwaters_ow
        and not atom.aNo in marginal_outwaters_ow
        and not atom.aNo in marginal_inwaters_ow and 'OW' in atom.ffType
    ]  # real outwater

    print(
        "inwaters_vmd:  same residue as (y > {gwa_y} + {margin} and y < {gwb_y} - {margin} and type OW)"
        .format(**vars()))
    print(
        "marginal_inwaters_vmd:  same residue as (((y > {gwa_y} and y < {gwa_y} + {margin}) or (y > {gwb_y} - {margin} and y < {gwb_y})) and type OW)"
        .format(**vars()))
    print(
        "inwaters_vmd_nomargin:  same residue as (y > {gwa_y} and y < {gwb_y} and type OW)"
        .format(**vars()))
    print(
        "marginal_outwaters_vmd:  same residue as (((y > {gwa_y} - {margin} and y < {gwa_y}) or (y > {gwb_y} and y < {gwb_y} + {margin})) and type OW)"
        .format(**vars()))

    if len(inwaters_ow_nomargin
           ) != len(inwaters_ow) + len(marginal_inwaters_ow):
        nu.warn(
            "\t- About %s water molecules are discarded out of %s atoms located near the border."
            % (diff, len(inwaters_ow_nomargin)))

    warn += "\t- Margin specified: %8.3f\n" % margin

    # record aNo
    def get_atoms(lst):
        result = []
        for ano in lst:
            atom = mybgf.getAtom(ano)
            result.append(atom.aNo)
            for i in atom.CONECT:
                result.append(i)
        return result

    inwaters = get_atoms(inwaters_ow)
    marginal_inwaters = get_atoms(marginal_inwaters_ow)
    marginal_outwaters = get_atoms(marginal_outwaters_ow)
    outwaters = get_atoms(outwaters_ow)

    if not (len(inwaters) % 3 == 0 and len(marginal_inwaters) % 3 == 0
            and len(marginal_outwaters) % 3 == 0 and len(outwaters) % 3 == 0):
        warn += "----- Suspicious water molecules division found!!!! -----\n"

    # calculate volume
    vol_mos2 = mos2_x * mos2_y * mos2_z
    vol_graphene = graphene_x * graphene_y * graphene_z
    vol_inwater = inwater_x * inwater_y * inwater_z
    vol_marginal_inwater = marginal_inwater_x * marginal_inwater_y * marginal_inwater_z
    vol_outwater = outwater_x * outwater_y * outwater_z
    vol_marginal_outwater = marginal_outwater_x * marginal_outwater_y * marginal_outwater_z

    vol_total = pbc_x * pbc_y * pbc_z
    vol_sum = vol_mos2 + vol_graphene + vol_inwater + vol_marginal_inwater + vol_outwater + vol_marginal_outwater
    '''
    # compute stats
    nu.warn("** Stats for confined water **")
    mass_inwater = 18.0154 * len(inwaters_ow)
    density_inwater = mass_inwater / vol_inwater / 6.022 * 10
    nu.warn("\t- Number: %d" % len(inwaters_ow))
    nu.warn("\t- Density: %8.5f" % density_inwater)
    '''
    # compute stats
    warn += "\n\n\t**** Stats for confined water ****\n"
    warn += "\t- Number:\n"
    warn += "\t\t real inwater / marginal inwater / marginal outwater / real outwater: %d %d %d %d\n" % (
        len(inwaters_ow), len(marginal_inwaters_ow),
        len(marginal_outwaters_ow), len(outwaters_ow))
    warn += "\t\t (%5.1f %%  %5.1f %%  %5.1f %%  %5.1f %%)\n" % (
        float(len(inwaters_ow)) / len(all_ow) * 100,
        float(len(marginal_inwaters_ow)) / len(all_ow) * 100,
        float(len(marginal_outwaters_ow)) / len(all_ow) * 100,
        float(len(outwaters_ow)) / len(all_ow) * 100)

    warn += "\t- Volumes: \n"
    warn += "\t\tvol_mos2: %.3f = %.3f * %.3f * %.3f\n" % (vol_mos2, mos2_x,
                                                           mos2_y, mos2_z)
    warn += "\t\tvol_graphene: %.3f = %.3f * %.3f * %.3f\n" % (
        vol_graphene, graphene_x, graphene_y, graphene_z)
    warn += "\t\tvol_inwater: %.3f = %.3f * %.3f * %.3f\n" % (
        vol_inwater, inwater_x, inwater_y, inwater_z)
    warn += "\t\tvol_marginal_inwater: %.3f = %.3f * %.3f * %.3f\n" % (
        vol_marginal_inwater, marginal_inwater_x, marginal_inwater_y,
        marginal_inwater_z)
    warn += "\t\tvol_marginal_outwater: %.3f = %.3f * %.3f * %.3f\n" % (
        vol_marginal_outwater, marginal_outwater_x, marginal_outwater_y,
        marginal_outwater_z)
    warn += "\t\tvol_outwater: %.3f = %.3f * %.3f * %.3f\n" % (
        vol_outwater, outwater_x, outwater_y, outwater_z)

    if vol_sum != vol_total:
        warn += "\n\t\t----- Suspicious volume division found!!!! Density might be different -----\n"
        warn += "\t\tTotal volume: %8.3f, Sum of divisions: %8.3f\n" % (
            vol_total, vol_sum)

    warn += "\t- Density:\n"
    density_inwater = 18.0154 * len(inwaters_ow) / vol_inwater / 6.022 * 10
    density_marginal_inwater = 18.0154 * len(
        marginal_inwaters_ow) / vol_marginal_inwater / 6.022 * 10
    density_marginal_outwater = 18.0154 * len(
        marginal_outwaters_ow) / vol_marginal_outwater / 6.022 * 10
    density_outwater = 18.0154 * len(outwaters_ow) / vol_outwater / 6.022 * 10
    warn += "\t\t real inwater / marginal inwater / marginal outwater / real outwater: %.3f %.3f %.3f %.3f\n" % (
        density_inwater, density_marginal_inwater, density_marginal_outwater,
        density_outwater)

    # separate water group into inwater and outwater
    warn += "\tModifying grps file %s.." % sys.argv[0]
    g = grpfile(grps_original_filename)
    #new_group_no = g.split_group(2, outwaters)
    marginal_inwater_group_no = g.split_group(2, marginal_inwaters)
    marginal_outwater_group_no = g.split_group(2, marginal_outwaters)
    outwater_group_no = g.split_group(2, outwaters)
    g.grp[1]['volume'] = vol_mos2 + vol_graphene
    g.grp[2]['volume'] = vol_inwater
    g.grp[marginal_inwater_group_no]['volume'] = vol_marginal_inwater
    g.grp[marginal_outwater_group_no]['volume'] = vol_marginal_outwater
    g.grp[outwater_group_no]['volume'] = vol_outwater

    #g.write(grps_filename, zip=False)
    g.write(grps_filename, zip=True)

    warn += "%s: Done." % sys.argv[0]

    print(
        "Numbers: real inwater / marginal inwater / marginal outwater / real outwater: %d %d %d %d"
        % (len(inwaters_ow), len(marginal_inwaters_ow),
           len(marginal_outwaters_ow), len(outwaters_ow)))
    print(
        "Density: real inwater / marginal inwater / marginal outwater / real outwater: %.3f %.3f %.3f %.3f"
        % (density_inwater, density_marginal_inwater,
           density_marginal_outwater, density_outwater))
def main(bgf_filename, grps_filename, margin=0.0):

    # initialization
    grps_original_filename = grps_filename + ".original"

    # keep original grps file at the first run
    if not os.path.exists(grps_original_filename):
        shutil.copy(grps_filename, grps_original_filename)

    # read atoms from bgf file
    mybgf = bgf.BgfFile(bgf_filename)
    pbc = mybgf.CRYSTX[:3]
    swr = 3.270615945 / 2  # (wwr + swr) / 2 (defined by eq. from Pradeep Kumar's 2005 PRL)
    gwr = 3.057430885 / 2  # (wwr + cwr) / 2

    # wrap water molecules
    #mybgf = bt.periodicMoleculeSort(mybgf, pbc, selection="'WAT' in atom.rName", silent=False)
    #mybgf.saveBGF(bgf_filename + '.wrap')

    nu.warn("* Volume assignment from %s to %s" %
            (bgf_filename, grps_filename))
    '''
    Overall structure of MoS2
    -------------------------

    -----------Gra
    S_3b ----
    Mo      :rNo 2
    S_3a ----
            < layer_distance >
    S_3b ----
    Mo      :rNo 1
    S_3a ----
    -----------Gra
    '''

    # configure regions
    pbc_x = mybgf.CRYSTX[0]
    pbc_y = mybgf.CRYSTX[1]
    pbc_z = mybgf.CRYSTX[2]

    # group 1: MoS2
    avg_s3a_z1 = bt.atoms_average(
        mybgf, 'atom.z',
        selection="'S_3a' in atom.ffType and atom.rNo == 1")  # mos2 bottom
    avg_s3b_z1 = bt.atoms_average(
        mybgf, 'atom.z',
        selection="'S_3b' in atom.ffType and atom.rNo == 1")  # mos2 bottom
    avg_s3a_z2 = bt.atoms_average(
        mybgf, 'atom.z',
        selection="'S_3a' in atom.ffType and atom.rNo == 2")  # mos2 top
    avg_s3b_z2 = bt.atoms_average(
        mybgf, 'atom.z',
        selection="'S_3b' in atom.ffType and atom.rNo == 2")  # mos2 top
    mos2_x = pbc_x
    mos2_y = pbc_y
    mos2_z = avg_s3b_z1 - avg_s3a_z1 + 2 * swr
    nu.warn("\t** MoS2 region **")
    nu.warn("\t\t- Effective MoS2 region dimensions: %8.3f %8.3f %8.3f" %
            (mos2_x, mos2_y, mos2_z))

    # group 2: graphene walls
    gwa_y = bt.atoms_average(mybgf, 'atom.y', selection="'GWA' in atom.rName")
    gwb_y = bt.atoms_average(mybgf, 'atom.y', selection="'GWB' in atom.rName")
    graphene_x = pbc_x
    graphene_y = gwb_y - gwa_y + 2 * gwr

    # group 3: inwater
    actual_distance = avg_s3a_z2 - avg_s3b_z1
    inwater_x = pbc_x
    inwater_y = graphene_y - 2 * margin
    inwater_z = actual_distance - 2 * swr  # effective interlayer distance
    graphene_z = pbc_z - mos2_z * 2 - inwater_z  # graphene
    nu.warn("\t** In-water region **")
    nu.warn("\t\t- Actual interlayer distance: %8.3f" % actual_distance)
    nu.warn("\t\t- Effective water region dimensions: %8.3f %8.3f %8.3f" %
            (inwater_x, inwater_y, inwater_z))

    # group 4: reservoir
    outwater_x = pbc_x
    outwater_y = pbc_y - graphene_y
    outwater_z = pbc_z
    nu.warn("\t** Reservoir water region **")
    nu.warn("\t\t- dimensions: %8.3f %8.3f %8.3f" %
            (outwater_x, outwater_y, outwater_z))

    # find water locations
    all_molecules = bt.getMoleculeList(mybgf)
    all_ow = [
        atom.aNo for atom in mybgf.a
        if 'OW' in atom.ffType or 'HW' in atom.ffType
    ]
    inwaters_ow = [
        atom.aNo for atom in mybgf.a
        if (atom.y > gwa_y + margin and atom.y < gwb_y -
            margin and 'OW' in atom.ffType)
    ]
    inwaters_ow_nomargin = [
        atom.aNo for atom in mybgf.a
        if (atom.y > gwa_y and atom.y < gwb_y and 'OW' in atom.ffType)
    ]

    if margin:
        nu.warn("\t- Margin specified: %8.3f" % margin)
        diff = len(inwaters_ow_nomargin) - len(inwaters_ow)
        if diff:
            nu.warn(
                "\t- About %s water molecules are discarded out of %s atoms located near the border."
                % (diff, len(inwaters_ow_nomargin)))

    # record inwater aNo
    inwaters = []
    for ano in inwaters_ow:
        atom = mybgf.getAtom(ano)
        inwaters.append(atom.aNo)
        for i in atom.CONECT:
            inwaters.append(i)

    outwaters = [i for i in all_ow if not i in inwaters]
    nu.warn("** Distinguishing water positions **")
    nu.warn("\t- Found %d atoms in in-water region (%8.3f molecules)" %
            (len(inwaters), (len(inwaters) / 3.0)))
    nu.warn("\t- Found %d atoms in reservoir region (%8.3f molecules)" %
            (len(outwaters), (len(outwaters) / 3.0)))
    debug_selection = "same residue as (y > %8.3f and y < %8.3f and type OW)" % (
        gwa_y, gwb_y)
    nu.warn("VMD selection for inwaters: %s" % debug_selection)

    # calculate volume
    vol_mos2 = mos2_x * mos2_y * mos2_z
    vol_graphene = graphene_x * graphene_y * graphene_z
    vol_inwater = inwater_x * inwater_y * inwater_z
    vol_outwater = outwater_x * outwater_y * outwater_z

    # compute stats
    nu.warn("** Stats for confined water **")
    mass_inwater = 18.0154 * len(inwaters_ow)
    density_inwater = mass_inwater / vol_inwater / 6.022 * 10
    nu.warn("\t- Number: %d" % len(inwaters_ow))
    nu.warn("\t- Density: %8.5f" % density_inwater)

    # separate water group into inwater and outwater
    nu.warn("\tModifying grps file %s.." % sys.argv[0])
    g = grpfile(grps_original_filename)
    if len(g.grp) == 3:
        new_group_no = g.split_group(3, outwaters)
        g.grp[1]['volume'] = vol_mos2
        g.grp[2]['volume'] = vol_graphene
        g.grp[3]['volume'] = vol_inwater
        g.grp[4]['volume'] = vol_outwater
    elif len(g.grp) == 2:
        new_group_no = g.split_group(2, outwaters)
        g.grp[1]['volume'] = vol_mos2 + vol_graphene
        g.grp[2]['volume'] = vol_inwater
        g.grp[3]['volume'] = vol_outwater
    else:
        nu.die("Error on group numbers on %s" % grps_original_filename)

    #g.write(grps_filename, zip=False)
    g.write(grps_filename, zip=True)

    nu.warn("%s: Done." % sys.argv[0])
예제 #8
0
usage = """
avoid.py bgffile outfile fffile
"""
if len(sys.argv) < 2:
    print usage
    sys.exit(0)

print(sys.argv)

b = bgf.BgfFile(sys.argv[1])
if len(sys.argv) <= 3:
    ff = os.environ['FF_CNT'].replace("'", "")
else:
    ff = sys.argv[3]

mols = bgftools.getMoleculeList(b)

# GRA 1 : bottom sheet
# GRA 2 : top sheet
top = 0.0
bottom = 0.0
for atom in b.a:
    if "GRA" in atom.rName:
        if atom.rNo == 1:
            bottom = atom.z
        elif atom.rNo == 2:
            top = atom.z

if top and bottom:
    print("Found two graphene sheets.")
else:
예제 #9
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
예제 #10
0
    "_temp.bgf", ff_file, "_temp.bgf")
nu.shutup()
os.system(addsolvent_cmd)
nu.say()

# empty center water
result = bgf.BgfFile('_temp.bgf')
min_mo_x1, max_mo_x1 = bt.atoms_minmax(
    result, 'atom.x', selection="'Mo' in atom.ffType and atom.rNo == 1")
min_mo_y1, max_mo_y1 = bt.atoms_minmax(
    result, 'atom.y', selection="'Mo' in atom.ffType and atom.rNo == 1")
avg_s3a_z1 = bt.atoms_average(
    result, 'atom.z', selection="'S_3a' in atom.ffType and atom.rNo == 1")
avg_s3b_z2 = bt.atoms_average(
    result, 'atom.z', selection="'S_3b' in atom.ffType and atom.rNo == 2")
all_molecules = bt.getMoleculeList(result)
del_list = []
mos2_coords = []
for atom in result.a:
    if "MOS" in atom.rName:
        mos2_coords.append([atom.x, atom.y, atom.z])

mos2_tree = scipy.spatial.KDTree(mos2_coords, leafsize=len(mos2_coords) + 1)

for molecule in tqdm.tqdm(all_molecules,
                          ncols=120,
                          desc='Removing bad contacts'):
    if not len(molecule) == 3: continue  # applies only to water

    cx, cy, cz = bt.getCom(result,
                           ff_file=ff_file,
예제 #11
0
def getHbond(bgf_file, trj_file, ff_file='', selection='', out_file=''):
    '''analyze something within a timestep in a series of lammps trajectory.
    '''
    # variables
    result = dict()

    # inner functions
    def get_line(file):
        with open(file, 'r') as f:
            for line in f:
                yield line

    # 1. Load BGF
    mybgf = bgf.BgfFile(bgf_file)
    N_BGF_ATOMS = len(mybgf.a)
    atom_frags = bt.getMoleculeList(mybgf)

    # 2. Read LAMMPS Trajectory
    mytrj = lt.lammpstrj(trj_file)
    mytrj.load()
    timesteps = sorted(mytrj.timesteps)
    N_HEADER = mytrj.nheader
    N_ATOMS = mytrj.natoms[timesteps[0]]
    N_BUFFER = N_HEADER + N_ATOMS
    if N_BGF_ATOMS != N_ATOMS:
        nu.die(
            "Number of atoms in trajectory file does not match with BGF file.")

    # 3. Determine dump style
    dump_keywords = mytrj._dump_style
    yes_scale = False
    if 'xs' in dump_keywords:
        yes_scale = True

    # 4. Update coordinates from the snapshot
    dump = get_line(trj_file)
    for t in tqdm.tqdm(timesteps, ncols=120, desc="Analyzing HBonds"):
        chunk = [next(dump) for i in range(N_BUFFER)]

        mybgf = update_coord(chunk, mybgf, mytrj.pbc[t], scaled=yes_scale)
        mybgf = bt.periodicMoleculeSort(mybgf,
                                        mybgf.CRYSTX,
                                        fragments=atom_frags,
                                        ff_file=ff_file,
                                        silent=True)

        ### collect data
        def calc_hbonds():
            # variables
            A = []
            D = []
            hbonds = []
            d_crit = 3.5
            a_crit = 30.0

            for atom in mybgf.a:
                if selection:
                    if "O" in atom.ffType and eval(selection):
                        A.append(atom)
                    if "O" in atom.ffType and eval(selection):
                        D.append(atom)
                else:
                    if "O" in atom.ffType:
                        A.append(atom)
                    if "O" in atom.ffType:
                        D.append(atom)
            if not len(A) or not len(D):
                nu.die(
                    "There are no atoms which can make H_bond (O atoms so far)!"
                )

            # calculate hbonds
            for d_atom in D:
                d = np.array([d_atom.x, d_atom.y, d_atom.z])  # donor coord
                neigh_anos = bt.get_neighbors_aNo(A,
                                                  d,
                                                  r=d_crit,
                                                  pbc=mytrj.pbc[t],
                                                  k=6)
                donors = [d_atom.aNo] + d_atom.CONECT

                for ano in neigh_anos:
                    a_atom = mybgf.getAtom(ano)
                    a = np.array([a_atom.x, a_atom.y,
                                  a_atom.z])  # acceptor coord
                    acceptors = [a_atom.aNo] + a_atom.CONECT

                    for ano in d_atom.CONECT:
                        h_atom = mybgf.getAtom(ano)
                        h = np.array([h_atom.x, h_atom.y, h_atom.z])
                        u = h - d
                        v = a - d
                        theta = np.dot(u, v) / norm(u) / norm(v)
                        theta = np.degrees(arccos(theta))
                        if theta < a_crit:  # HBond exists
                            dist = nu.pbc_dist(a, d, mytrj.pbc[t])
                            dist_ah = nu.pbc_dist(d, h, mytrj.pbc[t])

                            # E_vdw
                            sigma_r = O_sigma / dist
                            sigma_r_6 = sigma_r**6
                            sigma_r_12 = sigma_r**12
                            E_vdw = 4.0 * O_epsilon * (sigma_r_12 - sigma_r_6)
                            # E_vdw in kcal/mol

                            # E_coul
                            E_coul = 0.0
                            for i, j in itertools.product(donors, acceptors):
                                atom1 = mybgf.getAtom(i)
                                atom2 = mybgf.getAtom(j)
                                a1 = [atom1.x, atom1.y, atom1.z]
                                a2 = [atom2.x, atom2.y, atom2.z]
                                dist_ij = nu.pbc_dist(a1, a2, mytrj.pbc[t])
                                E_coul += 332.06371 * atom1.charge * atom2.charge / dist_ij  # E_coul in kcal/mol

                            # E_hbond
                            E_hbond = E_coul + E_vdw  # E_hbond = E_vdw + E_coul

                            # update for v4
                            # angle between H-O-H plane and O..O vector
                            H1 = mybgf.getAtom(d_atom.CONECT[0])
                            h1 = [H1.x, H1.y, H1.z]  # H1
                            H2 = mybgf.getAtom(d_atom.CONECT[1])
                            h2 = [H2.x, H2.y, H2.z]  # H2
                            p = d - h1
                            q = d - h2
                            n = np.cross(
                                p, q)  # normal vector of the H1-O-H2 plane
                            m = a - d
                            # O..O vector
                            alpha = np.dot(n, m) / norm(n) / norm(m)
                            alpha = np.degrees(
                                arcsin(alpha)
                            )  # angle between H-O-H plane and O..O vector

                            #hbonds.append([d_atom.aNo, a_atom.aNo, d, a, dist, theta, [E_coul, E_vdw, E_hbond]])  # v2
                            #hbonds.append([d_atom.aNo, a_atom.aNo, d, a, dist, theta, [E_coul, E_vdw, E_hbond], dist_ah])   # v3
                            hbonds.append([
                                d_atom.aNo, a_atom.aNo, d, a, dist, theta,
                                [E_coul, E_vdw, E_hbond], dist_ah, alpha
                            ])  # v4

            return hbonds

        hbonds = calc_hbonds()
        result[t] = hbonds

        #break; # tester

    # 5. Analyze
    if not out_file:
        out_file = trj_file + ".hbonds.v4"
    pickle_file = out_file + ".pickle"
    with open(pickle_file, 'wb') as f:
        pickle.dump(result, f, protocol=pickle.HIGHEST_PROTOCOL)
        print("Success to save the result to a pickle file %s" % pickle_file)
예제 #12
0
def addsolvent(bgf_file,
               solvent_bgf,
               min,
               max,
               n_solvent,
               out_file,
               ff_file,
               margin,
               mark,
               silent=True):

    ### initialize
    water = False
    default_margin = 1.0
    x_margin = 0.0
    y_margin = 0.0
    z_margin = 0.0
    if "x" in margin.lower():
        x_margin = default_margin
    if "y" in margin.lower():
        y_margin = default_margin
    if "z" in margin.lower():
        z_margin = default_margin

    ### load the solute bgf file
    if not silent: print("Initializing..")
    myBGF = bgf.BgfFile(bgf_file)  # str
    myBGF.renumber()

    if not silent: print("Loading the solvent file " + solvent_bgf + " ..")
    solventBGF = bgf.BgfFile(solvent_bgf)

    ### Generate error when the solvent box is not periodic:
    if not solventBGF.PERIOD:
        nu.die(
            "addSolvent: The solvent file is not periodic. Use a box full of solvent."
        )

    ### Check the type of solvent
    if not silent:
        print("(the solvent box seems to be full of " +
              os.path.basename(solvent_file)[:-4] + " )")
    if "f3c" in solvent_bgf:
        water = True  # this flag is used to remove the bad contacts with the molecule.
    if "spc" in solvent_bgf:
        water = True  # this flag is used to remove the bad contacts with the molecule.
    if "tip" in solvent_bgf:
        water = True  # this flag is used to remove the bad contacts with the molecule.

    ### calculate the box size
    if not silent: print("Analyzing box information..")
    if not min:
        min = [0.0, 0.0, 0.0]
    if not max:
        max = myBGF.CRYSTX[:3]

    strsize = [
        max[0] - min[0] - x_margin, max[1] - min[1] - y_margin,
        max[2] - min[2] - z_margin
    ]

    waterboxsize = solventBGF.CRYSTX[:3]  # REMARK: This is a kind of constant.
    copyNumber = [0, 0, 0]
    for index, i in enumerate(copyNumber):
        copyNumber[index] = math.ceil(
            strsize[index] /
            waterboxsize[index])  # how many times to replicate the water box

    if not silent: print("Creating box information: " + str(strsize))

    ### replicate the solvent box
    if not silent: print("Creating box.. this may take some time.")
    bigboxBGF = bgftools.replicateCell(solventBGF, copyNumber, True)
    bigboxBGF.saveBGF("_replicate.bgf")
    if not silent:
        print("- Number of atoms in the created box: " + str(len(bigboxBGF.a)))
    delatom = []
    delsolvent = []
    delsolventindex = []
    delwater = []
    delwaterindex = []

    bigboxBGF = bgf.BgfFile("_replicate.bgf")
    bigboxBGF.renumber()

    ### trim the water box
    if water:
        if not silent:
            print("Generating water box.. Calculating water molecules")
        for atom in bigboxBGF.a:
            if atom.x > strsize[0] or atom.y > strsize[1] or atom.z > strsize[
                    2]:
                delatom.append(atom.aNo)
        for aNo in delatom:
            water_molecule = bgftools.is_water(bigboxBGF, aNo)
            if not water_molecule in delwater:
                delwater.append(water_molecule)
        delwater = nu.flatten(delwater)
        delwater = nu.removeRepeat(delwater)
        for aNo in delwater:
            delwaterindex.append(bigboxBGF.a2i[aNo])
        if not silent: print("Generating water box.. Trimming")
        bigboxBGF.delAtoms(delwaterindex, False)
        bigboxBGF.renumber()
    elif not water:
        if not silent:
            print("Generating solvent box.. Extracting solvent molecules")
        for atom in tqdm.tqdm(bigboxBGF.a, desc='Iterating', ncols=120):
            if atom.x > strsize[0] or atom.y > strsize[1] or atom.z > strsize[
                    2]:
                delatom.append(atom.aNo)

        molecule = bgftools.getMoleculeList(bigboxBGF)
        for aNo in tqdm.tqdm(delatom,
                             desc='Appending atoms to remove',
                             ncols=120):
            for i in molecule:
                if aNo in i:
                    delsolvent += i
                    break
        delsolvent = list(set(delsolvent))
        for aNo in delsolvent:
            delsolventindex.append(bigboxBGF.a2i[aNo])
        if not silent: print("Generating solvent box.. Trimming")
        delsolventindex.sort()
        #delsolventindex.reverse()
        bigboxBGF.delAtoms(delsolventindex, False)
        bigboxBGF.renumber()

    bigboxBGF.saveBGF("_temp.bgf")  ## debug

    ### remain n molecules and delete residues
    bigboxBGF = bgftools.renumberMolecules(bigboxBGF, 0, False)  # renumber rNo

    if n_solvent:
        residues = set()
        for atom in bigboxBGF.a:
            residues.add(atom.rNo)  # scan molecule rNo
        residues = list(residues)
        if not silent: print("Found %d water molecules." % len(residues))
        if len(residues) < n_solvent:
            nu.die("Too few solvent molecules to choose %d molecules." %
                   n_solvent)

        rNos = random.sample(residues, n_solvent)  # select n molecules
        if not silent: print("%d water molecules are chosen." % n_solvent)

        # delete molecules
        delist = []
        for atom in bigboxBGF.a:
            if not atom.rNo in rNos:
                delist.append(bigboxBGF.a2i[atom.aNo])  # if not chosen, delete
        delist.sort()
        bigboxBGF.delAtoms(delist, False)
        bigboxBGF.renumber()

        bigboxBGF = bgftools.renumberMolecules(bigboxBGF, 0, False)

    ### move the water box to min position
    for atom in bigboxBGF.a:
        atom.x += min[0] + x_margin / 2
        atom.y += min[1] + y_margin / 2
        atom.z += min[2] + z_margin / 2

    ### add mark to the solvents
    if mark:
        for atom in bigboxBGF.a:
            atom.chain = mark

    bigboxBGF.saveBGF('_temp.bgf')

    # REMARK: it is natural to have the periodic information of water box for the output BGF file.
    # REMARK: HETATOM should be located on the first of the BGF file. So use dummy for merging.
    ## compute stats for adding solvents
    if not silent: print("\nComputing stats..")
    mol_list = bgftools.getMoleculeList(bigboxBGF)
    n_mol = len(mol_list)
    n_atom = len(nu.flatten(mol_list))
    if not silent:
        print(
            str(n_mol) + " molecules (" + str(n_atom) +
            " atoms) will be added.")

    ## merge
    #bigboxBGF = myBGF.merge(bigboxBGF, True)
    myBGF = bgf.BgfFile(bgf_file)
    bigboxBGF = bgf.BgfFile("_temp.bgf")
    bigboxBGF2 = myBGF.merge(bigboxBGF)
    if not silent: print("Total atoms in the file: " + str(len(bigboxBGF.a)))

    ## some paperworking for periodic box
    bigboxBGF2.OTHER = myBGF.OTHER
    bigboxBGF2.PERIOD = myBGF.PERIOD
    bigboxBGF2.AXES = myBGF.AXES
    bigboxBGF2.SGNAME = myBGF.SGNAME
    bigboxBGF2.CRYSTX = myBGF.CRYSTX
    bigboxBGF2.CELLS = myBGF.CELLS

    ### record BGF remarks
    bigboxBGF2.REMARK.insert(
        0, "Solvents added by " + os.path.basename(sys.argv[0]) + " by " +
        os.environ["USER"] + " on " + time.asctime(time.gmtime()))
    bigboxBGF2.REMARK.insert(0, "Solvents: " + str(solvent_file))

    ### save BGF
    if not silent: print("Saving the file.. see " + str(out_file))
    bigboxBGF2.saveBGF(out_file)

    return 1
예제 #13
0
def main(bgf_file, out_file, ff_file="", n=0, density=0.9, r=1.0):
    n_total_trial = 0
    # if molecule numbers are not specified, create the box with the existing molecules in the BGF file.
    # if molecule numbers specified, copy the molecules in the box as many as the number specified.
    if n:
        import copy
        mybgf = bgf.BgfFile()
        id = 0
        for i in tqdm.tqdm(range(int(n)), desc="Cloaning molecules",
                           ncols=120):
            id += 1
            mybgf2 = bgf.BgfFile(bgf_file)
            for i in mybgf2.a:
                i.rNo = id
            mybgf = mybgf.merge(mybgf2)
    else:
        mybgf = bgf.BgfFile(bgf_file)

    # calculate cubic size
    mass = bt.getMass(mybgf, ff_file=ff_file)
    target_density = density
    volume = mass / target_density / 6.022 * 10
    cell_x = math.pow(volume, 1.0 / 3)
    print("The script will generate a cubic with dimensions %f^3" % cell_x)
    mybgf.CRYSTX = [cell_x, cell_x, cell_x, 90.0, 90.0, 90.0]

    # get com
    redefined_coords = []
    molecules = bt.getMoleculeList(mybgf)
    for mol in tqdm.tqdm(molecules, ncols=120):
        #for index, mol in enumerate(molecules):
        n_trial = 0
        while True:
            n_trial += 1
            n_total_trial += 1
            cx, cy, cz = bt.getCom(mybgf, ff_file=ff_file, aNo_list=mol)
            new_pos = [random.uniform(0, cell_x) for i in range(3)]
            new_rot = [random.uniform(0, 2 * math.pi) for i in range(3)]
            U = mathtools.rotate_matrix(new_rot[0], new_rot[1], new_rot[2])

            # check the room before lying
            mol_coords = []
            for ano in sorted(mol):
                atom = mybgf.getAtom(ano)
                x = atom.x
                y = atom.y
                z = atom.z
                x -= cx
                y -= cy
                z -= cz

                # rotate
                v = np.matrix([x, y, z]).T
                Uv = U * v
                x = float(Uv[0])
                y = float(Uv[1])
                z = float(Uv[2])

                # move CM to new position
                x += new_pos[0]
                y += new_pos[1]
                z += new_pos[2]

                mol_coords.append([x, y, z])

            # only successful trials can quit the while loop
            if query_safe_coords(redefined_coords, mol_coords, r=r):
                for index, ano in enumerate(sorted(mol)):
                    atom = mybgf.getAtom(ano)
                    atom.x = mol_coords[index][0]
                    atom.y = mol_coords[index][1]
                    atom.z = mol_coords[index][2]

                redefined_coords += mol_coords
                break
            else:
                # fail if too many trials performed
                if n_trial > 1000:
                    print(
                        "Failed to find a suitable coordinates to insert a molecule %s"
                        % mol)
                    sys.exit(0)

    # check
    print("Checking bad contacts..")
    t = scipy.spatial.KDTree(redefined_coords)
    d = t.query_pairs(r)
    if not d:
        print("There are no bad contacts with distance < %.2f" % r)
    else:
        print("Looks there're %d bad contacts" % len(d))

    # save
    mybgf.saveBGF(out_file)
    print("File saved to %s" % out_file)
    print("\n** Stats **")
    print("Total generated coordinates: %d" % n_total_trial)
    print("Number of last trials: %d" % n_trial)
    print("Done.")
예제 #14
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