Geant4 Cross Reference |
1 // 2 // ******************************************************************** 3 // * License and Disclaimer * 4 // * * 5 // * The Geant4 software is copyright of the Copyright Holders of * 6 // * the Geant4 Collaboration. It is provided under the terms and * 7 // * conditions of the Geant4 Software License, included in the file * 8 // * LICENSE and available at http://cern.ch/geant4/license . These * 9 // * include a list of copyright holders. * 10 // * * 11 // * Neither the authors of this software system, nor their employing * 12 // * institutes,nor the agencies providing financial support for this * 13 // * work make any representation or warranty, express or implied, * 14 // * regarding this software system or assume any liability for its * 15 // * use. Please see the license in the file LICENSE and URL above * 16 // * for the full disclaimer and the limitation of liability. * 17 // * * 18 // * This code implementation is the result of the scientific and * 19 // * technical work of the GEANT4 collaboration. * 20 // * By using, copying, modifying or distributing the software (or * 21 // * any work based on the software) you agree to acknowledge its * 22 // * use in resulting scientific publications, and indicate your * 23 // * acceptance of all terms of the Geant4 Software license. * 24 // ******************************************************************** 25 // 26 /* 27 * ============================================================================= 28 * 29 * Filename: CexmcSetup.cc 30 * 31 * Description: physical setup 32 * 33 * Version: 1.0 34 * Created: 10.10.2009 23:00:50 35 * Revision: none 36 * Compiler: gcc 37 * 38 * Author: Alexey Radkov (), 39 * Company: PNPI 40 * 41 * ============================================================================= 42 */ 43 44 #include <G4GDMLParser.hh> 45 #include <G4MultiFunctionalDetector.hh> 46 #include <G4SDManager.hh> 47 #include <G4LogicalVolume.hh> 48 #include <G4VPhysicalVolume.hh> 49 #include <G4PhysicalVolumeStore.hh> 50 #include <G4Box.hh> 51 #include <G4LogicalVolumeStore.hh> 52 #include <G4Region.hh> 53 #include <G4RegionStore.hh> 54 #include <G4ProductionCuts.hh> 55 #include <G4VUserPhysicsList.hh> 56 #include <G4SystemOfUnits.hh> 57 #include "CexmcSetup.hh" 58 #include "CexmcPrimitiveScorer.hh" 59 #include "CexmcTrackPoints.hh" 60 #include "CexmcTrackPointsInLeftRightSet.hh" 61 #include "CexmcTrackPointsInCalorimeter.hh" 62 #include "CexmcTrackPointsFilter.hh" 63 #include "CexmcSimpleEnergyDeposit.hh" 64 #include "CexmcEnergyDepositInLeftRightSet.hh" 65 #include "CexmcEnergyDepositInCalorimeter.hh" 66 #include "CexmcRunManager.hh" 67 #include "CexmcPhysicsManager.hh" 68 #include "CexmcException.hh" 69 70 71 CexmcSetup::CexmcSetup( const G4String & gdmlFile_, 72 G4bool validateGDMLFile_ ) : 73 world( 0 ), gdmlFile( gdmlFile_ ), validateGDMLFile( validateGDMLFile_ ), 74 calorimeterRegionInitialized( false ), 75 calorimeterGeometryDataInitialized( false ), monitorVolume( NULL ), 76 vetoCounterVolume( NULL ), calorimeterVolume( NULL ), targetVolume( NULL ), 77 rightVetoCounter( NULL ), rightCalorimeter( NULL ) 78 { 79 } 80 81 82 G4VPhysicalVolume * CexmcSetup::Construct( void ) 83 { 84 if ( world ) 85 return world; 86 87 G4GDMLParser gdmlParser; 88 89 gdmlParser.Read( gdmlFile, validateGDMLFile ); 90 world = gdmlParser.GetWorldVolume(); 91 92 SetupSpecialVolumes( gdmlParser ); 93 94 ReadTransforms( gdmlParser ); 95 96 ReadRightDetectors(); 97 98 CexmcRunManager * runManager( static_cast< CexmcRunManager * >( 99 G4RunManager::GetRunManager() ) ); 100 101 runManager->SetupConstructionHook(); 102 103 const CexmcPhysicsManager * physicsManager( 104 dynamic_cast< const CexmcPhysicsManager * >( 105 runManager->GetUserPhysicsList() ) ); 106 107 if ( ! physicsManager ) 108 throw CexmcException( CexmcWeirdException ); 109 110 CexmcPhysicsManager * thePhysicsManager( 111 const_cast< CexmcPhysicsManager * >( physicsManager ) ); 112 thePhysicsManager->SetupConstructionHook( this ); 113 114 return world; 115 } 116 117 118 void CexmcSetup::SetupSpecialVolumes( const G4GDMLParser & gdmlParser ) 119 { 120 G4MultiFunctionalDetector * detector[ CexmcNumberOfDetectorRoles ] = 121 { NULL }; 122 const G4LogicalVolumeStore * lvs( G4LogicalVolumeStore::GetInstance() ); 123 124 for ( std::vector< G4LogicalVolume * >::const_iterator 125 lvIter( lvs->begin() ); lvIter != lvs->end(); ++lvIter ) 126 { 127 G4String volumeName( G4String( ( *lvIter )->GetName() ) ); 128 G4GDMLAuxListType auxInfo( gdmlParser.GetVolumeAuxiliaryInformation( 129 *lvIter ) ); 130 CexmcDetectorRole curDetectorRole( CexmcNumberOfDetectorRoles ); 131 132 for ( G4GDMLAuxListType::const_iterator pair( auxInfo.begin() ); 133 pair != auxInfo.end(); ++pair ) 134 { 135 CexmcPrimitiveScorer * scorer( NULL ); 136 G4String detectorName( "uninitialized" ); 137 do 138 { 139 if ( pair->type == "EnergyDepositDetector" ) 140 { 141 do 142 { 143 if ( pair->value == "MonitorRole" ) 144 { 145 AssertAndAsignDetectorRole( curDetectorRole, 146 CexmcMonitorDetectorRole ); 147 scorer = new CexmcSimpleEnergyDeposit( 148 CexmcDetectorTypeName[ CexmcEDDetector ] ); 149 break; 150 } 151 if ( pair->value == "VetoCounterRole" ) 152 { 153 AssertAndAsignDetectorRole( curDetectorRole, 154 CexmcVetoCounterDetectorRole ); 155 scorer = new CexmcEnergyDepositInLeftRightSet( 156 CexmcDetectorTypeName[ CexmcEDDetector ], 157 this ); 158 break; 159 } 160 if ( pair->value == "CalorimeterRole" ) 161 { 162 AssertAndAsignDetectorRole( curDetectorRole, 163 CexmcCalorimeterDetectorRole ); 164 scorer = new CexmcEnergyDepositInCalorimeter( 165 CexmcDetectorTypeName[ CexmcEDDetector ], 166 this ); 167 break; 168 } 169 } while ( false ); 170 detectorName = CexmcDetectorRoleName[ curDetectorRole ]; 171 G4cout << CEXMC_LINE_START "ED Scorer of detector role '" << 172 detectorName << "' in volume '" << volumeName << 173 "'" << G4endl; 174 break; 175 } 176 if ( pair->type == "TrackPointsDetector" ) 177 { 178 do 179 { 180 if ( pair->value == "MonitorRole" ) 181 { 182 AssertAndAsignDetectorRole( curDetectorRole, 183 CexmcMonitorDetectorRole ); 184 scorer = new CexmcTrackPoints( 185 CexmcDetectorTypeName[ CexmcTPDetector ] ); 186 break; 187 } 188 if ( pair->value == "VetoCounterRole" ) 189 { 190 AssertAndAsignDetectorRole( curDetectorRole, 191 CexmcVetoCounterDetectorRole ); 192 scorer = new CexmcTrackPointsInLeftRightSet( 193 CexmcDetectorTypeName[ CexmcTPDetector ], 194 this ); 195 break; 196 } 197 if ( pair->value == "CalorimeterRole" ) 198 { 199 AssertAndAsignDetectorRole( curDetectorRole, 200 CexmcCalorimeterDetectorRole ); 201 scorer = new CexmcTrackPointsInCalorimeter( 202 CexmcDetectorTypeName[ CexmcTPDetector ], 203 this ); 204 break; 205 } 206 if ( pair->value == "TargetRole" ) 207 { 208 AssertAndAsignDetectorRole( curDetectorRole, 209 CexmcTargetDetectorRole ); 210 scorer = new CexmcTrackPoints( 211 CexmcDetectorTypeName[ CexmcTPDetector ] ); 212 break; 213 } 214 } while ( false ); 215 detectorName = CexmcDetectorRoleName[ curDetectorRole ]; 216 G4cout << CEXMC_LINE_START "TP Scorer of detector role '" << 217 detectorName << "' in volume '" << volumeName << 218 "'" << G4endl; 219 if ( scorer ) 220 { 221 CexmcTrackPointsFilter * filter( 222 new CexmcTrackPointsFilter( "trackPoints" ) ); 223 scorer->SetFilter( filter ); 224 } 225 break; 226 } 227 if ( pair->type == "SensitiveRegion" ) 228 { 229 do 230 { 231 if ( pair->value == "CalorimeterRegion" ) 232 { 233 G4Region * region( NULL ); 234 if ( calorimeterRegionInitialized ) 235 { 236 region = G4RegionStore::GetInstance()-> 237 GetRegion( CexmcCalorimeterRegionName ); 238 } 239 else 240 { 241 region = new G4Region( 242 CexmcCalorimeterRegionName ); 243 G4ProductionCuts * cuts( 244 new G4ProductionCuts ); 245 G4double defaultProductionCut( 1.0 * mm ); 246 const G4VUserPhysicsList * physicsList( 247 G4RunManager::GetRunManager()-> 248 GetUserPhysicsList() ); 249 if ( physicsList ) 250 defaultProductionCut = 251 physicsList->GetDefaultCutValue(); 252 cuts->SetProductionCut( defaultProductionCut ); 253 region->SetProductionCuts( cuts ); 254 calorimeterRegionInitialized = true; 255 } 256 region->AddRootLogicalVolume( *lvIter ); 257 break; 258 } 259 } while ( false ); 260 G4cout << CEXMC_LINE_START "Sensitive Region for logical " 261 "volume '" << volumeName << "' registered" << 262 G4endl; 263 break; 264 } 265 if ( pair->type == "SpecialVolume" ) 266 { 267 do 268 { 269 if ( pair->value == "Monitor" ) 270 { 271 monitorVolume = *lvIter; 272 G4cout << CEXMC_LINE_START "Monitor volume '"; 273 break; 274 } 275 if ( pair->value == "VetoCounter" ) 276 { 277 vetoCounterVolume = *lvIter; 278 G4cout << CEXMC_LINE_START "VetoCounter volume '"; 279 break; 280 } 281 if ( pair->value == "Calorimeter" ) 282 { 283 calorimeterVolume = *lvIter; 284 G4cout << CEXMC_LINE_START "Calorimeter volume '"; 285 ReadCalorimeterGeometryData( *lvIter ); 286 calorimeterGeometryDataInitialized = true; 287 break; 288 } 289 if ( pair->value == "Target" ) 290 { 291 targetVolume = *lvIter; 292 G4cout << CEXMC_LINE_START "Target volume '"; 293 break; 294 } 295 } while ( false ); 296 G4cout << volumeName << "' registered" << G4endl; 297 break; 298 } 299 } 300 while ( false ); 301 302 if ( scorer ) 303 { 304 /* curDetectorRole must be intact when scorer is not NULL */ 305 if ( ! detector[ curDetectorRole ] ) 306 { 307 detector[ curDetectorRole ] = 308 new G4MultiFunctionalDetector( detectorName ); 309 } 310 detector[ curDetectorRole ]->RegisterPrimitive( scorer ); 311 /* now that scorer has initialized pointer to its detector, its 312 * messenger's path shall be properly initialized as well */ 313 scorer->InitializeMessenger(); 314 /* NB: logical volumes in GDML file may not have multiple 315 * detector roles: for example volume Monitor may have only one 316 * role MonitorRole. This restriction arises from that fact that 317 * a logical volume may contain only one sensitive detector. */ 318 ( *lvIter )->SetSensitiveDetector( 319 detector[ curDetectorRole ] ); 320 } 321 } 322 } 323 324 if ( ! calorimeterRegionInitialized ) 325 throw CexmcException( CexmcCalorimeterRegionNotInitialized ); 326 327 if ( ! calorimeterGeometryDataInitialized ) 328 throw CexmcException( CexmcCalorimeterGeometryDataNotInitialized ); 329 330 for ( G4int i( 0 ); i < CexmcNumberOfDetectorRoles; ++i ) 331 { 332 if ( detector[ i ] ) 333 G4SDManager::GetSDMpointer()->AddNewDetector( detector[ i ] ); 334 } 335 } 336 337 338 void CexmcSetup::ReadTransforms( const G4GDMLParser & gdmlParser ) 339 { 340 G4ThreeVector position( gdmlParser.GetPosition( "TargetPos" ) ); 341 G4ThreeVector rotation( gdmlParser.GetRotation( "TargetRot" ) ); 342 G4RotationMatrix rm; 343 344 RotateMatrix( rotation, rm ); 345 targetTransform.SetNetTranslation( position ); 346 targetTransform.SetNetRotation( rm ); 347 348 position = gdmlParser.GetPosition( "CalorimeterLeftPos" ); 349 rotation = gdmlParser.GetRotation( "CalorimeterLeftRot" ); 350 rm = G4RotationMatrix(); 351 RotateMatrix( rotation, rm ); 352 calorimeterLeftTransform.SetNetTranslation( position ); 353 calorimeterLeftTransform.SetNetRotation( rm ); 354 355 position = gdmlParser.GetPosition( "CalorimeterRightPos" ); 356 rotation = gdmlParser.GetRotation( "CalorimeterRightRot" ); 357 rm = G4RotationMatrix(); 358 RotateMatrix( rotation, rm ); 359 calorimeterRightTransform.SetNetTranslation( position ); 360 calorimeterRightTransform.SetNetRotation( rm ); 361 } 362 363 364 void CexmcSetup::ReadCalorimeterGeometryData( 365 const G4LogicalVolume * lVolume ) 366 { 367 if ( lVolume->GetNoDaughters() == 0 ) 368 throw CexmcException( CexmcIncompatibleGeometry ); 369 370 G4VPhysicalVolume * pVolume( lVolume->GetDaughter( 0 ) ); 371 EAxis axis; 372 G4double width; 373 G4double offset; 374 G4bool consuming; 375 376 if ( ! pVolume ) 377 throw CexmcException( CexmcIncompatibleGeometry ); 378 379 if ( pVolume->IsReplicated() ) 380 { 381 pVolume->GetReplicationData( axis, 382 calorimeterGeometry.nCrystalsInColumn, 383 width, offset, consuming ); 384 } 385 386 lVolume = pVolume->GetLogicalVolume(); 387 388 if ( lVolume->GetNoDaughters() == 0 ) 389 throw CexmcException( CexmcIncompatibleGeometry ); 390 391 pVolume = lVolume->GetDaughter( 0 ); 392 393 if ( ! pVolume ) 394 throw CexmcException( CexmcIncompatibleGeometry ); 395 396 if ( pVolume->IsReplicated() ) 397 { 398 pVolume->GetReplicationData( axis, calorimeterGeometry.nCrystalsInRow, 399 width, offset, consuming ); 400 } 401 402 lVolume = pVolume->GetLogicalVolume(); 403 404 /* NB: this is not necessarily a crystal itself as far as crystals can be 405 * wrapped in paper and other materials, but this is what reconstructor and 406 * digitizers really need */ 407 G4Box * crystalBox( dynamic_cast< G4Box * >( lVolume->GetSolid() ) ); 408 409 if ( ! crystalBox ) 410 throw CexmcException( CexmcIncompatibleGeometry ); 411 412 calorimeterGeometry.crystalWidth = crystalBox->GetXHalfLength() * 2; 413 calorimeterGeometry.crystalHeight = crystalBox->GetYHalfLength() * 2; 414 calorimeterGeometry.crystalLength = crystalBox->GetZHalfLength() * 2; 415 } 416 417 418 void CexmcSetup::ConvertToCrystalGeometry( const G4ThreeVector & src, 419 G4int & row, G4int & column, G4ThreeVector & dst ) const 420 { 421 G4int nCrystalsInColumn( calorimeterGeometry.nCrystalsInColumn ); 422 G4int nCrystalsInRow( calorimeterGeometry.nCrystalsInRow ); 423 G4double crystalWidth( calorimeterGeometry.crystalWidth ); 424 G4double crystalHeight( calorimeterGeometry.crystalHeight ); 425 426 row = G4int( ( src.y() + crystalHeight * nCrystalsInColumn / 2 ) / 427 crystalHeight ); 428 column = G4int( ( src.x() + crystalWidth * nCrystalsInRow / 2 ) / 429 crystalWidth ); 430 G4double xInCalorimeterOffset( 431 ( G4double( column ) - G4double( nCrystalsInRow ) / 2 ) * 432 crystalWidth + crystalWidth / 2 ); 433 G4double yInCalorimeterOffset( 434 ( G4double( row ) - G4double( nCrystalsInColumn ) / 2 ) * 435 crystalHeight + crystalHeight / 2 ); 436 dst.setX( src.x() - xInCalorimeterOffset ); 437 dst.setY( src.y() - yInCalorimeterOffset ); 438 } 439 440 441 void CexmcSetup::ReadRightDetectors( void ) 442 { 443 G4PhysicalVolumeStore * pvs( G4PhysicalVolumeStore::GetInstance() ); 444 445 for ( std::vector< G4VPhysicalVolume * >::const_iterator k( pvs->begin() ); 446 k != pvs->end(); ++k ) 447 { 448 /* FIXME: it would be more reasonable to find detectors from volumes 449 * tagged with 'EnergyDepositDetector' or 'TrackPointsDetector', and not 450 * from volumes tagged with 'SpecialVolume' as it is done here. However 451 * in case of calorimeters the role of detectors are played by crystal 452 * volumes, not the calorimeters themselves, but only calorimeters can 453 * hold information about their left or right positions! Thus, following 454 * considerations of convenience, right detectors for all detector roles 455 * are chosen from volumes tagged with 'SpecialVolume' */ 456 do 457 { 458 if ( ( *k )->GetLogicalVolume() == vetoCounterVolume ) 459 { 460 if ( G4StrUtil::contains(( *k )->GetName(), "Right" ) ) 461 rightVetoCounter = *k; 462 break; 463 } 464 if ( ( *k )->GetLogicalVolume() == calorimeterVolume ) 465 { 466 if ( G4StrUtil::contains(( *k )->GetName(), "Right" ) ) 467 rightCalorimeter = *k; 468 break; 469 } 470 } while ( false ); 471 } 472 } 473 474 475 void CexmcSetup::AssertAndAsignDetectorRole( CexmcDetectorRole & detectorRole, 476 CexmcDetectorRole value ) 477 { 478 if ( detectorRole != CexmcNumberOfDetectorRoles && detectorRole != value ) 479 throw CexmcException( CexmcMultipleDetectorRoles ); 480 481 detectorRole = value; 482 } 483 484 485 void CexmcSetup::RotateMatrix( const G4ThreeVector & rot, 486 G4RotationMatrix & rm ) 487 { 488 rm.rotateX( rot.x() ); 489 rm.rotateY( rot.y() ); 490 rm.rotateZ( rot.z() ); 491 } 492 493