示例#1
0
// 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 );
    }