Note
Go to the end to download the full example code.
Examples for error propagation
Hear we use the same config in particle_amplitude.py
9 config_str = """
10 decay:
11 A:
12 - [R1, B]
13 - [R2, C]
14 - [R3, D]
15 R1: [C, D]
16 R2: [B, D]
17 R3: [B, C]
18
19 particle:
20 $top:
21 A: { mass: 1.86, J: 0, P: -1}
22 $finals:
23 B: { mass: 0.494, J: 0, P: -1}
24 C: { mass: 0.139, J: 0, P: -1}
25 D: { mass: 0.139, J: 0, P: -1}
26 R1: [ R1_a, R1_b ]
27 R1_a: { mass: 0.7, width: 0.05, J: 1, P: -1}
28 R1_b: { mass: 0.5, width: 0.05, J: 0, P: +1}
29 R2: { mass: 0.824, width: 0.05, J: 0, P: +1}
30 R3: { mass: 0.824, width: 0.05, J: 0, P: +1}
31
32 """
33
34 import matplotlib.pyplot as plt
35 import yaml
36
37 from tf_pwa.config_loader import ConfigLoader
38 from tf_pwa.histogram import Hist1D
39
40 config = ConfigLoader(yaml.full_load(config_str))
41 input_params = {
42 "A->R1_a.BR1_a->C.D_total_0r": 6.0,
43 "A->R1_b.BR1_b->C.D_total_0r": 1.0,
44 "A->R2.CR2->B.D_total_0r": 2.0,
45 "A->R3.DR3->B.C_total_0r": 1.0,
46 }
47 config.set_params(input_params)
48
49 data = config.generate_toy(1000)
50 phsp = config.generate_phsp(10000)
8.8%[▓▓▓▓>---------------------------------------------] 0.43/4.94s eff: 90.000000%
93.2%[▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓>---] 1.36/1.46s eff: 7.277187%
100.1%[▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓>] 1.80/1.80s eff: 6.216684%
100.0%[▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓] 1.80/1.80s eff: 6.180988%
After we calculated the parameters error, we will have an error matrix config.inv_he (using the inverse hessain).
It is possible to save such matrix directly by numpy.save and to load it by numpy.load.
57 config.get_params_error(data=[data], phsp=[phsp])
Using Model
Time for calculating errors: 0.5375051498413086
/home/docs/checkouts/readthedocs.org/user_builds/tf-pwa/checkouts/stable/docs/../tf_pwa/utils.py:265: UserWarning: matrix is not positive definited
warnings.warn("matrix is not positive definited")
eigvalues: [ 0.03632311 0.01773997 0.01428318 -0.00113541 0.00060804 0.00241579]
DType class corresponding to the scalar type and dtype of the same name.
Please see `numpy.dtype` for the typical way to create
dtype instances and :ref:`arrays.dtypes` for additional
information.
hesse_error: [0.05716870899070608, 0.11223857683598046, 0.10813562180020414, 0.10252326365573486, 0.07774899400317759, 0.1616158633065301]
{'A->R1_b.BR1_b->C.D_total_0r': 0.05716870899070608, 'A->R1_b.BR1_b->C.D_total_0i': 0.11223857683598046, 'A->R2.CR2->B.D_total_0r': 0.10813562180020414, 'A->R2.CR2->B.D_total_0i': 0.10252326365573486, 'A->R3.DR3->B.C_total_0r': 0.07774899400317759, 'A->R3.DR3->B.C_total_0i': 0.1616158633065301}
We can use the following method to profamance the error propagation
by adding some calculation here. We need to use tensorflow functions instead of those of math or numpy.
68 import tensorflow as tf
69
70 with config.params_trans() as pt:
71 a2_r = pt["A->R2.CR2->B.D_total_0r"]
72 a2_i = pt["A->R2.CR2->B.D_total_0r"]
73 a2_x = a2_r * tf.cos(a2_i)
And then we can calculate the error we needed as
78 print(a2_x.numpy(), pt.get_error(a2_x).numpy())
-0.8322936730942848 0.2416551822324546
Uncertainties of fit fractions
We can also calculate some more complex examples, such as the fit fractions of all in C+D.
Even further, we can get the error of error in the meaning of error propagation.
86 amp = config.get_amplitude()
87
88 with config.params_trans() as pt1:
89 with config.params_trans() as pt:
90 int_mc = tf.reduce_sum(amp(phsp))
91 with amp.temp_used_res(["R1_a", "R1_b"]):
92 part_int_mc = tf.reduce_sum(amp(phsp))
93 ratio = part_int_mc / int_mc
94 error = pt.get_error(ratio)
95
96 print(ratio.numpy(), "+/-", error.numpy())
97 print(error.numpy(), "+/-", pt1.get_error(error).numpy())
0.42520552652768934 +/- 0.011657244750159976
0.011657244750159976 +/- 0.0008577773017336707
For large data size it would be some problem named OOM (out of memory).
TFPWA provide vm.batch_sum_var to do sum of large samples
103 int_mc_v = config.vm.batch_sum_var(amp, phsp, batch=5000)
104
105 with amp.temp_used_res(["R1_a", "R1_b"]):
106 part_int_mc_v = config.vm.batch_sum_var(amp, phsp, batch=5000)
It will store the pre-calculated gradients as
111 print(int_mc_v.grad, part_int_mc_v.grad)
tf.Tensor(
[1751674.66853607 -117780.40351603 1359484.69263483 79531.56972059
783486.71769585 10854.12939637], shape=(6,), dtype=float64) tf.Tensor(
[1848665.96791494 -4822.61854968 0. 0.
0. 0. ], shape=(6,), dtype=float64)
Then, we can use it as a function to do error propagation:
116 with config.params_trans() as pt:
117 ratio = part_int_mc_v() / int_mc_v()
118 error = pt.get_error(ratio)
119
120 print(ratio.numpy(), "+/-", error.numpy())
0.42520552652768934 +/- 0.011657244750159973
Besides the error propagation, there would be some additional uncertainties. For example, the uncertainty from the integration sample size is often defined as the sum of square as
126 with amp.temp_used_res(["R1_a", "R1_b"]):
127 int_square = tf.reduce_sum((amp(phsp) / int_mc) ** 2)
128
129 print(ratio.numpy(), "+/-", error.numpy(), "+/-", tf.sqrt(int_square).numpy())
0.42520552652768934 +/- 0.011657244750159973 +/- 0.010392777477148951
Total running time of the script: (0 minutes 3.733 seconds)