Geant4 가이드

Event Action

G4UserEventAction 클래스는 이벤트가 시작할 때 사용되는 BeginOfEventAction(const G4Event *) 와 이벤트가 끝날 때 사용되는 EndOfEventAction(const G4Event *) 함수를 이용할 수 있다.

이 예제에서 Event Action 클래스(OTEventAction)는 볼륨1의 에너지 축적량을 초기화, 업데이트, 그리고 저장을 관리한다. 먼저 볼륨1의 에너지 축적량인 edep1을 OTEventAction.hh 에 정의한다.

private:
  G4double edep1;

변수의 초기화는 이벤트의 시작인 BeginOfEventAction 함수에서 해준다(OTEventAction.cc).

void OTEventAction::BeginOfEventAction(const G4Event*) {
  edep1 = 0.;
}

변수의 업데이트를 위해서 다음과 같은 함수를 정의 한다(OTEventAction.hh).

void AddEnergyDeposit1(G4double edep) { edep1 += edep; }

위 함수는 볼륨1에서 발생한 매 스텝마다 에너지를 추가하기 위해서 정의하였으며 OTSteppingAction의 UserSteppingAction 함수에서 사용한다.

OTEventAction *eventAction = (OTEventAction *) G4EventManager::GetEventManager() -> GetUserEventAction();
if (volumeID == 1)
  eventAction -> AddEnergyDeposit1(totalEdep);

Stepping Action에서 이벤트 아이디를 받아왔던 것 과 같이 G4EventManager::GetEventManager()를 통해서 지금 사용하고 있는 Action 클래스의 주소를 받아 올 수 있다. 여기서는 OTEventAction 클래스의 AddEnergyDeposit1() 함수를 용 하기 위해서 EventAction을 불러오는데 사용하였다.

마지막으로 이벤트가 끝날 때 Ntuple에 값을 저장한다.

void OTEventAction::EndOfEventAction(const G4Event*) {
  G4AnalysisManager* analysisManager = G4AnalysisManager::Instance();
  analysisManager -> FillNtupleDColumn(1, 0, edep1);
  analysisManager -> AddNtupleRow(1);
}

이 전 토픽에서 주의했던 것 과 같이 ntuple 번호 1을 적어주는 것을 잊지 말자.

 

참고

댓글

