Пример #1
0
int plot_annotations_add_named_target(plotann_t* ann, const char* name) {
	target_t tar;
    int i, N;
    // Try bright stars
    N = bright_stars_n();
    for (i=0; i<N; i++) {
        const brightstar_t* bs = bright_stars_get(i);
        if (!bs->name && !bs->common_name)
            continue;
        if (strcaseeq(name, bs->name) || strcaseeq(name, bs->common_name)) {
            tar.ra = bs->ra;
            tar.dec = bs->dec;
            if (strcaseeq(name, bs->name))
                tar.name = bs->name;
            else
                tar.name = bs->common_name;
            logmsg("Found %s: RA,Dec (%g,%g)\n", name, bs->ra, bs->dec);
            bl_append(ann->targets, &tar);
            return 0;
        }
    }
    // Try NGC objects
	ngc_entry* e = ngc_get_entry_named(name);
	if (!e) {
		ERROR("Failed to find target named \"%s\"", name);
		return -1;
	}
	tar.name = ngc_get_name_list(e, " / ");
	tar.ra = e->ra;
	tar.dec = e->dec;
	logmsg("Found %s: RA,Dec (%g,%g)\n", tar.name, tar.ra, tar.dec);
	bl_append(ann->targets, &tar);
	return 0;
}
Пример #2
0
bl* henry_draper_get(hd_catalog_t* hdcat,
                     double racenter, double deccenter,
                     double r_arcsec) {
    double r2;
    double xyz[3];
    kdtree_qres_t* q;
    bl* res;
    int i;
    hd_entry_t hd;

    radecdeg2xyzarr(racenter, deccenter, xyz);
    r2 = arcsec2distsq(r_arcsec);
    q = kdtree_rangesearch(hdcat->kd, xyz, r2);
    if (!q) {
        return NULL;
    }

    res = bl_new(256, sizeof(hd_entry_t));
    for (i=0; i<q->nres; i++) {
        double* pt = q->results.d + i*3;
        xyzarr2radecdeg(pt, &(hd.ra), &(hd.dec));
        hd.hd = q->inds[i] + 1;
        bl_append(res, &hd);
    }

    kdtree_free_query(q);

    return res;
}
Пример #3
0
void test_try_all_codes(pquad* pq,
                        unsigned int* fieldstars, int dimquad,
                        solver_t* solver, double tol2) {
    int sorted[dimquad];
    int i;
    fflush(NULL);
    printf("test_try_all_codes: [");
    for (i=0; i<dimquad; i++) {
        printf("%s%i", (i?" ":""), fieldstars[i]);
    }
    printf("]");

    // sort AB and C[DE]...
    memcpy(sorted, fieldstars, dimquad * sizeof(int));
    qsort(sorted, 2, sizeof(int), compare_ints_asc);
    qsort(sorted+2, dimquad-2, sizeof(int), compare_ints_asc);

    printf(" -> [");
    for (i=0; i<dimquad; i++) {
        printf("%s%i", (i?" ":""), sorted[i]);
    }
    printf("]\n");
    fflush(NULL);

    bl_append(quadlist, sorted);
}
Пример #4
0
bl* opts_from_array(const an_option_t* opts, int N, bl* lst) {
    int i;
    if (!lst)
        lst = bl_new(4, sizeof(an_option_t));
    for (i=0; i<N; i++)
        bl_append(lst, opts + i);
    return lst;
}
Пример #5
0
void plot_annotations_add_target(plotann_t* ann, double ra, double dec,
								 const char* name) {
	target_t tar;
	memset(&tar, 0, sizeof(target_t));
	tar.ra = ra;
	tar.dec = dec;
	tar.name = strdup(name);
	logmsg("Added target \"%s\" at (%g,%g)\n", tar.name, tar.ra, tar.dec);
	bl_append(ann->targets, &tar);
}
Пример #6
0
static void add_quad(quadbuilder_t* qb, unsigned int* stars, void* vtoken) {
	int i;
	hpquads_t* me = vtoken;
	bl_append(me->quadlist, stars);
	if (me->count_uses) {
		for (i=0; i<me->dimquads; i++)
			me->nuses[stars[i]]++;
	}
	qb->stop_creating = TRUE;
	me->quad_created = TRUE;
}
Пример #7
0
static bl* get_chunks(startree_t* s, il* wordsizes) {
    bl* chunks = bl_new(4, sizeof(fitsbin_chunk_t));
    fitsbin_chunk_t chunk;
    kdtree_t* kd = s->tree;

    fitsbin_chunk_init(&chunk);
    chunk.tablename = "sweep";
	chunk.forced_type = fitscolumn_u8_type();
    chunk.itemsize = sizeof(uint8_t);
    chunk.nrows = kd->ndata;
    chunk.data = s->sweep;
    chunk.userdata = &(s->sweep);
    chunk.required = FALSE;
    bl_append(chunks, &chunk);
    if (wordsizes)
        il_append(wordsizes, sizeof(uint8_t));

    fitsbin_chunk_clean(&chunk);
    return chunks;
}
Пример #8
0
static int write_row_data(fitstable_t* table, void* data, int R) {
	assert(table);
	assert(data);
	if (in_memory(table)) {
		ensure_row_list_exists(table);
		bl_append(table->rows, data);
		// ?
		table->table->nr++;
		return 0;
	}
	if (R == 0)
		R = fitstable_row_size(table);
	if (fwrite(data, 1, R, table->fid) != R) {
		SYSERROR("Failed to write a row to %s", table->fn);
		return -1;
	}
	assert(table->table);
    table->table->nr++;
	return 0;
}
Пример #9
0
void test_try_permutations(int* stars, double* code, int dimquad, solver_t* s) {
	int i;
    fflush(NULL);
	/*
	 printf("test_try_permutations: [");
	 for (i=0; i<dimquad; i++) {
	 printf("%s%i", (i?" ":""), stars[i]);
	 }
	 printf("]\n");
	 */
	printf("{");
	for (i=0; i<dimquad; i++) {
		printf("%s%i", (i?",":""), stars[i]);
	}
	printf("}, ");
    fflush(NULL);
    bl_append(quadlist, stars);

	if (quad_obeys_invariants(NULL, code, dimquad, 0))
		ninv++;
}
Пример #10
0
void fitstable_next_extension(fitstable_t* tab) {
	if (is_writing(tab))
        fits_pad_file(tab->fid);

	if (in_memory(tab)) {
		fitsext_t ext;
		if (!tab->table)
			return;
		// update NAXIS2
		fitstable_fix_header(tab);
		ext.table = tab->table;
		ext.header = tab->header;
		ext.rows = tab->rows;
		bl_append(tab->extensions, &ext);
		tab->rows = NULL;
	} else {
		qfits_table_close(tab->table);
		qfits_header_destroy(tab->header);
	}
    tab->extension++;
    tab->table = NULL;
    tab->header = NULL;
}
Пример #11
0
void* bl_push(bl* list, const void* data) {
	return bl_append(list, data);
}
Пример #12
0
static fitscol_t* fitstable_add_column(fitstable_t* tab, fitscol_t* col) {
	col = bl_append(tab->cols, col);
	col->csize = fits_get_atom_size(col->ctype);
	col->fitssize = fits_get_atom_size(col->fitstype);
	return col;
}
Пример #13
0
int main(int argc, char *argv[]) {
    int argchar;
	char* progname = argv[0];
	char** inputfiles = NULL;
	int ninputfiles = 0;
	int i;
	int firstfield=0, lastfield=INT_MAX-1;
	int firstfieldfile=1, lastfieldfile=INT_MAX-1;
	matchfile** mfs;
	MatchObj** mos;
	anbool* eofs;
	anbool* eofieldfile;
	int nread = 0;
	int f;
	int fieldfile;
	int totalsolved, totalunsolved;
	int mode = MODE_BEST;
	double logodds_tosolve = -HUGE_VAL;
	anbool agree = FALSE;

	MatchObj* bestmo;
	bl* keepers;
	bl* leftovers = NULL;

    while ((argchar = getopt (argc, argv, OPTIONS)) != -1) {
		switch (argchar) {
		case 'S':
			solvedfile = optarg;
			break;
		case 's':
			solvedserver = optarg;
			break;
		case 'F':
			mode = MODE_FIRST;
			break;
		case 'a':
			mode = MODE_ALL;
			break;
		case 'r':
			ratio_tosolve = atof(optarg);
			logodds_tosolve = log(ratio_tosolve);
			break;
		case 'f':
			ninfield_tosolve = atoi(optarg);
			break;
		case 'M':
			agreefname = optarg;
			break;
		case 'L':
			leftoverfname = optarg;
			break;
		case 'I':
			firstfieldfile = atoi(optarg);
			break;
		case 'J':
			lastfieldfile = atoi(optarg);
			break;
		case 'A':
			firstfield = atoi(optarg);
			break;
		case 'B':
			lastfield = atoi(optarg);
			break;
		case 'h':
		default:
			printHelp(progname);
			exit(-1);
		}
	}
	if (optind < argc) {
		ninputfiles = argc - optind;
		inputfiles = argv + optind;
	} else {
		printHelp(progname);
		exit(-1);
	}

	if (lastfield < firstfield) {
		fprintf(stderr, "Last field (-B) must be at least as big as first field (-A)\n");
		exit(-1);
	}

	if (solvedserver)
		if (solvedclient_set_server(solvedserver)) {
			fprintf(stderr, "Failed to set solved server.\n");
			exit(-1);
		}

	if (leftoverfname) {
		leftovermf = matchfile_open_for_writing(leftoverfname);
		if (!leftovermf) {
			fprintf(stderr, "Failed to open file %s to write leftover matches.\n", leftoverfname);
			exit(-1);
		}
		BOILERPLATE_ADD_FITS_HEADERS(leftovermf->header);
		qfits_header_add(leftovermf->header, "HISTORY", "This file was created by the program \"agreeable\".", NULL, NULL);
		if (matchfile_write_headers(leftovermf)) {
			fprintf(stderr, "Failed to write leftovers matchfile header.\n");
			exit(-1);
		}
		leftovers = bl_new(256, sizeof(MatchObj));
	}
	if (agreefname) {
		agreemf = matchfile_open_for_writing(agreefname);
		if (!agreemf) {
			fprintf(stderr, "Failed to open file %s to write agreeing matches.\n", agreefname);
			exit(-1);
		}
		BOILERPLATE_ADD_FITS_HEADERS(agreemf->header);
		qfits_header_add(agreemf->header, "HISTORY", "This file was created by the program \"agreeable\".", NULL, NULL);
		if (matchfile_write_headers(agreemf)) {
			fprintf(stderr, "Failed to write agreeing matchfile header.\n");
			exit(-1);
		}
		agree = TRUE;
	}

	solved = il_new(256);
	unsolved = il_new(256);

	keepers = bl_new(256, sizeof(MatchObj));

	totalsolved = totalunsolved = 0;

	mos =  calloc(ninputfiles, sizeof(MatchObj*));
	eofs = calloc(ninputfiles, sizeof(anbool));
	eofieldfile = malloc(ninputfiles * sizeof(anbool));
	mfs = malloc(ninputfiles * sizeof(matchfile*));

	for (i=0; i<ninputfiles; i++) {
		fprintf(stderr, "Opening file %s...\n", inputfiles[i]);
		mfs[i] = matchfile_open(inputfiles[i]);
		if (!mfs[i]) {
			fprintf(stderr, "Failed to open matchfile %s.\n", inputfiles[i]);
			exit(-1);
		}
	}

	// we assume the matchfiles are sorted by field id and number.
	for (fieldfile=firstfieldfile; fieldfile<=lastfieldfile; fieldfile++) {
		anbool alldone = TRUE;

		memset(eofieldfile, 0, ninputfiles * sizeof(anbool));

		for (f=firstfield; f<=lastfield; f++) {
			int fieldnum = f;
			anbool donefieldfile;
			anbool solved_it;
			bl* writematches = NULL;

			// quit if we've reached the end of all the input files.
			alldone = TRUE;
			for (i=0; i<ninputfiles; i++)
				if (!eofs[i]) {
					alldone = FALSE;
					break;
				}
			if (alldone)
				break;

			// move on to the next fieldfile if all the input files have been
			// exhausted.
			donefieldfile = TRUE;
			for (i=0; i<ninputfiles; i++)
				if (!eofieldfile[i] && !eofs[i]) {
					donefieldfile = FALSE;
					break;
				}
			if (donefieldfile)
				break;

			// start a new field.
			fprintf(stderr, "File %i, Field %i.\n", fieldfile, f);
			solved_it = FALSE;
			bestmo = NULL;

			for (i=0; i<ninputfiles; i++) {
				int nr = 0;
				int ns = 0;

				while (1) {
					if (eofs[i])
						break;
					if (!mos[i])
						mos[i] = matchfile_read_match(mfs[i]);
					if (unlikely(!mos[i])) {
						eofs[i] = TRUE;
						break;
					}

					// skip past entries that are out of range...
					if ((mos[i]->fieldfile < firstfieldfile) ||
						(mos[i]->fieldfile > lastfieldfile) ||
						(mos[i]->fieldnum < firstfield) ||
						(mos[i]->fieldnum > lastfield)) {
						mos[i] = NULL;
						ns++;
						continue;
					}

					if (mos[i]->fieldfile > fieldfile)
						eofieldfile[i] = TRUE;

					if (mos[i]->fieldfile != fieldfile)
						break;

					assert(mos[i]->fieldnum >= fieldnum);
					if (mos[i]->fieldnum != fieldnum)
						break;
					nread++;
					if (nread % 10000 == 9999) {
						fprintf(stderr, ".");
						fflush(stderr);
					}

					// if we've already found a solution, skip past the
					// remaining matches in this file...
					if (solved_it && (mode == MODE_FIRST)) {
						ns++;
						mos[i] = NULL;
						continue;
					}

					nr++;

					if ((mos[i]->logodds >= logodds_tosolve)  &&
						(mos[i]->nindex >= ninfield_tosolve)) {
						solved_it = TRUE;
						// (note, we get a pointer to its position in the list)
						mos[i] = bl_append(keepers, mos[i]);
						if (!bestmo || mos[i]->logodds > bestmo->logodds)
							bestmo = mos[i];
					} else if (leftovers) {
						bl_append(leftovers, mos[i]);
					}

					mos[i] = NULL;

				}
				if (nr || ns)
					fprintf(stderr, "File %s: read %i matches, skipped %i matches.\n", inputfiles[i], nr, ns);
			}

			// which matches do we want to write out?
			if (agree) {
				writematches = bl_new(256, sizeof(MatchObj));

				switch (mode) {
				case MODE_BEST:
				case MODE_FIRST:
					if (bestmo)
						bl_append(writematches, bestmo);
					break;
				case MODE_ALL:
					bl_append_list(writematches, keepers);
					break;
				}
			}

			write_field(writematches, leftovers, fieldfile, fieldnum);

			if (agree)
				bl_free(writematches);

			if (leftovers)
				bl_remove_all(leftovers);
			if (keepers)
				bl_remove_all(keepers);

			fprintf(stderr, "This file: %i fields solved, %i unsolved.\n", il_size(solved), il_size(unsolved));
			fprintf(stderr, "Grand total: %i solved, %i unsolved.\n", totalsolved + il_size(solved), totalunsolved + il_size(unsolved));
		}
		totalsolved += il_size(solved);
		totalunsolved += il_size(unsolved);
		
		il_remove_all(solved);
		il_remove_all(unsolved);

		if (alldone)
			break;
	}

	for (i=0; i<ninputfiles; i++)
		matchfile_close(mfs[i]);
	free(mfs);
	free(mos);
	free(eofs);

	fprintf(stderr, "\nRead %i matches.\n", nread);
	fflush(stderr);

	if (keepers)
		bl_free(keepers);
	if (leftovers)
		bl_free(leftovers);

	il_free(solved);
	il_free(unsolved);

	if (leftovermf) {
		matchfile_fix_headers(leftovermf);
		matchfile_close(leftovermf);
	}

	if (agreemf) {
		matchfile_fix_headers(agreemf);
		matchfile_close(agreemf);
	}

	return 0;
}
Пример #14
0
int main(int argc, char** args) {
    int argchar;
	char* infn = NULL;
	char* outfn = NULL;
	unsigned int row;
	int bits;
	FILE* fid = stdin;
	FILE* fout = stdout;
	int loglvl = LOG_MSG;
	char* progname = args[0];
	int bzero = 0;
	int outformat;
	qfits_header* hdr;
	unsigned int plane;
	off_t datastart;
	anbool onepass = FALSE;
	bl* pixcache = NULL;

#if HAVE_NETPBM
	struct pam img;
	tuple * tuplerow;
#else
	void* rowbuf;
#endif
	int W, H, depth, maxval;

    while ((argchar = getopt (argc, args, OPTIONS)) != -1)
        switch (argchar) {
		case '?':
		case 'h':
			printHelp(progname);
			exit(0);
		case 'v':
			loglvl++;
			break;
		case 'q':
			loglvl--;
			break;
		case 'o':
			outfn = optarg;
			break;
		}

	log_init(loglvl);
	log_to(stderr);
	fits_use_error_system();

	if (optind == argc) {
		// ok, stdin to stdout.
	} else if (optind == argc-1) {
		infn = args[optind];
	} else if (optind == argc-2) {
		infn = args[optind];
		outfn = args[optind+1];
	} else {
		printHelp(progname);
		exit(-1);
	}

	if (infn && !streq(infn, "-")) {
		fid = fopen(infn, "rb");
		if (!fid) {
			SYSERROR("Failed to open input file %s", infn);
			exit(-1);
		}
	}
	if (outfn) {
		fout = fopen(outfn, "wb");
		if (!fid) {
			SYSERROR("Failed to open output file %s", outfn);
			exit(-1);
		}
	} else
		outfn = "stdout";

#if HAVE_NETPBM
	pm_init(args[0], 0);
	pnm_readpaminit(fid, &img, 
					// PAM_STRUCT_SIZE isn't defined until Netpbm 10.23 (July 2004)
#if defined(PAM_STRUCT_SIZE)
					PAM_STRUCT_SIZE(tuple_type)
#else
					sizeof(struct pam)
#endif
);
	W = img.width;
	H = img.height;
	depth = img.depth;
	maxval = img.maxval;

	tuplerow = pnm_allocpamrow(&img);
	bits = pm_maxvaltobits(img.maxval); 
	bits = (bits <= 8) ? 8 : 16;

#else // No NETPBM

	if (parse_pnm_header(fid, &W, &H, &depth, &maxval)) {
		ERROR("Failed to parse PNM header from file: %s\n", infn ? infn : "<stdin>");
		exit(-1);
	}
	bits = 8 * maxval_to_bytes(maxval);

	rowbuf = malloc(W * depth * (bits/8));

#endif

	logmsg("Read file %s: %i x %i pixels x %i color(s); maxval %i\n",
		   infn ? infn : "stdin", W, H, depth, maxval);
	if (bits == 8)
		outformat = BPP_8_UNSIGNED;
	else {
		outformat = BPP_16_SIGNED;
		if (maxval >= INT16_MAX)
			bzero = 0x8000;
	}
	logmsg("Using %i-bit output\n", bits);

	hdr = fits_get_header_for_image3(W, H, outformat, depth, NULL);
	if (bzero)
		fits_header_add_int(hdr, "BZERO", bzero, "Number that has been subtracted from pixel values");
	if (qfits_header_dump(hdr, fout)) {
		ERROR("Failed to write FITS header to file %s", outfn);
		exit(-1);
	}
	qfits_header_destroy(hdr);

	datastart = ftello(fid);
	// Figure out if we can seek backward in this input file...
	if ((fid == stdin) ||
		(fseeko(fid, 0, SEEK_SET) ||
		 fseeko(fid, datastart, SEEK_SET)))
		// Nope!
		onepass = TRUE;
	if (onepass && depth > 1) {
		logmsg("Reading in one pass\n");
		pixcache = bl_new(16384, bits/8);
	}

	for (plane=0; plane<depth; plane++) {
		if (plane > 0) {
			if (fseeko(fid, datastart, SEEK_SET)) {
				SYSERROR("Failed to seek back to start of image data");
				exit(-1);
			}
		}
		for (row = 0; row<H; row++) {
			unsigned int column;

#if HAVE_NETPBM
			pnm_readpamrow(&img, tuplerow);
#else
			read_pnm_row(fid, W, depth, maxval, rowbuf);
#endif

			for (column = 0; column<W; column++) {
				int rtn;
				int pixval;

#if HAVE_NETPBM
				pixval = tuplerow[column][plane];
#else
				pixval = (bits == 8 ?
						  ((uint8_t *)rowbuf)[column*depth + plane] :
						  ((uint16_t*)rowbuf)[column*depth + plane]);
#endif
				if (outformat == BPP_8_UNSIGNED)
					rtn = fits_write_data_B(fout, pixval);
				else
					rtn = fits_write_data_I(fout, pixval-bzero, TRUE);
				if (rtn) {
					ERROR("Failed to write FITS pixel");
					exit(-1);
				}
			}
			if (onepass && depth > 1) {
				for (column = 0; column<W; column++) {
					for (plane=1; plane<depth; plane++) {
						int pixval;
#if HAVE_NETPBM
						pixval = tuplerow[column][plane];
#else
						pixval = (bits == 8 ?
								  ((uint8_t *)rowbuf)[column*depth + plane] :
								  ((uint16_t*)rowbuf)[column*depth + plane]);
#endif
						if (outformat == BPP_8_UNSIGNED) {
							uint8_t pix = pixval;
							bl_append(pixcache, &pix);
						} else {
							int16_t pix = pixval - bzero;
							bl_append(pixcache, &pix);
						}
					}
				}
			}
		}
	}
	
#if HAVE_NETPBM
	pnm_freepamrow(tuplerow);
#else
	free(rowbuf);
#endif

	if (pixcache) {
		int i, j;
		int step = (depth - 1);
		logverb("Writing %zu queued pixels\n", bl_size(pixcache));
		for (plane=1; plane<depth; plane++) {
			j = (plane - 1);
			for (i=0; i<(W * H); i++) {
				int rtn;
				if (outformat == BPP_8_UNSIGNED) {
					uint8_t* pix = bl_access(pixcache, j);
					rtn = fits_write_data_B(fout, *pix);
				} else {
					int16_t* pix = bl_access(pixcache, j);
					rtn = fits_write_data_I(fout, *pix, TRUE);
				}
				if (rtn) {
					ERROR("Failed to write FITS pixel");
					exit(-1);
				}
				j += step;
			}
		}
		bl_free(pixcache);
	}

	if (fid != stdin)
		fclose(fid);

	if (fits_pad_file(fout)) {
		ERROR("Failed to pad output file \"%s\"", outfn);
		return -1;
	}

	if (fout != stdout)
		if (fclose(fout)) {
			SYSERROR("Failed to close output file %s", outfn);
			exit(-1);
		}

	return 0;
}
int uniformize_catalog(fitstable_t* intable, fitstable_t* outtable,
					   const char* racol, const char* deccol,
					   const char* sortcol, anbool sort_ascending,
					   double sort_min_cut,
					   // ?  Or do this cut in a separate process?
					   int bighp, int bignside,
					   int nmargin,
					   // uniformization nside.
					   int Nside,
					   double dedup_radius,
					   int nsweeps,
					   char** args, int argc) {
	anbool allsky;
	intmap_t* starlists;
	int NHP;
	anbool dense = FALSE;
	double dedupr2 = 0.0;
	tfits_type dubl;
	int N;
	int* inorder = NULL;
	int* outorder = NULL;
	int outi;
	double *ra = NULL, *dec = NULL;
	il* myhps = NULL;
	int i,j,k;
	int nkeep = nsweeps;
	int noob = 0;
	int ndup = 0;
	struct oh_token token;
	int* npersweep = NULL;
	qfits_header* outhdr = NULL;
	double *sortval = NULL;

	if (bignside == 0)
		bignside = 1;
	allsky = (bighp == -1);

    if (Nside % bignside) {
        ERROR("Fine healpixelization Nside must be a multiple of the coarse healpixelization Nside");
        return -1;
    }
	if (Nside > HP_MAX_INT_NSIDE) {
		ERROR("Error: maximum healpix Nside = %i", HP_MAX_INT_NSIDE);
		return -1;
	}

	NHP = 12 * Nside * Nside;
	logverb("Healpix Nside: %i, # healpixes on the whole sky: %i\n", Nside, NHP);
	if (!allsky) {
		logverb("Creating index for healpix %i, nside %i\n", bighp, bignside);
		logverb("Number of healpixes: %i\n", ((Nside/bignside)*(Nside/bignside)));
	}
	logverb("Healpix side length: %g arcmin.\n", healpix_side_length_arcmin(Nside));

	dubl = fitscolumn_double_type();
	if (!racol)
		racol = "RA";
	ra = fitstable_read_column(intable, racol, dubl);
	if (!ra) {
		ERROR("Failed to find RA column (%s) in table", racol);
		return -1;
	}
	if (!deccol)
		deccol = "DEC";
	dec = fitstable_read_column(intable, deccol, dubl);
	if (!dec) {
		ERROR("Failed to find DEC column (%s) in table", deccol);
		free(ra);
		return -1;
	}

	N = fitstable_nrows(intable);
	logverb("Have %i objects\n", N);

	// FIXME -- argsort and seek around the input table, and append to
	// starlists in order; OR read from the input table in sequence and
	// sort in the starlists?
	if (sortcol) {
		logverb("Sorting by %s...\n", sortcol);
		sortval = fitstable_read_column(intable, sortcol, dubl);
		if (!sortval) {
			ERROR("Failed to read sorting column \"%s\"", sortcol);
			free(ra);
			free(dec);
			return -1;
		}
		inorder = permuted_sort(sortval, sizeof(double),
								sort_ascending ? compare_doubles_asc : compare_doubles_desc,
								NULL, N);
		if (sort_min_cut > -HUGE_VAL) {
			logverb("Cutting to %s > %g...\n", sortcol, sort_min_cut);
			// Cut objects with sortval < sort_min_cut.
			if (sort_ascending) {
				// skipped objects are at the front -- find the first obj
				// to keep
				for (i=0; i<N; i++)
					if (sortval[inorder[i]] > sort_min_cut)
						break;
				// move the "inorder" indices down.
				if (i)
					memmove(inorder, inorder+i, (N-i)*sizeof(int));
				N -= i;
			} else {
				// skipped objects are at the end -- find the last obj to keep.
				for (i=N-1; i>=0; i--)
					if (sortval[inorder[i]] > sort_min_cut)
						break;
				N = i+1;
			}
			logverb("Cut to %i objects\n", N);
		}
		//free(sortval);
	}

	token.nside = bignside;
	token.finenside = Nside;
	token.hp = bighp;

	if (!allsky && nmargin) {
		int bigbighp, bighpx, bighpy;
		//int ninside;
		il* seeds = il_new(256);
		logverb("Finding healpixes in range...\n");
        healpix_decompose_xy(bighp, &bigbighp, &bighpx, &bighpy, bignside);
		//ninside = (Nside/bignside)*(Nside/bignside);
		// Prime the queue with the fine healpixes that are on the
		// boundary of the big healpix.
		for (i=0; i<((Nside / bignside) - 1); i++) {
			// add (i,0), (i,max), (0,i), and (0,max) healpixes
            int xx = i + bighpx * (Nside / bignside);
            int yy = i + bighpy * (Nside / bignside);
            int y0 =     bighpy * (Nside / bignside);
			// -1 prevents us from double-adding the corners.
            int y1 =(1 + bighpy)* (Nside / bignside) - 1;
            int x0 =     bighpx * (Nside / bignside);
            int x1 =(1 + bighpx)* (Nside / bignside) - 1;
            assert(xx < Nside);
            assert(yy < Nside);
            assert(x0 < Nside);
            assert(x1 < Nside);
            assert(y0 < Nside);
            assert(y1 < Nside);
			il_append(seeds, healpix_compose_xy(bigbighp, xx, y0, Nside));
			il_append(seeds, healpix_compose_xy(bigbighp, xx, y1, Nside));
			il_append(seeds, healpix_compose_xy(bigbighp, x0, yy, Nside));
			il_append(seeds, healpix_compose_xy(bigbighp, x1, yy, Nside));
		}
        logmsg("Number of boundary healpixes: %zu (Nside/bignside = %i)\n", il_size(seeds), Nside/bignside);

		myhps = healpix_region_search(-1, seeds, Nside, NULL, NULL,
									  outside_healpix, &token, nmargin);
		logmsg("Number of margin healpixes: %zu\n", il_size(myhps));
		il_free(seeds);

		il_sort(myhps, TRUE);
		// DEBUG
		il_check_consistency(myhps);
		il_check_sorted_ascending(myhps, TRUE);
	}

	dedupr2 = arcsec2distsq(dedup_radius);
	starlists = intmap_new(sizeof(int32_t), nkeep, 0, dense);

	logverb("Placing stars in grid cells...\n");
	for (i=0; i<N; i++) {
		int hp;
		bl* lst;
		int32_t j32;
		anbool oob;
		if (inorder) {
			j = inorder[i];
			//printf("Placing star %i (%i): sort value %s = %g, RA,Dec=%g,%g\n", i, j, sortcol, sortval[j], ra[j], dec[j]);
		} else
			j = i;
		
		hp = radecdegtohealpix(ra[j], dec[j], Nside);
		//printf("HP %i\n", hp);
		// in bounds?
		oob = FALSE;
		if (myhps) {
			oob = (outside_healpix(hp, &token) && !il_sorted_contains(myhps, hp));
		} else if (!allsky) {
			oob = (outside_healpix(hp, &token));
		}
		if (oob) {
			//printf("out of bounds.\n");
			noob++;
			continue;
		}

		lst = intmap_find(starlists, hp, TRUE);
		/*
		 printf("list has %i existing entries.\n", bl_size(lst));
		 for (k=0; k<bl_size(lst); k++) {
		 bl_get(lst, k, &j32);
		 printf("  %i: index %i, %s = %g\n", k, j32, sortcol, sortval[j32]);
		 }
		 */

		// is this list full?
		if (nkeep && (bl_size(lst) >= nkeep)) {
			// Here we assume we're working in sorted order: once the list is full we're done.
			//printf("Skipping: list is full.\n");
			continue;
		}

		if ((dedupr2 > 0.0) &&
			is_duplicate(hp, ra[j], dec[j], Nside, starlists, ra, dec, dedupr2)) {
			//printf("Skipping: duplicate\n");
			ndup++;
			continue;
		}

		// Add the new star (by index)
		j32 = j;
		bl_append(lst, &j32);
	}
	logverb("%i outside the healpix\n", noob);
	logverb("%i duplicates\n", ndup);

	il_free(myhps);
	myhps = NULL;
	free(inorder);
	inorder = NULL;
	free(ra);
	ra = NULL;
	free(dec);
	dec = NULL;

	outorder = malloc(N * sizeof(int));
	outi = 0;

	npersweep = calloc(nsweeps, sizeof(int));

	for (k=0; k<nsweeps; k++) {
		int starti = outi;
		int32_t j32;
		for (i=0;; i++) {
			bl* lst;
			int hp;
			if (!intmap_get_entry(starlists, i, &hp, &lst))
				break;
			if (bl_size(lst) <= k)
				continue;
			bl_get(lst, k, &j32);
			outorder[outi] = j32;
			//printf("sweep %i, cell #%i, hp %i, star %i, %s = %g\n", k, i, hp, j32, sortcol, sortval[j32]);
			outi++;
		}
		logmsg("Sweep %i: %i stars\n", k+1, outi - starti);
		npersweep[k] = outi - starti;

		if (sortcol) {
			// Re-sort within this sweep.
			permuted_sort(sortval, sizeof(double),
						  sort_ascending ? compare_doubles_asc : compare_doubles_desc,
						  outorder + starti, npersweep[k]);
			/*
			 for (i=0; i<npersweep[k]; i++) {
			 printf("  within sweep %i: star %i, j=%i, %s=%g\n",
			 k, i, outorder[starti + i], sortcol, sortval[outorder[starti + i]]);
			 }
			 */
		}

	}
	intmap_free(starlists);
	starlists = NULL;

	//////
	free(sortval);
	sortval = NULL;

	logmsg("Total: %i stars\n", outi);
	N = outi;

	outhdr = fitstable_get_primary_header(outtable);
    if (allsky)
        qfits_header_add(outhdr, "ALLSKY", "T", "All-sky catalog.", NULL);
    BOILERPLATE_ADD_FITS_HEADERS(outhdr);
    qfits_header_add(outhdr, "HISTORY", "This file was generated by the command-line:", NULL, NULL);
    fits_add_args(outhdr, args, argc);
    qfits_header_add(outhdr, "HISTORY", "(end of command line)", NULL, NULL);
	fits_add_long_history(outhdr, "uniformize-catalog args:");
	fits_add_long_history(outhdr, "  RA,Dec columns: %s,%s", racol, deccol);
	fits_add_long_history(outhdr, "  sort column: %s", sortcol);
	fits_add_long_history(outhdr, "  sort direction: %s", sort_ascending ? "ascending" : "descending");
	if (sort_ascending)
		fits_add_long_history(outhdr, "    (ie, for mag-like sort columns)");
	else
		fits_add_long_history(outhdr, "    (ie, for flux-like sort columns)");
	fits_add_long_history(outhdr, "  uniformization nside: %i", Nside);
	fits_add_long_history(outhdr, "    (ie, side length ~ %g arcmin)", healpix_side_length_arcmin(Nside));
	fits_add_long_history(outhdr, "  deduplication scale: %g arcsec", dedup_radius);
	fits_add_long_history(outhdr, "  number of sweeps: %i", nsweeps);

    fits_header_add_int(outhdr, "NSTARS", N, "Number of stars.");
    fits_header_add_int(outhdr, "HEALPIX", bighp, "Healpix covered by this catalog, with Nside=HPNSIDE");
    fits_header_add_int(outhdr, "HPNSIDE", bignside, "Nside of HEALPIX.");
	fits_header_add_int(outhdr, "CUTNSIDE", Nside, "uniformization scale (healpix nside)");
	fits_header_add_int(outhdr, "CUTMARG", nmargin, "margin size, in healpixels");
	//qfits_header_add(outhdr, "CUTBAND", cutband, "band on which the cut was made", NULL);
	fits_header_add_double(outhdr, "CUTDEDUP", dedup_radius, "deduplication radius [arcsec]");
	fits_header_add_int(outhdr, "CUTNSWEP", nsweeps, "number of sweeps");
	//fits_header_add_double(outhdr, "CUTMINMG", minmag, "minimum magnitude");
	//fits_header_add_double(outhdr, "CUTMAXMG", maxmag, "maximum magnitude");
	for (k=0; k<nsweeps; k++) {
		char key[64];
		sprintf(key, "SWEEP%i", (k+1));
        fits_header_add_int(outhdr, key, npersweep[k], "# stars added");
	}
	free(npersweep);

	if (fitstable_write_primary_header(outtable)) {
		ERROR("Failed to write primary header");
		return -1;
	}

	// Write output.
	fitstable_add_fits_columns_as_struct2(intable, outtable);
	if (fitstable_write_header(outtable)) {
		ERROR("Failed to write output table header");
		return -1;
	}
	logmsg("Writing output...\n");
	logverb("Row size: %i\n", fitstable_row_size(intable));
	if (fitstable_copy_rows_data(intable, outorder, N, outtable)) {
		ERROR("Failed to copy rows from input table to output");
		return -1;
	}
	if (fitstable_fix_header(outtable)) {
		ERROR("Failed to fix output table header");
		return -1;
	}
	free(outorder);
	return 0;
}
static void dualtree_rs_recurse(kdtree_t* xtree, kdtree_t* ytree,
								il* xnodes, il* xleaves,
								bl* xnodebbs, bl* xleafbbs,
								int ynode,
								ttype* ybb,
								double maxd2,
								rangesearch_callback cb, void* baton) {
	int leafmarker;
	il* childnodes;
	int i, N;
	ttype oldbbval;
	ttype splitval;
	uint8_t splitdim;

	// if the query node is a leaf...
	if (KD_IS_LEAF(ytree, ynode)) {
		// ... then run the result function on each x node
		/*
		 if (callbacks->start_results)
		 callbacks->start_results(callbacks->start_extra, ytree, ynode);
		 */
		if (cb) {
			// non-leaf nodes
			N = il_size(xnodes);
			for (i=0; i<N; i++)
				dtrs_nodes(xtree, ytree, il_get(xnodes, i), ynode, maxd2, cb, baton);
		    // leaf nodes
			N = il_size(xleaves);
			for (i=0; i<N; i++)
				dtrs_nodes(xtree, ytree, il_get(xleaves, i), ynode, maxd2, cb, baton);
		}
		/*
		 if (callbacks->end_results)
		 callbacks->end_results(callbacks->end_extra, ytree, ynode);
		 */
		return;
	}

	// if there are search leaves but no search nodes, run the result
	// function on each leaf.  (Note that the query node is not a leaf!)
	if (!il_size(xnodes)) {
		/*
		 result_function result = callbacks->result;
		 void* result_extra = callbacks->result_extra;
		 if (callbacks->start_results)
		 callbacks->start_results(callbacks->start_extra, ytree, ynode);
		 */
		// leaf nodes
		if (result) {
			N = il_size(xleaves);
			for (i=0; i<N; i++)
				dtrs_nodes(xtree, ytree, il_get(xleaves, i), ynode, maxd2, cb, baton);
			//result(result_extra, xtree, il_get(leaves, i), ytree, ynode);
		}
		/*
		 if (callbacks->end_results)
		 callbacks->end_results(callbacks->end_extra, ytree, ynode);
		 */
		return;
	}

	leafmarker = il_size(leaves);
	childnodes = il_new(256);

#define BBLO(bb, d) ((bb)[2*(d)])
#define BBHI(bb, d) ((bb)[(2*(d))+1])

	N = il_size(xnodes);
	for (i=0; i<N; i++) {
		int child1, child2;
		int xnode = il_get(xnodes, i);
		ttype* xbb = bl_access(xnodebbs, i);
		ttype* leftbb;
		ttype* rightbb;

		/*
		 node-node range...
		 if (!decision(decision_extra, xtree, xnode, ytree, ynode))
		 continue;
		 */
		split_dim_and_value(xtree, xnode, &splitdim, &splitval);
		child1 = KD_CHILD_LEFT(xnode);
		if (KD_IS_LEAF(xtree, child1)) {
			il_append(xleaves, child1);
			il_append(xleaves, child2);
			leftbb  = bl_append(xleafbbs, xbb);
			rightbb = bl_append(xleafbbs, xbb);
		} else {
			il_append(childnodes, child1);
			il_append(childnodes, child2);
			leftbb  = bl_append(xnodebbs, xbb);
			rightbb = bl_append(xnodebbs, xbb);
		}
		BBHI(leftbb,  splitdim) = splitval;
		BBLO(rightbb, splitdim) = splitval;
	}

	printf("dualtree: start left child of y node %i: %i\n", ynode, KD_CHILD_LEFT(ynode));
	// recurse on the Y children!
	split_dim_and_value(ytree, ynode, &splitdim, &splitval);
	// update y bb for the left child: max(splitdim) = splitval
	oldbbval = BBHI(ybb, splitdim);
	BBHI(ybb, splitdim) = splitval;
	dualtree_recurse(xtree, ytree, childnodes, leaves,
					 KD_CHILD_LEFT(ynode), callbacks);
	BBHI(ybb, splitdim) = oldbbval;
	printf("dualtree: done left child of y node %i: %i\n", ynode, KD_CHILD_LEFT(ynode));

	printf("dualtree: start right child of y node %i: %i\n", ynode, KD_CHILD_RIGHT(ynode));
	// update y bb for the right child: min(splitdim) = splitval
	oldbbval = BBLO(ybb, splitdim);
	BBLO(ybb, splitdim) = splitval;
	dualtree_recurse(xtree, ytree, childnodes, leaves,
					 KD_CHILD_RIGHT(ynode), callbacks);
	BBLO(ybb, splitdim) = oldbbval;
	printf("dualtree: done right child of y node %i: %i\n", ynode, KD_CHILD_LEFT(ynode));

	// put the "leaves" list back the way it was...
	il_remove_index_range(leaves, leafmarker, il_size(leaves)-leafmarker);
	il_free(childnodes);
}
Пример #17
0
void* bl_extend(bl* list) {
	return bl_append(list, NULL);
}
Пример #18
0
static void add_cmd(plot_args_t* pargs, cairocmd_t* cmd) {
	bl_append(pargs->cairocmds, cmd);
}
Пример #19
0
// One of "struc" or "ap" should be non-null.
static int write_one(fitstable_t* table, const void* struc, anbool flip,
					 va_list* ap) {
    int i;
    char* buf = NULL;
    int Nbuf = 0;
	int ret = 0;
	int nc = ncols(table);

	char* thisrow = NULL;
	int rowoff = 0;

	if (in_memory(table)) {
		ensure_row_list_exists(table);
		thisrow = calloc(1, bl_datasize(table->rows));
	}

    for (i=0; i<nc; i++) {
        fitscol_t* col;
        const char* columndata;
        col = getcol(table, i);
		if (col->in_struct) {
			if (struc)
				columndata = struc + col->coffset;
			else
				columndata = NULL;
		} else {
			if (struc)
				columndata = NULL;
			else
				columndata = va_arg(*ap, void *);
		}
		// If "columndata" is NULL, fits_write_data_array
		// skips the required number of bytes.
		// This allows both structs and normal columns to coexist
		// (in theory -- is this ever used?)
		// (yes, by blind.c when writing rdls and correspondence files
		//  with tag-along data...)

        if (columndata && col->fitstype != col->ctype) {
            int sz = MAX(256, MAX(col->csize, col->fitssize) * col->arraysize);
            if (sz > Nbuf) {
                free(buf);
                buf = malloc(sz);
            }
            fits_convert_data(buf, col->fitssize, col->fitstype,
                              columndata, col->csize, col->ctype,
                              col->arraysize, 1);
            columndata = buf;
        }
		
		if (in_memory(table)) {
			int nb = fitscolumn_get_size(col);
			memcpy(thisrow + rowoff, columndata, nb);
			rowoff += nb;
		} else {
			ret = fits_write_data_array(table->fid, columndata,
										col->fitstype, col->arraysize, flip);
			if (ret)
				break;
		}
    }
    free(buf);
	if (in_memory(table))
		bl_append(table->rows, thisrow);
	free(thisrow);
    table->table->nr++;
    return ret;
}
Пример #20
0
static void bl_sort_rec(bl* list, void* pivot,
						int (*compare)(const void* v1, const void* v2, void* userdata),
						void* userdata) {
	bl* less;
	bl* equal;
	bl* greater;
	int i;
    bl_node* node;

	// Empty case
	if (!list->head)
		return;

	// Base case: list with only one block.
	if (list->head == list->tail) {
		bl_node* node;
		struct funcandtoken ft;
		ft.compare = compare;
		ft.userdata = userdata;
		node = list->head;
		QSORT_R(NODE_DATA(node), node->N, list->datasize, &ft, qcompare);
		return;
	}

	less = bl_new(list->blocksize, list->datasize);
	equal = bl_new(list->blocksize, list->datasize);
	greater = bl_new(list->blocksize, list->datasize);
	for (node=list->head; node; node=node->next) {
		char* data = NODE_CHARDATA(node);
		for (i=0; i<node->N; i++) {
			int val = compare(data, pivot, userdata);
			if (val < 0)
				bl_append(less, data);
			else if (val > 0)
				bl_append(greater, data);
			else
				bl_append(equal, data);
			data += list->datasize;
		}
	}

    // recurse before freeing anything...
	bl_sort_with_userdata(less, compare, userdata);
	bl_sort_with_userdata(greater, compare, userdata);

	for (node=list->head; node;) {
        bl_node* next;
		next = node->next;
		bl_free_node(node);
		node = next;
    }
	list->head = NULL;
	list->tail = NULL;
	list->N = 0;
	list->last_access = NULL;
	list->last_access_n = 0;

	if (less->N) {
		list->head = less->head;
		list->tail = less->tail;
		list->N = less->N;
	}
	if (equal->N) {
		if (list->N) {
			list->tail->next = equal->head;
			list->tail = equal->tail;
		} else {
			list->head = equal->head;
			list->tail = equal->tail;
		}
		list->N += equal->N;
	}
	if (greater->N) {
		if (list->N) {
			list->tail->next = greater->head;
			list->tail = greater->tail;
		} else {
			list->head = greater->head;
			list->tail = greater->tail;
		}
		list->N += greater->N;
	}
	// note, these are supposed to be "free", not "bl_free"; we've stolen
	// the blocks, we're just freeing the headers.
	free(less);
	free(equal);
	free(greater);
}
Пример #21
0
/**
 * Insert the element "data" into the list, such that its index is "index".
 * All elements that previously had indices "index" and above are moved
 * one position to the right.
 */
