diff --git a/Hlt/Hlt2Conf/python/Hlt2Conf/lines/rd/__init__.py b/Hlt/Hlt2Conf/python/Hlt2Conf/lines/rd/__init__.py
index 9d62208085f7fb562a1cadb57d5ca29907798d63..a6bd8e46693cd3fa3088af21eaccaf01dddf794a 100644
--- a/Hlt/Hlt2Conf/python/Hlt2Conf/lines/rd/__init__.py
+++ b/Hlt/Hlt2Conf/python/Hlt2Conf/lines/rd/__init__.py
@@ -16,6 +16,8 @@ from . import b_to_hhgamma_gamma_to_ee
 from . import b_to_hhhgamma
 from . import b_to_hhhgamma_gamma_to_ee
 from . import B2ll_lines
+from . import qqbar_to_emu
+from . import upsilon_to_ll
 from .strange import all_lines as strange_lines
 
 # provide "all_lines" for correct registration by the overall HLT2 lines module
@@ -24,5 +26,7 @@ all_lines.update(b_to_hhgamma.all_lines)
 all_lines.update(b_to_hhgamma_gamma_to_ee.all_lines)
 all_lines.update(b_to_hhhgamma.all_lines)
 all_lines.update(b_to_hhhgamma_gamma_to_ee.all_lines)
+all_lines.update(qqbar_to_emu.all_lines)
 all_lines.update(B2ll_lines.all_lines)
 all_lines.update(strange_lines)
