307 lines
13 KiB
C++
307 lines
13 KiB
C++
//
|
|
// ********************************************************************
|
|
// * License and Disclaimer *
|
|
// * *
|
|
// * The Geant4 software is copyright of the Copyright Holders of *
|
|
// * the Geant4 Collaboration. It is provided under the terms and *
|
|
// * conditions of the Geant4 Software License, included in the file *
|
|
// * LICENSE and available at http://cern.ch/geant4/license . These *
|
|
// * include a list of copyright holders. *
|
|
// * *
|
|
// * Neither the authors of this software system, nor their employing *
|
|
// * institutes,nor the agencies providing financial support for this *
|
|
// * work make any representation or warranty, express or implied, *
|
|
// * regarding this software system or assume any liability for its *
|
|
// * use. Please see the license in the file LICENSE and URL above *
|
|
// * for the full disclaimer and the limitation of liability. *
|
|
// * *
|
|
// * This code implementation is the result of the scientific and *
|
|
// * technical work of the GEANT4 collaboration. *
|
|
// * By using, copying, modifying or distributing the software (or *
|
|
// * any work based on the software) you agree to acknowledge its *
|
|
// * use in resulting scientific publications, and indicate your *
|
|
// * acceptance of all terms of the Geant4 Software license. *
|
|
// ********************************************************************
|
|
//
|
|
/*
|
|
* ============================================================================
|
|
*
|
|
* Filename: CexmcChargeExchangeReconstructor.cc
|
|
*
|
|
* Description: charge exchange reconstructor
|
|
*
|
|
* Version: 1.0
|
|
* Created: 02.12.2009 15:17:13
|
|
* Revision: none
|
|
* Compiler: gcc
|
|
*
|
|
* Author: Alexey Radkov (),
|
|
* Company: PNPI
|
|
*
|
|
* ============================================================================
|
|
*/
|
|
|
|
#include <cmath>
|
|
#include <G4ThreeVector.hh>
|
|
#include <G4LorentzVector.hh>
|
|
#include "CexmcChargeExchangeReconstructor.hh"
|
|
#include "CexmcChargeExchangeReconstructorMessenger.hh"
|
|
#include "CexmcEnergyDepositStore.hh"
|
|
#include "CexmcPrimaryGeneratorAction.hh"
|
|
#include "CexmcParticleGun.hh"
|
|
#include "CexmcProductionModel.hh"
|
|
#include "CexmcRunManager.hh"
|
|
#include "CexmcException.hh"
|
|
|
|
|
|
CexmcChargeExchangeReconstructor::CexmcChargeExchangeReconstructor(
|
|
const CexmcProductionModel * productionModel ) :
|
|
outputParticleMass( 0 ), nucleusOutputParticleMass( 0 ),
|
|
useTableMass( false ), useMassCut( false ), massCutOPCenter( 0 ),
|
|
massCutNOPCenter( 0 ), massCutOPWidth( 0 ), massCutNOPWidth( 0 ),
|
|
massCutEllipseAngle( 0 ), useAbsorbedEnergyCut( false ),
|
|
absorbedEnergyCutCLCenter( 0 ), absorbedEnergyCutCRCenter( 0 ),
|
|
absorbedEnergyCutCLWidth( 0 ), absorbedEnergyCutCRWidth( 0 ),
|
|
absorbedEnergyCutEllipseAngle( 0 ), expectedMomentumAmp( -1 ),
|
|
edCollectionAlgorithm( CexmcCollectEDInAllCrystals ),
|
|
hasMassCutTriggered( false ), hasAbsorbedEnergyCutTriggered( false ),
|
|
beamParticleIsInitialized( false ), particleGun( NULL ), messenger( NULL )
|
|
{
|
|
if ( ! productionModel )
|
|
throw CexmcException( CexmcWeirdException );
|
|
|
|
productionModelData.incidentParticle =
|
|
productionModel->GetIncidentParticle();
|
|
|
|
CexmcRunManager * runManager( static_cast< CexmcRunManager * >(
|
|
G4RunManager::GetRunManager() ) );
|
|
const CexmcPrimaryGeneratorAction * primaryGeneratorAction(
|
|
static_cast< const CexmcPrimaryGeneratorAction * >(
|
|
runManager->GetUserPrimaryGeneratorAction() ) );
|
|
CexmcPrimaryGeneratorAction * thePrimaryGeneratorAction(
|
|
const_cast< CexmcPrimaryGeneratorAction * >(
|
|
primaryGeneratorAction ) );
|
|
particleGun = thePrimaryGeneratorAction->GetParticleGun();
|
|
|
|
productionModelData.nucleusParticle =
|
|
productionModel->GetNucleusParticle();
|
|
productionModelData.outputParticle =
|
|
productionModel->GetOutputParticle();
|
|
productionModelData.nucleusOutputParticle =
|
|
productionModel->GetNucleusOutputParticle();
|
|
|
|
messenger = new CexmcChargeExchangeReconstructorMessenger( this );
|
|
}
|
|
|
|
|
|
CexmcChargeExchangeReconstructor::~CexmcChargeExchangeReconstructor()
|
|
{
|
|
delete messenger;
|
|
}
|
|
|
|
|
|
void CexmcChargeExchangeReconstructor::SetupBeamParticle( void )
|
|
{
|
|
if ( *productionModelData.incidentParticle !=
|
|
*particleGun->GetParticleDefinition() )
|
|
throw CexmcException( CexmcBeamAndIncidentParticlesMismatch );
|
|
|
|
beamParticleIsInitialized = true;
|
|
}
|
|
|
|
|
|
void CexmcChargeExchangeReconstructor::Reconstruct(
|
|
const CexmcEnergyDepositStore * edStore )
|
|
{
|
|
if ( ! beamParticleIsInitialized )
|
|
{
|
|
if ( *productionModelData.incidentParticle !=
|
|
*particleGun->GetParticleDefinition() )
|
|
throw CexmcException( CexmcBeamAndIncidentParticlesMismatch );
|
|
|
|
beamParticleIsInitialized = true;
|
|
}
|
|
|
|
if ( edCollectionAlgorithm == CexmcCollectEDInAdjacentCrystals )
|
|
collectEDInAdjacentCrystals = true;
|
|
|
|
ReconstructEntryPoints( edStore );
|
|
if ( hasBasicTrigger )
|
|
ReconstructTargetPoint();
|
|
if ( hasBasicTrigger )
|
|
ReconstructAngle();
|
|
|
|
G4ThreeVector epLeft( calorimeterEPLeftWorldPosition -
|
|
targetEPWorldPosition );
|
|
G4ThreeVector epRight( calorimeterEPRightWorldPosition -
|
|
targetEPWorldPosition );
|
|
|
|
G4double cosTheAngle( std::cos( theAngle ) );
|
|
G4double calorimeterEDLeft( edStore->calorimeterEDLeft );
|
|
G4double calorimeterEDRight( edStore->calorimeterEDRight );
|
|
|
|
if ( edCollectionAlgorithm == CexmcCollectEDInAdjacentCrystals )
|
|
{
|
|
calorimeterEDLeft = calorimeterEDLeftAdjacent;
|
|
calorimeterEDRight = calorimeterEDRightAdjacent;
|
|
}
|
|
|
|
//G4double cosOutputParticleLAB(
|
|
//( calorimeterEDLeft * cosAngleLeft +
|
|
//calorimeterEDRight * cosAngleRight ) /
|
|
//std::sqrt( calorimeterEDLeft * calorimeterEDLeft +
|
|
//calorimeterEDRight * calorimeterEDRight +
|
|
//calorimeterEDLeft * calorimeterEDRight * cosTheAngle ) );
|
|
|
|
outputParticleMass = std::sqrt( 2 * calorimeterEDLeft *
|
|
calorimeterEDRight * ( 1 - cosTheAngle ) );
|
|
|
|
G4ThreeVector opdpLeftMomentum( epLeft );
|
|
opdpLeftMomentum.setMag( calorimeterEDLeft );
|
|
G4ThreeVector opdpRightMomentum( epRight );
|
|
opdpRightMomentum.setMag( calorimeterEDRight );
|
|
G4ThreeVector opMomentum( opdpLeftMomentum + opdpRightMomentum );
|
|
|
|
/* opMass will be used only in calculation of output particle's total
|
|
* energy, in other places outputParticleMass should be used instead */
|
|
G4double opMass( useTableMass ?
|
|
productionModelData.outputParticle->GetPDGMass() :
|
|
outputParticleMass );
|
|
/* the formula below is equivalent to
|
|
* calorimeterEDLeft + calorimeterEDRight if opMass = outputParticleMass */
|
|
G4double opEnergy( std::sqrt( opMomentum.mag2() +
|
|
opMass * opMass ) );
|
|
productionModelData.outputParticleLAB = G4LorentzVector( opMomentum,
|
|
opEnergy );
|
|
|
|
G4ThreeVector incidentParticleMomentum( particleGun->GetOrigDirection() );
|
|
G4double incidentParticleMomentumAmp( expectedMomentumAmp > 0 ?
|
|
expectedMomentumAmp : particleGun->GetOrigMomentumAmp() );
|
|
incidentParticleMomentum *= incidentParticleMomentumAmp;
|
|
|
|
G4double incidentParticlePDGMass(
|
|
productionModelData.incidentParticle->GetPDGMass() );
|
|
G4double incidentParticlePDGMass2( incidentParticlePDGMass *
|
|
incidentParticlePDGMass );
|
|
G4double incidentParticleEnergy(
|
|
std::sqrt( incidentParticleMomentumAmp * incidentParticleMomentumAmp +
|
|
incidentParticlePDGMass2 ) );
|
|
|
|
productionModelData.incidentParticleLAB = G4LorentzVector(
|
|
incidentParticleMomentum, incidentParticleEnergy );
|
|
G4double nucleusParticlePDGMass(
|
|
productionModelData.nucleusParticle->GetPDGMass() );
|
|
productionModelData.nucleusParticleLAB = G4LorentzVector(
|
|
G4ThreeVector( 0, 0, 0 ), nucleusParticlePDGMass );
|
|
|
|
G4LorentzVector lVecSum( productionModelData.incidentParticleLAB +
|
|
productionModelData.nucleusParticleLAB );
|
|
G4ThreeVector boostVec( lVecSum.boostVector() );
|
|
|
|
productionModelData.nucleusOutputParticleLAB =
|
|
lVecSum - productionModelData.outputParticleLAB;
|
|
|
|
productionModelData.incidentParticleSCM =
|
|
productionModelData.incidentParticleLAB;
|
|
productionModelData.nucleusParticleSCM =
|
|
productionModelData.nucleusParticleLAB;
|
|
productionModelData.outputParticleSCM =
|
|
productionModelData.outputParticleLAB;
|
|
productionModelData.nucleusOutputParticleSCM =
|
|
productionModelData.nucleusOutputParticleLAB;
|
|
|
|
productionModelData.incidentParticleSCM.boost( -boostVec );
|
|
productionModelData.nucleusParticleSCM.boost( -boostVec );
|
|
productionModelData.outputParticleSCM.boost( -boostVec );
|
|
productionModelData.nucleusOutputParticleSCM.boost( -boostVec );
|
|
|
|
G4ThreeVector nopMomentum( incidentParticleMomentum - opMomentum );
|
|
G4double nopEnergy( incidentParticleEnergy + nucleusParticlePDGMass -
|
|
opEnergy );
|
|
nucleusOutputParticleMass = std::sqrt( nopEnergy * nopEnergy -
|
|
nopMomentum.mag2() );
|
|
|
|
if ( useMassCut )
|
|
{
|
|
G4double cosMassCutEllipseAngle( std::cos( massCutEllipseAngle ) );
|
|
G4double sinMassCutEllipseAngle( std::sin( massCutEllipseAngle ) );
|
|
|
|
if ( massCutOPWidth <= 0. || massCutNOPWidth <= 0. )
|
|
{
|
|
hasMassCutTriggered = false;
|
|
}
|
|
else
|
|
{
|
|
G4double massCutOPWidth2( massCutOPWidth * massCutOPWidth );
|
|
G4double massCutNOPWidth2( massCutNOPWidth * massCutNOPWidth );
|
|
|
|
hasMassCutTriggered =
|
|
std::pow( ( outputParticleMass - massCutOPCenter ) *
|
|
cosMassCutEllipseAngle +
|
|
( nucleusOutputParticleMass - massCutNOPCenter ) *
|
|
sinMassCutEllipseAngle, 2 ) / massCutOPWidth2 +
|
|
std::pow( - ( outputParticleMass - massCutOPCenter ) *
|
|
sinMassCutEllipseAngle +
|
|
( nucleusOutputParticleMass - massCutNOPCenter ) *
|
|
cosMassCutEllipseAngle, 2 ) / massCutNOPWidth2 <
|
|
1;
|
|
}
|
|
}
|
|
|
|
if ( useAbsorbedEnergyCut )
|
|
{
|
|
G4double cosAbsorbedEnergyCutEllipseAngle(
|
|
std::cos( absorbedEnergyCutEllipseAngle ) );
|
|
G4double sinAbsorbedEnergyCutEllipseAngle(
|
|
std::sin( absorbedEnergyCutEllipseAngle ) );
|
|
|
|
if ( absorbedEnergyCutCLWidth <= 0. || absorbedEnergyCutCRWidth <= 0. )
|
|
{
|
|
hasAbsorbedEnergyCutTriggered = false;
|
|
}
|
|
else
|
|
{
|
|
G4double absorbedEnergyCutCLWidth2(
|
|
absorbedEnergyCutCLWidth * absorbedEnergyCutCLWidth );
|
|
G4double absorbedEnergyCutCRWidth2(
|
|
absorbedEnergyCutCRWidth * absorbedEnergyCutCRWidth );
|
|
|
|
hasAbsorbedEnergyCutTriggered =
|
|
std::pow( ( calorimeterEDLeft - absorbedEnergyCutCLCenter ) *
|
|
cosAbsorbedEnergyCutEllipseAngle +
|
|
( calorimeterEDRight - absorbedEnergyCutCRCenter ) *
|
|
sinAbsorbedEnergyCutEllipseAngle, 2 ) /
|
|
absorbedEnergyCutCLWidth2 +
|
|
std::pow( - ( calorimeterEDLeft - absorbedEnergyCutCLCenter ) *
|
|
sinAbsorbedEnergyCutEllipseAngle +
|
|
( calorimeterEDRight - absorbedEnergyCutCRCenter ) *
|
|
cosAbsorbedEnergyCutEllipseAngle, 2 ) /
|
|
absorbedEnergyCutCRWidth2 <
|
|
1;
|
|
}
|
|
}
|
|
|
|
hasBasicTrigger = true;
|
|
}
|
|
|
|
|
|
G4bool CexmcChargeExchangeReconstructor::HasFullTrigger( void ) const
|
|
{
|
|
if ( ! hasBasicTrigger )
|
|
return false;
|
|
if ( useMassCut && ! hasMassCutTriggered )
|
|
return false;
|
|
if ( useAbsorbedEnergyCut && ! hasAbsorbedEnergyCutTriggered )
|
|
return false;
|
|
|
|
return true;
|
|
}
|
|
|
|
|
|
void CexmcChargeExchangeReconstructor::SetExpectedMomentumAmpDiff(
|
|
G4double value )
|
|
{
|
|
expectedMomentumAmp = particleGun->GetOrigMomentumAmp() + value;
|
|
}
|
|
|