1 //
2 // hcorewfn.cc
3 //
4 // Copyright (C) 1996 Limit Point Systems, Inc.
5 //
6 // Author: Curtis Janssen <cljanss@limitpt.com>
7 // Maintainer: LPS
8 //
9 // This file is part of the SC Toolkit.
10 //
11 // The SC Toolkit is free software; you can redistribute it and/or modify
12 // it under the terms of the GNU Library General Public License as published by
13 // the Free Software Foundation; either version 2, or (at your option)
14 // any later version.
15 //
16 // The SC Toolkit is distributed in the hope that it will be useful,
17 // but WITHOUT ANY WARRANTY; without even the implied warranty of
18 // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
19 // GNU Library General Public License for more details.
20 //
21 // You should have received a copy of the GNU Library General Public License
22 // along with the SC Toolkit; see the file COPYING.LIB.  If not, write to
23 // the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA.
24 //
25 // The U.S. Government is granted a limited license as per AL 91-7.
26 //
27 
28 #include <util/misc/formio.h>
29 #include <util/state/stateio.h>
30 
31 #include <math/scmat/blocked.h>
32 
33 #include <chemistry/qc/wfn/obwfn.h>
34 #include <chemistry/qc/basis/integral.h>
35 #include <chemistry/qc/basis/petite.h>
36 
37 using namespace std;
38 using namespace sc;
39 
40 /////////////////////////////////////////////////////////////////////////
41 
42 static ClassDesc HCoreWfn_cd(
43   typeid(HCoreWfn),"HCoreWfn",1,"public OneBodyWavefunction",
44   0, create<HCoreWfn>, create<HCoreWfn>);
45 
HCoreWfn(StateIn & s)46 HCoreWfn::HCoreWfn(StateIn& s) :
47   SavableState(s),
48   OneBodyWavefunction(s)
49 {
50   s.get(nirrep_);
51   s.get(docc_);
52   s.get(socc_);
53   s.get(user_occ_);
54   s.get(total_charge_);
55 }
56 
HCoreWfn(const Ref<KeyVal> & keyval)57 HCoreWfn::HCoreWfn(const Ref<KeyVal>&keyval):
58   OneBodyWavefunction(keyval)
59 {
60   CharacterTable ct = molecule()->point_group()->char_table();
61 
62   nirrep_ = ct.ncomp();
63   docc_ = new int[nirrep_];
64   socc_ = new int[nirrep_];
65 
66   user_occ_ = 0;
67   total_charge_ = keyval->intvalue("total_charge");
68 
69   int nuclear_charge = int(molecule()->nuclear_charge());
70   int computed_charge = nuclear_charge;
71 
72   for (int i=0; i < nirrep_; i++) {
73     docc_[i]=0;
74     socc_[i]=0;
75 
76     if (keyval->exists("docc",i)) {
77       docc_[i] = keyval->intvalue("docc",i);
78       computed_charge -= 2;
79       user_occ_ = 1;
80       }
81     if (keyval->exists("socc",i)) {
82       socc_[i] = keyval->intvalue("socc",i);
83       computed_charge -= 1;
84       user_occ_ = 1;
85       }
86   }
87   if (!keyval->exists("total_charge")) {
88     if (user_occ_) total_charge_ = computed_charge;
89     else total_charge_ = 0;
90     }
91   else if (total_charge_ != computed_charge && user_occ_) {
92     ExEnv::err0() << indent
93                  << "ERROR: HCoreWfn: total_charge != computed_charge"
94                  << endl;
95     abort();
96     }
97   if (total_charge_ > nuclear_charge) {
98     ExEnv::err0() << indent
99                  << "ERROR: HCoreWfn: total_charge > nuclear_charge"
100                  << endl;
101     abort();
102   }
103 }
104 
~HCoreWfn()105 HCoreWfn::~HCoreWfn()
106 {
107   delete[] docc_;
108   delete[] socc_;
109 }
110 
111 void
save_data_state(StateOut & s)112 HCoreWfn::save_data_state(StateOut&s)
113 {
114   OneBodyWavefunction::save_data_state(s);
115   s.put(nirrep_);
116   s.put(docc_,nirrep_);
117   s.put(socc_,nirrep_);
118   s.put(user_occ_);
119   s.put(total_charge_);
120 }
121 
122 RefSCMatrix
oso_eigenvectors()123 HCoreWfn::oso_eigenvectors()
124 {
125   if (!oso_eigenvectors_.computed() || !eigenvalues_.computed()) {
126     RefSymmSCMatrix hcore_oso(oso_dimension(), basis_matrixkit());
127     hcore_oso->assign(0.0);
128     hcore_oso->accumulate_transform(so_to_orthog_so(), core_hamiltonian());
129 
130     if (debug_ > 1) {
131       core_hamiltonian().print("hcore in SO basis");
132     }
133 
134     if (debug_ > 1) {
135       hcore_oso.print("hcore in ortho SO basis");
136     }
137 
138     RefSCMatrix vec(oso_dimension(), oso_dimension(), basis_matrixkit());
139     RefDiagSCMatrix val(oso_dimension(), basis_matrixkit());
140 
141     hcore_oso.diagonalize(val,vec);
142 
143     if (debug_ > 1) {
144       val.print("hcore eigenvalues in ortho SO basis");
145       vec.print("hcore eigenvectors in ortho SO basis");
146     }
147     oso_eigenvectors_=vec;
148     oso_eigenvectors_.computed() = 1;
149 
150     eigenvalues_ = val;
151     eigenvalues_.computed() = 1;
152 
153     if (!user_occ_) {
154       int nelectron = int(molecule()->nuclear_charge()) - total_charge_;
155       int ndocc = nelectron/2;
156       int nsocc = nelectron%2;
157       fill_occ(val, ndocc, docc_, nsocc, socc_);
158 
159       ExEnv::out0() << indent << "docc = [";
160       for (int i=0; i<nirrep_; i++) ExEnv::out0() << " " << docc_[i];
161       ExEnv::out0() << "]" << endl;
162 
163       ExEnv::out0() << indent << "socc = [";
164       for (int i=0; i<nirrep_; i++) ExEnv::out0() << " " << socc_[i];
165       ExEnv::out0() << "]" << endl;
166       }
167   }
168 
169   return oso_eigenvectors_.result_noupdate();
170 }
171 
172 RefDiagSCMatrix
eigenvalues()173 HCoreWfn::eigenvalues()
174 {
175   if (!eigenvalues_.computed()) {
176     oso_eigenvectors();
177   }
178 
179   return eigenvalues_.result_noupdate();
180 }
181 
182 RefSymmSCMatrix
density()183 HCoreWfn::density()
184 {
185   if (!density_.computed()) {
186     // Make sure the eigenvectors are computed before
187     // the MO density is computed, otherwise, docc and
188     // socc might not have been initialized.
189     oso_eigenvectors();
190 
191     RefDiagSCMatrix mo_density(oso_dimension(), basis_matrixkit());
192     BlockedDiagSCMatrix *modens
193       = dynamic_cast<BlockedDiagSCMatrix*>(mo_density.pointer());
194     if (!modens) {
195       ExEnv::err0() << indent
196                    << "HCoreWfn::density: wrong MO matrix kit" << endl;
197       abort();
198     }
199 
200     modens->assign(0.0);
201     for (int iblock=0; iblock < modens->nblocks(); iblock++) {
202       RefDiagSCMatrix modens_ib = modens->block(iblock);
203       int i;
204       for (i=0; i < docc_[iblock]; i++)
205         modens_ib->set_element(i, 2.0);
206       for ( ; i < docc_[iblock]+socc_[iblock]; i++)
207         modens_ib->set_element(i, 1.0);
208     }
209 
210     RefSymmSCMatrix dens(so_dimension(), basis_matrixkit());
211     dens->assign(0.0);
212     dens->accumulate_transform(so_to_orthog_so().t() * mo_to_orthog_so(),
213                                mo_density);
214 
215     if (debug_ > 1) {
216       mo_density.print("MO Density");
217       dens.print("SO Density");
218       ExEnv::out0()
219                    << indent << "Nelectron(MO) = " << mo_density.trace()
220                    << endl
221                    << indent << "Nelectron(SO) = "
222                    << (overlap()*dens).trace()
223                    << endl;
224     }
225 
226     density_ = dens;
227     density_.computed() = 1;
228   }
229 
230   return density_.result_noupdate();
231 }
232 
233 double
occupation(int ir,int i)234 HCoreWfn::occupation(int ir, int i)
235 {
236   if (i < docc_[ir])
237     return 2.0;
238   else if (i < docc_[ir]+socc_[ir])
239     return 1.0;
240   else
241     return 0.0;
242 }
243 
244 int
spin_polarized()245 HCoreWfn::spin_polarized()
246 {
247   return 0;
248 }
249 
250 int
spin_unrestricted()251 HCoreWfn::spin_unrestricted()
252 {
253   return 0;
254 }
255 
256 void
compute()257 HCoreWfn::compute()
258 {
259   double e = (density()*core_hamiltonian()).trace();
260   set_energy(e);
261   set_actual_value_accuracy(desired_value_accuracy());
262   return;
263 }
264 
265 int
value_implemented() const266 HCoreWfn::value_implemented() const
267 {
268   return 1;
269 }
270 
271 void
fill_occ(const RefDiagSCMatrix & evals,int ndocc,int * docc,int nsocc,int * socc)272 HCoreWfn::fill_occ(const RefDiagSCMatrix &evals,int ndocc,int *docc,
273                    int nsocc, int *socc)
274 {
275   BlockedDiagSCMatrix *bval
276     = require_dynamic_cast<BlockedDiagSCMatrix*>(evals.pointer(),
277                                            "HCoreWave: getting occupations");
278   int nblock = bval->nblocks();
279   if (nblock != nirrep_) {
280     ExEnv::errn() << "ERROR: HCoreWfn: fill_occ: nblock != nirrep" << endl
281                  << "  nblock = " << nblock << endl
282                  << "  nirrep = " << nirrep_ << endl;
283     abort();
284   }
285   memset(docc,0,sizeof(docc[0])*nblock);
286   memset(socc,0,sizeof(socc[0])*nblock);
287   for (int i=0; i<ndocc; i++) {
288     double lowest;
289     int lowest_j = -1;
290     for (int j=0; j<nblock; j++) {
291       RefDiagSCMatrix block = bval->block(j);
292       if (block.null()) continue;
293       double current = block->get_element(docc[j]);
294       if (lowest_j < 0 || lowest > current) {
295         lowest = current;
296         lowest_j = j;
297       }
298     }
299     docc[lowest_j]++;
300   }
301   for (int i=0; i<nsocc; i++) {
302     double lowest;
303     int lowest_j = -1;
304     for (int j=0; j<nblock; j++) {
305       double current = bval->block(j)->get_element(docc[j]+socc[j]);
306       if (lowest_j < 0 || lowest > current) {
307         lowest = current;
308         lowest_j = j;
309       }
310     }
311     socc[lowest_j]++;
312   }
313 }
314 
315 /////////////////////////////////////////////////////////////////////////////
316 
317 // Local Variables:
318 // mode: c++
319 // c-file-style: "ETS"
320 // End:
321