def _rank_classifications(
            self,
            crossmatchArray,
            colMaps):
        """*rank the classifications returned from the catalogue crossmatcher, annotate the results with a classification rank-number (most likely = 1) and a rank-score (weight of classification)*

        **Key Arguments:**
            - ``crossmatchArrayIndex`` -- the index of list of unranked crossmatch classifications
            - ``colMaps`` -- dictionary of dictionaries with the name of the database-view (e.g. `tcs_view_agn_milliquas_v4_5`) as the key and the column-name dictary map as value (`{view_name: {columnMap}}`).

        **Return:**
            - ``classifications`` -- the classifications assigned to the transients post-crossmatches
            - ``crossmatches`` -- the crossmatches annotated with rankings and rank-scores

        .. todo ::

            - update key arguments values and definitions with defaults
            - update return values and definitions
            - update usage examples and text
            - update docstring text
            - check sublime snippet exists
            - clip any useful text to docs mindmap
            - regenerate the docs and check redendering of this docstring
        """
        self.log.debug('starting the ``_rank_classifications`` method')

        crossmatches = crossmatchArray

        # GROUP CROSSMATCHES INTO DISTINCT SOURCES (DUPLICATE ENTRIES OF THE
        # SAME ASTROPHYSICAL SOURCE ACROSS MULTIPLE CATALOGUES)
        ra, dec = zip(*[(r["raDeg"], r["decDeg"]) for r in crossmatches])

        from HMpTy.htm import sets
        xmatcher = sets(
            log=self.log,
            ra=ra,
            dec=dec,
            radius=3 / (60. * 60.),  # in degrees
            sourceList=crossmatches
        )
        groupedMatches = xmatcher.match

        associatationTypeOrder = ["AGN", "CV", "NT", "SN", "VS", "BS"]

        # ADD DISTINCT-SOURCE KEY
        dupKey = 0
        distinctMatches = []
        for x in groupedMatches:
            dupKey += 1
            mergedMatch = copy.deepcopy(x[0])
            mergedMatch["merged_rank"] = int(dupKey)

            # ADD OTHER ESSENTIAL KEYS
            for e in ['z', 'photoZ', 'photoZErr']:
                if e not in mergedMatch:
                    mergedMatch[e] = None

            bestDirectDistance = {
                "direct_distance": mergedMatch["direct_distance"],
                "direct_distance_modulus": mergedMatch["direct_distance_modulus"],
                "direct_distance_scale": mergedMatch["direct_distance"],
                "qual": colMaps[mergedMatch["catalogue_view_name"]]["object_type_accuracy"]
            }
            bestSpecz = {
                "z": mergedMatch["z"],
                "distance": mergedMatch["distance"],
                "distance_modulus": mergedMatch["distance_modulus"],
                "scale": mergedMatch["scale"],
                "qual": colMaps[mergedMatch["catalogue_view_name"]]["object_type_accuracy"]
            }
            bestPhotoz = {
                "photoZ": mergedMatch["photoZ"],
                "photoZErr": mergedMatch["photoZErr"],
                "distance": mergedMatch["distance"],
                "distance_modulus": mergedMatch["distance_modulus"],
                "scale": mergedMatch["scale"],
                "qual": colMaps[mergedMatch["catalogue_view_name"]]["object_type_accuracy"]
            }

            for i, m in enumerate(x):
                m["merged_rank"] = int(dupKey)
                if i > 0:
                    # MERGE ALL BEST MAGNITUDE MEASUREMENTS
                    for f in self.filterPreference:
                        if f in m and m[f] and (f not in mergedMatch or (f + "Err" in mergedMatch and (f + "Err" not in m or (mergedMatch[f + "Err"] > m[f + "Err"])))):
                            mergedMatch[f] = m[f]
                            try:
                                mergedMatch[f + "Err"] = m[f + "Err"]
                            except:
                                pass
                    mergedMatch["original_search_radius_arcsec"] = "multiple"
                    mergedMatch["catalogue_object_subtype"] = "multiple"
                    mergedMatch["catalogue_view_name"] = "multiple"

                    # MERGE SEARCH NAMES
                    snippet = m["search_name"].split(" ")[0].upper()

                    if "/" not in mergedMatch["search_name"] and snippet not in mergedMatch["search_name"].upper():
                        mergedMatch["search_name"] = mergedMatch["search_name"].split(
                            " ")[0].upper() + "/" + m["search_name"].split(" ")[0].upper()
                    elif snippet not in mergedMatch["search_name"].upper():
                        mergedMatch[
                            "search_name"] += "/" + m["search_name"].split(" ")[0].upper()
                    elif "/" not in mergedMatch["search_name"]:
                        mergedMatch["search_name"] = mergedMatch["search_name"].split(
                            " ")[0].upper()

                    mergedMatch["catalogue_table_name"] = mergedMatch[
                        "search_name"]

                    # MERGE CATALOGUE SOURCE NAMES
                    mergedMatch["catalogue_object_id"] = str(
                        mergedMatch["catalogue_object_id"])
                    m["catalogue_object_id"] = str(m["catalogue_object_id"])
                    if m["catalogue_object_id"].replace(" ", "").lower() not in mergedMatch["catalogue_object_id"].replace(" ", "").lower():
                        mergedMatch["catalogue_object_id"] += "/" + \
                            m["catalogue_object_id"]

                    # DETERMINE BEST CLASSIFICATION
                    if mergedMatch["classificationReliability"] == 3 and m["classificationReliability"] < 3:
                        mergedMatch["association_type"] = m["association_type"]
                        mergedMatch["classificationReliability"] = m[
                            "classificationReliability"]

                    if m["classificationReliability"] != 3 and m["association_type"] in associatationTypeOrder and (mergedMatch["association_type"] not in associatationTypeOrder or associatationTypeOrder.index(m["association_type"]) < associatationTypeOrder.index(mergedMatch["association_type"])):
                        mergedMatch["association_type"] = m["association_type"]
                        mergedMatch["classificationReliability"] = m[
                            "classificationReliability"]

                    # FIND BEST DISTANCES
                    if "direct_distance" in m and m["direct_distance"] and colMaps[m["catalogue_view_name"]]["object_type_accuracy"] > bestDirectDistance["qual"]:
                        bestDirectDistance = {
                            "direct_distance": m["direct_distance"],
                            "direct_distance_modulus": m["direct_distance_modulus"],
                            "direct_distance_scale": m["direct_distance_scale"],
                            "catalogue_object_type": m["catalogue_object_type"],
                            "qual": colMaps[m["catalogue_view_name"]]["object_type_accuracy"]
                        }
                    # FIND BEST SPEC-Z
                    if "z" in m and m["z"] and colMaps[m["catalogue_view_name"]]["object_type_accuracy"] > bestSpecz["qual"]:
                        bestSpecz = {
                            "z": m["z"],
                            "distance": m["distance"],
                            "distance_modulus": m["distance_modulus"],
                            "scale": m["scale"],
                            "catalogue_object_type": m["catalogue_object_type"],
                            "qual": colMaps[m["catalogue_view_name"]]["object_type_accuracy"]
                        }
                    # FIND BEST PHOT-Z
                    if "photoZ" in m and m["photoZ"] and colMaps[m["catalogue_view_name"]]["object_type_accuracy"] > bestPhotoz["qual"]:
                        bestPhotoz = {
                            "photoZ": m["photoZ"],
                            "photoZErr": m["photoZErr"],
                            "distance": m["distance"],
                            "distance_modulus": m["distance_modulus"],
                            "scale": m["scale"],
                            "catalogue_object_type": m["catalogue_object_type"],
                            "qual": colMaps[m["catalogue_view_name"]]["object_type_accuracy"]
                        }
                    # CLOSEST ANGULAR SEP & COORDINATES
                    if m["separationArcsec"] < mergedMatch["separationArcsec"]:
                        mergedMatch["separationArcsec"] = m["separationArcsec"]
                        mergedMatch["raDeg"] = m["raDeg"]
                        mergedMatch["decDeg"] = m["decDeg"]

            # MERGE THE BEST RESULTS
            for l in [bestPhotoz, bestSpecz, bestDirectDistance]:
                for k, v in l.iteritems():
                    if k != "qual":
                        mergedMatch[k] = v

            mergedMatch["catalogue_object_id"] = str(mergedMatch[
                "catalogue_object_id"]).replace(" ", "")

            # RECALULATE PHYSICAL DISTANCE SEPARATION
            if mergedMatch["direct_distance_scale"]:
                mergedMatch["physical_separation_kpc"] = mergedMatch[
                    "direct_distance_scale"] * mergedMatch["separationArcsec"]
            elif mergedMatch["scale"]:
                mergedMatch["physical_separation_kpc"] = mergedMatch[
                    "scale"] * mergedMatch["separationArcsec"]

            if "/" in mergedMatch["search_name"]:
                mergedMatch["search_name"] = "multiple"

            distinctMatches.append(mergedMatch)

        crossmatches = []
        for xm, gm in zip(distinctMatches, groupedMatches):

            # SPEC-Z GALAXIES
            if (xm["physical_separation_kpc"] is not None and xm["physical_separation_kpc"] != "null" and xm["physical_separation_kpc"] < 20. and xm["association_type"] == "SN" and (("z" in xm and xm["z"] is not None) or "photoZ" not in xm or xm["photoZ"] is None or xm["photoZ"] < 0.)):
                rankScore = xm["classificationReliability"] * 1000 + 2. - \
                    xm["physical_separation_kpc"] / 10
            # PHOTO-Z GALAXIES
            elif (xm["physical_separation_kpc"] is not None and xm["physical_separation_kpc"] != "null" and xm["physical_separation_kpc"] < 20. and xm["association_type"] == "SN"):
                rankScore = xm["classificationReliability"] * 1000 + 2.2 - \
                    xm["physical_separation_kpc"] / 10
            # NOT SPEC-Z, NON PHOTO-Z GALAXIES
            elif (xm["association_type"] == "SN"):
                rankScore = xm["classificationReliability"] * 1000 + 5.
            # VS
            elif (xm["association_type"] == "VS"):
                rankScore = xm["classificationReliability"] * \
                    1000 + xm["separationArcsec"] + 2.
            # BS
            elif (xm["association_type"] == "BS"):
                rankScore = xm["classificationReliability"] * \
                    1000 + xm["separationArcsec"]
            else:
                rankScore = xm["classificationReliability"] * \
                    1000 + xm["separationArcsec"] + 10.
            xm["rankScore"] = rankScore
            crossmatches.append(xm)
            if len(gm) > 1:
                for g in gm:
                    g["rankScore"] = rankScore

        crossmatches = sorted(
            crossmatches, key=itemgetter('rankScore'), reverse=False)
        crossmatches = sorted(
            crossmatches, key=itemgetter('transient_object_id'))

        transient_object_id = None
        uniqueIndexCheck = []
        classifications = {}
        crossmatchesKeep = []
        rank = 0
        transClass = []
        for xm in crossmatches:
            rank += 1
            if rank == 1:
                transClass.append(xm["association_type"])
                classifications[xm["transient_object_id"]] = transClass
            xm["rank"] = rank
            crossmatchesKeep.append(xm)
        crossmatches = crossmatchesKeep

        crossmatchesKeep = []
        for xm in crossmatches:
            group = groupedMatches[xm["merged_rank"] - 1]
            xm["merged_rank"] = None
            crossmatchesKeep.append(xm)

            if len(group) > 1:
                groupKeep = []
                uniqueIndexCheck = []
                for g in group:
                    g["merged_rank"] = xm["rank"]
                    g["rankScore"] = xm["rankScore"]
                    index = "%(catalogue_table_name)s%(catalogue_object_id)s" % g
                    # IF WE HAVE HIT A NEW SOURCE
                    if index not in uniqueIndexCheck:
                        uniqueIndexCheck.append(index)
                        crossmatchesKeep.append(g)

        crossmatches = crossmatchesKeep

        self.log.debug('completed the ``_rank_classifications`` method')

        return classifications, crossmatches