Skip to content

SMEFT + SM fits with low-energy observables - #146

Draft
ElieHammou wants to merge 7 commits into
mainfrom
lowE_observables
Draft

SMEFT + SM fits with low-energy observables#146
ElieHammou wants to merge 7 commits into
mainfrom
lowE_observables

Conversation

@ElieHammou

Copy link
Copy Markdown
Collaborator

PR for ongoing project with Juan and Kamil

Adding superallowed betadecays as an analytical external likelihood. It depends both on LEFT parameters as well as on SM ones (Vud).

Assuming that the other SMEFiT datasets do not depend on the SM, one can easily fit SMEFT+SM simultaneously.

It also contains an implementation of nuisance parameters relying a predefined gaussian constraints.

Copilot AI review requested due to automatic review settings May 26, 2026 12:36
@ElieHammou
ElieHammou marked this pull request as draft May 26, 2026 12:36

Copilot AI left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull request overview

Adds a new external likelihood for superallowed beta decays intended to enable simultaneous fits of SMEFT coefficients together with selected SM/nuisance parameters (e.g., (V_{ud})), using an analytic Jacobian from rgevolve plus optional Gaussian constraints.

Changes:

  • Introduces BetaDecayChi2RGevolve external (\chi^2) implementation using rgevolve to compute an analytic SMEFT→WET linear response.
  • Adds standalone Gaussian-constraint external (\chi^2) terms for DRV, eta2, eta3, and (V_{ud}).
  • Provides an example runcard wiring the beta-decay likelihood + constraints into a combined SM+SMEFT fit.

Reviewed changes

Copilot reviewed 3 out of 3 changed files in this pull request and generated 7 comments.

File Description
external_chi2/beta_decays/example_runcard_beta_decays_sm_smeft.yaml Example configuration for running a combined SM+SMEFT fit including beta-decay external likelihood and Gaussian constraints.
external_chi2/beta_decays/beta_decays.py Implements beta-decay external (\chi^2) using rgevolve to precompute an analytic Jacobian for a linearized SMEFT dependence.
external_chi2/beta_decays/beta_decays_gaussian_nuisance.py Implements Gaussian prior penalty terms as separate external (\chi^2) components for nuisance/SM parameters.

💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.

Comment thread external_chi2/beta_decays/example_runcard_beta_decays_sm_smeft.yaml Outdated
Comment on lines +45 to +52
import jax.numpy as jnp
from smefit.rge import RGE
from rgevolve.tools.functions import run_and_match, get_wc_basis

jax.config.update("jax_enable_x64", True)

# Experimental Ft values and 1-sigma uncertainties from 2010.13797 (in units of 10^-3 s)
_EXP_MEAN = jnp.array(
Comment on lines +185 to +193
elif coeff.expr is not None and coeff.vars:
for var in coeff.vars:
if var not in self._free_smeft_names:
continue
local = {v: (1.0 if v == var else 0.0) for v in coeff.vars}
try:
factor = float(eval(coeff.expr, {"__builtins__": {}}, local))
except Exception:
factor = 1.0
Comment on lines +189 to +197
local = {v: (1.0 if v == var else 0.0) for v in coeff.vars}
try:
factor = float(eval(coeff.expr, {"__builtins__": {}}, local))
except Exception:
factor = 1.0
for k, v in contrib.items():
self._eff_translation[var][k] = (
self._eff_translation[var].get(k, 0.0) + factor * v
)
Comment on lines +125 to +132
class BetaDecayChi2RGevolve:
"""SMEFiT external chi2 for superallowed beta decays — rgevolve Jacobian.

The Jacobian dL/dc_i is computed analytically at initialisation via
rgevolve.tools.functions.run_and_match, with no Wilson calls at any stage.
The chi2 is then a pure JAX linear function of the free parameters, identical
in form to BetaDecayChi2Linear but using rgevolve-derived derivatives.
"""
Comment thread external_chi2/beta_decays/beta_decays_gaussian_nuisance.py Outdated
Comment on lines +56 to +67
def __init__(self, coefficients, rge_dict=None, central=None, sigma=None, **_):
free_names = list(coefficients.free_names)
self._idx = free_names.index(self._param_name) if self._param_name in free_names else None
self._central = jnp.float64(float(central if central is not None else self._default_central))
self._sigma = jnp.float64(float(sigma if sigma is not None else self._default_sigma))
self.num_data = 1

def compute_chi2(self, coefficient_values):
if self._idx is None:
return jnp.float64(0.0)
val = jnp.asarray(coefficient_values, dtype=jnp.float64)[self._idx]
return ((val - self._central) / self._sigma) ** 2
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants