예제 #1
0
def calc_3pt(data, randoms, config_fname, zvar, random_zvar, ra_var='RA', dec_var='DEC', random_ra_var='RA', random_dec_var='DEC'):
    config_3pt = load_config(config_fname)['3PCF']
    cat = treecorr.Catalog(ra=data[ra_var], dec=data[dec_var],
                           dec_units='degrees', ra_units='degrees',
                           r=datasets.buzzard_cosmo.comoving_distance(data[zvar]).value*datasets.buzzard_cosmo.h)
    random_cat = treecorr.Catalog(ra=randoms[random_ra_var], dec=randoms[random_dec_var],
                                  dec_units='degrees', ra_units='degrees',
                                  r=datasets.buzzard_cosmo.comoving_distance(randoms[random_zvar]).value*datasets.buzzard_cosmo.h)
    print config_3pt
    ddd = treecorr.NNNCorrelation(config=config_3pt)
    ddr = treecorr.NNNCorrelation(config=config_3pt)
    drd = treecorr.NNNCorrelation(config=config_3pt)
    rdd = treecorr.NNNCorrelation(config=config_3pt)
    rdr = treecorr.NNNCorrelation(config=config_3pt)
    rrd = treecorr.NNNCorrelation(config=config_3pt)
    drr = treecorr.NNNCorrelation(config=config_3pt)
    rrr = treecorr.NNNCorrelation(config=config_3pt)
    ddd.process(cat, metric=config_3pt['metric'])
    ddr.process(cat, cat,  random_cat, metric=config_3pt['metric'])
    drd.process(cat, random_cat, cat, metric=config_3pt['metric'])
    rdd.process(random_cat, cat, cat, metric=config_3pt['metric'])
    rdr.process(random_cat, cat,  random_cat, metric=config_3pt['metric'])
    rrd.process(random_cat, random_cat,  cat, metric=config_3pt['metric'])
    drr.process(cat, random_cat,  random_cat, metric=config_3pt['metric'])
    rrr.process(random_cat, random_cat,  random_cat,
                metric=config_3pt['metric'])
    zeta, varzeta = ddd.calculateZeta(
        ddr=ddr, drd=drd, rdd=rdd, rrd=rrd, rdr=rdr, drr=drr, rrr=rrr)
    return zeta
예제 #2
0
 def compute_3pt_raw(self):
     nnn = treecorr.NNNCorrelation(config=self.config_3pt)
     toc = time.time()
     setdict = {'d': self.cat, 'r': self.random_cat}
     nnn.process(setdict[self.set_str[0]],
                 setdict[self.set_str[1]], setdict[self.set_str[2]],
                 metric=self.config_3pt['metric'])
     tic = time.time()
     print '3PCF took', tic - toc
     stdout.flush()
     self.nnn = nnn
