IDEA DCH full digitization chain#78
Conversation
| @@ -0,0 +1,93 @@ | |||
| # | |||
There was a problem hiding this comment.
There should be a test that runs this steering file, otherwise we don't know if it runs.
Updated the debug output file name to match the new naming convention.
tmadlener
left a comment
There was a problem hiding this comment.
This doesn't look like it has been clang-formatted yet (and CI will likely fail also due to that.
I have started to go through the code and there are a few things that could be improved. I didn't look at all of it, but some of the comments might apply on a broader scope.
| namespace BB | ||
| { | ||
| //Atomic number of material | ||
| double Z=2; | ||
|
|
||
| //Relative atomic mass | ||
| double A=4.0026; | ||
|
|
||
| //Atomic number of particle | ||
| double z_particle=1; | ||
|
|
||
| //Electron rest mass MeV | ||
| double me = 0.511; | ||
|
|
||
| //Electron charge in eV | ||
| double e = 1; | ||
|
|
||
| double K = 0.307075; | ||
|
|
||
| //double I=41.8*1e-6; | ||
| //variables for delta | ||
| double c=11.1393; | ||
| double x0=2.2017; | ||
| double x1=3.6122; | ||
| double a=0.13443; | ||
| double k1=5.8347; | ||
| const double k2=2.0*TMath::Log(10); | ||
|
|
||
| //double getDelta(double p, double m){ | ||
| // double delta; | ||
| // double x= TMath::Log10(p/m); | ||
| // | ||
| // cout<<x<<"\t"<<p<<endl; | ||
| // if(x>=x1) delta=k2*x-c; | ||
| // if(x<x1&&x>=x0) delta=k2*x-c+a*pow((x1-x),k1); | ||
| // if(x<x0) delta=0.0; | ||
| // |
There was a problem hiding this comment.
Are these used anywhere else than below in bethe_bloch? In that case I would simply move them there. Also these could / should probably marked constepr (where possible) or at least const
| // return delta; | ||
| //} | ||
|
|
||
| double bethe_bloch( double *xp,double *par){ |
There was a problem hiding this comment.
It doesn't look like this has to go through a ROOT interface at any point. Hence, we should be able to pass the xp and par as ,std::arrays. Checking the only call site of this, it might even just be double xp and std::array<double, 2> par. Alternatively already explicitly use m and I as arguments to not hide behind a way too generic interface.
| extension::SenseWireHitCollection, | ||
| extension::SenseWireHitSimTrackerHitLinkCollection, |
There was a problem hiding this comment.
Should this still use the extension types, or rather the ones that went to EDM4hep?
| class TF1; | ||
| class TFile; | ||
|
|
||
| /// constant to convert from mm (EDM4hep) to DD4hep (cm) |
| TVector3 Convert_EDM4hepVector_to_TVector3(const edm4hep::Vector3d& v, double scale) const { | ||
| return {v[0] * scale, v[1] * scale, v[2] * scale}; | ||
| }; | ||
| edm4hep::Vector3d Convert_TVector3_to_EDM4hepVector(const TVector3& v, double scale) const { | ||
| return {v.x() * scale, v.y() * scale, v.z() * scale}; | ||
| }; |
There was a problem hiding this comment.
At least for the scaling we have utilities in EDM4hep: https://github.com/key4hep/EDM4hep/blob/6d24c90b72c2434cacf3824a9b05b758d7e3911f/utils/include/edm4hep/utils/vector_utils.h#L293-L296
I.e. it should be possible to do:
return edm4hep::Vector3d{v.x(), v.y(), v.z()} * scale;| // This function is used to calculate the dNdx using BB.h file: | ||
| // when we have a beam-test TGraph gNcldx(bg)->(clusters/cm), | ||
| inline double DCHdigi_v03::get_dNcldx_per_cm(double betagamma, const edm4hep::MCParticle& mc) const | ||
| { | ||
| // 1) reconstruct momentum from β | ||
| const double m_GeV = mc.getMass(); | ||
| const double p_GeV = betagamma * m_GeV; | ||
|
|
||
| // 2) call your header: bethe_bloch(xp, par) | ||
| double xp[1] = { p_GeV }; // GeV (header multiplies by 1e3 internally) | ||
| double par[2] = { m_GeV * 1.0e3, // mass in MeV | ||
| m_MeanExcEnergy_eV.value() * 1e-6 // I in MeV | ||
| }; | ||
| const double dEdx_MeVcm2_per_g = BB::bethe_bloch(xp, par); | ||
| const double dEdx_MeV_per_cm = dEdx_MeVcm2_per_g * m_GasDensity_g_cm3.value(); | ||
| const double lambda_per_cm = (dEdx_MeV_per_cm * 1.0e6) / m_W_eff_eV.value(); | ||
|
|
||
| return (lambda_per_cm > 0.0) ? lambda_per_cm : 0.0; | ||
| } |
There was a problem hiding this comment.
This should probably live in the cpp file of the algorithm to which it belongs.
|
|
||
| // --- Experimental cluster size probabilities w(n) for He-iSobutane (90:10) --- | ||
| // Based on Fischle et al., NIM A301 (1991) | ||
| inline const std::vector<double>& w_cluster_He_iC4H10() |
There was a problem hiding this comment.
This can be done as constexpr when using a std::array<double, 35>. That way we don't have to keep track of init and we don't need a static vector. Plus we can guarantee that all the (admittedly probably negligible) work is done at compile time.
See e.g. https://godbolt.org/z/GsPTsG39E
| class DCHXT2DLUT { | ||
| public: | ||
| DCHXT2DLUT() = default; | ||
| ~DCHXT2DLUT(); | ||
|
|
||
| // Load xt_mean and xt_error from ROOT file (par.root) | ||
| bool load(const std::string& rootFile, | ||
| const std::string& meanName = "xt_mean", | ||
| const std::string& sigmaName = "xt_error"); | ||
|
|
||
| bool isLoaded() const { return m_loaded; } |
There was a problem hiding this comment.
The way this is used you could get rid of load and in turn isLoaded. In the algorithm you construct it and immediately afterwards call load. You never call load again. So you could just make the constructor do the loading in which case you can guarantee that either you have a valid object or you throw an exception in case you don't.
m_file should probably be a unique_ptr in which case you could save some manual management.
| // advance internal state to minimize possibility of creating correlations | ||
| rng_engine.discard(10); | ||
| for (int i = 0; i < 10; ++i) | ||
| myRandom.Rndm(); |
There was a problem hiding this comment.
You will probably have to do more than 10 iterations here if you really want to guarantee no correlations. I don't know exactly how many, but I seem to remember O(1000).
| if (!m_uidSvc) | ||
| ThrowException("Unable to get UniqueIDGenSvc"); | ||
|
|
||
| if (0 > m_z_resolution.value()) | ||
| ThrowException("Z resolution input value can not be negative!"); | ||
|
|
||
| if (0 > m_xy_resolution.value()) | ||
| ThrowException("Radial (XY) resolution input value can not be negative!"); |
There was a problem hiding this comment.
Many of these can probably be done with K4_GAUDI_CHECK. Which would also make it possible to get rid of ThrowException (for which I don't see the added value, since throw std::runtime_error("...."); is only a small number of additional characters, but withotu hiding what you actually do.
BEGINRELEASENOTES
Description
This PR introduces a full digitization chain for the IDEA Drift Chamber (DCH).
The implementation follows the standard detector signal formation sequence:
ionization → drift → amplification → signal formation → electronics → digitization.
New Gaudi algorithm:
DCHdigi_v03Drift time handling:
DCHXT2DLUTxt_meanandxt_errorfrom ROOT fileNoise simulation:
DCHFFTNoiseEDM4hep extensions:
SenseWireHitRawTimeSeriesCollectionSteering:
runDCHdigiV3.pyOutputs
SenseWireHitCollectionSenseWireHitSimTrackerHitLinkCollectionRawTimeSeriesCollectionENDRELEASENOTES