R3BROOT
R3B analysis software
Loading...
Searching...
No Matches
neuland_add_random_hitpar.py
Go to the documentation of this file.
1"""@package docstring
2Add random cal_to_hit_par to the parameter file, which could be the output from the simulation.
3"""
4
5import math
6import random
7from enum import Enum
8
9import ROOT
10from scipy.signal import square
11
12
13class Mode(Enum):
14 """
15 A enumerator for the random type of a parameter.
16 """
17
18
19 UNIFORM = 1
20
21 COSINE = 2
22
23 CLOCK = 3
24
25
27 """
28 Data structure containing all information to generate a random value
29 """
30
31 def __init__(self, **kwargs):
32 """Costructor
33
34 @param kwargs key-pairs passed to set() member function.
35 """
36 self.__is_set = True
37 self.set(**kwargs)
38
39 @classmethod
40 def empty(cls):
41 """Factory method to create an invalid empty object.
42 @return An invalid empty object.
43 """
44 value = cls(mode=Mode.UNIFORM, offset=0.0, amp=0.0, period=0, err=0.0)
45 value.unset()
46 return value
47
48 def is_set(self):
49 """Query whether the object is valid or not"""
50 return self.__is_set
51
52 def set(
53 self, mode: Mode, offset: float, amp: float, period: int = 100, err: float = 0.5
54 ):
55 """Set all parameters of random value generations with different mode and make the object valid.
56
57 @param mode Set a mode value (enumerator from Mode).
58 @param offset Set a offset value
59 @param amp Set a amplitude value
60 @param period Set period value if Mode.COSINE is chosen
61 @param err Set an error value
62 """
63 self.__is_set = True
64 self.mode = mode
65 self.offset = offset
66 self.amp = amp
67 self.period = period
68 self.err = err
69
70 def set_clock(self, **kwargs):
71 """Set all random generator parameter with the clock distribution.
72
73 @param kwargs Key-value pairs passed to set() member function
74 """
75 self.set(Mode.CLOCK, **kwargs)
76
77 def set_cos(self, **kwargs):
78 """Set all random generator parameter with the cosine distribution.
79
80 @param kwargs Key-value pairs passed to set() member function
81 """
82 self.set(Mode.COSINE, **kwargs)
83
84 def set_uniform(self, **kwargs):
85 """Set all random generator parameter with the uniform distribution.
86
87 @param kwargs Key-value pairs passed to set() member function
88 """
89 self.set(Mode.UNIFORM, **kwargs)
90
91 def unset(self):
92 """Make the object invalid"""
93 self.__is_set = False
94
95
97 """
98 Adding parameters whose values are randomly generated from the original file to the output file.
99
100 Example:
101 @code{.py}
102 from neuland_add_random_hitpar import NeulandRandHitParAdder as ParAdder
103
104 NUMBER_OF_BARS = 1300
105 par_adder = ParAdder(NUMBER_OF_BARS)
106
107 COS_PERIOD = 1000
108
109 # Use normal set function
110 par_adder.effective_speed.set(mode = Mode.COSINE, offset = 10., amp = 5., period = COS_PERIOD, err = 0.5)
111 par_adder.t_sync.set(mode = Mode.UNIFORM, offset = 15., amp = 5, period = COS_PERIOD, err = 0.5)
112
113 # Use alias set_uniform function. The range of the uniform distribution is [-3., 3.]
114 par_adder.t_diff.set_uniform( offset = 0., amp = 3., err = 0.5)
115
116 # Use alias set_cos function
117 par_adder.light_attenuation_length.set_cos( offset = 0.008, amp = 0.004, period = COS_PERIOD, err = 0.0005)
118 par_adder.energy_gain.set_cos( offset = 15., amp = 5., period = COS_PERIOD, err = 0.5)
119 par_adder.pedestal.set_cos( offset = 25., amp = 5., period = COS_PERIOD, err = 0.5)
120 par_adder.pmt_thresh.set_cos( offset = 0.75, amp = 0.25, period = COS_PERIOD, err = 0.5)
121 par_adder.saturation_coefficient.set_cos( offset = 0.5, amp = 0.4, period = COS_PERIOD, err = 0.5)
122
123 input_filename = "sim.par.root.0"
124 output_filename = "added_sim.par.root.0"
125
126 # Add a new parameter with random values with other paramters from the input file.
127 # After the call, the output parameter file will be created.
128 par_adder.insert_parameters(input_filename, output_filename);
129 @endcode
130 """
131
132 def __init__(self, module_num: int):
133 """
134 Constructor.
135
136 @param module_num The number of bars
137 """
138
139 self.__module_num: int = module_num
140
141
142 self.__run_id: int = 999
143
144
145 self.effective_speed = ParValueSet.empty()
146
147
148 self.t_sync = ParValueSet.empty()
149
150
151 self.t_diff = ParValueSet.empty()
152
153
154 self.light_attenuation_length = ParValueSet.empty()
155
156
157 self.energy_gain = ParValueSet.empty()
158
159
160 self.pedestal = ParValueSet.empty()
161
162
163 self.pmt_thresh = ParValueSet.empty()
164
165
166 self.saturation_coefficient = ParValueSet.empty()
167
168 @staticmethod
169 def generate_random_value_with_cos(par: ParValueSet, module_id):
170 """
171 Generating a random value according to the module id and the given random generator parameters.
172
173 @param module_id The module ID (0-based number) of the bar
174 """
175 noise = random.uniform(-par.err, par.err) # Zufällige Abweichung hinzufügen
176 value = 0.0
177 if par.mode == Mode.COSINE:
178 value = par.offset + par.amp * math.cos(
179 module_id * 2 * math.pi / par.period
180 )
181 elif par.mode == Mode.CLOCK:
182 value = square(2 * math.pi * module_id / par.period) * par.amp + par.offset
183 else:
184 value = random.uniform(par.offset - par.amp, par.offset + par.amp)
185 return round(value + noise, 6)
186
187 def set_run_id(self, val: int):
188 """Set the run id in the parameter file
189
190 @param val Run id
191 """
192 self.__run_id = val
193
194 def __assign_random_values(self, module_id: int):
195 """
196 Create a HitModulePar with random values.
197
198 @param module_id The module ID (0-based number) of the bar
199 """
200 one_module_par = ROOT.R3B.Neuland.HitModulePar()
201 one_module_par.module_num = module_id
202
203 effective_speed = self.generate_random_value_with_cos(
204 self.effective_speed, module_id
205 )
206 t_sync = self.generate_random_value_with_cos(self.t_sync, module_id)
207 t_diff = self.generate_random_value_with_cos(self.t_diff, module_id)
208 light_attenuation_length = self.generate_random_value_with_cos(
209 self.light_attenuation_length, module_id
210 )
211
212 energy_gain = self.generate_random_value_with_cos(self.energy_gain, module_id)
213 pedestal = self.generate_random_value_with_cos(self.pedestal, module_id)
214 pmt_thresh = self.generate_random_value_with_cos(self.pmt_thresh, module_id)
215 saturation_coefficient = self.generate_random_value_with_cos(
216 self.saturation_coefficient, module_id
217 )
218
219 # Werte im ROOT-Objekt setzen
220 one_module_par.effective_speed.value = effective_speed
221 one_module_par.effective_speed.error = 0
222 one_module_par.t_sync.value = t_sync
223 one_module_par.t_sync.error = 0
224 one_module_par.t_diff.value = t_diff
225 one_module_par.t_diff.error = 0
226
227 one_module_par.light_attenuation_length.value = light_attenuation_length
228 one_module_par.light_attenuation_length.error = 0
229
230 one_module_par.energy_gain.set_left(ROOT.R3B.ValueErrorD(energy_gain, 0))
231 one_module_par.energy_gain.set_right(ROOT.R3B.ValueErrorD(energy_gain, 0))
232 one_module_par.pedestal.set_left(ROOT.R3B.ValueErrorD(pedestal, 0))
233 one_module_par.pedestal.set_right(ROOT.R3B.ValueErrorD(pedestal, 0))
234 one_module_par.pmt_threshold.set_left(ROOT.R3B.ValueErrorD(pmt_thresh, 0.0))
235 one_module_par.pmt_threshold.set_right(ROOT.R3B.ValueErrorD(pmt_thresh, 0.0))
236 one_module_par.pmt_saturation.set_left(
237 ROOT.R3B.ValueErrorD(saturation_coefficient, 0.0)
238 )
239 one_module_par.pmt_saturation.set_right(
240 ROOT.R3B.ValueErrorD(saturation_coefficient, 0.0)
241 )
242 return one_module_par
243
244 def __check_if_all_parameters_set(self):
245 """
246 Check if all random generation parameters are set for each calibration parameter.
247 """
248 for member_str in dir(self):
249 if not member_str.startswith("_") and not callable(
250 getattr(self, member_str)
251 ):
252 if not getattr(self, member_str).is_set():
253 raise RuntimeError(f"parameter {member_str} is not set!")
254
255 def insert_parameters(self, original_filepath: str, output_filepath: str):
256 """
257 Adding the parameters with random values to the output file
258
259 @param original_filepath The original input file to be added
260 @param output_filepath The output file containing the new parameter
261 """
262 input_par_file = ROOT.TFile(original_filepath, "read")
263 output_file = ROOT.TFile(output_filepath, "recreate")
264
266
267 for key in input_par_file.GetListOfKeys():
268 if key.GetName() in [f"{self.__run_id}", "ProcessID0"]:
269 continue
270 var = key.ReadObj()
271 output_file.WriteObject(var, var.GetName(), "update")
272
273 # Neues Parameter-Objekt erstellen und Module hinzufügen
274 par_run = input_par_file.Get(f"{self.__run_id}")
275 cal_to_hit_par = ROOT.R3B.Neuland.Cal2HitPar("NeulandHitPar")
276 cal_to_hit_par.SetNumOfModules(self.__module_num)
277 for module_id in range(1, self.__module_num + 1):
278 one_module_par = self.__assign_random_values(module_id)
279 cal_to_hit_par.AddModulePar(one_module_par)
280
281 # Version des neuen Parameters hinzufügen
282 cal_to_hit_par_version = ROOT.FairParVersion("NeulandHitPar")
283 cal_to_hit_par_version.setRootVersion(1)
284 par_run.addParVersion(cal_to_hit_par_version)
285
286 # Parameter-Objekte schreiben
287 output_file.WriteObject(par_run, par_run.GetName(), "update")
288 output_file.WriteObject(cal_to_hit_par, cal_to_hit_par.GetName(), "override")
289 output_file.Close()
A enumerator for the random type of a parameter.
Adding parameters whose values are randomly generated from the original file to the output file.
insert_parameters(self, str original_filepath, str output_filepath)
Adding the parameters with random values to the output file.
effective_speed
Effective speed of light paramter in the scintillation material.
saturation_coefficient
Saturation coefficient of the PMT (Both sides)
pedestal
Pedestal parameter of the PMT (Both sides)
energy_gain
Energy gain parameter of the PMT (Both sides)
set_run_id(self, int val)
Set the run id in the parameter file.
light_attenuation_length
Light attenuation length parameter.
generate_random_value_with_cos(ParValueSet par, module_id)
Generating a random value according to the module id and the given random generator parameters.
Data structure containing all information to generate a random value.
empty(cls)
Factory method to create an invalid empty object.
set_uniform(self, **kwargs)
Set all random generator parameter with the uniform distribution.
set_cos(self, **kwargs)
Set all random generator parameter with the cosine distribution.
is_set(self)
Query whether the object is valid or not.
set(self, Mode mode, float offset, float amp, int period=100, float err=0.5)
Set all parameters of random value generations with different mode and make the object valid.
set_clock(self, **kwargs)
Set all random generator parameter with the clock distribution.