예제 #3
0
파일: corr3.py 프로젝트: mbaumer/TreeCorr
def corr3(config, logger=None):
    """Run the full three-point correlation function code based on the parameters in the
    given config dict.

    The function print_corr3_params() will output information about the valid parameters
    that are expected to be in the config dict.

    Optionally a logger parameter maybe given, in which case it is used for logging.
    If not given, the logging will be based on the verbose and log_file parameters.

    :param config:  The configuration dict which defines what to do.
    :param logger:  If desired, a logger object for logging. (default: None, in which case
                    one will be built according to the config dict's verbose level.)
    """
    # Setup logger based on config verbose value
    if logger is None:
        logger = treecorr.config.setup_logger(
            treecorr.config.get(config, 'verbose', int, 1),
            config.get('log_file', None))

    # Check that config doesn't have any extra parameters.
    # (Such values are probably typos.)
    # Also convert the given parameters to the correct type, etc.
    config = treecorr.config.check_config(config, corr3_valid_params,
                                          corr3_aliases, logger)

    import pprint
    logger.debug('Using configuration dict:\n%s', pprint.pformat(config))

    if ('output_dots' not in config and config.get('log_file', None) is None
            and config['verbose'] >= 2):
        config['output_dots'] = True

    # Set the number of threads
    num_threads = config.get('num_threads', None)
    logger.debug('From config dict, num_threads = %s', num_threads)
    treecorr.set_omp_threads(num_threads, logger)

    # Read in the input files.  Each of these is a list.
    cat1 = treecorr.read_catalogs(config, 'file_name', 'file_list', 0, logger)
    if len(cat1) == 0:
        raise AttributeError("Either file_name or file_list is required")
    cat2 = treecorr.read_catalogs(config, 'file_name2', 'rand_file_list2', 1,
                                  logger)
    cat3 = treecorr.read_catalogs(config, 'file_name3', 'rand_file_list3', 1,
                                  logger)
    rand1 = treecorr.read_catalogs(config, 'rand_file_name', 'rand_file_list',
                                   0, logger)
    rand2 = treecorr.read_catalogs(config, 'rand_file_name2',
                                   'rand_file_list2', 1, logger)
    rand3 = treecorr.read_catalogs(config, 'rand_file_name3',
                                   'rand_file_list3', 1, logger)
    if len(cat2) == 0 and len(rand2) > 0:
        raise AttributeError("rand_file_name2 is invalid without file_name2")
    if len(cat3) == 0 and len(rand3) > 0:
        raise AttributeError("rand_file_name3 is invalid without file_name3")
    logger.info("Done reading input catalogs")

    # Do GGG correlation function if necessary
    if 'ggg_file_name' in config:  #or 'm3_file_name' in config:
        logger.info("Start GGG calculations...")
        ggg = treecorr.GGGCorrelation(config, logger)
        ggg.process(cat1, cat2, cat3)
        logger.info("Done GGG calculations.")
        if 'ggg_file_name' in config:
            ggg.write(config['ggg_file_name'])
        if 'm3_file_name' in config:
            ggg.writeMapSq(config['m3_file_name'])

    # Do NNN correlation function if necessary
    if 'nnn_file_name' in config:
        if len(rand1) == 0:
            raise AttributeError(
                "rand_file_name is required for NNN correlation")
        if len(cat2) > 0 and len(rand2) == 0:
            raise AttributeError(
                "rand_file_name2 is required for NNN cross-correlation")
        if len(cat3) > 0 and len(rand3) == 0:
            raise AttributeError(
                "rand_file_name3 is required for NNN cross-correlation")
        if (len(cat2) > 0) != (len(cat3) > 0):
            raise NotImplementedError(
                "Cannot yet handle 3-point corrleations with only two catalogs. "
                + "Need both cat2 and cat3.")
        logger.info("Start DDD calculations...")
        ddd = treecorr.NNNCorrelation(config, logger)
        ddd.process(cat1, cat2, cat3)
        logger.info("Done DDD calculations.")

        if len(cat2) == 0:
            rrr = treecorr.NNNCorrelation(config, logger)
            rrr.process(rand1)
            logger.info("Done RRR calculations.")

            # For the next step, just make cat2 = cat3 = cat1 and rand2 = rand3 = rand1.
            cat2 = cat3 = cat1
            rand2 = rand3 = rand1
        else:
            rrr = treecorr.NNNCorrelation(config, logger)
            rrr.process(rand1, rand2, rand3)
            logger.info("Done RRR calculations.")

        if config['nnn_statistic'] == 'compensated':
            drr = treecorr.NNNCorrelation(config, logger)
            drr.process(cat1, rand2, rand3)
            logger.info("Done DRR calculations.")
            ddr = treecorr.NNNCorrelation(config, logger)
            ddr.process(cat1, cat2, rand3)
            logger.info("Done DDR calculations.")
            rdr = treecorr.NNNCorrelation(config, logger)
            rdr.process(rand1, cat2, rand3)
            logger.info("Done RDR calculations.")
            rrd = treecorr.NNNCorrelation(config, logger)
            rrd.process(rand1, rand2, cat3)
            logger.info("Done RRD calculations.")
            drd = treecorr.NNNCorrelation(config, logger)
            drd.process(cat1, rand2, cat3)
            logger.info("Done DRD calculations.")
            rdd = treecorr.NNNCorrelation(config, logger)
            rdd.process(rand1, cat2, cat3)
            logger.info("Done RDD calculations.")
            ddd.write(config['nnn_file_name'], rrr, drr, rdr, rrd, ddr, drd,
                      rdd)
        else:
            ddd.write(config['nnn_file_name'], rrr)

    # Do KKK correlation function if necessary
    if 'kkk_file_name' in config:
        logger.info("Start KKK calculations...")
        kkk = treecorr.KKKCorrelation(config, logger)
        kkk.process(cat1, cat2, cat3)
        logger.info("Done KKK calculations.")
        kkk.write(config['kkk_file_name'])

    # Do NNG correlation function if necessary
    if False:
        #if 'nng_file_name' in config or 'nnm_file_name' in config:
        if len(cat3) == 0:
            raise AttributeError("file_name3 is required for nng correlation")
        logger.info("Start NNG calculations...")
        nng = treecorr.NNGCorrelation(config, logger)
        nng.process(cat1, cat2, cat3)
        logger.info("Done NNG calculation.")

        # The default ng_statistic is compensated _iff_ rand files are given.
        rrg = None
        if len(rand1) == 0:
            if config.get('nng_statistic', None) == 'compensated':
                raise AttributeError(
                    "rand_files is required for nng_statistic = compensated")
        elif config.get('nng_statistic', 'compensated') == 'compensated':
            rrg = treecorr.NNGCorrelation(config, logger)
            rrg.process(rand1, rand1, cat2)
            logger.info("Done RRG calculation.")

        if 'nng_file_name' in config:
            nng.write(config['nng_file_name'], rrg)
        if 'nnm_file_name' in config:
            nng.writeNNMap(config['nnm_file_name'], rrg)

    # Do NNK correlation function if necessary
    if False:
        #if 'nnk_file_name' in config:
        if len(cat3) == 0:
            raise AttributeError("file_name3 is required for nnk correlation")
        logger.info("Start NNK calculations...")
        nnk = treecorr.NNKCorrelation(config, logger)
        nnk.process(cat1, cat2, cat3)
        logger.info("Done NNK calculation.")

        rrk = None
        if len(rand1) == 0:
            if config.get('nnk_statistic', None) == 'compensated':
                raise AttributeError(
                    "rand_files is required for nnk_statistic = compensated")
        elif config.get('nnk_statistic', 'compensated') == 'compensated':
            rrk = treecorr.NNKCorrelation(config, logger)
            rrk.process(rand1, rand1, cat2)
            logger.info("Done RRK calculation.")

        nnk.write(config['nnk_file_name'], rrk)

    # Do KKG correlation function if necessary
    if False:
        #if 'kkg_file_name' in config:
        if len(cat3) == 0:
            raise AttributeError("file_name3 is required for kkg correlation")
        logger.info("Start KKG calculations...")
        kkg = treecorr.KKGCorrelation(config, logger)
        kkg.process(cat1, cat2, cat3)
        logger.info("Done KKG calculation.")
        kkg.write(config['kkg_file_name'])
