B
    bL                 @   sL  d Z ddlmZmZmZ ddlZddlmZ ddlZ	ddl
mZ ddlmZ ddlm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mZmZmZmZmZm Z m!Z!m"Z"m#Z#m$Z$m%Z%m&Z&m'Z'm(Z( ddl)m*Z* ddl+m,Z,m-Z-m.Z. ddl/m0Z0 dgZ1e*d#ddZ2dd Z3dd Z4dd Z5dd Z6dd Z7dd Z8dd  Z9d!d" Z:dS )$zf
Convert an OpenMM Topology into a Structure instance, optionally filling in
parameters from a System
    )absolute_importdivisionprint_functionN)defaultdict   )unit)OpenMMWarning)	load_file)!box_vectors_to_lengths_and_angles)Element)	Structure)Angle	AngleTypeAtomAtomTypeBondBondTypeCmapCmapTypeDihedralDihedralType
ExtraPointImproperImproperTypeNonbondedExceptionNonbondedExceptionTypeRBTorsionTypeUreyBradley)needs_openmm)integer_types	iteritemsstring_types)rangeload_topologyTc             C   s>  ddl m} t }t }x|  D ]}|j}	x| D ]}
|
j}|
j}x|
	 D ]}|j
dkrlt|jd}nVyt|j}W n tk
r   |j}Y nX t|ts|nd}t|j
j|j|j
j|d}|||||	 |||< qPW q6W q"W x.|  D ]"\}}|jt|| ||  qW |  }|dk	rvt| \}}|tj}|tj}|d |d |d |d |d |d g|_d}|dk	rt|trt|d	d
}|j |_ |jdk	r|jdk	rd	}|j|_n||_ |dk	rd	}||_|jdk	rt!"|j|_|dkr|S t|tr t|}t||j#s6t$dt%|j	|& krdt$dt%|j	|& f t' }|j(|j)|j*|j+|j,|j-|j.|j/f}|0 r|s|1 }t| \}}|tj}|tj}t!"|d |d |d |d |d |d g|_nd|_x4|2 D ]&}t||j3rF|j3|kr:t4|| n
t5|| nt||j6r`t7|| nt||j8rzt9|| nt||j:rt;|| nt||j<rt=||s&d	|_>t?@dtA ndt||jBrtC|| nJt||jDrtE||| n.t||r
qnd	|_>t?@dtF|jG tA |HtF| qW |S )aL	  
    Creates a :class:`parmed.structure.Structure` instance from an OpenMM
    Topology, optionally filling in parameters from a System

    Parameters
    ----------
    topology : :class:`simtk.openmm.app.Topology`
        The Topology instance with the list of atoms and bonds for this system
    system : :class:`simtk.openmm.System` or str, optional
        If provided, parameters from this System will be applied to the
        Structure. If a string is given, it will be interpreted as the file name
        of an XML-serialized System, and it will be deserialized into a System
        before used to supply parameters
    xyz : str or array of float
        Name of a file containing coordinate information or an array of
        coordinates. If file has unit cell information, it also uses that
        information unless ``box`` (below) is also specified
    box : array of 6 floats
        Unit cell dimensions
    condense_atom_types : bool, default=True
        If True, create unique atom types based on de-duplicating properties. If False,
        create one atom type for each atom in the system, even if its properties match
        an existing atom type.

    Returns
    -------
    struct : :class:`Structure <parmed.structure.Structure>`
        The structure from the provided topology

    Raises
    ------
    OpenMMWarning if parameters are found that cannot be interpreted or
    processed by ParmEd

    TypeError if there are any mismatches between the provided topology and
    system (e.g., they have different numbers of atoms)

    IOError if system is a string and it is not an existing file

    Notes
    -----
    Due to its flexibility with CustomForces, it is entirely possible that the
    functional form of the potential will be unknown to ParmEd. This function
    will try to use the energy expression to identify supported potential types
    that are implemented as CustomForce objects. In particular, quadratic
    improper torsions, when recognized, will be extracted.

    Other CustomForces, including the CustomNonbondedForce used to implement
    NBFIX (off-diagonal L-J modifications) and the 12-6-4 potential, will not be
    processed and will result in an unknown functional form.

    If an OpenMM Atom.id attribute is populated by a non-integer, it will be
    used to name the corresponding ParmEd AtomType object.
    r   N)name )atomic_numberr$   masstype   r   FT)Z
skip_bondszSsystem must be an OpenMM System object or serialized XML of an OpenMM System objectz?Topology and System have different numbers of atoms (%d vs. %d)z-Unknown functional form of CustomTorsionForcezUnsupported Force type %s)IZsimtk.openmmZopenmmr   dictZchainsidZresiduesr$   indexatomselementr   int
ValueError
isinstancer   r   r&   r'   Zadd_atombondsappendr   ZgetPeriodicBoxVectorsr
   value_in_unitu	angstromsZdegreesboxr!   r	   ZcoordinatesnpZasarrayZSystem	TypeErrorlengetNumParticlessetZCMMotionRemoverZAndersenThermostatZMonteCarloBarostatZMonteCarloAnisotropicBarostatZMonteCarloMembraneBarostatZCustomExternalForceZGBSAOBCForceZCustomGBForceZusesPeriodicBoundaryConditionsZgetDefaultPeriodicBoxVectorsZ	getForcesZHarmonicBondForce_process_urey_bradley_process_bondZHarmonicAngleForce_process_angleZPeriodicTorsionForce_process_dihedralZRBTorsionForce_process_rbtorsionZCustomTorsionForce_process_improperunknown_functionalwarningswarnr   ZCMAPTorsionForce_process_cmapZNonbondedForce_process_nonbondedr(   __name__add)ZtopologysystemZxyzr7   condense_atom_typesZmmstructZatommapcchainrZresidueZresidaatomZaidZatypeZa1a2ZvectorsZlengZangZ
loaded_boxZprocessed_forcesZignored_forcesforce rT   6lib/python3.7/site-packages/parmed/openmm/topsystem.pyr#      s    8

*




2c             C   s   t  }xt| D ]}||\}}}}| j| | j|  }}	|j|jf}
|
|kr^||
 }n"t|d |}|||
< | j| |	|j	krx |j
D ]}|	|krP qW td||_q| j
t||	|d qW | j  dS )z' Adds bond parameters to the structure g      ?z4aj in ai.bond_partners, but couldn't find that bond!)r(   N)r*   r"   getNumBondsgetBondParametersr-   _valuer   Z
bond_typesr3   bond_partnersr2   RuntimeErrorr(   r   claim)rL   rS   typemapiiijreqkaiajkeyZ	bond_typeZbondrT   rT   rU   r>      s$    

r>   c          	   C   s   t  }xt| D ]}||\}}}}}|j|jf}	| j| | j| | j|   }
}}|	|krl||	 }n"t|d |}|||	< | j| | j	t
|
|||d qW | j  dS )z( Adds angle parameters to the structure g      ?)r(   N)r*   r"   ZgetNumAnglesZgetAngleParametersrX   r-   r   Zangle_typesr3   anglesr   r[   )rL   rS   r\   r]   r^   r_   ra   ZtheteqZfrc_krd   rb   rc   akZ
angle_typerT   rT   rU   r?      s    "
r?   c             C   s   | j stdt t }xt| D ]}||\}}}}| j| | j|  }}	|j	|j	f}
| j r||	j
krtd|j|	jf t |
|kr||
 }n"t|d |}|||
< | j| | jt||	|d q&W | j  dS )z/ Adds Urey-Bradley parameters to the structure zAdding what seems to be Urey-Bradley terms before Angles. This is unexpected, but the parameters will all be present in one form or another.zAdding what seems to be Urey-Bradley terms, but atoms %d and %d do not appear to be angled to each other. Parameters will all be present, but may not be in expected places.g      ?)r(   N)re   rD   rE   r   r*   r"   rV   rW   r-   rX   Zangle_partnersidxr   Zurey_bradley_typesr3   Zurey_bradleysr   r[   )rL   rS   r\   r]   r^   r_   r`   ra   rb   rc   rd   Z	urey_typerT   rT   rU   r=      s&    
r=   c             C   s   t  }xt| D ]}||\}}}}}}	}
| j| | j|  }}| j| | j|  }}||	j|
jf}||kr||| }n t|
||	}|||< | j| ||j	ko||j	ko||j	k}| j
t||||||d qW | j  dS )z) Adds periodic torsions to the structure )improperr(   N)r*   r"   getNumTorsionsgetTorsionParametersr-   rX   r   Zdihedral_typesr3   rY   Z	dihedralsr   r[   )rL   rS   r\   r]   r^   r_   ra   lZperZphaseZphi_krb   rc   rf   alrd   
dihed_typerh   rT   rT   rU   r@     s     

