Teuchos - Trilinos Tools Package  Version of the Day
 All Classes Namespaces Files Functions Variables Typedefs Enumerations Enumerator Friends Macros Groups Pages
Teuchos_VerboseObjectParameterListHelpers.cpp
1 // @HEADER
2 // *****************************************************************************
3 // Teuchos: Common Tools Package
4 //
5 // Copyright 2004 NTESS and the Teuchos contributors.
6 // SPDX-License-Identifier: BSD-3-Clause
7 // *****************************************************************************
8 // @HEADER
9 
10 #include "Teuchos_VerboseObjectParameterListHelpers.hpp"
11 #include "Teuchos_StandardParameterEntryValidators.hpp"
12 #include <fstream>
13 
14 namespace {
15 
16 
17 const std::string VerboseObject_name = "VerboseObject";
18 
19 const std::string OutputFile_name = "Output File";
20 const std::string OutputFile_default = "none";
21 
22 const std::string VerbosityLevel_name = "Verbosity Level";
23 const std::string VerbosityLevel_default = "default";
26  >
27 VerbosityLevel_validator;
28 
29 
30 } // namespace
31 
32 
33 
35 Teuchos::getValidVerboseObjectSublist()
36 {
37  using Teuchos::rcp_implicit_cast;
38  static RCP<const ParameterList> validParams;
39  if (is_null(validParams)) {
40  RCP<ParameterList>
41  pl = rcp(new ParameterList(VerboseObject_name));
42  VerbosityLevel_validator = verbosityLevelParameterEntryValidator(VerbosityLevel_name);
43  pl->set(
44  VerbosityLevel_name, VerbosityLevel_default,
45  "The verbosity level to use to override whatever is set in code.\n"
46  "The value of \"default\" will allow the level set in code to be used.",
47  rcp_implicit_cast<const ParameterEntryValidator>(VerbosityLevel_validator)
48  );
49  pl->set(
50  OutputFile_name, OutputFile_default,
51  "The file to send output to. If the value \"none\" is used, then\n"
52  "whatever is set in code will be used. However, any other std::string value\n"
53  "will be used to create an std::ofstream object to a file with the given name.\n"
54  "Therefore, any valid file name is a valid std::string value for this parameter."
55  );
56  validParams = pl;
57  }
58  return validParams;
59 }
60 
61 
62 void Teuchos::setupVerboseObjectSublist( ParameterList* paramList )
63 {
64  TEUCHOS_TEST_FOR_EXCEPT(0==paramList);
65  paramList->sublist(VerboseObject_name).setParameters(
67  ).disableRecursiveValidation();
68 }
69 
70 
71 void Teuchos::readVerboseObjectSublist(
72  ParameterList* paramList,
73  RCP<FancyOStream> *oStream, EVerbosityLevel *verbLevel
74  )
75 {
76  // Validate input
77  TEUCHOS_TEST_FOR_EXCEPT(0==paramList);
78  TEUCHOS_TEST_FOR_EXCEPT(0==oStream);
79  TEUCHOS_TEST_FOR_EXCEPT(0==verbLevel);
80  ParameterList
81  &voSublist = paramList->sublist(VerboseObject_name);
82  voSublist.validateParameters(*getValidVerboseObjectSublist());
83  const std::string
84  outputFileStr = voSublist.get(OutputFile_name,OutputFile_default);
85  *verbLevel = VerbosityLevel_validator->getIntegralValue(
86  voSublist,VerbosityLevel_name,VerbosityLevel_default
87  );
88  // the default file string is nothing
89  if (outputFileStr==OutputFile_default) {
90  *oStream = null;
91  }
92  // if a file is specified then output to an fstream
93  else {
94 
95  // JJE: 14 March 2019
96  // A fix for file output of an VerboseObject.
97  //
98  // This step is very important. With filestreams it does not make
99  // sense for multiple MPI ranks to open the same file. Nor,
100  // does it seem inline with the OStream model that each stream
101  // represent a unique file. Perhaps, if that functionality is desired
102  // then the file name could be suffixed with the MPI Rank.
103  //
104  // A fundamental flaw with this implementation is that we have no knowledge
105  // of a communicator on which this OStream belongs. That makes the idea
106  // of using a rank ambiguous.
107  //
108  // The code below was added, and uses COMM_WORLD, because as-is
109  // this functionality was fundamentally broken. Without restricting
110  // the stream to a single rank, two severe consquences follow:
111  // 1) Each MPI process opens the file, which is not scalable;
112  // 2) Moreover, each MPI process *writes* to the file. Which
113  // can give the illusion that things are working, if each
114  // process writes exactly the same information (e.g., solver
115  // convergence information for a bulk synchronous solve).
116  // This introduces a terrible scalability problem, as the
117  // filesystem is then tasked with coping with concurrent writes
118  // to the same shared file, which is should make you cry a little.
119  //
120  // The resolution, is two fold:
121  // 1st, construct the ostream as a regular wrapper around cout
122  // 2nd, restrict the file creation and opening to a single process
123  // Finally, map all ostreams except the fstream one to
124  // a blackhole. Ensuring each rank has a functional stream
125  // but that only one actually emits data to disk
126  //
127 
128  // this could be a BlackHole, but calling setOutputToRootOnly does slightly
129  // more than simply blackhole output, it also disabled buffering across processes
130  *oStream = Teuchos::fancyOStream(Teuchos::rcpFromRef(std::cout));
131 
132  // Until we resolve OS streams that are communicator aware, use rank 0
133  const int outputFileMPIRank = 0;
134 
135  #if defined(HAVE_TEUCHOS_MPI)
137  #else
138  const int rank = outputFileMPIRank;
139  #endif
140 
141  if ( rank == outputFileMPIRank) {
142  RCP<std::ofstream> oFileStream = rcp(new std::ofstream());
143  // If, in the future we decide to alter buffers, then
144  // change the fstream's buffer before calling open()
145 
146  // open the fstream only on a single MPI process
147  oFileStream->open(outputFileStr);
148 
150  oFileStream->eof(), Exceptions::InvalidParameterValue,
151  "Error, the file \"" << outputFileStr << "\n given by the parameter\n"
152  "\'" << OutputFile_name << "\' in the sublist\n"
153  "\'" << voSublist.name() << "\' count not be opened for output!"
154  );
155  // wrap the fstream inside fancyOStream
156  *oStream = fancyOStream(rcp_implicit_cast<std::ostream>(oFileStream));
157  }
158 
159  #if defined(HAVE_TEUCHOS_MPI)
160  // ensure that only one stream actually emits data
161  (*oStream)->setOutputToRootOnly(outputFileMPIRank);
162  #endif
163  }
164 #ifdef TEUCHOS_DEBUG
165  voSublist.validateParameters(*getValidVerboseObjectSublist());
166 #endif
167 }
RCP< T > rcp(const boost::shared_ptr< T > &sptr)
Conversion function that takes in a boost::shared_ptr object and spits out a Teuchos::RCP object...
static int getRank()
The rank of the calling process in MPI_COMM_WORLD.
RCP< basic_FancyOStream< char > > fancyOStream(const RCP< std::basic_ostream< char > > &oStream, const std::basic_string< char > &tabIndentStr=" ", const int startingTab=0, const bool showLinePrefix=false, const int maxLenLinePrefix=10, const bool showTabCount=false, const bool showProcRank=false)
Dynamically allocate a FancyOStream and return it wrapped in an RCP object.
int rank(const Comm< Ordinal > &comm)
Get the process rank.
Standard implementation of a ParameterEntryValidator that maps from a list of strings to an enum or i...
EVerbosityLevel
Verbosity level.
bool is_null(const ArrayRCP< T > &p)
Returns true if p.get()==NULL.
TEUCHOSPARAMETERLIST_LIB_DLL_EXPORT RCP< const ParameterList > getValidVerboseObjectSublist()
Return the sublist of valid parameters for the &quot;VerboseObject&quot; sublist.
Smart reference counting pointer class for automatic garbage collection.
#define TEUCHOS_TEST_FOR_EXCEPT(throw_exception_test)
This macro is designed to be a short version of TEUCHOS_TEST_FOR_EXCEPTION() that is easier to call...
#define TEUCHOS_TEST_FOR_EXCEPTION_PURE_MSG(throw_exception_test, Exception, msg)
Macro for throwing an exception with breakpointing to ease debugging.