fitsfile* create_fits_file(const char* filename, int precision, int width, int height, int num_times, int num_channels, double centre_deg[2], double fov_deg[2], double start_time_mjd, double delta_time_sec, double start_freq_hz, double delta_freq_hz, int* status) { long naxes[4]; double delta; fitsfile* f = 0; FILE* t = 0; if (*status) return 0; /* Create a new FITS file and write the image headers. */ t = fopen(filename, "rb"); if (t) { fclose(t); remove(filename); } naxes[0] = width; naxes[1] = height; naxes[2] = num_channels; naxes[3] = num_times; fits_create_file(&f, filename, status); fits_create_img(f, (precision == OSKAR_DOUBLE ? DOUBLE_IMG : FLOAT_IMG), 4, naxes, status); fits_write_date(f, status); /* Write axis headers. */ delta = oskar_convert_fov_to_cellsize(fov_deg[0] * M_PI/180, width) * 180/M_PI; write_axis_header(f, 1, "RA---SIN", "Right Ascension", centre_deg[0], -delta, width / 2 + 1, 0.0, status); delta = oskar_convert_fov_to_cellsize(fov_deg[1] * M_PI/180, height) * 180/M_PI; write_axis_header(f, 2, "DEC--SIN", "Declination", centre_deg[1], delta, height / 2 + 1, 0.0, status); write_axis_header(f, 3, "FREQ", "Frequency", start_freq_hz, delta_freq_hz, 1.0, 0.0, status); write_axis_header(f, 4, "UTC", "Time", start_time_mjd, delta_time_sec, 1.0, 0.0, status); /* Write other headers. */ fits_write_key_str(f, "BUNIT", "JY/BEAM", "Brightness units", status); fits_write_key_str(f, "TIMESYS", "UTC", NULL, status); fits_write_key_str(f, "TIMEUNIT", "s", "Time axis units", status); fits_write_key_dbl(f, "MJD-OBS", start_time_mjd, 10, "Start time", status); fits_write_key_dbl(f, "OBSRA", centre_deg[0], 10, "RA", status); fits_write_key_dbl(f, "OBSDEC", centre_deg[1], 10, "DEC", status); /*fits_flush_file(f, status);*/ return f; }
static void write_axis(fitsfile* fptr, int axis_id, const char* ctype, const char* ctype_comment, double crval, double cdelt, double crpix, int* status) { char key[FLEN_KEYWORD], value[FLEN_VALUE], comment[FLEN_COMMENT]; int decimals = 10; strncpy(comment, ctype_comment, FLEN_COMMENT-1); strncpy(value, ctype, FLEN_VALUE-1); fits_make_keyn("CTYPE", axis_id, key, status); fits_write_key_str(fptr, key, value, comment, status); fits_make_keyn("CRVAL", axis_id, key, status); fits_write_key_dbl(fptr, key, crval, decimals, NULL, status); fits_make_keyn("CDELT", axis_id, key, status); fits_write_key_dbl(fptr, key, cdelt, decimals, NULL, status); fits_make_keyn("CRPIX", axis_id, key, status); fits_write_key_dbl(fptr, key, crpix, decimals, NULL, status); fits_make_keyn("CROTA", axis_id, key, status); fits_write_key_dbl(fptr, key, 0.0, decimals, NULL, status); }
static fitsfile* create_fits_file(const char* filename, int precision, int width, int height, int num_times, int num_channels, double centre_deg[2], double fov_deg[2], double start_time_mjd, double delta_time_sec, double start_freq_hz, double delta_freq_hz, int horizon_mode, const char* settings_log, size_t settings_log_length, int* status) { int imagetype; long naxes[4], naxes_dummy[4] = {1l, 1l, 1l, 1l}; double delta; const double deg2rad = M_PI / 180.0; const double rad2deg = 180.0 / M_PI; fitsfile* f = 0; const char* line; size_t length; if (*status) return 0; /* Create a new FITS file and write the image headers. */ if (oskar_file_exists(filename)) remove(filename); imagetype = (precision == OSKAR_DOUBLE ? DOUBLE_IMG : FLOAT_IMG); naxes[0] = width; naxes[1] = height; naxes[2] = num_channels; naxes[3] = num_times; fits_create_file(&f, filename, status); fits_create_img(f, imagetype, 4, naxes_dummy, status); fits_write_date(f, status); fits_write_key_str(f, "TELESCOP", "OSKAR " OSKAR_VERSION_STR, 0, status); /* Write axis headers. */ if (horizon_mode) { delta = oskar_convert_fov_to_cellsize(M_PI, width); write_axis(f, 1, "-----SIN", "Azimuthal angle", 0.0, -delta * rad2deg, (width + 1) / 2.0, status); delta = oskar_convert_fov_to_cellsize(M_PI, height); write_axis(f, 2, "-----SIN", "Elevation", 90.0, delta * rad2deg, (height + 1) / 2.0, status); } else { delta = oskar_convert_fov_to_cellsize(fov_deg[0] * deg2rad, width); write_axis(f, 1, "RA---SIN", "Right Ascension", centre_deg[0], -delta * rad2deg, (width + 1) / 2.0, status); delta = oskar_convert_fov_to_cellsize(fov_deg[1] * deg2rad, height); write_axis(f, 2, "DEC--SIN", "Declination", centre_deg[1], delta * rad2deg, (height + 1) / 2.0, status); } write_axis(f, 3, "FREQ", "Frequency", start_freq_hz, delta_freq_hz, 1.0, status); write_axis(f, 4, "UTC", "Time", start_time_mjd * 86400.0, delta_time_sec, 1.0, status); /* Write other headers. */ fits_write_key_str(f, "TIMESYS", "UTC", NULL, status); fits_write_key_str(f, "TIMEUNIT", "s", "Time axis units", status); fits_write_key_dbl(f, "MJD-OBS", start_time_mjd, 10, "Start time", status); if (!horizon_mode) { fits_write_key_dbl(f, "OBSRA", centre_deg[0], 10, "RA", status); fits_write_key_dbl(f, "OBSDEC", centre_deg[1], 10, "DEC", status); } /* Write the settings log up to this point as HISTORY comments. */ line = settings_log; length = settings_log_length; for (; settings_log_length > 0;) { const char* eol; fits_write_history(f, line, status); eol = (const char*) memchr(line, '\0', length); if (!eol) break; eol += 1; length -= (eol - line); line = eol; } /* Update header keywords with the correct axis lengths. * Needs to be done here because CFITSIO doesn't let us write only the * file header with the correct axis lengths to start with. This trick * allows us to create a small dummy image block to write only the headers, * and not waste effort moving a huge block of zeros within the file. */ fits_update_key_lng(f, "NAXIS1", naxes[0], 0, status); fits_update_key_lng(f, "NAXIS2", naxes[1], 0, status); fits_update_key_lng(f, "NAXIS3", naxes[2], 0, status); fits_update_key_lng(f, "NAXIS4", naxes[3], 0, status); return f; }
/// Saves the current image in the OpenCL memory buffer to the specified FITS file /// If the OpenCL memory has not been initialzed, this function immediately returns void CLibOI::ExportImage(string filename) { if(mImage_cl == NULL) return; // TODO: Adapt for multi-spectral images Normalize(); // Create a storage buffer for the image and copoy the image to it: valarray<float> image(mImageWidth * mImageHeight * mImageDepth); ExportImage(&image[0], mImageWidth, mImageHeight, mImageDepth); // write out the FITS file: fitsfile *fptr; int status = 0; long fpixel = 1, naxis = 2, nelements; long naxes[2]; /*Initialise storage*/ naxes[0] = (long) mImageWidth; naxes[1] = (long) mImageHeight; nelements = mImageWidth * mImageWidth; /*Create new file*/ if (status == 0) fits_create_file(&fptr, filename.c_str(), &status); /*Create primary array image*/ if (status == 0) fits_create_img(fptr, FLOAT_IMG, naxis, naxes, &status); double RPMAS = (M_PI / 180.0) / 3600000.0; double image_scale_rad = mImageScale * RPMAS; // Write keywords to get WCS to work // fits_write_key_dbl(fptr, "CDELT1", -image_scale_rad, 3, "Radians per pixel", &status); fits_write_key_dbl(fptr, "CDELT2", image_scale_rad, 3, "Radians per pixel", &status); fits_write_key_dbl(fptr, "CRVAL1", 0.0, 3, "X-coordinate of reference pixel", &status); fits_write_key_dbl(fptr, "CRVAL2", 0.0, 3, "Y-coordinate of reference pixel", &status); fits_write_key_lng(fptr, "CRPIX1", naxes[0]/2, "reference pixel in X", &status); fits_write_key_lng(fptr, "CRPIX2", naxes[1]/2, "reference pixel in Y", &status); fits_write_key_str(fptr, "CTYPE1", "RA", "Name of X-coordinate", &status); fits_write_key_str(fptr, "CTYPE2", "DEC", "Name of Y-coordinate", &status); fits_write_key_str(fptr, "CUNIT1", "rad", "Unit of X-coordinate", &status); fits_write_key_str(fptr, "CUNIT2", "rad", "Unit of Y-coordinate", &status); /*Write a keywords (datafile, target, image scale) */ // if (status == 0) // fits_update_key(fptr, TSTRING, "DATAFILE", "FakeImage", "Data File Name", &status); // if (status == 0) // fits_update_key(fptr, TSTRING, "TARGET", "FakeImage", "Target Name", &status); // if (status == 0) // fits_update_key(fptr, TFLOAT, "SCALE", &mImageScale, "Scale (mas/pixel)", &status); /*Write image*/ if (status == 0) fits_write_img(fptr, TFLOAT, fpixel, nelements, &image[0], &status); /*Close file*/ if (status == 0) fits_close_file(fptr, &status); /*Report any errors*/ fits_report_error(stderr, status); }
int HPXhdr(fitsfile *fptr, struct healpix *hpxdat) { char comment[64], cval[16], *ctype1, *ctype2, *descr1, *descr2, *pcode; int status; float cos45, crpix1, crpix2, crval1, crval2, lonpole; double cdelt1, cdelt2; status = 0; fits_update_key_log(fptr, "EXTEND", 0, "No FITS extensions are present", &status); fits_write_date(fptr, &status); /* Set pixel transformation parameters. */ if (hpxdat->layout == 0) { crpix1 = (5 * hpxdat->nside + 1) / 2.0f; } else { crpix1 = (4 * hpxdat->nside + 1) / 2.0f; } crpix2 = crpix1; fits_write_key(fptr, TFLOAT, "CRPIX1", &crpix1, "Coordinate reference pixel", &status); fits_write_key(fptr, TFLOAT, "CRPIX2", &crpix2, "Coordinate reference pixel", &status); cos45 = (float)sqrt(2.0) / 2.0f; if (hpxdat->layout == 0) { fits_write_key_flt(fptr, "PC1_1", cos45, -8, "Transformation matrix element", &status); fits_write_key_flt(fptr, "PC1_2", cos45, -8, "Transformation matrix element", &status); fits_write_key_flt(fptr, "PC2_1", -cos45, -8, "Transformation matrix element", &status); fits_write_key_flt(fptr, "PC2_2", cos45, -8, "Transformation matrix element", &status); } cdelt1 = -90.0 / hpxdat->nside / sqrt(2.0); cdelt2 = -cdelt1; fits_write_key_dbl(fptr, "CDELT1", cdelt1, -8, "[deg] Coordinate increment", &status); fits_write_key_dbl(fptr, "CDELT2", cdelt2, -8, "[deg] Coordinate increment", &status); /* Celestial transformation parameters. */ if (hpxdat->layout == 0) { pcode = "HPX"; } else { pcode = "XPH"; } if (hpxdat->crdsys == 'G') { /* Galactic. */ ctype1 = "GLON"; ctype2 = "GLAT"; descr1 = "Galactic longitude"; descr2 = "Galactic latitude"; } else if (hpxdat->crdsys == 'E') { /* Ecliptic, who-knows-what. */ ctype1 = "ELON"; ctype2 = "ELAT"; descr1 = "Ecliptic longitude"; descr2 = "Ecliptic latitude"; } else if (hpxdat->crdsys == 'Q') { /* Equatorial, who-knows-what. */ ctype1 = "RA--"; ctype2 = "DEC-"; descr1 = "Right ascension"; descr2 = "Declination"; } else { /* Unknown. */ ctype1 = "XLON"; ctype2 = "XLAT"; descr1 = "Longitude"; descr2 = " Latitude"; } sprintf(cval, "%s-%s", ctype1, pcode); sprintf(comment, "%s in an %s projection", descr1, pcode); fits_write_key_str(fptr, "CTYPE1", cval, comment, &status); sprintf(cval, "%s-%s", ctype2, pcode); sprintf(comment, "%s in an %s projection", descr2, pcode); fits_write_key_str(fptr, "CTYPE2", cval, comment, &status); crval1 = 0.0f + 90.0f * hpxdat->quad; if (hpxdat->layout == 0) { crval2 = 0.0f; } else if (hpxdat->layout == 1) { crval1 += 180.0f; crval2 = 90.0f; } else { crval1 += 180.0f; crval2 = -90.0f; } if (360.0f < crval1) crval1 -= 360.0f; sprintf(comment, "[deg] %s at the reference point", descr1); fits_write_key(fptr, TFLOAT, "CRVAL1", &crval1, comment, &status); sprintf(comment, "[deg] %s at the reference point", descr2); fits_write_key(fptr, TFLOAT, "CRVAL2", &crval2, comment, &status); if (hpxdat->layout) { lonpole = 180.0f; sprintf(comment, "[deg] Native longitude of the celestial pole"); fits_write_key(fptr, TFLOAT, "LONPOLE", &lonpole, comment, &status); } if (hpxdat->layout == 0) { fits_write_key_lng(fptr, "PV2_1", (LONGLONG)4, "HPX H parameter (longitude)", &status); fits_write_key_lng(fptr, "PV2_2", (LONGLONG)3, "HPX K parameter (latitude)", &status); } /* Commentary. */ fits_write_record(fptr, " ", &status); if (hpxdat->layout == 0) { fits_write_comment(fptr, "Celestial map with FITS-standard HPX coordinate system generated by", &status); } else { fits_write_comment(fptr, "Celestial map with XPH coordinate system (polar HPX) generated by", &status); } fits_write_comment(fptr, "'HPXcvt' which reorganises HEALPix data without interpolation as", &status); fits_write_comment(fptr, "described in \"Mapping on the HEALPix grid\" by Mark Calabretta and", &status); fits_write_comment(fptr, "Boud Roukema. See http://www.atnf.csiro.au/people/Mark.Calabretta", &status); return status; }