1 #ifndef SBND_CRTDETSIMALG_CC
2 #define SBND_CRTDETSIMALG_CC
30 for (
auto &
y : wvf_y)
y /= max_y;
34 std::reverse(wvf_y.begin(),wvf_y.end());
37 (wvf_y.size(), ROOT::Math::Interpolation::kLINEAR);
39 fInterpolator->SetData(wvf_x, wvf_y);
48 mf::LogInfo(
"CRTDetSimAlg") <<
"Configured to use G4 ref time as time offset: "
54 mf::LogInfo(
"CRTDetSimAlg") <<
"Configured to use GlobalT0Offset as time offset: "
76 return static_cast<uint16_t
>(adc);
81 throw art::Exception(art::errors::LogicError)
82 <<
"Time delay cannot be negative for waveform emulation to happen." << std::endl;
98 <<
", waveform " << wf << std::endl;
100 return static_cast<uint16_t
>(wf);
105 const int & sipmID,
const uint16_t & adc)
107 uint16_t original_adc = feb_data.
ADC(sipmID);
108 uint16_t new_adc = original_adc + adc;
115 feb_data.
SetADC(sipmID, new_adc);
118 <<
", sipmID " << sipmID
119 <<
" with adc " << adc
120 <<
": was " << original_adc
121 <<
", now is " << feb_data.
ADC(sipmID) << std::endl;
130 std::map<uint16_t, sbnd::crt::FEBData> mac_to_febdata;
131 std::map<uint16_t, std::vector<AuxDetIDE>> mac_to_ides;
132 std::map<uint16_t, std::vector<int>> mac_to_sipmids;
135 std::array<uint16_t, 32> adc_pedestal = {
static_cast<uint16_t
>(
fParams.
QPed())};
137 for (
auto &
strip : strips)
141 if (!mac_to_febdata.count(
strip.mac5))
150 mac_to_ides[
strip.mac5] = std::vector<AuxDetIDE>();
151 mac_to_sipmids[
strip.mac5] = std::vector<int>();
157 if (
strip.sipm0.t1 < mac_to_febdata[
strip.mac5].Ts1())
159 mac_to_febdata[
strip.mac5].SetTs1(
strip.sipm0.t1);
160 mac_to_febdata[
strip.mac5].SetTs0(
strip.sipm0.t0);
161 mac_to_febdata[
strip.mac5].SetCoinc(
strip.sipm0.sipmID);
167 for (
auto &
strip : strips)
170 auto &feb_data = mac_to_febdata[
strip.mac5];
179 auto &ides = mac_to_ides[
strip.mac5];
180 ides.push_back(
strip.ide);
182 auto &sipmids = mac_to_sipmids[
strip.mac5];
183 sipmids.push_back(std::min(
strip.sipm0.sipmID,
strip.sipm1.sipmID));
186 for (
auto const& [mac, feb_data] : mac_to_febdata)
188 fData.push_back(std::make_pair(feb_data, mac_to_ides[mac]));
189 fAuxData.push_back(mac_to_sipmids[mac]);
193 <<
" FEBData object(s)." << std::endl << std::endl;
208 std::set<int> _mac5s;
209 std::vector<StripData> _strips;
210 uint32_t _trigger_time;
213 Trigger(
bool is_bottom,
double dead_time,
bool debug) {
214 _planeX = _planeY =
false;
215 _is_bottom = is_bottom;
216 _dead_time = dead_time;
222 _planeX = _planeY =
false;
227 if(_debug)
std::cout <<
"TRIGGER TIME IS " << _trigger_time << std::endl;
232 _strips.push_back(strip);
233 _mac5s.insert(strip.
mac5);
236 if (strip.
planeID == 0) _planeX =
true;
237 if (strip.
planeID == 1) _planeY =
true;
240 if(_debug)
std::cout <<
"\tAdded strip with mac " << strip.
mac5
241 <<
" on plane " << strip.
planeID
242 <<
", with time " << strip.
sipm0.
t1 << std::endl;
246 bool tagger_triggered() {
248 return _planeX or _planeY;
250 return _planeX
and _planeY;
254 bool is_in_dead_time(
int mac5,
int time) {
255 if (!_mac5s.count(mac5)) {
return false; }
256 return (time <= _dead_time);
261 <<
" on plane " << strip.
planeID
262 <<
", with time " << strip.
sipm0.
t1
263 <<
" -> didn't have SiPMs coincidence" << std::endl;
268 <<
" on plane " << strip.
planeID
269 <<
", with time " << strip.
sipm0.
t1
270 <<
" -> happened during dead time." << std::endl;
278 auto &
name = iter.first;
279 auto &
tagger = iter.second;
281 mf::LogInfo(
"CRTDetSimAlg") <<
"Simulating trigger for tagger " <<
name << std::endl;
283 bool is_bottom =
name.find(
"Bottom") != std::string::npos;
286 auto & strip_data_v =
tagger.data;
289 std::sort(strip_data_v.begin(), strip_data_v.end(),
292 return strip1.
sipm0.
t1 < strip2.sipm0.t1;
295 uint32_t trigger_ts1 = 0, current_time = 0;
296 bool first_trigger =
true;
299 for (
size_t i = 0; i < strip_data_v.size(); i++)
301 auto & strip_data = strip_data_v[i];
303 current_time = strip_data.sipm0.t1;
306 if (strip_data.sipm_coinc
and first_trigger)
308 first_trigger =
false;
309 trigger_ts1 = current_time;
310 trigger.reset(trigger_ts1);
316 trigger.add_strip(strip_data);
321 else if ((!trigger.tagger_triggered() or
322 (trigger.tagger_triggered()
and
323 !trigger.is_in_dead_time(strip_data.mac5, current_time - trigger_ts1)))
and
324 strip_data.sipm_coinc)
326 if (trigger.tagger_triggered()) {
331 trigger_ts1 = current_time;
334 trigger.reset(trigger_ts1);
337 trigger.add_strip(strip_data);
339 else if (!strip_data.sipm_coinc)
341 trigger.print_no_coinc(strip_data);
345 trigger.print_dead_time(strip_data);
350 if (trigger.tagger_triggered()) {
356 mf::LogInfo(
"CRTDetSimAlg") <<
"There are " <<
fData.size() <<
" FEBData objects." << std::endl;
362 vector<sim::AuxDetIDE> ides) {
364 art::ServiceHandle<geo::Geometry> geoService;
370 std::sort(ides.begin(), ides.end(),
372 return ((a.
entryT + a.
exitT)/2) < ((b.entryT + b.exitT)/2);
376 std::set<std::string> volNames = { adGeo.
TotalVolume()->GetName() };
377 std::vector<std::vector<TGeoNode const*> > paths =
378 geoService->FindAllVolumePaths(volNames);
380 std::string
path =
"";
381 for (
size_t inode=0; inode<paths.at(0).size(); inode++) {
382 path += paths.at(0).at(inode)->GetName();
383 if (inode < paths.at(0).size() - 1) {
388 TGeoManager* manager = geoService->ROOTGeoManager();
389 manager->cd(path.c_str());
395 TGeoNode* nodeArray = manager->GetCurrentNode();
396 TGeoNode* nodeStrip = nodeArray->GetDaughter(adsid);
397 TGeoNode* nodeModule = manager->GetMother(1);
398 TGeoNode* nodeTagger = manager->GetMother(2);
400 std::string volumeName = nodeStrip->GetVolume()->GetName();
402 mf::LogDebug(
"CRTDetSimAlg") <<
"Strip name: " << nodeStrip->GetName()
403 <<
", number = " << nodeStrip->GetNumber()
404 <<
"\n Array name: " << nodeArray->GetName()
405 <<
", number = " << nodeArray->GetNumber()
406 <<
"\n Module name: " << nodeModule->GetName()
407 <<
", number = " << nodeModule->GetNumber()
408 <<
"\n Tagger name: " << nodeTagger->GetName()
409 <<
", number = " << nodeTagger->GetNumber()
410 <<
"\n Strip volume name: " << volumeName << std::endl;
413 uint16_t mac5 =
static_cast<uint16_t
>(nodeModule->GetNumber());
416 double origin[3] = {0, 0, 0};
417 double modulePosMother[3];
418 nodeModule->LocalToMaster(origin, modulePosMother);
421 unsigned planeID = (modulePosMother[2] > 0);
424 bool top = (planeID == 1) ? (modulePosMother[1] > 0) : (modulePosMother[0] < 0);
427 mf::LogInfo(
"CRTDetSimAlg") <<
"We have " << ides.size() <<
" IDE for this SimChannel." << std::endl;
428 for (
size_t ide_i = 0; ide_i < ides.size(); ide_i++) {
441 mf::LogInfo(
"CRTDetSimAlg") <<
"True IDE with time " << tTrue
442 <<
", energy " << eDep << std::endl;
445 throw art::Exception(art::errors::LogicError)
446 <<
"Time cannot be negative. Check the time offset used for the CRT simulation.\n"
447 <<
"True time: " << (ide.
entryT + ide.
exitT) / 2 <<
"\n"
451 double world[3] = {
x,
y, z};
452 double svHitPosLocal[3];
456 double distToReadout;
458 distToReadout =
abs( adsGeo.
HalfWidth1() - svHitPosLocal[0]);
461 distToReadout =
abs(-adsGeo.
HalfWidth1() - svHitPosLocal[0]);
484 mf::LogWarning(
"CRTDetSimAlg") <<
"EqualizeSiPMTimes is on." << std::endl;
498 uint32_t moduleID = mac5;
499 uint32_t stripID = adsid;
500 uint32_t channel0ID = 32 * moduleID + 2 * stripID + 0;
501 uint32_t channel1ID = 32 * moduleID + 2 * stripID + 1;
502 uint32_t sipm0ID = stripID * 2 + 0;
503 uint32_t sipm1ID = stripID * 2 + 1;
505 if (volumeName.find(
"MINOS") != std::string::npos) {
continue;}
509 bool sipm_coinc =
false;
511 if (q0 > threshold &&
519 if (ts1_ch0 > ts1_ch1)
521 std::swap(ts1_ch0, ts1_ch1);
522 std::swap(channel0ID, channel1ID);
524 std::swap(sipm0ID, sipm1ID);
547 tagger.
data.push_back(strip_data);
551 mf::LogInfo(
"CRTDetSimAlg")
552 <<
"CRT HIT in adid/adsid " << adid <<
"/" << adsid <<
"\n"
553 <<
"MAC5 " << mac5 <<
"\n"
554 <<
"TRUE TIME " << tTrue <<
"\n"
555 <<
"TRACK ID " << ide.
trackID <<
"\n"
556 <<
"CRT HIT POS " << x <<
" " << y <<
" " << z <<
"\n"
557 <<
"CRT STRIP POS " << poss[0] <<
" " << poss[1] <<
" " << poss[2] <<
"\n"
558 <<
"CRT MODULE POS " << modulePosMother[0] <<
" "
559 << modulePosMother[1] <<
" "
560 << modulePosMother[2] <<
" "
562 <<
"CRT PATH: " << path <<
"\n"
563 <<
"CRT level 0 (strip): " << nodeStrip->GetName() <<
"\n"
564 <<
"CRT level 1 (array): " << nodeArray->GetName() <<
"\n"
565 <<
"CRT level 2 (module): " << nodeModule->GetName() <<
"\n"
566 <<
"CRT level 3 (tagger): " << nodeTagger->GetName() <<
"\n"
567 <<
"CRT PLANE ID: " << planeID <<
"\n"
568 <<
"CRT distToReadout: " << distToReadout <<
" " << (top ?
"top" :
"bot") <<
"\n"
569 <<
"CRT Q SiPM 0: " << q0 <<
", SiPM 1: " << q1
570 <<
"CRT Ts1 SiPM 0: " << ts1_ch0 <<
" SiPM 1: " << ts1_ch1 <<
"\n";
576 long & npe0,
long & npe1,
double & q0,
double &q1)
590 double npeExp0 = npeExpected * abs0 / (abs0 + abs1);
591 double npeExp1 = npeExpected * abs1 / (abs0 + abs1);
594 npe0 = CLHEP::RandPoisson::shoot(&
fEngine, npeExp0);
595 npe1 = CLHEP::RandPoisson::shoot(&
fEngine, npeExp1);
608 mf::LogInfo(
"CRTSetSimAlg")
609 <<
"CRT CHARGE RESPONSE: eDep = " << eDep
610 <<
", npeExpected = " << npeExpected
611 <<
", npe0 = " << npe0 <<
" -> q0 = " << q0
612 <<
", npe1 = " << npe1 <<
" -> q1 = " << q1 << std::endl;
616 float t0,
float npeMean,
float r)
630 double tDelay = CLHEP::RandGauss::shoot(&
fEngine, tDelayMean, tDelayRMS);
638 double t = t0 + tProp + tDelay;
646 mf::LogWarning(
"CRTSetSimAlg") <<
"Time is negative. Check the time offset used." << std::endl;
649 uint32_t time_int =
static_cast<uint32_t
>(time);
651 mf::LogInfo(
"CRTSetSimAlg")
652 <<
"CRT TIMING: t0 = " << t0 <<
" (true G4 time)"
653 <<
", tDelayMean = " << tDelayMean
654 <<
", tDelayRMS = " << tDelayRMS
655 <<
", tDelay = " << tDelay
656 <<
", tProp = " << tProp
658 <<
", time = " << time
659 <<
", time_int = " << time_int <<
" (time in uint32_t)" << std::endl;
uint32_t getChannelTriggerTicks(float t0, float npeMean, float r)
process_name opflash particleana ie ie ie z
fhicl::Atom< double > PropDelay
fhicl::Atom< double > TDelayRMSGausShift
fhicl::Atom< double > NpeScaleNorm
fhicl::Atom< double > QThreshold
void AddADC(sbnd::crt::FEBData &feb_data, const int &sipmID, const uint16_t &adc)
process_name opflash particleana ie x
void ConfigureTimeOffset()
std::vector< std::pair< sbnd::crt::FEBData, std::vector< AuxDetIDE > > > GetData()
int trackID
Geant4 supplied track ID.
AuxDetSensitiveGeo const & SensitiveVolume(size_t sv) const
std::unique_ptr< ROOT::Math::Interpolator > fInterpolator
The interpolator used to estimate the CRT waveform.
CRTDetSimParams fParams
The table of CRT simulation parameters.
fhicl::Atom< double > TDelayRMSExpShift
void FillTaggers(const uint32_t adid, const uint32_t adsid, std::vector< AuxDetIDE > ides)
void ProcessStrips(const std::vector< StripData > &strips)
double fG4RefTime
The G4 reference time that can be used as a time offset.
fhicl::Sequence< double > WaveformY
fhicl::Atom< bool > DoWaveformEmulation
fhicl::Atom< uint32_t > AdcSaturation
fhicl::Atom< double > QRMS
double HalfWidth1() const
fhicl::Atom< double > QSlope
fhicl::Atom< double > TResInterpolator
fhicl::Atom< double > TDelayShift
fhicl::Atom< double > TDelaySigma
float exitY
Exit position Y of particle.
BEGIN_PROLOG triggeremu_data_config_icarus settings PMTADCthresholds sequence::icarus_stage0_multiTPC_TPC physics sequence::icarus_stage0_EastHits_TPC physics sequence::icarus_stage0_WestHits_TPC physics producers purityana0 caloskimCalorimetryCryoE physics caloskimCalorimetryCryoW physics path
fhicl::Sequence< double > WaveformX
std::vector< std::pair< sbnd::crt::FEBData, std::vector< AuxDetIDE > > > fData
This member stores the final FEBData for the CRT simulation.
unsigned planeID
The plane ID (0 or 1 for horizontal or vertical)
timescale_traits< TriggerTimeCategory >::time_point_t trigger_time
A point in time on the trigger time scale.
double HalfHeight() const
SiPMData sipm0
One SiPM (the one that sees signal first)
fhicl::Atom< double > TDelayOffset
process_name opflash particleana ie ie y
float entryT
Entry time of particle.
std::vector< std::vector< int > > GetAuxData()
fhicl::Atom< bool > EqualizeSiPMTimes
void SetADC(size_t sipmID, uint16_t adc)
std::map< std::string, Tagger > fTaggers
A list of hit taggers, before any coincidence requirement (name -> tagger)
fhicl::Atom< double > PropDelayError
std::vector< StripData > data
A vector of strips that have energy deposits.
fhicl::Atom< double > AbsLenEff
float exitT
Exit time of particle.
fhicl::Atom< double > TDelayRMSExpNorm
auto end(FixedBins< T, C > const &) noexcept
fEngine(art::ServiceHandle< rndm::NuRandomService >() ->createEngine(*this, pset,"Seed"))
process_name drop raw::OpDetWaveforms_DataApr2016RecoStage1_saturation_ saturation
void ChargeResponse(double eDep, double d0, double d1, double distToReadout, long &npe0, long &npe1, double &q0, double &q1)
return match has_match and(match.match_pdg==11 or match.match_pdg==-11)
fhicl::Atom< double > TDelayRMSGausNorm
float exitZ
Exit position Z of particle.
fhicl::Table< CRTDetSimParams > Parameters
float entryZ
Entry position Z of particle.
fhicl::Atom< bool > DebugTrigger
float exitX
Exit position X of particle.
fhicl::Atom< double > QPed
constexpr auto absDiff(A const &a, B const &b)
Returns the absolute value of the difference between two values.
auto begin(FixedBins< T, C > const &) noexcept
float energyDeposited
total energy deposited for this track ID and time
fhicl::Atom< double > TDelayRMSGausSigma
fhicl::Atom< bool > UseEdep
fhicl::Atom< double > StripCoincidenceWindow
fhicl::Atom< double > TaggerPlaneCoincidenceWindow
fhicl::Atom< double > DeadTime
float entryX
Entry position X of particle.
float entryY
Entry position Y of particle.
const TGeoVolume * TotalVolume() const
fhicl::Atom< double > GlobalT0Offset
MC truth information to make RawDigits and do back tracking.
CLHEP::HepRandomEngine & fEngine
The random-number engine.
createEngine fG4RefTime(art::ServiceHandle< detinfo::DetectorClocksService const >() ->DataForJob().G4ToElecTime(0)*1e3)
void WorldToLocal(const double *world, double *auxdet) const
Transform point from world frame to local auxiliary detector frame.
uint16_t mac5
The FEB number this strip is in.
fhicl::Atom< double > ClockSpeedCRT
fhicl::Atom< double > TDelayNorm
stream1 can override from command line with o or output services user sbnd
fhicl::Atom< double > NpeScaleShift
CRTDetSimAlg(const Parameters &p, CLHEP::HepRandomEngine &fRandEngine, double g4RefTime)
void LocalToWorld(const double *auxdet, double *world) const
Transform point from local auxiliary detector frame to world frame.
bool sipm_coinc
Stores the ID of the SiPM that sees signal first (0-31)
std::vector< std::vector< int > > fAuxData
This member stores the indeces of SiPM per AuxDetIDE.
fhicl::Atom< double > TDelayRMSExpScale
double fTimeOffset
The time that will be used in the simulation.
uint16_t WaveformEmulation(const uint32_t &time_delay, const double &adc)
BEGIN_PROLOG could also be cout
constexpr Point origin()
Returns a origin position with a point of the specified type.
fhicl::Atom< bool > UseG4RefTimeOffset