From ff8dc1ccff97211d1a0af1844b99cbc409c0adf1 Mon Sep 17 00:00:00 2001
From: Eduardo Rodrigues <eduardo.rodrigues@cern.ch>
Date: Fri, 24 Feb 2023 15:41:42 +0100
Subject: [PATCH] DaVinci tests - enhance ntuple content checks and please
 QMTest

---
 .../test_davinci_configFuntuple.qmt           |  3 +-
 .../tupling.qms/test_davinci_tupling_All.qmt  | 16 ++--
 .../test_davinci_tupling_All_olddst.qmt       | 12 ++-
 .../tupling.qms/test_davinci_tupling_DTF.qmt  |  3 +-
 .../test_davinci_tupling_FunTupleEvent.qmt    | 17 +++--
 .../test_davinci_tupling_SubsPID.qmt          |  6 +-
 .../test_davinci_tupling_from_spruce_mc.qmt   | 76 +++++++++++++------
 .../test_example-tupling-basic-run-mc.qmt     | 25 +++++-
 .../test_example-tupling-basic.qmt            | 51 ++++++++-----
 .../test_davinci_tupling_array_taggers.ref    | 12 +--
 ..._davinci_tupling_array_taggers.ref.detdesc | 12 +--
 .../refs/test_davinci_tupling_from_hlt2.ref   |  6 +-
 ...test_davinci_tupling_from_hlt2.ref.detdesc |  6 +-
 ...t_davinci_tupling_unreconstructed_info.ref |  6 +-
 ...i_tupling_unreconstructed_info.ref.detdesc |  6 +-
 DaVinciTests/python/DaVinciTests/filters.py   |  4 +-
 .../davinci.qms/test_davinci_filters.qmt      |  8 +-
 .../davinci.qms/test_davinci_recVertices.qmt  |  3 +-
 .../tests/refs/test_davinci_filters.ref       |  4 +-
 .../refs/test_davinci_filters.ref.detdesc     |  4 +-
 .../test_tutorial1_functors_specialfield.qmt  |  9 ++-
 .../tests/qmtest/test_tutorial2_LoKi.qmt      | 12 ++-
 .../qmtest/test_tutorial3_ThOrfunctors.qmt    | 17 +++--
 .../test_tutorial4_trigger_eventinfo.qmt      | 15 ++--
 .../tests/qmtest/test_tutorial5_MCTruth.qmt   | 27 ++++---
 .../qmtest/test_tutorial6_DecayTreeFit.qmt    |  3 +-
 .../test_tutorial7_multiple_sel_lines.qmt     | 21 +++--
 .../tests/refs/test_tutorial5_MCTruth.ref     |  6 +-
 .../refs/test_tutorial5_MCTruth.ref.detdesc   |  6 +-
 29 files changed, 257 insertions(+), 139 deletions(-)

diff --git a/DaVinciExamples/tests/qmtest/tupling.qms/test_davinci_configFuntuple.qmt b/DaVinciExamples/tests/qmtest/tupling.qms/test_davinci_configFuntuple.qmt
index c72508695..1128f3c2a 100644
--- a/DaVinciExamples/tests/qmtest/tupling.qms/test_davinci_configFuntuple.qmt
+++ b/DaVinciExamples/tests/qmtest/tupling.qms/test_davinci_configFuntuple.qmt
@@ -34,6 +34,7 @@ countErrorLines({"FATAL":0, "ERROR":0})
 
 # Check there are no NaN values in the ntuple
 from DaVinciTests.QMTest.check_helpers import has_nan
-assert not has_nan("DV_example_configFuntuple_ntp.root", "Tuple_B0Dspi/DecayTree")
+if has_nan("DV_example_configFuntuple_ntp.root", "Tuple_B0Dspi/DecayTree"):
+    causes.append("Ntuple contains NaN entries")
   </text></argument>
 </extension>
diff --git a/DaVinciExamples/tests/qmtest/tupling.qms/test_davinci_tupling_All.qmt b/DaVinciExamples/tests/qmtest/tupling.qms/test_davinci_tupling_All.qmt
index a86bcabdc..9667922f5 100755
--- a/DaVinciExamples/tests/qmtest/tupling.qms/test_davinci_tupling_All.qmt
+++ b/DaVinciExamples/tests/qmtest/tupling.qms/test_davinci_tupling_All.qmt
@@ -62,17 +62,20 @@ B_vars_stored = sorted(B_vars_stored)
 
 #open the TFile and TTree
 ntuple = './DV_example_allFunctors_ntp.root'
-if not os.path.isfile(ntuple): raise Exception(f"File: {ntuple} does not exist!")
-f      = TFile.Open(ntuple)
-t_B    = f.Get('B0DsK_Tuple/DecayTree')
+if not os.path.isfile(ntuple):
+    causes.append(f"File {ntuple} does not exist!")
+f   = TFile.Open(ntuple)
+t_B = f.Get('B0DsK_Tuple/DecayTree')
 
 #sort the stores vars
 b_names = sorted([b.GetName() for b in t_B.GetListOfLeaves()])
 
 B_excluded_1 = set(B_vars_stored) - set(b_names)
 B_excluded_2 = set(b_names) - set(B_vars_stored)
-if len(B_excluded_1) != 0: raise Exception('Number of stored variables is less than what is expected. The extra variables expected are: ' , B_excluded_1)
-if len(B_excluded_2) != 0: raise Exception('Number of stored variables is greater than what is expected. The extra variables stored are: ', B_excluded_2)
+if len(B_excluded_1) != 0:
+    causes.append(f"Number of stored variables is less than what is expected. The extra variables expected are: {B_excluded_1}")
+if len(B_excluded_2) != 0:
+    causes.append(f"Number of stored variables is greater than what is expected. The extra variables stored are: {B_excluded_2}")
 f.Close()
 
 # Check there are no NaN values in the ntuple except where expected.
@@ -81,7 +84,8 @@ from DaVinciTests.QMTest.check_helpers import list_fields_with_nan
 l_branches_with_nans = ['B0_TRUEP', 'B0_TRUEPT', 'B0_TRUEPX', 'B0_TRUEPY', 'B0_TRUEPZ', 'B0_TRUEENERGY', 'B0_TRUEORIGINVERTEX_X', 'B0_TRUEORIGINVERTEX_Y', 'B0_TRUEORIGINVERTEX_Z', 'B0_TRUEENDVERTEX_X', 'B0_TRUEENDVERTEX_Y', 'B0_TRUEENDVERTEX_Z', 'B0_MASSWITHHYPOTHESES', 'Kaon_PROBNN_D', 'Kaon_PROBNN_MU', 'Kaon_TRUEP', 'Kaon_TRUEPT', 'Kaon_TRUEPX', 'Kaon_TRUEPY', 'Kaon_TRUEPZ', 'Kaon_TRUEENERGY', 'Kaon_BREMENERGY', 'Kaon_BREMBENDCORR', 'Kaon_BREMPIDE', 'Kaon_ECALPIDE', 'Kaon_ECALPIDMU', 'Kaon_HCALPIDE', 'Kaon_HCALPIDMU', 'Kaon_ELECTRONSHOWEREOP', 'Kaon_CLUSTERMATCH', 'Kaon_ELECTRONMATCH', 'Kaon_BREMHYPOMATCH', 'Kaon_ELECTRONENERGY', 'Kaon_BREMHYPOENERGY', 'Kaon_BREMHYPODELTAX', 'Kaon_ELECTRONID', 'Kaon_HCALEOP', 'Ds_TRUEP', 'Ds_TRUEPT', 'Ds_TRUEPX', 'Ds_TRUEPY', 'Ds_TRUEPZ', 'Ds_TRUEENERGY', 'Ds_TRUEORIGINVERTEX_X', 'Ds_TRUEORIGINVERTEX_Y', 'Ds_TRUEORIGINVERTEX_Z', 'Ds_TRUEENDVERTEX_X', 'Ds_TRUEENDVERTEX_Y', 'Ds_TRUEENDVERTEX_Z', 'Ds_BPVCORRMERR', 'Ds_BPVLTIME', 'Ds_MASSWITHHYPOTHESES', 'pip_PROBNN_D', 'pip_PROBNN_MU', 'pip_TRUEP', 'pip_TRUEPT', 'pip_TRUEPX', 'pip_TRUEPY', 'pip_TRUEPZ', 'pip_TRUEENERGY', 'pip_BREMENERGY', 'pip_BREMBENDCORR', 'pip_BREMPIDE', 'pip_ECALPIDE', 'pip_ECALPIDMU', 'pip_HCALPIDE', 'pip_HCALPIDMU', 'pip_ELECTRONSHOWEREOP', 'pip_CLUSTERMATCH', 'pip_ELECTRONMATCH', 'pip_BREMHYPOMATCH', 'pip_ELECTRONENERGY', 'pip_BREMHYPOENERGY', 'pip_BREMHYPODELTAX', 'pip_ELECTRONID', 'pip_HCALEOP']
 
 l_test = list_fields_with_nan("DV_example_allFunctors_ntp.root", "B0DsK_Tuple/DecayTree")
