Example #1
0
def run_detail(show_plot, save_plot):
    P = Profiler("0. Read data")
    import sys
    file_name = sys.argv[1]
    from xfel.clustering.singleframe import CellOnlyFrame
    cells = []
    for line in open(file_name, "r").xreadlines():
        tokens = line.strip().split()
        cells.append(CellOnlyFrame(args=tokens, path=None))
    MM = [c.mm for c in cells]  # get all metrical matrices
    MM_double = flex.double()
    for i in xrange(len(MM)):
        Tup = MM[i]
        for j in xrange(6):
            MM_double.append(Tup[j])

    print("There are %d cells X" % (len(MM)))
    CX = 0
    CY = 3
    coord_x = flex.double([c.uc[CX] for c in cells])
    coord_y = flex.double([c.uc[CY] for c in cells])
    if show_plot or save_plot:
        import matplotlib
        if not show_plot:
            # http://matplotlib.org/faq/howto_faq.html#generate-images-without-having-a-window-appear
            matplotlib.use('Agg')  # use a non-interactive backend
        from matplotlib import pyplot as plt
        plt.plot(coord_x, coord_y, "k.", markersize=3.)
        #plt.axes().set_aspect("equal")
        if save_plot:
            plt.savefig(plot_name,
                        size_inches=(10, 10),
                        dpi=300,
                        bbox_inches='tight')
        if show_plot:
            plt.show()

    print "Now constructing a Dij matrix."
    P = Profiler("1. compute Dij matrix")
    NN = len(MM)

    from cctbx.uctbx.determine_unit_cell import NCDist_matrix, NCDist_flatten
    #Dij = NCDist_matrix(MM_double)
    Dij = NCDist_flatten(MM_double)

    #from cctbx.uctbx.determine_unit_cell import NCDist # can this be refactored with MPI?
    #Dij = flex.double(flex.grid(NN,NN))
    #for i in xrange(NN):
    #  for j in xrange(i+1,NN):
    #    Dij[i,j] = NCDist(MM[i], MM[j])
    del P

    d_c = 10000  # the distance cutoff, such that average item neighbors 1-2% of all items
    CM = clustering_manager(Dij=Dij, d_c=d_c)

    # Summarize the results here
    n_cluster = 1 + flex.max(CM.cluster_id_final)
    print len(cells), "have been analyzed"
    print("# ------------   %d CLUSTERS  ----------------" % (n_cluster))
    for i in xrange(n_cluster):
        item = flex.first_index(CM.cluster_id_maxima, i)
        print "Cluster %d.  Central unit cell: item %d" % (i, item)
        cells[item].crystal_symmetry.show_summary()
        print "Cluster has %d items, or %d after trimming borders" % (
            (CM.cluster_id_full == i).count(True),
            (CM.cluster_id_final == i).count(True))
        print

    appcolors = [
        'b', 'r', '#ff7f0e', '#2ca02c', '#9467bd', '#8c564b', '#e377c2',
        '#7f7f7f', '#bcbd22', '#17becf'
    ]
    if show_plot:
        #Decision graph
        from matplotlib import pyplot as plt

        plt.plot(CM.rho, CM.delta, "r.", markersize=3.)
        for x in xrange(NN):
            if CM.cluster_id_maxima[x] >= 0:
                plt.plot([CM.rho[x]], [CM.delta[x]], "ro")
        plt.show()

        #No-halo plot
        from matplotlib import pyplot as plt
        colors = [appcolors[i % 10] for i in CM.cluster_id_full]

        plt.scatter(coord_x,
                    coord_y,
                    marker='o',
                    color=colors,
                    linewidths=0.4,
                    edgecolor='k')
        for i in xrange(n_cluster):
            item = flex.first_index(CM.cluster_id_maxima, i)
            plt.plot([cells[item].uc[CX]], [cells[item].uc[CY]], 'y.')
        #plt.axes().set_aspect("equal")
        plt.show()

        #Final plot
        halo = (CM.cluster_id_final == -1)
        core = ~halo
        plt.plot(coord_x.select(halo), coord_y.select(halo), "k.")
        colors = [appcolors[i % 10] for i in CM.cluster_id_final.select(core)]
        plt.scatter(coord_x.select(core),
                    coord_y.select(core),
                    marker="o",
                    color=colors,
                    linewidths=0.4,
                    edgecolor='k')
        for i in xrange(n_cluster):
            item = flex.first_index(CM.cluster_id_maxima, i)
            plt.plot([cells[item].uc[CX]], [cells[item].uc[CY]], 'y.')
        #plt.axes().set_aspect("equal")
        plt.show()
