-
Notifications
You must be signed in to change notification settings - Fork 0
Expand file tree
/
Copy pathqmat.py
More file actions
299 lines (226 loc) · 10.1 KB
/
qmat.py
File metadata and controls
299 lines (226 loc) · 10.1 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
import numpy as np
import MinimumSpanningTree as span
from numpy import linalg as LA
from numpy.linalg import inv
import copy
class Q_mat:
"""build Q matrix for kinetic calculations
"""
def __init__(self,N_states):
self.N_states = N_states
self.setup()
def setup (self):
#why is this a separate method? - is it called independently?
self.Q = np.zeros([self.N_states,self.N_states])
#unit matrices
self.u_col = np.ones((self.N_states,1))
self.u_row = np.ones((1,self.N_states))
def show(self):
"""Q-Matrix in string format"""
mat = "[\n"
for i in range(self.N_states):
line = "["
for j in range(self.N_states):
line += str(self.Q[i,j])
line += "\t"
line += "]"
mat += line + "\n"
mat += "]"
return mat
def set(self, i, j, value):
self.Q[i,j] = value
def get(self, i, j):
return self.Q[i, j]
def build_Q(self, rates):
"""Build Q-matrix, ignoring concentration + MR"""
for transition in rates:
rate_value = rates.get(transition)
#print transition, rate_value, rate_value[1], rate_value[1][0]
self.Q [transition] = rate_value [1][0]
self.rates = rates
# do this instead at the end otherwise, doing it twice gives 0. on diagonal
#for Row_sum, index in zip(self.Q.sum(1), range(self.N_states)):
#self.Q [index, index] = -Row_sum
def rebuild_Q(self):
"""Build Q-matrix, including all updates from MR"""
print("Rebuilding Q...")
for transition in self.rates:
rate_value = self.rates.get(transition)
#print transition, rate_value, rate_value[1], rate_value[1][0]
self.Q [transition] = rate_value [1][0]
def arrange_MR_on_Q(self, params):
"""Setup MR paths for Q matrix
arguments --
rate dictionary - not needed
params: dictionary with MR info
"""
#print params FINE AS DICT
###ONLY HAVE TO DO MR once for each jump
if params['MR_option'] != 'HardCoded':
self.graph = span.Q_Converter(self)
self.mst = span.MR_trees(self.graph)
# Use terms MR_avoid and MR_use to calculate MR paths
# MR_avoid should be the exact transition [a b] to constrain.
# This trick will give the right direction on cycle
if params['MR_option'] == 'Automatic':
#This should be reproducible and quite fast.
print ('\n-------------\nAutomatic MR\n--------------')
print ('Parameters ( [use] [avoid] ): ' + str(params['MR_use']) + str(params['MR_avoid'])+'\n')
self.mst.setup_MR(params['MR_avoid'], params['MR_use'])
#print self.mst.MR_paths good for debugging perhaps but otherwise overkill
elif params['MR_option'] == 'User_def':
self.mst.UserDefMR()
elif params['MR_option'] == 'Ignore':
pass
#elif params['MR_option'] == 'HardCoded':
#hardcoding, skip with MR=None
#these examples only work for particular models with these rate names
#OBSOLETE
# if MR.keys()[0] == 'k_min':
# a = rates['d1_min'][2]
# b = rates['d1_pl'][2]
# c = rates['d0_min'][2]
# d = rates['d0_pl'][2]
# ### kw = rates['k_min'][2]
# kx = rates['k_pl'][2]
# ky = rates['kd_pl'][2]
#kz = rates['kd_min'][2]
# self.Q [MR['k_min'][0],MR['k_min'][1]] = (b*kz*c*kx)/(d*ky*a) #MR
# if MR.keys()[0] == 'd0_pl':
# a = rates['d1_min'][2]
# b = rates['d1_pl'][2]
# c = rates['d0_min'][2]
#d = rates['d0_pl'][2]
# kw = rates['k_min'][2]
# kx = rates['k_pl'][2]
# ky = rates['kd_pl'][2]
# kz = rates['kd_min'][2]
# self.Q [MR['d0_pl'][0],MR['d0_pl'][1]] = (b*c*kz*kx)/(ky*a*kw) #MR
# if MR.keys()[0] == 'dop_min':
# a = rates['d1_min'][2]
# b = rates['d1_pl'][2]
# c = rates['dop_pl'][2]
# #d = rates['d0_pl'][2]
# kw = rates['beta'][2]
# kx = rates['alpha'][2]
# ky = rates['d2_pl'][2]
# kz = rates['d2_min'][2]
# self.Q [MR['dop_min'][0],MR['dop_min'][1]] = (kw*c*kz*a)/(ky*b*kx) #MR
#
# if MR.keys()[0] == 'alpha':
# a = rates['d1_min'][2]
# b = rates['d1_pl'][2]
# c = rates['dop_pl'][2]
# d = rates['dop_min'][2]
# kw = rates['beta'][2]
# #kx = rates['alpha'][2]
# ky = rates['d2_pl'][2]
# kz = rates['d2_min'][2]
#self.Q [MR['alpha'][0],MR['alpha'][1]] = (kw*c*kz*a)/(ky*b*d) #MR
def apply_MR_on_Q(self):
"""modify Q matrix according to MR constraints"""
for MR_rate in self.mst.MR_paths:
## for each MR, need to setup numerator prod, denom product
print "\nImposing MR on rate", MR_rate
eachpath = self.mst.MR_paths[MR_rate]
e = copy.deepcopy(eachpath) #deepcopy
n = MR_rate[:]
m = (int(n[1]), int(n[0])) #get tuple of opposing rate to MR
num_r = [m]
num = self.rates[m][1][0]
num_rates = [num]
while e != []:
index_tuple = tuple(int(x) for x in e.pop(0))
rate_constant = self.rates[index_tuple][1][0]
num *= rate_constant
#print index_tuple, rate_constant, den
num_r.append(index_tuple)
num_rates.append(rate_constant)
#print m, rates[m][1][0], num
f = copy.deepcopy(eachpath) #deepcopy
den = 1
den_r = []
den_rates = []
while f != []:
idx = [int(x) for x in f.pop(0)]
#print idx
idx.reverse() # reverse the list to get the opposing rate
#print idx
index_tuple = tuple(idx)
rate_constant = self.rates[index_tuple][1][0]
#print index_tuple, rate_constant
den *= rate_constant
den_r.append(index_tuple)
den_rates.append(rate_constant)
MR_rate_tuple = tuple(int(x) for x in MR_rate)
den_r.reverse() #for ease of reading (not if you forget to also reverse the other list too)
den_rates.reverse() #THIS LINE WAS OMITTED - CRAZY MAKING
print 'numerator rates: ', zip(num_r, num_rates)
print 'denominator rates:', zip(den_r, den_rates)
print 'Rate was: ', self.rates[MR_rate_tuple], '. Now setting to: ', num / den
self.rates[MR_rate_tuple][1][0] = num / den
print 'Updated rate dictionary: ', MR_rate_tuple, self.rates[MR_rate_tuple]
self.rebuild_Q()
print ("Q matrix updated, element " + str(MR_rate_tuple) + " set to: " + str(self.Q[MR_rate_tuple]))
print "\nMR Done\n"
def add_agonist_dependence_to_Q(self, drugs):
#cycle thru all keys to find concentration dependent rates
# NOT TRUE rate_value has format [ initial state, final state, rate constant, conc_depend_flag]
for transition in self.rates:
if self.rates[transition][1][1] in drugs:
#print transition, agonist, self.Q [transition]
self.Q [transition] = self.Q [transition] * drugs[self.rates[transition][1][1]]
#print self.Q [transition]
# make diagonal correct replace with method?
for Row_sum, index in zip(self.Q.sum(1),range(self.N_states)):
self.Q [index, index] = -Row_sum
#print self.Q
def do_diag(self):
for Row_sum, index in zip(self.Q.sum(1),range(self.N_states)):
self.Q [index, index] = -Row_sum
def p_infinity(self):
"""Calculate equilibrium occupancy"""
self.S = np.append(self.Q,self.u_col,axis=1)
SST = np.dot(self.S,self.S.transpose())
self.pinf = np.dot(self.u_row,inv(SST))
def update_rate(self, transition, new_value):
"""Change rate constant for a transition in the Q matrix"""
self.Q[transition] = new_value
### the problem of how to make a tuple that can access the rate in Q
### correspond to a rate name _ SOLVED tuple key NO LIST_KEY!!!
def spectral(self):
'''Calculate spectral matrices of Q matrix'''
#np.set_printoptions(precision=3,linewidth=150)
k = self.N_states
w, v = LA.eig(self.Q)
ind = np.argsort(w)
v = v[:,ind]
self.eigenval = w[ind]
N = v
M = inv(v)
self.A_mat = np.zeros([k, k, k])
for index in range(k):
n = np.matrix(N[:, index])
m = np.matrix(M[index, :])
n.shape = (k,1)
self.A_mat[:, :, index]= n * m
#TEST
#s = np.zeros([k,k])
#for a in range(k):
#s = s + self.A_mat[:,:,a]*self.eigenval[a]
#print "Q"
#print self.Q
#print "s"
#print s
#print self.Q == s,'should be equal'
#import sys; sys.exit()
def coefficient_calc(self, p_occup):
"""Calculate weighted components for relaxation for each state p * An"""
k =self.N_states
self.w = np.zeros([k,k])
for n in range (k):
self.w[n,:] = np.matrix(p_occup)*self.A_mat[:,:,n]
def relax(self, P_init):
self.p_infinity()
self.spectral()
self.coefficient_calc(P_init)