• Home
  • Features
  • Pricing
  • Docs
  • Announcements
  • Sign In

desihub / desispec / 8397945773

23 Mar 2024 12:22AM UTC coverage: 28.132% (+3.0%) from 25.113%
8397945773

Pull #2187

github

akremin
bug fixes in old sub scripts
Pull Request #2187: Introduce desi_proc_night to unify and simplify processing scripts

768 of 1152 new or added lines in 21 files covered. (66.67%)

1071 existing lines in 14 files now uncovered.

13184 of 46864 relevant lines covered (28.13%)

0.28 hits per line

Source File
Press 'n' to go to next uncovered line, 'b' for previous

7.12
/py/desispec/scripts/submit_night.py
1
"""
2
desispec.scripts.submit_night
3
=============================
4

5
"""
6
from desispec.workflow.science_selection import get_completed_tiles
1✔
7
from desiutil.log import get_logger
1✔
8
import numpy as np
1✔
9
import os
1✔
10
import sys
1✔
11
import time
1✔
12
import re
1✔
13
from astropy.table import Table, vstack
1✔
14
## Import some helper functions, you can see their definitions by uncomenting the bash shell command
15
from desispec.workflow.tableio import load_tables, write_table
1✔
16
from desispec.workflow.utils import pathjoin, sleep_and_report
1✔
17
from desispec.workflow.timing import what_night_is_it
1✔
18
from desispec.workflow.exptable import get_exposure_table_path, \
1✔
19
    get_exposure_table_name, get_last_step_options
20
from desispec.workflow.proctable import default_obstypes_for_proctable, get_processing_table_path, \
1✔
21
                                        get_processing_table_name, erow_to_prow, table_row_to_dict, \
22
                                        default_prow
23
from desispec.workflow.processing import parse_previous_tables, get_type_and_tile, \
1✔
24
                                        define_and_assign_dependency, create_and_submit, \
25
                                        checkfor_and_submit_joint_job, submit_tilenight_and_redshifts
26
from desispec.workflow.queue import update_from_queue, any_jobs_not_complete
1✔
27
from desispec.workflow.desi_proc_funcs import get_desi_proc_batch_file_path
1✔
28
from desispec.workflow.redshifts import read_minimal_exptables_columns
1✔
29
from desispec.io.util import decode_camword, difference_camwords, create_camword
1✔
30

31
def submit_night(night, proc_obstypes=None, z_submit_types=None, queue='realtime',
1✔
32
                 reservation=None, system_name=None,
33
                 exp_table_path=None, proc_table_path=None, tab_filetype='csv',
34
                 dry_run_level=0, dry_run=False, no_redshifts=False, error_if_not_available=True,
35
                 append_to_proc_table=False, ignore_proc_table_failures = False,
36
                 dont_check_job_outputs=False, dont_resubmit_partial_jobs=False,
37
                 tiles=None, surveys=None, laststeps=None, use_tilenight=False,
38
                 all_tiles=False, specstatus_path=None, use_specter=False,
39
                 do_cte_flat=False, complete_tiles_thrunight=None,
40
                 all_cumulatives=False):
