Classes | Public Member Functions | Private Types | Private Member Functions | Private Attributes | List of all members
WireCell::Gen::MultiDuctor Class Reference

#include <MultiDuctor.h>

Inheritance diagram for WireCell::Gen::MultiDuctor:
WireCell::IDuctor WireCell::IConfigurable WireCell::IQueuedoutNode< IDepo, IFrame > WireCell::IComponent< IConfigurable > WireCell::IQueuedoutNodeBase WireCell::Interface WireCell::INode WireCell::IComponent< INode > WireCell::Interface

Classes

struct  SubDuctor
 

Public Member Functions

 MultiDuctor (const std::string anode="AnodePlane")
 
virtual ~MultiDuctor ()
 
virtual bool operator() (const input_pointer &depo, output_queue &frames)
 The calling signature: More...
 
virtual void configure (const WireCell::Configuration &config)
 Accept a configuration. More...
 
virtual WireCell::Configuration default_configuration () const
 Optional, override to return a hard-coded default configuration. More...
 
- Public Member Functions inherited from WireCell::IDuctor
virtual ~IDuctor ()
 
virtual std::string signature ()
 
- Public Member Functions inherited from WireCell::IQueuedoutNode< IDepo, IFrame >
virtual ~IQueuedoutNode ()
 
virtual bool operator() (const boost::any &anyin, queuedany &outanyq)
 The calling signature: More...
 
virtual std::vector< std::stringinput_types ()
 
virtual std::vector< std::stringoutput_types ()
 
- Public Member Functions inherited from WireCell::IQueuedoutNodeBase
virtual ~IQueuedoutNodeBase ()
 
virtual NodeCategory category ()
 Return the behavior category type. More...
 
virtual int concurrency ()
 By default assume all subclasses maintain state. More...
 
- Public Member Functions inherited from WireCell::INode
virtual ~INode ()
 
virtual void reset ()
 
- Public Member Functions inherited from WireCell::IComponent< INode >
virtual ~IComponent ()
 
- Public Member Functions inherited from WireCell::Interface
virtual ~Interface ()
 
- Public Member Functions inherited from WireCell::IConfigurable
virtual ~IConfigurable ()
 
- Public Member Functions inherited from WireCell::IComponent< IConfigurable >
virtual ~IComponent ()
 

Private Types

typedef std::vector< SubDuctorductorchain_t
 

Private Member Functions

void merge (const output_queue &newframes)
 
void maybe_extract (const input_pointer &depo, output_queue &outframes)
 
bool start_processing (const input_pointer &depo)
 
void dump_frame (const IFrame::pointer frame, std::string msg="Gen::MultiDuctor:")
 

Private Attributes

std::string m_anode_tn
 
IAnodePlane::pointer m_anode
 
double m_tick
 
double m_start_time
 
double m_readout_time
 
int m_frame_count
 
bool m_continuous
 
bool m_eos
 
std::vector< ductorchain_tm_chains
 
output_queue m_frame_buffer
 

Additional Inherited Members

- Public Types inherited from WireCell::IDuctor
typedef std::shared_ptr< IDuctorpointer
 
- Public Types inherited from WireCell::IQueuedoutNode< IDepo, IFrame >
typedef std::shared_ptr< IQueuedoutNodeBasepointer
 
typedef IDepo input_type
 
typedef IFrame output_type
 
typedef std::shared_ptr< const IDepoinput_pointer
 
typedef std::shared_ptr< const IFrameoutput_pointer
 
typedef std::deque< output_pointeroutput_queue
 
- Public Types inherited from WireCell::IQueuedoutNodeBase
typedef std::shared_ptr< IQueuedoutNodeBasepointer
 
typedef std::deque< boost::any > queuedany
 
- Public Types inherited from WireCell::INode
enum  NodeCategory {
  unknown, sourceNode, sinkNode, functionNode,
  queuedoutNode, joinNode, splitNode, faninNode,
  fanoutNode, multioutNode, hydraNode
}
 
