2121 * Author: Martin Kuemmel
2222 */
2323#include < algorithm>
24+ #include < memory>
2425#include < ElementsKernel/Logging.h>
2526#include < ElementsKernel/Exception.h>
2627#include " SEFramework/Psf/VariablePsfStack.h"
@@ -73,18 +74,33 @@ void VariablePsfStack::setup(std::shared_ptr<CCfits::FITS> pFits) {
7374 // read the nrows value
7475 m_nrows = position_data.rows ();
7576
77+ // Temporary vectors for reading data
78+ std::vector<SeFloat> ra_values, dec_values, x_values, y_values;
79+ std::vector<double > gridx_values, gridy_values;
80+
7681 try {
7782 // 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);
83+ position_data.column (" GRIDX" , false ).read (gridx_values , 0 , m_nrows);
84+ position_data.column (" GRIDY" , false ).read (gridy_values , 0 , m_nrows);
8085 } 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);
86+ position_data.column (" X_CENTER" , false ).read (gridx_values, 0 , m_nrows);
87+ position_data.column (" Y_CENTER" , false ).read (gridy_values, 0 , m_nrows);
88+ }
89+ position_data.column (" RA" , false ).read (ra_values, 0 , m_nrows);
90+ position_data.column (" DEC" , false ).read (dec_values, 0 , m_nrows);
91+ position_data.column (" X" , false ).read (x_values, 0 , m_nrows);
92+ position_data.column (" Y" , false ).read (y_values, 0 , m_nrows);
93+
94+ // Populate the positions vector
95+ m_positions.reserve (m_nrows);
96+ for (long i = 0 ; i < m_nrows; ++i) {
97+ m_positions.push_back ({ra_values[i], dec_values[i], x_values[i], y_values[i], gridx_values[i], gridy_values[i]});
98+ }
99+
100+ // Build KdTree for fast nearest neighbor searches
101+ if (!m_positions.empty ()) {
102+ m_kdtree = std::make_unique<KdTree<PsfPosition>>(m_positions);
83103 }
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);
88104
89105 } catch (CCfits::FitsException& e) {
90106 throw Elements::Exception () << " Error loading stacked PSF file: " << e.message ();
@@ -95,54 +111,54 @@ void VariablePsfStack::selfTest() {
95111 int naxis1, naxis2;
96112
97113 // 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));
114+ auto x_grid_minmax = std::minmax_element (m_positions.begin (), m_positions.end (),
115+ [](const PsfPosition& a, const PsfPosition& b) { return a.gridx < b.gridx ; });
116+ auto y_grid_minmax = std::minmax_element (m_positions.begin (), m_positions.end (),
117+ [](const PsfPosition& a, const PsfPosition& b) { return a.gridy < b.gridy ; });
100118
101119 // read the image size
102120 m_pFits->extension (1 ).readKey (" NAXIS1" , naxis1);
103121 m_pFits->extension (1 ).readKey (" NAXIS2" , naxis2);
104122
105123 // 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
124+ if (x_grid_minmax.first -> gridx - m_grid_offset < 1 )
125+ throw Elements::Exception () << " The PSF at the smallest x-grid starts at: " << x_grid_minmax.first -> gridx - m_grid_offset;
126+ if (y_grid_minmax.first -> gridy - m_grid_offset < 1 )
127+ throw Elements::Exception () << " The PSF at the smallest y-grid starts at: " << y_grid_minmax.first -> gridy - m_grid_offset;
128+ if (x_grid_minmax.second -> gridx + m_grid_offset > naxis1)
129+ throw Elements::Exception () << " The PSF at the largest x-grid is too large: " << x_grid_minmax.second -> gridx + m_grid_offset
112130 << " 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 ;
131+ if (y_grid_minmax.second -> gridy + m_grid_offset > naxis2)
132+ throw Elements::Exception () << " The PSF at the largest y-grid is too large: " << y_grid_minmax.second -> gridy + m_grid_offset
133+ << " NAXIS2: " << naxis2 ;
116134}
117135
118136std::shared_ptr<VectorImage<SeFloat>> VariablePsfStack::getPsf (const std::vector<double >& values) const {
119- long index_min_distance = 0 ;
120- double min_distance = 1.0e+32 ;
121-
122137 // make sure there are only two positions
123138 if (values.size () != 2 )
124139 throw Elements::Exception () << " There can be only two positional value for the stacked PSF!" ;
125140
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- }
141+ // Use KdTree to find the nearest PSF position
142+ KdTree<PsfPosition>::Coord coord;
143+ coord.coord [0 ] = values[0 ]; // x coordinate
144+ coord.coord [1 ] = values[1 ]; // y coordinate
145+
146+ PsfPosition nearest_position = m_kdtree->findNearest (coord);
147+
148+ // Calculate distance for logging
149+ double min_distance = (values[0 ] - nearest_position.x ) * (values[0 ] - nearest_position.x ) +
150+ (values[1 ] - nearest_position.y ) * (values[1 ] - nearest_position.y );
151+
135152 // give some feedback
136153 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;
154+ << nearest_position.x << " ," << nearest_position.y << " )" ;
139155
140156 // get the first and last pixels for the PSF to be extracted
141157 // NOTE: CCfits has 1-based indices, also the last index is *included* in the reading
142158 // 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)};
159+ std::vector<long > first_vertex{long (nearest_position. gridx +.5 ) - long (m_grid_offset), long (nearest_position. gridy +.5 ) - long (m_grid_offset)};
144160 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 <<
161+ nearest_position. gridx -m_grid_offset << " " << nearest_position. gridy -m_grid_offset <<
146162 " grid offset:" << m_grid_offset;
147163
148164 std::vector<long > last_vertex{first_vertex[0 ] + long (m_psf_size) - 1 , first_vertex[1 ] +long ( m_psf_size) - 1 };
@@ -155,8 +171,6 @@ std::shared_ptr<VectorImage<SeFloat>> VariablePsfStack::getPsf(const std::vector
155171 m_pFits->extension (1 ).read (stamp_data, first_vertex, last_vertex, stride);
156172 }
157173
158- // stack_logger.info() << "DDD ( " << first_vertex[0] << ", " << first_vertex[1] << ") --> ( " << last_vertex[0] << ", " << last_vertex[1] << "): " << stamp_data.size();
159-
160174 // create and return the psf image
161175 return VectorImage<SeFloat>::create (m_psf_size, m_psf_size, std::begin (stamp_data), std::end (stamp_data));
162176}
0 commit comments