//___________________________________________________________________________________________
void KVIDTelescope::Print(Option_t* opt) const
{
   // print out telescope structure
   //if opt="fired" only fired detectors are printed

   TIter next(fDetectors);
   KVDetector* obj;

   if (!strcmp(opt, "fired")) {
      while ((obj = (KVDetector*) next())) {

         if (obj->Fired() || obj->GetEnergy())
            obj->Print("data");
      }
   } else {
      cout << "\n" << opt << "Structure of KVIDTelescope object: " <<
           GetName() << " " << GetType() << endl;
      cout << opt <<
           "--------------------------------------------------------" <<
           endl;
      while ((obj = (KVDetector*) next())) {
         cout << opt << "Detector: " << obj->GetName() << endl;
      }
   }
}
Bool_t KVReconstructedEvent::AnalyseDetectors(TList * kvtl)
{
   // Loop over detectors in list
   // if any detector has fired, start construction of new detected particle
   // More precisely: If detector has fired,
   // making sure fired detector hasn't already been used to reconstruct
   // a particle, then we create and fill a new detected particle.
   // In order to avoid creating spurious particles when reading data,
   // by default we ask that ALL coder values be non-zero here i.e. data and time-marker.
   // This can be changed by calling SetPartSeedCond("any"): in this case,
   // particles will be reconstructed starting from detectors with at least 1 fired parameter.

    KVDetector *d;
    TIter next(kvtl);
    while( (d = (KVDetector*)next()) ){
        /*
            If detector has fired,
            making sure fired detector hasn't already been used to reconstruct
            a particle, then we create and fill a new detected particle.
        */
        if ( (d->Fired( fPartSeedCond.Data() ) && !d->IsAnalysed()) ) {

            KVReconstructedNucleus *kvdp = AddParticle();
            //add all active detector layers in front of this one
            //to the detected particle's list
            kvdp->Reconstruct(d);

            //set detector state so it will not be used again
            d->SetAnalysed(kTRUE);
        }
    }

    return kTRUE;
}
void KVIDTelescope::CalculateParticleEnergy(KVReconstructedNucleus* nuc)
{
   // The energy of each particle is calculated as follows:
   //
   //      E = dE_1 + dE_2 + ... + dE_N
   //
   // dE_1, dE_2, ... = energy losses measured in each detector through which
   //                          the particle has passed (or stopped, in the case of dE_N).
   //                         These energy losses are corrected for (Z,A)-dependent effects
   //                          such as pulse-heigth defect in silicon detectors, losses in
   //                          windows of gas detectors, etc.
   //
   // Whenever possible, the energy loss for fired detectors which are uncalibrated
   // or not functioning is calculated. In this case the status returned by GetCalibStatus()
   // will be KVIDTelescope::kCalibStatus_Calculated.
   // If none of the detectors is calibrated, the particle's energy cannot be calculated &
   // the status will be KVIDTelescope::kCalibStatus_NoCalibrations.
   // Otherwise, the status code will be KVIDTelescope::kCalibStatus_OK.

   //status code
   fCalibStatus = kCalibStatus_NoCalibrations;

   UInt_t z = nuc->GetZ();
   //uncharged particles
   if (z == 0) return;

   KVDetector* d1 = GetDetector(1);
   KVDetector* d2 = (fDetectors->GetSize() > 1 ? GetDetector(2) : 0);
   Bool_t d1_cal = d1->IsCalibrated();
   Bool_t d2_cal = (d2 ? d2->IsCalibrated() : kFALSE);

   //no calibrations
   if (!d1_cal && !d2)
      return;
   if ((d1 && d2) && !d1_cal && !d2_cal)
      return;

   //status code
   fCalibStatus = kCalibStatus_OK;

   UInt_t a = nuc->GetA();

   // particles stopped in first member of telescope
   if (nuc->GetStatus() == 3) {
      if (d1_cal) {
         nuc->SetEnergy(d1->GetCorrectedEnergy(nuc, -1, kFALSE));  //N.B.: transmission=kFALSE because particle stop in d1
      }
      return;
   }

   Double_t e1, e2, einc;
   e1 = e2 = einc = 0.0;

   if (!d1_cal) {//1st detector not calibrated - calculate from residual energy in 2nd detector

      //second detector must exist and have all acquisition parameters fired with above-pedestal value
      if (d2 && d2->Fired("Pall")) e2 = d2->GetCorrectedEnergy(nuc, -1, kFALSE); //N.B.: transmission=kFALSE because particle stop in d2
      if (e2 <= 0.0) {
         // zero energy loss in 2nd detector ? can't do anything...
         fCalibStatus = kCalibStatus_NoCalibrations;
         return;
      }
      //calculate & set energy loss in dE detector
      //N.B. using e2 for the residual energy after detector 1 means
      //that we are assuming the particle stops in detector 2.
      //if this is not true, we will underestimate the energy of the particle.
      e1 = d1->GetDeltaEFromERes(z, a, e2);
      if (e1 < 0.0) e1 = 0.0;
      else {
         d1->SetEnergyLoss(e1);
         d1->SetEResAfterDetector(e2);
         e1 = d1->GetCorrectedEnergy(nuc);
         //status code
         fCalibStatus = kCalibStatus_Calculated;
      }
   } else {//1st detector is calibrated too: get corrected energy loss

      e1 = d1->GetCorrectedEnergy(nuc);

   }

   if (d2 && !d2_cal) {//2nd detector not calibrated - calculate from energy loss in 1st detector

      e1 = d1->GetCorrectedEnergy(nuc);
      if (e1 <= 0.0) {
         // zero energy loss in 1st detector ? can't do anything...
         fCalibStatus = kCalibStatus_NoCalibrations;
         return;
      }
      //calculate & set energy loss in 2nd detector
      e2 = d1->GetEResFromDeltaE(z, a);
      if (e2 < 0.0) e2 = 0.0;
      else {
         e2 = d2->GetDeltaE(z, a, e2);
         d2->SetEnergyLoss(e2);
         e2 = d2->GetCorrectedEnergy(nuc);
         //status code
         fCalibStatus = kCalibStatus_Calculated;
      }
   } else if (d2) { //2nd detector is calibrated too: get corrected energy loss

      e2 = d2->GetCorrectedEnergy(nuc, -1, kFALSE);//N.B.: transmission=kFALSE because particle assumed to stop in d2
      // recalculate corrected energy in first stage using info on Eres
      d1->SetEResAfterDetector(e2);
      e1 = d1->GetCorrectedEnergy(nuc);
   }

   //incident energy of particle (before 1st member of telescope)
   einc = e1 + e2;

   Double_t coherence_tolerance = gEnv->GetValue("KVIDTelescope.CoherencyTolerance", 1.05);
   if (coherence_tolerance < 1) coherence_tolerance += 1.00;

   //Now we have to work our way up the list of detectors from which the particle was
   //reconstructed. For each fired & calibrated detector which is only associated with
   //one particle in the events, we add the corrected measured energy loss
   //to the particle. For uncalibrated, unfired detectors and detectors through which
   //more than one particle has passed, we calculate the corrected energy loss and add it
   //to the particle.
   int ndets = nuc->GetNumDet();
   if (ndets > (int)GetSize()) { //particle passed through other detectors before this idtelesocpe
      //look at detectors not in this id telescope
      int idet = GetSize();//next detector after delta-e member of IDTelescope (stopping detector = 0)
      while (idet < ndets) {

         KVDetector* det = nuc->GetDetector(idet);
         if (det->Fired() && det->IsCalibrated() && det->GetNHits() == 1) {
            Double_t dE = det->GetEnergy();
            //in order to check if particle was really the only one to
            //hit each detector, we calculate the particle's energy loss
            //from its residual energy. if the measured energy loss is
            //significantly larger, there may be a second particle.
            e1 = det->GetDeltaEFromERes(z, a, einc);
            if (e1 < 0.0) e1 = 0.0;
            det->SetEResAfterDetector(einc);
            dE = det->GetCorrectedEnergy(nuc);
            einc += dE;
         } else {
            // Uncalibrated/unfired/multihit detector. Calculate energy loss.
            //calculate energy of particle before detector from energy after detector
            e1 = det->GetDeltaEFromERes(z, a, einc);
            if (e1 < 0.0) e1 = 0.0;
            if (det->GetNHits() > 1) {
               //Info("CalculateParticleEnergy",
               //    "Detector %s was hit by %d particles. Calculated energy loss for particle %f MeV",
               //    det->GetName(), det->GetNHits(), e1);
               if (!(det->Fired() && det->IsCalibrated())) {
                  det->SetEnergyLoss(e1 + det->GetEnergy());// sum up calculated energy losses in uncalibrated detector
               }
               //status code
               fCalibStatus = kCalibStatus_Multihit;
            } else if (!det->Fired() || !det->IsCalibrated()) {
               //Info("CalculateParticleEnergy",
               //    "Detector %s uncalibrated/not fired. Calculated energy loss for particle %f MeV",
               //    det->GetName(), e1);
               det->SetEnergyLoss(e1);
               //status code
               fCalibStatus = kCalibStatus_Calculated;
            }
            det->SetEResAfterDetector(einc);
            e1 = det->GetCorrectedEnergy(nuc, e1);
            einc += e1;
         }
         idet++;
      }
   }
   //einc is now the energy of the particle before crossing the first detector
   nuc->SetEnergy(einc);
}