- Adding comment lines to class description needed for Root documentation
[u/mrichter/AliRoot.git] / MUON / AliMUONPadStatusMaker.cxx
CommitLineData
2c780493 1/**************************************************************************
2* Copyright(c) 1998-1999, ALICE Experiment at CERN, All rights reserved. *
3* *
4* Author: The ALICE Off-line 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. The authors make no claims *
12* about the suitability of this software for any purpose. It is *
13* provided "as is" without express or implied warranty. *
14**************************************************************************/
15
16// $Id$
78649106 17
2c780493 18/// \class AliMUONPadStatusMaker
19///
20/// Make a 2DStore of pad statuses, using different sources of information,
21/// like pedestal values, gain values, and HV values.
22///
78649106 23/// \author Laurent Aphecetche
2c780493 24
25#include "AliMUONPadStatusMaker.h"
26
8d8e920c 27#include "AliCDBEntry.h"
28#include "AliCDBManager.h"
29#include "AliDCSValue.h"
30#include "AliLog.h"
2c780493 31#include "AliMUON2DMap.h"
9044498f 32#include "AliMUON2DStoreValidator.h"
33#include "AliMUONCalibParamNI.h"
2c780493 34#include "AliMUONCalibrationData.h"
35#include "AliMUONHVNamer.h"
2c780493 36#include "AliMUONVCalibParam.h"
2c780493 37#include "AliMpArea.h"
8d8e920c 38#include "AliMpConstants.h"
2c780493 39#include "AliMpDEIterator.h"
40#include "AliMpDEManager.h"
41#include "AliMpIntPair.h"
42#include "AliMpManuList.h"
43#include "AliMpMotifMap.h"
44#include "AliMpMotifPosition.h"
45#include "AliMpPCB.h"
46#include "AliMpPad.h"
47#include "AliMpSector.h"
48#include "AliMpSectorSegmentation.h"
49#include "AliMpSegmentation.h"
50#include "AliMpSlat.h"
51#include "AliMpSlatSegmentation.h"
52#include "AliMpStationType.h"
53#include "AliMpVPadIterator.h"
9044498f 54#include <Riostream.h>
55#include <TMap.h>
56#include <TStopwatch.h>
57#include <TString.h>
2c780493 58
2c780493 59
78649106 60/// \cond CLASSIMP
2c780493 61ClassImp(AliMUONPadStatusMaker)
78649106 62/// \endcond
2c780493 63
64//_____________________________________________________________________________
65AliMUONPadStatusMaker::AliMUONPadStatusMaker(const AliMUONCalibrationData& calibData)
66: fCalibrationData(calibData),
67 fPedMeanLimits(0,4095),
68 fPedSigmaLimits(0,4095),
69 fHVSt12Limits(0,5000),
70 fHVSt345Limits(0,5000)
71{
71a2d3aa 72 /// ctor
2c780493 73}
74
75//_____________________________________________________________________________
76AliMUONPadStatusMaker::~AliMUONPadStatusMaker()
77{
71a2d3aa 78 /// dtor.
2c780493 79}
80
81//_____________________________________________________________________________
8d8e920c 82AliMUONVStore*
83AliMUONPadStatusMaker::Combine(const AliMUONVStore& store1,
84 const AliMUONVStore& store2,
2c780493 85 Int_t binShift) const
86{
87 /// Combine two status containers into one, shifting store2 status bits
88 /// to the left by binShift before making an OR with store1.
89
90 TStopwatch timer;
91 timer.Start(kTRUE);
92
8d8e920c 93 AliMUONVStore* combined = static_cast<AliMUONVStore*>(store1.Clone());
2c780493 94
8d8e920c 95 TIter next(store1.CreateIterator());
96 AliMUONVCalibParam* param1;
2c780493 97
8d8e920c 98 while ( ( param1 = static_cast<AliMUONVCalibParam*>(next()) ) )
2c780493 99 {
8d8e920c 100 Int_t detElemId = param1->ID0();
101 Int_t manuId = param1->ID1();
102 AliMUONVCalibParam* param2 = static_cast<AliMUONVCalibParam*>(store2.FindObject(detElemId,manuId));
2c780493 103 if (!param2)
104 {
96199305 105 AliWarning(Form("Could not get statuses for store2 for DE %d ManuId %d. Marking as missing.",
2c780493 106 detElemId,manuId));
96199305 107 param2 = static_cast<AliMUONVCalibParam*>(param1->Clone());
108 for ( Int_t manuChannel = 0; manuChannel < param2->Size(); ++manuChannel )
109 {
110 param2->SetValueAsInt(manuChannel,0,kMissing);
111 }
2c780493 112 }
8d8e920c 113 AliMUONVCalibParam* paramCombined = static_cast<AliMUONVCalibParam*>(combined->FindObject(detElemId,manuId));
2c780493 114 if (!paramCombined)
115 {
96199305 116 paramCombined = static_cast<AliMUONVCalibParam*>(param2->Clone());
8d8e920c 117 combined->Add(paramCombined);
2c780493 118 }
119
120 for ( Int_t manuChannel = 0; manuChannel < param1->Size(); ++manuChannel )
121 {
122 if ( AliMpManuList::DoesChannelExist(detElemId, manuId, manuChannel) )
123 {
124 Int_t status1(param1->ValueAsInt(manuChannel));
125 Int_t status2(param2->ValueAsInt(manuChannel));
126
127 Int_t status = status1 | (status2 << binShift);
128
129 paramCombined->SetValueAsInt(manuChannel,0,status);
130 }
131 }
132 }
133
2c780493 134 AliInfo("Timer:");
135 StdoutToAliInfo(timer.Print(););
136
137 return combined;
138}
139
140//_____________________________________________________________________________
8d8e920c 141AliMUONVStore*
96199305 142AliMUONPadStatusMaker::GeneratePadStatus(Int_t value)
143{
144 /// Generate a "fake" store, with all (detElemId,manuId) present,
145 /// and containing all the same value
146
8d8e920c 147 AliMUONVStore* store = new AliMUON2DMap(true);
148
149 TList* list = AliMpManuList::ManuList();
150
151 AliMpIntPair* pair;
152
153 TIter next(list);
154
155 while ( ( pair = static_cast<AliMpIntPair*>(next()) ) )
156 {
157 Int_t detElemId = pair->GetFirst();
158 Int_t manuId = pair->GetSecond();
159 AliMUONVCalibParam* param = new AliMUONCalibParamNI(1,AliMpConstants::ManuNofChannels(),detElemId,manuId,value);
160 store->Add(param);
161 }
162
163 delete list;
96199305 164
8d8e920c 165 return store;
96199305 166}
167
168//_____________________________________________________________________________
2c780493 169Bool_t
170AliMUONPadStatusMaker::GetSt12Status(const TMap& hvMap,
171 Int_t detElemId, Int_t sector,
172 Bool_t& hvChannelTooLow,
173 Bool_t& hvChannelTooHigh,
174 Bool_t& hvChannelON) const
175{
176 /// Get HV status for one HV sector of St12
177
178 /// For a given PCB in a given DE, get the HV status (both the channel
179 /// and the switch).
180 /// Returns false if hv switch changed during the run.
181
182 Bool_t error = kFALSE;
183 hvChannelTooLow = kFALSE;
184 hvChannelTooHigh = kFALSE;
185 hvChannelON = kTRUE;
186
187 AliMUONHVNamer hvNamer;
188
189 TString hvChannel(hvNamer.DCSHVChannelName(detElemId,sector));
190
191 TPair* hvPair = static_cast<TPair*>(hvMap.FindObject(hvChannel.Data()));
192 if (!hvPair)
193 {
194 AliError(Form("Did not find expected alias (%s) for DE %d",
195 hvChannel.Data(),detElemId));
196 error = kTRUE;
197 }
198 else
199 {
200 TObjArray* values = static_cast<TObjArray*>(hvPair->Value());
201 if (!values)
202 {
203 AliError(Form("Could not get values for alias %s",hvChannel.Data()));
204 error = kTRUE;
205 }
206 else
207 {
208 // find out min and max value, and makes a cut
209 Float_t hvMin(1E9);
210 Float_t hvMax(0);
211 TIter next(values);
212 AliDCSValue* val;
213
214 while ( ( val = static_cast<AliDCSValue*>(next()) ) )
215 {
216 Float_t hv = val->GetFloat();
217 hvMin = TMath::Min(hv,hvMin);
218 hvMax = TMath::Max(hv,hvMax);
219 }
220
221 float lowThreshold = fHVSt12Limits.X();
222 float highThreshold = fHVSt12Limits.Y();
223
224 if ( hvMin < lowThreshold ) hvChannelTooLow = kTRUE;
225 if ( hvMax > highThreshold ) hvChannelTooHigh = kTRUE;
226 if ( hvMin < 1 ) hvChannelON = kFALSE;
227 }
228 }
229
230 return error;
231}
232
233//_____________________________________________________________________________
234Bool_t
235AliMUONPadStatusMaker::GetSt345Status(const TMap& hvMap,
236 Int_t detElemId, Int_t pcbIndex,
237 Bool_t& hvChannelTooLow,
238 Bool_t& hvChannelTooHigh,
239 Bool_t& hvChannelON,
240 Bool_t& hvSwitchON) const
241{
242 /// For a given PCB in a given DE, get the HV status (both the channel
243 /// and the switch).
244 /// Returns false if something goes wrong (in particular if
245 /// hv switch changed during the run).
246
247 Bool_t error = kFALSE;
248 hvChannelTooLow = kFALSE;
249 hvChannelTooHigh = kFALSE;
250 hvSwitchON = kTRUE;
251 hvChannelON = kTRUE;
252
253 AliMUONHVNamer hvNamer;
254
255 TString hvChannel(hvNamer.DCSHVChannelName(detElemId));
256
257 TPair* hvPair = static_cast<TPair*>(hvMap.FindObject(hvChannel.Data()));
258 if (!hvPair)
259 {
260 AliError(Form("Did not find expected alias (%s) for DE %d",
261 hvChannel.Data(),detElemId));
262 error = kTRUE;
263 }
264 else
265 {
266 TObjArray* values = static_cast<TObjArray*>(hvPair->Value());
267 if (!values)
268 {
269 AliError(Form("Could not get values for alias %s",hvChannel.Data()));
270 error = kTRUE;
271 }
272 else
273 {
274 // find out min and max value, and makes a cut
275 Float_t hvMin(1E9);
276 Float_t hvMax(0);
277 TIter next(values);
278 AliDCSValue* val;
279
280 while ( ( val = static_cast<AliDCSValue*>(next()) ) )
281 {
282 Float_t hv = val->GetFloat();
283 hvMin = TMath::Min(hv,hvMin);
284 hvMax = TMath::Max(hv,hvMax);
285 }
286
287 float lowThreshold = fHVSt345Limits.X();
288 float highThreshold = fHVSt345Limits.Y();
289
290 if ( hvMin < lowThreshold ) hvChannelTooLow = kTRUE;
291 if ( hvMax > highThreshold ) hvChannelTooHigh = kTRUE;
292 if ( hvMin < 1 ) hvChannelON = kFALSE;
293 }
294 }
295
296 TString hvSwitch(hvNamer.DCSHVSwitchName(detElemId,pcbIndex));
297 TPair* switchPair = static_cast<TPair*>(hvMap.FindObject(hvSwitch.Data()));
298 if (!switchPair)
299 {
300 AliError(Form("Did not find expected alias (%s) for DE %d PCB %d",
301 hvSwitch.Data(),detElemId,pcbIndex));
302 error = kTRUE;
303 }
304 else
305 {
306 TObjArray* values = static_cast<TObjArray*>(switchPair->Value());
307 if (!values)
308 {
309 AliError(Form("Could not get values for alias %s",hvSwitch.Data()));
310 error = kTRUE;
311 }
312 else
313 {
314 // we'll count the number of ON/OFF for this pad, to insure
315 // consistency (i.e. if status changed during the run, we should
316 // at least notify this fact ;-) and hope it's not the norm)
317 Int_t nTrue(0);
318 Int_t nFalse(0);
319 TIter next(values);
320 AliDCSValue* val;
321
322 while ( ( val = static_cast<AliDCSValue*>(next()) ) )
323 {
324 if ( val->GetBool() )
325 {
326 ++nTrue;
327 }
328 else
329 {
330 ++nFalse;
331 }
332 }
333
334 if ( (nTrue>0 && nFalse>0) )
335 {
336 AliWarning(Form("Status of HV Switch %s changed during this run nTrue=%d nFalse=%d! Will consider it OFF",
337 hvSwitch.Data(),nTrue,nFalse));
338 error = kTRUE;
339 }
340
341 if ( nFalse ) hvSwitchON = kFALSE;
342 }
343 }
344 return error;
345}
346
347//_____________________________________________________________________________
8d8e920c 348AliMUONVStore*
349AliMUONPadStatusMaker::MakeGainStatus(const AliMUONVStore& /*gainValues*/) const
2c780493 350{
351 /// FIXME: to be implemented
352 AliWarning("Not implemented yet");
353 return 0x0;
354}
355
356//_____________________________________________________________________________
8d8e920c 357AliMUONVStore*
2c780493 358AliMUONPadStatusMaker::MakeHVStatus(const TMap& hvValues) const
359{
360 /// Scrutinize HV values and deduce an HV status for each pad
361
362 TStopwatch timerSt12;
363 TStopwatch timerSt345;
364
365 timerSt12.Start(kTRUE);
366 timerSt12.Stop();
367 timerSt345.Start(kTRUE);
368 timerSt345.Stop();
369
370 AliMUONHVNamer hvNamer;
371
372 AliMpDEIterator deIt;
373
374 deIt.First();
375
8d8e920c 376 AliMUONVStore* hv = new AliMUON2DMap(kTRUE);
2c780493 377
378 while ( !deIt.IsDone() )
379 {
380 Int_t detElemId = deIt.CurrentDEId();
381
382 switch ( AliMpDEManager::GetStationType(detElemId) )
383 {
384 case AliMp::kStation1:
385 case AliMp::kStation2:
386 timerSt12.Start(kFALSE);
387 for ( int sector = 0; sector < 3; ++sector)
388 {
389 AliDebug(1,Form("detElemId %5d sector %d",detElemId,sector));
390
391 Bool_t hvChannelTooLow, hvChannelTooHigh, hvChannelON;
392 Bool_t error = GetSt12Status(hvValues,
393 detElemId,sector,
394 hvChannelTooLow,hvChannelTooHigh,
395 hvChannelON);
396 Int_t status = 0;
397 if ( error ) status |= kHVError;
398 if ( hvChannelTooLow ) status |= kHVTooLow;
399 if ( hvChannelTooHigh ) status |= kHVTooHigh;
400 if ( !hvChannelON ) status |= kHVChannelOFF;
401 SetStatusSt12(*hv,detElemId,sector,status);
402
403 }
404 timerSt12.Stop();
405 break;
406 case AliMp::kStation345:
407 {
408 timerSt345.Start(kFALSE);
409 for ( Int_t pcbIndex = 0; pcbIndex < hvNamer.NumberOfPCBs(detElemId); ++pcbIndex)
410 {
411 AliDebug(1,Form("detElemId %5d pcbIndex %d",detElemId,pcbIndex));
412 Bool_t hvChannelTooLow, hvChannelTooHigh, hvChannelON,hvSwitchON;
413 Bool_t error = GetSt345Status(hvValues,
414 detElemId,pcbIndex,
415 hvChannelTooLow,hvChannelTooHigh,
416 hvChannelON,hvSwitchON);
417 Int_t status = 0;
418 if ( error ) status |= kHVError;
419 if ( hvChannelTooLow ) status |= kHVTooLow;
420 if ( hvChannelTooHigh ) status |= kHVTooHigh;
421 if ( !hvSwitchON ) status |= kHVSwitchOFF;
422 if ( !hvChannelON) status |= kHVChannelOFF;
423 SetStatusSt345(*hv,detElemId,pcbIndex,status);
424 }
425 timerSt345.Stop();
426 }
427 break;
428 default:
429 break;
430 }
431 deIt.Next();
432 }
433
434 AliInfo("St12 timer:");
435 StdoutToAliInfo(timerSt12.Print(););
436 AliInfo("St345 timer:");
437 StdoutToAliInfo(timerSt345.Print(););
438
439 return hv;
440}
441
442//_____________________________________________________________________________
8d8e920c 443AliMUONVStore*
444AliMUONPadStatusMaker::MakePedestalStatus(const AliMUONVStore& pedValues) const
2c780493 445{
446 /// Assign a pedestal status to each pad
447
448 TStopwatch timer;
449
450 timer.Start(kTRUE);
451
8d8e920c 452 AliMUONVStore* pedStatuses = new AliMUON2DMap(kTRUE);
2c780493 453
8d8e920c 454 TIter next(pedValues.CreateIterator());
455 AliMUONVCalibParam* pedestals;
2c780493 456 Int_t nofManus(0);
457
8d8e920c 458 while ( ( pedestals = static_cast<AliMUONVCalibParam*>(next() ) ) )
2c780493 459 {
8d8e920c 460 Int_t detElemId = pedestals->ID0();
461 Int_t manuId = pedestals->ID1();
2c780493 462 ++nofManus;
463 for ( Int_t manuChannel = 0; manuChannel < pedestals->Size(); ++manuChannel )
464 {
465 Int_t status(0);
466 if ( AliMpManuList::DoesChannelExist(detElemId, manuId, manuChannel) )
467 {
468 Float_t pedMean = pedestals->ValueAsFloat(manuChannel,0);
469 Float_t pedSigma = pedestals->ValueAsFloat(manuChannel,1);
470 if ( pedMean < fPedMeanLimits.X() ) status |= kPedMeanTooLow;
471 if ( pedMean > fPedMeanLimits.Y() ) status |= kPedMeanTooHigh;
472 if ( pedSigma < fPedSigmaLimits.X() ) status |= kPedSigmaTooLow;
473 if ( pedSigma > fPedSigmaLimits.Y() ) status |= kPedSigmaTooHigh;
474 if ( pedMean == 0 ) status |= kPedMeanZero;
475
476 AliMUONVCalibParam* vStatus =
8d8e920c 477 static_cast<AliMUONVCalibParam*>(pedStatuses->FindObject(detElemId,manuId));
2c780493 478 if ( !vStatus )
479 {
8d8e920c 480 vStatus = new AliMUONCalibParamNI(1,AliMpConstants::ManuNofChannels(),detElemId,manuId,0);
481 pedStatuses->Add(vStatus);
2c780493 482 }
483 vStatus->SetValueAsInt(manuChannel,0,status);
484 }
485 }
486 }
487
488 AliInfo(Form("%d manus checked in :",nofManus));
489 StdoutToAliInfo(timer.Print(););
490 return pedStatuses;
491}
492
493//_____________________________________________________________________________
8d8e920c 494AliMUONVStore*
2c780493 495AliMUONPadStatusMaker::MakeStatus() const
496{
497 /// Read ped, gains and hv values from CDB, apply some Q&A and produces
498 /// a combined status for each pad.
499
500 TMap* hvValues = fCalibrationData.HV();
8d8e920c 501 AliMUONVStore* hvStatus(0x0);
2c780493 502
503 if (!hvValues)
504 {
96199305 505 AliError("Could not get HV values from CDB. Will create dummy ones and mark those as missing");
8d8e920c 506 hvStatus = GeneratePadStatus(kHVMissing);
96199305 507 }
508 else
509 {
510 hvStatus = MakeHVStatus(*hvValues);
2c780493 511 }
512
8d8e920c 513 AliMUONVStore* pedValues = fCalibrationData.Pedestals();
514 AliMUONVStore* pedStatus(0x0);
2c780493 515
516 if (!pedValues)
517 {
96199305 518 AliError("Could not get pedestals values from CDB. Will create dummy ones and mark those as missing");
8d8e920c 519 pedStatus = GeneratePadStatus(kPedMissing);
96199305 520 }
521 else
522 {
523 pedStatus = MakePedestalStatus(*pedValues);
2c780493 524 }
525
96199305 526 // FIXME: should do the same for gains as for hv and ped.
2c780493 527
8d8e920c 528 AliMUONVStore* status = Combine(*hvStatus,*pedStatus,8);
2c780493 529
530 delete hvStatus;
531 delete pedStatus;
532
96199305 533 // Insure we get all channels there (some or even all can be bad, but they
534 // must be there somehow).
535
536 AliMUON2DStoreValidator validator;
537
538 TObjArray* a = validator.Validate(*status);
539
540 if (a)
541 {
542 // this should not happen.
543 AliError("Status store not complete. Crash to follow soon...");
544 StdoutToAliError(a->Print(););
545 AliFatal("this should not happen at all!");
546 delete status;
547 status = 0x0;
548 }
549
2c780493 550 return status;
551}
552
553//_____________________________________________________________________________
554void
8d8e920c 555AliMUONPadStatusMaker::SetStatusSt12(AliMUONVStore& hvStatus,
2c780493 556 Int_t detElemId,
557 Int_t isector,
558 Int_t status) const
559{
560 /// Flag all pads of detElemId (for St12) as bad.
561
562 // FIXME: need a way to iterator on pads over a given HV sector for St12...
563 // we currently suppose that one sector is about a third of the chamber...
564 // FIXME !! This has to be checked very carefully...
565
566 const AliMp::CathodType kCathodes[] = { AliMp::kCath0, AliMp::kCath1 };
567
568 for ( Int_t icathode = 0; icathode < 2; ++icathode )
569 {
570 const AliMpSectorSegmentation* seg =
571 static_cast<const AliMpSectorSegmentation*>(AliMpSegmentation::Instance()->GetMpSegmentation(detElemId,kCathodes[icathode]));
572 const AliMpSector* sector = seg->GetSector();
573 AliMpMotifMap* mMap = sector->GetMotifMap();
574 TArrayI a;
575
576 mMap->GetAllMotifPositionsIDs(a);
577
578 TVector2 dim = seg->Dimensions();
579 Double_t x = dim.X()*2;
580 Double_t xmin = isector*x/3.0;
581 Double_t xmax = xmin + x/3.0;
582
583 for ( Int_t i = 0; i < a.GetSize(); ++i )
584 {
585 AliMpMotifPosition* pos = mMap->FindMotifPosition(a[i]);
586 Int_t manuId = pos->GetID();
587 TVector2 position = pos->Position();
588 if ( position.X() >= xmin && position.X() <= xmax)
589 {
590 AliMUONVCalibParam* dead =
8d8e920c 591 static_cast<AliMUONVCalibParam*>(hvStatus.FindObject(detElemId,manuId));
2c780493 592 if (!dead)
593 {
8d8e920c 594 dead = new AliMUONCalibParamNI(1,AliMpConstants::ManuNofChannels(),detElemId,manuId,status);
595 hvStatus.Add(dead);
2c780493 596 }
597 else
598 {
599 // FIXME: this should really not happen, if we'd know really the
600 // relationship between manuId and HV sector...
601 // For the time being, let's leave it like that, for testing
602 // purposes only. For production, this will have to be fixed.
603 AliWarning("Please fixme.");
604 }
605 }
606 }
607 }
608}
609
610//_____________________________________________________________________________
611void
8d8e920c 612AliMUONPadStatusMaker::SetStatusSt345(AliMUONVStore& hvStatus,
2c780493 613 Int_t detElemId, Int_t pcbIndex,
614 Int_t status) const
615{
616 /// Flag all pads of pcbIndex-th PCB of detElemId (for St345) as bad.
617
618 const AliMp::CathodType kCathodes[] = { AliMp::kCath0, AliMp::kCath1 };
619
620 for ( Int_t icathode = 0; icathode < 2; ++icathode )
621 {
622 const AliMpSlatSegmentation* seg = static_cast<const AliMpSlatSegmentation*>
623 (AliMpSegmentation::Instance()->GetMpSegmentation(detElemId,kCathodes[icathode]));
624 const AliMpSlat* slat = seg->Slat();
625 const AliMpPCB* pcb = slat->GetPCB(pcbIndex);
626
627 for ( Int_t i = 0; i < pcb->GetSize(); ++i )
628 {
629 AliMpMotifPosition* pos = pcb->GetMotifPosition(i);
630 Int_t manuId = pos->GetID();
631 AliMUONVCalibParam* dead =
8d8e920c 632 static_cast<AliMUONVCalibParam*>(hvStatus.FindObject(detElemId,manuId));
2c780493 633 if (dead)
634 {
635 AliError(Form("dead is not null as expected from DE %d manuId %d",
636 detElemId,manuId));
637 }
638 if (!dead)
639 {
8d8e920c 640 dead = new AliMUONCalibParamNI(1,AliMpConstants::ManuNofChannels(),detElemId,manuId,status);
641 hvStatus.Add(dead);
2c780493 642 }
643 }
644 }
645}
646
647
648