From 90db17c76c4014850c50d082469114944857a4e8 Mon Sep 17 00:00:00 2001
From: Dan Guest <daniel.hay.guest@cern.ch>
Date: Wed, 8 May 2024 16:34:33 +0200
Subject: [PATCH] Add PMGTruthWeightsAlgCfg, add unit tests for CA code

Add PMGTruthWeightsAlgCfg, add unit tests for CA code
---
 .../AsgAnalysisAlgorithms/CMakeLists.txt      | 10 ++++
 .../python/PMGTruthWeightAlgConfig.py         | 54 +++++++++++++++++++
 .../python/PileupReweightingAlgConfig.py      | 19 +++++++
 .../share/testPMGTruthWeightsAlg.py           | 42 +++++++++++++++
 .../share/testPileupReweightingAlgConfig.py   | 44 +++++++++++++++
 PhysicsAnalysis/Algorithms/README.md          |  7 +++
 6 files changed, 176 insertions(+)
 create mode 100644 PhysicsAnalysis/Algorithms/AsgAnalysisAlgorithms/python/PMGTruthWeightAlgConfig.py
 create mode 100755 PhysicsAnalysis/Algorithms/AsgAnalysisAlgorithms/share/testPMGTruthWeightsAlg.py
 create mode 100755 PhysicsAnalysis/Algorithms/AsgAnalysisAlgorithms/share/testPileupReweightingAlgConfig.py
 create mode 100644 PhysicsAnalysis/Algorithms/README.md

diff --git a/PhysicsAnalysis/Algorithms/AsgAnalysisAlgorithms/CMakeLists.txt b/PhysicsAnalysis/Algorithms/AsgAnalysisAlgorithms/CMakeLists.txt
index 31d702a14da0..52eee03fde47 100644
--- a/PhysicsAnalysis/Algorithms/AsgAnalysisAlgorithms/CMakeLists.txt
+++ b/PhysicsAnalysis/Algorithms/AsgAnalysisAlgorithms/CMakeLists.txt
@@ -81,6 +81,16 @@ if( XAOD_STANDALONE )
 
 else()
 
