A JANA2-based application for the Compton experiment to process data from EVIO-format files.
The application uses a two-level event structure (block-level and physics event-level) to process EVIO data:
-
JEventSource_EVIO reads EVIO files and creates block-level events:
- Extracts run numbers from run-control events (tags 0xFFD0–0xFFDF) and skips those events
- In
Emit, wraps each EVIO event in anEvioEventWrapperand inserts it into a block-levelJEvent - In
ProcessParallel, usesEvioEventParsertogether withBankParserimplementations registered inJEventService_BankParsersMapto decode the wrapped EVIO blocks intoPhysicsEventobjects containing detector hits, and inserts thosePhysicsEventobjects into the same block-level event
-
JEventUnfolder_EVIO unfolds block-level events into physics event-level child events:
- Takes
PhysicsEventobjects from the block-level parent event - Creates individual physics event-level child events
- Takes
-
JEventProcessor_Compton processes physics event level events:
- Receives FADC250 waveform and pulse hits
- Writes waveform data to a ROOT TTree
- Fills histograms with pulse integral distributions
- Outputs results to a ROOT file
Before building this application, ensure you have:
- CMake 3.16 or higher
- C++20 compatible compiler
- Git (for cloning dependencies)
- ROOT 6.36.04 (for data analysis and visualization)
This project requires the following dependencies:
JANA2 provides the core event processing framework for this application.
git clone https://github.com/JeffersonLab/JANA2.git JANA2
cd JANA2
cmake -S . -B build -DCMAKE_INSTALL_PREFIX=`pwd`
cmake --build build --target install -j 20The EVIO library is required for reading and parsing EVIO format data files.
git clone https://github.com/JeffersonLab/evio/
cd evio
git checkout v6.1.2
cmake -S . -B build
cmake --build build --target install --parallelInstall ROOT following the guide at https://root.cern/install/
- Configure the build:
cmake -S . -B build -DCMAKE_PREFIX_PATH="/path/to/JANA2;/path/to/EVIO/Linux-x86_64;/path/to/ROOT"Replace the paths with your actual installation directories:
/path/to/JANA2- Your JANA2 directory/path/to/EVIO- Your EVIO directory/path/to/ROOT- Your ROOT installation
- Build the application:
cmake --build build --parallelBuild Types: Add -DCMAKE_BUILD_TYPE=Debug for debugging or -DCMAKE_BUILD_TYPE=Release for optimized builds.
# 1. Build JANA2
git clone https://github.com/JeffersonLab/JANA2.git JANA2
cd JANA2
cmake -S . -B build -DCMAKE_INSTALL_PREFIX=`pwd`
cmake --build build --target install -j 20
cd ..
# 2. Build EVIO
git clone https://github.com/JeffersonLab/evio/
cd evio
git checkout v6.1.2
cmake -S . -B build
cmake --build build --target install --parallel
cd ..
# 3. Build application (adjust ROOT path as needed)
cd compton_exp
cmake -S . -B build -DCMAKE_PREFIX_PATH="/path/to/JANA2;/path/to/EVIO/Linux-x86_64;/path/to/ROOT"
cmake --build build --parallelNote: ROOT installation is not shown here, install ROOT first (see Dependencies section).
After building, run the application with:
./build/compton [jana_options] <evio_file1> [evio_file2] ...The application will process the specified EVIO files and create a ROOT output file (compton.root).
You can specify a custom ROOT output filename:
# Customize ROOT output filename
./build/compton -PROOT_OUT_FILENAME=my_data.root <evio_file>You can restrict which ROC and bank IDs are decoded by providing a simple text file and enabling filtering:
config/filter.db– Default plain text file in the source tree used for filtering, one entry per line:
# rocid slot model bank
21 3 250 250
22 5 250 250
Each non-comment, non-empty line has four integers:
- rocid – ROC ID
- slot – Slot number (read and saved but not used yet)
- model – Module model (read and saved but not used yet)
- bank – Bank tag you want to decode for that ROC
To customize filtering:
- Edit
config/filter.dband:- Add lines for additional (rocid, bank) pairs you want to allow.
- Remove or comment out lines (with
#) for combinations you want to exclude.
- Or point to your own file with the same four-column structure.
To run with filtering enabled:
./build/compton -PFILTER:ENABLE=1 -PFILTER:FILE=config/filter.db <evio_file>If you leave FILTER:ENABLE at its default false value, no filtering is applied and all ROCs/banks are decoded, regardless of the contents of config/filter.db.
This project provides a helper CMake target for running Valgrind with ROOT suppressions:
- From the build directory, run:
cmake --build . --target valgrind-checkThis will:
- Run
valgrindon./build/comptonusingscripts/valgrind_check.csh - Store Valgrind output under
build/scripts/valgrind_check/valgrind_out.log - Fail the target (non-zero exit) if any definite or indirect leaks are reported
compton.cc– Main application entry point that registers all componentsJEventSource_EVIO.cc/.h– EVIO file event source (block-level events, plusProcessParallelwhich createsPhysicsEventobjects)JEventUnfolder_EVIO.h– Unfolder that creates physics event-level child events from block-level eventsJEventProcessor_Compton.cc/.h– Main event processor that writes data to ROOT file
parser/EvioEventParser.cc/.h– EVIO event parsing utilities (block-level toPhysicsEventobjects, with optional filtering usingJEventService_FilterDB)parser/BankParser.h– Base interface for all bank parsers (hardware-agnostic)parser/data_objects/PhysicsEvent.h– Container for physics event data including event number and hitsparser/data_objects/EventHits.h– Abstract container interface for all event hitsparser/data_objects/EvioEventWrapper.h– JANA2 object wrapper for EVIO events (allowsstd::shared_ptrto be passed through the JANA2 pipeline)parser/data_objects/TriggerData.h– Simple POD holding trigger metadata for an EVIO blockservices/JEventService_BankParsersMap.h– JANA service mapping bank IDs toBankParserimplementationsservices/JEventService_FilterDB.h– JANA service providing ROC/bank filters loaded from a text file (e.g.filter.db)
This core parser area and services layer are intended to stay generic; you normally do not add hardware-specific code here.
User-defined hardware parsers live under user_parsers/. Each hardware type gets its own subdirectory, with
its hits and parser implementation plus a small CMake file. The central user_parsers/CMakeLists.txt file
adds all subdirectories and collects their libraries into USER_PARSER_LIBS, which the main executable links.
- FADC250 example
user_parsers/FADC/BankParser_FADC.cc/.h–BankParserimplementation for FADC250 datauser_parsers/FADC/data_objects/– FADC-specific hit and event container classes
Other provided examples:
user_parsers/FADCScaler/– FADC scaler bank parser and scaler hit data objectsuser_parsers/TIScaler/– TI scaler bank parser and scaler hit data objects
-
Pick a bank ID and hardware type
- Decide which EVIO bank tag you want to handle (e.g.
350for some new module). - Confirm the data format for that bank (word layout, headers, trailers, etc.).
- Decide which EVIO bank tag you want to handle (e.g.
-
Create a new user parser directory
- Under
user_parsers/, create a new subdirectory for your hardware, e.g.:user_parsers/MyHW/user_parsers/MyHW/data_objects/
- Use
user_parsers/FADC/as a reference for directory layout.
- Under
-
Define hardware-specific hit and event containers
- In
user_parsers/MyHW/data_objects/, create:- Hit classes (similar to
FADC250Hit,FADC250PulseHit,FADC250WaveformHit) that capture the decoded fields you care about. - A subclass of
EventHits(similar toEventHits_FADC) which:- Owns
std::vector<...*>of your hit types. - Implements
void insertIntoEvent(JEvent& event) overridetoevent.Insert(...)those hits.
- Owns
- Hit classes (similar to
- In
-
Implement a new
BankParsersubclass- In
user_parsers/MyHW/BankParser_MyHW.h:- Include
BankParser.hand your hit /EventHitsheaders. - Declare a class
BankParser_MyHW : public BankParserand override:void parse(std::shared_ptr<evio::BaseStructure> data_block, uint32_t rocid, std::vector<PhysicsEvent*>& physics_events, TriggerData& block_first_event_data) override;
- Include
- In
user_parsers/MyHW/BankParser_MyHW.cc:- Implement
parse(...)by:- Extracting 32-bit words from the EVIO bank (
getUIntData()). - Decoding headers/trailers/words for your hardware.
- Filling a
std::shared_ptr<EventHits_MyHW>as you walk the words. - Creating
PhysicsEvent*objects withstd::shared_ptr<EventHits>(upcast fromEventHits_MyHW) and pushing them intophysics_events.
- Extracting 32-bit words from the EVIO bank (
- Reuse
BankParser::getBitsInRange(...)helper to extract bit fields, similar toBankParser_FADC.
- Implement
- In
-
Expose your new parser to CMake
- Add a dedicated CMake file for your parser, similar to the existing ones:
- Create
user_parsers/MyHW/CMakeLists.txtwhich:- Defines a library for your parser, for example:
add_library(myhw_parsers STATIC BankParser_MyHW.cc)
- Adds include directories for your headers, e.g.:
target_include_directories(myhw_parsers PUBLIC ${PROJECT_SOURCE_DIR}/user_parsers/MyHW ${PROJECT_SOURCE_DIR}/user_parsers/MyHW/data_objects)
- Links against the core
parserlibrary:target_link_libraries(myhw_parsers PUBLIC parser)
- Defines a library for your parser, for example:
- Create
- Update
user_parsers/CMakeLists.txtto:- Add your subdirectory:
add_subdirectory(MyHW)
- Extend the
USER_PARSER_LIBSlist with your new library target:set(USER_PARSER_LIBS ${USER_PARSER_LIBS} myhw_parsers PARENT_SCOPE)
- Add your subdirectory:
- Add a dedicated CMake file for your parser, similar to the existing ones:
-
Register the parser with the service
- In
compton.cc, after creating the application and service:- Get the service:
auto bank_parsers_service = app.GetService<JEventService_BankParsersMap>();
- Register your parser for the chosen bank ID:
bank_parsers_service->addParser(<bank_id>, new BankParser_MyHW());
- Get the service:
- The
EvioEventParserwill automatically callJEventService_BankParsersMap::getParser(bank_id)for each EVIO bank and dispatch decoding to your parser when the bank tag matches.
- In
-
Rebuild and test
- Re-run CMake and build:
cmake -S . -B build(if you changed CMake)cmake --build build --parallel
- Run
./build/compton ...on EVIO files containing your new bank and verify:PhysicsEventobjects now contain your new hits.JEventUnfolder_EVIOpasses them to downstream processors (e.g.JEventProcessor_Comptonor your own processor).
- Re-run CMake and build: