double CheMPS2::DMRG::solve_site( const int index, const double dvdson_rtol, const double noise_level, const int virtual_dimension, const bool am_i_master, const bool moving_right, const bool change ){ struct timeval start, end; // Construct two-site object S. Each MPI process joins the MPS tensors. Before a matrix-vector multiplication the vector is broadcasted anyway. gettimeofday( &start, NULL ); Sobject * denS = new Sobject( index, denBK ); denS->Join( MPS[ index ], MPS[ index + 1 ] ); gettimeofday( &end, NULL ); timings[ CHEMPS2_TIME_S_JOIN ] += ( end.tv_sec - start.tv_sec ) + 1e-6 * ( end.tv_usec - start.tv_usec ); // Feed everything to the solver. Each MPI process returns the correct energy. Only MPI_CHEMPS2_MASTER has the correct denS solution. gettimeofday( &start, NULL ); Heff Solver( denBK, Prob, dvdson_rtol ); double ** VeffTilde = NULL; if ( Exc_activated ){ VeffTilde = prepare_excitations( denS ); } double Energy = Solver.SolveDAVIDSON( denS, Ltensors, Atensors, Btensors, Ctensors, Dtensors, S0tensors, S1tensors, F0tensors, F1tensors, Qtensors, Xtensors, nStates - 1, VeffTilde ); Energy += Prob->gEconst(); if ( Exc_activated ){ cleanup_excitations( VeffTilde ); } gettimeofday( &end, NULL ); timings[ CHEMPS2_TIME_S_SOLVE ] += ( end.tv_sec - start.tv_sec ) + 1e-6 * ( end.tv_usec - start.tv_usec ); // Decompose the S-object. MPI_CHEMPS2_MASTER decomposes denS. Each MPI process returns the correct discWeight. Each MPI process has the new MPS tensors set. gettimeofday( &start, NULL ); if (( noise_level > 0.0 ) && ( am_i_master )){ denS->addNoise( noise_level ); } const double discWeight = denS->Split( MPS[ index ], MPS[ index + 1 ], virtual_dimension, moving_right, change ); delete denS; if ( discWeight > MaxDiscWeightLastSweep ){ MaxDiscWeightLastSweep = discWeight; } gettimeofday( &end, NULL ); timings[ CHEMPS2_TIME_S_SPLIT ] += ( end.tv_sec - start.tv_sec ) + 1e-6 * ( end.tv_usec - start.tv_usec ); return Energy; }
void CheMPS2::DMRG::solve_fock( const int dmrg_orb1, const int dmrg_orb2, const double alpha, const double beta ){ #ifdef CHEMPS2_MPI_COMPILATION const bool am_i_master = ( MPIchemps2::mpi_rank() == MPI_CHEMPS2_MASTER ); #else const bool am_i_master = true; #endif if ( dmrg_orb1 == dmrg_orb2 ){ MPS[ dmrg_orb1 ]->number_operator( 2 * alpha, beta ); // alpha * ( E_zz + E_zz ) + beta * 1 return; } double sweep_inproduct = 0.0; if ( dmrg_orb1 + 1 == dmrg_orb2 ){ Sobject * newS = new Sobject( dmrg_orb1, denBK ); if ( am_i_master ){ Sobject * oldS = new Sobject( dmrg_orb1, denBK ); oldS->Join( MPS[ dmrg_orb1 ], MPS[ dmrg_orb2 ] ); sweep_inproduct = Excitation::matvec( denBK, denBK, dmrg_orb1, dmrg_orb2, alpha, alpha, beta, newS, oldS, NULL, NULL, NULL ); delete oldS; } // MPI_CHEMPS2_MASTER decomposes newS. Each MPI process returns the correct discarded_weight. Each MPI process has the new MPS tensors set. const double discarded_weight = newS->Split( MPS[ dmrg_orb1 ], MPS[ dmrg_orb2 ], OptScheme->get_D( OptScheme->get_number() - 1 ), true, true ); delete newS; } if ( dmrg_orb1 + 1 < dmrg_orb2 ){ SyBookkeeper * newBK = denBK; denBK = new SyBookkeeper( *newBK ); newBK->restart( dmrg_orb1 + 1, dmrg_orb2, OptScheme->get_D( OptScheme->get_number() - 1 ) ); TensorT ** old_mps = new TensorT * [ L ]; for ( int orbital = dmrg_orb1; orbital <= dmrg_orb2; orbital++ ){ old_mps[ orbital ] = MPS[ orbital ]; old_mps[ orbital ]->sBK( denBK ); MPS[ orbital ] = new TensorT( orbital, newBK ); MPS[ orbital ]->random(); left_normalize( MPS[ orbital ], NULL ); // MPI_CHEMPS2_MASTER broadcasts MPS[ orbital ] ( left-normalized ). } TensorO ** overlaps = NULL; TensorL ** regular = NULL; TensorL ** trans = NULL; if ( am_i_master ){ overlaps = new TensorO*[ L - 1 ]; regular = new TensorL*[ L - 1 ]; trans = new TensorL*[ L - 1 ]; for ( int cnt = 0; cnt < L - 1; cnt++ ){ overlaps[ cnt ] = NULL; regular[ cnt ] = NULL; trans[ cnt ] = NULL; } for ( int orbital = dmrg_orb1; orbital < dmrg_orb2 - 1; orbital++ ){ solve_fock_update_helper( orbital, dmrg_orb1, dmrg_orb2, true, MPS, old_mps, newBK, denBK, overlaps, regular, trans ); } } // Sweeps bool change = false; for ( int instruction = 0; instruction < OptScheme->get_number(); instruction++ ){ int num_iterations = 0; double previous_inproduct = sweep_inproduct + 10 * OptScheme->get_energy_conv( instruction ); while (( fabs( sweep_inproduct - previous_inproduct ) > OptScheme->get_energy_conv( instruction ) ) && ( num_iterations < OptScheme->get_max_sweeps( instruction ) )){ { const double noise_level = fabs( OptScheme->get_noise_prefactor( instruction ) ) * MaxDiscWeightLastSweep; MaxDiscWeightLastSweep = 0.0; for ( int index = dmrg_orb2 - 1; index > dmrg_orb1; index-- ){ Sobject * newS = new Sobject( index, newBK ); if ( am_i_master ){ Sobject * oldS = new Sobject( index, denBK ); oldS->Join( old_mps[ index ], old_mps[ index + 1 ] ); sweep_inproduct = Excitation::matvec( newBK, denBK, dmrg_orb1, dmrg_orb2, alpha, alpha, beta, newS, oldS, overlaps, regular, trans ); delete oldS; if ( noise_level > 0.0 ){ newS->addNoise( noise_level ); } } // MPI_CHEMPS2_MASTER decomposes newS. Each MPI process returns the correct discarded_weight. Each MPI process has the new MPS tensors set. const double discarded_weight = newS->Split( MPS[ index ], MPS[ index + 1 ], OptScheme->get_D( instruction ), false, change ); if ( discarded_weight > MaxDiscWeightLastSweep ){ MaxDiscWeightLastSweep = discarded_weight; } delete newS; if ( am_i_master ){ solve_fock_update_helper( index, dmrg_orb1, dmrg_orb2, false, MPS, old_mps, newBK, denBK, overlaps, regular, trans ); } } } change = true; { const double noise_level = fabs( OptScheme->get_noise_prefactor( instruction ) ) * MaxDiscWeightLastSweep; MaxDiscWeightLastSweep = 0.0; for ( int index = dmrg_orb1; index < dmrg_orb2 - 1; index++ ){ Sobject * newS = new Sobject( index, newBK ); if ( am_i_master ){ Sobject * oldS = new Sobject( index, denBK ); oldS->Join( old_mps[ index ], old_mps[ index + 1 ] ); sweep_inproduct = Excitation::matvec( newBK, denBK, dmrg_orb1, dmrg_orb2, alpha, alpha, beta, newS, oldS, overlaps, regular, trans ); delete oldS; if ( noise_level > 0.0 ){ newS->addNoise( noise_level ); } } // MPI_CHEMPS2_MASTER decomposes newS. Each MPI process returns the correct discarded_weight. Each MPI process has the new MPS tensors set. const double discarded_weight = newS->Split( MPS[ index ], MPS[ index + 1 ], OptScheme->get_D( instruction ), true, change ); if ( discarded_weight > MaxDiscWeightLastSweep ){ MaxDiscWeightLastSweep = discarded_weight; } delete newS; if ( am_i_master ){ solve_fock_update_helper( index, dmrg_orb1, dmrg_orb2, true, MPS, old_mps, newBK, denBK, overlaps, regular, trans ); } } } #ifdef CHEMPS2_MPI_COMPILATION CheMPS2::MPIchemps2::broadcast_array_double( &sweep_inproduct, 1, MPI_CHEMPS2_MASTER ); #endif previous_inproduct = sweep_inproduct; num_iterations++; } } if ( am_i_master ){ for ( int index = 0; index < L - 1; index++ ){ if ( overlaps[ index ] != NULL ){ delete overlaps[ index ]; } if ( regular[ index ] != NULL ){ delete regular[ index ]; } if ( trans[ index ] != NULL ){ delete trans[ index ]; } } delete [] overlaps; delete [] regular; delete [] trans; } for ( int orbital = dmrg_orb1; orbital <= dmrg_orb2; orbital++ ){ delete old_mps[ orbital ]; } delete [] old_mps; delete denBK; denBK = newBK; } if ( am_i_master ){ const double rdm_inproduct = 2 * alpha * the2DM->get1RDM_DMRG( dmrg_orb1, dmrg_orb2 ) + beta; cout << "DMRG::solve_fock : Accuracy = " << fabs( sweep_inproduct / ( Prob->gTwoS() + 1 ) - rdm_inproduct ) << endl; } }