Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
21 commits
Select commit Hold shift + click to select a range
b1a7a7d
Starting developement on incorporating LyA 1B changes into AMTL
LNapolitano Jul 29, 2025
d7334b4
Adding Handling for Lya1B Actiontype in loop_alt_ledger
LNapolitano Jul 29, 2025
477c09f
Adding tiletracker updating for lya1b action
LNapolitano Jul 30, 2025
cb69e6b
Ensuring LyA1B action is only run for obscon = dark ledgers.
LNapolitano Jul 30, 2025
920a178
Adding optional lya1b flag for lya qso numobs increase action. Fixing…
LNapolitano Jul 31, 2025
532e84a
Adding handling for extension in desitarget.mtl.update_ledger calls
LNapolitano Jul 31, 2025
e0b0c64
Adding Handling for maketwostyle kwarg in desitarget.io.read_targets_…
LNapolitano Jul 31, 2025
087ef1e
Adding additional update_ledget call to update dark ledgers on a dark…
LNapolitano Aug 1, 2025
3381678
Adding reading and merging of dark and dark1b targets for dark1b tiles.
LNapolitano Aug 1, 2025
9e8d61f
Modifying use of read_targets_in_tiles to pass two directories for da…
LNapolitano Aug 6, 2025
67ff6d8
Reverting a small change that broke file path setup for reproducing runs
LNapolitano Aug 7, 2025
d266a77
Fixing dark1b/bright1b file specification for update actions.
LNapolitano Aug 8, 2025
6b50b3f
Changes to update_alt_ledger for 1b tiles observed before lya1b chang…
LNapolitano Nov 4, 2025
5074538
syncing tiletracker update behavior with main branch
LNapolitano Nov 18, 2025
2131a61
Temporarily removing desitarget version checks, no longer necessary
LNapolitano Dec 4, 2025
2552dad
Updating file permissions to match main branch
LNapolitano Jan 28, 2026
7912472
Managing whitespace merge issue
LNapolitano Jan 28, 2026
1630005
Managing whitespace merge issue
LNapolitano Jan 28, 2026
f34cd6d
Removing desitarget_version specification and associated code
LNapolitano Jan 28, 2026
3f7de3b
Adjusting update_ledger logic for 1B programs
LNapolitano Feb 9, 2026
330d330
Updated to reflect make/update tiletracker changes.
LNapolitano Mar 16, 2026
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
6 changes: 4 additions & 2 deletions bin/UpdateAltMTLParallel.py
Original file line number Diff line number Diff line change
Expand Up @@ -32,7 +32,7 @@ def procFunc(nproc):
#then generate an update tiletracker with entries from tiles in the range [previous endDate, new endData]
#finally, the existing tiletracker will be merged with the update tiletracker, and files renamed such that the merged tiletracker is used by loop_alt_ledger
amt.updateTileTracker(altmtldir, args.endDate, survey = args.survey, obscon = args.obscon)

amt.loop_alt_ledger(obscon = args.obscon, survey = args.survey, mtldir = '/global/cfs/cdirs/desi/survey/ops/surveyops/trunk/mtl/', zcatdir = '/global/cfs/cdirs/desi/spectro/redux/daily/', altmtlbasedir = args.altMTLBaseDir, ndirs = None, numobs_from_ledger = True, secondary = False, getosubp = False, quickRestart = False, multiproc = True, nproc = nproc, singleDate = False, redoFA = False, mock = args.mock, targets = None, debug = False, verbose = False, reproducing = args.reproducing)

return
Expand All @@ -41,4 +41,6 @@ def procFunc(nproc):
inds = range(args.nproc)

p = Pool()
result = p.map(procFunc,inds)
result = p.map(procFunc,inds)
p.close()
p.join()
148 changes: 108 additions & 40 deletions py/LSS/SV3/altmtltools.py
100644 → 100755
Original file line number Diff line number Diff line change
Expand Up @@ -27,13 +27,14 @@
from desitarget.cuts import random_fraction_of_trues
from desitarget.mtl import get_mtl_dir, get_mtl_tile_file_name,get_mtl_ledger_format
from desitarget.mtl import get_zcat_dir, get_ztile_file_name, tiles_to_be_processed
from desitarget.mtl import make_zcat,survey_data_model,update_ledger, get_utc_date
from desitarget.mtl import make_zcat,survey_data_model,update_ledger, get_utc_date, update_lya_1b

