-
Notifications
You must be signed in to change notification settings - Fork 35
Feature/sungbino caf calo updates 2025 a #559
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
Feature/sungbino caf calo updates 2025 a #559
Conversation
…the CAF SRCalo object per-hit.
…e'r. Use actualy true deposition time to define true calo point time.
…_caf-calo-updates_tested
PetrilloAtWork
left a comment
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Points to discuss:
- I oppose having
TrackCaloSkimmerdepend onCAFMaker. CAF making has no role inTrackCaloSkimmer. Having a shared type definition (caf::ParticleIDE) is good, but it should live either inCalibrationlibrary, or in its own place (and be insbnnamespace rather thancaf). - The definition of the electric field correction may imply a bug in the code. The result of an investigation on the matter should be written down as comment in the code.
- I ask to reconsider the unit of the angle
phi. Having it in degrees means that every computation will need to convert it to radians. Personally I would consider to store its cosine instead, but if an angle is required, I believe it should be stored as radians.
I have left some additional points here and there, mostly C++ style and recommendations.
| truehits[c].p.y = (truehits[c].p.y*old_elec + ide->y*ide->numElectrons) / new_elec; | ||
| truehits[c].p.z = (truehits[c].p.z*old_elec + ide->z*ide->numElectrons) / new_elec; | ||
|
|
||
| truehits[c].time = (truehits[c].time*old_elec + tick*ide->numElectrons) / new_elec; |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This way of processing leaves me puzzled. I think it originates in 12-year old code that was written that way while interfacing with GEANT4 steps (so, at the same time when the true hits were being created) so that the information would be always valid. But here, in a single loop, it's just a waste times the 6 lines it's used in (7 now).
Not saying it's your duty to fix it, but it would be nice to.
Basically the alternative is either to use a sum in the look, and then divide once at the end, with a dedicated loop, or to use averaging objects (like lar::util::StatCollector and geo::vect::MiddlePointAccumulator).
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This is written purposefully. The number of electrons can get quite large, so you get numerical stability issues if you do a weighted sum the naive way. (sum p_i * w_i / sum w_i). I'm not sure if you mean something else, but in any case I think this is ok as is.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I do mean that.
So, you take truehits[c].time*old_elec + tick*ide->numElectrons, which I will call time_sum, you divide by new_elec, and then at the next loop you multiply again for new_elec (which in the meanwhile has become old_elec) to get time_sum again, and add a number.
How is that ensuring stability compared to storing old_time_sum all the way?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
(I actually do have my answer, but it assumes the internal precision of the FPU stack/registers is larger than the output CPU registry, plus some compiler optimisation)
sbncode/CAFMaker/FillReco.cxx
Outdated
| // Gets relative E field Distortions | ||
| geo::Vector_t EFieldOffsets = sce->GetEfieldOffsets(loc); | ||
| // Add 1 in X direction as this is the direction of the drift field | ||
| EFieldOffsets = EFieldOffsets + geo::Vector_t{1, 0, 0}; |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
It is not clear from SpaceCharge::GetEfieldOffset() whether it returns a "relative" offset (that is, assuming that the field vector is pointing on positive axis) or an absolute one (that is, in detector reference). In the latter case, the expression to the full field would need to include the absolute direction of the nominal field at the location loc.
Please check this, and document the assumption adding a comment above this line.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Thank you, added more words in the comments!
sbncode/CAFMaker/FillTrue.h
Outdated
| float totE; | ||
| }; | ||
|
|
||
| struct ParticleIDE { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This class has not much to to with a particle. It has more to do with the TPC readout. Please consider a better name ("ReadoutIDE"? I am bad in finding names).
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Agree! Updated the ParticleIDE to ReadoutIDE, I think that it is a good naming!
| const std::vector<geo::BoxBoundedGeo> &active_volumes, | ||
| const std::vector<std::vector<geo::BoxBoundedGeo>> &tpc_volumes, | ||
| const std::map<int, std::vector<std::pair<geo::WireID, const sim::IDE*>>> id_to_ide_map, | ||
| const std::map<int, std::vector<caf::ParticleIDE>> id_to_ide_map, |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Object parameters should be passed by reference unless there are explicit reasons to do otherwise ([CF-112]:
| const std::map<int, std::vector<caf::ParticleIDE>> id_to_ide_map, | |
| const std::map<int, std::vector<caf::ParticleIDE>>& id_to_ide_map, |
| std::vector<caf::ParticleIDE> empty; | ||
| const std::vector<caf::ParticleIDE> &particle_ides = id_to_ide_map.count(particle.TrackId()) ? id_to_ide_map.at(particle.TrackId()) : empty; |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
The current implementation performs the same query twice, and that would be better avoided. A way to avoid it, wrapped in a lambda function:
| std::vector<caf::ParticleIDE> empty; | |
| const std::vector<caf::ParticleIDE> &particle_ides = id_to_ide_map.count(particle.TrackId()) ? id_to_ide_map.at(particle.TrackId()) : empty; | |
| auto trackReadoutIDEs = [&id_to_ide_map](int trackID) -> std::vector<caf::ParticleIDE> const& | |
| { | |
| static std::vector<caf::ParticleIDE> const empty; | |
| auto const itIDEs = id_to_ide_map.find(trackID); | |
| return (itIDEs == id_to_ide_map.end())? empty: itIDEs->second; | |
| }; | |
| std::vector<caf::ParticleIDE> const& particle_ides = trackReadoutIDEs(particle.TrackId()); |
This is a suggestion.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I think it's ok as is -- this would be a small optimization at the cost of readability.
Hi @PetrilloAtWork , Thank you! I have made several updates following the suggestions.
Please also have a look to our responses to your additional points. |
PetrilloAtWork
left a comment
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Thank you for the answers. There still a clarification that I would like on the previous comments, but more important is that I noticed something I missed in the first review about the service management.
In short:
- link list should only include service interfaces, not implementation (like the
Standardones) - loading of the service should be limited to once per
produce()call.
Inline comments explain more.
sbncode/CAFMaker/CMakeLists.txt
Outdated
| larcorealg::Geometry | ||
| larcore::Geometry_Geometry_service | ||
| larcorealg::GeoAlgo | ||
| lardata::DetectorInfoServices_DetectorPropertiesServiceStandard_service |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Missed this... This library should not be necessary — if it is, there is a problem.
Try with:
| lardata::DetectorInfoServices_DetectorPropertiesServiceStandard_service | |
| lardataalg::headers |
(also, make sure it's appropriately indented) for the library, and add
lardata::DetectorPropertiesServicebelow (e.g. around line 69) for the module.
Rationale: DetectorPropertiesServiceStandard is an implementation of a service interface. Which implementation to use is decided run-time by reading the FHiCL services configuration, so it does not make sense to link a specific implementation at build time. What we really need is the "library" pulling in the interface. I hope my suggestion is the LArSoft's right name for the one we need here.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I have checked FillReco.h... we do have a problem: lardataalg/DetectorInfo/DetectorPropertiesStandard.h is included directly. It should not be. Ever.
Please replace that line with the appropriate header, which I think is:
#include "lardataalg/DetectorInfo/DetectorPropertiesData.h"(bonus points if you try to remove also the inclusion of ParticleInventoryService.h on the previous line, since it looks like it's not used — and if it is needed, leave it there)
With my thanks for fixing this pre-existing bug.
| if (sce->EnableSimEfieldSCE()) { | ||
| // Gets fractional E field distortions w.r.t. the nominal field on x-axis | ||
| geo::Vector_t EFieldOffsets = sce->GetEfieldOffsets(loc); | ||
| // Add 1 in X direction as this is the direction of the drift field, not caring if it is +x or -x direction, since we only want |E| |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Just to make double sure: does the offset as returned by sce always assume the nominal electric field to have positive x direction?
That assumption is an essential ingredient.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
It depends on how the SCE map is saved. For SBN SCE studies, it is assumed the nominal electric field has positive x direction.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Yes, it depends on that... unfortunately I don't see that assumption documented.
However, I see many places where that assumption is made, and if you haven't noticed anything strange in testing, that will have to do.
It is not about how it was written in the original code (in the same way in which it does not matter whether an energy was stored in MeV or GeV or erg), but rather how people expect it, and how it is expected to be used. CAF promise is that angles would be in radians; there needs to be a real need for that promise to be broken. I am not even sure there is any exception now (maybe some times bound to timestamps stored in nanoseconds). |
…ts.txt and FillReco.h headers
That makes sense. (sorry, I've not known that there has been CAF promise). Updated phi to rad from degree. |
|
@PetrilloAtWork I believe all of your comments have now been addressed. Please take another look. |
PetrilloAtWork
left a comment
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
There are some indentation fixes pending.
Worse, GitHub ate a request from yesterday's review.
The rest should be ok.
sbncode/CAFMaker/FillReco.cxx
Outdated
| // | ||
| // Use this to get the (SCE corrected) efield and the angle to the drift direction | ||
| unsigned traj_point_index = thms.at(i_hit)->Index(); | ||
| if (track.HasValidPoint(traj_point_index)) { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Please fix this indentation.
| if (track.HasValidPoint(traj_point_index)) { | |
| if (track.HasValidPoint(traj_point_index)) { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Fixed!
sbncode/Calibration/CMakeLists.txt
Outdated
| sbncode_CAFMaker | ||
| sbnobj::Common_Calibration_dict | ||
| larevt::SpaceCharge | ||
| caf_RecoUtils |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Please fix the indentation:
| caf_RecoUtils | |
| caf_RecoUtils |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Fixed!
| // Useful functions | ||
| #include "sbncode/CAFMaker/RecoUtils/RecoUtils.h" |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I suggest a comment detailing why they are useful 😉
| // Useful functions | |
| #include "sbncode/CAFMaker/RecoUtils/RecoUtils.h" | |
| #include "sbncode/CAFMaker/RecoUtils/RecoUtils.h" // sbn::ReadoutIDE, sbn::PrepTrueHits()... |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Done!
sbncode/CAFMaker/FillReco.cxx
Outdated
| double GetEfield(const detinfo::DetectorPropertiesData& dprop, const geo::Point_t loc) { | ||
| auto const* sce = lar::providerFrom<spacecharge::SpaceChargeService>(); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I am sorry, this is frustrating me and I am sure it will frustrate you too... somehow a comment on this function was not received by GitHub.
So the gist of it is that invoking a service from art at every point is not good, and this should happen only once in CAFMaker::produce().
So my request is to pass the space charge service provider as an argument from upstream:
| double GetEfield(const detinfo::DetectorPropertiesData& dprop, const geo::Point_t loc) { | |
| auto const* sce = lar::providerFrom<spacecharge::SpaceChargeService>(); | |
| double GetEfield(const detinfo::DetectorPropertiesData& dprop, spacecharge::SpaceCharge const& sce, const geo::Point_t& loc) { |
Notes:
- I am suggesting to pass a reference instead of a pointer to be consistent with
dpropservice data — that will require changing access below fromsce->tosce.. - I am also suggesting to pass
locby reference rather than by value. - In
CAFMaker::produce()there is already the variablescedefined (as pointer), which should be passed throughFillTrackPlaneCalo()to here.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Done! *sce is passed from CAFMaker::produce() into FillTrackCalo() as reference, and into FillTrackPlaneCalo() from FillTrackCalo().
sbncode/CAFMaker/FillReco.cxx
Outdated
| #include "larevt/SpaceChargeServices/SpaceChargeService.h" | ||
| #include "larcore/CoreUtils/ServiceUtil.h" |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
These will not be needed after the change below.
| #include "larevt/SpaceChargeServices/SpaceChargeService.h" | |
| #include "larcore/CoreUtils/ServiceUtil.h" |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Done! And moved #include "larevt/SpaceCharge/SpaceCharge.h" into FillReco.h from FillReco.cxx.
|
✔️ CI build for LArSoft Succeeded on slf7 for c14:prof -- details available through the CI dashboard |
|
✔️ CI build for LArSoft Succeeded on slf7 for e26:prof -- details available through the CI dashboard |
|
❌ CI build for SBND Failed at phase build SBND on slf7 for c14:prof -- details available through the CI dashboard 🚨 For more details about the failed phase, check the build SBND phase logs parent CI build details are available through the CI dashboard |
|
❌ CI build for ICARUS Failed at phase build ICARUS on slf7 for c14:prof -- details available through the CI dashboard 🚨 For more details about the failed phase, check the build ICARUS phase logs parent CI build details are available through the CI dashboard |
|
🚨 For more details about the warning phase, check the ci_tests SBND phase logs parent CI build details are available through the CI dashboard |
|
❌ CI build for ICARUS Failed at phase ci_tests ICARUS on slf7 for e26:prof - ignored warnings for build -- details available through the CI dashboard 🚨 For more details about the failed phase, check the ci_tests ICARUS phase logs parent CI build details are available through the CI dashboard |
Description
Adding phi and |E| for each hit for caf-level calorimetry
Related PR in sbnanaobj: PR151
MC BNB + cosmic flat.caf
Data BNB + light flat.caf
Data Offbeam + light flat.caf