isce3 0.25.0
Loading...
Searching...
No Matches
Sequential.icc
1// -*- C++ -*-
2// -*- coding: utf-8 -*-
3//
4// michael a.g. aïvázis <michael.aivazis@para-sim.com>
5// parasim
6// (c) 1998-2019 all rights reserved
7//
8
9// code guard
10#if !defined(ampcor_correlators_Sequential_icc)
11#error This header is an implementation detail of ampcor::correlators::Sequential
12#endif
13
14// interface
15template <typename raster_t>
16void
18addReferenceTile(size_type pid, const constview_type & ref)
19{
20 // figure out the starting address of this tile in the arena
21 cell_type * support = _arena + pid*(_refCells + _tgtCells);
22 // adapt it into a grid
23 tile_type tile(_refLayout, support);
24 // move the data
25 std::copy(ref.begin(), ref.end(), tile.view().begin());
26 // all done
27 return;
28}
29
30
31template <typename raster_t>
32void
34addTargetTile(size_type pid, const constview_type & tgt)
35{
36 // figure out the starting address of this tile in the arena
37 cell_type * support = _arena + pid*(_refCells + _tgtCells) + _refCells;
38 // adapt it into a grid
39 tile_type tile(_tgtLayout, support);
40 // move the data
41 std::copy(tgt.begin(), tgt.end(), tile.view().begin());
42 // all done
43 return;
44}
45
46
47template <typename raster_t>
48auto
50adjust() -> const value_type *
51{
52 // make a channel
53 pyre::journal::debug_t channel("ampcor");
54
55 // compute the dimension of the reference tiles; assume they are square
56 auto refDim = _refLayout.shape()[0];
57 // compute the dimension of the target tiles; assume they are square
58 auto tgtDim = _tgtLayout.shape()[0];
59 // compute the dimension of the correlation matrix
60 auto corDim = _corLayout.shape()[0];
61
62 // prelude: coarse adjustments
63 auto coarseArena = _arena;
64 // compute their amplitudes
65 auto amplitudes = _detect(coarseArena, refDim, tgtDim);
66 // adjust the reference tiles to zero mean and compute the variances
67 auto refStatistics = _refStats(amplitudes, refDim, tgtDim);
68 // compute the sum area tables for all possible search window placements within the target tile
69 auto sat = _sat(amplitudes, refDim, tgtDim);
70 // use the SATs to compute the mean amplitude of all possible window placements
71 auto tgtStatistics = _tgtStats(sat, refDim, tgtDim, corDim);
72 // compute the correlation hyper-surface
73 auto gamma = _correlate(amplitudes, refStatistics, tgtStatistics, refDim, tgtDim, corDim);
74 // find its maxima
75 auto maxcor = _maxcor(gamma, corDim);
76
77 // interlude: housekeeping
78 delete [] gamma;
79 delete [] tgtStatistics;
80 delete [] sat;
81 delete [] refStatistics;
82 delete [] amplitudes;
83
84 // refinement: refine the tiles by a factor and repeat the process with a narrower search
85 // window around the location of maximum correlation
86 // compute the dimension of the reference tiles; assume they are square
87 auto refRefinedDim = _refRefinedLayout.shape()[0];
88 // compute the dimension of the target tiles; assume they are square
89 auto tgtRefinedDim = _tgtRefinedLayout.shape()[0];
90 // compute the dimension of the correlation matrix
91 auto corRefinedDim = _corRefinedLayout.shape()[0];
92 // compute the dimension of the zoomed correlation matrix
93 auto corZoomedDim = _corZoomedLayout.shape()[0];
94 // ensure that the expanded target tiles where the correlation is maximum fit within the
95 // search window
96 _nudge(maxcor, refDim, tgtDim);
97 // allocate room for the refinement area
98 auto refinedArena = _refinedArena();
99 // refine the reference tiles
100 _refRefine(coarseArena, refinedArena);
101 // collect the expanded maxcor tiles and migrate them to our new arena
102 _tgtMigrate(coarseArena, maxcor, refinedArena);
103 // refine the expanded target tiles in place
104 _tgtRefine(refinedArena);
105 // compute amplitudes
106 amplitudes = _detect(refinedArena, refRefinedDim, tgtRefinedDim);
107 // adjust the reference tiles to zero mean and compute the variances
108 refStatistics = _refStats(amplitudes, refRefinedDim, tgtRefinedDim);
109 // compute the sum area tables for all possible search window placements with the target tile
110 sat = _sat(amplitudes, refRefinedDim, tgtRefinedDim);
111 // use the SATs to compute the mean amplitude of all possible window placements
112 tgtStatistics = _tgtStats(sat, refRefinedDim, tgtRefinedDim, corRefinedDim);
113 // compute the correlation hyper-surface
114 gamma = _correlate(amplitudes, refStatistics, tgtStatistics,
115 refRefinedDim, tgtRefinedDim, corRefinedDim);
116 // zoom in
117 auto zoomed = _zoomcor(gamma);
118 // find its maxima
119 auto maxcorZoomed = _maxcor(zoomed, corZoomedDim);
120 // compute the shifts and return them
121 auto offsets = _offsetField(maxcorZoomed);
122
123 // clean up
124 delete [] maxcorZoomed;
125 delete [] maxcor;
126 delete [] zoomed;
127 delete [] gamma;
128 delete [] tgtStatistics;
129 delete [] sat;
130 delete [] refStatistics;
131 delete [] amplitudes;
132 delete [] refinedArena;
133
134 // all done
135 return offsets;
136}
137
138
139// accessors
140template <typename raster_t>
141auto
143arena() const -> cell_type *
144{
145 return _arena;
146}
147
148
149template <typename raster_t>
150auto
152pairs() const -> size_type
153{
154 return _pairs;
155}
156
157
158// meta-methods
159template <typename raster_t>
161~Sequential() {
162 // release the host memory
163 delete [] _arena;
164 delete [] _offsets;
165}
166
167
168template <typename raster_t>
170Sequential(size_type pairs,
171 const layout_type & refLayout, const layout_type & tgtLayout,
172 size_type refineFactor, size_type refineMargin, size_type zoomFactor) :
173 _pairs{ pairs },
174 _refineFactor{ refineFactor },
175 _refineMargin{ refineMargin },
176 _zoomFactor{ zoomFactor },
177 _refLayout{ refLayout },
178 _tgtLayout{ tgtLayout },
179 _corLayout{ tgtLayout.shape() - refLayout.shape() + index_type::fill(1) },
180 _refRefinedLayout{ refineFactor * _refLayout.shape() },
181 _tgtRefinedLayout{ refineFactor * (_refLayout.shape() + index_type::fill(2*refineMargin)) },
182 _corRefinedLayout{ index_type::fill(2*refineFactor*refineMargin+1) },
183 _corZoomedLayout { zoomFactor * _corRefinedLayout.shape() },
184 _refCells{ _refLayout.size() },
185 _tgtCells{ _tgtLayout.size() },
186 _corCells{ _corLayout.size() },
187 _refRefinedCells{ _refRefinedLayout.size() },
188 _tgtRefinedCells{ _tgtRefinedLayout.size() },
189 _refFootprint{ _refCells * sizeof(cell_type) },
190 _tgtFootprint{ _tgtCells * sizeof(cell_type) },
191 _corFootprint{ _corCells * sizeof(value_type) }, // the correlation matrix is real...
192 _refRefinedFootprint{ _refRefinedCells * sizeof(cell_type) },
193 _tgtRefinedFootprint{ _tgtRefinedCells * sizeof(cell_type) },
194 _arena{ new cell_type[ _pairs * (_refCells+_tgtCells) ] },
195 _offsets{ new value_type[ 2 * _pairs ] }
196{
197 // compute the footprints
198 auto footprint = _pairs*(_refFootprint + _tgtFootprint);
199 auto refinedFootprint = _pairs*(_refRefinedFootprint + _tgtRefinedFootprint);
200 // make a channel
201 pyre::journal::debug_t channel("ampcor");
202 // show me
203 channel
204 << pyre::journal::at(__HERE__)
205 << "new Sequential worker:"
206 << pyre::journal::newline
207 << " pairs: " << _pairs
208 << pyre::journal::newline
209 << " ref shape: " << _refLayout << ", " << _refCells << " cells"
210 << pyre::journal::newline
211 << " tgt shape: " << _tgtLayout << ", " << _tgtCells << " cells"
212 << pyre::journal::newline
213 << " footprint: " << (_refCells+_tgtCells) << " cells in "
214 << (footprint/1024/1024) << " Mb"
215 << pyre::journal::newline
216 << " refine factor: " << refineFactor
217 << pyre::journal::newline
218 << " refine margin: " << refineMargin
219 << pyre::journal::newline
220 << " refined ref shape: " << _refRefinedLayout << ", " << _refRefinedCells << " cells"
221 << pyre::journal::newline
222 << " refined tgt shape: " << _tgtRefinedLayout << ", " << _tgtRefinedCells << " cells"
223 << pyre::journal::newline
224 << " footprint: " << (_refRefinedCells+_tgtRefinedCells) << " cells in "
225 << (refinedFootprint/1024/1024) << " Mb"
226 << pyre::journal::newline
227 << " arena: " << _arena
228 << pyre::journal::endl;
229}
230
231
232// debugging support
233template <typename raster_t>
234void
236dump() const
237{
238 // dump the arena as a sequence of reference and target tiles
239 pyre::journal::debug_t channel("ampcor");
240
241 // sign in
242 channel << pyre::journal::at(__HERE__);
243 // go through all the pairs
244 for (auto pid = 0; pid < _pairs; ++pid) {
245 // inject the pid
246 channel << "pid: " << pid << pyre::journal::newline;
247 // compute the address of the reference tile in the arena
248 cell_type * refLoc = _arena + pid*(_refCells + _tgtCells);
249 // adapt it into a grid
250 tile_type ref(_refLayout, refLoc);
251 // inject it
252 channel << "reference: " << pyre::journal::newline;
253 for (auto idx = 0; idx < _refLayout.shape()[0]; ++idx) {
254 for (auto jdx = 0; jdx < _refLayout.shape()[1]; ++jdx) {
255 channel << ref[{idx, jdx}] << " ";
256 }
257 channel << pyre::journal::newline;
258 }
259
260 // compute the address of the target tile in the arena
261 cell_type * tgtLoc = refLoc + _refCells;
262 // adapt it into a grid
263 tile_type tgt(_tgtLayout, tgtLoc);
264
265 // inject it
266 channel << "target: " << pyre::journal::newline;
267 for (auto idx = 0; idx < _tgtLayout.shape()[0]; ++idx) {
268 for (auto jdx = 0; jdx < _tgtLayout.shape()[1]; ++jdx) {
269 channel << tgt[{idx, jdx}] << " ";
270 }
271 channel << pyre::journal::newline;
272 }
273
274 }
275 // sing off
276 channel << pyre::journal::endl;
277
278 // all done
279 return;
280}
281
282
283// implementation details: methods
284
285
286
287// compute the amplitude of the signal
288template <typename raster_t>
289auto
291_detect(const cell_type * cArena, size_type refDim, size_type tgtDim) const -> value_type *
292{
293 // compute the size of a reference tile
294 auto refCells = refDim * refDim;
295 // compute the size of a target tile
296 auto tgtCells = tgtDim * tgtDim;
297
298 // get a spot
299 value_type * rArena = nullptr;
300 // compute the number of cells whose amplitude we have to compute
301 auto cells = _pairs * (refCells + tgtCells);
302 // allocate room for it
303 rArena = new (std::nothrow) value_type[cells]();
304
305 // if something went wrong
306 if (rArena == nullptr) {
307 // make a channel
308 pyre::journal::error_t error("ampcor");
309 // complain
310 error
311 << pyre::journal::at(__HERE__)
312 << "Error while allocating memory for the tile amplitudes"
313 << pyre::journal::endl;
314 // and bail
315 throw std::bad_alloc();
316 }
317
318 // engage...
319 kernels::detect(cArena, cells, rArena);
320
321 // all done
322 return rArena;
323}
324
325
326
327// compute the mean and deviation of reference tiles and subtract the mean from
328// each reference pixel
329template <typename raster_t>
330auto
332_refStats(value_type * rArena, size_type refDim, size_type tgtDim) const -> value_type *
333{
334 // compute the size of a reference tile
335 auto refCells = refDim * refDim;
336 // compute the size of a target tile
337 auto tgtCells = tgtDim * tgtDim;
338
339 // grab a spot
340 value_type * stats = nullptr;
341 // allocate room for deviation: one number per reference tile
342 stats = new (std::nothrow) value_type[_pairs]();
343
344 // if something went wrong
345 if (stats == nullptr) {
346 // make a channel
347 pyre::journal::error_t error("ampcor");
348 // complain
349 error
350 << pyre::journal::at(__HERE__)
351 << "Error while allocating memory for the variances of "
352 << "the reference tiles "
353 << pyre::journal::endl;
354 // and bail
355 throw std::bad_alloc();
356 }
357
358 // engage
359 kernels::refStats(rArena, _pairs, refDim, refCells + tgtCells, stats);
360
361 // all done
362 return stats;
363}
364
365
366
367
368// build the sum area tables for the target tiles
369template <typename raster_t>
370auto
372_sat(const value_type * rArena, size_type refDim, size_type tgtDim) const -> value_type *
373{
374
375 // compute the size of a reference tile
376 auto refCells = refDim * refDim;
377 // compute the size of a target tile
378 auto tgtCells = tgtDim * tgtDim;
379
380 // grab a spot for the sat tables
381 value_type * sat = nullptr;
382 // allocate memory
383 sat = new (std::nothrow) value_type[_pairs*tgtCells]();
384
385 // if something went wrong
386 if (sat == nullptr) {
387 // make a channel
388 pyre::journal::error_t error("ampcor");
389 // complain
390 error
391 << pyre::journal::at(__HERE__)
392 << "Error while allocating memory for the sum area tables "
393 << pyre::journal::endl;
394 // and bail
395 throw std::bad_alloc();
396 }
397
398 // engage
399 kernels::sat(rArena, _pairs, refCells, tgtCells, tgtDim, sat);
400
401 // all done
402 return sat;
403}
404
405
406// compute the average values for all possible placements of the reference shape within the
407// target tile
408template <typename raster_t>
409auto
411_tgtStats(const value_type * dSAT,
412 size_type refDim, size_type tgtDim, size_type corDim) const -> value_type *
413{
414 // pick a spot for the table of amplitude averages
415 value_type * stats = nullptr;
416 // allocate memory: one mean per placement per target tile
417 stats = new (std::nothrow) value_type[_pairs*corDim*corDim];
418
419 // if something went wrong
420 if (stats == nullptr) {
421 // make a channel
422 pyre::journal::error_t error("ampcor");
423 // complain
424 error
425 << pyre::journal::at(__HERE__)
426 << "Error while allocating memory for the table of target amplitude averages "
427 << pyre::journal::endl;
428 // and bail
429 throw std::bad_alloc();
430 }
431
432 // engage
433 kernels::tgtStats(dSAT, _pairs, refDim, tgtDim, corDim, stats);
434
435 // all done
436 return stats;
437}
438
439
440// compute the correlation surface
441template <typename raster_t>
442auto
444_correlate(const value_type * rArena,
445 const value_type * refStats, const value_type * tgtSat,
446 size_type refDim, size_type tgtDim, size_type corDim) const -> value_type *
447{
448
449 // compute the size of the reference tile
450 auto refCells = refDim * refDim;
451 // compute the size of the target tile
452 auto tgtCells = tgtDim * tgtDim;
453 // compute the size of the correlation matrix
454 auto corCells = corDim * corDim;
455
456 // pick a spot for the correlation matrix
457 value_type * dCorrelation = nullptr;
458 // compute the total number of cells in the amplitude hyper-grid
459 auto size = _pairs * corCells;
460 // allocate memory on the device
461 dCorrelation = new (std::nothrow) value_type[size]();
462
463 // if something went wrong
464 if (dCorrelation == nullptr) {
465 // make a channel
466 pyre::journal::error_t error("ampcor");
467 // complain
468 error
469 << pyre::journal::at(__HERE__)
470 << "Error while allocating memory for the correlation matrix "
471 << pyre::journal::endl;
472 // and bail
473 throw std::bad_alloc();
474 }
475
476 // engage
477 kernels::correlate(rArena, refStats, tgtSat,
478 _pairs,
479 refCells, tgtCells, corCells, refDim, tgtDim, corDim,
480 dCorrelation);
481
482 // all done
483 return dCorrelation;
484}
485
486
487// find the locations of the correlation maxima
488template <typename raster_t>
489auto
491_maxcor(const value_type * gamma, size_type corDim) const -> int *
492{
493
494 // compute the size of the correlation matrix
495 auto corCells = corDim * corDim;
496
497 // find a spot
498 int * loc = nullptr;
499 // allocate memory on the device
500 loc = new (std::nothrow) int[2 * _pairs]();
501 // if something went wrong
502 if (loc == nullptr) {
503 // make a channel
504 pyre::journal::error_t error("ampcor");
505 // complain
506 error
507 << pyre::journal::at(__HERE__)
508 << "Error while allocating device memory for the location of the correlation maxima "
509 << pyre::journal::endl;
510 // and bail
511 throw std::bad_alloc();
512 }
513
514 // engage
515 kernels::maxcor(gamma, _pairs, corCells, corDim, loc);
516
517 // all done
518 return loc;
519}
520
521
522// adjust the locations of the correlation maxima so that the new target tiles fit within the
523// search window
524template <typename raster_t>
525void
527_nudge(int * locations, size_type refDim, size_type tgtDim) const
528{
529 // make sure that all locations are adjusted so that they allow enough room for the
530 // {refineMargin} by moving the ULHC of the tiles so they fit
531 kernels::nudge(_pairs, refDim, tgtDim, _refineMargin, locations, _offsets);
532
533 // all done
534 return;
535}
536
537
538// allocate room for the refined tiles
539template <typename raster_t>
540auto
542_refinedArena() const -> cell_type *
543{
544 // grab a spot
545 cell_type * arena = nullptr;
546 // allocate room for it
547 arena = new (std::nothrow) cell_type[_pairs * (_refRefinedFootprint + _tgtRefinedFootprint)]();
548 // if something went wrong
549 if (arena == nullptr) {
550 // make a channel
551 pyre::journal::error_t error("ampcor");
552 // complain
553 error
554 << pyre::journal::at(__HERE__)
555 << "while allocating memory for the refined tile hyper-grid "
556 << pyre::journal::endl;
557 // and bail
558 throw std::bad_alloc();
559 }
560
561 // all done
562 return arena;
563}
564
565
566// refine the reference tiles
567template <typename raster_t>
568void
570_refRefine(cell_type * coarseArena, cell_type * refinedArena) const
571{
572 // make a channel
573 pyre::journal::debug_t channel("ampcor");
574
575 // get the shape the reference tile
576 auto rshape = _refLayout.shape();
577 // and the shape of the refined tile
578 auto tshape = _refRefinedLayout.shape();
579
580
581 // get number of threads. omp_get_max_threads is sometimes problematic.
582 size_t nthreads=0;
583 #pragma omp parallel reduction(+:nthreads)
584 nthreads += 1;
585
586 // step 1: initiate FFT processor
587 isce3::signal::Signal<float> * procFFT = nullptr;
588 procFFT = new (std::nothrow) isce3::signal::Signal<float>(nthreads);
589
590 // if something went wrong
591 if (procFFT == nullptr) {
592 // make a channel
593 pyre::journal::error_t error("ampcor");
594 // complain
595 error
596 << pyre::journal::at(__HERE__)
597 << "while instanciating a isce3::signal::Signal FFT processor"
598 << pyre::journal::endl;
599 // and bail
600 throw std::runtime_error("while instanciating a isce3::signal::Signal FFT processor");
601 }
602
603
604 // step 2: forward FFT from {coarseArena} to {refinedArena}
605 // the plan characteristics
606 int dim = 2;
607 int fwdRanks[] = { static_cast<int>(rshape[0]), static_cast<int>(rshape[1]) };
608 // the data layout of the coarse tiles
609 // the tile shape stays the same
610 int fwdIEmbed[] = { static_cast<int>(rshape[0]), static_cast<int>(rshape[1]) };
611 // the data is densely packed
612 int fwdIStride = 1;
613 // the distance between reference tiles
614 int fwdIDist = _refCells + _tgtCells;
615 // the data layout of the refined tiles
616 // the tile shape stays the same
617 int fwdOEmbed[] = { static_cast<int>(tshape[0]), static_cast<int>(tshape[1]) };
618 // the data is densely packed
619 int fwdOStride = 1;
620 // the distance between reference tiles in the refined arena
621 int fwdODist = _refRefinedCells + _tgtRefinedCells;
622
623 // Set the FFT forward plan for upsampling reference tiles
624 // This involves out-of-place FFT
625 procFFT->fftPlanForward(reinterpret_cast<std::complex<float> *>(coarseArena),
626 reinterpret_cast<std::complex<float> *>(refinedArena),
627 dim, fwdRanks, _pairs,
628 fwdIEmbed, fwdIStride, fwdIDist,
629 fwdOEmbed, fwdOStride, fwdODist, -1);
630
631
632
633
634 // step 3: inverse FFT of the tiles back into the refined arena
635 // the plan characteristics
636 int revRanks[] = { static_cast<int>(tshape[0]), static_cast<int>(tshape[1]) };
637 // the data layout of the transformed reference tiles
638 int revIEmbed[] = { static_cast<int>(tshape[0]), static_cast<int>(tshape[1]) };
639 // the data is densely packed
640 int revIStride = 1;
641 // the distance between reference tiles
642 int revIDist = _refRefinedCells + _tgtRefinedCells;
643 // the inverse FFT tiles have identical layout
644 int revOEmbed[] = { static_cast<int>(tshape[0]), static_cast<int>(tshape[1]) };
645 // the data is densely packed
646 int revOStride = 1;
647 // the distance between reference tiles
648 int revODist = _refRefinedCells + _tgtRefinedCells;
649
650 procFFT->fftPlanBackward(reinterpret_cast<std::complex<float> *>(refinedArena),
651 reinterpret_cast<std::complex<float> *>(refinedArena),
652 //dummy,
653 dim, revRanks, _pairs,
654 revIEmbed, revIStride, revIDist,
655 revOEmbed, revOStride, revODist, 1);
656
657
658 // step 4: Actual refinement (upsampling) of the reference tiles:
659 // FFT -> frequencies shuffling -> back FFT
660 procFFT->upsample2D(reinterpret_cast<std::complex<float> *>(coarseArena),
661 reinterpret_cast<std::complex<float> *>(refinedArena),
662 _refineFactor);
663
664 // cleaning
665 delete procFFT;
666
667 // all done
668 return;
669
670}
671
672
673
674
675
676// migrate the expanded unrefined target tiles into the {refinedArena}
677template <typename raster_t>
678void
680_tgtMigrate(cell_type * coarseArena, int * locations, cell_type * refinedArena) const
681{
682 // make a channel
683 pyre::journal::debug_t channel("ampcor");
684
685 // the reference tile shape
686 auto refShape = _refLayout.shape();
687 // the target tile shape
688 auto tgtShape = _tgtLayout.shape();
689 // the refined reference tile shape
690 auto refRefinedShape = _refRefinedLayout.shape();
691 // the refined target tile shape
692 auto tgtRefinedShape = _tgtRefinedLayout.shape();
693
694 // unpack the dimensions
695 auto refDim = refShape[0];
696 auto tgtDim = tgtShape[0];
697 auto refRefinedDim = refRefinedShape[0];
698 auto tgtRefinedDim = tgtRefinedShape[0];
699
700 // compute the dimension of the expanded maxcor tile
701 auto expDim = refDim + 2 * _refineMargin;
702
703 // engage...
704 kernels::migrate(coarseArena, _pairs,
705 refDim, tgtDim, expDim,
706 refRefinedDim, tgtRefinedDim,
707 locations,
708 refinedArena);
709
710 // all done
711 return;
712}
713
714
715// refine the target tiles around the locations of the correlation maxima
716template <typename raster_t>
717void
719_tgtRefine(cell_type * refinedArena) const
720{
721 // N.B.: assumes {locations} are already nudged and on the CPU...
722 // make a channel
723 pyre::journal::debug_t channel("ampcor");
724
725 // the shape of the target tile
726 //auto tgtShape = _tgtLayout.shape();
727 // the shape the refined target tile
728 auto tgtRefShape = _tgtRefinedLayout.shape();
729 // the shape of the expanded target tile
730 auto expShape = _refLayout.shape() + index_type::fill(2*_refineMargin);
731
732 // N.B.: the expanded maxcor target tiles are expected to have already been moved to the
733 // refined arena after the maxcor locations were determined
734
735
736 // get number of threads. omp_get_max_threads is sometimes problematic.
737 size_t nthreads=0;
738 #pragma omp parallel reduction(+:nthreads)
739 nthreads += 1;
740
741 // step 1: initiate FFT processor
742 isce3::signal::Signal<float> * procFFT = nullptr;
743 procFFT = new (std::nothrow) isce3::signal::Signal<float>(nthreads);
744
745 // if something went wrong
746 if (procFFT == nullptr) {
747 // make a channel
748 pyre::journal::error_t error("ampcor");
749 // complain
750 error
751 << pyre::journal::at(__HERE__)
752 << "while instanciating a isce3::signal::Signal FFT processor"
753 << pyre::journal::endl;
754 // and bail
755 throw std::runtime_error("while instanciating a isce3::signal::Signal FFT processor");
756 }
757
758
759
760 // step 2: forward FFT in place in {refinedArena}
761 // the plan characteristics
762 int dim = 2;
763 // use the shape of the expanded target tile
764 int fwdRanks[] = { static_cast<int>(expShape[0]), static_cast<int>(expShape[1]) };
765 // this tile is already occupying its destination location in {refinedArena}
766 int fwdIEmbed[] = { static_cast<int>(tgtRefShape[0]), static_cast<int>(tgtRefShape[1]) };
767 // the data is dense
768 int fwdIStride = 1;
769 // the distance between tiles
770 int fwdIDist = _refRefinedCells + _tgtRefinedCells;
771 // the destination of the forward FFT has indentical layout
772 int fwdOEmbed[] = { static_cast<int>(tgtRefShape[0]), static_cast<int>(tgtRefShape[1]) };
773 // the data is dense
774 int fwdOStride = 1;
775 // the distance between tiles
776 int fwdODist = _refRefinedCells + _tgtRefinedCells;
777
778 // the address of the first expanded target tile
779 auto firstTile = reinterpret_cast<std::complex<float> *>(refinedArena + _refRefinedCells);
780
781 procFFT->fftPlanForward(firstTile, firstTile,
782 dim, fwdRanks, _pairs,
783 fwdIEmbed, fwdIStride, fwdIDist,
784 fwdOEmbed, fwdOStride, fwdODist, -1);
785
786
787
788 // step 3: inverse FFT of the refined tiles back into the refined arena
789 // the plan characteristics
790 int revRanks[] = { static_cast<int>(tgtRefShape[0]), static_cast<int>(tgtRefShape[1]) };
791 // the data layout of the transformed reference tiles
792 int revIEmbed[] = { static_cast<int>(tgtRefShape[0]), static_cast<int>(tgtRefShape[1]) };
793 // the data is densely packed
794 int revIStride = 1;
795 // the distance between reference tiles
796 int revIDist = _refRefinedCells + _tgtRefinedCells;
797 // the inverse FFT tiles have identical layout
798 int revOEmbed[] = { static_cast<int>(tgtRefShape[0]), static_cast<int>(tgtRefShape[1]) };
799 // the data is densely packed
800 int revOStride = 1;
801 // the distance between reference tiles
802 int revODist = _refRefinedCells + _tgtRefinedCells;
803
804 procFFT->fftPlanBackward(firstTile, firstTile,
805 dim, revRanks, _pairs,
806 revIEmbed, revIStride, revIDist,
807 revOEmbed, revOStride, revODist, 1);
808
809
810 // step4: Upsample!
811 procFFT->upsample2D(firstTile, firstTile, _refineFactor);
812
813
814 // no need of plan anymore
815 delete procFFT;
816
817 // all done
818 return;
819
820}
821
822
823
824
825
826
827
828
829// zoom the correlation matrix
830template <typename raster_t>
831auto
833_zoomcor(value_type * gamma) const -> value_type *
834{
835 // make a channel
836 pyre::journal::debug_t channel("ampcor");
837
838 // get the shape of the incoming correlation matrix
839 auto corShape = _corRefinedLayout.shape();
840 // extract the dimension
841 int corDim = corShape[0];
842 // get the shape of the zoomed correlation matrix
843 auto zmdShape = _corZoomedLayout.shape();
844 // compute the number if cells in each zoomed correlation matrix
845 auto zmdCells = _corZoomedLayout.size();
846 // extract the dimension
847 int zmdDim = zmdShape[0];
848
849 // step 1: up-cast and embed
850 auto scratch = kernels::r2c(gamma, _pairs, corDim, zmdDim);
851
852
853 // step 2: forward FFT from the incoming gamma to the zoomed gamma
854 // the plan characteristics
855 int dim = 2;
856 int ranks[] = { corDim, corDim };
857 // the input layout
858 int iEmbed[] = { zmdDim, zmdDim };
859 // the data is densely packed
860 int iStride = 1;
861 // the distance between correlation matrices
862 int iDist = zmdCells;
863 // the output layout
864 int oEmbed[] = { zmdDim, zmdDim };
865 // the data is densely packed
866 int oStride = 1;
867 // the distance between successive correlation matrices
868 int oDist = zmdCells;
869
870 // get number of threads. omp_get_max_threads is sometimes problematic.
871 size_t nthreads=0;
872 #pragma omp parallel reduction(+:nthreads)
873 nthreads += 1;
874
875 // step 3: initiate FFT processor
876 isce3::signal::Signal<float> * procFFT = nullptr;
877 procFFT = new (std::nothrow) isce3::signal::Signal<float>(nthreads);
878
879 // if something went wrong
880 if (procFFT == nullptr) {
881 // make a channel
882 pyre::journal::error_t error("ampcor");
883 // complain
884 error
885 << pyre::journal::at(__HERE__)
886 << "while instanciating a isce3::signal::Signal FFT processor"
887 << pyre::journal::endl;
888 // and bail
889 throw std::runtime_error("while instanciating a isce3::signal::Signal FFT processor");
890 }
891
892
893 // Forward FFT plan - in-place transformation
894 procFFT->fftPlanForward(scratch, scratch,
895 dim, ranks, _pairs,
896 iEmbed, iStride, iDist,
897 oEmbed, oStride, oDist, -1);
898
899 // Reverse FFT plan - in-place transformation
900 ranks[0] = zmdDim;
901 ranks[1] = zmdDim;
902 procFFT->fftPlanBackward(scratch, scratch,
903 dim, ranks, _pairs,
904 oEmbed, oStride, oDist,
905 oEmbed, oStride, oDist, 1);
906
907 // Upsample the correlation map
908 // fwd FFT then spectrum shuffling then rev FFT
909 procFFT->upsample2D(scratch, scratch, _zoomFactor);
910
911
912 // no need of plan anymore
913 delete procFFT;
914
915 // Convert complex to real
916 auto zoomed = kernels::c2r(scratch, _pairs, zmdDim);
917
918 // clean up
919 delete scratch;
920
921 // all done
922 return zoomed;
923}
924
925
926
927
928// assemble the offsets
929template <typename raster_t>
930auto
932_offsetField(const int * fine) -> const value_type *
933{
934 // compute the search margin
935 auto margin = (_tgtLayout.shape()[0] - _refLayout.shape()[0]) / 2;
936 // compute the overall zoom factor
937 auto zoom = _refineFactor * _zoomFactor;
938
939 // launch the kernel that does the work
940 kernels::offsetField(fine, _pairs, margin, _refineMargin, zoom, _offsets);
941
942 // all done
943 return _offsets;
944}
945
946
947
948// end of file
Definition Sequential.h:18
A class to handle 2D FFT or 1D FFT in range or azimuth directions.
Definition Signal.h:22
void fftPlanForward(std::valarray< std::complex< T > > &input, std::valarray< std::complex< T > > &output, int rank, int *n, int howmany, int *inembed, int istride, int idist, int *onembed, int ostride, int odist, int sign)
initiate forward FFTW3 plan for a block of complex data input parameters follow FFTW3 interface for f...
Definition Signal.cpp:39
void fftPlanBackward(std::valarray< std::complex< T > > &input, std::valarray< std::complex< T > > &output, int rank, int *n, int howmany, int *inembed, int istride, int idist, int *onembed, int ostride, int odist, int sign)
initiate iverse FFTW3 plan for a block of spectrum input parameters follow FFTW3 interface for fftw_p...
Definition Signal.cpp:164
void upsample2D(std::valarray< std::complex< T > > &signal, std::valarray< std::complex< T > > &signalOversampled, int oversampleFactor)
2D upsampling a block of 2D data
Definition Signal.cpp:1097

Generated for ISCE3.0 by doxygen 1.13.2.