Skip to content

Commit

Permalink
Merge 9a10117 into bf971a0
Browse files Browse the repository at this point in the history
  • Loading branch information
moustakas committed Dec 30, 2022
2 parents bf971a0 + 9a10117 commit b92caa2
Show file tree
Hide file tree
Showing 9 changed files with 2,553 additions and 1,767 deletions.
5 changes: 3 additions & 2 deletions bin/fastphot
Original file line number Diff line number Diff line change
Expand Up @@ -5,5 +5,6 @@ Example call:
fastphot /global/cfs/cdirs/desi/spectro/redux/daily/tiles/80608/20201215/zbest-9-80608-20201215.fits -o fastphot.fits --ntargets 2 --mp 1
"""
from fastspecfit.fastspecfit import fastphot
fastphot(comm=None)
if __name__ == '__main__':
from fastspecfit.fastspecfit import fastphot
fastphot(comm=None)
5 changes: 3 additions & 2 deletions bin/fastspec
Original file line number Diff line number Diff line change
Expand Up @@ -5,5 +5,6 @@ Example call:
fastspec /global/cfs/cdirs/desi/spectro/redux/daily/tiles/80608/20201215/zbest-9-80608-20201215.fits -o fastspec.fits --ntargets 2 --mp 1
"""
from fastspecfit.fastspecfit import fastspec
fastspec(comm=None)
if __name__ == '__main__':
from fastspecfit.fastspecfit import fastspec
fastspec(comm=None)
73 changes: 62 additions & 11 deletions bin/fastspecfit-qa
Original file line number Diff line number Diff line change
Expand Up @@ -33,11 +33,15 @@ def parse(options=None):
parser.add_argument('--redrockfile-prefix', type=str, default='redrock-', help='Prefix of the input Redrock file name(s).')
parser.add_argument('--specfile-prefix', type=str, default='coadd-', help='Prefix of the spectral file(s).')
parser.add_argument('--qnfile-prefix', type=str, default='qso_qn-', help='Prefix of the QuasarNet afterburner file(s).')
parser.add_argument('--mapdir', type=str, default=None, help='Optional directory name for the dust maps.')
parser.add_argument('--dr9dir', type=str, default=None, help='Optional directory name for the DR9 photometry.')

parser.add_argument('--targetids', type=str, default=None, help='Comma-separated list of target IDs to process.')
parser.add_argument('-n', '--ntargets', type=int, help='Number of targets to process in each file.')
parser.add_argument('--firsttarget', type=int, default=0, help='Index of first object to to process in each file (0-indexed).')
parser.add_argument('--mp', type=int, default=1, help='Number of multiprocessing processes per MPI rank or node.')
parser.add_argument('--nolegend', action='store_true', help='Exclude legends from QA.')
parser.add_argument('--webqa', action='store_true', help='Build QA for the web-app.')
parser.add_argument('--outprefix', default=None, type=str, help='Optional prefix for output filename.')
parser.add_argument('-o', '--outdir', default='.', type=str, help='Full path to desired output directory.')

Expand Down Expand Up @@ -77,8 +81,41 @@ def main(args=None, comm=None):
if not os.path.isfile(args.fastfitfile[0]):
log.warning('File {} not found.'.format(args.fastfitfile[0]))
return

fastfit, metadata, coadd_type, fastphot = read_fastspecfit(args.fastfitfile[0])
if args.webqa:
# This is not great coding, but when building the webqa, assume that a
# companion fastphot- file exists and, if not, quit.
if 'fastspec-' not in args.fastfitfile[0]:
errmsg = 'For --webqa, input fastfitfile must be have the prefix "fastspec-"'
log.critical(errmsg)
raise IOError(errmsg)

fastphotfile = args.fastfitfile[0].replace('fastspec-', 'fastphot-').replace('.gz', '')
if not os.path.isfile(fastphotfile):
errmsg = '--webqa fastphot file {} not found.'.format(fastphotfile)
log.critical(errmsg)
raise IOError(errmsg)

webphot, _, _, _ = read_fastspecfit(fastphotfile)
if not np.all(fastfit['TARGETID'] == webphot['TARGETID']):
errmsg = 'Mismatch in fastspec and fastphot TARGETIDs'
log.critical(errmsg)
raise Valuerror(errmsg)

# merge the results
from astropy.table import hstack

joinkeys = ['SURVEY', 'PROGRAM', 'TARGETID']
if coadd_type == 'healpix':
joinkeys += ['HEALPIX']
else:
joinkeys += ['NIGHT', 'FIBER', 'TILEID']
assert(np.all(fastfit[joinkeys] == webphot[joinkeys]))

webphot.remove_columns(joinkeys)
fastfit = hstack((fastfit, webphot), table_names=['SPEC', 'PHOT'])

