53 #include <sys/types.h> 61 #define THRESHOLD 0.01 64 #define SIGN(x) ((x)>=0 ? 1:-1) 65 #define ONE_MINUS_COSZERO 1.0E-12 89 std::vector<Location>* recordedPhotonRoute =
new std::vector<Location>();
90 double* fluenceContribution;
91 double m_PhotonNormalizationValue;
92 long m_NumberPhotonsCurrent;
94 DetectorVoxel(Location location,
long totalNumberOfVoxels,
double photonNormalizationValue)
96 this->location = location;
97 this->fluenceContribution = (
double *)malloc(totalNumberOfVoxels *
sizeof(
double));
98 for (
int j = 0; j < totalNumberOfVoxels; j++) fluenceContribution[j] = 0;
99 m_NumberPhotonsCurrent = 0;
100 m_PhotonNormalizationValue = photonNormalizationValue;
111 long long ix, iy, iz;
113 int mcflag, launchflag, boundaryflag;
114 double xfocus, yfocus, zfocus;
115 double ux0, uy0, uz0;
119 int Nx, Ny, Nz, numberOfTissueTypes;
125 double* normalizationVector;
127 double xSpacing, ySpacing, zSpacing;
128 double simulationTimeFromFile;
130 long totalNumberOfVoxels;
131 double* totalFluence;
133 DetectorVoxel* detectorVoxel;
139 tissueType =
nullptr;
143 detectorVoxel =
nullptr;
144 normalizationVector =
nullptr;
151 double GetNormalizationValue(
int x,
int y,
int z)
153 if (normalizationVector)
154 return normalizationVector[z*Ny*Nx + x*Ny + y];
161 inputFilename = localInputFilename;
164 if (
verbose) std::cout <<
"Loading input image..." << std::endl;
165 m_inputImage = mitk::IOUtil::Load<mitk::Image>(
inputFilename);
166 if (
verbose) std::cout <<
"Loading input image... [Done]" << std::endl;
170 if (
verbose) std::cout <<
"No .nrrd file found ... switching to legacy mode." << std::endl;
175 if (simulatePVFC && !normalizationFilename.empty())
176 m_normalizationImage = mitk::IOUtil::Load<mitk::Image>(normalizationFilename);
180 if (
verbose) std::cout <<
"No normalization .nrrd file found ... will not normalize PVFC" << std::endl;
183 if (m_normalizationImage.IsNotNull())
186 normalizationVector = (
double *)readAccess3.
GetData();
189 if (m_inputImage.IsNotNull())
191 simulationTimeFromFile = 0;
193 Nx = m_inputImage->GetDimensions()[1];
194 Ny = m_inputImage->GetDimensions()[0];
195 Nz = m_inputImage->GetDimensions()[2];
197 xSpacing = m_inputImage->GetGeometry(0)->GetSpacing()[0];
198 ySpacing = m_inputImage->GetGeometry(0)->GetSpacing()[1];
199 zSpacing = m_inputImage->GetGeometry(0)->GetSpacing()[2];
201 mcflag = std::stoi(m_inputImage->GetProperty(
"mcflag")->GetValueAsString().c_str());
202 launchflag = std::stoi(m_inputImage->GetProperty(
"launchflag")->GetValueAsString().c_str());
203 boundaryflag = std::stoi(m_inputImage->GetProperty(
"boundaryflag")->GetValueAsString().c_str());
205 xs = std::stod(m_inputImage->GetProperty(
"launchPointX")->GetValueAsString().c_str());
206 ys = std::stod(m_inputImage->GetProperty(
"launchPointY")->GetValueAsString().c_str()) + yOffset;
207 zs = std::stod(m_inputImage->GetProperty(
"launchPointZ")->GetValueAsString().c_str());
209 xfocus = std::stod(m_inputImage->GetProperty(
"focusPointX")->GetValueAsString().c_str());
210 yfocus = std::stod(m_inputImage->GetProperty(
"focusPointY")->GetValueAsString().c_str());
211 zfocus = std::stod(m_inputImage->GetProperty(
"focusPointZ")->GetValueAsString().c_str());
213 ux0 = std::stod(m_inputImage->GetProperty(
"trajectoryVectorX")->GetValueAsString().c_str());
214 uy0 = std::stod(m_inputImage->GetProperty(
"trajectoryVectorY")->GetValueAsString().c_str());
215 uz0 = std::stod(m_inputImage->GetProperty(
"trajectoryVectorZ")->GetValueAsString().c_str());
217 radius = std::stod(m_inputImage->GetProperty(
"radius")->GetValueAsString().c_str());
218 waist = std::stod(m_inputImage->GetProperty(
"waist")->GetValueAsString().c_str());
220 totalNumberOfVoxels = Nx*Ny*Nz;
221 if (
verbose) std::cout << totalNumberOfVoxels <<
" = sizeof totalNumberOfVoxels" << std::endl;
223 muaVector = (
double *)malloc(totalNumberOfVoxels *
sizeof(
double));
224 musVector = (
double *)malloc(totalNumberOfVoxels *
sizeof(
double));
225 gVector = (
double *)malloc(totalNumberOfVoxels *
sizeof(
double));
228 muaVector = (
double *)readAccess0.
GetData();
230 musVector = (
double *)readAccess1.
GetData();
232 gVector = (
double *)readAccess2.
GetData();
236 mitkThrow() <<
"No longer support loading of binary tissue files.";
244 long i1 = 0, i2 = 31;
250 double* totalFluence;
252 DetectorVoxel* detectorVoxel;
256 detectorVoxel =
nullptr;
258 totalFluence =
nullptr;
285 #define MBIG 1000000000 286 #define MSEED 161803398 290 double RandomGen(
char Type,
long Seed,
long *Status) {
292 if (
verbose) std::cout <<
"Initialized random generator " <<
this <<
" with seed: " << Seed << std::endl;
293 mj =
MSEED - (Seed < 0 ? -Seed : Seed);
297 for (i = 1; i <= 54; i++) {
305 for (ii = 1; ii <= 4; ii++)
306 for (i = 1; i <= 55; i++) {
307 ma[i] -= ma[1 + (i + 30) % 55];
314 else if (Type == 1) {
319 mj = ma[i1] - ma[i2];
325 else if (Type == 2) {
326 for (i = 0; i < 55; i++)
327 Status[i] = ma[i + 1];
331 else if (Type == 3) {
332 for (i = 0; i < 55; i++)
333 ma[i + 1] = Status[i];
338 puts(
"Wrong parameter to RandomGen().");
350 bool SameVoxel(
double x1,
double y1,
double z1,
double x2,
double y2,
double z2,
double dx,
double dy,
double dz)
352 double xmin = min2((floor)(x1 / dx), (floor)(x2 / dx))*dx;
353 double ymin = min2((floor)(y1 / dy), (floor)(y2 / dy))*dy;
354 double zmin = min2((floor)(z1 / dz), (floor)(z2 / dz))*dz;
355 double xmax = xmin + dx;
356 double ymax = ymin + dy;
357 double zmax = zmin + dz;
360 sv = (x1 <= xmax && x2 <= xmax && y1 <= ymax && y2 <= ymax && z1 < zmax && z2 <= zmax);
367 double max2(
double a,
double b) {
379 double min2(
double a,
double b) {
390 double min3(
double a,
double b,
double c) {
394 else if (b <= min2(a, c))
405 double FindVoxelFace2(
double x1,
double y1,
double z1,
double ,
double ,
double ,
double dx,
double dy,
double dz,
double ux,
double uy,
double uz)
407 int ix1 = floor(x1 / dx);
408 int iy1 = floor(y1 / dy);
409 int iz1 = floor(z1 / dz);
427 double xs = fabs((ix2*dx - x1) / ux);
428 double ys = fabs((iy2*dy - y1) / uy);
429 double zs = fabs((iz2*dz - z1) / uz);
431 double s = min3(xs, ys, zs);
444 double RFresnel(
double n1,
458 else if (ca1 > (1.0 - 1.0e-12)) {
460 r = (n2 - n1) / (n2 + n1);
463 else if (ca1 < 1.0e-6) {
470 sa1 = sqrt(1 - ca1*ca1);
481 *ca2_Ptr = ca2 = sqrt(1 - sa2*sa2);
482 cap = ca1*ca2 - sa1*sa2;
483 cam = ca1*ca2 + sa1*sa2;
484 sap = sa1*ca2 + ca1*sa2;
485 sam = sa1*ca2 - ca1*sa2;
486 r = 0.5*sam*sam*(cam*cam + cap*cap) / (sap*sap*cam*cam);
497 double FindVoxelFace(
double x1,
double y1,
double z1,
double x2,
double y2,
double z2,
double dx,
double dy,
double dz,
double ux,
double uy,
double uz)
499 double x_1 = x1 / dx;
500 double y_1 = y1 / dy;
501 double z_1 = z1 / dz;
502 double x_2 = x2 / dx;
503 double y_2 = y2 / dy;
504 double z_2 = z2 / dz;
505 double fx_1 = floor(x_1);
506 double fy_1 = floor(y_1);
507 double fz_1 = floor(z_1);
508 double fx_2 = floor(x_2);
509 double fy_2 = floor(y_2);
510 double fz_2 = floor(z_2);
511 double x = 0, y = 0, z = 0, x0 = 0, y0 = 0, z0 = 0, s = 0;
513 if ((fx_1 != fx_2) && (fy_1 != fy_2) && (fz_1 != fz_2)) {
514 fx_2 = fx_1 +
SIGN(fx_2 - fx_1);
515 fy_2 = fy_1 +
SIGN(fy_2 - fy_1);
516 fz_2 = fz_1 +
SIGN(fz_2 - fz_1);
518 x = (max2(fx_1, fx_2) - x_1) / ux;
519 y = (max2(fy_1, fy_2) - y_1) / uy;
520 z = (max2(fz_1, fz_2) - z_1) / uz;
521 if (x == min3(x, y, z)) {
522 x0 = max2(fx_1, fx_2);
523 y0 = (x0 - x_1) / ux*uy + y_1;
524 z0 = (x0 - x_1) / ux*uz + z_1;
526 else if (y == min3(x, y, z)) {
527 y0 = max2(fy_1, fy_2);
528 x0 = (y0 - y_1) / uy*ux + x_1;
529 z0 = (y0 - y_1) / uy*uz + z_1;
532 z0 = max2(fz_1, fz_2);
533 y0 = (z0 - z_1) / uz*uy + y_1;
534 x0 = (z0 - z_1) / uz*ux + x_1;
537 else if ((fx_1 != fx_2) && (fy_1 != fy_2)) {
538 fx_2 = fx_1 +
SIGN(fx_2 - fx_1);
539 fy_2 = fy_1 +
SIGN(fy_2 - fy_1);
540 x = (max2(fx_1, fx_2) - x_1) / ux;
541 y = (max2(fy_1, fy_2) - y_1) / uy;
542 if (x == min2(x, y)) {
543 x0 = max2(fx_1, fx_2);
544 y0 = (x0 - x_1) / ux*uy + y_1;
545 z0 = (x0 - x_1) / ux*uz + z_1;
548 y0 = max2(fy_1, fy_2);
549 x0 = (y0 - y_1) / uy*ux + x_1;
550 z0 = (y0 - y_1) / uy*uz + z_1;
553 else if ((fy_1 != fy_2) && (fz_1 != fz_2)) {
554 fy_2 = fy_1 +
SIGN(fy_2 - fy_1);
555 fz_2 = fz_1 +
SIGN(fz_2 - fz_1);
556 y = (max2(fy_1, fy_2) - y_1) / uy;
557 z = (max2(fz_1, fz_2) - z_1) / uz;
558 if (y == min2(y, z)) {
559 y0 = max2(fy_1, fy_2);
560 x0 = (y0 - y_1) / uy*ux + x_1;
561 z0 = (y0 - y_1) / uy*uz + z_1;
564 z0 = max2(fz_1, fz_2);
565 x0 = (z0 - z_1) / uz*ux + x_1;
566 y0 = (z0 - z_1) / uz*uy + y_1;
569 else if ((fx_1 != fx_2) && (fz_1 != fz_2)) {
570 fx_2 = fx_1 +
SIGN(fx_2 - fx_1);
571 fz_2 = fz_1 +
SIGN(fz_2 - fz_1);
572 x = (max2(fx_1, fx_2) - x_1) / ux;
573 z = (max2(fz_1, fz_2) - z_1) / uz;
574 if (x == min2(x, z)) {
575 x0 = max2(fx_1, fx_2);
576 y0 = (x0 - x_1) / ux*uy + y_1;
577 z0 = (x0 - x_1) / ux*uz + z_1;
580 z0 = max2(fz_1, fz_2);
581 x0 = (z0 - z_1) / uz*ux + x_1;
582 y0 = (z0 - z_1) / uz*uy + y_1;
585 else if (fx_1 != fx_2) {
586 fx_2 = fx_1 +
SIGN(fx_2 - fx_1);
587 x0 = max2(fx_1, fx_2);
588 y0 = (x0 - x_1) / ux*uy + y_1;
589 z0 = (x0 - x_1) / ux*uz + z_1;
591 else if (fy_1 != fy_2) {
592 fy_2 = fy_1 +
SIGN(fy_2 - fy_1);
593 y0 = max2(fy_1, fy_2);
594 x0 = (y0 - y_1) / uy*ux + x_1;
595 z0 = (y0 - y_1) / uy*uz + z_1;
598 z0 = max2(fz_1, fz_2);
599 fz_2 = fz_1 +
SIGN(fz_2 - fz_1);
600 x0 = (z0 - z_1) / uz*ux + x_1;
601 y0 = (z0 - z_1) / uz*uy + y_1;
606 s = sqrt(
SQR((x0 - x_1)*dx) +
SQR((y0 - y_1)*dy) +
SQR((z0 - z_1)*dz));
613 void runMonteCarlo(InputValues* inputValues, ReturnValues* returnValue,
int thread, mitk::pa::MonteCarloThreadHandler::Pointer threadHandler);
630 int main(
int argc,
char * argv[]) {
635 parser.
setDescription(
"Runs Monte Carlo simulations on inputed tissues.");
636 parser.
setContributor(
"CAI, DKFZ based on code by Jacques and Li");
645 "Input tissue file",
"input tissue file (*.nrrd)",
649 "Output fluence file",
"where to save the simulated fluence (*.nrrd)",
655 "Verbose Output",
"Whether to produce verbose, or rather debug output");
658 "Detector voxel x position",
"Determines the x position of the detector voxel (default: -1 = dont use detector voxel)", -1);
661 "Detector voxel z position",
"Determines the z position of the detector voxel (default: -1 = dont use detector voxel)", -1);
664 "Number of photons",
"Specifies the number of photons (default: 100000). Simulation stops after that number. Use -t --timer to define a timer instead");
667 "Simulation time in min",
"Specifies the amount of time for simutation (default: 0). Simulation stops after that number of minutes. -n --number-of-photons is the override and default behavior and defines the maximum number of photons instead. If no simulation time or number of photons is specified the file time is taken.");
670 "Probe Y-Offset in mm",
"Specifies an offset of the photoacoustic probe in the y direction depending on the initial probe position (default: 0) in mm.");
673 "Number of jobs",
"Specifies the number of jobs for simutation (default: -1 which starts as many jobs as supported).");
676 "Xml definition of the probe",
"Specifies the absolute path of the location of the xml definition file of the probe design.",
us::Any(),
true,
false,
false,
mitkCommandLineParser::Input);
678 "Input normalization file",
"The input normalization file is used for normalization of the number of photons in the PVFC calculations.",
us::Any(),
true,
false,
false,
mitkCommandLineParser::Input);
682 std::map<std::string, us::Any> parsedArgs = parser.
parseArguments(argc, argv);
683 if (parsedArgs.size() == 0)
688 inputFilename = inputFilename.substr(0, inputFilename.find(
"_H.mci"));
689 inputFilename = inputFilename.substr(0, inputFilename.find(
"_T.bin"));
693 std::string suffix =
".nrrd";
699 if (parsedArgs.count(
"verbose"))
703 if (parsedArgs.count(
"detector-x"))
707 if (parsedArgs.count(
"detector-z"))
711 if (parsedArgs.count(
"timer"))
716 if (parsedArgs.count(
"y-offset"))
720 if (parsedArgs.count(
"number-of-photons"))
725 if (parsedArgs.count(
"jobs"))
729 if (parsedArgs.count(
"probe-xml"))
731 std::string inputXmlProbeDesign =
us::any_cast<std::string>(parsedArgs[
"probe-xml"]);
733 if (!m_PhotoacousticProbe->IsValid())
735 std::cerr <<
"Xml File was not valid. Simulation failed." << std::endl;
739 if (parsedArgs.count(
"normalization-file"))
749 std::cout <<
"Could not determine number of available threads. Launching only one." << std::endl;
757 std::cout <<
"Performing PVFC calculation for x=" <<
detector_x <<
" and z=" <<
detector_z << std::endl;
763 std::cout <<
"Will not perform PVFC calculation due to x=" <<
detector_x <<
" and/or z=" <<
detector_z << std::endl;
766 InputValues allInput = InputValues();
774 auto* tmp =
new ReturnValues();
775 allValues.push_back(*tmp);
778 if (
verbose) std::cout <<
"Initializing MonteCarloThreadHandler" << std::endl;
793 mitk::pa::MonteCarloThreadHandler::Pointer threadHandler = mitk::pa::MonteCarloThreadHandler::New(timeMetric,
interpretAsTime);
796 threadHandler->SetPackageSize(1000);
798 if (
verbose) std::cout <<
"\nStarting simulation ...\n" << std::endl;
800 auto simulationStartTime = std::chrono::system_clock::now();
804 threads[i] = std::thread(
runMonteCarlo, &allInput, &allValues[i], (i + 1), threadHandler);
812 auto simulationFinishTime = std::chrono::system_clock::now();
813 auto simulationTimeElapsed = simulationFinishTime - simulationStartTime;
815 if (
verbose) std::cout <<
"\n\nFinished simulation\n\n" << std::endl;
816 std::cout <<
"total time for simulation: " 817 << (int)std::chrono::duration_cast<std::chrono::seconds>(simulationTimeElapsed).count() <<
"sec " << std::endl;
825 if (
verbose) std::cout <<
"Allocating memory for normal simulation result ... ";
826 auto* finalTotalFluence = (
double *)malloc(allInput.totalNumberOfVoxels *
sizeof(
double));
827 if (
verbose) std::cout <<
"[OK]" << std::endl;
828 if (
verbose) std::cout <<
"Cleaning memory for normal simulation result ...";
829 for (
int i = 0; i < allInput.totalNumberOfVoxels; i++) {
830 finalTotalFluence[i] = 0;
832 if (
verbose) std::cout <<
"[OK]" << std::endl;
834 if (
verbose) std::cout <<
"Calculating resulting fluence ... ";
835 double tdx = 0, tdy = 0, tdz = 0;
836 long long tNphotons = 0;
839 tdx = allInput.xSpacing;
840 tdy = allInput.ySpacing;
841 tdz = allInput.zSpacing;
842 tNphotons += allValues[t].Nphotons;
843 for (
int voxelNumber = 0; voxelNumber < allInput.totalNumberOfVoxels; voxelNumber++) {
844 finalTotalFluence[voxelNumber] += allValues[t].totalFluence[voxelNumber];
847 if (
verbose) std::cout <<
"[OK]" << std::endl;
848 std::cout <<
"total number of photons simulated: " 849 << tNphotons << std::endl;
852 double temp = tdx*tdy*tdz*tNphotons;
853 for (
int i = 0; i < allInput.totalNumberOfVoxels; i++) {
854 finalTotalFluence[i] /= temp*allInput.muaVector[i];
861 auto* dimensionsOfImage =
new unsigned int[3];
864 dimensionsOfImage[0] = allInput.Ny;
865 dimensionsOfImage[1] = allInput.Nx;
866 dimensionsOfImage[2] = allInput.Nz;
868 resultImage->Initialize(TPixel, 3, dimensionsOfImage);
871 spacing[0] = allInput.ySpacing;
872 spacing[1] = allInput.xSpacing;
873 spacing[2] = allInput.zSpacing;
874 resultImage->SetSpacing(spacing);
877 resultImage->GetPropertyList()->SetFloatProperty(
"y-offset",
yOffset);
882 if (
verbose) std::cout <<
"[OK]" << std::endl;
886 std::cout <<
"x spacing = " << tdx << std::endl;
887 std::cout <<
"y spacing = " << tdy << std::endl;
888 std::cout <<
"z spacing = " << tdz << std::endl;
889 std::cout <<
"total number of voxels = " << allInput.totalNumberOfVoxels << std::endl;
890 std::cout <<
"number of photons = " << (int)tNphotons << std::endl;
895 if (
verbose) std::cout <<
"Allocating memory for PVFC simulation result ... ";
896 double* detectorFluence = ((
double*)malloc(allInput.totalNumberOfVoxels *
sizeof(
double)));
897 if (
verbose) std::cout <<
"[OK]" << std::endl;
898 if (
verbose) std::cout <<
"Cleaning memory for PVFC simulation result ...";
899 for (
int i = 0; i < allInput.totalNumberOfVoxels; i++) {
900 detectorFluence[i] = 0;
902 if (
verbose) std::cout <<
"[OK]" << std::endl;
904 if (
verbose) std::cout <<
"Calculating resulting PVFC fluence ... ";
905 double tdx = 0, tdy = 0, tdz = 0;
906 long long tNphotons = 0;
907 long pvfcPhotons = 0;
910 tdx = allInput.xSpacing;
911 tdy = allInput.ySpacing;
912 tdz = allInput.zSpacing;
913 tNphotons += allValues[t].Nphotons;
914 pvfcPhotons += allValues[t].detectorVoxel->m_NumberPhotonsCurrent;
915 for (
int voxelNumber = 0; voxelNumber < allInput.totalNumberOfVoxels; voxelNumber++) {
916 detectorFluence[voxelNumber] +=
917 allValues[t].detectorVoxel->fluenceContribution[voxelNumber];
920 if (
verbose) std::cout <<
"[OK]" << std::endl;
921 std::cout <<
"total number of photons simulated: " 922 << tNphotons << std::endl;
925 double temp = tdx*tdy*tdz*tNphotons;
926 for (
int i = 0; i < allInput.totalNumberOfVoxels; i++) {
927 detectorFluence[i] /= temp*allInput.muaVector[i];
930 if (
verbose) std::cout <<
"Saving PVFC ...";
932 std::stringstream detectorname(
"");
933 double detectorX = allValues[0].detectorVoxel->location.x;
934 double detectorY = allValues[0].detectorVoxel->location.y;
935 double detectorZ = allValues[0].detectorVoxel->location.z;
936 detectorname << detectorX <<
"," << detectorY <<
"," 937 << detectorZ <<
"FluenceContribution.nrrd";
940 outputFilename = outputFileBase +
"_p" + detectorname.str().c_str();
943 auto* dimensionsOfPvfcImage =
new unsigned int[3];
946 dimensionsOfPvfcImage[0] = allInput.Ny;
947 dimensionsOfPvfcImage[1] = allInput.Nx;
948 dimensionsOfPvfcImage[2] = allInput.Nz;
950 pvfcImage->Initialize(mitk::MakeScalarPixelType<double>(), 3, dimensionsOfPvfcImage);
953 pvfcSpacing[0] = allInput.ySpacing;
954 pvfcSpacing[1] = allInput.xSpacing;
955 pvfcSpacing[2] = allInput.zSpacing;
956 pvfcImage->SetSpacing(pvfcSpacing);
959 pvfcImage->GetPropertyList()->SetFloatProperty(
"detector-x", detectorX);
961 pvfcImage->GetPropertyList()->SetFloatProperty(
"detector-y", detectorY);
963 pvfcImage->GetPropertyList()->SetFloatProperty(
"detector-z", detectorZ);
965 pvfcImage->GetPropertyList()->SetFloatProperty(
"normalization-factor", allValues[0].detectorVoxel->m_PhotonNormalizationValue);
967 pvfcImage->GetPropertyList()->SetFloatProperty(
"simulated-photons", pvfcPhotons);
972 if (
verbose) std::cout <<
"[OK]" << std::endl;
976 std::cout <<
"x spacing = " << tdx << std::endl;
977 std::cout <<
"y spacing = " << tdy << std::endl;
978 std::cout <<
"z spacing = " << tdz << std::endl;
979 std::cout <<
"total number of voxels = " << allInput.totalNumberOfVoxels << std::endl;
980 std::cout <<
"number of photons = " << (int)tNphotons << std::endl;
988 void runMonteCarlo(InputValues* inputValues, ReturnValues* returnValue,
int thread, mitk::pa::MonteCarloThreadHandler::Pointer threadHandler)
990 if (
verbose) std::cout <<
"Thread " << thread <<
": Locking Mutex ..." << std::endl;
991 if (
verbose) std::cout <<
"[OK]" << std::endl;
992 if (
verbose) std::cout <<
"Initializing ... ";
997 double uxx, uyy, uzz;
1005 long photonIterator = 0;
1008 short photon_status;
1015 double tempx, tempy, tempz;
1021 returnValue->totalFluence = (
double *)malloc(inputValues->totalNumberOfVoxels *
sizeof(
double));
1025 if (detector_x<0 || detector_x>inputValues->Nx)
1027 std::cout <<
"Requested detector x position not valid. Needs to be >= 0 and <= " << inputValues->Nx << std::endl;
1030 if (detector_z<1 || detector_z>inputValues->Nz)
1032 std::cout <<
"Requested detector z position not valid. Needs to be > 0 and <= " << inputValues->Nz << std::endl;
1036 double photonNormalizationValue = 1 / inputValues->GetNormalizationValue(
detector_x, inputValues->Ny / 2,
detector_z);
1037 returnValue->detectorVoxel =
new DetectorVoxel(
initLocation(
detector_x, inputValues->Ny / 2,
detector_z, 0), inputValues->totalNumberOfVoxels, photonNormalizationValue);
1042 auto duration = std::chrono::system_clock::now().time_since_epoch();
1043 returnValue->RandomGen(0, (std::chrono::duration_cast<std::chrono::milliseconds>(duration).count() + thread) % 32000,
nullptr);
1044 for (j = 0; j < inputValues->totalNumberOfVoxels; j++) returnValue->totalFluence[j] = 0;
1048 long photonsToSimulate = 0;
1051 photonsToSimulate = threadHandler->GetNextWorkPackage();
1052 if (returnValue->detectorVoxel !=
nullptr)
1054 photonsToSimulate = photonsToSimulate * returnValue->detectorVoxel->m_PhotonNormalizationValue;
1058 MITK_INFO <<
"Photons to simulate: " << photonsToSimulate;
1060 photonIterator = 0L;
1065 photonIterator += 1;
1067 photon_status =
ALIVE;
1085 while ((rnd1 = returnValue->RandomGen(1, 0,
nullptr)) <= 0.0);
1086 while ((rnd2 = returnValue->RandomGen(1, 0,
nullptr)) <= 0.0);
1087 while ((rnd3 = returnValue->RandomGen(1, 0,
nullptr)) <= 0.0);
1088 while ((rnd4 = returnValue->RandomGen(1, 0,
nullptr)) <= 0.0);
1089 while ((rnd5 = returnValue->RandomGen(1, 0,
nullptr)) <= 0.0);
1090 while ((rnd6 = returnValue->RandomGen(1, 0,
nullptr)) <= 0.0);
1091 while ((rnd7 = returnValue->RandomGen(1, 0,
nullptr)) <= 0.0);
1092 while ((rnd8 = returnValue->RandomGen(1, 0,
nullptr)) <= 0.0);
1102 std::cout <<
"Created photon at position (" << x <<
"|" << y <<
"|" << z <<
") with angles (" << ux <<
"|" << uy <<
"|" << uz <<
")." << std::endl;
1107 if (inputValues->launchflag == 1)
1109 x = inputValues->xs;
1110 y = inputValues->ys;
1111 z = inputValues->zs;
1112 ux = inputValues->ux0;
1113 uy = inputValues->uy0;
1114 uz = inputValues->uz0;
1118 if (inputValues->mcflag == 0)
1121 while ((rnd = returnValue->RandomGen(1, 0,
nullptr)) <= 0.0);
1122 r = inputValues->radius*sqrt(rnd);
1123 while ((rnd = returnValue->RandomGen(1, 0,
nullptr)) <= 0.0);
1125 x = inputValues->xs + r*cos(phi);
1126 y = inputValues->ys + r*sin(phi);
1127 z = inputValues->zs;
1129 while ((rnd = returnValue->RandomGen(1, 0,
nullptr)) <= 0.0);
1130 r = inputValues->waist*sqrt(rnd);
1131 while ((rnd = returnValue->RandomGen(1, 0,
nullptr)) <= 0.0);
1136 inputValues->xfocus = r*cos(phi);
1137 inputValues->yfocus = r*sin(phi);
1138 temp = sqrt((x - inputValues->xfocus)*(x - inputValues->xfocus)
1139 + (y - inputValues->yfocus)*(y - inputValues->yfocus) + inputValues->zfocus*inputValues->zfocus);
1140 ux = -(x - inputValues->xfocus) / temp;
1141 uy = -(y - inputValues->yfocus) / temp;
1142 uz = sqrt(1 - ux*ux + uy*uy);
1144 else if (inputValues->mcflag == 5)
1147 while ((rnd = returnValue->RandomGen(1, 0,
nullptr)) <= 0.0);
1150 x = (rnd*2.5) - 1.25;
1152 while ((rnd = returnValue->RandomGen(1, 0,
nullptr)) <= 0.0);
1153 double b = ((rnd)-0.5);
1158 while ((rnd = returnValue->RandomGen(1, 0,
nullptr)) <= 0.0);
1161 uy = sin((rnd*0.42) - 0.21 + (b < 0 ? 1.0 : -1.0) * 0.436);
1163 while ((rnd = returnValue->RandomGen(1, 0,
nullptr)) <= 0.0);
1166 ux = sin((rnd*0.42) - 0.21);
1167 uz = sqrt(1 - ux*ux - uy*uy);
1169 else if (inputValues->mcflag == 4)
1172 while ((rnd = returnValue->RandomGen(1, 0,
nullptr)) <= 0.0);
1175 x = (rnd*2.5) - 1.25;
1177 while ((rnd = returnValue->RandomGen(1, 0,
nullptr)) <= 0.0);
1178 double b = ((rnd)-0.5);
1183 while ((rnd = returnValue->RandomGen(1, 0,
nullptr)) <= 0.0);
1186 uy = sin((rnd*0.42) - 0.21 + (b < 0 ? 1.0 : -1.0) * 0.375);
1188 while ((rnd = returnValue->RandomGen(1, 0,
nullptr)) <= 0.0);
1191 ux = sin((rnd*0.42) - 0.21);
1192 uz = sqrt(1 - ux*ux - uy*uy);
1195 costheta = 1.0 - 2.0 * returnValue->RandomGen(1, 0,
nullptr);
1196 sintheta = sqrt(1.0 - costheta*costheta);
1197 psi = 2.0 *
PI * returnValue->RandomGen(1, 0,
nullptr);
1200 sinpsi = sqrt(1.0 - cospsi*cospsi);
1202 sinpsi = -sqrt(1.0 - cospsi*cospsi);
1203 x = inputValues->xs;
1204 y = inputValues->ys;
1205 z = inputValues->zs;
1206 ux = sintheta*cospsi;
1207 uy = sintheta*sinpsi;
1219 ix = (int)(inputValues->Nx / 2 + x / inputValues->xSpacing);
1220 iy = (int)(inputValues->Ny / 2 + y / inputValues->ySpacing);
1221 iz = (int)(z / inputValues->zSpacing);
1222 if (ix >= inputValues->Nx) ix = inputValues->Nx - 1;
1223 if (iy >= inputValues->Ny) iy = inputValues->Ny - 1;
1224 if (iz >= inputValues->Nz) iz = inputValues->Nz - 1;
1229 i = (long)(iz*inputValues->Ny*inputValues->Nx + ix*inputValues->Ny + iy);
1233 if (returnValue->detectorVoxel !=
nullptr)
1234 returnValue->detectorVoxel->recordedPhotonRoute->clear();
1245 while ((rnd = returnValue->RandomGen(1, 0,
nullptr)) <= 0.0);
1250 s = sleft / inputValues->musVector[i];
1255 sv = returnValue->SameVoxel(x, y, z, tempx, tempy, tempz, inputValues->xSpacing, inputValues->ySpacing, inputValues->zSpacing);
1266 absorb = W*(1 - exp(-inputValues->muaVector[i] * s));
1272 i = (long)(iz*inputValues->Ny*inputValues->Nx + ix*inputValues->Ny + iy);
1273 returnValue->totalFluence[i] += absorb;
1277 if (returnValue->detectorVoxel !=
nullptr)
1280 returnValue->detectorVoxel->recordedPhotonRoute->push_back(
initLocation(ix, iy, iz, absorb));
1283 if ((returnValue->detectorVoxel->location.x == ix)
1284 && ((returnValue->detectorVoxel->location.y == iy)
1285 || (returnValue->detectorVoxel->location.y - 1 == iy))
1286 && (returnValue->detectorVoxel->location.z == iz))
1289 for (
unsigned int routeIndex = 0; routeIndex < returnValue->detectorVoxel->recordedPhotonRoute->size(); routeIndex++)
1292 i = (long)(returnValue->detectorVoxel->recordedPhotonRoute->at(routeIndex).z*inputValues->Ny*inputValues->Nx
1293 + returnValue->detectorVoxel->recordedPhotonRoute->at(routeIndex).x*inputValues->Ny
1294 + returnValue->detectorVoxel->recordedPhotonRoute->at(routeIndex).y);
1295 returnValue->detectorVoxel->fluenceContribution[i] += returnValue->detectorVoxel->recordedPhotonRoute->at(routeIndex).absorb;
1299 returnValue->detectorVoxel->m_NumberPhotonsCurrent++;
1300 returnValue->detectorVoxel->recordedPhotonRoute->clear();
1311 s =
ls + returnValue->FindVoxelFace2(x, y, z, tempx, tempy, tempz, inputValues->xSpacing, inputValues->ySpacing, inputValues->zSpacing, ux, uy, uz);
1316 absorb = W*(1 - exp(-inputValues->muaVector[i] * s));
1325 if (returnValue->detectorVoxel !=
nullptr)
1328 returnValue->detectorVoxel->recordedPhotonRoute->push_back(
initLocation(ix, iy, iz, absorb));
1331 if ((returnValue->detectorVoxel->location.x == ix)
1332 && ((returnValue->detectorVoxel->location.y == iy)
1333 || (returnValue->detectorVoxel->location.y - 1 == iy))
1334 && (returnValue->detectorVoxel->location.z == iz))
1337 for (
unsigned int routeIndex = 0; routeIndex < returnValue->detectorVoxel->recordedPhotonRoute->size(); routeIndex++)
1340 i = (long)(returnValue->detectorVoxel->recordedPhotonRoute->at(routeIndex).z*inputValues->Ny*inputValues->Nx
1341 + returnValue->detectorVoxel->recordedPhotonRoute->at(routeIndex).x*inputValues->Ny
1342 + returnValue->detectorVoxel->recordedPhotonRoute->at(routeIndex).y);
1343 returnValue->detectorVoxel->fluenceContribution[i] += returnValue->detectorVoxel->recordedPhotonRoute->at(routeIndex).absorb;
1347 returnValue->detectorVoxel->m_NumberPhotonsCurrent++;
1348 returnValue->detectorVoxel->recordedPhotonRoute->clear();
1352 i = (long)(iz*inputValues->Ny*inputValues->Nx + ix*inputValues->Ny + iy);
1353 returnValue->totalFluence[i] += absorb;
1357 sleft -= s*inputValues->musVector[i];
1358 if (sleft <=
ls) sleft = 0;
1366 ix = (int)(inputValues->Nx / 2 + x / inputValues->xSpacing);
1367 iy = (int)(inputValues->Ny / 2 + y / inputValues->ySpacing);
1368 iz = (int)(z / inputValues->zSpacing);
1371 if (inputValues->boundaryflag == 0) {
1375 if (iz >= inputValues->Nz) { iz = inputValues->Nz - 1; bflag = 0; }
1376 if (ix >= inputValues->Nx) { ix = inputValues->Nx - 1; bflag = 0; }
1377 if (iy >= inputValues->Ny) { iy = inputValues->Ny - 1; bflag = 0; }
1378 if (iz < 0) { iz = 0; bflag = 0; }
1379 if (ix < 0) { ix = 0; bflag = 0; }
1380 if (iy < 0) { iy = 0; bflag = 0; }
1382 else if (inputValues->boundaryflag == 1) {
1383 if (iz >= inputValues->Nz) { iz = inputValues->Nz - 1; photon_status =
DEAD; sleft = 0; }
1384 if (ix >= inputValues->Nx) { ix = inputValues->Nx - 1; photon_status =
DEAD; sleft = 0; }
1385 if (iy >= inputValues->Ny) { iy = inputValues->Ny - 1; photon_status =
DEAD; sleft = 0; }
1386 if (iz < 0) { iz = 0; photon_status =
DEAD; sleft = 0; }
1387 if (ix < 0) { ix = 0; photon_status =
DEAD; sleft = 0; }
1388 if (iy < 0) { iy = 0; photon_status =
DEAD; sleft = 0; }
1390 else if (inputValues->boundaryflag == 2) {
1391 if (iz >= inputValues->Nz) { iz = inputValues->Nz - 1; bflag = 0; }
1392 if (ix >= inputValues->Nx) { ix = inputValues->Nx - 1; bflag = 0; }
1393 if (iy >= inputValues->Ny) { iy = inputValues->Ny - 1; bflag = 0; }
1394 if (iz < 0) { iz = 0; photon_status =
DEAD; sleft = 0; }
1395 if (ix < 0) { ix = 0; bflag = 0; }
1396 if (iy < 0) { iy = 0; bflag = 0; }
1400 i = (long)(iz*inputValues->Ny*inputValues->Nx + ix*inputValues->Ny + iy);
1402 }
while (sleft > 0);
1411 while ((rnd = returnValue->RandomGen(1, 0,
nullptr)) <= 0.0);
1412 if (inputValues->gVector[i] == 0.0)
1414 costheta = 2.0 * rnd - 1.0;
1418 double temp = (1.0 - inputValues->gVector[i] * inputValues->gVector[i])
1419 / (1.0 - inputValues->gVector[i] + 2 * inputValues->gVector[i] * rnd);
1420 costheta = (1.0 + inputValues->gVector[i] * inputValues->gVector[i] - temp*temp) / (2.0*inputValues->gVector[i]);
1422 sintheta = sqrt(1.0 - costheta*costheta);
1425 psi = 2.0*
PI*returnValue->RandomGen(1, 0,
nullptr);
1428 sinpsi = sqrt(1.0 - cospsi*cospsi);
1430 sinpsi = -sqrt(1.0 - cospsi*cospsi);
1434 uxx = sintheta * cospsi;
1435 uyy = sintheta * sinpsi;
1436 uzz = costheta *
SIGN(uz);
1439 temp = sqrt(1.0 - uz * uz);
1440 uxx = sintheta * (ux * uz * cospsi - uy * sinpsi) / temp + ux * costheta;
1441 uyy = sintheta * (uy * uz * cospsi + ux * sinpsi) / temp + uy * costheta;
1442 uzz = -sintheta * cospsi * temp + uz * costheta;
1456 if (returnValue->RandomGen(1, 0,
nullptr) <=
CHANCE)
1458 else photon_status =
DEAD;
1460 }
while (photon_status ==
ALIVE);
1463 }
while (photonIterator < photonsToSimulate);
1465 returnValue->Nphotons += photonsToSimulate;
1466 }
while (photonsToSimulate > 0);
1468 if (
verbose) std::cout <<
"------------------------------------------------------" << std::endl;
1469 if (
verbose) std::cout <<
"Thread " << thread <<
" is finished." << std::endl;
int concurentThreadsSupported
std::string inputFilename
void setContributor(std::string contributor)
ValueType * any_cast(Any *operand)
void addArgument(const std::string &longarg, const std::string &shortarg, Type type, const std::string &argLabel, const std::string &argHelp=std::string(), const us::Any &defaultValue=us::Any(), bool optional=true, bool ignoreRest=false, bool deprecated=false, mitkCommandLineParser::Channel channel=mitkCommandLineParser::Channel::None)
float requestedSimulationTime
std::map< std::string, us::Any > parseArguments(const StringContainerType &arguments, bool *ok=nullptr)
std::string outputFilename
static void info(const char *fmt,...)
int main(int argc, char *argv[])
mitk::pa::Probe::Pointer m_PhotoacousticProbe
static IPropertyPersistence * GetPropertyPersistence(us::ModuleContext *context=us::GetModuleContext())
Get an IPropertyPersistence instance.
void runMonteCarlo(InputValues *inputValues, ReturnValues *returnValue, int thread, mitk::pa::MonteCarloThreadHandler::Pointer threadHandler)
#define ONE_MINUS_COSZERO
void setCategory(std::string category)
void setArgumentPrefix(const std::string &longPrefix, const std::string &shortPrefix)
std::string normalizationFilename
int requestedNumberOfPhotons
static void Save(const mitk::BaseData *data, const std::string &path, bool setPathProperty=false)
Save a mitk::BaseData instance.
MITKCORE_EXPORT const ScalarType eps
virtual bool AddInfo(const PropertyPersistenceInfo *info, bool overwrite=false)=0
Add persistence info for a specific base data property. If there is already a property info instance ...
void setTitle(std::string title)
ImageReadAccessor class to get locked read access for a particular image part.
void setDescription(std::string description)
void beginGroup(const std::string &description)
struct Location initLocation(int x, int y, int z, double absorb)
const void * GetData() const
Gives const access to the data.
Class for defining the data type of pixels.