- Public Types inherited from WireCell::IComponent< INode >
typedef std::shared_ptr< INodepointer
 Access subclass facet by pointer. More...
 
typedef std::vector< pointervector
 Vector of shared pointers. More...
 
- Public Types inherited from WireCell::Interface
typedef std::shared_ptr< Interfacepointer
 
- Public Types inherited from WireCell::IComponent< IConfigurable >
typedef std::shared_ptr< IConfigurablepointer
 Access subclass facet by pointer. More...
 
typedef std::vector< pointervector
 Vector of shared pointers. More...
 

Detailed Description

Definition at line 22 of file MultiDuctor.h.

Member Typedef Documentation

Definition at line 57 of file MultiDuctor.h.

Constructor & Destructor Documentation

Gen::MultiDuctor::MultiDuctor ( const std::string  anode = "AnodePlane")

Definition at line 20 of file MultiDuctor.cxx.

21  : m_anode_tn(anode)
22  , m_tick(0.5*units::us)
23  , m_start_time(0.0*units::ns)
25  , m_frame_count(0)
26  , m_continuous(false)
27  , m_eos(true)
28 {
29 }
static const double ms
Definition: Units.h:104
static const double ns
Definition: Units.h:102
static const double us
Definition: Units.h:105
Gen::MultiDuctor::~MultiDuctor ( )
virtual

Definition at line 30 of file MultiDuctor.cxx.

31 {
32 }

Member Function Documentation

void Gen::MultiDuctor::configure ( const WireCell::Configuration config)
virtual

Accept a configuration.

fixme: this is totally going to break when going to two-faced anodes.

Implements WireCell::IConfigurable.

Definition at line 126 of file MultiDuctor.cxx.

127 {
128  m_readout_time = get<double>(cfg, "readout_time", m_readout_time);
129  m_tick = get<double>(cfg, "tick", m_tick);
130  m_start_time = get<double>(cfg, "start_time", m_start_time);
131  m_frame_count = get<int>(cfg, "first_frame_number", m_frame_count);
132  m_continuous = get(cfg, "continuous", m_continuous);
133 
134  m_anode_tn = get(cfg, "anode", m_anode_tn);
135  m_anode = Factory::find_tn<IAnodePlane>(m_anode_tn);
136  if (!m_anode) {
137  std::cerr << "Gen::MultiDuctor::configure: error: unknown anode: " << m_anode_tn << std::endl;
138  return;
139  }
140  auto jchains = cfg["chains"];
141  if (jchains.isNull()) {
142  std::cerr << "Gen::MultiDuctor::configure: warning: configured with empty collection of chains\n";
143  return;
144  }
145 
146  /// fixme: this is totally going to break when going to two-faced anodes.
147  if ( m_anode->faces().size() > 1 ) {
148  std::cerr << "Gen::MultDuctor:configure: warning: I currently only support a front-faced AnodePlane.\n";
149  }
150 
151  std::vector<const Pimpos*> pimpos;
152  for (auto face : m_anode->faces()) {
153  if (face->planes().empty()) {
154  std::cerr << "Gen::MultDuctor: not given multi-plane AnodeFace for face "<<face->ident()<<"\n";
155  continue;
156  }
157  for (auto plane : face->planes()) {
158  pimpos.push_back(plane->pimpos());
159  }
160  break; // fixme:
161  }
162  if (pimpos.size() != 3) {
163  std::cerr << "Gen::MultiDuctor got unexpected number planes (" << pimpos.size() <<") from anode\n";
164  THROW(ValueError() << errmsg{"Gen::MultiDuctor got unexpected number planes"});
165  }
166 
167  for (auto jchain : jchains) {
168  std::cerr << "Gen::MultiDuctor::configure chain:\n";
169  ductorchain_t dchain;
170 
171  for (auto jrule : jchain) {
172  auto rule = jrule["rule"].asString();
173  auto ductor_tn = jrule["ductor"].asString();
174  std::cerr << "\tMultiDuctor: " << ductor_tn << " rule: " << rule << std::endl;
175  auto ductor = Factory::find_tn<IDuctor>(ductor_tn);
176  if (!ductor) {
177  THROW(KeyError() << errmsg{"Failed to find (sub) Ductor: " + ductor_tn});
178  }
179  auto jargs = jrule["args"];
180  if (rule == "wirebounds") {
181  dchain.push_back(SubDuctor(ductor_tn, Wirebounds(pimpos, jargs), ductor));
182  }
183  if (rule == "bool") {
184  dchain.push_back(SubDuctor(ductor_tn, ReturnBool(jargs), ductor));
185  }
186  }
187  m_chains.push_back(dchain);
188  } // loop to store chains of ductors
189 }
IAnodePlane::pointer m_anode
Definition: MultiDuctor.h:41
boost::error_info< struct tag_errmsg, std::string > errmsg
Definition: Exceptions.h:54
cfg
Definition: dbjson.py:29
std::vector< SubDuctor > ductorchain_t
Definition: MultiDuctor.h:57
#define THROW(e)
Definition: Exceptions.h:25
std::vector< ductorchain_t > m_chains
Definition: MultiDuctor.h:58
Pimpos pimpos(nwires, min_wire_pitch, max_wire_pitch)
QTextStream & endl(QTextStream &s)
WireCell::Configuration Gen::MultiDuctor::default_configuration ( ) const
virtual

