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
43// forward
44template <typename realT>
45struct array2FitEmpirical;
46
47// forward
48template <typename _realT>
49struct empirical2D_sym_fitter;
50
51/// Class to manage fitting a 2D Moffat to data via the \ref levmarInterface
52/** Fits \ref gen_math_moffats to a 2-dimensional array of data.
53 *
54 * This class allows for treating any of the parameters as fixed.
55 *
56 * \tparam fitterT a type meeting the requirements specified in \ref levmarInterface.
57 *
58 * \ingroup moffat_peak_fit
59 *
60 */
61template <typename fitterT>
62class fitEmpirical2DGen : public levmarInterface<fitterT>
63{
64
65 public:
66 typedef typename fitterT::realT realT;
67
68 public:
70
71 void initialize()
72 {
73 this->allocate_params( arr.nparams() );
74 this->adata = &arr;
75 }
76
77 public:
79 {
80 initialize();
81 }
82
84 {
85 }
86
87 /// Set whether each parameter is fixed.
88 /** Sets the parameter indices appropriately.
89 */
90 void setFixed( bool scale, ///< [in] if true, then scale will be not be part of the fit
91 bool dx, ///< [in] if true, then dx will be not be part of the fit
92 bool dy ///< [in] if true, then dy will be not be part of the fit
93 )
94 {
95 arr.setFixed( scale, dx, dy );
96 this->allocate_params( arr.nparams() );
97 }
98
99 /// Set the initial guess for the empirical fit
100 void setGuess( realT scale, ///< [in] the scale factr
101 realT dx, ///< [in] the x shift
102 realT dy ///< [in] the y shift
103 )
104 {
105 arr.scale( this->p, scale );
106 arr.dx( this->p, dx );
107 arr.dy( this->p, dy );
108 }
109
110 /// Set the data aray.
111 void setArray( const eigenImage<realT> *data, ///< [in] pointer to an nx X ny array of data to be fit
112 const eigenImage<realT> * ref ///< [in] pointer to the empirical function to fit
113 )
114 {
115 arr.setup(data, ref);
116
117 this->n = arr.m_nx * arr.m_ny;
118 }
119
120 /// Get the current value of the scale factor.
121 /**
122 * \returns the current value of scale
123 */
124 realT scale()
125 {
126 return arr.scale( this->p );
127 }
128
129 /// Get the current value of dx, the x shift
130 /**
131 * \returns the current value of dx
132 */
133 realT dx()
134 {
135 return arr.dx( this->p );
136 }
137
138 /// Get the current value of dy, the y shift
139 /**
140 * \returns the current value of dy
141 */
142 realT dy()
143 {
144 return arr.dy( this->p );
145 }
146
147};
148
149/// Wrapper for a native array to pass to \ref levmarInterface, with empirical function fit details.
150/** \ingroup moffat_peak_fit
151 */
152template <typename realT>
154{
155 const eigenImage<realT> *m_data{ nullptr }; ///< Pointer to the data array
156 const eigenImage<realT> *m_ref{ nullptr }; ///< Pointer to the reference image to fit to the data
157 eigenImage<realT> m_refShifted; ///< Working memory for the shifted reference image
158
159 size_t m_nx{ 0 }; ///< X dimension of the array
160 size_t m_ny{ 0 }; ///< Y dimension of the array
161
162 realT m_scale{ 0 };
163 realT m_dx{ 0 };
164 realT m_dy{ 0 };
165
166 int m_scale_idx{ 0 };
167 int m_dx_idx{ 1 };
168 int m_dy_idx{ 2 };
169
170 int m_nparams = 3;
171
172 void setup( const eigenImage<realT> *data,
173 const eigenImage<realT> *ref )
174 {
175 m_nx = data->rows();
176 m_ny = data->cols();
177
178 if(ref->rows() != m_nx || ref->cols() != m_ny)
179 {
180 std::cerr << "ref and data not same size\n";
181 exit(-1);
182 }
183
184 m_data = data;
185 m_ref = ref;
186 m_refShifted.resize(m_nx, m_ny);
187 }
188
189 /// Set whether each parameter is fixed.
190 /** Sets the parameter indices appropriately.
191 */
192 void setFixed( bool scale, bool dx, bool dy )
193 {
194 int idx = 0;
195
196 if( scale )
197 m_scale_idx = -1;
198 else
199 m_scale_idx = idx++;
200
201 if( dx )
202 m_dx_idx = -1;
203 else
204 m_dx_idx = idx++;
205
206 if( dy )
207 m_dy_idx = -1;
208 else
209 m_dy_idx = idx++;
210
211 m_nparams = idx;
212 }
213
214 realT scale( realT *p )
215 {
216 if( m_scale_idx < 0 )
217 {
218 return m_scale;
219 }
220 else
221 {
222 return p[m_scale_idx];
223 }
224 }
225
226 void scale( realT *p, realT nscale )
227 {
228 if( m_scale_idx < 0 )
229 {
230 m_scale = nscale;
231 }
232 else
233 {
234 p[m_scale_idx] = nscale;
235 }
236 }
237
238 realT dx( realT *p )
239 {
240 if( m_dx_idx < 0 )
241 {
242 return m_dx;
243 }
244 else
245 {
246 return p[m_dx_idx];
247 }
248 }
249
250 void dx( realT *p, realT ndx )
251 {
252 if( m_dx_idx < 0 )
253 {
254 m_dx = ndx;
255 }
256 else
257 {
258 p[m_dx_idx] = ndx;
259 }
260 }
261
262 realT dy( realT *p )
263 {
264 if( m_dy_idx < 0 )
265 {
266 return m_dy;
267 }
268 else
269 {
270 return p[m_dy_idx];
271 }
272 }
273
274 void dy( realT *p, realT ndy )
275 {
276 if( m_dy_idx < 0 )
277 {
278 m_dy = ndy;
279 }
280 else
281 {
282 p[m_dy_idx] = ndy;
283 }
284 }
285
286 int nparams()
287 {
288 return m_nparams;
289 }
290};
291
292///\ref levmarInterface fitter structure for 2D empirical functions.
293/** \ingroup moffat_peak_fit
294 *
295 */
296template <typename _realT>
298{
299 typedef _realT realT;
300
301 static const int nparams = 3;
302
303 static void func( realT *p, realT *hx, int m, int n, void *adata )
304 {
306
307 size_t idx_dat;
308
309 idx_dat = 0;
310
311 realT scale = arr->scale( p );
312 realT dx = arr->dx( p );
313 realT dy = arr->dy( p );
314
315 imageShift(arr->m_refShifted, *(arr->m_ref), dx, dy, cubicConvolTransform<realT>());
316
317 arr->m_refShifted *= scale;
318 for( int cc = 0; cc < arr->m_ny; ++cc )
319 {
320 for( int rr = 0; rr < arr->m_nx; ++rr )
321 {
322 hx[idx_dat] = pow(fabs((*(arr->m_data))(rr,cc)),1) * ((*(arr->m_data))(rr,cc) - arr->m_refShifted(rr,cc));
323
324 ++idx_dat;
325 }
326 }
327 }
328};
329
330/// Alias for the fitEmpirical2D type fitting the symmetric Moffat profile.
331/** \ingroup moffat_peak_fit
332 */
333template <typename realT>
335
336} // namespace fit
337} // namespace math
338
339} // namespace mx
340
341#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 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.
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.