Defining Observables
A user can define new observables for their analyses by combining existing observables, parameters, and kinematic variables within an arithmetic expression. Observables defined in this way benefit from the same optimizations as all built-in observables, including multi-threaded evaluation and caching. This section describes and exemplifies the syntax of the expression parser that interprets user defined python strings as new EOS observables.
Syntax
Arithmetic Expressions
Basic rules are used to parse the input string
Whitespaces such as spaces and tabs do not have semantic meaning and are ignored when parsing the expression. Hence, they can be added arbitrarily for readability.
Expressions are built upon the arithmetic operations
addition
+,subtraction
-,multiplication
*,division
/,and exponentiation
^.Parentheses are recognized in expressions, and the usual precedence rules of arithmetics apply.
Expressions can call the functions
exp,log,sin,cos,atan, andtheta, the Heaviside step function withtheta(0) = 1. The resolution kernelsKernel::Gaussian(u, mu, sigma)andKernel::CrystalBall(u, mu, sigma, alpha_L, n_L, alpha_R, n_R)are densities of unit area in their first argumentu. The latter is a Gaussian core with power-law tails beyond-alpha_Landalpha_Rstandard deviations, of powersn_Landn_R, which must exceed one.Expressions can refer to existing EOS objects
Observables are referenced by their
eos.QualifiedNameand must be encapsulated by two chevrons:<<...>>. All features of a qualified name are supported, including specifying option. Examples for a reference to an observable are<<B_u->lnu::BR>>and<<B->Kll::dBR/dq2;q=u>>.Parameters are also referenced by their
eos.QualifiedName, but these must be enclosed in square brackets:[[...]]. For example,[[mass::mu]]is a valid expression.Expressions usually depend on kinematic variables. These variables are implicitly inherited from the called observables (see the following section for details), but inherited and new kinematic variables can also be explicitly used in the expression. In this case, the name of the variable must be enclosed in braces:
{...}. Examples of a kinematic variable are{q2}or{E_gamma}.
The following strings are valid observable expressions
([[mass::B_d]]^2 - 4 * [[mass::mu]]^2) ^ 0.5
1.0 / <<B_u->lnu::BR;l=mu>>
<<B->K::f_+(q2)>> * (1 - {q2} / [[mass::B_d^*]]^2)
Dealing with Kinematic Variables
By default, a referenced observable’s dependence on a kinematic variables is transferred to the newly defined observable.
For example, the observable defined by the expression 1.0 / <<B->pilnu::dBR/dq2>> depends on the kinematic variable
q2, since the reference observable B->pilnu::dBR/dq2 does.
When more than one observable appears in the expression, it is sometimes useful or even essential to rename kinematic variables,
i.e., create an alias for the name of the kinematic variable.
For example, when defining a lepton-flavour universality observable such as the ratio of branching fractions <<B->Dlnu::BR;l=tau>> / <<B->Dlnu::BR;l=mu>>,
the kinematic variable q2 should be renamed to q2_tau and q2_mu for the two observables, respectively, to avoid any ambiguity.
Moreover, phenomenological application sometimes involve the evaluation of an observable at a fixed value of a kinematic variable,
or as a function of a different kinematic variable.
All of these modifications to the kinematic variables of a referenced observable are supported.
They are achieved by appending a kinematic specification to the reference of an EOS observable: <<...>>[...].
Three types of kinematics specification are supported
the
=>operator renames the kinematic variable on its left-hand side to the name on its right-hand side. For example, the expression<<B_u->lnu::BR@l=mu>>[q2=>q2_mu] / <<B_u->lnu::BR@l=e>>[q2=>q2_e]expects two kinematic variable:q2_muandq2_e. The value of the former is only used in the evaluation of the numerator; the value of the latter is only used in the evaluation of the denominator.the
=operator fixes a kinematic variable to a given value. For example, the expression<<B->pilnu::BR>>[q2_min=0.1]expects only one kinematic variableq2_max. The kinematic variableq2_minthat the references observableB->pilnu::BRalso depends on is fixed to the value0.1. The same kinematic variable can be set to different values in a single expression, i.e.<<B->pi::f_+(q2)>>[q2=1.0] + <<B->pi::f_0(q2)>>[q2=2.0]is also a valid expression.the
=operator followed by an expression substitutes a kinematic variable by a function of other kinematic variables. For example, the expression<<B->pi::f_+(q2)>>[q2={m}^2]expects only one kinematic variablem, and evaluates the form factor atq2equal to the square ofm. The expression on the right-hand side of=may only contain kinematic variables, constants, and functions; parameters and observables are rejected. The kinematic variables in this expression are those of the newly defined observable, not those of the referenced observable. For example, in<<B->pi::f_+(q2)>>[q2=2 * {q2}], theq2on the left-hand side of=is the kinematic variable of the form factor, while the{q2}on the right-hand side is the kinematic variable of the newly defined observable. This expression therefore evaluates the form factor at twice the value of the new observable’sq2.
Note that all types of specifications can be combined in comma-separated list in an arbitrary order, for example [q2_min=1.0,q2_max=>q2_max_mu].
A kinematic specification applies even if the kinematic variables of the newly defined observable include a variable of the same name.
For example, the expression <<B->pi::f_+(q2)>> / <<B->pi::f_+(q2)>>[q2=0.0] depends on q2 through its numerator only.
A substitution changes the variable, but not the measure of a density.
For example, to express the differential branching ratio of \(B\to K\mu^+\mu^-\) in the dilepton mass m_ll, the Jacobian must
be included explicitly: <<B->Kll::dBR/ds;l=mu>>[q2={m_ll}^2] * 2 * {m_ll}.
Note also that the references to observables can be nested: an observable defined by an expression can itself be referenced in a further expression.
In that case, the kinematic specification of the outer reference must not rename, fix, or substitute a kinematic variable that the expression of the inner observable already renames, fixes, or substitutes.
For example, if ex::f(q2=1) is defined by the expression <<B->pi::f_+(q2)>>[q2=1.0], then neither <<ex::f(q2=1)>>[q2=>q2_e]
nor <<ex::f(q2=1)>>[q2=2.0] is supported; making an observable from either expression raises an error.
Making a new Observable known
To make a new observable known to EOS, it must be added to the list of observables.
This can be done using the eos.Observables.insert() method.
eos.Observables().insert(name, latex, unit, options, expression)
Here the arguments name, latex and unit are the qualified name, the latex representation, and the unit of the new observable, respectively.
For the list of valid units, see here.
The argument options takes an eos.Options object and allows to specify global options (i.e. applied to all observables in the expression),
for the newly defined observable.
The argument expression is Python string that is parsed as described above.
We conclude with a concrete example for the definition of the lepton-flavour universality observable \(R_K\):
eos.Observables().insert('B->Kll::R_K_example', R'(R_K)', eos.Unit.Unity(), eos.Options(),
'( <<B->Kll::BR;l=mu>>[q2_max=6, q2_min=>q2_mu_min] / <<B->Kll::BR;l=e>>[q2_max=6,q2_min=>q2_e_min] )')
R_K = eos.Observable.make('B->Kll::R_K_example', eos.Parameters.Defaults(), eos.Kinematics(q2_e_min=1.1, q2_mu_min=1.1), eos.Options(**{'tag':'BFS2004'}))
R_K.evaluate() # should yield ~1