r@   c             C   s2  t  }xt| D ]}||\
}}}}}}	}
}}}| j| | j|  }}| j| | j|  }}y$|j|	j|
j|j|j|jf}d}W n* tk
r   ||	|
|||f}tj}Y nX ||kr|| }n>t	|| |	| |
| || || || }|||< | j
| | jt|||||d qW | j
  dS )z3 Adds Ryckaert-Bellemans torsions to the structure r)   )r(   N)r*   r"   ri   rj   r-   rX   AttributeErrorr5   kilojoules_per_moler   Zrb_torsion_typesr3   Zrb_torsionsr   r[   )rL   rS   r\   r]   r^   r_   ra   rk   Zc0Zc1Zc2Zc3Zc4Zc5rb   rc   rf   rl   rd   frm   rT   rT   rU   rA     s$    
*rA   c          
   C   s$  |  dd}d|kr*|d|d }|dkr6dS |drFd}nd	}t }xt| D ]}||\}}}}	\}
}| j| | j|  }}| j| | j|	  }}|
|f}||kr|| }n8t	|
| t
j t
jd
  |t
j }|||< | j| | jt|||||d q^W | j  dS )a@   Processes a CustomTorsionForce and looks at the energy expression to see
    if it's a quadratic improper torsion. Then adds the parameters if applicable

    Returns
    -------
    is_improper : bool
        Returns True if the energy expression is recognized as a quadratic
        improper, and False otherwise
     r%   ;N)z0.5*k*(theta-theta0)^2zk*(theta-theta0)^2zk*dtheta_torus^2z0.5*k*dtheta_torus^2Fz0.5g      ?r)   r   )r(   T)ZgetEnergyFunctionreplacer,   