-assert sorted(l_test) == sorted(l_branches_with_nans)
+if sorted(l_test) != sorted(l_branches_with_nans):
+    causes.append("Unexpected list of branches with NaN values")
 
 print('Test successfully completed!')
 os.system(f"rm {ntuple}")
diff --git a/DaVinciExamples/tests/qmtest/tupling.qms/test_davinci_tupling_All_olddst.qmt b/DaVinciExamples/tests/qmtest/tupling.qms/test_davinci_tupling_All_olddst.qmt
index 9f6fabc0f..a8d1e116d 100755
--- a/DaVinciExamples/tests/qmtest/tupling.qms/test_davinci_tupling_All_olddst.qmt
+++ b/DaVinciExamples/tests/qmtest/tupling.qms/test_davinci_tupling_All_olddst.qmt
@@ -62,7 +62,8 @@ B_vars_stored = sorted(B_vars_stored)
 
 #open the TFile and TTree
 ntuple = './DV_example_allFunctors_ntp_old.root'
-if not os.path.isfile(ntuple): raise Exception(f"File: {ntuple} does not exist!")
+if not os.path.isfile(ntuple):
+    causes.append(f"File {ntuple} does not exist!")
 f      = TFile.Open(ntuple)
 t_B    = f.Get('B0DsK_Tuple/DecayTree')
 
@@ -71,8 +72,10 @@ b_names = sorted([b.GetName() for b in t_B.GetListOfLeaves()])
 
 B_excluded_1 = set(B_vars_stored) - set(b_names)
 B_excluded_2 = set(b_names) - set(B_vars_stored)
-if len(B_excluded_1) != 0: raise Exception('Number of stored variables is less than what is expected. The extra variables expected are: ' , B_excluded_1)
-if len(B_excluded_2) != 0: raise Exception('Number of stored variables is greater than what is expected. The extra variables stored are: ', B_excluded_2)
+if len(B_excluded_1) != 0:
+    causes.append(f"Number of stored variables is less than what is expected. The extra variables expected are: {B_excluded_1}")
+if len(B_excluded_2) != 0:
+    causes.append(f"Number of stored variables is greater than what is expected. The extra variables stored are: {B_excluded_2}")
 f.Close()
 
 # Check there are no NaN values in the ntuple except where expected.
@@ -81,7 +84,8 @@ from DaVinciTests.QMTest.check_helpers import list_fields_with_nan
 l_branches_with_nans =  ['B0_TRUEP', 'B0_TRUEPT', 'B0_TRUEPX', 'B0_TRUEPY', 'B0_TRUEPZ', 'B0_TRUEENERGY', 'B0_TRUEORIGINVERTEX_X', 'B0_TRUEORIGINVERTEX_Y', 'B0_TRUEORIGINVERTEX_Z', 'B0_TRUEENDVERTEX_X', 'B0_TRUEENDVERTEX_Y', 'B0_TRUEENDVERTEX_Z', 'Kaon_PROBNN_D', 'Kaon_PROBNN_MU', 'Kaon_TRUEP', 'Kaon_TRUEPT', 'Kaon_TRUEPX', 'Kaon_TRUEPY', 'Kaon_TRUEPZ', 'Kaon_TRUEENERGY', 'Kaon_BREMENERGY', 'Kaon_BREMBENDCORR', 'Kaon_BREMPIDE', 'Kaon_ECALPIDE', 'Kaon_ECALPIDMU', 'Kaon_HCALPIDE', 'Kaon_HCALPIDMU', 'Kaon_ELECTRONSHOWEREOP', 'Kaon_CLUSTERMATCH', 'Kaon_ELECTRONMATCH', 'Kaon_BREMHYPOMATCH', 'Kaon_ELECTRONENERGY', 'Kaon_BREMHYPOENERGY', 'Kaon_BREMHYPODELTAX', 'Kaon_ELECTRONID', 'Kaon_HCALEOP', 'Ds_TRUEP', 'Ds_TRUEPT', 'Ds_TRUEPX', 'Ds_TRUEPY', 'Ds_TRUEPZ', 'Ds_TRUEENERGY', 'Ds_TRUEORIGINVERTEX_X', 'Ds_TRUEORIGINVERTEX_Y', 'Ds_TRUEORIGINVERTEX_Z', 'Ds_TRUEENDVERTEX_X', 'Ds_TRUEENDVERTEX_Y', 'Ds_TRUEENDVERTEX_Z', 'Ds_BPVCORRMERR', 'Ds_BPVLTIME', 'Ds_MASSWITHHYPOTHESES', 'pip_PROBNN_D', 'pip_PROBNN_MU', 'pip_TRUEP', 'pip_TRUEPT', 'pip_TRUEPX', 'pip_TRUEPY', 'pip_TRUEPZ', 'pip_TRUEENERGY', 'pip_BREMENERGY', 'pip_BREMBENDCORR', 'pip_BREMPIDE', 'pip_ECALPIDE', 'pip_ECALPIDMU', 'pip_HCALPIDE', 'pip_HCALPIDMU', 'pip_ELECTRONSHOWEREOP', 'pip_CLUSTERMATCH', 'pip_ELECTRONMATCH', 'pip_BREMHYPOMATCH', 'pip_ELECTRONENERGY', 'pip_BREMHYPOENERGY', 'pip_BREMHYPODELTAX', 'pip_ELECTRONID', 'pip_HCALEOP']
 
 l_test = list_fields_with_nan("DV_example_allFunctors_ntp_old.root", "B0DsK_Tuple/DecayTree")
-assert sorted(l_test) == sorted(l_branches_with_nans)
+if sorted(l_test) != sorted(l_branches_with_nans):
+    causes.append("Unexpected list of branches with NaN values")
 
 print('Test successfully completed!')
 os.system(f"rm {ntuple}")
diff --git a/DaVinciExamples/tests/qmtest/tupling.qms/test_davinci_tupling_DTF.qmt b/DaVinciExamples/tests/qmtest/tupling.qms/test_davinci_tupling_DTF.qmt
index 79cb56730..3dc872de6 100755
--- a/DaVinciExamples/tests/qmtest/tupling.qms/test_davinci_tupling_DTF.qmt
+++ b/DaVinciExamples/tests/qmtest/tupling.qms/test_davinci_tupling_DTF.qmt
@@ -35,6 +35,7 @@ from DaVinciTests.QMTest.check_helpers import list_fields_with_nan
 l_branches_with_nans = ['Jpsi_DTF_PV_MASS']
 
 l_test = list_fields_with_nan("DV-example-tupling-DTF-ntp.root", "DimuonsTuple/DecayTree")
-assert sorted(l_test) == sorted(l_branches_with_nans)
+if sorted(l_test) != sorted(l_branches_with_nans):
+    causes.append("Unexpected list of branches with NaN values")
 </text></argument>
 </extension>
diff --git a/DaVinciExamples/tests/qmtest/tupling.qms/test_davinci_tupling_FunTupleEvent.qmt b/DaVinciExamples/tests/qmtest/tupling.qms/test_davinci_tupling_FunTupleEvent.qmt
index 5da788675..006f3a911 100644
--- a/DaVinciExamples/tests/qmtest/tupling.qms/test_davinci_tupling_FunTupleEvent.qmt
+++ b/DaVinciExamples/tests/qmtest/tupling.qms/test_davinci_tupling_FunTupleEvent.qmt
@@ -28,6 +28,9 @@
 from DaVinciTests.QMTest.DaVinciExclusions import preprocessor,remove_known_warnings
 validateWithReference(preproc = preprocessor)
 
+countErrorLines({"FATAL": 0, "WARNING": 0, "ERROR": 0},
+                stdout=remove_known_warnings(stdout))
+
 import sys, os, glob
 from ROOT import TFile
 
@@ -38,7 +41,8 @@ B_vars_stored = sorted(B_vars_stored)
 
 #open the TFile and TTree
 ntuple = './tuple_FunTupleEvent.root'
-if not os.path.isfile(ntuple): raise Exception(f"File: {ntuple} does not exist!")
+if not os.path.isfile(ntuple):
+    causes.append(f"File {ntuple} does not exist!")
 f      = TFile.Open(ntuple)
 t_B    = f.Get('Tuple/EventInfo')
 
@@ -47,17 +51,18 @@ b_names = sorted([b.GetName() for b in t_B.GetListOfLeaves()])
 
 B_excluded_1 = set(B_vars_stored) - set(b_names)
 B_excluded_2 = set(b_names) - set(B_vars_stored)
-if len(B_excluded_1) != 0: raise Exception('Number of stored variables is less than what is expected. The extra variables expected are: ' , B_excluded_1)
-if len(B_excluded_2) != 0: raise Exception('Number of stored variables is greater than what is expected. The extra variables stored are: ', B_excluded_2)
+if len(B_excluded_1) != 0:
+    causes.append(f"Number of stored variables is less than what is expected. The extra variables expected are: {B_excluded_1}")
+if len(B_excluded_2) != 0:
+    causes.append(f"Number of stored variables is greater than what is expected. The extra variables stored are: {B_excluded_2}")
 
 # Check there are no NaN values in the ntuple
 from DaVinciTests.QMTest.check_helpers import has_nan
