// Copyright (c) 2009-2016 The Regents of the University of Michigan
// This file is part of the HOOMD-blue project, released under the BSD 3-Clause License.


// Maintainer: joaander

/*! \file Analyzer.h
    \brief Declares a base class for all analyers
*/

#ifdef NVCC
#error This header cannot be compiled by nvcc
#endif

#ifndef __ANALYZER_H__
#define __ANALYZER_H__

#include "Profiler.h"
#include "SystemDefinition.h"

#include <boost/shared_ptr.hpp>
#include <boost/utility.hpp>

/*! \ingroup hoomd_lib
    @{
*/

/*! \defgroup analyzers Analyzers
    \brief All classes that implement the Analyzer concept.
    \details See \ref page_dev_info for more information
*/

/*! @}
*/

//! Base class for analysis of particle data
/*! An Analyzer is a concept that encapsulates some process that is performed during
    the simulation with the sole purpose of outputting data to the user in some fashion.
    The results of an Analyzer can not modify the simulation in any way, that is what
    the Updater classes are for. In general, analyzers are likely to only be called every 1,000
    time steps or much less often (this value entirely at the user's discrestion).
    The System class will handle this. An Analyzer just needs to perform its calculations
    and make its output every time analyze() is called.

    By design Analyzers can reference any number of Computes while performing their
    analysis. The base class provides no methods for doing this, derived classes must
    implement the tracking of the attached Compute classes (via shared pointers)
    themselves. (it is recomenned to pass a shared pointer to the Compute
    into the constructor of the derived class).

    See \ref page_dev_info for more information

    \ingroup analyzers
*/
class Analyzer : boost::noncopyable
    {
    public:
        //! Constructs the analyzer and associates it with the ParticleData
        Analyzer(boost::shared_ptr<SystemDefinition> sysdef);
        virtual ~Analyzer() {};

        //! Abstract method that performs the analysis
        /*! Derived classes will implement this method to calculate their results
            \param timestep Current time step of the simulation
            */
        virtual void analyze(unsigned int timestep) = 0;

        //! Sets the profiler for the analyzer to use
        void setProfiler(boost::shared_ptr<Profiler> prof);

        //! Set autotuner parameters
        /*! \param enable Enable/disable autotuning
            \param period period (approximate) in time steps when returning occurs

            Derived classes should override this to set the parameters of their autotuners.
        */
        virtual void setAutotunerParams(bool enable, unsigned int period)
            {
            }

        //! Print some basic stats to stdout
        /*! Derived classes can optionally implement this function. A System will
            call all of the Analyzers' printStats functions at the end of a run
            so the user can see useful information
        */
        virtual void printStats()
            {
            }

        //! Reset stat counters
        /*! If derived classes implement printStats, they should also implement resetStats() to clear any running
            counters printed by printStats. System will reset the stats before any run() so that stats printed
            at the end of the run only apply to that run() alone.
        */
        virtual void resetStats()
            {
            }

        //! Get needed pdata flags
        /*! Not all fields in ParticleData are computed by default. When derived classes need one of these optional
            fields, they must return the requested fields in getRequestedPDataFlags().
        */
        virtual PDataFlags getRequestedPDataFlags()
            {
            return PDataFlags(0);
            }

        boost::shared_ptr<const ExecutionConfiguration> getExecConf()
            {
            return m_exec_conf;
            }

#ifdef ENABLE_MPI
        //! Set the communicator to use
        /*! \param comm The Communicator
         */
        virtual void setCommunicator(boost::shared_ptr<Communicator> comm)
            {
            m_comm = comm;
            }
#endif

    protected:
        const boost::shared_ptr<SystemDefinition> m_sysdef; //!< The system definition this analyzer is associated with
        const boost::shared_ptr<ParticleData> m_pdata;      //!< The particle data this analyzer is associated with
        boost::shared_ptr<Profiler> m_prof;                 //!< The profiler this analyzer is to use

#ifdef ENABLE_MPI
        boost::shared_ptr<Communicator> m_comm;             //!< The communicator to use
#endif

        boost::shared_ptr<const ExecutionConfiguration> m_exec_conf; //!< Stored shared ptr to the execution configuration
    };

//! Export the Analyzer class to python
void export_Analyzer();

#endif
