Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions icaruscode/CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -15,4 +15,5 @@ add_subdirectory(RecoUtils)
add_subdirectory(TPC)
add_subdirectory(Utilities)
add_subdirectory(Overlays)
add_subdirectory(ICARUSCVN)
#add_subdirectory(Supera)
6 changes: 6 additions & 0 deletions icaruscode/ICARUSCVN/CMakeLists.txt
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
add_subdirectory(module_helpers)
add_subdirectory(tf)
add_subdirectory(modules)
add_subdirectory(fcls)
install_fhicl()

77 changes: 77 additions & 0 deletions icaruscode/ICARUSCVN/README.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,77 @@
ICARUS CVN Mapper and Evaluator
Author: Felipe A. Wieler
Date: November 12, 2025
Email: f3aw@proton.me

------------------------------------------------------------
Overview
------------------------------------------------------------
The ICARUSCVNMapper and ICARUSCVNEvaluator modules provide the interface between reconstructed slices and the Convolutional Visual Network (CVN) models used in ICARUS.

- ICARUSCVNMapper.fcl: Configuration file for detector mapping and label management, including Grid Configuration.
- ICARUSZlibMaker.fcl: Converts the mapper output into compressed pixel map archives.
- ICARUSCVNEvaluator.fcl: Runs the trained CVN TensorFlow models to evaluate each slice and produce classification scores.

These tools together enable pixel map creation, compression, and evaluation for neutrino flavors classification in ICARUS data.

------------------------------------------------------------
Prerequisites
------------------------------------------------------------
Before running, ensure the following:
- LArSoft and ICARUS code are correctly set up in your environment.
- TensorFlow model files are accessible, those are defined on the ICARUSCVNMapper.fcl.
- Input files (stage1) have been produced by standard ICARUS reconstruction chains.
- standard_cvnzlibmaker is properly configured, including the OutputDir path also in ICARUSCVNMapper.fcl.

------------------------------------------------------------
Pixel Map Generation
------------------------------------------------------------
To create pixel maps from a stage1 file:
lar -c run_ICARUSCVNMapper.fcl -s <stage1_file.root>

This produces a ROOT output with slice and pixel map information.

Next, run the zlib maker to generate the compressed maps:
lar -c run_ICARUSZlibMaker.fcl -s <mapper_output.root>

This step creates:
- .gz files → contain pixel map arrays
- .info files → include truth and slice metadata from Pandora

These files are stored under the directory specified by OutputDir in standard_cvnzlibmaker on ICARUSCVNMapper.fcl.

------------------------------------------------------------
Running the Evaluator
------------------------------------------------------------
To evaluate slices using the trained CVN models:
lar -c run_ICARUSCVNEvaluator.fcl -s <stage1_file.root>

This produces a new ROOT file containing the CryoE and CryoW classification scores for each slice.

------------------------------------------------------------
Output Summary
------------------------------------------------------------
File Type | Description
----------|------------------------------------------------
.gz | Compressed pixel map arrays
.info | Truth and metadata from Pandora per slice
.root | Evaluation results including CryoE and CryoW scores

------------------------------------------------------------
Example Workflow
------------------------------------------------------------

Pixel Map Creation:
lar -c run_ICARUSCVNMapper.fcl -s reco_stage1.root
lar -c run_ICARUSZlibMaker.fcl -s output_mapper.root
------------------------------------------------------------

Root Evaluation:
lar -c run_ICARUSCVNEvaluator.fcl -s reco_stage1.root

------------------------------------------------------------
Notes
------------------------------------------------------------
- Use consistent stage1 files across all steps to maintain slice–truth consistency.
- Evaluation requires access to trained CVN TensorFlow models.
- The modules support both Cryostat East (CryoE) and Cryostat West (CryoW) toghether or individualy by changin the corresponding FHiCL file.
2 changes: 2 additions & 0 deletions icaruscode/ICARUSCVN/fcls/CMakeLists.txt
Original file line number Diff line number Diff line change
@@ -0,0 +1,2 @@
install_fhicl()

188 changes: 188 additions & 0 deletions icaruscode/ICARUSCVN/fcls/ICARUSCVNMapper.fcl
Original file line number Diff line number Diff line change
@@ -0,0 +1,188 @@
BEGIN_PROLOG

