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
35Teuchos::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
62void Teuchos::setupVerboseObjectSublist( ParameterList* paramList )
63{
64 TEUCHOS_TEST_FOR_EXCEPT(0==paramList);
65 paramList->sublist(VerboseObject_name).setParameters(
66 *getValidVerboseObjectSublist()
67 ).disableRecursiveValidation();
68}
69
70
71void 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)
136 const int rank = Teuchos::GlobalMPISession::getRank();
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}
static int getRank()
The rank of the calling process in MPI_COMM_WORLD.
Smart reference counting pointer class for automatic garbage collection.
#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.
TEUCHOS_DEPRECATED RCP< T > rcp(T *p, Dealloc_T dealloc, bool owns_mem)
Deprecated.