]> git.uio.no Git - u/mrichter/AliRoot.git/blame - RALICE/icepack/IceDwalk.cxx
07-jun-2007 GdV OM readout type also updated from the data contents in IceRoot.cxx.
[u/mrichter/AliRoot.git] / RALICE / icepack / IceDwalk.cxx
CommitLineData
67338e65 1/*******************************************************************************
2 * Copyright(c) 2003, IceCube Experiment at the South Pole. All rights reserved.
3 *
4 * Author: The IceCube RALICE-based Offline Project.
5 * Contributors are mentioned in the code where appropriate.
6 *
7 * Permission to use, copy, modify and distribute this software and its
8 * documentation strictly for non-commercial purposes is hereby granted
9 * without fee, provided that the above copyright notice appears in all
10 * copies and that both the copyright notice and this permission notice
11 * appear in the supporting documentation.
12 * The authors make no claims about the suitability of this software for
13 * any purpose. It is provided "as is" without express or implied warranty.
14 *******************************************************************************/
15
16// $Id$
17
18///////////////////////////////////////////////////////////////////////////
19// Class IceDwalk
20// TTask derived class to perform direct walk track reconstruction.
21// The procedure is based on the method described in the Amanda publication
22// in Nuclear Instruments and Methods A524 (2004) 179-180.
23// However, the Amanda method has been extended with the intention to
24// take also multiple (muon) tracks within 1 event into account.
25// This will not only provide a means to reconstruct muon bundles and
26// multiple track events in IceCube, but will also allow to reduce the
27// background of faked upgoing muons as a result of multiple downgoing
d6860cf1 28// muons hitting the top and bottom parts of the detector.
25eefd00 29// A further extension of the original Amanda method is the separate treatment
30// of the phase and group velocities as introduced in collaboration with
31// George Japaridze (Clark Atlanta University, USA) which will provide more
32// accurate time residuals due to the different velocities of the Cerenkov
33// wave front (v_phase) and the actually detected photons (v_group).
34// This distinction between v_phase and v_group can be (de)activated via the
35// memberfunction SetVgroupUsage(). By default the distinction between v_phase
36// and v_group is activated in the constructor of this class.
d6860cf1 37// To prevent waisting CPU time in trying to reconstruct (high-energy) cascade
38// events, or to select specifically reconstruction of low multiplicity events,
6f94f699 39// the user may invoke the memberfunctions SetMaxModA() and SetMinModA().
40// This allows selection of events for processing with a certain maximum and/or
41// minimum number of good Amanda OMs firing.
42// By default the minimum and maximum are set to 0 and 999, respectively,
25eefd00 43// in the constructor, which implies no multiplicity selection.
44// The maximum number of good hits per Amanda OM to be used for the reconstruction
35e721bf 45// can be specified via the memberfunction SetMaxHitsA().
25eefd00 46// By default only the first good hit of each Amanda OM is used.
47// Note that when all the good hits of an OM are used, this may lead to large
35e721bf 48// processing time in case many noise and/or afterpulse signals are not
49// recognised by the hit cleaning procedure.
25eefd00 50//
51// Information about the actual parameter settings can be found in the event
52// structure itself via the device named "IceDwalk".
53//
67338e65 54// The various reconstruction steps are summarised as follows :
55//
56// 1) Construction of track elements (TE's).
57// A track element is a straight line connecting two hits that
58// appeared at some minimum distance d and within some maximum
25eefd00 59// time difference dt, according to eq. (20) of the NIM article.
60// The default value for d is 75 meter, but this can be modified
61// via the memberfunction SetDmin().
62// By default dt=(hit distance)/c but an additional time margin
63// may be specified via the memberfunction SetDtmarg().
67338e65 64// The reference point r0 of the TE is taken as the center between
65// the two hit positions and the TE timestamp t0 at the position r0
66// is taken as the IceEvent timestamp increased by the average of the
67// two hit times. So, all timestamps contain the overall IceEvent
68// timestamp as a basis. This means that time differences can be
69// obtained via the AliTimestamp facilities (supporting upto picosecond
70// precision when available).
71// The TE direction is given by the relative position of the two hits.
72//
73// 2) Each TE will obtain so called associated hits.
74// A hit is associated to a TE when it fulfills both the conditions
75//
76// -30 < tres < 300 ns
25eefd00 77// dhit/lambda < F
78//
79// tres : time residual
80// Difference between the observed hit time and the time expected
81// for a direct photon hit.
82// dhit : Distance between the hit and the TE
83// lambda : Photon scattering length in ice
67338e65 84//
25eefd00 85// By default F is set to 2, but this can be modified via the memberfunction
86// SetMaxDhit().
67338e65 87//
88// 3) Construction of track candidates (TC's).
25eefd00 89// These are TE's that fulfill both the conditions
90//
91// nah >= 1
92// qtc >= 0.8*qtcmax
93//
94// where we have defined :
413d0114 95//
25eefd00 96// nah : Number of associated hits for the specific TE.
97// qtc : The track quality number (see hereafter).
98// qtcmax : Maximum quality number encountered for the TE's.
413d0114 99//
25eefd00 100// The track quality number qtc is defined as follows :
413d0114 101//
25eefd00 102// qtc=nah*(term1+term2)-term3-term4-term5
67338e65 103//
25eefd00 104// here we have defined :
67338e65 105//
25eefd00 106// term1=2*spread/span
107// term2=2*spreadL/spanL
108// term3=|spread-expspread|/spread
109// term4=|spreadL-expspreadL|/spreadL
110// term5=|medianT|/spreadT
67338e65 111//
25eefd00 112// The central observables here are the projected positions X on the track
113// of the various associated hits w.r.t. the track reference point r0.
114// Note that X can be negative as well as positive.
115// Therefore we also introduce XL=|X|.
116//
117// span : max(X)-min(X)
118// spanL : max(XL)-min(XL)
119// Xmedian : median of X
120// XmedianL : median of XL
121// spread : < |X-Xmedian| >
122// spreadL : < |XL-XmedianL| >
123// expspread : expected spread in X for a flat distribution of nah hits over span
124// expspreadL : expected spread in XL for a flat distribution of nah hits over spanL
125// medianT : median of tres
126// spreadT : < |tres-medianT| >
127//
128// However, if |Xmedian| > span/2 we set qtc=0 in order to always require
129// projected hits to appear on both sides of r0 on the track.
130//
131// Note : The qtc quality number is used to define the norm of the momentum
132// of the track candidate. As such it serves as a weight for the jet
133// momentum (direction) after clustering of the TC's and lateron
134// merging of the jets (see hereafter).
67338e65 135//
413d0114 136// 4) The remaining track candidates are clustered into jets when their directions
137// are within a certain maximum opening angle.
25eefd00 138// In addition a track candidate must within a certain maximum distance
139// of the jet starting TC in order to get clustered.
413d0114 140// The latter criterion prevents clustering of (nearly) parallel track candidates
141// crossing the detector a very different locations (e.g. muon bundles).
142// The default maximum track opening angle is 15 degrees, but can be modified
143// via the SetTangmax memberfunction.
25eefd00 144// The default maximum track distance is 20 meters, but can be modified
145// via the SetTdistmax memberfunction. This memberfunction also allows to
146// specify whether the distance is determined within the detector volume or not.
67338e65 147//
413d0114 148// The average of all the r0 and t0 values of the constituent TC's
149// of the jet will provide the r0 and t0 (i.e. reference point) of the jet.
67338e65 150//
25eefd00 151// The jet total momentum consists of the vector sum of the momenta of the
152// constituent TC's. This implies that the qtc quality numbers of the various
153// TC's define a weight for each track in the construction of the jet direction.
154// In addition it means that the total jet momentum represents the sum of the
155// qtc quality numbers of the constituent TC's weighted by the opening angles
156// between the various TC's.
157// As such each jet is given an absolute quality number defined as :
158//
159// qtcjet=|jet momentum|/ntracks
160//
161// This jet quality number is refined on basis of the number of hits
162// associated to the jet as :
163//
164// qtcjet=qtcjet+0.2*(nah-nahmax)
165//
166// where we have defined :
167//
168// nah : Number of associated hits for the specific jet.
169// nahmax : Maximum number of associated hits encountered for the jets.
170//
171// This qtcjet value is then used to order the various jets w.r.t.
172// decreasing qtcjet quality number.
173//
174// Note : The qtcjet value is stored as "energy" of the jet, such that
175// it is always available for each jet and can also be used for
176// ordering the jets according to this value using the generic
177// AliEvent::SortJets() facility.
178//
179// 5) The jets (after having been ordered w.r.t. decreasing qtcjet value)
180// are merged when their directions are within a certain maximum opening angle.
181// In addition a jet must within a certain maximum distance of the starting jet
182// in order to get merged.
413d0114 183// The latter criterion prevents merging of (nearly) parallel tracks/jets
184// crossing the detector a very different locations (e.g. muon bundles).
25eefd00 185// The jet ordering before the merging process is essential, since the starting jet
186// will "eat up" the jets that will be merged into it.
187// The jet ordering ensures that the jet with the highest quality number will
188// always initiate the merging process.
67338e65 189// The default maximum opening angle is half the TC maximum opening angle,
25eefd00 190// but can be modified via the SetJangmax memberfunction. This memberfunction
191// also allows to specify whether jet merging will be performed iteratively or not.
192// In case iteration has been activated, the jet ordering is performed after each
193// iteration step. This has to be done because since the quality numbers of the
194// resulting merged jets have been automatically updated in the merging process.
195//
196// The default maximum jet distance is 30 meters, but can be modified
197// via the SetJdistmax memberfunction. This memberfunction also allows to
198// specify whether the distance is determined within the detector volume or not.
413d0114 199//
67338e65 200// Note : Setting the maximum jet opening angle to <=0 will prevent
201// the merging of jets.
202//
413d0114 203// The average of all the r0 and t0 values of the merged jets will provide
204// the r0 and t0 (i.e. reference point) of the final jet.
205//
25eefd00 206// 6) The remaining (merged) jets are ordered w.r.t. decreasing jet quality number.
207// As such the jet with the highest quality number will be the first one
208// in the list, which will result in the fact that the final tracks are also
209// ordered w.r.t. decreasing quality number, as outlined hereafter.
67338e65 210// Each remaining jet will provide the parameters (e.g. direction)
211// for a reconstructed track.
212// The track 3-momentum is set to the total jet 3-momentum, normalised
213// to 1 GeV. The mass and charge of the track are left 0.
413d0114 214// The reference point data of the jet will provide the r0 and t0
215// (i.e. reference point) of the track.
d6860cf1 216//
217// All these tracks will be stored in the IceEvent structure with as
218// default "IceDwalk" as the name of the track.
219// This track name identifier can be modified by the user via the
220// SetTrackName() memberfunction. This will allow unique identification
221// of tracks which are produced when re-processing existing data with
222// different criteria.
30672a96 223// By default the charge of the produced tracks is set to 0, since
224// no distinction can be made between positive or negative tracks.
225// However, the user can define the track charge by invokation
226// of the memberfunction SetCharge().
227// This facility may be used to distinguish tracks produced by the
228// various reconstruction algorithms in a (3D) colour display
229// (see the class AliHelix for further details).
413d0114 230//
67338e65 231// Note : In case the maximum jet opening angle was specified <0,
25eefd00 232// only the jet with the highest quality number will appear
67338e65 233// as a reconstructed track in the IceEvent structure.
234// This will allow comparison with the standard Sieglinde
235// single track direct walk reconstruction results.
236//
237// For further details the user is referred to NIM A524 (2004) 169.
238//
239// Note : This algorithm works best on data which has been calibrated
240// (IceCalibrate), cross talk corrected (IceXtalk) and cleaned
241// from noise hits etc. (IceCleanHits).
242//
243//--- Author: Nick van Eijndhoven 07-oct-2005 Utrecht University
244//- Modified: NvE $Date$ Utrecht University
245///////////////////////////////////////////////////////////////////////////
246
247#include "IceDwalk.h"
248#include "Riostream.h"
249
250ClassImp(IceDwalk) // Class implementation to enable ROOT I/O
251
252IceDwalk::IceDwalk(const char* name,const char* title) : TTask(name,title)
253{
254// Default constructor.
255// The various reconstruction parameters are initialised to the values
256// as mentioned in NIM A524 (2004) 179-180.
257// The newly introduced angular separation parameter for jet merging
258// is initialised as half the value of the angular separation parameter
259// for track candidate clustering.
25eefd00 260 fDmin=75;
261 fDtmarg=0;
262 fMaxdhit=2;
413d0114 263 fTangmax=15;
25eefd00 264 fTdistmax=20;
265 fTinvol=1;
413d0114 266 fJangmax=fTangmax/2.;
25eefd00 267 fJiterate=1;
268 fJdistmax=30;
269 fJinvol=1;
d6860cf1 270 fMaxmodA=999;
6f94f699 271 fMinmodA=0;
25eefd00 272 fMaxhitsA=1;
273 fVgroup=1;
d6860cf1 274 fTrackname="IceDwalk";
30672a96 275 fCharge=0;
67338e65 276}
277///////////////////////////////////////////////////////////////////////////
278IceDwalk::~IceDwalk()
279{
280// Default destructor.
281}
282///////////////////////////////////////////////////////////////////////////
283void IceDwalk::SetDmin(Float_t d)
284{
285// Set minimum hit distance (in m) to form a track element.
25eefd00 286// In the constructor the default has been set to 75 meter.
67338e65 287 fDmin=d;
288}
289///////////////////////////////////////////////////////////////////////////
290void IceDwalk::SetDtmarg(Int_t dt)
291{
292// Set maximum hit time difference margin (in ns) for track elements.
25eefd00 293// In the constructor the default has been set to 0 ns.
67338e65 294 fDtmarg=dt;
295}
296///////////////////////////////////////////////////////////////////////////
25eefd00 297void IceDwalk::SetMaxDhit(Float_t d)
298{
299// Set maximum distance (in scattering length) for a hit to get associated.
300// In the constructor the default has been set to 2 lambda_scat.
301 fMaxdhit=d;
302}
303///////////////////////////////////////////////////////////////////////////
413d0114 304void IceDwalk::SetTangmax(Float_t ang)
67338e65 305{
413d0114 306// Set maximum angular separation (in deg) for track candidate clustering
307// into jets.
67338e65 308// In the constructor the default has been set to 15 deg, in accordance
309// to NIM A524 (2004) 180.
310//
413d0114 311// Note : This function also sets automatically the value of the maximum
312// angular separation for jet merging into 1 single track to ang/2.
313// In order to specify a different max. jet merging separation angle,
314// one has to invoke the memberfunction SetJangmax afterwards.
315
316 fTangmax=ang;
317 fJangmax=ang/2.;
318}
319///////////////////////////////////////////////////////////////////////////
25eefd00 320void IceDwalk::SetTdistmax(Float_t d,Int_t invol)
413d0114 321{
25eefd00 322// Set maximum distance (in m) of the two track candidates in the track
323// clustering process.
324// The distance between the two tracks can be determined restricted to the
325// detector volume (invol=1) or in the overall space (invol=0).
326// The former will prevent clustering of (nearly) parallel tracks which cross
327// the detector volume at very different locations, whereas the latter will
328// enable clustering of tracks with a common location of origin (e.g. muon
329// bundles from an air shower) even if they cross the detector volume at
330// very different locations.
331// At invokation of this memberfunction the default is invol=1.
332// In the constructor the default has been set to 20 meter with invol=1.
67338e65 333
25eefd00 334 fTdistmax=d;
335 fTinvol=invol;
67338e65 336}
337///////////////////////////////////////////////////////////////////////////
25eefd00 338void IceDwalk::SetJangmax(Float_t ang,Int_t iter)
67338e65 339{
340// Set angular separation (in deg) within which jets are merged into 1
341// single track.
25eefd00 342// The merging process is a dynamic procedure and can be carried out by
343// iteration (iter=1) until no further merging of the various jets occurs anymore.
344// However, by specification of iter=0 the user can also select to go only
345// once through all the jet combinations to check for mergers.
346// For large events the latter will in general result in more track candidates.
347// At invokation of this memberfunction the default is iter=1.
348// In the constructor the default angle has been set 7.5 deg, being half
349// of the value of the default track candidate clustering separation angle.
350// The iteration flag was set to 1 in the constructor.
67338e65 351//
352// Notes :
353// -------
354// 1) Setting ang=0 will prevent jet merging.
355// Consequently, every jet will appear as a separate track in the
356// reconstruction result.
357// 2) Setting ang<0 will prevent jet merging.
358// In addition, only the jet with the maximum number of tracks will
359// appear as a track in the reconstruction result.
360// This situation resembles the standard Sieglinde direct walk processing
361// and as such can be used to perform comparison studies.
362
413d0114 363 fJangmax=ang;
25eefd00 364 fJiterate=iter;
413d0114 365}
366///////////////////////////////////////////////////////////////////////////
25eefd00 367void IceDwalk::SetJdistmax(Float_t d,Int_t invol)
413d0114 368{
25eefd00 369// Set maximum distance (in m) of the two jets in the jet merging process.
370// The distance between the two jets can be determined restricted to the
371// detector volume (invol=1) or in the overall space (invol=0).
372// The former will prevent clustering of (nearly) parallel tracks which cross
373// the detector volume at very different locations, whereas the latter will
374// enable clustering of tracks with a common location of origin (e.g. muon
375// bundles from an air shower) even if they cross the detector volume at
376// very different locations.
377// At invokation of this memberfunction the default is invol=1.
378// In the constructor the default has been set to 30 meter with invol=1.
413d0114 379
25eefd00 380 fJdistmax=d;
381 fJinvol=invol;
67338e65 382}
383///////////////////////////////////////////////////////////////////////////
d6860cf1 384void IceDwalk::SetMaxModA(Int_t nmax)
385{
386// Set the maximum number of good Amanda modules that may have fired
387// in order to process this event.
388// This allows suppression of processing (high-energy) cascade events
389// with this direct walk tracking to prevent waisting cpu time for cases
390// in which tracking doesn't make sense anyhow.
391// Furthermore it allows selection of low multiplicity events for processing.
392// By default the maximum number of Amanda modules is set to 999 in the ctor,
6f94f699 393// which implies no selection on maximum module multiplicity.
394// See also the memberfunction SetMinModA().
d6860cf1 395 fMaxmodA=nmax;
396}
397///////////////////////////////////////////////////////////////////////////
6f94f699 398void IceDwalk::SetMinModA(Int_t nmin)
399{
400// Set the minimum number of good Amanda modules that must have fired
401// in order to process this event.
402// This allows selection of a minimal multiplicity for events to be processed.
403// By default the minimum number of Amanda modules is set to 0 in the ctor,
404// which implies no selection on minimum module multiplicity.
405// See also the memberfunction SetMaxModA().
406 fMinmodA=nmin;
407}
408///////////////////////////////////////////////////////////////////////////
35e721bf 409void IceDwalk::SetMaxHitsA(Int_t nmax)
410{
25eefd00 411// Set the maximum number of good hits per Amanda module to be processed.
35e721bf 412//
413// Special values :
25eefd00 414// nmax = 0 : No maximum limit set; all good hits will be processed
35e721bf 415// < 0 : No hits will be processed
416//
25eefd00 417// In case the user selects a maximum number of good hits per module, all the
35e721bf 418// hits of each module will be ordered w.r.t. increasing hit time (LE).
419// This allows selection of processing e.g. only the first hits etc...
25eefd00 420// By default the maximum number of hits per Amanda modules is set to 1 in the ctor,
421// which implies processing only the first good hit of each Amanda OM.
35e721bf 422 fMaxhitsA=nmax;
423}
424///////////////////////////////////////////////////////////////////////////
25eefd00 425void IceDwalk::SetVgroupUsage(Int_t flag)
426{
427// (De)activate the distinction between v_phase and v_group of the Cherenkov light.
428//
429// flag = 0 : No distinction between v_phase and v_group
430// = 1 : Separate treatment of v_phase and v_group
431//
432// By default the distinction between v_phase and v_group is activated
433// in the constructor of this class.
434 fVgroup=flag;
435}
436///////////////////////////////////////////////////////////////////////////
d6860cf1 437void IceDwalk::SetTrackName(TString s)
438{
439// Set (alternative) name identifier for the produced first guess tracks.
440// This allows unique identification of (newly) produced direct walk tracks
441// in case of re-processing of existing data with different criteria.
442// By default the produced first guess tracks have the name "IceDwalk"
443// which is set in the constructor of this class.
444 fTrackname=s;
445}
446///////////////////////////////////////////////////////////////////////////
30672a96 447void IceDwalk::SetCharge(Float_t charge)
448{
449// Set user defined charge for the produced first guess tracks.
450// This allows identification of these tracks on color displays.
451// By default the produced first guess tracks have charge=0
452// which is set in the constructor of this class.
453 fCharge=charge;
454}
455///////////////////////////////////////////////////////////////////////////
67338e65 456void IceDwalk::Exec(Option_t* opt)
457{
458// Implementation of the direct walk track reconstruction.
459
460 TString name=opt;
461 AliJob* parent=(AliJob*)(gROOT->GetListOfTasks()->FindObject(name.Data()));
462
463 if (!parent) return;
464
465 IceEvent* evt=(IceEvent*)parent->GetObject("IceEvent");
466 if (!evt) return;
467
35e721bf 468 // Enter the reco parameters as a device in the event
469 AliSignal params;
470 params.SetNameTitle("IceDwalk","IceDwalk reco parameters");
471 params.SetSlotName("Dmin",1);
472 params.SetSlotName("Dtmarg",2);
25eefd00 473 params.SetSlotName("Maxdhit",3);
474 params.SetSlotName("Tangmax",4);
475 params.SetSlotName("Tdistmax",5);
476 params.SetSlotName("Tinvol",6);
477 params.SetSlotName("Jangmax",7);
478 params.SetSlotName("Jiterate",8);
479 params.SetSlotName("Jdistmax",9);
480 params.SetSlotName("Jinvol",10);
481 params.SetSlotName("MaxmodA",11);
482 params.SetSlotName("MinmodA",12);
483 params.SetSlotName("MaxhitsA",13);
484 params.SetSlotName("Vgroup",14);
35e721bf 485
486 params.SetSignal(fDmin,1);
487 params.SetSignal(fDtmarg,2);
25eefd00 488 params.SetSignal(fMaxdhit,3);
489 params.SetSignal(fTangmax,4);
490 params.SetSignal(fTdistmax,5);
491 params.SetSignal(fTinvol,6);
492 params.SetSignal(fJangmax,7);
493 params.SetSignal(fJiterate,8);
494 params.SetSignal(fJdistmax,9);
495 params.SetSignal(fJinvol,10);
496 params.SetSignal(fMaxmodA,11);
497 params.SetSignal(fMinmodA,12);
498 params.SetSignal(fMaxhitsA,13);
499 params.SetSignal(fVgroup,14);
35e721bf 500
501 evt->AddDevice(params);
502
503 if (fMaxhitsA<0) return;
504
413d0114 505 // Fetch all fired Amanda OMs for this event
506 TObjArray* aoms=evt->GetDevices("IceAOM");
8a394508 507 if (!aoms) return;
413d0114 508 Int_t naoms=aoms->GetEntries();
509 if (!naoms) return;
510
6f94f699 511 // Check for the minimum and/or maximum number of good fired Amanda OMs
d6860cf1 512 Int_t ngood=0;
513 for (Int_t iom=0; iom<naoms; iom++)
514 {
515 IceGOM* omx=(IceGOM*)aoms->At(iom);
516 if (!omx) continue;
517 if (omx->GetDeadValue("ADC") || omx->GetDeadValue("LE") || omx->GetDeadValue("TOT")) continue;
518 ngood++;
519 }
6f94f699 520 if (ngood<fMinmodA || ngood>fMaxmodA) return;
d6860cf1 521
25eefd00 522 const Float_t pi=acos(-1.);
523 const Float_t c=0.299792458; // Light speed in vacuum in meters per ns
524 const Float_t npice=1.31768387; // Phase refractive index (c/v_phase) of ice
525 const Float_t ngice=1.35075806; // Group refractive index (c/v_group) of ice
526 const Float_t lambda=33.3; // Light scattering length in ice
527 const Float_t thetac=acos(1./npice); // Cherenkov angle (in radians)
528
529 // Angular reduction of complement of thetac due to v_phase and v_group difference
530 Float_t alphac=0;
531 if (fVgroup) alphac=atan((1.-npice/ngice)/sqrt(npice*npice-1.));
67338e65 532
35e721bf 533 // Storage of track elements.
67338e65 534 TObjArray tes;
535 tes.SetOwner();
67338e65 536
537 AliPosition r1;
538 AliPosition r2;
539 Ali3Vector r12;
80701e9a 540 Ali3Vector rsum;
67338e65 541 AliPosition r0;
542 TObjArray hits1;
543 TObjArray hits2;
544 Int_t nh1,nh2;
545 AliSignal* sx1=0;
546 AliSignal* sx2=0;
25eefd00 547 Float_t dist=0,dist2=0;
67338e65 548 Float_t t1,t2,dt,t0;
35e721bf 549 Float_t dtmax;
67338e65 550 TObjArray hits;
35e721bf 551 TObjArray* ordered;
67338e65 552
553 // Check the hits of Amanda OM pairs for posible track elements.
554 // Also all the good hits are stored in the meantime (to save CPU time)
555 // for hit association with the various track elements lateron.
67338e65 556 AliTrack* te=0;
67338e65 557 for (Int_t i1=0; i1<naoms; i1++) // First OM of the pair
558 {
559 IceGOM* omx1=(IceGOM*)aoms->At(i1);
560 if (!omx1) continue;
561 if (omx1->GetDeadValue("LE")) continue;
562 r1=omx1->GetPosition();
563 // Select all the good hits of this first OM
564 hits1.Clear();
35e721bf 565 // Determine the max. number of hits to be processed for this OM
566 ordered=0;
567 if (fMaxhitsA>0 && omx1->GetNhits()>fMaxhitsA) ordered=omx1->SortHits("LE",1,0,7);
568 nh1=0;
67338e65 569 for (Int_t j1=1; j1<=omx1->GetNhits(); j1++)
570 {
35e721bf 571 if (ordered)
572 {
573 if (nh1>=fMaxhitsA) break;
574 sx1=(AliSignal*)ordered->At(j1-1);
575 }
576 else
577 {
578 sx1=omx1->GetHit(j1);
579 }
67338e65 580 if (!sx1) continue;
581 if (sx1->GetDeadValue("ADC") || sx1->GetDeadValue("LE") || sx1->GetDeadValue("TOT")) continue;
582 hits1.Add(sx1);
583 // Also store all good hits in the total hit array
584 hits.Add(sx1);
35e721bf 585 nh1++;
67338e65 586 }
587
588 // No further pair to be formed with the last OM in the list
589 if (i1==(naoms-1)) break;
590
591 nh1=hits1.GetEntries();
592 if (!nh1) continue;
593
594 for (Int_t i2=i1+1; i2<naoms; i2++) // Second OM of the pair
595 {
596 IceGOM* omx2=(IceGOM*)aoms->At(i2);
597 if (!omx2) continue;
598 if (omx2->GetDeadValue("LE")) continue;
599 r2=omx2->GetPosition();
600 r12=r2-r1;
601 dist=r12.GetNorm();
413d0114 602
67338e65 603 if (dist<=fDmin) continue;
413d0114 604
67338e65 605 // Select all the good hits of this second OM
606 hits2.Clear();
35e721bf 607 // Determine the max. number of hits to be processed for this OM
608 ordered=0;
609 if (fMaxhitsA>0 && omx2->GetNhits()>fMaxhitsA) ordered=omx2->SortHits("LE",1,0,7);
610 nh2=0;
67338e65 611 for (Int_t j2=1; j2<=omx2->GetNhits(); j2++)
612 {
35e721bf 613 if (ordered)
614 {
615 if (nh2>=fMaxhitsA) break;
616 sx2=(AliSignal*)ordered->At(j2-1);
617 }
618 else
619 {
620 sx2=omx2->GetHit(j2);
621 }
67338e65 622 if (!sx2) continue;
623 if (sx2->GetDeadValue("ADC") || sx2->GetDeadValue("LE") || sx2->GetDeadValue("TOT")) continue;
624 hits2.Add(sx2);
35e721bf 625 nh2++;
67338e65 626 }
627
628 nh2=hits2.GetEntries();
629 if (!nh2) continue;
630
413d0114 631 // Position r0 in between the two OMs and normalised relative direction r12
632 rsum=(r1+r2)/2.;
633 r0.SetPosition((Ali3Vector&)rsum);
634 r12/=dist;
635
67338e65 636 // Check all hit pair combinations of these two OMs for possible track elements
413d0114 637 dtmax=dist/c+float(fDtmarg);
67338e65 638 for (Int_t ih1=0; ih1<nh1; ih1++) // Hits of first OM
639 {
640 sx1=(AliSignal*)hits1.At(ih1);
641 if (!sx1) continue;
642 for (Int_t ih2=0; ih2<nh2; ih2++) // Hits of second OM
643 {
644 sx2=(AliSignal*)hits2.At(ih2);
645 if (!sx2) continue;
646 t1=sx1->GetSignal("LE",7);
647 t2=sx2->GetSignal("LE",7);
648 dt=t2-t1;
649 t0=(t1+t2)/2.;
413d0114 650
651 if (fabs(dt)>=dtmax) continue;
652
653 te=new AliTrack();
654 tes.Add(te);
413d0114 655 if (dt<0) r12*=-1.;
656 r0.SetTimestamp((AliTimestamp&)*evt);
657 AliTimestamp* tsx=r0.GetTimestamp();
658 tsx->Add(0,0,(int)t0);
659 te->SetReferencePoint(r0);
660 te->Set3Momentum(r12);
67338e65 661 }
662 }
663 } // end of loop over the second OM of the pair
664 } // end of loop over first OM of the pair
665
25eefd00 666 // Association of hits to the various track elements.
67338e65 667 Int_t nte=tes.GetEntries();
668 Int_t nh=hits.GetEntries();
669 Float_t d=0;
670 Ali3Vector p;
671 Float_t tgeo,tres;
25eefd00 672 AliSample levers; // Statistics of the assoc. hit lever arms
673 levers.SetStoreMode(1);// Enable median calculation
674 AliSample hprojs; // Statistics of the assoc. hit position projections on the track w.r.t. r0
675 hprojs.SetStoreMode(1);// Enable median calculation
676 AliSample times; // Statistics of the time residuals of the associated hits
677 times.SetStoreMode(1); // Enable median calculation
678 AliSignal fit; // Storage of Q value etc... for each track candidate
679 fit.AddNamedSlot("QTC");
680 fit.AddNamedSlot("SpanL");
681 fit.AddNamedSlot("MedianL");
682 fit.AddNamedSlot("MeanL");
683 fit.AddNamedSlot("SigmaL");
684 fit.AddNamedSlot("SpreadL");
685 fit.AddNamedSlot("ExpSpreadL");
686 fit.AddNamedSlot("Span");
687 fit.AddNamedSlot("Median");
688 fit.AddNamedSlot("Mean");
689 fit.AddNamedSlot("Sigma");
690 fit.AddNamedSlot("Spread");
691 fit.AddNamedSlot("ExpSpread");
692 fit.AddNamedSlot("MedianT");
693 fit.AddNamedSlot("MeanT");
694 fit.AddNamedSlot("SigmaT");
695 fit.AddNamedSlot("SpreadT");
696 fit.AddNamedSlot("term1");
697 fit.AddNamedSlot("term2");
698 fit.AddNamedSlot("term3");
699 fit.AddNamedSlot("term4");
700 fit.AddNamedSlot("term5");
67338e65 701 Float_t qtc=0,qmax=0;
25eefd00 702 Int_t nah,nahmax=0; // Number of associated hits for a certain TE
703 Float_t lmin,lmax,spanl,medianl,meanl,sigmal,spreadl,expspreadl;
704 Float_t hproj,hprojmin,hprojmax,span,median,mean,sigma,spread,expspread;
705 Float_t mediant,meant,sigmat,spreadt;
706 Float_t term1,term2,term3,term4,term5;
67338e65 707 for (Int_t jte=0; jte<nte; jte++)
708 {
709 te=(AliTrack*)tes.At(jte);
710 if (!te) continue;
67338e65 711 AliPosition* tr0=te->GetReferencePoint();
413d0114 712 AliTimestamp* tt0=tr0->GetTimestamp();
713 t0=evt->GetDifference(tt0,"ns");
714 p=te->Get3Momentum();
67338e65 715 levers.Reset();
25eefd00 716 hprojs.Reset();
717 times.Reset();
67338e65 718 for (Int_t jh=0; jh<nh; jh++)
719 {
720 sx1=(AliSignal*)hits.At(jh);
721 if (!sx1) continue;
722 IceGOM* omx=(IceGOM*)sx1->GetDevice();
723 if (!omx) continue;
724 r1=omx->GetPosition();
35e721bf 725 d=te->GetDistance(r1);
67338e65 726 r12=r1-(*tr0);
25eefd00 727 hproj=p.Dot(r12);
728 dist=hproj+d/tan(pi/2.-thetac-alphac);
67338e65 729 tgeo=t0+dist/c;
730 t1=sx1->GetSignal("LE",7);
731 tres=t1-tgeo;
732
25eefd00 733 if (tres<-30 || tres>300 || d>fMaxdhit*lambda) continue;
67338e65 734
735 // Associate this hit to the TE
736 te->AddSignal(*sx1);
25eefd00 737 levers.Enter(fabs(hproj));
738 hprojs.Enter(hproj);
739 times.Enter(tres);
67338e65 740 }
413d0114 741
742 // Determine the Q quality of the various TE's.
743 // Good quality TE's will be called track candidates (TC's)
67338e65 744 nah=te->GetNsignals();
25eefd00 745 if (nah>nahmax) nahmax=nah;
746 lmin=levers.GetMinimum(1);
747 lmax=levers.GetMaximum(1);
748 spanl=lmax-lmin;
749 medianl=levers.GetMedian(1);
750 meanl=levers.GetMean(1);
67338e65 751 sigmal=levers.GetSigma(1);
25eefd00 752 spreadl=levers.GetSpread(1);
753 // Expected spread for a flat distribution
754 expspreadl=0;
755 if (spanl>0) expspreadl=(0.5*pow(lmin,2)+0.5*pow(lmax,2)+pow(medianl,2)-medianl*(lmin+lmax))/spanl;
756 hprojmin=hprojs.GetMinimum(1);
757 hprojmax=hprojs.GetMaximum(1);
758 span=hprojmax-hprojmin;
759 median=hprojs.GetMedian(1);
760 mean=hprojs.GetMean(1);
761 sigma=hprojs.GetSigma(1);
762 spread=hprojs.GetSpread(1);
763 // Expected spread for a flat distribution
764 expspread=0;
765 if (span>0) expspread=(0.5*pow(hprojmin,2)+0.5*pow(hprojmax,2)+pow(median,2)-median*(hprojmin+hprojmax))/span;
766 mediant=times.GetMedian(1);
767 meant=times.GetMean(1);
768 sigmat=times.GetSigma(1);
769 spreadt=times.GetSpread(1);
770
771 term1=0;
772 if (span>0) term1=2.*spread/span;
773
774 term2=0;
775 if (spanl>0) term2=2.*spreadl/spanl;
776
777 term3=0;
778 if (spread>0) term3=fabs(spread-expspread)/spread;
779
780 term4=0;
781 if (spreadl>0) term4=fabs(spreadl-expspreadl)/spreadl;
782
783 term5=0;
784 if (spreadt>0) term5=fabs(mediant)/spreadt;
785
786 qtc=float(nah)*(term1+term2)-term3-term4-term5;
787 if (fabs(median)>span/2.) qtc=0; // Require projected hits on both sides of r0
788
413d0114 789 fit.SetSignal(qtc,"QTC");
25eefd00 790 fit.SetSignal(spanl,"SpanL");
791 fit.SetSignal(medianl,"MedianL");
792 fit.SetSignal(meanl,"MeanL");
793 fit.SetSignal(sigmal,"SigmaL");
794 fit.SetSignal(spreadl,"SpreadL");
795 fit.SetSignal(expspreadl,"ExpSpreadL");
796 fit.SetSignal(span,"Span");
797 fit.SetSignal(median,"Median");
798 fit.SetSignal(mean,"Mean");
799 fit.SetSignal(sigma,"Sigma");
800 fit.SetSignal(spread,"Spread");
801 fit.SetSignal(expspread,"ExpSpread");
802 fit.SetSignal(mediant,"MedianT");
803 fit.SetSignal(meant,"MeanT");
804 fit.SetSignal(sigmat,"SigmaT");
805 fit.SetSignal(spreadt,"SpreadT");
806 fit.SetSignal(term1,"term1");
807 fit.SetSignal(term2,"term2");
808 fit.SetSignal(term3,"term3");
809 fit.SetSignal(term4,"term4");
810 fit.SetSignal(term5,"term5");
413d0114 811 te->SetFitDetails(fit);
812 if (qtc>qmax) qmax=qtc;
67338e65 813 }
67338e65 814
815 // Perform selection on Q value in case of multiple track candidates
816 for (Int_t jtc=0; jtc<nte; jtc++)
817 {
818 te=(AliTrack*)tes.At(jtc);
819 if (!te) continue;
25eefd00 820 nah=te->GetNsignals();
67338e65 821 sx1=(AliSignal*)te->GetFitDetails();
413d0114 822 qtc=-1;
823 if (sx1) qtc=sx1->GetSignal("QTC");
25eefd00 824 if (!nah || qtc<0.8*qmax)
67338e65 825 {
67338e65 826 tes.RemoveAt(jtc);
827 delete te;
828 }
25eefd00 829 else // Set Q value as momentum to provide a weight for jet clustering
830 {
831 if (qtc>0)
832 {
833 p=te->Get3Momentum();
834 p*=qtc;
835 te->Set3Momentum(p);
836 }
837 }
67338e65 838 }
839 tes.Compress();
840 nte=tes.GetEntries();
841
413d0114 842 if (!nte) return;
843
413d0114 844 // Cluster track candidates within a certain opening angle into jets.
25eefd00 845 // Also the track should be within a certain maximum distance of the
846 // starting track in order to get clustered.
413d0114 847 // The latter prevents clustering of (nearly) parallel track candidates
848 // crossing the detector a very different locations (e.g. muon bundles).
849 // The average r0 and t0 of the constituent tracks will be taken as the
850 // jet reference point.
67338e65 851 TObjArray jets;
852 jets.SetOwner();
853 AliTrack* te2=0;
854 Float_t ang=0;
413d0114 855 AliSample pos;
856 AliSample time;
857 Float_t vec[3],err[3];
25eefd00 858 nahmax=0; // Determine the max. number of associated hits for the jets
67338e65 859 for (Int_t jtc1=0; jtc1<nte; jtc1++)
860 {
25eefd00 861 te=(AliTrack*)tes.At(jtc1);
67338e65 862 if (!te) continue;
413d0114 863 AliPosition* x1=te->GetReferencePoint();
864 if (!x1) continue;
865 AliTimestamp* ts1=x1->GetTimestamp();
866 if (!ts1) continue;
67338e65 867 AliJet* jx=new AliJet();
868 jx->AddTrack(te);
413d0114 869 pos.Reset();
870 time.Reset();
871 x1->GetPosition(vec,"car");
872 pos.Enter(vec[0],vec[1],vec[2]);
873 t0=evt->GetDifference(ts1,"ns");
874 time.Enter(t0);
67338e65 875 for (Int_t jtc2=0; jtc2<nte; jtc2++)
876 {
413d0114 877 if (jtc2==jtc1) continue;
25eefd00 878 te2=(AliTrack*)tes.At(jtc2);
67338e65 879 if (!te2) continue;
880 ang=te->GetOpeningAngle(*te2,"deg");
25eefd00 881 if (ang<=fTangmax)
413d0114 882 {
883 AliPosition* x2=te2->GetReferencePoint();
884 if (!x2) continue;
885 AliTimestamp* ts2=x2->GetTimestamp();
886 if (!ts2) continue;
25eefd00 887 if (!fTinvol)
413d0114 888 {
25eefd00 889 dist=te->GetDistance(te2);
890 }
891 else
892 {
893 dist=te->GetDistance(x2);
894 dist2=te2->GetDistance(x1);
895 if (dist2<dist) dist=dist2;
896 }
897 if (dist<=fTdistmax)
898 {
899 x2->GetPosition(vec,"car");
900 pos.Enter(vec[0],vec[1],vec[2]);
901 t0=evt->GetDifference(ts2,"ns");
902 time.Enter(t0);
903 jx->AddTrack(te2);
413d0114 904 }
905 }
906 }
907
908 // Set the reference point data for this jet
909 for (Int_t j=1; j<=3; j++)
910 {
911 vec[j-1]=pos.GetMean(j);
912 err[j-1]=pos.GetSigma(j);
913 }
914 r0.SetPosition(vec,"car");
915 r0.SetPositionErrors(err,"car");
916 r0.SetTimestamp((AliTimestamp&)*evt);
917 AliTimestamp* jt0=r0.GetTimestamp();
918 t0=time.GetMean(1);
919 jt0->Add(0,0,(int)t0);
920 jx->SetReferencePoint(r0);
921
922 // Store this jet for further processing if ntracks>1
25eefd00 923 if (jx->GetNtracks() > 1 || fTangmax<=0)
413d0114 924 {
925 jets.Add(jx);
25eefd00 926 nah=jx->GetNsignals();
927 if (nah>nahmax) nahmax=nah;
413d0114 928 }
929 else // Only keep single-track jets which have qtc=qmax
930 {
931 sx1=(AliSignal*)te->GetFitDetails();
932 qtc=-1;
933 if (sx1) qtc=sx1->GetSignal("QTC");
934 if (qtc>=(qmax-1.e-10))
935 {
936 jets.Add(jx);
25eefd00 937 nah=jx->GetNsignals();
938 if (nah>nahmax) nahmax=nah;
413d0114 939 }
940 else
941 {
942 delete jx;
943 }
67338e65 944 }
945 }
413d0114 946 Int_t njets=jets.GetEntries();
947
948 if (!njets) return;
67338e65 949
25eefd00 950 // The sum of 0.15*(nah-nahmax) and average qtc value per track for this jet
951 // will be stored as the jet energy to enable sorting on this value lateron
952 Float_t sortval=0;
953 Int_t ntk=0;
954 for (Int_t ijet=0; ijet<njets; ijet++)
955 {
956 AliJet* jx=(AliJet*)jets.At(ijet);
957 if (!jx) continue;
958 nah=jx->GetNsignals();
959 ntk=jx->GetNtracks();
960 sortval=0.15*float(nah-nahmax);
961 if (ntk) sortval+=jx->GetMomentum()/float(ntk);
962 jx->SetScalar(sortval);
963 }
964
965 // Order the jets w.r.t. decreasing value of the above sortval
966 ordered=evt->SortJets(-2,&jets);
67338e65 967 TObjArray jets2(*ordered);
67338e65 968
969 // Merge jets within a certain opening to provide the final track(s).
25eefd00 970 // Also the jet should be within a certain maximum distance of the
971 // starting jet in order to get merged.
972 // The latter prevents merging of (nearly) parallel jets/tracks
973 // crossing the detector a very different locations (e.g. muon bundles).
974 // The average r0 and t0 of the constituent jets will be taken as the
975 // final reference point.
67338e65 976 AliJet* jx1=0;
977 AliJet* jx2=0;
25eefd00 978 Int_t merged=1;
979 if (fJangmax>=0)
67338e65 980 {
25eefd00 981 while (merged)
67338e65 982 {
25eefd00 983 merged=0;
984 nahmax=0;
985 for (Int_t jet1=0; jet1<njets; jet1++)
67338e65 986 {
25eefd00 987 jx1=(AliJet*)jets2.At(jet1);
988 if (!jx1) continue;
989 AliPosition* x1=jx1->GetReferencePoint();
990 if (!x1) continue;
991 AliTimestamp* ts1=x1->GetTimestamp();
992 if (!ts1) continue;
993 pos.Reset();
994 time.Reset();
995 x1->GetPosition(vec,"car");
996 pos.Enter(vec[0],vec[1],vec[2]);
997 t0=evt->GetDifference(ts1,"ns");
998 time.Enter(t0);
999 for (Int_t jet2=0; jet2<njets; jet2++)
67338e65 1000 {
25eefd00 1001 jx2=(AliJet*)jets2.At(jet2);
1002 if (!jx2 || jet2==jet1) continue;
1003 AliPosition* x2=jx2->GetReferencePoint();
1004 if (!x2) continue;
1005 AliTimestamp* ts2=x2->GetTimestamp();
1006 if (!ts2) continue;
1007 ang=jx1->GetOpeningAngle(*jx2,"deg");
1008 if (ang<=fJangmax)
67338e65 1009 {
25eefd00 1010 if (!fJinvol)
413d0114 1011 {
25eefd00 1012 dist=jx1->GetDistance(jx2);
1013 }
1014 else
1015 {
1016 dist=jx1->GetDistance(x2);
1017 dist2=jx2->GetDistance(x1);
1018 if (dist2<dist) dist=dist2;
1019 }
1020 if (dist<=fJdistmax)
1021 {
1022 x2->GetPosition(vec,"car");
1023 pos.Enter(vec[0],vec[1],vec[2]);
1024 t0=evt->GetDifference(ts2,"ns");
1025 time.Enter(t0);
1026 for (Int_t jtk=1; jtk<=jx2->GetNtracks(); jtk++)
1027 {
1028 te=jx2->GetTrack(jtk);
1029 if (!te) continue;
1030 jx1->AddTrack(te);
1031 }
1032 jets2.RemoveAt(jet2);
1033 if (fJiterate) merged=1;
413d0114 1034 }
67338e65 1035 }
25eefd00 1036 } // End of jet2 loop
1037
1038 // Set the reference point data for this jet
1039 for (Int_t k=1; k<=3; k++)
1040 {
1041 vec[k-1]=pos.GetMean(k);
1042 err[k-1]=pos.GetSigma(k);
67338e65 1043 }
25eefd00 1044 r0.SetPosition(vec,"car");
1045 r0.SetPositionErrors(err,"car");
1046 r0.SetTimestamp((AliTimestamp&)*evt);
1047 AliTimestamp* jt0=r0.GetTimestamp();
1048 t0=time.GetMean(1);
1049 jt0->Add(0,0,(int)t0);
1050 jx1->SetReferencePoint(r0);
1051
1052 nah=jx1->GetNsignals();
1053 if (nah>nahmax) nahmax=nah;
1054 } // End of jet1 loop
1055
1056 jets2.Compress();
1057
1058 // The sum of 0.15*(nah-nahmax) and average qtc value per track for this jet
1059 // will be stored as the jet energy to enable sorting on this value lateron
1060 for (Int_t jjet=0; jjet<njets; jjet++)
1061 {
1062 AliJet* jx=(AliJet*)jets2.At(jjet);
1063 if (!jx) continue;
1064 nah=jx->GetNsignals();
1065 ntk=jx->GetNtracks();
1066 sortval=0.15*float(nah-nahmax);
1067 if (ntk) sortval+=jx->GetMomentum()/float(ntk);
1068 jx->SetScalar(sortval);
67338e65 1069 }
25eefd00 1070
1071 // Order the jets w.r.t. decreasing value of the above sortval
1072 ordered=evt->SortJets(-2,&jets2);
1073 njets=ordered->GetEntries();
1074 jets2.Clear();
1075 for (Int_t icopy=0; icopy<njets; icopy++)
413d0114 1076 {
25eefd00 1077 jets2.Add(ordered->At(icopy));
413d0114 1078 }
25eefd00 1079 } // End of iterative while loop
67338e65 1080 }
1081
1082 // Store every jet as a reconstructed track in the event structure.
413d0114 1083 // The jet 3-momentum (normalised to 1) and reference point
1084 // (i.e.the average r0 and t0 of the constituent tracks) will make up
1085 // the final track parameters.
67338e65 1086 // All the associated hits of all the constituent tracks of the jet
1087 // will be associated to the final track.
1088 // In case the jet angular separation was set <0, only the jet with
1089 // the maximum number of tracks (i.e. the first one in the array)
1090 // will be used to form a track. This will allow comparison with
1091 // the standard Sieglinde processing.
67338e65 1092 AliTrack t;
d6860cf1 1093 t.SetNameTitle(fTrackname.Data(),"IceDwalk direct walk track");
30672a96 1094 t.SetCharge(fCharge);
67338e65 1095 for (Int_t jet=0; jet<njets; jet++)
1096 {
1097 AliJet* jx=(AliJet*)jets2.At(jet);
1098 if (!jx) continue;
413d0114 1099 AliPosition* ref=jx->GetReferencePoint();
1100 if (!ref) continue;
67338e65 1101 evt->AddTrack(t);
1102 AliTrack* trk=evt->GetTrack(evt->GetNtracks());
1103 if (!trk) continue;
1104 trk->SetId(evt->GetNtracks(1)+1);
1105 p=jx->Get3Momentum();
1106 p/=p.GetNorm();
1107 trk->Set3Momentum(p);
413d0114 1108 trk->SetReferencePoint(*ref);
1109 AliTimestamp* tt0=ref->GetTimestamp();
1110 if (tt0) trk->SetTimestamp(*tt0);
67338e65 1111 for (Int_t jt=1; jt<=jx->GetNtracks(); jt++)
1112 {
1113 AliTrack* tx=jx->GetTrack(jt);
1114 if (!tx) continue;
67338e65 1115 for (Int_t is=1; is<=tx->GetNsignals(); is++)
1116 {
1117 sx1=tx->GetSignal(is);
d0120ca2 1118 if (sx1) sx1->AddTrack(*trk);
67338e65 1119 }
1120 }
67338e65 1121
25eefd00 1122 // Only take the jet with the highest quality number
67338e65 1123 // (i.e. the first jet in the list) when the user had selected
1124 // this reconstruction mode.
413d0114 1125 if (fJangmax<0) break;
67338e65 1126 }
67338e65 1127}
1128///////////////////////////////////////////////////////////////////////////