inline_disco_eigcg_w.cc

Go to the documentation of this file.
00001 
00002 // $Id: inline_disco_eigcg_w.cc,v 1.19 2009/07/31 14:09:31 bjoo Exp $
00003 /*! \file
00004  * \brief Inline measurement 3pt_prop
00005  * 
00006  * This version does not use e/o preconditioning on the noise vectors,
00007  * but it does for the eigcg pieces, as it must.
00008  *
00009  */
00010 #include <vector> 
00011 #include <map> 
00012 #include <qdp-lapack.h>
00013 #include <qdp_config.h>
00014 #include "handle.h"
00015 #include "meas/inline/hadron/inline_disco_eigcg_w.h"
00016 #include "meas/inline/abs_inline_measurement_factory.h"
00017 #include "meas/smear/quark_smearing_factory.h"
00018 #include "meas/smear/quark_smearing_aggregate.h"
00019 #include "meas/smear/displacement.h"
00020 #include "meas/sources/source_smearing_aggregate.h"
00021 #include "meas/sources/source_smearing_factory.h"
00022 #include "meas/sources/dilutezN_source_const.h"
00023 #include "meas/sources/zN_src.h"
00024 #include "meas/sinks/sink_smearing_aggregate.h"
00025 #include "meas/sinks/sink_smearing_factory.h"
00026 #include "meas/hadron/barspinmat_w.h"
00027 #include "meas/hadron/baryon_operator_aggregate_w.h"
00028 #include "meas/hadron/baryon_operator_factory_w.h"
00029 #include "meas/hadron/barQll_w.h"
00030 #include "meas/hadron/dilution_scheme_aggregate.h"
00031 #include "meas/hadron/dilution_scheme_factory.h"
00032 #include "meas/glue/mesplq.h"
00033 #include "util/ft/sftmom.h"
00034 #include "util/info/proginfo.h"
00035 #include "meas/inline/make_xml_file.h"
00036 #include "util/info/unique_id.h"
00037 #include "util/ferm/transf.h"
00038 #include "meas/inline/io/named_objmap.h"
00039 
00040 #include "actions/ferm/fermacts/fermact_factory_w.h"
00041 #include "actions/ferm/fermacts/fermacts_aggregate_w.h"
00042 
00043 #include "eoprec_logdet_wilstype_fermact_w.h"
00044 #include "actions/ferm/linop/lgherm_w.h"
00045 
00046 #include "actions/ferm/fermacts/clover_fermact_params_w.h"
00047 #include "actions/ferm/fermacts/wilson_fermact_params_w.h"
00048 #include "actions/ferm/linop/linop_w.h"
00049 
00050 
00051 #include "util/ferm/key_val_db.h"
00052 
00053 
00054 
00055 namespace Chroma{ 
00056   namespace InlineDiscoEigCGEnv{ 
00057     namespace{
00058       AbsInlineMeasurement* createMeasurement(XMLReader& xml_in, 
00059                                               const std::string& path) 
00060       {
00061         return new InlineMeas(Params(xml_in, path));
00062       }
00063 
00064       //! Local registration flag
00065       bool registered = false;
00066     }
00067 
00068     const std::string name = "DISCO_EIGCG";
00069 
00070     //! Register all the factories
00071     bool registerAll() 
00072     {
00073       bool success = true; 
00074       if (! registered)
00075       {
00076         //success &= BaryonOperatorEnv::registerAll();
00077         success &= TheInlineMeasurementFactory::Instance().registerObject(name, createMeasurement);
00078         registered = true;
00079       }
00080       return success;
00081     }
00082   
00083   // Reader for input parameters
00084   void read(XMLReader& xml, const string& path, Params::Param_t& param){
00085       XMLReader paramtop(xml, path);
00086       
00087       int version;
00088       read(paramtop, "version", version);
00089       
00090       switch (version) 
00091         {
00092         case 1:
00093           /************************************************************/
00094           read(paramtop,"max_path_length",param.max_path_length);
00095           read(paramtop,"p2_max",param.p2_max);
00096           read(paramtop,"mass_label",param.mass_label);
00097           param.chi = readXMLArrayGroup(paramtop, "Quarks", "DilutionType");
00098           param.action = readXMLGroup(paramtop, "FermionAction","FermAct");
00099           
00100           break;
00101           
00102         default :
00103           /**************************************************************/
00104 
00105           QDPIO::cerr << "Input parameter version " << version << " unsupported." << endl;
00106           QDP_abort(1);
00107         }
00108     }
00109 
00110     // Writer for input parameters
00111     void write(XMLWriter& xml, const string& path, const Params::Param_t& param){
00112       push(xml, path);
00113       
00114       int version = 1;
00115       
00116       write(xml, "version", version);
00117 
00118       write(xml,"max_path_length",param.max_path_length);
00119       write(xml,"p2_max",param.p2_max);
00120       write(xml,"mass_label",param.mass_label);
00121       push(xml,"FermionAction");
00122       xml<<param.action.xml ;
00123       pop(xml);
00124       push(xml,"Quarks");
00125       for( int t(0);t<param.chi.size();t++){
00126         push(xml,"elem");
00127         xml<<param.chi[t].xml;
00128         pop(xml);
00129       }
00130       pop(xml);
00131       
00132       pop(xml); // final pop
00133     }
00134     
00135     //! Gauge field parameters
00136     void read(XMLReader& xml, const string& path, Params::NamedObject_t& input)
00137     {
00138       XMLReader inputtop(xml, path);
00139       
00140       read(inputtop, "gauge_id"   , input.gauge_id   ) ;
00141       // If no file is included, then we will turn off the eig_cg part (ie, use 0 vectors)
00142       if ( inputtop.count("evecs_file")!=0 )
00143         read(inputtop, "evecs_file" , input.evecs_file ) ;
00144       else
00145         input.evecs_file="";
00146         
00147       read(inputtop, "op_db_file" , input.op_db_file ) ;
00148     }
00149     
00150     //! Gauge field parameters
00151     void write(XMLWriter& xml, const string& path, const Params::NamedObject_t& input){
00152       push(xml, path);
00153       
00154       write(xml, "gauge_id"   , input.gauge_id   );
00155       write(xml, "evecs_file" , input.evecs_file );
00156       write(xml, "op_db_file" , input.op_db_file );
00157       pop(xml);
00158     }
00159     
00160     
00161     // Param stuff
00162     Params::Params(){ 
00163       frequency = 0;
00164     }
00165     
00166     Params::Params(XMLReader& xml_in, const std::string& path) 
00167     {
00168       try 
00169         {
00170           XMLReader paramtop(xml_in, path);
00171           
00172           if (paramtop.count("Frequency") == 1)
00173             read(paramtop, "Frequency", frequency);
00174           else
00175             frequency = 1;
00176           
00177           // Read program parameters
00178           read(paramtop, "Param", param);
00179           
00180           // Read in the output propagator/source configuration info
00181           read(paramtop, "NamedObject", named_obj);
00182           
00183           // Possible alternate XML file pattern
00184           if (paramtop.count("xml_file") != 0) 
00185             {
00186               read(paramtop, "xml_file", xml_file);
00187             }
00188         }
00189       catch(const std::string& e) 
00190         {
00191           QDPIO::cerr << __func__ << ": Caught Exception reading XML: " << e << endl;
00192           QDP_abort(1);
00193         }
00194     }
00195 
00196 
00197     void Params::write(XMLWriter& xml_out, const std::string& path) 
00198     {
00199       push(xml_out, path);
00200       
00201       // Parameters for source construction
00202       InlineDiscoEigCGEnv::write(xml_out, "Param", param);
00203       
00204       // Write out the output propagator/source configuration info
00205       InlineDiscoEigCGEnv::write(xml_out, "NamedObject", named_obj);
00206 
00207       pop(xml_out);
00208     }
00209 
00210     
00211     //! Meson operator     
00212     struct KeyOperator_t
00213     {
00214       multi1d<short int> mom     ; /*!< D-1 momentum of this operator */
00215       unsigned short int t_slice ; /*!< Meson operator time slice */
00216       multi1d<short int> disp    ; /*!< Displacement dirs of quark (right)*/
00217       
00218       KeyOperator_t(){
00219         mom.resize(Nd-1);
00220       }
00221     };
00222     
00223     bool operator<(const KeyOperator_t& a, const KeyOperator_t& b){
00224       return ((a.t_slice<b.t_slice)||(a.mom<b.mom)||(a.disp<b.disp));
00225     }
00226 
00227     std::ostream& operator<<(std::ostream& os, const KeyOperator_t& d)
00228     {
00229       os << "KeyOperator_t:"
00230          << " t_slice = " << d.t_slice
00231          << ", disp = ";
00232       for (int i=0; i<d.disp.size();i++)
00233         os << d.disp[i] << " " ;
00234       
00235       os << ", mom = ";
00236       for (int i=0; i<d.mom.size();i++)
00237         os << d.mom[i] << " " ;
00238 
00239       os << std::endl;
00240 
00241       return os;
00242     }
00243 
00244     class ValOperator_t{
00245     public:
00246       multi1d<ComplexD> op ;  
00247       ValOperator_t(){op.resize(Ns*Ns);} // Here go the 16 gamma matrices
00248       ~ValOperator_t(){}
00249     } ;
00250 
00251     //-------------------------------------------------------------------------                            
00252     //! stream IO                                                                                          
00253     std::ostream& operator<<(std::ostream& os, const ValOperator_t& d)
00254     {
00255       os << "ValOperator_t:\n";
00256       for (int i=0; i<d.op.size();i++)
00257         os <<"     gamma["<<i<<"] = "<< d.op[i] << endl ;
00258       
00259       return os;
00260     }
00261     
00262     struct KeyVal_t{
00263       SerialDBKey <KeyOperator_t> k ;
00264       SerialDBData<ValOperator_t> v ;
00265     };
00266 
00267     //! KeyOperator reader    
00268     void read(BinaryReader& bin, KeyOperator_t& d){
00269       read(bin,d.t_slice);
00270       unsigned short int n ;
00271       read(bin,n);
00272       d.disp.resize(n); 
00273       read(bin,d.disp);
00274       d.mom.resize(Nd-1) ;
00275       read(bin,d.mom);
00276     }
00277     //! KeyOperator writer
00278     void write(BinaryWriter& bin, KeyOperator_t& d){
00279       write(bin,d.t_slice);
00280       unsigned short int n ;
00281       n = d.disp.size();
00282       write(bin,n);
00283       write(bin,d.disp);
00284       write(bin,d.mom);
00285     }
00286 
00287     //! ValOperator reader    
00288     void read(BinaryReader& bin, ValOperator_t& d){
00289       d.op.resize(Ns*Ns);
00290       read(bin,d.op);
00291     }
00292     //! ValOperator writer
00293     void write(BinaryWriter& bin, ValOperator_t& d){
00294       write(bin,d.op);
00295     }
00296 
00297     namespace{
00298       StandardOutputStream& operator<<(StandardOutputStream& os, const multi1d<short int>& d){
00299         if (d.size() > 0){
00300           os << d[0]; 
00301           for(int i=1; i < d.size(); i++)
00302             os << " " << d[i];
00303         }
00304         return os;
00305       }
00306     }
00307 
00308     //    Set t0set;
00309     //    t0set.make(TimeSliceFunc(Nd-1));
00310     
00311     //    Set timerb;
00312     //    timerb.make(TimeSliceRBFunc(Nd-1));
00313     
00314     typedef LatticeFermion               T;
00315     typedef multi1d<LatticeColorMatrix>  P;
00316     typedef multi1d<LatticeColorMatrix>  Q;
00317 
00318     Handle<EvenOddPrecLinearOperator<T,P,Q> > 
00319     createOddOdd_Op( const Params::Param_t& param, const P& u){     
00320       //
00321       // Initialize fermion action
00322       //
00323       std::istringstream  xml_s(param.action.xml);
00324       XMLReader  fermacttop(xml_s);
00325       QDPIO::cout << "FermAct = " << param.action.id << endl;
00326       //
00327       // Try the factories
00328       //
00329       Handle< FermState< T,P,Q> > state ;
00330       try{
00331           QDPIO::cout << "Try the various Wilson fermion factories" << endl;
00332           // Generic Wilson-Type stuff
00333           Handle< FermionAction< T,P,Q > >
00334             Sf(TheFermionActionFactory::Instance().createObject(param.action.id,
00335                                                                 fermacttop,
00336                                                                 param.action.path));
00337           state = Sf->createState(u);//got the state
00338           QDPIO::cout << "Suitable factory found: compute the trace quark prop"<<endl;
00339       }
00340       catch (const std::string& e){
00341         QDPIO::cout << name 
00342                     << ": caught exception instantiating the action: " << e << endl;
00343       }
00344       
00345       // Now need to construct the operator
00346       // this seems tricky and maybe there is a better way... (Robert-Balint help!)
00347       // We only work with Wilson and Clover Wilson fermions so check the following 2
00348       // For the moment we restrict to EO preconditioned only
00349       
00350       //this is the Odd-Odd piece
00351       Handle<EvenOddPrecLinearOperator<T,P,Q> > Doo ;
00352       if(param.action.id == "WILSON"){
00353         WilsonFermActParams wp(fermacttop,param.action.path);
00354         return new EvenOddPrecWilsonLinOp(state,wp.Mass,wp.anisoParam ) ;
00355       }
00356       else if(param.action.id == "CLOVER"){
00357         CloverFermActParams cp(fermacttop,param.action.path);
00358         return new EvenOddPrecCloverLinOp(state,cp) ;
00359       }
00360       else{
00361         QDPIO::cout<<name<<" : Tough luck dude! No code for you..."<<endl ;
00362         QDP_abort(1);
00363       }
00364       return NULL ;
00365     }
00366 
00367     struct CholeskyFactors{
00368       multi1d<Real>    evals ;
00369       multi1d<Complex> H     ;
00370       multi1d<Complex> HU    ;
00371       int              ldh   ;
00372       int              Nvec  ;
00373     } ;
00374 
00375     void do_disco(map< KeyOperator_t, ValOperator_t >& db,
00376                   const LatticeFermion& qbar,
00377                   const LatticeFermion& q,
00378                   const SftMom& p,
00379                   const int& t, 
00380                   const multi1d<short int>& path,
00381                   const int& max_path_length ){
00382       QDPIO::cout<<" Computing Operator with path length "<<path.size()
00383                  <<" on timeslice "<<t<<".   Path: "<<path <<endl;
00384       ValOperator_t val ;
00385       KeyOperator_t key ;
00386       pair<KeyOperator_t, ValOperator_t> kv ; 
00387       kv.first.t_slice = t ;
00388       if(path.size()==0){
00389         kv.first.disp.resize(1);
00390         kv.first.disp[0] = 0 ;
00391       }
00392       else
00393         kv.first.disp = path ;
00394       
00395       multi1d< multi1d<ComplexD> > foo(p.numMom()) ;
00396       for (int m(0); m < p.numMom(); m++)
00397         foo[m].resize(Ns*Ns);
00398       for(int g(0);g<Ns*Ns;g++){
00399         LatticeComplex cc = localInnerProduct(qbar,Gamma(g)*q);
00400         for (int m(0); m < p.numMom(); m++){
00401           foo[m][g] = sum(p[m]*cc,p.getSet()[t]);
00402         }
00403       }
00404       for (int m(0); m < p.numMom(); m++){
00405         for(int i(0);i<(Nd-1);i++)
00406           kv.first.mom[i] = p.numToMom(m)[i] ;
00407         
00408         kv.second.op = foo[m];
00409         pair<map< KeyOperator_t, ValOperator_t >::iterator, bool> itbo;
00410         
00411         itbo = db.insert(kv);
00412         if( itbo.second ){
00413           QDPIO::cout<<"Inserting new entry in map\n";
00414         }
00415         else{ // if insert fails, key already exists, so add result
00416           for(int i(0);i<kv.second.op.size();i++)
00417             itbo.first->second.op[i] += kv.second.op[i] ;
00418         }
00419       }//m 
00420       
00421       if(path.size()<max_path_length){
00422         QDPIO::cout<<" attempt to add new path. "
00423                    <<" current path length is : "<<path.size();
00424         multi1d<short int> new_path(path.size()+1);
00425         QDPIO::cout<<" new path length is : "<<new_path.size()<<endl;
00426         for(int i(0);i<path.size();i++)
00427           new_path[i] = path[i] ;
00428         for(int sign(-1);sign<2;sign+=2)
00429           for(int mu(0);mu<Nd;mu++){
00430             new_path[path.size()]= sign*(mu+1) ;
00431             //skip back tracking 
00432             bool back_track=false ;
00433             if(path.size()>0)
00434               if(path[path.size()-1] == -new_path[path.size()])
00435                 back_track=true;
00436             if(!back_track){
00437               QDPIO::cout<<" Added path: "<<new_path<<endl;
00438               LatticeFermion q_mu ;
00439               if(sign>0)
00440                 q_mu = shift(q, FORWARD, mu);
00441               else
00442                 q_mu = shift(q, BACKWARD, mu);
00443 
00444               do_disco(db, qbar, q_mu, p, t, new_path, max_path_length);
00445             } // skip backtracking
00446           } // mu
00447       }// path.size loop
00448       
00449     }// do_disco
00450 
00451     void do_disco(map< KeyOperator_t, ValOperator_t >& db,
00452                   CholeskyFactors Clsk , 
00453                   multi1d<LatticeFermion>& vec,
00454                   const Params::Param_t& param, 
00455                   const Handle<EvenOddPrecLinearOperator<T,P,Q> >& Doo,
00456                   const P& u,
00457                   const int& t,
00458                   const Subset& trb, 
00459                   const SftMom& p,
00460                   const multi1d<short int>& path){
00461 
00462       QDPIO::cout<<" Computing Operator with path length "<<path.size()
00463                  <<" on timeslice "<<t<<".   Path: "<<path <<endl;
00464       int max_path_length = param.max_path_length;
00465       
00466       ValOperator_t val ;
00467       KeyOperator_t key ;
00468       pair<KeyOperator_t, ValOperator_t> kv ; 
00469 
00470       kv.first.t_slice = t ;
00471       if(path.size()==0){
00472         kv.first.disp.resize(1);
00473         kv.first.disp[0] = 0 ;
00474       }
00475       else
00476         kv.first.disp = path ;
00477       
00478       int ldb = vec.size();
00479       int info;
00480       char U = 'U';
00481       int Nrhs = ldb; // Because we have no dilution vectors, but rhs's are made of EigCG vecs...
00482       multi2d<Complex> B(Nrhs,ldb);
00483       /*
00484       multi1d< multi1d<LatticeFermion> > DDvec(ldb);
00485       // Zero out the fermions
00486       for(int i(0); i<ldb;i++){
00487         DDvec[i].resize(Ns*Ns);
00488         DDvec[i] = zero;
00489       }
00490       cout<<"We've initialized DDvec!\n";
00491 
00492       for(int i(0); i<ldb;i++){
00493         LatticeFermion qtmp = zero ;
00494         LatticeFermion qtmp2 = zero ;
00495         LatticeFermion qtmp3 = zero ;
00496         Doo->evenOddLinOp(qtmp,vec[i],PLUS);
00497         Doo->evenEvenInvLinOp(qtmp2,qtmp,PLUS);
00498         for(int g(0);g<Ns*Ns;g++){
00499           Doo->evenEvenInvLinOp(qtmp3,Gamma(g)*qtmp2,PLUS);
00500           qtmp = zero;
00501           qtmp2 = zero;
00502           Doo->oddEvenLinOp(qtmp,qtmp3,PLUS);
00503           Doo->oddOddLinOp(qtmp2,qtmp,MINUS);
00504           qtmp = zero;
00505           Doo->oddOddLinOp(qtmp,Gamma(g)*vec[i],MINUS);
00506           // I think this could run into memory problems with too many vectors
00507           DDvec[i][g] = qtmp + qtmp2;
00508         }
00509       }
00510       */
00511       multi1d< multi1d<ComplexD> > foo(p.numMom()) ;
00512       for (int m(0); m < p.numMom(); m++){
00513         foo[m].resize(Ns*Ns);
00514         foo[m] = zero;
00515       }
00516       // Okay, this is probably inefficient, b/c we are doing some things multiple times...
00517       multi1d< LatticeFermion > Svec(ldb);
00518       multi1d< LatticeFermion > DDvec(ldb);
00519       multi1d< LatticeFermion > DDSvec(ldb);
00520       Svec = zero;
00521       DDvec = zero;
00522       for(int i(0); i<ldb;i++){
00523         LatticeFermion qtmp = zero ;
00524         // DeeInv * Deo * V:
00525         Doo->evenOddLinOp(qtmp, vec[i],PLUS);
00526         Doo->evenEvenInvLinOp(DDvec[i], qtmp,PLUS);
00527         qtmp = zero;
00528         //DeeInv^dag * Deo^dag * Soo * V:
00529         Doo->oddOddLinOp(qtmp,vec[i],PLUS);
00530         LatticeFermion qtmp2 = zero;
00531         Doo->evenOddLinOp(qtmp2,qtmp,MINUS);
00532         Doo->evenEvenInvLinOp(DDSvec[i],qtmp2,MINUS);
00533         // Soo * V
00534         Doo->oddOddLinOp(Svec[i],vec[i],PLUS);
00535       }
00536       
00537       for(int g(0);g<Ns*Ns;g++){
00538         for (int m(0); m < p.numMom(); m++){
00539           for (int i(0); i<ldb;i++){
00540             for (int j(0); j<ldb;j++){
00541               LatticeComplex cc1 = localInnerProduct(Svec[j],Gamma(g)*vec[i]);
00542               LatticeComplex cc2 = localInnerProduct(DDSvec[j],Gamma(g)*DDvec[i]);
00543               B[i][j] = sum(p[m]*(cc1+cc2),trb) ;
00544               //              B[i][j] = sum(p[m]*(cc1+cc2),rb[1]) ;
00545             }//j
00546           }//i 
00547 
00548 #if BASE_PRECISION == 32
00549           int r = QDPLapack::cpotrs(U, Clsk.Nvec, Nrhs, Clsk.HU, Clsk.ldh, B, ldb, info);
00550 #else
00551           int r = QDPLapack::zpotrs(U, Clsk.Nvec, Nrhs, Clsk.HU, Clsk.ldh, B, ldb, info);
00552 #endif
00553 
00554           // and at this point, B is H^-1 Vdag Sdag gamma V, so
00555           // For debugging purposes, both r and info should be zero...
00556           QDPIO::cout<<"do_disco cpotrs r = "<<r<<endl;
00557           QDPIO::cout<<"do_disco cpotrs info = "<<info<<endl;
00558 
00559           for (int i(0); i<ldb;i++){
00560             foo[m][g] += ComplexD(B[i][i]);// Trace over last set of indices
00561           }
00562         }//m
00563       }//g
00564       for (int m(0); m < p.numMom(); m++){
00565         for(int i(0);i<(Nd-1);i++)
00566           kv.first.mom[i] = p.numToMom(m)[i] ;
00567         
00568         kv.second.op = foo[m];
00569 
00570         pair<map< KeyOperator_t, ValOperator_t >::iterator, bool> itbo;
00571         
00572         itbo = db.insert(kv);
00573         if( !(itbo.second) ){  // if insert fails, key already exists, so add result
00574           for(int i(0);i<kv.second.op.size();i++)
00575             itbo.first->second.op[i] += kv.second.op[i] ;
00576         }
00577         else
00578           QDPIO::cout<<"Inserting new entry in map\n";
00579       }
00580 
00581       if(path.size()<max_path_length){
00582         QDPIO::cout<<" attempt to add new path. "
00583                    <<" current path length is : "<<path.size();
00584         multi1d<short int> new_path(path.size()+1);
00585         QDPIO::cout<<" new path length is : "<<new_path.size()<<endl;
00586         for(int i(0);i<path.size();i++)
00587           new_path[i] = path[i] ;
00588         for(int sign(-1);sign<2;sign+=2)
00589           for(int mu(0);mu<Nd;mu++){
00590             new_path[path.size()]= sign*(mu+1) ;
00591             //skip back tracking 
00592             bool back_track=false ;
00593             if(path.size()>0)
00594               if(path[path.size()-1] == -new_path[path.size()])
00595                 back_track=true;
00596             if(!back_track){
00597               QDPIO::cout<<" Added path: "<<new_path<<endl;
00598               multi1d<LatticeFermion> vec_mu(vec.size()) ;
00599               for(int j(0);j<vec.size();j++){
00600                 if(sign>0)
00601                   vec_mu[j] = shift(vec[j], FORWARD, mu);
00602                 else
00603                   vec_mu[j] = shift(vec[j], BACKWARD, mu);
00604               }
00605               do_disco(db, Clsk , vec_mu, param, Doo, u, t, trb, p, new_path);
00606             } // skip backtracking
00607           } // mu
00608       }// path.size loop
00609     }// do_disco
00610     
00611 
00612     void ReadOPTEigCGVecs(multi1d<LatticeFermion>& vec,
00613                             CholeskyFactors& Clsk, 
00614                             const string& evecs_file)
00615     {
00616       QDPIO::cout<<name<<" : Reading vecs from "
00617                  << evecs_file <<endl ;
00618       StopWatch swatch;
00619       swatch.reset();
00620       swatch.start();
00621       
00622       int Nvecs,ldh ;
00623       // File XML                                      
00624       XMLReader file_xml;
00625       // Open file
00626       QDPFileReader to(file_xml,evecs_file,QDPIO_SERIAL);
00627       read(file_xml, "/OptEigInfo/ncurEvals", Nvecs);
00628       read(file_xml, "/OptEigInfo/ldh", ldh);
00629       // Added Nvecs and ldh to the Cholesky structure for later...
00630       Clsk.Nvec = Nvecs;
00631       Clsk.ldh = ldh;
00632       vec.resize(Nvecs);
00633       Clsk.evals.resize(ldh);
00634       Clsk.H.resize(ldh*ldh);
00635       Clsk.HU.resize(ldh*ldh);
00636 
00637       for(int v(0);v<Nvecs;v++){
00638         XMLReader record_xml;
00639         read(to, record_xml, vec[v]);
00640       }
00641       
00642       XMLReader record_xml;
00643       read(to, record_xml, Clsk.evals);
00644       read(to, record_xml, Clsk.H);
00645       read(to, record_xml, Clsk.HU);
00646       swatch.stop();
00647       QDPIO::cout<<name<<" : Time to read vecs= "
00648                  << swatch.getTimeInSeconds() <<" secs "<<endl ;
00649     }
00650 
00651     // PRchi returns chitilde = (1 - V Hinv Vdag Sdag S)chi given
00652     // an input chi vector, and of course the vectors and H. 
00653     void PRchi(multi1d<multi1d< multi1d<LatticeFermion> > >& quarkstilde,
00654                const multi1d< Handle< DilutionScheme<LatticeFermion> > >& quarks,
00655                Handle<EvenOddPrecLinearOperator<T,P,Q> >& Doo,
00656                CholeskyFactors Clsk , multi1d<LatticeFermion>& vec,
00657                const Params::Param_t& param, const P& u){
00658       char U = 'U';
00659       int info;
00660 
00661       int ldb = vec.size();//This is the offset that will for now be the size of each vector
00662 
00663       Set timerb;
00664       timerb.make(TimeSliceRBFunc(3));
00665 
00666       // Now we have to create the Sdag * S * quarks object to put into B
00667       for(int n(0);n<quarks.size();n++){
00668         for (int it(0) ; it < quarks[n]->getNumTimeSlices() ; ++it){
00669           int t = quarks[n]->getT0(it) ;
00670           int Nrhs = quarks[n]->getDilSize(it) ;
00671           multi2d<Complex> B(Nrhs, ldb);
00672           for(int i(0); i<ldb;i++){
00673             for(int j = 0 ; j <  Nrhs ; j++){
00674               /**
00675                  Here, we are calculating 
00676                    Sdag S chi
00677                  where chi (the solution) is Sinv eta, and eta is the noise vector (the source)
00678                  Thus, we can save time by using the source, and calculate
00679                    Sdag eta,
00680                  and that's what is being done here
00681                **/
00682               LatticeFermion qsrc     = quarks[n]->dilutedSource(it,j);
00683               LatticeFermion SdagSchi = zero ;
00684               Doo->oddOddLinOp(SdagSchi,qsrc,MINUS); 
00685               // Sum over (odd) lattice sites, so we return a complex number for B
00686               // SHOULD THIS BE ONLY SITES THAT INCLUDE THE TIMESLICE WE'RE ON?
00687               // Doesn't seem to matter, same answer either way.
00688               B[j][i] = sum(localInnerProduct(vec[i],SdagSchi),rb[1]);
00689               //B[j][i] = sum(localInnerProduct(vec[i],SdagSchi),timerb[2*t+1]);
00690             }
00691           }
00692 
00693 #if BASE_PRECISION == 32
00694           int r = QDPLapack::cpotrs(U, Clsk.Nvec, Nrhs, Clsk.HU, Clsk.ldh, B, ldb, info);
00695 #else
00696           int r = QDPLapack::zpotrs(U, Clsk.Nvec, Nrhs, Clsk.HU, Clsk.ldh, B, ldb, info);
00697 #endif 
00698           QDPIO::cout<<"PRchi cpotrs r = "<<r<<endl;
00699           QDPIO::cout<<"PRchi cpotrs info = "<<info<<endl;
00700 
00701           for(int j = 0 ; j <  Nrhs ; j++){
00702             LatticeFermion vB = zero;
00703             LatticeFermion q     = quarks[n]->dilutedSolution(it,j);
00704             for(int i(0); i<ldb;i++)
00705               vB += B[j][i]*vec[i];
00706             quarkstilde[n][it][j] = q - vB;
00707             cout<<"Norm of PRchi: "<<norm2(quarkstilde[n][it][j])<<endl;
00708           }
00709         }
00710       }
00711     }// End of PRchi call...
00712     
00713     /**
00714        This version is called if we have no EigCG vectors, so PR = 1
00715      **/
00716     void PRchi(multi1d<multi1d< multi1d<LatticeFermion> > >& quarkstilde,
00717                multi1d< Handle< DilutionScheme<LatticeFermion> > >& quarks){
00718       
00719       for(int n(0);n<quarks.size();n++){
00720         for (int it(0) ; it < quarks[n]->getNumTimeSlices() ; it++){
00721           for (int j(0) ; j < quarks[n]->getDilSize(it) ; j++){
00722             quarkstilde[n][it][j] = quarks[n]->dilutedSolution(it,j);
00723           }
00724         }
00725       }
00726     }// End of PRchi call...
00727     
00728   //--------------------------------------------------------------
00729   // Function call
00730   //  void 
00731   //InlineDiscoEigCG::operator()(unsigned long update_no,
00732   //                            XMLWriter& xml_out) 
00733     void InlineMeas::operator()(unsigned long update_no,
00734                                 XMLWriter& xml_out) 
00735     {
00736       // If xml file not empty, then use alternate
00737       if (params.xml_file != ""){
00738         string xml_file = makeXMLFileName(params.xml_file, update_no);
00739         
00740         push(xml_out, "discoEigCG");
00741         write(xml_out, "update_no", update_no);
00742         write(xml_out, "xml_file", xml_file);
00743         pop(xml_out);
00744         
00745         XMLFileWriter xml(xml_file);
00746         func(update_no, xml);
00747       }
00748       else{
00749         func(update_no, xml_out);
00750       }
00751     }
00752     
00753     
00754     // Function call
00755     //void 
00756     //InlineDiscoEigCG::func(unsigned long update_no,
00757     //                    XMLWriter& xml_out) 
00758     void InlineMeas::func(unsigned long update_no,
00759                           XMLWriter& xml_out) 
00760     {
00761       START_CODE();
00762       
00763       StopWatch snoop;
00764       snoop.reset();
00765       snoop.start();
00766       
00767       /*** Stuff to set up everything! ***/
00768       // Test and grab a reference to the gauge field
00769       XMLBufferWriter gauge_xml;
00770       try
00771         {
00772           TheNamedObjMap::Instance().getData< multi1d<LatticeColorMatrix> >(params.named_obj.gauge_id);
00773           TheNamedObjMap::Instance().get(params.named_obj.gauge_id).getRecordXML(gauge_xml);
00774         }
00775       catch( std::bad_cast ) 
00776         {
00777           QDPIO::cerr << InlineDiscoEigCGEnv::name << ": caught dynamic cast error" 
00778                       << endl;
00779           QDP_abort(1);
00780         }
00781       catch (const string& e) 
00782         {
00783           QDPIO::cerr << name << ": map call failed: " << e 
00784                       << endl;
00785           QDP_abort(1);
00786         }
00787       const multi1d<LatticeColorMatrix>& u = 
00788         TheNamedObjMap::Instance().getData< multi1d<LatticeColorMatrix> >(params.named_obj.gauge_id);
00789       
00790       push(xml_out, "discoEigCG");
00791       write(xml_out, "update_no", update_no);
00792       
00793       QDPIO::cout << name << ": Disconnected diagrams with eigCG vectors" << endl;
00794       
00795       proginfo(xml_out);    // Print out basic program info
00796       
00797       // Write out the input
00798       params.write(xml_out, "Input");
00799       
00800       // Write out the config info
00801       write(xml_out, "Config_info", gauge_xml);
00802       
00803       push(xml_out, "Output_version");
00804       write(xml_out, "out_version", 1);
00805       pop(xml_out);
00806       
00807       // First calculate some gauge invariant observables just for info.
00808       // This is really cheap.
00809       MesPlq(xml_out, "Observables", u);
00810       
00811       // Save current seed
00812       Seed ran_seed;
00813       QDP::RNG::savern(ran_seed);
00814       
00815       //
00816       // Read the source and solutions
00817       //
00818       StopWatch swatch;
00819       swatch.reset();
00820       swatch.start();
00821       
00822       int N_quarks = params.param.chi.size() ;
00823 
00824       multi1d< Handle< DilutionScheme<LatticeFermion> > > quarks(N_quarks);
00825 
00826       try{
00827         // Loop over quark dilutions
00828         for(int n(0); n < params.param.chi.size(); n++){
00829           const GroupXML_t& dil_xml = params.param.chi[n];
00830           std::istringstream  xml_d(dil_xml.xml);
00831           XMLReader  diltop(xml_d);
00832           QDPIO::cout << "Dilution type = " << dil_xml.id << endl;
00833           quarks[n] = 
00834             TheFermDilutionSchemeFactory::Instance().createObject(dil_xml.id, 
00835                                                                   diltop, 
00836                                                                   dil_xml.path);
00837         }
00838       }
00839       catch(const std::string& e){
00840         QDPIO::cerr << name << ": Caught Exception constructing dilution scheme: " << e << endl;
00841         QDP_abort(1);
00842       }
00843       
00844       
00845       //-------------------------------------------------------------------
00846       //Sanity checks   
00847 
00848       //Another Sanity check, the three quarks must all be 
00849       //inverted on the same cfg
00850       for (int n = 1 ; n < N_quarks ; n++){
00851         if (quarks[0]->getCfgInfo() != quarks[n]->getCfgInfo()){
00852           QDPIO::cerr << name << " : Quarks do not contain the same cfg info";
00853           QDPIO::cerr << ", quark "<< n << endl;
00854           QDP_abort(1);
00855         }               
00856       }
00857 
00858       //Also ensure that the cfg on which the inversions were performed 
00859       //is the same as the cfg that we are using
00860       { 
00861         std::string cfgInfo; 
00862         
00863         //Really ugly way of doing this (Robert Heeeelp!!)
00864         XMLBufferWriter top;
00865         write(top, "Config_info", gauge_xml);
00866         XMLReader from(top);
00867         XMLReader from2(from, "/Config_info");
00868         std::ostringstream os;
00869         from2.print(os);
00870         
00871         cfgInfo = os.str();
00872         
00873         if (cfgInfo != quarks[0]->getCfgInfo()){
00874           QDPIO::cerr << name << " : Quarks do not contain the same";
00875           QDPIO::cerr << " cfg info as the gauge field." ;
00876           QDPIO::cerr << "gauge: XX"<<cfgInfo<<"XX quarks: XX" ;
00877           QDPIO::cerr << quarks[0]->getCfgInfo()<<"XX"<<  endl;
00878           QDP_abort(1);
00879         }
00880       }      
00881 
00882       int decay_dir = quarks[0]->getDecayDir();
00883       //
00884       // Initialize the slow Fourier transform phases
00885       //
00886       SftMom phases(params.param.p2_max, false, decay_dir);
00887 
00888       // Create even/odd subsets on each timeslice:
00889       Set timerb;
00890       timerb.make(TimeSliceRBFunc(decay_dir));
00891       
00892       // Another sanity check. The seeds of all the quarks must be different
00893       // and thier decay directions must be the same 
00894       for(int n = 1 ; n < quarks.size(); n++){
00895         if(toBool(quarks[n]->getSeed()==quarks[0]->getSeed())){
00896           QDPIO::cerr << name << ": error, quark seeds are the same" << endl;
00897           QDP_abort(1);
00898         }
00899         
00900         if(toBool(quarks[n]->getDecayDir()!=quarks[0]->getDecayDir())){
00901           QDPIO::cerr<<name<< ": error, quark decay dirs do not match" <<endl;
00902           QDP_abort(1);
00903         }
00904       }
00905 
00906       // Instantiate the Dirac operator:
00907       Handle<EvenOddPrecLinearOperator<T,P,Q> > Doo=createOddOdd_Op(params.param,u);
00908 
00909       //Now read evecs from disk, if file is specified.
00910       multi1d<LatticeFermion> vec; // the vectors
00911       CholeskyFactors Clsk; // the Cholesky Factors 
00912       if (params.named_obj.evecs_file!="")
00913         ReadOPTEigCGVecs(vec,Clsk,params.named_obj.evecs_file);
00914       
00915       map< KeyOperator_t, ValOperator_t > data ;
00916       
00917       multi1d<multi1d< multi1d<LatticeFermion> > > quarkstilde(quarks.size());
00918       for(int n(0);n<quarks.size();n++){
00919         quarkstilde[n].resize(quarks[n]->getNumTimeSlices());
00920         for (int it(0) ; it < quarks[n]->getNumTimeSlices() ; it++){
00921           quarkstilde[n][it].resize(quarks[n]->getDilSize(it));
00922         }
00923       }
00924       
00925       /*** Everything is initialized, now to the real code ***/
00926       
00927       // chitilde = P_R S^-1 \eta_o
00928       // If there is no evecs file, then PR = 1
00929       if (params.named_obj.evecs_file!="")
00930         PRchi(quarkstilde, quarks, Doo, Clsk, vec, params.param, u);
00931       else
00932         PRchi(quarkstilde, quarks);
00933 
00934       for(int n(0);n<quarks.size();n++){
00935         for (int it(0) ; it < quarks[n]->getNumTimeSlices() ; it++){
00936           int t = quarks[n]->getT0(it) ;
00937           QDPIO::cout<<" Doing quark: "<< n <<endl ;
00938           QDPIO::cout<<"   quark: "<< n <<" has "<<quarks[n]->getDilSize(it);
00939           QDPIO::cout<<" dilutions on time slice "<< t <<endl ;
00940           for(int i = 0 ; i <  quarks[n]->getDilSize(it) ; i++){
00941             QDPIO::cout<<"   Doing dilution : "<<i<<endl ;
00942             multi1d<short int> d ;
00943             // The q chosen should be from quarkstilde = PR*quarks->dilutedSolution()
00944             LatticeFermion qbar  = quarks[n]->dilutedSource(it,i);
00945             LatticeFermion q     = quarkstilde[n][it][i];
00946             QDPIO::cout<<"   Starting recursion "<<endl ;
00947             // This is the noise vector piece.
00948             do_disco(data, qbar, q, phases, t, d, params.param.max_path_length);
00949 
00950             QDPIO::cout<<" done with recursion! "
00951                        <<"  The length of the path is: "<<d.size()<<endl ;
00952           }
00953           QDPIO::cout<<" Done with dilutions for quark: "<<n <<endl ;
00954         }
00955       }
00956 
00957       // Okay, first we are going to normalize all the pieces above by the number of 
00958       // quarks...
00959       SerialDBKey <KeyOperator_t> key ;
00960       SerialDBData<ValOperator_t> val ;
00961       map< KeyOperator_t, ValOperator_t >::iterator it;
00962 
00963       for(it=data.begin();it!=data.end();it++){
00964         key.key()  = it->first  ;
00965         val.data().op.resize(it->second.op.size()) ;
00966         for(int i(0);i<it->second.op.size();i++){
00967           val.data().op[i] = it->second.op[i]/toDouble(quarks.size());
00968         }
00969       }
00970       
00971       // Now calculate the other pieces which need no normalization...
00972       // Note using just timeslices for quarks[0]...may be a problem
00973       // if quarks dilute on diff timeslices...
00974       
00975       if (params.named_obj.evecs_file!=""){// Only if we have vectors...
00976         for (int it(0) ; it < quarks[0]->getNumTimeSlices() ; it++){
00977           multi1d<short int> d ;
00978           int t = quarks[0]->getT0(it) ;
00979           QDPIO::cout<<"   Starting recursion again"<<endl ;
00980           // Part with deflation..
00981           do_disco(data, Clsk, vec, params.param, Doo, u, t, timerb[2*t+1], phases,d);
00982           
00983           QDPIO::cout<<" done with recursion! "
00984                      <<"  The length of the path is: "<<d.size()<<endl ;
00985         }
00986       }
00987             
00988       //After all the pieces are computed we write the final result to the database
00989       // DB storage          
00990       BinaryStoreDB<SerialDBKey<KeyOperator_t>,SerialDBData<ValOperator_t> > qdp_db;
00991       
00992       // Open the file, and write the meta-data and the binary for this operator
00993       {
00994         XMLBufferWriter file_xml;
00995         
00996         push(file_xml, "DBMetaData");
00997         write(file_xml, "id", string("discoEigElemOp"));
00998         write(file_xml, "lattSize", QDP::Layout::lattSize());
00999         write(file_xml, "decay_dir", decay_dir);
01000         write(file_xml, "Params", params.param);
01001         write(file_xml, "Config_info", gauge_xml);
01002         pop(file_xml);
01003 
01004         std::string file_str(file_xml.str());
01005         qdp_db.setMaxUserInfoLen(file_str.size());
01006 
01007         qdp_db.open(params.named_obj.op_db_file, O_RDWR | O_CREAT, 0664);
01008 
01009         qdp_db.insertUserdata(file_str);
01010       }
01011 
01012       // Store all the data
01013       for(it=data.begin();it!=data.end();it++){
01014         key.key()  = it->first  ;
01015         val.data().op.resize(it->second.op.size()) ;
01016         // DON'T normalize to number of quarks here, because we only do it on a 
01017         // certain number of the terms in the trace...done above
01018         for(int i(0);i<it->second.op.size();i++)
01019           val.data().op[i] = it->second.op[i];
01020         qdp_db.insert(key,val) ;
01021       }
01022 
01023       // Close the namelist output file XMLDAT
01024       pop(xml_out);     // DiscoEigCG
01025       
01026       snoop.stop();
01027       QDPIO::cout << name << ": total time = "
01028                   << snoop.getTimeInSeconds() 
01029                   << " secs" << endl;
01030       
01031       QDPIO::cout << name << ": ran successfully" << endl;
01032       
01033       END_CODE();
01034     } 
01035   }  // namespace InlineDiscoEigCGEnv
01036 }// namespace chroma

Generated on Sun Nov 22 04:31:58 2009 for CHROMA by  doxygen 1.4.7