# parse the targetids optional input
if args.targetids:
targetids = [int(x) for x in args.targetids.split(',')]
Expand All @@ -88,25 +125,37 @@ def main(args=None, comm=None):
return
fastfit = fastfit[keep]
metadata = metadata[keep]

if args.webqa:
webphot = webphot[keep]

if args.ntargets is not None:
keep = np.arange(args.ntargets) + args.firsttarget
log.info('Keeping {} targets.'.format(args.ntargets))
fastfit = fastfit[keep]
metadata = metadata[keep]

fastfit, metadata = select(fastfit, metadata, coadd_type, healpixels=args.healpix,
tiles=args.tile, nights=args.night)
if args.webqa:
webphot = webphot[keep]

if args.webqa:
keep = select(fastfit, metadata, coadd_type, healpixels=args.healpix,
tiles=args.tile, nights=args.night, return_index=True)
fastfit = fastfit[keep]
metadata = metadata[keep]
webphot = webphot[keep]
else:
fastfit, metadata = select(fastfit, metadata, coadd_type, healpixels=args.healpix,
tiles=args.tile, nights=args.night)

if coadd_type == 'custom' and args.redrockfiles is None:
errmsg = 'redrockfiles input is required if coadd_type==custom'
log.critical(errmsg)
raise IOError(errmsg)

# Initialize the continuum- and emission-line fitting classes.
t0 = time.time()
CFit = ContinuumFit(nolegend=args.nolegend)
EMFit = EMLineFit(nolegend=args.nolegend)
Spec = DESISpectra(redux_dir=args.redux_dir)
CFit = ContinuumFit(nolegend=args.nolegend, mapdir=args.mapdir)
EMFit = EMLineFit(nolegend=args.nolegend, mapdir=args.mapdir)
Spec = DESISpectra(redux_dir=args.redux_dir, dr9dir=args.dr9dir)
log.info('Initializing the classes took: {:.2f} sec'.format(time.time()-t0))

if args.outdir:
Expand All @@ -116,22 +165,24 @@ def main(args=None, comm=None):
def _wrap_qa(redrockfile, indx=None):
if indx is None:
indx = np.arange(len(fastfit))

targetids = fastfit['TARGETID'][indx]
Spec.select(redrockfiles=redrockfile, targetids=targetids,
redrockfile_prefix=args.redrockfile_prefix,
specfile_prefix=args.specfile_prefix,
qnfile_prefix=args.qnfile_prefix)
data = Spec.read_and_unpack(CFit, fastphot=fastphot, synthphot=True, remember_coadd=True)
qaargs = [(CFit, EMFit, data[igal], fastfit[indx[igal]], metadata[indx[igal]],
coadd_type, fastphot, args.outdir, args.outprefix) for igal in np.arange(len(indx))]
data = Spec.read_and_unpack(CFit, fastphot=fastphot, synthphot=True)

qaargs = [(CFit, EMFit, data[igal], fastfit[indx[igal]], metadata[indx[igal]],
coadd_type, fastphot, args.outdir, args.outprefix, args.webqa)
for igal in np.arange(len(indx))]
if args.mp > 1:
import multiprocessing
with multiprocessing.Pool(args.mp) as P:
P.map(_desiqa_one, qaargs)
else:
[desiqa_one(*_qaargs) for _qaargs in qaargs]