startswithr*   r"   ri   rj   r-   r   r5   Zkilojoule_per_moleZradianZimproper_typesr3   Z	impropersr   r[   )rL   rS   ZeqnZfacr\   r]   r^   r_   ra   rk   Zpsi_kZpsi_eqrb   rc   rf   rl   rd   Zimp_typerT   rT   rU   rB   2  s.    



rB   c             C   sX  g }xft | D ]V}||\}}t|r:t||}nt||tj }|| |jj	
 |_d|_qW xt | D ]}||\	}}}}	}
}}}}||ks|	|ks|
|krtdt qz| j| | j| | j|	   }}}| j|
 | j|  }}|| }d|_| jt||||||d qzW x"|D ]}|jr,| j| q,W | j  dS )z Adds CMAPs to the structure Fz5Non-continuous CMAP torsions detected. Not supported.T)r(   N)r"   Z
getNumMapsZgetMapParametersr5   Zis_quantityr   ro   r3   gridTZswitch_rangeZusedri   rj   rD   rE   r   r-   Zcmapsr   
cmap_typesr[   )rL   rS   rw   r]   sizeru   typZmapidxZijZikZilZjiZjjZjkZjlrb   rc   rf   rl   ZamZ	cmap_typerT   rT   rU   rF   \  s0    


" 
rF   c          	   C   s`  t  }tt}| t| jks(tdxt| D ]}| j| }||\}}}	|j	dkrd|j	nt
|j }
|
|j|	jf}||kr|r|| }nD|j	dkr||
  d7  < d|
||
 f }
t|
d|j|j ||< }|tj|_|tjd d }|	tj}	||	| ||_|j|_	q6W tt}tt}xr| jD ]h}x`|jD ]V}||k	rb|| | x6|jD ],}||kr|qj||k	rj|| | qjW qFW q:W x t| D ]}||\}}}}}	|tjd }|tj}|	tj}	| j| | j|  }}|dkrL|dks,|	dkrL|| | || | qy||j|j  }W n0 tk
r   |dkrt d	| d}Y nX t!|d |	|}| j"#t$|||d
 | j%#| qW | j%&  d}x$| j%D ]}|j'dk	r|j'}P qW x"| j%D ]}|j'dkr||_'qW x8t(|D ],\}}|||  r,d| _)t*+dt, P q,W dS )z, Adds nonbonded parameters to the structure zAtom # mismatchr%   r)   z%s%dNgÚ?r   r   z(Can't scale charge product 0 to match %s)r(   g      ?Tz.Detected incomplete exceptions. Not supported.)-r*   r   r/   r;   r:   r-   AssertionErrorr"   ZgetParticleParametersr(   r   r&   rX   r   r'   r4   r5   Zelementary_chargeZcharger6   Zkilocalories_per_moleZset_lj_params	atom_typer$   r<   rY   rI   ZgetNumExceptionsZgetExceptionParametersZangstromZkilocalorie_per_moleZeroDivisionErrorr0   r   Zadjustsr3   r   Zadjust_typesr[   chgscaler    rC   rD   rE   r   )rL   rS   rK   r\   Zelement_typemapr^   rQ   ZchgZsigZepsZ
atype_namerd   r{   ZrminZexplicit_exceptionsZbond_graph_exceptionsrR   Za3r]   r_   qrb   rc   r}   ZnbtypeZfirst_scaling_factorZadjust_type
exceptionsrT   rT   rU   rG   {  s    






 
 


rG   )NNNT);__doc__Z
__future__r   r   r   rD   collectionsr   Znumpyr8   r%   r   r5   r   r   Zformatsr	   Zgeometryr
   Zperiodic_tabler   Z	structurer   Ztopologyobjectsr   r   r   r   r   r   r   r   r   r   r   r   r   r   r   r   r   Zutils.decoratorsr   Z	utils.sixr   r    r!   Zutils.six.movesr"   __all__r#   r>   r?   r=   r@   rA   rB   rF   rG   rT   rT   rT   rU   <module>   s4   L '*