void bl_insert(bl* list, int index, const void* data) {
	bl_node* node;
	int nskipped;

	if (list->N == index) {
		bl_append(list, data);
		return;
	}

	node = find_node(list, index, &nskipped);

	list->last_access = node;
	list->last_access_n = nskipped;

	// if the node is full:
	//   if we're inserting at the end of this node, then create a new node.
	//   else, shift all but the last element, add in this element, and 
	//     add the last element to a new node.
	if (node->N == list->blocksize) {
		int localindex, nshift;
		bl_node* next = node->next;
		bl_node* destnode;
		localindex = index - nskipped;

		// if the next node exists and is not full, then insert the overflowing
		// element at the front.  otherwise, create a new node.
		if (next && (next->N < list->blocksize)) {
			// shift the existing elements up by one position...
			memmove(NODE_CHARDATA(next) + list->datasize,
					NODE_CHARDATA(next),
					next->N * list->datasize);
			destnode = next;
		} else {
			// create and insert a new node.
			bl_node* newnode = bl_new_node(list);
			newnode->next = next;
			node->next = newnode;
			if (!newnode->next)
				list->tail = newnode;
			destnode = newnode;
		}

		if (localindex == node->N) {
			// the new element becomes the first element in the destination node.
			memcpy(NODE_CHARDATA(destnode), data, list->datasize);
		} else {
			// the last element in this node is added to the destination node.
			memcpy(NODE_CHARDATA(destnode), NODE_CHARDATA(node) + (node->N-1)*list->datasize, list->datasize);
			// shift the end portion of this node up by one...
			nshift = node->N - localindex - 1;
			memmove(NODE_CHARDATA(node) + (localindex+1) * list->datasize,
					NODE_CHARDATA(node) + localindex * list->datasize,
					nshift * list->datasize);
			// insert the new element...
			memcpy(NODE_CHARDATA(node) + localindex * list->datasize, data, list->datasize);
		}

		destnode->N++;
		list->N++;

	} else {
		// shift...
		int localindex, nshift;
		localindex = index - nskipped;
		nshift = node->N - localindex;
		memmove(NODE_CHARDATA(node) + (localindex+1) * list->datasize,
				NODE_CHARDATA(node) + localindex * list->datasize,
				nshift * list->datasize);
		// insert...
		memcpy(NODE_CHARDATA(node) + localindex * list->datasize,
			   data, list->datasize);
		node->N++;
		list->N++;
	}
}
Пример #22
0
int main(int argc, char** args) {
	int c;
	anbool help = FALSE;
	char* outdir = NULL;
	char* cmd;
	int i, j, f;
    int inputnum;
	int rtn;
	sl* engineargs;
	int nbeargs;
	anbool fromstdin = FALSE;
	anbool overwrite = FALSE;
	anbool cont = FALSE;
    anbool skip_solved = FALSE;
    anbool makeplots = TRUE;
	double plotscale = 1.0;
	char* inbgfn = NULL;
    char* bgfn = NULL;
    char* me;
    anbool verbose = FALSE;
    int loglvl = LOG_MSG;
    char* outbase = NULL;
	anbool usecurl = TRUE;
    bl* opts;
    augment_xylist_t theallaxy;
    augment_xylist_t* allaxy = &theallaxy;
    int nmyopts;
    char* removeopts = "ixo\x01";
    char* newfits;
    char* kmz = NULL;
    char* scamp = NULL;
    char* scampconfig = NULL;
    char* index_xyls;
	anbool just_augment = FALSE;
	anbool engine_batch = FALSE;
	bl* batchaxy = NULL;
	bl* batchsf = NULL;
	sl* outfiles;
	sl* tempfiles;
    // these are deleted after the outer loop over input files
	sl* tempfiles2;
	sl* tempdirs;
	anbool timestamp = FALSE;
    anbool tempaxy = FALSE;

    errors_print_on_exit(stderr);
    fits_use_error_system();

    me = find_executable(args[0], NULL);

	engineargs = sl_new(16);
	append_executable(engineargs, "astrometry-engine", me);

	// output filenames.
	outfiles = sl_new(16);
	tempfiles = sl_new(4);
	tempfiles2 = sl_new(4);
	tempdirs = sl_new(4);

	rtn = 0;

    nmyopts = sizeof(options)/sizeof(an_option_t);
    opts = opts_from_array(options, nmyopts, NULL);
    augment_xylist_add_options(opts);

    // remove duplicate short options.
    for (i=0; i<nmyopts; i++) {
        an_option_t* opt1 = bl_access(opts, i);
        for (j=nmyopts; j<bl_size(opts); j++) {
            an_option_t* opt2 = bl_access(opts, j);
            if (opt2->shortopt == opt1->shortopt)
                bl_remove_index(opts, j);
        }
    }

    // remove unwanted augment-xylist options.
    for (i=0; i<strlen(removeopts); i++) {
        for (j=nmyopts; j<bl_size(opts); j++) {
            an_option_t* opt2 = bl_access(opts, j);
            if (opt2->shortopt == removeopts[i])
                bl_remove_index(opts, j);
        }
    }

	// which options are left?
	/*{
		char options[256];
		memset(options, 0, 256);
		printf("options:\n");
		for (i=0; i<bl_size(opts); i++) {
			an_option_t* opt = bl_access(opts, i);
			printf("  %c (%i) %s\n", opt->shortopt, (int)opt->shortopt, opt->name);
			options[(int)((opt->shortopt + 256) % 256)] = 1;
		}
		printf("Remaining short opts:\n");
		for (i=0; i<256; i++) {
			if (!options[i])
				printf("  %c (%i, 0x%x)\n", (char)i, i, i);
		}
	 }*/

    augment_xylist_init(allaxy);

    // default output filename patterns.
    allaxy->axyfn    = "%s.axy";
    allaxy->matchfn  = "%s.match";
    allaxy->rdlsfn   = "%s.rdls";
    allaxy->solvedfn = "%s.solved";
    allaxy->wcsfn    = "%s.wcs";
    allaxy->corrfn   = "%s.corr";
    newfits          = "%s.new";
    index_xyls = "%s-indx.xyls";

	while (1) {
        int res;
		c = opts_getopt(opts, argc, args);
		//printf("option %c (%i)\n", c, (int)c);
        if (c == -1)
            break;
        switch (c) {
        case '\x91':
            allaxy->axyfn = optarg;
            break;
        case '\x90':
            tempaxy = TRUE;
            break;
		case '\x88':
			timestamp = TRUE;
			break;
		case '\x84':
			plotscale = atof(optarg);
			break;
		case '\x85':
			inbgfn = optarg;
			break;
		case '\x87':
			allaxy->assume_fits_image = TRUE;
			break;
		case '(':
			engine_batch = TRUE;
			break;
		case '@':
			just_augment = TRUE;
			break;
        case 'U':
            index_xyls = optarg;
            break;
        case 'n':
            scampconfig = optarg;
            break;
        case 'i':
            scamp = optarg;
            break;
        case 'Z':
            kmz = optarg;
            break;
        case 'N':
            newfits = optarg;
            break;
		case 'h':
			help = TRUE;
			break;
        case 'v':
            sl_append(engineargs, "--verbose");
            verbose = TRUE;
			allaxy->verbosity++;
            loglvl++;
            break;
		case 'D':
			outdir = optarg;
			break;
        case 'o':
            outbase = optarg;
            break;
		case 'b':
		case '\x89':
			sl_append(engineargs, "--config");
			append_escape(engineargs, optarg);
			break;
		case 'f':
			fromstdin = TRUE;
			break;
        case 'O':
            overwrite = TRUE;
            break;
        case 'p':
            makeplots = FALSE;
            break;
        case 'G':
            usecurl = FALSE;
            break;
        case 'K':
            cont = TRUE;
            break;
        case 'J':
            skip_solved = TRUE;
            break;
        default:
            res = augment_xylist_parse_option(c, optarg, allaxy);
            if (res) {
                rtn = -1;
                goto dohelp;
            }
        }
    }

	if ((optind == argc) && !fromstdin) {
		printf("ERROR: You didn't specify any files to process.\n");
		help = TRUE;
	}

	if (help) {
    dohelp:
		print_help(args[0], opts);
		exit(rtn);
	}
    bl_free(opts);

    // --dont-augment: advertised as just write xy file,
    // so quit after doing that.
    if (allaxy->dont_augment) {
        just_augment = TRUE;
    }

    log_init(loglvl);
	if (timestamp)
		log_set_timestamp(TRUE);

    if (kmz && starts_with(kmz, "-"))
        logmsg("Do you really want to save KMZ to the file named \"%s\" ??\n", kmz);

    if (starts_with(newfits, "-")) {
        logmsg("Do you really want to save the new FITS file to the file named \"%s\" ??\n", newfits);
    }

	if (engine_batch) {
		batchaxy = bl_new(16, sizeof(augment_xylist_t));
		batchsf  = bl_new(16, sizeof(solve_field_args_t));
	}

    // Allow (some of the) default filenames to be disabled by setting them to "none".
    allaxy->matchfn  = none_is_null(allaxy->matchfn);
    allaxy->rdlsfn   = none_is_null(allaxy->rdlsfn);
    allaxy->solvedfn = none_is_null(allaxy->solvedfn);
    allaxy->solvedinfn = none_is_null(allaxy->solvedinfn);
    allaxy->wcsfn    = none_is_null(allaxy->wcsfn);
    allaxy->corrfn   = none_is_null(allaxy->corrfn);
    newfits          = none_is_null(newfits);
    index_xyls = none_is_null(index_xyls);

	if (outdir) {
        if (mkdir_p(outdir)) {
            ERROR("Failed to create output directory %s", outdir);
            exit(-1);
        }
	}

	// number of engine args not specific to a particular file
	nbeargs = sl_size(engineargs);

	f = optind;
    inputnum = 0;
	while (1) {
		char* infile = NULL;
		anbool isxyls;
		char* reason;
		int len;
		char* base;
        char* basedir;
        char* basefile = NULL;
		char *objsfn=NULL;
		char *ppmfn=NULL;
        char* downloadfn = NULL;
        char* suffix = NULL;
		sl* cmdline;
        anbool ctrlc;
        anbool isurl;
        augment_xylist_t theaxy;
        augment_xylist_t* axy = &theaxy;
        int j;
		solve_field_args_t thesf;
		solve_field_args_t* sf = &thesf;
		anbool want_pnm = FALSE;

        // reset augment-xylist args.
        memcpy(axy, allaxy, sizeof(augment_xylist_t));

		memset(sf, 0, sizeof(solve_field_args_t));

		if (fromstdin) {
            char fnbuf[1024];
			if (!fgets(fnbuf, sizeof(fnbuf), stdin)) {
				if (ferror(stdin))
					SYSERROR("Failed to read a filename from stdin");
				break;
			}
			len = strlen(fnbuf);
			if (fnbuf[len-1] == '\n')
				fnbuf[len-1] = '\0';
			infile = fnbuf;
            logmsg("Reading input file \"%s\"...\n", infile);
		} else {
			if (f == argc)
				break;
			infile = args[f];
			f++;
            logmsg("Reading input file %i of %i: \"%s\"...\n",
                   f - optind, argc - optind, infile);
		}
        inputnum++;

        cmdline = sl_new(16);

		if (!engine_batch) {
			// Remove arguments that might have been added in previous trips through this loop
			sl_remove_from(engineargs,  nbeargs);
		}

		// Choose the base path/filename for output files.
        if (outbase)
            asprintf_safe(&basefile, outbase, inputnum, infile);
        else
			basefile = basename_safe(infile);
        //logverb("Base filename: %s\n", basefile);

        isurl = (!file_exists(infile) &&
                 (starts_with(infile, "http://") ||
                  starts_with(infile, "ftp://")));

		if (outdir)
            basedir = strdup(outdir);
		else {
            if (isurl)
                basedir = strdup(".");
            else
				basedir = dirname_safe(infile);
        }
        //logverb("Base directory: %s\n", basedir);

        asprintf_safe(&base, "%s/%s", basedir, basefile);
        //logverb("Base name for output files: %s\n", base);

        // trim .gz, .bz2
        // hmm, we drop the suffix in this case...
		len = strlen(base);
        if (ends_with(base, ".gz"))
            base[len-3] = '\0';
        else if (ends_with(base, ".bz2"))
            base[len-4] = '\0';
		len = strlen(base);
		// trim .xx / .xxx / .xxxx
		if (len >= 5) {
            for (j=3; j<=5; j++) {
                if (base[len - j] == '/')
                    break;
                if (base[len - j] == '.') {
                    base[len - j] = '\0';
                    suffix = base + len - j + 1;
                    break;
                }
            }
		}
        logverb("Base: \"%s\", basefile \"%s\", basedir \"%s\", suffix \"%s\"\n", base, basefile, basedir, suffix);

        if (tempaxy) {
            axy->axyfn = create_temp_file("axy", axy->tempdir);
            sl_append_nocopy(tempfiles2, axy->axyfn);
        } else
            axy->axyfn    = sl_appendf(outfiles, axy->axyfn,       base);
        if (axy->matchfn)
            axy->matchfn  = sl_appendf(outfiles, axy->matchfn,     base);
        if (axy->rdlsfn)
            axy->rdlsfn   = sl_appendf(outfiles, axy->rdlsfn,      base);
        if (axy->solvedfn)
            axy->solvedfn = sl_appendf(outfiles, axy->solvedfn,    base);
        if (axy->wcsfn)
            axy->wcsfn    = sl_appendf(outfiles, axy->wcsfn,       base);
        if (axy->corrfn)
            axy->corrfn   = sl_appendf(outfiles, axy->corrfn,      base);
        if (axy->cancelfn)
            axy->cancelfn  = sl_appendf(outfiles, axy->cancelfn, base);
        if (axy->keepxylsfn)
            axy->keepxylsfn  = sl_appendf(outfiles, axy->keepxylsfn, base);
        if (axy->pnmfn)
            axy->pnmfn  = sl_appendf(outfiles, axy->pnmfn, base);
        if (newfits)
            sf->newfitsfn  = sl_appendf(outfiles, newfits,  base);
		if (kmz)
			sf->kmzfn = sl_appendf(outfiles, kmz, base);
        if (index_xyls)
            sf->indxylsfn  = sl_appendf(outfiles, index_xyls, base);
		if (scamp)
			sf->scampfn = sl_appendf(outfiles, scamp, base);
		if (scampconfig)
			sf->scampconfigfn = sl_appendf(outfiles, scampconfig, base);
        if (makeplots) {
            objsfn     = sl_appendf(outfiles, "%s-objs.png",  base);
            sf->redgreenfn = sl_appendf(outfiles, "%s-indx.png",  base);
            sf->ngcfn      = sl_appendf(outfiles, "%s-ngc.png",   base);
        }
        if (isurl) {
            if (suffix)
                downloadfn = sl_appendf(outfiles, "%s.%s", base, suffix);
            else
                downloadfn = sl_appendf(outfiles, "%s", base);
        }

        if (axy->solvedinfn)
            asprintf_safe(&axy->solvedinfn, axy->solvedinfn, base);

        // Do %s replacement on --verify-wcs entries...
        if (sl_size(axy->verifywcs)) {
            sl* newlist = sl_new(4);
            for (j=0; j<sl_size(axy->verifywcs); j++)
                sl_appendf(newlist, sl_get(axy->verifywcs, j), base);
            axy->verifywcs = newlist;
        }

        // ... and plot-bg
        if (inbgfn)
            asprintf_safe(&bgfn, inbgfn, base);

        if (axy->solvedinfn && axy->solvedfn && streq(axy->solvedfn, axy->solvedinfn)) {
            // solved input and output files are the same: don't delete the input!
            sl_remove_string(outfiles, axy->solvedfn);
            free(axy->solvedfn);
            axy->solvedfn = axy->solvedinfn;
        }

        free(basedir);
        free(basefile);

        if (skip_solved) {
            char* tocheck[] = { axy->solvedinfn, axy->solvedfn };
            for (j=0; j<sizeof(tocheck)/sizeof(char*); j++) {
                if (!tocheck[j])
                    continue;
                logverb("Checking for solved file %s\n", tocheck[j]);
                if (file_exists(tocheck[j])) {
                    logmsg("Solved file exists: %s; skipping this input file.\n", tocheck[j]);
                    goto nextfile;
                } else {
                    logverb("File \"%s\" does not exist.\n", tocheck[j]);
                }
            }
        }

        // Check for overlap between input and output filenames
		for (i = 0; i < sl_size(outfiles); i++) {
			char* fn = sl_get(outfiles, i);
            if (streq(fn, infile)) {
                logmsg("Output filename \"%s\" is the same as your input file.\n"
                       "Refusing to continue.\n"
                       "You can either choose a different output filename, or\n"
                       "rename your input file to have a different extension.\n", fn);
                goto nextfile;
            }
        }

		// Check for (and possibly delete) existing output filenames.
		for (i = 0; i < sl_size(outfiles); i++) {
			char* fn = sl_get(outfiles, i);
			if (!file_exists(fn))
				continue;
            if (cont) {
            } else if (overwrite) {
				if (unlink(fn)) {
					SYSERROR("Failed to delete an already-existing output file \"%s\"", fn);
					exit(-1);
				}
			} else {
				logmsg("Output file already exists: \"%s\".\n"
				       "Use the --overwrite flag to overwrite existing files,\n"
                       " or the --continue  flag to not overwrite existing files but still try solving.\n", fn);
				logmsg("Continuing to next input file.\n");
                goto nextfile;
			}
		}

		// if we're making "redgreen" plot, we need:
		if (sf->redgreenfn) {
			// -- index xylist
			if (!sf->indxylsfn) {
				sf->indxylsfn = create_temp_file("indxyls", axy->tempdir);
				sl_append_nocopy(tempfiles, sf->indxylsfn);
			}
			// -- match file.
			if (!axy->matchfn) {
				axy->matchfn = create_temp_file("match", axy->tempdir);
				sl_append_nocopy(tempfiles, axy->matchfn);
			}
		}

		// if index xyls file is needed, we need:
		if (sf->indxylsfn) {
			// -- wcs
			if (!axy->wcsfn) {
				axy->wcsfn = create_temp_file("wcs", axy->tempdir);
				sl_append_nocopy(tempfiles, axy->wcsfn);
			}
			// -- rdls
			if (!axy->rdlsfn) {
				axy->rdlsfn = create_temp_file("rdls", axy->tempdir);
				sl_append_nocopy(tempfiles, axy->rdlsfn);
			}
		}

        // Download URL...
        if (isurl) {

            sl_append(cmdline, usecurl ? "curl" : "wget");
            if (!verbose)
                sl_append(cmdline, usecurl ? "--silent" : "--quiet");
            sl_append(cmdline, usecurl ? "--output" : "-O");
            append_escape(cmdline, downloadfn);
            append_escape(cmdline, infile);

            cmd = sl_implode(cmdline, " ");

            logmsg("Downloading...\n");
            if (run_command(cmd, &ctrlc)) {
                ERROR("%s command %s", sl_get(cmdline, 0),
                      (ctrlc ? "was cancelled" : "failed"));
                exit(-1);
            }
            sl_remove_all(cmdline);
            free(cmd);

            infile = downloadfn;
        }

		if (makeplots)
			want_pnm = TRUE;

		if (axy->assume_fits_image) {
			axy->imagefn = infile;
			if (axy->pnmfn)
				want_pnm = TRUE;
		} else {
			logverb("Checking if file \"%s\" ext %i is xylist or image: ",
                    infile, axy->extension);
			fflush(NULL);
			reason = NULL;
			isxyls = xylist_is_file_xylist(infile, axy->extension,
                                           axy->xcol, axy->ycol, &reason);
			logverb(isxyls ? "xyls\n" : "image\n");
			if (!isxyls)
				logverb("  (not xyls because: %s)\n", reason);
			free(reason);
			fflush(NULL);

			if (isxyls)
				axy->xylsfn = infile;
			else {
				axy->imagefn = infile;
				want_pnm = TRUE;
			}
		}

		if (want_pnm && !axy->pnmfn) {
            ppmfn = create_temp_file("ppm", axy->tempdir);
            sl_append_nocopy(tempfiles, ppmfn);
            axy->pnmfn = ppmfn;
            axy->force_ppm = TRUE;
		}

        axy->keep_fitsimg = (newfits || scamp);

        if (augment_xylist(axy, me)) {
            ERROR("augment-xylist failed");
            exit(-1);
        }

		if (just_augment)
			goto nextfile;

        if (makeplots) {
            // Check that the plotting executables were built...
            char* exec = find_executable("plotxy", me);
            free(exec);
            if (!exec) {
                logmsg("Couldn't find \"plotxy\" executable - maybe you didn't build the plotting programs?\n");
                logmsg("Disabling plots.\n");
                makeplots = FALSE;
            }
        }
        if (makeplots) {
            // source extraction overlay
            if (plot_source_overlay(axy, me, objsfn, plotscale, bgfn))
                makeplots = FALSE;
        }

		append_escape(engineargs, axy->axyfn);

		if (file_readable(axy->wcsfn))
			axy->wcs_last_mod = file_get_last_modified_time(axy->wcsfn);
		else
			axy->wcs_last_mod = 0;

		if (!engine_batch) {
			run_engine(engineargs);
			after_solved(axy, sf, makeplots, me, verbose,
						 axy->tempdir, tempdirs, tempfiles, plotscale, bgfn);
		} else {
			bl_append(batchaxy, axy);
			bl_append(batchsf,  sf );
		}
        fflush(NULL);

        // clean up and move on to the next file.
    nextfile:        
		free(base);
        sl_free2(cmdline);

		if (!engine_batch) {
			free(axy->fitsimgfn);
			free(axy->solvedinfn);
            free(bgfn);
			// erm.
			if (axy->verifywcs != allaxy->verifywcs)
				sl_free2(axy->verifywcs);
			sl_remove_all(outfiles);
			if (!axy->no_delete_temp)
				delete_temp_files(tempfiles, tempdirs);
		}
        errors_print_stack(stdout);
        errors_clear_stack();
        logmsg("\n");
	}

	if (engine_batch) {
		run_engine(engineargs);
		for (i=0; i<bl_size(batchaxy); i++) {
			augment_xylist_t* axy = bl_access(batchaxy, i);
			solve_field_args_t* sf = bl_access(batchsf, i);

			after_solved(axy, sf, makeplots, me, verbose,
						 axy->tempdir, tempdirs, tempfiles, plotscale, bgfn);
			errors_print_stack(stdout);
			errors_clear_stack();
			logmsg("\n");

			free(axy->fitsimgfn);
			free(axy->solvedinfn);
			// erm.
			if (axy->verifywcs != allaxy->verifywcs)
				sl_free2(axy->verifywcs);
		}
		if (!allaxy->no_delete_temp)
			delete_temp_files(tempfiles, tempdirs);
		bl_free(batchaxy);
		bl_free(batchsf);
	}

    if (!allaxy->no_delete_temp)
        delete_temp_files(tempfiles2, NULL);

	sl_free2(outfiles);
	sl_free2(tempfiles);
	sl_free2(tempfiles2);
	sl_free2(tempdirs);
	sl_free2(engineargs);
    free(me);
    augment_xylist_free_contents(allaxy);

	return 0;
}