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 <unistd.h>
7 #include <stdlib.h>
8 #include <stdio.h>
9 #include <math.h>
10 #include <string.h>
11 
12 #include "startree.h"
13 #include "fitstable.h"
14 #include "boilerplate.h"
15 #include "errors.h"
16 #include "log.h"
17 #include "fitsioutils.h"
18 
19 const char* OPTIONS = "hvL:d:t:bsSci:o:R:D:PTkn:";
20 
printHelp(char * progname)21 void printHelp(char* progname) {
22     BOILERPLATE_HELP_HEADER(stdout);
23     printf("\nUsage: %s\n"
24            "     -i <input-fits-catalog-name>\n"
25            "     -o <output-star-kdtree-name>\n"
26            "    [-R <ra-column-name>]: name of RA in FITS table (default RA)\n"
27            "    [-D <dec-column-name>]: name of DEC in FITS table (default DEC)\n"
28            "    [-b]: build bounding boxes (default: splitting planes)\n"
29            "    [-L Nleaf]: number of points in a kdtree leaf node (default 25)\n"
30            "    [-t  <tree type>]:  {double,float,u32,u16}, default u32.\n"
31            "    [-d  <data type>]:  {double,float,u32,u16}, default u32.\n"
32            "    [-S]: include separate splitdim array\n"
33            "    [-c]: run kdtree_check on the resulting tree\n"
34            "    [-P]: unpermute tree + tag-along data\n"
35            "    [-T]: write tag-along table as first extension HDU\n"
36            "    [-k]: keep RA,Dec columns in tag-along table\n"
37            "    [-n <name>]: kd-tree name (default \"stars\")\n"
38            "    [-v]: +verbose\n"
39            "\n", progname);
40 }
41 
42 
main(int argc,char * argv[])43 int main(int argc, char *argv[]) {
44     int argidx, argchar;
45     startree_t* starkd;
46     fitstable_t* cat;
47     fitstable_t* tag;
48     int Nleaf = 0;
49     char* skdtfn = NULL;
50     char* catfn = NULL;
51     char* progname = argv[0];
52     char* racol = NULL;
53     char* deccol = NULL;
54     int loglvl = LOG_MSG;
55     char* treename = NULL;
56 
57     int datatype = 0;
58     int treetype = 0;
59     int buildopts = 0;
60     anbool checktree = FALSE;
61     anbool unpermute = FALSE;
62     anbool remove_radec = TRUE;
63     u32* perm = NULL;
64     anbool tagalong_first = FALSE;
65 
66     if (argc <= 2) {
67         printHelp(progname);
68         return 0;
69     }
70 
71     while ((argchar = getopt (argc, argv, OPTIONS)) != -1)
72         switch (argchar) {
73         case 'T':
74             tagalong_first = TRUE;
75             break;
76         case 'n':
77             treename = optarg;
78             break;
79         case 'k':
80             remove_radec = FALSE;
81             break;
82         case 'P':
83             unpermute = TRUE;
84             break;
85         case 'R':
86             racol = optarg;
87             break;
88         case 'D':
89             deccol = optarg;
90             break;
91         case 'c':
92             checktree = TRUE;
93             break;
94         case 'L':
95             Nleaf = (int)strtoul(optarg, NULL, 0);
96             break;
97         case 'i':
98             catfn = optarg;
99             break;
100         case 'o':
101             skdtfn = optarg;
102             break;
103         case 't':
104             treetype = kdtree_kdtype_parse_tree_string(optarg);
105             break;
106         case 'd':
107             datatype = kdtree_kdtype_parse_data_string(optarg);
108             break;
109         case 'b':
110             buildopts |= KD_BUILD_BBOX;
111             break;
112         case 's':
113             buildopts |= KD_BUILD_SPLIT;
114             break;
115         case 'S':
116             buildopts |= KD_BUILD_SPLITDIM;
117             break;
118         case 'v':
119             loglvl++;
120             break;
121         case '?':
122             fprintf(stderr, "Unknown option `-%c'.\n", optopt);
123         case 'h':
124             printHelp(progname);
125             return 0;
126         default:
127             return -1;
128         }
129 
130     if (optind < argc) {
131         for (argidx = optind; argidx < argc; argidx++)
132             fprintf (stderr, "Non-option argument %s\n", argv[argidx]);
133         printHelp(progname);
134         exit(-1);
135     }
136 
137     if (!(catfn && skdtfn)) {
138         printHelp(progname);
139         exit(-1);
140     }
141 
142     log_init(loglvl);
143     fits_use_error_system();
144 
145     logmsg("Building star kdtree: reading %s, writing to %s\n", catfn, skdtfn);
146 
147     logverb("Reading star catalogue...");
148     cat = fitstable_open(catfn);
149     if (!cat) {
150         ERROR("Couldn't read catalog");
151         exit(-1);
152     }
153     logmsg("Got %i stars\n", fitstable_nrows(cat));
154 
155     starkd = startree_build(cat, racol, deccol, datatype, treetype,
156                             buildopts, Nleaf, argv, argc);
157     if (!starkd) {
158         ERROR("Failed to create star kdtree");
159         exit(-1);
160     }
161     if (checktree) {
162         logverb("Checking tree...\n");
163         if (kdtree_check(starkd->tree)) {
164             ERROR("kdtree_check failed!");
165             exit(-1);
166         }
167     }
168 
169     if (treename) {
170         free(starkd->tree->name);
171         starkd->tree->name = strdup(treename);
172     }
173 
174     if (unpermute) {
175         perm = starkd->tree->perm;
176         starkd->tree->perm = NULL;
177     }
178 
179     if (tagalong_first) {
180         logmsg("Writing tag-along data...\n");
181         tag = fitstable_open_for_writing(skdtfn);
182         if (fitstable_write_primary_header(tag)) {
183             ERROR("Failed to write primary header");
184             exit(-1);
185         }
186         if (startree_write_tagalong_table(cat, tag, racol, deccol,
187                                           (int*)perm, remove_radec)) {
188             ERROR("Failed to write tag-along table");
189             exit(-1);
190         }
191         if (fitstable_close(tag)) {
192             ERROR("Failed to close tag-along data");
193             exit(-1);
194         }
195         // Append kd-tree
196         logverb("Appending kd-tree structure...\n");
197         FILE* fid = fopen(skdtfn, "r+b");
198         if (!fid) {
199             SYSERROR("Failed to open startree output file to append kd-tree: %s", skdtfn);
200             exit(-1);
201         }
202         if (fseeko(fid, 0, SEEK_END)) {
203             SYSERROR("Failed to seek to the end of the startree file to append kd-tree: %s", skdtfn);
204             exit(-1);
205         }
206         off_t off = ftello(fid);
207         printf("Offset to write starkd: %lu\n", (unsigned long)off);
208 
209         if (startree_append_to(starkd, fid)) {
210             ERROR("Failed to append star kdtree");
211             exit(-1);
212         }
213         startree_close(starkd);
214         if (fclose(fid)) {
215             SYSERROR("Failed to close star kdtree file after appending tree\n");
216             exit(-1);
217         }
218     } else {
219         if (startree_write_to_file(starkd, skdtfn)) {
220             ERROR("Failed to write star kdtree");
221             exit(-1);
222         }
223         startree_close(starkd);
224 
225         // Append tag-along table.
226         logmsg("Writing tag-along data...\n");
227         tag = fitstable_open_for_appending(skdtfn);
228 
229         if (startree_write_tagalong_table(cat, tag, racol, deccol,
230                                           (int*)perm, remove_radec)) {
231             ERROR("Failed to write tag-along table");
232             exit(-1);
233         }
234 
235         if (fitstable_close(tag)) {
236             ERROR("Failed to close tag-along data");
237             exit(-1);
238         }
239     }
240     fitstable_close(cat);
241     return 0;
242 }
243 
244 
245