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

\[\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_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)

Gallery generated by Sphinx-Gallery