Hyperiso 1.0.3
Modular flavour-physics calculations, Wilson coefficients and statistical inference
Loading...
Searching...
No Matches
ObservableValue.py
Go to the documentation of this file.
1"""Python representation of computed observable values.
2
3The C++ observable layer returns ``ObservableValue`` objects containing an
4observable id, a numerical prediction, and optionally a bin range. This module
5keeps the public Python type lightweight and immutable while preserving explicit
6conversion helpers to and from the bound C++ object.
7"""
8
9from __future__ import annotations
10
11from dataclasses import dataclass
12from typing import Optional, Tuple
13
14from pyhyperiso.phyperiso.pyhyperiso.observable import ObservableValue as _CppObservableValue
15from pyhyperiso.core.Common.GeneralEnum import Observables
16from pyhyperiso.core.Common.Mapper import ObservableMapper
17from pyhyperiso.core.Common.SymbolId import ObservableId
18
19
20def _require_observable_id(value: ObservableId, name: str = "observable id") -> ObservableId:
21 if not isinstance(value, ObservableId):
22 raise TypeError(f"{name} must be un ObservableId Python, received {type(value)!r}.")
23 return value
24
25
26def _cpp_observable_id(value: ObservableId):
27 return _require_observable_id(value)._to_cpp()
28
29
30@dataclass(frozen=True)
32 """Value returned by an observable computation.
33
34 Attributes:
35 id: Internal observable identifier.
36 value: Numerical prediction or experimental value.
37 bin: Optional bin range ``(low, high)``. ``None`` means that the
38 observable is unbinned or that the C++ value did not carry bin
39 information.
40
41 Example:
42 >>> from pyhyperiso.core.BusinessLogic.ObservableValue import ObservableValue
43 >>> from pyhyperiso.core.Common.GeneralEnum import Observables
44 >>> ov = ObservableValue.from_observable(Observables.BR_BS_MUMU, 3.6e-9)
45 >>> ov.value
46 3.6e-09
47 """
48
49 id: ObservableId
50 value: float
51 bin: Optional[Tuple[float, float]] = None
52
53 def __post_init__(self) -> None:
54 """Validate and normalize the immutable dataclass fields.
55
56 Raises:
57 TypeError: If ``id`` is not an ``ObservableId`` or if ``bin`` is
58 neither ``None`` nor a two-entry tuple.
59 """
61 if self.binbin is not None:
62 if not (isinstance(self.binbin, tuple) and len(self.binbin) == 2):
63 raise TypeError("bin must be None ou un tuple (low, high).")
64 object.__setattr__(self, "bin", (float(self.binbin[0]), float(self.binbin[1])))
65 object.__setattr__(self, "value", float(self.valuevalue))
66
67 @classmethod
69 cls,
70 obs: Observables,
71 value: float,
72 bin: Optional[Tuple[float, float]] = None,
73 ) -> "ObservableValue":
74 """Create an observable value from a public observable enum.
75
76 Args:
77 obs: Public observable enum value.
78 value: Numerical value to store.
79 bin: Optional bin range ``(low, high)`` for binned observables.
80
81 Returns:
82 A normalized ``ObservableValue`` instance.
83
84 Raises:
85 TypeError: If ``obs`` is not an ``Observables`` enum value.
86 """
87 if not isinstance(obs, Observables):
88 raise TypeError(f"obs must be un Observables Python, received {type(obs)!r}.")
89 return cls(id=ObservableMapper.to_id(obs), value=float(value), bin=bin)
90
91 @classmethod
92 def from_cpp(cls, cpp_obj) -> "ObservableValue":
93 """Wrap a bound C++ ``ObservableValue`` object.
94
95 Args:
96 cpp_obj: Bound C++ object exposing ``id``, ``value`` and optional
97 ``bin`` fields.
98
99 Returns:
100 Equivalent Python ``ObservableValue`` instance.
101 """
102 py_id = ObservableId(str(cpp_obj.id))
103 b = cpp_obj.bin
104 py_bin = None if b is None else (float(b[0]), float(b[1]))
105 return cls(id=py_id, value=float(cpp_obj.value), bin=py_bin)
106
107 def to_cpp(self):
108 """Convert this value to the bound C++ representation.
109
110 Returns:
111 A C++ ``ObservableValue`` pybind11 object.
112 """
113 cpp_id = _cpp_observable_id(self.idid)
114 if self.binbin is None:
115 return _CppObservableValue(cpp_id, float(self.valuevalue))
116 return _CppObservableValue(cpp_id, float(self.valuevalue), self.binbin)
117
118
119__all__ = [
120 "ObservableValue",
121]
static IdOf< ObservableTag > to_id(Observables e)
Converts an enum value to an IdOf<Tag>.
"ObservableValue" from_observable(cls, Observables obs, float value, Optional[Tuple[float, float]] bin=None)
ObservableId _require_observable_id(ObservableId value, str name="observable id")