Citlali
Loading...
Searching...
No Matches
engine.h
Go to the documentation of this file.
1#pragma once
2
3#include "sys/types.h"
4#include "sys/sysinfo.h"
5
6#include <memory>
7#include <string>
8#include <vector>
9#include <omp.h>
10#include <fstream>
11#include <limits>
12
13#include <Eigen/Core>
14
15#include <citlali_config/config.h>
16#include <citlali_config/gitversion.h>
17#include <citlali_config/default_config.h>
18#include <kids/core/kidsdata.h>
19#include <kids/sweep/fitter.h>
20#include <kids/timestream/solver.h>
21#include <kids/toltec/toltec.h>
22#include <kidscpp_config/gitversion.h>
23#include <tula_config/gitversion.h>
24#include <tula/cli.h>
25#include <tula/config/core.h>
26#include <tula/config/flatconfig.h>
27#include <tula/config/yamlconfig.h>
28#include <tula/enum.h>
29#include <tula/filesystem.h>
30#include <tula/formatter/container.h>
31#include <tula/formatter/enum.h>
32#include <tula/grppi.h>
33#include <tula/logging.h>
34#include <tula/switch_invoke.h>
35
41
47
54
57
60
66
70
72 // interpolate over gaps in timestreams
74 // create reduction subdirectories
76
77 // run or skip tod processing
78 bool run_tod;
79
80 // output timestreams
82
83 // controls for mapmaking
88
89 // run source finding
91};
92
114
116 // source name
118
119 // beammap source position
121
122 // fluxes and errs
123 std::map<std::string, double> beammap_fluxes_mJy_beam, beammap_err_mJy_beam;
124 std::map<std::string, double> beammap_fluxes_MJy_Sr, beammap_err_MJy_Sr;
125
126 // maximum beammap iterations
128
129 // beammap tolerance
131
132 // subtract reference detector
134
135 // beammap reference detector
137
138 // derotate fitted detectors
140
141 // iteration to write out ptcdata
143
144 // upper and lower limits of psd for sensitivity calc
145 Eigen::VectorXd sens_psd_limits_Hz;
146
147 // limits on fwhm, sig2noise, and distance from center for flagging
148 std::map<std::string, double> lower_fwhm_arcsec, upper_fwhm_arcsec, lower_sig2noise,
150
151 // limits on sensitivity for flagging
153};
154
155class Engine: public reduControls, public reduClasses, public beammapControls {
156public:
157 // type for missing/invalid keys
158 using key_vec_t = std::vector<std::vector<std::string>>;
159
160 // get logger
161 std::shared_ptr<spdlog::logger> logger = spdlog::get("citlali_logger");
162
163 // for timing
164 Eigen::VectorXd t_common;
165 std::vector<Eigen::VectorXi> masks;
166 std::vector<Eigen::VectorXd> nw_times;
167
168 // date/time of each obs
169 std::vector<std::string> date_obs;
170
171 // add extra output for debugging
173
174 // time gaps
175 std::map<std::string,int> gaps;
176
177 // output directory and optional sub directory name
179
180 // reduction directory number
182
183 // obsnum and coadded directory names
185
186 // tod output file name
187 std::map<std::string, std::string> tod_filename;
188
189 // vectors to hold missing/invalid keys
191
192 // number of threads
194
195 // parallel execution policy
196 std::string parallel_policy;
197
198 // number of scans completed
200
201 // manual offsets for nws and hwp
202 std::map<std::string,double> interface_sync_offset;
203
204 // vectors for tod alignment offsets
205 std::vector<Eigen::Index> start_indices, end_indices;
206
207 // indices for hwpr alignment offsets
209
210 // xs, rs, is, qs
211 std::string tod_type;
212
213 // reduction type (science, pointing, beammap)
214 std::string redu_type;
215
216 // obsnum
217 std::string obsnum;
218
219 // write filtered maps as they complete
221
222 // rtc or ptc types
224
225 // map grouping and algorithm
227
228 // number of maps
230
231 // mapping from index in map vector to array index
233
234 // mapping from index in map vector to array index
235 Eigen::VectorXI maps_to_stokes;
236
237 // current fruit loops iteration
239
240 // manual pointing offsets
241 std::map<std::string, Eigen::VectorXd> pointing_offsets_arcsec;
242 // modified julian dates of pointing offsets
244
245 // map output files
246 std::vector<fitsIO<file_type_enum::write_fits, CCfits::ExtHDU*>> fits_io_vec, noise_fits_io_vec;
247 std::vector<fitsIO<file_type_enum::write_fits, CCfits::ExtHDU*>> filtered_fits_io_vec, filtered_noise_fits_io_vec;
248
249 // coadded map output files
250 std::vector<fitsIO<file_type_enum::write_fits, CCfits::ExtHDU*>> coadd_fits_io_vec, coadd_noise_fits_io_vec;
251 std::vector<fitsIO<file_type_enum::write_fits, CCfits::ExtHDU*>> filtered_coadd_fits_io_vec, filtered_coadd_noise_fits_io_vec;
252
253 // per obsnum setup common to all redu types
254 void obsnum_setup();
255
256 // get RTC config options
257 template<typename CT>
258 void get_rtc_config(CT &);
259
260 // get PTC config options
261 template<typename CT>
262 void get_ptc_config(CT &);
263
264 // get timestream config options
265 template<typename CT>
266 void get_timestream_config(CT &);
267
268 // get beammap config options
269 template<typename CT>
270 void get_beammap_config(CT &);
271
272 // get mapmaking config options
273 template<typename CT>
274 void get_mapmaking_config(CT &);
275
276 // get map filtering config options
277 template<typename CT>
278 void get_map_filter_config(CT &);
279
280 // get all non-input config options and call other config functions
281 template<typename CT>
282 void get_citlali_config(CT &);
283
284 // get source fluxes (beammap only)
285 template<typename CT>
286 void get_photometry_config(CT &);
287
288 // get pointing offsets
289 template<typename CT>
290 void get_astrometry_config(CT &);
291
292 // create fits files (does not populate them)
294
295 // add FITS header values to tod files
296 template <class map_buffer_t>
297 void add_tod_header(map_buffer_t &);
298
299 // create tod files (does not populate them)
300 template <engine_utils::toltecIO::ProdType prod_t>
301 void create_tod_files();
302
303 // output obs summary at command line
304 void cli_summary();
305
306 // write time chunk summary (verbose mode)
307 template <TCDataKind tc_t>
309
310 // write map summary (verbose mode)
311 template <typename map_buffer_t>
312 void write_map_summary(map_buffer_t &);
313
314 // create filenames
317 auto setup_filenames(std::string dir_name);
318
319 // create variable names for maps, psds, and hists
320 auto get_map_name(int);
321
322 // add primary header to FITS files
323 template <typename fits_io_type, class map_buffer_t>
324 void add_phdu(fits_io_type &, map_buffer_t &, Eigen::Index);
325
326 // add maps to FITS files and output them
327 template <typename fits_io_type, class map_buffer_t>
328 void write_maps(fits_io_type &, fits_io_type &, map_buffer_t &, Eigen::Index);
329
330 // write map psds
331 template <mapmaking::MapType map_t, class map_buffer_t>
332 void write_psd(map_buffer_t &, std::string);
333
334 // write map histograms
335 template <mapmaking::MapType map_t, class map_buffer_t>
336 void write_hist(map_buffer_t &, std::string);
337
338 // write stats netCDF4 file
339 void write_stats();
340
341 // run the wiener filter
342 template <mapmaking::MapType map_t, class map_buffer_t>
343 void run_wiener_filter(map_buffer_t &);
344
345 // find sources in the maps
346 template <mapmaking::MapType map_t, class map_buffer_t>
347 void find_sources(map_buffer_t &);
348
349 // write the sources to ecsv table
350 template <mapmaking::MapType map_t, class map_buffer_t>
351 void write_sources(map_buffer_t &, std::string);
352};
353
356 // get atm model
358
359 logger->info("using {} model for extinction correction",rtcproc.calibration.extinction_model);
360
361 // check tau (may be unnecessary now)
362 if (!telescope.sim_obs) {
363 Eigen::VectorXd tau_el(1);
364 // get mean elevation
365 tau_el << telescope.tel_data["TelElAct"].mean();
366 // get tau at mean elevation for each band
367 auto tau_freq = rtcproc.calibration.calc_tau(tau_el, telescope.tau_225_GHz);
368 // loop through and make sure average tau is not negative (implies wrong model)
369 for (auto const& [key, val] : tau_freq) {
370 if (val[0] < 0) {
371 logger->error("calculated mean {} tau {} < 0",toltec_io.array_name_map[key], val[0]);
372 std::exit(EXIT_FAILURE);
373 }
374 }
375 }
376 }
377 else {
379 }
380
381 // make sure there are matched fg's in apt if reducing in polarized mode
383 if ((calib.apt["fg"].array()==-1).all()) {
384 logger->error("no matched freq groups. cannot run in polarized mode");
385 std::exit(EXIT_FAILURE);
386 }
387 }
388
389 // setup kernel
390 if (rtcproc.run_kernel) {
392 }
393
394 // set despiker sample rate
396
397 // if filter is requested, make it here
400 }
401
402 // set map wcs crvals to source ra/dec
403 if (telescope.pixel_axes == "radec") {
404 omb.wcs.crval[0] = telescope.tel_header["Header.Source.Ra"](0)*RAD_TO_DEG;
405 omb.wcs.crval[1] = telescope.tel_header["Header.Source.Dec"](0)*RAD_TO_DEG;
406
407 if (run_coadd) {
408 cmb.wcs.crval[0] = telescope.tel_header["Header.Source.Ra"](0)*RAD_TO_DEG;
409 cmb.wcs.crval[1] = telescope.tel_header["Header.Source.Dec"](0)*RAD_TO_DEG;
410 }
411 }
412
413 // set map wcs crvals to source l/b
414 else if (telescope.pixel_axes == "galactic") {
415 omb.wcs.crval[0] = telescope.tel_header["Header.Source.L"](0)*RAD_TO_DEG;
416 omb.wcs.crval[1] = telescope.tel_header["Header.Source.B"](0)*RAD_TO_DEG;
417
418 if (run_coadd) {
419 cmb.wcs.crval[0] = telescope.tel_header["Header.Source.L"](0)*RAD_TO_DEG;
420 cmb.wcs.crval[1] = telescope.tel_header["Header.Source.B"](0)*RAD_TO_DEG;
421 }
422 }
423
424 // create timestream files
425 if (run_tod_output) {
426 // create tod output subdirectory if requested
427 if (tod_output_subdir_name!="null") {
428 fs::create_directories(obsnum_dir_name + "raw/" + tod_output_subdir_name);
429 }
430 // make rtc tod output file
431 if (tod_output_type == "rtc" || tod_output_type == "both") {
432 create_tod_files<engine_utils::toltecIO::rtc_timestream>();
433 }
434 // make ptc tod output file
435 if (tod_output_type == "ptc" || tod_output_type == "both") {
436 create_tod_files<engine_utils::toltecIO::ptc_timestream>();
437 }
438 }
439 // don't calculate any eigenvalues
440 else if (!diagnostics.write_evals) {
442 }
443
444 // tod output mode require sequential policy so set explicitly
445 if (run_tod_output) {
446 logger->warn("tod output mode require sequential policy. "
447 "parallelization will be disabled for some stages.");
448 parallel_policy = "seq";
449 }
450
451 // output basic info for obs reduction to command line
452 cli_summary();
453
454 // set up per-det stats file values
455 for (const auto &stat: diagnostics.det_stats_header) {
456 diagnostics.stats[stat].setZero(calib.n_dets, telescope.scan_indices.cols());
457 }
458 // set up per-group stats file values
459 for (const auto &stat: diagnostics.grp_stats_header) {
460 diagnostics.stats[stat].setZero(calib.n_arrays, telescope.scan_indices.cols());
461 }
462 // clear stored eigenvalues
463 std::map<Eigen::Index, std::vector<std::vector<Eigen::VectorXd>>>().swap(diagnostics.evals);
464}
465
466template<typename CT>
467void Engine::get_rtc_config(CT &config) {
468 logger->info("getting rtc config options");
469 // get rtcproc config
471
472 // offset inner chunks
475 }
476 // otherwise start at zero
477 else {
479 }
480
481 // ignore hwpr?
483 std::tuple{"timestream","polarimetry", "ignore_hwpr"});
484}
485
486template<typename CT>
487void Engine::get_ptc_config(CT &config) {
488 logger->info("getting ptc config options");
489 // get ptcproc config
491
492 // copy tod output bool for eigenvalues
495}
496
497template<typename CT>
499 logger->info("getting timestream config options");
500 // run tod processing
502 std::tuple{"timestream","enabled"});
503 // tod type (xs, rs, is, qs)
505 std::tuple{"timestream","type"});
506
507 // run rtc or ptc tod output?
508 bool run_tod_output_rtc, run_tod_output_ptc;
509 // output rtc
510 get_config_value(config, run_tod_output_rtc, missing_keys, invalid_keys,
511 std::tuple{"timestream","raw_time_chunk","output","enabled"});
512 // output ptc
513 get_config_value(config, run_tod_output_ptc, missing_keys, invalid_keys,
514 std::tuple{"timestream","processed_time_chunk","output","enabled"});
515 // set tod output to false by default
516 run_tod_output = false;
517
518 // check if rtc output is requested
519 if (run_tod_output_rtc) {
520 run_tod_output = true;
521 tod_output_type = "rtc";
522 }
523 // if ptc output is requested
524 if (run_tod_output_ptc) {
525 // check if rtc output was requested
526 if (run_tod_output == true) {
527 tod_output_type = "both";
528 }
529 // else just output ptc
530 else {
531 run_tod_output = true;
532 tod_output_type = "ptc";
533 }
534 }
535
536 // tod subdirectory name
538 std::tuple{"timestream","output", "subdir_name"});
539 // write eigenvalues to stats file
541 std::tuple{"timestream","output", "stats","eigenvalues"});
542 // get time chunk size
544 std::tuple{"timestream","chunking", "chunk_mode"});
545 // get time chunk size
547 std::tuple{"timestream","chunking", "value"});
548 // force chunking?
550 std::tuple{"timestream","chunking", "force_chunking"});
551
552 /* get raw time chunk config */
553 get_rtc_config(config);
554
555 /* get processed time chunk config */
556 get_ptc_config(config);
557}
558
559template<typename CT>
561 logger->info("getting mapmaking config options");
562 // enable mapmaking?
564 std::tuple{"mapmaking","enabled"});
565 // map grouping
567 std::tuple{"mapmaking","grouping"},{"auto","array","nw","detector","fg"});
568
569 // polarization is disabled for detector grouping
570 if (rtcproc.run_polarization && ((redu_type=="beammap" && map_grouping=="auto") || map_grouping=="detector")) {
571 logger->error("Detector grouping reductions do not currently support polarimetry mode");
572 std::exit(EXIT_FAILURE);
573 }
574
575 // set rtcproc map_grouping
577
578 // map_method
580 std::tuple{"mapmaking","method"},{"naive","jinc","maximum_likelihood"});
581
582 // map reference frame (radec, altaz, galactic)
584 std::tuple{"mapmaking","pixel_axes"},{"radec","altaz", "galactic"});
585
586 // get config for omb
587 logger->info("getting omb config options");
589
590 // run coaddition?
592 std::tuple{"coadd","enabled"});
593
594 // re-run to get config for cmb
595 if (run_coadd) {
596 logger->info("getting cmb config options");
598 }
599
600 // if flux calibration is not enabled, use tod type units (xs, rs, is, or qs)
601 if (!rtcproc.run_calibrate) {
604 }
605
606 // set parallelization for psd filter ffts (maintained with tod output/verbose mode)
610
611 if (map_method=="jinc") {
612 // maximum radius for jinc filter
614 std::tuple{"mapmaking","jinc_filter","r_max"});
615 // get jinc filter shape params
616 for (auto const& [arr_index, arr_name] : toltec_io.array_name_map) {
617 auto jinc_shape_vec = config.template get_typed<std::vector<double>>(std::tuple{"mapmaking","jinc_filter","shape_params",arr_name});
618 jinc_mm.shape_params[arr_index] = Eigen::Map<Eigen::VectorXd>(jinc_shape_vec.data(),jinc_shape_vec.size());
619 }
620
621 if (jinc_mm.mode=="matrix") {
622 // allocate jinc matrix
624 }
625 else if (jinc_mm.mode=="splines") {
626 // precompute jinc spline
628 }
629 }
630
631 else if (map_method=="maximum_likelihood") {
633 std::tuple{"mapmaking","maximum_likelihood","tolerance"});
635 std::tuple{"mapmaking","maximum_likelihood","max_iterations"});
636 }
637
638 // make noise maps?
640 std::tuple{"noise_maps","enabled"});
641 if (run_noise) {
642 // number of noise maps
644 std::tuple{"noise_maps","n_noise_maps"},{},{0},{});
645 // randomize noise maps on detector as well as time chunk
647 std::tuple{"noise_maps","randomize_dets"});
648
649 if (run_coadd) {
650 // copy omb number of noise maps to cmb
652 // copy randomize_dets to cmb
654 }
655 }
656 // otherwise set number of noise maps to zero
657 else {
658 omb.n_noise = 0;
659 cmb.n_noise = 0;
660 }
661
662 // set mapmaker polarization
665}
666
667template<typename CT>
669 logger->info("getting beammap config options");
670 // max beammap iteration
672 std::tuple{"beammap","iter_max"});
673 // beammap iteration tolerance
675 std::tuple{"beammap","iter_tolerance"});
676 // beammap reference detector
678 std::tuple{"beammap","reference_det"});
679 // subtract reference detector?
681 std::tuple{"beammap","subtract_reference_det"});
682 // derotate apt?
684 std::tuple{"beammap","derotate"});
685
686 // lower fwhm limit
687 auto lower_fwhm_arcsec_vec = config.template get_typed<std::vector<double>>(std::tuple{"beammap","flagging","array_lower_fwhm_arcsec"});
688 // upper fwhm limit
689 auto upper_fwhm_arcsec_vec = config.template get_typed<std::vector<double>>(std::tuple{"beammap","flagging","array_upper_fwhm_arcsec"});
690 // lower signal-to-noise limit
691 auto lower_sig2noise_vec = config.template get_typed<std::vector<double>>(std::tuple{"beammap","flagging","array_lower_sig2noise"});
692 // upper signal-to-noise limit
693 auto upper_sig2noise_vec = config.template get_typed<std::vector<double>>(std::tuple{"beammap","flagging","array_upper_sig2noise"});
694 // maximum allowed distance limit
695 auto max_dist_arcsec_vec = config.template get_typed<std::vector<double>>(std::tuple{"beammap","flagging","array_max_dist_arcsec"});
696
697 // add params to respective array values
698 Eigen::Index i = 0;
699 for (auto const& [arr_index, arr_name] : toltec_io.array_name_map) {
700 // lower fwhm limit
701 lower_fwhm_arcsec[arr_name] = lower_fwhm_arcsec_vec[i];
702 // upper fwhm limit
703 upper_fwhm_arcsec[arr_name] = upper_fwhm_arcsec_vec[i];
704 // lower signal-to-noise limit
705 lower_sig2noise[arr_name] = lower_sig2noise_vec[i];
706 // upper signal-to-noise limit
707 upper_sig2noise[arr_name] = upper_sig2noise_vec[i];
708 // maximum allowed distance limit
709 max_dist_arcsec[arr_name] = max_dist_arcsec_vec[i];
710 i++;
711 }
712
713 // sensitivity factors
714 auto sens_factors_vec = config.template get_typed<std::vector<double>>(std::tuple{"beammap","flagging","sens_factors"});
715 lower_sens_factor = sens_factors_vec[0];
716 upper_sens_factor = sens_factors_vec[1];
717
718 // upper and lower frequencies over which to calculate sensitivity
719 sens_psd_limits_Hz.resize(2);
720 // get psd limits for sens from config
721 auto sens_psd_limits_Hz_vec = config.template get_typed<std::vector<double>>(std::tuple{"beammap","sens_psd_limits_Hz"});
722 // map sens limits back to Eigen vector
723 sens_psd_limits_Hz = (Eigen::Map<Eigen::VectorXd>(sens_psd_limits_Hz_vec.data(), sens_psd_limits_Hz_vec.size()));
724
725 // if no tolerance is specified, write out max iteration tod
726 if (run_tod_output) {
727 if (beammap_iter_tolerance <=0) {
729 }
730 // otherwise write out first iteration tod
731 else {
733 }
734 }
735}
736
737template<typename CT>
739 logger->info("getting map filtering config options");
740 // get wiener filter config options
742
743 // if in science mode, write filtered maps as they complete
744 if (redu_type=="science") {
746 }
747 // otherwise write at end
748 else {
750 }
751 // check if kernel is enabled
752 if (wiener_filter.template_type=="kernel") {
753 if (!rtcproc.run_kernel) {
754 logger->error("wiener filter kernel template requires kernel");
755 std::exit(EXIT_FAILURE);
756 }
757 // copy the map fitter
758 else {
760 }
761 }
762 // make sure noise maps were enabled
763 if (!run_noise && (!wiener_filter.run_lowpass && wiener_filter.filter_type=="wiener_filter")) {
764 logger->error("wiener filter requires noise maps");
765 std::exit(EXIT_FAILURE);
766 }
767
768 // set parallelization for ffts (maintained with tod output/verbose mode)
770}
771
772template<typename CT>
774 // get interface offsets
775 if (config.has(std::tuple{"interface_sync_offset"})) {
776 auto interface_node = config.get_node(std::tuple{"interface_sync_offset"});
777 // interface key names
778 std::vector<std::string> interface_keys = {
779 "toltec0",
780 "toltec1",
781 "toltec2",
782 "toltec3",
783 "toltec4",
784 "toltec5",
785 "toltec6",
786 "toltec7",
787 "toltec8",
788 "toltec9",
789 "toltec10",
790 "toltec11",
791 "toltec12",
792 "hwpr"
793 };
794 // loop through interfaces
795 for (Eigen::Index i=0; i<interface_node.size(); ++i) {
796 auto offset = config.template get_typed<double>(std::tuple{"interface_sync_offset",i, interface_keys[i]});
797 interface_sync_offset[interface_keys[i]] = offset;
798 }
799 }
800
801 // verbose mode?
803 std::tuple{"runtime","verbose"});
804 // output directory
806 std::tuple{"runtime","output_dir"});
807 // number of threads to use
809 std::tuple{"runtime","n_threads"});
810 // overall parallel policy
812 std::tuple{"runtime","parallel_policy"},{"seq","omp"});
813 // reduction type (science, pointing, beammap)
815 std::tuple{"runtime","reduction_type"},{"science","pointing","beammap"});
816 // create redu00, redu01... subdirectories
818 std::tuple{"runtime","use_subdir"});
819 // interp over gaps in align_timestream
821 std::tuple{"runtime","interp_over_gaps"});
822
823 /* get timestream config */
824 get_timestream_config(config);
825
826 /* get mapmaking config */
827 get_mapmaking_config(config);
828
829 // run map filter?
831 std::tuple{"post_processing","map_filtering","enabled"});
832
833 // run source finder?
835 std::tuple{"post_processing","source_finding","enabled"});
836
837 // map fitter options if in pointing or beammap mode or if map filtering or source finding are enabled
838 if (redu_type=="pointing" || redu_type=="beammap" || run_map_filter || run_source_finder) {
839 // size of region around found source to fit
841 std::tuple{"post_processing","source_fitting","bounding_box_arcsec"},{},{0});
842 // radius around center of map to find source within
844 std::tuple{"post_processing","source_fitting","fitting_radius_arcsec"});
845 // fit 2d gaussian rotation angle
847 std::tuple{"post_processing","source_fitting", "gauss_model","fit_rotation_angle"});
848
849 // convert bounding box and fitting region to pixels
852
853 // fitter flux and fwhm limits
854 map_fitter.flux_limits.resize(2);
855 map_fitter.fwhm_limits.resize(2);
856 for (Eigen::Index i=0; i<map_fitter.flux_limits.size(); ++i) {
857 // flux limit
858 map_fitter.flux_limits(i) = config.template get_typed<double>(std::tuple{"post_processing","source_fitting",
859 "gauss_model","amp_limit_factors",i});
860 // fwhm limit
861 map_fitter.fwhm_limits(i) = config.template get_typed<double>(std::tuple{"post_processing","source_fitting",
862 "gauss_model","fwhm_limit_factors",i});
863 }
864
865 // flux lower factor
866 if (map_fitter.flux_limits(0) > 0) {
868 }
869 // flux lower factor
870 if (map_fitter.flux_limits(1) > 0) {
872 }
873 // fwhm lower factor
874 if (map_fitter.fwhm_limits(0) > 0) {
876 }
877 // fwhm upper factor
878 if (map_fitter.fwhm_limits(1) > 0) {
880 }
881 }
882
883 /* get wiener filter config */
884 if (run_map_filter) {
885 // needs map fitter config
886 get_map_filter_config(config);
887 }
888
889 // get source finder config options
890 if (run_source_finder) {
891 // minimum found source sigma
893 std::tuple{"post_processing","source_finding","source_sigma"});
894 // window around source to exclude other sources
896 std::tuple{"post_processing","source_finding","source_window_arcsec"});
897 // search map, negative of map, or both
899 std::tuple{"post_processing","source_finding","mode"});
900
901 // convert source window to radians
903
904 if (run_coadd) {
905 // copy omb source sigma to cmb
907 // copy omb source_window_rad to cmb
909 // copy omb source_finder_mode to cmb
911 }
912 }
913
914 /* get beammap config */
915 if (redu_type=="beammap") {
916 // needs redu_type config
917 get_beammap_config(config);
918 }
919
920 // disable map related keys if map-making is disabled
921 if (!run_mapmaking) {
922 run_coadd = false;
923 run_noise = false;
924 run_map_filter = false;
925 run_source_finder = false;
926 // we don't need to do iterations if no maps are made
928 }
929}
930
931template<typename CT>
933 // beammap source name
935 std::tuple{"beammap_source","name"});
936 // beammap source ra
938 std::tuple{"beammap_source","ra_deg"});
939 // convert ra to radians
941
942 // beammap source dec
944 std::tuple{"beammap_source","dec_deg"});
945 // convert dec to radians
947
948 // number of fluxes
949 Eigen::Index n_fluxes = config.get_node(std::tuple{"beammap_source","fluxes"}).size();
950
951 // get source fluxes
952 for (Eigen::Index i=0; i<n_fluxes; ++i) {
953 auto array = config.get_str(std::tuple{"beammap_source","fluxes",i,"array_name"});
954 // source flux in mJy/beam
955 auto flux = config.template get_typed<double>(std::tuple{"beammap_source","fluxes",i,"value_mJy"});
956 // source flux uncertainty in mJy/beam
957 auto uncertainty_mJy = config.template get_typed<double>(std::tuple{"beammap_source","fluxes",i,"uncertainty_mJy"});
958
959 // copy flux and uncertainty
960 beammap_fluxes_mJy_beam[array] = flux;
961 beammap_err_mJy_beam[array] = uncertainty_mJy;
962 }
963}
964
965template<typename CT>
967 // check if config file has pointing_offsets
968 if (config.has("pointing_offsets")) {
969 std::vector<double> offset;
970 // get az offset
971 offset = config.template get_typed<std::vector<double>>(std::tuple{"pointing_offsets",0,"value_arcsec"});
972 pointing_offsets_arcsec["az"] = Eigen::Map<Eigen::VectorXd>(offset.data(),offset.size());
973 // get alt offset
974 offset = config.template get_typed<std::vector<double>>(std::tuple{"pointing_offsets",1,"value_arcsec"});
975 pointing_offsets_arcsec["alt"] = Eigen::Map<Eigen::VectorXd>(offset.data(),offset.size());
976
977 // get julian date of pointing offsets
978 try {
979 offset = config.template get_typed<std::vector<double>>(std::tuple{"pointing_offsets",2,"modified_julian_date"});
980 pointing_offsets_modified_julian_date = Eigen::Map<Eigen::VectorXd>(offset.data(),offset.size());
981 }
982 catch (...) {
984 }
985 }
986 else {
987 logger->error("pointing_offsets not found in config");
988 std::exit(EXIT_FAILURE);
989 }
990}
991
993 // clear fits vectors for each observation
994 fits_io_vec.clear();
995 noise_fits_io_vec.clear();
996 filtered_fits_io_vec.clear();
998
999 // loop through arrays
1000 for (Eigen::Index i=0; i<calib.n_arrays; ++i) {
1001 // array index
1002 auto array = calib.arrays[i];
1003 // array name
1004 std::string array_name = toltec_io.array_name_map[array];
1005 // map filename
1009 // create fits_io class for current array file
1011 // append to fits_io vector
1012 fits_io_vec.push_back(std::move(fits_io));
1013
1014 // if noise maps are requested but coadding is not, populate noise fits vector
1015 if (!run_coadd) {
1016 if (run_noise) {
1017 // noise map filename
1021 // create fits_io class for current array file
1023 // append to fits_io vector
1024 noise_fits_io_vec.push_back(std::move(fits_io));
1025 }
1026
1027 // map filtering
1028 if (run_map_filter) {
1029 // filtered map filename
1032 redu_type, array_name,
1034 // create fits_io class for current array file
1036 // append to fits_io vector
1037 filtered_fits_io_vec.push_back(std::move(fits_io));
1038
1039 // filtered noise maps
1040 if (run_noise) {
1041 // filtered noise map filename
1044 array_name, obsnum, telescope.sim_obs);
1045 // create fits_io class for current array file
1047 // append to fits_io vector
1048 filtered_noise_fits_io_vec.push_back(std::move(fits_io));
1049 }
1050 }
1051 }
1052 }
1053}
1054
1055template <class map_buffer_t>
1056void Engine::add_tod_header(map_buffer_t &mb) {
1057 // loop through viles
1058 for (const auto & [fkey, fval]: tod_filename) {
1059 netCDF::NcFile fo(fval, netCDF::NcFile::write);
1060
1061 // add unit conversions
1062 if (rtcproc.run_calibrate) {
1063 for (const auto &val: calib.arrays) {
1064 auto name = toltec_io.array_name_map[val];
1065 // conversion to uK
1066 auto fwhm = (std::get<0>(calib.array_fwhms[val]) + std::get<1>(calib.array_fwhms[val]))/2;
1067 auto mJy_beam_to_uK = engine_utils::mJy_beam_to_uK(1, toltec_io.array_freq_map[val], fwhm*ASEC_TO_RAD);
1068
1069 // beam area in steradians
1070 auto beam_area_rad = 2.*pi*pow(fwhm*FWHM_TO_STD*ASEC_TO_RAD,2);
1071 // get Jy/pixel
1072 auto mJy_beam_to_Jy_px = 1e-3/beam_area_rad*pow(omb.pixel_size_rad,2);
1073
1074 if (omb.sig_unit == "mJy/beam") {
1075 // conversion to mJy/beam
1076 add_netcdf_var(fo, "to_mJy_beam_"+name, 1);
1077 // conversion to MJy/sr
1078 add_netcdf_var(fo, "to_MJy_sr_"+name, 1/(calib.array_beam_areas[val]*MJY_SR_TO_mJY_ASEC));
1079 // conversion to uK
1080 add_netcdf_var(fo, "to_uK_"+name, mJy_beam_to_uK);
1081 // conversion to Jy/pixel
1082 add_netcdf_var(fo, "to_Jy_pixel_"+name, mJy_beam_to_Jy_px);
1083 }
1084 else if (omb.sig_unit == "MJy/sr") {
1085 // conversion to mJy/beam
1086 add_netcdf_var(fo, "to_mJy_beam_"+name, calib.array_beam_areas[val]*MJY_SR_TO_mJY_ASEC);
1087 // conversion to MJy/Sr
1088 add_netcdf_var(fo, "to_MJy_sr_"+name, 1);
1089 // conversion to uK
1090 add_netcdf_var(fo, "to_uK_"+name, calib.array_beam_areas[val]*MJY_SR_TO_mJY_ASEC*mJy_beam_to_uK);
1091 // conversion to Jy/pixel
1092 add_netcdf_var(fo, "to_Jy_pixel_"+name, calib.array_beam_areas[val]*MJY_SR_TO_mJY_ASEC*mJy_beam_to_Jy_px);
1093 }
1094 else if (omb.sig_unit == "uK") {
1095 // conversion to mJy/beam
1096 add_netcdf_var(fo, "to_mJy_beam_"+name, 1/mJy_beam_to_uK);
1097 // conversion to MJy/sr
1098 add_netcdf_var(fo, "to_MJy_sr_"+name, 1/mJy_beam_to_uK/(calib.array_beam_areas[val]*MJY_SR_TO_mJY_ASEC));
1099 // conversion to uK
1100 add_netcdf_var(fo, "to_uK_"+name, 1);
1101 // conversion to Jy/pixel
1102 add_netcdf_var(fo, "to_Jy_pixel_"+name, (1/mJy_beam_to_uK)*mJy_beam_to_Jy_px);
1103 }
1104 else if (omb.sig_unit == "Jy/pixel") {
1105 // conversion to mJy/beam
1106 add_netcdf_var(fo, "to_mJy_beam_"+name, 1/mJy_beam_to_Jy_px);
1107 // conversion to MJy/sr
1108 add_netcdf_var(fo, "to_MJy_sr_"+name, (1/mJy_beam_to_Jy_px)/(calib.array_beam_areas[val]*MJY_SR_TO_mJY_ASEC));
1109 // conversion to uK
1110 add_netcdf_var(fo, "to_uK_"+name, mJy_beam_to_uK/mJy_beam_to_Jy_px);
1111 // conversion to Jy/pixel
1112 add_netcdf_var(fo, "to_Jy_pixel_"+name, 1);
1113 }
1114 }
1115 }
1116
1117 // add date and time of obs
1118 add_netcdf_var<std::string>(fo, "DATEOBS0", date_obs.back());
1119
1120 // add source
1121 add_netcdf_var<std::string>(fo,"SOURCE",telescope.source_name);
1122
1123 // add source flux for beammaps
1124 if (redu_type == "beammap") {
1125 for (const auto &val: calib.arrays) {
1126 auto name = toltec_io.array_name_map[val];
1127 add_netcdf_var(fo, "HEADER.SOURCE.FLUX_MJYPERBEAM_"+name, beammap_fluxes_mJy_beam[name]);
1128 add_netcdf_var(fo, "HEADER.SOURCE.FLUX_MJYPERSR_"+name, beammap_fluxes_MJy_Sr[name]);
1129 }
1130 add_netcdf_var(fo, "BEAMMAP.ITER_TOLERANCE", beammap_iter_tolerance);
1131 add_netcdf_var(fo, "BEAMMAP.ITER_MAX", beammap_iter_max);
1132 add_netcdf_var(fo, "BEAMMAP.IS_DEROTATED", beammap_derotate);
1133
1134 // add reference detector information
1136 add_netcdf_var(fo, "BEAMMAP.REF_DET_INDEX", beammap_reference_det);
1137 add_netcdf_var(fo, "BEAMMAP.REF_X_T", calib.apt["x_t"](beammap_reference_det));
1138 add_netcdf_var(fo, "BEAMMAP.REF_Y_T", calib.apt["y_t"](beammap_reference_det));
1139 }
1140 else {
1141 add_netcdf_var(fo, "BEAMMAP.REF_DET_INDEX", -99);
1142 add_netcdf_var(fo, "BEAMMAP.REF_X_T", -99);
1143 add_netcdf_var(fo, "BEAMMAP.REF_Y_T", -99);
1144 }
1145 }
1146
1147 add_netcdf_var<std::string>(fo,"INSTRUME","TolTEC");
1148 add_netcdf_var(fo, "HWPR", calib.run_hwpr);
1149 add_netcdf_var<std::string>(fo, "TELESCOP", "LMT");
1150 add_netcdf_var<std::string>(fo, "PIPELINE", "CITLALI");
1151 add_netcdf_var<std::string>(fo, "VERSION", CITLALI_GIT_VERSION);
1152 add_netcdf_var<std::string>(fo, "KIDS", KIDSCPP_GIT_VERSION);
1153 add_netcdf_var<std::string>(fo, "TULA", TULA_GIT_VERSION);
1154 add_netcdf_var<std::string>(fo, "PROJID", telescope.project_id);
1155 add_netcdf_var<std::string>(fo, "GOAL", redu_type);
1156 add_netcdf_var<std::string>(fo, "OBSGOAL", telescope.obs_goal);
1157 add_netcdf_var<std::string>(fo, "TYPE", tod_type);
1158 add_netcdf_var<std::string>(fo, "GROUPING", map_grouping);
1159 add_netcdf_var<std::string>(fo, "METHOD", map_method);
1160 add_netcdf_var(fo, "EXPTIME", omb.exposure_time);
1161 add_netcdf_var<std::string>(fo, "RADESYS", telescope.pixel_axes);
1162 add_netcdf_var(fo, "TAN_RA", telescope.tel_header["Header.Source.Ra"][0]);
1163 add_netcdf_var(fo, "TAN_DEC", telescope.tel_header["Header.Source.Dec"][0]);
1164 add_netcdf_var(fo, "MEAN_EL", RAD_TO_DEG*telescope.tel_data["TelElAct"].mean());
1165 add_netcdf_var(fo, "MEAN_AZ", RAD_TO_DEG*telescope.tel_data["TelAzAct"].mean());
1166 add_netcdf_var(fo, "MEAN_PA", RAD_TO_DEG*telescope.tel_data["ActParAng"].mean());
1167
1168 // add beamsizes
1169 for (const auto &arr: calib.arrays) {
1170 if (std::get<0>(calib.array_fwhms[arr]) >= std::get<1>(calib.array_fwhms[arr])) {
1171 add_netcdf_var(fo, "BMAJ_"+toltec_io.array_name_map[arr], std::get<0>(calib.array_fwhms[arr]));
1172 add_netcdf_var(fo, "BMIN_"+toltec_io.array_name_map[arr], std::get<1>(calib.array_fwhms[arr]));
1174 }
1175 else {
1176 add_netcdf_var(fo, "BMAJ_"+toltec_io.array_name_map[arr], std::get<1>(calib.array_fwhms[arr]));
1177 add_netcdf_var(fo, "BMIN_"+toltec_io.array_name_map[arr], std::get<0>(calib.array_fwhms[arr]));
1178 add_netcdf_var(fo, "BPA_"+toltec_io.array_name_map[arr], (calib.array_pas[arr] + pi/2)*RAD_TO_DEG);
1179 }
1180 }
1181
1182 add_netcdf_var(fo, "BUNIT", omb.sig_unit);
1183
1184 // add jinc shape params
1185 if (map_method=="jinc") {
1186 add_netcdf_var(fo, "JINC_R", jinc_mm.r_max);
1187 for (const auto &[key,val]: toltec_io.array_name_map) {
1188 add_netcdf_var(fo, "JINC_A_"+val, jinc_mm.shape_params[calib.arrays(key)][0]);
1189 add_netcdf_var(fo, "JINC_B_"+val, jinc_mm.shape_params[calib.arrays(key)][0]);
1190 add_netcdf_var(fo, "JINC_C_"+val, jinc_mm.shape_params[calib.arrays(key)][0]);
1191 }
1192 }
1193
1194 // add mean tau
1195 if (rtcproc.run_extinction) {
1196 Eigen::VectorXd tau_el(1);
1197 tau_el << telescope.tel_data["TelElAct"].mean();
1198 auto tau_freq = rtcproc.calibration.calc_tau(tau_el, telescope.tau_225_GHz);
1199
1200 Eigen::Index i = 0;
1201 for (auto const& [key, val] : tau_freq) {
1202 add_netcdf_var(fo, "MEAN_TAU_"+toltec_io.array_name_map[calib.arrays(i)], val[0]);
1203 i++;
1204 }
1205 }
1206 else {
1207 for (Eigen::Index i=0; i<calib.arrays.size(); ++i) {
1208 add_netcdf_var(fo, "MEAN_TAU_"+toltec_io.array_name_map[calib.arrays(i)], 0.);
1209 }
1210 }
1211
1212 // add sample rate
1213 add_netcdf_var(fo, "SAMPRATE", telescope.fsmp);
1214
1215 // add apt table
1216 std::vector<string> apt_filename;
1217 std::stringstream ss(calib.apt_filepath);
1218 std::string item;
1219 char delim = '/';
1220
1221 while (getline (ss, item, delim)) {
1222 apt_filename.push_back(item);
1223 }
1224 add_netcdf_var<std::string>(fo, "APT", apt_filename.back());
1225
1226 add_netcdf_var(fo, "FRUITLOOPS_ITER", fruit_iter);
1227
1228 // add control/runtime parameters
1229 add_netcdf_var(fo, "CONFIG.VERBOSE", verbose_mode);
1230 add_netcdf_var(fo, "CONFIG.POLARIZED", rtcproc.run_polarization);
1231 add_netcdf_var(fo, "CONFIG.DESPIKED", rtcproc.run_despike);
1232 add_netcdf_var(fo, "CONFIG.TODFILTERED", rtcproc.run_tod_filter);
1233 add_netcdf_var(fo, "CONFIG.DOWNSAMPLED", rtcproc.run_downsample);
1234 add_netcdf_var(fo, "CONFIG.CALIBRATED", rtcproc.run_calibrate);
1235 add_netcdf_var(fo, "CONFIG.EXTINCTION", rtcproc.run_extinction);
1236 add_netcdf_var<std::string>(fo, "CONFIG.EXTINCTION.EXTMODEL", rtcproc.calibration.extinction_model);
1237 add_netcdf_var<std::string>(fo, "CONFIG.WEIGHT.TYPE", ptcproc.weighting_type);
1238 add_netcdf_var(fo, "CONFIG.INV_VAR.RTC.WTLOW", rtcproc.lower_inv_var_factor);
1239 add_netcdf_var(fo, "CONFIG.INV_VAR.RTC.WTHIGH", rtcproc.upper_inv_var_factor);
1240 add_netcdf_var(fo, "CONFIG.INV_VAR.PTC.WTLOW", ptcproc.lower_inv_var_factor);
1241 add_netcdf_var(fo, "CONFIG.INV_VAR.PTC.WTHIGH", ptcproc.upper_inv_var_factor);
1242 add_netcdf_var(fo, "CONFIG.WEIGHT.PTC.WTLOW", ptcproc.lower_weight_factor);
1243 add_netcdf_var(fo, "CONFIG.WEIGHT.PTC.WTHIGH", ptcproc.upper_weight_factor);
1244 add_netcdf_var(fo, "CONFIG.WEIGHT.MEDWTFACTOR", ptcproc.med_weight_factor);
1245 add_netcdf_var(fo, "CONFIG.CLEANED", ptcproc.run_clean);
1246
1247 // loop through arrays and add number of eigenvalues removed
1248 for (Eigen::Index i=0; i<calib.arrays.size(); ++i) {
1249 if (ptcproc.run_clean) {
1250 add_netcdf_var(fo, "CONFIG.CLEANED.NEIG_"+toltec_io.array_name_map[calib.arrays(i)],
1252 }
1253 else {
1254 add_netcdf_var(fo, "CONFIG.CLEANED.NEIG_"+toltec_io.array_name_map[calib.arrays(i)], 0);
1255 }
1256 }
1257
1258 // out-of-focus holography parameters
1259 if (! telescope.sim_obs) {
1260 add_netcdf_var(fo, "OOF_T", 3.0);
1261 add_netcdf_var(fo, "OOF_M2X", telescope.tel_header["Header.M2.XReq"](0)/1000.*1e6);
1262 add_netcdf_var(fo, "OOF_M2Y", telescope.tel_header["Header.M2.YReq"](0)/1000.*1e6);
1263 add_netcdf_var(fo, "OOF_M2Z", telescope.tel_header["Header.M2.ZReq"](0)/1000.*1e6);
1264
1265 add_netcdf_var(fo, "OOF_RO", 25.);
1266 add_netcdf_var(fo, "OOF_RI", 1.65);
1267 for (int i = 0; i < calib.arrays.size(); ++i) {
1268 double rms;
1269
1270 if (redu_type != "beammap" && run_mapmaking) {
1271 rms = pow(mb->median_err(i), 0.5);
1272 }
1273 else {
1274 rms = 0.0;
1275 }
1276 auto name = toltec_io.array_name_map[calib.arrays(i)];
1277 add_netcdf_var(fo, "OOF_RMS_" + name, rms);
1278 add_netcdf_var(fo, "OOF_W_" + name, toltec_io.array_wavelength_map[calib.arrays(i)]/1000.);
1279 add_netcdf_var(fo, "OOF_ID_" + name, static_cast<int>(toltec_io.array_wavelength_map[calib.arrays(i)]*1000));
1280 }
1281 }
1282
1283 // fruit loops parameters
1284 add_netcdf_var(fo, "CONFIG.FRUITLOOPS", ptcproc.run_fruit_loops);
1285 add_netcdf_var<std::string>(fo, "CONFIG.FRUITLOOPS.PATH", ptcproc.fruit_loops_path);
1286 add_netcdf_var(fo, "CONFIG.FRUITLOOPS.S2N", ptcproc.fruit_loops_sig2noise);
1287 for (Eigen::Index i=0; i<calib.arrays.size(); ++i) {
1289 add_netcdf_var(fo, "CONFIG.FRUITLOOPS.FLUX_"+toltec_io.array_name_map[calib.arrays(i)], ptcproc.fruit_loops_flux(calib.arrays(i)));
1290 }
1291 else {
1292 add_netcdf_var(fo, "CONFIG.FRUITLOOPS.FLUX_"+toltec_io.array_name_map[calib.arrays(i)], 0);
1293 }
1294 }
1295
1296 add_netcdf_var(fo, "CONFIG.FRUITLOOPS.MAXITER", ptcproc.fruit_loops_iters);
1297
1298 fo.close();
1299 }
1300}
1301
1302template <engine_utils::toltecIO::ProdType prod_t>
1304 // name for std map
1305 std::string name;
1306 // subdirectory name
1307 std::string dir_name = obsnum_dir_name + "raw/";
1308
1309 // if config subdirectory name is specified, add it
1310 if (tod_output_subdir_name != "null") {
1311 dir_name = dir_name + tod_output_subdir_name + "/";
1312 }
1313
1314 // rtc tod output filename setup
1315 if constexpr (prod_t == engine_utils::toltecIO::rtc_timestream) {
1320
1321 tod_filename["rtc"] = filename + ".nc";
1322 name = "rtc";
1323 }
1324
1325 // ptc tod output filename setup
1326 else if constexpr (prod_t == engine_utils::toltecIO::ptc_timestream) {
1331
1332 tod_filename["ptc"] = filename + ".nc";
1333 name = "ptc";
1334 }
1335
1336 // create netcdf file
1337 netCDF::NcFile fo(tod_filename[name], netCDF::NcFile::replace);
1338
1339 // add tod output type to file
1340 netCDF::NcDim n_tod_output_type_dim = fo.addDim("n_tod_output_type",1);
1341 netCDF::NcVar tod_output_type_var = fo.addVar("tod_output_type",netCDF::ncString, n_tod_output_type_dim);
1342 const std::vector<size_t> tod_output_type_index = {0};
1343
1344 if constexpr (prod_t == engine_utils::toltecIO::rtc_timestream) {
1345 std::string tod_output_type_name = "rtc";
1346 tod_output_type_var.putVar(tod_output_type_index,tod_output_type_name);
1347 }
1348 else if constexpr (prod_t == engine_utils::toltecIO::ptc_timestream) {
1349 std::string tod_output_type_name = "ptc";
1350 tod_output_type_var.putVar(tod_output_type_index,tod_output_type_name);
1351
1352 // number of eigenvalues
1353 netCDF::NcDim n_eigs_dim = fo.addDim("n_eigs",ptcproc.cleaner.n_calc);
1354 }
1355
1356 // add obsnum
1357 netCDF::NcVar obsnum_v = fo.addVar("obsnum",netCDF::ncInt);
1358 obsnum_v.putAtt("units","N/A");
1359 int obsnum_int = std::stoi(obsnum);
1360 obsnum_v.putVar(&obsnum_int);
1361
1362 // add source ra
1363 netCDF::NcVar source_ra_v = fo.addVar("SourceRa",netCDF::ncDouble);
1364 source_ra_v.putAtt("units","rad");
1365 source_ra_v.putVar(&telescope.tel_header["Header.Source.Ra"](0));
1366
1367 // add source dec
1368 netCDF::NcVar source_dec_v = fo.addVar("SourceDec",netCDF::ncDouble);
1369 source_dec_v.putAtt("units","rad");
1370 source_dec_v.putVar(&telescope.tel_header["Header.Source.Dec"](0));
1371
1372 netCDF::NcDim n_pts_dim = fo.addDim("n_pts");
1373 netCDF::NcDim n_raw_scan_indices_dim = fo.addDim("n_raw_scan_indices", telescope.scan_indices.rows());
1374 netCDF::NcDim n_scan_indices_dim = fo.addDim("n_scan_indices", 2);
1375 netCDF::NcDim n_scans_dim = fo.addDim("n_scans", telescope.scan_indices.cols());
1376
1377 netCDF::NcDim n_dets_dim = fo.addDim("n_dets", calib.n_dets);
1378
1379 std::vector<netCDF::NcDim> dims = {n_pts_dim, n_dets_dim};
1380 std::vector<netCDF::NcDim> raw_scans_dims = {n_scans_dim, n_raw_scan_indices_dim};
1381 std::vector<netCDF::NcDim> scans_dims = {n_scans_dim, n_scan_indices_dim};
1382
1383 // raw file scan indices
1384 netCDF::NcVar raw_scan_indices_v = fo.addVar("raw_scan_indices",netCDF::ncInt, raw_scans_dims);
1385 raw_scan_indices_v.putAtt("units","N/A");
1386 raw_scan_indices_v.putVar(telescope.scan_indices.data());
1387
1388 // scan indices for data
1389 netCDF::NcVar scan_indices_v = fo.addVar("scan_indices",netCDF::ncInt, scans_dims);
1390 scan_indices_v.putAtt("units","N/A");
1391
1392 // signal
1393 netCDF::NcVar signal_v = fo.addVar("signal",netCDF::ncDouble, dims);
1394 signal_v.putAtt("units",omb.sig_unit);
1395
1396 // chunk sizes
1397 std::vector<std::size_t> chunkSizes;
1398 // set chunk mode
1399 netCDF::NcVar::ChunkMode chunkMode = netCDF::NcVar::nc_CHUNKED;
1400
1401 // set chunking to mean scan size and n_dets
1402 chunkSizes.push_back(((telescope.scan_indices.row(3) - telescope.scan_indices.row(2)).array() + 1).mean());
1403 chunkSizes.push_back(calib.n_dets);
1404
1405 // set signal chunking
1406 signal_v.setChunking(chunkMode, chunkSizes);
1407
1408 // flags
1409 netCDF::NcVar flags_v = fo.addVar("flags",netCDF::ncDouble, dims);
1410 flags_v.putAtt("units","N/A");
1411 flags_v.setChunking(chunkMode, chunkSizes);
1412
1413 // kernel
1414 if (rtcproc.run_kernel) {
1415 netCDF::NcVar kernel_v = fo.addVar("kernel",netCDF::ncDouble, dims);
1416 kernel_v.putAtt("units","N/A");
1417 kernel_v.setChunking(chunkMode, chunkSizes);
1418 }
1419
1420 // detector lat
1421 netCDF::NcVar det_lat_v = fo.addVar("det_lat",netCDF::ncDouble, dims);
1422 det_lat_v.putAtt("units","rad");
1423 det_lat_v.setChunking(chunkMode, chunkSizes);
1424
1425 // detector lon
1426 netCDF::NcVar det_lon_v = fo.addVar("det_lon",netCDF::ncDouble, dims);
1427 det_lon_v.putAtt("units","rad");
1428 det_lon_v.setChunking(chunkMode, chunkSizes);
1429
1430 // calc absolute pointing if in radec frame
1431 if (telescope.pixel_axes == "radec") {
1432 // detector absolute ra
1433 netCDF::NcVar det_ra_v = fo.addVar("det_ra",netCDF::ncDouble, dims);
1434 det_ra_v.putAtt("units","rad");
1435 det_ra_v.setChunking(chunkMode, chunkSizes);
1436
1437 // detector absolute dec
1438 netCDF::NcVar det_dec_v = fo.addVar("det_dec",netCDF::ncDouble, dims);
1439 det_dec_v.putAtt("units","rad");
1440 det_dec_v.setChunking(chunkMode, chunkSizes);
1441 }
1442
1443 // add apt table
1444 for (auto const& x: calib.apt) {
1445 netCDF::NcVar apt_v = fo.addVar("apt_" + x.first,netCDF::ncDouble, n_dets_dim);
1446 apt_v.putAtt("units",calib.apt_header_units[x.first]);
1447 }
1448
1449 // add telescope parameters
1450 for (auto const& x: telescope.tel_data) {
1451 netCDF::NcVar tel_data_v = fo.addVar(x.first,netCDF::ncDouble, n_pts_dim);
1452 tel_data_v.putAtt("units","rad");
1453 tel_data_v.setChunking(chunkMode, chunkSizes);
1454 }
1455
1456 // add pointing offset parameters
1457 for (auto const& x: pointing_offsets_arcsec) {
1458 logger->info("pointing_offsets_arcsec.second {} {}",x.first, x.second);
1459 netCDF::NcVar offsets_v = fo.addVar("pointing_offset_"+x.first,netCDF::ncDouble, n_pts_dim);
1460 offsets_v.putAtt("units","arcsec");
1461 offsets_v.setChunking(chunkMode, chunkSizes);
1462 }
1463
1464 // add weights
1465 if constexpr (prod_t == engine_utils::toltecIO::ptc_timestream) {
1466 std::vector<netCDF::NcDim> weight_dims = {n_scans_dim, n_dets_dim};
1467 netCDF::NcVar weights_v = fo.addVar("weights",netCDF::ncDouble, weight_dims);
1468 weights_v.putAtt("units","("+omb.sig_unit+")^-2");
1469 }
1470
1471 // add hwpr
1473 if (calib.run_hwpr) {
1474 netCDF::NcVar hwpr_v = fo.addVar("hwpr",netCDF::ncDouble, n_pts_dim);
1475 hwpr_v.putAtt("units","rad");
1476 }
1477 }
1478
1479 // add tel header
1480 netCDF::NcDim tel_header_dim = fo.addDim("tel_header_n_pts", 1);
1481 for (const auto &[key,val]: telescope.tel_header) {
1482 netCDF::NcVar tel_header_v = fo.addVar(key,netCDF::ncDouble, tel_header_dim);
1483 tel_header_v.putVar(&val(0));
1484 }
1485
1486 fo.close();
1487}
1488
1489//template <TCDataKind tc_t>
1491 logger->info("reduction info");
1492 logger->info("obsnum: {}", obsnum);
1493 logger->info("map buffer rows: {}", omb.n_rows);
1494 logger->info("map buffer cols: {}", omb.n_cols);
1495 logger->info("number of maps: {}", omb.signal.size());
1496 logger->info("map units: {}", omb.sig_unit);
1497 logger->info("polarized reduction: {}", rtcproc.run_polarization);
1498
1499 // total size of all maps
1500 double mb_size_total = 0;
1501
1502 // make a rough estimate of memory usage for obs map buffer
1503 double omb_size = 8*omb.n_rows*omb.n_cols*(omb.signal.size() + omb.weight.size() +
1504 omb.kernel.size() + omb.coverage.size())/1e9;
1505
1506 logger->info("estimated size of map buffer {} GB", omb_size);
1507
1508 mb_size_total = mb_size_total + omb_size;
1509
1510 // print info if coadd is requested
1511 if (run_coadd) {
1512 logger->info("coadd map buffer rows: {}", cmb.n_rows);
1513 logger->info("coadd map buffer cols: {}", cmb.n_cols);
1514
1515 // make a rough estimate of memory usage for coadd map buffer
1516 double cmb_size = 8*cmb.n_rows*cmb.n_cols*(cmb.signal.size() + cmb.weight.size() +
1517 cmb.kernel.size() + cmb.coverage.size())/1e9;
1518
1519 logger->info("estimated size of coadd buffer {} GB", cmb_size);
1520
1521 mb_size_total = mb_size_total + cmb_size;
1522
1523 // output info if coadd noise maps are requested
1524 if (run_noise) {
1525 logger->info("coadd map buffer noise maps: {}", cmb.n_noise);
1526 // make a rough estimate of memory usage for coadd noise maps
1527 double nmb_size = 8*cmb.n_rows*cmb.n_cols*cmb.noise.size()*cmb.n_noise/1e9;
1528 logger->info("estimated size of noise buffer {} GB", nmb_size);
1529 mb_size_total = mb_size_total + nmb_size;
1530 }
1531 }
1532 else {
1533 // output info if obs noise maps are requested
1534 if (run_noise) {
1535 logger->info("observation map buffer noise maps: {}", omb.n_noise);
1536 // make a rough estimate of memory usage for obs noise maps
1537 double nmb_size = 8*omb.n_rows*omb.n_cols*omb.noise.size()*omb.n_noise/1e9;
1538 logger->info("estimated size of noise buffer {} GB", nmb_size);
1539 mb_size_total = mb_size_total + nmb_size;
1540 }
1541 }
1542
1543 logger->info("estimated size of all maps {} GB", mb_size_total);
1544 logger->info("number of scans: {}",telescope.scan_indices.cols());
1545
1546 // test getting memory usage for fun
1547 /*struct sysinfo memInfo;
1548 long long totalPhysMem = memInfo.totalram;
1549 totalPhysMem *= memInfo.mem_unit;
1550
1551 logger->info("total physical memory available {} GB", (totalPhysMem/1024)/1e7);*/
1552 logger->info("physical memory used {} GB", engine_utils::get_phys_memory()/1e7);
1553}
1554
1555template <TCDataKind tc_t>
1557
1558 logger->debug("writing summary files for chunk {}",in.index.data);
1559
1560 std::string filename = "chunk_summary_" + std::to_string(in.index.data);
1561
1562 // write summary log file
1563 std::ofstream f;
1564 f.open (obsnum_dir_name+"/logs/" + filename + ".log");
1565
1566 f << "Summary file for scan " << in.index.data << "\n";
1567 f << "-Citlali version: " << CITLALI_GIT_VERSION << "\n";
1568 f << "-Kidscpp version: " << KIDSCPP_GIT_VERSION << "\n";
1569 f << "-Time of time chunk creation: " + in.creation_time + "\n";
1570 f << "-Time of file writing: " << engine_utils::current_date_time() << "\n";
1571
1572 f << "-Reduction type: " << redu_type << "\n";
1573 f << "-TOD type: " << tod_type << "\n";
1574 f << "-TOD unit: " << omb.sig_unit << "\n";
1575 f << "-TOD chunk type: " << in.name << "\n";
1576
1577 f << "-Calibrated: " << in.status.calibrated << "\n";
1578 f << "-Extinction Corrected: " << in.status.extinction_corrected << "\n";
1579 f << "-Demodulated: " << in.status.demodulated << "\n";
1580 f << "-Kernel Generated: " << in.status.kernel_generated << "\n";
1581 f << "-Despiked: " << in.status.despiked << "\n";
1582 f << "-TOD filtered: " << in.status.tod_filtered << "\n";
1583 f << "-Downsampled: " << in.status.downsampled << "\n";
1584 f << "-Cleaned: " << in.status.cleaned << "\n";
1585
1586 f << "-Scan length: " << in.scans.data.rows() << "\n";
1587
1588 f << "-Number of detectors: " << in.scans.data.cols() << "\n";
1589 f << "-Number of detectors flagged in APT table: " << (calib.apt["flag"].array()!=0).count() << "\n";
1590 f << "-Number of detectors flagged below weight limit: " << in.n_dets_low <<"\n";
1591 f << "-Number of detectors flagged above weight limit: " << in.n_dets_high << "\n";
1592 Eigen::Index n_flagged = in.n_dets_low + in.n_dets_high + (calib.apt["flag"].array()!=0).count();
1593 f << "-Number of detectors flagged: " << n_flagged << " (" << 100*float(n_flagged)/float(in.scans.data.cols()) << "%)\n";
1594
1595 f << "-NaNs found: " << in.scans.data.array().isNaN().count() << "\n";
1596 f << "-Infs found: " << in.scans.data.array().isInf().count() << "\n";
1597 f << "-Data min: " << in.scans.data.minCoeff() << " " << omb.sig_unit << "\n";
1598 f << "-Data max: " << in.scans.data.maxCoeff() << " " << omb.sig_unit << "\n";
1599 f << "-Data mean: " << in.scans.data.mean() << " " << omb.sig_unit << "\n";
1600 f << "-Data median: " << tula::alg::median(in.scans.data) << " " << omb.sig_unit << "\n";
1601 f << "-Data stddev: " << engine_utils::calc_std_dev(in.scans.data) << " " << omb.sig_unit << "\n";
1602
1603 if (in.status.kernel_generated) {
1604 f << "-Kernel max: " << in.kernel.data.maxCoeff() << " " << omb.sig_unit << "\n";
1605 }
1606
1607 f.close();
1608}
1609
1610template <typename map_buffer_t>
1611void Engine::write_map_summary(map_buffer_t &mb) {
1612
1613 logger->debug("writing map summary files");
1614
1615 std::string filename = "map_summary";
1616 std::ofstream f;
1617 f.open (obsnum_dir_name+"/logs/" + filename + ".log");
1618
1619 f << "Summary file for maps\n";
1620 f << "-Citlali version: " << CITLALI_GIT_VERSION << "\n";
1621 f << "-Kidscpp version: " << KIDSCPP_GIT_VERSION << "\n";
1622 f << "-Time of file writing: " << engine_utils::current_date_time() << "\n";
1623
1624 f << "-Reduction type: " << redu_type << "\n";
1625 f << "-Map type: " << tod_type << "\n";
1626 f << "-Map grouping: " << map_grouping << "\n";
1627 f << "-Rows: " << mb.n_rows << "\n";
1628 f << "-Cols: " << mb.n_cols << "\n";
1629 f << "-Number of maps: " << n_maps << "\n";
1630 f << "-Signal map unit: " << mb.sig_unit << "\n";
1631 f << "-Weight map unit: " << "1/(" + mb.sig_unit + ")^2" << "\n";
1632 f << "-Kernel maps generated: " << !mb.kernel.empty() << "\n";
1633 f << "-Coverage maps generated: " << !mb.coverage.empty() << "\n";
1634 f << "-Noise maps generated: " << !mb.noise.empty() << "\n";
1635 f << "-Number of noise maps: " << mb.noise.size() << "\n";
1636
1637 // map to count nans for all maps
1638 std::map<std::string,int> n_nans;
1639 n_nans["signal"] = 0;
1640 n_nans["weight"] = 0;
1641 n_nans["kernel"] = 0;
1642 n_nans["coverage"] = 0;
1643 n_nans["noise"] = 0;
1644
1645 // maps to hold infs for all maps
1646 std::map<std::string,int> n_infs;
1647 n_infs["signal"] = 0;
1648 n_infs["weight"] = 0;
1649 n_nans["kernel"] = 0;
1650 n_infs["coverage"] = 0;
1651 n_infs["noise"] = 0;
1652
1653 // loop through maps and count up nans and infs
1654 for (Eigen::Index i=0; i<mb.signal.size(); ++i) {
1655 n_nans["signal"] = n_nans["signal"] + mb.signal[i].array().isNaN().count();
1656 n_nans["weight"] = n_nans["weight"] + mb.weight[i].array().isNaN().count();
1657
1658 // check kernel for nans if requested
1659 if (!mb.kernel.empty()) {
1660 n_nans["kernel"] = n_nans["kernel"] + mb.kernel[i].array().isNaN().count();
1661 }
1662 // check coverage map for nans if available
1663 if (!mb.coverage.empty()) {
1664 n_nans["coverage"] = n_nans["coverage"] + mb.coverage[i].array().isNaN().count();
1665 }
1666
1667 n_infs["signal"] = n_infs["signal"] + mb.signal[i].array().isInf().count();
1668 n_infs["weight"] = n_infs["weight"] + mb.weight[i].array().isInf().count();
1669
1670 // check kernel for infs if requested
1671 if (!mb.kernel.empty()) {
1672 n_infs["kernel"] = n_infs["kernel"] + mb.kernel[i].array().isInf().count();
1673 }
1674 // check coverage map for infs if available
1675 if (!mb.coverage.empty()) {
1676 n_infs["coverage"] = n_infs["coverage"] + mb.coverage[i].array().isInf().count();
1677 }
1678
1679 // loop through noise maps and check for nans and infs
1680 if (!mb.noise.empty()) {
1681 for (Eigen::Index j=0; j<mb.noise.size(); ++j) {
1682 Eigen::Map<Eigen::Matrix<double, Eigen::Dynamic, Eigen::Dynamic>> noise_matrix(mb.noise[i].data() + j * mb.n_rows * mb.n_cols,
1683 mb.n_rows, mb.n_cols);
1684
1685 n_nans["noise"] = n_nans["noise"] + noise_matrix.array().isNaN().count();
1686 n_infs["noise"] = n_infs["noise"] + noise_matrix.array().isInf().count();
1687 }
1688 }
1689 }
1690
1691 for (auto const& [key, val] : n_nans) {
1692 f << "-Number of "+ key + " NaNs: " << val << "\n";
1693 }
1694
1695 for (auto const& [key, val] : n_infs) {
1696 f << "-Number of "+ key + " Infs: " << val << "\n";
1697 }
1698}
1699
1700template <mapmaking::MapType map_t, engine_utils::toltecIO::DataType data_t, engine_utils::toltecIO::ProdType prod_t>
1701auto Engine::setup_filenames(std::string dir_name) {
1702
1703 std::string filename;
1704
1705 // raw obs maps
1706 if constexpr (map_t == mapmaking::RawObs) {
1707 filename = toltec_io.create_filename<data_t, prod_t, engine_utils::toltecIO::raw>
1708 (dir_name, redu_type, "", obsnum, telescope.sim_obs);
1709 }
1710 // filtered obs maps
1711 else if constexpr (map_t == mapmaking::FilteredObs) {
1713 (dir_name, redu_type, "", obsnum, telescope.sim_obs);
1714 }
1715 // raw coadded maps
1716 else if constexpr (map_t == mapmaking::RawCoadd) {
1717 filename = toltec_io.create_filename<data_t, prod_t, engine_utils::toltecIO::raw>
1718 (dir_name, "", "", "", telescope.sim_obs);
1719 }
1720 // filtered coadded maps
1721 else if constexpr (map_t == mapmaking::FilteredCoadd) {
1723 (dir_name, "", "", "", telescope.sim_obs);
1724 }
1725
1726 return filename;
1727}
1728
1730 // get name for extension layer
1731 std::string map_name = "";
1732
1733 // only update name if we're not in array mode
1734 if (map_grouping!="array") {
1735 // if in nw mode
1736 if (map_grouping=="nw") {
1737 map_name = map_name + "nw_" + std::to_string(calib.nws(i)) + "_";
1738 }
1739 else if (map_grouping=="fg") {
1740 // find all detectors belonging to each fg
1741 Eigen::VectorXI array_indices(calib.fg.size()*calib.n_arrays*rtcproc.polarization.stokes_params.size());
1742 Eigen::Index k = 0;
1743 for (Eigen::Index j=0; j<calib.n_arrays; ++j) {
1744 for (Eigen::Index l=0; l<rtcproc.polarization.stokes_params.size(); ++l) {
1745 for (Eigen::Index m=0; m<calib.fg.size(); ++m) {
1746 array_indices(k) = calib.fg(m);
1747 k++;
1748 }
1749 }
1750 }
1751 // if in fg mode
1752 map_name = map_name + "fg_" + std::to_string(array_indices(i)) + "_";
1753 }
1754 // if in detector mode
1755 else if (map_grouping=="detector") {
1756 map_name = map_name + "det_" + std::to_string(i) + "_";
1757 }
1758 }
1759
1760 return map_name;
1761}
1762
1763template <typename fits_io_type, class map_buffer_t>
1764void Engine::add_phdu(fits_io_type &fits_io, map_buffer_t &mb, Eigen::Index i) {
1765 // array name
1766 std::string name = toltec_io.array_name_map[calib.arrays(i)];
1767
1768 logger->debug("adding unit conversions");
1769
1770 // conversion to uK
1771 auto fwhm = (std::get<0>(calib.array_fwhms[calib.arrays(i)]) + std::get<1>(calib.array_fwhms[calib.arrays(i)]))/2;
1773
1774 // beam area in steradians
1775 auto beam_area_rad = 2.*pi*pow(fwhm*FWHM_TO_STD*ASEC_TO_RAD,2);
1776 // get Jy/pixel
1777 auto mJy_beam_to_Jy_px = 1e-3/beam_area_rad*pow(mb->pixel_size_rad,2);
1778
1779 // add unit conversions
1780 if (rtcproc.run_calibrate) {
1781 if (mb->sig_unit == "mJy/beam") {
1782 // conversion to mJy/beam
1783 fits_io->at(i).pfits->pHDU().addKey("to_mJy/beam", 1, "Conversion to mJy/beam");
1784 // conversion to MJy/sr
1785 fits_io->at(i).pfits->pHDU().addKey("to_MJy/sr", 1/(calib.array_beam_areas[calib.arrays(i)]*MJY_SR_TO_mJY_ASEC),
1786 "Conversion to MJy/sr");
1787 // conversion to uK
1788 fits_io->at(i).pfits->pHDU().addKey("to_uK", mJy_beam_to_uK, "Conversion to uK");
1789 // conversion to Jy/pixel
1790 fits_io->at(i).pfits->pHDU().addKey("to_Jy/pixel", mJy_beam_to_Jy_px, "Conversion to Jy/pixel");
1791 }
1792 else if (mb->sig_unit == "MJy/sr") {
1793 // conversion to mJy/beam
1794 fits_io->at(i).pfits->pHDU().addKey("to_mJy/beam", calib.array_beam_areas[calib.arrays(i)]*MJY_SR_TO_mJY_ASEC,
1795 "Conversion to mJy/beam");
1796 // conversion to MJy/Sr
1797 fits_io->at(i).pfits->pHDU().addKey("to_MJy/sr", 1, "Conversion to MJy/sr");
1798 // conversion to uK
1799 fits_io->at(i).pfits->pHDU().addKey("to_uK", calib.array_beam_areas[calib.arrays(i)]*MJY_SR_TO_mJY_ASEC*mJy_beam_to_uK,
1800 "Conversion to uK");
1801 // conversion to Jy/pixel
1802 fits_io->at(i).pfits->pHDU().addKey("to_Jy/pixel", calib.array_beam_areas[calib.arrays(i)]*MJY_SR_TO_mJY_ASEC*mJy_beam_to_Jy_px,
1803 "Conversion to Jy/pixel");
1804 }
1805 else if (mb->sig_unit == "uK") {
1806 // conversion to mJy/beam
1807 fits_io->at(i).pfits->pHDU().addKey("to_mJy/beam", 1/mJy_beam_to_uK, "Conversion to mJy/beam");
1808 // conversion to MJy/sr
1809 fits_io->at(i).pfits->pHDU().addKey("to_MJy/sr", 1/mJy_beam_to_uK/(calib.array_beam_areas[calib.arrays(i)]*MJY_SR_TO_mJY_ASEC),
1810 "Conversion to MJy/sr");
1811 // conversion to uK
1812 fits_io->at(i).pfits->pHDU().addKey("to_uK", 1, "Conversion to uK");
1813 // conversion to Jy/pixel
1814 fits_io->at(i).pfits->pHDU().addKey("to_Jy/pixel", (1/mJy_beam_to_uK)*mJy_beam_to_Jy_px, "Conversion to Jy/pixel");
1815 }
1816 else if (mb->sig_unit == "Jy/pixel") {
1817 // conversion to mJy/beam
1818 fits_io->at(i).pfits->pHDU().addKey("to_mJy/beam", 1/mJy_beam_to_Jy_px, "Conversion to mJy/beam");
1819 // conversion to MJy/sr
1820 fits_io->at(i).pfits->pHDU().addKey("to_MJy/sr", (1/mJy_beam_to_Jy_px)/(calib.array_beam_areas[calib.arrays(i)]*MJY_SR_TO_mJY_ASEC),
1821 "Conversion to MJy/sr");
1822 // conversion to uK
1823 fits_io->at(i).pfits->pHDU().addKey("to_uK", mJy_beam_to_uK/mJy_beam_to_Jy_px, "Conversion to uK");
1824 // conversion to Jy/pixel
1825 fits_io->at(i).pfits->pHDU().addKey("to_Jy/pixel", 1, "Conversion to Jy/pixel");
1826 }
1827 }
1828 // if flux calibration is disabled
1829 else {
1830 fits_io->at(i).pfits->pHDU().addKey("to_mJy/beam", "N/A", "Conversion to mJy/beam");
1831 fits_io->at(i).pfits->pHDU().addKey("to_MJy/sr", "N/A", "Conversion to MJy/sr");
1832 fits_io->at(i).pfits->pHDU().addKey("to_uK", "N/A", "Conversion to uK");
1833 fits_io->at(i).pfits->pHDU().addKey("to_Jy/pixel", "N/A", "Conversion to Jy/pixel");
1834 }
1835
1836 // add source flux for beammaps
1837 if (redu_type == "beammap") {
1838 fits_io->at(i).pfits->pHDU().addKey("HEADER.SOURCE.FLUX_MJYPERBEAM", beammap_fluxes_mJy_beam[name], "Source flux (mJy/beam)");
1839 fits_io->at(i).pfits->pHDU().addKey("HEADER.SOURCE.FLUX_MJYPERSR", beammap_fluxes_MJy_Sr[name], "Source flux (MJy/sr)");
1840
1841 fits_io->at(i).pfits->pHDU().addKey("BEAMMAP.ITER_TOLERANCE", beammap_iter_tolerance, "Beammap iteration tolerance");
1842 fits_io->at(i).pfits->pHDU().addKey("BEAMMAP.ITER_MAX", beammap_iter_max, "Beammap max iterations");
1843 fits_io->at(i).pfits->pHDU().addKey("BEAMMAP.IS_DEROTATED", beammap_derotate, "Beammap derotated");
1844 // add reference detector information
1846 fits_io->at(i).pfits->pHDU().addKey("BEAMMAP.REF_DET_INDEX", beammap_reference_det, "Beammap Reference det (rotation center)");
1847 fits_io->at(i).pfits->pHDU().addKey("BEAMMAP.REF_X_T", calib.apt["x_t"](beammap_reference_det), "Az rotation center (arcsec)");
1848 fits_io->at(i).pfits->pHDU().addKey("BEAMMAP.REF_Y_T", calib.apt["y_t"](beammap_reference_det), "Alt rotation center (arcsec)");
1849 }
1850 else {
1851 fits_io->at(i).pfits->pHDU().addKey("BEAMMAP.REF_DET_INDEX", -99, "Beammap Reference det (rotation center)");
1852 fits_io->at(i).pfits->pHDU().addKey("BEAMMAP.REF_X_T", "N/A", "Az rotation center (arcsec)");
1853 fits_io->at(i).pfits->pHDU().addKey("BEAMMAP.REF_Y_T", "N/A", "Alt rotation center (arcsec)");
1854 }
1855 }
1856
1857 logger->debug("adding obsnums");
1858
1859 // add obsnums
1860 for (Eigen::Index j=0; j<mb->obsnums.size(); ++j) {
1861 fits_io->at(i).pfits->pHDU().addKey("OBSNUM"+std::to_string(j), mb->obsnums.at(j), "Observation Number " + std::to_string(j));
1862 }
1863
1864 // add date and time of obs
1865 if (mb->obsnums.size()==1) {
1866 fits_io->at(i).pfits->pHDU().addKey("DATEOBS0", date_obs.back(), "Date and time of observation 0");
1867 }
1868 else {
1869 for (Eigen::Index j=0; j<mb->obsnums.size(); ++j) {
1870 fits_io->at(i).pfits->pHDU().addKey("DATEOBS"+std::to_string(j), date_obs[j], "Date and time of observation "+std::to_string(j));
1871 }
1872 }
1873
1874 logger->debug("adding obs info");
1875
1876 // add source
1877 fits_io->at(i).pfits->pHDU().addKey("SOURCE", telescope.source_name, "Source name");
1878 // add instrument
1879 fits_io->at(i).pfits->pHDU().addKey("INSTRUME", "TolTEC", "Instrument");
1880 // add hwpr
1881 fits_io->at(i).pfits->pHDU().addKey("HWPR", calib.run_hwpr, "HWPR installed");
1882 // add telescope
1883 fits_io->at(i).pfits->pHDU().addKey("TELESCOP", "LMT", "Telescope");
1884 // add wavelength
1885 fits_io->at(i).pfits->pHDU().addKey("WAV", name, "Wavelength");
1886 // add pipeline
1887 fits_io->at(i).pfits->pHDU().addKey("PIPELINE", "CITLALI", "Redu pipeline");
1888 // add citlali version
1889 fits_io->at(i).pfits->pHDU().addKey("VERSION", CITLALI_GIT_VERSION, "CITLALI_GIT_VERSION");
1890 // add kids version
1891 fits_io->at(i).pfits->pHDU().addKey("KIDS", KIDSCPP_GIT_VERSION, "KIDSCPP_GIT_VERSION");
1892 // add kids version
1893 fits_io->at(i).pfits->pHDU().addKey("TULA", TULA_GIT_VERSION, "TULA_GIT_VERSION");
1894 // project id
1895 fits_io->at(i).pfits->pHDU().addKey("PROJID", telescope.project_id, "Project ID");
1896 // add redu type
1897 fits_io->at(i).pfits->pHDU().addKey("GOAL", redu_type, "Reduction type");
1898 // add obs goal
1899 fits_io->at(i).pfits->pHDU().addKey("OBSGOAL", telescope.obs_goal, "Obs goal");
1900 // add tod type
1901 fits_io->at(i).pfits->pHDU().addKey("TYPE", tod_type, "TOD Type");
1902 // add map grouping
1903 fits_io->at(i).pfits->pHDU().addKey("GROUPING", map_grouping, "Map grouping");
1904 // add map grouping
1905 fits_io->at(i).pfits->pHDU().addKey("METHOD", map_method, "Map method");
1906 // add exposure time
1907 fits_io->at(i).pfits->pHDU().addKey("EXPTIME", mb->exposure_time, "Exposure time (sec)");
1908 // add pixel axes
1909 fits_io->at(i).pfits->pHDU().addKey("RADESYS", telescope.pixel_axes, "Coord Reference Frame");
1910 // add source ra
1911 fits_io->at(i).pfits->pHDU().addKey("SRC_RA", telescope.tel_header["Header.Source.Ra"][0], "Source RA (radians)");
1912 // add source dec
1913 fits_io->at(i).pfits->pHDU().addKey("SRC_DEC", telescope.tel_header["Header.Source.Dec"][0], "Source Dec (radians)");
1914 // add map tangent point ra
1915 fits_io->at(i).pfits->pHDU().addKey("TAN_RA", telescope.tel_header["Header.Source.Ra"][0], "Map Tangent Point RA (radians)");
1916 //add map tangent point dec
1917 fits_io->at(i).pfits->pHDU().addKey("TAN_DEC", telescope.tel_header["Header.Source.Dec"][0], "Map Tangent Point Dec (radians)");
1918 // add mean alt
1919 fits_io->at(i).pfits->pHDU().addKey("MEAN_EL", RAD_TO_DEG*telescope.tel_data["TelElAct"].mean(), "Mean Elevation (deg)");
1920 // add mean az
1921 fits_io->at(i).pfits->pHDU().addKey("MEAN_AZ", RAD_TO_DEG*telescope.tel_data["TelAzAct"].mean(), "Mean Azimuth (deg)");
1922 // add mean parallactic angle
1923 fits_io->at(i).pfits->pHDU().addKey("MEAN_PA", RAD_TO_DEG*telescope.tel_data["ActParAng"].mean(), "Mean Parallactic angle (deg)");
1924
1925 logger->debug("adding beamsizes");
1926
1927 // add beamsizes
1928 if (std::get<0>(calib.array_fwhms[calib.arrays(i)]) >= std::get<1>(calib.array_fwhms[calib.arrays(i)])) {
1929 fits_io->at(i).pfits->pHDU().addKey("BMAJ", std::get<0>(calib.array_fwhms[calib.arrays(i)]), "beammaj (arcsec)");
1930 fits_io->at(i).pfits->pHDU().addKey("BMIN", std::get<1>(calib.array_fwhms[calib.arrays(i)]), "beammin (arcsec)");
1931 fits_io->at(i).pfits->pHDU().addKey("BPA", calib.array_pas[calib.arrays(i)]*RAD_TO_DEG, "beampa (deg)");
1932 }
1933 else {
1934 fits_io->at(i).pfits->pHDU().addKey("BMAJ", std::get<1>(calib.array_fwhms[calib.arrays(i)]), "beammaj (arcsec)");
1935 fits_io->at(i).pfits->pHDU().addKey("BMIN", std::get<0>(calib.array_fwhms[calib.arrays(i)]), "beammin (arcsec)");
1936 fits_io->at(i).pfits->pHDU().addKey("BPA", (calib.array_pas[calib.arrays(i)] + pi/2)*RAD_TO_DEG, "beampa (deg)");
1937 }
1938
1939 fits_io->at(i).pfits->pHDU().addKey("BUNIT", mb->sig_unit, "bunit");
1940
1941 // add jinc shape params
1942 if (map_method=="jinc") {
1943 logger->debug("adding jinc params");
1944
1945 fits_io->at(i).pfits->pHDU().addKey("JINC_R", jinc_mm.r_max, "Jinc filter R_max");
1946 fits_io->at(i).pfits->pHDU().addKey("JINC_A", jinc_mm.shape_params[calib.arrays(i)][0], "Jinc filter param a");
1947 fits_io->at(i).pfits->pHDU().addKey("JINC_B", jinc_mm.shape_params[calib.arrays(i)][1], "Jinc filter param b");
1948 fits_io->at(i).pfits->pHDU().addKey("JINC_C", jinc_mm.shape_params[calib.arrays(i)][2], "Jinc filter param c");
1949 }
1950
1951 // add mean tau
1952 logger->debug("adding extinction");
1953 if (rtcproc.run_extinction) {
1954 Eigen::VectorXd tau_el(1);
1955 tau_el << telescope.tel_data["TelElAct"].mean();
1956 auto tau_freq = rtcproc.calibration.calc_tau(tau_el, telescope.tau_225_GHz);
1957
1958 fits_io->at(i).pfits->pHDU().addKey("MEAN_TAU", tau_freq[i](0), "mean tau (" + name + ")");
1959 }
1960 else {
1961 fits_io->at(i).pfits->pHDU().addKey("MEAN_TAU", 0., "mean tau (" + name + ")");
1962 }
1963
1964 // add sample rate
1965 fits_io->at(i).pfits->pHDU().addKey("SAMPRATE", telescope.fsmp, "sample rate (Hz)");
1966
1967 // add apt table to header
1968 if (mb->obsnums.size()==1) {
1969 std::vector<string> apt_filename;
1970 std::stringstream ss(calib.apt_filepath);
1971 std::string item;
1972 char delim = '/';
1973
1974 while (getline (ss, item, delim)) {
1975 apt_filename.push_back(item);
1976 }
1977 fits_io->at(i).pfits->pHDU().addKey("APT", apt_filename.back(), "APT table used");
1978 }
1979
1980 double rms;
1981
1982 if (redu_type != "beammap") {
1983 // estimate rms from weight maps
1984 rms = pow(mb->median_err(i),0.5);
1985 }
1986 else {
1987 rms = 0.0;
1988 }
1989
1990 // out-of-focus holography parameters
1991 if (! telescope.sim_obs) {
1992 logger->debug("adding oof params");
1993 fits_io->at(i).pfits->pHDU().addKey("OOF_RMS", rms, "rms of map background (" + mb->sig_unit +")");
1994 fits_io->at(i).pfits->pHDU().addKey("OOF_W", toltec_io.array_wavelength_map[calib.arrays(i)]/1000., "wavelength (m)");
1995 fits_io->at(i).pfits->pHDU().addKey("OOF_ID", static_cast<int>(toltec_io.array_wavelength_map[calib.arrays(i)]*1000), "instrument id");
1996 fits_io->at(i).pfits->pHDU().addKey("OOF_T", 3.0, "taper (dB)");
1997 fits_io->at(i).pfits->pHDU().addKey("OOF_M2X", telescope.tel_header["Header.M2.XReq"](0)/1000.*1e6, "oof m2x (microns)");
1998 fits_io->at(i).pfits->pHDU().addKey("OOF_M2Y", telescope.tel_header["Header.M2.YReq"](0)/1000.*1e6, "oof m2y (microns)");
1999 fits_io->at(i).pfits->pHDU().addKey("OOF_M2Z", telescope.tel_header["Header.M2.ZReq"](0)/1000.*1e6, "oof m2z (microns)");
2000
2001 fits_io->at(i).pfits->pHDU().addKey("OOF_RO", 25., "outer diameter of the antenna (m)");
2002 fits_io->at(i).pfits->pHDU().addKey("OOF_RI", 1.65, "inner diameter of the antenna (m)");
2003 }
2004
2005 fits_io->at(i).pfits->pHDU().addKey("FRUITLOOPS_ITER", fruit_iter, "Current fruit loops iteration");
2006
2007 // add control/runtime parameters
2008 logger->debug("adding config params");
2009 fits_io->at(i).pfits->pHDU().addKey("CONFIG.VERBOSE", verbose_mode, "Reduced in verbose mode");
2010 fits_io->at(i).pfits->pHDU().addKey("CONFIG.POLARIZED", rtcproc.run_polarization, "Polarized Obs");
2011 fits_io->at(i).pfits->pHDU().addKey("CONFIG.DESPIKED", rtcproc.run_despike, "Despiked");
2012 fits_io->at(i).pfits->pHDU().addKey("CONFIG.TODFILTERED", rtcproc.run_tod_filter, "TOD Filtered");
2013 fits_io->at(i).pfits->pHDU().addKey("CONFIG.DOWNSAMPLED", rtcproc.run_downsample, "Downsampled");
2014 fits_io->at(i).pfits->pHDU().addKey("CONFIG.CALIBRATED", rtcproc.run_calibrate, "Calibrated");
2015 fits_io->at(i).pfits->pHDU().addKey("CONFIG.EXTINCTION", rtcproc.run_extinction, "Extinction corrected");
2016 fits_io->at(i).pfits->pHDU().addKey("CONFIG.EXTINCTION.EXTMODEL", rtcproc.calibration.extinction_model, "Extinction model");
2017 fits_io->at(i).pfits->pHDU().addKey("CONFIG.WEIGHT.TYPE", ptcproc.weighting_type, "Weighting scheme");
2018 fits_io->at(i).pfits->pHDU().addKey("CONFIG.INV_VAR.RTC.WTLOW", rtcproc.lower_inv_var_factor, "RTC lower inv var cutoff");
2019 fits_io->at(i).pfits->pHDU().addKey("CONFIG.INV_VAR.RTC.WTHIGH", rtcproc.upper_inv_var_factor, "RTC upper inv var cutoff");
2020 fits_io->at(i).pfits->pHDU().addKey("CONFIG.INV_VAR.PTC.WTLOW", ptcproc.lower_inv_var_factor, "PTC lower inv var cutoff");
2021 fits_io->at(i).pfits->pHDU().addKey("CONFIG.INV_VAR.PTC.WTHIGH", ptcproc.upper_inv_var_factor, "PTC upper inv var cutoff");
2022 fits_io->at(i).pfits->pHDU().addKey("CONFIG.WEIGHT.PTC.WTLOW", ptcproc.lower_weight_factor, "PTC lower weight cutoff");
2023 fits_io->at(i).pfits->pHDU().addKey("CONFIG.WEIGHT.PTC.WTHIGH", ptcproc.upper_weight_factor, "PTC upper weight cutoff");
2024 fits_io->at(i).pfits->pHDU().addKey("CONFIG.WEIGHT.MEDWTFACTOR", ptcproc.med_weight_factor, "Median weight factor");
2025 fits_io->at(i).pfits->pHDU().addKey("CONFIG.CLEANED", ptcproc.run_clean, "Cleaned");
2026 if (ptcproc.run_clean) {
2027 fits_io->at(i).pfits->pHDU().addKey("CONFIG.CLEANED.NEIG", ptcproc.cleaner.n_eig_to_cut[calib.arrays(i)].sum(),
2028 "Number of eigenvalues removed");
2029 }
2030 else {
2031 fits_io->at(i).pfits->pHDU().addKey("CONFIG.CLEANED.NEIG", 0, "Number of eigenvalues removed");
2032 }
2033
2034 fits_io->at(i).pfits->pHDU().addKey("CONFIG.FRUITLOOPS", ptcproc.run_fruit_loops, "Fruit loops");
2035 fits_io->at(i).pfits->pHDU().addKey("CONFIG.FRUITLOOPS.PATH", ptcproc.fruit_loops_path, "Fruit loops path");
2036 fits_io->at(i).pfits->pHDU().addKey("CONFIG.FRUITLOOPS.TYPE", ptcproc.fruit_loops_type, "Fruit loops type");
2037 fits_io->at(i).pfits->pHDU().addKey("CONFIG.FRUITLOOPS.S2N", ptcproc.fruit_loops_sig2noise, "Fruit loops S/N");
2039 fits_io->at(i).pfits->pHDU().addKey("CONFIG.FRUITLOOPS.FLUX", ptcproc.fruit_loops_flux(calib.arrays(i)), "Fruit loops flux (" + mb->sig_unit + ")");
2040 }
2041 else {
2042 fits_io->at(i).pfits->pHDU().addKey("CONFIG.FRUITLOOPS.FLUX", 0, "Fruit loops flux (" + mb->sig_unit + ")");
2043 }
2044 fits_io->at(i).pfits->pHDU().addKey("CONFIG.FRUITLOOPS.MAXITER", ptcproc.fruit_loops_iters, "Fruit loops iterations");
2045
2046 // add telescope file header information
2047 if (mb->obsnums.size()==1) {
2048 logger->debug("adding tel params");
2049 for (auto const& [key, val] : telescope.tel_header) {
2050 logger->debug("adding {}: {}", key, val);
2051 fits_io->at(i).pfits->pHDU().addKey(key, val(0), key);
2052 }
2053 }
2054}
2055
2056template <typename fits_io_type, class map_buffer_t>
2057void Engine::write_maps(fits_io_type &fits_io, fits_io_type &noise_fits_io, map_buffer_t &mb, Eigen::Index i) {
2058 // get name for extension layer
2059 std::string map_name = get_map_name(i);
2060
2061 // get the array for the given map
2062 Eigen::Index map_index = arrays_to_maps(i);
2063 // get the stokes parameter for the given map
2064 Eigen::Index stokes_index = maps_to_stokes(i);
2065
2066 // update wcs ctypes for frequency and stokes params
2067 mb->wcs.crval[2] = toltec_io.array_freq_map[calib.arrays[maps_to_arrays(i)]];
2068 mb->wcs.crval[3] = stokes_index;
2069
2070 // signal map
2071 fits_io->at(map_index).add_hdu("signal_" + map_name + rtcproc.polarization.stokes_params[stokes_index], mb->signal[i]);
2072 fits_io->at(map_index).add_wcs(fits_io->at(map_index).hdus.back(), mb->wcs, telescope.tel_header["Header.Source.Epoch"](0));
2073 fits_io->at(map_index).hdus.back()->addKey("UNIT", mb->sig_unit, "Unit of map");
2074
2075 // weight map
2076 fits_io->at(map_index).add_hdu("weight_" + map_name + rtcproc.polarization.stokes_params[stokes_index], mb->weight[i]);
2077 fits_io->at(map_index).add_wcs(fits_io->at(map_index).hdus.back(), mb->wcs, telescope.tel_header["Header.Source.Epoch"](0));
2078 fits_io->at(map_index).hdus.back()->addKey("UNIT", "1/("+mb->sig_unit+")^2", "Unit of map");
2079 if (redu_type != "beammap" && std::fabs(mb->median_err(i)) > std::numeric_limits<double>::epsilon()) {
2080 fits_io->at(map_index).hdus.back()->addKey("MEDERR", pow(mb->median_err(i),0.5), "Median Error ("+mb->sig_unit+")");
2081 }
2082 else {
2083 fits_io->at(map_index).hdus.back()->addKey("MEDERR", 0.0, "Median Error ("+mb->sig_unit+")");
2084 }
2085
2086 // kernel map
2087 if (rtcproc.run_kernel) {
2088 fits_io->at(map_index).add_hdu("kernel_" + map_name + rtcproc.polarization.stokes_params[stokes_index], mb->kernel[i]);
2089 fits_io->at(map_index).hdus.back()->addKey("TYPE",rtcproc.kernel.type, "Kernel type");
2090
2091 // add fwhm
2092 double fwhm = -99;
2093 if (rtcproc.kernel.type!="fits") {
2094 if (rtcproc.kernel.fwhm_rad<=0) {
2095 fwhm = (std::get<0>(calib.array_fwhms[calib.arrays(i)]) + std::get<1>(calib.array_fwhms[calib.arrays(i)]))/2;
2096 }
2097 else {
2099 }
2100 }
2101 fits_io->at(map_index).hdus.back()->addKey("FWHM",fwhm,"Kernel fwhm (arcsec)");
2102 fits_io->at(map_index).add_wcs(fits_io->at(map_index).hdus.back(), mb->wcs, telescope.tel_header["Header.Source.Epoch"](0));
2103 fits_io->at(map_index).hdus.back()->addKey("UNIT", mb->sig_unit, "Unit of map");
2104 }
2105
2106 // coverage map
2107 if (!mb->coverage.empty()) {
2108 fits_io->at(map_index).add_hdu("coverage_" + map_name + rtcproc.polarization.stokes_params[stokes_index], mb->coverage[i]);
2109 fits_io->at(map_index).add_wcs(fits_io->at(map_index).hdus.back(), mb->wcs, telescope.tel_header["Header.Source.Epoch"](0));
2110 fits_io->at(map_index).hdus.back()->addKey("UNIT", "sec", "Unit of map");
2111 }
2112
2113 /* coverage bool and signal-to-noise maps */
2114 if (!mb->coverage.empty()) {
2115 // need these to use eigen select
2116 Eigen::MatrixXd ones, zeros;
2117 ones.setOnes(mb->weight[i].rows(), mb->weight[i].cols());
2118 zeros.setZero(mb->weight[i].rows(), mb->weight[i].cols());
2119
2120 // get weight threshold for current map
2121 auto [weight_threshold, cov_ranges, cov_n_rows, cov_n_cols] = mb->calc_cov_region(i);
2122 // if weight is less than threshold, set to zero, otherwise set to one
2123 Eigen::MatrixXd coverage_bool = (mb->weight[i].array() < weight_threshold).select(zeros,ones);
2124
2125 // coverage bool map
2126 fits_io->at(map_index).add_hdu("coverage_bool_" + map_name + rtcproc.polarization.stokes_params[stokes_index], coverage_bool);
2127 fits_io->at(map_index).add_wcs(fits_io->at(map_index).hdus.back(), mb->wcs, telescope.tel_header["Header.Source.Epoch"](0));
2128 fits_io->at(map_index).hdus.back()->addKey("UNIT", "N/A", "Unit of map");
2129 fits_io->at(map_index).hdus.back()->addKey("WTTHRESH", weight_threshold, "Weight threshold");
2130
2131 // signal-to-noise map
2132 Eigen::MatrixXd sig2noise = mb->signal[i].array()*sqrt(mb->weight[i].array());
2133 fits_io->at(map_index).add_hdu("sig2noise_" + map_name + rtcproc.polarization.stokes_params[stokes_index], sig2noise);
2134 fits_io->at(map_index).add_wcs(fits_io->at(map_index).hdus.back(), mb->wcs, telescope.tel_header["Header.Source.Epoch"](0));
2135 fits_io->at(map_index).hdus.back()->addKey("UNIT", "N/A", "Unit of map");
2136 }
2137
2138 // write noise maps
2139 if (!mb->noise.empty()) {
2140 for (Eigen::Index n=0; n<mb->n_noise; ++n) {
2141 Eigen::Map<Eigen::Matrix<double, Eigen::Dynamic, Eigen::Dynamic>> noise_matrix(mb->noise[i].data() + n * mb->n_rows * mb->n_cols,
2142 mb->n_rows, mb->n_cols);
2143
2144 noise_fits_io->at(map_index).add_hdu("signal_" + map_name + std::to_string(n) + "_" + rtcproc.polarization.stokes_params[stokes_index],
2145 noise_matrix);
2146 noise_fits_io->at(map_index).add_wcs(noise_fits_io->at(map_index).hdus.back(), mb->wcs, telescope.tel_header["Header.Source.Epoch"](0));
2147 noise_fits_io->at(map_index).hdus.back()->addKey("UNIT", mb->sig_unit, "Unit of map");
2148 noise_fits_io->at(map_index).hdus.back()->addKey("MEDRMS", mb->median_rms[i], "Median RMS of noise maps");
2149 }
2150 }
2151}
2152
2153template <mapmaking::MapType map_t, class map_buffer_t>
2154void Engine::write_psd(map_buffer_t &mb, std::string dir_name) {
2155 // get filename
2156 std::string filename = setup_filenames<map_t,engine_utils::toltecIO::toltec,engine_utils::toltecIO::psd>(dir_name);
2157
2158 // create file
2159 netCDF::NcFile fo(filename + ".nc", netCDF::NcFile::replace);
2160
2161 // loop through psd vector
2162 for (Eigen::Index i=0; i<mb->psds.size(); ++i) {
2163 // get name for extension layer
2164 std::string map_name = get_map_name(i);
2165
2166 // get the array for the given map
2167 Eigen::Index map_index = arrays_to_maps(i);
2168 // get the stokes parameter for the given map
2169 Eigen::Index stokes_index = maps_to_stokes(i);
2170
2171 auto array = calib.arrays[map_index];
2172 std::string name = toltec_io.array_name_map[array] + "_" + map_name + rtcproc.polarization.stokes_params[stokes_index];
2173
2174 // add dimensions
2175 netCDF::NcDim psd_dim = fo.addDim(name + "_nfreq",mb->psds[i].size());
2176 netCDF::NcDim pds_2d_row_dim = fo.addDim(name + "_rows",mb->psd_2ds[i].rows());
2177 netCDF::NcDim pds_2d_col_dim = fo.addDim(name + "_cols",mb->psd_2ds[i].cols());
2178
2179 std::vector<netCDF::NcDim> dims;
2180 dims.push_back(pds_2d_row_dim);
2181 dims.push_back(pds_2d_col_dim);
2182
2183 // psd
2184 netCDF::NcVar psd_v = fo.addVar(name + "_psd",netCDF::ncDouble, psd_dim);
2185 psd_v.putVar(mb->psds[i].data());
2186
2187 // psd freq
2188 netCDF::NcVar psd_freq_v = fo.addVar(name + "_psd_freq",netCDF::ncDouble, psd_dim);
2189 psd_freq_v.putVar(mb->psd_freqs[i].data());
2190
2191 // transpose 2d psd and freq
2192 Eigen::MatrixXd psd_2d_transposed = mb->psd_2ds[i].transpose();
2193 Eigen::MatrixXd psd_2d_freq_transposed = mb->psd_2d_freqs[i].transpose();
2194
2195 // 2d psd
2196 netCDF::NcVar psd_2d_v = fo.addVar(name + "_psd_2d",netCDF::ncDouble, dims);
2197 psd_2d_v.putVar(psd_2d_transposed.data());
2198
2199 // 2d psd freq
2200 netCDF::NcVar psd_2d_freq_v = fo.addVar(name + "_psd_2d_freq",netCDF::ncDouble, dims);
2201 psd_2d_freq_v.putVar(psd_2d_freq_transposed.data());
2202
2203 if (!mb->noise.empty()) {
2204 // add dimensions
2205 netCDF::NcDim noise_psd_dim = fo.addDim(name + "_noise_nfreq",mb->noise_psds[i].size());
2206 netCDF::NcDim noise_pds_2d_row_dim = fo.addDim(name + "_noise_rows",mb->noise_psd_2ds[i].rows());
2207 netCDF::NcDim noise_pds_2d_col_dim = fo.addDim(name + "_noise_cols",mb->noise_psd_2ds[i].cols());
2208
2209 std::vector<netCDF::NcDim> noise_dims;
2210 noise_dims.push_back(noise_pds_2d_row_dim);
2211 noise_dims.push_back(noise_pds_2d_col_dim);
2212
2213 // noise psd
2214 netCDF::NcVar noise_psd_v = fo.addVar(name + "_noise_psd",netCDF::ncDouble, noise_psd_dim);
2215 noise_psd_v.putVar(mb->noise_psds[i].data());
2216
2217 // noise psd freq
2218 netCDF::NcVar noise_psd_freq_v = fo.addVar(name + "_noise_psd_freq",netCDF::ncDouble, noise_psd_dim);
2219 noise_psd_freq_v.putVar(mb->noise_psd_freqs[i].data());
2220
2221 // transpose 2d noise psd and freq
2222 Eigen::MatrixXd noise_psd_2d_transposed = mb->noise_psd_2ds[i].transpose();
2223 Eigen::MatrixXd noise_psd_2d_freq_transposed = mb->noise_psd_2d_freqs[i].transpose();
2224
2225 // 2d noise psd
2226 netCDF::NcVar noise_psd_2d_v = fo.addVar(name + "_noise_psd_2d",netCDF::ncDouble, noise_dims);
2227 noise_psd_2d_v.putVar(noise_psd_2d_transposed.data());
2228
2229 // 2d noise psd freq
2230 netCDF::NcVar noise_psd_2d_freq_v = fo.addVar(name + "_noise_psd_2d_freq",netCDF::ncDouble, noise_dims);
2231 noise_psd_2d_freq_v.putVar(noise_psd_2d_freq_transposed.data());
2232 }
2233 }
2234 // close file
2235 fo.close();
2236}
2237
2238template <mapmaking::MapType map_t, class map_buffer_t>
2239void Engine::write_hist(map_buffer_t &mb, std::string dir_name) {
2240 std::string filename = setup_filenames<map_t,engine_utils::toltecIO::toltec,engine_utils::toltecIO::hist>(dir_name);
2241
2242 netCDF::NcFile fo(filename + ".nc", netCDF::NcFile::replace);
2243 netCDF::NcDim hist_bins_dim = fo.addDim("n_bins", mb->hist_n_bins);
2244
2245 // loop through stored histograms
2246 for (Eigen::Index i=0; i<mb->hists.size(); ++i) {
2247 // string to hold name
2248 // get name for extension layer
2249 std::string map_name = get_map_name(i);
2250
2251 // get the array for the given map
2252 Eigen::Index map_index = arrays_to_maps(i);
2253 // get the stokes parameter for the given map
2254 Eigen::Index stokes_index = maps_to_stokes(i);
2255
2256 // array index
2257 auto array = calib.arrays[map_index];
2258 std::string name = toltec_io.array_name_map[array] + "_" + map_name + rtcproc.polarization.stokes_params[stokes_index];
2259
2260 // histogram bins
2261 netCDF::NcVar hist_bins_v = fo.addVar(name + "_bins",netCDF::ncDouble, hist_bins_dim);
2262 hist_bins_v.putVar(mb->hist_bins[i].data());
2263
2264 // histogram
2265 netCDF::NcVar hist_v = fo.addVar(name + "_hist",netCDF::ncDouble, hist_bins_dim);
2266 hist_v.putVar(mb->hists[i].data());
2267
2268 if (!mb->noise.empty()) {
2269 // average noise histogram
2270 netCDF::NcVar hist_v = fo.addVar(name + "_noise_hist",netCDF::ncDouble, hist_bins_dim);
2271 hist_v.putVar(mb->noise_hists[i].data());
2272 }
2273 }
2274 // close file
2275 fo.close();
2276}
2277
2279 std::string path = obsnum_dir_name + "raw/";
2280 // if using tod subdir, put stats file in it
2281 if (tod_output_subdir_name!="null") {
2282 if (!fs::exists(fs::status(path + tod_output_subdir_name))) {
2283 fs::create_directories(path + tod_output_subdir_name);
2284 path = path + tod_output_subdir_name + "/";
2285 }
2286 }
2287 // create stats filename
2290 (path, redu_type, "", obsnum, telescope.sim_obs);
2291
2292 // det stats header
2293 std::map<std::string, std::string> det_stats_header_units {
2294 {"rms", omb.sig_unit},
2295 {"stddev",omb.sig_unit},
2296 {"median",omb.sig_unit},
2297 {"flagged_frac","N/A"},
2298 {"weights","1/(" + omb.sig_unit + ")^2"},
2299 };
2300 // group stats header
2301 std::map<std::string, std::string> grp_stats_header_units {
2302 {"median_weights", "1/(" + omb.sig_unit + ")^2"},
2303 };
2304
2305 netCDF::NcFile fo(stats_filename + ".nc", netCDF::NcFile::replace);
2306
2307 // add obsnum
2308 netCDF::NcVar obsnum_v = fo.addVar("obsnum",netCDF::ncInt);
2309 obsnum_v.putAtt("units","N/A");
2310 int obsnum_int = std::stoi(obsnum);
2311 obsnum_v.putVar(&obsnum_int);
2312
2313 // add dimensions
2314 netCDF::NcDim n_dets_dim = fo.addDim("n_dets", calib.n_dets);
2315 netCDF::NcDim n_arrays_dim = fo.addDim("n_arrays", calib.n_arrays);
2316 netCDF::NcDim n_chunks_dim = fo.addDim("n_chunks", telescope.scan_indices.cols());
2317
2318 std::vector<netCDF::NcDim> dims = {n_chunks_dim, n_dets_dim};
2319 std::vector<netCDF::NcDim> grp_dims = {n_chunks_dim, n_arrays_dim};
2320
2321 // add det stats
2322 for (const auto &stat: diagnostics.det_stats_header) {
2323 netCDF::NcVar stat_v = fo.addVar(stat,netCDF::ncDouble, dims);
2324 stat_v.putVar(diagnostics.stats[stat].data());
2325 stat_v.putAtt("units",det_stats_header_units[stat]);
2326 }
2327 // add group stats
2328 for (const auto &stat: diagnostics.grp_stats_header) {
2329 netCDF::NcVar stat_v = fo.addVar(stat,netCDF::ncDouble, grp_dims);
2330 stat_v.putVar(diagnostics.stats[stat].data());
2331 stat_v.putAtt("units",grp_stats_header_units[stat]);
2332 }
2333
2334 // add apt table
2335 for (auto const& x: calib.apt) {
2336 netCDF::NcVar apt_v = fo.addVar("apt_" + x.first,netCDF::ncDouble, n_dets_dim);
2337 apt_v.putVar(x.second.data());
2338 apt_v.putAtt("units",calib.apt_header_units[x.first]);
2339 }
2340
2341 // add adc
2342 if (!diagnostics.adc_snap_data.empty()) {
2343 netCDF::NcDim adc_snap_dim = fo.addDim("adcSnapDim", diagnostics.adc_snap_data[0].cols());
2344 netCDF::NcDim adc_snap_data_dim = fo.addDim("adcSnapDataDim", diagnostics.adc_snap_data[0].rows());
2345 std::vector<netCDF::NcDim> dims = {adc_snap_dim, adc_snap_data_dim};
2346 Eigen::Index i = 0;
2347 for (auto const& x: diagnostics.adc_snap_data) {
2348 netCDF::NcVar adc_snap_v = fo.addVar("toltec" + std::to_string(calib.nws(i)) + "_adc_snap_data",netCDF::ncDouble, dims);
2349 adc_snap_v.putVar(x.data());
2350 i++;
2351 }
2352 }
2353
2354 // add eigenvalues
2355 if (!diagnostics.evals.empty()) {
2356 netCDF::NcDim n_eigs_dim = fo.addDim("n_eigs",ptcproc.cleaner.n_calc);
2357 netCDF::NcDim n_eig_grp_dim = fo.addDim("n_eig_grp",diagnostics.evals[0][0].size());
2358
2359 std::vector<netCDF::NcDim> eval_dims = {n_eig_grp_dim, n_eigs_dim};
2360
2361 // loop through chunks
2362 for (const auto &[key, val]: diagnostics.evals) {
2363 // loop through cleaner gropuing
2364 for (Eigen::Index i=0; i<val.size(); ++i) {
2365
2366 netCDF::NcVar eval_v = fo.addVar("evals_" + ptcproc.cleaner.grouping[i] + "_" + std::to_string(i) +
2367 "_chunk_" + std::to_string(key), netCDF::ncDouble,eval_dims);
2368 std::vector<std::size_t> start_eig_index = {0, 0};
2369 std::vector<std::size_t> size = {1, TULA_SIZET(ptcproc.cleaner.n_calc)};
2370
2371 // loop through eigenvalues in current group
2372 for (const auto &evals: val[i]) {
2373 eval_v.putVar(start_eig_index,size,evals.data());
2374 start_eig_index[0] += 1;
2375 }
2376 }
2377 }
2378 }
2379 fo.close();
2380}
2381
2382template <mapmaking::MapType map_t, class map_buffer_t>
2383void Engine::run_wiener_filter(map_buffer_t &mb) {
2384 // pointer to map buffer
2385 mapmaking::MapBuffer* pmb = &mb;
2386 // pointer to data file fits vector
2387 std::vector<fitsIO<file_type_enum::write_fits, CCfits::ExtHDU*>>* f_io = nullptr;
2388 // pointer to noise file fits vector
2389 std::vector<fitsIO<file_type_enum::write_fits, CCfits::ExtHDU*>>* n_io = nullptr;
2390 // directory name
2391 std::string dir_name;
2392
2393 // filtered obs maps
2394 if constexpr (map_t == mapmaking::FilteredObs) {
2395 f_io = &filtered_fits_io_vec;
2397 dir_name = obsnum_dir_name + "filtered/";
2398 }
2399
2400 // filtered coadded maps
2401 else if constexpr (map_t == mapmaking::FilteredCoadd) {
2404 dir_name = coadd_dir_name + "filtered/";
2405 }
2406
2407 for (Eigen::Index i=0; i<f_io->size(); ++i) {
2408 // get the array for the given map
2409 // add primary hdu
2410 add_phdu(f_io, pmb, i);
2411
2412 // add primary hdu to noise maps
2413 if (!pmb->noise.empty()) {
2414 add_phdu(n_io, pmb, i);
2415 }
2416 }
2417
2418 // loop through maps and run wiener filter
2419 for (Eigen::Index i=0; i<n_maps; ++i) {
2420 // current array
2421 auto array = maps_to_arrays(i);
2422 // get file index
2423 auto map_index = arrays_to_maps(i);
2424 // init fwhm in pixels
2426 // make wiener filter template
2428 // run the filter for the current map
2430
2431 // filter noise maps
2432 if (run_noise) {
2433 tula::logging::progressbar pb(
2434 [&](const auto &msg) { logger->info("{}", msg); }, 100,
2435 "filtering noise");
2436
2437 for (Eigen::Index j=0; j<mb.n_noise; ++j) {
2438 wiener_filter.filter_noise(mb, i, j);
2439 pb.count(mb.n_noise, mb.n_noise / 100);
2440 }
2441
2443 logger->info("renormalizing errors");
2444 // get median error from weight maps
2445 mb.calc_median_err();
2446 // get median map rms from noise maps
2447 mb.calc_median_rms();
2448
2449 // get rescaled normalization factor
2450 auto noise_factor = (1./pow(mb.median_rms.array(),2.))*mb.median_err.array();
2451 // re-normalize weight map
2452 mb.weight[i].noalias() = mb.weight[i]*noise_factor(i);
2453
2454 logger->info("median rms {} ({})", static_cast<float>(mb.median_rms(i)), mb.sig_unit);
2455 }
2456 }
2457
2459 // only write if saving all iterations or on last iteration
2460 // write maps immediately after filtering due to computation time
2461 write_maps(f_io,n_io,pmb,i);
2462
2463 logger->info("file has been written to:");
2464 logger->info("{}.fits",f_io->at(map_index).filepath);
2465
2466 // explicitly destroy the fits file after we're done with it
2467 bool close_file = true;
2470 close_file = false;
2471 }
2472 }
2473 // check if we're moving onto a new file
2474 if (i<n_maps-1) {
2475 if (arrays_to_maps(i+1) > arrays_to_maps(i) && close_file) {
2476 f_io->at(map_index).pfits->destroy();
2477 }
2478 }
2479 }
2480 }
2481
2483 // clear fits file vectors to ensure its closed.
2484 f_io->clear();
2485 n_io->clear();
2486 }
2487}
2488
2489template <mapmaking::MapType map_t, class map_buffer_t>
2490void Engine::find_sources(map_buffer_t &mb) {
2491 // clear all source vectors
2492 mb.n_sources.clear();
2493 mb.row_source_locs.clear();
2494 mb.col_source_locs.clear();
2495 // loop through maps
2496 for (Eigen::Index i=0; i<n_maps; ++i) {
2497 // update source vectors
2498 mb.n_sources.push_back(0);
2499 mb.row_source_locs.push_back(Eigen::VectorXi::Ones(1));
2500 mb.col_source_locs.push_back(Eigen::VectorXi::Ones(1));
2501
2502 // default value of -99 to keep size of vectors same as map vector
2503 mb.row_source_locs.back()*=-99;
2504 mb.col_source_locs.back()*=-99;
2505
2506 // run source finder
2507 auto sources_found = mb.find_sources(i);
2508
2509 // number of sources found for current map
2510 if (sources_found) {
2511 logger->info("{} source(s) found", mb.n_sources.back());
2512 }
2513 else {
2514 logger->info("no sources found");
2515 }
2516 }
2517
2518 // count up the total number of sources
2519 Eigen::Index n_sources = 0;
2520 for (const auto &sources: mb.n_sources) {
2521 n_sources += sources;
2522 }
2523
2524 // matrix to store source parameters
2525 mb.source_params.setZero(n_sources,map_fitter.n_params);
2526 mb.source_perror.setZero(n_sources,map_fitter.n_params);
2527
2528 // keep track of row in total source count
2529 Eigen::Index k = 0;
2530
2531 // now loop through and fit the sources
2532 for (Eigen::Index i=0; i<n_maps; ++i) {
2533 // skip map if no sources found
2534 if (mb.n_sources[i] > 0) {
2535 // current array
2536 auto array = maps_to_arrays(i);
2537 // init fwhm in pixels
2538 auto init_fwhm = toltec_io.array_fwhm_arcsec[array]*ASEC_TO_RAD/mb.pixel_size_rad;
2539
2540 // placeholder vectors for grppi map
2541 std::vector<int> source_in_vec, source_out_vec;
2542
2543 source_in_vec.resize(mb.n_sources[i]);
2544 std::iota(source_in_vec.begin(), source_in_vec.end(), 0);
2545 source_out_vec.resize(mb.n_sources[i]);
2546
2547 // loop through sources and fit them
2548 grppi::map(tula::grppi_utils::dyn_ex(parallel_policy), source_in_vec, source_out_vec, [&](auto j) {
2549 // update source rows and cols
2550 double init_row = mb.row_source_locs[i](j);
2551 double init_col = mb.col_source_locs[i](j);
2552
2553 // fit source
2554 auto [params, perrors, good_fit] =
2556 init_fwhm, init_row, init_col);
2557 if (good_fit) {
2558 // rescale fit params from pixel to on-sky units
2559 params(1) = RAD_TO_ASEC*mb.pixel_size_rad*(params(1) - (mb.n_cols)/2);
2560 params(2) = RAD_TO_ASEC*mb.pixel_size_rad*(params(2) - (mb.n_rows)/2);
2561 params(3) = RAD_TO_ASEC*STD_TO_FWHM*mb.pixel_size_rad*(params(3));
2562 params(4) = RAD_TO_ASEC*STD_TO_FWHM*mb.pixel_size_rad*(params(4));
2563
2564 // rescale fit errors from pixel to on-sky units
2565 perrors(1) = RAD_TO_ASEC*mb.pixel_size_rad*(perrors(1));
2566 perrors(2) = RAD_TO_ASEC*mb.pixel_size_rad*(perrors(2));
2567 perrors(3) = RAD_TO_ASEC*STD_TO_FWHM*mb.pixel_size_rad*(perrors(3));
2568 perrors(4) = RAD_TO_ASEC*STD_TO_FWHM*mb.pixel_size_rad*(perrors(4));
2569
2570 // if in radec calculate absolute pointing
2571 if (telescope.pixel_axes=="radec") {
2572 Eigen::VectorXd lat(1), lon(1);
2573 lat << params(2)*ASEC_TO_RAD;
2574 lon << params(1)*ASEC_TO_RAD;
2575
2576 auto [adec, ara] = engine_utils::tangent_to_abs(lat, lon, mb.wcs.crval[0]*DEG_TO_RAD, mb.wcs.crval[1]*DEG_TO_RAD);
2577
2578 params(1) = ara(0)*RAD_TO_DEG;
2579 params(2) = adec(0)*RAD_TO_DEG;
2580
2581 perrors(1) = perrors(1)*ASEC_TO_DEG;
2582 perrors(2) = perrors(2)*ASEC_TO_DEG;
2583 }
2584
2585 // add source params and errors to table
2586 mb.source_params.row(k+j) = params;
2587 mb.source_perror.row(k+j) = perrors;
2588 }
2589 return 0;
2590 });
2591
2592 // update row
2593 k += mb.n_sources[i];
2594 }
2595 }
2596}
2597
2598template <mapmaking::MapType map_t, class map_buffer_t>
2599void Engine::write_sources(map_buffer_t &mb, std::string dir_name) {
2600 // get filenmame for source table
2601 std::string source_filename = setup_filenames<map_t,engine_utils::toltecIO::source,
2602 engine_utils::toltecIO::map>(dir_name);
2603
2604 // source header information
2605 std::vector<std::string> source_header = {
2606 "array",
2607 "amp",
2608 "amp_err",
2609 "x_t",
2610 "x_t_err",
2611 "y_t",
2612 "y_t_err",
2613 "a_fwhm",
2614 "a_fwhm_err",
2615 "b_fwhm",
2616 "b_fwhm_err",
2617 "angle",
2618 "angle_err",
2619 "sig2noise"
2620 };
2621
2622 // units for fitted parameter centroids
2623 std::string pos_units = (telescope.pixel_axes == "radec") ? "deg" : "arcsec";
2624
2625 // units for source header
2626 std::map<std::string,std::string> source_header_units = {
2627 {"array","N/A"},
2628 {"amp", mb->sig_unit},
2629 {"amp_err", mb->sig_unit},
2630 {"x_t", pos_units},
2631 {"x_t_err", pos_units},
2632 {"y_t", pos_units},
2633 {"y_t_err", pos_units},
2634 {"a_fwhm", "arcsec"},
2635 {"a_fwhm_err", "arcsec"},
2636 {"b_fwhm", "arcsec"},
2637 {"b_fwhm_err", "arcsec"},
2638 {"angle", "rad"},
2639 {"angle_err", "rad"},
2640 {"sig2noise", "N/A"}
2641 };
2642
2643 // meta information for source table
2644 YAML::Node source_meta;
2645
2646 // add obsnums
2647 for (Eigen::Index i=0; i<mb->obsnums.size(); ++i) {
2648 // add obsnum to meta data
2649 source_meta["obsnum" + std::to_string(i)] = mb->obsnums[i];
2650 }
2651
2652 // add source name
2653 source_meta["Source"] = telescope.source_name;
2654
2655 // add date of file creation
2656 source_meta["creation_date"] = engine_utils::current_date_time();
2657
2658 // add observation date
2659 source_meta["date"] = date_obs.back();
2660
2661
2662 // populate source meta information
2663 for (const auto &[key,val]: source_header_units) {
2664 source_meta[key].push_back("units: " + val);
2665 // description from apt
2666 auto description = calib.apt_header_description[key];
2667 source_meta[key].push_back(description);
2668 }
2669
2670 // count up the total number of sources
2671 Eigen::Index n_sources = 0;
2672 for (const auto &sources: mb->n_sources) {
2673 n_sources += sources;
2674 }
2675
2676 // matrix to hold source information (floats for readability)
2677 Eigen::MatrixXf source_table(n_sources, 2*map_fitter.n_params + 2);
2678
2679 // loop through params and add arrays
2680 Eigen::Index k=0;
2681 for (Eigen::Index i=0; i<mb->n_sources.size(); ++i) {
2682 if (mb->n_sources[i]!=0) {
2683 // calculate map standard deviation
2684 double map_std_dev = engine_utils::calc_std_dev(mb->signal[i]);
2685
2686 for (Eigen::Index j=0; j<mb->n_sources[i]; ++j) {
2687 source_table(k,0) = maps_to_arrays(i);
2688 // set signal to noise
2689 source_table(k,2*map_fitter.n_params + 1) = mb->source_params(k,0)/map_std_dev;
2690
2691 k++;
2692 }
2693 }
2694 }
2695
2696 // populate source table
2697 Eigen::Index j = 0;
2698 for (Eigen::Index i=1; i<2*map_fitter.n_params; i=i+2) {
2699 source_table.col(i) = mb->source_params.col(j).template cast <float> ();
2700 source_table.col(i+1) = mb->source_perror.col(j).template cast <float> ();
2701 j++;
2702 }
2703
2704 // write source table
2705 to_ecsv_from_matrix(source_filename, source_table, source_header, source_meta);
2706}
Definition engine.h:155
Eigen::Index hwpr_start_indices
Definition engine.h:208
void obsnum_setup()
Definition engine.h:354
std::string obsnum_dir_name
Definition engine.h:184
void write_stats()
Definition engine.h:2278
std::string parallel_policy
Definition engine.h:196
void write_map_summary(map_buffer_t &)
Definition engine.h:1611
std::string redu_dir_name
Definition engine.h:178
std::map< std::string, Eigen::VectorXd > pointing_offsets_arcsec
Definition engine.h:241
std::vector< fitsIO< file_type_enum::write_fits, CCfits::ExtHDU * > > filtered_coadd_fits_io_vec
Definition engine.h:251
std::vector< Eigen::Index > start_indices
Definition engine.h:205
void create_tod_files()
Definition engine.h:1303
std::vector< Eigen::VectorXd > nw_times
Definition engine.h:166
void write_psd(map_buffer_t &, std::string)
Definition engine.h:2154
int redu_dir_num
Definition engine.h:181
auto get_map_name(int)
Definition engine.h:1729
std::vector< fitsIO< file_type_enum::write_fits, CCfits::ExtHDU * > > noise_fits_io_vec
Definition engine.h:246
std::vector< fitsIO< file_type_enum::write_fits, CCfits::ExtHDU * > > coadd_noise_fits_io_vec
Definition engine.h:250
void get_beammap_config(CT &)
Definition engine.h:668
key_vec_t invalid_keys
Definition engine.h:190
std::string tod_output_type
Definition engine.h:223
auto setup_filenames(std::string dir_name)
Definition engine.h:1701
std::string tod_output_subdir_name
Definition engine.h:223
void create_obs_map_files()
Definition engine.h:992
key_vec_t missing_keys
Definition engine.h:190
std::string coadd_dir_name
Definition engine.h:184
std::vector< fitsIO< file_type_enum::write_fits, CCfits::ExtHDU * > > filtered_noise_fits_io_vec
Definition engine.h:247
void get_mapmaking_config(CT &)
Definition engine.h:560
Eigen::VectorXI maps_to_arrays
Definition engine.h:232
int fruit_iter
Definition engine.h:238
bool verbose_mode
Definition engine.h:172
int n_maps
Definition engine.h:229
Eigen::VectorXI arrays_to_maps
Definition engine.h:232
std::vector< fitsIO< file_type_enum::write_fits, CCfits::ExtHDU * > > filtered_fits_io_vec
Definition engine.h:247
void run_wiener_filter(map_buffer_t &)
Definition engine.h:2383
std::string output_dir
Definition engine.h:178
int n_scans_done
Definition engine.h:199
bool write_filtered_maps_partial
Definition engine.h:220
Eigen::Index hwpr_end_indices
Definition engine.h:208
std::vector< Eigen::Index > end_indices
Definition engine.h:205
Eigen::VectorXd t_common
Definition engine.h:164
void write_hist(map_buffer_t &, std::string)
Definition engine.h:2239
std::vector< fitsIO< file_type_enum::write_fits, CCfits::ExtHDU * > > filtered_coadd_noise_fits_io_vec
Definition engine.h:251
void add_phdu(fits_io_type &, map_buffer_t &, Eigen::Index)
Definition engine.h:1764
std::string redu_type
Definition engine.h:214
std::map< std::string, int > gaps
Definition engine.h:175
std::vector< Eigen::VectorXi > masks
Definition engine.h:165
std::string map_grouping
Definition engine.h:226
std::shared_ptr< spdlog::logger > logger
Definition engine.h:161
void get_citlali_config(CT &)
Definition engine.h:773
void add_tod_header(map_buffer_t &)
Definition engine.h:1056
std::map< std::string, std::string > tod_filename
Definition engine.h:187
void write_sources(map_buffer_t &, std::string)
Definition engine.h:2599
void get_timestream_config(CT &)
Definition engine.h:498
std::string tod_type
Definition engine.h:211
void cli_summary()
Definition engine.h:1490
Eigen::VectorXI maps_to_stokes
Definition engine.h:235
void get_astrometry_config(CT &)
Definition engine.h:966
void get_photometry_config(CT &)
Definition engine.h:932
void get_rtc_config(CT &)
Definition engine.h:467
std::string obsnum
Definition engine.h:217
std::vector< fitsIO< file_type_enum::write_fits, CCfits::ExtHDU * > > coadd_fits_io_vec
Definition engine.h:250
void find_sources(map_buffer_t &)
Definition engine.h:2490
std::map< std::string, double > interface_sync_offset
Definition engine.h:202
std::vector< std::string > date_obs
Definition engine.h:169
void write_chunk_summary(TCData< tc_t, Eigen::MatrixXd > &)
Definition engine.h:1556
Eigen::ArrayXd pointing_offsets_modified_julian_date
Definition engine.h:243
void get_ptc_config(CT &)
Definition engine.h:487
std::vector< fitsIO< file_type_enum::write_fits, CCfits::ExtHDU * > > fits_io_vec
Definition engine.h:246
int n_threads
Definition engine.h:193
std::string map_method
Definition engine.h:226
std::vector< std::vector< std::string > > key_vec_t
Definition engine.h:158
void get_map_filter_config(CT &)
Definition engine.h:738
void write_maps(fits_io_type &, fits_io_type &, map_buffer_t &, Eigen::Index)
Definition engine.h:2057
Definition calib.h:14
Eigen::VectorXI fg
Definition calib.h:29
bool run_hwpr
Definition calib.h:41
std::string ignore_hwpr
Definition calib.h:32
Eigen::Index n_arrays
Definition calib.h:53
std::map< Eigen::Index, double > array_pas
Definition calib.h:62
std::map< Eigen::Index, double > array_beam_areas
Definition calib.h:65
Eigen::VectorXI nws
Definition calib.h:44
Eigen::VectorXI arrays
Definition calib.h:44
std::map< std::string, std::string > apt_header_units
Definition calib.h:116
std::string apt_filepath
Definition calib.h:20
std::map< std::string, Eigen::VectorXd > apt
Definition calib.h:22
std::map< std::string, std::string > apt_header_description
Definition calib.h:151
std::map< Eigen::Index, std::tuple< double, double > > array_fwhms
Definition calib.h:59
Eigen::Index n_dets
Definition calib.h:47
Definition diagnostics.h:14
std::map< Eigen::Index, std::vector< std::vector< Eigen::VectorXd > > > evals
Definition diagnostics.h:45
bool write_evals
Definition diagnostics.h:25
std::vector< std::string > grp_stats_header
Definition diagnostics.h:40
std::map< std::string, Eigen::MatrixXd > stats
Definition diagnostics.h:16
std::vector< std::string > det_stats_header
Definition diagnostics.h:31
std::vector< Eigen::Matrix< short, Eigen::Dynamic, Eigen::Dynamic > > adc_snap_data
Definition diagnostics.h:19
Definition telescope.h:12
bool sim_obs
Definition telescope.h:20
std::map< std::string, Eigen::VectorXd > tel_data
Definition telescope.h:54
double fsmp
Definition telescope.h:42
std::string chunk_mode
Definition telescope.h:30
std::string obs_goal
Definition telescope.h:23
std::string source_name
Definition telescope.h:23
double tau_225_GHz
Definition telescope.h:45
Eigen::MatrixXI scan_indices
Definition telescope.h:51
std::string project_id
Definition telescope.h:23
bool force_chunk
Definition telescope.h:36
std::string pixel_axes
Definition telescope.h:59
std::map< std::string, Eigen::VectorXd > tel_header
Definition telescope.h:56
double chunking_value
Definition telescope.h:33
Eigen::Index inner_scans_chunk
Definition telescope.h:48
Definition fitting.h:13
double bounding_box_pix
Definition fitting.h:26
auto fit_to_gaussian(Eigen::DenseBase< Derived > &, Eigen::DenseBase< Derived > &, double, double, double)
Definition fitting.h:172
int n_params
Definition fitting.h:23
double fwhm_low
Definition fitting.h:38
double flux_low
Definition fitting.h:33
double fitting_region_pix
Definition fitting.h:27
bool fit_angle
Definition fitting.h:43
@ pointing
Definition fitting.h:18
double fwhm_high
Definition fitting.h:40
double flux_high
Definition fitting.h:35
Eigen::VectorXd fwhm_limits
Definition fitting.h:30
Eigen::VectorXd flux_limits
Definition fitting.h:30
Definition toltec_io.h:10
ProdType
Definition toltec_io.h:21
@ map
Definition toltec_io.h:22
@ stats
Definition toltec_io.h:28
@ ptc_timestream
Definition toltec_io.h:27
@ rtc_timestream
Definition toltec_io.h:26
@ noise
Definition toltec_io.h:23
std::map< Eigen::Index, std::string > array_name_map
Definition toltec_io.h:54
std::map< Eigen::Index, double > array_freq_map
Definition toltec_io.h:68
std::map< Eigen::Index, double > array_wavelength_map
Definition toltec_io.h:61
DataType
Definition toltec_io.h:13
@ source
Definition toltec_io.h:17
@ toltec
Definition toltec_io.h:14
@ filtered
Definition toltec_io.h:34
@ raw
Definition toltec_io.h:33
std::string create_filename(const std::string, const std::string, std::string, std::string, const bool)
Definition toltec_io.h:86
std::map< Eigen::Index, double > array_fwhm_arcsec
Definition toltec_io.h:75
Definition fits_io.h:10
Definition jinc_mm.h:26
void calculate_jinc_splines()
Definition jinc_mm.h:152
std::string mode
Definition jinc_mm.h:56
std::map< Eigen::Index, Eigen::VectorXd > shape_params
Definition jinc_mm.h:68
double r_max
Definition jinc_mm.h:62
void allocate_jinc_matrix(double)
Definition jinc_mm.h:118
std::string parallel_policy
Definition jinc_mm.h:53
bool run_polarization
Definition jinc_mm.h:50
Definition ml_mm.h:22
double tolerance
Definition ml_mm.h:27
int max_iterations
Definition ml_mm.h:28
Definition map.h:45
WCS wcs
Definition map.h:48
double exposure_time
Definition map.h:75
std::string sig_unit
Definition map.h:73
double source_window_rad
Definition map.h:128
Eigen::Index n_rows
Definition map.h:65
std::string parallel_policy
Definition map.h:59
Eigen::Index n_cols
Definition map.h:65
std::vector< Eigen::MatrixXd > coverage
Definition map.h:78
std::vector< Eigen::MatrixXd > signal
Definition map.h:78
std::string source_finder_mode
Definition map.h:123
std::vector< Eigen::MatrixXd > weight
Definition map.h:78
bool randomize_dets
Definition map.h:87
std::vector< Eigen::MatrixXd > kernel
Definition map.h:78
Eigen::Index n_noise
Definition map.h:67
void get_config(tula::config::YamlConfig &, std::vector< std::vector< std::string > > &, std::vector< std::vector< std::string > > &, std::string, std::string)
Definition map.cpp:15
double source_sigma
Definition map.h:126
std::vector< Eigen::Tensor< double, 3 > > noise
Definition map.h:81
double pixel_size_rad
Definition map.h:69
Definition naive_mm.h:20
bool run_polarization
Definition naive_mm.h:52
Definition wiener_filter.h:23
void filter_noise(MB &mb, const int, const int)
Definition wiener_filter.h:939
std::string template_type
Definition wiener_filter.h:29
std::string parallel_policy
Definition wiener_filter.h:59
std::map< std::string, double > template_fwhm_rad
Definition wiener_filter.h:50
std::string filter_type
Definition wiener_filter.h:29
bool normalize_error
Definition wiener_filter.h:31
void filter_maps(MB &, const int)
Definition wiener_filter.h:870
double init_fwhm
Definition wiener_filter.h:47
engine_utils::mapFitter map_fitter
Definition wiener_filter.h:69
void get_config(config_t &, std::vector< std::vector< std::string > > &, std::vector< std::vector< std::string > > &)
Definition wiener_filter.h:126
void make_template(MB &, CD &c, const double, const int)
Definition wiener_filter.h:694
bool run_lowpass
Definition wiener_filter.h:35
auto calc_tau(Eigen::DenseBase< Derived > &, double)
Definition calibrate.h:136
void setup(double tau_225_zenith)
Definition calibrate.h:31
std::string extinction_model
Definition calibrate.h:18
std::map< Eigen::Index, Eigen::VectorXI > n_eig_to_cut
Definition clean.h:27
int n_calc
Definition clean.h:30
std::vector< std::string > grouping
Definition clean.h:36
double fsmp
Definition despike.h:22
void make_filter(double)
Definition filter.h:34
Eigen::Index n_terms
Definition filter.h:19
std::string type
Definition kernel.h:15
std::string map_grouping
Definition kernel.h:28
double fwhm_rad
Definition kernel.h:22
void setup(Eigen::Index)
Definition kernel.h:50
Definition ptcproc.h:19
void get_config(config_t &, std::vector< std::vector< std::string > > &, std::vector< std::vector< std::string > > &)
Definition ptcproc.h:62
bool run_clean
Definition ptcproc.h:22
timestream::Cleaner cleaner
Definition ptcproc.h:31
double upper_weight_factor
Definition ptcproc.h:26
double lower_weight_factor
Definition ptcproc.h:26
std::string weighting_type
Definition ptcproc.h:28
double med_weight_factor
Definition ptcproc.h:24
std::map< int, std::string > stokes_params
Definition polarization.h:15
Definition rtcproc.h:18
bool run_polarization
Definition rtcproc.h:23
bool run_kernel
Definition rtcproc.h:24
void get_config(config_t &, std::vector< std::vector< std::string > > &, std::vector< std::vector< std::string > > &)
Definition rtcproc.h:71
bool run_calibrate
Definition rtcproc.h:28
bool run_downsample
Definition rtcproc.h:27
timestream::Filter filter
Definition rtcproc.h:35
bool run_tod_filter
Definition rtcproc.h:26
bool run_despike
Definition rtcproc.h:25
bool run_extinction
Definition rtcproc.h:29
timestream::Calibration calibration
Definition rtcproc.h:37
timestream::Despiker despiker
Definition rtcproc.h:34
timestream::Kernel kernel
Definition rtcproc.h:33
timestream::Polarization polarization
Definition rtcproc.h:32
std::string fruit_loops_path
Definition timestream.h:281
double upper_inv_var_factor
Definition timestream.h:302
double fruit_loops_sig2noise
Definition timestream.h:289
bool run_tod_output
Definition timestream.h:276
bool write_evals
Definition timestream.h:276
int fruit_loops_iters
Definition timestream.h:287
bool run_fruit_loops
Definition timestream.h:279
Eigen::VectorXd fruit_loops_flux
Definition timestream.h:291
double lower_inv_var_factor
Definition timestream.h:302
std::string fruit_loops_type
Definition timestream.h:285
void get_config_value(config_t config, param_t &param, key_vec_t &missing_keys, key_vec_t &invalid_keys, option_t option, std::vector< param_t > allowed={}, std::vector< param_t > min_val={}, std::vector< param_t > max_val={})
Definition config.h:58
#define DEG_TO_RAD
Definition constants.h:27
#define MJY_SR_TO_mJY_ASEC
Definition constants.h:51
#define STD_TO_FWHM
Definition constants.h:45
#define FWHM_TO_STD
Definition constants.h:48
#define RAD_TO_ASEC
Definition constants.h:36
#define ASEC_TO_RAD
Definition constants.h:33
#define RAD_TO_DEG
Definition constants.h:30
#define ASEC_TO_DEG
Definition constants.h:24
constexpr auto pi
Definition constants.h:6
void to_ecsv_from_matrix(std::string filepath, Eigen::DenseBase< Derived > &table, std::vector< std::string > header, YAML::Node meta)
Definition ecsv_io.h:50
static const double mJy_beam_to_uK(const double flux_mjy_beam, const double freq_Hz, const double fwhm)
Definition utils.h:77
auto tangent_to_abs(Eigen::DenseBase< Derived > &lat, Eigen::DenseBase< Derived > &lon, const double cra, const double cdec)
Definition pointing.h:88
static const int get_phys_memory()
Definition utils.h:56
static const std::string current_date_time()
Definition utils.h:91
auto calc_std_dev(Eigen::DenseBase< DerivedA > &data)
Definition utils.h:336
MapType
Definition map.h:17
@ FilteredObs
Definition map.h:19
@ FilteredCoadd
Definition map.h:21
@ RawObs
Definition map.h:18
@ RawCoadd
Definition map.h:20
void add_netcdf_var(netCDF::NcFile &fo, std::string name, T data)
Definition netcdf_io.h:11
Definition engine.h:115
bool beammap_subtract_reference
Definition engine.h:133
std::map< std::string, double > lower_sig2noise
Definition engine.h:148
std::map< std::string, double > beammap_fluxes_mJy_beam
Definition engine.h:123
Eigen::Index beammap_reference_det
Definition engine.h:136
std::map< std::string, double > upper_fwhm_arcsec
Definition engine.h:148
std::map< std::string, double > max_dist_arcsec
Definition engine.h:149
double lower_sens_factor
Definition engine.h:152
std::map< std::string, double > lower_fwhm_arcsec
Definition engine.h:148
double beammap_dec_rad
Definition engine.h:120
Eigen::VectorXd sens_psd_limits_Hz
Definition engine.h:145
int beammap_tod_output_iter
Definition engine.h:142
std::string beammap_source_name
Definition engine.h:117
std::map< std::string, double > beammap_err_MJy_Sr
Definition engine.h:124
double beammap_ra_rad
Definition engine.h:120
std::map< std::string, double > beammap_fluxes_MJy_Sr
Definition engine.h:124
int beammap_iter_max
Definition engine.h:127
bool beammap_derotate
Definition engine.h:139
std::map< std::string, double > upper_sig2noise
Definition engine.h:149
double beammap_iter_tolerance
Definition engine.h:130
std::map< std::string, double > beammap_err_mJy_beam
Definition engine.h:123
double upper_sens_factor
Definition engine.h:152
std::vector< float > crval
Definition map.h:36
Definition engine.h:93
mapmaking::NaiveMapmaker naive_mm
Definition engine.h:109
engine::Telescope telescope
Definition engine.h:96
engine_utils::mapFitter map_fitter
Definition engine.h:99
mapmaking::MLMapmaker ml_mm
Definition engine.h:111
mapmaking::WienerFilter wiener_filter
Definition engine.h:112
engine::Diagnostics diagnostics
Definition engine.h:98
engine_utils::toltecIO toltec_io
Definition engine.h:97
timestream::PTCProc ptcproc
Definition engine.h:105
mapmaking::JincMapmaker jinc_mm
Definition engine.h:110
mapmaking::MapBuffer omb
Definition engine.h:108
mapmaking::MapBuffer cmb
Definition engine.h:108
timestream::RTCProc rtcproc
Definition engine.h:102
engine::Calib calib
Definition engine.h:95
Definition engine.h:71
bool run_noise
Definition engine.h:86
bool use_subdir
Definition engine.h:75
bool run_coadd
Definition engine.h:85
bool run_map_filter
Definition engine.h:87
bool interp_over_gaps
Definition engine.h:73
bool run_source_finder
Definition engine.h:90
bool run_tod_output
Definition engine.h:81
bool run_mapmaking
Definition engine.h:84
bool run_tod
Definition engine.h:78
TC data class.
Definition timestream.h:55