예제 #4
0
    def analyze_single_run(self, mode, **kwargs):

        template = treecorr.NNNCorrelation(config=self.config)

        if mode == 'angle':
            get_binned_stat = computeXvsAngle
        if mode == 'equi':
            get_binned_stat = compute_x_vs_side_length

        binned = {}
        binned['ddd'], bins = get_binned_stat(template,
                                              self.ddd,
                                              stat='sum',
                                              **kwargs)
        binned['ddr'], bins = get_binned_stat(template,
                                              self.ddr,
                                              stat='sum',
                                              **kwargs)
        binned['drd'], bins = get_binned_stat(template,
                                              self.drd,
                                              stat='sum',
                                              **kwargs)
        binned['rdd'], bins = get_binned_stat(template,
                                              self.rdd,
                                              stat='sum',
                                              **kwargs)
        binned['rrd'], bins = get_binned_stat(template,
                                              self.rrd,
                                              stat='sum',
                                              **kwargs)
        binned['drr'], bins = get_binned_stat(template,
                                              self.drr,
                                              stat='sum',
                                              **kwargs)
        binned['rdr'], bins = get_binned_stat(template,
                                              self.rdr,
                                              stat='sum',
                                              **kwargs)
        binned['rrr'], bins = get_binned_stat(template,
                                              self.rrr,
                                              stat='sum',
                                              **kwargs)

        binned['d1'], bins = get_binned_stat(
            template,
            template.u * np.abs(template.v) * np.exp(template.logr) +
            np.exp(template.logr), **kwargs)
        binned['d2'], bins = get_binned_stat(template, np.exp(template.logr),
                                             **kwargs)
        binned['d3'], bins = get_binned_stat(
            template, template.u * np.exp(template.logr), **kwargs)

        datatot = len(self.data)
        randtot = len(self.randoms)
        dddtot = float(datatot)**3 / 6
        drrtot = float(datatot) * float(randtot)**2 / 6
        rdrtot = float(datatot) * float(randtot)**2 / 6
        rrdtot = float(datatot) * float(randtot)**2 / 6
        ddrtot = float(datatot)**2 * float(randtot) / 6
        drdtot = float(datatot)**2 * float(randtot) / 6
        rddtot = float(datatot)**2 * float(randtot) / 6
        rrrtot = float(randtot)**3 / 6

        binned['zeta'] = (binned['ddd'] + dddtot *
                          (-binned['ddr'] / ddrtot - binned['drd'] / drdtot -
                           binned['rdd'] / rddtot + binned['rrd'] / rrdtot +
                           binned['rdr'] / rdrtot + binned['drr'] / drrtot -
                           binned['rrr'] / rrrtot)) / (binned['rrr'] * dddtot /
                                                       rrrtot)
        binned['denom'] = self.get_two_point_expectation(
            binned['d1'], binned['d2'], binned['d3'])
        binned['q'] = binned['zeta'] / binned['denom']
        return bins, binned
