blas_diis.cc

00001 /***************************************************************************
00002  *  PSIMRCC
00003  *  Copyright (C) 2007 by Francesco Evangelista and Andrew Simmonett
00004  *  frank@ccc.uga.edu   andysim@ccc.uga.edu
00005  *  A multireference coupled cluster code
00006  ***************************************************************************/
00007 
00008 #include "algebra_interface.h"
00009 #include "calculation_options.h"
00010 #include "blas.h"
00011 #include "moinfo.h"
00012 #include "memory_manager.h"
00013 #include "utilities.h"
00014 #include "error.h"
00015 #include <limits>
00016 #include <cmath>
00017 
00018 #include <libpsio/psio.h>
00019 #include <libciomr/libciomr.h>
00020 #include <libqt/qt.h>
00021 
00022 extern FILE *infile, *outfile;
00023 
00024 namespace psi{ namespace psimrcc{
00025 
00026 using namespace std;
00027 
00028 vector<pair<string,string> > diis_matrices;
00029 const double diis_singular_tollerance = 1.0e-12;
00030 
00031 void CCBLAS::diis_add(string amps, string delta_amps)
00032 {
00033   vector<string> amps_names = moinfo->get_matrix_names(amps);
00034   vector<string> delta_amps_names = moinfo->get_matrix_names(delta_amps);
00035   for(int n=0;n<amps_names.size();n++){
00036     diis_matrices.push_back(make_pair(amps_names[n],delta_amps_names[n]));
00037   }
00038 }
00039 
00040 void CCBLAS::diis_save_t_amps(int cycle)
00041 {
00042   int diis_step = cycle % options->get_int_option("MAXDIIS");
00043   for(vector<pair<string,string> >::iterator it=diis_matrices.begin();it!=diis_matrices.end();++it){
00044     for(int h=0;h<moinfo->get_nirreps();h++){
00045       CCMatIrTmp Amps = get_MatIrTmp(it->first,h,none);
00046       double** matrix = Amps->get_matrix()[h];
00047       size_t   block_sizepi = Amps->get_block_sizepi(h);
00048       if(block_sizepi>0){
00049         char data_label[80];
00050         sprintf(data_label,"%s_%s_%d_%d",(it->first).c_str(),"DIIS",h,diis_step);
00051         psio_write_entry(MRCC_ON_DISK,data_label,(char*)&(matrix[0][0]),block_sizepi*sizeof(double));
00052       }
00053     }
00054   }
00055 }
00056 
00057 void CCBLAS::diis(int cycle)
00058 {
00059   int diis_step = cycle % options->get_int_option("MAXDIIS");
00060 
00061   for(vector<pair<string,string> >::iterator it=diis_matrices.begin();it!=diis_matrices.end();++it){
00062     if(it->second.find("t3_delta")==string::npos){
00063       for(int h=0;h<moinfo->get_nirreps();h++){
00064         CCMatIrTmp DeltaAmps = get_MatIrTmp(it->second,h,none);
00065         double** matrix = DeltaAmps->get_matrix()[h];
00066         size_t   block_sizepi = DeltaAmps->get_block_sizepi(h);
00067         if(block_sizepi>0){
00068           char data_label[80];
00069           sprintf(data_label,"%s_%s_%d_%d",(it->second).c_str(),"DIIS",h,diis_step);
00070           psio_write_entry(MRCC_ON_DISK,data_label,(char*)&(matrix[0][0]),block_sizepi*sizeof(double));
00071         }
00072       }
00073     }
00074   }
00075 
00076   fprintf(outfile,"   S");
00077 
00078   // Do a DIIS step 
00079   if(diis_step==options->get_int_option("MAXDIIS")-1){
00080     double** diis_B;
00081     double*  diis_A;
00082     allocate1(double,diis_A,options->get_int_option("MAXDIIS")+1);
00083     allocate2(double,diis_B,options->get_int_option("MAXDIIS")+1,options->get_int_option("MAXDIIS")+1);
00084     bool singularities_found = false;
00085     for(vector<pair<string,string> >::iterator it=diis_matrices.begin();it!=diis_matrices.end();++it){
00086       // Zero A and B
00087       for(int i=0;i<options->get_int_option("MAXDIIS");i++){
00088         diis_A[i]=0.0;
00089         diis_B[i][options->get_int_option("MAXDIIS")]=diis_B[options->get_int_option("MAXDIIS")][i]=-1.0;
00090         for(int j=0;j<options->get_int_option("MAXDIIS");j++)
00091           diis_B[i][j]=0.0;
00092       }
00093       diis_B[options->get_int_option("MAXDIIS")][options->get_int_option("MAXDIIS")]=0.0;
00094       diis_A[options->get_int_option("MAXDIIS")]=-1.0;
00095 
00096       // Build B
00097       for(int h=0;h<moinfo->get_nirreps();h++){
00098         CCMatIrTmp Amps       = get_MatIrTmp(it->first,h,none);
00099         size_t   block_sizepi = Amps->get_block_sizepi(h);
00100         if(block_sizepi>0){
00101           double*  i_matrix;
00102           double*  j_matrix;
00103           allocate1(double,i_matrix,block_sizepi);
00104           allocate1(double,j_matrix,block_sizepi);
00105 
00106           // Build the diis_B matrix
00107           for(int i=0;i<options->get_int_option("MAXDIIS");i++){
00108             // Load vector i irrep h
00109             char i_data_label[80];
00110             sprintf(i_data_label,"%s_%s_%d_%d",(it->second).c_str(),"DIIS",h,i);
00111             psio_read_entry(MRCC_ON_DISK,i_data_label,(char*)&(i_matrix[0]),block_sizepi*sizeof(double));
00112 
00113             for(int j=i;j<options->get_int_option("MAXDIIS");j++){
00114               // Load vector j irrep h
00115               char j_data_label[80];
00116               sprintf(j_data_label,"%s_%s_%d_%d",(it->second).c_str(),"DIIS",h,j);
00117               psio_read_entry(MRCC_ON_DISK,j_data_label,(char*)&(j_matrix[0]),block_sizepi*sizeof(double));
00118 
00119               int dx = 1;
00120               int lenght = block_sizepi;
00121               if( block_sizepi < static_cast<size_t>(numeric_limits<int>::max()) ){
00122                 diis_B[i][j] += F_DDOT(&lenght,i_matrix,&dx,j_matrix,&dx);
00123                 diis_B[j][i] = diis_B[i][j];
00124               }else{
00125                 print_error("The numeric limits for int was reached for F_DDOT",__FILE__,__LINE__);
00126               }
00127             }
00128           }
00129           release1(i_matrix);
00130           release1(j_matrix);
00131         }
00132       }
00133 
00134       // Solve B x = A
00135       int  matrix_size = options->get_int_option("MAXDIIS") + 1;          
00136       int* IPIV = new int[matrix_size];
00137       int nrhs = 1;
00138       int info = 0;
00139       F_DGESV(&matrix_size, &nrhs, &(diis_B[0][0]),&matrix_size, &(IPIV[0]), &(diis_A[0]),&matrix_size, &info);         
00140       delete[] IPIV;
00141 
00142       // Update T = sum t(i) * A(i);
00143       if(!info){
00144         for(int h=0;h<moinfo->get_nirreps();h++){
00145           CCMatIrTmp Amps       = get_MatIrTmp(it->first,h,none);
00146           size_t   block_sizepi = Amps->get_block_sizepi(h);
00147           if(block_sizepi>0){
00148             // Update the amplitudes
00149             double*  i_matrix;
00150             double*  j_matrix;
00151             allocate1(double,i_matrix,block_sizepi);
00152             allocate1(double,j_matrix,block_sizepi);
00153             double* t_matrix = &(Amps->get_matrix()[h][0][0]);
00154             Amps->zero_matrix_block(h);
00155             for(int i=0;i<options->get_int_option("MAXDIIS");i++){
00156               char i_data_label[80];
00157               sprintf(i_data_label,"%s_%s_%d_%d",(it->first).c_str(),"DIIS",h,i);
00158               psio_read_entry(MRCC_ON_DISK,i_data_label,(char*)&(i_matrix[0]),block_sizepi*sizeof(double));
00159               for(size_t n=0;n<block_sizepi;n++){
00160                 t_matrix[n] += diis_A[i]*i_matrix[n];
00161               }
00162             }
00163             release1(i_matrix);
00164             release1(j_matrix);
00165           }
00166         }
00167       }else{
00168         singularities_found = true;
00169       }
00170 
00171     }
00172     fprintf(outfile,"/E");
00173     if(singularities_found)
00174       fprintf(outfile," (singularities found)");
00175     release1(diis_A);
00176     release2(diis_B);
00177   }
00178 }
00179 
00180 
00181 /*
00182 SOME OLD CODE THAT WAS SUPPOSED TO BE FANCIER, IT DOESN'T REALLY IMPROVE
00183 
00184 //           // This is a stable matrix inversion routine
00185 // 
00186 
00187 //           double** eigenvectors;
00188 //           double** original_matrix;
00189 //           double*  eigenvalues;
00190 // 
00191 //           int  matrix_size = options->get_int_option("MAXDIIS") + 1;          
00192 //           init_matrix<double>(eigenvalues,matrix_size);
00193 //           init_matrix<double>(eigenvectors,matrix_size,matrix_size);
00194 //           init_matrix<double>(original_matrix,matrix_size,matrix_size);
00195 // 
00196 //           for(int i = 0; i < matrix_size;i++)
00197 //             for(int j = 0; j < matrix_size;j++)
00198 //               original_matrix[i][j] = diis_B[i][j];
00199 // 
00200 //           sq_rsp(matrix_size,matrix_size,diis_B,eigenvalues,1,eigenvectors,1e-14);
00201 // 
00202 //           fprintf(outfile,"\n DIIS %s[%d]",it->first.c_str(),h);
00203 //           for(int i=0;i<matrix_size;i++)
00204 //             fprintf(outfile,"\n eigenvalues[%d] = %20.12f",i,eigenvalues[i]);
00205 // 
00206 //           for(int k = 0; k < matrix_size;k++){
00207 //             if(fabs(eigenvalues[k]) < diis_singular_tollerance){
00208 //               eigenvalues[k]=0.0;
00209 //             }else{
00210 //               eigenvalues[k]=1/eigenvalues[k];
00211 //             }
00212 //           }
00213 //           for(int i=0;i<matrix_size;i++)
00214 //             fprintf(outfile,"\n eigenvalues[%d] = %20.12f",i,eigenvalues[i]);
00215 //           
00216 //           for(int i = 0; i < matrix_size;i++){
00217 //             for(int j = 0; j < matrix_size;j++){
00218 //               diis_B[i][j] = 0.0;
00219 //               for(int k = 0; k < matrix_size;k++){
00220 //                 diis_B[i][j] += eigenvectors[i][k]*eigenvectors[j][k]*eigenvalues[k];
00221 //               }
00222 //             }
00223 //           }
00224 //           print_dmatrix(diis_B,matrix_size,matrix_size,outfile,"diis_B");
00225 // 
00226 //           for(int i = 0; i < matrix_size;i++){
00227 //             for(int j = 0; j < matrix_size;j++){
00228 //               eigenvectors[i][j] = 0.0;
00229 //               for(int k = 0; k < matrix_size;k++){
00230 //                 eigenvectors[i][j] += original_matrix[i][k]*diis_B[k][j];
00231 //               }
00232 //             }
00233 //           }
00234 //           fprintf(outfile,"\n DIIS %s[%d] Testing inverse",it->first.c_str(),h);
00235 //           print_dmatrix(eigenvectors,matrix_size,matrix_size,outfile);
00236 // 
00237 //           for(int i = 0; i < matrix_size;i++){
00238 //             eigenvalues[i] = 0.0;
00239 //             for(int j = 0; j < matrix_size;j++){
00240 //               eigenvalues[i] += diis_B[i][j] * diis_A[j];
00241 //             }
00242 //           }
00243 //           for(int i = 0; i < matrix_size;i++)
00244 //             diis_A[i] = eigenvalues[i];
00245 //           for(int i=0;i<matrix_size;i++)
00246 //             fprintf(outfile,"\n A[%d] = %20.12f",i,diis_A[i]);
00247 // 
00248 //           free_matrix<double>(eigenvalues,matrix_size);
00249 //           free_matrix<double>(eigenvectors,matrix_size,matrix_size);
00250 //           free_matrix<double>(original_matrix,matrix_size,matrix_size);
00251 // 
00252 // 
00253 //           fprintf(outfile,"\n DIIS %s[%d]",it->first.c_str(),h);
00254 //           print_dmatrix(diis_B,matrix_size,matrix_size,outfile);
00255 //           for(int i=0;i<matrix_size;i++){
00256 //             fprintf(outfile,"\n A[%d] = %20.12f",i,diis_A[i]);
00257 //           }
00258 
00259 */
00260 
00261 }} /* End Namespaces */

Generated on Wed Feb 13 16:35:39 2008 for PSI by  doxygen 1.5.4