CASToR  1.0
Tomographic Reconstruction (PET/SPECT)
oIterativeAlgorithm.cc
Go to the documentation of this file.
00001 
00002 /*
00003   Implementation of class oIterativeAlgorithm
00004 
00005   - separators: X
00006   - doxygen: X
00007   - default initialization: X
00008   - CASTOR_DEBUG: X
00009   - CASTOR_VERBOSE: none
00010 */
00011 
00018 #include "gVariables.hh"
00019 #include "oIterativeAlgorithm.hh"
00020 
00021 bool m_releaseThreads = false; 
00022 int m_nbThreadsWaiting = 0; 
00024 // =====================================================================
00025 // ---------------------------------------------------------------------
00026 // ---------------------------------------------------------------------
00027 // =====================================================================
00028 /*
00029   \brief oIterativeAlgorithm constructor. 
00030          Initialize the member variables to their default values.
00031 */
00032 oIterativeAlgorithm::oIterativeAlgorithm()
00033 {
00034   // Default number of iterations and subsets (1 for each)
00035   m_nbIterations = 1;
00036   mp_nbSubsets = (int*)malloc(1*sizeof(int));
00037   mp_nbSubsets[0] = 1;
00038   m_generalizedImplementation = true;
00039   mp_outputIterations = NULL; 
00040   // set all members to default values
00041   m_verbose = -1;
00042   m_flagGPU = false;
00043   mp_ID = NULL;
00044   m2p_DataFile= NULL;
00045   mp_ProjectorManager = NULL;
00046   mp_OptimizerManager = NULL;
00047   mp_DeformationManager = NULL;
00048   mp_DynamicModelManager = NULL;
00049   mp_ImageSpace = NULL;
00050   mp_ImageConvolverManager = NULL;
00051   mp_ImageProcessingManager = NULL;
00052   m_nbBeds = -1;
00053   m_pathToInitialImg = "";
00054   m_pathToSensitivityImg = "";
00055   m_pathToAnatomicalImg = "";
00056   m_pathToMaskImg = "";
00057   m_saveSensitivityHistoFlag = false;
00058   m_saveImageAfterSubsets = false;
00059 }
00060 
00061 // =====================================================================
00062 // ---------------------------------------------------------------------
00063 // ---------------------------------------------------------------------
00064 // =====================================================================
00065 /*
00066   \brief oIterativeAlgorithm destructor. 
00067 */
00068 oIterativeAlgorithm::~oIterativeAlgorithm()
00069 {
00070   // Delete some tables
00071   if (mp_nbSubsets!=NULL) free(mp_nbSubsets);
00072   if (mp_outputIterations!=NULL) free(mp_outputIterations);
00073 }
00074 
00075 // =====================================================================
00076 // ---------------------------------------------------------------------
00077 // ---------------------------------------------------------------------
00078 // =====================================================================
00079 /*
00080   \fn SetNbIterationsAndSubsets
00081   \param a_nbIterationsSubsets
00082   \brief Set the number of iterations and subsets
00083   \details The provided string is a list of iteration:subset pairs 
00084            separated by commas.
00085   \return 0 if success, positive value otherwise
00086 */
00087 int oIterativeAlgorithm::SetNbIterationsAndSubsets(const string& a_nbIterationsSubsets)
00088 {
00089   // If the string is empty, then just keep the defaults
00090   if (a_nbIterationsSubsets=="") return 0;
00091   // Otherwise, reset the number of iterations to 0
00092   m_nbIterations = 0;
00093 
00094   // Copy the string
00095   string buf = a_nbIterationsSubsets;
00096 
00097   // Loop to search for commas
00098   size_t pos_comma;
00099   while ((pos_comma=buf.find_first_of(","))!=string::npos)
00100   {
00101     // Get the substring before the comma
00102     string sub_buf = buf.substr(0,pos_comma);
00103     // Search for columns
00104     size_t pos_column = sub_buf.find_first_of(":");
00105     if (pos_column==string::npos || pos_column==0)
00106     {
00107       Cerr("***** oIterativeAlgorithm::SetNbIterationsAndSubsets() -> Syntax problem in number of iterations and subsets !" << endl);
00108       return 1;
00109     }
00110     int iter = atoi(  sub_buf.substr(0,pos_column).c_str()  );
00111     int subs = atoi(  sub_buf.substr(pos_column+1).c_str()  );
00112     mp_nbSubsets = (int*)realloc(mp_nbSubsets,(m_nbIterations+iter)*sizeof(int));
00113     for (int it=0; it<iter; it++) mp_nbSubsets[m_nbIterations+it] = subs;
00114     m_nbIterations += iter;
00115     buf = buf.substr(pos_comma+1);
00116   }
00117 
00118   // Last couple of iterations:subsets
00119   size_t pos_column = buf.find_first_of(":");
00120   if (pos_column==string::npos || pos_column==0)
00121   {
00122     Cerr("***** oIterativeAlgorithm::SetNbIterationsAndSubsets() -> Syntax problem in number of iterations and subsets !" << endl);
00123     return 1;
00124   }
00125   int iter = atoi(  buf.substr(0,pos_column).c_str()  );
00126   int subs = atoi(  buf.substr(pos_column+1).c_str()  );
00127   mp_nbSubsets = (int*)realloc(mp_nbSubsets,(m_nbIterations+iter)*sizeof(int));
00128   for (int it=0; it<iter; it++) mp_nbSubsets[m_nbIterations+it] = subs;
00129   m_nbIterations += iter;
00130 
00131   if (m_verbose>=3) 
00132   {
00133     Cout("oIterativeAlgorithm::SetNbIterationsAndSubsets() ->  Selected numbers of subsets for each iteration:" << endl); 
00134     Cout("  Iteration / number of subsets "<< endl); 
00135     for (int it=0 ; it<m_nbIterations ; it++) Cout("    " << it+1 << "  /  " <<  mp_nbSubsets[it] << endl); 
00136   }
00137   // End
00138   return 0;
00139 }
00140 
00141 // =====================================================================
00142 // ---------------------------------------------------------------------
00143 // ---------------------------------------------------------------------
00144 // =====================================================================
00145 /*
00146   \fn SetOutputIterations
00147   \param a_outputIterations
00148   \brief Set the selected output iterations
00149   \details The provided string is a list of couple a:b separated by commas.
00150           It means that we save one iteration over a until b is reached.
00151            "b" must be incrementing for each successive couples.
00152           If the list is empty, we save all iterations by default.
00153           If the list is equal to "-1", then we save only the last iteration.
00154   \return 0 if success, positive value otherwise
00155 */
00156 int oIterativeAlgorithm::SetOutputIterations(const string& a_outputIterations)
00157 {
00158   if(m_verbose>=2) Cout("oIterativeAlgorithm::SetOutputIterations ..."<< endl); 
00159     
00160   // Allocate the output iterations boolean table
00161   mp_outputIterations = (bool*)malloc(m_nbIterations*sizeof(bool));
00162   for (int it=0; it<m_nbIterations; it++) mp_outputIterations[it] = false;
00163 
00164   // If the list is empty, we save all iterations by default
00165   if (a_outputIterations=="")
00166   {
00167     for (int it=0; it<m_nbIterations; it++) mp_outputIterations[it] = true;
00168     return 0;
00169   }
00170 
00171   // Copy the string
00172   string buf = a_outputIterations;
00173 
00174   // Loop to search for commas
00175   size_t pos_comma;
00176   int current_iteration = -1;
00177   while ((pos_comma=buf.find_first_of(","))!=string::npos)
00178   {
00179     // Get the substring before the comma
00180     string sub_buf = buf.substr(0,pos_comma);
00181     // Search for columns
00182     size_t pos_column = sub_buf.find_first_of(":");
00183     if (pos_column==string::npos || pos_column==0)
00184     {
00185       Cerr("***** oIterativeAlgorithm::SetOutputIterations() -> Syntax problem in output iteration numbers !" << endl);
00186       return 1;
00187     }
00188     int step_iteration = atoi(  sub_buf.substr(0,pos_column).c_str()  );
00189     if (step_iteration<=0)
00190     {
00191       Cerr("***** oIterativeAlgorithm::SetOutputIterations() -> Iteration step must be strictly positive (here it is " << step_iteration << ") !" << endl);
00192       return 1;
00193     }
00194     int stop_iteration = atoi(  sub_buf.substr(pos_column+1).c_str()  );
00195     if (stop_iteration<=current_iteration)
00196     {
00197       Cerr("***** oIterationAlgorithm::SetOutputIterations() -> Output iteration number must be increasing through provided couples !" << endl);
00198       return 1;
00199     }
00200     for (int it=current_iteration+step_iteration; it<stop_iteration; it+=step_iteration) mp_outputIterations[it] = true;
00201     current_iteration = stop_iteration-1;
00202     buf = buf.substr(pos_comma+1);
00203   }
00204 
00205   // Last couple of iterations:subsets
00206   size_t pos_column = buf.find_first_of(":");
00207   if (pos_column==string::npos || pos_column==0)
00208   {
00209     // Special case if -1 is provided, it means we save the last iteration
00210     if (buf=="-1")
00211     {
00212       mp_outputIterations[m_nbIterations-1] = true;
00213       // We directly exist here
00214       return 0;
00215     }
00216     else
00217     {
00218       Cerr("***** oIterativeAlgorithm::SetOutputIterations() -> Syntax problem in output iteration numbers !" << endl);
00219       return 1;
00220     }
00221   }
00222   int step_iteration = atoi(  buf.substr(0,pos_column).c_str()  );
00223   if (step_iteration<=0)
00224   {
00225     Cerr("***** oIterativeAlgorithm::SetOutputIterations() -> Iteration step must be strictly positive (here it is " << step_iteration << ") !" << endl);
00226     return 1;
00227   }
00228   int stop_iteration = atoi(  buf.substr(pos_column+1).c_str()  );
00229   if (stop_iteration<=current_iteration)
00230   {
00231     Cerr("***** oIterationAlgorithm::SetOutputIterations() -> Output iteration number must be increasing through provided couples !" << endl);
00232     return 1;
00233   }
00234   for (int it=current_iteration+step_iteration; it<stop_iteration; it+=step_iteration) mp_outputIterations[it] = true;
00235 
00236   // End
00237   return 0;
00238 }
00239 
00240 // =====================================================================
00241 // ---------------------------------------------------------------------
00242 // ---------------------------------------------------------------------
00243 // =====================================================================
00244 /*
00245   \fn Iterate
00246   \brief Just call either the IterateCPU or the IterateGPU function as asked for
00247   \return 0 if success, positive value otherwise
00248 */
00249 int oIterativeAlgorithm::Iterate()
00250 {
00251   if(m_verbose>=2) Cout("oIterativeAlgorithm::Iterate ..."<< endl); 
00252     
00253   #ifdef CASTOR_GPU
00254   if (m_flagGPU) 
00255     return IterateGPU();
00256   else 
00257     return IterateCPU();
00258   #else
00259   return IterateCPU();
00260   #endif
00261 }
00262 
00263 // =====================================================================
00264 // ---------------------------------------------------------------------
00265 // ---------------------------------------------------------------------
00266 // =====================================================================
00267 /*
00268   \fn IterateCPU
00269   \brief Perform the iterative loop of the algorithm, call the different object 
00270          for optimization, projection, update, etc.
00271          Function designed to be executed on the CPU only.
00272   \details Loops over the iterations, subsets, bed position
00273            Call functions related to each steps of iterative reconstruction:
00274            
00275            StepBeforeIterationLoop()
00276            / Loop on iterations
00277            | StepBeforeSubsetLoop(iteration)
00278            |  / Loop on subsets
00279            |  | StepPreProcessInsideSubsetLoop(iteration,subset)
00280            |  | / Loop on bed positions
00281            |  | | StepInnerLoopInsideSubsetLoop(iteration,subset,bed)
00282            |  | StepPostProcessInsideSubsetLoop(iteration,subset)
00283            |  StepAfterSubsetLoop(iteration)
00284            StepAfterIterationLoop()
00285            
00286   \return 0 if success, positive value otherwise
00287 */
00288 int oIterativeAlgorithm::IterateCPU()
00289 {    
00290   // Verbose
00291   if (m_verbose>=1) Cout("oIterativeAlgorithm::IterateCPU() -> Start algorithm for " << m_nbIterations << " iterations" << endl);
00292 
00293   // Initial clock for execution time
00294   clock_t clock_start_whole = clock();
00295   time_t time_start_whole = time(NULL);
00296 
00297   // Call before iteration function
00298   if (StepBeforeIterationLoop())
00299   {
00300     Cerr("***** oIterativeAlgorithm::IterateCPU() -> A problem occured while calling StepBeforeIterationLoop() function !" << endl);
00301     return 1;
00302   }
00303 
00304   // Loop on iterations
00305   for (int iteration=0 ; iteration<m_nbIterations ; iteration++)
00306   {
00307 
00308     // Call before subset function
00309     if (StepBeforeSubsetLoop(iteration))
00310     {
00311       Cerr("***** oIterativeAlgorithm::IterateCPU() -> A problem occured while calling StepBeforeSubsetLoop() function !" << endl);
00312       return 1;
00313     }
00314 
00315     // Loop on subsets
00316     for (int subset=0 ; subset<mp_nbSubsets[iteration] ; subset++)
00317     {
00318       // Verbose
00319       if (m_verbose>=1) 
00320       {
00321         Cout("oIterativeAlgorithm::IterateCPU() -> Start iteration " << iteration+1 << "/" << m_nbIterations 
00322           << " subset " << subset+1 << "/" << mp_nbSubsets[iteration] << endl);
00323       }
00324       
00325       // Clock start for subset execution time
00326       clock_t clock_start_subset = clock();
00327       time_t time_start_subset = time(NULL);
00328 
00329       // Call pre-process inside subset loop function
00330       if (StepPreProcessInsideSubsetLoop(iteration,subset))
00331       {
00332         Cerr("***** oIterativeAlgorithm::IterateCPU() -> A problem occured while calling StepPreProcessInsideSubsetLoop() function !" << endl);
00333         return 1;
00334       }
00335 
00336       // Synchronize MPI processes
00337       #ifdef CASTOR_MPI
00338       MPI_Barrier(MPI_COMM_WORLD);
00339       #endif
00340 
00341       // Loop on bed positions
00342       for (int bed=0 ; bed<m_nbBeds ; bed++)
00343       {
00344 
00345         // Verbose
00346         if (m_verbose>=2 && m_nbBeds>1) Cout("oIterativeAlgorithm::IterateCPU() -> Processing bed " << bed << endl);
00347 
00348         // Call the inner loop on events inside subset loop function
00349         if (StepInnerLoopInsideSubsetLoop(iteration,subset,bed))
00350         {
00351           Cerr("***** oIterativeAlgorithm::IterateCPU() -> A problem occured while calling StepInnerLoopInsideSubsetLoop() function !" << endl);
00352           return 1;
00353         }
00354 
00355       } // End of beds loop
00356 
00357       // Synchronize MPI processes
00358       #ifdef CASTOR_MPI
00359       MPI_Barrier(MPI_COMM_WORLD);
00360       #endif
00361 
00362       // Call post-process inside subset loop function
00363       if (StepPostProcessInsideSubsetLoop(iteration,subset))
00364       {
00365         Cerr("***** oIterativeAlgorithm::IterateCPU() -> A problem occured while calling StepPostProcessInsideSubsetLoop() function !" << endl);
00366         return 1;
00367       }
00368 
00369       // Clock stop for subset execution time
00370       clock_t clock_stop_subset = clock();
00371       time_t time_stop_subset = time(NULL);
00372       if (m_verbose>=2) Cout ("oIterativeAlgorithm::IterateCPU() -> Time spent for subset " << subset+1 << " | User: " << time_stop_subset-time_start_subset
00373                            << " sec | CPU: " << (clock_stop_subset-clock_start_subset)/((FLTNB)CLOCKS_PER_SEC) << " sec" << endl);
00374 
00375 
00376     } // End of subsets loop
00377 
00378               
00379     // Call after subset function
00380     if (StepAfterSubsetLoop(iteration))
00381     {
00382       Cerr("***** oIterativeAlgorithm::IterateCPU() -> A problem occured while calling StepAfterSubsetLoop() function !" << endl);
00383       return 1;
00384     }
00385   
00386 
00387   } // End of iterations loop
00388 
00389   //  Call after iteration function
00390   if (StepAfterIterationLoop())
00391   {
00392     Cerr("***** oIterativeAlgorithm::IterateCPU() -> A problem occured while calling StepAfterIterationLoop() function !" << endl);
00393     return 1;
00394   }
00395 
00396   // Final clock for execution time
00397   clock_t clock_stop_whole = clock();
00398   time_t time_stop_whole = time(NULL);
00399   if (m_verbose>=1) Cout("oIterativeAlgorithm::IterateCPU() -> Total time spent | User: " << time_stop_whole-time_start_whole 
00400                       << " sec | CPU: " << (clock_stop_whole-clock_start_whole)/((FLTNB)CLOCKS_PER_SEC) << " sec" << endl);
00401   
00402 
00403   return 0;
00404 }
00405 
00406 // =====================================================================
00407 // ---------------------------------------------------------------------
00408 // ---------------------------------------------------------------------
00409 // =====================================================================
00410 /*
00411   \fn StepBeforeIterationLoop
00412   \brief This function is called at the beginning of the IterateCPU function.
00413   \details Initialization and memory allocation for the imageSpace and
00414            some managers
00415   \return 0 if success, positive value otherwise.
00416 */
00417 int oIterativeAlgorithm::StepBeforeIterationLoop()
00418 {
00419   if (m_verbose>=2) Cout("oIterativeAlgorithm::StepBeforeIterationLoop ... " << endl);
00420 
00421   // Check that the image space if already allocated
00422   if (mp_ImageSpace==NULL || !mp_ImageSpace->Checked())
00423   {
00424     Cerr("***** oIterativeAlgorithm::StepBeforeIterationLoop() -> Image space has not been created or was not checked !" << endl);
00425     return 1;
00426   }
00427 
00428   // In SPECT with attenuation correction
00429   if (m_pathToAtnImg!="" && m2p_DataFile[0]->GetDataType()==TYPE_SPECT)
00430   {
00431     // Check that the projection line strategy is not IMAGE_COMPUTATION_STRATEGY (this is not compatible)
00432     // Note that we cannot do this check in the oProjectionLine directly, because we cannot now in advance
00433     // that the projection method including attenuation will be used...
00434     if (mp_ProjectorManager->GetComputationStrategy()==IMAGE_COMPUTATION_STRATEGY)
00435     {
00436       Cerr("***** oIterativeAlgorithm::StepBeforeIterationLoop() -> The image-computation strategy of the oProjectionLine is not compatible with SPECT attenuation correction !");
00437       return 1;
00438     }
00439     // Check that the projector is compatible with SPECT with attenuation correction
00440     if (!mp_ProjectorManager->IsBackwardOperatorCompatibleWithSPECTAttenuationCorrection())
00441     {
00442       Cerr("***** oIterativeAlgorithm::StepBeforeIterationLoop() -> The backward projector is not compatible with SPECT attenuation correction !" << endl);
00443       return 1;
00444     }
00445   }
00446 
00447   // Instantiate all the required images from the oImageSpace
00448   mp_ImageSpace->InstantiateImage();
00449   mp_ImageSpace->InstantiateForwardImage();
00450   mp_ImageSpace->InstantiateBackwardImage(mp_OptimizerManager->GetNbBackwardImages());
00451   mp_ImageSpace->InstantiateSensitivityImage(m_pathToSensitivityImg);
00452   mp_ImageSpace->InstantiateOutputImage();
00453   mp_ImageSpace->InstantiateVisitedVoxelsImage();
00454   mp_DeformationManager->InstantiateImageForDeformation(mp_ImageSpace);
00455 
00456   // Main image and sensitivity image initialization
00457   if (mp_ImageSpace->InitImage(m_pathToInitialImg, mp_OptimizerManager->GetInitialValue()) )
00458   {
00459     Cerr("***** oIterativeAlgorithm::StepBeforeIterationLoop() -> An error occured while reading the initialization image !" << endl);
00460     return 1;
00461   }
00462 
00463   if (mp_ImageSpace->InitAttenuationImage(m_pathToAtnImg) )
00464   {
00465     Cerr("***** oIterativeAlgorithm::StepBeforeIterationLoop()-> Error during attenuation image initialization !" << endl);  
00466     return 1;
00467   }
00468 
00469   if (mp_ImageSpace->InitSensitivityImage(m_pathToSensitivityImg))
00470   {
00471     Cerr("***** oIterativeAlgorithm::StepBeforeIterationLoop() -> An error occured while initializing the sensitivity image !" << endl);
00472     return 1;
00473   }
00474 
00475   if (mp_ImageSpace->InitAnatomicalImage(m_pathToAnatomicalImg))
00476   {
00477     Cerr("***** oIterativeAlgorithm::StepBeforeIterationLoop()-> Error during anatomical image initialization !" << endl);
00478     return 1;
00479   }
00480 
00481   if (mp_ImageSpace->InitMaskImage(m_pathToMaskImg))
00482   {
00483     Cerr("***** oIterativeAlgorithm::StepBeforeIterationLoop()-> Error during mask image initialization !" << endl);
00484     return 1;
00485   }
00486 
00487   // End
00488   return 0;
00489 }
00490 
00491 // =====================================================================
00492 // ---------------------------------------------------------------------
00493 // ---------------------------------------------------------------------
00494 // =====================================================================
00495 /*
00496   \fn StepBeforeSubsetLoop
00497   \param a_iteration : iteration index
00498   \brief This function is called before starting the subset loop.
00499   \return 0 if success, positive value otherwise.
00500 */
00501 int oIterativeAlgorithm::StepBeforeSubsetLoop(int a_iteration)
00502 {
00503   if (m_verbose>=3) Cout("oIterativeAlgorithm::StepBeforeSubsetLoop ... " << endl);
00504     
00505   // End
00506   return 0;
00507 }
00508 
00509 // =====================================================================
00510 // ---------------------------------------------------------------------
00511 // ---------------------------------------------------------------------
00512 // =====================================================================
00513 /*
00514   \fn StepPreProcessInsideSubsetLoop
00515   \param a_iteration : iteration index
00516   \param a_subset : subset index
00517   \brief This function is called right after starting the subset loop.
00518          Apply any kind of processing on the forward image before projections
00519   \details Copy current main image into forward image matrix
00520            Reinitialize backward image and 4D gating indices
00521            Apply image processing/convolution on the forward image matrix
00522            (image to be projeted)
00523   \return 0 if success, positive value otherwise.
00524 */
00525 int oIterativeAlgorithm::StepPreProcessInsideSubsetLoop(int a_iteration, int a_subset)
00526 {
00527   if (m_verbose>=3) Cout("oIterativeAlgorithm::StepPreProcessInsideSubsetLoop ... " << endl);
00528     
00529   // Reinitialize 4D gate indexes
00530   mp_ID->ResetCurrentDynamicIndices();
00531 
00532   // Initialize the correction backward image(s)
00533   mp_ImageSpace->InitBackwardImage();
00534   mp_DeformationManager->InitImageForDeformation(mp_ImageSpace);
00535 
00536   // Copy current image in forward-image buffer (apply deformation if needed)
00537   mp_ImageSpace->PrepareForwardImage() ; 
00538 
00539   // Apply image processing to forward image
00540   if (mp_ImageProcessingManager->ApplyProcessingForward(mp_ImageSpace))
00541   {
00542     Cerr("***** oIterativeAlgorithm::StepPreProcessInsideSubsetLoop() -> A problem occured while applyin image processing to forward image !" << endl);
00543     return 1;
00544   }
00545 
00546   // Apply convolver to forward image
00547   if (mp_ImageConvolverManager->ConvolveForward(mp_ImageSpace))
00548   {
00549     Cerr("***** oIterativeAlgorithm::StepPreProcessInsideSubsetLoop() -> A problem occured while applying image convolver to forward image !" << endl);
00550     return 1;
00551   }
00552 
00553   // Apply deformation onto forward images. Basically in this situation, it will be used in the case of gating
00554   // where all gates are reconstructed into one single corrected image. Thus, one have to move back the forward
00555   // image into its original position.
00556   mp_DeformationManager->ApplyDeformationsToForwardImage(mp_ImageSpace);
00557 
00558   // Call the pre-event loop function from the optimizer manager
00559   mp_OptimizerManager->PreDataUpdateStep(a_iteration, m_nbIterations, a_subset, mp_nbSubsets[a_iteration]);
00560 
00561   // End
00562   return 0;
00563 }
00564 
00565 // =====================================================================
00566 // ---------------------------------------------------------------------
00567 // ---------------------------------------------------------------------
00568 // =====================================================================
00569 /*
00570   \fn StepInnerLoopInsideSubsetLoop
00571   \param a_iteration : iteration index
00572   \param a_subset : subset index
00573   \param a_bed : bed position
00574   \brief This function is called inside the subset loop and manages the main loop over the events
00575          The loop over the events is multithreaded, and involves a thread lock in the case of image-based deformation
00576   \details Step 1: Get the current event for that thread index
00577            Step 2: Call the dynamic switch function that updates the current frame and gate numbers, and also detects involuntary patient motion
00578                    Perform image-based deformation if needed (thread lock is required)
00579            Step 3: Compute the projection line
00580            Step 4: Optimize in the data space (forward-proj, update, backward-proj)
00581   \todo  Check the correct implementation of thread-locked operation on different architectures
00582   \return 0 if success, positive value otherwise.
00583 */
00584 int oIterativeAlgorithm::StepInnerLoopInsideSubsetLoop(int a_iteration, int a_subset, int a_bed)
00585 {
00586   // Verbose
00587   if (m_verbose>=2) Cout("oIterativeAlgorithm::StepInnerLoopInsideSubsetLoop() -> Start loop over events" << endl << flush);
00588 
00589   // Progression (increments of 2%)
00590   if (m_verbose>=2 && mp_ID->GetMPIRank()==0)
00591   {
00592     cout << "0   10%  20%  30%  40%  50%  60%  70%  80%  90%  100%" << endl;
00593     cout << "|----|----|----|----|----|----|----|----|----|----|" << endl;
00594     cout << "|" << flush;
00595   }
00596   
00597   int progression_percentage_old = 0;
00598   int progression_nb_bars = 0;
00599   uint64_t progression_printing_index = 0;
00600 
00601   // Compute start and stop indices taking MPI into account (the vDataFile does that)
00602   int64_t index_start = 0;
00603   int64_t index_stop  = 0;
00604   m2p_DataFile[a_bed]->GetEventIndexStartAndStop(&index_start, &index_stop, a_subset, mp_nbSubsets[a_iteration]);
00605 
00606   // Multi-threading with OpenMP
00607   m_releaseThreads = false;
00608   m_nbThreadsWaiting = 0;
00609 
00610   // Reset the file buffer range before launching the loop over the datafile (this is done only if the percentage load is under 100)
00611   m2p_DataFile[a_bed]->ResetBufferRange();
00612 
00613   // Synchronize MPI processes
00614   #ifdef CASTOR_MPI
00615   MPI_Barrier(MPI_COMM_WORLD);
00616   #endif
00617 
00618   // Set the number of threads for projections (right after this loop, we set back the number of threads for image computations)
00619   #ifdef CASTOR_OMP
00620   omp_set_num_threads(mp_ID->GetNbThreadsForProjection());
00621   #endif
00622 
00623   // This boolean is used to report any problem inside the parallel loop
00624   bool problem = false;
00625 
00626   // Compute the index limit over which we consider that threads have finished the loop
00627   // (to be valid, the omp loop need to use a static scheduling with a chunck size of 1)
00628   // The number of subsets times the number of threads is the loop increment for a given thread
00629   // OBSint64_t index_limit = index_stop - 1 - index_start - 2*((int64_t)(mp_nbSubsets[a_iteration] * mp_ID->GetNbThreadsForProjection()));
00630 
00631   // Compute the last index that each thread will manage here (this is to know when it has finished reading the datafile).
00632   // Note that everything here assumes a static scheduling with a chunck size of 1, so do not change that in the parallel loop below!
00633   int64_t* p_last_index = (int64_t*)malloc(mp_ID->GetNbThreadsForProjection()*sizeof(int64_t));
00634   for (int th=0; th<mp_ID->GetNbThreadsForProjection(); th++)
00635   {
00636     int64_t loop_increment = mp_nbSubsets[a_iteration];
00637     int64_t increment_for_this_thread = loop_increment * mp_ID->GetNbThreadsForProjection();
00638     int64_t index_start_for_this_thread = index_start + th * loop_increment;
00639     int64_t nb_loop_pass_through = (index_stop - 1 - index_start_for_this_thread) / increment_for_this_thread;
00640     p_last_index[th] = index_start_for_this_thread + nb_loop_pass_through * increment_for_this_thread;
00641   }
00642 
00643   // Launch the loop with precomputed start and stop and using a step equal to the number of subsets
00644   int64_t index;
00645   // Keep the static scheduling with a chunk size at 1, it is important
00646   #pragma omp parallel for private(index) schedule(static, 1)
00647   for ( index = index_start  ;  index < index_stop  ;  index += mp_nbSubsets[a_iteration] )
00648   {              
00649     // Get the thread index
00650     int th = 0;
00651     #ifdef CASTOR_OMP
00652     th = omp_get_thread_num();
00653     #endif
00654 
00655     // Print progression (do not log out with Cout here)
00656     if (m_verbose>=2 && th==0 && mp_ID->GetMPIRank()==0)
00657     {
00658       if (progression_printing_index%1000==0)
00659       {
00660         int progression_percentage_new = ((int)( (((float)(index-index_start+1))/((float)(index_stop-index_start)) ) * 
00661                                                 ( ((float)(a_bed+1))/((float)m_nbBeds) ) * 100. ));
00662         if (progression_percentage_new>=progression_percentage_old+2) // Increments of 2%
00663         {
00664           int nb_steps = (progression_percentage_new-progression_percentage_old)/2;
00665           for (int i=0; i<nb_steps; i++)
00666           {
00667             cout << "-" << flush;
00668             progression_nb_bars++;
00669           }
00670           progression_percentage_old += nb_steps*2;
00671         }
00672       }
00673       progression_printing_index++;
00674     }
00675 
00676     // Step 1: Get the current event for that thread index
00677     #ifdef CASTOR_DEBUG
00678     if (m_verbose>=4) Cout("oIterativeAlgorithm::StepInnerLoopInsideSubsetLoop()-> Step1: Get current event for that thread index " << endl);
00679     #endif
00680     #ifdef CASTOR_MPI
00681     vEvent* event = m2p_DataFile[a_bed]->GetEventWithoutOrderAssumption(index, th);
00682     #else
00683     //OBS    vEvent* event = m2p_DataFile[a_bed]->GetEventWithAscendingOrderAssumption(index, index_limit, th);
00684     // This function is not compatible with MPI, as the first index of the first thread may not be the index of the first event in the portion
00685     // of the datafile manage by the MPI instance (due to subsets). Will be investigated in future releases.
00686     vEvent* event = m2p_DataFile[a_bed]->GetEventWithAscendingOrderAssumption(index, p_last_index[th], th);
00687     #endif
00688 
00689     if (event==NULL)
00690     {
00691       Cerr("***** oIterativeAlgorithm::StepInnerLoopInsideSubsetLoop() -> An error occured while getting the event from index "
00692         << index << " (thread " << th << ") !" << endl);
00693       // Specify that there was a problem
00694       problem = true;
00695       // We must continue here because we are inside an OpenMP loop
00696       continue;
00697     }
00698 
00699     // Step 2: Call the dynamic switch function that updates the current frame and gate numbers, and also detects involuntary patient motion
00700     #ifdef CASTOR_DEBUG
00701     if (m_verbose>=4)
00702     {
00703       Cout("oIterativeAlgorithm::StepInnerLoopInsideSubsetLoop()-> Step2: Check for Dynamic event (frame/gate switch, image-based deformation " << endl);
00704     }
00705     #endif
00706     int dynamic_switch_value = mp_ID->DynamicSwitch(index, event->GetTimeInMs(), a_bed, th);
00707     
00708     // If the DYNAMIC_SWITCH_CONTINUE is returned, then it means that we are not yet at the first frame
00709     if ( dynamic_switch_value == DYNAMIC_SWITCH_CONTINUE )
00710     {
00711       // Then we just skip this event
00712       continue;
00713     }
00714     // Else, if the DYNAMIC_SWITCH_DEFORMATION is returned, then it means that a change of gate or involuntary motion has occured
00715     // and is associated to a deformation
00716     else if ( dynamic_switch_value == DYNAMIC_SWITCH_DEFORMATION )
00717     {
00718       // With multi-threads, we should wait all threads to be there to perform the deformation
00719       #ifdef CASTOR_OMP
00720       // Count the number of threads reaching this point
00721       ThreadBarrierIncrement();
00722       // Loop to lock the threads until the m_releaseThreads condition is enabled
00723       while (ThreadBarrierFlag())
00724       {
00725         // Allow thread 0 to enter once all threads are in the loop
00726         if ( (th==0) && ThreadBarrierCheck() )
00727         {
00728           // Perform here any deformation on the forward image.
00729           mp_DeformationManager->PerformDeformation(mp_ImageSpace);
00730           // Release the threads and set the thread counter to 0
00731           ThreadBarrierSetOff();
00732         }
00733       }
00734       // Count the number of threads reaching this point
00735       ThreadBarrierIncrement();
00736       // Set the thread lock condition once all threads reached this point
00737       if (ThreadBarrierCheck()) ThreadBarrierSetOn();
00738       #else
00739       // Perform here any resp related deformations on the forward image
00740       mp_DeformationManager->PerformDeformation(mp_ImageSpace);
00741       #endif
00742     }
00743 
00744     // Step 3: Compute the projection line
00745     #ifdef CASTOR_DEBUG
00746     if (m_verbose>=4) Cout("oIterativeAlgorithm::StepInnerLoopInsideSubsetLoop()-> Step3: Compute the projection line " << endl);
00747     #endif
00748     oProjectionLine *line = mp_ProjectorManager->ComputeProjectionLine(event, th);
00749     if (line==NULL)
00750     {
00751       Cerr("***** oIterativeAlgorithm::StepInnerLoopInsideSubsetLoop() -> A problem occured while computing the projection line !" << endl);
00752       // Specify that there was a problem
00753       problem = true;
00754       // We must continue here because we are inside an OpenMP loop
00755       continue;
00756     }
00757 
00758     // Step 4: Optimize in the data space (forward-proj, update, backward-proj)
00759     #ifdef CASTOR_DEBUG
00760     if (m_verbose>=4) Cout("oIterativeAlgorithm::StepInnerLoopInsideSubsetLoop()-> Step4: Optimize in the data space " << endl);
00761     #endif
00762     if (line->NotEmptyLine()) mp_OptimizerManager->DataUpdateStep( line, 
00763                                                                    mp_ImageSpace, 
00764                                                                    event, 
00765                                                                    a_bed, 
00766                                                                    mp_ID->GetCurrentTimeFrame(th),
00767                                                                    mp_ID->GetCurrentRespImage(th), 
00768                                                                    mp_ID->GetCurrentCardImage(th),
00769                                                                    a_iteration, 
00770                                                                    th);
00771   } // End of indices loop (OpenMP stops here)
00772 
00773   // Synchronize MPI processes
00774   #ifdef CASTOR_MPI
00775   MPI_Barrier(MPI_COMM_WORLD);
00776   #endif
00777 
00778   // Set back the number of threads for image computation
00779   #ifdef CASTOR_OMP
00780   omp_set_num_threads(mp_ID->GetNbThreadsForImageComputation());
00781   #endif
00782 
00783   // Free the last_index table
00784   free(p_last_index);
00785 
00786   // End of progression printing (do not log out with Cout here)
00787   if (m_verbose>=2 && mp_ID->GetMPIRank()==0)
00788   {
00789     int progression_total_bars = 49;
00790     for (int i=0; i<progression_total_bars-progression_nb_bars; i++) cout << "-";
00791     cout << "|" << endl;
00792   }
00793 
00794   // If a problem was encountered, then report it here
00795   if (problem)
00796   {
00797     Cerr("***** oIterativeAlgorithm::StepInnerLoopInsideSubsetLoop() -> A problem occured inside the parallel loop over events !" << endl);
00798     return 1;
00799   }
00800 
00801   // End
00802   return 0;
00803 }
00804 
00805 // =====================================================================
00806 // ---------------------------------------------------------------------
00807 // ---------------------------------------------------------------------
00808 // =====================================================================
00809 /*
00810   \fn StepPreProcessInsideSubsetLoop
00811   \param a_iteration : iteration index
00812   \param a_subset : subset index
00813   \brief This function is called right after starting the subset loop.
00814          Apply any kind of image processing on the backward image and
00815          main image after backprojections
00816   \details Synchronize parallel results
00817            Apply image deformation/processing/convolution on the backward image
00818            Update the image using the optimizer functions
00819            Apply dynamic model/image processing/convolution on the main image
00820   \return 0 if success, positive value otherwise.
00821 */
00822 int oIterativeAlgorithm::StepPostProcessInsideSubsetLoop(int a_iteration, int a_subset)
00823 {
00824   if (m_verbose>=3) Cout("oIterativeAlgorithm::StepPostProcessInsideSubsetLoop ... " << endl);
00825     
00826   // Merge parallel results
00827   mp_ImageSpace->Reduce();
00828 
00829   // Perform here any image-based deformations related to motion on the backward image.
00830   mp_DeformationManager->ApplyDeformationsToBackwardImage(mp_ImageSpace);
00831 
00832   // Apply convolver to backward images and sensitivity-if-needed
00833   if (mp_ImageConvolverManager->ConvolveBackward(mp_ImageSpace))
00834   {
00835     Cerr("***** oIterativeAlgorithm::StepPostProcessInsideSubsetLoop() -> A problem occured while applying convolver to backward images !" << endl);
00836     return 1;
00837   }
00838 
00839   // Call the post data update step function from the optimizer manager
00840   mp_OptimizerManager->PostDataUpdateStep(a_iteration, m_nbIterations, a_subset, mp_nbSubsets[a_iteration]);
00841 
00842   // Optimize in the image space (apply corrections, MAP and sensitivity); pass the number of subsets for list-mode sensitivity scaling
00843   mp_OptimizerManager->ImageUpdateStep(mp_ImageSpace, a_iteration, mp_nbSubsets[a_iteration]);
00844 
00845   // Apply convolver to current estime images
00846   if (mp_ImageConvolverManager->ConvolveIntra(mp_ImageSpace))
00847   {
00848     Cerr("***** oIterativeAlgorithm::StepPostProcessInsideSubsetLoop() -> A problem occured while applying convolver to current estimate images !" << endl);
00849     return 1;
00850   }
00851 
00852   // Post-update Dynamic Modeling step (if enabled). Manage either linear/non linear dynamic model (physiological or not)
00853   if (mp_DynamicModelManager->ApplyDynamicModel(mp_ImageSpace, a_iteration, mp_nbSubsets[a_iteration]))
00854   {
00855     Cerr("***** oIterativeAlgorithm::StepPostProcessInsideSubsetLoop() -> A problem occured while applying dynamic model to current estimate images !" << endl);
00856     return 1;
00857   }
00858   
00859   // Apply image processing to current estime images
00860   if (mp_ImageProcessingManager->ApplyProcessingIntra(mp_ImageSpace))
00861   {
00862     Cerr("***** oIterativeAlgorithm::StepPostProcessInsideSubsetLoop() -> A problem occured while applying image processing to current estimate images !" << endl);
00863     return 1;
00864   }
00865 
00866   // Save the sensitivity image in histogram mode, if asked for
00867   if (mp_ID->GetMPIRank()==0 && mp_outputIterations[a_iteration] && m_saveSensitivityHistoFlag && m2p_DataFile[0]->GetDataMode()==MODE_HISTOGRAM)
00868   {
00869     // Get output manager to build the file name
00870     sOutputManager* p_output_manager = sOutputManager::GetInstance();
00871     // Build the file name
00872     string temp_sens = p_output_manager->GetPathName() + p_output_manager->GetBaseName();
00873     stringstream temp_it; temp_it << a_iteration + 1;
00874     stringstream temp_ss; temp_ss << a_subset + 1;
00875     temp_sens.append("_it").append(temp_it.str()).append("_ss").append(temp_ss.str()).append("_sensitivity");
00876     // Save sensitivity
00877     mp_ImageSpace->LMS_SaveSensitivityImage(temp_sens, mp_DeformationManager);
00878   }
00879 
00880   // Save the current image estimate if asked for
00881   if (mp_ID->GetMPIRank()==0 && mp_outputIterations[a_iteration] && m_saveImageAfterSubsets)
00882   {
00883     // Verbose
00884     if (m_verbose>=1) Cout("oIterativeAlgorithm::StepPostProcessInsideSubsetLoop() -> Save image at iteration " << a_iteration+1 << " for subset " << a_subset+1 << endl);
00885     // Build image from basis functions
00886     mp_ImageSpace->ComputeOutputImage();
00887     // Apply post-convolution if needed
00888     if (mp_ImageConvolverManager->ConvolvePost(mp_ImageSpace))
00889     {
00890       Cerr("***** oIterativeAlgorithm::StepPostProcessInsideSubsetLoop() -> A problem occured while convolving the output image !" << endl);
00891       return 1;
00892     }
00893     // Apply post-processing if needed
00894     if (mp_ImageProcessingManager->ApplyProcessingPost(mp_ImageSpace))
00895     {
00896       Cerr("***** oIterativeAlgorithm::StepPostProcessInsideSubsetLoop() -> A problem occured while applying image processing the output image !" << endl);
00897       return 1;
00898     }
00899     // Apply output transaxial FOV masking
00900     if (mp_ImageSpace->ApplyOutputFOVMasking())
00901     {
00902       Cerr("***** oIterativeAlgorithm::StepPostProcessInsideSubsetLoop() -> A problem occured while applying output FOV masking !" << endl);
00903       return 1;
00904     }
00905     // Apply output flip
00906     if (mp_ImageSpace->ApplyOutputFlip())
00907     {
00908       Cerr("***** oIterativeAlgorithm::StepPostProcessInsideSubsetLoop() -> A problem occured while applying output flip !" << endl);
00909       return 1;
00910     }
00911     // Save output image
00912     if (mp_ImageSpace->SaveOutputImage(a_iteration, a_subset))
00913     {
00914       Cerr("***** oIterativeAlgorithm::StepPostProcessInsideSubsetLoop() -> A problem occured while saving output image !" << endl);
00915       return 1;
00916     }
00917   }
00918 
00919   // End
00920   return 0;
00921 }
00922 
00923 // =====================================================================
00924 // ---------------------------------------------------------------------
00925 // ---------------------------------------------------------------------
00926 // =====================================================================
00927 /*
00928   \fn StepAfterSubsetLoop
00929   \param a_iteration : iteration index
00930   \brief This function is called after finishing the subset loop.
00931   \details Clean the main images from never visited voxels
00932            Apply post-convolution/post-processing if needed
00933            Write output images on disk as requested by the user
00934   \todo : save parametric images using intrinsic basis functions ?
00935   \return 0 if success, positive value otherwise.
00936 */
00937 int oIterativeAlgorithm::StepAfterSubsetLoop(int a_iteration)
00938 {
00939   if (m_verbose>=3) Cout("oIterativeAlgorithm::StepAfterSubsetLoop ... " << endl);
00940   
00941   // Clean never visited voxels
00942   mp_ImageSpace->CleanNeverVisitedVoxels();
00943   // Save the main image
00944   if (mp_ID->GetMPIRank()==0 && mp_outputIterations[a_iteration])
00945   {
00946     if (m_verbose>=1) Cout("oIterativeAlgorithm::StepAfterSubsetLoop() -> Save image at iteration " << a_iteration+1 << endl);
00947     // Build image from basis functions
00948     mp_ImageSpace->ComputeOutputImage();
00949     // Apply post-convolution if needed
00950     if (mp_ImageConvolverManager->ConvolvePost(mp_ImageSpace))
00951     {
00952       Cerr("***** oIterativeAlgorithm::StepAfterSubsetLoop() -> A problem occured while convolving the output image !" << endl);
00953       return 1;
00954     }
00955     // Apply post-processing if needed
00956     if (mp_ImageProcessingManager->ApplyProcessingPost(mp_ImageSpace))
00957     {
00958       Cerr("***** oIterativeAlgorithm::StepAfterSubsetLoop() -> A problem occured while applying image processing the output image !" << endl);
00959       return 1;
00960     }
00961     // Save Dynamic images
00962     if (mp_DynamicModelManager->SaveParametricImages(a_iteration))
00963     {
00964       Cerr("***** oIterativeAlgorithm::StepAfterSubsetLoop() -> A problem occured while saving parametric images related to the dynamic model !" << endl);
00965       return 1;
00966     }
00967     // Todo : save parametric images using intrinsic basis functions
00968     // Apply output transaxial FOV masking
00969     if (mp_ImageSpace->ApplyOutputFOVMasking())
00970     {
00971       Cerr("***** oIterativeAlgorithm::StepAfterSubsetLoop() -> A problem occured while applying output FOV masking !" << endl);
00972       return 1;
00973     }
00974     // Apply output flip
00975     if (mp_ImageSpace->ApplyOutputFlip())
00976     {
00977       Cerr("***** oIterativeAlgorithm::StepAfterSubsetLoop() -> A problem occured while applying output flip !" << endl);
00978       return 1;
00979     }
00980     // Save output image
00981     if (mp_ImageSpace->SaveOutputImage(a_iteration))
00982     {
00983       Cerr("***** oIterativeAlgorithm::StepAfterSubsetLoop() -> A problem occured while saving output image !" << endl);
00984       return 1;
00985     }
00986   }
00987 
00988   // End
00989   return 0;
00990 }
00991 
00992 // =====================================================================
00993 // ---------------------------------------------------------------------
00994 // ---------------------------------------------------------------------
00995 // =====================================================================
00996 /*
00997   \fn StepAfterIterationLoop
00998   \brief This function is called at the end of the IterateCPU function.
00999   \details Free Memory for the imageSpace and
01000            some managers
01001   \return 0 if success, positive value otherwise.
01002 */
01003 int oIterativeAlgorithm::StepAfterIterationLoop()
01004 {
01005   if (m_verbose>=2) Cout("oIterativeAlgorithm::StepAfterIterationLoop ... " << endl);
01006   
01007   // Deallocate everything
01008   mp_DeformationManager->DeallocateImageForDeformation(mp_ImageSpace);
01009   mp_ImageSpace->DeallocateBackwardImage();
01010   mp_ImageSpace->DeallocateSensitivityImage();
01011   mp_ImageSpace->DeallocateAnatomicalImage();
01012   mp_ImageSpace->DeallocateMaskImage();
01013   mp_ImageSpace->DeallocateForwardImage();
01014   mp_ImageSpace->DeallocateImage();
01015   mp_ImageSpace->DeallocateOutputImage();
01016   mp_ImageSpace->DeallocateVisitedVoxelsImage();
01017 
01018   // Normal end
01019   return 0;
01020 }
01021 
01022 // =====================================================================
01023 // ---------------------------------------------------------------------
01024 // ---------------------------------------------------------------------
01025 // =====================================================================
01026 /*
01027   \fn InitSpecificOptions
01028   \param a_specificOptions
01029   \brief Set the selected output iterations
01030   \details Not Implemented yet
01031   \return 0
01032 */
01033 int oIterativeAlgorithm::InitSpecificOptions(string a_specificOptions)
01034 {
01035   if (m_verbose>=2) Cout("oIterativeAlgorithm::InitSpecificOptions ... " << endl);
01036     
01037   return 0;
01038 }
01039 
01040 // =====================================================================
01041 // ---------------------------------------------------------------------
01042 // ---------------------------------------------------------------------
01043 // =====================================================================
01044 // ----- Functions dedicated to barrier for multithreading ----- 
01045 // TODO we should keep in mind that different compiler may deal differently with OpenMP 
01046 // (as the compiler may take liberties and optimize shared variables as register variables, 
01047 // leading to non-concurrent observations of the variable. 
01048 // And this is not cool as this can completely stop the reconstruction process)
01049 // The omp-flush directives should prevent that, but further tests may be required
01050 
01051 /*
01052   \fn ThreadBarrierIncrement
01053   \brief Increment (thread safe) the m_nbThreadsWaiting variable.
01054 */
01055 void oIterativeAlgorithm::ThreadBarrierIncrement()
01056 {
01057   #ifdef CASTOR_DEBUG
01058   if (m_verbose>=4) Cout("oIterativeAlgorithm::ThreadBarrierIncrement ... " << endl);
01059   #endif
01060   
01061   #pragma omp critical(increment_waiting_threads)
01062   {
01063     m_nbThreadsWaiting++;
01064   }
01065 }
01066 
01067 // =====================================================================
01068 // ---------------------------------------------------------------------
01069 // ---------------------------------------------------------------------
01070 // =====================================================================
01071 /*
01072   \fn ThreadBarrierFlag
01073   \brief Check if the m_releaseThreads boolean is enabled or not 
01074   \return true if the threads can be released, false otherwise
01075 */
01076 bool oIterativeAlgorithm::ThreadBarrierFlag()
01077 {
01078   #ifdef CASTOR_DEBUG
01079   if (m_verbose>=4) Cout("oIterativeAlgorithm::ThreadBarrierFlag ... " << endl);
01080   #endif
01081   
01082   // Check any change in m_releaseThreads
01083   #pragma omp flush(m_releaseThreads)
01084   return !m_releaseThreads;
01085 }
01086 
01087 // =====================================================================
01088 // ---------------------------------------------------------------------
01089 // ---------------------------------------------------------------------
01090 // =====================================================================
01091 /*
01092   \fn ThreadBarrierCheck
01093   \brief Check if all the threads are currently in waiting condition
01094   \return true if all the threads are waiting, false otherwise
01095 */
01096 bool oIterativeAlgorithm::ThreadBarrierCheck()
01097 { 
01098   #ifdef CASTOR_DEBUG
01099   if (m_verbose>=4) Cout("oIterativeAlgorithm::ThreadBarrierCheck ... " << endl);
01100   #endif
01101   
01102   #pragma omp flush(m_nbThreadsWaiting) // Check any change in m_nbThreadsWaiting
01103   return (m_nbThreadsWaiting==mp_ID->GetNbThreadsForProjection());
01104 }
01105 
01106 // =====================================================================
01107 // ---------------------------------------------------------------------
01108 // ---------------------------------------------------------------------
01109 // =====================================================================
01110 /*
01111   \fn ThreadBarrierSetOff
01112   \brief Disable the thread locking variable (thread safe), and reset the number of waiting threads to 0
01113 */
01114 void oIterativeAlgorithm::ThreadBarrierSetOff()
01115 {
01116   #ifdef CASTOR_DEBUG
01117   if (m_verbose>=4) Cout("oIterativeAlgorithm::ThreadBarrierSetOff ... " << endl);
01118   #endif
01119   
01120   m_releaseThreads = true;
01121   #pragma omp flush(m_releaseThreads)   // Make sure the value of m_releaseThreads is propagated to other threads
01122   m_nbThreadsWaiting = 0;
01123   #pragma omp flush(m_nbThreadsWaiting)   // Same for m_nbThreadsWaiting
01124 }
01125 
01126 // =====================================================================
01127 // ---------------------------------------------------------------------
01128 // ---------------------------------------------------------------------
01129 // =====================================================================
01130 /*
01131   \fn ThreadBarrierSetOn
01132   \brief Enable the thread locking variable (thread safe), and reset the number of waiting threads to 0
01133 */
01134 void oIterativeAlgorithm::ThreadBarrierSetOn()
01135 {
01136   #ifdef CASTOR_DEBUG
01137   if (m_verbose>=4) Cout("oIterativeAlgorithm::ThreadBarrierSetOn ... " << endl);
01138   #endif
01139   
01140   m_releaseThreads = false;
01141   #pragma omp flush(m_releaseThreads)   // Make sure the value of m_releaseThreads is propagated to other threads
01142   m_nbThreadsWaiting = 0;
01143   #pragma omp flush(m_nbThreadsWaiting)   // Same for m_nbThreadsWaiting
01144 }
 All Classes Files Functions Variables Typedefs Defines