Example #1
0
vector<string> lookup_argument(const string& argument) {
  using boost::iequals;
  vector<string> args;
  if (iequals(argument, "int")) {
    args.push_back("int");
  } else if (iequals(argument, "ints")) {
    args.push_back("int");
    args.push_back("std::vector<int>");
    args.push_back("Eigen::Matrix<int, Eigen::Dynamic, 1>");
    args.push_back("Eigen::Matrix<int, 1, Eigen::Dynamic>");
  } else if (iequals(argument, "double")) {
    args.push_back("double");
    args.push_back("var");
  } else if (iequals(argument, "doubles")) {
    args.push_back("double");
    args.push_back("std::vector<double>");
    args.push_back("Eigen::Matrix<double, Eigen::Dynamic, 1>");
    args.push_back("Eigen::Matrix<double, 1, Eigen::Dynamic>");
    args.push_back("var");
    args.push_back("std::vector<var>");
    args.push_back("Eigen::Matrix<var, Eigen::Dynamic, 1>");
    args.push_back("Eigen::Matrix<var, 1, Eigen::Dynamic>");
  }
  return args;
}
Example #2
0
void Gatekeeper::Handle()
{
	std::stringstream r(message_);
	std::string s;

	r >> s;

	if( iequals( s, "GIV" ) )
	{
		std::getline(r, s);
		const std::size_t pos = s.find(':');
		std::string hex = s.substr(pos + 1, 2 * 16);
		GUID guid;
		assert(hex.size() == 32);
		Conv::Hex::Decode(hex.begin(), hex.end(), guid.begin());

		std::vector< DownloadPtr > v;
		System::GetDownloadMgr()->Dump(std::back_inserter(v));
		for(uint i = 0; i < v.size(); ++i)
			if(v[i]->HandleGIV(this, guid)) 
				break;
		return;
	}
	else if(iequals(s, "GET"))
	{
		if(message_.find("\r\n\r\n") == std::string::npos)
			throw MessageIncomplete();
		System::GetUploadMgr()->Accept(this);
	}
	else
		throw std::runtime_error("Unhandled");

}
bool
FortranProgramDeclarationsAndDefinitions::checkModuleExists (
    std::string const & moduleName)
{
  using boost::iequals;
  using std::string;
  using std::map;
  using std::vector;

  bool found = false;

  for (map <string, vector <string> >::const_iterator it =
      fileNameToModuleNames.begin (); it != fileNameToModuleNames.end (); ++it)
  {
    string fileName = it->first;

    vector <string> moduleNames = it->second;

    for (vector <string>::const_iterator vectorIt = moduleNames.begin (); vectorIt
        != moduleNames.end (); ++vectorIt)
    {
      if (iequals (*vectorIt, moduleName))
      {
        found = true;
      }
    }
  }

  return found;
}
SgType *
FortranProgramDeclarationsAndDefinitions::getTypeFromString (std::string const & opDataBaseTypeString,
  std::string const & variableName)
{
  using namespace SageBuilder;
  using boost::iequals;

  if ( iequals(opDataBaseTypeString, OP2::FortranSpecific::PrimitiveTypes::real8) )
    return buildDoubleType ();
  else if ( iequals(opDataBaseTypeString, OP2::FortranSpecific::PrimitiveTypes::real4) )
    return buildFloatType ();
  else if ( iequals(opDataBaseTypeString, OP2::FortranSpecific::PrimitiveTypes::integer4) )
    return buildIntType ();
  else
      throw Exceptions::ParallelLoop::UnsupportedBaseTypeException ("Bad type specified for GENERIC OP_DAT '"
          + variableName + "' ");    
}
Example #5
0
void UploaderImp::TranslateRequest()
{
	std::istream s( &request_ );

	std::string line;

	s >> line; //method

	if( line == "GET" ) method_ = GET;
	else if( line == "HEAD" ) method_ = HEAD;
	else throw Unhandled(400, "Unknown method" );

	s >> line; //object
	if( !starts_with( line, "/uri-res/N2R?" ) ) 
		throw Unhandled(400, "Requested uri type is not supported");

	std::string last = urn_;
	urn_ = line.substr(line.find('?') + 1);

	fileInfo_ = System::GetShareMgr()->GetByUrn( urn_ ); 

	if(last != urn_)
	{
		System::LogBas() << "Host " << endpoint_ << " requested file: " << fileInfo_.Name() << std::endl;
		fileInfo_.IncreaseRequests();
	}

	while( std::getline( s, line ) && line != "\r" )
	{
		std::string value = boost::trim_copy( line.substr( line.find( ':' ) + 1 ) );
	
		if( istarts_with( line, "Connection:" ) ) 
			keepAlive_ = iequals( value, "keep-alive" );
		else if( istarts_with( line, "X-Nick:" ) ) 
			nick_ = value;
		else if(istarts_with(line, "User-Agent:") && client_ != value)
		{
			client_ = value;
			if(System::GetSecurity()->AgentRestricted(client_))
				throw Unhandled(403, "Client software is restricted");
		}
		else if( istarts_with( line, "Range:" ) )
		{
			file_offset_t first = 0;
			file_offset_t last = 0;

			int result = sscanf( value.c_str(), "bytes=%llu-%llu", &first, &last );
			if( result == 0 ) throw Unhandled(416, "Couldn't parse range");
			if( result == 1 ) range_.SetBoundary( first, fileInfo_.Size() - 1);
			if( result == 2 ) range_.SetBoundary( first, last );
		}
	}

	if( range_.Empty() ) throw std::range_error( "Range is empty" );
//	std::cout << range_.Last() << " " << fileInfo.Size() << std::endl;
	if( range_.Last() >= fileInfo_.Size() ) 
		throw Unhandled(416, "Range is too large" );
}
LASPointReader::LASPointReader(string path){
	this->path = path;

	
	if(fs::is_directory(path)){
		// if directory is specified, find all las and laz files inside directory

		for(fs::directory_iterator it(path); it != fs::directory_iterator(); it++){
			fs::path filepath = it->path();
			if(fs::is_regular_file(filepath)){
				if(iequals(fs::extension(filepath), ".las") || iequals(fs::extension(filepath), ".laz")){
					files.push_back(filepath.string());
				}
			}
		}
	}else{
		files.push_back(path);
	}
	

	// read bounding box
	for(int i = 0; i < files.size(); i++){
		string file = files[i];

		LIBLASReader aabbReader(file);
		AABB lAABB = aabbReader.getAABB();
		
		aabb.update(lAABB.min);
		aabb.update(lAABB.max);

		aabbReader.close();
	}

	// open first file
	currentFile = files.begin();
	reader = new LIBLASReader(*currentFile);
//    cout << "let's go..." << endl;
}
Example #7
0
        virtual void
        visit (SgNode * node)
        {
          using boost::iequals;
          using boost::filesystem::path;
          using boost::filesystem::system_complete;

          SgSourceFile * file = isSgSourceFile (node);

          if (file != NULL)
          {
            path p = system_complete (path (file->getFileName ()));

            if (generator->isDirty (p.filename ()))
            {
              Debug::getInstance ()->debugMessage ("Unparsing '"
                  + p.filename () + "'", Debug::FUNCTION_LEVEL, __FILE__,
                  __LINE__);

              outputFiles.push_back ("rose_" + p.filename ());

              file->unparse ();
            }
            else if (iequals (p.filename (), generator->getFileName ()))
            {
              Debug::getInstance ()->debugMessage ("Unparsing generated file '"
                  + p.filename () + "'", Debug::FUNCTION_LEVEL, __FILE__,
                  __LINE__);

              outputFiles.push_back (p.filename ());

              generatedFile = p.filename ();

              file->unparse ();
            }
            else
            {
              Debug::getInstance ()->debugMessage ("File '" + p.filename ()
                  + "' remains unchanged", Debug::FUNCTION_LEVEL, __FILE__,
                  __LINE__);

              outputFiles.push_back ("rose_" + p.filename ());

              file->unparse ();
            }
          }
        }
