1 //
2 //  Solvmat.cpp
3 //  pbsam_xcode
4 //
5 //  Created by David Brookes on 6/20/16.
6 //  Copyright © 2016 David Brookes. All rights reserved.
7 //
8 
9 #include "Solvmat.h"
10 
11 
12 // computes Y = alpha*A*X + beta*Y
13 //applyMMat(IMat, &(fin), &(fout), 1.0, 0.0, p2, D, p2);
applyMMat(const double * A,const double * X,double * Y,const double alpha,const double beta,int ma,int nc,int na)14 void applyMMat(const double * A, const double * X, double * Y,
15                const double alpha, const double beta, int ma, int nc, int na)
16 
17 {
18   const int M = ma;
19   const int N = nc;
20   const int K = na;
21   const int lda = M;
22   const int ldb = K;
23   const int ldc = M;
24 
25 #ifdef __ACML
26   char transA = 'N';
27   char transB = 'N';
28   dgemm(transA, transB, M, N, &K, alpha, const_cast<double*>(A), lda,
29         const_cast<double*>(X), ldb, beta, Y, ldc);
30 #endif // ifACML
31 
32 #ifdef __MKL
33   char transA = 'N';
34   char transB = 'N';
35   dgemm(&transA, &transB, &M, &N, &K, &alpha, const_cast<double*>(A), &lda,
36         const_cast<double*>(X), &ldb, &beta, Y, &ldc);
37 #endif // ifMKL
38 
39 #if defined(__MACOS) || defined(__XCODE)
40   CBLAS_ORDER Order = CblasColMajor;
41   CBLAS_TRANSPOSE TransA = CblasNoTrans;
42   CBLAS_TRANSPOSE TransB = CblasNoTrans;
43   cblas_dgemm(Order, TransA, TransB, M, N, K, alpha, A, lda,
44               X,  ldb, beta, Y, ldc);
45 #endif
46 
47   return;
48 }
49 
50 
make_uniform_sph_grid(int m_grid,double r)51 vector<Pt> make_uniform_sph_grid(int m_grid, double r)
52 {
53   vector<Pt> grid (m_grid);
54   Pt gp;
55   grid[0].set_r(r);
56   grid[0].set_theta(0.0);
57   grid[0].set_phi(0.0);
58   double hk;
59   for (int k = 1; k < m_grid+1; k++)
60   {
61     grid[k-1].set_r(r);
62     hk = -1.0 + ((2.0 * ( (double)k-1.0)) / ( (double) m_grid-1.0));
63     grid[k-1].set_theta(acos(hk));
64 
65 
66     if ( k == 1 || k == m_grid) grid[k-1].set_phi(0);
67     else
68       grid[k-1].set_phi(grid[k-2].phi() +
69                         (3.6/sqrt(m_grid*(1.0-(hk*hk)))));
70 
71     while(grid[k-1].phi() > 2*M_PI) grid[k-1].set_phi(grid[k-1].phi()-2*M_PI);
72     while(grid[k-1].phi() <-2*M_PI) grid[k-1].set_phi(grid[k-1].phi()+2*M_PI);
73   }
74   return grid;
75 }
76 
calc_n_grid_pts(int p,double r)77 int calc_n_grid_pts(int p, double r)
78 {
79   // not about how these were chosen, taken directly from old stuff
80   int npPerOsc(5), nmin(1000), nmax(72000), nFinal;
81   int npts = (int) npPerOsc * 0.5 * p;
82   if (npts < nmin) npts = nmin;
83   if (npts > nmax) npts = nmax;
84 
85   int minPts = 200;
86   double cutoff(1.5), maxrad(10.0);
87   const double gradient = npts / ((maxrad-cutoff)*(maxrad-cutoff));
88   if (r < cutoff ) nFinal = minPts;
89   else
90   {
91     nFinal = int ( minPts + gradient * (r-cutoff) * (r-cutoff) );
92     if (nFinal > npts) nFinal = npts;
93   }
94   return nFinal;
95 }
96 
compute_coeffs()97 void ExpansionConstants::compute_coeffs()
98 {
99   int ct = 0;
100   // constants
101   for(int l=0; l < p_; l++)
102   {
103     set_const1_l( l, (2.0*l+1.0) / (4.0*M_PI));
104     set_const2_l( l,  1.0/ (double)(2*l+1));
105     for(int m=0; m <= l; m++)
106     {
107       imatLoc_[ct] = vector<int> {l, m};
108       ct++;
109     }
110   }
111 }
112 
inner_prod(MyMatrix<cmplx> & M1,MyMatrix<cmplx> & M2,int p)113 double inner_prod( MyMatrix<cmplx> & M1, MyMatrix<cmplx> & M2, int p )
114 {
115   double sum = 0;
116 
117   for (int n = 0; n < p; n++)
118     for (int m = -n; m <= n; m++)
119     {
120       sum += (M1(n, m+p).real() * M2(n, m+p).real()
121               + M1(n, m+p).imag() * M2(n, m+p).imag());
122     }
123   return sum;
124 }
125 
126 
ExpansionConstants(int p)127 ExpansionConstants::ExpansionConstants(int p)
128 : p_(p), expansionConst1_(p), expansionConst2_(p), imatLoc_(p*p)
129 {
130   compute_coeffs();
131 }
132 
133 
ComplexMoleculeMatrix(int I,int ns,int p)134 ComplexMoleculeMatrix::ComplexMoleculeMatrix(int I, int ns, int p)
135 :p_(p), mat_(ns, MyMatrix<cmplx> (p, 2*p+1)), I_(I)
136 {
137 }
138 
reset_mat(int k)139 void ComplexMoleculeMatrix::reset_mat(int k)
140 {
141   for (int i = 0; i < mat_[k].get_nrows(); i++)
142   {
143     for (int j = 0; j < mat_[k].get_ncols(); j++)
144     {
145       mat_[k].set_val(i, j, cmplx(0, 0));
146     }
147   }
148 }
149 
NumericalMatrix(int I,int ns,int p)150 NumericalMatrix::NumericalMatrix(int I, int ns, int p)
151 :p_(p), mat_(ns), mat_cmplx_(ns, MyMatrix<cmplx> (p, 2*p+1)), I_(I)
152 {
153 }
154 
reset_mat(int k)155 void NumericalMatrix::reset_mat(int k)
156 {
157   for (int i = 0; i < mat_cmplx_[k].get_nrows(); i++)
158   {
159     for (int j = 0; j < mat_cmplx_[k].get_ncols(); j++)
160     {
161       mat_cmplx_[k].set_val(i, j, cmplx(0, 0));
162     }
163   }
164 
165 }
166 
167 
EMatrix(int I,int ns,int p)168 EMatrix::EMatrix(int I, int ns, int p)
169 :ComplexMoleculeMatrix(I, ns, p)
170 {
171 }
172 
calc_vals(shared_ptr<BaseMolecule> mol,shared_ptr<SHCalc> _shcalc,double eps_in)173 void EMatrix::calc_vals(shared_ptr<BaseMolecule> mol,
174                         shared_ptr<SHCalc> _shcalc,
175                         double eps_in)
176 {
177   cmplx val;
178   Pt cen;
179   double r_alpha, a_k, q_alpha;
180   for (int k=0; k< mol->get_ns(); k++)
181   {
182     vector<int> allin = mol->get_ch_allin_k(k);
183     for (int alpha=0; alpha < allin.size(); alpha++)
184     {
185       cen = (mol->get_posj_realspace(allin[alpha]) - mol->get_centerk(k));
186       _shcalc->calc_sh(cen.theta(), cen.phi());
187       for (int n = 0; n < p_; n++)
188       {
189         for (int m = -n; m < n+1; m++)
190         {
191           q_alpha = mol->get_qj(allin[alpha]);
192           r_alpha = cen.r();
193           a_k = mol->get_ak(k);
194 
195           val = _shcalc->get_result(n, m);
196           val *= q_alpha / eps_in;
197           val *= pow(r_alpha / a_k, n);
198           val += get_mat_knm(k, n, m);
199           set_mat_knm(k, n, m, val);
200         }
201       }
202     }
203   }
204 }
205 
LEMatrix(int I,int ns,int p)206 LEMatrix::LEMatrix(int I, int ns, int p)
207 :ComplexMoleculeMatrix(I, ns, p)
208 {
209 }
210 
calc_vals(shared_ptr<BaseMolecule> mol,shared_ptr<SHCalc> _shcalc,double eps_in)211 void LEMatrix::calc_vals(shared_ptr<BaseMolecule> mol,
212                          shared_ptr<SHCalc> _shcalc,
213                          double eps_in)
214 {
215   cmplx val;
216   Pt cen;
217 
218   double r_alpha, a_k, q_alpha;
219   for (int k=0; k< mol->get_ns(); k++)
220   {
221     vector<int> allout = mol->get_ch_allout_k(k);
222     for (int alpha=0; alpha < allout.size(); alpha++)
223     {
224       cen = mol->get_posj_realspace(allout[alpha]) - mol->get_centerk(k);
225       _shcalc->calc_sh(cen.theta(), cen.phi());
226       for (int n = 0; n < p_; n++)
227       {
228         for (int m = -n; m < n+1; m++)
229         {
230           q_alpha = mol->get_qj(allout[alpha]);
231           r_alpha = cen.r();
232           a_k = mol->get_ak(k);
233 
234           val = _shcalc->get_result(n, m);
235           val *= q_alpha / eps_in;
236           val *= 1 / r_alpha;
237           val *= pow(a_k / r_alpha, n);
238           val += get_mat_knm(k, n, m);
239           set_mat_knm(k, n, m, val);
240         }
241       }
242     }
243   }
244 }
245 
246 
IEMatrix(int I,shared_ptr<BaseMolecule> _mol,shared_ptr<SHCalc> _shcalc,int p,shared_ptr<ExpansionConstants> _expconst,bool calc_npts,int npts,bool set_mol)247 IEMatrix::IEMatrix(int I, shared_ptr<BaseMolecule> _mol,
248                    shared_ptr<SHCalc> _shcalc, int p,
249                    shared_ptr<ExpansionConstants> _expconst,
250                    bool calc_npts, int npts, bool set_mol)
251 : p_(p), I_(I),
252 IE_orig_(_mol->get_ns(), vector<double> (p*p*p*p)),
253 _expConst_(_expconst), calc_pts_(calc_npts), set_mol_(set_mol),
254 gridPts_(npts), gridPtLocs_(_mol->get_ns()),
255 grid_exp_(_mol->get_ns()),grid_bur_(_mol->get_ns())
256 {
257   compute_grid_pts(_mol);
258 }
259 
IEMatrix(shared_ptr<IEMatrix> imat_in)260 IEMatrix::IEMatrix(shared_ptr<IEMatrix> imat_in)
261 : p_(imat_in->p_), I_(imat_in->I_),
262 IE_orig_(imat_in->IE_orig_),
263 _expConst_(imat_in->_expConst_),
264 calc_pts_(imat_in->calc_pts_), set_mol_(imat_in->set_mol_),
265 gridPts_(imat_in->gridPts_), gridPtLocs_(imat_in->gridPtLocs_),
266 grid_exp_(imat_in->grid_exp_),grid_bur_(imat_in->grid_bur_)
267 { }
268 
init_from_file(string imatfile,int k)269 void IEMatrix::init_from_file(string imatfile, int k )
270 {
271   IMatFile imat(imatfile, p_);
272   set_IE_k(k, imat.get_mat());
273 }
274 
init_from_other(shared_ptr<IEMatrix> other)275 void IEMatrix::init_from_other(shared_ptr<IEMatrix> other)
276 {
277   for (int k=0; k < other->get_k(); k++)
278     set_IE_k(k, other->get_IE_k_org(k));
279 }
280 
281 
get_IE_k(int k)282 MyMatrix<double> IEMatrix::get_IE_k(int k)
283 {
284   MyMatrix<double> IMat(p_*p_, p_*p_);
285 
286   int ind(0);
287   for (int l = 0; l < p_; l++)  // rows in old matrix
288     for (int s = 0; s < 2*l+1; s++)  //columns in old matrix
289       for (int n = 0; n < p_; n++)  // rows in new matrix
290         for (int m = 0; m < 2*n+1; m++)  // columns in new matrix
291         {
292           IMat(n*n+m, l*l+s) = get_IE_k_ind(k, ind);
293           ind++;
294         }
295 
296   return IMat;
297 }
298 
write_mat_k_reg(string imatFname,int k)299 void IEMatrix::write_mat_k_reg(string imatFname, int k)
300 {
301   ofstream fout;
302   fout.open(imatFname, ofstream::binary); //for writing
303   if (!fout)
304   {
305     cout << "file "<< imatFname << " could not be opened."<< endl;
306     exit(1);
307   }
308   fout << p_ << endl; // pole order
309   for (int i = 0; i< p_*p_*p_*p_; i++)
310   {
311     fout << IE_orig_[k][i] << " "; //mat
312     if ( (i%(p_*p_-1)) == 0 && (i > 0)) fout << endl;
313   }
314 
315   fout.close();
316 }
317 
write_mat_k(string imatFname,int k)318 void IEMatrix::write_mat_k(string imatFname, int k)
319 {
320   ofstream fout;
321   fout.open(imatFname, ofstream::binary); //for writing
322   if (!fout)
323   {
324     cout << "file "<< imatFname << " could not be opened."<< endl;
325     exit(1);
326   }
327   int length = p_*p_*p_*p_;
328   fout.write( reinterpret_cast<char const *> (&p_), sizeof(p_)); // pole order
329   fout.write( reinterpret_cast<char const *>(&IE_orig_[k][0]),
330              length*sizeof(double) ); //mat
331 
332   fout.close();
333 }
334 
compute_grid_pts(shared_ptr<BaseMolecule> _mol)335 void IEMatrix::compute_grid_pts(shared_ptr<BaseMolecule> _mol)
336 {
337   Pt real_grid;
338   vector<Pt> grid_loc;
339   for (int k = 0; k < _mol->get_ns(); k++)
340   {
341     vector<int> grid_exp, grid_bur;
342     vector<int> neighs = _mol->get_neighj(k);
343     if (calc_pts_) gridPts_ = calc_n_grid_pts(p_, _mol->get_ak(k));
344     grid_loc = make_uniform_sph_grid(gridPts_, _mol->get_ak(k));
345     if (set_mol_)    _mol->set_gridj(k, grid_loc);
346     else gridPtLocs_[k] = grid_loc;
347 
348     // Loop through points to find the exposed ones
349     for (int g = 0; g < gridPts_; g++)
350     {
351       bool buried = false;
352       // loop through other spheres in this BaseMolecule to find exposed gd pts:
353       for (int k2 = 0; k2 < neighs.size(); k2++)
354       {
355         real_grid = grid_loc[g] + _mol->get_centerk(k);
356         // check if sphere is overlapping another
357         if (real_grid.dist(_mol->get_centerk(neighs[k2]))
358             < _mol->get_ak(neighs[k2]))
359         {
360           grid_bur.push_back(g);
361           buried = true;
362           break;
363         }
364       }
365       if (!buried) grid_exp.push_back(g);
366     }
367 
368     if (set_mol_)
369     {
370       _mol->set_gridexpj(k, grid_exp);
371       _mol->set_gridburj(k, grid_bur);
372     } else
373     {
374       grid_bur_[k] = grid_bur;
375       grid_exp_[k] = grid_exp;
376     }
377 
378     grid_exp.clear(); grid_bur.clear();
379   }
380 }
381 
382 vector<MatOfMats<cmplx>::type >
compute_integral(shared_ptr<BaseMolecule> _mol,shared_ptr<SHCalc> sh_calc,int k)383 IEMatrix::compute_integral(shared_ptr<BaseMolecule> _mol,
384                            shared_ptr<SHCalc> sh_calc,
385                            int k)
386 {
387   int min, grid_tot;
388   bool bur;
389   vector<MatOfMats<cmplx>::type > Ys(2,
390                                      MatOfMats<cmplx>::type(p_, p_,
391                                                             MyMatrix<cmplx>
392                                                             (p_, p_)));
393   if (set_mol_)
394   {
395     gridPtLocs_[k] = _mol->get_gridj(k);
396     grid_bur_[k] = _mol->get_gdpt_burj(k);
397     grid_exp_[k] = _mol->get_gdpt_expj(k);
398   }
399 
400   grid_tot = (int) (grid_bur_[k].size() + grid_exp_[k].size());
401 
402   if ( grid_bur_[k].size() < grid_exp_[k].size() )
403   {
404     bur = true;
405     min = (int)grid_bur_[k].size();
406   }
407   else
408   {
409     bur = false;
410     min = (int)grid_exp_[k].size();
411   }
412   for(int h=0; h<min; h++)
413   {
414     double w=0;
415     int ind = (bur) ? grid_bur_[k][h] : grid_exp_[k][h];
416     Pt gdpt = gridPtLocs_[k][ind];
417     // convert the position relative to the center to spherical coordinates.
418     sh_calc->calc_sh(gdpt.theta(), gdpt.phi());
419 
420     // collect sums for (n,m) rows x (l,s) column
421     for(int l = 0; l < p_; l++)
422       for(int s = 0; s <= l; s++)
423       {
424         cmplx Yls, Ynm;
425         if(s==0) Yls = complex<double> (sh_calc->get_result(l,0));
426         else     Yls = complex<double> (sh_calc->get_result(l,s));
427 
428         for(int n=0; n<=l; n++)
429           for(int m=0; m<=n; m++)
430           {
431             if( n==l && m > s) break;
432             if(m==0) Ynm = complex<double> (sh_calc->get_result(n,0));
433             else     Ynm = complex<double> (sh_calc->get_result(n,m));
434 
435             // integrate using the appropriate integration rules
436             if(m==0 && s==0 && (n+l)%2==0) //simpson's rule
437             {
438               if(h > 0 && h < grid_tot)
439               {
440                 if(h % 2 == 0 ) w = 2.0/3.0; // even
441                 else w = 4.0/3.0; //odd
442               } else w = 1.0/3.0;
443             } else w = 1.0; // rectangular
444             // Yrr and Yri
445             Ys[0](l,s).set_val(n, m, Ys[0](l,s)(n,m)+ w * complex<double>
446                                (Yls.real()*Ynm.real(), Yls.real()*Ynm.imag()));
447             // Yir and Yii
448             Ys[1](l,s).set_val(n, m, Ys[1](l,s)(n,m) + w * complex<double>
449                                (Yls.imag()*Ynm.real(), Yls.imag()*Ynm.imag()));
450           }//nm
451       }//ls
452     if( h % 10000 == 0 ) cout <<"completed "<<h<<" points "<<endl;
453   }//h
454 
455   double dA = 4*M_PI / (double)(grid_tot-1);
456   double mul = (bur) ? -1.0 : 1.0;
457   for(int l=0; l<p_; l++)
458   {
459     double delta = (bur) ? 1.0/_expConst_->get_const1_l(l) : 0.0;
460     for(int s=0; s<=l; s++)
461       for(int n=0; n<=l; n++)
462         for(int m=0; m<=n; m++)
463         {
464           if( n==l && m > s ) break;
465           if( n==l && m==s )
466           {
467             if(m==0)
468             {
469               Ys[0](l,s)(n,m).real(delta + mul*dA*Ys[0](l,s)(n,m).real());
470               Ys[1](l,s)(n,m).imag(0.0);
471             }
472             else
473             {
474               Ys[0](l,s)(n,m).real(0.5*delta + mul*dA*Ys[0](l,s)(n,m).real());
475               Ys[1](l,s)(n,m).imag(0.5*delta + mul*dA*Ys[1](l,s)(n,m).imag());
476             }
477             Ys[0](l,s)(n,m).imag(Ys[0](l,s)(n,m).imag()*mul*dA);
478             Ys[1](l,s)(n,m).real(Ys[1](l,s)(n,m).real()*mul*dA);
479           }
480           else
481           {
482             Ys[0](l,s)(n,m) *= (mul*dA);
483             Ys[1](l,s)(n,m) *= (mul*dA);
484           }
485         } // end m
486   } // end l
487 
488   for(int l=0; l<p_; l++)
489     for(int s=0; s<=l; s++)
490       for(int n=0; n<=l; n++)
491         for(int m=0; m<=n; m++)
492         {
493           if( n==l && s < m)
494           {
495             vector<int> myind = _expConst_->get_imat_loc(m-s-1);
496             Ys[0](l,s).set_val(n, m, Ys[0](l,s+1)(myind[0], myind[1]));
497             Ys[1](l,s).set_val(n, m, Ys[1](l,s+1)(myind[0], myind[1]));
498           }
499         }
500 
501   return Ys;
502 } // end compute_integral
503 
504 // Currently using old format because I dont know whats going on!
505 // TODO: change to understandable
populate_mat(vector<MatOfMats<cmplx>::type> Ys,int k)506 void IEMatrix::populate_mat(vector<MatOfMats<cmplx>::type >  Ys, int k)
507 {
508   int i = 0;
509   int sNeg = -1; int mNeg = -1;
510   for(int l=0; l<p_; l++)
511   {
512     double imat;
513     for(int n=0; n<p_; n++) // s=0
514     {
515       double scl = _expConst_->get_const1_l(n);
516       for(int m=0; m<=n; m++)
517       {
518         bool bUpper = ( n<l || (n==l && m==0) );
519         imat = scl * (bUpper? Ys[0](l,0)(n,m).real():Ys[0](n,m)(l,0).real());
520         IE_orig_[k][i] = imat;
521         i++;
522         if ( m != 0 )
523         {
524           imat  = (bUpper ? Ys[0](l,0)(n,m).imag():Ys[1](n,m)(l,0).real());
525           IE_orig_[k][i] = (-1.0 * mNeg * scl * imat);
526           i++;
527         }
528       } //m
529     }//n
530 
531     for(int s=1; s<=l; s++) // s>0 and // (l,s)real columns
532     {
533       for(int n=0; n<p_; n++)
534       {
535         double scl = _expConst_->get_const1_l(n);
536         for(int m=0; m<=n; m++)
537         {
538           bool bUpper = ( n<l || (n==l && m<=s) );
539           imat = 2.*scl*(bUpper? Ys[0](l,s)(n,m).real():Ys[0](n,m)(l,s).real());
540           IE_orig_[k][i] = imat;
541           i++;
542           if ( m != 0 )
543           {
544             imat  = (bUpper? Ys[0](l,s)(n,m).imag():Ys[1](n,m)(l,s).real());
545             IE_orig_[k][i] = (mNeg * -2.0 * scl * imat);
546             i++;
547           }
548         } //m
549       }//n
550 
551       // (l,s)imag columns
552       for(int n=0; n<p_; n++)
553       {
554         double scl = _expConst_->get_const1_l(n);
555         for(int m=0; m<=n; m++)
556         {
557           bool bUpper = ( n<l || (n==l && m<=s) );
558           imat  = (bUpper? Ys[1](l,s)(n,m).real():Ys[0](n,m)(l,s).imag());
559           IE_orig_[k][i] =  (sNeg * -2.0 * scl * imat);
560           i++;
561           if ( m != 0 )
562           {
563             imat  = (bUpper? Ys[1](l,s)(n,m).imag():Ys[1](n,m)(l,s).imag());
564             IE_orig_[k][i] = (2.0 * scl * imat);
565             i++;
566           }
567         } //m
568       }//n
569     }//s
570   }//l
571 }
572 
calc_vals(shared_ptr<BaseMolecule> _mol,shared_ptr<SHCalc> _shcalc)573 void IEMatrix::calc_vals(shared_ptr<BaseMolecule> _mol,
574                          shared_ptr<SHCalc> _shcalc)
575 {
576   for (int k = 0; k < _mol->get_ns(); k++)
577   {
578     vector<MatOfMats<cmplx>::type > Ys = compute_integral(_mol, _shcalc, k);
579     populate_mat(Ys, k);
580   }
581 }
582 
reset_mat()583 void IEMatrix::reset_mat()
584 {
585   for (int k = 0; k < IE_orig_.size(); k++)
586   {
587     for (int ind = 0; ind < p_*p_*p_*p_; ind++)
588       IE_orig_[k][ind] = 0.0;
589   }
590 }
591 
LFMatrix(int I,int ns,int p)592 LFMatrix::LFMatrix(int I, int ns, int p)
593 :NumericalMatrix(I, ns, p)
594 {
595 }
596 
init(shared_ptr<BaseMolecule> mol,shared_ptr<FMatrix> F,shared_ptr<SHCalc> shcalc,shared_ptr<BesselCalc> bcalc,shared_ptr<PreCalcSH> pre_sh,shared_ptr<ExpansionConstants> _expconst,bool no_pre_sh)597 void LFMatrix::init(shared_ptr<BaseMolecule> mol, shared_ptr<FMatrix> F,
598                     shared_ptr<SHCalc> shcalc, shared_ptr<BesselCalc> bcalc,
599                     shared_ptr<PreCalcSH> pre_sh,
600                     shared_ptr<ExpansionConstants> _expconst,
601                     bool no_pre_sh)
602 {
603   double rl, im;
604   cmplx sh;
605   for (int k=0; k< mol->get_ns(); k++)
606   {
607     vector <int> exp_pts = mol->get_gdpt_expj(k);
608     mat_[k].resize( (int) exp_pts.size() );
609     double dA = 4 * M_PI / (double) mol->get_gridj(k).size();
610 
611     for (int h = 0; h < exp_pts.size(); h++)
612     {
613       double val = 0.0;
614       Pt q = mol->get_gridjh(k, exp_pts[h]);
615 
616       if (no_pre_sh) pre_sh->calc_and_add(q, shcalc);
617 
618       for (int n=0; n<p_; n++)
619       {
620         for (int m = -n; m <= n; m++)
621         {
622           sh = pre_sh->get_sh(q, n, m);
623           rl = sh.real()*F->get_mat_knm(k,n,m).real();
624           im = sh.imag()*F->get_mat_knm(k,n,m).imag();
625           val += dA*_expconst->get_const1_l(n) * ( rl + im );
626         }
627       }
628       set_mat_kh(k, h, val);
629     }
630   }
631 }
632 
calc_vals(shared_ptr<TMatrix> T,shared_ptr<FMatrix> F,shared_ptr<SystemSAM> sys,shared_ptr<PreCalcSH> pre_sh,int k,bool no_pre_sh)633 void LFMatrix::calc_vals(shared_ptr<TMatrix> T, shared_ptr<FMatrix> F,
634                          shared_ptr<SystemSAM> sys, shared_ptr<PreCalcSH> pre_sh,
635                          int k, bool no_pre_sh)
636 {
637   reset_mat(k);
638   MyMatrix<cmplx> reex;
639   for (int j = 0; j < T->get_nsi(I_); j++)
640   {
641     if (j==k) continue;
642 
643     if (T->is_analytic(I_, k, I_, j))
644     {
645       bool isF = true;
646       reex = T->re_expandX(F->get_mat_k(j), I_, k, I_, j, isF );
647     }
648     else
649     {
650       reex = T->re_expandX_numeric(get_mat(), I_, k, I_, j, 0.0, pre_sh,
651                                    no_pre_sh);
652     }
653 
654     mat_cmplx_[k] += reex;
655   }
656 }
657 
658 
LHMatrix(int I,int ns,int p,double kappa)659 LHMatrix::LHMatrix(int I, int ns, int p, double kappa)
660 :NumericalMatrix(I, ns, p), kappa_(kappa)
661 {
662 }
663 
init(shared_ptr<BaseMolecule> mol,shared_ptr<HMatrix> H,shared_ptr<SHCalc> shcalc,shared_ptr<BesselCalc> bcalc,shared_ptr<PreCalcSH> pre_sh,shared_ptr<ExpansionConstants> _expconst,bool no_pre_sh)664 void LHMatrix::init(shared_ptr<BaseMolecule> mol, shared_ptr<HMatrix> H,
665                     shared_ptr<SHCalc> shcalc, shared_ptr<BesselCalc> bcalc,
666                     shared_ptr<PreCalcSH> pre_sh,
667                     shared_ptr<ExpansionConstants> _expconst,
668                     bool no_pre_sh)
669 {
670   double rl, im;
671   cmplx sh;
672   for (int k=0; k< mol->get_ns(); k++)
673   {
674     vector <int> exp_pts = mol->get_gdpt_expj(k);
675     mat_[k].resize( (int) exp_pts.size() );
676     double dA = 4 * M_PI / (double) mol->get_gridj(k).size();
677 
678     for (int h = 0; h < exp_pts.size(); h++)
679     {
680       double val = 0.0;
681       Pt q = mol->get_gridjh(k, exp_pts[h]);
682       if (no_pre_sh) pre_sh->calc_and_add(q, shcalc);
683 
684       vector<double> bessI = bcalc->calc_mbfI(p_+1, kappa_*q.r());
685 
686       for (int n=0; n<p_; n++)
687       {
688         for (int m = -n; m <= n; m++)
689         {
690           sh = pre_sh->get_sh(q, n, m);
691 
692           rl = sh.real()*H->get_mat_knm(k,n,m).real();
693           im = sh.imag()*H->get_mat_knm(k,n,m).imag();
694           val += dA*_expconst->get_const1_l(n)*( rl + im )/bessI[n];
695         }
696       }
697       set_mat_kh(k, h, val);
698     }
699   }
700 }
701 
calc_vals(shared_ptr<TMatrix> T,shared_ptr<HMatrix> H,shared_ptr<PreCalcSH> pre_sh,int k,bool no_pre_sh)702 void LHMatrix::calc_vals(shared_ptr<TMatrix> T, shared_ptr<HMatrix> H,
703                          shared_ptr<PreCalcSH> pre_sh, int k, bool no_pre_sh)
704 {
705   reset_mat(k);
706   MyMatrix<cmplx> reex;
707 
708   for (int j = 0; j < T->get_nsi(I_); j++)
709   {
710     if (j==k) continue;
711 
712     if (T->is_analytic(I_, k, I_, j))
713       reex = T->re_expandX(H->get_mat_k(j), I_, k, I_, j );
714     else
715       reex = T->re_expandX_numeric(get_mat(), I_, k, I_, j, kappa_, pre_sh,
716                                    no_pre_sh);
717 
718     mat_cmplx_[k] += reex;
719   }
720 }
721 
722 
LHNMatrix(int I,int ns,int p,shared_ptr<SystemSAM> sys)723 LHNMatrix::LHNMatrix(int I, int ns, int p, shared_ptr<SystemSAM> sys)
724 :interPol_(ns, 1), ComplexMoleculeMatrix(I, ns, p)
725 {
726   Pt Ik, Jl;
727   double aIk, aJl, interPolcut = 10.0;
728   for (int k = 0; k <sys->get_Ns_i(I); k++)
729   {
730     for (int J = 0; J < sys->get_n(); J++)
731     {
732       if (J == I_) continue;
733       Ik = sys->get_centerik(I_, k);
734       aIk = sys->get_aik(I_, k);
735       for (int l = 0 ; l < sys->get_Ns_i(J); l++)
736       {
737         Jl = sys->get_centerik(J, l);
738         aJl = sys->get_aik(J, l);
739 
740         if ( sys->get_pbc_dist_vec_base(Ik, Jl).norm() < (interPolcut+aIk+aJl))
741         {
742           interPol_[k] = 0;
743         }
744       }
745     }
746   }
747 }
748 
calc_vals(shared_ptr<SystemSAM> sys,shared_ptr<TMatrix> T,vector<shared_ptr<HMatrix>> H,int k)749 void LHNMatrix::calc_vals(shared_ptr<SystemSAM> sys, shared_ptr<TMatrix> T,
750                           vector<shared_ptr<HMatrix> > H, int k)
751 {
752   reset_mat(k);
753   MyMatrix<cmplx> reex;
754   Pt Ik, Jl;
755   double aIk, aJl, interPolcut = 10.0;
756   for (int J = 0; J < T->get_nmol(); J++)
757   {
758     if (J == I_) continue;
759     Ik = sys->get_centerik(I_, k);
760     aIk = sys->get_aik(I_, k);
761     for (int l = 0 ; l < T->get_nsi(J); l++)
762     {
763       Jl = sys->get_centerik(J, l);
764       aJl = sys->get_aik(J, l);
765 
766       if ( sys->get_pbc_dist_vec_base(Ik, Jl).norm() < (interPolcut+aIk+aJl))
767       {
768 //        cout << "This is H before I " << I_ << " and k " << k
769 //        << " and j " << J << " and l " << l<< endl;
770 //        H[J]->print_kmat(l);
771         reex = T->re_expandX(H[J]->get_mat_k(l), I_, k, J, l);
772         mat_[k] += reex;
773 
774 //        cout << "This is H After " << endl;
775 //        for (int n = 0; n < p_; n++)
776 //        {
777 //          for (int m = 0; m <= n; m++)
778 //          {
779 //            cout << reex(n, m+p_) << ", ";
780 //          }
781 //          cout << endl;
782 //        }
783       }
784     }
785   }
786 
787 //  cout << "This is LHN I " << I_ << " and k " << k << endl;
788 //  print_kmat(k);
789 }
790 
XHMatrix(int I,int ns,int p,shared_ptr<BaseMolecule> mol,shared_ptr<EMatrix> E,shared_ptr<LEMatrix> LE)791 XHMatrix::XHMatrix(int I, int ns, int p,
792                    shared_ptr<BaseMolecule> mol,
793                    shared_ptr<EMatrix> E,
794                    shared_ptr<LEMatrix> LE)
795 : ComplexMoleculeMatrix(I, ns, p), E_LE_mat_(ns, MyMatrix<cmplx> (p, 2*p+1))
796 {
797   double ak;
798 
799   for (int k = 0; k < ns; k++)
800   {
801     ak = mol->get_ak(k);
802     for (int n = 0; n < p_; n++)
803     {
804       for (int m = -n; m < n+1; m++)
805       {
806         E_LE_mat_[k](n, m+p) = (E->get_mat_knm(k, n, m) +
807                                 ak*LE->get_mat_knm(k, n, m));
808       }
809     }
810   }
811 }
812 
calc_vals(shared_ptr<BaseMolecule> mol,shared_ptr<BesselCalc> bcalc,shared_ptr<LHMatrix> LH,shared_ptr<LFMatrix> LF,shared_ptr<LHNMatrix> LHN,double kappa,int k)813 void XHMatrix::calc_vals(shared_ptr<BaseMolecule> mol, shared_ptr<BesselCalc> bcalc,
814                          shared_ptr<LHMatrix> LH, shared_ptr<LFMatrix> LF,
815                          shared_ptr<LHNMatrix> LHN, double kappa, int k)
816 {
817   cmplx inner;
818   double ak = mol->get_ak(k);
819   vector<double> in_k = bcalc->calc_mbfI(p_, kappa * ak);
820 
821   for (int n = 0; n < p_; n++)
822   {
823     for (int m = - n; m <= n; m++)
824     {
825       inner = E_LE_mat_[k]( n, m+p_);
826       inner += ak*LF->get_mat_knm(k, n, m);
827       inner -= ak*in_k[n]*(LH->get_mat_knm(k, n, m)+LHN->get_mat_knm(k, n, m));
828       set_mat_knm(k, n, m, inner);
829     }
830   }
831 }
832 
833 
XFMatrix(int I,int ns,int p,double eps_in,double eps_out,shared_ptr<BaseMolecule> mol,shared_ptr<EMatrix> E,shared_ptr<LEMatrix> LE)834 XFMatrix::XFMatrix(int I, int ns, int p, double eps_in, double eps_out,
835                    shared_ptr<BaseMolecule> mol, shared_ptr<EMatrix> E,
836                    shared_ptr<LEMatrix> LE)
837 :ComplexMoleculeMatrix(I, ns, p), eps_(eps_in/eps_out),
838 E_LE_mat_(ns, MyMatrix<cmplx> (p, 2*p+1))
839 {
840   double ak;
841 
842   for (int k = 0; k < ns; k++)
843   {
844     ak = mol->get_ak(k);
845     for (int n = 0; n < p_; n++)
846     {
847       for (int m = -n; m <= n; m++)
848       {
849         E_LE_mat_[k](n, m+p_) = eps_ * ((double)(n+1) * E->get_mat_knm(k, n, m)
850                                         - n * ak * LE->get_mat_knm(k, n, m));
851       }
852     }
853   }
854 }
855 
calc_vals(shared_ptr<BaseMolecule> mol,shared_ptr<BesselCalc> bcalc,shared_ptr<LHMatrix> LH,shared_ptr<LFMatrix> LF,shared_ptr<LHNMatrix> LHN,double kappa,int k)856 void XFMatrix::calc_vals(shared_ptr<BaseMolecule> mol, shared_ptr<BesselCalc> bcalc,
857                          shared_ptr<LHMatrix> LH, shared_ptr<LFMatrix> LF,
858                          shared_ptr<LHNMatrix> LHN, double kappa, int k)
859 {
860   cmplx inner;
861   double ak = mol->get_ak(k);
862   vector<double> in_k = bcalc->calc_mbfI(p_+1, kappa * ak);
863 
864   for (int n = 0; n < p_; n++)
865   {
866     for (int m = -n; m < n+1; m++)
867     {
868       inner = (pow(kappa * ak, 2.0) * in_k[n+1])/(double)(2*n+3);
869       inner += double(n * in_k[n]);
870       inner *= ( ak * (LH->get_mat_knm(k, n, m) + LHN->get_mat_knm(k, n, m)));
871       inner += E_LE_mat_[k]( n, m+p_);
872       inner -= ( n * eps_ * ak * LF->get_mat_knm(k, n, m));
873       set_mat_knm(k, n, m, inner);
874     }
875   }
876 
877 }
878 
HMatrix(int I,int ns,int p,double kappa)879 HMatrix::HMatrix(int I, int ns, int p, double kappa)
880 :ComplexMoleculeMatrix(I, ns, p), kappa_(kappa)
881 {
882 }
883 
884 
init_from_exp(string hfilename,int k)885 void HMatrix::init_from_exp(string hfilename, int k)
886 {
887   HFFile hfil( hfilename, p_);
888   set_mat_k(k, hfil.get_mat());
889 }
890 
891 
892 // Initialize H matrix to E with charges mapped to cg (mol.cgCharges_)
init(shared_ptr<BaseMolecule> mol,shared_ptr<SHCalc> _sh_calc,double eps_in)893 void HMatrix::init(shared_ptr<BaseMolecule> mol,
894                    shared_ptr<SHCalc> _sh_calc, double eps_in)
895 {
896   cmplx val;
897   Pt cen;
898   double r_alpha, a_k, q_alpha;
899   for (int k=0; k< mol->get_ns(); k++)
900   {
901     for (int alpha=0; alpha < mol->get_nc_k(k); alpha++)
902     {
903       cen = mol->get_posj(mol->get_ch_k_alpha(k, alpha));
904       _sh_calc->calc_sh(cen.theta(), cen.phi());
905       for (int n = 0; n < p_; n++)
906       {
907         for (int m = -n; m < n+1; m++)
908         {
909           q_alpha = mol->get_qj(mol->get_ch_k_alpha(k, alpha));
910           r_alpha = cen.r();
911           a_k = mol->get_ak(k);
912 
913           val = _sh_calc->get_result(n, m);
914           val *= q_alpha / eps_in;
915           val *= pow(r_alpha / a_k, n);
916           val += get_mat_knm(k, n, m);
917           set_mat_knm(k, n, m, val);
918         }
919       }
920     }
921   }
922 }
923 
calc_vals(shared_ptr<BaseMolecule> mol,shared_ptr<HMatrix> prev,shared_ptr<XHMatrix> XH,shared_ptr<FMatrix> F,shared_ptr<IEMatrix> IE,shared_ptr<BesselCalc> bcalc,int k)924 void HMatrix::calc_vals(shared_ptr<BaseMolecule> mol,
925                         shared_ptr<HMatrix> prev,
926                         shared_ptr<XHMatrix> XH,
927                         shared_ptr<FMatrix> F,
928                         shared_ptr<IEMatrix> IE,
929                         shared_ptr<BesselCalc> bcalc, int k)
930 {
931   int ct = 0;
932   cmplx inner;
933   double ak = mol->get_ak(k);
934   double h_in[p_*p_], h_out[p_*p_];
935   vector<double> bessel_i = bcalc->calc_mbfI(p_+1, kappa_*ak);
936   vector<double> bessel_k = bcalc->calc_mbfK(p_+1, kappa_*ak);
937 
938   for (int l = 0; l < p_; l++)  // rows in old matrix
939   {
940     for (int s = 0; s < l+1; s++)  //columns in old matrix
941     {
942       inner = (2.0 * l + 1.0) / bessel_i[l];
943       inner -= exp(-kappa_*ak) * bessel_k[l];
944       inner *= prev->get_mat_knm(k, l, s);
945       inner += F->get_mat_knm(k, l, s);
946       inner += XH->get_mat_knm(k, l, s);
947 
948       h_in[ct] = inner.real();
949       ct++;
950       if ( s > 0 )
951       {
952         h_in[ct] = inner.imag();
953         ct++;
954       }
955     }
956   }
957 
958   const int p2 = p_*p_;
959 #ifdef __LAU
960   applyMMat(&IE->get_IE_k_org(k)[0], &h_in[0], &h_out[0], 1.0, 0.0, p2, 1, p2);
961 #else
962   MyMatrix<double> h_out1(p2, 1);
963   MyMatrix<double> h_in1 (p2, 1, h_in);
964   h_out1 = IE->get_IE_k(k) * h_in1;  // Matrix vector multiplication
965 #endif
966 
967   int ctr(0);
968   for (int n = 0; n < p_; n++)  // rows in new matrix
969   {
970     double scl = bessel_i[n] / (double)(2.0*n+1.0);
971     for (int m = 0; m < n+1; m++)  // columns in new matrix
972     {
973       double hRe, hIm;
974 #ifdef __LAU
975       hRe = h_out[ctr];
976 #else
977       hRe = h_out1(ctr,0);
978 #endif
979       ctr++;
980 
981       if ( m > 0 )
982       {
983 #ifdef __LAU
984         hIm = h_out[ctr];
985 #else
986         hIm = h_out1(ctr,0);
987 #endif
988         ctr++;
989       } else
990         hIm = 0.0;
991 
992       set_mat_knm(k, n, m, scl * complex<double> (hRe, hIm));
993       if ( m > 0 ) set_mat_knm(k, n, -m, scl * complex<double> (hRe, -hIm));
994     }
995   }
996 }
997 
make_hb_Ik(int k,Pt rb,shared_ptr<SHCalc> shcalc,vector<double> besseli)998 cmplx HMatrix::make_hb_Ik(int k, Pt rb,
999                           shared_ptr<SHCalc> shcalc,
1000                           vector<double> besseli)
1001 {
1002   cmplx hb_inner, hbj;
1003   vector<cmplx> h;
1004 
1005   shcalc->calc_sh(rb.theta(), rb.phi());
1006   hbj = 0;
1007   for (int n = 0; n < p_; n++)
1008   {
1009     for (int m = -n; m < n+1; m++)
1010     {
1011       hb_inner = ((2*n+1)/ (4*M_PI)) * get_mat_knm(k, n, m) ;
1012       hb_inner /= besseli[n];
1013       hb_inner *= shcalc->get_result(n, m);
1014       hbj += hb_inner;
1015     }
1016   }
1017   hbj /= pow(rb.r(), 2);  // make h_hat into h
1018   return hbj;
1019 }
1020 
1021 
1022 
FMatrix(int I,int ns,int p,double kappa)1023 FMatrix::FMatrix(int I, int ns, int p, double kappa)
1024 :ComplexMoleculeMatrix(I, ns, p), kappa_(kappa)
1025 {
1026 }
1027 
init_from_exp(string ffilename,int k)1028 void FMatrix::init_from_exp(string ffilename, int k)
1029 {
1030   HFFile ffil( ffilename, p_);
1031   set_mat_k(k, ffil.get_mat());
1032 }
1033 
1034 
calc_vals(shared_ptr<BaseMolecule> mol,shared_ptr<FMatrix> prev,shared_ptr<XFMatrix> XF,shared_ptr<HMatrix> H,shared_ptr<IEMatrix> IE,shared_ptr<BesselCalc> bcalc,int k,double kappa)1035 void FMatrix::calc_vals(shared_ptr<BaseMolecule> mol,
1036                         shared_ptr<FMatrix> prev,
1037                         shared_ptr<XFMatrix> XF,
1038                         shared_ptr<HMatrix> H,
1039                         shared_ptr<IEMatrix> IE,
1040                         shared_ptr<BesselCalc> bcalc, int k, double kappa)
1041 {
1042   int ct(0), p2(p_*p_);
1043   cmplx inner;
1044   double ak = mol->get_ak(k), fRe, fIm, scl;
1045   vector<double> bessel_i = bcalc->calc_mbfI(p_+1, kappa*ak);
1046   vector<double> bessel_k = bcalc->calc_mbfK(p_+1, kappa*ak);
1047   double f_in[p_*p_], f_out[p_*p_];;
1048 
1049   for (int l = 0; l < p_; l++)
1050   {
1051     for (int s = 0; s < l+1; s++)
1052     {
1053       inner = double(l * bessel_k[l]) - ((2.0*l+1.0) * bessel_k[l+1]);
1054       inner *= exp(-kappa*ak) * H->get_mat_knm(k, l, s);
1055       inner += XF->get_mat_knm(k, l, s);
1056       inner += (double(2*l + 1 - l * XF->get_eps()) *
1057                 prev->get_mat_knm(k, l, s));
1058       f_in[ct] = inner.real();
1059       ct++;
1060       if ( s > 0 )
1061       {
1062         f_in[ct] = inner.imag();
1063         ct++;
1064       }
1065     }
1066   }
1067 
1068 #ifdef __LAU
1069   applyMMat(&IE->get_IE_k_org(k)[0], &f_in[0], &f_out[0], 1.0, 0.0, p2, 1, p2);
1070 #else
1071   MyMatrix<double> f_out1(p2, 1);
1072   MyMatrix<double> f_in1 (p2, 1, f_in);
1073   f_out1 = IE->get_IE_k(k) * f_in1;  // Matrix vector multiplication
1074 #endif
1075 
1076   ct = 0;
1077   for (int n = 0; n < p_; n++)  // rows in new matrix
1078   {
1079     scl = 1.0 / (double)(2.0*n+1.0);
1080     for (int m = 0; m < n+1; m++)  // columns in new matrix
1081     {
1082 #ifdef __LAU
1083       fRe = f_out[ct];
1084 #else
1085       fRe = f_out1(ct,0);
1086 #endif
1087       ct++;
1088 
1089       if ( m > 0 )
1090       {
1091 #ifdef __LAU
1092         fIm = f_out[ct];
1093 #else
1094         fIm = f_out1(ct,0);
1095 #endif
1096         ct++;
1097       } else
1098         fIm = 0.0;
1099 
1100       set_mat_knm(k, n, m, scl * complex<double> (fRe, fIm));
1101       if ( m > 0 ) set_mat_knm(k, n, -m, scl * complex<double> (fRe, -fIm));
1102     }
1103   }
1104 }
1105