def run_detail(show_plot, save_plot, use_dummy_data=False):
    file_name = sys.argv[1]
    from xfel.clustering.singleframe import CellOnlyFrame
    from cctbx import crystal
    cells = []
    for line in open(file_name, "r").xreadlines():
        tokens = line.strip().split()
        unit_cell = tuple(float(x) for x in tokens[0:6])
        space_group_symbol = tokens[6]
        crystal_symmetry = crystal.symmetry(
            unit_cell=unit_cell, space_group_symbol=space_group_symbol)
        cells.append(CellOnlyFrame(crystal_symmetry, path=None))
    MM = [c.mm for c in cells]  # get all metrical matrices
    from scitbx.array_family import flex
    MM_double = flex.double()
    for i in range(len(MM)):
        Tup = MM[i]
        for j in range(6):
            MM_double.append(Tup[j])

    print("There are %d cells" % (len(MM)))
    if show_plot or save_plot:
        import matplotlib
        if not show_plot:
            # http://matplotlib.org/faq/howto_faq.html#generate-images-without-having-a-window-appear
            matplotlib.use('Agg')  # use a non-interactive backend
        from matplotlib import pyplot as plt
        plt.figure(1)
        plt.plot([c.uc[0] for c in cells], [c.uc[1] for c in cells],
                 "k.",
                 markersize=3.)
        plt.axes().set_aspect("equal")
        if save_plot:
            plt.savefig(plot_name,
                        size_inches=(10, 10),
                        dpi=300,
                        bbox_inches='tight')
        if show_plot:
            plt.show()

    print("Now constructing a Dij matrix.")
    NN = len(MM)
    import omptbx
    omptbx.omp_set_num_threads(64)
    from cctbx.uctbx.determine_unit_cell import NCDist_flatten
    if use_dummy_data:
        '''
      Generate blob data using sklearn. See example here.
      http://scikit-learn.org/stable/auto_examples/cluster/plot_cluster_comparison.html
      '''
        try:
            from sklearn import datasets
        except ImportError:
            print(
                "Module sklearn not available. Needed to generate dummy data.")
        import numpy as np
        NN = 100
        blobs = datasets.make_blobs(n_samples=NN, random_state=22)
        xx = []
        yy = []
        Dij = np.zeros([NN, NN])
        Dij = flex.double(Dij)
        for x, y in blobs[0]:
            xx.append(x)
            yy.append(y)
        # Get Dij matrix
        for i in range(len(xx)):
            for j in range(len(xx)):
                dij2 = (xx[i] - xx[j]) * (xx[i] - xx[j]) + (yy[i] - yy[j]) * (
                    yy[i] - yy[j])
                dij = np.sqrt(dij2)
                Dij[i * len(xx) + j] = dij
        if show_plot:
            import matplotlib.pyplot as plt
            #plt.figure()
            plt.scatter(xx, yy)
            plt.show()
    else:
        Dij = NCDist_flatten(MM_double)  # loop is flattened
    plot_with_dimensional_embedding(Dij / flex.max(Dij), show_plot=show_plot)
