PDDPChannelMap_service.cc
Go to the documentation of this file.
1 ////////////////////////////////////////////////////////////////////////
2 // Class: PDDPChannelMap
3 // Plugin Type: service (art v3_02_06)
4 // File: PDDPChannelMap_service.cc
5 //
6 // Generated at Thu Jul 18 10:29:03 2019 by Vyacheslav Galymov using cetskelgen
7 // from cetlib version v3_07_02.
8 //
9 //
10 // Classes to facility channel order translation between different
11 // representations
12 //
13 // seqn - unique counter to give channel data position in the record
14 // crate - utca crate number starting
15 // card - AMC card number
16 // cardch - AMC card channel number
17 // crp - CRP number
18 // view - view number (0/1)
19 // viewch - view channel number
20 //
21 // Boost multi_index_container provides interface to search and order various
22 // indicies. The container structure is defined in DPChannelTable, which has
23 // the following interfaces:
24 // - raw sequence index, tag IndexRawSeqn
25 // - crate number, tag IndexCrate, to get all channels to a given crate
26 // - crate number and card number, tag IndexCrateCard,
27 // to get all channels for a given card in a crate
28 // - crate, card, and channel number, tag IndexCrateCardChan, to access
29 // a given channel of a given card in a given crate
30 // - CRP index, tag IndexCrp, to access channels assigned to a given CRP
31 // - CRP index and view index, tag IndexCrpView, to access channels assigned to
32 // a given view in a specified CRP
33 // - CRP index, view index, and channel number, tag IndexCrpViewChan, to access
34 // a given view channel in a given CRP
35 //
36 ////////////////////////////////////////////////////////////////////////
37 
38 #include <boost/range.hpp>
39 #include <boost/range/adaptors.hpp>
40 
41 #include <iostream>
42 #include <iomanip>
43 #include <utility>
44 
45 #include "PDDPChannelMap.h"
46 
48 
49 using namespace dune;
50 
51 //class PDDPChannelMap;
52 
53 
54 
55 //
56 // ctor
58 {
59  mapname_ = "";
60  ntot_ = 0;
61  ncrates_ = 0;
62  ncrps_ = 0;
63  nch_ = 64;
64 
65  std::string MapName = p.get<std::string>("MapName", "pddp2crp");
66  // for test maps one can also specify Nb of crates, cards per crate, and views
67  unsigned ncrateInMap = p.get<unsigned>("MapCrateNb", 1);
68  unsigned ncardsInMap = p.get<unsigned>("MapCardNb", 10);
69  unsigned nviewsInMap = p.get<unsigned>("MapViewNb", 1);
70 
71  //initialize channel map
72  initMap( MapName, ncrateInMap, ncardsInMap, nviewsInMap );
73 }
74 
75 
76 //
77 // initMap
79  unsigned ncards, unsigned nviews )
80 {
81  // already defined?
82  if( mapname_.compare( mapname ) == 0 )
83  {
84  //cout<<"nothing to do"<<endl;
85  return;
86  }
87 
88  clearMap();
89  mapname_ = mapname;
90  if( mapname.compare("pddp2crp") == 0 )
91  pddp2crpMap();
92  else if( mapname.compare("pddp4crp") == 0 )
93  pddp4crpMap();
94  else
95  simpleMap( ncrates, ncards, nviews );
96 }
97 
98 
99 //
100 // clearMap
102 {
103  DPChannelTable().swap( chanTable );
104  ncrates_ = 0;
105  ncrps_ = 0;
106  ntot_ = 0;
107  mapname_ = "";
108  crateidx_.clear();
109  crpidx_.clear();
110 }
111 
112 
113 //
114 // a simple channel map for testing purposes
115 void PDDPChannelMap::simpleMap( unsigned ncrates, unsigned ncards, unsigned nviews )
116 {
117  unsigned nctot = ncards * ncrates; // total number of cards
118  unsigned ncview = nctot / nviews; // allocate the same for each view
119  unsigned nch = nch_; // number of ch per card (fixed)
120 
121  unsigned seqn = 0;
122  unsigned crate = 0;
123  unsigned crp = 0;
124  unsigned view = 0;
125  unsigned vch = 0;
126  for( unsigned card = 0; card < nctot; card++ )
127  {
128  if( card > 0 )
129  {
130  if( card % ncards == 0 ) crate++;
131  if( card % ncview == 0 ) {view++; vch=0;}
132  }
133  for( unsigned ch = 0; ch < nch; ch++ )
134  {
135  add( seqn++, crate, card % ncards, ch, crp, view, vch++);
136  //cout<<seqn<<" "<<crate<<" "<<card%ncards
137  }
138  }
139  //
140 }
141 
142 
143 //
144 // The channel map for 2 CRP configuration
146 {
147  // all idices run from 0
148  std::vector<unsigned> cards_per_crate_real{5, 5, 5, 10, 5, 5, 10, 10, 10, 5};
149  unsigned ncrates = 12; // only 10 are active
150  std::vector<unsigned> cards_per_crate(ncrates, 10);
151  unsigned nch = 64;
152  unsigned nchc = nch/2; // logical data channels per KEL/VHDCI connector
153  unsigned ncrp = 4; // only 2 are active
154  std::vector<unsigned> crpv(2*ncrp, 0);
155 
156  // map to TPC # in larsoft
157  std::vector<unsigned> dunetpcno = {3, 1, 0, 2};
158 
159  // all connector mappings should include ADC channel inversion on AMC
160  // this inversion is in groups of 8ch, i.e., AMC ch 0 -> 7 should be remapped to 7 -> 0
161  // the connector mappings below should be (re)generated with the python script card2crp.py
162 
163  // kel connector orientation in a given view, chans 0 -> 31
164  std::vector<unsigned> kel_nor = { 7, 6, 5, 4, 3, 2, 1, 0, 15, 14, 13, 12, 11, 10, 9, 8, 23, 22, 21, 20, 19, 18, 17, 16, 31, 30, 29, 28, 27, 26, 25, 24 };
165  // kel connector orientation in a given view, chans 31 -> 0
166  std::vector<unsigned> kel_inv = {24, 25, 26, 27, 28, 29, 30, 31, 16, 17, 18, 19, 20, 21, 22, 23, 8, 9, 10, 11, 12, 13, 14, 15, 0, 1, 2, 3, 4, 5, 6, 7 };
167 
168  //
169  unsigned seqn = 0;
170  unsigned crp, view;
171  for(unsigned crate = 0;crate<ncrates;crate++)
172  {
173  // number of cards in this crate
174  unsigned ncards = cards_per_crate[ crate ];
175  for( unsigned card = 0;card<ncards;card++ )
176  {
177  // which view ?
178  if( crate < 6 ) view = 0;
179  else view = 1;
180 
181  // which CRP ?
182  if( crate < 3 )
183  {
184  crp = 1;
185  if( card >= 5 ) crp = 2;
186  }
187  else if( crate >= 3 && crate < 6 )
188  {
189  crp = 0;
190  if( card >= 5 ) crp = 3;
191  }
192  else if( crate >=6 && crate < 9 )
193  {
194  crp = 0;
195  if( card >= 5 ) crp = 1;
196  }
197  else
198  {
199  crp = 3;
200  if( card >= 5 ) crp = 2;
201  }
202 
203 
204  // get iterator to view channel numbering
205  auto kel = kel_inv; // inverted order
206  bool topAmcFirst = true;
207  if( view == 0 )
208  {
209  kel = kel_nor; //normal order
210  topAmcFirst = false;
211  }
212 
213  auto vchIt = crpv.begin() + view * ncrp + crp;
214 
215  if( topAmcFirst ) // bot connector goes second
216  *vchIt = *vchIt + nchc;
217 
218  unsigned cstart = 0; // bottom AMC connector
219  for( unsigned ch = cstart; ch<cstart+nchc; ch++ )
220  {
221  int idx = ch - cstart;
222  if( idx < 0 || idx >= (int)kel.size() )
223  {
224  // should not happen
225  std::cerr<<"I screwed this up\n";
226  continue;
227  }
228  // view channel
229  unsigned vch = *vchIt + kel[ idx ];
230  if( view == 1 )
231  {
232  int ival = -vch + 959;
233  if( ival < 0 )
234  {
235  std::cerr<<"Bad view channel number\n";
236  continue;
237  }
238  vch = (unsigned)ival;
239  }
240 
241  // check if the channel actually exits
242  // since l1evb writes in the same format
243  unsigned state = 0;
244  if( crate >= cards_per_crate_real.size() )
245  {
246  state = 1;
247  }
248  else
249  {
250  if( card >= cards_per_crate_real[ crate ] )
251  state = 1;
252  }
253 
254  //add( seqn++, crate, card, ch, crp, view, vch, state );
255  unsigned tpc = dunetpcno[ crp ];
256  unsigned kview = (view == 0 ) ? 1:0;
257  add( seqn++, crate, card, ch, tpc, kview, vch, state );
258  }
259 
260  if( topAmcFirst ) // first half: top connector is first
261  *vchIt = *vchIt - nchc;
262  else
263  *vchIt = *vchIt + nchc;
264 
265  // move to the second connector
266  cstart = nchc; // top amc connector
267  for( unsigned ch = cstart; ch<cstart+nchc; ch++ )
268  {
269  int idx = ch - cstart;
270  if( idx < 0 || idx >= (int)kel.size() )
271  {
272  // should not happen
273  std::cerr<<"I screwed this up\n";
274  continue;
275  }
276  // view channel
277  unsigned vch = *vchIt + kel[ idx ];
278  if( view == 1 )
279  {
280  int ival = -vch + 959;
281  if( ival < 0 )
282  {
283  std::cerr<<"Bad view channel number\n";
284  continue;
285  }
286  vch = (unsigned)ival;
287  }
288 
289  // check if the channel actually exits
290  // since l1evb writes in the same format
291  unsigned state = 0;
292  if( crate >= cards_per_crate_real.size() )
293  {
294  state = 1;
295  }
296  else
297  {
298  if( card >= cards_per_crate_real[ crate ] )
299  state = 1;
300  }
301 
302  //add( seqn++, crate, card, ch, crp, view, vch, state );
303  unsigned tpc = dunetpcno[ crp ];
304  unsigned kview = (view == 0 ) ? 1:0;
305  add( seqn++, crate, card, ch, tpc, kview, vch, state );
306 
307  }
308 
309  // all done
310  if( topAmcFirst )
311  *vchIt = *vchIt + nch;
312  else
313  *vchIt = *vchIt + nchc;
314 
315  //
316  }
317  }
318 }
319 
320 //
321 // The channel map for 4 CRP configuration
322 // DO NOT USE until this configuration actually exists
324 {
325  // NEEDS TO BE FIXED
326 
327  // all idices run from 0
328  unsigned ncrates = 12;
329  std::vector<unsigned> cards_per_crate(ncrates, 10);
330  unsigned nch = 64;
331  unsigned ncrp = 4;
332  std::vector<unsigned> crpv(2*ncrp, 0);
333 
334  //
335  unsigned seqn = 0;
336  unsigned crp, view;
337  for(unsigned crate = 0;crate<ncrates;crate++)
338  {
339  // number of cards in this crate
340  unsigned ncards = cards_per_crate[ crate ];
341  for( unsigned card = 0;card<ncards;card++ )
342  {
343  // which view ?
344  if( crate < 6 ) view = 0;
345  else view = 1;
346 
347  // which CRP ?
348  if( crate < 3 )
349  {
350  crp = 1;
351  if( card >= 5 ) crp = 2;
352  }
353  else if( crate >= 3 && crate < 6 )
354  {
355  crp = 0;
356  if( card >= 5 ) crp = 3;
357  }
358  else if( crate >=6 && crate < 9 )
359  {
360  crp = 0;
361  if( card >= 5 ) crp = 1;
362  }
363  else
364  {
365  crp = 3;
366  if( card >= 5 ) crp = 2;
367  }
368 
369 
370  // get iterator to view channel numbering
371  auto vchIt = crpv.begin() + view * ncrp + crp;
372 
373  int apara = 1;
374  int bpara = 0;
375  if( view == 0 )
376  {
377  // order 31 -> 0 for these KEL connectors
378  apara = -1;
379  bpara = 31;
380  }
381  // card channels
382  for( unsigned ch = 0; ch<nch; ch++ )
383  {
384  if( ch == nch/2 ) *vchIt = *vchIt + nch/2;
385  int tmp = apara * (ch % 32) + bpara;
386  if( tmp < 0 )
387  {
388  std::cerr<<"oh oh I screwed up\n";
389  continue;
390  }
391 
392  unsigned vch = *vchIt + tmp;
393  add( seqn++, crate, card, ch, crp, view, vch );
394  }
395  // add the second connector
396  *vchIt = *vchIt + nch/2;
397 
398  //
399  }
400  }
401 }
402 
403 //
404 // add channl ID to map
405 void PDDPChannelMap::add( unsigned seq, unsigned crate, unsigned card, unsigned cch,
406  unsigned crp, unsigned view, unsigned vch, unsigned short state )
407 {
408  chanTable.insert( DPChannelId(seq, crate, card, cch, crp, view, vch, state) );
409  //
410  ntot_ = chanTable.size();
411 
412  //if( state == 0 ) //existing channels only
413  //{
414  crateidx_.insert( crate );
415  ncrates_ = crateidx_.size();
416 
417  crpidx_.insert( crp );
418  ncrps_ = crpidx_.size();
419  //}
420 
421  //
422  //ncrates_ = cdistinct( chanTable.get<IndexCrateCardChan>(),
423  //[](const DPChannelId& c){ return c.crate();} );
424 
425  //
426  //ncrps_ = cdistinct( chanTable.get<IndexCrpViewChan>(),
427  //[](const DPChannelId& c){ return c.crp();} );
428 }
429 
430 //
431 //
432 //
433 boost::optional<DPChannelId> PDDPChannelMap::find_by_seqn( unsigned seqn ) const
434 {
435  auto it = chanTable.get<IndexRawSeqnHash>().find( seqn );
436  if( it != chanTable.get<IndexRawSeqnHash>().end() )
437  return *it;
438 
439  return boost::optional<DPChannelId>();
440 }
441 
442 //
443 // the most low level info
444 std::vector<DPChannelId> PDDPChannelMap::find_by_seqn( unsigned from, unsigned to ) const
445 {
446  if( to < from ) std::swap( from, to );
447 
448  std::vector<DPChannelId> res;
449 
450  if( from == to )
451  {
452  if( boost::optional<DPChannelId> id = find_by_seqn( from ) )
453  res.push_back( *id );
454  //auto it = chanTable.find(from);
455  //if( it != chanTable.end() )
456  //res.push_back( *it );
457  }
458  else
459  {
460  auto first = chanTable.get<IndexRawSeqn>().lower_bound( from );
461  auto last = chanTable.get<IndexRawSeqn>().upper_bound( to );
462  res.insert( res.begin(), first, last );
463  }
464 
465  return res;
466 }
467 
468 //
469 //
470 std::vector<DPChannelId> PDDPChannelMap::find_by_crate( unsigned crate, bool ordered ) const
471 {
472  if( not ordered ) // get from hashed index
473  {
474  const auto r = chanTable.get<IndexCrate>().equal_range( crate );
475  std::vector<DPChannelId> res(r.first, r.second);
476  return res;
477  }
478 
479  const auto r = chanTable.get<IndexCrateCardChan>().equal_range( boost::make_tuple(crate) );
480  std::vector<DPChannelId> res(r.first, r.second);
481 
482  return res;
483 }
484 
485 //
486 //
487 std::vector<DPChannelId> PDDPChannelMap::find_by_crate_card( unsigned crate, unsigned card, bool ordered ) const
488 {
489  if( not ordered ) // get from hashed index
490  {
491  const auto r = chanTable.get<IndexCrateCard>().equal_range( boost::make_tuple(crate, card) );
492  std::vector<DPChannelId> res(r.first, r.second);
493  return res;
494  }
495 
496  // ordered accodring to channel number
497  const auto r = chanTable.get<IndexCrateCardChan>().equal_range( boost::make_tuple( crate, card) );
498  std::vector<DPChannelId> res(r.first, r.second);
499 
500  return res;
501 }
502 
503 //
504 //
505 boost::optional<DPChannelId> PDDPChannelMap::find_by_crate_card_chan( unsigned crate,
506  unsigned card, unsigned chan ) const
507 {
508  auto it = chanTable.get<IndexCrateCardChanHash>().find( boost::make_tuple(crate, card, chan) );
509  if( it != chanTable.get<IndexCrateCardChanHash>().end() )
510  return *it;
511 
512  return boost::optional<DPChannelId>();
513 }
514 
515 //
516 //
517 std::vector<DPChannelId> PDDPChannelMap::find_by_crp( unsigned crp, bool ordered ) const
518 {
519  if( not ordered ) // get from hashed index
520  {
521  const auto r = chanTable.get<IndexCrp>().equal_range( crp );
522  std::vector<DPChannelId> res(r.first, r.second);
523  return res;
524  }
525 
526  const auto r = chanTable.get<IndexCrpViewChan>().equal_range( crp );
527  std::vector<DPChannelId> res(r.first, r.second);
528  //return res;
529  return res;
530 }
531 
532 //
533 //
534 std::vector<DPChannelId> PDDPChannelMap::find_by_crp_view( unsigned crp, unsigned view, bool ordered ) const
535 {
536  if( not ordered ) // get from hashed index
537  {
538  const auto r = chanTable.get<IndexCrpView>().equal_range( boost::make_tuple(crp, view) );
539  std::vector<DPChannelId> res(r.first, r.second);
540  return res;
541  }
542 
543  // ordered accodring to channel number
544  const auto r = chanTable.get<IndexCrpViewChan>().equal_range( boost::make_tuple(crp, view) );
545  std::vector<DPChannelId> res(r.first, r.second);
546  return res;
547 }
548 
549 //
550 //
551 boost::optional<DPChannelId> PDDPChannelMap::find_by_crp_view_chan( unsigned crp,
552  unsigned view, unsigned chan ) const
553 {
554  auto it = chanTable.get<IndexCrpViewChanHash>().find( boost::make_tuple(crp, view, chan) );
555  if( it != chanTable.get<IndexCrpViewChanHash>().end() )
556  return *it;
557 
558  return boost::optional<DPChannelId>();
559 }
560 
561 //
562 // Map to CRP channels
563 int PDDPChannelMap::MapToCRP(int seqch, int &crp, int &view, int &chv) const
564 {
565  crp = view = chv = -1;
566  if( boost::optional<DPChannelId> id = find_by_seqn( (unsigned)seqch ) )
567  {
568  if( !id->exists() ) return -1;
569  crp = id->crp();
570  view = id->view();
571  chv = id->viewch();
572  return 1;
573  }
574 
575  return -1;
576 }
577 
578 //
579 // Map to DAQ channel sequence
580 int PDDPChannelMap::MapToDAQ(int crp, int view, int chv, int &seqch) const
581 {
582  seqch = -1;
583  if( boost::optional<DPChannelId> id = find_by_crp_view_chan( (unsigned)crp, (unsigned)view, (unsigned)chv ) )
584  {
585  if( !id->exists() ) return -1;
586  seqch = id->seqn();
587  return 1;
588  }
589  return -1;
590 }
591 
592 //
593 // number of cards assigned to a given crate
594 unsigned PDDPChannelMap::ncards( unsigned crate ) const
595 {
596  // assumes it is sorted according to card number
597  unsigned count = 0;
598  auto r = chanTable.get<IndexCrateCardChan>().equal_range( crate );
599  ssize_t last = -1;
600  for( DPChannelId const &ch : boost::make_iterator_range( r ) )
601  {
602  if( !ch.exists() ) continue;
603  unsigned val = ch.card();
604  if( val != last )
605  {
606  count++;
607  last = val;
608  }
609  }
610 
611  return count;
612 }
613 
614 //
615 // number of views assigned to a given CRP
616 unsigned PDDPChannelMap::nviews( unsigned crp ) const
617 {
618  // assumes it is sorted according to crp number
619  unsigned count = 0;
620  auto r = chanTable.get<IndexCrpViewChan>().equal_range( crp );
621  ssize_t last = -1;
622  for( DPChannelId const &ch : boost::make_iterator_range( r ) )
623  {
624  if( !ch.exists() ) continue;
625  unsigned val = ch.view();
626  if( val != last )
627  {
628  count++;
629  last = val;
630  }
631  }
632 
633  return count;
634 }
635 
636 //
637 //
638 void PDDPChannelMap::print( std::vector<DPChannelId> &vec )
639 {
640  for( auto it = vec.begin();it!=vec.end();++it )
641  {
642  unsigned seqn = it->seqn();
643  unsigned crate = it->crate();
644  unsigned card = it->card();
645  unsigned cch = it->cardch();
646  unsigned crp = it->crp();
647  unsigned view = it->view();
648  unsigned vch = it->viewch();
649  unsigned state = it->state();
650  bool exists = it->exists();
651  std::cout<<std::setw(7)<<seqn
652  <<std::setw(4)<<crate
653  <<std::setw(3)<<card
654  <<std::setw(3)<<cch
655  <<std::setw(3)<<crp
656  <<std::setw(2)<<view
657  <<std::setw(4)<<vch
658  <<std::setw(2)<<state
659  <<std::setw(2)<<exists<<std::endl;
660  }
661 }
662 
663 
664 
int MapToDAQ(int crp, int view, int chv, int &seqch) const
boost::optional< DPChannelId > find_by_seqn(unsigned seqn) const
crate(int id, int cards)
int MapToCRP(int seqch, int &crp, int &view, int &chv) const
std::string string
Definition: nybbler.cc:12
PDDPChannelMap(fhicl::ParameterSet const &p, art::ActivityRegistry &areg)
std::set< unsigned > crateidx_
void simpleMap(unsigned ncrates, unsigned ncards, unsigned nviews)
std::vector< DPChannelId > find_by_crate_card(unsigned crate, unsigned card, bool ordered=true) const
unsigned ncards(unsigned crate) const
std::vector< DPChannelId > find_by_crp_view(unsigned crp, unsigned view, bool ordered=true) const
bool exists(std::string path)
unsigned nviews(unsigned crp) const
void add(unsigned seq, unsigned crate, unsigned card, unsigned cch, unsigned crp, unsigned view, unsigned vch, unsigned short state=0)
void swap(Handle< T > &a, Handle< T > &b)
std::vector< DPChannelId > find_by_crate(unsigned crate, bool ordered=true) const
struct dune::tde::crate crate
void initMap(std::string mapname, unsigned ncrates=1, unsigned ncards=10, unsigned nviews=1)
T get(std::string const &key) const
Definition: ParameterSet.h:271
p
Definition: test.py:223
DPChannelTable chanTable
string tmp
Definition: languages.py:63
void print(std::vector< DPChannelId > &vec)
Q_EXPORT QTSManip setw(int w)
Definition: qtextstream.h:331
boost::optional< DPChannelId > find_by_crp_view_chan(unsigned crp, unsigned view, unsigned chan) const
#define DEFINE_ART_SERVICE(svc)
multi_index_container< DPChannelId, indexed_by< ordered_unique< tag< IndexRawSeqn >, const_mem_fun< DPChannelId, const unsigned,&DPChannelId::seqn > >, hashed_unique< tag< IndexRawSeqnHash >, const_mem_fun< DPChannelId, const unsigned,&DPChannelId::seqn > >, hashed_non_unique< tag< IndexCrate >, const_mem_fun< DPChannelId, const unsigned short,&DPChannelId::crate > >, hashed_non_unique< tag< IndexCrateCard >, composite_key< DPChannelId, const_mem_fun< DPChannelId, const unsigned short,&DPChannelId::crate >, const_mem_fun< DPChannelId, const unsigned short,&DPChannelId::card > > >, ordered_unique< tag< IndexCrateCardChan >, composite_key< DPChannelId, const_mem_fun< DPChannelId, const unsigned short,&DPChannelId::crate >, const_mem_fun< DPChannelId, const unsigned short,&DPChannelId::card >, const_mem_fun< DPChannelId, const unsigned short,&DPChannelId::cardch > > >, hashed_unique< tag< IndexCrateCardChanHash >, composite_key< DPChannelId, const_mem_fun< DPChannelId, const unsigned short,&DPChannelId::crate >, const_mem_fun< DPChannelId, const unsigned short,&DPChannelId::card >, const_mem_fun< DPChannelId, const unsigned short,&DPChannelId::cardch > > >, hashed_non_unique< tag< IndexCrp >, const_mem_fun< DPChannelId, const unsigned short,&DPChannelId::crp > >, hashed_non_unique< tag< IndexCrpView >, composite_key< DPChannelId, const_mem_fun< DPChannelId, const unsigned short,&DPChannelId::crp >, const_mem_fun< DPChannelId, const unsigned short,&DPChannelId::view > > >, ordered_unique< tag< IndexCrpViewChan >, composite_key< DPChannelId, const_mem_fun< DPChannelId, const unsigned short,&DPChannelId::crp >, const_mem_fun< DPChannelId, const unsigned short,&DPChannelId::view >, const_mem_fun< DPChannelId, const unsigned short,&DPChannelId::viewch > > >, hashed_unique< tag< IndexCrpViewChanHash >, composite_key< DPChannelId, const_mem_fun< DPChannelId, const unsigned short,&DPChannelId::crp >, const_mem_fun< DPChannelId, const unsigned short,&DPChannelId::view >, const_mem_fun< DPChannelId, const unsigned short,&DPChannelId::viewch > > > > > DPChannelTable
unsigned ncrates() const
std::set< unsigned > crpidx_
boost::optional< DPChannelId > find_by_crate_card_chan(unsigned crate, unsigned card, unsigned chan) const
std::vector< DPChannelId > find_by_crp(unsigned crp, bool ordered=true) const
QTextStream & endl(QTextStream &s)