ECCE @ EIC Software
 All Classes Namespaces Files Functions Variables Typedefs Enumerations Enumerator Friends Macros Groups Pages
G4WorkerThread.cc
Go to the documentation of this file. Or view the newest version in sPHENIX GitHub for file G4WorkerThread.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 #include "G4WorkerThread.hh"
27 #include "G4WorkerRunManager.hh"
28 #include "G4MTRunManager.hh"
29 
30 #include "G4GeometryWorkspace.hh"
31 #include "G4SolidsWorkspace.hh"
32 #include "G4ParticlesWorkspace.hh"
34 
35 #include "G4Region.hh"
36 #include "G4RegionStore.hh"
37 #include "G4LogicalVolume.hh"
38 #include "G4Region.hh"
39 #include "G4PhysicalVolumeStore.hh"
40 #include "G4LogicalVolumeStore.hh"
41 
43 {
44  threadId = tid;
45 }
46 
48 {
49  return threadId;
50 }
51 
53 {
54  numThreads = nw;
55 }
56 
58 {
59  return numThreads;
60 }
61 
63 {
64  // Initialise all split classes
65  // with copy of data from master thread
66 
71 }
72 
74 {
75  // Clear all split classes
76 
81 }
82 
84 {
85  // =================================================
86  // Step-0: keep sensitive detector and field manager
87  // =================================================
88  // First remember SD and Filed Associated with worker
89  // in order to re-use it
90  // (note that all the stuff after this will reset SD and Field)
91  typedef std::map<G4LogicalVolume*,
92  std::pair<G4VSensitiveDetector*,G4FieldManager*> > LV2SDFM;
93  LV2SDFM lvmap;
94 
95  typedef std::map<G4Region*,
96  std::pair<G4FastSimulationManager*,G4UserSteppingAction*> > R2FSM;
97  R2FSM rgnmap;
98 
100  for(size_t ip=0; ip<mLogVolStore->size(); ip++)
101  {
102  G4LogicalVolume *lv = (*mLogVolStore)[ip];
103 
104  // The following needs an explanation.
105  // Consider the case in which the user adds one LogVolume between
106  // the runs. The problem is that the thread-local part (split class)
107  // of the G4LogicalVolume object is not initialized for workers
108  // because the initialization is done once when the thread starts
109  // (see G4MTRunManagerKernel::StartThread Step-2 that calls
110  // G4WorkerThread::BuildGeometryAndPhysicsVector in this class).
111  // The problem is that pointers of SD and FM for these newly added LV
112  // may be invalid pointers (because never initialized, we have seen
113  // this behavior in our testing). If now we remember them and re-use
114  // them in Step-4 below we set invalid pointers to LV for this thread.
115  // Thus we need a way to know if for a given LV we need to remember
116  // or not the SD and FM pointers.
117  // To solve this problem: We assume that the ConstructSDandField() is
118  // called also by Master thread, thus for newly added LV the shadow
119  // pointers of SD and Fields are correct.
120  // (LIMITATION: this assumption may be too stringent, a user to save
121  // memory could instantiate SD only for workers, but we require this
122  // not to happen!).
123  // Thus if a SD and FieldMgr are needed for this particular LV, and
124  // shadow are !=0 it means that user wants an SD and FM to be
125  // associated with LV, we get the values and we remember them.
126  //
127  G4VSensitiveDetector* sd = 0;
128  G4FieldManager* fmgr = 0;
129  if ( lv->GetMasterSensitiveDetector() != 0 )
130  {
131  sd = lv->GetSensitiveDetector();
132  }
133  if ( lv->GetMasterFieldManager() != 0 )
134  {
135  fmgr = lv->GetFieldManager();
136  }
137  if ( sd || fmgr )
138  {
139  lvmap[lv] = std::make_pair(sd,fmgr);
140  }
141  }
143  for(size_t ir=0; ir<mRegStore->size(); ir++)
144  {
145  G4Region* reg = (*mRegStore)[ir];
148  if ( reg || usa )
149  {
150  rgnmap[reg] = std::make_pair(fsm,usa);
151  }
152  }
153 
154  //===========================
155  // Step-1: Clean the workspace
156  //===========================
157  G4GeometryWorkspace* geomWorkspace =
159  geomWorkspace->DestroyWorkspace();
160  G4SolidsWorkspace* solidWorkspace =
162  solidWorkspace->DestroyWorkspace();
163 
164  //===========================
165  // Step-2: Re-create and initialize workspace
166  //===========================
167  geomWorkspace->InitialiseWorkspace();
168  solidWorkspace->InitialiseWorkspace();
169 
170  //===================================================
171  // Step-4: Restore sensitive detector and field manaer
172  //===================================================
173  for ( LV2SDFM::const_iterator it = lvmap.begin() ;
174  it != lvmap.end() ; ++it )
175  {
176  G4LogicalVolume* lv = it->first;
177  G4VSensitiveDetector* sd = (it->second).first;
178  G4FieldManager* fmgr = (it->second).second;
179  if (fmgr) // What should be the second parameter?
180  { // We use always false for MT mode
181  lv->SetFieldManager(fmgr, false);
182  }
183  if (sd)
184  {
185  lv->SetSensitiveDetector(sd);
186  }
187  }
188  for ( R2FSM::const_iterator it3 = rgnmap.begin() ;
189  it3 != rgnmap.end() ; it3++ )
190  {
191  G4Region* reg = it3->first;
192  G4FastSimulationManager* fsm = (it3->second).first;
193  if(fsm) reg->SetFastSimulationManager(fsm);
194  G4UserSteppingAction* usa = (it3->second).second;
195  if(usa) reg->SetRegionalSteppingAction(usa);
196  }
197 }
198 
200 {
201  if ( affinity == 0 ) return;
202 
203 #if !defined(WIN32)
204  G4cout << "AFFINITY SET" << G4endl;
205  // Assign this thread to cpus in a round robin way
206  G4int offset = affinity;
207  G4int cpuindex = 0;
209  {
210  G4Exception("G4WorkerThread::SetPinAffinity()","Run0100", JustWarning,
211  "Cannot set thread affinity, affinity parameter larger than number of cores");
212  return;
213  }
214  if (offset>0) // Start assigning affinity to given CPU
215  {
216  --offset;
218  // Round robin
219  }
220  else // Exclude the given CPU
221  {
222  offset *= -1;
223  --offset;
225  cpuindex = myidx + (myidx>=offset);
226  }
227  G4cout << "Setting affinity to:" << cpuindex << G4endl;
228 
229 #if defined(G4MULTITHREADED)
230  // Avoid compilation warning in C90 standard w/o MT
231  G4NativeThread t = pthread_self();
232 #else
234 #endif
235  G4bool success = G4Threading::G4SetPinAffinity(cpuindex,t);
236  if ( ! success )
237  {
238  G4Exception("G4MTRunManagerKernel::StarThread()", "Run0101",
239  JustWarning, "Cannot set thread affinity.");
240  }
241 #endif
242 }