def get_uc_consensus(experiments_list,
                     show_plot=False,
                     save_plot=False,
                     return_only_first_indexed_model=False,
                     finalize_method='reindex_with_known_crystal_models',
                     clustering_params=None):
    '''
  Uses the Rodriguez Laio 2014 method to do a hierarchical clustering of the crystal models and
  then vote for the highest consensus crystal mode. Input needs to be a list of experiments object.
  Clustering code taken from github.com/cctbx-xfel/cluster_regression
  Clustering is first done first based on unit cell dimensions. Then for each of the clusters identified,
  a further clustering is done based on orientational matrix A
  '''
    if return_only_first_indexed_model:
        return [experiments_list[0].crystals()[0]], None
    cells = []

    from xfel.clustering.singleframe import CellOnlyFrame
    # Flag for testing Lysozyme data from NKS.Make sure cluster_regression repository is present and configured
    # Program will exit after plots are displayed if this flag is true
    test_nks = False
    if clustering_params is None:
        clustering_params = clustering_iota_scope

    if test_nks:
        from cctbx import crystal
        import libtbx.load_env
        cluster_regression = libtbx.env.find_in_repositories(
            relative_path="cluster_regression", test=os.path.isdir)
        file_name = os.path.join(cluster_regression, 'examples',
                                 'lysozyme1341.txt')
        for line in open(file_name, "r").xreadlines():
            tokens = line.strip().split()
            unit_cell = tuple(float(x) for x in tokens[0:6])
            space_group_symbol = tokens[6]
            crystal_symmetry = crystal.symmetry(
                unit_cell=unit_cell, space_group_symbol=space_group_symbol)
            cells.append(CellOnlyFrame(crystal_symmetry))
    else:
        clustered_experiments_list = flex.int()
        for experiment in experiments_list:
            if len(experiment.crystals()) > 1:
                print('IOTA:Should have only one crystal model')
            crystal_symmetry = experiment.crystals()[0].get_crystal_symmetry()
            cells.append(CellOnlyFrame(crystal_symmetry))
            # Maintain a list which is meaningless right now that will finally contain the
            # final clustering results
            clustered_experiments_list.append(-1)
    MM = [c.mm for c in cells]  # metrical matrices
    MM_double = flex.double()
    for i in range(len(MM)):
        Tup = MM[i]
        for j in range(6):
            MM_double.append(Tup[j])
    print('There are %d cells' % len(MM))
    coord_x = flex.double([c.uc[0] for c in cells])
    coord_y = flex.double([c.uc[1] for c in cells])
    if show_plot or save_plot:
        import matplotlib
        if not show_plot:
            matplotlib.use('Agg')
        import matplotlib.pyplot as plt
        plt.plot([c.uc[0] for c in cells], [c.uc[1] for c in cells],
                 "k.",
                 markersize=3.)
        plt.axes().set_aspect("equal")
    if save_plot:
        plot_name = 'uc_cluster.png'
        plt.savefig(plot_name,
                    size_inches=(10, 10),
                    dpi=300,
                    bbox_inches='tight')
    if show_plot:
        plt.show()
    print('Now constructing a Dij matrix: Starting Unit Cell clustering')
    NN = len(MM)
    from cctbx.uctbx.determine_unit_cell import NCDist_flatten
    Dij = NCDist_flatten(MM_double)
    from scitbx.math import five_number_summary
    d_c = clustering_params.d_c  #five_number_summary(list(Dij))[1]
    d_c = estimate_d_c(Dij)
    #d_c = flex.mean_and_variance(Dij.as_1d()).unweighted_sample_standard_deviation()
    print('d_c = ', d_c)
    if len(cells) < 5:
        return [experiments_list[0].crystals()[0]], None
    CM = clustering_manager(
        Dij=Dij,
        d_c=d_c,
        max_percentile_rho=clustering_params.max_percentile_rho_uc,
        Z_delta=clustering_params.Z_delta,
        strategy='strategy_3')
    n_cluster = 1 + flex.max(CM.cluster_id_final)
    print(len(cells), ' datapoints have been analyzed')
    print('%d CLUSTERS' % n_cluster)
    for i in range(n_cluster):
        item = flex.first_index(CM.cluster_id_maxima, i)
        print('Cluster %d central Unit cell = %d' % (i, item))
        cells[item].crystal_symmetry.show_summary()

    # More plots for debugging
    appcolors = [
        'b', 'r', '#ff7f0e', '#2ca02c', '#9467bd', '#8c564b', '#e377c2',
        '#7f7f7f', '#bcbd22', '#17becf'
    ]
    if show_plot:
        # Decision graph
        import matplotlib.pyplot as plt
        plt.plot(CM.rho, CM.delta, "r.", markersize=3.)
        for x in range(NN):
            if CM.cluster_id_maxima[x] >= 0:
                plt.plot([CM.rho[x]], [CM.delta[x]], "ro")
        plt.show()

    if show_plot:
        import matplotlib.pyplot as plt
        colors = [appcolors[i % 10] for i in CM.cluster_id_full]
        plt.scatter(coord_x,
                    coord_y,
                    marker='o',
                    color=colors,
                    linewidth=0.4,
                    edgecolor='k')
        for i in range(n_cluster):
            item = flex.first_index(CM.cluster_id_maxima, i)
            plt.plot([cells[item].uc[0]], cells[item].uc[1], 'y.')
            plt.axes().set_aspect("equal")
            plt.show()
    if test_nks:
        exit()

    # Now look at each unit cell cluster for orientational clustering
    # idea is to cluster the orientational component in each of the unit cell clusters
    #
    do_orientational_clustering = not return_only_first_indexed_model  # temporary.
    dxtbx_crystal_models = []
    if do_orientational_clustering:
        print('IOTA: Starting orientational clustering')
        Dij_ori = {}  # dictionary to store Dij for each cluster
        uc_experiments_list = {
        }  # dictionary to store experiments_lists for each cluster
        from collections import Counter
        uc_cluster_count = Counter(list(CM.cluster_id_final))
        # instantiate the Dij_ori flat 1-d array
        # Put all experiments list from same uc cluster together
        if True:
            from scitbx.matrix import sqr
            from cctbx_orientation_ext import crystal_orientation
            crystal_orientation_list = []
            all_A = []
            for i in range(len(experiments_list)):
                crystal_orientation_list.append(
                    crystal_orientation(
                        experiments_list[i].crystals()[0].get_A(), True))
                #exit()
                A_direct = sqr(crystal_orientation_list[i].reciprocal_matrix()
                               ).transpose().inverse()
                all_A.append(A_direct[0])
                #print ("Direct A matrix 1st element = %12.6f %12.6f %12.6f"%(A_direct[0], A_direct[1], A_direct[2]))
        #  exit()
        CM_mapping = {}
        for i in range(len(experiments_list)):
            if CM.cluster_id_full[i] not in uc_experiments_list:
                uc_experiments_list[CM.cluster_id_full[i]] = []
                CM_mapping[CM.cluster_id_full[i]] = []
            uc_experiments_list[CM.cluster_id_full[i]].append(
                experiments_list[i])
            # Maintain mapping between original experiments_list and uc_exeriments_list
            # Mapping: key> index_in_experiments_list | value> cluster_id, index_in_uc_cluster
            CM_mapping[CM.cluster_id_full[i]].append(
                (i, len(uc_experiments_list[CM.cluster_id_full[i]]) - 1))
        for cluster in uc_cluster_count:
            # Make sure there are atleast a minimum number of samples in the cluster
            if uc_cluster_count[cluster] < clustering_params.min_datapts:
                continue
            Dij_ori[cluster] = flex.double(
                [[0.0] * uc_cluster_count[cluster]] *
                uc_cluster_count[cluster])
            # Now populate the Dij_ori array
            N_samples_in_cluster = len(uc_experiments_list[cluster])
            for i in range(N_samples_in_cluster - 1):
                for j in range(i + 1, N_samples_in_cluster):
                    dij_ori = get_dij_ori(
                        uc_experiments_list[cluster][i].crystals()[0],
                        uc_experiments_list[cluster][j].crystals()[0])
                    A_direct_i = sqr(
                        uc_experiments_list[cluster][i].crystals()
                        [0].get_A()).transpose().inverse()
                    A_direct_j = sqr(
                        uc_experiments_list[cluster][j].crystals()
                        [0].get_A()).transpose().inverse()
                    #print ("Direct A matrix 1st element = %12.6f %12.6f %12.6f %12.6f %12.6f %12.6f %12.6f"%(dij_ori, A_direct_i[0], A_direct_j[0], A_direct_i[1],A_direct_j[1], A_direct_i[2], A_direct_j[2] ))
                    Dij_ori[cluster][N_samples_in_cluster * i + j] = dij_ori
                    Dij_ori[cluster][N_samples_in_cluster * j + i] = dij_ori

        # Now do the orientational cluster analysis
        d_c_ori = clustering_params.d_c_ori  # 0.13
        from exafel_project.ADSE13_25.clustering.plot_with_dimensional_embedding import plot_with_dimensional_embedding
        #plot_with_dimensional_embedding(1-Dij_ori[1]/flex.max(Dij_ori[1]), show_plot=True)
        A_matrices = []
        for cluster in Dij_ori:
            #if cluster == 2:
            #  CM_ori = clustering_manager(Dij=Dij_ori[cluster], d_c=d_c_ori, max_percentile_rho=0.85, debug=True)
            d_c_ori = estimate_d_c(Dij_ori[cluster])
            #else:
            #d_c_ori=flex.mean_and_variance(Dij_ori[cluster].as_1d()).unweighted_sample_standard_deviation()
            print('d_c_ori=', d_c_ori)
            CM_ori = clustering_manager(
                Dij=Dij_ori[cluster],
                d_c=d_c_ori,
                max_percentile_rho=clustering_params.max_percentile_rho_ori,
                Z_delta=clustering_params.Z_delta,
                strategy='strategy_3')
            n_cluster_ori = 1 + flex.max(CM_ori.cluster_id_final)
            #from IPython import embed; embed(); exit()
            for i in range(n_cluster_ori):
                if len([zz for zz in CM_ori.cluster_id_final if zz == i
                        ]) < clustering_params.min_datapts:
                    continue
                item = flex.first_index(CM_ori.cluster_id_maxima, i)
                dxtbx_crystal_model = uc_experiments_list[cluster][
                    item].crystals()[0]
                dxtbx_crystal_models.append(dxtbx_crystal_model)
                # Map the orientational clusters to the original experiments_list indices
                # This should be the final list of clusters!
                for j, ori_cluster_id in enumerate(CM_ori.cluster_id_final):
                    if ori_cluster_id == i:
                        xx, yy = CM_mapping[cluster][j]
                        clustered_experiments_list[xx] = len(
                            dxtbx_crystal_models) - 1
                from scitbx.matrix import sqr
                from cctbx_orientation_ext import crystal_orientation
                crystal_orientation = crystal_orientation(
                    dxtbx_crystal_model.get_A(), True)
                A_direct = sqr(crystal_orientation.reciprocal_matrix()
                               ).transpose().inverse()
                A_matrices.append(A_direct)
                print(
                    "IOTA: Direct A matrix 1st element of orientational cluster %d  = %12.6f"
                    % (i, A_direct[0]))
                print(A_direct)
            if show_plot:
                # Decision graph
                stretch_plot_factor = 1.05  # (1+fraction of limits by which xlim,ylim should be set)
                import matplotlib.pyplot as plt
                plt.plot(CM_ori.rho, CM_ori.delta, "r.", markersize=3.)
                for x in range(len(list(CM_ori.cluster_id_final))):
                    if CM_ori.cluster_id_maxima[x] >= 0:
                        plt.plot([CM_ori.rho[x]], [CM_ori.delta[x]], "ro")
                #exit()
                plt.xlim([-10, stretch_plot_factor * flex.max(CM_ori.rho)])
                plt.ylim([-10, stretch_plot_factor * flex.max(CM_ori.delta)])
                plt.show()
    # FIXME Still to be worked out what exactly should be returned
    #if return_only_first_indexed_model:
    #  return [experiments_list[0].crystals()[0]], clustered_experiments_list
    # Make sure the crystal models are not too close to each other
    # FIXME should be a PHIL
    #from IPython import embed; embed(); exit()
    min_angle = 5.0  # taken from indexer.py
    close_models_list = []
    # Not used really; other fixes have been made to code to figure out outliers
    # Still keeping this in case it it useful later on.
    if len(dxtbx_crystal_models) > 10000:
        from dials.algorithms.indexing.compare_orientation_matrices import difference_rotation_matrix_axis_angle
        from cctbx_orientation_ext import crystal_orientation
        from dxtbx.model import Crystal
        for i_a in range(0, len(dxtbx_crystal_models) - 1):
            for i_b in range(i_a + 1, len(dxtbx_crystal_models)):
                cryst_a = dxtbx_crystal_models[i_a]
                cryst_b = dxtbx_crystal_models[i_b]
                cryst_a_ori = crystal_orientation(cryst_a.get_A(), True)
                cryst_b_ori = crystal_orientation(cryst_b.get_A(), True)
                try:
                    best_similarity_transform = cryst_b_ori.best_similarity_transformation(
                        other=cryst_a_ori,
                        fractional_length_tolerance=20.00,
                        unimodular_generator_range=1)
                    cryst_b_ori_best = cryst_b_ori.change_basis(
                        best_similarity_transform)
                except Exception as e:
                    cryst_b_ori_best = cryst_b_ori

                # FIXME hardcoded space group for myoglobin LS49
                cryst_b_best = Crystal(cryst_b_ori_best.direct_matrix()[0:3],
                                       cryst_b_ori_best.direct_matrix()[3:6],
                                       cryst_b_ori_best.direct_matrix()[6:9],
                                       'P 1 21 1')
                R_ab, axis, angle, cb_op_ab = difference_rotation_matrix_axis_angle(
                    cryst_a, cryst_b_best)
                # FIXME
                if abs(angle) < min_angle:  # degrees
                    close_models_list.append((i_a, i_b))

    # Now prune the dxtbx_crystal_models list
        unique_experiments_list = flex.int(range(len(dxtbx_crystal_models)))
        for close_models in close_models_list:
            i_a, i_b = close_models
            if dxtbx_crystal_models[i_a] is not None and dxtbx_crystal_models[
                    i_b] is not None:
                dxtbx_crystal_models[i_b] = None
                unique_experiments_list[i_b] = i_a
                clustered_experiments_list.set_selected(
                    clustered_experiments_list == i_b, i_a)

        counter = -1
        for ii, model in enumerate(dxtbx_crystal_models):
            if model is not None:
                counter += 1
                clustered_experiments_list.set_selected(
                    clustered_experiments_list == unique_experiments_list[ii],
                    counter)
        dxtbx_crystal_models = [
            x for x in dxtbx_crystal_models if x is not None
        ]

    #from IPython import embed; embed(); exit()
    if len(dxtbx_crystal_models) > 0:
        return dxtbx_crystal_models, list(clustered_experiments_list)
    else:
        # If nothing works, atleast return the 1st crystal model that was found
        return [experiments_list[0].crystals()[0]], None
