Esempio n. 1
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
Esempio n. 2
0
    def _plot_edges(self, sn, ax = None, *args, **kwargs):
        if not 'intensity' in self.edge_mappings:
            return []

        pbcc = PBCCalculator(sn.structure.cell)

        n_sites = sn.n_sites
        centers = sn.centers

        # -- Edge attributes
        all_cs = None
        all_linewidths = None
        all_color = None
        all_groups = None
        # Get value arrays as they exist
        for edgekey in self.edge_mappings:
            edgeval = getattr(sn, self.edge_mappings[edgekey])
            if edgekey == 'intensity':
                all_cs = edgeval.copy()
            elif edgekey == 'width':
                all_linewidths = edgeval.copy()
            elif edgekey == 'group':
                assert edgeval.dtype == np.int
                all_groups = edgeval
            else:
                raise KeyError("Invalid edge mapping key `%s`" % edgekey)

        do_widths = not all_linewidths is None
        do_groups = not all_groups is None

        # - Normalize
        # Ignore values on the diagonal since we ignore them in the loop
        diag_mask = np.ones(shape = all_cs.shape, dtype = np.bool)
        np.fill_diagonal(diag_mask, False)

        self._normalize(all_cs, diag_mask)

        if do_widths:
            self._normalize(all_linewidths, diag_mask)

        # -- Construct Line3DCollection segments

        # Whether an edge has already been added
        done_already = np.zeros(shape = (n_sites, n_sites), dtype = np.bool)
        # For the Line3DCollection
        segments = []
        cs = []
        linewidths = []
        groups = []
        # To plot minimum images that are outside unit cell
        sites_to_plot = []
        sites_to_plot_positions = []

        for i in range(n_sites):
            for j in range(n_sites):
                # No self edges
                if i == j:
                    continue
                # If was already done
                if done_already[i, j]:
                    continue
                # Ignore anything below the threshold
                if all_cs[i, j] <= self.min_color_threshold:
                    continue
                if do_widths and all_linewidths[i, j] <= self.min_width_threshold:
                    continue

                segment = np.empty(shape = (2, 3), dtype = centers.dtype)
                segment[0] = centers[i]
                ptbuf = centers[j].copy()

                # Modified segment[1] in place
                minimg = pbcc.min_image(segment[0], ptbuf)
                was_already_min_img = minimg == 111

                segment[1] = ptbuf

                segments.append(segment)

                # If they are eachother's minimum image, then don't bother plotting
                # j -> i
                if was_already_min_img:
                    done_already[j, i] = True
                else:
                    # We'll plot it
                    sites_to_plot.append(j)
                    sites_to_plot_positions.append(segment[1])

                # The mean
                cs.append(np.mean([all_cs[i, j], all_cs[j, i]]))

                if do_widths:
                    linewidths.append(np.mean([all_linewidths[i, j], all_linewidths[j, i]]))
                if do_groups:
                    # Assumes symmetric
                    groups.append(all_groups[i, j])

                done_already[i, j] = True

        # -- Construct final Line3DCollection
        assert len(cs) == len(segments)

        if len(cs) > 0:
            lccolors = np.empty(shape = (len(cs), 4), dtype = np.float)
            # Group colors
            if do_groups:
                for i in range(len(cs)):
                    if groups[i] >= len(SiteNetworkPlotter.EDGE_GROUP_COLORS) - 1:
                        raise ValueError("Too many groups, not enough group colors")
                    lccolors[i] = matplotlib.colors.to_rgba(SiteNetworkPlotter.EDGE_GROUP_COLORS[groups[i]])
            else:
                lccolors[:] = matplotlib.colors.to_rgba(SiteNetworkPlotter.EDGE_GROUP_COLORS[0])
            # Intensity alpha
            lccolors[:,3] = np.array(cs) * self.minmax_edge_alpha[1]
            lccolors[:,3] += self.minmax_edge_alpha[0]

            if do_widths:
                linewidths = np.asarray(linewidths)
                linewidths *= self.minmax_linewidth[1]
                linewidths += self.minmax_linewidth[0]
            else:
                linewidths = self.minmax_linewidth[1] * 0.5

            lc = Line3DCollection(segments, linewidths = linewidths, colors = lccolors, zorder = -20)
            ax.add_collection(lc)

            # -- Plot new sites
            if len(sites_to_plot) > 0:
                sn2 = sn[sites_to_plot]
                sn2.update_centers(np.asarray(sites_to_plot_positions))
                pts_params = dict(self.plot_points_params)
                pts_params['alpha'] = 0.2
                return self._site_layers(sn2, pts_params, same_normalization = True)
            else:
                return []
        else:
            return []
Esempio n. 3
0
    def _build_mic_connmat(self, sn, connectivity_matrix):
        # We use a 3x3x3 = 27 supercell, so there are 27x as many sites
        assert len(sn) == connectivity_matrix.shape[0]

        images = np.asarray(list(itertools.product(range(-1, 2), repeat=3)))
        image_to_idex = dict(
            (100 * (image[0] + 1) + 10 * (image[1] + 1) + (image[2] + 1), i)
            for i, image in enumerate(images))
        n_images = len(images)
        assert n_images == 27

        n_sites = len(sn)
        pos = sn.centers  #.copy() # TODO: copy not needed after reinstall of sitator!
        n_total_sites = len(images) * n_sites
        newmat = lil_matrix((n_total_sites, n_total_sites), dtype=np.bool)

        mask_000 = np.zeros(shape=n_total_sites, dtype=np.bool)
        index_000 = image_to_idex[111]
        mask_000[index_000:index_000 + n_sites] = True
        assert np.sum(mask_000) == len(sn)

        pbcc = PBCCalculator(sn.structure.cell)
        buf = np.empty(shape=3)

        internal_mat = np.zeros_like(connectivity_matrix)
        external_connections = []
        for from_site, to_site in zip(*np.where(connectivity_matrix)):
            buf[:] = pos[to_site]
            if pbcc.min_image(pos[from_site], buf) == 111:
                # If we're in the main image, keep the connection: it's internal
                internal_mat[from_site, to_site] = True
                #internal_mat[to_site, from_site] = True # fake FIXME
            else:
                external_connections.append((from_site, to_site))
                #external_connections.append((to_site, from_site)) # FAKE FIXME

        for image_idex, image in enumerate(images):
            # Make the block diagonal
            newmat[image_idex * n_sites:(image_idex + 1) * n_sites,
                   image_idex * n_sites:(image_idex + 1) *
                   n_sites] = internal_mat

            # Check all external connections from this image; add other sparse entries
            for from_site, to_site in external_connections:
                buf[:] = pos[to_site]
                to_mic = pbcc.min_image(pos[from_site], buf)
                to_in_image = image + [
                    (to_mic // 10**(2 - i) % 10) - 1 for i in range(3)
                ]  # FIXME: is the -1 right
                assert to_in_image is not None, "%s" % to_in_image
                assert np.max(np.abs(to_in_image)) <= 2
                if not np.any(np.abs(to_in_image) > 1):
                    to_in_image = 100 * (to_in_image[0] + 1) + 10 * (
                        to_in_image[1] + 1) + 1 * (to_in_image[2] + 1)
                    newmat[image_idex * n_sites + from_site,
                           image_to_idex[to_in_image] * n_sites +
                           to_site] = True

        assert np.sum(newmat) >= n_images * np.sum(
            internal_mat)  # Lowest it can be is if every one is internal

        return newmat, mask_000, images