source: trunk/Mars/mhft/MHexagonalFT.cc@ 12704

Last change on this file since 12704 was 5691, checked in by tbretz, 20 years ago
*** empty log message ***
File size: 14.7 KB
Line 
1/* ======================================================================== *\
2!
3! *
4! * This file is part of MARS, the MAGIC Analysis and Reconstruction
5! * Software. It is distributed to you in the hope that it can be a useful
6! * and timesaving tool in analysing Data of imaging Cerenkov telescopes.
7! * It is distributed WITHOUT ANY WARRANTY.
8! *
9! * Permission to use, copy, modify and distribute this software and its
10! * documentation for any purpose is hereby granted without fee,
11! * provided that the above copyright notice appear in all copies and
12! * that both that copyright notice and this permission notice appear
13! * in supporting documentation. It is provided "as is" without express
14! * or implied warranty.
15! *
16!
17!
18! Author(s): Christoph Kolodziejski, 11/2004 <mailto:>
19! Author(s): Thomas Bretz, 11/2004 <mailto:tbretz@astro.uni-wuerzburg.de>
20!
21! Copyright: MAGIC Software Development, 2004-2005
22!
23!
24\* ======================================================================== */
25
26//////////////////////////////////////////////////////////////////////////////
27//
28// MHexagonalFT
29//
30// This is a class representating a (fast) fourier transformation explicitly
31// for hexagonal geometries as described in astro-ph/0409388.
32//
33//
34// WARNING:
35// ========
36// Be carefull using the fast transformation (Prepare())! The precalculation
37// consumes a lot of memory. fPsi has the size of 2*n^4 (while n is the
38// number of rows in fourier space). For the enhanced MAGIC camery fPsi has
39// the size 27691682*sizeof(float) = 105.6MB (Std MAGIC: ~12MB)
40//
41// The runtime is more or less determined by the speed of accessing a
42// huge amount of memory (see above) sequentially.
43//
44//
45// Coordinate systems:
46// ===================
47//
48// original hexagonal structure enhanced hexagonal structure
49// ---------------------------- ----------------------------
50//
51// structure
52// ---------
53//
54// h h h f f h h h f f
55// h h h h f h h h h f
56// h h h h h -----> h h h h h
57// h h h h h h h h
58// h h h h h h
59// f f
60// f
61//
62// numbering
63// ---------
64// d c b m n o p q r s
65// e 4 3 a g h i j k l
66// f 5 1 2 9 -----> b c d e f
67// g 6 7 8 7 8 9 a
68// h i j 4 5 6
69// 2 3
70// 1
71//
72// In reality the fourier space looks like because of symmetries:
73//
74// real part imaginary part
75// --------- --------------
76// m n o p o n m m n o 0 -o -n -m
77// g h i i h g g h i -i -h -g
78// b c d c b b c 0 -c -b
79// 7 8 8 7 7 8 -8 -7
80// 4 5 4 4 0 -4
81// 2 2 2 -2
82// 1 0
83//
84// column: GetK() row: GetM()
85// -------------- -----------
86// 6 5 4 3 2 1 0 0 1 2 3 4 5 6
87// 5 4 3 2 1 0 0 1 2 3 4 5
88// 4 3 2 1 0 0 1 2 3 4
89// 3 2 1 0 0 1 2 3
90// 2 1 0 0 1 2
91// 1 0 0 1
92// 0 0
93//
94// row: GetRow() (m+k) column: GetCol() (m-k)
95// ------------------- ----------------------
96// 6 6 6 6 6 6 6 -6 -4 -2 0 2 4 6
97// 5 5 5 5 5 5 -5 -3 -1 1 3 5
98// 4 4 4 4 4 -4 -2 0 2 4
99// 3 3 3 3 -3 -1 1 3
100// 2 2 2 -2 0 2
101// 1 1 -1 1
102// 0 0
103//
104//
105// The coordinates of the pixels in the triangle are:
106//
107// Double_t dx; // Distance of too pixels in x
108// Double_t dy; // Distance of to pixel rows in y
109// Int_t idx; // Index of pixel in triangle (see above)
110//
111// const Float_t x = dx*GetCol(idx);
112// const Float_t y = dy*Int_t(GetRow(idx)-2*GetNumRows()/3);
113//
114// You can use MGeomCam::GetPixelIdxXY(x, y) to get the corresponding index
115// in space space.
116//
117//////////////////////////////////////////////////////////////////////////////
118#include "MHexagonalFT.h"
119
120#include <TMath.h>
121
122#include "MLog.h"
123#include "MLogManip.h"
124
125#include "MArrayD.h"
126
127ClassImp(MHexagonalFT);
128
129using namespace std;
130
131// ---------------------------------------------------------------------------
132//
133// Default Constructor - empty
134//
135MHexagonalFT::MHexagonalFT()
136{
137}
138
139// ---------------------------------------------------------------------------
140//
141// Default Constructor - num is the number of lines the fourier space has.
142// It calls Prepare to fill the arrays with the necessary coefficients.
143//
144// Here are some simple rules to calculate parameters in a hexagonal space:
145//
146// Number of Rings (r) ---> Number of Pixels (p)
147// p = 3*r*(r-1)+1
148//
149// Number of Pixels (p) ---> Number of Rings (r)
150// p = (sqrt(9+12*(p-1))+3)/6
151//
152// Number of pixels at one border == number of rings (r)
153// Row of border == number of rings (r)
154//
155// Number of rows to get a triangle: 3r-2
156//
157MHexagonalFT::MHexagonalFT(Int_t num)
158{
159 Prepare(num);
160}
161
162// ---------------------------------------------------------------------------
163//
164// Calculate the contents of: fM, fK, fP, fIdx and fPsi.
165//
166// While fPsi are the fourier coefficients, fM and fK are the hexagonal x and
167// y coordinates of the pixel corresponding to the index i which is the
168// common index of all arrays. fP is P(i,j) for all pixels.
169//
170// fIdx is also filled and used for reverse mapping. Due to the geometry
171// the right and left side of the fourier space triangle has identical
172// values. fIdx 'maps' the indices from the right to the left side.
173//
174void MHexagonalFT::Prepare(Int_t num)
175{
176 fNumRows = num;
177
178 fPsi.Set(num*num*num*num*2);
179
180 Int_t lim = num*(num+1)/2;
181
182 fM.Set(lim);
183 fK.Set(lim);
184 fP.Set(lim);
185 fIdx.Set(lim);
186
187 for(int j=0; j<num; j++)
188 {
189 for(int n=0; n+j<num; n++)
190 {
191 int idx1 = (j+n)*(j+n+1)/2 + j;
192
193 fM[idx1]=n;
194 fK[idx1]=j;
195
196 fP[idx1]=P(j,n);
197
198 for(int k=0; k<num; k++)
199 {
200 for(int m=0; m+k<num; m++)
201 {
202 const Double_t dx = TMath::Pi()*(m-k)/(num-1)/3;
203 const Double_t dy = TMath::Pi()*(m+k)/(num-1);
204
205 const Double_t cos1 = TMath::Cos(dy*(j+n));
206 const Double_t cos2 = TMath::Cos(dy*j);
207 const Double_t cos3 = TMath::Cos(dy*n);
208
209 const Double_t psire = 2*(
210 +cos1*TMath::Cos(dx*(j-n))
211 +cos2*TMath::Cos(dx*(j+2*n))
212 +cos3*TMath::Cos(dx*(2*j+n)));
213
214 const Double_t psiim = 2*(
215 +cos1*TMath::Sin(dx*(j-n))
216 +cos2*TMath::Sin(dx*(j+2*n))
217 -cos3*TMath::Sin(dx*(2*j+n)));
218
219 const Int_t idx3 = (k+m)*(k+m+1)/2 + k;
220 const Int_t id1 = idx1*lim + idx3;
221
222 fPsi[id1*2] = psire;
223 fPsi[id1*2+1] = psiim;
224 }
225 }
226 }
227 }
228
229 for (int idx1=0; idx1<lim; idx1++)
230 {
231 int n = fM[idx1];
232 int j = fK[idx1];
233
234 int idx0;
235 for (idx0=0; idx0<lim; idx0++)
236 if (fM[idx0]==j && fK[idx0]==n)
237 break;
238
239 fIdx[idx1]=idx0;
240 }
241
242}
243
244// ---------------------------------------------------------------------------
245//
246// Do a fast forward tranformation. Because all coefficients are
247// precalculated, the tranformation is reduced to a simple pointer based
248// loop over the coeffiecients multiplied with the corresponding input
249// values.
250//
251// Parameters:
252// inre: array storing the real part of the input (eg. pixel contents)
253// outre: array storing the real part of the output
254// outim: array storing the imaginary part of the output
255//
256// inre must be of the size of the fourier space triangle. The pixel
257// contents must have been mapped into this new space with the proper
258// pixel indices. The size of outre and outim is set accordingly.
259//
260// After initialization (Prepare()) you can get the size of the arrays with
261// GetNumKnots()
262//
263// For the definition of the coordinate system see class description
264//
265void MHexagonalFT::TransformFastFWD(const MArrayD &inre, MArrayD &outre,
266 MArrayD &outim) const
267{
268 const UInt_t num = fP.GetSize();
269
270 if (inre.GetSize()!=num)
271 {
272 cout << "ERROR - MHexagonalFT prepared for different size." << endl;
273 return;
274 }
275
276 outre.Set(num);
277 outim.Set(num);
278
279 const Int_t cnt = 108*(fNumRows-1)*(fNumRows-1);
280
281 const Float_t *endp = fP.GetArray()+num;
282
283 for (UInt_t idx1=0; idx1<num; idx1++)
284 {
285 if (fK[idx1]>fM[idx1])
286 continue;
287
288 Double_t sumre=0;
289 Double_t sumim=0;
290
291 Float_t *psi = fPsi.GetArray() + idx1*num*2;
292 Float_t *p = fP.GetArray();
293 Double_t *re = inre.GetArray();
294
295 // 1st access to psi: const Float_t psire = *psi++;
296 // 2nd access to psi: const Float_t psiim = *psi++;
297 // sumre += f * *psire;
298 // sumim += f * *psiim;
299 while (p<endp)
300 {
301 const Double_t f = *p++ * *re++;
302
303 sumre += f * *psi++;
304 sumim += f * *psi++;
305 }
306
307 const Double_t factor2 = fP[idx1]/cnt;
308
309 outre[fIdx[idx1]] = (outre[idx1] = factor2 * sumre);
310 outim[fIdx[idx1]] = -(outim[idx1] = -factor2 * sumim);
311 }
312}
313
314// ---------------------------------------------------------------------------
315//
316// Do a fast backward tranformation. Because all coefficients are
317// precalculated, the tranformation is reduced to a simple pointer based
318// loop over the coeffiecients multiplied with the corresponding input
319// values.
320//
321// Parameters:
322// inre: outre of TransformFastBwd
323// inim: outim of TransformFastBwd
324// outre: backward tranformed real part of the resulting
325//
326// inre and inim must be of the size of the fourier space triangle. The
327// pixel contents must have been mapped into this new space with the proper
328// pixel indices. The size of outre is set accordingly.
329//
330// After initialization (Prepare()) you can get the size of the arrays with
331// GetNumKnots()
332//
333// For the definition of the coordinate system see class description
334//
335void MHexagonalFT::TransformFastBWD(const MArrayD &inre, const MArrayD &inim,
336 MArrayD &outre) const
337{
338 const UInt_t num = fP.GetSize();
339
340 // Sanity check: check size of arrays
341 if (inre.GetSize()!=num)
342 {
343 cout << "ERROR - MHexagonalFT prepared for different size." << endl;
344 return;
345 }
346 if (inim.GetSize()!=num)
347 {
348 cout << "ERROR - MHexagonalFT prepared for different size." << endl;
349 return;
350 }
351 outre.Set(num);
352
353 const Double_t *endre = inre.GetArray()+num;
354
355 for (UInt_t idx1=0; idx1<num; idx1++)
356 {
357 Float_t *psi = fPsi.GetArray() + idx1*num*2;
358 Double_t *im = inim.GetArray();
359 Double_t *re = inre.GetArray();
360
361 Double_t sumre=0;
362 while (re<endre)
363 {
364 const Float_t psire = *psi++;
365 const Float_t psiim = *psi++;
366
367 sumre += *re++ * psire - *im++ * psiim;
368 }
369
370 outre[idx1] = sumre;
371 }
372}
373
374// ---------------------------------------------------------------------------
375//
376// This is a slow (direct) version of the tranformation. It is identical
377// for forward and backward tranformation.
378//
379// The whole calculation is done straight forward without any precalculation.
380//
381// Parameters:
382// inre: real part of input
383// inim: imaginary part of input
384// outre: real part of output
385// outim: imaginary part of output
386// fwd: kTRUE for forward, kFALSE for backward transformations
387//
388// After initialization (Prepare()) you can get the size of the arrays with
389// GetNumKnots()
390//
391// For the definition of the coordinate system see class description
392//
393// It is currently not tested!
394//
395void MHexagonalFT::TransformSlow(const MArrayD &inre, const MArrayD &inim,
396 MArrayD &outre, MArrayD &outim,
397 Bool_t fwd)
398{
399 static const Double_t fgSqrt3 = TMath::Sqrt(3.);
400 static const Double_t fgTan30 = TMath::Tan(30*TMath::DegToRad())*3;
401
402 Int_t num = (Int_t)TMath::Sqrt((Float_t)inim.GetSize());
403 Int_t cnt = 108*(num-1)*(num-1);
404 Int_t inv = fwd?-1:1;
405
406 // FIXME: For p(j,n)
407 fNumRows = num;
408
409 for(int j=0; j<num; j++)
410 {
411 for(int n=0; n+j<num; n++)
412 {
413 if (j-n>0 && fwd)
414 continue;
415
416 Double_t sumre=0;
417 Double_t sumim=0;
418
419 for(int k=0; k<num; k++)
420 {
421 for(int m=0; m+k<num; m++)
422 {
423 Double_t dx = 0.5*(m-k)/num;
424 Double_t dy = 0.5*(m+k)/num*fgTan30;
425
426 dx *= TMath::TwoPi()/3;
427 dy *= TMath::TwoPi()/fgSqrt3;
428
429 const Double_t cos1 = TMath::Cos(dy*(j+n));
430 const Double_t cos2 = TMath::Cos(dy*j);
431 const Double_t cos3 = TMath::Cos(dy*n);
432
433 //Alternatie nach Paper:
434 const Double_t psire = 2*(
435 +cos1*TMath::Cos(dx*(j-n))
436 +cos2*TMath::Cos(dx*(j+2*n))
437 +cos3*TMath::Cos(dx*(2*j+n)));
438
439 const Double_t psiim = 2*inv*(
440 +cos1*TMath::Sin(dx*(j-n))
441 +cos2*TMath::Sin(dx*(j+2*n))
442 -cos3*TMath::Sin(dx*(2*j+n)));
443
444 const Double_t factor = (fwd==1?P(k,m):1.);
445
446 sumre += factor * (inre[k*num+m]*psire - inim[k*num+m]*psiim);
447 sumim += factor * (inre[k*num+m]*psiim + inim[k*num+m]*psire);
448 }
449 }
450
451 const Double_t factor = (fwd==1?P(j,n)/cnt:1.);
452
453 outre[j*num+n] = factor * sumre;
454 outim[j*num+n] = factor * sumim;
455
456 if (fwd)
457 {
458 outre[n*num+j] = factor * sumre;
459 outim[n*num+j] = -factor * sumim;
460 }
461 }
462 }
463}
464
465
Note: See TracBrowser for help on using the repository browser.