StartOfNight

Bases: KPFFunction

Send KPF in to a reasonable starting configuration

  • set FIU mode to observing
  • reset guider bias/sky subtraction file to default
  • Setup AO for KPF
  • Configure DCS (ROTDEST and ROTMODE)

ARGS:

  • AO - bool Open AO hatch, send PCU to KPF, and turn on HEPA? (default=True)
Source code in kpf/utils/StartOfNight.py
 25
 26
 27
 28
 29
 30
 31
 32
 33
 34
 35
 36
 37
 38
 39
 40
 41
 42
 43
 44
 45
 46
 47
 48
 49
 50
 51
 52
 53
 54
 55
 56
 57
 58
 59
 60
 61
 62
 63
 64
 65
 66
 67
 68
 69
 70
 71
 72
 73
 74
 75
 76
 77
 78
 79
 80
 81
 82
 83
 84
 85
 86
 87
 88
 89
 90
 91
 92
 93
 94
 95
 96
 97
 98
 99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
class StartOfNight(KPFFunction):
    '''Send KPF in to a reasonable starting configuration

    - set FIU mode to observing
    - reset guider bias/sky subtraction file to default
    - Setup AO for KPF
    - Configure DCS (ROTDEST and ROTMODE)

    ARGS:
    =====
    * __AO__ - `bool` Open AO hatch, send PCU to KPF, and turn on HEPA? (default=True)
    '''
    @classmethod
    @obey_scriptrun
    def pre_condition(cls, args):
        pass

    @classmethod
    @add_script_log(Path(__file__).name.replace(".py", ""))
    def perform(cls, args):
        log.info(f"Running KPF Start of Night script")

        # Check Scripts
        kpfconfig = ktl.cache('kpfconfig')
        expose = ktl.cache('kpfexpose', 'EXPOSE')
        scriptname = kpfconfig['SCRIPTNAME'].read()
        pid = kpfconfig['SCRIPTPID'].read(binary=True)
        script_running = scriptname not in ['', 'None', None] or pid >= 0
        if script_running and args.get('confirm', False) is True:
            log.error('Non-interactive mode set and script is running')
            return
        if script_running:
            # ---------------------------------
            # User Verification
            # ---------------------------------
            msg = ["",
                   "--------------------------------------------------------------",
                   f"A script ({scriptname}, {pid}) is currently running. ",
                   "",
                   "Depending on when you are seeing this, it may be a scheduled",
                   "nighttime calibration which can and should be interrupted to",
                   "enable observing.",
                   "",
                   "Do you wish to end the current exposure and request a script",
                   "stop in order to proceed with running StartOfNight?",
                   "",
                   "End Exposure and Request Script Stop?",
                   "(y/n) [y]:",
                   "--------------------------------------------------------------",
                   "",
                   ]
            for line in msg:
                print(line)
            user_input = input()
            if user_input.lower() in ['n', 'no', 'q', 'quit', 'abort']:
                log.warning(f'User aborted Start Of Night')
                return
            else:
                log.info('User opted to stop existing script')
                kpfconfig['SCRIPTSTOP'].write(1)
                expose.write('End')
                waittime = 120
                log.info(f'Waiting up to {waittime:.0f}s for running script to end')
                kpfconfig['SCRIPTPID'].waitFor("==-1", timeout=waittime)
                time.sleep(2) # time shim
                check_script_running()

        # ---------------------------------
        # Remaining non-AO Actions
        # ---------------------------------
        # Disallow cron job calibration scripts
        log.info('Set ALLOWSCHEDULEDCALS to No')
        kpfconfig = ktl.cache('kpfconfig')
        kpfconfig['ALLOWSCHEDULEDCALS'].write('No')

        HKCOOLING = ktl.cache('kpf_hk', 'COOLING')
        if HKCOOLING.read() != 'On':
            log.warning('HK Detector Cooling is not On')

        # Set Observer
        SetObserverFromSchedule.execute({})

        # Configure FIU
        log.info('Configure FIU for "Observing"')
        ConfigureFIU.execute({'mode': 'Observing'})

        # Reset CRED2 subtraction file to default
        kpfguide = ktl.cache('kpfguide')
        kpfguide[f'SUB_HIGH'].write(f'/kroot/rel/default/data/kpfguide/kpfguide_gain_high.fits')

        # Set DCS rotator parameters
        dcs = ktl.cache('dcs1')
        inst = dcs['INSTRUME'].read()
        if inst == 'KPF':
            log.info(f"Setting dcs.ROTDEST = 0")
            dcs['ROTDEST'].write(0)
            log.info(f"Setting dcs.ROTMODE = stationary")
            dcs['ROTMODE'].write('stationary')
        else:
            log.warning(f"Instrument is {inst}, not configuring DCS")

        # Report Agitator status
        runagitator = kpfconfig['USEAGITATOR'].read(binary=True)
        if runagitator is True:
            log.info(f"Agitator use is enabled")
        else:
            log.warning(f"Agitator use is disabled for tonight")
        # Pre-configure cal source
        calsource = kpfconfig['SIMULCALSOURCE'].read()
        log.info(f"Setting simultaneous CalSource/Octagon: {calsource}")
        SetCalSource.execute({'CalSource': calsource, 'wait': True})
        # Power on Simulcal lamp if needed
        if calsource in ['U_gold', 'U_daily', 'Th_daily', 'Th_gold']:
            CalLampPower.execute({'lamp': calsource, 'power': 'on'})
        # Set tip tilt loop gain to default value
        tip_tilt_gain = cfg.getfloat('tiptilt', 'tiptilt_loop_gain', fallback=0.3)
        log.info(f"Setting default tip tilt loop gain of {tip_tilt_gain}")
        SetTipTiltGain.execute({'GuideLoopGain': tip_tilt_gain})
        # Set tip tilt loop detection threshold to default value
        detect_snr = cfg.getfloat('tiptilt', 'detect_snr', fallback=7)
        log.info(f"Setting default tip tilt detection SNR of {detect_snr}")
        kpfguide['OBJECT_INTENSITY'].write(detect_snr)
        # Set tip tilt loop detection area to default value
        detect_area = cfg.getfloat('tiptilt', 'detect_area', fallback=100)
        log.info(f"Setting default tip tilt detection area of {detect_area}")
        kpfguide['OBJECT_AREA'].write(detect_area)
        # Set tip tilt loop deblend parameter to default value
        deblend = cfg.getfloat('tiptilt', 'deblend', fallback=1)
        log.info(f"Setting default tip tilt deblending parameter of {deblend}")
        kpfguide['OBJECT_DBCONT'].write(1.0)
        # Set DAR parameter to default value
        log.info(f"Ensuring DAR correction is on")
        kpfguide['DAR_ENABLE'].write('Yes')
        # Set Outdirs
        if expose.read() != 'Ready':
            log.info('Waiting for kpfexpose to be Ready')
            WaitForReady.execute({})
        SetOutdirs.execute({})
        # Set guider gain to high for initial acquisition and focus
        SetGuiderGain.execute({'GuideCamGain': 'high'})
        # Summarize Detector Disabled States
        cahk_enabled = kpfconfig['CA_HK_ENABLED'].read(binary=True)
        if cahk_enabled is False:
            log.warning(f"The CA_HK detector is disabled tonight")
        green_enabled = kpfconfig['GREEN_ENABLED'].read(binary=True)
        if green_enabled is False:
            log.warning(f"The Green detector is disabled tonight")
        red_enabled = kpfconfig['RED_ENABLED'].read(binary=True)
        if red_enabled is False:
            log.warning(f"The Red detector is disabled tonight")
        expmeter_enabled = kpfconfig['EXPMETER_ENABLED'].read(binary=True)
        if expmeter_enabled is False:
            log.warning(f"The ExpMeter detector is disabled tonight")

        # Setup AO
        if args.get('AO', True) is True and args.get('confirm', False) is False:
            # ---------------------------------
            # User Verification
            # ---------------------------------
            msg = ["",
                   "--------------------------------------------------------------",
                   "This script will configure the FIU and AO bench for observing.",
                   "The AO bench area should be clear of personnel before proceeding.",
                   "Do you wish to to continue?",
                   "(y/n) [y]:",
                   "--------------------------------------------------------------",
                   "",
                   ]
            for line in msg:
                print(line)
            user_input = input()
            if user_input.lower() in ['n', 'no', 'q', 'quit', 'abort']:
                log.warning(f'User aborted Start Of Night')
                return
            else:
                SetupAOforKPF.execute({})
                log.info('Open AO hatch')
                try:
                    ControlAOHatch.execute({'destination': 'open'})
                except FailedToReachDestination:
                    log.error(f"AO hatch did not move successfully")
                    print()
                    print('----------------------------------------------------------')
                    print('AO hatch reported problems moving. Make sure stars are')
                    print('visible on guide camera before proceeding.')
                    print('----------------------------------------------------------')
                    print()

    @classmethod
    def post_condition(cls, args):
        pass

    @classmethod
    def add_cmdline_args(cls, parser):
        parser.add_argument("--noAO", dest="AO",
                            default=True, action="store_false",
                            help="Skip configuring AO?")
        parser.add_argument("--confirm", dest="confirm",
                            default=False, action="store_true",
                            help="Skip confirmation questions (script will be non interactive)?")
        return super().add_cmdline_args(parser)