Ductor.cxx
Go to the documentation of this file.
1 #include "WireCellGen/Ductor.h"
4 #include "WireCellUtil/Units.h"
5 #include "WireCellUtil/Point.h"
9 
10 #include <string>
11 
14 
15 
16 using namespace std;
17 using namespace WireCell;
18 
19 Gen::Ductor::Ductor()
20  : m_anode_tn("AnodePlane")
21  , m_rng_tn("Random")
22  , m_start_time(0.0*units::ns)
23  , m_readout_time(5.0*units::ms)
24  , m_tick(0.5*units::us)
25  , m_drift_speed(1.0*units::mm/units::us)
26  , m_nsigma(3.0)
27  , m_fluctuate(true)
28  , m_mode("continuous")
29  , m_frame_count(0)
30  , l(Log::logger("sim"))
31 {
32 }
33 
34 WireCell::Configuration Gen::Ductor::default_configuration() const
35 {
37 
38  /// How many Gaussian sigma due to diffusion to keep before truncating.
39  put(cfg, "nsigma", m_nsigma);
40 
41  /// Whether to fluctuate the final Gaussian deposition.
42  put(cfg, "fluctuate", m_fluctuate);
43 
44  /// The initial time for this ductor
45  put(cfg, "start_time", m_start_time);
46 
47  /// The time span for each readout.
48  put(cfg, "readout_time", m_readout_time);
49 
50  /// The sample period
51  put(cfg, "tick", m_tick);
52 
53  /// If false then determine start time of each readout based on the
54  /// input depos. This option is useful when running WCT sim on a
55  /// source of depos which have already been "chunked" in time. If
56  /// true then this Ductor will continuously simulate all time in
57  /// "readout_time" frames leading to empty frames in the case of
58  /// some readout time with no depos.
59  put(cfg, "continuous", true);
60 
61  /// Fixed mode simply reads out the same time window all the time.
62  /// It implies discontinuous (continuous == false).
63  put(cfg, "fixed", false);
64 
65  /// The nominal speed of drifting electrons
66  put(cfg, "drift_speed", m_drift_speed);
67 
68  /// Allow for a custom starting frame number
69  put(cfg, "first_frame_number", m_frame_count);
70 
71  /// Name of component providing the anode plane.
72  put(cfg, "anode", m_anode_tn);
73  put(cfg, "rng", m_rng_tn);
74 
75  cfg["pirs"] = Json::arrayValue;
76  /// don't set here so user must, but eg:
77  //cfg["pirs"][0] = "PlaneImpactResponseU";
78  //cfg["pirs"][1] = "PlaneImpactResponseV";
79  //cfg["pirs"][2] = "PlaneImpactResponseW";
80 
81  return cfg;
82 }
83 
85 {
86  m_anode_tn = get<string>(cfg, "anode", m_anode_tn);
87  m_anode = Factory::find_tn<IAnodePlane>(m_anode_tn);
88 
89  m_nsigma = get<double>(cfg, "nsigma", m_nsigma);
90  bool continuous = get<bool>(cfg, "continuous", true);
91  bool fixed = get<bool>(cfg, "fixed", false);
92 
93  m_mode = "continuous";
94  if (fixed) {
95  m_mode = "fixed";
96  }
97  else if (!continuous) {
98  m_mode = "discontinuous";
99  }
100 
101  m_fluctuate = get<bool>(cfg, "fluctuate", m_fluctuate);
102  m_rng = nullptr;
103  if (m_fluctuate) {
104  m_rng_tn = get(cfg, "rng", m_rng_tn);
105  m_rng = Factory::find_tn<IRandom>(m_rng_tn);
106  }
107 
108  m_readout_time = get<double>(cfg, "readout_time", m_readout_time);
109  m_tick = get<double>(cfg, "tick", m_tick);
110  m_start_time = get<double>(cfg, "start_time", m_start_time);
111  m_drift_speed = get<double>(cfg, "drift_speed", m_drift_speed);
112  m_frame_count = get<int>(cfg, "first_frame_number", m_frame_count);
113 
114  auto jpirs = cfg["pirs"];
115  if (jpirs.isNull() or jpirs.empty()) {
116  l->critical("must configure with some plane impace response components");
117  THROW(ValueError() << errmsg{"Gen::Ductor: must configure with some plane impact response components"});
118  }
119  m_pirs.clear();
120  for (auto jpir : jpirs) {
121  auto tn = jpir.asString();
122  auto pir = Factory::find_tn<IPlaneImpactResponse>(tn);
123  m_pirs.push_back(pir);
124  }
125 
126  l->debug("AnodePlane: {}, mode: {}, fluctuate: {}, time start: {} ms, readout time: {} ms, frame start: {}", m_anode_tn, m_mode, (m_fluctuate ? "on" : "off"), m_start_time/units::ms, m_readout_time/units::ms, m_frame_count);
127 
128 }
129 
131  const IDepo::vector& face_depos)
132 {
133  ITrace::vector traces;
134 
135  int iplane = -1;
136  for (auto plane : face->planes()) {
137  ++iplane;
138 
139  const Pimpos* pimpos = plane->pimpos();
140 
143 
144  Gen::BinnedDiffusion bindiff(*pimpos, tbins, m_nsigma, m_rng);
145  for (auto depo : face_depos) {
146  bindiff.add(depo, depo->extent_long() / m_drift_speed, depo->extent_tran());
147  }
148 
149  auto& wires = plane->wires();
150 
151  auto pir = m_pirs.at(iplane);
152  Gen::ImpactZipper zipper(pir, bindiff);
153 
154  const int nwires = pimpos->region_binning().nbins();
155  for (int iwire=0; iwire<nwires; ++iwire) {
156  auto wave = zipper.waveform(iwire);
157 
158  auto mm = Waveform::edge(wave);
159  if (mm.first == (int)wave.size()) { // all zero
160  continue;
161  }
162 
163  int chid = wires[iwire]->channel();
164  int tbin = mm.first;
165 
166  ITrace::ChargeSequence charge(wave.begin()+mm.first, wave.begin()+mm.second);
167  auto trace = make_shared<SimpleTrace>(chid, tbin, charge);
168  traces.push_back(trace);
169  }
170  }
171  return traces;
172 }
173 
175 {
176  ITrace::vector traces;
177 
178  for (auto face : m_anode->faces()) {
179 
180  // Select the depos which are in this face's sensitive volume
181  IDepo::vector face_depos, dropped_depos;
182  auto bb = face->sensitive();
183  if (bb.empty()) {
184  l->debug("anode: {} face: {} is marked insensitive, skipping",
185  m_anode->ident(), face->ident());
186  continue;
187  }
188 
189  for (auto depo : m_depos) {
190  if (bb.inside(depo->pos())) {
191  face_depos.push_back(depo);
192  }
193  else {
194  dropped_depos.push_back(depo);
195  }
196  }
197 
198  if (face_depos.size()) {
199  auto ray = bb.bounds();
200  l->debug("anode: {}, face: {}, processing {} depos spanning "
201  "t:[{},{}]ms, bb:[{}-->{}]cm",
202  m_anode->ident(), face->ident(), face_depos.size(),
203  face_depos.front()->time()/units::ms,
204  face_depos.back()->time()/units::ms,
205  ray.first/units::cm,ray.second/units::cm);
206  }
207  if (dropped_depos.size()) {
208  auto ray = bb.bounds();
209  l->debug("anode: {}, face: {}, dropped {} depos spanning "
210  "t:[{},{}]ms, outside bb:[{}-->{}]cm",
211  m_anode->ident(), face->ident(),
212  dropped_depos.size(),
213  dropped_depos.front()->time()/units::ms,
214  dropped_depos.back()->time()/units::ms,
215  ray.first/units::cm, ray.second/units::cm);
216 
217  }
218 
219  auto newtraces = process_face(face, face_depos);
220  traces.insert(traces.end(), newtraces.begin(), newtraces.end());
221  }
222 
223  auto frame = make_shared<SimpleFrame>(m_frame_count, m_start_time, traces, m_tick);
224  frames.push_back(frame);
225  l->debug("made frame: {} with {} traces @ {}ms",
226  m_frame_count, traces.size(), m_start_time/units::ms);
227 
228  // fixme: what about frame overflow here? If the depos extend
229  // beyond the readout where does their info go? 2nd order,
230  // diffusion and finite field response can cause depos near the
231  // end of the readout to have some portion of their waveforms
232  // lost?
233  m_depos.clear();
234 
235  if (m_mode == "continuous") {
236  m_start_time += m_readout_time;
237  }
238 
239  ++m_frame_count;
240 }
241 
242 // Return true if ready to start processing and capture start time if
243 // in continuous mode.
245 {
246  if (!depo) {
247  return true;
248  }
249 
250  if (m_mode == "fixed") {
251  // fixed mode waits until EOS
252  return false;
253  }
254 
255  if (m_mode == "discontinuous") {
256  // discontinuous mode sets start time on first depo.
257  if (m_depos.empty()) {
258  m_start_time = depo->time();
259  return false;
260  }
261  }
262 
263  // continuous and discontinuous modes follow Just Enough
264  // Processing(TM) strategy.
265 
266  // Note: we use this depo time even if it may not actually be
267  // inside our sensitive volume.
268  bool ok = depo->time() > m_start_time + m_readout_time;
269  return ok;
270 }
271 
273 {
274  if (start_processing(depo)) {
275  process(frames);
276  }
277 
278  if (depo) {
279  m_depos.push_back(depo);
280  }
281  else {
282  frames.push_back(nullptr);
283  }
284 
285  return true;
286 }
287 
const int nwires
std::string m_rng_tn
Definition: Ductor.h:41
virtual void process(output_queue &frames)
Definition: Ductor.cxx:174
boost::error_info< struct tag_errmsg, std::string > errmsg
Definition: Exceptions.h:54
bool add(IDepo::pointer deposition, double sigma_time, double sigma_pitch)
WIRECELL_FACTORY(Ductor, WireCell::Gen::Ductor, WireCell::IDuctor, WireCell::IConfigurable) using namespace std
const Binning & region_binning() const
Definition: Pimpos.h:109
virtual void configure(const WireCell::Configuration &config)
Accept a configuration.
Definition: Ductor.cxx:84
double m_readout_time
Definition: Ductor.h:51
STL namespace.
void put(Configuration &cfg, const std::string &dotpath, const T &val)
Put value in configuration at the dotted path.
IAnodePlane::pointer m_anode
Definition: Ductor.h:44
std::string m_anode_tn
Definition: Ductor.h:40
cfg
Definition: dbjson.py:29
std::vector< pointer > vector
Definition: IData.h:21
bool start_processing(const input_pointer &depo)
Definition: Ductor.cxx:244
std::pair< int, int > edge(const realseq_t &wave)
Definition: Waveform.cxx:121
static QStrList * l
Definition: config.cpp:1044
static const double ms
Definition: Units.h:104
std::deque< output_pointer > output_queue
virtual bool operator()(const input_pointer &depo, output_queue &frames)
The calling signature:
Definition: Ductor.cxx:272
Binning tbins(nticks, t0, t0+readout_time)
Log::logptr_t l
Definition: Ductor.h:64
std::shared_ptr< Interface > pointer
Definition: Interface.h:16
#define THROW(e)
Definition: Exceptions.h:25
double m_start_time
Definition: Ductor.h:50
static const double cm
Definition: Units.h:59
double m_drift_speed
Definition: Ductor.h:53
Monte Carlo Simulation.
logptr_t logger(std::string name)
Definition: Logging.cxx:71
Thrown when a wrong value has been encountered.
Definition: Exceptions.h:37
static const double mm
Definition: Units.h:73
Definition: Main.h:22
IRandom::pointer m_rng
Definition: Ductor.h:45
static const double us
Definition: Units.h:101
Pimpos pimpos(nwires, min_wire_pitch, max_wire_pitch)
static const double ms
Definition: Units.h:100
IDepo::vector m_depos
Definition: Ductor.h:48
Pitch-Impact-Position.
Definition: Pimpos.h:36
std::string m_mode
Definition: Ductor.h:56
Json::Value Configuration
Definition: Configuration.h:50
std::vector< IPlaneImpactResponse::pointer > m_pirs
Definition: Ductor.h:46
std::shared_ptr< const IDepo > input_pointer
Waveform::realseq_t waveform(int wire) const
int nbins() const
Definition: Binning.h:42
QAsciiDict< Entry > ns
std::vector< float > ChargeSequence
Sequential collection of charge.
Definition: ITrace.h:21
virtual ITrace::vector process_face(IAnodeFace::pointer face, const IDepo::vector &face_depos)
Definition: Ductor.cxx:130