def chunk_fg_comp_dict_by_nbls(fg_model_comps_dict, use_redundancy=False, grp_size_threshold=5):
    "\n    Order dict keys in order of number of baselines in each group\n\n\n    chunk fit_groups in fg_model_comps_dict into chunks where all groups in the\n    same chunk have the same number of baselines in each group.\n\n    Parameters\n    ----------\n    fg_model_comps_dict: dict\n        dictionary with keys that are tuples of tuples of 2-tuples (thats right, 3 levels)\n        in the first level, each tuple represents a 'modeling group' visibilities in each\n        modeling group are represented by a set of basis vectors that span all baselines in that\n        group with elements raveled by baseline and then frequency. Each tuple in the modeling group is a\n        'redundant group' representing visibilities that we will represent with identical component coefficients\n        each element of each 'redundant group' is a 2-tuple antenna pair. Our formalism easily accomodates modeling\n        visibilities as redundant or non redundant (one simply needs to make each redundant group length 1).\n\n    use_redundancy: bool, optional\n        If False, break fitting groups with the same number of baselines in each redundant\n        sub_group into different fitting groups with no redundancy in each\n        redundant subgroup. This is to prevent fitting groups with single\n        redundant groups of varying lengths from being lumped into different chunks\n        increasing the number of chunks has a more significant impact on run-time\n        then increasing the number of baselines in each chunk.\n        default is False.\n    Returns:\n    fg_model_comps_dict_chunked: dict\n        dictionary where each key is a 2-tuple (nbl, nvecs) referring to the number\n        of baselines in each vector and the number of vectors. Each 2-tuple points to\n        a dictionary where each key is the fitting group in fg_comps_dict that includes\n        nbl baselines. Each key in the referenced dict points to an (nred_grps * nfreqs x nvecs)\n        numpy.ndarray describing the modeling components for each fitting group in the chunk.\n\n    "
    chunked_keys = {}
    maxvecs = {}
    fg_model_comps_dict = copy.deepcopy(fg_model_comps_dict)
    if (not use_redundancy):
        keys_with_redundancy = list(fg_model_comps_dict.keys())
        for fit_grp in keys_with_redundancy:
            rlens = np.asarray([len(red_grp) for red_grp in fit_grp])
            if (np.allclose(rlens, np.mean(rlens)) and (len(rlens) < grp_size_threshold)):
                modeling_vectors = fg_model_comps_dict.pop(fit_grp)
                for rednum in range(int(rlens[0])):
                    fit_grp_new = tuple([(red_grp[rednum],) for red_grp in fit_grp])
                    fg_model_comps_dict[fit_grp_new] = modeling_vectors
    for fit_grp in fg_model_comps_dict:
        nbl = 0
        for red_grp in fit_grp:
            for ap in red_grp:
                nbl += 1
        if (nbl in chunked_keys):
            chunked_keys[nbl].append(fit_grp)
            if (fg_model_comps_dict[fit_grp].shape[1] > maxvecs[nbl]):
                maxvecs[nbl] = fg_model_comps_dict[fit_grp].shape[1]
        else:
            chunked_keys[nbl] = [fit_grp]
            maxvecs[nbl] = fg_model_comps_dict[fit_grp].shape[1]
    fg_model_comps_dict_chunked = {}
    for nbl in chunked_keys:
        fg_model_comps_dict_chunked[(nbl, maxvecs[nbl])] = {k: fg_model_comps_dict[k] for k in chunked_keys[nbl]}
    return fg_model_comps_dict_chunked
Order dict keys in order of number of baselines in each group


chunk fit_groups in fg_model_comps_dict into chunks where all groups in the
same chunk have the same number of baselines in each group.

Parameters
----------
fg_model_comps_dict: dict
    dictionary with keys that are tuples of tuples of 2-tuples (thats right, 3 levels)
    in the first level, each tuple represents a 'modeling group' visibilities in each
    modeling group are represented by a set of basis vectors that span all baselines in that
    group with elements raveled by baseline and then frequency. Each tuple in the modeling group is a
    'redundant group' representing visibilities that we will represent with identical component coefficients
    each element of each 'redundant group' is a 2-tuple antenna pair. Our formalism easily accomodates modeling
    visibilities as redundant or non redundant (one simply needs to make each redundant group length 1).