-assert not has_nan(ntuple, 'Tuple/EventInfo')
+if has_nan(ntuple, 'Tuple/EventInfo'):
+    causes.append("Ntuple contains NaN entries")
 
 f.Close()
 print('Test successfully completed!')
 os.system(f"rm {ntuple}")
-countErrorLines({"FATAL": 0, "WARNING": 0, "ERROR": 0},
-                stdout=remove_known_warnings(stdout))
   </text></argument>
 </extension>
\ No newline at end of file
diff --git a/DaVinciExamples/tests/qmtest/tupling.qms/test_davinci_tupling_SubsPID.qmt b/DaVinciExamples/tests/qmtest/tupling.qms/test_davinci_tupling_SubsPID.qmt
index ea409a2c3..d3a4ee0d4 100644
--- a/DaVinciExamples/tests/qmtest/tupling.qms/test_davinci_tupling_SubsPID.qmt
+++ b/DaVinciExamples/tests/qmtest/tupling.qms/test_davinci_tupling_SubsPID.qmt
@@ -1,7 +1,7 @@
 <?xml version="1.0" ?>
 <!--
 ###############################################################################
-# (c) Copyright 2022 CERN for the benefit of the LHCb Collaboration           #
+# (c) Copyright 2022-2023 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".   #
@@ -25,13 +25,12 @@
 from DaVinciTests.QMTest.DaVinciExclusions import remove_known_warnings
 countErrorLines({"FATAL": 0, "ERROR": 0},
                 stdout=remove_known_warnings(stdout))
+
 import sys, os
 from ROOT import TFile
 
-
 B_vars_stored = ['BUNCHCROSSING_ID', 'BUNCHCROSSING_TYPE', 'B_ENERGY', 'B_ID', 'B_M', 'B_P', 'B_PT', 'Ds_ENERGY', 'Ds_ID', 'Ds_M', 'Ds_P', 'Ds_PT', 'EVENTNUMBER', 'GPSTIME', 'Kminus_ENERGY', 'Kminus_ID', 'Kminus_M', 'Kminus_P', 'Kminus_PT', 'Kplus_ENERGY', 'Kplus_ID', 'Kplus_M', 'Kplus_P', 'Kplus_PT', 'ODINTCK', 'RUNNUMBER', 'piminus_ENERGY', 'piminus_ID', 'piminus_M', 'piminus_P', 'piminus_PT', 'piplus_ENERGY', 'piplus_ID', 'piplus_M', 'piplus_P', 'piplus_PT']
 
-
 #sort the expected vars
 B_vars_stored = sorted(B_vars_stored)
 
@@ -60,6 +59,5 @@ f.Close()
 
 print('Test successfully completed!')
 os.system(f"rm {ntuple}")
-
   </text></argument>
 </extension>
diff --git a/DaVinciExamples/tests/qmtest/tupling.qms/test_davinci_tupling_from_spruce_mc.qmt b/DaVinciExamples/tests/qmtest/tupling.qms/test_davinci_tupling_from_spruce_mc.qmt
index 36cf0198a..65022ae51 100644
--- a/DaVinciExamples/tests/qmtest/tupling.qms/test_davinci_tupling_from_spruce_mc.qmt
+++ b/DaVinciExamples/tests/qmtest/tupling.qms/test_davinci_tupling_from_spruce_mc.qmt
@@ -1,7 +1,7 @@
 <?xml version="1.0" ?>
 <!--
 ###############################################################################
-# (c) Copyright 2022 CERN for the benefit of the LHCb Collaboration           #
+# (c) Copyright 2022-2023 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".   #
@@ -25,30 +25,62 @@
 findReferenceBlock("""Tuple                               SUCCESS Booked 1 N-Tuples and 0 Event Tag Collections"""
 , stdout, result, causes, signature_offset = 0)
 
+countErrorLines({"FATAL":0, "ERROR":0})
+
 import os
-from ROOT import TFile
-#open the TFile and TTree
+from DaVinciTests.QMTest.check_helpers import get_pandas_dataframe, list_fields_with_nan
+
 ntuple = './sprucing_mc_tuple.root'
-ttree_name = 'Tuple/DecayTree'
+
 if not os.path.isfile(ntuple):
-    raise Exception(f"File: {ntuple} does not exist!")
-f = TFile.Open(ntuple)
-t_B = f.Get(ttree_name)
-
-#check if all elements of bkg cat are zero or not
-B0_BKGCAT = [str(entry.B0_BKGCAT) for entry in t_B]
-print('B_BKGCAT: ' + ', '.join(B0_BKGCAT))
-Ds_BKGCAT = [str(entry.Ds_BKGCAT) for entry in t_B]
-print('Ds_BKGCAT: ' + ', '.join(Ds_BKGCAT))
-
-is_all_element_zero = all([v == 0 for v in B0_BKGCAT]) or all(
-    [v == 60 for v in Ds_BKGCAT])
-if is_all_element_zero:
-    raise Exception('MC background association not working')
-
-f.Close()
-print('Test successfully completed!')
+    causes.append(f"File {ntuple} does not exist!")
 
-countErrorLines({"FATAL":0, "ERROR":0})
+df = get_pandas_dataframe(ntuple, 'Tuple/DecayTree')
+
+# Check ntuples structure
+if df.empty:
+    causes.append(f"File {ntuple}: ntuple does not contain any branches")
+if df.shape != (15, 62):
+    causes.append("Ntuple not with expected number of entries and/or branches")
+
+# Check there are no NaN values in the ntuple except where expected
+l_branches_with_nans = ['B0_TRUEENERGY',
+                        'B0_TRUEFOURMOMENTUME',
+			'B0_TRUEFOURMOMENTUMX',
+			'B0_TRUEFOURMOMENTUMY',
+			'B0_TRUEFOURMOMENTUMZ',
+			'B0_TRUEP',
+			'B0_TRUEPT',
+			'B0_TRUEPX',
+			'B0_TRUEPY',
+			'B0_TRUEPZ',
+			'Ds_TRUEENERGY',
+			'Ds_TRUEFOURMOMENTUME',
+			'Ds_TRUEFOURMOMENTUMX',
+			'Ds_TRUEFOURMOMENTUMY',
+			'Ds_TRUEFOURMOMENTUMZ',
+			'Ds_TRUEP',
+			'Ds_TRUEPT',
+			'Ds_TRUEPX',
+			'Ds_TRUEPY',
+			'Ds_TRUEPZ']
+
+l_test = list_fields_with_nan(ntuple, "Tuple/DecayTree")
+if sorted(l_test) != sorted(l_branches_with_nans):
+    causes.append("Unexpected list of branches with NaN values")
+
+# Checks background category values and associated MC-truth PIDs are correctly assigned
+ok = (((df["B0_BKGCAT"].abs() == 20).sum() == 12) and
+      (df["Kp_BKGCAT"] == -1).all() and
+      ((df["B0_TRUEID"].abs() == 531).sum() == 13) and
+      ((df["Ds_TRUEID"].abs() == 431).sum() == 14) and
+      ((df["Ds_TRUEID"] == 0).sum() == 1) and
+      (df["Kp_TRUEID"] != 0).all()
+     )
+if not ok:
+    causes.append("Ntuple contains unexpected BKGCAT and/or TRUEID values")
+
+print('Test successfully completed!')
+os.system(f"rm {ntuple}")
 </text></argument>
 </extension>
diff --git a/DaVinciExamples/tests/qmtest/tupling.qms/test_example-tupling-basic-run-mc.qmt b/DaVinciExamples/tests/qmtest/tupling.qms/test_example-tupling-basic-run-mc.qmt
index 3e20965f9..22b15a94f 100755
--- a/DaVinciExamples/tests/qmtest/tupling.qms/test_example-tupling-basic-run-mc.qmt
+++ b/DaVinciExamples/tests/qmtest/tupling.qms/test_example-tupling-basic-run-mc.qmt
@@ -1,7 +1,7 @@
 <?xml version="1.0" ?>
 <!--
 ###############################################################################
-# (c) Copyright 2020-2021 CERN for the benefit of the LHCb Collaboration      #
+# (c) Copyright 2020-2023 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".   #
@@ -31,5 +31,28 @@
 from DaVinciTests.QMTest.DaVinciExclusions import preprocessor, counter_preprocessor
 validateWithReference(preproc = preprocessor, counter_preproc = counter_preprocessor)
 countErrorLines({"FATAL":0, "ERROR":0})
+
+import os
+from DaVinciTests.QMTest.check_helpers import get_pandas_dataframe, df_has_nan
+
+ntuple  = './DV-example-tupling-basic-ntp-run-mc.root'
+
+if not os.path.isfile(ntuple):
+    causes.append(f"File {ntuple} does not exist!")
+
+df = get_pandas_dataframe(ntuple, 'DimuonsTuple/DecayTree')
+
+# Check ntuple structure
+if df.empty:
+    causes.append(f"File {ntuple}: ntuple does not contain any branches")
+if df.shape != (16, 12):
+    causes.append("Ntuple not with expected number of entries and/or branches")
+
+# Check there are no NaN values in the ntuple
+if df_has_nan(df):
+    causes.append("Ntuple contains NaN entries")
+
+print('Test successfully completed!')
+os.system(f"rm {ntuple}")
   </text></argument>
 </extension>
