Building and solving pointing drifts

The figure [*] shows that for a given phase cycle, MRTCAL computes the average MJD of each of the 4 phases, and then the average of the ONs and the average of the OFFs, and uses the ON average MJD to associate the proper antenna position. The following list describes the main steps of the algorithm, which is currently implemented in the subroutine mrtcal_solve_pointing_bsw.

Figure: Representation of the time distribution of the first phase dumps for iram30m-nbc-20220301s205-imb.fits (subscan 1). The horizontal segments labeled from 1 to 4 represent the integration time of each phase.
\includegraphics[width=0.9\textwidth]{iram30m-nbc-20220301s205-subs1-phases}

  1. Major loop on all the subscans:
    1. Sub-loop on all dump cycles in a subscan:
      1. Fetching the next cycle: subroutine mrtcal_get_next_dumpcycle calls subroutines mrtcal_find_next_dumpcycle and mrtcal_read_next_dumpcycle. A cycle consists typically in the dump sequence 1=ON, 2=OFF, 3=ON, 4=OFF.
      2. mrtcal_read_next_dumpcycle calls a cascade down to mrtcal_read_subscan_data
      3. This also also includes chunkset mapping: as for the other observing modes, one dump from the IMBF-backendCONT table is mapped as a single chunk (chunk_t). Since continuum backends are used, it provides only 1 intensity value (1 channel). This chunk is attributed one MJD at the center of the dump integration time, and from this MJD the chunk position is interpolated from the antslow table (chunk%offset(1) and chunk%offset(2)). See subroutine mrtcal_chunksets_from_data_1time1pix_1chunk.
      4. After the reading, the subroutine mrtcal_get_next_dumpcycle, averages the ONs ( $\langle ON \rangle = 1+3$) and OFFs ( $\langle
OFF \rangle = 2+4$) in the subroutine average_phases. It uses mrtcal_chunkset_2d_accumulate_init and mrtcal_chunkset_2d_accumulate_do, ultimately calling mrtcal_chunkset_accumulate_do for weighted average of MJD and weighted average of offsets (weight is integration time of each phase). In return, $\langle ON \rangle$ has average MJD and offsets. Same for $\langle OFF \rangle$.

      5. Computing $\langle ON \rangle - \langle OFF \rangle$: i) call mrtcal_on_minus_off for one dump cycle in mode isotfmap, ii) subroutine mrtcal_on_minus_off_head keeps the $\langle ON \rangle$ MJD and offsets.

    2. Loop on chunksets to create one drift per chunkset (subroutine mrtcal_pointing_create). Each chunkset is a collection of chunks computed at the previous steps, i.e. a collection of $\langle ON \rangle - \langle OFF \rangle$ with proper MJD and offsets. Gather them as a continuum drift with irregular X axis in a CLASS type(observation) in subroutine mrtcal_chunkset_to_obs_con. The operation is repeated for all chunksets i.e. all subscans and all backend parts (H and V, etc) (backsci%drift%indiv).

  2. Classify the drifts (subroutine mrtcal_pointing_classify) as desired (MSET SOLVE POINTING): if there is more than 1 drift per class, resample the irregular X axis to regular and average the drifts (subroutine mrtcal_solve_pointing_gather_regular) also in a type(observation) (backsci%drift%solved).

  3. For each class (subroutine mrtcal_solve_and_write_obslist):
    1. Solve each class with a gaussian+baseline model (subroutine mrtcal_solve_pointing_observation) calling TELCAL solve_pointing. Convert TELCAL solution to CLASS pointing section (subroutine mrtcal_fit_to_obs_poi).
    2. Remove the fitted baseline from each class RY arrays and save the original RY as an associated array named POINTING (subroutine mrtcal_pointing_associate_array).
    3. Write to the output CLASS file (subroutine mrtcal_obs_to_class).

  4. Save all the pointing results of the scan to the dedicated MRTCAL section in the index (subroutine mrtcal_entry_sdrifts2poisec).

  5. Final feedback: i) ASCII table to screen or file (subroutine mrtcal_solve_pointing_user_feedback), and ii) XML file (subroutine pointing_to_VO).