from desitarget.targets import initial_priority_numobs, decode_targetid
from desitarget.targetmask import obsconditions, obsmask
from desitarget.targetmask import desi_mask, bgs_mask, mws_mask, zwarn_mask

from desiutil.log import get_logger
log = get_logger()

import fitsio
import LSS.common_tools as common
Expand Down Expand Up @@ -63,11 +64,8 @@
from datetime import datetime, timedelta
import glob


pr = cProfile.Profile()

log = get_logger()

#os.environ['DESIMODEL'] = '/global/common/software/desi/cori/desiconda/current/code/desimodel/master'
#os.environ['DESIMODEL'] = '/global/common/software/desi/perlmutter/desiconda/current/code/desimodel/main'

Expand Down Expand Up @@ -500,8 +498,12 @@ def updateTileTracker(altmtldir, endDate, survey = 'main', obscon = 'DARK'):
print('New end date is the same as the current end date, update will not be performed')
return

#only pass the lya1b keyword if prev_endDate is before 20250721 and new enddate is after 20250721
#is this effective? need to be sure we don't write multiple lya1b actions
upd_lya1b = (prev_endDate <= 20250721) & (endDate > 20250721)

#generate TileTracker update file
makeTileTracker(altmtldir, survey, obscon, startDate = prev_endDate, endDate = endDate, update_only=True)
makeTileTracker(altmtldir, survey, obscon, startDate = prev_endDate, endDate = endDate, update_only=True, lya1b = upd_lya1b)