Optional, override to return a hard-coded default configuration.

The initial time for this ductor

The time span for each readout.

If false then determine start time of each readout based on the input depos. This option is useful when running WCT sim on a source of depos which have already been "chunked" in time. If true then this Ductor will continuously simulate all time in "readout_time" frames leading to empty frames in the case of some readout time with no depos.

Allow for a custom starting frame number

Reimplemented from WireCell::IConfigurable.

Definition at line 34 of file MultiDuctor.cxx.

35 {
36  // The "chain" is a list of dictionaries. Each provides:
37  // - ductor: TYPE[:NAME] of a ductor component
38  // - rule: name of a rule function to apply
39  // - args: args for the rule function
40  //
41  // Rule functions:
42  // wirebounds (list of wire ranges)
43  // bool (true/false)
44 
46  cfg["anode"] = m_anode_tn;
47  cfg["chain"] = Json::arrayValue;
48 
49  // must be consistent with subductors
50  cfg["tick"] = m_tick;
51 
52  /// The initial time for this ductor
53  cfg["start_time"] = m_start_time;
54 
55  /// The time span for each readout.
56  cfg["readout_time"] = m_readout_time;
57 
58  /// If false then determine start time of each readout based on the
59  /// input depos. This option is useful when running WCT sim on a
60  /// source of depos which have already been "chunked" in time. If
61  /// true then this Ductor will continuously simulate all time in
62  /// "readout_time" frames leading to empty frames in the case of
63  /// some readout time with no depos.
64  cfg["continuous"] = m_continuous;
65 
66  /// Allow for a custom starting frame number
67  cfg["first_frame_number"] = m_frame_count;
68 
69  return cfg;
70 }
cfg
Definition: dbjson.py:29
Json::Value Configuration
Definition: Configuration.h:50
void Gen::MultiDuctor::dump_frame ( const IFrame::pointer  frame,
std::string  msg = "Gen::MultiDuctor:" 
)
private

Definition at line 221 of file MultiDuctor.cxx.

222 {
223  auto traces = frame->traces();
224  if (!traces or traces->empty()) {
225  std::cerr << msg
226  << " fid:" << frame->ident()
227  << " has no traces\n";
228  return;
229  }
230 
231  auto mm = FrameTools::tbin_range(*traces);
232  std::cerr << msg
233  << " fid:" << frame->ident()
234  << " #ch:" << traces->size()
235  << " t:" << std::setprecision(12) << m_start_time/units::us<<"us "
236  << " tbins:["<<mm.first<<","<<mm.second<<"]\n";
237 }
void msg(const char *fmt,...)
Definition: message.cpp:107
Q_EXPORT QTSManip setprecision(int p)
Definition: qtextstream.h:343
std::pair< int, int > tbin_range(const ITrace::vector &traces)
Definition: FrameTools.cxx:143
static const double mm
Definition: Units.h:73
static const double us
Definition: Units.h:105
void Gen::MultiDuctor::maybe_extract ( const input_pointer depo,
output_queue outframes 
)
private

