Line data Source code
1 : #ifndef AMREX_PRINT_H_
2 : #define AMREX_PRINT_H_
3 : #include <AMReX_Config.H>
4 :
5 : #include <AMReX.H>
6 : #include <AMReX_ParallelContext.H>
7 : #include <AMReX_ParallelDescriptor.H>
8 : #include <AMReX_ANSIEscCode.H>
9 :
10 : #include <sstream>
11 : #include <fstream>
12 : #include <iomanip>
13 : #include <utility>
14 :
15 : namespace amrex
16 : {
17 : template <typename T>
18 : std::ostream& operator<< (std::ostream& os, Array<T,AMREX_SPACEDIM> const& a)
19 : {
20 : os << AMREX_D_TERM( '(' << a[0] , <<
21 : ',' << a[1] , <<
22 : ',' << a[2]) << ')';
23 : return os;
24 : }
25 :
26 : template <typename T, typename S>
27 : std::ostream& operator<<(std::ostream& os, const std::pair<T, S>& v)
28 : {
29 : os << "(" << v.first << ", " << v.second << ")";
30 : return os;
31 : }
32 :
33 : //! This class provides the user with a few print options
34 : class Print
35 : {
36 : public:
37 :
38 : static constexpr int AllProcs = -1;
39 :
40 : /**
41 : * \brief Print on I/O Processor of the default communicator
42 : * Example: Print() << " x = " << x << '\n';
43 : */
44 5671 : explicit Print (std::ostream& os_ = amrex::OutStream())
45 5671 : : rank(ParallelContext::IOProcessorNumberSub())
46 5671 : , comm(ParallelContext::CommunicatorSub())
47 5671 : , os(os_)
48 5671 : { ss.precision(os.precision()); }
49 :
50 : /**
51 : * \brief Print on all processors of the default communicator
52 : * Example: Print(Print::AllProcs) << " x = " << x << '\n';
53 : */
54 300 : Print (int rank_, std::ostream& os_ = amrex::OutStream())
55 300 : : rank(rank_)
56 300 : , comm(ParallelContext::CommunicatorSub())
57 300 : , os(os_)
58 300 : { ss.precision(os.precision()); }
59 :
60 : /**
61 : * \brief Print on process rank_ of communicator comm_
62 : * Example: Print(rank_, comm_) << " x = " << x << '\n';
63 : */
64 : Print (int rank_, MPI_Comm comm_, std::ostream& os_ = amrex::OutStream())
65 : : rank(rank_)
66 : , comm(comm_)
67 : , os(os_)
68 : { ss.precision(os.precision()); }
69 :
70 5971 : ~Print () {
71 5971 : if (rank == AllProcs || rank == ParallelContext::MyProcSub()) {
72 5971 : std::ostream * my_os = ParallelContext::OFSPtrSub();
73 5971 : if (my_os) {
74 0 : my_os->flush();
75 0 : (*my_os) << ss.str();
76 0 : my_os->flush();
77 : }
78 5971 : os.flush();
79 5971 : os << ss.str();
80 5971 : os.flush();
81 : }
82 5971 : }
83 :
84 : Print (Print const&) = delete;
85 : Print (Print &&) = delete;
86 : Print& operator= (Print const&) = delete;
87 : Print& operator= (Print &&) = delete;
88 :
89 : Print& SetPrecision(int p) {
90 : ss.precision(p);
91 : return *this;
92 : }
93 :
94 : template <typename T>
95 46552 : Print& operator<< (const T& x) {
96 46552 : ss << x;
97 46552 : return *this;
98 : }
99 :
100 0 : Print& operator<< ( std::basic_ostream<char, std::char_traits<char> >&
101 : (*func)(std::basic_ostream<char, std::char_traits<char> >&))
102 : {
103 0 : ss << func;
104 0 : return *this;
105 : }
106 :
107 : private:
108 : int rank;
109 : MPI_Comm comm;
110 : std::ostream &os;
111 : std::ostringstream ss;
112 : };
113 :
114 : //! Print on all processors of the default communicator
115 : class AllPrint
116 : : public Print
117 : {
118 : public:
119 : //! Example: AllPrint() << " x = " << x << '\n';
120 300 : explicit AllPrint (std::ostream& os_ = amrex::OutStream())
121 300 : : Print(Print::AllProcs, os_)
122 300 : {}
123 :
124 : };
125 :
126 : //! This class prints to a file with a given base name
127 : class PrintToFile
128 : {
129 : public:
130 :
131 : static constexpr int AllProcs = -1;
132 :
133 : explicit PrintToFile (std::string file_name_)
134 : : file_name(std::move(file_name_))
135 : , rank(ParallelContext::IOProcessorNumberSub())
136 : , comm(ParallelContext::CommunicatorSub())
137 : { Initialize(); }
138 :
139 : PrintToFile (std::string file_name_, int rank_ )
140 : : file_name(std::move(file_name_))
141 : , rank(rank_)
142 : , comm(ParallelContext::CommunicatorSub())
143 : { Initialize(); }
144 :
145 : PrintToFile (std::string file_name_, int rank_, MPI_Comm comm_)
146 : : file_name(std::move(file_name_))
147 : , rank(rank_)
148 : , comm(comm_)
149 : { Initialize(); }
150 :
151 : ~PrintToFile () {
152 : if (rank == AllProcs || rank == ParallelContext::MyProcSub()) {
153 : ofs.flush();
154 : ofs << ss.str();
155 : ofs.flush();
156 : }
157 : }
158 :
159 : PrintToFile (PrintToFile const&) = delete;
160 : PrintToFile (PrintToFile &&) = delete;
161 : PrintToFile& operator= (PrintToFile const&) = delete;
162 : PrintToFile& operator= (PrintToFile &&) = delete;
163 :
164 : PrintToFile& SetPrecision(int p) {
165 : ss.precision(p);
166 : return *this;
167 : }
168 :
169 : template <typename T>
170 : PrintToFile& operator<< (const T& x) {
171 : ss << x;
172 : return *this;
173 : }
174 :
175 : PrintToFile& operator<< ( std::basic_ostream<char, std::char_traits<char> >&
176 : (*func)(std::basic_ostream<char, std::char_traits<char> >&))
177 : {
178 : ss << func;
179 : return *this;
180 : }
181 :
182 : private:
183 :
184 : void Initialize() {
185 : int my_proc = ParallelContext::MyProcSub();
186 : if (rank == AllProcs || rank == my_proc) {
187 : int my_proc_global = ParallelDescriptor::MyProc();
188 : std::string proc_file_name = file_name + "." + std::to_string(my_proc_global);
189 : #ifdef AMREX_USE_OMP
190 : proc_file_name += "." + std::to_string(omp_get_thread_num());
191 : #endif
192 : ofs.open(proc_file_name, std::ios_base::app);
193 : if (!ofs.is_open()) {
194 : amrex::Error("Could not open file for appending in amrex::Print()");
195 : }
196 : ss.precision(ofs.precision());
197 : }
198 : }
199 :
200 : std::string file_name;
201 : int rank;
202 : MPI_Comm comm;
203 : std::ofstream ofs;
204 : std::ostringstream ss;
205 : };
206 :
207 : //! Print on all processors of the default communicator
208 : class AllPrintToFile
209 : : public PrintToFile
210 : {
211 : public:
212 : //! Example: AllPrint() << " x = " << x << '\n';
213 : explicit AllPrintToFile (std::string file_name_)
214 : : PrintToFile(std::move(file_name_), Print::AllProcs)
215 : {}
216 :
217 : };
218 : }
219 :
220 : #endif
|