MuonCounter35Alg.cxx
Go to the documentation of this file.
1 ////////////////////////////////////////////////////////////////////////
2 /// \file MuonCounter35Alg.cxx
3 /// \brief Interface to algorithm class for DUNE 35t muon counters.
4 ///
5 /// \version $Id: $
6 /// \author Matthew Worcester (mworcester@bnl.gov)
7 ////////////////////////////////////////////////////////////////////////
8 
10 
13 
14 #include <fstream>
15 
16 namespace geo{
17 
18  //----------------------------------------------------------------------------
19 
21  {
22 
23  }
24 
25  //----------------------------------------------------------------------------
26 
28 
29  //----------------------------------------------------------------------------
30 
32  std::vector< std::vector<double> > &geometry){
33 
34  // This function loads the muon counter geometry from an external text file
35  // into a vector of vectors. Each sub-vector holds the geometry for one counter
36  // with the format: counter ID, condition flag (0=off, non-zero=on), list of
37  // coordinates for each corner of the counter (x0,y0,z0,x1,y1,z1,...).
38  // It returns 1 if some geometry data loads with the correct size, and 0 if
39  // it fails. The text file should contain one counter per line with exactly
40  // the same format as the geometry vectors.
41 
42  int loaded = 1;
43 
44  // open the file
45  std::ifstream counterfile(filename);
46 
47  // check that the file opened
48  if(counterfile.is_open()){
49 
50  mf::LogInfo("MuonCounter35t") << "Loading 35t muon counter geometry from " << filename;
51 
52  // load the counter geometry
53 
55  int ncounter = 0;
56 
57  // loop over the lines in the text file, each line represents a counter
58  while(std::getline(counterfile,line)){
59 
60  // skip lines that begin with #
61  if(line.at(0) != '#'){
62 
63  // this is a counter, so add an empty vector to fill with the geometry
64  geometry.push_back(std::vector<double>());
65  ncounter = geometry.size()-1;
66 
67  // format the line to easily extract the geometry
68  std::istringstream issline(line);
69  double value = 0.;
70 
71  while(issline >> value){
72 
73  // add the geometry to the vector
74  geometry[ncounter].push_back(value);
75 
76  }
77 
78  }
79 
80  } // done looping over lines in the text file
81 
82  counterfile.close();
83 
84  }
85  else{
86 
87  // the text file did not open
88 
89  mf::LogError("MuonCounter35t") << "Could not open " << filename;
90 
91  loaded = 0;
92 
93  }
94 
95  // check that some geometry data made it into the vectors
96 
97  if(geometry.size() != 0){
98 
99  // check that the amount of geometry data in each counter is correct
100 
101  for(unsigned int i=0; i<geometry.size(); i++){
102 
103  // there must be at least 3 verticies, so 9 values + 2 for the counter ID and flag
104 
105  if(geometry[i].size() < 11){
106 
107  //std::cout << "ERROR: counter " << geometry[i][0] << " has size " << geometry[i].size()
108  // << ", when it must have size > 11" << std::endl;
109 
110  loaded = 0;
111 
112  }
113 
114  // there must be x3 + 2 values
115 
116  if((geometry[i].size()-2) % 3 != 0){
117 
118  //std::cout << "ERROR: counter " << geometry[i][0] << " has size " << geometry[i].size()
119  // << ", when it must have size = x3 + 2" << std::endl;
120 
121  loaded = 0;
122 
123  }
124 
125  } // done looping over counter vector
126 
127  }
128  else{
129 
130  // no geometry data made it into the vectors
131 
132  loaded = 0;
133 
134  }
135 
136  return loaded;
137 
138  }
139 
140  //----------------------------------------------------------------------------
141 
143  TVector3 trackpoint, TVector3 trackdirection,
144  std::vector< std::vector<double> > &geometry,
145  std::vector< std::vector<double> > &hitcounters){
146 
147  // This function tests whether a track, defined by a point and a direction,
148  // intersects with any of the muon counters, defined in geometry. The
149  // geometry defines each counter with an ID number, a condition flag (0=off),
150  // and an area defined by one coordinate set for each corner of the counter
151  // (this is to handle trapezoidal counters and other oddly-shaped bits).
152  // It fills a vector of vectors, where each sub-vector contains the ID and
153  // condition flag of a hit counter, and the track ID and intersection point with
154  // that counter. It returns the number of hit counters.
155 
156  int counterID = -1;
157  int counterFlag = -1;
158 
159  // loop over the counters
160  for(unsigned int igeo=0; igeo<geometry.size(); igeo++){
161 
162  // first two indicies of each counter geometry are ID and flag
163  counterID = geometry[igeo][0];
164  counterFlag = geometry[igeo][1];
165 
166  // check that the counter is on
167  if(counterFlag != 0){
168 
169  // check if the track intersects the counter and get the intersection point
170 
171  TVector3 insectionPoint(0.,0.,0.);
172 
173  int inside = testTrackInCounter(trackpoint, trackdirection, geometry[igeo], insectionPoint);
174 
175  // if track intersection point is inside the counter area, fill the
176  // vector of hit counter data
177 
178  if(inside){
179 
180  // add an empty vector to fill with the hit data
181  hitcounters.push_back(std::vector<double>());
182  int ncounter = hitcounters.size()-1;
183 
184  // add the data to the vector
185  hitcounters[ncounter].push_back(counterID);
186  hitcounters[ncounter].push_back(counterFlag);
187  hitcounters[ncounter].push_back(trackID);
188  hitcounters[ncounter].push_back(insectionPoint.X());
189  hitcounters[ncounter].push_back(insectionPoint.Y());
190  hitcounters[ncounter].push_back(insectionPoint.Z());
191 
192  } // check if a track/counter plane intersection point was found
193 
194  } // check that the counter condition flag is non-zero
195 
196  } // loop over the counters
197 
198  return hitcounters.size();
199 
200  }
201 
202  //----------------------------------------------------------------------------
203 
204  int MuonCounter35Alg::testTrackInCounter(TVector3 trackpoint, TVector3 trackdirection,
205  std::vector<double> &singlecountergeometry,
206  TVector3 &intersectionpoint){
207 
208  // This function tests whether a track, defined by a point and a direction,
209  // intersects with a muon counter, defined in singlecountergeometry. The
210  // singlecountergeometry contains an ID number, a condition flag (0=off),
211  // and an area defined by one coordinate set for each corner of the counter
212  // (this is to handle trapezoidal counters and other oddly-shaped bits).
213  // It fills a TVector3 with the coordinates of the intersection point
214  // between the track and counter. It returns 1 if the track intersects the
215  // counter and 0 otherwise.
216 
217  int intersect = 0;
218 
219  // sort the counter verticies into TVector3 vectors
220  std::vector<TVector3> points;
221 
222  // after the first two indicies, each next three values are coordinates
223 
224  for(unsigned int icoord=2; icoord<singlecountergeometry.size(); icoord=icoord+3){
225 
226  TVector3 temppoint(singlecountergeometry[icoord],singlecountergeometry[icoord+1],
227  singlecountergeometry[icoord+2]);
228 
229  points.push_back(temppoint);
230 
231  }
232 
233  //std::cout << "Npoints " << points.size() << " first value " << points[0].X()
234  // << " last value " << points[points.size()-1].Z() << std::endl;
235 
236  // calculate the coefficients of the plane defined by the first 3 of those points
237 
238  double a = points[0].Y()*(points[1].Z()-points[2].Z())
239  + points[1].Y()*(points[2].Z()-points[0].Z())
240  + points[2].Y()*(points[0].Z()-points[1].Z());
241 
242  double b = points[0].Z()*(points[1].X()-points[2].X())
243  + points[1].Z()*(points[2].X()-points[0].X())
244  + points[2].Z()*(points[0].X()-points[1].X());
245 
246  double c = points[0].X()*(points[1].Y()-points[2].Y())
247  + points[1].X()*(points[2].Y()-points[0].Y())
248  + points[2].X()*(points[0].Y()-points[1].Y());
249 
250  double d = - points[0].X()*(points[1].Y()*points[2].Z() - points[2].Y()*points[1].Z())
251  - points[1].X()*(points[2].Y()*points[0].Z() - points[0].Y()*points[2].Z())
252  - points[2].X()*(points[0].Y()*points[1].Z() - points[1].Y()*points[0].Z());
253 
254  //std::cout << "cooefficients: a " << a << " b " << b << " c " << c << " d " << d << std::endl;
255 
256  // for completeness, check that the rest of the points are also in the plane
257 
258  for(unsigned int p=3; p<points.size(); p++){
259 
260  double plane = a*points[p].X() + b*points[p].Y() + c*points[p].Z() + d;
261 
262  if(plane > 0.0001){
263 
264  //std::cout << "ERROR: the corners of muon counter " << singlecountergeometry[0]
265  // << " do not lie in a plane." << std::endl;
266 
267  }
268 
269  }
270 
271  // find the normal to the plane of the counter
272 
273  double mag = sqrt(a*a + b*b + c*c);
274 
275  if(mag != 0){
276 
277  a = a/mag;
278  b = b/mag;
279  c = c/mag;
280 
281  }
282 
283  // find the intersection, if any, between the given track and the plane of the
284  // counter: start with any point in the plane and the normal to the plane
285 
286  TVector3 planepoint = points[2];
287  TVector3 planenorm(a, b, c);
288 
289  // distance between a point in the plane of the counter and a point on the track
290 
291  TVector3 diff = planepoint - trackpoint;
292  //std::cout << "diff " << diff[0] << ", " << diff[1] << ", " << diff[2] << std::endl;
293 
294  // pick out the distance between the track and plane in the direction normal
295  // to the plane; if num = 0, then the track point itself is in the plane of the counter
296 
297  double num = diff * planenorm;
298  //std::cout << "num " << num << std::endl;
299 
300  // pick out the vector of the track normal to the plane of the counter
301 
302  double den = trackdirection * planenorm;
303  //std::cout << "den " << den << std::endl;
304 
305  // if den = 0, then the track direction is perpendicular to the plane of the counter
306  // and there are no intersections; except in the special case that num = 0, in which
307  // case the entire track is in the plane of the counter, and the intersection
308  // point is chosen to be the initial track point
309 
310  double r = 0.;
311  int found_plane_intersection = 0;
312 
313  // calculate the intersection point between the track and plane of the counter
314 
315  TVector3 planeinterpoint(0.,0.,0.);
316 
317  if(fabs(den) > 0.0001){
318 
319  // case 1: the track direction is not perpendicular to the plane of the counter
320  // so a single intersection point should be found; if num=0 then the track
321  // point itself is in the plane of the counter
322 
323  r = num/den;
324  //std::cout << "r " << r << std::endl;
325 
326  planeinterpoint = r*trackdirection + trackpoint;
327  //std::cout << "planeinterpoint " << planeinterpoint.X() << ", " << planeinterpoint.Y()
328  // << ", " << planeinterpoint.Z() << std::endl;
329 
330  found_plane_intersection = 1;
331 
332  }
333  else{
334 
335  if(num == 0){
336 
337  // case 2: the entire track is in the plane of the counter; so we should
338  // check if the track crosses the counter area
339 
340  }
341 
342  }
343 
344  // check if the plane intersection point is inside the counter
345 
346  if(found_plane_intersection){
347 
348  // find the coordinate plane that the plane of the counter is closest to
349 
350  double xdiff = 0.; double xdiffmax = 0;
351  double ydiff = 0.; double ydiffmax = 0;
352  double zdiff = 0.; double zdiffmax = 0;
353 
354  for(unsigned int p=1; p<points.size(); p++){
355 
356  xdiff = points[p].X() - points[p-1].X();
357  if(xdiff > xdiffmax) xdiffmax = xdiff;
358 
359  ydiff = points[p].Y() - points[p-1].Y();
360  if(ydiff > ydiffmax) ydiffmax = ydiff;
361 
362  zdiff = points[p].Z() - points[p-1].Z();
363  if(zdiff > zdiffmax) zdiffmax = zdiff;
364 
365  }
366 
367  //std::cout << xdiffmax << " " << ydiffmax << " " << zdiffmax << std::endl;
368 
369  // Project both the coordinates of the counter and the intersection point
370  // down into the coordinate that the plane of the counter is closest to.
371  // This gives us a 2D polygon and a point which we can test to see if
372  // it is inside the polygon.
373 
374  double *vert1 = NULL;
375  vert1 = (double*) realloc(vert1,points.size()*sizeof(double));
376 
377  double *vert2 = NULL;
378  vert2 = (double*) realloc(vert2,points.size()*sizeof(double));
379 
380  if(vert1 != NULL && vert2 != NULL){
381 
382  for(unsigned int i=0; i<points.size(); i++){
383 
384  vert1[i] = 0;
385  vert2[i] = 0;
386 
387  }
388 
389  }
390 
391  double test1 = 0.;
392  double test2 = 0.;
393 
394  if(xdiffmax < ydiffmax && xdiffmax <= zdiffmax){
395 
396  // plane of the counter is closest to the y-z plane
397 
398  for(unsigned int i=0; i<points.size(); i++){
399 
400  vert1[i] = points[i].Y();
401  vert2[i] = points[i].Z();
402 
403  }
404 
405  test1 = planeinterpoint.Y();
406  test2 = planeinterpoint.Z();
407 
408  }
409  else if(ydiffmax < xdiffmax && ydiffmax <= zdiffmax){
410 
411  // plane of the counter is closest to the x-z plane
412 
413  for(unsigned int i=0; i<points.size(); i++){
414 
415  vert1[i] = points[i].X();
416  vert2[i] = points[i].Z();
417 
418  }
419 
420  test1 = planeinterpoint.X();
421  test2 = planeinterpoint.Z();
422 
423  }
424  else if (zdiffmax < xdiffmax && zdiffmax < ydiffmax){
425 
426  // plane of the counter is closest to the x-y plane
427 
428  for(unsigned int i=0; i<points.size(); i++){
429 
430  vert1[i] = points[i].X();
431  vert2[i] = points[i].Y();
432 
433  }
434 
435  test1 = planeinterpoint.X();
436  test2 = planeinterpoint.Y();
437 
438  }
439  else{
440 
441  //std::cout << "ERROR: case not considered for projecting counter. "
442  // << "Testing the intersection point will fail." << std::endl;
443 
444  }
445 
446  // test for the intersection point inside the counter polygon
447  // 1 = inside, 0 = outside
448 
449  intersect = testPointInPolygon(points.size(), vert1, vert2, test1, test2);
450 
451  free(vert1);
452  free(vert2);
453 
454  if(intersect) intersectionpoint = planeinterpoint;
455 
456  //std::cout << "intersection? " << intersect << std::endl;
457 
458  } // found an intersection between track and plane of counter
459 
460  return intersect;
461 
462  }
463 
464  //----------------------------------------------------------------------------
465 
466  int MuonCounter35Alg::testPointInPolygon(int nvert, double *vertx, double *verty,
467  double testx, double testy){
468 
469  // This function checks whether a given point (testx, testy) is inside a polygon
470  // defined by 2D coordinate arrays (vertx and verty) of the polygon's
471  // verticies. If the point is inside the polygon, the function will return 1; if
472  // outside, it returns 0; if the point is exactly on one edge,
473  // (e.g. testx = vertx[1] = vertx[2]) it is treated as outside and returns 0.
474  // Original author: W. Randolph Franklin. For the license to use, see the
475  // source: www.ecse.rpi.edu/Homepages/wrf/Research/Short_Notes/pnpoly.html
476 
477  int i, j, c = 0;
478 
479  for(i = 0, j = nvert - 1; i < nvert; j = i++){
480 
481  if( ((verty[i] > testy) != (verty[j] > testy)) &&
482  (testx < (vertx[j]-vertx[i]) * (testy-verty[i]) / (verty[j]-verty[i]) + vertx[i]) ){
483 
484  c = !c;
485 
486  }
487 
488  }
489 
490  return c;
491 
492  }
493 
494  //----------------------------------------------------------------------------
495 
496 } // namespace
MuonCounter35Alg(fhicl::ParameterSet const &p)
std::string string
Definition: nybbler.cc:12
MaybeLogger_< ELseverityLevel::ELsev_info, false > LogInfo
struct vector vector
MaybeLogger_< ELseverityLevel::ELsev_error, false > LogError
string filename
Definition: train.py:213
static int testTrackInCounter(TVector3 trackpoint, TVector3 trackvector, std::vector< double > &singlecountergeometry, TVector3 &intersectionpoint)
static int loadMuonCounterGeometry(char *filename, std::vector< std::vector< double > > &geometry)
decltype(auto) constexpr size(T &&obj)
ADL-aware version of std::size.
Definition: StdUtils.h:92
static int testPointInPolygon(int nvert, double *vertx, double *verty, double testx, double testy)
const double a
p
Definition: test.py:223
Interface to algorithm class for DUNE 35t muon counters.
void line(double t, double *p, double &x, double &y, double &z)
static bool * b
Definition: config.cpp:1043
static int testTrackInAllCounters(int trackID, TVector3 trackpoint, TVector3 trackvector, std::vector< std::vector< double > > &geometry, std::vector< std::vector< double > > &hitcounters)
LArSoft geometry interface.
Definition: ChannelGeo.h:16