예제 #1
0
파일: PointMesh.py 프로젝트: Zhairang/Donut
    def __init__(self,
                 coordList,
                 gridArray,
                 pointsArray=None,
                 pointsFile=None,
                 myMethod='sbs',
                 methodVal=None,
                 debugFlag=False,
                 title=""):
        """ initialize the class
        """
        self.debugFlag = debugFlag

        self.title = title

        self.nCoord = len(coordList)
        self.coordList = coordList

        # vignetting  HARDCODED
        self.radiusVignetted = 225.0

        # decam info
        self.decam = decaminfo()

        # Array with interpolation grid size and number of points
        # should contain a 4 tuple of [ny,ylo,yhi,nx,xlo,xhi] for each nCoord
        # these ylo,yhi and xlo,xhi should be the region EDGES
        self.gridArray = gridArray.copy()

        # contains an array of Points for each nCoord
        # [npoints,0] is the X value
        # [npoints,1] is the Y value
        # [npoints,2] is the Z value
        # [npoints,3] is the Weight value
        # the arrays are stored in a Python dictionary, keyed by nCoord index
        # NOTE:  nothing in this code enforces that pointArray has this content!!!
        if pointsArray != None:
            self.pointsArray = pointsArray.copy()
        elif pointsFile != None:
            self.readPointsFromFile(pointsFile)
        else:
            print("PointMesh: no input points")

        # construct the interpolation grid for each coordinate system
        self.myMethod = myMethod
        self.methodVal = methodVal
        self.interpPresent = False
        if self.checkMethod(myMethod, methodVal):
            self.interpPresent = True
            self.makeInterpolation(self.myMethod, self.methodVal)
예제 #2
0
    def __init__(self,coordList,gridArray,pointsArray=None,pointsFile=None,myMethod='sbs',methodVal=None,debugFlag=False,title=""):
        """ initialize the class
        """
        self.debugFlag = debugFlag

        self.title = title

        self.nCoord = len(coordList)
        self.coordList = coordList

        # vignetting  HARDCODED
        self.radiusVignetted = 225.0

        # decam info
        self.decam = decaminfo()

        # Array with interpolation grid size and number of points
        # should contain a 4 tuple of [ny,ylo,yhi,nx,xlo,xhi] for each nCoord
        # these ylo,yhi and xlo,xhi should be the region EDGES
        self.gridArray = gridArray.copy()
        
        # contains an array of Points for each nCoord
        # [npoints,0] is the X value
        # [npoints,1] is the Y value
        # [npoints,2] is the Z value
        # [npoints,3] is the Weight value
        # the arrays are stored in a Python dictionary, keyed by nCoord index
        # NOTE:  nothing in this code enforces that pointArray has this content!!!
        if pointsArray!=None:
            self.pointsArray = pointsArray.copy()
        elif pointsFile!=None:
            self.readPointsFromFile(pointsFile)
        else:
            print "PointMesh: no input points"

        # construct the interpolation grid for each coordinate system
        self.myMethod = myMethod
        self.methodVal = methodVal
        self.interpPresent = False
        if self.myMethod=='sbs' or self.myMethod=='rbf' or self.myMethod=='tmean' or self.myMethod=='grid' or self.myMethod == "idw":
            self.interpPresent = True
            self.makeInterpolation(self.myMethod,self.methodVal)