# This file defines the configuration for the CVNMapper and CVNMapperProtoDUNE modules
standard_pixelmapproducer:
{
TdcWidth: 640 #400 # 1000
WireLength: 6500 #3064 #2205 #6223 #8500 #or 9000 #collection plane : 2205, induction plane : 6223
TimeResolution: 1500 #1600 # 2560 # 3400
Threshold: 0
MultipleDrifts: true
verbose: false
ChangeWireNo: true
ReadoutSize: 4096. # in time ticks # 2560
ShiftT: 850 #850. # 420. #size of the back/front porch
InductionWires: 6500 #3064 #6223 #2205 #1984 #number of wires in the first induction plane
FlipInductionView: false
UseT: true #use time 0 of pfp
}

standard_cvnmapper_west:
{
module_type: ICARUSCVNMapper
HitsModuleLabel: "cluster3DCryoW"
ClusterPMLabel: "cvnmap"
MinClusterHits: 100
verbose: true
UseSlice: true
SliceLabel: "pandoraGausCryoW"
PFParticleModuleLabel: "pandoraGausCryoW"
T0Label: "pandoraGausCryoW"
PixelMapProducer: @local::standard_pixelmapproducer
MapVecSize: 100000

}

standard_cvnmapper_east:
{
module_type: ICARUSCVNMapper
HitsModuleLabel: "cluster3DCryoE"
ClusterPMLabel: "cvnmap"
MinClusterHits: 100
verbose: true
UseSlice: true
SliceLabel: "pandoraGausCryoE"
PFParticleModuleLabel: "pandoraGausCryoE"
T0Label: "pandoraGausCryoE"
PixelMapProducer: @local::standard_pixelmapproducer
MapVecSize: 100000

}

standard_cvnzlibmaker_east:
{
module_type: ICARUSCVNZlibMaker
Module: "East"
ZLibFileName: "fwieler_pixel_maps"
InfoFileName: "fwieler_pixel_maps"
OutputDir: "./NewZlibMakerOutput"
Grid: "false"
PixelMapInput: "icaruspixelmapeast"
SetLog: false
ReverseViews: [false,false,false]
PlaneLimit: 500
TDCLimit: 500
verbose: true
UseSlice: true
SliceLabel: "pandoraGausCryoE"
TopologyHitsCut: 0
GenieGenModuleLabel: "generator"
Verbose: true
UseBackTrackInfo: true
UseNuContainment: false
CosEfrac: 0.75
NuEfrac: 0.25
VolCut: 0.
SaveTree: false
PFParticleModuleLabel: "pandoraGausCryoE"
HitModuleLabel: "cluster3DCryoE"
T0Label: "pandoraGausCryoE"
}

standard_cvnzlibmaker_west:
{
module_type: ICARUSCVNZlibMaker
Module: West
ZLibFileName: "fwieler_pixel_maps"
InfoFileName: "fwieler_pixel_maps"
OutputDir: "./NewZlibMakerOutput"
PixelMapInput: "icaruspixelmapwest"
SetLog: false
ReverseViews: [false,false,false]
PlaneLimit: 500
TDCLimit: 500
verbose: true
UseSlice: true
SliceLabel: "pandoraGausCryoW"
TopologyHitsCut: 0
GenieGenModuleLabel: "generator"
Verbose: true
UseBackTrackInfo: true
UseNuContainment: false
CosEfrac: 0.75
NuEfrac: 0.25
VolCut: 0.
SaveTree: false
PFParticleModuleLabel: "pandoraGausCryoW"
HitModuleLabel: "cluster3DCryoW"
T0Label: "pandoraGausCryoW"
}


standard_icarustfnethandler:
{
LibPath: ""
#For the grid
#TFProtoBuf: "${INPUT_TAR_DIR_LOCAL}/icarus_cvn/srcs/icaruscode/icaruscode/ICARUSCVN/fcls/model/new_training_output1_flavour_40pixels_101layers_new_new_data_balanced_2-13-0.48.46.pb"
#Running Local
TFProtoBuf: "CVN/icarus_cvn_flavor.pb"
ChargeLogScale: false
NImageWires: 500
NImageTDCs : 500
ReverseViews: [false,false,false]
UseBundle: false
Inputs: ["view0", "view1", "view2"]
Outputs: ["flavour_1/Softmax"]
NInputs: 3
NOutputs: 1
verbose: true
}

