Exemplo n.º 1
0
int hpquads(startree_t* starkd,
			codefile_t* codes,
			quadfile_t* quads,
			int Nside,
			double scale_min_arcmin,
			double scale_max_arcmin,
			int dimquads,
			int passes,
			int Nreuses,
			int Nloosen,
			int id,
			anbool scanoccupied,

			void* sort_data,
			int (*sort_func)(const void*, const void*),
			int sort_size,
			
			char** args, int argc) {
	hpquads_t myhpquads;
	hpquads_t* me = &myhpquads;

	int i;
	int pass;
	anbool circle = TRUE;
	double radius2;
	il* hptotry;
	int Nhptotry = 0;
	int nquads;
	double hprad;
	double quadscale;

	int skhp, sknside;

	qfits_header* qhdr;
	qfits_header* chdr;

	int N;
	int dimcodes;
	int quadsize;
	int NHP;

	memset(me, 0, sizeof(hpquads_t));

	if (Nside > HP_MAX_INT_NSIDE) {
		ERROR("Error: maximum healpix Nside = %i", HP_MAX_INT_NSIDE);
		return -1;
	}
	if (Nreuses > 255) {
		ERROR("Error, reuse (-r) must be less than 256");
		return -1;
	}

	me->Nside = Nside;
	me->dimquads = dimquads;
	NHP = 12 * Nside * Nside;
	dimcodes = dimquad2dimcode(dimquads);
	quadsize = sizeof(unsigned int) * dimquads;

	logmsg("Nside=%i.  Nside^2=%i.  Number of healpixes=%i.  Healpix side length ~ %g arcmin.\n",
		   me->Nside, me->Nside*me->Nside, NHP, healpix_side_length_arcmin(me->Nside));

	me->sort_data = sort_data;
	me->sort_func = sort_func;
	me->sort_size = sort_size;

	tic();
	me->starkd = starkd;
	N = startree_N(me->starkd);
	logmsg("Star tree contains %i objects.\n", N);

	// get the "HEALPIX" header from the skdt...
	skhp = qfits_header_getint(startree_header(me->starkd), "HEALPIX", -1);
	if (skhp == -1) {
		if (!qfits_header_getboolean(startree_header(me->starkd), "ALLSKY", FALSE)) {
			logmsg("Warning: skdt does not contain \"HEALPIX\" header.  Code and quad files will not contain this header either.\n");
		}
	}
    // likewise "HPNSIDE"
	sknside = qfits_header_getint(startree_header(me->starkd), "HPNSIDE", 1);

    if (sknside && Nside % sknside) {
        logerr("Error: Nside (-n) must be a multiple of the star kdtree healpixelisation: %i\n", sknside);
		return -1;
    }

	if (!scanoccupied && (N*(skhp == -1 ? 1 : sknside*sknside*12) < NHP)) {
		logmsg("\n\n");
		logmsg("NOTE, your star kdtree is sparse (has only a fraction of the stars expected)\n");
		logmsg("  so you probably will get much faster results by setting the \"-E\" command-line\n");
		logmsg("  flag.\n");
		logmsg("\n\n");
	}

	quads->dimquads = me->dimquads;
	codes->dimcodes = dimcodes;
	quads->healpix = skhp;
	codes->healpix = skhp;
	quads->hpnside = sknside;
	codes->hpnside = sknside;
	if (id) {
		quads->indexid = id;
		codes->indexid = id;
	}

	qhdr = quadfile_get_header(quads);
	chdr = codefile_get_header(codes);

	add_headers(qhdr, args, argc, startree_header(me->starkd), circle, passes);
	add_headers(chdr, args, argc, startree_header(me->starkd), circle, passes);

    if (quadfile_write_header(quads)) {
        ERROR("Couldn't write headers to quad file");
		return -1;
    }
    if (codefile_write_header(codes)) {
        ERROR("Couldn't write headers to code file");
		return -1;
    }

    quads->numstars = codes->numstars = N;
	me->quad_dist2_upper = arcmin2distsq(scale_max_arcmin);
	me->quad_dist2_lower = arcmin2distsq(scale_min_arcmin);
    codes->index_scale_upper = quads->index_scale_upper = distsq2rad(me->quad_dist2_upper);
    codes->index_scale_lower = quads->index_scale_lower = distsq2rad(me->quad_dist2_lower);
	
	me->nuses = calloc(N, sizeof(unsigned char));

	// hprad = sqrt(2) * (healpix side length / 2.)
	hprad = arcmin2dist(healpix_side_length_arcmin(Nside)) * M_SQRT1_2;
	quadscale = 0.5 * sqrt(me->quad_dist2_upper);
	// 1.01 for a bit of safety.  we'll look at a few extra stars.
	radius2 = square(1.01 * (hprad + quadscale));
	me->radius2 = radius2;

	logmsg("Healpix radius %g arcsec, quad scale %g arcsec, total %g arcsec\n",
		   distsq2arcsec(hprad*hprad),
		   distsq2arcsec(quadscale*quadscale),
		   distsq2arcsec(radius2));

	hptotry = il_new(1024);

	if (scanoccupied) {
		logmsg("Scanning %i input stars...\n", N);
		for (i=0; i<N; i++) {
			double xyz[3];
			int j;
			if (startree_get(me->starkd, i, xyz)) {
				ERROR("Failed to get star %i", i);
				return -1;
			}
			j = xyzarrtohealpix(xyz, Nside);
			il_insert_unique_ascending(hptotry, j);
			if (log_get_level() > LOG_VERB) {
				double ra,dec;
				if (startree_get_radec(me->starkd, i, &ra, &dec)) {
					ERROR("Failed to get RA,Dec for star %i\n", i);
					return -1;
				}
				logdebug("star %i: RA,Dec %g,%g; xyz %g,%g,%g; hp %i\n",
						 i, ra, dec, xyz[0], xyz[1], xyz[2], j);
			}
		}
		logmsg("Will check %zu healpixes.\n", il_size(hptotry));
		if (log_get_level() > LOG_VERB) {
			logdebug("Checking healpixes: [ ");
			for (i=0; i<il_size(hptotry); i++)
				logdebug("%i ", il_get(hptotry, i));
			logdebug("]\n");
		}

	} else {
		if (skhp == -1) {
			// Try all healpixes.
			il_free(hptotry);
			hptotry = NULL;
			Nhptotry = NHP;
		} else {
			// The star kdtree may itself be healpixed
			int starhp, starx, stary;
			// In that case, the healpixes we are interested in form a rectangle
			// within a big healpix.  These are the coords (in [0, Nside)) of
			// that rectangle.
			int x0, x1, y0, y1;
			int x, y;

			healpix_decompose_xy(skhp, &starhp, &starx, &stary, sknside);
			x0 =  starx    * (Nside / sknside);
			x1 = (starx+1) * (Nside / sknside);
			y0 =  stary    * (Nside / sknside);
			y1 = (stary+1) * (Nside / sknside);

			for (y=y0; y<y1; y++) {
				for (x=x0; x<x1; x++) {
					int j = healpix_compose_xy(starhp, x, y, Nside);
					il_append(hptotry, j);
				}
			}
			assert(il_size(hptotry) == (Nside/sknside) * (Nside/sknside));
		}
	}
	if (hptotry)
		Nhptotry = il_size(hptotry);

	me->quadlist = bl_new(65536, quadsize);

	if (Nloosen)
		me->retryhps = il_new(1024);

	for (pass=0; pass<passes; pass++) {
		char key[64];
		int nthispass;

		logmsg("Pass %i of %i.\n", pass+1, passes);
		logmsg("Trying %i healpixes.\n", Nhptotry);

		nthispass = build_quads(me, Nhptotry, hptotry, Nreuses);

		logmsg("Made %i quads (out of %i healpixes) this pass.\n", nthispass, Nhptotry);
		logmsg("Made %i quads so far.\n", (me->bigquadlist ? bt_size(me->bigquadlist) : 0) + (int)bl_size(me->quadlist));

		sprintf(key, "PASS%i", pass+1);
		fits_header_mod_int(chdr, key, nthispass, "quads created in this pass");
		fits_header_mod_int(qhdr, key, nthispass, "quads created in this pass");

		logmsg("Merging quads...\n");
		if (!me->bigquadlist)
			me->bigquadlist = bt_new(quadsize, 256);
		for (i=0; i<bl_size(me->quadlist); i++) {
			void* q = bl_access(me->quadlist, i);
			bt_insert2(me->bigquadlist, q, FALSE, compare_quads, &me->dimquads);
		}
		bl_remove_all(me->quadlist);
	}

	il_free(hptotry);
	hptotry = NULL;

	if (Nloosen) {
		int R;
		for (R=Nreuses+1; R<=Nloosen; R++) {
			il* trylist;
			int nthispass;

			logmsg("Loosening reuse maximum to %i...\n", R);
			logmsg("Trying %zu healpixes.\n", il_size(me->retryhps));
			if (!il_size(me->retryhps))
				break;

			trylist = me->retryhps;
			me->retryhps = il_new(1024);
			nthispass = build_quads(me, il_size(trylist), trylist, R);
			logmsg("Made %i quads (out of %zu healpixes) this pass.\n", nthispass, il_size(trylist));
			il_free(trylist);
			for (i=0; i<bl_size(me->quadlist); i++) {
				void* q = bl_access(me->quadlist, i);
				bt_insert2(me->bigquadlist, q, FALSE, compare_quads, &me->dimquads);
			}
			bl_remove_all(me->quadlist);
		}
	}
	if (me->retryhps)
		il_free(me->retryhps);

	kdtree_free_query(me->res);
	me->res = NULL;
	me->inds = NULL;
	me->stars = NULL;
	free(me->nuses);
	me->nuses = NULL;

	logmsg("Writing quads...\n");

	// add the quads from the big-quadlist
	nquads = bt_size(me->bigquadlist);
	for (i=0; i<nquads; i++) {
		unsigned int* q = bt_access(me->bigquadlist, i);
		quad_write(codes, quads, q, me->starkd, me->dimquads, dimcodes);
	}
	// add the quads that were made during the final round.
	for (i=0; i<bl_size(me->quadlist); i++) {
		unsigned int* q = bl_access(me->quadlist, i);
		quad_write(codes, quads, q, me->starkd, me->dimquads, dimcodes);
	}

	// fix output file headers.
	if (quadfile_fix_header(quads)) {
		ERROR("Failed to fix quadfile headers");
		return -1;
	}
	if (codefile_fix_header(codes)) {
		ERROR("Failed to fix codefile headers");
		return -1;
	}

	bl_free(me->quadlist);
	bt_free(me->bigquadlist);

	toc();
	logmsg("Done.\n");
	return 0;
}
Exemplo n.º 2
0
int unpermute_quads(quadfile* quadin, codetree* treein,
					quadfile* quadout, codetree** p_treeout,
					char** args, int argc) {
	int i;
	qfits_header* codehdr;
	qfits_header* hdr;
	int healpix;
	int hpnside;
	int codehp = -1;
	qfits_header* qouthdr;
	qfits_header* qinhdr;
	codetree* treeout;
	anbool allsky;

	codehdr = codetree_header(treein);
	healpix = quadin->healpix;
	hpnside = quadin->hpnside;

	allsky = qfits_header_getboolean(codehdr, "ALLSKY", 0);
	if (allsky)
		logverb("Index is all-sky\n");
	else {
		codehp = qfits_header_getint(codehdr, "HEALPIX", -1);
		if (codehp == -1)
			ERROR("Warning, input code kdtree didn't have a HEALPIX header");
		else if (codehp != healpix) {
			ERROR("Quadfile says it's healpix %i, but code kdtree says %i",
				  healpix, codehp);
			return -1;
		}
	}

	quadout->healpix = healpix;
	quadout->hpnside = hpnside;
	quadout->indexid = quadin->indexid;
	quadout->numstars = quadin->numstars;
	quadout->dimquads = quadin->dimquads;
	quadout->index_scale_upper = quadin->index_scale_upper;
	quadout->index_scale_lower = quadin->index_scale_lower;

	qouthdr = quadfile_get_header(quadout);
	qinhdr  = quadfile_get_header(quadin);

	boilerplate_add_fits_headers(qouthdr);
	qfits_header_add(qouthdr, "HISTORY", "This file was created by the program \"unpermute-quads\".", NULL, NULL);
	qfits_header_add(qouthdr, "HISTORY", "unpermute-quads command line:", NULL, NULL);
	fits_add_args(qouthdr, args, argc);
	qfits_header_add(qouthdr, "HISTORY", "(end of unpermute-quads command line)", NULL, NULL);
	qfits_header_add(qouthdr, "HISTORY", "** unpermute-quads: history from input:", NULL, NULL);
	fits_copy_all_headers(qinhdr, qouthdr, "HISTORY");
	qfits_header_add(qouthdr, "HISTORY", "** unpermute-quads end of history from input.", NULL, NULL);
	qfits_header_add(qouthdr, "COMMENT", "** unpermute-quads: comments from input:", NULL, NULL);
	fits_copy_all_headers(qinhdr, qouthdr, "COMMENT");
	qfits_header_add(qouthdr, "COMMENT", "** unpermute-quads: end of comments from input.", NULL, NULL);
	fits_copy_header(qinhdr, qouthdr, "CXDX");
	fits_copy_header(qinhdr, qouthdr, "CXDXLT1");
	fits_copy_header(qinhdr, qouthdr, "CIRCLE");
	fits_copy_header(qinhdr, qouthdr, "ALLSKY");

	if (quadfile_write_header(quadout)) {
		ERROR("Failed to write quadfile header");
		return -1;
	}

	for (i=0; i<codetree_N(treein); i++) {
		unsigned int stars[quadin->dimquads];
		int ind = codetree_get_permuted(treein, i);
		if (quadfile_get_stars(quadin, ind, stars)) {
			ERROR("Failed to read quad entry");
			return -1;
        }
		if (quadfile_write_quad(quadout, stars)) {
			ERROR("Failed to write quad entry");
			return -1;
		}
	}

	if (quadfile_fix_header(quadout)) {
		ERROR("Failed to fix quadfile header");
		return -1;
	}

	treeout = codetree_new();
	treeout->tree = malloc(sizeof(kdtree_t));
	memcpy(treeout->tree, treein->tree, sizeof(kdtree_t));
	treeout->tree->perm = NULL;

	hdr = codetree_header(treeout);
	fits_copy_header(qinhdr, hdr, "HEALPIX");
	fits_copy_header(qinhdr, hdr, "HPNSIDE");
	fits_copy_header(qinhdr, hdr, "ALLSKY");
	boilerplate_add_fits_headers(hdr);
	qfits_header_add(hdr, "HISTORY", "This file was created by the program \"unpermute-quads\".", NULL, NULL);
	qfits_header_add(hdr, "HISTORY", "unpermute-quads command line:", NULL, NULL);
	fits_add_args(hdr, args, argc);
	qfits_header_add(hdr, "HISTORY", "(end of unpermute-quads command line)", NULL, NULL);
	qfits_header_add(hdr, "HISTORY", "** unpermute-quads: history from input ckdt:", NULL, NULL);
	fits_copy_all_headers(codehdr, hdr, "HISTORY");
	qfits_header_add(hdr, "HISTORY", "** unpermute-quads end of history from input ckdt.", NULL, NULL);
	qfits_header_add(hdr, "COMMENT", "** unpermute-quads: comments from input ckdt:", NULL, NULL);
	fits_copy_all_headers(codehdr, hdr, "COMMENT");
	qfits_header_add(hdr, "COMMENT", "** unpermute-quads: end of comments from input ckdt.", NULL, NULL);
	fits_copy_header(codehdr, hdr, "CXDX");
	fits_copy_header(codehdr, hdr, "CXDXLT1");
	fits_copy_header(codehdr, hdr, "CIRCLE");

	*p_treeout = treeout;
	return 0;
}
Exemplo n.º 3
0
int unpermute_stars(startree_t* treein, quadfile_t* qfin,
					startree_t** p_treeout, quadfile_t* qfout,
					anbool dosweeps, anbool check,
					char** args, int argc) {
	startree_t* treeout;
	int i;
	int N;
	int healpix = -1;
    int hpnside = 0;
	int starhp = -1;
	int lastgrass;
	qfits_header* qouthdr;
	qfits_header* qinhdr;
	anbool allsky;

	assert(p_treeout);
	N = startree_N(treein);
	allsky = qfits_header_getboolean(startree_header(treein), "ALLSKY", 0);
	if (allsky)
		logverb("Star kd-tree is all-sky\n");
	else {
		starhp = qfits_header_getint(startree_header(treein), "HEALPIX", -1);
		if (starhp == -1)
			ERROR("Warning, input star kdtree didn't have a HEALPIX header.\n");
		hpnside = qfits_header_getint(startree_header(treein), "HPNSIDE", 1);
		healpix = starhp;
		logverb("Star kd-tree covers healpix %i, nside %i\n", healpix, hpnside);
	}

	qfout->healpix = healpix;
    qfout->hpnside = hpnside;
	qfout->numstars          = qfin->numstars;
	qfout->dimquads          = qfin->dimquads;
	qfout->index_scale_upper = qfin->index_scale_upper;
	qfout->index_scale_lower = qfin->index_scale_lower;
	qfout->indexid           = qfin->indexid;

	qouthdr = quadfile_get_header(qfout);
	qinhdr  = quadfile_get_header(qfin);

	an_fits_copy_header(qinhdr, qouthdr, "ALLSKY");

	BOILERPLATE_ADD_FITS_HEADERS(qouthdr);
	qfits_header_add(qouthdr, "HISTORY", "This file was created by the program \"unpermute-stars\".", NULL, NULL);
	qfits_header_add(qouthdr, "HISTORY", "unpermute-stars command line:", NULL, NULL);
	fits_add_args(qouthdr, args, argc);
	qfits_header_add(qouthdr, "HISTORY", "(end of unpermute-stars command line)", NULL, NULL);
	qfits_header_add(qouthdr, "HISTORY", "** unpermute-stars: history from input:", NULL, NULL);
	fits_copy_all_headers(qinhdr, qouthdr, "HISTORY");
	qfits_header_add(qouthdr, "HISTORY", "** unpermute-stars: end of history from input.", NULL, NULL);
	qfits_header_add(qouthdr, "COMMENT", "** unpermute-stars: comments from input:", NULL, NULL);
	fits_copy_all_headers(qinhdr, qouthdr, "COMMENT");
	qfits_header_add(qouthdr, "COMMENT", "** unpermute-stars: end of comments from input.", NULL, NULL);

	if (quadfile_write_header(qfout)) {
		ERROR("Failed to write quadfile header.\n");
		return -1;
	}

	logmsg("Writing quads...\n");

	startree_compute_inverse_perm(treein);

	if (check) {
		logmsg("Running quadfile_check()...\n");
		if (quadfile_check(qfin)) {
			ERROR("quadfile_check() failed");
			return -1;
		}
		logmsg("Check passed.\n");

		logmsg("Checking inverse permutation...\n");
		if (startree_check_inverse_perm(treein)) {
			ERROR("check failed!");
			return -1;
		}

		logmsg("Running startree kdtree_check()...\n");
		if (kdtree_check(treein->tree)) {
			ERROR("kdtree_check() failed");
			return -1;
		}
		logmsg("Check passed.\n");
	}


	lastgrass = 0;
	for (i=0; i<qfin->numquads; i++) {
		int j;
		unsigned int stars[qfin->dimquads];
		if (i*80/qfin->numquads != lastgrass) {
			logmsg(".");
			fflush(stdout);
			lastgrass = i*80/qfin->numquads;
		}
		if (quadfile_get_stars(qfin, i, stars)) {
			ERROR("Failed to read quadfile entry.\n");
			return -1;
        }
		for (j=0; j<qfin->dimquads; j++)
			stars[j] = treein->inverse_perm[stars[j]];
		if (quadfile_write_quad(qfout, stars)) {
			ERROR("Failed to write quadfile entry.\n");
			return -1;
		}
	}
	logmsg("\n");


	if (quadfile_fix_header(qfout)) {
		ERROR("Failed to fix quadfile header");
		return -1;
	}

	treeout = startree_new();
	treeout->tree = malloc(sizeof(kdtree_t));
	memcpy(treeout->tree, treein->tree, sizeof(kdtree_t));
	treeout->tree->perm = NULL;

	an_fits_copy_header(startree_header(treein), startree_header(treeout), "HEALPIX");
	an_fits_copy_header(startree_header(treein), startree_header(treeout), "HPNSIDE");
	an_fits_copy_header(startree_header(treein), startree_header(treeout), "ALLSKY");
	an_fits_copy_header(startree_header(treein), startree_header(treeout), "JITTER");
	an_fits_copy_header(startree_header(treein), startree_header(treeout), "CUTNSIDE");
	an_fits_copy_header(startree_header(treein), startree_header(treeout), "CUTMARG");
	an_fits_copy_header(startree_header(treein), startree_header(treeout), "CUTBAND");
	an_fits_copy_header(startree_header(treein), startree_header(treeout), "CUTDEDUP");
	an_fits_copy_header(startree_header(treein), startree_header(treeout), "CUTNSWEP");
	an_fits_copy_header(startree_header(treein), startree_header(treeout), "CUTMINMG");
	an_fits_copy_header(startree_header(treein), startree_header(treeout), "CUTMAXMG");

	qfits_header_add(startree_header(treeout), "HISTORY", "unpermute-stars command line:", NULL, NULL);
	fits_add_args(startree_header(treeout), args, argc);
	qfits_header_add(startree_header(treeout), "HISTORY", "(end of unpermute-stars command line)", NULL, NULL);
	qfits_header_add(startree_header(treeout), "HISTORY", "** unpermute-stars: history from input:", NULL, NULL);
	fits_copy_all_headers(startree_header(treein), startree_header(treeout), "HISTORY");
	qfits_header_add(startree_header(treeout), "HISTORY", "** unpermute-stars: end of history from input.", NULL, NULL);
	qfits_header_add(startree_header(treeout), "COMMENT", "** unpermute-stars: comments from input:", NULL, NULL);
	fits_copy_all_headers(startree_header(treein), startree_header(treeout), "COMMENT");
	qfits_header_add(startree_header(treeout), "COMMENT", "** unpermute-stars: end of comments from input.", NULL, NULL);

	if (dosweeps) {
		// copy sweepX headers.
		for (i=1;; i++) {
			char key[16];
			int n;
			sprintf(key, "SWEEP%i", i);
			n = qfits_header_getint(treein->header, key, -1);
			if (n == -1)
				break;
			an_fits_copy_header(treein->header, treeout->header, key);
		}

		// compute sweep array.
		treeout->sweep = malloc(N * sizeof(uint8_t));
		for (i=0; i<N; i++) {
			int ind = treein->tree->perm[i];
			// Stars are sorted first by sweep and then by brightness within
			// the sweep.  Instead of just storing the sweep number, we can
			// store a quantization of the total-ordered rank.
			treeout->sweep[i] = (uint8_t)floor((float)256.0 * (float)ind / (float)N);
		}
	}

	*p_treeout = treeout;
	return 0;
}
Exemplo n.º 4
0
int allquads_open_outputs(allquads_t* aq) {
	int hp, hpnside;
	qfits_header* hdr;

	printf("Reading star kdtree %s ...\n", aq->skdtfn);
	aq->starkd = startree_open(aq->skdtfn);
	if (!aq->starkd) {
		ERROR("Failed to open star kdtree %s\n", aq->skdtfn);
		return -1;
	}
	printf("Star tree contains %i objects.\n", startree_N(aq->starkd));

	printf("Will write to quad file %s and code file %s\n", aq->quadfn, aq->codefn);
    aq->quads = quadfile_open_for_writing(aq->quadfn);
	if (!aq->quads) {
		ERROR("Couldn't open file %s to write quads.\n", aq->quadfn);
		return -1;
	}
    aq->codes = codefile_open_for_writing(aq->codefn);
	if (!aq->codes) {
		ERROR("Couldn't open file %s to write codes.\n", aq->quadfn);
		return -1;
	}

	aq->quads->dimquads = aq->dimquads;
	aq->codes->dimcodes = aq->dimcodes;

	if (aq->id) {
		aq->quads->indexid = aq->id;
		aq->codes->indexid = aq->id;
	}

	// get the "HEALPIX" header from the skdt and put it in the code and quad headers.
	hp = qfits_header_getint(startree_header(aq->starkd), "HEALPIX", -1);
	if (hp == -1) {
		logmsg("Warning: skdt does not contain \"HEALPIX\" header.  Code and quad files will not contain this header either.\n");
	}
	aq->quads->healpix = hp;
	aq->codes->healpix = hp;
    // likewise "HPNSIDE"
	hpnside = qfits_header_getint(startree_header(aq->starkd), "HPNSIDE", 1);
	aq->quads->hpnside = hpnside;
	aq->codes->hpnside = hpnside;

	hdr = quadfile_get_header(aq->quads);
	qfits_header_add(hdr, "CXDX", "T", "All codes have the property cx<=dx.", NULL);
	qfits_header_add(hdr, "CXDXLT1", "T", "All codes have the property cx+dx<=1.", NULL);
	qfits_header_add(hdr, "MIDHALF", "T", "All codes have the property cx+dx<=1.", NULL);
	qfits_header_add(hdr, "CIRCLE", "T", "Codes live in the circle, not the box.", NULL);

	hdr = codefile_get_header(aq->codes);
	qfits_header_add(hdr, "CXDX", "T", "All codes have the property cx<=dx.", NULL);
	qfits_header_add(hdr, "CXDXLT1", "T", "All codes have the property cx+dx<=1.", NULL);
	qfits_header_add(hdr, "MIDHALF", "T", "All codes have the property cx+dx<=1.", NULL);
	qfits_header_add(hdr, "CIRCLE", "T", "Codes live in the circle, not the box.", NULL);

    if (quadfile_write_header(aq->quads)) {
        ERROR("Couldn't write headers to quads file %s\n", aq->quadfn);
		return -1;
    }
    if (codefile_write_header(aq->codes)) {
        ERROR("Couldn't write headers to code file %s\n", aq->codefn);
		return -1;
    }

	if (!aq->use_d2_lower)
		aq->quad_d2_lower = 0.0;
	if (!aq->use_d2_upper)
		aq->quad_d2_upper = 10.0;

    aq->codes->numstars = startree_N(aq->starkd);
    aq->codes->index_scale_upper = distsq2rad(aq->quad_d2_upper);
    aq->codes->index_scale_lower = distsq2rad(aq->quad_d2_lower);

	aq->quads->numstars = aq->codes->numstars;
    aq->quads->index_scale_upper = aq->codes->index_scale_upper;
    aq->quads->index_scale_lower = aq->codes->index_scale_lower;
	return 0;
}