+   atlas_install_scripts(share/test*)
+
+   atlas_add_test( PMGTruthWeightsAlg
+    SCRIPT testPMGTruthWeightsAlg.py --max-events 10
+    POST_EXEC_SCRIPT nopost.sh )
+
+   atlas_add_test( PileupReweightingAlg
+    SCRIPT testPileupReweightingAlgConfig.py --max-events 10
+    POST_EXEC_SCRIPT nopost.sh )
+
    atlas_add_test( EventAlgsTestJobData
       SCRIPT athena.py
              AsgAnalysisAlgorithms/EventAlgorithmsTest_jobOptions.py - --data-type data
diff --git a/PhysicsAnalysis/Algorithms/AsgAnalysisAlgorithms/python/PMGTruthWeightAlgConfig.py b/PhysicsAnalysis/Algorithms/AsgAnalysisAlgorithms/python/PMGTruthWeightAlgConfig.py
new file mode 100644
index 000000000000..b3f25e09cfea
--- /dev/null
+++ b/PhysicsAnalysis/Algorithms/AsgAnalysisAlgorithms/python/PMGTruthWeightAlgConfig.py
@@ -0,0 +1,54 @@
+# Copyright (C) 2002-2024 CERN for the benefit of the ATLAS collaboration
+from AthenaServices.MetaDataSvcConfig import MetaDataSvcCfg
+from AthenaConfiguration.ComponentAccumulator import ComponentAccumulator
+from AthenaConfiguration.ComponentFactory import CompFactory
+
+
+# ATTENTION: This is a ComponentAccumulator-based configuration file
+# (not to be confused with ConfigAccumulator). If you are an analysis
+# user you are likely looking for GeneratorAnalysisBlock in
+# AsgAnalysisConfig.py. That uses the block-configuration generally
+# used for algorithms under PhysicsAnalysis/Algorithms. If you are
+# using the block configuration do not use this configuration. We
+# generally do not provide ComponentAccumulator-based configurations
+# for the CP algorithms, and a special exception was made for this
+# algorithm. Do not cite this as example why any other
+# ComponentAccumulator-based configurations should be added. You can
+# use this as an example for how ComponentAccumulator-based
+# configurations can look like, but do not try to extend this to cover
+# more CP algorithms. That is not supported, and you are likely to
+# encounter problems if you scale this up in the wrong way. This
+# configuration is covered by a unit test. Should it fail use your
+# best judgement whether to fix this configuration or to change it to
+# wrap the block configuration instead.
+
+def PMGTruthWeightAlgCfg(flags, systematicsRegex='.*'):
+    """Decorate systematically varied generator weights to
+    'EventInfo', with a human-readable name.
+
+    With systematicsRegex set to 'None', do not add the
+    SystematicsSvc.
+
+    """
+    ca = ComponentAccumulator()
+    # we need both the systematics service and the metadata service to
+    # make this tool work.
+    if systematicsRegex is not None:
+        ca.addService(
+            CompFactory.CP.SystematicsSvc(
+                name="SystematicsSvc",
+                sigmaRecommended=1,
+                systematicsRegex=systematicsRegex,
+            )
+        )
+    ca.merge(MetaDataSvcCfg(flags))
+    ca.addEventAlgo(
+        CompFactory.CP.PMGTruthWeightAlg(
+            name="PMGTruthWeightAlg",
+            truthWeightTool=CompFactory.PMGTools.PMGTruthWeightTool(
+                name="PMGTruthWeightTool"
+            ),
+            decoration = 'generatorWeight_%SYS%',
+        )
+    )
+    return ca
diff --git a/PhysicsAnalysis/Algorithms/AsgAnalysisAlgorithms/python/PileupReweightingAlgConfig.py b/PhysicsAnalysis/Algorithms/AsgAnalysisAlgorithms/python/PileupReweightingAlgConfig.py
index 0e273e771060..a9f1f95f7b0f 100644
--- a/PhysicsAnalysis/Algorithms/AsgAnalysisAlgorithms/python/PileupReweightingAlgConfig.py
+++ b/PhysicsAnalysis/Algorithms/AsgAnalysisAlgorithms/python/PileupReweightingAlgConfig.py
@@ -2,6 +2,24 @@
 from AthenaConfiguration.ComponentFactory import CompFactory
 from AthenaConfiguration.ComponentAccumulator import ComponentAccumulator
 
+# ATTENTION: This is a ComponentAccumulator-based configuration file
+# (not to be confused with ConfigAccumulator). If you are an analysis
+# user you are likely looking for some other Block in
+# AsgAnalysisConfig.py. That uses the block-configuration generally
+# used for algorithms under PhysicsAnalysis/Algorithms. If you are
+# using the block configuration do not use this configuration. We
+# generally do not provide ComponentAccumulator-based configurations
+# for the CP algorithms, and a special exception was made for this
+# algorithm. Do not cite this as example why any other
+# ComponentAccumulator-based configurations should be added. You can
+# use this as an example for how ComponentAccumulator-based
+# configurations can look like, but do not try to extend this to cover
+# more CP algorithms. That is not supported, and you are likely to
+# encounter problems if you scale this up in the wrong way. This
+# configuration is covered by a unit test. Should it fail use your
+# best judgement whether to fix this configuration or to change it to
+# wrap the block configuration instead.
+
 def PileupReweightingToolCfg(flags, name="PileupReweightingTool", **kwargs):
     acc = ComponentAccumulator()
     from Campaigns.Utils import getMCCampaign,Campaign
@@ -20,6 +38,7 @@ def PileupReweightingToolCfg(flags, name="PileupReweightingTool", **kwargs):
 
 def PileupReweightingAlgCfg(flags, name="PileupReweightingAlg", **kwargs):
     acc = ComponentAccumulator()
+    acc.addService(CompFactory.CP.SystematicsSvc("SystematicsSvc"))
     kwargs.setdefault("pileupReweightingTool", acc.popToolsAndMerge(PileupReweightingToolCfg(flags)))
     acc.addEventAlgo(CompFactory.CP.PileupReweightingAlg(name, **kwargs))
     return acc
diff --git a/PhysicsAnalysis/Algorithms/AsgAnalysisAlgorithms/share/testPMGTruthWeightsAlg.py b/PhysicsAnalysis/Algorithms/AsgAnalysisAlgorithms/share/testPMGTruthWeightsAlg.py
new file mode 100755
index 000000000000..70d729689835
--- /dev/null
+++ b/PhysicsAnalysis/Algorithms/AsgAnalysisAlgorithms/share/testPMGTruthWeightsAlg.py
@@ -0,0 +1,42 @@
+#!/usr/bin/env python
+# Copyright (C) 2002-2022 CERN for the benefit of the ATLAS collaboration
+"""
+Test to run PMGTruthWeightsAlg
+"""
+
+_input_help = "with no inputs use ASG_TEST_FILE_MC"
+
+from argparse import ArgumentParser
+import os
+
+from GaudiKernel.Configurable import DEBUG
+from AthenaConfiguration.MainServicesConfig import MainServicesCfg
+from AthenaConfiguration.ComponentFactory import CompFactory
+from AthenaPoolCnvSvc.PoolReadConfig import PoolReadCfg
+from AthenaConfiguration.AllConfigFlags import initConfigFlags
+from AsgAnalysisAlgorithms.PMGTruthWeightAlgConfig import PMGTruthWeightAlgCfg
+
+def get_parser():
+    parser = ArgumentParser(description=__doc__)
+    parser.add_argument('input_files', nargs='*', help=_input_help)
+    parser.add_argument('-m', '--max-events', type=int, const=10, nargs='?')
+    parser.add_argument('-d', '--debug-logs', action='store_true')
+    return parser.parse_args()
+
+def run():
+    args = get_parser()
+    flags = initConfigFlags()
+    flags.Input.Files = args.input_files or [os.environ['ASG_TEST_FILE_MC']]
+    if args.debug_logs:
+        flags.Exec.OutputLevel = DEBUG
+    if args.max_events:
+        flags.Exec.MaxEvents = args.max_events
+    ca = MainServicesCfg(flags)
+    ca.merge(PoolReadCfg(flags))
+
+    ca.merge(PMGTruthWeightAlgCfg(flags))
+
+    ca.run()
+
+if __name__ == '__main__':
+    run()
diff --git a/PhysicsAnalysis/Algorithms/AsgAnalysisAlgorithms/share/testPileupReweightingAlgConfig.py b/PhysicsAnalysis/Algorithms/AsgAnalysisAlgorithms/share/testPileupReweightingAlgConfig.py
new file mode 100755
index 000000000000..ef2b0ef5dde2
--- /dev/null
+++ b/PhysicsAnalysis/Algorithms/AsgAnalysisAlgorithms/share/testPileupReweightingAlgConfig.py
@@ -0,0 +1,44 @@
+#!/usr/bin/env python
+# Copyright (C) 2002-2022 CERN for the benefit of the ATLAS collaboration
+"""
+Test to run PileupReweightingToolCfg
+"""
+
+_input_help = "with no inputs use ASG_TEST_FILE_MC"
+
+from argparse import ArgumentParser
+import os
+
+from GaudiKernel.Configurable import DEBUG
+from AthenaConfiguration.MainServicesConfig import MainServicesCfg
+from AthenaConfiguration.ComponentFactory import CompFactory
+from AthenaPoolCnvSvc.PoolReadConfig import PoolReadCfg
+from AthenaConfiguration.AllConfigFlags import initConfigFlags
+from AsgAnalysisAlgorithms.PileupReweightingAlgConfig import (
+    PileupReweightingAlgCfg
+)
+
+def get_parser():
+    parser = ArgumentParser(description=__doc__)
+    parser.add_argument('input_files', nargs='*', help=_input_help)
+    parser.add_argument('-m', '--max-events', type=int, const=10, nargs='?')
+    parser.add_argument('-d', '--debug-logs', action='store_true')
+    return parser.parse_args()
+
+def run():
+    args = get_parser()
+    flags = initConfigFlags()
+    flags.Input.Files = args.input_files or [os.environ['ASG_TEST_FILE_MC']]
+    if args.debug_logs:
+        flags.Exec.OutputLevel = DEBUG
+    if args.max_events:
+        flags.Exec.MaxEvents = args.max_events
+    ca = MainServicesCfg(flags)
+    ca.merge(PoolReadCfg(flags))
+
+    ca.merge(PileupReweightingAlgCfg(flags))
+
+    ca.run()
+
+if __name__ == '__main__':
+    run()
diff --git a/PhysicsAnalysis/Algorithms/README.md b/PhysicsAnalysis/Algorithms/README.md
new file mode 100644
index 000000000000..0e54b8d04139
--- /dev/null
+++ b/PhysicsAnalysis/Algorithms/README.md
@@ -0,0 +1,7 @@
+## Common CP Algorithms
+
+You can use these to build your analysis framework. They should provide all the most up to date recommendations from the Combined Performance (CP) groups.
+
+### Policies for developers:
+
+- **Do not** add `ComponentAccumulator`-based configuration here. All configuration should be based on `ConfigBlock`.
-- 
GitLab