def urand_get_dur_list(self, nevents, tot_time): """return a list of durations, distributed uniformly in [0,max_dur] (but still on t_gran) - mean time is tot/n, max is 2*tot/n - get int(n/2) random times - fill with max-val (so pairs average at mean) - if n is odd, append one mean duration - shuffle """ if nevents <= 0: return [] if nevents == 1: return [tot_time] max_dur = tot_time * 2.0 / nevents # maximum num t_gran possibile (equates to 0..max_dur in time) # (+0.01 is to avoid a close trunction miss) nmax = int(max_dur / self.t_gran + 0.01) durlist = [] for ind in range(nevents//2): ngran = self.rand_uniform_int(nmax+1) # add time and balancing time durlist.append(ngran * self.t_gran) durlist.append((nmax - ngran) * self.t_gran) if nevents % 2: durlist.append(max_dur/2.0) UTIL.shuffle(durlist) return durlist
def decay_fixed_get_dur_list(self, nevents, tot_time, max_dur): """return a list of durations, distributed as e^-x on [0, max_dur] with mean tot_time/nevents (durations are still on t_gran) - mean time is tot/n, max should be positive - get n times via decay_pdf_get_ranged_times() - shuffle """ import afnipython.lib_decay_timing as LDT if nevents <= 0: return [] if nevents == 1: return [tot_time] if tot_time <= 0.0: return [0.0]*nevents if max_dur <= 0: print('** decay_fixed_GDL: illegal max_dur %g' % max_dur) return [] mean = float(tot_time)/nevents durlist = LDT.decay_pdf_get_ranged_times(0, max_dur, mean, nevents, t_grid=self.t_gran, verb=self.verb) UTIL.shuffle(durlist) return durlist
def ugrid_get_dur_list(self, nevents, tot_time): """return a list of durations, distributed evenly along [0,max_dur], but truncated to the t_gran grid EXPECTS: minimum event time == 0, i.e. old min was subtracted out - like urand, but create a list of evenly divided times, without any randomness - mean time is tot/n, max is 2*tot/n - make int(n/2) lower grid times - compute exact time, then convert to t_gran indices (val) - fill with max-val (so pairs average at mean) - if n is odd, append one mean duration - shuffle """ if nevents <= 0: return [] if nevents == 1: return [tot_time] max_dur = tot_time * 2.0 / nevents tspace = max_dur / (nevents - 1.0) # maximum num t_gran possibile (equates to 0..max_dur in time) # (+0.01 is to avoid a close trunction miss) nmax = int(max_dur / self.t_gran + 0.01) durlist = [] for ind in range(nevents//2): actual_time = ind * tspace grid_time = self.t_gran * int(actual_time/self.t_gran) # add time and balancing time durlist.append(grid_time) durlist.append(max_dur - grid_time) # if odd number, include a mean dur if nevents % 2: durlist.append(max_dur/2.0) UTIL.shuffle(durlist) return durlist
def decay_apply_max_limit(self, dlist, nmax): """none of the (integer) entries in dlist should exceed nmax instead of: - truncating all big times to max (too many max's) - adding each extra time unit to a random event now: - give all big times new times on a uniform grid - distribute time in random blocks one event at a time: while time to distribute exists choose a non-max event add random amount of time (subject to max and total) - re-randomize list (so we can separate maxed out events) """ nevents = len(dlist) intotal = sum(dlist) * self.t_gran if self.verb > 3: print('-- decay: dist %d rest events, time=%g, ave time=%g' \ % (nevents, intotal, intotal/nevents)) # give big times new ones in the proper range, and tally lost time textra = 0 nfixed = 0 for dind, dur in enumerate(dlist): if dur > nmax: dnew = self.rand_uniform_int(nmax+1) textra += (dur-dnew) nfixed += 1 dlist[dind] = dnew # now remove any that are maxed out addlist = [dur for dur in dlist if dur < nmax] nadd = len(addlist) nmaxed = nevents - nadd if self.verb > 4: ttotal = textra * self.t_gran print('-- decay: dist %d rest atoms (time=%g)' % (textra, ttotal)) print(' nadd=%d, nmaxed=%d, nfixed=%d' % (nadd, nmaxed, nfixed)) ttotal = sum(dlist) * self.t_gran print(' fix %g/%d = %g' % (ttotal,len(dlist),ttotal/len(dlist))) # and add remaining time until we are done until we are done while textra > 0: # should not occur: if nadd == 0: print('** rcr screw-up: nadd = 0') sys.exit(1) # get random index to add to aind = self.rand_uniform_int(nadd) # set max to add space = nmax - addlist[aind] # get random space in {1,...,space} # try linearly decreasing prob dist func rval = self.rand_uniform_int(space*space) ntoadd = rval//space if (rval % space) < ntoadd: ntoadd = rval % space ntoadd += 1 if ntoadd > textra: ntoadd = textra addlist[aind] += ntoadd textra -= ntoadd # if maxed, pop... if addlist[aind] == nmax: nmaxed += 1 addlist.pop(aind) nadd -= 1 # finally, re-randomize list addlist.extend([nmax] * nmaxed) dlist = addlist UTIL.shuffle(dlist) outtotal = sum(dlist) * self.t_gran if self.verb > 3: print('-- final, ave %g/%d = %g' \ % (outtotal, len(dlist), outtotal/len(dlist))) if intotal != outtotal: print('** decay - apply max: intotal %g != outtotal %g' \ % (intotal, outtotal)) return dlist
def decay_get_dur_list(self, nevents, tot_time, max_dur, maxtype=0): """return a list of durations of length nevents, such that tot_time is distributed with PDF decay (okay, the discrete version, which is less) maxtype 0 means default delay function """ durlist = [0] * nevents # see how much rest there is to distribute nrest = int(tot_time / self.t_gran) # if no rest, just return the 0-filled list if nrest < 1: return durlist # start by doing a simple random distribution at t_gran granularity # (partition time with nevents-1 dividers) elist = [1] * (nevents - 1) rlist = [0] * nrest elist.extend(rlist) UTIL.shuffle(elist) # add a trailer to count the final duration (since only n-1 dividers) elist.append(1) # now get counts posn = -1 prev = posn for eind in range(nevents): # look for the next 1 try: posn = elist.index(1, prev+1) except: print('** DGDL index failure, n = %d, elist = %s' % (nevents, elist)) return durlist # rest count is number of zeros between prev and posn durlist[eind] = posn-prev-1 prev = posn # if no maximum to deal with, we are done (scale by t_gran) if max_dur < 0: for dind in range(nevents): durlist[dind] *= self.t_gran return durlist # -------------------------------------------------- # have a max duration, so redistribute the wealth nmax = int(max_dur / self.t_gran) # limit to maximum; have multiple methods to choose from if maxtype == 0: durlist = self.decay_apply_max_limit(durlist, nmax) elif maxtype == 1: durlist = self.decay_apply_max_limit_old(durlist, nmax) else: print('** decay limit, illegal maxtype %d' % maxtype) durlist = self.decay_apply_max_limit(durlist, nmax) # and finally, scale by t_gran for dind in range(len(durlist)): durlist[dind] *= self.t_gran return durlist