1 /* Ergo, version 3.8, a program for linear scaling electronic structure
2  * calculations.
3  * Copyright (C) 2019 Elias Rudberg, Emanuel H. Rubensson, Pawel Salek,
4  * and Anastasia Kruchinina.
5  *
6  * This program is free software: you can redistribute it and/or modify
7  * it under the terms of the GNU General Public License as published by
8  * the Free Software Foundation, either version 3 of the License, or
9  * (at your option) any later version.
10  *
11  * This program is distributed in the hope that it will be useful,
12  * but WITHOUT ANY WARRANTY; without even the implied warranty of
13  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
14  * GNU General Public License for more details.
15  *
16  * You should have received a copy of the GNU General Public License
17  * along with this program.  If not, see <http://www.gnu.org/licenses/>.
18  *
19  * Primary academic reference:
20  * Ergo: An open-source program for linear-scaling electronic structure
21  * calculations,
22  * Elias Rudberg, Emanuel H. Rubensson, Pawel Salek, and Anastasia
23  * Kruchinina,
24  * SoftwareX 7, 107 (2018),
25  * <http://dx.doi.org/10.1016/j.softx.2018.03.005>
26  *
27  * For further information about Ergo, see <http://www.ergoscf.org>.
28  */
29 
30 /** @file scf_utils.cc
31 
32     @brief Various utilities used by self-consistent field (SCF)
33     code. For example, interface routines converting between HML
34     matrix format used in main SCF code and elementwise format used by
35     integral code.
36 
37     @author: Elias Rudberg <em>responsible</em>
38 */
39 
40 #include <pthread.h>
41 #include <sstream>
42 
43 #include "scf_utils.h"
44 #include "output.h"
45 #include "integrals_1el.h"
46 #include "memorymanag.h"
47 #include "operator_matrix.h"
48 #include "integrals_1el_kinetic.h"
49 #include "integrals_1el_potential.h"
50 #include "utilities.h"
51 #include "integrals_2el_explicit.h"
52 #include "basis_func_pair_list.h"
53 #include "integrals_2el_boxed.h"
54 #include "integrals_2el_explicit.h"
55 #include "integrals_2el_layer.h"
56 #include "density_description_file.h"
57 #include "mat_acc_extrapolate.h"
58 #include "basis_func_pair_list_1el.h"
59 #include "integral_matrix_wrappers.h"
60 #include "units.h"
61 #include "densitymanager.h"
62 
63 
64 /* Flag for skipping DFT stuff, used in QD precision tests. */
65 //#define SKIP_DFT_FLAG
66 
67 #ifndef SKIP_DFT_FLAG
68 #include "dft_common.h"
69 #include "xc_matrix.h"
70 #include "xc_matrix_sparse.h"
71 #endif
72 
73 
74 
75 
76 template<class Tinvestigator, class Tworker>
do_scan_and_report(Tinvestigator investigator,Tworker worker,const char * scanName,int nSteps,ergo_real startThresh,ergo_real stepFactor)77 static void do_scan_and_report(Tinvestigator investigator,
78 			       Tworker worker,
79 			       const char* scanName,
80 			       int nSteps,
81 			       ergo_real startThresh,
82 			       ergo_real stepFactor)
83 {
84   investigator.Scan(worker, startThresh, stepFactor, nSteps);
85   ergo_real threshList[nSteps];
86   ergo_real errorList_frob[nSteps];
87   ergo_real errorList_eucl[nSteps];
88   ergo_real errorList_maxe[nSteps];
89   ergo_real timeList[nSteps];
90   investigator.GetScanResult(threshList,
91 			     errorList_frob,
92 			     errorList_eucl,
93 			     errorList_maxe,
94 			     timeList);
95   do_output(LOG_CAT_INFO, LOG_AREA_SCF, "Accuracy scan result for '%s':", scanName);
96   do_output(LOG_CAT_INFO, LOG_AREA_SCF, "      thresh            frob            eucl            maxe            time");
97   for(int i = 0; i < nSteps; i++)
98     do_output(LOG_CAT_INFO, LOG_AREA_SCF, "%15.6g %15.6g %15.6g %15.6g %15.6g",
99 	      (double)threshList[i],
100 	      (double)errorList_frob[i],
101 	      (double)errorList_eucl[i],
102 	      (double)errorList_maxe[i],
103 	      (double)timeList[i]);
104 }
105 
106 
107 
108 
109 
110 class Jworker
111 {
112 public:
Jworker(const symmMatrix & D_,const IntegralInfo & integralInfo_,const BasisInfoStruct & basisInfo_,const triangMatrix & invCholFactor_,bool doInvCholFactorTransformation_,const JK::Params & J_K_params_,std::vector<int> const & permutationHML_)113   Jworker(const symmMatrix & D_,
114 	  const IntegralInfo & integralInfo_,
115 	  const BasisInfoStruct & basisInfo_,
116 	  const triangMatrix & invCholFactor_,
117 	  bool doInvCholFactorTransformation_,
118 	  const JK::Params & J_K_params_,
119 	  std::vector<int> const & permutationHML_) :
120     D(D_),
121     integralInfo(integralInfo_),
122     basisInfo(basisInfo_),
123     invCholFactor(invCholFactor_),
124     doInvCholFactorTransformation(doInvCholFactorTransformation_),
125     permutationHML(permutationHML_)
126   {
127     J_K_params = J_K_params_;
128   }
129   void ComputeMatrix(ergo_real param,
130 		     symmMatrix & result) const;
131 private:
132   const symmMatrix & D;
133   const IntegralInfo & integralInfo;
134   const BasisInfoStruct & basisInfo;
135   const triangMatrix & invCholFactor;
136   bool doInvCholFactorTransformation;
137   JK::Params J_K_params;
138   std::vector<int> const & permutationHML;
139 };
140 
ComputeMatrix(ergo_real param,symmMatrix & result) const141 void Jworker::ComputeMatrix(ergo_real param,
142 			    symmMatrix & result) const
143 {
144   JK::Params J_K_params_tmp = J_K_params;
145   J_K_params_tmp.threshold_J = param;
146   if(compute_J_by_boxes_sparse(basisInfo,
147 			       integralInfo,
148 			       J_K_params_tmp,
149 			       result,
150 			       D,
151 			       permutationHML) != 0)
152     throw "Jworker::ComputeMatrix: error in compute_J_by_boxes_sparse";
153   if(doInvCholFactorTransformation)
154     result = transpose(invCholFactor) * result * invCholFactor;
155 }
156 
157 void
do_acc_scan_J(const symmMatrix & D,const IntegralInfo & integralInfo,const BasisInfoStruct & basisInfo,triangMatrix & invCholFactor,bool doInvCholFactorTransformation,const JK::Params & J_K_params,mat::SizesAndBlocks const & matrix_size_block_info,std::vector<int> const & permutationHML,int nSteps,ergo_real startThresh,ergo_real stepFactor)158 do_acc_scan_J(const symmMatrix & D,
159 	      const IntegralInfo & integralInfo,
160 	      const BasisInfoStruct & basisInfo,
161 	      triangMatrix & invCholFactor,
162 	      bool doInvCholFactorTransformation,
163 	      const JK::Params & J_K_params,
164 	      mat::SizesAndBlocks const & matrix_size_block_info,
165 	      std::vector<int> const & permutationHML,
166 	      int nSteps,
167 	      ergo_real startThresh,
168 	      ergo_real stepFactor)
169 {
170   invCholFactor.readFromFile();
171   Jworker worker(D, integralInfo, basisInfo, invCholFactor, doInvCholFactorTransformation, J_K_params, permutationHML);
172   MatAccInvestigator<ergo_real, Jworker> investigator(matrix_size_block_info);
173   do_scan_and_report(investigator, worker, "J", nSteps, startThresh, stepFactor);
174   invCholFactor.writeToFile();
175 }
176 
177 
178 
179 class Kworker
180 {
181 public:
Kworker(symmMatrix & D_,const IntegralInfo & integralInfo_,const BasisInfoStruct & basisInfo_,const triangMatrix & invCholFactor_,bool doInvCholFactorTransformation_,const JK::ExchWeights & CAM_params_,const JK::Params & J_K_params_,std::vector<int> const & permutationHML_,std::vector<int> const & inversePermutationHML_)182   Kworker(symmMatrix & D_,
183 	  const IntegralInfo & integralInfo_,
184 	  const BasisInfoStruct & basisInfo_,
185 	  const triangMatrix & invCholFactor_,
186 	  bool doInvCholFactorTransformation_,
187 	  const JK::ExchWeights & CAM_params_,
188 	  const JK::Params & J_K_params_,
189 	  std::vector<int> const & permutationHML_,
190 	  std::vector<int> const & inversePermutationHML_) :
191     D(D_),
192     integralInfo(integralInfo_),
193     basisInfo(basisInfo_),
194     invCholFactor(invCholFactor_),
195     doInvCholFactorTransformation(doInvCholFactorTransformation_),
196     CAM_params(CAM_params_),
197     permutationHML(permutationHML_),
198     inversePermutationHML(inversePermutationHML_)
199   {
200     J_K_params = J_K_params_;
201   }
202   void ComputeMatrix(ergo_real param,
203 		     symmMatrix & result) const;
204 private:
205   symmMatrix & D;
206   const IntegralInfo & integralInfo;
207   const BasisInfoStruct & basisInfo;
208   const triangMatrix & invCholFactor;
209   bool doInvCholFactorTransformation;
210   const JK::ExchWeights & CAM_params;
211   JK::Params J_K_params;
212   std::vector<int> const & permutationHML;
213   std::vector<int> const & inversePermutationHML;
214 };
215 
ComputeMatrix(ergo_real param,symmMatrix & result) const216 void Kworker::ComputeMatrix(ergo_real param,
217 			    symmMatrix & result) const
218 {
219   JK::Params J_K_params_tmp = J_K_params;
220   J_K_params_tmp.threshold_K = param;
221   if(compute_K_by_boxes_sparse(basisInfo,
222 			       integralInfo,
223 			       CAM_params,
224 			       J_K_params_tmp,
225 			       result,
226 			       D,
227 			       permutationHML,
228 			       inversePermutationHML) != 0)
229     throw "Kworker::ComputeMatrix: error in compute_K_by_boxes_sparse";
230   if(doInvCholFactorTransformation)
231     result = transpose(invCholFactor) * result * invCholFactor;
232 }
233 
234 void
do_acc_scan_K(symmMatrix & D,const IntegralInfo & integralInfo,const BasisInfoStruct & basisInfo,triangMatrix & invCholFactor,bool doInvCholFactorTransformation,const JK::ExchWeights & CAM_params,const JK::Params & J_K_params,mat::SizesAndBlocks const & matrix_size_block_info,std::vector<int> const & permutationHML,std::vector<int> const & inversePermutationHML,int nSteps,ergo_real startThresh,ergo_real stepFactor)235 do_acc_scan_K(symmMatrix & D,
236 	      const IntegralInfo & integralInfo,
237 	      const BasisInfoStruct & basisInfo,
238 	      triangMatrix & invCholFactor,
239 	      bool doInvCholFactorTransformation,
240 	      const JK::ExchWeights & CAM_params,
241 	      const JK::Params & J_K_params,
242 	      mat::SizesAndBlocks const & matrix_size_block_info,
243 	      std::vector<int> const & permutationHML,
244 	      std::vector<int> const & inversePermutationHML,
245 	      int nSteps,
246 	      ergo_real startThresh,
247 	      ergo_real stepFactor)
248 {
249   invCholFactor.readFromFile();
250   Kworker worker(D, integralInfo, basisInfo, invCholFactor, doInvCholFactorTransformation, CAM_params, J_K_params, permutationHML, inversePermutationHML);
251   MatAccInvestigator<ergo_real, Kworker> investigator(matrix_size_block_info);
252   do_scan_and_report(investigator, worker, "K", nSteps, startThresh, stepFactor);
253   invCholFactor.writeToFile();
254 }
255 
256 
257 class Vxc_worker
258 {
259 public:
Vxc_worker(symmMatrix & D_,const IntegralInfo & integralInfo_,const BasisInfoStruct & basisInfo_,const Molecule & molecule_,const Dft::GridParams & gridParams_,int noOfElectrons_,const triangMatrix & invCholFactor_,bool doInvCholFactorTransformation_,mat::SizesAndBlocks const & matrix_size_block_info_,std::vector<int> const & permutationHML_,std::vector<int> const & inversePermutationHML_)260   Vxc_worker(symmMatrix & D_,
261 	     const IntegralInfo & integralInfo_,
262 	     const BasisInfoStruct & basisInfo_,
263 	     const Molecule & molecule_,
264 	     const Dft::GridParams & gridParams_,
265 	     int noOfElectrons_,
266 	     const triangMatrix & invCholFactor_,
267 	     bool doInvCholFactorTransformation_,
268 	     mat::SizesAndBlocks const & matrix_size_block_info_,
269 	     std::vector<int> const & permutationHML_,
270 	     std::vector<int> const & inversePermutationHML_) :
271     D(D_),
272     integralInfo(integralInfo_),
273     basisInfo(basisInfo_),
274     molecule(molecule_),
275     gridParams(gridParams_),
276     noOfElectrons(noOfElectrons_),
277     invCholFactor(invCholFactor_),
278     doInvCholFactorTransformation(doInvCholFactorTransformation_),
279     matrix_size_block_info(matrix_size_block_info_),
280     permutationHML(permutationHML_)
281     //inversePermutationHML(inversePermutationHML_
282   {
283   }
284   void ComputeMatrix(ergo_real param,
285 		     symmMatrix & result) const;
286 private:
287   symmMatrix & D;
288   const IntegralInfo & integralInfo;
289   const BasisInfoStruct & basisInfo;
290   const Molecule & molecule;
291   const Dft::GridParams & gridParams;
292   int noOfElectrons;
293   const triangMatrix & invCholFactor;
294   bool doInvCholFactorTransformation;
295   mat::SizesAndBlocks const & matrix_size_block_info;
296   std::vector<int> const & permutationHML;
297   //std::vector<int> const & inversePermutationHML;
298 };
299 
ComputeMatrix(ergo_real param,symmMatrix & result) const300 void Vxc_worker::ComputeMatrix(ergo_real param,
301 			       symmMatrix & result) const
302 {
303   Dft::GridParams gridParams_tmp = gridParams;
304   gridParams_tmp.hicuParams.maxError = param;
305   result.resetSizesAndBlocks(matrix_size_block_info,
306 			     matrix_size_block_info);
307   /* Remove grid files to make sure new grid is generated. */
308   grid_free_files();
309   ergo_real dftEnergy = 0;
310   Dft::getXC_mt(basisInfo, integralInfo,
311 		molecule, gridParams_tmp, noOfElectrons,
312 		D, result, &dftEnergy,
313 		permutationHML);
314   do_output(LOG_CAT_INFO, LOG_AREA_SCF, "Vxc_worker::ComputeMatrix dftEnergy = %25.15f", (double)dftEnergy);
315   if(doInvCholFactorTransformation)
316     result = transpose(invCholFactor) * result * invCholFactor;
317 }
318 
319 void
do_acc_scan_Vxc(symmMatrix & D,const IntegralInfo & integralInfo,const BasisInfoStruct & basisInfo,const Molecule & molecule,const Dft::GridParams & gridParams,int noOfElectrons,triangMatrix & invCholFactor,bool doInvCholFactorTransformation,mat::SizesAndBlocks const & matrix_size_block_info,std::vector<int> const & permutationHML,std::vector<int> const & inversePermutationHML,int nSteps,ergo_real startThresh,ergo_real stepFactor)320 do_acc_scan_Vxc(symmMatrix & D,
321 		const IntegralInfo & integralInfo,
322 		const BasisInfoStruct & basisInfo,
323 		const Molecule & molecule,
324 		const Dft::GridParams & gridParams,
325 		int noOfElectrons,
326 		triangMatrix & invCholFactor,
327 		bool doInvCholFactorTransformation,
328 		mat::SizesAndBlocks const & matrix_size_block_info,
329 		std::vector<int> const & permutationHML,
330 		std::vector<int> const & inversePermutationHML,
331 		int nSteps,
332 		ergo_real startThresh,
333 		ergo_real stepFactor)
334 {
335   invCholFactor.readFromFile();
336   Vxc_worker worker(D,
337 		    integralInfo,
338 		    basisInfo,
339 		    molecule,
340 		    gridParams,
341 		    noOfElectrons,
342 		    invCholFactor,
343 		    doInvCholFactorTransformation,
344 		    matrix_size_block_info,
345 		    permutationHML,
346 		    inversePermutationHML);
347   MatAccInvestigator<ergo_real, Vxc_worker> investigator(matrix_size_block_info);
348   do_scan_and_report(investigator, worker, "Vxc", nSteps, startThresh, stepFactor);
349   invCholFactor.writeToFile();
350 }
351 
352 
353 
354 
355 
356 template <typename Tmatrix>
output_sparsity_template(int n,const Tmatrix & M,const char * matrixName,const char * matrixTypeName)357 void output_sparsity_template(int n,
358 			      const Tmatrix & M,
359 			      const char* matrixName,
360 			      const char* matrixTypeName) {
361   /* Use double to avoid integer overflow. */
362   double nnz_as_double = M.nnz();
363   ergo_real percent = 100 * nnz_as_double / ((double)n*n);
364   ergo_real memUsage = (double)M.memory_usage() / 1000000000;
365   do_output(LOG_CAT_INFO, LOG_AREA_SCF,
366 	    "Matrix '%s' (%s): n = %6i, nnz = %12.0f <-> %6.2f %%, mem usage %7.4f G",
367 	    matrixName, matrixTypeName, n, nnz_as_double, (double)percent, (double)memUsage);
368 }
369 
370 
output_sparsity(int n,const normalMatrix & M,const char * matrixName)371 void output_sparsity(int n, const normalMatrix & M, const char* matrixName)
372 {
373   output_sparsity_template(n, M, matrixName, "normal");
374 }
375 
output_sparsity_symm(int n,const symmMatrix & M,const char * matrixName)376 void output_sparsity_symm(int n, const symmMatrix & M, const char* matrixName)
377 {
378   output_sparsity_template(n, M, matrixName, " symm ");
379 }
380 
output_sparsity_triang(int n,const triangMatrix & M,const char * matrixName)381 void output_sparsity_triang(int n, const triangMatrix & M, const char* matrixName)
382 {
383   output_sparsity_template(n, M, matrixName, "triang");
384 }
385 
386 
387 static ergo_real
get_trace(int n,const ergo_real * P,const ergo_real * H_core)388 get_trace(int n, const ergo_real* P, const ergo_real* H_core)
389 {
390   ergo_real sum = 0;
391   for(int i = 0; i < n; i++)
392     for(int j = 0; j < n; j++)
393       sum += P[i*n+j] * H_core[i*n+j];
394   return sum;
395 }
396 
397 
398 static int
add_square_matrices(int n,const ergo_real * A,const ergo_real * B,ergo_real * C)399 add_square_matrices(int n, const ergo_real* A, const ergo_real* B, ergo_real* C)
400 {
401   int n2 = n*n;
402   for(int i = 0; i < n2; i++)
403     C[i] = A[i] + B[i];
404   return 0;
405 }
406 
407 
408 int
compute_h_core_matrix_simple_dense(const IntegralInfo & integralInfo,const Molecule & molecule,const BasisInfoStruct & basisInfo,symmMatrix & H_core_Matrix_sparse,ergo_real threshold_integrals_1el,int noOfThreadsForV,mat::SizesAndBlocks const & matrix_size_block_info,std::vector<int> const & permutationHML,ergo_real & result_nuclearRepulsionEnergy)409 compute_h_core_matrix_simple_dense(const IntegralInfo& integralInfo,
410 				   const Molecule& molecule,
411 				   const BasisInfoStruct& basisInfo,
412 				   symmMatrix & H_core_Matrix_sparse,
413 				   ergo_real threshold_integrals_1el,
414 				   int noOfThreadsForV,
415 				   mat::SizesAndBlocks const & matrix_size_block_info,
416 				   std::vector<int> const & permutationHML,
417 				   ergo_real & result_nuclearRepulsionEnergy)
418 {
419   int n = basisInfo.noOfBasisFuncs;
420   result_nuclearRepulsionEnergy = molecule.getNuclearRepulsionEnergyQuadratic();
421   std::vector<ergo_real> A(n*n);
422   if(compute_h_core_matrix_full(integralInfo,
423 				basisInfo,
424 				molecule.getNoOfAtoms(),
425 				molecule.getAtomListPtr(),
426 				&A[0],
427 				threshold_integrals_1el) != 0)
428     {
429       do_output(LOG_CAT_ERROR, LOG_AREA_SCF, "error in compute_h_core_matrix_full");
430       return -1;
431     }
432   int nvalues = n * (n + 1) / 2;
433   std::vector<int> rowind(nvalues);
434   std::vector<int> colind(nvalues);
435   std::vector<ergo_real> values(nvalues);
436   // populate vectors
437   int count = 0;
438   for(int i = 0; i < n; i++) {
439     for(int j = i; j < n; j++) {
440       rowind[count] = i;
441       colind[count] = j;
442       values[count] = A[i*n+j];
443       count++;
444     }
445   }
446   H_core_Matrix_sparse.assign_from_sparse(rowind,
447 					  colind,
448 					  values,
449 					  permutationHML,
450 					  permutationHML);
451   return 0;
452 }
453 
454 
455 
456 int
compute_h_core_matrix_sparse(const IntegralInfo & integralInfo,const Molecule & molecule,const Molecule & extraCharges,ergo_real electric_field_x,ergo_real electric_field_y,ergo_real electric_field_z,const BasisInfoStruct & basisInfo,symmMatrix & H_core_Matrix_sparse,ergo_real threshold_integrals_1el,int noOfThreadsForV,ergo_real boxSizeForVT,ergo_real & result_nuclearRepulsionEnergy,mat::SizesAndBlocks const & matrix_size_block_info,std::vector<int> const & permutationHML,int const create_dipole_mtx,std::vector<int> const * const inversePermutationHML,std::string const * const calculation_identifier,std::string const * const method_and_basis_set)457 compute_h_core_matrix_sparse(const IntegralInfo& integralInfo,
458 			     const Molecule& molecule,
459 			     const Molecule& extraCharges,
460 			     ergo_real electric_field_x,
461 			     ergo_real electric_field_y,
462 			     ergo_real electric_field_z,
463 			     const BasisInfoStruct& basisInfo,
464 			     symmMatrix & H_core_Matrix_sparse,
465 			     ergo_real threshold_integrals_1el,
466 			     int noOfThreadsForV,
467 			     ergo_real boxSizeForVT,
468 			     ergo_real & result_nuclearRepulsionEnergy,
469 			     mat::SizesAndBlocks const & matrix_size_block_info,
470 			     std::vector<int> const & permutationHML,
471 			     int const create_dipole_mtx,
472 			     std::vector<int> const * const inversePermutationHML,
473 			     std::string const * const calculation_identifier,
474 			     std::string const * const method_and_basis_set)
475 {
476   int n = basisInfo.noOfBasisFuncs;
477   do_output(LOG_CAT_INFO, LOG_AREA_SCF,
478 	    "entering compute_h_core_matrix_sparse, nAtoms = %i, n = %i, threshold = %g", molecule.getNoOfAtoms(), n, (double)threshold_integrals_1el);
479 
480   Util::TimeMeter timeMeterTot;
481 
482   // Get T
483 
484   Util::TimeMeter timeMeterT;
485 
486   symmMatrix T(H_core_Matrix_sparse);
487   T.clear();
488 
489   if(compute_T_sparse_linear(basisInfo,
490 			     integralInfo,
491 			     threshold_integrals_1el,
492 			     boxSizeForVT,
493 			     T,
494 			     permutationHML) != 0) {
495     do_output(LOG_CAT_ERROR, LOG_AREA_SCF, "error in compute_T_sparse");
496     return -1;
497   }
498   do_output(LOG_CAT_INFO, LOG_AREA_SCF, "compute_T_sparse_linear returned OK.");
499   timeMeterT.print(LOG_AREA_SCF, "compute_T_sparse_linear");
500 
501   // Get V
502   Util::TimeMeter timeMeterV;
503   symmMatrix V;
504   V.resetSizesAndBlocks(matrix_size_block_info,
505 			matrix_size_block_info);
506   if(compute_V_sparse(basisInfo,
507 		      integralInfo,
508 		      molecule,
509 		      threshold_integrals_1el,
510 		      boxSizeForVT,
511 		      V,
512 		      permutationHML,
513 		      result_nuclearRepulsionEnergy) != 0)
514     {
515       do_output(LOG_CAT_ERROR, LOG_AREA_SCF, "error in compute_V_sparse");
516       return -1;
517     }
518   timeMeterV.print(LOG_AREA_SCF, "Computation of V");
519 
520   H_core_Matrix_sparse = T + V;
521   T.clear();
522   V.clear();
523 
524   // No truncation of T or V was done so far... and not now!
525 
526   // Write to file and read again to reduce memory fragmentation.
527   H_core_Matrix_sparse.writeToFile();
528   H_core_Matrix_sparse.readFromFile();
529 
530   if(create_dipole_mtx == 1) {
531     // Output dipole matrices in mtx format
532     if ( calculation_identifier == 0 )
533       throw "calculation_identifier == 0 when create_dipole_mtx == 1";
534     if ( method_and_basis_set == 0 )
535       throw "method_and_basis_set == 0 when create_dipole_mtx == 1";
536     if ( inversePermutationHML  == 0 )
537       throw "inversePermutationHML == 0 when create_dipole_mtx == 1";
538     {
539       // dipole matrix X
540       std::stringstream id_ss;
541       id_ss << *calculation_identifier << " - dipole matrix X";
542       symmMatrix fieldMatrix(H_core_Matrix_sparse);
543       fieldMatrix.clear();
544       if(compute_operator_matrix_sparse_symm(basisInfo,
545 					     1, 0, 0,
546 					     fieldMatrix,
547 					     permutationHML) != 0)
548 	return -1;
549       do_output(LOG_CAT_INFO, LOG_AREA_SCF, "Creating mtx file for dipole matrix X");
550       write_matrix_in_matrix_market_format( fieldMatrix,
551 					    *inversePermutationHML,
552 					    "dipole_matrix_x",
553 					    id_ss.str(),
554 					    *method_and_basis_set );
555     }
556     {
557       // dipole matrix Y
558       std::stringstream id_ss;
559       id_ss << *calculation_identifier << " - dipole matrix Y";
560       symmMatrix fieldMatrix(H_core_Matrix_sparse);
561       fieldMatrix.clear();
562       if(compute_operator_matrix_sparse_symm(basisInfo,
563 					     0, 1, 0,
564 					     fieldMatrix,
565 					     permutationHML) != 0)
566 	return -1;
567       do_output(LOG_CAT_INFO, LOG_AREA_SCF, "Creating mtx file for dipole matrix Y");
568       write_matrix_in_matrix_market_format( fieldMatrix,
569 					    *inversePermutationHML,
570 					    "dipole_matrix_y",
571 					    id_ss.str(),
572 					    *method_and_basis_set );
573     }
574     {
575       // dipole matrix Z
576       std::stringstream id_ss;
577       id_ss << *calculation_identifier << " - dipole matrix Z";
578       symmMatrix fieldMatrix(H_core_Matrix_sparse);
579       fieldMatrix.clear();
580       if(compute_operator_matrix_sparse_symm(basisInfo,
581 					     0, 0, 1,
582 					     fieldMatrix,
583 					     permutationHML) != 0)
584 	return -1;
585       do_output(LOG_CAT_INFO, LOG_AREA_SCF, "Creating mtx file for dipole matrix Z");
586       write_matrix_in_matrix_market_format( fieldMatrix,
587 					    *inversePermutationHML,
588 					    "dipole_matrix_z",
589 					    id_ss.str(),
590 					    *method_and_basis_set );
591     }
592   } // end if(create_dipole_mtx == 1)
593 
594 
595   // Add contributions from electric field, if any
596   if(electric_field_x != 0)
597     {
598       do_output(LOG_CAT_INFO, LOG_AREA_SCF,
599 		"electric_field_x = %22.11f", (double)electric_field_x);
600       symmMatrix fieldMatrix(H_core_Matrix_sparse);
601       fieldMatrix.clear();
602       if(compute_operator_matrix_sparse_symm(basisInfo,
603 					     1, 0, 0,
604 					     fieldMatrix,
605 					     permutationHML) != 0)
606 	return -1;
607       H_core_Matrix_sparse +=
608 	(ergo_real)(-1.0) * electric_field_x * fieldMatrix;
609     }
610   if(electric_field_y != 0)
611     {
612       do_output(LOG_CAT_INFO, LOG_AREA_SCF,
613 		"electric_field_y = %22.11f", (double)electric_field_y);
614       symmMatrix fieldMatrix(H_core_Matrix_sparse);
615       fieldMatrix.clear();
616       if(compute_operator_matrix_sparse_symm(basisInfo,
617 					     0, 1, 0,
618 					     fieldMatrix,
619 					     permutationHML) != 0)
620 	return -1;
621       H_core_Matrix_sparse +=
622 	(ergo_real)(-1.0) * electric_field_y * fieldMatrix;
623     }
624   if(electric_field_z != 0)
625     {
626       do_output(LOG_CAT_INFO, LOG_AREA_SCF,
627 		"electric_field_z = %22.11f", (double)electric_field_z);
628       symmMatrix fieldMatrix(H_core_Matrix_sparse);
629       fieldMatrix.clear();
630       if(compute_operator_matrix_sparse_symm(basisInfo,
631 					     0, 0, 1,
632 					     fieldMatrix,
633 					     permutationHML) != 0)
634 	return -1;
635       H_core_Matrix_sparse +=
636 	(ergo_real)(-1.0) * electric_field_z * fieldMatrix;
637     }
638 
639   // Add contribution from extra charges, if any.
640   if(extraCharges.getNoOfAtoms() > 0) {
641     do_output(LOG_CAT_INFO, LOG_AREA_SCF, "Using 'extra charges', extraCharges.noOfAtoms = %d", extraCharges.getNoOfAtoms());
642     ergo_real sumCharge = 0;
643     ergo_real maxCharge = extraCharges.getAtom(0).charge;
644     ergo_real minCharge = extraCharges.getAtom(0).charge;
645     for(int i = 0; i < extraCharges.getNoOfAtoms(); i++) {
646       ergo_real currCharge = extraCharges.getAtom(i).charge;
647       sumCharge += currCharge;
648       if(currCharge > maxCharge)
649 	maxCharge = currCharge;
650       if(currCharge < minCharge)
651 	minCharge = currCharge;
652     }
653     do_output(LOG_CAT_INFO, LOG_AREA_SCF, "Using 'extra charges', sum = %8.4f, min = %8.4f, max = %8.4f",
654 	      (double)sumCharge, (double)minCharge, (double)maxCharge);
655     ergo_real minDist = template_blas_get_num_limit_max<ergo_real>();
656     ergo_real minDistCharge1 = 0;
657     ergo_real minDistCharge2 = 0;
658     for(int i = 0; i < extraCharges.getNoOfAtoms(); i++)
659       for(int j = 0; j < molecule.getNoOfAtoms(); j++) {
660 	ergo_real dx = extraCharges.getAtom(i).coords[0] - molecule.getAtom(j).coords[0];
661 	ergo_real dy = extraCharges.getAtom(i).coords[1] - molecule.getAtom(j).coords[1];
662 	ergo_real dz = extraCharges.getAtom(i).coords[2] - molecule.getAtom(j).coords[2];
663 	ergo_real dist = template_blas_sqrt(dx*dx+dy*dy+dz*dz);
664 	if(dist < minDist) {
665 	  minDist = dist;
666 	  minDistCharge1 = molecule.getAtom(j).charge;
667 	  minDistCharge2 = extraCharges.getAtom(i).charge;
668 	}
669       }
670     do_output(LOG_CAT_INFO, LOG_AREA_SCF, "Min dist between any 'extra charge' atom and any atom in main molecule: %9.5f a.u. = %9.5f Angstrom",
671 	      (ergo_real)minDist, (ergo_real)(minDist/UNIT_one_Angstrom));
672     do_output(LOG_CAT_INFO, LOG_AREA_SCF, "Charges for min dist: %9.5f (main) and %9.5f (extra)", (double)minDistCharge1, (double)minDistCharge2);
673     Util::TimeMeter timeMeter_V_extra;
674     symmMatrix V_extra;
675     V_extra.resetSizesAndBlocks(matrix_size_block_info,
676 				matrix_size_block_info);
677     ergo_real nuclearRepulsionEnergy_dummy = 0;
678     if(compute_V_sparse(basisInfo,
679 			integralInfo,
680 			extraCharges,
681 			threshold_integrals_1el,
682 			boxSizeForVT,
683 			V_extra,
684 			permutationHML,
685 			nuclearRepulsionEnergy_dummy) != 0) {
686       do_output(LOG_CAT_ERROR, LOG_AREA_SCF, "error in compute_V_sparse");
687       return -1;
688     }
689     timeMeter_V_extra.print(LOG_AREA_SCF, "Computation of V_extra");
690     H_core_Matrix_sparse += (ergo_real)(1.0) * V_extra;
691   }
692 
693   do_output(LOG_CAT_INFO, LOG_AREA_SCF, "compute_h_core_matrix_sparse ending OK.");
694   timeMeterTot.print(LOG_AREA_SCF, "compute_h_core_matrix_sparse");
695 
696   return 0;
697 }
698 
699 
700 int
get_gradient_for_given_mol_and_dens(const IntegralInfo & integralInfo,const Molecule & molecule,const BasisInfoStruct & basisInfo,const symmMatrix & D,ergo_real threshold_integrals_1el,mat::SizesAndBlocks const & matrix_size_block_info,std::vector<int> const & permutationHML,ergo_real * result_gradient_list)701 get_gradient_for_given_mol_and_dens(const IntegralInfo& integralInfo,
702 				    const Molecule& molecule,
703 				    const BasisInfoStruct& basisInfo,
704 				    const symmMatrix & D,
705 				    ergo_real threshold_integrals_1el,
706 				    mat::SizesAndBlocks const & matrix_size_block_info,
707 				    std::vector<int> const & permutationHML,
708 				    ergo_real* result_gradient_list)
709 {
710   ergo_real boxSize = 1.0;
711   if(compute_gradient_of_nucl_and_trDV(basisInfo,
712 				       integralInfo,
713 				       molecule,
714 				       threshold_integrals_1el,
715 				       boxSize,
716 				       D,
717 				       permutationHML,
718 				       result_gradient_list) != 0) {
719     throw "Error in compute_gradient_of_tr_D_V";
720   }
721   return 0;
722 }
723 
724 
725 
726 /** Saves specified symmetic matrix to a file of specified name.
727     @param A the matrix to save. The matrix must be saved to a backing
728     store already.
729     @param basisInfo the basis set description.
730     @param fileName The file that will contain the matrix. It will be
731     overwritten without further questions.
732     @param inversePermutationHML permutation information needed when using hierarchic matrices.
733 */
734 int
save_symmetric_matrix(symmMatrix & A,const BasisInfoStruct & basisInfo,const char * fileName,std::vector<int> const & inversePermutationHML)735 save_symmetric_matrix(symmMatrix& A, const BasisInfoStruct & basisInfo,
736                       const char *fileName,
737 		      std::vector<int> const & inversePermutationHML)
738 {
739   int n = basisInfo.noOfBasisFuncs;
740   do_output(LOG_CAT_INFO, LOG_AREA_SCF, "save_symmetric_matrix allocating full n*n matrix.");
741   ergo_real* potentialMatrixFull = new ergo_real[n*n];
742   normalMatrix* tmpMat;
743   A.readFromFile();
744   tmpMat = new normalMatrix(A);
745   A.writeToFile();
746   std::vector<ergo_real> fullTmp(n*n);
747   tmpMat->fullMatrix(fullTmp,
748 		     inversePermutationHML,
749 		     inversePermutationHML);
750   std::copy (fullTmp.begin(), fullTmp.end(), potentialMatrixFull);
751   delete tmpMat;
752   int ret = ddf_writeShellListAndDensityMatricesToFile(basisInfo,
753                                                        1,
754                                                        &potentialMatrixFull,
755                                                        fileName);
756   delete [] potentialMatrixFull;
757   return ret;
758 }
759 
760 int
add_disturbance_to_matrix(int n,symmMatrix & A,ergo_real disturbance,int specificElementCount,const int * elementIndexVector,std::vector<int> const & permutationHML)761 add_disturbance_to_matrix(int n,
762 			  symmMatrix & A,
763 			  ergo_real disturbance,
764 			  int specificElementCount,
765 			  const int* elementIndexVector,
766 			  std::vector<int> const & permutationHML)
767 {
768   // Create diagonal matrix with random numbers.
769   std::vector<ergo_real> diagonalValues(n);
770   std::vector<int> rowind(n);
771   std::vector<int> colind(n);
772   for(int i = 0; i < n; i++)
773     diagonalValues[i] = 0;
774   if(specificElementCount == 0)
775     {
776       // use random numbers
777       for(int i = 0; i < n; i++)
778 	{
779 	  double randomNumber = (double)rand() / RAND_MAX;
780 	  // Now randomNumber is between 0 and 1
781 	  randomNumber *= 2;
782 	  // Now randomNumber is between 0 and 2
783 	  randomNumber -= 1;
784 	  // Now randomNumber is between -1 and 1
785 	  diagonalValues[i] = randomNumber * disturbance;
786 	}
787     }
788   else
789     {
790       // use list of specific elements
791       for(int i = 0; i < specificElementCount; i++)
792 	{
793 	  int idx = elementIndexVector[i];
794 	  if(idx >= 0 && idx < n)
795 	    diagonalValues[idx] = disturbance;
796 	}
797     }
798   for(int i = 0; i < n; i++)
799     {
800       rowind[i] = i;
801       colind[i] = i;
802     }
803   symmMatrix B(A);
804   B.clear();
805   B.assign_from_sparse(rowind,
806 		       colind,
807 		       diagonalValues,
808 		       permutationHML,
809 		       permutationHML);
810   A += (ergo_real)1.0 * B;
811 
812   return 0;
813 }
814 
815 
816 
817 int
get_simple_starting_guess_sparse(int n,int noOfElectrons,symmMatrix & densityMatrix)818 get_simple_starting_guess_sparse(int n,
819 				 int noOfElectrons,
820 				 symmMatrix & densityMatrix)
821 {
822   std::vector<ergo_real> diagonalValues(n);
823   std::vector<int> rowind(n);
824   std::vector<int> colind(n);
825   for(int i = 0; i < n; i++)
826     diagonalValues[i] = (ergo_real)noOfElectrons / n;
827   for(int i = 0; i < n; i++)
828     {
829       rowind[i] = i;
830       colind[i] = i;
831     }
832   do_output(LOG_CAT_INFO, LOG_AREA_SCF, "get_simple_starting_guess_sparse: calling densityMatrix.assign_from_sparse.");
833   densityMatrix.assign_from_sparse(rowind, colind, diagonalValues);
834   do_output(LOG_CAT_INFO, LOG_AREA_SCF, "get_simple_starting_guess_sparse: densityMatrix.assign_from_sparse returned.");
835   return 0;
836 }
837 
838 
839 int
get_diag_matrix_from_file(int n,symmMatrix & M,const char * fileName,std::vector<int> const & permutationHML)840 get_diag_matrix_from_file(int n,
841 			  symmMatrix & M,
842 			  const char* fileName,
843 			  std::vector<int> const & permutationHML)
844 {
845   std::vector<ergo_real> diagonalValues(n);
846   std::vector<int> rowind(n);
847   std::vector<int> colind(n);
848   // First read values from file.
849   FILE* f = fopen(fileName, "rt");
850   if(f == NULL)
851     {
852       do_output(LOG_CAT_ERROR, LOG_AREA_MAIN, "error opening file '%s'", fileName);
853       return -1;
854     }
855 
856   const int BUFSIZE = 888888;
857   std::vector<char> buf(BUFSIZE);
858   memset(&buf[0], 0, BUFSIZE * sizeof(char));
859 
860   int nBytes = (int)fread(&buf[0], sizeof(char), BUFSIZE, f);
861   fclose(f);
862   if(nBytes <= 0)
863     {
864       do_output(LOG_CAT_ERROR, LOG_AREA_MAIN, "error reading file '%s'", fileName);
865       return -1;
866     }
867   if(nBytes >= (BUFSIZE-1000))
868     {
869       do_output(LOG_CAT_ERROR, LOG_AREA_MAIN, "error in get_diag_matrix_from_file: input file too large");
870       return -1;
871     }
872 
873   do_output(LOG_CAT_INFO, LOG_AREA_MAIN, "get_diag_matrix_from_file: File '%s' read OK, nBytes = %i", fileName, nBytes);
874 
875   int i = 0;
876   char* p = &buf[0];
877   while(*p != '\0')
878     {
879       // Now we expect p to point to the beginning of a new line
880       if(i >= n)
881 	{
882 	  do_output(LOG_CAT_ERROR, LOG_AREA_MAIN, "error in get_diag_matrix_from_file: too many lines in file.");
883 	  return -1;
884 	}
885 
886       // Skip blanks
887       while(*p == ' ' || *p == '\t')
888 	p++;
889 
890       diagonalValues[i] = atof(p);
891       i++;
892 
893       // Skip rest of line
894       while(*p != '\n' && *p != '\0')
895 	p++;
896       p++;
897     } // END WHILE
898 
899   for(i = 0; i < n; i++)
900     {
901       rowind[i] = i;
902       colind[i] = i;
903     }
904   do_output(LOG_CAT_INFO, LOG_AREA_SCF, "get_diag_matrix_from_file: calling densityMatrix.assign_from_sparse.");
905   M.assign_from_sparse(rowind,
906 		       colind,
907 		       diagonalValues,
908 		       permutationHML,
909 		       permutationHML);
910   do_output(LOG_CAT_INFO, LOG_AREA_SCF, "get_diag_matrix_from_file: densityMatrix.assign_from_sparse returned.");
911 
912   return 0;
913 }
914 
915 
916 int
write_diag_elements_to_file(int n,const symmMatrix & M,const char * fileName,std::vector<int> const & permutationHML)917 write_diag_elements_to_file(int n,
918 			    const symmMatrix & M,
919 			    const char* fileName,
920 			    std::vector<int> const & permutationHML)
921 {
922   do_output(LOG_CAT_INFO, LOG_AREA_MAIN, "write_diag_elements_to_file, n = %i", n);
923 
924   FILE* f = fopen(fileName, "wt");
925   if(f == NULL)
926     {
927       do_output(LOG_CAT_ERROR, LOG_AREA_MAIN, "error opening file '%s'.", fileName);
928       return -1;
929     }
930 
931   std::vector<int> rowind(n);
932   std::vector<int> colind(n);
933   std::vector<ergo_real> values(n);
934 
935   for(int i = 0; i < n; i++)
936     {
937       rowind[i] = i;
938       colind[i] = i;
939     }
940 
941   do_output(LOG_CAT_INFO, LOG_AREA_MAIN, "write_diag_elements_to_file, calling M.get_values.");
942   M.get_values(rowind,
943 	       colind,
944 	       values,
945 	       permutationHML,
946 	       permutationHML);
947   do_output(LOG_CAT_INFO, LOG_AREA_MAIN, "write_diag_elements_to_file, after M.get_values.");
948 
949   for(int i = 0; i < n; i++)
950     fprintf(f, "%12.6f\n", (double)values[i]);
951   fclose(f);
952 
953   return 0;
954 }
955 
956 
957 
958 int
write_full_matrix(int n,const symmMatrix & M,const char * fileName,std::vector<int> const & inversePermutationHML)959 write_full_matrix(int n, const symmMatrix & M, const char* fileName,
960 		  std::vector<int> const & inversePermutationHML)
961 {
962   std::vector<ergo_real> buf(n*n);
963   M.fullMatrix(buf, inversePermutationHML, inversePermutationHML);
964   FILE* f = fopen(fileName, "wb");
965   if(f == NULL)
966     throw "error in write_full_matrix, in fopen.";
967   size_t noOfItemsWritten = fwrite(&buf[0], sizeof(ergo_real), n*n, f);
968   fclose(f);
969   if(noOfItemsWritten != (size_t)n*n)
970     throw "error in write_full_matrix, in fwrite.";
971   return 0;
972 }
973 
974 
975 int
write_basis_func_coord_file(const BasisInfoStruct & basisInfo)976 write_basis_func_coord_file(const BasisInfoStruct & basisInfo)
977 {
978   FILE* f = fopen("basis_func_coords.m", "wt");
979   if(f == NULL)
980     throw "write_basis_func_coord_file, in fopen.";
981   int n = basisInfo.noOfBasisFuncs;
982   fprintf(f, "basis_func_coords = [\n");
983   for(int i = 0; i < n; i++)
984     fprintf(f, "%15.9f %15.9f %15.9f\n",
985 	    (double)basisInfo.basisFuncList[i].centerCoords[0],
986 	    (double)basisInfo.basisFuncList[i].centerCoords[1],
987 	    (double)basisInfo.basisFuncList[i].centerCoords[2]);
988   fprintf(f, "];\n");
989   fclose(f);
990   return 0;
991 }
992 
993 
994 int
write_2el_integral_m_file(const BasisInfoStruct & basisInfo,const IntegralInfo & integralInfo)995 write_2el_integral_m_file(const BasisInfoStruct & basisInfo, const IntegralInfo & integralInfo)
996 {
997   int n = basisInfo.noOfBasisFuncs;
998   FILE* f = fopen("setup_twoel_integrals.m", "wt");
999   if(f == NULL)
1000     throw "write_2el_integral_m_file, in fopen.";
1001   fprintf(f, "twoel_integrals = zeros(%2d, %2d, %2d, %2d);\n", n, n, n, n);
1002   for(int a = 0; a < n; a++)
1003     for(int b = 0; b < n; b++)
1004       for(int c = 0; c < n; c++)
1005 	for(int d = 0; d < n; d++) {
1006 	  ergo_real integralValue = do_2e_integral(a, b, c, d, basisInfo, integralInfo);
1007 	  fprintf(f, "twoel_integrals(%2d, %2d, %2d, %2d) = %15.11f;\n", a+1, b+1, c+1, d+1, (double)integralValue);
1008 	}
1009   fclose(f);
1010   return 0;
1011 }
1012 
1013 
1014 
1015 static int
get_2e_matrix_and_energy_simple_HF_sparse(const BasisInfoStruct & basisInfo,const Molecule & molecule,const IntegralInfo & integralInfo,const JK::ExchWeights & CAM_params,symmMatrix & twoelMatrix_sparse,symmMatrix & densityMatrix_sparse,const JK::Params & J_K_params,mat::SizesAndBlocks const & matrix_size_block_info,std::vector<int> const & permutationHML,std::vector<int> const & inversePermutationHML,ergo_real * energy_2el,int get_J_K_matrices,symmMatrix & J_matrix,symmMatrix & K_matrix)1016 get_2e_matrix_and_energy_simple_HF_sparse(const BasisInfoStruct& basisInfo,
1017 					  const Molecule& molecule,
1018 					  const IntegralInfo& integralInfo,
1019 					  const JK::ExchWeights & CAM_params,
1020 					  symmMatrix & twoelMatrix_sparse,
1021 					  symmMatrix & densityMatrix_sparse,
1022 					  const JK::Params& J_K_params,
1023 					  mat::SizesAndBlocks const & matrix_size_block_info,
1024 					  std::vector<int> const & permutationHML,
1025 					  std::vector<int> const & inversePermutationHML,
1026 					  ergo_real* energy_2el,
1027 					  int get_J_K_matrices,
1028 					  symmMatrix & J_matrix,
1029 					  symmMatrix & K_matrix)
1030 {
1031 
1032   symmMatrix J;
1033   J.resetSizesAndBlocks(matrix_size_block_info,
1034 			       matrix_size_block_info);
1035   symmMatrix K;
1036   K.resetSizesAndBlocks(matrix_size_block_info,
1037 			       matrix_size_block_info);
1038   // FMM for J
1039   if(compute_J_by_boxes_sparse(basisInfo,
1040 			       integralInfo,
1041 			       J_K_params,
1042 			       J,
1043 			       densityMatrix_sparse,
1044 			       permutationHML) != 0)
1045     {
1046       do_output(LOG_CAT_ERROR, LOG_AREA_SCF, "error in compute_J_by_boxes_sparse");
1047       return -1;
1048     }
1049 
1050   // exchange matrix K
1051   if(compute_K_by_boxes_sparse(basisInfo,
1052 			       integralInfo,
1053 			       CAM_params,
1054 			       J_K_params,
1055 			       K,
1056 			       densityMatrix_sparse,
1057 			       permutationHML,
1058 			       inversePermutationHML) != 0)
1059     {
1060       do_output(LOG_CAT_ERROR, LOG_AREA_SCF, "error in compute_K_by_boxes_sparse");
1061       return -1;
1062     }
1063 
1064   twoelMatrix_sparse = J + K;
1065   if ( get_J_K_matrices == 1 ) {
1066     do_output(LOG_CAT_INFO, LOG_AREA_SCF, "Saving J and K matrices as requested.");
1067     J_matrix = J;
1068     K_matrix = K;
1069   }
1070 
1071   *energy_2el = 0.5 * symmMatrix::trace_ab(densityMatrix_sparse, twoelMatrix_sparse);
1072 
1073   return 0;
1074 }
1075 
1076 
1077 
1078 static int
get_2e_matrices_and_energy_simple_HF_sparse_unrestricted(const BasisInfoStruct & basisInfo,const Molecule & molecule,const IntegralInfo & integralInfo,symmMatrix & twoelMatrix_sparse_alpha,symmMatrix & twoelMatrix_sparse_beta,symmMatrix & densityMatrix_sparse_alpha,symmMatrix & densityMatrix_sparse_beta,const JK::Params & J_K_params,const JK::ExchWeights & CAM_params,mat::SizesAndBlocks const & matrix_size_block_info,std::vector<int> const & permutationHML,std::vector<int> const & inversePermutationHML,ergo_real * energy_2el)1079 get_2e_matrices_and_energy_simple_HF_sparse_unrestricted(const BasisInfoStruct& basisInfo,
1080 							 const Molecule& molecule,
1081 							 const IntegralInfo& integralInfo,
1082 							 symmMatrix & twoelMatrix_sparse_alpha,
1083 							 symmMatrix & twoelMatrix_sparse_beta,
1084 							 symmMatrix & densityMatrix_sparse_alpha,
1085 							 symmMatrix & densityMatrix_sparse_beta,
1086 							 const JK::Params& J_K_params,
1087 							 const JK::ExchWeights & CAM_params,
1088 							 mat::SizesAndBlocks const & matrix_size_block_info,
1089 							 std::vector<int> const & permutationHML,
1090 							 std::vector<int> const & inversePermutationHML,
1091 							 ergo_real* energy_2el)
1092 {
1093   symmMatrix J;
1094   J.resetSizesAndBlocks(matrix_size_block_info,
1095 			       matrix_size_block_info);
1096   symmMatrix K_alpha;
1097   K_alpha.resetSizesAndBlocks(matrix_size_block_info,
1098 				     matrix_size_block_info);
1099   symmMatrix K_beta;
1100   K_beta.resetSizesAndBlocks(matrix_size_block_info,
1101 				    matrix_size_block_info);
1102   // Compute total density matrix
1103   symmMatrix D_tot(densityMatrix_sparse_alpha);
1104   D_tot += densityMatrix_sparse_beta;
1105 
1106   // FMM for J
1107   if(compute_J_by_boxes_sparse(basisInfo,
1108 			       integralInfo,
1109 			       J_K_params,
1110 			       J,
1111 			       D_tot,
1112 			       permutationHML) != 0)
1113     {
1114       do_output(LOG_CAT_ERROR, LOG_AREA_SCF, "error in compute_J_by_boxes_sparse");
1115       return -1;
1116     }
1117   D_tot.clear();
1118 
1119   // exchange matrices
1120   if(compute_K_by_boxes_sparse(basisInfo,
1121 			       integralInfo,
1122 			       CAM_params,
1123 			       J_K_params,
1124 			       K_alpha,
1125 			       densityMatrix_sparse_alpha,
1126 			       permutationHML,
1127 			       inversePermutationHML) != 0)
1128     {
1129       do_output(LOG_CAT_ERROR, LOG_AREA_SCF, "error in compute_K_by_boxes_sparse");
1130       return -1;
1131     }
1132   if(compute_K_by_boxes_sparse(basisInfo,
1133 			       integralInfo,
1134 			       CAM_params,
1135 			       J_K_params,
1136 			       K_beta,
1137 			       densityMatrix_sparse_beta,
1138 			       permutationHML,
1139 			       inversePermutationHML) != 0)
1140     {
1141       do_output(LOG_CAT_ERROR, LOG_AREA_SCF, "error in compute_K_by_boxes_sparse");
1142       return -1;
1143     }
1144 
1145   K_alpha *= 2;
1146   K_beta  *= 2;
1147   twoelMatrix_sparse_alpha = J + K_alpha;
1148   twoelMatrix_sparse_beta  = J + K_beta;
1149 
1150   *energy_2el = 0;
1151   *energy_2el +=  0.5 * symmMatrix::trace_ab(densityMatrix_sparse_alpha, twoelMatrix_sparse_alpha);
1152   *energy_2el +=  0.5 * symmMatrix::trace_ab(densityMatrix_sparse_beta , twoelMatrix_sparse_beta );
1153 
1154   return 0;
1155 }
1156 
1157 /**
1158 Routine for computing the two-electron part of the Fock/KS matrix, in
1159 sparse form. This routine is only used when FMM is enabled.
1160 */
1161 static int
get_2e_matrix_and_energy_simple_sparse(const BasisInfoStruct & basisInfo,const Molecule & molecule,const IntegralInfo & integralInfo,symmMatrix & twoelMatrix_sparse,symmMatrix & densityMatrix_sparse,const JK::Params & J_K_params,const JK::ExchWeights & CAM_params,const Dft::GridParams & gridParams,mat::SizesAndBlocks const & matrix_size_block_info,std::vector<int> const & permutationHML,std::vector<int> const & inversePermutationHML,ergo_real * energy_2el,int do_xc,int noOfElectrons,int get_J_K_Fxc_matrices,symmMatrix & J_matrix,symmMatrix & K_matrix,symmMatrix & Fxc_matrix,SCF_statistics & stats)1162 get_2e_matrix_and_energy_simple_sparse(const BasisInfoStruct& basisInfo,
1163 				       const Molecule& molecule,
1164 				       const IntegralInfo& integralInfo,
1165 				       symmMatrix & twoelMatrix_sparse,
1166 				       symmMatrix & densityMatrix_sparse, // should be in memory when this routine is called
1167 				       const JK::Params& J_K_params,
1168 				       const JK::ExchWeights & CAM_params,
1169 				       const Dft::GridParams& gridParams,
1170 				       mat::SizesAndBlocks const & matrix_size_block_info,
1171 				       std::vector<int> const & permutationHML,
1172 				       std::vector<int> const & inversePermutationHML,
1173 				       ergo_real* energy_2el,
1174 				       int do_xc,
1175 				       int noOfElectrons,
1176 				       int get_J_K_Fxc_matrices,
1177 				       symmMatrix & J_matrix,
1178 				       symmMatrix & K_matrix,
1179 				       symmMatrix & Fxc_matrix,
1180 				       SCF_statistics & stats)
1181 {
1182   {
1183     // FMM for J
1184     symmMatrix J;
1185     J.resetSizesAndBlocks(matrix_size_block_info,
1186 				 matrix_size_block_info);
1187     stats.start_timer("compute_J_by_boxes_sparse");
1188     if(compute_J_by_boxes_sparse(basisInfo,
1189 				 integralInfo,
1190 				 J_K_params,
1191 				 J,
1192 				 densityMatrix_sparse,
1193 				 permutationHML) != 0)
1194       {
1195 	do_output(LOG_CAT_ERROR, LOG_AREA_SCF, "error in compute_J_by_boxes_sparse");
1196 	return -1;
1197       }
1198     stats.stop_timer("compute_J_by_boxes_sparse");
1199     twoelMatrix_sparse = J;
1200     if ( get_J_K_Fxc_matrices == 1 ) {
1201       do_output(LOG_CAT_INFO, LOG_AREA_SCF, "Saving J matrix as requested.");
1202       J_matrix = J;
1203     }
1204   }
1205 
1206 
1207   if(CAM_params.alpha != 0.0 || CAM_params.computeRangeSeparatedExchange)
1208     {
1209       // exchange matrix K
1210       symmMatrix K;
1211       K.resetSizesAndBlocks(matrix_size_block_info,
1212 				   matrix_size_block_info);
1213       stats.start_timer("compute_K_by_boxes_sparse");
1214       if(compute_K_by_boxes_sparse(basisInfo,
1215 				   integralInfo,
1216 				   CAM_params,
1217 				   J_K_params,
1218 				   K,
1219 				   densityMatrix_sparse,
1220 				   permutationHML,
1221 				   inversePermutationHML) != 0)
1222 	{
1223 	  do_output(LOG_CAT_ERROR, LOG_AREA_SCF, "error in compute_K_by_boxes_sparse");
1224 	  return -1;
1225 	}
1226       stats.stop_timer("compute_K_by_boxes_sparse");
1227       if(!CAM_params.computeRangeSeparatedExchange) {
1228         twoelMatrix_sparse += CAM_params.alpha * K;
1229 	if ( get_J_K_Fxc_matrices == 1 ) {
1230 	  do_output(LOG_CAT_INFO, LOG_AREA_SCF, "Saving K matrix as requested.");
1231 	  K_matrix = CAM_params.alpha * K;
1232 	}
1233       }
1234       else {
1235 	twoelMatrix_sparse += K;
1236 	if ( get_J_K_Fxc_matrices == 1 ) {
1237 	  do_output(LOG_CAT_INFO, LOG_AREA_SCF, "Saving K matrix as requested.");
1238 	  K_matrix = K;
1239 	}
1240       }
1241     }
1242 
1243   *energy_2el = 0.5 * symmMatrix::trace_ab(densityMatrix_sparse, twoelMatrix_sparse);
1244   if(do_xc)
1245     {
1246       ergo_real dftEnergy;
1247       symmMatrix F_xc;
1248       // construct matrix Fxc and xc_energy
1249 
1250       output_current_memory_usage(LOG_AREA_SCF, "before dft_get_xc_mt");
1251 
1252       if(do_xc == 1) {
1253         int n = basisInfo.noOfBasisFuncs;
1254         do_output(LOG_CAT_INFO, LOG_AREA_SCF, "get_2e_matrix_and_energy_simple_sparse (do_xc == 1) allocating full n*n matrix.");
1255         ergo_real* densityMatrix_full = new ergo_real[n*n];
1256 	{
1257 	  std::vector<ergo_real> fullTmp(n*n);
1258 	  densityMatrix_sparse.fullMatrix(fullTmp,
1259 					  inversePermutationHML,
1260 					  inversePermutationHML);
1261 	  std::copy (fullTmp.begin(), fullTmp.end(), densityMatrix_full);
1262 	}
1263 	std::vector<ergo_real> F_xc_full(n*n, 0);
1264 
1265         // dft_get_xc_mt is the call to the basic DFT code
1266         do_output(LOG_CAT_INFO, LOG_AREA_SCF,
1267                   "calling dft_get_xc_mt, n = %i, noOfElectrons = %i",
1268                   n, noOfElectrons);
1269 
1270         dft_get_xc_mt(noOfElectrons, densityMatrix_full,
1271                       &basisInfo, &molecule, gridParams,
1272                       &F_xc_full[0], &dftEnergy);
1273 
1274         output_current_memory_usage(LOG_AREA_SCF, "after  dft_get_xc_mt");
1275         delete []densityMatrix_full;
1276       	F_xc.resetSizesAndBlocks(matrix_size_block_info,
1277 					matrix_size_block_info);
1278 	F_xc.assignFromFull(F_xc_full, permutationHML, permutationHML);
1279       }
1280       else {
1281         do_output(LOG_CAT_INFO, LOG_AREA_SCF,
1282                   "calling sparse Dft::getXC, noOfElectrons = %i",
1283                   noOfElectrons);
1284       	F_xc.resetSizesAndBlocks(matrix_size_block_info,
1285 					matrix_size_block_info);
1286 
1287 	/* FIXME: what does the comment below mean??  */
1288         /* Threaded version gathers data in a thread-unsafe way. */
1289 
1290 	stats.start_timer("getXC_mt");
1291         Dft::getXC_mt(basisInfo, integralInfo,
1292                       molecule, gridParams, noOfElectrons,
1293                       densityMatrix_sparse, F_xc, &dftEnergy,
1294 		      permutationHML);
1295 	stats.stop_timer("getXC_mt");
1296 
1297         output_current_memory_usage(LOG_AREA_SCF, "after  dft_get_xc_mt");
1298       }
1299       twoelMatrix_sparse += F_xc;
1300       if ( get_J_K_Fxc_matrices == 1 ) {
1301 	do_output(LOG_CAT_INFO, LOG_AREA_SCF, "Saving Fxc matrix as requested.");
1302 	Fxc_matrix = F_xc;
1303       }
1304       *energy_2el += dftEnergy;
1305     }
1306 
1307   return 0;
1308 }
1309 
1310 
1311 
1312 
1313 
1314 
1315 static int
get_2e_matrices_and_energy_simple_sparse_unrestricted(const BasisInfoStruct & basisInfo,const Molecule & molecule,const IntegralInfo & integralInfo,const JK::ExchWeights & CAM_params,symmMatrix & twoelMatrix_sparse_alpha,symmMatrix & twoelMatrix_sparse_beta,symmMatrix & densityMatrix_sparse_alpha,symmMatrix & densityMatrix_sparse_beta,const JK::Params & J_K_params,const Dft::GridParams & gridParams,mat::SizesAndBlocks const & matrix_size_block_info,std::vector<int> const & permutationHML,std::vector<int> const & inversePermutationHML,ergo_real * energy_2el,int do_xc,int noOfElectrons)1316 get_2e_matrices_and_energy_simple_sparse_unrestricted(const BasisInfoStruct& basisInfo,
1317                                        const Molecule& molecule,
1318                                        const IntegralInfo& integralInfo,
1319 				       const JK::ExchWeights & CAM_params,
1320                                        symmMatrix & twoelMatrix_sparse_alpha,
1321                                        symmMatrix & twoelMatrix_sparse_beta,
1322                                        symmMatrix & densityMatrix_sparse_alpha,
1323                                        symmMatrix & densityMatrix_sparse_beta,
1324                                        const JK::Params& J_K_params,
1325 				       const Dft::GridParams& gridParams,
1326                                        mat::SizesAndBlocks const & matrix_size_block_info,
1327 				       std::vector<int> const & permutationHML,
1328 				       std::vector<int> const & inversePermutationHML,
1329                                        ergo_real* energy_2el,
1330                                        int do_xc,
1331                                        int noOfElectrons)
1332 {
1333   symmMatrix J;
1334   J.resetSizesAndBlocks(matrix_size_block_info,
1335 			matrix_size_block_info);
1336   // Compute total density matrix
1337   symmMatrix D_tot(densityMatrix_sparse_alpha);
1338   D_tot += densityMatrix_sparse_beta;
1339 
1340   // FMM for J
1341   if(compute_J_by_boxes_sparse(basisInfo,
1342 			       integralInfo,
1343 			       J_K_params,
1344 			       J,
1345 			       D_tot,
1346 			       permutationHML) != 0)
1347     {
1348       do_output(LOG_CAT_ERROR, LOG_AREA_SCF, "error in compute_J_by_boxes_sparse");
1349       return -1;
1350     }
1351   twoelMatrix_sparse_alpha = J;
1352   twoelMatrix_sparse_beta = J;
1353   J.clear();
1354 
1355   if(CAM_params.alpha != 0 || CAM_params.computeRangeSeparatedExchange)
1356     {
1357       D_tot *= ergo_real(0.5);
1358       symmMatrix D_spin(ergo_real(0.5)*densityMatrix_sparse_alpha);
1359       D_spin -= ergo_real(0.5)*densityMatrix_sparse_beta;
1360 
1361       /* Multiply by alpha only if no range-separated exchange is computed.
1362 	 It CAM params are used the hf weight has already been accounted for. */
1363       ergo_real real_hf_weight = (CAM_params.computeRangeSeparatedExchange == 0)
1364 	? CAM_params.alpha * 2.0 : 2.0;
1365       symmMatrix K_tot, K_spin;
1366       K_tot.resetSizesAndBlocks(matrix_size_block_info,
1367 				matrix_size_block_info);
1368       K_spin.resetSizesAndBlocks(matrix_size_block_info,
1369 				 matrix_size_block_info);
1370 
1371       // exchange matrices
1372       if(compute_K_by_boxes_sparse(basisInfo,
1373 				   integralInfo,
1374 				   CAM_params,
1375 				   J_K_params,
1376 				   K_tot,
1377 				   D_tot,
1378 				   permutationHML,
1379 				   inversePermutationHML) != 0)
1380 	{
1381 	  do_output(LOG_CAT_ERROR, LOG_AREA_SCF, "error in compute_K_by_boxes_sparse");
1382 	  return -1;
1383 	}
1384       twoelMatrix_sparse_alpha += real_hf_weight * K_tot;
1385       twoelMatrix_sparse_beta  += real_hf_weight * K_tot;
1386       K_tot.clear();
1387 
1388       if(compute_K_by_boxes_sparse(basisInfo,
1389 				   integralInfo,
1390 				   CAM_params,
1391 				   J_K_params,
1392 				   K_spin,
1393 				   D_spin,
1394 				   permutationHML,
1395 				   inversePermutationHML) != 0)
1396 	{
1397 	  do_output(LOG_CAT_ERROR, LOG_AREA_SCF, "error in compute_K_by_boxes_sparse");
1398 	  return -1;
1399 	}
1400 
1401       twoelMatrix_sparse_alpha += real_hf_weight * K_spin;
1402       twoelMatrix_sparse_beta  -= real_hf_weight * K_spin;
1403     }
1404   D_tot.clear();
1405 
1406   *energy_2el = 0;
1407   *energy_2el +=  0.5 * symmMatrix::trace_ab(densityMatrix_sparse_alpha, twoelMatrix_sparse_alpha);
1408   *energy_2el +=  0.5 * symmMatrix::trace_ab(densityMatrix_sparse_beta , twoelMatrix_sparse_beta );
1409 
1410   if(do_xc == 1)
1411     {
1412       ergo_real dftEnergy;
1413       int n = basisInfo.noOfBasisFuncs;
1414       do_output(LOG_CAT_INFO, LOG_AREA_SCF, "get_2e_matrices_and_energy_simple_sparse_unrestricted allocating full n*n matrices.");
1415       std::vector<ergo_real> xcMatrix_full_alpha(n*n,0);
1416       std::vector<ergo_real> xcMatrix_full_beta (n*n,0);
1417       std::vector<ergo_real> densityMatrix_full_alpha(n*n);
1418       std::vector<ergo_real> densityMatrix_full_beta (n*n);
1419       densityMatrix_sparse_alpha.fullMatrix(densityMatrix_full_alpha,
1420 					    inversePermutationHML,
1421 					    inversePermutationHML);
1422       densityMatrix_sparse_beta .fullMatrix(densityMatrix_full_beta,
1423 					    inversePermutationHML,
1424 					    inversePermutationHML);
1425 
1426       do_output(LOG_CAT_INFO, LOG_AREA_SCF, "calling dft_get_uxc_mt, n = %i", n);
1427 
1428 
1429 #ifndef SKIP_DFT_FLAG
1430       dft_get_uxc_mt(noOfElectrons,
1431                      &densityMatrix_full_alpha[0], &densityMatrix_full_beta[0],
1432 		     &basisInfo, &molecule, gridParams,
1433 		     &xcMatrix_full_alpha[0], &xcMatrix_full_beta[0], &dftEnergy);
1434 #endif
1435 
1436       densityMatrix_full_alpha.reserve(0);
1437       densityMatrix_full_beta.reserve(0);
1438 
1439       *energy_2el += dftEnergy;
1440 
1441       output_current_memory_usage(LOG_AREA_SCF, "after dft_get_uxc_mt");
1442 
1443       symmMatrix tmp;
1444       tmp.resetSizesAndBlocks(matrix_size_block_info,
1445 				     matrix_size_block_info);
1446       tmp.assignFromFull(xcMatrix_full_alpha,
1447 			 permutationHML,
1448 			 permutationHML);
1449       twoelMatrix_sparse_alpha += tmp;
1450       tmp.assignFromFull(xcMatrix_full_beta,
1451 			 permutationHML,
1452 			 permutationHML);
1453       twoelMatrix_sparse_beta  += tmp;
1454 
1455     }
1456   else
1457     {
1458       ergo_real dftEnergy = 0;
1459       symmMatrix FA_xc, FB_xc;
1460       do_output(LOG_CAT_INFO, LOG_AREA_SCF,
1461                 "calling sparse Dft::getUXC, noOfElectrons = %i",
1462                 noOfElectrons);
1463       FA_xc.resetSizesAndBlocks(matrix_size_block_info,
1464                                 matrix_size_block_info);
1465       FB_xc.resetSizesAndBlocks(matrix_size_block_info,
1466                                 matrix_size_block_info);
1467 
1468       /* FIXME: what does the comment below mean??  */
1469       /* Threaded version gathers data in a thread-unsafe way. */
1470 
1471       Dft::getUXC_seq(basisInfo, integralInfo,
1472                      molecule, gridParams, noOfElectrons,
1473                      densityMatrix_sparse_alpha, densityMatrix_sparse_beta,
1474                      FA_xc, FB_xc, &dftEnergy,
1475                      permutationHML);
1476 
1477       output_current_memory_usage(LOG_AREA_SCF, "after  dft_get_xc_mt");
1478       twoelMatrix_sparse_alpha += FA_xc;
1479       twoelMatrix_sparse_beta += FB_xc;
1480       *energy_2el += dftEnergy;
1481     }
1482 
1483   return 0;
1484 }
1485 
1486 
1487 
1488 /**
1489 General routine for computing the two-electron part of the Fock/KS
1490 matrix.  Both input and output matrices are in sparse form, but full
1491 matrix form may be used in intermediate steps. If FMM is not used,
1492 full matrix format is applied.
1493 
1494 @param basisInfo the used basis set.
1495 @param molecule position of atoms (used for eg. XC grid).
1496 @param integralInfo - the integral evaluation object.
1497 @param twoelMatrix_sparse - the evaluation result.
1498 
1499 @param densityMatrix_sparse - the density for which 2e matrix is to be
1500 evaluated.
1501 
1502 @param J_K_params the settings of the integral evaluation.
1503 
1504 @param do_xc whether xc contribution to 2e matrix and energy are to be
1505 added. 1 means that the traditional full matrix code should be called,
1506 2 means that the sparse variant is to be used.
1507 
1508 @param energy_2el 2el energy contribution
1509 
1510 @param noOfElectrons number of electrons...
1511 
1512 @param CAM_params a structure containing parameters needed when functionals like CAMB3LYP are used.
1513 @param gridParams a structure containing parameters for the grid.
1514 @param matrix_size_block_info block sizes etc for hierarchic matrix library.
1515 
1516 @param get_J_K_Fxc_matrices flag saying if matrices should be saved for statistics/testing purposes.
1517 If that feature is active, matrices are saved in parameters J_matrix K_matrix Fxc_matrix .
1518 
1519 @param J_matrix resulting J matrix, if requested.
1520 @param K_matrix resulting K matrix, if requested.
1521 @param Fxc_matrix resulting Fxc matrix, if requested.
1522 
1523 @param stats a structure holding SCF statistics.
1524 
1525 @param permutationHML - the permutation of basis functions, needed
1526 for transformation between the dense and sparse formats.
1527 @param inversePermutationHML - the inverse permutation of basis functions, needed
1528 for transformation between the dense and sparse formats.
1529 */
1530 int
get_2e_matrix_and_energy_sparse(const BasisInfoStruct & basisInfo,const Molecule & molecule,const IntegralInfo & integralInfo,symmMatrix & twoelMatrix_sparse,symmMatrix & densityMatrix_sparse,const JK::Params & J_K_params,const JK::ExchWeights & CAM_params,const Dft::GridParams & gridParams,int do_xc,ergo_real * energy_2el,int noOfElectrons,mat::SizesAndBlocks const & matrix_size_block_info,std::vector<int> const & permutationHML,std::vector<int> const & inversePermutationHML,int get_J_K_Fxc_matrices,symmMatrix & J_matrix,symmMatrix & K_matrix,symmMatrix & Fxc_matrix,SCF_statistics & stats)1531 get_2e_matrix_and_energy_sparse(const BasisInfoStruct & basisInfo,
1532 				const Molecule& molecule,
1533 				const IntegralInfo& integralInfo,
1534 				symmMatrix & twoelMatrix_sparse,
1535 				symmMatrix & densityMatrix_sparse,
1536 				const JK::Params& J_K_params,
1537 				const JK::ExchWeights & CAM_params,
1538 				const Dft::GridParams& gridParams,
1539 				int do_xc,
1540 				ergo_real* energy_2el,
1541 				int noOfElectrons,
1542 				mat::SizesAndBlocks const & matrix_size_block_info,
1543 				std::vector<int> const & permutationHML,
1544 				std::vector<int> const & inversePermutationHML,
1545 				int get_J_K_Fxc_matrices,
1546 				symmMatrix & J_matrix,
1547 				symmMatrix & K_matrix,
1548 				symmMatrix & Fxc_matrix,
1549 				SCF_statistics & stats)
1550 {
1551   if(J_K_params.use_naive_fockmat_constr == 1)
1552     {
1553       int n = basisInfo.noOfBasisFuncs;
1554       do_output(LOG_CAT_INFO, LOG_AREA_SCF, "get_2e_matrix_and_energy_sparse naive impl allocating full n*n matrices.");
1555       ergo_real* twoelMatrixG      = new ergo_real[n*n];
1556       ergo_real* densityMatrixFull = new ergo_real[n*n];
1557       {
1558 	std::vector<ergo_real> fullTmp(n*n);
1559 	densityMatrix_sparse.fullMatrix(fullTmp,
1560 					inversePermutationHML,
1561 					inversePermutationHML);
1562 	std::copy (fullTmp.begin(), fullTmp.end(), densityMatrixFull);
1563       }
1564       // Use smallest of threshold_J and threshold_K.
1565       ergo_real threshold_JK = J_K_params.threshold_J;
1566       if(J_K_params.threshold_K < threshold_JK)
1567 	threshold_JK = J_K_params.threshold_K;
1568       if(compute_2e_matrix_list_explicit(basisInfo, integralInfo, &twoelMatrixG, &densityMatrixFull, 1, threshold_JK) != 0)
1569 	{
1570 	  do_output(LOG_CAT_ERROR, LOG_AREA_SCF, "error in compute_2e_matrix_list_explicit");
1571 	  return -1;
1572 	}
1573       *energy_2el = get_trace(n, densityMatrixFull, twoelMatrixG)*0.5;
1574       {
1575 	std::vector<ergo_real> fullTmp(twoelMatrixG, twoelMatrixG + n*n);
1576 	twoelMatrix_sparse.assignFromFull(fullTmp,
1577 					  permutationHML,
1578 					  permutationHML);
1579       }
1580       delete []twoelMatrixG;
1581       delete []densityMatrixFull;
1582       return 0;
1583     }
1584 
1585   if(do_xc == 0 && J_K_params.use_fmm == 1)
1586     {
1587       // Simple Hartree-Fock case, with FMM.
1588       // In this case we use a special function to get away with less memory usage.
1589       if(get_2e_matrix_and_energy_simple_HF_sparse(basisInfo,
1590 						   molecule,
1591 						   integralInfo,
1592 						   CAM_params,
1593 						   twoelMatrix_sparse,
1594 						   densityMatrix_sparse,
1595 						   J_K_params,
1596 						   matrix_size_block_info,
1597 						   permutationHML,
1598 						   inversePermutationHML,
1599 						   energy_2el,
1600 						   get_J_K_Fxc_matrices,
1601 						   J_matrix,
1602 						   K_matrix) != 0)
1603 	{
1604 	  do_output(LOG_CAT_ERROR, LOG_AREA_SCF, "error in get_2e_matrix_and_energy_simple_HF_sparse");
1605 	  return -1;
1606 	}
1607       return 0;
1608     }
1609 
1610   if(J_K_params.use_fmm == 1 || CAM_params.computeRangeSeparatedExchange)
1611     {
1612       // Simple case, with FMM.
1613       if(get_2e_matrix_and_energy_simple_sparse(basisInfo,
1614 						molecule,
1615 						integralInfo,
1616 						twoelMatrix_sparse,
1617 						densityMatrix_sparse,
1618 						J_K_params,
1619 						CAM_params,
1620 						gridParams,
1621 						matrix_size_block_info,
1622 						permutationHML,
1623 						inversePermutationHML,
1624 						energy_2el,
1625 						do_xc,
1626 						noOfElectrons,
1627 						get_J_K_Fxc_matrices,
1628 						J_matrix,
1629 						K_matrix,
1630 						Fxc_matrix,
1631 						stats) != 0)
1632 	{
1633 	  do_output(LOG_CAT_ERROR, LOG_AREA_SCF, "error in get_2e_matrix_and_energy_simple_sparse");
1634 	  return -1;
1635 	}
1636       return 0;
1637     }
1638 
1639   int n = basisInfo.noOfBasisFuncs;
1640   do_output(LOG_CAT_INFO, LOG_AREA_SCF, "get_2e_matrix_and_energy_sparse allocating full n*n matrices.");
1641   ergo_real* twoelMatrix_full   = new ergo_real[n*n];
1642   ergo_real* densityMatrix_full = new ergo_real[n*n];
1643   {
1644     std::vector<ergo_real> fullTmp(n*n);
1645     densityMatrix_sparse.fullMatrix(fullTmp,
1646 				    inversePermutationHML,
1647 				    inversePermutationHML);
1648     std::copy (fullTmp.begin(), fullTmp.end(), densityMatrix_full);
1649   }
1650   {
1651     // Get J
1652     if(compute_2e_matrix_coulomb(basisInfo,
1653 				 integralInfo,
1654 				 twoelMatrix_full,
1655 				 densityMatrix_full,
1656 				 J_K_params) != 0)
1657       {
1658 	do_output(LOG_CAT_ERROR, LOG_AREA_SCF, "error in compute_2e_matrix_coulomb");
1659 	return -1;
1660       }
1661     if(CAM_params.alpha != ergo_real(0.0) || CAM_params.computeRangeSeparatedExchange)
1662       {
1663 	ergo_real* K   = new ergo_real[n*n];
1664 	// Get K
1665 	if(compute_2e_matrix_exchange(basisInfo,
1666 				      integralInfo,
1667 				      CAM_params,
1668 				      K,
1669 				      densityMatrix_full,
1670 				      J_K_params.threshold_K) != 0)
1671 	  {
1672 	    do_output(LOG_CAT_ERROR, LOG_AREA_SCF, "error in compute_2e_matrix_exchange");
1673 	    return -1;
1674 	  }
1675 	add_square_matrices(n, twoelMatrix_full, K, twoelMatrix_full);
1676 	delete []K;
1677       }
1678   }
1679 
1680   *energy_2el = get_trace(n, densityMatrix_full, twoelMatrix_full)*0.5;
1681 
1682   if(do_xc)
1683     {
1684       ergo_real dftEnergy;
1685       // construct matrix Fxc and xc_energy
1686       do_output(LOG_CAT_INFO, LOG_AREA_SCF, "calling dft_get_xc_mt, n = %i, noOfElectrons = %i",
1687 		n, noOfElectrons);
1688 
1689       output_current_memory_usage(LOG_AREA_SCF, "before dft_get_xc_mt");
1690 
1691       // call dft_get_xc_mt. The resulting F_xc matrix is added to the existing twoelMatrix.
1692 
1693 
1694 #ifndef SKIP_DFT_FLAG
1695       dft_get_xc_mt(noOfElectrons, densityMatrix_full,
1696                     &basisInfo, &molecule, gridParams,
1697 		    twoelMatrix_full, &dftEnergy);
1698 #endif
1699 
1700 
1701       output_current_memory_usage(LOG_AREA_SCF, "after  dft_get_xc_mt");
1702 
1703       *energy_2el += dftEnergy;
1704     }
1705 
1706   {
1707     std::vector<ergo_real> fullTmp(twoelMatrix_full, twoelMatrix_full + n*n);
1708     twoelMatrix_sparse.assignFromFull(fullTmp,
1709 				      permutationHML,
1710 				      permutationHML);
1711   }
1712   delete [] twoelMatrix_full;
1713   delete [] densityMatrix_full;
1714 
1715   return 0;
1716 }
1717 
1718 
1719 
1720 int
get_2e_matrices_and_energy_sparse_unrestricted(const BasisInfoStruct & basisInfo,const Molecule & molecule,const IntegralInfo & integralInfo,const JK::ExchWeights & CAM_params,symmMatrix & twoelMatrix_sparse_alpha,symmMatrix & twoelMatrix_sparse_beta,symmMatrix & densityMatrix_sparse_alpha,symmMatrix & densityMatrix_sparse_beta,const JK::Params & J_K_params,const Dft::GridParams & gridParams,int do_xc,ergo_real * energy_2el,int noOfElectrons,mat::SizesAndBlocks const & matrix_size_block_info,std::vector<int> const & permutationHML,std::vector<int> const & inversePermutationHML)1721 get_2e_matrices_and_energy_sparse_unrestricted(const BasisInfoStruct & basisInfo,
1722 					       const Molecule& molecule,
1723 					       const IntegralInfo& integralInfo,
1724 					       const JK::ExchWeights & CAM_params,
1725 					       symmMatrix & twoelMatrix_sparse_alpha,
1726 					       symmMatrix & twoelMatrix_sparse_beta,
1727 					       symmMatrix & densityMatrix_sparse_alpha,
1728 					       symmMatrix & densityMatrix_sparse_beta,
1729 					       const JK::Params& J_K_params,
1730 					       const Dft::GridParams& gridParams,
1731 					       int do_xc,
1732 					       ergo_real* energy_2el,
1733 					       int noOfElectrons,
1734 					       mat::SizesAndBlocks const & matrix_size_block_info,
1735 					       std::vector<int> const & permutationHML,
1736 					       std::vector<int> const & inversePermutationHML)
1737 {
1738   if(J_K_params.use_naive_fockmat_constr == 1)
1739     {
1740       do_output(LOG_CAT_ERROR, LOG_AREA_SCF, "error: use_naive_fockmat_constr not implemented for unrestricted case.");
1741       return -1;
1742     }
1743 
1744   if(do_xc == 0 && J_K_params.use_fmm == 1)
1745     {
1746       // Simple Hartree-Fock case, with FMM.
1747       // In this case we use a special function to get away with less memory usage.
1748       if(get_2e_matrices_and_energy_simple_HF_sparse_unrestricted(basisInfo,
1749 								  molecule,
1750 								  integralInfo,
1751 								  twoelMatrix_sparse_alpha,
1752 								  twoelMatrix_sparse_beta,
1753 								  densityMatrix_sparse_alpha,
1754 								  densityMatrix_sparse_beta,
1755 								  J_K_params,
1756 								  CAM_params,
1757 								  matrix_size_block_info,
1758 								  permutationHML,
1759 								  inversePermutationHML,
1760 								  energy_2el) != 0)
1761 	{
1762 	  do_output(LOG_CAT_ERROR, LOG_AREA_SCF, "error in get_2e_matrices_and_energy_simple_HF_sparse_unrestricted");
1763 	  return -1;
1764 	}
1765       return 0;
1766     }
1767   if(J_K_params.use_fmm == 1 || CAM_params.computeRangeSeparatedExchange)
1768     {
1769       // Simple case, with FMM.
1770       if(get_2e_matrices_and_energy_simple_sparse_unrestricted(basisInfo,
1771 						               molecule,
1772 						               integralInfo,
1773 							       CAM_params,
1774 						twoelMatrix_sparse_alpha,
1775                                                 twoelMatrix_sparse_beta,
1776 						densityMatrix_sparse_alpha,
1777                                                 densityMatrix_sparse_beta,
1778 						J_K_params,
1779 					        gridParams,
1780 						matrix_size_block_info,
1781 						permutationHML,
1782 						inversePermutationHML,
1783 						energy_2el,
1784 						do_xc,
1785 						noOfElectrons) != 0)
1786 	{
1787 	  do_output(LOG_CAT_ERROR, LOG_AREA_SCF, "error in get_2e_matrices_and_energy_simple_sparse_unrestricted");
1788 	  return -1;
1789 	}
1790       return 0;
1791     }
1792 
1793   int n = basisInfo.noOfBasisFuncs;
1794   do_output(LOG_CAT_INFO, LOG_AREA_SCF, "get_2e_matrices_and_energy_sparse_unrestricted allocating full n*n matrices.");
1795   std::vector<ergo_real> twoelMatrix_full_alpha(n*n);
1796   std::vector<ergo_real> twoelMatrix_full_beta(n*n);
1797   std::vector<ergo_real> densityMatrix_full_alpha(n*n);
1798   std::vector<ergo_real> densityMatrix_full_beta(n*n);
1799   {
1800     std::vector<ergo_real> fullTmp(n*n);
1801     densityMatrix_sparse_alpha.fullMatrix(fullTmp,
1802 					  inversePermutationHML,
1803 					  inversePermutationHML);
1804     std::copy (fullTmp.begin(), fullTmp.end(), densityMatrix_full_alpha.begin());
1805     densityMatrix_sparse_beta.fullMatrix(fullTmp,
1806 					 inversePermutationHML,
1807 					 inversePermutationHML);
1808     std::copy (fullTmp.begin(), fullTmp.end(), densityMatrix_full_beta.begin());
1809   }
1810 
1811   // get both J and K at the same time
1812   if(J_K_params.use_differential_density == 1)
1813     {
1814       do_output(LOG_CAT_ERROR, LOG_AREA_SCF, "error: use_differential_density not impl for unrestricted case.");
1815       return -1;
1816     }
1817   else
1818     {
1819       if(CAM_params.computeRangeSeparatedExchange)
1820 	{
1821 	  do_output(LOG_CAT_ERROR, LOG_AREA_SCF,
1822 		    "error in get_2e_matrices_and_energy_simple_sparse_unrestricted: "
1823 		    "cannot use compute_JK_single_box when CAM params are used.");
1824 	  return -1;
1825 	}
1826 
1827       // Get both J and K at once
1828       ergo_real* J_list[2];
1829       ergo_real* K_list[2];
1830       J_list[0] = new ergo_real[n*n];
1831       J_list[1] = new ergo_real[n*n];
1832       K_list[0] = new ergo_real[n*n];
1833       K_list[1] = new ergo_real[n*n];
1834       ergo_real* D_list[2];
1835       D_list[0] = &densityMatrix_full_alpha[0];
1836       D_list[1] = &densityMatrix_full_beta[0];
1837 
1838       // Use smallest of threshold_J and threshold_K.
1839       ergo_real threshold_JK = J_K_params.threshold_J;
1840       if(J_K_params.threshold_K < threshold_JK)
1841 	threshold_JK = J_K_params.threshold_K;
1842 
1843       if(compute_JK_single_box(basisInfo,
1844 			       integralInfo,
1845 			       J_list[0],
1846 			       K_list[0],
1847 			       D_list[0],
1848 			       threshold_JK) != 0)
1849 	{
1850 	  do_output(LOG_CAT_ERROR, LOG_AREA_SCF, "error in compute_JK_single_box");
1851 	  return -1;
1852 	}
1853       if(compute_JK_single_box(basisInfo,
1854 			       integralInfo,
1855 			       J_list[1],
1856 			       K_list[1],
1857 			       D_list[1],
1858 			       threshold_JK) != 0)
1859 	{
1860 	  do_output(LOG_CAT_ERROR, LOG_AREA_SCF, "error in compute_JK_single_box");
1861 	  return -1;
1862 	}
1863 
1864       ergo_real hf_weight = CAM_params.alpha;
1865       for(int i = 0; i < n*n; i++)
1866 	{
1867 	  twoelMatrix_full_alpha[i] = J_list[0][i] + J_list[1][i] + 2 * K_list[0][i] * hf_weight;
1868 	  twoelMatrix_full_beta [i] = J_list[0][i] + J_list[1][i] + 2 * K_list[1][i] * hf_weight;
1869 	}
1870       delete [] J_list[0];
1871       delete [] J_list[1];
1872       delete [] K_list[0];
1873       delete [] K_list[1];
1874     }
1875 
1876 
1877   *energy_2el = 0;
1878   *energy_2el += 0.5 * get_trace(n, &densityMatrix_full_alpha[0],
1879                                  &twoelMatrix_full_alpha[0]);
1880   *energy_2el += 0.5 * get_trace(n, &densityMatrix_full_beta[0],
1881                                  &twoelMatrix_full_beta[0] );
1882 
1883 
1884   if(do_xc)
1885     {
1886       ergo_real dftEnergy = 0;
1887 
1888       std::vector<ergo_real> xcMatrix_full_alpha(n*n);
1889       std::vector<ergo_real> xcMatrix_full_beta(n*n);
1890       memset(&xcMatrix_full_alpha[0], 0, n*n*sizeof(ergo_real));
1891       memset(&xcMatrix_full_beta[0] , 0, n*n*sizeof(ergo_real));
1892 
1893       /* construct xc matrices and xc_energy. */
1894       do_output(LOG_CAT_INFO, LOG_AREA_SCF, "calling dft_get_uxc, n = %i", n);
1895 
1896 #ifndef SKIP_DFT_FLAG
1897       dft_get_uxc_mt(noOfElectrons,
1898 		     &densityMatrix_full_alpha[0], &densityMatrix_full_beta[0],
1899                      &basisInfo, &molecule, gridParams,
1900 		     &xcMatrix_full_alpha[0], &xcMatrix_full_beta[0],
1901                      &dftEnergy);
1902 #endif
1903 
1904       *energy_2el += dftEnergy;
1905 
1906       output_current_memory_usage(LOG_AREA_SCF, "after dft_get_uxc_mt");
1907 
1908       for(int i = 0; i < n*n; i++)
1909         {
1910           twoelMatrix_full_alpha[i] += xcMatrix_full_alpha[i];
1911           twoelMatrix_full_beta [i] += xcMatrix_full_beta [i];
1912         }
1913     }
1914   twoelMatrix_sparse_alpha.assignFromFull(twoelMatrix_full_alpha,
1915                                           permutationHML,
1916                                           permutationHML);
1917   twoelMatrix_sparse_beta.assignFromFull(twoelMatrix_full_beta,
1918                                          permutationHML,
1919                                          permutationHML);
1920 
1921   return 0;
1922 }
1923 
1924 /** Computes  G_c and G_o.
1925     G_c is defined as J_a + J_b + K_a + K_b.
1926     G_o is defined as J_a + J_b + K_a.
1927 */
1928 int
get_2e_matrices_and_energy_restricted_open(const BasisInfoStruct & basisInfo,const Molecule & molecule,const IntegralInfo & integralInfo,const JK::ExchWeights & CAM_params,symmMatrix & twoelMatrix_Fc,symmMatrix & twoelMatrix_Fo,symmMatrix & densityMatrix_sparse_alpha,symmMatrix & densityMatrix_sparse_beta,const JK::Params & J_K_params,const Dft::GridParams & gridParams,int do_xc,ergo_real * energy_2el,int noOfElectrons,mat::SizesAndBlocks const & matrix_size_block_info,std::vector<int> const & permutationHML,std::vector<int> const & inversePermutationHML)1929 get_2e_matrices_and_energy_restricted_open(const BasisInfoStruct & basisInfo,
1930 					   const Molecule& molecule,
1931 					   const IntegralInfo& integralInfo,
1932 					   const JK::ExchWeights & CAM_params,
1933 					   symmMatrix & twoelMatrix_Fc,
1934 					   symmMatrix & twoelMatrix_Fo,
1935 					   symmMatrix & densityMatrix_sparse_alpha,
1936 					   symmMatrix & densityMatrix_sparse_beta,
1937 					   const JK::Params& J_K_params,
1938 					   const Dft::GridParams& gridParams,
1939 					   int do_xc,
1940 					   ergo_real* energy_2el,
1941 					   int noOfElectrons,
1942 					   mat::SizesAndBlocks const & matrix_size_block_info,
1943 					   std::vector<int> const & permutationHML,
1944 					   std::vector<int> const & inversePermutationHML)
1945 {
1946   if(J_K_params.use_naive_fockmat_constr)
1947     {
1948       do_output(LOG_CAT_ERROR, LOG_AREA_SCF,
1949 		"error: use_naive_fockmat_constr not implemented for unrestricted case.");
1950       return -1;
1951     }
1952 
1953   symmMatrix J_tot, K_alpha, K_beta;
1954   J_tot.resetSizesAndBlocks(matrix_size_block_info,
1955 				   matrix_size_block_info);
1956   K_alpha.resetSizesAndBlocks(matrix_size_block_info,
1957 				     matrix_size_block_info);
1958   K_beta.resetSizesAndBlocks(matrix_size_block_info,
1959 				    matrix_size_block_info);
1960 
1961   // Compute total density matrix
1962   symmMatrix D_tot(densityMatrix_sparse_alpha);
1963   D_tot += densityMatrix_sparse_beta;
1964 
1965   // FMM for J
1966   if(compute_J_by_boxes_sparse(basisInfo,
1967 			       integralInfo,
1968 			       J_K_params,
1969 			       J_tot,
1970 			       D_tot,
1971 			       permutationHML) != 0)
1972     {
1973       do_output(LOG_CAT_ERROR, LOG_AREA_SCF, "error in compute_J_by_boxes_sparse");
1974       return -1;
1975     }
1976   D_tot.clear();
1977 
1978   if(CAM_params.alpha != ergo_real(0) ||
1979      CAM_params.computeRangeSeparatedExchange ) {
1980     // exchange matrices
1981     if(compute_K_by_boxes_sparse(basisInfo,
1982                                  integralInfo,
1983                                  CAM_params,
1984                                  J_K_params,
1985                                  K_alpha,
1986                                  densityMatrix_sparse_alpha,
1987 				 permutationHML,
1988 				 inversePermutationHML) != 0)
1989       {
1990         do_output(LOG_CAT_ERROR, LOG_AREA_SCF, "error in compute_K_by_boxes_sparse");
1991         return -1;
1992       }
1993 
1994     if(compute_K_by_boxes_sparse(basisInfo,
1995                                  integralInfo,
1996                                  CAM_params,
1997                                  J_K_params,
1998                                  K_beta,
1999                                  densityMatrix_sparse_beta,
2000 				 permutationHML,
2001 				 inversePermutationHML) != 0)
2002       {
2003         do_output(LOG_CAT_ERROR, LOG_AREA_SCF, "error in compute_K_by_boxes_sparse");
2004         return -1;
2005       }
2006     ergo_real hf_weight = CAM_params.computeRangeSeparatedExchange
2007       ? 1.0 : CAM_params.alpha;
2008     K_alpha *= hf_weight*2.0;
2009     K_beta  *= hf_weight*2.0;
2010   }
2011 
2012   *energy_2el = 0;
2013   *energy_2el +=  0.5 * symmMatrix::trace_ab(densityMatrix_sparse_alpha, J_tot);
2014   *energy_2el +=  0.5 * symmMatrix::trace_ab(densityMatrix_sparse_alpha, K_alpha);
2015   *energy_2el +=  0.5 * symmMatrix::trace_ab(densityMatrix_sparse_beta, J_tot);
2016   *energy_2el +=  0.5 * symmMatrix::trace_ab(densityMatrix_sparse_beta, K_beta);
2017   twoelMatrix_Fc  = J_tot;
2018   twoelMatrix_Fc += ergo_real(0.5)*K_alpha;
2019   twoelMatrix_Fc += ergo_real(0.5)*K_beta;
2020   twoelMatrix_Fo  = J_tot;
2021   twoelMatrix_Fo += K_alpha;
2022 
2023   J_tot.clear(); K_alpha.clear(); K_beta.clear();
2024 
2025   if(do_xc)
2026     {
2027       int n = basisInfo.noOfBasisFuncs;
2028       ergo_real dftEnergy = 0;
2029 
2030       std::vector<ergo_real> density_full_alpha(n*n);
2031       std::vector<ergo_real> density_full_beta(n*n);
2032       densityMatrix_sparse_alpha.fullMatrix(density_full_alpha,
2033 					    inversePermutationHML,
2034 					    inversePermutationHML);
2035       densityMatrix_sparse_beta.fullMatrix(density_full_beta,
2036 					    inversePermutationHML,
2037 					    inversePermutationHML);
2038 
2039       std::vector<ergo_real> xcMatrix_full_alpha(n*n,0);
2040       std::vector<ergo_real> xcMatrix_full_beta (n*n,0);
2041 
2042       /* construct xc matrices and xc_energy. */
2043       do_output(LOG_CAT_INFO, LOG_AREA_SCF, "calling dft_get_uxc, n = %i", n);
2044 
2045 #ifndef SKIP_DFT_FLAG
2046       dft_get_uxc_mt(noOfElectrons,
2047 		     &density_full_alpha[0], &density_full_beta[0],
2048                      &basisInfo, &molecule, gridParams,
2049 		     &xcMatrix_full_alpha[0], &xcMatrix_full_beta[0], &dftEnergy);
2050 #endif
2051 
2052       *energy_2el += dftEnergy;
2053 
2054       output_current_memory_usage(LOG_AREA_SCF, "after dft_get_uxc_mt");
2055       symmMatrix xcSparse_alpha, xcSparse_beta;
2056       xcSparse_alpha.resetSizesAndBlocks(matrix_size_block_info,
2057 						matrix_size_block_info);
2058       xcSparse_beta.resetSizesAndBlocks(matrix_size_block_info,
2059 					       matrix_size_block_info);
2060 
2061       xcSparse_alpha.assignFromFull(xcMatrix_full_alpha,
2062 				    permutationHML, permutationHML);
2063       xcSparse_beta.assignFromFull(xcMatrix_full_beta,
2064 				   permutationHML, permutationHML);
2065 
2066       twoelMatrix_Fc += ergo_real(0.5)*xcSparse_alpha;
2067       twoelMatrix_Fc += ergo_real(0.5)*xcSparse_beta;
2068 
2069       twoelMatrix_Fo += xcSparse_alpha;
2070     }
2071 
2072 
2073 
2074   return 0;
2075 }
2076 
2077 
2078 
2079 
2080 
2081 
2082 
2083 int
compute_FDSminusSDF_sparse(int n,symmMatrix & F_symm,symmMatrix & D_symm,symmMatrix & S_symm,normalMatrix & result,ergo_real sparse_threshold)2084 compute_FDSminusSDF_sparse(int n,
2085 			   symmMatrix & F_symm,
2086 			   symmMatrix & D_symm,
2087 			   symmMatrix & S_symm,
2088 			   normalMatrix & result,
2089 			   ergo_real sparse_threshold)
2090 {
2091   // FIXME: we should be able to do this without so many temporary objects.
2092   // We should probably use something like FDS-SDF = FDS - (FDS)^T
2093   // FIXME: Implement eucl_thresh() for general matrices.
2094 
2095   Util::TimeMeter timeMeter;
2096 
2097   do_output(LOG_CAT_INFO, LOG_AREA_DENSFROMF, "compute_FDSminusSDF_sparse() start.");
2098   Util::TimeMeter timeMeterWriteAndReadAll;
2099   std::string sizesStr = mat::FileWritable::writeAndReadAll();
2100   timeMeterWriteAndReadAll.print(LOG_AREA_DENSFROMF, "FileWritable::writeAndReadAll");
2101   do_output(LOG_CAT_INFO, LOG_AREA_DENSFROMF, ((std::string)"writeAndReadAll: '" + sizesStr).c_str());
2102 
2103   normalMatrix S(S_symm);
2104   normalMatrix FD;
2105   normalMatrix DF;
2106 
2107   S_symm.writeToFile();
2108   S.writeToFile();
2109 
2110 
2111   output_current_memory_usage(LOG_AREA_SCF, "compute_FDSminusSDF_sparse before computing FD (symm-symm multiply)");
2112 
2113   Util::TimeMeter timeMeterFD;
2114 
2115   mat::SingletonForTimings::instance().reset();
2116 
2117   FD  = (ergo_real)1.0 * F_symm * D_symm;
2118 
2119 #ifdef MAT_USE_ALLOC_TIMER
2120   do_output(LOG_CAT_INFO, LOG_AREA_SCF, "compute_FDSminusSDF_sparse, F*D mult mat alloc time: %15.5f seconds",
2121 	    mat::SingletonForTimings::instance().getAccumulatedTime());
2122 #endif
2123 
2124   timeMeterFD.print(LOG_AREA_SCF, "compute_FDSminusSDF_sparse, F*D mult");
2125 
2126   output_current_memory_usage(LOG_AREA_SCF,
2127 			      "compute_FDSminusSDF_sparse after computing FD");
2128 
2129   output_sparsity(n, FD, "FD before eucl truncation");
2130   FD.eucl_thresh(sparse_threshold);
2131   output_sparsity(n, FD, "FD after  eucl truncation");
2132 
2133   F_symm.writeToFile();
2134   D_symm.writeToFile();
2135 
2136   S.readFromFile();
2137 
2138   result = (ergo_real)1.0 * FD * S; // result now contains FDS
2139 
2140   output_current_memory_usage(LOG_AREA_SCF,
2141 			      "compute_FDSminusSDF_sparse "
2142 			      "after computing FDS");
2143 
2144   output_sparsity(n, result, "FDS before eucl truncation");
2145   result.eucl_thresh(sparse_threshold);
2146   output_sparsity(n, result, "FDS after  eucl truncation");
2147 
2148   // We no longer need FD, set it to zero and free memory
2149   FD.clear();
2150 
2151   S.writeToFile();
2152   result.writeToFile();
2153 
2154   // Read D before F to reduce problems with memory fragmentation;
2155   // we assume D is more dense than F.
2156   D_symm.readFromFile();
2157   F_symm.readFromFile();
2158 
2159   output_current_memory_usage(LOG_AREA_SCF,
2160 			      "compute_FDSminusSDF_sparse before "
2161 			      "computing DF (symm-symm multiply)");
2162 
2163   DF  = (ergo_real)1.0 * D_symm * F_symm;
2164 
2165   output_current_memory_usage(LOG_AREA_SCF,
2166 			      "compute_FDSminusSDF_sparse after computing DF");
2167 
2168   DF.eucl_thresh(sparse_threshold);
2169 
2170   F_symm.writeToFile();
2171   D_symm.writeToFile();
2172 
2173   result.readFromFile();
2174   S.readFromFile();
2175 
2176   result = (ergo_real)1.0 * S * DF + ((ergo_real)(-1.0) * result);
2177 
2178   output_current_memory_usage(LOG_AREA_SCF,
2179 			      "compute_FDSminusSDF_sparse after "
2180 			      "computing result");
2181 
2182   S.clear();
2183   FD.clear();
2184   DF.clear();
2185 
2186   result.eucl_thresh(sparse_threshold);
2187 
2188   // read input matrices back from file
2189   D_symm.readFromFile();
2190   F_symm.readFromFile();
2191   S_symm.readFromFile();
2192 
2193   do_output(LOG_CAT_INFO, LOG_AREA_SCF, "compute_FDSminusSDF_sparse ending OK.");
2194   timeMeter.print(LOG_AREA_SCF, "compute_FDSminusSDF_sparse");
2195 
2196   return 0;
2197 }
2198 
2199 
2200 int
determine_number_of_electrons_unrestricted(int noOfElectrons,int alpha_beta_diff,int * noOfElectrons_alpha,int * noOfElectrons_beta)2201 determine_number_of_electrons_unrestricted(int noOfElectrons,
2202 					   int alpha_beta_diff,
2203 					   int* noOfElectrons_alpha,
2204 					   int* noOfElectrons_beta)
2205 {
2206   *noOfElectrons_alpha = (noOfElectrons + alpha_beta_diff) / 2;
2207   *noOfElectrons_beta  = noOfElectrons - *noOfElectrons_alpha;
2208   int sum = *noOfElectrons_alpha + *noOfElectrons_beta;
2209   if(sum != noOfElectrons)
2210     {
2211       do_output(LOG_CAT_ERROR, LOG_AREA_SCF, "error: n_alpha + n_beta != N");
2212       return -1;
2213     }
2214   int diff = *noOfElectrons_alpha - *noOfElectrons_beta;
2215   if(diff != alpha_beta_diff)
2216     {
2217       do_output(LOG_CAT_ERROR, LOG_AREA_SCF,
2218 		"error: n_alpha - n_beta != alpha_beta_diff");
2219       return -1;
2220     }
2221   do_output(LOG_CAT_INFO, LOG_AREA_SCF,
2222 	    "noOfElectrons_alpha  noOfElectrons_beta  =  %i %i",
2223 	    *noOfElectrons_alpha, *noOfElectrons_beta);
2224   return 0;
2225 }
2226 
2227 
2228 static void
get_mulliken_charges(const symmMatrix & densityMatrix,const symmMatrix & S_symm,const BasisInfoStruct & basisInfo,mat::SizesAndBlocks const & matrix_size_block_info,std::vector<int> const & permutationHML,std::vector<int> const & inversePermutationHML,const Molecule & molecule,std::vector<ergo_real> & resultVector)2229 get_mulliken_charges(const symmMatrix & densityMatrix,
2230 		     const symmMatrix & S_symm,
2231 		     const BasisInfoStruct & basisInfo,
2232 		     mat::SizesAndBlocks const & matrix_size_block_info,
2233 		     std::vector<int> const & permutationHML,
2234 		     std::vector<int> const & inversePermutationHML,
2235 		     const Molecule& molecule,
2236 		     std::vector<ergo_real> & resultVector)
2237 {
2238   int nAtoms = molecule.getNoOfAtoms();
2239   resultVector.resize(nAtoms);
2240   for(int i = 0; i < nAtoms; i++)
2241     resultVector[i] = 0;
2242   // Create mapping between basis functions and atoms.
2243   int n = basisInfo.noOfBasisFuncs;
2244   std::vector<int> atomMapping(n);
2245   for(int i = 0; i < n; i++) {
2246     // Check if this basis function is near any atom.
2247     int foundAtomIndex = -1;
2248     for(int k = 0; k < nAtoms; k++) {
2249       ergo_real dx = molecule.getAtom(k).coords[0] - basisInfo.basisFuncList[i].centerCoords[0];
2250       ergo_real dy = molecule.getAtom(k).coords[1] - basisInfo.basisFuncList[i].centerCoords[1];
2251       ergo_real dz = molecule.getAtom(k).coords[2] - basisInfo.basisFuncList[i].centerCoords[2];
2252       ergo_real distance = template_blas_sqrt(dx*dx + dy*dy + dz*dz);
2253       if(distance < 1e-4)
2254 	foundAtomIndex = k;
2255     }
2256     if(foundAtomIndex < 0)
2257       throw "Error in get_mulliken_charges: all basis functions are not centered on atoms.";
2258     atomMapping[i] = foundAtomIndex;
2259   }
2260 
2261   normalMatrix D(densityMatrix);
2262   normalMatrix S(S_symm);
2263   // Now get all elements of the matrix D.
2264   std::vector<int> rowind;
2265   std::vector<int> colind;
2266   std::vector<ergo_real> values_D;
2267   D.get_all_values(rowind,
2268 		   colind,
2269 		   values_D,
2270 		   inversePermutationHML,
2271 		   inversePermutationHML);
2272   int nvalues = values_D.size();
2273 
2274   // Now get corresponding elements of S.
2275   std::vector<ergo_real> values_S(nvalues);
2276   for(int i = 0; i < nvalues; i++)
2277     values_S[i] = 0;
2278   S.get_values(rowind,
2279 	       colind,
2280 	       values_S,
2281 	       permutationHML, //inversePermutationHML,
2282 	       permutationHML);//inversePermutationHML);
2283 
2284   // Now go through all elements of D and S and make the corresponding contributions to the result vector.
2285   for(int i = 0; i < nvalues; i++) {
2286     int row = rowind[i];
2287     int col = colind[i];
2288     int atomIndex1 = atomMapping[row];
2289     int atomIndex2 = atomMapping[col];
2290     resultVector[atomIndex1] += 0.5 * values_D[i] * values_S[i];
2291     resultVector[atomIndex2] += 0.5 * values_D[i] * values_S[i];
2292   }
2293 }
2294 
2295 void
do_mulliken_atomic_charges(const symmMatrix & densityMatrix,const symmMatrix & S_symm,const BasisInfoStruct & basisInfo,mat::SizesAndBlocks const & matrix_size_block_info,std::vector<int> const & permutationHML,std::vector<int> const & inversePermutationHML,const Molecule & molecule)2296 do_mulliken_atomic_charges(const symmMatrix & densityMatrix,
2297 			   const symmMatrix & S_symm,
2298 			   const BasisInfoStruct & basisInfo,
2299 			   mat::SizesAndBlocks const & matrix_size_block_info,
2300 			   std::vector<int> const & permutationHML,
2301 			   std::vector<int> const & inversePermutationHML,
2302 			   const Molecule& molecule)
2303 {
2304   // Compute Mulliken atomic charges.
2305   // First get vector with summed electron charge for all atoms.
2306   std::vector<ergo_real> electronChargeSums;
2307   get_mulliken_charges(densityMatrix, S_symm, basisInfo, matrix_size_block_info, permutationHML, inversePermutationHML, molecule, electronChargeSums);
2308   int nAtoms = molecule.getNoOfAtoms();
2309   ergo_real chargeSum = 0;
2310   for(int i = 0; i < nAtoms; i++)
2311     chargeSum += electronChargeSums[i];
2312   do_output(LOG_CAT_INFO, LOG_AREA_SCF, "Sum of Mulliken charges (electrons): %15.7f", (double)chargeSum);
2313   std::vector<ergo_real> atomicCharges(nAtoms);
2314   for(int i = 0; i < nAtoms; i++)
2315     atomicCharges[i] = molecule.getAtom(i).charge - electronChargeSums[i];
2316   for(int i = 0; i < nAtoms; i++)
2317     do_output(LOG_CAT_INFO, LOG_AREA_SCF, "Mulliken charge of atom %d = %15.7f", i, (double)atomicCharges[i]);
2318   chargeSum = 0;
2319   for(int i = 0; i < nAtoms; i++)
2320     chargeSum += atomicCharges[i];
2321   do_output(LOG_CAT_INFO, LOG_AREA_SCF, "Sum of Mulliken atomic charges: %15.7f", (double)chargeSum);
2322 }
2323 
2324 void
do_mulliken_spin_densities(const symmMatrix & spinDensityMatrix,const symmMatrix & S_symm,const BasisInfoStruct & basisInfo,mat::SizesAndBlocks const & matrix_size_block_info,std::vector<int> const & permutationHML,std::vector<int> const & inversePermutationHML,const Molecule & molecule)2325 do_mulliken_spin_densities(const symmMatrix & spinDensityMatrix,
2326 			   const symmMatrix & S_symm,
2327 			   const BasisInfoStruct & basisInfo,
2328 			   mat::SizesAndBlocks const & matrix_size_block_info,
2329 			   std::vector<int> const & permutationHML,
2330 			   std::vector<int> const & inversePermutationHML,
2331 			   const Molecule& molecule)
2332 {
2333   std::vector<ergo_real> mullikenCharges;
2334   get_mulliken_charges(spinDensityMatrix, S_symm, basisInfo, matrix_size_block_info, permutationHML, inversePermutationHML, molecule, mullikenCharges);
2335   int nAtoms = molecule.getNoOfAtoms();
2336   for(int i = 0; i < nAtoms; i++)
2337     do_output(LOG_CAT_INFO, LOG_AREA_SCF, "Mulliken spin density of atom %d = %15.7f", i, (double)mullikenCharges[i]);
2338   ergo_real chargeSum = 0;
2339   for(int i = 0; i < nAtoms; i++)
2340     chargeSum += mullikenCharges[i];
2341   do_output(LOG_CAT_INFO, LOG_AREA_SCF, "Sum of Mulliken atomic spin densities: %15.7f", (double)chargeSum);
2342 }
2343 
write_gcube_file_header(FILE * f,const char * firstLine,const Molecule & m,double originX,double originY,double originZ,int NX,double incrX,int NY,double incrY,int NZ,double incrZ)2344 static int write_gcube_file_header(FILE* f,
2345 				   const char* firstLine,
2346 				   const Molecule& m,
2347 				   double originX, double originY, double originZ,
2348 				   int NX, double incrX,
2349 				   int NY, double incrY,
2350 				   int NZ, double incrZ) {
2351   fprintf(f, "%s\n\n", firstLine);
2352   fprintf(f, "%d  %9.5f  %9.5f  %9.5f\n", m.getNoOfAtoms(), originX, originY, originZ);
2353   fprintf(f, "%d  %9.5f    0.0    0.0\n", NX, incrX);
2354   fprintf(f, "%d    0.0  %9.5f    0.0\n", NY, incrY);
2355   fprintf(f, "%d    0.0    0.0  %9.5f\n", NZ, incrZ);
2356   for(int i = 0; i < m.getNoOfAtoms(); i++)
2357     fprintf(f, "%d 0.0 %9.5f %9.5f %9.5f\n", (int)m.getAtom(i).charge, (double)m.getAtom(i).coords[0], (double)m.getAtom(i).coords[1], (double)m.getAtom(i).coords[2]);
2358   return 0;
2359 }
2360 
2361 
2362 
2363 
get_exp_value_pos_operator(const BasisInfoStruct & basisInfo,const Molecule & molecule,const symmMatrix & densityMatrix,mat::SizesAndBlocks const & matrix_size_block_info,std::vector<int> const & permutationHML,std::vector<ergo_real> & mean,std::vector<ergo_real> & std)2364 void get_exp_value_pos_operator(const BasisInfoStruct & basisInfo,
2365 				const Molecule& molecule,
2366 				const symmMatrix & densityMatrix,
2367 				mat::SizesAndBlocks const & matrix_size_block_info,
2368 				std::vector<int> const & permutationHML,
2369 				std::vector<ergo_real> &mean,
2370 				std::vector<ergo_real> &std)
2371 
2372 {
2373   ergo_real expval;
2374   int xi = 0, yi = 0, zi = 0;
2375   mean.clear(); mean.resize(3);
2376   std.clear(); std.resize(3);
2377 
2378   symmMatrix opMatrix;
2379   opMatrix.resetSizesAndBlocks(matrix_size_block_info, matrix_size_block_info);
2380 
2381   for(int coord = 0; coord < 3; ++coord)
2382     {
2383       switch(coord)
2384 	{
2385 	case 0: xi = 1; break;
2386 	case 1: yi = 1; break;
2387 	case 2: zi = 1; break;
2388 	default: throw "Error in get_exp_value_pos_operator: wrong value of coord";
2389 	}
2390       // compute expectated value of position operator
2391       if(compute_operator_matrix_sparse_symm(basisInfo, xi, yi, zi, opMatrix, permutationHML) != 0)
2392 	throw "Error in compute_operator_matrix_sparse_symm";
2393       expval = symmMatrix::trace_ab(densityMatrix, opMatrix); // E[X]
2394       mean[coord] = expval;
2395 
2396       // compute standard deviation
2397       if(compute_operator_matrix_sparse_symm(basisInfo, 2*xi, 2*yi, 2*zi, opMatrix, permutationHML) != 0)
2398 	throw "Error in compute_operator_matrix_sparse_symm";
2399       expval = symmMatrix::trace_ab(densityMatrix, opMatrix); // E[X^2]
2400       std[coord] = template_blas_sqrt(expval - mean[coord]*mean[coord]); // sqrt[ E[X^2] - (E[X])^2 ]
2401 
2402       xi = 0; yi = 0; zi = 0;
2403     }
2404 }
2405 
2406 
2407 
2408 
2409 void
do_density_images(const BasisInfoStruct & basisInfo,const Molecule & molecule,const ergo_real * densityMatrixFull_tot,const ergo_real * densityMatrixFull_spin,double output_density_images_boxwidth,const std::string & filename_id)2410 do_density_images(const BasisInfoStruct & basisInfo,
2411 		  const Molecule& molecule,
2412 		  const ergo_real* densityMatrixFull_tot,
2413 		  const ergo_real* densityMatrixFull_spin,
2414 		  double output_density_images_boxwidth,
2415 		  const std::string &filename_id)
2416 {
2417 
2418   int nPrims1 = 0;
2419   int nPrims2 = 0;
2420 
2421   DistributionSpecStruct* rho1 = NULL;
2422   DistributionSpecStruct* rho2 = NULL;
2423   ergo_real cutoff = 1e-7;//1e-7;
2424 
2425   do_output(LOG_CAT_INFO, LOG_AREA_SCF, "do_density_images, calling get_density() with cutoff = %8.4g.", cutoff);
2426 
2427   nPrims1 = get_no_of_primitives_for_density(cutoff, densityMatrixFull_tot , basisInfo);
2428   nPrims2 = get_no_of_primitives_for_density(cutoff, densityMatrixFull_spin, basisInfo);
2429   rho1 = new DistributionSpecStruct[nPrims1];
2430   rho2 = new DistributionSpecStruct[nPrims2];
2431 
2432   Util::TimeMeter timeMeterGetDens;
2433   int n1 = get_density(basisInfo,
2434 		       densityMatrixFull_tot,
2435 		       cutoff,
2436 		       nPrims1,
2437 		       rho1);
2438   int n2 = get_density(basisInfo,
2439 		       densityMatrixFull_spin,
2440 		       cutoff,
2441 		       nPrims2,
2442 		       rho2);
2443   if(n1 < 0 || n2 < 0)
2444     {
2445       do_output(LOG_CAT_ERROR, LOG_AREA_SCF, "aborting do_density_images(): (n1 < 0 || n2 < 0)");
2446       throw "aborting do_density_images(): (n1 < 0 || n2 < 0)";
2447     }
2448   nPrims1 = n1;
2449   nPrims2 = n2;
2450   timeMeterGetDens.print(LOG_AREA_SCF, "get_density() calls");
2451 
2452   do_output(LOG_CAT_INFO, LOG_AREA_SCF, "do_density_images, after get_density() calls: nPrims1 = %d, nPrims2 = %d.", nPrims1, nPrims2);
2453 
2454   // get min max coords for molecule
2455   ergo_real minlist[3];
2456   ergo_real maxlist[3];
2457   int coordno;
2458   for(coordno = 0; coordno < 3; coordno++)
2459     {
2460       minlist[coordno] = template_blas_get_num_limit_max<ergo_real>();
2461       maxlist[coordno] = template_blas_get_num_limit_min<ergo_real>();
2462     }
2463   for(int i = 0; i < molecule.getNoOfAtoms(); i++)
2464     {
2465       for(coordno = 0; coordno < 3; coordno++)
2466 	{
2467 	  ergo_real curr = molecule.getAtom(i).coords[coordno];
2468 	  if(curr < minlist[coordno])
2469 	    minlist[coordno] = curr;
2470 	  if(curr > maxlist[coordno])
2471 	    maxlist[coordno] = curr;
2472 	}
2473     }
2474   // OK, now we have min max coords for molecule.
2475   // Add some margin.
2476   ergo_real margin = 4.4;
2477   for(coordno = 0; coordno < 3; coordno++)
2478     {
2479       minlist[coordno] -= margin;
2480       maxlist[coordno] += margin;
2481     }
2482 
2483   ergo_real boxWidthApprox = output_density_images_boxwidth; //0.3;
2484   int Nx = (int)((maxlist[0] - minlist[0]) / boxWidthApprox);
2485   int Ny = (int)((maxlist[1] - minlist[1]) / boxWidthApprox);
2486   int Nz = (int)((maxlist[2] - minlist[2]) / boxWidthApprox);
2487 
2488   // Make sure Nx Ny Nz are odd numbers (this seems to be required for the electrostatic potential computation feature in Gabedit).
2489   if(Nx % 2 == 0) Nx++;
2490   if(Ny % 2 == 0) Ny++;
2491   if(Nz % 2 == 0) Nz++;
2492 
2493   do_output(LOG_CAT_INFO, LOG_AREA_SCF, "do_density_images: Nx Ny Nz = %5i %5i %5i", Nx, Ny, Nz);
2494 
2495   ergo_real boxWidth_x = (maxlist[0] - minlist[0]) / Nx;
2496   ergo_real boxWidth_y = (maxlist[1] - minlist[1]) / Ny;
2497   ergo_real boxWidth_z = (maxlist[2] - minlist[2]) / Nz;
2498 
2499   do_output(LOG_CAT_INFO, LOG_AREA_SCF, "do_density_images, preparing to write Gabedit gcube files.");
2500 
2501   // Create Gabedit "gcube" density files.
2502   std::ostringstream name_f1, name_f2;
2503   name_f1 << "density" << filename_id << ".gcube";
2504   name_f2 << "spindensity" << filename_id << ".gcube";
2505 
2506   FILE* f1 = fopen(name_f1.str().c_str(), "wt");
2507   FILE* f2 = fopen(name_f2.str().c_str(), "wt");
2508   if(f1 == NULL || f2 == NULL)
2509     {
2510       do_output(LOG_CAT_ERROR, LOG_AREA_SCF, "aborting do_density_images: (f1 == NULL || f2 == NULL)");
2511       throw "aborting do_density_images: (f1 == NULL || f2 == NULL)";
2512     }
2513   double originX = minlist[0];
2514   double originY = minlist[1];
2515   double originZ = minlist[2];
2516   double dx = (maxlist[0] - minlist[0]) / Nx;
2517   double dy = (maxlist[1] - minlist[1]) / Ny;
2518   double dz = (maxlist[2] - minlist[2]) / Nz;
2519   // Shift origin coordinates by half of the box width in each direction (it seems Gabedit is interpreting the values in that way).
2520   originX += 0.5 * dx;
2521   originY += 0.5 * dy;
2522   originZ += 0.5 * dz;
2523   write_gcube_file_header(f1,
2524 			  "Density file in gcube format, generated by the Ergo program.",
2525 			  molecule,
2526 			  originX, originY, originZ,
2527 			  Nx, dx,
2528 			  Ny, dy,
2529 			  Nz, dz);
2530   write_gcube_file_header(f2,
2531 			  "Spin density file in gcube format, generated by the Ergo program.",
2532 			  molecule,
2533 			  originX, originY, originZ,
2534 			  Nx, dx,
2535 			  Ny, dy,
2536 			  Nz, dz);
2537   // Now compute density values in all needed boxes.
2538   do_output(LOG_CAT_INFO, LOG_AREA_SCF, "do_density_images, computing density values needed for Gabedit gcube files.");
2539   Util::TimeMeter timeMeterGetDensValues;
2540   std::vector< std::vector< std::vector<double> > > vector_dens(Nx);
2541   std::vector< std::vector< std::vector<double> > > vector_spin(Nx);
2542 #ifdef _OPENMP
2543 #pragma omp parallel for
2544 #endif
2545   for(int ix = 0; ix < Nx; ix++) {
2546     vector_dens[ix].resize(Ny);
2547     vector_spin[ix].resize(Ny);
2548     for(int iy = 0; iy < Ny; iy++) {
2549       vector_dens[ix][iy].resize(Nz);
2550       vector_spin[ix][iy].resize(Nz);
2551       for(int iz = 0; iz < Nz; iz++) {
2552 	ergo_real minVect[3];
2553 	ergo_real maxVect[3];
2554 	minVect[0] = minlist[0] + ix * (maxlist[0] - minlist[0]) / Nx;
2555 	maxVect[0] = minVect[0] + boxWidth_x;
2556 	minVect[1] = minlist[1] + iy * (maxlist[1] - minlist[1]) / Ny;
2557 	maxVect[1] = minVect[1] + boxWidth_y;
2558 	minVect[2] = minlist[2] + iz * (maxlist[2] - minlist[2]) / Nz;
2559 	maxVect[2] = minVect[2] + boxWidth_z;
2560 	ergo_real dens = integrate_density_in_box_2(nPrims1,
2561 						    rho1,
2562 						    minVect,
2563 						    maxVect);
2564 	ergo_real spin = integrate_density_in_box_2(nPrims2,
2565 						    rho2,
2566 						    minVect,
2567 						    maxVect);
2568 	vector_dens[ix][iy][iz] = dens;
2569 	vector_spin[ix][iy][iz] = spin;
2570       } // END FOR iz
2571     } // END FOR iy
2572   } // END FOR ix
2573   timeMeterGetDensValues.print(LOG_AREA_SCF, "getting density values");
2574   // Now write to files.
2575   Util::TimeMeter timeMeterWriteFiles;
2576   ergo_real sum_dens = 0;
2577   ergo_real sum_spin = 0;
2578   for(int ix = 0; ix < Nx; ix++)
2579     for(int iy = 0; iy < Ny; iy++) {
2580       int count = 0;
2581       for(int iz = 0; iz < Nz; iz++) {
2582 	ergo_real dens = vector_dens[ix][iy][iz];
2583 	ergo_real spin = vector_spin[ix][iy][iz];
2584 	sum_dens += dens;
2585 	sum_spin += spin;
2586 	ergo_real volume = dx*dy*dz;
2587 	fprintf(f1, " %9.5f", (double)(dens / volume));
2588 	fprintf(f2, " %9.5f", (double)(spin / volume));
2589 	count++;
2590 	if(count % 6 == 0) {
2591 	  fprintf(f1, "\n");
2592 	  fprintf(f2, "\n");
2593 	}
2594       }
2595       if(count % 6 != 0) {
2596 	fprintf(f1, "\n");
2597 	fprintf(f2, "\n");
2598       }
2599     }
2600   timeMeterWriteFiles.print(LOG_AREA_SCF, "writing to gcube files");
2601   do_output(LOG_CAT_INFO, LOG_AREA_SCF, "sum_dens = %9.5f, sum_spin = %9.5f", sum_dens, sum_spin);
2602 
2603   fclose(f1);
2604   fclose(f2);
2605 
2606   do_output(LOG_CAT_INFO, LOG_AREA_SCF, "do_density_images done, Gabedit gcube files written.");
2607 }
2608 
2609 
2610 void
get_hf_weight_and_cam_params(int use_dft,ergo_real * exch_param_alpha,ergo_real * exch_param_beta,ergo_real * exch_param_mu)2611 get_hf_weight_and_cam_params(int use_dft,
2612 			     ergo_real* exch_param_alpha,
2613 			     ergo_real* exch_param_beta,
2614 			     ergo_real* exch_param_mu)
2615 {
2616   if(use_dft)
2617     {
2618 #ifndef SKIP_DFT_FLAG
2619       int use_cam_params =
2620         fun_get_cam_param(exch_param_alpha, exch_param_beta, exch_param_mu);
2621       if(!use_cam_params) {
2622         *exch_param_alpha = fun_get_hf_weight();
2623 	*exch_param_beta = 0.0;
2624       }
2625 #else
2626       throw "ERROR in get_hf_weight_and_cam_params: SKIP_DFT_FLAG given and use_dft set.";
2627 #endif
2628     }
2629   else
2630     {
2631       *exch_param_alpha = 1.0;
2632       *exch_param_beta = 0;
2633       *exch_param_mu = 0;
2634     }
2635 }
2636 
2637 
2638 void
create_mtx_files_with_different_orderings(const symmMatrix & A,const std::string & calculation_identifier,const std::string & method_and_basis_set,const std::vector<int> & inversePermutationHML,const BasisInfoStruct & basisInfo)2639 create_mtx_files_with_different_orderings(const symmMatrix & A,
2640 					  const std::string & calculation_identifier,
2641 					  const std::string & method_and_basis_set,
2642 					  const std::vector<int> & inversePermutationHML,
2643 					  const BasisInfoStruct & basisInfo) {
2644   // Original ordering
2645   std::stringstream ss_id_1;
2646   ss_id_1 << calculation_identifier << " - matrix (original ordering)";
2647   write_matrix_in_matrix_market_format( A, inversePermutationHML, "S_matrix_original", ss_id_1.str(), method_and_basis_set );
2648   // HML ordering
2649   int n = basisInfo.noOfBasisFuncs;
2650   std::vector<int> permutationNone(n);
2651   for(int i = 0; i < n; i++)
2652     permutationNone[i] = i;
2653   std::stringstream ss_id_2;
2654   ss_id_2 << calculation_identifier << " - matrix (HML ordering)";
2655   write_matrix_in_matrix_market_format( A, permutationNone, "S_matrix_HML", ss_id_2.str(), method_and_basis_set );
2656   // Factor2 ordering
2657   std::vector<int> permutationFactor2, inversePermutationFactor2;
2658   std::vector<ergo_real> xcoords(n);
2659   std::vector<ergo_real> ycoords(n);
2660   std::vector<ergo_real> zcoords(n);
2661   for(int i = 0; i < n; i++) {
2662     xcoords[i] = basisInfo.basisFuncList[i].centerCoords.v[0];
2663     ycoords[i] = basisInfo.basisFuncList[i].centerCoords.v[1];
2664     zcoords[i] = basisInfo.basisFuncList[i].centerCoords.v[2];
2665   }
2666   getMatrixPermutationOnlyFactor2(xcoords, ycoords, zcoords, 1, 1, permutationFactor2, inversePermutationFactor2);
2667   std::vector<int> perm(n);
2668   for(int i = 0; i < n; i++)
2669     perm[i] = permutationFactor2[ inversePermutationHML[i] ];
2670   std::stringstream ss_id_3;
2671   ss_id_3 << calculation_identifier << " - matrix (Factor2 ordering)";
2672   write_matrix_in_matrix_market_format( A, perm, "S_matrix_Factor2", ss_id_3.str(), method_and_basis_set );
2673   // Random ordering
2674   std::vector<int> permRandom(n);
2675   std::vector<bool> taken(n);
2676   for(int i = 0; i < n; i++)
2677     taken[i] = false;
2678   for(int i = 0; i < n; i++) {
2679     int randNumber = rand() % (n-i);
2680     int idx = randNumber;
2681     for(int k = 0; k < n; k++) {
2682       if(taken[k] && k <= idx)
2683 	idx++;
2684     }
2685     assert(idx >= 0);
2686     assert(idx < n);
2687     assert(taken[idx] == false);
2688     assert(idx >= 0 && idx < n && taken[idx] == false);
2689     taken[idx] = true;
2690     permRandom[i] = idx;
2691   }
2692   for(int i = 0; i < n; i++)
2693     assert(taken[i] == true);
2694   std::stringstream ss_id_4;
2695   ss_id_4 << calculation_identifier << " - matrix (random ordering)";
2696   write_matrix_in_matrix_market_format( A, permRandom, "S_matrix_random", ss_id_4.str(), method_and_basis_set );
2697 }
2698 
2699 
2700