def get_uc_consensus(experiments_list,
                     show_plot=False,
                     return_only_first_indexed_model=False,
                     finalize_method=None,
                     clustering_params=None):
    '''
  Uses the Rodriguez Laio 2014 method to do a clustering of the unit cells and then vote for the highest
  consensus unit cell. Input needs to be a list of experiments object.
  Clustering code taken from github.com/cctbx-xfel/cluster_regression
  Returns an experiment object with crystal unit cell from the cluster with the most points
  '''
    if return_only_first_indexed_model:
        return [experiments_list[0].crystals()[0]], None
    cells = []
    from xfel.clustering.singleframe import CellOnlyFrame
    save_plot = False
    # Flag for testing Lysozyme data from NKS.Make sure cluster_regression repository is present and configured
    # Program will exit after plots are displayed if this flag is true
    test_nks = False
    if test_nks:
        from cctbx import crystal
        import libtbx.load_env
        cluster_regression = libtbx.env.find_in_repositories(
            relative_path="cluster_regression", test=os.path.isdir)
        file_name = os.path.join(cluster_regression, 'examples',
                                 'lysozyme1341.txt')
        for line in open(file_name, "r").xreadlines():
            tokens = line.strip().split()
            unit_cell = tuple(float(x) for x in tokens[0:6])
            space_group_symbol = tokens[6]
            crystal_symmetry = crystal.symmetry(
                unit_cell=unit_cell, space_group_symbol=space_group_symbol)
            cells.append(CellOnlyFrame(crystal_symmetry))
    else:
        for experiment in experiments_list:
            if len(experiment.crystals()) > 1:
                print('IOTA:Should have only one crystal model')
            crystal_symmetry = experiment.crystals()[0].get_crystal_symmetry()
            cells.append(CellOnlyFrame(crystal_symmetry))
    MM = [c.mm for c in cells]  # metrical matrices
    MM_double = flex.double()
    for i in range(len(MM)):
        Tup = MM[i]
        for j in range(6):
            MM_double.append(Tup[j])
    print('There are %d cells' % len(MM))
    coord_x = flex.double([c.uc[0] for c in cells])
    coord_y = flex.double([c.uc[1] for c in cells])
    if show_plot or save_plot:
        import matplotlib
        if not show_plot:
            matplotlib.use('Agg')
        import matplotlib.pyplot as plt
        #from IPython import embed; embed(); exit()
        plt.plot([c.uc[0] for c in cells], [c.uc[1] for c in cells],
                 "k.",
                 markersize=3.)
        plt.axes().set_aspect("equal")
    if save_plot:
        plot_name = 'uc_cluster.png'
        plt.savefig(plot_name,
                    size_inches=(10, 10),
                    dpi=300,
                    bbox_inches='tight')
    if show_plot:
        plt.show()
    print('Now constructing a Dij matrix: Starting Unit Cell clustering')
    NN = len(MM)
    from cctbx.uctbx.determine_unit_cell import NCDist_flatten
    Dij = NCDist_flatten(MM_double)
    d_c = flex.mean_and_variance(
        Dij.as_1d()).unweighted_sample_standard_deviation()  #6.13
    #FIXME should be a PHIL param
    if len(cells) < 5:
        return [experiments_list[0].crystals()[0]], None
    CM = clustering_manager(Dij=Dij, d_c=d_c, max_percentile_rho=0.95)
    n_cluster = 1 + flex.max(CM.cluster_id_final)
    print(len(cells), ' datapoints have been analyzed')
    print('%d CLUSTERS' % n_cluster)
    for i in range(n_cluster):
        item = flex.first_index(CM.cluster_id_maxima, i)
        print('Cluster %d central Unit cell = %d' % (i, item))
        cells[item].crystal_symmetry.show_summary()

    # More plots for debugging
    appcolors = [
        'b', 'r', '#ff7f0e', '#2ca02c', '#9467bd', '#8c564b', '#e377c2',
        '#7f7f7f', '#bcbd22', '#17becf'
    ]
    if show_plot:
        # Decision graph
        import matplotlib.pyplot as plt
        plt.plot(CM.rho, CM.delta, "r.", markersize=3.)
        for x in range(NN):
            if CM.cluster_id_maxima[x] >= 0:
                plt.plot([CM.rho[x]], [CM.delta[x]], "ro")
        plt.show()

    if show_plot:
        import matplotlib.pyplot as plt
        colors = [appcolors[i % 10] for i in CM.cluster_id_full]
        plt.scatter(coord_x,
                    coord_y,
                    marker='o',
                    color=colors,
                    linewidth=0.4,
                    edgecolor='k')
        for i in range(n_cluster):
            item = flex.first_index(CM.cluster_id_maxima, i)
            plt.plot([cells[item].uc[0]], cells[item].uc[1], 'y.')
            plt.axes().set_aspect("equal")
            plt.show()
    if test_nks:
        exit()

    # Now look at each unit cell cluster for orientational clustering
    # idea is to cluster the orientational component in each of the unit cell clusters
    #
    do_orientational_clustering = not return_only_first_indexed_model  # temporary.
    dxtbx_crystal_models = []
    if do_orientational_clustering:
        print('IOTA: Starting orientational clustering')
        Dij_ori = {}  # dictionary to store Dij for each cluster
        uc_experiments_list = {
        }  # dictionary to store experiments_lists for each cluster
        from collections import Counter
        uc_cluster_count = Counter(list(CM.cluster_id_final))
        # instantiate the Dij_ori flat 1-d array
        # Put all experiments list from same uc cluster together
        if True:
            from scitbx.matrix import sqr
            from cctbx_orientation_ext import crystal_orientation
            #crystal_orientation_list = []
            #for i in range(len(experiments_list)):
            #  crystal_orientation_list.append(crystal_orientation(experiments_list[i].crystals()[0].get_A(), True))
            #from IPython import embed; embed(); exit()
            #A_direct = sqr(crystal_orientation_list[i].reciprocal_matrix()).transpose().inverse()
            #print ("Direct A matrix 1st element = %12.6f"%A_direct[0])
        for i in range(len(experiments_list)):
            if CM.cluster_id_full[i] not in uc_experiments_list:
                uc_experiments_list[CM.cluster_id_full[i]] = []
            uc_experiments_list[CM.cluster_id_full[i]].append(
                experiments_list[i])
        for cluster in uc_cluster_count:
            # Make sure there are atleast a minimum number of samples in the cluster
            if uc_cluster_count[cluster] < 5:
                continue
            Dij_ori[cluster] = flex.double(
                [[0.0] * uc_cluster_count[cluster]] *
                uc_cluster_count[cluster])
            # Now populate the Dij_ori array
            N_samples_in_cluster = len(uc_experiments_list[cluster])
            for i in range(N_samples_in_cluster - 1):
                for j in range(i + 1, N_samples_in_cluster):
                    dij_ori = get_dij_ori(
                        uc_experiments_list[cluster][i].crystals()[0],
                        uc_experiments_list[cluster][j].crystals()[0])
                    Dij_ori[cluster][N_samples_in_cluster * i + j] = dij_ori
                    Dij_ori[cluster][N_samples_in_cluster * j + i] = dij_ori

        # Now do the orientational cluster analysis
        #from IPython import embed; embed(); exit()
        d_c_ori = 0.13
        from exafel_project.ADSE13_25.clustering.plot_with_dimensional_embedding import plot_with_dimensional_embedding
        #plot_with_dimensional_embedding(1-Dij_ori[1]/flex.max(Dij_ori[1]), show_plot=True)
        for cluster in Dij_ori:
            d_c_ori = flex.mean_and_variance(Dij_ori[cluster].as_1d(
            )).unweighted_sample_standard_deviation()
            CM_ori = clustering_manager(Dij=Dij_ori[cluster],
                                        d_c=d_c_ori,
                                        max_percentile_rho=0.85)
            n_cluster_ori = 1 + flex.max(CM_ori.cluster_id_final)
            #from IPython import embed; embed()
            #FIXME should be a PHIL param
            for i in range(n_cluster_ori):
                if len([zz for zz in CM_ori.cluster_id_final if zz == i]) < 5:
                    continue
                item = flex.first_index(CM_ori.cluster_id_maxima, i)
                dxtbx_crystal_model = uc_experiments_list[cluster][
                    item].crystals()[0]
                dxtbx_crystal_models.append(dxtbx_crystal_model)
                from scitbx.matrix import sqr
                from cctbx_orientation_ext import crystal_orientation
                crystal_orientation = crystal_orientation(
                    dxtbx_crystal_model.get_A(), True)
                A_direct = sqr(crystal_orientation.reciprocal_matrix()
                               ).transpose().inverse()
                print(
                    "IOTA: Direct A matrix 1st element of orientational cluster %d  = %12.6f"
                    % (i, A_direct[0]))
            if show_plot:
                # Decision graph
                stretch_plot_factor = 1.05  # (1+fraction of limits by which xlim,ylim should be set)
                import matplotlib.pyplot as plt
                plt.plot(CM_ori.rho, CM_ori.delta, "r.", markersize=3.)
                for x in range(len(list(CM_ori.cluster_id_final))):
                    if CM_ori.cluster_id_maxima[x] >= 0:
                        plt.plot([CM_ori.rho[x]], [CM_ori.delta[x]], "ro")
                #from IPython import embed; embed(); exit()
                plt.xlim([-10, stretch_plot_factor * flex.max(CM_ori.rho)])
                plt.ylim([-10, stretch_plot_factor * flex.max(CM_ori.delta)])
                plt.show()
    # Make sure the crystal models are not too close to each other
    # FIXME should be a PHIL
    min_angle = 5.0  # taken from indexer.py
    close_models_list = []
    if len(dxtbx_crystal_models) > 1:
        from dials.algorithms.indexing.compare_orientation_matrices import difference_rotation_matrix_axis_angle
        for i_a in range(0, len(dxtbx_crystal_models) - 1):
            for i_b in range(i_a, len(dxtbx_crystal_models)):
                cryst_a = dxtbx_crystal_models[i_a]
                cryst_b = dxtbx_crystal_models[i_b]
                R_ab, axis, angle, cb_op_ab = difference_rotation_matrix_axis_angle(
                    cryst_a, cryst_b)
                # FIXME
                if abs(angle) < min_angle:  # degrees
                    close_models_list.append((i_a, i_b))

    # Now prune the dxtbx_crystal_models list
    for close_models in close_models_list:
        i_a, i_b = close_models
        if dxtbx_crystal_models[i_a] is not None and dxtbx_crystal_models[
                i_b] is not None:
            dxtbx_crystal_models[i_a] = None

    dxtbx_crystal_models = [x for x in dxtbx_crystal_models if x is not None]
    if len(dxtbx_crystal_models) > 0:
        return dxtbx_crystal_models, None
    else:
        # If nothing works, atleast return the 1st crystal model that was found
        return [experiments_list[0].crystals()[0]], None