#  Copyright (C) 2012,2013
#      Max Planck Institute for Polymer Research
#  Copyright (C) 2008,2009,2010,2011
#      Max-Planck-Institute for Polymer Research & Fraunhofer SCAI
#  
#  This file is part of ESPResSo++.
#  
#  ESPResSo++ is free software: you can redistribute it and/or modify
#  it under the terms of the GNU General Public License as published by
#  the Free Software Foundation, either version 3 of the License, or
#  (at your option) any later version.
#  
#  ESPResSo++ is distributed in the hope that it will be useful,
#  but WITHOUT ANY WARRANTY; without even the implied warranty of
#  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
#  GNU General Public License for more details.
#  
#  You should have received a copy of the GNU General Public License
#  along with this program.  If not, see <http://www.gnu.org/licenses/>. 


"""
************************************************************
**BerendsenBarostatAnisotropic** - Berendsen barostat Object
************************************************************

#TODO fix these comments 
This is the Berendsen barostat implementation according to the original paper [Berendsen84]_.
If Berendsen barostat is defined (as a property of integrator) then at the each run the system size
and the particle coordinates will be scaled by scaling parameter :math:`\mu` according to
the formula:

.. math::   \mu = [1 - \Delta t/\\tau (P_{0} - P)]^{1/3}

where :math:`\Delta t` - integration timestep, :math:`\\tau` - time parameter (coupling parameter),
:math:`P_{0}` - external pressure and :math:`P` - instantaneous pressure. 

Example:

    >>> berendsenP = espresso.integrator.BerendsenBarostatAnisotropic(system)
    >>> berendsenP.tau = 0.1
    >>> berendsenP.pressure = 1.0
    >>> integrator.addExtension(berendsenP)

**!IMPORTANT** In order to run *npt* simulation one should separately define thermostat as well 
(e.g. BerendsenThermostat_).

.. _BerendsenThermostat: espresso.integrator.BerendsenThermostat.html

Definition:

    In order to define the Berendsen barostat
    
    >>> berendsenP = espresso.integrator.BerendsenBarostatAnisotropic(system)
    
    one should have the System_ defined.

.. _System: espresso.System.html

Properties:

*   *berendsenP.tau*

    The property 'tau' defines the time parameter :math:`\\tau`.

*   *berendsenP.pressure*
    
    The property 'pressure' defines the external pressure :math:`P_{0}`.
    
Setting the integration property:
    
    >>> integrator.addExtension(berendsenP)
    
    It will define Berendsen barostat as a property of integrator.
    
One more example:

    >>> berendsen_barostat = espresso.integrator.BerendsenBarostatAnisotropic(system)
    >>> berendsen_barostat.tau = 10.0
    >>> berendsen_barostat.pressure = 3.5
    >>> integrator.addExtension(berendsen_barostat)


Canceling the barostat:
    
    If one do not need the pressure regulation in system anymore or need to switch
    the ensamble or whatever :)

    >>> # define barostat with parameters
    >>> berendsen = espresso.integrator.BerendsenBarostatAnisotropic(system)
    >>> berendsen.tau = 0.8
    >>> berendsen.pressure = 15.0
    >>> integrator.addExtension(berendsen)
    >>> ...
    >>> # some runs
    >>> ...
    >>> # disconnect Berendsen barostat
    >>> berendsen.disconnect()
    >>> # the next runs will not include the system size and particle coordinates scaling

    
  Connecting the barostat back after the disconnection
  
    >>> berendsen.connect()

"""


from espresso.esutil import cxxinit
from espresso import pmi

from espresso.integrator.Extension import *
from _espresso import integrator_BerendsenBarostatAnisotropic

class BerendsenBarostatAnisotropicLocal(ExtensionLocal, integrator_BerendsenBarostatAnisotropic):
  def __init__(self, system):
    'The (local) Velocity Verlet Integrator.'
    if not (pmi._PMIComm and pmi._PMIComm.isActive()) or \
            pmi._MPIcomm.rank in pmi._PMIComm.getMPIcpugroup():
      cxxinit(self, integrator_BerendsenBarostatAnisotropic, system)

if pmi.isController:
  class BerendsenBarostatAnisotropic(Extension):
    __metaclass__ = pmi.Proxy
    pmiproxydefs = dict(
      cls =  'espresso.integrator.BerendsenBarostatAnisotropicLocal',
      pmiproperty = [ 'tau', 'pressure' ]
    )
