Skip to content
Snippets Groups Projects
Geant4SurfaceTest.cpp 6.76 KiB
Newer Older
Markus Frank's avatar
Markus Frank committed
//  AIDA Detector description implementation 
//--------------------------------------------------------------------------
// Copyright (C) Organisation europeenne pour la Recherche nucleaire (CERN)
// All rights reserved.
//
// For the licensing terms see $DD4hepINSTALL/LICENSE.
// For the list of contributors see $DD4hepINSTALL/doc/CREDITS.
//
//  \author Markus Frank
//  \date   2015-10-14
//
//==========================================================================
#ifndef DD4HEP_DDG4_GEANT4SURFACETEST_H
#define DD4HEP_DDG4_GEANT4SURFACETEST_H

// Framework include files
//#include "Geant4SurfaceTest.h"
#include "DDG4/Geant4EventAction.h"

/// Namespace for the AIDA detector description toolkit
Markus Frank's avatar
Markus Frank committed
namespace dd4hep {

  /// Namespace for the Geant4 based simulation part of the AIDA detector description toolkit
Markus Frank's avatar
Markus Frank committed
  namespace sim {

    /** @class Geant4SurfaceTest Geant4SurfaceTest.h reco/Geant4SurfaceTest.h
     */
    class Geant4SurfaceTest : public Geant4EventAction     {
    public: 
      /// Standard constructor
      Geant4SurfaceTest(Geant4Context* context, const std::string& nam); 
      /// Destructor
      virtual ~Geant4SurfaceTest( );

      /// Begin-of-event callback
      virtual void begin(const G4Event* event);
      /// End-of-event callback
      virtual void end(const G4Event* event);

    protected:

    private:

    };
Markus Frank's avatar
Markus Frank committed
  }    // End namespace sim
}      // End namespace dd4hep

#endif // DD4HEP_DDG4_GEANT4SURFACETEST_H

// Framework include files
Markus Frank's avatar
Markus Frank committed
#include "DD4hep/Detector.h"
#include "DD4hep/DD4hepUnits.h"
#include "DD4hep/InstanceCount.h"

#include "DDG4/Factories.h"
#include "DDG4/Geant4Data.h"
#include "DDG4/Geant4Context.h"
#include "DDG4/Geant4SensDetAction.h"
#include "DDG4/Geant4HitCollection.h"

#include "DDRec/Surface.h"
#include "DDRec/DetectorSurfaces.h"
#include "DDRec/SurfaceManager.h"
#include "DDRec/SurfaceHelper.h"

// Geant 4 includes
#include "G4VHitsCollection.hh"
#include "G4HCofThisEvent.hh"
#include "G4Event.hh"

// C/C++ include files
#include <stdexcept>
#include <map>
#include <sstream>

using namespace std;
Markus Frank's avatar
Markus Frank committed
using namespace dd4hep::DDRec;
using namespace dd4hep::detail;
using namespace dd4hep::sim;

DECLARE_GEANT4ACTION(Geant4SurfaceTest)

/// Standard constructor, initializes variables
Geant4SurfaceTest::Geant4SurfaceTest(Geant4Context* ctxt, const std::string& nam)
: Geant4EventAction(ctxt, nam)
{
  InstanceCount::increment(this);
}

/// Default Destructor
Geant4SurfaceTest::~Geant4SurfaceTest() {
  InstanceCount::decrement(this);
} 

/// Begin-of-event callback
void Geant4SurfaceTest::begin(const G4Event* event)  {
  if ( event )  {
  }
}

