33 #include "MPIchemps2.h" 34 #include "Excitation.h" 43 struct timeval start, end;
44 gettimeofday( &start, NULL );
46 assert( the3DM != NULL );
48 symm_4rdm_helper( output, Y, Z, 1.0, 1.0,
false, 0.5 );
49 symm_4rdm_helper( output, Y, Z, 1.0, 0.0,
true, -0.5 );
51 for (
int r = 0; r < L; r++ ){
52 for (
int q = 0; q < L; q++ ){
53 for (
int p = 0; p < L; p++ ){
54 for (
int k = 0; k < L; k++ ){
55 for (
int j = 0; j < L; j++ ){
56 for (
int i = 0; i < L; i++ ){
57 output[ i + L * ( j + L * ( k + L * ( p + L * ( q + L * r )))) ] -= 0.5 * the3DM->
get_ham_index( i, j, k, p, q, r );
59 output[ Y + L * ( j + L * ( k + L * ( p + L * ( q + L * r )))) ] -= 0.5 * the3DM->
get_ham_index( Z, j, k, p, q, r );
60 output[ Z + L * ( j + L * ( k + L * ( p + L * ( q + L * r )))) ] -= 0.5 * the3DM->
get_ham_index( Y, j, k, p, q, r );
61 output[ j + L * ( Y + L * ( k + L * ( p + L * ( q + L * r )))) ] -= 0.5 * the3DM->
get_ham_index( j, Z, k, p, q, r );
62 output[ j + L * ( Z + L * ( k + L * ( p + L * ( q + L * r )))) ] -= 0.5 * the3DM->
get_ham_index( j, Y, k, p, q, r );
63 output[ j + L * ( k + L * ( Y + L * ( p + L * ( q + L * r )))) ] -= 0.5 * the3DM->
get_ham_index( j, k, Z, p, q, r );
64 output[ j + L * ( k + L * ( Z + L * ( p + L * ( q + L * r )))) ] -= 0.5 * the3DM->
get_ham_index( j, k, Y, p, q, r );
65 output[ j + L * ( k + L * ( p + L * ( Y + L * ( q + L * r )))) ] -= 0.5 * the3DM->
get_ham_index( j, k, p, Z, q, r );
66 output[ j + L * ( k + L * ( p + L * ( Z + L * ( q + L * r )))) ] -= 0.5 * the3DM->
get_ham_index( j, k, p, Y, q, r );
67 output[ j + L * ( k + L * ( p + L * ( q + L * ( Y + L * r )))) ] -= 0.5 * the3DM->
get_ham_index( k, j, p, Z, q, r );
68 output[ j + L * ( k + L * ( p + L * ( q + L * ( Z + L * r )))) ] -= 0.5 * the3DM->
get_ham_index( k, j, p, Y, q, r );
69 output[ j + L * ( k + L * ( p + L * ( q + L * ( r + L * Y )))) ] -= 0.5 * the3DM->
get_ham_index( p, j, k, Z, q, r );
70 output[ j + L * ( k + L * ( p + L * ( q + L * ( r + L * Z )))) ] -= 0.5 * the3DM->
get_ham_index( p, j, k, Y, q, r );
79 gettimeofday( &end, NULL );
80 const double elapsed = ( end.tv_sec - start.tv_sec ) + 1e-6 * ( end.tv_usec - start.tv_usec );
81 #ifdef CHEMPS2_MPI_COMPILATION 84 { cout <<
"CheMPS2::DMRG::Symm4RDM( " << Y <<
" , " << Z <<
" ) : Elapsed wall time = " << elapsed <<
" seconds." << endl; }
88 void CheMPS2::DMRG::symm_4rdm_helper(
double * output,
const int ham_orb1,
const int ham_orb2,
const double alpha,
const double beta,
const bool add,
const double factor ){
91 assert( ham_orb1 >= 0 );
92 assert( ham_orb2 >= 0 );
93 assert( ham_orb1 < L );
94 assert( ham_orb2 < L );
95 const int first_dmrg_orb = (( Prob->
gReorder() ) ? Prob->
gf1( ham_orb1 ) : ham_orb1 );
96 const int second_dmrg_orb = (( Prob->
gReorder() ) ? Prob->
gf1( ham_orb2 ) : ham_orb2 );
97 const int dmrg_orb1 = (( first_dmrg_orb <= second_dmrg_orb ) ? first_dmrg_orb : second_dmrg_orb );
98 const int dmrg_orb2 = (( first_dmrg_orb <= second_dmrg_orb ) ? second_dmrg_orb : first_dmrg_orb );
102 if ( dmrg_orb1 != dmrg_orb2 ){ denBK =
new SyBookkeeper( *oldBK ); }
104 for (
int orbital = 0; orbital < L; orbital++ ){
105 backup_mps[ orbital ] = MPS[ orbital ];
106 MPS[ orbital ] =
new TensorT( orbital, denBK );
107 int totalsize = MPS[ orbital ]->
gKappa2index( MPS[ orbital ]->gNKappa() );
109 dcopy_( &totalsize, backup_mps[ orbital ]->gStorage(), &inc1, MPS[ orbital ]->gStorage(), &inc1 );
111 deleteAllBoundaryOperators();
114 for (
int siteindex = L - 1; siteindex > dmrg_orb2; siteindex-- ){
115 right_normalize( MPS[ siteindex - 1 ], MPS[ siteindex ] );
116 updateMovingLeftSafeFirstTime( siteindex - 1 );
120 solve_fock( dmrg_orb1, dmrg_orb2, alpha, beta );
123 for (
int siteindex = dmrg_orb2; siteindex > 0; siteindex-- ){
124 right_normalize( MPS[ siteindex - 1 ], MPS[ siteindex ] );
125 updateMovingLeftSafeFirstTime( siteindex - 1 );
129 tensor_3rdm_a_J0_doublet =
new Tensor3RDM****[ L - 1 ];
130 tensor_3rdm_a_J1_doublet =
new Tensor3RDM****[ L - 1 ];
131 tensor_3rdm_a_J1_quartet =
new Tensor3RDM****[ L - 1 ];
132 tensor_3rdm_b_J0_doublet =
new Tensor3RDM****[ L - 1 ];
133 tensor_3rdm_b_J1_doublet =
new Tensor3RDM****[ L - 1 ];
134 tensor_3rdm_b_J1_quartet =
new Tensor3RDM****[ L - 1 ];
135 tensor_3rdm_c_J0_doublet =
new Tensor3RDM****[ L - 1 ];
136 tensor_3rdm_c_J1_doublet =
new Tensor3RDM****[ L - 1 ];
137 tensor_3rdm_c_J1_quartet =
new Tensor3RDM****[ L - 1 ];
138 tensor_3rdm_d_J0_doublet =
new Tensor3RDM****[ L - 1 ];
139 tensor_3rdm_d_J1_doublet =
new Tensor3RDM****[ L - 1 ];
140 tensor_3rdm_d_J1_quartet =
new Tensor3RDM****[ L - 1 ];
143 helper3rdm->
fill_site( MPS[ 0 ], Ltensors, F0tensors, F1tensors, S0tensors, S1tensors, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL );
146 for (
int siteindex = 1; siteindex < L; siteindex++ ){
149 left_normalize( MPS[ siteindex - 1 ], MPS[ siteindex ] );
152 update_safe_3rdm_operators( siteindex );
153 updateMovingRightSafe2DM( siteindex - 1 );
156 helper3rdm->
fill_site( MPS[ siteindex ], Ltensors, F0tensors, F1tensors, S0tensors, S1tensors,
157 tensor_3rdm_a_J0_doublet[ siteindex - 1 ], tensor_3rdm_a_J1_doublet[ siteindex - 1 ], tensor_3rdm_a_J1_quartet[ siteindex - 1 ],
158 tensor_3rdm_b_J0_doublet[ siteindex - 1 ], tensor_3rdm_b_J1_doublet[ siteindex - 1 ], tensor_3rdm_b_J1_quartet[ siteindex - 1 ],
159 tensor_3rdm_c_J0_doublet[ siteindex - 1 ], tensor_3rdm_c_J1_doublet[ siteindex - 1 ], tensor_3rdm_c_J1_quartet[ siteindex - 1 ],
160 tensor_3rdm_d_J0_doublet[ siteindex - 1 ], tensor_3rdm_d_J1_doublet[ siteindex - 1 ], tensor_3rdm_d_J1_quartet[ siteindex - 1 ] );
165 #ifdef CHEMPS2_MPI_COMPILATION 171 delete_3rdm_operators( L - 1 );
172 delete [] tensor_3rdm_a_J0_doublet;
173 delete [] tensor_3rdm_a_J1_doublet;
174 delete [] tensor_3rdm_a_J1_quartet;
175 delete [] tensor_3rdm_b_J0_doublet;
176 delete [] tensor_3rdm_b_J1_doublet;
177 delete [] tensor_3rdm_b_J1_quartet;
178 delete [] tensor_3rdm_c_J0_doublet;
179 delete [] tensor_3rdm_c_J1_doublet;
180 delete [] tensor_3rdm_c_J1_quartet;
181 delete [] tensor_3rdm_d_J0_doublet;
182 delete [] tensor_3rdm_d_J1_doublet;
183 delete [] tensor_3rdm_d_J1_quartet;
187 for (
int orbital = 0; orbital < L; orbital++ ){
188 delete MPS[ orbital ];
189 MPS[ orbital ] = backup_mps[ orbital ];
191 delete [] backup_mps;
192 if ( dmrg_orb1 != dmrg_orb2 ){
197 deleteAllBoundaryOperators();
201 void CheMPS2::DMRG::solve_fock(
const int dmrg_orb1,
const int dmrg_orb2,
const double alpha,
const double beta ){
203 #ifdef CHEMPS2_MPI_COMPILATION 206 const bool am_i_master =
true;
209 if ( dmrg_orb1 == dmrg_orb2 ){
214 double sweep_inproduct = 0.0;
216 if ( dmrg_orb1 + 1 == dmrg_orb2 ){
220 oldS->
Join( MPS[ dmrg_orb1 ], MPS[ dmrg_orb2 ] );
221 sweep_inproduct =
Excitation::matvec( denBK, denBK, dmrg_orb1, dmrg_orb2, alpha, alpha, beta, newS, oldS, NULL, NULL, NULL );
225 const double discarded_weight = newS->
Split( MPS[ dmrg_orb1 ], MPS[ dmrg_orb2 ], OptScheme->
get_D( OptScheme->
get_number() - 1 ),
true,
true );
229 if ( dmrg_orb1 + 1 < dmrg_orb2 ){
235 for (
int orbital = dmrg_orb1; orbital <= dmrg_orb2; orbital++ ){
236 old_mps[ orbital ] = MPS[ orbital ];
237 old_mps[ orbital ]->
sBK( denBK );
238 MPS[ orbital ] =
new TensorT( orbital, newBK );
240 left_normalize( MPS[ orbital ], NULL );
247 overlaps =
new TensorO*[ L - 1 ];
248 regular =
new TensorL*[ L - 1 ];
250 for (
int cnt = 0; cnt < L - 1; cnt++ ){
251 overlaps[ cnt ] = NULL;
252 regular[ cnt ] = NULL;
255 for (
int orbital = dmrg_orb1; orbital < dmrg_orb2 - 1; orbital++ ){
256 solve_fock_update_helper( orbital, dmrg_orb1, dmrg_orb2,
true, MPS, old_mps, newBK, denBK, overlaps, regular, trans );
262 for (
int instruction = 0; instruction < OptScheme->
get_number(); instruction++ ){
263 int num_iterations = 0;
264 double previous_inproduct = sweep_inproduct + 10 * OptScheme->
get_energy_conv( instruction );
265 while (( fabs( sweep_inproduct - previous_inproduct ) > OptScheme->
get_energy_conv( instruction ) ) && ( num_iterations < OptScheme->get_max_sweeps( instruction ) )){
267 const double noise_level = fabs( OptScheme->
get_noise_prefactor( instruction ) ) * MaxDiscWeightLastSweep;
268 MaxDiscWeightLastSweep = 0.0;
269 for (
int index = dmrg_orb2 - 1; index > dmrg_orb1; index-- ){
273 oldS->
Join( old_mps[ index ], old_mps[ index + 1 ] );
274 sweep_inproduct =
Excitation::matvec( newBK, denBK, dmrg_orb1, dmrg_orb2, alpha, alpha, beta, newS, oldS, overlaps, regular, trans );
276 if ( noise_level > 0.0 ){ newS->
addNoise( noise_level ); }
279 const double discarded_weight = newS->
Split( MPS[ index ], MPS[ index + 1 ], OptScheme->
get_D( instruction ),
false, change );
280 if ( discarded_weight > MaxDiscWeightLastSweep ){ MaxDiscWeightLastSweep = discarded_weight; }
283 solve_fock_update_helper( index, dmrg_orb1, dmrg_orb2,
false, MPS, old_mps, newBK, denBK, overlaps, regular, trans );
289 const double noise_level = fabs( OptScheme->
get_noise_prefactor( instruction ) ) * MaxDiscWeightLastSweep;
290 MaxDiscWeightLastSweep = 0.0;
291 for (
int index = dmrg_orb1; index < dmrg_orb2 - 1; index++ ){
295 oldS->
Join( old_mps[ index ], old_mps[ index + 1 ] );
296 sweep_inproduct =
Excitation::matvec( newBK, denBK, dmrg_orb1, dmrg_orb2, alpha, alpha, beta, newS, oldS, overlaps, regular, trans );
298 if ( noise_level > 0.0 ){ newS->
addNoise( noise_level ); }
301 const double discarded_weight = newS->
Split( MPS[ index ], MPS[ index + 1 ], OptScheme->
get_D( instruction ),
true, change );
302 if ( discarded_weight > MaxDiscWeightLastSweep ){ MaxDiscWeightLastSweep = discarded_weight; }
305 solve_fock_update_helper( index, dmrg_orb1, dmrg_orb2,
true, MPS, old_mps, newBK, denBK, overlaps, regular, trans );
309 #ifdef CHEMPS2_MPI_COMPILATION 310 CheMPS2::MPIchemps2::broadcast_array_double( &sweep_inproduct, 1, MPI_CHEMPS2_MASTER );
312 previous_inproduct = sweep_inproduct;
318 for (
int index = 0; index < L - 1; index++ ){
319 if ( overlaps[ index ] != NULL ){
delete overlaps[ index ]; }
320 if ( regular[ index ] != NULL ){
delete regular[ index ]; }
321 if ( trans[ index ] != NULL ){
delete trans[ index ]; }
328 for (
int orbital = dmrg_orb1; orbital <= dmrg_orb2; orbital++ ){
delete old_mps[ orbital ]; }
336 const double rdm_inproduct = 2 * alpha * the2DM->
get1RDM_DMRG( dmrg_orb1, dmrg_orb2 ) + beta;
337 cout <<
"DMRG::solve_fock : Accuracy = " << fabs( sweep_inproduct / ( Prob->
gTwoS() + 1 ) - rdm_inproduct ) << endl;
342 void CheMPS2::DMRG::solve_fock_update_helper(
const int index,
const int dmrg_orb1,
const int dmrg_orb2,
const bool moving_right,
TensorT ** new_mps,
TensorT ** old_mps,
SyBookkeeper * new_bk,
SyBookkeeper * old_bk,
TensorO ** overlaps,
TensorL ** regular,
TensorL ** trans ){
344 if ( overlaps[ index ] != NULL ){
delete overlaps[ index ]; }
345 if ( regular[ index ] != NULL ){
delete regular[ index ]; }
346 if ( trans[ index ] != NULL ){
delete trans[ index ]; }
348 const int Idiff = new_bk->
gIrrep( dmrg_orb1 );
349 assert( Idiff == new_bk->
gIrrep( dmrg_orb2 ) );
350 overlaps[ index ] =
new TensorO( index + 1, moving_right, new_bk, old_bk );
351 regular[ index ] =
new TensorL( index + 1, Idiff, moving_right, new_bk, old_bk );
352 trans[ index ] =
new TensorL( index + 1, Idiff, moving_right, old_bk, new_bk );
355 if ( index == dmrg_orb1 ){
356 overlaps[ index ]->create( new_mps[ index ], old_mps[ index ] );
357 regular[ index ]->
create( new_mps[ index ], old_mps[ index ], NULL, NULL );
358 trans[ index ]->
create( old_mps[ index ], new_mps[ index ], NULL, NULL );
362 double * workmem =
new double[ dimL * dimR ];
363 overlaps[ index ]->update( overlaps[ index - 1 ], new_mps[ index ], old_mps[ index ], workmem );
364 regular[ index ]->
update( regular[ index - 1 ], new_mps[ index ], old_mps[ index ], workmem );
365 trans[ index ]->
update( trans[ index - 1 ], old_mps[ index ], new_mps[ index ], workmem );
369 if ( index + 1 == dmrg_orb2 ){
370 overlaps[ index ]->create( new_mps[ index + 1 ], old_mps[ index + 1 ] );
371 regular[ index ]->
create( new_mps[ index + 1 ], old_mps[ index + 1 ], NULL, NULL );
372 trans[ index ]->
create( old_mps[ index + 1 ], new_mps[ index + 1 ], NULL, NULL );
376 double * workmem =
new double[ dimL * dimR ];
377 overlaps[ index ]->update( overlaps[ index + 1 ], new_mps[ index + 1 ], old_mps[ index + 1 ], workmem );
378 regular[ index ]->
update( regular[ index + 1 ], new_mps[ index + 1 ], old_mps[ index + 1 ], workmem );
379 trans[ index ]->
update( trans[ index + 1 ], old_mps[ index + 1 ], new_mps[ index + 1 ], workmem );
double get_energy_conv(const int instruction) const
Get the energy convergence threshold for a particular instruction.
void random()
Fill storage with random numbers 0 < val < 1.
void mpi_allreduce()
Add the 3-RDM elements of all MPI processes.
void update(TensorOperator *previous, TensorT *mps_tensor_up, TensorT *mps_tensor_down, double *workmem)
Clear and update.
void create(TensorT *mps_tensor)
Create a new TensorL.
void Symm4RDM(double *output, const int ham_orb1, const int ham_orb2, const bool last_case)
Obtain the symmetrized 4-RDM terms 0.5 * ( Gamma4_ijkl,pqrt + Gamma4_ijkt,pqrl ) with l and t fixed...
static double matvec(const SyBookkeeper *book_up, const SyBookkeeper *book_down, const int orb1, const int orb2, const double alpha, const double beta, const double gamma, Sobject *S_up, Sobject *S_down, TensorO **overlaps, TensorL **regular, TensorL **trans)
Matrix-vector multiplication S_up = ( alpha * E_{orb1,orb2} + beta * E_{orb2,orb1} + gamma ) x S_down...
double get_noise_prefactor(const int instruction) const
Get the noise prefactor for a particular instruction.
bool gReorder() const
Get whether the Hamiltonian orbitals are reordered for the DMRG calculation.
void correct_higher_multiplicities()
After the whole 3-RDM is filled, a prefactor for higher multiplicities should be applied.
void restart(const int start, const int stop, const int virtual_dim)
Restart by setting the virtual dimensions from boundary start to boundary stop to FCI virtual dimensi...
double Split(TensorT *Tleft, TensorT *Tright, const int virtualdimensionD, const bool movingright, const bool change)
SVD an S-object into 2 TensorT's.
static int mpi_rank()
Get the rank of this MPI process.
void fill_ham_index(const double alpha, const bool add, double *storage, const int last_orb_start, const int last_orb_num)
Perform storage[ :, :, :, :, :, : ] { = or += } alpha * 3-RDM[ :, :, :, :, :, last_orb_start: last_or...
int get_D(const int instruction) const
Get the number of renormalized states for a particular instruction.
int gTwoS() const
Get twice the targeted spin.
int get_number() const
Get the number of instructions.
double get1RDM_DMRG(const int cnt1, const int cnt2) const
Get a 1-RDM term, using the DMRG indices.
void PreSolve()
Reconstruct the renormalized operators when you overwrite the matrix elements with Prob->setMxElement...
void sBK(const SyBookkeeper *newBK)
Set the pointer to the symmetry bookkeeper.
int gf1(const int HamOrb) const
Get the DMRG index corresponding to a Ham index.
void Join(TensorT *Tleft, TensorT *Tright)
Join two sites to form a composite S-object.
void fill_site(TensorT *denT, TensorL ***Ltens, TensorF0 ****F0tens, TensorF1 ****F1tens, TensorS0 ****S0tens, TensorS1 ****S1tens, Tensor3RDM ****dm3_a_J0_doublet, Tensor3RDM ****dm3_a_J1_doublet, Tensor3RDM ****dm3_a_J1_quartet, Tensor3RDM ****dm3_b_J0_doublet, Tensor3RDM ****dm3_b_J1_doublet, Tensor3RDM ****dm3_b_J1_quartet, Tensor3RDM ****dm3_c_J0_doublet, Tensor3RDM ****dm3_c_J1_doublet, Tensor3RDM ****dm3_c_J1_quartet, Tensor3RDM ****dm3_d_J0_doublet, Tensor3RDM ****dm3_d_J1_doublet, Tensor3RDM ****dm3_d_J1_quartet)
Fill the 3-RDM terms corresponding to site denT->gIndex()
int gMaxDimAtBound(const int boundary) const
Get the maximum virtual dimension at a certain boundary.
double get_ham_index(const int cnt1, const int cnt2, const int cnt3, const int cnt4, const int cnt5, const int cnt6) const
Get a 3-RDM, using the HAM indices.
void number_operator(const double alpha, const double beta)
Apply alpha * ( number operator ) + beta to the MPS tensor.
int gIrrep(const int orbital) const
Get an orbital irrep.
void addNoise(const double NoiseLevel)
Add noise to the current S-object.
int gKappa2index(const int kappa) const
Get the storage jump corresponding to a certain tensor block.