예제 #5
0
def test_3pt():
    # Test a direct calculation of the 3pt function with the Periodic metric.

    from test_nnn import is_ccw

    ngal = 50
    Lx = 250.
    Ly = 180.
    rng = np.random.RandomState(8675309)
    x = (rng.random_sample(ngal)-0.5) * Lx
    y = (rng.random_sample(ngal)-0.5) * Ly
    cat = treecorr.Catalog(x=x, y=y)

    min_sep = 1.
    max_sep = 40.  # This only really makes sense if max_sep < L/4 for all L.
    nbins = 50
    min_u = 0.13
    max_u = 0.89
    nubins = 10
    min_v = 0.13
    max_v = 0.59
    nvbins = 10

    ddd = treecorr.NNNCorrelation(min_sep=min_sep, max_sep=max_sep, nbins=nbins,
                                  min_u=min_u, max_u=max_u, nubins=nubins,
                                  min_v=min_v, max_v=max_v, nvbins=nvbins,
                                  bin_slop=0, xperiod=Lx, yperiod=Ly, brute=True)
    ddd.process(cat, metric='Periodic', num_threads=1)
    #print('ddd.ntri = ',ddd.ntri)

    log_min_sep = np.log(min_sep)
    log_max_sep = np.log(max_sep)
    true_ntri = np.zeros( (nbins, nubins, 2*nvbins) )
    bin_size = (log_max_sep - log_min_sep) / nbins
    ubin_size = (max_u-min_u) / nubins
    vbin_size = (max_v-min_v) / nvbins
    for i in range(ngal):
        for j in range(i+1,ngal):
            for k in range(j+1,ngal):
                xi = x[i]
                xj = x[j]
                xk = x[k]
                yi = y[i]
                yj = y[j]
                yk = y[k]
                #print(i,j,k,xi,yi,xj,yj,xk,yk)
                xi,xj = wrap(xi, xj, Lx, xk)
                #print('  ',xi,xj,xk)
                xi,xk = wrap(xi, xk, Lx, xj)
                #print('  ',xi,xj,xk)
                xj,xk = wrap(xj, xk, Lx, xi)
                #print('  ',xi,xj,xk)
                yi,yj = wrap(yi, yj, Ly, yk)
                #print('  ',yi,yj,yk)
                yi,yk = wrap(yi, yk, Ly, yj)
                #print('  ',yi,yj,yk)
                yj,yk = wrap(yj, yk, Ly, yi)
                #print('  ',yi,yj,yk)
                #print('->',xi,yi,xj,yj,xk,yk)
                dij = np.sqrt((xi-xj)**2 + (yi-yj)**2)
                dik = np.sqrt((xi-xk)**2 + (yi-yk)**2)
                djk = np.sqrt((xj-xk)**2 + (yj-yk)**2)
                if dij == 0.: continue
                if dik == 0.: continue
                if djk == 0.: continue
                ccw = True
                if dij < dik:
                    if dik < djk:
                        d3 = dij; d2 = dik; d1 = djk;
                        ccw = is_ccw(xi,yi,xj,yj,xk,yk)
                    elif dij < djk:
                        d3 = dij; d2 = djk; d1 = dik;
                        ccw = is_ccw(xj,yj,xi,yi,xk,yk)
                    else:
                        d3 = djk; d2 = dij; d1 = dik;
                        ccw = is_ccw(xj,yj,xk,yk,xi,yi)
                else:
                    if dij < djk:
                        d3 = dik; d2 = dij; d1 = djk;
                        ccw = is_ccw(xi,yi,xk,yk,xj,yj)
                    elif dik < djk:
                        d3 = dik; d2 = djk; d1 = dij;
                        ccw = is_ccw(xk,yk,xi,yi,xj,yj)
                    else:
                        d3 = djk; d2 = dik; d1 = dij;
                        ccw = is_ccw(xk,yk,xj,yj,xi,yi)

                #print('d1,d2,d3 = ',d1,d2,d3)
                r = d2
                u = d3/d2
                v = (d1-d2)/d3
                if r < min_sep or r >= max_sep: continue
                if u < min_u or u >= max_u: continue
                if v < min_v or v >= max_v: continue
                if not ccw:
                    v = -v
                #print('r,u,v = ',r,u,v)
                kr = int(np.floor( (np.log(r)-log_min_sep) / bin_size ))
                ku = int(np.floor( (u-min_u) / ubin_size ))
                if v > 0:
                    kv = int(np.floor( (v-min_v) / vbin_size )) + nvbins
                else:
                    kv = int(np.floor( (v-(-max_v)) / vbin_size ))
                #print('kr,ku,kv = ',kr,ku,kv)
                assert 0 <= kr < nbins
                assert 0 <= ku < nubins
                assert 0 <= kv < 2*nvbins
                true_ntri[kr,ku,kv] += 1
                #print('good.', true_ntri[kr,ku,kv])


    #print('true_ntri => ',true_ntri)
    #print('diff = ',ddd.ntri - true_ntri)
    mask = np.where(true_ntri > 0)
    #print('ddd.ntri[mask] = ',ddd.ntri[mask])
    #print('true_ntri[mask] = ',true_ntri[mask])
    #print('diff[mask] = ',(ddd.ntri - true_ntri)[mask])
    mask2 = np.where(ddd.ntri > 0)
    #print('ddd.ntri[mask2] = ',ddd.ntri[mask2])
    #print('true_ntri[mask2] = ',true_ntri[mask2])
    #print('diff[mask2] = ',(ddd.ntri - true_ntri)[mask2])
    np.testing.assert_array_equal(ddd.ntri, true_ntri)

    # If don't give a period, then an error.
    ddd = treecorr.NNNCorrelation(min_sep=min_sep, max_sep=max_sep, nbins=nbins,
                                  min_u=min_u, max_u=max_u, nubins=nubins,
                                  min_v=min_v, max_v=max_v, nvbins=nvbins)
    with assert_raises(ValueError):
        ddd.process(cat, metric='Periodic')

    # Or if only give one kind of period
    ddd = treecorr.NNNCorrelation(min_sep=min_sep, max_sep=max_sep, nbins=nbins,
                                  min_u=min_u, max_u=max_u, nubins=nubins,
                                  min_v=min_v, max_v=max_v, nvbins=nvbins,
                                  xperiod=3)
    with assert_raises(ValueError):
        ddd.process(cat, metric='Periodic')
    ddd = treecorr.NNNCorrelation(min_sep=min_sep, max_sep=max_sep, nbins=nbins,
                                  min_u=min_u, max_u=max_u, nubins=nubins,
                                  min_v=min_v, max_v=max_v, nvbins=nvbins,
                                  yperiod=3)
    with assert_raises(ValueError):
        ddd.process(cat, metric='Periodic')

    # If give period, but then don't use Periodic metric, that's also an error.
    ddd = treecorr.NNNCorrelation(min_sep=min_sep, max_sep=max_sep, nbins=nbins,
                                  min_u=min_u, max_u=max_u, nubins=nubins,
                                  min_v=min_v, max_v=max_v, nvbins=nvbins,
                                  period=3)
    with assert_raises(ValueError):
        ddd.process(cat)
