Examples for error propagation

Here we use the same config in ex3_particle_config.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)
6.9%[▓▓▓>----------------------------------------------] 0.42/6.03s eff: 90.000000%
90.0%[▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓>----] 1.30/1.45s eff: 5.723630%
101.8%[▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓>] 1.74/1.71s eff: 4.713576%
100.0%[▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓] 1.74/1.74s  eff: 4.751026%

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.5463066101074219
hesse_error: [0.05889069640666947, 0.13124507146345105, 0.12084210165259626, 0.11073069472327886, 0.07242484195484554, 0.13930833090883138]

{'A->R1_b.BR1_b->C.D_total_0r': 0.05889069640666947, 'A->R1_b.BR1_b->C.D_total_0i': 0.13124507146345105, 'A->R2.CR2->B.D_total_0r': 0.12084210165259626, 'A->R2.CR2->B.D_total_0i': 0.11073069472327886, 'A->R3.DR3->B.C_total_0r': 0.07242484195484554, 'A->R3.DR3->B.C_total_0i': 0.13930833090883138}

We can use the following method to profamance the error propagation

\[\sigma_{f} = \sqrt{\frac{\partial f}{\partial x_i} V_{ij} \frac{\partial f}{\partial x_j }}\]

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_0i"]
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())
-1.9349672615108753 0.12317099449347577

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 pt:
89     int_mc = tf.reduce_sum(amp(phsp))
90     with amp.temp_used_res(["R1_a", "R1_b"]):
91         part_int_mc = tf.reduce_sum(amp(phsp))
92     ratio = part_int_mc / int_mc
93 error = pt.get_error(ratio)
94
95 print(ratio.numpy(), "+/-", error.numpy())
0.4337630598756568 +/- 0.018905619798362056

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

101 int_mc_v = config.vm.batch_sum_var(amp, phsp, batch=5000)
102
103 with amp.temp_used_res(["R1_a", "R1_b"]):
104     part_int_mc_v = config.vm.batch_sum_var(amp, phsp, batch=5000)

It will store the pre-calculated gradients as

109 print(int_mc_v.grad, part_int_mc_v.grad)
tf.Tensor(
[1625038.98645163   52488.47002723 1512848.13524342   85143.66309983
  655538.1070127   -32685.64757322], shape=(6,), dtype=float64) tf.Tensor(
[1837597.5663628   13221.3329254       0.              0.
       0.              0.       ], shape=(6,), dtype=float64)

Then, we can use it as a function to do error propagation:

114 with config.params_trans() as pt:
115     ratio = part_int_mc_v() / int_mc_v()
116 error = pt.get_error(ratio)
117
118 print(ratio.numpy(), "+/-", error.numpy())
0.4337630598756568 +/- 0.01890561979836206

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

124 with amp.temp_used_res(["R1_a", "R1_b"]):
125     int_square = tf.reduce_sum((amp(phsp) / int_mc) ** 2)
126
127 print(ratio.numpy(), "+/-", error.numpy(), "+/-", tf.sqrt(int_square).numpy())
0.4337630598756568 +/- 0.01890561979836206 +/- 0.01067521523788381

Total running time of the script: (0 minutes 3.480 seconds)

Gallery generated by Sphinx-Gallery