Citlali
Loading...
Searching...
No Matches
timestream.h
Go to the documentation of this file.
1#pragma once
2
3#include <map>
4#include <filesystem>
5
6#include <unsupported/Eigen/CXX11/Tensor>
7
8#include <CCfits/CCfits>
9
10#include <tula/enum.h>
11#include <tula/nddata/labelmapper.h>
12#include <tula/formatter/enum.h>
13#include <tula/formatter/matrix.h>
14#include <tula/formatter/utils.h>
15#include <tula/logging.h>
16#include <kids/core/wcs.h>
17
21
23
24namespace timestream {
25
27 Good = 0,
28 D21FitsBetter = 1 << 0,
31 D21OutOfRange = 1 << 3,
33 LargeOffset = 1 << 5,
34 NotConverged = 1 << 6,
35 OutOfRange = 1 << 7,
36 QrOutOfRange = 1 << 8,
37 LowGain = 1 << 9,
38 APT = 1 << 10,
39 Spike = 1 << 11,
40 Freq = 1 << 12
41};
42
43namespace wcs = kids::wcs;
44
45// clang-format off
46TULA_BITFLAG(TCDataKind, int, 0xFFFF,
47 RTC = 1 << 0,
48 PTC = 1 << 1,
49 Any = RTC | PTC
50 );
51// clang-format on
52
54template <TCDataKind kind_ = TCDataKind::Any, typename = void>
55struct TCData;
56
57} // namespace timestream
58
59namespace std {
60
61// register TCData as a variant type
62// below are mandatory to inherit from variant on gcc
63template <timestream::TCDataKind kind>
64struct variant_size<timestream::TCData<kind>>
65 : variant_size<typename timestream::TCData<kind>::variant_t> {};
66
67template <size_t _Np, auto kind>
68struct variant_alternative<_Np, timestream::TCData<kind>>
69 : variant_alternative<_Np, typename timestream::TCData<kind>::variant_t> {};
70
71#if defined(__GNUC__) && !defined(__clang__)
72#if (__GNUC__ >= 9 && __GNUC__ < 13)
73// this is need to allow inherit from std::variant on GCC
74namespace __detail {
75namespace __variant {
76
77template <typename _Ret, typename _Visitor, auto kind, size_t __first>
78struct _Multi_array<_Ret (*)(_Visitor, timestream::TCData<kind>), __first>
79 : _Multi_array<_Ret (*)(_Visitor, typename timestream::TCData<kind>::variant_t),
80 __first> {
81 static constexpr int __do_cookie = 0;
82};
83template <typename _Maybe_variant_cookie, auto kind>
84struct _Extra_visit_slot_needed<_Maybe_variant_cookie, timestream::TCData<kind>>
85 : _Extra_visit_slot_needed<_Maybe_variant_cookie,
86 typename timestream::TCData<kind>::variant_t> {};
87
88template <typename _Maybe_variant_cookie, auto kind>
89struct _Extra_visit_slot_needed<_Maybe_variant_cookie, timestream::TCData<kind> &>
90 : _Extra_visit_slot_needed<_Maybe_variant_cookie,
91 typename timestream::TCData<kind>::variant_t &> {};
92} // namespace __variant
93} // namespace __detail
94#else
95#endif
96#endif
97
98} // namespace std
99
100namespace timestream {
101
102namespace internal {
103
104template <typename Derived>
106
107template <TCDataKind kind_>
108struct TCDataBase<TCData<kind_>> {
109 static constexpr auto kind() { return kind_; }
110 //using meta_t = typename internal::impl_traits<TCData<kind_>>::meta_t;
111 //meta_t meta;
112};
113
114} // namespace internal
115
116// data status
117struct Status {
118 bool demodulated = false;
119 bool kernel_generated = false;
120 bool despiked = false;
121 bool tod_filtered = false;
122 bool downsampled = false;
123 bool calibrated = false;
125 bool cleaned = false;
126};
127
128// wcs objects
129struct DetectorAxis : wcs::Axis<DetectorAxis, wcs::CoordsKind::Column>,
130 wcs::LabeledData<DetectorAxis> {
131 DetectorAxis() = default;
132 DetectorAxis(Eigen::MatrixXd data_, tula::nddata::LabelMapper<DetectorAxis> row_labels_)
133 : data{std::move(data_)}, row_labels{std::move(row_labels_)} {}
134 std::string_view name{"detector"};
135 Eigen::MatrixXd data;
136 tula::nddata::LabelMapper<DetectorAxis> row_labels;
137};
138
139struct TimeAxis : wcs::Axis<TimeAxis, wcs::CoordsKind::Row>,
140 wcs::LabeledData<TimeAxis> {
141 TimeAxis() = default;
142 TimeAxis(Eigen::MatrixXd data_, tula::nddata::LabelMapper<TimeAxis> col_labels_)
143 : data{std::move(data_)}, col_labels{std::move(col_labels_)} {}
144 std::string_view name{"time"};
145 Eigen::MatrixXd data;
146 tula::nddata::LabelMapper<TimeAxis> col_labels;
147};
148
149struct TimeStreamFrame : wcs::Frame2D<TimeStreamFrame, TimeAxis, DetectorAxis> {
152
153 // Frame2D impl
154 const TimeAxis &row_axis() const { return time_axis; }
155 const DetectorAxis &col_axis() const { return detector_axis; }
156};
157
158// data objects
159
161template <typename Derived>
163 tula::nddata::NDData<TimeStream<Derived>> {
165 // the timestream is stored in row major for efficient r/w
166 template <typename PlainObject>
167 struct dataref_t : tula::nddata::NDData<dataref_t<PlainObject>> {
168 PlainObject data{nullptr, 0, 0};
169 };
170
171 template <typename PlainObject>
172 struct data_t : tula::nddata::NDData<data_t<PlainObject>> {
173 PlainObject data;
174 };
175
176 // time of creation
178
179 // number of detectors lower than weight limit
181
182 // data status struct
184
185 // kernel timestreams
187 // flag timestream
189 // noise timestreams
191 // bitwise flags
193 // current scan indices
195 // scan index
197 // telescope data for scan
199 // pointing offsets
201 // hwpr angle for scan
203 // detector angle
205 // fcf
207 // vectors for mapping apt table onto timestreams
209 // detector pointing
211};
212
213template <typename RefType>
214struct TCData<TCDataKind::RTC,RefType>
215 : TimeStream<TCData<TCDataKind::RTC>> {
217 using data_t = std::conditional_t<tula::eigen_utils::is_plain_v<RefType>,Base::data_t<RefType>,
218 Base::dataref_t<RefType>>;
219 // time chunk type
220 std::string_view name{"RTC"};
221 // data timestreams
223};
224
225template <typename RefType>
226struct TCData<TCDataKind::PTC, RefType>
227 : TimeStream<TCData<TCDataKind::PTC>> {
229 using data_t = std::conditional_t<tula::eigen_utils::is_plain_v<RefType>,Base::data_t<RefType>,
230 Base::dataref_t<RefType>>;
231 // time chunk type
232 std::string_view name{"PTC"};
233 // data timestreams
235 // weights for current scan
236 Base::data_t<Eigen::VectorXd> weights;
237 // eigenvalues for scan
238 Base::data_t<std::vector<std::vector<Eigen::VectorXd>>> evals;
239 // eigenvectors for scan
240 Base::data_t<std::vector<std::vector<Eigen::MatrixXd>>> evecs;
241 // medians of good detector weights
242 Base::data_t<std::vector<double>> median_weights;
243};
244
246template <TCDataKind kind_>
247struct TCData<kind_, std::enable_if_t<tula::enum_utils::is_compound_v<kind_>>>
248 : tula::enum_utils::enum_to_variant_t<kind_, TCData> {
249 using Base = tula::enum_utils::enum_to_variant_t<kind_, TCData>;
250 using variant_t = tula::enum_utils::enum_to_variant_t<kind_, TCData>;
251
252 const variant_t &variant() const { return *this; }
253 static constexpr auto kind() { return kind_; }
254};
255
256// class for tod processing
257class TCProc {
258public:
259 // get logger
260 std::shared_ptr<spdlog::logger> logger = spdlog::get("citlali_logger");
261
262 // toltec io class for array names
264
265 // add or subtract gaussian source
274
275 // tod output
277
278 // run fruit loops
280 // path for input images
281 std::string fruit_loops_path;
282 // paths for first set of images
283 std::vector<std::string> init_fruit_loops_path;
284 // fruit loops type and mode
286 // number of fruit loops iterations
288 // signal-to-noise cut for fruit loops algorithm
290 // flux density cut for fruit loops algorithm
291 Eigen::VectorXd fruit_loops_flux;
292 // save all iterations
294
295 // map buffer for map to tod approach
297
298 // number of weight outlier iterations
299 int iter_lim = 0;
300
301 // upper and lower inv var limits for outliers
303
304 // mask radius in arcseconds
306
307 // create a map buffer from a citlali reduction directory
308 template <class calib_t>
309 void load_mb(std::string, std::string, calib_t &);
310
311 // get limits for a particular grouping
312 template <class calib_t>
313 auto get_grouping(std::string, calib_t &, int);
314
315 // compute and store pointing of all detectors
316 template <TCDataKind tcdata_t, class calib_t>
317 void precompute_pointing(TCData<tcdata_t, Eigen::MatrixXd> &, calib_t &, std::string, std::string);
318
319 // translate citlali map buffer to timestream and add/subtract from TCData scans
320 template <TCProc::SourceType source_type, class mb_t, TCDataKind tcdata_t, class calib_t, typename Derived>
321 void map_to_tod(mb_t &, TCData<tcdata_t, Eigen::MatrixXd> &, calib_t &, Eigen::DenseBase<Derived> &, std::string, std::string);
322
323 // remove detectors with outlier weights
324 template <TCDataKind tcdata_t, class calib_t>
325 auto remove_bad_dets(TCData<tcdata_t, Eigen::MatrixXd> &, calib_t &, std::string);
326
327 // remove detectors with small correlations
328 template <TCDataKind tcdata_t, class calib_t, typename Derived>
329 auto remove_uncorrelated(TCData<tcdata_t, Eigen::MatrixXd> &, calib_t &, std::string);
330
331 // add or subtract gaussian to timestream
332 template <SourceType source_type, TCDataKind tcdata_t, typename Derived, typename apt_t>
333 void add_gaussian(TCData<tcdata_t, Eigen::MatrixXd> &, Eigen::DenseBase<Derived> &, std::string &,
334 std::string &, apt_t &, double, Eigen::Index, Eigen::Index);
335
336 // flag a region around the center of the map
337 template <TCDataKind tcdata_t, class calib_t>
338 auto mask_region(TCData<tcdata_t, Eigen::MatrixXd> &, calib_t &, std::string, std::string, int, int, int);
339
340 // append time chunk params common to rtcs and ptcs
341 template <TCDataKind tcdata_t, class calib_t, typename pointing_offset_t>
342 void append_base_to_netcdf(netCDF::NcFile &, TCData<tcdata_t, Eigen::MatrixXd> &, std::string,
343 std::string &, pointing_offset_t &, calib_t &);
344};
345
346template <class calib_t>
347void TCProc::load_mb(std::string filepath, std::string noise_filepath, calib_t &calib) {
348
349 namespace fs = std::filesystem;
350
351 // clear map buffer
352 std::vector<Eigen::MatrixXd>().swap(tod_mb.signal);
353 std::vector<Eigen::MatrixXd>().swap(tod_mb.weight);
354 std::vector<Eigen::MatrixXd>().swap(tod_mb.kernel);
355 std::vector<Eigen::Tensor<double,3>>().swap(tod_mb.noise);
356 std::vector<std::string>().swap(tod_mb.wcs.cunit);
357
358 tod_mb.median_rms.resize(0);
359
360 // resize wcs params
361 tod_mb.wcs.naxis.resize(4,0.);
362 tod_mb.wcs.crpix.resize(4,0.);
363 tod_mb.wcs.crval.resize(4,0.);
364 tod_mb.wcs.cdelt.resize(4,0.);
365 tod_mb.wcs.cunit.push_back("N/A");
366 tod_mb.wcs.cunit.push_back("N/A");
367
368 // vector to hold mean rms
369 std::vector<double> median_rms_vec;
370
371 // loop through arrays in current obs
372 for (const auto &arr: calib.arrays) {
373 try {
374 // loop through files in redu directory
375 for (const auto& entry : fs::directory_iterator(filepath)) {
376 // check if fits file
377 bool fits_file = entry.path().string().find(".fits") != std::string::npos;
378 // find current array obs map
379 if (entry.path().string().find(toltec_io.array_name_map[arr]) != std::string::npos && fits_file) {
380
381 // get filename
382 std::string filename;
383 size_t last_slash_pos = entry.path().string().find_last_of("/");
384 if (last_slash_pos != std::string::npos) {
385 filename = entry.path().string().substr(last_slash_pos + 1);
386 }
387
388 // get maps (if noise not in filename)
389 if (filename.find("noise") == std::string::npos) {
390 // get fits file
391 fitsIO<file_type_enum::read_fits, CCfits::ExtHDU*> fits_io(entry.path().string());
392
393 // get number of extensions other than primary extension
394 int num_extensions = 0;
395 bool keep_going = true;
396 while (keep_going) {
397 try {
398 // attempt to access an HDU (ignore primary hdu)
399 CCfits::ExtHDU& ext = fits_io.pfits->extension(num_extensions + 1);
400 num_extensions++;
401 } catch (CCfits::FITS::NoSuchHDU) {
402 // NoSuchHDU exception is thrown when there are no more HDUs
403 keep_going = false;
404 }
405 }
406
407 if (num_extensions == 0) {
408 logger->error("{} is empty",filename);
409 std::exit(EXIT_FAILURE);
410 }
411
412 // get wcs (should be same for all maps)
413 CCfits::ExtHDU& extension = fits_io.pfits->extension(1);
414
415 // get naxis
416 extension.readKey("NAXIS1", tod_mb.wcs.naxis[0]);
417 extension.readKey("NAXIS2", tod_mb.wcs.naxis[1]);
418 // get crpix
419 extension.readKey("CRPIX1", tod_mb.wcs.crpix[0]);
420 extension.readKey("CRPIX2", tod_mb.wcs.crpix[1]);
421 // get crval
422 extension.readKey("CRVAL1", tod_mb.wcs.crval[0]);
423 extension.readKey("CRVAL2", tod_mb.wcs.crval[1]);
424 // get cdelt
425 extension.readKey("CDELT1", tod_mb.wcs.cdelt[0]);
426 extension.readKey("CDELT2", tod_mb.wcs.cdelt[1]);
427 // get cunit
428 extension.readKey("CUNIT1", tod_mb.wcs.cunit[0]);
429 extension.readKey("CUNIT2", tod_mb.wcs.cunit[1]);
430
431 // get maps, including all fg maps
432 for (int i=0; i<num_extensions; ++i) {
433 CCfits::ExtHDU& ext = fits_io.pfits->extension(i+1);
434 std::string extName;
435 ext.readKey("EXTNAME", extName);
436 // get signal map
437 if (extName.find("signal") != std::string::npos) {
438 tod_mb.signal.push_back(fits_io.get_hdu(extName));
439 logger->info("found {} [{}]", filename, extName);
440 }
441 // get weight map
442 else if (extName.find("weight") != std::string::npos) {
443 tod_mb.weight.push_back(fits_io.get_hdu(extName));
444 logger->info("found {} [{}]", filename, extName);
445 }
446 // get kernel map
447 else if (extName.find("kernel") != std::string::npos) {
448 tod_mb.kernel.push_back(fits_io.get_hdu(extName));
449 logger->info("found {} [{}]", filename, extName);
450 }
451 }
452 }
453 }
454 }
455
456 // get noise maps
457 // loop through files in redu directory
458 for (const auto& entry : fs::directory_iterator(noise_filepath)) {
459 // check if fits file
460 bool fits_file = entry.path().string().find(".fits") != std::string::npos;
461 // find current array obs map
462 if (entry.path().string().find(toltec_io.array_name_map[arr]) != std::string::npos && fits_file) {
463
464 // get filename
465 std::string filename;
466 size_t lastSlashPos = entry.path().string().find_last_of("/");
467 if (lastSlashPos != std::string::npos) {
468 filename = entry.path().string().substr(lastSlashPos + 1);
469 }
470
471 // check if the current file is a noise map
472 if (filename.find("_noise_citlali.fits") != std::string::npos) {
473 // get fits file
474 fitsIO<file_type_enum::read_fits, CCfits::ExtHDU*> fits_io(entry.path().string());
475
476 // get number of noise maps
477 int num_extensions = 0;
478 bool keep_going = true;
479 while (keep_going) {
480 try {
481 // attempt to access an HDU (ignore primary hdu)
482 CCfits::ExtHDU& ext = fits_io.pfits->extension(num_extensions + 1);
483 std::string extName;
484 ext.readKey("EXTNAME", extName);
485
486 // only get stokes I
487 if (extName.find("_I") != std::string::npos) {
488 tod_mb.n_noise++;
489 }
490 // if extension found, add to total number
491 num_extensions++;
492 } catch (CCfits::FITS::NoSuchHDU) {
493 // NoSuchHDU exception is thrown when there are no more HDUs
494 keep_going = false;
495 }
496 }
497
498 if (num_extensions == 0) {
499 logger->error("{} is empty",filename);
500 std::exit(EXIT_FAILURE);
501 }
502
503 // loop through noise maps for current array
504 for (int i=0; i<num_extensions; ++i) {
505 // get current extension
506 CCfits::ExtHDU& ext = fits_io.pfits->extension(i+1);
507 // get extension name
508 std::string extName;
509 ext.readKey("EXTNAME", extName);
510 // if signal I's first noise map (ignore Q, U, and extra noise maps)
511 if (extName.find("signal") != std::string::npos && extName.find("_0_I") != std::string::npos) { // get mean rms for current extension
512 // get median rms from current extension
513 double median_rms;
514 ext.readKey("MEDRMS", median_rms);
515 median_rms_vec.push_back(median_rms);
516 logger->info("found {} [{}]", filename, extName);
517 }
518 }
519 }
520 }
521 }
522
523 } catch (const fs::filesystem_error& err) {
524 logger->error("{}", err.what());
525 std::exit(EXIT_FAILURE);
526 }
527 }
528
529 // check if we found any maps
530 if (tod_mb.signal.empty() || tod_mb.weight.empty()) {
531 logger->error("no signal maps found in {}", filepath);
532 std::exit(EXIT_FAILURE);
533 }
534
535 if (!median_rms_vec.empty()) {
536 // map median rms from fits files vector to map buffer vector
537 tod_mb.median_rms = Eigen::Map<Eigen::VectorXd>(median_rms_vec.data(),median_rms_vec.size());
538 }
539
540 // set dimensions
543
544 // get pixel size in radians
545 if (tod_mb.wcs.cunit[0] == "deg") {
547 }
548 else if (tod_mb.wcs.cunit[0] == "arcsec") {
550 }
551
552 Eigen::MatrixXd ones, zeros;
553 ones.setOnes(tod_mb.weight[0].rows(), tod_mb.weight[0].cols());
554 zeros.setZero(tod_mb.weight[0].rows(), tod_mb.weight[0].cols());
555
556 // calculate coverage bool map
557 for (int i=0; i<tod_mb.weight.size(); ++i) {
558 // get weight threshold for current map
559 auto [weight_threshold, cov_ranges, cov_n_rows, cov_n_cols] = tod_mb.calc_cov_region(i);
560 // if weight is less than threshold, set to zero, otherwise set to one
561 auto cov_bool = (tod_mb.weight[i].array() < weight_threshold).select(zeros,ones);
562 tod_mb.signal[i] = tod_mb.signal[i].array() * cov_bool.array();
563 if (!tod_mb.kernel.empty()) {
564 tod_mb.kernel[i] = tod_mb.kernel[i].array() * cov_bool.array();
565 }
566 }
567 // clear weight maps to save memory
568 std::vector<Eigen::MatrixXd>().swap(tod_mb.weight);
569}
570
571template <class calib_t>
572auto TCProc::get_grouping(std::string grp, calib_t &calib, int n_dets) {
573 std::map<Eigen::Index, std::tuple<Eigen::Index, Eigen::Index>> grp_limits;
574
575 // initial group value is value for the first det index
576 Eigen::Index grp_i = calib.apt[grp](0);
577 // set up first group
578 grp_limits[grp_i] = std::tuple<Eigen::Index, Eigen::Index>{0, 0};
579 Eigen::Index j = 0;
580 // loop through apt table arrays, get highest index for current array
581 for (Eigen::Index i=0; i<n_dets; ++i) {
582 auto det_index = i;
583 // if we're still on the current group
584 if (calib.apt[grp](det_index) == grp_i) {
585 std::get<1>(grp_limits[grp_i]) = i + 1;
586 }
587 // otherwise increment and start the next group
588 else {
589 grp_i = calib.apt[grp](det_index);
590 j += 1;
591 grp_limits[grp_i] = std::tuple<Eigen::Index, Eigen::Index>{i,0};
592 }
593 }
594 return grp_limits;
595}
596
597// compute pointing for all detectors
598template <TCDataKind tcdata_t, class calib_t>
599void TCProc::precompute_pointing(TCData<tcdata_t, Eigen::MatrixXd> &in, calib_t &calib, std::string pixel_axes, std::string map_grouping) {
600
601 // dimensions of data
602 Eigen::Index n_dets = in.scans.data.cols();
603 Eigen::Index n_pts = in.scans.data.rows();
604
605 in.pointing.data["lat"].resize(n_pts,n_dets);
606 in.pointing.data["lon"].resize(n_pts,n_dets);
607
608 for (Eigen::Index i=0; i<n_dets; ++i) {
609 // current detector index in apt
610 auto det_index = i;
611 double az_off = calib.apt["x_t"](det_index);
612 double el_off = calib.apt["y_t"](det_index);
613
614 // get detector pointing
615 auto [lat, lon] = engine_utils::calc_det_pointing(in.tel_data.data, az_off, el_off, pixel_axes,
616 in.pointing_offsets_arcsec.data, map_grouping);
617
618 in.pointing.data["lat"].col(i) = std::move(lat);
619 in.pointing.data["lon"].col(i) = std::move(lon);
620 }
621}
622
623template <TCProc::SourceType source_type, class mb_t, TCDataKind tcdata_t, class calib_t, typename Derived>
624void TCProc::map_to_tod(mb_t &mb, TCData<tcdata_t, Eigen::MatrixXd> &in, calib_t &calib,
625 Eigen::DenseBase<Derived> &map_indices, std::string pixel_axes,
626 std::string map_grouping) {
627
628 // dimensions of data
629 Eigen::Index n_dets = in.scans.data.cols();
630 Eigen::Index n_pts = in.scans.data.rows();
631
632 // add or subtract timestream
633 int factor = 1;
634 if constexpr (source_type==NegativeMap) {
635 factor = -1;
636 }
637
638 // run kernel through fruit loops
639 bool run_kernel = in.kernel.data.size() !=0;
640 // if mean rms is filled use S/N limit
641 bool run_noise = mb.median_rms.size() != 0;
642
643 // loop through detectors
644 for (Eigen::Index i=0; i<n_dets; ++i) {
645 // current detector index in apt
646 auto map_index = map_indices(i);
647 int array_index = calib.apt["array"](i);
648
649 // check if detector is not flagged
650 if (calib.apt["flag"](i) == 0 && (in.flags.data.col(i).array() == 0).any()) {
651 double az_off = calib.apt["x_t"](i);
652 double el_off = calib.apt["y_t"](i);
653
654 // calc tangent plane pointing
655 auto [lat, lon] = engine_utils::calc_det_pointing(in.tel_data.data, az_off, el_off, pixel_axes,
656 in.pointing_offsets_arcsec.data, map_grouping);
657
658 // get map buffer row and col indices for lat and lon vectors
659 Eigen::VectorXd irows = lat.array()/mb.pixel_size_rad + (mb.n_rows)/2.;
660 Eigen::VectorXd icols = lon.array()/mb.pixel_size_rad + (mb.n_cols)/2.;
661
662 // loop through data points
663 for (Eigen::Index j=0; j<n_pts; ++j) {
664 // row and col pixel from signal image
665 Eigen::Index ir = irows(j);
666 Eigen::Index ic = icols(j);
667
668 // check if current sample is on the image and add to the timestream
669 if ((ir >= 0) && (ir < mb.n_rows) && (ic >= 0) && (ic < mb.n_cols)) {
670 double signal = mb.signal[map_index](ir,ic);
671 // check whether we should include pixel
672 bool run_pix_s2n = false;
673 bool run_pix_flux = false;
674 if (fruit_mode == "upper") {
675 run_pix_s2n = run_noise && (signal / mb.median_rms(map_index) >= fruit_loops_sig2noise);
676 run_pix_flux = signal >= fruit_loops_flux(array_index);
677 }
678 else if (fruit_mode == "lower") {
679 run_pix_s2n = run_noise && (signal / mb.median_rms(map_index) <= fruit_loops_sig2noise);
680 run_pix_flux = signal <= fruit_loops_flux(array_index);
681 }
682 else if (fruit_mode == "both") {
683 run_pix_s2n = run_noise && (abs(signal / mb.median_rms(map_index)) >= abs(fruit_loops_sig2noise));
684 run_pix_flux = abs(signal) >= abs(fruit_loops_flux(array_index));
685 }
686
687 // if signal flux is higher than S/N limit or flux limit
688 if (run_pix_s2n || run_pix_flux) {
689 // add/subtract signal pixel from signal timestream
690 in.scans.data(j,i) += factor * signal;
691 // add/subtract kernel pixel from kernel timestream
692 if (run_kernel) {
693 in.kernel.data(j,i) += factor * mb.kernel[map_index](ir,ic);
694 }
695 }
696 }
697 }
698 }
699 }
700}
701
702template <TCDataKind tcdata_t, class calib_t>
703auto TCProc::remove_bad_dets(TCData<tcdata_t, Eigen::MatrixXd> &in, calib_t &calib, std::string map_grouping) {
704
705 // make a copy of the calib class for flagging
706 calib_t calib_scan = calib;
707
708 // only run if limits are not zero
710 logger->info("removing outlier dets");
711 // number of detectors
712 Eigen::Index n_dets = in.scans.data.cols();
713
714 // get grouping
715 auto grp_limits = get_grouping("array", calib, n_dets);
716
717 in.n_dets_low = 0;
718 in.n_dets_high = 0;
719
720 // loop through group limits
721 for (auto const& [key, val] : grp_limits) {
722 // control for iteration
723 bool keep_going = true;
724 Eigen::Index n_iter = 0;
725
726 while (keep_going) {
727 // number of unflagged detectors
728 Eigen::Index n_good_dets = 0;
729
730 // get good dets in group
731 for (Eigen::Index j=std::get<0>(grp_limits[key]); j<std::get<1>(grp_limits[key]); ++j) {
732 if (calib.apt["flag"](j)==0 && (in.flags.data.col(j).array()==0).any()) {
733 n_good_dets++;
734 }
735 }
736
737 Eigen::VectorXd det_std_dev(n_good_dets);
738 Eigen::VectorXI dets(n_good_dets);
739 Eigen::Index k = 0;
740
741 // collect standard deviation from good detectors
742 for (Eigen::Index j=std::get<0>(grp_limits[key]); j<std::get<1>(grp_limits[key]); ++j) {
743 Eigen::Index det_index = j;
744 if (calib.apt["flag"](det_index)==0 && (in.flags.data.col(j).array()==0).any()) {
745 // make Eigen::Maps for each detector's scan
746 Eigen::Map<Eigen::Matrix<double, Eigen::Dynamic, 1>> scans(
747 in.scans.data.col(j).data(), in.scans.data.rows());
748 Eigen::Map<Eigen::Matrix<bool, Eigen::Dynamic, 1>> flags(
749 in.flags.data.col(j).data(), in.flags.data.rows());
750
751 // calc standard deviation
752 det_std_dev(k) = engine_utils::calc_std_dev(scans, flags);
753
754 // convert to 1/variance so it is a weight
755 if (det_std_dev(k) !=0) {
756 det_std_dev(k) = std::pow(det_std_dev(k),-2);
757 }
758 else {
759 det_std_dev(k) = 0;
760 }
761
762 dets(k) = j;
763 k++;
764 }
765 }
766
767 // get median standard deviation
768 double median_std_dev = tula::alg::median(det_std_dev);
769
770 int n_dets_low = 0;
771 int n_dets_high = 0;
772
773 // loop through good detectors and flag those that have std devs beyond the limits
774 for (Eigen::Index j=0; j<n_good_dets; ++j) {
775 Eigen::Index det_index = dets(j);
776 // only run if unflagged already
777 if (calib.apt["flag"](det_index)==0) {
778 // flag those below limit
779 if ((det_std_dev(j) < (lower_inv_var_factor*median_std_dev)) && lower_inv_var_factor!=0) {
780 if (map_grouping!="detector") {
781 in.flags.data.col(dets(j)).setOnes();
782 }
783 else {
784 calib_scan.apt["flag"](det_index) = 1;
785 }
786 in.n_dets_low++;
787 n_dets_low++;
788 }
789
790 // flag those above limit
791 if ((det_std_dev(j) > (upper_inv_var_factor*median_std_dev)) && upper_inv_var_factor!=0) {
792 if (map_grouping!="detector") {
793 in.flags.data.col(dets(j)).setOnes();
794 }
795 else {
796 calib_scan.apt["flag"](det_index) = 1;
797 }
798 in.n_dets_high++;
799 n_dets_high++;
800 }
801 }
802 }
803
804 logger->info("array {} iter {}: {}/{} dets below inv var limit. {}/{} dets above inv var limit.", key, n_iter,
805 n_dets_low, n_good_dets, n_dets_high, n_good_dets);
806
807 // increment iteration
808 n_iter++;
809 // check if no more detectors are above limit
810 if ((n_dets_low==0 && n_dets_high==0) || n_iter > iter_lim) {
811 keep_going = false;
812 }
813 }
814 }
815 // set up scan calib
816 calib_scan.setup();
817 }
818
819 return std::move(calib_scan);
820}
821
822template <TCDataKind tcdata_t, class calib_t, typename Derived>
823auto TCProc::remove_uncorrelated(TCData<tcdata_t, Eigen::MatrixXd> &in, calib_t &calib, std::string map_grouping) {
824 //Eigen::Index n_dets = in.scans.data.cols();
825 //Eigen::Index n_pts = in.scans.data.rows();
826
827 // make copy of flags
828 //Eigen::MatrixXd f = abs(flags.derived().template cast<double> ().array() - 1);
829
830 // container for covariance matrix
831 //Eigen::MatrixXd pca_cov(n_dets, n_dets);
832
833 // calculate the covariance matrix
834 //pca_cov.noalias() = ((scans.adjoint() * scans).array()).matrix();// / denom.array()).matrix();
835}
836
837template <TCProc::SourceType source_type, TCDataKind tcdata_t, typename Derived, typename apt_t>
838void TCProc::add_gaussian(TCData<tcdata_t, Eigen::MatrixXd> &in, Eigen::DenseBase<Derived> &params, std::string &pixel_axes,
839 std::string &map_grouping, apt_t &apt, double pixel_size_rad, Eigen::Index n_rows, Eigen::Index n_cols) {
840
841 Eigen::Index n_dets = in.scans.data.cols();
842 Eigen::Index n_pts = in.scans.data.rows();
843
844 // loop through detectors
845 for (Eigen::Index i=0; i<n_dets; ++i) {
846 // detector index in apt
847 auto det_index = i;
848 // map index
849 auto map_index = in.map_indices.data(i);
850
851 double az_off = apt["x_t"](det_index);
852 double el_off = apt["y_t"](det_index);
853
854 // get pointing
855 auto [lat, lon] = engine_utils::calc_det_pointing(in.tel_data.data, az_off, el_off, pixel_axes,
856 in.pointing_offsets_arcsec.data, map_grouping);
857
858 // get parameters from current map
859 double amp = params(map_index,0);
860 // rows
861 double off_lat = params(map_index,2);
862 // cols
863 double off_lon = params(map_index,1);
864 // row fwhm
865 double sigma_lat = params(map_index,4);
866 // col fwhm
867 double sigma_lon = params(map_index,3);
868 // rot angle
869 double rot_ang = params(map_index,5);
870
871 // use maximum of sigmas due to atmospheric cleaning
872 double sigma = std::max(sigma_lat, sigma_lon);
873
874 // subtract source
875 if constexpr (source_type==NegativeGaussian) {
876 amp = -amp;
877 }
878
879 // rescale offsets and stddev to on-sky units
880 off_lat = pixel_size_rad*(off_lat - (n_rows)/2);
881 off_lon = pixel_size_rad*(off_lon - (n_cols)/2);
882
883 // convert to on-sky units
884 sigma_lon = pixel_size_rad*sigma;
885 sigma_lat = pixel_size_rad*sigma;
886 sigma = pixel_size_rad*sigma;
887
888 // get 2d elliptical gaussian angles
889 auto cost2 = cos(rot_ang) * cos(rot_ang);
890 auto sint2 = sin(rot_ang) * sin(rot_ang);
891 auto sin2t = sin(2. * rot_ang);
892 auto xstd2 = sigma * sigma;
893 auto ystd2 = sigma * sigma;
894 auto a = - 0.5 * ((cost2 / xstd2) + (sint2 / ystd2));
895 auto b = - 0.5 * ((sin2t / xstd2) - (sin2t / ystd2));
896 auto c = - 0.5 * ((sint2 / xstd2) + (cost2 / ystd2));
897
898 // calculate distance to source to truncate it
899 //auto dist = ((lat.array() - off_lat).pow(2) + (lon.array() - off_lon).pow(2)).sqrt();
900
901 Eigen::VectorXd gauss(n_pts);
902 // make timestream from 2d gaussian
903 for (Eigen::Index j=0; j<n_pts; ++j) {
904 gauss(j) = amp*exp(pow(lon(j) - off_lon, 2) * a +
905 (lon(j) - off_lon) * (lat(j) - off_lat) * b +
906 pow(lat(j) - off_lat, 2) * c);
907 }
908
909 // check for bad fit?
910 if (!gauss.array().isNaN().any()) {
911 // add gaussian to detector scan
912 in.scans.data.col(i) = in.scans.data.col(i).array() + gauss.array();
913 }
914 }
915}
916
917template <TCDataKind tcdata_t, class calib_t>
918auto TCProc::mask_region(TCData<tcdata_t, Eigen::MatrixXd> &in, calib_t &calib, std::string pixel_axes, std::string map_grouping,
919 int n_pts, int n_dets, int start_index) {
920
921 // copy of tel data
922 std::map<std::string, Eigen::VectorXd> tel_data_copy;
923
924 // populate copy of tel data
925 for (const auto &[key,val]: in.tel_data.data) {
926 tel_data_copy[key] = in.tel_data.data[key].segment(0,n_pts);
927 }
928
929 // copy of pointing offsets
930 std::map<std::string, Eigen::VectorXd> pointing_offset_copy;
931
932 // populate copy of pointing offsets
933 for (const auto &[key,val]: in.pointing_offsets_arcsec.data) {
934 pointing_offset_copy[key] = in.pointing_offsets_arcsec.data[key].segment(0,n_pts);
935 }
936
937 // make a copy of the timestream flags
938 Eigen::Matrix<bool, Eigen::Dynamic, Eigen::Dynamic> masked_flags = in.flags.data.block(0, start_index, n_pts, n_dets);
939
940 // loop through detectors
941 for (Eigen::Index i=0; i<n_dets; ++i) {
942 // current detector index in apt
943 auto det_index = i + start_index;
944
945 double az_off = calib.apt["x_t"](det_index);
946 double el_off = calib.apt["y_t"](det_index);
947
948 // calc tangent plane pointing
949 auto [lat, lon] = engine_utils::calc_det_pointing(tel_data_copy, az_off, el_off, pixel_axes,
950 pointing_offset_copy, map_grouping);
951
952 // distance to center of map
953 auto dist = (lat.array().pow(2) + lon.array().pow(2)).sqrt();
954
955 // loop through samples
956 for (Eigen::Index j=0; j<n_pts; ++j) {
957 // flag samples within radius as bad
958 if (dist(j) < mask_radius_arcsec*ASEC_TO_RAD) {
959 masked_flags(j,i) = 1;
960 }
961 }
962 }
963
964 return std::move(masked_flags);
965}
966
967template <TCDataKind tcdata_t, class calib_t, typename pointing_offset_t>
968void TCProc::append_base_to_netcdf(netCDF::NcFile &fo, TCData<tcdata_t, Eigen::MatrixXd> &in, std::string map_grouping,
969 std::string &pixel_axes, pointing_offset_t &pointing_offsets_arcsec, calib_t &calib) {
970 using netCDF::NcDim;
971 using netCDF::NcFile;
972 using netCDF::NcType;
973 using netCDF::NcVar;
974 using namespace netCDF::exceptions;
975
976 Eigen::Index n_pts = in.scans.data.rows();
977 Eigen::Index n_dets = in.scans.data.cols();
978
979 // tangent plane pointing for each detector
980 Eigen::MatrixXd lat(n_pts,n_dets), lon(n_pts,n_dets);
981
982 // loop through detectors and get tangent plane pointing
983 for (Eigen::Index i=0; i<n_dets; ++i) {
984 // detector index in apt
985 auto det_index = i;
986 double az_off = calib.apt["x_t"](det_index);
987 double el_off = calib.apt["y_t"](det_index);
988
989 // get tangent pointing
990 auto [det_lat, det_lon] = engine_utils::calc_det_pointing(in.tel_data.data, az_off, el_off, pixel_axes,
991 pointing_offsets_arcsec, map_grouping);
992 lat.col(i) = std::move(det_lat);
993 lon.col(i) = std::move(det_lon);
994 }
995
996 // get variables
997 auto vars = fo.getVars();
998
999 // get absolute coords
1000 double cra, cdec;
1001 vars.find("SourceRa")->second.getVar(&cra);
1002 vars.find("SourceDec")->second.getVar(&cdec);
1003
1004 // get dimensions
1005 NcDim n_pts_dim = fo.getDim("n_pts");
1006 NcDim n_dets_dim = fo.getDim("n_dets");
1007
1008 // number of samples currently in file
1009 unsigned long n_pts_exists = n_pts_dim.getSize();
1010 // number of detectors currently in file
1011 unsigned long n_dets_exists = n_dets_dim.getSize();
1012
1013 // start indices for data
1014 std::vector<std::size_t> start_index = {n_pts_exists, 0};
1015 // size for data
1016 std::vector<std::size_t> size = {1, TULA_SIZET(n_dets)};
1017
1018 // start index for telescope data
1019 std::vector<std::size_t> start_index_tel = {n_pts_exists};
1020 // size for telescope data
1021 std::vector<std::size_t> size_tel = {TULA_SIZET(n_pts)};
1022
1023 // start index for apt table
1024 std::vector<std::size_t> start_index_apt = {0};
1025 // size for apt
1026 std::vector<std::size_t> size_apt = {1};
1027
1028 // get timestream variables
1029 NcVar signal_v = fo.getVar("signal");
1030 NcVar flags_v = fo.getVar("flags");
1031 NcVar kernel_v = fo.getVar("kernel");
1032
1033 // detector tangent plane pointing
1034 NcVar det_lat_v = fo.getVar("det_lat");
1035 NcVar det_lon_v = fo.getVar("det_lon");
1036
1037 // detector absolute pointing
1038 NcVar det_ra_v = fo.getVar("det_ra");
1039 NcVar det_dec_v = fo.getVar("det_dec");
1040
1041 // append data (doing this per row is way faster than transposing
1042 // and populating them at once)
1043 for (std::size_t i=0; i<TULA_SIZET(n_pts); ++i) {
1044 start_index[0] = n_pts_exists + i;
1045 // append scans
1046 Eigen::VectorXd scans = in.scans.data.row(i);
1047 signal_v.putVar(start_index, size, scans.data());
1048
1049 // append flags
1050 Eigen::VectorXi flags_int = in.flags.data.row(i).template cast<int> ();
1051 flags_v.putVar(start_index, size, flags_int.data());
1052
1053 // append kernel
1054 if (!kernel_v.isNull()) {
1055 Eigen::VectorXd kernel = in.kernel.data.row(i);
1056 kernel_v.putVar(start_index, size, kernel.data());
1057 }
1058
1059 // append detector latitudes
1060 Eigen::VectorXd lat_row = lat.row(i);
1061 det_lat_v.putVar(start_index, size, lat_row.data());
1062
1063 // append detector longitudes
1064 Eigen::VectorXd lon_row = lon.row(i);
1065 det_lon_v.putVar(start_index, size, lon_row.data());
1066
1067 if (pixel_axes == "radec") {
1068 // get absolute pointing
1069 auto [dec, ra] = engine_utils::tangent_to_abs(lat_row, lon_row, cra, cdec);
1070
1071 // append detector ra
1072 det_ra_v.putVar(start_index, size, ra.data());
1073
1074 // append detector dec
1075 det_dec_v.putVar(start_index, size, dec.data());
1076 }
1077 }
1078
1079 // append telescope
1080 for (auto const& x: in.tel_data.data) {
1081 NcVar tel_data_v = fo.getVar(x.first);
1082 tel_data_v.putVar(start_index_tel, size_tel, x.second.data());
1083 }
1084
1085 // append pointing offsets
1086 for (auto const& x: in.pointing_offsets_arcsec.data) {
1087 NcVar offset_v = fo.getVar("pointing_offset_"+x.first);
1088 offset_v.putVar(start_index_tel, size_tel, x.second.data());
1089 }
1090
1091 // append hwpr angle
1092 if (calib.run_hwpr) {
1093 NcVar hwpr_v = fo.getVar("hwpr");
1094 hwpr_v.putVar(start_index_tel, size_tel, in.hwpr_angle.data.data());
1095 }
1096
1097
1098 // overwrite apt table (can be updated between beammap iterations)
1099 for (auto const& x: calib.apt) {
1100 netCDF::NcVar apt_v = fo.getVar("apt_" + x.first);
1101 if (!apt_v.isNull()) {
1102 for (std::size_t i=0; i<TULA_SIZET(n_dets_exists); ++i) {
1103 start_index_apt[0] = i;
1104 apt_v.putVar(start_index_apt, size_apt, &calib.apt[x.first](i));
1105 }
1106 }
1107 }
1108
1109 // vector to hold current scan indices
1110 Eigen::VectorXd scan_indices(2);
1111
1112 // if not on first scan, grab last scan and add size of current scan
1113 if (in.index.data > 0) {
1114 // start indices for data
1115 std::vector<std::size_t> scan_indices_start_index = {TULA_SIZET(in.index.data-1), 0};
1116 // size for data
1117 std::vector<std::size_t> scan_indices_size = {1, 2};
1118 vars.find("scan_indices")->second.getVar(scan_indices_start_index,scan_indices_size,scan_indices.data());
1119
1120 scan_indices = scan_indices.array() + in.scans.data.rows();
1121 }
1122
1123 // otherwise, use size of this scan
1124 else {
1125 scan_indices(0) = 0;
1126 scan_indices(1) = in.scans.data.rows() - 1;
1127 }
1128
1129 // add current scan indices row
1130 std::vector<std::size_t> scan_indices_start_index = {TULA_SIZET(in.index.data), 0};
1131 std::vector<std::size_t> scan_indices_size = {1, 2};
1132 NcVar scan_indices_v = fo.getVar("scan_indices");
1133 scan_indices_v.putVar(scan_indices_start_index, scan_indices_size,scan_indices.data());
1134}
1135} // namespace timestream
Definition toltec_io.h:10
std::map< Eigen::Index, std::string > array_name_map
Definition toltec_io.h:54
Definition fits_io.h:10
auto get_hdu(std::string hdu_name)
Definition fits_io.h:82
std::unique_ptr< CCfits::FITS > pfits
Definition fits_io.h:19
Definition map.h:45
WCS wcs
Definition map.h:48
std::tuple< double, Eigen::MatrixXd, Eigen::Index, Eigen::Index > calc_cov_region(Eigen::Index)
Definition map.cpp:253
Eigen::Index n_rows
Definition map.h:65
Eigen::Index n_cols
Definition map.h:65
std::vector< Eigen::MatrixXd > signal
Definition map.h:78
std::vector< Eigen::MatrixXd > weight
Definition map.h:78
std::vector< Eigen::MatrixXd > kernel
Definition map.h:78
Eigen::Index n_noise
Definition map.h:67
Eigen::VectorXd median_rms
Definition map.h:117
std::vector< Eigen::Tensor< double, 3 > > noise
Definition map.h:81
double pixel_size_rad
Definition map.h:69
Definition timestream.h:257
auto mask_region(TCData< tcdata_t, Eigen::MatrixXd > &, calib_t &, std::string, std::string, int, int, int)
Definition timestream.h:918
auto get_grouping(std::string, calib_t &, int)
Definition timestream.h:572
std::string fruit_loops_path
Definition timestream.h:281
std::shared_ptr< spdlog::logger > logger
Definition timestream.h:260
double upper_inv_var_factor
Definition timestream.h:302
double fruit_loops_sig2noise
Definition timestream.h:289
bool save_all_iters
Definition timestream.h:293
double mask_radius_arcsec
Definition timestream.h:305
bool run_tod_output
Definition timestream.h:276
void append_base_to_netcdf(netCDF::NcFile &, TCData< tcdata_t, Eigen::MatrixXd > &, std::string, std::string &, pointing_offset_t &, calib_t &)
Definition timestream.h:968
std::vector< std::string > init_fruit_loops_path
Definition timestream.h:283
void map_to_tod(mb_t &, TCData< tcdata_t, Eigen::MatrixXd > &, calib_t &, Eigen::DenseBase< Derived > &, std::string, std::string)
Definition timestream.h:624
bool write_evals
Definition timestream.h:276
int iter_lim
Definition timestream.h:299
auto remove_uncorrelated(TCData< tcdata_t, Eigen::MatrixXd > &, calib_t &, std::string)
Definition timestream.h:823
engine_utils::toltecIO toltec_io
Definition timestream.h:263
void precompute_pointing(TCData< tcdata_t, Eigen::MatrixXd > &, calib_t &, std::string, std::string)
Definition timestream.h:599
auto remove_bad_dets(TCData< tcdata_t, Eigen::MatrixXd > &, calib_t &, std::string)
Definition timestream.h:703
int fruit_loops_iters
Definition timestream.h:287
SourceType
Definition timestream.h:266
@ NegativeGaussian
Definition timestream.h:268
@ NegativeMap
Definition timestream.h:272
@ Map
Definition timestream.h:271
@ NegativeAiry
Definition timestream.h:270
@ Airy
Definition timestream.h:269
@ Gaussian
Definition timestream.h:267
void load_mb(std::string, std::string, calib_t &)
Definition timestream.h:347
bool run_fruit_loops
Definition timestream.h:279
std::string fruit_mode
Definition timestream.h:285
mapmaking::MapBuffer tod_mb
Definition timestream.h:296
Eigen::VectorXd fruit_loops_flux
Definition timestream.h:291
double lower_inv_var_factor
Definition timestream.h:302
void add_gaussian(TCData< tcdata_t, Eigen::MatrixXd > &, Eigen::DenseBase< Derived > &, std::string &, std::string &, apt_t &, double, Eigen::Index, Eigen::Index)
Definition timestream.h:838
std::string fruit_loops_type
Definition timestream.h:285
#define DEG_TO_RAD
Definition constants.h:27
#define ASEC_TO_RAD
Definition constants.h:33
auto calc_det_pointing(tel_data_t &tel_data, double az_off, double el_off, const std::string pixel_axes, pointing_offset_t &pointing_offsets, const std::string map_grouping)
Definition pointing.h:11
auto tangent_to_abs(Eigen::DenseBase< Derived > &lat, Eigen::DenseBase< Derived > &lon, const double cra, const double cdec)
Definition pointing.h:88
static const std::string current_date_time()
Definition utils.h:91
auto calc_std_dev(Eigen::DenseBase< DerivedA > &data)
Definition utils.h:336
Definition sensitivity.h:13
Definition timestream.h:59
Definition clean.h:10
TimestreamFlags
Definition timestream.h:26
@ D21LargeOffset
Definition timestream.h:29
@ D21NotConverged
Definition timestream.h:30
@ D21QrOutOfRange
Definition timestream.h:32
@ QrOutOfRange
Definition timestream.h:36
@ Good
Definition timestream.h:27
@ D21FitsBetter
Definition timestream.h:28
@ NotConverged
Definition timestream.h:34
@ APT
Definition timestream.h:38
@ D21OutOfRange
Definition timestream.h:31
@ Freq
Definition timestream.h:40
@ Spike
Definition timestream.h:39
@ LargeOffset
Definition timestream.h:33
@ LowGain
Definition timestream.h:37
@ OutOfRange
Definition timestream.h:35
TULA_BITFLAG(TCDataKind, int, 0xFFFF, RTC=1<< 0, PTC=1<< 1, Any=RTC|PTC)
std::vector< float > cdelt
Definition map.h:27
std::vector< std::string > cunit
Definition map.h:39
std::vector< float > crpix
Definition map.h:33
std::vector< int > naxis
Definition map.h:30
std::vector< float > crval
Definition map.h:36
Definition timestream.h:130
DetectorAxis(Eigen::MatrixXd data_, tula::nddata::LabelMapper< DetectorAxis > row_labels_)
Definition timestream.h:132
tula::nddata::LabelMapper< DetectorAxis > row_labels
Definition timestream.h:136
Eigen::MatrixXd data
Definition timestream.h:135
std::string_view name
Definition timestream.h:134
Definition timestream.h:117
bool kernel_generated
Definition timestream.h:119
bool downsampled
Definition timestream.h:122
bool tod_filtered
Definition timestream.h:121
bool cleaned
Definition timestream.h:125
bool calibrated
Definition timestream.h:123
bool demodulated
Definition timestream.h:118
bool extinction_corrected
Definition timestream.h:124
bool despiked
Definition timestream.h:120
std::conditional_t< tula::eigen_utils::is_plain_v< RefType >, Base::data_t< RefType >, Base::dataref_t< RefType > > data_t
Definition timestream.h:230
Base::data_t< std::vector< double > > median_weights
Definition timestream.h:242
data_t scans
Definition timestream.h:234
Base::data_t< Eigen::VectorXd > weights
Definition timestream.h:236
Base::data_t< std::vector< std::vector< Eigen::MatrixXd > > > evecs
Definition timestream.h:240
Base::data_t< std::vector< std::vector< Eigen::VectorXd > > > evals
Definition timestream.h:238
data_t scans
Definition timestream.h:222
std::conditional_t< tula::eigen_utils::is_plain_v< RefType >, Base::data_t< RefType >, Base::dataref_t< RefType > > data_t
Definition timestream.h:218
tula::enum_utils::enum_to_variant_t< kind_, TCData > variant_t
Definition timestream.h:250
tula::enum_utils::enum_to_variant_t< kind_, TCData > Base
Definition timestream.h:249
TC data class.
Definition timestream.h:55
Definition timestream.h:140
std::string_view name
Definition timestream.h:144
Eigen::MatrixXd data
Definition timestream.h:145
tula::nddata::LabelMapper< TimeAxis > col_labels
Definition timestream.h:146
TimeAxis(Eigen::MatrixXd data_, tula::nddata::LabelMapper< TimeAxis > col_labels_)
Definition timestream.h:142
Definition timestream.h:149
TimeAxis time_axis
Definition timestream.h:150
const TimeAxis & row_axis() const
Definition timestream.h:154
DetectorAxis detector_axis
Definition timestream.h:151
const DetectorAxis & col_axis() const
Definition timestream.h:155
Definition timestream.h:172
PlainObject data
Definition timestream.h:173
Definition timestream.h:167
PlainObject data
Definition timestream.h:168
base class for time stream data
Definition timestream.h:163
Status status
Definition timestream.h:183
data_t< std::map< std::string, Eigen::VectorXd > > tel_data
Definition timestream.h:198
TimeStreamFrame wcs
Definition timestream.h:164
data_t< Eigen::VectorXd > angle
Definition timestream.h:204
data_t< std::map< std::string, Eigen::MatrixXd > > pointing
Definition timestream.h:210
int n_dets_high
Definition timestream.h:180
data_t< std::map< std::string, Eigen::VectorXd > > pointing_offsets_arcsec
Definition timestream.h:200
data_t< Eigen::VectorXI > map_indices
Definition timestream.h:208
data_t< Eigen::MatrixXi > noise
Definition timestream.h:190
data_t< Eigen::Matrix< TimestreamFlags, Eigen::Dynamic, Eigen::Dynamic > > flags2
Definition timestream.h:192
data_t< Eigen::Index > index
Definition timestream.h:196
std::string creation_time
Definition timestream.h:177
data_t< Eigen::MatrixXd > kernel
Definition timestream.h:186
data_t< Eigen::VectorXd > hwpr_angle
Definition timestream.h:202
int n_dets_low
Definition timestream.h:180
data_t< Eigen::Matrix< Eigen::Index, Eigen::Dynamic, 1 > > scan_indices
Definition timestream.h:194
data_t< Eigen::VectorXd > fcf
Definition timestream.h:206
data_t< Eigen::Matrix< bool, Eigen::Dynamic, Eigen::Dynamic > > flags
Definition timestream.h:188
static constexpr auto kind()
Definition timestream.h:109
Definition timestream.h:105