BDSIM
BDSIM is a Geant4 extension toolkit for simulation of particle transport in accelerator beamlines.
Loading...
Searching...
No Matches
HistogramAccumulator.cc
1/*
2Beam Delivery Simulation (BDSIM) Copyright (C) BDSIM Collaboration, 2001 - 2026.
3
4This file is part of BDSIM.
5
6BDSIM is free software: you can redistribute it and/or modify
7it under the terms of the GNU General Public License as published
8by the Free Software Foundation version 3 of the License.
9
10BDSIM is distributed in the hope that it will be useful, but
11WITHOUT ANY WARRANTY; without even the implied warranty of
12MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13GNU General Public License for more details.
14
15You should have received a copy of the GNU General Public License
16along with BDSIM. If not, see <http://www.gnu.org/licenses/>.
17*/
18#include "HistogramAccumulator.hh"
19
20#include "TH1.h"
21#include "TH1D.h"
22#include "TH2D.h"
23#include "TH3D.h"
24#include "BDSBH4DBase.hh"
25
26#include <cmath>
27#include <iostream>
28#include <stdexcept>
29#include <string>
30
32
34 nDimensions(1),
35 n(0),
36 terminated(false),
37 mean(nullptr),
38 variance(nullptr),
39 result(nullptr)
40{;}
41
43 const std::string& resultHistNameIn,
44 const std::string& resultHistTitleIn):
45 HistogramAccumulator(baseHistogram, (int)baseHistogram->GetDimension(), resultHistNameIn, resultHistTitleIn)
46{;}
47
49 int nDimensionsIn,
50 const std::string& resultHistNameIn,
51 const std::string& resultHistTitleIn):
52 nDimensions(nDimensionsIn),
53 n(0),
54 terminated(false),
55 resultHistName(resultHistNameIn),
56 resultHistTitle(resultHistTitleIn),
57 mean(nullptr),
58 variance(nullptr),
59 result(nullptr)
60{
61 std::string meanName = resultHistName + "_Mean";
62 std::string variName = resultHistName + "_Vari";
63 switch (nDimensions)
64 {
65 case 1:
66 {
67 mean = dynamic_cast<TH1D*>(baseHistogram->Clone(meanName.c_str()));
68 variance = dynamic_cast<TH1D*>(baseHistogram->Clone(variName.c_str()));
69 result = dynamic_cast<TH1D*>(baseHistogram->Clone(resultHistName.c_str()));
70 break;
71 }
72 case 2:
73 {
74 mean = dynamic_cast<TH2D*>(baseHistogram->Clone(meanName.c_str()));
75 variance = dynamic_cast<TH2D*>(baseHistogram->Clone(variName.c_str()));
76 result = dynamic_cast<TH2D*>(baseHistogram->Clone(resultHistName.c_str()));
77 break;
78 }
79 case 3:
80 {
81 mean = dynamic_cast<TH3D*>(baseHistogram->Clone(meanName.c_str()));
82 variance = dynamic_cast<TH3D*>(baseHistogram->Clone(variName.c_str()));
83 result = dynamic_cast<TH3D*>(baseHistogram->Clone(resultHistName.c_str()));
84 break;
85 }
86 case 4:
87 {
88#ifdef USE_BOOST
89 mean = dynamic_cast<BDSBH4DBase*>(baseHistogram)->Clone(meanName.c_str());
90 variance = dynamic_cast<BDSBH4DBase*>(baseHistogram)->Clone(variName.c_str());
91 result = dynamic_cast<BDSBH4DBase*>(baseHistogram)->Clone(resultHistName.c_str());
92 break;
93#endif
94 }
95 default:
96 {throw std::domain_error("Invalid number of dimensions"); break;}
97 }
98 if (mean && variance && result)
99 {// technically these could be nullptr
100 if (nDimensions != 4)
101 {
102 // empty contents
103 mean->Reset();
104 variance->Reset();
105 result->Reset();
106 // set title
107 result->SetTitle(resultHistTitle.c_str());
108 mean->SetTitle(meanName.c_str());
109 variance->SetTitle(variName.c_str());
110 }
111 else
112 {
113#ifdef USE_BOOST
114 // empty contents
115 static_cast<BDSBH4DBase*>(mean)->Reset_BDSBH4D();
116 static_cast<BDSBH4DBase*>(variance)->Reset_BDSBH4D();
117 static_cast<BDSBH4DBase*>(result)->Reset_BDSBH4D();
118 // set title
119 static_cast<BDSBH4DBase*>(result)->SetTitle(resultHistTitle.c_str());
120 static_cast<BDSBH4DBase*>(mean)->SetTitle(meanName.c_str());
121 static_cast<BDSBH4DBase*>(variance)->SetTitle(variName.c_str());
122#endif
123 }
124 }
125}
126
128{
129 // deleting histograms removes them from currently open output file
130 delete mean;
131 delete variance;
132 // leak result here as ROOT annoyingly requires this to be left
133}
134
136{
137 // temporary variables
138 double newMean = 0;
139 double newVari = 0;
140 const double error = 0; // needed to pass reference to unused parameter
141 const unsigned long nEntriesToAccumulate = 1;
142
143 n++; // must always count even if nothing to add up
144
145 switch (nDimensions)
146 {
147 case 1:
148 {
149 TH1D* h1 = dynamic_cast<TH1D*>(mean);
150 TH1D* h1e = dynamic_cast<TH1D*>(variance);
151 TH1D* ht = dynamic_cast<TH1D*>(newValue);
152 for (int j = 0; j <= h1->GetNbinsX() + 1; ++j)
153 {
154 AccumulateSingleValue(h1->GetBinContent(j),
155 h1e->GetBinContent(j),
156 ht->GetBinContent(j),
157 error, n, nEntriesToAccumulate,
158 newMean, newVari);
159 h1->SetBinContent(j, newMean);
160 h1e->SetBinContent(j, newVari);
161 }
162 break;
163 }
164 case 2:
165 {
166 TH2D* h1 = dynamic_cast<TH2D*>(mean);
167 TH2D* h1e = dynamic_cast<TH2D*>(variance);
168 TH2D* ht = dynamic_cast<TH2D*>(newValue);
169 for (int j = 0; j <= h1->GetNbinsX() + 1; ++j)
170 {
171 for (int k = 0; k <= h1->GetNbinsY() + 1; ++k)
172 {
173 AccumulateSingleValue(h1->GetBinContent(j,k),
174 h1e->GetBinContent(j,k),
175 ht->GetBinContent(j,k),
176 error, n, nEntriesToAccumulate,
177 newMean, newVari);
178 h1->SetBinContent(j, k, newMean);
179 h1e->SetBinContent(j, k, newVari);
180 }
181 }
182 break;
183 }
184 case 3:
185 {
186 TH3D* h1 = dynamic_cast<TH3D*>(mean);
187 TH3D* h1e = dynamic_cast<TH3D*>(variance);
188 TH3D* ht = dynamic_cast<TH3D*>(newValue);
189 for (int j = 0; j <= h1->GetNbinsX() + 1; ++j)
190 {
191 for (int k = 0; k <= h1->GetNbinsY() + 1; ++k)
192 {
193 for (int l = 0; l <= h1->GetNbinsZ() + 1; ++l)
194 {
195 AccumulateSingleValue(h1->GetBinContent(j,k,l),
196 h1e->GetBinContent(j,k,l),
197 ht->GetBinContent(j,k,l),
198 error, n, nEntriesToAccumulate,
199 newMean, newVari);
200 h1->SetBinContent(j, k, l, newMean);
201 h1e->SetBinContent(j, k, l, newVari);
202 }
203 }
204 }
205 break;
206 }
207 case 4:
208 {
209#ifdef USE_BOOST
210 BDSBH4DBase* h1 = dynamic_cast<BDSBH4DBase*>(mean);
211 BDSBH4DBase* h1e = dynamic_cast<BDSBH4DBase*>(variance);
212 BDSBH4DBase* ht = dynamic_cast<BDSBH4DBase*>(newValue);
213 for (int j = -1; j <= h1->GetNbinsX(); ++j)
214 {
215 for (int k = -1; k <= h1->GetNbinsY(); ++k)
216 {
217 for (int l = -1; l <= h1->GetNbinsZ(); ++l)
218 {
219 for (int e = -1; e <= h1->GetNbinsE(); ++e)
220 {
221 AccumulateSingleValue(h1->At(j,k,l,e),
222 h1e->At(j,k,l,e),
223 ht->At(j,k,l,e),
224 error, n, nEntriesToAccumulate,
225 newMean, newVari);
226 h1->Set_BDSBH4D(j,k,l,e, newMean);
227 h1e->Set_BDSBH4D(j,k,l,e, newVari);
228 }
229
230 }
231 }
232 }
233 break;
234#endif
235 }
236 default:
237 {break;}
238 }
239}
240
242{
243 // error on mean is sqrt(1/n) * std = sqrt(1/n) * sqrt(1/(n-1)) * sqrt(variance)
244 // the only variable is the variance, so take the rest out as a factor.
245 const double nD = (double)n; // cast only once
246 const double factor = std::sqrt(1./(nD * (nD - 1))); // nan if n = 1 -> won't be used
247 double mn = 0; // temporary variable for mean
248 double err = 0; // temporary variable for standard error on mean
249 double var = 0; // temporary variable for variance
250
251 // note here we set the std to 0 if there's only one entry (ie n = 1) to avoid
252 // division by zero and nans
253 switch (nDimensions)
254 {
255 case 1:
256 {
257 for (int j = 0; j <= result->GetNbinsX() + 1; ++j)
258 {
259 mn = mean->GetBinContent(j);
260 var = variance->GetBinContent(j);
261 err = n > 1 ? factor*std::sqrt(var) : 0;
262 result->SetBinContent(j, mn);
263 result->SetBinError(j, err);
264 }
265 break;
266 }
267 case 2:
268 {
269 for (int j = 0; j <= result->GetNbinsX() + 1; ++j)
270 {
271 for (int k = 0; k <= result->GetNbinsY() + 1; ++k)
272 {
273 mn = mean->GetBinContent(j,k);
274 var = variance->GetBinContent(j, k);
275 err = n > 1 ? factor*std::sqrt(var) : 0;
276 result->SetBinContent(j, k, mn);
277 result->SetBinError(j, k, err);
278 }
279 }
280 break;
281 }
282 case 3:
283 {
284 for (int j = 0; j <= result->GetNbinsX() + 1; ++j)
285 {
286 for (int k = 0; k <= result->GetNbinsY() + 1; ++k)
287 {
288 for (int l = 0; l <= result->GetNbinsZ() + 1; ++l)
289 {
290 mn = mean->GetBinContent(j,k,l);
291 var = variance->GetBinContent(j, k, l);
292 err = n > 1 ? factor*std::sqrt(var) : 0;
293 result->SetBinContent(j,k,l, mn);
294 result->SetBinError(j,k,l, err);
295 }
296 }
297 }
298 break;
299 }
300 case 4:
301 {
302#ifdef USE_BOOST
303 auto histCast = dynamic_cast<BDSBH4DBase*>(result);
304 auto mnCast = dynamic_cast<BDSBH4DBase*>(mean);
305 auto varCast = dynamic_cast<BDSBH4DBase*>(variance);
306 auto resCast = dynamic_cast<BDSBH4DBase*>(result);
307 int nBinsX = histCast->GetNbinsX();
308 int nBinsY = histCast->GetNbinsY();
309 int nBinsZ = histCast->GetNbinsZ();
310 int nBinsE = histCast->GetNbinsE();
311 for (int j = -1; j <= nBinsX; ++j)
312 {
313 for (int k = -1; k <= nBinsY; ++k)
314 {
315 for (int l = -1; l <= nBinsZ; ++l)
316 {
317 for (int e = -1; e <= nBinsE; ++e)
318 {
319 mn = mnCast->At(j, k, l, e);
320 var = varCast->At(j, k, l, e);
321 err = n > 1 ? factor*std::sqrt(var) : 0;
322 resCast->Set_BDSBH4D(j, k, l, e, mn);
323 resCast->SetError_BDSBH4D(j, k, l, e, err);
324 }
325 }
326 }
327 }
328 break;
329#endif
330 }
331 default:
332 {break;}
333 }
334 if(nDimensions==4)
335 {dynamic_cast<BDSBH4DBase*>(result)->SetEntries_BDSBH4D((double)n);}
336 else
337 {result->SetEntries((double)n);}
338
339 return result;
340}
341
343 double oldVari,
344 double x,
345 double /*xVari*/,
346 unsigned long nEntriesAccumulated,
347 unsigned long/*nEntriesToAccumulate*/,
348 double& newMean,
349 double& newVari) const
350{
351 newMean = oldMean + ((x - oldMean) / (double)nEntriesAccumulated);
352 newVari = oldVari + ((x - oldMean) * (x - newMean));
353}
Base class for the 4D histogram classes.
Class to accumulate and merge histograms in different ways.
const std::string resultHistName
Name for resultant histogram.
int nDimensions
Number of dimensions.
virtual void AccumulateSingleValue(double oldMean, double oldVari, double x, double xVari, unsigned long nEntriesAccumulated, unsigned long nEntriesToAccumulate, double &newMean, double &newVari) const
const std::string resultHistTitle
Title for resultant histogram.
unsigned long n
Counter.
HistogramAccumulator()
Default constructor only for ROOT reflexivity - not intended for use.
virtual void Accumulate(TH1 *newValue)