Beispiel #1
0
    def setUpClass(cls):
        cls.psf = load_psf(resource_filename("specter.test", "t/psf-spot.fits"))

        np.random.seed(0)
        nspec = 10
        wmin = min(cls.psf.wavelength(0, y=0), cls.psf.wavelength(nspec-1, y=0))
        ### ww = psf.wavelength(0, y=np.arange(10,60))
        wmin, wmax = cls.psf.wavelength(0, y=(10,50))
        ww = np.arange(wmin, wmax, 0.5)
        nwave = len(ww)

        phot_shape = (nspec, nwave)
        phot = np.random.uniform(1, 1000, size=phot_shape)
        image_orig = cls.psf.project(ww, phot, verbose=False)
        var = 1.0 + image_orig
        image = image_orig + np.random.normal(scale=np.sqrt(var))

        cls.phot = phot
        cls.image_orig = image_orig
        cls.image = image
        cls.ivar = 1.0 / var
        cls.ww = ww
        cls.nspec = nspec

        # construct a symmetric test matrix
        cls.dim = 100
        cls.a1 = np.random.uniform(low=0.01, high=100.0, size=(cls.dim, cls.dim))
        cls.a2 = np.random.uniform(low=0.01, high=100.0, size=(cls.dim, cls.dim))
        cls.sym = np.dot(np.transpose(cls.a1), cls.a1)
        cls.sym += np.dot(np.transpose(cls.a2), cls.a2)
Beispiel #2
0
    def setUpClass(self):
        np.random.seed(0)
        psf = load_psf(test_data_dir() + "/psf-spot.fits")

        nspec = 10
        wmin = min(psf.wavelength(0, y=0), psf.wavelength(nspec-1, y=0))
        ### ww = psf.wavelength(0, y=np.arange(10,60))
        wmin, wmax = psf.wavelength(0, y=(10,50))
        ww = np.arange(wmin, wmax, 0.5)
        nwave = len(ww)
        
        phot_shape = (nspec, nwave)
        phot = np.random.uniform(1, 1000, size=phot_shape)
        image_orig = psf.project(ww, phot, verbose=False)
        var = 1.0 + image_orig
        image = image_orig + np.random.normal(scale=np.sqrt(var))
                
        self.phot = phot
        self.image_orig = image_orig
        self.image = image
        self.ivar = 1.0 / var
        self.psf = psf        
        self.ww = ww
        self.nspec = nspec

        # construct a symmetric test matrix
        self.dim = 100
        self.a1 = np.random.uniform(low=0.01, high=100.0, size=(self.dim, self.dim))
        self.a2 = np.random.uniform(low=0.01, high=100.0, size=(self.dim, self.dim))
        self.sym = np.dot(np.transpose(self.a1), self.a1)
        self.sym += np.dot(np.transpose(self.a2), self.a2)
Beispiel #3
0
    def setUpClass(cls):
        cls.psf = load_psf(resource_filename("specter.test",
                                             "t/psf-spot.fits"))

        np.random.seed(0)
        nspec = 10
        ### wmin = min(cls.psf.wavelength(0, y=0), cls.psf.wavelength(nspec-1, y=0))
        ### ww = psf.wavelength(0, y=np.arange(10,60))
        wmin, wmax = cls.psf.wavelength(0, y=(10, 90))
        ww = np.arange(wmin, wmax, 1.0)
        nwave = len(ww)

        phot_shape = (nspec, nwave)
        phot = np.random.uniform(1, 1000, size=phot_shape)
        image_orig = cls.psf.project(ww, phot, verbose=False)
        var = 1.0 + image_orig
        image = image_orig + np.random.normal(scale=np.sqrt(var))

        cls.phot = phot
        cls.image_orig = image_orig
        cls.image = image
        cls.ivar = 1.0 / var
        cls.ww = ww
        cls.nspec = nspec

        # construct a symmetric test matrix
        cls.dim = 100
        cls.a1 = np.random.uniform(low=0.01,
                                   high=100.0,
                                   size=(cls.dim, cls.dim))
        cls.a2 = np.random.uniform(low=0.01,
                                   high=100.0,
                                   size=(cls.dim, cls.dim))
        cls.sym = np.dot(np.transpose(cls.a1), cls.a1)
        cls.sym += np.dot(np.transpose(cls.a2), cls.a2)
Beispiel #4
0
 def test_psfbias(self):
     psf = load_psf(resource_filename('specter.test', "t/psf-pix.fits"))
     wmid = 0.5*(psf.wmin+psf.wmax)
     ww = np.linspace(wmid-10, wmid+10)
     phot = np.ones(len(ww))
     phot[10] = 20
     bias = util.psfbias(psf, psf, ww, phot)
     absbias, R = util.psfabsbias(psf, psf, ww, phot)
Beispiel #5
0
 def test_psfbias(self):
     psf = load_psf(resource_filename('specter.test', "t/psf-pix.fits"))
     wmid = 0.5 * (psf.wmin + psf.wmax)
     ww = np.linspace(wmid - 10, wmid + 10)
     phot = np.ones(len(ww))
     phot[10] = 20
     bias = util.psfbias(psf, psf, ww, phot)
     absbias, R = util.psfabsbias(psf, psf, ww, phot)
Beispiel #6
0
 def test_psfbias(self):
     psf = load_psf(test_data_dir() + "/psf-pix.fits")
     wmid = 0.5*(psf.wmin+psf.wmax)
     ww = np.linspace(wmid-10, wmid+10)
     phot = np.ones(len(ww))
     phot[10] = 20
     bias = util.psfbias(psf, psf, ww, phot)
     absbias, R = util.psfabsbias(psf, psf, ww, phot)
Beispiel #7
0
    def test_boxcar(self):
        from lvmspec.boxcar import do_boxcar
        psf = load_psf(self.psffile)

        pix = np.random.normal(0, 3.0, size=(psf.npix_y, psf.npix_x))
        ivar = np.ones_like(pix) / 3.0**2
        mask = np.zeros(pix.shape, dtype=np.uint32)
        img = lvmspec.image.Image(pix, ivar, mask, camera='z0')

        outwave = np.arange(7500, 7600)
        nwave = len(outwave)
        nspec = 5
        flux, ivar, resolution = do_boxcar(img,
                                           psf,
                                           outwave,
                                           boxwidth=2.5,
                                           nspec=nspec)

        self.assertEqual(flux.shape, (nspec, nwave))
        self.assertEqual(ivar.shape, (nspec, nwave))
        self.assertEqual(resolution.shape[0], nspec)
        # resolution.shape[1] is number of diagonals; picked by algorithm
        self.assertEqual(resolution.shape[2], nwave)
