def allocfiles(self, **kwargs): # **kwargs override fname[k] """ Save version info and preallocate empty memory-mapped arrays on disk. The arrays are taken from self.ftype, but may be overridden by optional keyword arguments. For example, allocfiles(genotype=...) will save the provided genotype as "genotype.npy" rather than allocate an empty file of that name with dtype = ftype["genotype"].dtype. """ genotype = kwargs.pop("genotype", self.genotype) shape = (len(genotype),) # must be tuple, or open_memmap creates broken file np.save("index.npy", np.arange(len(genotype))) for name, dtype in self.ftype.items(): fname = "%s.npy" % name assert not os.path.exists(fname) if name in kwargs: np.save(fname, kwargs.pop(name)) else: f = open_memmap(fname, mode="w+", dtype=dtype, shape=shape) if name == "timing": f[:] = nans_like(np.empty(dtype=dtype, shape=shape)) f["waiting"] = time() f["attempts"] = 0 del f assert not kwargs, "Unrecognized keyword argument(s) %s" % kwargs.keys()
def resume(self): """Prepare to rerun unfinished workpieces.""" timing = open_memmap("timing.npy") indexbool = ~np.isfinite(timing["finished"]) if self.resumeconv: c = np.load("convergence.npy").view(np.recarray) indexbool = indexbool | ((c.intervals > 0) & (c.period == 0)) index = np.where(indexbool)[0] if len(index) == 0: raise Exception("No workpieces to resume") np.save("index.npy", index) timing[index]["waiting"] = time() timing[index]["attempts"] += 1 del timing
def task(self, real_i): """ Map genotype i to parameter to steady state. Input and output uses memmaps. To allow load balancing, the memmaps have only a single element (one genotype, one parameter set, etc.). In case of alternans, a list of (t, y, stats, integrals) is stored as e.g. alternans/123.list.npy To retrieve the list, use "L = np.load(filename).item()" """ m = Dotdict() for name in self.ftype: m[name] = open_memmap("%s.npy" % name, offset=real_i, shape=1) i = 0 alog.debug("Workpiece: real_i=%s, i=%s", real_i, i) m.timing[i]["attempts"] += 1 m.timing[i]["started"] = time() try: m.genotype[i] = gt = self.genotype[real_i] m.parameter[i] = par = self.gt2par(gt) li = self.li with li.autorestore(_p=par): # Compute quiescent state with li.autorestore(stim_amplitude=0): t, y, flag = li.integrate(t=[0, 1e6]) m.quiescent[i] = yq = y[-1:] # yq now has shape (1,) # Run voltage stepping protocols bp = li.bond_protocols() p3, p5, p7 = [listify(bp[j].protocol) for j in 3, 5, 7] p3[1][1] = -40, -20, 0, 20, 40 p5[1][1] = -40, -20, 0, 20, 40 p7[2][0] = 2, 127, 252, 377, 502 with li.autorestore(_y=yq): L3 = li.vecvclamp(p3) # P1-P2 voltage stepping for i_Na L5 = li.vecvclamp(p5) # P1-P2 voltage stepping for i_CaL L7 = li.vecvclamp(p7) # Variable-gap protocol for i_CaL d = OrderedDict() # to hold voltage-clamp phenotype characteristics # Time constant of inactivation: -1/slope of ln(current) vs t after P1 peak for curr, L in ("i_Na", L3), ("i_CaL", L5): for v, tau in zip(*decayfits(L, 1, curr)): sv = str(v).replace("-", "m") # avoid minus sign in field name k = "%s_tau_%s" % (curr, sv) d[k] = tau # Michaelis-Menten half-saturation and asymptote of peak current vs gap duration gaps, voltages = p7[2] proto, traj = [np.array(j, dtype=object) for j in zip(*L7)] # Vectorized voltage clamping returns a 1-d array. # Dimensions should be (gap length, interpulse voltage, pulse index, last) # where the last dimension has length 2 for proto (duration, voltage) # and 4 for traj (t, y, dy, a). for j in proto, traj: j.shape = [len(gaps), len(voltages)] + list(j.shape[1:]) for j, v in enumerate(voltages): imax, thalf = mmfits(zip(proto[:,j,:,:], traj[:,j,:,:]), k="i_CaL") sv = str(v).replace("-", "m") d["i_CaL_vg_max_" + sv] = imax d["i_CaL_vg_thalf_" + sv] = thalf # print " ".join(dict2rec(d).dtype.names) # for self.datatypes() m.clamppheno[i] = dict2rec(d).view(np.recarray) # Steady state under regular pacing (period, intervals), steady = li.par2steady(y0=yq, reltol=self.reltol, max_nap=1000) # # oldintervals will be nonzero if an earlier run failed to converge # oldperiod, oldintervals = m.convergence[i] # y0 = m.steady[i] if (self.resumeconv and oldintervals) else None # # # Run to convergence; steady is a list of (t, y, stats, integrals). # # The cycle is aligned so that it starts with the highest Cai peak. # (period, intervals), steady = self.par2steady(par, y0) # intervals += oldintervals m.convergence[i] = period, intervals if period and (len(steady) > 1): with write_if_not_exists("alternans/%s.list.npy" % real_i, raise_if_exists=True) as f: L = [] for t, y, stats, int_ in steady: ix = thin(len(t), self.raw_nthin) L.append((t[ix], y[ix], stats, int_)) np.save(f, L) t, y, stats, _ = steady[-1] m.steady[i] = y[0] # Phenotypes for steady-state dynamics aps = [(t, y, stats) for t, y, stats, int_ in steady[-self.raw_nap:]] m.raw[i], m.ap_stats[i] = self.thin_aps(aps, self.raw_nthin, par) # Ion-current phenotypes, also applied to other state variables. # One table/ndarray per phenotype, one column per variable. raw = m.raw[i] currstats = np.concatenate([current_phenotypes_array(raw["t"], raw[k]) for k in raw.dtype.names if k != "t"]) for k in currstats.dtype.names: m[k][i] = np.ascontiguousarray(currstats[k]) m.timing[i]["finished"] = time() m.timing[i]["seconds"] = m.timing[i]["finished"] - m.timing[i]["started"] except Exception, exc: m.timing[i]["error"] = time() alog.exception("Error processing item %s", i)