void
FortranCUDAUserSubroutine::createStatements ()
{
  using namespace SageInterface;
  using boost::iequals;
  using std::string;
  using std::vector;
  
  class TreeVisitor: public AstSimpleProcessing
  {
    private:
    /*
     * ======================================================
     * The recursive visit of a user subroutine populates
     * this vector with successive function calls which are
     * then appended after the visit
     * ======================================================
     */            
    vector < SgProcedureHeaderStatement * > calledRoutines;

    public:

      vector < SgProcedureHeaderStatement * > getCalledRoutinesInStatement()
      {
        return calledRoutines;
      }
      
      TreeVisitor ()
      {
      }

      virtual void
      visit (SgNode * node)
      {
        SgExprStatement * isExprStatement = isSgExprStatement ( node );
        if ( isExprStatement != NULL )
        {      
          SgFunctionCallExp * functionCallExp = isSgFunctionCallExp ( isExprStatement->get_expression() );
        
          if ( functionCallExp != NULL )
          {
            string const
                calleeName =
                    functionCallExp->getAssociatedFunctionSymbol ()->get_name ().getString ();

            Debug::getInstance ()->debugMessage ("Found function call in user subroutine "
                + calleeName + "'", Debug::OUTER_LOOP_LEVEL, __FILE__, __LINE__);

            /*
             * ======================================================
             * As we are in fortran, all user subroutines must be
             * SgProcedureHeaderStatements = subroutines and not
             * functions. This might be extended to cover also 
             * functions in the future (?). Probably not in OP2
             * ======================================================
             */
            SgProcedureHeaderStatement * isProcedureHeaderStatement = isSgProcedureHeaderStatement ( 
              functionCallExp->getAssociatedFunctionDeclaration() );

            calledRoutines.push_back ( isProcedureHeaderStatement );
          }
        }
      }
  };
  
  Debug::getInstance ()->debugMessage ("User subroutine: outputting and modifying statements",
      Debug::FUNCTION_LEVEL, __FILE__, __LINE__);

  SgFunctionParameterList * originalParameters =
      originalSubroutine->get_parameterList ();

  vector <SgStatement *> originalStatements =
      originalSubroutine->get_definition ()->get_body ()->get_statements ();

  for (vector <SgStatement *>::iterator it = originalStatements.begin (); it
      != originalStatements.end (); ++it)
  {      
 
    SgExprStatement * isExprStatement = isSgExprStatement ( *it );
    if ( isExprStatement != NULL )
    {      
      SgFunctionCallExp * functionCallExp = isSgFunctionCallExp ( isExprStatement->get_expression() );
    
      if ( functionCallExp != NULL )
      {
        string const
            calleeName =
                functionCallExp->getAssociatedFunctionSymbol ()->get_name ().getString ();

        Debug::getInstance ()->debugMessage ("Found function call in user subroutine "
            + calleeName + "'", Debug::OUTER_LOOP_LEVEL, __FILE__, __LINE__);

        /*
         * ======================================================
         * As we are in fortran, all user subroutines must be
         * SgProcedureHeaderStatements = subroutines and not
         * functions. This might be extended to cover also 
         * functions in the future (probably not in OP2)
         * ======================================================
         */            
        SgProcedureHeaderStatement * isProcedureHeaderStatement = isSgProcedureHeaderStatement ( 
          functionCallExp->getAssociatedFunctionDeclaration() );
            
        calledRoutines.push_back ( isProcedureHeaderStatement );
      }
    }

    SgVariableDeclaration * isVariableDeclaration = isSgVariableDeclaration (
        *it);

    if (isVariableDeclaration == NULL)
    { 
      /*
       * ======================================================
       * Do not append use statement, because other subroutines
       * are directly appended to the CUDA module
       * ======================================================
       */                  
      SgUseStatement * isUseStmt = isSgUseStatement ( *it );
      if (isUseStmt != NULL)
        {
          Debug::getInstance ()->debugMessage (
                "Not appending use statement",
                Debug::HIGHEST_DEBUG_LEVEL, __FILE__, __LINE__);
        }
      else
      {
        Debug::getInstance ()->debugMessage (
              "Appending (non-variable-declaration) statement",
              Debug::HIGHEST_DEBUG_LEVEL, __FILE__, __LINE__);

        appendStatement (*it, subroutineScope);

        /*
         * ======================================================
         * Recursively look for subroutine calls inside shallow
         * nodes in the routines (e.g. when a call is inside an 
         * if). After the visit get the generated vector of names
         * and append it to the userSubroutine vector
         * ======================================================
         */                  
        TreeVisitor * visitor = new TreeVisitor ();
	  
        visitor->traverse (*it, preorder);
          
        Debug::getInstance ()->debugMessage ("Appending deep subroutine calls", Debug::OUTER_LOOP_LEVEL, __FILE__, __LINE__);

          
        vector < SgProcedureHeaderStatement * > deepStatementCalls = visitor->getCalledRoutinesInStatement ();
        vector < SgProcedureHeaderStatement * >::iterator itDeepCalls;
        for (itDeepCalls = deepStatementCalls.begin(); itDeepCalls != deepStatementCalls.end(); ++itDeepCalls)
          calledRoutines.push_back (*itDeepCalls);
      
        Debug::getInstance ()->debugMessage ("Appending deep subroutine calls", Debug::OUTER_LOOP_LEVEL, __FILE__, __LINE__);
      }
    }
    else
    {
      Debug::getInstance ()->debugMessage ("Appending variable declaration",
          Debug::HIGHEST_DEBUG_LEVEL, __FILE__, __LINE__);

      unsigned int OP_DAT_ArgumentGroup = 1;

      for (SgInitializedNamePtrList::iterator variableIt =
          isVariableDeclaration->get_variables ().begin (); variableIt
          != isVariableDeclaration->get_variables ().end (); ++variableIt)
      {
        string const variableName = (*variableIt)->get_name ().getString ();

        SgType * type = (*variableIt)->get_typeptr ();

        /*
         * ======================================================
         * Specification of "value" attribute is only
         * for user kernels. Our call convention is that
         * in all deeper level calls we always pass parameters
         * by reference (see else branch below)
         * ======================================================
         */                  
        
        bool isFormalParamater = false;
	
        for (SgInitializedNamePtrList::iterator paramIt =
            originalParameters->get_args ().begin (); paramIt
            != originalParameters->get_args ().end (); ++paramIt, ++OP_DAT_ArgumentGroup)
        {
          string const formalParamterName = (*paramIt)->get_name ().getString ();

          if (iequals (variableName, formalParamterName))
          {
            isFormalParamater = true;

            if (parallelLoop->isIndirect (OP_DAT_ArgumentGroup)
                && parallelLoop->isRead (OP_DAT_ArgumentGroup))
            {
              Debug::getInstance ()->debugMessage ("'" + variableName
                  + "' is an INDIRECT formal parameter which is READ",
                  Debug::HIGHEST_DEBUG_LEVEL, __FILE__, __LINE__);

              SgVariableDeclaration * variableDeclaration;
              if ( isUserKernel == true )
                variableDeclaration =
                      FortranStatementsAndExpressionsBuilder::appendVariableDeclarationAsFormalParameter (
                          variableName, type, subroutineScope,
                          formalParameters, 0);
              else
                  variableDeclaration =
                      FortranStatementsAndExpressionsBuilder::appendVariableDeclarationAsFormalParameter (
                          variableName, type, subroutineScope,
                          formalParameters, 0);

                ROSE_ASSERT ( variableDeclaration != NULL );
            }
            else if (parallelLoop->isGlobal (OP_DAT_ArgumentGroup)                     
                     && parallelLoop->isRead (OP_DAT_ArgumentGroup))
            {
              Debug::getInstance ()->debugMessage ("'" + variableName
                + "' is a GLOBAL formal parameter which is READ",
                Debug::HIGHEST_DEBUG_LEVEL, __FILE__, __LINE__);

                SgVariableDeclaration * variableDeclaration =
                  FortranStatementsAndExpressionsBuilder::appendVariableDeclarationAsFormalParameter (
                    variableName, type, subroutineScope, formalParameters, 0);
            }
            else
            {
              Debug::getInstance ()->debugMessage ("'" + variableName
                  + "' is a formal parameter "
                  + parallelLoop->getOpDatInformation (OP_DAT_ArgumentGroup),
                  Debug::HIGHEST_DEBUG_LEVEL, __FILE__, __LINE__);

              if ( isUserKernel == true )
                SgVariableDeclaration * variableDeclaration =
                  FortranStatementsAndExpressionsBuilder::appendVariableDeclarationAsFormalParameter (
                    variableName, type, subroutineScope, formalParameters, 0);
              else
                SgVariableDeclaration * variableDeclaration =
                  FortranStatementsAndExpressionsBuilder::appendVariableDeclarationAsFormalParameter (
                    variableName, type, subroutineScope, formalParameters, 0);
            }
          }
        }
          
        if (isFormalParamater == false)
        {
          Debug::getInstance ()->debugMessage ("'" + variableName
            + "' is NOT a formal parameter", Debug::HIGHEST_DEBUG_LEVEL,
            __FILE__, __LINE__);

          SgVariableDeclaration * variableDeclaration =
            FortranStatementsAndExpressionsBuilder::appendVariableDeclaration (
            variableName, type, subroutineScope);
        }
      }
    }
  }
}
/*
 * ======================================================
 * This function appends all additional subroutines
 * called inside the user subroutine. It is specialised
 * for CUDA in the related subclass
 * ======================================================
 */
