B
    bo                 @   sb   d Z ddlmZ ddlmZ ddlmZ ddlm	Z	m
Z
mZ ejfddZedejfd	d
ZdS )zL
This package contains some useful functionality for common tasks in OpenMM
    )unit)needs_openmm)	iteritems)rangezipmapc             C   s   t  }t  }t  }x8t| D ],}|drt| |}|dd ||< qW x(|  D ]}| }	||	 ||	< qZW x8t	|D ],\}
}|j
dd|
> d}| |||< qW |j
dd }|||d< |S )a'  
    This computes the energy of every force group in the given structure and
    computes the energy for each force group for the given Context.  Note, the
    context must have positions already assigned.

    Parameters
    ----------
    structure : Structure
        This should be the Structure object from which the System object in the
        Context was created
    context : mm.Context
        The OpenMM context set up for computing forces and energies
    nrg : energy unit, optional
        The unit to convert all energies into. Default is kcal/mol

    Returns
    -------
    dict {str:float}
        A dictionary mapping the name of the force group (taken from the
        attribute names of the format XXX_FORCE_GROUP in the structure object)
        with the energy of that group in
    Z_FORCE_GROUP T   )	getEnergygroups)r
   Ztotal)dictdirendswithgetattrreplacelowerZ	getSystem	getForcesgetForceGroupr   getStategetPotentialEnergyvalue_in_unit)	structurecontextnrgZ	all_namesZforce_group_namesZenergy_componentsattrvalforceZgpgrpnamestatee r!   2lib/python3.7/site-packages/parmed/openmm/utils.pyenergy_decomposition	   s     

r#   Nc                sJ  ddl m} dd  D }g }fdd zxFt D ]6\}}t||jrl||  || |	| q@W |dkr|
|dn|
|d|j|| j | jdk	rԈj| j  tt fdd	t S d}	xJt| D ]8\}
}t||jr4|||	  |	d
7 }	|	|
 qW X dS )a  
    This function computes the energy contribution for all of the different
    force groups.

    Parameters
    ----------
    structure : Structure
        The Structure with the coordinates for this system
    system : mm.System
        The OpenMM System object to get decomposed energies from
    platform : str
        The platform to use. Options are None (default), 'CPU', 'Reference',
        'CUDA', and 'OpenCL'. None will pick default OpenMM platform for this
        installation and computer
    nrg : energy unit, optional
        The unit to convert all energies into. Default is kcal/mol

    Returns
    -------
    energies : list of tuple
        Each entry is a tuple with the name of the force followed by its
        contribution
    r   Nc             S   s   g | ]}|  qS r!   )r   ).0fr!   r!   r"   
<listcomp>R   s    z/energy_decomposition_system.<locals>.<listcomp>c                s0   | j dd|> d}t|j|  fS )NTr	   )r
   r   )r   typeZgetForce__name__r   r   )r   r   st)r   systemr!   r"   _eneT   s    z)energy_decomposition_system.<locals>._enegMbP?c                s
    | S )Nr!   )x)r+   conr!   r"   <lambda>h       z-energy_decomposition_system.<locals>.<lambda>r	   )Zsimtk.openmmZopenmmr   	enumerate
isinstanceZNonbondedForceappendZgetReciprocalSpaceForceGroupZsetReciprocalSpaceForceGroupZsetForceGroupZContextZVerletIntegratorZPlatformZgetPlatformByNameZsetPositionsZ	positionsZboxZsetPeriodicBoxVectorsZbox_vectorslistr   r   ZgetNumForcesr   )r   r*   platformr   ZmmZ
old_groupsZold_recip_groupir%   idxr   r   r!   )r+   r-   r   r*   r"   energy_decomposition_system6   s0    

 r7   )__doc__Zparmedr   uZparmed.utils.decoratorsr   Zparmed.utils.sixr   Zparmed.utils.six.movesr   r   r   Zkilocalories_per_moler#   r7   r!   r!   r!   r"   <module>   s   -