Examples for config.yml file

Configuration file config.yml use YAML (https://yaml.org) format to describe decay process.

The main parts of config.yml is decay and particle.

The decay part describe the particle (or an id of a list of particle) decay into which particles, it can be a list of a list of list. A list means that there is ony one decay mode, A list of list is the list of possible decay mode. The list item can be the particle name (or a dict to describe the decay parameters). All name should appear in particle part.

The particle part describe the parameters of particles. There are two special parts $top and $finals describe the top and finals particles. The other parts are lists of particle name or dicts of particle parameters. The list is the same type particle in decay part. The dict is the parameters of the particle name.

22 config_str = """
23
24 decay:
25     A:
26        - [R1, B]
27        - [R2, C]
28        - [R3, D]
29     R1: [C, D]
30     R2: [B, D]
31     R3: [B, C]
32
33 particle:
34     $top:
35        A: { mass: 1.86, J: 0, P: -1}
36     $finals:
37        B: { mass: 0.494, J: 0, P: -1}
38        C: { mass: 0.139, J: 0, P: -1}
39        D: { mass: 0.139, J: 0, P: -1}
40     R1: [ R1_a, R1_b ]
41     R1_a: { mass: 0.7, width: 0.05, J: 1, P: -1}
42     R1_b: { mass: 0.5, width: 0.05, J: 0, P: +1}
43     R2: { mass: 0.824, width: 0.05, J: 0, P: +1}
44     R3: { mass: 0.824, width: 0.05, J: 0, P: +1}
45
46 """

The config file can be loaded by yaml library.

52 import matplotlib.pyplot as plt
53 import yaml
54
55 from tf_pwa.config_loader import ConfigLoader
56 from tf_pwa.histogram import Hist1D

The simple way to create config is write it to config.yml file and then you can load it as config = ConfigLoader("config.yml"). Here we used config_str directly.

64 config = ConfigLoader(yaml.full_load(config_str))

We set parameters to a blance value. And we can generate some toy data and calclute the weights The full params can be found by print(config.get_params()).

71 input_params = {
72     "A->R1_a.BR1_a->C.D_total_0r": 6.0,
73     "A->R1_b.BR1_b->C.D_total_0r": 1.0,
74     "A->R2.CR2->B.D_total_0r": 2.0,
75     "A->R3.DR3->B.C_total_0r": 1.0,
76 }
77 config.set_params(input_params)
True

Here we generate some toy data and phsp mc to show the model

82 data = config.generate_toy(1000)
83 phsp = config.generate_phsp(10000)
9.1%[▓▓▓▓>---------------------------------------------] 0.41/4.55s eff: 90.000000%
56.2%[▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓>---------------------] 1.15/2.04s eff: 7.522486%
102.0%[▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓>] 1.76/1.72s eff: 3.878746%
100.0%[▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓] 1.76/1.76s  eff: 3.790466%

You can also fit the data fit to the data We can omit the args when writen in config.yml

90 fit_result = config.fit([data], [phsp])
91 # After the fit, you can get the uncertaities as
92 err = config.get_params_error(fit_result, [data], [phsp])
Using Model
decay chains included:
   [A->R1_a+B, R1_a->C+D]  ls:  ((1, 1),) ((1, 0),)
   [A->R1_b+B, R1_b->C+D]  ls:  ((0, 0),) ((0, 0),)
   [A->R2+C, R2->B+D]  ls:  ((0, 0),) ((0, 0),)
   [A->R3+D, R3->B+C]  ls:  ((0, 0),) ((0, 0),)

########### initial parameters
{
  "R1_a_mass": 0.7,
  "R1_a_width": 0.05,
  "R1_b_mass": 0.5,
  "R1_b_width": 0.05,
  "R2_mass": 0.824,
  "R2_width": 0.05,
  "R3_mass": 0.824,
  "R3_width": 0.05,
  "A->R1_a.BR1_a->C.D_total_0r": 6.0,
  "A->R1_a.BR1_a->C.D_total_0i": 0.0,
  "A->R1_a.B_g_ls_0r": 1.0,
  "A->R1_a.B_g_ls_0i": 0.0,
  "R1_a->C.D_g_ls_0r": 1.0,
  "R1_a->C.D_g_ls_0i": 0.0,
  "A->R1_b.BR1_b->C.D_total_0r": 1.0,
  "A->R1_b.BR1_b->C.D_total_0i": 2.0118377772474645,
  "A->R1_b.B_g_ls_0r": 1.0,
  "A->R1_b.B_g_ls_0i": 0.0,
  "R1_b->C.D_g_ls_0r": 1.0,
  "R1_b->C.D_g_ls_0i": 0.0,
  "A->R2.CR2->B.D_total_0r": 2.0,
  "A->R2.CR2->B.D_total_0i": 2.0687057121861594,
  "A->R2.C_g_ls_0r": 1.0,
  "A->R2.C_g_ls_0i": 0.0,
  "R2->B.D_g_ls_0r": 1.0,
  "R2->B.D_g_ls_0i": 0.0,
  "A->R3.DR3->B.C_total_0r": 1.0,
  "A->R3.DR3->B.C_total_0i": -3.1213519850281184,
  "A->R3.D_g_ls_0r": 1.0,
  "A->R3.D_g_ls_0i": 0.0,
  "R3->B.C_g_ls_0r": 1.0,
  "R3->B.C_g_ls_0i": 0.0
}
initial NLL:  tf.Tensor(-783.2149247715024, shape=(), dtype=float64)
nll_grad  cost time: 0.2186119556427002
nll_grad  cost time: 0.21996760368347168
nll_grad  cost time: 0.2197856903076172
tf.Tensor(-785.0202945529009, shape=(), dtype=float64)
nll_grad  cost time: 0.2186124324798584
nll_grad  cost time: 0.21710896492004395
tf.Tensor(-785.4400439333403, shape=(), dtype=float64)
nll_grad  cost time: 0.2188405990600586
tf.Tensor(-786.0021972742334, shape=(), dtype=float64)
nll_grad  cost time: 0.22063493728637695
nll_grad  cost time: 0.2196054458618164
tf.Tensor(-786.0200308168432, shape=(), dtype=float64)
nll_grad  cost time: 0.2187347412109375
nll_grad  cost time: 0.21707916259765625
tf.Tensor(-786.0246339350379, shape=(), dtype=float64)
nll_grad  cost time: 0.21822786331176758
tf.Tensor(-786.0307638418062, shape=(), dtype=float64)
nll_grad  cost time: 0.22521114349365234
nll_grad  cost time: 0.2205202579498291
tf.Tensor(-786.0790680504488, shape=(), dtype=float64)
nll_grad  cost time: 0.21915364265441895
tf.Tensor(-786.1021691437363, shape=(), dtype=float64)
nll_grad  cost time: 0.22006487846374512
tf.Tensor(-786.1021915235533, shape=(), dtype=float64)
nll_grad  cost time: 0.22339105606079102
tf.Tensor(-786.1021916581713, shape=(), dtype=float64)
Optimization terminated successfully.
         Current function value: -786.102192
         Iterations: 10
         Function evaluations: 16
         Gradient evaluations: 16
  message: Optimization terminated successfully.
  success: True
   status: 0
      fun: -786.1021916581713
        x: [ 1.115e+00  1.980e+00  2.104e+00  2.047e+00  1.149e+00
            -3.225e+00]
      nit: 10
      jac: [-5.619e-04 -1.478e-04  5.700e-04  1.293e-04 -5.181e-04
             6.854e-06]
 hess_inv: [[ 6.462e-03 -3.777e-04 ...  5.372e-03 -2.184e-04]
            [-3.777e-04  1.246e-02 ...  1.511e-04  3.959e-03]
            ...
            [ 5.372e-03  1.511e-04 ...  8.298e-03 -5.152e-06]
            [-2.184e-04  3.959e-03 ... -5.152e-06  1.525e-02]]
     nfev: 16
     njev: 16
fit  cost time: 3.756481409072876
Using Model
Time for calculating errors: 0.5266296863555908
hesse_error: [0.08131388704490601, 0.11283119287945828, 0.14281744560172993, 0.10741827581192308, 0.09324334155826125, 0.12455274069341889]

we can see that thre fit results consistant with inputs, the first one is fixed.

 97 for var in input_params:
 98     print(
 99         f"in: {input_params[var]} => out: {fit_result.params[var]} +/- {err.get(var, 0.)}"
100     )
in: 6.0 => out: 6.0 +/- 0.0
in: 1.0 => out: 1.1151145388492583 +/- 0.08131388704490601
in: 2.0 => out: 2.104457026741137 +/- 0.14281744560172993
in: 1.0 => out: 1.1487910799207282 +/- 0.09324334155826125

We can use the amplitude to plot the fit results

105 amp = config.get_amplitude()

This is the total \(|A|^2\)

110 weight = amp(phsp)

This is the \(|A_i|^2\) for each decay chain

We can plot the data, Hist1D include some plot method base on matplotlib.

120 data_hist = Hist1D.histogram(
121     data.get_mass("(C, D)"), bins=60, range=(0.25, 1.45)
122 )

Read the mass var from phsp.

127 mass_phsp = phsp.get_mass("(C, D)")

For helicity angle it can be read as phsp.get_angle("(C, D)", "C") The first arg is used to deteminate the decay chain. (decay chain include all particles) The second arg is used to deteminate the angle in decay chain. The return value is a dict as {"alpha": phi, "beta": theta, "gamma": 0}

136 phsp_hist = Hist1D.histogram(
137     mass_phsp, weights=weight, bins=60, range=(0.25, 1.45)
138 )
139 scale = phsp_hist.scale_to(data_hist)
140
141 pw_hist = []
142 for w in partial_weight:
143     # here we used more bins for a smooth plot
144     hist = Hist1D.histogram(
145         mass_phsp, weights=w, bins=60 * 2, range=(0.25, 1.45)
146     )
147     pw_hist.append(scale * hist * 2)

Then we can plot the histogram into matplotlib

152 for hist, dec in zip(pw_hist, config.get_decay()):
153     hist.draw_kde(label=str(dec))
154 phsp_hist.draw(label="total amplitude")
155 data_hist.draw_error(label="toy data", color="black")
156
157 plt.legend()
158 plt.ylim((0, None))
159 plt.xlabel("M(CD)/ GeV")
160 plt.ylabel("Events/ 20 MeV")
161 plt.show()
ex3 particle config

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

Gallery generated by Sphinx-Gallery