Back to home page

EIC code displayed by LXR

 
 

    


File indexing completed on 2026-04-17 07:51:37

0001 //
0002 // ********************************************************************
0003 // * License and Disclaimer                                           *
0004 // *                                                                  *
0005 // * The  Geant4 software  is  copyright of the Copyright Holders  of *
0006 // * the Geant4 Collaboration.  It is provided  under  the terms  and *
0007 // * conditions of the Geant4 Software License,  included in the file *
0008 // * LICENSE and available at  http://cern.ch/geant4/license .  These *
0009 // * include a list of copyright holders.                             *
0010 // *                                                                  *
0011 // * Neither the authors of this software system, nor their employing *
0012 // * institutes,nor the agencies providing financial support for this *
0013 // * work  make  any representation or  warranty, express or implied, *
0014 // * regarding  this  software system or assume any liability for its *
0015 // * use.  Please see the license in the file  LICENSE  and URL above *
0016 // * for the full disclaimer and the limitation of liability.         *
0017 // *                                                                  *
0018 // * This  code  implementation is the result of  the  scientific and *
0019 // * technical work of the GEANT4 collaboration.                      *
0020 // * By using,  copying,  modifying or  distributing the software (or *
0021 // * any work based  on the software)  you  agree  to acknowledge its *
0022 // * use  in  resulting  scientific  publications,  and indicate your *
0023 // * acceptance of all terms of the Geant4 Software license.          *
0024 // ********************************************************************
0025 //
0026 // Author: M.A. Cortes-Giraldo, Universidad de Sevilla
0027 //
0028 // History changelog prior creation of this example:
0029 // - 13/04/2009: Messenger class added.
0030 // - 17/10/2009: version 1.0
0031 // - 20/11/2009: version 1.1 before publishing:
0032 //   - Changed some names by more suitable ones
0033 // - 02/08/2010: version 1.2-dev:
0034 //   - Added possbility of applying axial symmetries
0035 // - 14/09/2023: version 2.0
0036 //   - Following Geant4 coding guidelines
0037 // - 18/10/2025: version 3.0
0038 //   - Creation of IAEASourceIdRegistry for thread-safe source_id assignation
0039 //
0040 
0041 
0042 #include "G4IAEAphspReader.hh"
0043 
0044 #include "iaea_phsp.h"
0045 #include "iaea_record.h"
0046 #include "IAEASourceIdRegistry.hh"
0047 
0048 #include <vector>
0049 
0050 #include "globals.hh"
0051 #include "G4SystemOfUnits.hh"
0052 #include "G4ThreeVector.hh"
0053 #include "G4Gamma.hh"
0054 #include "G4Electron.hh"
0055 #include "G4Positron.hh"
0056 #include "G4Neutron.hh"
0057 #include "G4Proton.hh"
0058 #include "G4Event.hh"
0059 #include "G4PrimaryParticle.hh"
0060 #include "G4PrimaryVertex.hh"
0061 #include "Randomize.hh"
0062 #include "G4Threading.hh"
0063 
0064 #include "G4IAEAphspReaderMessenger.hh"
0065 
0066 
0067 // =============================================================================
0068 
0069 G4IAEAphspReader::G4IAEAphspReader(const char* filename, const G4int threads)
0070   :fVerbose(0)
0071 {
0072   fTotalThreads = threads;
0073   fFileName = filename;
0074 
0075   InitializeMembers();
0076   InitializeSource(fFileName);
0077   //MAC  ReadAndStoreFirstParticle();
0078 }
0079 
0080 
0081 // =============================================================================
0082 
0083 G4IAEAphspReader::G4IAEAphspReader(const G4String filename, const G4int threads)
0084   :fVerbose(0)
0085 {
0086   fTotalThreads = threads;
0087   fFileName = filename;
0088 
0089   InitializeMembers();
0090   InitializeSource(fFileName);
0091   //MAC  ReadAndStoreFirstParticle();
0092 }
0093 
0094 
0095 // =============================================================================
0096 
0097 G4IAEAphspReader::~G4IAEAphspReader()
0098 {
0099   if (fVerbose > 0) G4cout << "Destroying G4IAEAphspReader" << G4endl;
0100   delete fMessenger;
0101 
0102   // clear and delete the vectors
0103   fParticleTypeVec->clear();
0104   fKinEVec->clear();
0105   fPosVec->clear();
0106   fMomDirVec->clear();
0107   fWeightVec->clear();
0108 
0109   if (fNumberOfExtraFloats > 0) {
0110     fExtraFloatVec->clear();
0111     fExtraFloatTypes->clear();
0112   }
0113 
0114   if (fNumberOfExtraInts > 0) {
0115     fExtraIntVec->clear();
0116     fExtraIntTypes->clear();
0117   }
0118 
0119   delete fParticleTypeVec;
0120   delete fKinEVec;
0121   delete fPosVec;
0122   delete fMomDirVec;
0123   delete fWeightVec;
0124 
0125   delete fExtraFloatVec;
0126   delete fExtraIntVec;
0127 
0128   delete fExtraFloatTypes;
0129   delete fExtraIntTypes;
0130 
0131   // IAEA file has to be closed
0132   const IAEA_I32 sourceRead = static_cast<IAEA_I32>( fSourceReadId );
0133   IAEA_I32 result = 0;
0134 
0135   if (fVerbose > 0)
0136     G4cout << "Destroying IAEA source #" << sourceRead << G4endl;
0137 
0138   iaea_destroy_source(&sourceRead, &result);
0139   if (result > 0) {
0140     IAEASourceIdRegistry::Instance().Release(fSourceReadId);
0141     G4cout << "File " << fFileName << ".IAEAphsp closed successfully!"
0142        << G4endl;
0143   }
0144   else {
0145     G4Exception("G4IAEAphspReader::~G4IAEAphspReader()",
0146         "IAEAphspReader001", JustWarning,
0147         "IAEA file not closed properly");
0148   }
0149 
0150   if (fVerbose > 0) G4cout << "G4IAEAphspReader destroyed" << G4endl;
0151 }
0152 
0153 
0154 // =============================================================================
0155 
0156 void G4IAEAphspReader::InitializeMembers()
0157 {
0158   G4ThreeVector zeroVec;
0159   G4ThreeVector yAxis(0.0, 1.0, 0.0);
0160   G4ThreeVector zAxis(0.0, 0.0, 1.0);
0161 
0162   particle_time = 0.0;
0163   particle_position = zeroVec;
0164 
0165   if ( G4Threading::IsMultithreadedApplication() )
0166     fSourceReadId = G4Threading::G4GetThreadId();
0167   else
0168     fSourceReadId = 0;
0169 
0170   fOrigHistories = -1;
0171   fTotalParticles = -1;
0172   fExtraFloatTypes = new std::vector<G4int>;
0173   fExtraIntTypes = new std::vector<G4int>;
0174 
0175   fParticleTypeVec = new std::vector<G4int>;
0176   fKinEVec = new std::vector<G4double>;
0177   fPosVec = new std::vector<G4ThreeVector>;
0178   fMomDirVec = new std::vector<G4ThreeVector>;
0179   fWeightVec = new std::vector<G4double>;
0180   fExtraFloatVec = new std::vector< std::vector<G4double> >;
0181   fExtraIntVec = new std::vector< std::vector<G4long> >;
0182 
0183   fTotalParallelRuns = 1;
0184   fParallelRun = 1;
0185   fTimesRecycled = 0;
0186   fUsedOrigHistories = 0;
0187   fCurrentParticle = 0;
0188   fEndOfFile = false;
0189   fLastGenerated = true; //MAC to make the file 'restart' at the first event
0190 
0191   fGlobalPhspTranslation = zeroVec;
0192   fRotationOrder = 123;
0193   fAlpha = fBeta = fGamma = 0.;
0194   fIsocenterPosition = zeroVec;
0195   fCollimatorAngle = fGantryAngle = 0.;
0196   fCollimatorRotAxis = zAxis;
0197   fGantryRotAxis = yAxis;
0198 
0199   fAxialSymmetryX = false;
0200   fAxialSymmetryY = false;
0201   fAxialSymmetryZ = false;
0202 
0203   // Messenger class
0204   fMessenger = new G4IAEAphspReaderMessenger(this);
0205 }
0206 
0207 
0208 // =============================================================================
0209 
0210 void G4IAEAphspReader::InitializeSource(const G4String filename)
0211 {
0212   // Reserve a global ID and request it explicitly from IAEA source registry
0213   G4int reserved = IAEASourceIdRegistry::Instance().ReserveNextLowest();
0214   if (reserved < 0) {
0215     G4ExceptionDescription ed;
0216     ed << "No free IAEA source_ID's available" << G4endl;
0217     G4Exception("G4IAEAphspReader::InitializeSource",
0218         "IAEAphspReader002",FatalException, ed);
0219   }
0220   IAEA_I32 sourceRead = static_cast<IAEA_I32>(reserved);
0221 
0222   // Now try to open the IAEAphsp file, and check if all it's OK
0223   const IAEA_I32 accessRead = 1; //static_cast<IAEA_I32>(fAccessRead);
0224   IAEA_I32 result = 0;
0225 
0226   iaea_new_source(&sourceRead, const_cast<char*>(filename.data()),
0227           &accessRead, &result, filename.size()+1);
0228   if ( sourceRead < 0 || result < 0 ) {
0229     IAEASourceIdRegistry::Instance().Release(reserved);
0230     G4ExceptionDescription msg;
0231     msg << "Could not open IAEA source file to read" << G4endl;
0232     G4Exception("G4IAEAphspReader::InitializeSource()",
0233         "IAEAphspReader003", FatalException, msg);
0234   }
0235 
0236   // Update fSourceReadId, just in case.
0237   fSourceReadId = static_cast<G4int>(sourceRead);   // should equal 'reserved'
0238 
0239   // After creating a new IAEA source, the value of sourceRead
0240   // may have change. We check this.
0241   G4cout << "G4IAEAphspReader ==> This object has IAEA source ID = "
0242      << fSourceReadId << "." << G4endl;
0243 
0244 
0245   iaea_check_file_size_byte_order(&sourceRead, &result);
0246   if (result < 0 )
0247     G4Exception("G4IAEAphspReader::InitializeSource()",
0248         "IAEAphspReader004", FatalException,
0249         "Failure at iaea_check_size_byte_order()");
0250 
0251 
0252   // Now get the total number of particles stored in file
0253 
0254   IAEA_I32 particleType = -1; // To count all kind of particles
0255   IAEA_I64 nParticles;
0256   iaea_get_max_particles(&sourceRead, &particleType, &nParticles);
0257 
0258   if (nParticles < 0) {
0259     G4Exception("G4IAEAphspReader::InitializeSource()",
0260         "IAEAphspReader005", FatalException,
0261         "Failure at iaea_get_max_particles()");
0262   }
0263   else {
0264     fTotalParticles = static_cast<G4long>(nParticles);
0265     G4cout << "Total number of particles in file \"" << filename
0266        << ".IAEAphsp\"" << " = " << GetTotalParticles() << G4endl;
0267   }
0268 
0269 
0270   // Now get the number of original simulated histories
0271 
0272   IAEA_I64 nHistories;
0273   iaea_get_total_original_particles(&sourceRead, &nHistories);
0274   fOrigHistories = static_cast<G4long>(nHistories);
0275 
0276   G4cout << "Number of original histories in header file \""
0277      << filename << ".IAEAphsp\"" << " = " << nHistories << G4endl;
0278 
0279 
0280   // And finally, take all the information related to the extra variables
0281 
0282   IAEA_I32 nExtraFloat, nExtraInt;
0283   iaea_get_extra_numbers(&sourceRead, &nExtraFloat, &nExtraInt );
0284   fNumberOfExtraFloats = static_cast<G4int>( nExtraFloat );
0285   fNumberOfExtraInts = static_cast<G4int>( nExtraInt );
0286 
0287   G4cout << "The number of Extra Floats is " << fNumberOfExtraFloats
0288      << " and the number of Extra Ints is " << fNumberOfExtraInts
0289      << G4endl;
0290 
0291   // Initializing vectors
0292 
0293   IAEA_I32 extraFloatTypes[NUM_EXTRA_FLOAT], extraIntTypes[NUM_EXTRA_LONG];
0294   iaea_get_type_extra_variables(&sourceRead, &result,
0295                 extraIntTypes, extraFloatTypes);
0296 
0297   if (fNumberOfExtraFloats > 0) {
0298     fExtraFloatTypes->reserve( fNumberOfExtraFloats );
0299     for (G4int jj = 0; jj < fNumberOfExtraFloats; jj++)
0300       fExtraFloatTypes->push_back( static_cast<G4int>(extraFloatTypes[jj]) );
0301   }
0302 
0303   if (fNumberOfExtraInts > 0) {
0304     fExtraIntTypes->reserve( fNumberOfExtraInts );
0305     for (G4int ii = 0; ii < fNumberOfExtraInts; ii++)
0306       fExtraIntTypes->push_back( static_cast<G4int>(extraIntTypes[ii]) );
0307   }
0308 }
0309 
0310 
0311 // =============================================================================
0312 // This is the pure virtual method inherited from G4VUserPrimaryGeneratorAction
0313 // and it is meant to be a template method.
0314 
0315 void G4IAEAphspReader::GeneratePrimaryVertex(G4Event* evt)
0316 {
0317   if (fLastGenerated) {
0318     RestartSourceFile();
0319     ReadAndStoreFirstParticle();
0320   }
0321 
0322   PrepareThisEvent();
0323 
0324   if (fNStat == 0) {
0325     ReadThisEvent();
0326     GeneratePrimaryParticles(evt);
0327   }
0328 }
0329 
0330 
0331 // =============================================================================
0332 
0333 void G4IAEAphspReader::RestartSourceFile()
0334 {
0335   // Restart counters and flags
0336   fCurrentParticle = 0;
0337   fEndOfFile = false;
0338   fLastGenerated = false;
0339 
0340   // Clear all the vectors
0341   fParticleTypeVec->clear();
0342   fKinEVec->clear();
0343   fPosVec->clear();
0344   fMomDirVec->clear();
0345   fWeightVec->clear();
0346   if (fNumberOfExtraFloats) fExtraFloatVec->clear();
0347   if (fNumberOfExtraInts) fExtraIntVec->clear();
0348 
0349   // Close and reopen the IAEA source with the same ID
0350   IAEA_I32 sourceRead = static_cast<IAEA_I32>(fSourceReadId);
0351   const IAEA_I32 accessRead = 1; // static_cast<IAEA_I32>( fAccessRead );
0352   IAEA_I32 result = 0;
0353 
0354   G4cout << "G4IAEAphspReader ==> Closing IAEA source ID = " << fSourceReadId
0355      << " to re-open it and reset fOriginalHistoriesUsed"
0356      << G4endl;
0357   iaea_destroy_source(&sourceRead, &result);
0358 
0359   iaea_new_source(&sourceRead, const_cast<char*>( fFileName.data() ),
0360           &accessRead, &result, fFileName.size()+1 );
0361   if ( sourceRead < 0 || result < 0 )
0362     G4Exception("G4IAEAphspReader::RestartSourceFile()",
0363         "IAEAphspReader006", FatalException,
0364         "Could not open IAEA source file to read");
0365 
0366   // Ensure that source Id data member is correct.
0367   fSourceReadId = static_cast<G4int>(sourceRead);
0368   G4cout << "G4IAEAphspReader ==> IAEA source re-started with ID = "
0369      << fSourceReadId << "." << G4endl;
0370 
0371   iaea_check_file_size_byte_order(&sourceRead, &result);
0372 
0373   if (result < 0 )
0374     G4Exception("G4IAEAphspReader::RestartSourceFile()",
0375         "IAEAphspReader007", FatalException,
0376         "Failure at iaea_check_size_byte_order()");
0377 }
0378 
0379 
0380 
0381 // =============================================================================
0382 
0383 void G4IAEAphspReader::ReadAndStoreFirstParticle()
0384 {
0385   // Particle properties
0386   IAEA_I32 type, nStat;
0387   IAEA_Float E, wt, x, y, z, u, v, w;
0388   IAEA_Float extraFloats[NUM_EXTRA_FLOAT];
0389   IAEA_I32 extraInts[NUM_EXTRA_LONG]; 
0390 
0391   IAEA_I32 sourceRead = static_cast<IAEA_I32>(fSourceReadId);
0392 
0393   // -------------------------------------------------------------------
0394   // Compute first and last particle in case that parallel run commands
0395   // may have not been issued
0396   // -------------------------------------------------------------------
0397 
0398   if (fParallelRun == 1)
0399     ComputeFirstLastParticle();
0400 
0401   // ------------------------------
0402   //  Go to the suitable particle
0403   // ------------------------------
0404   IAEA_I32 chunk = static_cast<IAEA_I32>((fParallelRun-1)*fTotalThreads);
0405 
0406   if ( G4Threading::IsMultithreadedApplication() )
0407     chunk += static_cast<IAEA_I32>(G4Threading::G4GetThreadId()+1);
0408   else
0409     chunk += 1;
0410 
0411   // G4cout << "DEBUG!! fParallelRun= " << fParallelRun << G4endl;
0412   // G4cout << "DEBUG!! fTotalThreads= " << fTotalThreads << G4endl;
0413   // G4cout << "DEBUG!! chunk= " << chunk << G4endl;
0414 
0415   IAEA_I32 totalChunks =
0416     static_cast<IAEA_I32>(fTotalParallelRuns*fTotalThreads);
0417   // G4cout << "DEBUG!! totalChunks= " << totalChunks << G4endl;
0418 
0419   IAEA_I32 result;
0420   iaea_set_parallel(&sourceRead, 0, &chunk, &totalChunks, &result);
0421   // G4cout << "DEBUG!!!   " << sourceRead << "  " << chunk
0422   //     << "   " << totalChunks << "    " << result << G4endl;
0423 
0424   if (result < 0) {
0425     G4ExceptionDescription ed;
0426     ed << "ERROR placing the cursor within the phsp file [iaea_set_parallel()]"
0427        << G4endl;
0428     G4Exception("G4IAEAphspReader::ReadAndStoreFirstParticle()",
0429         "IAEAphspReader008", FatalException, ed);
0430   }
0431 
0432   fCurrentParticle = fFirstParticle;  // To keep track of ordering in phsp file
0433 
0434   // -------------------------------------------------
0435   //  Obtain all the information needed from the file
0436   // -------------------------------------------------
0437 
0438   // read IAEA particle
0439   fCurrentParticle++; // to keep the position of this particle in the PSF
0440   iaea_get_particle(&sourceRead, &nStat, &type, 
0441             &E, &wt, &x, &y, &z, &u, &v, &w, extraFloats, extraInts);
0442   // This function increases the number returne
0443   // by iaea_get_used_original_particles
0444 
0445   if (fVerbose > 1) {
0446     G4cout << std::setprecision(6) << G4endl
0447        << "G4IAEAphspReader: Reading particle # "
0448        << fCurrentParticle << "   type= " << type
0449        << "   n_stat= " << nStat
0450        << G4endl
0451        << "\t\t E= " << E << "   wt= " << wt
0452        << G4endl
0453        << "\t\t x= " << x << "   y= " << y << "   z= " << z
0454        << "   u= " << u << "   v= " << v << "   w= " << w
0455        << G4endl;
0456   }
0457 
0458   if (nStat == -1)
0459     G4Exception("G4IAEAphspReader::ReadAndStoreFirstParticle()",
0460         "IAEAphspReader009", FatalException,
0461         "Cannot find source file");
0462   else if (nStat == 0)
0463     fNStat = 1; // needed to set this first particle as new event
0464   else
0465     fNStat = nStat;
0466     // important to calculate correlations properly
0467 
0468   // -------------------------------------------------
0469   //  Store the information into the data members
0470   // -------------------------------------------------
0471 
0472   fParticleTypeVec->push_back(static_cast<G4int>(type) );
0473   fKinEVec->push_back(static_cast<G4double>(E));
0474 
0475   G4ThreeVector pos, momDir;
0476   pos.set(static_cast<G4double>(x),
0477       static_cast<G4double>(y),
0478       static_cast<G4double>(z));
0479 
0480   momDir.set(static_cast<G4double>(u),
0481          static_cast<G4double>(v),
0482          static_cast<G4double>(w));
0483 
0484   fPosVec->push_back(pos);
0485   fMomDirVec->push_back(momDir);
0486 
0487   fWeightVec->push_back(static_cast<G4double>(wt));
0488 
0489   if (fNumberOfExtraFloats > 0) {
0490     std::vector<G4double> vExtraFloats;
0491     vExtraFloats.reserve(fNumberOfExtraFloats);
0492     for (G4int jj = 0; jj < fNumberOfExtraFloats; jj++)
0493       vExtraFloats.push_back( static_cast<G4double>(extraFloats[jj]) );
0494 
0495     fExtraFloatVec->push_back(vExtraFloats);
0496   }
0497 
0498   if (fNumberOfExtraInts > 0) {
0499     std::vector<G4long> vExtraInts;
0500     vExtraInts.reserve(fNumberOfExtraInts);
0501     for (G4int ii = 0; ii < fNumberOfExtraInts; ii++)
0502       vExtraInts.push_back( static_cast<G4long>(extraInts[ii]) );
0503 
0504     fExtraIntVec->push_back(vExtraInts);
0505   }
0506 
0507   //  Update fUsedOrigHistories
0508   // ---------------------------------
0509 
0510   IAEA_I64 nUsedOriginal;
0511   iaea_get_used_original_particles(&sourceRead, &nUsedOriginal);
0512   fUsedOrigHistories = static_cast<G4long>(nUsedOriginal);
0513   if (fVerbose > 0)
0514     G4cout << "G4IAEAphspReader::fUsedOrigHistories = "
0515        << fUsedOrigHistories << " from IAEAphsp source #" << sourceRead
0516        << G4endl;
0517 
0518   //  Safety check in case that only one particle is stored
0519   //  or only one particle can be taken into consideration.
0520   // -------------------------------------------------------
0521 
0522   if (fCurrentParticle == fLastParticle) 
0523     fEndOfFile = true;
0524 }
0525 
0526 
0527 // =============================================================================
0528 
0529 void G4IAEAphspReader::PrepareThisEvent()
0530 {
0531   fNStat--;  // A new event begins
0532 
0533   // Erase all the elements but the last in the vectors
0534   // In case that the size of the lists is just 1, there's no need
0535   // to clean up.
0536 
0537   G4int listSizes = fParticleTypeVec->size();
0538 
0539   if (listSizes > 1) {
0540     fParticleTypeVec->erase(fParticleTypeVec->begin(),
0541                 fParticleTypeVec->end()-1);
0542     fKinEVec->erase(fKinEVec->begin(), fKinEVec->end()-1);
0543     fPosVec->erase(fPosVec->begin(), fPosVec->end()-1);
0544     fMomDirVec->erase(fMomDirVec->begin(), fMomDirVec->end()-1);
0545     fWeightVec->erase(fWeightVec->begin(), fWeightVec->end()-1);
0546 
0547     if (fNumberOfExtraFloats > 0)
0548       fExtraFloatVec->erase(fExtraFloatVec->begin(), fExtraFloatVec->end()-1);
0549 
0550     if (fNumberOfExtraInts > 0)
0551       fExtraIntVec->erase(fExtraIntVec->begin(), fExtraIntVec->end()-1);
0552   }
0553 }
0554 
0555 
0556 // =============================================================================
0557 
0558 void G4IAEAphspReader::ReadThisEvent()
0559 {
0560   // Particle properties
0561   IAEA_I32 type, nStat;
0562   IAEA_Float E, wt, x, y, z, u, v, w;
0563   IAEA_I32 extraInts[NUM_EXTRA_LONG]; 
0564   IAEA_Float extraFloats[NUM_EXTRA_FLOAT];
0565 
0566   IAEA_I32 sourceRead = static_cast<IAEA_I32>(fSourceReadId);
0567 
0568   // -------------------------------------------------
0569   //  Obtain all the information needed from the file
0570   // -------------------------------------------------
0571 
0572   while (fNStat == 0 && !fEndOfFile) {
0573     //  Read next IAEA particle
0574     // -------------------------
0575 
0576     fCurrentParticle++;
0577     iaea_get_particle(&sourceRead, &nStat, &type, &E, &wt,
0578               &x, &y, &z, &u, &v, &w, extraFloats, extraInts);
0579     if (fVerbose > 1)
0580       G4cout << std::setprecision(6) << G4endl
0581          << "G4IAEAphspReader: Reading particle # "
0582          << fCurrentParticle << "   type= " << type
0583          << "   n_stat= " << nStat
0584          << G4endl
0585          << "\t\t E= " << E << "   wt= " << wt
0586          << G4endl
0587          << "\t\t x= " << x << "   y= " << y << "   z= " << z
0588          << "   u= " << u << "   v= " << v << "   w= " << w
0589          << G4endl;
0590 
0591     if (nStat == -1)
0592       G4Exception("G4IAEAphspReader::ReadThisEvent()",
0593           "IAEAphspReader010", FatalException,
0594           "Cannot find source file");
0595     else
0596       fNStat += nStat;  // statistical book-keeping
0597 
0598 
0599     //  Store the information into the data members
0600     // ---------------------------------------------
0601 
0602     fParticleTypeVec->push_back(static_cast<G4int>(type) );
0603     fKinEVec->push_back(static_cast<G4double>(E));
0604 
0605     G4ThreeVector pos, momDir;
0606     pos.set(static_cast<G4double>(x), 
0607         static_cast<G4double>(y),
0608         static_cast<G4double>(z));
0609 
0610     momDir.set(static_cast<G4double>(u),
0611         static_cast<G4double>(v),
0612         static_cast<G4double>(w));
0613 
0614     fPosVec->push_back(pos);
0615     fMomDirVec->push_back(momDir);
0616 
0617     fWeightVec->push_back(static_cast<G4double>(wt));
0618 
0619     if (fNumberOfExtraFloats > 0) {
0620       std::vector<G4double> vExtraFloats;
0621       vExtraFloats.reserve(fNumberOfExtraFloats);
0622       for (G4int jj = 0; jj < fNumberOfExtraFloats; jj++)
0623     vExtraFloats.push_back( static_cast<G4double>(extraFloats[jj]) );
0624 
0625       fExtraFloatVec->push_back(vExtraFloats);
0626     }
0627 
0628     if (fNumberOfExtraInts > 0) {
0629       std::vector<G4long> vExtraInts;
0630       vExtraInts.reserve(fNumberOfExtraInts);
0631       for (G4int ii = 0; ii < fNumberOfExtraInts; ii++)
0632     vExtraInts.push_back( static_cast<G4long>(extraInts[ii]) );
0633 
0634       fExtraIntVec->push_back(vExtraInts);
0635     }
0636 
0637     //  Update fUsedOrigHistories
0638     // ---------------------------------
0639 
0640     IAEA_I64 nUsedOriginal;
0641     iaea_get_used_original_particles(&sourceRead, &nUsedOriginal);
0642     fUsedOrigHistories = static_cast<G4long>(nUsedOriginal);
0643     if (fVerbose > 0)
0644       G4cout << "G4IAEAphspReader::fUsedOrigHistories = "
0645          << fUsedOrigHistories << " from IAEAphsp source #" << sourceRead
0646          << G4endl;
0647 
0648     //  Check whether the end of chunk has been reached
0649     // -------------------------------------------------
0650     if (fCurrentParticle == fLastParticle)
0651       fEndOfFile = true;
0652   }
0653 }
0654 
0655 
0656 // =============================================================================
0657 
0658 void G4IAEAphspReader::GeneratePrimaryParticles(G4Event* evt)
0659 {
0660   // -----------------------------------------------------------
0661   // Only when the EOF has been reached and fNStat is still 0 
0662   // all the particles must be read.
0663   // Otherwise, don't read the last particle.
0664   // -----------------------------------------------------------
0665 
0666   G4int listSize = fParticleTypeVec->size();
0667 
0668   if (fEndOfFile && fNStat == 0) {
0669     // Read all the particles, so this flag switches on
0670     fLastGenerated = true;
0671 
0672     // Throw a warning due to the following restarting
0673     G4cout << "WARNING: Last particle to read from IAEAphsp reached at event "
0674        << evt->GetEventID() << "."
0675        << G4endl;
0676   }
0677   else {
0678     // The last particle belongs to a later event
0679     listSize--;
0680   }
0681 
0682   // ---------------------------------------------------------------------
0683   // Generate the random rotations if any rotational symmetry is applied.
0684   // This is applied when recycling particles.
0685   // In order to keep correlations, the same rotation must be applied to
0686   // all the particles of the same original history during same re-use.
0687   // ---------------------------------------------------------------------
0688 
0689   std::vector<G4double> randomRotations;
0690 
0691   if (fAxialSymmetryZ || fAxialSymmetryX || fAxialSymmetryY) {
0692     randomRotations.reserve(fTimesRecycled+1);
0693     for (G4int ii = 0; ii <= fTimesRecycled; ii++) {
0694       G4double randomAngle = G4UniformRand();
0695       randomAngle *= (360.*deg);
0696       randomRotations.push_back(randomAngle);
0697     }
0698   }
0699 
0700   // ---------------------------------------------
0701   // loop over all the particles obtained from PSF
0702   // ---------------------------------------------
0703   for (G4int ii = 0; ii < listSize; ii++) {
0704 
0705     // First: Particle Definition
0706     // --------------------------
0707     
0708     G4ParticleDefinition * partDef = 0;
0709     switch((*fParticleTypeVec)[ii]) {
0710     case 1:
0711       partDef = G4Gamma::Definition();
0712       break;
0713     case 2:
0714       partDef = G4Electron::Definition();
0715       break;
0716     case 3:
0717       partDef = G4Positron::Definition();
0718       break;
0719     case 4:
0720       partDef = G4Neutron::Definition();
0721       break;
0722     case 5:
0723       partDef = G4Proton::Definition();
0724       break;
0725     default:
0726       G4ExceptionDescription ED;
0727       ED << "Particle code read at event #" << evt->GetEventID()
0728      << "is" << (*fParticleTypeVec)[ii]
0729      << " - this is not supported by the IAEAphsp format." << G4endl;
0730       G4Exception("G4IAEAphspReader::GeneratePrimaryParticles()",
0731           "IAEAphspReader011", EventMustBeAborted, ED);
0732       return;
0733     }
0734 
0735     // Second: Particle position, time and momentum
0736     // --------------------------------------------
0737 
0738     particle_position = (*fPosVec)[ii];
0739     particle_position *= cm;        // IAEA file stores in cm
0740 
0741     G4double partMass = partDef->GetPDGMass();
0742     G4double partTotE = static_cast<G4double>((*fKinEVec)[ii])*MeV + partMass;
0743     G4double partMom = std::sqrt( partTotE*partTotE - partMass*partMass );
0744 
0745     G4ThreeVector partMomVec;
0746     partMomVec = (*fMomDirVec)[ii];
0747     partMomVec *= partMom;
0748 
0749     // Third: Translation and rotations
0750     // ---------------------------------
0751 
0752     // Translation is performed before rotations
0753     particle_position += fGlobalPhspTranslation;
0754     PerformRotations(partMomVec);
0755 
0756     // -------------------------------------------------
0757     //  Creation of the new primary particle and vertex
0758     // -------------------------------------------------
0759 
0760     // loop to take care of recycling
0761     for (G4int jj = 0; jj <= fTimesRecycled; jj++)  {
0762       // Apply the rotational symmetries if they are applicable
0763       if (fAxialSymmetryZ) {
0764     particle_position.rotateZ(randomRotations[jj]);
0765     partMomVec.rotateZ(randomRotations[jj]);
0766       }
0767       else if (fAxialSymmetryX) {
0768     particle_position.rotateX(randomRotations[jj]);
0769     partMomVec.rotateX(randomRotations[jj]);
0770       }
0771       else if (fAxialSymmetryY) {
0772     particle_position.rotateY(randomRotations[jj]);
0773     partMomVec.rotateY(randomRotations[jj]);
0774       }
0775 
0776       // Create the new primary particle
0777       G4PrimaryParticle * particle =
0778     new G4PrimaryParticle(partDef,
0779                   partMomVec.x(),partMomVec.y(),partMomVec.z());
0780 
0781       particle->SetWeight( ((*fWeightVec)[ii])/(fTimesRecycled+1) );
0782 
0783       // Create the new primary vertex and set the primary to it
0784       G4PrimaryVertex * vertex =
0785     new G4PrimaryVertex(particle_position, particle_time);
0786       vertex->SetPrimary(particle);
0787 
0788       if (fVerbose > 1)
0789     G4cout << std::setprecision(6) << G4endl
0790            << "G4IAEAphspReader ==> Vertex produced: "
0791            << " Event # " << evt->GetEventID()
0792            << "   ParticleName: " << partDef->GetParticleName()
0793            << G4endl
0794            << "\t\t kinEnergy[MeV]= " << particle->GetKineticEnergy()/MeV
0795            << "   weight= " << particle->GetWeight()
0796            << G4endl
0797            << "\t\t x[cm]= " << vertex->GetX0()/cm
0798            << "   y[cm]= " << vertex->GetY0()/cm
0799            << "   z[cm]= " << vertex->GetZ0()/cm
0800            << "   u= " << particle->GetMomentumDirection().x()
0801            << "   v= " << particle->GetMomentumDirection().y()
0802            << "   w= " << particle->GetMomentumDirection().z()
0803            << G4endl;
0804 
0805       // And finally set the vertex to this event
0806       evt->AddPrimaryVertex(vertex);
0807     }
0808   }
0809 }
0810 
0811 
0812 // =============================================================================
0813 
0814 void G4IAEAphspReader::PerformRotations(G4ThreeVector & mom)
0815 {
0816   PerformGlobalRotations(mom);
0817   PerformHeadRotations(mom);
0818 }
0819 
0820 
0821 // =============================================================================
0822 
0823 void G4IAEAphspReader::PerformGlobalRotations(G4ThreeVector & momentum)
0824 {
0825   switch (fRotationOrder) {
0826   case 123:
0827     particle_position.rotateX(fAlpha);
0828     particle_position.rotateY(fBeta);
0829     particle_position.rotateZ(fGamma);
0830     momentum.rotateX(fAlpha);
0831     momentum.rotateY(fBeta);
0832     momentum.rotateZ(fGamma);
0833     break;
0834 
0835   case 132:
0836     particle_position.rotateX(fAlpha);
0837     particle_position.rotateZ(fGamma);
0838     particle_position.rotateY(fBeta);
0839     momentum.rotateX(fAlpha);
0840     momentum.rotateZ(fGamma);
0841     momentum.rotateY(fBeta);
0842     break;
0843 
0844   case 213:
0845     particle_position.rotateY(fBeta);
0846     particle_position.rotateX(fAlpha);
0847     particle_position.rotateZ(fGamma);
0848     momentum.rotateY(fBeta);
0849     momentum.rotateX(fAlpha);
0850     momentum.rotateZ(fGamma);
0851     break;
0852 
0853   case 231:
0854     particle_position.rotateY(fBeta);
0855     particle_position.rotateZ(fGamma);
0856     particle_position.rotateX(fAlpha);
0857     momentum.rotateY(fBeta);
0858     momentum.rotateZ(fGamma);
0859     momentum.rotateX(fAlpha);
0860     break;
0861 
0862   case 312:
0863     particle_position.rotateZ(fGamma);
0864     particle_position.rotateX(fAlpha);
0865     particle_position.rotateY(fBeta);
0866     momentum.rotateZ(fGamma);
0867     momentum.rotateX(fAlpha);
0868     momentum.rotateY(fBeta);
0869     break;
0870 
0871   case 321:
0872     particle_position.rotateZ(fGamma);
0873     particle_position.rotateY(fBeta);
0874     particle_position.rotateX(fAlpha);
0875     momentum.rotateZ(fGamma);
0876     momentum.rotateY(fBeta);
0877     momentum.rotateX(fAlpha);
0878     break;
0879 
0880   default:
0881     G4ExceptionDescription ED;
0882     ED << "Invalid combination in G4IAEAphspReader::fRotationOrder -> "
0883        << "NO global rotations are done." << G4endl;
0884     G4Exception("G4IAEAphspReader::PerformGlobalRotations()",
0885         "IAEAphspReader012", FatalErrorInArgument, ED);
0886   }
0887 }
0888 
0889 
0890 // =============================================================================
0891 
0892 void G4IAEAphspReader::PerformHeadRotations(G4ThreeVector & momentum)
0893 {
0894   // First we need the position related to the isocenter
0895   particle_position -= fIsocenterPosition;
0896 
0897   // And now comes both rotations whose axis contain the isocenter
0898 
0899   // First is the rotation of the collimator around its defined axis
0900   particle_position.rotate(fCollimatorRotAxis, fCollimatorAngle);
0901   momentum.rotate(fCollimatorRotAxis, fCollimatorAngle);
0902 
0903   // The rotation of the complete machine is applied afterwards
0904   particle_position.rotate(fGantryRotAxis, fGantryAngle);
0905   momentum.rotate(fGantryRotAxis, fGantryAngle);
0906 
0907   // And finally, restore the position to the global coordinate system
0908   particle_position += fIsocenterPosition;
0909 }
0910 
0911 
0912 
0913 // =============================================================================
0914 
0915 void G4IAEAphspReader::SetParallelRun(const G4int parallelRun)
0916 {
0917   if (parallelRun > fTotalParallelRuns || parallelRun < 1) {
0918     G4ExceptionDescription ED;
0919     ED << "SetParallelRun argument must be an integer between 1 "
0920        << "and fTotalParallelRuns" << G4endl;
0921     G4Exception("G4IAEAphspReader::SetParallelRun()",
0922         "IAEAphspReader013", FatalErrorInArgument, ED);
0923   }
0924   fParallelRun = parallelRun;
0925 
0926   if (fVerbose > 0)
0927     G4cout << "G4IAEAphspReader::fParallelRun = " << fParallelRun
0928        << G4endl;
0929 
0930   ComputeFirstLastParticle();
0931 }
0932 
0933 
0934 // =============================================================================
0935 
0936 void G4IAEAphspReader::ComputeFirstLastParticle()
0937 {
0938   // ---------------------------------------------------------
0939   // Get the limits within this instance reads from the file,
0940   // defined by first and last particle.
0941   // ---------------------------------------------------------
0942 
0943   G4cout << "G4IAEAphspReader: Defined " << fTotalParallelRuns
0944      << " chunks in the file"
0945      << " (i.e. number of independent simulations in parallel)" << G4endl;
0946 
0947   G4cout << "G4IAEAphspReader ==> This run is using the chunk #"
0948          << fParallelRun << " of the " << fTotalParallelRuns
0949          << " defined in the phsp file." << G4endl;
0950 
0951   // Below, operations are done exactly the same way as seen in
0952   // iaea_set_parallel() method, for consistency.
0953   // This means that all integers are obtained by truncation of floats.
0954   // Thus, it is expected that
0955   // particlesChunk*(fTotalParallelRuns*fTotalThreads) <= fTotalParticles
0956 
0957   IAEA_I64 particlesChunk = fTotalParticles/(fTotalParallelRuns*fTotalThreads);
0958   IAEA_I64 firstParticle = particlesChunk*(fParallelRun-1)*fTotalThreads;
0959 
0960   if ( G4Threading::IsMultithreadedApplication() ) {
0961     IAEA_I32 threadID = static_cast<IAEA_I32>(G4Threading::G4GetThreadId());
0962     firstParticle += particlesChunk*threadID;
0963   }
0964 
0965   IAEA_I64 lastParticle = firstParticle + particlesChunk;
0966 
0967   fFirstParticle = static_cast<G4long>(firstParticle);
0968   fLastParticle = static_cast<G4long>(lastParticle);
0969 
0970   // In case of roundings instead of truncation, the following may happen.
0971   if (fLastParticle > fTotalParticles)
0972     fLastParticle = fTotalParticles;
0973 
0974   // Note: The first particle is at position #1, not #0.
0975   G4cout << "G4IAEAphspReader: "
0976      << "This thread is reading the particles from place #"
0977      << fFirstParticle+1 << " to #" << fLastParticle
0978      << " within the phsp file" << G4endl;
0979 }
0980 
0981 
0982 // =============================================================================
0983 
0984 void G4IAEAphspReader::SetCollimatorRotationAxis(const G4ThreeVector & axis)
0985 {
0986   G4double mod = axis.mag();
0987   if (mod > 0) {
0988     // Normalization
0989     G4double scale = 1.0/mod;
0990     G4double ux = scale*axis.getX();
0991     G4double uy = scale*axis.getY();
0992     G4double uz = scale*axis.getZ();
0993     fCollimatorRotAxis.setX(ux);
0994     fCollimatorRotAxis.setY(uy);
0995     fCollimatorRotAxis.setZ(uz);
0996   }
0997   else {
0998     G4ExceptionDescription ED;
0999     ED << "Trying to set as CollimatorRotationAxis a null vector, "
1000        << "thus the previous value will remain." << G4endl;
1001     G4Exception("G4IAEAphspReader::SetCollimatorRotationAxis()",
1002         "IAEAphspReader014", JustWarning, ED);
1003   } 
1004 }
1005 
1006 
1007 // =============================================================================
1008 
1009 void G4IAEAphspReader::SetGantryRotationAxis(const G4ThreeVector & axis)
1010 {
1011   G4double mod = axis.mag();
1012   if ( mod > 0 ) {
1013     // Normalization
1014     G4double scale = 1.0/mod;
1015     G4double ux = scale*axis.getX();
1016     G4double uy = scale*axis.getY();
1017     G4double uz = scale*axis.getZ();
1018     fGantryRotAxis.setX(ux);
1019     fGantryRotAxis.setY(uy);
1020     fGantryRotAxis.setZ(uz);
1021   }
1022   else {
1023     G4ExceptionDescription ED;
1024     ED << "Trying to set as GantryRotationAxis a null vector, "
1025        << "thus the previous value will remain." << G4endl;
1026     G4Exception("G4IAEAphspReader::SetGantryRotationAxis()",
1027         "IAEAphspReader015", JustWarning, ED);
1028   }
1029 }
1030 
1031 
1032 // =============================================================================
1033 
1034 G4long G4IAEAphspReader::GetTotalParticlesOfType(const G4String type) const
1035 {
1036   IAEA_I32 particleType;
1037 
1038   if (type == "ALL") particleType = -1;
1039   else if (type == "PHOTON") particleType = 1;
1040   else if (type == "ELECTRON") particleType = 2;
1041   else if (type == "POSITRON") particleType = 3;
1042   else if (type == "NEUTRON") particleType = 4;
1043   else if (type == "PROTON") particleType = 5;
1044   else particleType = 0;
1045 
1046   if (particleType == 0) {
1047     G4ExceptionDescription ED;
1048     ED << "Particle type \"" << type << "\" is not valid."
1049        << " (Please do ensure that all characters are uppercase)"
1050        << G4endl;
1051     G4Exception("G4IAEAphspReader::GetTotalParticlesOfType()",
1052         "IAEAphspReader016", JustWarning, ED);
1053     return -1;
1054   }
1055 
1056   IAEA_I64 nParticles;
1057   const IAEA_I32 sourceRead = static_cast<IAEA_I32>( fSourceReadId );
1058   iaea_get_max_particles(&sourceRead, &particleType, &nParticles);
1059 
1060   if (nParticles < 0)
1061     G4Exception("G4IAEAphspReader::GetTotalParticlesOfType()",
1062         "IAEAphspReader017", JustWarning,
1063         "IAEA header file not found");
1064   else
1065     G4cout << "G4IAEAphspReader: "
1066        << "Total number of " << type << " in filename "
1067        << fFileName << ".IAEAphsp" << " = " << nParticles << G4endl;
1068 
1069   return ( static_cast<G4long>(nParticles) );
1070 }
1071 
1072 
1073 // =============================================================================
1074 
1075 G4double G4IAEAphspReader::GetConstantVariable(const G4int index) const
1076 {
1077   const IAEA_I32 sourceRead = static_cast<IAEA_I32>( fSourceReadId );
1078   const IAEA_I32 idx = static_cast<IAEA_I32>( index );
1079   IAEA_Float constVariable;
1080   IAEA_I32 result;
1081 
1082   iaea_get_constant_variable(&sourceRead, &idx, &constVariable, &result);
1083 
1084   if (result == -1)
1085     G4Exception("G4IAEAphspReader::GetConstantVariable()",
1086         "IAEAphspReader018", JustWarning,
1087         "IAEA header file source not found");
1088   else if (result == -2)
1089     G4Exception("G4IAEAphspReader::GetConstantVariable()",
1090         "IAEAphspReader019", JustWarning,
1091         "index out of range");
1092   else if (result == -3)
1093     G4Exception("G4IAEAphspReader::GetConstantVariable()",
1094         "IAEAphspReader020", JustWarning,
1095         "parameter indicated by 'index' is not a constant");
1096 
1097   return ( static_cast<G4double>(constVariable) );
1098 }