Ejemplo n.º 1
0
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;

}
Ejemplo n.º 2
0
void CheMPS2::DMRG::calc2DM(){

   //First get the whole MPS into left-canonical form
   int index = Prob->gL()-2;
   Sobject * denS = new Sobject(index,denBK->gIrrep(index),denBK->gIrrep(index+1),denBK);
   denS->Join(MPS[index],MPS[index+1]);
   Heff Solver(denBK, Prob);
   double Energy = 0.0;
   double ** VeffTilde = NULL;
   if (Exc_activated){
      VeffTilde = new double*[nStates-1];
      for (int cnt=0; cnt<nStates-1; cnt++){
         VeffTilde[cnt] = new double[denS->gKappa2index(denS->gNKappa())];
         calcVeffTilde(VeffTilde[cnt], denS, cnt);
      }
   }
   Energy = Solver.SolveDAVIDSON(denS, Ltensors, Atensors, Btensors, Ctensors, Dtensors, S0tensors, S1tensors, F0tensors, F1tensors, Qtensors, Xtensors, nStates-1, VeffTilde);
   if (Exc_activated){
      for (int cnt=0; cnt<nStates-1; cnt++){ delete [] VeffTilde[cnt]; }
      delete [] VeffTilde;
   }
   Energy += Prob->gEconst();
   if (Energy<MinEnergy){ MinEnergy = Energy; }
   denS->Split(MPS[index],MPS[index+1],OptScheme->getD(OptScheme->getNInstructions()-1),true,true);
   delete denS;
   
   cout << "*********************" << endl;
   cout << "** 2DM calculation **" << endl;
   cout << "*********************" << endl;
   updateMovingRightSafe(index);
   
   TensorDiag * Norm = new TensorDiag(Prob->gL(), denBK);
   MPS[Prob->gL()-1]->QR(Norm);
   delete Norm;
   
   //Then calculate step by step the 2DM
   if (!the2DMallocated){
      the2DMallocated = true;
      the2DM = new TwoDM(denBK, Prob);
   }
   for (int siteindex=Prob->gL()-1; siteindex>=0; siteindex--){
      the2DM->FillSite(MPS[siteindex], Ltensors, F0tensors, F1tensors, S0tensors, S1tensors);
      if (siteindex>0){
         TensorDiag * Left = new TensorDiag(siteindex, denBK);
         MPS[siteindex]->LQ(Left);
         MPS[siteindex-1]->RightMultiply(Left);
         delete Left;
         updateMovingLeftSafe2DM(siteindex-1);
      }
   }
   
   //Then perform two checks: double trace & energy
   double NtimesNminus1 = the2DM->doubletrace2DMA();
   cout << "   N(N-1) = " << denBK->gN() * (denBK->gN() - 1) << " and calculated by double trace of the 2DM-A = " << NtimesNminus1 << endl;
   
   double Energy2DMA = the2DM->calcEnergy();
   cout << "   Energy obtained by Heffective at edge = " << Energy << " and as Econst + 0.5*trace(2DM-A*Ham) = " << Energy2DMA << endl;

}
Ejemplo n.º 3
0
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;
   }

}