1 /*
2 # This file is part of the Astrometry.net suite.
3 # Licensed under a 3-clause BSD style license - see LICENSE
4 */
5
6 #include <string.h>
7 #include <unistd.h>
8 #include <assert.h>
9
10 #include "codefile.h"
11 #include "starutil.h"
12 #include "ioutils.h"
13 #include "fitsioutils.h"
14 #include "errors.h"
15 #include "quad-utils.h"
16
quad_write(codefile_t * codes,quadfile_t * quads,unsigned int * quad,startree_t * starkd,int dimquads,int dimcodes)17 void quad_write(codefile_t* codes, quadfile_t* quads,
18 unsigned int* quad, startree_t* starkd,
19 int dimquads, int dimcodes) {
20 double code[DCMAX];
21 quad_compute_code(quad, dimquads, starkd, code);
22 quad_enforce_invariants(quad, code, dimquads, dimcodes);
23 codefile_write_code(codes, code);
24 quadfile_write_quad(quads, quad);
25 }
26
quad_write_const(codefile_t * codes,quadfile_t * quads,const unsigned int * quad,startree_t * starkd,int dimquads,int dimcodes)27 void quad_write_const(codefile_t* codes, quadfile_t* quads,
28 const unsigned int* quad, startree_t* starkd,
29 int dimquads, int dimcodes) {
30 int k;
31 unsigned int quadcopy[DQMAX];
32 for (k=0; k<dimquads; k++)
33 quadcopy[k] = quad[k];
34 quad_write(codes, quads, quadcopy, starkd, dimquads, dimcodes);
35 }
36
codefile_compute_field_code(const double * xy,double * code,int dimquads)37 void codefile_compute_field_code(const double* xy, double* code, int dimquads) {
38 double Ax, Ay;
39 double Bx, By;
40 double ABx, ABy;
41 double scale, invscale;
42 double costheta, sintheta;
43 int i;
44
45 Ax = xy[2*0 + 0];
46 Ay = xy[2*0 + 1];
47 Bx = xy[2*1 + 0];
48 By = xy[2*1 + 1];
49 ABx = Bx - Ax;
50 ABy = By - Ay;
51 scale = (ABx * ABx) + (ABy * ABy);
52 invscale = 1.0 / scale;
53 costheta = (ABy + ABx) * invscale;
54 sintheta = (ABy - ABx) * invscale;
55
56 // starting with star C...
57 for (i=2; i<dimquads; i++) {
58 double Cx, Cy;
59 double x, y;
60 Cx = xy[2*i + 0];
61 Cy = xy[2*i + 1];
62 Cx -= Ax;
63 Cy -= Ay;
64 x = Cx * costheta + Cy * sintheta;
65 y = -Cx * sintheta + Cy * costheta;
66 code[2*(i-2)+0] = x;
67 code[2*(i-2)+1] = y;
68 }
69 }
70
codefile_compute_star_code(const double * starxyz,double * code,int dimquads)71 void codefile_compute_star_code(const double* starxyz, double* code, int dimquads) {
72 quad_compute_star_code(starxyz, code, dimquads);
73 }
74
75
76 #define CHUNK_CODES 0
77
codes_chunk(codefile_t * cf)78 static fitsbin_chunk_t* codes_chunk(codefile_t* cf) {
79 return fitsbin_get_chunk(cf->fb, CHUNK_CODES);
80 }
81
callback_read_header(fitsbin_t * fb,fitsbin_chunk_t * chunk)82 static int callback_read_header(fitsbin_t* fb, fitsbin_chunk_t* chunk) {
83 qfits_header* primheader = fitsbin_get_primary_header(fb);
84 codefile_t* cf = chunk->userdata;
85
86 cf->dimcodes = qfits_header_getint(primheader, "DIMCODES", 4);
87 cf->numcodes = qfits_header_getint(primheader, "NCODES", -1);
88 cf->numstars = qfits_header_getint(primheader, "NSTARS", -1);
89 cf->index_scale_upper = qfits_header_getdouble(primheader, "SCALE_U", -1.0);
90 cf->index_scale_lower = qfits_header_getdouble(primheader, "SCALE_L", -1.0);
91 cf->indexid = qfits_header_getint(primheader, "INDEXID", 0);
92 cf->healpix = qfits_header_getint(primheader, "HEALPIX", -1);
93 cf->hpnside = qfits_header_getint(primheader, "HPNSIDE", 1);
94
95 if ((cf->numcodes == -1) || (cf->numstars == -1) ||
96 (cf->index_scale_upper == -1.0) || (cf->index_scale_lower == -1.0)) {
97 ERROR("Couldn't find NCODES or NSTARS or SCALE_U or SCALE_L entries in FITS header");
98 return -1;
99 }
100 if (fits_check_endian(primheader)) {
101 ERROR("File was written with the wrong endianness");
102 return -1;
103 }
104 chunk->itemsize = cf->dimcodes * sizeof(double);
105 chunk->nrows = cf->numcodes;
106 return 0;
107 }
108
new_codefile(const char * fn,anbool writing,anbool inmem)109 static codefile_t* new_codefile(const char* fn, anbool writing, anbool inmem) {
110 fitsbin_chunk_t chunk;
111 codefile_t* cf = calloc(1, sizeof(codefile_t));
112 if (!cf) {
113 SYSERROR("Couldn't calloc a codefile struct");
114 return NULL;
115 }
116 cf->healpix = -1;
117 cf->hpnside = 1;
118
119 if (inmem) {
120 cf->fb = fitsbin_open_in_memory();
121 } else {
122 if (writing)
123 cf->fb = fitsbin_open_for_writing(fn);
124 else
125 cf->fb = fitsbin_open(fn);
126 }
127 if (!cf->fb) {
128 ERROR("Failed to create fitsbin");
129 return NULL;
130 }
131
132 fitsbin_chunk_init(&chunk);
133 chunk.tablename = "codes";
134 chunk.required = 1;
135 chunk.callback_read_header = callback_read_header;
136 chunk.userdata = cf;
137 fitsbin_add_chunk(cf->fb, &chunk);
138 fitsbin_chunk_clean(&chunk);
139
140 return cf;
141 }
142
codefile_get_code(const codefile_t * cf,int codeid,double * code)143 void codefile_get_code(const codefile_t* cf, int codeid, double* code) {
144 int i;
145 if (codeid >= cf->numcodes) {
146 ERROR("Requested codeid %i, but number of codes is %i", codeid, cf->numcodes);
147 assert(codeid < cf->numcodes);
148 // just carry on - we'll probably segfault.
149 }
150 for (i=0; i<cf->dimcodes; i++)
151 code[i] = cf->codearray[codeid * cf->dimcodes + i];
152 }
153
codefile_close(codefile_t * cf)154 int codefile_close(codefile_t* cf) {
155 int rtn;
156 if (!cf) return 0;
157 rtn = fitsbin_close(cf->fb);
158 free(cf);
159 return rtn;
160 }
161
codefile_open(const char * fn)162 codefile_t* codefile_open(const char* fn) {
163 codefile_t* cf = NULL;
164
165 cf = new_codefile(fn, FALSE, FALSE);
166 if (!cf)
167 goto bailout;
168 if (fitsbin_read(cf->fb)) {
169 ERROR("Failed to open codes file");
170 goto bailout;
171 }
172 cf->codearray = codes_chunk(cf)->data;
173 return cf;
174
175 bailout:
176 if (cf)
177 codefile_close(cf);
178 return NULL;
179 }
180
open_for_writing(const char * fn)181 static codefile_t* open_for_writing(const char* fn) {
182 codefile_t* cf;
183 qfits_header* hdr;
184 if (fn)
185 cf = new_codefile(fn, TRUE, FALSE);
186 else
187 cf = new_codefile(fn, TRUE, TRUE);
188 if (!cf)
189 goto bailout;
190 // default
191 cf->dimcodes = 4;
192
193 // add default values to header
194 hdr = codefile_get_header(cf);
195 fits_add_endian(hdr);
196 qfits_header_add(hdr, "AN_FILE", "CODE", "This file lists the code for each quad.", NULL);
197 qfits_header_add(hdr, "NCODES", "0", "", NULL);
198 qfits_header_add(hdr, "NSTARS", "0", "", NULL);
199 fits_header_add_int(hdr, "DIMCODES", cf->dimcodes, "");
200 qfits_header_add(hdr, "SCALE_U", "0.0", "", NULL);
201 qfits_header_add(hdr, "SCALE_L", "0.0", "", NULL);
202 qfits_header_add(hdr, "INDEXID", "0", "", NULL);
203 qfits_header_add(hdr, "HEALPIX", "-1", "", NULL);
204 qfits_header_add(hdr, "HPNSIDE", "1", "", NULL);
205 fits_add_long_comment(hdr, "The first extension contains the codes "
206 "stored as %i native-endian doubles. "
207 "(the quad location in %i-D code space)", cf->dimcodes, cf->dimcodes);
208 return cf;
209 bailout:
210 if (cf)
211 codefile_close(cf);
212 return NULL;
213 }
214
codefile_open_for_writing(const char * fn)215 codefile_t* codefile_open_for_writing(const char* fn) {
216 if (!fn) {
217 ERROR("Non-NULL filename required");
218 return NULL;
219 }
220 return open_for_writing(fn);
221 }
222
codefile_open_in_memory()223 codefile_t* codefile_open_in_memory() {
224 return open_for_writing(NULL);
225 }
226
codefile_switch_to_reading(codefile_t * cf)227 int codefile_switch_to_reading(codefile_t* cf) {
228 if (codefile_fix_header(cf)) {
229 ERROR("Failed to fix codes header");
230 return -1;
231 }
232 if (fitsbin_switch_to_reading(cf->fb)) {
233 ERROR("Failed to switch to read mode");
234 return -1;
235 }
236 if (fitsbin_read(cf->fb)) {
237 ERROR("Failed to open codes file");
238 return -1;
239 }
240 cf->codearray = codes_chunk(cf)->data;
241 return 0;
242 }
243
codefile_write_header(codefile_t * cf)244 int codefile_write_header(codefile_t* cf) {
245 fitsbin_t* fb = cf->fb;
246 fitsbin_chunk_t* chunk = codes_chunk(cf);
247 chunk->itemsize = cf->dimcodes * sizeof(double);
248 chunk->nrows = cf->numcodes;
249
250 if (fitsbin_write_primary_header(fb) ||
251 fitsbin_write_chunk_header(fb, chunk)) {
252 ERROR("Failed to write codefile header");
253 return -1;
254 }
255 return 0;
256 }
257
codefile_fix_header(codefile_t * cf)258 int codefile_fix_header(codefile_t* cf) {
259 qfits_header* hdr;
260 fitsbin_t* fb = cf->fb;
261 fitsbin_chunk_t* chunk = codes_chunk(cf);
262 chunk->itemsize = cf->dimcodes * sizeof(double);
263 chunk->nrows = cf->numcodes;
264
265 hdr = codefile_get_header(cf);
266
267 // fill in the real values...
268 fits_header_mod_int(hdr, "DIMCODES", cf->dimcodes, "Number of values in a code.");
269 fits_header_mod_int(hdr, "NCODES", cf->numcodes, "Number of codes.");
270 fits_header_mod_int(hdr, "NSTARS", cf->numstars, "Number of stars.");
271 fits_header_mod_double(hdr, "SCALE_U", cf->index_scale_upper, "Upper-bound index scale (radians).");
272 fits_header_mod_double(hdr, "SCALE_L", cf->index_scale_lower, "Lower-bound index scale (radians).");
273 fits_header_mod_int(hdr, "INDEXID", cf->indexid, "Index unique ID.");
274 fits_header_mod_int(hdr, "HEALPIX", cf->healpix, "Healpix of this index.");
275 fits_header_mod_int(hdr, "HPNSIDE", cf->hpnside, "Nside of the healpixelization");
276
277 if (fitsbin_fix_primary_header(fb) ||
278 fitsbin_fix_chunk_header(fb, chunk)) {
279 ERROR("Failed to fix code header");
280 return -1;
281 }
282 return 0;
283 }
284
codefile_write_code(codefile_t * cf,double * code)285 int codefile_write_code(codefile_t* cf, double* code) {
286 fitsbin_chunk_t* chunk = codes_chunk(cf);
287 if (fitsbin_write_item(cf->fb, chunk, code)) {
288 ERROR("Failed to write code");
289 return -1;
290 }
291 cf->numcodes++;
292 return 0;
293 }
294
codefile_get_header(const codefile_t * cf)295 qfits_header* codefile_get_header(const codefile_t* cf) {
296 return fitsbin_get_primary_header(cf->fb);
297 }
298
codefile_dimcodes(const codefile_t * cf)299 int codefile_dimcodes(const codefile_t* cf) {
300 return cf->dimcodes;
301 }
302