41
    """
42
    Creates a processing table and an unprocessed table from a fully populated exposure table and submits those
43
    jobs for processing (unless dry_run is set).
44

45
    Args:
46
        night (int): The night of data to be processed. Exposure table must exist.
47
        proc_obstypes (list or np.array, optional): A list of exposure OBSTYPE's that should be processed (and therefore
48
            added to the processing table).
49
        z_submit_types (list of str or comma-separated list of str, optional): The "group" types of redshifts that should be
50
            submitted with each exposure. If not specified, default for daily processing is
51
            ['cumulative', 'pernight-v0']. If false, 'false', or [], then no redshifts are submitted.
52
        queue (str, optional): The name of the queue to submit the jobs to. Default is "realtime".
53
        reservation (str, optional): The reservation to submit jobs to. If None, it is not submitted to a reservation.
54
        system_name (str): batch system name, e.g. cori-haswell, cori-knl, perlmutter-gpu
55
        exp_table_path (str): Full path to where to exposure tables are stored, WITHOUT the monthly directory included.
56
        proc_table_path (str): Full path to where to processing tables to be written.
57
        tab_filetype (str, optional): The file extension (without the '.') of the exposure and processing tables.
58
        dry_run_level (int, optional): If nonzero, this is a simulated run. If dry_run=1 the scripts will be written but not submitted.
59
            If dry_run=2, the scripts will not be written nor submitted. Logging will remain the same
60
            for testing as though scripts are being submitted. Default is 0 (false).
61
        dry_run (bool, optional): When to run without submitting scripts or not. If dry_run_level is defined, then it over-rides
62
            this flag. dry_run_level not set and dry_run=True, dry_run_level is set to 2 (no scripts
63
            generated or run). Default for dry_run is False.
64
        no_redshifts (bool, optional): Whether to submit redshifts or not. If True, redshifts are not submitted.
65
        error_if_not_available (bool, optional): Default is True. Raise as error if the required exposure table doesn't exist,
66
            otherwise prints an error and returns.
67
        append_to_proc_table (bool, optional): True if you want to submit jobs even if a processing table already exists.
68
            Otherwise jobs will be appended to it. Default is False
69
        ignore_proc_table_failures (bool, optional): True if you want to submit other jobs even the loaded
70
            processing table has incomplete jobs in it. Use with caution. Default is False.
71
        dont_check_job_outputs (bool, optional): Default is False. If False, the code checks for the existence of the expected final
72
            data products for the script being submitted. If all files exist and this is False,
73
            then the script will not be submitted. If some files exist and this is False, only the
74
            subset of the cameras without the final data products will be generated and submitted.
75
        dont_resubmit_partial_jobs (bool, optional): Default is False. Must be used with dont_check_job_outputs=False. If this flag is
76
            False, jobs with some prior data are pruned using PROCCAMWORD to only process the
77
            remaining cameras not found to exist.
78
        tiles (array-like, optional): Only submit jobs for these TILEIDs.
79
        surveys (array-like, optional): Only submit science jobs for these surveys (lowercase)
80
        laststeps (array-like, optional): Only submit jobs for exposures with LASTSTEP in these laststeps (lowercase)
81
        use_tilenight (bool, optional): Default is False. If True, use desi_proc_tilenight for prestdstar, stdstar,
82
            and poststdstar steps for science exposures.
83
        all_tiles (bool, optional): Default is False. Set to NOT restrict to completed tiles as defined by
84
            the table pointed to by specstatus_path.
85
        specstatus_path (str, optional): Default is $DESI_SURVEYOPS/ops/tiles-specstatus.ecsv.
86
            Location of the surveyops specstatus table.
87
        use_specter (bool, optional): Default is False. If True, use specter, otherwise use gpu_specter by default.
88
        do_cte_flat (bool, optional): Default is False. If True, one second flat exposures are processed for cte identification.
89
        complete_tiles_thrunight (int, optional): Default is None. Only tiles completed
90
            on or before the supplied YYYYMMDD are considered
91
            completed and will be processed. All complete
92
            tiles are submitted if None or all_tiles is True.
93
        all_cumulatives (bool, optional): Default is False. Set to run cumulative redshifts for all tiles
94
            even if the tile has observations on a later night.
95
    """
96
    log = get_logger()
×
97

98
    ## Recast booleans from double negative
99
    check_for_outputs = (not dont_check_job_outputs)
×
100
    resubmit_partial_complete = (not dont_resubmit_partial_jobs)
×
101

102
    if proc_obstypes is None:
×
103
        proc_obstypes = default_obstypes_for_proctable()
×
104
    print(f"Processing the following obstypes: {proc_obstypes}")
×
105

106
    ## Determine where the exposure table will be written
107
    if exp_table_path is None:
×
108
        exp_table_path = get_exposure_table_path(night=night, usespecprod=True)
