#define REPORT_PROCESS_TIME 0
#include <iostream>
#include <TROOT.h>
#include <TMath.h>
#include <TCanvas.h>
#include "Map2D.h"
#include <list>
#include <TMatrixD.h>
#include <TDecompSVD.h>
#include <sys/time.h>
#include <sys/resource.h>
ClassImp(Map2D);
#ifndef SQR_FUNC
#define SQR_FUNC 1
Double_t sqr(Double_t x) { return x*x; }
#endif
const Double_t Map2D::zunit2xy = 0.001;
#define EMBED_BREAKPOINT asm volatile ("int3;")
Map2D::Map2D() : TH2D()
{
SetStats(0);
}
Map2D::Map2D(const Map2D &m) : TH2D((TH2D&)m)
{
SetStats(0);
}
Map2D::Map2D(const TH2D &h) : TH2D(h)
{
SetStats(0);
}
Map2D::~Map2D()
{ }
Map2D &Map2D::Add(const Map2D *map, Double_t c)
{
Int_t nxbins = map->GetXaxis()->GetNbins();
Int_t nybins = map->GetYaxis()->GetNbins();
if (nxbins != GetXaxis()->GetNbins() ||
nybins != GetYaxis()->GetNbins()) {
std::cerr << "Error in Map2D::Add - source and destination histograms"
<< " have different dimensions, cannot add them"
<< std::endl;
return *this;
}
for (Int_t i=1; i <= nxbins; ++i) {
for (Int_t j=1; j <= nybins; ++j) {
Double_t z1 = map->GetBinContent(i,j);
Double_t z0 = GetBinContent(i,j);
SetBinContent(i,j,z0+c*z1);
}
}
return *this;
}
Map2D &Map2D::Add(const Map2D *map1, const Map2D *map2,
Double_t c1, Double_t c2)
{
Int_t nxbins = map1->GetXaxis()->GetNbins();
Int_t nybins = map1->GetYaxis()->GetNbins();
if (nxbins != map2->GetXaxis()->GetNbins() ||
nybins != map2->GetYaxis()->GetNbins()) {
std::cerr << "Error in Map2D::Add - two source histograms"
<< " have different dimensions, cannot add them"
<< std::endl;
return *this;
}
else if (nxbins != GetXaxis()->GetNbins() ||
nybins != GetYaxis()->GetNbins()) {
Double_t xmin = map1->GetXaxis()->GetXmin();
Double_t xmax = map1->GetXaxis()->GetXmax();
Double_t ymin = map1->GetYaxis()->GetXmin();
Double_t ymax = map1->GetYaxis()->GetXmax();
SetBins(nxbins,xmin,xmax,nybins,ymin,ymax);
}
for (Int_t i=1; i <= nxbins; ++i) {
for (Int_t j=1; j <= nybins; ++j) {
Double_t z1 = map1->GetBinContent(i,j);
Double_t z2 = map2->GetBinContent(i,j);
SetBinContent(i,j,c1*z1+c2*z2);
}
}
return *this;
}
Map2D &Map2D::Shift(Double_t dx, Double_t dy, Double_t dz)
{
Map2D *tmp = shift(dx,dy,dz);
*this = *tmp;
delete tmp;
return *this;
}
Map2D *Map2D::shift(Double_t dx, Double_t dy, Double_t dz) const
{
Int_t nxbins = GetXaxis()->GetNbins();
Int_t nybins = GetYaxis()->GetNbins();
Double_t xmin = GetXaxis()->GetXmin();
Double_t xmax = GetXaxis()->GetXmax();
Double_t ymin = GetYaxis()->GetXmin();
Double_t ymax = GetYaxis()->GetXmax();
Double_t dbinx = dx/(xmax-xmin)*nxbins;
Double_t dbiny = dy/(ymax-ymin)*nybins;
Int_t di = int(dbinx);
Int_t dj = int(dbiny);
Int_t i0 = (di > 0)? di+1 : 1;
Int_t j0 = (dj > 0)? dj+1 : 1;
Int_t i1 = (di < 0)? di+nxbins : nxbins;
Int_t j1 = (dj < 0)? dj+nybins : nybins;
Double_t fx1 = dbinx-di;
Double_t fy1 = dbiny-dj;
Double_t fx0 = 1-fx1;
Double_t fy0 = 1-fy1;
Map2D *dst = new Map2D(*this);
dst->Reset();
for (Int_t i=i0; i < i1; ++i) {
Int_t isrc = i-di;
Double_t z00 = GetBinContent(isrc,j0-dj);
Double_t z10 = GetBinContent(isrc+1,j0-dj);
Double_t zint0 = (z00 == 0)? ((fx0 > 0.5)? 0 : z10) :
(z10 == 0)? ((fx1 > 0.5)? 0 : z00) :
z00*fx0 + z10*fx1;
for (Int_t j=j0; j < j1; ++j) {
Int_t jsrc = j-dj;
Double_t z01 = GetBinContent(isrc,jsrc+1);
Double_t z11 = GetBinContent(isrc+1,jsrc+1);
Double_t zint1 = (z01 == 0)? ((fx0 > 0.5)? 0 : z11) :
(z11 == 0)? ((fx1 > 0.5)? 0 : z01) :
z01*fx0 + z11*fx1;
Double_t zint = (zint0 == 0)? ((fy0 > 0.5)? 0 : zint1) :
(zint1 == 0)? ((fy1 > 0.5)? 0 : zint0) :
zint0*fy0 + zint1*fy1;
dst->SetBinContent(i,j,(zint == 0)? 0 : zint+dz);
zint0 = zint1;
}
}
return dst;
}
Map2D &Map2D::Rotate(Double_t phi, Double_t theta, Double_t psi, Int_t degrees)
{
Double_t xmin = GetXaxis()->GetXmin();
Double_t xmax = GetXaxis()->GetXmax();
Double_t ymin = GetYaxis()->GetXmin();
Double_t ymax = GetYaxis()->GetXmax();
Double_t x0 = (xmin+xmax)/2;
Double_t y0 = (ymin+ymax)/2;
Int_t nxbins = GetXaxis()->GetNbins();
Int_t nybins = GetYaxis()->GetNbins();
Int_t pcount=0;
for (Int_t ix=1; ix <= nxbins; ++ix) {
for (Int_t iy=1; iy <= nybins; ++iy) {
if (GetBinContent(ix,iy)) {
++pcount;
}
}
}
Int_t i0 = nxbins/2;
Int_t j0 = nybins/2;
Int_t peri=0;
Double_t sum0=1;
Double_t sum1=GetBinContent(i0,j0);
while (sum0 < pcount/10) {
++peri;
for (Int_t i=-peri; i < peri; ++i) {
Double_t z;
sum1 += ((z=GetBinContent(i0+i,j0-peri)) != 0)? ++sum0,z : 0;
sum1 += ((z=GetBinContent(i0+peri,j0+i)) != 0)? ++sum0,z : 0;
sum1 += ((z=GetBinContent(i0-i,j0+peri)) != 0)? ++sum0,z : 0;
sum1 += ((z=GetBinContent(i0-peri,j0-i)) != 0)? ++sum0,z : 0;
}
}
Double_t z0 = sum1/sum0;
Double_t toradians = (degrees)? M_PI/180 : 1;
Double_t thetax = theta*cos(phi*toradians);
Double_t thetay = theta*sin(phi*toradians);
Map2D *tmp1 = this;
if (thetax != 0) {
tmp1 = rotateX(thetax*toradians,y0,z0);
}
Map2D *tmp2 = tmp1;
if (thetay != 0) {
tmp2 = tmp1->rotateY(thetay*toradians,x0,z0);
}
Map2D *tmp3 = tmp2;
if (psi != 0) {
tmp3 = tmp2->rotateZ(psi*toradians,x0,y0);
}
if (tmp3 != this) {
*this = *tmp3;
}
if (tmp1 != this) {
delete tmp1;
}
if (tmp2 != tmp1) {
delete tmp2;
}
if (tmp3 != tmp2) {
delete tmp3;
}
return *this;
}
Map2D *Map2D::rotateX(Double_t thetarad, Double_t y0, Double_t z0) const
{
Int_t nxbins = GetXaxis()->GetNbins();
Int_t nybins = GetYaxis()->GetNbins();
Double_t ymin = GetYaxis()->GetXmin();
Double_t ymax = GetYaxis()->GetXmax();
Double_t dy = (ymax-ymin)/nybins;
Double_t costheta = cos(thetarad);
Double_t sintheta = sin(thetarad);
Map2D *dst = new Map2D(*this);
dst->Reset();
for (Int_t j=1; j <= nybins; ++j) {
Double_t y = ymin+(j-0.5)*(ymax-ymin)/nybins - y0;
for (Int_t i=1; i <= nxbins; ++i) {
Double_t z = GetBinContent(i,j);
if (z == 0) {
dst->SetBinContent(i,j,0);
}
else {
dst->SetBinContent(i,j,y*sintheta/zunit2xy+(z-z0)*costheta+z0);
}
if (fabs((z-z0)*sintheta)*zunit2xy > dy) {
std::cerr << "Warning in Map2D::rotateX - loss of accuracy"
<< " trying to rotate too far away from normal."
<< std::endl;
}
}
}
Map2D *redst = dst->rescale(1,costheta,1,0,y0,0);
delete dst;
return redst;
}
Map2D *Map2D::rotateY(Double_t thetarad, Double_t x0, Double_t z0) const
{
Int_t nxbins = GetXaxis()->GetNbins();
Int_t nybins = GetYaxis()->GetNbins();
Double_t xmin = GetXaxis()->GetXmin();
Double_t xmax = GetXaxis()->GetXmax();
Double_t dx = (xmax-xmin)/nxbins;
Double_t costheta = cos(thetarad);
Double_t sintheta = sin(thetarad);
Map2D *dst = new Map2D(*this);
dst->Reset();
for (Int_t i=1; i <= nxbins; ++i) {
Double_t x = xmin+(i-0.5)*(xmax-xmin)/nxbins - x0;
for (Int_t j=1; j <= nybins; ++j) {
Double_t z = GetBinContent(i,j);
if (z == 0) {
dst->SetBinContent(i,j,0);
}
else {
dst->SetBinContent(i,j,-x*sintheta/zunit2xy+(z-z0)*costheta+z0);
}
if (fabs((z-z0)*sintheta)*zunit2xy > dx) {
std::cerr << "Warning in Map2D::rotateY - loss of accuracy"
<< " trying to rotate too far away from normal."
<< std::endl;
}
}
}
Map2D *redst = dst->rescale(costheta,1,1,x0,0,0);
delete dst;
return redst;
}
Map2D *Map2D::rotateZ(Double_t phirad, Double_t x0, Double_t y0) const
{
Int_t nxbins = GetXaxis()->GetNbins();
Int_t nybins = GetYaxis()->GetNbins();
Double_t xmin = GetXaxis()->GetXmin();
Double_t xmax = GetXaxis()->GetXmax();
Double_t ymin = GetYaxis()->GetXmin();
Double_t ymax = GetYaxis()->GetXmax();
Double_t dx = (xmax-xmin)/nxbins;
Double_t dy = (ymax-ymin)/nybins;
Double_t cosphi = cos(phirad);
Double_t sinphi = sin(phirad);
Map2D *dst = new Map2D(*this);
dst->Reset();
for (Int_t i=1; i <= nxbins; ++i) {
Double_t x = xmin+(i-0.5)*dx - x0;
for (Int_t j=1; j <= nybins; ++j) {
Double_t y = ymin+(j-0.5)*dy - y0;
Double_t xsrc = x*cosphi+y*sinphi + x0;
Double_t ysrc = y*cosphi-x*sinphi + y0;
Double_t xbins = (xsrc-xmin)/dx;
Double_t ybins = (ysrc-ymin)/dy;
if (xbins < 0 || xbins > nxbins ||
ybins < 0 || ybins > nybins) {
continue;
}
Int_t i0 = int(xbins+0.5);
Int_t j0 = int(ybins+0.5);
i0 = (i0 < 1)? 1 : i0;
j0 = (j0 < 1)? 1 : j0;
Int_t i1 = (i0 >= nxbins)? i0 : i0+1;
Int_t j1 = (j0 >= nybins)? j0 : j0+1;
Double_t fx0 = xbins+0.5-i0;
Double_t fy0 = ybins+0.5-j0;
Double_t fx1 = 1-fx0;
Double_t fy1 = 1-fy0;
Double_t z00 = GetBinContent(i0,j0);
Double_t z10 = GetBinContent(i1,j0);
Double_t z01 = GetBinContent(i0,j1);
Double_t z11 = GetBinContent(i1,j1);
Double_t zint0 = (z00 == 0)? ((fx0 > 0.5)? 0 : z10) :
(z10 == 0)? ((fx1 > 0.5)? 0 : z00) :
z00*fx0 + z10*fx1;
Double_t zint1 = (z01 == 0)? ((fx0 > 0.5)? 0 : z11) :
(z11 == 0)? ((fx1 > 0.5)? 0 : z01) :
z01*fx0 + z11*fx1;
Double_t zint = (zint0 == 0)? ((fy0 > 0.5)? 0 : zint1) :
(zint1 == 0)? ((fy1 > 0.5)? 0 : zint0) :
zint0*fy0 + zint1*fy1;
dst->SetBinContent(i,j,zint);
}
}
return dst;
}
Map2D &Map2D::Rescale(Double_t sx, Double_t sy, Double_t sz)
{
Double_t xmin = GetXaxis()->GetXmin();
Double_t xmax = GetXaxis()->GetXmax();
Double_t ymin = GetYaxis()->GetXmin();
Double_t ymax = GetYaxis()->GetXmax();
Map2D *tmp = rescale(sx,sy,sz,(xmax+xmin)/2,(ymax-ymin)/2,0);
*this = *tmp;
delete tmp;
return *this;
}
Map2D &Map2D::Resize(Double_t xlow, Double_t ylow,
Double_t xhigh, Double_t yhigh, Int_t pixels) const
{
std::string name = GetName();
size_t sufi = name.rfind("_r");
for (int revno=1; revno < 99999999; ++revno) {
char str[99];
sprintf(str,"_r%d",revno);
name = name.substr(0,sufi) + str;
if (gDirectory->FindObject(name.c_str()) == 0) {
break;
}
sufi = name.rfind("_r");
}
std::cout << "New map created with name " << name << std::endl;
Double_t deltaX = GetXaxis()->GetBinWidth(1);
Double_t deltaY = GetYaxis()->GetBinWidth(1);
Int_t nxbins,nybins;
if (pixels) {
nxbins = (int)(xhigh-xlow)+1;
nybins = (int)(yhigh-ylow)+1;
xlow = GetXaxis()->GetXmin()+(xlow-1)*deltaX;
ylow = GetYaxis()->GetXmin()+(ylow-1)*deltaY;
}
else {
nxbins = (int)((xhigh-xlow)/deltaX + 0.999);
nybins = (int)((yhigh-ylow)/deltaY + 0.999);
}
xhigh = xlow+nxbins*deltaX;
yhigh = ylow+nybins*deltaY;
TH2D hnew(name.c_str(),GetTitle(),nxbins,xlow,xhigh,nybins,ylow,yhigh);
Map2D *newmap = new Map2D(hnew);
newmap->Fill(this);
return *newmap;
}
Map2D *Map2D::rescale(Double_t sx, Double_t sy, Double_t sz,
Double_t x0, Double_t y0, Double_t z0) const
{
Int_t nxbins = GetXaxis()->GetNbins();
Int_t nybins = GetYaxis()->GetNbins();
Double_t xmin = GetXaxis()->GetXmin();
Double_t xmax = GetXaxis()->GetXmax();
Double_t ymin = GetYaxis()->GetXmin();
Double_t ymax = GetYaxis()->GetXmax();
Double_t dx = (xmax-xmin)/nxbins;
Double_t dy = (ymax-ymin)/nybins;
Map2D *dst = new Map2D(*this);
dst->Reset();
for (Int_t i=1; i <= nxbins; ++i) {
Double_t x = (xmin+(i-0.5)*dx-x0)/sx + x0;
for (Int_t j=1; j <=nybins; ++j) {
Double_t y = (ymin+(j-0.5)*dy-y0)/sy + y0;
Double_t xbins = (x-xmin)/dx;
Double_t ybins = (y-ymin)/dy;
Int_t i0 = int(xbins+0.5);
Int_t j0 = int(ybins+0.5);
i0 = (i0 < 1)? 1 : i0;
j0 = (j0 < 1)? 1 : j0;
Int_t i1 = (i0 >= nxbins)? i0 : i0+1;
Int_t j1 = (j0 >= nybins)? j0 : j0+1;
Double_t fx0 = i1-xbins-0.5;
Double_t fy0 = j1-ybins-0.5;
Double_t fx1 = 1-fx0;
Double_t fy1 = 1-fy0;
Double_t z00 = GetBinContent(i0,j0);
Double_t z10 = GetBinContent(i1,j0);
Double_t z01 = GetBinContent(i0,j1);
Double_t z11 = GetBinContent(i1,j1);
Double_t zint0 = (z00 == 0)? ((fx0 > 0.5)? 0 : z10) :
(z10 == 0)? ((fx1 > 0.5)? 0 : z00) :
z00*fx0 + z10*fx1;
Double_t zint1 = (z01 == 0)? ((fx0 > 0.5)? 0 : z11) :
(z11 == 0)? ((fx1 > 0.5)? 0 : z01) :
z01*fx0 + z11*fx1;
Double_t zint = (zint0 == 0)? ((fy0 > 0.5)? 0 : zint1) :
(zint1 == 0)? ((fy1 > 0.5)? 0 : zint0) :
zint0*fy0 + zint1*fy1;
dst->SetBinContent(i,j,(zint-z0)*sz+z0);
}
}
return dst;
}
Double_t Map2D::Correlation(const Map2D *map, Double_t contrast) const
{
Int_t nxbins = GetXaxis()->GetNbins();
Int_t nybins = GetYaxis()->GetNbins();
if (map->GetXaxis()->GetNbins() != nxbins ||
map->GetYaxis()->GetNbins() != nybins) {
std::cerr << "Error in Map2D::Correlation - "
<< "maps must have the same dimensions."
<< std::endl;
return 0;
}
Double_t sum00=0;
Double_t sum10=0;
Double_t sum01=0;
Double_t sum11=0;
Double_t sum20=0;
Double_t sum02=0;
for (Int_t i=1; i <= nxbins; ++i) {
for (Int_t j=1; j <= nybins; ++j) {
Double_t z0 = GetBinContent(i,j);
Double_t z1 = map->GetBinContent(i,j);
Double_t wgt = (z0*z1 == 0)? contrast : 1;
if (wgt > 1) {
z0 = (z0==0)? -wgt : z0;
z1 = (z1==0)? -wgt : z1;
wgt = 1;
}
sum00 += wgt;
sum10 += wgt*z0;
sum01 += wgt*z1;
sum11 += wgt*z0*z1;
sum20 += wgt*z0*z0;
sum02 += wgt*z1*z1;
}
}
Double_t covar = sum11/sum00-(sum10/sum00)*(sum01/sum00);
Double_t var0 = sum20/sum00-(sum10/sum00)*(sum10/sum00);
Double_t var1 = sum02/sum00-(sum01/sum00)*(sum01/sum00);
return covar/sqrt((var0*var1 > 0)? var0*var1 : 1e-100);
}
Map2D &Map2D::Fill(const Map2D *map)
{
Int_t nxbins = GetXaxis()->GetNbins();
Int_t nybins = GetYaxis()->GetNbins();
Double_t xmin = GetXaxis()->GetXmin();
Double_t xmax = GetXaxis()->GetXmax();
Double_t ymin = GetYaxis()->GetXmin();
Double_t ymax = GetYaxis()->GetXmax();
Double_t dx = (xmax-xmin)/nxbins;
Double_t dy = (ymax-ymin)/nybins;
Int_t nxbins_s = map->GetXaxis()->GetNbins();
Int_t nybins_s = map->GetYaxis()->GetNbins();
Double_t xmin_s = map->GetXaxis()->GetXmin();
Double_t xmax_s = map->GetXaxis()->GetXmax();
Double_t ymin_s = map->GetYaxis()->GetXmin();
Double_t ymax_s = map->GetYaxis()->GetXmax();
Double_t dx_s = (xmax_s-xmin_s)/nxbins_s;
Double_t dy_s = (ymax_s-ymin_s)/nybins_s;
Int_t pwritten=0;
for (Int_t i=1; i <= nxbins; ++i) {
Double_t x = xmin+(i-0.5)*dx;
for (Int_t j=1; j <=nybins; ++j) {
Double_t y = ymin+(j-0.5)*dy;
Double_t xbin_s = (x-xmin_s)/dx_s;
Double_t ybin_s = (y-ymin_s)/dy_s;
Int_t i0 = int(xbin_s+0.5);
Int_t j0 = int(ybin_s+0.5);
i0 = (i0 < 1)? 1 : i0;
j0 = (j0 < 1)? 1 : j0;
Int_t i1 = (i0 >= nxbins_s)? i0 : i0+1;
Int_t j1 = (j0 >= nybins_s)? j0 : j0+1;
Double_t fx0 = i1-xbin_s-0.5;
Double_t fy0 = j1-ybin_s-0.5;
Double_t fx1 = 1-fx0;
Double_t fy1 = 1-fy0;
Double_t z00 = map->GetBinContent(i0,j0);
Double_t z10 = map->GetBinContent(i1,j0);
Double_t z01 = map->GetBinContent(i0,j1);
Double_t z11 = map->GetBinContent(i1,j1);
Double_t zint0 = (z00 == 0)? ((fx0 > 0.5)? 0 : z10) :
(z10 == 0)? ((fx1 > 0.5)? 0 : z00) :
z00*fx0 + z10*fx1;
Double_t zint1 = (z01 == 0)? ((fx0 > 0.5)? 0 : z11) :
(z11 == 0)? ((fx1 > 0.5)? 0 : z01) :
z01*fx0 + z11*fx1;
Double_t zint = (zint0 == 0)? ((fy0 > 0.5)? 0 : zint1) :
(zint1 == 0)? ((fy1 > 0.5)? 0 : zint0) :
zint0*fy0 + zint1*fy1;
if (zint) {
SetBinContent(i,j,zint);
++pwritten;
}
}
}
std::cout << "Map2D::Fill overlayed " << pwritten
<< " pixels." << std::endl;
return *this;
}
Map2D &Map2D::Mask(const Map2D *map, Int_t neg, Double_t value)
{
Int_t nxbins = map->GetXaxis()->GetNbins();
Int_t nybins = map->GetYaxis()->GetNbins();
if (GetXaxis()->GetNbins() != nxbins || GetYaxis()->GetNbins() != nybins) {
std::cerr << "Error in Map2D::Mask - argument map has different"
<< " pixel dimensions from the object being masked."
<< std::endl;
return *this;
}
for (Int_t i=1; i <= nxbins; ++i) {
for (Int_t j=1; j <= nybins; ++j) {
double cont = map->GetBinContent(i,j);
if (!neg && cont == 0 || neg && cont != 0) {
SetBinContent(i,j,0);
}
else if (value) {
SetBinContent(i,j,value);
}
}
}
return *this;
}
Int_t Map2D::ZeroSuppress(Double_t threshold, Double_t zero)
{
int count=0;
for (int ix=1; ix <= GetXaxis()->GetNbins(); ++ix) {
for (int iy=1; iy <= GetYaxis()->GetNbins(); ++iy) {
if (GetBinContent(ix,iy) < threshold) {
SetBinContent(ix,iy,zero);
++count;
}
}
}
return count;
}
Int_t Map2D::Despeckle(Int_t maxsize)
{
std::vector<Int_t> rsize;
std::vector<Int_t> rjoin;
rsize.push_back(0);
rjoin.push_back(0);
Int_t regions=1;
Int_t nxbins = GetXaxis()->GetNbins();
Int_t nybins = GetYaxis()->GetNbins();
Int_t *mask = new Int_t[nxbins*nybins];
Int_t region = 0;
for (Int_t j=0; j < nybins; ++j) {
if (GetBinContent(1,j+1) == 0) {
mask[j] = region = 0;
++rsize[0];
}
else if (region > 0) {
mask[j] = region;
++rsize[region];
}
else {
mask[j] = region = regions++;
rsize.push_back(1);
rjoin.push_back(0);
}
}
for (Int_t i=1; i < nxbins; ++i) {
region = 0;
Int_t j0 = i*nybins;
for (Int_t j=0; j < nybins; ++j) {
if (GetBinContent(i+1,j+1) == 0) {
mask[j+j0] = region = 0;
++rsize[0];
continue;
}
else if (mask[j+j0-nybins] != 0) {
Int_t left = mask[j+j0-nybins];
if (region > left) {
rjoin[region] = left;
rsize[left] += rsize[region];
rsize[region] = 0;
region = left;
}
else if (region == 0) {
region = left;
}
else if (region < left) {
rjoin[left] = region;
rsize[region] += rsize[left];
rsize[left] = 0;
}
}
else if (region == 0) {
region = regions++;
rsize.push_back(0);
rjoin.push_back(0);
}
mask[j+j0] = region;
++rsize[region];
}
}
for (Int_t i=0; i < nxbins; ++i) {
Int_t j0 = i*nybins;
for (Int_t j=0; j < nybins; ++j) {
region = mask[j+j0];
while (rjoin[region]) {
region = rjoin[region];
}
if (rsize[region] <= maxsize) {
SetBinContent(i+1,j+1,0);
}
}
}
Int_t surviving = 0;
for (Int_t r=1; r < regions; ++r) {
if (rjoin[r] == 0 && rsize[r] > maxsize) {
++surviving;
}
}
delete [] mask;
return surviving;
}
Int_t Map2D::Despike(Double_t maxheight, Int_t regionsize)
{
Int_t nxbins = GetXaxis()->GetNbins()+1;
Int_t nybins = GetYaxis()->GetNbins()+1;
Double_t *zsum = new Double_t[nxbins*nybins];
Int_t *nsum = new Int_t[nxbins*nybins];
Int_t *mask = new Int_t[nxbins*nybins];
for (Int_t ix=0; ix < nxbins; ++ix) {
mask[ix] = 0;
zsum[ix] = 0;
nsum[ix] = 0;
}
for (Int_t iy=1; iy < nybins; ++iy) {
Int_t rowsum0[nxbins];
Double_t rowsum1[nxbins];
Int_t sum0 = rowsum0[0] = 0;
Double_t sum1 = rowsum1[0] = 0;
for (Int_t ix=1; ix < nxbins; ++ix) {
Double_t content = GetBinContent(ix,iy);
mask[iy*nxbins+ix] = (content > 0)? 1 : 0;
rowsum0[ix] = (content > 0)? ++sum0 : sum0;
rowsum1[ix] = sum1 += content;
}
zsum[iy*nxbins] = 0;
nsum[iy*nxbins] = 0;
for (Int_t ix=1; ix < nxbins; ++ix) {
Int_t start = ix-regionsize;
Int_t stop = ix+regionsize;
start = (start < 1)? 0 : start-1;
stop = (stop >= nxbins)? nxbins-1 : stop;
nsum[iy*nxbins+ix] = rowsum0[stop] - rowsum0[start];
zsum[iy*nxbins+ix] = rowsum1[stop] - rowsum1[start];
}
}
for (Int_t ix=1; ix < nxbins; ++ix) {
Int_t colsum0[nybins];
Double_t colsum1[nybins];
Int_t sum0 = colsum0[0] = 0;
Double_t sum1 = colsum1[0] = 0;
for (Int_t iy=1; iy < nybins; ++iy) {
colsum0[iy] = sum0 += nsum[iy*nxbins+ix];
colsum1[iy] = sum1 += zsum[iy*nxbins+ix];
}
for (Int_t iy=1; iy < nybins; ++iy) {
Int_t start = iy-regionsize;
Int_t stop = iy+regionsize;
start = (start < 1)? 0 : start-1;
stop = (stop >= nybins)? nybins-1 : stop;
nsum[iy*nxbins+ix] = colsum0[stop] - colsum0[start];
zsum[iy*nxbins+ix] = colsum1[stop] - colsum1[start];
}
}
Int_t changes=1;
while (changes) {
changes = 0;
for (Int_t ix=1; ix < nxbins; ++ix) {
for (Int_t iy=1; iy < nybins; ++iy) {
if (mask[iy*nxbins+ix] == 1) {
Double_t z = GetBinContent(ix,iy);
Double_t zave = zsum[iy*nxbins+ix]/nsum[iy*nxbins+ix];
if (fabs(z-zave) > maxheight) {
Int_t rx0 = ix-regionsize;
Int_t rx1 = ix+regionsize;
Int_t ry0 = iy-regionsize;
Int_t ry1 = iy+regionsize;
rx0 = (rx0 < 1)? 1 : rx0;
ry0 = (ry0 < 1)? 1 : ry0;
rx1 = (rx1 < nxbins)? rx1 : nxbins-1;
ry1 = (ry1 < nybins)? ry1 : nybins-1;
for (Int_t rx=rx0; rx <= rx1; ++rx) {
for (Int_t ry=ry0; ry <= ry1; ++ry) {
zsum[ry*nxbins+rx] -= z;
nsum[ry*nxbins+rx] -= 1;
}
}
mask[iy*nxbins+ix] = -1;
++changes;
}
}
}
}
}
Int_t spikes = 0;
for (Int_t ix=1; ix < nxbins; ++ix) {
for (Int_t iy=1; iy < nybins; ++iy) {
Int_t mask_ = mask[iy*nxbins+ix];
Int_t nsum_ = nsum[iy*nxbins+ix];
if (mask_ == 1) {
SetBinContent(ix,iy,GetBinContent(ix,iy));
}
else if (mask_ == -1 && nsum_ > 0) {
SetBinContent(ix,iy,zsum[iy*nxbins+ix]/nsum_);
++spikes;
}
}
}
delete [] zsum;
delete [] nsum;
delete [] mask;
return spikes;
}
Map2D &Map2D::Center()
{
Int_t nxbins = GetXaxis()->GetNbins();
Int_t nybins = GetYaxis()->GetNbins();
Double_t xmin = GetXaxis()->GetXmin();
Double_t xmax = GetXaxis()->GetXmax();
Double_t ymin = GetYaxis()->GetXmin();
Double_t ymax = GetYaxis()->GetXmax();
Double_t dx = (xmax-xmin)/nxbins;
Double_t dy = (ymax-ymin)/nybins;
Double_t sum=0;
Double_t sumx=0;
Double_t sumy=0;
for (Int_t ix=1; ix < nxbins; ++ix) {
for (Int_t iy=1; iy < nybins; ++iy) {
if (GetBinContent(ix,iy) == 0) {
continue;
}
sumx += ix;
sumy += iy;
++sum;
}
}
if (sum == 0) {
return *this;
}
Double_t xshift = ((nxbins+1)/2 - sumx/sum) * dx;
Double_t yshift = ((nybins+1)/2 - sumy/sum) * dy;
return Shift(xshift,yshift);
}
Map2D &Map2D::Level()
{
Int_t nxbins = GetXaxis()->GetNbins();
Int_t nybins = GetYaxis()->GetNbins();
Double_t xmin = GetXaxis()->GetXmin();
Double_t xmax = GetXaxis()->GetXmax();
Double_t ymin = GetYaxis()->GetXmin();
Double_t ymax = GetYaxis()->GetXmax();
Double_t dx = (xmax-xmin)/nxbins;
Double_t dy = (ymax-ymin)/nybins;
Int_t left[3] = {nxbins,0,0};
Int_t right[3] = {0,0,0};
for (Int_t ix=1; ix <= nxbins; ++ix) {
for (Int_t iy=1; iy <= nybins; ++iy) {
double cont = GetBinContent(ix,iy);
if (cont == 0) {
continue;
}
if (ix < left[0]) {
left[0] = ix;
left[1] = iy;
left[2] = 1;
}
else if (ix == left[0]) {
left[1] += iy;
left[2] += 1;
}
else if (ix > right[0]) {
right[0] = ix;
right[1] = iy;
right[2] = 1;
}
else if (ix == right[0]) {
right[1] += iy;
right[2] += 1;
}
}
}
Double_t alpha = atan2((right[1]/right[2] - left[1]/left[2]) * dy,
(right[0] - left[0]) * dx);
return Rotate(0,0,-alpha);
}
Map2D &Map2D::Normalize()
{
double max = -1e300;
double min = +1e300;
for (int ix=1; ix <= GetNbinsX(); ++ix) {
for (int iy=1; iy <= GetNbinsY(); ++iy) {
double cont = GetBinContent(ix,iy);
if (cont == 0) {
continue;
}
max = (cont > max)? cont : max;
min = (cont < min)? cont : min;
}
}
SetMaximum(max);
SetMinimum(min);
return *this;
}
Double_t Map2D::TotalCurl(const Map2D *Vx, const Map2D *Vy,
Map2D **silhouette)
{
Int_t nxbins = Vx->GetXaxis()->GetNbins();
Int_t nybins = Vx->GetYaxis()->GetNbins();
Double_t xmin = Vx->GetXaxis()->GetXmin();
Double_t xmax = Vx->GetXaxis()->GetXmax();
Double_t ymin = Vx->GetYaxis()->GetXmin();
Double_t ymax = Vx->GetYaxis()->GetXmax();
Double_t dx = (xmax-xmin)/nxbins;
Double_t dy = (ymax-ymin)/nybins;
if (Vy->GetXaxis()->GetNbins() != nxbins ||
Vy->GetYaxis()->GetNbins() != nybins ||
Vy->GetXaxis()->GetXmin() != xmin ||
Vy->GetXaxis()->GetXmax() != xmax ||
Vy->GetYaxis()->GetXmin() != ymin ||
Vy->GetYaxis()->GetXmax() != ymax) {
std::cerr << "Error in Map2D::TotalCurl - the two input maps have"
<< " different pixel dimensions or axis bounds."
<< std::endl;
return 0;
}
*this = *Vx;
Mask(Vy);
int specksize=10;
while (Despeckle(specksize) > 1) {
specksize *= 2;
}
if (Despeckle() != 1) {
std::cerr << "Error in Map2D::TotalCurl - the map is too fragmented"
<< " for this algorithm, please despeckle and try again."
<< std::endl;
return 0;
}
Double_t *bound = new Double_t[nxbins*nybins];
for (Int_t i=1; i <= nxbins; ++i) {
Int_t j0 = (i-1)*nybins-1;
for (Int_t j=1; j <= nybins; ++j) {
if (GetBinContent(i,j) != 0) {
Double_t south = (j == 1)? 0 : GetBinContent(i,j-1);
Double_t north = (j == nybins)? 0 : GetBinContent(i,j+1);
Double_t west = (i == 1)? 0 : GetBinContent(i-1,j);
Double_t east = (i == nxbins)? 0 : GetBinContent(i+1,j);
bound[j+j0] = 4.1 - ((south == 0)? 0 : 1) - ((north == 0)? 0 : 1)
- ((west == 0)? 0 : 1) - ((east == 0)? 0 : 1);
}
else {
bound[j+j0] = 0;
}
}
}
for (Int_t i=1; i <= nxbins; ++i) {
Int_t j0 = (i-1)*nybins-1;
for (Int_t j=1; j <= nybins; ++j) {
SetBinContent(i,j,bound[j+j0]);
}
}
Int_t di[4] = {+1,0,-1,0};
Int_t dj[4] = {0,+1,0,-1};
Int_t back[4] = {2,3,0,1};
Int_t istep=0;
Int_t jstep=0;
for (Int_t i=nxbins/2,j=nybins/2; i < nxbins; ++i) {
if (bound[i*nybins+j] > 1) {
istep = i;
jstep = j;
}
}
Int_t istart=istep;
Int_t jstart=jstep;
Int_t stepdir=2;
std::list<Int_t> dirseq;
Int_t steps=0;
#ifdef MANUAL_STEPPING_IN_TOTALCURL
Int_t skip=0;
TCanvas *c1=0;
#endif
while (1 > 0) {
SetBinContent(istep+1,jstep+1,5.1);
#ifdef MANUAL_STEPPING_IN_TOTALCURL
if (skip-- == 0) {
GetXaxis()->SetRangeUser(xmin+(istep-25)*dx,xmin+(istep+25)*dx);
GetYaxis()->SetRangeUser(ymin+(jstep-25)*dy,ymin+(jstep+25)*dy);
if (c1 == 0) {
gDirectory->GetObject("c1",c1);
if (c1 == 0) {
c1 = new TCanvas("c1","c1",500,500);
}
c1->cd();
}
Draw("colz");
c1->Update();
std::cout << "Enter number of steps to skip before pausing next: ";
std::cin >> skip;
if (skip < 0) {
return 0;
}
}
#endif
Double_t score = 4;
Int_t nextdir = -1;
for (Int_t d=1; d < 4; ++d) {
Int_t dir = back[(stepdir+d)%4];
Double_t s = bound[(istep+di[dir])*nybins+jstep+dj[dir]];
if (s > 1 && s < score) {
nextdir = dir;
score = s;
}
}
if (score > 3) {
for (Int_t d=1; d < 4; ++d) {
Int_t dir = back[(stepdir+d)%4];
Int_t itry = istep+di[dir];
Int_t jtry = jstep+dj[dir];
if (bound[itry*nybins+jtry] > 0) {
Double_t sees=0;
for (Int_t dtry=0; dtry < 4; ++dtry) {
Double_t s = bound[(itry+di[dtry])*nybins+jtry+dj[dtry]];
if (s > 1 && s < 3) {
++sees;
}
}
if (sees > 0) {
nextdir = dir;
score = 3;
break;
}
}
}
}
if (score > 3) {
if (steps) {
SetBinContent(istep+1,jstep+1,4.1);
istep -= di[stepdir];
jstep -= dj[stepdir];
stepdir = dirseq.back();
dirseq.pop_back();
--steps;
continue;
}
std::cerr << "Error in Map2D::TotalCurl - algorithm is stuck after "
<< steps << " steps, and cannot continue."
<< std::endl;
return 0;
}
SetBinContent(istep+1,jstep+1,3.8);
dirseq.push_back(stepdir);
stepdir = nextdir;
istep += di[stepdir];
jstep += dj[stepdir];
bound[istep*nybins+jstep] = -1;
steps++;
if (istep == istart && jstep == jstart) {
dirseq.push_back(stepdir);
break;
}
}
for (Int_t ix=2; ix < nxbins; ++ix) {
for (Int_t iy=2; iy < nybins; ++iy) {
if (GetBinContent(ix,iy) < 2) {
SetBinContent(ix,iy,0.1);
}
}
}
int voids=1;
while (voids) {
voids = 0;
for (Int_t ix=2; ix < nxbins; ++ix) {
for (Int_t iy=2; iy < nybins; ++iy) {
double u = GetBinContent(ix,iy);
if (u > 0 && u < 1 && (
GetBinContent(ix,iy-1) == 0 ||
GetBinContent(ix-1,iy) == 0 ))
{
SetBinContent(ix,iy,0);
++voids;
}
}
}
for (Int_t ix=nxbins-1; ix > 1; --ix) {
for (Int_t iy=nybins-1; iy > 1; --iy) {
double u = GetBinContent(ix,iy);
if (u > 0 && u < 1 && (
GetBinContent(ix,iy+1) == 0 ||
GetBinContent(ix+1,iy) == 0 ))
{
SetBinContent(ix,iy,0);
++voids;
}
}
}
}
GetXaxis()->SetRange();
GetYaxis()->SetRange();
if (silhouette) {
if (*silhouette) {
delete *silhouette;
}
*silhouette = new Map2D(*this);
}
Reset();
istep = istart;
jstep = jstart;
Double_t curl=0;
std::list<Int_t>::iterator stepit = dirseq.begin();
for (++stepit; stepit != dirseq.end(); ++stepit) {
switch (*stepit) {
case 0:
curl += Vx->GetBinContent(istep+1,jstep+1)*dx;
++istep;
break;
case 1:
curl += Vy->GetBinContent(istep+1,jstep+1)*dy;
++jstep;
break;
case 2:
curl -= Vx->GetBinContent(istep,jstep+1)*dx;
--istep;
break;
case 3:
curl -= Vy->GetBinContent(istep+1,jstep)*dy;
--jstep;
break;
}
SetBinContent(istep+1,jstep+1,curl);
}
if (istep != istart || jstep != jstart) {
std::cerr << "Error in Map2D::TotalCurl - path around map periphery"
<< " is not closed, and cannot continue."
<< std::endl;
std::cerr << " istart,jstart=" << istart << "," << jstart << std::endl
<< " istop,jstop=" << istep << "," << jstep << std::endl;
return 0;
}
delete [] bound;
return curl;
}
Double_t Map2D::Curl(const Map2D *Vx, const Map2D *Vy)
{
Int_t nxbins = Vx->GetXaxis()->GetNbins();
Int_t nybins = Vx->GetYaxis()->GetNbins();
Double_t xmin = Vx->GetXaxis()->GetXmin();
Double_t xmax = Vx->GetXaxis()->GetXmax();
Double_t ymin = Vx->GetYaxis()->GetXmin();
Double_t ymax = Vx->GetYaxis()->GetXmax();
Double_t dx = (xmax-xmin)/nxbins;
Double_t dy = (ymax-ymin)/nybins;
if (Vy->GetXaxis()->GetNbins() != nxbins ||
Vy->GetYaxis()->GetNbins() != nybins ||
Vy->GetXaxis()->GetXmin() != xmin ||
Vy->GetXaxis()->GetXmax() != xmax ||
Vy->GetYaxis()->GetXmin() != ymin ||
Vy->GetYaxis()->GetXmax() != ymax) {
std::cerr << "Error in Map2D::Curl - the two input maps have"
<< " different pixel dimensions or axis bounds."
<< std::endl;
return 0;
}
*this = *Vx;
Mask(Vy);
int specksize=10;
while (Despeckle(specksize) > 1) {
specksize *= 2;
}
if (Despeckle() != 1) {
std::cerr << "Error in Map2D::Curl - the map is too fragmented"
<< " for this algorithm, please despeckle and try again."
<< std::endl;
return 0;
}
for (Int_t ix=2; ix < nxbins; ++ix) {
for (Int_t iy=2; iy < nybins; ++iy) {
SetBinContent(ix,iy,0);
}
}
Double_t sum = 0;
for (Int_t ix=2; ix < nxbins; ++ix) {
for (Int_t iy=2; iy < nybins; ++iy) {
double Vx_i_j = Vx->GetBinContent(ix,iy);
double Vy_i_j = Vy->GetBinContent(ix,iy);
double Vx_i_jp = Vx->GetBinContent(ix,iy+1);
double Vy_i_jp = Vy->GetBinContent(ix,iy+1);
double Vx_ip_j = Vx->GetBinContent(ix+1,iy);
double Vy_ip_j = Vy->GetBinContent(ix+1,iy);
double Vx_ip_jp = Vx->GetBinContent(ix+1,iy+1);
double Vy_ip_jp = Vy->GetBinContent(ix+1,iy+1);
if (Vx_i_j != 0 && Vx_i_jp != 0 && Vx_ip_j != 0 && Vx_ip_jp != 0 &&
Vy_i_j != 0 && Vy_i_jp != 0 && Vy_ip_j != 0 && Vy_ip_jp != 0)
{
double curlint = (Vy_ip_j - Vy_i_j) * dy
- (Vx_i_jp - Vx_i_j) * dx;
SetBinContent(ix,iy,curlint);
sum += curlint;
}
else {
SetBinContent(ix,iy,0);
}
}
}
return sum;
}
Map2D &Map2D::Uncurl(const Map2D *Vx, const Map2D *Vy, Int_t comp)
{
Int_t nxbins = GetXaxis()->GetNbins();
Int_t nybins = GetYaxis()->GetNbins();
Double_t xmin = GetXaxis()->GetXmin();
Double_t xmax = GetXaxis()->GetXmax();
Double_t ymin = GetYaxis()->GetXmin();
Double_t ymax = GetYaxis()->GetXmax();
Double_t dx = (xmax-xmin)/nxbins;
Double_t dy = (ymax-ymin)/nybins;
if (Vx->GetXaxis()->GetNbins() != nxbins ||
Vx->GetYaxis()->GetNbins() != nybins ||
Vx->GetXaxis()->GetXmin() != xmin ||
Vx->GetXaxis()->GetXmax() != xmax ||
Vx->GetYaxis()->GetXmin() != ymin ||
Vx->GetYaxis()->GetXmax() != ymax ||
Vy->GetXaxis()->GetNbins() != nxbins ||
Vy->GetYaxis()->GetNbins() != nybins ||
Vy->GetXaxis()->GetXmin() != xmin ||
Vy->GetXaxis()->GetXmax() != xmax ||
Vy->GetYaxis()->GetXmin() != ymin ||
Vy->GetYaxis()->GetXmax() != ymax) {
std::cerr << "Error in Map2D::Uncurl - the input maps have"
<< " different pixel dimensions or axis bounds."
<< std::endl;
return *this;
}
if (comp == 0) {
for (Int_t ix=1; ix < nxbins; ++ix) {
double sum0 = 0;
double sum1 = 0;
double Vxp[nybins];
for (Int_t iy=1; iy < nybins; ++iy) {
double Vx_i_j = Vx->GetBinContent(ix,iy);
double Vy_i_j = Vy->GetBinContent(ix,iy);
double Vx_i_jp = Vx->GetBinContent(ix,iy+1);
double Vy_i_jp = Vy->GetBinContent(ix,iy+1);
double Vx_ip_j = Vx->GetBinContent(ix+1,iy);
double Vy_ip_j = Vy->GetBinContent(ix+1,iy);
double Vx_ip_jp = Vx->GetBinContent(ix+1,iy+1);
double Vy_ip_jp = Vy->GetBinContent(ix+1,iy+1);
if (Vx_i_j != 0 && Vx_i_jp != 0 && Vx_ip_j != 0 && Vx_ip_jp != 0 &&
Vy_i_j != 0 && Vy_i_jp != 0 && Vy_ip_j != 0 && Vy_ip_jp != 0)
{
if (Vxp[iy-1] == 0) {
Vxp[iy-1] = Vx_i_j;
++sum0;
}
Vxp[iy] = Vxp[iy-1] + (Vy_ip_j - Vy_i_j) * dy/dx;
}
else {
Vxp[iy] = 0;
}
sum1 += Vx_i_jp - Vxp[iy];
++sum0;
}
double offset = (sum0 > 0)? sum1/sum0 : 0;
for (Int_t iy=1; iy <= nybins; ++iy) {
if (Vxp[iy-1] != 0) {
SetBinContent(ix,iy,Vxp[iy-1]+offset);
}
else {
SetBinContent(ix,iy,0);
}
}
}
}
else {
for (Int_t iy=1; iy < nybins; ++iy) {
double sum0 = 0;
double sum1 = 0;
double Vyp[nxbins];
for (Int_t ix=1; ix < nxbins; ++ix) {
double Vx_i_j = Vx->GetBinContent(ix,iy);
double Vy_i_j = Vy->GetBinContent(ix,iy);
double Vx_i_jp = Vx->GetBinContent(ix,iy+1);
double Vy_i_jp = Vy->GetBinContent(ix,iy+1);
double Vx_ip_j = Vx->GetBinContent(ix+1,iy);
double Vy_ip_j = Vy->GetBinContent(ix+1,iy);
double Vx_ip_jp = Vx->GetBinContent(ix+1,iy+1);
double Vy_ip_jp = Vy->GetBinContent(ix+1,iy+1);
if (Vx_i_j != 0 && Vx_i_jp != 0 && Vx_ip_j != 0 && Vx_ip_jp != 0 &&
Vy_i_j != 0 && Vy_i_jp != 0 && Vy_ip_j != 0 && Vy_ip_jp != 0)
{
if (Vyp[ix-1] == 0) {
Vyp[ix-1] = Vy_i_j;
++sum0;
}
Vyp[ix] = Vyp[ix-1] + (Vx_i_jp - Vx_i_j) * dx/dy;
sum1 += Vy_ip_j - Vyp[ix];
++sum0;
}
else {
Vyp[ix] = 0;
}
}
double offset = (sum0 > 0)? sum1/sum0 : 0;
for (Int_t ix=1; ix <= nxbins; ++ix) {
if (Vyp[ix-1] != 0) {
SetBinContent(ix,iy,Vyp[ix-1]+offset);
}
else {
SetBinContent(ix,iy,0);
}
}
}
}
return *this;
}
Double_t Map2D::Divergence(const Map2D *Vx, const Map2D *Vy)
{
Int_t nxbins = Vx->GetXaxis()->GetNbins();
Int_t nybins = Vx->GetYaxis()->GetNbins();
Double_t xmin = Vx->GetXaxis()->GetXmin();
Double_t xmax = Vx->GetXaxis()->GetXmax();
Double_t ymin = Vx->GetYaxis()->GetXmin();
Double_t ymax = Vx->GetYaxis()->GetXmax();
Double_t dx = (xmax-xmin)/nxbins;
Double_t dy = (ymax-ymin)/nybins;
if (Vy->GetXaxis()->GetNbins() != nxbins ||
Vy->GetYaxis()->GetNbins() != nybins ||
Vy->GetXaxis()->GetXmin() != xmin ||
Vy->GetXaxis()->GetXmax() != xmax ||
Vy->GetYaxis()->GetXmin() != ymin ||
Vy->GetYaxis()->GetXmax() != ymax) {
std::cerr << "Error in Map2D::Divergence - the two input maps have"
<< " different pixel dimensions or axis bounds."
<< std::endl;
return 0;
}
*this = *Vx;
Double_t divsum = 0;
for (Int_t iy=1; iy <= GetNbinsY(); ++iy) {
for (Int_t ix=1; ix <= GetNbinsX(); ++ix) {
if (ix > 1 && iy > 1) {
Double_t Vx1 = Vx->GetBinContent(ix,iy);
Double_t Vx0 = Vx->GetBinContent(ix-1,iy);
Double_t Vy1 = Vy->GetBinContent(ix,iy);
Double_t Vy0 = Vy->GetBinContent(ix,iy-1);
if (Vx1*Vx0*Vy0*Vy1 != 0) {
Double_t div = (Vx1-Vx0)/dx + (Vy1-Vy0)/dy;
SetBinContent(ix,iy,div);
divsum += div;
continue;
}
}
SetBinContent(ix,iy,0);
}
}
return divsum*dx*dy;
}
Int_t Map2D::Gradient(Map2D *Vx, Map2D *Vy) const
{
if (Vx == 0 && Vy == 0) {
return 0;
}
if (Vx) {
*Vx = *this;
Vx->Reset();
}
if (Vy) {
*Vy = *this;
Vy->Reset();
}
Double_t dx = GetXaxis()->GetBinWidth(1);
Double_t dy = GetYaxis()->GetBinWidth(1);
Int_t pixels=0;
for (Int_t iy=1; iy < GetNbinsY(); ++iy) {
for (Int_t ix=1; ix < GetNbinsX(); ++ix) {
Double_t h00 = GetBinContent(ix,iy);
Int_t count = 0;
if (Vx) {
Double_t h10 = GetBinContent(ix+1,iy);
Double_t val = (h10*h00 != 0)? (h10-h00)/dx : 0;
Vx->SetBinContent(ix,iy,val);
count += (val != 0)? 1 : 0;
}
if (Vy) {
Double_t h01 = GetBinContent(ix,iy+1);
Double_t val = (h01*h00 != 0)? (h01-h00)/dy : 0;
Vy->SetBinContent(ix,iy,val);
count += (val != 0)? 1 : 0;
}
pixels += (count == 0)? 0 : 1;
}
}
return pixels;
}
Int_t Map2D::PoissonSolve(const Map2D *rho, const Map2D *mask)
{
#if REPORT_PROCESS_TIME
struct timeval time_so_far;
struct rusage resource_usage[9];
getrusage(RUSAGE_SELF, &resource_usage[0]);
printf("-- Entry to Map2D::PoissonSolve, starting the process clock.\n");
printf("-- time to compute the Greens function for this grid: ");
#endif
Int_t nxbins = rho->GetNbinsX();
Int_t nybins = rho->GetNbinsY();
Double_t xmin = rho->GetXaxis()->GetXmin();
Double_t xmax = rho->GetXaxis()->GetXmax();
Double_t ymin = rho->GetYaxis()->GetXmin();
Double_t ymax = rho->GetYaxis()->GetXmax();
Double_t dx = (xmax-xmin)/nxbins;
Double_t dy = (ymax-ymin)/nybins;
Double_t xrange = xmax-xmin-dx/2;
Double_t yrange = ymax-ymin-dy/2;
Map2D *G = new Map2D(TH2D("G","2D Green\'s Function",
2*nxbins-1,-xrange,xrange,
2*nybins-1,-yrange,yrange));
G->GreensFunction(0,0);
Int_t igx0 = nxbins;
Int_t igy0 = nybins;
#if REPORT_PROCESS_TIME
getrusage(RUSAGE_SELF, &resource_usage[1]);
timersub(&resource_usage[1].ru_utime,
&resource_usage[0].ru_utime,
&time_so_far);
printf("%f\n",time_so_far.tv_sec + time_so_far.tv_usec/1000000.);
printf("-- time to do the Greens function integral for this grid: ");
#endif
Map2D work(*rho);
work.Reset();
for (Int_t ix0=1; ix0 <= nxbins; ++ix0) {
for (Int_t iy0=1; iy0 <= nybins; ++iy0) {
Double_t q = rho->GetBinContent(ix0,iy0);
if (q != 0) {
for (Int_t ix=1; ix <= nxbins; ++ix) {
for (Int_t iy=1; iy <= nybins; ++iy) {
Double_t sol = work.GetBinContent(ix,iy);
sol += q*G->GetBinContent(ix-ix0+igx0,iy-iy0+igy0);
work.SetBinContent(ix,iy,sol);
}
}
}
}
}
#if REPORT_PROCESS_TIME
getrusage(RUSAGE_SELF, &resource_usage[2]);
timersub(&resource_usage[2].ru_utime,
&resource_usage[1].ru_utime,
&time_so_far);
printf("%f\n",time_so_far.tv_sec + time_so_far.tv_usec/1000000.);
printf("-- time to compute the homogeneous solution for this grid: ");
#endif
Add(&work,-dx*dy);
Int_t result = LaplaceSolve(mask);
Add(&work,dx*dy);
#if REPORT_PROCESS_TIME
getrusage(RUSAGE_SELF, &resource_usage[3]);
timersub(&resource_usage[3].ru_utime,
&resource_usage[2].ru_utime,
&time_so_far);
printf("%f\n",time_so_far.tv_sec + time_so_far.tv_usec/1000000.);
printf("-- Exit from Map2D::PoissonSolve.\n");
#endif
return result;
}
Double_t Map2D::PoissonIter(const Map2D *rho, const Map2D *mask)
{
#if REPORT_PROCESS_TIME
struct timeval time_so_far;
struct rusage resource_usage[9];
getrusage(RUSAGE_SELF, &resource_usage[0]);
#endif
Int_t nxbins = rho->GetNbinsX();
Int_t nybins = rho->GetNbinsY();
Double_t xmin = rho->GetXaxis()->GetXmin();
Double_t xmax = rho->GetXaxis()->GetXmax();
Double_t ymin = rho->GetYaxis()->GetXmin();
Double_t ymax = rho->GetYaxis()->GetXmax();
Double_t dx = (xmax-xmin)/nxbins;
Double_t dy = (ymax-ymin)/nybins;
Double_t dx2 = dx*dx;
Double_t dy2 = dy*dy;
Double_t dx2dy2 = dx2*dy2;
Map2D delta(TH2D("delta","delta",nxbins,xmin,xmax,nybins,ymin,ymax));
for (int ix=2; ix < nxbins; ++ix) {
for (int iy=2; iy < nybins; ++iy) {
double rho_i_j = (rho == 0)? 0 : rho->GetBinContent(ix,iy);
if (rho_i_j == 0) {
continue;
}
double u_i_j = GetBinContent(ix,iy);
double u_im1_j = GetBinContent(ix-1,iy);
double u_ip1_j = GetBinContent(ix+1,iy);
double u_i_jm1 = GetBinContent(ix,iy-1);
double u_i_jp1 = GetBinContent(ix,iy+1);
if (mask != 0 && mask->GetBinContent(ix,iy) == 0 ||
mask == 0 && GetBinContent(ix,iy) == 0)
{
double new_u_i_j = (u_im1_j + u_ip1_j) * dy2
+ (u_i_jm1 + u_i_jp1) * dx2
- rho_i_j * dx2dy2;
new_u_i_j /= 2 * (dx2 + dy2);
if (u_im1_j * u_ip1_j * u_i_jm1 * u_i_jp1 != 0) {
delta.SetBinContent(ix,iy, new_u_i_j - u_i_j);
}
}
}
}
Add(&delta);
#if REPORT_PROCESS_TIME
getrusage(RUSAGE_SELF, &resource_usage[1]);
timersub(&resource_usage[1].ru_utime,
&resource_usage[0].ru_utime,
&time_so_far);
printf("Map2D::PoissonIter used %f cpu seconds\n",
time_so_far.tv_sec + time_so_far.tv_usec/1000000.);
#endif
double dmax = fabs(delta.GetMaximum());
double dmin = fabs(delta.GetMinimum());
return (dmax > dmin)? dmax : dmin;
}
Bool_t Map2D::GreensFunction(Double_t x0, Double_t y0)
{
Int_t nxbins = GetNbinsX();
Int_t nybins = GetNbinsY();
Double_t xmin = GetXaxis()->GetXmin();
Double_t xmax = GetXaxis()->GetXmax();
Double_t ymin = GetYaxis()->GetXmin();
Double_t ymax = GetYaxis()->GetXmax();
Double_t dx = (xmax-xmin)/nxbins;
Double_t dy = (ymax-ymin)/nybins;
Int_t ix0 = int((x0-xmin)/dx)+1;
Int_t iy0 = int((y0-ymin)/dy)+1;
Double_t fourpi=8*acos(0);
for (Int_t ix=1; ix <= nxbins; ++ix) {
Double_t x = xmin+(ix-0.5)*dx-x0;
for (Int_t iy=1; iy <= nybins; ++iy) {
Double_t y = ymin+(iy-0.5)*dy-y0;
Double_t r2 = x*x+y*y+1e-50;
SetBinContent(ix,iy,log(r2)/fourpi);
}
}
Int_t Ndim = 35;
Int_t ix1 = ix0-Ndim/2;
Int_t iy1 = iy0-Ndim/2;
if (ix0 < 3 || ix0 > nxbins-4 ||
iy0 < 3 || ix0 > nxbins-4) {
std::cerr << "Map2D::GreensFunction error - computing the Green\'s"
<< " function with x0,y0 too close to the edge of the map,"
<< " cannot continue."
<< std::endl;
return false;
}
else if (ix1 < 0 || ix1+Ndim >= nxbins ||
iy1 < 0 || iy1+Ndim >= nybins) {
std::cerr << "Map2D::GreensFunction warning - computing the Green\'s"
<< " function with x0,y0 close to the edge of the map,"
<< " loss of precision will result."
<< std::endl;
Int_t margin=0;
margin = (-ix1 > margin)? -ix1 : margin;
margin = (-iy1 > margin)? -iy1 : margin;
margin = (ix1+Ndim-nxbins >= margin)? ix1+Ndim-nxbins+1 : margin;
margin = (iy1+Ndim-nybins >= margin)? iy1+Ndim-nybins+1 : margin;
Ndim -= margin;
ix1 = ix0-Ndim/2;
iy1 = iy0-Ndim/2;
}
TMatrixD A(Ndim*Ndim,Ndim*Ndim);
TVectorD b(Ndim*Ndim);
A.Zero();
Int_t eq=0;
for (Int_t ix=0; ix < Ndim; ++ix) {
for (Int_t iy=0; iy < Ndim; ++iy,++eq) {
Int_t ci = iy*Ndim+ix;
if (ix == 0 || ix == Ndim-1 || iy == 0 || iy == Ndim-1) {
A(eq,ci) = 1;
b(eq) = GetBinContent(ix+ix1,iy+iy1);
}
else {
A(eq,ci) = -2/(dx*dx)-2/(dy*dy);
A(eq,ci-Ndim) = 1/(dy*dy);
A(eq,ci+Ndim) = 1/(dy*dy);
A(eq,ci-1) = 1/(dx*dx);
A(eq,ci+1) = 1/(dx*dx);
b(eq) = (ix+ix1 == ix0 && iy+iy1 == iy0)? 1/(dx*dy) : 0;
}
}
}
TDecompSVD svd(A);
if (!svd.Decompose()) {
std::cerr << "Map2D::GreensFunction error - TDecompSVD method"
<< " Decompose failed, unable to continue."
<< std::endl;
return false;
}
svd.Solve(b);
for (Int_t ix=0; ix < Ndim; ++ix) {
for (Int_t iy=0; iy < Ndim; ++iy) {
Int_t ci = iy*Ndim+ix;
SetBinContent(ix+ix1,iy+iy1,b(ci));
}
}
return true;
}
Int_t Map2D::LaplaceSolve(const Map2D *mask)
{
class basis_function {
public:
basis_function(const Map2D *map)
{
fNxbins = map->GetNbinsX();
fNybins = map->GetNbinsY();
fXlow = map->GetXaxis()->GetXmin();
fXhigh = map->GetXaxis()->GetXmax();
fYlow = map->GetYaxis()->GetXmin();
fYhigh = map->GetYaxis()->GetXmax();
fXwidth = fXhigh-fXlow;
fYwidth = fYhigh-fYlow;
fXcenter = (fXhigh+fXlow)/2;
fYcenter = (fYhigh+fYlow)/2;
fXdelta = (fXhigh-fXlow)/fNxbins;
fYdelta = (fYhigh-fYlow)/fNybins;
fRscale2 = (fXwidth*fXwidth + fYwidth*fYwidth)/4;
}
Double_t F(Int_t i, Double_t x, Double_t y)
{
x -= fXcenter;
y -= fYcenter;
Double_t r2 = (x*x+y*y)/fRscale2;
Double_t phi = atan2(y,x);
Int_t m = (i+1)/2;
switch (i-m*2) {
case 0:
return pow(r2,m/2.) * cos(m*phi);
case -1:
return pow(r2,m/2.) * sin(m*phi);
default:
std::cerr << "Map2D::LaplaceSolve::basis_function error - "
<< "method F called with negative index i = "
<< i << std::endl;
return 0;
}
}
Double_t F(Int_t i, Int_t ix, Int_t iy)
{
return F(i,(ix-0.5)*fXdelta+fXlow,(iy-0.5)*fYdelta+fYlow);
}
private:
Int_t fNxbins;
Int_t fNybins;
Double_t fXlow;
Double_t fXhigh;
Double_t fYlow;
Double_t fYhigh;
Double_t fXwidth;
Double_t fYwidth;
Double_t fXcenter;
Double_t fYcenter;
Double_t fXdelta;
Double_t fYdelta;
Double_t fRscale2;
};
Int_t nxbins = GetNbinsX();
Int_t nybins = GetNbinsY();
std::vector<Double_t> bX,bY,bValue;
std::vector<Int_t> iX,iY;
for (Int_t ix=1; ix <= nxbins; ++ix) {
for (Int_t iy=1; iy <= nybins; ++iy) {
if (mask != 0 && mask->GetBinContent(ix,iy) != 0 ||
mask == 0 && GetBinContent(ix,iy) != 0)
{
iX.push_back(ix);
iY.push_back(iy);
bX.push_back(GetXaxis()->GetBinCenter(ix));
bY.push_back(GetYaxis()->GetBinCenter(iy));
bValue.push_back(GetBinContent(ix,iy));
}
}
}
basis_function f(this);
Int_t Mvalues = bValue.size();
Int_t Nbases = Mvalues;
Mvalues = (Mvalues < Nbases)? Nbases : Mvalues;
TMatrixD A(Mvalues,Nbases);
TVectorD b(Mvalues);
for (UInt_t m=0; m < bValue.size(); ++m) {
for (Int_t n=0; n < Nbases; ++n) {
A(m,n) = f.F(n,bX[m],bY[m]);
}
b(m) = bValue[m];
}
for (Int_t m=bValue.size(); m < Mvalues; ++m) {
for (Int_t n=0; n < Nbases; ++n) {
A(m,n) = 0;
}
b(m) = 0;
}
TDecompSVD svd(A);
if (!svd.Decompose()) {
std::cerr << "Map2D::LaplaceSolve error - TDecompSVD method"
<< " Decompose failed, unable to continue."
<< std::endl;
return 0;
}
svd.Solve(b);
TVectorD sig = svd.GetSig();
Int_t rank;
for (rank=0; rank < sig.GetNrows(); ++rank) {
if (sig(rank) < 1e-300) {
break;
}
}
for (Int_t ix=1; ix <= nxbins; ++ix) {
for (Int_t iy=1; iy <= nybins; ++iy) {
Double_t val=0;
for (Int_t n=0; n < Nbases; ++n) {
val += b(n)*f.F(n,ix,iy);
}
SetBinContent(ix,iy,val);
}
}
for (unsigned int m=0; m < bValue.size(); ++m) {
double val=0;
for (int n=0; n < Nbases; ++n) {
val += b(n)*f.F(n,bX[m],bY[m]);
}
printf("point %d: input %f output %f\n",m,bValue[m],val);
}
return rank;
}
TH1D &Map2D::Profile(const char *name, const char *title,
Int_t nbins, Double_t xlow, Double_t xhigh)
{
if (xlow == 999) {
xlow = 1e30;
for (Int_t ix=1; ix <= GetNbinsX(); ++ix) {
for (Int_t iy=1; iy <= GetNbinsY(); ++iy) {
double cont = GetBinContent(ix,iy);
if (cont == 0) {
continue;
}
xlow = (cont < xlow)? cont : xlow;
}
}
}
if (xhigh == 999) {
xhigh = -1e30;
for (Int_t ix=1; ix <= GetNbinsX(); ++ix) {
for (Int_t iy=1; iy <= GetNbinsY(); ++iy) {
double cont = GetBinContent(ix,iy);
if (cont == 0) {
continue;
}
xhigh = (cont > xhigh)? cont : xhigh;
}
}
}
TH1D *prof = new TH1D(name,title,nbins,xlow,xhigh);
for (Int_t ix=1; ix <= GetNbinsX(); ++ix) {
for (Int_t iy=1; iy <= GetNbinsY(); ++iy) {
double cont = GetBinContent(ix,iy);
if (cont) {
prof->Fill(cont);
}
}
}
return *prof;
}