// // ******************************************************************** // * 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. * // ******************************************************************** // // $Id: HadrontherapyMatrix.cc; // See more at: http://g4advancedexamples.lngs.infn.it/Examples/hadrontherapy// #include "HadrontherapyMatrix.hh" #include "HadrontherapyAnalysisManager.hh" #include "G4RunManager.hh" #include "HadrontherapyPrimaryGeneratorAction.hh" #include "G4ParticleGun.hh" #include #include #include #include #include #include "globals.hh" // Units definition: CLHEP/Units/SystemOfUnits.h // HadrontherapyMatrix* HadrontherapyMatrix::instance = NULL; G4bool HadrontherapyMatrix::secondaries = false; // Only return a pointer to matrix HadrontherapyMatrix* HadrontherapyMatrix::GetInstance() { return instance; } // This STATIC method delete (!) the old matrix and rewrite a new object returning a pointer to it // TODO A check on the parameters is required! HadrontherapyMatrix* HadrontherapyMatrix::GetInstance(G4int voxelX, G4int voxelY, G4int voxelZ, G4double mass) { if (instance) delete instance; instance = new HadrontherapyMatrix(voxelX, voxelY, voxelZ, mass); instance -> Initialize();// XXX return instance; } HadrontherapyMatrix::HadrontherapyMatrix(G4int voxelX, G4int voxelY, G4int voxelZ, G4double mass): filename("Dose.out"), doseUnit(MeV/g) { // Number of the voxels of the phantom // For Y = Z = 1 the phantom is divided in slices (and not in voxels) // orthogonal to the beam axis numberOfVoxelAlongX = voxelX; numberOfVoxelAlongY = voxelY; numberOfVoxelAlongZ = voxelZ; massOfVoxel = mass; // Create the dose matrix matrix = new G4double[numberOfVoxelAlongX*numberOfVoxelAlongY*numberOfVoxelAlongZ]; if (matrix) { G4cout << "HadrontherapyMatrix: Memory space to store physical dose into " << numberOfVoxelAlongX*numberOfVoxelAlongY*numberOfVoxelAlongZ << " voxels has been allocated " << G4endl; } else G4Exception(" HadrontherapyMatrix::HadrontherapyMatrix. Can't allocate memory to store physical dose!"); // Hit voxel (TrackID) marker // This array mark the status of voxel, if a hit occur, with the trackID of the particle // Must be initialized hitTrack = new G4int[numberOfVoxelAlongX*numberOfVoxelAlongY*numberOfVoxelAlongZ]; ClearHitTrack(); } ///////////////////////////////////////////////////////////////////////////// HadrontherapyMatrix::~HadrontherapyMatrix() { delete[] matrix; delete[] hitTrack; // clear fluences/dose data Clear(); } ///////////////////////////////////////////////////////////////////////////// void HadrontherapyMatrix::Clear() { for (size_t i=0; i GetPDGEncoding(); PDGencoding -= PDGencoding%10; // Search for already allocated data... for (size_t l=0; l < ionStore.size(); l++) { if (ionStore[l].PDGencoding == PDGencoding ) { // Is it a primary or a secondary particle? if ( trackID ==1 && ionStore[l].isPrimary || trackID !=1 && !ionStore[l].isPrimary) { if (energyDeposit > 0.) ionStore[l].dose[Index(i, j, k)] += energyDeposit/massOfVoxel; // Fill a matrix per each ion with the fluence if (fluence) ionStore[l].fluence[Index(i, j, k)]++; return true; } } } G4int Z = particleDef-> GetAtomicNumber(); G4int A = particleDef-> GetAtomicMass(); G4String fullName = particleDef -> GetParticleName(); G4String name = fullName.substr (0, fullName.find("[") ); // cut excitation energy // Let's put a new particle in our store... ion newIon = { (trackID == 1) ? true:false, PDGencoding, name, name.length(), Z, A, new G4double[numberOfVoxelAlongX * numberOfVoxelAlongY * numberOfVoxelAlongZ], new unsigned int[numberOfVoxelAlongX * numberOfVoxelAlongY * numberOfVoxelAlongZ] }; // Initialize data if (newIon.dose && newIon.fluence) { for(G4int m=0; m 0.) newIon.dose[Index(i, j, k)] += energyDeposit/massOfVoxel; if (fluence) newIon.fluence[Index(i, j, k)]++; ionStore.push_back(newIon); // TODO Put some verbosity check /* G4cout << "Memory space to store the DOSE/FLUENCE into " << numberOfVoxelAlongX*numberOfVoxelAlongY*numberOfVoxelAlongZ << " voxels has been allocated for the nuclide " << newIon.name << " (Z = " << Z << ", A = " << A << ")" << G4endl ; */ return true; } else // XXX Out of memory! XXX { return false; } } ///////////////////////////////////////////////////////////////////////////// ///////////////////////////////////////////////////////////////////////////// // Methods to store data to filenames... //////////////////////////////////////////////////////////////////////////// //////////////////////////////////////////////////////////////////////////// // // General method to store matrix data to filename void HadrontherapyMatrix::StoreMatrix(G4String file, void* data, size_t psize) { if (data) { ofs.open(file, std::ios::out); if (ofs.is_open()) { for(G4int i = 0; i < numberOfVoxelAlongX; i++) for(G4int j = 0; j < numberOfVoxelAlongY; j++) for(G4int k = 0; k < numberOfVoxelAlongZ; k++) { G4int n = Index(i, j, k); // Check for data type: u_int, G4double, XXX if (psize == sizeof(unsigned int)) { unsigned int* pdata = (unsigned int*)data; if (pdata[n]) ofs << i << '\t' << j << '\t' << k << '\t' << pdata[n] << G4endl; } else if (psize == sizeof(G4double)) { G4double* pdata = (G4double*)data; if (pdata[n]) ofs << i << '\t' << j << '\t' << k << '\t' << pdata[n] << G4endl; } } ofs.close(); } } } // Store fluence per single ion in multiple files void HadrontherapyMatrix::StoreFluenceData() { for (size_t i=0; i < ionStore.size(); i++){ StoreMatrix(ionStore[i].name + "_Fluence.out", ionStore[i].fluence, sizeof(unsigned int)); } } // Store dose per single ion in multiple files void HadrontherapyMatrix::StoreDoseData() { for (size_t i=0; i < ionStore.size(); i++){ StoreMatrix(ionStore[i].name + "_Dose.out", ionStore[i].dose, sizeof(G4double)); } } ///////////////////////////////////////////////////////////////////////// // Store dose for all ions into a single file and into ntuples. // Please note that this function is called via messenger commands // defined in the HadrontherapyAnalysisFileMessenger.cc class file void HadrontherapyMatrix::StoreDoseFluenceAscii() { // Sort like periodic table std::sort(ionStore.begin(), ionStore.end()); #define width 15L ofs.open(filename, std::ios::out); if (ofs.is_open()) { // // Write the voxels index and the list of particles/ions ofs << std::setprecision(6) << std::left << "i\tj\tk\t"; /* G4RunManager *runManager = G4RunManager::GetRunManager(); HadrontherapyPrimaryGeneratorAction *pPGA = (HadrontherapyPrimaryGeneratorAction*)runManager -> GetUserPrimaryGeneratorAction(); G4String name = pPGA -> GetParticleGun() -> GetParticleDefinition() -> GetParticleName(); */ // Total dose ofs << std::setw(width) << "Dose"; for (size_t l=0; l < ionStore.size(); l++) { G4String a = (ionStore[l].isPrimary) ? "_1":""; // is it a primary? ofs << std::setw(width) << ionStore[l].name + a << std::setw(width) << ionStore[l].name + a; } ofs << G4endl; /* // PDGencoding ofs << std::setprecision(6) << std::left << "0\t0\t0\t"; // Total dose ofs << std::setw(width) << '0'; for (size_t l=0; l < ionStore.size(); l++) { ofs << std::setw(width) << ionStore[l].PDGencoding << std::setw(width) << ionStore[l].PDGencoding; } ofs << G4endl; */ // Write data for(G4int i = 0; i < numberOfVoxelAlongX; i++) for(G4int j = 0; j < numberOfVoxelAlongY; j++) for(G4int k = 0; k < numberOfVoxelAlongZ; k++) { G4int n = Index(i, j, k); // Write only not identically null data lines if (matrix[n]) { ofs << G4endl; ofs << i << '\t' << j << '\t' << k << '\t'; // Total dose ofs << std::setw(width) << matrix[n]/(doseUnit); { for (size_t l=0; l < ionStore.size(); l++) { // Fill ASCII file rows ofs << std::setw(width) << ionStore[l].dose[n]/(doseUnit) << std::setw(width) << ionStore[l].fluence[n]; } } } } ofs.close(); } } ///////////////////////////////////////////////////////////////////////////// #ifdef G4ANALYSIS_USE_ROOT void HadrontherapyMatrix::StoreDoseFluenceRoot() { HadrontherapyAnalysisManager* analysis = HadrontherapyAnalysisManager::GetInstance(); for(G4int i = 0; i < numberOfVoxelAlongX; i++) for(G4int j = 0; j < numberOfVoxelAlongY; j++) for(G4int k = 0; k < numberOfVoxelAlongZ; k++) { G4int n = Index(i, j, k); for (size_t l=0; l < ionStore.size(); l++) { // Do the same work for .root file: fill dose/fluence ntuple analysis -> FillVoxelFragmentTuple( i, j, k, ionStore[l].A, ionStore[l].Z, ionStore[l].dose[n]/(doseUnit), ionStore[l].fluence[n] ); } } } #endif void HadrontherapyMatrix::Fill(G4int i, G4int j, G4int k, G4double energyDeposit) { if (matrix) matrix[Index(i,j,k)] += energyDeposit; // Store the energy deposit in the matrix element corresponding // to the phantom voxel } void HadrontherapyMatrix::TotalEnergyDeposit() { // Convert energy deposited to dose. // Store the information of the matrix in a ntuple and in // a 1D Histogram #ifdef G4ANALYSIS_USE_ROOT HadrontherapyAnalysisManager* analysis = HadrontherapyAnalysisManager::GetInstance(); #endif if (matrix) { for(G4int i = 0; i < numberOfVoxelAlongX; i++) for(G4int j = 0; j < numberOfVoxelAlongY; j++) for(G4int k = 0; k < numberOfVoxelAlongZ; k++) { G4int n = Index(i,j,k); matrix[n] = matrix[n] / massOfVoxel; #ifdef G4ANALYSIS_USE_ROOT analysis -> FillEnergyDeposit(i, j, k, matrix[n]/doseUnit); analysis -> BraggPeak(i, matrix[n]/doseUnit); #endif } } }