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