diff --git a/DaVinciExamples/tests/qmtest/tupling.qms/test_example-tupling-basic.qmt b/DaVinciExamples/tests/qmtest/tupling.qms/test_example-tupling-basic.qmt
index f829ca10e..29a0a30fe 100644
--- a/DaVinciExamples/tests/qmtest/tupling.qms/test_example-tupling-basic.qmt
+++ b/DaVinciExamples/tests/qmtest/tupling.qms/test_example-tupling-basic.qmt
@@ -1,7 +1,7 @@
 <?xml version="1.0" ?>
 <!--
 ###############################################################################
-# (c) Copyright 2020-2021 CERN for the benefit of the LHCb Collaboration      #
+# (c) Copyright 2020-2023 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".   #
@@ -35,22 +35,39 @@ TFile: name=DV-example-tupling-basic-ntp.root, title=Gaudi Trees, option=CREATE
 """, stdout, result, causes, signature_offset = 0)
 countErrorLines({"FATAL":0, "ERROR":0})
 
-import sys, os, glob
-import ROOT as r
-from ROOT import TFile
-
-try:
-    ntuple = 'DV-example-tupling-basic-ntp.root'
-    f = TFile.Open(ntuple)
-    if f.IsZombie():
-        raise AttributeError('Output ROOT file is Zombie')
-    print('-- DV-example-tupling-basic-ntp.root QMTest -- : found output NTuple')
-    f.Close()
-    os.system('rm %s' %ntuple)
-except IOError as err:
-    raise IOError('Impossible to open file: ', err)
-except:
-    raise Exception('Unexpected error while opening file: ')
+import os
+from DaVinciTests.QMTest.check_helpers import get_pandas_dataframe, df_has_nan
+
+ntuple  = './DV-example-tupling-basic-ntp.root'
+
+
+if not os.path.isfile(ntuple):
+    causes.append(f"File {ntuple} does not exist!")
+
+df1 = get_pandas_dataframe(ntuple, 'DimuonsTuple/DecayTree')
+df2 = get_pandas_dataframe(ntuple, 'KsTuple/DecayTree')
+
+# Check ntuples structure
+if df1.empty:
+    causes.append(f"File {ntuple}: ntuple 'DimuonsTuple/DecayTree' does not contain any branches")
+if df2.empty: 
+    causes.append(f"File: {ntuple}: ntuple 'KsTuple/DecayTree' does not contain any branches")
+if df1.shape != (16, 12):
+    causes.append("Ntuple 'DimuonsTuple/DecayTree' not with expected number of entries and/or branches")
+# FIXME: check disabled because 8(7) candidates are tupled with(out) DD4hep!
+# No appetite to investigate since we should soon update the input files used.
+#if df2.shape != (8, 10):
+#    causes.append("Ntuple 'KsTuple/DecayTree' not with expected number of entries and/or branches")
+
+# Check there are no NaN values in the ntuples
+if df_has_nan(df1):
+    causes.append("Ntuple 'DimuonsTuple/DecayTree' contains NaN entries")
+if df_has_nan(df2):
+    causes.append("Ntuple 'KsTuple/DecayTree' contains NaN entries")
+
+print('Test successfully completed!')
+#os.system(f"rm {ntuple}")
+#os.system(f"rm {ntuple_new}")
 <argument name="exit_code"><integer>1</integer></argument>
 </text></argument>
 </extension>
diff --git a/DaVinciExamples/tests/refs/test_davinci_tupling_array_taggers.ref b/DaVinciExamples/tests/refs/test_davinci_tupling_array_taggers.ref
index 9d1c3b740..6b3fd43d3 100644
--- a/DaVinciExamples/tests/refs/test_davinci_tupling_array_taggers.ref
+++ b/DaVinciExamples/tests/refs/test_davinci_tupling_array_taggers.ref
@@ -6,12 +6,12 @@ NTupleSvc                              INFO Added stream file:DV-example-tagger-
 RootHistSvc                            INFO Writing ROOT histograms to: DV-example-tagger-ntp.root
 HistogramPersistencySvc                INFO Added successfully Conversion service:RootHistSvc
 FSROutputStreamDstWriter               INFO Data source: EventDataSvc output: SVC='Gaudi::RootCnvSvc'
-MCTruthAndBkgCatAlg#1.DaVinciSma...    INFO Will look into [/Event/Spruce/HLT2/Relations/ChargedPP2MCP, /Event/Spruce/HLT2/Relations/NeutralPP2MCP]
-MCTruthAndBkgCatAlg#1.DaVinciSma...    INFO Will look into [/Event/Spruce/HLT2/Relations/ChargedPP2MCP, /Event/Spruce/HLT2/Relations/NeutralPP2MCP]
-MCTruthAndBkgCatAlg#1.Background...    INFO Will look into [/Event/Spruce/HLT2/Relations/ChargedPP2MCP, /Event/Spruce/HLT2/Relations/NeutralPP2MCP]
-MCTruthAndBkgCatAlg#2.DaVinciSma...    INFO Will look into [/Event/Spruce/HLT2/Relations/ChargedPP2MCP, /Event/Spruce/HLT2/Relations/NeutralPP2MCP]
-MCTruthAndBkgCatAlg#2.DaVinciSma...    INFO Will look into [/Event/Spruce/HLT2/Relations/ChargedPP2MCP, /Event/Spruce/HLT2/Relations/NeutralPP2MCP]
-MCTruthAndBkgCatAlg#2.Background...    INFO Will look into [/Event/Spruce/HLT2/Relations/ChargedPP2MCP, /Event/Spruce/HLT2/Relations/NeutralPP2MCP]
+MCTruthAndBkgCatAlg#1.DaVinciSma...    INFO Will look into protoparticle locations [/Event/Spruce/HLT2/Relations/ChargedPP2MCP, /Event/Spruce/HLT2/Relations/NeutralPP2MCP]
+MCTruthAndBkgCatAlg#1.DaVinciSma...    INFO Will look into protoparticle locations [/Event/Spruce/HLT2/Relations/ChargedPP2MCP, /Event/Spruce/HLT2/Relations/NeutralPP2MCP]
+MCTruthAndBkgCatAlg#1.Background...    INFO Will look into protoparticle locations [/Event/Spruce/HLT2/Relations/ChargedPP2MCP, /Event/Spruce/HLT2/Relations/NeutralPP2MCP]
+MCTruthAndBkgCatAlg#2.DaVinciSma...    INFO Will look into protoparticle locations [/Event/Spruce/HLT2/Relations/ChargedPP2MCP, /Event/Spruce/HLT2/Relations/NeutralPP2MCP]
+MCTruthAndBkgCatAlg#2.DaVinciSma...    INFO Will look into protoparticle locations [/Event/Spruce/HLT2/Relations/ChargedPP2MCP, /Event/Spruce/HLT2/Relations/NeutralPP2MCP]
+MCTruthAndBkgCatAlg#2.Background...    INFO Will look into protoparticle locations [/Event/Spruce/HLT2/Relations/ChargedPP2MCP, /Event/Spruce/HLT2/Relations/NeutralPP2MCP]
 ApplicationMgr                         INFO Application Manager Initialized successfully
 ApplicationMgr                         INFO Application Manager Started successfully
 EventPersistencySvc                    INFO Added successfully Conversion service:RootCnvSvc
diff --git a/DaVinciExamples/tests/refs/test_davinci_tupling_array_taggers.ref.detdesc b/DaVinciExamples/tests/refs/test_davinci_tupling_array_taggers.ref.detdesc
index 9d1c3b740..6b3fd43d3 100644
--- a/DaVinciExamples/tests/refs/test_davinci_tupling_array_taggers.ref.detdesc
+++ b/DaVinciExamples/tests/refs/test_davinci_tupling_array_taggers.ref.detdesc
@@ -6,12 +6,12 @@ NTupleSvc                              INFO Added stream file:DV-example-tagger-
 RootHistSvc                            INFO Writing ROOT histograms to: DV-example-tagger-ntp.root
 HistogramPersistencySvc                INFO Added successfully Conversion service:RootHistSvc
 FSROutputStreamDstWriter               INFO Data source: EventDataSvc output: SVC='Gaudi::RootCnvSvc'
-MCTruthAndBkgCatAlg#1.DaVinciSma...    INFO Will look into [/Event/Spruce/HLT2/Relations/ChargedPP2MCP, /Event/Spruce/HLT2/Relations/NeutralPP2MCP]
-MCTruthAndBkgCatAlg#1.DaVinciSma...    INFO Will look into [/Event/Spruce/HLT2/Relations/ChargedPP2MCP, /Event/Spruce/HLT2/Relations/NeutralPP2MCP]
-MCTruthAndBkgCatAlg#1.Background...    INFO Will look into [/Event/Spruce/HLT2/Relations/ChargedPP2MCP, /Event/Spruce/HLT2/Relations/NeutralPP2MCP]
-MCTruthAndBkgCatAlg#2.DaVinciSma...    INFO Will look into [/Event/Spruce/HLT2/Relations/ChargedPP2MCP, /Event/Spruce/HLT2/Relations/NeutralPP2MCP]
-MCTruthAndBkgCatAlg#2.DaVinciSma...    INFO Will look into [/Event/Spruce/HLT2/Relations/ChargedPP2MCP, /Event/Spruce/HLT2/Relations/NeutralPP2MCP]
-MCTruthAndBkgCatAlg#2.Background...    INFO Will look into [/Event/Spruce/HLT2/Relations/ChargedPP2MCP, /Event/Spruce/HLT2/Relations/NeutralPP2MCP]
+MCTruthAndBkgCatAlg#1.DaVinciSma...    INFO Will look into protoparticle locations [/Event/Spruce/HLT2/Relations/ChargedPP2MCP, /Event/Spruce/HLT2/Relations/NeutralPP2MCP]
+MCTruthAndBkgCatAlg#1.DaVinciSma...    INFO Will look into protoparticle locations [/Event/Spruce/HLT2/Relations/ChargedPP2MCP, /Event/Spruce/HLT2/Relations/NeutralPP2MCP]
+MCTruthAndBkgCatAlg#1.Background...    INFO Will look into protoparticle locations [/Event/Spruce/HLT2/Relations/ChargedPP2MCP, /Event/Spruce/HLT2/Relations/NeutralPP2MCP]
+MCTruthAndBkgCatAlg#2.DaVinciSma...    INFO Will look into protoparticle locations [/Event/Spruce/HLT2/Relations/ChargedPP2MCP, /Event/Spruce/HLT2/Relations/NeutralPP2MCP]
+MCTruthAndBkgCatAlg#2.DaVinciSma...    INFO Will look into protoparticle locations [/Event/Spruce/HLT2/Relations/ChargedPP2MCP, /Event/Spruce/HLT2/Relations/NeutralPP2MCP]
+MCTruthAndBkgCatAlg#2.Background...    INFO Will look into protoparticle locations [/Event/Spruce/HLT2/Relations/ChargedPP2MCP, /Event/Spruce/HLT2/Relations/NeutralPP2MCP]
 ApplicationMgr                         INFO Application Manager Initialized successfully
 ApplicationMgr                         INFO Application Manager Started successfully
 EventPersistencySvc                    INFO Added successfully Conversion service:RootCnvSvc
diff --git a/DaVinciExamples/tests/refs/test_davinci_tupling_from_hlt2.ref b/DaVinciExamples/tests/refs/test_davinci_tupling_from_hlt2.ref
index ed5db584b..c7db7b6c5 100644
--- a/DaVinciExamples/tests/refs/test_davinci_tupling_from_hlt2.ref
+++ b/DaVinciExamples/tests/refs/test_davinci_tupling_from_hlt2.ref
@@ -6,9 +6,9 @@ NTupleSvc                              INFO Added stream file:tuple_D0_Kpi_10evt
 RootHistSvc                            INFO Writing ROOT histograms to: tuple_D0_Kpi_10evts_fromHlt2_ntuples.root
 HistogramPersistencySvc                INFO Added successfully Conversion service:RootHistSvc
 FSROutputStreamDstWriter               INFO Data source: EventDataSvc output: SVC='Gaudi::RootCnvSvc'
-MCTruthAndBkgCatAlg#1.DaVinciSma...    INFO Will look into [/Event/HLT2/Relations/ChargedPP2MCP, /Event/HLT2/Relations/NeutralPP2MCP]
-MCTruthAndBkgCatAlg#1.DaVinciSma...    INFO Will look into [/Event/HLT2/Relations/ChargedPP2MCP, /Event/HLT2/Relations/NeutralPP2MCP]
-MCTruthAndBkgCatAlg#1.Background...    INFO Will look into [/Event/HLT2/Relations/ChargedPP2MCP, /Event/HLT2/Relations/NeutralPP2MCP]
+MCTruthAndBkgCatAlg#1.DaVinciSma...    INFO Will look into protoparticle locations [/Event/HLT2/Relations/ChargedPP2MCP, /Event/HLT2/Relations/NeutralPP2MCP]
+MCTruthAndBkgCatAlg#1.DaVinciSma...    INFO Will look into protoparticle locations [/Event/HLT2/Relations/ChargedPP2MCP, /Event/HLT2/Relations/NeutralPP2MCP]
+MCTruthAndBkgCatAlg#1.Background...    INFO Will look into protoparticle locations [/Event/HLT2/Relations/ChargedPP2MCP, /Event/HLT2/Relations/NeutralPP2MCP]
 ApplicationMgr                         INFO Application Manager Initialized successfully
 ApplicationMgr                         INFO Application Manager Started successfully
 EventPersistencySvc                    INFO Added successfully Conversion service:RootCnvSvc
diff --git a/DaVinciExamples/tests/refs/test_davinci_tupling_from_hlt2.ref.detdesc b/DaVinciExamples/tests/refs/test_davinci_tupling_from_hlt2.ref.detdesc
index ed5db584b..c7db7b6c5 100644
--- a/DaVinciExamples/tests/refs/test_davinci_tupling_from_hlt2.ref.detdesc
+++ b/DaVinciExamples/tests/refs/test_davinci_tupling_from_hlt2.ref.detdesc
@@ -6,9 +6,9 @@ NTupleSvc                              INFO Added stream file:tuple_D0_Kpi_10evt
 RootHistSvc                            INFO Writing ROOT histograms to: tuple_D0_Kpi_10evts_fromHlt2_ntuples.root
 HistogramPersistencySvc                INFO Added successfully Conversion service:RootHistSvc
 FSROutputStreamDstWriter               INFO Data source: EventDataSvc output: SVC='Gaudi::RootCnvSvc'
-MCTruthAndBkgCatAlg#1.DaVinciSma...    INFO Will look into [/Event/HLT2/Relations/ChargedPP2MCP, /Event/HLT2/Relations/NeutralPP2MCP]
-MCTruthAndBkgCatAlg#1.DaVinciSma...    INFO Will look into [/Event/HLT2/Relations/ChargedPP2MCP, /Event/HLT2/Relations/NeutralPP2MCP]
-MCTruthAndBkgCatAlg#1.Background...    INFO Will look into [/Event/HLT2/Relations/ChargedPP2MCP, /Event/HLT2/Relations/NeutralPP2MCP]
+MCTruthAndBkgCatAlg#1.DaVinciSma...    INFO Will look into protoparticle locations [/Event/HLT2/Relations/ChargedPP2MCP, /Event/HLT2/Relations/NeutralPP2MCP]
+MCTruthAndBkgCatAlg#1.DaVinciSma...    INFO Will look into protoparticle locations [/Event/HLT2/Relations/ChargedPP2MCP, /Event/HLT2/Relations/NeutralPP2MCP]
+MCTruthAndBkgCatAlg#1.Background...    INFO Will look into protoparticle locations [/Event/HLT2/Relations/ChargedPP2MCP, /Event/HLT2/Relations/NeutralPP2MCP]
 ApplicationMgr                         INFO Application Manager Initialized successfully
 ApplicationMgr                         INFO Application Manager Started successfully
 EventPersistencySvc                    INFO Added successfully Conversion service:RootCnvSvc
diff --git a/DaVinciExamples/tests/refs/test_davinci_tupling_unreconstructed_info.ref b/DaVinciExamples/tests/refs/test_davinci_tupling_unreconstructed_info.ref
index cab6d738a..a01b727b2 100644
--- a/DaVinciExamples/tests/refs/test_davinci_tupling_unreconstructed_info.ref
+++ b/DaVinciExamples/tests/refs/test_davinci_tupling_unreconstructed_info.ref
@@ -22,9 +22,9 @@ HLTControlFlowMgr                      INFO Start initialization
 RootHistSvc                            INFO Writing ROOT histograms to: mytuple.root
 HistogramPersistencySvc                INFO Added successfully Conversion service:RootHistSvc
 FSROutputStreamDstWriter               INFO Data source: EventDataSvc output: SVC='Gaudi::RootCnvSvc'
-MCTruthAndBkgCatAlg#1.DaVinciSma...    INFO Will look into [/Event/HLT2/Relations/ChargedPP2MCP, /Event/HLT2/Relations/NeutralPP2MCP]
-MCTruthAndBkgCatAlg#1.DaVinciSma...    INFO Will look into [/Event/HLT2/Relations/ChargedPP2MCP, /Event/HLT2/Relations/NeutralPP2MCP]
-MCTruthAndBkgCatAlg#1.Background...    INFO Will look into [/Event/HLT2/Relations/ChargedPP2MCP, /Event/HLT2/Relations/NeutralPP2MCP]
+MCTruthAndBkgCatAlg#1.DaVinciSma...    INFO Will look into protoparticle locations [/Event/HLT2/Relations/ChargedPP2MCP, /Event/HLT2/Relations/NeutralPP2MCP]
+MCTruthAndBkgCatAlg#1.DaVinciSma...    INFO Will look into protoparticle locations [/Event/HLT2/Relations/ChargedPP2MCP, /Event/HLT2/Relations/NeutralPP2MCP]
+MCTruthAndBkgCatAlg#1.Background...    INFO Will look into protoparticle locations [/Event/HLT2/Relations/ChargedPP2MCP, /Event/HLT2/Relations/NeutralPP2MCP]
 HiveDataBrokerSvc                   WARNING non-reentrant algorithm: RecordStream/FSROutputStreamDstWriter
 HLTControlFlowMgr                      INFO Concurrency level information:
 HLTControlFlowMgr                      INFO  o Number of events slots: 1
diff --git a/DaVinciExamples/tests/refs/test_davinci_tupling_unreconstructed_info.ref.detdesc b/DaVinciExamples/tests/refs/test_davinci_tupling_unreconstructed_info.ref.detdesc
index cab6d738a..a01b727b2 100644
--- a/DaVinciExamples/tests/refs/test_davinci_tupling_unreconstructed_info.ref.detdesc
+++ b/DaVinciExamples/tests/refs/test_davinci_tupling_unreconstructed_info.ref.detdesc
@@ -22,9 +22,9 @@ HLTControlFlowMgr                      INFO Start initialization
 RootHistSvc                            INFO Writing ROOT histograms to: mytuple.root
 HistogramPersistencySvc                INFO Added successfully Conversion service:RootHistSvc
 FSROutputStreamDstWriter               INFO Data source: EventDataSvc output: SVC='Gaudi::RootCnvSvc'
-MCTruthAndBkgCatAlg#1.DaVinciSma...    INFO Will look into [/Event/HLT2/Relations/ChargedPP2MCP, /Event/HLT2/Relations/NeutralPP2MCP]
-MCTruthAndBkgCatAlg#1.DaVinciSma...    INFO Will look into [/Event/HLT2/Relations/ChargedPP2MCP, /Event/HLT2/Relations/NeutralPP2MCP]
-MCTruthAndBkgCatAlg#1.Background...    INFO Will look into [/Event/HLT2/Relations/ChargedPP2MCP, /Event/HLT2/Relations/NeutralPP2MCP]
+MCTruthAndBkgCatAlg#1.DaVinciSma...    INFO Will look into protoparticle locations [/Event/HLT2/Relations/ChargedPP2MCP, /Event/HLT2/Relations/NeutralPP2MCP]
+MCTruthAndBkgCatAlg#1.DaVinciSma...    INFO Will look into protoparticle locations [/Event/HLT2/Relations/ChargedPP2MCP, /Event/HLT2/Relations/NeutralPP2MCP]
+MCTruthAndBkgCatAlg#1.Background...    INFO Will look into protoparticle locations [/Event/HLT2/Relations/ChargedPP2MCP, /Event/HLT2/Relations/NeutralPP2MCP]
 HiveDataBrokerSvc                   WARNING non-reentrant algorithm: RecordStream/FSROutputStreamDstWriter
 HLTControlFlowMgr                      INFO Concurrency level information:
 HLTControlFlowMgr                      INFO  o Number of events slots: 1
diff --git a/DaVinciTests/python/DaVinciTests/filters.py b/DaVinciTests/python/DaVinciTests/filters.py
index 56ac7fcba..cacdc9e74 100644
--- a/DaVinciTests/python/DaVinciTests/filters.py
+++ b/DaVinciTests/python/DaVinciTests/filters.py
@@ -1,5 +1,5 @@
 ###############################################################################
-# (c) Copyright 2021-2022 CERN for the benefit of the LHCb Collaboration      #
+# (c) Copyright 2021-2023 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".   #
@@ -9,7 +9,7 @@
 # or submit itself to any jurisdiction.                                       #
 ###############################################################################
 """
