34 #include "nusimdata/SimulationBase/MCParticle.h"
35 #include "nusimdata/SimulationBase/MCTruth.h"
39 #include "sbndaq-artdaq-core/Overlays/Common/BernCRTFragmentV2.hh"
40 #include "sbndaq-artdaq-core/Overlays/Common/CAENV1730Fragment.hh"
41 #include "sbndaq-artdaq-core/Overlays/FragmentType.hh"
42 #include "artdaq-core/Data/Fragment.hh"
45 #include "art/Framework/Core/EDProducer.h"
46 #include "art/Framework/Principal/Event.h"
47 #include "art/Framework/Principal/Handle.h"
48 #include "art/Framework/Services/Registry/ServiceHandle.h"
49 #include "art_root_io/TFileService.h"
50 #include "art/Framework/Core/ModuleMacros.h"
51 #include "canvas/Persistency/Common/FindManyP.h"
52 #include "canvas/Utilities/Exception.h"
57 #include "messagefacility/MessageLogger/MessageLogger.h"
58 #include "fhiclcpp/ParameterSet.h"
59 #include "fhiclcpp/types/Table.h"
60 #include "fhiclcpp/types/Atom.h"
61 #include "cetlib/pow.h"
64 #include "nurandom/RandomUtils/NuRandomService.h"
65 #include "CLHEP/Random/RandFlat.h"
96 void produce(art::Event&
e)
override;
157 art::ServiceHandle<art::TFileService>
tfs;
167 fSimModuleLabel(
p.get<std::string>(
"SimModuleLabel",
"largeant")),
168 fCRTSimLabel(
p.get<std::string>(
"CRTSimLabel",
"crt")),
169 fFEBDataLabel(
p.get<std::string>(
"FEBDataLabel",
"crtsim")),
170 fVerbose(
p.get<
bool>(
"Verbose",
false)),
171 fClockSpeedCRT(
p.get<
double>(
"ClockSpeedCRT")),
172 fFirstFEBMac5(
p.get<
size_t>(
"FirstFEBMac5", 0)),
173 fInputModuleNameWvfm(
p.get<std::string>(
"InputModuleNameWvfm")),
174 fInputModuleNameTrigger(
p.get<std::string>(
"InputModuleNameTrigger")),
176 fMultiplicityThreshold(
p.get<
int>(
"MultiplicityThreshold")),
177 fBeamWindowLength(
p.get<
double>(
"BeamWindowLength", 1.6)),
178 nChannelsFrag(
p.get<
double>(
"nChannelsFrag", 15)),
179 wfm_length(
p.get<
double>(
"WfmLength", 5120)),
180 fTriggerTimeEngine(art::ServiceHandle<rndm::NuRandomService>{}->createEngine(*
this,
"HepJamesRandom",
"trigger",
p,
"SeedTriggerTime"))
184 produces< std::vector<artdaq::Fragment> >();
187 fGeometryService = lar::providerFrom<geo::Geometry>();
190 auto const clockData = art::ServiceHandle<detinfo::DetectorClocksService const>()->DataForJob();
191 fSampling = clockData.OpticalClock().Frequency();
194 auto subsetCondition = [](
auto const& i)->
bool {
return i[
"pd_type"] ==
"pmt_coated" || i[
"pd_type"] ==
"pmt_uncoated"; };
195 auto pmtMap = pdMap.getCollectionFromCondition(subsetCondition);
196 if (fVerbose)
std::cout <<
"Number of PDs selected: \t" << pmtMap.size() <<
"\n";
197 for(
auto const& i:pmtMap){
198 channelList.push_back(i[
"channel"]);
210 fSubrun = e.subRun();
211 fEvent = e.id().event();
213 std::cout<<
"============================================"<<std::endl
214 <<
"Run = "<<fRun<<
", SubRun = "<<fSubrun<<
", Event = "<<fEvent<<std::endl
215 <<
"============================================"<<std::endl;
222 for(
int i=0; i<num_febs; i++){empty_fragment[i]=
true;}
224 int num_module = fCrtGeo.NumModules();
231 art::Handle<std::vector<sbnd::crt::FEBData>> feb_data_h;
232 e.getByLabel(fFEBDataLabel, feb_data_h);
235 if (!feb_data_h.isValid()) {
236 throw art::Exception(art::errors::Configuration) <<
"could not locate FEBData." << std::endl;;
239 std::vector<art::Ptr<sbnd::crt::FEBData>> feb_data_v;
240 art::fill_ptr_vector(feb_data_v, feb_data_h);
242 art::FindManyP<sim::AuxDetIDE, sbnd::crt::FEBTruthInfo> febdata_to_ides (feb_data_h, e, fFEBDataLabel);
245 std::fill(feb_hits_in_fragments, feb_hits_in_fragments +
sizeof(feb_hits_in_fragments), 0);
248 std::unique_ptr<std::vector<artdaq::Fragment>> vecFrag = std::make_unique<std::vector<artdaq::Fragment>>();
252 uint16_t lostcpu = 0;
253 uint16_t lostfpga = 0;
255 uint16_t lost_hits = 0;
259 uint64_t run_start_time = 0;
260 uint64_t this_poll_start = 0;
261 uint64_t this_poll_end = 0;
262 int32_t system_clock_deviation = 0;
263 uint32_t feb_hits_in_poll = 0;
266 uint64_t sequence_id = fEvent;
268 uint64_t temp_last_time = 0;
272 std::normal_distribution<double> distribution(175.0,23.0);
275 for (
size_t feb_i = 0; feb_i < feb_data_v.size(); feb_i++) {
277 auto const feb_data = feb_data_v[feb_i];
279 if(fVerbose){
std::cout <<
"FEB " << feb_i <<
" with mac " << feb_data->Mac5() << std::endl;}
281 empty_fragment[feb_data->Mac5()] =
false;
283 int channel = feb_data->Mac5() * 32;
284 std::string stripName = fCrtGeo.ChannelToStripName(channel);
285 std::string
tagger = fCrtGeo.GetTaggerName(stripName);
286 taggers[feb_data->Mac5()] = tagger;
288 T0s[feb_data->Mac5()][feb_hits_in_fragments[feb_data->Mac5()]] = feb_data->Ts0();
289 T1s[feb_data->Mac5()][feb_hits_in_fragments[feb_data->Mac5()]] = feb_data->Ts1();
290 for (
int i_adc = 0; i_adc<32; i_adc++){
292 if (feb_data->ADC()[i_adc] > 4089){
294 }
else if (feb_data->ADC()[i_adc] == 0){
296 adc = distribution(generator);
298 adc = feb_data->ADC()[i_adc];
300 ADCs[feb_data->Mac5()][feb_hits_in_fragments[feb_data->Mac5()]][i_adc] = adc;
303 feb_hits_in_fragments[feb_data->Mac5()]++;
308 for (
size_t feb_i = fFirstFEBMac5; feb_i < num_module+fFirstFEBMac5; feb_i++){
310 if (empty_fragment[feb_i]){
312 feb_hits_in_fragments[feb_i] = 1;
313 int channel = feb_i * 32;
314 std::string stripName = fCrtGeo.ChannelToStripName(channel);
315 std::string
tagger = fCrtGeo.GetTaggerName(stripName);
316 taggers[feb_i] = tagger;
320 for (
int i_adc = 0; i_adc<32; i_adc++){
321 uint16_t adc = distribution(generator);
322 ADCs[feb_i][0][i_adc] = adc;
326 if (feb_hits_in_fragments[feb_i]==0)
continue;
329 uint8_t mac5 = (uint8_t)feb_i;
330 uint16_t feb_hits_in_fragment = feb_hits_in_fragments[feb_i];
332 sbndaq::BernCRTFragmentMetadataV2 metadata;
334 metadata.set_mac5(mac5);
335 metadata.set_clock_deviation(system_clock_deviation);
336 metadata.set_hits_in_poll(feb_hits_in_poll);
337 metadata.set_hits_in_fragment(feb_hits_in_fragment);
338 metadata.set_run_start_time(run_start_time);
339 metadata.update_poll_time(this_poll_start, this_poll_end);
341 uint64_t timestamp = (uint64_t)(T0s[feb_i][feb_hits_in_fragments[feb_i]]/fClockSpeedCRT);
345 uint16_t fragmentIDVal = 32768 + 12288 + (plane_num * 256) + (uint16_t)mac5;
346 if(fVerbose){
std::cout<<
"fragmentID: "<<std::bitset<16>{fragmentIDVal}<<std::endl;}
347 auto fragment_uptr = artdaq::Fragment::FragmentBytes(
sizeof(sbndaq::BernCRTHitV2)*metadata.hits_in_fragment(),
350 sbndaq::detail::FragmentType::BERNCRTV2,
356 std::vector<sbndaq::BernCRTHitV2> data_vec;
357 for (
int i_frag = 0; i_frag<feb_hits_in_fragments[feb_i]; i_frag++){
358 sbndaq::BernCRTHitV2
hit;
361 uint32_t ts0 = T0s[feb_i][i_frag];
362 uint32_t ts1 = T1s[feb_i][i_frag];
364 if (ts0==0){flags=7;}
else if (ts1==0){flags=11;}
366 uint64_t feb_hit_number = feb_hits_in_fragments[feb_i];
367 timestamp = (uint64_t)ts0/fClockSpeedCRT;
368 uint64_t last_accepted_timestamp = temp_last_time;
369 temp_last_time = timestamp;
371 hit.flags = (uint16_t)flags;
372 hit.lostcpu = (uint16_t)lostcpu;
373 hit.lostfpga = (uint16_t)lostfpga;
374 hit.ts0 = (uint32_t)ts0;
375 hit.ts1 = (uint32_t)ts1;
376 for (
int i_adc = 0; i_adc<32; i_adc++){
377 hit.adc[i_adc] = ADCs[feb_i][i_frag][i_adc];
379 hit.coinc = (uint32_t)coinc;
380 hit.feb_hit_number = (uint64_t)feb_hit_number;
381 hit.timestamp = (uint64_t)timestamp;
382 hit.last_accepted_timestamp = (uint64_t)last_accepted_timestamp;
383 hit.lost_hits = (uint16_t)lost_hits;
385 data_vec.emplace_back(hit);
389 std::memcpy(fragment_uptr->dataBeginBytes(), data_vec.data(),
sizeof(sbndaq::BernCRTHitV2)*metadata.hits_in_fragment());
392 vecFrag->push_back(*fragment_uptr);
396 int num_crt_frags = vecFrag->size();
397 if(fVerbose)
std::cout <<
"CRT Fragments written: " << num_crt_frags << std::endl;
404 art::Handle< std::vector< raw::OpDetWaveform > > wvfmHandle;
405 art::Handle< std::vector< sbnd::comm::pmtTrigger > > triggerHandle;
406 e.getByLabel(fInputModuleNameWvfm, wvfmHandle);
407 e.getByLabel(fInputModuleNameTrigger, triggerHandle);
409 if(!wvfmHandle.isValid()) {
410 throw art::Exception(art::errors::Configuration)
411 <<
"Could not find any waveforms, input must contain OpDetWaveforms." <<
"\n";
413 if(!triggerHandle.isValid()) {
414 throw art::Exception(art::errors::Configuration)
415 <<
"Could not find any PMT hardware trigger object, must run PMT trigger producer before running this module." <<
"\n";
419 double fMinStartTime = -1510.0;
420 double fMaxEndTime = 1510.0;
422 for(
auto const& wvf : (*wvfmHandle)) {
423 double fChNumber = wvf.ChannelNumber();
424 std::string opdetType = pdMap.pdType(fChNumber);
426 if (opdetType !=
"pmt_coated" && opdetType !=
"pmt_uncoated")
continue;
427 if (wvf.TimeStamp() < fMinStartTime){ fMinStartTime = wvf.TimeStamp(); }
428 if ((
double(wvf.size()) / fSampling + wvf.TimeStamp()) > fMaxEndTime){ fMaxEndTime = double(wvf.size()) / fSampling + wvf.TimeStamp();}
431 if (fVerbose){
std::cout<<
"MinStartTime: "<<fMinStartTime<<
" MaxEndTime: "<<fMaxEndTime<<std::endl;}
433 std::vector<short> wvf_0; wvf_0.reserve((
int)(3020*1e6/2));
434 for (
double i = fMinStartTime; i<fMaxEndTime+(1./fSampling); i+=(1./fSampling)){
437 for (
size_t i = 0; i < channelList.size(); i++){
438 wvf_channel.push_back(wvf_0);
447 for(
auto const& wvf : (*wvfmHandle)) {
449 double fChNumber = wvf.ChannelNumber();
450 std::string opdetType = pdMap.pdType(fChNumber);
453 if (opdetType !=
"pmt_coated" && opdetType !=
"pmt_uncoated")
continue;
457 double fStartTime = wvf.TimeStamp();
458 double fEndTime = double(wvf.size()) / fSampling + fStartTime;
461 std::vector<short> wvf_full; wvf_full.reserve((
short)(3020*1e6/2));
463 if (fStartTime > fMinStartTime){
464 for (
double i = fStartTime-fMinStartTime; i>0.; i-=(1./fSampling)){
469 for(
unsigned int i = 0; i < wvf.size(); i++) {
470 wvf_full.push_back(wvf[i]);
473 if (fEndTime < fMaxEndTime){
474 for (
double i = fMaxEndTime-fEndTime; i>0.; i-=(1./fSampling)){
481 auto ich = std::find(channelList.begin(), channelList.end(), fChNumber);
482 if (ich != channelList.end()){
483 i_ch = ich - channelList.begin();
485 if (wvf_channel.at(i_ch).size() < wvf_full.size()){
486 if (fVerbose)
std::cout<<
"Full waveform -- Previous Channel" << fChNumber <<
" Size: "<<wvf_channel.at(i_ch).size()<<
"New Channel" << fChNumber <<
" Size: "<<wvf_full.size()<<std::endl;
487 for(
unsigned int i = wvf_channel.at(i_ch).size(); i < wvf_full.size(); i++) {
488 wvf_channel.at(i_ch).push_back(
fBaseline);
491 for(
unsigned int i = 0; i < wvf_full.size(); i++) {
492 wvf_channel.at(i_ch)[i] += (wvf_full[i] -
fBaseline);
501 std::vector<size_t> triggerIndex;
502 for(
auto const& trigger : (*triggerHandle)) {
503 for (
size_t idx = 0; idx < trigger.numPassed.size(); idx++) {
504 if (trigger.numPassed[idx] >= fMultiplicityThreshold) {
506 triggerIndex.push_back(idx);
513 if (fVerbose)
std::cout <<
"Number of PMT hardware triggers found: " << triggerIndex.size() << std::endl;
516 uint32_t nChannelsTotal = channelList.size();
518 uint32_t nFrag = (uint32_t)nChannelsTotal/nChannelsFrag;
522 uint32_t sequenceIDVal = fEvent;
525 sbndaq::CAENV1730FragmentMetadata metadata;
526 metadata.nChannels = nChannelsFrag + 1;
527 metadata.nSamples = wfm_length;
530 uint32_t eventCounterVal = fEvent;
531 uint32_t boardIDVal = 0;
532 uint32_t triggerTimeTagVal = (uint32_t)CLHEP::RandFlat::shoot(&fTriggerTimeEngine, 0, 1e9);
533 uint32_t eventSizeVal = ((wfm_length * (nChannelsFrag+1)) *
sizeof(uint16_t) +
sizeof(sbndaq::CAENV1730EventHeader)) /
sizeof(uint32_t);
536 for (
auto wvfIdx : triggerIndex) {
539 size_t trigIdx = wvfIdx*4;
540 size_t startIdx = trigIdx-500;
543 double triggerTime = fMinStartTime + wvfIdx*0.008;
544 double timestampVal = 0.5 + (triggerTime*1e-6);
545 metadata.timeStampSec = (uint32_t)timestampVal;
546 metadata.timeStampNSec = (uint32_t)(timestampVal*1e9);
553 const auto fragment_datasize_bytes = metadata.ExpectedDataSize();
554 uint32_t fragmentIDVal =
counter;
555 auto fragment_uptr = artdaq::Fragment::FragmentBytes(fragment_datasize_bytes, sequenceIDVal, fragmentIDVal, sbndaq::detail::FragmentType::CAENV1730, metadata);
556 fragment_uptr->setTimestamp(timestampVal);
559 auto header_ptr =
reinterpret_cast<sbndaq::CAENV1730EventHeader*
>(fragment_uptr->dataBeginBytes());
561 header_ptr->eventCounter = eventCounterVal;
562 header_ptr->boardID = boardIDVal;
563 header_ptr->triggerTimeTag = triggerTimeTagVal;
564 header_ptr->eventSize = eventSizeVal;
568 uint16_t* data_begin =
reinterpret_cast<uint16_t*
>(fragment_uptr->dataBeginBytes() +
sizeof(sbndaq::CAENV1730EventHeader));
569 uint16_t* value_ptr = data_begin;
571 size_t ch_offset = 0;
574 for (
size_t i_ch = 0; i_ch < nChannelsFrag; i_ch++) {
575 ch_offset = (size_t)(i_ch*wfm_length);
577 for (
size_t i_t = 0; i_t < wfm_length; i_t++) {
579 value = wvf_channel[
counter*nChannelsFrag + i_ch][startIdx+i_t];
580 value_ptr = data_begin + ch_offset + i_t;
586 ch_offset = (size_t)(nChannelsFrag*wfm_length);
587 size_t beamStartIdx =
abs(fMinStartTime)*1000/2;
588 size_t beamEndIdx = beamStartIdx + fBeamWindowLength*1000/2;
590 for (
size_t i_t = 0; i_t < wfm_length; i_t++) {
592 if (startIdx + i_t >= beamStartIdx && startIdx + i_t <= beamEndIdx) value = 1;
594 value_ptr = data_begin + ch_offset + i_t;
599 vecFrag->push_back(*fragment_uptr);
603 if(fVerbose)
std::cout <<
"PMT Fragments written: " << vecFrag->size() - num_crt_frags << std::endl;
607 e.put(std::move(vecFrag));
611 wvf_channel.shrink_to_fit();
uint16_t feb_hits_in_fragments[num_febs]
int fMultiplicityThreshold
bool empty_fragment[num_febs]
CLHEP::HepRandomEngine & fTriggerTimeEngine
std::vector< unsigned int > channelList
std::vector< std::vector< short > > wvf_channel
geo::GeometryCore const * fGeometryService
ArtdaqFragmentProducer(fhicl::ParameterSet const &p)
art::ServiceHandle< art::TFileService > tfs
Access the description of detector geometry.
object containing MC truth information necessary for making RawDigits and doing back tracking ...
auto counter(T begin, T end)
Returns an object to iterate values from begin to end in a range-for loop.
art::InputTag fSimModuleLabel
name of detsim producer
art framework interface to geometry description for auxiliary detectors
enum::sbnd::CRTPlane GetPlaneIndex(std::string tagger)
void fill(const art::PtrVector< recob::Hit > &hits, int only_plane)
ArtdaqFragmentProducer & operator=(ArtdaqFragmentProducer const &)=delete
Description of geometry of one entire detector.
Definition of data types for geometry description.
void produce(art::Event &e) override
std::string fInputModuleNameWvfm
uint16_t ADCs[num_febs][max_hits_in_fragment][num_channels]
std::string taggers[num_febs]
bool fVerbose
print information about what's going on
opdet::sbndPDMapAlg pdMap
std::string fInputModuleNameTrigger
size_t fFirstFEBMac5
lowest mac5 address for CRT FEBs
art::InputTag fCRTSimLabel
name of CRT producer
stream1 can override from command line with o or output services user sbnd
uint32_t T0s[num_febs][max_hits_in_fragment]
uint32_t T1s[num_febs][max_hits_in_fragment]
std::string fFEBDataLabel
name of FEBData producer
art framework interface to geometry description
BEGIN_PROLOG could also be cout