Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Sample scripts for validating future samples #1216

Merged
merged 11 commits into from
Nov 30, 2023
31 changes: 31 additions & 0 deletions DQM/include/DQM/SampleValidation.h
Original file line number Diff line number Diff line change
@@ -0,0 +1,31 @@
#ifndef DQM_SAMPLEVALIDATION_H
#define DQM_SAMPLEVALIDATION_H

//LDMX Framework
#include "Framework/Configure/Parameters.h"
#include "Framework/EventProcessor.h"

namespace dqm {

/**
* @class SampleValidation
* @brief
*/

class SampleValidation : public framework::Analyzer {
public:

SampleValidation(const std::string& name, framework::Process& process) : Analyzer(name, process) {}

virtual void configure(framework::config::Parameters& ps);

virtual void analyze(const framework::Event& event);

int pdgid_label(const int pdgid);
private:

};

}

#endif
21 changes: 21 additions & 0 deletions DQM/python/dqm.py
Original file line number Diff line number Diff line change
Expand Up @@ -594,6 +594,27 @@ def __init__(self,name='Trigger',coll='Trigger') :
self.trigger_name = coll
self.trigger_pass = ''


class SampleValidation(ldmxcfg.Analyzer) :
def __init__(self, name='SampleValidation') :
super().__init__(name, 'dqm::SampleValidation', 'DQM')

# primary histograms
self.build1DHistogram("pdgid_primaries", "PDG ID of primary particles", 19, 0, 19)
self.build1DHistogram("energy_primaries", "Energy of primary particles", 90, 0, 9000) # range applicable for 4 GeV beam
self.build2DHistogram("beam_smear", "x", 30, -150, 150, "y", 30, -150, 150)
self.build1DHistogram("pdgid_primarydaughters", "PDG ID of primary daughtesr", 19, 0, 19)
self.build1DHistogram("energy_daughterphoton", "Energy spectrum of all photons from primary", 170, 0, 8500)

# primary daughter of interest (brem / dark brem) histograms
self.build1DHistogram("pdgid_harddaughters", "PDG ID of primary daughters", 19, 0, 19)
self.build1DHistogram("startZ_hardbrem", "Start z position of hard primary daughter", 100, -500, 500)
self.build1DHistogram("endZ_hardbrem", "End z position of hard primary daughter", 100, -500, 500)
self.build1DHistogram("energy_hardbrem", "Energy spectrum of hard primary daughter", 130, 2000, 8500)

# daughters of hard brem histograms
self.build1DHistogram("pdgid_hardbremdaughters", "PDG ID of hard brem daughters", 19, 0, 19)
self.build1DHistogram("startZ_hardbremdaughters", "Start z position of hard brem daughters", 200, -1000, 1000)