×
109
    name = get_exposure_table_name(night=night, extension=tab_filetype)
×
110
    exp_table_pathname = pathjoin(exp_table_path, name)
×
111
    if not os.path.exists(exp_table_pathname):
×
112
        if error_if_not_available:
×
113
            raise IOError(f"Exposure table: {exp_table_pathname} not found. Exiting this night.")
×
114
        else:
115
            print(f"ERROR: Exposure table: {exp_table_pathname} not found. Exiting this night.")
×
116
            return
×
117

118
    ## Determine where the processing table will be written
119
    if proc_table_path is None:
×
120
        proc_table_path = get_processing_table_path()
×
121
    os.makedirs(proc_table_path, exist_ok=True)
×
122
    name = get_processing_table_name(prodmod=night, extension=tab_filetype)
×
123
    proc_table_pathname = pathjoin(proc_table_path, name)
×
124

125
    ## Define the group types of redshifts you want to generate for each tile
126
    if no_redshifts:
×
127
        z_submit_types = None
×
128
    else:
129
        if z_submit_types is None:
×
130
            pass
×
131
        elif isinstance(z_submit_types, str):
×
132
            if z_submit_types.lower() == 'false':
×
133
                z_submit_types = None
×
134
            elif z_submit_types.lower() == 'none':
×
135
                z_submit_types = None
×
136
            else:
137
                z_submit_types = [ztype.strip().lower() for ztype in z_submit_types.split(',')]
×
138
                for ztype in z_submit_types:
×
139
                    if ztype not in ['cumulative', 'pernight-v0', 'pernight', 'perexp']:
×
140
                        raise ValueError(f"Couldn't understand ztype={ztype} in z_submit_types={z_submit_types}.")
×
141
        else:
142
            raise ValueError(f"Couldn't understand z_submit_types={z_submit_types}, type={type(z_submit_types)}.")
×
143

144
    if z_submit_types is None:
×
145
        print("Not submitting scripts for redshift fitting")
×
146
    else:
147
        print(f"Redshift fitting with redshift group types: {z_submit_types}")
×
148

149
    ## Reconcile the dry_run and dry_run_level
150
    if dry_run and dry_run_level == 0:
×
151
        dry_run_level = 2
×
152
    elif dry_run_level > 0:
×
153
        dry_run = True
×
154

155
    ## If laststeps not defined, default is only LASTSTEP=='all' exposures for non-tilenight runs
156
    tilenight_laststeps = laststeps
×
157
    if laststeps is None:
×
158
        laststeps = ['all',]
×
159
    else:
160
        laststep_options = get_last_step_options()
×
161
        for laststep in laststeps:
×
162
            if laststep not in laststep_options:
×
163
                raise ValueError(f"Couldn't understand laststep={laststep} in laststeps={laststeps}.")
×
164
    print(f"Processing exposures with the following LASTSTEP's: {laststeps}")
×
165

166
    ## Check if night has already been submitted and don't submit if it has, unless told to with ignore_existing
167
    if os.path.exists(proc_table_pathname):
×
168
        if not append_to_proc_table:
×
169
            print(f"ERROR: Processing table: {proc_table_pathname} already exists and not "+
×
170
                  "given flag --append-to-proc-table. Exiting this night.")
171
            return
×
172

173
    ## Determine where the unprocessed data table will be written
174
    unproc_table_pathname = pathjoin(proc_table_path, name.replace('processing', 'unprocessed'))
×
175

176
    ## Combine the table names and types for easier passing to io functions
177
    table_pathnames = [exp_table_pathname, proc_table_pathname]
×
178
    table_types = ['exptable', 'proctable']
×
179

180
    ## Load in the files defined above
181
    etable, ptable = load_tables(tablenames=table_pathnames, tabletypes=table_types)
×
182
    full_etable = etable.copy()
×
183

184
    ## Sort science exposures by TILEID
185
    sciexps = (etable['OBSTYPE']=='science')
×
186
    scisrtd = etable[sciexps].argsort(['TILEID','EXPID'])
×
187
    etable[sciexps] = etable[sciexps][scisrtd]
×
188

189
    ## filter by TILEID if requested
190
    if tiles is not None:
×
191
        log.info(f'Filtering by tiles={tiles}')
×
192
        if etable is not None:
×
193
            keep = np.isin(etable['TILEID'], tiles)
×
194
            etable = etable[keep]
×
195
        #if ptable is not None:
196
        #    keep = np.isin(ptable['TILEID'], tiles)
197
        #    ptable = ptable[keep]
198

199
    if surveys is not None:
×
200
        log.info(f'Filtering by surveys={surveys}')
×
201
        if etable is not None:
×
202
            if 'SURVEY' not in etable.dtype.names:
×
203
                raise ValueError(f'surveys={surveys} filter requested, but no SURVEY column in {exp_table_pathname}')
×
204

205
            # only apply survey filter to OBSTYPE=science exposures, i.e. auto-keep non-science
206
            keep = (etable['OBSTYPE'] != 'science')
×
207

208
            # np.isin doesn't work with bytes vs. str from Tables but direct comparison does, so loop
209
            for survey in surveys:
×
210
                keep |= etable['SURVEY'] == survey
×
211

212
            etable = etable[keep]
×
213
        #if ptable is not None:
214
        #    # ptable doesn't have "SURVEY", so filter by the TILEIDs we just kept
215
        #    keep = np.isin(ptable['TILEID'], etable['TILEID'])
216
        #    ptable = ptable[keep]
217

218
    ## If asked to do so, only process tiles deemed complete by the specstatus file
219
    if not all_tiles:
×
220
        all_completed_tiles = get_completed_tiles(specstatus_path,
×
221
                                              complete_tiles_thrunight=complete_tiles_thrunight)
222

223
        ## Add -99 to keep calibration exposures
224
        all_completed_tiles_withcalib = np.append([-99], all_completed_tiles)
×
225
        if etable is not None:
×
226
            keep = np.isin(etable['TILEID'], all_completed_tiles_withcalib)
×
227
            sciselect = np.isin(etable['TILEID'], all_completed_tiles)
×
228
            completed_tiles = np.unique(etable['TILEID'][keep])
×
229
            sci_tiles = np.unique(etable['TILEID'][sciselect])
×
230
            log.info(f"Processing completed science tiles: {', '.join(sci_tiles.astype(str))}")
×
231
            log.info(f"Filtering by completed tiles retained {len(sci_tiles)}/{sum(np.unique(etable['TILEID'])>0)} science tiles")
×
232
            log.info(f"Filtering by completed tiles retained {sum(sciselect)}/{sum(etable['TILEID']>0)} science exposures")
×
233
            etable = etable[keep]
×
234

235
    ## Cut on LASTSTEP
236
    good_exps = np.isin(np.array(etable['LASTSTEP']).astype(str), laststeps)
×
237
    etable = etable[good_exps]
×
238

239
    ## For cumulative redshifts, identify tiles for which this is the last night that they were observed
240
    tiles_cumulative = list()
×
241
    if z_submit_types is not None and 'cumulative' in z_submit_types:
×
242
        tiles_this_night = np.unique(np.asarray(etable['TILEID']))
×
243
        tiles_this_night = tiles_this_night[tiles_this_night > 0]  # science tiles, not calibs
×
244
        if all_cumulatives:
×
245
            tiles_cumulative = list(tiles_this_night)
×
246
            log.info(f'Submitting cumulative redshifts for all tiles: {tiles_cumulative}')
×
247
        else:
248
            allexp = read_minimal_exptables_columns(tileids=tiles_this_night)
×
249
            for tileid in tiles_this_night:
×
250
                nights_with_tile = allexp['NIGHT'][allexp['TILEID'] == tileid]
×
251
                if len(nights_with_tile) > 0 and night == np.max(nights_with_tile):
×
252
                    tiles_cumulative.append(tileid)
×
253
            log.info(f'Submitting cumulative redshifts for {len(tiles_cumulative)}/{len(tiles_this_night)} tiles '
×
254
                     f'for which {night} is the last night: {tiles_cumulative}')
255

256
    ## Count zeros before trimming by OBSTYPE since they are used for
257
    ## nightly bias even if they aren't processed individually
258
    num_zeros = np.sum([erow['OBSTYPE'] == 'zero' and
×
259
                       (erow['PROGRAM'].startswith('calib zeros') or erow['PROGRAM'].startswith('zeros for dark'))
260
                       for erow in etable])
261

262
    ## Cut on OBSTYPES
263
    good_types = np.isin(np.array(etable['OBSTYPE']).astype(str), proc_obstypes)
×
264
    etable = etable[good_types]
×
265

266
    ## Cut on EXPTIME
267
    good_exptimes = []
×
268
    already_found_cte_flat = False
×
269
    for erow in etable:
×
270
        if erow['OBSTYPE'] == 'science' and erow['EXPTIME'] < 60:
×
271
            good_exptimes.append(False)
×
272
        elif erow['OBSTYPE'] == 'arc' and erow['EXPTIME'] > 8.:
×
273
            good_exptimes.append(False)
×
274
        elif erow['OBSTYPE'] == 'dark' and np.abs(float(erow['EXPTIME']) - 300.) > 1:
×
275
            good_exptimes.append(False)
×
276
        elif erow['OBSTYPE'] == 'flat' and np.abs(float(erow['EXPTIME']) - 120.) > 1:
×
277
            if do_cte_flat and not already_found_cte_flat \
×
278
               and np.abs(float(erow['EXPTIME']) - 1.) < 0.5:
279
                good_exptimes.append(True)
×
280
                already_found_cte_flat = True
×
281
            else:
282
                good_exptimes.append(False)
×
283
        else:
284
            good_exptimes.append(True)
×
285
    etable = etable[np.array(good_exptimes)]
×
286

287
    ## Simple table organization to ensure cals processed first
288
    ## To be eventually replaced by more sophisticated cal selection
289
    ## Get one dark first
290
    isdarkcal = np.array([(erow['OBSTYPE'] == 'dark' and 'calib' in
×
291
                          erow['PROGRAM']) for erow in etable])
292
    isdark = np.array([(erow['OBSTYPE'] == 'dark') for erow in etable])
×
293

294
    ## If a cal, want to select that but ignore all other darks
295
    ## elif only a dark sequence, use that
296
    if np.sum(isdarkcal)>0:
×
297
        wheredark = np.where(isdarkcal)[0]
×
298
        ## note this is ~isdark because want to get rid of all other darks
299
        etable = vstack([etable[wheredark[0]], etable[~isdark]])
×
300
    elif np.sum(isdark)>0:
×
301
        wheredark = np.where(isdark)[0]
×
302
        etable = vstack([etable[wheredark[0]], etable[~isdark]])
×
303

304
    ## Then get rest of the cals above scis
305
    issci = (etable['OBSTYPE'] == 'science')
×
306
    etable = vstack([etable[~issci], etable[issci]])
×
307

308
    ## Get relevant data from the tables
309
    arcs, flats, sciences, calibjobs, curtype, lasttype, \
×
310
    curtile, lasttile, internal_id = parse_previous_tables(etable, ptable, night)
311
    if len(ptable) > 0:
×
312
        ptable = update_from_queue(ptable, dry_run=0)
×
313
        if dry_run_level < 3:
×
314
            write_table(ptable, tablename=proc_table_pathname)
×
315
        if any_jobs_not_complete(ptable['STATUS']):
×
316
            if not ignore_proc_table_failures:
×
317
                print("ERROR: Some jobs have an incomplete job status. This script "
×
318
                      + "will not fix them. You should remedy those first. "
319
                      + "To proceed anyway use '--ignore-proc-table-failures'. Exiting.")
320
                return
×
321
            else:
322
                print("Warning: Some jobs have an incomplete job status, but "
×
323
                      + "you entered '--ignore-proc-table-failures'. This "
324
                      + "script will not fix them. "
325
                      + "You should have fixed those first. Proceeding...")
326
        ptable_expids = np.unique(np.concatenate(ptable['EXPID']))
×
327
        if len(set(etable['EXPID']).difference(set(ptable_expids))) == 0:
×
328
            print("All EXPID's already present in processing table, nothing to run. Exiting")
×
329
            return
×
330
    else:
331
        ptable_expids = np.array([], dtype=int)
×
332

333
    tableng = len(ptable)
×
334

335
    ## Now figure out everything that isn't in the final list, which we'll
336
    ## Write out to the unproccessed table
337
    toprocess = np.isin(full_etable['EXPID'], etable['EXPID'])
×
338
    processed = np.isin(full_etable['EXPID'], ptable_expids)
×
339
    unproc_table = full_etable[~(toprocess|processed)]
×
340

341
    ## Done determining what not to process, so write out unproc file
342
    if dry_run_level < 3:
×
343
        write_table(unproc_table, tablename=unproc_table_pathname)
×
344

345
    ## If just starting out and no dark, do the nightlybias
346
    do_bias = ('bias' in proc_obstypes or 'dark' in proc_obstypes) and num_zeros>0
×
347
    if tableng == 0 and np.sum(isdark) == 0 and do_bias:
×
348
        print("\nNo dark found. Submitting nightlybias before processing exposures.\n")
×
349
        prow = default_prow()
×
350
        prow['INTID'] = internal_id
×
351
        prow['OBSTYPE'] = 'zero'
×
352
        internal_id += 1
×
353
        prow['JOBDESC'] = 'nightlybias'
×
354
        prow['NIGHT'] = night
×
355
        prow['CALIBRATOR'] = 1
×
356
        cams = set(decode_camword('a0123456789'))
×
357
        for row in unproc_table:
×
358
            if row['OBSTYPE'] == 'zero' and 'calib' in row['PROGRAM']:
×
359
                proccamword = difference_camwords(row['CAMWORD'], row['BADCAMWORD'])
×
360
                cams = cams.intersection(set(decode_camword(proccamword)))
×
361
        prow['PROCCAMWORD'] = create_camword(list(cams))
×
362
        prow = create_and_submit(prow, dry_run=dry_run_level, queue=queue,
×
363
                                 reservation=reservation,
364
                                 strictly_successful=True,
365
                                 check_for_outputs=check_for_outputs,
366
                                 resubmit_partial_complete=resubmit_partial_complete,
367
                                 system_name=system_name)
368
        calibjobs['nightlybias'] = prow.copy()
×
369
        ## Add the processing row to the processing table
370
        ptable.add_row(prow)
×
371
        ## Write out the processing table
372
        if dry_run_level < 3:
×
373
            write_table(ptable, tablename=proc_table_pathname)
×
374
            sleep_and_report(2, message_suffix=f"after nightlybias",
×
375
                             dry_run=dry_run)
376

377
    ## Loop over new exposures and process them as relevant to that type
378
    for ii, erow in enumerate(etable):
×
379
        if erow['EXPID'] in ptable_expids:
×
380
            continue
×
381
        erow = table_row_to_dict(erow)
×
382
        exp = int(erow['EXPID'])
×
383
        print(f'\n\n##################### {exp} #########################')
×
384

385
        print(f"\nFound: {erow}")
×
386

387
        curtype, curtile = get_type_and_tile(erow)
×
388

389
        # if this is a new tile/obstype, proceed with submitting all of the jobs for the previous tile
390
        if lasttype is not None and ((curtype != lasttype) or (curtile != lasttile)):
×
391
            # don't submit cumulative redshifts for lasttile if it isn't in tiles_cumulative
392
            if (z_submit_types is not None) and ('cumulative' in z_submit_types) and (lasttile not in tiles_cumulative):
×
393
                cur_z_submit_types = z_submit_types.copy()
×
394
                cur_z_submit_types.remove('cumulative')
×
395
            else:
396
                cur_z_submit_types = z_submit_types
×
397

398
            # If done with science exposures for a tile and use_tilenight==True, use
399
            # submit_tilenight_and_redshifts, otherwise use checkfor_and_submit_joint_job
400
            if use_tilenight and lasttype == 'science' and len(sciences)>0:
×
NEW
401
                extra_job_args = {}
×
NEW
402
                extra_job_args['z_submit_types'] = cur_z_submit_types
×
NEW
403
                extra_job_args['laststeps'] = ['all','fluxcalib','skysub']
×
UNCOV
404
                ptable, sciences, internal_id \
×
405
                    = submit_tilenight_and_redshifts(ptable, sciences, calibjobs, internal_id,
406
                                                    dry_run=dry_run_level,
407
                                                    queue=queue,
408
                                                    reservation=reservation,
409
                                                    strictly_successful=True,
410
                                                    check_for_outputs=check_for_outputs,
411
                                                    resubmit_partial_complete=resubmit_partial_complete,
412
                                                    system_name=system_name,use_specter=use_specter,
413
                                                    extra_job_args=extra_job_args)
414
            else:
415
                ## If running redshifts and there is a future exposure of the same tile
416
                ## then only run per exposure redshifts until then
417
                if lasttype == 'science' and z_submit_types is not None and not use_tilenight:
×
418
                    tile_exps = etable['EXPID'][((etable['TILEID'] == lasttile) &
×
419
                                                 (etable['LASTSTEP'] == 'all'))]
420
                    unprocd_exps = [exp not in ptable_expids for exp in tile_exps]
×
421
                    if np.any(unprocd_exps):
×
422
                        print(f"Identified that tile {lasttile} has future exposures"
×
423
                            + f" for this night. Not submitting full night "
424
                            + f"redshift jobs.")
425
                        if 'perexp' in z_submit_types:
×
426
                            print("Still submitting perexp redshifts")
×
427
                            cur_z_submit_types = ['perexp']
×
428
                        else:
429
                            cur_z_submit_types = None
×
430
                ptable, calibjobs, sciences, internal_id \
×
431
                    = checkfor_and_submit_joint_job(ptable, arcs, flats, sciences,
432
                                                calibjobs,
433
                                                lasttype, internal_id,
434
                                                dry_run=dry_run_level,
435
                                                queue=queue,
436
                                                reservation=reservation,
437
                                                strictly_successful=True,
438
                                                check_for_outputs=check_for_outputs,
439
                                                resubmit_partial_complete=resubmit_partial_complete,
440
                                                z_submit_types=cur_z_submit_types,
441
                                                system_name=system_name)
442

443
        prow = erow_to_prow(erow)
×
444
        prow['INTID'] = internal_id
×
445
        internal_id += 1
×
446
        if prow['OBSTYPE'] == 'dark':
×
447
            if num_zeros == 0:
×
448
                prow['JOBDESC'] = 'badcol'   # process dark for bad columns even if we don't have zeros for nightlybias
×
449
            else:
450
                prow['JOBDESC'] = 'ccdcalib' # ccdcalib = nightlybias(zeros) + badcol(dark)
×
451
        else:
452
            prow['JOBDESC'] = prow['OBSTYPE']
×
453
        prow = define_and_assign_dependency(prow, calibjobs)
×
454
        if (not use_tilenight) or erow['OBSTYPE'] != 'science':
×
455
            print(f"\nProcessing: {prow}\n")
×
456
            prow = create_and_submit(prow, dry_run=dry_run_level, queue=queue,
×
457
                                 reservation=reservation, strictly_successful=True,
458
                                 check_for_outputs=check_for_outputs,
459
                                 resubmit_partial_complete=resubmit_partial_complete,
460
                                 system_name=system_name,use_specter=use_specter)
461

462
            ## If processed a dark, assign that to the dark job
463
            if curtype == 'dark':
×
464
                prow['CALIBRATOR'] = 1