Big fat lazy programmer FIXME: there is a bug waiting to bite here. If somehow a sub-ductor manages to make a frame that remains bigger than m_readout_time after the split() above, it will cause the final output frame to extend past requested duration. There needs to be a loop over to_extract added.

Big fat lazy programmer FIXME v2: there can be multiple traces on the same channel which may overlap in time.

Definition at line 240 of file MultiDuctor.cxx.

241 {
242  if (!start_processing(depo)) { // may set m_start_time
243  return;
244  }
245 
246  // Must flush all sub-ductors to assure synchronization.
247  for (auto& chain : m_chains) {
248  for (auto& sd : chain) {
249  output_queue newframes;
250  (*sd.ductor)(nullptr, newframes); // flush with EOS marker
251  merge(newframes); // updates frame buffer
252  }
253  }
254 
255  // we must read out, and yet we have nothing
256  //
257  // fixme: the default behavior of this is to make sequential
258  // blocks of m_readout_time even if there be no data. Need to
259  // also handle a more isolated running where the readout window is
260  // data driven up until EOS is found.
261  if (!m_frame_buffer.size()) {
262 
263  std::cerr << "MultiDuctor: returning empty frame with "<<m_frame_count
264  << " at " << m_start_time << "\n";
265 
266  ITrace::vector traces;
267  auto frame = std::make_shared<SimpleFrame>(m_frame_count, m_start_time, traces, m_tick);
268  outframes.push_back(frame);
269 
270  m_start_time += m_readout_time;
271  ++m_frame_count;
272  return;
273  }
274 
275 
276  // At this point the m_frame_buffer has at least some frames from
277  // multiple sub-ductors, each of different time and channel extent
278  // and potentially out of order.
279 
280 
281  const double target_time = m_start_time + m_readout_time;
282  output_queue to_keep, to_extract;
283  for (auto frame: m_frame_buffer) {
284  if (!frame) {
285  std::cerr << "Gen::MultiDuctor: skipping null frame in frame buffer\n";
286  continue;
287  }
288  if (!frame->traces()) {
289  std::cerr << "Gen::MultiDuctor: skipping empty frame in frame buffer\n";
290  continue;
291  }
292 
293  {
294  const double tick = frame->tick();
295  if (std::abs(tick - m_tick) > 0.0001) {
296  std::cerr << "MultiDuctor: configuration error: got different tick in frame from sub-ductor = "
297  << tick/units::us << "us, mine = " << m_tick/units::us << "us\n";
298  THROW(ValueError() << errmsg{"tick size mismatch"});
299  }
300  }
301 
302  int cmp = FrameTools::frmtcmp(frame, target_time);
303  // std::cerr << "Gen::MultiDuctor: checking to keep: "
304  // << std::setprecision(12)
305  // << "t_target=" << target_time/units::us << "us, "
306  // << "cmp returns " << cmp << ", frame is:\n";
307  // dump_frame(frame, "\t");
308 
309  if (cmp < 0) {
310  to_extract.push_back(frame);
311  continue;
312  }
313  if (cmp > 0) {
314  to_keep.push_back(frame);
315  continue;
316  }
317 
318  // If cmp==0 above then both halves of the pair should hold a frame.
319  auto ff = FrameTools::split(frame, target_time);
320  if (ff.first) {
321  to_extract.push_back(ff.first);
322  //dump_frame(ff.first, "Gen::MultiDuctor: to extract");
323  }
324  else {
325  std::cerr << "Gen::MultiDuctor: error: early split is null\n";
326  }
327 
328  if (ff.second) {
329  to_keep.push_back(ff.second);
330  //dump_frame(ff.second, "Gen::MultiDuctor: to keep");
331  }
332  else {
333  std::cerr << "Gen::MultiDuctor: error: late split is null\n";
334  }
335 
336  }
337  m_frame_buffer = to_keep;
338 
339  if (!to_extract.size()) {
340  // we read out, and yet we have nothing
341 
342  std::cerr << "MultiDuctor: returning empty frame after sub frame sorting with "
343  << m_frame_count<<" at " << m_start_time << "\n";
344 
345  ITrace::vector traces;
346  auto frame = std::make_shared<SimpleFrame>(m_frame_count, m_start_time, traces, m_tick);
347  outframes.push_back(frame);
348  m_start_time += m_readout_time;
349  ++m_frame_count;
350  return;
351  }
352 
353 
354  /// Big fat lazy programmer FIXME: there is a bug waiting to bite
355  /// here. If somehow a sub-ductor manages to make a frame that
356  /// remains bigger than m_readout_time after the split() above, it
357  /// will cause the final output frame to extend past requested
358  /// duration. There needs to be a loop over to_extract added.
359 
360  /// Big fat lazy programmer FIXME v2: there can be multiple traces
361  /// on the same channel which may overlap in time.
362 
363  ITrace::vector traces;
364  for (auto frame: to_extract) {
365  const double tref = frame->time();
366  const int extra_tbins = (tref-m_start_time)/m_tick;
367  for (auto trace : (*frame->traces())) {
368  const int tbin = trace->tbin() + extra_tbins;
369  const int chid = trace->channel();
370  // std::cerr <<traces.size()
371  // <<" tstart="<<m_start_time/units::us<<"us"
372  // <<" tref="<<tref/units::us << "us"
373  // <<" tbin="<<tbin
374  // <<" extra bins="<< extra_tbins<<" chid="<<chid<<"\n";
375  auto mtrace = std::make_shared<SimpleTrace>(chid, tbin, trace->charge());
376  traces.push_back(mtrace);
377  }
378  }
379  auto frame = std::make_shared<SimpleFrame>(m_frame_count, m_start_time, traces, m_tick);
380  dump_frame(frame, "Gen::MultiDuctor: output frame");
381 
382  outframes.push_back(frame);
383  m_start_time += m_readout_time;
384  ++m_frame_count;
385 }
void merge(const output_queue &newframes)
boost::error_info< struct tag_errmsg, std::string > errmsg
Definition: Exceptions.h:54
std::vector< pointer > vector
Definition: IData.h:21
const double tick
std::deque< output_pointer > output_queue
void dump_frame(const IFrame::pointer frame, std::string msg="Gen::MultiDuctor:")
T abs(T value)
#define THROW(e)
Definition: Exceptions.h:25
int frmtcmp(IFrame::pointer frame, double time)
Definition: FrameTools.cxx:14
std::vector< ductorchain_t > m_chains
Definition: MultiDuctor.h:58
std::pair< IFrame::pointer, IFrame::pointer > split(IFrame::pointer frame, double time)
Definition: FrameTools.cxx:32
output_queue m_frame_buffer
Definition: MultiDuctor.h:65
static const double us
Definition: Units.h:105
bool start_processing(const input_pointer &depo)
void Gen::MultiDuctor::merge ( const output_queue newframes)
private