#read into memory
update_TT = Table.read(TileTrackerFN.replace('TileTracker','TileTracker-Update{}'.format(endDate)))
Expand Down Expand Up @@ -533,7 +535,7 @@ def updateTileTracker(altmtldir, endDate, survey = 'main', obscon = 'DARK'):
def makeTileTrackerFN(dirName, survey, obscon):
return dirName + '/{0}survey-{1}obscon-TileTracker.ecsv'.format(survey, obscon.upper())
def makeTileTracker(altmtldir, survey = 'main', obscon = 'DARK', startDate = None,
endDate = None, overwrite = True, update_only = False):
endDate = None, overwrite = True, update_only = False, lya1b = True):
"""Create action file which orders all actions to do with AMTL in order
in which real survey did them.

Expand All @@ -550,6 +552,16 @@ def makeTileTracker(altmtldir, survey = 'main', obscon = 'DARK', startDate = Non
Used to look up the correct ledger, in combination with `obscon`.
Options are ``'main'`` and ``'svX``' (where X is 1, 2, 3 etc.)
for the main survey and different iterations of SV, respectively.
update_only : :class:`bool`, optional, defaults to False
Used when only actions since the startdate are needed, for example
in the updateTileTracker function.
lya1b : :class:`bool`, optional, defaults to True
Used to determine if an action should be created to mimic the lya1b
numobs increase. (see: https://github.com/desihub/desitarget/pull/845/
for details.) Only runs for obscon = dark and if there are actions
at dates > 2025-07-21. Should be set to false in only extremely specific
scenarios, when one is not trying to mimic real survey decisions.



Returns
Expand Down Expand Up @@ -585,8 +597,8 @@ def makeTileTracker(altmtldir, survey = 'main', obscon = 'DARK', startDate = Non

TSS = Table.read(TSSFN)


MTLDTFN = '/global/cfs/cdirs/desi/survey/ops/surveyops/trunk/mtl/mtl-done-tiles.ecsv'

MTLDT = Table.read(MTLDTFN)

#tiles-specstatus file filtered to only matching obscon and surveySURVEY FAPRGRM
Expand All @@ -596,26 +608,32 @@ def makeTileTracker(altmtldir, survey = 'main', obscon = 'DARK', startDate = Non

#if we only want entries from tiles within the [startDate, endDate] window
if update_only:
# 20260303 LGN Changing behavior to work with makeTileTracker refactor
# 20260303 LGN We now longer check against the end date based on MTLDoneTiles, just start date
# 20260303 LGN This allows us to select actions fa'd before, but updated after the end date

#change output name to avoid overwriting the existing tile tracker
TileTrackerFN = TileTrackerFN.replace('TileTracker','TileTracker-Update{}'.format(endDate))
#convert dates into datetime objects
startDate_dt = datetime.strptime(str(startDate), "%Y%m%d")
endDate_dt = datetime.strptime(str(endDate), "%Y%m%d")
#endDate_dt = datetime.strptime(str(endDate), "%Y%m%d")

#format into strings for comparisson to MTL DT timestamp column
#note we increment startDate by one day to avoid overlapping on previous endDate
#note we increment endDate by one day to catch tiles from the final day (less than or equal to doesn't work due to column datatype comparison)
startDate_frm = (startDate_dt+timedelta(days=1)).strftime("%Y-%m-%d")
endDate_frm = (endDate_dt+timedelta(days=1)).strftime("%Y-%m-%d")
#endDate_frm = (endDate_dt+timedelta(days=1)).strftime("%Y-%m-%d")

#select relevant tiles using timestamps in mtl done tiles file, only interested in tiles matching survey and program
#overwrite iterand TilesSel (note we still use the initial determination of TilesSel to check prog/survey match)
time_sel = (MTLDT['TIMESTAMP'] > startDate_frm) & (MTLDT['TIMESTAMP'] < endDate_frm) & (np.isin(MTLDT['TILEID'],TilesSel))
time_sel = (MTLDT['TIMESTAMP'] > startDate_frm) & (np.isin(MTLDT['TILEID'],TilesSel))
TilesSel = np.unique(MTLDT[time_sel]['TILEID'])

TileIDs = []
TypeOfActions = []
TimesOfActions = []
#times for fa actions come from the fiberassign-{tile}.fits file
#times for update actions come from the mtl done tiles file
doneFlag = []
archiveDates = []

Expand All @@ -626,17 +644,18 @@ def makeTileTracker(altmtldir, survey = 'main', obscon = 'DARK', startDate = Non

thisTileMTLDT = MTLDT[MTLDT['TILEID'] == tileid]

if len(thisTileMTLDT) > 1:
thisTileMTLDT.sort('TIMESTAMP')
elif len(thisTileMTLDT) == 0:
# 20260302 LGN Rewriting to remove ARCHIVEDATE check.
# 20260302 LGN We want fa actions before the endDate to be included.
if len(thisTileMTLDT) == 0:
continue
elif len(thisTileMTLDT) > 1:
thisTileMTLDT.sort('TIMESTAMP')
else:
log.info(len(thisTileMTLDT))
log.info(thisTileMTLDT['ARCHIVEDATE'])
log.info(thisTileMTLDT['ARCHIVEDATE'][0])
log.info(type(thisTileMTLDT['ARCHIVEDATE'][0]))
if thisTileMTLDT['ARCHIVEDATE'][0] > int(endDate):
continue

reprocFlag = False
thisFAFN = FABaseDir + f'/{ts[0:3]}/fiberassign-{ts}.fits'

Expand Down Expand Up @@ -676,6 +695,21 @@ def makeTileTracker(altmtldir, survey = 'main', obscon = 'DARK', startDate = Non
doneFlag.append(False)
archiveDates.append(update['ARCHIVEDATE'])
reprocFlag = True


#LGN 07/29/25: adding new special action for the LyA QSO NUMOBS increase
#LGN This runs for all dark time surveys with actions at times later than 2025-07-21
#LGN unless the lya1b flag is set to false. Only change this flag if you are certain
#LGN you don't want to mimic real survey decisions.
if (lya1b) and (obscon.lower() == 'dark') and (max(TimesOfActions) > '2025-07-21T23:36:04+00:00'):
log.info('Adding QSO NUMOBS Increase Action')
TileIDs.append(-1)
TypeOfActions.append('lya1b')
TimesOfActions.append('2025-07-21T23:36:04+00:00')
doneFlag.append(False)
archiveDates.append(20250721)


ActionList = [TileIDs, TypeOfActions, TimesOfActions, doneFlag, archiveDates]
t = Table(ActionList,
names=('TILEID', 'ACTIONTYPE', 'ACTIONTIME', 'DONEFLAG', 'ARCHIVEDATE'),
Expand Down Expand Up @@ -1312,7 +1346,11 @@ def make_fibermaps(altmtldir, OrigFAs, AltFAs, AltFAs2, TSs, fadates, tiles, sur
log.info('write_amtl_tile_tracker retval = {0}'.format(retval))

return A2RMap, R2AMap
def update_alt_ledger(altmtldir,althpdirname, altmtltilefn, actions, survey = 'sv3', obscon = 'dark', today = None,

# LGN 20260220 Adding tiletracker as a passed argument
# LGN 20260220 Necessary to check the fa date of an update action
# LGN 20260220 In order to check if we should pass the ext keyword
def update_alt_ledger(altmtldir,althpdirname, altmtltilefn, actions, tiletracker, survey = 'sv3', obscon = 'dark', today = None,
getosubp = False, zcatdir = None, mock = False, numobs_from_ledger = True, targets = None, verbose = False, debug = False):
if verbose or debug:
log.info('today = {0}'.format(today))
Expand Down Expand Up @@ -1381,27 +1419,45 @@ def update_alt_ledger(altmtldir,althpdirname, altmtltilefn, actions, survey = '
msg = "Update state for {} targets".format(ntargs)
msg += " (the zcats also contain {} skies with +ve TARGETIDs)".format(nsky)
log.info(msg)

# setting up update info
didUpdateHappen = False
if obscon.lower() == 'dark1b' or obscon.lower() == 'bright1b':
log.info('setting 1B flag for update')
is_1b = True

# LGN 20260220 In order to determine if we pass ext=True we need to check the fiberassign date associated with this update
#fa_time = tiletracker[(tiletracker['TILEID'] == t['TILEID']) & (tiletracker['ACTIONTYPE'] == 'fa')]['ACTIONTIME']
if t['ACTIONTIME'] < '2025-07-21T23:36:04+00:00':
log.info('setting ext flag = False for 1B tile')
is_ext = False
else:
log.info('setting ext flag = True for update')
is_ext = True
else:
is_1b = False

# ADM update the appropriate ledger.
if mock:

if targets is None:
raise ValueError('If processing mocks, you MUST specify a target file')
log.info('update loc a')
update_ledger(althpdirname, altZCat, obscon=obscon.upper(),
numobs_from_ledger=numobs_from_ledger, tabform='ascii.ecsv')#, targets = targets)
didUpdateHappen = True
elif targets is None:
log.info('update loc b')
update_ledger(althpdirname, altZCat, obscon=obscon.upper(),
numobs_from_ledger=numobs_from_ledger)
didUpdateHappen = True
# LGN 20250909 Revising this section to update for 1B changes and simplifying
if mock and targets is None:
raise ValueError('If processing mocks, you MUST specify a target file')

if is_1b:
#getting abbreviated obscon/path for non 1B survey (i.e. dark1b -> dark)
althpdirname_short = os.path.join(os.path.dirname(althpdirname), os.path.basename(althpdirname).replace('1b', ''))
obscon_short = obscon.replace('1B','')

# LGN: CHECK WITH AURELIO ABOUT TARGETS KEYWORD FOR MOCKS

#Updating the non-1b ledger
update_ledger(althpdirname_short, altZCat, obscon=obscon_short.upper(),numobs_from_ledger=numobs_from_ledger, tabform='ascii.ecsv', ext=is_ext, targets = targets)
#Updating the 1b ledger
update_ledger(althpdirname, altZCat, obscon=obscon.upper(),numobs_from_ledger=numobs_from_ledger, tabform='ascii.ecsv', ext=is_ext, targets = targets)

else:
log.info('update loc c')
update_ledger(althpdirname, altZCat, obscon=obscon.upper(),
numobs_from_ledger=numobs_from_ledger, targets = targets)
didUpdateHappen = True
assert(didUpdateHappen)
#Updating ledger (No ext keyword)
update_ledger(althpdirname, altZCat, obscon=obscon.upper(),numobs_from_ledger=numobs_from_ledger, tabform='ascii.ecsv', targets = targets)

if verbose or debug:
log.info('if main, should sleep 1 second')
#thisUTCDate = get_utc_date(survey=survey)
Expand Down Expand Up @@ -1549,7 +1605,6 @@ def loop_alt_ledger(obscon, survey='sv3', zcatdir=None, mtldir=None,
### JL - End of directory/loop variable construction ###



if quickRestart:
raise NotImplementedError('There is no way the quick restart will work properly post refactor.')
quickRestartFxn(ndirs = ndirs, altmtlbasedir = altmtlbasedir, survey = survey, obscon = obscon, multiproc = multiproc, nproc = nproc)
Expand Down Expand Up @@ -1594,14 +1649,17 @@ def loop_alt_ledger(obscon, survey='sv3', zcatdir=None, mtldir=None,
actionList = actionList[:1]

for action in actionList:

if action['ACTIONTYPE'] == 'fa':
OrigFAs, AltFAs, AltFAs2, TSs, fadates, tiles = do_fiberassignment(altmtldir, [action], survey = survey, obscon = obscon ,verbose = verbose, debug = debug, getosubp = getosubp, redoFA = redoFA, mock = mock, reproducing = reproducing)
assert(len(OrigFAs))
A2RMap, R2AMap = make_fibermaps(altmtldir, OrigFAs, AltFAs, AltFAs2, TSs, fadates, tiles, changeFiberOpt = changeFiberOpt, verbose = verbose, debug = debug, survey = survey , obscon = obscon, getosubp = getosubp, redoFA = redoFA )


# LGN 20260220 Adding tiletracker as a passed argument
# LGN 20260220 Necessary to check the fa date of an update action
# LGN 20260220 In order to check if we should pass the ext keyword
elif action['ACTIONTYPE'] == 'update':
althpdirname, altmtltilefn, ztilefn, tiles = update_alt_ledger(altmtldir,althpdirname, altmtltilefn, action, survey = survey, obscon = obscon ,getosubp = getosubp, zcatdir = zcatdir, mock = mock, numobs_from_ledger = numobs_from_ledger, targets = targets, verbose = verbose, debug = debug)
althpdirname, altmtltilefn, ztilefn, tiles = update_alt_ledger(altmtldir,althpdirname, altmtltilefn, action, altMTLTileTracker, survey = survey, obscon = obscon ,getosubp = getosubp, zcatdir = zcatdir, mock = mock, numobs_from_ledger = numobs_from_ledger, targets = targets, verbose = verbose, debug = debug)

elif action['ACTIONTYPE'] == 'reproc':
#returns timedict
Expand All @@ -1610,9 +1668,17 @@ def loop_alt_ledger(obscon, survey='sv3', zcatdir=None, mtldir=None,
retval = reprocess_alt_ledger(altmtldir, action, obscon=obscon, survey = survey)
if debug or verbose:
log.info(f'retval = {retval}')

#LGN 07/29/25: Adding new LyA1B case
elif action['ACTIONTYPE'] == 'lya1b':
log.info('Running LyA1B Ledger Update')
#run update on the realization
update_lya_1b(obscon=obscon, mtldir=altmtldir, timestamp=action['ACTIONTIME'], donefile=False)
#record succesful update in ledger
retval = write_amtl_tile_tracker(altmtldir, [action], obscon = obscon, survey = survey)

else:
raise ValueError('actiontype must be `fa`, `update`, or `reproc`.')
raise ValueError('actiontype must be `fa`, `update`, `reproc` or `lya1b`.')
#retval = write_amtl_tile_tracker(altmtldir, None, None, today, obscon = obscon, survey = survey, mode = 'endofday')
#log.info('write_amtl_tile_tracker retval = {0}'.format(retval))

Expand Down Expand Up @@ -2384,7 +2450,9 @@ def write_amtl_tile_tracker(dirname, tiles, obscon = 'dark', survey = 'main'):
tileid = t['TILEID']
#reprocFlag = t['REPROCFLAG']
actionType = t['ACTIONTYPE']
cond = (TileTracker['TILEID'] == tileid) & (TileTracker['ACTIONTYPE'] == actionType)
#LGN 20251103 - Adding actiontime as an additional condition due to the existance of tiles with multiple reproc actions
actionTime = t['ACTIONTIME']
cond = (TileTracker['TILEID'] == tileid) & (TileTracker['ACTIONTYPE'] == actionType) & (TileTracker['ACTIONTIME'] == actionTime)
log.info('for tile {0}, number of matching tiles = {1}'.format(tileid, np.sum(cond)))
#debugTrap = np.copy(TileTracker[dateKey])
TileTracker['DONEFLAG'][cond] = True
Expand Down
Loading