ecal_dqm = [
Expand Down
130 changes: 130 additions & 0 deletions DQM/src/DQM/SampleValidation.cxx
Original file line number Diff line number Diff line change
@@ -0,0 +1,130 @@
#include "DQM/SampleValidation.h"
#include "SimCore/Event/SimParticle.h"
#include "SimCore/Event/SimTrackerHit.h"
#include "Framework/NtupleManager.h"
#include <iostream>
#include <fstream>
#include <algorithm>

namespace dqm {

void SampleValidation::configure(framework::config::Parameters& ps) {

return;
}

void SampleValidation::analyze(const framework::Event& event) {

//Grab the SimParticle Map and Target Scoring Plane Hits
auto targetSPHits(event.getCollection<ldmx::SimTrackerHit>("TargetScoringPlaneHits"));
auto particle_map{event.getMap<int, ldmx::SimParticle>("SimParticles")};

std::vector<int> primary_daughters;

double hard_thresh = 2500;
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Why are we defining hard_thresh down here and redefining it later?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I needed to declare hard_thresh outside the first for loop since it is used in later loops. But in principle I should only declare it here without assigning it a value yet. This was likely a remnant from when hard_thresh was a hard-coded value. I can remove the value definition but will still keep the variable declared here.


//Loop over all SimParticles
for (auto const& it : particle_map) {
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Not something that needs to be fixed but something that is useful is that when iterating over a map you can do

for (auto const& [id, particle] : particle_map) { ... }

To define the id and particle variables directly without having to do it.second :)

ldmx::SimParticle p = it.second;
int pdgid = p.getPdgID();
std::vector<double> vertex = p.getVertex();
double energy = p.getEnergy();
std::vector<int> parents_track_ids = p.getParents();
std::vector<int> daughters = p.getDaughters();

for (auto const& parent_track_id: parents_track_ids) {
if (parent_track_id == 0) {
histograms_.fill("pdgid_primaries", pdgid_label(pdgid));
histograms_.fill("energy_primaries", energy);
hard_thresh = (2500/4000)*energy;
primary_daughters = daughters;
for (const ldmx::SimTrackerHit &sphit : targetSPHits) {
if (sphit.getTrackID() == it.first && sphit.getPosition()[2] < 0) {
histograms_.fill("beam_smear", vertex[0], vertex[1]);
}
}
}
}
}

std::vector<std::vector<int>> hardbrem_daughters;

for (auto const& it : particle_map) {
int trackid = it.first;
ldmx::SimParticle p = it.second;
for (auto const& primary_daughter : primary_daughters) {
if (trackid == primary_daughter) {
histograms_.fill("pdgid_primarydaughters", pdgid_label(p.getPdgID()));
if (p.getPdgID() == 22) {
histograms_.fill("energy_daughterphoton", p.getEnergy());
}
if (p.getEnergy() >= hard_thresh) {
histograms_.fill("pdgid_harddaughters", pdgid_label(p.getPdgID()));
histograms_.fill("startZ_hardbrem", p.getVertex()[2]);
histograms_.fill("endZ_hardbrem", p.getEndPoint()[2]);
histograms_.fill("energy_hardbrem", p.getEnergy());
hardbrem_daughters.push_back(p.getDaughters());
}
}
}
}

for (auto const& it : particle_map) {
int trackid = it.first;
ldmx::SimParticle p = it.second;
for (const std::vector<int> &daughter_track_id : hardbrem_daughters){
for (const int &daughter_id : daughter_track_id) {
if (trackid == daughter_id) {
histograms_.fill("pdgid_hardbremdaughters", pdgid_label(p.getPdgID()));
histograms_.fill("startZ_hardbremdaughters", p.getVertex()[2]);
}
}
}
}


return;
}

int SampleValidation::pdgid_label(const int pdgid) {
int label = 18; // initially assign label as "anything else"/overflow value, only change if the pdg id is something of interest
if (pdgid == -11) label = 1; // e+

if (pdgid == 11) label = 2; // e-

if (pdgid == -13) label = 3; // μ+

if (pdgid == 13) label = 4; // μ-

if (pdgid == 22) label = 5; // γ

if (pdgid == 2212) label = 6; // proton

if (pdgid == 2112) label = 7; // neutron

if (pdgid == 211) label = 8; //π+

if (pdgid == -211) label = 9; //π-

if (pdgid == 111) label = 10; //π0

if (pdgid == 321) label = 11; // K+

if (pdgid == -321) label = 12; // K-

if (pdgid == 130) label = 13; // K-Long

if (pdgid == 310) label = 14; // K-Short

if (pdgid == 3122 || pdgid == 3222 || pdgid == 3212 || pdgid == 3112 || pdgid == 3322 || pdgid == 3312) label = 16; // strange baryon

if (pdgid > 10000) label = 15; //nuclei
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Is it worth differentiating between general nuclei and light ions here? The production of alpha, deuterium, and tritium from PN interactions is non-trivial.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I can include this distinction since I meant for the label to mainly catch remnants of a tungsten explosion. Do you think "light"/"heavy" nuclei is granular enough, with "light" being only hydrogen or helium nuclides?

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The bertini cascade will attempt to take nucleons being ejected from the cascade that are "similar" and bunch them together into deuterium, tritium, alpha (called "Coalescence") so you can get these even for quite ordinary interactions.

There is a version of a test for what counts as a light ion here (that probably should live somewhere else...)
https://github.com/LDMX-Software/ldmx-sw/blob/8e6e9e195eb71ad78f7aa94648a179342a12e1f6/Biasing/include/Biasing/PhotoNuclearTopologyFilters.h#L62C1-L78


if (pdgid == 622) label = 17; // dark photon, need pdg id for other models like ALPs and SIMPs

return label;
}

}

DECLARE_ANALYZER_NS(dqm, SampleValidation)
1 change: 1 addition & 0 deletions Validation/src/Validation/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -7,3 +7,4 @@
from . import hcal
from . import photonuclear
from . import dark_brem
from . import simparticles
53 changes: 53 additions & 0 deletions Validation/src/Validation/simparticles.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,53 @@
from ._differ import Differ
from ._plotter import plotter
import logging

log = logging.getLogger('8GeV')

@plotter(hist=True, event=False)
def beamenergy_comp(d: Differ, out_dir=None):

pdgid_labels = ['', 'e+', 'e-', 'μ+', 'μ-', 'γ', 'p', 'n', 'π+', 'π-', 'π0', 'K+', 'K-', 'K-L', 'K-S', 'nucleus', 'strange baryon', "A\'", 'something else'] # finish later

d.plot1d("SampleValidation/SampleValidation_pdgid_primaries", "PDG ID, primaries",
tick_labels=pdgid_labels,
out_dir=out_dir,
density=True)

d.plot1d("SampleValidation/SampleValidation_energy_primaries", "Energy of primaries (MeV)",
out_dir=out_dir,
density=True)

d.plot1d("SampleValidation/SampleValidation_pdgid_primarydaughters", "PDG ID, primary daughters",
tick_labels=pdgid_labels,
out_dir=out_dir,
density=True)
d.plot1d("SampleValidation/SampleValidation_energy_daughterphoton", "Energy spectrum of all photons from primary",
out_dir=out_dir,
density=True)

d.plot1d("SampleValidation/SampleValidation_pdgid_harddaughters", "PDG ID of hard primary daughter",
tick_labels=pdgid_labels,
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This is really great. Makes it SO much easier to read and grasp the plot!

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

+1

out_dir=out_dir,
density=True)

d.plot1d("SampleValidation/SampleValidation_startZ_hardbrem", "Start z position of hard primary daughter",
out_dir=out_dir,
density=True)

d.plot1d("SampleValidation/SampleValidation_endZ_hardbrem", "End z position of hard primary daughter",
out_dir=out_dir,
density=True)

d.plot1d("SampleValidation/SampleValidation_energy_hardbrem", "Energy spectrum of hard primary daughter",
out_dir=out_dir,
density=True)

d.plot1d("SampleValidation/SampleValidation_pdgid_hardbremdaughters", "PDG ID, hard brem daughters",
tick_labels=pdgid_labels,
out_dir=out_dir,
density=True)

d.plot1d("SampleValidation/SampleValidation_startZ_hardbremdaughters", "Start z position of hard brem daughters",
out_dir=out_dir,
density=True)