+all_lines.update(upsilon_to_ll.all_lines)
diff --git a/Hlt/Hlt2Conf/python/Hlt2Conf/lines/rd/builders/qqbar_builder.py b/Hlt/Hlt2Conf/python/Hlt2Conf/lines/rd/builders/qqbar_builder.py
new file mode 100644
index 0000000000000000000000000000000000000000..4b104337f032268c82edf412dfd5fa460e27ccb4
--- /dev/null
+++ b/Hlt/Hlt2Conf/python/Hlt2Conf/lines/rd/builders/qqbar_builder.py
@@ -0,0 +1,457 @@
+##############################################################################
+# (c) Copyright 2022 CERN for the benefit of the LHCb Collaboration           #
+#                                                                             #
+# This software is distributed under the terms of the GNU General Public      #
+# Licence version 3 (GPL Version 3), copied verbatim in the file "COPYING".   #
+#                                                                             #
+# In applying this licence, CERN does not waive the privileges and immunities #
+# granted to it by virtue of its status as an Intergovernmental Organization  #
+# or submit itself to any jurisdiction.                                       #
+###############################################################################
+"""
+Definiton of dedicated prompt builders for LFV lines of qqbar -> emu (detached lines are using standard make_rd_detached_mue)
+- Phi(1020) -> E Mu + SS prompt
+- J/Psi(1S) -> E Mu + SS prompt
+- Upsilon(1S) -> E Mu + SS
+
+author: Miroslav Saur
+date: 27.12.2021
+
+"""
+
+import Functors as F
+from Functors.math import in_range
+
+from GaudiKernel.SystemOfUnits import MeV, GeV
+
+from RecoConf.reconstruction_objects import make_pvs_v2 as make_pvs
+
+from Hlt2Conf.algorithms_thor import require_all, ParticleFilter
+from PyConf import configurable
+from Hlt2Conf.algorithms import ParticleCombinerWithPVs
+from Hlt2Conf.lines.rd.builders.rdbuilder_thor import make_rd_tauons_hadronic_decay
+
+from Hlt2Conf.standard_particles import (
+    make_detached_mue_with_brem,
+    make_detached_dielectron_with_brem,
+    make_detached_mumu,
+    make_long_electrons_with_brem,
+    make_ismuon_long_muon,
+)
+
+
+# filter based on the rd_detached_mue / make_detached_mue_with_brem with zero cuts on IP and added combination cuts
+@configurable
+def make_prompt_mue(
+    name="prompt_mue_builder",
+    min_dilepton_mass=0.0 * MeV,
+    max_dilepton_mass=6000.0 * MeV,
+    min_dilepton_pt=1.0 * GeV,
+    max_ipchi2_mue=50,
+    parent_id="J/psi(1S)",
+    min_probnn_mu=0.0,
+    min_PIDmu=0.0,
+    IsMuon=True,
+    min_PIDe=2.0,
+    min_pt_e=0.5 * GeV,
+    min_pt_mu=0.5 * GeV,
+    minipchi2=0,  # must be 0 for a prompt builder
+    min_bpvvdchi2=0.0,  # must be 0 for a prompt builder
+    max_vchi2ndof=10.0,
+    max_trghostprob=0.2,
+    same_sign=False,
+):
+    """
+    Make the detached muon-electron pair, opposite-sign or same-sign.
+    """
+    pvs = make_pvs()
+    dileptons = make_detached_mue_with_brem(
+        dilepton_ID=parent_id,
+        min_probnn_mu=min_probnn_mu,
+        min_PIDmu=0.0,
+        IsMuon=IsMuon,
+        min_PIDe=min_PIDe,
+        same_sign=same_sign,
+        min_pt_e=min_pt_e,
+        min_pt_mu=min_pt_mu,
+        minipchi2_track=minipchi2,
+        min_bpvvdchi2=min_bpvvdchi2,
+        max_vchi2ndof=max_vchi2ndof,
+        max_trghostprob=max_trghostprob,
+    )
+    code = require_all(
+        in_range(min_dilepton_mass, F.MASS, max_dilepton_mass),
+        F.PT > min_dilepton_pt,
+        F.BPVIPCHI2(pvs) < max_ipchi2_mue,
+    )
+    return ParticleFilter(dileptons, F.FILTER(code), name=name)
+
+
+@configurable
+def make_prompt_etau(
+    name="prompt_mue_builder",
+    min_dilepton_mass=7000.0 * MeV,
+    max_dilepton_mass=13000.0 * MeV,
+    min_dilepton_pt=1.0 * GeV,
+    max_ipchi2_etau=50,
+    parent_id="Upsilon(1S)",
+    min_PIDe=2.0,
+    max_adocachi2=30.0,
+    min_pt_e=0.5 * GeV,
+    min_pt_tau=0.3 * GeV,
+    minipchi2=0,  # must be 0 for a prompt builder
+    min_bpvvdchi2=0.0,  # must be 0 for a prompt builder
+    max_vchi2ndof=10.0,
+):
+    """
+    Make the detached electron-tau pair, opposite-sign for now.
+    """
+    pvs = make_pvs()
+    descriptor = "[{} -> e+ tau-]cc".format(parent_id)
+    taus = make_rd_tauons_hadronic_decay(
+        best_pi_ipchi2_min=minipchi2
+    )  # Make them prompt(?)
+    electrons = make_long_electrons_with_brem()
+    daughters_code = {
+        "tau+": f"(PT > {min_pt_tau}) & (MIPCHI2DV(PRIMARY) > {minipchi2})",  # Do we need to add a minipchi2 to the taus also for promptness?
+        "tau-": f"(PT > {min_pt_tau}) & (MIPCHI2DV(PRIMARY) > {minipchi2})",
+        "e+": f"(PIDe > {min_PIDe}) & (PT > {min_pt_e}) & (MIPCHI2DV(PRIMARY) > {minipchi2})",
+        "e-": f"(PIDe > {min_PIDe}) & (PT > {min_pt_e}) & (MIPCHI2DV(PRIMARY) > {minipchi2})",
+    }
+    combination_code = f"ADOCACHI2CUT({max_adocachi2}, '')"
+    vertex_code = (
+        f"(VFASPF(VCHI2/VDOF) < {max_vchi2ndof}) & (BPVVDCHI2() > {min_bpvvdchi2})"
+    )
+    etau = ParticleCombinerWithPVs(
+        particles=[electrons, taus],
+        pvs=pvs,
+        DaughtersCuts=daughters_code,
+        DecayDescriptor=descriptor,
+        CombinationCut=combination_code,
+        MotherCut=vertex_code,
+    )
+    code = require_all(
+        in_range(min_dilepton_mass, F.MASS, max_dilepton_mass),
+        F.PT > min_dilepton_pt,
+        F.BPVIPCHI2(pvs) < max_ipchi2_etau,
+    )
+    return ParticleFilter(etau, F.FILTER(code), name=name)
+
+
+@configurable
+def make_prompt_mutau(
+    name="prompt_mue_builder",
+    min_dilepton_mass=7000.0 * MeV,
+    max_dilepton_mass=13000.0 * MeV,
+    min_dilepton_pt=1.0 * GeV,
+    max_ipchi2_mutau=50,
+    parent_id="Upsilon(1S)",
+    min_probnn_mu=0.2,
+    min_PIDmu=0.0,
+    IsMuon=False,
+    min_pt_mu=0.0 * GeV,
+    max_adocachi2=30.0,
+    min_pt_tau=0.3 * GeV,
+    minipchi2=0,  # must be 0 for a prompt builder
+    min_bpvvdchi2=0.0,  # must be 0 for a prompt builder
+    max_vchi2ndof=10.0,
+):
+    """
+    Make the detached electron-tau pair, opposite-sign for now.
+    """
+    pvs = make_pvs()
+    descriptor = "[{} -> mu+ tau-]cc".format(parent_id)
+    taus = make_rd_tauons_hadronic_decay(
+        best_pi_ipchi2_min=minipchi2
+    )  # Make them prompt(?)
+    muons = make_ismuon_long_muon()
+    daughters_code = {
+        "tau+": f"(PT > {min_pt_tau}) & (MIPCHI2DV(PRIMARY) > {minipchi2})",  # Do we need to add a minipchi2 to the taus also for promptness?
+        "tau-": f"(PT > {min_pt_tau}) & (MIPCHI2DV(PRIMARY) > {minipchi2})",
+        "mu+": f"(PROBNNmu > {min_probnn_mu}) & (PIDmu > {min_PIDmu}) & (PT > {min_pt_mu}) & (MIPCHI2DV(PRIMARY) > {minipchi2})",
+        "mu-": f"(PROBNNmu > {min_probnn_mu}) & (PIDmu > {min_PIDmu}) & (PT > {min_pt_mu}) & (MIPCHI2DV(PRIMARY) > {minipchi2})",
+    }
+    if IsMuon:
+        daughters_code["mu+"] = daughters_code["mu+"] + " & ISMUON"
+        daughters_code["mu-"] = daughters_code["mu-"] + " & ISMUON"
+    combination_code = f"ADOCACHI2CUT({max_adocachi2}, '')"
+    vertex_code = (
+        f"(VFASPF(VCHI2/VDOF) < {max_vchi2ndof}) & (BPVVDCHI2() > {min_bpvvdchi2})"
+    )
+    mutau = ParticleCombinerWithPVs(
+        particles=[muons, taus],
+        pvs=pvs,
+        DaughtersCuts=daughters_code,
+        DecayDescriptor=descriptor,
+        CombinationCut=combination_code,
+        MotherCut=vertex_code,
+    )
+    code = require_all(
+        in_range(min_dilepton_mass, F.MASS, max_dilepton_mass),
+        F.PT > min_dilepton_pt,
+        F.BPVIPCHI2(pvs) < max_ipchi2_mutau,
+    )
+    return ParticleFilter(mutau, F.FILTER(code), name=name)
+
+
+@configurable
+def make_prompt_tautau(
+    name="prompt_tautau_builder",
+    min_dilepton_mass=7000.0 * MeV,
+    max_dilepton_mass=13000.0 * MeV,
+    min_dilepton_pt=1.0 * GeV,
+    max_ipchi2_tautau=50,
+    max_adocachi2=30.0,
+    parent_id="Upsilon(1S)",
+    min_pt_tau=0.3 * GeV,
+    minipchi2=0,  # must be 0 for a prompt builder
+    min_bpvvdchi2=0.0,  # must be 0 for a prompt builder
+    max_vchi2ndof=10.0,
+):
+    """
+    Make the detached muon-electron pair, opposite-sign or same-sign.
+    """
+    pvs = make_pvs()
+    taus = make_rd_tauons_hadronic_decay(
+        best_pi_ipchi2_min=minipchi2
+    )  # Make them prompt(?)
+    descriptor = "{} -> tau+ tau-".format(parent_id)
+    combination_code = f"ADOCACHI2CUT({max_adocachi2}, '')"
+    vertex_code = (
+        f"(VFASPF(VCHI2/VDOF) < {max_vchi2ndof}) & (BPVVDCHI2() > {min_bpvvdchi2})"
+    )
+    daughters_code = {
+        "tau+": f"(PT > {min_pt_tau})",  # Do we need to add a minipchi2 to the taus also for promptness?
+        "tau-": f"(PT > {min_pt_tau})",
+    }
+    tautau = ParticleCombinerWithPVs(
+        particles=[taus, taus],
+        pvs=pvs,
+        DaughtersCuts=daughters_code,
+        DecayDescriptor=descriptor,
+        CombinationCut=combination_code,
+        MotherCut=vertex_code,
+    )
+
+    code = require_all(
+        in_range(min_dilepton_mass, F.MASS, max_dilepton_mass),
+        F.PT > min_dilepton_pt,
+        F.BPVIPCHI2(pvs) < max_ipchi2_tautau,
+    )
+    return ParticleFilter(tautau, F.FILTER(code), name=name)
+
+
+# filter based on the rd_detached_mue / make_detached_mue_with_brem with zero cuts on IP and added combination cuts
+@configurable
+def make_prompt_mumu(
+    name="prompt_mumu_builder",
+    min_dilepton_mass=0.0 * MeV,
+    max_dilepton_mass=6000.0 * MeV,
+    min_dilepton_pt=1.0 * GeV,
+    max_ipchi2_mumu=50,
+    parent_id="J/psi(1S)",
+    min_probnn_mu=0.0,
+    IsMuon=True,
+    min_pt_mu=0.5 * GeV,
+    minipchi2=0,  # must be 0 for a prompt builder
+    min_bpvvdchi2=0.0,  # must be 0 for a prompt builder
+    max_trghostprob=0.2,
+):
+    """
+    Make the detached muon-electron pair, opposite-sign or same-sign.
+    """
+    pvs = make_pvs()
+    dileptons = make_detached_mumu(
+        adocachi2cut=30,
+        vfaspfchi2ndof=10,
+        probnn_mu=min_probnn_mu,
+        pt_mu=min_pt_mu,
+        minipchi2=minipchi2,
+        bpvvdchi2=min_bpvvdchi2,
+        trghostprob=max_trghostprob,
+    )
+    code = require_all(
+        in_range(min_dilepton_mass, F.MASS, max_dilepton_mass),
+        F.PT > min_dilepton_pt,
+        F.BPVIPCHI2(pvs) < max_ipchi2_mumu,
+    )
+    return ParticleFilter(dileptons, F.FILTER(code), name=name)
+
+
+@configurable
+def make_prompt_ee(
+    name="prompt_ee_builder",
+    opposite_sign=True,
+    PIDe_min=2.0,
+    pt_e=0.5 * GeV,
+    minipchi2=0,  # must be 0 for a prompt builder
+    max_ipchi2_ee=50,
+    trghostprob=0.2,
+    parent_id="J/psi(1S)",
+    min_dilepton_pt=0 * GeV,
+    min_dilepton_mass=0 * MeV,
+    max_dilepton_mass=6000 * MeV,
+    adocachi2cut=30,
+    max_vchi2ndof=7.5,
+):
+    """
+    Make the detached muon-electron pair, opposite-sign or same-sign.
+    """
+    pvs = make_pvs()
+    dileptons = make_detached_dielectron_with_brem(
+        opposite_sign=opposite_sign,
+        PIDe_min=PIDe_min,
+        pt_e=pt_e,
+        minipchi2=minipchi2,
+        trghostprob=trghostprob,
+        dielectron_ID=parent_id,
+        pt_diE=min_dilepton_pt,
+        m_diE_min=min_dilepton_mass,
+        m_diE_max=max_dilepton_mass,
+        adocachi2cut=adocachi2cut,
+        vfaspfchi2ndof=max_vchi2ndof,
+    )
+    code = require_all(
+        in_range(min_dilepton_mass, F.MASS, max_dilepton_mass),
+        F.PT > min_dilepton_pt,
+        F.BPVIPCHI2(pvs) < max_ipchi2_ee,
+    )
+    return ParticleFilter(dileptons, F.FILTER(code), name=name)
+
+
+"""
+### dedicated filters and builders for making up everything from the basic particles; keeping it now for posible revison but to be removed before merging into master
+@configurable
+def make_prompt_long_electrons(pvs,
+                               make_particles=make_long_electrons_with_brem,
+                               name="prompt_long_electrons",
+                               min_pt_e=0. * MeV,
+                               min_p_e=0. * GeV,
+                               min_ipchi2_electron=0,
+                               min_ip_electron=0,
+                               min_pid_electron=-5,
+                               max_ghostprob_electron=0.7,
+                               max_trackchi2_electron=None,
+                               max_ipchi2_electron=None):
+
+    #pvs = make_pvs()
+
+    code = require_all(F.PT > min_pt_e, F.P > min_p_e,
+                       F.MINIPCHI2(pvs) > min_ipchi2_electron,
+                       F.MINIP(pvs) > min_ip_electron,
+                       F.PID_MU > min_pid_electron,
+                       F.GHOSTPROB < max_ghostprob_electron)
+
+    if max_trackchi2_electron is not None:
+        code &= (F.CHI2 < max_trackchi2_electron)
+    if max_ipchi2_electron is not None:
+        code &= (F.MINIPCHI2(pvs) < max_ipchi2_electron)
+
+    return ParticleFilter(make_particles(), name=name, Cut=F.FILTER())
+
+
+@configurable
+def make_prompt_long_muons(pvs,
+                           make_particles=make_long_muons,
+                           name="prompt_long_muons",
+                           min_pt_mu=0. * MeV,
+                           min_p_mu=0. * GeV,
+                           min_ipchi2_muon=0,
+                           min_ip_muon=0,
+                           min_pid_muon=-5,
+                           max_ghostprob_muon=0.7,
+                           max_trackchi2_muon=None,
+                           max_ipchi2_muon=None):
+
+    #pvs = make_pvs()
+
+    code = require_all(F.PT > min_pt_mu, F.ISMUON, F.P > min_p_mu,
+                       F.MINIPCHI2(pvs) > min_ipchi2_muon,
+                       F.MINIP(pvs) > min_ip_muon, F.PID_MU > min_pid_muon,
+                       F.GHOSTPROB < max_ghostprob_muon)
+
+    if max_trackchi2_muon is not None:
+        code &= (F.CHI2 < max_trackchi2_muon)
+    if max_ipchi2_muon is not None:
+        code &= (F.MINIPCHI2(pvs) < max_ipchi2_muon)
+
+    return ParticleFilter(make_particles(), name=name, Cut=F.FILTER(code))
+
+
+"""
+"""
+@configurable #currenctly does not work, no events selected even after removing all the requirements
+def make_prompt_mue(name='prompt_mue_builder',
+                    DecayDescriptor='[J/psi(1S) -> mu+ e-]CC',
+                    min_dilepton_mass=0. * MeV,
+                    max_dilepton_mass=100000. * MeV,
+                    min_pt_mue=1. * GeV,
+                    min_DIRA_mue=0.95,
+                    min_bpvvdchi2_mue=100.,
+                    max_ipchi2_mue=20,
+                    max_vertexchi2_mue=20,
+                    max_vchi2ndof=10,
+                    min_pt_mu=0.25 * GeV,
+                    min_p_mu=2. * GeV,
+                    min_ipchi2_muon=0,
+                    min_ip_muon=0,
+                    max_ghostprob_muon=0.5,
+                    min_pid_muon=-0,
+                    min_pt_e=0.25 * GeV,
+                    min_p_e=1. * GeV,
+                    min_ipchi2_electron=0,
+                    min_ip_electron=0,
+                    max_ghostprob_electron=0.5,
+                    min_pid_electron=-5,
+                    max_trackchi2_muon=None,
+                    max_trackchi2_electron=None):
+
+    #DecayDescriptor = '{} -> mu+ e-'.format(parent_id) # <- giving a weird error: ValueError: received an instance of <class 'list'>, but <class 'str'> expected
+    #if same_sign: DecayDescriptor = ['[{} -> mu+ e+]CC'.format(parent_id)]
+
+    pvs = make_pvs()
+
+    muons = make_prompt_long_muons(
+        pvs,
+        min_pt_mu=min_pt_mu,
+        min_p_mu=min_p_mu,
+        min_ipchi2_muon=min_ipchi2_muon,
+        min_ip_muon=min_ip_muon,
+        max_ghostprob_muon=max_ghostprob_muon,
+        max_trackchi2_muon=max_trackchi2_muon,
+        min_pid_muon=min_pid_muon)
+
+    electrons = make_prompt_long_electrons(
+        pvs,
+        min_pt_e=min_pt_e,
+        min_p_e=min_p_e,
+        min_ipchi2_electron=min_ipchi2_electron,
+        min_ip_electron=min_ip_electron,
+        max_ghostprob_electron=max_ghostprob_electron,
+        max_trackchi2_electron=max_trackchi2_electron,
+        min_pid_electron=min_pid_electron)
+
+    combination_code = require_all(
+        in_range(min_dilepton_mass, F.MASS, max_dilepton_mass))
+
+    # require that the muons come from the same vertex
+    vertex_code = require_all(
+        F.CHI2DOF < max_vertexchi2_mue,
+        #F.CHI2 / F.NDOF < max_vchi2ndof, <- doesn't work?
+        F.PT > min_pt_mue,
+        F.BPVFDCHI2(pvs) > min_bpvvdchi2_mue,
+        F.BPVIPCHI2(pvs) < max_ipchi2_mue,
+        F.BPVDIRA(pvs) > min_DIRA_mue)
+
+    return ParticleCombiner(
+        name=name,
+        Inputs=[muons, electrons],
+        DecayDescriptor=DecayDescriptor,
+        #CombinationCut=combination_code,
+        #CompositeCut=vertex_code
+        )
+"""
+
+#################
+## END OF FILE ##
+#################
diff --git a/Hlt/Hlt2Conf/python/Hlt2Conf/lines/rd/builders/rdbuilder_thor.py b/Hlt/Hlt2Conf/python/Hlt2Conf/lines/rd/builders/rdbuilder_thor.py
index cfc3294a05e375efccd1bb2080c7cb3734a54117..23ffc3ee8af09121389977614ca4417363d4cb15 100644
--- a/Hlt/Hlt2Conf/python/Hlt2Conf/lines/rd/builders/rdbuilder_thor.py
+++ b/Hlt/Hlt2Conf/python/Hlt2Conf/lines/rd/builders/rdbuilder_thor.py
@@ -805,6 +805,7 @@ def make_rd_detached_dielectron(name="rd_detached_dielectron",
 
 @configurable
 def make_rd_detached_mue(name="rd_detached_mue",
+                         min_dilepton_mass=0. * MeV,
                          max_dilepton_mass=6000. * MeV,
                          parent_id='J/psi(1S)',
                          min_probnn_mu=0.,
@@ -830,7 +831,7 @@ def make_rd_detached_mue(name="rd_detached_mue",
         min_pt_mu=min_pt_mu,
         min_bpvvdchi2=min_bpvvdchi2,
         max_vchi2ndof=max_vchi2ndof)
-    code = require_all(F.MASS < max_dilepton_mass)
+    code = require_all(in_range(min_dilepton_mass, F.MASS, max_dilepton_mass))
     return ParticleFilter(dileptons, F.FILTER(code), name=name)
 
 
diff --git a/Hlt/Hlt2Conf/python/Hlt2Conf/lines/rd/qqbar_to_emu.py b/Hlt/Hlt2Conf/python/Hlt2Conf/lines/rd/qqbar_to_emu.py
new file mode 100644
index 0000000000000000000000000000000000000000..11f2d4a6e3fd841a915fc6a01943025de3380a07
--- /dev/null
+++ b/Hlt/Hlt2Conf/python/Hlt2Conf/lines/rd/qqbar_to_emu.py
@@ -0,0 +1,348 @@
+##############################################################################
+# (c) Copyright 2021 CERN for the benefit of the LHCb Collaboration           #
+#                                                                             #
+# This software is distributed under the terms of the GNU General Public      #
+# Licence version 3 (GPL Version 3), copied verbatim in the file "COPYING".   #
+#                                                                             #
+# In applying this licence, CERN does not waive the privileges and immunities #
+# granted to it by virtue of its status as an Intergovernmental Organization  #
+# or submit itself to any jurisdiction.                                       #
+###############################################################################
+"""
+Definiton of LFV lines of qqbar -> emu
+- Phi(1020) -> E Mu + SS prompt
+- Phi(1020) -> E Mu + SS detached
+- J/Psi(1S) -> E Mu + SS prompt
+- J/Psi(1S) -> E Mu + SS detached
+- Upsilon(1S) -> E Mu + SS prompt only
+
+add control channels e+e- / mu+mu-
+
+author: Miroslav Saur
+date: 27.12.2021
+
+"""
+
+from GaudiKernel.SystemOfUnits import MeV, GeV
+from PyConf import configurable
+from RecoConf.hlt1_tracking import require_pvs, require_gec
+from RecoConf.reconstruction_objects import (make_pvs_v2 as make_pvs,
+                                             upfront_reconstruction)
+from Moore.config import register_line_builder
+from Moore.lines import Hlt2Line
+from Hlt2Conf.lines.rd.builders.rdbuilder_thor import make_rd_detached_mue
+from Hlt2Conf.lines.rd.builders.qqbar_builder import make_prompt_mue, make_prompt_ee
+
+all_lines = {}
+
+
+def prefilters():
+    return [require_gec(), require_pvs(make_pvs())]
+
+
+###### PROMPT LINES #####
+
+
+@register_line_builder(all_lines)
+@configurable
+def phi_to_mue_line(name="Hlt2RD_PhiToMuE_Line", prescale=1,
+                    persistreco=False):
+    """
+    Definiton of [phi(1020) -> mu- e+]CC
+    """
+    emu = make_prompt_mue(
+        name="Hlt2RD_PhiToMuE_Builder",
+        parent_id='phi(1020)',
+        min_dilepton_mass=850. * MeV,
+        max_dilepton_mass=1520. * MeV,
+        min_dilepton_pt=2.0 * GeV,
+        min_pt_e=0.5 * GeV,
+        min_pt_mu=0.5 * GeV)
+    return Hlt2Line(
+        name=name,
+        algs=upfront_reconstruction() + prefilters() + [emu],
+        prescale=prescale,
+        persistreco=persistreco)
+
+
+@register_line_builder(all_lines)
+@configurable
+def phi_to_mue_ss_line(name="Hlt2RD_PhiToMuE_SS_Line",
+                       prescale=1,
+                       persistreco=False):
+    emu = make_prompt_mue(
+        name="Hlt2RD_PhiToMuE_SS_Builder",
+        parent_id='phi(1020)',
+        min_dilepton_mass=850. * MeV,
+        max_dilepton_mass=1520. * MeV,
+        min_dilepton_pt=2.0 * GeV,
+        min_pt_e=0.5 * GeV,
+        min_pt_mu=0.5 * GeV,
+        same_sign=True)
+    return Hlt2Line(
+        name=name,
+        algs=upfront_reconstruction() + prefilters() + [emu],
+        prescale=prescale,
+        persistreco=persistreco)
+
+
+@register_line_builder(all_lines)
+@configurable
+def jpsi_to_mue_line(name="Hlt2RD_JpsiToMuE_Line",
+                     prescale=1,
+                     persistreco=False):
+
+    emu = make_prompt_mue(
+        name="Hlt2RD_JpsiToMuE_Builder",
+        parent_id='J/psi(1S)',
+        min_dilepton_mass=2600. * MeV,
+        max_dilepton_mass=3700. * MeV,
+        min_dilepton_pt=2.0 * GeV,
+        min_pt_e=1.0 * GeV,
+        min_pt_mu=1.0 * GeV)
+    return Hlt2Line(
+        name=name,
+        algs=upfront_reconstruction() + prefilters() + [emu],
+        prescale=prescale,
+        persistreco=persistreco)
+
+
+@register_line_builder(all_lines)
+@configurable
+def jpsi_to_mue_ss_line(name="Hlt2RD_JpsiToMuE_SS_Line",
+                        prescale=1,
+                        persistreco=False):
+
+    emu = make_prompt_mue(
+        name="Hlt2RD_JpsiToMuE_SS_Builder",
+        parent_id='J/psi(1S)',
+        min_dilepton_mass=2600. * MeV,
+        max_dilepton_mass=3700. * MeV,
+        min_dilepton_pt=2.0 * GeV,
+        min_pt_e=1.0 * GeV,
+        min_pt_mu=1.0 * GeV,
+        same_sign=True)
+    return Hlt2Line(
+        name=name,
+        algs=upfront_reconstruction() + prefilters() + [emu],
+        prescale=prescale,
+        persistreco=persistreco)
+
+
+@register_line_builder(all_lines)
+@configurable
+def upsilon_to_mue_line(name="Hlt2RD_UpsilonToMuE_Line",
+                        prescale=1,
+                        persistreco=False):
+
+    emu = make_prompt_mue(
+        name="Hlt2RD_UpsilonToMuE_Builder",
+        parent_id='Upsilon(1S)',
+        min_dilepton_mass=7000. * MeV,
+        max_dilepton_mass=13000. * MeV,
+        min_dilepton_pt=1.0 * GeV,
+        min_pt_e=1.0 * GeV,
+        min_pt_mu=1.0 * GeV,
+        same_sign=False)
+    return Hlt2Line(
+        name=name,
+        algs=upfront_reconstruction() + prefilters() + [emu],
+        prescale=prescale,
+        persistreco=persistreco)
+
+
+@register_line_builder(all_lines)
+@configurable
+def upsilon_to_mue_ss_line(name="Hlt2RD_UpsilonToMuE_SS_Line",
+                           prescale=1,
+                           persistreco=False):
+
+    emu = make_prompt_mue(
+        name="Hlt2RD_UpsilonToMuE_SS_Builder",
+        parent_id='Upsilon(1S)',
+        min_dilepton_mass=7000. * MeV,
+        max_dilepton_mass=13000. * MeV,
+        min_dilepton_pt=1.0 * GeV,
+        min_pt_e=1.0 * GeV,
+        min_pt_mu=1.0 * GeV,
+        same_sign=True)
+    return Hlt2Line(
+        name=name,
+        algs=upfront_reconstruction() + prefilters() + [emu],
+        prescale=prescale,
+        persistreco=persistreco)
+
+
+##### DETACHED LINES #####
+
+
+@register_line_builder(all_lines)
+@configurable
+def phi_to_mue_detached_line(name="Hlt2RD_PhiToMuE_Detached_Line",
+                             prescale=1,
+                             persistreco=False):
+    """
+    Definiton of [phi(1020) -> mu- e+]CC
+    """
+    emu = make_rd_detached_mue(
+        name="Hlt2RD_PhiToMuE_detached_Builder",
+        parent_id='phi(1020)',
+        min_dilepton_mass=800. * MeV,
+        max_dilepton_mass=1570. * MeV,
+        min_probnn_mu=0.,
+        min_pt_e=0.25 * GeV,
+        min_pt_mu=0.25 * GeV,
+        min_bpvvdchi2=30.,
+        max_vchi2ndof=8.,
+    )
+    return Hlt2Line(
+        name=name,
+        algs=upfront_reconstruction() + prefilters() + [emu],
+        prescale=prescale,
+        persistreco=persistreco)
+
+
+@register_line_builder(all_lines)
+@configurable
+def phi_to_mue_ss_detached_line(name="Hlt2RD_PhiToMuE_SS_Detached_Line",
+                                prescale=1,
+                                persistreco=False):
+    """
+    Definiton of [phi(1020) -> mu+ e+]CC
+    """
+    emu = make_rd_detached_mue(
+        name="Hlt2RD_PhiToMuE_SS_detached_Builder",
+        parent_id='phi(1020)',
+        min_dilepton_mass=800. * MeV,
+        max_dilepton_mass=1570. * MeV,
+        min_probnn_mu=0.,
+        min_pt_e=0.25 * GeV,
+        min_pt_mu=0.25 * GeV,
+        min_bpvvdchi2=30.,
+        max_vchi2ndof=8.,
+        same_sign=True)
+    return Hlt2Line(
+        name=name,
+        algs=upfront_reconstruction() + prefilters() + [emu],
+        prescale=prescale,
+        persistreco=persistreco)
+
+
+@register_line_builder(all_lines)
+@configurable
+def jpsi_to_mue_detached_line(name="Hlt2RD_JpsiToMuE_Detached_Line",
+                              prescale=1,
+                              persistreco=False):
+    """
+    Definiton of [J/psi(1S) -> mu- e+]CC
+    """
+    emu = make_rd_detached_mue(
+        name="Hlt2RD_JpsiToMuE_detached_Builder",
+        parent_id='J/psi(1S)',
+        min_dilepton_mass=2600. * MeV,
+        max_dilepton_mass=3700. * MeV,
+        min_probnn_mu=0.,
+        min_pt_e=0.5 * GeV,
+        min_pt_mu=0.5 * GeV,
+        min_bpvvdchi2=30.,
+        max_vchi2ndof=8.,
+    )
+    return Hlt2Line(
+        name=name,
+        algs=upfront_reconstruction() + prefilters() + [emu],
+        prescale=prescale,
+        persistreco=persistreco)
+
+
+@register_line_builder(all_lines)
+@configurable
+def jpsi_to_mue_ss_detached_line(name="Hlt2RD_JpsiToMuE_SS_Detached_Line",
+                                 prescale=1,
+                                 persistreco=False):
+    """
+    Definiton of [J/psi(1S) -> mu+ e+]CC
+    """
+    emu = make_rd_detached_mue(
+        name="Hlt2RD_JpsiToMuE_SS_deached_Builder",
+        parent_id='J/psi(1S)',
+        min_dilepton_mass=2600. * MeV,
+        max_dilepton_mass=3700. * MeV,
+        min_probnn_mu=0.,
+        min_pt_e=0.5 * GeV,
+        min_pt_mu=0.5 * GeV,
+        min_bpvvdchi2=30.,
+        max_vchi2ndof=8.,
+        same_sign=True)
+    return Hlt2Line(
+        name=name,
+        algs=upfront_reconstruction() + prefilters() + [emu],
+        prescale=prescale,
+        persistreco=persistreco)
+
+
+##### CONTROL ee/mumu LINES #####
+
+
+@register_line_builder(all_lines)
+@configurable
+def phi_to_ee_line(name="Hlt2RD_PhiToEE_Line", prescale=1, persistreco=False):
+    emu = make_prompt_ee(
+        name="Hlt2RD_PhiToMuE_SS_Builder",
+        parent_id='phi(1020)',
+        opposite_sign=True,
+        PIDe_min=2.,
+        pt_e=1.5 * GeV,
+        min_dilepton_pt=2.0 * GeV,
+        min_dilepton_mass=850 * MeV,
+        max_dilepton_mass=1520 * MeV)
+    return Hlt2Line(
+        name=name,
+        algs=upfront_reconstruction() + prefilters() + [emu],
+        prescale=prescale,
+        persistreco=persistreco)
+
+
+@register_line_builder(all_lines)
+@configurable
+def jpsi_to_ee_line(name="Hlt2RD_JpsiToEE_Line", prescale=1,
+                    persistreco=False):
+    emu = make_prompt_ee(
+        name="Hlt2RD_PhiToMuE_SS_Builder",
+        parent_id='J/psi(1S)',
+        opposite_sign=True,
+        PIDe_min=2.,
+        pt_e=0.5 * GeV,
+        min_dilepton_pt=1.0 * GeV,
+        min_dilepton_mass=2600 * MeV,
+        max_dilepton_mass=3700 * MeV)
+    return Hlt2Line(
+        name=name,
+        algs=upfront_reconstruction() + prefilters() + [emu],
+        prescale=prescale,
+        persistreco=persistreco)
+
+
+@register_line_builder(all_lines)
+@configurable
+def upsilon_to_ee_line(name="Hlt2RD_UpsilonToEE_Line",
+                       prescale=1,
+                       persistreco=False):
+    emu = make_prompt_ee(
+        name="Hlt2RD_UpsilonToMuE_Builder",
+        parent_id='Upsilon(1S)',
+        opposite_sign=True,
+        PIDe_min=2.,
+        pt_e=1. * GeV,
+        min_dilepton_pt=0.5 * GeV,
+        min_dilepton_mass=7000 * MeV,
+        max_dilepton_mass=13000 * MeV)
+    return Hlt2Line(
+        name=name,
+        algs=upfront_reconstruction() + prefilters() + [emu],
+        prescale=prescale,
+        persistreco=persistreco)
+
+
+#################
+## END OF FILE ##
+#################
diff --git a/Hlt/Hlt2Conf/python/Hlt2Conf/lines/rd/upsilon_to_ll.py b/Hlt/Hlt2Conf/python/Hlt2Conf/lines/rd/upsilon_to_ll.py
new file mode 100644
index 0000000000000000000000000000000000000000..e6bd6e258ccb486c1bbc1a305ac086fba61c71d7
--- /dev/null
+++ b/Hlt/Hlt2Conf/python/Hlt2Conf/lines/rd/upsilon_to_ll.py
@@ -0,0 +1,151 @@
+###############################################################################
+# (c) Copyright 2021 CERN for the benefit of the LHCb Collaboration           #
+#                                                                             #
+# This software is distributed under the terms of the GNU General Public      #
+# Licence version 3 (GPL Version 3), copied verbatim in the file "COPYING".   #
+#                                                                             #
+# In applying this licence, CERN does not waive the privileges and immunities #
+# granted to it by virtue of its status as an Intergovernmental Organization  #
+# or submit itself to any jurisdiction.                                       #
+###############################################################################
+"""
+Registration of Upsilon to ll(')(gamma) lines for the RD working group.
+It contains also B2HH as this is an important normalisation.
+- Upsilon -> e e
+- Upsilon -> mumu
+- Upsilon -> tautau
+- Upsilon -> etau
+- Upsilon -> mutau
+
+author: Raja Nandakumar, Fergus Wilson
+date: 31.01.2022
+"""
+
+from Moore.config import register_line_builder
+from Moore.lines import Hlt2Line
+from GaudiKernel.SystemOfUnits import MeV, GeV
+from PyConf import configurable
+
+from RecoConf.reconstruction_objects import upfront_reconstruction
+
+from Hlt2Conf.lines.rd.builders.qqbar_builder import (
+    make_prompt_mumu,
+    make_prompt_ee,
+    make_prompt_tautau,
+)
+from Hlt2Conf.lines.rd.builders.qqbar_builder import make_prompt_etau, make_prompt_mutau
+
+all_lines = {}
+
+
+@register_line_builder(all_lines)
+@configurable
+def Hlt2RD_UpsilonToEE_Line(
+    name="Hlt2RD_UpsilonToEE_Line", prescale=1, persistreco=False
+):
+
+    ee = make_prompt_ee(
+        name="Hlt2RD_UpsilonToEE_Builder",
+        parent_id="Upsilon(1S)",
+        opposite_sign=True,
+        min_dilepton_mass=7000.0 * MeV,
+        max_dilepton_mass=13000.0 * MeV,
+        min_dilepton_pt=1.0 * GeV,
+        pt_e=1.0 * GeV,  # The minimum Pt
+    )
+    return Hlt2Line(
+        name=name,
+        algs=upfront_reconstruction() + [ee],
+        prescale=prescale,
+        persistreco=persistreco,
+    )
+
+
+@register_line_builder(all_lines)
+@configurable
+def Hlt2RD_UpsilonToMuMu_Line(
+    name="Hlt2RD_UpsilonToMuMu_Line", prescale=1, persistreco=False
+):
+
+    mumu = make_prompt_mumu(
+        name="Hlt2RD_UpsilonToMuMu_Builder",
+        parent_id="Upsilon(1S)",
+        min_dilepton_mass=7000.0 * MeV,
+        max_dilepton_mass=13000.0 * MeV,
+        min_dilepton_pt=1.0 * GeV,
+        min_pt_mu=1.0 * GeV,
+    )
+    return Hlt2Line(
+        name=name,
+        algs=upfront_reconstruction() + [mumu],
+        prescale=prescale,
+        persistreco=persistreco,
+    )
+
+
+@register_line_builder(all_lines)
+@configurable
+def Hlt2RD_UpsilonToTauTau_Line(
+    name="Hlt2RD_UpsilonToTauTau_Line", prescale=1, persistreco=False
+):
+
+    tautau = make_prompt_tautau(
+        name="Hlt2RD_UpsilonToTauTau_Builder",
+        parent_id="Upsilon(1S)",
+        min_dilepton_mass=7000.0 * MeV,
+        max_dilepton_mass=13000.0 * MeV,
+        min_dilepton_pt=1.0 * GeV,
+    )
+
+    return Hlt2Line(
+        name=name,
+        algs=upfront_reconstruction() + [tautau],
+        prescale=prescale,
+        persistreco=persistreco,
+    )
+
+
+@register_line_builder(all_lines)
+@configurable
+def Hlt2RD_UpsilonToeTau_Line(
+    name="Hlt2RD_UpsilonToeTau_Line", prescale=1, persistreco=False
+):
+
+    etau = make_prompt_etau(
+        name="Hlt2RD_UpsilonToeTau_Builder",
+        parent_id="Upsilon(1S)",
+        min_dilepton_mass=7000.0 * MeV,
+        max_dilepton_mass=13000.0 * MeV,
+        min_dilepton_pt=1.0 * GeV,
+        min_pt_e=1.0 * GeV,
+    )
+
+    return Hlt2Line(
+        name=name,
+        algs=upfront_reconstruction() + [etau],
+        prescale=prescale,
+        persistreco=persistreco,
+    )
+
+
+@register_line_builder(all_lines)
+@configurable
+def Hlt2RD_UpsilonTomuTau_Line(
+    name="Hlt2RD_UpsilonTomuTau_Line", prescale=1, persistreco=False
+):
+
+    mutau = make_prompt_mutau(
+        name="Hlt2RD_UpsilonTomuTau_Builder",
+        parent_id="Upsilon(1S)",
+        min_dilepton_mass=7000.0 * MeV,
+        max_dilepton_mass=13000.0 * MeV,
+        min_dilepton_pt=1.0 * GeV,
+        min_pt_mu=1.0 * GeV,
+    )
+
+    return Hlt2Line(
+        name=name,
+        algs=upfront_reconstruction() + [mutau],
+        prescale=prescale,
+        persistreco=persistreco,
+    )