Definition at line 387 of file MultiDuctor.cxx.

388 {
389  for (auto frame : newframes) {
390  if (!frame) { continue; } // skip internal EOS
391  auto traces = frame->traces();
392  if (!traces) { continue; }
393  if (traces->empty()) { continue; }
394 
395  //dump_frame(frame, "Gen::MultiDuctor: merging frame");
396  m_frame_buffer.push_back(frame);
397  }
398 }
output_queue m_frame_buffer
Definition: MultiDuctor.h:65
bool Gen::MultiDuctor::operator() ( const input_pointer in,
output_queue outq 
)
virtual

The calling signature:

Implements WireCell::IQueuedoutNode< IDepo, IFrame >.

Definition at line 400 of file MultiDuctor.cxx.

401 {
402  // end of stream processing
403  if (!depo) {
404  //std::cerr << "Gen::MultiDuctor: end of stream processing\n";
405  maybe_extract(depo, outframes);
406  outframes.push_back(nullptr); // pass on EOS marker
407  if (!m_frame_buffer.empty()) {
408  std::cerr << "Gen::MultiDuctor: purging " << m_frame_buffer.size() << " frames at EOS\n";
409  for (auto frame : m_frame_buffer) {
410  dump_frame(frame, "\t");
411  }
412  m_frame_buffer.clear();
413  }
414  return true;
415  }
416 
417 
418  // check each rule in the chain to find match
419  bool all_okay = true;
420  int count = 0;
421  for (auto& chain : m_chains) {
422 
423  for (auto& sd : chain) {
424 
425  if (!sd.check(depo)) {
426  continue;
427  }
428 
429  // found a matching sub-ductor
430  ++count;
431 
432  // Normal buffered processing.
433  output_queue newframes;
434  bool ok = (*sd.ductor)(depo, newframes);
435  merge(newframes);
436  all_okay = all_okay && ok;
437 
438  // got a match so abandon chain
439  break;
440  }
441  }
442  if (count == 0) {
443  std::cerr << "Gen::MultiDuctor: warning: no appropriate Ductor for depo at: "
444  << depo->pos() << std::endl;
445  }
446 
447  maybe_extract(depo, outframes);
448  if (outframes.size()) {
449  std::cerr << "Gen::MultiDuctor: returning " << outframes.size() << " frames\n";
450  }
451  return true;
452 }
void merge(const output_queue &newframes)
std::deque< output_pointer > output_queue
void dump_frame(const IFrame::pointer frame, std::string msg="Gen::MultiDuctor:")
void maybe_extract(const input_pointer &depo, output_queue &outframes)
std::vector< ductorchain_t > m_chains
Definition: MultiDuctor.h:58
output_queue m_frame_buffer
Definition: MultiDuctor.h:65
QTextStream & endl(QTextStream &s)
bool Gen::MultiDuctor::start_processing ( const input_pointer depo)
private

