|
| 1 | +import numpy as np |
| 2 | + |
| 3 | +def rdf(sys, |
| 4 | + sel_type = [None, None], |
| 5 | + max_r = 5, |
| 6 | + nbins = 100) : |
| 7 | + """ |
| 8 | + compute the rdf of a system |
| 9 | +
|
| 10 | + Parameters |
| 11 | + ---------- |
| 12 | + sys : System or LabeledSystem |
| 13 | + The dpdata system |
| 14 | + sel_type: list |
| 15 | + List of size 2. The first element specifies the type of the first atom, |
| 16 | + while the second element specifies the type of the second atom. |
| 17 | + Both elements can be ints or list of ints. |
| 18 | + If the element is None, all types are specified. |
| 19 | + Examples are sel_type = [0, 0], sel_type = [0, [0, 1]] or sel_type = [0, None] |
| 20 | + max_r: float |
| 21 | + Maximal range of rdf calculation |
| 22 | + nbins: int |
| 23 | + Number of bins for rdf calculation |
| 24 | + """ |
| 25 | + return compute_rdf(sys['cells'], sys['coords'], sys['atom_types'], |
| 26 | + sel_type = sel_type, |
| 27 | + max_r = max_r, |
| 28 | + nbins = nbins) |
| 29 | + |
| 30 | +def compute_rdf(box, |
| 31 | + posis, |
| 32 | + atype, |
| 33 | + sel_type = [None, None], |
| 34 | + max_r = 5, |
| 35 | + nbins = 100) : |
| 36 | + nframes = box.shape[0] |
| 37 | + xx = None |
| 38 | + all_rdf = [] |
| 39 | + for ii in range(nframes): |
| 40 | + xx, rdf = _compute_rdf_1frame(box[ii], posis[ii], atype, sel_type, max_r, nbins) |
| 41 | + all_rdf.append(rdf) |
| 42 | + all_rdf = np.array(all_rdf).reshape([nframes, -1]) |
| 43 | + all_rdf = np.average(all_rdf, axis = 0) |
| 44 | + return xx, all_rdf |
| 45 | + |
| 46 | +def _compute_rdf_1frame(box, |
| 47 | + posis, |
| 48 | + atype, |
| 49 | + sel_type = [None, None], |
| 50 | + max_r = 5, |
| 51 | + nbins = 100) : |
| 52 | + all_types = list(set(list(np.sort(atype)))) |
| 53 | + if sel_type[0] is None: |
| 54 | + sel_type[0] = all_types |
| 55 | + if sel_type[1] is None: |
| 56 | + sel_type[1] = all_types |
| 57 | + if type(sel_type[0]) is not list: |
| 58 | + sel_type[0] = [sel_type[0]] |
| 59 | + if type(sel_type[1]) is not list: |
| 60 | + sel_type[1] = [sel_type[1]] |
| 61 | + natoms = len(posis) |
| 62 | + from ase import Atoms |
| 63 | + import ase.neighborlist |
| 64 | + atoms = Atoms(positions=posis, cell=box, pbc=[1,1,1]) |
| 65 | + nlist = ase.neighborlist.NeighborList(max_r, self_interaction=False, bothways=True, primitive=ase.neighborlist.NewPrimitiveNeighborList) |
| 66 | + nlist.update(atoms) |
| 67 | + stat = np.zeros(nbins) |
| 68 | + hh = max_r / float(nbins) |
| 69 | + for ii in range(natoms) : |
| 70 | + # atom "0" |
| 71 | + if atype[ii] in sel_type[0]: |
| 72 | + indices, offsets = nlist.get_neighbors(ii) |
| 73 | + for jj, os in zip(indices, offsets): |
| 74 | + # atom "1" |
| 75 | + if atype[jj] in sel_type[1]: |
| 76 | + posi_jj = atoms.positions[jj] + np.dot(os, atoms.get_cell()) |
| 77 | + diff = posi_jj - atoms.positions[ii] |
| 78 | + dr = np.linalg.norm(diff) |
| 79 | + # if (np.linalg.norm(diff- diff_1)) > 1e-12 : |
| 80 | + # raise RuntimeError |
| 81 | + si = int(dr / hh) |
| 82 | + if si < nbins: |
| 83 | + stat[si] += 1 |
| 84 | + # count the number of atom1 |
| 85 | + c0 = 0 |
| 86 | + for ii in sel_type[0]: |
| 87 | + c0 += np.sum(atype == ii) |
| 88 | + # count the number of atom1 |
| 89 | + c1 = 0 |
| 90 | + for ii in sel_type[1]: |
| 91 | + c1 += np.sum(atype == ii) |
| 92 | + rho1 = c1 / np.linalg.det(box) |
| 93 | + # compute rdf |
| 94 | + for ii in range(nbins): |
| 95 | + vol = 4./3. * np.pi * ( ((ii+1)*hh) ** 3 - ((ii)*hh) ** 3 ) |
| 96 | + rho = stat[ii] / vol |
| 97 | + stat[ii] = rho / rho1 / c0 |
| 98 | + xx = np.arange(0, max_r-1e-12, hh) |
| 99 | + return xx, stat |
| 100 | + |
| 101 | +if __name__ == '__main__': |
| 102 | + import dpdata |
| 103 | + sys = dpdata.System('out.lmp') |
| 104 | + xx, stat = rdf(sys, sel_type = [[0], None], max_r = 8, nbins = 100) |
| 105 | + res = np.concatenate([xx, stat]).reshape([2, -1]) |
| 106 | + np.savetxt('rdf.out', res.T) |
0 commit comments