t0 = time.time()
if coadd_type == 'healpix':
allspecprods = metadata['SPECPROD'].data
Expand Down
39 changes: 25 additions & 14 deletions bin/mpi-fastspecfit
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,8 @@ mpi-fastspecfit --merge --specprod fuji --fastphot
mpi-fastspecfit --mp 32 --makeqa --specprod fuji --dry-run
mpi-fastspecfit --mp 32 --makeqa --specprod fuji --fastphot --dry-run
mpi-fastspecfit --mp 32 --webqa
"""
import pdb # for debugging

Expand All @@ -24,7 +26,7 @@ from desiutil.log import get_logger
log = get_logger()

def run_fastspecfit(args, comm=None, fastphot=False, specprod_dir=None,
makeqa=False, outdir_data='.', outdir_html='.'):
makeqa=False, webqa=False, outdir_data='.', outdir_html='.'):

import sys, subprocess
from fastspecfit.mpi import backup_logs, plan
Expand All @@ -41,6 +43,7 @@ def run_fastspecfit(args, comm=None, fastphot=False, specprod_dir=None,
comm=comm, specprod=args.specprod, specprod_dir=specprod_dir,
coadd_type=args.coadd_type, survey=args.survey, program=args.program,
healpix=args.healpix, tile=args.tile, night=args.night,
makeqa=args.makeqa, webqa=args.webqa,
fastphot=fastphot, outdir_data=outdir_data, outdir_html=outdir_html,
overwrite=args.overwrite)
log.info('Planning took {:.2f} sec'.format(time.time() - t0))
Expand All @@ -55,7 +58,6 @@ def run_fastspecfit(args, comm=None, fastphot=False, specprod_dir=None,

#if comm:
# comm.barrier()

sys.stdout.flush()

# all done
Expand All @@ -70,13 +72,15 @@ def run_fastspecfit(args, comm=None, fastphot=False, specprod_dir=None,
log.debug('Rank {} started at {}'.format(rank, time.asctime()))
sys.stdout.flush()

if args.makeqa:
# hack--the desired output directories are in the 'zbestfiles' variable!
# note: by default don't render the legend
if fastphot:
cmd = 'fastspecfit-qa --fastphotfile {} --nolegend -o {} --mp {}'.format(outfiles[ii], zbestfiles[ii], args.mp)
else:
cmd = 'fastspecfit-qa --fastspecfile {} --nolegend -o {} --mp {}'.format(outfiles[ii], zbestfiles[ii], args.mp)
# With --webqa and --makeqa the desired output directories are in the
# 'zbestfiles' variable.
if args.webqa or args.makeqa:
cmd = 'fastspecfit-qa {} -o {} --mp {}'.format(outfiles[ii], zbestfiles[ii], args.mp)
if args.webqa:
cmd += ' --webqa'
## Note: by default don't render the legend.
#if args.makeqa:
# cmd += ' --nolegend'
if args.ntargets:
cmd += ' --ntargets {}'.format(args.ntargets)
else:
Expand All @@ -90,7 +94,12 @@ def run_fastspecfit(args, comm=None, fastphot=False, specprod_dir=None,
if args.ntargets:
cmd += ' --ntargets {}'.format(args.ntargets)

logfile = outfiles[ii].replace('.gz', '').replace('.fits', '.log')
if args.webqa or args.makeqa:
logfile = zbestfiles[ii].replace('.gz', '').replace('.fits', '.log')
if args.webqa:
logfile = logfile.replace('fastspec-', 'fastfit-')
else:
logfile = outfiles[ii].replace('.gz', '').replace('.fits', '.log')
assert(logfile != outfiles[ii])

log.info('Rank {}, ntargets={}: {}'.format(rank, ntargets[ii], cmd))
Expand Down Expand Up @@ -170,16 +179,17 @@ def main():
parser.add_argument('--merge', action='store_true', help='Merge all individual catalogs (for a given survey and program) into one large file.')
parser.add_argument('--mergeall', action='store_true', help='Merge all the individual merged catalogs into a single merged catalog.')
parser.add_argument('--makeqa', action='store_true', help='Build QA in parallel.')
parser.add_argument('--webqa', action='store_true', help='Build QA for the web-app.')

parser.add_argument('--overwrite', action='store_true', help='Overwrite any existing output files.')
parser.add_argument('--plan', action='store_true', help='Plan how many nodes to use and how to distribute the targets.')
parser.add_argument('--nompi', action='store_true', help='Do not use MPI parallelism.')
parser.add_argument('--nolog', action='store_true', help='Do not write to the log file.')
parser.add_argument('--dry-run', action='store_true', help='Generate but do not run commands.')

parser.add_argument('--outdir-html', default='/global/cfs/cdirs/desi/users/ioannis/fastspecfit',
parser.add_argument('--outdir-html', default='/global/cfs/cdirs/desi/users/ioannis/fastspecfit-dev',
type=str, help='Base output HTML directory.')
parser.add_argument('--outdir-data', default='/global/cfs/cdirs/desi/spectro/fastspecfit',
parser.add_argument('--outdir-data', default='/global/cfs/cdirs/desi/spectro/fastspecfit-dev',
type=str, help='Base output data directory.')

specprod_dir = None
Expand Down Expand Up @@ -207,7 +217,7 @@ def main():
overwrite=args.overwrite, fastphot=args.fastphot, supermerge=args.mergeall,
mp=args.mp)
return

if args.plan:
if comm is None:
rank = 0
Expand All @@ -217,11 +227,12 @@ def main():
plan(comm=comm, specprod=args.specprod, specprod_dir=specprod_dir,
coadd_type=args.coadd_type, survey=args.survey, program=args.program,
healpix=args.healpix, tile=args.tile, night=args.night,
makeqa=args.makeqa, webqa=args.webqa,
fastphot=args.fastphot, outdir_data=args.outdir_data,
outdir_html=args.outdir_html, overwrite=args.overwrite)
else:
run_fastspecfit(args, comm=comm, fastphot=args.fastphot, specprod_dir=specprod_dir,
makeqa=args.makeqa, outdir_data=args.outdir_data,
makeqa=args.makeqa, webqa=args.webqa, outdir_data=args.outdir_data,
outdir_html=args.outdir_html)

if __name__ == '__main__':
Expand Down
Loading

0 comments on commit b92caa2

Please sign in to comment.