Cand.cxx
Go to the documentation of this file.
1 ////////////////////////////////////////////////////////////////////////
2 // \file Cand.cxx
3 // \version $Id: Cand.cxx,v 1.28 2012-10-31 00:05:29 bckhouse Exp $
4 // \author Christopher Backhouse - bckhouse@caltech.edu
5 ////////////////////////////////////////////////////////////////////////
6 
7 #include "DiscreteTracker/Cand.h"
8 
10 
11 #include <algorithm>
12 #include <cassert>
13 
14 #include "Geometry/Geometry.h"
16 #include "GeometryObjects/Geo.h"
17 
18 #include "RecoBase/CellHit.h"
19 #include "RecoBase/Cluster.h"
20 
22 
23 namespace dt
24 {
25  //......................................................................
27  : fView(view), fUp(up),
28  fAllMMax(+1e10), fAllMMin(-1e10),
29  fAllCMax(+1e10), fAllCMin(-1e10),
30  fNChunks(0), fNDeadChunks(0),
31  fAllHitsDirty(true)
32  {
33  }
34 
35  //......................................................................
37  {
38  fAllHitsDirty = true;
39 
40  if(chunk.HasHits())
41  ++fNChunks;
42  else
43  ++fNDeadChunks;
44  assert(chunk.Up() == fUp);
45 
46  if(dir == kDownstream)
47  fChunks.push_back(chunk);
48  else
49  fChunks.push_front(chunk);
50  }
51 
52  //......................................................................
54  {
55 
56  if(fChunks.front().HasHits())
57  --fNChunks;
58  else
59  --fNDeadChunks;
60 
61  fChunks.pop_front();
62 
63  fAllHitsDirty = true;
64  }
65 
66  //......................................................................
68  {
69  if(fChunks.back().HasHits())
70  --fNChunks;
71  else
72  --fNDeadChunks;
73 
74  fChunks.pop_back();
75 
76  fAllHitsDirty = true;
77  }
78 
79  //......................................................................
80  bool Cand::operator<(const Cand& rhs) const
81  {
82  // This is sufficient to sort them, but can't be used for a map or set
83  // Possibly shouldn't include it as an operator then...
84 
85  if(NHitPlanes() < rhs.NHitPlanes()) return true;
86  if(NHitPlanes() > rhs.NHitPlanes()) return false;
87 
88  if(fSegs.size() < rhs.fSegs.size()) return true;
89  if(fSegs.size() > rhs.fSegs.size()) return false;
90 
91  // Having more dead is a _bad_ thing. Select the ones without
92  // preferentially
93  if(fNDeadChunks > rhs.fNDeadChunks) return true;
94  if(fNDeadChunks < rhs.fNDeadChunks) return false;
95 
96  // if(fChunks.size() < rhs.fChunks.size()) return true;
97  // if(fChunks.size() > rhs.fChunks.size()) return false;
98 
99  // Even if these are only destined to be singleton chunks, need to give the
100  // biggest ones back first because we'll stop looking for new chains when
101  // we see small ones.
102  if(AllHits().size() < rhs.AllHits().size()) return true;
103  if(AllHits().size() > rhs.AllHits().size()) return false;
104 
105  // Arbitrary, but removes dependence on order FindCands emits things
106  return FirstChunk().Plane() < rhs.FirstChunk().Plane();
107  }
108 
109  //......................................................................
110  void Cand::MinMaxLines(const SubSeg& segi, const SubSeg& segj,
111  double& mmax, double& mmin,
112  double& cmax, double& cmin) const
113  {
114  const double dz = segj.z-segi.z;
115 
116  // Got sorted at some earlier stage
117  assert(dz > 0);
118 
119  mmax = std::min(mmax, (segj.y1-segi.y0)/dz);
120  mmin = std::max(mmin, (segj.y0-segi.y1)/dz);
121 
122  cmax = std::min(cmax, segi.y1-segi.z*(segj.y0-segi.y1)/dz);
123  cmin = std::max(cmin, segi.y0-segi.z*(segj.y1-segi.y0)/dz);
124  }
125 
126  //......................................................................
127  void Cand::MinMaxLines(const Segment& segi, const Segment& segj,
128  double& mmax, double& mmin,
129  double& cmax, double& cmin) const
130  {
131  const double dz = segj.zL-segi.zL;
132 
133  if(dz < 0){
134  MinMaxLines(segj, segi, mmax, mmin, cmax, cmin);
135  return;
136  }
137 
138  mmax = +1e10;
139  mmin = -1e10;
140  cmax = +1e10;
141  cmin = -1e10;
142 
143  MinMaxLines(segi.GetSubSeg(kUpstream), segj.GetSubSeg(kUpstream), mmax, mmin, cmax, cmin);
144  MinMaxLines(segi.GetSubSeg(kUpstream), segj.GetSubSeg(kDownstream), mmax, mmin, cmax, cmin);
145  MinMaxLines(segi.GetSubSeg(kDownstream), segj.GetSubSeg(kUpstream), mmax, mmin, cmax, cmin);
146  MinMaxLines(segi.GetSubSeg(kDownstream), segj.GetSubSeg(kDownstream), mmax, mmin, cmax, cmin);
147  }
148 
149  //......................................................................
150  bool Cand::TryAddSeg(const Segment& seg, Direction dir, bool check)
151  {
152  if(check){
153  // Must alternate sides
154  assert(fSegs.empty() || seg.left != ExtremalSeg(dir).left);
155  }
156 
157  double newAllMMax = fAllMMax;
158  double newAllMMin = fAllMMin;
159  double newAllCMax = fAllCMax;
160  double newAllCMin = fAllCMin;
161 
162  for(std::list<Segment>::iterator it = fSegs.begin(); it != fSegs.end(); ++it){
163  const Segment& segi = *it;
164  // In principle would have to loop over all j > i. But this happens every
165  // time we add a new seg, so only the last one is novel.
166  const Segment& segj = seg;
167 
168  double mmax, mmin, cmax, cmin;
169  MinMaxLines(segi, segj, mmax, mmin, cmax, cmin);
170  newAllMMax = std::min(mmax, newAllMMax);
171  newAllMMin = std::max(mmin, newAllMMin);
172  newAllCMax = std::min(cmax, newAllCMax);
173  newAllCMin = std::max(cmin, newAllCMin);
174 
175  if(newAllMMax <= newAllMMin ||
176  newAllCMax <= newAllCMin) return false;
177  } // end for it
178 
179  // TODO: I'm worried about the interaction of this with imperfect
180  // geometry/staggering, but it, or something like it, is necessary to
181  // prevent cands with the obviously "wrong" sense through one-cell chunks
182  if((fUp && newAllMMax < 0) || (!fUp && newAllMMin > 0)) return false;
183 
184  // Everything checks out, finalize the addition
185 
186  if(dir == kDownstream)
187  fSegs.push_back(seg);
188  else
189  fSegs.push_front(seg);
190 
191  fAllHitsDirty = true;
192 
193  fAllMMax = newAllMMax;
194  fAllMMin = newAllMMin;
195  fAllCMax = newAllCMax;
196  fAllCMin = newAllCMin;
197 
198  return true;
199  }
200 
201  //......................................................................
203  {
204  if(TryAddSeg(seg, kDownstream, false)){
205  fSegs.sort();
206  return true;
207  }
208  return false;
209  }
210 
211  //......................................................................
213  {
214  assert(fSegs.size() > 1);
215 
216  const Segment segi = fSegs.front();
217  fSegs.pop_front();
218 
219  PopSegHelper(segi, kUpstream);
220  }
221 
222  //......................................................................
224  {
225  assert(fSegs.size() > 1);
226 
227  const Segment segi = fSegs.back();
228  fSegs.pop_back();
229 
230  PopSegHelper(segi, kDownstream);
231  }
232 
233  //......................................................................
235  {
236  if(fSegs.size() == 1){
237  fAllMMax = +1e10;
238  fAllMMin = -1e10;
239  fAllCMax = +1e10;
240  fAllCMin = -1e10;
241  return;
242  }
243 
244  // Work out if this seg was responsible for any of the strongest
245  // constraints.
246  bool needRecalc = false;
247  for(std::list<Segment>::iterator it = fSegs.begin(); it != fSegs.end(); ++it){
248  const Segment& segj = *it;
249 
250  double mmax, mmin, cmax, cmin;
251  MinMaxLines((end == kDownstream) ? segj : segi,
252  (end == kDownstream) ? segi : segj,
253  mmax, mmin, cmax, cmin);
254 
255  if(mmax-1e-6 < fAllMMax ||
256  mmin+1e-6 > fAllMMin ||
257  cmax-1e-6 < fAllCMax ||
258  cmin+1e-6 > fAllCMin){
259  needRecalc = true;
260  break;
261  }
262  }
263 
264  if(!needRecalc) return;
265 
266  // If this seg was important, need to recalculate the whole lot to find the
267  // 2nd most stringent. To avoid this we'd have to store more information in
268  // the object.
269  std::list<Segment> segs = fSegs;
270  fSegs.clear();
271 
272  fAllMMax = +1e10;
273  fAllMMin = -1e10;
274  fAllCMax = +1e10;
275  fAllCMin = -1e10;
276 
277  for(std::list<Segment>::iterator it = segs.begin(); it != segs.end(); ++it){
278  const bool ok = TryAddSeg(*it, kDownstream);
279  assert(ok);
280  }
281  }
282 
283  //......................................................................
284  void Cand::EstimateStraightLine(double& z1, double& y1,
285  double& z2, double& y2) const
286  {
287  assert(fSegs.size() > 1);
288 
290 
291  // Best guess is starting halfway to the previous plane and ending halfway
292  // to the next.
293  const int firstPlane = FirstChunk().Plane();
294  const int prevPlane = fSegs.front().left ? geom->NextPlaneInView(firstPlane, -1) : firstPlane;
295 
296  const int lastPlane = LastChunk().Plane();
297  const int nextPlane = fSegs.back().left ? lastPlane : geom->NextPlaneInView(lastPlane, +1);
298 
299  if(prevPlane != geo::kPLANE_NOT_FOUND){
300  double a[3], b[3];
301  geom->Plane(prevPlane)->Cell(0)->GetCenter(a);
302  geom->Plane(firstPlane)->Cell(0)->GetCenter(b);
303  z1 = (a[2]+b[2])/2;
304  }
305  else{
306  z1 = fSegs.front().zL;
307  }
308 
309  if(nextPlane != geo::kPLANE_NOT_FOUND){
310  double a[3], b[3];
311  geom->Plane(lastPlane)->Cell(0)->GetCenter(a);
312  geom->Plane(nextPlane)->Cell(0)->GetCenter(b);
313  z2 = (a[2]+b[2])/2;
314  }
315  else{
316  z2 = fSegs.back().zR;
317  }
318 
319  // Except if the first or last chunk is partial, in which case our best
320  // guess is nearest the centre of the first or last cell.
321  if(!fSegs.front().left){
322  const double newz1 = ClosestToEndCell(true);
323  if(newz1 < fSegs.front().zL) z1 = newz1;
324  } // end if
325 
326 
327  if(fSegs.back().left){
328  const double newz2 = ClosestToEndCell(false);
329  if(newz2 > fSegs.back().zR) z2 = newz2;
330  }
331 
332  const double cavg = CAvg();
333  const double mavg = MAvg();
334 
335  y1 = cavg+mavg*z1;
336  y2 = cavg+mavg*z2;
337 
338  assert(z2 >= z1);
339  }
340 
341  //......................................................................
342  int Cand::NHitPlanes() const
343  {
344  int ret = 0;
345  for(std::list<Chunk>::const_iterator it = fChunks.begin(); it != fChunks.end(); ++it){
346  if(!it->AllDead()) ++ret;
347  }
348 
349  return ret;
350  }
351 
352  //......................................................................
353  const Chunk& Cand::FirstChunk() const
354  {
355  return fChunks.front();
356  }
357 
358  //......................................................................
359  const Chunk& Cand::LastChunk() const
360  {
361  return fChunks.back();
362  }
363 
364  //......................................................................
365  const Segment& Cand::FirstSeg() const
366  {
367  return fSegs.front();
368  }
369 
370  //......................................................................
371  const Segment& Cand::LastSeg() const
372  {
373  return fSegs.back();
374  }
375 
376  //......................................................................
378  {
379  if(dir == kUpstream) return FirstSeg().left;
380  return !LastSeg().left;
381  }
382 
383  //......................................................................
385  {
386  const bool complete = IsExtremalChunkComplete(dir);
387 
388  if(dir == kUpstream){
389  fChunks.begin()->SetShowerChunk();
390  if(complete) PopFirstSeg();
391  PopFirstSeg();
392  const std::pair<Segment, Segment> segs = fChunks.begin()->GetSegs();
393  bool ok = TryAddSeg(segs.second, kUpstream);
394  assert(ok);
395  if(complete){
396  ok = TryAddSeg(segs.first, kUpstream);
397  assert(ok);
398  }
399  }
400  else{
401  fChunks.rbegin()->SetShowerChunk();
402  if(complete) PopLastSeg();
403  PopLastSeg();
404  const std::pair<Segment, Segment> segs = fChunks.rbegin()->GetSegs();
405  bool ok = TryAddSeg(segs.first, kDownstream);
406  assert(ok);
407  if(complete){
408  ok = TryAddSeg(segs.second, kDownstream);
409  assert(ok);
410  }
411  }
412  }
413 
414  //......................................................................
415  bool Cand::IsAllShower() const
416  {
417  for(std::list<Chunk>::const_iterator it = fChunks.begin(); it != fChunks.end(); ++it){
418  if(!it->IsShowerChunk()) return false;
419  }
420  return true;
421  }
422 
423  //......................................................................
425  {
426  if(!fAllHitsDirty) return fAllHits;
427  fAllHitsDirty = false;
428 
429  fAllHits.clear();
430  if(fSegs.size() <= 1) return fAllHits;
431  if(fNChunks == 0) return fAllHits;
432 
433  for(std::list<Chunk>::const_iterator it = fChunks.begin(); it != fChunks.end(); ++it){
434  art::PtrVector<rb::CellHit> chunkHits = it->AllHits();
435 
436  // Unless it's the type of chunk you have to do by dead-reckoning the
437  // track.
438  if(it->IsShowerChunk() ||
439  (it == fChunks.begin() && !FirstSeg().left) ||
440  (it->Plane() == LastChunk().Plane() && LastSeg().left)){
441 
442  chunkHits = it->HitsOnLine(MAvg(), CAvg());
443  }
444 
445  for(unsigned int m = 0; m < chunkHits.size(); ++m)
446  fAllHits.push_back(chunkHits[m]);
447  } // end for it
448 
449  return fAllHits;
450  }
451 
452  //......................................................................
454  {
455  double z1, y1, z2, y2;
456  EstimateStraightLine(z1, y1, z2, y2);
458  fView, y1, z1, y2-y1, z2-z1);
459  ret.AppendTrajectoryPoint(y2, z2);
460  for(std::list<Chunk>::const_iterator it = fChunks.begin(); it != fChunks.end(); ++it){
461  ret.Add(it->AllHits());
462  }
463  // TODO: this can happen sometimes, figure out when and why
464  // assert(ret.NCell() > 0);
465  return ret;
466  }
467 
468  //......................................................................
469  double Cand::ClosestToEndCell(bool left) const
470  {
471  double bestL = left ? +1e10 : -1e10;
472  double bestZ = -1e10;
473 
475 
476  const art::PtrVector<rb::CellHit> allhits = AllHits();
477  for(unsigned int n = 0; n < allhits.size(); ++n){
478  const geo::CellGeo* geocell = geom->Plane(allhits[n]->Plane())->Cell(allhits[n]->Cell());
479  double xyz[3];
480  geocell->GetCenter(xyz);
481  // y-view by convention
482  xyz[1] = xyz[fView];
483  xyz[0] = 0;
484 
485  const TVector3 orig(0, CAvg(), 0);
486  const TVector3 dir(0, MAvg(), 1);
487 
488  TVector3 start;
489  geo::ClosestApproach(TVector3(xyz), orig, dir, start);
490 
491  // Distance along the line
492  const double L = (start-orig).Dot(dir);
493 
494  if((left && L < bestL) ||
495  (!left && L > bestL)){
496  bestL = L;
497  bestZ = start.Z();
498  }
499  } // end for n
500 
501  // TODO
502  // assert(bestZ > -1e10);
503  return bestZ;
504  }
505 
506  //......................................................................
508  {
509  fAllHitsDirty = true;
510 
511  while(!fChunks.empty()){
512  if(!fChunks.front().AllDead()) return;
513  const int plane = fChunks.front().Plane();
514  fChunks.pop_front();
515  while(fSegs.front().plane == plane) fSegs.pop_front();
516  }
517  }
518 
519  //......................................................................
521  {
522  fAllHitsDirty = true;
523 
524  while(!fChunks.empty()){
525  if(!fChunks.back().AllDead()) return;
526  const int plane = fChunks.back().Plane();
527  fChunks.pop_back();
528  while(fSegs.back().plane == plane) fSegs.pop_back();
529  }
530  }
531 
532  //......................................................................
534  {
535  if(dir == kDownstream){
536  if(!FirstSeg().left) PopFirstChunk();
537  PopFirstSeg();
538  }
539  else{
540  if(LastSeg().left) PopLastChunk();
541  PopLastSeg();
542  }
543  }
544 
545 
546  //......................................................................
547  Cand Cand::MaybeFlip(bool& ok) const
548  {
549  Cand ret(fView, !fUp);
550 
551  for(std::list<Chunk>::const_iterator it = fChunks.begin(); it != fChunks.end(); ++it){
552  Chunk chunk = *it;
553  chunk.SetUp(!fUp);
554  ret.AddChunk(chunk, kDownstream);
555 
556  const std::pair<Segment, Segment> segs = chunk.GetSegs();
557 
558  // Add first seg unless it's the very first and we don't have it
559  if(it != fChunks.begin() || fSegs.front().left){
560  ok = ret.TryAddSeg(segs.first, kDownstream);
561  if(!ok) return ret;
562  }
563 
564  // Add second seg unless it's the last and we don't have it
565  if(ret.fSegs.size() < fSegs.size()){
566  ok = ret.TryAddSeg(segs.second, kDownstream);
567  if(!ok) return ret;
568  }
569  }
570 
571  return ret;
572  }
573 
574  //......................................................................
575  bool Cand::FindChunk(int plane, Chunk& chunk) const
576  {
577  for(std::list<Chunk>::const_iterator it = fChunks.begin(); it != fChunks.end(); ++it){
578  if(it->Plane() == plane){
579  chunk = *it;
580  return true;
581  }
582  }
583  return false;
584  }
585 
586  //......................................................................
587  bool Cand::operator==(const Cand& rhs) const
588  {
589  if(fView != rhs.fView) return false;
590  if(fUp != rhs.fUp) return false;
591 
592  return fSegs == rhs.fSegs;
593  }
594 
595 } // namespace
T max(const caf::Proxy< T > &a, T b)
double CAvg() const
Definition: Cand.h:113
bool fUp
Definition: Cand.h:117
void GetCenter(double *xyz, double localz=0.0) const
Definition: CellGeo.cxx:159
int Plane() const
Definition: Chunk.h:23
set< int >::iterator it
Cand(geo::View_t view, bool up)
Definition: Cand.cxx:26
float Dot(const Proxy &v) const
Float_t y1[n_points_granero]
Definition: compare.C:5
double y0
Definition: Segment.h:20
void PopSegHelper(const Segment &segi, Direction end)
Definition: Cand.cxx:234
bool operator<(const Cand &rhs) const
Definition: Cand.cxx:80
std::pair< Segment, Segment > GetSegs() const
Definition: Chunk.cxx:102
const int cmax
Definition: cellShifts.C:14
enum geo::_plane_proj View_t
Enumerate the possible plane projections.
Sequence of contiguous hits and dead cells all on the same plane.
Definition: Chunk.h:17
std::list< Segment > fSegs
Definition: Cand.h:123
const CellGeo * Cell(int icell) const
Definition: PlaneGeo.h:48
void TrimBack()
Definition: Cand.cxx:520
const Segment & ExtremalSeg(Direction dir) const
Definition: Cand.h:56
bool IsAllShower() const
Definition: Cand.cxx:415
int NHitPlanes() const
Definition: Cand.cxx:342
double ClosestToEndCell(bool left) const
Z position.
Definition: Cand.cxx:469
bool left
Definition: Segment.h:41
A rb::Prong with full reconstructed trajectory.
Definition: Track.h:20
const Chunk & FirstChunk() const
Definition: Cand.cxx:353
const Segment & LastSeg() const
Definition: Cand.cxx:371
const PlaneGeo * Plane(unsigned int i) const
bool Up() const
Definition: Chunk.cxx:49
bool operator==(const Cand &rhs) const
Definition: Cand.cxx:587
int fNDeadChunks
Definition: Cand.h:121
void EstimateStraightLine(double &z1, double &y1, double &z2, double &y2) const
Definition: Cand.cxx:284
geo::View_t fView
Definition: Cand.h:115
virtual void Add(const art::Ptr< rb::CellHit > &cell, double weight=1)
Definition: Cluster.cxx:84
Definition: Cand.cxx:23
Calculation and representation of a straight line passing through several "segment" windows...
Definition: Cand.h:25
bool TryAddSegOutOfOrder(const Segment &seg)
Definition: Cand.cxx:202
double dz[NP][NC]
double fAllMMax
Definition: Cand.h:119
void push_back(Ptr< U > const &p)
Definition: PtrVector.h:441
static constexpr double L
void PopLastSeg()
Definition: Cand.cxx:223
const double a
void AppendTrajectoryPoint(TVector3 pt)
Definition: Track.cxx:112
rb::Track ToTrack() const
Definition: Cand.cxx:453
void PopFirstSeg()
Definition: Cand.cxx:212
Collect Geo headers and supply basic geometry functions.
art::PtrVector< rb::CellHit > AllHits() const
Definition: Cand.cxx:424
const Segment & FirstSeg() const
Definition: Cand.cxx:365
double fAllCMax
Definition: Cand.h:119
void PopFirstChunk()
Definition: Cand.cxx:53
Cand MaybeFlip(bool &ok) const
Definition: Cand.cxx:547
Direction
Definition: Types.h:5
size_type size() const
Definition: PtrVector.h:308
Just the upstream or downstream part, just coordinates.
Definition: Segment.h:17
bool IsExtremalChunkComplete(Direction dir) const
Definition: Cand.cxx:377
void MarkExtremalChunkShower(Direction dir)
Definition: Cand.cxx:384
const Chunk & LastChunk() const
Definition: Cand.cxx:359
double zL
Definition: Segment.h:39
constexpr auto const & left(const_AssnsIter< L, R, D, Dir > const &a, const_AssnsIter< L, R, D, Dir > const &b)
Definition: AssnsIter.h:104
bool TryAddSeg(const Segment &seg, Direction dir, bool check=true)
Appends seg to fSegs and updates internal state reflecting limits on the possible straight lines...
Definition: Cand.cxx:150
void SetUp(bool up)
Definition: Chunk.cxx:55
int fNChunks
Definition: Cand.h:121
double ClosestApproach(const double point[], const double intercept[], const double slopes[], double closest[])
Find the distance of closest approach between point and line.
Definition: Geo.cxx:222
TDirectory * dir
Definition: macro.C:5
double MAvg() const
Definition: Cand.h:112
void AddChunk(const Chunk &chunk, Direction dir)
Simply store the chunk in the list. Need to call AddSeg too.
Definition: Cand.cxx:36
void MinMaxLines(const Segment &segi, const Segment &segj, double &mmax, double &mmin, double &cmax, double &cmin) const
Helper for TryAddSeg.
Definition: Cand.cxx:127
void PopLastChunk()
Definition: Cand.cxx:67
void geom(int which=0)
Definition: geom.C:163
double fAllMMin
Definition: Cand.h:119
const hit & b
Definition: hits.cxx:21
double fAllCMin
Definition: Cand.h:119
assert(nhit_max >=nhit_nbins)
bool HasHits() const
Definition: Chunk.h:35
bool fAllHitsDirty
Definition: Cand.h:126
Window the line must pass through from (z,y0)-(z,y1)
Definition: Segment.h:24
T min(const caf::Proxy< T > &a, T b)
double z
Definition: Segment.h:20
void TrimFront()
Definition: Cand.cxx:507
void ShortenOne(Direction dir)
Definition: Cand.cxx:533
Float_t e
Definition: plot.C:35
Encapsulate the cell geometry.
Definition: CellGeo.h:25
SubSeg GetSubSeg(Direction dir) const
Definition: Segment.cxx:20
void clear()
Definition: PtrVector.h:537
std::list< Chunk > fChunks
Definition: Cand.h:124
double y1
Definition: Segment.h:20
Encapsulate the geometry of one entire detector (near, far, ndos)
art::PtrVector< rb::CellHit > fAllHits
Always access via AllHits.
Definition: Cand.h:128
bool FindChunk(int plane, Chunk &chunk) const
Definition: Cand.cxx:575