Esempio n. 1
0
LVector LTransform::operator*(const LVector rhs) const
{
    if (_orderIn != rhs.getOrder())
        FormatAndThrow<>()
                << "Order mismatch between LTransform [" << _orderIn
                << "] and LVector [" << rhs.getOrder()
                << "]";
    boost::shared_ptr<tmv::Vector<double> > out(new tmv::Vector<double>(sizeOut()));
    *out = (*_m) * rhs.rVector();
    return LVector(_orderOut, out);
}
Esempio n. 2
0
    void ShapeletFitImage(double sigma, LVector& bvec, const BaseImage<T>& image,
                          double image_scale, const Position<double>& center)
    {
        // TODO: It would be nice to be able to fit this with an arbitrary WCS to fit in
        //       sky coordinates.  For now, just use the image_scale.
        dbg<<"Start ShapeletFitImage:\n";
        xdbg<<"sigma = "<<sigma<<std::endl;
        xdbg<<"bvec = "<<bvec<<std::endl;
        xdbg<<"center = "<<center<<std::endl;
        double scale = image_scale / sigma;
        xdbg<<"scale = "<<scale<<std::endl;
        const int nx = image.getXMax() - image.getXMin() + 1;
        const int ny = image.getYMax() - image.getYMin() + 1;
        xdbg<<"nx,ny = "<<nx<<','<<ny<<std::endl;
        const int npts = nx * ny;
        xdbg<<"npts = "<<npts<<std::endl;
        tmv::Vector<double> x(npts);
        tmv::Vector<double> y(npts);
        tmv::Vector<double> I(npts);
        int i=0;
        for (int ix = image.getXMin(); ix <= image.getXMax(); ++ix) {
            for (int iy = image.getYMin(); iy <= image.getYMax(); ++iy,++i) {
                x[i] = (ix - center.x) * scale;
                y[i] = (iy - center.y) * scale;
                I[i] = image(ix,iy);
            }
        }
        xxdbg<<"x = "<<x<<std::endl;
        xxdbg<<"y = "<<y<<std::endl;
        xxdbg<<"I = "<<I<<std::endl;

        tmv::Matrix<double> psi(npts,bvec.size());
        LVector::basis(x.view(),y.view(),psi.view(),bvec.getOrder(),sigma);
        // I = psi * b
        // TMV solves this by writing b = I/psi.
        // We use QRP in case the psi matrix is close to singular (although it shouldn't be).
        psi.divideUsing(tmv::QRP);
        bvec.rVector() = I/psi;
        xdbg<<"Done FitImage: bvec = "<<bvec<<std::endl;
    }