예제 #3
0
def findDonuts(dataAmp, xOffset, inputDict, extName):
    """ find donuts in the data array
    """

    nBlock = inputDict["nBlock"]
    fluxThreshold = inputDict["fluxThreshold"]
    kNNFind = inputDict["kNNFind"]
    distanceLimit = inputDict["distanceLimit"]
    fluxMinCut = inputDict["fluxMinCut"]
    fluxMaxCut = inputDict["fluxMaxCut"]
    npixelsMinCut = inputDict["npixelsMinCut"]
    npixelsMaxCut = inputDict["npixelsMaxCut"]
    nDonutWanted = inputDict[
        "nDonutWanted"] // 2  # divide by 2 for 2 amplifiers
    ellipCut = inputDict["ellipCut"]

    # info about CCDs
    dinfo = decaminfo()

    # time it
    startingTime = time.clock()

    # list for output of donuts
    donutList = []

    # convert from 2048 by 1024 to 128 by 64, by python magic
    dataBlockView = block_view(dataAmp, (nBlock, nBlock))
    dataBlock = dataBlockView.sum(2).sum(2)

    # find sky background and subtract
    skyBkg = calcSky(dataBlock)
    dataBlock = dataBlock - skyBkg

    # zero edge values - they are screwy
    dataBlock[0, :] = 0.0
    dataBlock[-1, :] = 0.0
    dataBlock[:, -1] = 0.0
    dataBlock[:, 0] = 0.0

    # zero pixels lower than the threshold
    dataPeak = numpy.where(dataBlock > fluxThreshold, dataBlock, 0.)

    # keep track of which pixels are above threshold too
    # = 1 is > threshold, =0 is below
    # later we'll use this array to keep track of which pixels
    # aren't in a cluster yet
    dataOn = numpy.where(dataBlock > fluxThreshold, 1, 0)

    # find list of pixels that are non-zero
    nzList = numpy.argwhere(dataPeak).tolist()
    numOverThreshold = len(nzList)

    # build a kdTree to locate nearest neighbors
    kdtree = cKDTree(nzList)

    # also sort the array, the [::-1] is python magic to reverse the order of the array!
    ny, nx = dataPeak.shape
    dataPeakFlat = dataPeak.reshape(ny * nx)
    indSort = numpy.argsort(dataPeakFlat)[::-1]

    # get the sorted indices as a tuple of iy,ix 'es
    ixSort = numpy.mod(indSort, nx).tolist()
    iySort = ((indSort - ixSort) // nx).tolist()
    iyxSort = list(zip(iySort, ixSort))

    # now loop over pixels in sorted order
    # but only look at those above the threshold
    for i in range(numOverThreshold):

        # get the iy,ix tuple
        iyx = iyxSort[i]

        # check that this pixel is still available
        if dataOn[iyx] == 1:

            # try this pixel as the center of a donut
            # find all nearby overthreshold pixels
            d, ind = kdtree.query(iyx,
                                  k=kNNFind,
                                  distance_upper_bound=distanceLimit)

            # get the centroid of these guys, sum the flux
            # looks like we have to loop
            tempX = numpy.zeros(kNNFind)
            tempY = numpy.zeros(kNNFind)
            tempV = numpy.zeros(kNNFind)
            nOk = 0
            nLengthInd = len(ind)
            for i in range(nLengthInd):
                # if we don't find enough neighbors, the others have d==inf and ind=nLength
                if ind[i] < numOverThreshold:
                    iy, ix = nzList[ind[i]]
                    # check that this pixel is still available
                    if dataOn[iy, ix] == 1:
                        nOk = nOk + 1
                        tempY[i] = iy
                        tempX[i] = ix
                        tempV[i] = dataPeak[iy, ix]
                        # remove from dataOn array, so we don't reuse
                        dataOn[iy, ix] = 0

            # now all the neighbors are collected
            # calculate flux and centroid and ellipticity, see if its a good guy!
            if nOk > npixelsMinCut:
                # calculate flux, centroid and moments
                flux = tempV.sum()
                xCentroid = (tempV * tempX).sum() / flux
                yCentroid = (tempV * tempY).sum() / flux
                xDiff = tempX - xCentroid
                yDiff = tempY - yCentroid
                xxMoment = (tempV * xDiff * xDiff).sum() / flux
                yyMoment = (tempV * yDiff * yDiff).sum() / flux
                xyMoment = (tempV * xDiff * yDiff).sum() / flux
                if (xxMoment + yyMoment) > 1.e-10:
                    ellip1 = (xxMoment - yyMoment) / (xxMoment + yyMoment)
                    ellip2 = 2.0 * xyMoment / (xxMoment + yyMoment)
                else:
                    ellip1 = 0.0
                    ellip2 = 0.0

                # check if this guy passes the cuts

                # calculate the pixels
                ixDonut = int(xCentroid * nBlock) + nBlock // 2 + xOffset
                iyDonut = int(yCentroid * nBlock) + nBlock // 2

                # calculate rdecam
                xdecam, ydecam = dinfo.getPosition(extName, ixDonut, iyDonut)
                rdecam = numpy.sqrt(xdecam * xdecam + ydecam * ydecam)

                if nOk < npixelsMaxCut and flux > fluxMinCut and flux < fluxMaxCut and numpy.abs(
                        ellip1) < ellipCut and numpy.abs(
                            ellip2) < ellipCut and rdecam < 225.0:
                    # make output list of Dictionaries
                    # convert x,y to 2048x2048 coordinates
                    info = {"x": ixDonut, "y": iyDonut, "mag": flux}
                    donutList.append(info)
                    if len(donutList) >= nDonutWanted:
                        return donutList

                # clear all guys nearby too


#                for j in range(len(ind)):
#                    if d[j]<3.0*distanceLimit:
#                        iy,ix = nzList[ind[j]]
#                        dataOn[iy,ix] = 0

# Done!
    return donutList
예제 #4
0
파일: donutfit.py 프로젝트: sazabi4/Donut
    def __init__(self, **inputDict):
        # init contains all initializations which are done only once for all fits
        # parameters in fixParamArray1 are nEle,rzero,bkgd,Z2,Z3,Z4,....Z11

        self.paramDict = {
            "nZernikeTerms": 11,
            "nFits": 1,
            "fixedParamArray1":
            [0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1,
             1],  #need defaults up to quadrefoil
            "debugFlag": False,
            "outputWavefront": False,
            "outputDiff": True,
            "outputChi2": False,
            "printLevel": 1,
            "maxIterations": 1000,
            "calcRzeroDerivative": True
        }

        # search for key in inputDict, change defaults
        self.paramDict.update(inputDict)

        # setup the fit engine
        self.gFitFunc = donutengine(**self.paramDict)

        # need dummy versions before calling self.chisq
        self.imgarray = numpy.zeros(1)
        self.weight = numpy.ones(1)
        self.sigmasq = numpy.ones(1)

        # get decam info or desi info
        if self.paramDict["iTelescope"] == 6 or self.paramDict[
                "iTelescope"] == 7 or self.paramDict["iTelescope"] == 8:
            print('This is for DESI CI')
            from donutlib.desiutil import desiciinfo
            self.dInfo = desiciinfo()
        elif self.paramDict["iTelescope"] == 5:
            print('This is for DESI GFA')
            from donutlib.desiutil import desiinfo
            self.dInfo = desiinfo()
        else:
            print('This is for DECam')
            from donutlib.decamutil import decaminfo
            self.dInfo = decaminfo()

        # setup MINUIT
        self.gMinuit = ROOT.TMinuit(self.gFitFunc.npar)
        self.gMinuit.SetFCN(self.chisq)

        # arglist is for the parameters in Minuit commands
        arglist = array('d', 10 * [0.])
        ierflg = ctypes.c_int(1982)  #L ROOT.Long(1982)

        # set the definition of 1sigma
        arglist[0] = 1.0
        self.gMinuit.mnexcm("SET ERR", arglist, 1, ierflg)

        # turn off Warnings
        arglist[0] = 0
        self.gMinuit.mnexcm("SET NOWARNINGS", arglist, 0, ierflg)

        # set printlevel
        arglist[0] = self.paramDict["printLevel"]
        self.gMinuit.mnexcm("SET PRINTOUT", arglist, 1, ierflg)

        # do initial setup of Minuit parameters

        # status/limit arrays for Minuit parameters
        self.startingParam = numpy.zeros(self.gFitFunc.npar)
        self.errorParam = numpy.ones(self.gFitFunc.npar)
        self.loParam = numpy.zeros(self.gFitFunc.npar)
        self.hiParam = numpy.zeros(self.gFitFunc.npar)
        self.paramStatusArray = numpy.zeros(
            self.gFitFunc.npar)  # store =0 Floating, =1 Fixed

        # Set starting values and step sizes for parameters
        # (note that one can redefine the parameters, so this method can be called multiple times)
        for ipar in range(self.gFitFunc.npar):
            self.gMinuit.DefineParameter(ipar, self.gFitFunc.parNames[ipar],
                                         self.startingParam[ipar],
                                         self.errorParam[ipar],
                                         self.loParam[ipar],
                                         self.hiParam[ipar])
예제 #5
0
파일: makedonut.py 프로젝트: safonova/Donut
    def __init__(self, **inputDict):
        """ initialize
        """

        # initialize the parameter Dictionary, and update defaults from inputDict
        self.paramDict = {
            "inputFile": "",
            "wfmFile": "",
            "wfmArray": None,
            "writeToFits": False,
            "outputPrefix": "testone",
            "xDECam": 0.0,
            "yDECam": 0.0,
            "debugFlag": False,
            "rootFlag": False,
            "iTelescope": 0,
            "waveLength": 700.0e-9,
            "nZernikeTerms": 37,
            "nbin": 512,
            "nPixels": 64,
            "gridCalcMode": True,
            "pixelOverSample": 8,
            "scaleFactor": 1.,
            "rzero": 0.125,
            "nEle": 1.0e6,
            "background": 4000.,
            "randomFlag": False,
            "randomSeed":
            209823,  # if this is an invalid integer, crazy errors will ensue
            "gain": 1.0,
            "flipFlag": False,
            "ZernikeArray": []
        }

        self.paramDict.update(inputDict)

        # check parameters are ok
        if self.paramDict["nbin"] != self.paramDict[
                "nPixels"] * self.paramDict["pixelOverSample"]:
            print("makedonut:  nbin must = nPixels * pixelOverSample !!!")
            sys.exit(1)

        # also require that _Lu > 2R, ie. that pupil fits in pupil plane
        # this translates into requiring that (Lambda F / pixelSize) * pixelOverSample * scaleFactor > 1
        # Why does this depend on scaleFactor, but not Z4?? Answer: scaleFactor effectively changes the wavelength, so
        # it must be included.  It is also possible that Z4 is too big for the nPixels - buts that another limit than this one
        F = 2.9  # hardcode for DECam for now
        pixelSize = 15.e-6
        if self.paramDict["pixelOverSample"] * self.paramDict["scaleFactor"] * (
                self.paramDict["waveLength"] * F / pixelSize) < 1.:
            print("makedonut:  ERROR pupil doesn't fit!!!")
            print(
                "            value = ", self.paramDict["pixelOverSample"] *
                self.paramDict["scaleFactor"] *
                (self.paramDict["waveLength"] * F / pixelSize))
            #sys.exit(2)

        # for WFM, need to turn gridCalcMode to False for donutengine
        #if self.paramDict["useWFM"]:
        #    self.paramDict["gridCalcMode"] = False
        #
        # don't do this by default, may need it if Zemax is used, but not if correct bins sizes are used.
        # and it isn't coded with c++ donutengine yet either...

        # declare fit function
        self.gFitFunc = donutengine(**self.paramDict)

        # DECam info
        self.dinfo = decaminfo()

        # set random seed
        numpy.random.seed(self.paramDict["randomSeed"])
예제 #6
0
    def __init__(self,**inputDict):
        # init contains all initializations which are done only once for all fits
        # parameters in fixParamArray1 are nEle,rzero,bkgd,Z2,Z3,Z4,....Z11
        
        self.paramDict = {"nZernikeTerms":11,
                          "nFits":1,
                          "fixedParamArray1":[0,1,0,0,0,0,0,0,0,0,0,0,1,1,1,1,1],  #need defaults up to quadrefoil
                          "debugFlag":False,
                          "outputWavefront":False,
                          "outputDiff":True,
                          "outputChi2":False,
                          "printLevel":1,
                          "maxIterations":1000}

        # search for key in inputDict, change defaults
        self.paramDict.update(inputDict)

        # setup the fit engine
        self.gFitFunc = donutengine(**self.paramDict)
        
        # need dummy versions before calling self.chisq
        self.imgarray = numpy.zeros(1)
        self.weight = numpy.ones(1)
        self.sigmasq = numpy.ones(1)

        # get decam info
        self.decamInfo = decaminfo()

        # setup MINUIT
        self.gMinuit = ROOT.TMinuit(self.gFitFunc.npar)
        self.gMinuit.SetFCN( self.chisq )

        # arglist is for the parameters in Minuit commands
        arglist = array( 'd', 10*[0.] )
        ierflg = ROOT.Long(1982)

        # set the definition of 1sigma 
        arglist[0] = 1.0
        self.gMinuit.mnexcm( "SET ERR", arglist, 1, ierflg )

        # turn off Warnings
        arglist[0] = 0
        self.gMinuit.mnexcm("SET NOWARNINGS", arglist,0,ierflg)

        # set printlevel
        arglist[0] = self.paramDict["printLevel"]
        self.gMinuit.mnexcm("SET PRINTOUT", arglist,1,ierflg)

        # do initial setup of Minuit parameters

        # status/limit arrays for Minuit parameters
        self.startingParam = numpy.zeros(self.gFitFunc.npar)
        self.errorParam = numpy.ones(self.gFitFunc.npar)
        self.loParam = numpy.zeros(self.gFitFunc.npar)
        self.hiParam = numpy.zeros(self.gFitFunc.npar)
        self.paramStatusArray = numpy.zeros(self.gFitFunc.npar)   # store =0 Floating, =1 Fixed

        # Set starting values and step sizes for parameters
        # (note that one can redefine the parameters, so this method can be called multiple times)
        for ipar in range(self.gFitFunc.npar):
            self.gMinuit.DefineParameter(ipar,self.gFitFunc.parNames[ipar],self.startingParam[ipar],self.errorParam[ipar],self.loParam[ipar],self.hiParam[ipar])
예제 #7
0
def findDonuts(dataAmp,xOffset,inputDict,extName):
    """ find donuts in the data array
    """

    nBlock = inputDict["nBlock"]
    fluxThreshold = inputDict["fluxThreshold"]
    kNNFind = inputDict["kNNFind"]
    distanceLimit = inputDict["distanceLimit"]
    fluxMinCut = inputDict["fluxMinCut"]
    fluxMaxCut = inputDict["fluxMaxCut"]
    npixelsMinCut = inputDict["npixelsMinCut"]
    npixelsMaxCut = inputDict["npixelsMaxCut"]
    nDonutWanted = inputDict["nDonutWanted"]/2    # divide by 2 for 2 amplifiers
    ellipCut = inputDict["ellipCut"]

    # info about CCDs
    dinfo = decaminfo()

    # time it
    startingTime = time.clock()

    
    # list for output of donuts
    donutList = []

    # convert from 2048 by 1024 to 128 by 64, by python magic
    dataBlockView = block_view(dataAmp,(nBlock,nBlock))
    dataBlock = dataBlockView.sum(2).sum(2)

    # find sky background and subtract
    skyBkg = calcSky(dataBlock)
    dataBlock = dataBlock - skyBkg

    # zero edge values - they are screwy
    dataBlock[0,:] = 0.0
    dataBlock[-1,:] = 0.0
    dataBlock[:,-1] = 0.0
    dataBlock[:,0] = 0.0

    # zero pixels lower than the threshold
    dataPeak = numpy.where(dataBlock>fluxThreshold,dataBlock,0.)

    # keep track of which pixels are above threshold too
    # = 1 is > threshold, =0 is below
    # later we'll use this array to keep track of which pixels
    # aren't in a cluster yet
    dataOn = numpy.where(dataBlock>fluxThreshold,1,0)
    
    # find list of pixels that are non-zero
    nzList = numpy.argwhere(dataPeak).tolist()
    numOverThreshold = len(nzList)

    # build a kdTree to locate nearest neighbors
    kdtree = cKDTree(nzList)


    # also sort the array, the [::-1] is python magic to reverse the order of the array!
    ny,nx = dataPeak.shape
    dataPeakFlat = dataPeak.reshape(ny*nx)
    indSort = numpy.argsort(dataPeakFlat)[::-1]

    # get the sorted indices as a tuple of iy,ix 'es
    ixSort = numpy.mod(indSort,nx).tolist()
    iySort = ((indSort - ixSort)/nx).tolist()
    iyxSort = zip(iySort,ixSort)

    # now loop over pixels in sorted order
    # but only look at those above the threshold
    for i in range(numOverThreshold):

        # get the iy,ix tuple
        iyx = iyxSort[i]

        # check that this pixel is still available
        if dataOn[iyx]==1:
            
            # try this pixel as the center of a donut
            # find all nearby overthreshold pixels
            d,ind = kdtree.query(iyx,k=kNNFind,distance_upper_bound=distanceLimit)

            # get the centroid of these guys, sum the flux
            # looks like we have to loop
            tempX = numpy.zeros(kNNFind)
            tempY = numpy.zeros(kNNFind)
            tempV = numpy.zeros(kNNFind)
            nOk = 0
            nLengthInd = len(ind)
            for i in range(nLengthInd):            
                # if we don't find enough neighbors, the others have d==inf and ind=nLength
                if ind[i]<numOverThreshold:
                    iy,ix = nzList[ind[i]]
                    # check that this pixel is still available
                    if dataOn[iy,ix] == 1:
                        nOk = nOk + 1
                        tempY[i] = iy
                        tempX[i] = ix
                        tempV[i] = dataPeak[iy,ix]
                        # remove from dataOn array, so we don't reuse
                        dataOn[iy,ix] = 0

            # now all the neighbors are collected
            # calculate flux and centroid and ellipticity, see if its a good guy!
            if nOk>npixelsMinCut:
                # calculate flux, centroid and moments
                flux = tempV.sum()
                xCentroid = (tempV*tempX).sum()/flux
                yCentroid = (tempV*tempY).sum()/flux
                xDiff = tempX - xCentroid
                yDiff = tempY - yCentroid
                xxMoment = (tempV*xDiff*xDiff).sum()/flux
                yyMoment = (tempV*yDiff*yDiff).sum()/flux
                xyMoment = (tempV*xDiff*yDiff).sum()/flux
                if (xxMoment+yyMoment) > 1.e-10:
                    ellip1 = (xxMoment - yyMoment)/(xxMoment + yyMoment)
                    ellip2 = 2.0*xyMoment/(xxMoment+yyMoment)
                else:
                    ellip1 = 0.0
                    ellip2 = 0.0

                # check if this guy passes the cuts

                # calculate the pixels
                ixDonut = int(xCentroid * nBlock) + nBlock/2 + xOffset
                iyDonut = int(yCentroid * nBlock) + nBlock/2 

                # calculate rdecam
                xdecam,ydecam = dinfo.getPosition(extName,ixDonut,iyDonut)
                rdecam = numpy.sqrt(xdecam*xdecam + ydecam*ydecam)
                    
                if nOk<npixelsMaxCut and flux>fluxMinCut and flux<fluxMaxCut and numpy.abs(ellip1)<ellipCut and numpy.abs(ellip2)<ellipCut and rdecam<225.0:
                    # make output list of Dictionaries
                    # convert x,y to 2048x2048 coordinates
                    info = {"x":ixDonut,"y":iyDonut,"mag":flux}
                    donutList.append(info)
                    if len(donutList) >= nDonutWanted:
                        return donutList

                # clear all guys nearby too
#                for j in range(len(ind)):
#                    if d[j]<3.0*distanceLimit:
#                        iy,ix = nzList[ind[j]]
#                        dataOn[iy,ix] = 0

    # Done!
    return donutList
예제 #8
0
    def __init__(self,**inputDict):
        """ initialize
        """

        # initialize the parameter Dictionary, and update defaults from inputDict
        self.paramDict = {"inputFile":"",
                          "wfmFile":"",
                          "wfmArray":None,
                          "writeToFits":False,
                          "outputPrefix":"testone",
                          "xDECam":0.0,
                          "yDECam":0.0,
                          "debugFlag":False,
                          "rootFlag":False,
                          "iTelescope":0,
                          "waveLength":700.0e-9,
                          "nZernikeTerms":37,
                          "nbin":512,
                          "nPixels":64,
                          "gridCalcMode":True,
                          "pixelOverSample":8,
                          "scaleFactor":1.,                 
                          "rzero":0.125,
                          "nEle":1.0e6,
                          "background":4000.,
                          "randomFlag":False,
                          "randomSeed":209823,  # if this is an invalid integer, crazy errors will ensue
                          "gain":1.0,
                          "flipFlag":False,
                          "ZernikeArray":[]}

        self.paramDict.update(inputDict)

        # check parameters are ok
        if self.paramDict["nbin"] != self.paramDict["nPixels"]*self.paramDict["pixelOverSample"]:
            print "makedonut:  nbin must = nPixels * pixelOverSample !!!"
            sys.exit(1)

        # also require that _Lu > 2R, ie. that pupil fits in pupil plane
        # this translates into requiring that (Lambda F / pixelSize) * pixelOverSample * scaleFactor > 1
        # Why does this depend on scaleFactor, but not Z4?? Answer: scaleFactor effectively changes the wavelength, so 
        # it must be included.  It is also possible that Z4 is too big for the nPixels - buts that another limit than this one
        F = 2.9  # hardcode for DECam for now
        pixelSize = 15.e-6 
        if self.paramDict["pixelOverSample"] * self.paramDict["scaleFactor"] * (self.paramDict["waveLength"] * F / pixelSize) < 1. :
            print "makedonut:  ERROR pupil doesn't fit!!!"
            print "            value = ",self.paramDict["pixelOverSample"] * self.paramDict["scaleFactor"] * (self.paramDict["waveLength"] * F / pixelSize)
            #sys.exit(2)

        # for WFM, need to turn gridCalcMode to False for donutengine
        #if self.paramDict["useWFM"]:
        #    self.paramDict["gridCalcMode"] = False
            #
            # don't do this by default, may need it if Zemax is used, but not if correct bins sizes are used.
            # and it isn't coded with c++ donutengine yet either...
            
        # declare fit function
        self.gFitFunc = donutengine(**self.paramDict)

        # DECam info
        self.dinfo = decaminfo()

        # set random seed
        numpy.random.seed(self.paramDict["randomSeed"])