// 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: jglaser

#include "TwoStepNVTMTK.h"

#ifndef __TWO_STEP_NVT_MTK_GPU_H__
#define __TWO_STEP_NVT_MTK_GPU_H__

/*! \file TwoStepNVTMTKGPU.h
    \brief Declares the TwoStepNVTMTKGPU class
*/

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

#include "hoomd/Autotuner.h"

//! Integrates part of the system forward in two steps in the NVT ensemble on the GPU
/*! Implements Nose-Hoover NVT integration through the IntegrationMethodTwoStep interface, runs on the GPU

    In order to compute efficiently and limit the number of kernel launches integrateStepOne() performs a first
    pass reduction on the sum of m*v^2 and stores the partial reductions. A second kernel is then launched to recude
    those to a final \a sum2K, which is a scalar but stored in a GPUArray for convenience.

    \ingroup updaters
*/
class TwoStepNVTMTKGPU : public TwoStepNVTMTK
    {
    public:
        //! Constructs the integration method and associates it with the system
        TwoStepNVTMTKGPU(boost::shared_ptr<SystemDefinition> sysdef,
                      boost::shared_ptr<ParticleGroup> group,
                      boost::shared_ptr<ComputeThermo> thermo,
                      Scalar tau,
                      boost::shared_ptr<Variant> T,
                      const std::string& suffix = std::string(""));
        virtual ~TwoStepNVTMTKGPU() {};

        //! Performs the first step of the integration
        virtual void integrateStepOne(unsigned int timestep);

        //! Performs the second step of the integration
        virtual void integrateStepTwo(unsigned int timestep);

        //! Set autotuner parameters
        /*! \param enable Enable/disable autotuning
            \param period period (approximate) in time steps when returning occurs
        */
        virtual void setAutotunerParams(bool enable, unsigned int period)
            {
            TwoStepNVTMTK::setAutotunerParams(enable, period);
            m_tuner_one->setPeriod(period);
            m_tuner_one->setEnabled(enable);
            m_tuner_two->setPeriod(period);
            m_tuner_two->setEnabled(enable);
            m_tuner_rescale->setPeriod(period);
            m_tuner_rescale->setEnabled(enable);
            m_tuner_reduce->setPeriod(period);
            m_tuner_reduce->setEnabled(enable);
            }

    protected:
        boost::scoped_ptr<Autotuner> m_tuner_one; //!< Autotuner for block size (step one kernel)
        boost::scoped_ptr<Autotuner> m_tuner_two; //!< Autotuner for block size (step two kernel)
        boost::scoped_ptr<Autotuner> m_tuner_reduce; //!< Autotuner for reduction size (step two)
        boost::scoped_ptr<Autotuner> m_tuner_rescale; //!< Autotuner for temperature rescaling (step two)

        GPUVector<Scalar> m_scratch;    //!< Scratch space for reduction of squared velocities
        GPUArray<Scalar> m_temperature; //!< Stores temperature after reduction step
    };

//! Exports the TwoStepNVTMTKGPU class to python
void export_TwoStepNVTMTKGPU();

#endif // #ifndef __TWO_STEP_NVT_MTK_GPU_H__
