Skip to content

Commit

Permalink
Entropy/PCA updates
Browse files Browse the repository at this point in the history
  • Loading branch information
alsinmr committed Jun 4, 2024
1 parent 92af0cf commit 69371ef
Show file tree
Hide file tree
Showing 6 changed files with 577 additions and 37 deletions.
153 changes: 151 additions & 2 deletions Entropy/Entropy.py
Original file line number Diff line number Diff line change
Expand Up @@ -27,7 +27,7 @@
class EntropyCC:
R=8.31446261815324 #J/mol/K

def __init__(self,select):
def __init__(self,select,PCA=None):
"""
Initialize the Entropy Cross-Correlation object with either a selection
object or filename from a saved EntropyCC object
Expand All @@ -36,6 +36,7 @@ def __init__(self,select):
----------
select : MolSelect or string
pyDR selection object or filename
pca : PCA object (optional)
Returns
-------
Expand All @@ -62,6 +63,8 @@ def __init__(self,select):
self._Sres=temp._Sres
self._Scc=temp._Scc

self.PCA=PCA


def reset(self):
"""
Expand All @@ -86,7 +89,7 @@ def reset(self):
self._CCstate=None
self._Scc=None
self._CC=None

self._CCpca=None

return self

Expand Down Expand Up @@ -523,6 +526,152 @@ def Smax(self):
"""
return np.log(self.total_mult)*self.R

#%% Lagged CC
def LaggedCC(self,i0:int,i1:int,Nt:int=1000,step=1):
"""
Parameters
----------
i0 : int
DESCRIPTION.
i1 : int
DESCRIPTION.
Nt : int, optional
DESCRIPTION. The default is 1000.
step : TYPE, optional
DESCRIPTION. The default is 1.
Returns
-------
t : TYPE
DESCRIPTION.
out : TYPE
DESCRIPTION.
"""
out=np.zeros([2,Nt])
for k,N0 in enumerate(np.arange(Nt)*step):
if isinstance(i0,str) and i0.lower()=='pca':
state0=self.PCA.Cluster.state[:(None if N0==0 else -N0)]
mult=self.PCA.Cluster.n_clusters
else:
state0=self.state[i0,:(None if N0==0 else -N0)]
mult=self.total_mult[i0]
p=np.unique(state0,return_counts=True)[1]/len(state0)
S0=-(p*np.log(p)).sum()

if isinstance(i1,str) and i1.lower()=='pca':
state1=self.PCA.Cluster.state[N0:]
else:
state1=self.state[i1,N0:]
p=np.unique(state1,return_counts=True)[1]/len(state0)
S1=-(p*np.log(p)).sum()

state=state0+mult*state1
p=np.unique(state,return_counts=True)[1]/len(state0)
Scc=-(p*np.log(p)).sum()

out[0,k]=2*(S0+S1-Scc)/(S1+S0)

for k,N0 in enumerate(np.arange(Nt)*step):
if isinstance(i0,str) and i0.lower()=='pca':
state0=self.PCA.Cluster.state[N0:]
mult=self.PCA.Cluster.n_clusters
else:
state0=self.state[i0,N0:]
mult=self.total_mult[i0]
p=np.unique(state0,return_counts=True)[1]/len(state0)
S0=(p*np.log(p)).sum()

if isinstance(i1,str) and i1.lower()=='pca':
state1=self.PCA.Cluster.state[:(None if N0==0 else -N0)]
else:
state1=self.state[i1,:(None if N0==0 else -N0)]
p=np.unique(state1,return_counts=True)[1]/len(state0)
S1=(p*np.log(p)).sum()

state=state0+mult*state1
p=np.unique(state,return_counts=True)[1]/len(state0)
Scc=(p*np.log(p)).sum()

out[1,k]=2*(S0+S1-Scc)/(S1+S0)

t=np.arange(Nt)*step*self.traj.dt/1e3

return t,out

def plot_lag(self,i0:int,i1:int,Nt:int=1000,step:int=1,ax=None):
t,out=self.LaggedCC(i0=i0,i1=i1,Nt=Nt,step=step)

if ax is None:ax=plt.subplots()[1]

ax.plot(t,out.T)
ax.set_xlabel(r'$\Delta$t / ns')
ax.set_ylabel('C.C.')
label0='PCA' if isinstance(i0,str) and i0.lower()=='pca' else f'{self.resids[i0]}{AA(self.resi[i0].resname).symbol}'
label1='PCA' if isinstance(i1,str) and i1.lower()=='pca' else f'{self.resids[i1]}{AA(self.resi[i1].resname).symbol}'
ax.legend((f'{label1} follows {label0}',f'{label0} follows {label1}'))

return ax

#%% vs PCA
@property
def Spca(self):
"""
Return the entropy of states identified in PCA clustering
Returns
-------
float
"""
if self.PCA is None:return None

p=np.unique(self.PCA.Cluster.state,return_counts=True)[1]/len(self.PCA.Cluster.state)
return -self.R*(p*np.log(p)).sum()

@property
def CCpca(self):
"""
Return correlation coefficient between PCA states and individual side
chains
Returns
-------
np.array
"""
if self._CCpca is None:
Spca=self.Spca
S=self.Sres

state=self.state*(self.PCA.Cluster.state.max()+1)+self.PCA.Cluster.state

SCC=np.zeros(self.N)
for k in range(state.max()):
p=(state==k).mean(-1)
i=p>0
SCC[i]+=-self.R*(p[i]*np.log(p[i]))

self._CCpca=2*(S+Spca-SCC)/(S+Spca)


return self._CCpca

def plotCCpca(self,index=None,ax=None,**kwargs):
if ax is None:ax=plt.subplots()[1]
if index is None:index=np.ones(len(self.CCpca),dtype=bool)

if 'color' not in kwargs:kwargs['color']='black'
ax.plot(self.CCpca[index],**kwargs)
ax.xaxis.set_major_formatter(self._axis_formatter(index))
ax.tick_params(axis='x', labelrotation=90)
ax.set_ylabel('C.C')

return ax



#%% Plotting

Expand Down
5 changes: 2 additions & 3 deletions Frames/eval_fr.py
Original file line number Diff line number Diff line change
Expand Up @@ -1568,15 +1568,15 @@ def ini_vec_load(traj,frame_funs,tensor_fun,frame_index=None,index=None,info=Non
traj[i] #Go to current frame
for k,f in enumerate(frame_funs):
v[k].append(f())

vT.append(tensor_fun())
"Print the progress"
try:
if c%int(len(index)/100)==0 or c+1==len(index):
ProgressBar(c+1, len(index), prefix = 'Loading Ref. Frames:', suffix = 'Complete', length = 50)
except:
pass



for k,v0 in enumerate(v):
v[k]=np.array(v0)
"""Put the vectors in order such that if two vectors given, each vector
Expand All @@ -1587,6 +1587,5 @@ def ini_vec_load(traj,frame_funs,tensor_fun,frame_index=None,index=None,info=Non


vT=np.moveaxis(vT,0,-1)


return {'n_frames':nf,'v':v,'vT':vT,'t':t,'index':index,'frame_index':frame_index,'info':info}
60 changes: 49 additions & 11 deletions Frames/special_frames.py
Original file line number Diff line number Diff line change
Expand Up @@ -80,6 +80,7 @@ def sub()
import numpy as np
from pyDR.MDtools import vft
from pyDR.Selection import select_tools as selt
from copy import copy

def hop_setup(uni,sel1,sel2,sel3,sel4,ntest=1000):
"""
Expand Down Expand Up @@ -463,9 +464,24 @@ def __init__(self,molecule,sel1=None,sel2=None,resids=None,segids=None,filter_st
self.sel1,self.sel2=[selt.sel_simple(molecule,s,resids,segids,filter_str) for s in [sel1,sel2]]

self.sel0=selt.find_bonded(self.sel2,self.sel2.residues.atoms,exclude=self.sel1,n=3)

self.reset()

def reset(self):
self.vm1=None
self.vZc=None
self.vXZc=None
self.nuZ=np.zeros([3,len(self.sel1)])
self.nuZ[2]=1
self.nuXZ=np.zeros([3,len(self.sel1)])
self.nuXZ[0]=1

self.frame=-1
self.traj[0]
self.record_state()
return self

@property
def traj(self):
return self.molecule.traj


@property
Expand Down Expand Up @@ -510,6 +526,18 @@ def v(self):
for sel0 in self.sel0:
out.append(vft.norm(vft.pbc_corr((sel0.positions-self.sel2.positions).T,self.molecule.box)))
return out

#%% Here, we take care of the frame definition


def record_state(self):
if self.frame==self.traj.frame:return

self.frame=self.traj.frame
self.vm1=self.v
self.vZm1=self.vZ
self.vXZm1=self.vXZ
return self

@property
def overlap(self):
Expand All @@ -524,25 +552,35 @@ def overlap(self):
DESCRIPTION.
"""
if self.vm1 is None:
self.vZc=self.vZ
self.vXZc=self.vXZ
return None
self.vm1=self.v
vZ=self.vZ
return np.array([(vm1*vZ).sum(0) for vm1 in self.vm1])



@property
def hop(self):
if self.vm1 is None:
return np.zeros(len(self.sel1),dtype=bool)
else:
return np.logical_not(np.all(self.overlap[0]>=self.overlap[1:],axis=0))
# if self.vm1 is None:
# return np.zeros(len(self.sel1),dtype=bool)
# else:
return np.logical_not(np.all(self.overlap[0]>=self.overlap[1:],axis=0))

def __call__(self):
hop=self.hop
if self.traj.frame==0:self.reset()
hop=self.hop #Did a hop occur?

self.vm1=self.v

if np.any(hop):
nuZ,nuXZ=vft.applyFrame(self.nuZ[:,hop],self.nuXZ[:,hop],
nuZ_F=self.vZm1[:,hop],nuXZ_F=self.vXZm1[:,hop])
sc=vft.getFrame(self.vZ[:,hop],self.vXZ[:,hop])

self.nuZ[:,hop],self.nuXZ[:,hop]=vft.R(nuZ,*sc),vft.R(nuXZ,*sc)


self.record_state()

return copy(self.nuZ),copy(self.nuXZ)



Expand Down
38 changes: 32 additions & 6 deletions PCA/PCAclean.py
Original file line number Diff line number Diff line change
Expand Up @@ -18,7 +18,7 @@
from copy import copy,deepcopy
from ..misc.tools import linear_ex
from .PCAmovies import PCAmovies
from .PCAsubs import PCA_Ct,PCA_S2,PCAvecs,PCA2Data,Weighting,Impulse,Hist
from .PCAsubs import PCA_Ct,PCA_S2,PCAvecs,PCA2Data,Weighting,Impulse,Hist,Cluster



Expand All @@ -38,6 +38,7 @@ def __init__(self,select,align_ref='name CA',project=None):
self.clear()
self._source=clsDict['Source']('PCAmode')
self._n=None
self._ref_pos=None

self._select_bond=self.select.select_bond

Expand Down Expand Up @@ -94,6 +95,12 @@ def Hist(self):
self._Hist=Hist(self)
return self._Hist

@property
def Cluster(self):
if self._Cluster is None:
self._Cluster=Cluster(self)
return self._Cluster

#%% Misc.
def clear(self):
"""
Expand All @@ -105,7 +112,7 @@ def clear(self):
"""
keys=['_pos','_covar','_sel1index','_sel2index','_lambda','_PC','_pcamp','_mean',
'_S2','_Ct','_Vecs','_Data','_Movie','_Weighting','_Impulse','_Hist']
'_S2','_Ct','_Vecs','_Data','_Movie','_Weighting','_Impulse','_Hist','_Cluster']
for k in keys:setattr(self,k,None)
return self

Expand Down Expand Up @@ -359,9 +366,11 @@ def load(self,t0:int=None,tf:int=None,step=None):

pos=[]
ref=self.uni.select_atoms(self.align_ref)
self.traj[0]
ref0=ref.positions
ref0-=ref0.mean(0)
# self.traj[0]
# ref0=ref.positions
# ref0-=ref0.mean(0)
ref0=self.ref_pos

for _ in self.traj:
pos.append(self.align(ref0,ref,atoms))

Expand All @@ -378,7 +387,24 @@ def load(self,t0:int=None,tf:int=None,step=None):
self._pos=np.array(pos)
# self.align(ref)
self._covar=None #Clears any existing covariance matrix


@property
def ref_pos(self):
"""
Store positions of the reference atoms
Returns
-------
None.
"""
if self._ref_pos is None:
ref=self.uni.select_atoms(self.align_ref)
self.traj[0]
self._ref_pos=ref.positions
self._ref_pos-=self._ref_pos.mean(0)
return self._ref_pos

@staticmethod
def align(ref0,ref,atoms):
ref=ref.positions
Expand Down
Loading

0 comments on commit 69371ef

Please sign in to comment.