7 static double dist2(
double x0,
double y0,
double x1,
double y1)
10 return (x0-x1)*(x0-x1) + (y0-y1)*(y0-y1);
15 static int nearest_neighbors(
int n,
double x,
double y,
int Npts,
const double * vx,
16 const double * vy,
int * nearest_i,
double * nearest_d2)
21 for (
int i = 0; i < Npts; i++)
24 double d2 = dist2(x,y,vx[i],vy[i]);
32 else if (d2 < nearest_d2[nfound-1])
37 if (nfound < n) nfound++;
40 for (
int ii = 0 ; ii < last-1; ii++)
42 if (d2 < nearest_d2[ii])
51 for (
int ii = nfound-1; ii > new_index; ii--)
53 nearest_d2[ii] = nearest_d2[ii-1];
54 nearest_i[ii] = nearest_i[ii-1];
57 nearest_d2[new_index] = d2;
58 nearest_i[new_index] = i;
66 UCorrelator::KDE2D::KDE2D(
int n,
const double *xin,
const double * yin,
const double * weights, KDE2DOptions opt)
67 : x(xin, xin+n), y(yin,yin+n)
71 w.insert(w.end(), weights, weights+n);
74 double sx = opt.sigma_x ? opt.sigma_x: pow(n,-1./6)*TMath::RMS(n,xin);
75 double sy = opt.sigma_y ? opt.sigma_y: pow(n,-1./6)*TMath::RMS(n,yin);
79 if (opt.adaptiveness == 0)
82 sigma_x.push_back(sx);
83 sigma_y.push_back(sy);
84 rho.push_back(opt.corr);
85 double sum_of_weights = n;
89 for (
unsigned i = 0; i < w.size(); i++) sum_of_weights += w[i];
91 W = 1./( 2*sum_of_weights*M_PI * sx*sy*sqrt(1-opt.corr*opt.corr));
100 std::vector<double> nearest_d2(opt.adaptiveness+1);
101 std::vector<int> nearest_i(opt.adaptiveness+1);
103 for (
int i = 0; i < n; i++)
105 int found = nearest_neighbors(opt.adaptiveness+1, xin[i],yin[i], n, xin, yin, &nearest_i[0], &nearest_d2[0]);
107 double d2 =nearest_d2[found-1];
109 sigma_x.push_back(sx * d);
110 sigma_y.push_back(sy * d);
111 rho.push_back(opt.corr * d);
112 double this_w = w.size() ? w[i] : 1;
113 Winv += this_w/( 2*d2*M_PI * sx*sy*sqrt(1-d2*opt.corr*opt.corr));
121 double UCorrelator::KDE2D::operator()(
double xt,
double yt)
const 124 double sxinv = 1./sigma_x[0];
125 double syinv = 1./sigma_y[0];
126 double sxinv2 = sxinv*sxinv;
127 double syinv2 = syinv*syinv;
129 double one_minus_r_inv = 1./(1-r);
130 double sxyinv = r == 0 ? 0 : sxinv*syinv;
133 for (
unsigned i = 0; i < x.size(); i++)
135 if (sigma_x.size() > 1 && i > 0)
137 sxinv = 1./sigma_x[i];
138 syinv = 1./sigma_y[i];
139 sxinv2 = sxinv*sxinv;
140 syinv2 = syinv*syinv;
142 one_minus_r_inv = 1./(1-r);
143 sxyinv = r == 0 ? 0 : sxinv*syinv;
146 double xd = ( x[i] - xt);
147 double yd = ( y[i] - yt);
148 double z = xd*xd*sxinv2 + yd*yd*syinv2;
149 if (r!=0) z -= 2*r*xd*yd*sxyinv;
150 double this_w = w.size() == 0 ? 1 : w[i];
151 sum += this_w * (r == 0 ? exp ( - 0.5* z ) : exp(-0.5*z*one_minus_r_inv));
158 void UCorrelator::KDE2D::getNSigmaBounds(
double nsig,
double & xmin,
double & xmax,
double & ymin,
double & ymax)
const 161 double sig_x = sigma_x[0];
162 double sig_y = sigma_y[0];
164 xmin = x[0] - sig_x * nsig;
165 xmax = x[0] + sig_x * nsig;
166 ymin = y[0] - sig_y * nsig;
167 ymax = y[0] + sig_y * nsig;
169 for (
unsigned i = 1; i < x.size() ; i++)
171 if (sigma_x.size() > 1)
177 double test_xmin = x[i] - sig_x * nsig;
178 double test_xmax = x[i] + sig_x * nsig;
179 double test_ymin = y[i] - sig_y * nsig;
180 double test_ymax = y[i] + sig_y * nsig;
183 if (test_xmin < xmin) xmin = test_xmin;
184 if (test_ymin < ymin) ymin = test_ymin;
185 if (test_xmax > xmax) xmax = test_xmax;
186 if (test_ymax > ymax) ymax = test_ymax;
191 TF2 * UCorrelator::KDE2D::makeTF2(
const char * name,
double nsigma_bounds)
const 194 double xmin,xmax,ymin,ymax;
195 getNSigmaBounds(nsigma_bounds,xmin,xmax,ymin,ymax);
197 return new TF2(name,
this, xmin,xmax,ymin,ymax, 0,2);
200 TH2 *
UCorrelator::KDE2D::makeTH2(
double binwidth_x,
double binwidth_y,
const char * name,
const char * title,
double nsigma_bounds,
double auto_factor)
const 203 double xmin,xmax,ymin,ymax;
204 getNSigmaBounds(nsigma_bounds,xmin,xmax,ymin,ymax);
208 binwidth_x = sigma_x[0] * auto_factor;
209 for (
unsigned i = 1; i < sigma_x.size(); i++) binwidth_x = TMath::Min(binwidth_x, sigma_x[i]*auto_factor);
214 binwidth_y = sigma_y[0] * auto_factor;
215 for (
unsigned i = 1; i < sigma_y.size(); i++) binwidth_y = TMath::Min(binwidth_y, sigma_y[i]*auto_factor);
218 int nbinsx = ceil((xmax-xmin)/binwidth_x);
219 int nbinsy = ceil((ymax-ymin)/binwidth_x);
220 xmax = xmin + nbinsx * binwidth_x;
221 ymax = ymin + nbinsy * binwidth_y;
223 TH2 * h =
new TH2D ( name,title, nbinsx, xmin, xmax, nbinsy, ymin, ymax);
225 h->SetEntries(x.size());
226 for (
int i = 1; i <= h->GetNbinsX(); i++)
228 for (
int j = 1; j <= h->GetNbinsY(); j++)
230 h->SetBinContent(i,j, this->
operator()(h->GetXaxis()->GetBinCenter(i), h->GetYaxis()->GetBinCenter(j)));
TH2 * makeTH2(double binwidth_x=0, double binwidth_y=0, const char *name="hkde2d", const char *title="Kernel Density Estimator", double n_sigma_bound=3, double auto_factor=0.25) const