void FortranCUDAUserSubroutine::appendAdditionalSubroutines ( SgScopeStatement * moduleScope,
  FortranParallelLoop * parallelLoop, FortranProgramDeclarationsAndDefinitions * declarations,
  FortranConstantDeclarations * CUDAconstants, std::vector < SgProcedureHeaderStatement * > * allCalledRoutines)
{
  using std::vector;
  using boost::iequals;
  /*
   * ======================================================
   * First removes duplicates in calledRoutines itself
   * ======================================================
   */
  sort ( calledRoutines.begin(), calledRoutines.end() );
  calledRoutines.erase ( unique ( calledRoutines.begin(), calledRoutines.end() ), calledRoutines.end() );

  Debug::getInstance ()->debugMessage ("Before removing, the list of routine calls found in the user kernels is: ",
   Debug::FUNCTION_LEVEL, __FILE__, __LINE__);
  vector < SgProcedureHeaderStatement * > :: iterator routinesIt2;
  for ( routinesIt2 = calledRoutines.begin (); routinesIt2 != calledRoutines.end (); routinesIt2++ )
  {
    string appendingSubroutine = (*routinesIt2)->get_name ().getString ();
    Debug::getInstance ()->debugMessage (appendingSubroutine,
      Debug::FUNCTION_LEVEL, __FILE__, __LINE__);
  }
  
  /*
   * ======================================================
   * The removes routines already appended by other user
   * kernels, using the list in allCalledRoutines
   * ======================================================
   */
  Debug::getInstance ()->debugMessage ("Removing global duplicates, the number of routines in the list is: '"
    + boost::lexical_cast<string> ((int) calledRoutines.size()) + "'", Debug::FUNCTION_LEVEL, __FILE__, __LINE__);

  vector < SgProcedureHeaderStatement * > :: iterator routinesIt;
  for ( routinesIt = calledRoutines.begin (); routinesIt != calledRoutines.end (); ) //routinesIt++ )
  {
    string appendingSubroutine = (*routinesIt)->get_name ().getString ();

    Debug::getInstance ()->debugMessage ("Checking routine for deletion: '"
      + appendingSubroutine + "'", Debug::FUNCTION_LEVEL, __FILE__, __LINE__);

    bool foundAndErased = false;
    vector < SgProcedureHeaderStatement * > :: iterator finder;
    for ( finder = allCalledRoutines->begin (); finder != allCalledRoutines->end (); finder++ )
    {
      Debug::getInstance ()->debugMessage ("Checking against: '"
        + (*finder)->get_name ().getString () + "'", Debug::FUNCTION_LEVEL, __FILE__, __LINE__);

      if ( iequals ((*finder)->get_name ().getString (), appendingSubroutine) )
      {
        /*
         * ======================================================
         * Routine already appended by another user kernel:
         * delete it from list of routines to be appended for
         * this user kernel, and exit this loop
         * ======================================================
         */      
        Debug::getInstance ()->debugMessage ("Deleting: '"
          + appendingSubroutine + "'", Debug::FUNCTION_LEVEL, __FILE__, __LINE__);
        
        calledRoutines.erase (routinesIt++);

        if ( calledRoutines.empty () ) return;

        foundAndErased = true;

        routinesIt--;
        break;
      }      
    }

    if ( foundAndErased == false )
    {
        /*
         * ======================================================
         * New routine: it must be added to the list of 
         * routines called by all previous user kernels because
         * recursively called routines need to discard those
         * already appended by this routine
         * ======================================================
         */
         Debug::getInstance ()->debugMessage ("Not found, appending: '"
          + appendingSubroutine + "'", Debug::FUNCTION_LEVEL, __FILE__, __LINE__);
        
        allCalledRoutines->push_back ( *routinesIt );
        
        routinesIt++;
    }
  }
  
  
  vector < SgProcedureHeaderStatement * > :: iterator it;
  for ( it = calledRoutines.begin(); it != calledRoutines.end(); it++ )
  {
   
    string calledSubroutineName = (*it)->get_name ().getString ();
    
    Debug::getInstance ()->debugMessage ("Appending new subroutine '"
        + calledSubroutineName + "'", Debug::FUNCTION_LEVEL, __FILE__, __LINE__);
   
    FortranCUDAUserSubroutine * newRoutine = new FortranCUDAUserSubroutine ( moduleScope, 
        parallelLoop, declarations, calledSubroutineName );

    newRoutine->createFormalParameterDeclarations ();
    newRoutine->createStatements ();
   
    additionalSubroutines.push_back (newRoutine);        
  }
  
  vector < FortranUserSubroutine * > :: iterator itRecursive;
  for ( itRecursive = additionalSubroutines.begin(); itRecursive != additionalSubroutines.end(); itRecursive++ )
  {
    FortranCUDAUserSubroutine * cudaSubroutineCasting = (FortranCUDAUserSubroutine *) *itRecursive;

    CUDAconstants->patchReferencesToConstants (
      (cudaSubroutineCasting )->getSubroutineHeaderStatement ());
          
    RoseHelper::forceOutputOfCodeToFile (
      (cudaSubroutineCasting )->getSubroutineHeaderStatement ());
  }

  for ( itRecursive = additionalSubroutines.begin(); itRecursive != additionalSubroutines.end(); itRecursive++ )
  {
    FortranCUDAUserSubroutine * cudaSubroutineCasting = (FortranCUDAUserSubroutine *) *itRecursive;

    cudaSubroutineCasting->appendAdditionalSubroutines (moduleScope, parallelLoop, declarations, CUDAconstants, allCalledRoutines);
  }
}
void
FortranProgramDeclarationsAndDefinitions::visit (SgNode * node)
{
  using boost::filesystem::path;
  using boost::filesystem::system_complete;
  using boost::iequals;
  using boost::starts_with;
  using boost::lexical_cast;
  using std::string;

  if (isSgSourceFile (node))
  {
    path p = system_complete (path (isSgSourceFile (node)->getFileName ()));

    currentSourceFile = p.filename ();

    Debug::getInstance ()->debugMessage ("Source file '" + currentSourceFile
        + "' detected", Debug::OUTER_LOOP_LEVEL, __FILE__, __LINE__ );
  }
  else if (Globals::getInstance ()->isInputFile (currentSourceFile))
  {
    /*
     * ======================================================
     * Only process this portion of the AST if we recognise
     * this source file as one passed on the command line. In
     * Fortran, .rmod files are sometimes generated whose
     * traversal should be avoided
     * ======================================================
     */

    switch (node->variantT ())
    {
      case V_SgModuleStatement:
      {
        SgModuleStatement * moduleStatement = isSgModuleStatement (node);

        currentModuleName = moduleStatement->get_name ().getString ();

        fileNameToModuleNames[currentSourceFile].push_back (currentModuleName);

        moduleNameToFileName[currentModuleName] = currentSourceFile;

        Debug::getInstance ()->debugMessage ("Module '" + currentModuleName
            + "' in file '" + currentSourceFile + "'", Debug::OUTER_LOOP_LEVEL,
            __FILE__, __LINE__ );

        break;
      }

      case V_SgProcedureHeaderStatement:
      {
        /*
         * ======================================================
         * We need to store all subroutine definitions since we
         * later have to copy and modify the user kernel subroutine
         * ======================================================
         */
        SgProcedureHeaderStatement * procedureHeaderStatement =
            isSgProcedureHeaderStatement (node);

        string const subroutineName =
            procedureHeaderStatement->get_name ().getString ();

        subroutinesInSourceCode[subroutineName] = procedureHeaderStatement;

        ROSE_ASSERT (currentModuleName.size() > 0);

        moduleNameToSubroutines[currentModuleName].push_back (subroutineName);

        subroutineToFileName[subroutineName] = currentSourceFile;

        Debug::getInstance ()->debugMessage (
            "Found procedure header statement '"
                + procedureHeaderStatement->get_name ().getString ()
                + "' in file '" + currentSourceFile + "', and module '"
                + currentModuleName + "'", Debug::FUNCTION_LEVEL, __FILE__,
            __LINE__);

        break;
      }

      case V_SgFunctionCallExp:
      {
        /*
         * ======================================================
         * Function call found in the AST. Get its actual arguments
         * and the callee name
         * ======================================================
         */
        SgFunctionCallExp * functionCallExp = isSgFunctionCallExp (node);

        SgExprListExp * actualArguments = functionCallExp->get_args ();

        string const
            calleeName =
                functionCallExp->getAssociatedFunctionSymbol ()->get_name ().getString ();

        Debug::getInstance ()->debugMessage ("Found function call '"
            + calleeName + "'", Debug::OUTER_LOOP_LEVEL, __FILE__, __LINE__);

        if ( iequals (calleeName, OP2::OP_DECL_SET) ||
             iequals (calleeName, OP2::OP_DECL_SET_HDF5) )
        {
          /*
           * ======================================================
           * An OP_SET variable declared through an OP_DECL_SET call
           * ======================================================
           */
          bool isHDF5Format = false;
          
          if ( iequals (calleeName, OP2::OP_DECL_SET_HDF5) ) isHDF5Format = true;
          
          FortranOpSetDefinition * opSetDeclaration =
              new FortranOpSetDefinition (actualArguments, isHDF5Format);

          OpSetDefinitions[opSetDeclaration->getVariableName ()]
              = opSetDeclaration;
        }        
        else if ( iequals (calleeName, OP2::OP_DECL_MAP) ||
                  iequals (calleeName, OP2::OP_DECL_MAP_HDF5) )
        {
          /*
           * ======================================================
           * An OP_MAP variable declared through an OP_DECL_MAP call
           * ======================================================
           */

          bool isHDF5Format = false;
          
          if ( iequals (calleeName, OP2::OP_DECL_MAP_HDF5) )
          {
            isHDF5Format = true;

            Debug::getInstance ()->debugMessage ("This is the HDF5 version: '"
              + calleeName + "'", Debug::OUTER_LOOP_LEVEL, __FILE__, __LINE__);
          }
          
          FortranOpMapDefinition * opMapDeclaration =
              new FortranOpMapDefinition (actualArguments, isHDF5Format);

          OpMapDefinitions[opMapDeclaration->getVariableName ()]
              = opMapDeclaration;
        }
        else if ( iequals (calleeName, OP2::OP_DECL_DAT) ||
                  iequals (calleeName, OP2::OP_DECL_DAT_HDF5) )
        {
          /*
           * ======================================================
           * An OP_DAT variable declared through an OP_DECL_DAT call
           * ======================================================
           */
          bool isHDF5Format = false;
          
          if ( iequals (calleeName, OP2::OP_DECL_DAT_HDF5) ) isHDF5Format = true;

          FortranOpDatDefinition * opDatDeclaration =
              new FortranOpDatDefinition (actualArguments, isHDF5Format);

          OpDatDefinitions[opDatDeclaration->getVariableName ()]
              = opDatDeclaration;
        }
        else if (iequals (calleeName, OP2::OP_DECL_CONST))
        {
          /*
           * ======================================================
           * A constant declared through an OP_DECL_CONST call
           * ======================================================
           */

          FortranOpConstDefinition * opConstDeclaration =
              new FortranOpConstDefinition (actualArguments, functionCallExp);

          OpConstDefinitions[opConstDeclaration->getVariableName ()]
              = opConstDeclaration;
        }
        else if (starts_with (calleeName, OP2::OP_PAR_LOOP))
        {
          /*
           * ======================================================
           * The first argument to an 'OP_PAR_LOOP' call should be
           * a reference to the kernel function. Cast it and proceed,
           * otherwise throw an exception
           * ======================================================
           */

          SgExprListExp * actualArguments = functionCallExp->get_args ();

          SgFunctionRefExp * functionRefExpression = isSgFunctionRefExp (
              actualArguments->get_expressions ().front ());

          ROSE_ASSERT (functionRefExpression != NULL);

          string const
              userSubroutineName =
                  functionRefExpression->getAssociatedFunctionDeclaration ()->get_name ().getString ();

          Debug::getInstance ()->debugMessage ("Found '" + calleeName
              + "' with (host) user subroutine '" + userSubroutineName + "'",
              Debug::OUTER_LOOP_LEVEL, __FILE__, __LINE__);

          if (parallelLoops.find (userSubroutineName) == parallelLoops.end ())
          {
            int numberOfOpArgs = getLoopSuffixNumber ( calleeName );

            /*
             * ======================================================
             * If this kernel has not been previously encountered then
             * build a new parallel loop representation
             * ======================================================
             */

            FortranParallelLoop * parallelLoop = new FortranParallelLoop (
                functionCallExp);

            parallelLoop->addFileName (currentSourceFile);

            parallelLoops[userSubroutineName] = parallelLoop;

            Debug::getInstance ()->debugMessage ("Parallel loop with '"
                + lexical_cast <string> (numberOfOpArgs)  + "' arguments",
                Debug::OUTER_LOOP_LEVEL, __FILE__, __LINE__);
                        
            analyseParallelLoopArguments (parallelLoop, actualArguments,
              numberOfOpArgs);

            parallelLoop->checkArguments ();
            
            parallelLoop->setIncrementalID (IDCounter);
            IDCounter++;
          }
          else
          {
            Debug::getInstance ()->debugMessage ("Parallel loop for '"
                + userSubroutineName + "' already created",
                Debug::OUTER_LOOP_LEVEL, __FILE__, __LINE__);

            ParallelLoop * parallelLoop = parallelLoops[userSubroutineName];

            parallelLoop->addFunctionCallExpression (functionCallExp);

            parallelLoop->addFileName (currentSourceFile);
          }
        }

        break;
      }

      default:
      {
        break;
      }
    }
  }
}
void
FortranProgramDeclarationsAndDefinitions::analyseParallelLoopArguments (
    FortranParallelLoop * parallelLoop, SgExprListExp * actualArguments,
    int numberOfOpArgs)
{
  using boost::iequals;
  using boost::lexical_cast;
  using std::find;
  using std::string;
  using std::vector;
  using std::map;

  Debug::getInstance ()->debugMessage (
      "Analysing OP_PAR_LOOP actual arguments", Debug::FUNCTION_LEVEL,
      __FILE__, __LINE__);

  unsigned int OP_DAT_ArgumentGroup = 1;
  
  /*
   * ======================================================
   * Loops over the arguments to populate the parallel loop object
   * Each object in the actualArguments array is a function call
   * We analyse the arguments of each call
   * \warning: the args start from position 2 (the first two args are
   * the user kernel reference and the iteration set
   * ======================================================
   */
  
  for ( int i = 2; i < numberOfOpArgs + 2; i++ )
  {
   /*
    * ======================================================
    * Distinguish between op_dat and global variable by
    * checking the function name
    * ======================================================
    */
    SgFunctionCallExp * functionExpression = isSgFunctionCallExp (
      actualArguments->get_expressions ()[i]);
    
    ROSE_ASSERT (functionExpression != NULL);
    
    string functionName = functionExpression ->getAssociatedFunctionSymbol ()->
      get_name ().getString ();
    
    SgExprListExp * opArgArguments = functionExpression ->get_args ();
    ROSE_ASSERT (opArgArguments );

    /*
     * ======================================================
     * Assume that this is not an op_mat, possibly amend later
     * ======================================================     
     */
    parallelLoop->setIsOpMatArg (OP_DAT_ArgumentGroup, false);
    
    if ( functionName == "op_arg_dat" )
    {     
     /*
      * ======================================================
      * Obtain the op_dat reference and its name
      * ======================================================
      */
     
      SgVarRefExp * opDatReference = NULL;

      opDatReference = getOpDatReferenceFromOpArg (opArgArguments);

      ROSE_ASSERT (opDatReference != NULL);

      string const opDatName = opDatReference->get_symbol ()->get_name ().getString ();

     /*
      * ======================================================
      * Obtain the map reference and name, and select access
      * type (direct or indirect)
      * ======================================================            
      */
      SgVarRefExp * opMapReference;

      opMapReference = getOpMapReferenceFromOpArg (opArgArguments);

      ROSE_ASSERT (opMapReference != NULL);

      string const mappingValue = opMapReference->get_symbol ()->get_name ().getString ();

      if (iequals (mappingValue, OP2::OP_ID))
      {
        /*
         * ======================================================
         * OP_ID signals identity mapping and therefore direct
         * access to the data
         * ======================================================
         */
        Debug::getInstance ()->debugMessage ("...DIRECT mapping descriptor",
            Debug::OUTER_LOOP_LEVEL, __FILE__, __LINE__);

        parallelLoop->setOpMapValue (OP_DAT_ArgumentGroup, DIRECT);
      }
      else
      {
        Debug::getInstance ()->debugMessage ("...INDIRECT mapping descriptor",
            Debug::OUTER_LOOP_LEVEL, __FILE__, __LINE__);

        parallelLoop->setOpMapValue (OP_DAT_ArgumentGroup, INDIRECT);
      }

      setOpDatProperties (parallelLoop, opDatName, OP_DAT_ArgumentGroup);

      setParallelLoopAccessDescriptor (parallelLoop, opArgArguments, OP_DAT_ArgumentGroup, DAT_ACC_POSITION);
    }
    else if ( functionName == "op_arg_gbl" )
    {

      Debug::getInstance ()->debugMessage ("...GLOBAL mapping descriptor",
        Debug::OUTER_LOOP_LEVEL, __FILE__, __LINE__);

     /*
      * ======================================================
      * Get the OP_GBL variable reference and name
      * ======================================================
      */
      SgVarRefExp * opDatReference;

      if (isSgDotExp (opArgArguments->get_expressions ()[DAT_POSITION])
          != NULL)
      {
        opDatReference
            = isSgVarRefExp (
                isSgDotExp (
                    opArgArguments->get_expressions ()[DAT_POSITION])->get_rhs_operand ());
      }
      else
      {
        opDatReference = isSgVarRefExp (
            opArgArguments->get_expressions ()[DAT_POSITION]);
      }

      string const globalName =
          opDatReference->get_symbol ()->get_name ().getString ();
      

     /*
      * ======================================================
      * Get the OP_GBL dimension: check the number of args
      * to the op_arg_gbl function (3 = array, 2 = scalar)
      * ======================================================
      */
      if ( opArgArguments->get_expressions ().size () == GBL_SCALAR_ARG_NUM )
      {

        Debug::getInstance ()->debugMessage ("'" + globalName + "' is a scalar",
            Debug::FUNCTION_LEVEL, __FILE__, __LINE__);

       /*
        * ======================================================
        * Since this is a scalar, set the dimension to 1
        * ======================================================
        */

        parallelLoop->setOpDatDimension (OP_DAT_ArgumentGroup, 1);
      }
      else
      {
        SgIntVal * intValExp = isSgIntVal (opArgArguments->get_expressions ()[GBL_DIM_POSITION]);
        ROSE_ASSERT (intValExp != NULL);
        
        int globalDimension = intValExp->get_value ();
        
        parallelLoop->setOpDatDimension (OP_DAT_ArgumentGroup, globalDimension);
        
        Debug::getInstance ()->debugMessage ("'" + globalName
          + "' is NOT a scalar, but has dimension " + lexical_cast<string> (globalDimension),
          Debug::FUNCTION_LEVEL, __FILE__, __LINE__);
      }

     /*
      * ======================================================
      * Set the other fields
      * ======================================================
      */
      parallelLoop->setOpDatType (OP_DAT_ArgumentGroup,
        (opArgArguments->get_expressions ()[DAT_POSITION])->get_type ());
     
      parallelLoop->setUniqueOpDat (globalName);

      parallelLoop->setOpDatVariableName (OP_DAT_ArgumentGroup, globalName);

      parallelLoop->setDuplicateOpDat (OP_DAT_ArgumentGroup, false);

      parallelLoop->setOpMapValue (OP_DAT_ArgumentGroup, GLOBAL);

      if ( opArgArguments->get_expressions ().size () == GBL_SCALAR_ARG_NUM )       
        setParallelLoopAccessDescriptor (parallelLoop, opArgArguments,
          OP_DAT_ArgumentGroup, GBL_SCALAR_ACC_POSITION);
      else        
        setParallelLoopAccessDescriptor (parallelLoop, opArgArguments,
          OP_DAT_ArgumentGroup, GBL_ARRAY_ACC_POSITION);
    }
    else if ( functionName == "op_arg_dat_generic" )
    {
      Debug::getInstance ()->debugMessage ("Found generic op_dat",
        Debug::OUTER_LOOP_LEVEL, __FILE__, __LINE__);

      /*
       * ======================================================
       * Obtain the op_dat reference and its name
       * ======================================================
       */
      SgVarRefExp * opDatReference = NULL;

      opDatReference = getOpDatReferenceFromOpArg (opArgArguments);

      ROSE_ASSERT (opDatReference != NULL);

      string const opDatName = opDatReference->get_symbol ()->get_name ().getString ();      

      /*
       * ======================================================
       * Obtain the map reference and name, and select access
       * type (direct or indirect)
       * ======================================================
       */
      SgVarRefExp * opMapReference;

      opMapReference = getOpMapReferenceFromOpArg (opArgArguments);

      ROSE_ASSERT (opMapReference != NULL);

      string const mappingValue = opMapReference->get_symbol ()->get_name ().getString ();

      if (iequals (mappingValue, OP2::OP_ID))
        {
          /*
           * ======================================================
           * OP_ID signals identity mapping and therefore direct
           * access to the data
           * ======================================================
           */
          Debug::getInstance ()->debugMessage ("...DIRECT mapping descriptor",
            Debug::OUTER_LOOP_LEVEL, __FILE__, __LINE__);

          parallelLoop->setOpMapValue (OP_DAT_ArgumentGroup, DIRECT);
        }
      else
        {
          Debug::getInstance ()->debugMessage ("...INDIRECT mapping descriptor",
            Debug::OUTER_LOOP_LEVEL, __FILE__, __LINE__);

          parallelLoop->setOpMapValue (OP_DAT_ArgumentGroup, INDIRECT);
        }

      /*
       * ======================================================
       * In case of generic loop, I have to read also the
       * dimension and type to be able to set the op_dat info
       * in the parallel loop class
       * ======================================================
       */
      SgIntVal * opDatDimension = isSgIntVal (
        opArgArguments->get_expressions ()[GENERIC_DIM_POSITION]);

        
      SgStringVal * opDataBaseTypeString = isSgStringVal (
        opArgArguments->get_expressions ()[GENERIC_TYPE_POSITION]);

      ROSE_ASSERT (opDataBaseTypeString != NULL);
        
      SgType * opDataBaseType = getTypeFromString (opDataBaseTypeString->get_value (),
        opDatName);

      ROSE_ASSERT (opDataBaseType != NULL);

      setOpDatPropertiesGeneric (parallelLoop, opDatName, opDatDimension->get_value (),
         opDataBaseType, OP_DAT_ArgumentGroup);

      Debug::getInstance ()->debugMessage ("Getting access",
        Debug::OUTER_LOOP_LEVEL, __FILE__, __LINE__);

      setParallelLoopAccessDescriptor (parallelLoop, opArgArguments,
        OP_DAT_ArgumentGroup, GENERIC_ACC_POSITION);
    } 
    else if ( functionName == "op_arg_mat" )
    {
      Debug::getInstance ()->debugMessage ("Unsupported argument type",
        Debug::OUTER_LOOP_LEVEL, __FILE__, __LINE__);
    }
    else
    {
      Debug::getInstance ()->debugMessage ("Argument type not recognised",
        Debug::OUTER_LOOP_LEVEL, __FILE__, __LINE__);      
    }

   /*
    * ======================================================
    * This identifies the argument position in the data
    * structures, while the iteration variable 'i' identifies
    * the corresponding op_arg position in the op_par_loop
    * arguments (i == OP_DAT_ArgumentGroup + 2)
    * ======================================================
    */

    OP_DAT_ArgumentGroup++;
  }
  
  parallelLoop->setNumberOfOpDatArgumentGroups (numberOfOpArgs);
  parallelLoop->setNumberOfOpMatArgumentGroups (0);
  
  if ( parallelLoop->isDirectLoop () )
    Debug::getInstance ()->debugMessage ("This is a DIRECT parallel loop",
      Debug::OUTER_LOOP_LEVEL, __FILE__, __LINE__);
  else
    Debug::getInstance ()->debugMessage ("This is an INDIRECT parallel loop",
      Debug::OUTER_LOOP_LEVEL, __FILE__, __LINE__);  
}
void
FortranProgramDeclarationsAndDefinitions::setParallelLoopAccessDescriptor (
    FortranParallelLoop * parallelLoop, SgExprListExp * actualArguments,
    unsigned int OP_DAT_ArgumentGroup, unsigned int accessPosition)
{
  using boost::iequals;
  using boost::lexical_cast;
  using std::string;

  SgVarRefExp * accessExpression = isSgVarRefExp (
      actualArguments->get_expressions ()[accessPosition]);

  string const accessValue =
      accessExpression->get_symbol ()->get_name ().getString ();

  if (iequals (accessValue, OP2::OP_READ))
  {
    Debug::getInstance ()->debugMessage ("...READ access descriptor",
        Debug::OUTER_LOOP_LEVEL, __FILE__, __LINE__);

    parallelLoop->setOpAccessValue (OP_DAT_ArgumentGroup, READ_ACCESS);
  }
  else if (iequals (accessValue, OP2::OP_WRITE))
  {
    Debug::getInstance ()->debugMessage ("...WRITE access descriptor",
        Debug::OUTER_LOOP_LEVEL, __FILE__, __LINE__);

    parallelLoop->setOpAccessValue (OP_DAT_ArgumentGroup, WRITE_ACCESS);
  }
  else if (iequals (accessValue, OP2::OP_INC))
  {
    Debug::getInstance ()->debugMessage ("...INCREMENT access descriptor",
        Debug::OUTER_LOOP_LEVEL, __FILE__, __LINE__);

    parallelLoop->setOpAccessValue (OP_DAT_ArgumentGroup, INC_ACCESS);
  }
  else if (iequals (accessValue, OP2::OP_RW))
  {
    Debug::getInstance ()->debugMessage ("...READ/WRITE access descriptor",
        Debug::OUTER_LOOP_LEVEL, __FILE__, __LINE__);

    parallelLoop->setOpAccessValue (OP_DAT_ArgumentGroup, RW_ACCESS);
  }
  else if (iequals (accessValue, OP2::OP_MAX))
  {
    Debug::getInstance ()->debugMessage ("...MAXIMUM access descriptor",
        Debug::OUTER_LOOP_LEVEL, __FILE__, __LINE__);

    parallelLoop->setOpAccessValue (OP_DAT_ArgumentGroup, MAX_ACCESS);
  }
  else if (iequals (accessValue, OP2::OP_MIN))
  {
    Debug::getInstance ()->debugMessage ("...MINIMUM access descriptor",
        Debug::OUTER_LOOP_LEVEL, __FILE__, __LINE__);

    parallelLoop->setOpAccessValue (OP_DAT_ArgumentGroup, MIN_ACCESS);
  }
  else
  {
    throw Exceptions::ParallelLoop::UnknownAccessException (
        "Unknown access descriptor: '" + accessValue + "' for OP_DAT argument "
            + lexical_cast <string> (OP_DAT_ArgumentGroup));
  }
}
Example #13
0
//! Execute random walk simulator application mode.
void executeRandomWalkSimulator( 
    const std::string databasePath, 
    const tudat::input_output::parsed_data_vector_utilities::ParsedDataVectorPtr parsedData )
{
    ///////////////////////////////////////////////////////////////////////////

    // Declare using-statements.

    using std::advance;
    using std::cerr;
    using std::cout;
    using std::endl;
    using std::max_element;
    using std::min_element;
    using std::numeric_limits;
    using std::ofstream;
    using std::ostringstream;
    using std::setprecision;
    using std::string;

    using boost::iequals;
    using namespace boost::filesystem; 
    using boost::make_shared;   

    using namespace assist::astrodynamics;
    using namespace assist::basics;
    using namespace assist::mathematics;

    using namespace tudat::basic_astrodynamics::orbital_element_conversions;
    using namespace tudat::basic_mathematics::mathematical_constants;
    using namespace tudat::input_output;
    using namespace tudat::input_output::dictionary;
    using namespace tudat::statistics;

    using namespace stomi::astrodynamics;
    using namespace stomi::database;
    using namespace stomi::input_output;

    ///////////////////////////////////////////////////////////////////////////

    // Extract input parameters.

    // Get dictionary.
    const DictionaryPointer dictionary = getRandomWalkSimulatorDictionary( );

    // Print database path to console.
    cout << "Database                                                  " 
         << databasePath << endl;

    // Extract required parameters. 
    const string randomWalkRunName = extractParameterValue< string >(
                parsedData->begin( ), parsedData->end( ), 
                findEntry( dictionary, "RANDOMWALKRUN" ) );
    cout << "Random walk run                                           "  
         << randomWalkRunName << endl;  

    // Extract optional parameters. 
    const int numberOfThreads = extractParameterValue< int >(
                parsedData->begin( ), parsedData->end( ),
                findEntry( dictionary, "NUMBEROFTHREADS" ), 1 );
    cout << "Number of threads                                         " 
         << numberOfThreads << endl;  

    const string outputMode = extractParameterValue< string >(
                parsedData->begin( ), parsedData->end( ),
                findEntry( dictionary, "OUTPUTMODE" ), "DATABASE" );
    cout << "Output mode                                               "
         << outputMode << endl;          

    const string fileOutputDirectory = extractParameterValue< string >(
                parsedData->begin( ), parsedData->end( ),
                findEntry( dictionary, "FILEOUTPUTDIRECTORY" ), "" ) + "/";
    cout << "File output directory                                     "
         << fileOutputDirectory << endl;

    const string randomWalkSimulations = extractParameterValue< string >(
                parsedData->begin( ), parsedData->end( ),
                findEntry( dictionary, "RANDOMWALKSIMULATIONS" ), "ALL" );
    cout << "Random walk simulations                                   "
         << randomWalkSimulations << endl;         

    const string randomWalkRunTableName = extractParameterValue< string >(
                parsedData->begin( ), parsedData->end( ),
                findEntry( dictionary, "RANDOMWALKRUNTABLENAME" ), "random_walk_run" );
    cout << "Random walk run table                                     " 
         << randomWalkRunTableName << endl;

    const string randomWalkInputTableName = extractParameterValue< string >(
                parsedData->begin( ), parsedData->end( ),
                findEntry( dictionary, "RANDOMWALKINPUTTABLENAME" ), "random_walk_input" );
    cout << "Random walk input table                                   " 
         << randomWalkInputTableName << endl;         

    const string randomWalkPerturberTableName = extractParameterValue< string >(
                parsedData->begin( ), parsedData->end( ),
                findEntry( dictionary, "RANDOMWALKPERTURBERTABLENAME" ),
                "random_walk_perturbers" );
    cout << "Random walk perturber table                               "
         << randomWalkPerturberTableName << endl;

    const string randomWalkOutputTableName = extractParameterValue< string >(
                parsedData->begin( ), parsedData->end( ),
                findEntry( dictionary, "RANDOMWALKOUTPUTTABLENAME" ), "random_walk_output" );
    cout << "Random walk output table                                  "
              << randomWalkOutputTableName << endl; 

    const string testParticleCaseTableName = extractParameterValue< string >(
                parsedData->begin( ), parsedData->end( ),
                findEntry( dictionary, "TESTPARTICLECASETABLENAME" ), "test_particle_case" );
    cout << "Test particle case table                                  "
         << testParticleCaseTableName << endl;                

    const string testParticleKickTableName = extractParameterValue< string >(
                parsedData->begin( ), parsedData->end( ),
                findEntry( dictionary, "TESTPARTICLEKICKTABLENAME" ), "test_particle_kicks" );
    cout << "Test particle kick table                                  "
         << testParticleKickTableName << endl;          

    // Retrieve and store random walk run data from database.
    RandomWalkRunPointer randomWalkRun;

    // Random walk run data is extracted in local scope from the database, with overwritten
    // parameters extracted from the input file, to ensure that none of these parameters are used
    // globally elsewhere in this file.
    {
        const RandomWalkRunPointer retrievedRandomWalkRun = getRandomWalkRun( 
            databasePath, randomWalkRunName, randomWalkRunTableName ); 

        const double perturberRingNumberDensity = extractParameterValue< double >(
                    parsedData->begin( ), parsedData->end( ),
                    findEntry( dictionary, "PERTURBERRINGNUMBERDENSITY" ),
                    retrievedRandomWalkRun->perturberRingNumberDensity );    
        cout << "Perturber ring number density                             " 
             << perturberRingNumberDensity << " perturbers per R_Hill" << endl;

        const double perturberRingMass = extractParameterValue< double >(
                    parsedData->begin( ), parsedData->end( ),
                    findEntry( dictionary, "PERTURBERRINGMASS" ),
                    retrievedRandomWalkRun->perturberRingMass );    
        cout << "Perturber ring mass                                       "
             << perturberRingMass << " M_PerturbedBody" << endl;              

        const double observationPeriod = extractParameterValue< double >(
                    parsedData->begin( ), parsedData->end( ),
                    findEntry( dictionary, "OBSERVATIONPERIOD" ),
                    retrievedRandomWalkRun->observationPeriod, &convertJulianYearsToSeconds );
        cout << "Observation period                                        "
             << convertSecondsToJulianYears( observationPeriod ) << " yrs" << endl; 

        const unsigned int numberOfEpochWindows = extractParameterValue< unsigned int >(
                    parsedData->begin( ), parsedData->end( ),
                    findEntry( dictionary, "NUMBEROFEPOCHWINDOWS" ),
                    retrievedRandomWalkRun->numberOfEpochWindows );    
        cout << "Number of epoch windows                                   "
             << numberOfEpochWindows << endl;                                                 

        const double epochWindowSize = extractParameterValue< double >(
                    parsedData->begin( ), parsedData->end( ),
                    findEntry( dictionary, "EPOCHWINDOWSIZE" ),
                    retrievedRandomWalkRun->epochWindowSize, &convertJulianDaysToSeconds  );
        cout << "Epoch window size                                         "
             << convertSecondsToJulianDays( epochWindowSize ) << " days" << endl;     

        // Store random walk run data with possible overwritten data.
        randomWalkRun = make_shared< RandomWalkRun >( 
            retrievedRandomWalkRun->randomWalkRunId, randomWalkRunName, 
            retrievedRandomWalkRun->testParticleCaseId, perturberRingNumberDensity,
            perturberRingMass, observationPeriod, numberOfEpochWindows, epochWindowSize );
    }

    // Check that all required parameters have been set.
    checkRequiredParameters( dictionary );

    ///////////////////////////////////////////////////////////////////////////

    ///////////////////////////////////////////////////////////////////////////

    // Fetch test particle case and random walk input data from database.

    cout << endl;
    cout << "****************************************************************************" << endl;
    cout << "Database operations" << endl;
    cout << "****************************************************************************" << endl;
    cout << endl;

    // Generate output message.
    cout << "Fetching test particle case data from database ..." << endl;      

    // Retrieve and store test particle case data.
    const TestParticleCasePointer testParticleCaseData = getTestParticleCase( 
        databasePath, randomWalkRun->testParticleCaseId, testParticleCaseTableName ); 

    // Generate output message to indicate that test particle case data was fetched successfully.
    cout << "Test particle case data fetched successfully from database!" << endl;   

    // Generate output message.
    cout << "Fetching random walk input data from database ..." << endl;   

    // Check if all incomplete random walk simulations are to be executed and fetch the random
    // walk input table, else only fetch the requested random walk simulation IDs.
    RandomWalkInputTable randomWalkInputTable;

    if ( iequals( randomWalkSimulations, "ALL" )  )
    {
        cout << "Fetching all incomplete random walk Monte Carlo runs ..." << endl;    

        // Get entire random walk input table from database.
        randomWalkInputTable = getCompleteRandomWalkInputTable(
                    databasePath, randomWalkRun->randomWalkRunId, 
                    randomWalkInputTableName, randomWalkPerturberTableName );
    }

    else
    {
        cout << "Fetching all requested random walk Monte Carlo runs ..." << endl;    

        // Get selected random walk input table from database.
        randomWalkInputTable = getSelectedRandomWalkInputTable(
                    databasePath, randomWalkRun->randomWalkRunId, randomWalkSimulations, 
                    randomWalkInputTableName, randomWalkPerturberTableName );
    }

    // Generate output message to indicate that the input table was fetched successfully.
    cout << "Random walk input data (" << randomWalkInputTable.size( )
         << " rows) fetched successfully from database!" << endl;    

    ///////////////////////////////////////////////////////////////////////////

    ///////////////////////////////////////////////////////////////////////////

    // Compute derived parameters.

    cout << endl;
    cout << "****************************************************************************" << endl;
    cout << "Derived parameters" << endl;
    cout << "****************************************************************************" << endl;
    cout << endl;

    // Compute epoch window spacing [s].
    const double epochWindowSpacing 
        = randomWalkRun->observationPeriod / ( randomWalkRun->numberOfEpochWindows - 1 );
    cout << "Epoch window spacing                                      " 
         << convertSecondsToJulianDays( epochWindowSpacing ) << " days" << endl;

    // Compute mass of perturbed body [kg].
    const double perturbedBodyMass = computeMassOfSphere(
                testParticleCaseData->perturbedBodyRadius, 
                testParticleCaseData->perturbedBodyBulkDensity );
    cout << "Perturbed body mass                                       " 
         << perturbedBodyMass << " kg" << endl;

    // Compute perturbed body's gravitational parameter [m^3 s^-2].
    const double perturbedBodyGravitationalParameter
            = computeGravitationalParameter( perturbedBodyMass );
    cout << "Perturbed body gravitational parameter                    " 
         << perturbedBodyGravitationalParameter << " m^3 s^-2" << endl;
         
    // Compute perturber population using density and semi-major axis distribution limits.
    // Note, in the floor() function, adding 0.5 is a workaround for the fact that there is no
    // round() function in C++03 (it is available in C++11).
    ConvertHillRadiiToMeters convertHillRadiiToMeters( 
        testParticleCaseData->centralBodyGravitationalParameter, 
        perturbedBodyGravitationalParameter, 
        testParticleCaseData->perturbedBodyStateInKeplerianElementsAtT0( semiMajorAxisIndex ) );
    const double perturberRingNumberDensityInMeters 
        = randomWalkRun->perturberRingNumberDensity / convertHillRadiiToMeters( 1.0 );
    const unsigned int perturberPopulation = std::floor( 
        2.0 * testParticleCaseData->semiMajorAxisDistributionLimit 
        * perturberRingNumberDensityInMeters + 0.5 );
    cout << "Perturber population                                      " 
         << perturberPopulation << endl;

    // Compute perturber mass ratio.
    // Note, for the random walk simulations, the mass ratio is equal for all perturbers.
    const double perturberMassRatio = randomWalkRun->perturberRingMass / perturberPopulation;
    cout << "Perturber mass ratio                                      "
         << perturberMassRatio << endl;

    ///////////////////////////////////////////////////////////////////////////

    ///////////////////////////////////////////////////////////////////////////

    // Execute Monte Carlo simulation.
    cout << endl;
    cout << "****************************************************************************" << endl;
    cout << "Simulation loop" << endl;
    cout << "****************************************************************************" << endl;
    cout << endl;

    // Execute simulation loop.
    cout << "Starting simulation loop ... " << endl;
    cout << randomWalkInputTable.size( ) << " random walk simulations queued for execution ..." 
         << endl;
    cout << endl;    

    // Loop over input table.
#pragma omp parallel for num_threads( numberOfThreads )
    for ( unsigned int i = 0; i < randomWalkInputTable.size( ); i++ )
    {
        ///////////////////////////////////////////////////////////////////////////

        // Set input table iterator and emit output message.

        // Set input table iterator for current simulation wrt to start of input table and counter.
        RandomWalkInputTable::iterator iteratorRandomWalkInputTable 
            = randomWalkInputTable.begin( );
        advance( iteratorRandomWalkInputTable, i );

        // Emit output message.
#pragma omp critical( outputToConsole )
        {
            cout << "Random walk simulation " 
                 << iteratorRandomWalkInputTable->randomWalkSimulationId 
                 << " on thread " << omp_get_thread_num( ) + 1 << " / " 
                 << omp_get_num_threads( ) << endl;
        }

        ///////////////////////////////////////////////////////////////////////////

        ///////////////////////////////////////////////////////////////////////////

        // Fetch test particle kick table based on test particle simulation IDs for random walk 
        // simulation.
        TestParticleKickTable testParticleKickTable;
#pragma omp critical( databaseOperations )
        {        
            testParticleKickTable = getTestParticleKickTable( 
                databasePath, testParticleCaseData->randomWalkSimulationPeriod,
                iteratorRandomWalkInputTable->testParticleSimulationIds, 
                testParticleKickTableName );
        }

        // Check if output mode is set to "FILE".
        // If so, open output file and write test particle kick table data.
        // Check if the output directory exists: if not, create it.
        if ( iequals( outputMode, "FILE" ) )
        {
            // Check if output directory exists.
            if ( !exists( fileOutputDirectory ) )
            {
               cerr << "Directory does not exist. Will be created." << endl;
               create_directories( fileOutputDirectory );
            }        

            // Declare file handler.
            ofstream testParticleKickTableFile;

            // Set up and write file header to file.
            ostringstream testParticleKickTableFilename;
            testParticleKickTableFilename << fileOutputDirectory << "randomWalkSimulation" 
                                          << iteratorRandomWalkInputTable->randomWalkSimulationId 
                                          << "_testParticleKickTable.csv";    

            testParticleKickTableFile.open( testParticleKickTableFilename.str( ).c_str( ) );

            testParticleKickTableFile 
                << "kickId,simulationId,conjunctionEpoch,conjunctionDistance,"
                << "preConjunctionEpoch,preConjunctionDistance,"
                << "preConjunctionSemiMajorAxis,preConjunctionEccentricity,"
                << "preConjunctionInclination,preConjunctionArgumentOfPeriapsis,"
                << "preConjunctionLongitudeOfAscendingNode,preConjunctionTrueAnomaly"
                << "postConjunctionEpoch,postConjunctionDistance,"
                << "postConjunctionSemiMajorAxis,postConjunctionEccentricity,"
                << "postConjunctionInclination,postConjunctionArgumentOfPeriapsis,"
                << "postConjunctionLongitudeOfAscendingNode,postConjunctionTrueAnomaly"
                << endl;
            testParticleKickTableFile 
                << "# [-],[-],[s],[m],[s],[m],[m],[-],[rad],[rad],[rad],[rad]," 
                << "[s],[m],[m],[-],[rad],[rad],[rad],[rad]" << endl;       

            // Write test particle kick table to file.
            for ( TestParticleKickTable::iterator iteratorTestParticleKicks 
                    = testParticleKickTable.begin( );
                  iteratorTestParticleKicks != testParticleKickTable.end( );
                  iteratorTestParticleKicks++ )
            {
                testParticleKickTableFile 
                    << iteratorTestParticleKicks->testParticleKickId << "," 
                    << iteratorTestParticleKicks->testParticleSimulationId << ",";
                testParticleKickTableFile
                    << setprecision( numeric_limits< double >::digits10 )
                    << iteratorTestParticleKicks->conjunctionEpoch << ","
                    << iteratorTestParticleKicks->conjunctionDistance << ","
                    << iteratorTestParticleKicks->preConjunctionEpoch << ","
                    << iteratorTestParticleKicks->preConjunctionDistance << ","
                    << iteratorTestParticleKicks->preConjunctionStateInKeplerianElements( 
                        semiMajorAxisIndex ) << ","
                    << iteratorTestParticleKicks->preConjunctionStateInKeplerianElements( 
                        eccentricityIndex ) << ","
                    << iteratorTestParticleKicks->preConjunctionStateInKeplerianElements( 
                        inclinationIndex ) << ","
                    << iteratorTestParticleKicks->preConjunctionStateInKeplerianElements( 
                        argumentOfPeriapsisIndex ) << ","
                    << iteratorTestParticleKicks->preConjunctionStateInKeplerianElements( 
                        longitudeOfAscendingNodeIndex ) << ","
                    << iteratorTestParticleKicks->preConjunctionStateInKeplerianElements( 
                        trueAnomalyIndex ) << ","
                    << iteratorTestParticleKicks->postConjunctionEpoch << ","
                    << iteratorTestParticleKicks->postConjunctionDistance << ","
                    << iteratorTestParticleKicks->postConjunctionStateInKeplerianElements( 
                        semiMajorAxisIndex ) << ","
                    << iteratorTestParticleKicks->postConjunctionStateInKeplerianElements( 
                        eccentricityIndex ) << ","
                    << iteratorTestParticleKicks->postConjunctionStateInKeplerianElements( 
                        inclinationIndex ) << ","
                    << iteratorTestParticleKicks->postConjunctionStateInKeplerianElements( 
                        argumentOfPeriapsisIndex ) << ","
                    << iteratorTestParticleKicks->postConjunctionStateInKeplerianElements( 
                        longitudeOfAscendingNodeIndex ) << ","
                    << iteratorTestParticleKicks->postConjunctionStateInKeplerianElements( 
                        trueAnomalyIndex ) << endl;
            }                 

            // Close file handler.
            testParticleKickTableFile.close( );
        }

        ///////////////////////////////////////////////////////////////////////////

        ///////////////////////////////////////////////////////////////////////////

        // Execute random walk simulation.

        // Declare perturbed body propagation history. This stores the propagation history of the
        // action variables only (semi-major axis, eccentricity, inclination).
        DoubleKeyVector3dValueMap keplerianActionElementsHistory;

        // Set perturbed body initial state (actions) in Keplerian elements.
        keplerianActionElementsHistory[ 0.0 ]
                = testParticleCaseData->perturbedBodyStateInKeplerianElementsAtT0.segment( 0, 3 );

        // Declare iterator to previous state in Keplerian elements.
        DoubleKeyVector3dValueMap::iterator iteratorPreviousKeplerianElements
                = keplerianActionElementsHistory.begin( );

        // Loop through aggregate kick table and execute kicks on perturbed body. 
        for ( TestParticleKickTable::iterator iteratorKickTable = testParticleKickTable.begin( );
              iteratorKickTable != testParticleKickTable.end( ); iteratorKickTable++ )
        {
            // Execute kick and store results in propagation history.
            keplerianActionElementsHistory[ iteratorKickTable->conjunctionEpoch ]
                    = executeKick( iteratorPreviousKeplerianElements->second,
                                   iteratorKickTable, perturberMassRatio );

            advance( iteratorPreviousKeplerianElements, 1 );
        }

        // Check if output mode is set to "FILE".
        // If so, open output file and write header content.
        if ( iequals( outputMode, "FILE" ) )
        {
            ostringstream keplerianActionElementsFilename;
            keplerianActionElementsFilename << "randomWalkSimulation" 
                                            << iteratorRandomWalkInputTable->randomWalkSimulationId
                                            << "_keplerianActionElements.csv"; 
            
            ostringstream keplerianActionElementsFileHeader;
            keplerianActionElementsFileHeader << "epoch,semiMajorAxis,eccentricity,inclination" 
                                              << endl;
            keplerianActionElementsFileHeader << "# [s],[m],[-],[rad]" << endl;

            writeDataMapToTextFile( keplerianActionElementsHistory,
                                    keplerianActionElementsFilename.str( ),
                                    fileOutputDirectory, 
                                    keplerianActionElementsFileHeader.str( ),
                                    numeric_limits< double >::digits10, 
                                    numeric_limits< double >::digits10,
                                    "," ); 
        }        

        ///////////////////////////////////////////////////////////////////////////

        ///////////////////////////////////////////////////////////////////////////

        // Compute average longitude residual and maximum longitude residual change in observation
        // period.

        // Declare average longitude residual in observation period [-].
        double averageLongitudeResidual = TUDAT_NAN;

        // Declare maximum longitude residual change in observation period [-].
        double maximumLongitudeResidualChange = TUDAT_NAN;

        // Declare map of average longitude residuals per window [rad].
        DoubleKeyDoubleValueMap averageLongitudeResiduals;

        {
            // Populate temporary map with epochs and semi-major axes.
            DoubleKeyDoubleValueMap semiMajorAxisHistory;

            for ( DoubleKeyVector3dValueMap::iterator iteratorKeplerianActionElements 
                  = keplerianActionElementsHistory.begin( );
                  iteratorKeplerianActionElements != keplerianActionElementsHistory.end( );
                  iteratorKeplerianActionElements++ )
            {
                semiMajorAxisHistory[ iteratorKeplerianActionElements->first ]
                    = iteratorKeplerianActionElements->second( semiMajorAxisIndex );
            }  

            // Compute longitude history.
            DoubleKeyDoubleValueMap longitudeHistory
                    = computeLongitudeHistory( 
                        semiMajorAxisHistory,
                        testParticleCaseData->centralBodyGravitationalParameter );      

            // Compute reduced longitude history (data is reduced to only the epoch windows).
            DoubleKeyDoubleValueMap reducedLongitudeHistory
                    = reduceLongitudeHistory( 
                        longitudeHistory, 
                        iteratorRandomWalkInputTable->observationPeriodStartEpoch,
                        epochWindowSpacing, 
                        randomWalkRun->epochWindowSize,
                        randomWalkRun->numberOfEpochWindows ); 

            // Set input data for simple linear regression.
            SimpleLinearRegression longitudeHistoryRegression( reducedLongitudeHistory );
         
            // Compute linear fit.
            longitudeHistoryRegression.computeFit( );        
                
            // Store longitude residuals history.
            DoubleKeyDoubleValueMap longitudeResidualsHistory;

            // Generate longitude history residuals by subtracting linear fit from data.
            for ( DoubleKeyDoubleValueMap::iterator iteratorReducedLongitudeHistory
                    = reducedLongitudeHistory.begin( );
                  iteratorReducedLongitudeHistory != reducedLongitudeHistory.end( );
                  iteratorReducedLongitudeHistory++ )
            {
                longitudeResidualsHistory[ iteratorReducedLongitudeHistory->first ]
                        = iteratorReducedLongitudeHistory->second
                          - longitudeHistoryRegression.getCoefficientOfConstantTerm( )
                          - longitudeHistoryRegression.getCoefficientOfLinearTerm( )
                          * iteratorReducedLongitudeHistory->first;
            }           

            // Loop over observation period and compute average longitude residuals per epoch window.
            for ( int windowNumber = 0; 
                  windowNumber < randomWalkRun->numberOfEpochWindows; 
                  windowNumber++ )
            {
                const double epochWindowCenter 
                    = iteratorRandomWalkInputTable->observationPeriodStartEpoch 
                      + windowNumber * epochWindowSpacing;

                averageLongitudeResiduals[ epochWindowCenter ] 
                    = computeStepFunctionWindowAverage( 
                        longitudeResidualsHistory, 
                        epochWindowCenter - 0.5 * randomWalkRun->epochWindowSize, 
                        epochWindowCenter + 0.5 * randomWalkRun->epochWindowSize );
            }

             // Compute average longitude residual during propagation history.
            double sumLongitudeResiduals = 0.0;

            for ( DoubleKeyDoubleValueMap::iterator iteratorAverageLongitudeResiduals 
                    = averageLongitudeResiduals.begin( );
                  iteratorAverageLongitudeResiduals != averageLongitudeResiduals.end( );
                  iteratorAverageLongitudeResiduals++ )
            {
                sumLongitudeResiduals += iteratorAverageLongitudeResiduals->second;
            }

            averageLongitudeResidual 
                = sumLongitudeResiduals / randomWalkRun->numberOfEpochWindows;

            // Compute maximum longitude residual change during propagation history.
            maximumLongitudeResidualChange 
                = ( max_element( averageLongitudeResiduals.begin( ), 
                                 averageLongitudeResiduals.end( ),
                                 CompareDoubleKeyDoubleValueMapValues( ) ) )->second
                  - ( min_element( averageLongitudeResiduals.begin( ), 
                                   averageLongitudeResiduals.end( ),
                                   CompareDoubleKeyDoubleValueMapValues( ) ) )->second;            

            // Check if output mode is set to "FILE".
            // If so, open output file and write header content.
            if ( iequals( outputMode, "FILE" ) )
            {
                ostringstream longitudeHistoryFilename;
                longitudeHistoryFilename << "randomWalkSimulation"
                                         << iteratorRandomWalkInputTable->randomWalkSimulationId
                                         << "_longitudeHistory.csv"; 
                
                ostringstream longitudeHistoryFileHeader;
                longitudeHistoryFileHeader << "epoch,longitude" << endl;
                longitudeHistoryFileHeader << "# [s],[rad]" << endl;

                writeDataMapToTextFile( longitudeHistory,
                                        longitudeHistoryFilename.str( ),
                                        fileOutputDirectory, 
                                        longitudeHistoryFileHeader.str( ),
                                        numeric_limits< double >::digits10, 
                                        numeric_limits< double >::digits10,
                                        "," );             

                ostringstream reducedLongitudeHistoryFilename;
                reducedLongitudeHistoryFilename 
                    << "randomWalkSimulation" 
                    << iteratorRandomWalkInputTable->randomWalkSimulationId
                    << "_reducedLongitudeHistory.csv"; 
                
                ostringstream reducedLongitudeHistoryFileHeader;
                reducedLongitudeHistoryFileHeader << "epoch,longitude" << endl;
                reducedLongitudeHistoryFileHeader << "# [s],[rad]" << endl;

                writeDataMapToTextFile( reducedLongitudeHistory,
                                        reducedLongitudeHistoryFilename.str( ),
                                        fileOutputDirectory, 
                                        reducedLongitudeHistoryFileHeader.str( ),
                                        numeric_limits< double >::digits10, 
                                        numeric_limits< double >::digits10,
                                        "," );            

                ostringstream longitudeResidualsFilename;
                longitudeResidualsFilename << "randomWalkSimulation"
                                           << iteratorRandomWalkInputTable->randomWalkSimulationId
                                           << "_longitudeResiduals.csv"; 
                
                ostringstream longitudeResidualsFileHeader;
                longitudeResidualsFileHeader << "epoch,longitudeResidual" << endl;
                longitudeResidualsFileHeader << "# [s],[rad]" << endl;      

                writeDataMapToTextFile( longitudeResidualsHistory,
                                        longitudeResidualsFilename.str( ),
                                        fileOutputDirectory, 
                                        longitudeResidualsFileHeader.str( ),
                                        numeric_limits< double >::digits10, 
                                        numeric_limits< double >::digits10,
                                        "," );                                                 
            }                       
        }

        ///////////////////////////////////////////////////////////////////////////        

        ///////////////////////////////////////////////////////////////////////////

        // Compute average eccentricity and maximum eccentricity change in observation window.

        // Declare average eccentricity in observation period [-].
        double averageEccentricity = TUDAT_NAN;

        // Declare maximum eccentricity change in observation period [-].
        double maximumEccentricityChange = TUDAT_NAN;

        // Declare map of average eccentricities per window [-].
        DoubleKeyDoubleValueMap averageEccentricities;

        {
            // Populate temporary map with epochs and eccentricities.
            DoubleKeyDoubleValueMap eccentricityHistory;

            for ( DoubleKeyVector3dValueMap::iterator iteratorKeplerianActionElements 
                  = keplerianActionElementsHistory.begin( );
                  iteratorKeplerianActionElements != keplerianActionElementsHistory.end( );
                  iteratorKeplerianActionElements++ )
            {
                eccentricityHistory[ iteratorKeplerianActionElements->first ]
                    = iteratorKeplerianActionElements->second( eccentricityIndex );
            }            

            // Loop over observation period and compute average eccentricities per epoch window.
            for ( int windowNumber = 0; 
                  windowNumber < randomWalkRun->numberOfEpochWindows; 
                  windowNumber++ )
            {
                const double epochWindowCenter 
                    = iteratorRandomWalkInputTable->observationPeriodStartEpoch
                      + windowNumber * epochWindowSpacing;

                averageEccentricities[ epochWindowCenter ] 
                    = computeStepFunctionWindowAverage( 
                        eccentricityHistory, 
                        epochWindowCenter - 0.5 * randomWalkRun->epochWindowSize, 
                        epochWindowCenter + 0.5 * randomWalkRun->epochWindowSize );
            }

            // Compute average eccentricity during propagation history.
            double sumEccentricities = 0.0;

            for ( DoubleKeyDoubleValueMap::iterator iteratorAverageEccentricities 
                    = averageEccentricities.begin( );
                  iteratorAverageEccentricities != averageEccentricities.end( );
                  iteratorAverageEccentricities++ )
            {
                sumEccentricities += iteratorAverageEccentricities->second;
            }

            averageEccentricity = sumEccentricities / randomWalkRun->numberOfEpochWindows;

            // Compute maximum eccentricity change during propagation history.
            maximumEccentricityChange 
                = ( max_element( averageEccentricities.begin( ), 
                                 averageEccentricities.end( ),
                                 CompareDoubleKeyDoubleValueMapValues( ) ) )->second
                  - ( min_element( averageEccentricities.begin( ), 
                                   averageEccentricities.end( ),
                                   CompareDoubleKeyDoubleValueMapValues( ) ) )->second;            
        }

        ///////////////////////////////////////////////////////////////////////////

        ///////////////////////////////////////////////////////////////////////////

        // Compute average inclination and maximum inclination change in observation window.

        // Declare average inclination in observation period [rad].
        double averageInclination = TUDAT_NAN;

        // Declare maximum inclination change in observation period [rad].
        double maximumInclinationChange = TUDAT_NAN;

        // Declare map of average inclinations per window [rad].
        DoubleKeyDoubleValueMap averageInclinations;        

        {
            // Populate temporary map with epochs and inclinations.
            DoubleKeyDoubleValueMap inclinationHistory;

            for ( DoubleKeyVector3dValueMap::iterator iteratorKeplerianActionElements 
                  = keplerianActionElementsHistory.begin( );
                  iteratorKeplerianActionElements != keplerianActionElementsHistory.end( );
                  iteratorKeplerianActionElements++ )
            {
                inclinationHistory[ iteratorKeplerianActionElements->first ]
                    = iteratorKeplerianActionElements->second( inclinationIndex );
            }            

            // Loop over observation period and compute average inclinations per epoch window.
            for ( int windowNumber = 0; 
                  windowNumber < randomWalkRun->numberOfEpochWindows; 
                  windowNumber++ )
            {
                const double epochWindowCenter 
                    = iteratorRandomWalkInputTable->observationPeriodStartEpoch
                      + windowNumber * epochWindowSpacing;

                averageInclinations[ epochWindowCenter ] 
                    = computeStepFunctionWindowAverage( 
                        inclinationHistory, 
                        epochWindowCenter - randomWalkRun->epochWindowSize * 0.5, 
                        epochWindowCenter + randomWalkRun->epochWindowSize * 0.5 );
            }

            // Compute average inclination during propagation history.
            double sumInclinations = 0.0;

            for ( DoubleKeyDoubleValueMap::iterator iteratorAverageInclinations 
                    = averageInclinations.begin( );
                  iteratorAverageInclinations != averageInclinations.end( );
                  iteratorAverageInclinations++ )
            {
                sumInclinations += iteratorAverageInclinations->second;
            }

            averageInclination = sumInclinations / randomWalkRun->numberOfEpochWindows;

            // Compute maximum inclination change during propagation history.
            maximumInclinationChange 
                = ( max_element( averageInclinations.begin( ), 
                                 averageInclinations.end( ),
                                 CompareDoubleKeyDoubleValueMapValues( ) ) )->second
                  - ( min_element( averageInclinations.begin( ), 
                                   averageInclinations.end( ),
                                   CompareDoubleKeyDoubleValueMapValues( ) ) )->second;        
        }

        ///////////////////////////////////////////////////////////////////////////

        ///////////////////////////////////////////////////////////////////////////

        // Write epoch-windoow average values to file.

        // Check if output mode is set to "FILE".
        // If so, open output file and write header content.
        if ( iequals( outputMode, "FILE" ) )
        {
            // Declare file handler.
            ofstream epochWindowAveragesFile;   

            ostringstream epochWindowAveragesFilename;
            epochWindowAveragesFilename << fileOutputDirectory << "randomWalkRun" 
                                        << iteratorRandomWalkInputTable->randomWalkSimulationId
                                        << "_epochWindowAverages.csv";
            
            epochWindowAveragesFile.open( epochWindowAveragesFilename.str( ).c_str( ) );

            epochWindowAveragesFile << "epoch,longitudeResidual,eccentricity,inclination" << endl;
            epochWindowAveragesFile << "# [s],[rad],[-],[rad]" << endl; 

            // Loop through epoch-window averages and write data to file.
            DoubleKeyDoubleValueMap::iterator iteratorEpochWindowAverageLongitudeResiduals
                = averageLongitudeResiduals.begin( );
            DoubleKeyDoubleValueMap::iterator iteratorEpochWindowAverageEccentricities
                = averageEccentricities.begin( );
            DoubleKeyDoubleValueMap::iterator iteratorEpochWindowAverageInclinations
                = averageInclinations.begin( );
                                                
            for ( int i = 0; i < randomWalkRun->numberOfEpochWindows; i++ )
            {
                epochWindowAveragesFile 
                    << setprecision( numeric_limits< double >::digits10 )
                    << iteratorEpochWindowAverageLongitudeResiduals->first << ","
                    << iteratorEpochWindowAverageLongitudeResiduals->second << ","
                    << iteratorEpochWindowAverageEccentricities->second << ","
                    << iteratorEpochWindowAverageInclinations->second << endl;

                iteratorEpochWindowAverageLongitudeResiduals++;    
                iteratorEpochWindowAverageEccentricities++;
                iteratorEpochWindowAverageInclinations++;
            }

            // Close file handler.
            epochWindowAveragesFile.close( );
        }        

        ///////////////////////////////////////////////////////////////////////////

        ///////////////////////////////////////////////////////////////////////////

        // Write random walk output to database. To avoid locking of the database, this section is
        // thread-critical, so will be executed one-by-one by multiple threads.

        // Check if output mode is set to "DATABASE".
        if ( iequals( outputMode, "DATABASE" ) )
        {
    #pragma omp critical( databaseOperations )
            {
                // Populate output table in database.
                populateRandomWalkOutputTable( 
                    databasePath, iteratorRandomWalkInputTable->randomWalkSimulationId,
                    averageLongitudeResidual, maximumLongitudeResidualChange,
                    averageEccentricity, maximumEccentricityChange,
                    averageInclination, maximumInclinationChange,
                    randomWalkOutputTableName, randomWalkInputTableName );
            }
        }

        /////////////////////////////////////////////////////////////////
    } // simulation for-loop

    ///////////////////////////////////////////////////////////////////
}