SimWireDUNE35t_module.cc
Go to the documentation of this file.
1 ////////////////////////////////////////////////////////////////////////
2 //
3 // SimWireDUNE35t class designed to simulate signal on a wire in the TPC
4 //
5 //
6 // jti3@fnal.gov
7 // - Revised to use sim::RawDigit instead of rawdata::RawDigit, and to
8 // - save the electron clusters associated with each digit.
9 //
10 ////////////////////////////////////////////////////////////////////////
11 
12 #include <vector>
13 #include <string>
14 #include <algorithm>
15 #include <sstream>
16 #include <bitset>
17 
18 extern "C" {
19 #include <sys/types.h>
20 #include <sys/stat.h>
21 }
22 
28 #include "art_root_io/TFileService.h"
29 #include "art_root_io/TFileDirectory.h"
30 #include "fhiclcpp/ParameterSet.h"
32 
33 // art extensions
34 #include "nurandom/RandomUtils/NuRandomService.h"
35 
37 #include "lardataobj/RawData/raw.h"
41 
46 
47 #include "TMath.h"
48 #include "TComplex.h"
49 #include "TString.h"
50 #include "TH2.h"
51 #include "TH1D.h"
52 #include "TFile.h"
53 #include "TProfile.h"
54 
55 #include "CLHEP/Random/RandFlat.h"
56 #include "CLHEP/Random/RandGaussQ.h"
57 
58 ///Detector simulation of raw signals on wires
59 namespace detsim {
60 
61  // tye used for passing messages for simulating gaps
62 
63  typedef enum {
65  } GapType_t;
66 
67 
68  // Base class for creation of raw signals on wires.
70 
71  public:
72 
73  explicit SimWireDUNE35t(fhicl::ParameterSet const& pset);
74 
75  // read/write access to event
76  void produce (art::Event& evt);
77  void beginJob();
78  void endJob();
79  void reconfigure(fhicl::ParameterSet const& p);
80 
81  private:
82 
83  void GenNoise(std::vector<float>& array);
84 
85  std::string fDriftEModuleLabel;///< module making the ionization electrons
86  raw::Compress_t fCompression; ///< compression type to use
87  unsigned int fNoiseOn; ///< noise turned on or off for debugging; default is on
88  unsigned int fNoiseModel; ///< noise model>
89  float fNoiseFact; ///< noise scale factor
90  float fNoiseWidth; ///< exponential noise width (kHz)
91  float fLowCutoff; ///< low frequency filter cutoff (kHz)
92  float fNoiseFactZ; ///< noise scale factor for Z (collection) plane
93  float fNoiseWidthZ; ///< exponential noise width (kHz) for Z (collection) plane
94  float fLowCutoffZ; ///< low frequency filter cutoff (kHz) for Z (collection) plane
95  float fNoiseFactU; ///< noise scale factor for U plane
96  float fNoiseWidthU; ///< exponential noise width (kHz) for U plane
97  float fLowCutoffU; ///< low frequency filter cutoff (kHz) for U plane
98  float fNoiseFactV; ///< noise scale factor for V plane
99  float fNoiseWidthV; ///< exponential noise width (kHz) for V plane
100  float fLowCutoffV; ///< low frequency filter cutoff (kHz) for V plane
101  unsigned int fZeroThreshold; ///< Zero suppression threshold
102  int fNearestNeighbor; ///< Maximum distance between hits above threshold before they are separated into different blocks
103  unsigned int fNeighboringChannels; ///< Number of neighboring channels on either side allowed to influence zero suppression
104  int fNTicks; ///< number of ticks of the clock
105  double fSampleRate; ///< sampling rate in ns
106  unsigned int fNSamplesReadout; ///< number of ADC readout samples in 1 readout frame
107  unsigned int fNTimeSamples; ///< number of ADC readout samples in all readout frames (per event)
108  unsigned int fNoiseArrayPoints; ///< number of points in randomly generated noise array
109 
110  std::vector<double> fChargeWork;
111  //std::vector< std::vector<float> > fNoise;///< noise on each channel for each time
112  std::vector< std::vector<float> > fNoiseZ;///< noise on each channel for each time for Z (collection) plane
113  std::vector< std::vector<float> > fNoiseU;///< noise on each channel for each time for U plane
114  std::vector< std::vector<float> > fNoiseV;///< noise on each channel for each time for V plane
115 
116  TH1D* fNoiseDist; ///< distribution of noise counts
117 
118 
119  // variables for simulating the charge deposition in gaps and charge drifting over the comb materials.
120 
122 
123  // variables for finding the first and last channel numbers on each plane
124 
125  std::vector< uint32_t > fFirstChannelsInPlane;
126  std::vector< uint32_t > fLastChannelsInPlane;
127 
128  //define max ADC value - if one wishes this can
129  //be made a fcl parameter but not likely to ever change
130  const float adcsaturation = 4095;
131  float fCollectionPed; ///< ADC value of baseline for collection plane
132  float fCollectionPedRMS; ///< ADC value of baseline RMS for collection plane
133  float fInductionPed; ///< ADC value of baseline for induction plane
134  float fInductionPedRMS; ///< ADC value of baseline RMS for induction plane
135  float fCollectionCalibPed; ///< Assumed measured value for coll plane pedestal
136  float fCollectionCalibPedRMS; ///< Assumed measured value for coll plane pedestal RMS
137  float fInductionCalibPed; ///< Assumed measured value for ind plane pedestal
138  float fInductionCalibPedRMS; ///< Assumed measured value for ind plane pedestal RMS
139  bool fPedestalOn; ///< switch for simulation of nonzero pedestals
140 
141  // input fcl parameters
142 
143  bool fSimCombs; ///< switch for simulation of the combs
144  bool fSimStuckBits; ///< switch for simulation of stuck bits
145 
146  std::string fStuckBitsProbabilitiesFname; ///< file holding ADC stuck code overflow and underflow probabilities
147  std::string fStuckBitsOverflowProbHistoName; ///< Name of histogram holding ADC stuck code overflow probabilities
148  std::string fStuckBitsUnderflowProbHistoName; ///< Name of histogram holding ADC stuck code underflow probabilities
149 
150  bool fSaveEmptyChannel; // switch for saving channels with all zero entries
151  std::vector<float> fFractUUCollect; // fraction of charge that collects on U (non-transparency) when charge drifts over the comb holding U wires
152  std::vector<float> fFractUVCollect; // fraction of charge that collects on U (non-transparency) when charge drifts over the comb holding V wires
153  std::vector<float> fFractVUCollect; // fraction of charge that collects on V (non-transparency) when charge drifts over the comb holding U wires
154  std::vector<float> fFractVVCollect; // fraction of charge that collects on V (non-transparency) when charge drifts over the comb holding V wires
155  std::vector<float> fFractUUMiss; // fraction of charge that gets missed on U when charge drifts over the comb holding U
156  std::vector<float> fFractUVMiss; // fraction of charge that gets missed on U when charge drifts over the comb holding V
157  std::vector<float> fFractVUMiss; // fraction of charge that gets missed on V when charge drifts over the comb holding U
158  std::vector<float> fFractVVMiss; // fraction of charge that gets missed on V when charge drifts over the comb holding V
159  std::vector<float> fFractZUMiss; // fraction of charge that gets missed on Z (collection) when charge drifts over the comb holding U
160  std::vector<float> fFractZVMiss; // fraction of charge that gets missed on Z (collection) when charge drifts over the comb holding V
161  std::vector<float> fFractHorizGapUMiss; // fraction of charge in the horizontal gap that is missing on U (and not collected)
162  std::vector<float> fFractVertGapUMiss; // fraction of charge in the horizontal gaps that is missing on U
163  std::vector<float> fFractHorizGapVMiss; // fraction of charge in the horizontal gap that is missing on V
164  std::vector<float> fFractVertGapVMiss; // fraction of charge in the horizontal gaps that is missing on V
165  std::vector<float> fFractHorizGapZMiss; // fraction of charge in the horizontal gap that is missing on Z (collection)
166  std::vector<float> fFractVertGapZMiss; // fraction of charge in the horizontal gaps that is missing on Z (collection
167  std::vector<float> fFractHorizGapUCollect; // fraction of charge in the horizontal gap that collects on U
168  std::vector<float> fFractVertGapUCollect; // fraction of charge in the horizontal gaps that collects on U
169  std::vector<float> fFractHorizGapVCollect; // fraction of charge in the horizontal gap that collects on V
170  std::vector<float> fFractVertGapVCollect; // fraction of charge in the horizontal gaps that collects on V
171 
172  // boundaries of the combs -- cached here for speed
173 
180 
181  GapType_t combtest35t(double x, double y, double z);
182  int GapHasDeflector(double x, double y, double z);
183 
184  double fOverflowProbs[64]; ///< array of probabilities of 6 LSF bits getting stuck at 000000
185  double fUnderflowProbs[64]; ///< array of probabilities of 6 LSF bits getting stuck at 111111
186  CLHEP::HepRandomEngine& fEngine;
187 
188  }; // class SimWireDUNE35t
189 
190  //-------------------------------------------------
192  : EDProducer{pset}
193  // create a default random engine; obtain the random seed from NuRandomService,
194  // unless overridden in configuration with key "Seed"
196  {
197 
198  this->reconfigure(pset);
199 
200  produces< std::vector<raw::RawDigit> >();
201 
203  TString compression(pset.get< std::string >("CompressionType"));
204  if(compression.Contains("Huffman",TString::kIgnoreCase)) fCompression = raw::kHuffman;
205  if(compression.Contains("ZeroSuppression",TString::kIgnoreCase)) fCompression = raw::kZeroSuppression;
206 
207  }
208 
209  //-------------------------------------------------
211  {
212  fDriftEModuleLabel= p.get< std::string >("DriftEModuleLabel");
213 
214 
215  fNoiseFactZ = p.get< double >("NoiseFactZ");
216  fNoiseWidthZ = p.get< double >("NoiseWidthZ");
217  fLowCutoffZ = p.get< double >("LowCutoffZ");
218  fNoiseFactU = p.get< double >("NoiseFactU");
219  fNoiseWidthU = p.get< double >("NoiseWidthU");
220  fLowCutoffU = p.get< double >("LowCutoffU");
221  fNoiseFactV = p.get< double >("NoiseFactV");
222  fNoiseWidthV = p.get< double >("NoiseWidthV");
223  fLowCutoffV = p.get< double >("LowCutoffV");
224  fZeroThreshold = p.get< unsigned int >("ZeroThreshold");
225  fNearestNeighbor = p.get< int >("NearestNeighbor");
226  fNeighboringChannels = p.get< unsigned int >("NeighboringChannels");
227  fNoiseArrayPoints = p.get< unsigned int >("NoiseArrayPoints");
228  fNoiseOn = p.get< unsigned int >("NoiseOn");
229  fNoiseModel = p.get< unsigned int >("NoiseModel");
230  fCollectionPed = p.get< float >("CollectionPed");
231  fCollectionPedRMS = p.get< float >("CollectionPedRMS");
232  fInductionPed = p.get< float >("InductionPed");
233  fInductionPedRMS = p.get< float >("InductionPedRMS");
234  fCollectionCalibPed = p.get< float >("CollectionCalibPed");
235  fCollectionCalibPedRMS = p.get< float >("CollectionCalibPedRMS");
236  fInductionCalibPed = p.get< float >("InductionCalibPed");
237  fInductionCalibPedRMS = p.get< float >("InductionCalibPedRMS");
238  fPedestalOn = p.get< bool >("PedestalOn");
239  auto const clockData = art::ServiceHandle<detinfo::DetectorClocksService const>()->DataForJob();
240  auto const detProp = art::ServiceHandle<detinfo::DetectorPropertiesService const>()->DataForJob(clockData);
241  fSampleRate = sampling_rate(clockData);
242  fNSamplesReadout = detProp.ReadOutWindowSize();
243  fNTimeSamples = detProp.NumberTimeSamples();
244 
245  fSimCombs = p.get< bool >("SimCombs");
246  fSimStuckBits = p.get< bool >("SimStuckBits");
247 
248  fStuckBitsProbabilitiesFname = p.get< std::string >("StuckBitsProbabilitiesFname");
249  fStuckBitsOverflowProbHistoName = p.get< std::string >("StuckBitsOverflowProbHistoName");
250  fStuckBitsUnderflowProbHistoName = p.get< std::string >("StuckBitsUnderflowProbHistoName");
251 
252  fSaveEmptyChannel = p.get< bool >("SaveEmptyChannel");
253  fFractUUCollect = p.get< std::vector<float> >("FractUUCollect");
254  fFractUVCollect = p.get< std::vector<float> >("FractUVCollect");
255  fFractVUCollect = p.get< std::vector<float> >("FractVUCollect");
256  fFractVVCollect = p.get< std::vector<float> >("FractVVCollect");
257  fFractUUMiss = p.get< std::vector<float> >("FractUUMiss");
258  fFractUVMiss = p.get< std::vector<float> >("FractUVMiss");
259  fFractVUMiss = p.get< std::vector<float> >("FractVUMiss");
260  fFractVVMiss = p.get< std::vector<float> >("FractVVMiss");
261  fFractZUMiss = p.get< std::vector<float> >("FractZUMiss");
262  fFractZVMiss = p.get< std::vector<float> >("FractZVMiss");
263  fFractHorizGapUMiss = p.get< std::vector<float> >("FractHorizGapUMiss");
264  fFractVertGapUMiss = p.get< std::vector<float> >("FractVertGapUMiss");
265  fFractHorizGapVMiss = p.get< std::vector<float> >("FractHorizGapVMiss");
266  fFractVertGapVMiss = p.get< std::vector<float> >("FractVertGapVMiss");
267  fFractHorizGapZMiss = p.get< std::vector<float> >("FractHorizGapZMiss");
268  fFractVertGapZMiss = p.get< std::vector<float> >("FractVertGapZMiss");
269  fFractHorizGapUCollect = p.get< std::vector<float> >("FractHorizGapUCollect");
270  fFractVertGapUCollect = p.get< std::vector<float> >("FractVertGapUCollect");
271  fFractHorizGapVCollect = p.get< std::vector<float> >("FractHorizGapVCollect");
272  fFractVertGapVCollect = p.get< std::vector<float> >("FractVertGapVCollect");
273 
274  return;
275  }
276 
277  //-------------------------------------------------
279  {
280 
281  // get access to the TFile service
283 
284  fNoiseDist = tfs->make<TH1D>("Noise", ";Noise (ADC);", 1000, -10., 10.);
285 
286 
288  fNTicks = fFFT->FFTSize();
289 
290  if ( fNTicks%2 != 0 )
291  MF_LOG_DEBUG("SimWireDUNE35t") << "Warning: FFTSize not a power of 2. "
292  << "May cause issues in (de)convolution.\n";
293 
294  if ( (int)fNSamplesReadout > fNTicks )
295  mf::LogError("SimWireDUNE35t") << "Cannot have number of readout samples "
296  << "greater than FFTSize!";
297 
298  fChargeWork.resize(fNTicks, 0.);
300 
301  bool foundfirstcollectionchannel = false;
302  fFirstChannelsInPlane.push_back(0);
303  unsigned int currentPlaneNumber = geo->ChannelToWire(0).at(0).Plane; // ID of current wire plane
304  unsigned int currentTPCNumber = geo->ChannelToWire(0).at(0).TPC; // ID of current wire plane
305 
306  for (uint32_t ichan=0;ichan<geo->Nchannels();ichan++)
307  {
308 
309  if(!foundfirstcollectionchannel)
310  {
311  const geo::View_t view = geo->View(ichan);
312  if (view == geo::kZ)
313  {
314  foundfirstcollectionchannel = true;
315  fFirstCollectionChannel = ichan;
316  //break;
317  }
318  }
319 
320  const unsigned int thisPlaneNumber = geo->ChannelToWire(ichan).at(0).Plane;
321  const unsigned int thisTPCNumber = geo->ChannelToWire(ichan).at(0).TPC;
322 
323  if(thisPlaneNumber != currentPlaneNumber || (thisPlaneNumber == geo::kZ && thisTPCNumber != currentTPCNumber))
324  {
325  fLastChannelsInPlane.push_back(ichan-1);
326  fFirstChannelsInPlane.push_back(ichan);
327  currentPlaneNumber = thisPlaneNumber;
328  currentTPCNumber = thisTPCNumber;
329  }
330 
331  }
332  if (!foundfirstcollectionchannel)
333  {
334  throw cet::exception("SimWireDUNE35t BeginJob") << " Could not find any collection channels\n";
335  }
336 
337  fLastChannelsInPlane.push_back(geo->Nchannels()-1);
338 
339 
340  // //Check starting and ending channels for each wire plane
341  // for(size_t ip = 0; ip < fFirstChannelsInPlane.size(); ++ip){
342  // std::cout << "First channel in plane " << ip << " is " << fFirstChannelsInPlane.at(ip) << std::endl;
343  // }
344 
345  // for(size_t ip = 0; ip < fLastChannelsInPlane.size(); ++ip){
346  // std::cout << "Last channel in plane " << ip << " is " << fLastChannelsInPlane.at(ip) << std::endl;
347  // }
348 
349  //Generate noise if selected to be on
350  if(fNoiseOn && fNoiseModel==1){
351 
352  //fNoise.resize(geo->Nchannels());
353  fNoiseZ.resize(fNoiseArrayPoints);
354  fNoiseU.resize(fNoiseArrayPoints);
355  fNoiseV.resize(fNoiseArrayPoints);
356 
357  // GenNoise() will further resize each channel's
358  // fNoise vector to fNoiseArrayPoints long.
359 
360  for(unsigned int p = 0; p < fNoiseArrayPoints; ++p){
361 
365 
366  GenNoise(fNoiseZ[p]);
367  for(int i = 0; i < fNTicks; ++i)
368  fNoiseDist->Fill(fNoiseZ[p][i]);
369 
373 
374  GenNoise(fNoiseU[p]);
375  for(int i = 0; i < fNTicks; ++i)
376  fNoiseDist->Fill(fNoiseU[p][i]);
377 
378 
382 
383 
384  GenNoise(fNoiseV[p]);
385  for(int i = 0; i < fNTicks; ++i)
386  fNoiseDist->Fill(fNoiseV[p][i]);
387 
388  }// end loop over wires
389  }
390 
391  // initialize the comb test positions. This is clumsy here mainly due to the irregular geometry
392  // should write something more systematic for the FD. There is also some duplication as the
393  // vertical positions of APA's 0 and 3 are assumed to be the same. Could think about either adding
394  // an exception if they're not, or defining more y positions to hold different APA positions if we want
395  // them to be different at a later time. Simulation may always be perfect though.
396 
397  // WireEndPoints takes cryostat, tpc, plane, wire, as ints and returns endpoints
398  //geo->WireEndPoints(c,t,p,w,xyzbeg,xyzend);
399 
400  // wire endpoints are at the places where the wire hits the comb that supports it. Bits of
401  // wire running over the comb are beyond the endpoints. So we need to extrapolate.
402 
403  double xyzbeg[3],xyzend[3];
404  int lastwire = 0;
405 
406  // Numbers in comments are from Geometry V3 for debugging purposes.
407 
408  // APA 0
409 
410  geo->WireEndPoints(0,0,0,0,xyzbeg,xyzend); // first U wire in TPC 0.
411  zcomb2 = xyzbeg[2]; // 0.0
412  ycomb5 = xyzend[1]; // 113.142
413 
414  lastwire = geo->Nwires(0,0,0)-1; // 358 in v3
415  geo->WireEndPoints(0,0,0,lastwire,xyzbeg,xyzend); // last U wire in TPC 0.
416  zcomb5 = xyzend[2]; // 50.8929
417  ycomb2 = xyzbeg[1]; // -82.9389
418 
419  geo->WireEndPoints(0,0,1,0,xyzbeg,xyzend); // first V wire in TPC 0.
420  zcomb4 = xyzend[2]; // 50.5774
421  ycomb4 = xyzbeg[1]; // 113.142
422 
423  lastwire = geo->Nwires(1,0,0)-1; // 344 in v3
424  geo->WireEndPoints(0,0,1,lastwire,xyzbeg,xyzend); // last V wire in TPC 0.
425  zcomb3 = xyzbeg[2]; // 0.3155
426  ycomb3 = xyzend[1]; // -82.6234
427 
428  // the collection wires appear to end where they meet their comb.
429  //geo->WireEndPoints(0,0,2,0,xyzbeg,xyzend); // first collection wire in TPC 0
430  //ycomb3 = xyzbeg[2]; // -82.308
431  //ycomb4 = xyzend[2]; // 113.142
432 
433  // need to get zcomb1, zcomb6, ycomb1, and ycomb6 -- extrapolate
434 
435  zcomb1 = zcomb2 - (zcomb3 - zcomb2);
436  zcomb6 = zcomb5 + (zcomb5 - zcomb4);
437  ycomb1 = ycomb2 - (ycomb3 - ycomb2);
438  ycomb6 = ycomb5 + (ycomb5 - ycomb4);
439 
440 
441  // APA 1
442 
443  geo->WireEndPoints(0,2,0,0,xyzbeg,xyzend); // first U wire in TPC 2.
444  zcomb11 = xyzend[2]; // 102.817
445  ycomb8 = xyzbeg[1]; // -85.221
446 
447  lastwire = geo->Nwires(0,2,0)-1; // 194 in v3
448  geo->WireEndPoints(0,2,0,lastwire,xyzbeg,xyzend); // last U wire in TPC 2.
449  zcomb8 = xyzbeg[2]; // 51.924
450  ycomb11 = xyzend[1]; // -0.831
451 
452  geo->WireEndPoints(0,2,1,0,xyzbeg,xyzend); // first V wire in TPC 2.
453  zcomb9 = xyzbeg[2]; // 52.2395
454  ycomb9 = xyzend[1]; // -85.222
455 
456  lastwire = geo->Nwires(1,2,0)-1; // 188 in v3
457  geo->WireEndPoints(0,2,1,lastwire,xyzbeg,xyzend); // last V wire in TPC 2.
458  zcomb10 = xyzend[2]; // 102.501
459  ycomb10 = xyzbeg[1]; // -1.14655
460 
461  //geo->WireEndPoints(0,2,2,0,xyzbeg,xyzend); // first collection wire in TPC 2
462  //ycombx = xyzbeg[2]; // -85.222 edges of the combs
463  //ycombx = xyzend[2]; // -1.46205
464 
465  // need to get zcomb7, zcomb12, ycomb7, and ycomb12 -- extrapolate
466 
467  zcomb7 = zcomb8 - (zcomb9 - zcomb8);
468  zcomb12 = zcomb11 + (zcomb11 - zcomb10);
469  ycomb7 = ycomb8 - (ycomb9 - ycomb8);
470  ycomb12 = ycomb11 + (ycomb11 - ycomb10);
471 
472  // APA 2
473 
474  geo->WireEndPoints(0,4,0,0,xyzbeg,xyzend); // first U wire in TPC 4.
475  zcomb8 = xyzbeg[2]; // 51.924 -- same as above
476  ycomb17 = xyzend[1]; // 113.142 -- same as above
477 
478  lastwire = geo->Nwires(0,4,0)-1; // 235 in v3
479  geo->WireEndPoints(0,4,0,lastwire,xyzbeg,xyzend); // last U wire in TPC 4.
480  zcomb11 = xyzend[2]; // 102.817 -- same as above
481  ycomb14 = xyzbeg[1]; // 0.83105
482 
483  geo->WireEndPoints(0,4,1,0,xyzbeg,xyzend); // first V wire in TPC 4.
484  zcomb10 = xyzend[2]; // 102.501 -- same as above
485  ycomb16 = xyzbeg[1]; // 113.142 -- everything ends here in y
486 
487  lastwire = geo->Nwires(1,4,0)-1; // 227 in v3
488  geo->WireEndPoints(0,4,1,lastwire,xyzbeg,xyzend); // last V wire in TPC 4.
489  zcomb9 = xyzbeg[2]; // 52.2395 -- same as above
490  ycomb15 = xyzend[1]; // 1.14655
491 
492  //geo->WireEndPoints(0,4,2,0,xyzbeg,xyzend); // first collection wire in TPC 1
493  //ycombx = xyzbeg[2]; // 52.2234 edges of the combs -- not what we want
494  //ycombx = xyzend[2]; // 113.142 for this
495 
496  // need to get zcomb7, zcomb12, ycomb13, and ycomb18 -- extrapolate
497  // the z's are just recalculations of the numbers above
498 
499  zcomb7 = zcomb8 - (zcomb9 - zcomb8);
500  zcomb12 = zcomb11 + (zcomb11 - zcomb10);
501  ycomb13 = ycomb14 - (ycomb15 - ycomb14);
502  ycomb18 = ycomb17 + (ycomb17 - ycomb16);
503 
504  // APA 3 -- a lot like APA 0
505 
506  geo->WireEndPoints(0,6,0,0,xyzbeg,xyzend); // first U wire in TPC 6.
507  zcomb14 = xyzbeg[2]; // 103.84
508  ycomb5 = xyzend[1]; // 113.142 -- same as above
509 
510  lastwire = geo->Nwires(0,6,0)-1; // 358 in v3
511  geo->WireEndPoints(0,6,0,lastwire,xyzbeg,xyzend); // last U wire in TPC 6.
512  zcomb17 = xyzend[2]; // 154.741
513  ycomb2 = xyzbeg[1]; // -82.9389 -- same as above
514 
515  geo->WireEndPoints(0,6,1,0,xyzbeg,xyzend); // first V wire in TPC 6.
516  zcomb16 = xyzend[2]; // 154.425
517  ycomb4 = xyzbeg[1]; // 113.142 -- same as above
518 
519  lastwire = geo->Nwires(1,6,0)-1; // 344 in v3
520  geo->WireEndPoints(0,6,1,lastwire,xyzbeg,xyzend); // last V wire in TPC 6.
521  zcomb15 = xyzbeg[2]; // 104.164
522  ycomb3 = xyzend[1]; // -82.6234 -- same as above
523 
524  // the collection wires appear to end where they meet their comb.
525  //geo->WireEndPoints(0,6,2,0,xyzbeg,xyzend); // first collection wire in TPC 0
526  //ycomb3 = xyzbeg[2]; // -82.308
527  //ycomb4 = xyzend[2]; // 113.142
528 
529  // need to get zcomb13, zcomb18, ycomb1, and ycomb6 -- extrapolate
530  // the ycomb1 and ycomb6 are just copies.
531 
532  zcomb13 = zcomb14 - (zcomb15 - zcomb14);
533  zcomb18 = zcomb17 + (zcomb17 - zcomb16);
534  ycomb1 = ycomb2 - (ycomb3 - ycomb2);
535  ycomb6 = ycomb5 + (ycomb5 - ycomb4);
536 
537  if(fSimStuckBits){
538 
539  mf::LogInfo("SimWireDUNE35t") << " using ADC stuck code probabilities from .root file " ;
540 
541  // constructor decides if initialized value is a path or an environment variable
543  cet::search_path sp("FW_SEARCH_PATH");
545 
546  std::unique_ptr<TFile> fin(new TFile(fname.c_str(), "READ"));
547  if ( !fin->IsOpen() ) throw art::Exception( art::errors::NotFound ) << "Could not find the ADC stuck code probabilities file " << fname << "!" << std::endl;
548 
549  TString iOverflowHistoName = Form( "%s", fStuckBitsOverflowProbHistoName.c_str());
550  TProfile *overflowtemp = (TProfile*) fin->Get( iOverflowHistoName );
551  if ( !overflowtemp ) throw art::Exception( art::errors::NotFound ) << "Could not find the ADC code overflow probabilities histogram " << fStuckBitsOverflowProbHistoName << "!" << std::endl;
552 
553  if ( overflowtemp->GetNbinsX() != 64 ) throw art::Exception( art::errors::InvalidNumber ) << "Overflow ADC stuck code probability histograms should always have 64 bins corresponding to each of 64 LSB cells!" << std::endl;
554 
555  TString iUnderflowHistoName = Form( "%s", fStuckBitsUnderflowProbHistoName.c_str());
556  TProfile *underflowtemp = (TProfile*) fin->Get( iUnderflowHistoName );
557  if ( !underflowtemp ) throw art::Exception( art::errors::NotFound ) << "Could not find the ADC code underflow probabilities histogram " << fStuckBitsUnderflowProbHistoName << "!" << std::endl;
558 
559  if ( underflowtemp->GetNbinsX() != 64 ) throw art::Exception( art::errors::InvalidNumber ) << "Underflow ADC stuck code probability histograms should always have 64 bins corresponding to each of 64 LSB cells!" << std::endl;
560 
561 
562  for(unsigned int cellnumber=0; cellnumber < 64; ++cellnumber){
563  fOverflowProbs[cellnumber] = overflowtemp->GetBinContent(cellnumber+1);
564  fUnderflowProbs[cellnumber] = underflowtemp->GetBinContent(cellnumber+1);
565  }
566 
567  fin->Close();
568  }
569  return;
570 
571  }
572 
573  //-------------------------------------------------
575  {
576  }
577 
578  //-------------------------------------------------
580  {
581  // get the geometry to be able to figure out signal types and chan -> plane mappings
583  unsigned int signalSize = fNTicks;
584 
585  // vectors for working
586  std::vector<short> adcvec(signalSize, 0);
587  std::vector<const sim::SimChannel*> chanHandle;
588  evt.getView(fDriftEModuleLabel,chanHandle);
589 
590  //Get fIndShape and fColShape from SignalShapingService, on the fly
592 
593  // make a vector of const sim::SimChannel* that has same number
594  // of entries as the number of channels in the detector
595  // and set the entries for the channels that have signal on them
596  // using the chanHandle
597  std::vector<const sim::SimChannel*> channels(geo->Nchannels());
598  for(size_t c = 0; c < chanHandle.size(); ++c){
599  channels[chanHandle[c]->Channel()] = chanHandle[c];
600  }
601 
602  // make an unique_ptr of sim::SimDigits that allows ownership of the produced
603  // digits to be transferred to the art::Event after the put statement below
604  std::unique_ptr< std::vector<raw::RawDigit> > digcol(new std::vector<raw::RawDigit>);
605 
606  unsigned int chan = 0;
607  fChargeWork.clear();
608  fChargeWork.resize(fNTicks, 0.);
609 
610 
611  std::vector<double> fChargeWorkCollInd;
612 
614 
615  // Add all channels
616  CLHEP::RandFlat flat(fEngine);
617 
619 
620 
621  // make ring buffer to hold neighboring channels in order to enable nearest neighbor-influenced zero suppression
622 
623  boost::circular_buffer<std::vector<short>> adcvec_neighbors(fNeighboringChannels*2+1);
624 
625  // make vector of adc vectors to hold first channels in induction plane in order to wrap around to the start for nearest neighbor-influenced zero suppression
626 
627  std::vector<std::vector<short>> adcvec_inductionplanestart;
628 
629  unsigned int plane_number = 0;
630 
631  int dflag = 0;
632 
633  auto const clockData = art::ServiceHandle<detinfo::DetectorClocksService const>()->DataFor(evt);
634 
635  for(chan = 0; chan < geo->Nchannels(); chan++) {
636 
637 
638  fChargeWork.clear();
639  // fChargeWork.resize(fNTicks, 0.);
640  fChargeWork.resize(fNTimeSamples, 0.);
641  if (fSimCombs)
642  {
643  fChargeWorkCollInd.clear();
644  fChargeWorkCollInd.resize(fNTimeSamples, 0.);
645  }
646 
647  // get the sim::SimChannel for this channel
648  const sim::SimChannel* sc = channels[chan];
649  const geo::View_t view = geo->View(chan);
650 
651 
652  if( sc ){
653  // loop over the tdcs and grab the number of electrons for each
654  for(size_t t = 0; t < fChargeWork.size(); ++t)
655  if (fSimCombs)
656  {
657  const std::vector<sim::IDE> ides = sc->TrackIDsAndEnergies(t,t);
658  for (auto const &ide : ides)
659  {
660  GapType_t gaptype = combtest35t(ide.x,ide.y,ide.z);
661  switch (gaptype)
662  {
663  case ACTIVE:
664  {
665  fChargeWork[t] += ide.numElectrons;
666  break;
667  }
668  case UCOMB:
669  {
670  dflag = GapHasDeflector(ide.x,ide.y,ide.z);
671  switch (view)
672  {
673  case geo::kU:
674  {
675  fChargeWork[t] += ide.numElectrons * (1.0 - fFractUUCollect[dflag] - fFractUUMiss[dflag]);
676  fChargeWorkCollInd[t] += ide.numElectrons * fFractUUCollect[dflag];
677  break;
678  }
679  case geo::kV:
680  {
681  fChargeWork[t] += ide.numElectrons * (1.0 - fFractVUCollect[dflag] - fFractUUCollect[dflag] - fFractVUMiss[dflag]);
682  fChargeWorkCollInd[t] += ide.numElectrons * fFractVUCollect[dflag];
683  break;
684  }
685  case geo::kZ:
686  {
687  fChargeWork[t] += ide.numElectrons * (1.0-fFractVUCollect[dflag]-fFractUUCollect[dflag]-fFractZUMiss[dflag]);
688  break;
689  }
690  default:
691  {
692  throw cet::exception("SimWireDUNE35t") << "ILLEGAL VIEW Type: " << view <<"\n";
693  }
694  }
695  break;
696  }
697  case VCOMB:
698  {
699  dflag = GapHasDeflector(ide.x,ide.y,ide.z);
700  switch (view)
701  {
702  case geo::kU:
703  {
704  fChargeWork[t] += ide.numElectrons * (1.0 - fFractUVCollect[dflag] - fFractUVMiss[dflag]);
705  fChargeWorkCollInd[t] += ide.numElectrons * fFractUVCollect[dflag];
706  break;
707  }
708  case geo::kV:
709  {
710  fChargeWork[t] += ide.numElectrons * (1.0 - fFractVVCollect[dflag] - fFractUVCollect[dflag] - fFractVVMiss[dflag]);
711  fChargeWorkCollInd[t] += ide.numElectrons * fFractVVCollect[dflag];
712  break;
713  }
714  case geo::kZ:
715  {
716  fChargeWork[t] += ide.numElectrons * (1.0-fFractVVCollect[dflag]-fFractUVCollect[dflag]-fFractZVMiss[dflag]);
717  break;
718  }
719  default:
720  {
721  throw cet::exception("SimWireDUNE35t") << "ILLEGAL VIEW Type: " << view <<"\n";
722  }
723  }
724  break;
725  }
726  case HORIZGAP:
727  {
728  dflag = GapHasDeflector(ide.x,ide.y,ide.z);
729  switch (view)
730  {
731  case geo::kU:
732  {
733  fChargeWork[t] += ide.numElectrons * (1.0-fFractHorizGapUMiss[dflag]-fFractHorizGapUCollect[dflag]);
734  fChargeWorkCollInd[t] += ide.numElectrons * fFractHorizGapUCollect[dflag];
735  break;
736  }
737  case geo::kV:
738  {
739  fChargeWork[t] += ide.numElectrons * (1.0-fFractHorizGapVMiss[dflag]-fFractHorizGapUCollect[dflag]-fFractHorizGapVCollect[dflag]);
740  fChargeWorkCollInd[t] += ide.numElectrons * fFractHorizGapVCollect[dflag];
741  break;
742  }
743  case geo::kZ:
744  {
745  fChargeWork[t] += ide.numElectrons * (1.0-fFractHorizGapZMiss[dflag]-fFractHorizGapUCollect[dflag]-fFractHorizGapVCollect[dflag]);
746  break;
747  }
748  default:
749  {
750  throw cet::exception("SimWireDUNE35t") << "ILLEGAL VIEW Type: " << view <<"\n";
751  }
752  }
753  break;
754  }
755  case VERTGAP:
756  {
757  dflag = GapHasDeflector(ide.x,ide.y,ide.z);
758  switch (view)
759  {
760  case geo::kU:
761  {
762  fChargeWork[t] += ide.numElectrons * (1.0-fFractVertGapUMiss[dflag]-fFractVertGapUCollect[dflag]);
763  fChargeWorkCollInd[t] += ide.numElectrons * fFractVertGapUCollect[dflag];
764  break;
765  }
766  case geo::kV:
767  {
768  fChargeWork[t] += ide.numElectrons * (1.0-fFractVertGapVMiss[dflag]-fFractVertGapUCollect[dflag]-fFractVertGapVCollect[dflag]);
769  fChargeWorkCollInd[t] += ide.numElectrons * fFractVertGapVCollect[dflag];
770  break;
771  }
772  case geo::kZ:
773  {
774  fChargeWork[t] += ide.numElectrons * (1.0-fFractVertGapZMiss[dflag]-fFractVertGapUCollect[dflag]-fFractVertGapVCollect[dflag]);
775  break;
776  }
777  default:
778  {
779  throw cet::exception("SimWireDUNE35t") << "ILLEGAL VIEW Type: " << view <<"\n";
780  }
781  }
782  break;
783  }
784  case NONACTIVE:
785  {
786  break;
787  }
788  }
789  }
790  // the line all this replaced.
791  // fChargeWork[t] = sc->Charge(t);
792  }
793  else
794  {
795  fChargeWork[t] = sc->Charge(t);
796  //if (chan == 180 ) std::cout << "Xin1: " << t << " " << fChargeWork[t] << std::endl;
797  }
798 
799  // Convolve charge with appropriate response function
800 
801  fChargeWork.resize(fNTicks,0);
802  sss->Convolute(clockData, chan,fChargeWork);
803  // if (chan == 180 ) {
804  // for(size_t t = 0; t < fChargeWork.size(); ++t) {
805  // std::cout << "Xin2: " << t << " " << fChargeWork[t] << std::endl;
806  // }
807  // }
808 
809  fChargeWorkCollInd.resize(fNTicks,0);
810  sss->Convolute(clockData, fFirstCollectionChannel,fChargeWorkCollInd);
811 
812  }
813 
814  float ped_mean = fCollectionPed;
815  float ped_rms = fCollectionPedRMS;
816  geo::SigType_t sigtype = geo->SignalType(chan);
817  if (sigtype == geo::kInduction){
818  ped_mean = fInductionPed;
819  ped_rms = fInductionPedRMS;
820  }
821  else if (sigtype == geo::kCollection){
822  ped_mean = fCollectionPed;
823  ped_rms = fCollectionPedRMS;
824  }
825 
826  // noise was already generated for each wire in the event
827  // raw digit vec is already in channel order
828  // pick a new "noise channel" for every channel - this makes sure
829  // the noise has the right coherent characteristics to be on one channel
830 
831  int noisechan = nearbyint(flat.fire()*(1.*(fNoiseArrayPoints-1)+0.1));
832  // optimize for speed -- access vectors as arrays
833 
834  double *fChargeWork_a=0;
835  double *fChargeWorkCollInd_a=0;
836  short *adcvec_a=0;
837  float *noise_a_U=0;
838  float *noise_a_V=0;
839  float *noise_a_Z=0;
840 
841  if (signalSize>0) {
842  fChargeWork_a = fChargeWork.data();
843  fChargeWorkCollInd_a = fChargeWorkCollInd.data();
844  adcvec_a = adcvec.data();
845  if (fNoiseOn && fNoiseModel==1) {
846  noise_a_U=(fNoiseU[noisechan]).data();
847  noise_a_V=(fNoiseV[noisechan]).data();
848  noise_a_Z=(fNoiseZ[noisechan]).data();
849  }
850  }
851 
852  float tmpfv=0; // this is here so we do our own rounding from floats to short ints (saves CPU time)
853  float tnoise=0;
854 
855  if (view != geo::kU && view != geo::kV && view != geo::kZ) {
856  mf::LogError("SimWireDUNE35t") << "ERROR: CHANNEL NUMBER " << chan << " OUTSIDE OF PLANE";
857  }
858 
859  if(fNoiseOn && fNoiseModel==1) {
860  for(unsigned int i = 0; i < signalSize; ++i){
861  if(view==geo::kU) { tnoise = noise_a_U[i]; }
862  else if (view==geo::kV) { tnoise = noise_a_V[i]; }
863  else { tnoise = noise_a_Z[i]; }
864  tmpfv = tnoise + fChargeWork_a[i] ;
865  if (fSimCombs) tmpfv += fChargeWorkCollInd_a[i];
866  //allow for ADC saturation
867  if ( tmpfv > adcsaturation - ped_mean)
868  tmpfv = adcsaturation- ped_mean;
869  //don't allow for "negative" saturation
870  if ( tmpfv < 0 - ped_mean)
871  tmpfv = 0- ped_mean;
872 
873  adcvec_a[i] = (tmpfv >=0) ? (short) (tmpfv+0.5) : (short) (tmpfv-0.5);
874  }
875  }else if (fNoiseOn && fNoiseModel==2){
876 
877  float fASICGain = sss->GetASICGain(chan);
878 
879  double fShapingTime = sss->GetShapingTime(chan);
880  std::map< double, int > fShapingTimeOrder;
881  fShapingTimeOrder = { {0.5, 0}, {1.0, 1}, {2.0, 2}, {3.0, 3} };
882  DoubleVec fNoiseFactVec;
883 
884  //
885 
886  auto tempNoiseVec = sss->GetNoiseFactVec();
887 
888  if ( fShapingTimeOrder.find( fShapingTime ) != fShapingTimeOrder.end() ){
889  size_t i = 0;
890  fNoiseFactVec.resize(2);
891  for (auto& item : tempNoiseVec) {
892  fNoiseFactVec[i] = item.at( fShapingTimeOrder.find( fShapingTime )->second );
893  fNoiseFactVec[i] *= fASICGain/4.7;
894  ++i;
895  }
896  }
897  else {//Throw exception...
898  throw cet::exception("SimWireDUNE35t")
899  << "\033[93m"
900  << "Shaping Time received from signalservices_dune.fcl is not one of allowed values"
901  << std::endl
902  << "Allowed values: 0.5, 1.0, 2.0, 3.0 usec"
903  << "\033[00m"
904  << std::endl;
905  }
906  //std::cout << "Xin " << fASICGain << " " << fShapingTime << " " << fNoiseFactVec[0] << " " << fNoiseFactVec[1] << std::endl;
907 
908  CLHEP::RandGaussQ rGauss_Ind(fEngine, 0.0, fNoiseFactVec[0]);
909  CLHEP::RandGaussQ rGauss_Col(fEngine, 0.0, fNoiseFactVec[1]);
910 
911 
912  for(unsigned int i = 0; i < signalSize; ++i){
913  if(view==geo::kU) { tnoise = rGauss_Ind.fire(); }
914  else if (view==geo::kV) { tnoise = rGauss_Ind.fire(); }
915  else { tnoise = rGauss_Col.fire(); }
916  tmpfv = tnoise + fChargeWork_a[i] ;
917  if (fSimCombs) tmpfv += fChargeWorkCollInd_a[i];
918  //allow for ADC saturation
919  if ( tmpfv > adcsaturation - ped_mean)
920  tmpfv = adcsaturation- ped_mean;
921  //don't allow for "negative" saturation
922  if ( tmpfv < 0 - ped_mean)
923  tmpfv = 0- ped_mean;
924  adcvec_a[i] = (tmpfv >=0) ? (short) (tmpfv+0.5) : (short) (tmpfv-0.5);
925  }
926  }else { // no noise, so just round the values to nearest short ints and store them
927  for(unsigned int i = 0; i < signalSize; ++i){
928  tmpfv = fChargeWork_a[i];
929  if (fSimCombs) tmpfv += fChargeWorkCollInd_a[i] ;
930  //allow for ADC saturation
931  if ( tmpfv > adcsaturation - ped_mean)
932  tmpfv = adcsaturation- ped_mean;
933  //don't allow for "negative" saturation
934  if ( tmpfv < 0 - ped_mean)
935  tmpfv = 0- ped_mean;
936  adcvec_a[i] = (tmpfv >=0) ? (short) (tmpfv+0.5) : (short) (tmpfv-0.5);
937  }
938  }
939 
940  // resize the adcvec to be the correct number of time samples,
941  // just drop the extra samples
942 
943 
944  adcvec.resize(fNSamplesReadout);
945 
946  float calibrated_pedestal_value = 0; // Estimated calibrated value of pedestal to be passed to RawDigits collection
947  float calibrated_pedestal_rms_value = 0; // Estimated calibrated value of pedestal RMS to be passed to RawDigits collection
948  int calibrated_integer_pedestal_value = 0; // Estimated calibrated value of pedestal to be passed to data compression
949 
950  // add pedestal values
951  if(fPedestalOn)
952  {
953  if(ped_rms>0){
954  CLHEP::RandGaussQ rGauss_Ped(fEngine, 0.0, ped_rms);
955  for(unsigned int i = 0; i < signalSize; ++i){
956  float ped_variation = rGauss_Ped.fire();
957  tmpfv = adcvec_a[i] + ped_mean + ped_variation;
958 
959  adcvec_a[i] = (short) tmpfv;
960 
961  }
962  }
963  else{
964  for(unsigned int i = 0; i < signalSize; ++i){
965  tmpfv = adcvec_a[i] + ped_mean;
966  adcvec_a[i] = (short) tmpfv;
967  }
968 
969  }
970 
971 
972 
973  if (sigtype == geo::kInduction){
974  calibrated_pedestal_value = fInductionCalibPed;
975  calibrated_pedestal_rms_value = fInductionCalibPedRMS;
976  }
977  else if (sigtype == geo::kCollection){
978  calibrated_pedestal_value = fCollectionCalibPed;
979  calibrated_pedestal_rms_value = fCollectionCalibPedRMS;
980  }
981 
982  }
983  else{
984  calibrated_pedestal_value = 0;
985  calibrated_pedestal_rms_value = 0;
986 
987  }
988 
989  calibrated_integer_pedestal_value = (int) calibrated_pedestal_value;
990 
991 
992  if(fSimStuckBits)//
993  {
994 
995  for(size_t i = 0; i < adcvec.size(); ++i){
996  CLHEP::RandFlat flat(fEngine);
997 
998 
999  double rnd = flat.fire(0,1);
1000 
1001 
1002  unsigned int zeromask = 0xffc0;
1003  unsigned int onemask = 0x003f;
1004 
1005  unsigned int sixlsbs = adcvec_a[i] & onemask;
1006 
1007  int probability_index = (int)sixlsbs;
1008 
1009  if(rnd < fUnderflowProbs[probability_index]){
1010  adcvec_a[i] = adcvec_a[i] | onemask; // 6 LSBs are stuck at 3F
1011  adcvec_a[i] -= 64; // correct 1st MSB value by subtracting 64
1012  }
1013  else if(rnd > fUnderflowProbs[probability_index] && rnd < fUnderflowProbs[probability_index] + fOverflowProbs[probability_index]){
1014  adcvec_a[i] = adcvec_a[i] & zeromask; // 6 LSBs are stuck at 0
1015  adcvec_a[i] += 64; // correct 1st MSB value by adding 64
1016  }
1017  //else adcvec value remains unchanged
1018  }
1019 
1020  }
1021 
1022 
1023  if(fNeighboringChannels==0){ // case where neighboring channels are disregarded in zero suppression
1024 
1025 
1026  // compress the adc vector using the desired compression scheme,
1027  // if raw::kNone is selected nothing happens to adcvec
1028  // This shrinks adcvec, if fCompression is not kNone.
1029 
1030  if(!fPedestalOn){
1031  raw::Compress(adcvec, fCompression, fZeroThreshold, calibrated_integer_pedestal_value, fNearestNeighbor, fSimStuckBits);
1032  }
1033  else{
1034  raw::Compress(adcvec, fCompression, fZeroThreshold, calibrated_integer_pedestal_value, fNearestNeighbor, fSimStuckBits);
1035  }
1036 
1037 
1038  raw::RawDigit rd(chan, fNSamplesReadout, adcvec, fCompression);
1039  rd.SetPedestal(calibrated_pedestal_value,calibrated_pedestal_rms_value);
1040 
1041 
1042  adcvec.resize(signalSize); // Then, resize adcvec back to full length. Do not initialize to zero (slow)
1043  if(fSaveEmptyChannel || adcvec[1]>0)
1044  digcol->push_back(rd); // add this digit to the collection
1045 
1046 
1047  }
1048  else{ //case where contribution of neighboring channels is included in zero suppression
1049 
1050 
1051  if(sigtype == geo::kCollection)
1052  {
1053 
1054 
1055  // push the adc vector to the ring buffer to enable zero suppression with neighboring channel contributions
1056 
1057  adcvec_neighbors.push_back(adcvec);
1058 
1059 
1060  if(!(adcvec_neighbors.full()))
1061  {
1062  if(adcvec_neighbors.size()>fNeighboringChannels){ // apply zero suppression to entries at start of collection plane, once ring buffer is full enough with neighbors
1063 
1064  adcvec = adcvec_neighbors.at(adcvec_neighbors.size()-fNeighboringChannels);
1065  // apply zero suppression to entries at start of collection plane, once ring buffer is full enough with neighbors
1066  if(!fPedestalOn){
1067  raw::Compress(adcvec_neighbors,adcvec, fCompression, fZeroThreshold, calibrated_integer_pedestal_value, fNearestNeighbor, fSimStuckBits);
1068  }
1069  else{
1070  raw::Compress(adcvec_neighbors,adcvec, fCompression, fZeroThreshold, calibrated_integer_pedestal_value, fNearestNeighbor, fSimStuckBits);
1071  }
1072 
1074  rd.SetPedestal(calibrated_pedestal_value,calibrated_pedestal_rms_value);
1075 
1076  if(fSaveEmptyChannel || adcvec[1]>0)
1077  digcol->push_back(rd); // add this digit to the collection
1078 
1079  }
1080  }
1081  else{ // ring buffer is full
1082 
1083  // compress the adc vector using the desired compression scheme,
1084  // if raw::kNone is selected nothing happens to adcvec
1085  // This shrinks adcvec, if fCompression is not kNone.
1086 
1087  adcvec = adcvec_neighbors.at(fNeighboringChannels);
1088  // apply zero suppression to entry in middle of ring buffer
1089  if(!fPedestalOn){
1090  raw::Compress(adcvec_neighbors,adcvec, fCompression, fZeroThreshold, calibrated_integer_pedestal_value, fNearestNeighbor, fSimStuckBits);
1091  }
1092  else{
1093  raw::Compress(adcvec_neighbors,adcvec, fCompression, fZeroThreshold, calibrated_integer_pedestal_value, fNearestNeighbor, fSimStuckBits);
1094  }
1096  rd.SetPedestal(calibrated_pedestal_value,calibrated_pedestal_rms_value);
1097 
1098  if(fSaveEmptyChannel || adcvec[1]>0)
1099  digcol->push_back(rd); // add this digit to the collection
1100 
1101  if(chan == fLastChannelsInPlane.at(plane_number)) // End of collection plane is reached, so apply zero suppression to last entries as well
1102  {
1103 
1104 
1105  unsigned int channel_number = chan - fNeighboringChannels;
1106  //std::cout << "We have reached the end of a collection plane!" << std::endl;
1107  for(size_t lastentries = 0; lastentries < fNeighboringChannels; ++lastentries)
1108  {
1109  ++channel_number;
1110 
1111  adcvec_neighbors.pop_front(); // remove first entry from ring buffer, to exclude it from nearest neighboring wire checks in zero
1112 
1113  adcvec = adcvec_neighbors.at(fNeighboringChannels);
1114  // apply zero suppression to entry in middle of ring buffer
1115  if(!fPedestalOn){
1116  raw::Compress(adcvec_neighbors,adcvec, fCompression, fZeroThreshold, calibrated_integer_pedestal_value, fNearestNeighbor, fSimStuckBits);
1117  }
1118  else{
1119  raw::Compress(adcvec_neighbors,adcvec, fCompression, fZeroThreshold, calibrated_integer_pedestal_value, fNearestNeighbor, fSimStuckBits);
1120  }
1121  raw::RawDigit rd2(channel_number, fNSamplesReadout, adcvec, fCompression);
1122  rd2.SetPedestal(calibrated_pedestal_value,calibrated_pedestal_rms_value);
1123 
1124  if(fSaveEmptyChannel || adcvec[1]>0)
1125  digcol->push_back(rd2); // add this digit to the collection
1126 
1127  }
1128 
1129  adcvec_neighbors.clear(); // clear ring buffer for next wire plane
1130  }
1131  } // ring buffer is full
1132 
1133  } // collection plane
1134  else if(sigtype == geo::kInduction)
1135  {
1136  // push the adc vector to the ring buffer to enable zero suppression with neighboring channel contributions
1137 
1138 
1139  adcvec_neighbors.push_back(adcvec);
1140  if(!(adcvec_neighbors.full()))
1141  {
1142  adcvec_inductionplanestart.push_back(adcvec);
1143 
1144 
1145  }
1146  else //ring buffer is full
1147  {
1148 
1149  // compress the adc vector using the desired compression scheme,
1150  // if raw::kNone is selected nothing happens to adcvec
1151  // This shrinks adcvec, if fCompression is not kNone.
1152 
1153  adcvec = adcvec_neighbors.at(fNeighboringChannels);
1154  // apply zero suppression to entry in middle of ring buffer
1155  if(!fPedestalOn){
1156  raw::Compress(adcvec_neighbors,adcvec, fCompression, fZeroThreshold, calibrated_integer_pedestal_value, fNearestNeighbor, fSimStuckBits);
1157  }
1158  else{
1159  raw::Compress(adcvec_neighbors,adcvec, fCompression, fZeroThreshold, calibrated_integer_pedestal_value, fNearestNeighbor, fSimStuckBits);
1160  }
1162  rd.SetPedestal(calibrated_pedestal_value,calibrated_pedestal_rms_value);
1163 
1164  if(fSaveEmptyChannel || adcvec[1]>0)
1165  digcol->push_back(rd); // add this digit to the collection
1166 
1167  }
1168  if(chan==fLastChannelsInPlane.at(plane_number)){ // reached the last channel of the induction plane
1169 
1170  unsigned int channel_number = chan-fNeighboringChannels;
1171 
1172  for(size_t lastentries = 0; lastentries < 2*fNeighboringChannels; ++lastentries)
1173  {
1174 
1175  ++channel_number;
1176 
1177  if(channel_number > fLastChannelsInPlane.at(plane_number))
1178  channel_number = fFirstChannelsInPlane.at(plane_number); // set channel number back to start of induction plane after looping around
1179 
1180  //std::cout << "Channel number of looping-around sections of induction plane = " << channel_number << std::endl;
1181 
1182  adcvec_neighbors.push_back(adcvec_inductionplanestart.at(lastentries)); // push channel from start of plane onto ring buffer
1183 
1184  adcvec = adcvec_neighbors.at(fNeighboringChannels);
1185 
1186  // apply zero suppression to entry in middle of ring buffer
1187  if(!fPedestalOn){
1188  raw::Compress(adcvec_neighbors,adcvec, fCompression, fZeroThreshold, calibrated_integer_pedestal_value, fNearestNeighbor, fSimStuckBits);
1189  }
1190  else{
1191  raw::Compress(adcvec_neighbors,adcvec, fCompression, fZeroThreshold, calibrated_integer_pedestal_value, fNearestNeighbor, fSimStuckBits);
1192  }
1193  raw::RawDigit rd2(channel_number, fNSamplesReadout, adcvec, fCompression);
1194  rd2.SetPedestal(calibrated_pedestal_value,calibrated_pedestal_rms_value);
1195 
1196  if(fSaveEmptyChannel || adcvec[1]>0)
1197  digcol->push_back(rd2); // add this digit to the collection
1198 
1199  }
1200 
1201  adcvec_neighbors.clear(); // clear ring buffer for next wire plane
1202  adcvec_inductionplanestart.clear(); // clear vector of starting adc vectors for next induction plane
1203  }
1204 
1205  } // induction plane
1206 
1207  } // zero suppression with nearest neighboring wire influence complete
1208 
1209  adcvec.resize(signalSize); // Then, resize adcvec back to full length. Do not initialize to zero (slow)
1210 
1211  if(chan==fLastChannelsInPlane.at(plane_number))
1212  ++plane_number;
1213 
1214  }// end loop over channels
1215 
1216  evt.put(std::move(digcol));
1217 
1218  return;
1219  }
1220 
1221  //-------------------------------------------------
1222  void SimWireDUNE35t::GenNoise(std::vector<float>& noise)
1223  {
1224  CLHEP::RandFlat flat(fEngine);
1225 
1226  noise.clear();
1227  noise.resize(fNTicks,0.0);
1228  // noise in frequency space
1229  std::vector<TComplex> noiseFrequency(fNTicks/2+1, 0.);
1230 
1231  double pval = 0.;
1232  double lofilter = 0.;
1233  double phase = 0.;
1234  double rnd[2] = {0.};
1235 
1236  // width of frequencyBin in kHz
1237  double binWidth = 1.0/(fNTicks*fSampleRate*1.0e-6);
1238  for(int i=0; i< fNTicks/2+1; ++i){
1239  // exponential noise spectrum
1240  pval = fNoiseFact*exp(-(double)i*binWidth/fNoiseWidth);
1241  // low frequency cutoff
1242  lofilter = 1.0/(1.0+exp(-(i-fLowCutoff/binWidth)/0.5));
1243  // randomize 10%
1244  flat.fireArray(2,rnd,0,1);
1245  pval *= lofilter*(0.9+0.2*rnd[0]);
1246  // random pahse angle
1247  phase = rnd[1]*2.*TMath::Pi();
1248 
1249  TComplex tc(pval*cos(phase),pval*sin(phase));
1250  noiseFrequency[i] += tc;
1251  }
1252 
1253 
1254  // inverse FFT MCSignal
1256  fFFT->DoInvFFT(noiseFrequency, noise);
1257 
1258  noiseFrequency.clear();
1259 
1260  // multiply each noise value by fNTicks as the InvFFT
1261  // divides each bin by fNTicks assuming that a forward FFT
1262  // has already been done.
1263  for(unsigned int i = 0; i < noise.size(); ++i) noise[i] *= 1.*fNTicks;
1264 
1265  return;
1266  }
1267 
1268 
1269 
1270  //-------------------------------------------------
1271 
1272 
1273  // see the ASCII cartoon of APA's at the bottom of this file for a picture of what all the boundaries are
1274 
1275  //-------------------------------------------------
1276  GapType_t SimWireDUNE35t::combtest35t(double x, double y, double z)
1277  {
1278 
1279  if (z<zcomb1) return VERTGAP; // off to the side of the first APA -- kind of like being in a vertical gap
1280  if (z<zcomb2) return UCOMB; // over U comb
1281  if (z<zcomb3) return VCOMB; // over V comb
1282  if (z<zcomb4)
1283  {
1284  if (y<ycomb1) return HORIZGAP; // below the bottom
1285  if (y<ycomb2) return UCOMB; // over U comb
1286  if (y<ycomb3) return VCOMB; // over V comb
1287  if (y<ycomb4) return ACTIVE; // active volume
1288  if (y<ycomb5) return VCOMB; // over V comb
1289  if (y<ycomb6) return UCOMB; // over U comb
1290  return HORIZGAP; // outside top edge
1291 
1292  }
1293  if (z<zcomb5) return VCOMB; // over V comb
1294  if (z<zcomb6) return UCOMB; // over U comb
1295 
1296  if (z<zcomb7) return VERTGAP; // in gap
1297  if (z<zcomb8) return UCOMB; // over U comb
1298  if (z<zcomb9) return VCOMB; // over V comb
1299  if (z<zcomb10)
1300  {
1301  if (y<ycomb7) return HORIZGAP; // off the bottom
1302  if (y<ycomb8) return UCOMB; // over U comb
1303  if (y<ycomb9) return VCOMB; // over V comb
1304  if (y<ycomb10) return ACTIVE; // active
1305  if (y<ycomb11) return VCOMB; // over V comb
1306  if (y<ycomb12) return UCOMB; // over U comb
1307  if (y<ycomb13) return HORIZGAP; // over gap
1308  if (y<ycomb14) return UCOMB; // over U comb
1309  if (y<ycomb15) return VCOMB; // over V comb
1310  if (y<ycomb16) return ACTIVE; // active volume
1311  if (y<ycomb17) return VCOMB; // over V comb
1312  if (y<ycomb18) return UCOMB; // over U comb
1313  return HORIZGAP; // above the top edge
1314  }
1315  if (z<zcomb11) return VCOMB; // over V comb
1316  if (z<zcomb12) return UCOMB; // over U comb
1317 
1318  if (z<zcomb13) return VERTGAP; // outside first APA
1319  if (z<zcomb14) return UCOMB; // over U comb
1320  if (z<zcomb15) return VCOMB; // over V comb
1321  if (z<zcomb16)
1322  {
1323  if (y<ycomb1) return HORIZGAP; // below the bottom
1324  if (y<ycomb2) return UCOMB; // over U comb
1325  if (y<ycomb3) return VCOMB; // over V comb
1326  if (y<ycomb4) return ACTIVE; // active volume
1327  if (y<ycomb5) return VCOMB; // over V comb
1328  if (y<ycomb6) return UCOMB; // over U comb
1329  return HORIZGAP; // outside top edge
1330  }
1331  if (z<zcomb17) return VCOMB; // over V comb
1332  if (z<zcomb18) return UCOMB; // over U comb
1333  return VERTGAP; // off the end in Z.
1334 
1335  }
1336 
1337  int SimWireDUNE35t::GapHasDeflector(double x, double y, double z)
1338  {
1339  if ( y < ycomb12 && y > ycomb7 && x > 0 && z < zcomb9 && z > zcomb4 ) return 1;
1340  return 0;
1341  }
1342 
1343 }
1344 
1346 
1347 
1348 /* -------------------------------------------------
1349  APA Cartoons for the combtest35t method
1350 
1351  z->
1352 
1353  ^
1354  |
1355  y
1356 
1357 
1358  zcomb1 zcomb6
1359  zcomb2 zcomb5
1360  zcomb3 zcomb4
1361  ______________________________________________ ycomb6
1362  |____________________________________________| ycomb5
1363  ||__________________________________________|| ycomb4
1364  ||| |||
1365  ||| |||
1366  ||| |||
1367  ||| |||
1368  ||| |||
1369  ||| |||
1370  ||| |||
1371  ||| |||
1372  ||| |||
1373  ||| |||
1374  ||| |||
1375  ||| |||
1376  ||| |||
1377  ||| |||
1378  ||| |||
1379  ||| APA0 |||
1380  ||| |||
1381  ||| |||
1382  ||| |||
1383  ||| |||
1384  ||| |||
1385  ||| |||
1386  ||| |||
1387  ||| |||
1388  ||| |||
1389  ||| |||
1390  ||| |||
1391  ||| |||
1392  ||| |||
1393  ||| |||
1394  ||| |||
1395  ||| |||
1396  ||| |||
1397  ||| |||
1398  ||__________________________________________|| ycomb3
1399  |____________________________________________| ycomb2
1400  ______________________________________________ ycomb1
1401 
1402 
1403  z->
1404 
1405  ^
1406  |
1407  y
1408 
1409 
1410  zcomb7 zcomb12
1411  zcomb8 zcomb11
1412  zcomb9 zcomb10
1413  ______________________________________________ ycomb18
1414  |____________________________________________| ycomb17
1415  ||__________________________________________|| ycomb16
1416  ||| |||
1417  ||| |||
1418  ||| |||
1419  ||| |||
1420  ||| |||
1421  ||| |||
1422  ||| |||
1423  ||| |||
1424  ||| |||
1425  ||| |||
1426  ||| |||
1427  ||| APA2 |||
1428  ||| |||
1429  ||| |||
1430  ||| |||
1431  ||| |||
1432  ||| |||
1433  ||| |||
1434  ||| |||
1435  ||| |||
1436  ||| |||
1437  ||| |||
1438  ||| |||
1439  ||__________________________________________|| ycomb15
1440  |____________________________________________| ycomb14
1441  ______________________________________________ ycomb13
1442 
1443  ______________________________________________ ycomb12
1444  |____________________________________________| ycomb11
1445  ||__________________________________________|| ycomb10
1446  ||| |||
1447  ||| |||
1448  ||| |||
1449  ||| |||
1450  ||| |||
1451  ||| APA1 |||
1452  ||| |||
1453  ||| |||
1454  ||| |||
1455  ||| |||
1456  ||| |||
1457  ||__________________________________________|| ycomb9
1458  |____________________________________________| ycomb8
1459  ______________________________________________ ycomb7
1460 
1461 
1462  APA 0 Cartoon:
1463 
1464  z->
1465 
1466  ^
1467  |
1468  y
1469 
1470 
1471  zcomb13 zcomb18
1472  zcomb14 zcomb17
1473  zcomb15 zcomb16
1474  ______________________________________________ ycomb6
1475  |____________________________________________| ycomb5
1476  ||__________________________________________|| ycomb4
1477  ||| |||
1478  ||| |||
1479  ||| |||
1480  ||| |||
1481  ||| |||
1482  ||| |||
1483  ||| |||
1484  ||| |||
1485  ||| |||
1486  ||| |||
1487  ||| |||
1488  ||| |||
1489  ||| |||
1490  ||| |||
1491  ||| |||
1492  ||| |||
1493  ||| APA3 |||
1494  ||| |||
1495  ||| |||
1496  ||| |||
1497  ||| |||
1498  ||| |||
1499  ||| |||
1500  ||| |||
1501  ||| |||
1502  ||| |||
1503  ||| |||
1504  ||| |||
1505  ||| |||
1506  ||| |||
1507  ||| |||
1508  ||| |||
1509  ||| |||
1510  ||| |||
1511  ||__________________________________________|| ycomb3
1512  |____________________________________________| ycomb2
1513  ______________________________________________ ycomb1
1514 
1515 
1516 
1517 */
void GenNoise(std::vector< float > &array)
float fInductionCalibPedRMS
Assumed measured value for ind plane pedestal RMS.
intermediate_table::iterator iterator
base_engine_t & createEngine(seed_t seed)
int fNTicks
number of ticks of the clock
Huffman Encoding.
Definition: RawTypes.h:10
std::vector< float > fFractUVCollect
std::vector< std::vector< float > > fNoiseU
noise on each channel for each time for U plane
double GetShapingTime(Channel channel) const override
enum raw::_compress Compress_t
std::vector< float > fFractVUCollect
float fNoiseWidthZ
exponential noise width (kHz) for Z (collection) plane
float fInductionPed
ADC value of baseline for induction plane.
float fNoiseWidth
exponential noise width (kHz)
Collection of charge vs time digitized from a single readout channel.
Definition: RawDigit.h:69
Energy deposited on a readout channel by simulated tracks.
Definition: SimChannel.h:140
bool fSimCombs
switch for simulation of the combs
float fLowCutoffZ
low frequency filter cutoff (kHz) for Z (collection) plane
std::vector< float > fFractHorizGapVMiss
void reconfigure(fhicl::ParameterSet const &p)
std::vector< float > fFractHorizGapZMiss
std::vector< uint32_t > fFirstChannelsInPlane
std::vector< float > fFractUUMiss
enum geo::_plane_proj View_t
Enumerate the possible plane projections.
std::string string
Definition: nybbler.cc:12
MaybeLogger_< ELseverityLevel::ELsev_info, false > LogInfo
Planes which measure V.
Definition: geo_types.h:130
float fNoiseWidthU
exponential noise width (kHz) for U plane
std::vector< DoubleVec > GetNoiseFactVec() const override
EDProducer(fhicl::ParameterSet const &pset)
Definition: EDProducer.h:20
TH1D * fNoiseDist
distribution of noise counts
std::vector< float > fFractUVMiss
Detector simulation of raw signals on wires.
SimWireDUNE35t(fhicl::ParameterSet const &pset)
const unsigned int onemask
Definition: raw.h:139
std::vector< float > fFractUUCollect
std::vector< geo::WireID > ChannelToWire(raw::ChannelID_t const channel) const
Returns a list of wires connected to the specified TPC channel.
std::vector< float > fFractVUMiss
Planes which measure Z direction.
Definition: geo_types.h:132
unsigned int fNoiseModel
noise model>
int GapHasDeflector(double x, double y, double z)
float fInductionCalibPed
Assumed measured value for ind plane pedestal.
SigType_t SignalType(geo::PlaneID const &pid) const
Returns the type of signal on the channels of specified TPC plane.
MaybeLogger_< ELseverityLevel::ELsev_error, false > LogError
float fInductionPedRMS
ADC value of baseline RMS for induction plane.
Service to provide microboone-specific signal shaping for simulation (convolution) and reconstruction...
unsigned int fNSamplesReadout
number of ADC readout samples in 1 readout frame
float fNoiseFact
noise scale factor
no compression
Definition: RawTypes.h:9
float fLowCutoffU
low frequency filter cutoff (kHz) for U plane
std::vector< float > fFractHorizGapVCollect
unsigned int Nwires(unsigned int p, unsigned int tpc=0, unsigned int cstat=0) const
Returns the total number of wires in the specified plane.
art framework interface to geometry description
void DoInvFFT(std::vector< TComplex > &input, std::vector< T > &output)
Definition: LArFFT.h:120
unsigned int Nchannels() const
Returns the number of TPC readout channels in the detector.
unsigned int fNoiseArrayPoints
number of points in randomly generated noise array
std::vector< float > fFractHorizGapUMiss
GapType_t combtest35t(double x, double y, double z)
float fCollectionPed
ADC value of baseline for collection plane.
Zero Suppression algorithm.
Definition: RawTypes.h:11
int fNearestNeighbor
Maximum distance between hits above threshold before they are separated into different blocks...
std::string fStuckBitsUnderflowProbHistoName
Name of histogram holding ADC stuck code underflow probabilities.
Planes which measure U.
Definition: geo_types.h:129
int FFTSize() const
Definition: LArFFT.h:69
std::vector< float > fFractVVMiss
float fNoiseFactU
noise scale factor for U plane
#define DEFINE_ART_MODULE(klass)
Definition: ModuleMacros.h:67
unsigned int fNoiseOn
noise turned on or off for debugging; default is on
Signal from induction planes.
Definition: geo_types.h:145
double Charge(TDC_t tdc) const
Returns the total number of ionization electrons on this channel in the specified TDC...
Definition: SimChannel.cxx:134
enum geo::_plane_sigtype SigType_t
bool fPedestalOn
switch for simulation of nonzero pedestals
def move(depos, offset)
Definition: depos.py:107
T get(std::string const &key) const
Definition: ParameterSet.h:271
double fUnderflowProbs[64]
array of probabilities of 6 LSF bits getting stuck at 111111
float fCollectionPedRMS
ADC value of baseline RMS for collection plane.
raw::Compress_t fCompression
compression type to use
std::vector< double > fChargeWork
std::vector< float > fFractZVMiss
float fNoiseWidthV
exponential noise width (kHz) for V plane
float fNoiseFactZ
noise scale factor for Z (collection) plane
p
Definition: test.py:223
float fCollectionCalibPed
Assumed measured value for coll plane pedestal.
ProductID put(std::unique_ptr< PROD > &&edp, std::string const &instance={})
Definition: DataViewImpl.h:686
View_t View(geo::PlaneID const &pid) const
Returns the view (wire orientation) on the channels of specified TPC plane.
void produce(art::Event &evt)
unsigned int fNTimeSamples
number of ADC readout samples in all readout frames (per event)
float fCollectionCalibPedRMS
Assumed measured value for coll plane pedestal RMS.
cet::coded_exception< errors::ErrorCodes, ExceptionDetail::translate > Exception
Definition: Exception.h:66
std::vector< float > fFractVertGapVMiss
pval
Definition: tracks.py:168
auto array(Array const &a)
Returns a manipulator which will print the specified array.
Definition: DumpUtils.h:228
std::string fDriftEModuleLabel
module making the ionization electrons
void Convolute(detinfo::DetectorClocksData const &clockData, Channel channel, std::vector< T > &func) const
std::vector< float > fFractVertGapVCollect
std::vector< std::vector< float > > fNoiseZ
noise on each channel for each time for Z (collection) plane
std::vector< sim::IDE > TrackIDsAndEnergies(TDC_t startTDC, TDC_t endTDC) const
Return all the recorded energy deposition within a time interval.
Definition: SimChannel.cxx:180
void SetPedestal(float ped, float sigma=1.)
Set pedestal and its RMS (the latter is 0 by default)
Definition: RawDigit.cxx:68
CLHEP::HepRandomEngine & fEngine
std::vector< float > fFractVVCollect
std::string fStuckBitsProbabilitiesFname
file holding ADC stuck code overflow and underflow probabilities
double fSampleRate
sampling rate in ns
std::vector< float > fFractVertGapUMiss
#define MF_LOG_DEBUG(id)
std::string find_file(std::string const &filename) const
Definition: search_path.cc:96
void WireEndPoints(geo::WireID const &wireid, double *xyzStart, double *xyzEnd) const
Fills two arrays with the coordinates of the wire end points.
bool fSimStuckBits
switch for simulation of stuck bits
void Compress(std::vector< short > &adc, raw::Compress_t compress)
Compresses a raw data buffer.
Definition: raw.cxx:19
double fOverflowProbs[64]
array of probabilities of 6 LSF bits getting stuck at 000000
list x
Definition: train.py:276
std::vector< std::vector< float > > fNoiseV
noise on each channel for each time for V plane
std::size_t getView(std::string const &moduleLabel, std::string const &productInstanceName, std::string const &processName, std::vector< ELEMENT const * > &result) const
Definition: DataViewImpl.h:500
Tools and modules for checking out the basics of the Monte Carlo.
TCEvent evt
Definition: DataStructs.cxx:7
float fLowCutoffV
low frequency filter cutoff (kHz) for V plane
double GetASICGain(Channel channel) const override
std::vector< uint32_t > fLastChannelsInPlane
double sampling_rate(DetectorClocksData const &data)
Returns the period of the TPC readout electronics clock.
unsigned int fZeroThreshold
Zero suppression threshold.
float fNoiseFactV
noise scale factor for V plane
LArSoft geometry interface.
Definition: ChannelGeo.h:16
std::vector< float > fFractHorizGapUCollect
float fLowCutoff
low frequency filter cutoff (kHz)
std::string fStuckBitsOverflowProbHistoName
Name of histogram holding ADC stuck code overflow probabilities.
std::vector< float > fFractZUMiss
unsigned int fNeighboringChannels
Number of neighboring channels on either side allowed to influence zero suppression.
std::vector< float > fFractVertGapZMiss
std::vector< float > fFractVertGapUCollect
cet::coded_exception< error, detail::translate > exception
Definition: exception.h:33
QTextStream & endl(QTextStream &s)
Signal from collection planes.
Definition: geo_types.h:146
std::vector< double > DoubleVec