//*********************************************************************************************************** // BinToStd_ProtonAtExit.C // Root command file // Type: root BinToStd_ProtonAtExit.C // // Read the output file ProtonAtExit.dat that is generated by Geant4 tomography simulation // It reads proton at exit information, and rewrite the events in a binary file StimEvent_std.DAT // // More information is available in UserGuide // Created by Z.LI LP2i Bordeaux 2022 //*********************************************************************************************************** #include #include #include #include #include // using namespace std; // Define a structure to read and write each event in the required binary format struct StimEvent { uint16_t energy_keV; // different from Pixe Event, it is in keV uint16_t pixelIndex; uint16_t sliceIndex; uint8_t projectionIndex; }; struct ParticleInfo { float energy_keV; float mx; float my; float mz; }; struct RunInfo { // uint_16t uint8_t projectionIndex; // 1 byte uint16_t sliceIndex; // uint16_t pixelIndex; uint32_t nbParticle; // 4 bytes int }; struct Point { double m_x; double m_y; double m_z; }; bool IsDetected(Point poi1, Point poi2, double theta) { double a = (poi1.m_x * poi2.m_x + poi1.m_y * poi2.m_y + poi1.m_z * poi2.m_z) / sqrt(poi1.m_x * poi1.m_x + poi1.m_y * poi1.m_y + poi1.m_z * poi1.m_z) / sqrt(poi2.m_x * poi2.m_x + poi2.m_y * poi2.m_y + poi2.m_z * poi2.m_z); if (a > 1.0) a = 1; if (a < -1.0) a = -1; double r = acos(a); if (r > theta) return false; else return true; } void BinToStd_ProtonAtExit() { //*********************************************************************** //**************************Detection parameters (begin)**************** //*********************************************************************** const int nbProjection = 10; const int nbSlice = 1; const int nbPixel = 20; double totalAngleSpan = 180.; // in degree // angle of detector relative to the incident direction of the primary protons at first projection // for proton, it is fixed to 0 degree, namely opposite to the source double angleOfDetector = 0.; double distanceObjectDetector = 22.; // 22 mm double radiusOfDetector = 5.; // 5 mm // double theta = atan(radiusOfDetector/distanceObjectDetector); //half apex angle of the right // circular cone in radian double theta = 10.2 * TMath::DegToRad(); // in radian //*********************************************************************** //**************************Detection parameters (end)******************* //*********************************************************************** FILE* input = fopen("../build/ProtonAtExit.dat", "rb"); FILE* out = fopen("../build/StimEvent_std.DAT", "wb"); if (input == NULL) { printf("error for opening the input ProtonAtExit.dat file\n"); return; } RunInfo runInfo; StimEvent stimEvent; Point centerOfDetector; Point protonMomentum; long long count = 0; int runID = -1; // while(!feof(input)) //if not the end, read while (fread(&runInfo, sizeof(RunInfo), 1, input)) { runID++; int nbParticle = runInfo.nbParticle; //(begin)*************************************************************** // the following codes are used only when in the simulation // the index of projection, slice and pixel is not // correctly configured runInfo.projectionIndex = runID / (nbSlice * nbPixel); int remain = runID % (nbSlice * nbPixel); runInfo.sliceIndex = remain / nbPixel; runInfo.pixelIndex = remain % nbPixel; //(end)****************************************************************** //*********************************************************************** //**************************Print information (begin)******************** //*********************************************************************** printf("---------RunID=%d: ProjectionIndex=%d, SliceIndex=%d, PixelIndex=%d, nbParticle = %d\n", runID, runInfo.projectionIndex, runInfo.sliceIndex, runInfo.pixelIndex, nbParticle); //*********************************************************************** //**************************Print information (end)********************** //*********************************************************************** if (!nbParticle) continue; std::vector protonAtExit(nbParticle); fread(&protonAtExit[0], sizeof(ParticleInfo), nbParticle, input); // angleOfDetector+totalAngleSpan/nbProjection*runInfo.projectionIndex means the angle between // source direction and detector, which should be constant when source is rotating double ra = TMath::DegToRad() * (angleOfDetector + totalAngleSpan / nbProjection * runInfo.projectionIndex); centerOfDetector.m_x = distanceObjectDetector * cos(ra); centerOfDetector.m_y = distanceObjectDetector * sin(ra); centerOfDetector.m_z = 0; for (int i = 0; i < nbParticle; ++i) { // proton selection: energy should be lower than 4095 keV if (protonAtExit[i].energy_keV >= 4095) continue; // proton selection protonMomentum.m_x = protonAtExit[i].mx; protonMomentum.m_y = protonAtExit[i].my; protonMomentum.m_z = protonAtExit[i].mz; if (!IsDetected(centerOfDetector, protonMomentum, theta)) continue; else { stimEvent.energy_keV = floor(protonAtExit[i].energy_keV + 0.5); stimEvent.projectionIndex = runInfo.projectionIndex; stimEvent.sliceIndex = runInfo.sliceIndex; stimEvent.pixelIndex = runInfo.pixelIndex; fwrite(&stimEvent, 7, 1, out); count++; // printf("energy=%f keV\n",protonAtExit[i].energy_keV); } } } printf("---------------Number of StimEvent in total: %lld------------------------\n", count); fclose(input); fclose(out); // FILE* input2; // input2 = fopen("StimEvent_std.DAT","rb"); // StimEvent p; // double eventId = -1; // while(fread(&p, 7, 1, input2)) // { // if(p.projectionIndex == 8 &&p.sliceIndex ==64 && p.pixelIndex==64) // { // eventId++; // printf("StimEvent_%.0f ProjectionIndex=%d, SliceIndex=%d, PixelIndex=%d, Energy_keV=%d keV\n", // eventId, p.projectionIndex, p.sliceIndex, p.pixelIndex, p.energy_keV); // } // } // fclose(input2); }