TDCRPy 1.2.0__py3-none-any.whl → 1.4.0__py3-none-any.whl

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.

Potentially problematic release.


This version of TDCRPy might be problematic. Click here for more details.

tdcrpy/TDCRPy1.py ADDED
@@ -0,0 +1,946 @@
1
+ # -*- coding: utf-8 -*-
2
+ """
3
+ Created on Mon Jan 23 16:01:49 2023
4
+
5
+ A Monte-Carlo code to calculate detection efficiency in TDCR measurements
6
+
7
+ @author: Romain Coulon, Jialin Hu
8
+ Bureau International des Poids et Mesures
9
+ """
10
+
11
+ ## IMPORT PYTHON MODULES
12
+ # import tdcrpy.TDCR_model_lib as tl
13
+ import TDCR_model_lib as tl
14
+ import importlib.resources
15
+ from importlib.resources import files
16
+ import configparser
17
+ import numpy as np
18
+ from tqdm import tqdm
19
+
20
+ def TDCRPy(L, TD, TAB, TBC, TAC, Rad, pmf_1, N, kB, V, mode, mode2, Display=False, barp=False,uncData=False):
21
+ """
22
+ This is the main function of the TDCRPy package running the Monte-Carlo Triple-to-Double Coincidence Ratio model.
23
+ The computation is made for a given solution containing a radionuclide (or a mixture of radionuclides), a given volume of scintillator V and a given Birks constant kB.
24
+
25
+ It can operates in two modes:
26
+
27
+ --> In mode="eff", it calculates the efficiency of the TDCR system as a function of a value (triplet) of free parameter(s) L, the measurement data is not used;
28
+
29
+ --> In mode="res", it calculates the residual of the TDCR model parametrized by a value (or triplet) of free parameter(s) L and the measurement data TD, TAB, TBC, TAC.
30
+
31
+ also, two configuration can be set:
32
+
33
+ --> mode2="sym", where symmetry is considered between the 3 photomultiplier tubes - here L is a scalar and only the global TDCR value TD is used as measurement data.
34
+
35
+ --> mode2="asym", where an asymmetry between the 3 photomultiplier tubes is possible - here L is a triplet and only the specific TDCR values TAB, TBC, TAC are used as measurement data.
36
+
37
+ The parmeter N sets the number of Monte-Carlo trails used for the estimation. Each MC trial corresponds to a simulated radiactive decay.
38
+ TDCRPY() used a set of fonctions from the tdcrpy.TDCR_model_lib module.
39
+
40
+ Advanced settings can be configured in the config.toml file.
41
+
42
+ --> By default Y = True so that the analytical model is applied for solution containing only pure beta emitting radionuclides. If you would like to apply the MC calculation also for these nuclides, set Y = False.
43
+
44
+ --> If you would like to change the number of bins nE to discretize the linear energy space for quenching calculation, you can change nE_electron and nE_alpha parameters for respectively electrons and alpha particles.
45
+
46
+ --> By default the calculation is set for Ultima-Gold cocktail mixed with a small amount of aqueous solution. You can adapt for a specific scintillator by changing the density, the mean charge number Z and the mean mass number A of the scintillator.
47
+
48
+
49
+ Parameters
50
+ ----------
51
+ L : Float (if mode2="sym") or a tuple (if mode2="asym")
52
+ Free parameter in keV-1.
53
+ TD : float
54
+ triple-to-double coincidence ratio. Not consider if mode2="asym". Not consider if mode2="asym".
55
+ TAB : float
56
+ triple-to-double coincidence ratio (coincidences between channel A and B). Not consider if mode2="sym".
57
+ TBC : float
58
+ triple-to-double coincidence ratio (coincidences between channel B and C). Not consider if mode2="sym".
59
+ TAC : float
60
+ triple-to-double coincidence ratio (coincidences between channel A and C). Not consider if mode2="sym".
61
+ Rad : string
62
+ List of radionuclides (eg. "H-3, Co-60").
63
+ pmf_1 : string
64
+ list of probability of each radionuclide (eg. "0.8, 0.2").
65
+ N : integer
66
+ Number of Monte-Carlo trials. recommanded N>10000 (see JCGM 101). Not applied in the case of pure beta emitting radionuclides.
67
+ kB : float
68
+ Birks constant in cm/keV.
69
+ V : float
70
+ volume of the scintillator in ml.
71
+ mode : string
72
+ "res" to return the residual, "eff" to return efficiencies.
73
+ mode2 : string
74
+ "sym" for symetrical model, "asym" for symetrical model.
75
+ Display : Boolean, optional
76
+ "True" to display details on the decay sampling. The default is False.
77
+ barp : Boolean, optional
78
+ "True" to display the calculation progress. The default is True.
79
+
80
+ Returns
81
+ -------
82
+ res : float
83
+ Residuals of the model compared the measurement data for (a) given free parmeters L. (only in mode="res")
84
+ mean_efficiency_S : float
85
+ Estimation of the efficiency of single counting events. (only in mode="eff")
86
+ std_efficiency_S : float
87
+ Standard uncertainty from calculation associated with the estimation of the efficiency of single counting events. (only in mode="eff")
88
+ mean_efficiency_D : float
89
+ Estimation of the efficiency of logic sum of double coincidences. (only in mode="eff")
90
+ std_efficiency_D : float
91
+ Standard uncertainty from calculation associated with the estimation of the efficiency of logic sum of double coincidences. (only in mode="eff")
92
+ mean_efficiency_T : float
93
+ Estimation of the efficiency of triple coincidences. (only in mode="eff")
94
+ std_efficiency_T : float
95
+ Standard uncertainty from calculation associated with the estimation of the efficiency of triple coincidences. (only in mode="eff")
96
+ """
97
+ if barp: tl.display_header()
98
+ config = configparser.ConfigParser()
99
+ with importlib.resources.as_file(files('tdcrpy').joinpath('config.toml')) as data_path:
100
+ file_conf = data_path
101
+ config.read(file_conf)
102
+ tau=config["Inputs"].getfloat("tau")
103
+ Y=config["Inputs"].getboolean("Y")
104
+ radListPureBeta=config["Inputs"].get("radListPureBeta")
105
+ radListPureBeta=radListPureBeta.replace(" ","")
106
+ radListPureBeta=radListPureBeta.split(',')
107
+ X = Rad in radListPureBeta
108
+ if X:
109
+ nElist=config["Inputs"].get("nE")
110
+ nElist=nElist.split(',')
111
+ nElist = [int(i) for i in nElist]
112
+ if X and Y:
113
+ inE = radListPureBeta.index(Rad)
114
+ nE = nElist[inE]
115
+ out=tl.modelAnalytical(L,TD,TAB,TBC,TAC,Rad,kB,V,mode,mode2,nE)
116
+ if mode == "res":
117
+ return out
118
+ if mode == "eff":
119
+ return out[0], 0, out[1], 0, out[2], 0
120
+ else:
121
+ nE_electron = config["Inputs"].getint("nE_electron")
122
+ nE_alpha = config["Inputs"].getint("nE_alpha")
123
+ Rad=Rad.replace(" ","")
124
+ Rad=Rad.split(",")
125
+ pmf_1=pmf_1.split(",")
126
+ pmf_1 = [float(x) for x in pmf_1]
127
+
128
+ if np.size(pmf_1) > 1:
129
+ if sum(pmf_1) !=1: print("warning p not equal to 1")
130
+ elif pmf_1[0] != 1: print("warning")
131
+
132
+ """
133
+ Read PenNuc File
134
+ """
135
+ out_PenNuc = []
136
+ particle = [] # Particle(s) from the Mother -- indice 3
137
+ p_branch = [] # Probablity of the different decay of branch -- indice 5
138
+ e_branch = [] # Energy of the different decay of branch -- indice 4
139
+ LevelDaughter = [] # Level of the Daughter nucleus just after the particle emission -- indice 6
140
+ levelNumber = [] # The vector of level of the daughter to get information of all possible isomeric transitions -- indice 11
141
+ prob_trans = [] # Probability for each transition -- indice 10
142
+ prob_branch = [] # Probability for each branch -- indice 7
143
+ levelEnergy = [] # Energy of each level -- indice 13
144
+ transitionType = [] # type of each possible transitions (internal transitions or gamma emission) -- indice 8
145
+ e_trans = [] # Energy of the transition -- indice 9
146
+ next_level = [] # Next level on the daughter nucleus -- indice 12
147
+ Q_value = [] # Energy of the reaction -- indice 2
148
+ DaughterVec = [] # Daughters -- indice 0
149
+ Pdaughter = [] # Probabiblity related to daughters -- indice 1
150
+ Transition_prob_sum = []
151
+ u_prob_trans = [] # uncertainty of the probabilities for each transition -- indice 10
152
+ trans_halfLife = [] # half life of the transition
153
+
154
+ for rad_i in Rad:
155
+ out_PenNuc = tl.readPenNuc2(rad_i)
156
+ particle.append(out_PenNuc[3]) # Particle(s) from the Mother -- indice 3
157
+ p_branch.append(out_PenNuc[5]) # Probablity of the different decay of branch -- indice 5
158
+ e_branch.append(out_PenNuc[4]) # Energy of the different decay of branch -- indice 4
159
+ LevelDaughter.append(out_PenNuc[6]) # Level of the Daughter nucleus just after the particle emission -- indice 6
160
+ levelNumber.append(out_PenNuc[11]) # The vector of level of the daughter to get information of all possible isomeric transitions -- indice 11
161
+ prob_trans.append(out_PenNuc[10]) # Probability for each transition -- indice 10
162
+ prob_branch.append(out_PenNuc[7]) # Probability for each branch -- indice 7
163
+ levelEnergy.append(out_PenNuc[13]) # Energy of each level -- indice 13
164
+ transitionType.append(out_PenNuc[8]) # type of each possible transitions (internal transitions or gamma emission) -- indice 8
165
+ e_trans.append(out_PenNuc[9]) # Energy of the transition -- indice 9
166
+ next_level.append(out_PenNuc[12]) # Next level on the daughter nucleus -- indice 12
167
+ Q_value.append(out_PenNuc[2]) # Energy of the reaction -- indice 2
168
+ DaughterVec.append(out_PenNuc[0]) # Daughters -- indice 0
169
+ Pdaughter.append(out_PenNuc[1]) # Probabiblity related to daughters -- indice 1
170
+ Transition_prob_sum.append(out_PenNuc[14])
171
+ u_prob_trans.append(out_PenNuc[16])
172
+ trans_halfLife.append(out_PenNuc[15])
173
+ # print("\n",trans_halfLife)
174
+
175
+ efficiency_S = []
176
+ efficiency_D = []
177
+ efficiency_T = []
178
+ efficiency_S2 = []
179
+ efficiency_D2 = []
180
+ efficiency_T2 = []
181
+ efficiency_AB = []
182
+ efficiency_BC = []
183
+ efficiency_AC = []
184
+ efficiency_AB2 = []
185
+ efficiency_BC2 = []
186
+ efficiency_AC2 = []
187
+
188
+ if barp and not Display: NN = tqdm(range(N), desc="Processing", unit=" decays")
189
+ else: NN = range(N)
190
+ for i in NN: # Main Loop - Monte Carlo trials
191
+ particle_vec=[]
192
+ energy_vec=[]
193
+ '''
194
+ ===============================
195
+ 0. SAMPLING OF THE RADIONUCLIDE
196
+ ===============================
197
+ '''
198
+ index_rad = tl.sampling(pmf_1)
199
+ rad_i = Rad[index_rad]
200
+ if Display: print("\n Trial ",str(i+1),"- Sampled radionuclide: ", rad_i)
201
+
202
+
203
+ '''
204
+ ===========================
205
+ I. DESINTEGRATION NUCLEAIRE
206
+ ===========================
207
+ '''
208
+ #=========================
209
+ # Sampling of the daughter
210
+ #=========================
211
+ iDaughter=tl.sampling(np.asarray(Pdaughter[index_rad])/sum(np.asarray(Pdaughter[index_rad])))
212
+ Daughter = DaughterVec[index_rad][iDaughter]
213
+ if Display:
214
+ print("\t Sampled daughter:")
215
+ print("\t\t Daughter = ", Daughter)
216
+ #=============================
217
+ # Sampling of the decay branch
218
+ #=============================
219
+ branch_i = tl.normalise(prob_branch[index_rad][iDaughter]) # normalise la proba de branch
220
+ i_branch=tl.sampling(branch_i) # indice de la branche globale
221
+ if p_branch[index_rad][iDaughter][i_branch] != []:
222
+ branch_proba = tl.normalise(p_branch[index_rad][iDaughter][i_branch])
223
+ index_subBranch = tl.sampling(branch_proba) # indice de la branch precise
224
+ particle_branch = particle[index_rad][iDaughter][i_branch][index_subBranch] # sampled particle emitted by the mother
225
+ energy_branch = e_branch[index_rad][iDaughter][i_branch][index_subBranch] # energy of the particle emitted by the mother
226
+ # probability_branch = p_branch[index_rad][iDaughter][i_branch][index_subBranch] # probability of the sampled branch
227
+ levelOftheDaughter = LevelDaughter[index_rad][iDaughter][i_branch][index_subBranch] # Level of the daughter just after the particle emission from the mother
228
+ level_before_trans = LevelDaughter[index_rad][iDaughter][i_branch][index_subBranch]
229
+ if Display:
230
+ print("\t Sampled decay branch:")
231
+ if particle_branch[:4]=="Atom":
232
+ if particle_branch=="Atom_K": print("\t\t Electron capture on K shell")
233
+ if particle_branch=="Atom_L" or particle_branch=="Atom_L1" or particle_branch=="Atom_L2" or particle_branch=="Atom_L3": print("\t\t Electron capture on L shell")
234
+ if particle_branch=="Atom_M": print("\t\t Electron capture on M shell")
235
+ if particle_branch=="Atom_O": print("\t\t Electron capture on O shell")
236
+ else:
237
+ print("\t\t Particle: ", particle_branch)
238
+ print("\t\t Energy of the particle = ", energy_branch, " keV")
239
+ print("\t\t Level of the daughter nucleus: ", levelOftheDaughter)
240
+ #========
241
+ # Scoring
242
+ #========
243
+ e_sum = energy_branch # Update the Energy summary
244
+ particle_vec.append(particle_branch) # Update of the particle vector
245
+ energy_vec.append(energy_branch) # Update of the energy of the particle
246
+ else:
247
+ transition_prob = tl.normalise(Transition_prob_sum[index_rad][iDaughter])
248
+ index_transition_level = tl.sampling(transition_prob)
249
+ levelOftheDaughter = levelNumber[index_rad][iDaughter][index_transition_level][0]
250
+ if Display:
251
+ print("\t Sampled decay branch:")
252
+ print("\t\t Particle = isomeric transition, no particle")
253
+ print("\t\t Level of the nucleus : ",levelOftheDaughter)
254
+ e_sum = 0
255
+
256
+ '''
257
+ ==============
258
+ I-1 Transition
259
+ ==============
260
+ '''
261
+ if Display: print("\t Subsequent isomeric transition(s)") # finish with the mother / now with the daughter
262
+ evenement = 1
263
+ e_sum2 = 0
264
+ particle_vec2 = []
265
+ energy_vec2 = []
266
+ while levelOftheDaughter > 0: # Go on the loop while the daughter nucleus is a its fundamental level (energy 0)
267
+ i_level = levelNumber[index_rad][iDaughter].index([levelOftheDaughter]) # Find the position in the daughter level vector
268
+
269
+ t1 = np.random.exponential(trans_halfLife[index_rad][iDaughter][i_level][0], size=1)[0]
270
+
271
+ # test whether the decay occurs within the coincidence resolving time or not
272
+ if t1 > tau:
273
+ #splitEvent = True
274
+ evenement = evenement + 1
275
+
276
+ if transitionType[index_rad][iDaughter][i_level] != []:
277
+ #====================================================================
278
+ # Sampling of the transition in energy levels of the daughter nucleus
279
+ #====================================================================
280
+
281
+ if uncData:
282
+ prob_trans_s=[]
283
+ for ipt, xpt in enumerate(prob_trans[index_rad][iDaughter][i_level]):
284
+ prob_trans_s.append(np.random.normal(xpt, u_prob_trans[index_rad][iDaughter][i_level][ipt], 1)[0])
285
+
286
+ probability_tran = tl.normalise(prob_trans_s) # normaliser la proba de transition
287
+ else:
288
+ probability_tran = tl.normalise(prob_trans[index_rad][iDaughter][i_level]) # normaliser la proba de transition
289
+ #probability_tran = tl.normalise(prob_trans[index_rad][iDaughter][i_level]) # normaliser la proba de transition
290
+ index_t = tl.sampling(probability_tran) # indice de la transition
291
+ if Display:
292
+ print("\t\t Energy of the level = ", levelEnergy[index_rad][iDaughter][i_level][0], " keV")
293
+ trans = transitionType[index_rad][iDaughter][i_level][index_t]
294
+ if trans == "GA":
295
+ print("\t\t Energy of the gamma ray = ", e_trans[index_rad][iDaughter][i_level][index_t], "keV")
296
+ elif trans == "EK":
297
+ print("\t\t Energy of the conversion electron from K shell = ", e_trans[index_rad][iDaughter][i_level][index_t], "keV")
298
+ elif trans == "EL":
299
+ print("\t\t Energy of the conversion electron from L shell = ", e_trans[index_rad][iDaughter][i_level][index_t], "keV")
300
+ elif trans == "EM":
301
+ print("\t\t Energy of the conversion electron from M shell = ", e_trans[index_rad][iDaughter][i_level][index_t], "keV")
302
+ print("\t\t next level = ", next_level[index_rad][iDaughter][i_level][index_t])
303
+ #========
304
+ # Scoring
305
+ #========
306
+
307
+ ## evenement retardé
308
+ if evenement != 1:
309
+ if transitionType[index_rad][iDaughter][i_level][index_t] == "GA": # if it is a gamma that has been emitted
310
+ particle_vec2.append("gamma") # Update of the particle vector
311
+ energy_vec2.append(e_trans[index_rad][iDaughter][i_level][index_t]) # Update the energy vector
312
+ else: # if not, it is a internal conversion, so an electron
313
+ particle_vec2.append("electron") # !!!!!!!!! it is OK for our model? Does the electron leave with the kinetic enegy of the transition
314
+ energy_vec2.append(e_trans[index_rad][iDaughter][i_level][index_t]) # Update the energy vector
315
+ if transitionType[index_rad][iDaughter][i_level][index_t] == "EK": # record that an electron is missing on the K shell of the dughter nucleus
316
+ particle_vec2.append("Atom_K")
317
+ energy_vec2.append(0)
318
+
319
+ if transitionType[index_rad][iDaughter][i_level][index_t] == "EL": # record that an electron is missing on the L1 shell of the dughter nucleus
320
+ particle_vec2.append("Atom_L")
321
+ energy_vec2.append(0)
322
+
323
+ if transitionType[index_rad][iDaughter][i_level][index_t] == "EL1": # record that an electron is missing on the L1 shell of the dughter nucleus
324
+ particle_vec2.append("Atom_L1")
325
+ energy_vec2.append(0)
326
+
327
+ if transitionType[index_rad][iDaughter][i_level][index_t] == "EL2": # record that an electron is missing on the L2 shell of the dughter nucleus
328
+ particle_vec2.append("Atom_L2")
329
+ energy_vec2.append(0)
330
+
331
+ if transitionType[index_rad][iDaughter][i_level][index_t] == "EL3": # record that an electron is missing on the L3 shell of the dughter nucleus
332
+ particle_vec2.append("Atom_L3")
333
+ energy_vec2.append(0)
334
+
335
+ if transitionType[index_rad][iDaughter][i_level][index_t] == "EM": # record that an electron is missing on the M shell of the dughter nucleus
336
+ particle_vec2.append("Atom_M")
337
+ energy_vec2.append(0)
338
+
339
+ if transitionType[index_rad][iDaughter][i_level][index_t] == "EN": # record that an electron is missing on the N shell of the dughter nucleus
340
+ particle_vec2.append("Atom_N")
341
+ energy_vec2.append(0)
342
+ e_sum2 += e_trans[index_rad][iDaughter][i_level][index_t] # Energy summary
343
+
344
+
345
+ ## evenement normal
346
+ else:
347
+ if transitionType[index_rad][iDaughter][i_level][index_t] == "GA": # if it is a gamma that has been emitted
348
+ particle_vec.append("gamma") # Update of the particle vector
349
+ energy_vec.append(e_trans[index_rad][iDaughter][i_level][index_t]) # Update the energy vector
350
+ else: # if not, it is a internal conversion, so an electron
351
+ particle_vec.append("electron") # !!!!!!!!! it is OK for our model? Does the electron leave with the kinetic enegy of the transition
352
+ energy_vec.append(e_trans[index_rad][iDaughter][i_level][index_t]) # Update the energy vector
353
+ if transitionType[index_rad][iDaughter][i_level][index_t] == "EK": # record that an electron is missing on the K shell of the dughter nucleus
354
+ particle_vec.append("Atom_K")
355
+ energy_vec.append(0)
356
+
357
+ if transitionType[index_rad][iDaughter][i_level][index_t] == "EL": # record that an electron is missing on the L1 shell of the dughter nucleus
358
+ particle_vec.append("Atom_L")
359
+ energy_vec.append(0)
360
+
361
+ if transitionType[index_rad][iDaughter][i_level][index_t] == "EL1": # record that an electron is missing on the L1 shell of the dughter nucleus
362
+ particle_vec.append("Atom_L1")
363
+ energy_vec.append(0)
364
+
365
+ if transitionType[index_rad][iDaughter][i_level][index_t] == "EL2": # record that an electron is missing on the L2 shell of the dughter nucleus
366
+ particle_vec.append("Atom_L2")
367
+ energy_vec.append(0)
368
+
369
+ if transitionType[index_rad][iDaughter][i_level][index_t] == "EL3": # record that an electron is missing on the L3 shell of the dughter nucleus
370
+ particle_vec.append("Atom_L3")
371
+ energy_vec.append(0)
372
+
373
+ if transitionType[index_rad][iDaughter][i_level][index_t] == "EM": # record that an electron is missing on the M shell of the dughter nucleus
374
+ particle_vec.append("Atom_M")
375
+ energy_vec.append(0)
376
+
377
+ if transitionType[index_rad][iDaughter][i_level][index_t] == "EN": # record that an electron is missing on the N shell of the dughter nucleus
378
+ particle_vec.append("Atom_N")
379
+ energy_vec.append(0)
380
+ e_sum += e_trans[index_rad][iDaughter][i_level][index_t] # Energy summary
381
+
382
+
383
+
384
+ levelOftheDaughter = next_level[index_rad][iDaughter][i_level][index_t] # set the next level
385
+
386
+ else:
387
+ i_level = levelNumber[index_rad][iDaughter].index([levelOftheDaughter])
388
+ print("warning:pas de données de transition:daughter,niveau,niveau d'énergie",DaughterVec[index_rad][iDaughter],levelOftheDaughter,levelEnergy[index_rad][iDaughter][i_level] )
389
+ levelOftheDaughter = 0 # set the next level
390
+
391
+ if Display:
392
+ print("\t Summary of the nuclear promt decay")
393
+ for i, p in enumerate(particle_vec):
394
+ if p[:4] != "Atom":
395
+ print('particle :',p)
396
+ print(f"\t\t energy of {p} = ", energy_vec[i]," keV")
397
+ if evenement != 1:
398
+ print("\t Summary of the nuclear delayed decay")
399
+ for i, p in enumerate(particle_vec2):
400
+ if p[:4] != "Atom":
401
+ print('particle :',p)
402
+ print(f"\t\t energy of {p} = ", energy_vec2[i]," keV")
403
+
404
+ '''
405
+ ==========================
406
+ II. LA RELAXATION ATOMIQUE
407
+ ==========================
408
+ '''
409
+ ## evenement retarde
410
+ if evenement != 1:
411
+
412
+ daughter_relax = DaughterVec[index_rad][iDaughter]
413
+ for i_part in range(len(particle_vec)):
414
+ relaxation = False
415
+ if "Atom_K" in particle_vec[i_part] or "Atom_L" in particle_vec[i_part] or "Atom_M" in particle_vec[i_part]:
416
+ relaxation = True
417
+ while relaxation:
418
+ tf,ef = tl.relaxation_atom(daughter_relax,Rad[index_rad],particle_vec[i_part])
419
+ if tf == "XKA":
420
+ particle_vec[i_part] = "Atom_L"
421
+ particle_vec.append(tf)
422
+ energy_vec.append(ef)
423
+ relaxation = True
424
+ elif tf == "XKB":
425
+ particle_vec[i_part] = "Atom_M"
426
+ particle_vec.append(tf)
427
+ energy_vec.append(ef)
428
+ relaxation = False
429
+ elif tf == "XL":
430
+ particle_vec[i_part] = "Atom_M"
431
+ particle_vec.append(tf)
432
+ energy_vec.append(ef)
433
+ relaxation = False
434
+ elif tf == "Auger K":
435
+ particle_vec[i_part] = "Atom_L"
436
+ particle_vec.append(tf)
437
+ energy_vec.append(ef)
438
+ relaxation = True
439
+ elif tf == "Auger L":
440
+ particle_vec[i_part] = "Atom_M"
441
+ particle_vec.append(tf)
442
+ energy_vec.append(ef)
443
+ relaxation = False
444
+ else:
445
+ if Display: print("untermined x or Auger")
446
+ relaxation = False
447
+ e_sum += ef
448
+ if Display:
449
+ print("\t Summary of the atomic relaxation (promt emission)")
450
+ for i, p in enumerate(particle_vec):
451
+ if p[:4] != "Atom":
452
+ print(f"\t\t energy of {p} = ", round(energy_vec[i],3), "keV")
453
+
454
+ for i_part in range(len(particle_vec2)):
455
+ relaxation = False
456
+ if "Atom_K" in particle_vec2[i_part] or "Atom_L" in particle_vec2[i_part] or "Atom_M" in particle_vec2[i_part]:
457
+ relaxation = True
458
+ while relaxation:
459
+ tf,ef = tl.relaxation_atom(daughter_relax,Rad[index_rad],particle_vec2[i_part])
460
+ if tf == "XKA":
461
+ particle_vec2[i_part] = "Atom_L"
462
+ particle_vec2.append(tf)
463
+ energy_vec2.append(ef)
464
+ relaxation = True
465
+ elif tf == "XKB":
466
+ particle_vec2[i_part] = "Atom_M"
467
+ particle_vec2.append(tf)
468
+ energy_vec2.append(ef)
469
+ relaxation = False
470
+ elif tf == "XL":
471
+ particle_vec2[i_part] = "Atom_M"
472
+ particle_vec2.append(tf)
473
+ energy_vec2.append(ef)
474
+ relaxation = False
475
+ elif tf == "Auger K":
476
+ particle_vec2[i_part] = "Atom_L"
477
+ particle_vec2.append(tf)
478
+ energy_vec2.append(ef)
479
+ relaxation = True
480
+ elif tf == "Auger L":
481
+ particle_vec2[i_part] = "Atom_M"
482
+ particle_vec2.append(tf)
483
+ energy_vec2.append(ef)
484
+ relaxation = False
485
+ else:
486
+ if Display: print("untermined x or Auger")
487
+ relaxation = False
488
+ e_sum2 += ef
489
+
490
+ if Display:
491
+ print("\t Summary of the atomic relaxation (delayed emission)")
492
+ for i, p in enumerate(particle_vec2):
493
+ if p[:4] != "Atom":
494
+ print(f"\t\t energy of {p} = ", round(energy_vec2[i],3), "keV")
495
+
496
+ '''
497
+ ==========================================================
498
+ III.a SPECTRES D'EMISSION
499
+ ==========================================================
500
+ '''
501
+
502
+ for i, p in enumerate(particle_vec2):
503
+ if p == "beta":
504
+ e_b,p_b = tl.readBetaShape(rad_i,"beta-",level_before_trans) # read the data of BetaShape
505
+ index_beta_energy = tl.sampling(p_b) # sampling energy of beta
506
+ particle_vec2[i] = "electron"
507
+ energy_vec2[i] = e_b[index_beta_energy]
508
+
509
+ if p == "beta+":
510
+ e_b,p_b = tl.readBetaShape(rad_i,"beta+",level_before_trans)
511
+ index_beta_energy = tl.sampling(p_b)
512
+ particle_vec2[i] = "positron"
513
+ energy_vec2[i] = e_b[index_beta_energy]
514
+ particle_vec2.append("gamma")
515
+ particle_vec2.append("gamma")
516
+ energy_vec2.append(511)
517
+ energy_vec2.append(511)
518
+ energy_vec_initial2 = energy_vec2
519
+ if Display:
520
+ print("\t Summary of emitted particles from the delayed atomic relaxation")
521
+ for i, p in enumerate(particle_vec2):
522
+ if p[:4] != "Atom": print(f"\t\t energy of {p} = ", round(energy_vec2[i],3), "keV")
523
+
524
+
525
+ for i, p in enumerate(particle_vec):
526
+ if p == "beta":
527
+ e_b,p_b = tl.readBetaShape(rad_i,"beta-",level_before_trans) # read the data of BetaShape
528
+ index_beta_energy = tl.sampling(p_b) # sampling energy of beta
529
+ particle_vec[i] = "electron"
530
+ energy_vec[i] = e_b[index_beta_energy]
531
+
532
+ if p == "beta+":
533
+ e_b,p_b = tl.readBetaShape(rad_i,"beta+",level_before_trans)
534
+ index_beta_energy = tl.sampling(p_b)
535
+ particle_vec[i] = "positron"
536
+ energy_vec[i] = e_b[index_beta_energy]
537
+ particle_vec.append("gamma")
538
+ particle_vec.append("gamma")
539
+ energy_vec.append(511)
540
+ energy_vec.append(511)
541
+ energy_vec_initial = energy_vec
542
+ if Display:
543
+ print("\t Summary of emitted particles from the promt nuclear relaxation")
544
+ for i, p in enumerate(particle_vec):
545
+ if p[:4] != "Atom": print(f"\t\t energy of {p} = ", round(energy_vec[i],3), "keV")
546
+
547
+
548
+ '''
549
+ ==========================================================
550
+ III.b INTERACTION RAYONNEMENT/MATIERE
551
+ ==========================================================
552
+ '''
553
+
554
+ for i, p in enumerate(particle_vec2):
555
+ if p == "electron":
556
+ energy_vec2[i] = tl.energie_dep_beta(energy_vec2[i])
557
+
558
+ if p == "beta+":
559
+ energy_vec2[i] = tl.energie_dep_beta(energy_vec2[i])
560
+
561
+ if p == "gamma" or p == "XKA" or p == "XKB" or p == "XL":
562
+ energy_vec2[i] = tl.energie_dep_gamma(energy_vec2[i],v=V) # sampling energy free from photon
563
+ particle_vec2[i] = "electron"
564
+
565
+ if p == "Auger K" or p == "Auger L":
566
+ particle_vec2[i] = "electron"
567
+ energy_vec2[i] = tl.energie_dep_beta(energy_vec2[i])
568
+
569
+ if Display:
570
+ print("\t Summary of the energy deposited by charged particles by the delayed atomic relaxation")
571
+ for i, p in enumerate(particle_vec2):
572
+ if p[:4] != "Atom": print(f"\t\t energy of {p} = ", round(energy_vec2[i],3), "keV")
573
+
574
+
575
+ for i, p in enumerate(particle_vec):
576
+ if p == "electron":
577
+ energy_vec[i] = tl.energie_dep_beta(energy_vec[i])
578
+
579
+ if p == "beta+":
580
+ energy_vec[i] = tl.energie_dep_beta(energy_vec[i])
581
+
582
+ if p == "gamma" or p == "XKA" or p == "XKB" or p == "XL":
583
+ energy_vec[i] = tl.energie_dep_gamma(energy_vec[i],v=V) # sampling energy free from photon
584
+ particle_vec[i] = "electron"
585
+
586
+ if p == "Auger K" or p == "Auger L":
587
+ particle_vec[i] = "electron"
588
+ energy_vec[i] = tl.energie_dep_beta(energy_vec[i])
589
+
590
+ if Display:
591
+ print("\t Summary of the energy deposited by charged particles from the prompt nuclear relaxation")
592
+ for i, p in enumerate(particle_vec):
593
+ if p[:4] != "Atom": print(f"\t\t energy of {p} = ", round(energy_vec[i],3), "keV")
594
+
595
+ '''
596
+ ====================
597
+ IV. LA SCINTILLATION
598
+ Calculation of the scintillation quenching with the Birks Model
599
+ ====================
600
+ '''
601
+ if Display: print("\t Summary of the estimation of quenched energies by the delayed atomic relaxation")
602
+ e_quenching2=[]
603
+ for i, p in enumerate(particle_vec2):
604
+ if p == "alpha":
605
+ energy_vec2[i] = tl.Em_a(energy_vec2[i],kB,nE_alpha)
606
+ e_quenching2.append(energy_vec2[i])
607
+ elif p == "electron" or p == "positron":
608
+ energy_vec2[i] = tl.Em_e(energy_vec_initial2[i]*1e3,energy_vec2[i]*1e3,kB*1e3,nE_electron)*1e-3
609
+ e_quenching2.append(energy_vec2[i])
610
+ else:
611
+ e_quenching2.append(0)
612
+ if Display: print("\t\t Birks constant = ", kB, ' cm/keV')
613
+ if Display:
614
+ for i, p in enumerate(particle_vec2):
615
+ if p[:4] != "Atom": print(f"\t\t quenched energy of {p} = ", round(e_quenching2[i],3), "keV")
616
+
617
+
618
+ # changer l'intégration E_i - E_d à E_i
619
+ if Display: print("\t Summary of the estimation of quenched energies from the prompt nuclear relaxation")
620
+ e_quenching=[]
621
+ for i, p in enumerate(particle_vec):
622
+ if p == "alpha":
623
+ energy_vec[i] = tl.Em_a(energy_vec[i],kB,nE_alpha)
624
+ e_quenching.append(energy_vec[i])
625
+ elif p == "electron" or p == "positron":
626
+ energy_vec[i] = tl.Em_e(energy_vec_initial[i]*1e3,energy_vec[i]*1e3,kB*1e3,nE_electron)*1e-3
627
+ e_quenching.append(energy_vec[i])
628
+ else:
629
+ e_quenching.append(0)
630
+ if Display: print("\t\t Birks constant = ", kB, ' cm/keV')
631
+ if Display:
632
+ for i, p in enumerate(particle_vec):
633
+ if p[:4] != "Atom": print(f"\t\t quenched energy of {p} = ", round(e_quenching[i],3), "keV")
634
+
635
+ '''
636
+ ====================
637
+ V. LE MESURE TDCR
638
+ ====================
639
+ '''
640
+
641
+ if mode2=="sym":
642
+ p_nosingle2 = np.exp(-L*np.sum(np.asarray(e_quenching2))/3) # probability to have 0 electrons in a PMT
643
+ p_single2 = 1-p_nosingle2 # probability to have at least 1 electrons in a PMT
644
+ efficiency_S2.append(p_single2)
645
+ efficiency_T2.append(p_single2**3)
646
+ efficiency_D2.append(3*(p_single2)**2-2*efficiency_T2[-1])
647
+ if Display: print("\t Summary of TDCR measurement (delayed)")
648
+ if Display: print("\t\t Free parameter = ", L, "keV-1")
649
+ if Display: print("\t\t Efficiency of single events = ", round(efficiency_S2[-1],5))
650
+ if Display: print("\t\t Efficiency of double events = ", round(efficiency_D2[-1],5))
651
+ if Display: print("\t\t Efficiency of triple events = ", round(efficiency_T2[-1],5))
652
+
653
+ p_nosingle = np.exp(-L*np.sum(np.asarray(e_quenching))/3) # probability to have 0 electrons in a PMT
654
+ p_single = 1-p_nosingle # probability to have at least 1 electrons in a PMT
655
+ efficiency_S.append(p_single)
656
+ efficiency_T.append(p_single**3)
657
+ efficiency_D.append(3*(p_single)**2-2*efficiency_T[-1])
658
+ if Display: print("\t Summary of TDCR measurement (prompt)")
659
+ if Display: print("\t\t Free parameter = ", L, "keV-1")
660
+ if Display: print("\t\t Efficiency of single events = ", round(efficiency_S[-1],5))
661
+ if Display: print("\t\t Efficiency of double events = ", round(efficiency_D[-1],5))
662
+ if Display: print("\t\t Efficiency of triple events = ", round(efficiency_T[-1],5))
663
+
664
+ elif mode2=="asym":
665
+ pA_nosingle2 = np.exp(-L[0]*np.sum(np.asarray(e_quenching2))/3) # probability to have 0 electrons in a PMT
666
+ pA_single2 = 1-pA_nosingle2 # probability to have at least 1 electrons in a PMT
667
+ pB_nosingle2 = np.exp(-L[1]*np.sum(np.asarray(e_quenching2))/3) # probability to have 0 electrons in a PMT
668
+ pB_single2 = 1-pB_nosingle2 # probability to have at least 1 electrons in a PMT
669
+ pC_nosingle2 = np.exp(-L[2]*np.sum(np.asarray(e_quenching2))/3) # probability to have 0 electrons in a PMT
670
+ pC_single2 = 1-pC_nosingle2 # probability to have at least 1 electrons in a PMT
671
+
672
+ efficiency_AB2.append(pA_single2*pB_single2)
673
+ efficiency_BC2.append(pB_single2*pC_single2)
674
+ efficiency_AC2.append(pA_single2*pC_single2)
675
+ efficiency_T2.append(pA_single2*pB_single2*pC_single2)
676
+ efficiency_D2.append(efficiency_AB2[-1]+efficiency_BC2[-1]+efficiency_AC2[-1]-2*efficiency_T2[-1])
677
+ efficiency_S2.append(pA_single2+pB_single2+pC_single2-efficiency_D2[-1]-efficiency_T2[-1])
678
+ if Display: print("\t Summary of TDCR measurement (delayed)")
679
+ if Display: print("\t\t Free parameter PMT A: ", L[0], "keV-1")
680
+ if Display: print("\t\t Free parameter PMT B: ", L[1], "keV-1")
681
+ if Display: print("\t\t Free parameter PMT C: ", L[2], "keV-1")
682
+ if Display: print("\t\t Efficiency of single events: ", round(efficiency_S2[-1],5))
683
+ if Display: print("\t\t Efficiency of double events: ", round(efficiency_D2[-1],5))
684
+ if Display: print("\t\t Efficiency of triple events: ", round(efficiency_T2[-1],5))
685
+
686
+
687
+ pA_nosingle = np.exp(-L[0]*np.sum(np.asarray(e_quenching))/3) # probability to have 0 electrons in a PMT
688
+ pA_single = 1-pA_nosingle # probability to have at least 1 electrons in a PMT
689
+ pB_nosingle = np.exp(-L[1]*np.sum(np.asarray(e_quenching))/3) # probability to have 0 electrons in a PMT
690
+ pB_single = 1-pB_nosingle # probability to have at least 1 electrons in a PMT
691
+ pC_nosingle = np.exp(-L[2]*np.sum(np.asarray(e_quenching))/3) # probability to have 0 electrons in a PMT
692
+ pC_single = 1-pC_nosingle # probability to have at least 1 electrons in a PMT
693
+
694
+ efficiency_AB.append(pA_single*pB_single)
695
+ efficiency_BC.append(pB_single*pC_single)
696
+ efficiency_AC.append(pA_single*pC_single)
697
+ efficiency_T.append(pA_single*pB_single*pC_single)
698
+ efficiency_D.append(efficiency_AB[-1]+efficiency_BC[-1]+efficiency_AC[-1]-2*efficiency_T[-1])
699
+ efficiency_S.append(pA_single+pB_single+pC_single-efficiency_D[-1]-efficiency_T[-1])
700
+ if Display: print("\t Summary of TDCR measurement (prompt)")
701
+ if Display: print("\t\t Free parameter PMT A: ", L[0], "keV-1")
702
+ if Display: print("\t\t Free parameter PMT B: ", L[1], "keV-1")
703
+ if Display: print("\t\t Free parameter PMT C: ", L[2], "keV-1")
704
+ if Display: print("\t\t Efficiency of single events: ", round(efficiency_S[-1],5))
705
+ if Display: print("\t\t Efficiency of double events: ", round(efficiency_D[-1],5))
706
+ if Display: print("\t\t Efficiency of triple events: ", round(efficiency_T[-1],5))
707
+
708
+ else: # One decay event into the resolving time
709
+
710
+ daughter_relax = DaughterVec[index_rad][iDaughter]
711
+ for i_part in range(len(particle_vec)):
712
+ relaxation = False
713
+ if "Atom_K" in particle_vec[i_part] or "Atom_L" in particle_vec[i_part] or "Atom_M" in particle_vec[i_part]:
714
+ relaxation = True
715
+ while relaxation:
716
+ tf,ef = tl.relaxation_atom(daughter_relax,Rad[index_rad],particle_vec[i_part])
717
+ if tf == "XKA":
718
+ particle_vec[i_part] = "Atom_L"
719
+ particle_vec.append(tf)
720
+ energy_vec.append(ef)
721
+ relaxation = True
722
+ elif tf == "XKB":
723
+ particle_vec[i_part] = "Atom_M"
724
+ particle_vec.append(tf)
725
+ energy_vec.append(ef)
726
+ relaxation = False
727
+ elif tf == "XL":
728
+ particle_vec[i_part] = "Atom_M"
729
+ particle_vec.append(tf)
730
+ energy_vec.append(ef)
731
+ relaxation = False
732
+ elif tf == "Auger K":
733
+ particle_vec[i_part] = "Atom_L"
734
+ particle_vec.append(tf)
735
+ energy_vec.append(ef)
736
+ relaxation = True
737
+ elif tf == "Auger L":
738
+ particle_vec[i_part] = "Atom_M"
739
+ particle_vec.append(tf)
740
+ energy_vec.append(ef)
741
+ relaxation = False
742
+ else:
743
+ if Display: print("untermined x or Auger")
744
+ relaxation = False
745
+ e_sum += ef
746
+ if Display:
747
+ print("\t Summary of the atomic relaxation")
748
+ for i, p in enumerate(particle_vec):
749
+ if p[:4] != "Atom":
750
+ print(f"\t\t energy of {p} = ", round(energy_vec[i],3), "keV")
751
+
752
+ '''
753
+ ==========================================================
754
+ III.a SPECTRES D'EMISSION
755
+ ==========================================================
756
+ '''
757
+
758
+ for i, p in enumerate(particle_vec):
759
+ if p == "beta":
760
+ e_b,p_b = tl.readBetaShape(rad_i,"beta-",level_before_trans) # read the data of BetaShape
761
+ index_beta_energy = tl.sampling(p_b) # sampling energy of beta
762
+ particle_vec[i] = "electron"
763
+ energy_vec[i] = e_b[index_beta_energy]
764
+
765
+ if p == "beta+":
766
+ e_b,p_b = tl.readBetaShape(rad_i,"beta+",level_before_trans)
767
+ index_beta_energy = tl.sampling(p_b)
768
+ particle_vec[i] = "positron"
769
+ energy_vec[i] = e_b[index_beta_energy]
770
+ particle_vec.append("gamma")
771
+ particle_vec.append("gamma")
772
+ energy_vec.append(511)
773
+ energy_vec.append(511)
774
+ energy_vec_initial = energy_vec
775
+ if Display:
776
+ print("\t Summary of emitted particles")
777
+ for i, p in enumerate(particle_vec):
778
+ if p[:4] != "Atom": print(f"\t\t energy of {p} = ", round(energy_vec[i],3), "keV")
779
+
780
+
781
+ '''
782
+ ==========================================================
783
+ III.b INTERACTION RAYONNEMENT/MATIERE
784
+ ==========================================================
785
+ '''
786
+ for i, p in enumerate(particle_vec):
787
+ if p == "electron":
788
+ energy_vec[i] = tl.energie_dep_beta(energy_vec[i])
789
+
790
+ if p == "beta+":
791
+ energy_vec[i] = tl.energie_dep_beta(energy_vec[i])
792
+
793
+ if p == "gamma" or p == "XKA" or p == "XKB" or p == "XL":
794
+ energy_vec[i] = tl.energie_dep_gamma(energy_vec[i],v=V) # sampling energy free from photon
795
+ particle_vec[i] = "electron"
796
+
797
+ if p == "Auger K" or p == "Auger L":
798
+ particle_vec[i] = "electron"
799
+ energy_vec[i] = tl.energie_dep_beta(energy_vec[i])
800
+
801
+ if Display:
802
+ print("\t Summary of the energy deposited by charged particles")
803
+ for i, p in enumerate(particle_vec):
804
+ if p[:4] != "Atom": print(f"\t\t energy of {p} = ", round(energy_vec[i],3), "keV")
805
+
806
+ '''
807
+ ====================
808
+ IV. LA SCINTILLATION
809
+ Calculation of the scintillation quenching with the Birks Model
810
+ ====================
811
+ '''
812
+ # changer l'intégration E_i - E_d à E_i
813
+ if Display: print("\t Summary of the estimation of quenched energies")
814
+ e_quenching=[]
815
+ for i, p in enumerate(particle_vec):
816
+ if p == "alpha":
817
+ energy_vec[i] = tl.Em_a(energy_vec[i],kB,nE_alpha)
818
+ e_quenching.append(energy_vec[i])
819
+ elif p == "electron" or p == "positron":
820
+ energy_vec[i] = tl.Em_e(energy_vec_initial[i]*1e3,energy_vec[i]*1e3,kB*1e3,nE_electron)*1e-3
821
+ e_quenching.append(energy_vec[i])
822
+ else:
823
+ e_quenching.append(0)
824
+ if Display: print("\t\t Birks constant = ", kB, ' cm/keV')
825
+ if Display:
826
+ for i, p in enumerate(particle_vec):
827
+ if p[:4] != "Atom": print(f"\t\t quenched energy of {p} = ", round(e_quenching[i],3), "keV")
828
+
829
+ '''
830
+ ====================
831
+ V. LE MESURE TDCR
832
+ ====================
833
+ '''
834
+ if mode2=="sym":
835
+ p_nosingle = np.exp(-L*np.sum(np.asarray(e_quenching))/3) # probability to have 0 electrons in a PMT
836
+ p_single = 1-p_nosingle # probability to have at least 1 electrons in a PMT
837
+ efficiency_S.append(p_single)
838
+ efficiency_T.append(p_single**3)
839
+ efficiency_D.append(3*(p_single)**2-2*efficiency_T[-1])
840
+ if Display: print("\t Summary of TDCR measurement")
841
+ if Display: print("\t\t Free parameter = ", L, "keV-1")
842
+ if Display: print("\t\t Efficiency of single events = ", round(efficiency_S[-1],5))
843
+ if Display: print("\t\t Efficiency of double events = ", round(efficiency_D[-1],5))
844
+ if Display: print("\t\t Efficiency of triple events = ", round(efficiency_T[-1],5))
845
+ elif mode2=="asym":
846
+ pA_nosingle = np.exp(-L[0]*np.sum(np.asarray(e_quenching))/3) # probability to have 0 electrons in a PMT
847
+ pA_single = 1-pA_nosingle # probability to have at least 1 electrons in a PMT
848
+ pB_nosingle = np.exp(-L[1]*np.sum(np.asarray(e_quenching))/3) # probability to have 0 electrons in a PMT
849
+ pB_single = 1-pB_nosingle # probability to have at least 1 electrons in a PMT
850
+ pC_nosingle = np.exp(-L[2]*np.sum(np.asarray(e_quenching))/3) # probability to have 0 electrons in a PMT
851
+ pC_single = 1-pC_nosingle # probability to have at least 1 electrons in a PMT
852
+
853
+ efficiency_AB.append(pA_single*pB_single)
854
+ efficiency_BC.append(pB_single*pC_single)
855
+ efficiency_AC.append(pA_single*pC_single)
856
+ efficiency_T.append(pA_single*pB_single*pC_single)
857
+ efficiency_D.append(efficiency_AB[-1]+efficiency_BC[-1]+efficiency_AC[-1]-2*efficiency_T[-1])
858
+ efficiency_S.append(pA_single+pB_single+pC_single-efficiency_D[-1]-efficiency_T[-1])
859
+ if Display: print("\t Summary of TDCR measurement")
860
+ if Display: print("\t\t Free parameter PMT A: ", L[0], "keV-1")
861
+ if Display: print("\t\t Free parameter PMT B: ", L[1], "keV-1")
862
+ if Display: print("\t\t Free parameter PMT C: ", L[2], "keV-1")
863
+ if Display: print("\t\t Efficiency of single events: ", round(efficiency_S[-1],5))
864
+ if Display: print("\t\t Efficiency of double events: ", round(efficiency_D[-1],5))
865
+ if Display: print("\t\t Efficiency of triple events: ", round(efficiency_T[-1],5))
866
+
867
+ '''
868
+ ====================
869
+ VI. CALCULATION OF THE FINAL ESTIMATORS
870
+ ====================
871
+ '''
872
+ mean_efficiency_T = np.mean(efficiency_T) # average
873
+ std_efficiency_T = np.std(efficiency_T)/np.sqrt(N) # standard deviation
874
+ std_efficiency_T = np.sqrt(std_efficiency_T**2+1e-8) # combined with uncertainty due to quenching calculation
875
+ mean_efficiency_D = np.mean(efficiency_D)
876
+ std_efficiency_D = np.std(efficiency_D)/np.sqrt(N)
877
+ std_efficiency_D = np.sqrt(std_efficiency_D**2+1e-8)
878
+ mean_efficiency_S = np.mean(efficiency_S)
879
+ std_efficiency_S = np.std(efficiency_S)/np.sqrt(N)
880
+ std_efficiency_S = np.sqrt(std_efficiency_S**2+1e-8)
881
+ if mode2=="sym":
882
+ TDCR_calcul = mean_efficiency_T/mean_efficiency_D
883
+ elif mode2=="asym":
884
+ mean_efficiency_AB = np.mean(efficiency_AB)
885
+ std_efficiency_AB = np.std(efficiency_AB)/np.sqrt(N)
886
+ mean_efficiency_BC = np.mean(efficiency_BC)
887
+ std_efficiency_BC = np.std(efficiency_BC)/np.sqrt(N)
888
+ mean_efficiency_AC = np.mean(efficiency_AC)
889
+ std_efficiency_AC = np.std(efficiency_AC)/np.sqrt(N)
890
+ TDCR_calcul = mean_efficiency_T/mean_efficiency_D
891
+ TABmodel = mean_efficiency_T/mean_efficiency_AB
892
+ TBCmodel = mean_efficiency_T/mean_efficiency_BC
893
+ TACmodel = mean_efficiency_T/mean_efficiency_AC
894
+
895
+
896
+ # x = np.arange(np.mean(efficiency_T),1.001,0.001)
897
+ # plt.figure("efficiency distribution")
898
+ # plt.clf()
899
+ # plt.hist(np.asarray(efficiency_D),bins=x,label="Efficiency of double coincidences")[0]
900
+ # plt.hist(np.asarray(efficiency_T),bins=x,label="Efficiency of triple coincidences")[0]
901
+ # plt.xlabel("Efficiency", fontsize = 14)
902
+ # plt.ylabel(r"Number of counts", fontsize = 14)
903
+ # plt.legend(fontsize = 12)
904
+ # plt.savefig('Effdistribution.png')
905
+
906
+ # x = np.arange(np.mean(tdcr),1.001,0.001)
907
+ # plt.figure("TDCR distribution")
908
+ # plt.clf()
909
+ # plt.hist(np.asarray(tdcr),bins=x,label="Calculated TDCR")[0]
910
+ # plt.plot(x,st.norm.pdf(x, TDCR_measure, u_TDCR_measure),label="measured TDCR")[0]
911
+ # plt.xlabel("Efficiency", fontsize = 14)
912
+ # plt.ylabel(r"Number of counts", fontsize = 14)
913
+ # plt.legend(fontsize = 12)
914
+ # plt.savefig('TDCRdistribution.png')
915
+
916
+ if mode2=="sym":
917
+ res=(TDCR_calcul-TD)**2
918
+ elif mode2=="asym":
919
+ res=(TAB-TABmodel)**2+(TBC-TBCmodel)**2+(TAC-TACmodel)**2
920
+
921
+ if mode == "res":
922
+ return res
923
+ if mode == "eff":
924
+ if N<200:
925
+ print("Warning. too low number of MC trials - inaccurate estimation")
926
+ return mean_efficiency_S, 1, mean_efficiency_D, 1, mean_efficiency_T, 1
927
+ else:
928
+ return mean_efficiency_S, std_efficiency_S, mean_efficiency_D, std_efficiency_D, mean_efficiency_T, std_efficiency_T
929
+ if mode =="dis":
930
+ return efficiency_S, efficiency_D, efficiency_T
931
+
932
+ L = (1, 1, 1)
933
+ TD = 0.977667386529166
934
+ TAB = 0.992232838598821
935
+ TBC = 0.992343419459002
936
+ TAC = 0.99275350064608
937
+ Rad="Cd-109"
938
+ pmf_1="1"
939
+ N = 10
940
+ kB =1.0e-5
941
+ V = 10
942
+ mode = "dis"
943
+ mode2 = "asym"
944
+
945
+
946
+ S,D,T = TDCRPy(L, TD, TAB, TBC, TAC, Rad, pmf_1, N, kB, V, mode, mode2, Display=False, barp=False,uncData=True)