Source code for openmicron.forcefield.aicgmodel

import numpy as np
import pandas as pd
from openmm import app
from openmm import unit
import sys
import os

from openmicron.forcefield.simulationsystem import SimulationSystem
from openmicron.forcefield import functionterms
from openmicron import utils

__location__ = os.path.dirname(os.path.abspath(__file__))
_A_to_nm = 0.1
_kcal_to_kj = 4.1840

[docs] class AICG2Model(SimulationSystem): """ A class for AICG2+ model **Attributes:** bonded_attr_name: list The categories of interactions within chains. Such as ['protein_bonds','protein_harmonic_angles','protein_aicg13_angles', 'protein_native_dihd','protein_aicg_dihd','protein_intra_contact'] nonbonded_attr_name: list The categories of interactions between chains. ['protein_inter_contact'] flp_bond_ang_params: pd.DataFrame The parameters of flexible local potential regarding bond angle. flp_bond_dihd_params: pd.DataFrame The parameters of flexible local potential regarding dihedral. protein_bonds: pd.DataFrame The parameters of harmonica bond interaction protein_harmonic_angles: pd.DataFrame The parameters of harmonica angle interaction protein_aicg13_angles: pd.DataFrame The parameters of aicg13 angles protein_native_dihd: pd.DataFrame The parameters of native dihedral protein_aicg_dihd: pd.DataFrame The parameters of aicg dihedral protein_intra_contact: pd.DataFrame The parameters of intra-contact protein_inter_contact: pd.DataFrame The parameters of inter-contact """ def __init__(self): """ Initialize. """ self.bonded_attr_name = ['protein_bonds','protein_harmonic_angles','protein_aicg13_angles', 'protein_native_dihd','protein_aicg_dihd','protein_intra_contact'] self.nonbonded_attr_name = ['protein_inter_contact'] self.parser_flp = utils.parser_flp_para() self.parser_flp.get_corr_flex_ang_para(f'{__location__}/para/flexible_local_abeta.para') self.flp_bond_ang_params = self.parser_flp.flp_bond_ang_params self.flp_bond_dihd_params = self.parser_flp.flp_bond_dihd_params
[docs] def add_protein_bond(self, force_group=1): """ Add protein bonds. Parameters ---------- force_group: int Force group. """ if hasattr(self, 'protein_bonds'): print('Add protein bonds.') force = functionterms.harmonic_bond_term(self.protein_bonds, False,force_group) self.system.addForce(force)
[docs] def add_protein_harmonic_angle(self,k_angle_scale=4,force_group=2): """ Add protein harmonic angles. Parameters ---------- force_group: int Force group. """ if hasattr(self, 'protein_harmonic_angles'): print('Add protein angles.') force = functionterms.harmonic_angle_term( self.protein_harmonic_angles,False,force_group) self.system.addForce(force)
[docs] def add_protein_aicg13_angle(self,force_group=3): """ Add protein aicg13 angles involved CA atom that describe the local structure in backbone chain Parameters ---------- force_group: int Force group. """ if hasattr(self, 'protein_aicg13_angles'): print('Add protien aicg13 angles.') aicg13_ang_params = self.protein_aicg13_angles ang_idx = [] ang_params = [] for row in aicg13_ang_params.itertuples(): if row.epsilon!=0: ang_idx.append([row.a1,row.a2,row.a3]) ang_params.append([row.epsilon,row.r0,row.width]) ang_idx = np.array(ang_idx).astype(np.int64) ang_params = np.array(ang_params).astype(np.float64) pd_ang_idx = pd.DataFrame(ang_idx,columns=['a1','a2','a3']) pd_ang_params = pd.DataFrame(ang_params,columns=['epsilon','r0','width']) aicg13_ang_params_invo_ca = pd.concat([pd_ang_idx,pd_ang_params],axis=1) force = functionterms.aicg13_angle_term(aicg13_ang_params_invo_ca,force_group=force_group) self.system.addForce(force)
[docs] def add_protein_native_dihedral(self,force_group=4): """ add native protein dihedrals for side bead. Parameters ---------- force_group: int Force group. """ if hasattr(self, 'protein_native_dihd'): print('Add protein native dihedral angle.') nat_dihd_params = self.protein_native_dihd dihd_idx = [] dihd_params = [] for row in nat_dihd_params.itertuples(): if row.k_dihd1 !=0 and row.k_dihd3!=0: dihd_idx.append([row.a1,row.a2,row.a3,row.a4]) dihd_params.append([row.k_dihd1,row.natdihd,row.k_dihd3]) dihd_idx = np.array(dihd_idx).astype(np.int64) dihd_params = np.array(dihd_params).astype(np.float64) pd_dihd_idx = pd.DataFrame(dihd_idx,columns=['a1','a2','a3','a4']) pd_dihd_params = pd.DataFrame(dihd_params,columns=['k_dihd1','natdihd','k_dihd3']) nat_dihd_params_invo_cb = pd.concat([pd_dihd_idx,pd_dihd_params],axis=1) force = functionterms.native_dihd_term(nat_dihd_params_invo_cb,force_group=force_group) self.system.addForce(force)
[docs] def add_protein_aicg_dihedral(self,force_group=5): """ add protein aicg dihedral angle for backbone chain. Parameters ---------- force_group: int Force group. """ if hasattr(self,'protein_aicg_dihd'): print('Add protein aicg dihedral.') aicg14_dihd_params = self.protein_aicg_dihd dihd_idx = [] dihd_params = [] for row in aicg14_dihd_params.itertuples(): if row.epsilon!=0: dihd_idx.append([row.a1,row.a2,row.a3,row.a4]) dihd_params.append([row.epsilon, row.natdihd,row.width]) dihd_idx = np.array(dihd_idx).astype(np.int64) dihd_params = np.array(dihd_params).astype(np.float64) pd_dihd_idx = pd.DataFrame(dihd_idx,columns=['a1','a2','a3','a4']) pd_dihd_params = pd.DataFrame(dihd_params,columns=['epsilon','natdihd','width']) nat_dihd_params_invo_ca = pd.concat([pd_dihd_idx,pd_dihd_params],axis=1) force = functionterms.aicg_dihd_term(nat_dihd_params_invo_ca, force_group=force_group) self.system.addForce(force)
[docs] def add_flexible_loc_angle(self,force_group=6): """ Add flexible local potential for angle are composed of CA atoms in backbone. Parameters ---------- force_group: int Force group. """ print('Add flexible local potential of angle of backbone.') flp_ang_idx = [] flp_ang_params = [] all_ca_atoms = [ai for ai in self.atoms if ai.name=='CA'] for i in range(len(all_ca_atoms)-2): a1 = all_ca_atoms[i] a2 = all_ca_atoms[i+1] a3 = all_ca_atoms[i+2] chain_idx = set([a1.residue.chain.index,a2.residue.chain.index,a3.residue.chain.index]) if len(list(chain_idx)) == 1: flp_ang_idx.append([a1.index,a2.index,a3.index]) flp_ang_params.append(self.flp_bond_ang_params[a2.residue.name]) flp_ang_idx = np.array(flp_ang_idx).astype(np.int64) flp_ang_params = np.array(flp_ang_params).astype(np.float64) pd_flp_ang_idx = pd.DataFrame(flp_ang_idx,columns=['a1','a2','a3']) pd_flp_ang_params = pd.DataFrame(flp_ang_params) flp_ang_idx_params = pd.concat([pd_flp_ang_idx,pd_flp_ang_params],axis=1) force = functionterms.flex_angle_term(flp_ang_idx_params,force_group=force_group) self.system.addForce(force)
[docs] def add_flexible_loc_dihedral(self,force_group=7): """ Add flexible local potential for dihedral angle are composed CA atoms in backbone. Parameters ---------- force_group: int Force group. """ print('Add flexible local potential of dihedral of backbone') flp_dihd_idx = [] flp_dihd_params = [] all_ca_atoms = [ai for ai in self.atoms if ai.name=='CA'] for i in range(len(all_ca_atoms)-3): a1 = all_ca_atoms[i] a2 = all_ca_atoms[i+1] a3 = all_ca_atoms[i+2] a4 = all_ca_atoms[i+3] chain_idx = set([a1.residue.chain.index,a2.residue.chain.index,a3.residue.chain.index,a4.residue.chain.index]) if len(list(chain_idx)) == 1: flp_dihd_idx.append([a1.index,a2.index,a3.index,a4.index]) centre_residue_pair_name = a2.residue.name + a3.residue.name flp_dihd_params.append(self.flp_bond_dihd_params[centre_residue_pair_name]) flp_dihd_idx = np.array(flp_dihd_idx).astype(np.int64) flp_dihd_params = np.array(flp_dihd_params).astype(np.float64) pd_flp_dihd_idx = pd.DataFrame(flp_dihd_idx,columns=['a1','a2','a3','a4']) pd_flp_dihd_params = pd.DataFrame(flp_dihd_params,columns=['C','c1','s1','c2','s2','c3','s3','fdih_ener_corr']) flp_dihd_idx_params = pd.concat([pd_flp_dihd_idx,pd_flp_dihd_params],axis=1) force = functionterms.flex_dihd_term(flp_dihd_idx_params,force_group=force_group) self.system.addForce(force)
[docs] def add_protein_native_pair(self,cutoff=2.5,force_group=8): """ Add native contact pair. Parameters ---------- force_group: int Force group. """ if hasattr(self, 'protein_inter_contact') or hasattr(self,'protein_intra_contact'): if hasattr(self, 'protein_inter_contact') and hasattr(self,'protein_intra_contact'): print('Add protein inter and intra native contact') inter_contact = self.protein_inter_contact.copy() intra_contact = self.protein_intra_contact.copy() protein_nat_con = pd.concat([intra_contact,inter_contact],axis=0) elif hasattr(self,'protein_inter_contact') and not hasattr(self,'protein_intra_contact'): print('Add protien inter native contact') protein_nat_con = self.protein_inter_contact.copy() elif not hasattr(self, 'protein_inter_contact') and hasattr(self,'protein_intra_contact'): print('Add protien intra native contact') protein_nat_con = self.protein_intra_contact.copy() force = functionterms.go_contact_term(protein_nat_con,self.use_pbc,cutoff,force_group) self.system.addForce(force)
[docs] def add_kim_hummer(self,path=f'{__location__}/para/kh.para',kh_model_symbol='D',T=300,kh_epsilon_scale=1.3,cutoff=2.5, rad_scale = 0.85,force_group=10): """ Add kim hummer potential between CB and CB which there is no native contact Parameters ---------- path: str The path of kim-hummer parameters file. kh_model_symbol: str The parameters represent symbols of the Kim-Hummer parameters model. The model consists of six types: A, B, C, D, E, and F. Specific numerical values are referenced from "Journal of Molecular Biology, 2008, 375(5): 1416-1433." T: float Temperature kh_epsilon_scale: float The parameter scale the size of kim-hummer epsilon. cutoff: float cutoff = truncated distance / rest length rad_scale: float scaling factor to radii(sigma) and default value is 0.85 force_group: int Force group. """ print('Add kim-hummer force') resi_type,epsilon_KH,sigma_KH = utils.parser_kh_params(path,kh_model_symbol,kh_epsilon_scale,T) num_type_resi = len(resi_type.keys()) sigma_KH = sigma_KH * rad_scale atom_resi_types = [] for ai in self.atoms: atom_resi_types.append(resi_type[ai.residue.name]) if hasattr(self,'extraexclusions'): extraexclusions = self.extraexclusions else: extraexclusions = None force = functionterms.kim_hummer_term(atom_resi_types,epsilon_KH,sigma_KH, self.exclusions,extraexclusions,use_pbc=self.use_pbc, cutoff=cutoff,force_group=force_group) self.system.addForce(force)
[docs] def add_excluded(self, epsilon=0.2,sigma = 3.8,cutoff=2.5,rad_scale=1,force_group=11): """ Add excluded interaction between atoms. Parameters ---------- cutoff: float cutoff = truncated distance / rest length rad_scale: float scaling factor to radii(sigma) and default value is 0.85 force_group: int Force group. """ print('Add excluded force') atom_type = [] exv_params = utils.parser_exv_params(f'{__location__}/para/exv.para') numbeadtype = len(exv_params.keys()) - 2 keys = list(exv_params.keys()) epsilon_map = np.zeros((numbeadtype,numbeadtype),dtype=float) sigma_map = np.zeros((numbeadtype,numbeadtype),dtype=float) epsilon_map[:] = exv_params['exv_coef'] for i in range(numbeadtype): for j in range(numbeadtype): sigma_map[i,j] = (exv_params[keys[i]] + exv_params[keys[j]])/2 for ai in self.atoms: atom_type.append(keys.index(ai.residue.name)) if hasattr(self,'extraexclusions'): extraexclusions = self.extraexclusions else: extraexclusions = None sigma_map = sigma_map * rad_scale force = functionterms.excluded_term(atom_type,epsilon_map,sigma_map, self.exclusions,extraexclusions,use_pbc=self.use_pbc, cutoff=cutoff,force_group=force_group) self.system.addForce(force)
[docs] def add_debye_huckel(self,dieletric_constant=80,ion_strength=0.02,temperature=300,extra_charged_atom=None,cutoff=20,force_group=13): """ Add electrical potential. Parameters ---------- ion_strength: float Salt concentration. temperature: float Temperature. extra_charged_atom: list This represents the additional atoms requiring charge to be added. It consists of N*2 lists, where the first column represents the atom index, and the second column represents the atom's charge. cutoff: float cutoff = truncated distance / rest length force_group: int Force group. """ print('Add debye huckel potential') self.auto_get_charged_atom() if extra_charged_atom is not None: self.charged_atoms = self.charged_atoms + extra_charged_atom pair_index_charged_atoms = [[i_ind_q[0],j_ind_q[0],i_ind_q[1],j_ind_q[1]] for i,i_ind_q in enumerate(self.charged_atoms[:-1]) for j,j_ind_q in enumerate(self.charged_atoms[i+1:])] force = functionterms.debye_Huckel_bond_form(pair_index_charged_atoms,self.exclusions,dieletric_constant=dieletric_constant, ion_strength=ion_strength,T=temperature, use_pbc=self.use_pbc,cutoff=cutoff,force_group=force_group) self.system.addForce(force)
[docs] def add_all_default_ener_function(self,oriented_Hbond=False,cutoff_hbond=2.5,cutoff_go=2.5,cutoff_kh=2.5,cutoff_exv=2.0,kh_epsilon_scale=1.3,temperature=300): """ Add all default energy function to create a aicg force field. Parameters ---------- oriented_Hbond: bool Whether to add orientation-dependent hydrogen bond between CA atoms for force field. If False, the hydrogen would not apply to f rce field. cutoff_hbond: float cutoff_hbond = truncated distance / rest length cutoff_go: float cutoff_go = truncated distance / rest length cutoff_kh: float cutoff_kh = truncated distance / rest length cutoff_exv: float cutoff_exv= truncated distance / rest length kh_epsilon_scale: float The parameter scale the size of kim-hummer epsilon. """ self.add_protein_bond(force_group=1) self.add_protein_harmonic_angle(force_group=2) self.add_protein_aicg13_angle(force_group=3) self.add_flexible_loc_angle(force_group=4) self.add_protein_native_dihedral(force_group=5) self.add_protein_aicg_dihedral(force_group=6) self.add_flexible_loc_dihedral(force_group=7) self.add_protein_native_pair(force_group=9) # cutoff=cutoffgo self.get_exclusion(exclude_nat_con=True) self.add_kim_hummer(cutoff=cutoff_kh,force_group=10) self.add_excluded(cutoff=cutoff_exv,force_group=11) atoms_per_chain = list(self.chains[0].atoms()) terminal_charge = [] for i in range(len(self.chains)): index_N = len(atoms_per_chain) * i + 0 index_C = len(atoms_per_chain) * i + 76 terminal_charge.append([index_N,1.0]) terminal_charge.append([index_C,-1.0]) self.add_debye_huckel(ion_strength=0.02, temperature=temperature,extra_charged_atom=terminal_charge,force_group=11)