def bary_to_topo(infofilenm, rawdatafile=False, ephem="DE200"): """ bary_to_topo(infofilenm, ephem="DE200"): Returns the barycentric and topocentric times evert 10 seconds. The data for the observation must be found in the info file. """ if infofilenm[-4:] == ".inf": infofilenm = infofilenm[:-4] filetype = 'inf' elif infofilenm[-5:] == ".fits": infofilenm = infofilenm filetype = 'PSRFITS' else: raise ValueError("file type not recognized. Must be .inf, or .fits") if filetype == "inf": obs = read_inffile(infofilenm) T = obs.N * obs.dt dt = 10.0 tto = obs.mjd_i + obs.mjd_f tts = Num.arange(tto, tto + (T + dt) / psr_utils.SECPERDAY, dt / psr_utils.SECPERDAY) nn = len(tts) bts = Num.zeros(nn, 'd') vel = Num.zeros(nn, 'd') ra = psr_utils.coord_to_string(obs.ra_h, obs.ra_m, obs.ra_s) dec = psr_utils.coord_to_string(obs.dec_d, obs.dec_m, obs.dec_s) if (obs.telescope == 'Parkes'): tel = 'PK' elif (obs.telescope == 'Effelsberg'): tel = 'EB' elif (obs.telescope == 'Arecibo'): tel = 'AO' elif (obs.telescope == 'MMT'): tel = 'MT' elif (obs.telescope == 'GBT'): tel = 'GB' else: print("Telescope not recognized.") return 0 elif filetype == "PSRFITS": if not rawdatafile: rawdatafile = psrfits.PsrfitsFile(infofilenm) T = rawdatafile.specinfo.T dt = 10.0 tto = rawdatafile.specinfo.start_MJD[0] tts = Num.arange(tto, tto + (T + dt) / psr_utils.SECPERDAY, dt / psr_utils.SECPERDAY) nn = len(tts) bts = Num.zeros(nn, 'd') vel = Num.zeros(nn, 'd') ra = rawdatafile.specinfo.ra_str dec = rawdatafile.specinfo.dec_str if (rawdatafile.specinfo.telescope == 'Parkes'): tel = 'PK' elif (rawdatafile.specinfo.telescope == 'Effelsberg'): tel = 'EB' elif (rawdatafile.specinfo.telescope == 'Arecibo'): tel = 'AO' elif (rawdatafile.specinfo.telescope == 'MMT'): tel = 'MT' elif (rawdatafile.specinfo.telescope == 'GBT'): tel = 'GB' else: print("Telescope not recognized.") return 0 barycenter(tts, bts, vel, nn, ra, dec, tel, ephem) avgvel = Num.add.reduce(vel) / nn tts = Num.arange(nn, dtype='d') * dt bts = (bts - bts[0]) * psr_utils.SECPERDAY return tts, bts
def bary_to_topo(pb, pbd, pbdd, infofilenm, ephem="DE200"): """ bary_to_topo(pb, pbd, pbdd, infofilenm, ephem="DE200"): Use least squares to calculate topocentric period period derivative, and period second derivative for the corresponding barycentric values. The data for the observation must be found in the info file. """ from numpy.linalg.old import linear_least_squares if infofilenm[-4:] == ".inf": infofilenm = infofilenm[:-4] obs = read_inffile(infofilenm) T = obs.N * obs.dt dt = 10.0 tto = obs.mjd_i + obs.mjd_f tts = np.arange(tto, tto + (T + dt) / SECPERDAY, dt / SECPERDAY) nn = len(tts) bts = np.zeros(nn, 'd') vel = np.zeros(nn, 'd') ra = psr_utils.coord_to_string(obs.ra_h, obs.ra_m, obs.ra_s) dec = psr_utils.coord_to_string(obs.dec_d, obs.dec_m, obs.dec_s) if (obs.telescope == 'Parkes'): tel = 'PK' elif (obs.telescope == 'Effelsberg'): tel = 'EB' elif (obs.telescope == 'Arecibo'): tel = 'AO' elif (obs.telescope == 'MMT'): tel = 'MT' else: print("Telescope not recognized.") return 0 barycenter(tts, bts, vel, nn, ra, dec, tel, ephem) print("Topocentric start time = %17.11f" % tts[0]) print("Barycentric start time = %17.11f" % bts[0]) avgvel = np.add.reduce(vel) / nn print("Average Earth velocity = %10.5e c" % (avgvel)) tts = np.arange(nn, dtype='d') * dt bts = (bts - bts[0]) * SECPERDAY [fb, fbd, fbdd] = p_to_f(pb, pbd, pbdd) b = fb * bts + fbd * bts**2.0 / 2.0 + fbdd * bts**3.0 / 6.0 a = np.transpose(np.asarray([tts, tts**2.0, tts**3.0])) [ft, ftd, ftdd], residuals, rank, sv = linear_least_squares(a, b) [pt, ptd, ptdd] = p_to_f(ft, ftd, ftdd) print(" Topocentric period = %15.12f" % pt) print(" Topocentric p-dot = %15.9e" % ptd) print(" Topocentric p-dotdot = %15.9e" % ptdd) print(" Quick Topo period = %15.12f" % (pb * (1.0 + avgvel))) print(" Quick Topo p-dot = %15.9e" % (pbd * (1.0 + avgvel))) print(" Quick Topo p-dotdot = %15.9e" % (pbdd * (1.0 + avgvel))) return [pt, ptd, ptdd]
def __init__(self, fil_filenm): self.fil_filenm = fil_filenm self.basefilenm = fil_filenm[:fil_filenm.find(".fil")] filhdr, hdrlen = sigproc.read_header(fil_filenm) self.MJD = filhdr['tstart'] self.nchans = filhdr['nchans'] self.ra_rad = sigproc.ra2radians(filhdr['src_raj']) self.ra_string = pu.coord_to_string(*pu.rad_to_hms(self.ra_rad)) self.dec_rad = sigproc.dec2radians(filhdr['src_dej']) self.dec_string = pu.coord_to_string(*pu.rad_to_dms(self.dec_rad)) self.str_coords = "J"+"".join(self.ra_string.split(":")[:2]) if self.dec_rad >= 0.0: self.str_coords += "+" self.str_coords += "".join(self.dec_string.split(":")[:2]) self.az = filhdr['az_start'] self.el = 90.0-filhdr['za_start'] fillen = os.stat(fil_filenm)[6] self.raw_N = (fillen-hdrlen)/(filhdr['nbits']/8)/filhdr['nchans'] self.dt = filhdr['tsamp'] self.raw_T = self.raw_N * self.dt self.N = orig_N self.T = self.N * self.dt # Determine the average barycentric velocity of the observation self.baryv = presto.get_baryv(self.ra_string, self.dec_string, self.MJD, self.T, obs="GB") # Where to dump all the results # Directory structure is under the base_output_directory # according to base/MJD/filenmbase/beam self.outputdir = os.path.join(base_output_dir, str(int(self.MJD)), self.str_coords) # Figure out which host we are processing on self.hostname = socket.gethostname() # The fraction of the data recommended to be masked by rfifind self.masked_fraction = 0.0 # Initialize our timers self.rfifind_time = 0.0 self.downsample_time = 0.0 self.dedispersing_time = 0.0 self.FFT_time = 0.0 self.lo_accelsearch_time = 0.0 self.hi_accelsearch_time = 0.0 self.singlepulse_time = 0.0 self.sifting_time = 0.0 self.folding_time = 0.0 self.total_time = 0.0 # Inialize some candidate counters self.num_sifted_cands = 0 self.num_folded_cands = 0 self.num_single_cands = 0
def read(self, parfilenm): self.FILE = parfilenm pf = open(parfilenm) for line in pf.readlines(): # Convert any 'D-' or 'D+' to 'E-' or 'E+' line = line.replace("D-", "E-") line = line.replace("D+", "E+") try: splitline = line.split() key = splitline[0] if key in str_keys: setattr(self, key, splitline[1]) elif key in float_keys: try: setattr(self, key, float(splitline[1])) except ValueError: pass if len( splitline ) == 3: # Some parfiles don't have flags, but do have errors if splitline[2] not in ['0', '1']: setattr(self, key + '_ERR', float(splitline[2])) if len(splitline) == 4: setattr(self, key + '_ERR', float(splitline[3])) except: print('') # Read PSR name if hasattr(self, 'PSR'): setattr(self, 'PSR', self.PSR) if hasattr(self, 'PSRJ'): setattr(self, 'PSRJ', self.PSRJ) # Deal with Ecliptic coords if (hasattr(self, 'BETA') and hasattr(self, 'LAMBDA')): self.use_eclip = True setattr(self, 'ELAT', self.BETA) setattr(self, 'ELONG', self.LAMBDA) if (slalib and hasattr(self, 'ELAT') and hasattr(self, 'ELONG')): self.use_eclip = True if hasattr(self, 'POSEPOCH'): epoch = self.POSEPOCH else: epoch = self.PEPOCH ra_rad, dec_rad = sla_ecleq(self.ELONG * pu.DEGTORAD, self.ELAT * pu.DEGTORAD, epoch) rstr = pu.coord_to_string(*pu.rad_to_hms(ra_rad)) dstr = pu.coord_to_string(*pu.rad_to_dms(dec_rad)) setattr(self, 'RAJ', rstr) setattr(self, 'DECJ', dstr) if hasattr(self, 'RAJ'): setattr(self, 'RA_RAD', pu.ra_to_rad(self.RAJ)) if hasattr(self, 'DECJ'): setattr(self, 'DEC_RAD', pu.dec_to_rad(self.DECJ)) # Compute the Galactic coords if (slalib and hasattr(self, 'RA_RAD') and hasattr(self, 'DEC_RAD')): l, b = sla_eqgal(self.RA_RAD, self.DEC_RAD) setattr(self, 'GLONG', l * pu.RADTODEG) setattr(self, 'GLAT', b * pu.RADTODEG) # Compute the Ecliptic coords if (slalib and hasattr(self, 'RA_RAD') and hasattr(self, 'DEC_RAD')): if hasattr(self, 'POSEPOCH'): epoch = self.POSEPOCH else: epoch = self.PEPOCH elon, elat = sla_eqecl(self.RA_RAD, self.DEC_RAD, epoch) setattr(self, 'ELONG', elon * pu.RADTODEG) setattr(self, 'ELAT', elat * pu.RADTODEG) if hasattr(self, 'P'): setattr(self, 'P0', self.P) if hasattr(self, 'P0'): setattr(self, 'F0', 1.0 / self.P0) if hasattr(self, 'F0'): setattr(self, 'P0', 1.0 / self.F0) if hasattr(self, 'F1'): setattr(self, 'P1', -self.F1 / (self.F0 * self.F0)) if hasattr(self, 'FB0'): setattr(self, 'PB', (1.0 / self.FB0) / 86400.0) if hasattr(self, 'P0_ERR'): if hasattr(self, 'P1_ERR'): f, ferr, fd, fderr = pu.pferrs(self.P0, self.P0_ERR, self.P1, self.P1_ERR) setattr(self, 'F0_ERR', ferr) setattr(self, 'F1', fd) setattr(self, 'F1_ERR', fderr) else: f, fd, = pu.p_to_f(self.P0, self.P1) setattr(self, 'F0_ERR', self.P0_ERR / (self.P0 * self.P0)) setattr(self, 'F1', fd) if hasattr(self, 'F0_ERR'): if hasattr(self, 'F1_ERR'): p, perr, pd, pderr = pu.pferrs(self.F0, self.F0_ERR, self.F1, self.F1_ERR) setattr(self, 'P0_ERR', perr) setattr(self, 'P1', pd) setattr(self, 'P1_ERR', pderr) else: p, pd, = pu.p_to_f(self.F0, self.F1) setattr(self, 'P0_ERR', self.F0_ERR / (self.F0 * self.F0)) setattr(self, 'P1', pd) if hasattr(self, 'DM'): setattr(self, 'DM', self.DM) if hasattr(self, 'EPS1') and hasattr(self, 'EPS2'): self.use_ell = True ecc = math.sqrt(self.EPS1 * self.EPS1 + self.EPS2 * self.EPS2) omega = math.atan2(self.EPS1, self.EPS2) setattr(self, 'ECC', ecc) setattr(self, 'OM', omega) if hasattr(self, 'PB') and hasattr(self, 'A1') and not hasattr(self, 'ECC'): setattr(self, 'ECC', 0.0) pf.close()
def __init__(self, parfilenm): self.FILE = parfilenm pf = open(parfilenm) for line in pf.readlines(): # Skip comments if line[0] == '#': continue # Convert any 'D-' or 'D+' to 'E-' or 'E+' line = line.replace("D-", "E-") line = line.replace("D+", "E+") splitline = line.split() # Skip blank lines if len(splitline) == 0: continue key = splitline[0] # Regex checks for non-digit chars, followed by digit chars m1 = re.search(r'(\D+)(\d+)$', key) # This one looks for the DMX[RF][12]_* params m2 = re.search(r'(\D+\d+_)(\d+)$', key) if key == "JUMP": if splitline[3] not in ['0', '1']: setattr(self, key + '_%s' % splitline[2], float(splitline[3])) if len(splitline) == 5: if splitline[4] not in ['0', '1']: setattr(self, key + '_%s' % splitline[2] + '_ERR', float(splitline[4])) elif len(splitline) == 6: setattr(self, key + '_%s' % splitline[2] + '_ERR', float(splitline[5])) if key in str_keys: setattr(self, key, splitline[1]) elif key in float_keys: try: setattr(self, key, float(splitline[1])) except ValueError: pass elif m1 is not None: m = m1 if m2 is not None: m = m2 if m.group(1) in floatn_keys: try: setattr(self, key, float(splitline[1])) except ValueError: pass if len( splitline ) == 3: # Some parfiles don't have flags, but do have errors if splitline[2] not in ['0', '1']: setattr(self, key + '_ERR', float(splitline[2])) if len(splitline) == 4: setattr(self, key + '_ERR', float(splitline[3])) # Deal with Ecliptic coords if (hasattr(self, 'BETA') and hasattr(self, 'LAMBDA')): setattr(self, 'ELAT', self.BETA) setattr(self, 'ELONG', self.LAMBDA) if (slalib and hasattr(self, 'ELAT') and hasattr(self, 'ELONG')): # TEMPO's ecliptic coords are always based on J2000 epoch ra_rad, dec_rad = sla_ecleq(self.ELONG * pc.DEGTORAD, self.ELAT * pc.DEGTORAD, J2000) rstr = pu.coord_to_string(*pu.rad_to_hms(ra_rad)) dstr = pu.coord_to_string(*pu.rad_to_dms(dec_rad)) setattr(self, 'RAJ', rstr) setattr(self, 'DECJ', dstr) if hasattr(self, 'RAJ'): setattr(self, 'RA_RAD', pu.ra_to_rad(self.RAJ)) if hasattr(self, 'DECJ'): setattr(self, 'DEC_RAD', pu.dec_to_rad(self.DECJ)) # Compute the Galactic coords if (slalib and hasattr(self, 'RA_RAD') and hasattr(self, 'DEC_RAD')): l, b = sla_eqgal(self.RA_RAD, self.DEC_RAD) setattr(self, 'GLONG', l * pc.RADTODEG) setattr(self, 'GLAT', b * pc.RADTODEG) # Compute the Ecliptic coords if (slalib and hasattr(self, 'RA_RAD') and hasattr(self, 'DEC_RAD')): # TEMPO's ecliptic coords are always based on J2000 epoch elon, elat = sla_eqecl(self.RA_RAD, self.DEC_RAD, J2000) setattr(self, 'ELONG', elon * pc.RADTODEG) setattr(self, 'ELAT', elat * pc.RADTODEG) if hasattr(self, 'P'): setattr(self, 'P0', self.P) if hasattr(self, 'P0'): setattr(self, 'F0', 1.0 / self.P0) if hasattr(self, 'F0'): setattr(self, 'P0', 1.0 / self.F0) if hasattr(self, 'FB0'): setattr(self, 'PB', (1.0 / self.FB0) / pc.SECPERDAY) if hasattr(self, 'P0_ERR'): if hasattr(self, 'P1_ERR'): f, ferr, fd, fderr = pu.pferrs(self.P0, self.P0_ERR, self.P1, self.P1_ERR) setattr(self, 'F0_ERR', ferr) setattr(self, 'F1', fd) setattr(self, 'F1_ERR', fderr) else: f, fd, = pu.p_to_f(self.P0, self.P1) setattr(self, 'F0_ERR', self.P0_ERR / (self.P0 * self.P0)) setattr(self, 'F1', fd) else: if hasattr(self, 'P1'): f, fd, = pu.p_to_f(self.P0, self.P1) setattr(self, 'F1', fd) elif hasattr(self, 'F1'): p, pd, = pu.p_to_f(self.F0, self.F1) setattr(self, 'P1', pd) if (hasattr(self, 'F0_ERR') and hasattr(self, 'F1_ERR')): p, perr, pd, pderr = pu.pferrs(self.F0, self.F0_ERR, self.F1, self.F1_ERR) setattr(self, 'P0_ERR', perr) setattr(self, 'P1', pd) setattr(self, 'P1_ERR', pderr) elif (hasattr(self, 'F0') and hasattr(self, 'F0_ERR')): setattr(self, 'P0_ERR', self.F0_ERR / (self.F0 * self.F0)) if hasattr(self, 'EPS1') and hasattr(self, 'EPS2'): ecc = math.sqrt(self.EPS1 * self.EPS1 + self.EPS2 * self.EPS2) omega = math.atan2(self.EPS1, self.EPS2) setattr(self, 'E', ecc) setattr(self, 'OM', omega * pc.RADTODEG) setattr(self, 'T0', self.TASC + self.PB * omega / pc.TWOPI) if hasattr(self, 'PB') and hasattr(self, 'A1') and not \ (hasattr(self, 'E') or hasattr(self, 'ECC')): setattr(self, 'E', 0.0) if hasattr(self, 'T0') and not hasattr(self, 'TASC'): setattr(self, 'TASC', self.T0 - self.PB * self.OM / 360.0) if hasattr(self, 'E') and not hasattr(self, 'ECC'): setattr(self, 'ECC', self.E) if not hasattr(self, 'EPS1'): if hasattr(self, 'E_ERR'): setattr(self, 'ECC_ERR', self.E_ERR) if hasattr(self, 'ECC') and not hasattr(self, 'E'): setattr(self, 'E', self.ECC) setattr(self, 'E_ERR', self.ECC_ERR) pf.close()
print("1st_file_samps = ", first_file_subints) print("numfiles = ", numfiles) break else: accum_subints += subints_per_file[ii] # Now make a command line option for guppidrift2fil.py tmpfilenm = "tmp%d.fil" % random.randint(0, 2**30) cmd = "guppidrift2fil.py --skip=%d --nsubint=%d -o %s " % \ (skip, raw_N, tmpfilenm) for goodfile in infilenms[ii:ii + numfiles]: cmd += "%s " % goodfile print(cmd) os.system(cmd) # Now read the header to determine what the correct filename # should be. Use that to rename the fil file. filhdr, hdrlen = sigproc.read_header(tmpfilenm) MJDi = int(filhdr['tstart']) ra_rad = sigproc.ra2radians(filhdr['src_raj']) ra_string = pu.coord_to_string(*pu.rad_to_hms(ra_rad)) dec_rad = sigproc.dec2radians(filhdr['src_dej']) dec_string = pu.coord_to_string(*pu.rad_to_dms(dec_rad)) str_coords = "".join(ra_string.split(":")[:2]) if dec_rad >= 0.0: str_coords += "+" str_coords += "".join(dec_string.split(":")[:2]) filfilenm = "GBT350drift_%d_%s.fil" % (MJDi, str_coords) os.rename(tmpfilenm, filfilenm) print("Renamed '%s' to '%s'." % (tmpfilenm, filfilenm))
def __str__(self): out = '' if (self.name): out = out + "\nPulsar B%s (J%s)\n" % \ (self.name, self.jname) else: out = out + "\nPulsar J%s\n" % (self.jname) if (self.alias): out = out + " Alias = %s\n" % self.alias if (self.assoc is not None): out = out + " Association = %s\n" % self.assoc if (self.survey is not None): out = out + " Survey Detections = %s\n" % self.survey out = out + " (Discoverer first)\n" if (self.type is not None): out = out + " Type = %s\n" % self.type (h, m, s) = pu.rad_to_hms(self.ra) serr = pc.RADTOSEC * self.raerr out = out + " RA (J2000) = %s +/- %.4fs\n" % \ (pu.coord_to_string(h, m, s), serr) (d, m, s) = pu.rad_to_dms(self.dec) serr = pc.RADTOARCSEC * self.decerr out = out + " DEC (J2000) = %s +/- %.4f\"\n" % \ (pu.coord_to_string(d, m, s), serr) out = out + " (l, b) = (%.2f, %.2f)\n" % \ (self.l, self.b) out = out + " DM (cm-3 pc) = %.8g +/- %.5g\n" % \ (self.dm, self.dmerr) if (self.s400 is not None): out = out + " S_400MHz (mJy) = %.3g +/- %.2g\n" % \ (self.s400, self.s400err) if (self.s1400 is not None): out = out + " S_1400MHz (mJy) = %.3g +/- %.2g\n" % \ (self.s1400, self.s1400err) if (self.dist is not None): out = out + " Distance (kpc) = %.3g\n" % self.dist out = out + " Period (s) = %.15g +/- %.15g\n" % \ (self.p, self.perr) out = out + " P-dot (s/s) = %.8g +/- %.8g\n" % \ (self.pd, self.pderr) out = out + " Epoch (MJD) = %.10g\n" % self.pepoch if (self.binary): out = out + " P_binary (s) = %.10g +/- %.10g\n" % \ (self.pb*86400.0, self.pberr*86400.0) out = out + " P_binary (d) = %.10g +/- %.10g\n" % \ (self.pb, self.pberr) if self.x is not None: out = out + " a*sin(i)/c (s) = %.8g +/- %.8g\n" % \ (self.x, self.xerr) if self.e is not None: out = out + " Eccentricity = %.8g +/- %.8g\n" % \ (self.e, self.eerr) if (self.e > 0.0): if self.w is not None: out = out + " Long of Peri (deg) = %.10g +/- %.10g\n" % \ (self.w, self.werr) if self.To is not None: out = out + " Time of Peri (MJD) = %.12g +/- %.12g\n" % \ (self.To, self.Toerr) else: if self.To is not None: out = out + " T of Ascd Node (MJD) = %.12g +/- %.12g\n" % \ (self.To, self.Toerr) return out
def __init__(self, fil_filenm): self.fil_filenm = fil_filenm self.basefilenm = fil_filenm.rstrip(".fil") self.beam = int(self.basefilenm[-1]) filhdr, self.hdrlen = sigproc.read_header(fil_filenm) self.orig_filenm = filhdr['rawdatafile'] self.MJD = filhdr['tstart'] self.nchans = filhdr['nchans'] self.ra_rad = sigproc.ra2radians(filhdr['src_raj']) self.ra_string = psr_utils.coord_to_string(\ *psr_utils.rad_to_hms(self.ra_rad)) self.dec_rad = sigproc.dec2radians(filhdr['src_dej']) self.dec_string = psr_utils.coord_to_string(\ *psr_utils.rad_to_dms(self.dec_rad)) self.az = filhdr['az_start'] self.el = 90.0 - filhdr['za_start'] self.BW = abs(filhdr['foff']) * filhdr['nchans'] self.dt = filhdr['tsamp'] self.orig_N = sigproc.samples_per_file(fil_filenm, filhdr, self.hdrlen) self.orig_T = self.orig_N * self.dt self.N = psr_utils.choose_N(self.orig_N) self.T = self.N * self.dt # Update the RA and DEC from the database file if required newposn = read_db_posn(self.orig_filenm, self.beam) if newposn is not None: self.ra_string, self.dec_string = newposn # ... and use them to update the filterbank file fix_fil_posn(fil_filenm, self.hdrlen, self.ra_string, self.dec_string) # Determine the average barycentric velocity of the observation self.baryv = presto.get_baryv(self.ra_string, self.dec_string, self.MJD, self.T, obs="AO") # Where to dump all the results # Directory structure is under the base_output_directory # according to base/MJD/filenmbase/beam self.outputdir = os.path.join(base_output_directory, str(int(self.MJD)), self.basefilenm[:-2], str(self.beam)) # Figure out which host we are processing on self.hostname = socket.gethostname() # The fraction of the data recommended to be masked by rfifind self.masked_fraction = 0.0 # Initialize our timers self.rfifind_time = 0.0 self.downsample_time = 0.0 self.subbanding_time = 0.0 self.dedispersing_time = 0.0 self.FFT_time = 0.0 self.lo_accelsearch_time = 0.0 self.hi_accelsearch_time = 0.0 self.singlepulse_time = 0.0 self.sifting_time = 0.0 self.folding_time = 0.0 self.total_time = 0.0 # Inialize some candidate counters self.num_sifted_cands = 0 self.num_folded_cands = 0 self.num_single_cands = 0