1 /*
2  *                This source code is part of
3  *
4  *                     E  R  K  A  L  E
5  *                             -
6  *                       HF/DFT from Hel
7  *
8  * Written by Susi Lehtola, 2010-2014
9  * Copyright (c) 2010-2014, Susi Lehtola
10  *
11  * This program is free software; you can redistribute it and/or
12  * modify it under the terms of the GNU General Public License
13  * as published by the Free Software Foundation; either version 2
14  * of the License, or (at your option) any later version.
15  */
16 
17 /**
18  * This file contains routines for the automatical formation of
19  * application-specific basis sets.
20  *
21  * The algorithm performs completeness-optimization that was introduced in
22  *
23  * P. Manninen and J. Vaara, "Systematic Gaussian Basis-Set Limit
24  * Using Completeness-Optimized Primitive Sets. A Case for Magnetic
25  * Properties", J. Comp. Chem. 27, 434 (2006).
26  *
27  *
28  * The automatic algorithm for generating primitive basis sets was
29  * introduced in
30  *
31  * J. Lehtola, P. Manninen, M. Hakala, and K. Hämäläinen,
32  * "Completeness-optimized basis sets: Application to ground-state
33  * electron momentum densities", J. Chem. Phys. 137, 104105 (2012).
34  *
35  * and it was generalized to contracted basis sets in
36  *
37  * S. Lehtola, P. Manninen, M. Hakala, and K. Hämäläinen, "Contraction
38  * of completeness-optimized basis sets: Application to ground-state
39  * electron momentum densities", J. Chem. Phys. 138, 044109 (2013).
40  */
41 
42 #include "co-opt.h"
43 #include "elements.h"
44 
maxam(const std::vector<coprof_t> & cpl)45 int maxam(const std::vector<coprof_t> & cpl) {
46   for(size_t i=cpl.size()-1;i<cpl.size();i--)
47     if(cpl[i].exps.size()>0)
48       return (int) i;
49 
50   // Dummy statement
51   return -1;
52 }
53 
get_nfuncs(const std::vector<coprof_t> & cpl)54 int get_nfuncs(const std::vector<coprof_t> & cpl) {
55   int n=0;
56   for(int am=0;am<=maxam(cpl);am++)
57     n+=(2*am+1)*cpl[am].exps.size();
58   return n;
59 }
60 
print_limits(const std::vector<coprof_t> & cpl,const char * msg)61 void print_limits(const std::vector<coprof_t> & cpl, const char *msg) {
62   if(msg)
63     printf("%s\n",msg);
64   for(int am=0;am<=maxam(cpl);am++)
65     printf("%c % .3f % .3f %e %2i\n",shell_types[am],cpl[am].start,cpl[am].end,cpl[am].tol,(int) cpl[am].exps.size());
66   printf("Totaling %i functions.\n\n",get_nfuncs(cpl));
67   fflush(stdout);
68 }
69 
print_scheme(const BasisSetLibrary & baslib,int len)70 void print_scheme(const BasisSetLibrary & baslib, int len) {
71   // Get contraction scheme
72   ElementBasisSet el=baslib.get_elements()[0];
73 
74   // Number of exponents and contractions
75   std::vector<int> nc, nx;
76 
77   for(int am=0;am<=el.get_max_am();am++) {
78     arma::vec exps;
79     arma::mat coeffs;
80     el.get_primitives(exps,coeffs,am);
81     nx.push_back(coeffs.n_rows);
82     nc.push_back(coeffs.n_cols);
83   }
84 
85   // Is the set contracted?
86   bool contr=false;
87   for(size_t i=0;i<nx.size();i++)
88     if(nx[i]!=nc[i])
89       contr=true;
90 
91   std::string out;
92   char tmp[180];
93 
94   if(contr) {
95     out="[";
96     for(int l=0;l<=el.get_max_am();l++) {
97       sprintf(tmp,"%i%c",nx[l],tolower(shell_types[l]));
98       out+=std::string(tmp);
99     }
100     out+="|";
101     for(int l=0;l<=el.get_max_am();l++)
102       if(nc[l]!=nx[l]) {
103 	sprintf(tmp,"%i%c",nc[l],tolower(shell_types[l]));
104 	out+=std::string(tmp);
105       }
106     out+="]";
107   } else {
108     out="(";
109     for(int l=0;l<=el.get_max_am();l++) {
110       sprintf(tmp,"%i%c",nx[l],tolower(shell_types[l]));
111       out+=std::string(tmp);
112     }
113     out+=")";
114   }
115 
116   if(len==0)
117     printf("%s",out.c_str());
118   else {
119     // Format specifier
120     sprintf(tmp,"%%-%is",len);
121     printf(tmp,out.c_str());
122   }
123 }
124 
maxwidth_exps_table(int am,double tol,size_t nexp,double & width,int n)125 arma::vec maxwidth_exps_table(int am, double tol, size_t nexp, double & width, int n) {
126 
127   // Optimized exponents
128   static std::vector<co_exps_t> opt(max_am+1);
129 
130   // Check if we already have the exponents in store
131   if(opt[am].tol!=tol || opt[am].exps.size()!=nexp) {
132     opt[am].tol=tol;
133     opt[am].exps=maxwidth_exps(am,tol,nexp,opt[am].w,n);
134   }
135 
136   width=opt[am].w;
137 
138   if(opt[am].exps.size() != nexp) {
139     std::ostringstream oss;
140     oss << "Required " << nexp << " completeness-optimized primitives but got " << opt[am].exps.size() << "!\n";
141     throw std::runtime_error(oss.str());
142   }
143 
144   return opt[am].exps;
145 }
146 
span_width(int am,double tol,double & width,int nx,int n)147 arma::vec span_width(int am, double tol, double & width, int nx, int n) {
148   // Check starting point
149   if(nx<0)
150     nx=0;
151 
152   // Determine necessary amount of exponents
153   arma::vec exps;
154   double w=0.0;
155 
156   for(nx++;nx<=NFMAX;nx++) {
157     exps=maxwidth_exps_table(am,tol,nx,w,n);
158     if(w>=width)
159       break;
160   }
161 
162   // Store real width
163   width=w;
164 
165   // Return exponents
166   return exps;
167 }
168 
get_element_library(const std::string & el,const std::vector<coprof_t> & cpl)169 ElementBasisSet get_element_library(const std::string & el, const std::vector<coprof_t> & cpl) {
170   ElementBasisSet elbas(el);
171   for(size_t am=0;am<cpl.size();am++)
172     for(size_t ish=0;ish<cpl[am].exps.size();ish++) {
173       FunctionShell sh(am);
174       sh.add_exponent(1.0,cpl[am].exps[ish]);
175       elbas.add_function(sh);
176     }
177   elbas.sort();
178 
179   return elbas;
180 }
181 
augment_basis(const std::vector<coprof_t> & cplo,int ndiffuse,int ntight,int n_tau)182 std::vector<coprof_t> augment_basis(const std::vector<coprof_t> & cplo, int ndiffuse, int ntight, int n_tau) {
183   // New profile
184   std::vector<coprof_t> cpl(cplo);
185   if(ndiffuse==0 && ntight==0)
186     // Nothing to do
187     return cpl;
188 
189   for(int am=0;am<=maxam(cpl);am++) {
190     // Require at least two exponents per augmented shell.
191     if(cpl[am].exps.size()<2)
192       continue;
193 
194     // Current width
195     double width=cpl[am].end-cpl[am].start;
196 
197     // New width and exponents
198     double w;
199     arma::vec exps=maxwidth_exps_table(am,cpl[am].tol,cpl[am].exps.size()+ndiffuse+ntight,w,n_tau);
200 
201     // Additional width is
202     double dw=w-width;
203 
204     // Update
205     cpl[am].start -= ndiffuse*dw/(ndiffuse+ntight);
206     cpl[am].end   += ntight*dw/(ndiffuse+ntight);
207     cpl[am].exps=move_exps(exps,cpl[am].start);
208   }
209 
210   return cpl;
211 }
212 
213 
get_library(const std::vector<coprof_t> & cpl)214 BasisSetLibrary get_library(const std::vector<coprof_t> & cpl) {
215   // Construct the basis set library
216   BasisSetLibrary baslib;
217   for(int Z=1;Z<=maxZ;Z++)
218     baslib.add_element(get_element_library(element_symbols[Z],cpl));
219 
220   return baslib;
221 }
222