Definition at line 204 of file MultiDuctor.cxx.

205 {
206  if (!depo) {
207  m_eos = true;
208  return true;
209  }
210  if (!m_continuous) {
211  if (depo && m_eos) {
212  m_eos = false;
213  m_start_time = depo->time();
214  return false;
215  }
216  }
217  return depo->time() > m_start_time + m_readout_time;
218 }

Member Data Documentation

IAnodePlane::pointer WireCell::Gen::MultiDuctor::m_anode
private

Definition at line 41 of file MultiDuctor.h.

std::string WireCell::Gen::MultiDuctor::m_anode_tn
private

Definition at line 40 of file MultiDuctor.h.

std::vector<ductorchain_t> WireCell::Gen::MultiDuctor::m_chains
private

Definition at line 58 of file MultiDuctor.h.

bool WireCell::Gen::MultiDuctor::m_continuous
private

Definition at line 46 of file MultiDuctor.h.

bool WireCell::Gen::MultiDuctor::m_eos
private

Definition at line 47 of file MultiDuctor.h.

output_queue WireCell::Gen::MultiDuctor::m_frame_buffer
private

As sub ductors are called they will each return frames which are not in general synchronized with the others. Their frames must be buffered here and released as a merged frame in order for MultiDuctor to behave just like a monolithic ductor.

Definition at line 65 of file MultiDuctor.h.

int WireCell::Gen::MultiDuctor::m_frame_count
private

Definition at line 45 of file MultiDuctor.h.

double WireCell::Gen::MultiDuctor::m_readout_time
private

Definition at line 44 of file MultiDuctor.h.

double WireCell::Gen::MultiDuctor::m_start_time
private

Definition at line 43 of file MultiDuctor.h.

double WireCell::Gen::MultiDuctor::m_tick
private

Definition at line 42 of file MultiDuctor.h.


The documentation for this class was generated from the following files: