Teuchos - Trilinos Tools Package Version of the Day
Loading...
Searching...
No Matches
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
14namespace {
15
16
17const std::string VerboseObject_name = "VerboseObject";
18
19const std::string OutputFile_name = "Output File";
20const std::string OutputFile_default = "none";
21
22const std::string VerbosityLevel_name = "Verbosity Level";
23const std::string VerbosityLevel_default = "default";
26 >
27VerbosityLevel_validator;
28
29
30} // namespace
31
32
33
36{
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
62void Teuchos::setupVerboseObjectSublist( ParameterList* paramList )
63{
64 TEUCHOS_TEST_FOR_EXCEPT(0==paramList);
65 paramList->sublist(VerboseObject_name).setParameters(
67 ).disableRecursiveValidation();
68}
69
70
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}
int rank(const Comm< Ordinal > &comm)
Get the process rank.
static int getRank()
The rank of the calling process in MPI_COMM_WORLD.
Smart reference counting pointer class for automatic garbage collection.
RCP< T2 > rcp_implicit_cast(const RCP< T1 > &p1)
Implicit cast of underlying RCP type from T1* to T2*.
RCP< T > rcpFromRef(T &r)
Return a non-owning weak RCP object from a raw object reference for a defined type.
Standard implementation of a ParameterEntryValidator that maps from a list of strings to an enum or i...
TEUCHOSPARAMETERLIST_LIB_DLL_EXPORT void readVerboseObjectSublist(ParameterList *paramList, RCP< FancyOStream > *oStream, EVerbosityLevel *verbLevel)
Read the parameters in the "VerboseObject" sublist and set them on the given VerboseObject.
TEUCHOSPARAMETERLIST_LIB_DLL_EXPORT void setupVerboseObjectSublist(ParameterList *paramList)
Setup a sublist called "VerboseObject" in the given parameter list.
TEUCHOSPARAMETERLIST_LIB_DLL_EXPORT RCP< const ParameterList > getValidVerboseObjectSublist()
Return the sublist of valid parameters for the "VerboseObject" sublist.
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.
#define TEUCHOS_TEST_FOR_EXCEPTION_PURE_MSG(throw_exception_test, Exception, msg)
Macro for throwing an exception with breakpointing to ease debugging.
#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.
bool is_null(const boost::shared_ptr< T > &p)
Returns true if p.get()==NULL.
TEUCHOS_DEPRECATED RCP< T > rcp(T *p, Dealloc_T dealloc, bool owns_mem)
Deprecated.