RandomChannelStatusService_service.cc
Go to the documentation of this file.
1 // Chris Backhouse - c.backhouse@ucl.ac.uk Dec 2017
2 
5 
7 #include "lardataobj/Simulation/sim.h" // GetRandomNumberSeed()
8 
9 #include "CLHEP/Random/RandFlat.h"
10 
11 namespace detvar
12 {
13  //......................................................................
14  // Implement Table 5 from dune docdb 4064v2
15  void ChipAndChannelToSpot(int chip, int chan, geo::View_t& view, int& wire)
16  {
17  // Ultimately this logic should be contained in some ChannelMap service
18 
19  assert(chip >= 1 && chip <= 8);
20  assert(chan >= 0 && chan <= 15);
21 
22  int wireMin = -1; // smallest value in block
23  int chipMin = -1, chanMin = -1; // position of smallest value
24  int height = -1; // height of block
25  int chipSign = 0, chanSign = 0; // which way the numbers count
26 
27  if(chip == 1 || chip == 2){
28  wireMin = 1; chipMin = 2; chipSign = -1; chanSign = -1;
29  /**/ if(chan <= 4){view = geo::kU; chanMin = 4; height = 5;}
30  else if(chan <= 9){view = geo::kV; chanMin = 9; height = 5;}
31  else/* */{view = geo::kW; chanMin = 15; height = 6;}
32  }
33 
34  if(chip == 3 || chip == 4){
35  wireMin = 2; chipMin = 4; chipSign = -1; chanSign = +1;
36  /**/ if(chan <= 5){view = geo::kW; chanMin = 0; height = 6;}
37  else if(chan <= 10){view = geo::kV; chanMin = 6; height = 5;}
38  else/* */{view = geo::kU; chanMin = 11; height = 5;}
39  }
40 
41  if(chip == 5 || chip == 6){
42  chipMin = 5; chipSign = +1; chanSign = -1;
43  /**/ if(chan <= 4){view = geo::kU; wireMin = 21; chanMin = 4; height = 5;}
44  else if(chan <= 9){view = geo::kV; wireMin = 21; chanMin = 9; height = 5;}
45  else/* */{view = geo::kW; wireMin = 25; chanMin = 15; height = 6;}
46  }
47 
48  if(chip == 7 || chip == 8){
49  chipMin = 7; chipSign = +1; chanSign = +1;
50  /**/ if(chan <= 5){view = geo::kW; wireMin = 26; chanMin = 0; height = 6;}
51  else if(chan <= 10){view = geo::kV; wireMin = 22; chanMin = 6; height = 5;}
52  else/* */{view = geo::kU; wireMin = 22; chanMin = 11; height = 5;}
53  }
54 
55  assert(wireMin >= 0 && chipMin >= 0 && chanMin >= 0 && height >= 0 && chipSign != 0 && chanSign != 0);
56 
57  // Compute the wire number inside the block
58  wire = wireMin+2*((chan-chanMin)*chanSign + (chip-chipMin)*height*chipSign);
59 
60  assert(wire >= 1 && wire <= 48);
61  }
62 
63  /// For whatever reason the iterators in Geometry can't be used to initialize
64  /// a vector directly
65  template<class T, class It_t> std::vector<T> VectorViaSet(It_t begin,
66  It_t end)
67  {
68  const std::set<T> s(begin, end);
69  return std::vector<T>(s.begin(), s.end());
70  }
71 
72  class RandomTPC
73  {
74  public:
76  : fCryos(VectorViaSet<geo::CryostatID>(geom->begin_cryostat_id(),
77  geom->end_cryostat_id()))
78  {
79  for(geo::CryostatID c: fCryos){
80  fTPCs[c] = VectorViaSet<geo::TPCID>(geom->begin_TPC_id(c),
81  geom->end_TPC_id(c));
82 
83  fTPCsets[c] = VectorViaSet<readout::TPCsetID>(geom->begin_TPCset_id(c),
84  geom->end_TPCset_id(c));
85  }
86  }
87 
89  {
90  const geo::CryostatID c = fCryos[gRandom->Integer(fCryos.size())];
91  const std::vector<geo::TPCID>& ts = fTPCs.find(c)->second;
92  return ts[gRandom->Integer(ts.size())];
93  }
94 
96  {
97  const geo::CryostatID c = fCryos[gRandom->Integer(fCryos.size())];
98  const std::vector<readout::TPCsetID>& ts = fTPCsets.find(c)->second;
99  return ts[gRandom->Integer(ts.size())];
100  }
101 
102  protected:
103  std::vector<geo::CryostatID> fCryos;
104  std::map<geo::CryostatID, std::vector<geo::TPCID>> fTPCs;
105  std::map<geo::CryostatID, std::vector<readout::TPCsetID>> fTPCsets;
106  };
107 
109  {
110  public:
112  const raw::ChannelID_t& b) const
113  {
114  return GetZ(a) < GetZ(b);
115  }
116  protected:
117  double GetZ(const raw::ChannelID_t& c) const
118  {
119  double z = 0;
120  double y = -1e9;
121 
122  // Search through all the wires associated with this channel for the
123  // top-most position (where it attaches to the APA frame) and quote that
124  // Z position.
125  const std::vector<geo::WireID> wires = geom->ChannelToWire(c);
126  for(const geo::WireID& wire: wires){
127  const geo::WireGeo& wg = geom->Wire(wire);
128  if(wg.GetStart().Y() > y){
129  y = wg.GetStart().Y();
130  z = wg.GetStart().Z();
131  }
132  if(wg.GetEnd().Y() > y){
133  y = wg.GetEnd().Y();
134  z = wg.GetEnd().Z();
135  }
136  }
137 
138  return z;
139  }
140 
142  };
143 
144  //......................................................................
145  // Three vectors, one for each view. Will be sorted by ID number
146  std::vector<std::vector<raw::ChannelID_t>>
148  {
149  // No good way of enumerating all the unique channels, or selecting them by
150  // index. Have to figure them out from the wires.
151  std::set<raw::ChannelID_t> chanset[3];
152  for(geo::WireID wire: geom->IterateWireIDs(tpc)){
153  const raw::ChannelID_t chan = geom->PlaneWireToChannel(wire);
154  // But this also gives us wires that are actually attached to the other
155  // face and just wrapped onto this face. So long as the order of the
156  // vector returned from this function is meaningful, this should work
157  // to keep just the ones we need.
158  if(geom->ChannelToWire(chan)[0] == wire)
159  chanset[geom->View(chan)].insert(chan);
160  }
161  // We'll want to index by channel number within the APAs. Sort spatially as
162  // our best guess as to that mapping.
163  std::vector<std::vector<raw::ChannelID_t>> chans;
164  for(int i = 0; i < 3; ++i){
165  chans.emplace_back(chanset[i].begin(), chanset[i].end());
166  SortChansByZ scz;
167  std::sort(chans.back().begin(), chans.back().end(), scz);
168  }
169  return chans;
170  }
171 
172  //......................................................................
175  {
176  const double badfrac = pset.get<double>("BadChanFrac");
177 
178  EMode_t mode = kUnknown;
179 
180  const std::string modestr = pset.get<std::string>("Mode");
181  if(modestr == "channels") mode = kRandomChans;
182  if(modestr == "APAs") mode = kRandomAPAs;
183  if(modestr == "APAsides") mode = kRandomAPAsides;
184  if(modestr == "boards") mode = kRandomBoards;
185  if(modestr == "chips") mode = kRandomChips;
186  if(mode == kUnknown){
187  std::cout << "RandomChannelStatusService: unknown mode '"
188  << modestr << "'" << std::endl;
189  abort();
190  }
191 
193 
194  // TODO don't seem to be able to access the RandomNumberGenerator service
195  // from here, let alone anything to do with seeds.
196  // const unsigned int seed = pset.get<unsigned int>("Seed", sim::GetRandomNumberSeed());
197  // auto& engine = createEngine(seed);
198  // CLHEP::RandFlat r(engine);
199 
200  const unsigned int target = badfrac*geom->Nchannels();
201 
202  switch(mode){
203  case kRandomChans: MarkChansBad(target); break;
204 
205  case kRandomAPAs: MarkAPAsBad(target); break;
206 
207  case kRandomAPAsides: MarkAPASidesBad(target); break;
208 
209  case kRandomBoards:
210  case kRandomChips:
211  MarkBoardsOrChipsBad(mode, target);
212  break;
213 
214  default:
215  abort(); // impossible
216  }
217 
218  // goodchans = allchans - badchans
219  std::set<raw::ChannelID_t> allchans;
220  for(geo::WireID wire: geom->IterateWireIDs())
221  allchans.insert(geom->PlaneWireToChannel(wire));
222 
223  std::set_difference(allchans.begin(), allchans.end(),
224  fBadChans.begin(), fBadChans.end(),
225  std::inserter(fGoodChans, fGoodChans.begin()));
226  }
227 
228  //......................................................................
230  {
232 
233  // Geometry doesn't have a way to iterate directly over channels. Iterate
234  // over the wires and convert them. Use a set to remove duplicates
235  std::set<raw::ChannelID_t> allchans;
236  for(geo::WireID wire: geom->IterateWireIDs())
237  allchans.insert(geom->PlaneWireToChannel(wire));
238 
239  // But a vector is much easier to pick from randomly. This will be used for
240  // the random chans mode.
241  const std::vector<raw::ChannelID_t> vchans(allchans.begin(),
242  allchans.end());
243 
244  // Generate exactly the requested fraction of bad channels (rather than a
245  // random sample with that probability). Should make results of studies
246  // less noisy.
247  while(fBadChans.size() < target){
248  // Insert a random element. There will be duplicates, but the set will
249  // filter them out. Shouldn't be too inefficient for the low bad
250  // channel fractions we'll use in practice.
251  fBadChans.insert(vchans[gRandom->Integer(vchans.size())]);
252  } // end while
253  }
254 
255  //......................................................................
257  {
259 
260  std::map<readout::TPCsetID, std::set<raw::ChannelID_t>> tpcset_to_chans;
261  for(const readout::TPCsetID& ts: geom->IterateTPCsetIDs()){
262  // There is no version of IterateWireIDs over a TPCset. Use another layer
263  // of indirection.
264  for(geo::TPCID t: geom->TPCsetToTPCs(ts)){
265  for(const geo::WireID& wire: geom->IterateWireIDs(t)){
266  const raw::ChannelID_t chan = geom->PlaneWireToChannel(wire);
267  tpcset_to_chans[ts].insert(chan);
268  }
269  }
270  }
271 
272  RandomTPC tpcs(geom.get());
273 
274  while(fBadChans.size() < target){
275  // Mark all the channels in this TPCset (both sides of an APA) bad
276  const readout::TPCsetID t = tpcs.GetTPCset();
277  for(raw::ChannelID_t chan: tpcset_to_chans[t]){
278  fBadChans.insert(chan);
279  }
280 
281  std::cout << "RandomChannelStatusService: Generated "
282  << fBadChans.size() << " bad channels of "
283  << target << " required" << std::endl;
284  }
285  }
286 
287  //......................................................................
289  {
291 
292  std::map<geo::TPCID, std::vector<raw::ChannelID_t>> tpc_to_chans;
293  for(const geo::TPCID& t: geom->IterateTPCIDs()){
294  // Geometry doesn't provide a way to directly iterate the channels in the
295  // TPC. Instead iterate the wires and convert to channels
296  for(const geo::WireID& wire: geom->IterateWireIDs(t)){
297  const raw::ChannelID_t chan = geom->PlaneWireToChannel(wire);
298  // But this also gives us wires that are actually attached to the other
299  // face and just wrapped onto this face. So long as the order of the
300  // vector returned from this function is meaningful, this should work
301  // to keep just the ones we need.
302  if(geom->ChannelToWire(chan)[0] == wire)
303  tpc_to_chans[t].push_back(chan);
304  }
305  }
306 
307  RandomTPC tpcs(geom.get());
308 
309  while(fBadChans.size() < target){
310  const geo::TPCID t = tpcs.GetTPC();
311 
312  // Mark all the channels in this TPC (ie APA side) bad
313  for(raw::ChannelID_t chan: tpc_to_chans[t]){
314  fBadChans.insert(chan);
315  }
316 
317  std::cout << "RandomChannelStatusService: Generated "
318  << fBadChans.size() << " bad channels of "
319  << target << " required" << std::endl;
320  }
321  }
322 
323  //......................................................................
326  {
328 
329  RandomTPC tpcs(geom.get());
330 
331  // Generate exactly the requested fraction of bad channels (rather than a
332  // random sample with that probability). Should make results of studies
333  // less noisy.
334  while(fBadChans.size() < target){
335  const geo::TPCID t = tpcs.GetTPC();
336 
337  const std::vector<std::vector<raw::ChannelID_t>> chans = ChannelsForTPC(geom.get(), t);
338 
339  // An APA has 20 boards total, 10 on each side. ie a side has 480 W wires
340  // and 400+400 U+V wires.
341  const int board = gRandom->Integer(10);
342 
343  if(mode == kRandomBoards) MarkBoardBad(board, chans);
344 
345  if(mode == kRandomChips){
346  const int chip = 1+gRandom->Integer(8); // One of 8 chips
347  MarkChipBad(board, chip, geom.get(), chans);
348  }
349 
350  std::cout << "RandomChannelStatusService: Generated "
351  << fBadChans.size() << " bad channels of "
352  << target << " required" << std::endl;
353  }
354  }
355 
356  //......................................................................
358  MarkBoardBad(int board,
359  const std::vector<std::vector<raw::ChannelID_t>>& chans)
360  {
361  // Check we succesfully got a single side of an APA
362  assert(chans[geo::kU].size() == 400);
363  assert(chans[geo::kV].size() == 400);
364  assert(chans[geo::kW].size() == 480);
365 
366  for(int i = 0; i < 40; ++i) fBadChans.insert(chans[geo::kU][board*40+i]);
367  for(int i = 0; i < 40; ++i) fBadChans.insert(chans[geo::kV][board*40+i]);
368  for(int i = 0; i < 48; ++i) fBadChans.insert(chans[geo::kW][board*48+i]);
369  }
370 
371  //......................................................................
373  MarkChipBad(int board, int chip,
374  const geo::GeometryCore* geom,
375  const std::vector<std::vector<raw::ChannelID_t>>& chans)
376  {
377  // Check we succesfully got a single side of an APA
378  assert(chans[geo::kU].size() == 400);
379  assert(chans[geo::kV].size() == 400);
380  assert(chans[geo::kW].size() == 480);
381 
382  // Knock out all the channels in this chip
383  for(int chan = 0; chan <= 15; ++chan){
384  geo::View_t view = geo::kUnknown;
385  // TODO the table calls this a "spot". We're using it as an index into
386  // the sorted list of channel IDs for this view (by Z coordinate). That
387  // could be wrong, but the Geometry doesn't seem to have any coresponding
388 
389  // concept.
390  int spot;
391  ChipAndChannelToSpot(chip, chan, view, spot);
392 
393  // How many wires to add on between each board
394  const int stride = (view == geo::kW) ? 48 : 40;
395 
396  assert(spot+board*stride <= int(chans[view].size()));
397  fBadChans.insert(chans[view][spot+board*stride-1]);
398  } // end for chan
399  }
400 }
401 
end
while True: pbar.update(maxval-len(onlies[E][S])) #print iS, "/", len(onlies[E][S]) found = False for...
void GetStart(double *xyz) const
Definition: WireGeo.h:157
Geometry description of a TPC wireThe wire is a single straight segment on a wire plane...
Definition: WireGeo.h:65
IDparameter< geo::CryostatID > CryostatID
Member type of validated geo::CryostatID parameter.
TPC_id_iterator begin_TPC_id() const
Returns an iterator pointing to the first TPC ID in the detector.
T * get() const
Definition: ServiceHandle.h:63
enum geo::_plane_proj View_t
Enumerate the possible plane projections.
std::string string
Definition: nybbler.cc:12
Planes which measure V.
Definition: geo_types.h:130
Unknown view.
Definition: geo_types.h:136
struct vector vector
Class identifying a set of TPC sharing readout channels.
Definition: readout_types.h:70
std::vector< std::vector< raw::ChannelID_t > > ChannelsForTPC(const geo::GeometryCore *geom, geo::TPCID tpc)
readout::TPCsetID GetTPCset() const
std::vector< geo::WireID > ChannelToWire(raw::ChannelID_t const channel) const
Returns a list of wires connected to the specified TPC channel.
TPCset_id_iterator end_TPCset_id() const
Returns an iterator pointing after the last TPC set ID in the detector.
bool operator()(const raw::ChannelID_t &a, const raw::ChannelID_t &b) const
IteratorBox< TPC_id_iterator,&GeometryCore::begin_TPC_id,&GeometryCore::end_TPC_id > IterateTPCIDs() const
Enables ranged-for loops on all TPC IDs of the detector.
art framework interface to geometry description
unsigned int Nchannels() const
Returns the number of TPC readout channels in the detector.
std::map< geo::CryostatID, std::vector< geo::TPCID > > fTPCs
decltype(auto) constexpr size(T &&obj)
ADL-aware version of std::size.
Definition: StdUtils.h:92
Planes which measure U.
Definition: geo_types.h:129
IteratorBox< wire_id_iterator,&GeometryCore::begin_wire_id,&GeometryCore::end_wire_id > IterateWireIDs() const
Enables ranged-for loops on all wire IDs of the detector.
fInnerVessel push_back(Point(-578.400000, 0.000000, 0.000000))
void MarkBoardsOrChipsBad(EMode_t mode, unsigned int target)
art::ServiceHandle< geo::Geometry > geom
void MarkBoardBad(int board, const std::vector< std::vector< raw::ChannelID_t >> &chans)
const double a
T get(std::string const &key) const
Definition: ParameterSet.h:271
TPCset_id_iterator begin_TPCset_id() const
Returns an iterator pointing to the first TPC set ID in the detector.
The data type to uniquely identify a TPC.
Definition: geo_types.h:386
Description of geometry of one entire detector.
RandomTPC(const geo::GeometryCore *geom)
View_t View(geo::PlaneID const &pid) const
Returns the view (wire orientation) on the channels of specified TPC plane.
TPC_id_iterator end_TPC_id() const
Returns an iterator pointing after the last TPC ID in the detector.
std::vector< geo::CryostatID > fCryos
double GetZ(const raw::ChannelID_t &c) const
raw::ChannelID_t PlaneWireToChannel(WireID const &wireid) const
Returns the ID of the TPC channel connected to the specified wire.
void GetEnd(double *xyz) const
Definition: WireGeo.h:163
void MarkChipBad(int board, int chip, const geo::GeometryCore *geom, const std::vector< std::vector< raw::ChannelID_t >> &chans)
IteratorBox< TPCset_id_iterator,&GeometryCore::begin_TPCset_id,&GeometryCore::end_TPCset_id > IterateTPCsetIDs() const
Enables ranged-for loops on all TPC set IDs of the detector.
std::map< geo::CryostatID, std::vector< readout::TPCsetID > > fTPCsets
static bool * b
Definition: config.cpp:1043
decltype(auto) constexpr begin(T &&obj)
ADL-aware version of std::begin.
Definition: StdUtils.h:72
Planes which measure W (third view for Bo, MicroBooNE, etc).
Definition: geo_types.h:131
Tools and modules for checking out the basics of the Monte Carlo.
unsigned int ChannelID_t
Type representing the ID of a readout channel.
Definition: RawTypes.h:28
std::vector< geo::TPCID > TPCsetToTPCs(readout::TPCsetID const &tpcsetid) const
Returns a list of ID of TPCs belonging to the specified TPC set.
void ChipAndChannelToSpot(int chip, int chan, geo::View_t &view, int &wire)
LArSoft geometry interface.
Definition: ChannelGeo.h:16
RandomChannelStatusProvider(const fhicl::ParameterSet &pset)
std::vector< T > VectorViaSet(It_t begin, It_t end)
static QCString * s
Definition: config.cpp:1042
QTextStream & endl(QTextStream &s)
Service providing information about the quality of channels.
The data type to uniquely identify a cryostat.
Definition: geo_types.h:190
#define DEFINE_ART_SERVICE_INTERFACE_IMPL(svc, iface)