use_redundancy: bool, optional
    If False, break fitting groups with the same number of baselines in each redundant
    sub_group into different fitting groups with no redundancy in each
    redundant subgroup. This is to prevent fitting groups with single
    redundant groups of varying lengths from being lumped into different chunks
    increasing the number of chunks has a more significant impact on run-time
    then increasing the number of baselines in each chunk.
    default is False.
Returns:
fg_model_comps_dict_chunked: dict
    dictionary where each key is a 2-tuple (nbl, nvecs) referring to the number
    of baselines in each vector and the number of vectors. Each 2-tuple points to
    a dictionary where each key is the fitting group in fg_comps_dict that includes
    nbl baselines. Each key in the referenced dict points to an (nred_grps * nfreqs x nvecs)
    numpy.ndarray describing the modeling components for each fitting group in the chunk.
def chunk_fg_comp_dict_by_nbls(fg_model_comps_dict, use_redundancy=False, grp_size_threshold=5):
    "\n    Order dict keys in order of number of baselines in each group\n\n\n    chunk fit_groups in fg_model_comps_dict into chunks where all groups in the\n    same chunk have the same number of baselines in each group.\n\n    Parameters\n    ----------\n    fg_model_comps_dict: dict\n        dictionary with keys that are tuples of tuples of 2-tuples (thats right, 3 levels)\n        in the first level, each tuple represents a 'modeling group' visibilities in each\n        modeling group are represented by a set of basis vectors that span all baselines in that\n        group with elements raveled by baseline and then frequency. Each tuple in the modeling group is a\n        'redundant group' representing visibilities that we will represent with identical component coefficients\n        each element of each 'redundant group' is a 2-tuple antenna pair. Our formalism easily accomodates modeling\n        visibilities as redundant or non redundant (one simply needs to make each redundant group length 1).\n\n    use_redundancy: bool, optional\n        If False, break fitting groups with the same number of baselines in each redundant\n        sub_group into different fitting groups with no redundancy in each\n        redundant subgroup. This is to prevent fitting groups with single\n        redundant groups of varying lengths from being lumped into different chunks\n        increasing the number of chunks has a more significant impact on run-time\n        then increasing the number of baselines in each chunk.\n        default is False.\n    Returns:\n    fg_model_comps_dict_chunked: dict\n        dictionary where each key is a 2-tuple (nbl, nvecs) referring to the number\n        of baselines in each vector and the number of vectors. Each 2-tuple points to\n        a dictionary where each key is the fitting group in fg_comps_dict that includes\n        nbl baselines. Each key in the referenced dict points to an (nred_grps * nfreqs x nvecs)\n        numpy.ndarray describing the modeling components for each fitting group in the chunk.\n\n    "
    chunked_keys = {}
    maxvecs = {}
    fg_model_comps_dict = copy.deepcopy(fg_model_comps_dict)
    if (not use_redundancy):
        keys_with_redundancy = list(fg_model_comps_dict.keys())
        for fit_grp in keys_with_redundancy:
            rlens = np.asarray([len(red_grp) for red_grp in fit_grp])
            if (np.allclose(rlens, np.mean(rlens)) and (len(rlens) < grp_size_threshold)):
                modeling_vectors = fg_model_comps_dict.pop(fit_grp)
                for rednum in range(int(rlens[0])):
                    fit_grp_new = tuple([(red_grp[rednum],) for red_grp in fit_grp])
                    fg_model_comps_dict[fit_grp_new] = modeling_vectors
    for fit_grp in fg_model_comps_dict:
        nbl = 0
        for red_grp in fit_grp:
            for ap in red_grp:
                nbl += 1
        if (nbl in chunked_keys):
            chunked_keys[nbl].append(fit_grp)
            if (fg_model_comps_dict[fit_grp].shape[1] > maxvecs[nbl]):
                maxvecs[nbl] = fg_model_comps_dict[fit_grp].shape[1]
        else:
            chunked_keys[nbl] = [fit_grp]
            maxvecs[nbl] = fg_model_comps_dict[fit_grp].shape[1]
    fg_model_comps_dict_chunked = {}
    for nbl in chunked_keys:
        fg_model_comps_dict_chunked[(nbl, maxvecs[nbl])] = {k: fg_model_comps_dict[k] for k in chunked_keys[nbl]}
    return fg_model_comps_dict_chunked