41 #include "art/Framework/Core/EDProducer.h"
42 #include "art/Framework/Core/ModuleMacros.h"
43 #include "canvas/Persistency/Common/FindManyP.h"
44 #include "art/Framework/Principal/Event.h"
45 #include "fhiclcpp/ParameterSet.h"
46 #include "fhiclcpp/types/DelegatedParameter.h"
47 #include "art/Framework/Principal/Handle.h"
48 #include "art/Utilities/make_tool.h"
49 #include "canvas/Persistency/Common/Ptr.h"
50 #include "art/Framework/Services/Registry/ServiceHandle.h"
51 #include "messagefacility/MessageLogger/MessageLogger.h"
52 #include "cetlib/pow.h"
55 constexpr
unsigned int int_max_as_unsigned_int{std::numeric_limits<int>::max()};
74 Name(
"TrackModuleLabel"),
75 Comment(
"Module label for track producer.")
79 Name(
"T0ModuleLabel"),
80 Comment(
"Module label for T0 time producer."),
85 Name(
"AssocHitModuleLabel"),
86 Comment(
"Module label for association between tracks and hits. If not set, defaults to TrackModuleLabel."),
92 Comment(
"Method used to extract charge from a hit. Options: 0==Amplitude(), 1==Integral(), 2==SummedADC(). See the ChargeMethod enum.")
96 Name(
"FieldDistortion"),
97 Comment(
"True if field distortion (i.e. from space charge) is included in the input.")
101 Name(
"FieldDistortionEfield"),
102 Comment(
"True if field distortion (i.e. from space charge) is included in the input.")
106 Name(
"TrackIsFieldDistortionCorrected"),
107 Comment(
"Whether the space-points on the input tracks have their points corrected for the field distortions. "
108 "I.e. whether the track trajectory points represent charge as seen by wires or the 3D particle trajectory.")
113 Comment(
"Which cryostat number the input tracks occupy.")
117 Name(
"FieldDistortionCorrectionXSign"),
118 Comment(
"Sign of the field distortion correction to be applied in the X direction. Positive by default."),
124 Comment(
"Configuration for the calo::CalorimetryAlg")
129 Comment(
"List of INormalizeCharge tool configurations to use.")
148 const std::vector<const recob::TrackHitMeta *> &thms,
151 const std::vector<const recob::TrackHitMeta *> &thms,
154 const std::vector<const recob::TrackHitMeta *> &thms,
173 fCaloAlg(fConfig.CalorimetryAlgConfig())
175 produces< std::vector<anab::Calorimetry> >();
176 produces< art::Assns<recob::Track, anab::Calorimetry> >();
178 std::vector<fhicl::ParameterSet> norm_tool_configs = fConfig.NormTools.get<std::vector<fhicl::ParameterSet>>();
179 for (
const fhicl::ParameterSet &
p: norm_tool_configs) {
180 fNormTools.push_back(art::make_tool<INormalizeCharge>(
p));
187 art::ServiceHandle<geo::Geometry const> geom;
188 auto const clock_data = art::ServiceHandle<detinfo::DetectorClocksService const>()->DataFor(evt);
189 auto const det_prop =
190 art::ServiceHandle<detinfo::DetectorPropertiesService const>()->DataFor(evt, clock_data);
192 size_t nplanes = geom->Nplanes();
195 std::unique_ptr< std::vector<anab::Calorimetry> > outputCalo(
new std::vector<anab::Calorimetry>);
196 std::unique_ptr< art::Assns<recob::Track, anab::Calorimetry> > outputCaloAssn(
new art::Assns<recob::Track, anab::Calorimetry>);
199 art::Handle< std::vector<recob::Track> > trackListHandle;
200 std::vector<art::Ptr<recob::Track> > tracklist;
201 if (evt.getByLabel(fConfig.TrackModuleLabel(), trackListHandle)) {
202 art::fill_ptr_vector(tracklist, trackListHandle);
206 const std::string &hitLabel = (fConfig.AssocHitModuleLabel() ==
"") ? fConfig.TrackModuleLabel() : fConfig.AssocHitModuleLabel();
207 art::FindManyP<recob::Hit, recob::TrackHitMeta> fmHits(trackListHandle, evt, hitLabel);
210 art::FindManyP<anab::T0> fmT0s(trackListHandle, evt, fConfig.T0ModuleLabel());
213 for (
unsigned trk_i = 0; trk_i < tracklist.size(); trk_i++) {
217 const std::vector<art::Ptr<recob::Hit>> &hits = fmHits.at(trk_i);
218 const std::vector<const recob::TrackHitMeta *> &thms = fmHits.data(trk_i);
221 if (fConfig.T0ModuleLabel().size()) {
222 const std::vector<art::Ptr<anab::T0>> &this_t0s = fmT0s.at(trk_i);
223 if (this_t0s.size()) T0 = this_t0s.at(0)->Time();
227 std::vector<std::vector<unsigned>> hit_indices = OrganizeHits(hits, thms, track, nplanes);
229 for (
unsigned plane_i = 0; plane_i < nplanes; plane_i++) {
231 float kinetic_energy = 0.;
232 std::vector<float> dEdxs;
233 std::vector<float> dQdxs;
234 std::vector<float> resranges;
235 std::vector<float> deadwireresranges;
237 std::vector<float> pitches;
238 std::vector<geo::Point_t> xyzs;
239 std::vector<size_t> tp_indices;
243 plane.
Plane = plane_i;
245 plane.
Cryostat = fConfig.Cryostat();
248 std::vector<float> lengths;
249 for (
unsigned hit_i = 0; hit_i < hit_indices[plane_i].size(); hit_i++) {
250 unsigned hit_index = hit_indices[plane_i][hit_i];
256 double pitch =
GetPitch(track, hits[hit_index], thms[hit_index]);
259 double charge = GetCharge(hits[hit_index]);
262 double EField =
GetEfield(det_prop, track, hits[hit_index], thms[hit_index]);
264 double dQdx = charge / pitch;
267 dQdx = Normalize(dQdx, evt,
272 fCaloAlg.dEdx_AMP(clock_data, det_prop, dQdx, hits[hit_index]->PeakTime(), hits[hit_index]->WireID().Plane,
T0, EField) : \
273 fCaloAlg.dEdx_AREA(clock_data, det_prop, dQdx, hits[hit_index]->PeakTime(), hits[hit_index]->WireID().Plane,
T0, EField);
276 if (xyzs.size() == 0) {
277 lengths.push_back(0.);
280 lengths.push_back((location - xyzs.back()).
r());
284 dEdxs.push_back(dEdx);
285 dQdxs.push_back(dQdx);
286 pitches.push_back(pitch);
287 xyzs.push_back(location);
288 kinetic_energy += dEdx * pitch;
297 tp_indices.push_back(hits[hit_index].key());
304 if (lengths.size() > 1) {
305 range = std::accumulate(lengths.begin(), lengths.end(), 0.);
309 bool is_downstream = \
313 resranges.resize(lengths.size());
315 resranges[lengths.size() - 1] = lengths.back() / 2.;
316 for (
int i_len = lengths.size() - 2; i_len >= 0; i_len --) {
317 resranges[i_len] = resranges[i_len+1] + lengths[i_len+1];
321 resranges[0] = lengths[1] / 2.;
322 for (
unsigned i_len = 1; i_len < lengths.size(); i_len ++) {
323 resranges[i_len] = resranges[i_len-1] + lengths[i_len];
331 if (lengths.size() > 1) {
356 util::CreateAssn(*
this, evt, *outputCalo, tracklist[trk_i], *outputCaloAssn);
362 evt.put(std::move(outputCalo));
363 evt.put(std::move(outputCaloAssn));
370 const std::vector<const recob::TrackHitMeta *> &thms,
374 return OrganizeHitsIndividual(hits, thms, track, nplanes);
378 return OrganizeHitsSnippets(hits, thms, track, nplanes);
383 const std::vector<const recob::TrackHitMeta *> &thms,
385 std::vector<std::vector<unsigned>> ret(nplanes);
386 for (
unsigned i = 0; i < hits.size(); i++) {
387 if (HitIsValid(hits[i], thms[i], track)) {
388 ret[hits[i]->WireID().Plane].push_back(i);
396 const std::vector<const recob::TrackHitMeta *> &thms,
403 struct HitIdentifier {
418 inline bool operator==(
const HitIdentifier& rhs)
const {
419 return startTick == rhs.startTick && endTick == rhs.endTick && wire == rhs.wire;
423 inline bool operator>(
const HitIdentifier& rhs)
const {
424 return integral > rhs.integral;
428 std::vector<std::vector<unsigned>> ret(nplanes);
429 std::vector<std::vector<HitIdentifier>> hit_idents(nplanes);
430 for (
unsigned i = 0; i < hits.size(); i++) {
431 if (HitIsValid(hits[i], thms[i], track)) {
432 HitIdentifier this_ident(*hits[i]);
435 bool found_snippet =
false;
436 for (
unsigned j = 0; j < ret[hits[i]->WireID().Plane].size(); j++) {
437 if (this_ident == hit_idents[hits[i]->
WireID().Plane][j]) {
438 found_snippet =
true;
439 if (this_ident > hit_idents[hits[i]->
WireID().Plane][j]) {
440 ret[hits[i]->WireID().Plane][j] = i;
441 hit_idents[hits[i]->WireID().Plane][j] = this_ident;
446 if (!found_snippet) {
447 ret[hits[i]->WireID().Plane].push_back(i);
448 hit_idents[hits[i]->WireID().Plane].push_back(this_ident);
456 if (thm->
Index() == int_max_as_unsigned_int)
return false;
467 auto const* sce = lar::providerFrom<spacecharge::SpaceChargeService>();
471 if (sce->EnableCalSpatialSCE() && fConfig.FieldDistortion()) {
474 ret.SetX(ret.X() + fConfig.FieldDistortionCorrectionXSign() * offset.X());
475 ret.SetY(ret.Y() + offset.Y());
476 ret.SetZ(ret.Z() + offset.Z());
489 auto const* sce = lar::providerFrom<spacecharge::SpaceChargeService>();
490 art::ServiceHandle<geo::Geometry const> geom;
494 if (sce->EnableCalSpatialSCE() && fConfig.FieldDistortion()) {
496 int corr = geom->TPC(tpc.
TPC).DriftDir()[0];
500 ret.SetX(ret.X() + corr * fConfig.FieldDistortionCorrectionXSign() * offset.X());
501 ret.SetY(ret.Y() + offset.Y());
502 ret.SetZ(ret.Z() + offset.Z());
509 art::ServiceHandle<geo::Geometry const> geom;
510 auto const* sce = lar::providerFrom<spacecharge::SpaceChargeService>();
512 double angleToVert = geom->WireAngleToVertical(hit->View(), hit->WireID().TPC, hit->WireID().Cryostat) - 0.5*::util::pi<>();
519 if (sce->EnableCalSpatialSCE() && fConfig.FieldDistortion() && fConfig.TrackIsFieldDistortionCorrected()) {
524 geo::Point_t loc_mdx = loc - track_dir * (geom->WirePitch(hit->View()) / 2.);
525 geo::Point_t loc_pdx = loc + track_dir * (geom->WirePitch(hit->View()) / 2.);
531 dir = (loc_pdx - loc_mdx) / (loc_mdx - loc_pdx).r();
539 double cosgamma =
std::abs(std::sin(angleToVert)*dir.Y() + std::cos(angleToVert)*dir.Z());
542 pitch = geom->WirePitch(hit->View())/cosgamma;
554 pitch = (locw_pdx_traj -
loc).R();
560 switch (fConfig.ChargeMethod()) {
562 return hit->Integral();
564 return hit->PeakAmplitude();
566 return hit->SummedADC();
576 for (
auto const &nt: fNormTools) {
577 ret = nt->Normalize(ret, e, h, location, direction, t0);
584 auto const* sce = lar::providerFrom<spacecharge::SpaceChargeService>();
586 double EField = dprop.
Efield();
587 if (sce->EnableSimEfieldSCE() && fConfig.FieldDistortionEfield()) {
593 EFieldOffsets = EField * EFieldOffsets;
595 EField = EFieldOffsets.r();
ROOT::Math::DisplacementVector3D< ROOT::Math::Cartesian3D< double >, ROOT::Math::GlobalCoordinateSystemTag > Vector_t
Type for representation of momenta in 3D space.
GnocchiCalorimetry(Parameters const &config)
Functions to help with numbers.
BEGIN_PROLOG TPC Trig offset(g4 rise time) ProjectToHeight
fhicl::Atom< unsigned > Cryostat
void produce(art::Event &evt) override
geo::WireID WireID() const
const recob::TrackTrajectory & Trajectory() const
Access to the stored recob::TrackTrajectory.
Declaration of signal hit object.
art::EDProducer::Table< Config > Parameters
fhicl::DelegatedParameter NormTools
fhicl::Atom< float > FieldDistortionCorrectionXSign
Point_t const & LocationAtPoint(size_t i) const
The data type to uniquely identify a Plane.
bool isValid
Whether this ID points to a valid element.
bool HasValidPoint(size_t i) const
CryostatID_t Cryostat
Index of cryostat.
geo::Point_t GetLocation(const spacecharge::SpaceCharge *sce, geo::Point_t loc_w, geo::TPCID TPC, float xsign=1.)
Get the location in the presence of space charge.
float Integral() const
Integral under the calibrated signal waveform of the hit, in tick x ADC units.
WireID_t Wire
Index of the wire within its plane.
bool HitIsValid(const art::Ptr< recob::Hit > hit, const recob::TrackHitMeta *thm, const recob::Track &track)
process_name use argoneut_mc_hitfinder track
double Normalize(double dQdx, const art::Event &e, const recob::Hit &h, const geo::Point_t &location, const geo::Vector_t &direction, double t0)
std::vector< std::vector< unsigned > > OrganizeHitsSnippets(const std::vector< art::Ptr< recob::Hit >> &hits, const std::vector< const recob::TrackHitMeta * > &thms, const recob::Track &track, unsigned nplanes)
geo::Point_t GetLocationAtWires(const recob::Track &track, const art::Ptr< recob::Hit > hit, const recob::TrackHitMeta *meta)
geo::Point_t GetLocationAtWires(const spacecharge::SpaceCharge *sce, const geo::GeometryCore *geo, geo::Point_t loc, geo::TPCID TPC, float xsign=1.)
Get the SCE-distorted location (i.e. the location "seen" by the wireplanes)
double Efield(unsigned int planegap=0) const
kV/cm
fhicl::Atom< std::string > TrackModuleLabel
process_name can override from command line with o or output calo
auto vector(Vector const &v)
Returns a manipulator which will print the specified array.
fhicl::Atom< std::string > T0ModuleLabel
geo::Point_t WireToTrajectoryPosition(const geo::Point_t &loc, const geo::TPCID &tpc)
IDparameter< geo::WireID > WireID
Member type of validated geo::WireID parameter.
std::vector< std::unique_ptr< INormalizeCharge > > fNormTools
double GetEfield(const detinfo::DetectorPropertiesData &dprop, const recob::Track &track, const art::Ptr< recob::Hit > hit, const recob::TrackHitMeta *meta)
fhicl::Atom< bool > FieldDistortion
geo::Point_t WireToTrajectoryPosition(const geo::Point_t &loc, const geo::TPCID &tpc)
BEGIN_PROLOG vertical distance to the surface Name
geo::Point_t TrajectoryToWirePosition(const geo::Point_t &loc, const geo::TPCID &tpc)
double GetPitch(const geo::GeometryCore *geo, const spacecharge::SpaceCharge *sce, geo::Point_t loc, geo::Vector_t dir, geo::View_t view, geo::TPCID tpc, bool correct_sce, bool track_is_sce_corrected, float xsign=1.)
Computes the track-pitch on a plane given an input direction and location.
The data type to uniquely identify a TPC.
PlaneID_t Plane
Index of the plane within its TPC.
raw::TDCtick_t StartTick() const
Initial tdc tick for hit.
float dEdx(detinfo::DetectorClocksData const &clockData, detinfo::DetectorPropertiesData const &detProp, const TCSlice &slc, TP3D &tp3d)
Provides recob::Track data product.
fhicl::Atom< bool > TrackIsFieldDistortionCorrected
Encapsulate the geometry of a wire.
raw::TDCtick_t EndTick() const
Final tdc tick for hit.
fhicl::Table< calo::CalorimetryAlg::Config > CalorimetryAlgConfig
bool CreateAssn(art::Event &evt, std::vector< T > const &a, art::Ptr< U > const &b, art::Assns< U, T > &assn, std::string a_instance, size_t index=UINT_MAX)
Creates a single one-to-one association.
std::vector< std::vector< unsigned > > OrganizeHits(const std::vector< art::Ptr< recob::Hit >> &hits, const std::vector< const recob::TrackHitMeta * > &thms, const recob::Track &track, unsigned nplanes)
constexpr bool operator>(Interval< Q, Cat > const a, Quantity< Args...> const b) noexcept
Encapsulate the construction of a single detector plane.
Point_t const & End() const
Returns the position of the last valid point of the trajectory [cm].
Interface for experiment-specific channel quality info provider.
double GetPitch(const recob::Track &track, const art::Ptr< recob::Hit > hit, const recob::TrackHitMeta *meta)
geo::Point_t TrajectoryToWirePosition(const geo::Point_t &loc, const geo::TPCID &tpc)
fhicl::Atom< bool > FieldDistortionEfield
double GetEfield(const detinfo::DetectorPropertiesData &dprop, const spacecharge::SpaceCharge *sce, geo::Point_t loc, geo::TPCID TPC, bool correct_loc_sce, float xsign=1.)
Get the E-Field in the presence of space charge.
Vector_t DirectionAtPoint(size_t i) const
double GetCharge(const art::Ptr< recob::Hit > hit)
constexpr double kBogusD
obviously bogus double value
geo::Point_t GetLocation(const recob::Track &track, const art::Ptr< recob::Hit > hit, const recob::TrackHitMeta *meta)
2D representation of charge deposited in the TDC/wire plane
TPCID_t TPC
Index of the TPC within its cryostat.
Interface for experiment-specific service for channel quality info.
Collection of Physical constants used in LArSoft.
fhicl::Atom< std::string > AssocHitModuleLabel
ROOT::Math::PositionVector3D< ROOT::Math::Cartesian3D< double >, ROOT::Math::GlobalCoordinateSystemTag > Point_t
Type for representation of position in physical 3D space.
Point_t const & Start() const
Returns the position of the first valid point of the trajectory [cm].
Utility functions to extract information from recob::Track
bool operator==(infinite_endcount_iterator< T > const &, count_iterator< T > const &)
Track from a non-cascading particle.A recob::Track consists of a recob::TrackTrajectory, plus additional members relevant for a "fitted" track:
process_name opdaq physics producers generator physics producers generator physics producers generator physics producers generator physics producers generator physics producers generator physics producers generator physics producers generator T0
std::vector< std::vector< unsigned > > OrganizeHitsIndividual(const std::vector< art::Ptr< recob::Hit >> &hits, const std::vector< const recob::TrackHitMeta * > &thms, const recob::Track &track, unsigned nplanes)
This is an interface for an art Tool which scales charge by some factor given information about its a...