22 #include "CLHEP/Random/RandFlat.h"
23 #include "CLHEP/Random/RandGaussQ.h"
24 #include "CLHEP/Random/JamesRandom.h"
34 #include "art/Framework/Core/ModuleMacros.h"
35 #include "art/Framework/Core/EDProducer.h"
36 #include "art/Framework/Principal/Event.h"
37 #include "art/Framework/Principal/Handle.h"
38 #include "art/Framework/Services/Registry/ServiceHandle.h"
39 #include "art_root_io/TFileService.h"
40 #include "art_root_io/TFileDirectory.h"
41 #include "art/Utilities/make_tool.h"
42 #include "fhiclcpp/ParameterSet.h"
43 #include "messagefacility/MessageLogger/MessageLogger.h"
45 #include "nurandom/RandomUtils/NuRandomService.h"
63 #include "icarus_signal_processing/Filters/ICARUSFFT.h"
79 void produce (art::Event&
evt);
124 const float adcsaturation = 4095;
137 using FFTPointer = std::unique_ptr<icarus_signal_processing::ICARUSFFT<double>>;
151 , fPedestalEngine(art::ServiceHandle<rndm::NuRandomService>()->createEngine(*
this,
"HepJamesRandom",
"pedestal", pset,
"SeedPedestal"))
152 , fUncNoiseEngine(art::ServiceHandle<rndm::NuRandomService>()->createEngine(*
this,
"HepJamesRandom",
"noise", pset,
"Seed"))
153 , fCorNoiseEngine(art::ServiceHandle<rndm::NuRandomService>()->createEngine(*
this,
"HepJamesRandom",
"cornoise", pset,
"Seed"))
154 , fGeometry(*lar::providerFrom<geo::Geometry>())
155 , fChannelMap(art::ServiceHandle<icarusDB::IICARUSChannelMap const>{}.get())
159 produces< std::vector<raw::RawDigit>>(fOutInstanceLabel);
161 TString
compression(pset.get< std::string >(
"CompressionType"));
167 SimReadoutBoardICARUS::~SimReadoutBoardICARUS() {}
171 fDriftEModuleLabel = p.get< art::InputTag >(
"DriftEModuleLabel",
"largeant");
172 fOutInstanceLabel = p.get< std::string >(
"OutputInstanceLabel",
"");
173 fProcessAllTPCs = p.get<
bool >(
"ProcessAllTPCs",
false);
174 fCryostat = p.get<
unsigned int >(
"Cryostat", 0);
175 fSimDeadChannels = p.get<
bool >(
"SimDeadChannels",
false);
176 fSuppressNoSignal = p.get<
bool >(
"SuppressNoSignal",
false);
177 fMakeHistograms = p.get<
bool >(
"MakeHistograms",
false);
178 fSmearPedestals = p.get<
bool >(
"SmearPedestals",
true);
179 fNumChanPerMB = p.get<
int >(
"NumChanPerMB", 32);
180 fTest = p.get<
bool >(
"Test",
false);
181 fTestWire = p.get<
size_t >(
"TestWire", 0);
182 fTestIndex = p.get< std::vector<size_t> >(
"TestIndex", std::vector<size_t>());
183 fTestCharge = p.get< std::vector<double> >(
"TestCharge", std::vector<double>());
185 using TPCValsPair = std::pair<unsigned int, unsigned int>;
186 using TPCValsVec = std::vector<TPCValsPair>;
188 TPCValsVec tempIDVec = p.get< TPCValsVec >(
"TPCVec", TPCValsVec());
190 for(
const auto& idPair : tempIDVec)
192 fTPCVec.push_back(
geo::TPCID(idPair.first,idPair.second));
195 if(fTestIndex.size() != fTestCharge.size())
196 throw cet::exception(__FUNCTION__)<<
"# test pulse mismatched: check TestIndex and TestCharge fcl parameters...";
198 fNoiseTool = art::make_tool<icarus_tool::IGenNoise>(p.get<fhicl::ParameterSet>(
"NoiseGenTool"));
202 fShapingTimeOrder = { {0.6, 0}, {1, 1}, {1.3, 2}, {3.0, 3} };
205 auto const detProp = art::ServiceHandle<detinfo::DetectorPropertiesService const>()->DataForJob();
206 fNTimeSamples =
detProp.NumberTimeSamples();
208 fSignalShapingService = art::ServiceHandle<icarusutil::SignalShapingICARUSService>{}.get();
210 fFFT = std::make_unique<icarus_signal_processing::ICARUSFFT<double>>(fNTimeSamples);
215 void SimReadoutBoardICARUS::beginJob()
218 art::ServiceHandle<art::TFileService>
tfs;
223 if(fGeometry.Nchannels()<=fTestWire)
224 throw cet::exception(__FUNCTION__)<<
"Invalid test wire channel: "<<fTestWire;
225 std::vector<unsigned int> channels;
226 for(
auto const& plane_id : fGeometry.IteratePlaneIDs())
227 channels.push_back(fGeometry.PlaneWireToChannel(plane_id.Plane,fTestWire));
228 double xyz[3] = { std::numeric_limits<double>::max() };
229 for(
auto const& ch : channels)
232 for(
size_t i=0; i<fTestIndex.size(); ++i)
234 fTestSimChannel_v.back().AddIonizationElectrons(-1,
238 std::numeric_limits<double>::max());
243 fSimCharge = tfs->make<TH1F>(
"fSimCharge",
"simulated charge", 150, 0, 1500);
244 fSimChargeWire = tfs->make<TH2F>(
"fSimChargeWire",
"simulated charge", 5600,0.,5600.,500, 0, 1500);
249 void SimReadoutBoardICARUS::endJob()
251 void SimReadoutBoardICARUS::produce(art::Event&
evt)
265 auto const clockData = art::ServiceHandle<detinfo::DetectorClocksService const>()->DataFor(evt);
279 std::vector<const sim::SimChannel*> channels(maxChannel,
nullptr);
282 std::vector<const sim::SimChannel*> chanHandle;
283 evt.getView(fDriftEModuleLabel,chanHandle);
285 for(
const auto& simChannel : chanHandle) channels.at(simChannel->Channel()) = simChannel;
288 for(
const auto& testChannel : fTestSimChannel_v) channels.at(testChannel.Channel()) = &testChannel;
292 std::unique_ptr< std::vector<raw::RawDigit>> digcol(
new std::vector<raw::RawDigit>);
293 digcol->reserve(maxChannel);
302 std::vector<short> adcvec(fNTimeSamples, 0);
308 if (chargeWork.size() < fNTimeSamples)
throw std::range_error(
"SimReadoutBoardICARUS: chargeWork vector too small");
311 auto const detProp = art::ServiceHandle<detinfo::DetectorPropertiesService const>()->DataFor(evt);
314 fNoiseTool->nextEvent();
322 unsigned int boardCount(0);
324 std::set<raw::ChannelID_t> channelIDSet;
326 for(
const auto& boardPair : readoutBoardToChannelMap)
331 std::vector<geo::WireID> wireIDVec;
333 for(
const auto& channelPair : boardPair.second.second)
335 wireIDVec = fGeometry.ChannelToWire(channelPair.first);
337 if (wireIDVec.size() > 0)
break;
340 if (wireIDVec.empty())
continue;
342 bool goodBoard(
false);
343 unsigned int cryostat(0);
348 if (tpcid.Cryostat == wireIDVec[0].Cryostat && tpcid.TPC == wireIDVec[0].TPC)
351 cryostat = tpcid.Cryostat;
357 if (!goodBoard)
continue;
360 for(
const auto& channelPair : boardPair.second.second)
364 size_t plane = channelPair.second;
367 if (channelIDSet.find(channel) != channelIDSet.end())
369 std::cout <<
"############### Found already used channel! channelID: " << channel << std::endl;
371 channelIDSet.insert(channel);
374 adcvec.resize(fNTimeSamples, 0);
375 noisetmp.resize(fNTimeSamples, 0.);
380 float ped_mean = 2048;
382 if (fSmearPedestals )
384 CLHEP::RandGaussQ rGaussPed(fPedestalEngine, 0.0, 3.0);
385 ped_mean += rGaussPed.fire();
389 double noise_factor(0.);
390 double shapingTime = fSignalShapingService->GetShapingTime(plane);
391 auto tempNoiseVec = fSignalShapingService->GetNoiseFactVec();
393 if (fShapingTimeOrder.find( shapingTime ) != fShapingTimeOrder.end() )
394 noise_factor = tempNoiseVec[plane].at( fShapingTimeOrder.find( shapingTime )->second );
398 throw cet::exception(
"SimReadoutBoardICARUS")
400 <<
"Shaping Time received from signalservices_icarus.fcl is not one of allowed values"
402 <<
"Allowed values: 0.6, 1.0, 1.3, 3.0 usec"
408 std::vector<geo::WireID> widVec = fGeometry.ChannelToWire(channel);
418 fNoiseTool->generateNoise(fUncNoiseEngine,
430 if(simChan && !(fSimDeadChannels && (ChannelStatusProvider.
IsBad(channel) || !ChannelStatusProvider.
IsPresent(channel))))
432 double gain = fSignalShapingService->GetASICGain(channel) *
sampling_rate(clockData) * 1.e-3;
433 int timeOffset = fSignalShapingService->ResponseTOffset(channel);
438 std::fill(chargeWork.begin(), chargeWork.end(), 0.);
448 if( tdc < 0 )
continue;
450 double charge = simChan->
Charge(tdc);
452 chargeWork[
tick] += charge/gain;
456 fFFT->convolute(chargeWork, response.
getConvKernel(), timeOffset);
459 MakeADCVec(adcvec, noisetmp, chargeWork, ped_mean);
462 else MakeADCVec(adcvec, noisetmp, zeroCharge, ped_mean);
471 raw::RawDigit rd(channel, fNTimeSamples, adcvec, fCompression);
473 if(fMakeHistograms && plane==2)
475 short area = std::accumulate(adcvec.begin(),adcvec.end(),0,[](
const auto& val,
const auto& sum){
return sum + val - 400;});
479 std::vector<geo::WireID> widVec = fGeometry.ChannelToWire(channel);
481 fSimCharge->Fill(area);
482 fSimChargeWire->Fill(widVec[0].Wire,area);
487 digcol->push_back(std::move(rd));
492 evt.put(std::move(digcol), fOutInstanceLabel);
500 for(
unsigned int i = 0; i < fNTimeSamples; ++i)
502 float adcval = noisevec[i] + chargevec[i] + ped_mean;
504 adcval = std::max(
float(0.), std::min(adcval, adcsaturation));
506 adcvec[i] = std::round(adcval);
CLHEP::HepRandomEngine & fCorNoiseEngine
TString compression(pset.get< std::string >("CompressionType"))
TPCIDVec fTPCVec
List of TPCs to process for this instance of the module.
enum raw::_compress Compress_t
bool fSimDeadChannels
if True, simulate dead channels using the ChannelStatus service. If false, do not simulate dead chann...
Collection of charge vs time digitized from a single readout channel.
std::vector< geo::TPCID > TPCIDVec
int fNumChanPerMB
Number of channels per motherboard.
std::vector< double > fTestCharge
Energy deposited on a readout channel by simulated tracks.
ResponseParams(double charge, size_t time)
virtual bool IsBad(raw::ChannelID_t channel) const =0
Returns whether the specified channel is bad in the current run.
std::unique_ptr< icarus_signal_processing::ICARUSFFT< double >> FFTPointer
The data type to uniquely identify a Plane.
Definition of basic raw digits.
bool fSmearPedestals
If True then we smear the pedestals.
bool fSuppressNoSignal
If no signal on wire (simchannel) then suppress the channel.
std::string fOutInstanceLabel
The label to apply to the output data product.
bool fProcessAllTPCs
If true we process all TPCs.
Access the description of detector geometry.
virtual bool IsPresent(raw::ChannelID_t channel) const =0
Returns whether the specified channel is physical and connected to wire.
const geo::GeometryCore & fGeometry
std::vector< size_t > fTestIndex
double Charge(TDC_t tdc) const
Returns the total number of ionization electrons on this channel in the specified TDC...
art::InputTag fDriftEModuleLabel
module making the ionization electrons
const icarusDB::IICARUSChannelMap * fChannelMap
Collect all the RawData header files together.
std::vector< SigProcPrecision > TimeVec
tick_as<> tick
Tick number, represented by std::ptrdiff_t.
icarusutil::SignalShapingICARUSService * fSignalShapingService
std::map< double, int > fShapingTimeOrder
void fill(const art::PtrVector< recob::Hit > &hits, int only_plane)
Class providing information about the quality of channels.
unsigned int fCryostat
If ProcessAllTPCs is false then cryostat to use.
The data type to uniquely identify a TPC.
Description of geometry of one entire detector.
CLHEP::HepRandomEngine & fUncNoiseEngine
void SetPedestal(float ped, float sigma=1.)
Set pedestal and its RMS (the latter is 0 by default)
std::map< unsigned int, SlotChannelVecPair > TPCReadoutBoardToChannelMap
object containing MC truth information necessary for making RawDigits and doing back tracking ...
Interface for experiment-specific channel quality info provider.
std::vector< sim::SimChannel > fTestSimChannel_v
void Compress(std::vector< short > &adc, raw::Compress_t compress)
Compresses a raw data buffer.
This is the interface class for a tool to handle a GenNoise for the overall response.
art::ServiceHandle< art::TFileService > tfs
raw::Compress_t fCompression
compression type to use
unsigned int ChannelID_t
Type representing the ID of a readout channel.
Interface for experiment-specific service for channel quality info.
double sampling_rate(DetectorClocksData const &data)
Returns the period of the TPC readout electronics clock.
Tools and modules for checking out the basics of the Monte Carlo.
unsigned int fNTimeSamples
number of ADC readout samples in all readout frames (per event)
CLHEP::HepRandomEngine & fPedestalEngine
art framework interface to geometry description
BEGIN_PROLOG could also be cout
std::unique_ptr< icarus_tool::IGenNoise > fNoiseTool
Tool for generating noise.