댓글 본문
  1. ejungwoo
    이것만으로는 무엇이 문제인지 모르겠네요.
    전체 코드를 보여주시면 문제를 파악하는데 도움이 될 것 같습니다.
    대화보기
    • 지나가는 초보
      안녕하세요 답변 주신것 잘실행해 보았고, 잘돌아가는 것을 확인하였습니다.
      적어 주신 조건문에 조건을
      *소스:
      //(EventAction 클래스 이름이 OTEventAction 일때)
      void MySteppingAction::UserSteppingAction(const G4Step* step) {
      if (trackID==1&&ParentID=0)//제가 쏜입자만 count
      {
      if (voludmeID==7) // 제가 원하는 Detector number
      {
      ((OTEventAction *) G4EventManager::GetEventManager() -> GetUserEventAction()) -> TrackIsDetected();
      }
      }
      }
      로 if 문을 작성하였더니 모든 event 에서 다 1이 count 되는 것으로 확인되었네요....
      제가적은 조건문에 문제가 있는 것일까요?
      아니면 결과 출력을 할 떄 문제가 있는걸까요...!! 도움 주시면 감사하겠습니다
    • ejungwoo
      이 경우는 EventAction을 이용해야 해서 조금 복잡하지만 대충 이런식으로 할 수 있습니다.

      ---

      1. EventAction 헤더에 두개의 변수를 정의합니다. int fCountTotal, bool fCountThisEvent.
      fCountTotal 는 런에서 총 몇개의 이벤트에서 입자가 검출기에 들어갔는지,
      fCountThisEvent 는 이번 이벤트에 입자가 들어왔는지 안들어왔는지를 판단하는 변수입니다.
      그리고 SteppingAction에서 fCountThisEvent 를 업데이트 할 수 있도록 함수를 만듭니다: TrackIsDetected().

      그 다음 BeginOfEventAction()에서 fCountThisEvent를 false로 초기화 하고
      EndOfEventAction() 에서 fCountThisEvent 가 true 라면 fCountTotal 를 1 늘려줍니다.

      *헤더:
      int fCountTotal = 0;
      bool fCountThisEvent = false;
      void TrackIsDetected() { fCountThisEvent = true; }
      *소스:
      void OTEventAction::BeginOfEventAction(const G4Event*) {
      fCountThisEvent = false;
      }
      void OTEventAction::EndOfEventAction(const G4Event*) {
      if (fCountThisEvent == true)
      fCountTotal++;
      }

      ---

      2. SteppingAction의 UserSteppingAction() 에서 트랙이 검출기에 들어오면 EventAction의 CountThisEvent() 함수를 부릅니다.

      *소스:
      //(EventAction 클래스 이름이 OTEventAction 일때)
      void MySteppingAction::UserSteppingAction(const G4Step* step) {
      if (조건)
      ((OTEventAction *) G4EventManager::GetEventManager() -> GetUserEventAction()) -> TrackIsDetected();
      }

      ---

      3. 시뮬레이션 마지막에 fCountTotal 의 값을 확인하면, 총 이벤트 중에서 몇개의 이벤트에 트랙이 검출되었는지 알 수 있습니다.
      대화보기
      • 지나가는 초보
        앗 말씀하신대로 시뮬레이션을 수행하는데 값이 누적되지는 않네요.

        하나 궁금한게........ 총 1000번의 시뮬레이션을 돌렸을때 원하는 Detector 에 몇개의 particle이 들어왔는지를 알고 싶습니다.

        int volumeID = step -> GetPreStepPoint() -> GetPhysicalVolume() -> GetCopyNo();
        if (volumeID == 7) {
        count = count +1;
        // 트랙이 detector 를 지나감
        }
        }


        위와같이 count 라는 것을 만들어 누적시켜 보려했으나 전부 1이 나와서 실패했네요... 간단한 조언 해주시면 감사하겠습니다
        대화보기
        • ejungwoo
          UserSteppingAction 함수의 G4Step 은 누적되지 않은 독립적인 스탭입니다.
          어느 값이 누적 되었다고 생각했는지 알 수 있을까요?
          대화보기
          • 지나가는 초보
            안녕하세요, 지난번 답변 감사드리고 추가적으로 질문 조금만 더드리도록 하겠습니다.

            stepping action과 관련되 code에서 입자가 track을 통과했는지 안했는지는
            void MySteppingAction::UserSteppingAction(const G4Step* step) {
            int trackID = step -> GetTrack() -> GetTrackID();
            if (trackID == 1) {
            // 내가 처음 쏜 트랙이 만든 step에 해당함
            }
            int volumeID = step -> GetPreStepPoint() -> GetPhysicalVolume() -> GetCopyNo();
            if (volumeID == 7) {
            count = count +1;
            // 트랙이 detector 를 지나감
            }
            }
            아래와 같이 진행하면 되지만 단점은 volume내에서 step이 여러번 진행되면 전부다 누적되는 것으로 판단됩니다.

            값을 누적시키지 않고 여러 step을 진행하도 한번만 나오게 하는 방법이 있을까요?
            대화보기
            • ejungwoo
              먼저 detector 를 확인하기 위해서 위치를 확인하는 것 보다는 copyNo 를 이용하는것이 좋습니다.
              DetectorConstruction 클래스의 Construction() 함수에서 PVPlacement 를 정의할 때 마지막에서 두번째 변수인 pCopyNo 를 "다른 볼륨과 겹치지 않게" 지정해줍니다. 편의상 7 번이라고 하겠습니다.

              void MyDetectorConstruction::Construct() {
              ...
              new G4PVPlacement(0, G4ThreeVector(), logicDetector, "detector", logicWorld, false, 7, true);
              ...
              }

              --

              TrackAction 으로는 track의 시작과 끝만 알 수 있습니다. 끝을 알리는 PostUserTrackingAction 함수에서 어느 볼륨에서 트랙이 멈추었는지 알 수 있습니다.

              void MyTrackingAction::PostUserTrackingAction(G4Track *track) {
              if (track -> GetVolume() -> GetCopyNo() == 7) {
              //트랙이 detector 에서 멈춤
              }
              }

              --

              Detector 를 통과했는지 통과하지 않았는지는 SteppingAction을 사용해야 합니다. 만약에 처음 쏜 입자가 아닌 다른 입자가 들어간 경우를 제외하려면 trackID 가 1 번인지를 확인하면 됩니다.

              void MySteppingAction::UserSteppingAction(const G4Step* step) {
              int trackID = step -> GetTrack() -> GetTrackID();
              if (trackID == 1) {
              // 내가 처음 쏜 트랙이 만든 step에 해당함
              }
              int volumeID = step -> GetPreStepPoint() -> GetPhysicalVolume() -> GetCopyNo();
              if (volumeID == 7) {
              // 트랙이 detector 를 지나감
              }
              }
              대화보기
              • 지나가는 초보
                안녕하세요, 이제 막 Geant4를 시작한 초보 사용자인데요
                코딩을 하는데 어려움이 있어 질문 드립니다.

                제가 쏜 입자가(예를 들어 중성자) 원하는 Detector에 도달했는지, 혹은 통과했는지, 혹은 멈췄는지를 알고 싶습니다.

                지금 떠오르는 아이디어로는 tracking action에서 Detector 의범위안에 x1<x<x2 , y1<y<y2, z1<z<z2에 있으면 count하는 방식으로 코드를 작성하려고 하는데 이렇에 하면 지난 입자인지 통과한 입자인지 알 방법이 없어서요...

                혹시 확인할 수 있는 fuction이나 좋은 방법있으면 알려주시면 감사하겠습니다.
                제가초보라 혹시 간단한 코드도 적어주시면 많은 도움이 될것 같습니다.
              버전 관리
              ejungwoo
              현재 버전
              선택 버전
              graphittie 자세히 보기