ECCE @ EIC Software
 All Classes Namespaces Files Functions Variables Typedefs Enumerations Enumerator Friends Macros Groups Pages
G4MTcoutDestination.cc
Go to the documentation of this file. Or view the newest version in sPHENIX GitHub for file G4MTcoutDestination.cc
1 //
2 // ********************************************************************
3 // * License and Disclaimer *
4 // * *
5 // * The Geant4 software is copyright of the Copyright Holders of *
6 // * the Geant4 Collaboration. It is provided under the terms and *
7 // * conditions of the Geant4 Software License, included in the file *
8 // * LICENSE and available at http://cern.ch/geant4/license . These *
9 // * include a list of copyright holders. *
10 // * *
11 // * Neither the authors of this software system, nor their employing *
12 // * institutes,nor the agencies providing financial support for this *
13 // * work make any representation or warranty, express or implied, *
14 // * regarding this software system or assume any liability for its *
15 // * use. Please see the license in the file LICENSE and URL above *
16 // * for the full disclaimer and the limitation of liability. *
17 // * *
18 // * This code implementation is the result of the scientific and *
19 // * technical work of the GEANT4 collaboration. *
20 // * By using, copying, modifying or distributing the software (or *
21 // * any work based on the software) you agree to acknowledge its *
22 // * use in resulting scientific publications, and indicate your *
23 // * acceptance of all terms of the Geant4 Software license. *
24 // ********************************************************************
25 //
26 //
27 // --------------------------------------------------------------------
28 //
29 // G4MTcoutDestination.cc
30 //
31 // --------------------------------------------------------------------
32 
33 #include <sstream>
34 #include <assert.h>
35 
36 #include "G4MTcoutDestination.hh"
37 #include "G4LockcoutDestination.hh"
39 #include "G4FilecoutDestination.hh"
41 #include "G4strstreambuf.hh"
42 #include "G4AutoLock.hh"
43 
44 namespace
45 {
46  G4String empty = "";
47 }
48 
50  : ref_defaultOut(nullptr), ref_masterOut(nullptr),
51  masterDestinationFlag(true),masterDestinationFmtFlag(true),
52  id(threadId), useBuffer(false), ignoreCout(false), ignoreInit(true),
53  prefix("G4WT")
54 {
55  // TODO: Move these two out of here and in the caller
58 
61 }
62 
63 void G4MTcoutDestination::SetDefaultOutput( G4bool addmasterDestination ,
64  G4bool formatAlsoMaster )
65 {
66  masterDestinationFlag = addmasterDestination;
67  masterDestinationFmtFlag = formatAlsoMaster;
68  // Formatter: add prefix to each thread
69  const auto f = [this](G4String& msg)->G4bool {
70  std::ostringstream str;
71  str<<prefix;
72  if ( id!=G4Threading::GENERICTHREAD_ID ) str<<id;
73  str<<" > "<<msg;
74  msg = str.str();
75  return true;
76  };
77  // Block cout if not in correct state
78  const auto filter_out = [this](G4String&)->G4bool {
79  if (this->ignoreCout ||
80  ( this->ignoreInit &&
81  this->stateMgr->GetCurrentState() == G4State_Init ) )
82  { return false; }
83  return true;
84  };
85 
86  // Default behavior, add a destination that uses cout and uses a mutex
87  auto output = G4coutDestinationUPtr( new G4LockcoutDestination );
88  ref_defaultOut = output.get();
89  output->AddCoutTransformer(filter_out);
90  output->AddCoutTransformer(f);
91  output->AddCerrTransformer(f);
92  push_back( std::move(output) );
93  if ( addmasterDestination )
94  {
95  AddMasterOutput(formatAlsoMaster);
96  }
97 }
98 
100 {
101  // Add a destination, that forwards the message to the master thread
103  ref_masterOut = forwarder.get();
104  const auto filter_out = [this](G4String&)->G4bool {
105  if (this->ignoreCout ||
106  ( this->ignoreInit &&
107  this->stateMgr->GetCurrentState() == G4State_Idle ) )
108  { return false; }
109  return true;
110  };
111  forwarder->AddCoutTransformer(filter_out);
112  if ( formatAlsoMaster )
113  {
114  // Formatter: add prefix to each thread
115  const auto f = [this](G4String& msg)->G4bool {
116  std::ostringstream str;
117  str<<prefix;
118  if ( id!=G4Threading::GENERICTHREAD_ID ) str<<id;
119  str<<" > "<<msg;
120  msg = str.str();
121  return true;
122  };
123  forwarder->AddCoutTransformer(f);
124  forwarder->AddCerrTransformer(f);
125  }
126  push_back( std::move(forwarder ) );
127 
128 }
129 
131 {
132  if ( useBuffer ) DumpBuffer();
133 }
134 
136 {
137  clear();
139 }
140 
142  G4bool suppressDefault)
143 {
144  // Logic: we create a file destination. We want this to get only the G4cout
145  // stream and should discard everything in G4cerr.
146  // First we create the destination with the appropriate open mode
147 
148  std::ios_base::openmode mode = (ifAppend ? std::ios_base::app
149  : std::ios_base::trunc);
150  auto output = G4coutDestinationUPtr( new G4FilecoutDestination(fileN,mode));
151 
152  // This reacts only to G4cout, so let's make a filter that removes everything
153  // from G4cerr
154  output->AddCerrTransformer( [](G4String&) { return false;} );
155  push_back(std::move(output));
156  // Silence G4cout from default formatter
157  if ( suppressDefault )
158  {
159  ref_defaultOut->AddCoutTransformer( [](G4String&) { return false; } );
160  if ( ref_masterOut )
161  ref_masterOut->AddCoutTransformer( [](G4String&) { return false; } );
162  }
163 }
164 
166  G4bool suppressDefault)
167 {
168  // See HandleFileCout for explanation, switching cout with cerr
169 
170  std::ios_base::openmode mode = (ifAppend ? std::ios_base::app
171  : std::ios_base::trunc);
172  auto output = G4coutDestinationUPtr( new G4FilecoutDestination(fileN,mode));
173  output->AddCoutTransformer( [](G4String&) { return false;} );
174  push_back(std::move(output));
175  if ( suppressDefault )
176  {
177  ref_defaultOut->AddCerrTransformer( [](G4String&) { return false; } );
178  if ( ref_masterOut )
179  ref_masterOut->AddCerrTransformer( [](G4String&) { return false; } );
180  }
181 }
182 
184  G4bool ifAppend)
185 {
186  // First let's go back to the default
187  Reset();
188  if ( fileN != "**Screen**" )
189  {
190  HandleFileCout(fileN,ifAppend,true);
191  }
192 }
193 
195 {
196  // I was using buffered output and now I want to turn it off, dump current
197  // buffer content and reset output
198  if ( useBuffer && !flag )
199  {
200  DumpBuffer();
201  Reset();
202  }
203  else if ( useBuffer && flag ) { /* do nothing: already using */ }
204  else if ( !useBuffer && !flag ) { /* do nothing: not using */ }
205  else if ( !useBuffer && flag )
206  {
207  // Remove everything, in this case also removing the forward to the master
208  // thread, we want everything to be dumpled to a file
209  clear();
210  const size_t infiniteSize = 0;
211  push_back(G4coutDestinationUPtr(new G4BuffercoutDestination(infiniteSize)));
212  }
213  else { assert(false); } // Should never happen
214  useBuffer = flag;
215 }
216 
218  G4bool ifAppend)
219 {
220  // This is like the equivalent SetCoutFileName, but in this case we do not
221  // remove or silence what is already exisiting
222  HandleFileCout(fileN,ifAppend,false);
223 }
224 
226  G4bool ifAppend)
227 {
228  // See SetCoutFileName for explanation
229  Reset();
230  if ( fileN != "**Screen**")
231  {
232  HandleFileCerr(fileN,ifAppend,true);
233  }
234 }
235 
237  G4bool ifAppend)
238 {
239  HandleFileCerr(fileN,ifAppend,false);
240 }
241 
243 {
244  if (tid<0) { ignoreCout = false; }
245  else { ignoreCout = (tid!=id); }
246 }
247 
248 namespace
249 {
251 }
252 
254 {
255  G4AutoLock l(&coutm);
256  std::ostringstream msg;
257  msg << "=======================\n";
258  msg << "cout buffer(s) for worker with ID:" << id << std::endl;
260  G4bool sep = false;
261  std::for_each( begin() , end(),
262  [this,&sep](G4coutDestinationUPtr& el) {
263  auto cout = dynamic_cast<G4BuffercoutDestination*>(el.get());
264  if ( cout != nullptr ) {
265  cout->FlushG4cout();
266  if ( sep ) { G4coutDestination::ReceiveG4cout("==========\n"); }
267  else { sep = true; }
268  }
269  } );
270  sep = false;
271  msg.str("");
272  msg.clear();
273  msg << "=======================\n";
274  msg << "cerr buffer(s) for worker with ID:" << id
275  << " (goes to std error)" << std::endl;
277  std::for_each( begin() , end(),
278  [this,&sep](G4coutDestinationUPtr& el) {
279  auto cout = dynamic_cast<G4BuffercoutDestination*>(el.get());
280  if ( cout != nullptr ) {
281  cout->FlushG4cerr();
282  if (sep ) { G4coutDestination::ReceiveG4cout("==========\n"); }
283  else { sep = true; }
284  }
285  } );
286  G4coutDestination::ReceiveG4cout("=======================\n");
287 }