def invert(self, phis, prc, phi_offset=0): """ Find the resulting probability density function after applying a perturbation, resulting in phase response curve prc, at time 0. Returns a phase_distribution class of the perturbed system. """ prc_interp = PeriodicSpline(phis, prc) ptc_interp = ptc_from_prc(prc_interp) res = self.invert_res iphis = np.linspace(0, 2*np.pi, num=res, endpoint=True) spacing = iphis[1] x = np.linspace(-2*np.pi, 4*np.pi, num=3*res, endpoint=True) # Is the phase transition curve monotonic? # if so, use abbreviated formula if ptc_interp(phis, 1).min() > 1E-2: invertedptc = UnivariateSpline(ptc_interp(x), x, s=0) f_perturbed = (invertedptc(iphis, 1) * self.phase_offset(invertedptc(iphis), phi_offset)) # Not monotonic, must calculate roots at each point else: f_perturbed = np.zeros(res) root_interp = RootFindingSpline(x, ptc_interp(x)) # import matplotlib.pylab as plt # fig = plt.figure() # ax = fig.add_subplot(111) # ax.plot(x, root_interp(x)) for i,phi in enumerate(iphis): start = phi - spacing/2 stop = phi + spacing/2 roots_above = root_interp.root_offset(stop) roots_below = root_interp.root_offset(start) roots = np.hstack([roots_below, roots_above]) roots.sort() roots = roots.reshape((-1, 2)) for pair in roots: # ax.fill_between([pair[0], pair[1]], start, stop, # alpha=0.3) # dx = pair[1] - pair[0] dy = spacing int_fx = self.integrate(pair[0], pair[1], phi_offset) f_perturbed[i] += int_fx/dy scale = p_integrate(iphis, f_perturbed) assert scale > 0.975, \ "pdf inversion error (Error = %0.3f)"%scale f_perturbed *= 1./scale f_p_interp = PeriodicSpline(iphis, f_perturbed) return phase_distribution(f_p_interp, self.phase_diffusivity, invert_res=self.invert_res)
def calc_pulse_responses(self, pulse_creator, trans_duration=3, res=100): """ Integrate pulses starting at different initial phases to find x(phi, t), create interpolation object, and find amplitude and phase response curves for the given pulse """ self._create_arc_integrator(trans_duration) if not hasattr(self, 'avg'): self.average() if not hasattr(self, 'lc'): self.limitCycle() pulse = pulse_creator(0.) phis = np.linspace(0, 2 * np.pi, num=res) trajectories = [] references = [] arc = [] prc = [] if pulse['type'] is 'param': pulse_traj = [] for phi in phis: out = self._simulate_pulse_and_ref(pulse_creator(phi), trans_duration) trajectories += [out['traj']] references += [out['ref']] prc += [out['p_diff']] arc += [ self._calc_amp_change(self.arc_traj_ts, out['traj'], out['ref']) ] if pulse['type'] is 'param': pulse_traj += [out['pulse_traj']] trajectories = np.array(trajectories) references = np.array(references) self.traj_interp = cyl_interp(phis, self.arc_traj_ts, trajectories) self.ref_interp = cyl_interp(phis, self.arc_traj_ts, references) if pulse['type'] is 'param': pulse_traj = np.array(pulse_traj) comb_ts = np.hstack([pulse['ts'][:-1], self.arc_traj_ts]) comb_traj = np.concatenate([pulse_traj[:, :-1, :], trajectories], axis=1) self.comb_interp = cyl_interp(phis, comb_ts, comb_traj) self.pulse_creator = pulse_creator self.prc_single_cell = np.array(prc) # Single Cell PRC self.arc_single_cell = np.array(arc) # Single Cell ARC self.phis = phis self.prc_interp = PeriodicSpline(self.phis, self.prc_single_cell, period=2 * np.pi) self.ptc_interp = lambda x: x + self.prc_interp(x)
def __init__(self, phis, prc): self.prc_interp = PeriodicSpline(phis, prc, k=4) self.ptc_interp = ptc_from_prc(self.prc_interp) res = len(phis) self.prc_deriv = self.prc_interp.derivative() self.div_points = self.prc_deriv.root_offset(-1) # Rescale phis and points such that phi=0 is the first # division offset = self.div_points[0] # phi_scaled = (phis - offset)%2*np.pi # self.phi_to_theta = lambda phi: (phi - offset)%(2*np.pi) # self.theta_to_phi = lambda theta: (theta + offset)%(2*np.pi) self.div_scaled = self.div_points - offset # Add 2pi to the end of region for final segment self.div_scaled = np.hstack([self.div_scaled, 2*np.pi]) self.fwd_sections = fnlist([]) self.inv_sections = fnlist([]) for i, point in enumerate(self.div_scaled[1:]): start = self.div_scaled[i] stop = point section_length = stop - start section_res = int(res*section_length/(2*np.pi) + 20) x = np.linspace(start, stop, num=section_res, endpoint=True) y = x + self.prc_interp(x + offset) fwd_spline = BoundedUniveriateSpline(x, y, bbox=[x.min(), x.max()]) inv_spline = BoundedUniveriateSpline(y, x, bbox=[y.min(), y.max()]) self.fwd_sections += [fwd_spline] self.inv_sections += [inv_spline]
def __init__(self, mu, sigma, phase_diffusivity, invert_res=60): """ mu and sigma should be the mean and standard deviation of the trajectory. """ assert np.isfinite(mu), "Mu must be a number" assert np.isfinite(sigma), "Sigma must be a number" assert np.isfinite(phase_diffusivity), "D must be a number" # General phase distribution variables self.phase_diffusivity = phase_diffusivity self.period = 2*np.pi self.invert_res = invert_res # Gaussian specific variables self.mu = mu%(2*np.pi) self.sigma = sigma self.length = np.exp((self.sigma**2)/(-2)) self.fo_phi = lambda phis: wrapped_gaussian(phis%(2*np.pi), mu, sigma) phis = np.linspace(0, 2*np.pi, 100) self.fo_phi_interp = PeriodicSpline(phis, self.fo_phi(phis))
class gaussian_phase_distribution(phase_distribution): """ Class to handle the specific case where the phase distribution is a wrapped gaussian function, with methods that take into account the more tractable nature of gaussian distributions. """ def __init__(self, mu, sigma, phase_diffusivity, invert_res=60): """ mu and sigma should be the mean and standard deviation of the trajectory. """ assert np.isfinite(mu), "Mu must be a number" assert np.isfinite(sigma), "Sigma must be a number" assert np.isfinite(phase_diffusivity), "D must be a number" # General phase distribution variables self.phase_diffusivity = phase_diffusivity self.period = 2*np.pi self.invert_res = invert_res # Gaussian specific variables self.mu = mu%(2*np.pi) self.sigma = sigma self.length = np.exp((self.sigma**2)/(-2)) self.fo_phi = lambda phis: wrapped_gaussian(phis%(2*np.pi), mu, sigma) phis = np.linspace(0, 2*np.pi, 100) self.fo_phi_interp = PeriodicSpline(phis, self.fo_phi(phis)) def __call__(self, ts, phi_res=100, advance_t=True): """ Convolute the original gaussian with the diffusion update to generate the pdf at time t. Advance_t=False hold the mean in place for x_hat """ # Set up time variables ts = np.atleast_1d(ts) phis = np.linspace(0, 2*np.pi, num=phi_res, endpoint=True) # Return distribution matrix, evaluated at phis and ts ret_phis = np.zeros((len(ts), phi_res)) # For every time point, find distribution for i, t in enumerate(ts): ##Parallelize? sigma_d = np.sqrt(2*self.phase_diffusivity*np.abs(t)) mu_d = (t * (2*np.pi)/self.period)%(2*np.pi) # From the convolution of two gaussian functions mu_f = self.mu + mu_d if advance_t else self.mu, # Allow negative times to reverse diffusion var = self.sigma**2 + np.sign(t)*sigma_d**2 sigma_f = np.sqrt(var) if var > 0 else 0. ret_phis[i] = wrapped_gaussian(phis, mu_f, sigma_f) return ret_phis def integrate(self, a, b, phi_offset=0): """ implement a wrapped error function eventually? """ return self.fo_phi_interp.integrate(a-phi_offset, b-phi_offset)
# axmatrix[0].plot(test.phis, test.prc_single_cell) # axmatrix[0].set_title('Single Cell PRC') # axmatrix[1].plot(test.phis, test.arc_single_cell[:,0]) # axmatrix[1].set_title('Single Cell ARC') # plot_grey_zero(axmatrix[0]) # plot_grey_zero(axmatrix[1]) # format_2pi_axis(axmatrix[1]) period = 2*np.pi mean = np.pi/4 std = 0.5 decay = 0.01 phis = np.linspace(0, 2*np.pi, num=100, endpoint=True) po = wrapped_gaussian(phis, mean, std) po_interp = PeriodicSpline(phis, po) test_population = gaussian_phase_distribution(mean, std, decay, invert_res=60) perturbed_popul = test_population.invert(test.phis, test.prc_single_cell) test.calc_population_responses(test_population, tarc=False) mean_p, std_p = mean_std(test.z_hat(0)) mean_pert_pop = gaussian_phase_distribution(mean_p, std_p, decay) fig = plt.figure() ax = fig.add_subplot(111) iphis = np.linspace(0, 2*np.pi, 60)
from CommonFiles.Amplitude2 import Amplitude from CommonFiles.Models.tyson2statemodel import model, paramset amp = Amplitude(model(), paramset) state_pulse_creator = amp._s_pulse_creator(1, 0.5) amp.calc_pulse_responses(state_pulse_creator) res = len(amp.phis) phis = amp.phis prc = np.hstack([amp.prc_single_cell[:-1][(res/2):], amp.prc_single_cell[:-1][:(res/2)]]) prc = np.hstack([prc, prc[0]]) prc_interp = PeriodicSpline(phis, prc) ptc = ptc_from_prc(prc_interp) # ax.plot(test.ptc_interp(phis), phis, '.') test = InvertedPTC(phis, prc) fig = plt.figure() ax = fig.add_subplot(111) ax.plot(phis, ptc(phis)) ax.plot(test.div_points, ptc(test.div_points), 'o') # thetas = test.phi_to_theta(phis)