/// End-of-event callback
void Geant4SurfaceTest::end(const G4Event* evt)  {
  stringstream sst;
Markus Frank's avatar
Markus Frank committed
  Detector& description = context()->detectorDescription();
  SurfaceManager& surfMan = *description.extension< SurfaceManager >() ;
  const SurfaceMap& surfMap = *surfMan.map( "world" ) ;
  G4HCofThisEvent*  hce = evt->GetHCofThisEvent();

  if ( !hce )  {
    error("Event:%d: No Geant4 event record (HCE) found.",evt->GetEventID());
    return;
  }

  for(int j=0, nCol=hce->GetNumberOfCollections(); j<nCol; ++j)   {
    G4VHitsCollection* hc = hce->GetHC(j);
    Geant4HitCollection* coll = dynamic_cast<Geant4HitCollection*>(hc);

    if ( !(coll && coll->type().type == typeid(Geant4Tracker::Hit)) )   {
      continue;
    }

    SensitiveDetector sd = coll->sensitive()->sensitiveDetector();
    if ( !sd.isValid() )  {
      error("Event:%d: Collection:%s Invalid sensitive detector.",
            evt->GetEventID(),hc->GetName().c_str());
      continue;
    }
    IDDescriptor idDesc    = sd.readout().idSpec();
    const string idStr     = idDesc.fieldDescription();
    BitField64   idDecoder(idStr);
    info("Event: %d [%s: %d hits] Desc:%s",
         evt->GetEventID(),hc->GetName().c_str(),coll->GetSize(),idStr.c_str());
    for(size_t i=0, nHit=coll->GetSize(); i<nHit; ++i)    {
      Geant4Tracker::Hit* h = coll->hit(i);
      const Position& pos = h->position;
      int trackID = h->truth.trackID;
      idDecoder.setValue( h->cellID ) ;
      SurfaceMap::const_iterator si = surfMap.find(h->cellID);
      ISurface* surf = (si != surfMap.end() ?  si->second  : 0);
      
      // ===== test that we have a surface with the correct ID for every hit ======================
      if ( !surf )   {
        error("FAILED: Hit:%ld Track:%d No surface found cell id: %016llX",i,trackID,h->cellID);
        continue;
      }
      info("PASSED: Hit:%ld Track:%d Surface found for cell: %016llX",i,trackID,h->cellID);

      Vector3D hit_point(pos.x()*dd4hep::mm,pos.y()*dd4hep::mm,pos.z()*dd4hep::mm);	  
      bool isInside = surf->insideBounds(hit_point);
      string flag = "";
      if ( h->flag & Geant4Tracker::Hit::HIT_SECONDARY_TRACK ) flag += " TRK:SECONDARY";
      if ( h->flag & Geant4Tracker::Hit::HIT_KILLED_TRACK    ) flag += " TRK:KILLED";
      if ( h->flag & Geant4Tracker::Hit::HIT_NEW_TRACK       ) flag += " NEW_TRACK";
      if ( h->flag & Geant4Tracker::Hit::HIT_STARTED_OUTSIDE ) flag += " START:OUTSIDE";
      if ( h->flag & Geant4Tracker::Hit::HIT_STARTED_INSIDE  ) flag += " START:INSIDE";
      if ( h->flag & Geant4Tracker::Hit::HIT_STARTED_SURFACE ) flag += " START:SURFACE";
      if ( h->flag & Geant4Tracker::Hit::HIT_ENDED_OUTSIDE   ) flag += " END:OUTSIDE";
      if ( h->flag & Geant4Tracker::Hit::HIT_ENDED_INSIDE    ) flag += " END:INSIDE";
      if ( h->flag & Geant4Tracker::Hit::HIT_ENDED_SURFACE   ) flag += " END:SURFACE";

      sst.str("");
      if ( isInside )  {
        sst << hc->GetName() << " " << "PASSED: Track:" << trackID << " Hit:" << i
          //<< " Point " << hit_point 
            << " is ON SURFACE. "
            << "(FLAG:" << h->flag << flag << ").";
        print(sst.str().c_str());
      }
      else   {
        double dist = surf->distance(hit_point)/dd4hep::mm;
        sst.str("");
        sst << hc->GetName() << " FAILED: Track:" << trackID << " Hit:" << i 
            << " Point: " << hit_point;
        error(sst.str().c_str());
        //sst.str("");
        //sst <<   -> Surface:" <<  *surf;
        //error(sst.str().c_str());
        sst.str("");
        sst << "   -> Hit is NOT ON SURFACE (Flag:" << h->flag << flag << ")"
            << " Distance to surface:" << dist << " mm.";
        error(sst.str().c_str());
        // No need for further tests, if this one failed....
        continue;
      }
      // ====== Test to show that moved hit points are outside their surface
      hit_point = hit_point + 1e-3 * surf->normal() ;
      sst.str("") ;
      sst << "Track:" << trackID << " Hit:" << i << " Moved:" << hit_point;
      if ( (isInside=surf->insideBounds(hit_point)) )  {
        error("FAILED: %s is ON SURFACE (SHOULD NOT BE)",sst.str().c_str());
        continue;
      }
      info("PASSED: %s is NOT ON SURFACE (SHOULD NOT BE)",sst.str().c_str());
    }
  }
}