mxlib
c++ tools for analyzing astronomical data and other tasks by Jared R. Males. [git repo]
Loading...
Searching...
No Matches
fraunhoferPropagator.hpp
Go to the documentation of this file.
1/** \file fraunhoferPropagator.hpp
2 * \brief Declares and defines a class for Fraunhofer propagation of optical wavefronts
3 * \ingroup imaging
4 * \author Jared R. Males (jaredmales@gmail.com)
5 *
6 */
7
8//***********************************************************************//
9// Copyright 2015-2020 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 wfp_fraunhoferPropagator_hpp
28#define wfp_fraunhoferPropagator_hpp
29
30#include "../mxlib.hpp"
31
32#include "../math/constants.hpp"
33#include "imagingArray.hpp"
34#include "imagingUtils.hpp"
35
36#include "../math/ft/fftT.hpp"
37
38#ifdef MXLIB_CUDA
39#include "../math/cuda/templateCuda.hpp"
40#include "../math/cuda/cudaPtr.hpp"
41#include "../math/cuda/templateCufft.hpp"
42#include "../math/cuda/templateCublas.hpp"
43#endif
44
45#ifdef DEBUG
46#define BREAD_CRUMB std::cout << "DEBUG: " << __FILE__ << " " << __LINE__ << "\n";
47#else
48#define BREAD_CRUMB
49#endif
50
51namespace mx
52{
53
54namespace wfp
55{
56
57template <typename wavefrontT, int cudaGPU>
58struct fraunhoferPropagatorArrayT;
59
60template <typename wavefrontT>
61struct fraunhoferPropagatorArrayT<wavefrontT, 0>
62{
63 typedef wavefrontT arrayT;
64};
65
66#ifdef MXLIB_CUDA
67template <typename wavefrontT>
68struct fraunhoferPropagatorArrayT<wavefrontT, 1>
69{
70 typedef mx::cuda::cudaPtr<typename wavefrontT::Scalar> arrayT;
71};
72#endif
73
74/// Class to perform Fraunhofer propagation between pupil and focal planes
75/** This class uses the FFT to propagate between planes, and normalizes so that flux
76 * is conserved. For propagation from pupil to focal plane, the pupil wavefront is tilted so that
77 * the focal-plane image is centered at the geometric center of the array. After propagation from
78 * focal plane to pupil plane, the pupil plane wavefront is un-tilted to restore the
79 * pupil to its original position.
80 *
81 * \tparam _wavefrontT is an Eigen::Array-like type, with std::complex values.
82 *
83 * \todo check if we should reverse the FFT orders to be proper
84 *
85 * \ingroup imaging
86 */
87template <typename _wavefrontT, int _cudaGPU = 0>
89{
90
91 public:
92 /// The wavefront data type
93 typedef _wavefrontT wavefrontT;
94
95 static constexpr int cudaGPU = _cudaGPU;
96
97 /// The complex data type
98 typedef typename wavefrontT::Scalar complexT;
99
100 /// The real data type
101 typedef typename wavefrontT::Scalar::value_type realT;
102
103 /// The array data type
104 typedef typename fraunhoferPropagatorArrayT<wavefrontT, cudaGPU>::arrayT arrayT;
105
106 typedef verbose::d verboseT;
107
108 protected:
109 /// The size of the wavefront in pixels
111
112 realT m_xcen{ 0 }; ///< x-coordinate of focal plane center, in pixels
113 realT m_ycen{ 0 }; ///< x-coordinate of focal plane center, in pixels
114
115 /// Determines how the image is centered.
116 /** If 0 (default) it is at 0.5*(wfSz-1), if true it is shifted by 0.5*m_wholePixel in each axis.
117 */
119
120 /// Phase screen for tilting the pupil plane so that the focal plane image is centered.
121 fraunhoferPropagatorArrayT<wavefrontT, cudaGPU>::arrayT m_centerFocal;
122
123 /// Phase screen for un-tilting the pupil plane after propagating from a centered focal plane.
124 fraunhoferPropagatorArrayT<wavefrontT, cudaGPU>::arrayT m_centerPupil;
125
126 /// FFT object for forward FFTs
127 math::ft::fftT<complexT, complexT, 2, cudaGPU> m_fft_fwd;
128
129 /// FFT object for backward FFTs
130 math::ft::fftT<complexT, complexT, 2, cudaGPU> m_fft_back;
131
132 public:
133 /// Constructor
135
136 /// Destructor
138
139 /// Get the value of the wholePixel parameter
140 /** The wholePixel parameter determines how the image is centered. If 0 (default) it is at 0.5*(wfSz-1), if true it
141 * is shifted by 0.5*m_wholePixel in each axis.
142 *
143 * \returns the value of m_wholePixel
144 */
146
147 /// Set the value of the wholePixel parameter
148 /** The wholePixel parameter determines how the image is centered. If 0 (default) it is at 0.5*(wfSz-1), if true it
149 * is shifted by 0.5*m_wholePixel in each axis.
150 */
151 void wholePixel( realT wp /**< [in] the new wholePixel value */ );
152
153 /// Apply the shift to a pupil wavefront and apply the normalization.
154 /** This will center the resultant focal plane image.
155 * You must have allocated the shift screens first, by calling propagatePupilToFocal, propagateFocalToPupil, or
156 * setWavefrontSizePixels.
157 */
158 template <int ccudaGPU = cudaGPU>
159 error_t shiftPupil( arrayT &complexPupil, /**< [in.out] the complex pupil plane wavefront to shift*/
160 typename std::enable_if<ccudaGPU == 0>::type * = 0 );
161
162 /// Apply the shift to a pupil wavefront and apply the normalization.
163 /** This will center the resultant focal plane image.
164 * You must have allocated the shift screens first, by calling propagatePupilToFocal, propagateFocalToPupil, or
165 * setWavefrontSizePixels.
166 */
167 template <int ccudaGPU = cudaGPU>
168 error_t shiftPupil( arrayT &complexPupil, /**< [in.out] the complex pupil plane wavefront to shift*/
169 typename std::enable_if<ccudaGPU == 1>::type * = 0 );
170
171 /// Apply the shift to a pupil wavefront which will restore it to a centered pupil image, with correct flux.
172 /** You must have allocated the shift screens first, by calling propagatePupilToFocal, propagateFocalToPupil, or
173 * setWavefrontSizePixels.
174 */
175 template <int ccudaGPU = cudaGPU>
176 error_t unshiftPupil( arrayT &complexPupil, /**< [in.out] the complex pupil plane wavefront to shift*/
177 typename std::enable_if<ccudaGPU == 0>::type * = 0 );
178
179 /// Apply the shift to a pupil wavefront which will restore it to a centered pupil image, with correct flux.
180 /** You must have allocated the shift screens first, by calling propagatePupilToFocal, propagateFocalToPupil, or
181 * setWavefrontSizePixels.
182 */
183 template <int ccudaGPU = cudaGPU>
184 error_t unshiftPupil( arrayT &complexPupil, /**< [in.out] the complex pupil plane wavefront to shift*/
185 typename std::enable_if<ccudaGPU == 1>::type * = 0 );
186
187 public:
188 /// Propagate the wavefront from the pupil plane to the focal plane
189 /** The pupil plane wavefront (complexPupil) is multiplied by a tilt to place the
190 * image in the geometric center of the focal plane. This can be prevented by
191 * setting doCenter to false.
192 *
193 */
194 error_t propagatePupilToFocal( arrayT &complexFocal, /**< [out] the focal plane wavefront. Must be
195 pre-allocated to same size as complexPupil.*/
196 arrayT &complexPupil, /**< [in] the pupil plane wavefront. Modified due
197 to application of centering tilt.*/
198 bool doCenter = true /**< [in] [optional] set to false to not apply
199 the centering shift*/
200 );
201
202 /// Propagate the wavefront from Focal plane to Pupil plane
203 /** After the fourier transform, the output pupil plane wavefront is de-tilted, restoring it
204 * to the state prior to calling \ref propagatePupilToFocal. This can be prevented by
205 * setting doCenter to false.
206 *
207 */
208 error_t propagateFocalToPupil( arrayT &complexPupil, /**< [out] the pupil plane wavefront. Must be
209 pre-allocated to same size as complexFocal.*/
210 arrayT &complexFocal, /**< [in] the focal plane wavefront. */
211 bool doCenter = true /**< [in] [optional] set to false to not apply
212 the centering shift*/
213 );
214
215 /// Set the size of the wavefront, in pixels
216 /** Checks if the size changes, does nothing if no change. Otherwise, calls
217 * \ref makeShiftPhase to pre-calculate the tilt arrays and plans the FFTs.
218 *
219 */
220 void setWavefrontSizePixels( int wfsPix /**< [in] the desired new size of the wavefront */ );
221
222 protected:
223 template <int ccudaGPU = cudaGPU>
224 void
225 setShiftPhase( complexT *shiftFocal, complexT *shiftPupil, typename std::enable_if<ccudaGPU == 0>::type * = 0 );
226
227 template <int ccudaGPU = cudaGPU>
228 void
229 setShiftPhase( complexT *shiftFocal, complexT *shiftPupil, typename std::enable_if<ccudaGPU == 1>::type * = 0 );
230
231 /// Calculate the complex tilt arrays for centering and normalizing the wavefronts
232 /**
233 */
235
236}; // class fraunhoferPropagator
237
238template <typename wavefrontT, int cudaGPU>
242
243template <typename wavefrontT, int cudaGPU>
247
248template <typename wavefrontT, int cudaGPU>
250{
251 return m_wholePixel;
252}
253
254template <typename wavefrontT, int cudaGPU>
256{
257 m_wholePixel = wp;
258
259 // Re-make the shift phase if size already set.
260 if( m_wavefrontSizePixels > 0 )
261 {
262 makeShiftPhase();
263 }
264}
265
266template <typename wavefrontT, int cudaGPU>
267template <int ccudaGPU>
269 typename std::enable_if<ccudaGPU == 0>::type * )
270{
271 complexPupil *= m_centerFocal;
272
273 return error_t::noerror;
274}
275
276template <typename wavefrontT, int cudaGPU>
277template <int ccudaGPU>
279 typename std::enable_if<ccudaGPU == 1>::type * )
280{
281 BREAD_CRUMB;
282#ifdef MXLIB_CUDA
283
284 cudaError_t ce = mx::cuda::elementwiseXxY( reinterpret_cast<cuComplex *>( complexPupil.m_devicePtr ),
285 reinterpret_cast<cuComplex *>( m_centerFocal.m_devicePtr ),
286 pow( m_wavefrontSizePixels, 2 ) );
287
288 if( ce != cudaSuccess )
289 {
290 return internal::mxlib_error_report<verboseT>( cudaError2error_t( ce ), "from mx::cuda::elementwiseXxY" );
291 }
292
293#endif
294
295 BREAD_CRUMB;
296
297 return error_t::noerror;
298}
299
300template <typename wavefrontT, int cudaGPU>
301template <int ccudaGPU>
303 typename std::enable_if<ccudaGPU == 0>::type * )
304{
305 complexPupil *= m_centerPupil;
306
307 return error_t::noerror;
308}
309
310template <typename wavefrontT, int cudaGPU>
311template <int ccudaGPU>
313 typename std::enable_if<ccudaGPU == 1>::type * )
314{
315#ifdef MXLIB_CUDA
316 cudaError_t ce = mx::cuda::elementwiseXxY( reinterpret_cast<cuComplex *>( complexPupil.m_devicePtr ),
317 reinterpret_cast<cuComplex *>( m_centerPupil.m_devicePtr ),
318 pow( m_wavefrontSizePixels, 2 ) );
319
320 if( ce != cudaSuccess )
321 {
322 return internal::mxlib_error_report<verboseT>( cudaError2error_t( ce ), "from mx::cuda::elementwiseXxY" );
323 }
324#endif
325
326 return error_t::noerror;
327}
328
329template <typename wavefrontT, int cudaGPU>
331 arrayT &complexPupil,
332 bool doCenter /*default = true*/
333)
334{
335
336 BREAD_CRUMB;
337
338 // First setup the tilt screens (does nothing if there's no change in size)
339 setWavefrontSizePixels( complexPupil.rows() );
340
341 BREAD_CRUMB;
342
343 // Apply the centering shift -- this adjusts by 0.5 pixels and normalizes
344 if( doCenter )
345 {
346 error_t ec = shiftPupil( complexPupil );
347
348 if(ec != error_t::noerror)
349 {
350 return internal::mxlib_error_report<verboseT>(ec, "from shiftPupil");
351 }
352 }
353
354 BREAD_CRUMB;
355
356 // fft_fwd.fft(complexPupil.data(), complexFocal.data() );
357 m_fft_fwd( complexFocal.data(), complexPupil.data() );
358
359 BREAD_CRUMB;
360
361 return error_t::noerror;
362}
363
364template <typename wavefrontT, int cudaGPU>
366 arrayT &complexFocal,
367 bool doCenter /*default = true*/
368)
369{
370 BREAD_CRUMB;
371
372 // First setup the tilt screens (does nothing if there's no change in size)
373 setWavefrontSizePixels( complexPupil.rows() );
374
375 BREAD_CRUMB;
376 // fft_back.fft( complexFocal.data(), complexPupil.data());
377 m_fft_back( complexPupil.data(), complexFocal.data() );
378
379 BREAD_CRUMB;
380
381 // Unshift the wavefront and normalize
382 if( doCenter )
383 {
384 error_t ec = unshiftPupil( complexPupil );
385
386 if(ec != error_t::noerror)
387 {
388 return internal::mxlib_error_report<verboseT>(ec, "from unshiftPupil");
389 }
390
391 }
392
393 BREAD_CRUMB;
394
395 return error_t::noerror;
396}
397
398template <typename wavefrontT, int cudaGPU>
400{
401 BREAD_CRUMB;
402
403 // If no change in size, do nothing
404 if( wfsPix == m_centerFocal.rows() )
405 {
406 return;
407 }
408
409 BREAD_CRUMB;
410
411 m_wavefrontSizePixels = wfsPix;
412
413 BREAD_CRUMB;
414
415 m_xcen = 0.5 * ( wfsPix - 1.0 );
416 m_ycen = 0.5 * ( wfsPix - 1.0 );
417
418 BREAD_CRUMB;
419
420 makeShiftPhase();
421
422 BREAD_CRUMB;
423
424 m_fft_fwd.plan( wfsPix, wfsPix );
425
426 BREAD_CRUMB;
427
428 m_fft_back.plan( wfsPix, wfsPix, math::ft::dir::backward );
429
430 BREAD_CRUMB;
431}
432
433template <typename wavefrontT, int cudaGPU>
434template <int ccudaGPU>
436 complexT *centerPupil,
437 typename std::enable_if<ccudaGPU == 0>::type * )
438{
439 m_centerFocal.resize( m_wavefrontSizePixels, m_wavefrontSizePixels );
440 m_centerPupil.resize( m_wavefrontSizePixels, m_wavefrontSizePixels );
441
442 // Have to do this manually b/c "Eigen-like" might not support copy from a map
443 for( int cc = 0; cc < m_wavefrontSizePixels; ++cc )
444 {
445 for( int rr = 0; rr < m_wavefrontSizePixels; ++rr )
446 {
447 m_centerFocal( rr, cc ) = centerFocal[cc * m_wavefrontSizePixels + rr];
448 m_centerPupil( rr, cc ) = centerPupil[cc * m_wavefrontSizePixels + rr];
449 }
450 }
451}
452
453template <typename wavefrontT, int cudaGPU>
454template <int ccudaGPU>
455void fraunhoferPropagator<wavefrontT, cudaGPU>::setShiftPhase( complexT *centerFocal,
456 complexT *centerPupil,
457 typename std::enable_if<ccudaGPU == 1>::type * )
458{
459#ifdef MXLIB_CUDA
460
461 BREAD_CRUMB;
462
463 m_centerFocal.upload( centerFocal, m_wavefrontSizePixels, m_wavefrontSizePixels );
464
465 BREAD_CRUMB;
466
467 m_centerPupil.upload( centerPupil, m_wavefrontSizePixels, m_wavefrontSizePixels );
468
469 BREAD_CRUMB;
470
471#endif
472}
473
474template <typename wavefrontT, int cudaGPU>
476{
477 constexpr realT pi = math::pi<realT>();
478
479 // The normalization is included in the tilt.
480 realT norm = 1. / ( m_wavefrontSizePixels * sqrt( 2 ) );
481 complexT cnorm = complexT( norm, norm );
482
483 BREAD_CRUMB;
484
485 /// Host memory to build the shift screens
486 complexT *centerFocal = new complexT[m_wavefrontSizePixels * m_wavefrontSizePixels];
487
488 complexT *centerPupil = new complexT[m_wavefrontSizePixels * m_wavefrontSizePixels];
489
490 // Shift by 0.5 pixels
491 realT arg = -2.0 * pi * 0.5 * ( m_wavefrontSizePixels - m_wholePixel ) / ( m_wavefrontSizePixels - 1 );
492
493 for( int cc = 0; cc < m_wavefrontSizePixels; ++cc )
494 {
495 for( int rr = 0; rr < m_wavefrontSizePixels; ++rr )
496 {
497 centerFocal[cc * m_wavefrontSizePixels + rr] =
498 cnorm * exp( complexT( 0., arg * ( ( rr - m_xcen ) + ( cc - m_ycen ) ) ) );
499 centerPupil[cc * m_wavefrontSizePixels + rr] =
500 cnorm * exp( complexT( 0., 0.5 * pi - arg * ( ( rr - m_xcen ) + ( cc - m_ycen ) ) ) );
501 }
502 }
503
504 BREAD_CRUMB;
505
506 setShiftPhase( centerFocal, centerPupil );
507
508 BREAD_CRUMB;
509
510 delete[] centerFocal;
511 delete[] centerPupil;
512}
513
514} // namespace wfp
515} // namespace mx
516
517#endif // wfp_fraunhoferPropagator_hpp
Class to perform Fraunhofer propagation between pupil and focal planes.
fraunhoferPropagatorArrayT< wavefrontT, cudaGPU >::arrayT arrayT
The array data type.
fraunhoferPropagatorArrayT< wavefrontT, cudaGPU >::arrayT m_centerFocal
Phase screen for tilting the pupil plane so that the focal plane image is centered.
math::ft::fftT< complexT, complexT, 2, cudaGPU > m_fft_back
FFT object for backward FFTs.
wavefrontT::Scalar complexT
The complex data type.
void setWavefrontSizePixels(int wfsPix)
Set the size of the wavefront, in pixels.
error_t propagateFocalToPupil(arrayT &complexPupil, arrayT &complexFocal, bool doCenter=true)
Propagate the wavefront from Focal plane to Pupil plane.
int wholePixel()
Get the value of the wholePixel parameter.
fraunhoferPropagatorArrayT< wavefrontT, cudaGPU >::arrayT m_centerPupil
Phase screen for un-tilting the pupil plane after propagating from a centered focal plane.
error_t shiftPupil(arrayT &complexPupil, typename std::enable_if< ccudaGPU==0 >::type *=0)
Apply the shift to a pupil wavefront and apply the normalization.
void wholePixel(realT wp)
Set the value of the wholePixel parameter.
realT m_wholePixel
Determines how the image is centered.
wavefrontT::Scalar::value_type realT
The real data type.
_wavefrontT wavefrontT
The wavefront data type.
error_t unshiftPupil(arrayT &complexPupil, typename std::enable_if< ccudaGPU==1 >::type *=0)
Apply the shift to a pupil wavefront which will restore it to a centered pupil image,...
int m_wavefrontSizePixels
The size of the wavefront in pixels.
realT m_xcen
x-coordinate of focal plane center, in pixels
realT m_ycen
x-coordinate of focal plane center, in pixels
error_t propagatePupilToFocal(arrayT &complexFocal, arrayT &complexPupil, bool doCenter=true)
Propagate the wavefront from the pupil plane to the focal plane.
void makeShiftPhase()
Calculate the complex tilt arrays for centering and normalizing the wavefronts.
error_t unshiftPupil(arrayT &complexPupil, typename std::enable_if< ccudaGPU==0 >::type *=0)
Apply the shift to a pupil wavefront which will restore it to a centered pupil image,...
math::ft::fftT< complexT, complexT, 2, cudaGPU > m_fft_fwd
FFT object for forward FFTs.
error_t shiftPupil(arrayT &complexPupil, typename std::enable_if< ccudaGPU==1 >::type *=0)
Apply the shift to a pupil wavefront and apply the normalization.
error_t
The mxlib error codes.
Definition error_t.hpp:26
@ noerror
No error has occurred.
@ backward
Specifies the backward transform.
constexpr floatT six_fifths()
Return 6/5 in the specified precision.
Declares and defines a class for managing images.
Utilities for modeling image formation.
MXLIB_DEFAULT_VERBOSITY d
The default verbosity.
Definition error.hpp:202
The mxlib c++ namespace.
Definition mxlib.hpp:37