예제 #1
0
파일: coord.py 프로젝트: mir-group/surfator
def calculate_coord_numbers(traj, atoms, cutoff):
    """Compute the coordination numbers for `mask` atoms at all times in `traj`.

    Args:
        - traj (ndarray n_frames x n_atoms x 3)
        - mask (ndarray bool n_atoms)
        - atoms (ase.Atoms)
        - cutoff (float, distance units)
        - skin (float, distance units, default: 0)
    Returns:
        ndarray of int, n_frames x n_atoms
    """
    n_atoms = len(atoms)

    # Prealloc buffers
    out = np.full(shape=(len(traj), n_atoms), fill_value=-1, dtype=np.int)
    distbuf = np.empty(shape=(n_atoms, n_atoms))
    neighborbuf = np.empty(shape=(n_atoms, n_atoms), dtype=np.bool)

    pbcc = PBCCalculator(atoms.cell)

    for f_idex, frame in enumerate(tqdm(traj)):
        pbcc.pairwise_distances(frame, out=distbuf)
        np.less_equal(distbuf, cutoff, out=neighborbuf)
        np.sum(neighborbuf, axis=1, out=out[f_idex])

    out -= 1  # Previous sum always counted atom itself in its CN, which is wrong

    assert np.min(out) >= 0

    return out
예제 #2
0
    def func(atoms, **kwargs):
        nonlocal pbcc, dmat, connmat, newtags, layer_mask
        # preallocate buffers
        if pbcc is None:
            pbcc = PBCCalculator(atoms.cell)
            dmat = np.empty(shape=(len(atoms), len(atoms)))
            connmat = np.empty(shape=(len(atoms), len(atoms)), dtype=np.bool)
            newtags = np.empty(shape=len(atoms), dtype=np.int)
            layer_mask = np.empty(shape=len(atoms), dtype=np.bool)

        tags = groupfunc(atoms, **kwargs)
        layers = np.unique(tags)
        layers.sort()
        newtags.fill(-1)

        pbcc.pairwise_distances(atoms.positions, out=dmat)
        np.less_equal(dmat, cutoff, out=connmat)

        agreegrp_conns = []
        nexttag = 0
        for layer in layers:
            np.equal(tags, layer, out=layer_mask)
            layer_conrows = connmat[layer_mask]
            layer_conmat = layer_conrows[:, layer_mask]
            n_groups_layer, group_tags = connected_components(layer_conmat,
                                                              directed=False)
            group_tags += nexttag
            newtags[layer_mask] = group_tags
            neighbor_groups = newtags[np.logical_or.reduce(layer_conrows,
                                                           axis=0)]
            agreegrp_conns.append(neighbor_groups)
            nexttag += n_groups_layer

        agreegrp_connmat = np.zeros(shape=(nexttag + 1, nexttag + 1),
                                    dtype=np.bool)
        for agreegrp, neighbors in enumerate(agreegrp_conns):
            agreegrp_connmat[agreegrp, neighbors] = True
        agreegrp_connmat = agreegrp_connmat[:-1, :-1]

        agreegrp_connmat |= agreegrp_connmat.T

        return newtags, np.arange(nexttag), agreegrp_connmat
        def cfunc(sn):
            jl = sn.jump_lag.copy()
            jl -= 1.0  # Center it around 1 since that's the minimum lag, 1 frame
            jl /= jump_lag_sigma
            np.square(jl, out=jl)
            jl *= -0.5
            np.exp(jl, out=jl)  # exp correctly takes the -infs to 0

            jl[sn.jump_lag > jump_lag_cutoff] = 0.

            # Distance term
            pbccalc = PBCCalculator(sn.structure.cell)
            dists = pbccalc.pairwise_distances(sn.centers)
            dmat = dists.copy()

            # We want to strongly boost the similarity of *very* close sites
            dmat /= distance_sigma
            np.square(dmat, out=dmat)
            dmat *= -0.5
            np.exp(dmat, out=dmat)

            return (sn.p_ij + jump_lag_coeff * jl) * (distance_coeff * dmat +
                                                      (1 - distance_coeff))
예제 #4
0
    def _get_sites_to_merge(self, st, coordinating_mask = None):
        sn = st.site_network

        # -- Compute jump statistics
        if not sn.has_attribute('n_ij'):
            ja = JumpAnalysis()
            ja.run(st)

        pos = sn.centers
        if coordinating_mask is None:
            coordinating_mask = sn.static_mask
        else:
            assert not np.any(coordinating_mask & sn.mobile_mask)
        # -- Build images
        mobile_idex = np.where(sn.mobile_mask)[0][0]
        one_mobile_structure = sn.structure[coordinating_mask]
        one_mobile_structure.extend(sn.structure[mobile_idex])
        mobile_idex = -1
        one_mobile_structure.set_calculator(self.calculator)
        interpolation_coeffs = np.linspace(0, 1, self.n_driven_images)
        energies = np.empty(shape = self.n_driven_images)

        # -- Decide on pairs to check
        pbcc = PBCCalculator(sn.structure.cell)
        dists = pbcc.pairwise_distances(pos)
        # At the start, all within distance cutoff are mergable
        mergable = dists <= self.maximum_pairwise_distance
        mergable &= sn.n_ij >= self.minimum_jumps_mergable

        # -- Check pairs' barriers
        # Symmetric, and diagonal is trivially true. Combinations avoids those cases.
        jbuf = pos[0].copy()
        first_calculate = True
        mergable_pairs = (p for p in itertools.combinations(range(sn.n_sites), r = 2) if mergable[p] or mergable[p[1], p[0]])
        n_mergable = (np.sum(mergable) - sn.n_sites) // 2
        for i, j in tqdm(mergable_pairs, total = n_mergable):
            jbuf[:] = pos[j]
            # Get minimage
            _ = pbcc.min_image(pos[i], jbuf)
            # Do coordinate driving
            vector = jbuf - pos[i]
            for image_i in range(self.n_driven_images):
                one_mobile_structure.positions[mobile_idex] = vector
                one_mobile_structure.positions[mobile_idex] *= interpolation_coeffs[image_i]
                one_mobile_structure.positions[mobile_idex] += pos[i]
                energies[image_i] = one_mobile_structure.get_potential_energy()
                first_calculate = False
            # Check barrier
            barrier_idex = np.argmax(energies)
            forward_barrier = energies[barrier_idex] - energies[0]
            backward_barrier = energies[barrier_idex] - energies[-1]
            # If it's an actual maxima barrier between them, then we want to
            # check its height
            if barrier_idex != 0 and barrier_idex != self.n_driven_images - 1:
                mergable[i, j] = forward_barrier <= self.barrier_threshold
                mergable[j, i] = backward_barrier <= self.barrier_threshold
            # Otherwise, if there's no maxima between them, they are in the same
            # basin.

        # Get mergable groups
        n_merged_sites, labels = connected_components(
            mergable,
            directed = True,
            connection = 'strong'
        )
        # MergeSites will check pairwise distances; we just need to make it the
        # right format.
        merge_groups = []
        for lbl in range(n_merged_sites):
            merge_groups.append(np.where(labels == lbl)[0])

        return merge_groups