├── prepare ├── mpi_compile.sh ├── gpu_hostfile.txt ├── mpi_run.sh ├── README ├── polyco_struct.h ├── combine_mocks_cmd.cli ├── .gitignore ├── configure.ac ├── combine_mocks_cmd.h ├── test_psrfits_read.c ├── Makefile.am ├── polyco.h ├── psrfits_subband_cmd.cli ├── combine_mocks.1 ├── fold.h ├── find_dropped_blocks.c ├── psrfits_subband_cmd.h ├── psrfits_subband.1 ├── fix_psrfits_polyco.c ├── test_psrfits.c ├── downsample.c ├── psrfits.h ├── guppi_PSRFITS_v3.4_search_template.txt ├── misc_utils.c ├── config └── ax_pthread.m4 ├── polyco.c ├── combine_mocks.c ├── mpimerge_psrfits.c ├── fold.c ├── psrfits_singlepulse.c ├── read_psrfits.c ├── combine_mocks_cmd.c └── fold_psrfits.c /prepare: -------------------------------------------------------------------------------- 1 | #! /bin/csh 2 | autoreconf --install --force 3 | -------------------------------------------------------------------------------- /mpi_compile.sh: -------------------------------------------------------------------------------- 1 | mpicc -O3 -Wall -W -o mpimerge_psrfits mpimerge_psrfits.c -L/home/pulsar64/lib -lpsrfits_utils 2 | -------------------------------------------------------------------------------- /gpu_hostfile.txt: -------------------------------------------------------------------------------- 1 | localhost 2 | gpu1-10 3 | gpu2-10 4 | gpu3-10 5 | gpu4-10 6 | gpu5-10 7 | gpu6-10 8 | gpu7-10 9 | gpu8-10 10 | -------------------------------------------------------------------------------- /mpi_run.sh: -------------------------------------------------------------------------------- 1 | # Note: run as gpu! 2 | mpirun -np 9 --hostfile /home/pulsar64/src/psrfits_utils/gpu_hostfile.txt /home/pulsar64/src/psrfits_utils/mpimerge_psrfits guppi_55317_Terzan5_0003 3 | -------------------------------------------------------------------------------- /README: -------------------------------------------------------------------------------- 1 | psrfits_utils 2 | by P. Demorest, S. Ransom. 3 | 4 | psrfits_utils is a lightweight library for processing PSRFITS pulsar 5 | data files. 6 | 7 | To compile: 8 | ./prepare (should only be necessary the first time) 9 | ./configure [options] 10 | make && make install 11 | 12 | -------------------------------------------------------------------------------- /polyco_struct.h: -------------------------------------------------------------------------------- 1 | #ifndef _POLYCO_STRUCT_H 2 | #define _POLYCO_STRUCT_H 3 | struct polyco { 4 | char psr[15]; 5 | int mjd; 6 | double fmjd; 7 | long long rphase_int; 8 | double rphase; 9 | double f0; 10 | int nsite; 11 | int nmin; 12 | int nc; 13 | float rf; 14 | int used; 15 | double c[15]; 16 | }; 17 | #endif 18 | -------------------------------------------------------------------------------- /combine_mocks_cmd.cli: -------------------------------------------------------------------------------- 1 | Name combine_mocks 2 | 3 | Usage "\nCombine two frequency bands of Mock spectrometer data.\n" 4 | 5 | Version [exec date +%d%b%y] 6 | 7 | Commandline full_cmd_line 8 | 9 | # Options (in order you want them to appear) 10 | String -o outputbasename {Basename for the output files} 11 | 12 | 13 | # Rest of command line: 14 | Rest infile {Input file name(s) of the PSRFITs datafiles} \ 15 | -c 1 2000 16 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | .deps/ 2 | .libs/ 3 | *.o 4 | *.lo 5 | *.la 6 | *~ 7 | Makefile 8 | Makefile.in 9 | aclocal.m4 10 | autom4te.cache/ 11 | config.log 12 | config.status 13 | config/config.guess 14 | config/config.sub 15 | config/depcomp 16 | config/install-sh 17 | config/libtool.m4 18 | config/ltmain.sh 19 | config/ltoptions.m4 20 | config/ltsugar.m4 21 | config/ltversion.m4 22 | config/lt~obsolete.m4 23 | config/missing 24 | configure 25 | fold_psrfits 26 | libtool 27 | psrfits_singlepulse 28 | psrfits_subband 29 | mpimerge_psrfits 30 | find_dropped_blocks 31 | combine_mocks 32 | -------------------------------------------------------------------------------- /configure.ac: -------------------------------------------------------------------------------- 1 | AC_INIT([psrfits_utils], [1.0]) 2 | AC_CONFIG_SRCDIR([downsample.c]) 3 | AC_CONFIG_MACRO_DIR([config]) 4 | AC_CONFIG_AUX_DIR([config]) 5 | AM_INIT_AUTOMAKE([-Wall -Werror foreign]) 6 | 7 | m4_ifdef([AM_PROG_AR], [AM_PROG_AR]) 8 | AC_PROG_CC 9 | AC_PROG_LIBTOOL 10 | 11 | AX_PTHREAD 12 | 13 | AC_CHECK_LIB([m],[sin]) 14 | AC_CHECK_LIB([cfitsio],[ffgky],[], 15 | [AC_MSG_ERROR([cfitsio is required])]) 16 | 17 | AC_ARG_ENABLE([sse], 18 | [AS_HELP_STRING([--enable-sse], 19 | [enable SSE folding code])], 20 | [], 21 | [enable_sse=no]) 22 | if test "x$enable_sse" = "xyes"; then 23 | AC_DEFINE([FOLD_USE_INTRINSICS], [1], [Use SSE intrinsics for folding]) 24 | fi 25 | 26 | AC_CONFIG_FILES([Makefile]) 27 | AC_OUTPUT 28 | -------------------------------------------------------------------------------- /combine_mocks_cmd.h: -------------------------------------------------------------------------------- 1 | #ifndef __combine_mocks_cmd__ 2 | #define __combine_mocks_cmd__ 3 | /***** 4 | command line parser interface -- generated by clig 5 | (http://wsd.iitb.fhg.de/~geg/clighome/) 6 | 7 | The command line parser `clig': 8 | (C) 1995-2004 Harald Kirsch (clig@geggus.net) 9 | *****/ 10 | 11 | typedef struct s_Cmdline { 12 | /***** -o: Basename for the output files */ 13 | char outputbasenameP; 14 | char* outputbasename; 15 | int outputbasenameC; 16 | /***** uninterpreted command line parameters */ 17 | int argc; 18 | /*@null*/char **argv; 19 | /***** the whole command line concatenated */ 20 | char *full_cmd_line; 21 | } Cmdline; 22 | 23 | 24 | extern char *Program; 25 | extern void usage(void); 26 | extern /*@shared*/Cmdline *parseCmdline(int argc, char **argv); 27 | 28 | #endif 29 | 30 | -------------------------------------------------------------------------------- /test_psrfits_read.c: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include "fitsio.h" 4 | #include "psrfits.h" 5 | 6 | int main(int argc, char *argv[]) { 7 | struct psrfits pf; 8 | sprintf(pf.basefilename, 9 | "/data2/demorest/parspec/parspec_test_B0329+54_0009"); 10 | pf.filenum=1; 11 | int rv = psrfits_open(&pf); 12 | pf.sub.dat_freqs = (float *)malloc(sizeof(float) * pf.hdr.nchan); 13 | pf.sub.dat_weights = (float *)malloc(sizeof(float) * pf.hdr.nchan); 14 | pf.sub.dat_offsets = (float *)malloc(sizeof(float) 15 | * pf.hdr.nchan * pf.hdr.npol); 16 | pf.sub.dat_scales = (float *)malloc(sizeof(float) 17 | * pf.hdr.nchan * pf.hdr.npol); 18 | pf.sub.data = (unsigned char *)malloc(pf.sub.bytes_per_subint); 19 | while ((rv=psrfits_read_subint(&pf))==0) { 20 | printf("Read subint (file %d, row %d/%d)\n", 21 | pf.filenum, pf.rownum-1, pf.rows_per_file); 22 | } 23 | if (rv) { fits_report_error(stderr, rv); } 24 | exit(0); 25 | } 26 | -------------------------------------------------------------------------------- /Makefile.am: -------------------------------------------------------------------------------- 1 | ACLOCAL_AMFLAGS = -I config 2 | 3 | pkginclude_HEADERS = \ 4 | fold.h \ 5 | polyco.h \ 6 | polyco_struct.h \ 7 | psrfits.h 8 | 9 | noinst_HEADERS = 10 | 11 | dist_data_DATA = \ 12 | guppi_PSRFITS_v3.4_fold_template.txt \ 13 | guppi_PSRFITS_v3.4_search_template.txt 14 | 15 | lib_LTLIBRARIES = libpsrfits_utils.la 16 | libpsrfits_utils_la_SOURCES = \ 17 | downsample.c \ 18 | fold.c \ 19 | misc_utils.c \ 20 | polyco.c \ 21 | read_psrfits.c \ 22 | write_psrfits.c 23 | 24 | LDADD = libpsrfits_utils.la 25 | AM_CPPFLAGS = -DPSRFITS_TEMPLATE_DIR='"$(datadir)"' 26 | 27 | bin_PROGRAMS = fold_psrfits psrfits_singlepulse psrfits_subband combine_mocks 28 | 29 | fold_psrfits_CFLAGS = @PTHREAD_CFLAGS@ $(AM_CFLAGS) 30 | fold_psrfits_LDFLAGS = @PTHREAD_CFLAGS@ $(AM_LDFLAGS) 31 | fold_psrfits_LDADD = libpsrfits_utils.la @PTHREAD_LIBS@ 32 | 33 | psrfits_subband_SOURCES = psrfits_subband.c \ 34 | psrfits_subband_cmd.h psrfits_subband_cmd.c 35 | 36 | combine_mocks_SOURCES = combine_mocks.c \ 37 | combine_mocks_cmd.h combine_mocks_cmd.c 38 | -------------------------------------------------------------------------------- /polyco.h: -------------------------------------------------------------------------------- 1 | 2 | #ifndef _POLYCO_H 3 | #define _POLYCO_H 4 | 5 | #include 6 | #include 7 | 8 | #include "polyco_struct.h" 9 | 10 | int read_one_pc(FILE *f, struct polyco *pc); 11 | int read_pc(FILE *f, struct polyco *pc, const char *psr, int mjd, double fmjd); 12 | int read_all_pc(FILE *f, struct polyco **pc); 13 | int select_pc(const struct polyco *pc, int npc, const char *psr, 14 | int imjd, double fmjd); 15 | double psr_phase(const struct polyco *pc, int mjd, double fmjd, double *freq, 16 | long long *pulsenum); 17 | double psr_fdot(const struct polyco *pc, int mjd, double fmjd, double *fdot); 18 | double psr_phase_avg(const struct polyco *pc, int mjd, 19 | double fmjd1, double fmjd2); 20 | int pc_range_check(const struct polyco *pc, int mjd, double fmjd); 21 | int pc_out_of_range(const struct polyco *pc, int mjd, double fmjd); 22 | int pc_out_of_range_sloppy(const struct polyco *pc, int mjd, double fmjd, double slop); 23 | int polycos_differ(const struct polyco *pc1, const struct polyco *pc2); 24 | 25 | #include "psrfits.h" 26 | int make_polycos(const char *parfile, struct hdrinfo *hdr, char *src, 27 | struct polyco **pc); 28 | 29 | #endif 30 | -------------------------------------------------------------------------------- /psrfits_subband_cmd.cli: -------------------------------------------------------------------------------- 1 | Name psrfits_subband 2 | 3 | Usage "\nPartially de-disperse and subband PSRFITS search-mode data.\n" 4 | 5 | Version [exec date +%d%b%y] 6 | 7 | Commandline full_cmd_line 8 | 9 | # Options (in order you want them to appear) 10 | Double -dm dm {Dispersion measure to use for the subband de-dispersion} \ 11 | -r 0.0 10000.0 -d 0.0 12 | Int -nsub nsub {Number of output frequency subbands} \ 13 | -r 1 4096 14 | Int -dstime dstime {Power-of-2 number of samples to average in time} \ 15 | -r 1 128 -d 1 16 | Int -startfile startfile {Starting file number of sequence} \ 17 | -r 1 2000 -d 1 18 | Int -numfiles numfiles {Number of files to process} \ 19 | -r 1 2000 20 | Float -filetime filetime {Desired length of the resulting files in sec} \ 21 | -r 0.0 100000.0 22 | Float -filelen filelen {Desired length of the resulting files in GB} \ 23 | -r 0.0 1000.0 24 | Flag -bytes bytes {Make the raw data unsigned chars instead of signed shorts} 25 | Flag -onlyI onlyI {Only output total intensity data} 26 | String -weights wgtsfile {Filename containing ASCII list of channels and weights to use} 27 | String -o outputbasename {Basename for the output files} 28 | # Rest of command line: 29 | Rest infile {Input file name(s) of the PSRFITs datafiles} \ 30 | -c 1 2000 31 | -------------------------------------------------------------------------------- /combine_mocks.1: -------------------------------------------------------------------------------- 1 | .\" clig manual page template 2 | .\" (C) 1995-2004 Harald Kirsch (clig@geggus.net) 3 | .\" 4 | .\" This file was generated by 5 | .\" clig -- command line interface generator 6 | .\" 7 | .\" 8 | .\" Clig will always edit the lines between pairs of `cligPart ...', 9 | .\" but will not complain, if a pair is missing. So, if you want to 10 | .\" make up a certain part of the manual page by hand rather than have 11 | .\" it edited by clig, remove the respective pair of cligPart-lines. 12 | .\" 13 | .\" cligPart TITLE 14 | .TH "combine_mocks" 1 "14Feb11" "Clig-manuals" "Programmer's Manual" 15 | .\" cligPart TITLE end 16 | 17 | .\" cligPart NAME 18 | .SH NAME 19 | combine_mocks \- 20 | Combine two frequency bands of Mock spectrometer data. 21 | 22 | .\" cligPart NAME end 23 | 24 | .\" cligPart SYNOPSIS 25 | .SH SYNOPSIS 26 | .B combine_mocks 27 | [-o outputbasename] 28 | infile ... 29 | .\" cligPart SYNOPSIS end 30 | 31 | .\" cligPart OPTIONS 32 | .SH OPTIONS 33 | .IP -o 34 | Basename for the output files, 35 | .br 36 | 1 String value 37 | .IP infile 38 | Input file name(s) of the PSRFITs datafiles. 39 | .\" cligPart OPTIONS end 40 | 41 | .\" cligPart DESCRIPTION 42 | .SH DESCRIPTION 43 | This manual page was generated automagically by clig, the 44 | Command Line Interface Generator. Actually the programmer 45 | using clig was supposed to edit this part of the manual 46 | page after 47 | generating it with clig, but obviously (s)he didn't. 48 | 49 | Sadly enough clig does not yet have the power to pick a good 50 | program description out of blue air ;-( 51 | .\" cligPart DESCRIPTION end 52 | -------------------------------------------------------------------------------- /fold.h: -------------------------------------------------------------------------------- 1 | #ifndef _FOLD_H 2 | #define _FOLD_H 3 | #include "polyco.h" 4 | 5 | struct foldbuf { 6 | int nbin; 7 | int nchan; 8 | int npol; 9 | float *data; 10 | unsigned *count; 11 | }; 12 | 13 | void malloc_foldbuf(struct foldbuf *f); 14 | 15 | void free_foldbuf(struct foldbuf *f); 16 | 17 | void clear_foldbuf(struct foldbuf *f); 18 | 19 | size_t foldbuf_data_size(const struct foldbuf *f); 20 | size_t foldbuf_count_size(const struct foldbuf *f); 21 | 22 | int normalize_transpose_folds(float *out, const struct foldbuf *f); 23 | 24 | struct fold_args { 25 | struct polyco *pc; 26 | int imjd; 27 | double fmjd; 28 | char *data; 29 | int nsamp; 30 | double tsamp; 31 | int raw_signed; 32 | struct foldbuf *fb; 33 | float *scale; 34 | float *offset; 35 | }; 36 | 37 | void *fold_8bit_power_thread(void *_args); 38 | 39 | int fold_8bit_power(const struct polyco *pc, int imjd, double fmjd, 40 | const char *data, int nsamp, double tsamp, int raw_signed, 41 | struct foldbuf *f); 42 | 43 | void *fold_16bit_power_thread(void *_args); 44 | 45 | int fold_16bit_power(const struct polyco *pc, int imjd, double fmjd, 46 | const int16_t *data, int nsamp, double tsamp, int raw_signed, 47 | struct foldbuf *f); 48 | 49 | void *fold_float_power_thread(void *_args); 50 | 51 | int fold_float_power(const struct polyco *pc, int imjd, double fmjd, 52 | const float *data, int nsamp, double tsamp, 53 | struct foldbuf *f); 54 | 55 | int scale_offset_folds(struct foldbuf *f, 56 | const float *scale, const float *offset); 57 | 58 | int accumulate_folds(struct foldbuf *ftot, const struct foldbuf *f); 59 | 60 | #endif 61 | -------------------------------------------------------------------------------- /find_dropped_blocks.c: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | #include "fitsio.h" 5 | 6 | // This tests to see if 2 times are within 100ns of each other 7 | #define TEST_CLOSE(a, b) (fabs((a)-(b)) <= 1e-7 ? 1 : 0) 8 | 9 | int main(int argc, char *argv[]) { 10 | fitsfile *pf; 11 | double offs, last_offs, diff_offs, num_blocks, row_duration; 12 | int ii, firsttime = 1, filenum = 1, status = 0, anynull = 0; 13 | long nrows, row = 1; 14 | char filename[100]; 15 | 16 | while (1) { 17 | sprintf(filename, "%s_%04d.fits", argv[1], filenum); 18 | fits_open_file(&pf, filename, READONLY, &status); 19 | if (status) break; 20 | fits_movabs_hdu(pf, 2, NULL, &status); 21 | fits_get_num_rows(pf, &nrows, &status); 22 | printf("Working on '%s' with %ld rows\n", filename, nrows); 23 | row = 1; 24 | for (ii = 1 ; ii <= nrows ; ii++) { 25 | if (firsttime) { 26 | fits_read_col(pf, TDOUBLE, 1, row, 1, 1, 27 | 0, &row_duration, &anynull, &status); 28 | last_offs = -0.5*row_duration; 29 | firsttime = 0; 30 | } 31 | fits_read_col(pf, TDOUBLE, 2, row, 1, 1, 32 | 0, &offs, &anynull, &status); 33 | diff_offs = offs - last_offs; 34 | if (!TEST_CLOSE(diff_offs, row_duration)) { 35 | num_blocks = diff_offs/row_duration; 36 | printf("At row %ld, found %.3f dropped rows.\n", 37 | row, num_blocks); 38 | } 39 | last_offs = offs; 40 | row++; 41 | } 42 | filenum++; 43 | printf(" checked %d rows.\n", row-1); 44 | fits_close_file(pf, &status); 45 | } 46 | if (status != 104) // 104 is file could not be opened or some such 47 | printf("Exited with status = %d\n", status); 48 | exit(0); 49 | } 50 | -------------------------------------------------------------------------------- /psrfits_subband_cmd.h: -------------------------------------------------------------------------------- 1 | #ifndef __psrfits_subband_cmd__ 2 | #define __psrfits_subband_cmd__ 3 | /***** 4 | command line parser interface -- generated by clig 5 | (http://wsd.iitb.fhg.de/~geg/clighome/) 6 | 7 | The command line parser `clig': 8 | (C) 1995-2004 Harald Kirsch (clig@geggus.net) 9 | *****/ 10 | 11 | typedef struct s_Cmdline { 12 | /***** -dm: Dispersion measure to use for the subband de-dispersion */ 13 | char dmP; 14 | double dm; 15 | int dmC; 16 | /***** -nsub: Number of output frequency subbands */ 17 | char nsubP; 18 | int nsub; 19 | int nsubC; 20 | /***** -dstime: Power-of-2 number of samples to average in time */ 21 | char dstimeP; 22 | int dstime; 23 | int dstimeC; 24 | /***** -startfile: Starting file number of sequence */ 25 | char startfileP; 26 | int startfile; 27 | int startfileC; 28 | /***** -numfiles: Number of files to process */ 29 | char numfilesP; 30 | int numfiles; 31 | int numfilesC; 32 | /***** -filetime: Desired length of the resulting files in sec */ 33 | char filetimeP; 34 | float filetime; 35 | int filetimeC; 36 | /***** -filelen: Desired length of the resulting files in GB */ 37 | char filelenP; 38 | float filelen; 39 | int filelenC; 40 | /***** -bytes: Make the raw data unsigned chars instead of signed shorts */ 41 | char bytesP; 42 | /***** -onlyI: Only output total intensity data */ 43 | char onlyIP; 44 | /***** -weights: Filename containing ASCII list of channels and weights to use */ 45 | char wgtsfileP; 46 | char* wgtsfile; 47 | int wgtsfileC; 48 | /***** -o: Basename for the output files */ 49 | char outputbasenameP; 50 | char* outputbasename; 51 | int outputbasenameC; 52 | /***** uninterpreted command line parameters */ 53 | int argc; 54 | /*@null*/char **argv; 55 | /***** the whole command line concatenated */ 56 | char *full_cmd_line; 57 | } Cmdline; 58 | 59 | 60 | extern char *Program; 61 | extern void usage(void); 62 | extern /*@shared*/Cmdline *parseCmdline(int argc, char **argv); 63 | 64 | #endif 65 | 66 | -------------------------------------------------------------------------------- /psrfits_subband.1: -------------------------------------------------------------------------------- 1 | .\" clig manual page template 2 | .\" (C) 1995-2004 Harald Kirsch (clig@geggus.net) 3 | .\" 4 | .\" This file was generated by 5 | .\" clig -- command line interface generator 6 | .\" 7 | .\" 8 | .\" Clig will always edit the lines between pairs of `cligPart ...', 9 | .\" but will not complain, if a pair is missing. So, if you want to 10 | .\" make up a certain part of the manual page by hand rather than have 11 | .\" it edited by clig, remove the respective pair of cligPart-lines. 12 | .\" 13 | .\" cligPart TITLE 14 | .TH "psrfits_subband" 1 "04Mar11" "Clig-manuals" "Programmer's Manual" 15 | .\" cligPart TITLE end 16 | 17 | .\" cligPart NAME 18 | .SH NAME 19 | psrfits_subband \- 20 | Partially de-disperse and subband PSRFITS search-mode data. 21 | 22 | .\" cligPart NAME end 23 | 24 | .\" cligPart SYNOPSIS 25 | .SH SYNOPSIS 26 | .B psrfits_subband 27 | [-dm dm] 28 | [-nsub nsub] 29 | [-dstime dstime] 30 | [-startfile startfile] 31 | [-numfiles numfiles] 32 | [-filetime filetime] 33 | [-filelen filelen] 34 | [-bytes] 35 | [-onlyI] 36 | [-weights wgtsfile] 37 | [-o outputbasename] 38 | infile ... 39 | .\" cligPart SYNOPSIS end 40 | 41 | .\" cligPart OPTIONS 42 | .SH OPTIONS 43 | .IP -dm 44 | Dispersion measure to use for the subband de-dispersion, 45 | .br 46 | 1 Double value between 0.0 and 10000.0. 47 | .br 48 | Default: `0.0' 49 | .IP -nsub 50 | Number of output frequency subbands, 51 | .br 52 | 1 Int value between 1 and 4096. 53 | .IP -dstime 54 | Power-of-2 number of samples to average in time, 55 | .br 56 | 1 Int value between 1 and 128. 57 | .br 58 | Default: `1' 59 | .IP -startfile 60 | Starting file number of sequence, 61 | .br 62 | 1 Int value between 1 and 2000. 63 | .br 64 | Default: `1' 65 | .IP -numfiles 66 | Number of files to process, 67 | .br 68 | 1 Int value between 1 and 2000. 69 | .IP -filetime 70 | Desired length of the resulting files in sec, 71 | .br 72 | 1 Float value between 0.0 and 100000.0. 73 | .IP -filelen 74 | Desired length of the resulting files in GB, 75 | .br 76 | 1 Float value between 0.0 and 1000.0. 77 | .IP -bytes 78 | Make the raw data unsigned chars instead of signed shorts. 79 | .IP -onlyI 80 | Only output total intensity data. 81 | .IP -weights 82 | Filename containing ASCII list of channels and weights to use, 83 | .br 84 | 1 String value 85 | .IP -o 86 | Basename for the output files, 87 | .br 88 | 1 String value 89 | .IP infile 90 | Input file name(s) of the PSRFITs datafiles. 91 | .\" cligPart OPTIONS end 92 | 93 | .\" cligPart DESCRIPTION 94 | .SH DESCRIPTION 95 | This manual page was generated automagically by clig, the 96 | Command Line Interface Generator. Actually the programmer 97 | using clig was supposed to edit this part of the manual 98 | page after 99 | generating it with clig, but obviously (s)he didn't. 100 | 101 | Sadly enough clig does not yet have the power to pick a good 102 | program description out of blue air ;-( 103 | .\" cligPart DESCRIPTION end 104 | -------------------------------------------------------------------------------- /fix_psrfits_polyco.c: -------------------------------------------------------------------------------- 1 | /* fix_psrfits_polyco.c 2 | * 3 | * Install missing polycos into a psrfits file. 4 | */ 5 | #include 6 | #include 7 | #include 8 | #include 9 | #include 10 | #include 11 | #include "polyco.h" 12 | #include "psrfits.h" 13 | 14 | int main(int argc, char *argv[]) { 15 | 16 | /* cmd line */ 17 | static struct option long_opts[] = { 18 | {"parfile", 1, NULL, 'P'}, 19 | {0,0,0,0} 20 | }; 21 | int opt, opti; 22 | char parfile[256]=""; 23 | while ((opt=getopt_long(argc,argv,"P:",long_opts,&opti))!=-1) { 24 | switch (opt) { 25 | case 'P': 26 | strncpy(parfile, optarg, 255); 27 | parfile[255]='\0'; 28 | break; 29 | default: 30 | exit(0); 31 | break; 32 | } 33 | } 34 | if (optind==argc) { 35 | fprintf(stderr, "No files given.\n"); 36 | exit(1); 37 | } 38 | if (parfile[0]=='\0') { 39 | fprintf(stderr, "No .par file given.\n"); 40 | exit(1); 41 | } 42 | 43 | int i, rv; 44 | struct psrfits pf; 45 | struct polyco *pc=NULL; 46 | for (i=optind; i 2 | #include 3 | #include 4 | #include 5 | #include "psrfits.h" 6 | #include "slalib.h" 7 | 8 | #ifndef DEGTORAD 9 | #define DEGTORAD 0.017453292519943295769236907684886127134428718885417 10 | #endif 11 | #ifndef RADTODEG 12 | #define RADTODEG 57.29577951308232087679815481410517033240547246656 13 | #endif 14 | 15 | void dec2hms(char *out, double in, int sflag) { 16 | int sign = 1; 17 | char *ptr = out; 18 | int h, m; 19 | double s; 20 | if (in<0.0) { sign = -1; in = fabs(in); } 21 | h = (int)in; in -= (double)h; in *= 60.0; 22 | m = (int)in; in -= (double)m; in *= 60.0; 23 | s = in; 24 | if (sign==1 && sflag) { *ptr='+'; ptr++; } 25 | else if (sign==-1) { *ptr='-'; ptr++; } 26 | sprintf(ptr, "%2.2d:%2.2d:%07.4f", h, m, s); 27 | } 28 | 29 | int main(int argc, char *argv[]) { 30 | int ii; 31 | double dtmp; 32 | struct psrfits pf; 33 | 34 | // Only set the basefilename and not "filename" 35 | // Also, fptr will be set by psrfits_create_searchmode() 36 | 37 | strcpy(pf.basefilename, "test_psrfits"); 38 | pf.filenum = 0; // This is the crucial one to set to initialize things 39 | pf.rows_per_file = 200; // Need to set this based on PSRFITS_MAXFILELEN 40 | 41 | // Now set values for our hdrinfo structure 42 | pf.hdr.scanlen = 5; // in sec 43 | strcpy(pf.hdr.observer, "John Doe"); 44 | strcpy(pf.hdr.source, "Cool PSR A"); 45 | strcpy(pf.hdr.frontend, "L-band"); 46 | strcpy(pf.hdr.project_id, "GBT09A-001"); 47 | strcpy(pf.hdr.date_obs, "2010-01-01T05:15:30.000"); 48 | strcpy(pf.hdr.poln_type, "LIN"); 49 | strcpy(pf.hdr.track_mode, "TRACK"); 50 | strcpy(pf.hdr.cal_mode, "OFF"); 51 | strcpy(pf.hdr.feed_mode, "FA"); 52 | pf.hdr.dt = 0.000050; 53 | pf.hdr.fctr = 1400.0; 54 | pf.hdr.BW = 800.0; 55 | pf.hdr.ra2000 = 302.0876876; 56 | dec2hms(pf.hdr.ra_str, pf.hdr.ra2000/15.0, 0); 57 | pf.hdr.dec2000 = -3.456987698; 58 | dec2hms(pf.hdr.dec_str, pf.hdr.dec2000, 1); 59 | pf.hdr.azimuth = 123.123; 60 | pf.hdr.zenith_ang = 23.0; 61 | pf.hdr.beam_FWHM = 0.25; 62 | pf.hdr.start_lst = 10000.0; 63 | pf.hdr.start_sec = 25000.82736876; 64 | pf.hdr.start_day = 55000; 65 | pf.hdr.scan_number = 3; 66 | pf.hdr.rcvr_polns = 2; 67 | pf.hdr.summed_polns = 1; 68 | pf.hdr.offset_subint = 0; 69 | pf.hdr.nchan = 1024; 70 | pf.hdr.orig_nchan = pf.hdr.nchan; 71 | pf.hdr.orig_df = pf.hdr.df = pf.hdr.BW / pf.hdr.nchan; 72 | pf.hdr.nbits = 8; 73 | pf.hdr.npol = 1; 74 | pf.hdr.nsblk = 10000; 75 | pf.hdr.MJD_epoch = 55555.123123123123123123L; // Note the "L" for long double 76 | 77 | // Now set values for our subint structure 78 | pf.sub.tsubint = pf.hdr.nsblk * pf.hdr.dt; 79 | pf.sub.offs = (pf.tot_rows + 0.5) * pf.sub.tsubint; 80 | pf.sub.lst = pf.hdr.start_lst; 81 | pf.sub.ra = pf.hdr.ra2000; 82 | pf.sub.dec = pf.hdr.dec2000; 83 | slaEqgal(pf.hdr.ra2000*DEGTORAD, pf.hdr.dec2000*DEGTORAD, 84 | &pf.sub.glon, &pf.sub.glat); 85 | pf.sub.glon *= RADTODEG; 86 | pf.sub.glat *= RADTODEG; 87 | pf.sub.feed_ang = 0.0; 88 | pf.sub.pos_ang = 0.0; 89 | pf.sub.par_ang = 0.0; 90 | pf.sub.tel_az = pf.hdr.azimuth; 91 | pf.sub.tel_zen = pf.hdr.zenith_ang; 92 | pf.sub.bytes_per_subint = (pf.hdr.nbits * pf.hdr.nchan * 93 | pf.hdr.npol * pf.hdr.nsblk) / 8; 94 | pf.sub.FITS_typecode = TBYTE; // 11 = byte 95 | 96 | // Create and initialize the subint arrays 97 | pf.sub.dat_freqs = (float *)malloc(sizeof(float) * pf.hdr.nchan); 98 | pf.sub.dat_weights = (float *)malloc(sizeof(float) * pf.hdr.nchan); 99 | dtmp = pf.hdr.fctr - 0.5 * pf.hdr.BW + 0.5 * pf.hdr.df; 100 | for (ii = 0 ; ii < pf.hdr.nchan ; ii++) { 101 | pf.sub.dat_freqs[ii] = dtmp + ii * pf.hdr.df; 102 | pf.sub.dat_weights[ii] = 1.0; 103 | } 104 | pf.sub.dat_offsets = (float *)malloc(sizeof(float) * pf.hdr.nchan * pf.hdr.npol); 105 | pf.sub.dat_scales = (float *)malloc(sizeof(float) * pf.hdr.nchan * pf.hdr.npol); 106 | for (ii = 0 ; ii < pf.hdr.nchan * pf.hdr.npol ; ii++) { 107 | pf.sub.dat_offsets[ii] = 0.0; 108 | pf.sub.dat_scales[ii] = 1.0; 109 | } 110 | 111 | 112 | // This is what you would update for each time sample (likely just 113 | // adjusting the pointer to point to your data) 114 | pf.sub.data = (unsigned char *)malloc(pf.sub.bytes_per_subint); 115 | for (ii = 0 ; ii < pf.sub.bytes_per_subint ; ii++) { 116 | pf.sub.data[ii] = ii % 256; 117 | } 118 | 119 | // Here is the real data-writing loop 120 | do { 121 | // Update the pf.sub entries here for each subint 122 | // as well as the pf.sub.data pointer 123 | psrfits_write_subint(&pf); 124 | } while (pf.T < pf.hdr.scanlen && !pf.status); 125 | 126 | // Close the last file and cleanup 127 | fits_close_file(pf.fptr, &(pf.status)); 128 | free(pf.sub.dat_freqs); 129 | free(pf.sub.dat_weights); 130 | free(pf.sub.dat_offsets); 131 | free(pf.sub.dat_scales); 132 | free(pf.sub.data); 133 | 134 | printf("Done. Wrote %d subints (%f sec) in %d files. status = %d\n", 135 | pf.tot_rows, pf.T, pf.filenum, pf.status); 136 | 137 | exit(0); 138 | } 139 | -------------------------------------------------------------------------------- /downsample.c: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include "psrfits.h" 4 | 5 | // TODO: for these to work with OpenMP, we probably need 6 | // separate input and output arrays and then a copy. 7 | // Otherwise, the threads will step on each other. 8 | 9 | void convert_4bit_to_8bit(unsigned char *indata, unsigned char *outdata, int N) 10 | // This converts 4-bit indata to 8-bit outdata 11 | // N is the total number of data points 12 | { 13 | int ii; 14 | unsigned char uctmp; 15 | 16 | // Convert all the data from 4-bit to 8-bit 17 | for (ii = 0 ; ii < N / 2 ; ii++, indata++) { 18 | uctmp = *indata; 19 | *outdata++ = uctmp >> 4; // 1st 4 bits (MSBs) are first nibble 20 | *outdata++ = uctmp & 0x0F; // 2nd 4 bits (LSBs) are second nibble 21 | } 22 | } 23 | 24 | 25 | void pf_4bit_to_8bit(struct psrfits *pf) 26 | // This converts 4-bit pf->sub.rawdata to 8-bit pf->sub.data 27 | { 28 | convert_4bit_to_8bit((unsigned char *)pf->sub.rawdata, 29 | (unsigned char *)pf->sub.data, 30 | pf->sub.bytes_per_subint * 2); 31 | } 32 | 33 | 34 | void convert_8bit_to_4bit(unsigned char *indata, unsigned char *outdata, int N) 35 | // This converts 8-bit indata to 4-bit outdata 36 | // N is the total number of data points 37 | { 38 | int ii; 39 | 40 | // Convert all the data from 4-bit to 8-bit 41 | for (ii = 0 ; ii < N / 2 ; ii++, outdata++) { 42 | *outdata = *indata++ << 4; // 1st 4 bits (MSBs) are first point 43 | *outdata += *indata++; // 2nd 4 bits (LSBs) are second point 44 | } 45 | } 46 | 47 | 48 | void pf_8bit_to_4bit(struct psrfits *pf) 49 | // This converts 8-bit pf->sub.data into 4-bit pf->sub.rawdata 50 | { 51 | long long numoutsamp = pf->sub.bytes_per_subint * 2 / \ 52 | (pf->hdr.ds_time_fact * pf->hdr.ds_freq_fact); 53 | convert_8bit_to_4bit((unsigned char *)pf->sub.data, 54 | (unsigned char *)pf->sub.rawdata, 55 | numoutsamp); 56 | } 57 | 58 | 59 | void get_stokes_I(struct psrfits *pf) 60 | /* Move the Stokes I in place so that it is consecutive in the array */ 61 | { 62 | int ii; 63 | float *data; 64 | struct hdrinfo *hdr = &(pf->hdr); 65 | const int out_nchan = hdr->nchan / hdr->ds_freq_fact; 66 | 67 | // In this mode, average the polns first to make it like IQUV 68 | if (strncmp(hdr->poln_order, "AABBCRCI", 8)==0) { 69 | float *bbptr; 70 | int jj; 71 | for (ii = 0 ; ii < hdr->nsblk ; ii++) { 72 | data = pf->sub.fdata + ii * out_nchan * 4; // 4 polns 73 | bbptr = data + out_nchan; 74 | for (jj = 0 ; jj < out_nchan ; jj++, data++, bbptr++) 75 | *data = 0.5 * (*data + *bbptr); // Average AA and BB polns 76 | } 77 | } 78 | data = pf->sub.fdata; 79 | // Start from 1 since we don't need to move the 1st spectra 80 | for (ii = 1 ; ii < hdr->nsblk ; ii++) { 81 | memcpy(data + ii * out_nchan, 82 | data + ii * 4 * out_nchan, 83 | out_nchan * sizeof(float)); 84 | } 85 | } 86 | 87 | 88 | void downsample_time(struct psrfits *pf) 89 | /* Average adjacent time samples together in place */ 90 | /* This should be called _after_ make_subbands() */ 91 | { 92 | int ii, jj, kk; 93 | struct hdrinfo *hdr = &(pf->hdr); 94 | float *data = pf->sub.fdata; 95 | float *indata, *outdata, *tmpspec; 96 | const int dsfact = hdr->ds_time_fact; 97 | // Treat the polns as being parts of the same spectrum 98 | int out_npol = hdr->npol; 99 | if (hdr->onlyI) out_npol = 1; 100 | const int in_nchan = hdr->nchan * out_npol; 101 | const int out_nchan = in_nchan / hdr->ds_freq_fact; 102 | const int out_nsblk = hdr->nsblk / dsfact; 103 | const float norm = 1.0 / dsfact; 104 | 105 | tmpspec = (float *)malloc(out_nchan * sizeof(float)); 106 | indata = data; 107 | // Iterate over the output times 108 | for (ii = 0 ; ii < out_nsblk ; ii++) { 109 | // Initiaize the summation 110 | for (jj = 0 ; jj < out_nchan ; jj++) 111 | tmpspec[jj] = 0.0; 112 | // Add up the samples in time in the tmp array 113 | for (jj = 0 ; jj < dsfact ; jj++) { 114 | outdata = tmpspec; 115 | for (kk = 0 ; kk < out_nchan ; kk++, indata++, outdata++) 116 | *outdata += *indata; 117 | } 118 | // Convert the sum to an average and put into the output array 119 | outdata = data + ii * out_nchan; 120 | for (jj = 0 ; jj < out_nchan ; jj++) 121 | outdata[jj] = tmpspec[jj] * norm; 122 | } 123 | free(tmpspec); 124 | } 125 | 126 | 127 | void guppi_update_ds_params(struct psrfits *pf) 128 | /* Update the various output data arrays / values so that */ 129 | /* they are correct for the downsampled data. */ 130 | { 131 | struct hdrinfo *hdr = &(pf->hdr); 132 | struct subint *sub = &(pf->sub); 133 | 134 | int out_npol = hdr->npol; 135 | if (hdr->onlyI) out_npol = 1; 136 | int out_nchan = hdr->nchan / hdr->ds_freq_fact; 137 | 138 | if (hdr->ds_freq_fact > 1) { 139 | int ii; 140 | double dtmp; 141 | 142 | /* Note: we don't need to malloc the subint arrays since */ 143 | /* their original values are longer by default. */ 144 | 145 | // The following correctly accounts for the middle-of-bin FFT offset 146 | dtmp = hdr->fctr - 0.5 * hdr->BW; 147 | dtmp += 0.5 * (hdr->ds_freq_fact - 1.0) * hdr->df; 148 | for (ii = 0 ; ii < out_nchan ; ii++) 149 | sub->dat_freqs[ii] = dtmp + ii * (hdr->df * hdr->ds_freq_fact); 150 | 151 | for (ii = 1 ; ii < out_npol ; ii++) { 152 | memcpy(sub->dat_offsets+ii*out_nchan, 153 | sub->dat_offsets+ii*hdr->nchan, 154 | sizeof(float)*out_nchan); 155 | memcpy(sub->dat_scales+ii*out_nchan, 156 | sub->dat_scales+ii*hdr->nchan, 157 | sizeof(float)*out_nchan); 158 | } 159 | } 160 | } 161 | -------------------------------------------------------------------------------- /psrfits.h: -------------------------------------------------------------------------------- 1 | /* psrfits.h */ 2 | #ifndef _PSRFITS_H 3 | #define _PSRFITS_H 4 | #include "fitsio.h" 5 | 6 | // The following is the max file length in GB, different for fold/search 7 | #define PSRFITS_MAXFILELEN_SEARCH 10L 8 | #define PSRFITS_MAXFILELEN_FOLD 1L 9 | 10 | // The following is the template file to use to create a PSRFITS file. 11 | #define PSRFITS_SEARCH_TEMPLATE "guppi_PSRFITS_v3.4_search_template.txt" 12 | #define PSRFITS_FOLD_TEMPLATE "guppi_PSRFITS_v3.4_fold_template.txt" 13 | 14 | struct hdrinfo { 15 | char obs_mode[8]; // Observing mode (SEARCH, PSR, CAL) 16 | char telescope[24]; // Telescope used 17 | char observer[24]; // Observer's name 18 | char source[24]; // Source name 19 | char frontend[24]; // Frontend used 20 | char backend[24]; // Backend or instrument used 21 | char project_id[24]; // Project identifier 22 | char date_obs[24]; // Start of observation (YYYY-MM-DDTHH:MM:SS.SSS) 23 | char ra_str[16]; // Right Ascension string (HH:MM:SS.SSSS) 24 | char dec_str[16]; // Declination string (DD:MM:SS.SSSS) 25 | char poln_type[8]; // Polarization recorded (LIN or CIRC) 26 | char poln_order[16]; // Order of polarizations (i.e. XXYYXYYX) 27 | char track_mode[16]; // Track mode (TRACK, SCANGC, SCANLAT) 28 | char cal_mode[8]; // Cal mode (OFF, SYNC, EXT1, EXT2 29 | char feed_mode[8]; // Feed track mode (FA, CPA, SPA, TPA) 30 | long double MJD_epoch; // Starting epoch in MJD 31 | double dt; // Sample duration (s) 32 | double fctr; // Center frequency of the observing band (MHz) 33 | double orig_df; // Original frequency spacing between the channels (MHz) 34 | double df; // Frequency spacing between the channels (MHz) 35 | double BW; // Bandwidth of the observing band (MHz) 36 | double ra2000; // RA of observation (deg, J2000) at obs start 37 | double dec2000; // Dec of observation (deg, J2000) at obs start 38 | double azimuth; // Azimuth (commanded) at the start of the obs (deg) 39 | double zenith_ang; // Zenith angle (commanded) at the start of the obs (deg) 40 | double beam_FWHM; // Beam FWHM (deg) 41 | double cal_freq; // Cal modulation frequency (Hz) 42 | double cal_dcyc; // Cal duty cycle (0-1) 43 | double cal_phs; // Cal phase (wrt start time) 44 | double feed_angle; // Feed/Posn angle requested (deg) 45 | double scanlen; // Requested scan length (sec) 46 | double start_lst; // Start LST (sec past 00h) 47 | double start_sec; // Start time (sec past UTC 00h) 48 | double chan_dm; // DM that each channel was de-dispersed at (pc/cm^3) 49 | double fd_sang; // Reference angle for feed rotation (deg) 50 | double fd_xyph; // Cal signal poln cross-term phase (deg) 51 | int start_day; // Start MJD (UTC days) (J - long integer) 52 | int scan_number; // Number of scan 53 | int nbits; // Number of bits per data sample 54 | int nbin; // Number of bins per period in fold mode 55 | int nchan; // Number of channels 56 | int npol; // Number of polarizations to be stored (1 for summed) 57 | int nsblk; // Number of spectra per row 58 | int orig_nchan; // Number of spectral channels per sample 59 | int summed_polns; // Are polarizations summed? (1=Yes, 0=No) 60 | int rcvr_polns; // Number of polns provided by the receiver 61 | int offset_subint; // Offset subint number for first row in the file 62 | int ds_time_fact; // Software downsampling factor in time (1 if none) 63 | int ds_freq_fact; // Software downsampling factor in freq (1 if none) 64 | int onlyI; // 1 if the software will only record Stokes I 65 | int fd_hand; // Receiver "handedness" or X/Y swap (+/-1) 66 | int be_phase; // Backend poln cross-term phase convention (+/-1) 67 | }; 68 | 69 | struct subint { 70 | double tsubint; // Length of subintegration (sec) 71 | double offs; // Offset from Start of subint centre (sec) 72 | double lst; // LST at subint centre (sec) 73 | double ra; // RA (J2000) at subint centre (deg) 74 | double dec; // Dec (J2000) at subint centre (deg) 75 | double glon; // Gal longitude at subint centre (deg) 76 | double glat; // Gal latitude at subint centre (deg) 77 | double feed_ang; // Feed angle at subint centre (deg) 78 | double pos_ang; // Position angle of feed at subint centre (deg) 79 | double par_ang; // Parallactic angle at subint centre (deg) 80 | double tel_az; // Telescope azimuth at subint centre (deg) 81 | double tel_zen; // Telescope zenith angle at subint centre (deg) 82 | int bytes_per_subint; // Number of bytes for one row of raw data 83 | int FITS_typecode; // FITS data typecode as per CFITSIO 84 | float *dat_freqs; // Ptr to array of Centre freqs for each channel (MHz) 85 | float *dat_weights; // Ptr to array of Weights for each channel 86 | float *dat_offsets; // Ptr to array of offsets for each chan * pol 87 | float *dat_scales; // Ptr to array of scalings for each chan * pol 88 | float *fdata; // Ptr to optional array to compute scaled and offset data 89 | unsigned char *rawdata; // Ptr to the raw data itself (for non-8bit) 90 | unsigned char *data; // Ptr to 8-bit representation of the data itself 91 | }; 92 | 93 | #include "polyco_struct.h" 94 | struct foldinfo { 95 | char parfile[256]; // Parfile name for folding 96 | int n_polyco_sets; // Number of polyco sets present 97 | struct polyco *pc; // Pointer to polyco blocks 98 | int nbin; // Requested number of bins 99 | double tfold; // Requested fold integration time 100 | }; 101 | 102 | struct psrfits { 103 | char basefilename[200]; // The base filename from which to build the true filename 104 | char filename[200]; // Filename of the current PSRFITs file 105 | long long N; // Current number of spectra written 106 | double T; // Current duration of the observation written 107 | int filenum; // The current number of the file in the scan (1-offset) 108 | int numfiles; // The number of input files (if specified, 0 if basefilename) 109 | int rownum; // The current subint number to be written (1-offset) 110 | int tot_rows; // The total number of subints written so far 111 | int rows_per_file; // The maximum number of rows (subints) per file 112 | int status; // The CFITSIO status value 113 | fitsfile *fptr; // The CFITSIO file structure 114 | int multifile; // Write multiple output files 115 | int quiet; // Be quiet about writing each subint 116 | char mode; // Read (r) or write (w). 117 | char **filenames; // Array of the input file names 118 | struct hdrinfo hdr; 119 | struct subint sub; 120 | struct foldinfo fold; 121 | }; 122 | 123 | // In write_psrfits.c 124 | int psrfits_create(struct psrfits *pf); 125 | int psrfits_write_subint(struct psrfits *pf); 126 | int psrfits_write_polycos(struct psrfits *pf, struct polyco *pc, int npc); 127 | int psrfits_write_ephem(struct psrfits *pf, FILE *parfile); 128 | int psrfits_close(struct psrfits *pf); 129 | #define SEARCH_MODE 1 130 | #define FOLD_MODE 2 131 | int psrfits_obs_mode(const char *obs_mode); 132 | int psrfits_remove_polycos(struct psrfits *pf); 133 | int psrfits_remove_ephem(struct psrfits *pf); 134 | 135 | // In read_psrfits.c 136 | int is_search_PSRFITS(char *filename); 137 | void psrfits_set_files(struct psrfits *pf, int numfiles, char *filenames[]); 138 | int psrfits_open(struct psrfits *pf); 139 | int psrfits_read_subint(struct psrfits *pf); 140 | int psrfits_read_part_DATA(struct psrfits *pf, int N, int numunsigned, 141 | float *fbuffer); 142 | void scale_and_offset_data(struct psrfits *pf, int numunsigned); 143 | 144 | #endif 145 | -------------------------------------------------------------------------------- /guppi_PSRFITS_v3.4_search_template.txt: -------------------------------------------------------------------------------- 1 | SIMPLE = T / file does conform to FITS standard 2 | BITPIX = 8 / number of bits per data pixel 3 | NAXIS = 0 / number of data axes 4 | EXTEND = T / FITS dataset may contain extensions 5 | HDRVER = '3.4 ' / Header version 6 | FITSTYPE= 'PSRFITS' / FITS definition for pulsar data files 7 | DATE = ' ' / File creation date (YYYY-MM-DDThh:mm:ss UTC) 8 | OBSERVER= ' ' / Observer name(s) 9 | PROJID = ' ' / Project name 10 | TELESCOP= 'GBT' / Telescope name 11 | ANT_X = 882589.65 / [m] Antenna ITRF X-coordinate (D) 12 | ANT_Y = -4924872.32 / [m] Antenna ITRF Y-coordinate (D) 13 | ANT_Z = 3943729.348 / [m] Antenna ITRF Z-coordinate (D) 14 | FRONTEND= ' ' / Rx and feed ID 15 | NRCVR = 2 / Number of receiver polarisation channels 16 | FD_POLN = 'LIN' / LIN or CIRC 17 | FD_HAND = -1 / +/- 1. +1 is LIN:A=X,B=Y, CIRC:A=L,B=R (I) 18 | FD_SANG = 45.0 / [deg] FA of E vect for equal sig in A&B (E) 19 | FD_XYPH = 0.0 / [deg] Phase of A^* B for injected cal (E) 20 | BACKEND = 'GUPPI' / Backend ID 21 | BECONFIG= 'N/A' / Backend configuration file name 22 | BE_PHASE= -1 / 0/+1/-1 BE cross-phase:0 unknown,+/-1 std/rev 23 | BE_DCC = 0 / 0/1 BE downconversion conjugation corrected 24 | BE_DELAY= 0.0 / [s] Backend propn delay from digitiser input 25 | TCYCLE = 0.0 / [s] On-line cycle time (D) 26 | OBS_MODE= 'SEARCH' / (PSR, CAL, SEARCH) 27 | DATE-OBS= ' ' / Date of observation (YYYY-MM-DDThh:mm:ss UTC) 28 | OBSFREQ = * / [MHz] Centre frequency for observation 29 | OBSBW = * / [MHz] Bandwidth for observation 30 | OBSNCHAN= * / Number of frequency channels (original) 31 | CHAN_DM = 0.0 / DM used to de-disperse each channel (pc/cm^3) 32 | SRC_NAME= ' ' / Source or scan ID 33 | COORD_MD= 'J2000' / Coordinate mode (J2000, GAL, ECLIP, etc.) 34 | EQUINOX = 2000.0 / Equinox of coords (e.g. 2000.0) 35 | RA = ' ' / Right ascension (hh:mm:ss.ssss) 36 | DEC = ' ' / Declination (-dd:mm:ss.sss) 37 | BMAJ = * / [deg] Beam major axis length 38 | BMIN = * / [deg] Beam minor axis length 39 | BPA = 0.0 / [deg] Beam position angle 40 | STT_CRD1= ' ' / Start coord 1 (hh:mm:ss.sss or ddd.ddd) 41 | STT_CRD2= ' ' / Start coord 2 (-dd:mm:ss.sss or -dd.ddd) 42 | TRK_MODE= 'TRACK' / Track mode (TRACK, SCANGC, SCANLAT) 43 | STP_CRD1= ' ' / Stop coord 1 (hh:mm:ss.sss or ddd.ddd) 44 | STP_CRD2= ' ' / Stop coord 2 (-dd:mm:ss.sss or -dd.ddd) 45 | SCANLEN = * / [s] Requested scan length (E) 46 | FD_MODE = 'FA' / Feed track mode - FA, CPA, SPA, TPA 47 | FA_REQ = 0.0 / [deg] Feed/Posn angle requested (E) 48 | CAL_MODE= 'OFF' / Cal mode (OFF, SYNC, EXT1, EXT2) 49 | CAL_FREQ= 0.0 / [Hz] Cal modulation frequency (E) 50 | CAL_DCYC= 0.0 / Cal duty cycle (E) 51 | CAL_PHS = 0.0 / Cal phase (wrt start time) (E) 52 | STT_IMJD= * / Start MJD (UTC days) (J - long integer) 53 | STT_SMJD= * / [s] Start time (sec past UTC 00h) (J) 54 | STT_OFFS= * / [s] Start time offset (D) 55 | STT_LST = * / [s] Start LST (D) 56 | END 57 | # 58 | ############################################################################### 59 | # 60 | # Subintegration data Binary Table Extension 61 | # 62 | ############################################################################### 63 | # 64 | XTENSION= BINTABLE / ***** Subintegration data ***** 65 | BITPIX = 8 / N/A 66 | NAXIS = 2 / 2-dimensional binary table 67 | NAXIS1 = * / width of table in bytes 68 | NAXIS2 = * / Number of rows in table (NSUBINT) 69 | PCOUNT = 0 / size of special data area 70 | GCOUNT = 1 / one data group (required keyword) 71 | TFIELDS = * / Number of fields per row 72 | INT_TYPE= 'TIME' / Time axis (TIME, BINPHSPERI, BINLNGASC, etc) 73 | INT_UNIT= 'SEC' / Unit of time axis (SEC, PHS (0-1), DEG) 74 | SCALE = 'FluxDen' / Intensity units (FluxDen/RefFlux/Jansky) 75 | NPOL = 1 / Nr of polarisations 76 | POL_TYPE= 'AA+BB' / Polarisation identifier (e.g., AABBCRCI, AA+BB) 77 | TBIN = * / [s] Time per bin or sample 78 | NBIN = 1 / Nr of bins (PSR/CAL mode; else 1) 79 | NBIN_PRD= 0 / Nr of bins/pulse period (for gated data) 80 | PHS_OFFS= 0.0 / Phase offset of bin 0 for gated data 81 | NBITS = 8 / Nr of bits/datum (SEARCH mode 'X' data, else 1) 82 | NSUBOFFS= 0 / Subint offset (Contiguous SEARCH-mode files) 83 | NCHAN = * / Number of channels/sub-bands in this file 84 | CHAN_BW = * / [MHz] Channel/sub-band width 85 | NCHNOFFS= 0 / Channel/sub-band offset for split files 86 | NSBLK = * / Samples/row (SEARCH mode, else 1) 87 | EXTNAME = SUBINT / name of this binary table extension 88 | TTYPE# = TSUBINT / Length of subintegration 89 | TFORM# = 1D / Double 90 | TUNIT# = s / Units of field 91 | TTYPE# = OFFS_SUB / Offset from Start of subint centre 92 | TFORM# = 1D / Double 93 | TUNIT# = s / Units of field 94 | TTYPE# = LST_SUB / LST at subint centre 95 | TFORM# = 1D / Double 96 | TUNIT# = s / Units of field 97 | TTYPE# = RA_SUB / RA (J2000) at subint centre 98 | TFORM# = 1D / Double 99 | TUNIT# = deg / Units of field 100 | TTYPE# = DEC_SUB / Dec (J2000) at subint centre 101 | TFORM# = 1D / Double 102 | TUNIT# = deg / Units of field 103 | TTYPE# = GLON_SUB / [deg] Gal longitude at subint centre 104 | TFORM# = 1D / Double 105 | TUNIT# = deg / Units of field 106 | TTYPE# = GLAT_SUB / [deg] Gal latitude at subint centre 107 | TFORM# = 1D / Double 108 | TUNIT# = deg / Units of field 109 | TTYPE# = FD_ANG / [deg] Feed angle at subint centre 110 | TFORM# = 1E / Float 111 | TUNIT# = deg / Units of field 112 | TTYPE# = POS_ANG / [deg] Position angle of feed at subint centre 113 | TFORM# = 1E / Float 114 | TUNIT# = deg / Units of field 115 | TTYPE# = PAR_ANG / [deg] Parallactic angle at subint centre 116 | TFORM# = 1E / Float 117 | TUNIT# = deg / Units of field 118 | TTYPE# = TEL_AZ / [deg] Telescope azimuth at subint centre 119 | TFORM# = 1E / Float 120 | TUNIT# = deg / Units of field 121 | TTYPE# = TEL_ZEN / [deg] Telescope zenith angle at subint centre 122 | TFORM# = 1E / Float 123 | TUNIT# = deg / Units of field 124 | TTYPE# = DAT_FREQ / [MHz] Centre frequency for each channel 125 | TFORM# = E / NCHAN floats 126 | TUNIT# = MHz / Units of field 127 | TTYPE# = DAT_WTS / Weights for each channel 128 | TFORM# = E / NCHAN floats 129 | TTYPE# = DAT_OFFS / Data offset for each channel 130 | TFORM# = E / NCHAN*NPOL floats 131 | TTYPE# = DAT_SCL / Data scale factor for each channel 132 | TFORM# = E / NCHAN*NPOL floats 133 | TTYPE# = DATA / Subint data table 134 | TDIM# = (*,*,*,*) / Dimensions (NBITS or NBIN,NCHAN,NPOL,NSBLK) 135 | TFORM# = B / NBIN*NCHAN*NPOL*NSBLK int, byte(B) or bit(X) 136 | TUNIT# = Jy / Units of subint data 137 | END 138 | -------------------------------------------------------------------------------- /misc_utils.c: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | #include 5 | #include 6 | #include 7 | 8 | /* like strcpy, except guaranteed to work with overlapping strings */ 9 | #define strMove(d,s) memmove(d,s,strlen(s)+1) 10 | 11 | char *rmtrail(char *str) 12 | /* Removes trailing space from a string */ 13 | { 14 | int i; 15 | 16 | if (str && 0 != (i = strlen(str))) { 17 | while (--i >= 0) { 18 | if (!isspace(str[i])) 19 | break; 20 | } 21 | str[++i] = '\0'; 22 | } 23 | return str; 24 | } 25 | 26 | 27 | char *rmlead(char *str) 28 | /* Removes leading space from a string */ 29 | { 30 | char *obuf; 31 | 32 | if (str) { 33 | for (obuf = str; *obuf && isspace(*obuf); ++obuf); 34 | if (str != obuf) strMove(str, obuf); 35 | } 36 | return str; 37 | } 38 | 39 | 40 | char *remove_whitespace(char *str) 41 | /* Remove leading and trailing space from a string */ 42 | { 43 | return rmlead(rmtrail(str)); 44 | } 45 | 46 | 47 | char *strlower(char *str) 48 | /* Convert a string to lower case */ 49 | { 50 | char *ss; 51 | 52 | if (str) { 53 | for (ss = str; *ss; ++ss) 54 | *ss = tolower(*ss); 55 | } 56 | return str; 57 | } 58 | 59 | 60 | void split_path_file(char *input, char **path, char **file) 61 | /* This routine splits an input string into a path and */ 62 | /* a filename. Since it allocates the memory for the */ 63 | /* path and filename dynamically, the calling program */ 64 | /* must free both "path" and "file". */ 65 | { 66 | char *sptr = NULL, stmp[200]; 67 | unsigned int len, pathlen = 0, filelen = 0; 68 | 69 | len = strlen(input); 70 | sptr = strrchr(input, '/'); 71 | if (sptr == NULL) { 72 | getcwd(stmp, 200); 73 | if (stmp == NULL) { 74 | printf("\nCurrent directory name is too long.\n"); 75 | printf("Exiting\n\n"); 76 | exit(1); 77 | } 78 | pathlen = strlen(stmp); 79 | *path = (char *) calloc(pathlen + 1, sizeof(char)); 80 | *file = (char *) calloc(len + 1, sizeof(char)); 81 | strcpy(*path, stmp); 82 | strncpy(*file, input, len); 83 | } else { 84 | pathlen = sptr - input; 85 | filelen = len - pathlen - 1; 86 | *path = (char *) calloc(pathlen + 1, sizeof(char)); 87 | *file = (char *) calloc(filelen + 1, sizeof(char)); 88 | strncpy(*path, input, pathlen); 89 | strncpy(*file, sptr + 1, filelen); 90 | } 91 | } 92 | 93 | 94 | int split_root_suffix(char *input, char **root, char **suffix) 95 | /* This routine splits an input string into a root name */ 96 | /* + suffix. Since it allocates the memory for the */ 97 | /* root and suffix dynamically, the calling program */ 98 | /* must free both "root" and "suffix". */ 99 | /* If the routine finds a suffix, it returns 1, else 0. */ 100 | { 101 | char *sptr = NULL; 102 | unsigned int len, rootlen = 0, suffixlen = 0; 103 | 104 | len = strlen(input); 105 | sptr = strrchr(input, '.'); 106 | if (sptr == NULL) { 107 | *root = (char *) calloc(len + 1, sizeof(char)); 108 | strncpy(*root, input, len); 109 | return 0; 110 | } else { 111 | rootlen = sptr - input; 112 | *root = (char *) calloc(rootlen + 1, sizeof(char)); 113 | strncpy(*root, input, rootlen); 114 | suffixlen = len - rootlen - 1; 115 | *suffix = (char *) calloc(suffixlen + 1, sizeof(char)); 116 | strncpy(*suffix, sptr + 1, suffixlen); 117 | return 1; 118 | } 119 | } 120 | 121 | 122 | void strtofilename(char *string) 123 | /* Trim spaces off the end of *input and convert */ 124 | /* all other spaces into underscores. */ 125 | { 126 | int ii; 127 | 128 | ii = strlen(string) - 1; 129 | do { 130 | if (string[ii] == ' ') 131 | string[ii] = '\0'; 132 | else 133 | break; 134 | } while (ii--); 135 | do { 136 | if (string[ii] == ' ') 137 | string[ii] = '_'; 138 | } while (ii--); 139 | } 140 | 141 | 142 | double delay_from_dm(double dm, double freq_emitted) 143 | /* Return the delay in seconds caused by dispersion, given */ 144 | /* a Dispersion Measure (dm) in cm-3 pc, and the emitted */ 145 | /* frequency (freq_emitted) of the pulsar in MHz. */ 146 | { 147 | return dm / (0.000241 * freq_emitted * freq_emitted); 148 | } 149 | 150 | 151 | long long next2_to_n(long long x) 152 | /* Return the first value of 2^n >= x */ 153 | { 154 | long long i = 1; 155 | 156 | while (i < x) 157 | i <<= 1; 158 | return i; 159 | } 160 | 161 | 162 | void avg_std(float *x, int n, double *mean, double *std, int stride) 163 | /* For a float vector, *x, of length n*stride, this */ 164 | /* routine returns the mean and variance of the n values */ 165 | /* separated in memory by stride bytes (contiguous is stride=1) */ 166 | { 167 | int ii; 168 | double an = 0.0, an1 = 0.0, dx, var; 169 | 170 | /* Modified (29 June 98) C version of the following: */ 171 | /* ALGORITHM AS 52 APPL. STATIST. (1972) VOL.21, P.226 */ 172 | /* Returned values were checked with Mathematica 3.01 */ 173 | 174 | if (n < 1) { 175 | printf("\vVector length must be > 0 in avg_var(). Exiting\n"); 176 | exit(1); 177 | } else { 178 | *mean = (double) x[0]; 179 | var = 0.0; 180 | } 181 | 182 | for (ii = 1; ii < n; ii++) { 183 | an = (double) (ii + 1); 184 | an1 = (double) (ii); 185 | dx = ((double) x[ii*stride] - *mean) / an; 186 | var += an * an1 * dx * dx; 187 | *mean += dx; 188 | } 189 | 190 | if (n > 1) { 191 | var /= an1; 192 | *std = sqrt(var); 193 | } else { 194 | *std = 0.0; 195 | } 196 | 197 | return; 198 | } 199 | 200 | 201 | static int TOMS_gcd(int a, int b) 202 | /* Return the greatest common denominator of 'a' and 'b' */ 203 | { 204 | int r; 205 | do { 206 | r = a % b; 207 | a = b; 208 | b = r; 209 | } while (r != 0); 210 | 211 | return a; 212 | } 213 | 214 | 215 | short transpose_bytes(unsigned char *a, int nx, int ny, unsigned char *move, 216 | int move_size) 217 | /* 218 | * TOMS Transpose. Revised version of algorithm 380. 219 | * 220 | * These routines do in-place transposes of arrays. 221 | * 222 | * [ Cate, E.G. and Twigg, D.W., ACM Transactions on Mathematical Software, 223 | * vol. 3, no. 1, 104-110 (1977) ] 224 | * 225 | * C version by Steven G. Johnson. February 1997. 226 | * 227 | * "a" is a 1D array of length ny*nx which contains the nx x ny matrix to be 228 | * transposed. "a" is stored in C order (last index varies fastest). move 229 | * is a 1D array of length move_size used to store information to speed up 230 | * the process. The value move_size=(ny+nx)/2 is recommended. 231 | * 232 | * The return value indicates the success or failure of the routine. Returns 0 233 | * if okay, -1 if ny or nx < 0, and -2 if move_size < 1. The return value 234 | * should never be positive, but it it is, it is set to the final position in 235 | * a when the search is completed but some elements have not been moved. 236 | * 237 | * Note: move[i] will stay zero for fixed points. 238 | */ 239 | { 240 | int i, j, im, mn; 241 | unsigned char b, c, d; 242 | int ncount; 243 | int k; 244 | 245 | /* check arguments and initialize: */ 246 | if (ny < 0 || nx < 0) 247 | return -1; 248 | if (ny < 2 || nx < 2) 249 | return 0; 250 | if (move_size < 1) 251 | return -2; 252 | 253 | if (ny == nx) { 254 | /* 255 | * if matrix is square, exchange elements a(i,j) and a(j,i): 256 | */ 257 | for (i = 0; i < nx; ++i) 258 | for (j = i + 1; j < nx; ++j) { 259 | b = a[i + j * nx]; 260 | a[i + j * nx] = a[j + i * nx]; 261 | a[j + i * nx] = b; 262 | } 263 | return 0; 264 | } 265 | ncount = 2; /* always at least 2 fixed points */ 266 | k = (mn = ny * nx) - 1; 267 | 268 | for (i = 0; i < move_size; ++i) 269 | move[i] = 0; 270 | 271 | if (ny >= 3 && nx >= 3) 272 | ncount += TOMS_gcd(ny - 1, nx - 1) - 1; /* # fixed points */ 273 | 274 | i = 1; 275 | im = ny; 276 | 277 | while (1) { 278 | int i1, i2, i1c, i2c; 279 | int kmi; 280 | 281 | /** Rearrange the elements of a loop 282 | and its companion loop: **/ 283 | 284 | i1 = i; 285 | kmi = k - i; 286 | b = a[i1]; 287 | i1c = kmi; 288 | c = a[i1c]; 289 | 290 | while (1) { 291 | i2 = ny * i1 - k * (i1 / nx); 292 | i2c = k - i2; 293 | if (i1 < move_size) 294 | move[i1] = 1; 295 | if (i1c < move_size) 296 | move[i1c] = 1; 297 | ncount += 2; 298 | if (i2 == i) 299 | break; 300 | if (i2 == kmi) { 301 | d = b; 302 | b = c; 303 | c = d; 304 | break; 305 | } 306 | a[i1] = a[i2]; 307 | a[i1c] = a[i2c]; 308 | i1 = i2; 309 | i1c = i2c; 310 | } 311 | a[i1] = b; 312 | a[i1c] = c; 313 | 314 | if (ncount >= mn) 315 | break; /* we've moved all elements */ 316 | 317 | /** Search for loops to rearrange: **/ 318 | 319 | while (1) { 320 | int max; 321 | 322 | max = k - i; 323 | ++i; 324 | if (i > max) 325 | return i; 326 | im += ny; 327 | if (im > k) 328 | im -= k; 329 | i2 = im; 330 | if (i == i2) 331 | continue; 332 | if (i >= move_size) { 333 | while (i2 > i && i2 < max) { 334 | i1 = i2; 335 | i2 = ny * i1 - k * (i1 / nx); 336 | } 337 | if (i2 == i) 338 | break; 339 | } else if (!move[i]) 340 | break; 341 | } 342 | } 343 | 344 | return 0; 345 | } 346 | -------------------------------------------------------------------------------- /config/ax_pthread.m4: -------------------------------------------------------------------------------- 1 | # =========================================================================== 2 | # http://www.nongnu.org/autoconf-archive/ax_pthread.html 3 | # =========================================================================== 4 | # 5 | # SYNOPSIS 6 | # 7 | # AX_PTHREAD([ACTION-IF-FOUND[, ACTION-IF-NOT-FOUND]]) 8 | # 9 | # DESCRIPTION 10 | # 11 | # This macro figures out how to build C programs using POSIX threads. It 12 | # sets the PTHREAD_LIBS output variable to the threads library and linker 13 | # flags, and the PTHREAD_CFLAGS output variable to any special C compiler 14 | # flags that are needed. (The user can also force certain compiler 15 | # flags/libs to be tested by setting these environment variables.) 16 | # 17 | # Also sets PTHREAD_CC to any special C compiler that is needed for 18 | # multi-threaded programs (defaults to the value of CC otherwise). (This 19 | # is necessary on AIX to use the special cc_r compiler alias.) 20 | # 21 | # NOTE: You are assumed to not only compile your program with these flags, 22 | # but also link it with them as well. e.g. you should link with 23 | # $PTHREAD_CC $CFLAGS $PTHREAD_CFLAGS $LDFLAGS ... $PTHREAD_LIBS $LIBS 24 | # 25 | # If you are only building threads programs, you may wish to use these 26 | # variables in your default LIBS, CFLAGS, and CC: 27 | # 28 | # LIBS="$PTHREAD_LIBS $LIBS" 29 | # CFLAGS="$CFLAGS $PTHREAD_CFLAGS" 30 | # CC="$PTHREAD_CC" 31 | # 32 | # In addition, if the PTHREAD_CREATE_JOINABLE thread-attribute constant 33 | # has a nonstandard name, defines PTHREAD_CREATE_JOINABLE to that name 34 | # (e.g. PTHREAD_CREATE_UNDETACHED on AIX). 35 | # 36 | # ACTION-IF-FOUND is a list of shell commands to run if a threads library 37 | # is found, and ACTION-IF-NOT-FOUND is a list of commands to run it if it 38 | # is not found. If ACTION-IF-FOUND is not specified, the default action 39 | # will define HAVE_PTHREAD. 40 | # 41 | # Please let the authors know if this macro fails on any platform, or if 42 | # you have any other suggestions or comments. This macro was based on work 43 | # by SGJ on autoconf scripts for FFTW (http://www.fftw.org/) (with help 44 | # from M. Frigo), as well as ac_pthread and hb_pthread macros posted by 45 | # Alejandro Forero Cuervo to the autoconf macro repository. We are also 46 | # grateful for the helpful feedback of numerous users. 47 | # 48 | # LICENSE 49 | # 50 | # Copyright (c) 2008 Steven G. Johnson 51 | # 52 | # This program is free software: you can redistribute it and/or modify it 53 | # under the terms of the GNU General Public License as published by the 54 | # Free Software Foundation, either version 3 of the License, or (at your 55 | # option) any later version. 56 | # 57 | # This program is distributed in the hope that it will be useful, but 58 | # WITHOUT ANY WARRANTY; without even the implied warranty of 59 | # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General 60 | # Public License for more details. 61 | # 62 | # You should have received a copy of the GNU General Public License along 63 | # with this program. If not, see . 64 | # 65 | # As a special exception, the respective Autoconf Macro's copyright owner 66 | # gives unlimited permission to copy, distribute and modify the configure 67 | # scripts that are the output of Autoconf when processing the Macro. You 68 | # need not follow the terms of the GNU General Public License when using 69 | # or distributing such scripts, even though portions of the text of the 70 | # Macro appear in them. The GNU General Public License (GPL) does govern 71 | # all other use of the material that constitutes the Autoconf Macro. 72 | # 73 | # This special exception to the GPL applies to versions of the Autoconf 74 | # Macro released by the Autoconf Archive. When you make and distribute a 75 | # modified version of the Autoconf Macro, you may extend this special 76 | # exception to the GPL to apply to your modified version as well. 77 | 78 | #serial 5 79 | 80 | AU_ALIAS([ACX_PTHREAD], [AX_PTHREAD]) 81 | AC_DEFUN([AX_PTHREAD], [ 82 | AC_REQUIRE([AC_CANONICAL_HOST]) 83 | AC_LANG_SAVE 84 | AC_LANG_C 85 | ax_pthread_ok=no 86 | 87 | # We used to check for pthread.h first, but this fails if pthread.h 88 | # requires special compiler flags (e.g. on True64 or Sequent). 89 | # It gets checked for in the link test anyway. 90 | 91 | # First of all, check if the user has set any of the PTHREAD_LIBS, 92 | # etcetera environment variables, and if threads linking works using 93 | # them: 94 | if test x"$PTHREAD_LIBS$PTHREAD_CFLAGS" != x; then 95 | save_CFLAGS="$CFLAGS" 96 | CFLAGS="$CFLAGS $PTHREAD_CFLAGS" 97 | save_LIBS="$LIBS" 98 | LIBS="$PTHREAD_LIBS $LIBS" 99 | AC_MSG_CHECKING([for pthread_join in LIBS=$PTHREAD_LIBS with CFLAGS=$PTHREAD_CFLAGS]) 100 | AC_TRY_LINK_FUNC(pthread_join, ax_pthread_ok=yes) 101 | AC_MSG_RESULT($ax_pthread_ok) 102 | if test x"$ax_pthread_ok" = xno; then 103 | PTHREAD_LIBS="" 104 | PTHREAD_CFLAGS="" 105 | fi 106 | LIBS="$save_LIBS" 107 | CFLAGS="$save_CFLAGS" 108 | fi 109 | 110 | # We must check for the threads library under a number of different 111 | # names; the ordering is very important because some systems 112 | # (e.g. DEC) have both -lpthread and -lpthreads, where one of the 113 | # libraries is broken (non-POSIX). 114 | 115 | # Create a list of thread flags to try. Items starting with a "-" are 116 | # C compiler flags, and other items are library names, except for "none" 117 | # which indicates that we try without any flags at all, and "pthread-config" 118 | # which is a program returning the flags for the Pth emulation library. 119 | 120 | ax_pthread_flags="pthreads none -Kthread -kthread lthread -pthread -pthreads -mthreads pthread --thread-safe -mt pthread-config" 121 | 122 | # The ordering *is* (sometimes) important. Some notes on the 123 | # individual items follow: 124 | 125 | # pthreads: AIX (must check this before -lpthread) 126 | # none: in case threads are in libc; should be tried before -Kthread and 127 | # other compiler flags to prevent continual compiler warnings 128 | # -Kthread: Sequent (threads in libc, but -Kthread needed for pthread.h) 129 | # -kthread: FreeBSD kernel threads (preferred to -pthread since SMP-able) 130 | # lthread: LinuxThreads port on FreeBSD (also preferred to -pthread) 131 | # -pthread: Linux/gcc (kernel threads), BSD/gcc (userland threads) 132 | # -pthreads: Solaris/gcc 133 | # -mthreads: Mingw32/gcc, Lynx/gcc 134 | # -mt: Sun Workshop C (may only link SunOS threads [-lthread], but it 135 | # doesn't hurt to check since this sometimes defines pthreads too; 136 | # also defines -D_REENTRANT) 137 | # ... -mt is also the pthreads flag for HP/aCC 138 | # pthread: Linux, etcetera 139 | # --thread-safe: KAI C++ 140 | # pthread-config: use pthread-config program (for GNU Pth library) 141 | 142 | case "${host_cpu}-${host_os}" in 143 | *solaris*) 144 | 145 | # On Solaris (at least, for some versions), libc contains stubbed 146 | # (non-functional) versions of the pthreads routines, so link-based 147 | # tests will erroneously succeed. (We need to link with -pthreads/-mt/ 148 | # -lpthread.) (The stubs are missing pthread_cleanup_push, or rather 149 | # a function called by this macro, so we could check for that, but 150 | # who knows whether they'll stub that too in a future libc.) So, 151 | # we'll just look for -pthreads and -lpthread first: 152 | 153 | ax_pthread_flags="-pthreads pthread -mt -pthread $ax_pthread_flags" 154 | ;; 155 | esac 156 | 157 | if test x"$ax_pthread_ok" = xno; then 158 | for flag in $ax_pthread_flags; do 159 | 160 | case $flag in 161 | none) 162 | AC_MSG_CHECKING([whether pthreads work without any flags]) 163 | ;; 164 | 165 | -*) 166 | AC_MSG_CHECKING([whether pthreads work with $flag]) 167 | PTHREAD_CFLAGS="$flag" 168 | ;; 169 | 170 | pthread-config) 171 | AC_CHECK_PROG(ax_pthread_config, pthread-config, yes, no) 172 | if test x"$ax_pthread_config" = xno; then continue; fi 173 | PTHREAD_CFLAGS="`pthread-config --cflags`" 174 | PTHREAD_LIBS="`pthread-config --ldflags` `pthread-config --libs`" 175 | ;; 176 | 177 | *) 178 | AC_MSG_CHECKING([for the pthreads library -l$flag]) 179 | PTHREAD_LIBS="-l$flag" 180 | ;; 181 | esac 182 | 183 | save_LIBS="$LIBS" 184 | save_CFLAGS="$CFLAGS" 185 | LIBS="$PTHREAD_LIBS $LIBS" 186 | CFLAGS="$CFLAGS $PTHREAD_CFLAGS" 187 | 188 | # Check for various functions. We must include pthread.h, 189 | # since some functions may be macros. (On the Sequent, we 190 | # need a special flag -Kthread to make this header compile.) 191 | # We check for pthread_join because it is in -lpthread on IRIX 192 | # while pthread_create is in libc. We check for pthread_attr_init 193 | # due to DEC craziness with -lpthreads. We check for 194 | # pthread_cleanup_push because it is one of the few pthread 195 | # functions on Solaris that doesn't have a non-functional libc stub. 196 | # We try pthread_create on general principles. 197 | AC_TRY_LINK([#include 198 | static void routine(void* a) {a=0;} 199 | static void* start_routine(void* a) {return a;}], 200 | [pthread_t th; pthread_attr_t attr; 201 | pthread_join(th, 0); 202 | pthread_attr_init(&attr); 203 | pthread_cleanup_push(routine, 0); 204 | pthread_create(&th,0,start_routine,0); 205 | pthread_cleanup_pop(0); ], 206 | [ax_pthread_ok=yes]) 207 | 208 | LIBS="$save_LIBS" 209 | CFLAGS="$save_CFLAGS" 210 | 211 | AC_MSG_RESULT($ax_pthread_ok) 212 | if test "x$ax_pthread_ok" = xyes; then 213 | break; 214 | fi 215 | 216 | PTHREAD_LIBS="" 217 | PTHREAD_CFLAGS="" 218 | done 219 | fi 220 | 221 | # Various other checks: 222 | if test "x$ax_pthread_ok" = xyes; then 223 | save_LIBS="$LIBS" 224 | LIBS="$PTHREAD_LIBS $LIBS" 225 | save_CFLAGS="$CFLAGS" 226 | CFLAGS="$CFLAGS $PTHREAD_CFLAGS" 227 | 228 | # Detect AIX lossage: JOINABLE attribute is called UNDETACHED. 229 | AC_MSG_CHECKING([for joinable pthread attribute]) 230 | attr_name=unknown 231 | for attr in PTHREAD_CREATE_JOINABLE PTHREAD_CREATE_UNDETACHED; do 232 | AC_TRY_LINK([#include ], [int attr=$attr; return attr;], 233 | [attr_name=$attr; break]) 234 | done 235 | AC_MSG_RESULT($attr_name) 236 | if test "$attr_name" != PTHREAD_CREATE_JOINABLE; then 237 | AC_DEFINE_UNQUOTED(PTHREAD_CREATE_JOINABLE, $attr_name, 238 | [Define to necessary symbol if this constant 239 | uses a non-standard name on your system.]) 240 | fi 241 | 242 | AC_MSG_CHECKING([if more special flags are required for pthreads]) 243 | flag=no 244 | case "${host_cpu}-${host_os}" in 245 | *-aix* | *-freebsd* | *-darwin*) flag="-D_THREAD_SAFE";; 246 | *solaris* | *-osf* | *-hpux*) flag="-D_REENTRANT";; 247 | esac 248 | AC_MSG_RESULT(${flag}) 249 | if test "x$flag" != xno; then 250 | PTHREAD_CFLAGS="$flag $PTHREAD_CFLAGS" 251 | fi 252 | 253 | LIBS="$save_LIBS" 254 | CFLAGS="$save_CFLAGS" 255 | 256 | # More AIX lossage: must compile with xlc_r or cc_r 257 | if test x"$GCC" != xyes; then 258 | AC_CHECK_PROGS(PTHREAD_CC, xlc_r cc_r, ${CC}) 259 | else 260 | PTHREAD_CC=$CC 261 | fi 262 | else 263 | PTHREAD_CC="$CC" 264 | fi 265 | 266 | AC_SUBST(PTHREAD_LIBS) 267 | AC_SUBST(PTHREAD_CFLAGS) 268 | AC_SUBST(PTHREAD_CC) 269 | 270 | # Finally, execute ACTION-IF-FOUND/ACTION-IF-NOT-FOUND: 271 | if test x"$ax_pthread_ok" = xyes; then 272 | ifelse([$1],,AC_DEFINE(HAVE_PTHREAD,1,[Define if you have POSIX threads libraries and header files.]),[$1]) 273 | : 274 | else 275 | ax_pthread_ok=no 276 | $2 277 | fi 278 | AC_LANG_RESTORE 279 | ])dnl AX_PTHREAD 280 | -------------------------------------------------------------------------------- /polyco.c: -------------------------------------------------------------------------------- 1 | /* polyco.c 2 | * routines to read/use polyco.dat 3 | */ 4 | 5 | #include "polyco.h" 6 | #include "psrfits.h" 7 | #include 8 | #include 9 | #include 10 | #include 11 | #include 12 | 13 | int read_one_pc(FILE *f, struct polyco *pc) { 14 | 15 | int i, j; 16 | char *rv; 17 | int ret; 18 | char buf[90]; 19 | /* Read in polyco chunk */ 20 | rv = fgets(buf, 90, f); 21 | if (rv==NULL) { return(-1); } 22 | strncpy(pc->psr, &buf[0], 10); pc->psr[10] = '\0'; 23 | pc->mjd = atoi(&buf[31]); 24 | pc->fmjd = atof(&buf[39]); 25 | if ((rv=strchr(pc->psr, ' '))!=NULL) { *rv='\0'; } 26 | rv = fgets(buf,90,f); 27 | if (rv==NULL) { return(-1); } 28 | pc->rphase_int = atoll(&buf[0]); 29 | pc->rphase = fmod(atof(&buf[0]),1.0); 30 | pc->f0 = atof(&buf[20]); 31 | pc->nsite = atoi(&buf[42]); 32 | pc->nmin = atoi(&buf[43]); 33 | pc->nc = atoi(&buf[50]); 34 | pc->rf = atof(&buf[55]); 35 | pc->used = 0; 36 | for (i=0; inc/3 + (pc->nc%3)?1:0; i++) { 37 | rv=fgets(buf, 90, f); 38 | if (rv==NULL) { return(-1); } 39 | for (j=0; j<90; j++) { if (buf[j]=='D' || buf[j]=='d') buf[j]='e'; } 40 | ret=sscanf(buf, "%lf %lf %lf", 41 | &(pc->c[3*i]), &(pc->c[3*i+1]), &(pc->c[3*i+2])); 42 | if (ret!=3) { return(-1); } 43 | } 44 | 45 | return(0); 46 | 47 | } 48 | 49 | int read_pc(FILE *f, struct polyco *pc, const char *psr, int mjd, double fmjd) { 50 | 51 | /* Read through until we get to right psr, mjd */ 52 | int done=0, nomatch=0; 53 | int i, j; 54 | char *rv; 55 | int ret; 56 | char buf[90]; 57 | float tdiff; 58 | while (!done) { 59 | /* Read in polyco chunk */ 60 | rv = fgets(buf, 90, f); 61 | if (rv==NULL) { done=1; nomatch=1; continue; } 62 | strncpy(pc->psr, &buf[0], 10); pc->psr[10] = '\0'; 63 | pc->mjd = atoi(&buf[31]); 64 | pc->fmjd = atof(&buf[39]); 65 | if ((rv=strchr(pc->psr, ' '))!=NULL) { *rv='\0'; } 66 | rv = fgets(buf,90,f); 67 | pc->rphase = fmod(atof(&buf[0]),1.0); 68 | pc->f0 = atof(&buf[20]); 69 | pc->nsite = atoi(&buf[42]); 70 | pc->nmin = atoi(&buf[43]); 71 | pc->nc = atoi(&buf[50]); 72 | pc->rf = atof(&buf[55]); 73 | for (i=0; inc/3 + (pc->nc%3)?1:0; i++) { 74 | rv=fgets(buf, 90, f); 75 | if (rv==NULL) { return(-1); } 76 | for (j=0; j<90; j++) { if (buf[j]=='D' || buf[j]=='d') buf[j]='e'; } 77 | ret=sscanf(buf, "%lf %lf %lf", 78 | &(pc->c[3*i]), &(pc->c[3*i+1]), &(pc->c[3*i+2])); 79 | if (ret!=3) { return(-1); } 80 | } 81 | /* check for correct psr - null psrname matches any */ 82 | if (psr!=NULL) { if (strcmp(pc->psr, psr)!=0) { continue; } } 83 | tdiff = 1440.0*((double)(mjd-pc->mjd) + (fmjd-pc->fmjd)); 84 | if (fabs(tdiff) > (float)pc->nmin/2.0) { continue; } 85 | done=1; 86 | } 87 | 88 | return(-1*nomatch); 89 | 90 | } 91 | 92 | /* Reads all polycos in a file, mallocs space for them, returns 93 | * number found 94 | */ 95 | int read_all_pc(FILE *f, struct polyco **pc) { 96 | int rv, npc=0; 97 | do { 98 | *pc = (struct polyco *)realloc(*pc, sizeof(struct polyco) * (npc+1)); 99 | rv = read_one_pc(f, &((*pc)[npc])); 100 | npc++; 101 | } while (rv==0); 102 | npc--; // Final "read" is really a error or EOF. 103 | return(npc); 104 | } 105 | 106 | /* Select appropriate polyco set */ 107 | int select_pc(const struct polyco *pc, int npc, const char *psr, 108 | int imjd, double fmjd) { 109 | int ipc; 110 | const char *tmp = psr; 111 | if (psr!=NULL) 112 | if (tmp[0]=='J' || tmp[0]=='B') tmp++; 113 | // Verbose 114 | //fprintf(stderr, "Looking for polycos with src='%s' imjd=%d fmjd=%f\n", 115 | // tmp, imjd, fmjd); 116 | for (ipc=0; ipcmjd)+(fmjd-pc->fmjd)); 130 | int i; 131 | double phase = pc->c[pc->nc-1]; 132 | double f = 0.0; 133 | if (fabs(dt)>(double)pc->nmin/2.0) { return(-1.0); } 134 | for (i=pc->nc-1; i>0; i--) { 135 | phase = dt*(phase) + pc->c[i-1]; 136 | f = dt*(f) + (double)i*pc->c[i]; 137 | } 138 | f = pc->f0 + (1.0/60.0)*f; 139 | phase += pc->rphase + dt*60.0*pc->f0; 140 | if (freq!=NULL) { *freq = f; } 141 | if (pulsenum!=NULL) { 142 | long long n = pc->rphase_int; 143 | n += (long long)(phase - fmod(phase,1.0)); 144 | phase = fmod(phase,1.0); 145 | if (phase<0.0) { phase += 1.0; n--; } 146 | *pulsenum = n; 147 | } 148 | return(phase); 149 | } 150 | 151 | double psr_fdot(const struct polyco *pc, int mjd, double fmjd, double *fdot) { 152 | double dt = 1440.0*((double)(mjd-pc->mjd)+(fmjd-pc->fmjd)); 153 | if (fabs(dt)>(double)pc->nmin/2.0) { return(-1.0); } 154 | double fd=0.0; 155 | int i; 156 | for (i=pc->nc-1; i>1; i--) { 157 | fd = dt*fd + ((double)i)*((double)i-1.0)*pc->c[i]; 158 | } 159 | fd /= 60.0; 160 | if (fdot!=NULL) { *fdot=fd; } 161 | return(fd); 162 | } 163 | 164 | double psr_phase_avg(const struct polyco *pc, int mjd, 165 | double fmjd1, double fmjd2) { 166 | double dt1 = 1440.0*((double)(mjd-pc->mjd)+(fmjd1-pc->fmjd)); 167 | double dt2 = 1440.0*((double)(mjd-pc->mjd)+(fmjd2-pc->fmjd)); 168 | if (fabs(dt1)>(double)pc->nmin/2.0) { return(-1.0); } 169 | if (fabs(dt2)>(double)pc->nmin/2.0) { return(-1.0); } 170 | double pavg; 171 | int i; 172 | double tmp1=0.0, tmp2=0.0; 173 | for (i=pc->nc-1; i>=0; i--) { 174 | tmp1 = dt1*tmp1 + pc->c[i]/((double)i+1.0); 175 | tmp2 = dt2*tmp2 + pc->c[i]/((double)i+1.0); 176 | } 177 | tmp1 *= dt1; tmp2 *= dt2; 178 | pavg = (tmp2-tmp1)/(dt2-dt1) + pc->rphase + (dt1+dt2)*60.0*pc->f0/2.0; 179 | return(pavg); 180 | } 181 | 182 | int pc_range_check(const struct polyco *pc, int mjd, double fmjd) { 183 | double dt; 184 | dt = (double)(mjd - pc->mjd) + (fmjd - pc->fmjd); 185 | dt *= 1440.0; 186 | if (dt < -1.0*(double)pc->nmin/2.0) { return(-1); } 187 | else if (dt > (double)pc->nmin/2.0) { return(1); } 188 | else { return(0); } 189 | } 190 | 191 | int pc_out_of_range(const struct polyco *pc, int mjd, double fmjd) { 192 | double dt; 193 | dt = (double)(mjd - pc->mjd) + (fmjd - pc->fmjd); 194 | dt *= 1440.0; 195 | if (fabs(dt)>(double)pc->nmin/2.0) { return(1); } 196 | return(0); 197 | } 198 | 199 | int pc_out_of_range_sloppy(const struct polyco *pc, int mjd, double fmjd, 200 | double slop) { 201 | double dt; 202 | dt = (double)(mjd - pc->mjd) + (fmjd - pc->fmjd); 203 | dt *= 1440.0; 204 | if (fabs(dt)>slop*(double)pc->nmin/2.0) { return(1); } 205 | return(0); 206 | } 207 | 208 | /* Check whether or not two polyco structs are the same */ 209 | int polycos_differ(const struct polyco *p1, const struct polyco *p2) { 210 | // Could add more tests as needed 211 | if (strncmp(p1->psr, p2->psr,15)!=0) return(1); 212 | if (p1->mjd!=p2->mjd) return(1); 213 | if (p1->fmjd!=p2->fmjd) return(1); 214 | if (p1->rf!=p2->rf) return(1); 215 | if (p1->nsite!=p2->nsite) return(1); 216 | if (p1->nmin!=p2->nmin) return(1); 217 | if (p1->nc!=p2->nc) return(1); 218 | return(0); 219 | } 220 | 221 | /* Convert telescope name to tempo code */ 222 | char telescope_name_to_code(const char *name) { 223 | 224 | /* Assume a 1-char input is already a code */ 225 | if (strlen(name)==1) { return(name[0]); } 226 | 227 | /* Add to these as needed .. */ 228 | if (strcasecmp(name, "GBT")==0) return('1'); 229 | 230 | if (strcasecmp(name, "GB43m")==0) return('a'); 231 | if (strcasecmp(name, "GB 43m")==0) return('a'); 232 | if (strncasecmp(name, "GB140",5)==0) return('a'); 233 | if (strncasecmp(name, "GB 140",6)==0) return('a'); 234 | if (strncasecmp(name, "NRAO20",6)==0) return('a'); 235 | 236 | if (strncasecmp(name, "Arecibo",7)==0) return('3'); 237 | if (strcasecmp(name, "AO")==0) return('3'); 238 | 239 | if (strcasecmp(name, "SHAO")==0) return('s'); 240 | 241 | if (strcasecmp(name, "VLA")==0) return('6'); 242 | 243 | /* Not found, return null */ 244 | return('\0'); 245 | } 246 | 247 | /* Generate polycos from a parfile */ 248 | #define make_polycos_cleanup() do {\ 249 | unlink("pulsar.par");\ 250 | unlink("polyco.dat");\ 251 | unlink("tz.in");\ 252 | chdir(origdir);\ 253 | free(origdir);\ 254 | rmdir(tmpdir);\ 255 | } while (0) 256 | int make_polycos(const char *parfile, struct hdrinfo *hdr, 257 | char *src, struct polyco **pc) { 258 | 259 | /* Open parfile */ 260 | FILE *pf = fopen(parfile, "r"); 261 | if (pf==NULL) { 262 | fprintf(stderr, "make_polycos: Error opening parfile %s\n", parfile); 263 | return(-1); 264 | } 265 | 266 | /* Generate temp directory */ 267 | char tmpdir[] = "/tmp/polycoXXXXXX"; 268 | if (mkdtemp(tmpdir)==NULL) { 269 | fprintf(stderr, "make_polycos: Error generating temp dir.\n"); 270 | fclose(pf); 271 | return(-1); 272 | } 273 | 274 | /* change to temp dir */ 275 | char *origdir = getcwd(NULL,0); 276 | chdir(tmpdir); 277 | 278 | /* Open temp dir */ 279 | char fname[256]; 280 | sprintf(fname, "%s/pulsar.par", tmpdir); 281 | FILE *fout = fopen(fname, "w"); 282 | if (fout==NULL) { 283 | fprintf(stderr, "make_polycos: Error writing to temp dir.\n"); 284 | fclose(pf); 285 | make_polycos_cleanup(); 286 | return(-1); 287 | } 288 | 289 | /* Get source name, copy file */ 290 | char line[256], parsrc[32]="", *key, *val, *saveptr, *ptr; 291 | while (fgets(line,256,pf)!=NULL) { 292 | fprintf(fout, "%s", line); 293 | while ((ptr=strchr(line,'\t'))!=NULL) *ptr=' '; 294 | if ((ptr=strrchr(line,'\n')) != NULL) *ptr='\0'; 295 | key = strtok_r(line, " ", &saveptr); 296 | val = strtok_r(NULL, " ", &saveptr); 297 | if (key==NULL || val==NULL) continue; 298 | if (strncmp(key, "PSR", 3)==0) { 299 | // J or B is bad here? 300 | if (val[0]=='J' || val[0]=='B') val++; 301 | strcpy(parsrc, val); 302 | } 303 | } 304 | fclose(pf); 305 | fclose(fout); 306 | if (parsrc[0]=='\0') { 307 | fprintf(stderr, "make_polycos: Couldn't find source name in %s\n", 308 | parfile); 309 | make_polycos_cleanup(); 310 | return(-1); 311 | } 312 | if (src!=NULL) { strcpy(src,parsrc); } 313 | 314 | /* Get telescope character */ 315 | char tcode = telescope_name_to_code(hdr->telescope); 316 | if (tcode=='\0') { 317 | fprintf(stderr, "make_polycos: Unrecognized telescope name (%s)\n", 318 | hdr->telescope); 319 | make_polycos_cleanup(); 320 | return(-1); 321 | } 322 | 323 | /* Write tz.in */ 324 | sprintf(fname, "%s/tz.in", tmpdir); 325 | fout = fopen(fname, "w"); 326 | if (fout==NULL) { 327 | fprintf(stderr, "make_polycos: Error opening tz.in for write.\n"); 328 | make_polycos_cleanup(); 329 | return(-1); 330 | } 331 | fprintf(fout, "%c 12 30 15 %.5f\n\n\n%s\n", 332 | tcode, hdr->fctr, parsrc); 333 | fclose(fout); 334 | 335 | /* Call tempo */ 336 | int mjd0, mjd1; 337 | mjd0 = (int)hdr->MJD_epoch; 338 | mjd1 = (int)(hdr->MJD_epoch + hdr->scanlen/86400.0 + 0.5); 339 | if (mjd1==mjd0) mjd1++; 340 | sprintf(line, "echo %d %d | tempo -z -f pulsar.par > /dev/null", 341 | mjd0-1, mjd1); 342 | system(line); 343 | 344 | /* Read polyco file */ 345 | FILE *pcfile = fopen("polyco.dat", "r"); 346 | if (pcfile==NULL) { 347 | fprintf(stderr, "make_polycos: Error reading polyco.dat\n"); 348 | make_polycos_cleanup(); 349 | return(-1); 350 | } 351 | int npc = read_all_pc(pcfile, pc); 352 | fclose(pcfile); 353 | 354 | /* Clean up */ 355 | make_polycos_cleanup(); 356 | 357 | return(npc); 358 | } 359 | 360 | -------------------------------------------------------------------------------- /combine_mocks.c: -------------------------------------------------------------------------------- 1 | //This code combines the two frequency bands from the Mock 2 | //spectrometers at Arecibo. K. Stovall Oct 2010 3 | 4 | #include 5 | #include 6 | #include 7 | #include 8 | #include 9 | #include 10 | #include "psrfits.h" 11 | #include "combine_mocks_cmd.h" 12 | 13 | static void print_percent_complete(int current, int number, int reset) 14 | { 15 | static int newper = 0, oldper = -1; 16 | 17 | if (reset) { 18 | oldper = -1; 19 | newper = 0; 20 | } else { 21 | newper = (int) (current / (float) (number) * 100.0); 22 | if (newper < 0) 23 | newper = 0; 24 | if (newper > 100) 25 | newper = 100; 26 | if (newper > oldper) { 27 | printf("\r%3d%% ", newper); 28 | fflush(stdout); 29 | oldper = newper; 30 | } 31 | } 32 | } 33 | 34 | //Routine taken from PRESTO 35 | void avg_var(float *x, int n, double *mean, double *var) 36 | /* For a float vector, *x, of length n, this routine */ 37 | /* returns the mean and variance of *x. */ 38 | { 39 | long i; 40 | double an = 0.0, an1 = 0.0, dx; 41 | 42 | /* Modified (29 June 98) C version of the following: */ 43 | /* ALGORITHM AS 52 APPL. STATIST. (1972) VOL.21, P.226 */ 44 | /* Returned values were checked with Mathematica 3.01 */ 45 | 46 | if (n < 1) { 47 | printf("\vVector length must be > 0 in avg_var(). Exiting\n"); 48 | exit(1); 49 | } else { 50 | *mean = (double) x[0]; 51 | *var = 0.0; 52 | } 53 | 54 | for (i = 1; i < n; i++) { 55 | an = (double) (i + 1); 56 | an1 = (double) (i); 57 | dx = (x[i] - *mean) / an; 58 | *var += an * an1 * dx * dx; 59 | *mean += dx; 60 | } 61 | 62 | if (n > 1) 63 | *var /= an1; 64 | 65 | return; 66 | } 67 | 68 | //End of routine taken from PRESTO 69 | 70 | int main(int argc, char *argv[]) 71 | { 72 | Cmdline *cmd; 73 | struct psrfits pfupper, pflower, pfo; 74 | fitsfile *infits, *outfits; 75 | char *pc1, *pc2; 76 | char outfilename[200]; //Name of outfile if not specified on command line 77 | int stat = 0, padding = 0, userN = 0, status; 78 | 79 | // Call usage() if we have no command line arguments 80 | if (argc == 1) { 81 | Program = argv[0]; 82 | usage(); 83 | exit(0); 84 | } 85 | // Parse the command line using the excellent program Clig 86 | cmd = parseCmdline(argc, argv); 87 | 88 | pfupper.tot_rows = pfupper.N = pfupper.T = pfupper.status = 0; //Initialize upper band 89 | pflower.tot_rows = pflower.N = pflower.T = pflower.status = 0; //Initialize lower band 90 | pfo.tot_rows = pfo.N = pfo.T = pfo.status = pfo.multifile = 0; //Initialize output 91 | 92 | psrfits_set_files(&pflower, 1, &cmd->argv[1]); 93 | psrfits_set_files(&pfupper, 1, &cmd->argv[0]); 94 | 95 | int rv = psrfits_open(&pfupper); //Open upper band 96 | if (rv) { 97 | fits_report_error(stderr, rv); 98 | exit(1); 99 | } 100 | rv = psrfits_open(&pflower); //Open lower band 101 | if (rv) { 102 | fits_report_error(stderr, rv); 103 | exit(1); 104 | } 105 | pfo = pflower; //Copy all lower band variables into the output struct 106 | if (!cmd->outputbasenameP) { 107 | //Setting the name of the output file, setting as same name as input file, but removing s0/s1. 108 | pc1 = strstr(pflower.filename, "s1"); 109 | pc2 = strrchr(pflower.filename, '.'); //At '.fits' 110 | pc2--; 111 | while ((pc2 >= pflower.filename) && isdigit(*pc2)) //Move through the digits to the separation char. 112 | pc2--; 113 | strncpy(outfilename, pflower.filename, pc1 - pflower.filename); //Copy everything up to s1 into outfilename 114 | printf("outfilename = '%s'\n", outfilename); 115 | strncpy(outfilename + (pc1 - pflower.filename), pc1 + 2, pc2 - pc1 - 2); //Concatenate from after s1 to char before the separation char. 116 | printf("2 outfilename = '%s'\n", outfilename); 117 | pc1 = outfilename + (pc2 - pflower.filename - 2); 118 | *pc1 = 0; 119 | sprintf(pfo.basefilename, basename(outfilename)); 120 | } else 121 | sprintf(pfo.basefilename, cmd->outputbasename); 122 | pfo.numfiles = 0; 123 | pfo.filenum = 0; 124 | sprintf(pfo.filename, "\0"); //Set filename to null so psrfits_open will create the filename for me 125 | pfo.rownum = 1; 126 | pfo.tot_rows = 0; 127 | pfo.N = 0; 128 | if (pfupper.rows_per_file != pflower.rows_per_file) { //Sanity check for the two input frequency bands 129 | fprintf(stderr, "rows_per_file in input files do not match!\n"); 130 | exit(1); 131 | } 132 | 133 | double upperfreqoflower, nextfromlower, lowerfreqofupper, numchandiff; //Used to find which frequencies to take from each band 134 | double offsetfactor, scalefactor; //Factors which will be applied to offsets and scales 135 | int upchanskip, lowchanskip; //Number of channels to skip in each banda 136 | 137 | //Variables used to make code cleaner 138 | int extrachanoffset, outoffset, upperoffset, numtocopyupper, loweroffset_skip, 139 | loweroffset, numtocopylower, newuppernchan, newlowernchan; 140 | double df = pflower.hdr.df; 141 | int nchan = pflower.hdr.nchan; 142 | int outnchan; 143 | int npol = pflower.hdr.npol; 144 | int nbits = pflower.hdr.nbits; 145 | int nsblk = pflower.hdr.nsblk; 146 | //Allocate memory for all upper and lower data 147 | pflower.sub.dat_freqs = (float *) malloc(sizeof(float) * nchan); 148 | pflower.sub.dat_weights = (float *) malloc(sizeof(float) * nchan); 149 | pflower.sub.dat_offsets = (float *) malloc(sizeof(float) * nchan * npol); 150 | pflower.sub.dat_scales = (float *) malloc(sizeof(float) * nchan * npol); 151 | pflower.sub.rawdata = (unsigned char *) malloc(pflower.sub.bytes_per_subint); 152 | pflower.sub.data = (unsigned char *) malloc(pflower.sub.bytes_per_subint*2); 153 | 154 | pfupper.sub.dat_freqs = (float *) malloc(sizeof(float) * nchan); 155 | pfupper.sub.dat_weights = (float *) malloc(sizeof(float) * nchan); 156 | pfupper.sub.dat_offsets = (float *) malloc(sizeof(float) * nchan * npol); 157 | pfupper.sub.dat_scales = (float *) malloc(sizeof(float) * nchan * npol); 158 | pfupper.sub.rawdata = (unsigned char *) malloc(pfupper.sub.bytes_per_subint); 159 | pfupper.sub.data = (unsigned char *) malloc(pfupper.sub.bytes_per_subint*2); 160 | 161 | int firsttime = 1; //First time through do while loop 162 | do { 163 | print_percent_complete(pflower.rownum, pflower.rows_per_file, 164 | pflower.rownum == 1 ? 1 : 0); 165 | psrfits_read_subint(&pflower); 166 | psrfits_read_subint(&pfupper); 167 | if (firsttime) { //First time through loop, calculate factors for scales and offsets and number of channels to skip 168 | firsttime = 0; 169 | //Find the number of channels in the upper band which will be skipped 170 | if (df < 0) { //Find channel order, low to high or high to low 171 | upperfreqoflower = pflower.sub.dat_freqs[0]; //Highest frequency channel in lower band 172 | lowerfreqofupper = pfupper.sub.dat_freqs[nchan - 1]; //Lowest frequency channel in upper band 173 | } else { 174 | upperfreqoflower = pflower.sub.dat_freqs[nchan - 1]; //Highest frequency channel in lower band 175 | lowerfreqofupper = pfupper.sub.dat_freqs[0]; //Lowest frequency channel in upper band 176 | } 177 | nextfromlower = upperfreqoflower + fabs(df); //Second highest channel in lower band 178 | numchandiff = (nextfromlower - lowerfreqofupper) / fabs(df); //Number of channels to skip in float form 179 | int chanskip; 180 | if (numchandiff > 0) { //Make sure there are channels which need to be skipped 181 | if (numchandiff - (double) ((int) numchandiff) > .5) // See whether we need to round up integer channels to skip 182 | chanskip = (int) numchandiff + 1; 183 | else 184 | chanskip = (int) numchandiff; 185 | } else 186 | chanskip = 0; //No need to skip any channels 187 | if (chanskip % 2 == 1) { //Odd number of channels, give lower band the extra channel 188 | upchanskip = chanskip / 2; 189 | lowchanskip = chanskip / 2 + 1; 190 | } else //Even number of channels to skip 191 | upchanskip = lowchanskip = chanskip / 2; 192 | if (upchanskip % 2 == 1) { //We want an even number of channels in upper band for 4-bit data to get copied correctly 193 | ++lowchanskip; 194 | --upchanskip; 195 | } 196 | //Find new values given the number of channels skipped 197 | pfo.hdr.nchan = outnchan = nchan + nchan - chanskip + 2; //New number of channels, plus 2 to make nchan=960 (many factors of 2) 198 | pfo.hdr.BW = (double) outnchan *fabs(df); //New bandwidth 199 | pfo.hdr.fctr = //New center frequency 200 | (pflower.hdr.fctr - (double) (nchan / 2) * fabs(df)) + pfo.hdr.BW / 2.0; 201 | pfo.sub.bytes_per_subint = //Calculate new number of bytes in each subint 202 | outnchan * nsblk * nbits / 8 * npol; 203 | //Allocate space for output data now that we know the new number of channels 204 | pfo.sub.dat_freqs = (float *) malloc(sizeof(float) * outnchan); 205 | pfo.sub.dat_weights = (float *) malloc(sizeof(float) * outnchan); 206 | pfo.sub.dat_offsets = (float *) malloc(sizeof(float) * outnchan * npol); 207 | pfo.sub.dat_scales = (float *) malloc(sizeof(float) * outnchan * npol); 208 | pfo.sub.rawdata = (unsigned char *) malloc(pfo.sub.bytes_per_subint); 209 | pfo.sub.data = (unsigned char *) malloc(pfo.sub.bytes_per_subint*2); 210 | newuppernchan = nchan - upchanskip; //The number of channels to copy from the upper sideband. 211 | newlowernchan = nchan - lowchanskip; //The number of channels to copy from the lower sideband. 212 | 213 | extrachanoffset = 2; //Offset for 2 extra freq channels making nchan 960 in bytes 214 | outoffset = (outnchan * npol); //Offset in each loop due to previously written data 215 | upperoffset = (nchan * npol); //Offset in loop for upper band 216 | numtocopyupper = (newuppernchan * npol); //Number of bytes to copy from upper band 217 | loweroffset_skip = (lowchanskip * npol); //Number of bytes to skip when copying lower band due to 218 | //having written upper band 219 | loweroffset = //Number of bytes to skip due to having written previous lower band data 220 | (nchan * npol); 221 | numtocopylower = (newlowernchan * npol); //Number of bytes to copy from lower band 222 | double upmean, upvar, lowmean, lowvar; 223 | avg_var(pfupper.sub.dat_offsets + (nchan - upchanskip), //Find the mean and variance of the upper band's offsets 224 | upchanskip, &upmean, &upvar); 225 | printf("Upper offset stats: mean=%f variance=%f\n", upmean, upvar); 226 | avg_var(pflower.sub.dat_offsets, lowchanskip, &lowmean, &lowvar); //Find the mean and variance of the lower band's offsets 227 | printf("Lower offset stats: mean=%f variance=%f\n", lowmean, lowvar); 228 | printf("Applying factor of %f to upper offsets\n", (lowmean / upmean)); 229 | offsetfactor = lowmean / upmean; //Set offset factor used to correct variance differences in the two bands 230 | avg_var(pfupper.sub.dat_scales + (nchan - upchanskip), //Find the mean and var. of the upper band's scales 231 | upchanskip, &upmean, &upvar); 232 | printf("Upper scales stats: mean=%f variance=%f\n", upmean, upvar); 233 | avg_var(pflower.sub.dat_scales, lowchanskip, &lowmean, &lowvar); //Find the mean and var. of the lower band's scales 234 | printf("Lower scales stats: mean=%f variance=%f\n", lowmean, lowvar); 235 | printf("Applying factor of %f to upper scales\n", (lowmean / upmean)); 236 | scalefactor = lowmean / upmean; //Set scale factor used to correct variance differences in the two bands 237 | } 238 | if (pflower.status == 0 && pfupper.status == 0) { 239 | //Copy info from the lower band subint struct to the output file's subint struct 240 | pfo.sub.tsubint = pflower.sub.tsubint; 241 | pfo.sub.offs = pflower.sub.offs; 242 | pfo.sub.lst = pflower.sub.lst; 243 | pfo.sub.ra = pflower.sub.ra; 244 | pfo.sub.dec = pflower.sub.dec; 245 | pfo.sub.glon = pflower.sub.glon; 246 | pfo.sub.glat = pflower.sub.glat; 247 | pfo.sub.feed_ang = pflower.sub.feed_ang; 248 | pfo.sub.pos_ang = pflower.sub.pos_ang; 249 | pfo.sub.par_ang = pflower.sub.par_ang; 250 | pfo.sub.tel_az = pflower.sub.tel_az; 251 | pfo.sub.tel_zen = pflower.sub.tel_zen; 252 | pfo.sub.FITS_typecode = pflower.sub.FITS_typecode; 253 | 254 | //Create variables to reduce column width of lines below 255 | float *dat_freqs = pfo.sub.dat_freqs; 256 | float *udat_freqs = pfupper.sub.dat_freqs; 257 | float *ldat_freqs = pflower.sub.dat_freqs; 258 | float *dat_weights = pfo.sub.dat_weights; 259 | float *udat_weights = pfupper.sub.dat_weights; 260 | float *ldat_weights = pflower.sub.dat_weights; 261 | float *dat_offsets = pfo.sub.dat_offsets; 262 | float *udat_offsets = pfupper.sub.dat_offsets; 263 | float *ldat_offsets = pflower.sub.dat_offsets; 264 | float *dat_scales = pfo.sub.dat_scales; 265 | float *udat_scales = pfupper.sub.dat_scales; 266 | float *ldat_scales = pflower.sub.dat_scales; 267 | unsigned char *data = pfo.sub.data; 268 | unsigned char *udata = pfupper.sub.data; 269 | unsigned char *ldata = pflower.sub.data; 270 | 271 | if (df < 0) { 272 | //Copy frequency labels 273 | dat_freqs[1] = udat_freqs[0] + fabs(df); //Calculate the frequency labels 274 | dat_freqs[0] = dat_freqs[1] + fabs(df); //for our two empty frequency channels 275 | int newuppernchan = nchan - upchanskip; //The number of channels to copy from the upper band 276 | int newlowernchan = nchan - lowchanskip; //The number of channels to copy from the lower band 277 | memcpy(dat_freqs + 2, udat_freqs, sizeof(float) * newuppernchan); //Copy from the upper band, skipping first two chans. 278 | memcpy(dat_freqs + newuppernchan + 2, //Copy from the lower band 279 | ldat_freqs + lowchanskip, sizeof(float) * newlowernchan); 280 | //Copy weights 281 | dat_weights[0] = dat_weights[1] = 0; //Set the weights of first two channels to 0, so they shouldn't be used in calculations 282 | memcpy(dat_weights + 2, udat_weights, //Copy weights from the upper band 283 | sizeof(float) * newuppernchan); 284 | memcpy(dat_weights + 2 + newuppernchan, //Copy weights from the lower band 285 | ldat_weights + lowchanskip, sizeof(float) * newlowernchan); 286 | //Copy offsets 287 | dat_offsets[0] = dat_offsets[1] = //Set offsets of first two channels to the same as upper's first channel 288 | udat_offsets[0]; //(shouldn't matter since they should be ignored) 289 | int ii; 290 | for (ii = 0; ii < newuppernchan; ++ii) //Apply offset factor to upper band 291 | udat_offsets[ii] = udat_offsets[ii] * (offsetfactor); 292 | memcpy(dat_offsets + 2 * npol, udat_offsets, //Copy upper offsets 293 | sizeof(float) * newuppernchan * npol); 294 | memcpy(dat_offsets + (newuppernchan + 2) * npol, //Copy lower offsets 295 | ldat_offsets + lowchanskip, sizeof(float) * newlowernchan * npol); 296 | //Copy scales 297 | for (ii = 0; ii < newuppernchan; ++ii) //Apply scale factor to upper band 298 | udat_scales[ii] = udat_scales[ii] * (scalefactor); 299 | dat_scales[0] = dat_scales[1] = udat_scales[0]; 300 | memcpy(dat_scales + 2 * npol, udat_scales, //Copy upper scales 301 | sizeof(float) * newuppernchan * npol); 302 | memcpy(dat_scales + (newuppernchan + 2) * npol, //Copy lower scales 303 | ldat_scales + lowchanskip, sizeof(float) * newlowernchan * npol); 304 | //Copy the data 305 | for (ii = 0; ii < nsblk; ++ii) { //Loop through data copying into place 306 | memcpy(data + ii * outoffset + extrachanoffset, 307 | udata + ii * upperoffset, numtocopyupper); 308 | memcpy(data + ii * outoffset + extrachanoffset + 309 | numtocopyupper, 310 | ldata + ii * loweroffset + loweroffset_skip, numtocopylower); 311 | } 312 | psrfits_write_subint(&pfo); 313 | } else { 314 | } 315 | } 316 | } while (pfo.rownum <= pfo.rows_per_file); 317 | printf("Closing file '%s'\n", pflower.filename); 318 | fits_close_file(pfupper.fptr, &status); 319 | printf("Closing file '%s'\n", pfupper.filename); 320 | fits_close_file(pflower.fptr, &status); 321 | exit(0); 322 | } 323 | -------------------------------------------------------------------------------- /mpimerge_psrfits.c: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | #include 5 | #include 6 | #include "psrfits.h" 7 | #include "mpi.h" 8 | 9 | #define HDRLEN 14400 10 | #define FLAG 9e9 11 | 12 | void reorder_data(unsigned char* outbuf, unsigned char *inbuf, 13 | int nband, int nspec, int npol, int nchan) 14 | { 15 | int band, spec, pol, inoff = 0, outoff = 0; 16 | int spband = nspec * npol * nchan; 17 | int spspec = npol * nchan; 18 | 19 | for (spec = 0 ; spec < nspec ; spec++) { 20 | for (pol = 0 ; pol < npol ; pol++) { 21 | for (band = 0 ; band < nband ; band++) { 22 | inoff = band * spband + pol * nchan + spec * spspec; 23 | memcpy(outbuf + outoff, inbuf + inoff, nchan); 24 | outoff += nchan; 25 | } 26 | } 27 | } 28 | } 29 | 30 | void usage() { 31 | printf("usage: mpimerge_psrfits [optios] basefilename\n" 32 | "Options:\n" 33 | " -o name, --output=name Output base filename (auto-generate)\n" 34 | " -i nn, --initial=nn Starting input file number (1)\n" 35 | " -f nn, --final=nn Ending input file number (auto)\n" 36 | " -s nn, --starthpc=nn hpc ID for first file\n" 37 | " -V dir, --vegas=dir Use VEGAS filenames, in specified dir\n" 38 | " -r, --reverse Combine files in reverse order\n" 39 | "\n"); 40 | } 41 | 42 | 43 | int main(int argc, char *argv[]) 44 | { 45 | int ii, ipol, nc = 0, ncnp = 0, gpubps = 0, status = 0, statsum = 0; 46 | int fnum_start = 1, fnum_end = 0; 47 | int numprocs, numbands, myid, baddata = 0, droppedrow = 0; 48 | int *counts, *offsets; 49 | unsigned char *tmpbuf = NULL; 50 | struct psrfits pf; 51 | struct { 52 | double value; 53 | int index; 54 | } offs_in, offs_out; 55 | char hostname[256]; 56 | char vegas_base_dir[256] = "\0"; 57 | char output_base[256] = "\0"; 58 | int starthpc = 0; 59 | int reverse = 0; 60 | MPI_Status mpistat; 61 | /* Cmd line */ 62 | static struct option long_opts[] = { 63 | {"output", 1, NULL, 'o'}, 64 | {"initial", 1, NULL, 'i'}, 65 | {"final", 1, NULL, 'f'}, 66 | {"vegas", 1, NULL, 'V'}, 67 | {"starthpc",1, NULL, 's'}, 68 | {"reverse" ,0, NULL, 'r'}, 69 | {0,0,0,0} 70 | }; 71 | int opt, opti; 72 | 73 | MPI_Init(&argc, &argv); 74 | MPI_Comm_size(MPI_COMM_WORLD, &numprocs); 75 | MPI_Comm_rank(MPI_COMM_WORLD, &myid); 76 | numbands = numprocs - 1; 77 | 78 | // Process the command line 79 | while ((opt=getopt_long(argc,argv,"o:i:f:V:s:r",long_opts,&opti))!=-1) { 80 | switch (opt) { 81 | case 'o': 82 | strncpy(output_base, optarg, 255); 83 | output_base[255]='\0'; 84 | break; 85 | case 'i': 86 | fnum_start = atoi(optarg); 87 | break; 88 | case 'f': 89 | fnum_end = atoi(optarg); 90 | break; 91 | case 'V': 92 | strcpy(vegas_base_dir, optarg); 93 | break; 94 | case 's': 95 | starthpc = atoi(optarg); 96 | break; 97 | case 'r': 98 | reverse = 1; 99 | break; 100 | default: 101 | if (myid==0) usage(); 102 | MPI_Finalize(); 103 | exit(0); 104 | break; 105 | } 106 | } 107 | if (optind==argc) { 108 | if (myid==0) usage(); 109 | MPI_Finalize(); 110 | exit(1); 111 | } 112 | 113 | if (myid == 0) { // Master proc only 114 | printf("\n\n"); 115 | printf(" MPI Search-mode PSRFITs Combiner\n"); 116 | printf(" by Scott M. Ransom\n\n"); 117 | } 118 | 119 | // Determine the hostnames of the processes 120 | { 121 | if (gethostname(hostname, 255) < 0) 122 | strcpy(hostname, "unknown"); 123 | 124 | MPI_Barrier(MPI_COMM_WORLD); 125 | if (myid == 0) printf("\n"); 126 | fflush(NULL); 127 | for (ii = 0 ; ii < numprocs ; ii++) { 128 | MPI_Barrier(MPI_COMM_WORLD); 129 | if (myid == ii) 130 | printf("Process %3d is on machine %s\n", myid, hostname); 131 | fflush(NULL); 132 | MPI_Barrier(MPI_COMM_WORLD); 133 | } 134 | MPI_Barrier(MPI_COMM_WORLD); 135 | fflush(NULL); 136 | } 137 | 138 | // Basefilenames for the GPU nodes 139 | if (myid > 0) { 140 | 141 | // Default to GUPPI mode 142 | if (vegas_base_dir[0]=='\0') 143 | sprintf(pf.basefilename, "/data/gpu/partial/%s/%s", 144 | hostname, argv[optind]); 145 | 146 | // VEGAS mode 147 | else { 148 | 149 | int hpcidx; 150 | if (reverse) 151 | hpcidx = starthpc - myid + 1; 152 | else 153 | hpcidx = myid + starthpc - 1; 154 | 155 | sprintf(pf.basefilename, "%s/vegas-hpc%d-bdata1/%s", 156 | vegas_base_dir, hpcidx, argv[optind]); 157 | 158 | printf("**********: hostname = %s, myid = %d, datamnt = %d, basename=%s\n", 159 | hostname, myid, hpcidx, pf.basefilename); 160 | 161 | } 162 | } 163 | 164 | // Initialize some key parts of the PSRFITS structure 165 | pf.tot_rows = pf.N = pf.T = pf.status = 0; 166 | pf.filenum = fnum_start; 167 | pf.filename[0] = '\0'; 168 | pf.filenames = NULL; 169 | pf.numfiles = 0; 170 | 171 | if (myid == 1) { 172 | FILE *psrfitsfile; 173 | char hdr[HDRLEN], filenm[200]; 174 | 175 | // Read the header info 176 | sprintf(filenm, "%s_0001.fits", pf.basefilename); 177 | psrfitsfile = fopen(filenm, "r"); 178 | fread(&hdr, 1, HDRLEN, psrfitsfile); 179 | fclose(psrfitsfile); 180 | 181 | // Send the header to the master proc 182 | MPI_Send(hdr, HDRLEN, MPI_CHAR, 0, 0, MPI_COMM_WORLD); 183 | 184 | } else if (myid == 0) { 185 | FILE *psrfitsfile; 186 | char hdr[HDRLEN], tmpfilenm[80]; 187 | 188 | // Receive the header info from proc 1 189 | MPI_Recv(hdr, HDRLEN, MPI_CHAR, 1, 0, MPI_COMM_WORLD, &mpistat); 190 | 191 | // Now write that header to a temp file 192 | strcpy(tmpfilenm, "mpi_merge_psrfits.XXXXXX"); 193 | mkstemp(tmpfilenm); 194 | psrfitsfile = fopen(tmpfilenm, "w"); 195 | fwrite(&hdr, 1, HDRLEN, psrfitsfile); 196 | fclose(psrfitsfile); 197 | pf.filenames = (char **)malloc(sizeof(char *)); 198 | pf.filenames[0] = tmpfilenm; 199 | pf.basefilename[0]='\0'; 200 | pf.filenum = 0; 201 | pf.numfiles = 1; 202 | 203 | // And read the key information into a PSRFITS struct 204 | status = psrfits_open(&pf); 205 | status = psrfits_close(&pf); 206 | free(pf.filenames); 207 | remove(tmpfilenm); 208 | 209 | // Now create the output PSTFITS file 210 | if (output_base[0]=='\0') { 211 | /* Set up default output filename */ 212 | strcpy(output_base, argv[optind]); 213 | } 214 | strcpy(pf.basefilename, output_base); 215 | pf.multifile = 1; 216 | pf.filenum = 0; 217 | pf.numfiles = 0; 218 | pf.filename[0] = '\0'; 219 | pf.filenames = NULL; 220 | nc = pf.hdr.nchan; 221 | ncnp = pf.hdr.nchan * pf.hdr.npol; 222 | gpubps = pf.sub.bytes_per_subint; 223 | pf.hdr.orig_nchan *= numbands; 224 | pf.hdr.nchan *= numbands; 225 | pf.hdr.fctr = pf.hdr.fctr - 0.5 * pf.hdr.BW + numbands/2.0 * pf.hdr.BW; 226 | pf.hdr.BW *= numbands; 227 | pf.sub.bytes_per_subint *= numbands; 228 | long long filelen = 40 * (1L<<30); // In GB 229 | pf.rows_per_file = filelen / pf.sub.bytes_per_subint; 230 | status = psrfits_create(&pf); 231 | // For in-memory transpose of data 232 | tmpbuf = (unsigned char *)malloc(pf.sub.bytes_per_subint); 233 | } 234 | 235 | // Open the input PSRFITs files for real 236 | if (myid > 0) { 237 | status = psrfits_open(&pf); 238 | nc = pf.hdr.nchan; 239 | ncnp = pf.hdr.nchan * pf.hdr.npol; 240 | gpubps = pf.sub.bytes_per_subint; 241 | } 242 | 243 | // Alloc data buffers for the PSRFITS files 244 | pf.sub.dat_freqs = (float *)malloc(sizeof(float) * pf.hdr.nchan); 245 | pf.sub.dat_weights = (float *)malloc(sizeof(float) * pf.hdr.nchan); 246 | pf.sub.dat_offsets = (float *)malloc(sizeof(float) * 247 | pf.hdr.nchan * pf.hdr.npol); 248 | pf.sub.dat_scales = (float *)malloc(sizeof(float) * 249 | pf.hdr.nchan * pf.hdr.npol); 250 | pf.sub.data = (unsigned char *)malloc(pf.sub.bytes_per_subint); 251 | pf.sub.rawdata = pf.sub.data; 252 | 253 | // Counts and offsets for MPI_Gatherv 254 | counts = (int *)malloc(sizeof(int) * numprocs); 255 | offsets = (int *)malloc(sizeof(int) * numprocs); 256 | counts[0] = offsets[0] = 0; // master sends nothing 257 | 258 | // Now loop over the rows (i.e. subints)... 259 | do { 260 | MPI_Barrier(MPI_COMM_WORLD); 261 | 262 | // Read the current subint from each of the "slave" nodes 263 | if ((myid > 0) && (!baddata)) { 264 | status = psrfits_read_subint(&pf); 265 | if (status) { 266 | pf.sub.offs = FLAG; // High value so it won't be min 267 | if (pf.rownum > pf.rows_per_file) { 268 | // Shouldn't be here unless opening of new file failed... 269 | printf("Proc %d: Can't open next file. Setting status=114.\n", myid); 270 | status = 114; 271 | } 272 | } 273 | } else { // Root process 274 | pf.sub.offs = FLAG; // High value so it won't be min 275 | } 276 | 277 | // Find the minimum value of OFFS_SUB to see if we dropped a row 278 | offs_in.value = pf.sub.offs; 279 | offs_in.index = myid; 280 | MPI_Allreduce(&offs_in, &offs_out, 1, MPI_DOUBLE_INT, 281 | MPI_MINLOC, MPI_COMM_WORLD); 282 | // If all procs are returning the FLAG value, break. 283 | if (offs_out.value==FLAG) break; 284 | // Identify dropped rows 285 | if ((myid > 0) && (!status) && (!baddata) && 286 | (pf.sub.offs > (offs_out.value + 0.1 * pf.sub.tsubint))) { 287 | printf("Proc %d, row %d: Dropped a row. Filling with zeros.\n", 288 | myid, pf.rownum); 289 | droppedrow = 1; 290 | } 291 | 292 | if (myid > 0) { 293 | // Ignore errors for moving past EOF (107), read errors (108) 294 | // and missing files (114) 295 | if (droppedrow || 296 | status==108 || 297 | ((myid > 0) && (status==114 || status==107) && (!baddata))) { 298 | if (status) printf("Proc %d, row %d: Ignoring CFITSIO error %d. Filling with zeros.\n", myid, pf.rownum, status); 299 | // Set the data and the weights to all zeros 300 | for (ii = 0 ; ii < pf.hdr.nchan ; ii++) 301 | pf.sub.dat_weights[ii] = 0.0; 302 | for (ii = 0 ; ii < pf.sub.bytes_per_subint ; ii++) 303 | pf.sub.data[ii] = 0; 304 | // And the scales and offsets to nominal values 305 | for (ii = 0 ; ii < pf.hdr.nchan * pf.hdr.npol ; ii++) { 306 | pf.sub.dat_offsets[ii] = 0.0; 307 | pf.sub.dat_scales[ii] = 1.0; 308 | } 309 | // reset the status to 0 and allow going to next row 310 | if (status==114 || status==107) { 311 | baddata = 1; 312 | } 313 | if (status==108) { // Try reading the next row... 314 | pf.rownum++; 315 | pf.tot_rows++; 316 | pf.N += pf.hdr.nsblk; 317 | pf.T = pf.N * pf.hdr.dt; 318 | } 319 | if (droppedrow) { // We want to read the current row again... 320 | pf.rownum--; 321 | pf.tot_rows--; 322 | pf.N -= pf.hdr.nsblk; 323 | pf.T = pf.N * pf.hdr.dt; 324 | droppedrow = 0; // reset 325 | } 326 | status = 0; 327 | } 328 | } 329 | 330 | // If we've passed final file, exit 331 | if (fnum_end && pf.filenum > fnum_end) break; 332 | 333 | // Combine statuses of all nodes by summing.... 334 | MPI_Allreduce(&status, &statsum, 1, 335 | MPI_INT, MPI_SUM, MPI_COMM_WORLD); 336 | if (statsum) break; 337 | 338 | if (myid == offs_out.index) { // Send all of the non-band-specific parts to master 339 | MPI_Send(&pf.sub.tsubint, 1, MPI_DOUBLE, 0, 0, MPI_COMM_WORLD); 340 | MPI_Send(&pf.sub.offs, 1, MPI_DOUBLE, 0, 0, MPI_COMM_WORLD); 341 | MPI_Send(&pf.sub.lst, 1, MPI_DOUBLE, 0, 0, MPI_COMM_WORLD); 342 | MPI_Send(&pf.sub.ra, 1, MPI_DOUBLE, 0, 0, MPI_COMM_WORLD); 343 | MPI_Send(&pf.sub.dec, 1, MPI_DOUBLE, 0, 0, MPI_COMM_WORLD); 344 | MPI_Send(&pf.sub.glon, 1, MPI_DOUBLE, 0, 0, MPI_COMM_WORLD); 345 | MPI_Send(&pf.sub.glat, 1, MPI_DOUBLE, 0, 0, MPI_COMM_WORLD); 346 | MPI_Send(&pf.sub.feed_ang, 1, MPI_DOUBLE, 0, 0, MPI_COMM_WORLD); 347 | MPI_Send(&pf.sub.pos_ang, 1, MPI_DOUBLE, 0, 0, MPI_COMM_WORLD); 348 | MPI_Send(&pf.sub.par_ang, 1, MPI_DOUBLE, 0, 0, MPI_COMM_WORLD); 349 | MPI_Send(&pf.sub.tel_az, 1, MPI_DOUBLE, 0, 0, MPI_COMM_WORLD); 350 | MPI_Send(&pf.sub.tel_zen, 1, MPI_DOUBLE, 0, 0, MPI_COMM_WORLD); 351 | } else if (myid == 0) { // Receive all of the non-data parts 352 | MPI_Recv(&pf.sub.tsubint, 1, MPI_DOUBLE, offs_out.index, 0, MPI_COMM_WORLD, &mpistat); 353 | MPI_Recv(&pf.sub.offs, 1, MPI_DOUBLE, offs_out.index, 0, MPI_COMM_WORLD, &mpistat); 354 | MPI_Recv(&pf.sub.lst, 1, MPI_DOUBLE, offs_out.index, 0, MPI_COMM_WORLD, &mpistat); 355 | MPI_Recv(&pf.sub.ra, 1, MPI_DOUBLE, offs_out.index, 0, MPI_COMM_WORLD, &mpistat); 356 | MPI_Recv(&pf.sub.dec, 1, MPI_DOUBLE, offs_out.index, 0, MPI_COMM_WORLD, &mpistat); 357 | MPI_Recv(&pf.sub.glon, 1, MPI_DOUBLE, offs_out.index, 0, MPI_COMM_WORLD, &mpistat); 358 | MPI_Recv(&pf.sub.glat, 1, MPI_DOUBLE, offs_out.index, 0, MPI_COMM_WORLD, &mpistat); 359 | MPI_Recv(&pf.sub.feed_ang, 1, MPI_DOUBLE, offs_out.index, 0, MPI_COMM_WORLD, &mpistat); 360 | MPI_Recv(&pf.sub.pos_ang, 1, MPI_DOUBLE, offs_out.index, 0, MPI_COMM_WORLD, &mpistat); 361 | MPI_Recv(&pf.sub.par_ang, 1, MPI_DOUBLE, offs_out.index, 0, MPI_COMM_WORLD, &mpistat); 362 | MPI_Recv(&pf.sub.tel_az, 1, MPI_DOUBLE, offs_out.index, 0, MPI_COMM_WORLD, &mpistat); 363 | MPI_Recv(&pf.sub.tel_zen, 1, MPI_DOUBLE, offs_out.index, 0, MPI_COMM_WORLD, &mpistat); 364 | } 365 | 366 | // Now gather the vector quantities... 367 | 368 | // Vectors of length nchan 369 | for (ii = 1 ; ii < numprocs ; ii++) { 370 | counts[ii] = nc; 371 | offsets[ii] = (ii - 1) * nc; 372 | } 373 | status = MPI_Gatherv(pf.sub.dat_freqs, nc, MPI_FLOAT, 374 | pf.sub.dat_freqs, counts, offsets, MPI_FLOAT, 375 | 0, MPI_COMM_WORLD); 376 | status = MPI_Gatherv(pf.sub.dat_weights, nc, MPI_FLOAT, 377 | pf.sub.dat_weights, counts, offsets, MPI_FLOAT, 378 | 0, MPI_COMM_WORLD); 379 | 380 | // Vectors of length nchan * npol 381 | for (ipol=0; ipol < pf.hdr.npol; ipol++) { 382 | for (ii = 1 ; ii < numprocs ; ii++) { 383 | counts[ii] = nc; 384 | offsets[ii] = ipol*nc*numbands + (ii - 1) * nc; 385 | } 386 | status = MPI_Gatherv(pf.sub.dat_offsets+(ipol*nc), nc, MPI_FLOAT, 387 | pf.sub.dat_offsets, counts, offsets, 388 | MPI_FLOAT, 0, MPI_COMM_WORLD); 389 | status = MPI_Gatherv(pf.sub.dat_scales+(ipol*nc), nc, MPI_FLOAT, 390 | pf.sub.dat_scales, counts, offsets, 391 | MPI_FLOAT, 0, MPI_COMM_WORLD); 392 | } 393 | 394 | // Vectors of length pf.sub.bytes_per_subint for the raw data 395 | for (ii = 1 ; ii < numprocs ; ii++) { 396 | counts[ii] = gpubps; 397 | offsets[ii] = (ii - 1) * gpubps; 398 | } 399 | status = MPI_Gatherv(pf.sub.data, gpubps, MPI_UNSIGNED_CHAR, 400 | tmpbuf, counts, offsets, MPI_UNSIGNED_CHAR, 401 | 0, MPI_COMM_WORLD); 402 | 403 | // Reorder and write the new row to the output file 404 | if (myid == 0) { 405 | reorder_data(pf.sub.data, tmpbuf, numbands, 406 | pf.hdr.nsblk, pf.hdr.npol, nc); 407 | status = psrfits_write_subint(&pf); 408 | } 409 | 410 | } while (statsum == 0); 411 | 412 | // Free the arrays 413 | free(pf.sub.dat_freqs); 414 | free(pf.sub.dat_weights); 415 | free(pf.sub.dat_offsets); 416 | free(pf.sub.dat_scales); 417 | free(pf.sub.data); 418 | if (myid == 0) free(tmpbuf); 419 | free(counts); 420 | free(offsets); 421 | 422 | // Close the files and finalize things 423 | status = psrfits_close(&pf); 424 | MPI_Finalize(); 425 | exit(0); 426 | } 427 | -------------------------------------------------------------------------------- /fold.c: -------------------------------------------------------------------------------- 1 | /* Simple fold routines */ 2 | #include 3 | #include 4 | #include 5 | #include 6 | #include 7 | 8 | #ifdef FOLD_USE_INTRINSICS 9 | # include 10 | # define _MM_LOAD_PS _mm_load_ps 11 | # define _MM_STORE_PS _mm_store_ps 12 | #endif 13 | 14 | #include "fold.h" 15 | #include "polyco.h" 16 | 17 | void malloc_foldbuf(struct foldbuf *f) { 18 | #ifdef FOLD_USE_INTRINSICS 19 | const int alignment = 64; 20 | if ((f->npol * f->nchan * sizeof(float)) % alignment) { 21 | fprintf(stderr, 22 | "Error: foldbuf dimension are not appropriate for alignment:\n" 23 | " npol=%d nchan=%d\n", f->npol, f->nchan); 24 | exit(1); 25 | } 26 | int rv = posix_memalign((void *)&f->data, alignment, 27 | sizeof(float) * f->nbin * f->npol * f->nchan); 28 | if (rv) { 29 | fprintf(stderr, "Error in posix_memalign"); 30 | exit(1); 31 | } 32 | #else 33 | f->data = (float *)malloc(sizeof(float) * f->nbin * f->npol * f->nchan); 34 | #endif 35 | f->count = (unsigned *)malloc(sizeof(unsigned) * f->nbin); 36 | } 37 | 38 | void free_foldbuf(struct foldbuf *f) { 39 | if (f->data!=NULL) { free(f->data); f->data=NULL; } 40 | if (f->count!=NULL) { free(f->count); f->count=NULL; } 41 | } 42 | 43 | void clear_foldbuf(struct foldbuf *f) { 44 | memset(f->data, 0, sizeof(float) * f->nbin * f->npol * f->nchan); 45 | memset(f->count, 0, sizeof(unsigned) * f->nbin); 46 | } 47 | 48 | size_t foldbuf_data_size(const struct foldbuf *f) { 49 | if (f->data==NULL) return(0); 50 | return(sizeof(float) * f->nbin * f->npol * f->nchan); 51 | } 52 | 53 | size_t foldbuf_count_size(const struct foldbuf *f) { 54 | if (f->count==NULL) return(0); 55 | return(sizeof(unsigned) * f->nbin); 56 | } 57 | 58 | /* Combines unpack and accumulate */ 59 | void vector_accumulate_8bit(float *out, const char *in, int n) { 60 | #ifdef FOLD_USE_INTRINSICS 61 | __m128 in_, out_, tmp_; 62 | float ftmp; 63 | int ii; 64 | for (ii = 0 ; ii < (n & -16) ; ii += 16) { 65 | __builtin_prefetch(out + 64, 1, 0); 66 | __builtin_prefetch(in + 64, 0, 0); 67 | 68 | out_ = _MM_LOAD_PS(out); 69 | in_ = _mm_cvtpi8_ps(*((__m64 *)in)); 70 | tmp_ = _mm_add_ps(out_, in_); 71 | _MM_STORE_PS(out, tmp_); 72 | in += 4; 73 | out += 4; 74 | 75 | out_ = _MM_LOAD_PS(out); 76 | in_ = _mm_cvtpi8_ps(*((__m64 *)in)); 77 | tmp_ = _mm_add_ps(out_, in_); 78 | _MM_STORE_PS(out, tmp_); 79 | in += 4; 80 | out += 4; 81 | 82 | out_ = _MM_LOAD_PS(out); 83 | in_ = _mm_cvtpi8_ps(*((__m64 *)in)); 84 | tmp_ = _mm_add_ps(out_, in_); 85 | _MM_STORE_PS(out, tmp_); 86 | in += 4; 87 | out += 4; 88 | 89 | out_ = _MM_LOAD_PS(out); 90 | in_ = _mm_cvtpi8_ps(*((__m64 *)in)); 91 | tmp_ = _mm_add_ps(out_, in_); 92 | _MM_STORE_PS(out, tmp_); 93 | in += 4; 94 | out += 4; 95 | } 96 | for (; ii < (n & -4) ; ii += 4) { 97 | out_ = _MM_LOAD_PS(out); 98 | in_ = _mm_cvtpi8_ps(*((__m64 *)in)); 99 | tmp_ = _mm_add_ps(out_, in_); 100 | _MM_STORE_PS(out, tmp_); 101 | in += 4; 102 | out += 4; 103 | } 104 | for (; ii < n ; ii++) { // Cast these without intrinsics 105 | ftmp = (float)(*in); 106 | out_ = _mm_load_ss(out); 107 | in_ = _mm_load_ss(&ftmp); 108 | tmp_ = _mm_add_ss(out_, in_); 109 | _mm_store_ss(out, tmp_); 110 | in += 1; 111 | out += 1; 112 | } 113 | _mm_empty(); 114 | #else 115 | int i; 116 | for (i=0; ipc, args->imjd, args->fmjd, args->data, 272 | args->nsamp, args->tsamp, args->raw_signed, args->fb); 273 | pthread_exit(&rv); 274 | } 275 | 276 | void *fold_16bit_power_thread(void *_args) { 277 | struct fold_args *args = (struct fold_args *)_args; 278 | int rv = fold_16bit_power(args->pc, args->imjd, args->fmjd, 279 | (const int16_t *)args->data, 280 | args->nsamp, args->tsamp, args->raw_signed, args->fb); 281 | pthread_exit(&rv); 282 | } 283 | 284 | void *fold_float_power_thread(void *_args) { 285 | struct fold_args *args = (struct fold_args *)_args; 286 | int rv = fold_float_power(args->pc, args->imjd, args->fmjd, 287 | (const float *)args->data, 288 | args->nsamp, args->tsamp, args->fb); 289 | pthread_exit(&rv); 290 | } 291 | 292 | int fold_8bit_power(const struct polyco *pc, int imjd, double fmjd, 293 | const char *data, int nsamp, double tsamp, int raw_signed, 294 | struct foldbuf *f) { 295 | 296 | /* Find midtime */ 297 | double fmjd_mid = fmjd + nsamp*tsamp/2.0/86400.0; 298 | 299 | /* Check polyco set, allow 5% expansion of range */ 300 | if (pc_out_of_range_sloppy(pc, imjd, fmjd,1.05)) { return(-1); } 301 | 302 | /* Calc phase, phase step */ 303 | /* NOTE: Starting sample phase is computed for the middle 304 | * of the first sample, assuming input fmjd refers to 305 | * the rising edge of the first sample given 306 | */ 307 | double dphase=0.0; 308 | double phase = psr_phase(pc, imjd, fmjd + tsamp/2.0/86400.0, NULL, NULL); 309 | phase = fmod(phase, 1.0); 310 | if (phase<0.0) { phase += 1.0; } 311 | psr_phase(pc, imjd, fmjd_mid, &dphase, NULL); 312 | dphase *= tsamp; 313 | 314 | /* Fold em */ 315 | int i, ibin; 316 | float *fptr; 317 | for (i=0; inbin); 319 | if (ibin<0) { ibin+=f->nbin; } 320 | if (ibin>=f->nbin) { ibin-=f->nbin; } 321 | fptr = &f->data[ibin*f->nchan*f->npol]; 322 | if (zero_check(&data[i*f->nchan*f->npol], f->nchan*f->npol)==0) { 323 | if (raw_signed==1) 324 | vector_accumulate_8bit(fptr, 325 | &data[i*f->nchan*f->npol], 326 | f->nchan*f->npol); 327 | else if (raw_signed==2) { 328 | // First 2 polns are unsigned, last 2 are signed 329 | vector_accumulate_8bit_unsigned(fptr, 330 | &data[i*f->nchan*f->npol], 331 | f->nchan*2); 332 | vector_accumulate_8bit(fptr + 2*f->nchan, 333 | &data[i*f->nchan*f->npol + 2*f->nchan], 334 | f->nchan*2); 335 | } else if (raw_signed==3) { 336 | // First 1 pol is unsigned, last 3 are signed 337 | vector_accumulate_8bit_unsigned(fptr, 338 | &data[i*f->nchan*f->npol], 339 | f->nchan); 340 | vector_accumulate_8bit(fptr + f->nchan, 341 | &data[i*f->nchan*f->npol + f->nchan], 342 | f->nchan*3); 343 | } else 344 | // All unsigned 345 | vector_accumulate_8bit_unsigned(fptr, 346 | (unsigned char *)&data[i*f->nchan*f->npol], 347 | f->nchan*f->npol); 348 | f->count[ibin]++; 349 | } 350 | phase += dphase; 351 | if (phase>1.0) { phase -= 1.0; } 352 | } 353 | 354 | return(0); 355 | } 356 | 357 | int fold_16bit_power(const struct polyco *pc, int imjd, double fmjd, 358 | const int16_t *data, int nsamp, double tsamp, int raw_signed, 359 | struct foldbuf *f) { 360 | 361 | /* Find midtime */ 362 | double fmjd_mid = fmjd + nsamp*tsamp/2.0/86400.0; 363 | 364 | /* Check polyco set, allow 5% expansion of range */ 365 | if (pc_out_of_range_sloppy(pc, imjd, fmjd,1.05)) { return(-1); } 366 | 367 | /* Calc phase, phase step */ 368 | /* NOTE: Starting sample phase is computed for the middle 369 | * of the first sample, assuming input fmjd refers to 370 | * the rising edge of the first sample given 371 | */ 372 | double dphase=0.0; 373 | double phase = psr_phase(pc, imjd, fmjd + tsamp/2.0/86400.0, NULL, NULL); 374 | phase = fmod(phase, 1.0); 375 | if (phase<0.0) { phase += 1.0; } 376 | psr_phase(pc, imjd, fmjd_mid, &dphase, NULL); 377 | dphase *= tsamp; 378 | 379 | /* Fold em */ 380 | int i, ibin; 381 | float *fptr; 382 | for (i=0; inbin); 384 | if (ibin<0) { ibin+=f->nbin; } 385 | if (ibin>=f->nbin) { ibin-=f->nbin; } 386 | fptr = &f->data[ibin*f->nchan*f->npol]; 387 | if (zero_check((const char *)&data[i*f->nchan*f->npol], 388 | 2*f->nchan*f->npol)==0) { 389 | if (raw_signed==1) 390 | vector_accumulate_16bit(fptr, 391 | &data[i*f->nchan*f->npol], 392 | f->nchan*f->npol); 393 | else if (raw_signed==2) { 394 | // First 2 polns are unsigned, last 2 are signed 395 | vector_accumulate_16bit_unsigned(fptr, 396 | &data[i*f->nchan*f->npol], 397 | f->nchan*2); 398 | vector_accumulate_16bit(fptr + 2*f->nchan, 399 | &data[i*f->nchan*f->npol + 2*f->nchan], 400 | f->nchan*2); 401 | } else if (raw_signed==3) { 402 | // First 1 pol is unsigned, last 3 are signed 403 | vector_accumulate_16bit_unsigned(fptr, 404 | &data[i*f->nchan*f->npol], 405 | f->nchan); 406 | vector_accumulate_16bit(fptr + f->nchan, 407 | &data[i*f->nchan*f->npol + f->nchan], 408 | f->nchan*3); 409 | } else 410 | // All unsigned 411 | vector_accumulate_16bit_unsigned(fptr, 412 | (uint16_t *)&data[i*f->nchan*f->npol], 413 | f->nchan*f->npol); 414 | f->count[ibin]++; 415 | } 416 | phase += dphase; 417 | if (phase>1.0) { phase -= 1.0; } 418 | } 419 | 420 | return(0); 421 | } 422 | 423 | int fold_float_power(const struct polyco *pc, int imjd, double fmjd, 424 | const float *data, int nsamp, double tsamp, 425 | struct foldbuf *f) { 426 | 427 | /* Find midtime */ 428 | double fmjd_mid = fmjd + nsamp*tsamp/2.0/86400.0; 429 | 430 | /* Check polyco set, allow 5% expansion of range */ 431 | if (pc_out_of_range_sloppy(pc, imjd, fmjd,1.05)) { return(-1); } 432 | 433 | /* Calc phase, phase step */ 434 | /* NOTE: Starting sample phase is computed for the middle 435 | * of the first sample, assuming input fmjd refers to 436 | * the rising edge of the first sample given 437 | */ 438 | double dphase=0.0; 439 | double phase = psr_phase(pc, imjd, fmjd + tsamp/2.0/86400.0, NULL, NULL); 440 | phase = fmod(phase, 1.0); 441 | if (phase<0.0) { phase += 1.0; } 442 | psr_phase(pc, imjd, fmjd_mid, &dphase, NULL); 443 | dphase *= tsamp; 444 | 445 | /* Fold em */ 446 | int i, ibin; 447 | float *fptr; 448 | for (i=0; inbin); 450 | if (ibin<0) { ibin+=f->nbin; } 451 | if (ibin>=f->nbin) { ibin-=f->nbin; } 452 | fptr = &f->data[ibin*f->nchan*f->npol]; 453 | if (zero_check((const char *)&data[i*f->nchan*f->npol], 454 | 4*f->nchan*f->npol)==0) { 455 | vector_accumulate(fptr, 456 | &data[i*f->nchan*f->npol], 457 | f->nchan*f->npol); 458 | f->count[ibin]++; 459 | } 460 | phase += dphase; 461 | if (phase>1.0) { phase -= 1.0; } 462 | } 463 | 464 | return(0); 465 | } 466 | int accumulate_folds(struct foldbuf *ftot, const struct foldbuf *f) { 467 | if (ftot->nbin!=f->nbin || ftot->nchan!=f->nchan || ftot->npol!=f->npol) { 468 | return(-1); 469 | } 470 | int i; 471 | for (i=0; inbin; i++) { ftot->count[i] += f->count[i]; } 472 | vector_accumulate(ftot->data, f->data, f->nbin * f->nchan * f->npol); 473 | return(0); 474 | } 475 | 476 | /* normalize and transpose to psrfits order */ 477 | int normalize_transpose_folds(float *out, const struct foldbuf *f) { 478 | int ibin, ii; 479 | for (ibin=0; ibinnbin; ibin++) { 480 | if (f->count[ibin]==0) { 481 | for (ii=0; iinchan*f->npol; ii++) 482 | out[ibin + ii*f->nbin] = 0.0; 483 | } else { 484 | for (ii=0; iinchan*f->npol; ii++) 485 | out[ibin + ii*f->nbin] = 486 | f->data[ii + ibin*f->nchan*f->npol] / (float)f->count[ibin]; 487 | } 488 | } 489 | return(0); 490 | } 491 | 492 | /* Apply a per-channel/poln scale and offset */ 493 | /* Note, this only works on pre-normalized fold results! */ 494 | int scale_offset_folds(struct foldbuf *f, 495 | const float *scale, const float *offset) { 496 | int ibin, ii; 497 | float tmp; 498 | for (ibin=0; ibinnbin; ibin++) { 499 | for (ii=0; iinchan*f->npol; ii++) { 500 | tmp = f->data[ii + ibin*f->nchan*f->npol]; 501 | f->data[ii + ibin*f->nchan*f->npol] = tmp*scale[ii] + 502 | (float)f->count[ibin]*offset[ii]; 503 | } 504 | } 505 | return(0); 506 | } 507 | -------------------------------------------------------------------------------- /psrfits_singlepulse.c: -------------------------------------------------------------------------------- 1 | /* psrfits_singlepulse.c 2 | * 3 | * "Fold" PSRFITS search mode data into single-pulse folded PSRFITS. 4 | */ 5 | #include 6 | #include 7 | #include 8 | #include 9 | #include 10 | #include 11 | #include 12 | #include "polyco.h" 13 | #include "fold.h" 14 | #include "psrfits.h" 15 | 16 | /* Signal handler */ 17 | int run=1; 18 | void cc(int sig) { run=0; } 19 | 20 | void usage() { 21 | printf( 22 | "Usage: psrfits_singlepulse [options] input_filename_base or filenames\n" 23 | "Options:\n" 24 | " -h, --help Print this\n" 25 | " -o name, --output=name Output base filename (auto-generate)\n" 26 | " -n nn, --npulse=nn Number of pulses per output file (64)\n" 27 | " -b nn, --nbin=nn Number of profile bins (256)\n" 28 | " -i nn, --initial=nn Starting input file number (1)\n" 29 | " -f nn, --final=nn Ending input file number (auto)\n" 30 | " -T nn, --time=nn Start nn seconds in (0)\n" 31 | " -L nn, --length=nn Process nn total seconds (all)\n" 32 | " -s src, --src=src Override source name from file\n" 33 | " -p file, --polyco=file Polyco file to use (polyco.dat)\n" 34 | " -P file, --parfile=file Use given .par file\n" 35 | " -F nn, --foldfreq=nn Fold at constant freq (Hz)\n" 36 | " -C, --cal Cal folding mode\n" 37 | " -u, --unsigned Raw data is unsigned\n" 38 | " -U n, --nunsigned Num of unsigned polns\n" 39 | " -q, --quiet No progress indicator\n" 40 | ); 41 | } 42 | 43 | int main(int argc, char *argv[]) { 44 | 45 | /* Cmd line */ 46 | static struct option long_opts[] = { 47 | {"output", 1, NULL, 'o'}, 48 | {"npulse", 1, NULL, 'n'}, 49 | {"nbin", 1, NULL, 'b'}, 50 | {"nthread", 1, NULL, 'j'}, 51 | {"initial", 1, NULL, 'i'}, 52 | {"final", 1, NULL, 'f'}, 53 | {"time", 1, NULL, 'T'}, 54 | {"length", 1, NULL, 'L'}, 55 | {"src", 1, NULL, 's'}, 56 | {"polyco", 1, NULL, 'p'}, 57 | {"parfile", 1, NULL, 'P'}, 58 | {"foldfreq",1, NULL, 'F'}, 59 | {"cal", 0, NULL, 'C'}, 60 | {"unsigned",0, NULL, 'u'}, 61 | {"nunsigned",1, NULL, 'U'}, 62 | {"quiet", 0, NULL, 'q'}, 63 | {"help", 0, NULL, 'h'}, 64 | {0,0,0,0} 65 | }; 66 | int opt, opti; 67 | int nbin=256, nthread=4, fnum_start=1, fnum_end=0; 68 | int quiet=0, raw_signed=1, use_polycos=1, cal=0; 69 | int npulse_per_file = 64; 70 | double start_time=0.0, process_time=0.0; 71 | double fold_frequency=0.0; 72 | char output_base[256] = ""; 73 | char polyco_file[256] = ""; 74 | char par_file[256] = ""; 75 | char source[24]; source[0]='\0'; 76 | while ((opt=getopt_long(argc,argv,"o:n:b:j:i:f:T:L:s:p:P:F:CuU:qh",long_opts,&opti))!=-1) { 77 | switch (opt) { 78 | case 'o': 79 | strncpy(output_base, optarg, 255); 80 | output_base[255]='\0'; 81 | break; 82 | case 'n': 83 | npulse_per_file = atoi(optarg); 84 | break; 85 | case 'b': 86 | nbin = atoi(optarg); 87 | break; 88 | case 'j': 89 | nthread = atoi(optarg); 90 | break; 91 | case 'i': 92 | fnum_start = atoi(optarg); 93 | break; 94 | case 'f': 95 | fnum_end = atoi(optarg); 96 | break; 97 | case 'T': 98 | start_time = atof(optarg); 99 | break; 100 | case 'L': 101 | process_time = atof(optarg); 102 | break; 103 | case 's': 104 | strncpy(source, optarg, 24); 105 | source[23]='\0'; 106 | break; 107 | case 'p': 108 | strncpy(polyco_file, optarg, 255); 109 | polyco_file[255]='\0'; 110 | use_polycos = 1; 111 | break; 112 | case 'P': 113 | strncpy(par_file, optarg, 255); 114 | par_file[255] = '\0'; 115 | break; 116 | case 'F': 117 | fold_frequency = atof(optarg); 118 | use_polycos = 0; 119 | break; 120 | case 'C': 121 | cal = 1; 122 | use_polycos = 0; 123 | break; 124 | case 'u': 125 | raw_signed=0; 126 | break; 127 | case 'U': 128 | raw_signed = 4 - atoi(optarg); 129 | break; 130 | case 'q': 131 | quiet=1; 132 | break; 133 | case 'h': 134 | default: 135 | usage(); 136 | exit(0); 137 | break; 138 | } 139 | 140 | } 141 | if (optind==argc) { 142 | usage(); 143 | exit(1); 144 | } 145 | 146 | /* If no polyco/par file given, default to polyco.dat */ 147 | if (use_polycos && (par_file[0]=='\0' && polyco_file[0]=='\0')) 148 | sprintf(polyco_file, "polyco.dat"); 149 | 150 | /* Open first file */ 151 | struct psrfits pf; 152 | psrfits_set_files(&pf, argc - optind, argv + optind); 153 | // Use the dynamic filename allocation 154 | if (pf.numfiles==0) pf.filenum = fnum_start; 155 | pf.tot_rows = pf.N = pf.T = pf.status = 0; 156 | pf.hdr.chan_dm = 0.0; // What if folding data that has been partially de-dispersed? 157 | pf.filename[0]='\0'; 158 | int rv = psrfits_open(&pf); 159 | if (rv) { fits_report_error(stderr, rv); exit(1); } 160 | 161 | /* Check any constraints */ 162 | if (pf.hdr.nbits!=8) { 163 | fprintf(stderr, "Only implemented for 8-bit data (read nbits=%d).\n", 164 | pf.hdr.nbits); 165 | exit(1); 166 | } 167 | 168 | /* Check for calfreq */ 169 | if (cal) { 170 | if (pf.hdr.cal_freq==0.0) { 171 | if (fold_frequency==0.0) { 172 | fprintf(stderr, "Error: Cal mode selected, but CAL_FREQ=0. " 173 | "Set cal frequency with -F\n"); 174 | exit(1); 175 | } else { 176 | pf.hdr.cal_freq = fold_frequency; 177 | } 178 | } else { 179 | fold_frequency = pf.hdr.cal_freq; 180 | } 181 | } 182 | 183 | /* Set up output file */ 184 | struct psrfits pf_out; 185 | memcpy(&pf_out, &pf, sizeof(struct psrfits)); 186 | if (source[0]!='\0') { strncpy(pf_out.hdr.source, source, 24); } 187 | else { strncpy(source, pf.hdr.source, 24); source[23]='\0'; } 188 | if (output_base[0]=='\0') { 189 | /* Set up default output filename */ 190 | if (start_time>0.0) 191 | sprintf(output_base, "%s_SP_%s_%5.5d_%5.5d_%4.4d_%3.3d%s", 192 | pf_out.hdr.backend, 193 | pf_out.hdr.source, pf_out.hdr.start_day, 194 | (int)pf_out.hdr.start_sec, fnum_start, 195 | (int)start_time, 196 | cal ? "_cal" : ""); 197 | else 198 | sprintf(output_base, "%s_SP_%s_%5.5d_%5.5d%s", pf_out.hdr.backend, 199 | pf_out.hdr.source, pf_out.hdr.start_day, 200 | (int)pf_out.hdr.start_sec, cal ? "_cal" : ""); 201 | } 202 | strcpy(pf_out.basefilename, output_base); 203 | if (cal) { 204 | sprintf(pf_out.hdr.obs_mode, "CAL"); 205 | sprintf(pf_out.hdr.cal_mode, "SYNC"); 206 | } else 207 | sprintf(pf_out.hdr.obs_mode, "PSR"); 208 | strncpy(pf_out.fold.parfile,par_file,255); pf_out.fold.parfile[255]='\0'; 209 | pf_out.fptr = NULL; 210 | pf_out.filenum=0; 211 | pf_out.status=0; 212 | pf_out.hdr.nbin=nbin; 213 | pf_out.sub.FITS_typecode = TFLOAT; 214 | pf_out.sub.bytes_per_subint = sizeof(float) * 215 | pf_out.hdr.nchan * pf_out.hdr.npol * pf_out.hdr.nbin; 216 | pf_out.multifile = 1; 217 | pf_out.quiet = 1; 218 | pf_out.rows_per_file = npulse_per_file; 219 | rv = psrfits_create(&pf_out); 220 | if (rv) { fits_report_error(stderr, rv); exit(1); } 221 | 222 | /* Alloc data buffers */ 223 | pf.sub.dat_freqs = (float *)malloc(sizeof(float) * pf.hdr.nchan); 224 | pf_out.sub.dat_freqs = pf.sub.dat_freqs; 225 | pf.sub.dat_weights = (float *)malloc(sizeof(float) * pf.hdr.nchan); 226 | pf_out.sub.dat_weights = (float *)malloc(sizeof(float) * pf.hdr.nchan); 227 | pf.sub.dat_offsets = (float *)malloc(sizeof(float) 228 | * pf.hdr.nchan * pf.hdr.npol); 229 | pf_out.sub.dat_offsets = (float *)malloc(sizeof(float) 230 | * pf.hdr.nchan * pf.hdr.npol); 231 | pf.sub.dat_scales = (float *)malloc(sizeof(float) 232 | * pf.hdr.nchan * pf.hdr.npol); 233 | pf_out.sub.dat_scales = (float *)malloc(sizeof(float) 234 | * pf.hdr.nchan * pf.hdr.npol); 235 | pf_out.sub.data = (unsigned char *)malloc(pf_out.sub.bytes_per_subint); 236 | 237 | /* Output scale/offset */ 238 | int i, j, ipol, ichan; 239 | float offset_uv=0.0; 240 | // Extra cross-term offset for GUPPI 241 | if (strcmp("GUPPI",pf.hdr.backend)==0) { 242 | offset_uv=0.5; 243 | fprintf(stderr, "Found backend=GUPPI, setting offset_uv=%f\n", 244 | offset_uv); 245 | } 246 | // TODO: copy these from the input file 247 | for (ipol=0; ipol1) offs = offset_uv; 251 | pf_out.sub.dat_scales[ipol*pf.hdr.nchan + ichan] = 1.0; 252 | pf_out.sub.dat_offsets[ipol*pf.hdr.nchan + ichan] = offs; 253 | } 254 | } 255 | for (i=0; ifnum_end) { run=0; break; } 338 | 339 | /* Get start date, etc */ 340 | imjd = (int)pf.hdr.MJD_epoch; 341 | fmjd = (double)(pf.hdr.MJD_epoch - (long double)imjd); 342 | fmjd += (pf.sub.offs-0.5*pf.sub.tsubint)/86400.0; 343 | 344 | /* Select polyco set. 345 | * We'll assume same one is valid for whole data block. 346 | */ 347 | if (use_polycos) { 348 | ipc = select_pc(pc, npc, source, imjd, fmjd); 349 | //ipc = select_pc(pc, npc, NULL, imjd, fmjd); 350 | if (ipc<0) { 351 | fprintf(stderr, 352 | "No matching polycos (src=%s, imjd=%d, fmjd=%f)\n", 353 | source, imjd, fmjd); 354 | break; 355 | } 356 | } else { 357 | ipc = 0; 358 | } 359 | pc[ipc].used = 1; // Mark this polyco set as used for folding 360 | 361 | /* First time stuff */ 362 | if (first_loop) { 363 | fmjd0 = fmjd; 364 | psr_phase(&pc[ipc], imjd, fmjd, NULL, &last_pulse); 365 | pf_out.sub.offs=0.0; 366 | first_loop=0; 367 | for (i=0; i0.0) { 375 | double cur_time = (fmjd - fmjd0) * 86400.0; 376 | if (cur_time0.0) { 387 | double cur_time = (fmjd - fmjd0) * 86400.0; 388 | if (cur_time > start_time + process_time) { 389 | run=0; 390 | break; 391 | } 392 | } 393 | 394 | /* for singlepulse: loop over samples, output a new subint 395 | * whenever pulse number increases. 396 | */ 397 | for (i=0; i last_pulse) { 425 | 426 | /* Figure out timestamp */ 427 | pf_out.sub.offs /= (double)sampcount; 428 | pf_out.sub.tsubint = 1.0/psr_freq; 429 | fmjd_epoch = fmjd0 + pf_out.sub.offs/86400.0; 430 | 431 | /* Transpose, output subint */ 432 | normalize_transpose_folds((float *)pf_out.sub.data, &fb); 433 | psrfits_write_subint(&pf_out); 434 | 435 | /* If file incremented, clear polyco flags */ 436 | if (pf_out.filenum > last_filenum) 437 | for (j=0; j100) { fits_report_error(stderr, rv); } 476 | exit(0); 477 | } 478 | -------------------------------------------------------------------------------- /read_psrfits.c: -------------------------------------------------------------------------------- 1 | /* read_psrfits.c */ 2 | #include 3 | #include 4 | #include "psrfits.h" 5 | 6 | 7 | int is_search_PSRFITS(char *filename) 8 | // Return 1 if the file described by filename is a PSRFITS file 9 | // Return 0 otherwise. 10 | { 11 | fitsfile *fptr; 12 | int status=0; 13 | char ctmp[80], comment[120]; 14 | 15 | // Read the primary HDU 16 | fits_open_file(&fptr, filename, READONLY, &status); 17 | if (status) return 0; 18 | 19 | // Make the easy check first 20 | fits_read_key(fptr, TSTRING, "FITSTYPE", ctmp, comment, &status); 21 | if (status || strcmp(ctmp, "PSRFITS")) return 0; 22 | 23 | // See if the data are search-mode 24 | fits_read_key(fptr, TSTRING, "OBS_MODE", ctmp, comment, &status); 25 | if (status || (strcmp(ctmp, "SEARCH") && 26 | strcmp(ctmp, "SRCH"))) return 0; 27 | 28 | fits_close_file(fptr, &status); 29 | return 1; // it is search-mode PSRFITS 30 | } 31 | 32 | 33 | void psrfits_set_files(struct psrfits *pf, int numfiles, char *filenames[]) 34 | /* Determine whether we are using explicit filenames (and */ 35 | /* how many there are, or whether we are building our own */ 36 | /* using sequence numbers and the basefilename. */ 37 | { 38 | int ii; 39 | 40 | // Check if we were passed a basefilename 41 | if (numfiles==1 && (!is_search_PSRFITS(filenames[0]))) { 42 | strncpy(pf->basefilename, filenames[0], 200); 43 | printf("Using '%s' as our base PSRFITS file name.\n", pf->basefilename); 44 | pf->numfiles = 0; // dynamically determined 45 | pf->filenum = 1; 46 | pf->filename[0] = '\0'; 47 | pf->filenames = NULL; 48 | return; 49 | } 50 | // Using real filenames instead... 51 | pf->basefilename[0]='\0'; 52 | pf->numfiles = numfiles; 53 | pf->filenum = 0; 54 | pf->filenames = filenames; 55 | // Test that all of the input files are valid PSRFITS 56 | for (ii = 0; ii < numfiles; ii++) { 57 | // printf("Checking '%s'...\n", filenames[ii]); 58 | if (!is_search_PSRFITS(filenames[ii])) 59 | fprintf(stderr, "Error: '%s' is not PSRFITS. Exiting.\n", filenames[ii]); 60 | } 61 | printf("Found %d valid PSRFITS files for input.\n", numfiles); 62 | return; 63 | } 64 | 65 | 66 | /* This function is similar to psrfits_create, except it 67 | * deals with reading existing files. It is assumed that 68 | * basename and filenum are filled in correctly to point to 69 | * the first file in the set OR that filename already contains 70 | * the correct file name. 71 | */ 72 | int psrfits_open(struct psrfits *pf) { 73 | 74 | int itmp; 75 | double dtmp; 76 | char ctmp[256]; 77 | 78 | struct hdrinfo *hdr = &(pf->hdr); 79 | struct subint *sub = &(pf->sub); 80 | struct foldinfo *fold = &(pf->fold); 81 | int *status = &(pf->status); 82 | 83 | if (pf->numfiles==0) { 84 | // Dynamically generated file names 85 | sprintf(pf->filename, "%s_%04d.fits", pf->basefilename, pf->filenum); 86 | } else { 87 | // Using explicit filenames 88 | if (pf->filenum < pf->numfiles) { 89 | strncpy(pf->filename, pf->filenames[pf->filenum], 200); 90 | } else { 91 | *status = FILE_NOT_OPENED; 92 | return *status; 93 | } 94 | } 95 | 96 | fits_open_file(&(pf->fptr), pf->filename, READONLY, status); 97 | pf->mode = 'r'; 98 | 99 | // If file no exist, exit now 100 | if (*status) { 101 | return *status; 102 | } else { 103 | printf("Opened file '%s'\n", pf->filename); 104 | } 105 | 106 | // Move to main HDU 107 | fits_movabs_hdu(pf->fptr, 1, NULL, status); 108 | 109 | // Figure out obs mode 110 | fits_read_key(pf->fptr, TSTRING, "OBS_MODE", hdr->obs_mode, NULL, status); 111 | int mode = psrfits_obs_mode(hdr->obs_mode); 112 | 113 | // Set the downsampling stuff to default values 114 | hdr->onlyI = 0; 115 | hdr->ds_time_fact = 1; 116 | hdr->ds_freq_fact = 1; 117 | 118 | // Blank parfile name, folding params 119 | fold->parfile[0] = '\0'; 120 | fold->n_polyco_sets = 0; 121 | fold->pc = NULL; 122 | 123 | // Read some stuff 124 | fits_read_key(pf->fptr, TSTRING, "TELESCOP", hdr->telescope, NULL, status); 125 | fits_read_key(pf->fptr, TSTRING, "OBSERVER", hdr->observer, NULL, status); 126 | fits_read_key(pf->fptr, TSTRING, "PROJID", hdr->project_id, NULL, status); 127 | fits_read_key(pf->fptr, TSTRING, "FRONTEND", hdr->frontend, NULL, status); 128 | fits_read_key(pf->fptr, TSTRING, "BACKEND", hdr->backend, NULL, status); 129 | fits_read_key(pf->fptr, TSTRING, "FD_POLN", hdr->poln_type, NULL, status); 130 | fits_read_key(pf->fptr, TSTRING, "DATE-OBS", hdr->date_obs, NULL, status); 131 | fits_read_key(pf->fptr, TDOUBLE, "OBSFREQ", &(hdr->fctr), NULL, status); 132 | fits_read_key(pf->fptr, TDOUBLE, "OBSBW", &(hdr->BW), NULL, status); 133 | fits_read_key(pf->fptr, TINT, "OBSNCHAN", &(hdr->orig_nchan), NULL, status); 134 | hdr->orig_df = hdr->BW / hdr->orig_nchan; 135 | fits_read_key(pf->fptr, TDOUBLE, "CHAN_DM", &(hdr->chan_dm), NULL, status); 136 | if (*status==KEY_NO_EXIST) { hdr->chan_dm=0.0; *status=0; } 137 | fits_read_key(pf->fptr, TSTRING, "SRC_NAME", hdr->source, NULL, status); 138 | fits_read_key(pf->fptr, TSTRING, "TRK_MODE", hdr->track_mode, NULL, status); 139 | // TODO warn if not TRACK? 140 | fits_read_key(pf->fptr, TSTRING, "RA", hdr->ra_str, NULL, status); 141 | fits_read_key(pf->fptr, TSTRING, "DEC", hdr->dec_str, NULL, status); 142 | fits_read_key(pf->fptr, TDOUBLE, "BMAJ", &(hdr->beam_FWHM), NULL, status); 143 | fits_read_key(pf->fptr, TSTRING, "CAL_MODE", hdr->cal_mode, NULL, status); 144 | fits_read_key(pf->fptr, TDOUBLE, "CAL_FREQ", &(hdr->cal_freq), NULL, 145 | status); 146 | fits_read_key(pf->fptr, TDOUBLE, "CAL_DCYC", &(hdr->cal_dcyc), NULL, 147 | status); 148 | fits_read_key(pf->fptr, TDOUBLE, "CAL_PHS", &(hdr->cal_phs), NULL, status); 149 | fits_read_key(pf->fptr, TSTRING, "FD_MODE", hdr->feed_mode, NULL, status); 150 | fits_read_key(pf->fptr, TDOUBLE, "FA_REQ", &(hdr->feed_angle), NULL, 151 | status); 152 | fits_read_key(pf->fptr, TDOUBLE, "SCANLEN", &(hdr->scanlen), NULL, status); 153 | fits_read_key(pf->fptr, TDOUBLE, "FD_SANG", &(hdr->fd_sang), NULL, status); 154 | fits_read_key(pf->fptr, TDOUBLE, "FD_XYPH", &(hdr->fd_xyph), NULL, status); 155 | fits_read_key(pf->fptr, TINT, "FD_HAND", &(hdr->fd_hand), NULL, status); 156 | fits_read_key(pf->fptr, TINT, "BE_PHASE", &(hdr->be_phase), NULL, status); 157 | 158 | fits_read_key(pf->fptr, TINT, "STT_IMJD", &itmp, NULL, status); 159 | hdr->MJD_epoch = (long double)itmp; 160 | hdr->start_day = itmp; 161 | fits_read_key(pf->fptr, TDOUBLE, "STT_SMJD", &dtmp, NULL, status); 162 | hdr->MJD_epoch += dtmp/86400.0L; 163 | hdr->start_sec = dtmp; 164 | fits_read_key(pf->fptr, TDOUBLE, "STT_OFFS", &dtmp, NULL, status); 165 | hdr->MJD_epoch += dtmp/86400.0L; 166 | hdr->start_sec += dtmp; 167 | 168 | fits_read_key(pf->fptr, TDOUBLE, "STT_LST", &(hdr->start_lst), NULL, 169 | status); 170 | 171 | // Move to first subint 172 | fits_movnam_hdu(pf->fptr, BINARY_TBL, "SUBINT", 0, status); 173 | 174 | // Read some more stuff 175 | fits_read_key(pf->fptr, TINT, "NPOL", &(hdr->npol), NULL, status); 176 | fits_read_key(pf->fptr, TSTRING, "POL_TYPE", &(hdr->poln_order), NULL, status); 177 | if (strncmp(hdr->poln_order, "AA+BB", 6)==0) hdr->summed_polns=1; 178 | else hdr->summed_polns=0; 179 | fits_read_key(pf->fptr, TDOUBLE, "TBIN", &(hdr->dt), NULL, status); 180 | fits_read_key(pf->fptr, TINT, "NBIN", &(hdr->nbin), NULL, status); 181 | fits_read_key(pf->fptr, TINT, "NSUBOFFS", &(hdr->offset_subint), NULL, 182 | status); 183 | fits_read_key(pf->fptr, TINT, "NCHAN", &(hdr->nchan), NULL, status); 184 | fits_read_key(pf->fptr, TDOUBLE, "CHAN_BW", &(hdr->df), NULL, status); 185 | fits_read_key(pf->fptr, TINT, "NSBLK", &(hdr->nsblk), NULL, status); 186 | fits_read_key(pf->fptr, TINT, "NBITS", &(hdr->nbits), NULL, status); 187 | 188 | if (mode==SEARCH_MODE) { 189 | long long lltmp = hdr->nsblk; // Prevents a possible overflow in numerator below 190 | lltmp = (lltmp * hdr->nbits * hdr->nchan * hdr->npol) / 8L; 191 | sub->bytes_per_subint = (int) lltmp; 192 | } else if (mode==FOLD_MODE) { 193 | sub->bytes_per_subint = 194 | (hdr->nbin * hdr->nchan * hdr->npol); // XXX data type?? 195 | } 196 | 197 | // Init counters 198 | pf->rownum = 1; 199 | fits_read_key(pf->fptr, TINT, "NAXIS2", &(pf->rows_per_file), NULL, status); 200 | 201 | return *status; 202 | } 203 | 204 | 205 | void apply_scales_and_offsets(int numchan, int numpol, int numspect, 206 | int numunsigned, 207 | float *scales, float *offsets, 208 | unsigned char *inbuf, float *outbuf) 209 | { 210 | int ii, jj, poln, N; 211 | float *outptr = outbuf; 212 | 213 | N = numchan * numpol; 214 | for (ii = 0 ; ii < numspect ; ii++) { 215 | for (poln = 0 ; poln < numpol ; poln++) { 216 | float *sptr = scales + poln * numchan; 217 | float *optr = offsets + poln * numchan; 218 | if (poln < numunsigned) { 219 | unsigned char *inptr = inbuf + ii * N + poln * numchan; 220 | for (jj = 0 ; jj < numchan ; jj++, sptr++, optr++, inptr++, outptr++) 221 | *outptr = *sptr * (float)(*inptr) + *optr; 222 | } else { 223 | signed char *inptr = (signed char *)(inbuf + ii * N + poln * numchan); 224 | for (jj = 0 ; jj < numchan ; jj++, sptr++, optr++, inptr++, outptr++) 225 | *outptr = *sptr * (float)(*inptr) + *optr; 226 | } 227 | } 228 | } 229 | } 230 | 231 | 232 | void scale_and_offset_data(struct psrfits *pf, int numunsigned) { 233 | // Make sure that pf->sub.fdata has been allocated! 234 | apply_scales_and_offsets(pf->hdr.nchan, pf->hdr.npol, pf->hdr.nsblk, 235 | numunsigned, 236 | pf->sub.dat_scales, pf->sub.dat_offsets, 237 | pf->sub.data, pf->sub.fdata); 238 | } 239 | 240 | 241 | /* Read next subint from the set of files described 242 | * by the psrfits struct. It is assumed that all files 243 | * form a consistent set. Read automatically goes to the 244 | * next file when one ends. Arrays should be allocated 245 | * outside this routine. 246 | */ 247 | int psrfits_read_subint(struct psrfits *pf) { 248 | 249 | struct hdrinfo *hdr = &(pf->hdr); 250 | struct subint *sub = &(pf->sub); 251 | int colnum = 0, *status = &(pf->status); 252 | 253 | // See if we need to move to next file 254 | if (pf->rownum > pf->rows_per_file) { 255 | printf("Closing file '%s'\n", pf->filename); 256 | fits_close_file(pf->fptr, status); 257 | pf->filenum++; 258 | psrfits_open(pf); 259 | if (*status==FILE_NOT_OPENED) { 260 | printf("Finished with all input files.\n"); 261 | pf->filenum--; 262 | *status = 1; 263 | return *status; 264 | } 265 | } 266 | 267 | int mode = psrfits_obs_mode(hdr->obs_mode); 268 | int nchan = hdr->nchan; 269 | int nivals = hdr->nchan * hdr->npol; 270 | int row = pf->rownum; 271 | 272 | // TODO: bad! really need to base this on column names 273 | fits_get_colnum(pf->fptr, 0, "TSUBINT", &colnum, status); 274 | fits_read_col(pf->fptr, TDOUBLE, colnum, row, 1, 1, NULL, &(sub->tsubint), 275 | NULL, status); 276 | double last_offs = sub->offs; 277 | fits_get_colnum(pf->fptr, 0, "OFFS_SUB", &colnum, status); 278 | fits_read_col(pf->fptr, TDOUBLE, colnum, row, 1, 1, NULL, &(sub->offs), 279 | NULL, status); 280 | // Hack to fix wrapping in coherent data 281 | if (pf->tot_rows > 0) { 282 | double delta_offs = sub->offs - last_offs; 283 | double wrap_offs = 4294967296L * hdr->dt; 284 | if (delta_offs < -0.5*wrap_offs) { 285 | sub->offs += wrap_offs; 286 | fprintf(stderr, "Warning: detected likely counter wrap, attempting to fix it.\n"); 287 | } 288 | } 289 | fits_get_colnum(pf->fptr, 0, "LST_SUB", &colnum, status); 290 | fits_read_col(pf->fptr, TDOUBLE, colnum, row, 1, 1, NULL, &(sub->lst), 291 | NULL, status); 292 | fits_get_colnum(pf->fptr, 0, "RA_SUB", &colnum, status); 293 | fits_read_col(pf->fptr, TDOUBLE, colnum, row, 1, 1, NULL, &(sub->ra), 294 | NULL, status); 295 | fits_get_colnum(pf->fptr, 0, "DEC_SUB", &colnum, status); 296 | fits_read_col(pf->fptr, TDOUBLE, colnum, row, 1, 1, NULL, &(sub->dec), 297 | NULL, status); 298 | fits_get_colnum(pf->fptr, 0, "GLON_SUB", &colnum, status); 299 | fits_read_col(pf->fptr, TDOUBLE, colnum, row, 1, 1, NULL, &(sub->glon), 300 | NULL, status); 301 | fits_get_colnum(pf->fptr, 0, "GLAT_SUB", &colnum, status); 302 | fits_read_col(pf->fptr, TDOUBLE, colnum, row, 1, 1, NULL, &(sub->glat), 303 | NULL, status); 304 | fits_get_colnum(pf->fptr, 0, "FD_ANG", &colnum, status); 305 | fits_read_col(pf->fptr, TDOUBLE, colnum, row, 1, 1, NULL, &(sub->feed_ang), 306 | NULL, status); 307 | fits_get_colnum(pf->fptr, 0, "POS_ANG", &colnum, status); 308 | fits_read_col(pf->fptr, TDOUBLE, colnum, row, 1, 1, NULL, &(sub->pos_ang), 309 | NULL, status); 310 | fits_get_colnum(pf->fptr, 0, "PAR_ANG", &colnum, status); 311 | fits_read_col(pf->fptr, TDOUBLE, colnum, row, 1, 1, NULL, &(sub->par_ang), 312 | NULL, status); 313 | fits_get_colnum(pf->fptr, 0, "TEL_AZ", &colnum, status); 314 | fits_read_col(pf->fptr, TDOUBLE, colnum, row, 1, 1, NULL, &(sub->tel_az), 315 | NULL, status); 316 | fits_get_colnum(pf->fptr, 0, "TEL_ZEN", &colnum, status); 317 | fits_read_col(pf->fptr, TDOUBLE, colnum, row, 1, 1, NULL, &(sub->tel_zen), 318 | NULL, status); 319 | fits_get_colnum(pf->fptr, 0, "DAT_FREQ", &colnum, status); 320 | fits_read_col(pf->fptr, TFLOAT, colnum, row, 1, nchan, NULL, sub->dat_freqs, 321 | NULL, status); 322 | fits_get_colnum(pf->fptr, 0, "DAT_WTS", &colnum, status); 323 | fits_read_col(pf->fptr, TFLOAT, colnum, row, 1, nchan, NULL, sub->dat_weights, 324 | NULL, status); 325 | fits_get_colnum(pf->fptr, 0, "DAT_OFFS", &colnum, status); 326 | fits_read_col(pf->fptr, TFLOAT, colnum, row, 1, nivals, NULL, sub->dat_offsets, 327 | NULL, status); 328 | fits_get_colnum(pf->fptr, 0, "DAT_SCL", &colnum, status); 329 | fits_read_col(pf->fptr, TFLOAT, colnum, row, 1, nivals, NULL, sub->dat_scales, 330 | NULL, status); 331 | fits_get_colnum(pf->fptr, 0, "DATA", &colnum, status); 332 | if (mode==SEARCH_MODE) { 333 | if (hdr->nbits==32) 334 | fits_read_col(pf->fptr, TFLOAT, colnum, row, 1, 335 | sub->bytes_per_subint/4, 336 | NULL, sub->rawdata, NULL, status); 337 | else 338 | fits_read_col(pf->fptr, TBYTE, colnum, row, 1, 339 | sub->bytes_per_subint, 340 | NULL, sub->rawdata, NULL, status); 341 | if (hdr->nbits==4) pf_4bit_to_8bit(pf); 342 | } else if (mode==FOLD_MODE) { 343 | fits_read_col(pf->fptr, TFLOAT, colnum, row, 1, sub->bytes_per_subint, 344 | NULL, sub->data, NULL, status); 345 | } 346 | 347 | // Complain on error 348 | fits_report_error(stderr, *status); 349 | 350 | // Update counters 351 | if (!(*status)) { 352 | pf->rownum++; 353 | pf->tot_rows++; 354 | pf->N += hdr->nsblk; 355 | pf->T = pf->N * hdr->dt; 356 | } 357 | 358 | return *status; 359 | } 360 | 361 | /* Read only part (N "spectra" in time) of the DATA column from the 362 | * current subint from the set of files described by the psrfits 363 | * struct. Put the data into the buffer "buffer". It is assumed that 364 | * all files form a consistent set. Read automatically goes to the 365 | * next file when one ends. Arrays should be allocated outside this 366 | * routine. Counters are _not_ updated as they are in 367 | * psrfits_read_subint(). 368 | */ 369 | int psrfits_read_part_DATA(struct psrfits *pf, int N, int numunsigned, 370 | float *fbuffer) { 371 | 372 | struct hdrinfo *hdr = &(pf->hdr); 373 | int colnum = 0, *status = &(pf->status); 374 | 375 | // See if we need to move to next file 376 | if (pf->rownum > pf->rows_per_file) { 377 | printf("Closing file '%s'\n", pf->filename); 378 | fits_close_file(pf->fptr, status); 379 | pf->filenum++; 380 | psrfits_open(pf); 381 | if (*status==FILE_NOT_OPENED) { 382 | printf("Finished with all input files.\n"); 383 | pf->filenum--; 384 | *status = 1; 385 | return *status; 386 | } 387 | } 388 | 389 | int nivals = hdr->nchan * hdr->npol; 390 | long long numdata = (long long) nivals * (long long) N; 391 | long long bytes_to_read = (hdr->nbits * numdata) / 8L; 392 | float *offsets = (float *)malloc(sizeof(float) * nivals); 393 | float *scales = (float *)malloc(sizeof(float) * nivals); 394 | unsigned char *buffer = (unsigned char *)malloc(numdata); 395 | unsigned char *rawbuffer = buffer; 396 | if (hdr->nbits==4) { 397 | rawbuffer = (unsigned char *)malloc(bytes_to_read); 398 | } 399 | 400 | // Now read the data 401 | fits_get_colnum(pf->fptr, 0, "DAT_OFFS", &colnum, status); 402 | fits_read_col(pf->fptr, TFLOAT, colnum, pf->rownum, 1, nivals, 403 | NULL, offsets, NULL, status); 404 | fits_get_colnum(pf->fptr, 0, "DAT_SCL", &colnum, status); 405 | fits_read_col(pf->fptr, TFLOAT, colnum, pf->rownum, 1, nivals, 406 | NULL, scales, NULL, status); 407 | fits_get_colnum(pf->fptr, 0, "DATA", &colnum, status); 408 | fits_read_col(pf->fptr, TBYTE, colnum, pf->rownum, 1, bytes_to_read, 409 | NULL, rawbuffer, NULL, status); 410 | if (hdr->nbits==4) { 411 | convert_4bit_to_8bit(rawbuffer, (unsigned char *)buffer, numdata); 412 | free(rawbuffer); 413 | } 414 | 415 | // Now convert the 8-bit data to floats using the scales and offsets 416 | apply_scales_and_offsets(hdr->nchan, hdr->npol, N, numunsigned, 417 | scales, offsets, buffer, fbuffer); 418 | free(offsets); 419 | free(scales); 420 | free(buffer); 421 | 422 | // Complain on error 423 | fits_report_error(stderr, *status); 424 | 425 | return *status; 426 | } 427 | -------------------------------------------------------------------------------- /combine_mocks_cmd.c: -------------------------------------------------------------------------------- 1 | /***** 2 | command line parser -- generated by clig 3 | (http://wsd.iitb.fhg.de/~kir/clighome/) 4 | 5 | The command line parser `clig': 6 | (C) 1995-2004 Harald Kirsch (clig@geggus.net) 7 | *****/ 8 | 9 | #include 10 | #include 11 | #include 12 | #include 13 | #include 14 | #include 15 | #include 16 | #include 17 | 18 | #include "combine_mocks_cmd.h" 19 | 20 | char *Program; 21 | 22 | /*@-null*/ 23 | 24 | static Cmdline cmd = { 25 | /***** -o: Basename for the output files */ 26 | /* outputbasenameP = */ 0, 27 | /* outputbasename = */ (char*)0, 28 | /* outputbasenameC = */ 0, 29 | /***** uninterpreted rest of command line */ 30 | /* argc = */ 0, 31 | /* argv = */ (char**)0, 32 | /***** the original command line concatenated */ 33 | /* full_cmd_line = */ NULL 34 | }; 35 | 36 | /*@=null*/ 37 | 38 | /***** let LCLint run more smoothly */ 39 | /*@-predboolothers*/ 40 | /*@-boolops*/ 41 | 42 | 43 | /******************************************************************/ 44 | /***** 45 | This is a bit tricky. We want to make a difference between overflow 46 | and underflow and we want to allow v==Inf or v==-Inf but not 47 | v>FLT_MAX. 48 | 49 | We don't use fabs to avoid linkage with -lm. 50 | *****/ 51 | static void 52 | checkFloatConversion(double v, char *option, char *arg) 53 | { 54 | char *err = NULL; 55 | 56 | if( (errno==ERANGE && v!=0.0) /* even double overflowed */ 57 | || (v-HUGE_VAL && (v<0.0?-v:v)>(double)FLT_MAX) ) { 58 | err = "large"; 59 | } else if( (errno==ERANGE && v==0.0) 60 | || (v!=0.0 && (v<0.0?-v:v)<(double)FLT_MIN) ) { 61 | err = "small"; 62 | } 63 | if( err ) { 64 | fprintf(stderr, 65 | "%s: parameter `%s' of option `%s' to %s to represent\n", 66 | Program, arg, option, err); 67 | exit(EXIT_FAILURE); 68 | } 69 | } 70 | 71 | int 72 | getIntOpt(int argc, char **argv, int i, int *value, int force) 73 | { 74 | char *end; 75 | long v; 76 | 77 | if( ++i>=argc ) goto nothingFound; 78 | 79 | errno = 0; 80 | v = strtol(argv[i], &end, 0); 81 | 82 | /***** check for conversion error */ 83 | if( end==argv[i] ) goto nothingFound; 84 | 85 | /***** check for surplus non-whitespace */ 86 | while( isspace((int) *end) ) end+=1; 87 | if( *end ) goto nothingFound; 88 | 89 | /***** check if it fits into an int */ 90 | if( errno==ERANGE || v>(long)INT_MAX || v<(long)INT_MIN ) { 91 | fprintf(stderr, 92 | "%s: parameter `%s' of option `%s' to large to represent\n", 93 | Program, argv[i], argv[i-1]); 94 | exit(EXIT_FAILURE); 95 | } 96 | *value = (int)v; 97 | 98 | return i; 99 | 100 | nothingFound: 101 | if( !force ) return i-1; 102 | 103 | fprintf(stderr, 104 | "%s: missing or malformed integer value after option `%s'\n", 105 | Program, argv[i-1]); 106 | exit(EXIT_FAILURE); 107 | } 108 | /**********************************************************************/ 109 | 110 | int 111 | getIntOpts(int argc, char **argv, int i, 112 | int **values, 113 | int cmin, int cmax) 114 | /***** 115 | We want to find at least cmin values and at most cmax values. 116 | cmax==-1 then means infinitely many are allowed. 117 | *****/ 118 | { 119 | int alloced, used; 120 | char *end; 121 | long v; 122 | if( i+cmin >= argc ) { 123 | fprintf(stderr, 124 | "%s: option `%s' wants at least %d parameters\n", 125 | Program, argv[i], cmin); 126 | exit(EXIT_FAILURE); 127 | } 128 | 129 | /***** 130 | alloc a bit more than cmin values. It does not hurt to have room 131 | for a bit more values than cmax. 132 | *****/ 133 | alloced = cmin + 4; 134 | *values = (int*)calloc((size_t)alloced, sizeof(int)); 135 | if( ! *values ) { 136 | outMem: 137 | fprintf(stderr, 138 | "%s: out of memory while parsing option `%s'\n", 139 | Program, argv[i]); 140 | exit(EXIT_FAILURE); 141 | } 142 | 143 | for(used=0; (cmax==-1 || used(long)INT_MAX || v<(long)INT_MIN ) { 162 | fprintf(stderr, 163 | "%s: parameter `%s' of option `%s' to large to represent\n", 164 | Program, argv[i+used+1], argv[i]); 165 | exit(EXIT_FAILURE); 166 | } 167 | 168 | (*values)[used] = (int)v; 169 | 170 | } 171 | 172 | if( used=argc ) goto nothingFound; 190 | 191 | errno = 0; 192 | *value = strtol(argv[i], &end, 0); 193 | 194 | /***** check for conversion error */ 195 | if( end==argv[i] ) goto nothingFound; 196 | 197 | /***** check for surplus non-whitespace */ 198 | while( isspace((int) *end) ) end+=1; 199 | if( *end ) goto nothingFound; 200 | 201 | /***** check for overflow */ 202 | if( errno==ERANGE ) { 203 | fprintf(stderr, 204 | "%s: parameter `%s' of option `%s' to large to represent\n", 205 | Program, argv[i], argv[i-1]); 206 | exit(EXIT_FAILURE); 207 | } 208 | return i; 209 | 210 | nothingFound: 211 | /***** !force means: this parameter may be missing.*/ 212 | if( !force ) return i-1; 213 | 214 | fprintf(stderr, 215 | "%s: missing or malformed value after option `%s'\n", 216 | Program, argv[i-1]); 217 | exit(EXIT_FAILURE); 218 | } 219 | /**********************************************************************/ 220 | 221 | int 222 | getLongOpts(int argc, char **argv, int i, 223 | long **values, 224 | int cmin, int cmax) 225 | /***** 226 | We want to find at least cmin values and at most cmax values. 227 | cmax==-1 then means infinitely many are allowed. 228 | *****/ 229 | { 230 | int alloced, used; 231 | char *end; 232 | 233 | if( i+cmin >= argc ) { 234 | fprintf(stderr, 235 | "%s: option `%s' wants at least %d parameters\n", 236 | Program, argv[i], cmin); 237 | exit(EXIT_FAILURE); 238 | } 239 | 240 | /***** 241 | alloc a bit more than cmin values. It does not hurt to have room 242 | for a bit more values than cmax. 243 | *****/ 244 | alloced = cmin + 4; 245 | *values = (long int *)calloc((size_t)alloced, sizeof(long)); 246 | if( ! *values ) { 247 | outMem: 248 | fprintf(stderr, 249 | "%s: out of memory while parsing option `%s'\n", 250 | Program, argv[i]); 251 | exit(EXIT_FAILURE); 252 | } 253 | 254 | for(used=0; (cmax==-1 || used=argc ) goto nothingFound; 300 | 301 | errno = 0; 302 | v = strtod(argv[i], &end); 303 | 304 | /***** check for conversion error */ 305 | if( end==argv[i] ) goto nothingFound; 306 | 307 | /***** check for surplus non-whitespace */ 308 | while( isspace((int) *end) ) end+=1; 309 | if( *end ) goto nothingFound; 310 | 311 | /***** check for overflow */ 312 | checkFloatConversion(v, argv[i-1], argv[i]); 313 | 314 | *value = (float)v; 315 | 316 | return i; 317 | 318 | nothingFound: 319 | if( !force ) return i-1; 320 | 321 | fprintf(stderr, 322 | "%s: missing or malformed float value after option `%s'\n", 323 | Program, argv[i-1]); 324 | exit(EXIT_FAILURE); 325 | 326 | } 327 | /**********************************************************************/ 328 | 329 | int 330 | getFloatOpts(int argc, char **argv, int i, 331 | float **values, 332 | int cmin, int cmax) 333 | /***** 334 | We want to find at least cmin values and at most cmax values. 335 | cmax==-1 then means infinitely many are allowed. 336 | *****/ 337 | { 338 | int alloced, used; 339 | char *end; 340 | double v; 341 | 342 | if( i+cmin >= argc ) { 343 | fprintf(stderr, 344 | "%s: option `%s' wants at least %d parameters\n", 345 | Program, argv[i], cmin); 346 | exit(EXIT_FAILURE); 347 | } 348 | 349 | /***** 350 | alloc a bit more than cmin values. 351 | *****/ 352 | alloced = cmin + 4; 353 | *values = (float*)calloc((size_t)alloced, sizeof(float)); 354 | if( ! *values ) { 355 | outMem: 356 | fprintf(stderr, 357 | "%s: out of memory while parsing option `%s'\n", 358 | Program, argv[i]); 359 | exit(EXIT_FAILURE); 360 | } 361 | 362 | for(used=0; (cmax==-1 || used=argc ) goto nothingFound; 403 | 404 | errno = 0; 405 | *value = strtod(argv[i], &end); 406 | 407 | /***** check for conversion error */ 408 | if( end==argv[i] ) goto nothingFound; 409 | 410 | /***** check for surplus non-whitespace */ 411 | while( isspace((int) *end) ) end+=1; 412 | if( *end ) goto nothingFound; 413 | 414 | /***** check for overflow */ 415 | if( errno==ERANGE ) { 416 | fprintf(stderr, 417 | "%s: parameter `%s' of option `%s' to %s to represent\n", 418 | Program, argv[i], argv[i-1], 419 | (*value==0.0 ? "small" : "large")); 420 | exit(EXIT_FAILURE); 421 | } 422 | 423 | return i; 424 | 425 | nothingFound: 426 | if( !force ) return i-1; 427 | 428 | fprintf(stderr, 429 | "%s: missing or malformed value after option `%s'\n", 430 | Program, argv[i-1]); 431 | exit(EXIT_FAILURE); 432 | 433 | } 434 | /**********************************************************************/ 435 | 436 | int 437 | getDoubleOpts(int argc, char **argv, int i, 438 | double **values, 439 | int cmin, int cmax) 440 | /***** 441 | We want to find at least cmin values and at most cmax values. 442 | cmax==-1 then means infinitely many are allowed. 443 | *****/ 444 | { 445 | int alloced, used; 446 | char *end; 447 | 448 | if( i+cmin >= argc ) { 449 | fprintf(stderr, 450 | "%s: option `%s' wants at least %d parameters\n", 451 | Program, argv[i], cmin); 452 | exit(EXIT_FAILURE); 453 | } 454 | 455 | /***** 456 | alloc a bit more than cmin values. 457 | *****/ 458 | alloced = cmin + 4; 459 | *values = (double*)calloc((size_t)alloced, sizeof(double)); 460 | if( ! *values ) { 461 | outMem: 462 | fprintf(stderr, 463 | "%s: out of memory while parsing option `%s'\n", 464 | Program, argv[i]); 465 | exit(EXIT_FAILURE); 466 | } 467 | 468 | for(used=0; (cmax==-1 || used=argc ) { 516 | if( force ) { 517 | fprintf(stderr, "%s: missing string after option `%s'\n", 518 | Program, argv[i-1]); 519 | exit(EXIT_FAILURE); 520 | } 521 | return i-1; 522 | } 523 | 524 | if( !force && argv[i][0] == '-' ) return i-1; 525 | *value = argv[i]; 526 | return i; 527 | } 528 | /**********************************************************************/ 529 | 530 | int 531 | getStringOpts(int argc, char **argv, int i, 532 | char* **values, 533 | int cmin, int cmax) 534 | /***** 535 | We want to find at least cmin values and at most cmax values. 536 | cmax==-1 then means infinitely many are allowed. 537 | *****/ 538 | { 539 | int alloced, used; 540 | 541 | if( i+cmin >= argc ) { 542 | fprintf(stderr, 543 | "%s: option `%s' wants at least %d parameters\n", 544 | Program, argv[i], cmin); 545 | exit(EXIT_FAILURE); 546 | } 547 | 548 | alloced = cmin + 4; 549 | 550 | *values = (char**)calloc((size_t)alloced, sizeof(char*)); 551 | if( ! *values ) { 552 | outMem: 553 | fprintf(stderr, 554 | "%s: out of memory during parsing of option `%s'\n", 555 | Program, argv[i]); 556 | exit(EXIT_FAILURE); 557 | } 558 | 559 | for(used=0; (cmax==-1 || used=cmin && argv[used+i+1][0]=='-' ) break; 567 | (*values)[used] = argv[used+i+1]; 568 | } 569 | 570 | if( used=min ) continue; 603 | fprintf(stderr, 604 | "%s: parameter %d of option `%s' smaller than min=%d\n", 605 | Program, i+1, opt, min); 606 | exit(EXIT_FAILURE); 607 | } 608 | } 609 | /**********************************************************************/ 610 | 611 | void 612 | checkLongLower(char *opt, long *values, int count, long max) 613 | { 614 | int i; 615 | 616 | for(i=0; i=min ) continue; 633 | fprintf(stderr, 634 | "%s: parameter %d of option `%s' smaller than min=%ld\n", 635 | Program, i+1, opt, min); 636 | exit(EXIT_FAILURE); 637 | } 638 | } 639 | /**********************************************************************/ 640 | 641 | void 642 | checkFloatLower(char *opt, float *values, int count, float max) 643 | { 644 | int i; 645 | 646 | for(i=0; i=min ) continue; 663 | fprintf(stderr, 664 | "%s: parameter %d of option `%s' smaller than min=%f\n", 665 | Program, i+1, opt, min); 666 | exit(EXIT_FAILURE); 667 | } 668 | } 669 | /**********************************************************************/ 670 | 671 | void 672 | checkDoubleLower(char *opt, double *values, int count, double max) 673 | { 674 | int i; 675 | 676 | for(i=0; i=min ) continue; 693 | fprintf(stderr, 694 | "%s: parameter %d of option `%s' smaller than min=%f\n", 695 | Program, i+1, opt, min); 696 | exit(EXIT_FAILURE); 697 | } 698 | } 699 | /**********************************************************************/ 700 | 701 | static char * 702 | catArgv(int argc, char **argv) 703 | { 704 | int i; 705 | size_t l; 706 | char *s, *t; 707 | 708 | for(i=0, l=0; icmd.argc ) { 777 | fprintf(stderr, "%s: there should be at least 1 non-option argument(s)\n", 778 | Program); 779 | exit(EXIT_FAILURE); 780 | } 781 | if( 2000 6 | #include 7 | #include 8 | #include 9 | #include 10 | #include 11 | #include 12 | #include 13 | #include "polyco.h" 14 | #include "fold.h" 15 | #include "psrfits.h" 16 | 17 | /* Signal handler */ 18 | int run=1; 19 | void cc(int sig) { run=0; } 20 | 21 | void usage() { 22 | printf( 23 | "Usage: fold_psrfits [options] input_filename_base or filenames\n" 24 | "Options:\n" 25 | " -h, --help Print this\n" 26 | " -o name, --output=name Output base filename (auto-generate)\n" 27 | " -b nn, --nbin=nn Number of profile bins (256)\n" 28 | " -t nn, --tsub=n Folded subintegration time, sec (60)\n" 29 | " -j nn, --nthread=nn Max number of threads (4)\n" 30 | " -i nn, --initial=nn Starting input file number (1)\n" 31 | " -f nn, --final=nn Ending input file number (auto)\n" 32 | " -s src, --src=src Override source name from file\n" 33 | " -p file, --polyco=file Polyco file to use (polyco.dat)\n" 34 | " -P file, --parfile=file Use given .par file\n" 35 | " -F nn, --foldfreq=nn Fold at constant freq (Hz)\n" 36 | " -C, --cal Cal folding mode\n" 37 | " -u, --unsigned Raw data is unsigned\n" 38 | " -U n, --nunsigned Num of unsigned polns\n" 39 | " -S size, --split=size Approximate max size per output file, GB (1)\n" 40 | " -A, --apply Apply input scale/offset to the results\n" 41 | " -T nn, --start=nn Start nn seconds in to the set\n" 42 | " -E nn, --end=nn Stop nn seconds in to the set\n" 43 | " -q, --quiet No progress indicator\n" 44 | ); 45 | } 46 | 47 | int main(int argc, char *argv[]) { 48 | 49 | /* Cmd line */ 50 | static struct option long_opts[] = { 51 | {"output", 1, NULL, 'o'}, 52 | {"nbin", 1, NULL, 'b'}, 53 | {"tsub", 1, NULL, 't'}, 54 | {"nthread", 1, NULL, 'j'}, 55 | {"initial", 1, NULL, 'i'}, 56 | {"final", 1, NULL, 'f'}, 57 | {"src", 1, NULL, 's'}, 58 | {"polyco", 1, NULL, 'p'}, 59 | {"parfile", 1, NULL, 'P'}, 60 | {"foldfreq",1, NULL, 'F'}, 61 | {"cal", 0, NULL, 'C'}, 62 | {"unsigned",0, NULL, 'u'}, 63 | {"nunsigned",1, NULL, 'U'}, 64 | {"split", 1, NULL, 'S'}, 65 | {"apply", 0, NULL, 'A'}, 66 | {"quiet", 0, NULL, 'q'}, 67 | {"start", 1, NULL, 'T'}, 68 | {"end", 1, NULL, 'E'}, 69 | {"help", 0, NULL, 'h'}, 70 | {0,0,0,0} 71 | }; 72 | int opt, opti; 73 | int nbin=256, nthread=4, fnum_start=1, fnum_end=0; 74 | int quiet=0, raw_signed=1, use_polycos=1, cal=0, apply_scale=0; 75 | double split_size_gb = 1.0; 76 | double tfold = 60.0; 77 | double fold_frequency=0.0; 78 | double tstart=-1.0, tend=-1.0; 79 | char output_base[256] = ""; 80 | char polyco_file[256] = ""; 81 | char par_file[256] = ""; 82 | char source[24]; source[0]='\0'; 83 | while ((opt=getopt_long(argc,argv,"o:b:t:j:i:f:s:p:P:F:CuU:S:AT:E:qh",long_opts,&opti))!=-1) { 84 | switch (opt) { 85 | case 'o': 86 | strncpy(output_base, optarg, 255); 87 | output_base[255]='\0'; 88 | break; 89 | case 'b': 90 | nbin = atoi(optarg); 91 | break; 92 | case 't': 93 | tfold = atof(optarg); 94 | break; 95 | case 'j': 96 | nthread = atoi(optarg); 97 | break; 98 | case 'i': 99 | fnum_start = atoi(optarg); 100 | break; 101 | case 'f': 102 | fnum_end = atoi(optarg); 103 | break; 104 | case 's': 105 | strncpy(source, optarg, 24); 106 | source[23]='\0'; 107 | break; 108 | case 'p': 109 | strncpy(polyco_file, optarg, 255); 110 | polyco_file[255]='\0'; 111 | use_polycos = 1; 112 | break; 113 | case 'P': 114 | strncpy(par_file, optarg, 255); 115 | par_file[255] = '\0'; 116 | break; 117 | case 'F': 118 | fold_frequency = atof(optarg); 119 | use_polycos = 0; 120 | break; 121 | case 'C': 122 | cal = 1; 123 | use_polycos = 0; 124 | break; 125 | case 'u': 126 | raw_signed=0; 127 | break; 128 | case 'U': 129 | raw_signed = 4 - atoi(optarg); 130 | break; 131 | case 'S': 132 | split_size_gb = atof(optarg); 133 | break; 134 | case 'A': 135 | apply_scale = 1; 136 | break; 137 | case 'T': 138 | tstart = atof(optarg); 139 | break; 140 | case 'E': 141 | tend = atof(optarg); 142 | break; 143 | case 'q': 144 | quiet=1; 145 | break; 146 | case 'h': 147 | default: 148 | usage(); 149 | exit(0); 150 | break; 151 | } 152 | 153 | } 154 | if (optind==argc) { 155 | usage(); 156 | exit(1); 157 | } 158 | 159 | /* If no polyco/par file given, default to polyco.dat */ 160 | if (use_polycos && (par_file[0]=='\0' && polyco_file[0]=='\0')) 161 | sprintf(polyco_file, "polyco.dat"); 162 | 163 | /* Open first file */ 164 | struct psrfits pf; 165 | psrfits_set_files(&pf, argc - optind, argv + optind); 166 | // Use the dynamic filename allocation 167 | if (pf.numfiles==0) pf.filenum = fnum_start; 168 | pf.tot_rows = pf.N = pf.T = pf.status = 0; 169 | pf.hdr.chan_dm = 0.0; // What if folding data that has been partially de-dispersed? 170 | int rv = psrfits_open(&pf); 171 | if (rv) { fits_report_error(stderr, rv); exit(1); } 172 | 173 | // /* Check any constraints */ 174 | // if (pf.hdr.nbits!=8) { 175 | // fprintf(stderr, "Only implemented for 8-bit data (read nbits=%d).\n", 176 | // pf.hdr.nbits); 177 | // exit(1); 178 | // } 179 | 180 | /* Check for calfreq */ 181 | if (cal) { 182 | if (pf.hdr.cal_freq==0.0) { 183 | if (fold_frequency==0.0) { 184 | fprintf(stderr, "Error: Cal mode selected, but CAL_FREQ=0. " 185 | "Set cal frequency with -F\n"); 186 | exit(1); 187 | } else { 188 | pf.hdr.cal_freq = fold_frequency; 189 | } 190 | } else { 191 | fold_frequency = pf.hdr.cal_freq; 192 | } 193 | } 194 | 195 | /* Set up output file */ 196 | struct psrfits pf_out; 197 | memcpy(&pf_out, &pf, sizeof(struct psrfits)); 198 | if (source[0]!='\0') { strncpy(pf_out.hdr.source, source, 24); } 199 | else { strncpy(source, pf.hdr.source, 24); source[23]='\0'; } 200 | if (output_base[0]=='\0') { 201 | /* Set up default output filename */ 202 | sprintf(output_base, "%s_%s_%5.5d_%5.5d%s", pf_out.hdr.backend, 203 | pf_out.hdr.source, pf_out.hdr.start_day, 204 | (int)pf_out.hdr.start_sec, cal ? "_cal" : ""); 205 | } 206 | sprintf(pf_out.basefilename, output_base); 207 | if (cal) { 208 | sprintf(pf_out.hdr.obs_mode, "CAL"); 209 | sprintf(pf_out.hdr.cal_mode, "SYNC"); 210 | } else 211 | sprintf(pf_out.hdr.obs_mode, "PSR"); 212 | strncpy(pf_out.fold.parfile,par_file,255); pf_out.fold.parfile[255]='\0'; 213 | pf_out.fptr = NULL; 214 | pf_out.filenum=0; 215 | pf_out.status=0; 216 | pf_out.quiet=0; 217 | pf_out.hdr.nbin=nbin; 218 | pf_out.sub.FITS_typecode = TFLOAT; 219 | pf_out.sub.bytes_per_subint = sizeof(float) * 220 | pf_out.hdr.nchan * pf_out.hdr.npol * pf_out.hdr.nbin; 221 | if (split_size_gb > 0.0) { 222 | pf_out.multifile = 1; 223 | pf_out.rows_per_file = (int) (split_size_gb * (1024.0*1024.0*1024.0) 224 | / (double)pf_out.sub.bytes_per_subint); 225 | printf("Writing a maximum of %d subintegrations (~%.1f GB) per output file.\n", 226 | pf_out.rows_per_file, split_size_gb); 227 | } else { 228 | pf_out.multifile = 0; 229 | printf("Writing a single output file.\n"); 230 | } 231 | 232 | rv = psrfits_create(&pf_out); 233 | if (rv) { fits_report_error(stderr, rv); exit(1); } 234 | 235 | /* Alloc data buffers */ 236 | pf.sub.dat_freqs = (float *)malloc(sizeof(float) * pf.hdr.nchan); 237 | pf_out.sub.dat_freqs = pf.sub.dat_freqs; 238 | pf.sub.dat_weights = (float *)malloc(sizeof(float) * pf.hdr.nchan); 239 | pf_out.sub.dat_weights = (float *)malloc(sizeof(float) * pf.hdr.nchan); 240 | pf.sub.dat_offsets = (float *)malloc(sizeof(float) 241 | * pf.hdr.nchan * pf.hdr.npol); 242 | pf_out.sub.dat_offsets = (float *)malloc(sizeof(float) 243 | * pf.hdr.nchan * pf.hdr.npol); 244 | pf.sub.dat_scales = (float *)malloc(sizeof(float) 245 | * pf.hdr.nchan * pf.hdr.npol); 246 | pf_out.sub.dat_scales = (float *)malloc(sizeof(float) 247 | * pf.hdr.nchan * pf.hdr.npol); 248 | pf_out.sub.data = (unsigned char *)malloc(pf_out.sub.bytes_per_subint); 249 | 250 | /* Output scale/offset */ 251 | int i, ipol, ichan; 252 | float offset_uv=0.0; 253 | // Extra cross-term offset for GUPPI 254 | if (strcmp("GUPPI",pf.hdr.backend)==0 && apply_scale==0) { 255 | offset_uv=0.5; 256 | fprintf(stderr, "Found backend=GUPPI, setting offset_uv=%f\n", 257 | offset_uv); 258 | } 259 | // Initialize scale/output and weights. 260 | // These get copied from the input file later during the main loop. 261 | for (ipol=0; ipol1) offs = offset_uv; 265 | pf_out.sub.dat_scales[ipol*pf.hdr.nchan + ichan] = 1.0; 266 | pf_out.sub.dat_offsets[ipol*pf.hdr.nchan + ichan] = offs; 267 | } 268 | } 269 | for (i=0; inbin = pf_out.hdr.nbin; 343 | fargs[i].fb->nchan = pf.hdr.nchan; 344 | fargs[i].fb->npol = pf.hdr.npol; 345 | fargs[i].nsamp = pf.hdr.nsblk; 346 | fargs[i].tsamp = pf.hdr.dt; 347 | fargs[i].raw_signed=raw_signed; 348 | malloc_foldbuf(fargs[i].fb); 349 | clear_foldbuf(fargs[i].fb); 350 | fargs[i].scale = (float *)malloc(sizeof(float) 351 | * pf.hdr.nchan * pf.hdr.npol); 352 | fargs[i].offset = (float *)malloc(sizeof(float) 353 | * pf.hdr.nchan * pf.hdr.npol); 354 | } 355 | 356 | /* Main loop */ 357 | rv=0; 358 | int imjd; 359 | double fmjd, fmjd0=0, fmjd_next=0, fmjd_epoch; 360 | double offs0=0, offs1=0; 361 | //double phase=0.0, freq=1.0; 362 | int first=1, subcount=0; 363 | int cur_thread = 0; 364 | signal(SIGINT, cc); 365 | while (run) { 366 | 367 | /* Read data block */ 368 | pf.sub.data = (unsigned char *)fargs[cur_thread].data; 369 | if (pf.hdr.nbits >= 8) { 370 | // 8-or-more-bit raw data. No need for conversion 371 | pf.sub.rawdata = pf.sub.data; 372 | } else { 373 | pf.sub.rawdata = (char *)malloc(sizeof(char)*pf.sub.bytes_per_subint); 374 | } 375 | rv = psrfits_read_subint(&pf); 376 | if (rv) { 377 | if (rv==FILE_NOT_OPENED) rv=0; // Don't complain on file not found 378 | run=0; 379 | break; 380 | } 381 | 382 | /* If we've passed final file, exit */ 383 | if (fnum_end && pf.filenum>fnum_end) { run=0; break; } 384 | 385 | /* Get start date, etc */ 386 | imjd = (int)pf.hdr.MJD_epoch; 387 | fmjd = (double)(pf.hdr.MJD_epoch - (long double)imjd); 388 | fmjd += (pf.sub.offs-0.5*pf.sub.tsubint)/86400.0; 389 | 390 | /* Check for start/end times */ 391 | if (tstart>0.0 && pf.sub.offs0.0 && pf.sub.offs>tend) { run=0; break; } 393 | 394 | /* First time stuff */ 395 | if (first) { 396 | fmjd0 = fmjd; 397 | fmjd_next = fmjd + tfold/86400.0; 398 | pf_out.sub.offs=0.0; 399 | offs0 = pf.sub.offs - 0.5*pf.sub.tsubint; 400 | offs1 = pf.sub.offs + 0.5*pf.sub.tsubint; 401 | first=0; 402 | for (i=0; ifmjd_next) { 468 | 469 | /* Loop over active threads */ 470 | for (i=0; i fmjd_next) { 499 | 500 | /* Figure out timestamp */ 501 | pf_out.sub.offs /= (double)subcount; 502 | pf_out.sub.tsubint = offs1 - offs0; 503 | fmjd_epoch = fmjd0 + pf_out.sub.offs/86400.0; 504 | /* 505 | // Don't need this stuff if we set EPOCHS=MIDTIME 506 | ipc = select_pc(pc, npc, pf.hdr.source, imjd, fmjd_epoch); 507 | if (ipc<0) { 508 | fprintf(stderr, "Polyco error, exiting.\n"); 509 | exit(1); 510 | } 511 | phase = psr_phase(&pc[ipc], imjd, fmjd_epoch, &freq); 512 | phase = fmod(phase, 1.0); 513 | pf_out.sub.offs -= phase/freq; // ref epoch needs 0 phase 514 | */ 515 | 516 | /* Transpose, output subint */ 517 | normalize_transpose_folds((float *)pf_out.sub.data, &fb); 518 | int last_filenum = pf_out.filenum; 519 | psrfits_write_subint(&pf_out); 520 | 521 | 522 | /* Check for write errors */ 523 | if (pf_out.status) { 524 | fprintf(stderr, "Error writing subint.\n"); 525 | fits_report_error(stderr, pf_out.status); 526 | exit(1); 527 | } 528 | 529 | /* Check if we started a new file */ 530 | if (pf_out.filenum!=last_filenum) { 531 | /* No polycos yet written to this file */ 532 | for (i=0; i100) { fits_report_error(stderr, rv); } 581 | exit(0); 582 | } 583 | --------------------------------------------------------------------------------