1 /*
2  * This file is written by Arto Sakko and Susi Lehtola, 2011.
3  * Copyright (c) 2011, Arto Sakko and Susi Lehtola
4  *
5  *
6  *
7  *                   This file is part of
8  *
9  *                     E  R  K  A  L  E
10  *                             -
11  *                       DFT from Hel
12  *
13  * Erkale is written by Susi Lehtola, 2010-2011
14  * Copyright (c) 2010-2011, Susi Lehtola
15  *
16  *
17  * This program is free software; you can redistribute it and/or
18  * modify it under the terms of the GNU General Public License
19  * as published by the Free Software Foundation; either version 2
20  * of the License, or (at your option) any later version.
21  */
22 
23 #include "casida.h"
24 #include "casida_grid.h"
25 #include "../lmgrid.h"
26 #include "../settings.h"
27 #include "../xrs/fourierprod.h"
28 #include "../linalg.h"
29 #include "../eriworker.h"
30 #include "../stringutil.h"
31 #include "../timer.h"
32 
33 #include <cstdio>
34 #include <cstdlib>
35 #include <cfloat>
36 
37 // \delta parameter in Eichkorn et al
38 #define DELTA 1e-9
39 
40 // Screen Coulomb integrals?
41 #define SCREENING
42 // Screening threshold
43 #define SCREENTHR 1e-10
44 
45 extern Settings settings;
46 
Casida()47 Casida::Casida() {
48 }
49 
Casida(const BasisSet & basis,const arma::vec & Ev,const arma::mat & Cv,const arma::mat & Pv,const std::vector<double> & occs)50 Casida::Casida(const BasisSet & basis, const arma::vec & Ev, const arma::mat & Cv, const arma::mat & Pv, const std::vector<double> & occs) {
51   E.push_back(Ev);
52   C.push_back(Cv);
53   P.push_back(Pv);
54 
55   // Form pairs
56   std::vector< std::vector<double> > occ;
57   occ.push_back(occs);
58   form_pairs(occ);
59   // Sanity check
60   if(pairs[0].size()==0)
61     throw std::runtime_error("No pairs for Casida calculation! Please check your input.\n");
62   printf("Casida calculation has %u pairs.\n",(unsigned int) pairs[0].size());
63 
64   // Parse coupling mode
65   parse_coupling();
66 
67   // Calculate K matrix
68   calc_K(basis);
69   // and solve Casida equation
70   solve();
71 }
72 
Casida(const BasisSet & basis,const arma::vec & Ea,const arma::vec & Eb,const arma::mat & Ca,const arma::mat & Cb,const arma::mat & Pa,const arma::mat & Pb,const std::vector<double> & occa,const std::vector<double> & occb)73 Casida::Casida(const BasisSet & basis, const arma::vec & Ea, const arma::vec & Eb, const arma::mat & Ca, const arma::mat & Cb, const arma::mat & Pa, const arma::mat & Pb, const std::vector<double> & occa, const std::vector<double> & occb) {
74 
75   E.push_back(Ea);
76   E.push_back(Eb);
77   C.push_back(Ca);
78   C.push_back(Cb);
79   P.push_back(Pa);
80   P.push_back(Pb);
81 
82   // Form pairs
83   std::vector< std::vector<double> > occ;
84   occ.push_back(occa);
85   occ.push_back(occb);
86   form_pairs(occ);
87   // Sanity check
88   if(pairs[0].size()==0 && pairs[1].size()==0)
89     throw std::runtime_error("No pairs for Casida calculation! Please check your input.\n");
90   printf("Casida calculation has %u spin up and %u spin down pairs.\n",(unsigned int) pairs[0].size(),(unsigned int) pairs[1].size());
91 
92   // Parse coupling mode
93   parse_coupling();
94 
95   // Calculate K matrix
96   calc_K(basis);
97   // and solve Casida equation
98   solve();
99 }
100 
parse_coupling()101 void Casida::parse_coupling() {
102   // Determine coupling
103   switch(settings.get_int("CasidaCoupling")) {
104   case(0):
105     // IPA.
106     coupling=IPA;
107     break;
108 
109   case(1):
110     // RPA.
111     coupling=RPA;
112     break;
113 
114   case(2):
115     // LDAXC, add xc contribution.
116     coupling=TDLDA;
117     break;
118 
119   default:
120     throw std::runtime_error("Unknown coupling!\n");
121   }
122 }
123 
calc_K(const BasisSet & basis)124 void Casida::calc_K(const BasisSet & basis) {
125   // Exchange and correlation functionals
126   int x_func=settings.get_int("CasidaXfunc");
127   int c_func=settings.get_int("CasidaCfunc");
128   double tol=settings.get_double("CasidaTol");
129 
130   // Allocate memory
131   if(pairs.size()==1)
132     // Restricted case
133     K.zeros(pairs[0].size(),pairs[0].size());
134   else
135     // Unrestricted case
136     K.zeros(pairs[0].size()+pairs[1].size(),pairs[0].size()+pairs[1].size());
137 
138   printf("\n");
139 
140   // Do we need to form K?
141   if(coupling!=IPA) {
142     // Compute Coulomb coupling
143     Kcoul(basis);
144 
145     // Compute XC coupling if necessary
146     if(coupling==TDLDA) {
147       Kxc(basis,tol,x_func,c_func);
148     }
149   }
150 }
151 
~Casida()152 Casida::~Casida() {
153 };
154 
matrix_transform(bool ispin,const arma::mat & m) const155 arma::mat Casida::matrix_transform(bool ispin, const arma::mat & m) const {
156   return arma::trans(C[ispin])*m*C[ispin];
157 }
158 
matrix_transform(bool ispin,const arma::cx_mat & m) const159 arma::cx_mat Casida::matrix_transform(bool ispin, const arma::cx_mat & m) const {
160   return arma::trans(C[ispin])*m*C[ispin];
161 }
162 
form_pairs(const std::vector<std::vector<double>> occs)163 void Casida::form_pairs(const std::vector< std::vector<double> > occs) {
164   // First, determine amount of occupied and virtual states.
165 
166   nocc.resize(occs.size());
167   nvirt.resize(occs.size());
168 
169   for(size_t ispin=0;ispin<nocc.size();ispin++) {
170     // Count number of occupied states.
171     nocc[ispin]=0;
172     while(occs[ispin][nocc[ispin]]>0)
173       nocc[ispin]++;
174 
175     // Check that all values are equal.
176     for(size_t i=0;i<nocc[ispin];i++)
177       if(occs[ispin][i]!=occs[ispin][0]) {
178 	ERROR_INFO();
179 	throw std::runtime_error("Error - occupancies of occupied orbitals differ!\n");
180       }
181 
182     // Count number of unoccupied states.
183     nvirt[ispin]=occs[ispin].size()-nocc[ispin];
184     for(size_t i=nocc[ispin];i<occs[ispin].size();i++)
185       if(occs[ispin][i]!=0.0) {
186 	ERROR_INFO();
187 	throw std::runtime_error("Gaps in occupancy not allowed!\n");
188       }
189   }
190 
191   // Resize pairs
192   pairs.resize(nocc.size());
193   // Resize occupation numbers
194   f.resize(nocc.size());
195 
196   // What orbitals are included in the calculation?
197   std::vector<std::string> states=splitline(settings.get_string("CasidaStates"));
198   if(states.size()==0) {
199     // Include all pairs in the calculation.
200     for(size_t ispin=0;ispin<nocc.size();ispin++) {
201       for(size_t iocc=0;iocc<nocc[ispin];iocc++)
202 	for(size_t ivirt=0;ivirt<nvirt[ispin];ivirt++) {
203 	  states_pair_t tmp;
204 	  tmp.i=iocc;
205 	  tmp.f=nocc[ispin]+ivirt;
206 	  pairs[ispin].push_back(tmp);
207 	}
208     }
209 
210     // Form f. Polarized calculation?
211     bool pol=(nocc.size() == 2);
212     for(size_t ispin=0;ispin<nocc.size();ispin++) {
213       f[ispin].zeros(nocc[ispin]+nvirt[ispin]);
214       for(size_t iocc=0;iocc<nocc[ispin];iocc++)
215 	f[ispin](iocc)=pol ? 1.0 : 2.0;
216     }
217   } else {
218     // Loop over spins
219     for(size_t ispin=0;ispin<nocc.size();ispin++) {
220 
221       // Indices of orbitals to include.
222       std::vector<size_t> idx=parse_range(states[ispin]);
223 
224       // Check that we don't run over states
225       if(idx[idx.size()-1]>nocc[ispin]+nvirt[ispin]) {
226 	ERROR_INFO();
227 	std::ostringstream oss;
228 	oss << "Orbital " << idx[idx.size()-1] << " was requested in calculation, but only " << nocc[ispin]+nvirt[ispin] << " orbitals exist!\n";
229 	throw std::runtime_error(oss.str());
230       }
231 
232       // Convert to C++ indexing
233       for(size_t i=0;i<idx.size();i++)
234 	idx[i]--;
235 
236       // Get active orbitals and energies
237       arma::mat newC(C[ispin].n_rows,idx.size());
238       for(size_t i=0;i<idx.size();i++)
239 	newC.col(i)=C[ispin].col(idx[i]);
240       C[ispin]=newC;
241 
242       arma::vec newE(C[ispin].n_elem);
243       for(size_t i=0;i<idx.size();i++)
244 	newE(i)=E[ispin](idx[i]);
245       E[ispin]=newE;
246 
247       // Form f. Polarized calculation?
248       bool pol=(nocc.size()==2);
249       f[ispin].zeros(idx.size());
250       for(size_t i=0;i<idx.size();i++)
251 	if(idx[i]<nocc[ispin])
252 	  // Occupied orbital
253 	  f[ispin](i)=pol ? 1.0 : 2.0;
254 	else
255 	  break;
256 
257       // Loop over indices
258       for(size_t iocc=0;iocc<idx.size();iocc++) {
259 	// Check that it truly is occupied.
260 	if(idx[iocc]>=nocc[ispin])
261 	  continue;
262 
263 	for(size_t jvirt=iocc+1;jvirt<idx.size();jvirt++) {
264 	  // Check that it truly is virtual.
265 	  if(idx[jvirt]<nocc[ispin])
266 	    continue;
267 
268 	  // Create state pair (no idx needed here since we have
269 	  // already dropped inactive orbitals from C)
270 	  states_pair_t tmp;
271           tmp.i=iocc;
272           tmp.f=jvirt;
273 
274           pairs[ispin].push_back(tmp);
275         }
276       }
277     }
278   }
279 }
280 
esq(states_pair_t ip,bool ispin) const281 double Casida::esq(states_pair_t ip, bool ispin) const {
282   double dE=E[ispin](ip.f)-E[ispin](ip.i);
283   return dE*dE;
284 }
285 
fe(states_pair_t ip,bool ispin) const286 double Casida::fe(states_pair_t ip, bool ispin) const {
287   return sqrt((f[ispin](ip.i)-f[ispin](ip.f))*(E[ispin](ip.f)-E[ispin](ip.i)));
288 }
289 
solve()290 void Casida::solve() {
291   Timer t;
292 
293   w_i.zeros(K.n_rows);
294   F_i.zeros(K.n_rows,K.n_cols);
295 
296   // Generate the coupling matrix (eqn 2.11), but use the K array to
297   // save memory.
298 
299   if(coupling!=IPA) {
300     // Add relevant factors to Coulomb / exchange-correlation terms
301     for(size_t ispin=0;ispin<pairs.size();ispin++)
302       for(size_t jspin=0;jspin<pairs.size();jspin++) {
303 	// Offset in i
304 	const size_t ioff=ispin*pairs[0].size();
305 	// Offset in j
306 	const size_t joff=jspin*pairs[0].size();
307 
308 	for(size_t ip=0;ip<pairs[ispin].size();ip++)
309 	  for(size_t jp=0;jp<pairs[jspin].size();jp++)
310 	    K(ioff+ip,joff+jp)*=2.0*fe(pairs[ispin][ip],ispin)*fe(pairs[jspin][jp],jspin);
311       }
312   }
313 
314 
315   // Add IPA contribution to diagonal
316   for(size_t ispin=0;ispin<pairs.size();ispin++) {
317     // Offset in i
318     const size_t ioff=ispin*pairs[0].size();
319     for(size_t ip=0;ip<pairs[ispin].size();ip++)
320       K(ioff+ip,ioff+ip)+=esq(pairs[ispin][ip],ispin);
321   }
322 
323   // Solve eigenvalues and eigenvectors using direct linear algebraic methods
324   eig_sym_ordered(w_i, F_i, K);
325 
326   // The eigenvalues are the squares of the excitation energies
327   for(size_t i=0;i<w_i.n_elem;i++)
328     w_i(i) = sqrt(w_i(i));
329 
330   printf("Casida equations solved in %s.\n",t.elapsed().c_str());
331 }
332 
transition(const std::vector<arma::mat> & m) const333 arma::mat Casida::transition(const std::vector<arma::mat> & m) const {
334   // Transition rates for every transition
335   arma::mat tr(w_i.n_elem,3);
336   tr.zeros();
337 
338   // Loop over transitions
339   for(size_t it=0;it<w_i.n_elem;it++) {
340     // Loop over spins
341     for(size_t jspin=0;jspin<pairs.size();jspin++) {
342       // Offset in F
343       size_t joff=jspin*pairs[0].size();
344       // Loop over pairs
345       for(size_t jp=0;jp<pairs[jspin].size();jp++) {
346 	// Compute |x| = x^T S^{-1/2} F_i
347 	tr(it)+=m[jspin](pairs[jspin][jp].i,pairs[jspin][jp].f)*F_i(joff+jp,it)*fe(pairs[jspin][jp],jspin);
348       }
349     }
350 
351     // Normalize to get \f$ \left\langle \Psi_0 \left| \hat{x}
352     // \right| \right\rangle \f$ , see Eq. 4.40 of Casida (1994),
353     // or compare Eqs. 2.14 and 2.16 in Jamorski et al (1996).
354     tr(it)/=sqrt(w_i(it));
355   }
356 
357   // Transition energies and oscillator strengths
358   arma::mat osc(w_i.n_elem,2);
359   for(size_t it=0; it<w_i.n_elem;it++) {
360     osc(it,0) = w_i(it);
361     osc(it,1) = tr(it)*tr(it);
362   }
363 
364   return osc;
365 }
366 
transition(const std::vector<arma::cx_mat> & m) const367 arma::mat Casida::transition(const std::vector<arma::cx_mat> & m) const {
368   // Transition rates for every transition
369   arma::cx_vec tr(w_i.n_elem,3);
370   tr.zeros();
371 
372   // Loop over transitions
373   for(size_t it=0;it<w_i.n_elem;it++) {
374     // Loop over spins
375     for(size_t jspin=0;jspin<pairs.size();jspin++) {
376       // Offset in F
377       size_t joff=jspin*pairs[0].size();
378       // Loop over pairs
379       for(size_t jp=0;jp<pairs[jspin].size();jp++) {
380 	  // Compute |x| = x^T S^{-1/2} F_i
381 	tr(it)+=m[jspin](pairs[jspin][jp].i,pairs[jspin][jp].f)*F_i(joff+jp,it)*fe(pairs[jspin][jp],jspin);
382       }
383     }
384 
385     // Normalize to get \f$ \left\langle \Psi_0 \left| \hat{x}
386     // \right| \right\rangle \f$ , see Eq. 4.40 of Casida (1994),
387     // or compare Eqs. 2.14 and 2.16 in Jamorski et al (1996).
388     tr(it)/=sqrt(w_i(it));
389   }
390 
391   // Transition energies and oscillator strengths
392   arma::mat osc(w_i.n_elem,2);
393   for(size_t it=0; it<w_i.n_elem;it++) {
394     osc(it,0) = w_i(it);
395     osc(it,1) = std::norm(tr(it));
396   }
397 
398   return osc;
399 }
400 
dipole_transition(const BasisSet & bas) const401 arma::mat Casida::dipole_transition(const BasisSet & bas) const {
402   // Form dipole matrix
403   std::vector<arma::mat> dm=bas.moment(1);
404 
405   // and convert it to the MO basis
406   std::vector< std::vector<arma::mat> > dip(3);
407   for(int ic=0;ic<3;ic++)
408     for(size_t ispin=0;ispin<C.size();ispin++) {
409       dip[ic].resize(C.size());
410       dip[ic][ispin]=matrix_transform(ispin,dm[ic]);
411     }
412 
413   // Compute the oscillator strengths.
414   arma::mat osc(w_i.n_elem,2);
415   osc.zeros();
416   for(int ic=0;ic<3;ic++) {
417     // Compute the transitions in the current direction
418     arma::mat hlp=transition(dip[ic]);
419 
420     // Store the energies
421     osc.col(0)=hlp.col(0);
422     // and increment the transition speeds
423     osc.col(1)+=2.0/3.0*hlp.col(1);
424   }
425 
426   return osc;
427 }
428 
transition(const BasisSet & basis,const arma::vec & q) const429 arma::mat Casida::transition(const BasisSet & basis, const arma::vec & q) const {
430   if(q.n_elem!=3) {
431     ERROR_INFO();
432     throw std::runtime_error("Momentum transfer should have 3 coordinates!\n");
433   }
434 
435   // Form products of basis functions.
436   const size_t Nbf=basis.get_Nbf();
437   std::vector<prod_gaussian_3d> bfprod=compute_products(basis);
438 
439   // and their Fourier transforms
440   std::vector<prod_fourier> bffour=fourier_transform(bfprod);
441 
442   // Get the momentum transfer matrix
443   arma::cx_mat momtrans=momentum_transfer(bffour,Nbf,q);
444   // and transform it to the MO basis
445   std::vector< arma::cx_mat > mtrans(C.size());
446   for(size_t ispin=0;ispin<C.size();ispin++)
447     mtrans[ispin]=matrix_transform(ispin,momtrans);
448 
449   // Compute the transitions
450   return transition(mtrans);
451 }
452 
transition(const BasisSet & basis,double qr) const453 arma::mat Casida::transition(const BasisSet & basis, double qr) const {
454   // Form products of basis functions.
455   const size_t Nbf=basis.get_Nbf();
456   std::vector<prod_gaussian_3d> bfprod=compute_products(basis);
457 
458   // and their Fourier transforms
459   std::vector<prod_fourier> bffour=fourier_transform(bfprod);
460 
461   // Get the grid for computing the spherical averages.
462   std::vector<angular_grid_t> grid=form_angular_grid(2*basis.get_max_am());
463   // We normalize the weights so that for purely dipolar transitions we
464   // get the same output as with using the dipole matrix.
465   for(size_t i=0;i<grid.size();i++) {
466     // Dipole integral is only wrt theta - divide off phi part.
467     grid[i].w/=2.0*M_PI;
468   }
469 
470   // Transition energies and oscillator strengths
471   arma::mat osc(w_i.n_elem,2);
472   osc.zeros();
473 
474   // Loop over the angular mesh
475   for(size_t ig=0;ig<grid.size();ig++) {
476     // Current value of q is
477     arma::vec q(3);
478     q(0)=qr*grid[ig].r.x;
479     q(1)=qr*grid[ig].r.y;
480     q(2)=qr*grid[ig].r.z;
481     // and the weight is
482     double w=grid[ig].w;
483 
484     // Get the momentum transfer matrix
485     arma::cx_mat momtrans=momentum_transfer(bffour,Nbf,q);
486     // and transform it to the MO basis
487     std::vector< arma::cx_mat > mtrans(C.size());
488     for(size_t ispin=0;ispin<C.size();ispin++)
489       mtrans[ispin]=matrix_transform(ispin,momtrans);
490 
491     // Compute the transitions
492     arma::mat hlp=transition(mtrans);
493     // Store the energies
494     osc.col(0)=hlp.col(0);
495     // and increment the transition speeds
496     osc.col(1)+=w*hlp.col(1);
497   }
498 
499   return osc;
500 }
501 
coulomb_fit(const BasisSet & basis,std::vector<arma::mat> & munu,arma::mat & ab_inv) const502 void Casida::coulomb_fit(const BasisSet & basis, std::vector<arma::mat> & munu, arma::mat & ab_inv) const {
503   // Get density fitting basis
504   BasisSet dfitbas;
505 
506   if(stricmp(settings.get_string("FittingBasis"),"Auto")==0)
507     dfitbas=basis.density_fitting();
508   else {
509     // Load basis library
510     BasisSetLibrary fitlib;
511     fitlib.load_basis(settings.get_string("FittingBasis"));
512 
513     // Construct fitting basis
514     construct_basis(dfitbas,basis.get_nuclei(),fitlib);
515   }
516 
517   // Amount of auxiliary functions
518   const size_t Naux=dfitbas.get_Nbf();
519 
520   // Get the shells
521   std::vector<GaussianShell> orbshells=basis.get_shells();
522   std::vector<GaussianShell> auxshells=dfitbas.get_shells();
523 
524   // Get list of pairs
525   std::vector<shellpair_t> orbpairs=basis.get_unique_shellpairs();
526   std::vector<shellpair_t> auxpairs=dfitbas.get_unique_shellpairs();
527 
528   // Dummy shell, helper for computing ERIs
529   GaussianShell dummy=dummyshell();
530 
531   // First, compute the two-center integrals
532   arma::mat ab(Naux,Naux);
533   ab.zeros();
534 
535 #ifdef _OPENMP
536 #pragma omp parallel
537 #endif
538   {
539     ERIWorker eri(dfitbas.get_max_am(),dfitbas.get_max_Ncontr());
540     const std::vector<double> * erip;
541 
542 #ifdef _OPENMP
543 #pragma omp for schedule(dynamic)
544 #endif
545     for(size_t ip=0;ip<auxpairs.size();ip++) {
546       // Shells in question are
547       size_t is=auxpairs[ip].is;
548       size_t js=auxpairs[ip].js;
549 
550       // Compute (a|b)
551       eri.compute(&auxshells[is],&dummy,&auxshells[js],&dummy);
552       erip=eri.getp();
553 
554       // Store integrals
555       for(size_t ii=0;ii<auxshells[is].get_Nbf();ii++)
556 	for(size_t jj=0;jj<auxshells[js].get_Nbf();jj++) {
557 	  ab(auxshells[is].get_first_ind()+ii,auxshells[js].get_first_ind()+jj)=(*erip)[ii*auxshells[js].get_Nbf()+jj];
558 	  ab(auxshells[js].get_first_ind()+jj,auxshells[is].get_first_ind()+ii)=(*erip)[ii*auxshells[js].get_Nbf()+jj];
559 	}
560     }
561   }
562 
563   // Form ab_inv
564   ab_inv=arma::inv(ab+DELTA);
565 
566   // Allocate memory for the three-center integrals.
567   munu.resize(C.size());
568   for(size_t ispin=0;ispin<C.size();ispin++) {
569     munu[ispin].zeros(C[ispin].n_cols*C[ispin].n_cols,Naux);
570   }
571 
572 #ifdef SCREENING
573   // Screen the integrals.
574   arma::mat screen(orbshells.size(),orbshells.size());
575 #ifdef _OPENMP
576 #pragma omp parallel
577 #endif
578   {
579     ERIWorker eri(basis.get_max_am(),basis.get_max_Ncontr());
580     const std::vector<double> * erip;
581 
582 #ifdef _OPENMP
583 #pragma omp for schedule(dynamic)
584 #endif
585     for(size_t ip=0;ip<orbpairs.size();ip++) {
586       // The shells in question are
587       size_t is=orbpairs[ip].is;
588       size_t js=orbpairs[ip].js;
589 
590       // Compute (*Erip)
591       eri.compute(&orbshells[is],&orbshells[js],&orbshells[is],&orbshells[js]);
592       erip=eri.getp();
593 
594       // Find out maximum value
595       double max=0.0;
596       for(size_t i=0;i<(*erip).size();i++)
597 	if(fabs((*erip)[i])>max)
598 	  max=(*erip)[i];
599       max=sqrt(max);
600 
601       // Store value
602       screen(is,js)=max;
603       screen(js,is)=max;
604     }
605   }
606 #endif
607 
608   // Compute the three-center integrals.
609 #ifdef _OPENMP
610 #pragma omp parallel
611 #endif
612   {
613     ERIWorker eri(std::max(basis.get_max_am(),dfitbas.get_max_am()),std::max(basis.get_max_Ncontr(),dfitbas.get_max_Ncontr()));
614     const std::vector<double> * erip;
615 
616 
617 #ifdef _OPENMP
618     // Worker stack for each thread
619     std::vector<arma::mat> munu_wrk=munu;
620 
621 #pragma omp for schedule(dynamic)
622 #endif
623     for(size_t ip=0;ip<orbpairs.size();ip++) {
624       // Shells in question are
625       size_t imu=orbpairs[ip].is;
626       size_t inu=orbpairs[ip].js;
627 
628 #ifdef SCREENING
629       // Do we need to compute the integral?
630       if(screen(imu,inu)<SCREENTHR)
631 	continue;
632 #endif
633 
634       // Amount of functions on shell
635       size_t Nmu=orbshells[imu].get_Nbf();
636       // Index of first function on shell
637       size_t mu0=orbshells[imu].get_first_ind();
638 
639       // Amount of functions on shell
640       size_t Nnu=orbshells[inu].get_Nbf();
641       // Index of first function on shell
642       size_t nu0=orbshells[inu].get_first_ind();
643 
644       for(size_t ia=0;ia<auxshells.size();ia++) {
645 	// Amount of functions on shell
646 	size_t Na=auxshells[ia].get_Nbf();
647 	// Index of first function on shell
648 	size_t a0=auxshells[ia].get_first_ind();
649 
650 	// Compute the integral over the AOs
651 	eri.compute(&auxshells[ia],&dummy,&orbshells[imu],&orbshells[inu]);
652 	erip=eri.getp();
653 
654 	// Transform integrals to spin orbitals.
655 	for(size_t ispin=0;ispin<C.size();ispin++) {
656 	  // Amount of active orbitals with current spin.
657 	  size_t Norb=C[ispin].n_cols;
658 
659 	  size_t indmu, indnu, inda;
660 	  // Loop over orbitals
661 	  for(size_t mu=0;mu<Norb;mu++)
662 	    for(size_t nu=0;nu<=mu;nu++) {
663 	      // Loop over functions
664 	      for(size_t muf=0;muf<Nmu;muf++) {
665 		indmu=mu0+muf;
666 		for(size_t nuf=0;nuf<Nnu;nuf++) {
667 		  indnu=nu0+nuf;
668 
669 		  // Coefficient of integral is
670 		  double c= (imu!=inu) ? C[ispin](indmu,mu)*C[ispin](indnu,nu) + C[ispin](indmu,nu)*C[ispin](indnu,mu) : C[ispin](indmu,mu)*C[ispin](indnu,nu);
671 
672 		  // Loop over auxiliary functions
673 		  for(size_t af=0;af<Na;af++) {
674 		    inda=a0+af;
675 
676 #ifdef _OPENMP
677 		    munu_wrk[ispin](mu*Norb+nu,inda)+=c*(*erip)[(af*Nmu+muf)*Nnu+nuf];
678 #else
679 		    munu[ispin](mu*Norb+nu,inda)+=c*(*erip)[(af*Nmu+muf)*Nnu+nuf];
680 #endif
681 		  }
682 		}
683 	      }
684 	    }
685 
686 	} // end loop over spins
687       }
688     }
689 
690 #ifdef _OPENMP
691 #pragma omp critical
692     // Sum the results together
693     for(size_t ispin=0;ispin<C.size();ispin++)
694       munu[ispin]+=munu_wrk[ispin];
695 #endif
696   } // end parallel region
697 
698   // Symmetrize munu
699   for(size_t ispin=0;ispin<C.size();ispin++) {
700     size_t Norb=C[ispin].n_cols;
701     for(size_t mu=0;mu<Norb;mu++)
702       for(size_t nu=0;nu<=mu;nu++)
703 	munu[ispin].row(nu*Norb+mu)=munu[ispin].row(mu*Norb+nu);
704   }
705 }
706 
Kcoul(const BasisSet & basis)707 void Casida::Kcoul(const BasisSet & basis) {
708   Timer t;
709 
710   if(!C.size())
711     throw std::runtime_error("Error - no orbitals!\n");
712 
713   // Inverse Coulomb overlap matrix of fitting basis
714   arma::mat ab_inv;
715   // The [\mu \nu|I] matrices in Jamorski (4.16).
716   std::vector<arma::mat> munu_I;
717 
718   // Get density fitting integrals
719   coulomb_fit(basis,munu_I,ab_inv);
720 
721   // Construct K
722   for(size_t ispin=0;ispin<C.size();ispin++)
723     for(size_t jspin=0;jspin<=ispin;jspin++) {
724       // Amount of active orbitals
725       const size_t Norbi=C[ispin].n_cols;
726       const size_t Norbj=C[jspin].n_cols;
727 
728       // Offset in i
729       const size_t ioff=ispin*pairs[0].size();
730       // Offset in j
731       const size_t joff=jspin*pairs[0].size();
732 
733       if(ispin==jspin) {
734 #ifdef _OPENMP
735 #pragma omp parallel for
736 #endif
737 	for(size_t ip=0;ip<pairs[ispin].size();ip++) {
738 	  // Off-diagonal, symmetrization is done later
739 	  for(size_t jp=0;jp<ip;jp++) {
740 	    double tmp=arma::as_scalar(munu_I[ispin].row(pairs[ispin][ip].i*Norbi+pairs[ispin][ip].f)*ab_inv*arma::trans(munu_I[ispin].row(pairs[ispin][jp].i*Norbi+pairs[ispin][jp].f)));
741 	    K(ioff+ip,joff+jp)+=tmp;
742 	    K(joff+jp,ioff+ip)+=tmp;
743 	  }
744 	  // Diagonal
745 	  K(ioff+ip,ioff+ip)+=arma::as_scalar(munu_I[ispin].row(pairs[ispin][ip].i*Norbi+pairs[ispin][ip].f)*ab_inv*arma::trans(munu_I[ispin].row(pairs[ispin][ip].i*Norbi+pairs[ispin][ip].f)));
746 	}
747       } else {
748 #ifdef _OPENMP
749 #pragma omp parallel for
750 #endif
751 	for(size_t ip=0;ip<pairs[ispin].size();ip++)
752 	  for(size_t jp=0;jp<pairs[jspin].size();jp++) {
753 	    K(ioff+ip,joff+jp)=arma::as_scalar(munu_I[ispin].row(pairs[ispin][ip].i*Norbi+pairs[ispin][ip].f)*ab_inv*arma::trans(munu_I[jspin].row(pairs[jspin][jp].i*Norbj+pairs[jspin][jp].f)));
754 	  }
755       }
756 
757       if(ispin!=jspin) {
758 	// Symmetrize
759 	K.submat(joff,ioff,joff+pairs[jspin].size()-1,ioff+pairs[ispin].size()-1)=arma::trans(K.submat(ioff,joff,ioff+pairs[ispin].size()-1,joff+pairs[jspin].size()-1));
760       }
761     }
762 
763   printf("Coulomb coupling matrix computed in %s.\n",t.elapsed().c_str());
764 }
765 
Kxc(const BasisSet & bas,double tol,int x_func,int c_func)766 void Casida::Kxc(const BasisSet & bas, double tol, int x_func, int c_func) {
767   Timer t;
768 
769   // Make grid
770   CasidaGrid grid(&bas);
771   // Evaluate Kxc
772   grid.Kxc(P,tol,x_func,c_func,C,pairs,K);
773 
774   printf("XC coupling matrix computed in %s.\n",t.elapsed().c_str());
775 }
776