-Read the output of an Sprucing job with the new DaVinci configuration.
+Read the output of a Sprucing job in DaVinci with line specific filters.
 """
 from DaVinci.algorithms import add_filter
 from DaVinci import Options, make_config
diff --git a/DaVinciTests/tests/qmtest/davinci.qms/test_davinci_filters.qmt b/DaVinciTests/tests/qmtest/davinci.qms/test_davinci_filters.qmt
index 73fcd987c..b387e983d 100644
--- a/DaVinciTests/tests/qmtest/davinci.qms/test_davinci_filters.qmt
+++ b/DaVinciTests/tests/qmtest/davinci.qms/test_davinci_filters.qmt
@@ -1,7 +1,7 @@
 <?xml version="1.0" ?>
 <!--
 ###############################################################################
-# (c) Copyright 2021 CERN for the benefit of the LHCb Collaboration           #
+# (c) Copyright 2021-2023 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".   #
@@ -22,8 +22,8 @@
   <argument name="extra_options_yaml"><text>
     evt_pre_filters:
       Hlt2TopoLineFilter: "HLT_PASS('Hlt2Topo2BodyLineDecision')"
-    ntuple_file: "ntuple_filter.root"
-    histo_file: "histo_filter.root"
+    ntuple_file: "davinci_filters_ntuple.root"
+    histo_file: "davinci_filters_histos.root"
     print_freq: 1
   </text></argument>
   <argument name="reference"><text>../refs/test_davinci_filters.ref</text></argument>
@@ -31,5 +31,7 @@
   <argument name="validator"><text>
 from DaVinciTests.QMTest.DaVinciExclusions import preprocessor, counter_preprocessor
 validateWithReference(preproc = preprocessor, counter_preproc = counter_preprocessor)
+
+countErrorLines({"FATAL":0, "ERROR":0})
   </text></argument>
 </extension>
diff --git a/DaVinciTests/tests/qmtest/davinci.qms/test_davinci_recVertices.qmt b/DaVinciTests/tests/qmtest/davinci.qms/test_davinci_recVertices.qmt
index aefbb934e..f8e0aaef2 100644
--- a/DaVinciTests/tests/qmtest/davinci.qms/test_davinci_recVertices.qmt
+++ b/DaVinciTests/tests/qmtest/davinci.qms/test_davinci_recVertices.qmt
@@ -35,6 +35,7 @@ countErrorLines({"FATAL":0, "ERROR":0})
 
 # Check there are no NaN values in the ntuple
 from DaVinciTests.QMTest.check_helpers import has_nan
-assert not has_nan("test_recVertices.root", "B0DsK_Tuple/DecayTree")
+if has_nan("test_recVertices.root", "B0DsK_Tuple/DecayTree"):
+    causes.append("Ntuple contains NaN entries")
   </text></argument>
 </extension>
diff --git a/DaVinciTests/tests/refs/test_davinci_filters.ref b/DaVinciTests/tests/refs/test_davinci_filters.ref
index 2431ec373..2017c245f 100644
--- a/DaVinciTests/tests/refs/test_davinci_filters.ref
+++ b/DaVinciTests/tests/refs/test_davinci_filters.ref
@@ -2,8 +2,8 @@ ApplicationMgr    SUCCESS
 ====================================================================================================================================
 ====================================================================================================================================
 ApplicationMgr       INFO Application Manager Configured successfully
-NTupleSvc                              INFO Added stream file:ntuple_filter.root as FILE1
-RootHistSvc                            INFO Writing ROOT histograms to: ntuple_filter.root
+NTupleSvc                              INFO Added stream file:davinci_filters_ntuple.root as FILE1
+RootHistSvc                            INFO Writing ROOT histograms to: davinci_filters_ntuple.root
 HistogramPersistencySvc                INFO Added successfully Conversion service:RootHistSvc
 FSROutputStreamDstWriter               INFO Data source: EventDataSvc output: SVC='Gaudi::RootCnvSvc'
 ApplicationMgr                         INFO Application Manager Initialized successfully
diff --git a/DaVinciTests/tests/refs/test_davinci_filters.ref.detdesc b/DaVinciTests/tests/refs/test_davinci_filters.ref.detdesc
index 2431ec373..2017c245f 100644
--- a/DaVinciTests/tests/refs/test_davinci_filters.ref.detdesc
+++ b/DaVinciTests/tests/refs/test_davinci_filters.ref.detdesc
@@ -2,8 +2,8 @@ ApplicationMgr    SUCCESS
 ====================================================================================================================================
 ====================================================================================================================================
 ApplicationMgr       INFO Application Manager Configured successfully
-NTupleSvc                              INFO Added stream file:ntuple_filter.root as FILE1
-RootHistSvc                            INFO Writing ROOT histograms to: ntuple_filter.root
+NTupleSvc                              INFO Added stream file:davinci_filters_ntuple.root as FILE1
+RootHistSvc                            INFO Writing ROOT histograms to: davinci_filters_ntuple.root
 HistogramPersistencySvc                INFO Added successfully Conversion service:RootHistSvc
 FSROutputStreamDstWriter               INFO Data source: EventDataSvc output: SVC='Gaudi::RootCnvSvc'
 ApplicationMgr                         INFO Application Manager Initialized successfully
diff --git a/DaVinciTutorials/tests/qmtest/test_tutorial1_functors_specialfield.qmt b/DaVinciTutorials/tests/qmtest/test_tutorial1_functors_specialfield.qmt
index c3485ed24..097024329 100644
--- a/DaVinciTutorials/tests/qmtest/test_tutorial1_functors_specialfield.qmt
+++ b/DaVinciTutorials/tests/qmtest/test_tutorial1_functors_specialfield.qmt
@@ -42,11 +42,14 @@ if not os.path.isfile(ntuple): raise Exception(f"File {ntuple} does not exist!")
 df = get_pandas_dataframe(ntuple, 'TDirectoryName/TTreeName')
 
 # Check ntuple structure
-if df.empty: raise Exception(f"File {ntuple}: ntuple does not contain any branches. Please check.")
-assert df.shape == (30, 22)
+if df.empty:
+    raise Exception(f"File {ntuple}: ntuple does not contain any branches")
+if df.shape != (30, 22):
+    causes.append("Ntuple not with expected number of entries and/or branches")
 
 # Check there are no NaN values in the ntuple
-assert not df_has_nan(df)
+if df_has_nan(df):
+    causes.append("Ntuple contains NaN entries")
 
 print('Test successfully completed!')
 os.system(f"rm {ntuple}")
diff --git a/DaVinciTutorials/tests/qmtest/test_tutorial2_LoKi.qmt b/DaVinciTutorials/tests/qmtest/test_tutorial2_LoKi.qmt
index 5534b317f..78d8ed1ad 100644
--- a/DaVinciTutorials/tests/qmtest/test_tutorial2_LoKi.qmt
+++ b/DaVinciTutorials/tests/qmtest/test_tutorial2_LoKi.qmt
@@ -37,16 +37,20 @@ ntuple  = './tutorial2_LoKi.root'
 #this file should be disabled
 ntuple_new  = './tutorial2_LoKi_new.root'
 
-if not os.path.isfile(ntuple): raise Exception(f"File {ntuple} does not exist!")
+if not os.path.isfile(ntuple):
+    causes.append(f"File {ntuple} does not exist!")
 
 df = get_pandas_dataframe(ntuple, 'TDirectoryName/TTreeName')
 
 # Check ntuple structure
-if df.empty: raise Exception(f"File {ntuple}: ntuple does not contain any branches. Please check.")
-assert df.shape == (30, 50)
+if df.empty:
+    causes.append(f"File {ntuple}: ntuple does not contain any branches")
+if df.shape != (30, 50):
+    causes.append("Ntuple not with expected number of entries and/or branches")
 
 # Check there are no NaN values in the ntuple
-assert not df_has_nan(df)
+if df_has_nan(df):
+    causes.append("Ntuple contains NaN entries")
 
 print('Test successfully completed!')
 os.system(f"rm {ntuple}")
diff --git a/DaVinciTutorials/tests/qmtest/test_tutorial3_ThOrfunctors.qmt b/DaVinciTutorials/tests/qmtest/test_tutorial3_ThOrfunctors.qmt
index 13a40dcf0..5bc265685 100644
--- a/DaVinciTutorials/tests/qmtest/test_tutorial3_ThOrfunctors.qmt
+++ b/DaVinciTutorials/tests/qmtest/test_tutorial3_ThOrfunctors.qmt
@@ -37,21 +37,24 @@ ntuple  = './tutorial3_ThOrfunctors.root'
 #this file should be disabled
 ntuple_new  = './tutorial3_ThOrfunctors_new.root'
 
-if not os.path.isfile(ntuple): raise Exception(f"File {ntuple} does not exist!")
+if not os.path.isfile(ntuple):
+    causes.append(f"File {ntuple} does not exist!")
 
 df = get_pandas_dataframe(ntuple, 'TDirectoryName/TTreeName')
 
 # Check ntuple structure
-if df.empty: raise Exception(f"File {ntuple}: ntuple does not contain any branches. Please check.")
-assert df.shape == (30, 26)
+if df.empty:
+    causes.append(f"File {ntuple}: ntuple does not contain any branches")
+if df.shape != (30, 26):
+    causes.append("Ntuple not with expected number of entries and/or branches")
 
 # Check there are no NaN values in the ntuple
-assert not df_has_nan(df)
+if df_has_nan(df):
+    causes.append("Ntuple contains NaN entries")
 
 # Checks PIDs are correctly assigned
-assert (df["Bs_Kp_ID"].abs() == 321).all()
-assert (df["Bs_jpsi_ID"].abs() == 443).all()
-assert (df["Bs_phi_ID"].abs() == 333).all()
+if not ( (df["Bs_Kp_ID"].abs() == 321).all() and (df["Bs_jpsi_ID"].abs() == 443).all() and (df["Bs_phi_ID"].abs() == 333).all() ):
+    causes.append("Ntuple contains unexpected PID values")
 
 print('Test successfully completed!')
 os.system(f"rm {ntuple}")
diff --git a/DaVinciTutorials/tests/qmtest/test_tutorial4_trigger_eventinfo.qmt b/DaVinciTutorials/tests/qmtest/test_tutorial4_trigger_eventinfo.qmt
index 61b9fcb8d..430c64436 100644
--- a/DaVinciTutorials/tests/qmtest/test_tutorial4_trigger_eventinfo.qmt
+++ b/DaVinciTutorials/tests/qmtest/test_tutorial4_trigger_eventinfo.qmt
@@ -37,19 +37,24 @@ ntuple  = './tutorial4_trigger_eventinfo.root'
 #this file should be disabled
 ntuple_new  = './tutorial4_trigger_eventinfo_new.root'
 
-if not os.path.isfile(ntuple): raise Exception(f"File {ntuple} does not exist!")
+if not os.path.isfile(ntuple):
+    causes.append(f"File {ntuple} does not exist!")
 
 df = get_pandas_dataframe(ntuple, 'TDirectoryName/TTreeName')
 
 # Check ntuple structure
-if df.empty: raise Exception(f"File {ntuple}: ntuple does not contain any branches. Please check.")
-assert df.shape == (30, 12)
+if df.empty:
+    causes.append(f"File {ntuple}: ntuple does not contain any branches")
+if df.shape != (30, 12):
+    causes.append("Ntuple not with expected number of entries and/or branches")
 
 # Check there are no NaN values in the ntuple
-assert not df_has_nan(df)
+if df_has_nan(df):
+    causes.append("Ntuple contains NaN entries")
 
 # Checks PIDs are correctly assigned
-assert (df["Bs_ID"] == 531).all()
+if not (df["Bs_ID"] == 531).all():
+    causes.append("Ntuple contains unexpected Bs_ID values")
 
 print('Test successfully completed!')
 os.system(f"rm {ntuple}")
diff --git a/DaVinciTutorials/tests/qmtest/test_tutorial5_MCTruth.qmt b/DaVinciTutorials/tests/qmtest/test_tutorial5_MCTruth.qmt
index da920daf1..d890f93e3 100644
--- a/DaVinciTutorials/tests/qmtest/test_tutorial5_MCTruth.qmt
+++ b/DaVinciTutorials/tests/qmtest/test_tutorial5_MCTruth.qmt
@@ -37,29 +37,36 @@ ntuple  = './tutorial5_MCTruth.root'
 #this file should be disabled
 ntuple_new  = './tutorial5_MCTruth_new.root'
 
-if not os.path.isfile(ntuple): raise Exception(f"File {ntuple} does not exist!")
+if not os.path.isfile(ntuple):
+    causes.append(f"File {ntuple} does not exist!")
 
 df = get_pandas_dataframe(ntuple, 'TDirectoryName/TTreeName')
 
 # Check ntuple structure
-if df.empty: raise Exception(f"File {ntuple}: ntuple does not contain any branches. Please check.")
-assert df.shape == (30, 39)
+if df.empty:
+    causes.append(f"File {ntuple}: ntuple does not contain any branches")
+if df.shape != (30, 39):
+    causes.append("Ntuple not with expected number of entries and/or branches")
 
 # Check there are no NaN values in the ntuple except where expected
 from DaVinciTests.QMTest.check_helpers import list_fields_with_nan
 l_branches_with_nans = ['Bs_TRUEP', 'Jpsi_TRUEP', 'Phi_TRUEP', 'Mup_TRUEP', 'Mum_TRUEP', 'Kp_TRUEEPHI', 'Kp_TRUEP', 'Km_TRUEP']
 l_test = list_fields_with_nan(ntuple, 'TDirectoryName/TTreeName')
-assert sorted(l_test) == sorted(l_branches_with_nans)
+if sorted(l_test) != sorted(l_branches_with_nans):
+    causes.append("Unexpected list of branches with NaN values")
 
 # Checks PIDs are correctly assigned
-# TODO: these values are not OK and need to be fixed, cf. for example issue https://gitlab.cern.ch/lhcb/DaVinci/-/issues/100
-assert (df.filter(regex=("[B|J|P].*TRUEID"))==0).any().any()  # no matched MC
-assert (df.filter(regex=("K.*TRUEID"))==0).any().any()  # no matched kaons
-assert (df.filter(regex=("Mu.*TRUEID")).abs()!=13).any().any()  # no true muons
+if not ((df.filter(regex=("[B|J|P].*TRUEID"))==0).all().all()  # no matched MC
+        and ( (df["Km_TRUEID"].abs()==0).sum() + (df["Kp_TRUEID"].abs()==0).sum() == 14 )
+        and ( (df["Mum_TRUEID"].abs()==0).sum() + (df["Mup_TRUEID"].abs()==0).sum() == 3 )
+       ):
+    causes.append("Ntuple contains unexpected TRUEID values")
 
 # Check background categories
-assert (df.filter(regex=("[B|J|P].*BKGCAT"))!=0).any().any()  # no signal
-assert (df.filter(regex=("[K|Mu].*BKGCAT"))==-1).all().all()  # for kaons and muons, all entries are -1
+if not ((df.filter(regex=("[B|J|P].*BKGCAT"))!=0).all().all()
+         and (df.filter(regex=("[K|Mu].*BKGCAT"))==-1).all().all()  # for kaons and muons, all entries are -1
+       ):
+    causes.append("Ntuple contains unexpected BKGCAT values")
 
 print('Test successfully completed!')
 os.system(f"rm {ntuple}")
diff --git a/DaVinciTutorials/tests/qmtest/test_tutorial6_DecayTreeFit.qmt b/DaVinciTutorials/tests/qmtest/test_tutorial6_DecayTreeFit.qmt
index 2554b6ef8..5dcd29271 100644
--- a/DaVinciTutorials/tests/qmtest/test_tutorial6_DecayTreeFit.qmt
+++ b/DaVinciTutorials/tests/qmtest/test_tutorial6_DecayTreeFit.qmt
@@ -46,7 +46,8 @@ if df.empty: raise Exception(f"File {ntuple}: ntuple does not contain any branch
 assert df.shape == (30, 48)
 
 # Check there are no NaN values in the ntuple
-assert not df_has_nan(df)
+if df_has_nan(df):
+    causes.append("Ntuple contains NaN entries")
 
 print('Test successfully completed!')
 os.system(f"rm {ntuple}")
diff --git a/DaVinciTutorials/tests/qmtest/test_tutorial7_multiple_sel_lines.qmt b/DaVinciTutorials/tests/qmtest/test_tutorial7_multiple_sel_lines.qmt
index 7a8fffc9c..17e907f81 100644
--- a/DaVinciTutorials/tests/qmtest/test_tutorial7_multiple_sel_lines.qmt
+++ b/DaVinciTutorials/tests/qmtest/test_tutorial7_multiple_sel_lines.qmt
@@ -37,20 +37,27 @@ ntuple  = './tutorial7_multiple_sel_lines.root'
 #this file should be disabled
 ntuple_new  = './tutorial7_multiple_sel_lines_new.root'
 
-if not os.path.isfile(ntuple): raise Exception(f"File {ntuple} does not exist!")
+if not os.path.isfile(ntuple):
+    causes.append(f"File {ntuple} does not exist!")
 
 df1 = get_pandas_dataframe(ntuple, 'TDirectoryName1/TTreeName1')
 df2 = get_pandas_dataframe(ntuple, 'TDirectoryName2/TTreeName2')
 
 # Check ntuple structure
-if df1.empty: raise Exception(f"File {ntuple}: ntuple 'TDirectoryName1/TTreeName1' does not contain any branches. Please check.")
-if df2.empty: raise Exception(f"File: {ntuple}: ntuple 'TDirectoryName2/TTreeName2' does not contain any branches. Please check.")
-assert df1.shape == (30, 23)
-assert df2.shape == (13, 23)
+if df1.empty:
+    causes.append(f"File {ntuple}: ntuple 'TDirectoryName1/TTreeName1' does not contain any branches")
+if df2.empty:
+    causes.append(f"File {ntuple}: ntuple 'TDirectoryName2/TTreeName2' does not contain any branches")
+if df1.shape != (30, 23):
+    causes.append("Ntuple 'TDirectoryName1/TTreeName1' not with expected number of entries and/or branches")
+if df2.shape != (13, 23):
+    causes.append("Ntuple 'TDirectoryName2/TTreeName2' not with expected number of entries and/or branches")
 
 # Check there are no NaN values in the ntuples
-assert not df_has_nan(df1)
-assert not df_has_nan(df2)
+if df_has_nan(df1):
+    causes.append("Ntuple 'TDirectoryName1/TTreeName1' contains NaN entries")
+if df_has_nan(df2):
+    causes.append("Ntuple 'TDirectoryName2/TTreeName2' contains NaN entries")
 
 print('Test successfully completed!')
 os.system(f"rm {ntuple}")
diff --git a/DaVinciTutorials/tests/refs/test_tutorial5_MCTruth.ref b/DaVinciTutorials/tests/refs/test_tutorial5_MCTruth.ref
index 34c78bc62..c69953f0f 100644
--- a/DaVinciTutorials/tests/refs/test_tutorial5_MCTruth.ref
+++ b/DaVinciTutorials/tests/refs/test_tutorial5_MCTruth.ref
@@ -6,9 +6,9 @@ NTupleSvc                              INFO Added stream file:tutorial5_MCTruth.
 RootHistSvc                            INFO Writing ROOT histograms to: tutorial5_MCTruth.root
 HistogramPersistencySvc                INFO Added successfully Conversion service:RootHistSvc
 FSROutputStreamDstWriter               INFO Data source: EventDataSvc output: SVC='Gaudi::RootCnvSvc'
-MCTruthAndBkgCatAlg#1.DaVinciSma...    INFO Will look into [/Event/HLT2/Relations/ChargedPP2MCP, /Event/HLT2/Relations/NeutralPP2MCP]
-MCTruthAndBkgCatAlg#1.DaVinciSma...    INFO Will look into [/Event/HLT2/Relations/ChargedPP2MCP, /Event/HLT2/Relations/NeutralPP2MCP]
-MCTruthAndBkgCatAlg#1.Background...    INFO Will look into [/Event/HLT2/Relations/ChargedPP2MCP, /Event/HLT2/Relations/NeutralPP2MCP]
+MCTruthAndBkgCatAlg#1.DaVinciSma...    INFO Will look into protoparticle locations [/Event/HLT2/Relations/ChargedPP2MCP, /Event/HLT2/Relations/NeutralPP2MCP]
+MCTruthAndBkgCatAlg#1.DaVinciSma...    INFO Will look into protoparticle locations [/Event/HLT2/Relations/ChargedPP2MCP, /Event/HLT2/Relations/NeutralPP2MCP]
+MCTruthAndBkgCatAlg#1.Background...    INFO Will look into protoparticle locations [/Event/HLT2/Relations/ChargedPP2MCP, /Event/HLT2/Relations/NeutralPP2MCP]
 ApplicationMgr                         INFO Application Manager Initialized successfully
 ApplicationMgr                         INFO Application Manager Started successfully
 EventPersistencySvc                    INFO Added successfully Conversion service:RootCnvSvc
diff --git a/DaVinciTutorials/tests/refs/test_tutorial5_MCTruth.ref.detdesc b/DaVinciTutorials/tests/refs/test_tutorial5_MCTruth.ref.detdesc
index 34c78bc62..c69953f0f 100644
--- a/DaVinciTutorials/tests/refs/test_tutorial5_MCTruth.ref.detdesc
+++ b/DaVinciTutorials/tests/refs/test_tutorial5_MCTruth.ref.detdesc
@@ -6,9 +6,9 @@ NTupleSvc                              INFO Added stream file:tutorial5_MCTruth.
 RootHistSvc                            INFO Writing ROOT histograms to: tutorial5_MCTruth.root
 HistogramPersistencySvc                INFO Added successfully Conversion service:RootHistSvc
 FSROutputStreamDstWriter               INFO Data source: EventDataSvc output: SVC='Gaudi::RootCnvSvc'
-MCTruthAndBkgCatAlg#1.DaVinciSma...    INFO Will look into [/Event/HLT2/Relations/ChargedPP2MCP, /Event/HLT2/Relations/NeutralPP2MCP]
-MCTruthAndBkgCatAlg#1.DaVinciSma...    INFO Will look into [/Event/HLT2/Relations/ChargedPP2MCP, /Event/HLT2/Relations/NeutralPP2MCP]
-MCTruthAndBkgCatAlg#1.Background...    INFO Will look into [/Event/HLT2/Relations/ChargedPP2MCP, /Event/HLT2/Relations/NeutralPP2MCP]
+MCTruthAndBkgCatAlg#1.DaVinciSma...    INFO Will look into protoparticle locations [/Event/HLT2/Relations/ChargedPP2MCP, /Event/HLT2/Relations/NeutralPP2MCP]
+MCTruthAndBkgCatAlg#1.DaVinciSma...    INFO Will look into protoparticle locations [/Event/HLT2/Relations/ChargedPP2MCP, /Event/HLT2/Relations/NeutralPP2MCP]
+MCTruthAndBkgCatAlg#1.Background...    INFO Will look into protoparticle locations [/Event/HLT2/Relations/ChargedPP2MCP, /Event/HLT2/Relations/NeutralPP2MCP]
 ApplicationMgr                         INFO Application Manager Initialized successfully
 ApplicationMgr                         INFO Application Manager Started successfully
 EventPersistencySvc                    INFO Added successfully Conversion service:RootCnvSvc
-- 
GitLab