예제 #6
0
 def load(self):
     [ddd, ddr, drd, rdd, drr, rdr, rrd,
      rrr] = 8 * [treecorr.NNNCorrelation(config=self.config)]
     for nnn in [ddd, ddr, drd, rdd, drr, rdr, rrd, rrr]:
         pass
예제 #7
0
        var[np.where(isRightSize & isCollapsed)],
        bins=nbins,
        statistic='mean')
    full_var = np.concatenate((out2, out1))
    #make edges centers
    bins1 += (bins1[1] - bins1[0]) / 2
    bins2 += (bins2[1] - bins2[0]) / 2
    full_bins = np.concatenate((bins2[:-1], bins1[:-1]))
    return full_var, full_bins


#load data
with open(output_dir + runname + '.config') as f:
    config = json.loads(f.read())

nnn = treecorr.NNNCorrelation(config=config)
rrr = treecorr.NNNCorrelation(config=config)

ddd.read(output_dir + runname + str(random_set_id) + '.out', file_type='FITS')
drr.read(output_dir + runname + str(random_set_id) + '.out', file_type='FITS')

data = fits.getdata(output_dir + 'redmagic_Y1_sims_data.fits')
randoms = fits.getdata(output_dir + 'redmagic_Y1_sims_5x_randoms.fits')

