mxlib
c++ tools for analyzing astronomical data and other tasks by Jared R. Males. [git repo]
Loading...
Searching...
No Matches
fitEmpirical.hpp
Go to the documentation of this file.
1/** \file fitEmpirical.hpp
2 * \author Jared R. Males
3 * \brief Tools for fitting empirical functions to data.
4 * \ingroup fitting_files
5 *
6 */
7
8//***********************************************************************//
9// Copyright 2024 Jared R. Males (jaredmales@gmail.com)
10//
11// This file is part of mxlib.
12//
13// mxlib is free software: you can redistribute it and/or modify
14// it under the terms of the GNU General Public License as published by
15// the Free Software Foundation, either version 3 of the License, or
16// (at your option) any later version.
17//
18// mxlib is distributed in the hope that it will be useful,
19// but WITHOUT ANY WARRANTY; without even the implied warranty of
20// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
21// GNU General Public License for more details.
22//
23// You should have received a copy of the GNU General Public License
24// along with mxlib. If not, see <http://www.gnu.org/licenses/>.
25//***********************************************************************//
26
27#ifndef fitEmpirical_hpp
28#define fitEmpirical_hpp
29
30#include "levmarInterface.hpp"
31
32#include "../../improc/eigenImage.hpp"
33#include "../../improc/imageTransforms.hpp"
34
35namespace mx
36{
37namespace math
38{
39namespace fit
40{
41
42// forward
43template <typename realT>
44struct array2FitEmpirical;
45
46// forward
47template <typename _realT>
48struct empirical2D_sym_fitter;
49
50/// Class to manage fitting a 2D Moffat to data via the \ref levmarInterface
51/** Fits \ref gen_math_moffats to a 2-dimensional array of data.
52 *
53 * This class allows for treating any of the parameters as fixed.
54 *
55 * \tparam fitterT a type meeting the requirements specified in \ref levmarInterface.
56 *
57 * \ingroup moffat_peak_fit
58 *
59 */
60template <typename fitterT>
61class fitEmpirical2DGen : public levmarInterface<fitterT>
62{
63
64 public:
65 typedef typename fitterT::realT realT;
66
67 public:
69
70 void initialize()
71 {
72 this->allocate_params( arr.nparams() );
73 this->adata = &arr;
74 }
75
76 public:
78 {
79 initialize();
80 }
81
83 {
84 }
85
86 /// Set whether each parameter is fixed.
87 /** Sets the parameter indices appropriately.
88 */
89 void setFixed( bool scale, ///< [in] if true, then scale will be not be part of the fit
90 bool dx, ///< [in] if true, then dx will be not be part of the fit
91 bool dy ///< [in] if true, then dy will be not be part of the fit
92 )
93 {
94 arr.setFixed( scale, dx, dy );
95 this->allocate_params( arr.nparams() );
96 }
97
98 /// Set the initial guess for the empirical fit
99 void setGuess( realT scale, ///< [in] the scale factr
100 realT dx, ///< [in] the x shift
101 realT dy ///< [in] the y shift
102 )
103 {
104 arr.scale( this->p, scale );
105 arr.dx( this->p, dx );
106 arr.dy( this->p, dy );
107 }
108
109 /// Set the data aray.
110 void setArray( const eigenImage<realT> *data, ///< [in] pointer to an nx X ny array of data to be fit
111 const eigenImage<realT> *ref, ///< [in] pointer to the empirical function to fit
112 const eigenImage<realT> *weights
113 )
114 {
115 arr.setup( data, ref, weights );
116
117 this->n = arr.m_nx * arr.m_ny;
118 }
119
120 /// Set the data aray.
121 void setArray( const eigenImage<realT> *data, ///< [in] pointer to an nx X ny array of data to be fit
122 const eigenImage<realT> *ref ///< [in] pointer to the empirical function to fit
123 )
124 {
125 setArray( data, ref, nullptr);
126 }
127
128 /// Get the current value of the scale factor.
129 /**
130 * \returns the current value of scale
131 */
132 realT scale()
133 {
134 return arr.scale( this->p );
135 }
136
137 /// Get the current value of dx, the x shift
138 /**
139 * \returns the current value of dx
140 */
141 realT dx()
142 {
143 return arr.dx( this->p );
144 }
145
146 /// Get the current value of dy, the y shift
147 /**
148 * \returns the current value of dy
149 */
150 realT dy()
151 {
152 return arr.dy( this->p );
153 }
154};
155
156/// Wrapper for a native array to pass to \ref levmarInterface, with empirical function fit details.
157/** \ingroup moffat_peak_fit
158 */
159template <typename realT>
161{
162 const eigenImage<realT> *m_data{ nullptr }; ///< Pointer to the data array
163 const eigenImage<realT> *m_ref{ nullptr }; ///< Pointer to the reference image to fit to the data
164 const eigenImage<realT> *m_weights{ nullptr }; ///< Pointer to the weight image
165 eigenImage<realT> m_refShifted; ///< Working memory for the shifted reference image
166
167 size_t m_nx{ 0 }; ///< X dimension of the array
168 size_t m_ny{ 0 }; ///< Y dimension of the array
169
170 realT m_scale{ 0 };
171 realT m_dx{ 0 };
172 realT m_dy{ 0 };
173
174 int m_scale_idx{ 0 };
175 int m_dx_idx{ 1 };
176 int m_dy_idx{ 2 };
177
178 int m_nparams = 3;
179
180 void setup( const eigenImage<realT> *data, const eigenImage<realT> *ref, const eigenImage<realT> *weights )
181 {
182 m_nx = data->rows();
183 m_ny = data->cols();
184
185 if( ref->rows() != m_nx || ref->cols() != m_ny )
186 {
187 std::cerr << "ref and data not same size\n";
188 exit( -1 );
189 }
190
191 if( weights )
192 {
193 if( weights->rows() != m_nx || weights->cols() != m_ny )
194 {
195 std::cerr << "ref and data not same size\n";
196 exit( -1 );
197 }
198 }
199
200 m_data = data;
201 m_ref = ref;
202 m_weights = weights;
203 m_refShifted.resize( m_nx, m_ny );
204 }
205
206 void setup( const eigenImage<realT> *data, const eigenImage<realT> *ref )
207 {
208 setup( data, ref, nullptr );
209 }
210
211 /// Set whether each parameter is fixed.
212 /** Sets the parameter indices appropriately.
213 */
214 void setFixed( bool scale, bool dx, bool dy )
215 {
216 int idx = 0;
217
218 if( scale )
219 m_scale_idx = -1;
220 else
221 m_scale_idx = idx++;
222
223 if( dx )
224 m_dx_idx = -1;
225 else
226 m_dx_idx = idx++;
227
228 if( dy )
229 m_dy_idx = -1;
230 else
231 m_dy_idx = idx++;
232
233 m_nparams = idx;
234 }
235
236 realT scale( realT *p )
237 {
238 if( m_scale_idx < 0 )
239 {
240 return m_scale;
241 }
242 else
243 {
244 return p[m_scale_idx];
245 }
246 }
247
248 void scale( realT *p, realT nscale )
249 {
250 if( m_scale_idx < 0 )
251 {
252 m_scale = nscale;
253 }
254 else
255 {
256 p[m_scale_idx] = nscale;
257 }
258 }
259
260 realT dx( realT *p )
261 {
262 if( m_dx_idx < 0 )
263 {
264 return m_dx;
265 }
266 else
267 {
268 return p[m_dx_idx];
269 }
270 }
271
272 void dx( realT *p, realT ndx )
273 {
274 if( m_dx_idx < 0 )
275 {
276 m_dx = ndx;
277 }
278 else
279 {
280 p[m_dx_idx] = ndx;
281 }
282 }
283
284 realT dy( realT *p )
285 {
286 if( m_dy_idx < 0 )
287 {
288 return m_dy;
289 }
290 else
291 {
292 return p[m_dy_idx];
293 }
294 }
295
296 void dy( realT *p, realT ndy )
297 {
298 if( m_dy_idx < 0 )
299 {
300 m_dy = ndy;
301 }
302 else
303 {
304 p[m_dy_idx] = ndy;
305 }
306 }
307
308 int nparams()
309 {
310 return m_nparams;
311 }
312};
313
314///\ref levmarInterface fitter structure for 2D empirical functions.
315/** \ingroup moffat_peak_fit
316 *
317 */
318template <typename _realT>
320{
321 typedef _realT realT;
322
323 static const int nparams = 3;
324
325 static void func( realT *p, realT *hx, int m, int n, void *adata )
326 {
328
329 size_t idx_dat;
330
331 idx_dat = 0;
332
333 realT scale = arr->scale( p );
334 realT dx = arr->dx( p );
335 realT dy = arr->dy( p );
336
337 imageShift( arr->m_refShifted, *( arr->m_ref ), dx, dy, cubicConvolTransform<realT>() );
338
339 arr->m_refShifted *= scale;
340
341 if( arr->m_weights )
342 {
343 for( int cc = 0; cc < arr->m_ny; ++cc )
344 {
345 for( int rr = 0; rr < arr->m_nx; ++rr )
346 {
347 hx[idx_dat] =(*arr->m_weights)(rr,cc)*( ( *arr->m_data)( rr, cc ) - arr->m_refShifted( rr, cc ) );
348
349 ++idx_dat;
350 }
351 }
352 }
353 else
354 {
355 for( int cc = 0; cc < arr->m_ny; ++cc )
356 {
357 for( int rr = 0; rr < arr->m_nx; ++rr )
358 {
359 hx[idx_dat] = ( ( *( arr->m_data ) )( rr, cc ) - arr->m_refShifted( rr, cc ) );
360
361 ++idx_dat;
362 }
363 }
364 }
365 }
366};
367
368/// Alias for the fitEmpirical2D type fitting the symmetric Moffat profile.
369/** \ingroup moffat_peak_fit
370 */
371template <typename realT>
373
374} // namespace fit
375} // namespace math
376
377} // namespace mx
378
379#endif // fitEmpirical_hpp
Class to manage fitting a 2D Moffat to data via the levmarInterface.
void setArray(const eigenImage< realT > *data, const eigenImage< realT > *ref)
Set the data aray.
realT dx()
Get the current value of dx, the x shift.
realT scale()
Get the current value of the scale factor.
void setFixed(bool scale, bool dx, bool dy)
Set whether each parameter is fixed.
realT dy()
Get the current value of dy, the y shift.
void setArray(const eigenImage< realT > *data, const eigenImage< realT > *ref, const eigenImage< realT > *weights)
Set the data aray.
void setGuess(realT scale, realT dx, realT dy)
Set the initial guess for the empirical fit.
A templatized interface to the levmar package.
void allocate_params()
Allocate parameters array based on previous call to nParams.
realT * p
Parameter array. On input is the initial estimates. On output has the estimated solution.
int n
I: measurement vector dimension.
void * adata
Pointer to possibly additional data, passed uninterpreted to func & jacf.
constexpr floatT six_fifths()
Return 6/5 in the specified precision.
A c++ interface to the templatized levmar minimization routines..
The mxlib c++ namespace.
Definition mxError.hpp:106
Wrapper for a native array to pass to levmarInterface, with empirical function fit details.
const eigenImage< realT > * m_weights
Pointer to the weight image.
void setFixed(bool scale, bool dx, bool dy)
Set whether each parameter is fixed.
eigenImage< realT > m_refShifted
Working memory for the shifted reference image.
size_t m_nx
X dimension of the array.
size_t m_ny
Y dimension of the array.
const eigenImage< realT > * m_data
Pointer to the data array.
const eigenImage< realT > * m_ref
Pointer to the reference image to fit to the data.
levmarInterface fitter structure for 2D empirical functions.