def make_data_tree(self):
     #The astroML correlation function methods want a cartesian position
     #instead of the angular positions- this does the conversion
     
     print "make_datatree says: Computing the BallTree for data."
     data = np.asarray(corr.ra_dec_to_xyz(self._ra[self._use], self._dec[self._use]), order='F').T
     self._data_tree = BallTree(data, leaf_size=2)
     
     return
    def make_random_tree(self):
        #Make sure we have the random data made
        if (self._ra_random is None) or (self._dec_random is None):
            print "make_random_tree says: no random sample found.  Generating one."
            self.generate_random_sample()

        #Make the tree
        print "make_randomtree says: Computing the BallTree for the randoms."
        random_data=np.asarray(corr.ra_dec_to_xyz(self._ra_random, self._dec_random), order='F').T
        self._random_tree = BallTree(random_data, leaf_size=2)                
                
        return          
    def generate_rr(self, set_nbins=None, logbins=True, min_sep=0.01, 
                    force_n_randoms=None, save_to=None, n_chunks=1):
        #Do random-random counts over the entire field.  If set_nbins is declared,
        #generate_rr will not go looking for the correlation functions so that the
        #RR counts for the IC calculation and the CF calculation can be done in parallel.
 
        #Figure out how many randoms we need.  This was calculated by playing with
        #the number of randoms in the GOODS-S field and seeing when the RR counts converged
        #to the "way too many" curve.  27860 per 1.43e-5 steradians was what I settled on.
        #If there's a forced number, it will ignore my estimate.
        #  Amendment 4/15- this minimum number seems to be somewhat too small for fields that 
        #                  aren't as smooth as GOODS-S, so I'm multiplying it by 5.  This looks ok.
        #  Amendment 8/15- added the capability to do this in several chunks.
        
        if force_n_randoms is None:
            surface_density_required = 27860.*5./1.43e-5
            area = self._image_mask.masked_area_solid_angle()
            number_needed = surface_density_required * area
        else:
            number_needed=force_n_randoms

        #If we're doing more than one chunk, divide the number we need into n_chunks chunks
        if n_chunks > 1:
            number_needed = np.ceil(float(number_needed)/n_chunks).astype(int)
        total_number = number_needed * n_chunks
        print "total number: ",  total_number
        print "number per iteration: ", number_needed
        print "number of chunks: ", n_chunks

        #Range of separations to make bins over
        min_ra = self._ra[self._use].min()
        min_dec = self._dec[self._use].min()
        max_ra = self._ra[self._use].max()
        max_dec = self._dec[self._use].max()
        max_sep=misc.ang_sep(min_ra, min_dec, max_ra, max_dec,
                           radians_in=False, radians_out=False)

        #Choose how many bins
        if set_nbins is None:
            #Get our theta bin info from the CF if we can.  Error if we can't
            if self._theta_bins is None:
                raise ValueError("AngularCatalog.generate_rr says: I need"
                                " either a set number of bins (set_nbins=N)"
                                " or thetas from a CF to extrapolate. "
                                " You have given me neither.")
            centers, edges = self._cfs[name].get_thetas(unit='degrees')
            nbins= np.ceil( len(centers) * 2. * max_sep/edges.max())
        else:
            nbins=set_nbins

        #Make the bins
        rr_theta_bins = binclass.ThetaBins(min_sep, max_sep, nbins,
                                           unit='d', logbins=logbins)
        use_centers, use_theta_bins = rr_theta_bins.get_thetas(unit='degrees')

        #Do the loop
        G_p=np.zeros(nbins)
        rr_counts=np.zeros(nbins)
        for n_i in np.arange(n_chunks):
            print "doing chunk #", n_i
            #Remake the random sample so we're sure we have the right oversample factor            
            self.generate_random_sample(masked=True, make_exactly=number_needed)
        
            #Code snippet shamelessly copied from astroML.correlations
            xyz_data = corr.ra_dec_to_xyz(self._ra_random,
                                         self._dec_random)
            data_R = np.asarray(xyz_data, order='F').T
            bins = corr.angular_dist_to_euclidean_dist(use_theta_bins)
            Nbins = len(bins) - 1
            counts_RR = np.zeros(Nbins + 1)
            for i in range(Nbins + 1):
                counts_RR[i] = np.sum(self._random_tree.query_radius(data_R, bins[i],
                                                                            count_only=True))
            rr = np.diff(counts_RR)
            #Landy and Szalay define G_p(theta) as <N_p(theta)>/(n(n-1)/2)
            G_p += rr/(number_needed*(number_needed-1)) 
            rr_counts += rr

        print "Dividing out the theta bin sizes and number of chunks"
        
        #I divide out the bin width because just using the method
        #that L&S detail gives you a {G_p,i} with the property that
        #Sum[G_p,i]=1.  This is not equivalent to Integral[G_p d(theta)]=1,
        #which is what they assume everywhere else.
        #Dividing out the bin width gives you that and lets you pretend
        #G_p is a continuous but chunky-looking function.
        G_p /= np.diff(use_theta_bins)                    
        G_p /= n_chunks                                   
        self._rr_ngals=[total_number, n_chunks]
        self._Gp = gpclass.Gp(min_sep, max_sep, nbins, G_p, total_number,
                              n_chunks, logbins=logbins, unit='d',
                              RR=rr_counts)

        if save_to is not None:
            self.save_gp(save_to)