×
465
                calibjobs[prow['JOBDESC']] = prow.copy()
×
466

467
            ## Add the processing row to the processing table
468
            ptable.add_row(prow)
×
469

470
        ptable_expids = np.append(ptable_expids, erow['EXPID'])
×
471

472
        ## Note: Assumption here on number of flats
473
        if curtype == 'flat' and calibjobs['nightlyflat'] is None \
×
474
                and int(erow['SEQTOT']) < 5 \
475
                and np.abs(float(erow['EXPTIME'])-120.) < 1.:
476
            flats.append(prow)
×
477
        elif curtype == 'arc' and calibjobs['psfnight'] is None:
×
478
            arcs.append(prow)
×
479
        elif curtype == 'science' and (prow['LASTSTEP'] != 'skysub' or use_tilenight):
×
480
            sciences.append(prow)
×
481

482
        lasttile = curtile
×
483
        lasttype = curtype
×
484

485
        tableng = len(ptable)
×
486
        if tableng > 0 and ii % 1 == 0 and dry_run_level < 3:
×
487
            write_table(ptable, tablename=proc_table_pathname)
×
488

489
        sleep_and_report(1, message_suffix=f"to slow down the queue submission rate",
×
490
                         dry_run=dry_run)
491

492
        ## Flush the outputs
493
        sys.stdout.flush()
×
494
        sys.stderr.flush()
×
495

496
    if tableng > 0 or (use_tilenight and len(sciences)>0):
×
497
        ## No more data coming in, so do bottleneck steps if any apply
498

499
        # don't submit cumulative redshifts for lasttile if it isn't in tiles_cumulative
500
        if (z_submit_types is not None) and ('cumulative' in z_submit_types) and (lasttile not in tiles_cumulative):
×
501
            cur_z_submit_types = z_submit_types.copy()
×
502
            cur_z_submit_types.remove('cumulative')
×
503
        else:
504
            cur_z_submit_types = z_submit_types
×
505

506
        if use_tilenight and len(sciences)>0:
×
NEW
507
            extra_job_args = {}
×
NEW
508
            extra_job_args['z_submit_types'] = cur_z_submit_types
×
NEW
509
            extra_job_args['laststeps'] = ['all','fluxcalib','skysub']
×
UNCOV
510
            ptable, sciences, internal_id \
×
511
                = submit_tilenight_and_redshifts(ptable, sciences, calibjobs, internal_id,
512
                                                dry_run=dry_run_level,
513
                                                queue=queue,
514
                                                reservation=reservation,
515
                                                strictly_successful=True,
516
                                                check_for_outputs=check_for_outputs,
517
                                                resubmit_partial_complete=resubmit_partial_complete,
518
                                                system_name=system_name,use_specter=use_specter,
519
                                                extra_job_args=extra_job_args)
520
        else:
521
            ptable, calibjobs, sciences, internal_id \
×
522
                = checkfor_and_submit_joint_job(ptable, arcs, flats, sciences, calibjobs,
523
                                            lasttype, internal_id, dry_run=dry_run_level,
524
                                            queue=queue, reservation=reservation,
525
                                            strictly_successful=True,
526
                                            check_for_outputs=check_for_outputs,
527
                                            resubmit_partial_complete=resubmit_partial_complete,
528
                                            z_submit_types=cur_z_submit_types,
529
                                            system_name=system_name)
530
        ## All jobs now submitted, update information from job queue and save
531
        ptable = update_from_queue(ptable, dry_run=dry_run_level)
×
532
        if dry_run_level < 3:
×
533
            write_table(ptable, tablename=proc_table_pathname)
×
534

535
    print(f"Completed submission of exposures for night {night}.", '\n\n\n')
×
536

STATUS · Troubleshooting · Open an Issue · Sales · Support · CAREERS · ENTERPRISE · START FREE · SCHEDULE DEMO
ANNOUNCEMENTS · TWITTER · TOS & SLA · Supported CI Services · What's a CI service? · Automated Testing

© 2026 Coveralls, Inc