Geant4 Cross Reference |
1 // 1 // 2 // ******************************************* 2 // ******************************************************************** 3 // * License and Disclaimer 3 // * License and Disclaimer * 4 // * 4 // * * 5 // * The Geant4 software is copyright of th 5 // * The Geant4 software is copyright of the Copyright Holders of * 6 // * the Geant4 Collaboration. It is provided 6 // * the Geant4 Collaboration. It is provided under the terms and * 7 // * conditions of the Geant4 Software License 7 // * conditions of the Geant4 Software License, included in the file * 8 // * LICENSE and available at http://cern.ch/ 8 // * LICENSE and available at http://cern.ch/geant4/license . These * 9 // * include a list of copyright holders. 9 // * include a list of copyright holders. * 10 // * 10 // * * 11 // * Neither the authors of this software syst 11 // * Neither the authors of this software system, nor their employing * 12 // * institutes,nor the agencies providing fin 12 // * institutes,nor the agencies providing financial support for this * 13 // * work make any representation or warran 13 // * work make any representation or warranty, express or implied, * 14 // * regarding this software system or assum 14 // * regarding this software system or assume any liability for its * 15 // * use. Please see the license in the file 15 // * use. Please see the license in the file LICENSE and URL above * 16 // * for the full disclaimer and the limitatio 16 // * for the full disclaimer and the limitation of liability. * 17 // * 17 // * * 18 // * This code implementation is the result 18 // * This code implementation is the result of the scientific and * 19 // * technical work of the GEANT4 collaboratio 19 // * technical work of the GEANT4 collaboration. * 20 // * By using, copying, modifying or distri 20 // * By using, copying, modifying or distributing the software (or * 21 // * any work based on the software) you ag 21 // * any work based on the software) you agree to acknowledge its * 22 // * use in resulting scientific publicati 22 // * use in resulting scientific publications, and indicate your * 23 // * acceptance of all terms of the Geant4 Sof 23 // * acceptance of all terms of the Geant4 Software license. * 24 // ******************************************* 24 // ******************************************************************** 25 // 25 // 26 // G4MTcoutDestination class implementation << 26 // >> 27 // -------------------------------------------------------------------- >> 28 // >> 29 // G4MTcoutDestination.cc 27 // 30 // 28 // Authors: M.Asai, A.Dotti (SLAC) - 23 May 20 << 31 // -------------------------------------------------------------------- 29 // ------------------------------------------- << 30 32 31 #include "G4MTcoutDestination.hh" << 33 #include <sstream> >> 34 #include <assert.h> 32 35 33 #include "G4AutoLock.hh" << 36 #include "G4MTcoutDestination.hh" 34 #include "G4BuffercoutDestination.hh" << 35 #include "G4FilecoutDestination.hh" << 36 #include "G4LockcoutDestination.hh" 37 #include "G4LockcoutDestination.hh" 37 #include "G4MasterForwardcoutDestination.hh" 38 #include "G4MasterForwardcoutDestination.hh" 38 << 39 #include "G4FilecoutDestination.hh" 39 #include <cassert> << 40 #include "G4BuffercoutDestination.hh" 40 #include <sstream> << 41 #include "G4strstreambuf.hh" >> 42 #include "G4AutoLock.hh" 41 43 42 namespace 44 namespace 43 { 45 { 44 G4String empty = ""; 46 G4String empty = ""; 45 } 47 } 46 48 47 // ------------------------------------------- << 48 G4MTcoutDestination::G4MTcoutDestination(const 49 G4MTcoutDestination::G4MTcoutDestination(const G4int& threadId) 49 : id(threadId) << 50 : ref_defaultOut(nullptr), ref_masterOut(nullptr), >> 51 masterDestinationFlag(true),masterDestinationFmtFlag(true), >> 52 id(threadId), useBuffer(false), ignoreCout(false), ignoreInit(true), >> 53 prefix("G4WT") 50 { 54 { 51 // TODO: Move this out of here and in the ca << 55 // TODO: Move these two out of here and in the caller 52 G4iosSetDestination(this); << 56 G4coutbuf.SetDestination(this); >> 57 G4cerrbuf.SetDestination(this); 53 58 54 stateMgr = G4StateManager::GetStateManager() << 59 stateMgr=G4StateManager::GetStateManager(); 55 SetDefaultOutput(masterDestinationFlag, mast << 60 SetDefaultOutput(masterDestinationFlag,masterDestinationFmtFlag); 56 } 61 } 57 62 58 // ------------------------------------------- << 63 void G4MTcoutDestination::SetDefaultOutput( G4bool addmasterDestination , 59 void G4MTcoutDestination::SetDefaultOutput(G4b << 64 G4bool formatAlsoMaster ) 60 G4b << 61 { 65 { 62 masterDestinationFlag = addmasterDestinat << 66 masterDestinationFlag = addmasterDestination; 63 masterDestinationFmtFlag = formatAlsoMaster; 67 masterDestinationFmtFlag = formatAlsoMaster; 64 // Formatter: add prefix to each thread 68 // Formatter: add prefix to each thread 65 const auto f = [this](G4String& msg) -> G4bo << 69 const auto f = [this](G4String& msg)->G4bool { 66 std::ostringstream str; 70 std::ostringstream str; 67 str << prefix; << 71 str<<prefix; 68 if(id != G4Threading::GENERICTHREAD_ID) << 72 if ( id!=G4Threading::GENERICTHREAD_ID ) str<<id; 69 { << 73 str<<" > "<<msg; 70 str << id; << 71 } << 72 str << " > " << msg; << 73 msg = str.str(); 74 msg = str.str(); 74 return true; 75 return true; 75 }; 76 }; 76 // Block cout if not in correct state 77 // Block cout if not in correct state 77 const auto filter_out = [this](G4String&) -> << 78 const auto filter_out = [this](G4String&)->G4bool { 78 return !( << 79 if (this->ignoreCout || 79 this->ignoreCout || << 80 ( this->ignoreInit && 80 (this->ignoreInit && this->stateMgr->Get << 81 this->stateMgr->GetCurrentState() == G4State_Init ) ) >> 82 { return false; } >> 83 return true; 81 }; 84 }; 82 85 83 // Default behavior, add a destination that 86 // Default behavior, add a destination that uses cout and uses a mutex 84 auto output = G4coutDestinationUPtr(new G << 87 auto output = G4coutDestinationUPtr( new G4LockcoutDestination ); 85 ref_defaultOut = output.get(); 88 ref_defaultOut = output.get(); 86 output->AddDebugTransformer(filter_out); << 87 output->AddDebugTransformer(f); << 88 output->AddCoutTransformer(filter_out); 89 output->AddCoutTransformer(filter_out); 89 output->AddCoutTransformer(f); 90 output->AddCoutTransformer(f); 90 output->AddCerrTransformer(f); 91 output->AddCerrTransformer(f); 91 push_back(std::move(output)); << 92 push_back( std::move(output) ); 92 if(addmasterDestination) << 93 if ( addmasterDestination ) 93 { 94 { 94 AddMasterOutput(formatAlsoMaster); << 95 AddMasterOutput(formatAlsoMaster); 95 } 96 } 96 } 97 } 97 98 98 // ------------------------------------------- << 99 void G4MTcoutDestination::AddMasterOutput(G4bool formatAlsoMaster ) 99 void G4MTcoutDestination::AddMasterOutput(G4bo << 100 { 100 { 101 // Add a destination, that forwards the mess 101 // Add a destination, that forwards the message to the master thread 102 auto forwarder = G4coutDestinationUPtr(new G << 102 auto forwarder = G4coutDestinationUPtr( new G4MasterForwardcoutDestination ); 103 ref_masterOut = forwarder.get(); << 103 ref_masterOut = forwarder.get(); 104 const auto filter_out = [this](G4String&) -> << 104 const auto filter_out = [this](G4String&)->G4bool { 105 return !( << 105 if (this->ignoreCout || 106 this->ignoreCout || << 106 ( this->ignoreInit && 107 (this->ignoreInit && this->stateMgr->Get << 107 this->stateMgr->GetCurrentState() == G4State_Idle ) ) >> 108 { return false; } >> 109 return true; 108 }; 110 }; 109 forwarder->AddDebugTransformer(filter_out); << 110 forwarder->AddCoutTransformer(filter_out); 111 forwarder->AddCoutTransformer(filter_out); 111 if(formatAlsoMaster) << 112 if ( formatAlsoMaster ) 112 { 113 { 113 // Formatter: add prefix to each thread << 114 // Formatter: add prefix to each thread 114 const auto f = [this](G4String& msg) -> G4 << 115 const auto f = [this](G4String& msg)->G4bool { 115 std::ostringstream str; << 116 std::ostringstream str; 116 str << prefix; << 117 str<<prefix; 117 if(id != G4Threading::GENERICTHREAD_ID) << 118 if ( id!=G4Threading::GENERICTHREAD_ID ) str<<id; 118 { << 119 str<<" > "<<msg; 119 str << id; << 120 msg = str.str(); 120 } << 121 return true; 121 str << " > " << msg; << 122 }; 122 msg = str.str(); << 123 forwarder->AddCoutTransformer(f); 123 return true; << 124 forwarder->AddCerrTransformer(f); 124 }; << 125 forwarder->AddDebugTransformer(f); << 126 forwarder->AddCoutTransformer(f); << 127 forwarder->AddCerrTransformer(f); << 128 } 125 } 129 push_back(std::move(forwarder)); << 126 push_back( std::move(forwarder ) ); >> 127 130 } 128 } 131 129 132 // ------------------------------------------- << 133 G4MTcoutDestination::~G4MTcoutDestination() 130 G4MTcoutDestination::~G4MTcoutDestination() 134 { 131 { 135 if(useBuffer) << 132 if ( useBuffer ) DumpBuffer(); 136 { << 137 DumpBuffer(); << 138 } << 139 } 133 } 140 134 141 // ------------------------------------------- << 142 void G4MTcoutDestination::Reset() 135 void G4MTcoutDestination::Reset() 143 { 136 { 144 clear(); 137 clear(); 145 SetDefaultOutput(masterDestinationFlag, mast << 138 SetDefaultOutput(masterDestinationFlag,masterDestinationFmtFlag); 146 } 139 } 147 140 148 // ------------------------------------------- << 141 void G4MTcoutDestination::HandleFileCout(G4String fileN, G4bool ifAppend, 149 void G4MTcoutDestination::HandleFileCout(const << 150 G4boo 142 G4bool suppressDefault) 151 { 143 { 152 // Logic: we create a file destination. We w 144 // Logic: we create a file destination. We want this to get only the G4cout 153 // stream and should discard everything in G 145 // stream and should discard everything in G4cerr. 154 // First we create the destination with the 146 // First we create the destination with the appropriate open mode 155 147 156 std::ios_base::openmode mode = << 148 std::ios_base::openmode mode = (ifAppend ? std::ios_base::app 157 (ifAppend ? std::ios_base::app : std::ios_ << 149 : std::ios_base::trunc); 158 auto output = G4coutDestinationUPtr(new G4Fi << 150 auto output = G4coutDestinationUPtr( new G4FilecoutDestination(fileN,mode)); 159 << 151 160 // This reacts only to G4cout, so let's make << 152 // This reacts only to G4cout, so let's make a filter that removes everything 161 output->AddDebugTransformer([](G4String&) { << 153 // from G4cerr 162 output->AddCerrTransformer([](G4String&) { r << 154 output->AddCerrTransformer( [](G4String&) { return false;} ); 163 push_back(std::move(output)); 155 push_back(std::move(output)); 164 // Silence G4cout from default formatter 156 // Silence G4cout from default formatter 165 if(suppressDefault) << 157 if ( suppressDefault ) 166 { 158 { 167 ref_defaultOut->AddCoutTransformer([](G4St << 159 ref_defaultOut->AddCoutTransformer( [](G4String&) { return false; } ); 168 if(ref_masterOut != nullptr) << 160 if ( ref_masterOut ) 169 { << 161 ref_masterOut->AddCoutTransformer( [](G4String&) { return false; } ); 170 ref_masterOut->AddCoutTransformer([](G4S << 171 } << 172 } 162 } 173 } 163 } 174 164 175 // ------------------------------------------- << 165 void G4MTcoutDestination::HandleFileCerr(G4String fileN, G4bool ifAppend, 176 void G4MTcoutDestination::HandleFileCerr(const << 177 G4boo 166 G4bool suppressDefault) 178 { 167 { 179 // See HandleFileCout for explanation, switc 168 // See HandleFileCout for explanation, switching cout with cerr 180 169 181 std::ios_base::openmode mode = << 170 std::ios_base::openmode mode = (ifAppend ? std::ios_base::app 182 (ifAppend ? std::ios_base::app : std::ios_ << 171 : std::ios_base::trunc); 183 auto output = G4coutDestinationUPtr(new G4Fi << 172 auto output = G4coutDestinationUPtr( new G4FilecoutDestination(fileN,mode)); 184 output->AddDebugTransformer([](G4String&) { << 173 output->AddCoutTransformer( [](G4String&) { return false;} ); 185 output->AddCoutTransformer([](G4String&) { r << 186 push_back(std::move(output)); 174 push_back(std::move(output)); 187 if(suppressDefault) << 175 if ( suppressDefault ) 188 { 176 { 189 ref_defaultOut->AddCerrTransformer([](G4St << 177 ref_defaultOut->AddCerrTransformer( [](G4String&) { return false; } ); 190 if(ref_masterOut != nullptr) << 178 if ( ref_masterOut ) 191 { << 179 ref_masterOut->AddCerrTransformer( [](G4String&) { return false; } ); 192 ref_masterOut->AddCerrTransformer([](G4S << 193 } << 194 } 180 } 195 } 181 } 196 182 197 // ------------------------------------------- << 198 void G4MTcoutDestination::SetCoutFileName(cons 183 void G4MTcoutDestination::SetCoutFileName(const G4String& fileN, 199 G4bo << 184 G4bool ifAppend) 200 { 185 { 201 // First let's go back to the default 186 // First let's go back to the default 202 Reset(); 187 Reset(); 203 if(fileN != "**Screen**") << 188 if ( fileN != "**Screen**" ) 204 { 189 { 205 HandleFileCout(fileN, ifAppend, true); << 190 HandleFileCout(fileN,ifAppend,true); 206 } 191 } 207 } 192 } 208 193 209 // ------------------------------------------- << 210 void G4MTcoutDestination::EnableBuffering(G4bo 194 void G4MTcoutDestination::EnableBuffering(G4bool flag) 211 { 195 { 212 // I was using buffered output and now I wan 196 // I was using buffered output and now I want to turn it off, dump current 213 // buffer content and reset output 197 // buffer content and reset output 214 if(useBuffer && !flag) << 198 if ( useBuffer && !flag ) 215 { 199 { 216 DumpBuffer(); << 200 DumpBuffer(); 217 Reset(); << 201 Reset(); 218 } 202 } 219 else if(useBuffer && flag) << 203 else if ( useBuffer && flag ) { /* do nothing: already using */ } 220 { /* do nothing: already using */ << 204 else if ( !useBuffer && !flag ) { /* do nothing: not using */ } 221 } << 205 else if ( !useBuffer && flag ) 222 else if(!useBuffer && !flag) << 206 { 223 { /* do nothing: not using */ << 207 // Remove everything, in this case also removing the forward to the master 224 } << 208 // thread, we want everything to be dumpled to a file 225 else if(!useBuffer && flag) << 209 clear(); 226 { << 210 const size_t infiniteSize = 0; 227 // Remove everything, in this case also re << 211 push_back(G4coutDestinationUPtr(new G4BuffercoutDestination(infiniteSize))); 228 // thread, we want everything to be dumple << 229 clear(); << 230 const size_t infiniteSize = 0; << 231 push_back(G4coutDestinationUPtr(new G4Buff << 232 } << 233 else // Should never happen << 234 { << 235 assert(false); << 236 } 212 } >> 213 else { assert(false); } // Should never happen 237 useBuffer = flag; 214 useBuffer = flag; 238 } 215 } 239 216 240 // ------------------------------------------- << 241 void G4MTcoutDestination::AddCoutFileName(cons 217 void G4MTcoutDestination::AddCoutFileName(const G4String& fileN, 242 G4bo << 218 G4bool ifAppend) 243 { 219 { 244 // This is like the equivalent SetCoutFileNa 220 // This is like the equivalent SetCoutFileName, but in this case we do not 245 // remove or silence what is already exisiti 221 // remove or silence what is already exisiting 246 HandleFileCout(fileN, ifAppend, false); << 222 HandleFileCout(fileN,ifAppend,false); 247 } 223 } 248 224 249 // ------------------------------------------- << 250 void G4MTcoutDestination::SetCerrFileName(cons 225 void G4MTcoutDestination::SetCerrFileName(const G4String& fileN, 251 G4bo << 226 G4bool ifAppend) 252 { 227 { 253 // See SetCoutFileName for explanation 228 // See SetCoutFileName for explanation 254 Reset(); 229 Reset(); 255 if(fileN != "**Screen**") << 230 if ( fileN != "**Screen**") 256 { 231 { 257 HandleFileCerr(fileN, ifAppend, true); << 232 HandleFileCerr(fileN,ifAppend,true); 258 } 233 } 259 } 234 } 260 235 261 // ------------------------------------------- << 262 void G4MTcoutDestination::AddCerrFileName(cons 236 void G4MTcoutDestination::AddCerrFileName(const G4String& fileN, 263 G4bo << 237 G4bool ifAppend) 264 { 238 { 265 HandleFileCerr(fileN, ifAppend, false); << 239 HandleFileCerr(fileN,ifAppend,false); 266 } 240 } 267 241 268 // ------------------------------------------- << 269 void G4MTcoutDestination::SetIgnoreCout(G4int 242 void G4MTcoutDestination::SetIgnoreCout(G4int tid) 270 { 243 { 271 if(tid < 0) << 244 if (tid<0) { ignoreCout = false; } 272 { << 245 else { ignoreCout = (tid!=id); } 273 ignoreCout = false; << 274 } << 275 else << 276 { << 277 ignoreCout = (tid != id); << 278 } << 279 } 246 } 280 247 281 namespace 248 namespace 282 { 249 { 283 G4Mutex coutm = G4MUTEX_INITIALIZER; 250 G4Mutex coutm = G4MUTEX_INITIALIZER; 284 } 251 } 285 252 286 // ------------------------------------------- << 287 void G4MTcoutDestination::DumpBuffer() 253 void G4MTcoutDestination::DumpBuffer() 288 { 254 { 289 G4AutoLock l(&coutm); 255 G4AutoLock l(&coutm); 290 std::ostringstream msg; 256 std::ostringstream msg; 291 G4bool sep = false; << 292 << 293 sep = false; << 294 msg.str(""); << 295 msg.clear(); << 296 msg << "=======================\n"; << 297 msg << "debug buffer(s) for worker with ID:" << 298 G4coutDestination::ReceiveG4cout(msg.str()); << 299 std::for_each(begin(), end(), [this, &sep](G << 300 auto cout = dynamic_cast<G4BuffercoutDesti << 301 if(cout != nullptr) << 302 { << 303 cout->FlushG4debug(); << 304 if(sep) << 305 { << 306 G4coutDestination::ReceiveG4cout("==== << 307 } << 308 else << 309 { << 310 sep = true; << 311 } << 312 } << 313 }); << 314 << 315 sep = false; << 316 msg.str(""); << 317 msg.clear(); << 318 msg << "=======================\n"; 257 msg << "=======================\n"; 319 msg << "cout buffer(s) for worker with ID:" 258 msg << "cout buffer(s) for worker with ID:" << id << std::endl; 320 G4coutDestination::ReceiveG4cout(msg.str()); 259 G4coutDestination::ReceiveG4cout(msg.str()); 321 std::for_each(begin(), end(), [this, &sep](G << 260 G4bool sep = false; 322 auto cout = dynamic_cast<G4BuffercoutDesti << 261 std::for_each( begin() , end(), 323 if(cout != nullptr) << 262 [this,&sep](G4coutDestinationUPtr& el) { 324 { << 263 auto cout = dynamic_cast<G4BuffercoutDestination*>(el.get()); 325 cout->FlushG4cout(); << 264 if ( cout != nullptr ) { 326 if(sep) << 265 cout->FlushG4cout(); 327 { << 266 if ( sep ) { G4coutDestination::ReceiveG4cout("==========\n"); } 328 G4coutDestination::ReceiveG4cout("==== << 267 else { sep = true; } 329 } << 268 } 330 else << 269 } ); 331 { << 332 sep = true; << 333 } << 334 } << 335 }); << 336 << 337 sep = false; 270 sep = false; 338 msg.str(""); 271 msg.str(""); 339 msg.clear(); 272 msg.clear(); 340 msg << "=======================\n"; 273 msg << "=======================\n"; 341 msg << "cerr buffer(s) for worker with ID:" << 274 msg << "cerr buffer(s) for worker with ID:" << id 342 << std::endl; << 275 << " (goes to std error)" << std::endl; 343 G4coutDestination::ReceiveG4cout(msg.str()); 276 G4coutDestination::ReceiveG4cout(msg.str()); 344 std::for_each(begin(), end(), [this, &sep](G << 277 std::for_each( begin() , end(), 345 auto cout = dynamic_cast<G4BuffercoutDesti << 278 [this,&sep](G4coutDestinationUPtr& el) { 346 if(cout != nullptr) << 279 auto cout = dynamic_cast<G4BuffercoutDestination*>(el.get()); 347 { << 280 if ( cout != nullptr ) { 348 cout->FlushG4cerr(); << 281 cout->FlushG4cerr(); 349 if(sep) << 282 if (sep ) { G4coutDestination::ReceiveG4cout("==========\n"); } 350 { << 283 else { sep = true; } 351 G4coutDestination::ReceiveG4cout("==== << 284 } 352 } << 285 } ); 353 else << 354 { << 355 sep = true; << 356 } << 357 } << 358 }); << 359 << 360 G4coutDestination::ReceiveG4cout("========== 286 G4coutDestination::ReceiveG4cout("=======================\n"); 361 } 287 } 362 288