#IF RUNNING ON THE PIXEL MAPS NOT ON THE ROOT FILE
standard_icaruscvnevaluatorpm:
{
module_type: ICARUSCVNEvaluator
Module: "West"
PixelMapModuleLabel: ""
PixelMapInput: "/pnfs/icarus/scratch/users/fwieler/pixelMaps_score2/W_set/"
SliceLabel: ""
PFParticleModuleLabel: "pandoraGausCryoW"
T0Label: "pandoraGausCryoW"
CVNType: "Tensorflow"
verbose: true
ICARUSTFHandler: {
tool_type: ICARUSTFNetHandler
@table::standard_icarustfnethandler
}
PixelMapProducer: @local::standard_pixelmapproducer
}

#RUNNING ON THE ROOT FILE
standard_icaruscvnevaluatorslc_west:
{
module_type: ICARUSCVNEvaluator
Module: "West"
PixelMapModuleLabel: ""
PixelMapInput: ""
SliceLabel: "pandoraGausCryoW"
PFParticleModuleLabel: "pandoraGausCryoW"
T0Label: "pandoraGausCryoW"
CVNType: "Tensorflow"
verbose: true
ICARUSTFHandler: {
tool_type: ICARUSTFNetHandler
@table::standard_icarustfnethandler
}
PixelMapProducer: @local::standard_pixelmapproducer
}

standard_icaruscvnevaluatorslc_east:
{
module_type: ICARUSCVNEvaluator
Module: "East"
PixelMapModuleLabel: ""
PixelMapInput: ""
SliceLabel: "pandoraGausCryoE"
PFParticleModuleLabel: "pandoraGausCryoE"
T0Label: "pandoraGausCryoE"
CVNType: "Tensorflow"
verbose: true
ICARUSTFHandler: {
tool_type: ICARUSTFNetHandler
@table::standard_icarustfnethandler
}
PixelMapProducer: @local::standard_pixelmapproducer
}


END_PROLOG
74 changes: 74 additions & 0 deletions icaruscode/ICARUSCVN/fcls/getTrueInfo.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,74 @@
import re
import glob
import os

def normalize(value):
if value > 2:
return 3
return value

def normalize2(value):
if value < 0:
return 1
return 0

directory = '/pnfs/icarus/scratch/users/fwieler/pixelMaps_score2/W_set' # current directory
pattern = re.compile(r'e(\d+)')
files = list(glob.iglob(directory + "/**/*.gz", recursive=True))

output_lines = []
extracted_e_values = []
i = 0

for filename in files:
match = pattern.search(filename)

if not match:
continue
i += 1
print(f'Processing [{i}/{len(files)}]')
e_value = f"e{match.group(1)}"
extracted_e_values.append(e_value)

file_ID = filename.split("/")[-1][:-3]
infofile = file_ID + '.info'
dir_path = os.path.dirname(filename)

try:
with open(dir_path + "/" + infofile, 'r') as f:
info = f.readlines()
except FileNotFoundError:
continue

if not len(info):
continue

fInt = int(info[0].strip())
flavour = fInt // 4
if flavour == 3:
flavour = 2;
interaction = fInt % 4

fNuEnergy = float(info[1].strip())
fLepEnergy = float(info[2].strip())
fRecoNueEnergy = float(info[3].strip())
fRecoNumuEnergy = float(info[4].strip())
fEventWeight = float(info[6].strip())

fNuPDG = normalize2(int(info[7].strip()))
fNProton = normalize(int(info[8].strip()))
fNPion = normalize(int(info[9].strip()))
fNPizero = normalize(int(info[10].strip()))
fNNeutron = normalize(int(info[11].strip()))

# Create a CSV line: eXX, flavour, interaction, energies, weights, normalized particles
line = f"{file_ID},{flavour},{interaction},{fNuEnergy},{fLepEnergy},{fRecoNueEnergy},{fRecoNumuEnergy},{fEventWeight},{fNuPDG},{fNProton},{fNPion},{fNPizero},{fNNeutron}"
output_lines.append(line)

# Write all results to a file
with open("event_info_wset_score2.csv", "w") as outfile:
outfile.write("fid,flavour,interaction,fNuEnergy,fLepEnergy,fRecoNueEnergy,fRecoNumuEnergy,fEventWeight,fNuPDG,fNProton,fNPion,fNPizero,fNNeutron\n")
for line in output_lines:
outfile.write(line + "\n")

print("\nSaved event info to 'event_info_wset_score2.csv'.")
Loading