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