Esempio n. 3
0
int
main(int argc, 
     char *argv[]) {
    
    // Parameters to set:
    // columns for necessary input:
    int idCol;
    int segIdCol;
    int raCol;
    int decCol;
    int magCol;
    int bgCol;
    int rCol;              // half-light radius (pix)
    int aCol, bCol, paCol; // WC observed ellipse
    int g1Col;
    int g2Col;
    int fwdColStart;
    int fwdColEnd;
    
    // The fit:
    int order;
    double maskSigma;
    
    // Input files
    string fitsName;
    string catName;
    string psfName;
    int    psfOrder;
    string weightName;
    string wcsName;
    string segmentationName;
    int    segmentationPadding;
    
    string weightScaleKey;
    string fluxScaleKey;
    
    // Data properties
    double sky;
    //double rn;
    //double gain;
    int stampSize;
    
    // GL interpolation of missing values
    double maxBadPixels;
    int interpolationOrder;
    double maxBadFlux;
    
    Pset parameters;
    {
	const int def=PsetMember::hasDefault;
	const int low=PsetMember::hasLowerBound;
	const int up=PsetMember::hasUpperBound;
	const int lowopen = low | PsetMember::openLowerBound;
	const int upopen = up | PsetMember::openUpperBound;
	
	parameters.addMemberNoValue("FILES:",0,
				    "Input data");
	parameters.addMember("fitsName", &fitsName, def,
			     "Image FITS file", "set0001.fit");
	parameters.addMember("catName", &catName, def,
			     "Input SExtractor catalog", "set0001.scat");
	parameters.addMember("psfName", &psfName, def,
			     "Input PSFEx file", "model.txt");
	parameters.addMember("psfOrder", &psfOrder, def | low,
			     (std::string("Maximum order of polynomial psf variation used; ")+
			      std::string("-1 for order of PSFEx model")).c_str(), -1, -1);
	parameters.addMember("weightName", &weightName, def, 
			     "Input weight map proportional to inverse variance", "weight.fit");
	parameters.addMember("wcsName", &wcsName, def,
			     "World coordinate header file", "wcs.txt");
	parameters.addMember("weightScaleKey", &weightScaleKey, def,
			     "Scaling factor for weight map (e.g. from Swarp) keyword in WCS header",
			     "WTSCALE");
	// This is the scale that transforms weight proportional to 1/sig^2 to weights EQUAL to 
	// 1/sig^2 of the respective single frame.
	// Note that single frame rescaling is happening on top of this on both the science and 
	// weight frames
	parameters.addMember("fluxScaleKey", &fluxScaleKey, def,
			     "Scaling factor for flux (e.g. from WCS header) keyword in WCS header",
			     "FLXSCALE");
	parameters.addMember("segmentationName", &segmentationName, def,
			     "segmentation map", "segment.fits");
	parameters.addMember("segmentationPadding", &segmentationPadding, def | low,
			     "padding around segmentation maps [pix]", 0, 0);
	parameters.addMember("stampSize", &stampSize, def | low,
			     "Pixel size of img postage stamps", 64, 3);
	
	parameters.addMemberNoValue("DATA PROPERTIES:",0,
				    "Input data");
	parameters.addMember("sky", &sky, def,
			     "sky level", 0.);
	//parameters.addMember("rn", &rn, def | low,
	//		   "Read noise, i.e. RMS at 0 ADU", 1000., 0.);
	//parameters.addMember("gain", &gain, def | low,
	//		   "Gain, e/ADU for Poissson, 0 for no Poisson", 1., 0.);
	
	parameters.addMemberNoValue("FDNT:",0,
				    "Fitting parameters:");
	parameters.addMember("order", &order, def,
			     "FDNT GL-fit order (0 for FFT)", 0);
	parameters.addMember("maskSigma", &maskSigma, def,
			     "GL and FDNT mask sigma (-1 auto)", -1. /*4.*/); // changed 21.11.12
	
	parameters.addMemberNoValue("CATALOG TRANSLATION:",0,
				    "Columns holding input data");
	parameters.addMember("idCol", &idCol, def | low,
			     "Object ID", 1, 1);
	parameters.addMember("segIdCol", &segIdCol, def | low,
			     "Object ID in segmentation map; determined automatically if 0", 1, 0);
	parameters.addMember("raCol", &raCol, def | low,
			     "RA centroid", 2, 1);
	parameters.addMember("decCol", &decCol, def | low,
			     "DEC centroid", 3, 1);
	parameters.addMember("magCol", &magCol, def | low,
			     "Magnitude", 4, 1);
	parameters.addMember("bgCol", &bgCol, def | low,
			     "photometric background flux (zero if bgCol==0)", 5, 0);
	parameters.addMember("rCol", &rCol, def | low,
			     "Half-light radius (in pixels)", 6, 1);
	parameters.addMember("g1Col", &g1Col, def | low,
			     "g1 shape estimate (use native shape if 0)", 7, 0);
	parameters.addMember("g2Col", &g2Col, def | low,
			     "g2 shape estimate (use native shape if 0)", 8, 0);
	parameters.addMember("aCol", &aCol, def | low,
			     "Major axis (in WC)", 7, 1);
	parameters.addMember("bCol", &bCol, def | low,
			     "Minor axis (in WC)", 8, 1);
	parameters.addMember("paCol", &paCol, def | low,
			     "Position angle (in WC)", 9, 1);
	parameters.addMember("fwdColStart", &fwdColStart, def | low,
			     "first forwarded column from input catalog", 0, 1);
	parameters.addMember("fwdColEnd", &fwdColEnd, def | low,
			     "last forwarded column from input catalog", 0, 1);
	parameters.addMember("maxBadPixels", &maxBadPixels, def,
			     "Maximum fraction of bad pixels in postage stamp", 0.1);
	parameters.addMember("maxBadFlux", &maxBadFlux, def,
			     "Maximum fraction of model flux in bad pixels", 0.05);
	parameters.addMember("interpolationOrder", &interpolationOrder, def,
			     "GL order for bad pixel interpolation", 4);
    }
    
    parameters.setDefault();
    
    try {
	for (int i=1; i<argc; i++) {
	    // Open & read all specified input files
	    ifstream ifs(argv[i]);
	    if (!ifs) {
		cerr << "Can't open file " << argv[i] << endl;
		exit(1);
	    }
	    try {
		parameters.setStream(ifs);
	    } catch (std::runtime_error &m) {
		cerr << "In file " << argv[i] << ":" << endl;
		quit(m,1);
	    }
	}
	// ... and from stdin
	try {
	    parameters.setStream(cin);
	} catch (std::runtime_error &m) {
	    cerr << "In stdin:" << endl;
	    quit(m,1);
	}
	
	cerr << "# " << stringstuff::taggedCommandLine(argc, argv) << endl;
	parameters.dump(cerr);
	
	// (1) Read the PSF
	PSFExModel *model;
	try {
	    model = new PSFExModel(psfName.c_str());
	} catch (PSFExError &e) {
	    cerr << "Error reading PSFEx model: " << e.what() << "; exiting." << endl; 
	    exit(1);
	} catch (...) {
	    cerr << "Error reading PSFEx model; exiting." << endl; 
	    exit(1);
	}
	
	if (!model->selfTest(1, 3, psfOrder)) { // this is a very lenient self-test
	    cerr << "PSFEx model did not pass self test; exiting." << endl;
	    exit(1);
	}
	
	cerr << "reading image " << flush;
	// (2) Open image
	Image<> sci;
	FITSImage<> fits(fitsName);
	sci = fits.extract();
        
	cerr << ", header " << flush;
	// (3) Read astrometry
	img::ImageHeader h;
	ifstream mapfs(wcsName.c_str());
	if (!mapfs) {
	    cerr << "Could not open astrometry file " << wcsName 
		 << "; trying FITS header in science frame" << endl;
	    h = *(sci.header());
	}
	else {
	    h = img::HeaderFromStream(mapfs);
	}
	SCAMPMap *fullmap = new SCAMPMap(h,0);
	double xw, yw;
	fullmap->toWorld(0,0,xw,yw);
	
#ifdef DEBUGFDNTPSFEX
	cerr << "# WCS " << xw << " " << yw << " is the (0,0) pixel WC w.r.t. the TP" << endl;
#endif
	
	cerr << ", weight " << flush;
	// (4) Open weight image and read weight scale
	Image<> wt;
	FITSImage<> wtfits(weightName);
	wt = wtfits.extract();
	cerr << "read, " << flush;
	
	HdrRecordBase* weightScaleRecord = h.find(weightScaleKey);
	double weightScale = 1.0;
	if (weightScaleRecord)
	    weightScale = atof(weightScaleRecord->getValueString().c_str());
	else
	    cerr << "WARNING: weight scale key not found in header; assuming weight scale is 1.0\n";
	
	cerr << "SCAMP weight scale: " << weightScale << endl;
	
	HdrRecordBase* fluxScaleRecord = h.find(fluxScaleKey);
	double fluxScale = 1.0;
	if (fluxScaleRecord)
	    fluxScale = atof(fluxScaleRecord->getValueString().c_str());
	else
	    cerr << "WARNING: flux scale key not found in header; assuming flux scale is 1.0\n";
	
	cerr << "SCAMP flux scale: " << fluxScale << endl;
	
	cerr << "reading segmentation map" << endl;
	Image<> seg;
	FITSImage<> fitsseg(segmentationName.c_str());
	seg = fitsseg.extract();
	
	// (5) rescale weight map
	Bounds<int> chip_bounds = sci.getBounds();
	Bounds<int> safe_chip_bounds = chip_bounds;
	safe_chip_bounds.addBorder(-2);
	
	// the inverse variance scales with flux in the following way:
	weightScale = weightScale / (fluxScale*fluxScale); 
	for (int iy=chip_bounds.getYMin(); iy<=chip_bounds.getYMax(); iy++)
	    for (int ix=chip_bounds.getXMin(); ix<=chip_bounds.getXMax(); ix++) {
		// weight map just rescaled sky inverse-variance:
		wt(ix,iy)  = wt(ix,iy) * weightScale;
		sci(ix,iy) = sci(ix,iy) * fluxScale;
	    }    
	
	// initialize sums
	UnweightedShearEstimator se;
	int ngood=0;
	int nfail=0;
	int nfail_post=0;
	int nfail_postmeas=0;
	int nfail_badpix=0;
	int nfail_bpgl=0;
	int nfail_bpff=0;
	int nfail_fdnt=0;
	int nfail_seg=0;
	
	// (6) Loop through objects
	int nread=MAX(idCol, raCol);
	nread = MAX(nread, decCol);
	nread = MAX(nread, segIdCol);
	nread = MAX(nread, rCol);
	nread = MAX(nread, aCol);
	nread = MAX(nread, bCol);
	nread = MAX(nread, paCol);
	nread = MAX(nread, bgCol);
	nread = MAX(nread, g1Col);
	nread = MAX(nread, g2Col);
	nread = MAX(nread, fwdColEnd);
	vector<string> readvals(nread);
	ifstream ccat(catName.c_str());
	if (!ccat) {
	    cerr << "Error opening catalog file " << catName << endl;
	    exit(1);
	}
	string buffer;
	tmv::SymMatrix<double> covE(2);
	
	cout << "# id x_pix y_pix eta1 eta2 sig1 sig2 cov12 mu egFix fdFlags "
	     << "considered_success forwarded_column" << endl;
	
	
	while (stringstuff::getlineNoComment(ccat, buffer)) { // all objects
	    /*
	    cerr << "######################################################" << endl
		 << "// (a) Acquire info of object " << flush;
	    */
	    istringstream iss(buffer);
	    for (int i=0; i<nread; i++) iss >> readvals[i];
	    if (!iss) {
		cerr << "Bad catalog input line: " << buffer;
		exit(1);
	    }
	    string id = readvals[idCol-1];
	    //cerr << id << endl;
	    double ra0 = atof(readvals[raCol-1].c_str());
	    double dec0 = atof(readvals[decCol-1].c_str());
	    double a_wc = atof(readvals[aCol-1].c_str());
	    double b_wc = atof(readvals[bCol-1].c_str());
	    double pa_wc = atof(readvals[paCol-1].c_str());
	    double r_pix = atof(readvals[rCol-1].c_str()); // FLUX_RADIUS in pixels, not wcs
	    double bg = 0.;
	    if (bgCol > 0)
		bg = atof(readvals[bgCol-1].c_str());
	    string fwd = "";
	    if (fwdColStart <= fwdColEnd && fwdColEnd > 0) {
		for (int i=max(1,fwdColStart); i<=fwdColEnd; i++) {
		    fwd += readvals[i-1];
		    fwd += " ";
		}
	    }
	    
	    double x_wc, y_wc; // tangent plane coordinates
	    double x_pix, y_pix;
	    fullmap->toWorld(x_pix, y_pix, x_wc, y_wc);
	    
#ifdef DEBUGFDNTPSFEX
	    cerr << "(a) processing object at (RA,dec)=(" << ra0 << "," << dec0 << ")=(" 
		 << x_wc << "," << y_wc << ") " << "(x,y)=(" << x_pix << "," << y_pix << ")" << endl;
#endif
	    
	    // deproject spherical coordinates to xi (x_wc) and eta (y_wc)
	    SphericalICRS point(ra0*DEGREE, dec0*DEGREE);
	    TangentPlane tp(point, fullmap->projection());
	    tp.getLonLat(x_wc, y_wc);
	    x_wc /= DEGREE;
	    y_wc /= DEGREE;
	    try {
		//cerr << "# object at WCS " << x_wc << " " << y_wc << endl; // DEBUG
		fullmap->toPix(x_wc, y_wc, x_pix, y_pix);
	    }
	    catch  (AstrometryError& e) {
		cerr << e.what() << endl;
		cerr << "(b) processing object at (RA,dec)=(" << ra0 << "," << dec0 << ")" << endl;
		cerr << "toPix failure" << endl;
		exit(0);
	    }
	    
	    if (!safe_chip_bounds.includes(int(x_pix), int(y_pix)))
		continue;

	    cerr << "######################################################" << endl
		 << "// (a) Acquire info of object " << id << endl
		 << "# object at WCS " << x_wc << " " << y_wc << endl; // DEBUG
#ifdef DEBUGFDNTPSFEX
	    cerr << "processing object at (RA,dec)=(" << ra0 << "," << dec0 << ")=(" 
		 << x_wc << "," << y_wc << ") " << "(x,y)=(" << x_pix << "," << y_pix << ")" << endl;
#endif
	    
#ifdef DEBUGFDNTPSFEX
	    cerr << "// (b) get the Jacobian of coordinate transformation at that position" << endl;
#endif
	    Matrix22 J = fullmap->dWorlddPix(x_pix,y_pix);
	    double rescale = sqrt(fabs(J(0,0)*J(1,1)-J(0,1)*J(1,0)));
	    // distorted approximate pixel scale: how much the scales are enlarged by WC transform
	    
#ifdef DEBUGFDNTPSFEX
	    cerr << "rescaling by " << rescale << endl;
	    
	    cerr << "// (c) get PSF model at the position" << endl;
#endif
	    // generate model PSF at this location
	    model->fieldPosition(x_pix, y_pix); // model now holds the psf model at this position
	    cerr << "flux before normalization: " << model->sb()->getFlux() << endl;
	    model->setFlux(1.0);
	    
	    // FWHM is twice the half-light radius for Gaussian psf, scaled to world coords
	    double ee50psf = model->getFWHM()/2.*rescale; 
	    Ellipse psfBasis(0., 0., log(ee50psf/1.17));
	    
	    // generate PSF image in WC
	    SBDistort psfWCS(*(model->sb()),J(0,0),J(0,1),J(1,0),J(1,1));
	    cerr << "dWorld/dPix " << J;  // J comes with its own endl
	    cerr << ee50psf << endl;
	    // sets flux of basis correctly to have flux normalization after distortion
	    psfWCS.setFlux(1.); 
	    
	    double dx = ee50psf / 2.35; // magic 4.7 factor from PSFEx
	    cerr << "drawing psf postage stamp with dx=" << dx << endl;
	    Image<> ipsf = psfWCS.draw(dx);
	    
	    // Measure PSF GL size & significance
	    Image<> psfwt(ipsf.getBounds());
	    psfwt = pow(1e-5/dx, -2.);
	    psfBasis.setMu( psfBasis.getMu() - log(dx));
	    GLSimple<> gl(ipsf, psfwt, psfBasis, 4);
	    if (!gl.solve()) {
		cerr << "# Failed measuring psf, flags " << gl.getFlags() 
		     << "; ignoring object" << endl;
		continue;
	    }
	    psfBasis = gl.getBasis();
	    psfBasis.setMu( psfBasis.getMu() + log(dx));
#ifdef DEBUGFDNTPSFEX
	    cerr << "# PSF e and GL sigma: " << psfBasis.getS()
		 << " " << exp(psfBasis.getMu())
		 << endl;
#endif
	    
	    PSFInformation psfinfo(psfWCS, psfBasis);
	    
#ifdef DEBUGFDNTPSFEX
	    cerr << "// (d) Starting ellipse of galaxy" << endl;
#endif
	    
	    double e1start = (a_wc*a_wc-b_wc*b_wc)/(a_wc*a_wc+b_wc*b_wc);
	    double e2start = e1start * sin(2*pa_wc*PI/180.);
	    e1start *= cos(2*pa_wc*PI/180.);
	    cerr << "SExtractor ellipse r = " << r_pix*rescale << ", e = " << e1start << "," 
		 << e2start << endl;
	    // all in wcs pixel coordinates
	    Ellipse sexE(e1start, e2start, log(r_pix*rescale), x_wc, y_wc); 
	    
	    Shear initShear; 
	    Ellipse initE;
	    double g1_wc;
	    double g2_wc;
	    if (g1Col > 0 && g2Col > 0) {
		// read in g1, g2 (if available)
		g1_wc = atof(readvals[g1Col-1].c_str());
		g2_wc = atof(readvals[g2Col-1].c_str());
		double gabs = sqrt(g1_wc*g1_wc+g2_wc*g2_wc);
		if (gabs > 0.95) {  // sanitize shear
		    g1_wc=g1_wc*0.95/gabs;
		    g2_wc=g2_wc*0.95/gabs;
		}
		initShear.setG1G2(g1_wc, g2_wc); 
		initShear.getE1E2(e1start, e2start);
		initE = Ellipse(e1start, e2start, log(r_pix*rescale), x_wc, y_wc); // all in wcs
	    } else if (g1Col <= 0 && g2Col <= 0) {
		// approximate g1, g2 with native shape (if g1, g2 not available)
		initE = sexE;
	    } else {
		cerr << "g1Col / g2Col specification inconsistent, exiting" << endl;
		exit(2);
	    }
            /*
	    cerr << "starting ellipse r = " << r_pix*rescale 
		 << ", e = " << e1start << ", " << e2start << endl;
	    */	    
	    
#ifdef DEBUGFDNTPSFEX
	    cerr << "// (e) building FitExposure" << endl;
#endif
	    FitExposure<>* fep;
#ifdef DEBUGFDNTPSFEX
	    cerr << "// get the postage stamp" << endl;
#endif
	    int xi0 = x_pix-stampSize/2;
	    if (xi0 < chip_bounds.getXMin()) 
		xi0 = chip_bounds.getXMin();
	    if ((xi0 + stampSize+1) > chip_bounds.getXMax()) 
		xi0 = chip_bounds.getXMax() - stampSize - 1;
	    int yi0 = y_pix-stampSize / 2;
	    if (yi0 < chip_bounds.getYMin()) 
		yi0 = chip_bounds.getYMin();
	    if ((yi0 + stampSize+1) > chip_bounds.getYMax()) 
		yi0 = chip_bounds.getYMax() - stampSize - 1;
#ifdef DEBUGFDNTPSFEX
	    cerr << "// " << xi0 << " " << xi0+stampSize-1 << " " 
		 << yi0 << " " << yi0+stampSize-1 << endl;
	    cerr << "// hopefully inside x=" << chip_bounds.getXMin() 
		 << ".." << chip_bounds.getXMax() 
		 << ", y=" << chip_bounds.getYMin() 
		 << ".." << chip_bounds.getYMax() << endl; 
#endif      
	    Bounds<int> stamp(xi0,xi0+stampSize-1, yi0, yi0+stampSize-1);
	    cerr << "set bounds" << endl;
	    Image<float> scistamp = sci.subimage(stamp).duplicate();
	    cerr << "sci bounds" << endl;
	    Image<float> wtstamp  = wt.subimage(stamp).duplicate();
	    cerr << "wt  bounds" << endl;
	    Image<float> segstamp = seg.subimage(stamp).duplicate();
	    cerr << "seg bounds" << endl;
	    Image<double> xwstamp(stamp);
	    Image<double> ywstamp(stamp);
	    int segId = 0;
	    if (segIdCol > 0) 
		segId = atoi(readvals[segIdCol-1].c_str());
	    else {
		bool badSegID=false;
		// check a small square region
		for (int dx=0; dx<=1; dx++) {
		    for (int dy=0; dy<=1; dy++) {
			//cerr << int(x_pix) + dx << " " << int(y_pix) + dy << endl;
			int dsegId = seg(int(x_pix)+dx, int(y_pix)+dy);
			if (!segId && dsegId) {
			    segId = dsegId;
			}
			else if (dsegId && segId!=dsegId) {
			    badSegID = true;
			}
		    }
		}
		
		if (badSegID) {
		    cerr << "# fail: could not get segmentation id for " << id << endl;
#ifdef CHECKPLOTS
		    ipsf.shift(1,1);
		    FITSImage<>::writeToFITS("check_"+id+"_psf_badseg.fits",ipsf);
		    wtstamp.shift(1,1);
		    FITSImage<>::writeToFITS("check_"+id+"_wt_badseg.fits",wtstamp);
		    scistamp.shift(1,1);
		    FITSImage<>::writeToFITS("check_"+id+"_sci_badseg.fits",scistamp);
		    segstamp.shift(1,1);
		    FITSImage<>::writeToFITS("check_"+id+"_seg_badseg.fits",segstamp);
#endif
		    nfail++;
		    nfail_seg++;
		    continue; 
		}
	    }
	    
	    cerr << "got segid" << endl;
	    try {
		for (int iy=stamp.getYMin(); iy<=stamp.getYMax(); iy++)
		{
		    for (int ix=stamp.getXMin(); ix<=stamp.getXMax(); ix++) {
			double dxw,dyw;
			fullmap->toWorld(ix,iy,dxw,dyw);
			xwstamp(ix,iy) = dxw;
			ywstamp(ix,iy) = dyw;
			if (segstamp(ix,iy) && segstamp(ix,iy)!=segId) { //it's another object!
			    for (int iiy=max(stamp.getYMin(),iy-segmentationPadding); 
				 iiy<=min(stamp.getYMax(),iy+segmentationPadding); iiy++) 
				for (int iix=max(stamp.getXMin(),ix-segmentationPadding); 
				     iix<=min(stamp.getXMax(),ix+segmentationPadding); iix++) 
				    wtstamp(iix,iiy)=0.;
			}
		    }
		}
		fep = new FitExposure<>(scistamp, 
					wtstamp, 
					xwstamp, 
					ywstamp, 0, sky+bg); 
		// stack background with sky-subtracted single frames == 
		// photometric local background in stack flux scale 
	    }
	    catch (...)
	    {
		cerr << "# fail: could not get postage stamp for " << id << endl;
		nfail++;
		nfail_post++;
		delete fep;
		continue;
	    }

#ifdef DEBUGFDNTPSFEX
	    cerr << "// (f) checking bad pixels" << endl;
#endif
	    double meanweight=0.;
	    vector< Position<int> > bp = fep->badPixels(meanweight);
	    cerr << "mean weight: " << meanweight << endl;
	    if (bp.size()>maxBadPixels*stampSize*stampSize) {
		cerr << "# fail: " << id << " has too many bad pixels" << endl;
#ifdef CHECKPLOTS
		ipsf.shift(1,1);
		FITSImage<>::writeToFITS("check_"+id+"_psf_badpix.fits",ipsf);
		wtstamp.shift(1,1);
		FITSImage<>::writeToFITS("check_"+id+"_wt_badpix.fits",wtstamp);
		scistamp.shift(1,1);
		FITSImage<>::writeToFITS("check_"+id+"_sci_badpix.fits",scistamp);
		segstamp.shift(1,1);
		FITSImage<>::writeToFITS("check_"+id+"_seg_badpix.fits",segstamp);
#endif
		nfail++;
		nfail_badpix++;
		delete fep;
		continue;
	    }
#ifdef DEBUGFDNTPSFEX
	    // residual image (science image with the GL model subtracted)
	    Image<float> glstamp = sci.subimage(stamp).duplicate(); 
#endif
	    
	    // has bad pixels, but not too many to begin with: do GL interpolation
	    if (bp.size() > 0) {
#ifdef DEBUGFDNTPSFEX
		cerr << "# trying to interpolate " << bp.size() << " bad pixels" << endl;
		cerr << sexE << " " <<  interpolationOrder << endl;
#endif
		GLSimple<> gal(*fep, sexE, interpolationOrder); 
		if (!gal.solve()) {
		    cerr << "# fail: GL fit failed for " << id << endl;
#ifdef CHECKPLOTS
		    ipsf.shift(1,1);
		    FITSImage<>::writeToFITS("check_"+id+"_psf_bpgl.fits",ipsf);
		    wtstamp.shift(1,1);
		    FITSImage<>::writeToFITS("check_"+id+"_wt_bpgl.fits",wtstamp);
		    scistamp.shift(1,1);
		    FITSImage<>::writeToFITS("check_"+id+"_sci_bpgl.fits",scistamp);
		    segstamp.shift(1,1);
		    FITSImage<>::writeToFITS("check_"+id+"_seg_bpgl.fits",segstamp);
#endif
		    nfail++;
		    nfail_bpgl++;
		    delete fep;
		    continue;
		}
		LVector bvec = gal.getB();
		double fluxModel = bvec.flux();
		Ellipse basis = gal.getBasis();
		double missingFlux=0.;
		double scaleFactor = exp(basis.getMu());
		
		for (vector< Position<int> >::iterator it=bp.begin(); it<bp.end(); it++) {
		    LVector psi(bvec.getOrder());
		    Position<double> xunit = 
			basis.inv(Position<double>(xwstamp((*it).x,(*it).y),
						   ywstamp((*it).x,(*it).y)));
		    psi.fillBasis(xunit.x, xunit.y, scaleFactor);
		    scistamp((*it).x,(*it).y)=bvec.dot(psi);
		    wtstamp((*it).x,(*it).y)=meanweight;
		    // The interpolated pixel is assumed to have the mean weight of the good pixels;
		    // this makes sense because in the Fourier code homogeneous uncertainties are 
		    // assumed
		    missingFlux += scistamp((*it).x,(*it).y);
		    scistamp((*it).x,(*it).y)+=sky+bg;
		}
		missingFlux *= rescale*rescale; // scale flux with coordinate system
		
#ifdef DEBUGFDNTPSFEX
		for (int iy=stamp.getYMin(); iy<=stamp.getYMax(); iy++) {
		    for (int ix=stamp.getXMin(); ix<=stamp.getXMax(); ix++) {
			LVector psi(bvec.getOrder());
			Position<double> xunit = 
			    basis.inv(Position<double>(xwstamp(ix,iy), ywstamp(ix,iy)));
			psi.fillBasis(xunit.x, xunit.y, scaleFactor);
			glstamp(ix,iy) -= bvec.dot(psi);   
		    }
		}
		
		cerr << "# fluxModel = " << fluxModel << endl;
		cerr << "# scaleFactor = " << scaleFactor << endl;
		cerr << "# missingFlux = " << missingFlux << endl;
#endif
		
		if (missingFlux/fluxModel > maxBadFlux) {
		    cerr << "# fail: bad pixels in " << id << " have too high flux fraction" << endl;
#ifdef CHECKPLOTS
		    ipsf.shift(1,1);
		    FITSImage<>::writeToFITS("check_"+id+"_psf_bpff.fits",ipsf);
		    wtstamp.shift(1,1);
		    FITSImage<>::writeToFITS("check_"+id+"_wt_bpff.fits",wtstamp);
		    scistamp.shift(1,1);
		    FITSImage<>::writeToFITS("check_"+id+"_sci_bpff.fits",scistamp);
		    segstamp.shift(1,1);
		    FITSImage<>::writeToFITS("check_"+id+"_seg_bpff.fits",segstamp);
		    glstamp.shift(1,1);
		    FITSImage<>::writeToFITS("check_"+id+"_glr_bpff.fits",glstamp);
#endif
		    nfail++;
		    nfail_bpff++;
		    delete fep;
		    continue;
		}
	    }
	    
#ifdef DEBUGFDNTPSFEX      
	    cerr << "// (g) running FDNT..." << flush;
#endif
	    FDNT<> fd(*fep, psfinfo, initE, order);
	    fd.setMaskSigma(maskSigma);
	    fd.GLAll();
	    bool success = fd.prepare();
	    if (success)
		cerr << " success!" << endl;
	    else
		cerr << " failed." << endl;
	    
	    
#ifdef DEBUGFDNTPSFEX
	    cerr << "// (h) evaluating FDNT" << endl;
#endif    
	    Shear targetS = fd.getBasis().getS();
	    cerr << targetS << endl;
	    double prob;
	    tmv::SymMatrix<double> covE(2,2);
	    if (success) {
		cerr << "making the actual measurement" << endl;
		try {
		    targetS = fd.shape2(prob, covE);  // THIS IS THE ACTUAL MEASUREMENT!!
		}
		catch (...) {
		    cerr << "an error occurred" << endl; 
		}
		cerr << "made the actual measurement" << endl;
		// ??? Make flag mask an input parameter ???
		success = !(fd.getFlags() & (DidNotConverge + Singularity
					     + OutOfBounds + TooLarge + UnderSampled
					     + TooElliptical + GLFailure));
	    }
	    
	    double eta1, eta2;
	    targetS.getEta1Eta2(eta1, eta2);
	    double egFix = 0.;
	    double sig1 = 0., sig2 = 0.;
	    double cov12 = 0.;
	    if (success) {
		try {
		    egFix = fd.shrinkResponse(targetS);
		    cerr << "got shrink response" << endl;
		    sig1 = sqrt(covE(0,0));
		    sig2 = sqrt(covE(1,1));
		    cov12 = covE(0,1);
		    se.add(targetS, egFix, sig1, sig2);
		    cerr << "good " << targetS << " " << egFix << " " << sig1 << " " << sig2 << endl;
		    ngood++;
		}
		catch (...)
		{
		    cerr << "an error occured on previously successful measurement" << endl;
		    nfail++;
		    nfail_postmeas++;
		    success=false;
		}
#ifdef CHECKPLOTS
		ipsf.shift(1,1);
		FITSImage<>::writeToFITS("check_"+id+"_psf_good.fits",ipsf);
		wtstamp.shift(1,1);
		FITSImage<>::writeToFITS("check_"+id+"_wt_good.fits",wtstamp);
		scistamp.shift(1,1);
		FITSImage<>::writeToFITS("check_"+id+"_sci_good.fits",scistamp);
		segstamp.shift(1,1);
		FITSImage<>::writeToFITS("check_"+id+"_seg_good.fits",segstamp);
		Image<> filter1 = fd.drawFilter1(targetS,initE);
		Image<> filter2 = fd.drawFilter2(targetS,initE);
		filter1.shift(1,1);
		FITSImage<>::writeToFITS("check_"+id+"_f1_good.fits",filter1);
		filter2.shift(1,1);
		FITSImage<>::writeToFITS("check_"+id+"_f2_good.fits",filter2);
		if (bp.size()>0) {
		    glstamp.shift(1,1);
		    FITSImage<>::writeToFITS("check_"+id+"_glr_good.fits",glstamp);
		}
#endif
	    } else {
		cerr << "# fail: some obscure thing in FDNT::prepare() happens for " << id 
		     << ", flags " << fd.getFlags() << endl;
		stringstream flags; 
		flags << fd.getFlags();	
#ifdef CHECKPLOTS
		ipsf.shift(1,1);
		FITSImage<>::writeToFITS("check_"+id+"_psf_fdnt_"+flags.str()+".fits",ipsf);
		wtstamp.shift(1,1);
		FITSImage<>::writeToFITS("check_"+id+"_wt_fdnt_"+flags.str()+".fits",wtstamp);
		scistamp.shift(1,1);
		FITSImage<>::writeToFITS("check_"+id+"_sci_fdnt_"+flags.str()+".fits",scistamp);
		segstamp.shift(1,1);
		FITSImage<>::writeToFITS("check_"+id+"_seg_fdnt_"+flags.str()+".fits",segstamp);
		if (bp.size()>0) {
		    glstamp.shift(1,1);
		    FITSImage<>::writeToFITS("check_"+id+"_glr_fdnt_"+flags.str()+".fits",glstamp);
		}
#endif
		
		nfail++;
		nfail_fdnt++;
	    }
	    double mu = fd.getBasis().getMu();
	    cout << id 
		 << " " << ra0
		 << " " << dec0
		 << " " << x_pix
		 << " " << y_pix 
		//<< " " << mag 
		 << " " << eta1 
		 << " " << eta2
		 << " " << sig1
		 << " " << sig2
		 << " " << cov12
		 << " " << mu
		 << " " << egFix
		 << " " << fd.getFlags()
		 << " " << success
		 << " " << fwd
		 << endl;
	    
	    delete fep;
	}
	
	delete model;
	delete fullmap;
	
	// Print out mean shear estimate
	Shear S(se);
	double g1, g2, sig1, sig2;
	S.getG1G2(g1,g2);
	se.sigmaE(sig1,sig2, false);
	
	cout << fixed << setprecision(6);
	// Approximate the reduced-shear error as 1/2 of the distortion error
	cout << "# Means: " << g1 << " +- " << sig1/2
	     << " " << g2 << " +- " << sig2/2
	     << endl;
	cout << "# Failed / good " << nfail << " / " << ngood << endl;
	cout << "# Reasons for failure:\n# " << nfail_post 
	     << "\t couldn't get postage stamp\n# " 
	     << nfail_badpix << "\t had too many bad pixels\n# " 
	     << nfail_bpgl << "\t couldn't GL-interpolate bad pixels\n# " 
	     << nfail_bpff << "\t had too much flux in bad pixels\n# " 
	     << nfail_postmeas << "\t failed after measurement\n# "  
	     << nfail_fdnt << "\t had some error in FDNT\n# " 
	     << nfail_seg << "\t had ambiguous segmentation information\n"<< endl;
    } catch (std::runtime_error &m) {
	cerr << m.what() << endl;
	quit(m,1);
    }
}