data = data[((data['ZREDMAGIC'] > config['min_z']) &
             (data['ZREDMAGIC'] < config['max_z']))]
data = data[((data['RA'] > config['min_ra']) &
             (data['RA'] < config['max_ra']))]
data = data[((data['DEC'] > config['min_dec']) &
             (data['DEC'] < config['max_dec']))]
예제 #8
0
파일: corr3.py 프로젝트: ztq1996/TreeCorr
def corr3(config, logger=None):
    """Run the full three-point correlation function code based on the parameters in the
    given config dict.

    The function `print_corr3_params` will output information about the valid parameters
    that are expected to be in the config dict.

    Optionally a logger parameter maybe given, in which case it is used for logging.
    If not given, the logging will be based on the verbose and log_file parameters.

    :param config:  The configuration dict which defines what to do.
    :param logger:  If desired, a logger object for logging. (default: None, in which case
                    one will be built according to the config dict's verbose level.)
    """
    # Setup logger based on config verbose value
    if logger is None:
        logger = treecorr.config.setup_logger(
            treecorr.config.get(config, 'verbose', int, 1),
            config.get('log_file', None))

    # Check that config doesn't have any extra parameters.
    # (Such values are probably typos.)
    # Also convert the given parameters to the correct type, etc.
    config = treecorr.config.check_config(config, corr3_valid_params,
                                          corr3_aliases, logger)

    import pprint
    logger.debug('Using configuration dict:\n%s', pprint.pformat(config))

    if ('output_dots' not in config and config.get('log_file', None) is None
            and config['verbose'] >= 2):
        config['output_dots'] = True

    # Set the number of threads
    num_threads = config.get('num_threads', None)
    logger.debug('From config dict, num_threads = %s', num_threads)
    treecorr.set_omp_threads(num_threads, logger)

    # Read in the input files.  Each of these is a list.
    cat1 = treecorr.read_catalogs(config, 'file_name', 'file_list', 0, logger)
    cat2 = treecorr.read_catalogs(config, 'file_name2', 'rand_file_list2', 1,
                                  logger)
    cat3 = treecorr.read_catalogs(config, 'file_name3', 'rand_file_list3', 1,
                                  logger)
    rand1 = treecorr.read_catalogs(config, 'rand_file_name', 'rand_file_list',
                                   0, logger)
    rand2 = treecorr.read_catalogs(config, 'rand_file_name2',
                                   'rand_file_list2', 1, logger)
    rand3 = treecorr.read_catalogs(config, 'rand_file_name3',
                                   'rand_file_list3', 1, logger)
    if len(cat1) == 0:
        raise TypeError("Either file_name or file_list is required")
    if len(cat2) == 0: cat2 = None
    if len(cat3) == 0: cat3 = None
    if len(rand1) == 0: rand1 = None
    if len(rand2) == 0: rand2 = None
    if len(rand3) == 0: rand3 = None
    if cat2 is None and rand2 is not None:
        raise TypeError("rand_file_name2 is invalid without file_name2")
    if cat3 is None and rand3 is not None:
        raise TypeError("rand_file_name3 is invalid without file_name3")
    if (cat2 is None) != (cat3 is None):
        raise NotImplementedError(
            "Cannot yet handle 3-point corrleations with only two catalogs. " +
            "Need both cat2 and cat3.")
    logger.info("Done reading input catalogs")

    # Do GGG correlation function if necessary
    if 'ggg_file_name' in config or 'm3_file_name' in config:
        logger.warning("Performing GGG calculations...")
        ggg = treecorr.GGGCorrelation(config, logger)
        ggg.process(cat1, cat2, cat3)
        logger.info("Done GGG calculations.")
        if 'ggg_file_name' in config:
            ggg.write(config['ggg_file_name'])
            logger.warning("Wrote GGG correlation to %s",
                           config['ggg_file_name'])
        if 'm3_file_name' in config:
            ggg.writeMap3(config['m3_file_name'])
            logger.warning("Wrote Map3 values to %s", config['m3_file_name'])

    # Do NNN correlation function if necessary
    if 'nnn_file_name' in config:
        logger.warning("Performing DDD calculations...")
        ddd = treecorr.NNNCorrelation(config, logger)
        ddd.process(cat1, cat2, cat3)
        logger.info("Done DDD calculations.")

        drr = None
        rdr = None
        rrd = None
        ddr = None
        drd = None
        rdd = None
        if rand1 is None:
            if rand2 is not None or rand3 is not None:
                raise TypeError(
                    "rand_file_name is required if rand2 or rand3 is given")
            logger.warning(
                "No random catalogs given.  Only doing ntri calculation.")
            rrr = None
        elif cat2 is None:
            logger.warning("Performing RRR calculations...")
            rrr = treecorr.NNNCorrelation(config, logger)
            rrr.process(rand1)
            logger.info("Done RRR calculations.")

            # For the next step, just make cat2 = cat3 = cat1 and rand2 = rand3 = rand1.
            cat2 = cat3 = cat1
            rand2 = rand3 = rand1
        else:
            if rand2 is None:
                raise TypeError(
                    "rand_file_name2 is required when file_name2 is given")
            if cat3 is not None and rand3 is None:
                raise TypeError(
                    "rand_file_name3 is required when file_name3 is given")
            logger.warning("Performing RRR calculations...")
            rrr = treecorr.NNNCorrelation(config, logger)
            rrr.process(rand1, rand2, rand3)
            logger.info("Done RRR calculations.")

        if rrr is not None and config['nnn_statistic'] == 'compensated':
            logger.warning("Performing DRR calculations...")
            drr = treecorr.NNNCorrelation(config, logger)
            drr.process(cat1, rand2, rand3)
            logger.info("Done DRR calculations.")
            logger.warning("Performing DDR calculations...")
            ddr = treecorr.NNNCorrelation(config, logger)
            ddr.process(cat1, cat2, rand3)
            logger.info("Done DDR calculations.")
            logger.warning("Performing RDR calculations...")
            rdr = treecorr.NNNCorrelation(config, logger)
            rdr.process(rand1, cat2, rand3)
            logger.info("Done RDR calculations.")
            logger.warning("Performing RRD calculations...")
            rrd = treecorr.NNNCorrelation(config, logger)
            rrd.process(rand1, rand2, cat3)
            logger.info("Done RRD calculations.")
            logger.warning("Performing DRD calculations...")
            drd = treecorr.NNNCorrelation(config, logger)
            drd.process(cat1, rand2, cat3)
            logger.info("Done DRD calculations.")
            logger.warning("Performing RDD calculations...")
            rdd = treecorr.NNNCorrelation(config, logger)
            rdd.process(rand1, cat2, cat3)
            logger.info("Done RDD calculations.")
        ddd.write(config['nnn_file_name'], rrr, drr, rdr, rrd, ddr, drd, rdd)
        logger.warning("Wrote NNN correlation to %s", config['nnn_file_name'])

    # Do KKK correlation function if necessary
    if 'kkk_file_name' in config:
        logger.warning("Performing KKK calculations...")
        kkk = treecorr.KKKCorrelation(config, logger)
        kkk.process(cat1, cat2, cat3)
        logger.info("Done KKK calculations.")
        kkk.write(config['kkk_file_name'])
        logger.warning("Wrote KKK correlation to %s", config['kkk_file_name'])