Run a generic SIDIS asymmetry analysis with CLAS12 data.
Use clas12-analysis or your own software to produce the input ROOT trees with event by event kinematics selecting all unique
Begin by cloning the repository:
git clone --recurse-submodules https://github.com/mfmceneaney/saga.git- Python >=3.7.3
- A compiler with C++11 support
- Pip 10+ or CMake >= 3.4 (or 3.14+ on Windows, which was the first version to support VS 2019)
- ROOT
This is a CMake project so you can build wherever but this is probably the simplest way to go. From the top-level project directory run:
cmake -S . -B build -DBUILD_DOXYGEN=FALSE
cmake --build build
cmake --install build --prefix $PWD/binYou should now have several executables in your bin directory.
You can manually source the environment scripts or add the following to your startup script to include these executables on your $PATH:
# Add SAGA environment variables: https://github.com/mfmceneaney/saga.git
cd /path/to/saga
source bin/env.sh
cd -You may install via pip using the path to the top-level repository directory:
pip install -e /path/to/sagaThen you can import the libraries in your python code with:
import sagaYou may also install and run the project as a Docker or apptainer/singularity container. A Dockerfile (docker/Dockerfile) and
a Singularity/Apptainer definition (singularity/saga.def) are provided. Below are minimal build and run examples that
bind a host directory (for input and output) into the container so you can read/write data between the container and host.
Build the image from source:
git clone --recurse-submodules https://github.com/mfmceneaney/saga.git
cd saga
docker build -t saga:latest -f docker/Dockerfile .Or, pull a prebuilt image
docker pull ghcr.io/mfmceneaney/saga-docker:latestThen, run the container and bind a host folder (e.g. /data) into /data
in the container with the option -v <host_dir>:<container_dir>
docker run --rm -it -v /path/on/host:/data saga:latestYou may run the project from the container like so:
docker run --rm -it -v /path/on/host:/data saga:latest /usr/src/saga/bin/run.sh --helpSimilarly, you may also use apptainer/singularity to build and run the container. Currently, apptainer and singularity have not diverged much and so they are interchangeable in the following commands. However, this is not guaranteed to last.
Build the image from source:
git clone --recurse-submodules https://github.com/mfmceneaney/saga.git
cd saga
apptainer build saga.sif singularity/saga.defOr, pull a prebuilt image:
apptainer pull saga.sif oras://ghcr.io/mfmceneaney/saga-apptainer:latestThen, run the project from the container and bind a host folder (e.g. /data) into /data
in the container with the option -v <host_dir>:<container_dir>:
singularity exec -B /path/on/host:/data saga.sif getKinBinnedAsymOnce you build and start the container you should have the following environment variables:
SAGA_HOMESAGA_BUILD-
SAGA_BINFurthermore, the project executables in$SAGA_BINshould be available from your$PATH.
Check out the documentation page on Read The Docs!
Additional prerequisites for building the documentation:
- doxygen
- sphinx (available with pip)
- sphinx_rtd_theme (available with pip)
- breathe (available with pip)
- myst-parser (available with pip)
To build the documentation run cmake with the BUILD_DOXYGEN option set to TRUE:
cd build
cmake .. -DBUILD_DOXYGEN=TRUE
makeSee the example configuration yamls for each C++ executable and the example python scripts in the tutorials folder.
Below is a detailed description of the project and how one might run an analysis.
This library assumes your input data are stored in ROOT TTrees whose entries are event-level kinematics.
The provided C++ executables are entirely branch name agnostic. These executables also assume configuration options will be passed in yaml file format which makes running analyses with different configuration option values extremely straightforward and easily organized.
Complementary to this aspect, the python libraries provide an easy interface for setting up job directories with different configurations and submitting jobs to slurm. See, in particular, the saga.orchestrate module.
The python libraries also provide some generic functionality for reading output asymmetry results from CSV files, aggregating results from job directories created by saga.orchestrate.create_jobs(), loading and computing systematics, and plotting asymmetry results and saving them to CSV. See, in particular, the saga.aggregate module.
The first step to any analysis should be to peruse your data. Use the getBinKinematicsTH1Ds to produce 1D histograms of your kinematic variables in each bin. You will also need average kinematics in each bin if you plan to compare with theory results. Use the getBinKinematics executable to get the statistics and average kinematics in each bin.
Use the findBinLimits executable to find the bin limits that will give roughly equal bin statistics for each binning variable in your dataset.
Detector reconstruction smears reconstructed kinematics across the true generated kinematics. To correct for this effect, one typically computes and then inverts a bin migration matrix. The bin migration matrix is defined such that each entry
Use the getBinMigration executable to compute bin migration fractions and save the results to a CSV file.
Some physics channels isolate an asymmetry produced from a particle, such as a
The method saga::signal::fitMass() allows one to apply a generic signal + background fit to an invariant mass spectrum in one or more variables. Starting parameters and even PDF formulas for both signal and background may be loaded in a bin dependent way by specifying the massfit_yamlfile_map argument mapping bin scheme ids from saga::analysis::getKinBinnedAsym() to paths for YAML files containing the appropriate arguments to be loaded by saga::signal::fitMass().
To correct for the background contributions to the final results there are two generally accepted methods.
The first, Sideband Subtraction is very straightforward and simply uses a weighted subtraction of the asymmetry result computed in an arbitrary region(s) adjacent to the signal mass region, the sideband(s). The weight
Solving for the signal asymmetry
Of course, the simplest way to apply this is to fit the asymmetry in the signal region and in the sideband region separately, and then find the true signal asymmetry
However, oftentimes many asymmetry terms will need to be fit simultaneously, and it becomes more reliable to fit both the signal and sideband simultaneously. This approach also allows one to treat
One may then simply read off the fitted values for
The second method,
Fitting an asymmetry
For a
since the acceptance may reasonably be assumed to not depend on the beam helicity
For an unbinned ML fit the acceptance naturally reduces to a relative luminosity factor between the positive and negative helicity subsets of the data (H. Wollny, Thesis, University of Freiburg, 2010., G. Smith, Thesis, University of Glasgow, 2008.). This may usually be assumed to be
An extended ML Fit simply introduces the normalization factor
Use the getKinBinnedAsym executable to run a set of generically binned ML asymmetry fits and save the results to a CSV file.
For
$D^{\Lambda}{LL'} = \frac{1}{\alpha{\Lambda} \overline{\lambda^2}}\frac{\sum_{i=1}^{N_{\Lambda}}\lambda_{i}\cos{\theta_{LL'}^i}}{\sum_{i=1}^{N_{\Lambda}}D(y_i) \cos^2{\theta_{LL'}^i}} ,,$
Here,
The method relies on the assumption that the luminosity averaged helicity
Use the getKinBinnedHB executable to run a set of generically binned HB asymmetry extractions and save the results to a CSV file.
To evaluate the effectiveness of your asymmetry extraction chain with all its fits and corrections, it is useful to inject an artificial asymmetry into simulated data where the event-level truth is known for each event. The injection algorithm proceeds as follows.
For each event, a random number
Otherwise, positive and negative helicity and spin values are generated with equal probability.
The probability
$w = \frac{1}{N} ( 1 + A_{UU} + S_{\parallel} A_{UL} + A_{UT}(\phi^{\mathrm{True}}{S}) + \lambda [A{LU} + S_{\parallel} A_{LL} + A_{LT}(\phi^{\mathrm{True}}_{S})] ),$
where
and
Note that, in almost all scenarios, the unpolarized and any even
To make projections of the uncertainties on planned asymmetry measurements for future experiments one must scale, in a sense "convert", uncertainties from simulated data to real data. This requires one to compute the uncertainties on an existing simulation dataset and its corresponding real dataset. These should provide a realistic comparison with the planned experiment. For example, one might use CLAS12 RGC simulation and data to obtain CLAS12 RGH projections since both use a polarized target.
To scale these uncertainties, one first assumes Poissonian statistics so
You must also compute ratio of the acceptance ratios, that is, the ratio of reconstructed to generated counts:
for the two simulation samples and then the projected statistics in a given kinematic bin
where
In practice, rather than computing
Contact: matthew.mceneaney@duke.edu