File indexing completed on 2024-09-27 07:03:26
0001
0002
0003
0004 #include "Hist4D.h"
0005
0006 ClassImp(Hist4D);
0007
0008 struct DifferentNumberOfBins : public std::runtime_error {
0009 DifferentNumberOfBins() :
0010 std::runtime_error("histograms have different numbers of bins") { }
0011 };
0012 struct DifferentAxisLimits : public std::runtime_error {
0013 DifferentAxisLimits() :
0014 std::runtime_error("histograms have different axis limits") { }
0015 };
0016 struct DifferentBinLimits : public std::runtime_error {
0017 DifferentBinLimits() :
0018 std::runtime_error("histograms have different bin limits") { }
0019 };
0020 struct DifferentLabels : public std::runtime_error {
0021 DifferentLabels() :
0022 std::runtime_error("histograms have different bin limits") { }
0023 };
0024
0025 Hist4D::Hist4D(
0026 char const* name, char const* title,
0027 Int_t nbins_w, Double_t const* bins_w,
0028 Int_t nbins_x, Double_t const* bins_x,
0029 Int_t nbins_y, Double_t const* bins_y,
0030 Int_t nbins_z, Double_t const* bins_z) :
0031 TNamed(name, title),
0032 _w_axis(new TAxis(nbins_w, bins_w)),
0033 _x_axis(new TAxis(nbins_x, bins_x)),
0034 _y_axis(new TAxis(nbins_y, bins_y)),
0035 _z_axis(new TAxis(nbins_z, bins_z)),
0036 _hists() {
0037 CreateAxes();
0038 CreateHists();
0039 }
0040
0041 Hist4D::Hist4D(
0042 char const* name, char const* title,
0043 Int_t nbins_w, Double_t w_lower, Double_t w_upper,
0044 Int_t nbins_x, Double_t x_lower, Double_t x_upper,
0045 Int_t nbins_y, Double_t y_lower, Double_t y_upper,
0046 Int_t nbins_z, Double_t z_lower, Double_t z_upper) :
0047 TNamed(name, title),
0048 _w_axis(new TAxis(nbins_w, w_lower, w_upper)),
0049 _x_axis(new TAxis(nbins_x, x_lower, x_upper)),
0050 _y_axis(new TAxis(nbins_y, y_lower, y_upper)),
0051 _z_axis(new TAxis(nbins_z, z_lower, z_upper)),
0052 _hists() {
0053 CreateAxes();
0054 CreateHists();
0055 }
0056
0057 bool Hist4D::CheckConsistency(Hist4D const* h1, Hist4D const* h2) {
0058 if (h1 == h2) {
0059 return true;
0060 }
0061 Int_t nbins_w = h1->_w_axis->GetNbins();
0062 Int_t nbins_x = h1->_x_axis->GetNbins();
0063 Int_t nbins_y = h1->_y_axis->GetNbins();
0064 Int_t nbins_z = h1->_z_axis->GetNbins();
0065 if (nbins_w != h2->_w_axis->GetNbins()
0066 || nbins_x != h2->_x_axis->GetNbins()
0067 || nbins_y != h2->_y_axis->GetNbins()
0068 || nbins_z != h2->_z_axis->GetNbins()) {
0069 throw DifferentNumberOfBins();
0070 return false;
0071 }
0072 if (h1->_hists.size() != h2->_hists.size()) {
0073 throw DifferentNumberOfBins();
0074 return false;
0075 }
0076 bool result = true;
0077 result &= CheckAxisLimits(h1->_w_axis, h2->_w_axis);
0078 result &= CheckAxisLimits(h1->_x_axis, h2->_x_axis);
0079 result &= CheckAxisLimits(h1->_y_axis, h2->_y_axis);
0080 result &= CheckAxisLimits(h1->_z_axis, h2->_z_axis);
0081 result &= CheckBinLimits(h1->_w_axis, h2->_w_axis);
0082 result &= CheckBinLimits(h1->_x_axis, h2->_x_axis);
0083 result &= CheckBinLimits(h1->_y_axis, h2->_y_axis);
0084 result &= CheckBinLimits(h1->_z_axis, h2->_z_axis);
0085 result &= CheckBinLabels(h1->_w_axis, h2->_w_axis);
0086 result &= CheckBinLabels(h1->_x_axis, h2->_x_axis);
0087 result &= CheckBinLabels(h1->_y_axis, h2->_y_axis);
0088 result &= CheckBinLabels(h1->_z_axis, h2->_z_axis);
0089 return result;
0090 }
0091
0092 bool Hist4D::CheckAxisLimits(TAxis const* ax1, TAxis const* ax2) {
0093 Double_t first_bin = ax1->GetBinWidth(1);
0094 Double_t last_bin = ax1->GetBinWidth(ax1->GetNbins());
0095 if (!TMath::AreEqualAbs(ax1->GetXmin(), ax2->GetXmin(), first_bin * 1e-10)
0096 || !TMath::AreEqualAbs(ax1->GetXmax(), ax2->GetXmax(), last_bin * 1e-10)) {
0097 throw DifferentAxisLimits();
0098 return false;
0099 }
0100 return true;
0101 }
0102
0103 bool Hist4D::CheckBinLimits(TAxis const* ax1, TAxis const* ax2) {
0104 TArrayD const* h1arr = ax1->GetXbins();
0105 TArrayD const* h2arr = ax2->GetXbins();
0106 Int_t count = h1arr->GetSize();
0107 if (count != 0) {
0108 if (h2arr->GetSize() != count) {
0109 throw DifferentBinLimits();
0110 return false;
0111 } else {
0112 for (Int_t idx = 0; idx < count; ++idx) {
0113 Double_t bin_width = ax1->GetBinWidth(idx);
0114 if (!TMath::AreEqualAbs(h1arr->GetAt(idx), h2arr->GetAt(idx), bin_width * 1e-10)) {
0115 throw DifferentBinLimits();
0116 return false;
0117 }
0118 }
0119 }
0120 }
0121 return true;
0122 }
0123
0124 bool Hist4D::CheckBinLabels(TAxis const* ax1, TAxis const* ax2) {
0125 THashList* l1 = ax1->GetLabels();
0126 THashList* l2 = ax2->GetLabels();
0127 if (!l1 && !l2) {
0128 return true;
0129 } else if (!l1 || !l2) {
0130 throw DifferentLabels();
0131 return false;
0132 } else {
0133 for (Int_t idx = 1; idx <= ax1->GetNbins(); ++idx) {
0134 TString label1 = ax1->GetBinLabel(idx);
0135 TString label2 = ax2->GetBinLabel(idx);
0136 if (label1 != label2) {
0137 throw DifferentLabels();
0138 return false;
0139 }
0140 }
0141 }
0142 return true;
0143 }
0144
0145 void Hist4D::CreateHists() {
0146
0147 Int_t nbins_w = _w_axis->GetNbins();
0148 Int_t nbins_x = _x_axis->GetNbins();
0149 Int_t nbins_y = _y_axis->GetNbins();
0150 Int_t nbins_z = _z_axis->GetNbins();
0151 for (Int_t idx_x = 0; idx_x < nbins_x + 2; ++idx_x) {
0152 for (Int_t idx_w = 0; idx_w < nbins_w + 2; ++idx_w) {
0153 std::string hist_name = std::string(fName.Data())
0154 + "/hist" + std::to_string(idx_x) + ":" + std::to_string(idx_w);
0155 TArrayD const* bins_y = _y_axis->GetXbins();
0156 TArrayD const* bins_z = _z_axis->GetXbins();
0157 bool linear = (bins_y->GetSize() == 0) && (bins_z->GetSize() == 0);
0158 TH2D* hist;
0159 if (linear) {
0160 hist = new TH2D(
0161 hist_name.c_str(), "",
0162 nbins_y, _y_axis->GetXmin(), _y_axis->GetXmax(),
0163 nbins_z, _z_axis->GetXmin(), _z_axis->GetXmax());
0164 } else {
0165 hist = new TH2D(
0166 hist_name.c_str(), "",
0167 bins_y->GetSize() - 1, bins_y->GetArray(),
0168 bins_z->GetSize() - 1, bins_z->GetArray());
0169 }
0170 hist->GetXaxis()->SetTickLength(0.);
0171 hist->GetXaxis()->SetLabelOffset(999.);
0172 hist->GetXaxis()->SetLabelSize(0.);
0173 hist->GetYaxis()->SetTickLength(0.);
0174 hist->GetYaxis()->SetLabelOffset(999.);
0175 hist->GetYaxis()->SetLabelSize(0.);
0176 hist->SetStats(0);
0177 Int_t idx = (nbins_w + 2) * idx_x + idx_w;
0178 _hists.push_back(hist);
0179 }
0180 }
0181 }
0182
0183 void Hist4D::CreateAxes() {
0184 std::string axes_hist_name = fName.Data();
0185 axes_hist_name += "/axes_hist";
0186 TArrayD const* bins_w = _w_axis->GetXbins();
0187 TArrayD const* bins_x = _x_axis->GetXbins();
0188 bool linear = (bins_w->GetSize() == 0) && (bins_x->GetSize() == 0);
0189 if (linear) {
0190 _axes = new TH2D(
0191 axes_hist_name.c_str(), "",
0192 _w_axis->GetNbins(), _w_axis->GetXmin(), _w_axis->GetXmax(),
0193 _x_axis->GetNbins(), _x_axis->GetXmin(), _x_axis->GetXmax());
0194 } else {
0195 _axes = new TH2D(
0196 axes_hist_name.c_str(), "",
0197 bins_w->GetSize() - 1, bins_w->GetArray(),
0198 bins_x->GetSize() - 1, bins_x->GetArray());
0199 }
0200 _axes->SetStats(0);
0201 _w_axis = _axes->GetXaxis();
0202 _x_axis = _axes->GetYaxis();
0203 _axes->GetXaxis()->SetTickLength(0.);
0204
0205
0206 _axes->GetYaxis()->SetTickLength(0.);
0207
0208
0209 }
0210
0211 TObject* Hist4D::Clone(char const* new_name) const {
0212 Hist4D* result = new Hist4D();
0213 result->SetName(new_name);
0214 result->SetTitle(fTitle);
0215 result->_w_axis = _w_axis;
0216 result->_x_axis = _x_axis;
0217 result->_y_axis = _y_axis;
0218 result->_z_axis = _z_axis;
0219 result->_axes = static_cast<TH2D*>(_axes->Clone());
0220 for (TH2D* hist : _hists) {
0221 result->_hists.push_back(static_cast<TH2D*>(hist->Clone()));
0222 }
0223 CheckConsistency(this, result);
0224 return result;
0225 }
0226
0227 void Hist4D::Fill(Double_t w, Double_t x, Double_t y, Double_t z) {
0228 Int_t idx_w = _w_axis->FindBin(w);
0229 Int_t idx_x = _x_axis->FindBin(x);
0230 Int_t nbins_w = _w_axis->GetNbins();
0231 Int_t nbins_x = _x_axis->GetNbins();
0232 Int_t idx = (nbins_w + 2) * idx_x + idx_w;
0233 _hists[idx]->Fill(y, z);
0234 }
0235
0236 void Hist4D::Fill(Double_t w, Double_t x, Double_t y, Double_t z, Double_t weight) {
0237 Int_t idx_w = _w_axis->FindBin(w);
0238 Int_t idx_x = _x_axis->FindBin(x);
0239 Int_t nbins_w = _w_axis->GetNbins();
0240 Int_t nbins_x = _x_axis->GetNbins();
0241 Int_t idx = (nbins_w + 2) * idx_x + idx_w;
0242 _hists[idx]->Fill(y, z, weight);
0243 }
0244
0245 Double_t Hist4D::GetEntries() {
0246 Double_t result = 0;
0247 for (TH2D* hist : _hists) {
0248 result += hist->GetEntries();
0249 }
0250 return result;
0251 }
0252
0253 void Hist4D::Divide(Hist4D* other) {
0254 CheckConsistency(this, other);
0255 for (std::size_t idx = 0; idx < _hists.size(); ++idx) {
0256 _hists[idx]->Divide(other->_hists[idx]);
0257 }
0258 }
0259
0260 void Hist4D::Scale(Double_t c) {
0261 for (TH2D* hist : _hists) {
0262 hist->Scale(c);
0263 }
0264 }
0265
0266 TH2D* Hist4D::ProjectionYZ(char const* pname) {
0267 TArrayD const* bins_y = _y_axis->GetXbins();
0268 TArrayD const* bins_z = _z_axis->GetXbins();
0269 bool linear = (bins_y->GetSize() == 0) && (bins_z->GetSize() == 0);
0270 TH2D* hist_proj;
0271 if (linear) {
0272 hist_proj = new TH2D(
0273 pname, "",
0274 _y_axis->GetNbins(), _y_axis->GetXmin(), _y_axis->GetXmax(),
0275 _z_axis->GetNbins(), _z_axis->GetXmin(), _z_axis->GetXmax());
0276 } else {
0277 hist_proj = new TH2D(
0278 pname, "",
0279 bins_y->GetSize() - 1, bins_y->GetArray(),
0280 bins_z->GetSize() - 1, bins_z->GetArray());
0281 }
0282 for (TH2D* hist : _hists) {
0283 hist_proj->Add(hist);
0284 }
0285 return hist_proj;
0286 }
0287
0288 TH2D* Hist4D::ProjectionWX(
0289 char const* pname,
0290 Int_t firstbiny, Int_t lastbiny,
0291 Int_t firstbinz, Int_t lastbinz) {
0292 TArrayD const* bins_w = _w_axis->GetXbins();
0293 TArrayD const* bins_x = _x_axis->GetXbins();
0294 Int_t nbins_w = _w_axis->GetNbins();
0295 Int_t nbins_x = _x_axis->GetNbins();
0296 bool linear = (bins_w->GetSize() == 0) && (bins_x->GetSize() == 0);
0297 TH2D* hist_proj;
0298 if (linear) {
0299 hist_proj = new TH2D(
0300 pname, "",
0301 _w_axis->GetNbins(), _w_axis->GetXmin(), _w_axis->GetXmax(),
0302 _x_axis->GetNbins(), _x_axis->GetXmin(), _x_axis->GetXmax());
0303 } else {
0304 hist_proj = new TH2D(
0305 pname, "",
0306 bins_w->GetSize() - 1, bins_w->GetArray(),
0307 bins_x->GetSize() - 1, bins_x->GetArray());
0308 }
0309 hist_proj->Sumw2(kFALSE);
0310 for (Int_t idx_x = 0; idx_x < nbins_x + 2; ++idx_x) {
0311 for (Int_t idx_w = 0; idx_w < nbins_w + 2; ++idx_w) {
0312 Int_t idx = (nbins_w + 2) * idx_x + idx_w;
0313 TH2D* hist = _hists[idx];
0314 Double_t error;
0315 Double_t integral = hist->IntegralAndError(
0316 firstbiny, lastbiny, firstbinz, lastbinz, error);
0317 Int_t bin = hist_proj->GetBin(idx_w, idx_x);
0318 hist_proj->SetBinContent(bin, integral);
0319 hist_proj->SetBinError(bin, error);
0320 }
0321 }
0322 hist_proj->Sumw2(kTRUE);
0323 return hist_proj;
0324 }
0325
0326 void Hist4D::DrawPad(TVirtualPad* pad, char const* options) {
0327
0328 for (TH2D* hist : _hists) {
0329 TArrayD const* bins_y = _y_axis->GetXbins();
0330 TArrayD const* bins_z = _z_axis->GetXbins();
0331 bool linear = (bins_y->GetSize() == 0) && (bins_z->GetSize() == 0);
0332 if (linear) {
0333 hist->SetBins(
0334 _y_axis->GetNbins(), _y_axis->GetXmin(), _y_axis->GetXmax(),
0335 _z_axis->GetNbins(), _z_axis->GetXmin(), _z_axis->GetXmax());
0336 } else {
0337 hist->SetBins(
0338 bins_y->GetSize() - 1, bins_y->GetArray(),
0339 bins_z->GetSize() - 1, bins_z->GetArray());
0340 }
0341 }
0342
0343 Double_t min = _minimum;
0344 Double_t max = _maximum;
0345 if (TMath::IsNaN(min)) {
0346 min = TMath::Infinity();
0347 for (TH2D* hist : _hists) {
0348 Double_t next_min = hist->GetBinContent(hist->GetMinimumBin());
0349 if (next_min < min) {
0350 min = next_min;
0351 }
0352 }
0353 }
0354 if (TMath::IsNaN(max)) {
0355 max = -TMath::Infinity();
0356 for (TH2D* hist : _hists) {
0357 Double_t next_max = hist->GetBinContent(hist->GetMaximumBin());
0358 if (next_max > max) {
0359 max = next_max;
0360 }
0361 }
0362 }
0363
0364 pad->cd();
0365 _axes->SetTitle(fTitle);
0366 _axes->SetMinimum(min);
0367 _axes->SetMaximum(max);
0368 std::string axes_options = "colz ";
0369 axes_options += options;
0370 _axes->Draw(axes_options.c_str());
0371 pad->Paint();
0372
0373 Int_t nbins_w = _w_axis->GetNbins();
0374 Int_t nbins_x = _x_axis->GetNbins();
0375 Int_t nbins_y = _y_axis->GetNbins();
0376 Int_t nbins_z = _z_axis->GetNbins();
0377 for (Int_t idx_x = 1; idx_x < nbins_x + 1; ++idx_x) {
0378 for (Int_t idx_w = 1; idx_w < nbins_w + 1; ++idx_w) {
0379 Int_t idx = (nbins_w + 2) * idx_x + idx_w;
0380 std::string pad_name = pad->GetName();
0381 pad_name += "/subpad" + std::to_string(idx_x) + ":" + std::to_string(idx_w);
0382 pad->cd();
0383 TPad* subpad = dynamic_cast<TPad*>(
0384 pad->GetPrimitive(pad_name.c_str()));
0385 if (subpad == nullptr) {
0386 Double_t width = pad->GetWw() * pad->GetAbsWNDC();
0387 Double_t height = pad->GetWh() * pad->GetAbsHNDC();
0388 Double_t pad_x_lo = pad->XtoPixel(pad->XtoPad(_w_axis->GetBinLowEdge(idx_w))) / width;
0389 Double_t pad_y_lo = pad->YtoPixel(pad->YtoPad(_x_axis->GetBinLowEdge(idx_x))) / height;
0390 Double_t pad_x_hi = pad->XtoPixel(pad->XtoPad(_w_axis->GetBinUpEdge(idx_w))) / width;
0391 Double_t pad_y_hi = pad->YtoPixel(pad->YtoPad(_x_axis->GetBinUpEdge(idx_x))) / height;
0392 Double_t pad_x_min = pad->XtoPixel(pad->GetUxmin()) / width;
0393 Double_t pad_y_min = pad->YtoPixel(pad->GetUymin()) / height;
0394 Double_t pad_x_max = pad->XtoPixel(pad->GetUxmax()) / width;
0395 Double_t pad_y_max = pad->YtoPixel(pad->GetUymax()) / height;
0396 if (!(pad_x_min < pad_x_max)) {
0397 Double_t temp = pad_x_min;
0398 pad_x_min = pad_x_max;
0399 pad_x_max = temp;
0400 }
0401 if (!(pad_y_min < pad_y_max)) {
0402 Double_t temp = pad_y_min;
0403 pad_y_min = pad_y_max;
0404 pad_y_max = temp;
0405 }
0406 if (!(pad_x_lo < pad_x_hi)) {
0407 Double_t temp = pad_x_lo;
0408 pad_x_lo = pad_x_hi;
0409 pad_x_hi = temp;
0410 }
0411 if (!(pad_y_lo < pad_y_hi)) {
0412 Double_t temp = pad_y_lo;
0413 pad_y_lo = pad_y_hi;
0414 pad_y_hi = temp;
0415 }
0416 if (pad_x_lo >= pad_x_min
0417 && pad_y_lo >= pad_y_min
0418 && pad_x_hi <= pad_x_max
0419 && pad_y_hi <= pad_y_max) {
0420 subpad = new TPad(
0421 pad_name.c_str(), "",
0422 pad_x_lo, 1. - pad_y_hi, pad_x_hi, 1. - pad_y_lo);
0423 subpad->SetLeftMargin(0.01);
0424 subpad->SetRightMargin(0.01);
0425 subpad->SetTopMargin(0.01);
0426 subpad->SetBottomMargin(0.01);
0427 subpad->SetFillStyle(4000);
0428 subpad->SetFrameFillStyle(4000);
0429 subpad->SetFrameLineColor(0);
0430 subpad->SetFrameLineWidth(0);
0431 subpad->SetBorderMode(0);
0432 if (pad->GetLogz()) {
0433 subpad->SetLogz();
0434 }
0435 }
0436 }
0437 if (subpad != nullptr) {
0438 pad->cd();
0439 subpad->Draw();
0440 subpad->cd();
0441 std::string hist_options = "cola ";
0442 hist_options += options;
0443 _hists[idx]->SetMinimum(min);
0444 _hists[idx]->SetMaximum(max);
0445 _hists[idx]->Draw(hist_options.c_str());
0446 }
0447 }
0448 }
0449 pad->cd();
0450 }
0451
0452 Hist4D::~Hist4D() {
0453 if(_w_axis) delete _w_axis;
0454 if(_x_axis) delete _x_axis;
0455 if(_y_axis) delete _y_axis;
0456 if(_z_axis) delete _z_axis;
0457 if(_axes) delete _axes;
0458 for(auto e : _hists)
0459 if(e) delete e;
0460 _hists.clear();
0461 }