LSSTApplications  10.0+286,10.0+36,10.0+46,10.0-2-g4f67435,10.1+152,10.1+37,11.0,11.0+1,11.0-1-g47edd16,11.0-1-g60db491,11.0-1-g7418c06,11.0-2-g04d2804,11.0-2-g68503cd,11.0-2-g818369d,11.0-2-gb8b8ce7
LSSTDataManagementBasePackage
BVec.cc
Go to the documentation of this file.
1 // -*- LSST-C++ -*-
2 
3 /*
4  * LSST Data Management System
5  * Copyright 2008, 2009, 2010 LSST Corporation.
6  *
7  * This product includes software developed by the
8  * LSST Project (http://www.lsst.org/).
9  *
10  * This program is free software: you can redistribute it and/or modify
11  * it under the terms of the GNU General Public License as published by
12  * the Free Software Foundation, either version 3 of the License, or
13  * (at your option) any later version.
14  *
15  * This program is distributed in the hope that it will be useful,
16  * but WITHOUT ANY WARRANTY; without even the implied warranty of
17  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
18  * GNU General Public License for more details.
19  *
20  * You should have received a copy of the LSST License Statement and
21  * the GNU General Public License along with this program. If not,
22  * see <http://www.lsstcorp.org/LegalNotices/>.
23  */
24 
25 #include <cmath>
26 #include <iostream>
27 
30 #include "lsst/afw/geom/Angle.h"
31 
32 namespace afwGeom = lsst::afw::geom;
33 
34 namespace lsst {
35 namespace meas {
36 namespace algorithms {
37 namespace shapelet {
38 
40  {
41  rhs.assignTo(*this);
42  return *this;
43  }
44 
45  BVec& BVec::operator=(const BVec& rhs)
46  {
47  rhs.assignTo(*this);
48  return *this;
49  }
50 
51  void BVec::assignTo(BVec& rhs) const
52  {
53  rhs.setSigma(_sigma);
54  rhs.setValues(_b);
55  }
56 
57  void BVec::setValues(const DVector& v)
58  {
59  if (_b.size() == v.size()) {
60  _b = v;
61  } else if (_b.size() > v.size()) {
62  _b.TMV_subVector(0,v.size()) = v;
63  _b.TMV_subVector(v.size(),_b.size()).setZero();
64  } else {
65  xdbg<<"Warning truncating information in BVec::setValues\n";
66  _b = v.TMV_subVector(0,_b.size());
67  }
68  }
69 
71  {
72  const int N = getOrder();
73  for(int n=1,k=1;n<=N;++n) {
74  for(int m=n;m>=0;m-=2) {
75  if (m==0) ++k;
76  else {
77  _b(k+1) *= -1.0;
78  k+=2;
79  }
80  }
81  }
82  }
83 
85  std::complex<double> z, int order1, int order2, DMatrix& T)
86  {
87  const int size1 = (order1+1)*(order1+2)/2;
88  const int size2 = (order2+1)*(order2+2)/2;
89  Assert(int(T.TMV_colsize()) >= size1);
90  Assert(int(T.TMV_rowsize()) >= size2);
91 
92  T.setZero();
93 
94  if (z == 0.0) {
95  T.TMV_diagpart(0,0,std::min(size1,size2)).TMV_setAllTo(1.);
96  return;
97  }
98 
99  // T(st,pq) = f(p,s) f*(q,t)
100  // f(p,0) = (-z/2)^p / sqrt(p!) exp(-|z|^2/8)
101  // f(p,s+1) = (sqrt(p) f(p-1,s) + 1/2 z* f(p,s) )/sqrt(s+1)
102 
103  std::complex<double> zo2 = -z/2.;
104  std::vector<std::vector<std::complex<double> > > f(
105  order2+1,std::vector<std::complex<double> >(order1+1));
106 
107  f[0][0] = exp(-std::norm(z)/8.); // f(0,0)
108  for(int p=1;p<=order2;++p) {
109  f[p][0] = f[p-1][0]*(-zo2)/sqrtn(p); // f(p,0)
110  }
111  for(int s=0;s<order1;++s) {
112  f[0][s+1] = std::conj(zo2)*f[0][s]/sqrtn(s+1); // f(0,s+1)
113  for(int p=1;p<=order2;++p) {
114  f[p][s+1] = (sqrtn(p)*f[p-1][s] + std::conj(zo2)*f[p][s])/
115  sqrtn(s+1); // f(p,s+1)
116  }
117  }
118 
119  for(int n=0,pq=0;n<=order2;++n) {
120  for(int p=n,q=0;p>=q;--p,++q,++pq) {
121  double* Tpq = TMV_ptr(T.col(pq));
122  double* Tpq1 = Tpq + TMV_stepj(T);
123  const std::vector<std::complex<double> >& fp = f[p];
124  const std::vector<std::complex<double> >& fq = f[q];
125  for(int nn=0,st=0;nn<=order1;++nn) {
126  for(int s=nn,t=0;s>=t;--s,++t,++st) {
127  std::complex<double> t1 = fp[s] * std::conj(fq[t]);
128  if (p==q) {
129  if (s==t) {
130  Tpq[st] = std::real(t1); // T(st,pq)
131  } else {
132  Tpq[st] = std::real(t1);
133  Tpq[st+1] = std::imag(t1);
134  ++st;
135  }
136  } else if (s==t) {
137  // b_st = t_stpq b_pq + t_stqp b_qp
138  // In this case with s=t, t_stpq == t_stqp*
139  Tpq[st] = 2.*std::real(t1);
140  Tpq1[st] = -2.*std::imag(t1);
141  } else {
142  std::complex<double> t2 = fq[s] * std::conj(fp[t]);
143  Tpq[st] = std::real(t1) + std::real(t2);
144  Tpq[st+1]= std::imag(t1) + std::imag(t2);
145  Tpq1[st] = -std::imag(t1) + std::imag(t2);
146  Tpq1[st+1] = std::real(t1) - std::real(t2);
147  ++st;
148  }
149  }
150  }
151  if (p!=q) ++pq;
152  }
153  }
154  }
155 
156  void augmentZTransformCols(std::complex<double> z, int order, DMatrix& T)
157  {
158  const int order1 = order;
159  const int order2 = order+2;
160  const int size1 = (order1+1)*(order1+2)/2;
161  //const int size2 = (order2+1)*(order2+2)/2;
162  Assert(int(T.TMV_colsize()) >= size1);
163  Assert(int(T.TMV_rowsize()) >= (order2+1)*(order2+2)/2);
164 
165  if (z == 0.0) return;
166 
167  std::complex<double> zo2 = -z/2.;
168  std::vector<std::vector<std::complex<double> > > f(
169  order2+1,std::vector<std::complex<double> >(order1+1));
170 
171  f[0][0] = exp(-std::norm(z)/8.); // f(0,0)
172  for(int p=1;p<=order2;++p) {
173  f[p][0] = f[p-1][0]*(-zo2)/sqrtn(p); // f(p,0)
174  }
175  for(int s=0;s<order1;++s) {
176  f[0][s+1] = std::conj(zo2)*f[0][s]/sqrtn(s+1); // f(0,s+1)
177  for(int p=1;p<=order2;++p) {
178  f[p][s+1] = (sqrtn(p)*f[p-1][s] + std::conj(zo2)*f[p][s])/
179  sqrtn(s+1); // f(p,s+1)
180  }
181  }
182 
183  for(int n=order1+1,pq=size1;n<=order2;++n) {
184  for(int p=n,q=0;p>=q;--p,++q,++pq) {
185  const std::vector<std::complex<double> >& fp = f[p];
186  const std::vector<std::complex<double> >& fq = f[q];
187  double* Tpq = TMV_ptr(T.col(pq));
188  double* Tpq1 = Tpq + TMV_stepj(T);
189  for(int nn=0,st=0;nn<=order1;++nn) {
190  for(int s=nn,t=0;s>=t;--s,++t,++st) {
191  std::complex<double> t1 = fp[s] * std::conj(fq[t]);
192  if (p==q) {
193  if (s==t) {
194  Tpq[st] = std::real(t1);
195  } else {
196  Tpq[st] = std::real(t1);
197  Tpq[st+1] = std::imag(t1);
198  ++st;
199  }
200  } else if (s==t) {
201  Tpq[st] = 2.*std::real(t1);
202  Tpq1[st] = -2.*std::imag(t1);
203  } else {
204  std::complex<double> t2 = fq[s] * std::conj(fp[t]);
205  Tpq[st] = std::real(t1) + std::real(t2);
206  Tpq[st+1]= std::imag(t1) + std::imag(t2);
207  Tpq1[st] = -std::imag(t1) + std::imag(t2);
208  Tpq1[st+1] = std::real(t1) - std::real(t2);
209  ++st;
210  }
211  }
212  }
213  if (p!=q) ++pq;
214  }
215  }
216  }
217 
218  void applyZ(std::complex<double> z, BVec& b)
219  {
220  if (z != 0.0) {
221  DMatrix T(int(b.size()),int(b.size()));
223  b.vec() = T * b.vec();
224  }
225  }
226 
227  void calculateMuTransform(double mu, int order1, int order2, DMatrix& D)
228  {
229  const int size1 = (order1+1)*(order1+2)/2;
230  const int size2 = (order2+1)*(order2+2)/2;
231  Assert(int(D.TMV_colsize()) >= size1);
232  Assert(int(D.TMV_rowsize()) >= size2);
233  // First I should point out an error in BJ02. It lists
234  // D(pq,00) = e^mu sech(mu) tanh(mu)^p delta_pq
235  // This is wrong.
236  // This is the formula for D(00,pq).
237  //
238  // Second, this formula has a different normalization than what we
239  // want. This gives the transformation I(x,y) -> I(exp(-mu)x,exp(-mu)y).
240  // However, we want the transformation for the same I, but measured in
241  // a different coordinate system. The difference is in the fact that
242  // the flux scales as sigma^2, so this gives another factor of exp(-2mu).
243  // So the formula we need is:
244  // D(00,pq) = e^-mu sech(mu) tanh(mu)^p delta_pq
245  //
246  // Third, the recursion suggested for calculating D(st,pq)
247  // is a bit cumbersome since it has a q+1 on the rhs, so the
248  // calculation of D(30,30) for example, would require knowledge
249  // of D(00,33) which is a higher order than we really need.
250  //
251  // An easier recursion is the following:
252  // D(00,pq) = e^-mu sech(mu) tanh(mu)^p delta_pq
253  // D(s0,pq) = 1/sqrt(s) sech(mu) sqrt(p) D(s-10,p-1q)
254  // D(st,pq) = 1/sqrt(t) [ sech(mu) sqrt(q) D(st-1,pq-1)
255  // - tanh(mu) sqrt(s) D(s-1t-1,pq) ]
256  // Note: Only s-t = p-q terms are nonzero.
257  // This means that this can be significantly sped up
258  // by forming smaller matrices for each m, and using
259  // permutations to rotate b so that these elements are
260  // continuous and then rotate back after multiplying.
261  // However, I'll wait to implement this until such speed
262  // is found to be necessary.
263 
264  D.setZero();
265 
266  if (mu == 0.0) {
267  D.TMV_diagpart(0,0,std::min(size1,size2)).TMV_setAllTo(1.);
268  return;
269  }
270 
271  double tmu = tanh(mu);
272  double smu = 1./cosh(mu);
273 
274  int minorder = std::min(order1,order2);
275  double Dqq = exp(-mu)*smu;
276  // Dqq = exp(-mu) sech(mu) (-tanh(mu))^q
277  // This variable keeps the latest Dqq value:
278  for(int n=0,pq=0;n<=order2;++n) {
279  for(int p=n,q=0;p>=q;--p,++q,++pq) {
280  double* Dpq = TMV_ptr(D.col(pq));
281  double* Dpq_n = TMV_ptr(D.col(pq-n));
282  double* Dpq_n_2 = q>0?TMV_ptr(D.col(pq-n-2)):0;
283  double* Dpq1 = p>q?TMV_ptr(D.col(pq+1)):0;
284  if (p==q) {
285  if (p > 0) Dqq *= tmu;
286  Dpq[0] = Dqq; // D(0,pq)
287  }
288  for(int m=1,st=1;m<=minorder;++m) {
289  for(int s=m,t=0;s>=t;--s,++t,++st) {
290  if (p-q==s-t) {
291  double temp;
292  if (t == 0) {
293  temp = smu*sqrtn(p)*Dpq_n[st-m]/sqrtn(s);
294  } else {
295  temp = -tmu*sqrtn(s)*Dpq[st-2*m-1];
296  if (q > 0) {
297  temp += smu*sqrtn(q)*Dpq_n_2[st-m-2];
298  }
299  temp /= sqrtn(t);
300  }
301  if (s == t) {
302  Dpq[st] = temp; // D(st,pq)
303  } else {
304  Dpq[st] = temp; // D(st,pq)
305  Dpq1[st+1] = temp; // D(st+1,pq+1)
306  }
307  }
308  if (s!=t) ++st;
309  }
310  }
311  if (p!=q) ++pq;
312  }
313  }
314  }
315 
316  void augmentMuTransformCols(double mu, int order, DMatrix& D)
317  {
318  const int order1 = order;
319  const int order2 = order+2;
320  const int size1 = (order1+1)*(order1+2)/2;
321  //const int size2 = (order2+1)*(order2+2)/2;
322  Assert(int(D.TMV_colsize()) >= size1);
323  Assert(int(D.TMV_rowsize()) >= (order2+1)*(order2+2)/2);
324 
325  if (mu == 0.0) return;
326 
327  double tmu = tanh(mu);
328  double smu = 1./cosh(mu);
329 
330  double Dqq = exp(-mu)*smu;
331  for(int q=order1/2;q>0;--q) Dqq *= tmu;
332  for(int n=order1+1,pq=size1;n<=order2;++n) {
333  for(int p=n,q=0;p>=q;--p,++q,++pq) {
334  double* Dpq = TMV_ptr(D.col(pq));
335  double* Dpq_n = TMV_ptr(D.col(pq-n));
336  double* Dpq_n_2 = q>0?TMV_ptr(D.col(pq-n-2)):0;
337  double* Dpq1 = p>q?TMV_ptr(D.col(pq+1)):0;
338  if (p==q) {
339  if (p > 0) Dqq *= tmu;
340  Dpq[0] = Dqq; // D(0,pq)
341  }
342  for(int m=1,st=1;m<=order1;++m) {
343  for(int s=m,t=0;s>=t;--s,++t,++st) {
344  if (p-q==s-t) {
345  double temp;
346  if (t == 0) {
347  temp = smu*sqrtn(p)*Dpq_n[st-m]/sqrtn(s);
348  } else {
349  temp = -tmu*sqrtn(s)*Dpq[st-2*m-1];
350  if (q > 0) {
351  temp += smu*sqrtn(q)*Dpq_n_2[st-m-2];
352  }
353  temp /= sqrtn(t);
354  }
355  Dpq[st] = temp;
356  if (s!=t) Dpq1[st+1] = temp;
357  }
358  if (s!=t) ++st;
359  }
360  }
361  if (p!=q) ++pq;
362  }
363  }
364  }
365 
366  void augmentMuTransformRows(double mu, int order, DMatrix& D)
367  {
368  const int order1 = order+2;
369  const int order2 = order;
370  //const int size1 = (order1+1)*(order1+2)/2;
371  const int size2 = (order2+1)*(order2+2)/2;
372  Assert(int(D.TMV_colsize()) == (order1+1)*(order1+2)/2);
373  Assert(int(D.TMV_rowsize()) == size2);
374 
375  if (mu == 0.0) return;
376 
377  double tmu = tanh(mu);
378  double smu = 1./cosh(mu);
379 
380  for(int n=0,pq=0;n<=order2;++n) {
381  for(int p=n,q=0;p>=q;--p,++q,++pq) {
382  double* Dpq = TMV_ptr(D.col(pq));
383  double* Dpq_n = TMV_ptr(D.col(pq-n));
384  double* Dpq_n_2 = q>0?TMV_ptr(D.col(pq-n-2)):0;
385  double* Dpq1 = p>q?TMV_ptr(D.col(pq+1)):0;
386  for(int m=order2+1,st=size2;m<=order1;++m) {
387  for(int s=m,t=0;s>=t;--s,++t,++st) {
388  if (p-q==s-t) {
389  double temp;
390  if (t == 0) {
391  temp = smu*sqrtn(p)*Dpq_n[st-m]/sqrtn(s);
392  } else {
393  temp = -tmu*sqrtn(s)*Dpq[st-2*m-1];
394  if (q > 0) {
395  temp += smu*sqrtn(q)*Dpq_n_2[st-m-2];
396  }
397  temp /= sqrtn(t);
398  }
399  Dpq[st] = temp;
400  if (s!=t) Dpq1[st+1] = temp;
401  }
402  if (s!=t) ++st;
403  }
404  }
405  if (p!=q) ++pq;
406  }
407  }
408  }
409 
410  void applyMu(double mu, BVec& b)
411  {
412  if (mu != 0.0) {
413  DMatrix D(int(b.size()),int(b.size()));
414  calculateMuTransform(mu,b.getOrder(),D);
415  b.vec() = D * b.vec();
416  }
417  }
418 
420  double theta, int order1, int order2, DBandMatrix& R)
421  {
422  const int size1 = (order1+1)*(order1+2)/2;
423  const int size2 = (order2+1)*(order2+2)/2;
424  Assert(int(R.TMV_colsize()) >= size1);
425  Assert(int(R.TMV_rowsize()) >= size2);
426 
427  R.setZero();
428 
429  if (theta == 0.0) {
430  R.TMV_diagpart(0,0,std::min(size1,size2)).TMV_setAllTo(1.);
431  return;
432  }
433 
434  int minorder = std::min(order1,order2);
435  std::vector<std::complex<double> > expimt(minorder+1);
436  expimt[0] = 1.;
437  if (minorder > 0) expimt[1] = std::polar(1.,theta);
438  for(int m=2;m<=minorder;++m) expimt[m] = expimt[m-1] * expimt[1];
439 
440  for(int n=0,pq=0;n<=minorder;++n) {
441  for(int p=n,q=0,m=n;p>=q;--p,++q,++pq,m-=2) {
442  if (m==0) {
443  R(pq,pq) = 1.;
444  } else {
445  R(pq,pq) = real(expimt[m]);
446  R(pq,pq+1) = -imag(expimt[m]);
447  R(pq+1,pq) = imag(expimt[m]);
448  R(pq+1,pq+1) = real(expimt[m]);
449  ++pq;
450  }
451  }
452  }
453  }
454 
455  void applyTheta(double theta, BVec& b)
456  {
457  if (theta != 0.0) {
458 #ifdef USE_TMV
459  DBandMatrix R(int(b.size()),int(b.size()),1,1);
460 #else
461  DBandMatrix R(int(b.size()),int(b.size()));
462 #endif
463  calculateThetaTransform(theta,b.getOrder(),R);
464  b.vec() = R * b.vec();
465  }
466  }
467 
469  std::complex<double> g, int order1, int order2, DMatrix& S)
470  {
471  const int size1 = (order1+1)*(order1+2)/2;
472  const int size2 = (order2+1)*(order2+2)/2;
473  Assert(int(S.TMV_colsize()) >= size1);
474  Assert(int(S.TMV_rowsize()) >= size2);
475  // S(st,pq) = f(p,s) f(q,t) (eta/|eta|)^(s-t-p+q)
476  // f(p,0) = sqrt(p!)/(p/2)! sqrt(sech(|eta|/2)) (-tanh(|eta|/2)/2)^p/2
477  // f(p,s+1) = (sqrt(p) sech(|eta|/2) f(p-1,s) +
478  // sqrt(s) tanh(|eta|/2) f(p,s-1))/sqrt(s+1)
479  //
480  // tanh(|eta|/2) = |g|
481  // sech(|eta|/2) = sqrt(1-|g|^2)
482  //
483  // Note: Like with the matrix in applyMu, this one is also fairly
484  // sparse. Could get a speedup by expoiting that, but currently don't.
485  // I'll wait until the speedup is found to be necessary.
486 
487  S.setZero();
488 
489  if (g == 0.0) {
490  S.TMV_diagpart(0,0,std::min(size1,size2)).TMV_setAllTo(1.);
491  return;
492  }
493 
494  double absg = std::abs(g);
495  double normg = std::norm(g);
496  std::vector<std::complex<double> > phase(order1+order2+1);
497  phase[0] = 1.;
498  std::complex<double> ph = -std::conj(g)/absg;
499  // I'm not sure why conj was needed here. Maybe there is an
500  // error in the phase indices below that this corrects.
501  for(int i=1;i<=order1+order2;++i) phase[i] = phase[i-1]*ph;
502 
503  double te = absg;
504  double se = sqrt(1.-normg);
505 
506  std::vector<std::vector<double> > f(
507  order2+1,std::vector<double>(order1+1,0.));
508 
509  f[0][0] = sqrt(se); // f(0,0)
510  // only terms with p+s even are non-zero.
511  for(int p=2;p<=order2;p+=2) {
512  f[p][0] = f[p-2][0]*(-te/2.)*sqrtn(p*(p-1))/double(p/2); // f(p,0)
513  }
514 
515  for(int s=0;s<order1;++s) {
516  if (s%2==1) {
517  f[0][s+1] = sqrtn(s)*te*f[0][s-1]/sqrtn(s+1); // f(0,s+1)
518  }
519  for(int p=s%2+1;p<=order2;p+=2) {
520  double temp = sqrtn(p)*se*f[p-1][s];
521  if (s>0) temp += sqrtn(s)*te*f[p][s-1];
522  temp /= sqrtn(s+1);
523  f[p][s+1] = temp; // f(p,s+1)
524  }
525  }
526 
527  for(int n=0,pq=0;n<=order2;++n) {
528  for(int p=n,q=0;p>=q;--p,++q,++pq) {
529  const std::vector<double>& fp = f[p];
530  const std::vector<double>& fq = f[q];
531  double* Spq = TMV_ptr(S.col(pq));
532  double* Spq1 = p>q?TMV_ptr(S.col(pq+1)):0;
533  for(int nn=n%2,st=(nn==0?0:1);nn<=order1;nn+=2,st+=nn) {
534  for(int s=nn,t=0;s>=t;--s,++t,++st) {
535 
536  double s0 = fp[s] * fq[t];
537 
538  int iphase = s-t-p+q;
539  std::complex<double> s1 = s0 *
540  (iphase >= 0 ?
541  phase[iphase/2] :
542  std::conj(phase[-iphase/2]));
543 
544  if (p==q) {
545  if (s==t) {
546  Spq[st] = std::real(s1);
547  } else {
548  Spq[st] = std::real(s1);
549  Spq[st+1] = std::imag(s1);
550  ++st;
551  }
552  } else if (s==t) {
553  // b_st = t_stpq b_pq + t_stqp b_qp
554  // In this case with s=t, t_stpq == t_stqp*
555  Spq[st] = 2.*std::real(s1);
556  Spq1[st] = -2.*std::imag(s1);
557  } else {
558  s0 = fq[s] * fp[t];
559  iphase = s-t-q+p;
560  std::complex<double> s2 = s0 *
561  (iphase >= 0 ?
562  phase[iphase/2] :
563  std::conj(phase[-iphase/2]));
564  Spq[st] = std::real(s1) + std::real(s2);
565  Spq[st+1] = std::imag(s1) + std::imag(s2);
566  Spq1[st] = -std::imag(s1) + std::imag(s2);
567  Spq1[st+1] = std::real(s1) - std::real(s2);
568  ++st;
569  }
570  }
571  }
572  if (p!=q) ++pq;
573  }
574  }
575  }
576 
577  void augmentGTransformCols(std::complex<double> g, int order, DMatrix& S)
578  {
579  const int order1 = order;
580  const int order2 = order+2;
581  const int size1 = (order1+1)*(order1+2)/2;
582  //const int size2 = (order2+1)*(order2+2)/2;
583  Assert(int(S.TMV_colsize()) == size1);
584  Assert(int(S.TMV_rowsize()) == (order2+1)*(order2+2)/2);
585 
586  if (g == 0.0) return;
587 
588  double absg = std::abs(g);
589  double normg = std::norm(g);
590  std::vector<std::complex<double> > phase(order1+order2+1);
591  phase[0] = 1.;
592  std::complex<double> ph = -std::conj(g)/absg;
593  for(int i=1;i<=order1+order2;++i) phase[i] = phase[i-1]*ph;
594 
595  double te = absg;
596  double se = sqrt(1.-normg);
597 
598  std::vector<std::vector<double> > f(
599  order2+1,std::vector<double>(order1+1,0.));
600 
601  f[0][0] = sqrt(se); // f(0,0)
602  // only terms with p+s even are non-zero.
603  for(int p=2;p<=order2;p+=2) {
604  f[p][0] = f[p-2][0]*(-te/2.)*sqrtn(p*(p-1))/double(p/2); // f(p,0)
605  }
606 
607  for(int s=0;s<order1;++s) {
608  if (s%2==1) {
609  f[0][s+1] = sqrtn(s)*te*f[0][s-1]/sqrtn(s+1); // f(0,s+1)
610  }
611  for(int p=s%2+1;p<=order2;p+=2) {
612  double temp = sqrtn(p)*se*f[p-1][s];
613  if (s>0) temp += sqrtn(s)*te*f[p][s-1];
614  temp /= sqrtn(s+1);
615  f[p][s+1] = temp; // f(p,s+1)
616  }
617  }
618 
619  for(int n=order1+1,pq=size1;n<=order2;++n) {
620  for(int p=n,q=0;p>=q;--p,++q,++pq) {
621  const std::vector<double>& fp = f[p];
622  const std::vector<double>& fq = f[q];
623  double* Spq = TMV_ptr(S.col(pq));
624  double* Spq1 = p>q?TMV_ptr(S.col(pq+1)):0;
625  for(int nn=n%2,st=(nn==0?0:1);nn<=order1;nn+=2,st+=nn) {
626  for(int s=nn,t=0;s>=t;--s,++t,++st) {
627 
628  double s0 = fp[s] * fq[t];
629  int iphase = s-t-p+q;
630  std::complex<double> s1 = s0 *
631  (iphase >= 0 ?
632  phase[iphase/2] :
633  std::conj(phase[-iphase/2]));
634 
635  if (p==q) {
636  if (s==t) {
637  Spq[st] = std::real(s1);
638  } else {
639  Spq[st] = std::real(s1);
640  Spq[st+1] = std::imag(s1);
641  ++st;
642  }
643  } else if (s==t) {
644  Spq[st] = 2.*std::real(s1);
645  Spq1[st] = -2.*std::imag(s1);
646  } else {
647  s0 = fq[s] * fp[t];
648  iphase = s-t-q+p;
649  std::complex<double> s2 = s0 *
650  (iphase >= 0 ?
651  phase[iphase/2] :
652  std::conj(phase[-iphase/2]));
653  Spq[st]= std::real(s1) + std::real(s2);
654  Spq1[st] = -std::imag(s1) + std::imag(s2);
655  Spq[st+1] = std::imag(s1) + std::imag(s2);
656  Spq1[st+1] = std::real(s1) - std::real(s2);
657  ++st;
658  }
659  }
660  }
661  if (p!=q) ++pq;
662  }
663  }
664  }
665 
666  void applyG(std::complex<double> g, BVec& b)
667  {
668  if (g != 0.0) {
669  DMatrix S(int(b.size()),int(b.size()));
670  calculateGTransform(g,b.getOrder(),S);
671  b.vec() = S * b.vec();
672  }
673  }
674 
676  const BVec& bpsf, int order1, int order2, double sigma, DMatrix& C)
677  {
678  //xdbg<<"Start calculatePsfConvolve\n";
679  //xdbg<<"bpsf = "<<bpsf<<std::endl;
680  //xdbg<<"order = "<<order<<std::endl;
681  //xdbg<<"sigma = "<<sigma<<std::endl;
682  // Just make the matrix which multiplies b to effect the convolution.
683  // b_obs = C * b_init
684  // However, we do not actually use it this way. Rather, we use it to
685  // switch the model from:
686  // I = Sum psi_pq b_obs_pq
687  // to
688  // I = Sum psi_pq C b_init_pq
689  // We use this to solve for the ML b_init.
690  const int order3 = bpsf.getOrder();
691  Assert(int(C.TMV_colsize()) >= (order1+1)*(order2+2)/2);
692  Assert(int(C.TMV_rowsize()) >= (order2+1)*(order2+2)/2);
693  Assert(int(bpsf.size()) == (order3+1)*(order3+2)/2);
694 
695  // C(st,pq) = 1/sqrt(pi) Sum_uv sqrt(p!u!q!v!/s!t!)/w!
696  // G(s,p,u) G(t,q,v) bpsf_uv
697  // The sum is only over terms for which p+u-s == q+v-t,
698  // and w = p+u-s = q+v-t >= 0
699  //
700  // G(0,p,u) = binom(p+u,u) (-A)^u B^p
701  // G(s+1,p,u) = A G(s,p-1,u) + B G(s,p,u-1)
702  // where A = sigma_init / sigma_obs, B = sigma_psf / sigma_obs
703  // D = A^2 = 1-B^2
704  //
705  // It is more efficient to combine the sqrt(p!u!/s!w!) into the G(s,p,u).
706  // Call the product H(s,p,u). We need to translate the above formulae:
707  // H(0,p,u) = sqrt(p!u!/(p+u)!) (p+u)!/(p!u!) (-A)^u B^p
708  // = sqrt((p+u)!/(p!u!)) (-A)^u B^p
709  // H(s+1,p,u) = sqrt(p!u!/(s+1)!(p+u-s-1)!) * [
710  // A H(s,p-1,u) / sqrt((p-1)!u!/s!(p+u-s-1)!) +
711  // B H(s,p,u-1) / sqrt(p!(u-1)!/s!(p+u-s-1)!) ]
712  // = A sqrt(p)/sqrt(s+1) H(s,p-1,u) +
713  // B sqrt(u)/sqrt(s+1) H(s,p,u-1)
714 
715  C.setZero();
716 
717  // sigma^2 = exp(mu)
718  // D = sigma_i^2 / (sigma_i^2 + sigma_psf^2)
719  // = 1 / (1 + (sigma_psf/sigma_i)^2)
720  double D = 1./(1.+pow(bpsf.getSigma()/sigma,2));
721  double A = sqrt(D);
722  double B = sqrt(1-D);
723 
724  std::vector<std::vector<std::vector<double> > > H(
725  order1+1,std::vector<std::vector<double> >(
726  order2+1,std::vector<double>(order3+1)));
727 
728  H[0][0][0] = 1.; // H[0](0,0)
729  for(int u=0;u<=order3;++u) {
730  if (u>0) H[0][0][u] = -A * H[0][0][u-1];
731  for(int p=1;p<=order2;++p)
732  H[0][p][u] = B*sqrtn(p+u)/sqrtn(p)*H[0][p-1][u]; // H[0](p,u)
733  }
734  for(int s=0;s<order1;++s) {
735  H[s+1][0][0] = 0.;
736  for(int p=1;p<=order2;++p)
737  H[s+1][p][0] = A*sqrtn(p)*H[s][p-1][0]/sqrtn(s+1);
738  for(int u=1;u<=order3;++u) {
739  H[s+1][0][u] = B*sqrtn(u)*H[s][0][u-1]/sqrtn(s+1);
740  for(int p=1;p<=order2;++p)
741  H[s+1][p][u] = (A*sqrtn(p)*H[s][p-1][u] +
742  B*sqrtn(u)*H[s][p][u-1])/ sqrtn(s+1);
743  }
744  }
745 
746  int pq = 0;
747  const double* bpsfv = TMV_cptr(bpsf.vec());
748  for(int n=0;n<=order2;++n) {
749  for(int p=n,q=0;p>=q;(p==q?++pq:pq+=2),--p,++q) {
750  //xdbg<<"Start column "<<pq<<" = "<<p<<','<<q<<std::endl;
751  int pmq = p-q;
752  double* Cpq = TMV_ptr(C.col(pq));
753  double* Cpq1 = p>q?TMV_ptr(C.col(pq+1)):0;
754  int st = 0;
755  for(int nn=0;nn<=order1;++nn) {
756  for(int s=nn,t=0;s>=t;(s==t?++st:st+=2),--s,++t) {
757  //xdbg<<"st = "<<st<<" = "<<s<<','<<t<<std::endl;
758  int smt = s-t;
759  double Cpqst = 0.;
760  double Cpq1st = 0.;
761  double Cpqst1 = 0.;
762  double Cpq1st1 = 0.;
763  const std::vector<double>& Hsp = H[s][p];
764  const std::vector<double>& Hsq = H[s][q];
765  const std::vector<double>& Htp = H[t][p];
766  const std::vector<double>& Htq = H[t][q];
767  int uv0 = 0;
768  int parity = (n+nn)%2;
769  for(int upv=0;upv<=order3;++upv,uv0+=upv) {
770  if (upv % 2 != parity) continue;
771  // There are three values of u-v that are worth considering:
772  // u-v = (s-t) - (p-q) >= 0
773  // u-v = (s-t) + (p-q) > 0
774  // u-v = (p-q) - (s-t) < 0
775 
776  int umv = smt-pmq;
777  if (umv >= 0 && umv <= upv) {
778  // First do terms with p>=q, u>=v (always keep s>=t)
779  // s-t = p-q + u-v
780  int u = (upv+umv)/2;
781  int v = (upv-umv)/2;
782 
783  int w = p+u-s;
784  Assert(q+v-t == w);
785  //Assert((w >= 0) == (umv >= 0));
786  if (w >= 0) {
787  int uv = uv0 + 2*v;
788  if (umv == 0) {
789  double temp = Hsp[u]*Htq[v]*bpsfv[uv];
790  if (s==t) {
791  Assert(p==q);
792  Cpqst += temp;
793  } else {
794  Cpqst += temp;
795  Cpq1st1 += temp;
796  }
797  } else {
798  Assert(s>t);
799  double tempr = Hsp[u]*Htq[v];
800  double tempi = tempr * bpsfv[uv+1];
801  tempr *= bpsfv[uv];
802  if (p==q) {
803  Cpqst += tempr;
804  Cpqst1 += tempi;
805  } else {
806  Assert(p>q);
807  Cpqst += tempr;
808  Cpqst1 += tempi;
809  Cpq1st -= tempi;
810  Cpq1st1 += tempr;
811  }
812  }
813  }
814  }
815 
816  umv = smt+pmq;
817  if (pmq != 0 && umv <= upv) {
818  // Next p<q, u>v. Implement by swapping p,q
819  // These terms account for the fact that
820  // b_init_qp = b_init_pq*
821  // s-t = q-p + u-v
822 
823  Assert(umv > 0);
824  int u = (upv+umv)/2;
825  int v = (upv-umv)/2;
826 
827  int w = q+u-s;
828  Assert(p+v-t == w);
829  //Assert((w >= 0) == (umv > 0));
830  if (w >= 0) {
831  int uv = uv0 + 2*v;
832  //Assert(w > 0);
833  //Assert((w > 0) == (umv > 0));
834  Assert(u>v);
835  double tempr = Hsq[u]*Htp[v];
836  double tempi = tempr * bpsfv[uv+1];
837  tempr *= bpsfv[uv];
838  if (smt==0) {
839  Cpqst += tempr;
840  Cpq1st += tempi;
841  } else {
842  Cpqst += tempr;
843  Cpqst1 += tempi;
844  Cpq1st += tempi;
845  Cpq1st1 -= tempr;
846  }
847  }
848  }
849 
850  umv = pmq-smt;
851  if (umv > 0 && umv <= upv) {
852  // Next p>q, u<v.
853  // These terms account for b_psf_vu = b_psf_uv*
854  int u = (upv+umv)/2;
855  int v = (upv-umv)/2;
856 
857  int w = p+v-s;
858  Assert(q+u-t == w);
859  if (w >= 0) {
860  int uv = uv0 + 2*v;
861  // s-t = p-q + v-u
862  Assert(p>q);
863  double tempr = Hsp[v]*Htq[u];
864  double tempi = -tempr * bpsfv[uv+1];
865  tempr *= bpsfv[uv];
866  if (smt==0) {
867  Cpqst += tempr;
868  Cpq1st -= tempi;
869  } else {
870  Cpqst += tempr;
871  Cpqst1 += tempi;
872  Cpq1st -= tempi;
873  Cpq1st1 += tempr;
874  }
875  }
876  }
877  }
878  Assert(uv0 == int(bpsf.size()));
879  //xdbg<<"Cpq[st] = "<<Cpqst<<std::endl;
880  Cpq[st] = Cpqst;
881  if (smt != 0) Cpq[st+1] = Cpqst1;
882  if (pmq != 0) {
883  Cpq1[st] = Cpq1st;
884  if (smt != 0) Cpq1[st+1] = Cpq1st1;
885  }
886  }
887  }
888  Assert(st == int(C.TMV_colsize()));
889  }
890  }
891  Assert(pq == int(C.TMV_rowsize()));
892  C /= afwGeom::SQRTPI;
893  }
894 
895  void applyPsf(const BVec& bpsf, BVec& b)
896  {
897  DMatrix C(int(b.size()),int(b.size()));
898  calculatePsfConvolve(bpsf,b.getOrder(),b.getSigma(),C);
899  b.vec() = C * b.vec();
900  }
901 
902 }}}}
void augmentMuTransformCols(double mu, int order, DMatrix &D)
Definition: BVec.cc:316
void assignTo(BVec &bvec) const
Definition: BVec.cc:51
virtual void assignTo(BVec &bvec) const =0
void applyPsf(const BVec &bpsf, BVec &b)
Definition: BVec.cc:895
BVec & operator=(const AssignableToBVec &rhs)
Definition: BVec.cc:39
T norm(const T &x)
Definition: Integrate.h:191
void calculateGTransform(std::complex< double > g, int order1, int order2, DMatrix &S)
Definition: BVec.cc:468
void applyG(std::complex< double > g, BVec &b)
Definition: BVec.cc:666
#define TMV_cptr(m)
Definition: MyMatrix.h:206
#define TMV_ptr(m)
Definition: MyMatrix.h:205
afw::table::Key< double > sigma
Definition: GaussianPsf.cc:43
void augmentZTransformCols(std::complex< double > z, int order, DMatrix &T)
Definition: BVec.cc:156
void calculateZTransform(std::complex< double > z, int order1, int order2, DMatrix &T)
Definition: BVec.cc:84
double w
Definition: CoaddPsf.cc:57
void setValues(const DVector &v)
Definition: BVec.cc:57
void setSigma(double sigma)
Definition: BVec.h:69
void applyZ(std::complex< double > z, BVec &b)
Definition: BVec.cc:218
void calculateThetaTransform(double theta, int order1, int order2, DBandMatrix &R)
Definition: BVec.cc:419
void augmentMuTransformRows(double mu, int order, DMatrix &D)
Definition: BVec.cc:366
void augmentGTransformCols(std::complex< double > g, int order, DMatrix &S)
Definition: BVec.cc:577
void applyMu(double mu, BVec &b)
Definition: BVec.cc:410
tuple m
Definition: lsstimport.py:48
afw::table::Key< double > b
#define xdbg
Definition: dbg.h:70
void calculatePsfConvolve(const BVec &bpsf, int order1, int order2, double sigma, DMatrix &C)
Definition: BVec.cc:675
T real(const T &x)
Definition: Integrate.h:193
double const SQRTPI
Definition: Angle.h:22
#define Assert(x)
Definition: dbg.h:73
void calculateMuTransform(double mu, int order1, int order2, DMatrix &D)
Definition: BVec.cc:227
#define TMV_stepj(m)
Definition: MyMatrix.h:208
void applyTheta(double theta, BVec &b)
Definition: BVec.cc:455