Beispiel #8
0
def main_mpi(args, comm=None):

    log = get_logger()

    psf_file = args.psf
    input_file = args.input

    # these parameters are interpreted as the *global* spec range,
    # to be divided among processes.
    specmin = args.specmin
    nspec = args.nspec

    #- Load input files and broadcast

    # FIXME: after we have fixed the serialization
    # of the PSF, read and broadcast here, to reduce
    # disk contention.

    img = None
    if comm is None:
        img = io.read_image(input_file)
    else:
        if comm.rank == 0:
            img = io.read_image(input_file)
        img = comm.bcast(img, root=0)

    psf = load_psf(psf_file)

    # get spectral range

    if nspec is None:
        nspec = psf.nspec
    specmax = specmin + nspec

    camera = img.meta['CAMERA'].lower()  #- b0, r1, .. z9
    spectrograph = int(camera[1])
    fibermin = spectrograph * psf.nspec + specmin

    if args.fibermap is not None:
        fibermap = io.read_fibermap(args.fibermap)
        fibermap = fibermap[fibermin:fibermin + nspec]
        fibers = fibermap['FIBER']
    else:
        fibermap = None
        fibers = np.arange(fibermin, fibermin + nspec, dtype='i4')

    #- Get wavelength grid from options

    if args.wavelength is not None:
        wstart, wstop, dw = [float(tmp) for tmp in args.wavelength.split(',')]
    else:
        wstart = np.ceil(psf.wmin_all)
        wstop = np.floor(psf.wmax_all)
        dw = 0.5

    wave = np.arange(wstart, wstop + dw / 2.0, dw)
    nwave = len(wave)

    #- Confirm that this PSF covers these wavelengths for these spectra

    psf_wavemin = np.max(psf.wavelength(list(range(specmin, specmax)), y=0))
    psf_wavemax = np.min(
        psf.wavelength(list(range(specmin, specmax)), y=psf.npix_y - 1))
    if psf_wavemin > wstart:
        raise ValueError(
            'Start wavelength {:.2f} < min wavelength {:.2f} for these fibers'.
            format(wstart, psf_wavemin))
    if psf_wavemax < wstop:
        raise ValueError(
            'Stop wavelength {:.2f} > max wavelength {:.2f} for these fibers'.
            format(wstop, psf_wavemax))

    # Now we divide our spectra into bundles

    bundlesize = args.bundlesize
    checkbundles = set()
    checkbundles.update(
        np.floor_divide(np.arange(specmin, specmax),
                        bundlesize * np.ones(nspec)).astype(int))
    bundles = sorted(checkbundles)
    nbundle = len(bundles)

    bspecmin = {}
    bnspec = {}
    for b in bundles:
        if specmin > b * bundlesize:
            bspecmin[b] = specmin
        else:
            bspecmin[b] = b * bundlesize
        if (b + 1) * bundlesize > specmax:
            bnspec[b] = specmax - bspecmin[b]
        else:
            bnspec[b] = bundlesize

    # Now we assign bundles to processes

    nproc = 1
    rank = 0
    if comm is not None:
        nproc = comm.size
        rank = comm.rank

    mynbundle = int(nbundle // nproc)
    myfirstbundle = 0
    leftover = nbundle % nproc
    if rank < leftover:
        mynbundle += 1
        myfirstbundle = rank * mynbundle
    else:
        myfirstbundle = ((mynbundle + 1) * leftover) + (mynbundle *
                                                        (rank - leftover))

    if rank == 0:
        #- Print parameters
        log.info("extract:  input = {}".format(input_file))
        log.info("extract:  psf = {}".format(psf_file))
        log.info("extract:  specmin = {}".format(specmin))
        log.info("extract:  nspec = {}".format(nspec))
        log.info("extract:  wavelength = {},{},{}".format(wstart, wstop, dw))
        log.info("extract:  nwavestep = {}".format(args.nwavestep))
        log.info("extract:  regularize = {}".format(args.regularize))

    # get the root output file

    outpat = re.compile(r'(.*)\.fits')
    outmat = outpat.match(args.output)
    if outmat is None:
        raise RuntimeError(
            "extraction output file should have .fits extension")
    outroot = outmat.group(1)

    outdir = os.path.normpath(os.path.dirname(outroot))
    if rank == 0:
        if not os.path.isdir(outdir):
            os.makedirs(outdir)

    if comm is not None:
        comm.barrier()

    failcount = 0

    for b in range(myfirstbundle, myfirstbundle + mynbundle):
        outbundle = "{}_{:02d}.fits".format(outroot, b)
        outmodel = "{}_model_{:02d}.fits".format(outroot, b)

        log.info('extract:  Rank {} starting {} spectra {}:{} at {}'.format(
            rank,
            os.path.basename(input_file),
            bspecmin[b],
            bspecmin[b] + bnspec[b],
            time.asctime(),
        ))
        sys.stdout.flush()

        #- The actual extraction
        try:
            results = ex2d(img.pix,
                           img.ivar * (img.mask == 0),
                           psf,
                           bspecmin[b],
                           bnspec[b],
                           wave,
                           regularize=args.regularize,
                           ndecorr=True,
                           bundlesize=bundlesize,
                           wavesize=args.nwavestep,
                           verbose=args.verbose,
                           full_output=True)

            flux = results['flux']
            ivar = results['ivar']
            Rdata = results['resolution_data']
            chi2pix = results['chi2pix']

            mask = np.zeros(flux.shape, dtype=np.uint32)
            mask[results['pixmask_fraction'] > 0.5] |= specmask.SOMEBADPIX
            mask[results['pixmask_fraction'] == 1.0] |= specmask.ALLBADPIX
            mask[chi2pix > 100.0] |= specmask.BAD2DFIT

            #- Augment input image header for output
            img.meta['NSPEC'] = (nspec, 'Number of spectra')
            img.meta['WAVEMIN'] = (wstart, 'First wavelength [Angstroms]')
            img.meta['WAVEMAX'] = (wstop, 'Last wavelength [Angstroms]')
            img.meta['WAVESTEP'] = (dw, 'Wavelength step size [Angstroms]')
            img.meta['SPECTER'] = (specter.__version__,
                                   'https://github.com/desihub/specter')
            img.meta['IN_PSF'] = (_trim(psf_file), 'Input spectral PSF')
            img.meta['IN_IMG'] = (_trim(input_file), 'Input image')

            if fibermap is not None:
                bfibermap = fibermap[bspecmin[b] - specmin:bspecmin[b] +
                                     bnspec[b] - specmin]
            else:
                bfibermap = None

            bfibers = fibers[bspecmin[b] - specmin:bspecmin[b] + bnspec[b] -
                             specmin]

            frame = Frame(wave,
                          flux,
                          ivar,
                          mask=mask,
                          resolution_data=Rdata,
                          fibers=bfibers,
                          meta=img.meta,
                          fibermap=bfibermap,
                          chi2pix=chi2pix)

            #- Write output
            io.write_frame(outbundle, frame, units='photon/bin')

            if args.model is not None:
                from astropy.io import fits
                fits.writeto(outmodel,
                             results['modelimage'],
                             header=frame.meta)

            log.info('extract:  Done {} spectra {}:{} at {}'.format(
                os.path.basename(input_file), bspecmin[b],
                bspecmin[b] + bnspec[b], time.asctime()))
            sys.stdout.flush()
        except:
            # Log the error and increment the number of failures
            log.error(
                "extract:  FAILED bundle {}, spectrum range {}:{}".format(
                    b, bspecmin[b], bspecmin[b] + bnspec[b]))
            exc_type, exc_value, exc_traceback = sys.exc_info()
            lines = traceback.format_exception(exc_type, exc_value,
                                               exc_traceback)
            log.error(''.join(lines))
            failcount += 1
            sys.stdout.flush()

    if comm is not None:
        failcount = comm.allreduce(failcount)

    if failcount > 0:
        # all processes throw
        raise RuntimeError("some extraction bundles failed")

    if rank == 0:
        mergeopts = ['--output', args.output, '--force', '--delete']
        mergeopts.extend(
            ["{}_{:02d}.fits".format(outroot, b) for b in bundles])
        mergeargs = mergebundles.parse(mergeopts)
        mergebundles.main(mergeargs)

        if args.model is not None:
            model = None
            for b in bundles:
                outmodel = "{}_model_{:02d}.fits".format(outroot, b)
                if model is None:
                    model = fits.getdata(outmodel)
                else:
                    #- TODO: test and warn if models overlap for pixels with
                    #- non-zero values
                    model += fits.getdata(outmodel)

                os.remove(outmodel)

            fits.writeto(args.model, model)
Beispiel #9
0
def main(args):

    psf_file = args.psf
    input_file = args.input
    specmin = args.specmin
    nspec = args.nspec

    #- Load input files
    psf = load_psf(psf_file)
    img = io.read_image(input_file)

    if nspec is None:
        nspec = psf.nspec
    specmax = specmin + nspec

    camera = img.meta['CAMERA'].lower()  #- b0, r1, .. z9
    spectrograph = int(camera[1])
    fibermin = spectrograph * psf.nspec + specmin

    print('Starting {} spectra {}:{} at {}'.format(
        os.path.basename(input_file), specmin, specmin + nspec,
        time.asctime()))

    if args.fibermap is not None:
        fibermap = io.read_fibermap(args.fibermap)
        fibermap = fibermap[fibermin:fibermin + nspec]
        fibers = fibermap['FIBER']
    else:
        fibermap = None
        fibers = np.arange(fibermin, fibermin + nspec, dtype='i4')

    #- Get wavelength grid from options
    if args.wavelength is not None:
        wstart, wstop, dw = [float(tmp) for tmp in args.wavelength.split(',')]
    else:
        wstart = np.ceil(psf.wmin_all)
        wstop = np.floor(psf.wmax_all)
        dw = 0.5

    wave = np.arange(wstart, wstop + dw / 2.0, dw)
    nwave = len(wave)
    bundlesize = args.bundlesize

    #- Confirm that this PSF covers these wavelengths for these spectra
    psf_wavemin = np.max(psf.wavelength(list(range(specmin, specmax)), y=0))
    psf_wavemax = np.min(
        psf.wavelength(list(range(specmin, specmax)), y=psf.npix_y - 1))
    if psf_wavemin > wstart:
        raise ValueError(
            'Start wavelength {:.2f} < min wavelength {:.2f} for these fibers'.
            format(wstart, psf_wavemin))
    if psf_wavemax < wstop:
        raise ValueError(
            'Stop wavelength {:.2f} > max wavelength {:.2f} for these fibers'.
            format(wstop, psf_wavemax))

    #- Print parameters
    print("""\
#--- Extraction Parameters ---
input:      {input}
psf:        {psf}
output:     {output}
wavelength: {wstart} - {wstop} AA steps {dw}
specmin:    {specmin}
nspec:      {nspec}
regularize: {regularize}
#-----------------------------\
    """.format(input=input_file,
               psf=psf_file,
               output=args.output,
               wstart=wstart,
               wstop=wstop,
               dw=dw,
               specmin=specmin,
               nspec=nspec,
               regularize=args.regularize))

    #- The actual extraction
    results = ex2d(img.pix,
                   img.ivar * (img.mask == 0),
                   psf,
                   specmin,
                   nspec,
                   wave,
                   regularize=args.regularize,
                   ndecorr=True,
                   bundlesize=bundlesize,
                   wavesize=args.nwavestep,
                   verbose=args.verbose,
                   full_output=True)
    flux = results['flux']
    ivar = results['ivar']
    Rdata = results['resolution_data']
    chi2pix = results['chi2pix']

    mask = np.zeros(flux.shape, dtype=np.uint32)
    mask[results['pixmask_fraction'] > 0.5] |= specmask.SOMEBADPIX
    mask[results['pixmask_fraction'] == 1.0] |= specmask.ALLBADPIX
    mask[chi2pix > 100.0] |= specmask.BAD2DFIT

    #- Augment input image header for output
    img.meta['NSPEC'] = (nspec, 'Number of spectra')
    img.meta['WAVEMIN'] = (wstart, 'First wavelength [Angstroms]')
    img.meta['WAVEMAX'] = (wstop, 'Last wavelength [Angstroms]')
    img.meta['WAVESTEP'] = (dw, 'Wavelength step size [Angstroms]')
    img.meta['SPECTER'] = (specter.__version__,
                           'https://github.com/desihub/specter')
    img.meta['IN_PSF'] = (_trim(psf_file), 'Input spectral PSF')
    img.meta['IN_IMG'] = (_trim(input_file), 'Input image')

    frame = Frame(wave,
                  flux,
                  ivar,
                  mask=mask,
                  resolution_data=Rdata,
                  fibers=fibers,
                  meta=img.meta,
                  fibermap=fibermap,
                  chi2pix=chi2pix)

    #- Write output
    io.write_frame(args.output, frame, units='photon/bin')

    if args.model is not None:
        from astropy.io import fits
        fits.writeto(args.model,
                     results['modelimage'],
                     header=frame.meta,
                     clobber=True)

    print('Done {} spectra {}:{} at {}'.format(os.path.basename(input_file),
                                               specmin, specmin + nspec,
                                               time.asctime()))
Beispiel #10
0
def main(args):

    if args.mpi:
        from mpi4py import MPI
        comm = MPI.COMM_WORLD
        return main_mpi(args, comm)

    psf_file = args.psf
    input_file = args.input
    specmin = args.specmin
    nspec = args.nspec

    #- Load input files
    psf = load_psf(psf_file)
    img = io.read_image(input_file)

    if nspec is None:
        nspec = psf.nspec
    specmax = specmin + nspec

    if args.fibermap_index is not None :
        fibermin = args.fibermap_index
    else :
        camera = img.meta['CAMERA'].lower()     #- b0, r1, .. z9
        spectrograph = int(camera[1])
        fibermin = spectrograph * 500 + specmin

    print('Starting {} spectra {}:{} at {}'.format(os.path.basename(input_file),
        specmin, specmin+nspec, time.asctime()))

    if args.fibermap is not None:
        fibermap = io.read_fibermap(args.fibermap)
    else:
        try:
            fibermap = io.read_fibermap(args.input)
        except (AttributeError, IOError, KeyError):
            fibermap = None

    #- Trim fibermap to matching fiber range and create fibers array
    if fibermap:
        ii = np.in1d(fibermap['FIBER'], np.arange(fibermin, fibermin+nspec))
        fibermap = fibermap[ii]
        fibers = fibermap['FIBER']
    else:
        fibers = np.arange(fibermin, fibermin+nspec, dtype='i4')

    #- Get wavelength grid from options
    if args.wavelength is not None:
        wstart, wstop, dw = [float(tmp) for tmp in args.wavelength.split(',')]
    else:
        wstart = np.ceil(psf.wmin_all)
        wstop = np.floor(psf.wmax_all)
        dw = 0.7

    if args.heliocentric_correction :
        heliocentric_correction_factor = heliocentric_correction_multiplicative_factor(img.meta)
        wstart /= heliocentric_correction_factor
        wstop  /= heliocentric_correction_factor
        dw     /= heliocentric_correction_factor
    else :
        heliocentric_correction_factor = 1.
    
    wave = np.arange(wstart, wstop+dw/2.0, dw)
        
    nwave = len(wave)
    bundlesize = args.bundlesize

    #- Confirm that this PSF covers these wavelengths for these spectra
    psf_wavemin = np.max(psf.wavelength(list(range(specmin, specmax)), y=0))
    psf_wavemax = np.min(psf.wavelength(list(range(specmin, specmax)), y=psf.npix_y-1))
    if psf_wavemin-5 > wstart:
        raise ValueError('Start wavelength {:.2f} < min wavelength {:.2f} for these fibers'.format(wstart, psf_wavemin))
    if psf_wavemax+5 < wstop:
        raise ValueError('Stop wavelength {:.2f} > max wavelength {:.2f} for these fibers'.format(wstop, psf_wavemax))

    #- Print parameters
    print("""\
#--- Extraction Parameters ---
input:      {input}
psf:        {psf}
output:     {output}
wavelength: {wstart} - {wstop} AA steps {dw}
specmin:    {specmin}
nspec:      {nspec}
regularize: {regularize}
#-----------------------------\
    """.format(input=input_file, psf=psf_file, output=args.output,
        wstart=wstart, wstop=wstop, dw=dw,
        specmin=specmin, nspec=nspec,
        regularize=args.regularize))

    #- The actual extraction
    results = ex2d(img.pix, img.ivar*(img.mask==0), psf, specmin, nspec, wave,
                 regularize=args.regularize, ndecorr=args.decorrelate_fibers,
                 bundlesize=bundlesize, wavesize=args.nwavestep, verbose=args.verbose,
                   full_output=True, nsubbundles=args.nsubbundles,psferr=args.psferr)
    flux = results['flux']
    ivar = results['ivar']
    Rdata = results['resolution_data']
    chi2pix = results['chi2pix']

    mask = np.zeros(flux.shape, dtype=np.uint32)
    mask[results['pixmask_fraction']>0.5] |= specmask.SOMEBADPIX
    mask[results['pixmask_fraction']==1.0] |= specmask.ALLBADPIX
    mask[chi2pix>100.0] |= specmask.BAD2DFIT

    if heliocentric_correction_factor != 1 :
        #- Apply heliocentric correction factor to the wavelength
        #- without touching the spectra, that is the whole point
        wave   *= heliocentric_correction_factor
        wstart *= heliocentric_correction_factor
        wstop  *= heliocentric_correction_factor
        dw     *= heliocentric_correction_factor
        img.meta['HELIOCOR']   = heliocentric_correction_factor
    
    #- Augment input image header for output
    img.meta['NSPEC']   = (nspec, 'Number of spectra')
    img.meta['WAVEMIN'] = (wstart, 'First wavelength [Angstroms]')
    img.meta['WAVEMAX'] = (wstop, 'Last wavelength [Angstroms]')
    img.meta['WAVESTEP']= (dw, 'Wavelength step size [Angstroms]')
    img.meta['SPECTER'] = (specter.__version__, 'https://github.com/desihub/specter')
    img.meta['IN_PSF']  = (_trim(psf_file), 'Input spectral PSF')
    img.meta['IN_IMG']  = (_trim(input_file), 'Input image')

    frame = Frame(wave, flux, ivar, mask=mask, resolution_data=Rdata,
                fibers=fibers, meta=img.meta, fibermap=fibermap,
                chi2pix=chi2pix)

    #- Add unit
    #   In specter.extract.ex2d one has flux /= dwave
    #   to convert the measured total number of electrons per
    #   wavelength node to an electron 'density'
    frame.meta['BUNIT'] = 'count/Angstrom'

    #- Add scores to frame
    if not args.no_scores :
        compute_and_append_frame_scores(frame,suffix="RAW")

    #- Write output
    io.write_frame(args.output, frame)

    if args.model is not None:
        from astropy.io import fits
        fits.writeto(args.model, results['modelimage'], header=frame.meta, overwrite=True)

    print('Done {} spectra {}:{} at {}'.format(os.path.basename(input_file),
        specmin, specmin+nspec, time.asctime()))
Beispiel #11
0
def main(args, comm=None):
    if args.verbose:
        import logging
        log.setLevel(logging.DEBUG)

    rank = 0
    nproc = 1
    if comm is not None:
        rank = comm.rank
        nproc = comm.size
    else:
        if args.ncpu == 0:
            import multiprocessing as mp
            args.ncpu = mp.cpu_count() // 2

    if rank == 0:
        log.info('Starting pixsim at {}'.format(asctime()))

    # - Pre-flight check that these cameras haven't been done yet
    if (rank == 0) and (not args.overwrite) and os.path.exists(args.rawfile):
        log.debug('Checking if cameras are already in output file')
        from astropy.io import fits
        fx = fits.open(args.rawfile)
        oops = False
        for camera in args.cameras:
            if camera.upper() in fx:
                log.error('Camera {} already in {}'.format(camera, args.rawfile))
                oops = True
        fx.close()
        if oops:
            log.fatal('Exiting due to repeat cameras already in output file')
            if comm is not None:
                comm.Abort()
            else:
                sys.exit(1)

    ncamera = len(args.cameras)

    comm_group = comm
    comm_rank = None
    group = 0
    ngroup = 1
    group_rank = 0
    if comm is not None:
        if args.mpi_camera > 1:
            ngroup = int(comm.size / args.mpi_camera)
            group = int(comm.rank / args.mpi_camera)
            group_rank = comm.rank % args.mpi_camera
            comm_group = comm.Split(color=group, key=group_rank)
            comm_rank = comm.Split(color=group_rank, key=group)
        else:
            group = comm.rank
            ngroup = comm.size
            comm_group = MPI.COMM_SELF
            comm_rank = comm

    group_cameras = np.array_split(np.arange(ncamera, dtype=np.int32), ngroup)[group]

    # Compute which spectrographs our group needs to store based on which
    # cameras we are processing.

    group_spectro = np.unique(np.array([int(args.cameras[c][1]) for c in group_cameras], dtype=np.int32))

    # Remove outputs and or temp files

    rawtemp = "{}.tmp".format(args.rawfile)
    simpixtemp = "{}.tmp".format(args.simpixfile)

    if rank == 0:
        if args.overwrite and os.path.exists(args.rawfile):
            log.debug('removing {}'.format(args.rawfile))
            os.remove(args.rawfile)

        if args.overwrite and os.path.exists(args.simpixfile):
            log.debug('removing {}'.format(args.simpixfile))
            os.remove(args.simpixfile)

        # cleanup stale temp files
        if os.path.isfile(rawtemp):
            os.remove(rawtemp)
        if os.path.isfile(simpixtemp):
            os.remove(simpixtemp)

    if comm is not None:
        comm.barrier()

    psf = None
    if args.psf is not None:
        from specter.psf import load_psf
        psf = load_psf(args.psf)

    # Read and distribute the simspec data

    simspec = None
    if comm is not None:
        simspec = io.read_simspec_mpi(args.simspec, comm, spectrographs=group_spectro)
    else:
        simspec = io.read_simspec(args.simspec)

    # Read the fibermap

    fibers = None
    if rank == 0:
        if args.fibermap is not None:
            fibermap = lvmspec.io.read_fibermap(args.fibermap)
            fibers = np.array(fibermap['FIBER'], dtype=np.int32)
        else:
            # Get the fiber list from the simspec file
            from astropy.io import fits
            from astropy.table import Table
            fx = fits.open(args.simspec, memmap=True)
            if 'FIBERMAP' in fx:
                fibermap = Table(fx['FIBERMAP'].data)
                fibers = np.array(fibermap['FIBER'], dtype=np.int32)
            else:
                # Get the number of fibers from one of the photon HDUs
                fibers = np.arange(fx['PHOT_B'].header['NAXIS2'], dtype=np.int32)
            fx.close()
        if args.nspec > 0:
            fibers = fibers[0:args.nspec]
    if comm is not None:
        fibers = comm.bcast(fibers, root=0)

    fs = np.in1d(fibers // 500, group_spectro)
    group_fibers = fibers[fs]

    # Use original seed to generate different random seeds for each camera
    np.random.seed(args.seed)
    seeds = np.random.randint(0, 2**32 - 1, size=ncamera)

    image = {}
    rawpix = {}
    truepix = {}

    lastchannel = None
    for c in group_cameras:
        camera = args.cameras[c]
        if group_rank == 0:
            log.debug('Processing camera {}'.format(camera))
        channel = camera[0].lower()

        # Set the seed for this camera (regardless of which process is
        # performing the simulation).
        np.random.seed(seeds[c])

        # Get the random cosmic expids.  The actual values will be
        # remapped internally with the modulus operator.
        cosexpid = np.random.randint(0, 100, size=1)[0]

        # Read inputs for this camera.  Unfortunately psf
        # objects are not serializable, so we read it on all
        # processes.
        if args.psf is None:
            if channel != lastchannel:
                psf = lvmmodel.io.load_psf(channel)
                if args.ccd_npix_x is not None:
                    psf.npix_x = args.ccd_npix_x
                if args.ccd_npix_y is not None:
                    psf.npix_y = args.ccd_npix_y
            lastchannel = channel

        cosmics = None
        if args.cosmics:
            if group_rank == 0:
                if args.cosmics_file is None:
                    cosmics_file = io.find_cosmics(camera, simspec.header['EXPTIME'],
                                                   cosmics_dir=args.cosmics_dir)
                    log.info('cosmics templates {}'.format(cosmics_file))
                else:
                    cosmics_file = args.cosmics_file

                shape = (psf.npix_y, psf.npix_x)
                cosmics = io.read_cosmics(cosmics_file, cosexpid, shape=shape)
            if comm_group is not None:
                cosmics = comm_group.bcast(cosmics, root=0)

        # - Do the actual simulation
        # Each process in the group is responsible for a subset of the
        # fibers.

        if group_rank == 0:
            group_size = 1
            if comm_group is not None:
                group_size = comm_group.size
            log.info("Group {} ({} processes) simulating camera "
                     "{}".format(group, group_size, camera))

        image[camera], rawpix[camera], truepix[camera] = \
            simulate(camera, simspec, psf, fibers=group_fibers,
                     ncpu=args.ncpu, nspec=args.nspec, cosmics=cosmics,
                     wavemin=args.wavemin, wavemax=args.wavemax, preproc=False,
                     comm=comm_group)

        if args.psf is None:
            del psf

    # Write the cameras in order.  Only the rank zero process in each
    # group has the data.  If we are appending new cameras to an existing
    # raw file, then copy the original to the temporary output first.
    # Move temp files into place
    if rank == 0:
        # Copy the original files into place if we are appending
        if not args.overwrite and os.path.exists(args.rawfile):
            shutil.copy2(args.rawfile, rawtemp)
        if not args.overwrite and os.path.exists(args.simpixfile):
            shutil.copy2(args.simpixfile, simpixtemp)

    # Wait for all processes to finish their cameras
    if comm is not None:
        comm.barrier()

    for c in np.arange(ncamera, dtype=np.int32):
        camera = args.cameras[c]
        if c in group_cameras:
            if group_rank == 0:
                lvmspec.io.write_raw(rawtemp, rawpix[camera],
                                     camera=camera, header=image[camera].meta,
                                     primary_header=simspec.header)
                log.info('Wrote {} image to {}'.format(camera, args.rawfile))
                io.write_simpix(simpixtemp, truepix[camera],
                                camera=camera, meta=simspec.header)
                log.info('Wrote {} image to {}'.format(camera, args.simpixfile))
        if comm is not None:
            comm.barrier()

    # Move temp files into place
    if rank == 0:
        os.rename(simpixtemp, args.simpixfile)
        os.rename(rawtemp, args.rawfile)
    if comm is not None:
        comm.barrier()

    # Apply preprocessing
    if args.preproc:
        if rank == 0:
            log.info('Preprocessing raw -> pix files')
        if len(group_cameras) > 0:
            if group_rank == 0:
                for c in group_cameras:
                    camera = args.cameras[c]
                    pixfile = lvmspec.io.findfile('pix', night=args.night,
                                                  expid=args.expid, camera=camera)
                    preproc_opts = ['--infile', args.rawfile, '--outdir',
                                    args.preproc_dir, '--pixfile', pixfile]
                    preproc_opts += ['--cameras', camera]
                    preproc.main(preproc.parse(preproc_opts))

    if comm is not None:
        comm.barrier()

    # Python is terrible with garbage collection, but at least
    # encourage it...
    del image
    del rawpix
    del truepix

    if rank == 0:
        log.info('Finished pixsim {} expid {} at {}'.format(args.night, args.expid, asctime()))
Beispiel #12
0
def main_mpi(args, comm=None):

    psf_file = args.psf
    input_file = args.input

    # these parameters are interpreted as the *global* spec range,
    # to be divided among processes.
    specmin = args.specmin
    nspec = args.nspec

    #- Load input files and broadcast

    # FIXME: after we have fixed the serialization
    # of the PSF, read and broadcast here, to reduce
    # disk contention.

    img = None
    if comm is None:
        img = io.read_image(input_file)
    else:
        if comm.rank == 0:
            img = io.read_image(input_file)
        img = comm.bcast(img, root=0)

    psf = load_psf(psf_file)

    # get spectral range

    if nspec is None:
        nspec = psf.nspec
    specmax = specmin + nspec

    camera = img.meta['CAMERA'].lower()     #- b0, r1, .. z9
    spectrograph = int(camera[1])
    fibermin = spectrograph * psf.nspec + specmin

    if args.fibermap is not None:
        fibermap = io.read_fibermap(args.fibermap)
        fibermap = fibermap[fibermin:fibermin+nspec]
        fibers = fibermap['FIBER']
    else:
        fibermap = None
        fibers = np.arange(fibermin, fibermin+nspec, dtype='i4')

    #- Get wavelength grid from options

    if args.wavelength is not None:
        wstart, wstop, dw = map(float, args.wavelength.split(','))
    else:
        wstart = np.ceil(psf.wmin_all)
        wstop = np.floor(psf.wmax_all)
        dw = 0.5
        
    wave = np.arange(wstart, wstop+dw/2.0, dw)
    nwave = len(wave)

    #- Confirm that this PSF covers these wavelengths for these spectra
    
    psf_wavemin = np.max(psf.wavelength(range(specmin, specmax), y=0))
    psf_wavemax = np.min(psf.wavelength(range(specmin, specmax), y=psf.npix_y-1))
    if psf_wavemin > wstart:
        raise ValueError, 'Start wavelength {:.2f} < min wavelength {:.2f} for these fibers'.format(wstart, psf_wavemin)
    if psf_wavemax < wstop:
        raise ValueError, 'Stop wavelength {:.2f} > max wavelength {:.2f} for these fibers'.format(wstop, psf_wavemax)

    # Now we divide our spectra into bundles

    bundlesize = args.bundlesize
    checkbundles = set()
    checkbundles.update(np.floor_divide(np.arange(specmin, specmax), bundlesize*np.ones(nspec)).astype(int))
    bundles = sorted(list(checkbundles))
    nbundle = len(bundles)

    bspecmin = {}
    bnspec = {}
    for b in bundles:
        if specmin > b * bundlesize:
            bspecmin[b] = specmin
        else:
            bspecmin[b] = b * bundlesize
        if (b+1) * bundlesize > specmax:
            bnspec[b] = specmax - bspecmin[b]
        else:
            bnspec[b] = bundlesize

    # Now we assign bundles to processes

    nproc = 1
    rank = 0
    if comm is not None:
        nproc = comm.size
        rank = comm.rank

    mynbundle = int(nbundle // nproc)
    myfirstbundle = 0
    leftover = nbundle % nproc
    if rank < leftover:
        mynbundle += 1
        myfirstbundle = rank * mynbundle
    else:
        myfirstbundle = ((mynbundle + 1) * leftover) + (mynbundle * (rank - leftover))

    if rank == 0:
        #- Print parameters
        print "extract:  input = {}".format(input_file)
        print "extract:  psf = {}".format(psf_file)
        print "extract:  specmin = {}".format(specmin)
        print "extract:  nspec = {}".format(nspec)
        print "extract:  wavelength = {},{},{}".format(wstart, wstop, dw)
        print "extract:  nwavestep = {}".format(args.nwavestep)
        print "extract:  regularize = {}".format(args.regularize)

    # get the root output file

    outpat = re.compile(r'(.*)\.fits')
    outmat = outpat.match(args.output)
    if outmat is None:
        raise RuntimeError("extraction output file should have .fits extension")
    outroot = outmat.group(1)

    outdir = os.path.normpath(os.path.dirname(outroot))
    if rank == 0:
        if not os.path.isdir(outdir):
            os.makedirs(outdir)

    if comm is not None:
        comm.barrier()

    failcount = 0

    for b in range(myfirstbundle, myfirstbundle+mynbundle):
        outbundle = "{}_{:02d}.fits".format(outroot, b)
        outmodel = "{}_model_{:02d}.fits".format(outroot, b)

        print('extract:  Rank {} starting {} spectra {}:{} at {}'.format(
            rank, os.path.basename(input_file),
            bspecmin[b], bspecmin[b]+bnspec[b], time.asctime(),
            ) )

        #- The actual extraction
        try:
            results = ex2d(img.pix, img.ivar*(img.mask==0), psf, bspecmin[b], 
                bnspec[b], wave, regularize=args.regularize, ndecorr=True,
                bundlesize=bundlesize, wavesize=args.nwavestep, verbose=args.verbose,
                full_output=True)

            flux = results['flux']
            ivar = results['ivar']
            Rdata = results['resolution_data']
            chi2pix = results['chi2pix']

            mask = np.zeros(flux.shape, dtype=np.uint32)
            mask[results['pixmask_fraction']>0.5] |= specmask.SOMEBADPIX
            mask[results['pixmask_fraction']==1.0] |= specmask.ALLBADPIX
            mask[chi2pix>100.0] |= specmask.BAD2DFIT

            #- Augment input image header for output
            img.meta['NSPEC']   = (nspec, 'Number of spectra')
            img.meta['WAVEMIN'] = (wstart, 'First wavelength [Angstroms]')
            img.meta['WAVEMAX'] = (wstop, 'Last wavelength [Angstroms]')
            img.meta['WAVESTEP']= (dw, 'Wavelength step size [Angstroms]')
            img.meta['SPECTER'] = (specter.__version__, 'https://github.com/desihub/specter')
            img.meta['IN_PSF']  = (_trim(psf_file), 'Input spectral PSF')
            img.meta['IN_IMG']  = (_trim(input_file), 'Input image')

            if fibermap is not None:
                bfibermap = fibermap[bspecmin[b]-specmin:bspecmin[b]+bnspec[b]-specmin]
            else:
                bfibermap = None

            bfibers = fibers[bspecmin[b]-specmin:bspecmin[b]+bnspec[b]-specmin]

            frame = Frame(wave, flux, ivar, mask=mask, resolution_data=Rdata,
                        fibers=bfibers, meta=img.meta, fibermap=bfibermap,
                        chi2pix=chi2pix)

            #- Write output
            io.write_frame(outbundle, frame)

            if args.model is not None:
                from astropy.io import fits
                fits.writeto(outmodel, results['modelimage'], header=frame.meta)

            print('extract:  Done {} spectra {}:{} at {}'.format(os.path.basename(input_file),
                bspecmin[b], bspecmin[b]+bnspec[b], time.asctime()))
        except:
            failcount += 1

    if comm is not None:
        failcount = comm.allreduce(failcount)

    if failcount > 0:
        # all processes throw
        raise RuntimeError("some extraction bundles failed")

    if rank == 0:
        mergeopts = [
            '--output', args.output,
            '--force',
            '--delete'
        ]
        mergeopts.extend([ "{}_{:02d}.fits".format(outroot, b) for b in bundles ])
        mergeargs = mergebundles.parse(mergeopts)
        mergebundles.main(mergeargs)

        if args.model is not None:
            model = None
            for b in bundles:
                outmodel = "{}_model_{:02d}.fits".format(outroot, b)
                if model is None:
                    model = fits.getdata(outmodel)
                else:
                    #- TODO: test and warn if models overlap for pixels with
                    #- non-zero values
                    model += fits.getdata(outmodel)

                os.remove(outmodel)

            fits.writeto(args.model, model)
Beispiel #13
0
 def setUpClass(cls):
     cls.psf = load_psf(resource_filename("specter.test", "t/psf-monospot.fits"))
Beispiel #14
0
    def run(self, *args, **kwargs):

        if len(args) == 0:
            raise qlexceptions.ParameterException("Missing input parameter")
        if not self.is_compatible(type(args[0])):
            raise qlexceptions.ParameterException(
                "Incompatible input. Was expecting %s got %s" %
                (type(self.__inpType__), type(args[0])))
        if "PSFFile_sp" not in kwargs:
            raise qlexceptions.ParameterException("Need PSF File")
        from specter.psf import load_psf

        input_image = args[0]
        psffile = kwargs["PSFFile_sp"]
        psf = load_psf(psffile)

        if "Wavelength" not in kwargs:
            wstart = np.ceil(psf.wmin_all)
            wstop = np.floor(psf.wmax_all)
            dw = 0.5
        else:
            wavelength = kwargs["Wavelength"]
            if kwargs[
                    "Wavelength"] is not None:  #- should be in wstart,wstop,dw format
                wstart, wstop, dw = map(float, wavelength.split(','))
            else:
                wstart = np.ceil(psf.wmin_all)
                wstop = np.floor(psf.wmax_all)
                dw = 0.5
        wave = np.arange(wstart, wstop + dw / 2.0, dw)

        if "Specmin" not in kwargs:
            specmin = 0
        else:
            specmin = kwargs["Specmin"]
            if kwargs["Specmin"] is None:
                specmin = 0

        if "Nspec" not in kwargs:
            nspec = psf.nspec
        else:
            nspec = kwargs["Nspec"]
            if nspec is None:
                nspec = psf.nspec

        specmax = specmin + nspec

        camera = input_image.meta['CAMERA'].lower()  #- b0, r1, .. z9
        spectrograph = int(camera[1])
        fibermin = spectrograph * 500 + specmin

        if "FiberMap" not in kwargs:
            fibermap = None
            fibers = np.arange(fibermin, fibermin + nspec, dtype='i4')
        else:
            fibermap = kwargs["FiberMap"]
            fibermap = fibermap[fibermin:fibermin + nspec]
            fibers = fibermap['FIBER']
        if "Regularize" in kwargs:
            regularize = kwargs["Regularize"]
        else:
            regularize = False
        if "ndecorr" in kwargs:
            ndecorr = ndecorr
        else:
            ndecorr = True

        bundlesize = 25  #- hard coded

        if "Outfile" in kwargs:
            outfile = kwargs["Outfile"]
        else:
            outfile = None

        if "Nwavestep" in kwargs:
            wavesize = kwargs["Nwavestep"]
        else:
            wavesize = 50

        return self.run_pa(input_image,
                           psf,
                           specmin,
                           nspec,
                           wave,
                           regularize=regularize,
                           ndecorr=ndecorr,
                           bundlesize=bundlesize,
                           wavesize=wavesize,
                           outfile=outfile,
                           fibers=fibers,
                           fibermap=fibermap)
Beispiel #15
0
    def run(self,*args,**kwargs):

        if len(args) == 0 :
            raise qlexceptions.ParameterException("Missing input parameter")
        if not self.is_compatible(type(args[0])):
            raise qlexceptions.ParameterException("Incompatible input. Was expecting %s got %s"%(type(self.__inpType__),type(args[0])))
        if "PSFFile_sp" not in kwargs:
            raise qlexceptions.ParameterException("Need PSF File")
        from specter.psf import load_psf

        input_image=args[0]
        psffile=kwargs["PSFFile_sp"]
        psf=load_psf(psffile)

        if "Wavelength" not in kwargs:
            wstart = np.ceil(psf.wmin_all)
            wstop = np.floor(psf.wmax_all)
            dw = 0.5
        else: 
            wavelength=kwargs["Wavelength"]
            if kwargs["Wavelength"] is not None: #- should be in wstart,wstop,dw format                
                wstart, wstop, dw = map(float, wavelength.split(','))
            else: 
                wstart = np.ceil(psf.wmin_all)
                wstop = np.floor(psf.wmax_all)
                dw = 0.5            
        wave = np.arange(wstart, wstop+dw/2.0, dw)

        if "Specmin" not in kwargs:
            specmin=0
        else:
            specmin=kwargs["Specmin"]
            if kwargs["Specmin"] is None:
               specmin=0

        if "Nspec" not in kwargs:
            nspec = psf.nspec
        else:
            nspec=kwargs["Nspec"]
            if nspec is None:
                nspec=psf.nspec

        specmax = specmin + nspec

        camera = input_image.meta['CAMERA'].lower()     #- b0, r1, .. z9
        spectrograph = int(camera[1])
        fibermin = spectrograph*500 + specmin
  
        if "FiberMap" not in kwargs:
            fibermap = None
            fibers = np.arange(fibermin, fibermin+nspec, dtype='i4')
        else:
            fibermap=kwargs["FiberMap"]
            fibermap = fibermap[fibermin:fibermin+nspec]
            fibers = fibermap['FIBER']
        if "Regularize" in kwargs:
            regularize=kwargs["Regularize"]
        else:
            regularize=False
        if "ndecorr" in kwargs:
            ndecorr=ndecorr
        else: 
            ndecorr=True

        bundlesize=25 #- hard coded
      
        if "Outfile" in kwargs:
            outfile=kwargs["Outfile"]
        else:
            outfile=None

        if "Nwavestep" in kwargs:
            wavesize=kwargs["Nwavestep"]
        else:
            wavesize=50       

        return self.run_pa(input_image,psf,specmin,nspec,wave,regularize=regularize,ndecorr=ndecorr, bundlesize=bundlesize, wavesize=wavesize,outfile=outfile,fibers=fibers,fibermap=fibermap)
Beispiel #16
0
def main(args, comm=None):
    if args.verbose:
        import logging
        log.setLevel(logging.DEBUG)
    #we do this so we can use operator.itemgetter
    import operator
    #we do this so our print statements can have timestamps
    import time

    rank = 0
    nproc = 1
    if comm is not None:
        import mpi4py
        rank = comm.rank
        nproc = comm.size
    else:
        if args.ncpu == 0:
            import multiprocessing as mp
            args.ncpu = mp.cpu_count() // 2

    if rank == 0:
        log.info('Starting pixsim at {}'.format(asctime()))

    #- Pre-flight check that these cameras haven't been done yet
    if (rank == 0) and (not args.overwrite) and os.path.exists(args.rawfile):
        log.debug('Checking if cameras are already in output file')
        from astropy.io import fits
        fx = fits.open(args.rawfile)
        oops = False
        for camera in args.cameras:
            if camera.upper() in fx:
                log.error('Camera {} already in {}'.format(
                    camera, args.rawfile))
                oops = True
        fx.close()
        if oops:
            log.fatal('Exiting due to repeat cameras already in output file')
            if comm is not None:
                comm.Abort()
            else:
                sys.exit(1)

    #assign communicators, groups, etc, used for both mpi and multiprocessing
    ncamera = len(args.cameras)
    comm_group = comm
    comm_rank = None
    group = 0
    ngroup = 1
    group_rank = 0
    if comm is not None:
        if args.mpi_camera > 1:
            ngroup = int(comm.size / args.mpi_camera)
            group = int(comm.rank / args.mpi_camera)
            group_rank = comm.rank % args.mpi_camera
            comm_group = comm.Split(color=group, key=group_rank)
            comm_rank = comm.Split(color=group_rank, key=group)
        else:
            group = comm.rank
            ngroup = comm.size
            comm_group = MPI.COMM_SELF
            comm_rank = comm

    #check to make sure that the number of frames is evenly divisible by nubmer of nodes
    #if not, abort and provide a helpful error message
    #otherwise due to barrier logic the program will hang
    if comm is not None:
        if comm.rank == 0:
            if ncamera % ngroup != 0:
                msg = 'Number of frames (ncamera) must be evenly divisible by number of nodes (N)'
                log.error(msg)
                raise ValueError(msg)
                comm.Abort()

    # Remove outputs and or temp files
    rawtemp = "{}.tmp".format(args.rawfile)
    simpixtemp = "{}.tmp".format(args.simpixfile)

    if rank == 0:
        if args.overwrite and os.path.exists(args.rawfile):
            log.debug('removing {}'.format(args.rawfile))
            os.remove(args.rawfile)

        if args.overwrite and os.path.exists(args.simpixfile):
            log.debug('removing {}'.format(args.simpixfile))
            os.remove(args.simpixfile)

        # cleanup stale temp files
        if os.path.isfile(rawtemp):
            os.remove(rawtemp)
        if os.path.isfile(simpixtemp):
            os.remove(simpixtemp)

    if comm is not None:
        comm.barrier()

    #load psf for both mpi and multiprocessing
    psf = None
    if args.psf is not None:
        from specter.psf import load_psf
        psf = load_psf(args.psf)

    # create list of tuples
    camera_channel_args = []
    camera_channel_list = []
    if comm is not None:
        #need to parse these together so we preserve the order
        for item in args.cameras:
            #0th element is camera (b,r,z)
            #1st element is channel (0-9)
            camera_channel_args.append((item[0], item[1]))
            #divide cameras among nodes
            #first sort so zs get distributed first
            #reverse the order so z comes first
            #sort in reverse order so we get z first
            camera_channel_list = np.asarray(
                sorted(camera_channel_args,
                       key=operator.itemgetter(0),
                       reverse=True))
    #also handle multiprocessing case
    if comm is None:
        camera_channel_list = []
        for item in args.cameras:
            camera_channel_list.append((item[0], item[1]))

    #if mpi and N>1, divide cameras between nodes
    if comm is not None:
        if ngroup > 1:
            node_cameras = None
            for i in range(ngroup):
                if i == group:
                    node_cameras = camera_channel_list[i::ngroup]
        if ngroup == 1:
            node_cameras = camera_channel_list
    #also handle multiprocessing case
    if comm is None:
        node_cameras = camera_channel_list

    group_spectro = np.array([int(c[1]) for c in node_cameras], dtype=np.int32)

    #preallocate things needed for multiprocessing (we handle mpi later)
    if comm is None:
        simspec = None
        cosmics = None
        image = {}
        rawpix = {}
        truepix = {}
        lastcamera = None

    # Read the fibermap
    #this is cheap, do here both mpi non mpi
    fibers = None
    if rank == 0:
        if args.fibermap is not None:
            fibermap = desispec.io.read_fibermap(args.fibermap)
            fibers = np.array(fibermap['FIBER'], dtype=np.int32)
        else:
            # Get the fiber list from the simspec file
            from astropy.io import fits
            from astropy.table import Table
            fx = fits.open(args.simspec, memmap=True)
            if 'FIBERMAP' in fx:
                fibermap = Table(fx['FIBERMAP'].data)
                fibers = np.array(fibermap['FIBER'], dtype=np.int32)
            else:
                # Get the number of fibers from one of the photon HDUs
                fibers = np.arange(fx['PHOT_B'].header['NAXIS2'],
                                   dtype=np.int32)
            fx.close()
        if args.nspec > 0:
            fibers = fibers[0:args.nspec]
    if comm is not None:
        fibers = comm.bcast(fibers, root=0)

    #do multiprocessing fibers now, handle mpi inside the loop
    if comm is None:
        fs = np.in1d(fibers // 500, group_spectro)
        group_fibers = fibers[fs]

    # Use original seed to generate different random seeds for each camera
    np.random.seed(args.seed)
    seeds = np.random.randint(0, 2**32 - 1, size=ncamera)
    seed_counter = 0  #need to initialize counter

    #this loop handles the mpi case
    if comm is not None:
        #now that each communicator (group) knows which cameras it
        #is supposed to process, we can get started
        previous_camera = 'a'  #need to initialize
        for i in range(len(node_cameras)):  #may be different in each group
            if i > 1:
                #keep track in case we can avoid re-broadcasting stuff
                previous_camera = node_cameras[i - 1]
            current_camera = node_cameras[i]
            camera = current_camera[0] + current_camera[1]
            channel = current_camera[0]

            #since we clear, we need to pre-allocate every time
            simspec = None
            image = {}
            rawpix = {}
            truepix = {}

            #since we handle only one spectra at a time, just load the one we need
            simspec = io.read_simspec_mpi(args.simspec,
                                          comm_group,
                                          channel,
                                          spectrographs=group_spectro[i])

            if group_rank == 0:
                log.debug('Processing camera {}'.format(camera))

            # Set the seed for this camera (regardless of which process is
            # performing the simulation).
            np.random.seed(seeds[(seed_counter)])

            # Get the random cosmic expids.  The actual values will be
            # remapped internally with the modulus operator.
            cosexpid = np.random.randint(0, 100, size=1)[0]

            # Read inputs for this camera.  Unfortunately psf
            # objects are not serializable, so we read it on all
            # processes.

            if args.psf is None:
                psf = desimodel.io.load_psf(channel)
                if args.ccd_npix_x is not None:
                    psf.npix_x = args.ccd_npix_x
                if args.ccd_npix_y is not None:
                    psf.npix_y = args.ccd_npix_y

            #if we have already loaded the right cosmics camera, don't bcast again
            cosmics = None
            if args.cosmics:
                if current_camera[0] != previous_camera[0]:
                    cosmics = None
                    if group_rank == 0:
                        if args.cosmics_file is None:
                            cosmics_file = io.find_cosmics(
                                camera,
                                simspec.header['EXPTIME'],
                                cosmics_dir=args.cosmics_dir)
                            log.info(
                                'cosmics templates {}'.format(cosmics_file))
                        else:
                            cosmics_file = args.cosmics_file

                        shape = (psf.npix_y, psf.npix_x)
                        cosmics = io.read_cosmics(cosmics_file,
                                                  cosexpid,
                                                  shape=shape)

                    cosmics = comm_group.bcast(cosmics, root=0)

            if group_rank == 0:
                group_size = comm_group.size
                log.info("Group {} ({} processes) simulating camera "
                         "{}".format(group, group_size, camera))

            #calc group_fibers inside the loop
            fs = np.in1d(fibers // 500, group_spectro[i])
            group_fibers = fibers[fs]

            image[camera], rawpix[camera], truepix[camera] = \
                simulate(camera, simspec, psf, fibers=group_fibers,
                    ncpu=args.ncpu, nspec=args.nspec, cosmics=cosmics,
                    wavemin=args.wavemin, wavemax=args.wavemax, preproc=False,
                    comm=comm_group)

            #to avoid overflowing the memory let's write after each instance of simulate
            #the data are already at rank 0 in each communicator
            #then have each communicator open and write to the file one at a time
            #this is the part that will fail if the number of nodes divided by number of frames
            #is not evenly divisible (hence the check above)
            for i in range(ngroup):  #number of total communicators
                if group == i:  #only one group at a time should open/write/close
                    if group_rank == 0:  #write only from rank 0 where the data are
                        #write the raw file using desispec write_raw in raw.py
                        desispec.io.write_raw(rawtemp,
                                              rawpix[camera],
                                              camera=camera,
                                              header=image[camera].meta,
                                              primary_header=simspec.header)
                        log.info('Wrote {} image to {} at time {}'.format(
                            camera, args.rawfile, time.asctime()))
                        #write the simpix file using desisim write_simpix in io.py
                        io.write_simpix(simpixtemp,
                                        truepix[camera],
                                        camera=camera,
                                        meta=simspec.header)
                        log.info('Wrote {} image to {} at time {}'.format(
                            camera, args.simpixfile, time.asctime()))
                        #delete for each group after we have written the output files
                    del rawpix, image, truepix, simspec
                #to avoid bugs this barrier statement must align with if group==i!!
                comm.Barrier()  #all ranks should be done writing

            if args.psf is None:
                del psf

            #iterate random number counter
            seed_counter = seed_counter + 1

    #initalize random number seeds
    seed_counter = 0  #need to initialize counter
    if comm is None:
        simspec = io.read_simspec(args.simspec)
        previous_camera = 'a'
        for i in range(len(node_cameras)):

            current_camera = node_cameras[i]
            camera = current_camera[0] + current_camera[1]
            channel = current_camera[0]

            if group_rank == 0:
                log.debug('Processing camera {}'.format(camera))

            # Set the seed for this camera (regardless of which process is
            # performing the simulation).
            np.random.seed(seeds[(seed_counter)])

            # Get the random cosmic expids.  The actual values will be
            # remapped internally with the modulus operator.
            cosexpid = np.random.randint(0, 100, size=1)[0]

            # Read inputs for this camera.  Unfortunately psf
            # objects are not serializable, so we read it on all
            # processes.
            if args.psf is None:
                #add this so that it won't fail if we enter two repeated channels
                if camera != previous_camera:
                    psf = desimodel.io.load_psf(channel)
                    if args.ccd_npix_x is not None:
                        psf.npix_x = args.ccd_npix_x
                    if args.ccd_npix_y is not None:
                        psf.npix_y = args.ccd_npix_y
                previous_camera = camera

            if args.cosmics:
                if group_rank == 0:
                    if args.cosmics_file is None:
                        cosmics_file = io.find_cosmics(
                            camera,
                            simspec.header['EXPTIME'],
                            cosmics_dir=args.cosmics_dir)
                        log.info('cosmics templates {}'.format(cosmics_file))
                    else:
                        cosmics_file = args.cosmics_file

                    shape = (psf.npix_y, psf.npix_x)
                    cosmics = io.read_cosmics(cosmics_file,
                                              cosexpid,
                                              shape=shape)

            #- Do the actual simulation
            # Each process in the group is responsible for a subset of the
            # fibers.

            if group_rank == 0:
                group_size = 1
                log.info("Group {} ({} processes) simulating camera "
                         "{}".format(group, group_size, camera))

            image[camera], rawpix[camera], truepix[camera] = \
                simulate(camera, simspec, psf, fibers=group_fibers,
                    ncpu=args.ncpu, nspec=args.nspec, cosmics=cosmics,
                    wavemin=args.wavemin, wavemax=args.wavemax, preproc=False,
                    comm=comm_group)

            #like we did in mpi, move the write in here so we don't have to
            #keep accumulating all the data
            if group_rank == 0:
                desispec.io.write_raw(rawtemp,
                                      rawpix[camera],
                                      camera=camera,
                                      header=image[camera].meta,
                                      primary_header=simspec.header)
                log.info('Wrote {} image to {}'.format(camera, args.rawfile))
                io.write_simpix(simpixtemp,
                                truepix[camera],
                                camera=camera,
                                meta=simspec.header)
                log.info('Wrote {} image to {}'.format(camera,
                                                       args.simpixfile))

            if args.psf is None:
                del psf

            #iterate random number counter
            seed_counter = seed_counter + 1

    #done with both mpi and multiprocessing

    # Move temp files into place
    if rank == 0:
        # Copy the original files into place if we are appending
        if not args.overwrite and os.path.exists(args.rawfile):
            shutil.copy2(args.rawfile, rawtemp)
        if not args.overwrite and os.path.exists(args.simpixfile):
            shutil.copy2(args.simpixfile, simpixtemp)

    if rank == 0:
        os.rename(simpixtemp, args.simpixfile)
        os.rename(rawtemp, args.rawfile)
    if comm is not None:
        comm.barrier()

    # Apply preprocessing
    if args.preproc:
        if rank == 0:
            log.info('Preprocessing raw -> pix files')
        from desispec.scripts import preproc
        if len(node_cameras) > 0:
            if group_rank == 0:
                for i in range(len(node_cameras)):
                    current_camera = node_cameras[i]
                    camera = current_camera[0] + current_camera[1]
                    #file should be preproc instead of pix
                    pixfile = desispec.io.findfile('preproc',
                                                   night=args.night,
                                                   expid=args.expid,
                                                   camera=camera)
                    if args.preproc_dir:
                        pixfile = os.path.join(args.preproc_dir,
                                               os.path.basename(pixfile))

                    pixdir = os.path.dirname(pixfile)
                    if not os.path.isdir(pixdir):
                        os.makedirs(pixdir)
                    preproc_opts = [
                        '--infile', args.rawfile, '--outfile', pixfile,
                        '--cameras', camera
                    ]
                    preproc.main(preproc.parse(preproc_opts))

    # Python is terrible with garbage collection, but at least
    # encourage it...
    if comm is None:
        del image
        del rawpix
        del truepix
    #have already deleted these for the mpi case

    if rank == 0:
        log.info('Finished pixsim {} expid {} at {}'.format(
            args.night, args.expid, asctime()))
Beispiel #17
0
def main_mpi(args, comm=None):

    psf_file = args.psf
    input_file = args.input

    # these parameters are interpreted as the *global* spec range,
    # to be divided among processes.
    specmin = args.specmin
    nspec = args.nspec

    #- Load input files and broadcast

    # FIXME: after we have fixed the serialization
    # of the PSF, read and broadcast here, to reduce
    # disk contention.

    img = None
    if comm is None:
        img = io.read_image(input_file)
    else:
        if comm.rank == 0:
            img = io.read_image(input_file)
        img = comm.bcast(img, root=0)

    psf = load_psf(psf_file)

    # get spectral range

    if nspec is None:
        nspec = psf.nspec
    specmax = specmin + nspec

    camera = img.meta['CAMERA'].lower()  #- b0, r1, .. z9
    spectrograph = int(camera[1])
    fibermin = spectrograph * psf.nspec + specmin

    if args.fibermap is not None:
        fibermap = io.read_fibermap(args.fibermap)
        fibermap = fibermap[fibermin:fibermin + nspec]
        fibers = fibermap['FIBER']
    else:
        fibermap = None
        fibers = np.arange(fibermin, fibermin + nspec, dtype='i4')

    #- Get wavelength grid from options

    if args.wavelength is not None:
        wstart, wstop, dw = map(float, args.wavelength.split(','))
    else:
        wstart = np.ceil(psf.wmin_all)
        wstop = np.floor(psf.wmax_all)
        dw = 0.5

    wave = np.arange(wstart, wstop + dw / 2.0, dw)
    nwave = len(wave)

    #- Confirm that this PSF covers these wavelengths for these spectra

    psf_wavemin = np.max(psf.wavelength(range(specmin, specmax), y=0))
    psf_wavemax = np.min(
        psf.wavelength(range(specmin, specmax), y=psf.npix_y - 1))
    if psf_wavemin > wstart:
        raise ValueError, 'Start wavelength {:.2f} < min wavelength {:.2f} for these fibers'.format(
            wstart, psf_wavemin)
    if psf_wavemax < wstop:
        raise ValueError, 'Stop wavelength {:.2f} > max wavelength {:.2f} for these fibers'.format(
            wstop, psf_wavemax)

    # Now we divide our spectra into bundles

    bundlesize = args.bundlesize
    checkbundles = set()
    checkbundles.update(
        np.floor_divide(np.arange(specmin, specmax),
                        bundlesize * np.ones(nspec)).astype(int))
    bundles = sorted(list(checkbundles))
    nbundle = len(bundles)

    bspecmin = {}
    bnspec = {}
    for b in bundles:
        if specmin > b * bundlesize:
            bspecmin[b] = specmin
        else:
            bspecmin[b] = b * bundlesize
        if (b + 1) * bundlesize > specmax:
            bnspec[b] = specmax - bspecmin[b]
        else:
            bnspec[b] = bundlesize

    # Now we assign bundles to processes

    nproc = 1
    rank = 0
    if comm is not None:
        nproc = comm.size
        rank = comm.rank

    mynbundle = int(nbundle / nproc)
    myfirstbundle = 0
    leftover = nbundle % nproc
    if rank < leftover:
        mynbundle += 1
        myfirstbundle = rank * mynbundle
    else:
        myfirstbundle = ((mynbundle + 1) * leftover) + (mynbundle *
                                                        (rank - leftover))

    if rank == 0:
        #- Print parameters
        print "extract:  input = {}".format(input_file)
        print "extract:  psf = {}".format(psf_file)
        print "extract:  specmin = {}".format(specmin)
        print "extract:  nspec = {}".format(nspec)
        print "extract:  wavelength = {},{},{}".format(wstart, wstop, dw)
        print "extract:  nwavestep = {}".format(args.nwavestep)
        print "extract:  regularize = {}".format(args.regularize)

    # get the root output file

    outpat = re.compile(r'(.*)\.fits')
    outmat = outpat.match(args.output)
    if outmat is None:
        raise RuntimeError(
            "extraction output file should have .fits extension")
    outroot = outmat.group(1)

    outdir = os.path.dirname(outroot)
    if rank == 0:
        if not os.path.isdir(outdir):
            os.makedirs(outdir)

    if comm is not None:
        comm.barrier()

    failcount = 0

    for b in range(myfirstbundle, myfirstbundle + mynbundle):
        outbundle = "{}_{:02d}.fits".format(outroot, b)

        print('extract:  Starting {} spectra {}:{} at {}'.format(
            os.path.basename(input_file), bspecmin[b], bspecmin[b] + bnspec[b],
            time.asctime()))

        #- The actual extraction
        try:
            flux, ivar, Rdata = ex2d(img.pix,
                                     img.ivar * (img.mask == 0),
                                     psf,
                                     bspecmin[b],
                                     bnspec[b],
                                     wave,
                                     regularize=args.regularize,
                                     ndecorr=True,
                                     bundlesize=bundlesize,
                                     wavesize=args.nwavestep,
                                     verbose=args.verbose)

            #- Augment input image header for output
            img.meta['NSPEC'] = (nspec, 'Number of spectra')
            img.meta['WAVEMIN'] = (wstart, 'First wavelength [Angstroms]')
            img.meta['WAVEMAX'] = (wstop, 'Last wavelength [Angstroms]')
            img.meta['WAVESTEP'] = (dw, 'Wavelength step size [Angstroms]')
            img.meta['SPECTER'] = (specter.__version__,
                                   'https://github.com/desihub/specter')
            img.meta['IN_PSF'] = (_trim(psf_file), 'Input spectral PSF')
            img.meta['IN_IMG'] = (_trim(input_file), 'Input image')

            bfibermap = fibermap[bspecmin[b] - specmin:bspecmin[b] +
                                 bnspec[b] - specmin]
            bfibers = fibers[bspecmin[b] - specmin:bspecmin[b] + bnspec[b] -
                             specmin]

            frame = Frame(wave,
                          flux,
                          ivar,
                          resolution_data=Rdata,
                          fibers=bfibers,
                          meta=img.meta,
                          fibermap=bfibermap)

            #- Write output
            io.write_frame(outbundle, frame)

            print('extract:  Done {} spectra {}:{} at {}'.format(
                os.path.basename(input_file), bspecmin[b],
                bspecmin[b] + bnspec[b], time.asctime()))
        except:
            failcount += 1

    if comm is not None:
        failcount = comm.allreduce(failcount)

    if failcount > 0:
        # all processes throw
        raise RuntimeError("some extraction bundles failed")

    if rank == 0:
        opts = ['--output', args.output, '--force', '--delete']
        opts.extend(["{}_{:02d}.fits".format(outroot, b) for b in bundles])
        args = merge.parse(opts)
        merge.main(args)
Beispiel #18
0
def main(args):

    psf_file = args.psf
    input_file = args.input
    specmin = args.specmin
    nspec = args.nspec

    #- Load input files
    psf = load_psf(psf_file)
    img = io.read_image(input_file)

    if nspec is None:
        nspec = psf.nspec
    specmax = specmin + nspec

    camera = img.meta['CAMERA'].lower()  #- b0, r1, .. z9
    spectrograph = int(camera[1])
    fibermin = spectrograph * psf.nspec + specmin

    print('Starting {} spectra {}:{} at {}'.format(
        os.path.basename(input_file), specmin, specmin + nspec,
        time.asctime()))

    if args.fibermap is not None:
        fibermap = io.read_fibermap(args.fibermap)
        fibermap = fibermap[fibermin:fibermin + nspec]
        fibers = fibermap['FIBER']
    else:
        fibermap = None
        fibers = np.arange(fibermin, fibermin + nspec, dtype='i4')

    #- Get wavelength grid from options
    if args.wavelength is not None:
        wstart, wstop, dw = map(float, args.wavelength.split(','))
    else:
        wstart = np.ceil(psf.wmin_all)
        wstop = np.floor(psf.wmax_all)
        dw = 0.5

    wave = np.arange(wstart, wstop + dw / 2.0, dw)
    nwave = len(wave)
    bundlesize = args.bundlesize

    #- Confirm that this PSF covers these wavelengths for these spectra
    psf_wavemin = np.max(psf.wavelength(range(specmin, specmax), y=0))
    psf_wavemax = np.min(
        psf.wavelength(range(specmin, specmax), y=psf.npix_y - 1))
    if psf_wavemin > wstart:
        raise ValueError, 'Start wavelength {:.2f} < min wavelength {:.2f} for these fibers'.format(
            wstart, psf_wavemin)
    if psf_wavemax < wstop:
        raise ValueError, 'Stop wavelength {:.2f} > max wavelength {:.2f} for these fibers'.format(
            wstop, psf_wavemax)

    #- Print parameters
    print """\
#--- Extraction Parameters ---
input:      {input}
psf:        {psf}
output:     {output}
wavelength: {wstart} - {wstop} AA steps {dw}
specmin:    {specmin}
nspec:      {nspec}
regularize: {regularize}
#-----------------------------\
    """.format(input=input_file,
               psf=psf_file,
               output=args.output,
               wstart=wstart,
               wstop=wstop,
               dw=dw,
               specmin=specmin,
               nspec=nspec,
               regularize=args.regularize)

    #- The actual extraction
    flux, ivar, Rdata = ex2d(img.pix,
                             img.ivar * (img.mask == 0),
                             psf,
                             specmin,
                             nspec,
                             wave,
                             regularize=args.regularize,
                             ndecorr=True,
                             bundlesize=bundlesize,
                             wavesize=args.nwavestep,
                             verbose=args.verbose)

    #- Augment input image header for output
    img.meta['NSPEC'] = (nspec, 'Number of spectra')
    img.meta['WAVEMIN'] = (wstart, 'First wavelength [Angstroms]')
    img.meta['WAVEMAX'] = (wstop, 'Last wavelength [Angstroms]')
    img.meta['WAVESTEP'] = (dw, 'Wavelength step size [Angstroms]')
    img.meta['SPECTER'] = (specter.__version__,
                           'https://github.com/desihub/specter')
    img.meta['IN_PSF'] = (_trim(psf_file), 'Input spectral PSF')
    img.meta['IN_IMG'] = (_trim(input_file), 'Input image')

    frame = Frame(wave,
                  flux,
                  ivar,
                  resolution_data=Rdata,
                  fibers=fibers,
                  meta=img.meta,
                  fibermap=fibermap)

    #- Write output
    io.write_frame(args.output, frame)

    print('Done {} spectra {}:{} at {}'.format(os.path.basename(input_file),
                                               specmin, specmin + nspec,
                                               time.asctime()))
Beispiel #19
0
    def setUp(self):

        self.rawfile = 'test-raw-abcd.fits'
        self.pixfile = 'test-pix-abcd.fits'
        self.xwfile = 'test-xw-abcd.fits'
        self.framefile = 'test-frame-abcd.fits'
        self.fibermapfile = 'test-fibermap-abcd.fits'
        self.skyfile = 'test-sky-abcd.fits'
        self.qafile = 'test_qa.yaml'
        self.qafig = 'test_qa.png'

        #- use specter psf for this test
        self.psffile = resource_filename('specter', 'test/t/psf-monospot.fits')
        #self.psffile=os.environ['DESIMODEL']+'/data/specpsf/psf-b.fits'
        self.config = {}

        #- rawimage

        hdr = dict()
        hdr['CAMERA'] = 'z1'
        hdr['DATE-OBS'] = '2018-09-23T08:17:03.988'

        #- Dimensions per amp
        ny = self.ny = 500
        nx = self.nx = 400
        noverscan = nover = 50

        hdr['BIASSEC1'] = xy2hdr(np.s_[0:ny, nx:nx + nover])
        hdr['DATASEC1'] = xy2hdr(np.s_[0:ny, 0:nx])
        hdr['CCDSEC1'] = xy2hdr(np.s_[0:ny, 0:nx])

        hdr['BIASSEC2'] = xy2hdr(np.s_[0:ny, nx + nover:nx + 2 * nover])
        hdr['DATASEC2'] = xy2hdr(np.s_[0:ny,
                                       nx + 2 * nover:nx + 2 * nover + nx])
        hdr['CCDSEC2'] = xy2hdr(np.s_[0:ny, nx:nx + nx])

        hdr['BIASSEC3'] = xy2hdr(np.s_[ny:ny + ny, nx:nx + nover])
        hdr['DATASEC3'] = xy2hdr(np.s_[ny:ny + ny, 0:nx])
        hdr['CCDSEC3'] = xy2hdr(np.s_[ny:ny + ny, 0:nx])

        hdr['BIASSEC4'] = xy2hdr(np.s_[ny:ny + ny, nx + nover:nx + 2 * nover])
        hdr['DATASEC4'] = xy2hdr(np.s_[ny:ny + ny,
                                       nx + 2 * nover:nx + 2 * nover + nx])
        hdr['CCDSEC4'] = xy2hdr(np.s_[ny:ny + ny, nx:nx + nx])

        hdr['NIGHT'] = '20180923'
        hdr['EXPID'] = 1
        hdr['PROGRAM'] = 'dark'
        hdr['FLAVOR'] = 'science'
        hdr['EXPTIME'] = 100.0

        rawimage = np.zeros((2 * ny, 2 * nx + 2 * noverscan))
        offset = {'1': 100.0, '2': 100.5, '3': 50.3, '4': 200.4}
        gain = {'1': 1.0, '2': 1.5, '3': 0.8, '4': 1.2}
        rdnoise = {'1': 2.0, '2': 2.2, '3': 2.4, '4': 2.6}

        quad = {
            '1': np.s_[0:ny, 0:nx],
            '2': np.s_[0:ny, nx:nx + nx],
            '3': np.s_[ny:ny + ny, 0:nx],
            '4': np.s_[ny:ny + ny, nx:nx + nx],
        }

        for amp in ('1', '2', '3', '4'):

            hdr['GAIN' + amp] = gain[amp]
            hdr['RDNOISE' + amp] = rdnoise[amp]

            xy = _parse_sec_keyword(hdr['BIASSEC' + amp])
            shape = [xy[0].stop - xy[0].start, xy[1].stop - xy[1].start]
            rawimage[xy] += offset[amp]
            rawimage[xy] += np.random.normal(scale=rdnoise[amp],
                                             size=shape) / gain[amp]
            xy = _parse_sec_keyword(hdr['DATASEC' + amp])
            shape = [xy[0].stop - xy[0].start, xy[1].stop - xy[1].start]
            rawimage[xy] += offset[amp]
            rawimage[xy] += np.random.normal(scale=rdnoise[amp],
                                             size=shape) / gain[amp]

        #- set CCD parameters
        self.ccdsec1 = hdr["CCDSEC1"]
        self.ccdsec2 = hdr["CCDSEC2"]
        self.ccdsec3 = hdr["CCDSEC3"]
        self.ccdsec4 = hdr["CCDSEC4"]

        #- raw data are integers, not floats
        rawimg = rawimage.astype(np.int32)
        self.expid = hdr["EXPID"]
        self.camera = hdr["CAMERA"]
        #- Confirm that all regions were correctly offset
        assert not np.any(rawimage == 0.0)

        #- write to the rawfile and read it in QA test
        hdr['DOSVER'] = 'SIM'
        hdr['FEEVER'] = 'SIM'
        hdr['DETECTOR'] = 'SIM'

        desispec.io.write_raw(self.rawfile, rawimg, hdr, camera=self.camera)
        self.rawimage = fits.open(self.rawfile)

        #- read psf, should use specter.PSF.load_psf instead of desispec.PSF(), otherwise need to create a psfboot somewhere.

        psf = self.psf = load_psf(self.psffile)

        #- make the test pixfile, fibermap file
        img_pix = rawimg
        img_ivar = np.ones_like(img_pix) / 3.0**2
        img_mask = np.zeros(img_pix.shape, dtype=np.uint32)
        img_mask[200] = 1

        self.image = desispec.image.Image(img_pix,
                                          img_ivar,
                                          img_mask,
                                          camera='z1',
                                          meta=hdr)
        desispec.io.write_image(self.pixfile, self.image)

        self.fibermap = desispec.io.empty_fibermap(30)
        self.fibermap['OBJTYPE'][::2] = 'ELG'
        self.fibermap['OBJTYPE'][::3] = 'STD'
        self.fibermap['OBJTYPE'][::5] = 'QSO'
        self.fibermap['OBJTYPE'][::9] = 'LRG'
        self.fibermap['OBJTYPE'][::7] = 'SKY'
        #- add a filter and arbitrary magnitude
        self.fibermap['MAG'][:29] = np.tile(np.random.uniform(18, 20, 29),
                                            5).reshape(29,
                                                       5)  #- Last fiber left
        self.fibermap['FILTER'][:29] = np.tile(
            ['DECAM_R', '..', '..', '..', '..'], (29, 1))  #- last fiber left

        desispec.io.write_fibermap(self.fibermapfile, self.fibermap)

        #- make a test frame file
        self.night = hdr['NIGHT']
        self.nspec = nspec = 30
        wave = np.arange(7600.0, 9800.0, 1.0)  #- z channel
        nwave = self.nwave = len(wave)
        flux = np.random.uniform(size=(nspec, nwave)) + 100.
        ivar = np.ones_like(flux)
        resolution_data = np.ones((nspec, 13, nwave))
        self.frame = desispec.frame.Frame(wave,
                                          flux,
                                          ivar,
                                          resolution_data=resolution_data,
                                          fibermap=self.fibermap)
        self.frame.meta = dict(CAMERA=self.camera,
                               PROGRAM='dark',
                               FLAVOR='science',
                               NIGHT=self.night,
                               EXPID=self.expid,
                               EXPTIME=100,
                               CCDSEC1=self.ccdsec1,
                               CCDSEC2=self.ccdsec2,
                               CCDSEC3=self.ccdsec3,
                               CCDSEC4=self.ccdsec4)
        desispec.io.write_frame(self.framefile, self.frame)

        #- make a skymodel
        sky = np.ones_like(self.frame.flux) * 0.5
        skyivar = np.ones_like(sky)
        self.mask = np.zeros(sky.shape, dtype=np.uint32)
        self.skymodel = desispec.sky.SkyModel(wave, sky, skyivar, self.mask)
        self.skyfile = desispec.io.write_sky(self.skyfile, self.skymodel)

        #- Make a dummy boundary map for wavelength-flux in pixel space
        self.map2pix = {}
        self.map2pix["LEFT_MAX_FIBER"] = 14
        self.map2pix["RIGHT_MIN_FIBER"] = 17
        self.map2pix["BOTTOM_MAX_WAVE_INDEX"] = 900
        self.map2pix["TOP_MIN_WAVE_INDEX"] = 1100
Beispiel #20
0
def main(args, comm=None):
    if args.verbose:
        import logging
        log.setLevel(logging.DEBUG)

    rank = 0
    nproc = 1
    if comm is not None:
        rank = comm.rank
        nproc = comm.size

    if rank == 0:
        log.info('Starting pixsim at {}'.format(asctime()))

    #- Pre-flight check that these cameras haven't been done yet
    if (rank == 0) and (not args.overwrite) and os.path.exists(args.rawfile):
        log.debug('Checking if cameras are already in output file')
        from astropy.io import fits
        fx = fits.open(args.rawfile)
        oops = False
        for camera in args.cameras:
            if camera.upper() in fx:
                log.error('Camera {} already in {}'.format(camera, 
                    args.rawfile))
                oops = True
        fx.close()
        if oops:
            log.fatal('Exiting due to repeat cameras already in output file')
            if comm is not None:
                comm.Abort()
            else:
                sys.exit(1)

    ncamera = len(args.cameras)

    comm_group = comm
    comm_rank = None
    group = 0
    ngroup = 1
    group_rank = 0
    if comm is not None:
        if args.mpi_camera > 1:
            ngroup = int(comm.size / args.mpi_camera)
            group = int(comm.rank / args.mpi_camera)
            group_rank = comm.rank % args.mpi_camera
            comm_group = comm.Split(color=group, key=group_rank)
            comm_rank = comm.Split(color=group_rank, key=group)
        else:
            group = comm.rank
            ngroup = comm.size
            comm_group = MPI.COMM_SELF
            comm_rank = comm

    mycameras = np.array_split(np.arange(ncamera, dtype=np.int32), 
        ngroup)[group]

    rawtemp = "{}.tmp".format(args.rawfile)
    simpixtemp = "{}.tmp".format(args.simpixfile)

    if rank == 0:
        if args.overwrite and os.path.exists(args.rawfile):
            log.debug('removing {}'.format(args.rawfile))
            os.remove(args.rawfile)

        if args.overwrite and os.path.exists(args.simpixfile):
            log.debug('removing {}'.format(args.simpixfile))
            os.remove(args.simpixfile)

        # cleanup stale temp files
        if os.path.isfile(rawtemp):
            os.remove(rawtemp)
    
    if comm is not None:
        comm.barrier()

    psf = None
    if args.psf is not None:
        from specter.psf import load_psf
        psf = load_psf(args.psf)

    simspec = None
    if rank == 0:
        simspec = io.read_simspec(args.simspec)
    if comm is not None:
        # Broadcast one array at a time, since this is a 
        # very large object.
        flv = None
        wv = None
        pht = None
        if simspec is not None:
            flv = simspec.flavor
            wv = simspec.wave
            pht = simspec.phot
        flv = comm.bcast(flv, root=0)
        wv = comm.bcast(wv, root=0)
        pht = comm.bcast(pht, root=0)
        if simspec is None:
            simspec = SimSpec(flv, wv, pht)
        simspec.flux = comm.bcast(simspec.flux, root=0)
        simspec.skyflux = comm.bcast(simspec.skyflux, root=0)
        simspec.skyphot = comm.bcast(simspec.skyphot, root=0)
        simspec.metadata = comm.bcast(simspec.metadata, root=0)
        simspec.fibermap = comm.bcast(simspec.fibermap, root=0)
        simspec.obs = comm.bcast(simspec.obs, root=0)
        simspec.header = comm.bcast(simspec.header, root=0)

    fibers = None
    if args.fibermap:
        if rank == 0:
            fibermap = desispec.io.read_fibermap(args.fibermap)
            fibers = fibermap['FIBER']
            if args.nspec is not None:
                fibers = fibers[0:args.nspec]
        if comm is not None:
            fibers = comm.bcast(fibers, root=0)

    # Use original seed to generate different random seeds for each camera
    np.random.seed(args.seed)
    seeds = np.random.randint(0, 2**32-1, size=ncamera)

    image = {}
    rawpix = {}
    truepix = {}

    for c in mycameras:
        camera = args.cameras[c]
        if group_rank == 0:
            log.debug('Processing camera {}'.format(camera))
        channel = camera[0].lower()

        # Set the seed for this camera (regardless of which process is
        # performing the simulation).
        np.random.seed(seeds[c])

        # Get the random cosmic expids.  The actual values will be
        # remapped internally with the modulus operator.
        cosexpid = np.random.randint(0, 100, size=1)[0]

        # Read inputs for this camera.  Unfortunately psf
        # objects are not serializable, so we read it on all
        # processes.
        if args.psf is None:
            psf = desimodel.io.load_psf(channel)
            if args.ccd_npix_x is not None:
                psf.npix_x = args.ccd_npix_x
            if args.ccd_npix_y is not None:
                psf.npix_y = args.ccd_npix_y

        cosmics = None
        if args.cosmics:
            if group_rank == 0:
                if args.cosmics_file is None:
                    cosmics_file = io.find_cosmics(camera, 
                        simspec.header['EXPTIME'],
                        cosmics_dir=args.cosmics_dir)
                    log.info('cosmics templates {}'.format(cosmics_file))
                else:
                    cosmics_file = args.cosmics_file

                shape = (psf.npix_y, psf.npix_x)
                cosmics = io.read_cosmics(cosmics_file, cosexpid, 
                    shape=shape)
            if comm_group is not None:
                cosmics = comm_group.bcast(cosmics, root=0)

        #- Do the actual simulation
        image[camera], rawpix[camera], truepix[camera] = \
            desisim.pixsim.simulate(camera, simspec, psf, fibers=fibers,
            nspec=args.nspec, ncpu=args.ncpu, cosmics=cosmics,
            wavemin=args.wavemin, wavemax=args.wavemax, preproc=False,
            comm=comm_group)

        if args.psf is None:
            del psf

    # Wait for all processes to finish their cameras
    if comm is not None:
        comm.barrier()

    # Write the cameras in order.  Only the rank zero process in each
    # group has the data.
    for c in np.arange(ncamera, dtype=np.int32):
        camera = args.cameras[c]
        if c in mycameras:
            if group_rank == 0:
                desispec.io.write_raw(rawtemp, rawpix[camera], 
                    camera=camera, header=image[camera].meta, 
                    primary_header=simspec.header)
                log.info('Wrote {} image to {}'.format(camera, args.rawfile))
                io.write_simpix(simpixtemp, truepix[camera], 
                    camera=camera, meta=simspec.header)
                log.info('Wrote {} image to {}'.format(camera, 
                    args.simpixfile))
        if comm is not None:
            comm.barrier()

    # Move temp files into place
    if rank == 0:
        os.rename(simpixtemp, args.simpixfile)
        os.rename(rawtemp, args.rawfile)
    if comm is not None:
        comm.barrier()

    # Apply preprocessing
    if args.preproc:
        if rank == 0:
            log.info('Preprocessing raw -> pix files')
        from desispec.scripts import preproc
        if len(mycameras) > 0:
            if group_rank == 0:
                for c in mycameras:
                    camera = args.cameras[c]
                    pixfile = desispec.io.findfile('pix', night=args.night,
                        expid=args.expid, camera=camera)
                    preproc_opts = ['--infile', args.rawfile, '--outdir',
                        args.preproc_dir, '--pixfile', pixfile]
                    preproc_opts += ['--cameras', camera]
                    preproc.main(preproc.parse(preproc_opts))

    if comm is not None:
        comm.barrier()
    
    # Python is terrible with garbage collection, but at least
    # encourage it...
    del image
    del rawpix
    del truepix

    if rank == 0:
        log.info('Finished pixsim {} expid {} at {}'.format(args.night, args.expid, asctime()))
Beispiel #21
0
 def setUpClass(cls):
     cls.psf = load_psf(resource_filename("specter.test", "t/psf-gausshermite2.fits"))
Beispiel #22
0
def main(args=None):
    log.info('Starting pixsim at {}'.format(asctime()))
    if isinstance(args, (list, tuple, type(None))):
        args = parse(args)

    if args.verbose:
        import logging
        log.setLevel(logging.DEBUG)

    if args.mpi:
        from mpi4py import MPI
        mpicomm = MPI.COMM_WORLD
        log.debug('Using mpi4py MPI communicator')
    else:
        from desisim.util import _FakeMPIComm
        log.debug('Using fake MPI communicator')
        mpicomm = _FakeMPIComm()

    log.info('Starting pixsim rank {} at {}'.format(mpicomm.rank, asctime()))
    log.debug('MPI rank {} size {} / {} {}'.format(mpicomm.rank, mpicomm.size,
                                                   mpicomm.Get_rank(),
                                                   mpicomm.Get_size()))

    #- Pre-flight check that these cameras haven't been done yet
    if (mpicomm.rank == 0) and (not args.overwrite) and os.path.exists(
            args.rawfile):
        log.debug('Checking if cameras are already in output file')
        from astropy.io import fits
        fx = fits.open(args.rawfile)
        oops = False
        for camera in args.cameras:
            if camera.upper() in fx:
                log.error('Camera {} already in {}'.format(
                    camera, args.rawfile))
                oops = True

        fx.close()
        if oops:
            log.fatal('Exiting due to repeat cameras already in output file')
            mpicomm.Abort()

    ncameras = len(args.cameras)
    if ncameras % mpicomm.size != 0:
        log.fatal('Processing cameras {}'.format(args.cameras))
        log.fatal(
            'Number of cameras {} must be evenly divisible by MPI size {}'.
            format(ncameras, mpicomm.size))
        mpicomm.Abort()

    #- Use original seed to generate different random seeds for each MPI rank
    np.random.seed(args.seed)
    while True:
        seeds = np.random.randint(0, 2**32 - 1, size=mpicomm.size)
        if np.unique(seeds).size == mpicomm.size:
            random.seed(seeds[mpicomm.rank])
            np.random.seed(seeds[mpicomm.rank])
            break

    if args.psf is not None:
        from specter.psf import load_psf
        psf = load_psf(args.psf)

    simspec = io.read_simspec(args.simspec)

    if args.fibermap:
        fibermap = desispec.io.read_fibermap(args.fibermap)
        fibers = fibermap['FIBER']
        if args.nspec is not None:
            fibers = fibers[0:args.nspec]
    else:
        fibers = None

    if args.overwrite and os.path.exists(args.rawfile):
        log.debug('removing {}'.format(args.rawfile))
        os.remove(args.rawfile)

    if args.overwrite and os.path.exists(args.simpixfile):
        log.debug('removing {}'.format(args.simpixfile))
        os.remove(args.simpixfile)

    for i in range(mpicomm.rank, ncameras, mpicomm.size):
        camera = args.cameras[i]
        log.debug('Rank {} processing camera {}'.format(mpicomm.rank, camera))
        channel = camera[0].lower()
        assert channel in (
            'b', 'r',
            'z'), "Unknown camera {} doesn't start with b,r,z".format(camera)

        #- Read inputs for this camera
        if args.psf is None:
            psf = desimodel.io.load_psf(channel)
            if args.ccd_npix_x is not None:
                psf.npix_x = args.ccd_npix_x
            if args.ccd_npix_y is not None:
                psf.npix_y = args.ccd_npix_y

        if args.cosmics:
            if args.cosmics_file is None:
                cosmics_file = io.find_cosmics(camera,
                                               simspec.header['EXPTIME'],
                                               cosmics_dir=args.cosmics_dir)
                log.info('cosmics templates {}'.format(cosmics_file))
            else:
                cosmics_file = args.cosmics_file

            shape = (psf.npix_y, psf.npix_x)
            cosmics = io.read_cosmics(cosmics_file, args.expid, shape=shape)
        else:
            cosmics = None

        #- Do the actual simulation
        image, rawpix, truepix = desisim.pixsim.simulate(camera,
                                                         simspec,
                                                         psf,
                                                         fibers=fibers,
                                                         nspec=args.nspec,
                                                         ncpu=args.ncpu,
                                                         cosmics=cosmics,
                                                         wavemin=args.wavemin,
                                                         wavemax=args.wavemax,
                                                         preproc=False)

        #- Synchronize with other MPI threads before continuing with output
        mpicomm.Barrier()

        #- Loop over MPI ranks, letting each one take its turn writing output
        for rank in range(mpicomm.size):
            if rank == mpicomm.rank:
                desispec.io.write_raw(args.rawfile,
                                      rawpix,
                                      camera=camera,
                                      header=image.meta,
                                      primary_header=simspec.header)
                log.info('Wrote {} image to {}'.format(camera, args.rawfile))
                io.write_simpix(args.simpixfile,
                                truepix,
                                camera=camera,
                                meta=simspec.header)
                log.info('Wrote {} image to {}'.format(camera,
                                                       args.simpixfile))
                mpicomm.Barrier()
            else:
                mpicomm.Barrier()

    #- Call preproc separately from pixsim.simulate to ensure that it is
    #- done identically to real data.
    #- Note: This does lose the advantage of parallel preprocessing; we could
    #- change this if that is problematic
    if args.preproc and mpicomm.rank == 0:
        log.info('Preprocessing raw -> pix files')
        from desispec.scripts import preproc
        preproc_opts = ['--infile', args.rawfile, '--outdir', args.preproc_dir]
        preproc_opts += ['--cameras', ','.join(args.cameras)]
        preproc.main(preproc.parse(preproc_opts))

    if mpicomm.rank == 0:
        log.info('Finished pixsim {} expid {} at {}'.format(
            args.night, args.expid, asctime()))
Beispiel #23
0
    def setUp(self):
        #- use specter psf for this test
        self.psffile=resource_filename('specter', 'test/t/psf-monospot.fits') 
        #self.psffile=os.environ['DESIMODEL']+'/data/specpsf/psf-b.fits'
        self.config={"kwargs":{
            "refKey":None,
            "param":{},
            "qso_resid":None
            }}

        #- rawimage

        hdr = dict()
        hdr['CAMERA'] = 'z1'
        hdr['DATE-OBS'] = '2018-09-23T08:17:03.988'
        hdr['PROGRAM'] = 'dark'
        hdr['EXPTIME'] = 100

        #- Dimensions per amp
        ny = self.ny = 500
        nx = self.nx = 400
        noverscan = nover = 50

        hdr['BIASSEC1'] = xy2hdr(np.s_[0:ny, nx:nx+nover])
        hdr['DATASEC1'] = xy2hdr(np.s_[0:ny, 0:nx])
        hdr['CCDSEC1'] = xy2hdr(np.s_[0:ny, 0:nx])
        
        hdr['BIASSEC2'] = xy2hdr(np.s_[0:ny, nx+nover:nx+2*nover])
        hdr['DATASEC2'] = xy2hdr(np.s_[0:ny, nx+2*nover:nx+2*nover+nx])
        hdr['CCDSEC2'] =  xy2hdr(np.s_[0:ny, nx:nx+nx])

        hdr['BIASSEC3'] = xy2hdr(np.s_[ny:ny+ny, nx:nx+nover])
        hdr['DATASEC3'] = xy2hdr(np.s_[ny:ny+ny, 0:nx])
        hdr['CCDSEC3'] = xy2hdr(np.s_[ny:ny+ny, 0:nx])

        hdr['BIASSEC4'] = xy2hdr(np.s_[ny:ny+ny, nx+nover:nx+2*nover])
        hdr['DATASEC4'] = xy2hdr(np.s_[ny:ny+ny, nx+2*nover:nx+2*nover+nx])
        hdr['CCDSEC4'] =  xy2hdr(np.s_[ny:ny+ny, nx:nx+nx])
        
        hdr['NIGHT'] = '20180923'
        hdr['EXPID'] = 1
        hdr['PROGRAM'] = 'dark'
        hdr['FLAVOR'] = 'science'
        hdr['EXPTIME'] = 100.0
        
        rawimage = np.zeros((2*ny, 2*nx+2*noverscan))
        offset = {'1':100.0, '2':100.5, '3':50.3, '4':200.4}
        gain = {'1':1.0, '2':1.5, '3':0.8, '4':1.2}
        rdnoise = {'1':2.0, '2':2.2, '3':2.4, '4':2.6}
        obsrdn = {'1':3.4, '2':3.3, '3':3.6, '4':3.3}

        quad = {
            '1': np.s_[0:ny, 0:nx], '2': np.s_[0:ny, nx:nx+nx],
            '3': np.s_[ny:ny+ny, 0:nx], '4': np.s_[ny:ny+ny, nx:nx+nx],
        }
        
        for amp in ('1', '2', '3', '4'):

            hdr['GAIN'+amp] = gain[amp]
            hdr['RDNOISE'+amp] = rdnoise[amp]
            hdr['OBSRDN'+amp] = obsrdn[amp]

            xy = _parse_sec_keyword(hdr['BIASSEC'+amp])
            shape = [xy[0].stop-xy[0].start, xy[1].stop-xy[1].start]
            rawimage[xy] += offset[amp]
            rawimage[xy] += np.random.normal(scale=rdnoise[amp], size=shape)/gain[amp]
            xy = _parse_sec_keyword(hdr['DATASEC'+amp])
            shape = [xy[0].stop-xy[0].start, xy[1].stop-xy[1].start]
            rawimage[xy] += offset[amp]
            rawimage[xy] += np.random.normal(scale=rdnoise[amp], size=shape)/gain[amp]

        #- set CCD parameters
        self.ccdsec1=hdr["CCDSEC1"]
        self.ccdsec2=hdr["CCDSEC2"]
        self.ccdsec3=hdr["CCDSEC3"]
        self.ccdsec4=hdr["CCDSEC4"]

        #- raw data are integers, not floats
        rawimg = rawimage.astype(np.int32)
        self.expid=hdr["EXPID"]
        self.camera=hdr["CAMERA"]
        #- Confirm that all regions were correctly offset
        assert not np.any(rawimage == 0.0)        

        #- write to the rawfile and read it in QA test
        hdr['DOSVER'] = 'SIM'
        hdr['FEEVER'] = 'SIM'
        hdr['DETECTOR'] = 'SIM'

        desispec.io.write_raw(self.rawfile,rawimg,hdr,camera=self.camera)
        self.rawimage=fits.open(self.rawfile)
        
        #- read psf, should use specter.PSF.load_psf instead of desispec.PSF(), otherwise need to create a psfboot somewhere.

        self.psf = load_psf(self.psffile)

        #- make the test pixfile, fibermap file
        img_pix = rawimg
        img_ivar = np.ones_like(img_pix) / 3.0**2
        img_mask = np.zeros(img_pix.shape, dtype=np.uint32)
        img_mask[200] = 1

        self.image = desispec.image.Image(img_pix, img_ivar, img_mask, camera='z1',meta=hdr)
        desispec.io.write_image(self.pixfile, self.image)

        #- Create a fibermap with purposefully overlapping targeting bits
        n = 30
        self.fibermap = desispec.io.empty_fibermap(n)
        self.fibermap['OBJTYPE'][:] = 'TGT'
        self.fibermap['DESI_TARGET'][::2] |= desi_mask.ELG
        self.fibermap['DESI_TARGET'][::5] |= desi_mask.QSO
        self.fibermap['DESI_TARGET'][::7] |= desi_mask.LRG

        #- add some arbitrary fluxes
        for key in ['FLUX_G', 'FLUX_R', 'FLUX_Z', 'FLUX_W1', 'FLUX_W2']:
            self.fibermap[key] = 10**((22.5 - np.random.uniform(18, 21, size=n))/2.5)

        #- Make some standards; these still have OBJTYPE = 'TGT'
        ii = [6,18,29]
        self.fibermap['DESI_TARGET'][ii] = desi_mask.STD_FAINT

        #- set some targets to SKY
        ii = self.skyfibers = [5,10,21]
        self.fibermap['OBJTYPE'][ii] = 'SKY'
        self.fibermap['DESI_TARGET'][ii] = desi_mask.SKY
        for key in ['FLUX_G', 'FLUX_R', 'FLUX_Z', 'FLUX_W1', 'FLUX_W2']:
            self.fibermap[key][ii] = np.random.normal(scale=100, size=len(ii))

        desispec.io.write_fibermap(self.fibermapfile, self.fibermap)

        #- make a test frame file
        self.night=hdr['NIGHT']
        self.nspec = nspec = 30
        wave=np.arange(7600.0,9800.0,1.0) #- z channel
        nwave = self.nwave = len(wave)
        flux=np.random.uniform(size=(nspec,nwave))+100.
        ivar=np.ones_like(flux)
        resolution_data=np.ones((nspec,13,nwave))
        self.frame=desispec.frame.Frame(wave,flux,ivar,resolution_data=resolution_data,fibermap=self.fibermap)
        self.frame.meta =  hdr
        self.frame.meta['WAVESTEP']=0.5
        desispec.io.write_frame(self.framefile, self.frame)

        #- make a skymodel
        sky=np.ones_like(self.frame.flux)*0.5
        skyivar=np.ones_like(sky)
        self.mask=np.zeros(sky.shape,dtype=np.uint32)
        self.skymodel=desispec.sky.SkyModel(wave,sky,skyivar,self.mask)
        self.skyfile=desispec.io.write_sky(self.skyfile,self.skymodel)
        
        #- Make a dummy boundary map for wavelength-flux in pixel space
        self.map2pix={}
        self.map2pix["LEFT_MAX_FIBER"] = 14
        self.map2pix["RIGHT_MIN_FIBER"] = 17
        self.map2pix["BOTTOM_MAX_WAVE_INDEX"] = 900
        self.map2pix["TOP_MIN_WAVE_INDEX"] = 1100
Beispiel #24
0
def main_mpi(args, comm=None, timing=None):
    freeze_iers()
    nproc = 1
    rank = 0
    if comm is not None:
        nproc = comm.size
        rank = comm.rank

    mark_start = time.time()

    log = get_logger()

    psf_file = args.psf
    input_file = args.input

    # these parameters are interpreted as the *global* spec range,
    # to be divided among processes.
    specmin = args.specmin
    nspec = args.nspec

    #- Load input files and broadcast

    # FIXME: after we have fixed the serialization
    # of the PSF, read and broadcast here, to reduce
    # disk contention.

    img = None
    if rank == 0:
        img = io.read_image(input_file)
    if comm is not None:
        img = comm.bcast(img, root=0)

    psf = load_psf(psf_file)

    mark_read_input = time.time()

    # get spectral range
    if nspec is None:
        nspec = psf.nspec

    if args.fibermap is not None:
        fibermap = io.read_fibermap(args.fibermap)
    else:
        try:
            fibermap = io.read_fibermap(args.input)
        except (AttributeError, IOError, KeyError):
            fibermap = None

    if fibermap is not None:
        fibermap = fibermap[specmin:specmin + nspec]
        if nspec > len(fibermap):
            log.warning(
                "nspec {} > len(fibermap) {}; reducing nspec to {}".format(
                    nspec, len(fibermap), len(fibermap)))
            nspec = len(fibermap)
        fibers = fibermap['FIBER']
    else:
        fibers = np.arange(specmin, specmin + nspec)

    specmax = specmin + nspec

    #- Get wavelength grid from options
    if args.wavelength is not None:
        raw_wstart, raw_wstop, raw_dw = [
            float(tmp) for tmp in args.wavelength.split(',')
        ]
    else:
        raw_wstart = np.ceil(psf.wmin_all)
        raw_wstop = np.floor(psf.wmax_all)
        raw_dw = 0.7

    raw_wave = np.arange(raw_wstart, raw_wstop + raw_dw / 2.0, raw_dw)
    nwave = len(raw_wave)
    bundlesize = args.bundlesize

    if args.barycentric_correction:
        if ('RA' in img.meta) or ('TARGTRA' in img.meta):
            barycentric_correction_factor = \
                    barycentric_correction_multiplicative_factor(img.meta)
        #- Early commissioning has RA/TARGTRA in fibermap but not HDU 0
        elif fibermap is not None and \
                (('RA' in fibermap.meta) or ('TARGTRA' in fibermap.meta)):
            barycentric_correction_factor = \
                    barycentric_correction_multiplicative_factor(fibermap.meta)
        else:
            msg = 'Barycentric corr requires (TARGT)RA in HDU 0 or fibermap'
            log.critical(msg)
            raise KeyError(msg)
    else:
        barycentric_correction_factor = 1.

    # Explictly define the correct wavelength values to avoid confusion of reference frame
    # If correction applied, otherwise divide by 1 and use the same raw values
    wstart = raw_wstart / barycentric_correction_factor
    wstop = raw_wstop / barycentric_correction_factor
    dw = raw_dw / barycentric_correction_factor
    wave = raw_wave / barycentric_correction_factor

    #- Confirm that this PSF covers these wavelengths for these spectra
    psf_wavemin = np.max(psf.wavelength(list(range(specmin, specmax)), y=-0.5))
    psf_wavemax = np.min(
        psf.wavelength(list(range(specmin, specmax)), y=psf.npix_y - 0.5))
    if psf_wavemin - 5 > wstart:
        raise ValueError(
            'Start wavelength {:.2f} < min wavelength {:.2f} for these fibers'.
            format(wstart, psf_wavemin))
    if psf_wavemax + 5 < wstop:
        raise ValueError(
            'Stop wavelength {:.2f} > max wavelength {:.2f} for these fibers'.
            format(wstop, psf_wavemax))

    if rank == 0:
        #- Print parameters
        log.info("extract:  input = {}".format(input_file))
        log.info("extract:  psf = {}".format(psf_file))
        log.info("extract:  specmin = {}".format(specmin))
        log.info("extract:  nspec = {}".format(nspec))
        log.info("extract:  wavelength = {},{},{}".format(wstart, wstop, dw))
        log.info("extract:  nwavestep = {}".format(args.nwavestep))
        log.info("extract:  regularize = {}".format(args.regularize))

    if barycentric_correction_factor != 1.:
        img.meta['HELIOCOR'] = barycentric_correction_factor

    #- Augment input image header for output
    img.meta['NSPEC'] = (nspec, 'Number of spectra')
    img.meta['WAVEMIN'] = (raw_wstart, 'First wavelength [Angstroms]')
    img.meta['WAVEMAX'] = (raw_wstop, 'Last wavelength [Angstroms]')
    img.meta['WAVESTEP'] = (raw_dw, 'Wavelength step size [Angstroms]')
    img.meta['SPECTER'] = (specter.__version__,
                           'https://github.com/desihub/specter')
    img.meta['IN_PSF'] = (io.shorten_filename(psf_file), 'Input spectral PSF')
    img.meta['IN_IMG'] = io.shorten_filename(input_file)
    depend.add_dependencies(img.meta)

    #- Check if input PSF was itself a traceshifted version of another PSF
    orig_psf = None
    if rank == 0:
        try:
            psfhdr = fits.getheader(psf_file, 'PSF')
            orig_psf = psfhdr['IN_PSF']
        except KeyError:
            #- could happen due to PSF format not having "PSF" extension,
            #- or due to PSF header not having 'IN_PSF' keyword.  Either is OK
            pass

    if comm is not None:
        orig_psf = comm.bcast(orig_psf, root=0)

    if orig_psf is not None:
        img.meta['ORIG_PSF'] = orig_psf

    #- If not using MPI, use a single call to each of these and then end this function call
    #  Otherwise, continue on to splitting things up for the different ranks
    if comm is None:
        _extract_and_save(img, psf, specmin, nspec, specmin, wave, raw_wave,
                          fibers, fibermap, args.output, args.model,
                          bundlesize, args, log)

        #- This is it if we aren't running MPI, so return
        return
    #else:
    #    # Continue to the MPI section, which could go under this else statment
    #    # But to save on indentation we'll just pass on to the rest of the function
    #    # since the alternative has already returned
    #    pass

    # Now we divide our spectra into bundles
    checkbundles = set()
    checkbundles.update(
        np.floor_divide(np.arange(specmin, specmax),
                        bundlesize * np.ones(nspec)).astype(int))
    bundles = sorted(checkbundles)
    nbundle = len(bundles)

    bspecmin = {}
    bnspec = {}

    for b in bundles:
        if specmin > b * bundlesize:
            bspecmin[b] = specmin
        else:
            bspecmin[b] = b * bundlesize
        if (b + 1) * bundlesize > specmax:
            bnspec[b] = specmax - bspecmin[b]
        else:
            bnspec[b] = bundlesize

    # Now we assign bundles to processes
    mynbundle = int(nbundle // nproc)
    myfirstbundle = 0
    leftover = nbundle % nproc
    if rank < leftover:
        mynbundle += 1
        myfirstbundle = rank * mynbundle
    else:
        myfirstbundle = ((mynbundle + 1) * leftover) + (mynbundle *
                                                        (rank - leftover))

    # get the root output file
    outpat = re.compile(r'(.*)\.fits')
    outmat = outpat.match(args.output)
    if outmat is None:
        raise RuntimeError(
            "extraction output file should have .fits extension")
    outroot = outmat.group(1)

    outdir = os.path.normpath(os.path.dirname(outroot))

    if rank == 0:
        if not os.path.isdir(outdir):
            os.makedirs(outdir)

    if comm is not None:
        comm.barrier()

    mark_preparation = time.time()
    time_total_extraction = 0.0
    time_total_write_output = 0.0
    failcount = 0

    for b in range(myfirstbundle, myfirstbundle + mynbundle):
        mark_iteration_start = time.time()
        outbundle = "{}_{:02d}.fits".format(outroot, b)
        outmodel = "{}_model_{:02d}.fits".format(outroot, b)

        log.info('extract:  Rank {} extracting {} spectra {}:{} at {}'.format(
            rank,
            os.path.basename(input_file),
            bspecmin[b],
            bspecmin[b] + bnspec[b],
            time.asctime(),
        ))
        sys.stdout.flush()

        #- The actual extraction
        try:
            mark_extraction = _extract_and_save(img, psf, bspecmin[b],
                                                bnspec[b], specmin, wave,
                                                raw_wave, fibers, fibermap,
                                                outbundle, outmodel,
                                                bundlesize, args, log)

            mark_write_output = time.time()

            time_total_extraction += mark_extraction - mark_iteration_start
            time_total_write_output += mark_write_output - mark_extraction
        except:
            # Log the error and increment the number of failures
            log.error(
                "extract:  FAILED bundle {}, spectrum range {}:{}".format(
                    b, bspecmin[b], bspecmin[b] + bnspec[b]))
            exc_type, exc_value, exc_traceback = sys.exc_info()
            lines = traceback.format_exception(exc_type, exc_value,
                                               exc_traceback)
            log.error(''.join(lines))
            failcount += 1
            sys.stdout.flush()

    if comm is not None:
        failcount = comm.allreduce(failcount)

    if failcount > 0:
        # all processes throw
        raise RuntimeError("some extraction bundles failed")

    time_merge = None
    if rank == 0:
        mark_merge_start = time.time()
        mergeopts = ['--output', args.output, '--force', '--delete']
        mergeopts.extend(
            ["{}_{:02d}.fits".format(outroot, b) for b in bundles])
        mergeargs = mergebundles.parse(mergeopts)
        mergebundles.main(mergeargs)

        if args.model is not None:
            model = None
            for b in bundles:
                outmodel = "{}_model_{:02d}.fits".format(outroot, b)
                if model is None:
                    model = fits.getdata(outmodel)
                else:
                    #- TODO: test and warn if models overlap for pixels with
                    #- non-zero values
                    model += fits.getdata(outmodel)

                os.remove(outmodel)

            fits.writeto(args.model, model)
        mark_merge_end = time.time()
        time_merge = mark_merge_end - mark_merge_start

    # Resolve difference timer data

    if type(timing) is dict:
        timing["read_input"] = mark_read_input - mark_start
        timing["preparation"] = mark_preparation - mark_read_input
        timing["total_extraction"] = time_total_extraction
        timing["total_write_output"] = time_total_write_output
        timing["merge"] = time_merge
Beispiel #25
0
def main(args):

    psf_file = args.psf
    input_file = args.input
    specmin = args.specmin
    nspec = args.nspec

    #- Load input files
    psf = load_psf(psf_file)
    img = io.read_image(input_file)

    if nspec is None:
        nspec = psf.nspec
    specmax = specmin + nspec

    camera = img.meta['CAMERA'].lower()     #- b0, r1, .. z9
    spectrograph = int(camera[1])
    fibermin = spectrograph * psf.nspec + specmin

    print('Starting {} spectra {}:{} at {}'.format(os.path.basename(input_file),
        specmin, specmin+nspec, time.asctime()))

    if args.fibermap is not None:
        fibermap = io.read_fibermap(args.fibermap)
        fibermap = fibermap[fibermin:fibermin+nspec]
        fibers = fibermap['FIBER']
    else:
        fibermap = None
        fibers = np.arange(fibermin, fibermin+nspec, dtype='i4')

    #- Get wavelength grid from options
    if args.wavelength is not None:
        wstart, wstop, dw = map(float, args.wavelength.split(','))
    else:
        wstart = np.ceil(psf.wmin_all)
        wstop = np.floor(psf.wmax_all)
        dw = 0.5
        
    wave = np.arange(wstart, wstop+dw/2.0, dw)
    nwave = len(wave)
    bundlesize = args.bundlesize

    #- Confirm that this PSF covers these wavelengths for these spectra
    psf_wavemin = np.max(psf.wavelength(range(specmin, specmax), y=0))
    psf_wavemax = np.min(psf.wavelength(range(specmin, specmax), y=psf.npix_y-1))
    if psf_wavemin > wstart:
        raise ValueError, 'Start wavelength {:.2f} < min wavelength {:.2f} for these fibers'.format(wstart, psf_wavemin)
    if psf_wavemax < wstop:
        raise ValueError, 'Stop wavelength {:.2f} > max wavelength {:.2f} for these fibers'.format(wstop, psf_wavemax)

    #- Print parameters
    print """\
#--- Extraction Parameters ---
input:      {input}
psf:        {psf}
output:     {output}
wavelength: {wstart} - {wstop} AA steps {dw}
specmin:    {specmin}
nspec:      {nspec}
regularize: {regularize}
#-----------------------------\
    """.format(input=input_file, psf=psf_file, output=args.output,
        wstart=wstart, wstop=wstop, dw=dw,
        specmin=specmin, nspec=nspec,
        regularize=args.regularize)

    #- The actual extraction
    results = ex2d(img.pix, img.ivar*(img.mask==0), psf, specmin, nspec, wave,
                 regularize=args.regularize, ndecorr=True,
                 bundlesize=bundlesize, wavesize=args.nwavestep, verbose=args.verbose,
                 full_output=True)
    flux = results['flux']
    ivar = results['ivar']
    Rdata = results['resolution_data']
    chi2pix = results['chi2pix']
    
    mask = np.zeros(flux.shape, dtype=np.uint32)
    mask[results['pixmask_fraction']>0.5] |= specmask.SOMEBADPIX
    mask[results['pixmask_fraction']==1.0] |= specmask.ALLBADPIX
    mask[chi2pix>100.0] |= specmask.BAD2DFIT

    #- Augment input image header for output
    img.meta['NSPEC']   = (nspec, 'Number of spectra')
    img.meta['WAVEMIN'] = (wstart, 'First wavelength [Angstroms]')
    img.meta['WAVEMAX'] = (wstop, 'Last wavelength [Angstroms]')
    img.meta['WAVESTEP']= (dw, 'Wavelength step size [Angstroms]')
    img.meta['SPECTER'] = (specter.__version__, 'https://github.com/desihub/specter')
    img.meta['IN_PSF']  = (_trim(psf_file), 'Input spectral PSF')
    img.meta['IN_IMG']  = (_trim(input_file), 'Input image')

    frame = Frame(wave, flux, ivar, mask=mask, resolution_data=Rdata,
                fibers=fibers, meta=img.meta, fibermap=fibermap,
                chi2pix=chi2pix)

    #- Write output
    io.write_frame(args.output, frame)

    if args.model is not None:
        from astropy.io import fits
        fits.writeto(args.model, results['modelimage'], header=frame.meta, clobber=True)

    print('Done {} spectra {}:{} at {}'.format(os.path.basename(input_file),
        specmin, specmin+nspec, time.asctime()))
Beispiel #26
0
parser = argparse.ArgumentParser(usage="{prog} [options]")
# parser.add_argument("-i", "--input", type=str,  help="input data")
parser.add_argument("-n",
                    "--nproc",
                    type=int,
                    help="number of parallel processes to use")
opts = parser.parse_args()

if opts.nproc is None:
    opts.nproc = multiprocessing.cpu_count() // 2
    print('Using nproc={}'.format(opts.nproc))

#- Load input data
t0 = time.time()
print('{} Reading input data'.format(time.asctime()))
psf = load_psf('psfmodel.fits')
image = fits.getdata('image.fits', 'IMAGE')
image_ivar = fits.getdata('image.fits', 'IVAR')

#- Split data into sub-regions to extract
t1 = time.time()
print('{} Splitting data into subregions'.format(time.asctime()))
wavelengths = np.arange(psf.wmin_all, psf.wmax_all)
nspec = 25
nwave = 200
args = list()
for specmin in range(0, 500, nspec):
    for i in range(0, len(wavelengths), nwave):
        ww = wavelengths[i:i + nwave]
        xyrange = psf.xyrange((specmin, specmin + nspec), ww)
        xmin, xmax, ymin, ymax = xyrange