12combined_module_quality_estimator_teacher
13-----------------------------------------
15Information on the MVA Track Quality Indicator / Estimator can be found
17<https://xwiki.desy.de/xwiki/rest/p/0d3f4>`_.
22This python script is used for the combined training and validation of three
23classifiers, the actual final MVA track quality estimator and the two quality
24estimators for the intermediate standalone track finders that it depends on.
26 - Final MVA track quality estimator:
27 The final quality estimator for fully merged and fitted tracks (RecoTracks).
28 Its classifier uses features from the track fitting, merger, hit pattern, ...
29 But it also uses the outputs from respective intermediate quality
30 estimators for the VXD and the CDC track finding as inputs. It provides
31 the final quality indicator (QI) exported to the track objects.
33 - VXDTF2 track quality estimator:
34 MVA quality estimator for the VXD standalone track finding.
36 - CDC track quality estimator:
37 MVA quality estimator for the CDC standalone track finding.
39Each classifier requires for its training a different training data set and they
40need to be validated on a separate testing data set. Further, the final quality
41estimator can only be trained, when the trained weights for the intermediate
42quality estimators are available. If the final estimator shall be trained without
43one or both previous estimators, the requirements have to be commented out in the
44__init__.py file of tracking.
45For all estimators, a list of variables to be ignored is specified in the MasterTask.
46The current choice is mainly based on pure data MC agreement in these quantities or
47on outdated implementations. It was decided to leave them in the hardcoded "ugly" way
48in here to remind future generations that they exist in principle and they should and
49could be added to the estimator, once their modelling becomes better in future or an
50alternative implementation is programmed.
51To avoid mistakes, b2luigi is used to create a task chain for a combined training and
52validation of all classifiers.
54b2luigi: Understanding the steering file
55~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
57All trainings and validations are done in the correct order in this steering
58file. For the purpose of creating a dependency graph, the `b2luigi
59<https://b2luigi.readthedocs.io>`_ python package is used, which extends the
60`luigi <https://luigi.readthedocs.io>`_ package developed by spotify.
62Each task that has to be done is represented by a special class, which defines
63which defines parameters, output files and which other tasks with which
64parameters it depends on. For example a teacher task, which runs
65``basf2_mva_teacher.py`` to train the classifier, depends on a data collection
66task which runs a reconstruction and writes out track-wise variables into a root
67file for training. An evaluation/validation task for testing the classifier
68requires both the teacher task, as it needs the weightfile to be present, and
69also a data collection task, because it needs a dataset for testing classifier.
71The final task that defines which tasks need to be done for the steering file to
72finish is the ``MasterTask``. When you only want to run parts of the
73training/validation pipeline, you can comment out requirements in the Master
74task or replace them by lower-level tasks during debugging.
79This steering file relies on b2luigi_ for task scheduling and `uncertain_panda
80<https://github.com/nils-braun/uncertain_panda>`_ for uncertainty calculations.
81uncertain_panda is not in the externals and b2luigi is not upto v01-07-01. Both
82can be installed via pip::
84 python3 -m pip install [--user] b2luigi uncertain_panda
86Use the ``--user`` option if you have not rights to install python packages into
87your externals (e.g. because you are using cvmfs) and install them in
88``$HOME/.local`` instead.
93Instead of command line arguments, the b2luigi script is configured via a
94``settings.json`` file. Open it in your favorite text editor and modify it to
95fit to your requirements.
100You can test the b2luigi without running it via::
102 python3 combined_quality_estimator_teacher.py --dry-run
103 python3 combined_quality_estimator_teacher.py --show-output
105This will show the outputs and show potential errors in the definitions of the
106luigi task dependencies. To run the the steering file in normal (local) mode,
109 python3 combined_quality_estimator_teacher.py
111I usually use the interactive luigi web interface via the central scheduler
112which visualizes the task graph while it is running. Therefore, the scheduler
113daemon ``luigid`` has to run in the background, which is located in
114``~/.local/bin/luigid`` in case b2luigi had been installed with ``--user``. For
119Then, execute your steering (e.g. in another terminal) with::
121 python3 combined_quality_estimator_teacher.py --scheduler-port 8886
123To view the web interface, open your webbrowser enter into the url bar::
127If you don't run the steering file on the same machine on which you run your web
128browser, you have two options:
130 1. Run both the steering file and ``luigid`` remotely and use
131 ssh-port-forwarding to your local host. Therefore, run on your local
134 ssh -N -f -L 8886:localhost:8886 <remote_user>@<remote_host>
136 2. Run the ``luigid`` scheduler locally and use the ``--scheduler-host <your
137 local host>`` argument when calling the steering file
139Accessing the results / output files
140~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
142All output files are stored in a directory structure in the ``result_path``. The
143directory tree encodes the used b2luigi parameters. This ensures reproducibility
144and makes parameter searches easy. Sometimes, it is hard to find the relevant
145output files. You can view the whole directory structure by running ``tree
146<result_path>``. Ise the unix ``find`` command to find the files that interest
149 find <result_path> -name "*.zip" # find all validation plot files
150 find <result_path> -name "*.root" # find all ROOT files
155from pathlib
import Path
158from datetime
import datetime
159from typing
import Iterable
161import matplotlib.pyplot
as plt
164from matplotlib.backends.backend_pdf
import PdfPages
168from packaging
import version
172from tracking.path_utils import add_cdc_track_finding, add_vxd_track_finding_vxdtf2, add_track_fit_and_track_creator
175from tracking_mva_filter_payloads.write_tracking_mva_filter_payloads_to_db
import write_mva_weightfile_content_to_db
176from tracking_mva_filter_payloads.write_tracking_mva_filter_payloads_to_db
import write_tracking_mva_filter_payloads_to_db
180install_helpstring_formatter = (
"\nCould not find {module} python module.Try installing it via\n"
181 " python3 -m pip install [--user] {module}\n")
184 from b2luigi.core.utils
import get_serialized_parameters
185 from b2luigi.basf2_helper
import Basf2PathTask, Basf2Task
186 from b2luigi.core.task
import Task, ExternalTask
187 from b2luigi.basf2_helper.utils
import get_basf2_git_hash
188except ModuleNotFoundError:
189 print(install_helpstring_formatter.format(module=
"b2luigi"))
192 from uncertain_panda
import pandas
as upd
193except ModuleNotFoundError:
194 print(install_helpstring_formatter.format(module=
"uncertain_panda"))
202 version.parse(b2luigi.__version__) <= version.parse(
"0.3.2")
and
203 get_basf2_git_hash()
is None and
204 os.getenv(
"BELLE2_LOCAL_DIR")
is not None
206 print(f
"b2luigi version could not obtain git hash because of a bug not yet fixed in version {b2luigi.__version__}\n"
207 "Please install the latest version of b2luigi from github via\n\n"
208 " python3 -m pip install --upgrade [--user] git+https://github.com/nils-braun/b2luigi.git\n")
214def create_fbdt_option_string(fast_bdt_option):
216 returns a readable string created by the fast_bdt_option array
218 return "_nTrees" + str(fast_bdt_option[0]) +
"_nCuts" + str(fast_bdt_option[1]) +
"_nLevels" + \
219 str(fast_bdt_option[2]) +
"_shrin" + str(int(round(100*fast_bdt_option[3], 0)))
222def createV0momenta(x, mu, beta):
224 Copied from Biancas K_S0 particle gun code: Returns a realistic V0 momentum distribution
225 when running over x. Mu and Beta are properties of the function that define center and tails.
226 Used for the particle gun simulation code for K_S0 and Lambda_0
228 return (1/beta)*np.exp(-(x - mu)/beta) * np.exp(-np.exp(-(x - mu) / beta))
231def my_basf2_mva_teacher(
234 weightfile_identifier,
235 target_variable="truth",
236 exclude_variables=None,
237 fast_bdt_option=[200, 8, 3, 0.1]
240 My custom wrapper for basf2 mva teacher. Adapted from code in ``trackfindingcdc_teacher``.
242 :param records_files: List of files with collected ("recorded") variables to use as training data for the MVA.
243 :param tree_name: Name of the TTree in the ROOT file from the ``data_collection_task``
244 that contains the training data for the MVA teacher.
245 :param weightfile_identifier: Name of the weightfile that is created.
246 Should either end in ".xml" for local weightfiles or in ".root", when
247 the weightfile needs later to be uploaded as a payload to the conditions
249 :param target_variable: Feature/variable to use as truth label in the quality estimator MVA classifier.
250 :param exclude_variables: List of collected variables to not use in the training of the QE MVA classifier.
251 In addition to variables containing the "truth" substring, which are excluded by default.
252 :param fast_bdt_option: specified fast BDT options, default: [200, 8, 3, 0.1] [nTrees, nCuts, nLevels, shrinkage]
255 if exclude_variables
is None:
256 exclude_variables = []
258 weightfile_extension = Path(weightfile_identifier).suffix
259 if weightfile_extension
not in {
".xml",
".root"}:
260 raise ValueError(f
"Weightfile Identifier should end in .xml or .root, but ends in {weightfile_extension}")
263 with root_utils.root_open(records_files[0])
as records_tfile:
264 input_tree = records_tfile.Get(tree_name)
265 feature_names = [leave.GetName()
for leave
in input_tree.GetListOfLeaves()]
268 truth_free_variable_names = [
270 for name
in feature_names
272 (
"truth" not in name)
and
273 (name != target_variable)
and
274 (name
not in exclude_variables)
277 if "weight" in truth_free_variable_names:
278 truth_free_variable_names.remove(
"weight")
279 weight_variable =
"weight"
280 elif "__weight__" in truth_free_variable_names:
281 truth_free_variable_names.remove(
"__weight__")
282 weight_variable =
"__weight__"
287 general_options = basf2_mva.GeneralOptions()
288 general_options.m_datafiles = basf2_mva.vector(*records_files)
289 general_options.m_treename = tree_name
290 general_options.m_weight_variable = weight_variable
291 general_options.m_identifier = weightfile_identifier
292 general_options.m_variables = basf2_mva.vector(*truth_free_variable_names)
293 general_options.m_target_variable = target_variable
294 fastbdt_options = basf2_mva.FastBDTOptions()
296 fastbdt_options.m_nTrees = fast_bdt_option[0]
297 fastbdt_options.m_nCuts = fast_bdt_option[1]
298 fastbdt_options.m_nLevels = fast_bdt_option[2]
299 fastbdt_options.m_shrinkage = fast_bdt_option[3]
301 basf2_mva.teacher(general_options, fastbdt_options)
304def _my_uncertain_mean(series: upd.Series):
306 Temporary Workaround bug in ``uncertain_panda`` where a ``ValueError`` is
307 thrown for ``Series.unc.mean`` if the series is empty. Can be replaced by
308 .unc.mean when the issue is fixed.
309 https://github.com/nils-braun/uncertain_panda/issues/2
312 return series.unc.mean()
320def get_uncertain_means_for_qi_cuts(df: upd.DataFrame, column: str, qi_cuts: Iterable[float]):
322 Return a pandas series with an mean of the dataframe column and
323 uncertainty for each quality indicator cut.
325 :param df: Pandas dataframe with at least ``quality_indicator``
326 and another numeric ``column``.
327 :param column: Column of which we want to aggregate the means
328 and uncertainties for different QI cuts
329 :param qi_cuts: Iterable of quality indicator minimal thresholds.
330 :returns: Series of of means and uncertainties with ``qi_cuts`` as index
333 uncertain_means = (_my_uncertain_mean(df.query(f
"quality_indicator > {qi_cut}")[column])
334 for qi_cut
in qi_cuts)
335 uncertain_means_series = upd.Series(data=uncertain_means, index=qi_cuts)
336 return uncertain_means_series
339def plot_with_errobands(uncertain_series,
340 error_band_alpha=0.3,
342 fill_between_kwargs={},
345 Plot an uncertain series with error bands for y-errors
349 uncertain_series = uncertain_series.dropna()
350 ax.plot(uncertain_series.index.values, uncertain_series.nominal_value, **plot_kwargs)
351 ax.fill_between(x=uncertain_series.index,
352 y1=uncertain_series.nominal_value - uncertain_series.std_dev,
353 y2=uncertain_series.nominal_value + uncertain_series.std_dev,
354 alpha=error_band_alpha,
355 **fill_between_kwargs)
358def format_dictionary(adict, width=80, bullet="•"):
360 Helper function to format dictionary to string as a wrapped key-value bullet
361 list. Useful to print metadata from dictionaries.
363 :param adict: Dictionary to format
364 :param width: Characters after which to wrap a key-value line
365 :param bullet: Character to begin a key-value line with, e.g. ``-`` for a
371 return "\n".join(textwrap.fill(f
"{bullet} {key}: {value}", width=width)
372 for (key, value)
in adict.items())
376 return [x
for xs
in xss
for x
in xs]
383 Generate simulated Monte Carlo with background overlay.
385 Make sure to use different ``random_seed`` parameters for the training data
386 format the classifier trainings and for the test data for the respective
387 evaluation/validation tasks.
391 n_events = b2luigi.IntParameter()
393 experiment_number = b2luigi.IntParameter()
396 random_seed = b2luigi.Parameter()
398 bkgfiles_dir = b2luigi.Parameter(
409 Create output file name depending on number of events and production
410 mode that is specified in the random_seed string.
414 if random_seed
is None:
416 return "generated_mc_N" + str(n_events) +
"_" + random_seed +
".root"
420 Generate list of output files that the task should produce.
421 The task is considered finished if and only if the outputs all exist.
427 Create basf2 path to process with event generation and simulation.
430 path = basf2.create_path()
436 f
"Simulating events with experiment number {self.experiment_number} is not implemented yet.")
441 path.add_module(
"EvtGenInput")
443 path.add_module(
"EvtGenInput")
444 path.add_module(
"InclusiveParticleChecker", particles=[310, 3122], includeConjugates=
True)
446 import generators
as ge
467 pdgs = [310, 3122, -3122]
469 myx = [i*0.01
for i
in range(321)]
472 y = createV0momenta(x, mu, beta)
474 polParams = myx + myy
478 particlegun = basf2.register_module(
'ParticleGun')
479 particlegun.param(
'pdgCodes', pdg_list)
480 particlegun.param(
'nTracks', 8)
481 particlegun.param(
'momentumGeneration',
'polyline')
482 particlegun.param(
'momentumParams', polParams)
483 particlegun.param(
'thetaGeneration',
'uniformCos')
484 particlegun.param(
'thetaParams', [17, 150])
485 particlegun.param(
'phiGeneration',
'uniform')
486 particlegun.param(
'phiParams', [0, 360])
487 particlegun.param(
'vertexGeneration',
'fixed')
488 particlegun.param(
'xVertexParams', [0])
489 particlegun.param(
'yVertexParams', [0])
490 particlegun.param(
'zVertexParams', [0])
491 path.add_module(particlegun)
493 ge.add_babayaganlo_generator(path=path, finalstate=
'ee', minenergy=0.15, minangle=10.0)
495 ge.add_kkmc_generator(path=path, finalstate=
'mu+mu-')
497 babayaganlo = basf2.register_module(
'BabayagaNLOInput')
498 babayaganlo.param(
'FinalState',
'gg')
499 babayaganlo.param(
'MaxAcollinearity', 180.0)
500 babayaganlo.param(
'ScatteringAngleRange', [0., 180.])
501 babayaganlo.param(
'FMax', 75000)
502 babayaganlo.param(
'MinEnergy', 0.01)
503 babayaganlo.param(
'Order',
'exp')
504 babayaganlo.param(
'DebugEnergySpread', 0.01)
505 babayaganlo.param(
'Epsilon', 0.00005)
506 path.add_module(babayaganlo)
507 generatorpreselection = basf2.register_module(
'GeneratorPreselection')
508 generatorpreselection.param(
'nChargedMin', 0)
509 generatorpreselection.param(
'nChargedMax', 999)
510 generatorpreselection.param(
'MinChargedPt', 0.15)
511 generatorpreselection.param(
'MinChargedTheta', 17.)
512 generatorpreselection.param(
'MaxChargedTheta', 150.)
513 generatorpreselection.param(
'nPhotonMin', 1)
514 generatorpreselection.param(
'MinPhotonEnergy', 1.5)
515 generatorpreselection.param(
'MinPhotonTheta', 15.0)
516 generatorpreselection.param(
'MaxPhotonTheta', 165.0)
517 generatorpreselection.param(
'applyInCMS',
True)
518 path.add_module(generatorpreselection)
519 empty = basf2.create_path()
520 generatorpreselection.if_value(
'!=11', empty)
522 ge.add_aafh_generator(path=path, finalstate=
'e+e-e+e-', preselection=
False)
524 ge.add_aafh_generator(path=path, finalstate=
'e+e-mu+mu-', preselection=
False)
526 ge.add_kkmc_generator(path, finalstate=
'tau+tau-')
528 ge.add_continuum_generator(path, finalstate=
'ddbar')
530 ge.add_continuum_generator(path, finalstate=
'uubar')
532 ge.add_continuum_generator(path, finalstate=
'ssbar')
534 ge.add_continuum_generator(path, finalstate=
'ccbar')
543 components = [
'PXD',
'SVD',
'CDC',
'ECL',
'TOP',
'ARICH',
'TRG']
560 Generate simulated Monte Carlo with background overlay.
562 Make sure to use different ``random_seed`` parameters for the training data
563 format the classifier trainings and for the test data for the respective
564 evaluation/validation tasks.
568 n_events = b2luigi.IntParameter()
570 experiment_number = b2luigi.IntParameter()
573 random_seed = b2luigi.Parameter()
575 bkgfiles_dir = b2luigi.Parameter(
586 Create output file name depending on number of events and production
587 mode that is specified in the random_seed string.
591 if random_seed
is None:
593 return "generated_mc_N" + str(n_events) +
"_" + random_seed +
".root"
597 Generate list of output files that the task should produce.
598 The task is considered finished if and only if the outputs all exist.
604 Generate list of luigi Tasks that this Task depends on.
606 n_events_per_task = MasterTask.n_events_per_task
607 quotient, remainder = divmod(self.
n_events, n_events_per_task)
608 for i
in range(quotient):
611 num_processes=MasterTask.num_processes,
612 random_seed=self.
random_seed +
'_' + str(i).zfill(3),
613 n_events=n_events_per_task,
619 num_processes=MasterTask.num_processes,
620 random_seed=self.
random_seed +
'_' + str(quotient).zfill(3),
625 @b2luigi.on_temporary_files
628 When all GenerateSimTasks finished, merge the output.
630 file_list = self.get_all_input_file_names()
631 file_list = flat(file_list)
632 print(
"Merge the following files:\n")
634 cmd = [
"b2file-merge",
"-f"]
635 args = cmd + [self.get_output_file_name(self.
output_file_name())] + file_list
636 print(f
"args to merge: {args}")
637 subprocess.check_call(args)
638 print(
"Finished merging. Removing the input files to save space.")
640 args = cmd2 + file_list
641 print(f
"args for deleting: {args}")
642 subprocess.check_call(args)
647 Task to check if the given file really exists.
650 filename = b2luigi.Parameter()
654 Specify the output to be the file that was just checked.
656 from luigi
import LocalTarget
662 Collect variables/features from VXDTF2 tracking and write them to a ROOT
665 These variables are to be used as labelled training data for the MVA
666 classifier which is the VXD track quality estimator
669 n_events = b2luigi.IntParameter()
671 experiment_number = b2luigi.IntParameter()
674 random_seed = b2luigi.Parameter()
681 Create output file name depending on number of events and production
682 mode that is specified in the random_seed string.
686 if random_seed
is None:
688 if 'vxd' not in random_seed:
689 random_seed +=
'_vxd'
690 if 'DATA' in random_seed:
691 return 'qe_records_DATA_vxd.root'
693 if 'USESIMBB' in random_seed:
694 random_seed =
'BBBAR_' + random_seed.split(
"_", 1)[1]
695 elif 'USESIMEE' in random_seed:
696 random_seed =
'BHABHA_' + random_seed.split(
"_", 1)[1]
697 return 'qe_records_N' + str(n_events) +
'_' + random_seed +
'.root'
701 Get input file names depending on the use case: If they already exist, search in
702 the corresponding folders, for data check the specified list and if they are created
703 in the same run, check for the task that produced them.
707 if random_seed
is None:
709 if "USESIM" in random_seed:
710 if 'USESIMBB' in random_seed:
711 random_seed =
'BBBAR_' + random_seed.split(
"_", 1)[1]
712 elif 'USESIMEE' in random_seed:
713 random_seed =
'BHABHA_' + random_seed.split(
"_", 1)[1]
714 return [
'datafiles/' + GenerateSimTask.output_file_name(GenerateSimTask,
715 n_events=n_events, random_seed=random_seed)]
716 elif "DATA" in random_seed:
717 return MasterTask.datafiles
719 return self.get_input_file_names(GenerateSimTask.output_file_name(
720 GenerateSimTask, n_events=n_events, random_seed=random_seed))
724 Generate list of luigi Tasks that this Task depends on.
741 Generate list of output files that the task should produce.
742 The task is considered finished if and only if the outputs all exist.
748 Create basf2 path with VXDTF2 tracking and VXD QE data collection.
750 path = basf2.create_path()
754 inputFileNames=inputFileNames,
756 path.add_module(
"Gearbox")
757 tracking.add_geometry_modules(path)
759 from rawdata
import add_unpackers
760 add_unpackers(path, components=[
'SVD',
'PXD'])
761 tracking.add_hit_preparation_modules(path)
762 add_vxd_track_finding_vxdtf2(
763 path, components=[
"SVD"], add_mva_quality_indicator=
False
767 "VXDQETrainingDataCollector",
769 SpacePointTrackCandsStoreArrayName=
"SPTrackCands",
770 EstimationMethod=
"tripletFit",
772 ClusterInformation=
"Average",
773 MCStrictQualityEstimator=
False,
779 "TrackFinderMCTruthRecoTracks",
780 RecoTracksStoreArrayName=
"MCRecoTracks",
787 "VXDQETrainingDataCollector",
789 SpacePointTrackCandsStoreArrayName=
"SPTrackCands",
790 EstimationMethod=
"tripletFit",
792 ClusterInformation=
"Average",
793 MCStrictQualityEstimator=
True,
801 Collect variables/features from CDC tracking and write them to a ROOT file.
803 These variables are to be used as labelled training data for the MVA
804 classifier which is the CDC track quality estimator
807 n_events = b2luigi.IntParameter()
809 experiment_number = b2luigi.IntParameter()
812 random_seed = b2luigi.Parameter()
819 Create output file name depending on number of events and production
820 mode that is specified in the random_seed string.
824 if random_seed
is None:
826 if 'cdc' not in random_seed:
827 random_seed +=
'_cdc'
828 if 'DATA' in random_seed:
829 return 'qe_records_DATA_cdc.root'
831 if 'USESIMBB' in random_seed:
832 random_seed =
'BBBAR_' + random_seed.split(
"_", 1)[1]
833 elif 'USESIMEE' in random_seed:
834 random_seed =
'BHABHA_' + random_seed.split(
"_", 1)[1]
835 return 'qe_records_N' + str(n_events) +
'_' + random_seed +
'.root'
839 Get input file names depending on the use case: If they already exist, search in
840 the corresponding folders, for data check the specified list and if they are created
841 in the same run, check for the task that produced them.
845 if random_seed
is None:
847 if "USESIM" in random_seed:
848 if 'USESIMBB' in random_seed:
849 random_seed =
'BBBAR_' + random_seed.split(
"_", 1)[1]
850 elif 'USESIMEE' in random_seed:
851 random_seed =
'BHABHA_' + random_seed.split(
"_", 1)[1]
852 return [
'datafiles/' + GenerateSimTask.output_file_name(GenerateSimTask,
853 n_events=n_events, random_seed=random_seed)]
854 elif "DATA" in random_seed:
855 return MasterTask.datafiles
857 return self.get_input_file_names(GenerateSimTask.output_file_name(
858 GenerateSimTask, n_events=n_events, random_seed=random_seed))
862 Generate list of luigi Tasks that this Task depends on.
879 Generate list of output files that the task should produce.
880 The task is considered finished if and only if the outputs all exist.
886 Create basf2 path with CDC standalone tracking and CDC QE with recording filter for MVA feature collection.
888 path = basf2.create_path()
892 inputFileNames=inputFileNames,
894 path.add_module(
"Gearbox")
895 tracking.add_geometry_modules(path)
897 filter_choice =
"recording_data"
898 from rawdata
import add_unpackers
899 add_unpackers(path, components=[
'CDC'])
901 filter_choice =
"recording"
904 add_cdc_track_finding(path, add_mva_quality_indicator=
True)
905 basf2.set_module_parameters(
907 name=
"TFCDC_TrackQualityEstimator",
908 filter=filter_choice,
912 deactivateIfDeadBoard=
False
919 Collect variables/features from the reco track reconstruction including the
920 fit and write them to a ROOT file.
922 These variables are to be used as labelled training data for the MVA
923 classifier which is the MVA track quality estimator. The collected
924 variables include the classifier outputs from the VXD and CDC quality
925 estimators, namely the CDC and VXD quality indicators, combined with fit,
926 merger, timing, energy loss information etc. This task requires the
927 subdetector quality estimators to be trained.
931 n_events = b2luigi.IntParameter()
933 experiment_number = b2luigi.IntParameter()
936 random_seed = b2luigi.Parameter()
938 cdc_training_target = b2luigi.Parameter()
942 recotrack_option = b2luigi.Parameter(
944 default=
'deleteCDCQI080'
948 fast_bdt_option = b2luigi.ListParameter(
950 hashed=
True, default=[200, 8, 3, 0.1]
954 process_type = b2luigi.Parameter(
965 Create output file name depending on number of events and production
966 mode that is specified in the random_seed string.
970 if random_seed
is None:
972 if recotrack_option
is None:
977 if 'rec' not in random_seed:
978 random_seed +=
'_rec'
979 if 'DATA' in random_seed:
980 return 'qe_records_DATA_rec.root'
982 if 'USESIMBB' in random_seed:
983 random_seed =
'BBBAR_' + random_seed.split(
"_", 1)[1]
984 elif 'USESIMEE' in random_seed:
985 random_seed =
'BHABHA_' + random_seed.split(
"_", 1)[1]
986 return 'qe_records_N' + str(n_events) +
'_' + random_seed +
'_' + recotrack_option +
'.root'
990 Get input file names depending on the use case: If they already exist, search in
991 the corresponding folders, for data check the specified list and if they are created
992 in the same run, check for the task that produced them.
996 if random_seed
is None:
998 if "USESIM" in random_seed:
999 if 'USESIMBB' in random_seed:
1000 random_seed =
'BBBAR_' + random_seed.split(
"_", 1)[1]
1001 elif 'USESIMEE' in random_seed:
1002 random_seed =
'BHABHA_' + random_seed.split(
"_", 1)[1]
1003 return [
'datafiles/' + GenerateSimTask.output_file_name(GenerateSimTask,
1004 n_events=n_events, random_seed=random_seed)]
1005 elif "DATA" in random_seed:
1006 return MasterTask.datafiles
1008 return self.get_input_file_names(GenerateSimTask.output_file_name(
1009 GenerateSimTask, n_events=n_events, random_seed=random_seed))
1013 Generate list of luigi Tasks that this Task depends on.
1030 n_events_training=MasterTask.n_events_training,
1034 exclude_variables=MasterTask.exclude_variables_cdc,
1039 n_events_training=MasterTask.n_events_training,
1042 exclude_variables=MasterTask.exclude_variables_vxd,
1048 Generate list of output files that the task should produce.
1049 The task is considered finished if and only if the outputs all exist.
1055 Create basf2 reconstruction path that should mirror the default path
1056 from ``add_tracking_reconstruction()``, but with modules for the VXD QE
1057 and CDC QE application and for collection of variables for the reco
1058 track quality estimator.
1060 path = basf2.create_path()
1064 inputFileNames=inputFileNames,
1066 path.add_module(
"Gearbox")
1076 from rawdata
import add_unpackers
1078 tracking.add_tracking_reconstruction(path, add_cdcTrack_QI=mvaCDC, add_vxdTrack_QI=mvaVXD, add_recoTrack_QI=
True)
1085 cdc_identifier =
'datafiles/' + \
1086 CDCQETeacherTask.get_weightfile_identifier(CDCQETeacherTask, fast_bdt_option=self.
fast_bdt_option) +
'.xml'
1087 if os.path.exists(cdc_identifier):
1088 replace_cdc_qi =
True
1090 raise ValueError(f
"CDC QI Identifier not found: {cdc_identifier}")
1092 replace_cdc_qi =
False
1094 replace_cdc_qi =
False
1096 cdc_identifier = self.get_input_file_names(
1097 CDCQETeacherTask.get_weightfile_identifier(
1099 replace_cdc_qi =
True
1101 vxd_identifier =
'datafiles/' + \
1102 VXDQETeacherTask.get_weightfile_identifier(VXDQETeacherTask, fast_bdt_option=self.
fast_bdt_option) +
'.xml'
1103 if os.path.exists(vxd_identifier):
1104 replace_vxd_qi =
True
1105 print(f
"vxd_identifier is {vxd_identifier}")
1107 raise ValueError(f
"VXD QI Identifier not found: {vxd_identifier}")
1109 replace_vxd_qi =
False
1111 replace_vxd_qi =
False
1113 vxd_identifier = self.get_input_file_names(
1114 VXDQETeacherTask.get_weightfile_identifier(
1116 replace_vxd_qi =
True
1118 cdc_qe_mva_filter_parameters =
None
1126 cdc_qe_mva_filter_parameters = {
1127 "identifier": cdc_identifier,
"cut": cut}
1129 cdc_qe_mva_filter_parameters = {
1131 elif replace_cdc_qi:
1132 cdc_qe_mva_filter_parameters = {
1133 "identifier": cdc_identifier}
1134 basf2.conditions.prepend_testing_payloads(
"localdb/database.txt")
1136 if cdc_qe_mva_filter_parameters
is not None and cdc_identifier
is not None:
1137 name =
'TrackingMVAFilterParameters'
1138 cdc_qe_mva_filter_parameters = {
'DBPayloadName': name}
1139 if replace_vxd_qi
and vxd_identifier
is not None:
1140 vxd_name =
'VXDQualityEstimatorMVA'
1142 if cdc_qe_mva_filter_parameters
is not None:
1144 print(f
'cdc_qe_mva_filter_parameters is {cdc_qe_mva_filter_parameters}')
1145 basf2.set_module_parameters(
1147 name=
"TFCDC_TrackQualityEstimator",
1148 filterParameters=cdc_qe_mva_filter_parameters,
1150 resetTakenFlag=
True,
1151 deactivateIfDeadBoard=
False,
1154 print(f
"replace_vxd_qi is true and vxd_identifier is {vxd_identifier}")
1155 basf2.set_module_parameters(
1157 name=
"VXDQualityEstimatorMVA",
1158 WeightFileIdentifier=vxd_name)
1161 track_qe_module_name =
"TrackQualityEstimatorMVA"
1162 mc_track_matcher_module_name =
"MCRecoTracksMatcher"
1163 qe_module_found =
False
1164 mc_matcher_module_found =
False
1165 new_path = basf2.create_path()
1166 for module
in path.modules():
1167 if module.name() == track_qe_module_name:
1170 new_path.add_module(
1176 recoTrackColName=
'RecoTracks',
1177 trackColName=
'MDSTTracks')
1178 qe_module_found =
True
1179 elif module.name() == mc_track_matcher_module_name:
1180 new_path.add_module(module)
1182 new_path.add_module(
1183 "TrackQETrainingDataCollector",
1185 collectEventFeatures=
True
1187 mc_matcher_module_found =
True
1189 new_path.add_module(module)
1190 if not qe_module_found:
1191 raise KeyError(f
"No module {track_qe_module_name} found in path")
1192 if not mc_matcher_module_found:
1193 raise KeyError(f
"No module {mc_matcher_module_found} found in path")
1200 A teacher task runs the basf2 mva teacher on the training data provided by a
1201 data collection task.
1203 Since teacher tasks are needed for all quality estimators covered by this
1204 steering file and the only thing that changes is the required data
1205 collection task and some training parameters, I decided to use inheritance
1206 and have the basic functionality in this base class/interface and have the
1207 specific teacher tasks inherit from it.
1210 n_events_training = b2luigi.IntParameter()
1212 experiment_number = b2luigi.IntParameter()
1216 process_type = b2luigi.Parameter(
1222 training_target = b2luigi.Parameter(
1229 exclude_variables = b2luigi.ListParameter(
1231 hashed=
True, default=[]
1235 fast_bdt_option = b2luigi.ListParameter(
1237 hashed=
True, default=[200, 8, 3, 0.1]
1244 Property defining the basename for the .xml and .root weightfiles that are created.
1245 Has to be implemented by the inheriting teacher task class.
1247 raise NotImplementedError(
1248 "Teacher Task must define a static weightfile_identifier"
1253 Name of the xml weightfile that is created by the teacher task.
1254 It is subsequently used as a local weightfile in the following validation tasks.
1256 if fast_bdt_option
is None:
1258 if recotrack_option
is None and hasattr(self,
'recotrack_option'):
1267 recotrack_option =
''
1268 weightfile_details = create_fbdt_option_string(fast_bdt_option)
1270 if recotrack_option !=
'':
1271 weightfile_name = weightfile_name +
'_' + recotrack_option
1272 return weightfile_name +
"_weights"
1277 Property defining the name of the tree in the ROOT file from the
1278 ``data_collection_task`` that contains the recorded training data. Must
1279 implemented by the inheriting specific teacher task class.
1281 raise NotImplementedError(
"Teacher Task must define a static tree_name")
1286 Property defining random seed to be used by the ``GenerateSimTask``.
1287 Should differ from the random seed in the test data samples. Must
1288 implemented by the inheriting specific teacher task class.
1290 raise NotImplementedError(
"Teacher Task must define a static random seed")
1295 Property defining the specific ``DataCollectionTask`` to require. Must
1296 implemented by the inheriting specific teacher task class.
1298 raise NotImplementedError(
1299 "Teacher Task must define a data collection task to require "
1304 Generate list of luigi Tasks that this Task depends on.
1316 num_processes=MasterTask.num_processes,
1324 Generate list of output files that the task should produce.
1325 The task is considered finished if and only if the outputs all exist.
1331 Use basf2_mva teacher to create MVA weightfile from collected training
1334 This is the main process that is dispatched by the ``run`` method that
1335 is inherited from ``Basf2Task``.
1345 if hasattr(self,
'recotrack_option')
and isinstance(self, RecoTrackQETeacherTask):
1346 records_files = self.get_input_file_names(
1353 records_files = self.get_input_file_names(
1360 print(
'The weightfile used is:', weightfile_identifier)
1361 my_basf2_mva_teacher(
1362 records_files=records_files,
1364 weightfile_identifier=weightfile_identifier,
1374 Task to run basf2 mva teacher on collected data for VXDTF2 track quality estimator
1377 weightfile_identifier_basename =
"vxdtf2_mva_qe"
1382 random_seed =
"train_vxd"
1385 data_collection_task = VXDQEDataCollectionTask
1387 object_name =
'VXDQualityEstimatorMVA'
1391 Creates the local VXD payload from weightfiles.
1394 with open(vxd_identifier,
"r")
as f:
1395 weight_file_content = f.read()
1396 vxd_name = write_mva_weightfile_content_to_db(
1398 content=weight_file_content,
1399 iovList=(0, 0, 0, -1)
1406 Task to run basf2 mva teacher on collected data for CDC track quality estimator
1411 recotrack_option = b2luigi.Parameter(
1413 default=
'deleteCDCQI080'
1417 weightfile_identifier_basename =
"cdc_mva_qe"
1420 tree_name =
"records"
1422 random_seed =
"train_cdc"
1425 data_collection_task = CDCQEDataCollectionTask
1427 object_name =
'TrackingMVAFilterParameters'
1431 Creates the local CDC payload from weightfiles.
1439 iovList=(0, 0, 0, -1),
1440 weightfile_identifier=cdc_identifier,
1447 Task to run basf2 mva teacher on collected data for the final, combined
1448 track quality estimator
1453 recotrack_option = b2luigi.Parameter(
1455 default=
'deleteCDCQI080'
1460 weightfile_identifier_basename =
"recotrack_mva_qe"
1465 random_seed =
"train_rec"
1468 data_collection_task = RecoTrackQEDataCollectionTask
1470 cdc_training_target = b2luigi.Parameter()
1472 object_name =
'TrackQualityEstimatorMVA'
1476 Generate list of luigi Tasks that this Task depends on.
1489 num_processes=MasterTask.num_processes,
1499 Creates the local Reco payload from weightfiles.
1502 with open(recotrack_identifier,
'r')
as f:
1503 weight_file_content = f.read()
1504 recotrack_name = write_mva_weightfile_content_to_db(
1506 content=weight_file_content,
1507 iovList=(0, 0, 0, -1)
1509 return recotrack_name
1514 Run track reconstruction with MVA quality estimator and write out
1515 (="harvest") a root file with variables useful for the validation.
1519 n_events_testing = b2luigi.IntParameter()
1521 n_events_training = b2luigi.IntParameter()
1523 experiment_number = b2luigi.IntParameter()
1527 process_type = b2luigi.Parameter(
1534 exclude_variables = b2luigi.ListParameter(
1540 fast_bdt_option = b2luigi.ListParameter(
1542 hashed=
True, default=[200, 8, 3, 0.1]
1546 validation_output_file_name =
"harvesting_validation.root"
1548 reco_output_file_name =
"reconstruction.root"
1552 cdc_training_target =
"truth"
1557 Teacher task to require to provide a quality estimator weightfile for ``add_tracking_with_quality_estimation``
1559 raise NotImplementedError()
1563 Add modules for track reconstruction to basf2 path that are to be
1564 validated. Besides track finding it should include MC matching, fitted
1565 track creation and a quality estimator module.
1567 raise NotImplementedError()
1571 Generate list of luigi Tasks that this Task depends on.
1586 filename=
'datafiles/generated_mc_N' + str(self.
n_events_testing) +
'_' + process +
'_test.root'
1598 Generate list of output files that the task should produce.
1599 The task is considered finished if and only if the outputs all exist.
1606 Create a basf2 path that uses ``add_tracking_with_quality_estimation()``
1607 and adds the ``CombinedTrackingValidationModule`` to write out variables
1610 basf2.conditions.prepend_testing_payloads(
"localdb/database.txt")
1612 path = basf2.create_path()
1618 inputFileNames = [
'datafiles/generated_mc_N' + str(self.
n_events_testing) +
'_' + process +
'_test.root']
1620 inputFileNames = self.get_input_file_names(GenerateSimTask.output_file_name(
1624 inputFileNames=inputFileNames,
1626 path.add_module(
"Gearbox")
1627 tracking.add_geometry_modules(path)
1628 tracking.add_hit_preparation_modules(path)
1637 output_file_name=self.get_output_file_name(
1651 Run VXDTF2 track reconstruction and write out (="harvest") a root file with
1652 variables useful for validation of the VXD Quality Estimator.
1656 validation_output_file_name =
"vxd_qe_harvesting_validation.root"
1658 reco_output_file_name =
"vxd_qe_reconstruction.root"
1660 teacher_task = VXDQETeacherTask
1664 Generate list of luigi Tasks that this Task depends on.
1679 filename=
'datafiles/generated_mc_N' + str(self.
n_events_testing) +
'_' + process +
'_test.root'
1691 Add modules for VXDTF2 tracking with VXD quality estimator to basf2 path.
1693 add_vxd_track_finding_vxdtf2(
1696 reco_tracks=
"RecoTracks",
1697 add_mva_quality_indicator=
True,
1701 vxd_name =
'VXDQualityEstimatorMVA'
1702 basf2.set_module_parameters(
1704 name=
"VXDQualityEstimatorMVA",
1705 WeightFileIdentifier=vxd_name,
1707 tracking.add_mc_matcher(path, components=[
"SVD"], relate_tracks_to_mcparticles=
False)
1708 add_track_fit_and_track_creator(path, components=[
"SVD"])
1713 Run CDC reconstruction and write out (="harvest") a root file with variables
1714 useful for validation of the CDC Quality Estimator.
1717 training_target = b2luigi.Parameter()
1719 validation_output_file_name =
"cdc_qe_harvesting_validation.root"
1721 reco_output_file_name =
"cdc_qe_reconstruction.root"
1723 teacher_task = CDCQETeacherTask
1728 Generate list of luigi Tasks that this Task depends on.
1744 filename=
'datafiles/generated_mc_N' + str(self.
n_events_testing) +
'_' + process +
'_test.root'
1756 Add modules for CDC standalone tracking with CDC quality estimator to basf2 path.
1758 add_cdc_track_finding(
1760 output_reco_tracks=
"RecoTracks",
1761 add_mva_quality_indicator=
True,
1764 basf2.conditions.prepend_testing_payloads(
"localdb/database.txt")
1765 cdc_qe_mva_filter_parameters = {
1766 "identifier": self.get_input_file_names(
1767 CDCQETeacherTask.get_weightfile_identifier(
1770 'DBPayloadName':
'trackfindingcdc_TrackQualityEstimatorParameters'}
1772 name =
'TrackingMVAFilterParameters'
1773 cdc_qe_mva_filter_parameters = {
'DBPayloadName': name}
1774 basf2.set_module_parameters(
1776 name=
"TFCDC_TrackQualityEstimator",
1777 filterParameters=cdc_qe_mva_filter_parameters,
1778 deactivateIfDeadBoard=
False,
1780 tracking.add_mc_matcher(path, components=[
"CDC"], relate_tracks_to_mcparticles=
False)
1781 add_track_fit_and_track_creator(path, components=[
"CDC"])
1786 Run track reconstruction and write out (="harvest") a root file with variables
1787 useful for validation of the MVA track Quality Estimator.
1790 cdc_training_target = b2luigi.Parameter()
1792 validation_output_file_name =
"reco_qe_harvesting_validation.root"
1794 reco_output_file_name =
"reco_qe_reconstruction.root"
1796 teacher_task = RecoTrackQETeacherTask
1800 Generate list of luigi Tasks that this Task depends on.
1807 exclude_variables=MasterTask.exclude_variables_cdc,
1814 exclude_variables=MasterTask.exclude_variables_vxd,
1832 filename=
'datafiles/generated_mc_N' + str(self.
n_events_testing) +
'_' + process +
'_test.root'
1844 Add modules for reco tracking with all track quality estimators to basf2 path.
1847 tracking.add_tracking_reconstruction(
1849 add_cdcTrack_QI=
True,
1850 add_vxdTrack_QI=
True,
1851 add_recoTrack_QI=
True,
1852 skipGeometryAdding=
True,
1853 skipHitPreparerAdding=
True,
1856 name =
'TrackingMVAFilterParameters'
1857 cdc_qe_mva_filter_parameters = {
'DBPayloadName': name}
1858 basf2.set_module_parameters(
1860 name=
"TFCDC_TrackQualityEstimator",
1861 filterParameters=cdc_qe_mva_filter_parameters,
1862 deactivateIfDeadBoard=
False,
1864 vxd_name =
'VXDQualityEstimatorMVA'
1865 basf2.set_module_parameters(
1867 name=
"VXDQualityEstimatorMVA",
1868 WeightFileIdentifier=vxd_name,
1870 recotrack_name =
'TrackQualityEstimatorMVA'
1871 basf2.set_module_parameters(
1873 name=
"TrackQualityEstimatorMVA",
1874 WeightFileIdentifier=recotrack_name,
1880 Base class for evaluating a quality estimator ``basf2_mva_evaluate.py`` on a
1881 separate test data set.
1883 Evaluation tasks for VXD, CDC and combined QE can inherit from it.
1891 git_hash = b2luigi.Parameter(
1893 default=get_basf2_git_hash()
1897 n_events_testing = b2luigi.IntParameter()
1899 n_events_training = b2luigi.IntParameter()
1901 experiment_number = b2luigi.IntParameter()
1905 process_type = b2luigi.Parameter(
1911 training_target = b2luigi.Parameter(
1918 exclude_variables = b2luigi.ListParameter(
1924 fast_bdt_option = b2luigi.ListParameter(
1926 hashed=
True, default=[200, 8, 3, 0.1]
1934 Property defining specific teacher task to require.
1936 raise NotImplementedError(
1937 "Evaluation Tasks must define a teacher task to require "
1943 Property defining the specific ``DataCollectionTask`` to require. Must
1944 implemented by the inheriting specific teacher task class.
1946 raise NotImplementedError(
1947 "Evaluation Tasks must define a data collection task to require "
1953 Acronym to distinguish between cdc, vxd and rec(o) MVA
1955 raise NotImplementedError(
1956 "Evaluation Tasks must define a task acronym."
1961 Generate list of luigi Tasks that this Task depends on.
1974 output_basename = self.
teacher_task.weightfile_identifier_basename + weightfile_details +
".zip"
1975 output_path = self.get_output_file_name(output_basename)
1979 if os.path.exists(output_path):
1981 os.remove(output_path)
1982 print(f
"[INFO] Cleared folder of old file: {output_path}")
1983 except Exception
as e:
1984 print(f
"[WARNING] Failed to remove output file {output_path}: {e}")
1991 filename=
'datafiles/qe_records_N' + str(self.
n_events_testing) +
'_' + process +
'_test_' +
1996 num_processes=MasterTask.num_processes,
2004 Generate list of output files that the task should produce.
2005 The task is considered finished if and only if the outputs all exist.
2008 evaluation_pdf_output = self.
teacher_task.weightfile_identifier_basename + weightfile_details +
".zip"
2009 yield self.add_to_output(evaluation_pdf_output)
2013 Run ``basf2_mva_evaluate.py`` subprocess to evaluate QE MVA.
2015 The MVA weight file created from training on the training data set is
2016 evaluated on separate test data.
2019 evaluation_pdf_output_basename = self.
teacher_task.weightfile_identifier_basename + weightfile_details +
".zip"
2020 evaluation_pdf_output_path = self.get_output_file_name(evaluation_pdf_output_basename)
2027 datafiles =
'datafiles/qe_records_N' + str(self.
n_events_testing) +
'_' + \
2030 datafiles = self.get_input_file_names(
2037 for req
in b2luigi.task.flatten(self.
requires()):
2041 if hasattr(teacher_task,
'recotrack_option')
and isinstance(self, RecoTrackQEEvaluationTask):
2042 records_files = teacher_task.get_input_file_names(
2046 random_seed=self.
process_type +
'_' + teacher_task.random_seed,
2047 recotrack_option=teacher_task.recotrack_option))
2049 records_files = teacher_task.get_input_file_names(
2053 random_seed=self.
process_type +
'_' + teacher_task.random_seed))
2055 "basf2_mva_evaluate.py",
2057 self.get_input_file_names(
2061 "--train_datafiles",
2068 evaluation_pdf_output_path
2071 'The weightfile for QE Evaluate is:',
2072 self.get_input_file_names(
2080 subprocess.run(cmd, check=
True)
2085 Run ``basf2_mva_evaluate.py`` for the VXD quality estimator on separate test data
2089 teacher_task = VXDQETeacherTask
2092 data_collection_task = VXDQEDataCollectionTask
2095 task_acronym =
'vxd'
2100 Run ``basf2_mva_evaluate.py`` for the CDC quality estimator on separate test data
2104 teacher_task = CDCQETeacherTask
2107 data_collection_task = CDCQEDataCollectionTask
2110 task_acronym =
'cdc'
2115 Run ``basf2_mva_evaluate.py`` for the final, combined quality estimator on
2120 teacher_task = RecoTrackQETeacherTask
2123 data_collection_task = RecoTrackQEDataCollectionTask
2126 task_acronym =
'rec'
2128 cdc_training_target = b2luigi.Parameter()
2132 Generate list of luigi Tasks that this Task depends on.
2149 filename=
'datafiles/qe_records_N' + str(self.
n_events_testing) +
'_' + process +
'_test_' +
2154 num_processes=MasterTask.num_processes,
2164 Create a PDF file with validation plots for a quality estimator produced
2165 from the ROOT ntuples produced by a harvesting validation task
2168 n_events_testing = b2luigi.IntParameter()
2170 n_events_training = b2luigi.IntParameter()
2172 experiment_number = b2luigi.IntParameter()
2176 process_type = b2luigi.Parameter(
2183 exclude_variables = b2luigi.ListParameter(
2189 fast_bdt_option = b2luigi.ListParameter(
2191 hashed=
True, default=[200, 8, 3, 0.1]
2195 primaries_only = b2luigi.BoolParameter(
2201 cdc_training_target =
"truth"
2206 Specifies related harvesting validation task which produces the ROOT
2207 files with the data that is plotted by this task.
2209 raise NotImplementedError(
"Must define a QI harvesting validation task for which to do the plots")
2215 Name of the output PDF file containing the validation plots
2218 return validation_harvest_basename.replace(
".root",
"_plots.pdf")
2222 Generate list of luigi Tasks that this Task depends on.
2228 Generate list of output files that the task should produce.
2229 The task is considered finished if and only if the outputs all exist.
2234 @b2luigi.on_temporary_files
2237 Use basf2_mva teacher to create MVA weightfile from collected training
2240 Main process that is dispatched by the ``run`` method that is inherited
2245 validation_harvest_path = self.get_input_file_names(validation_harvest_basename)[0]
2246 print(
'\nThe validation harvest path is:', validation_harvest_path,
'\n')
2250 'is_fake',
'is_clone',
'is_matched',
'quality_indicator',
2251 'experiment_number',
'run_number',
'event_number',
'pr_store_array_number',
2252 'pt_estimate',
'z0_estimate',
'd0_estimate',
'tan_lambda_estimate',
2253 'phi0_estimate',
'pt_truth',
'z0_truth',
'd0_truth',
'tan_lambda_truth',
2257 pr_df = uproot.open(validation_harvest_path)[
'pr_tree/pr_tree'].arrays(pr_columns, library=
'pd')
2259 'experiment_number',
2262 'pr_store_array_number',
2267 mc_df = uproot.open(validation_harvest_path)[
'mc_tree/mc_tree'].arrays(mc_columns, library=
'pd')
2269 mc_df = mc_df[mc_df.is_primary.eq(
True)]
2272 qi_cuts = np.linspace(0., 1, 20, endpoint=
False)
2279 with PdfPages(output_pdf_file_path, keep_empty=
False)
as pdf:
2284 titlepage_fig, titlepage_ax = plt.subplots()
2285 titlepage_ax.axis(
"off")
2286 title = f
"Quality Estimator validation plots from {self.__class__.__name__}"
2287 titlepage_ax.set_title(title)
2289 weightfile_identifier = teacher_task.get_weightfile_identifier(
2292 "Date": datetime.today().strftime(
"%Y-%m-%d %H:%M"),
2293 "Created by steering file": os.path.realpath(__file__),
2294 "Created from data in": validation_harvest_path,
2296 "weight file": weightfile_identifier,
2298 if hasattr(self,
'exclude_variables'):
2300 meta_data_string = (format_dictionary(meta_data) +
2301 "\n\n(For all MVA training parameters look into the produced weight file)")
2302 luigi_params = get_serialized_parameters(self)
2303 luigi_param_string = (f
"\n\nb2luigi parameters for {self.__class__.__name__}\n" +
2304 format_dictionary(luigi_params))
2305 title_page_text = meta_data_string + luigi_param_string
2306 titlepage_ax.text(0, 1, title_page_text, ha=
"left", va=
"top", wrap=
True, fontsize=8)
2307 pdf.savefig(titlepage_fig)
2308 plt.close(titlepage_fig)
2310 fake_rates = get_uncertain_means_for_qi_cuts(pr_df,
"is_fake", qi_cuts)
2311 fake_fig, fake_ax = plt.subplots()
2312 fake_ax.set_title(
"Fake rate")
2313 plot_with_errobands(fake_rates, ax=fake_ax)
2314 fake_ax.set_ylabel(
"fake rate")
2315 fake_ax.set_xlabel(
"quality indicator requirement")
2316 pdf.savefig(fake_fig, bbox_inches=
"tight")
2320 clone_rates = get_uncertain_means_for_qi_cuts(pr_df,
"is_clone", qi_cuts)
2321 clone_fig, clone_ax = plt.subplots()
2322 clone_ax.set_title(
"Clone rate")
2323 plot_with_errobands(clone_rates, ax=clone_ax)
2324 clone_ax.set_ylabel(
"clone rate")
2325 clone_ax.set_xlabel(
"quality indicator requirement")
2326 pdf.savefig(clone_fig, bbox_inches=
"tight")
2327 plt.close(clone_fig)
2334 pr_track_identifiers = [
'experiment_number',
'run_number',
'event_number',
'pr_store_array_number']
2336 left=mc_df, right=pr_df[pr_track_identifiers + [
'quality_indicator']],
2338 on=pr_track_identifiers
2341 missing_fractions = (
2342 _my_uncertain_mean(mc_df[
2343 mc_df.quality_indicator.isnull() | (mc_df.quality_indicator > qi_cut)][
'is_missing'])
2344 for qi_cut
in qi_cuts
2347 findeff_fig, findeff_ax = plt.subplots()
2348 findeff_ax.set_title(
"Finding efficiency")
2349 finding_efficiencies = 1.0 - upd.Series(data=missing_fractions, index=qi_cuts)
2350 plot_with_errobands(finding_efficiencies, ax=findeff_ax)
2351 findeff_ax.set_ylabel(
"finding efficiency")
2352 findeff_ax.set_xlabel(
"quality indicator requirement")
2353 pdf.savefig(findeff_fig, bbox_inches=
"tight")
2354 plt.close(findeff_fig)
2359 fake_roc_fig, fake_roc_ax = plt.subplots()
2360 fake_roc_ax.set_title(
"Fake rate vs. finding efficiency ROC curve")
2361 fake_roc_ax.errorbar(x=finding_efficiencies.nominal_value, y=fake_rates.nominal_value,
2362 xerr=finding_efficiencies.std_dev, yerr=fake_rates.std_dev, elinewidth=0.8)
2363 fake_roc_ax.set_xlabel(
'finding efficiency')
2364 fake_roc_ax.set_ylabel(
'fake rate')
2365 pdf.savefig(fake_roc_fig, bbox_inches=
"tight")
2366 plt.close(fake_roc_fig)
2369 clone_roc_fig, clone_roc_ax = plt.subplots()
2370 clone_roc_ax.set_title(
"Clone rate vs. finding efficiency ROC curve")
2371 clone_roc_ax.errorbar(x=finding_efficiencies.nominal_value, y=clone_rates.nominal_value,
2372 xerr=finding_efficiencies.std_dev, yerr=clone_rates.std_dev, elinewidth=0.8)
2373 clone_roc_ax.set_xlabel(
'finding efficiency')
2374 clone_roc_ax.set_ylabel(
'clone rate')
2375 pdf.savefig(clone_roc_fig, bbox_inches=
"tight")
2376 plt.close(clone_roc_fig)
2381 kinematic_qi_cuts = [0, 0.5, 0.9]
2385 params = [
'd0',
'z0',
'pt',
'tan_lambda',
'phi0']
2390 "tan_lambda":
r"$\tan{\lambda}$",
2397 "tan_lambda":
"rad",
2400 n_kinematic_bins = 75
2402 "pt": np.linspace(0, np.percentile(pr_df[
'pt_truth'].dropna(), 95), n_kinematic_bins),
2403 "z0": np.linspace(-0.1, 0.1, n_kinematic_bins),
2404 "d0": np.linspace(0, 0.01, n_kinematic_bins),
2405 "tan_lambda": np.linspace(-2, 3, n_kinematic_bins),
2406 "phi0": np.linspace(0, 2 * np.pi, n_kinematic_bins)
2410 kinematic_qi_cuts = [0, 0.5, 0.8]
2411 blue, yellow, green = plt.get_cmap(
"tab10").colors[0:3]
2412 for param
in params:
2413 fig, axarr = plt.subplots(ncols=len(kinematic_qi_cuts), sharey=
True, sharex=
True, figsize=(14, 6))
2414 fig.suptitle(f
"{label_by_param[param]} distributions")
2415 for i, qi
in enumerate(kinematic_qi_cuts):
2417 ax.set_title(f
"QI > {qi}")
2418 incut = pr_df[(pr_df[
'quality_indicator'] > qi)]
2419 incut_matched = incut[incut.is_matched.eq(
True)]
2420 incut_clones = incut[incut.is_clone.eq(
True)]
2421 incut_fake = incut[incut.is_fake.eq(
True)]
2424 if any(series.empty
for series
in (incut, incut_matched, incut_clones, incut_fake)):
2425 ax.text(0.5, 0.5,
"Not enough data in bin", ha=
"center", va=
"center", transform=ax.transAxes)
2428 bins = bins_by_param[param]
2429 stacked_histogram_series_tuple = (
2430 incut_matched[f
'{param}_estimate'],
2431 incut_clones[f
'{param}_estimate'],
2432 incut_fake[f
'{param}_estimate'],
2434 histvals, _, _ = ax.hist(stacked_histogram_series_tuple,
2436 bins=bins, range=(bins.min(), bins.max()),
2437 color=(blue, green, yellow),
2438 label=(
"matched",
"clones",
"fakes"))
2439 ax.set_xlabel(f
'{label_by_param[param]} estimate / ({unit_by_param[param]})')
2440 ax.set_ylabel(
'# tracks')
2441 axarr[0].legend(loc=
"upper center", bbox_to_anchor=(0, -0.15))
2442 pdf.savefig(fig, bbox_inches=
"tight")
2448 Create a PDF file with validation plots for the VXDTF2 track quality
2449 estimator produced from the ROOT ntuples produced by a VXDTF2 track QE
2450 harvesting validation task
2456 Harvesting validation task to require, which produces the ROOT files
2457 with variables to produce the VXD QE validation plots.
2465 num_processes=MasterTask.num_processes,
2472 Create a PDF file with validation plots for the CDC track quality estimator
2473 produced from the ROOT ntuples produced by a CDC track QE harvesting
2477 training_target = b2luigi.Parameter()
2482 Harvesting validation task to require, which produces the ROOT files
2483 with variables to produce the CDC QE validation plots.
2492 num_processes=MasterTask.num_processes,
2499 Create a PDF file with validation plots for the reco MVA track quality
2500 estimator produced from the ROOT ntuples produced by a reco track QE
2501 harvesting validation task
2504 cdc_training_target = b2luigi.Parameter()
2509 Harvesting validation task to require, which produces the ROOT files
2510 with variables to produce the final MVA track QE validation plots.
2519 num_processes=MasterTask.num_processes,
2526 Wrapper task that needs to finish for b2luigi to finish running this steering file.
2528 It is done if the outputs of all required subtasks exist. It is thus at the
2529 top of the luigi task graph. Edit the ``requires`` method to steer which
2530 tasks and with which parameters you want to run.
2535 process_type = b2luigi.get_setting(
2537 "process_type", default=
'BBBAR'
2541 n_events_training = b2luigi.get_setting(
2543 "n_events_training", default=20000
2547 n_events_testing = b2luigi.get_setting(
2549 "n_events_testing", default=5000
2553 n_events_per_task = b2luigi.get_setting(
2555 "n_events_per_task", default=100
2559 num_processes = b2luigi.get_setting(
2561 "basf2_processes_per_worker", default=0
2565 datafiles = b2luigi.get_setting(
"datafiles")
2567 bkgfiles_by_exp = b2luigi.get_setting(
"bkgfiles_by_exp")
2569 bkgfiles_by_exp = {int(key): val
for (key, val)
in bkgfiles_by_exp.items()}
2571 exclude_variables_cdc = [
2572 "has_matching_segment",
2577 "cont_layer_variance",
2582 "cont_layer_max_vs_last",
2583 "cont_layer_first_vs_min",
2585 "cont_layer_occupancy",
2587 "super_layer_variance",
2588 "super_layer_max_vs_last",
2589 "super_layer_first_vs_min",
2590 "super_layer_occupancy",
2591 "drift_length_mean",
2592 "drift_length_variance",
2596 "norm_drift_length_mean",
2597 "norm_drift_length_variance",
2598 "norm_drift_length_max",
2599 "norm_drift_length_min",
2600 "norm_drift_length_sum",
2616 exclude_variables_vxd = [
2617 'energyLoss_max',
'energyLoss_min',
'energyLoss_mean',
'energyLoss_std',
'energyLoss_sum',
2618 'size_max',
'size_min',
'size_mean',
'size_std',
'size_sum',
2619 'seedCharge_max',
'seedCharge_min',
'seedCharge_mean',
'seedCharge_std',
'seedCharge_sum',
2620 'tripletFit_P_Mag',
'tripletFit_P_Eta',
'tripletFit_P_Phi',
'tripletFit_P_X',
'tripletFit_P_Y',
'tripletFit_P_Z']
2622 exclude_variables_rec = [
2634 'N_diff_PXD_SVD_RecoTracks',
2635 'N_diff_SVD_CDC_RecoTracks',
2637 'Fit_NFailedPoints',
2639 'N_TrackPoints_without_KalmanFitterInfo',
2640 'N_Hits_without_TrackPoint',
2641 'SVD_CDC_CDCwall_Chi2',
2642 'SVD_CDC_CDCwall_Pos_diff_Z',
2643 'SVD_CDC_CDCwall_Pos_diff_Pt',
2644 'SVD_CDC_CDCwall_Pos_diff_Theta',
2645 'SVD_CDC_CDCwall_Pos_diff_Phi',
2646 'SVD_CDC_CDCwall_Pos_diff_Mag',
2647 'SVD_CDC_CDCwall_Pos_diff_Eta',
2648 'SVD_CDC_CDCwall_Mom_diff_Z',
2649 'SVD_CDC_CDCwall_Mom_diff_Pt',
2650 'SVD_CDC_CDCwall_Mom_diff_Theta',
2651 'SVD_CDC_CDCwall_Mom_diff_Phi',
2652 'SVD_CDC_CDCwall_Mom_diff_Mag',
2653 'SVD_CDC_CDCwall_Mom_diff_Eta',
2654 'SVD_CDC_POCA_Pos_diff_Z',
2655 'SVD_CDC_POCA_Pos_diff_Pt',
2656 'SVD_CDC_POCA_Pos_diff_Theta',
2657 'SVD_CDC_POCA_Pos_diff_Phi',
2658 'SVD_CDC_POCA_Pos_diff_Mag',
2659 'SVD_CDC_POCA_Pos_diff_Eta',
2660 'SVD_CDC_POCA_Mom_diff_Z',
2661 'SVD_CDC_POCA_Mom_diff_Pt',
2662 'SVD_CDC_POCA_Mom_diff_Theta',
2663 'SVD_CDC_POCA_Mom_diff_Phi',
2664 'SVD_CDC_POCA_Mom_diff_Mag',
2665 'SVD_CDC_POCA_Mom_diff_Eta',
2672 'SVD_FitSuccessful',
2673 'CDC_FitSuccessful',
2676 'is_Vzero_Daughter',
2688 'weight_firstCDCHit',
2689 'weight_lastSVDHit',
2692 'smoothedChi2_mean',
2694 'smoothedChi2_median',
2695 'smoothedChi2_n_zeros',
2696 'smoothedChi2_firstCDCHit',
2697 'smoothedChi2_lastSVDHit',
2699 [
"SVD_" + x
for x
in exclude_variables_vxd] + \
2700 [
"SVDbefore_" + x
for x
in exclude_variables_vxd]
2704 Generate list of tasks that needs to be done for luigi to finish running
2707 cdc_training_targets = [
2712 fast_bdt_options = []
2721 fast_bdt_options.append([350, 6, 5, 0.1])
2723 experiment_numbers = b2luigi.get_setting(
"experiment_numbers")
2726 for experiment_number, cdc_training_target, fast_bdt_option
in itertools.product(
2727 experiment_numbers, cdc_training_targets, fast_bdt_options
2730 if b2luigi.get_setting(
"test_selected_task", default=
False):
2733 for cut
in [
'000',
'070',
'090',
'095']:
2737 experiment_number=experiment_number,
2739 recotrack_option=
'useCDC_useVXD_deleteCDCQI'+cut,
2740 cdc_training_target=cdc_training_target,
2741 fast_bdt_option=fast_bdt_option,
2746 experiment_number=experiment_number,
2752 experiment_number=experiment_number,
2754 training_target=cdc_training_target,
2755 fast_bdt_option=fast_bdt_option,
2763 experiment_number=experiment_number,
2769 experiment_number=experiment_number,
2775 experiment_number=experiment_number,
2777 recotrack_option=
'deleteCDCQI080',
2778 cdc_training_target=cdc_training_target,
2779 fast_bdt_option=fast_bdt_option,
2783 if b2luigi.get_setting(
"run_validation_tasks", default=
True):
2788 experiment_number=experiment_number,
2789 cdc_training_target=cdc_training_target,
2791 fast_bdt_option=fast_bdt_option,
2797 experiment_number=experiment_number,
2799 training_target=cdc_training_target,
2800 fast_bdt_option=fast_bdt_option,
2807 experiment_number=experiment_number,
2808 fast_bdt_option=fast_bdt_option,
2811 if b2luigi.get_setting(
"run_mva_evaluate", default=
True):
2818 experiment_number=experiment_number,
2819 cdc_training_target=cdc_training_target,
2821 fast_bdt_option=fast_bdt_option,
2827 experiment_number=experiment_number,
2829 fast_bdt_option=fast_bdt_option,
2830 training_target=cdc_training_target,
2836 experiment_number=experiment_number,
2838 fast_bdt_option=fast_bdt_option,
2842if __name__ ==
"__main__":
2845 nEventsTestOnData = b2luigi.get_setting(
"n_events_test_on_data", default=-1)
2846 if nEventsTestOnData > 0
and 'DATA' in b2luigi.get_setting(
"process_type", default=
"BBBAR"):
2847 from ROOT
import Belle2
2849 environment.setNumberEventsOverride(nEventsTestOnData)
2852 globaltags = b2luigi.get_setting(
"globaltags", default=[])
2853 if len(globaltags) > 0:
2854 basf2.conditions.reset()
2855 for gt
in globaltags:
2856 basf2.conditions.prepend_globaltag(gt)
2857 workers = b2luigi.get_setting(
"workers", default=1)
2858 b2luigi.process(
MasterTask(), workers=workers)
get_background_files(folder=None, output_file_info=True)
static Environment & Instance()
Static method to get a reference to the Environment instance.
experiment_number
Experiment number of the conditions database, e.g.
get_records_file_name(self, n_events=None, random_seed=None)
Filename of the recorded/collected data for the final QE MVA training.
n_events
Number of events to generate.
get_input_files(self, n_events=None, random_seed=None)
random_seed
Random basf2 seed used by the GenerateSimTask.
add_tracking_with_quality_estimation(self, path)
training_target
Feature/variable to use as truth label in the quality estimator MVA classifier.
str object_name
DBObject name.
harvesting_validation_task_instance(self)
training_target
Feature/variable to use as truth label in the quality estimator MVA classifier.
filename
filename to check
experiment_number
Experiment number of the conditions database, e.g.
n_events
Number of events to generate.
bkgfiles_dir
Directory with overlay background root files.
output_file_name(self, n_events=None, random_seed=None)
Name of the ROOT output file with generated and simulated events.
random_seed
Random basf2 seed.
TrackQETeacherBaseTask teacher_task(self)
str reco_output_file_name
Name of the output of the RootOutput module with reconstructed events.
experiment_number
Experiment number of the conditions database, e.g.
fast_bdt_option
Hyperparameter option of the FastBDT algorithm.
str cdc_training_target
Feature/variable to use as truth label for the CDC track quality estimator.
# USESIM and USEREC process_type
Define which kind of process shall be used.
n_events_training
Number of events to generate for the training data set.
n_events_testing
Number of events to generate for the test data set.
str validation_output_file_name
Name of the "harvested" ROOT output file with variables that can be used for validation.
None add_tracking_with_quality_estimation(self, basf2.Path path)
exclude_variables
List of collected variables to not use in the training of the QE MVA classifier.
process_type
Define which kind of process shall be used.
list exclude_variables_rec
list of variables to exclude for the recotrack mva:
list exclude_variables_vxd
list of variables to exclude for the vxd mva:
n_events_training
Number of events to generate for the training data set.
n_events_testing
Number of events to generate for the test data set.
list exclude_variables_cdc
list of variables to exclude for the cdc mva.
num_processes
Number of basf2 processes to use in Basf2PathTasks.
process_type
Define which kind of process shall be used.
experiment_number
Experiment number of the conditions database, e.g.
fast_bdt_option
Hyperparameter option of the FastBDT algorithm.
str cdc_training_target
Feature/variable to use as truth label for the CDC track quality estimator.
n_events_training
Number of events to generate for the training data set.
n_events_testing
Number of events to generate for the test data set.
primaries_only
Whether to normalize the track finding efficiencies to primary particles only.
exclude_variables
List of collected variables to not use in the training of the QE MVA classifier.
HarvestingValidationBaseTask harvesting_validation_task_instance(self)
output_pdf_file_basename
Name of the output PDF file containing the validation plots.
cdc_training_target
Feature/variable to use as truth label for the CDC track quality estimator.
experiment_number
Experiment number of the conditions database, e.g.
get_records_file_name(self, n_events=None, random_seed=None, recotrack_option=None)
Filename of the recorded/collected data for the final QE MVA training.
fast_bdt_option
Hyperparameter option of the FastBDT algorithm.
recotrack_option
RecoTrack option, use string that is additive: deleteCDCQI0XY (= deletes CDCTracks with CDC-QI below ...
n_events
Number of events to generate.
get_input_files(self, n_events=None, random_seed=None)
random_seed
Random basf2 seed used by the GenerateSimTask.
cdc_training_target
Feature/variable to use as truth label for the CDC track quality estimator.
add_tracking_with_quality_estimation(self, path)
cdc_training_target
Feature/variable to use as truth label for the CDC track quality estimator.
str object_name
DBObject name.
harvesting_validation_task_instance(self)
experiment_number
Experiment number of the conditions database, e.g.
n_events
Number of events to generate.
bkgfiles_dir
Directory with overlay background root files.
output_file_name(self, n_events=None, random_seed=None)
Name of the ROOT output file with generated and simulated events.
random_seed
Random basf2 seed.
process_type
Define which kind of process shall be used.
experiment_number
Experiment number of the conditions database, e.g.
fast_bdt_option
Hyperparameter options for the FastBDT algorithm.
n_events_training
Number of events to generate for the training data set.
n_events_testing
Number of events to generate for the test data set.
exclude_variables
List of collected variables to not use in the training of the QE MVA classifier.
training_target
Feature/variable to use as truth label in the quality estimator MVA classifier.
teacher_task
Task that is required by the evaluation base class to create the MVA weightfile that needs to be eval...
Basf2PathTask data_collection_task(self)
process_type
Define which kind of process shall be used.
experiment_number
Experiment number of the conditions database, e.g.
fast_bdt_option
Hyperparameter option of the FastBDT algorithm.
recotrack_option
RecoTrack option, use string that is additive: deleteCDCQI0XY (= deletes CDCTracks with CDC-QI below ...
n_events_training
Number of events to generate for the training data set.
exclude_variables
List of collected variables to not use in the training of the QE MVA classifier.
weightfile_identifier_basename(self)
training_target
Feature/variable to use as truth label in the quality estimator MVA classifier.
get_weightfile_identifier(self, fast_bdt_option=None, recotrack_option=None)
Basf2PathTask data_collection_task(self)
experiment_number
Experiment number of the conditions database, e.g.
get_records_file_name(self, n_events=None, random_seed=None)
Filename of the recorded/collected data for the final QE MVA training.
n_events
Number of events to generate.
get_input_files(self, n_events=None, random_seed=None)
random_seed
Random basf2 seed used by the GenerateSimTask.
add_tracking_with_quality_estimation(self, path)
str object_name
DBObject name.
harvesting_validation_task_instance(self)
add_simulation(path, components=None, bkgfiles=None, bkgOverlay=True, forceSetPXDDataReduction=False, usePXDDataReduction=True, cleanupPXDDataReduction=True, generate_2nd_cdc_hits=False, simulateT0jitter=True, isCosmics=False, FilterEvents=False, usePXDGatedMode=False, skipExperimentCheckForBG=False, ignoreRunNumberForBG=False, save_slow_pions_in_mc=False, save_all_charged_particles_in_mc=False)