def ideal_subset_mean_life_time(Q, state1, state2): """ Calculate mean life time in a specified subset. Add all rates out of subset to get total rate out. Skip rates within subset. Parameters ---------- mec : instance of type Mechanism state1,state2 : int State numbers (counting origin 1) Returns ------- mean : float Mean life time. """ k = Q.shape[0] p = qml.pinf(Q) # Total occupancy for subset. pstot = np.sum(p[state1-1 : state2]) # Total rate out if pstot == 0: mean = 0.0 else: s = 0.0 for i in range(state1-1, state2): for j in range(k): if (j < state1-1) or (j > state2 - 1): s += Q[i, j] * p[i] / pstot mean = 1 / s return mean
def Popen(mec, tres, conc=0, eff='c'): """ Calculate equilibrium open probability (Popen) and correct for unresolved blockages in case of presence of fast pore blocker. Parameters ---------- mec : dcpyps.Mechanism The mechanism to be analysed. tres : float Time resolution (dead time). conc : float Concentration. Returns ------- Popen : float Open probability value at a given concentration. """ mec.set_eff(eff, conc) if tres == 0: p = qml.pinf(mec.QGG) popen = np.sum(p[:mec.kA]) / np.sum(p) else: hmopen, hmshut = scl.exact_mean_open_shut_time(mec, tres) popen = (hmopen / (hmopen + hmshut)) if mec.fastblock: popen = popen / (1 + conc / mec.fastKB) return popen
def shut_times_between_burst_pdf_components(mec): """ Calculate time constants and amplitudes for a PDF of gaps between bursts. Parameters ---------- mec : dcpyps.Mechanism The mechanism to be analysed. Returns ------- eigs : ndarray, shape(k, 1) Time constants. w : ndarray, shape(k, 1) Component amplitudes. """ uA = np.ones((mec.kA, 1)) eigsB, AmatB = qml.eigs(-mec.QBB) eigsF, AmatF = qml.eigs(-mec.QFF) pA = qml.pinf(mec.Q)[:mec.kA] end = np.dot(-mec.QAA, endBurst(mec)) start = pA / np.dot(pA, end) rowB = np.dot(start, mec.QAB) rowF = np.dot(start, mec.QAF) colB = np.dot(mec.QBA, uA) colF = np.dot(mec.QFA, uA) wB = -np.dot(np.dot(rowB, AmatB), colB) wF = np.dot(np.dot(rowF, AmatF), colF) w = np.append(wB, wF) eigs = np.append(eigsB, eigsF) return eigs, w
def shut_times_between_burst_mean(mec): """ Calculate the mean length of the gap between bursts (Eq. 3.86, CH82). Parameters ---------- mec : dcpyps.Mechanism The mechanism to be analysed. Returns ------- m : float The mean shut time between bursts. """ pA = qml.pinf(mec.Q)[:mec.kA] end = np.dot(-mec.QAA, endBurst(mec)) start = pA / np.dot(pA, end) uA = np.ones((mec.kA, 1)) GAF, GFA = qml.iGs(mec.Q, mec.kA, mec.kF) invQFF = -nplin.inv(mec.QFF) invQBB = -nplin.inv(mec.QBB) GAB, GBA = qml.iGs(mec.Q, mec.kA, mec.kB) m1 = np.dot(np.dot(mec.QAF, invQFF), GFA) m2 = np.dot(np.dot(mec.QAB, invQBB), GBA) m = np.dot(np.dot(start, m1 - m2), uA)[0] return m
def transition_frequency(Q): """ """ k = Q.shape[0] pinf = qml.pinf(Q) f = Q.copy().transpose() for i in range(k): f[i] = f[i] * pinf f[i,i] = 0 return f.transpose()
def calc_jump (mec, reclen, step, cfunc, cargs): """ Calculate response to a concentration pulse directly from Q matrix. Parameters ---------- mec : dcpyps.Mechanism The mechanism to be analysed. reclen : float Trace length. step : float Sampling time interval. cfunc : function Concentration profile. cargs : tuple Arguments for cfunc(t, cargs). Returns ------- t : ndarray Time samples. c : ndarray Concentration profile. P : ndarray All state occupancies. Popen : ndarray Open probability. """ t = np.arange(0, reclen, step) c = cfunc(t, cargs) mec.set_eff('c', cargs[1]) pi = qml.pinf(mec.Q) Pt = np.array([pi.copy()]) for i in range(1, t.shape[0]): mec.set_eff('c', c[i]) eigenvals, A = qml.eigs_sorted(mec.Q) w = coefficient_calc(mec.k, A, pi) pi = P_t(step, eigenvals, w) Pt = np.append(Pt, [pi.copy()], axis=0) P = Pt.transpose() Popen = np.sum(P[: mec.kA], axis=0) return t, c, Popen, P
def weighted_taus(mec, cmax, width, eff='c'): """ Calculate weighted on and off time constants for a square concentration pulse. Parameters ---------- mec : dcpyps.Mechanism The mechanism to be analysed. cmax : float Pulse concentration. width : float Pulse width. Returns ------- tau_on_weighted, tau_off_weighted : floats Weighted time constants. """ mec.set_eff(eff, 0) eigs0, A0 = qml.eigs_sorted(mec.Q) P0 = qml.pinf(mec.Q) mec.set_eff(eff, cmax) eigsInf, Ainf = qml.eigs_sorted(mec.Q) w_on = coefficient_calc(mec.k, Ainf, P0) Pt = P_t(width, eigsInf, w_on) w_off = coefficient_calc(mec.k, A0, Pt) ampl_on = np.sum(w_on[:, :mec.kA], axis=1) max_ampl_on = np.max(np.abs(ampl_on)) rel_ampl_on = ampl_on / max_ampl_on tau_on_weighted = np.sum(-rel_ampl_on[:-1] * (-1 / eigsInf[:-1])) tau_on = -1 / eigsInf[:-1] ampl_off = np.sum(w_off[:, :mec.kA], axis=1) max_ampl_off = np.max(np.abs(ampl_off)) rel_ampl_off = ampl_off / max_ampl_off tau_off_weighted = np.sum(rel_ampl_off[: -1] * (-1 / eigs0[:-1])) tau_off = -1 / eigs0[:-1] return tau_on_weighted, tau_on, tau_off_weighted, tau_off
def solve_jump(mec, reclen, step, cfunc, cargs, abserr=1.0e-8, relerr=1.0e-6): """ Calculate response to a concentration pulse by integration. Parameters ---------- mec : dcpyps.Mechanism The mechanism to be analysed. reclen : float Trace length. step : float Sampling time interval. cfunc : function Concentration profile. cargs : tuple Arguments for cfunc(t, cargs). rtol, atol : float, optional Tolerance limits for the error control performed by the scipy.odeint solver. Returns ------- t : ndarray Time samples. c : ndarray Concentration profile. P : ndarray All state occupancies. Popen : ndarray Open probability. """ t = np.arange(0, reclen, step) mec.set_eff('c', cargs[1]) P0 = qml.pinf(mec.Q) Pt = scpi.odeint(dPdt, P0, t, args=(mec, cfunc, cargs), atol=abserr,rtol=relerr) P = Pt.transpose() Popen = np.sum(P[: mec.kA], axis=0) c = cfunc(t, cargs) return t, c, Popen, P
def phiBurst(mec): """ Calculate the start probabilities of a burst (Eq. 3.2, CH82). phiB = (pCinf * (QCB * GBA + QCA)) / (pCinf * (QCB * GBA + QCA) * uA) Parameters ---------- mec : dcpyps.Mechanism The mechanism to be analysed. Returns ------- phiB : array_like, shape (1, kA) """ uA = np.ones((mec.kA, 1)) pC = qml.pinf(mec.Q)[mec.kE:mec.kG] GAB, GBA = qml.iGs(mec.Q, mec.kA, mec.kB) nom = np.dot(pC, (np.dot(mec.QCB, GBA) + mec.QCA)) denom = np.dot(nom, uA) phiB = nom / denom return phiB
def printout_occupancies(mec, tres): """ """ str = ('\n\n\n*******************************************\n\n' + 'Open\tEquilibrium\tMean life\tMean latency (ms)\n' + 'state\toccupancy\t(ms)\tto next shutting\n' + '\t\t\tgiven start in this state\n') pinf = qml.pinf(mec.Q) for i in range(mec.k): if i == 0: mean_life_A = ideal_subset_mean_life_time(mec.Q, 1, mec.kA) str += ('Subset A ' + '\t{0:.5g}'.format(np.sum(pinf[:mec.kA])) + '\t{0:.5g}\n'.format(mean_life_A * 1000)) if i == mec.kA: mean_life_B = ideal_subset_mean_life_time(mec.Q, mec.kA + 1, mec.kE) str += ('\nShut\tEquilibrium\tMean life\tMean latency (ms)\n' + 'state\toccupancy\t(ms)\tto next opening\n' + '\t\t\tgiven start in this state\n' + 'Subset B ' + '\t{0:.5g}'.format(np.sum(pinf[mec.kA : mec.kE])) + '\t{0:.5g}\n'.format(mean_life_B * 1000)) if i == mec.kE: mean_life_C = ideal_subset_mean_life_time(mec.Q, mec.kE + 1, mec.kG) str += ('\nSubset C ' + '\t{0:.5g}'.format(np.sum(pinf[mec.kE : mec.kG])) + '\t{0:.5g}\n'.format(mean_life_C * 1000)) if i == mec.kG: mean_life_D = ideal_subset_mean_life_time(mec.Q, mec.kG + 1, mec.k) str += ('\nSubset D ' + '\t{0:.5g}'.format(np.sum(pinf[mec.kG : mec.k])) + '\t{0:.5g}\n'.format(mean_life_D * 1000)) mean = ideal_mean_latency_given_start_state(mec, i+1) str += ('{0:d}'.format(i+1) + '\t{0:.5g}'.format(pinf[i]) + '\t{0:.5g}'.format(-1 / mec.Q[i,i] * 1000) + '\t{0:.5g}\n'.format(mean * 1000)) expQFF = qml.expQt(mec.QFF, tres) expQAA = qml.expQt(mec.QAA, tres) GAF, GFA = qml.iGs(mec.Q, mec.kA, mec.kF) eGAF = qml.eGs(GAF, GFA, mec.kA, mec.kF, expQFF) eGFA = qml.eGs(GFA, GAF, mec.kF, mec.kA, expQAA) phiA = qml.phiHJC(eGAF, eGFA, mec.kA) phiF = qml.phiHJC(eGFA, eGAF, mec.kF) str += ('\n\nInitial vector for HJC openings phiOp =\n') for i in range(phiA.shape[0]): str += ('\t{0:.5g}'.format(phiA[i])) str += ('\nInitial vector for ideal openings phiOp =\n') phiAi = qml.phiA(mec) for i in range(phiA.shape[0]): str += ('\t{0:.5g}'.format(phiAi[i])) str += ('\nInitial vector for HJC shuttings phiSh =\n') for i in range(phiF.shape[0]): str += ('\t{0:.5g}'.format(phiF[i])) str += ('\nInitial vector for ideal shuttings phiSh =\n') phiFi = qml.phiF(mec) for i in range(phiF.shape[0]): str += ('\t{0:.5g}'.format(phiFi[i])) str += '\n' return str
def printout(mec, cmax, width, eff='c'): """ """ #TODO: on/off binding #TODO: move some of calculations from here to separate functions str = ('\n*******************************************\n' + 'CONCENTRATION JUMPS\n') gamma = 30 # Conductance in pS Vm = -80e-3 # Transmembrane potential in V. mec.set_eff(eff, 0) P0 = qml.pinf(mec.Q) eigs0, A0 = qml.eigs_sorted(mec.Q) str += ('\nEquilibrium occupancies before t=0, at concentration = 0.0:\n') for i in range(mec.k): str += ('p00({0:d}) = {1:.5g}\n'.format(i+1, P0[i])) mec.set_eff(eff, cmax) Pinf = qml.pinf(mec.Q) eigsInf, Ainf = qml.eigs_sorted(mec.Q) w_on = coefficient_calc(mec.k, Ainf, P0) str += ('\nEquilibrium occupancies at maximum concentration = {0:.5g} mM:\n' .format(cmax * 1000)) for i in range(mec.k): str += ('pinf({0:d}) = '.format(i+1) + '{0:.5g}\n'.format(Pinf[i])) Pt = P_t(width, eigsInf, w_on) str += ('\nOccupancies at the end of {0:.5g} ms pulse:\n'. format(width * 1000)) for i in range(mec.k): str += ('pt({0:d}) = '.format(i+1) + '{0:.5g}\n'.format(Pt[i])) tau_on_weighted, tau_on, tau_off_weighted, tau_off = weighted_taus(mec, cmax, width, eff='c') str += ('\nON-RELAXATION for ideal step:\n' + 'Time course for current\n' + '\nComp\tEigen\t\tTau (ms)\n') for i in range(mec.k-1): str += ('{0:d}\t'.format(i+1) + '{0:.5g}\t\t'.format(eigsInf[i]) + '{0:.5g}\t\n'.format(-1000 / eigsInf[i])) # convert to ms ampl_on = np.sum(w_on[:, :mec.kA], axis=1) cur_on = ampl_on * gamma * Vm max_ampl_on = np.max(np.abs(ampl_on)) rel_ampl_on = ampl_on / max_ampl_on area_on = -cur_on[:-1] / eigsInf[:-1] str += ('\nAmpl.(t=0,pA)\tRel.ampl.\t\tArea(pC)\n') for i in range(mec.k-1): str += ('{0:.5g}\t\t'.format(cur_on[i]) + '{0:.5g}\t\t'.format(rel_ampl_on[i]) + '{0:.5g}\t\n'.format(area_on[i] * 1000)) str += ('\nWeighted On Tau (ms) = {0:.5g}\n'.format(tau_on_weighted * 1000)) str += ('\nTotal current at t=0 (pA) = {0:.5g}\n'. format(np.sum(cur_on))) str += ('Total current at equilibrium (pA) = {0:.5g}\n'. format(cur_on[-1])) str += ('Total area (pC) = {0:.5g}\n'. format(np.sum(area_on))) #TODO: Current at the end of pulse ct = cur_on[:-1] * np.exp(width * eigsInf[:-1]) str += ('Current at the end of {0:.5g}'.format(width * 1000) + ' ms pulse = {0:.5g}\n'.format(np.sum(ct) + cur_on[-1])) # Calculate off- relaxation. str += ('\nOFF-RELAXATION for ideal step:\n' + 'Time course for current\n' + '\nComp\tEigen\t\tTau (ms)\n') for i in range(mec.k-1): str += ('{0:d}\t'.format(i+1) + '{0:.5g}\t\t'.format(eigs0[i]) + '{0:.5g}\t\n'.format(-1000 / eigs0[i])) w_off = coefficient_calc(mec.k, A0, Pt) ampl_off = np.sum(w_off[:, :mec.kA], axis=1) cur_off = ampl_off * gamma * Vm max_ampl_off = np.max(np.abs(ampl_off)) rel_ampl_off = ampl_off / max_ampl_off area_off = np.zeros((mec.k-1)) str += ('\nAmpl.(t=0,pA)\tRel.ampl.\t\tArea(pC)\n') for i in range(mec.k-1): area_off[i] = -1000 * cur_off[i] / eigs0[i] str += ('{0:.5g}\t\t'.format(cur_off[i]) + '{0:.5g}\t\t'.format(rel_ampl_off[i]) + '{0:.5g}\t\n'.format(area_off[i])) str += ('\nWeighted Off Tau (ms) = {0:.5g}\n'.format(tau_off_weighted * 1000)) str += ('\nTotal current at t=0 (pA) = {0:.5g}\n'. format(np.sum(cur_off))) str += ('Total current at equilibrium (pA) = {0:.5g}\n'. format(cur_off[-1])) str += ('Total area (pC) = {0:.5g}\n'.format(np.sum(area_off))) return str