1 /* Copyright (c) 2015 Gerald Knizia
2 *
3 * This file is part of the IboView program (see: http://www.iboview.org)
4 *
5 * IboView is free software: you can redistribute it and/or modify
6 * it under the terms of the GNU General Public License as published by
7 * the Free Software Foundation, version 3.
8 *
9 * IboView is distributed in the hope that it will be useful,
10 * but WITHOUT ANY WARRANTY; without even the implied warranty of
11 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12 * GNU General Public License for details.
13 *
14 * You should have received a copy of the GNU General Public License
15 * along with bfint (LICENSE). If not, see http://www.gnu.org/licenses/
16 *
17 * Please see IboView documentation in README.txt for:
18 * -- A list of included external software and their licenses. The included
19 * external software's copyright is not touched by this agreement.
20 * -- Notes on re-distribution and contributions to/further development of
21 * the IboView software
22 */
23
24 #include <stdexcept>
25 #include <iostream>
26 #include <string.h> // for memcpy
27
28 #include <fstream> // for importing stuff (cp2k data)
29 #include <stdexcept>
30
31 #include <boost/format.hpp>
32 #include <boost/algorithm/string.hpp>
33 // #include <boost/program_options.hpp>
34 // namespace po = boost::program_options;
35
36 // #include "CtCommon.h"
37 #include "CtIo.h"
38 #include "CtAtomSet.h"
39 #include "CtBasisLibrary.h"
40 #include "CtBasisSet.h"
41 // #include "CtInt1e.h"
42 #include "CtMatrix.h"
43 // #include "AicDrv.h" // for making integrals
44
45 #include "CtTiming.h" // for embdedded HF timer.
46 #include "CtConstants.h"
47
48 #include "CxNumpyArray.h"
49 // #include "AicGridOps.h"
50
51 using boost::format;
52 using boost::str;
53
54 #define HAVE_GRID_KERNEL
55
56 namespace ct {
57
58
59 #if 0
60 void FormIntIJA(double *pIntFai, FMatrixView OrbA, FMatrixView OrbI, FMatrixView Jcd, FRawBasis const *pOrbBasis, FRawBasis const *pFitBasis, ir::FIntegralKernel &IntKernel, FMemoryStack &Mem)
61 {
62 void
63 *pBaseOfMemory = Mem.Alloc(0);
64 size_t
65 nAo = pOrbBasis->nFn(),
66 nFit = pFitBasis->nFn(),
67 nOrbA = OrbA.nCols,
68 nOcc = OrbI.nCols;
69 if ( nAo != OrbI.nRows || nAo != OrbA.nRows )
70 throw std::runtime_error("MakeFittingIntegrals: Input orbitals not consistent with orbital basis set.");
71 double
72 *pDF_NFi;
73 Mem.Alloc(pDF_NFi, nAo * nFit * nOcc);
74
75 for ( size_t iShF = 0; iShF != pFitBasis->Shells.size(); ++ iShF ){
76 ir::FRawShell const &ShF = pFitBasis->Shells[iShF];
77 size_t nFnF = ShF.nFn();
78
79 double
80 *pMNF;
81 Mem.Alloc(pMNF, nAo * nAo * nFnF );
82
83 for ( size_t iShB = 0; iShB < pOrbBasis->Shells.size(); ++ iShB ){
84 ir::FRawShell const &ShB = pOrbBasis->Shells[iShB];
85 size_t nFnB = ShB.nFn();
86 for ( size_t iShA = iShB; iShA < pOrbBasis->Shells.size(); ++ iShA ) {
87 ir::FRawShell const &ShA = pOrbBasis->Shells[iShA];
88 size_t
89 nFnA = ShA.nFn(),
90 Strides[3] = {1, nFnA, nFnA * nFnB};
91 double
92 *pIntData;
93 Mem.Alloc(pIntData, nFnA * nFnB * nFnF );
94
95 ir::EvalInt2e3c(pIntData, Strides, &ShA, &ShB, &ShF,1, 1.0, &IntKernel, Mem);
96
97 for ( size_t iF = 0; iF < nFnF; ++ iF )
98 for ( size_t iB = 0; iB < nFnB; ++ iB )
99 for ( size_t iA = 0; iA < nFnA; ++ iA ) {
100 double
101 f = pIntData[iA + nFnA * (iB + nFnB * iF)];
102 // assign to (\mu\nu| and (\nu\mu|. (int has perm symmetry).
103 pMNF[(pOrbBasis->iFn(iShA) + iA) + nAo * (pOrbBasis->iFn(iShB) + iB) + nAo * nAo * iF] = f;
104 pMNF[(pOrbBasis->iFn(iShB) + iB) + nAo * (pOrbBasis->iFn(iShA) + iA) + nAo * nAo * iF] = f;
105 }
106
107 Mem.Free(pIntData);
108 }
109 }
110
111 // D[\nu A i] = (i\nu|A) = C(\mu,i) (\mu [\nu|A)]
112 FMatrixView
113 DF_NFI(pDF_NFi + nAo * pFitBasis->iFn(iShF), nAo * nFnF, nOcc, 1, nFit * nAo);
114 Mxm( DF_NFI,
115 FMatrixView(pMNF, nAo * nFnF, nAo, nAo, 1),
116 OrbI );
117
118 Mem.Free(pMNF);
119 }
120
121 // Jcd version:
122 // Solve[Jcd[AB] D[\nu B i]] -> D[\nu A I]
123 for ( uint i = 0; i < nOcc; ++ i ){
124 FMatrixView
125 D_NF(pDF_NFi + nAo * nFit * i, nAo, nFit),
126 K_Fa(pIntFai + nFit * nOrbA * i, nFit, nOrbA);
127 // TriangularSolve(Transpose(D_NF), Jcd);
128 // Mxm(K_Fa, Transpose(D_NF), OrbA);
129 // ^- hm... I think I thought this was a good idea for some reason,
130 // but I cannot remember why.
131 Mxm(K_Fa, Transpose(D_NF), OrbA);
132 TriangularSolve(K_Fa, Jcd);
133 }
134
135 Mem.Free(pDF_NFi);
136 Mem.Free(pBaseOfMemory);
137 }
138
139
140
141
142 void MakeFittingIntegrals(double *pIntFai, FMatrixView OrbA, FMatrixView OrbI, FBasisSet const *pOrbBasis, FBasisSet const *pFitBasis, FMemoryStack &Mem)
143 {
144 uint
145 nAo = pOrbBasis->nFn(),
146 nFit = pFitBasis->nFn();
147
148 xout << boost::format(" ORBITAL BASIS %s:%35t%5i FUNCTIONS") % pOrbBasis->Name % nAo << "\n"
149 << boost::format(" FITTING BASIS %s:%35t%5i FUNCTIONS") % pFitBasis->Name % nFit << "\n"
150 << std::endl;
151
152 // Make fitting coefficients J^{-1/2}.
153 FTimer TimerJmh;
154 FStackMatrix
155 Jmh(nFit, nFit, &Mem);
156 MakeIntMatrix(Jmh, *pFitBasis, *pFitBasis, FKrn2i_Direct(&ir::g_IrCoulombKernel), Mem);
157 CalcCholeskyFactors(Jmh);
158 xout << format(pTimingFmt) % "J^{-1/2} of fitting basis" % (double)TimerJmh; xout.flush();
159
160 // make (F|ai) the lame way: assume we can keep (ai|A) in memory.
161 FTimer TimerIJA;
162 FormIntIJA(pIntFai, OrbA, OrbI, Jmh,
163 &*pOrbBasis->pRawBasis, &*pFitBasis->pRawBasis, ir::g_IrCoulombKernel, Mem);
164 xout << format(pTimingFmt) % "3-index integrals" % (double)TimerIJA; xout.flush();
165 };
166 #endif // 0
167
168 #ifdef HAVE_GRID_KERNEL
Vec3Eq(double const * pA,double const * pB)169 bool Vec3Eq(double const *pA, double const *pB) {
170 return pA[0] == pB[0] && pA[1] == pB[1] && pA[2] == pB[2];
171 }
172
MakeGridValues(double * pOut,FMatrixView Grid,FMatrixView Orb,uint GridDxOrder,FBasisSet const * pBasis,FMemoryStack & Mem_)173 void MakeGridValues(double *pOut, FMatrixView Grid, FMatrixView Orb, uint GridDxOrder, FBasisSet const *pBasis, FMemoryStack &Mem_)
174 {
175 void
176 *pBaseOfMemory = Mem_.Alloc(0);
177 size_t
178 nGridPt_Total = Grid.nCols,
179 nComp = 1,
180 nGridStep = 128,
181 nAo = pBasis->nFn(),
182 nOrb = Orb.nCols;
183 if ( GridDxOrder == 1 ) nComp = 4;
184 if ( GridDxOrder == 2 ) nComp = 10;
185 // std::cout << "nAo = " << nAo << " Orb.nRows =" << Orb.nRows << std::endl;
186 if ( nAo != Orb.nRows )
187 throw std::runtime_error("MakeGridValues: Input orbitals not consistent with orbital basis set.");
188
189 // convert basis format for low level driver input...
190 FRawBasis::FShellArray
191 &ShellsA = const_cast<FBasisSet*>(pBasis)->pRawBasis->Shells;
192
193 assert(Grid.nRowSt == 1 && Grid.nRows == 3);
194
195 {
196 FMemoryStackArray MemStacks(Mem_);
197 // #pragma omp parallel for schedule(dynamic)
198 // for ( size_t iGridPt = 0; iGridPt < nGridPt_Total; iGridPt += nGridStep ) {
199 int nGridPt_Batches = int((nGridPt_Total + nGridStep - 1)/nGridStep);
200 #pragma omp parallel for schedule(dynamic)
201 for ( int iGridPt_Batch = 0; iGridPt_Batch < nGridPt_Batches; ++ iGridPt_Batch ) {
202 size_t iGridPt = size_t(iGridPt_Batch) * nGridStep;
203 // ^- that's for OMP 2.0 which allows only 'int' variables for loop control.
204 FMemoryStack &Mem = MemStacks.GetStackOfThread();
205 size_t
206 nGridPt = nGridStep;
207 if ( iGridPt + nGridPt > nGridPt_Total )
208 nGridPt = nGridPt_Total - iGridPt;
209 if (nGridPt == 0)
210 continue;
211 void
212 *pMem1 = Mem.Alloc(0);
213 size_t
214 *pMap, nMap = 0, iFnBase = 0;
215 double
216 *pOrbValAo, *pOrbsCompressed;
217 Mem.Alloc(pOrbValAo, nGridPt * nComp * nAo);
218 Mem.Alloc(pOrbsCompressed, nAo * nOrb);
219
220 ir::FRawShell
221 *pLastBf = &ShellsA[0];
222 Mem.Alloc(pMap, nAo);
223 for ( ir::FRawShell *pFirstBf = &ShellsA[0]; pFirstBf != &ShellsA[0] + ShellsA.size(); pFirstBf = pLastBf ) {
224 pLastBf = pFirstBf;
225 size_t nFn = 0;
226 while ( pLastBf != &ShellsA[0] + ShellsA.size() && Vec3Eq(pLastBf->vCen, pFirstBf->vCen) ) {
227 nFn += pLastBf->nFn();
228 ++pLastBf;
229 }
230 size_t
231 nBfStride = nGridPt*nComp;
232 EvalShellGroupOnGrid(&pOrbValAo[nBfStride*nMap], nGridPt, nBfStride, // comp stride, bf stride
233 pMap, nMap, iFnBase, &Grid(0,iGridPt), Grid.nColSt, nGridPt,
234 pFirstBf, pLastBf, &pFirstBf->vCen[0],
235 GridDxOrder, 1e-10, 40, Mem);
236 iFnBase += nFn;
237 }
238 assert(iFnBase == nAo && nMap <= nAo);
239 assert(pLastBf == &ShellsA[0] + ShellsA.size());
240
241 FMatrixView
242 OrbCmpr(pOrbsCompressed, nMap, nOrb),
243 OrbValAo(pOrbValAo, nGridPt*nComp, nMap);
244 // compress input orbital matrix: delete basis functions not occurring in nMap.
245 for ( size_t iOrb = 0; iOrb != nOrb; ++ iOrb )
246 for ( size_t iMap_ = 0; iMap_ != nMap; ++ iMap_ )
247 OrbCmpr(iMap_, iOrb) = Orb(pMap[iMap_], iOrb);
248 for (uint iComp = 0; iComp < nComp; ++ iComp) {
249 FMatrixView
250 Out(&pOut[iGridPt+nGridPt_Total*iComp], nGridPt, nOrb, 1, nGridPt_Total*nComp),
251 OrbValAoComp = OrbValAo;
252 if (nMap == 0) {
253 Out.Clear();
254 } else {
255 OrbValAoComp.nRows = nGridPt;
256 OrbValAoComp.pData += nGridPt * iComp;
257 Mxm(Out, OrbValAoComp, OrbCmpr);
258 }
259 }
260 Mem.Free(pMem1);
261 }
262 }
263
264 Mem_.Free(pBaseOfMemory);
265 }
266 #endif
267
268
269 #if 0
270 void WriteMatrixToFile_Rect(std::string const &FileName, std::string const Desc, double *pData, uint nRows, uint nCols, char const *pNumFmt)
271 {
272 if ( pNumFmt == 0 )
273 pNumFmt = "%21.14f";
274 std::ofstream
275 File(FileName.c_str());
276 File << format("! %s, %i x %i\n") % Desc % nRows % nCols;
277 if ( !File.good() )
278 throw std::runtime_error("failed to open file '" + FileName + "' for writing.");
279 for ( uint iRow = 0; iRow < nRows; ++ iRow ) {
280 for ( uint iCol = 0; iCol < nCols; ++ iCol ) {
281 File << " " << format(pNumFmt) % pData[iRow + nRows*iCol];
282 };
283 File << "\n";
284 }
285 }
286
287
288 void WriteMatrixtoFile2(std::string const &FileName, ct::FMatrixView const &M, std::string const &MatrixName, std::string const &MatrixFormat, int Verbosity = 0)
289 {
290 if ( MatrixFormat == "npy" ) {
291 if ( M.nRowSt != 1 || M.nColSt != M.nRows )
292 throw std::runtime_error("Sorry, WriteNpy can currently only export continuous matrices in default layout.");
293 ct::WriteNpy(FileName, M.pData, ct::MakeShape(M.nRows, M.nCols));
294 }
295 else if ( MatrixFormat == "list" )
296 WriteMatrixToFile(FileName, M, MatrixName);
297 else if ( MatrixFormat == "rect" )
298 WriteMatrixToFile_Rect(FileName, MatrixName, M.pData, M.nRows, M.nCols, " %22.15e");
299 else
300 throw std::runtime_error("output matrix format not recognized: '" + MatrixFormat + "'");
301 if ( Verbosity >= 1 )
302 ct::xout << format(" * wrote %s matrix to '%s'.") % MatrixName % FileName << std::endl;
303 };
304
305 // Set Out := L^T In R.
306 void BasisChange2( FMatrixView &Out, FMatrixView const &L,
307 FMatrixView const &In, FMatrixView const &R, FMemoryStack &Mem)
308 {
309 assert( L.nRows == In.nRows && R.nRows == In.nCols );
310 // Out = FMatrixView( 0, L.nCols, R.nCols );
311 // Mem.Alloc(Out.pData, Out.GetStridedSize());
312 assert( Out.nRows == L.nCols && Out.nCols == R.nCols );
313
314 if ( L.nRows * L.nCols <= R.nRows * R.nCols ) {
315 // T1 := L^T In
316 FStackMatrix
317 T1(L.nCols, In.nCols, &Mem);
318 Mxm(T1, Transpose(L), In);
319 Mxm(Out, T1, R);
320 } else {
321 // T1 := In * R
322 FStackMatrix
323 T1(In.nRows, R.nCols, &Mem);
324 Mxm(T1, In, R);
325 Mxm(Out, Transpose(L), T1);
326 }
327
328 if ( L.pData == R.pData && In.IsSymmetric(1e-10) )
329 Symmetrize(Out);
330 }
331 #endif // 0
332
333 } // namespace ct
334
335 #if 0
336 int main_integral_export(int argc, char *argv[])
337 {
338 using namespace ct;
339 std::cout << " :::: IR/WMME [v20150427] -- Write Molecular Matrix Elements (Gerald Knizia, 2013) ::::"
340 << std::endl;
341
342
343 po::options_description options_desc("Options");
344 std::vector< std::string >
345 FileNames_BasisLibs;
346 std::string
347 BasisName_Orbital,
348 BasisName_Orbital2,
349 BasisName_Fit,
350 FileName_Overlap,
351 FileName_Overlap12,
352 FileName_Overlap2,
353 FileName_CoreH,
354 FileName_VNucN,
355 FileName_RSqN,
356 FileName_Dipole,
357 FileName_2eFit,
358 FileName_Atoms,
359 FileName_AtomsAu,
360 FileName_AtomsAng,
361 FileName_InputOrbitals,
362 FileName_GridCoords,
363 FileName_GridValues,
364 FileName_GridOps,
365 Name_OrbitalTrafo,
366 MatrixFormat;
367 int
368 GridDxOrder = 0;
369 options_desc.add_options()
370 ("help",
371 "print this help message")
372 ("basis-lib", po::value<std::vector<std::string> >(&FileNames_BasisLibs)->composing(),
373 "file names of .libmol basis set libraries to load (Molpro basis lib format). Can occur multiple times. "
374 "all basis sets used in the input must be defined in one of those files.")
375 ("save-overlap", po::value<std::string>(&FileName_Overlap)->default_value(""),
376 "if given, save the AO overlap matrix S <mu|nu> to this file.")
377 ("save-coreh", po::value<std::string>(&FileName_CoreH)->default_value(""),
378 "if given, save the core Hamiltonian (1e terms) to this file.")
379 // ("save-vnucN", po::value<std::string>(&FileName_VNucN)->default_value(""),
380 // "if given, save the individual nuclear repulsion matrices (nOrb x nOrb x nAtoms) to this file.")
381 // ("save-rsqN", po::value<std::string>(&FileName_RSqN)->default_value(""),
382 // "if given, save the individual <mu|(r-rA)^2|nu> matrices, for rA going over the nuclei (nOrb x nOrb x nAtoms) to this file.")
383 // ("save-dipole", po::value<std::string>(&FileName_Dipole)->default_value(""),
384 // "if given, save the dipole operator matrices (nOrb x nOrb x 3) to this file.")
385 ("save-fint2e", po::value<std::string>(&FileName_2eFit)->default_value(""),
386 "if given, save the full (F|mu nu) 2e fitting integral matrix to this file. "
387 "Fitting metric is already absorbed in F; i.e., the 2e integral "
388 "(mu nu|eta xi) \\approx \\sum_F (mu nu|F)(F|eta xi).")
389 ("basis-orb", po::value<std::string>(&BasisName_Orbital)->default_value("MINAO"),
390 "name of the orbital basis to use for r,s. (e.g., cc-pVTZ, def2-SVP)")
391 ("basis-fit", po::value<std::string>(&BasisName_Fit)->default_value("univ-JKFIT"),
392 "name of the fitting basis to use for F (e.g., def2-TZVPP-JKFIT, def2-TZVPP-MP2FI)")
393 ("orb-trafo", po::value<std::string>(&Name_OrbitalTrafo)->default_value("None"),
394 "can be 'None' or 'Smh'. In the latter case, all output integrals (except "
395 "for overlap matrices) are stored in terms of symmetrically orthogonalized "
396 "basis functions for mu,nu instead of raw basis functions.")
397 ("matrix-format", po::value<std::string>(&MatrixFormat)->default_value("list"),
398 "Can be 'npy', 'list' or 'rect'. Defines file format of output matrices. "
399 "npy is a binary format that can be loaded by numpy.load(..).")
400 ("atoms-ang", po::value<std::string>(&FileName_AtomsAng)->default_value(""),
401 "File name of input atoms (xyz format). Input coordinates are given in "
402 "angstroms (1.0 == 10^-{10} meter). Normally .xyz files use these units.")
403 ("atoms-au", po::value<std::string>(&FileName_AtomsAu)->default_value(""),
404 "File name of input atoms (xyz format). Input coordinates are given in "
405 "atomic units (1.0 == 1.0 bohr radius)")
406 ("basis-orb-2", po::value<std::string>(&BasisName_Orbital2)->default_value(""),
407 "name of a second orbital basis; if given, --save-overlap-2 and --save-overlap-12 "
408 "can be used to calculate the overlap between two orbital basis sets.")
409 ("save-overlap-2", po::value<std::string>(&FileName_Overlap2)->default_value(""),
410 "if given, save the overlap matrix in the second orbital basis to this file")
411 ("save-overlap-12", po::value<std::string>(&FileName_Overlap12)->default_value(""),
412 "if given, save the overlap matrix between the first and the second basis to this file")
413 #ifdef HAVE_GRID_KERNEL
414 ("eval-orbitals", po::value<std::string>(&FileName_InputOrbitals)->default_value(""),
415 "if given, evaluate given orbitals (nAo x nOrb matrix) on grid. nAo must be comaptible with basis-orb. If given, --grid-coords must also be given.")
416 ("save-grid-ops", po::value<std::string>(&FileName_GridOps)->default_value(""),
417 "if given, evaluate position operators (nAo x nAo x nGrid matrix) on grid. If given, --grid-coords must also be given.")
418 ("grid-coords", po::value<std::string>(&FileName_GridCoords)->default_value(""),
419 "read grid coordinates(3 x nGrid matrix) from this file.")
420 ("save-grid-values", po::value<std::string>(&FileName_GridValues)->default_value(""),
421 "save values of orbitals on grid to this file.")
422 ("eval-orbitals-dx", po::value<int>(&GridDxOrder)->default_value(0),
423 "order of derivatives to evaluate for orbitals on grid: 0: values only ... 2: up to 2nd derivatives.")
424 #endif
425 ;
426 // Args = [("--eval-orbitals-dx=%s" % DerivativeOrder)]
427 // Inputs = [("--grid-coords", "GRID", Grid)]
428 // Outputs = [("--grid-values", "ORBS_ON_GRID")]
429
430 po::variables_map vm;
431 po::store(po::parse_command_line(argc, argv, options_desc), vm);
432 po::notify(vm);
433
434 if (vm.count("help") || argc == 1) {
435 xout << "\nThis program calculates molecular matrix elements (``integrals'') over Gaussian"
436 "\nbasis functions and writes them to disk. See README for an explanation of the"
437 "\nterms, the intended usage, and more information on input and output formats."
438 "\n"
439 << std::endl;
440 xout << options_desc << std::endl;
441 return 1;
442 }
443
444 // find file name of input atomic coordinates.
445 double
446 fInputAtomScale = 1.0;
447 if ( FileName_AtomsAu != "" ) {
448 FileName_Atoms = FileName_AtomsAu;
449 fInputAtomScale = ToAng;
450 } else if ( FileName_AtomsAng != "" ) {
451 FileName_Atoms = FileName_AtomsAng;
452 fInputAtomScale = 1.0;
453 } else {
454 throw std::runtime_error("either --atoms-au or --atoms-ang arguments must be given.");
455 }
456
457 // check combinations of other input options.
458 if ( FileNames_BasisLibs.empty() )
459 throw std::runtime_error("you must specify at least one basis set library file to load (--basis-lib missing)");
460 if ( BasisName_Fit.empty() && !FileName_2eFit.empty() )
461 throw std::runtime_error("if calculating 2e integrals, you must specify a fitting basis (--basis-fit)");
462 bool
463 TransformToSmh = false;
464 if ( Name_OrbitalTrafo != "None" and Name_OrbitalTrafo != "Smh" )
465 throw std::runtime_error("orbital transformation not recognized (--orb-trafo)");
466 if ( Name_OrbitalTrafo == "Smh" )
467 TransformToSmh = true;
468 if ( MatrixFormat != "npy" && MatrixFormat != "list" && MatrixFormat != "rect" )
469 throw std::runtime_error("Output matrix format must be 'npy', 'list' or 'rect' (--matrix-format)");
470 if ( FileName_InputOrbitals == "" ) {
471 if ( FileName_GridCoords != "" || FileName_GridValues != "" || GridDxOrder != 0 )
472 throw std::runtime_error("no input orbitals provided. Grid options are to be used in conjunction with --eval-orbitals.");
473 } else {
474 if ( FileName_GridCoords == "" || FileName_GridValues == "" )
475 throw std::runtime_error("when --eval-orbitals is given, --grid-coords and --save-grid-values must also be given.");
476 if ( GridDxOrder != 0 && GridDxOrder != 1 && GridDxOrder != 2 )
477 throw std::runtime_error("grid derivatives can only be evaluated up to 2nd order.");
478 }
479 if ( BasisName_Orbital2 == "" && (FileName_Overlap2 != "" || FileName_Overlap12 != "") )
480 throw std::runtime_error("overlaps <2|2> or <1|2> between two orbital basis sets were requested, but no second orbital basis was specified. Use --basis-orb-2 to set one.");
481
482 // xout << fmt::ind();
483
484 MajorProgramIntro(xout, "BASIS LIBRARY");
485 for ( uint iBasisLib = 0; iBasisLib < FileNames_BasisLibs.size(); ++ iBasisLib )
486 g_BasisSetLibrary.ImportMolproLib(FileNames_BasisLibs[iBasisLib], &xout);
487
488 boost::intrusive_ptr<FAtomSet>
489 pAtoms = new FAtomSet;
490 FBasisDescs
491 DefaultBases;
492 DefaultBases[BASIS_Orbital] = BasisName_Orbital;
493 DefaultBases[BASIS_JkFit] = BasisName_Fit;
494 if ( BasisName_Orbital2 != "" )
495 DefaultBases[BASIS_Guess] = BasisName_Orbital2;
496 // ^- slight abuse of the orbital context
497
498 pAtoms->AddAtomsFromXyzFile(FileName_Atoms, DefaultBases);
499 if ( fInputAtomScale != 1.0 ) {
500 for ( uint iAtom = 0; iAtom < pAtoms->size(); ++ iAtom )
501 (*pAtoms)[iAtom].vPos *= fInputAtomScale;
502 }
503
504 MajorProgramIntro(xout, "GEOMETRY & ENVIRONMENT");
505 xout << " ATOMIC CONFIGURATION\n\n";
506 xout << *pAtoms;
507
508 MajorProgramIntro(xout, "EXPORT OF INTEGRALS");
509
510 // instanciate the basis sets.
511 FBasisSetPtr
512 pOrbBasis = new FBasisSet(*pAtoms, BASIS_Orbital),
513 pFitBasis;
514 if ( FileName_2eFit != "" )
515 pFitBasis = new FBasisSet(*pAtoms, BASIS_JkFit);
516 uint
517 nAo = pOrbBasis->nFn(),
518 nFit = 0;
519 if ( pFitBasis )
520 nFit = pFitBasis->nFn();
521
522 std::size_t
523 RequiredMem = 4*nAo*nAo + (1500<<20);
524 if ( FileName_2eFit != "" )
525 RequiredMem += (2*nFit*nAo*nAo) + nFit*nFit;
526 FMemoryStack2
527 Mem(RequiredMem);
528
529 // we'll just do the transformation always, and push a indentity matrix
530 // if raw output integrals are requested. Can simply use MakeFittingIntegrals
531 // then.
532 FStackMatrix
533 S(nAo, nAo, &Mem),
534 Orbs(nAo, nAo, &Mem);
535 pAtoms->MakeOverlapMatrix(S, *pOrbBasis, *pOrbBasis, Mem);
536 // MakeIntMatrix(S, *pOrbBasis, *pOrbBasis, ir::g_IrOverlapKernel, Mem);
537 // S.Print(xout, "OVERLAP");
538 if ( !TransformToSmh ) {
539 Orbs.SetIdentity();
540 } else {
541 Move(Orbs, S);
542 CalcSmhMatrix(Orbs, Mem, FSmhOptions(1e-15,1e-15,(" S^{-1/2} for orbital basis ("+BasisName_Orbital+")").c_str(), &ct::xout));
543 // S.SetIdentity();
544 }
545 if ( FileName_Overlap != "" )
546 WriteMatrixtoFile2(FileName_Overlap, S, "Overlap", MatrixFormat, 1);
547
548 if ( FileName_CoreH != "" ) {
549 FStackMatrix
550 CoreH_Ao(nAo, nAo, &Mem),
551 CoreH_Mo(nAo, nAo, &Mem);
552 pAtoms->MakeCoreHamiltonMatrix(CoreH_Ao, *pOrbBasis, *pOrbBasis, Mem);
553 BasisChange2(CoreH_Mo, Orbs, CoreH_Ao, Orbs, Mem);
554 WriteMatrixtoFile2(FileName_CoreH, CoreH_Mo, "CoreH", MatrixFormat, 1);
555 }
556
557 // if ( FileName_VNucN != "" ) {
558 // FStackMatrix
559 // VNucI_Ao(nAo, nAo, &Mem),
560 // VNucN_Mo(nAo*nAo, pAtoms->size(), &Mem);
561 // for (uint iAtom = 0; iAtom < pAtoms->size(); ++ iAtom) {
562 // FMatrixView
563 // VNucI_Mo(VNucN_Mo.pData + nAo*nAo * iAtom, nAo, nAo);
564 // pAtoms->MakeVNucMatrixI(VNucI_Ao, *pOrbBasis, *pOrbBasis, iAtom, Mem);
565 // BasisChange2(VNucI_Mo, Orbs, VNucI_Ao, Orbs, Mem);
566 // }
567 // WriteMatrixtoFile2(FileName_VNucN, VNucN_Mo, "VNucN [nOrb x nOrb x nAtoms]", MatrixFormat, 1);
568 // }
569 //
570 // if ( FileName_RSqN != "" ) {
571 // FStackMatrix
572 // VRsqI_Ao(nAo, nAo, &Mem),
573 // VRsqN_Mo(nAo*nAo, pAtoms->size(), &Mem);
574 // for (uint iAtom = 0; iAtom < pAtoms->size(); ++ iAtom) {
575 // FMatrixView
576 // VRsqI_Mo(VRsqN_Mo.pData + nAo*nAo * iAtom, nAo, nAo);
577 // pAtoms->MakeRsqMatrix(VRsqI_Ao, *pOrbBasis, *pOrbBasis, (*pAtoms)[iAtom].vPos, Mem);
578 // BasisChange2(VRsqI_Mo, Orbs, VRsqI_Ao, Orbs, Mem);
579 // }
580 // WriteMatrixtoFile2(FileName_RSqN, VRsqN_Mo, "(r-rA)^2 [nOrb x nOrb x nAtoms]", MatrixFormat, 1);
581 // }
582 //
583 //
584 // if ( FileName_Dipole != "" ) {
585 // FStackMatrix
586 // DipI_Ao(nAo, nAo, &Mem),
587 // DipN_Mo(nAo*nAo, 3, &Mem);
588 // for (uint ixyz = 0; ixyz < 3; ++ ixyz) {
589 // FVector3
590 // vDir(0,0,0),
591 // vExpPoint(0,0,0);
592 // vDir[ixyz] = 1.;
593 // FMatrixView
594 // DipI_Mo(DipN_Mo.pData + nAo*nAo * ixyz, nAo, nAo);
595 // DipI_Ao.Clear();
596 // pAtoms->AddDipoleMatrix(DipI_Ao, *pOrbBasis, *pOrbBasis, vDir, vExpPoint, Mem);
597 // BasisChange2(DipI_Mo, Orbs, DipI_Ao, Orbs, Mem);
598 // }
599 // WriteMatrixtoFile2(FileName_Dipole, DipN_Mo, "Dipole operator [nOrb x nOrb x 3]", MatrixFormat, 1);
600 // }
601
602 if ( FileName_2eFit != "" ) {
603 FStackMatrix
604 IntFai(nFit, nAo*nAo, &Mem);
605 MakeFittingIntegrals(IntFai.pData, Orbs, Orbs, &*pOrbBasis, &*pFitBasis, Mem);
606 WriteMatrixtoFile2(FileName_2eFit, IntFai, "2e-(F|rs)", MatrixFormat, 1);
607 }
608
609 if ( BasisName_Orbital2 != "" && (FileName_Overlap2 != "" || FileName_Overlap12 != "") ) {
610 // make overlap/stuff matrices for overlap with second basis.
611 FBasisSetPtr
612 pOrbBasis2 = new FBasisSet(*pAtoms, BASIS_Guess);
613 uint
614 nAo2 = pOrbBasis2->nFn();
615 if ( FileName_Overlap2 != "" ) {
616 FStackMatrix
617 S2(nAo2, nAo2, &Mem);
618 pAtoms->MakeOverlapMatrix(S2, *pOrbBasis2, *pOrbBasis2, Mem);
619 WriteMatrixtoFile2(FileName_Overlap2, S2, "Overlap/<basis2|basis2>", MatrixFormat, 1);
620 }
621 if ( FileName_Overlap12 != "" ) {
622 FStackMatrix
623 S12(nAo, nAo2, &Mem);
624 pAtoms->MakeOverlapMatrix(S12, *pOrbBasis, *pOrbBasis2, Mem);
625 WriteMatrixtoFile2(FileName_Overlap12, S12, "Overlap/<basis1|basis2>", MatrixFormat, 1);
626 }
627 }
628
629 #ifdef HAVE_GRID_KERNEL
630 if ( FileName_InputOrbitals != "" ) {
631 FArrayNpy
632 Grid, Orbs;
633 ReadNpy(Grid, FileName_GridCoords);
634 ReadNpy(Orbs, FileName_InputOrbitals);
635 if ( Grid.Rank() != 2 || Grid.Shape[0] != 3 )
636 throw std::runtime_error("input grid array must have rank 2 and shape (3,*).");
637 if ( Orbs.Rank() != 2 || Orbs.Shape[0] != nAo )
638 throw std::runtime_error("input orbital value array must have rank 2 and shape (nAo,*), where nAo is the number of functions in --basis-orb.");
639
640 uint const
641 nDerivativeComps_[] = {1,4,10},
642 nGrid = Grid.Shape[1],
643 nComps = nDerivativeComps_[GridDxOrder];
644 TArray<double>
645 GridValues(nAo * nComps * nGrid);
646 FMatrixView
647 Orb_(&Orbs.Data[0], Orbs.Shape[0], Orbs.Shape[1], Orbs.Strides[0], Orbs.Strides[1]),
648 Grid1_(&Grid.Data[0], Grid.Shape[0], Grid.Shape[1], Grid.Strides[0], Grid.Strides[1]);
649 FStackMatrix
650 Grid_(Grid.Shape[0], Grid.Shape[1], &Mem);
651 Move(Grid_, Grid1_); // <- copy over the array to get rid of funky strides.
652 GridValues.clear_data();
653 MakeGridValues(&GridValues[0], Grid_, Orb_, GridDxOrder, pOrbBasis.get(), Mem);
654 FMatrixView
655 GridValues_(&GridValues[0], nComps*Grid.Shape[1], Orbs.Shape[1]);
656 WriteMatrixtoFile2(FileName_GridValues, GridValues_, "Orbitals on grid: (nGridPt x nDerivComp) x nOrb", MatrixFormat, 1);
657 }
658 #endif
659 xout << "\n";
660 xout << format(pResultFmt) % "Nuclear repulsion energy" % pAtoms->NuclearRepulsionEnergy();
661
662 xout.flush();
663 return 0;
664 };
665
666
667 int main(int argc, char *argv[])
668 {
669 // return mainWheHeehee();
670 return main_integral_export(argc, argv);
671 };
672
673 #endif
674