CHROMA
sftmom.cc
Go to the documentation of this file.
1 // $Id: sftmom.cc,v 3.9 2009-02-17 16:33:38 edwards Exp $
2 // $Log: sftmom.cc,v $
3 // Revision 3.9 2009-02-17 16:33:38 edwards
4 // Added a function that will return the multiplicity of a particular mom id.
5 // This is number of equiv. canonical mom. Only non-zero when mom averaging
6 // is enabled. Can use this to undo the averaging.
7 //
8 // Revision 3.8 2008/12/21 21:03:43 edwards
9 // Moved include of chromabase into the .h file.
10 //
11 // Revision 3.7 2008/08/18 18:23:56 jbulava
12 // Added an additional constructor to sftmom class that allows a list of momenta
13 // to be calculated rather than all momenta less that a max value.
14 //
15 // Revision 3.6 2007/08/23 21:28:31 edwards
16 // Bug fix. Removed some invalid uses of resize within a multi2d.
17 //
18 // Revision 3.5 2007/08/01 19:33:14 edwards
19 // Removed check for origin_offset must be zero in case of momentum averaging.
20 // The check is not needed. The phase of the origin is removed in the correct
21 // way no matter whether the phases are added together or not.
22 //
23 // Revision 3.4 2007/06/21 18:18:55 edwards
24 // Added subset versions of "sft" function.
25 //
26 // Revision 3.3 2007/06/12 16:10:01 edwards
27 // Added a default constructor.
28 //
29 // Revision 3.2 2006/08/30 02:10:19 edwards
30 // Technically a bug fix. The test for a zero_offset should only be in directions
31 // not in the fourier transform. E.g., there was a missing test of mu==decay_dir.
32 //
33 // Revision 3.1 2006/08/19 19:29:33 flemingg
34 // Changed the interface of the slow Fourier transform (SftMom) class to allow
35 // for any lattice point to be chosen as the spatial origin. Previously, this
36 // meant that the origin was always implicitly (0,0,0,0), which lead to
37 // various phase problems. One example is 2pt correlation functions between a
38 // point source not at the origin and a sink at non-zero momentum: the overall
39 // phase depends upon the location of the source. Using the new interface,
40 // the phase can be made independent of the location of the source by choosing
41 // the origin of the Fourier transform to be the location of the source.
42 // Several things remain to be fixed:
43 // (1) sequential sources at non-zero sink momentum,
44 // (2) building blocks with link paths which cross boundaries,
45 // (3) baryonic sequential sources where t_source > t_sink,
46 // i.e. the boundary is between the source and sink.
47 //
48 // Revision 3.0 2006/04/03 04:59:12 edwards
49 // Major overhaul of fermion and gauge action interface. Basically,
50 // all fermacts and gaugeacts now carry out <T,P,Q> template parameters. These are
51 // the fermion type, the "P" - conjugate momenta, and "Q" - generalized coordinates
52 // in the sense of Hamilton's equations. The fermbc's have been rationalized to never
53 // be over multi1d<T>. The "createState" within the FermionAction is now fixed meaning
54 // the "u" fields are now from the coordinate type. There are now "ConnectState" that
55 // derive into FermState<T,P,Q> and GaugeState<P,Q>.
56 //
57 // Revision 2.2 2006/02/26 21:17:34 edwards
58 // Put TimeSliceFunc in an anonymous namespace.
59 //
60 // Revision 2.1 2005/09/29 15:53:42 edwards
61 // Updates to interface.
62 //
63 // Revision 2.0 2005/09/25 21:04:44 edwards
64 // Moved to version 2.0
65 //
66 // Revision 1.10 2005/07/27 16:23:28 edwards
67 // Added getter for momentum offset
68 //
69 // Revision 1.9 2005/01/14 18:42:38 edwards
70 // Converted all lib files to be in chroma namespace.
71 //
72 // Revision 1.8 2004/04/28 18:55:38 edwards
73 // Added numSites().
74 //
75 // Revision 1.7 2004/02/03 20:04:05 edwards
76 // Added sft for LatticeReal. Changed getSubset() to the more accurate
77 // getSet().
78 //
79 // Revision 1.6 2003/12/17 04:50:42 edwards
80 // Added function to return decay direction. Added some doxygen comments.
81 //
82 // Revision 1.5 2003/04/02 22:28:22 edwards
83 // Changed proto.h to qdp_util.h
84 //
85 // Revision 1.4 2003/04/01 02:46:43 edwards
86 // Added const qual.
87 //
88 // Revision 1.3 2003/03/20 19:34:25 flemingg
89 // Evolved formfac_w.cc to use SftMom class, which included some bug fixes
90 // in features in SftMom which had been previously untested and evolution
91 // of the corresponding test program.
92 //
93 // Revision 1.2 2003/03/14 17:13:44 flemingg
94 // SftMom::sft() now works.
95 //
96 // Revision 1.1 2003/03/14 05:06:06 flemingg
97 // Initial version of SftMom class
98 //
99 
100 #include "util/ft/sftmom.h"
101 #include "util/ft/single_phase.h"
102 #include "qdp_util.h" // part of QDP++, for crtesn()
103 
104 namespace Chroma
105 {
106 
107  // Param struct for SftMom
109  {
110  mom2_max = 0; /*!< (mom - mom_origin)^2 <= mom2_max */
111  mom_offset.resize(Nd-1); /*!< Origin for the momentum */
112  mom_offset = 0;
113  avg_equiv_mom = false; /*!< average over equivalent momenta */
114  origin_offset.resize(Nd); /*<! Coordinate offset of the origin. Used to fix phase factor */
115  origin_offset = 0;
116  decay_dir = -1; /*!< Decay direction */
117  }
118 
119 
120  // Anonymous namespace
121  namespace
122  {
123  //! Function object used for constructing the time-slice set
124  class TimeSliceFunc : public SetFunc
125  {
126  public:
127  TimeSliceFunc(int dir): dir_decay(dir) {}
128 
129  int operator() (const multi1d<int>& coordinate) const ;
130 
131  int numSubsets() const ;
132 
133  private:
134  TimeSliceFunc() {} // hide default constructor
135 
137  };
138  }
139 
140  int
141  TimeSliceFunc::operator() (const multi1d<int>& coordinate) const
142  {
143  if ((dir_decay<0)||(dir_decay>=Nd)) {
144  return 0 ;
145  } else {
146  return coordinate[dir_decay] ;
147  }
148  }
149 
150  int
152  {
153  if ((dir_decay<0)||(dir_decay>=Nd)) {
154  return 1 ;
155  } else {
156  return Layout::lattSize()[dir_decay] ;
157  }
158  }
159 
160 
161  SftMom::SftMom(int mom2_max, bool avg_mom, int j_decay)
162  {
163  multi1d<int> origin_off(Nd);
164  multi1d<int> mom_off;
165 
166  if ((j_decay<0)||(j_decay>=Nd)) {
167  mom_off.resize(Nd) ;
168  } else {
169  mom_off.resize(Nd-1) ;
170  }
171 
172  origin_off = 0 ;
173  mom_off = 0 ;
174 
175  init(mom2_max, origin_off, mom_off, avg_mom, j_decay) ;
176  }
177 
178  SftMom::SftMom(const multi2d<int> & moms , int j_decay)
179  {
180  decay_dir = j_decay;
181 
182  multi1d<int> orig(Nd);
183 
184 
185  for(int i = 0 ; i < Nd ; ++i)
186  orig[i] = 0;
187 
188  init(0, orig, orig , false, decay_dir);
189 
190  num_mom = moms.size2();
191  mom_list = moms;
192 
193  phases.resize(num_mom);
194 
195 
196  for (int m = 0 ; m < num_mom ; ++m)
197  {
198  phases[m] = singlePhase(orig, mom_list[m], decay_dir);
199  }
200 
201  }
202 
203  SftMom::SftMom(int mom2_max, multi1d<int> origin_offset_, bool avg_mom,
204  int j_decay)
205  {
206  multi1d<int> mom_off;
207 
208  if ((j_decay<0)||(j_decay>=Nd)) {
209  mom_off.resize(Nd) ;
210  } else {
211  mom_off.resize(Nd-1) ;
212  }
213  mom_off = 0 ;
214 
215  init(mom2_max, origin_offset_, mom_off, avg_mom, j_decay) ;
216  }
217 
218  int
220  {
221  int vol = 1;
222 
223  if ((decay_dir<0)||(decay_dir>=Nd))
224  vol = Layout::vol();
225  else
226  {
227  for(int m=0; m < Nd; ++m)
228  vol *= Layout::lattSize()[m];
229  }
230 
231  return vol;
232  }
233 
234 
235  void
236  SftMom::init(int mom2_max, multi1d<int> origin_off, multi1d<int> mom_off,
237  bool avg_mom, int j_decay)
238  {
239  decay_dir = j_decay; // private copy
240  origin_offset = origin_off; // private copy
241  mom_offset = mom_off; // private copy
242  avg_equiv_mom = avg_mom; // private copy
243 
244  sft_set.make(TimeSliceFunc(j_decay)) ;
245 
246  // determine the number of momenta with mom^2 <= (mom_max)^2
247  // If avg_equiv_mom is true then only consider momenta with
248  // mom[0] >= mom[1] >= ... >= mom[mu] >= ... >= 0
249  multi1d<int> mom_size ;
250  if ((j_decay<0)||(j_decay>=Nd)) {
251  mom_size.resize(Nd) ;
252  } else {
253  mom_size.resize(Nd-1) ;
254  }
255 
256  int L;
257  int mom_vol = 1;
258 
259  for (L=1; L*L <= mom2_max; ++L) ;
260 
261  for(int mu=0; mu < mom_size.size(); ++mu) {
262  if (avg_equiv_mom) {
263  mom_vol *= L;
264  mom_size[mu] = L;
265  } else {
266  mom_vol *= (2*L) + 1;
267  mom_size[mu] = (2*L) + 1;
268  }
269  }
270 
271  num_mom = 0;
272 
273  for(int n=0; n < mom_vol; ++n) {
274  multi1d<int> mom = crtesn(n, mom_size);
275 
276  int mom2 = 0 ;
277 
278  for(int mu=0; mu < mom_size.size(); ++mu) {
279  if (!avg_equiv_mom) mom[mu] -= L ;
280  mom2 += mom[mu]*mom[mu];
281  }
282 
283  if (mom2 > mom2_max) {
284  continue;
285  } else if (avg_equiv_mom) {
286  // Ensure mom[0] >= mom[1] >= ... >= mom[mu] >= ... >= 0
287  bool skip = false ;
288  for(int mu=0; mu < mom_size.size()-1; ++mu)
289  for(int nu=mu+1; nu < mom_size.size(); ++nu)
290  if (mom[nu] > mom[mu]) skip=true;
291 
292  if (!skip) ++num_mom ;
293  } else {
294  ++num_mom ;
295  }
296  }
297 
298  // After all that shenanigans just to get num_mom, resize the momentum list
299  mom_list.resize(num_mom, mom_size.size()) ;
300 
301  // Now we do exactly the same thing we did when counting, except this time
302  // we can acutally fill the list
303  int mom_num = 0;
304 
305  for(int n=0; n < mom_vol; ++n)
306  {
307  multi1d<int> mom = crtesn(n, mom_size);
308 
309  int mom2 = 0 ;
310 
311  for(int mu=0; mu < mom_size.size(); ++mu) {
312  if (!avg_equiv_mom) mom[mu] -= L ;
313  mom2 += mom[mu]*mom[mu];
314  }
315 
316  if (mom2 > mom2_max) {
317  continue;
318  } else if (avg_equiv_mom) {
319  // Ensure mom[0] >= mom[1] >= ... >= mom[mu] >= ... >= 0
320  bool skip = false ;
321  for(int mu=0; mu < mom_size.size()-1; ++mu)
322  for(int nu=mu+1; nu < mom_size.size(); ++nu)
323  if (mom[nu] > mom[mu]) skip = true ;
324 
325  if (!skip) mom_list[mom_num++] = mom ;
326  } else {
327  for (int mu=0; mu < mom_size.size(); ++mu) {
328  mom_list[mom_num][mu] = mom_offset[mu] + mom[mu] ;
329  }
330  ++mom_num ;
331  }
332  }
333 
334  // Now resize and initialize the Fourier phase table. Then, loop over
335  // allowed momenta, optionally averaging over equivalent momenta.
336  phases.resize(num_mom) ;
337  phases = 0. ;
338 
339  // Coordinates for sink momenta
340  multi1d<LatticeInteger> my_coord(Nd);
341  for (int mu=0; mu < Nd; ++mu)
342  my_coord[mu] = Layout::latticeCoordinate(mu);
343 
344  // Keep track of |mom| degeneracy for averaging
345  mom_degen.resize(num_mom);
346  mom_degen = 0;
347 
348  // If averaging over equivalent momenta, we need redo mom_size and mom_vol
349  // to allow both positive and negative momentum components
350  if (avg_equiv_mom) {
351  mom_vol = 1 ;
352 
353  for (int mu=0; mu < mom_size.size(); ++mu) {
354  mom_vol *= (2*L) + 1 ;
355  mom_size[mu] = (2*L) + 1 ;
356  }
357  }
358 
359  // reset mom_num
360  mom_num = 0 ;
361 
362  for (int n=0; n < mom_vol; ++n) {
363  multi1d<int> mom = crtesn(n, mom_size) ;
364 
365  int mom2 = 0 ;
366 
367  for(int mu=0; mu < mom_size.size(); ++mu) {
368  mom[mu] -= L ;
369  mom2 += mom[mu]*mom[mu];
370  }
371 
372  // skip when (mom)^2 > (mom_max)^2
373  if (mom2 > mom2_max) continue;
374 
375  // At this point, if (avg_equiv_mom == true) then we need to determine
376  // mom_num by a fairly time consuming process.
377  // If (avg_equiv_mom == false) then (mom == mom_list[mom_num])
378  // (will double check this) and the momentum offset can be applied.
379 
380  if (avg_equiv_mom) {
381 
382  // determine mom_num for entering table mom_list
383  // put the momenta into canonical order
384  multi1d<int> mom_tmp = canonicalOrder(mom);
385 
386  // mom_tmp should now contain a momentum that appears in mom_list.
387  // scan through list until we find a match.
388  mom_num = -1 ;
389 
390  for(int k=0; k < num_mom; ++k) {
391  bool match = true ;
392  for (int mu=0; mu < mom_tmp.size(); ++mu) {
393  if (mom_list[k][mu] != mom_tmp[mu]) {
394  match = false ;
395  break;
396  }
397  }
398  if (match) {
399  mom_num = k ;
400  break ;
401  }
402  }
403 
404  if (mom_num < 0) {
405  QDP_error_exit("SftMom: mom_num < 0. Shouldn't be here.\n") ;
406  }
407 
408  // increment degeneracy for this mom_num
409  ++(mom_degen[mom_num]) ;
410  } else /* (avg_equiv_mom == false) */ {
411 
412  // apply momentum offset
413  for (int mu=0; mu < mom_size.size(); ++mu) {
414  mom[mu] += mom_offset[mu] ;
415  }
416 
417  // double check that (mom == mom_list[n])
418  // this check should never fail and could be removed in the future
419  for (int mu=0; mu < mom_size.size(); ++mu) {
420  if (mom[mu] != mom_list[mom_num][mu]) {
421  // Should never get here !!!
422  QDP_error_exit("SftMom: (mom != mom_list[mom_num])\n") ;
423  }
424  }
425  } // end if (avg_equiv_mom)
426 
427  //
428  // Build the phase.
429  // RGE: the origin_offset works with or without momentum averaging
430  //
431  LatticeReal p_dot_x ;
432  p_dot_x = 0. ;
433 
434  int j = 0;
435  for(int mu = 0; mu < Nd; ++mu) {
436  const Real twopi = 6.283185307179586476925286;
437 
438  if (mu == j_decay) continue ;
439 
440  p_dot_x += LatticeReal(my_coord[mu] - origin_offset[mu]) * twopi *
441  Real(mom[j]) / Layout::lattSize()[mu];
442  ++j ;
443  } // end for(mu)
444 
445  phases[mom_num] += cmplx(cos(p_dot_x), sin(p_dot_x)) ;
446 
447  // increment mom_num for next valid momenta
448  ++mom_num ;
449 
450  } // end for (int n=0; n < mom_vol; ++n)
451 
452  // Finish averaging
453  // Momentum averaging works even in the presence of an origin_offset
454  if (avg_equiv_mom) {
455  for (int mom_num=0; mom_num < num_mom; ++mom_num)
456  phases[mom_num] /= mom_degen[mom_num] ;
457  }
458  }
459 
460 
461  // Canonically order an array of momenta
462  /* \return abs(mom[0]) >= abs(mom[1]) >= ... >= abs(mom[mu]) >= ... >= 0 */
463  multi1d<int>
464  SftMom::canonicalOrder(const multi1d<int>& mom) const
465  {
466  // first step: make all the components positive
467  multi1d<int> mom_tmp = mom;
468  for (int mu=0; mu < mom_tmp.size(); ++mu)
469  if (mom_tmp[mu] < 0) mom_tmp[mu] = -mom_tmp[mu];
470 
471  // Initially, the first item is considered sorted. mu divides mom
472  // into a sorted region (<mu) and an unsorted one (>=mu)
473  for (int mu=1; mu < mom_tmp.size(); ++mu)
474  {
475  // Select the item at the beginning of the unsorted region
476  int v = mom_tmp[mu];
477  // Work backwards, finding where v should go
478  int nu = mu;
479  // If this element is less than v, move it up one
480  while (mom_tmp[nu-1] < v) {
481  mom_tmp[nu] = mom_tmp[nu-1];
482  --nu;
483  if (nu < 1) break;
484  }
485  // Stopped when mom_tmp[nu-1] >= v, so put v at postion nu
486  mom_tmp[nu] = v;
487  }
488 
489  return mom_tmp;
490  }
491 
492 
493  // Convert array of momenta to momenta id
494  /* \return id in [0,numMom()-1] or -1 if not in list */
495  int
496  SftMom::momToNum(const multi1d<int>& mom_in) const
497  {
498  multi1d<int> mom;
499 
500  // If mom avg is turned on, then canonicalize the input mom
501  if (avg_equiv_mom)
502  mom = canonicalOrder(mom_in);
503  else
504  mom = mom_in;
505 
506  // Search for the mom
507  for(int mom_num=0; mom_num < num_mom; ++mom_num)
508  {
509  bool match = true ;
510  for (int mu=0; mu < mom.size(); ++mu)
511  {
512  if (mom_list[mom_num][mu] != mom[mu])
513  {
514  match = false ;
515  break;
516  }
517  }
518  if (match) return mom_num ;
519  }
520  return -1;
521  }
522 
523  multi2d<DComplex>
524  SftMom::sft(const LatticeComplex& cf) const
525  {
526  multi2d<DComplex> hsum(num_mom, sft_set.numSubsets()) ;
527 
528  for (int mom_num=0; mom_num < num_mom; ++mom_num)
529  hsum[mom_num] = sumMulti(phases[mom_num]*cf, sft_set) ;
530 
531  return hsum ;
532  }
533 
534  multi2d<DComplex>
535  SftMom::sft(const LatticeComplex& cf, int subset_color) const
536  {
537  int length = sft_set.numSubsets();
538  multi2d<DComplex> hsum(num_mom, length);
539 
540  for (int mom_num=0; mom_num < num_mom; ++mom_num)
541  {
542  hsum[mom_num] = zero;
543  hsum[mom_num][subset_color] = sum(phases[mom_num]*cf, sft_set[subset_color]);
544  }
545 
546  return hsum ;
547  }
548 
549  multi2d<DComplex>
550  SftMom::sft(const LatticeReal& cf) const
551  {
552  multi2d<DComplex> hsum(num_mom, sft_set.numSubsets()) ;
553 
554  for (int mom_num=0; mom_num < num_mom; ++mom_num)
555  hsum[mom_num] = sumMulti(phases[mom_num]*cf, sft_set) ;
556 
557  return hsum ;
558  }
559 
560  multi2d<DComplex>
561  SftMom::sft(const LatticeReal& cf, int subset_color) const
562  {
563  int length = sft_set.numSubsets();
564  multi2d<DComplex> hsum(num_mom, length);
565 
566  for (int mom_num=0; mom_num < num_mom; ++mom_num)
567  {
568  hsum[mom_num] = zero;
569  hsum[mom_num][subset_color] = sum(phases[mom_num]*cf, sft_set[subset_color]);
570  }
571 
572  return hsum ;
573  }
574 
575 #if BASE_PRECISION==32
576  multi2d<DComplex>
577  SftMom::sft(const LatticeComplexD& cf) const
578  {
579  multi2d<DComplex> hsum(num_mom, sft_set.numSubsets()) ;
580 
581  for (int mom_num=0; mom_num < num_mom; ++mom_num)
582  hsum[mom_num] = sumMulti(phases[mom_num]*cf, sft_set) ;
583 
584  return hsum ;
585  }
586 
587  multi2d<DComplex>
588  SftMom::sft(const LatticeComplexD& cf, int subset_color) const
589  {
590  int length = sft_set.numSubsets();
591  multi2d<DComplex> hsum(num_mom, length);
592 
593  for (int mom_num=0; mom_num < num_mom; ++mom_num)
594  {
595  hsum[mom_num] = zero;
596  hsum[mom_num][subset_color] = sum(phases[mom_num]*cf, sft_set[subset_color]);
597  }
598 
599  return hsum ;
600  }
601 #endif
602 
603 } // end namespace Chroma
multi2d< int > mom_list
Definition: sftmom.h:121
int numSites() const
Number of sites in each subset.
Definition: sftmom.cc:219
multi1d< int > canonicalOrder(const multi1d< int > &mom) const
Canonically order an array of momenta.
Definition: sftmom.cc:464
int decay_dir
Definition: sftmom.h:123
multi1d< int > origin_offset
Definition: sftmom.h:125
multi1d< int > mom_offset
Definition: sftmom.h:126
int momToNum(const multi1d< int > &mom_in) const
Convert array of momenta to momenta id.
Definition: sftmom.cc:496
multi2d< DComplex > sft(const LatticeComplex &cf) const
Do a sumMulti(cf*phases,getSet())
Definition: sftmom.cc:524
bool avg_equiv_mom
Definition: sftmom.h:122
multi1d< LatticeComplex > phases
Definition: sftmom.h:127
void init(int mom2_max, multi1d< int > origin_offset, multi1d< int > mom_offset, bool avg_mom_=false, int j_decay=-1)
Definition: sftmom.cc:236
multi1d< int > mom_degen
Definition: sftmom.h:128
Function object used for constructing the time-slice set.
Definition: barQll_w.h:95
int numSubsets() const
Definition: barQll_w.h:108
int operator()(const multi1d< int > &coordinate) const
Definition: barQll_w.h:99
int mu
Definition: cool.cc:24
int nu
Definition: cool.cc:25
LatticeComplex singlePhase(const multi1d< int > &t_srce, const multi1d< int > &sink_mom, int j_decay)
A single exp(ip.x) phase used in hadron construction.
Definition: single_phase.cc:13
unsigned j
Definition: ldumul_w.cc:35
unsigned n
Definition: ldumul_w.cc:36
static int m[4]
Definition: make_seeds.cc:16
int j_decay
Definition: meslate.cc:22
Nd
Definition: meslate.cc:74
Asqtad Staggered-Dirac operator.
Definition: klein_gord.cc:10
QDP_error_exit("too many BiCG iterations", n_count, rsd_sq, cp, c, re_rvr, im_rvr, re_a, im_a, re_b, im_b)
int i
Definition: pbg5p_w.cc:55
const Real twopi
Definition: chromabase.h:55
Double zero
Definition: invbicg.cc:106
int k
Definition: invbicg.cc:119
Double sum
Definition: qtopcor.cc:37
Fourier transform phase factor support.
Compute a single phase factor.
multi1d< int > mom_offset
Definition: sftmom.h:23
multi1d< int > origin_offset
Definition: sftmom.h:25