31 #include "MPIchemps2.h" 41 #ifdef CHEMPS2_MPI_COMPILATION 44 const bool am_i_master =
true;
54 successful_solve =
false;
56 if (( am_i_master ) && ( docc != NULL ) && ( socc != NULL )){
58 for (
int irrep = 0; irrep < num_irreps-1; irrep++ ){ cout << docc[ irrep ] <<
" , "; }
59 cout << docc[ num_irreps - 1 ] <<
" ]" << endl;
61 for (
int irrep = 0; irrep < num_irreps-1; irrep++ ){ cout << socc[ irrep ] <<
" , "; }
62 cout << socc[ num_irreps - 1 ] <<
" ]" << endl;
65 for (
int irrep = 0; irrep < num_irreps; irrep++ ){
66 const int norb_in = nocc[ irrep ] + ndmrg[ irrep ] + nvirt[ irrep ];
68 if (( norb_ham != norb_in ) && ( am_i_master )){
69 cout <<
"CASSCF::CASSCF : nocc[" << irrep <<
"] + ndmrg[" << irrep <<
"] + nvirt[" << irrep <<
"] = " << norb_in
70 <<
" and in the Hamiltonian norb[" << irrep <<
"] = " << norb_ham <<
"." << endl;
72 assert( norb_ham == norb_in );
80 DMRG1DM =
new double[nOrbDMRG * nOrbDMRG];
81 DMRG2DM =
new double[nOrbDMRG * nOrbDMRG * nOrbDMRG * nOrbDMRG];
91 if (( docc != NULL ) && ( socc != NULL )){ checkHF( docc, socc ); }
93 cout <<
"DMRGSCF::setupStart : Number of variables in the x-matrix = " << unitary->getNumVariablesX() << endl;
96 this->tmp_folder = new_tmp_folder;
121 for (
int i1 = 0; i1 < LAS; i1++ ){
122 for (
int i2 = 0; i2 < LAS; i2++ ){
123 for (
int i3 = 0; i3 < LAS; i3++ ){
124 for (
int i4 = 0; i4 < LAS; i4++ ){
126 two_dm[ i1 + LAS * ( i2 + LAS * ( i3 + LAS * i4 ) ) ] += theDMRG2DM->
getTwoDMA_HAM( i1, i2, i3, i4 );
136 #ifdef CHEMPS2_MPI_COMPILATION 139 const bool am_i_master =
true;
143 const double prefactor = 1.0 / ( num_elec - 1 );
144 for (
int cnt1 = 0; cnt1 < LAS; cnt1++ ){
145 for (
int cnt2 = cnt1; cnt2 < LAS; cnt2++ ){
147 for (
int sum = 0; sum < LAS; sum++ ){ value += two_dm[ cnt1 + LAS * ( sum + LAS * ( cnt2 + LAS * sum ) ) ]; }
148 one_dm[ cnt1 + LAS * cnt2 ] = prefactor * value;
149 one_dm[ cnt2 + LAS * cnt1 ] = one_dm[ cnt1 + LAS * cnt2 ];
154 #ifdef CHEMPS2_MPI_COMPILATION 155 MPIchemps2::broadcast_array_double( one_dm, LAS * LAS, MPI_CHEMPS2_MASTER );
164 const int size = tot_dmrg * tot_dmrg;
166 for (
int cnt = 0; cnt < size; cnt++ ){ eigenvecs[ cnt ] = 0.0; }
168 for (
int irrep = 0; irrep < n_irreps; irrep++ ){
170 const int NDMRG = idx->
getNDMRG( irrep );
173 double * Ublock = umat->
getBlock( irrep );
174 double * Eblock = eigenvecs + passed * ( 1 + tot_dmrg );
176 for (
int row = 0; row < NDMRG; row++ ){
177 for (
int col = 0; col < NDMRG; col++ ){
178 Eblock[ row + tot_dmrg * col ] = Ublock[ col + NDMRG * row ];
190 void CheMPS2::CASSCF::rotateOldToNew(
DMRGSCFmatrix * myMatrix ){
192 for (
int irrep = 0; irrep < num_irreps; irrep++ ){
194 int NORB = iHandler->
getNORB( irrep );
196 double * Umat = unitary->
getBlock( irrep );
197 double * work = theQmatWORK->
getBlock( irrep );
198 double * block = myMatrix->
getBlock( irrep );
203 dgemm_( ¬rans, ¬rans, &NORB, &NORB, &NORB, &one, Umat, &NORB, block, &NORB, &
set, work, &NORB );
204 dgemm_( ¬rans, &trans, &NORB, &NORB, &NORB, &one, work, &NORB, Umat, &NORB, &
set, block, &NORB );
212 for (
int irrepQ = 0; irrepQ < num_irreps; irrepQ++ ){
214 const int linearsizeQ = iHandler->
getNORB( irrepQ );
215 const int triangsizeQ = ( linearsizeQ * ( linearsizeQ + 1 ) ) / 2;
218 #pragma omp parallel for schedule(static) 219 for (
int combinedindex = 0; combinedindex < triangsizeQ; combinedindex++ ){
222 const int rowQ = myindices[ 0 ];
223 const int colQ = myindices[ 1 ];
227 for (
int irrepN = 0; irrepN < num_irreps; irrepN++ ){
228 const int linearsizeN = iHandler->
getNORB( irrepN );
229 for (
int rowN = 0; rowN < linearsizeN; rowN++ ){
231 value += density->
get( irrepN, rowN, rowN ) * ( VMAT_ORIG->
get( irrepQ, irrepN, irrepQ, irrepN, rowQ, rowN, colQ, rowN )
232 - 0.5 * VMAT_ORIG->
get( irrepQ, irrepQ, irrepN, irrepN, rowQ, colQ, rowN, rowN ) );
234 for (
int colN = rowN + 1; colN < linearsizeN; colN++ ){
236 value += density->
get( irrepN, rowN, colN ) * ( 2 * VMAT_ORIG->
get( irrepQ, irrepN, irrepQ, irrepN, rowQ, rowN, colQ, colN )
237 - 0.5 * VMAT_ORIG->
get( irrepQ, irrepQ, irrepN, irrepN, rowQ, colQ, rowN, colN )
238 - 0.5 * VMAT_ORIG->
get( irrepQ, irrepQ, irrepN, irrepN, rowQ, colQ, colN, rowN ) );
244 result->
set( irrepQ, rowQ, colQ, value );
245 result->
set( irrepQ, colQ, rowQ, value );
252 void CheMPS2::CASSCF::buildQmatOCC(){
254 #ifdef CHEMPS2_MPI_COMPILATION 257 const bool am_i_master =
true;
261 for (
int irrep = 0; irrep < num_irreps; irrep++ ){
263 int NORB = iHandler->
getNORB( irrep );
265 int NOCC = iHandler->
getNOCC( irrep );
270 double * Umat = unitary->
getBlock( irrep );
271 double * work = theQmatWORK->
getBlock( irrep );
272 dgemm_( &trans, ¬rans, &NORB, &NORB, &NOCC, &two, Umat, &NORB, Umat, &NORB, &
set, work, &NORB );
275 constructCoulombAndExchangeMatrixInOrigIndices( theQmatWORK, theQmatOCC );
276 rotateOldToNew( theQmatOCC );
279 #ifdef CHEMPS2_MPI_COMPILATION 280 theQmatOCC->broadcast( MPI_CHEMPS2_MASTER );
285 void CheMPS2::CASSCF::buildQmatACT(){
287 #ifdef CHEMPS2_MPI_COMPILATION 290 const bool am_i_master =
true;
294 for (
int irrep = 0; irrep < num_irreps; irrep++ ){
296 int NORB = iHandler->
getNORB( irrep );
298 int NACT = iHandler->
getNDMRG( irrep );
303 double * Umat = unitary->
getBlock( irrep ) + iHandler->
getNOCC( irrep );
304 double * work = theQmatWORK->
getBlock( irrep );
305 double * work2 = theQmatACT->
getBlock( irrep );
306 double * RDM = DMRG1DM + iHandler->
getDMRGcumulative( irrep ) * ( 1 + nOrbDMRG );
307 dgemm_( &trans, ¬rans, &NORB, &NACT, &NACT, &one, Umat, &NORB, RDM, &nOrbDMRG, &
set, work2, &NORB );
308 dgemm_( ¬rans, ¬rans, &NORB, &NORB, &NACT, &one, work2, &NORB, Umat, &NORB, &
set, work, &NORB );
311 constructCoulombAndExchangeMatrixInOrigIndices( theQmatWORK, theQmatACT );
312 rotateOldToNew( theQmatACT );
315 #ifdef CHEMPS2_MPI_COMPILATION 316 theQmatACT->broadcast( MPI_CHEMPS2_MASTER );
321 void CheMPS2::CASSCF::buildTmatrix(){
323 #ifdef CHEMPS2_MPI_COMPILATION 326 const bool am_i_master =
true;
330 for (
int irrep = 0; irrep < num_irreps; irrep++ ){
331 const int NumORB = iHandler->
getNORB( irrep );
332 for (
int row = 0; row < NumORB; row++ ){
333 for (
int col = 0; col < NumORB; col++ ){
334 theTmatrix->
set( irrep, row, col, TMAT_ORIG->
get( irrep, row, col ) );
338 rotateOldToNew( theTmatrix );
341 #ifdef CHEMPS2_MPI_COMPILATION 342 theTmatrix->broadcast( MPI_CHEMPS2_MASTER );
347 void CheMPS2::CASSCF::fillConstAndTmatDMRG(
Hamiltonian * HamDMRG )
const{
350 double constant = NUCL_ORIG;
351 for (
int irrep = 0; irrep < num_irreps; irrep++ ){
352 const int NOCC = iHandler->
getNOCC( irrep );
353 for (
int occ = 0; occ < NOCC; occ++ ){
354 constant += ( 2 * theTmatrix->
get( irrep, occ, occ )
355 + theQmatOCC->
get( irrep, occ, occ ) );
361 for (
int irrep = 0; irrep < num_irreps; irrep++ ){
363 const int NACT = iHandler->
getNDMRG( irrep );
364 const int NOCC = iHandler->
getNOCC( irrep );
365 for (
int cnt1 = 0; cnt1 < NACT; cnt1++ ){
366 for (
int cnt2 = cnt1; cnt2 < NACT; cnt2++ ){
367 HamDMRG->
setTmat( JUMP + cnt1, JUMP + cnt2, ( theTmatrix->
get( irrep, NOCC + cnt1, NOCC + cnt2 )
368 + theQmatOCC->
get( irrep, NOCC + cnt1, NOCC + cnt2 ) ) );
383 for (
int irrep = 0; irrep < n_irreps; irrep++ ){
385 const int NOCC = idx->
getNOCC( irrep );
386 const int NACT = idx->
getNDMRG( irrep );
389 for (
int orb = 0; orb < NOCC; orb++ ){
390 result->
set( irrep, orb, orb, 2.0 );
394 for (
int row = 0; row < NACT; row++ ){
395 for (
int col = 0; col < NACT; col++ ){
396 result->
set( irrep, NOCC + row, NOCC + col, origin[ passed + row + tot_dmrg * ( passed + col ) ] );
403 assert( passed == tot_dmrg );
412 for (
int cnt = 0; cnt < tot_dmrg * tot_dmrg; cnt++ ){ result[ cnt ] = 0.0; }
415 for (
int irrep = 0; irrep < n_irreps; irrep++ ){
417 const int NOCC = idx->
getNOCC( irrep );
418 const int NACT = idx->
getNDMRG( irrep );
420 for (
int row = 0; row < NACT; row++ ){
421 for (
int col = 0; col < NACT; col++ ){
422 result[ passed + row + tot_dmrg * ( passed + col ) ] = origin->
get( irrep, NOCC + row, NOCC + col );
429 assert( passed == tot_dmrg );
435 #ifdef CHEMPS2_MPI_COMPILATION 438 const bool am_i_master =
true;
446 for (
int irrep = 0; irrep < n_irreps; irrep++ ){
448 int NTOTAL = idx->
getNORB( irrep );
449 int NROTATE = (( space ==
'O' ) ? idx->
getNOCC( irrep ) : (( space ==
'A' ) ? idx->
getNDMRG( irrep ) : idx->
getNVIRT( irrep )));
450 int NSHIFT = (( space ==
'O' ) ? 0 : (( space ==
'A' ) ? idx->
getNOCC( irrep ) : NTOTAL - NROTATE ));
456 for (
int row = 0; row < NROTATE; row++ ){
457 for (
int col = 0; col < NROTATE; col++ ){
458 work1[ row + NROTATE * col ] = Mat->
get( irrep, NSHIFT + row, NSHIFT + col );
464 int size = max( 3 * NROTATE - 1, NROTATE * NROTATE );
465 dsyev_( &jobz, &uplo, &NROTATE, work1, &NROTATE, work2 + size, work2, &size, &info );
470 for (
int col = 0; col < NROTATE / 2; col++ ){
471 for (
int row = 0; row < NROTATE; row++ ){
472 const double temp = work1[ row + NROTATE * ( NROTATE - 1 - col ) ];
473 work1[ row + NROTATE * ( NROTATE - 1 - col ) ] = work1[ row + NROTATE * col ];
474 work1[ row + NROTATE * col ] = temp;
480 double * umatrix = Umat->
getBlock( irrep ) + NSHIFT;
481 for (
int row = 0; row < NROTATE; row++ ){
482 for (
int col = 0; col < NTOTAL; col++ ){
483 work2[ row + NROTATE * col ] = umatrix[ row + NTOTAL * col ];
490 dgemm_( &trans, ¬rans, &NROTATE, &NTOTAL, &NROTATE, &one, work1, &NROTATE, work2, &NROTATE, &
set, umatrix, &NTOTAL );
494 if ( two_dm != NULL ){ rotate_active_space_object( 4, two_dm, work2, work1, tot_dmrg, NJUMP, NROTATE ); }
495 if ( three_dm != NULL ){ rotate_active_space_object( 6, three_dm, work2, work1, tot_dmrg, NJUMP, NROTATE ); }
496 if ( contract != NULL ){ rotate_active_space_object( 6, contract, work2, work1, tot_dmrg, NJUMP, NROTATE ); }
502 #ifdef CHEMPS2_MPI_COMPILATION 503 Umat->broadcast( MPI_CHEMPS2_MASTER );
505 if ( two_dm != NULL ){ MPIchemps2::broadcast_array_double( two_dm, tot_dmrg * tot_dmrg * tot_dmrg * tot_dmrg, MPI_CHEMPS2_MASTER ); }
506 if ( three_dm != NULL ){ MPIchemps2::broadcast_array_double( three_dm, tot_dmrg * tot_dmrg * tot_dmrg * tot_dmrg * tot_dmrg * tot_dmrg, MPI_CHEMPS2_MASTER ); }
507 if ( contract != NULL ){ MPIchemps2::broadcast_array_double( contract, tot_dmrg * tot_dmrg * tot_dmrg * tot_dmrg * tot_dmrg * tot_dmrg, MPI_CHEMPS2_MASTER ); }
513 void CheMPS2::CASSCF::rotate_active_space_object(
const int num_indices,
double *
object,
double * work,
double * rotation,
const int LAS,
const int NJUMP,
const int NROTATE ){
515 assert( num_indices >= 2 );
516 assert( num_indices <= 6 );
522 LAS * LAS * LAS * LAS,
523 LAS * LAS * LAS * LAS * LAS,
524 LAS * LAS * LAS * LAS * LAS * LAS };
526 for (
int rot_index = num_indices - 1; rot_index >= 0; rot_index-- ){
527 for (
int block = 0; block < power[ num_indices - 1 - rot_index ]; block++ ){
528 double * mat =
object + power[ rot_index ] * NJUMP + power[ rot_index + 1 ] * block;
529 int ROTDIM = NROTATE;
533 dgemm_( ¬rans, ¬rans, power + rot_index, &ROTDIM, &ROTDIM, &one, mat, power + rot_index, rotation, &ROTDIM, &
set, work, power + rot_index );
534 int size = power[ rot_index ] * NROTATE;
536 dcopy_( &size, work, &inc1, mat, &inc1 );
int getNORB(const int irrep) const
Get the number of orbitals for an irrep.
double * getBlock(const int irrep)
Get a matrix block.
bool setGroup(const int nGroup)
Set the group.
int getNumberOfIrreps() const
Get the number of irreps for the currently activated group.
static void copy_active(double *origin, DMRGSCFmatrix *result, const DMRGSCFindices *idx, const bool one_rdm)
Copy a one-orbital quantity from array format to DMRGSCFmatrix format.
void setTmat(const int index1, const int index2, const double val)
Set a Tmat element.
double get(const int irrep_i, const int irrep_j, const int irrep_k, const int irrep_l, const int i, const int j, const int k, const int l) const
Get an element.
static int mpi_rank()
Get the rank of this MPI process.
double getVmat(const int index1, const int index2, const int index3, const int index4) const
Get a Vmat element.
int getDMRGcumulative(const int irrep) const
Get the cumulative number of active orbitals for an irrep.
void setEconst(const double val)
Set the constant energy.
int getGroupNumber() const
Get the group number.
void set(const int irrep, const int p, const int q, const double val)
Set an element.
static void copy2DMover(TwoDM *theDMRG2DM, const int LAS, double *two_dm)
Copy over the DMRG 2-RDM.
double getTmat(const int index1, const int index2) const
Get a Tmat element.
static void block_diagonalize(const char space, const DMRGSCFmatrix *Mat, DMRGSCFunitary *Umat, double *work1, double *work2, const DMRGSCFindices *idx, const bool invert, double *two_dm, double *three_dm, double *contract)
Block-diagonalize Mat.
double getTwoDMA_HAM(const int cnt1, const int cnt2, const int cnt3, const int cnt4) const
Get a 2DM_A term, using the HAM indices.
static void fillLocalizedOrbitalRotations(DMRGSCFunitary *umat, DMRGSCFindices *idx, double *eigenvecs)
From an Edmiston-Ruedenberg active space rotation, fetch the eigenvectors and store them in eigenvecs...
void Print() const
Print my contents.
int get_irrep_size(const int irrep) const
Get a given irrep size.
int get_num_irreps()
Get the number of irreps.
double get(const int irrep, const int p, const int q) const
Get an element.
static void invert_triangle_two(const int global, int *result)
Triangle function for two variables.
static void setDMRG1DM(const int num_elec, const int LAS, double *one_dm, double *two_dm)
Construct the 1-RDM from the 2-RDM.
double get(const int irrep, const int i, const int j) const
Get an element.
int getNDMRG(const int irrep) const
Get the number of active orbitals for an irrep.
virtual ~CASSCF()
Destructor.
int getNGroup() const
Get the group number.
int getNOCC(const int irrep) const
Get the number of occupied orbitals for an irrep.
double getEconst() const
Get the constant energy.
int getNVIRT(const int irrep) const
Get the number of virtual orbitals for an irrep.
void clear()
Clear the matrix.
int getL() const
Get the number of orbitals.
CASSCF(Hamiltonian *ham_in, int *docc, int *socc, int *nocc, int *ndmrg, int *nvirt, const string tmp_folder=CheMPS2::defaultTMPpath)
Constructor.
int getNirreps() const
Get the number of irreps.