![]() |
CASToR
1.0
Tomographic Reconstruction (PET/SPECT)
|
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 }