With Boris and Antonin:
[u/mrichter/AliRoot.git] / HLT / MUON / OnlineAnalysis / AliHLTMUONMansoTrackerFSMComponent.cxx
CommitLineData
b92524d0 1/**************************************************************************
2 * This file is property of and copyright by the ALICE HLT Project *
3 * All rights reserved. *
4 * *
5 * Primary Authors: *
6 * Artur Szostak <artursz@iafrica.com> *
7 * Indranil Das <indra.das@saha.ac.in> *
8 * *
9 * Permission to use, copy, modify and distribute this software and its *
10 * documentation strictly for non-commercial purposes is hereby granted *
11 * without fee, provided that the above copyright notice appears in all *
12 * copies and that both the copyright notice and this permission notice *
13 * appear in the supporting documentation. The authors make no claims *
14 * about the suitability of this software for any purpose. It is *
15 * provided "as is" without express or implied warranty. *
16 **************************************************************************/
17
18/* $Id$ */
19
6253e09b 20///
21/// @file AliHLTMUONMansoTrackerFSMComponent.cxx
22/// @author Artur Szostak <artursz@iafrica.com>,
23/// Indranil Das <indra.das@saha.ac.in>
24/// @date
25/// @brief Implementation of AliHLTMUONMansoTrackerFSMComponent class.
26///
b92524d0 27
28#include "AliHLTMUONMansoTrackerFSMComponent.h"
29#include "AliHLTMUONConstants.h"
30#include "AliHLTMUONUtils.h"
31#include "AliHLTMUONMansoTrackerFSM.h"
32#include "AliHLTMUONDataBlockReader.h"
33#include "AliHLTMUONDataBlockWriter.h"
34#include <cstdlib>
d42549e3 35#include <cstring>
b92524d0 36#include <cerrno>
5bf92d6f 37#include <new>
b92524d0 38
b92524d0 39ClassImp(AliHLTMUONMansoTrackerFSMComponent);
40
41
42AliHLTMUONMansoTrackerFSMComponent::AliHLTMUONMansoTrackerFSMComponent() :
43 AliHLTProcessor(),
44 AliHLTMUONMansoTrackerFSMCallback(),
45 fTracker(NULL),
46 fTrackCount(0),
d42549e3 47 fBlock(NULL),
5bf92d6f 48 fRecHitBlockArraySize(0),
d42549e3 49 fWarnForUnexpecedBlock(false)
b92524d0 50{
6253e09b 51 ///
52 /// Default constructor.
53 ///
5bf92d6f 54
55 for (Int_t i = 0; i < 4; i++)
56 {
57 fRecHitBlockCount[i] = 0;
58 fRecHitBlock[i] = NULL;
59 }
b92524d0 60}
61
62
63AliHLTMUONMansoTrackerFSMComponent::~AliHLTMUONMansoTrackerFSMComponent()
64{
6253e09b 65 ///
66 /// Default destructor.
67 ///
68
b92524d0 69 assert( fTracker == NULL );
5bf92d6f 70 assert( fRecHitBlock[0] == NULL );
b92524d0 71}
72
73
74const char* AliHLTMUONMansoTrackerFSMComponent::GetComponentID()
75{
6253e09b 76 ///
77 /// Inherited from AliHLTComponent. Returns the component ID.
78 ///
79
b92524d0 80 return AliHLTMUONConstants::MansoTrackerFSMId();
81}
82
83
84void AliHLTMUONMansoTrackerFSMComponent::GetInputDataTypes(
85 vector<AliHLTComponentDataType>& list
86 )
87{
6253e09b 88 ///
89 /// Inherited from AliHLTProcessor. Returns the list of expected input data types.
90 ///
91
b92524d0 92 assert( list.empty() );
93 list.push_back( AliHLTMUONConstants::TriggerRecordsBlockDataType() );
94 list.push_back( AliHLTMUONConstants::RecHitsBlockDataType() );
95}
96
97
98AliHLTComponentDataType AliHLTMUONMansoTrackerFSMComponent::GetOutputDataType()
99{
6253e09b 100 ///
101 /// Inherited from AliHLTComponent. Returns the output data type.
102 ///
103
b92524d0 104 return AliHLTMUONConstants::MansoTracksBlockDataType();
105}
106
107
108void AliHLTMUONMansoTrackerFSMComponent::GetOutputDataSize(
109 unsigned long& constBase, double& inputMultiplier
110 )
111{
6253e09b 112 ///
113 /// Inherited from AliHLTComponent. Returns an estimate of the expected output data size.
114 ///
115
b92524d0 116 constBase = sizeof(AliHLTMUONMansoTracksBlockStruct);
117 inputMultiplier = 1;
118}
119
120
121AliHLTComponent* AliHLTMUONMansoTrackerFSMComponent::Spawn()
122{
6253e09b 123 ///
124 /// Inherited from AliHLTComponent. Creates a new object instance.
125 ///
126
b92524d0 127 return new AliHLTMUONMansoTrackerFSMComponent;
128}
129
130
131int AliHLTMUONMansoTrackerFSMComponent::DoInit(int argc, const char** argv)
132{
6253e09b 133 ///
134 /// Inherited from AliHLTComponent.
135 /// Parses the command line parameters and initialises the component.
136 ///
137
6ec6a7c1 138 HLTInfo("Initialising dHLT manso tracker FSM component.");
139
5bf92d6f 140 try
141 {
142 fTracker = new AliHLTMUONMansoTrackerFSM();
143 }
144 catch (const std::bad_alloc&)
145 {
146 HLTError("Could not allocate more memory for the tracker component.");
147 return -ENOMEM;
148 }
b92524d0 149 fTracker->SetCallback(this);
d42549e3 150
151 fWarnForUnexpecedBlock = false;
152
153 for (int i = 0; i < argc; i++)
154 {
155 if (strcmp(argv[i], "-warn_on_unexpected_block") == 0)
47415aa9 156 {
d42549e3 157 fWarnForUnexpecedBlock = true;
47415aa9 158 continue;
159 }
160
161 HLTError("Unknown option '%s'.", argv[i]);
162 return EINVAL;
d42549e3 163 }
164
5bf92d6f 165 const int initArraySize = 10;
166 // allocate some initial memory for the reconstructed hit arrays.
167 try
168 {
169 fRecHitBlock[0] = new AliRecHitBlockInfo[initArraySize*4];
170 }
171 catch (const std::bad_alloc&)
172 {
173 HLTError("Could not allocate more memory for the reconstructed hit arrays.");
174 return -ENOMEM;
175 }
176 // Only set the arrays' size once we have successfully allocated the memory for the arrays.
177 fRecHitBlockArraySize = initArraySize;
178 // Now we need to set the pointers fRecHitBlock[i] {i>0} relative to fRecHitBlock[0].
179 for (Int_t i = 1; i < 4; i++)
180 {
181 fRecHitBlock[i] = fRecHitBlock[i-1] + fRecHitBlockArraySize;
182 }
183 // And reset the number of records actually stored in the arrays.
184 for (Int_t i = 0; i < 4; i++)
185 {
186 fRecHitBlockCount[i] = 0;
187 }
188
b92524d0 189 return 0;
190}
191
192
193int AliHLTMUONMansoTrackerFSMComponent::DoDeinit()
194{
6253e09b 195 ///
196 /// Inherited from AliHLTComponent. Performs a cleanup of the component.
197 ///
198
6ec6a7c1 199 HLTInfo("Deinitialising dHLT manso tracker FSM component.");
200
b92524d0 201 if (fTracker != NULL)
202 {
203 delete fTracker;
204 fTracker = NULL;
205 }
5bf92d6f 206
207 // Remember that only fRecHitBlock[0] stores the pointer to the allocated memory.
208 // The other pointers are just reletive to this.
209 if (fRecHitBlock[0] != NULL)
210 delete [] fRecHitBlock[0];
211
212 fRecHitBlockArraySize = 0;
213 for (Int_t i = 0; i < 4; i++)
214 {
215 fRecHitBlockCount[i] = 0;
216 fRecHitBlock[i] = NULL;
217 }
218
b92524d0 219 return 0;
220}
221
222
223int AliHLTMUONMansoTrackerFSMComponent::DoEvent(
224 const AliHLTComponentEventData& evtData,
5def1693 225 const AliHLTComponentBlockData* blocks,
226 AliHLTComponentTriggerData& /*trigData*/,
227 AliHLTUInt8_t* outputPtr,
b92524d0 228 AliHLTUInt32_t& size,
229 std::vector<AliHLTComponentBlockData>& outputBlocks
230 )
231{
6253e09b 232 ///
233 /// Inherited from AliHLTProcessor. Processes the new event data.
234 ///
235
b92524d0 236 Reset();
237 AliHLTUInt32_t specification = 0; // Contains the output data block spec bits.
238
5bf92d6f 239 // Resize the rec hit arrays if we need to. To guarantee that they will not overflow
240 // we need to make sure each array is at least as big as the number of input data block.
241 if (fRecHitBlockArraySize < evtData.fBlockCnt)
242 {
243 // Release the old memory block and allocate more memory.
244 delete [] fRecHitBlock[0];
245 // Reset the number of records actually stored in the arrays.
246 for (Int_t i = 0; i < 4; i++)
247 {
248 fRecHitBlockCount[i] = 0;
249 }
250
251 try
252 {
253 fRecHitBlock[0] = new AliRecHitBlockInfo[evtData.fBlockCnt*4];
254 }
255 catch (const std::bad_alloc&)
256 {
257 HLTError("Could not allocate more memory for the reconstructed hit arrays.");
258 // Ok so now we need to clear all the pointers because we actually
259 // deleted the memory.
260 fRecHitBlockArraySize = 0;
261 for (Int_t i = 0; i < 4; i++)
262 {
263 fRecHitBlock[i] = NULL;
264 }
265 return -ENOMEM;
266 }
267 // Only set the arrays' size once we have successfully allocated the memory for the arrays.
268 fRecHitBlockArraySize = evtData.fBlockCnt;
269 // Now we need to set the pointers fRecHitBlock[i] {i>0} relative to fRecHitBlock[0].
270 for (Int_t i = 1; i < 4; i++)
271 {
272 fRecHitBlock[i] = fRecHitBlock[i-1] + fRecHitBlockArraySize;
273 }
274 }
275
b92524d0 276 AliHLTMUONMansoTracksBlockWriter block(outputPtr, size);
277 fBlock = &block;
278
279 if (not block.InitCommonHeader())
280 {
281 Logging(kHLTLogError,
282 "AliHLTMUONMansoTrackerFSMComponent::DoEvent",
283 "Buffer overflow",
284 "The buffer is only %d bytes in size. We need a minimum of %d bytes.",
285 size, sizeof(AliHLTMUONMansoTracksBlockWriter::HeaderType)
286 );
287 size = 0; // Important to tell framework that nothing was generated.
5bf92d6f 288 return -ENOBUFS;
b92524d0 289 }
290
291 // Loop over all input blocks in the event and add the ones that contain
292 // reconstructed hits into the hit buffers. The blocks containing trigger
293 // records are ignored for now and will be processed later.
294 for (AliHLTUInt32_t n = 0; n < evtData.fBlockCnt; n++)
295 {
296 if (blocks[n].fDataType == AliHLTMUONConstants::RecHitsBlockDataType())
297 {
298 specification |= blocks[n].fSpecification;
299
300 AliHLTMUONRecHitsBlockReader inblock(blocks[n].fPtr, blocks[n].fSize);
301 if (not inblock.BufferSizeOk())
302 {
d42549e3 303 size_t headerSize = sizeof(AliHLTMUONRecHitsBlockReader::HeaderType);
304 if (blocks[n].fSize < headerSize)
305 {
306 HLTError("Received a reconstructed hits data block with a size of %d bytes,"
307 " which is smaller than the minimum valid header size of %d bytes."
308 " The block must be corrupt.",
309 blocks[n].fSize, headerSize
310 );
311 continue;
312 }
313
314 size_t expectedWidth = sizeof(AliHLTMUONRecHitsBlockReader::ElementType);
315 if (inblock.CommonBlockHeader().fRecordWidth != expectedWidth)
316 {
317 HLTError("Received a reconstructed hits data block with a record"
318 " width of %d bytes, but the expected value is %d bytes."
319 " The block might be corrupt.",
47415aa9 320 inblock.CommonBlockHeader().fRecordWidth, expectedWidth
d42549e3 321 );
322 continue;
323 }
324
325 HLTError("Received a reconstructed hits data block with a size of %d bytes,"
326 " but the block header claims the block should be %d bytes."
327 " The block might be corrupt.",
328 blocks[n].fSize, inblock.BytesUsed()
b92524d0 329 );
330 continue;
331 }
332
4a9f11d4 333 if (inblock.Nentries() != 0)
334 AddRecHits(blocks[n].fSpecification, inblock.GetArray(), inblock.Nentries());
335 else
336 {
d42549e3 337 Logging(kHLTLogDebug,
4a9f11d4 338 "AliHLTMUONMansoTrackerFSMComponent::DoEvent",
339 "Block empty",
340 "Received a reconstructed hits data block which contains no entries."
341 );
342 }
b92524d0 343 }
344 else if (blocks[n].fDataType != AliHLTMUONConstants::TriggerRecordsBlockDataType())
345 {
346 // Log a message indicating that we got a data block that we
347 // do not know how to handle.
348 char id[kAliHLTComponentDataTypefIDsize+1];
349 for (int i = 0; i < kAliHLTComponentDataTypefIDsize; i++)
350 id[i] = blocks[n].fDataType.fID[i];
351 id[kAliHLTComponentDataTypefIDsize] = '\0';
352 char origin[kAliHLTComponentDataTypefOriginSize+1];
353 for (int i = 0; i < kAliHLTComponentDataTypefOriginSize; i++)
354 origin[i] = blocks[n].fDataType.fOrigin[i];
355 origin[kAliHLTComponentDataTypefOriginSize] = '\0';
356
d42549e3 357 if (fWarnForUnexpecedBlock)
358 HLTWarning("Received a data block of a type we cannot handle: %s origin: %s",
359 static_cast<char*>(id), static_cast<char*>(origin)
360 );
361 else
362 HLTDebug("Received a data block of a type we cannot handle: %s origin: %s",
363 static_cast<char*>(id), static_cast<char*>(origin)
364 );
b92524d0 365 }
366 }
367
368 // Again loop over all input blocks in the event, but this time look for
369 // the trigger record blocks and process these.
370 for (AliHLTUInt32_t n = 0; n < evtData.fBlockCnt; n++)
371 {
372 if (blocks[n].fDataType != AliHLTMUONConstants::TriggerRecordsBlockDataType())
373 continue;
374
375 AliHLTMUONTriggerRecordsBlockReader inblock(blocks[n].fPtr, blocks[n].fSize);
376 if (not inblock.BufferSizeOk())
377 {
d42549e3 378 size_t headerSize = sizeof(AliHLTMUONTriggerRecordsBlockReader::HeaderType);
379 if (blocks[n].fSize < headerSize)
380 {
381 HLTError("Received a trigger records data block with a size of %d bytes,"
382 " which is smaller than the minimum valid header size of %d bytes."
383 " The block must be corrupt.",
384 blocks[n].fSize, headerSize
385 );
386 continue;
387 }
388
389 size_t expectedWidth = sizeof(AliHLTMUONTriggerRecordsBlockReader::ElementType);
390 if (inblock.CommonBlockHeader().fRecordWidth != expectedWidth)
391 {
392 HLTError("Received a trigger records data block with a record"
393 " width of %d bytes, but the expected value is %d bytes."
394 " The block might be corrupt.",
47415aa9 395 inblock.CommonBlockHeader().fRecordWidth, expectedWidth
d42549e3 396 );
397 continue;
398 }
399
400 HLTError("Received a trigger records data block with a size of %d bytes,"
401 " but the block header claims the block should be %d bytes."
402 " The block might be corrupt.",
403 blocks[n].fSize, inblock.BytesUsed()
b92524d0 404 );
405 continue;
406 }
407 DebugTrace("Processing a trigger block with "
408 << inblock.Nentries() << " entries."
409 );
410
411 specification |= blocks[n].fSpecification;
412
413 for (AliHLTUInt32_t i = 0; i < inblock.Nentries(); i++)
414 {
415 fTracker->FindTrack(inblock[i]);
416
417 // Reset the tracker so that we do not double count tracks.
418 fTracker->Reset();
419 }
420 }
421
422 AliHLTComponentBlockData bd;
423 FillBlockData(bd);
424 bd.fPtr = outputPtr;
425 bd.fOffset = 0;
426 bd.fSize = block.BytesUsed();
427 bd.fDataType = AliHLTMUONConstants::MansoTracksBlockDataType();
428 bd.fSpecification = specification;
429 outputBlocks.push_back(bd);
430 size = block.BytesUsed();
431
432 return 0;
433}
434
435
436void AliHLTMUONMansoTrackerFSMComponent::Reset()
437{
6253e09b 438 ///
439 /// Reset the track count and reconstructed hit data block arrays.
440 ///
441
b92524d0 442 DebugTrace("Resetting AliHLTMUONMansoTrackerFSMComponent.");
443
444 //fTracker->Reset(); // Not necessary here because it is done after every FindTrack call.
445 fTrackCount = 0;
446 fBlock = NULL; // Do not delete. Already done implicitly at the end of DoEvent.
447 for (int i = 0; i < 4; i++)
448 {
5bf92d6f 449 fRecHitBlockCount[i] = 0;
b92524d0 450 }
451}
452
453
454void AliHLTMUONMansoTrackerFSMComponent::AddRecHits(
6253e09b 455 AliHLTUInt32_t specification,
b92524d0 456 const AliHLTMUONRecHitStruct* recHits,
457 AliHLTUInt32_t count
458 )
459{
6253e09b 460 ///
461 /// Adds a new reconstructed hit data block to the internal list of blocks
462 /// for the tracker to process.
463 /// These lists will later be used when the tracker requests them through
464 /// the callback method 'RequestClusters'.
465 ///
466
b92524d0 467 DebugTrace("AliHLTMUONMansoTrackerFSMComponent::AddRecHits called with specification = 0x"
468 << std::hex << specification << std::dec << " and count = "
469 << count << " rec hits."
470 );
471
472 AliHLTUInt8_t chamberMap[20] = {
473 1, 1, 2, 2, 3, 3, 4, 4, 5, 5, 6, 6, 7, 7, 8, 8, 9, 9, 10, 10
474 };
475
476 // Identify the chamber the rec hits came from using the specifications field.
477 bool gotDataFromDDL[22];
478 AliHLTMUONUtils::UnpackSpecBits(specification, gotDataFromDDL);
479
480 AliHLTInt8_t chamber = -1;
481 for (int i = 0; i < 20; i++)
482 {
483 if (not gotDataFromDDL[i]) continue;
484 if (7 <= chamberMap[i] and chamberMap[i] <= 10)
485 {
486 if (chamber != -1 and chamber != chamberMap[i])
487 {
488 Logging(kHLTLogError,
489 "AliHLTMUONMansoTrackerFSMComponent::AddRecHits",
490 "Invalid block",
491 "Received a data block with data from multiple chambers."
492 " This component cannot handle such a case."
493 );
494 return;
495 }
496 else
497 chamber = chamberMap[i];
498 }
499 else
500 {
501 Logging(kHLTLogError,
502 "AliHLTMUONMansoTrackerFSMComponent::AddRecHits",
503 "Invalid chamber",
504 "Received a data block with data from chamber %d"
505 " which is outside the expected range: [7..10].",
506 chamberMap[i]
507 );
508 return;
509 }
510 }
511
512 // Make sure we got one chamber number.
513 if (chamber < 7 or 10 < chamber)
514 {
515 Logging(kHLTLogError,
516 "AliHLTMUONMansoTrackerFSMComponent::AddRecHits",
517 "Invalid block",
518 "Received a reconstructed hit data block with a null specification."
519 " Cannot know which chamber the data comes from."
520 );
521 return;
522 }
523
524 DebugTrace("Added " << count << " reconstructed hits from chamber "
d42549e3 525 << (int)chamber << " to the internal arrays."
526 );
b92524d0 527
5bf92d6f 528 assert( fRecHitBlockCount[chamber-7] < fRecHitBlockArraySize );
529 AliRecHitBlockInfo info(count, recHits);
530 fRecHitBlock[chamber-7][fRecHitBlockCount[chamber-7]] = info;
531 fRecHitBlockCount[chamber-7]++;
b92524d0 532}
533
534
535void AliHLTMUONMansoTrackerFSMComponent::RequestClusters(
536 AliHLTMUONMansoTrackerFSM* tracker,
f1169efa 537 AliHLTFloat32_t left, AliHLTFloat32_t right,
538 AliHLTFloat32_t bottom, AliHLTFloat32_t top,
b92524d0 539 AliHLTMUONChamberName chamber, const void* tag
540 )
541{
6253e09b 542 ///
543 /// Inherited from AliHLTMUONMansoTrackerFSMCallback.
544 /// This is the call back method used by the tracker algorithm to request
545 /// clusters on a certain chamber.
546 ///
547
b92524d0 548 DebugTrace("AliHLTMUONMansoTracker::RequestClusters(chamber = " << chamber << ")");
549 void* ctag = const_cast<void*>(tag);
550 int chNo = -1;
5bf92d6f 551 AliHLTUInt32_t recHitsCount = 0;
552 AliRecHitBlockInfo* recHitsBlock = NULL;
b92524d0 553 switch (chamber)
554 {
555 case kChamber7:
5bf92d6f 556 recHitsCount = fRecHitBlockCount[0];
557 recHitsBlock = fRecHitBlock[0];
b92524d0 558 chNo = 7;
559 break;
560
561 case kChamber8:
5bf92d6f 562 recHitsCount = fRecHitBlockCount[1];
563 recHitsBlock = fRecHitBlock[1];
b92524d0 564 chNo = 8;
565 break;
566
567 case kChamber9:
5bf92d6f 568 recHitsCount = fRecHitBlockCount[2];
569 recHitsBlock = fRecHitBlock[2];
b92524d0 570 chNo = 9;
571 break;
572
573 case kChamber10:
5bf92d6f 574 recHitsCount = fRecHitBlockCount[3];
575 recHitsBlock = fRecHitBlock[3];
b92524d0 576 chNo = 10;
577 break;
578
579 default: return;
580 }
581
582 DebugTrace("Returning requested hits for chamber " << chNo << ":");
5bf92d6f 583 for (AliHLTUInt32_t i = 0; i < recHitsCount; i++)
584 for (AliHLTUInt32_t j = 0; j < recHitsBlock[i].Count(); j++)
b92524d0 585 {
5bf92d6f 586 const AliHLTMUONRecHitStruct* hit = &(recHitsBlock[i].Data()[j]);
f1169efa 587 if (left < hit->fX and hit->fX < right and bottom < hit->fY and hit->fY < top)
588 tracker->ReturnClusters(ctag, hit, 1);
b92524d0 589 }
590 DebugTrace("Done returning hits from chamber " << chNo << ".");
591 tracker->EndOfClusters(ctag);
592}
593
594
595void AliHLTMUONMansoTrackerFSMComponent::EndOfClusterRequests(
5def1693 596 AliHLTMUONMansoTrackerFSM* /*tracker*/
b92524d0 597 )
598{
6253e09b 599 ///
600 /// Inherited from AliHLTMUONMansoTrackerFSMCallback.
601 /// Nothing special to do here.
602 ///
603
b92524d0 604 DebugTrace("End of cluster requests.");
605}
606
607
608void AliHLTMUONMansoTrackerFSMComponent::FoundTrack(AliHLTMUONMansoTrackerFSM* tracker)
609{
6253e09b 610 ///
611 /// Inherited from AliHLTMUONMansoTrackerFSMCallback.
612 /// This is the call back method used by the tracker algorithm to declare
613 /// that a new track has been found.
614 ///
615
b92524d0 616 DebugTrace("AliHLTMUONMansoTrackerFSMComponent::FoundTrack()");
617
618 AliHLTMUONMansoTracksBlockWriter* block =
619 reinterpret_cast<AliHLTMUONMansoTracksBlockWriter*>(fBlock);
620
621 AliHLTMUONMansoTrackStruct* track = block->AddEntry();
622 if (track == NULL)
623 {
624 Logging(kHLTLogError,
625 "AliHLTMUONMansoTrackerFSMComponent::FoundTrack",
626 "Buffer overflow",
627 "We have overflowed the output buffer for Manso track data."
628 " The output buffer size is only %d bytes.",
629 block->BufferSize()
630 );
631 return;
632 }
633
634 fTrackCount++;
635 tracker->FillTrackData(*track);
636 DebugTrace("\tTrack data = " << *track);
637}
638
639
5def1693 640void AliHLTMUONMansoTrackerFSMComponent::NoTrackFound(AliHLTMUONMansoTrackerFSM* /*tracker*/)
b92524d0 641{
6253e09b 642 ///
643 /// Inherited from AliHLTMUONMansoTrackerFSMCallback.
644 /// Nothing special to do here.
645 ///
646
b92524d0 647 DebugTrace("No track found.");
648}
6253e09b 649