File indexing completed on 2025-01-31 09:21:58
0001
0002
0003
0004
0005
0006
0007
0008
0009
0010
0011
0012
0013
0014
0015
0016
0017
0018
0019
0020
0021
0022
0023
0024
0025
0026
0027
0028
0029
0030
0031
0032
0033
0034
0035
0036
0037
0038
0039
0040
0041
0042
0043
0044
0045
0046
0047
0048
0049
0050
0051
0052
0053 #include "doiPETAnalysis.hh"
0054 #include "G4SystemOfUnits.hh"
0055 #include "G4PhysicalConstants.hh"
0056 #include <iomanip>
0057 #include "Randomize.hh"
0058 #include "G4SPSRandomGenerator.hh"
0059 #include "doiPETAnalysisMessenger.hh"
0060 #include "G4UnitsTable.hh"
0061 #include "globals.hh"
0062
0063 doiPETAnalysis* doiPETAnalysis::instance=0;
0064
0065
0066 doiPETAnalysis::doiPETAnalysis()
0067 {
0068 factoryOn = false;
0069
0070 for (G4int k=0; k<MaxNtCol; k++) fNtColId[k] = 0;
0071
0072 fAnalysisMessenger = new doiPETAnalysisMessenger(this);
0073
0074
0075 lowerThreshold = 400*keV;
0076 upperThreshold = 600*keV;
0077 triggerEnergy = 50*eV;
0078
0079
0080 InitialActivity = 1000000*becquerel;
0081
0082
0083 halfLife = 109.771*60 * s;
0084
0085
0086 totalTime = 0 * s;
0087 prev_totalTime = 0 * s;
0088 prev_eventID = 0;
0089
0090
0091
0092 crystalIDNew_tan = -1;
0093 crystalIDNew_axial = -1;
0094 crystalIDNew_DOI = -1;
0095
0096
0097 scatterIndex = 0;
0098
0099
0100 numberOfPixel_tan = 2*numberOfCrystal_tangential;
0101 numberOfPixel_axial = 2*numberOfCrystal_axial;
0102
0103
0104 block_DeadTime = 256*ns;
0105 module_DeadTime = 0*ns;
0106
0107
0108
0109
0110
0111 crystalResolutionMin = 0.13;
0112 crystalResolutionMax = 0.17;
0113
0114 crystalEnergyRef = 511 * keV;
0115
0116
0117
0118 crystalQuantumEfficiency = 1;
0119
0120
0121
0122 numberOfBlocks_total = numberOfRings * numberOfDetector_perRing;
0123 blockTime = new double[numberOfBlocks_total];
0124 moduleTime = new double[numberOfBlocks_total];
0125
0126
0127 for(G4int i = 0; i<numberOfBlocks_total; i++){
0128 blockTime [i] = 0.0;
0129 moduleTime [i] = 0.0;
0130 }
0131
0132
0133 getSinglesData = false;
0134 getCoincidenceData = false;
0135
0136 ApplyAngerLogic = true;
0137 isDOIlookUpTablePrepared = false;
0138
0139 numberOfHit = 0;
0140
0141
0142 shiftCoeff = 0.5;
0143
0144
0145 PMTblurring_tan = 0.0;
0146 PMTblurring_axial = 0.0;
0147 }
0148
0149 doiPETAnalysis::~doiPETAnalysis()
0150 {
0151 delete fAnalysisMessenger;
0152 delete [] blockTime;
0153 delete [] moduleTime;
0154 }
0155
0156
0157 doiPETAnalysis* doiPETAnalysis::GetInstance()
0158 {
0159 if(instance==0) instance = new doiPETAnalysis();
0160 return instance;
0161 }
0162 void doiPETAnalysis::Delete()
0163 {
0164 delete instance;
0165 }
0166
0167
0168
0169 void doiPETAnalysis::SetScatterIndexInPhantom(G4int sci){
0170 scatterIndex = sci;
0171 }
0172
0173
0174
0175 void doiPETAnalysis::SetSourcePosition(G4ThreeVector spos){
0176 spositionX = spos.x();
0177 spositionY = spos.y();
0178 spositionZ = spos.z();
0179 }
0180
0181
0182
0183
0184 void doiPETAnalysis::SetEventID(G4int evID){
0185 eventID = evID;
0186 }
0187
0188
0189
0190 void doiPETAnalysis::GetSizeOfDetector(G4double detSizeDoi, G4double detSizeTan, G4double detSizeAxial){
0191 sizeOfDetector_DOI = detSizeDoi;
0192 sizeOfDetector_axial = detSizeTan;
0193 sizeOfDetector_tangential = detSizeAxial;
0194 }
0195
0196
0197 void doiPETAnalysis::SetActivity(G4double newActivity){
0198 InitialActivity = newActivity;
0199 G4cout<<"Initial activity: "<<InitialActivity/becquerel<<" Bq."<<G4endl;
0200 }
0201 void doiPETAnalysis::SetIsotopeHalfLife(G4double newHalfLife){
0202 halfLife = newHalfLife;
0203 G4cout<<"Half life of the isotope "<<halfLife/s<<" sec."<<G4endl;
0204 }
0205
0206
0207
0208 void doiPETAnalysis::CalulateAcquisitionTime(){
0209
0210 activityNow = InitialActivity * std::exp(-((0.693147/halfLife)*totalTime));
0211
0212
0213 timeInterval = -std::log(G4UniformRand())*(1./activityNow);
0214 totalTime = timeInterval+prev_totalTime;
0215 prev_totalTime = totalTime;
0216 }
0217
0218
0219 G4double doiPETAnalysis::QuantumEffifciency(G4double edep, G4int blkID, G4int cysID)
0220 {
0221 if(fixedResolution){
0222 crystalResolution = energyResolution_fixed;
0223 }
0224 else{
0225 crystalResolution = energyResolution_cryDependent[blkID][cysID];
0226 }
0227 crystalCoeff = crystalResolution * std::sqrt(crystalEnergyRef);
0228
0229 G4double QE = G4UniformRand();
0230
0231
0232 if(QE <= crystalQuantumEfficiency)
0233 {
0234 edep_AfterCrystalBlurring = G4RandGauss::shoot(edep,crystalCoeff*std::sqrt(edep)/2.35);
0235 }
0236 else {
0237
0238 edep_AfterCrystalBlurring = 0 *keV;
0239 }
0240 return edep_AfterCrystalBlurring;
0241 }
0242
0243
0244
0245 void doiPETAnalysis::ReadOut(G4int blkID, G4int cryID, G4double interTime, G4double timeAnnih, G4ThreeVector interPos, G4double edep)
0246 {
0247 blockID = blkID;
0248 crystalID = cryID;
0249 interactionTime = interTime;
0250 time_annihil = timeAnnih;
0251 interactionPos = interPos;
0252 totalEdep = edep;
0253
0254
0255 time_tof = interactionTime - time_annihil;
0256
0257
0258 timeStamp = totalTime + time_tof;
0259
0260
0261 if(totalEdep<triggerEnergy)return;
0262
0263
0264
0265 if(std::fabs(timeStamp - blockTime[blockID]) >= block_DeadTime){
0266 blockTime[blockID] = timeStamp;
0267 }
0268 else {
0269
0270 blockTime[blockID] = timeStamp;
0271
0272
0273
0274 return;
0275 }
0276
0277
0278
0279 if(std::fabs(timeStamp - moduleTime[blockID]) > module_DeadTime){
0280
0281
0282 for (G4int r_ring = 0; r_ring < numberOfRings; r_ring++){
0283 if (blockID >= r_ring*numberOfDetector_perRing && blockID <(r_ring + 1)*numberOfDetector_perRing){
0284 for (G4int m_module = 0; m_module < numberOfRings; m_module++){
0285
0286
0287 moduleTime[blockID + (m_module - r_ring)*numberOfDetector_perRing] = timeStamp;
0288 }
0289 }
0290 }
0291 }
0292 else return;
0293
0294
0295
0296
0297 if(totalEdep>lowerThreshold && totalEdep<upperThreshold ){
0298
0299
0300 DOI_ID = G4int(crystalID/(numberOfCrystal_tangential * numberOfCrystal_axial));
0301
0302
0303 crystalID_2D = crystalID - (DOI_ID*numberOfCrystal_tangential * numberOfCrystal_axial);
0304
0305
0306 crystalID_axial = crystalID_2D/numberOfCrystal_axial;
0307 crystalID_tangential = crystalID_2D%numberOfCrystal_tangential;
0308
0309 intPosX = interactionPos.x();
0310 intPosY = interactionPos.y();
0311 intPosZ = interactionPos.z();
0312
0313
0314 if(ApplyAngerLogic){
0315
0316 AngerLogic(intPosX, intPosY, intPosZ, totalEdep, shiftCoeff, isDOIlookUpTablePrepared);
0317 }
0318
0319
0320 if(getSinglesData) WriteOutput();
0321
0322
0323 if(getCoincidenceData){
0324 eventID_coin.push_back(eventID);
0325 blockID_coin.push_back(blockID);
0326 cryID_axial_coin.push_back(crystalID_axial);
0327 cryID_tan_coin.push_back(crystalID_tangential);
0328 edep_coin.push_back(totalEdep);
0329 cryDOI_coin.push_back(DOI_ID);
0330 time_coin.push_back(timeStamp);
0331
0332 numberOfHit++;
0333
0334 if(numberOfHit == 2){
0335 WriteOutput();
0336 ResetNumberOfHits();
0337 }
0338 }
0339 }
0340 }
0341
0342
0343
0344
0345 void doiPETAnalysis::ResetNumberOfHits()
0346 {
0347 numberOfHit = 0;
0348 eventID_coin.clear();
0349 blockID_coin.clear();
0350 cryID_axial_coin.clear();
0351 cryID_tan_coin.clear();
0352 edep_coin.clear();
0353 cryDOI_coin.clear();
0354 time_coin.clear();
0355
0356 }
0357
0358
0359 void doiPETAnalysis::Open(G4String fileName)
0360 {
0361 if(getSinglesData){
0362 asciiFileName = fileName + "Singles.data";
0363 rootFileName = fileName+"Singles.root";
0364 }
0365 if(getCoincidenceData){
0366 asciiFileName = fileName + "Coincidence.data";
0367 rootFileName = fileName+"Coincidence.root";
0368 }
0369
0370 ofs.open(asciiFileName.c_str());
0371 if(!ofs.is_open()){
0372 G4cerr<<"=== \n File opening Error to write the output ===="<<G4endl;
0373 exit(0);
0374 }
0375
0376 }
0377
0378 void doiPETAnalysis::WriteOutput(){
0379 if(getSinglesData){
0380 ofs<<eventID<<" "<<blockID<<" "<<std::setprecision(17)<<timeStamp/s<<" "<<std::setprecision(7)<<totalEdep/keV<<" "<<intPosX<<" "<<intPosY<<" "<<intPosZ<<" "<<spositionX<<" "<<spositionY<<" "<<spositionZ<<G4endl;
0381
0382
0383 }
0384 if(getCoincidenceData){
0385
0386 for(G4int i=0; i<2; i++){
0387
0388
0389 if(i==0){
0390 eventID0 = eventID_coin[0];
0391 blockID0 = blockID_coin[0];
0392 crystalID_axial0 = cryID_axial_coin[0];
0393 crystalID_tangential0 = cryID_tan_coin[0];
0394 DOI_ID0 = cryDOI_coin[0];
0395 timeStamp0 = time_coin[0];
0396 totalEdep0 = edep_coin[0];
0397 }
0398 if(i==1){
0399
0400 eventID1 = eventID_coin[1];
0401 blockID1 = blockID_coin[1];
0402 crystalID_axial1 = cryID_axial_coin[1];
0403 crystalID_tangential1 = cryID_tan_coin[1];
0404 DOI_ID1 = cryDOI_coin[1];
0405 timeStamp1 = time_coin[1];
0406 totalEdep1 = edep_coin[1];
0407 }
0408 }
0409
0410 ofs<<eventID0<<" "<<blockID0<<" "<<crystalID_axial0<<" "<<crystalID_tangential0<<" "<<DOI_ID0<<" "<<std::setprecision(17)<<timeStamp0/s<<" "<<std::setprecision(7)<<totalEdep0/keV<<" "
0411 <<eventID1<<" "<<blockID1<<" "<<crystalID_axial1<<" "<<crystalID_tangential1<<" "<<DOI_ID1<<" "<<std::setprecision(17)<<timeStamp1/s<<" "<<std::setprecision(7)<<totalEdep1/keV<<" "
0412 <<spositionX<<" "<<spositionY<<" "<<spositionZ<<G4endl;
0413
0414 }
0415 #ifdef ANALYSIS_USE
0416 FillListModeEvent();
0417 #endif
0418
0419 }
0420
0421
0422
0423 void doiPETAnalysis::Close()
0424 {
0425
0426 ofs.close();
0427
0428 }
0429
0430
0431
0432
0433
0434
0435 void doiPETAnalysis::PMTPosition(){
0436
0437 sizeOfDetector_DOI = (numberOfCrystal_DOI * sizeOfCrystal_DOI) + (numberOfCrystal_DOI - 1)*crystalGap_DOI;
0438 sizeOfDetector_axial = (numberOfCrystal_axial * sizeOfCrystal_axial) + (numberOfCrystal_axial - 1)*crystalGap_axial;
0439 sizeOfDetector_tangential = (numberOfCrystal_tangential * sizeOfCrystal_tangential) + (numberOfCrystal_tangential - 1)*crystalGap_tangential;
0440
0441
0442 posPMT1x = sizeOfDetector_DOI/2;
0443 posPMT1y = -sizeOfDetector_tangential/2;
0444 posPMT1z = -sizeOfDetector_axial/2;
0445
0446
0447 posPMT2x = sizeOfDetector_DOI/2;
0448 posPMT2y = sizeOfDetector_tangential/2;
0449 posPMT2z = -sizeOfDetector_axial/2;
0450
0451
0452 posPMT3x = sizeOfDetector_DOI/2;
0453 posPMT3y = -sizeOfDetector_tangential/2;
0454 posPMT3z = sizeOfDetector_axial/2;
0455
0456
0457 posPMT4x = sizeOfDetector_DOI/2;
0458 posPMT4y = sizeOfDetector_tangential/2;
0459 posPMT4z = sizeOfDetector_axial/2;
0460
0461 G4cout<<"PMT positions: "<<G4endl;
0462 G4cout<<"PMT1 (mm) ("<<posPMT1x<<", "<<posPMT1y<<", "<<posPMT1z<<")"<<G4endl;
0463 G4cout<<"PMT2 (mm) ("<<posPMT2x<<", "<<posPMT2y<<", "<<posPMT2z<<")"<<G4endl;
0464 G4cout<<"PMT3 (mm) ("<<posPMT3x<<", "<<posPMT3y<<", "<<posPMT3z<<")"<<G4endl;
0465 G4cout<<"PMT4 (mm) ("<<posPMT4x<<", "<<posPMT4y<<", "<<posPMT4z<<")"<<G4endl;
0466
0467 }
0468
0469
0470 void doiPETAnalysis::BlurringParameters(){
0471 char inputChar[256];
0472 std::string inputLine;
0473 G4String value[7];
0474 std::string filename = "inputParameter.txt";
0475 ifs.open(filename.c_str());
0476 if(!ifs.good()){
0477 G4cerr<<"File opening Error: Could not open "<<filename<<G4endl;
0478 exit(0);
0479 }
0480 while(!ifs.eof()){
0481 ifs.getline(inputChar,256);
0482 inputLine = inputChar;
0483 if(inputChar[0]!='#' && inputLine.length()!=0 ){
0484 if( (std::string::size_type)inputLine.find("block_DeadTime:")!=std::string::npos){
0485 std::istringstream tmpStream(inputLine);
0486 tmpStream >> value[0] >> value[1] >> value[2];
0487 block_DeadTime = atof(value[1].c_str());
0488 if(value[2] != "ns"){
0489 G4cerr<<" Dead time unit is not in nano seconds (ns), Make it in 'ns' "<<G4endl;
0490 exit(0);
0491 }
0492 block_DeadTime = block_DeadTime*ns;
0493 G4cout<<"Dead time of the detector: "<<block_DeadTime <<" ns."<<G4endl;
0494 }
0495 if( (std::string::size_type)inputLine.find("module_DeadTime:")!=std::string::npos){
0496 std::istringstream tmpStream(inputLine);
0497 tmpStream >> value[0] >> value[1] >> value[2];
0498 module_DeadTime = atof(value[1].c_str());
0499 if(value[2] != "ns"){
0500 G4cerr<<" Dead time unit is not in nano seconds (ns), Make it in 'ns' "<<G4endl;
0501 exit(0);
0502 }
0503 module_DeadTime = module_DeadTime*ns;
0504 G4cout<<"Dead time of the module (axially multiplexed detectors): "<<module_DeadTime <<" ns."<<G4endl;
0505 }
0506
0507 if( (std::string::size_type)inputLine.find("crystalResolutionMin:")!=std::string::npos){
0508 std::istringstream tmpStream(inputLine);
0509 tmpStream >> value[0] >> value[1];
0510 crystalResolutionMin = atof(value[1].c_str());
0511 G4cout<<"crystal Resolution (Min.): "<<crystalResolutionMin*100<< " %." <<G4endl;
0512 }
0513 if( (std::string::size_type)inputLine.find("crystalResolutionMax:")!=std::string::npos){
0514 std::istringstream tmpStream(inputLine);
0515 tmpStream >> value[0] >> value[1];
0516 crystalResolutionMax = atof(value[1].c_str());
0517 G4cout<<"crystal Resolution (Max.): "<<crystalResolutionMax*100<<" %"<<G4endl;
0518 }
0519
0520
0521 if( (std::string::size_type)inputLine.find("fixedResolution:")!=std::string::npos){
0522 std::istringstream tmpStream(inputLine);
0523 tmpStream >> value[0] >> value[1];
0524 if(value[1]=="true"){
0525 fixedResolution = true;
0526 energyResolution_fixed = (crystalResolutionMin + crystalResolutionMax)*0.5;
0527 G4cout<<"Fixed crystal resolution is used. "<<G4endl;
0528 }
0529 else {
0530 fixedResolution = false;
0531
0532 std::string fname = "crystalDependentResolution.txt";
0533 std::ofstream outFname(fname.c_str());
0534
0535 G4cout<<" \n Crystal dependent resolution is used. preparing look-up table .... "<<G4endl;
0536 energyResolution_cryDependent.resize(numberOfBlocks_total,std::vector<G4double>(numberOfCrystal_tangential*numberOfCrystal_axial*numberOfCrystal_DOI,0));
0537 for(G4int i_blk = 0; i_blk < numberOfBlocks_total; i_blk++){
0538 for(G4int i_cry = 0; i_cry < numberOfCrystal_tangential*numberOfCrystal_axial*numberOfCrystal_DOI; i_cry++){
0539 energyResolution_cryDependent[i_blk][i_cry] = crystalResolutionMin + (crystalResolutionMax - crystalResolutionMin)*G4UniformRand();
0540
0541 outFname<<i_blk<<" "<<i_cry<<" "<<energyResolution_cryDependent[i_blk][i_cry]<<G4endl;
0542 }
0543 }
0544 G4cout<<"Done. \n"<<G4endl;
0545 outFname.close();
0546 }
0547
0548 }
0549
0550
0551 if( (std::string::size_type)inputLine.find("crystalEnergyRef:")!=std::string::npos){
0552 std::istringstream tmpStream(inputLine);
0553 tmpStream >> value[0] >> value[1] >> value[2];
0554 crystalEnergyRef = atof(value[1].c_str());
0555 if(value[2] != "keV"){
0556 G4cerr<<" The unit of reference energy is not in keV, Make it in 'keV' "<<G4endl;
0557 exit(0);
0558 }
0559 crystalEnergyRef = crystalEnergyRef*keV;
0560 G4cout<<"Energy of refernce: "<<crystalEnergyRef/keV<<" keV."<<G4endl;
0561 }
0562 if( (std::string::size_type)inputLine.find("crystalQuantumEfficiency:")!=std::string::npos){
0563 std::istringstream tmpStream(inputLine);
0564 tmpStream >> value[0] >> value[1];
0565 crystalQuantumEfficiency = atof(value[1].c_str());
0566 G4cout<<"Quantum Efficiency "<<crystalQuantumEfficiency*100<< " % "<<G4endl;
0567 }
0568 if( (std::string::size_type)inputLine.find("lowerThreshold:")!=std::string::npos){
0569 std::istringstream tmpStream(inputLine);
0570 tmpStream >> value[0] >> value[1] >> value[2];
0571 lowerThreshold = atof(value[1].c_str());
0572 if(value[2] != "keV"){
0573 G4cerr<<" The unit of Lower energy threshold is not in keV, Make it in 'keV' "<<G4endl;
0574 exit(0);
0575 }
0576 lowerThreshold = lowerThreshold*keV;
0577 G4cout<<"Lower energy threshold: "<<lowerThreshold/keV<<" keV."<<G4endl;
0578
0579 }
0580 if( (std::string::size_type)inputLine.find("upperThreshold:")!=std::string::npos){
0581 std::istringstream tmpStream(inputLine);
0582 tmpStream >> value[0] >> value[1] >> value[2];
0583 upperThreshold = atof(value[1].c_str());
0584 if(value[2] != "keV"){
0585 G4cerr<<" The unit of Upper energy threshold is not in keV, Make it in 'keV' "<<G4endl;
0586 exit(0);
0587 }
0588 upperThreshold = upperThreshold*keV;
0589 G4cout<<"Upper energy threshold: "<<upperThreshold/keV<<" keV."<<G4endl;
0590
0591 }
0592
0593
0594 if( (std::string::size_type)inputLine.find("triggerEnergy:")!=std::string::npos){
0595 std::istringstream tmpStream(inputLine);
0596 tmpStream >> value[0] >> value[1] >> value[2];
0597 triggerEnergy = atof(value[1].c_str());
0598 if(value[2] != "keV"){
0599 G4cerr<<" The unit of Trigger energy threshold is not in keV, Make it in 'keV' "<<G4endl;
0600 exit(0);
0601 }
0602 triggerEnergy = triggerEnergy*keV;
0603 G4cout<<"Trigger energy threshold: "<<triggerEnergy/keV<<" keV."<<G4endl;
0604
0605 }
0606
0607
0608 if( (std::string::size_type)inputLine.find("ApplyAngerLogic:")!=std::string::npos){
0609 std::istringstream tmpStream(inputLine);
0610 tmpStream >> value[0] >> value[1];
0611 if(value[1]=="true"){
0612 ApplyAngerLogic = true;
0613 G4cout<<"Angler Logic calculation is applied. "<<G4endl;
0614 }
0615 else if(value[1]=="false") {
0616 ApplyAngerLogic = false;
0617 G4cout<<"Angler Logic calculation is NOT applied. "<<G4endl;
0618 }
0619 else {
0620 ApplyAngerLogic = true;
0621 G4cout<<"Angler Logic calculation is applied (by defualt). "<<G4endl;
0622 }
0623 }
0624
0625
0626 if( (std::string::size_type)inputLine.find("PMTblurring:")!=std::string::npos){
0627 std::istringstream tmpStream(inputLine);
0628 tmpStream >> value[0] >> value[1]>>value[2];
0629 PMTblurring_tan = atof(value[1].c_str());
0630 PMTblurring_axial = atof(value[2].c_str());
0631 G4cout<<"PMTblurring position response blurring at FWHM (tan x axial) "<<PMTblurring_tan<<" x " <<PMTblurring_axial<<" mm2"<<G4endl;
0632 }
0633
0634
0635 if( (std::string::size_type)inputLine.find("TypeOfOutput:")!=std::string::npos){
0636 std::istringstream tmpStream(inputLine);
0637 tmpStream >> value[0] >> value[1];
0638 if(value[1]=="singlesOutput"){
0639 getSinglesData = true;
0640 G4cout<<"Single mode output enabled. "<<G4endl;
0641 }
0642 else if(value[1]=="coincidenceOutput") {
0643 getCoincidenceData = true;
0644 G4cout<<"Coicidence mode output enabled. "<<G4endl;
0645 }
0646
0647 }
0648
0649 }
0650 }
0651 ifs.close();
0652 }
0653
0654
0655
0656
0657
0658
0659 void doiPETAnalysis::ReadReflectorPattern(){
0660 G4cout<<" Reflector pattern is being read "<<G4endl;
0661
0662 std::vector<std::string> stringReflectorValue;
0663
0664 char inputChar[256];
0665 std::string inputLine;
0666
0667
0668 std::string filename = "inputParameter.txt";
0669
0670 G4String refValue;
0671
0672 ifs.open(filename.c_str());
0673 if(!ifs.good()){
0674 G4cerr<<"File opening Error: Could not open "<<filename<<G4endl;
0675 exit(0);
0676 }
0677 while(!ifs.eof()){
0678 ifs.getline(inputChar,256);
0679 inputLine = inputChar;
0680
0681
0682 if(inputChar[0]!='#' && inputLine.length()!=0 ){
0683
0684
0685 if( (std::string::size_type)inputLine.find("reflectorLayer1_Tangential:")!=std::string::npos){
0686 std::istringstream tmpStream(inputLine);
0687 while(tmpStream >> refValue){
0688 stringReflectorValue.push_back(refValue);
0689 if(stringReflectorValue.size()>1){
0690 G4int tmp_value = atoi(stringReflectorValue[stringReflectorValue.size()-1].c_str());
0691 ireflectorLayer1_Tangential.push_back(tmp_value);
0692 }
0693 }
0694 stringReflectorValue.clear();
0695 }
0696
0697
0698
0699 if( (std::string::size_type)inputLine.find("reflectorLayer1_Axial:")!=std::string::npos){
0700 std::istringstream tmpStream(inputLine);
0701 while(tmpStream >> refValue){
0702 stringReflectorValue.push_back(refValue);
0703 if(stringReflectorValue.size()>1){
0704 G4int tmp_value = atoi(stringReflectorValue[stringReflectorValue.size()-1].c_str());
0705 ireflectorLayer1_Axial.push_back(tmp_value);
0706 }
0707 }
0708 stringReflectorValue.clear();
0709 }
0710
0711
0712 if( (std::string::size_type)inputLine.find("reflectorLayer2_Tangential:")!=std::string::npos){
0713 std::istringstream tmpStream(inputLine);
0714 while(tmpStream >> refValue){
0715 stringReflectorValue.push_back(refValue);
0716 if(stringReflectorValue.size()>1){
0717 G4int tmp_value = atoi(stringReflectorValue[stringReflectorValue.size()-1].c_str());
0718 ireflectorLayer2_Tangential.push_back(tmp_value);
0719 }
0720 }
0721 stringReflectorValue.clear();
0722 }
0723
0724
0725 if( (std::string::size_type)inputLine.find("reflectorLayer2_Axial:")!=std::string::npos){
0726 std::istringstream tmpStream(inputLine);
0727 while(tmpStream >> refValue){
0728 stringReflectorValue.push_back(refValue);
0729 if(stringReflectorValue.size()>1){
0730 G4int tmp_value = atoi(stringReflectorValue[stringReflectorValue.size()-1].c_str());
0731 ireflectorLayer2_Axial.push_back(tmp_value);
0732 }
0733 }
0734 stringReflectorValue.clear();
0735 }
0736
0737
0738 if( (std::string::size_type)inputLine.find("reflectorLayer3_Tangential:")!=std::string::npos){
0739 std::istringstream tmpStream(inputLine);
0740 while(tmpStream >> refValue){
0741 stringReflectorValue.push_back(refValue);
0742 if(stringReflectorValue.size()>1){
0743 G4int tmp_value = atoi(stringReflectorValue[stringReflectorValue.size()-1].c_str());
0744 ireflectorLayer3_Tangential.push_back(tmp_value);
0745 }
0746 }
0747 stringReflectorValue.clear();
0748 }
0749
0750
0751 if( (std::string::size_type)inputLine.find("reflectorLayer3_Axial:")!=std::string::npos){
0752 std::istringstream tmpStream(inputLine);
0753 while(tmpStream >> refValue){
0754 stringReflectorValue.push_back(refValue);
0755 if(stringReflectorValue.size()>1){
0756 G4int tmp_value = atoi(stringReflectorValue[stringReflectorValue.size()-1].c_str());
0757 ireflectorLayer3_Axial.push_back(tmp_value);
0758 }
0759 }
0760 stringReflectorValue.clear();
0761 }
0762
0763
0764 if( (std::string::size_type)inputLine.find("reflectorLayer4_Tangential:")!=std::string::npos){
0765 std::istringstream tmpStream(inputLine);
0766 while(tmpStream >> refValue){
0767 stringReflectorValue.push_back(refValue);
0768 if(stringReflectorValue.size()>1){
0769 G4int tmp_value = atoi(stringReflectorValue[stringReflectorValue.size()-1].c_str());
0770 ireflectorLayer4_Tangential.push_back(tmp_value);
0771 }
0772 }
0773 stringReflectorValue.clear();
0774 }
0775
0776
0777 if( (std::string::size_type)inputLine.find("reflectorLayer4_Axial:")!=std::string::npos){
0778 std::istringstream tmpStream(inputLine);
0779 while(tmpStream >> refValue){
0780 stringReflectorValue.push_back(refValue);
0781 if(stringReflectorValue.size()>1){
0782 G4int tmp_value = atoi(stringReflectorValue[stringReflectorValue.size()-1].c_str());
0783 ireflectorLayer4_Axial.push_back(tmp_value);
0784 }
0785 }
0786 stringReflectorValue.clear();
0787 }
0788 }
0789 }
0790
0791
0792
0793 G4cout<<"\n========= Reflector Pattern ==========="<<G4endl;
0794 G4cout<<"Layer 1"<<G4endl;
0795 for(unsigned int i = 0; i<ireflectorLayer1_Tangential.size();i++){
0796 G4cout<<ireflectorLayer1_Tangential[i]<<" ";
0797 }G4cout<<G4endl;
0798 for(unsigned int i = 0; i<ireflectorLayer1_Axial.size();i++){
0799 G4cout<<ireflectorLayer1_Axial[i]<<" ";
0800 }G4cout<<G4endl;
0801 G4cout<<"Layer 2"<<G4endl;
0802 for(unsigned int i = 0; i<ireflectorLayer2_Tangential.size();i++){
0803 G4cout<<ireflectorLayer2_Tangential[i]<<" ";
0804 }G4cout<<G4endl;
0805 for(unsigned int i = 0; i<ireflectorLayer2_Axial.size();i++){
0806 G4cout<<ireflectorLayer2_Axial[i]<<" ";
0807 }G4cout<<G4endl;
0808 G4cout<<"Layer 3"<<G4endl;
0809 for(unsigned int i = 0; i<ireflectorLayer3_Tangential.size();i++){
0810 G4cout<<ireflectorLayer3_Tangential[i]<<" ";
0811 }G4cout<<G4endl;
0812 for(unsigned int i = 0; i<ireflectorLayer3_Axial.size();i++){
0813 G4cout<<ireflectorLayer3_Axial[i]<<" ";
0814 }G4cout<<G4endl;
0815 G4cout<<"Layer 4"<<G4endl;
0816 for(unsigned int i = 0; i<ireflectorLayer4_Tangential.size();i++){
0817 G4cout<<ireflectorLayer4_Tangential[i]<<" ";
0818 }G4cout<<G4endl;
0819 for(unsigned int i = 0; i<ireflectorLayer4_Axial.size();i++){
0820 G4cout<<ireflectorLayer4_Axial[i]<<" ";
0821 }G4cout<<G4endl;
0822 G4cout<<"========= Reflector Pattern Ended ===========\n"<<G4endl;
0823
0824
0825 G4int index_doi = 0, doiID;
0826 doi_table.resize(numberOfCrystal_tangential*numberOfCrystal_axial*numberOfCrystal_DOI,0);
0827
0828 std::string LUT_FileName = "look_up_table_DOI.txt";
0829 std::ifstream ifs_doiLUT;
0830 std::ofstream ofs_doiLUT;
0831 ifs_doiLUT.open(LUT_FileName.c_str());
0832 if(ifs_doiLUT.is_open()){
0833 G4cout<<" DOI Look-up table found and used: File name: "<<LUT_FileName<<G4endl;
0834
0835 while(ifs_doiLUT>>index_doi>>doiID && index_doi < int(doi_table.size())){
0836 doi_table[index_doi] = doiID;
0837 }
0838 if(index_doi==int(doi_table.size())){
0839 G4cout<<"!!!Warning: The DOI table index is greater than the total number of crystals."<<G4endl;
0840 PrepareDOILookUpTable(LUT_FileName);
0841 }
0842 isDOIlookUpTablePrepared = true;
0843 }
0844 else
0845 {
0846 PrepareDOILookUpTable(LUT_FileName);
0847 }
0848
0849 ofs_doiLUT.open(LUT_FileName.c_str());
0850 if(!ofs_doiLUT.is_open()){
0851 G4cerr<<"Unable to open file to write doi_LUT"<<G4endl;
0852 exit(0);
0853 }
0854 for(G4int i=0;i<int(doi_table.size()); i++){
0855 ofs_doiLUT<<i<<"\t"<<doi_table[i]<<G4endl;
0856 }
0857 ifs_doiLUT.close();
0858
0859
0860 ifs.close();
0861 }
0862 void doiPETAnalysis::PrepareDOILookUpTable(G4String){
0863 isDOIlookUpTablePrepared = false;
0864 G4cout<<"Preparing DOI look-up table... "<<G4endl;
0865 std::string outputFileName = "_check_2Dposition.txt";
0866 std::ofstream outFile(outputFileName.c_str());
0867
0868 G4double crystalPositionX;
0869 G4double crystalPositionY;
0870 G4double crystalPositionZ;
0871
0872
0873 for(G4int i_DOI = 0; i_DOI<numberOfCrystal_DOI; i_DOI++){
0874 crystalPositionX=(i_DOI-((float)numberOfCrystal_DOI)/2 + 0.5)*(sizeOfCrystal_DOI + crystalGap_DOI);
0875 for(G4int i_axial=0; i_axial< numberOfCrystal_axial;i_axial++){
0876 crystalPositionZ = (i_axial-((float)numberOfCrystal_axial)/2 + 0.5)*(sizeOfCrystal_axial + crystalGap_axial);
0877 for(G4int i_tan=0; i_tan<numberOfCrystal_tangential;i_tan++){
0878 crystalPositionY=(i_tan-((float)numberOfCrystal_tangential)/2 + 0.5)*(sizeOfCrystal_tangential + crystalGap_tangential);
0879 AngerLogic(crystalPositionX, crystalPositionY, crystalPositionZ, 1, 0.5, isDOIlookUpTablePrepared);
0880 outFile<<PositionAngerZ<<" "<<PositionAngerY<<G4endl;
0881 doi_table[crystalID_in2D_posHist]=i_DOI;
0882
0883 }
0884 }
0885 }
0886 G4cout<<"done."<<G4endl;
0887 isDOIlookUpTablePrepared = true;
0888 }
0889
0890
0891
0892
0893
0894
0895 void doiPETAnalysis::AngerLogic(G4double posCrystalX, G4double posCrystalY, G4double posCrystalZ, G4double Edep, G4double shiftDis, G4bool isDOI_LUT)
0896 {
0897 G4double crystalPitch_DOI = sizeOfCrystal_DOI + crystalGap_DOI;
0898 G4double crystalPitch_tan = sizeOfCrystal_tangential + crystalGap_tangential;
0899 G4double crystalPitch_axial = sizeOfCrystal_axial + crystalGap_axial;
0900
0901
0902 G4int i_doi = posCrystalX/crystalPitch_DOI + (float)numberOfCrystal_DOI*0.5;
0903 G4int i_tan = posCrystalY/crystalPitch_tan + (float)numberOfCrystal_tangential*0.5;
0904 G4int i_axial = posCrystalZ/crystalPitch_axial + (float)numberOfCrystal_axial*0.5;
0905
0906
0907 posCrystalX = (i_doi-((float)numberOfCrystal_DOI)/2 + 0.5)*crystalPitch_DOI;
0908 posCrystalY = (i_tan-((float)numberOfCrystal_tangential)/2 + 0.5)*crystalPitch_tan;
0909 posCrystalZ = (i_axial-((float)numberOfCrystal_axial)/2 + 0.5)*crystalPitch_axial;
0910
0911
0912
0913
0914
0915
0916
0917 dist1z = std::fabs(posPMT1z - posCrystalZ);
0918 dist2z = std::fabs(posPMT2z - posCrystalZ);
0919 dist3z = std::fabs(posPMT3z - posCrystalZ);
0920 dist4z = std::fabs(posPMT4z - posCrystalZ);
0921
0922
0923
0924
0925 distz = dist1z + dist3z;
0926
0927
0928
0929 dist1y = std::fabs(posPMT1y - posCrystalY);
0930 dist2y = std::fabs(posPMT2y - posCrystalY);
0931 dist3y = std::fabs(posPMT3y - posCrystalY);
0932 dist4y = std::fabs(posPMT4y - posCrystalY);
0933
0934
0935
0936
0937 disty = dist1y + dist2y;
0938
0939
0940 signalPMT1z = Edep * dist3z/(dist1z + dist3z);
0941 signalPMT3z = Edep * dist1z/(dist1z + dist3z);
0942
0943 signalPMT2z = Edep * dist4z/(dist2z + dist4z);
0944 signalPMT4z = Edep * dist2z/(dist2z + dist4z);
0945
0946
0947
0948 signalPMT1y = Edep * dist2y/(dist1y + dist2y);
0949 signalPMT2y = Edep * dist1y/(dist1y + dist2y);
0950
0951 signalPMT3y = Edep * dist4y/(dist3y + dist4y);
0952 signalPMT4y = Edep * dist3y/(dist3y + dist4y);
0953
0954
0955 signalPMT1 = (signalPMT1z + signalPMT1y)*0.5;
0956 signalPMT2 = (signalPMT2z + signalPMT2y)*0.5;
0957 signalPMT3 = (signalPMT3z + signalPMT3y)*0.5;
0958 signalPMT4 = (signalPMT4z + signalPMT4y)*0.5;
0959
0960
0961 signalZplus = (signalPMT3 + signalPMT4);
0962 signalZminus = (signalPMT1 + signalPMT2);
0963 signalYplus = (signalPMT2 + signalPMT4);
0964 signalYminus = (signalPMT1 + signalPMT3);
0965
0966
0967
0968
0969 PositionAngerZ = (signalZplus - signalZminus)/(signalZplus + signalZminus)*distz;
0970 PositionAngerY = (signalYplus - signalYminus)/(signalYplus + signalYminus)*disty;
0971
0972
0973
0974
0975
0976
0977
0978
0979
0980 if(i_doi == 0){
0981
0982 if(ireflectorLayer1_Tangential[i_tan] == 1 && ireflectorLayer1_Tangential[i_tan + 1] == 0) PositionAngerY += (crystalPitch_tan/2)*shiftDis;
0983
0984
0985 if(ireflectorLayer1_Tangential[i_tan] == 0 && ireflectorLayer1_Tangential[i_tan + 1] == 1) PositionAngerY -= (crystalPitch_tan/2)*shiftDis;
0986
0987 if(ireflectorLayer1_Axial[i_axial] == 1 && ireflectorLayer1_Axial [i_axial + 1] == 0) PositionAngerZ += (crystalPitch_axial/2)*shiftDis;
0988 if(ireflectorLayer1_Axial[i_axial] == 0 && ireflectorLayer1_Axial [i_axial + 1] == 1) PositionAngerZ -= (crystalPitch_axial/2)*shiftDis;
0989 }
0990 if(i_doi == 1){
0991 if(ireflectorLayer2_Tangential[i_tan] == 1 && ireflectorLayer2_Tangential[i_tan + 1] == 0) PositionAngerY += (crystalPitch_tan/2)*shiftDis;
0992 if(ireflectorLayer2_Tangential[i_tan] == 0 && ireflectorLayer2_Tangential[i_tan + 1] == 1) PositionAngerY -= (crystalPitch_tan/2)*shiftDis;
0993
0994 if(ireflectorLayer2_Axial[i_axial] == 1 && ireflectorLayer2_Axial [i_axial + 1] == 0) PositionAngerZ += (crystalPitch_axial/2)*shiftDis;
0995 if(ireflectorLayer2_Axial[i_axial] == 0 && ireflectorLayer2_Axial [i_axial + 1] == 1) PositionAngerZ -= (crystalPitch_axial/2)*shiftDis;
0996 }
0997 if(i_doi == 2){
0998 if(ireflectorLayer3_Tangential[i_tan] == 1 && ireflectorLayer3_Tangential[i_tan + 1] == 0) PositionAngerY += (crystalPitch_tan/2)*shiftDis;
0999 if(ireflectorLayer3_Tangential[i_tan] == 0 && ireflectorLayer3_Tangential[i_tan + 1] == 1) PositionAngerY -= (crystalPitch_tan/2)*shiftDis;
1000
1001 if(ireflectorLayer3_Axial[i_axial] == 1 && ireflectorLayer3_Axial [i_axial + 1] == 0) PositionAngerZ += (crystalPitch_axial/2)*shiftDis;
1002 if(ireflectorLayer3_Axial[i_axial] == 0 && ireflectorLayer3_Axial [i_axial + 1] == 1) PositionAngerZ -= (crystalPitch_axial/2)*shiftDis;
1003 }
1004 if(i_doi == 3){
1005 if(ireflectorLayer4_Tangential[i_tan] == 1 && ireflectorLayer4_Tangential[i_tan + 1] == 0) PositionAngerY += (crystalPitch_tan/2)*shiftDis;
1006 if(ireflectorLayer4_Tangential[i_tan] == 0 && ireflectorLayer4_Tangential[i_tan + 1] == 1) PositionAngerY -= (crystalPitch_tan/2)*shiftDis;
1007
1008 if(ireflectorLayer4_Axial[i_axial] == 1 && ireflectorLayer4_Axial [i_axial + 1] == 0) PositionAngerZ += (crystalPitch_axial/2)*shiftDis;
1009 if(ireflectorLayer4_Axial[i_axial] == 0 && ireflectorLayer4_Axial [i_axial + 1] == 1) PositionAngerZ -= (crystalPitch_axial/2)*shiftDis;
1010 }
1011
1012
1013 if(isDOI_LUT){
1014 PositionAngerZ = G4RandGauss::shoot(PositionAngerZ,PMTblurring_axial/2.35);
1015 PositionAngerY = G4RandGauss::shoot(PositionAngerY,PMTblurring_tan/2.35);
1016 }
1017
1018
1019
1020
1021 crystalID_in2D_posHist_axial = (G4int)(PositionAngerZ/(crystalPitch_axial*0.5) + (G4double)numberOfPixel_axial*0.5);
1022
1023
1024 crystalID_in2D_posHist_tan = (G4int)(PositionAngerY/(crystalPitch_tan*0.5) + (G4double)numberOfPixel_tan * 0.5);
1025
1026
1027 crystalID_in2D_posHist = crystalID_in2D_posHist_axial + crystalID_in2D_posHist_tan * numberOfPixel_tan;
1028
1029
1030
1031
1032
1033 crystalIDNew_tan = (G4int)(crystalID_in2D_posHist_tan/2);
1034
1035
1036 crystalIDNew_axial = (G4int)(crystalID_in2D_posHist_axial/2);
1037
1038
1039 if(crystalID_in2D_posHist>numberOfCrystal_tangential*numberOfCrystal_axial*numberOfCrystal_DOI) return;
1040 crystalIDNew_DOI = doi_table[crystalID_in2D_posHist];
1041
1042
1043 if(crystalIDNew_tan < 0 || crystalIDNew_axial < 0 || crystalIDNew_DOI < 0 ||
1044 crystalIDNew_tan >= numberOfCrystal_tangential || crystalIDNew_axial >= numberOfCrystal_axial || crystalIDNew_DOI >= numberOfCrystal_DOI){
1045 return;
1046 }
1047
1048 CrystalIDAfterAngerLogic(crystalIDNew_tan,crystalIDNew_axial,crystalIDNew_DOI);
1049 }
1050
1051
1052 void doiPETAnalysis::CrystalIDAfterAngerLogic(G4int i_tan, G4int i_axial, G4int i_doi){
1053 crystalID_tangential = i_tan;
1054 crystalID_axial = i_axial;
1055 DOI_ID = i_doi;
1056 }
1057
1058 void doiPETAnalysis::book()
1059 {
1060 auto manager = G4AnalysisManager::Instance();
1061
1062
1063
1064 G4bool fileOpen = manager->OpenFile(rootFileName);
1065 if (!fileOpen) {
1066 G4cout << "\n---> HistoManager::book(): cannot open "
1067 << rootFileName << G4endl;
1068 return;
1069 }
1070
1071
1072
1073 manager->SetFirstNtupleId(1);
1074
1075 if(getSinglesData){
1076 manager -> CreateNtuple("Singles", "Singles");
1077 fNtColId[0] = manager -> CreateNtupleIColumn("eventID");
1078 fNtColId[1] = manager -> CreateNtupleIColumn("blockID");
1079
1080
1081
1082 fNtColId[2] = manager -> CreateNtupleDColumn("timeStamp");
1083 fNtColId[3] = manager -> CreateNtupleDColumn("totalEdep");
1084
1085
1086 fNtColId[4] = manager -> CreateNtupleDColumn("intPosX");
1087 fNtColId[5] = manager -> CreateNtupleDColumn("intPosY");
1088 fNtColId[6] = manager -> CreateNtupleDColumn("intPosZ");
1089
1090
1091 fNtColId[7] = manager -> CreateNtupleDColumn("spositionX");
1092 fNtColId[8] = manager -> CreateNtupleDColumn("spositionY");
1093 fNtColId[9] = manager -> CreateNtupleDColumn("spositionZ");
1094
1095 manager -> FinishNtuple();
1096 }
1097 if(getCoincidenceData){
1098 manager -> CreateNtuple("Coincidence", "Coincidence");
1099 fNtColId[0] = manager -> CreateNtupleIColumn("eventID0");
1100 fNtColId[1] = manager -> CreateNtupleIColumn("blockID0");
1101 fNtColId[2] = manager -> CreateNtupleIColumn("crystalID_axial0");
1102 fNtColId[3] = manager -> CreateNtupleIColumn("crystalID_tangential0");
1103 fNtColId[4] = manager -> CreateNtupleIColumn("DOI_ID0");
1104 fNtColId[5] = manager -> CreateNtupleDColumn("timeStamp0");
1105 fNtColId[6] = manager -> CreateNtupleDColumn("totalEdep0");
1106
1107 fNtColId[7] = manager -> CreateNtupleIColumn("eventID1");
1108 fNtColId[8] = manager -> CreateNtupleIColumn("blockID1");
1109 fNtColId[9] = manager -> CreateNtupleIColumn("crystalID_axial1");
1110 fNtColId[10] = manager -> CreateNtupleIColumn("crystalID_tangential1");
1111 fNtColId[11] = manager -> CreateNtupleIColumn("DOI_ID1");
1112 fNtColId[12] = manager -> CreateNtupleDColumn("timeStamp1");
1113 fNtColId[13] = manager -> CreateNtupleDColumn("totalEdep1");
1114
1115
1116 fNtColId[14] = manager -> CreateNtupleDColumn("spositionX");
1117 fNtColId[15] = manager -> CreateNtupleDColumn("spositionY");
1118 fNtColId[16] = manager -> CreateNtupleDColumn("spositionZ");
1119
1120 manager -> FinishNtuple();
1121
1122 }
1123
1124
1125 factoryOn = true;
1126 }
1127 void doiPETAnalysis::FillListModeEvent()
1128 {
1129
1130 auto manager = G4AnalysisManager::Instance();
1131 if(getSinglesData){
1132 manager -> FillNtupleIColumn(1, fNtColId[0], G4int(eventID));
1133 manager -> FillNtupleIColumn(1, fNtColId[1], G4int(blockID));
1134
1135
1136
1137 manager -> FillNtupleDColumn(1, fNtColId[2], timeStamp/s);
1138 manager -> FillNtupleDColumn(1, fNtColId[3], totalEdep/keV);
1139
1140
1141 manager -> FillNtupleDColumn(1, fNtColId[4], intPosX);
1142 manager -> FillNtupleDColumn(1, fNtColId[5], intPosY);
1143 manager -> FillNtupleDColumn(1, fNtColId[6], intPosZ);
1144
1145
1146
1147 manager -> FillNtupleDColumn(1, fNtColId[7], spositionX);
1148 manager -> FillNtupleDColumn(1, fNtColId[8], spositionY);
1149 manager -> FillNtupleDColumn(1, fNtColId[9], spositionZ);
1150
1151 manager -> AddNtupleRow(1);
1152 }
1153
1154 if(getCoincidenceData){
1155
1156 manager -> FillNtupleIColumn(1, fNtColId[0], eventID0);
1157 manager -> FillNtupleIColumn(1, fNtColId[1], blockID0);
1158 manager -> FillNtupleIColumn(1, fNtColId[2], crystalID_axial0);
1159 manager -> FillNtupleIColumn(1, fNtColId[3], crystalID_tangential0);
1160 manager -> FillNtupleIColumn(1, fNtColId[4], DOI_ID0);
1161 manager -> FillNtupleDColumn(1, fNtColId[5], timeStamp0/s);
1162 manager -> FillNtupleDColumn(1, fNtColId[6], totalEdep0/keV);
1163
1164
1165 manager -> FillNtupleIColumn(1, fNtColId[7], eventID1);
1166 manager -> FillNtupleIColumn(1, fNtColId[8], blockID1);
1167 manager -> FillNtupleIColumn(1, fNtColId[9], crystalID_axial1);
1168 manager -> FillNtupleIColumn(1, fNtColId[10], crystalID_tangential1);
1169 manager -> FillNtupleIColumn(1, fNtColId[11], DOI_ID1);
1170 manager -> FillNtupleDColumn(1, fNtColId[12], timeStamp1/s);
1171 manager -> FillNtupleDColumn(1, fNtColId[13], totalEdep1/keV);
1172
1173
1174 manager -> FillNtupleDColumn(1, fNtColId[14], spositionX);
1175 manager -> FillNtupleDColumn(1, fNtColId[15], spositionY);
1176 manager -> FillNtupleDColumn(1, fNtColId[16], spositionZ);
1177
1178 manager -> AddNtupleRow(1);
1179 }
1180
1181 }
1182 void doiPETAnalysis::finish()
1183 {
1184 if (factoryOn)
1185 {
1186 auto manager = G4AnalysisManager::Instance();
1187 manager -> Write();
1188 manager -> CloseFile();
1189
1190
1191 factoryOn = false;
1192 }
1193 }