Exemple #1
0
int main(int argc, char *argv []) {

        if(populate_env_variable(REF_ERROR_CODES_FILE, "L2_ERROR_CODES_FILE")) {

                printf("\nUnable to populate [REF_ERROR_CODES_FILE] variable with corresponding environment variable. Routine will proceed without error handling\n");

        }

        if (argc != 7) {

                if(populate_env_variable(SPE_BLURB_FILE, "L2_SPE_BLURB_FILE")) {

                        RETURN_FLAG = 1;

                } else {

                        print_file(SPE_BLURB_FILE);

                }

                write_key_to_file(ERROR_CODES_FILE, REF_ERROR_CODES_FILE, "L2STATEX", -1, "Status flag for L2 spextract routine", ERROR_CODES_FILE_WRITE_ACCESS);

                return 1;

        } else {
                // ***********************************************************************
                // Redefine routine input parameters
                
                char *input_f                           = strdup(argv[1]);              
                char *method                            = strdup(argv[2]); 
                char *ss_method                         = strdup(argv[3]); 
                double target_half_aperture_px          = strtod(argv[4], NULL); 
                int sky_window_half_aperture_px         = strtol(argv[5], NULL, 0);   
                char *output_f                          = strdup(argv[6]);                    
                
                // ***********************************************************************
                // Open input file (ARG 1), get parameters and perform any data format 
                // checks

                fitsfile *input_f_ptr;

                int input_f_maxdim = 2, input_f_status = 0, input_f_bitpix, input_f_naxis;
                long input_f_naxes [2] = {1,1};

                if(!fits_open_file(&input_f_ptr, input_f, IMG_READ_ACCURACY, &input_f_status)) {

                        if(!populate_img_parameters(input_f, input_f_ptr, input_f_maxdim, &input_f_bitpix, &input_f_naxis, input_f_naxes, &input_f_status, "INPUT FRAME")) {

                                if (input_f_naxis != 2) {       // any data format checks here

                                        write_key_to_file(ERROR_CODES_FILE, REF_ERROR_CODES_FILE, "L2STATEX", -2, "Status flag for L2 spextract routine", ERROR_CODES_FILE_WRITE_ACCESS);

                                        free(input_f);
                                        free(output_f);
                                        free(method);
                                        free(ss_method);
                                        if(fits_close_file(input_f_ptr, &input_f_status)) fits_report_error (stdout, input_f_status); 

                                        return 1;
        
                                }

                        } else { 

                                write_key_to_file(ERROR_CODES_FILE, REF_ERROR_CODES_FILE, "L2STATEX", -3, "Status flag for L2 spextract routine", ERROR_CODES_FILE_WRITE_ACCESS);
                                fits_report_error(stdout, input_f_status); 

                                free(input_f);
                                free(output_f);                                
                                free(method);
                                free(ss_method);
                                if(fits_close_file(input_f_ptr, &input_f_status)) fits_report_error (stdout, input_f_status); 

                                return 1; 

                        }

                } else { 

                        write_key_to_file(ERROR_CODES_FILE, REF_ERROR_CODES_FILE, "L2STATEX", -4, "Status flag for L2 spextract routine", ERROR_CODES_FILE_WRITE_ACCESS);
                        fits_report_error(stdout, input_f_status); 

                        free(input_f);
                        free(output_f);                        
                        free(method);
                        free(ss_method);
                        
                        return 1; 

                }
                
                // ***********************************************************************
                // Set the range limits

                int cut_x [2] = {1, input_f_naxes[0]};
                int cut_y [2] = {1, input_f_naxes[1]};

                // ***********************************************************************
                // Set parameters used when reading data from input file (ARG 1)

                long fpixel [2] = {cut_x[0], cut_y[0]};
                long nxelements = (cut_x[1] - cut_x[0]) + 1;
                long nyelements = (cut_y[1] - cut_y[0]) + 1;

                // ***********************************************************************
                // Create arrays to store pixel values from input fits file (ARG 1)

                double input_f_pixels [nxelements];
                
                // ***********************************************************************
                // Get input fits file (ARG 1) values and store in 2D array

                int ii;

                double input_frame_values [nyelements][nxelements];
                memset(input_frame_values, 0, sizeof(double)*nxelements*nyelements);
                for (fpixel[1] = cut_y[0]; fpixel[1] <= cut_y[1]; fpixel[1]++) {

                        memset(input_f_pixels, 0, sizeof(double)*nxelements);

                        if(!fits_read_pix(input_f_ptr, TDOUBLE, fpixel, nxelements, NULL, input_f_pixels, NULL, &input_f_status)) {

                                for (ii=0; ii<nxelements; ii++) {
                                        input_frame_values[fpixel[1]-1][ii] = input_f_pixels[ii];
                                }

                        } else { 

                                write_key_to_file(ERROR_CODES_FILE, REF_ERROR_CODES_FILE, "L2STATEX", -5, "Status flag for L2 spextract routine", ERROR_CODES_FILE_WRITE_ACCESS);
                                fits_report_error(stdout, input_f_status); 

                                free(input_f);  
                                free(output_f);  
                                free(method);
                                free(ss_method);                                
                                if(fits_close_file(input_f_ptr, &input_f_status)) fits_report_error (stdout, input_f_status); 

                                return 1; 

                        }

                }
                
                // ***********************************************************************
                // Open [SPFIND_OUTPUTF_PEAKS_FILE] input file
        
                FILE *inputfile;
        
                if (!check_file_exists(SPFIND_OUTPUTF_PEAKS_FILE)) { 

                        inputfile = fopen(SPFIND_OUTPUTF_PEAKS_FILE , "r");

                } else {

                        write_key_to_file(ERROR_CODES_FILE, REF_ERROR_CODES_FILE, "L2STATEX", -6, "Status flag for L2 spextract routine", ERROR_CODES_FILE_WRITE_ACCESS);

                        return 1;

                }

                // ***********************************************************************
                // Find some [SPFIND_OUTPUTF_PEAKS_FILE] input file details

                char input_string [150];
                
                int row_count = 0;
                while(!feof(inputfile)) {
                        memset(input_string, '\0', sizeof(char)*150);
                        fgets(input_string, 150, inputfile);
                        if (strtol(&input_string[0], NULL, 0) > 0) {            // check the line begins with a positive number (usable)
                                row_count++;
                        }
                }
                
                rewind(inputfile);
                
                // ***********************************************************************
                // Store [SPFIND_OUTPUTF_PEAKS_FILE] data               
                
                double x_coords[row_count];
                memset(x_coords, 0, sizeof(double)*(row_count));

                double y_coords[row_count];
                memset(y_coords, 0, sizeof(double)*(row_count));

                double coord_x, coord_y;
                int idx = 0;
                while(!feof(inputfile)) {
                        memset(input_string, '\0', sizeof(char)*150);
                        fgets(input_string, 150, inputfile);    
                        if (strtol(&input_string[0], NULL, 0) > 0) {            // check the line begins with a positive number (usable)
                                sscanf(input_string, "%lf\t%lf\n", &coord_x, &coord_y);
                                x_coords[idx] = coord_x;
                                y_coords[idx] = coord_y;
                                idx++;
                        }
                }            
        
                double output_frame_values[nxelements];
                memset(output_frame_values, 0, sizeof(double)*nxelements);     
                
                // ***********************************************************************
                // EXTRACTION
                               
                if (strcmp(method, "simple") == 0) {
                    // ***********************************************************************
                    // PARTIAL PIXEL APERTURE

                    int ii, jj;

                    double y;    
                    
                    y = y_coords[0];                            // should only be one bin in [SPFIND_OUTPUTF_PEAKS_FILE] data file
     
                    double this_col_value;
                    for (ii=0; ii<nxelements; ii++) {   
                      
                        this_col_value = 0.;
                        
                        // ***********************************************************************
                        // Does [y] violate the img boundaries?

                        if ((y + target_half_aperture_px > nyelements) || (y - target_half_aperture_px <= 0)) {

                            write_key_to_file(ERROR_CODES_FILE, REF_ERROR_CODES_FILE, "L2STATEX", -7, "Status flag for L2 spextract routine", ERROR_CODES_FILE_WRITE_ACCESS);
                            fits_report_error(stdout, input_f_status); 

                            free(input_f);
                            free(output_f);  
                            free(method);
                            free(ss_method);
                            
                            if(fits_close_file(input_f_ptr, &input_f_status)) fits_report_error (stdout, input_f_status); 
                            fclose(inputfile);

                            return 1;

                        }

                        // ***********************************************************************
                        // Extract flux within aperture

                        double y_low, y_high;

                        y_low = y-target_half_aperture_px-0.5;
                        y_high = y+target_half_aperture_px+0.5;                   

                        int y_low_floor, y_high_floor;
        
                        y_low_floor = floor(y-target_half_aperture_px-0.5);            // 0.5 as taking (half_ap*2) + 1 as total aperture
                        y_high_floor = floor(y+target_half_aperture_px+0.5);
                                            
                        for (jj=y_low_floor; jj<=y_high_floor; jj++) {
                         
                            if (jj == y_low_floor) {                        // outside pixel where partial flux needs to be taken into account
                                  

                                double partial_fraction_of_bin = (y_low_floor + 1) - y_low;
                                this_col_value += partial_fraction_of_bin * input_frame_values[jj][ii];
                                
                            } else if (jj == y_high_floor) {                // outside pixel where partial flux needs to be taken into account
                                  
                                double partial_fraction_of_bin = y_high - y_high_floor;
                                this_col_value += partial_fraction_of_bin * input_frame_values[jj][ii];
                                
                            } else {
                              
                                this_col_value += input_frame_values[jj][ii]; 
                                    
                            }
                        }   
                        
                        output_frame_values[ii] = this_col_value;
                        
                    }    
                } else {
                  
                    write_key_to_file(ERROR_CODES_FILE, REF_ERROR_CODES_FILE, "L2STATEX", -8, "Status flag for L2 spextract routine", ERROR_CODES_FILE_WRITE_ACCESS);
                    fits_report_error(stdout, input_f_status); 

                    free(input_f);
                    free(output_f);
                    free(method);
                    free(ss_method);
                    
                    if(fits_close_file(input_f_ptr, &input_f_status)) fits_report_error (stdout, input_f_status);  
                    fclose(inputfile);
                    
                    return 1;
                    
                }
                
                // ***********************************************************************
                // SKY SUBTRACTION
                
                if (strcmp(ss_method, "none") == 0) {
                } else if (strcmp(ss_method, "median") == 0) {

                    // ***********************************************************************
                    // MEDIAN SUBTRACTION             
                    int ii, jj;

                    double y;    
                    
                    y = y_coords[0];                            // should only be one bin in [SPFIND_OUTPUTF_PEAKS_FILE] data file
     
                    double this_col_value;
                    
                    for (ii=0; ii<nxelements; ii++) {          
                        this_col_value = 0.;
                        
                        // ***********************************************************************
                        // Does [y] violate the img boundaries?

                        if ((y + target_half_aperture_px + sky_window_half_aperture_px > nyelements) || (y - target_half_aperture_px - sky_window_half_aperture_px <= 0)) {

                            write_key_to_file(ERROR_CODES_FILE, REF_ERROR_CODES_FILE, "L2STATEX", -9, "Status flag for L2 spextract routine", ERROR_CODES_FILE_WRITE_ACCESS);
                            fits_report_error(stdout, input_f_status); 

                            free(input_f);
                            free(output_f);  
                            free(method);
                            free(ss_method);
                            
                            if(fits_close_file(input_f_ptr, &input_f_status)) fits_report_error (stdout, input_f_status); 
                            fclose(inputfile);

                            return 1;

                        }
                        
                        // ***********************************************************************
                        // Find pixels for sky aperture

                        int ap_lower_lo, ap_lower_hi, ap_upper_lo, ap_upper_hi; 
                        
                        ap_lower_lo = floor(y-target_half_aperture_px-0.5) - sky_window_half_aperture_px - 1;
                        ap_lower_hi = floor(y-target_half_aperture_px-0.5) - 1;
                        ap_upper_lo = floor(y+target_half_aperture_px+0.5) + 1;
                        ap_upper_hi = floor(y+target_half_aperture_px+0.5) + sky_window_half_aperture_px + 1;
                        
                        int n_ap_values = (ap_lower_hi-ap_lower_lo) + (ap_upper_hi-ap_upper_lo) + 2;
                        
                        double ap_values[n_ap_values];
                             
                        int idx = 0;
 
                        
                        for (jj=ap_lower_lo; jj<=ap_lower_hi; jj++) {
                          
                            ap_values[idx] = input_frame_values[jj][ii]; 
                            idx++;
                                    
                        }  
                        
                        for (jj=ap_upper_lo; jj<=ap_upper_hi; jj++) {
                          
                            ap_values[idx] = input_frame_values[jj][ii]; 
                            idx++;
                                    
                        }  
                        
                        // DEBUG
                        /*for (jj=0; jj<idx; jj++) 
                          printf("%f,", ap_values[jj]);
                        
                        printf("\n");
                        
                        for (jj=0; jj<idx; jj++) 
                          printf("%d,", jj);
                        
                        printf("\n");*/ 
                        
                        // Take median
                        double ap_values_sorted [n_ap_values];
                        memcpy(ap_values_sorted, ap_values, sizeof(double)*n_ap_values);

                        gsl_sort(ap_values_sorted, 1, (ap_lower_hi-ap_lower_lo) + (ap_upper_hi-ap_upper_lo) + 2);
                        double ap_values_median = gsl_stats_median_from_sorted_data(ap_values_sorted, 1, n_ap_values);     
                        
                        this_col_value = ap_values_median * ((target_half_aperture_px*2) + 1);    // need to scale up to target extraction aperture size
                        
                        output_frame_values[ii] -= this_col_value;              

                    }
                  
                } else {
                  
                    write_key_to_file(ERROR_CODES_FILE, REF_ERROR_CODES_FILE, "L2STATEX", -10, "Status flag for L2 spextract routine", ERROR_CODES_FILE_WRITE_ACCESS);
                    fits_report_error(stdout, input_f_status); 

                    free(input_f);
                    free(output_f);
                    free(method);
                    free(ss_method);
                    
                    if(fits_close_file(input_f_ptr, &input_f_status)) fits_report_error (stdout, input_f_status);  
                    fclose(inputfile);
                    
                    return 1;
                    
                }
                
                // ***********************************************************************
                // Set output frame parameters

                fitsfile *output_f_ptr;
        
                int output_f_status = 0;
                long output_f_naxes [2] = {nxelements, 1};
        
                long output_f_fpixel = 1;

                // ***********************************************************************
                // Create and write [output_frame_values] to output file (ARG 6)
        
                if (!fits_create_file(&output_f_ptr, output_f, &output_f_status)) {
        
                        if (!fits_create_img(output_f_ptr, INTERMEDIATE_IMG_ACCURACY[0], 2, output_f_naxes, &output_f_status)) {

                                if (!fits_write_img(output_f_ptr, INTERMEDIATE_IMG_ACCURACY[1], output_f_fpixel, nxelements, output_frame_values, &output_f_status)) {

                                } else { 

                                        write_key_to_file(ERROR_CODES_FILE, REF_ERROR_CODES_FILE, "L2STATEX", -11, "Status flag for L2 spextract routine", ERROR_CODES_FILE_WRITE_ACCESS);
                                        fits_report_error(stdout, output_f_status); 

                                        free(input_f);
                                        free(output_f);
                                        free(method);
                                        free(ss_method);
                                        
                                        if(fits_close_file(input_f_ptr, &input_f_status)) fits_report_error (stdout, input_f_status); 
                                        if(fits_close_file(output_f_ptr, &output_f_status)) fits_report_error (stdout, output_f_status);
                                        fclose(inputfile);

                                        return 1; 

                                }

                        } else {

                                write_key_to_file(ERROR_CODES_FILE, REF_ERROR_CODES_FILE, "L2STATEX", -12, "Status flag for L2 spextract routine", ERROR_CODES_FILE_WRITE_ACCESS);
                                fits_report_error(stdout, output_f_status); 

                                free(input_f);
                                free(output_f);
                                free(method);
                                free(ss_method);
                                
                                if(fits_close_file(input_f_ptr, &input_f_status)) fits_report_error (stdout, input_f_status); 
                                if(fits_close_file(output_f_ptr, &output_f_status)) fits_report_error (stdout, output_f_status);
                                fclose(inputfile);

                                return 1; 

                        }

                } else {

                        write_key_to_file(ERROR_CODES_FILE, REF_ERROR_CODES_FILE, "L2STATEX", -13, "Status flag for L2 spextract routine", ERROR_CODES_FILE_WRITE_ACCESS);
                        fits_report_error(stdout, output_f_status); 

                        free(input_f);
                        free(output_f);
                        free(method);
                        if(fits_close_file(input_f_ptr, &input_f_status)) fits_report_error (stdout, input_f_status); 
                        fclose(inputfile);

                        return 1; 

                }                
                
                // ***********************************************************************
                // Free arrays on heap

                free(input_f);
                free(output_f);
                free(method);  
                free(ss_method);
                
                // ***********************************************************************
                // Close input file (ARG 1) and output file (ARG 6)          
                
                if(fits_close_file(input_f_ptr, &input_f_status)) { 

                        write_key_to_file(ERROR_CODES_FILE, REF_ERROR_CODES_FILE, "L2STATEX", -14, "Status flag for L2 spextract routine", ERROR_CODES_FILE_WRITE_ACCESS);
                        fits_report_error (stdout, input_f_status); 

                        return 1; 

                }     
               
                if(fits_close_file(output_f_ptr, &output_f_status)) { 

                        write_key_to_file(ERROR_CODES_FILE, REF_ERROR_CODES_FILE, "L2STATEX", -15, "Status flag for L2 spextract routine", ERROR_CODES_FILE_WRITE_ACCESS);
                        fits_report_error (stdout, output_f_status); 

                        return 1; 

                }  
                
                if (fclose(inputfile)) {
                        write_key_to_file(ERROR_CODES_FILE, REF_ERROR_CODES_FILE, "L2STATTR", -16, "Status flag for L2 spextract routine", ERROR_CODES_FILE_WRITE_ACCESS);
                        return 1; 
                } 
                
                // Write success to [ERROR_CODES_FILE]

                write_key_to_file(ERROR_CODES_FILE, REF_ERROR_CODES_FILE, "L2STATEX", RETURN_FLAG, "Status flag for L2 spextract routine", ERROR_CODES_FILE_WRITE_ACCESS);

                return 0;

        }

}
int main(int argc, char *argv []) {
	if(populate_env_variable(REF_ERROR_CODES_FILE, "L2_ERROR_CODES_FILE")) {

		printf("\nUnable to populate [REF_ERROR_CODES_FILE] variable with corresponding environment variable. Routine will proceed without error handling\n");

	}

	if (argc != 2) {

		if(populate_env_variable(SPTS_BLURB_FILE, "L2_SPTS_BLURB_FILE")) {

			RETURN_FLAG = 1;

		} else {

			print_file(SPTS_BLURB_FILE);

		}

		write_key_to_file(ERROR_CODES_FILE, REF_ERROR_CODES_FILE, "L2STATTR", -1, "Status flag for L2 sptrace routine", ERROR_CODES_FILE_WRITE_ACCESS);

		return 1;

	} else {
		// ***********************************************************************
		// Redefine routine input parameters

		int order	                = strtol(argv[1], NULL, 0);	
                
		// ***********************************************************************
		// Open [SPFIND_OUTPUTF_PEAKS_FILE] input file
	
		FILE *inputfile;
	
		if (!check_file_exists(SPFIND_OUTPUTF_PEAKS_FILE)) { 

			inputfile = fopen(SPFIND_OUTPUTF_PEAKS_FILE , "r");

		} else {

			write_key_to_file(ERROR_CODES_FILE, REF_ERROR_CODES_FILE, "L2STATTR", -2, "Status flag for L2 sptrace routine", ERROR_CODES_FILE_WRITE_ACCESS);

			return 1;

		}

		// ***********************************************************************
		// Find some [SPFIND_OUTPUTF_PEAKS_FILE] input file details

		char input_string [150];
		
		int row_count = 0;
		while(!feof(inputfile)) {
			memset(input_string, '\0', sizeof(char)*150);
			fgets(input_string, 150, inputfile);
			if (strtol(&input_string[0], NULL, 0) > 0) {		// check the line begins with a positive number (usable)
				row_count++;
			}
		}
		
		rewind(inputfile);
		
		// ***********************************************************************
		// Store [SPFIND_OUTPUTF_PEAKS_FILE] data		
		
		double x_coords[row_count];
		memset(x_coords, 0, sizeof(double)*(row_count));

		double y_coords[row_count];
		memset(y_coords, 0, sizeof(double)*(row_count));

		double coord_x, coord_y;
		int idx = 0;
		while(!feof(inputfile)) {
			memset(input_string, '\0', sizeof(char)*150);
			fgets(input_string, 150, inputfile);	
			if (strtol(&input_string[0], NULL, 0) > 0) {		// check the line begins with a positive number (usable)
				sscanf(input_string, "%lf\t%lf\n", &coord_x, &coord_y);
				x_coords[idx] = coord_x;
				y_coords[idx] = coord_y;
				idx++;
			}
		}
		
		// ***********************************************************************
		// Perform a few checks to ensure the input tracing parameters 
		// are sensible

		if ((order < SPTRACE_VAR_POLYORDER_LO) || (order > SPTRACE_VAR_POLYORDER_HI)) {	// Check [order] is within config limits
			write_key_to_file(ERROR_CODES_FILE, REF_ERROR_CODES_FILE, "L2STATTR", -3, "Status flag for L2 sptrace routine", ERROR_CODES_FILE_WRITE_ACCESS);
			fclose(inputfile);
			return 1; 
		}
		
		// ***********************************************************************
		// Create [SPTRACE_OUTPUTF_TRACES_FILE] output file and print a few 
		// parameters

		FILE *outputfile;
		outputfile = fopen(SPTRACE_OUTPUTF_TRACES_FILE, FILE_WRITE_ACCESS);

		if (!outputfile) { 
			write_key_to_file(ERROR_CODES_FILE, REF_ERROR_CODES_FILE, "L2STATTR", -4, "Status flag for L2 sptrace routine", ERROR_CODES_FILE_WRITE_ACCESS);
			fclose(inputfile);
			return 1;
		}

		char timestr [80];
		memset(timestr, '\0', sizeof(char)*80);

		find_time(timestr);

		fprintf(outputfile, "#### %s ####\n\n", SPTRACE_OUTPUTF_TRACES_FILE);
		fprintf(outputfile, "# Lists the trace coefficients and corresponding chi-squareds found using the sptrace program.\n\n");
		fprintf(outputfile, "# Run datetime:\t\t%s\n", timestr);
		fprintf(outputfile, "# Polynomial Order:\t%d\n\n", order);
		
		// ***********************************************************************
		// Fit and store results to [SPTRACE_OUTPUTF_TRACES_FILE] file

		double coeffs[order];
		double this_chi_squared;
		if (calc_least_sq_fit(order, row_count, x_coords, y_coords, coeffs, &this_chi_squared)) {	// reversed [coord_y] and [coord_x] as want to find x = f(y) not y = f(x)
			write_key_to_file(ERROR_CODES_FILE, REF_ERROR_CODES_FILE, "L2STATTR", -5, "Status flag for L2 frtrace routine", ERROR_CODES_FILE_WRITE_ACCESS);
			fclose(inputfile);
			fclose(outputfile);
			return 1; 
		}	

		int ii;
		for (ii=0; ii<=order; ii++) {
			fprintf(outputfile, SPTRACE_VAR_ACCURACY_COEFFS, coeffs[ii]);
			fprintf(outputfile, "\t");
		}
		fprintf(outputfile, SPTRACE_VAR_ACCURACY_CHISQ, this_chi_squared);
		fprintf(outputfile, "\n");
		fprintf(outputfile, "%d", EOF);

		printf("\nFitting results");
		printf("\n--------------------\n");
		printf("\nχ2:\t\t\t%.2f\n", this_chi_squared);
		
		// ***********************************************************************
		// Perform a few checks to ensure the chi squareds are sensible 

		if ((this_chi_squared < SPTRACE_VAR_CHISQUARED_MIN) || (this_chi_squared > SPTRACE_VAR_CHISQUARED_MAX)) {	// comparing doubles but accuracy isn't a necessity so don't need gsl_fcmp function
			RETURN_FLAG = 2;
		}	

		// ***********************************************************************
		// Close [SPFIND_OUTPUTF_PEAKS_FILE] input file and 
		// [SPTRACE_OUTPUTF_TRACES_FILE] output file

		if (fclose(inputfile)) {
			write_key_to_file(ERROR_CODES_FILE, REF_ERROR_CODES_FILE, "L2STATTR", -6, "Status flag for L2 sptrace routine", ERROR_CODES_FILE_WRITE_ACCESS);
			return 1; 
		}
		
		if (fclose(outputfile)) {
			write_key_to_file(ERROR_CODES_FILE, REF_ERROR_CODES_FILE, "L2STATTR", -7, "Status flag for L2 sptrace routine", ERROR_CODES_FILE_WRITE_ACCESS);
			return 1; 
		}		
		
		// Write success to [ERROR_CODES_FILE]

		write_key_to_file(ERROR_CODES_FILE, REF_ERROR_CODES_FILE, "L2STATTR", RETURN_FLAG, "Status flag for L2 sptrace routine", ERROR_CODES_FILE_WRITE_ACCESS);

		return 0;

	}

}
int main (int argc, char *argv []) {

	if(populate_env_variable(REF_ERROR_CODES_FILE, "L2_ERROR_CODES_FILE")) {

		printf("\nUnable to populate [REF_ERROR_CODES_FILE] variable with corresponding environment variable. Routine will proceed without error handling\n");

	}

	if (argc != 8) {

		if(populate_env_variable(LOR_BLURB_FILE, "L2_LOR_BLURB_FILE")) {

			RETURN_FLAG = 1;

		} else {

			print_file(LOR_BLURB_FILE);

		}

		write_key_to_file(ERROR_CODES_FILE, REF_ERROR_CODES_FILE, "L2STATRE", -1, "Status flag for L2 lorebin routine", ERROR_CODES_FILE_WRITE_ACCESS);

		return 1;

	} else {

		// ***********************************************************************
		// Redefine routine input parameters
	
		char *input_f	                = strdup(argv[1]);
		double start_wav		= strtod(argv[2], NULL);
		double end_wav			= strtod(argv[3], NULL);
		char *interpolation_type	= strdup(argv[4]);
		double dispersion		= strtod(argv[5], NULL);
		int conserve_flux		= strtol(argv[6], NULL, 0);
		char *output_f	                = strdup(argv[7]);

		// ***********************************************************************
		// Open input file (ARG 1), get parameters and perform any data format 
                // checks 

		fitsfile *input_f_ptr;

		int input_f_maxdim = 2;
		int input_f_status = 0, input_f_bitpix, input_f_naxis;
		long input_f_naxes [2] = {1,1};

		if(!fits_open_file(&input_f_ptr, input_f, READONLY, &input_f_status)) {

			if(!populate_img_parameters(input_f, input_f_ptr, input_f_maxdim, &input_f_bitpix, &input_f_naxis, input_f_naxes, &input_f_status, "INPUT FRAME")) {

				if (input_f_naxis != 2) {	// any data format checks here

					write_key_to_file(ERROR_CODES_FILE, REF_ERROR_CODES_FILE, "L2STATRE", -2, "Status flag for L2 lorebin routine", ERROR_CODES_FILE_WRITE_ACCESS);

					free(input_f);
					free(interpolation_type);
					free(output_f);

					if(fits_close_file(input_f_ptr, &input_f_status)) fits_report_error (stdout, input_f_status); 

					return 1;
	
				}

			} else { 

				write_key_to_file(ERROR_CODES_FILE, REF_ERROR_CODES_FILE, "L2STATRE", -3, "Status flag for L2 lorebin routine", ERROR_CODES_FILE_WRITE_ACCESS);
				fits_report_error(stdout, input_f_status); 

				free(input_f);
				free(interpolation_type);
				free(output_f);

				if(fits_close_file(input_f_ptr, &input_f_status)) fits_report_error (stdout, input_f_status); 

				return 1; 

			}

		} else { 

			write_key_to_file(ERROR_CODES_FILE, REF_ERROR_CODES_FILE, "L2STATRE", -4, "Status flag for L2 lorebin routine", ERROR_CODES_FILE_WRITE_ACCESS);
			fits_report_error(stdout, input_f_status); 

			free(input_f);
			free(interpolation_type);
			free(output_f);

			return 1; 

		}

		// ***********************************************************************
		// Set the range limits using input fits file (ARG 1)

		int cut_x [2] = {1, input_f_naxes[0]};
		int cut_y [2] = {1, input_f_naxes[1]};

		// ***********************************************************************
		// Set parameters used when reading data from input fits file (ARG 1)

		long fpixel [2] = {cut_x[0], cut_y[0]};
		long nxelements = (cut_x[1] - cut_x[0]) + 1;
		long nyelements = (cut_y[1] - cut_y[0]) + 1;

		// ***********************************************************************
		// Create arrays to store pixel values from input fits file (ARG 1)

		double input_f_pixels [nxelements];

		// ***********************************************************************
		// Open [LOARCFIT_OUTPUTF_WAVFITS_FILE] dispersion solutions file

		FILE *dispersion_solutions_f;
	
		if (!check_file_exists(LOARCFIT_OUTPUTF_WAVFITS_FILE)) { 

			dispersion_solutions_f = fopen(LOARCFIT_OUTPUTF_WAVFITS_FILE , "r");

		} else {

			write_key_to_file(ERROR_CODES_FILE, REF_ERROR_CODES_FILE, "L2STATRE", -5, "Status flag for L2 lorebin routine", ERROR_CODES_FILE_WRITE_ACCESS);

			free(input_f);
			free(interpolation_type);
			free(output_f);

			if(fits_close_file(input_f_ptr, &input_f_status)) fits_report_error (stdout, input_f_status); 

			return 1;

		}	

		// ***********************************************************************
		// Find some [LOARCFIT_OUTPUTF_WAVFITS_FILE] file details

		char input_string [500];

		bool find_polynomialorder_comment = FALSE;

		int polynomial_order;	

		char search_string_1 [20] = "# Polynomial Order:\0";	// this is the comment to be found from the [LOARCFIT_OUTPUTF_WAVFITS_FILE] file

		while(!feof(dispersion_solutions_f)) {

			memset(input_string, '\0', sizeof(char)*500);
	
			fgets(input_string, 500, dispersion_solutions_f);	

			if (strncmp(input_string, search_string_1, strlen(search_string_1)) == 0) { 

				sscanf(input_string, "%*[^\t]%d", &polynomial_order);		// read all data up to tab as string ([^\t]), but do not store (*)
				find_polynomialorder_comment = TRUE;
				break;


			} 

		}

		if (find_polynomialorder_comment == FALSE) {	// error check - didn't find the comment in the [LOARCFIT_OUTPUTF_WAVFITS_FILE] file

			write_key_to_file(ERROR_CODES_FILE, REF_ERROR_CODES_FILE, "L2STATRE", -6, "Status flag for L2 lorebin routine", ERROR_CODES_FILE_WRITE_ACCESS);

			free(input_f);
			free(interpolation_type);
			free(output_f);

			fclose(dispersion_solutions_f);

			if(fits_close_file(input_f_ptr, &input_f_status)) fits_report_error (stdout, input_f_status); 

			return 1;

		}

		// ***********************************************************************
		// Rewind and extract coefficients from [LOARCFIT_OUTPUTF_WAVFITS_FILE]
		// file 

		rewind(dispersion_solutions_f);

		int token_index;	// this variable will hold which token we're dealing with
		int coeff_index;	// this variable will hold which coefficient we're dealing with
		double this_coeff;
		double this_chisquared;
	
		char *token;

		double coeffs [polynomial_order+1];
		memset(coeffs, 0, sizeof(double)*(polynomial_order+1));

		while(!feof(dispersion_solutions_f)) {

			memset(input_string, '\0', sizeof(char)*500);
	
			fgets(input_string, 500, dispersion_solutions_f);

			token_index = 0;
			coeff_index = 0;

			if (strtol(&input_string[0], NULL, 0) > 0) { 		// check the line begins with a positive number

				// ***********************************************************************
				// String tokenisation loop: 
				//
				// 1. init calls strtok() loading the function with input_string
				// 2. terminate when token is null
				// 3. we keep assigning tokens of input_string to token until termination by calling strtok with a NULL first argument
				// 
				// n.b. searching for tab or newline separators ('\t' and '\n')

				for (token=strtok(input_string, "\t\n"); token !=NULL; token = strtok(NULL, "\t\n")) {
                                  
                                        if (token_index == 0) {    
                                        } else if ((token_index >= 1) && (token_index <= polynomial_order+1)) { 	// coeff token

						this_coeff = strtod(token, NULL);
						// printf("%d\t%e\n", coeff_index, this_coeff);		// DEBUG
						coeffs[coeff_index] = this_coeff;
						coeff_index++;

					} else if (token_index == polynomial_order+2) {					// chisquared token

						this_chisquared = strtod(token, NULL);
                                                //printf("%f\n", this_chisquared);                      // DEBUG

					}

					token_index++;

				}

			}

		}

		// ***********************************************************************
		// Find wavelength extremities from [LOARCFIT_OUTPUTF_WAVFITS_FILE] file
		// and ensure the input constraints [start_wav] (ARG 2) and [end_wav]
		// (ARG 3) don't lie outside these boundaries

		double smallest_wav, largest_wav;

		int ii;

		for (ii=0; ii<=polynomial_order; ii++) {
		    
			smallest_wav += coeffs[ii]*pow(0+INDEXING_CORRECTION, ii);
			largest_wav += coeffs[ii]*pow((cut_x[1]-1)+INDEXING_CORRECTION, ii);

		}

		// ***********************************************************************
	        // Need to find pixel indexes for starting/ending wavelength positions

	        double this_element_wav;
	        int first_element_index, last_element_index;
                int jj;
		for (ii=0; ii<nxelements; ii++) {
                        this_element_wav = 0.0;
                        for (jj=0; jj<=polynomial_order; jj++) {
                                this_element_wav += coeffs[jj]*pow(ii,jj);
                        }
		      	if (this_element_wav >= start_wav) {	// the current index, ii, represents the first pixel with a wavelength >= start_wav. Comparing doubles but accuracy isn't a necessity so don't need gsl_fcmp function
		       		break;
		     	}
		     	
                        first_element_index = ii;		     	
                }

		// printf("%d\t%f\n", ii, this_element_wav);	// DEBUG

		for (ii=nxelements; ii>=0; ii--) {
                        this_element_wav = 0.0;
                        for (jj=0; jj<=polynomial_order; jj++) {
                                this_element_wav += coeffs[jj]*pow(ii,jj);
                        }
                        if (this_element_wav <= end_wav) {    // the current index, ii, represents the first pixel with a wavelength <= end_wav. Comparing doubles but accuracy isn't a necessity so don't need gsl_fcmp function
                                break;
                        }

			last_element_index = ii;

	        }
	        
	        // printf("%d\t%f\n", ii, this_element_wav);     // DEBUG
	
		printf("\nWavelength boundaries");
		printf("\n---------------------\n");

		printf("\nInherent minimum wavelength:\t%.2f Å", smallest_wav);
		printf("\nInherent maximum wavelength:\t%.2f Å\n", largest_wav);

		if (start_wav < smallest_wav) {         // Comparing doubles but accuracy isn't a necessity so don't need gsl_fcmp function
		  
			write_key_to_file(ERROR_CODES_FILE, REF_ERROR_CODES_FILE, "L2STATRE", -7, "Status flag for L2 lorebin routine", ERROR_CODES_FILE_WRITE_ACCESS);

			free(input_f);
			free(interpolation_type);
			free(output_f);

			fclose(dispersion_solutions_f);

			if(fits_close_file(input_f_ptr, &input_f_status)) fits_report_error (stdout, input_f_status); 

			return 1; 

		} else if (end_wav > largest_wav) {     // Comparing doubles but accuracy isn't a necessity so don't need gsl_fcmp function

			write_key_to_file(ERROR_CODES_FILE, REF_ERROR_CODES_FILE, "L2STATRE", -8, "Status flag for L2 lorebin routine", ERROR_CODES_FILE_WRITE_ACCESS);

			free(input_f);
			free(interpolation_type);
			free(output_f);

			fclose(dispersion_solutions_f);

			if(fits_close_file(input_f_ptr, &input_f_status)) fits_report_error (stdout, input_f_status); 

			return 1; 

		}

		// ***********************************************************************
	        // Set the bin wavelengths 

		int num_bins = 0;

		if (!gsl_fcmp((end_wav-start_wav)/dispersion, rint((end_wav-start_wav)/dispersion), 1e-5)) {	// check to see if nearest integer is within tolerance value	

			num_bins = rint((end_wav-start_wav)/dispersion) + 1;					// if TRUE, round

		} else {

			num_bins = floor((end_wav-start_wav)/dispersion) + 1;					// if FALSE, floor

		}

		// printf("%d\n", num_bins);						// DEBUG

		double bin_wavelengths [num_bins];
		memset(bin_wavelengths, 0, sizeof(double)*num_bins);

		for (ii=0; ii<num_bins; ii++) {

			bin_wavelengths[ii] = start_wav + dispersion*ii;		
			// printf("%f\n", bin_wavelengths[ii]);				// DEBUG
		
		}	

		// printf("%f\t%f\n", bin_wavelengths[0], bin_wavelengths[num_bins-1]);	// DEBUG


		// REBIN INPUT FRAME (ARG 1) AND CONSERVE FLUX IF APPLICABLE
		// ***********************************************************************
		// 1.	Open input frame

		int this_row_index;

		double x_wav [nxelements];

		double output_frame_values [nyelements][num_bins];
		memset(output_frame_values, 0, sizeof(double)*nyelements*num_bins);

		double output_f_pixels [num_bins];
		memset(output_f_pixels, 0, sizeof(double)*(num_bins));

		double this_pre_rebin_row_flux, this_post_rebin_row_flux;

		double conservation_factor;	

		for (fpixel[1] = cut_y[0]; fpixel[1] <= cut_y[1]; fpixel[1]++) {

			this_row_index = fpixel[1] - 1;

			memset(input_f_pixels, 0, sizeof(double)*nxelements);

			if(!fits_read_pix(input_f_ptr, IMG_READ_ACCURACY, fpixel, nxelements, NULL, input_f_pixels, NULL, &input_f_status)) {

				// 2.	Calculate pre-rebin total fluxes

				this_pre_rebin_row_flux = 0.0;

				for (ii=first_element_index; ii<=last_element_index; ii++) {

					this_pre_rebin_row_flux += input_f_pixels[ii];

				}

				// 3.	Create pixel-wavelength translation array and perform interpolation

				memset(x_wav, 0, sizeof(double)*nxelements);

				for (ii=0; ii<nxelements; ii++) {

					for (jj=0; jj<=polynomial_order; jj++) {
					    
						x_wav[ii] += coeffs[jj]*pow(ii+INDEXING_CORRECTION,jj);

					}

					// printf("%d\t%f\n", ii, x_wav[ii]); // DEBUG

				}

				// for (ii=0; ii< nxelements; ii++) printf("\n%f\t%f", x_wav[ii], input_f_pixels[ii]);	// DEBUG

				if (interpolate(interpolation_type, x_wav, input_f_pixels, nxelements, bin_wavelengths[0], bin_wavelengths[num_bins-1], dispersion, output_f_pixels)) {
		
					write_key_to_file(ERROR_CODES_FILE, REF_ERROR_CODES_FILE, "L2STATRE", -9, "Status flag for L2 lorebin routine", ERROR_CODES_FILE_WRITE_ACCESS);

					free(input_f);
					free(interpolation_type);
					free(output_f);

					fclose(dispersion_solutions_f);

					if(fits_close_file(input_f_ptr, &input_f_status)) fits_report_error (stdout, input_f_status); 

					return 1; 

				}

				// 4.	Calculate post-rebin total fluxes

				this_post_rebin_row_flux = 0.0;

				for (ii=0; ii<num_bins; ii++) {

					this_post_rebin_row_flux += output_f_pixels[ii];

				}

				// 5.	Conserve flux if applicable

				conservation_factor = this_pre_rebin_row_flux/this_post_rebin_row_flux;

				// printf("%f\t%f\t%f\n", this_pre_rebin_row_flux, this_post_rebin_row_flux, conservation_factor);	// DEBUG

				for (ii=0; ii<num_bins; ii++) {

					if (conserve_flux == TRUE) {

						output_frame_values[this_row_index][ii] = output_f_pixels[ii]*conservation_factor;

					} else {

						output_frame_values[this_row_index][ii] = output_f_pixels[ii];

					}

				}

			} else { 

				write_key_to_file(ERROR_CODES_FILE, REF_ERROR_CODES_FILE, "L2STATRE", -10, "Status flag for L2 lorebin routine", ERROR_CODES_FILE_WRITE_ACCESS);
				fits_report_error(stdout, input_f_status);

				free(input_f);
				free(interpolation_type);
				free(output_f);

				fclose(dispersion_solutions_f);

				if(fits_close_file(input_f_ptr, &input_f_status)) fits_report_error (stdout, input_f_status); 

				return 1; 

			}

		}

		// 6.	Create [LOREBIN_OUTPUTF_REBIN_WAVFITS_FILE] output file and print
		// 	a few parameters

		FILE *outputfile;
		outputfile = fopen(LOREBIN_OUTPUTF_REBIN_WAVFITS_FILE, FILE_WRITE_ACCESS);

		if (!outputfile) { 

			write_key_to_file(ERROR_CODES_FILE, REF_ERROR_CODES_FILE, "L2STATRE", -11, "Status flag for L2 frrebin routine", ERROR_CODES_FILE_WRITE_ACCESS);

			free(input_f);
			free(interpolation_type);
			free(output_f);

			fclose(dispersion_solutions_f);

			if(fits_close_file(input_f_ptr, &input_f_status)) fits_report_error (stdout, input_f_status); 

			return 1;

		}

		char timestr [80];
		memset(timestr, '\0', sizeof(char)*80);

		find_time(timestr);

		fprintf(outputfile, "#### %s ####\n\n", LOREBIN_OUTPUTF_REBIN_WAVFITS_FILE);
	        fprintf(outputfile, "# Rebinning wavelength fit parameters.\n\n");
                fprintf(outputfile, "# Run Datetime:\t\t%s\n\n", timestr);
	        fprintf(outputfile, "# Target Filename:\t%s\n\n", input_f);
	        fprintf(outputfile, "# Starting Wavelength:\t%.2f\n", bin_wavelengths[0]);
	        fprintf(outputfile, "# Dispersion:\t\t%.2f\n", dispersion);
		fprintf(outputfile, "%d", EOF);

		// 7.	Write these values to the [ADDITIONAL_KEYS_FILE] file

		write_additional_key_to_file_str(ADDITIONAL_KEYS_FILE, "LSS_CALIBRATION", "CTYPE1", "Wavelength", "Type of co-ordinate on axis 1", ADDITIONAL_KEYS_FILE_WRITE_ACCESS);
		write_additional_key_to_file_str(ADDITIONAL_KEYS_FILE, "LSS_CALIBRATION", "CUNIT1", "Angstroms", "Units for axis 1", ADDITIONAL_KEYS_FILE_WRITE_ACCESS);
		write_additional_key_to_file_dbl(ADDITIONAL_KEYS_FILE, "LSS_CALIBRATION", "CRVAL1", bin_wavelengths[0], "[pixel] Value at ref. pixel on axis 1", ADDITIONAL_KEYS_FILE_WRITE_ACCESS);
		write_additional_key_to_file_dbl(ADDITIONAL_KEYS_FILE, "LSS_CALIBRATION", "CDELT1", dispersion, "[pixel] Pixel scale on axis 1", ADDITIONAL_KEYS_FILE_WRITE_ACCESS);
		write_additional_key_to_file_dbl(ADDITIONAL_KEYS_FILE, "LSS_CALIBRATION", "CRPIX1", 1.0, "[pixel] Reference pixel on axis 1", ADDITIONAL_KEYS_FILE_WRITE_ACCESS);
		write_additional_key_to_file_str(ADDITIONAL_KEYS_FILE, "LSS_CALIBRATION", "CTYPE2", "a2", "Type of co-ordinate on axis 2", ADDITIONAL_KEYS_FILE_WRITE_ACCESS);
		write_additional_key_to_file_str(ADDITIONAL_KEYS_FILE, "LSS_CALIBRATION", "CUNIT2", "Pixels", "Units for axis 2", ADDITIONAL_KEYS_FILE_WRITE_ACCESS);
		write_additional_key_to_file_dbl(ADDITIONAL_KEYS_FILE, "LSS_CALIBRATION", "CRVAL2", 1, "[pixel] Value at ref. pixel on axis 2", ADDITIONAL_KEYS_FILE_WRITE_ACCESS);
		write_additional_key_to_file_dbl(ADDITIONAL_KEYS_FILE, "LSS_CALIBRATION", "CDELT2", 1, "[pixel] Pixel scale on axis 2", ADDITIONAL_KEYS_FILE_WRITE_ACCESS);
		write_additional_key_to_file_dbl(ADDITIONAL_KEYS_FILE, "LSS_CALIBRATION", "CRPIX2", 1, "[pixel] Reference pixel on axis 2", ADDITIONAL_KEYS_FILE_WRITE_ACCESS);

		write_additional_key_to_file_str(ADDITIONAL_KEYS_FILE, "SPEC_CALIBRATION", "CTYPE1", "Wavelength", "Type of co-ordinate on axis 1", ADDITIONAL_KEYS_FILE_WRITE_ACCESS);
		write_additional_key_to_file_str(ADDITIONAL_KEYS_FILE, "SPEC_CALIBRATION", "CUNIT1", "Angstroms", "Units for axis 1", ADDITIONAL_KEYS_FILE_WRITE_ACCESS);
		write_additional_key_to_file_dbl(ADDITIONAL_KEYS_FILE, "SPEC_CALIBRATION", "CRVAL1", bin_wavelengths[0], "[pixel] Value at ref. pixel on axis 1", ADDITIONAL_KEYS_FILE_WRITE_ACCESS);
		write_additional_key_to_file_dbl(ADDITIONAL_KEYS_FILE, "SPEC_CALIBRATION", "CDELT1", dispersion, "[pixel] Pixel scale on axis 1", ADDITIONAL_KEYS_FILE_WRITE_ACCESS);
		write_additional_key_to_file_dbl(ADDITIONAL_KEYS_FILE, "SPEC_CALIBRATION", "CRPIX1", 1.0, "[pixel] Reference pixel on axis 1", ADDITIONAL_KEYS_FILE_WRITE_ACCESS);
		write_additional_key_to_file_str(ADDITIONAL_KEYS_FILE, "SPEC_CALIBRATION", "CTYPE2", "a2", "Type of co-ordinate on axis 2", ADDITIONAL_KEYS_FILE_WRITE_ACCESS);
		write_additional_key_to_file_str(ADDITIONAL_KEYS_FILE, "SPEC_CALIBRATION", "CUNIT2", "Pixels", "Units for axis 2", ADDITIONAL_KEYS_FILE_WRITE_ACCESS);
		write_additional_key_to_file_dbl(ADDITIONAL_KEYS_FILE, "SPEC_CALIBRATION", "CRVAL2", 1, "[pixel] Value at ref. pixel on axis 2", ADDITIONAL_KEYS_FILE_WRITE_ACCESS);
		write_additional_key_to_file_dbl(ADDITIONAL_KEYS_FILE, "SPEC_CALIBRATION", "CDELT2", 1, "[pixel] Pixel scale on axis 2", ADDITIONAL_KEYS_FILE_WRITE_ACCESS);
		write_additional_key_to_file_dbl(ADDITIONAL_KEYS_FILE, "SPEC_CALIBRATION", "CRPIX2", 1, "[pixel] Reference pixel on axis 2", ADDITIONAL_KEYS_FILE_WRITE_ACCESS);

		// ***********************************************************************
		// Set output frame parameters

		fitsfile *output_f_ptr;
	
		int output_f_status = 0;
		long output_f_naxes [2] = {num_bins,nyelements};
	
		long output_f_fpixel = 1;

		// ***********************************************************************
		// Create [output_frame_values_1D] array to hold the output data in the 
                // correct format

		double output_frame_values_1D [num_bins*nyelements];
		memset(output_frame_values_1D, 0, sizeof(double)*num_bins*nyelements);
                int kk;
		for (ii=0; ii<nyelements; ii++) {
	
			jj = ii * num_bins;
	
			for (kk=0; kk<num_bins; kk++) {
	
				output_frame_values_1D[jj] = output_frame_values[ii][kk];
				jj++;

			}
		
		}

		// ***********************************************************************
		// Create and write [output_frame_values_1D] to output file (ARG 5)	
	
		if (!fits_create_file(&output_f_ptr, output_f, &output_f_status)) {
	
			if (!fits_create_img(output_f_ptr, INTERMEDIATE_IMG_ACCURACY[0], 2, output_f_naxes, &output_f_status)) {

				if (!fits_write_img(output_f_ptr, INTERMEDIATE_IMG_ACCURACY[1], output_f_fpixel, num_bins * nyelements, output_frame_values_1D, &output_f_status)) {

				} else { 

					write_key_to_file(ERROR_CODES_FILE, REF_ERROR_CODES_FILE, "L2STATRE", -12, "Status flag for L2 lorebin routine", ERROR_CODES_FILE_WRITE_ACCESS);
					fits_report_error(stdout, output_f_status); 

					free(input_f);
					free(interpolation_type);
					free(output_f);

					fclose(dispersion_solutions_f);
					fclose(outputfile);

					if(fits_close_file(input_f_ptr, &input_f_status)) fits_report_error (stdout, input_f_status); 
					if(fits_close_file(output_f_ptr, &output_f_status)); 

					return 1; 

				}

			} else {

				write_key_to_file(ERROR_CODES_FILE, REF_ERROR_CODES_FILE, "L2STATRE", -13, "Status flag for L2 lorebin routine", ERROR_CODES_FILE_WRITE_ACCESS);
				fits_report_error(stdout, output_f_status); 

				free(input_f);
				free(interpolation_type);
				free(output_f);

				fclose(dispersion_solutions_f);
				fclose(outputfile);

                                if(fits_close_file(input_f_ptr, &input_f_status)) fits_report_error (stdout, input_f_status); 
                                if(fits_close_file(output_f_ptr, &output_f_status)); 

				return 1; 

			}

		} else {

			write_key_to_file(ERROR_CODES_FILE, REF_ERROR_CODES_FILE, "L2STATRE", -14, "Status flag for L2 lorebin routine", ERROR_CODES_FILE_WRITE_ACCESS);
			fits_report_error(stdout, output_f_status); 

			free(input_f);
			free(interpolation_type);
			free(output_f);

			fclose(dispersion_solutions_f);
			fclose(outputfile);

			if(fits_close_file(input_f_ptr, &input_f_status)) fits_report_error (stdout, input_f_status);  

			return 1; 

		}

		// ***********************************************************************
		// Clean up heap memory

		free(input_f);
		free(interpolation_type);
		free(output_f);

		// ***********************************************************************
		// Close input file (ARG 1), output file (ARG 7) and 
		// [FRARCFIT_OUTPUTF_WAVFITS_FILE] file

		if (fclose(dispersion_solutions_f)) {

			write_key_to_file(ERROR_CODES_FILE, REF_ERROR_CODES_FILE, "L2STATRE", -15, "Status flag for L2 lorebin routine", ERROR_CODES_FILE_WRITE_ACCESS);

			fclose(outputfile);

                        if(fits_close_file(input_f_ptr, &input_f_status)) fits_report_error (stdout, input_f_status); 
                        if(fits_close_file(output_f_ptr, &output_f_status)); 

			return 1; 

		}

		if (fclose(outputfile)) {

			write_key_to_file(ERROR_CODES_FILE, REF_ERROR_CODES_FILE, "L2STATRE", -16, "Status flag for L2 lorebin routine", ERROR_CODES_FILE_WRITE_ACCESS);

                        if(fits_close_file(input_f_ptr, &input_f_status)) fits_report_error (stdout, input_f_status); 
                        if(fits_close_file(output_f_ptr, &output_f_status)); 

			return 1; 

		}

		if(fits_close_file(input_f_ptr, &input_f_status)) { 

			write_key_to_file(ERROR_CODES_FILE, REF_ERROR_CODES_FILE, "L2STATRE", -17, "Status flag for L2 lorebin routine", ERROR_CODES_FILE_WRITE_ACCESS);
			fits_report_error (stdout, input_f_status); 

                        if(fits_close_file(output_f_ptr, &output_f_status)); 

			return 1; 

	    	}

		if(fits_close_file(output_f_ptr, &output_f_status)) { 

			write_key_to_file(ERROR_CODES_FILE, REF_ERROR_CODES_FILE, "L2STATRE", -18, "Status flag for L2 lorebin routine", ERROR_CODES_FILE_WRITE_ACCESS);
			fits_report_error (stdout, output_f_status); 

			return 1; 

	    	}

		// ***********************************************************************
		// Write success to [ERROR_CODES_FILE]

		write_key_to_file(ERROR_CODES_FILE, REF_ERROR_CODES_FILE, "L2STATRE", RETURN_FLAG, "Status flag for L2 lorebin routine", ERROR_CODES_FILE_WRITE_ACCESS);

		return 0;

	}

}
Exemple #4
0
int main(int argc, char *argv []) {

	if(populate_env_variable(REF_ERROR_CODES_FILE, "L2_ERROR_CODES_FILE")) {

		printf("\nUnable to populate [REF_ERROR_CODES_FILE] variable with corresponding environment variable. Routine will proceed without error handling\n");

	}

	if (argc != 15) {

		if(populate_env_variable(SPF_BLURB_FILE, "L2_SPF_BLURB_FILE")) {

			RETURN_FLAG = 1;

		} else {

			print_file(SPF_BLURB_FILE);

		}

		write_key_to_file(ERROR_CODES_FILE, REF_ERROR_CODES_FILE, "L2STATFI", -1, "Status flag for L2 spfind routine", ERROR_CODES_FILE_WRITE_ACCESS);

		return 1;

	} else {
		// ***********************************************************************
		// Redefine routine input parameters
		
		char *target_f				= strdup(argv[1]);	
		int bin_size_px				= strtol(argv[2], NULL, 0);
		double bg_percentile			= strtod(argv[3], NULL);
		double clip_sigma			= strtod(argv[4], NULL);
		int median_filter_width_px		= strtol(argv[5], NULL, 0);	
		double min_SNR				= strtod(argv[6], NULL);
		int min_spatial_width_px		= strtol(argv[7], NULL, 0);
                int finding_window_lo_px                = strtol(argv[8], NULL, 0);
                int finding_window_hi_px                = strtol(argv[9], NULL, 0);                
		int max_centering_num_px		= strtol(argv[10], NULL, 0);		
		int centroid_half_window_size_px	= strtol(argv[11], NULL, 0);
		int min_used_bins			= strtol(argv[12], NULL, 0);
		int window_x_lo				= strtol(argv[13], NULL, 0);
		int window_x_hi				= strtol(argv[14], NULL, 0);
		
		// ***********************************************************************
		// Open target file (ARG 1), get parameters and perform any data format 
		// checks

		fitsfile *target_f_ptr;

		int target_f_maxdim = 2, target_f_status = 0, target_f_bitpix, target_f_naxis;
		long target_f_naxes [2] = {1,1};

		if(!fits_open_file(&target_f_ptr, target_f, IMG_READ_ACCURACY, &target_f_status)) {

			if(!populate_img_parameters(target_f, target_f_ptr, target_f_maxdim, &target_f_bitpix, &target_f_naxis, target_f_naxes, &target_f_status, "TARGET FRAME")) {

				if (target_f_naxis != 2) {	// any data format checks here

					write_key_to_file(ERROR_CODES_FILE, REF_ERROR_CODES_FILE, "L2STATFI", -2, "Status flag for L2 spfind routine", ERROR_CODES_FILE_WRITE_ACCESS);

					free(target_f);
					if(fits_close_file(target_f_ptr, &target_f_status)) fits_report_error (stdout, target_f_status); 

					return 1;
	
				}

			} else { 

				write_key_to_file(ERROR_CODES_FILE, REF_ERROR_CODES_FILE, "L2STATFI", -3, "Status flag for L2 spfind routine", ERROR_CODES_FILE_WRITE_ACCESS);
				fits_report_error(stdout, target_f_status); 

				free(target_f);
				if(fits_close_file(target_f_ptr, &target_f_status)) fits_report_error (stdout, target_f_status); 

				return 1; 

			}

		} else { 

			write_key_to_file(ERROR_CODES_FILE, REF_ERROR_CODES_FILE, "L2STATFI", -4, "Status flag for L2 spfind routine", ERROR_CODES_FILE_WRITE_ACCESS);
			fits_report_error(stdout, target_f_status); 

			free(target_f);

			return 1; 

		}
		
		// ***********************************************************************
		// Set the range limits

		int cut_x [2] = {window_x_lo, window_x_hi};
		int cut_y [2] = {1, target_f_naxes[1]};

		// ***********************************************************************
		// Set parameters used when reading data from target file (ARG 1)

		long fpixel [2] = {cut_x[0], cut_y[0]};
		long nxelements = (cut_x[1] - cut_x[0]) + 1;
		long nyelements = (cut_y[1] - cut_y[0]) + 1;

		// ***********************************************************************
		// Create arrays to store pixel values from target fits file (ARG 1)

		double target_f_pixels [nxelements];
		
		// ***********************************************************************
		// Get target fits file (ARG 1) values and store in 2D array

		int ii;

		double target_frame_values [nyelements][nxelements];
		memset(target_frame_values, 0, sizeof(double)*nxelements*nyelements);
		for (fpixel[1] = cut_y[0]; fpixel[1] <= cut_y[1]; fpixel[1]++) {

			memset(target_f_pixels, 0, sizeof(double)*nxelements);

			if(!fits_read_pix(target_f_ptr, TDOUBLE, fpixel, nxelements, NULL, target_f_pixels, NULL, &target_f_status)) {

				for (ii=0; ii<nxelements; ii++) {

					target_frame_values[fpixel[1]-1][ii] = target_f_pixels[ii];

				}

			} else { 

				write_key_to_file(ERROR_CODES_FILE, REF_ERROR_CODES_FILE, "L2STATFI", -5, "Status flag for L2 spfind routine", ERROR_CODES_FILE_WRITE_ACCESS);
				fits_report_error(stdout, target_f_status); 

				free(target_f);									
				if(fits_close_file(target_f_ptr, &target_f_status)) fits_report_error (stdout, target_f_status); 

				return 1; 

			}

		}
		
		// FIND VALUES OF PEAK CENTROID ALONG DISPERSION AXIS
		// ***********************************************************************		
		// 1.	Bin array according to bin width given by [bin_size_px]
			
		int disp_nelements = nxelements, spat_nelements = nyelements;
		
		int disp_nelements_binned = (int)floor(disp_nelements/bin_size_px);			
		double this_frame_values_binned[spat_nelements][disp_nelements_binned];
		memset(this_frame_values_binned, 0, sizeof(double)*spat_nelements*disp_nelements_binned);
		
		double this_bin_value;
		int bin_number = 0;
		int jj;
		for (jj=0; jj<spat_nelements; jj++) {
			this_bin_value = 0;
			bin_number = 0;
			for (ii=0; ii<disp_nelements; ii++) {
				if (ii % bin_size_px == 0 && ii != 0) {
					this_frame_values_binned[jj][bin_number] = this_bin_value;
					bin_number++;
					this_bin_value = 0;
				}
				this_bin_value += target_frame_values[jj][ii];
			}
		}

		printf("\nFinding peaks");
		printf("\n-------------------------------------\n");	
		double peaks[disp_nelements_binned];
		int num_bins_used = 0;
		for (ii=0; ii<disp_nelements_binned; ii++) {

			// 1a.	Establish if any target flux is in this bin
			// 	First find the mean/sd of the [bg_percentile]th lowest valued pixels as an initial parameters for sigma clip			
			double this_spat_values[spat_nelements];
			double this_spat_values_sorted[spat_nelements];
			for (jj=0; jj<spat_nelements; jj++) {
				this_spat_values[jj] = this_frame_values_binned[jj][ii];
			}			
			memcpy(this_spat_values_sorted, this_spat_values, sizeof(double)*spat_nelements);	
			gsl_sort(this_spat_values_sorted, 1, spat_nelements);
			
			int bg_nelements = (int)floor(spat_nelements*bg_percentile);
			double bg_values [bg_nelements];
			int idx = 0;
			for (jj=0; jj<spat_nelements; jj++) {
				if (this_spat_values_sorted[jj] != 0) {			// avoid 0s set from median filter edges
					bg_values[idx] = this_spat_values_sorted[jj];
					idx++;
					if (idx == bg_nelements)
						break;
				}
			}

			if (idx != bg_nelements) {
				write_key_to_file(ERROR_CODES_FILE, REF_ERROR_CODES_FILE, "L2STATFI", -6, "Status flag for L2 spfind routine", ERROR_CODES_FILE_WRITE_ACCESS);

				free(target_f);
				if(fits_close_file(target_f_ptr, &target_f_status)) fits_report_error (stdout, target_f_status); 

				return 1;
			}
			
			double start_mean = gsl_stats_mean(bg_values, 1, bg_nelements);
			double start_sd	  = gsl_stats_sd(bg_values, 1, bg_nelements);

			// 1b.	Iterative sigma clip around dataset with the initial guess
			int retain_indexes[spat_nelements];
			double final_mean, final_sd;
			int final_num_retained_indexes;
			
			printf("\nBin:\t\t\t\t%d", ii);	
			printf("\nStart mean:\t\t\t%f", start_mean);
			printf("\nStart SD:\t\t\t%f", start_sd);
			iterative_sigma_clip(this_spat_values, spat_nelements, clip_sigma, retain_indexes, start_mean, start_sd, &final_mean, &final_sd, &final_num_retained_indexes, FALSE);
			printf("\nFinal mean:\t\t\t%f", final_mean);
			printf("\nFinal SD:\t\t\t%f", final_sd);
			
			// 2.	Smooth array with median filter
			double this_spat_values_smoothed[spat_nelements];			
			memset(this_spat_values_smoothed, 0, sizeof(double)*spat_nelements);
			median_filter(this_spat_values, this_spat_values_smoothed, spat_nelements, median_filter_width_px);
			
			// 3.	Ascertain if this bin contains target flux
			int num_pixels_contain_target_flux = 0;
			for (jj=0; jj<spat_nelements-1; jj++) {
				if (this_spat_values_smoothed[jj] > final_mean + final_sd*min_SNR) {
					num_pixels_contain_target_flux++;
				}
			}
			printf("\nNum pixels (target):\t\t%d", num_pixels_contain_target_flux);
			
			printf("\nDoes bin contain target flux?\t");
			if (num_pixels_contain_target_flux >= min_spatial_width_px) {
				printf("Yes\n");
			} else {
				printf("No\n");
				peaks[ii] = -1;
				continue;
			}
			
			// 3.	Take derivatives
			double this_spat_values_der[spat_nelements-1];
			memset(this_spat_values_der, 0, sizeof(double)*spat_nelements-1);
			for (jj=1; jj<spat_nelements; jj++) {
				this_spat_values_der[jj-1] = this_frame_values_binned[jj][ii] - this_frame_values_binned[jj-1][ii];
			}
			
			// 4.	Smooth derivatives
			double this_spat_values_der_smoothed[spat_nelements-1];	
			memcpy(this_spat_values_der_smoothed, this_spat_values_der, sizeof(double)*spat_nelements-1);
			median_filter(this_spat_values_der, this_spat_values_der_smoothed, spat_nelements-1, median_filter_width_px);				
			
			// 5.	Pick most positive gradient from window, retaining proper index   
                        double this_spat_values_der_smoothed_windowed[spat_nelements-1]; 
                        memcpy(this_spat_values_der_smoothed_windowed, this_spat_values_der_smoothed, sizeof(double)*spat_nelements-1);
                        for (jj=0; jj<spat_nelements; jj++) {
                            if (jj >= finding_window_lo_px && jj <= finding_window_hi_px) {
                                this_spat_values_der_smoothed_windowed[jj] = this_spat_values_der_smoothed_windowed[jj];
                            } else {
                                this_spat_values_der_smoothed_windowed[jj] = -1;
                            }  
                        }
			size_t this_pk_idx = gsl_stats_max_index(this_spat_values_der_smoothed_windowed, 1, spat_nelements-1);
			printf("Start peak index:\t\t%d\n", this_pk_idx);	
			
			// 6.	Using this index, walk through centering window [max_centering_num_px] and find derivative turnover point
			printf("Found turnover:\t\t\t");			
			bool found_turnover = FALSE;
			for (jj=this_pk_idx; jj<this_pk_idx+max_centering_num_px; jj++) {
				if (this_spat_values_der_smoothed[jj] < 0.) {
					this_pk_idx = jj;
					found_turnover = TRUE;
					break;
				}
			}
			
			if (found_turnover) {
				printf("Yes\n");
				printf("End peak index:\t\t\t%d\n", this_pk_idx);	
			} else {
				printf("No\n");
				peaks[ii] = -1;
				continue;
			}

			// 7.	Get parabolic centroid using the full centroid window [centroid_half_window_size_px]
			double this_pk_window_idxs[1 + (2*centroid_half_window_size_px)];
			double this_pk_window_vals[1 + (2*centroid_half_window_size_px)];
			
			memset(this_pk_window_idxs, 0, sizeof(double)*(1 + (2*centroid_half_window_size_px)));
			memset(this_pk_window_vals, 0, sizeof(double)*(1 + (2*centroid_half_window_size_px)));
			idx = 0;
			for (jj=this_pk_idx-centroid_half_window_size_px; jj<=this_pk_idx+centroid_half_window_size_px; jj++) {
				this_pk_window_idxs[idx] = jj;
				this_pk_window_vals[idx] = this_frame_values_binned[jj][ii];
				idx++;
			}	
			
			int order = 2;
			double coeffs [order+1];  
			memset(coeffs, 0, sizeof(double)*order+1);
			double chi_squared;
			if (calc_least_sq_fit(2, 1 + (2*centroid_half_window_size_px), this_pk_window_idxs, this_pk_window_vals, coeffs, &chi_squared)) {

				write_key_to_file(ERROR_CODES_FILE, REF_ERROR_CODES_FILE, "L2STATFI", -7, "Status flag for L2 spfind routine", ERROR_CODES_FILE_WRITE_ACCESS);

				free(target_f);
				if(fits_close_file(target_f_ptr, &target_f_status)) fits_report_error (stdout, target_f_status); 

				return 1; 		

			}
			
			double fitted_peak_idx = -coeffs[1]/(2*coeffs[2]);
			printf("Fitted peak index:\t\t%f\n", fitted_peak_idx);

			// 8.	Ensure fitted peak location is within finding window
			printf("Is fitted peak within window?\t");
			if (fitted_peak_idx > finding_window_lo_px && fitted_peak_idx < finding_window_hi_px) {
				printf("Yes\n");
                                num_bins_used++;
			} else {
				printf("No\n");
				peaks[ii] = -1;
				continue;
			}

			peaks[ii] = fitted_peak_idx;	
			
			/*for (jj=0; jj<spat_nelements-1; jj++) {
				printf("%d\t%f\t%f\n", jj, this_spat_values_der_smoothed[jj], this_spat_values_der[jj]);
			}*/ // DEBUG	
			
		}	
		
		printf("\nNum bins used:\t%d\n", num_bins_used);		
		
		if (num_bins_used < min_used_bins) {
			write_key_to_file(ERROR_CODES_FILE, REF_ERROR_CODES_FILE, "L2STATFI", -8, "Status flag for L2 spfind routine", ERROR_CODES_FILE_WRITE_ACCESS);

			free(target_f);
			if(fits_close_file(target_f_ptr, &target_f_status)) fits_report_error (stdout, target_f_status); 

			return 1;
		}		
		
		// ***********************************************************************
		// Create [FRFIND_OUTPUTF_PEAKS_FILE] output file and print a few 
		// parameters

		FILE *outputfile;
		outputfile = fopen(SPFIND_OUTPUTF_PEAKS_FILE, FILE_WRITE_ACCESS);

		if (!outputfile) { 

			write_key_to_file(ERROR_CODES_FILE, REF_ERROR_CODES_FILE, "L2STATFI", -9, "Status flag for L2 spfind routine", ERROR_CODES_FILE_WRITE_ACCESS);

			free(target_f);
			if(fits_close_file(target_f_ptr, &target_f_status)) fits_report_error (stdout, target_f_status); 

			return 1;


		}

		char timestr [80];
		memset(timestr, '\0', sizeof(char)*80);

		find_time(timestr);

		fprintf(outputfile, "#### %s ####\n\n", SPFIND_OUTPUTF_PEAKS_FILE);
		fprintf(outputfile, "# Lists the coordinates of the peaks found using the spfind routine.\n\n");
		fprintf(outputfile, "# Run filename:\t%s\n", target_f);
		fprintf(outputfile, "# Run datetime:\t%s\n\n", timestr);
		
		for (ii=0; ii<disp_nelements_binned; ii++) {
			if (peaks[ii] == -1)
				continue;
			
			fprintf(outputfile, "%f\t%f\n", cut_x[0]+(ii*bin_size_px) + (double)bin_size_px/2., peaks[ii]);	
		}
		
		fprintf(outputfile, "%d", EOF);		
		
		// ***********************************************************************
		// Clean up heap memory

		free(target_f);

		// ***********************************************************************
		// Close [FRFIND_OUTPUTF_PEAKS_FILE] output file and target file (ARG 1)
		
		if (fclose(outputfile)) {

			write_key_to_file(ERROR_CODES_FILE, REF_ERROR_CODES_FILE, "L2STATFI", -10, "Status flag for L2 spfind routine", ERROR_CODES_FILE_WRITE_ACCESS);

			if(fits_close_file(target_f_ptr, &target_f_status)) fits_report_error (stdout, target_f_status); 

			return 1; 

		}

		if(fits_close_file(target_f_ptr, &target_f_status)) { 

			write_key_to_file(ERROR_CODES_FILE, REF_ERROR_CODES_FILE, "L2STATFI", -11, "Status flag for L2 spfind routine", ERROR_CODES_FILE_WRITE_ACCESS);
			fits_report_error (stdout, target_f_status); 

			return 1; 

	    	}		
		
		// ***********************************************************************
		// Write success to [ERROR_CODES_FILE]

		write_key_to_file(ERROR_CODES_FILE, REF_ERROR_CODES_FILE, "L2STATFI", RETURN_FLAG, "Status flag for L2 spfind routine", ERROR_CODES_FILE_WRITE_ACCESS);

		return 0;

	}

}
int main(int argc, char *argv []) {

	if(populate_env_variable(REF_ERROR_CODES_FILE, "L2_ERROR_CODES_FILE")) {

		printf("\nUnable to populate [REF_ERROR_CODES_FILE] variable with corresponding environment variable. Routine will proceed without error handling\n");

	}

	if (argc != 5) {

		if(populate_env_variable(SPCS_BLURB_FILE, "L2_SPCS_BLURB_FILE")) {

			RETURN_FLAG = 1;

		} else {

			print_file(SPCS_BLURB_FILE);

		}

		write_key_to_file(ERROR_CODES_FILE, REF_ERROR_CODES_FILE, "L2STATCO", -1, "Status flag for L2 spcorrect routine", ERROR_CODES_FILE_WRITE_ACCESS);

		return 1;

	} else {
		// ***********************************************************************
		// Redefine routine input parameters
		
		char *input_f			= strdup(argv[1]);
		char *interpolation_type	= strdup(argv[2]);
		int conserve_flux		= strtol(argv[3], NULL, 0);		
		char *output_f			= strdup(argv[4]);		
		
		// ***********************************************************************
		// Open input file (ARG 1), get parameters and perform any data format 
		// checks

		fitsfile *input_f_ptr;

		int input_f_maxdim = 2, input_f_status = 0, input_f_bitpix, input_f_naxis;
		long input_f_naxes [2] = {1,1};

		if(!fits_open_file(&input_f_ptr, input_f, IMG_READ_ACCURACY, &input_f_status)) {

			if(!populate_img_parameters(input_f, input_f_ptr, input_f_maxdim, &input_f_bitpix, &input_f_naxis, input_f_naxes, &input_f_status, "INPUT FRAME")) {

				if (input_f_naxis != 2) {	// any data format checks here

					write_key_to_file(ERROR_CODES_FILE, REF_ERROR_CODES_FILE, "L2STATCO", -2, "Status flag for L2 spcorrect routine", ERROR_CODES_FILE_WRITE_ACCESS);

					free(input_f);
					free(output_f);					
					free(interpolation_type);
					if(fits_close_file(input_f_ptr, &input_f_status)) fits_report_error (stdout, input_f_status); 

					return 1;
	
				}

			} else { 

				write_key_to_file(ERROR_CODES_FILE, REF_ERROR_CODES_FILE, "L2STATCO", -3, "Status flag for L2 spcorrect routine", ERROR_CODES_FILE_WRITE_ACCESS);
				fits_report_error(stdout, input_f_status); 

				free(input_f);
					free(output_f);					
				free(interpolation_type);
				if(fits_close_file(input_f_ptr, &input_f_status)) fits_report_error (stdout, input_f_status); 

				return 1; 

			}

		} else { 

			write_key_to_file(ERROR_CODES_FILE, REF_ERROR_CODES_FILE, "L2STATCO", -4, "Status flag for L2 spcorrect routine", ERROR_CODES_FILE_WRITE_ACCESS);
			fits_report_error(stdout, input_f_status); 

			free(input_f);
			free(output_f);				
			free(interpolation_type);			

			return 1; 

		}
		
		// ***********************************************************************
		// Set the range limits

		int cut_x [2] = {1, input_f_naxes[0]};
		int cut_y [2] = {1, input_f_naxes[1]};

		// ***********************************************************************
		// Set parameters used when reading data from input file (ARG 1)

		long fpixel [2] = {cut_x[0], cut_y[0]};
		long nxelements = (cut_x[1] - cut_x[0]) + 1;
		long nyelements = (cut_y[1] - cut_y[0]) + 1;

		// ***********************************************************************
		// Create arrays to store pixel values from input fits file (ARG 1)

		double input_f_pixels [nxelements];
		
		// ***********************************************************************
		// Get input fits file (ARG 1) values and store in 2D array

		int ii;

		double input_frame_values [nyelements][nxelements];
		memset(input_frame_values, 0, sizeof(double)*nxelements*nyelements);
		for (fpixel[1] = cut_y[0]; fpixel[1] <= cut_y[1]; fpixel[1]++) {

			memset(input_f_pixels, 0, sizeof(double)*nxelements);

			if(!fits_read_pix(input_f_ptr, TDOUBLE, fpixel, nxelements, NULL, input_f_pixels, NULL, &input_f_status)) {

				for (ii=0; ii<nxelements; ii++) {

					input_frame_values[fpixel[1]-1][ii] = input_f_pixels[ii];

				}

			} else { 

				write_key_to_file(ERROR_CODES_FILE, REF_ERROR_CODES_FILE, "L2STATCO", -5, "Status flag for L2 spcorrect routine", ERROR_CODES_FILE_WRITE_ACCESS);
				fits_report_error(stdout, input_f_status); 

				free(input_f);
				free(output_f);					
				free(interpolation_type);				
				if(fits_close_file(input_f_ptr, &input_f_status)) fits_report_error (stdout, input_f_status); 

				return 1; 

			}

		}	
		
		// ***********************************************************************
		// Open [SPTRACE_OUTPUTF_TRACES_FILE] input file
	
		FILE *inputfile;
	
		if (!check_file_exists(SPTRACE_OUTPUTF_TRACES_FILE)) { 

			inputfile = fopen(SPTRACE_OUTPUTF_TRACES_FILE , "r");

		} else {

			write_key_to_file(ERROR_CODES_FILE, REF_ERROR_CODES_FILE, "L2STATCO", -6, "Status flag for L2 spcorrect routine", ERROR_CODES_FILE_WRITE_ACCESS);

			return 1;

		}	
		
		// ***********************************************************************
		// Find some [SPTRACE_OUTPUTF_TRACES_FILE] file details

		char input_string [500];

		bool find_polynomialorder_comment = FALSE;

		int polynomial_order;	

		char search_string_1 [20] = "# Polynomial Order:\0";	// this is the comment to be found from the [SPTRACE_OUTPUTF_TRACES_FILE] file

		while(!feof(inputfile)) {

			memset(input_string, '\0', sizeof(char)*500);
	
			fgets(input_string, 500, inputfile);	

			if (strncmp(input_string, search_string_1, strlen(search_string_1)) == 0) { 

				sscanf(input_string, "%*[^\t]%d", &polynomial_order);		// read all data up to tab as string ([^\t]), but do not store (*)
				find_polynomialorder_comment = TRUE;
				break;

			} 

		}

		if (find_polynomialorder_comment == FALSE) {	// error check - didn't find the comment in the [SPTRACE_OUTPUTF_TRACES_FILE] file

			write_key_to_file(ERROR_CODES_FILE, REF_ERROR_CODES_FILE, "L2STATCO", -7, "Status flag for L2 frcorrect routine", ERROR_CODES_FILE_WRITE_ACCESS);

			free(input_f);
			free(output_f);				
			free(interpolation_type);				
			if(fits_close_file(input_f_ptr, &input_f_status)) fits_report_error (stdout, input_f_status); 

			return 1;

		}
		
		// ***********************************************************************
		// Rewind and extract coefficients from [SPTRACE_OUTPUTF_TRACES_FILE] file 

		rewind(inputfile);

		int token_index;	// this variable will hold which token we're dealing with
		int coeff_index;	// this variable will hold which coefficient we're dealing with
		double this_coeff;
		double this_chisquared;
	
		char *token;

		double coeffs [polynomial_order+1];
		memset(coeffs, 0, sizeof(double)*(polynomial_order+1));

		while(!feof(inputfile)) {

			memset(input_string, '\0', sizeof(char)*500);
	
			fgets(input_string, 500, inputfile);

			token_index = 0;
			coeff_index = 0;

			if (strtol(&input_string[0], NULL, 0) > 0) { 		// check the line begins with a positive number
				
				// ***********************************************************************
				// String tokenisation loop: 
				//
				// 1. init calls strtok() loading the function with input_string
				// 2. terminate when token is null
				// 3. we keep assigning tokens of input_string to token until termination by calling strtok with a NULL first argument
				// 
				// n.b. searching for tab or newline separators ('\t' and '\n')
				for (token=strtok(input_string, "\t\n"); token !=NULL; token = strtok(NULL, "\t\n")) {	
					if ((token_index >= 0) && (token_index <= polynomial_order)) { 			// coeff token
						this_coeff = strtod(token, NULL);
						//printf("%d\t%e\n", coeff_index, this_coeff);				// DEBUG
						coeffs[coeff_index] = this_coeff;
						coeff_index++;
					} else if (token_index == polynomial_order+1) {					// chisquared token
						this_chisquared = strtod(token, NULL);
					}
					token_index++;
				}
			}
		}	
		
		// ***********************************************************************
		// Determine the min and max offsets from c0 (this is needed to avoid 
		// trying to interpolate past the limits) otherwise throws GSL 
		// INTERPOLATION ERROR.
		
		double c0 = coeffs[0];
		float min_offset = 0;	// this is how much the curvature extends in -ve y
		float max_offset = 0;	// this is how much the curvature extends in +ve y
		for (ii=0; ii<nxelements; ii++) {
			float this_offset = gsl_poly_eval(coeffs, polynomial_order+1, ii) - c0;
			if (this_offset > max_offset) {
				max_offset = this_offset;
			}
			if (this_offset < min_offset) {
				min_offset = this_offset;
			}
		}	

                int min_offset_int = (int)ceil(fabs(min_offset));
		int max_offset_int = (int)ceil(fabs(max_offset));
		int nyelements_reb = nyelements - max_offset_int - min_offset_int;

		// ***********************************************************************
		// Do the rebinning (conserving flux where applicable)

		double reb_values[nyelements_reb][nxelements];
		memset(reb_values, 0, sizeof(double)*nyelements_reb*nxelements);		
		
		double this_pre_rebin_flux, this_post_rebin_flux;
		double this_column_values[nyelements];
		double this_column_values_reb[nyelements_reb];		
		double x_offsetted[nyelements];
		
		int jj;
		for (ii=0; ii<nxelements; ii++) {
			this_pre_rebin_flux = 0.;
			double this_offset = gsl_poly_eval(coeffs, polynomial_order+1, ii) - c0;
			memset(this_column_values, 0, sizeof(double)*nyelements);
			memset(this_column_values_reb, 0, sizeof(double)*nyelements_reb);			
			for (jj=0; jj<nyelements; jj++) {
				this_column_values[jj] = input_frame_values[jj][ii];
				x_offsetted[jj] = jj - this_offset;
				this_pre_rebin_flux += input_frame_values[jj][ii];
			}

			interpolate(interpolation_type, x_offsetted, this_column_values, nyelements, min_offset_int, nyelements_reb-max_offset_int, 1, this_column_values_reb);

			// get post rebin flux
			this_post_rebin_flux = 0.;
			for (jj=0; jj<nyelements_reb; jj++) {
				this_post_rebin_flux += this_column_values_reb[jj];
			}
			
			// apply conservation factor
			double conservation_factor = this_pre_rebin_flux/this_post_rebin_flux;
			//printf("%f\t%f\t%f\n", this_pre_rebin_flux, this_post_rebin_flux, conservation_factor);	// DEBUG
			if (conserve_flux == TRUE) {
				for (jj=0; jj<nyelements_reb; jj++) {
					reb_values[jj][ii] = this_column_values_reb[jj] * conservation_factor;
				} 
			} else {
				for (jj=0; jj<nyelements_reb; jj++) {				
					reb_values[jj][ii] = this_column_values_reb[jj];					
				}
			}	
		}
		
		// ***********************************************************************
		// Set output frame parameters	

		fitsfile *output_f_ptr;
	
		int output_f_status = 0;
		long output_f_naxes [2] = {nxelements,nyelements_reb};
	
		long output_f_fpixel = 1;

		// ***********************************************************************
		// Create [output_frame_values] array to hold the output data in the 
		// correct format
                
		int kk;
		double output_frame_values [nxelements*nyelements_reb];
		memset(output_frame_values, 0, sizeof(double)*nxelements*nyelements_reb);
		for (ii=0; ii<nyelements_reb; ii++) {	
			jj = ii * nxelements;			
			for (kk=0; kk<nxelements; kk++) {
				output_frame_values[jj] = reb_values[ii][kk];
				jj++;
			}
		}	
		
		// ***********************************************************************
		// Create and write [output_frame_values] to output file (ARG 4)
	
		if (!fits_create_file(&output_f_ptr, output_f, &output_f_status)) {
	
			if (!fits_create_img(output_f_ptr, INTERMEDIATE_IMG_ACCURACY[0], 2, output_f_naxes, &output_f_status)) {

				if (!fits_write_img(output_f_ptr, INTERMEDIATE_IMG_ACCURACY[1], output_f_fpixel, nxelements*nyelements_reb, output_frame_values, &output_f_status)) {

				} else { 

					write_key_to_file(ERROR_CODES_FILE, REF_ERROR_CODES_FILE, "L2STATCO", -8, "Status flag for L2 spcorrect routine", ERROR_CODES_FILE_WRITE_ACCESS);
					fits_report_error(stdout, output_f_status); 

					free(input_f);
					free(output_f);				
					free(interpolation_type);
					if(fits_close_file(input_f_ptr, &input_f_status)) fits_report_error (stdout, input_f_status); 
					if(fits_close_file(output_f_ptr, &output_f_status)) fits_report_error (stdout, output_f_status);

					return 1; 

				}

			} else {

				write_key_to_file(ERROR_CODES_FILE, REF_ERROR_CODES_FILE, "L2STATCO", -9, "Status flag for L2 spcorrect routine", ERROR_CODES_FILE_WRITE_ACCESS);
				fits_report_error(stdout, output_f_status); 

				free(input_f);
				free(output_f);				
				free(interpolation_type);
				if(fits_close_file(input_f_ptr, &input_f_status)) fits_report_error (stdout, input_f_status); 
				if(fits_close_file(output_f_ptr, &output_f_status)) fits_report_error (stdout, output_f_status);

				return 1; 

			}

		} else {

			write_key_to_file(ERROR_CODES_FILE, REF_ERROR_CODES_FILE, "L2STATCO", -10, "Status flag for L2 spcorrect routine", ERROR_CODES_FILE_WRITE_ACCESS);
			fits_report_error(stdout, output_f_status); 

			free(input_f);
			free(output_f);				
			free(interpolation_type);
			if(fits_close_file(input_f_ptr, &input_f_status)) fits_report_error (stdout, input_f_status); 

			return 1; 

		}

		// ***********************************************************************
		// Free arrays on heap

		free(input_f);
		free(interpolation_type);
		free(output_f);
		
		// ***********************************************************************
		// Close [SPTRACE_OUTPUTF_TRACES_FILE] output file, input file (ARG 1) and
		// output file (ARG 4)
		
		if (fclose(inputfile)) {

			write_key_to_file(ERROR_CODES_FILE, REF_ERROR_CODES_FILE, "L2STATCO", -11, "Status flag for L2 spcorrect routine", ERROR_CODES_FILE_WRITE_ACCESS);

			if(fits_close_file(input_f_ptr, &input_f_status)) fits_report_error (stdout, input_f_status); 

			return 1; 

		}		

		if(fits_close_file(input_f_ptr, &input_f_status)) { 

			write_key_to_file(ERROR_CODES_FILE, REF_ERROR_CODES_FILE, "L2STATCO", -12, "Status flag for L2 spcorrect routine", ERROR_CODES_FILE_WRITE_ACCESS);
			fits_report_error (stdout, input_f_status); 

			return 1; 

	    	}
	    	
		if(fits_close_file(output_f_ptr, &output_f_status)) { 

			write_key_to_file(ERROR_CODES_FILE, REF_ERROR_CODES_FILE, "L2STATCO", -13, "Status flag for L2 spcorrect routine", ERROR_CODES_FILE_WRITE_ACCESS);
			fits_report_error (stdout, output_f_status); 

			return 1; 

	    	}	    	
		
		// ***********************************************************************
		// Write success to [ERROR_CODES_FILE]

		write_key_to_file(ERROR_CODES_FILE, REF_ERROR_CODES_FILE, "L2STATCO", RETURN_FLAG, "Status flag for L2 spcorrect routine", ERROR_CODES_FILE_WRITE_ACCESS);

		return 0;

	}

}