FancyOutputting_test.cpp

Go to the documentation of this file.
00001 #include "Teuchos_VerboseObject.hpp"
00002 #include "Teuchos_StandardCatchMacros.hpp"
00003 #include "Teuchos_GlobalMPISession.hpp"
00004 #include "Teuchos_CommandLineProcessor.hpp"
00005 #include "Teuchos_ParameterListAcceptor.hpp"
00006 #include "Teuchos_StandardParameterEntryValidators.hpp"
00007 #include "Teuchos_VerboseObjectParameterListHelpers.hpp"
00008 #include "Teuchos_dyn_cast.hpp"
00009 #include "Teuchos_Version.hpp"
00010 
00011 // This is a typical function that would be present in Trilinos right now what
00012 // does not know about FancyOStream and does not derive from VerboseObject.
00013 // However, because of the magic of FancyOStream, this output will be indented
00014 // correctly!
00015 void someDumbFunction( std::ostream &out, const std::string &indentSpacer )
00016 {
00017   out << "\nEntering someDumbFunction(...)\n";
00018   {
00019     out << std::endl << indentSpacer << "I am \"dumb\" code that knows nothing of FancyOStream and does indenting manually! ...\n";
00020   }
00021   out << "\nLeaving someDumbFunction(...)\n";
00022   // Note that this output will be indented correctly even through it knows nothing of FancyOStream
00023 }
00024 
00025 // This is a function who's interface was written before there was a
00026 // FancyOStream and therefore is written in terms of std::ostream.  However,
00027 // in this case the implementation has been modifed to use FancyOStream as
00028 // shown.
00029 void someLessDumbFunction( std::ostream &out_arg )
00030 {
00031   using Teuchos::OSTab;
00032   // Get a FancyOStream from out_arg or create a new one ...
00033   Teuchos::RCP<Teuchos::FancyOStream>
00034     out = Teuchos::getFancyOStream(Teuchos::rcp(&out_arg,false));
00035   // Do our tab indent and our name.
00036   OSTab tab(out,1,"LDUMBALGO");
00037   *out << "\nEntering someLessDumbFunction(...)\n";
00038   {
00039     Teuchos::OSTab(out_arg).o()
00040       << std::endl << "I am less \"dumb\" code that knows about FancyOStream but my interface does not support it directly! ...\n";
00041     *Teuchos::tab(out)
00042       << std::endl << "Another print from this less \"dumb\" code ...\n";
00043   }
00044   *out << "\nLeaving someLessDumbFunction(...)\n";
00045 }
00046 
00047 // This is a typical numerical class that derives from VerboseObject and does
00048 // outputting.  Note that the use of the OSTab class requires initialization
00049 // using VerboseObject::getOSTab(...) which takes care of the hassles and is
00050 // easy to use.
00051 //
00052 // This class also derives from ParameterListAcceptor and uses helper
00053 // functio  ns to read options for VerboseObject from a parameter sublist.
00054 class AlgorithmA
00055   : public Teuchos::VerboseObject<AlgorithmA>,
00056     public Teuchos::ParameterListAcceptor
00057 {
00058 public:
00059 
00060   // Constructor(s)
00061 
00062   AlgorithmA();
00063 
00064   // Overridden from ParameterListAccpetor
00065 
00066   void setParameterList(Teuchos::RCP<Teuchos::ParameterList> const& paramList);
00067 
00068   Teuchos::RCP<Teuchos::ParameterList> getNonconstParameterList();
00069 
00070   Teuchos::RCP<Teuchos::ParameterList> unsetParameterList();
00071 
00072   Teuchos::RCP<const Teuchos::ParameterList> getParameterList() const;
00073 
00074   Teuchos::RCP<const Teuchos::ParameterList> getValidParameters() const;
00075 
00076   // Other functions
00077 
00078   void doAlgorithm();
00079 
00080 private:
00081 
00082   enum EAlgoType { ALGO_BOB, ALGO_JOHN, ALGO_HARRY };
00083 
00084   static const std::string toString( AlgorithmA::EAlgoType algoType );
00085 
00086   Teuchos::RCP<Teuchos::ParameterList> paramList_;
00087   EAlgoType algoType_;
00088   double algoTol_;
00089   
00090 };
00091 
00092 
00093 // Implementations for AlgorithmA
00094 
00095 namespace {
00096 
00097 const std::string AlgoType_name = "Algo Type";
00098 const std::string AlgoType_default = "Bob";
00099 
00100 const std::string AlgoTol_name = "Algo Tol";
00101 const double AlgoTol_default = 1e-5;
00102 
00103 } // namespace
00104 
00105 const std::string AlgorithmA::toString( AlgorithmA::EAlgoType algoType )
00106 {
00107   switch(algoType) {
00108     case ALGO_BOB: return "Bob";
00109     case ALGO_JOHN: return "John";
00110     case ALGO_HARRY: return "Harry";
00111     default: TEST_FOR_EXCEPT("Should never get here!");
00112   }
00113   return ""; // never be called!
00114 }
00115 
00116 
00117 AlgorithmA::AlgorithmA()
00118   : algoType_(ALGO_BOB), algoTol_(AlgoTol_default)
00119 {
00120   this->setLinePrefix("ALGO_A"); // I tell me who I am for line prefix outputting
00121 }
00122 
00123 
00124 void AlgorithmA::setParameterList(
00125   Teuchos::RCP<Teuchos::ParameterList> const& paramList
00126   )
00127 {
00128   TEST_FOR_EXCEPT(is_null(paramList));
00129   // Validate and set the parameter defaults.  Here, the parameters are
00130   // validated and the state of *this is not changed unless the parameter
00131   // validation succeeds.  Also, any validators that are defined for various
00132   // parameters are passed along so that they can be used in extracting
00133   // values!
00134   paramList->validateParametersAndSetDefaults(*this->getValidParameters(),0);
00135   paramList_ = paramList;
00136   // Get the enum value for the algorithm type. Here, the actual type stored
00137   // for the algorithm type in the parameter list is an std::string but this
00138   // helper function does all the work of extracting the validator set in
00139   // getValidParameters() and set on *paramList_ through the
00140   // validateParametersAndSetDefaults(...) function above!
00141   algoType_ = Teuchos::getIntegralValue<EAlgoType>(*paramList_,AlgoType_name);
00142   // Get the tolerance for the algorithm.  Here, the actual type of the
00143   // parameter stored on input could be many different types.  Here, I can
00144   // just assume that it is a double since it would have been converted to a
00145   // double above in validateParametersAndSetDefaults(...).
00146   algoTol_ = Teuchos::getParameter<double>(*paramList_,AlgoTol_name);
00147   // Read the sublist for verbosity settings.
00148   Teuchos::readVerboseObjectSublist(&*paramList_,this);
00149 #ifdef TEUCHOS_DEBUG
00150   paramList_->validateParameters(*this->getValidParameters());
00151 #endif
00152 }
00153 
00154 
00155 Teuchos::RCP<Teuchos::ParameterList>
00156 AlgorithmA::getNonconstParameterList()
00157 {
00158   return paramList_;
00159 }
00160 
00161 
00162 Teuchos::RCP<Teuchos::ParameterList>
00163 AlgorithmA::unsetParameterList()
00164 {
00165   Teuchos::RCP<Teuchos::ParameterList> paramList = paramList_;
00166   paramList_ = Teuchos::null;
00167   return paramList;
00168 }
00169 
00170 
00171 Teuchos::RCP<const Teuchos::ParameterList>
00172 AlgorithmA::getParameterList() const
00173 {
00174   return paramList_;
00175 }
00176 
00177 
00178 Teuchos::RCP<const Teuchos::ParameterList>
00179 AlgorithmA::getValidParameters() const
00180 {
00181   using Teuchos::RCP; using Teuchos::ParameterList;
00182   using Teuchos::setStringToIntegralParameter;
00183   using Teuchos::tuple;
00184   static RCP<const ParameterList> validParams;
00185   if (is_null(validParams)) {
00186     RCP<ParameterList>
00187       pl = Teuchos::rcp(new ParameterList("AlgorithmA"));
00188     setStringToIntegralParameter<EAlgoType>(
00189       AlgoType_name, AlgoType_default,
00190       "The algorithm type to use",
00191       tuple<std::string>("Bob", "John", "Harry"),
00192       tuple<EAlgoType>(ALGO_BOB, ALGO_JOHN, ALGO_HARRY),
00193       &*pl
00194       );
00195     Teuchos::setDoubleParameter(
00196       AlgoTol_name, AlgoTol_default,
00197       "The tolerance for the algorithm.",
00198       &*pl
00199       );
00200     Teuchos::setupVerboseObjectSublist(&*pl);
00201     validParams = pl;
00202   }
00203   return validParams;
00204 }
00205 
00206 
00207 void AlgorithmA::doAlgorithm()
00208 {
00209   using Teuchos::OSTab;
00210   // Get the verbosity that we are going to use
00211   Teuchos::EVerbosityLevel verbLevel = this->getVerbLevel();
00212   // Here I grab the stream that I will use for outputting.  It is a good
00213   // idea to grab the RCP to this object just to be safe.
00214   Teuchos::RCP<Teuchos::FancyOStream> out = this->getOStream();
00215   // Here I set my line prefix and a single indent.  The convention will
00216   // be that a called function will set its own indent.  This convention makes
00217   // the most sense.
00218   OSTab tab = this->getOSTab(); // This sets the line prefix and adds one tab
00219   if(out.get() && includesVerbLevel(verbLevel,Teuchos::VERB_LOW,true))
00220     *out << "\nEntering AlgorithmA::doAlgorithm() with verbLevel="<<Teuchos::toString(verbLevel)<<"\n";
00221   {
00222     // Here I use a simple macro for the typical case of one tab indent to
00223     // save typing.  The idea is that this should be as easy to write as
00224     // OSTab tab; but is more general.
00225     TEUCHOS_OSTAB;
00226     if(out.get() && includesVerbLevel(verbLevel,Teuchos::VERB_LOW,true))
00227       *out
00228         << "\nI am \"smart\" code that knows about FancyOStream and OSTab ...\n"
00229         << "\nDoing algorithm of type \""<<toString(algoType_)<<"\""
00230         << "\nUsing tolerance of " << algoTol_ << "\n";
00231     {
00232       // Here I temporaraly turn off tabbing so that I can print an imporant warning message.
00233       OSTab tab2 = this->getOSTab(OSTab::DISABLE_TABBING);
00234       if(out.get() && includesVerbLevel(verbLevel,Teuchos::VERB_LOW,true))
00235         *out << "\n***\n*** Warning, I am doing something very dangerous so watch out!!!\n***\n";
00236     }
00237     if(out.get() && includesVerbLevel(verbLevel,Teuchos::VERB_LOW,true))
00238       *out << "\nHere I am doing some more stuff and printing with indenting turned back on!\n";
00239     {
00240       // Here I am going to be calling a dumb piece of code that does not
00241       // know about the FancyOStream system and will not use tabs or
00242       // anything like that.  There is a lot of code in Trilinos that
00243       // falls in this category.  The first thing I do is manually indent
00244       // the stream one tab and set a line prefix for the dumb code since
00245       // it may not do this itself.
00246       OSTab tab2 = this->getOSTab(1,"DUMBALGO");
00247       // Now a Pass in the updated FancyOStream object, which is properly
00248       // indented now, through the std::ostream interface.  I also pass in
00249       // the std::string that is being used for creating tabs.  The output from
00250       // this function will be indented correctly without the dumb code
00251       // knowing it!
00252       someDumbFunction(*out,out->getTabIndentStr());
00253     }
00254     // Here I am calling a less dumb piece of code who's interface does
00255     // not support FancyOStream but the implementation does.  Note that
00256     // this function also follows the convention of doing an initial
00257     // indent.
00258     someLessDumbFunction(*out);
00259   }
00260   if(out.get() && includesVerbLevel(verbLevel,Teuchos::VERB_LOW,true))
00261     *out << "\nLeaving AlgorithmA::doAlgorithm()\n";
00262 }
00263 
00264 
00265 //
00266 // Here is a simple driver function that I call over and over to show
00267 // different features of FancyOStream
00268 //
00269 
00270 void doAlgorithmStuff( Teuchos::ParameterList *algoParams = 0 )
00271 {
00272 
00273   // Here I just create the algorithm object that derives from VerboseObject.
00274   // By default, this object will print to *Verbose::getDefaultOStream()
00275   AlgorithmA algoA;
00276   if(algoParams)
00277     algoA.setParameterList(Teuchos::rcp(algoParams,false));
00278   // Note that here I could change the stream just this object prints to
00279   // by calling algoA.setOStream(...).
00280   
00281   // Now I call the algorithm which will print to its default output stream
00282   algoA.doAlgorithm();
00283   
00284   *algoA.getOStream() << std::endl;
00285   
00286 }
00287 
00288 //
00289 // Test that static initailziation of VerboseObjectBase and VerboseObject works!
00290 //
00291 
00292 class TestVerboseObjectBaseInitialization {
00293 public:
00294   TestVerboseObjectBaseInitialization()
00295     {
00296       // Get the verbosity level for AlgorithmA
00297       Teuchos::EVerbosityLevel verbLevel = Teuchos::VerboseObject<AlgorithmA>::getDefaultVerbLevel();
00298       TEST_FOR_EXCEPT_PRINT(verbLevel!=Teuchos::VERB_DEFAULT,&std::cerr);
00299       // Print to the default default OStream to make sure that the initialization
00300       // trick worked!
00301       *Teuchos::VerboseObjectBase::getDefaultOStream()
00302         << "\n***\n*** Printing to default OStream before main() even starts!\n***\n\n"
00303         << std::flush;
00304     }
00305 };
00306 
00307 static TestVerboseObjectBaseInitialization testVerboseObjectBaseInitialization;
00308 
00309 //
00310 // Main driver program
00311 //
00312 
00313 int main(int argc, char* argv[])
00314 {
00315 
00316   using Teuchos::RCP;
00317   using Teuchos::rcp;
00318   using Teuchos::FancyOStream;
00319   using Teuchos::VerboseObjectBase;
00320   using Teuchos::OSTab;
00321   using Teuchos::dyn_cast;
00322   using Teuchos::CommandLineProcessor;
00323 
00324   bool success = true;
00325 
00326   Teuchos::GlobalMPISession mpiSession(&argc,&argv);
00327   const int numProcs = Teuchos::GlobalMPISession::getNProc();
00328 
00329   try {
00330 
00331     // Get some commandline options
00332     CommandLineProcessor  clp;
00333     clp.throwExceptions(false);
00334     clp.addOutputSetupOptions(true);
00335     CommandLineProcessor::EParseCommandLineReturn parse_return = clp.parse(argc,argv);
00336     if( parse_return != CommandLineProcessor::PARSE_SUCCESSFUL ) return parse_return;
00337 
00338     // Here I am just grabbing the default output stream
00339     RCP<FancyOStream>
00340       out = VerboseObjectBase::getDefaultOStream();
00341     // Note that the VerboseObject manages FancyOStream objects and not just
00342     // std::ostream objects.  This is important to the design and very
00343     // resonable I think.
00344 
00345     *out << std::endl << Teuchos::Teuchos_Version() << std::endl << std::endl;
00346 
00347     //
00348     // Now I call doAlgorithmStuff() a bunch of times with different setups to
00349     // show the different kinds of line prefix options
00350     //
00351   
00352     *out << "\n***\n*** Testing VerboseObject base class use\n***\n";
00353   
00354     *out << "\n*** Algorithm output with default formatting\n\n";
00355     doAlgorithmStuff();
00356   
00357     out->setShowAllFrontMatter(false).setShowProcRank(numProcs>1);
00358     *out << "\n*** Algorithm output with no front matter\n\n";
00359     out->setShowAllFrontMatter(false);
00360     doAlgorithmStuff();
00361   
00362     out->setShowAllFrontMatter(false).setShowProcRank(numProcs>1);
00363     *out << "\n*** Algorithm output with processor ranks\n\n";
00364     out->setShowAllFrontMatter(false).setShowProcRank(true);
00365     doAlgorithmStuff();
00366   
00367     out->setShowAllFrontMatter(false).setShowProcRank(numProcs>1);
00368     *out << "\n*** Algorithm output with line prefix names\n\n";
00369     out->setShowAllFrontMatter(false).setShowLinePrefix(true);
00370     doAlgorithmStuff();
00371   
00372     out->setShowAllFrontMatter(false).setShowProcRank(numProcs>1);
00373     *out << "\n*** Algorithm output with tab counts\n\n";
00374     out->setShowAllFrontMatter(false).setShowTabCount(true);
00375     doAlgorithmStuff();
00376   
00377     out->setShowAllFrontMatter(false).setShowProcRank(numProcs>1);
00378     *out << "\n*** Algorithm output with line prefix names and tab counts\n\n";
00379     out->setShowAllFrontMatter(false).setShowLinePrefix(true).setShowTabCount(true);
00380     doAlgorithmStuff();
00381   
00382     out->setShowAllFrontMatter(false).setShowProcRank(numProcs>1);
00383     *out << "\n*** Algorithm output with processor ranks and line prefix names\n\n";
00384     out->setShowAllFrontMatter(false).setShowProcRank(true).setShowLinePrefix(true);
00385     doAlgorithmStuff();
00386   
00387     out->setShowAllFrontMatter(false).setShowProcRank(numProcs>1);
00388     *out << "\n*** Algorithm output with processor ranks and tab counts\n\n";
00389     out->setShowAllFrontMatter(false).setShowProcRank(true).setShowTabCount(true);
00390     doAlgorithmStuff();
00391   
00392     out->setShowAllFrontMatter(false).setShowProcRank(numProcs>1);
00393     *out << "\n*** Algorithm output with processor ranks, line prefix names, and tab counts\n\n";
00394     out->setShowAllFrontMatter(false).setShowProcRank(true).setShowLinePrefix(true).setShowTabCount(true);
00395     doAlgorithmStuff();
00396   
00397     out->setShowAllFrontMatter(false).setShowProcRank(numProcs>1);
00398     *out << "\n*** Algorithm output with processor ranks, line prefix names, and tab counts but no output for AlgorithmA\n\n";
00399     Teuchos::VerboseObject<AlgorithmA>::setDefaultVerbLevel(Teuchos::VERB_NONE);
00400     out->setShowAllFrontMatter(false).setShowProcRank(true).setShowLinePrefix(true).setShowTabCount(true);
00401     doAlgorithmStuff();
00402     Teuchos::VerboseObject<AlgorithmA>::setDefaultVerbLevel(Teuchos::VERB_DEFAULT);
00403 
00404     *out << "\n*** Running the algorithm by setting parameters in the parameter list ...\n";
00405 
00406     Teuchos::ParameterList algoParams("AlgorithmA");
00407 
00408     out->setShowAllFrontMatter(false).setShowProcRank(numProcs>1);
00409     *out << "\n*** Set AlgorithmA verbosity level to extreme through a parameter list\n\n";
00410     algoParams.sublist("VerboseObject").set("Verbosity Level","extreme");
00411     algoParams.set("Algo Type","Harry");
00412     algoParams.set("Algo Tol",0.3);
00413     doAlgorithmStuff(&algoParams);
00414 
00415     out->setShowAllFrontMatter(false).setShowProcRank(numProcs>1);
00416     *out << "\n*** Set AlgorithmA verbosity level to medium and the output file \"AlgorithmA.out\" through a parameter list\n\n";
00417     algoParams.sublist("VerboseObject").set("Verbosity Level","medium");
00418     algoParams.sublist("VerboseObject").set("Output File","AlgorithmA.out");
00419     algoParams.set("Algo Type","John");
00420     algoParams.set("Algo Tol",10);
00421     doAlgorithmStuff(&algoParams);
00422 
00423     out->setShowAllFrontMatter(false).setShowProcRank(numProcs>1);
00424     *out << "\n*** Set AlgorithmA verbosity level to low and the output back to default through a parameter list\n\n";
00425     algoParams.sublist("VerboseObject").set("Verbosity Level","low");
00426     algoParams.sublist("VerboseObject").set("Output File","none");
00427     algoParams.set("Algo Tol","20");
00428     doAlgorithmStuff(&algoParams);
00429 
00430     out->setShowAllFrontMatter(false).setShowProcRank(numProcs>1);
00431     *out << "\n***\n*** Do some more simple tests to make sure things work correctly\n***\n\n";
00432 
00433     //
00434     // Now I do some other simple tests just to see that FancyOStream is working
00435     // correctly
00436     //
00437 
00438     out->setShowAllFrontMatter(false).setShowProcRank(numProcs>1).setShowTabCount(true);
00439     out->setProcRankAndSize(mpiSession.getRank(),mpiSession.getNProc());
00440     
00441     *out << "\n***\n*** Testing basic FancyOStream and OSTab classes\n***\n\n";
00442     
00443     *out << "\nThis is very good output\nand I like it a lot!\n";
00444     *out << "";
00445     *out << "\n";
00446     *out << "This should";
00447     *out << " all be";
00448     *out << " printed on";
00449     *out << " the same";
00450     *out << " line two lines below the above output!\n";
00451     RCP<FancyOStream>
00452       out2 = rcp(new FancyOStream(rcp(new std::ostringstream),"  "));
00453     {
00454       OSTab tab1(out);
00455       *out << "This should be indented one tab!\n";
00456       {
00457         OSTab tab2(out);
00458         *out << "This should be indented two tabs!\n";
00459         *out2 << "This should be indented zero tabs from out2!\n";
00460         {
00461           OSTab tab3(out2);
00462           *out << "This should be indented two tabs!\n";
00463           *out2 << "This should be indented one tab from out2!\n";
00464         }
00465       }
00466       *out << "This should be indented one tab!\n";
00467     }
00468     *out << "This should be indented zero tabs!\n";
00469     
00470     *out << std::endl; // This required overflow() to be overridden!
00471 
00472     *out << "\n***\n*** Now outputting the latent output that was sent to out2\n***\n\n"
00473          << dyn_cast<std::ostringstream>(*out2->getOStream()).str();
00474 
00475     if(success)
00476       *out << "\nEnd Result: TEST PASSED" << std::endl;
00477     
00478   }
00479   TEUCHOS_STANDARD_CATCH_STATEMENTS(true,std::cerr,success);
00480     
00481   return ( success ? 0 : 1 );
00482   
00483 }
 All Classes Namespaces Files Functions Variables Typedefs Enumerations Enumerator Friends Defines

Generated on Tue Oct 20 10:13:59 2009 for Teuchos Package Browser (Single Doxygen Collection) by  doxygen 1.6.1