Example #1
0
int main(int argc, char *argv[])
{
   /* Any variable that begins with 't' means topocentric */
   /* Any variable that begins with 'b' means barycentric */
   FILE **outfiles = NULL;
   float **outdata;
   double dtmp, *dms, avgdm = 0.0, dsdt = 0, maxdm;
   double *dispdt, tlotoa = 0.0, blotoa = 0.0, BW_ddelay = 0.0;
   double max = -9.9E30, min = 9.9E30, var = 0.0, avg = 0.0;
   double *btoa = NULL, *ttoa = NULL, avgvoverc = 0.0;
   char obs[3], ephem[10], rastring[50], decstring[50];
   long totnumtowrite, totwrote = 0, padwrote = 0, datawrote = 0;
   int *idispdt, **offsets;
   int ii, jj, numadded = 0, numremoved = 0, padding = 0, good_inputs = 1;
   int numbarypts = 0, numread = 0, numtowrite = 0;
   int padtowrite = 0, statnum = 0;
   int numdiffbins = 0, *diffbins = NULL, *diffbinptr = NULL, good_padvals = 0;
   double local_lodm;
   char *datafilenm, *outpath, *outfilenm, *hostname;
   struct spectra_info s;
   infodata idata;
   mask obsmask;

   MPI_Init(&argc, &argv);
   MPI_Comm_size(MPI_COMM_WORLD, &numprocs);
   MPI_Comm_rank(MPI_COMM_WORLD, &myid);
#ifdef _OPENMP
   omp_set_num_threads(1); // Explicitly turn off OpenMP
#endif
   set_using_MPI();
   {
      FILE *hostfile;
      char tmpname[100];
      int retval;

      hostfile = chkfopen("/etc/hostname", "r");
      retval = fscanf(hostfile, "%s\n", tmpname);
      if (retval==0) {
          printf("Warning:  error reading /etc/hostname on proc %d\n", myid);
      }
      hostname = (char *) calloc(strlen(tmpname) + 1, 1);
      memcpy(hostname, tmpname, strlen(tmpname));
      fclose(hostfile);
   }

   /* Call usage() if we have no command line arguments */

   if (argc == 1) {
      if (myid == 0) {
         Program = argv[0];
         usage();
      }
      MPI_Finalize();
      exit(1);
   }

   make_maskbase_struct();
   make_spectra_info_struct();

   /* Parse the command line using the excellent program Clig */

   cmd = parseCmdline(argc, argv);
   spectra_info_set_defaults(&s);
   // If we are zeroDMing, make sure that clipping is off.
   if (cmd->zerodmP) cmd->noclipP = 1;
   s.clip_sigma = cmd->clip;
   if (cmd->noclipP) {
       cmd->clip = 0.0;
       s.clip_sigma = 0.0;
   }
   if (cmd->ifsP) {
       // 0 = default or summed, 1-4 are possible also
       s.use_poln = cmd->ifs + 1;
   }
   if (!cmd->numoutP)
      cmd->numout = LONG_MAX;

#ifdef DEBUG
   showOptionValues();
#endif

   if (myid == 0) {             /* Master node only */
      printf("\n\n");
      printf("      Parallel Pulsar Subband De-dispersion Routine\n");
      printf("                 by Scott M. Ransom\n\n");

      s.filenames = cmd->argv;
      s.num_files = cmd->argc;
      s.clip_sigma = cmd->clip;
      // -1 causes the data to determine if we use weights, scales, & 
      // offsets for PSRFITS or flip the band for any data type where
      // we can figure that out with the data
      s.apply_flipband = (cmd->invertP) ? 1 : -1;
      s.apply_weight = (cmd->noweightsP) ? 0 : -1;
      s.apply_scale  = (cmd->noscalesP) ? 0 : -1;
      s.apply_offset = (cmd->nooffsetsP) ? 0 : -1;
      s.remove_zerodm = (cmd->zerodmP) ? 1 : 0;

      if (RAWDATA) {
          if (cmd->filterbankP) s.datatype = SIGPROCFB;
          else if (cmd->psrfitsP) s.datatype = PSRFITS;
          else if (cmd->pkmbP) s.datatype = SCAMP;
          else if (cmd->bcpmP) s.datatype = BPP;
          else if (cmd->wappP) s.datatype = WAPP;
          else if (cmd->spigotP) s.datatype = SPIGOT;
      } else {  // Attempt to auto-identify the data
          identify_psrdatatype(&s, 1);
          if (s.datatype==SIGPROCFB) cmd->filterbankP = 1;
          else if (s.datatype==PSRFITS) cmd->psrfitsP = 1;
          else if (s.datatype==SCAMP) cmd->pkmbP = 1;
          else if (s.datatype==BPP) cmd->bcpmP = 1;
          else if (s.datatype==WAPP) cmd->wappP = 1;
          else if (s.datatype==SPIGOT) cmd->spigotP = 1;
          else if (s.datatype==SUBBAND) insubs = 1;
          else {
              printf("\nError:  Unable to identify input data files.  Please specify type.\n\n");
              good_inputs = 0;
          }
      }
      // So far we can only handle PSRFITS, filterbank, and subbands
      if (s.datatype!=PSRFITS && 
          s.datatype!=SIGPROCFB && 
          s.datatype!=SUBBAND) good_inputs = 0;

      // For subbanded data
      if (!RAWDATA) s.files = (FILE **)malloc(sizeof(FILE *) * s.num_files);

      if (good_inputs && (RAWDATA || insubs)) {
          char description[40];
          psrdatatype_description(description, s.datatype);
          if (s.num_files > 1)
              printf("Reading %s data from %d files:\n", description, s.num_files);
          else
              printf("Reading %s data from 1 file:\n", description);
          for (ii = 0; ii < s.num_files; ii++) {
              printf("  '%s'\n", cmd->argv[ii]);
              if (insubs) s.files[ii] = chkfopen(s.filenames[ii], "rb");
          }
          printf("\n");
          if (RAWDATA) {
              read_rawdata_files(&s);
              print_spectra_info_summary(&s);
              spectra_info_to_inf(&s, &idata);
          } else { // insubs
              char *root, *suffix;
              cmd->nsub = s.num_files;
              s.N = chkfilelen(s.files[0], sizeof(short));
              s.start_subint = gen_ivect(1);
              s.num_subint = gen_ivect(1);
              s.start_MJD = (long double *)malloc(sizeof(long double));
              s.start_spec = (long long *)malloc(sizeof(long long));
              s.num_spec = (long long *)malloc(sizeof(long long));
              s.num_pad = (long long *)malloc(sizeof(long long));
              s.start_spec[0] = 0L;
              s.start_subint[0] = 0;
              s.num_spec[0] = s.N;
              s.num_subint[0] = s.N / SUBSBLOCKLEN;
              s.num_pad[0] = 0L;
              s.padvals = gen_fvect(s.num_files);
              for (ii = 0 ; ii < ii ; ii++)
                  s.padvals[ii] = 0.0;
              if (split_root_suffix(s.filenames[0], &root, &suffix) == 0) {
                  printf("\nError:  The input filename (%s) must have a suffix!\n\n", s.filenames[0]);
                  exit(1);
              }
              if (strncmp(suffix, "sub", 3) == 0) {
                  char *tmpname;
                  tmpname = calloc(strlen(root) + 10, 1);
                  sprintf(tmpname, "%s.sub", root);
                  readinf(&idata, tmpname);
                  free(tmpname);
                  strncpy(s.telescope, idata.telescope, 40);
                  strncpy(s.backend, idata.instrument, 40);
                  strncpy(s.observer, idata.observer, 40);
                  strncpy(s.source, idata.object, 40);
                  s.ra2000 = hms2rad(idata.ra_h, idata.ra_m,
                                     idata.ra_s) * RADTODEG;
                  s.dec2000 = dms2rad(idata.dec_d, idata.dec_m,
                                      idata.dec_s) * RADTODEG;
                  ra_dec_to_string(s.ra_str,
                                   idata.ra_h, idata.ra_m, idata.ra_s);
                  ra_dec_to_string(s.dec_str,
                                   idata.dec_d, idata.dec_m, idata.dec_s);
                  s.num_channels = idata.num_chan;
                  s.start_MJD[0] = idata.mjd_i + idata.mjd_f;
                  s.dt = idata.dt;
                  s.T = s.N * s.dt;
                  s.lo_freq = idata.freq;
                  s.df = idata.chan_wid;
                  s.hi_freq = s.lo_freq + (s.num_channels - 1.0) * s.df;
                  s.BW = s.num_channels * s.df;
                  s.fctr = s.lo_freq - 0.5 * s.df + 0.5 * s.BW;
                  s.beam_FWHM = idata.fov / 3600.0;
                  s.spectra_per_subint = SUBSBLOCKLEN;
                  print_spectra_info_summary(&s);
              } else {
                  printf("\nThe input files (%s) must be subbands!  (i.e. *.sub##)\n\n",
                         cmd->argv[0]);
                  MPI_Finalize();
                  exit(1);
              }
              free(root);
              free(suffix);
          }
      }
   }

   //  If we don't have good input data, exit
   MPI_Bcast(&good_inputs, 1, MPI_INT, 0, MPI_COMM_WORLD);
   if (!good_inputs) {
       MPI_Finalize();
       exit(1);
   }
   
   MPI_Bcast(&insubs, 1, MPI_INT, 0, MPI_COMM_WORLD);
   if (insubs)
       cmd->nsub = cmd->argc;

   /* Determine the output file names and open them */

   local_numdms = cmd->numdms / (numprocs - 1);
   dms = gen_dvect(local_numdms);
   if (cmd->numdms % (numprocs - 1)) {
       if (myid == 0)
           printf
               ("\nThe number of DMs must be divisible by (the number of processors - 1).\n\n");
       MPI_Finalize();
       exit(1);
   }
   local_lodm = cmd->lodm + (myid - 1) * local_numdms * cmd->dmstep;
   
   split_path_file(cmd->outfile, &outpath, &outfilenm);
   datafilenm = (char *) calloc(strlen(outfilenm) + 20, 1);
   if (myid > 0) {
       if (chdir(outpath) == -1) {
           printf("\nProcess %d on %s cannot chdir() to '%s'.  Exiting.\n\n", 
                  myid, hostname, outpath);
           MPI_Finalize();
           exit(1);
       }
       outfiles = (FILE **) malloc(local_numdms * sizeof(FILE *));
       for (ii = 0; ii < local_numdms; ii++) {
           dms[ii] = local_lodm + ii * cmd->dmstep;
           avgdm += dms[ii];
           sprintf(datafilenm, "%s_DM%.2f.dat", outfilenm, dms[ii]);
           outfiles[ii] = chkfopen(datafilenm, "wb");
       }
       avgdm /= local_numdms;
   }
   
   // Broadcast the raw data information

   broadcast_spectra_info(&s, myid);
   if (myid > 0) {
       spectra_info_to_inf(&s, &idata);
       if (s.datatype==SIGPROCFB) cmd->filterbankP = 1;
       else if (s.datatype==PSRFITS) cmd->psrfitsP = 1;
       else if (s.datatype==SCAMP) cmd->pkmbP = 1;
       else if (s.datatype==BPP) cmd->bcpmP = 1;
       else if (s.datatype==WAPP) cmd->wappP = 1;
       else if (s.datatype==SPIGOT) cmd->spigotP = 1;
       else if (s.datatype==SUBBAND) insubs = 1;
   }
   s.filenames = cmd->argv;

   /* Read an input mask if wanted */
   
   if (myid > 0) {
       int numpad = s.num_channels;
       if (insubs)
           numpad = s.num_files;
       s.padvals = gen_fvect(numpad);
       for (ii = 0 ; ii < numpad ; ii++)
           s.padvals[ii] = 0.0;
   }
   if (cmd->maskfileP) {
       if (myid == 0) {
           read_mask(cmd->maskfile, &obsmask);
           printf("Read mask information from '%s'\n\n", cmd->maskfile);
           good_padvals = determine_padvals(cmd->maskfile, &obsmask, s.padvals);
       }
       broadcast_mask(&obsmask, myid);
       MPI_Bcast(&good_padvals, 1, MPI_INT, 0, MPI_COMM_WORLD);
       MPI_Bcast(s.padvals, obsmask.numchan, MPI_FLOAT, 0, MPI_COMM_WORLD);
   } else {
       obsmask.numchan = obsmask.numint = 0;
       MPI_Bcast(&good_padvals, 1, MPI_INT, 0, MPI_COMM_WORLD);
   }

   // The number of topo to bary time points to generate with TEMPO
   numbarypts = (int) (s.T * 1.1 / TDT + 5.5) + 1;

   // Identify the TEMPO observatory code
   {
       char *outscope = (char *) calloc(40, sizeof(char));
       telescope_to_tempocode(idata.telescope, outscope, obs);
       free(outscope);
   }

   // Broadcast or calculate a few extra important values
   if (insubs) avgdm = idata.dm;
   idata.dm = avgdm;
   dsdt = cmd->downsamp * idata.dt;
   maxdm = cmd->lodm + cmd->numdms * cmd->dmstep;
   BW_ddelay = delay_from_dm(maxdm, idata.freq) - 
       delay_from_dm(maxdm, idata.freq + (idata.num_chan-1) * idata.chan_wid);
   blocksperread = ((int) (BW_ddelay / idata.dt) / s.spectra_per_subint + 1);
   worklen = s.spectra_per_subint * blocksperread;
   
   if (cmd->nsub > s.num_channels) {
      printf
          ("Warning:  The number of requested subbands (%d) is larger than the number of channels (%d).\n",
           cmd->nsub, s.num_channels);
      printf("          Re-setting the number of subbands to %d.\n\n", s.num_channels);
      cmd->nsub = s.num_channels;
   }

   if (s.spectra_per_subint % cmd->downsamp) {
       if (myid == 0) {
           printf
               ("\nError:  The downsample factor (%d) must be a factor of the\n",
                cmd->downsamp);
           printf("        blocklength (%d).  Exiting.\n\n", s.spectra_per_subint);
       }
       MPI_Finalize();
       exit(1);
   }

   tlotoa = idata.mjd_i + idata.mjd_f;  /* Topocentric epoch */

   if (cmd->numoutP)
      totnumtowrite = cmd->numout;
   else
      totnumtowrite = (long) idata.N / cmd->downsamp;

   if (cmd->nobaryP) {          /* Main loop if we are not barycentering... */

      /* Dispersion delays (in bins).  The high freq gets no delay   */
      /* All other delays are positive fractions of bin length (dt)  */

      dispdt = subband_search_delays(s.num_channels, cmd->nsub, avgdm,
                                     idata.freq, idata.chan_wid, 0.0);
      idispdt = gen_ivect(s.num_channels);
      for (ii = 0; ii < s.num_channels; ii++)
          idispdt[ii] = NEAREST_LONG(dispdt[ii] / idata.dt);
      vect_free(dispdt);

      /* The subband dispersion delays (see note above) */

      offsets = gen_imatrix(local_numdms, cmd->nsub);
      for (ii = 0; ii < local_numdms; ii++) {
         double *subdispdt;

         subdispdt = subband_delays(s.num_channels, cmd->nsub, dms[ii],
                                    idata.freq, idata.chan_wid, 0.0);
         dtmp = subdispdt[cmd->nsub - 1];
         for (jj = 0; jj < cmd->nsub; jj++)
            offsets[ii][jj] = NEAREST_LONG((subdispdt[jj] - dtmp) / dsdt);
         vect_free(subdispdt);
      }

      /* Allocate our data array and start getting data */

      if (myid == 0) {
         printf("De-dispersing using %d subbands.\n", cmd->nsub);
         if (cmd->downsamp > 1)
            printf("Downsampling by a factor of %d (new dt = %.10g)\n",
                   cmd->downsamp, dsdt);
         printf("\n");
      }
      
      /* Print the nodes and the DMs they are handling */
      print_dms(hostname, myid, numprocs, local_numdms, dms);

      outdata = gen_fmatrix(local_numdms, worklen / cmd->downsamp);
      numread = get_data(outdata, blocksperread, &s,
                         &obsmask, idispdt, offsets, &padding);

      while (numread == worklen) {

         numread /= cmd->downsamp;
         if (myid == 0)
            print_percent_complete(totwrote, totnumtowrite);

         /* Write the latest chunk of data, but don't   */
         /* write more than cmd->numout points.         */

         numtowrite = numread;
         if (cmd->numoutP && (totwrote + numtowrite) > cmd->numout)
            numtowrite = cmd->numout - totwrote;
         if (myid > 0) {
            write_data(outfiles, local_numdms, outdata, 0, numtowrite);
            /* Update the statistics */
            if (!padding) {
               for (ii = 0; ii < numtowrite; ii++)
                  update_stats(statnum + ii, outdata[0][ii], &min, &max, &avg, &var);
               statnum += numtowrite;
            }
         }
         totwrote += numtowrite;

         /* Stop if we have written out all the data we need to */

         if (cmd->numoutP && (totwrote == cmd->numout))
            break;

         numread = get_data(outdata, blocksperread, &s,
                            &obsmask, idispdt, offsets, &padding);
      }
      datawrote = totwrote;

   } else {                     /* Main loop if we are barycentering... */

      /* What ephemeris will we use?  (Default is DE405) */
      strcpy(ephem, "DE405");

      /* Define the RA and DEC of the observation */

      ra_dec_to_string(rastring, idata.ra_h, idata.ra_m, idata.ra_s);
      ra_dec_to_string(decstring, idata.dec_d, idata.dec_m, idata.dec_s);

      /* Allocate some arrays */

      btoa = gen_dvect(numbarypts);
      ttoa = gen_dvect(numbarypts);
      for (ii = 0; ii < numbarypts; ii++)
         ttoa[ii] = tlotoa + TDT * ii / SECPERDAY;

      /* Call TEMPO for the barycentering */

      if (myid == 0) {
         double maxvoverc = -1.0, minvoverc = 1.0, *voverc = NULL;

         printf("\nGenerating barycentric corrections...\n");
         voverc = gen_dvect(numbarypts);
         barycenter(ttoa, btoa, voverc, numbarypts, rastring, decstring, obs, ephem);
         for (ii = 0; ii < numbarypts; ii++) {
            if (voverc[ii] > maxvoverc)
               maxvoverc = voverc[ii];
            if (voverc[ii] < minvoverc)
               minvoverc = voverc[ii];
            avgvoverc += voverc[ii];
         }
         avgvoverc /= numbarypts;
         vect_free(voverc);

         printf("   Average topocentric velocity (c) = %.7g\n", avgvoverc);
         printf("   Maximum topocentric velocity (c) = %.7g\n", maxvoverc);
         printf("   Minimum topocentric velocity (c) = %.7g\n\n", minvoverc);
         printf("De-dispersing using %d subbands.\n", cmd->nsub);
         if (cmd->downsamp > 1) {
             printf("     Downsample = %d\n", cmd->downsamp);
             printf("  New sample dt = %.10g\n", dsdt);
         }
         printf("\n");
      }

      /* Print the nodes and the DMs they are handling */
      print_dms(hostname, myid, numprocs, local_numdms, dms);

      MPI_Bcast(btoa, numbarypts, MPI_DOUBLE, 0, MPI_COMM_WORLD);
      MPI_Bcast(&avgvoverc, 1, MPI_DOUBLE, 0, MPI_COMM_WORLD);
      blotoa = btoa[0];

      /* Dispersion delays (in bins).  The high freq gets no delay   */
      /* All other delays are positive fractions of bin length (dt)  */

      dispdt = subband_search_delays(s.num_channels, cmd->nsub, avgdm,
                                     idata.freq, idata.chan_wid, avgvoverc);
      idispdt = gen_ivect(s.num_channels);
      for (ii = 0; ii < s.num_channels; ii++)
          idispdt[ii] = NEAREST_LONG(dispdt[ii] / idata.dt);
      vect_free(dispdt);

      /* The subband dispersion delays (see note above) */

      offsets = gen_imatrix(local_numdms, cmd->nsub);
      for (ii = 0; ii < local_numdms; ii++) {
         double *subdispdt;

         subdispdt = subband_delays(s.num_channels, cmd->nsub, dms[ii],
                                    idata.freq, idata.chan_wid, avgvoverc);
         dtmp = subdispdt[cmd->nsub - 1];
         for (jj = 0; jj < cmd->nsub; jj++)
            offsets[ii][jj] = NEAREST_LONG((subdispdt[jj] - dtmp) / dsdt);
         vect_free(subdispdt);
      }

      /* Convert the bary TOAs to differences from the topo TOAs in */
      /* units of bin length (dt) rounded to the nearest integer.   */

      dtmp = (btoa[0] - ttoa[0]);
      for (ii = 0; ii < numbarypts; ii++)
         btoa[ii] = ((btoa[ii] - ttoa[ii]) - dtmp) * SECPERDAY / dsdt;

      /* Find the points where we need to add or remove bins */
      {
         int oldbin = 0, currentbin;
         double lobin, hibin, calcpt;

         numdiffbins = abs(NEAREST_LONG(btoa[numbarypts - 1])) + 1;
         diffbins = gen_ivect(numdiffbins);
         diffbinptr = diffbins;
         for (ii = 1; ii < numbarypts; ii++) {
            currentbin = NEAREST_LONG(btoa[ii]);
            if (currentbin != oldbin) {
               if (currentbin > 0) {
                  calcpt = oldbin + 0.5;
                  lobin = (ii - 1) * TDT / dsdt;
                  hibin = ii * TDT / dsdt;
               } else {
                  calcpt = oldbin - 0.5;
                  lobin = -((ii - 1) * TDT / dsdt);
                  hibin = -(ii * TDT / dsdt);
               }
               while (fabs(calcpt) < fabs(btoa[ii])) {
                  /* Negative bin number means remove that bin */
                  /* Positive bin number means add a bin there */
                  *diffbinptr =
                      NEAREST_LONG(LININTERP
                                  (calcpt, btoa[ii - 1], btoa[ii], lobin, hibin));
                  diffbinptr++;
                  calcpt = (currentbin > 0) ? calcpt + 1.0 : calcpt - 1.0;
               }
               oldbin = currentbin;
            }
         }
         *diffbinptr = cmd->numout; /* Used as a marker */
      }
      diffbinptr = diffbins;

      /* Now perform the barycentering */

      outdata = gen_fmatrix(local_numdms, worklen / cmd->downsamp);
      numread = get_data(outdata, blocksperread, &s, 
                         &obsmask, idispdt, offsets, &padding);

      while (numread == worklen) {      /* Loop to read and write the data */
         int numwritten = 0;
         double block_avg, block_var;

         numread /= cmd->downsamp;
         /* Determine the approximate local average */
         avg_var(outdata[0], numread, &block_avg, &block_var);
         if (myid == 0)
            print_percent_complete(totwrote, totnumtowrite);

         /* Simply write the data if we don't have to add or */
         /* remove any bins from this batch.                 */
         /* OR write the amount of data up to cmd->numout or */
         /* the next bin that will be added or removed.      */

         numtowrite = abs(*diffbinptr) - datawrote;
         if (cmd->numoutP && (totwrote + numtowrite) > cmd->numout)
            numtowrite = cmd->numout - totwrote;
         if (numtowrite > numread)
            numtowrite = numread;
         if (myid > 0) {
            write_data(outfiles, local_numdms, outdata, 0, numtowrite);
            /* Update the statistics */
            if (!padding) {
               for (ii = 0; ii < numtowrite; ii++)
                  update_stats(statnum + ii, outdata[0][ii], &min, &max, &avg, &var);
               statnum += numtowrite;
            }
         }
         datawrote += numtowrite;
         totwrote += numtowrite;
         numwritten += numtowrite;

         if ((datawrote == abs(*diffbinptr)) && 
             (numwritten != numread) && 
             (totwrote < cmd->numout)) {  /* Add/remove a bin */
            int skip, nextdiffbin;

            skip = numtowrite;

            /* Write the rest of the data after adding/removing a bin  */
            do {

               if (*diffbinptr > 0) {
                  /* Add a bin */
                  if (myid > 0)
                     write_padding(outfiles, local_numdms, block_avg, 1);
                  numadded++;
                  totwrote++;
               } else {
                  /* Remove a bin */
                  numremoved++;
                  datawrote++;
                  numwritten++;
                  skip++;
               }
               diffbinptr++;

               /* Write the part after the diffbin */

               numtowrite = numread - numwritten;
               if (cmd->numoutP && (totwrote + numtowrite) > cmd->numout)
                  numtowrite = cmd->numout - totwrote;
               nextdiffbin = abs(*diffbinptr) - datawrote;
               if (numtowrite > nextdiffbin)
                  numtowrite = nextdiffbin;
               if (myid > 0) {
                  write_data(outfiles, local_numdms, outdata, skip, numtowrite);
                  /* Update the statistics and counters */
                  if (!padding) {
                     for (ii = 0; ii < numtowrite; ii++)
                        update_stats(statnum + ii,
                                     outdata[0][skip + ii], &min, &max, &avg, &var);
                     statnum += numtowrite;
                  }
               }
               numwritten += numtowrite;
               datawrote += numtowrite;
               totwrote += numtowrite;
               skip += numtowrite;

               /* Stop if we have written out all the data we need to */

               if (cmd->numoutP && (totwrote == cmd->numout))
                  break;
            } while (numwritten < numread);
         }
         /* Stop if we have written out all the data we need to */

         if (cmd->numoutP && (totwrote == cmd->numout))
            break;

         numread = get_data(outdata, blocksperread, &s,
                            &obsmask, idispdt, offsets, &padding);
      }
   }

   if (myid > 0) {

      /* Calculate the amount of padding we need  */

      if (cmd->numoutP && (cmd->numout > totwrote))
         padwrote = padtowrite = cmd->numout - totwrote;

      /* Write the new info file for the output data */

      idata.dt = dsdt;
      update_infodata(&idata, totwrote, padtowrite, diffbins,
                      numdiffbins, cmd->downsamp);
      for (ii = 0; ii < local_numdms; ii++) {
         idata.dm = dms[ii];
         if (!cmd->nobaryP) {
            double baryepoch, barydispdt, baryhifreq;

            baryhifreq = idata.freq + (s.num_channels - 1) * idata.chan_wid;
            barydispdt = delay_from_dm(dms[ii], doppler(baryhifreq, avgvoverc));
            baryepoch = blotoa - (barydispdt / SECPERDAY);
            idata.bary = 1;
            idata.mjd_i = (int) floor(baryepoch);
            idata.mjd_f = baryepoch - idata.mjd_i;
         }
         sprintf(idata.name, "%s_DM%.2f", outfilenm, dms[ii]);
         writeinf(&idata);
      }

      /* Set the padded points equal to the average data point */

      if (idata.numonoff >= 1) {
         int index, startpad, endpad;

         for (ii = 0; ii < local_numdms; ii++) {
            fclose(outfiles[ii]);
            sprintf(datafilenm, "%s_DM%.2f.dat", outfilenm, dms[ii]);
            outfiles[ii] = chkfopen(datafilenm, "rb+");
         }
         for (ii = 0; ii < idata.numonoff; ii++) {
            index = 2 * ii;
            startpad = idata.onoff[index + 1];
            if (ii == idata.numonoff - 1)
               endpad = idata.N - 1;
            else
               endpad = idata.onoff[index + 2];
            for (jj = 0; jj < local_numdms; jj++)
               chkfseek(outfiles[jj], (startpad + 1) * sizeof(float), SEEK_SET);
            padtowrite = endpad - startpad;
            write_padding(outfiles, local_numdms, avg, padtowrite);
         }
      }
   }

   /* Print simple stats and results */

   var /= (datawrote - 1);
   if (myid == 0)
      print_percent_complete(1, 1);
   if (myid == 1) {
      printf("\n\nDone.\n\nSimple statistics of the output data:\n");
      printf("             Data points written:  %ld\n", totwrote);
      if (padwrote)
         printf("          Padding points written:  %ld\n", padwrote);
      if (!cmd->nobaryP) {
         if (numadded)
            printf("    Bins added for barycentering:  %d\n", numadded);
         if (numremoved)
            printf("  Bins removed for barycentering:  %d\n", numremoved);
      }
      printf("           Maximum value of data:  %.2f\n", max);
      printf("           Minimum value of data:  %.2f\n", min);
      printf("              Data average value:  %.2f\n", avg);
      printf("         Data standard deviation:  %.2f\n", sqrt(var));
      printf("\n");
   }

   /* Close the files and cleanup */

   if (cmd->maskfileP)
      free_mask(obsmask);
   if (myid > 0) {
      for (ii = 0; ii < local_numdms; ii++)
         fclose(outfiles[ii]);
      free(outfiles);
   }
   vect_free(outdata[0]);
   vect_free(outdata);
   vect_free(dms);
   free(hostname);
   vect_free(idispdt);
   vect_free(offsets[0]);
   vect_free(offsets);
   free(datafilenm);
   free(outfilenm);
   free(outpath);
   if (!cmd->nobaryP) {
      vect_free(btoa);
      vect_free(ttoa);
      vect_free(diffbins);
   }
   MPI_Finalize();
   return (0);
}
Example #2
0
int main(int argc, char *argv[])
{
   Cmdline *cmd;
   struct psrfits pfupper, pflower, pfo;
   fitsfile *infits, *outfits;
   char *pc1, *pc2;
   char outfilename[200];       //Name of outfile if not specified on command line
   int stat = 0, padding = 0, userN = 0, status;

   // Call usage() if we have no command line arguments
   if (argc == 1) {
      Program = argv[0];
      usage();
      exit(0);
   }
   // Parse the command line using the excellent program Clig
   cmd = parseCmdline(argc, argv);
   pfupper.tot_rows = pfupper.N = pfupper.T = pfupper.status = 0;       //Initialize upper band
   pflower.tot_rows = pflower.N = pflower.T = pflower.status = 0;       //Initialize lower band
   pfupper.filenum = pflower.filenum = 1;
   pfo.tot_rows = pfo.N = pfo.T = pfo.status = pfo.multifile = 0;       //Initialize output
   sprintf(pfupper.filename, cmd->argv[0]);     //Copy filename specified on command line to
   sprintf(pflower.filename, cmd->argv[0]);     //upper and lower bands, will correct filenames shortly
   if ((pc2 = strstr(pfupper.filename, "s1")) != NULL)  //Upper contains s1, change to s0
      strncpy(pc2, "s0", 2);
   else if ((pc2 = strstr(pflower.filename, "s0")) != NULL)     //Lower contains s0, change to s1
      strncpy(pc2, "s1", 2);
   else {
      printf("Unable to determine which sideband is which\n");
      exit(EXIT_FAILURE);
   }
   //Setting the name of the output file, setting as same name as input file, but removing s0/s1. 
   pc1 = strstr(pflower.filename, "s1");
   pc2 = strrchr(pflower.filename, '.');        //At '.fits'
   pc2--;
   while ((pc2 >= pflower.filename) && isdigit(*pc2))   //Move through the digits to the separation char.
      pc2--;
   strncpy(outfilename, pflower.filename, pc1 - pflower.filename);      //Copy everything up to s1 into outfilename
   strncpy(outfilename + (pc1 - pflower.filename), pc1 + 2, pc2 - pc1 - 2);     //Concatenate from after s1 to char before the separation char.
   pc1 = outfilename + (pc2 - pflower.filename - 2);
   *pc1 = 0;
   int rv = psrfits_open(&pfupper);   //Open upper band
   if (rv) {
      fits_report_error(stderr, rv);
      exit(1);
   }
   rv = psrfits_open(&pflower);       //Open lower band
   if (rv) {
      fits_report_error(stderr, rv);
      exit(1);
   }
   pfo = pflower;               //Copy all lower band variables into the output struct
   if (!cmd->outputbasenameP)
      sprintf(pfo.basefilename, basename(outfilename));
   else
      sprintf(pfo.basefilename, cmd->outputbasename);
   pfo.filenum = 0;
   sprintf(pfo.filename, "\0"); //Set filename to null so psrfits_open will create the filename for me
   pfo.rownum = 1;
   pfo.tot_rows = 0;
   pfo.N = 0;
   printf("lower rows_per_file=%d\n",pflower.rows_per_file);
   printf("upper rows_per_file=%d\n",pfupper.rows_per_file);
   if (pfupper.rows_per_file != pflower.rows_per_file) {        //Sanity check for the two input frequency bands
      fprintf(stderr, "rows_per_file in input files do not match!\n");
      exit(1);
   }

   double upperfreqoflower, nextfromlower, lowerfreqofupper, numchandiff;       //Used to find which frequencies to take from each band
   double offsetfactor, scalefactor;    //Factors which will be applied to offsets and scales
   int upchanskip, lowchanskip; //Number of channels to skip in each banda

   //Variables used to make code cleaner
   int extrachanoffset, outoffset, upperoffset, numtocopyupper, loweroffset_skip,
       loweroffset, numtocopylower, newuppernchan, newlowernchan;
   double df = pflower.hdr.df;
   int nchan = pflower.hdr.nchan;
   int outnchan;
   int npol = pflower.hdr.npol;
   int nbits = pflower.hdr.nbits;
   int nsblk = pflower.hdr.nsblk;
   //Allocate memory for all upper and lower data
   pflower.sub.dat_freqs = (double *) malloc(sizeof(double) * nchan);
   pflower.sub.dat_weights = (float *) malloc(sizeof(float) * nchan);
   pflower.sub.dat_offsets = (float *) malloc(sizeof(float) * nchan * npol);
   pflower.sub.dat_scales = (float *) malloc(sizeof(float) * nchan * npol);
   pflower.sub.rawdata = (unsigned char *) malloc(pflower.sub.bytes_per_subint);
   pflower.sub.data = (unsigned char *) malloc(pflower.sub.bytes_per_subint*2);

   pfupper.sub.dat_freqs = (double *) malloc(sizeof(double) * nchan);
   pfupper.sub.dat_weights = (float *) malloc(sizeof(float) * nchan);
   pfupper.sub.dat_offsets = (float *) malloc(sizeof(float) * nchan * npol);
   pfupper.sub.dat_scales = (float *) malloc(sizeof(float) * nchan * npol);
   pfupper.sub.rawdata = (unsigned char *) malloc(pfupper.sub.bytes_per_subint);
   pfupper.sub.data = (unsigned char *) malloc(pfupper.sub.bytes_per_subint*2);

   int firsttime = 1;           //First time through do while loop
   do {
      print_percent_complete(pflower.rownum, pflower.rows_per_file,
                             pflower.rownum == 1 ? 1 : 0);
      psrfits_read_subint(&pflower);
      psrfits_read_subint(&pfupper);
      if (firsttime) {          //First time through loop, calculate factors for scales and offsets and number of channels to skip
         firsttime = 0;
         //Find the number of channels in the upper band which will be skipped
         if (df < 0) {          //Find channel order, low to high or high to low
            upperfreqoflower = pflower.sub.dat_freqs[0];        //Highest frequency channel in lower band
            lowerfreqofupper = pfupper.sub.dat_freqs[nchan - 1];        //Lowest frequency channel in upper band
         } else {
            upperfreqoflower = pflower.sub.dat_freqs[nchan - 1];        //Highest frequency channel in lower band
            lowerfreqofupper = pfupper.sub.dat_freqs[0];        //Lowest frequency channel in upper band
         }
         nextfromlower = upperfreqoflower + fabs(df);   //Second highest channel in lower band
         numchandiff = (nextfromlower - lowerfreqofupper) / fabs(df);   //Number of channels to skip in float form
         int chanskip;
         if (numchandiff > 0) { //Make sure there are channels which need to be skipped
            if (numchandiff - (double) ((int) numchandiff) > .5)        // See whether we need to round up integer channels to skip
               chanskip = (int) numchandiff + 1;
            else
               chanskip = (int) numchandiff;
         } else
            chanskip = 0;       //No need to skip any channels
         if (chanskip % 2 == 1) {       //Odd number of channels, give lower band the extra channel
            upchanskip = chanskip / 2;
            lowchanskip = chanskip / 2 + 1;
         } else                 //Even number of channels to skip
            upchanskip = lowchanskip = chanskip / 2;
         if (upchanskip % 2 == 1) {     //We want an even number of channels in upper band for 4-bit data to get copied correctly
            ++lowchanskip;
            --upchanskip;
         }
         //Find new values given the number of channels skipped
         pfo.hdr.nchan = outnchan = nchan + nchan - chanskip + 2;       //New number of channels, plus 2 to make nchan=960 (many factors of 2)
         pfo.hdr.BW = (double) outnchan *fabs(df);      //New bandwidth
         pfo.hdr.fctr =         //New center frequency
             (pflower.hdr.fctr - (double) (nchan / 2) * fabs(df)) + pfo.hdr.BW / 2.0;
         pfo.sub.bytes_per_subint =     //Calculate new number of bytes in each subint
             outnchan * nsblk * nbits / 8 * npol;
         //Allocate space for output data now that we know the new number of channels
         pfo.sub.dat_freqs = (double *) malloc(sizeof(double) * outnchan);
         pfo.sub.dat_weights = (float *) malloc(sizeof(float) * outnchan);
         pfo.sub.dat_offsets = (float *) malloc(sizeof(float) * outnchan * npol);
         pfo.sub.dat_scales = (float *) malloc(sizeof(float) * outnchan * npol);
         pfo.sub.rawdata = (unsigned char *) malloc(pfo.sub.bytes_per_subint);
         pfo.sub.data = (unsigned char *) malloc(pfo.sub.bytes_per_subint*2);
         newuppernchan = nchan - upchanskip;    //The number of channels to copy from the upper sideband.
         newlowernchan = nchan - lowchanskip;   //The number of channels to copy from the lower sideband.

         extrachanoffset = 2;     //Offset for 2 extra freq channels making nchan 960 in bytes
         outoffset = (outnchan * npol);     //Offset in each loop due to previously written data
         upperoffset = (nchan * npol);      //Offset in loop for upper band
         numtocopyupper = (newuppernchan * npol);   //Number of bytes to copy from upper band
         loweroffset_skip = (lowchanskip * npol);   //Number of bytes to skip when copying lower band due to 
         //having written upper band
         loweroffset =          //Number of bytes to skip due to having written previous lower band data
             (nchan * npol);
         numtocopylower = (newlowernchan * npol);   //Number of bytes to copy from lower band
         float upmean, upvar, lowmean, lowvar;
         avg_var(pfupper.sub.dat_offsets + (nchan - upchanskip),              //Find the mean and variance of the upper band's offsets
                 upchanskip, &upmean, &upvar);
         printf("Upper offset stats: mean=%f variance=%f\n", upmean, upvar);
         avg_var(pflower.sub.dat_offsets, lowchanskip, &lowmean, &lowvar);      //Find the mean and variance of the lower band's offsets
         printf("Lower offset stats: mean=%f variance=%f\n", lowmean, lowvar);
         printf("Applying factor of %f to upper offsets\n", (lowmean / upmean));
         offsetfactor = lowmean / upmean;       //Set offset factor used to correct variance differences in the two bands
         avg_var(pfupper.sub.dat_scales + (nchan - upchanskip), //Find the mean and var. of the upper band's scales
                 upchanskip, &upmean, &upvar);
         printf("Upper scales stats: mean=%f variance=%f\n", upmean, upvar);
         avg_var(pflower.sub.dat_scales, lowchanskip, &lowmean, &lowvar);       //Find the mean and var. of the lower band's scales
         printf("Lower scales stats: mean=%f variance=%f\n", lowmean, lowvar);
         printf("Applying factor of %f to upper scales\n", (lowmean / upmean));
         scalefactor = lowmean / upmean;        //Set scale factor used to correct variance differences in the two bands
      }
      if (pflower.status == 0 && pfupper.status == 0) {
         //Copy info from the lower band subint struct to the output file's subint struct
         pfo.sub.tsubint = pflower.sub.tsubint;
         pfo.sub.offs = pflower.sub.offs;
         pfo.sub.lst = pflower.sub.lst;
         pfo.sub.ra = pflower.sub.ra;
         pfo.sub.dec = pflower.sub.dec;
         pfo.sub.glon = pflower.sub.glon;
         pfo.sub.glat = pflower.sub.glat;
         pfo.sub.feed_ang = pflower.sub.feed_ang;
         pfo.sub.pos_ang = pflower.sub.pos_ang;
         pfo.sub.par_ang = pflower.sub.par_ang;
         pfo.sub.tel_az = pflower.sub.tel_az;
         pfo.sub.tel_zen = pflower.sub.tel_zen;
         pfo.sub.FITS_typecode = pflower.sub.FITS_typecode;
         //Create variables to reduce column width of lines below
         double *dat_freqs = pfo.sub.dat_freqs;
         double *udat_freqs = pfupper.sub.dat_freqs;
         double *ldat_freqs = pflower.sub.dat_freqs;
         float *dat_weights = pfo.sub.dat_weights;
         float *udat_weights = pfupper.sub.dat_weights;
         float *ldat_weights = pflower.sub.dat_weights;
         float *dat_offsets = pfo.sub.dat_offsets;
         float *udat_offsets = pfupper.sub.dat_offsets;
         float *ldat_offsets = pflower.sub.dat_offsets;
         float *dat_scales = pfo.sub.dat_scales;
         float *udat_scales = pfupper.sub.dat_scales;
         float *ldat_scales = pflower.sub.dat_scales;
         unsigned char *data = pfo.sub.data;
         unsigned char *udata = pfupper.sub.data;
         unsigned char *ldata = pflower.sub.data;

         if (df < 0) {
            //Copy frequency labels
            dat_freqs[1] = udat_freqs[0] + fabs(df);    //Calculate the frequency labels
            dat_freqs[0] = dat_freqs[1] + fabs(df);     //for our two empty frequency channels
            int newuppernchan = nchan - upchanskip;     //The number of channels to copy from the upper band
            int newlowernchan = nchan - lowchanskip;    //The number of channels to copy from the lower band
            memcpy(dat_freqs + 2, udat_freqs, sizeof(double) * newuppernchan);   //Copy from the upper band, skipping first two chans.
            memcpy(dat_freqs + newuppernchan + 2,       //Copy from the lower band
                   ldat_freqs + lowchanskip, sizeof(double) * newlowernchan);
            //Copy weights
            dat_weights[0] = dat_weights[1] = 0;        //Set the weights of first two channels to 0, so they shouldn't be used in calculations
            memcpy(dat_weights + 2, udat_weights,       //Copy weights from the upper band
                   sizeof(float) * newuppernchan);
            memcpy(dat_weights + 2 + newuppernchan,     //Copy weights from the lower band
                   ldat_weights + lowchanskip, sizeof(float) * newlowernchan);
            //Copy offsets
            dat_offsets[0] = dat_offsets[1] =   //Set offsets of first two channels to the same as upper's first channel
                udat_offsets[0];        //(shouldn't matter since they should be ignored)
            int ii;
            for (ii = 0; ii < newuppernchan; ++ii)      //Apply offset factor to upper band
               udat_offsets[ii] = udat_offsets[ii] * (offsetfactor);
            memcpy(dat_offsets + 2 * npol, udat_offsets,        //Copy upper offsets
                   sizeof(float) * newuppernchan * npol);
            memcpy(dat_offsets + (newuppernchan + 2) * npol,    //Copy lower offsets
                   ldat_offsets + lowchanskip, sizeof(float) * newlowernchan * npol);
            //Copy scales
            for (ii = 0; ii < newuppernchan; ++ii)      //Apply scale factor to upper band
               udat_scales[ii] = udat_scales[ii] * (scalefactor);
            dat_scales[0] = dat_scales[1] = udat_scales[0];
            memcpy(dat_scales + 2 * npol, udat_scales,  //Copy upper scales
                   sizeof(float) * newuppernchan * npol);
            memcpy(dat_scales + (newuppernchan + 2) * npol,     //Copy lower scales
                   ldat_scales + lowchanskip, sizeof(float) * newlowernchan * npol);
            //Copy the data
            for (ii = 0; ii < nsblk; ++ii) {    //Loop through data copying into place
               memcpy(data + ii * outoffset + extrachanoffset,
                      udata + ii * upperoffset, numtocopyupper);
               memcpy(data + ii * outoffset + extrachanoffset +
                      numtocopyupper,
                      ldata + ii * loweroffset + loweroffset_skip, numtocopylower);
            }
            psrfits_write_subint(&pfo);
         } else {
         }
      }
   } while (pfo.rownum <= pfo.rows_per_file && pfupper.status==0 && pflower.status==0);
   printf("Closing file '%s'\n", pflower.filename);
   fits_close_file(pfupper.fptr, &status);
   printf("Closing file '%s'\n", pfupper.filename);
   fits_close_file(pflower.fptr, &status);
   if(pflower.status!=0||pfupper.status!=0)
   {
     fprintf(stderr,"An error occurred when combining the two Mock files!\n");
     if(pflower.status==108||pfupper.status==108)
       fprintf(stderr,"One or both of the files is incomplete.\n");
     exit(1);
   }
   exit(0);
}
int get_current_row(struct psrfits *pfi, struct subband_info *si) {
    static int firsttime = 1, num_pad_blocks = 0;
    static double last_offs, row_duration;
    double diff_offs, dnum_blocks;

    if (firsttime) {
        row_duration = pfi->sub.tsubint;
        last_offs = pfi->sub.offs-row_duration;
        firsttime = 0;
    }

    print_percent_complete(pfi->rownum, pfi->rows_per_file,
                           pfi->rownum==1 ? 1 : 0);

#if 0
    printf("row %d\n", pfi->rownum);
#endif

    if (num_pad_blocks==0) {  // Try to read the PSRFITS file

        // Read the current row of data
        psrfits_read_subint(pfi);
        diff_offs = pfi->sub.offs - last_offs;
        if (si->userwgts) // Always overwrite if using user weights
            memcpy(pfi->sub.dat_weights, si->userwgts,
                   pfi->hdr.nchan * sizeof(float));

        if (!TEST_CLOSE(diff_offs, row_duration) || pfi->status) {
            if (pfi->status) { // End of the files
                num_pad_blocks = 1;
            } else { // Missing row(s)
                dnum_blocks = diff_offs/row_duration - 1.0;
                num_pad_blocks = (int)(dnum_blocks + 1e-7);
                pfi->rownum--;   // Will re-read when no more padding
                pfi->tot_rows--; // Only count "real" rows towards tot_rows
#if 1
                printf("At row %d, found %d dropped rows.\n",
                       pfi->rownum, num_pad_blocks);
                printf("Adding a missing row (#%d) of padding to the subbands.\n",
                       pfi->tot_rows);
#endif
                pfi->N -= pfi->hdr.nsblk;  // Will be re-added below for padding
            }
            // Now fill the main part of si->fbuffer with the chan_avgs so that
            // it acts like a correctly read block (or row)
            fill_chans_with_avgs(si->buflen, si->bufwid,
                                 pfi->sub.fdata, si->chan_avgs);
        } else { // Return the row from the file
            // Compute the float representations of the data
            scale_and_offset_data(pfi, si->numunsigned);
            // Determine channel statistics
            get_chan_stats(pfi, si);
            last_offs = pfi->sub.offs;
            return 0;
        }
    }

    // Return the same padding as before
    last_offs += row_duration;
    pfi->N += pfi->hdr.nsblk;
    pfi->T = pfi->N * pfi->hdr.dt;
    num_pad_blocks--;
    return num_pad_blocks;
}
Example #4
0
int main(int argc, char *argv[])
{
   int ii;
   double ttim, utim, stim, tott;
   struct tms runtimes;
   subharminfo **subharminfs;
   accelobs obs;
   infodata idata;
   GSList *cands = NULL;
   Cmdline *cmd;

   /* 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("    Fourier-Domain Acceleration Search Routine\n");
   printf("               by Scott M. Ransom\n\n");

   /* Create the accelobs structure */
   create_accelobs(&obs, &idata, cmd, 1);

   /* Zap birdies if requested and if in memory */
   if (cmd->zaplistP && !obs.mmap_file && obs.fft) {
      int numbirds;
      double *bird_lobins, *bird_hibins, hibin;

      /* Read the Standard bird list */
      numbirds = get_birdies(cmd->zaplist, obs.T, cmd->baryv,
                             &bird_lobins, &bird_hibins);

      /* Zap the birdies */
      printf("Zapping them using a barycentric velocity of %.5gc.\n\n", cmd->baryv);
      hibin = obs.N / 2;
      for (ii = 0; ii < numbirds; ii++) {
         if (bird_lobins[ii] >= hibin)
            break;
         if (bird_hibins[ii] >= hibin)
            bird_hibins[ii] = hibin - 1;
         zapbirds(bird_lobins[ii], bird_hibins[ii], NULL, obs.fft);
      }

      free(bird_lobins);
      free(bird_hibins);
   }

   printf("Searching with up to %d harmonics summed:\n",
          1 << (obs.numharmstages - 1));
   printf("  f = %.1f to %.1f Hz\n", obs.rlo / obs.T, obs.rhi / obs.T);
   printf("  r = %.1f to %.1f Fourier bins\n", obs.rlo, obs.rhi);
   printf("  z = %.1f to %.1f Fourier bins drifted\n\n", obs.zlo, obs.zhi);

   /* Generate the correlation kernels */

   printf("Generating correlation kernels:\n");
   subharminfs = create_subharminfos(obs.numharmstages, (int) obs.zhi);
   printf("Done generating kernels.\n\n");
   printf("Starting the search.\n");
   /* Don't use the *.txtcand files on short in-memory searches */
   if (!obs.dat_input) {
      printf("  Working candidates in a test format are in '%s'.\n\n",
             obs.workfilenm);
   }

   /* Start the main search loop */

   {
      double startr = obs.rlo, lastr = 0, nextr = 0;
      ffdotpows *fundamental;

      while (startr + ACCEL_USELEN * ACCEL_DR < obs.highestbin) {
         /* Search the fundamental */
         print_percent_complete(startr - obs.rlo,
                                obs.highestbin - obs.rlo, "search", 0);
         nextr = startr + ACCEL_USELEN * ACCEL_DR;
         lastr = nextr - ACCEL_DR;
         fundamental = subharm_ffdot_plane(1, 1, startr, lastr,
                                           &subharminfs[0][0], &obs);
         cands = search_ffdotpows(fundamental, 1, &obs, cands);

         if (obs.numharmstages > 1) {   /* Search the subharmonics */
            int stage, harmtosum, harm;
            ffdotpows *subharmonic;

            for (stage = 1; stage < obs.numharmstages; stage++) {
               harmtosum = 1 << stage;
               for (harm = 1; harm < harmtosum; harm += 2) {
                  subharmonic = subharm_ffdot_plane(harmtosum, harm, startr, lastr,
                                                    &subharminfs[stage][harm - 1],
                                                    &obs);
                  add_ffdotpows(fundamental, subharmonic, harmtosum, harm);
                  free_ffdotpows(subharmonic);
               }
               cands = search_ffdotpows(fundamental, harmtosum, &obs, cands);
            }
         }
         free_ffdotpows(fundamental);
         startr = nextr;
      }
      print_percent_complete(obs.highestbin - obs.rlo,
                             obs.highestbin - obs.rlo, "search", 0);
   }

   printf("\n\nDone searching.  Now optimizing each candidate.\n\n");
   free_subharminfos(obs.numharmstages, subharminfs);

   {                            /* Candidate list trimming and optimization */
      int numcands;
      GSList *listptr;
      accelcand *cand;
      fourierprops *props;


      numcands = g_slist_length(cands);

      if (numcands) {

         /* Sort the candidates according to the optimized sigmas */

         cands = sort_accelcands(cands);

         /* Eliminate (most of) the harmonically related candidates */
         if ((cmd->numharm > 1) && !(cmd->noharmremoveP))
             eliminate_harmonics(cands, &numcands);

         /* Now optimize each candidate and its harmonics */

         print_percent_complete(0, 0, NULL, 1);
         listptr = cands;
         for (ii = 0; ii < numcands; ii++) {
            print_percent_complete(ii, numcands, "optimization", 0);
            cand = (accelcand *) (listptr->data);
            optimize_accelcand(cand, &obs);
            listptr = listptr->next;
         }
         print_percent_complete(ii, numcands, "optimization", 0);

         /* Calculate the properties of the fundamentals */

         props = (fourierprops *) malloc(sizeof(fourierprops) * numcands);
         listptr = cands;
         for (ii = 0; ii < numcands; ii++) {
            cand = (accelcand *) (listptr->data);
            /* In case the fundamental harmonic is not significant,  */
            /* send the originally determined r and z from the       */
            /* harmonic sum in the search.  Note that the derivs are */
            /* not used for the computations with the fundamental.   */
            calc_props(cand->derivs[0], cand->r, cand->z, 0.0, props + ii);
            /* Override the error estimates based on power */
            props[ii].rerr = (float) (ACCEL_DR) / cand->numharm;
            props[ii].zerr = (float) (ACCEL_DZ) / cand->numharm;
            listptr = listptr->next;
         }

         /* Write the fundamentals to the output text file */

         output_fundamentals(props, cands, &obs, &idata);

         /* Write the harmonics to the output text file */

         output_harmonics(cands, &obs, &idata);

         /* Write the fundamental fourierprops to the cand file */

         obs.workfile = chkfopen(obs.candnm, "wb");
         chkfwrite(props, sizeof(fourierprops), numcands, obs.workfile);
         fclose(obs.workfile);
         free(props);
         printf("\n\n");
      } else {
         printf("No candidates above sigma = %.2f were found.\n\n", obs.sigma);
      }
   }

   /* Finish up */

   printf("Searched the following approx numbers of independent points:\n");
   printf("  %d harmonic:   %9lld\n", 1, obs.numindep[0]);
   for (ii = 1; ii < obs.numharmstages; ii++)
      printf("  %d harmonics:  %9lld\n", 1 << ii, obs.numindep[ii]);

   printf("\nTiming 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("Final candidates in binary format are in '%s'.\n", obs.candnm);
   printf("Final Candidates in a text format are in '%s'.\n\n", obs.accelnm);

   free_accelobs(&obs);
   g_slist_foreach(cands, free_accelcand, NULL);
   g_slist_free(cands);
   return (0);
}