int main(int argc, char *argv[]) { FILE *fftfile, *candfile; float powargr, powargi, *powers = NULL, *minifft; float norm, numchunks, *powers_pos; int nbins, newncand, nfftsizes, fftlen, halffftlen, binsleft; int numtoread, filepos = 0, loopct = 0, powers_offset, ncand2; int ii, ct, newper = 0, oldper = 0, numsumpow = 1; double T, totnumsearched = 0.0, minsig = 0.0, min_orb_p, max_orb_p; char *rootfilenm, *notes; fcomplex *data = NULL; rawbincand tmplist[MININCANDS], *list; infodata idata; struct tms runtimes; double ttim, utim, stim, tott; Cmdline *cmd; fftwf_plan fftplan; /* Prep the timer */ tott = times(&runtimes) / (double) CLK_TCK; /* Call usage() if we have no command line arguments */ if (argc == 1) { Program = argv[0]; printf("\n"); usage(); exit(1); } /* Parse the command line using the excellent program Clig */ cmd = parseCmdline(argc, argv); #ifdef DEBUG showOptionValues(); #endif printf("\n\n"); printf(" Phase Modulation Pulsar Search Routine\n"); printf(" by Scott M. Ransom\n\n"); { int hassuffix = 0; char *suffix; hassuffix = split_root_suffix(cmd->argv[0], &rootfilenm, &suffix); if (hassuffix) { if (strcmp(suffix, "fft") != 0) { printf("\nInput file ('%s') must be a FFT file ('.fft')!\n\n", cmd->argv[0]); free(suffix); exit(0); } free(suffix); } else { printf("\nInput file ('%s') must be a FFT file ('.fft')!\n\n", cmd->argv[0]); exit(0); } } /* Read the info file */ readinf(&idata, rootfilenm); T = idata.N * idata.dt; if (strlen(remove_whitespace(idata.object)) > 0) { printf("Analyzing '%s' data from '%s'.\n\n", remove_whitespace(idata.object), cmd->argv[0]); } else { printf("Analyzing data from '%s'.\n\n", cmd->argv[0]); } min_orb_p = MINORBP; if (cmd->noaliasP) max_orb_p = T / 2.0; else max_orb_p = T / 1.2; /* open the FFT file and get its length */ fftfile = chkfopen(cmd->argv[0], "rb"); nbins = chkfilelen(fftfile, sizeof(fcomplex)); /* Check that cmd->maxfft is an acceptable power of 2 */ ct = 4; ii = 1; while (ct < MAXREALFFT || ii) { if (ct == cmd->maxfft) ii = 0; ct <<= 1; } if (ii) { printf("\n'maxfft' is out of range or not a power-of-2.\n\n"); exit(1); } /* Check that cmd->minfft is an acceptable power of 2 */ ct = 4; ii = 1; while (ct < MAXREALFFT || ii) { if (ct == cmd->minfft) ii = 0; ct <<= 1; } if (ii) { printf("\n'minfft' is out of range or not a power-of-2.\n\n"); exit(1); } /* Low and high Fourier freqs to check */ if (cmd->floP) { cmd->rlo = floor(cmd->flo * T); if (cmd->rlo < cmd->lobin) cmd->rlo = cmd->lobin; if (cmd->rlo > cmd->lobin + nbins - 1) { printf("\nLow frequency to search 'flo' is greater than\n"); printf(" the highest available frequency. Exiting.\n\n"); exit(1); } } else { cmd->rlo = 1.0; if (cmd->rlo < cmd->lobin) cmd->rlo = cmd->lobin; if (cmd->rlo > cmd->lobin + nbins - 1) { printf("\nLow frequency to search 'rlo' is greater than\n"); printf(" the available number of points. Exiting.\n\n"); exit(1); } } if (cmd->fhiP) { cmd->rhi = ceil(cmd->fhi * T); if (cmd->rhi > cmd->lobin + nbins - 1) cmd->rhi = cmd->lobin + nbins - 1; if (cmd->rhi < cmd->rlo) { printf("\nHigh frequency to search 'fhi' is less than\n"); printf(" the lowest frequency to search 'flo'. Exiting.\n\n"); exit(1); } } else if (cmd->rhiP) { if (cmd->rhi > cmd->lobin + nbins - 1) cmd->rhi = cmd->lobin + nbins - 1; if (cmd->rhi < cmd->rlo) { printf("\nHigh frequency to search 'rhi' is less than\n"); printf(" the lowest frequency to search 'rlo'. Exiting.\n\n"); exit(1); } } /* Determine how many different mini-fft sizes we will use */ nfftsizes = 1; ii = cmd->maxfft; while (ii > cmd->minfft) { ii >>= 1; nfftsizes++; } /* Allocate some memory and prep some variables. */ /* For numtoread, the 6 just lets us read extra data at once */ numtoread = 6 * cmd->maxfft; if (cmd->stack == 0) powers = gen_fvect(numtoread); minifft = (float *) fftwf_malloc(sizeof(float) * (cmd->maxfft * cmd->numbetween + 2)); ncand2 = 2 * cmd->ncand; list = (rawbincand *) malloc(sizeof(rawbincand) * ncand2); for (ii = 0; ii < ncand2; ii++) list[ii].mini_sigma = 0.0; for (ii = 0; ii < MININCANDS; ii++) tmplist[ii].mini_sigma = 0.0; filepos = cmd->rlo - cmd->lobin; numchunks = (float) (cmd->rhi - cmd->rlo) / numtoread; printf("Searching...\n"); printf(" Amount complete = %3d%%", 0); fflush(stdout); /* Prep FFTW */ read_wisdom(); /* Loop through fftfile */ while ((filepos + cmd->lobin) < cmd->rhi) { /* Calculate percentage complete */ newper = (int) (loopct / numchunks * 100.0); if (newper > oldper) { newper = (newper > 99) ? 100 : newper; printf("\r Amount complete = %3d%%", newper); oldper = newper; fflush(stdout); } /* Adjust our search parameters if close to end of zone to search */ binsleft = cmd->rhi - (filepos + cmd->lobin); if (binsleft < cmd->minfft) break; if (binsleft < numtoread) { /* Change numtoread */ numtoread = cmd->maxfft; while (binsleft < numtoread) { cmd->maxfft /= 2; numtoread = cmd->maxfft; } } fftlen = cmd->maxfft; /* Read from fftfile */ if (cmd->stack == 0) { data = read_fcomplex_file(fftfile, filepos, numtoread); for (ii = 0; ii < numtoread; ii++) powers[ii] = POWER(data[ii].r, data[ii].i); numsumpow = 1; } else { powers = read_float_file(fftfile, filepos, numtoread); numsumpow = cmd->stack; } if (filepos == 0) powers[0] = 1.0; /* Chop the powers that are way above the median level */ prune_powers(powers, numtoread, numsumpow); /* Loop through the different small FFT sizes */ while (fftlen >= cmd->minfft) { halffftlen = fftlen / 2; powers_pos = powers; powers_offset = 0; /* Create the appropriate FFT plan */ fftplan = fftwf_plan_dft_r2c_1d(cmd->interbinP ? fftlen : 2 * fftlen, minifft, (fftwf_complex *) minifft, FFTW_PATIENT); /* Perform miniffts at each section of the powers array */ while ((numtoread - powers_offset) > (int) ((1.0 - cmd->overlap) * cmd->maxfft + DBLCORRECT)) { /* Copy the proper amount and portion of powers into minifft */ memcpy(minifft, powers_pos, fftlen * sizeof(float)); /* For Fourier interpolation use a zeropadded FFT */ if (cmd->numbetween > 1 && !cmd->interbinP) { for (ii = fftlen; ii < cmd->numbetween * fftlen; ii++) minifft[ii] = 0.0; } /* Perform the minifft */ fftwf_execute(fftplan); /* Normalize and search the miniFFT */ norm = sqrt(fftlen * numsumpow) / minifft[0]; for (ii = 0; ii < (cmd->interbinP ? fftlen + 1 : 2 * fftlen + 1); ii++) minifft[ii] *= norm; search_minifft((fcomplex *) minifft, halffftlen, min_orb_p, max_orb_p, tmplist, MININCANDS, cmd->harmsum, cmd->numbetween, idata.N, T, (double) (powers_offset + filepos + cmd->lobin), cmd->interbinP ? INTERBIN : INTERPOLATE, cmd->noaliasP ? NO_CHECK_ALIASED : CHECK_ALIASED); /* Check if the new cands should go into the master cand list */ for (ii = 0; ii < MININCANDS; ii++) { if (tmplist[ii].mini_sigma > minsig) { /* Check to see if another candidate with these properties */ /* is already in the list. */ if (not_already_there_rawbin(tmplist[ii], list, ncand2)) { list[ncand2 - 1] = tmplist[ii]; minsig = percolate_rawbincands(list, ncand2); } } else { break; } /* Mini-fft search for loop */ } totnumsearched += fftlen; powers_pos += (int) (cmd->overlap * fftlen); powers_offset = powers_pos - powers; /* Position of mini-fft in data set while loop */ } fftwf_destroy_plan(fftplan); fftlen >>= 1; /* Size of mini-fft while loop */ } if (cmd->stack == 0) vect_free(data); else vect_free(powers); filepos += (numtoread - (int) ((1.0 - cmd->overlap) * cmd->maxfft)); loopct++; /* File position while loop */ } /* Print the final percentage update */ printf("\r Amount complete = %3d%%\n\n", 100); /* Print the number of frequencies searched */ printf("Searched %.0f pts (including interbins).\n\n", totnumsearched); printf("Timing summary:\n"); tott = times(&runtimes) / (double) CLK_TCK - tott; utim = runtimes.tms_utime / (double) CLK_TCK; stim = runtimes.tms_stime / (double) CLK_TCK; ttim = utim + stim; printf(" CPU time: %.3f sec (User: %.3f sec, System: %.3f sec)\n", ttim, utim, stim); printf(" Total time: %.3f sec\n\n", tott); printf("Writing result files and cleaning up.\n"); /* Count how many candidates we actually have */ ii = 0; while (ii < ncand2 && list[ii].mini_sigma != 0) ii++; newncand = (ii > cmd->ncand) ? cmd->ncand : ii; /* Set our candidate notes to all spaces */ notes = malloc(sizeof(char) * newncand * 18 + 1); for (ii = 0; ii < newncand; ii++) strncpy(notes + ii * 18, " ", 18); /* Check the database for possible known PSR detections */ if (idata.ra_h && idata.dec_d) { for (ii = 0; ii < newncand; ii++) { comp_rawbin_to_cand(&list[ii], &idata, notes + ii * 18, 0); } } /* Compare the candidates with each other */ compare_rawbin_cands(list, newncand, notes); /* Send the candidates to the text file */ file_rawbin_candidates(list, notes, newncand, cmd->harmsum, rootfilenm); /* Write the binary candidate file */ { char *candnm; candnm = (char *) calloc(strlen(rootfilenm) + 15, sizeof(char)); sprintf(candnm, "%s_bin%d.cand", rootfilenm, cmd->harmsum); candfile = chkfopen(candnm, "wb"); chkfwrite(list, sizeof(rawbincand), (unsigned long) newncand, candfile); fclose(candfile); free(candnm); } /* Free our arrays and close our files */ if (cmd->stack == 0) vect_free(powers); free(list); fftwf_free(minifft); free(notes); free(rootfilenm); fclose(fftfile); printf("Done.\n\n"); return (0); }
void search_minifft(fcomplex * minifft, int numminifft, double min_orb_p, double max_orb_p, rawbincand * cands, int numcands, int numharmsum, int numbetween, double numfullfft, double timefullfft, double lorfullfft, presto_interptype interptype, presto_checkaliased checkaliased) /* This routine searches a short FFT (usually produced using the */ /* MiniFFT binary search method) and returns a candidte vector */ /* containing information about the best binary candidates found. */ /* The routine uses either interbinning or interpolation as well */ /* as harmonic summing during the search. */ /* Arguments: */ /* 'minifft' is the FFT to search (complex valued) */ /* 'numminifft' is the number of complex points in 'minifft' */ /* 'min_orb_p' is the minimum orbital period (s) to search */ /* 'max_orb_p' is the maximum orbital period (s) to search */ /* 'cands' is a pre-allocated vector of rawbincand type in which */ /* the sorted (in decreasing sigma) candidates are returned */ /* 'numcands' is the length of the 'cands' vector */ /* 'numharmsum' the number of harmonics to sum during the search */ /* 'numbetween' the points to interpolate per bin */ /* 'numfullfft' the number of points in the original long FFT */ /* 'timefullfft' the duration of the original time series (s) */ /* 'lorfullfft' the 1st bin of the long FFT that was miniFFT'd */ /* 'interptype' is either INTERBIN or INTERPOLATE. */ /* INTERBIN = (interbinning) is fast but less sensitive. */ /* NOTE: INTERBINNING is conducted by this routine! */ /* INTERPOLATE = (Fourier interpolation) is slower but more */ /* sensitive. */ /* NOTE: The interpolation is assumed to ALREADY have been */ /* completed by the calling function! The easiest */ /* way is by zero-padding to 2*numminifft and FFTing. */ /* If you use this method, make sure numminifft is the*/ /* original length rather than the interpolated */ /* length and also make sure numbetween is correct. */ /* 'checkaliased' is either CHECK_ALIASED or NO_CHECK_ALIASED. */ /* NO_CHECK_ALIASED = harmonic summing does not include */ /* aliased freqs making it faster but less sensitive. */ /* CHECK_ALIASED = harmonic summing includes aliased freqs */ /* making it slower but more sensitive. */ { int ii, jj, fftlen, offset, numtosearch = 0, lobin, hibin, numspread = 0; float powargr, powargi, *fullpows = NULL, *sumpows; double twobypi, minpow, minsig, dr, numindep; fcomplex *spread; /* Override the value of numbetween if interbinning */ if (interptype == INTERBIN) numbetween = 2; /* Prep some other values we will need */ dr = 1.0 / (double) numbetween; twobypi = 2.0 / PI; fftlen = numminifft * numbetween; for (ii = 0; ii < numcands; ii++) { cands[ii].mini_sigma = 0.0; cands[ii].mini_power = 0.0; } lobin = ceil(2 * numminifft * min_orb_p / timefullfft); if (lobin <= 0) lobin = 1; hibin = floor(2 * numminifft * max_orb_p / timefullfft); if (hibin >= 2 * numminifft) hibin = 2 * numminifft - 1; lobin *= numbetween; hibin *= numbetween; /* Spread and interpolate the fft */ numtosearch = (checkaliased == CHECK_ALIASED) ? 2 * fftlen : fftlen; numspread = numminifft * numbetween + 1; if (interptype == INTERPOLATE) { /* INTERPOLATE */ spread = minifft; } else { /* INTERBIN */ spread = gen_cvect(numspread); spread_with_pad(minifft, numminifft, spread, numspread, numbetween, 0); for (ii = 1; ii < fftlen; ii += 2) { spread[ii].r = twobypi * (spread[ii - 1].r - spread[ii + 1].r); spread[ii].i = twobypi * (spread[ii - 1].i - spread[ii + 1].i); } } spread[0].r = spread[fftlen].r = 1.0; spread[0].i = spread[fftlen].i = 0.0; fullpows = gen_fvect(numtosearch); fullpows[0] = 1.0; if (checkaliased == CHECK_ALIASED) fullpows[fftlen] = 1.0; /* used to be nyquist^2 */ /* The following wraps the data around the Nyquist freq such that */ /* we consider aliased frequencies as well (If CHECK_ALIASED). */ if (checkaliased == CHECK_ALIASED) for (ii = 1, jj = numtosearch - 1; ii < fftlen; ii++, jj--) fullpows[ii] = fullpows[jj] = POWER(spread[ii].r, spread[ii].i); else for (ii = 1; ii < numtosearch; ii++) fullpows[ii] = POWER(spread[ii].r, spread[ii].i); if (interptype == INTERBIN) vect_free(spread); /* Search the raw powers */ numindep = hibin - lobin + 1.0; minpow = power_for_sigma(MINRETURNSIG, 1, numindep); for (ii = lobin; ii < hibin; ii++) { if (fullpows[ii] > minpow) { cands[numcands - 1].mini_r = dr * (double) ii; cands[numcands - 1].mini_power = fullpows[ii]; cands[numcands - 1].mini_numsum = 1.0; cands[numcands - 1].mini_sigma = candidate_sigma(fullpows[ii], 1, numindep); minsig = percolate_rawbincands(cands, numcands); if (cands[numcands - 1].mini_power > minpow) minpow = cands[numcands - 1].mini_power; } } /* If needed, sum and search the harmonics */ if (numharmsum > 1) { sumpows = gen_fvect(numtosearch); memcpy(sumpows, fullpows, sizeof(float) * numtosearch); for (ii = 2; ii <= numharmsum; ii++) { offset = ii / 2; numindep = (hibin - lobin + 1.0) / (double) ii; if (cands[numcands - 1].mini_sigma < MINRETURNSIG) minsig = MINRETURNSIG; else minsig = cands[numcands - 1].mini_sigma; minpow = power_for_sigma(minsig, ii, numindep); for (jj = lobin * ii; jj < hibin; jj++) { sumpows[jj] += fullpows[(jj + offset) / ii]; if (sumpows[jj] > minpow) { cands[numcands - 1].mini_r = (dr * (double) jj) / ii; cands[numcands - 1].mini_power = sumpows[jj]; cands[numcands - 1].mini_numsum = (double) ii; cands[numcands - 1].mini_sigma = candidate_sigma(sumpows[jj], ii, numindep); minsig = percolate_rawbincands(cands, numcands); if (minsig > MINRETURNSIG) minpow = power_for_sigma(minsig, ii, numindep); } } } vect_free(sumpows); } vect_free(fullpows); /* Add the rest of the rawbincand data to the candidate array */ for (ii = 0; ii < numcands; ii++) { cands[ii].full_N = numfullfft; cands[ii].full_T = timefullfft; cands[ii].full_lo_r = lorfullfft; cands[ii].mini_N = 2 * numminifft; /* # of real points */ cands[ii].psr_p = timefullfft / (lorfullfft + numminifft); cands[ii].orb_p = timefullfft * cands[ii].mini_r / cands[ii].mini_N; } }