// initialize and parse the command line parameters bool Initialize(size_t argc, LPCTSTR* argv) { // initialize log and console OPEN_LOG(); OPEN_LOGCONSOLE(); // group of options allowed only on command line boost::program_options::options_description generic("Generic options"); generic.add_options() ("help,h", "produce this help message") ("working-folder,w", boost::program_options::value<std::string>(&WORKING_FOLDER), "working directory (default current directory)") ("config-file,c", boost::program_options::value<std::string>(&OPT::strConfigFileName)->default_value(APPNAME _T(".cfg")), "file name containing program options") ("archive-type", boost::program_options::value<unsigned>(&OPT::nArchiveType)->default_value(2), "project archive type: 0-text, 1-binary, 2-compressed binary") ("process-priority", boost::program_options::value<int>(&OPT::nProcessPriority)->default_value(-1), "process priority (below normal by default)") ("max-threads", boost::program_options::value<unsigned>(&OPT::nMaxThreads)->default_value(0), "maximum number of threads (0 for using all available cores)") #if TD_VERBOSE != TD_VERBOSE_OFF ("verbosity,v", boost::program_options::value<int>(&g_nVerbosityLevel)->default_value( #if TD_VERBOSE == TD_VERBOSE_DEBUG 3 #else 2 #endif ), "verbosity level") #endif ; // group of options allowed both on command line and in config file boost::program_options::options_description config("Main options"); config.add_options() ("input-file,i", boost::program_options::value<std::string>(&OPT::strInputFileName), "input filename containing camera poses and image list") ("output-file,o", boost::program_options::value<std::string>(&OPT::strOutputFileName), "output filename for storing the mesh") ("output-image-folder", boost::program_options::value<std::string>(&OPT::strOutputImageFolder)->default_value("undistorted_images"), "output folder to store undistorted images") ; boost::program_options::options_description cmdline_options; cmdline_options.add(generic).add(config); boost::program_options::options_description config_file_options; config_file_options.add(config); boost::program_options::positional_options_description p; p.add("input-file", -1); try { // parse command line options boost::program_options::store(boost::program_options::command_line_parser((int)argc, argv).options(cmdline_options).positional(p).run(), OPT::vm); boost::program_options::notify(OPT::vm); INIT_WORKING_FOLDER; // parse configuration file std::ifstream ifs(MAKE_PATH_SAFE(OPT::strConfigFileName)); if (ifs) { boost::program_options::store(parse_config_file(ifs, config_file_options), OPT::vm); boost::program_options::notify(OPT::vm); } } catch (const std::exception& e) { LOG(e.what()); return false; } // initialize the log file OPEN_LOGFILE(MAKE_PATH(APPNAME _T("-")+Util::getUniqueName(0)+_T(".log")).c_str()); // print application details: version and command line Util::LogBuild(); LOG(_T("Command line:%s"), Util::CommandLineToString(argc, argv).c_str()); // validate input Util::ensureValidPath(OPT::strInputFileName); Util::ensureUnifySlash(OPT::strInputFileName); if (OPT::vm.count("help") || OPT::strInputFileName.IsEmpty()) { boost::program_options::options_description visible("Available options"); visible.add(generic).add(config); GET_LOG() << visible; } if (OPT::strInputFileName.IsEmpty()) return false; // initialize optional options if (OPT::strInputFileName.IsEmpty()) return false; Util::ensureValidPath(OPT::strOutputFileName); Util::ensureUnifySlash(OPT::strOutputFileName); Util::ensureUnifySlash(OPT::strOutputImageFolder); Util::ensureDirectorySlash(OPT::strOutputImageFolder); if (OPT::strOutputFileName.IsEmpty()) OPT::strOutputFileName = Util::getFullFileName(OPT::strInputFileName) + MVS_EXT; // initialize global options Process::setCurrentProcessPriority((Process::Priority)OPT::nProcessPriority); #ifdef _USE_OPENMP if (OPT::nMaxThreads != 0) omp_set_num_threads(OPT::nMaxThreads); #endif #ifdef _USE_BREAKPAD // start memory dumper MiniDumper::Create(APPNAME, WORKING_FOLDER); #endif return true; }
vector< SLargeScaleOpt > ParameterOptimizationServer< SamplePointT, SamplePointGrid > ::GetLargeVolumeCandidates( const SEnergyOpt &oStartEnergyLoc, const vector<SDetParamMsg> &vDetParams, const vector<SStepSizeInfo> & vOptMaxDeviation ) { typedef GeometricOptimizationBase<SamplePointT> Base; VoxelQueue.RandomizeReset(); vector<SamplePointT> oLargeSearchList; VoxelQueue.Get( LocalSetup.InputParameters().nParamMCGlobalSearchElements, std::back_inserter( oLargeSearchList ) ); vector<SLargeScaleOpt> vCandidates; vector<vector<SDetParamMsg> > oDetParamList( nProcessingElements ); vector<Float> oEnergyList ( nProcessingElements ); GET_LOG( osLogFile ) << "Large Scale Volume Candidate Search " << std::endl; GET_LOG( osLogFile ) << "Beam Energy " << oStartEnergyLoc.fBeamEnergy << std::endl; for( Size_Type i = 0; i < vOptMaxDeviation.size(); i ++ ) { GET_LOG( osLogFile ) << "---------------------" << std::endl; GET_LOG( osLogFile ) << "Euler Angles Steps: " << vOptMaxDeviation[i].oEulerSteps << std::endl; GET_LOG( osLogFile ) << "vOptMaxDeviation[i].fBeamCenterJ : " << vOptMaxDeviation[i].fBeamCenterJ << std::endl; GET_LOG( osLogFile ) << "vOptMaxDeviation[i].fBeamCenterK : " << vOptMaxDeviation[i].fBeamCenterK << std::endl; GET_LOG( osLogFile ) << "vOptMaxDeviation[i].xPos : " << vOptMaxDeviation[i].oDetectorPos.m_fX << std::endl; GET_LOG( osLogFile ) << "---------------------" << std::endl; } for( Int nClientID = 1; nClientID < nProcessingElements; nClientID ++ ) { vector<SDetParamMsg> vNewDetectorLoc; SEnergyOpt oNewEnergyLoc; if ( nClientID > 1 ) // have one of them start from the origin { vNewDetectorLoc = Base::RandomMoveDet( vDetParams, vOptMaxDeviation ); oNewEnergyLoc.fBeamEnergy = oStartEnergyLoc.fBeamEnergy + oRandomReal( -oStartEnergyLoc.fEnergyStep, oStartEnergyLoc.fEnergyStep ); } else { vNewDetectorLoc = vDetParams; oNewEnergyLoc.fBeamEnergy = oStartEnergyLoc.fBeamEnergy; } oEnergyList [ nClientID ] = oNewEnergyLoc.fBeamEnergy; oDetParamList[ nClientID ] = vNewDetectorLoc; Base::Comm.SendCommand( 0, nClientID, XDMParallel::SET_EXP_PARAM ); Base::SendExpParameters( nClientID, oNewEnergyLoc, vNewDetectorLoc ); GET_LOG( osLogFile ) << " Sending " << oLargeSearchList.size() << " voxels to client " << nClientID << std::endl; Base::Comm.SendCommand( 0, nClientID, XDMParallel::FIT_MC_LIST ); Base::Comm.SendWorkUnitList( nClientID, oLargeSearchList ); } // listen for result Int nClientsLeft = nProcessingElements - 1; vector<SLargeScaleOpt> oCandidateList; while( nClientsLeft > 0 ) { Int nCommand, nClientID; Base::Comm.RecvCommand( &nClientID, &nCommand ); RUNTIME_ASSERT( nCommand == XDMParallel::REPORT_MC_LIST, "Server ERROR! Wrong comamnd recv'd \n"); vector< SParamOptMsg<SamplePointT> > vOptResults; Base::Comm.RecvWorkUnitList( nClientID, vOptResults ); // calculate cost Float fCost = 0; Int nFitted = 0; Int nUnfitted = 0; for( Size_Type i = 0; i < vOptResults.size(); i ++ ) { if( vOptResults[i].bConverged ) { fCost += Float(1) - vOptResults[i].oOverlapInfo.fQuality; nFitted ++; } else { fCost += Float(1); nUnfitted ++; } } GET_LOG( osLogFile ) << "Client " << nClientID << " Fitted " << nFitted << " Unfitted " << nUnfitted << " cost = " << fCost << std::endl; if( fCost < static_cast<Float>( oLargeSearchList.size() ) ) { SLargeScaleOpt oNewPoint; oNewPoint.fCost = fCost / static_cast<Float>( oLargeSearchList.size() ); oNewPoint.fEnergy = oEnergyList[ nClientID ]; oNewPoint.vDetParams = oDetParamList[ nClientID ]; vCandidates.push_back( oNewPoint ); } nClientsLeft --; } GET_LOG( osLogFile ) << " Finished Large Scale Optimization: Num Candidates = " << vCandidates.size() << std::endl; return vCandidates; }
boost::tuple< std::vector< SDetParamMsg >, Float, SEnergyOpt > ParameterOptimizationServer< SamplePointT, SamplePointGrid > ::LocalParamOptimization( const SEnergyOpt & oEnergyLoc, const vector<SDetParamMsg> & vDetParams, const vector< SParamOptMsg<SamplePointT> > & vSamplePoints, const vector<SStepSizeInfo> & vClientStepSizeInfo, const vector<SStepSizeInfo> & vOptMaxDeviation ) { typedef GeometricOptimizationBase<SamplePointT> Base; SMonteCarloParam oMCParam; oMCParam.fTemperature = LocalSetup.InputParameters().fParameterMCTemperature; oMCParam.nCoolingSteps = LocalSetup.InputParameters().nNumParamOptSteps * LocalSetup.InputParameters().fCoolingFraction; oMCParam.fDTemperature = oMCParam.fTemperature / oMCParam.nCoolingSteps; oMCParam.nThermalizeSteps = LocalSetup.InputParameters().nNumParamOptSteps * LocalSetup.InputParameters().fThermalizeFraction; oMCParam.nMaxIterations = LocalSetup.InputParameters().nNumParamOptSteps; oMCParam.eSearchMethod = static_cast<SO3SearchMethod>( LocalSetup.InputParameters().nOrientationSearchMethod); Base::Comm.SendCommand ( nMyID, 1, nProcessingElements - 1, XDMParallel::EVAL_OVERLAP ); Base::Comm.BcastSend ( nMyID, oMCParam ); Base::Comm.BcastSendList( nMyID, vSamplePoints ); Base::Comm.BcastSendList( nMyID, vClientStepSizeInfo ); GET_LOG( osLogFile ) << "Begin Local Optimization " << std::endl; //----------------------------------- // Send to All (making this structured would help) //----------------------------------- for ( Int nClientID = 1; nClientID < nProcessingElements; nClientID ++ ) { vector< SDetParamMsg > vDetectorStartLoc; SEnergyOpt oEnergyStartLoc; oEnergyStartLoc.fEnergyStep = oEnergyLoc.fEnergyStep; if ( nClientID > 1 ) // have one of them start from the origin { vDetectorStartLoc = Base::RandomMoveDet( vDetParams, vOptMaxDeviation ); oEnergyStartLoc.fBeamEnergy = oEnergyLoc.fBeamEnergy + oRandomReal( -oEnergyLoc.fEnergyStep, oEnergyLoc.fEnergyStep ); } else { vDetectorStartLoc = vDetParams; oEnergyStartLoc.fBeamEnergy = oEnergyLoc.fBeamEnergy; } Base::SendExpParameters( nClientID, oEnergyStartLoc, vDetectorStartLoc ); } vector<SDetParamMsg> vBestParam; SEnergyOpt oBestEnergyParam; Float fBestCost = 2; Int nBestID = nMyID; Int nReported = 0; while( nReported < nProcessingElements - 1 ) { Int nClientID; vector< SDetParamMsg > vReturnedList; Float fCost; Int nCommand; SEnergyOpt oNewEnergyParam; Base::Comm.RecvCommand( &nClientID, &nCommand ); Base::Comm.RecvWorkUnit( nClientID, &fCost ); Base::Comm.RecvWorkUnit( nClientID, &oNewEnergyParam ); Base::Comm.RecvWorkUnitList( nClientID, vReturnedList ); if( fBestCost > fCost ) { fBestCost = fCost; nBestID = nClientID; vBestParam = vReturnedList; oBestEnergyParam = oNewEnergyParam; } GET_LOG( osLogFile ) << "Optimal from: " << nClientID << " " << fCost << std::endl; nReported ++; } return boost::make_tuple( vBestParam, fBestCost, oBestEnergyParam ); }
void ParameterOptimizationServer< SamplePointT, SamplePointGrid >::Process( ) { typedef GeometricOptimizationBase<SamplePointT> Base; // typedef ParameterOptimizationServer< Reconstructor, SamplePointT, SamplePointGrid > Self; RUNTIME_ASSERT( LocalSetup.InputParameters().fThermalizeFraction >= 0, "ParallelReconstruction: fThermalizeFraction < 0" ); RUNTIME_ASSERT( LocalSetup.InputParameters().fCoolingFraction >= 0, "ParallelReconstruction: fCoolingFraction < 0" ); RUNTIME_ASSERT( ( LocalSetup.InputParameters().fThermalizeFraction + LocalSetup.InputParameters().fCoolingFraction <= 1), "ParallelReconstruction: fThermalizeFraction + fCoolingFraction > 1 "); vector<SStepSizeInfo> vGlobalMaxDeviation = LocalSetup.ExperimentalSetup().GetOptimizationInfo(); vector<SDetParamMsg> vCurrentDetParams = LocalSetup.ExperimentalSetup().GetExperimentalParameters(); const vector<SStepSizeInfo> & vMinStepSizes = LocalSetup.ExperimentalSetup().GetDetectorSensitivity(); //----------------------------------- // reduce step size by the cube root of the number or processors // (This is the approximate volume taken by each processor) //----------------------------------- Float fScale = Float ( 1 ) / ( pow( (nProcessingElements - 1) * LocalSetup.InputParameters().nNumParamOptSteps, Float( 1 ) / Float ( 3 ) ) ); GET_LOG( osLogFile ) << "Scaling Factor for parameter MC: " << fScale << " " << nProcessingElements << std::endl; vector<SStepSizeInfo> vClientStepSizeInfo = vGlobalMaxDeviation; Base::ScaleParamOptMsg( vClientStepSizeInfo, vMinStepSizes, fScale ); Int nIter = 0; Float fGlobalBestCost = 2; const Float fReductionScale = std::min( LocalSetup.InputParameters().fSearchVolReductionFactor / pow( Float( nProcessingElements -1 ), Float(1) / Float(3) ), Float( 0.8 ) ); // 4 is the fudge factor vector< SParamOptMsg<SamplePointT> > vSamplePoints; VoxelQueue.RandomizeReset(); SEnergyOpt oEnergyLoc; oEnergyLoc.fBeamEnergy = LocalSetup.ExperimentalSetup().GetBeamEnergy(); oEnergyLoc.fEnergyStep = LocalSetup.InputParameters().BeamEnergyWidth / Float(2) * fScale; SEnergyOpt oBestEnergyLoc = oEnergyLoc; vector<SDetParamMsg> vBestParams = vCurrentDetParams; Int nLocalRestarts = 0; Int nLargeStepRestarts = 0; bool bFitNewVoxels = true; while ( nIter < LocalSetup.InputParameters().nParameterRefinements ) { Bool bFitSuccess = false; if( bFitNewVoxels ) { boost::tie(vSamplePoints, bFitSuccess) = GetNConvergedElements( ); VoxelQueue.RandomizeReset(); bFitNewVoxels = false; } Bool bNeedRestart = true; if( bFitSuccess || (!bFitNewVoxels) ) { // Run LocalParamOptimization SEnergyOpt OptimizedEnergyLoc; vector<SDetParamMsg> OptimizedParams; Float fCurrentCost = 2; boost::tie( OptimizedParams, fCurrentCost, OptimizedEnergyLoc ) = LocalParamOptimization( oEnergyLoc, vCurrentDetParams, vSamplePoints, vClientStepSizeInfo, vGlobalMaxDeviation ); GET_LOG( osLogFile ) << "[Best Cost, New Cost] " << fGlobalBestCost << " " << fCurrentCost << std::endl; if( fCurrentCost < fGlobalBestCost ) // if something's found, refine { fGlobalBestCost = fCurrentCost; vCurrentDetParams = OptimizedParams; vBestParams = OptimizedParams; oBestEnergyLoc = OptimizedEnergyLoc; oEnergyLoc = OptimizedEnergyLoc; GET_LOG( osLogFile ) << "Decided to refine, reduced by: " << fReductionScale << std::endl; oEnergyLoc.fEnergyStep *= fReductionScale; Base::ScaleParamOptMsg( vGlobalMaxDeviation, vMinStepSizes, fReductionScale ); Base::ScaleParamOptMsg( vClientStepSizeInfo, vMinStepSizes, fReductionScale ); bNeedRestart = false; } } if( bNeedRestart ) // is this even useful? { bFitNewVoxels = true; VoxelQueue.RandomizeReset(); if( nLocalRestarts < LocalSetup.InputParameters().nMaxParamMCLocalRestarts ) { vCurrentDetParams = Base::RandomMoveDet( vCurrentDetParams, vClientStepSizeInfo ); oEnergyLoc.fBeamEnergy = oEnergyLoc.fBeamEnergy + oRandomReal( -oEnergyLoc.fEnergyStep, oEnergyLoc.fEnergyStep ); SetClientParameters( oEnergyLoc, vCurrentDetParams ); nLocalRestarts ++; } else if ( nLargeStepRestarts < LocalSetup.InputParameters().nMaxParamMCGlobalRestarts ) { nLocalRestarts = 0; Bool bCandidateFound = false; while( nLargeStepRestarts < LocalSetup.InputParameters().nMaxParamMCGlobalRestarts && ! bCandidateFound ) { nLargeStepRestarts ++; vector< SLargeScaleOpt > oCandidateList = GetLargeVolumeCandidates( oEnergyLoc, vCurrentDetParams, vGlobalMaxDeviation ); if( oCandidateList.size() > 0 ) { bCandidateFound = true; std::sort( oCandidateList.begin(), oCandidateList.end() ); // sort ascending order by cost vCurrentDetParams = oCandidateList[0].vDetParams; oEnergyLoc.fBeamEnergy = oCandidateList[0].fEnergy; SetClientParameters( oEnergyLoc, vCurrentDetParams ); } } } } nIter ++; } //---------------------------------------- //----------------------------------- // save mic file //----------------------------------- RUNTIME_ASSERT( 0, "Need to rewrite the part that saves to mic"); VoxelQueue.ClearSolution(); for( Size_Type i = 0; i < vSamplePoints.size(); i ++ ) VoxelQueue.Push( vSamplePoints[i].oVoxel ); // Base::WriteFitResult( VoxelQueue.Solution(), ".opt"); Base::SetExperimentalParameters( oBestEnergyLoc.fBeamEnergy, vBestParams ); GET_LOG( osLogFile ) << "Best Energy: " << oBestEnergyLoc.fBeamEnergy << std::endl; Base::Comm.SendCommand( nMyID, 1, nProcessingElements -1, XDMParallel::PROCESS_DONE ); // VoxelQueue.ClearSolution(); }
std::pair< std::vector< SParamOptMsg< SamplePointT > >, bool > ParameterOptimizationServer< SamplePointT, SamplePointGrid > ::GetNConvergedElements( ) { typedef GeometricOptimizationBase<SamplePointT> Base; const Int nMaxElements = nProcessingElements * LocalSetup.InputParameters().nOptNumElementPerPE * 3; if( VoxelQueue.Size() > nMaxElements ) { GET_LOG( osLogFile ) << "Number of elements from structure: " << VoxelQueue.Size() << std::endl; GET_LOG( osLogFile ) << " exceeds the maximum number of elements to be fitted: " << nMaxElements << std::endl; GET_LOG( osLogFile ) << "Limiting to " << nMaxElements << " elements " << std::endl; VoxelQueue.RandomizedSetMaxElements( nMaxElements ); } std::queue<int> WaitQueue; for( int i = 1; i <= (nProcessingElements - 1); i ++ ) // start from 1, since 0 is Server WaitQueue.push( i ); typedef XDMParallel::MultiElementDistribution<SamplePointT> MultiElementDistributor; MultiElementDistributor SingleVoxelDistributor(1); Utilities::WorkUnitDistribution( VoxelQueue, SingleVoxelDistributor, WaitQueue, Base::Comm, osLogFile, 0, XDMParallel::FIT_MC ); GET_LOG( osLogFile ) << "Finished with Initial Work Unit Distribution " << std::endl; typedef SParamOptMsg< SamplePointT > ParamOptMsg; vector<ParamOptMsg> oConvergedSamplePoints; Int nElementsToFit = LocalSetup.InputParameters().nOptNumElementPerPE; // parameters? int NumClients = nProcessingElements -1; Int NumElementsUsed = NumClients; while( ! VoxelQueue.Empty() || WaitQueue.size() < NumClients || Int( oConvergedSamplePoints.size() ) >= nElementsToFit ) { Int nClientPE; Int nCommand; vector<ParamOptMsg> TmpResult; ParamOptMsg oOptResult; NumElementsUsed ++; Base::Comm.RecvCommand( &nClientPE, &nCommand ); RUNTIME_ASSERT( nCommand == XDMParallel::REPORT_MC, "\nDriver::Server: Unknown command from client recv \n" ); Base::Comm.RecvWorkUnitList( nClientPE, TmpResult ); RUNTIME_ASSERT( TmpResult.size() == 1, "[This error check shall be removed after debugging] Error: Size mismatch in PMC\n " ); oOptResult = TmpResult[0]; if( oOptResult.bConverged ) oConvergedSamplePoints.push_back( oOptResult ); if ( oConvergedSamplePoints.size() < nElementsToFit && (NumElementsUsed < nMaxElements) ) // if there's still voxels left Utilities::WorkUnitDistribution( VoxelQueue, SingleVoxelDistributor, WaitQueue, Base::Comm, osLogFile, 0, XDMParallel::FIT_MC ); else // tell client that we're done Base::Comm.SendCommand( nMyID, nClientPE, XDMParallel::WAIT ); } if( oConvergedSamplePoints.size() > nElementsToFit ) { GET_LOG( osLogFile ) << "Needed " << nElementsToFit << " Ended with " << oConvergedSamplePoints.size() << std::endl; std::sort( oConvergedSamplePoints.begin(), oConvergedSamplePoints.end() ); // sort by quality, ascending int nExtraPoints = oConvergedSamplePoints.size() - nElementsToFit; oConvergedSamplePoints.erase( oConvergedSamplePoints.begin(), oConvergedSamplePoints.begin() + nExtraPoints ); // keep only the last nElementsToFit GET_LOG( osLogFile ) << "List has been trimed to the best " << oConvergedSamplePoints.size() << " elements " << std::endl; } return std::make_pair( oConvergedSamplePoints, oConvergedSamplePoints.size() >= nElementsToFit ); }