SourceXtractorPlusPlus 1.0.3
SourceXtractor++, the next generation SExtractor
Loading...
Searching...
No Matches
VariablePsfStack.cpp
Go to the documentation of this file.
1
17/*
18 * VariablePsfStack.cpp
19 *
20 * Created on: July 10, 2019
21 * Author: Martin Kuemmel
22 */
23#include <algorithm>
24#include <ElementsKernel/Logging.h>
25#include <ElementsKernel/Exception.h>
27
28static auto stack_logger = Elements::Logging::getLogger("VarStackPsf");
29
30namespace SourceXtractor {
31
33 try {
34 // basic check: load the primary HDU
35 CCfits::PHDU& phdu = pFits->pHDU();
36 if (phdu.axes() != 0) {
37 throw Elements::Exception() << "The primary HDU is not empty! File: " << pFits->name();
38 }
39
40 // basic check: load the first extension
41 CCfits::ExtHDU& psf_data = pFits->extension(1);
42 if (psf_data.axes() != 2) {
43 throw Elements::Exception() << "The first HDU is not an image! File: " << pFits->name();
44 }
45
46 // basic check: load the second extension
47 CCfits::ExtHDU& position_data = pFits->extension(2);
48 if (position_data.axes() != 2) {
49 throw Elements::Exception() << "The second HDU has not the right dimension! File: " << pFits->name();
50 }
51
52 // give some feedback
53 stack_logger.debug() << "Checked the file: " << pFits->name();
54
55 // get and store the stamp size;
56 // define the offset from GRIDX and GRIDY
57 psf_data.readKey("STMPSIZE", m_psf_size);
58 m_grid_offset = m_psf_size / 2; // this is for CCfits where indices start with 1!
59
60 // make sure the PSF size is odd
61 if (m_psf_size % 2 == 0) {
62 throw Elements::Exception() << "PSF kernel must have odd size, but has: " << m_psf_size;
63 }
64
65 try {
66 // try to get the sampling
67 psf_data.readKey("SAMPLING", mm_pixel_sampling);
68 } catch (CCfits::HDU::NoSuchKeyword&) {
69 // use a default value
71 }
72
73 // read the nrows value
74 m_nrows = position_data.rows();
75
76 try {
77 // read in all the EXT specific columns
78 position_data.column("GRIDX", false).read(m_gridx_values, 0, m_nrows);
79 position_data.column("GRIDY", false).read(m_gridy_values, 0, m_nrows);
80 } catch (CCfits::Table::NoSuchColumn) {
81 position_data.column("X_CENTER", false).read(m_gridx_values, 0, m_nrows);
82 position_data.column("Y_CENTER", false).read(m_gridy_values, 0, m_nrows);
83 }
84 position_data.column("RA", false).read(m_ra_values, 0, m_nrows);
85 position_data.column("DEC", false).read(m_dec_values, 0, m_nrows);
86 position_data.column("X", false).read(m_x_values, 0, m_nrows);
87 position_data.column("Y", false).read(m_y_values, 0, m_nrows);
88
89 } catch (CCfits::FitsException& e) {
90 throw Elements::Exception() << "Error loading stacked PSF file: " << e.message();
91 }
92}
93
95 int naxis1, naxis2;
96
97 // read in the min/max grid values in x/y
98 const auto x_grid_minmax = std::minmax_element(begin(m_gridx_values), end(m_gridx_values));
99 const auto y_grid_minmax = std::minmax_element(begin(m_gridy_values), end(m_gridy_values));
100
101 // read the image size
102 m_pFits->extension(1).readKey("NAXIS1", naxis1);
103 m_pFits->extension(1).readKey("NAXIS2", naxis2);
104
105 // make sure all PSF in the grid are there
106 if (*x_grid_minmax.first - m_grid_offset < 1)
107 throw Elements::Exception() << "The PSF at the smallest x-grid starts at: " << *x_grid_minmax.first - m_grid_offset;
108 if (*y_grid_minmax.first - m_grid_offset < 1)
109 throw Elements::Exception() << "The PSF at the smallest y-grid starts at: " << *y_grid_minmax.first - m_grid_offset;
110 if (*x_grid_minmax.second + m_grid_offset > naxis1)
111 throw Elements::Exception() << "The PSF at the largest x-grid is too large: " << *x_grid_minmax.second + m_grid_offset
112 << " NAXIS1: " << naxis1;
113 if (*y_grid_minmax.second + m_grid_offset > naxis2)
114 throw Elements::Exception() << "The PSF at the largest y-grid is too large: " << *y_grid_minmax.second + m_grid_offset
115 << " NAXIS2: " << naxis1;
116}
117
119 long index_min_distance = 0;
120 double min_distance = 1.0e+32;
121
122 // make sure there are only two positions
123 if (values.size() != 2)
124 throw Elements::Exception() << "There can be only two positional value for the stacked PSF!";
125
126 // find the position of minimal distance
127 for (int act_index = 0; act_index < m_nrows; act_index++) {
128 double act_distance = (values[0] - m_x_values[act_index]) * (values[0] - m_x_values[act_index]) +
129 (values[1] - m_y_values[act_index]) * (values[1] - m_y_values[act_index]);
130 if (act_distance < min_distance) {
131 index_min_distance = act_index;
132 min_distance = act_distance;
133 }
134 }
135 // give some feedback
136 stack_logger.debug() << "Distance: " << sqrt(min_distance) << " (" << values[0] << "," << values[1] << ")<-->("
137 << m_x_values[index_min_distance] << "," << m_y_values[index_min_distance]
138 << ") index: " << index_min_distance;
139
140 // get the first and last pixels for the PSF to be extracted
141 // NOTE: CCfits has 1-based indices, also the last index is *included* in the reading
142 // NOTE: the +0.5 forces a correct cast/ceiling
143 std::vector<long> first_vertex{long(m_gridx_values[index_min_distance]+.5) - long(m_grid_offset), long(m_gridy_values[index_min_distance]+.5) - long(m_grid_offset)};
144 stack_logger.debug() << "First vertex: ( " << first_vertex[0] << ", " << first_vertex[1] << ") First vertex alternative: " <<
145 m_gridx_values[index_min_distance]-m_grid_offset << " " << m_gridy_values[index_min_distance]-m_grid_offset <<
146 " grid offset:" << m_grid_offset;
147
148 std::vector<long> last_vertex{first_vertex[0] + long(m_psf_size) - 1, first_vertex[1] +long( m_psf_size) - 1};
149 std::vector<long> stride{1, 1};
150
151 // read out the image
152 std::valarray<SeFloat> stamp_data;
153 {
155 m_pFits->extension(1).read(stamp_data, first_vertex, last_vertex, stride);
156 }
157
158 //stack_logger.info() << "DDD ( " << first_vertex[0] << ", " << first_vertex[1] << ") --> ( " << last_vertex[0] << ", " << last_vertex[1] << "): " << stamp_data.size();
159
160 // create and return the psf image
161 return VectorImage<SeFloat>::create(m_psf_size, m_psf_size, std::begin(stamp_data), std::end(stamp_data));
162}
163
164} // end SExtractor
static auto stack_logger
T begin(T... args)
static Logging getLogger(const std::string &name="")
std::vector< SeFloat > m_ra_values
virtual std::shared_ptr< VectorImage< SeFloat > > getPsf(const std::vector< double > &values) const
void setup(std::shared_ptr< CCfits::FITS > pFits)
std::vector< double > m_gridx_values
std::shared_ptr< CCfits::FITS > m_pFits
std::vector< SeFloat > m_x_values
std::vector< double > m_gridy_values
std::vector< SeFloat > m_dec_values
std::vector< SeFloat > m_y_values
static std::shared_ptr< VectorImage< T > > create(Args &&... args)
T end(T... args)
T lock(T... args)
T minmax_element(T... args)
T size(T... args)
T sqrt(T... args)