LBNFWormPlotter.cc
Go to the documentation of this file.
1 // Code that implements the "worm" plotter using G4 intersections and ROOT graphs.
2 // John Back, March 2016
3 
4 #include "LBNFWormPlotter.hh"
5 
6 #include "G4EventManager.hh"
7 
8 #include "G4UnitsTable.hh"
9 #include "G4VFigureFileMaker.hh"
10 
11 #include "G4GeometryManager.hh"
12 #include "G4SDManager.hh"
13 #include "G4StateManager.hh"
14 #include "G4Event.hh"
15 #include "G4TrajectoryContainer.hh"
16 
17 #include "G4VisAttributes.hh"
18 #include "G4UImanager.hh"
19 #include "G4TransportationManager.hh"
20 #include "G4RegionStore.hh"
21 #include "G4ProductionCutsTable.hh"
22 #include "G4VVisManager.hh"
23 
24 #include "G4ProcessManager.hh"
25 #include "G4ProcessVector.hh"
26 #include "G4Geantino.hh"
27 #include "G4RayShooter.hh"
28 
29 #include "G4UserLimits.hh"
30 
31 #include "LBNFWormPlotMessenger.hh"
32 #include "LBNETrajectory.hh"
33 #include "G4VTrajectoryPoint.hh"
34 
35 #include "TGraph.h"
36 #include "TAxis.h"
37 #include "TCanvas.h"
38 #include "TROOT.h"
39 #include "TStyle.h"
40 #include "TH2.h"
41 
43  xAxis(G4ThreeVector(0.0, 0.0, 1.0)), // along z
44  yAxis(G4ThreeVector(0.0, 1.0, 0.0)), // along y
45  zAxis(G4ThreeVector(-1.0, 0.0, 0.0)), // cross-product of x and y
46  xMin(-1.0*CLHEP::m),
47  xMax(1.0*CLHEP::m),
48  yMin(-1.0*CLHEP::m),
49  yMax(1.0*CLHEP::m),
50  z0(0.0*CLHEP::m),
51  gotBounds(false),
52  ABSq(0.0),
53  ADSq(0.0),
54  AB(G4ThreeVector(0.0, 0.0, 0.0)),
55  AD(G4ThreeVector(0.0, 0.0, 0.0)),
56  PointA(G4ThreeVector(0.0, 0.0, 0.0)),
57  xName(""),
58  yName(""),
59  theRayShooter(0),
60  theMessenger(0),
61  theEventManager(0)
62 {
63 
64  theRayShooter = new G4RayShooter();
66  theEventManager = G4EventManager::GetEventManager();
67 
68 }
69 
71 
72  delete theRayShooter;
73  delete theMessenger;
74 
75 }
76 
77 void LBNFWormPlotter::CreatePlot(const G4String& fileName) {
78 
79  zAxis = xAxis.cross(yAxis);
80 
81  G4cout<<"Creating worm plot: "<<fileName<<G4endl;
82  // Print plot dimension information
83  G4cout<<"xAxis unit vector = "<<xAxis<<G4endl;
84  G4cout<<"yAxis unit vector = "<<yAxis<<G4endl;
85  G4cout<<"zAxis unit vector = "<<zAxis<<G4endl;
86  G4cout<<"x limits = ("<<xMin/CLHEP::cm<<", "<<xMax/CLHEP::cm<<") cm"<<G4endl;
87  G4cout<<"y limits = ("<<yMin/CLHEP::cm<<", "<<yMax/CLHEP::cm<<") cm"<<G4endl;
88  G4cout<<"z0 position = "<<z0/CLHEP::cm<<" cm"<<G4endl;
89 
90  // Check if we have got the squared lengths of the plot axes
91  if (gotBounds == false) {
92 
93  AB = (xMax - xMin)*xAxis;
94  ABSq = AB.mag2();
95  AD = (yMax - yMin)*yAxis;
96  ADSq = AD.mag2();
97 
99 
100  gotBounds = true;
101 
102  //G4cout<<"*** ABSq = "<<ABSq<<", ADSq = "<<ADSq<<", PointA = "<<PointA<<G4endl;
103 
104  }
105 
106  // Use 1,000 lines per axis
107  G4int nX(1000), nY(1000);
108  G4double dx = (xMax - xMin)/(nX*1.0);
109  G4double dy = (yMax - yMin)/(nY*1.0);
110  G4cout<<"dx = "<<dx/CLHEP::cm<<", dy = "<<dy/CLHEP::cm<<" cm"<<G4endl;
111 
112  // Confirm process(es) of Geantino is initialized
113  G4VPhysicalVolume* pWorld = G4TransportationManager::GetTransportationManager()->
114  GetNavigatorForTracking()->GetWorldVolume();
115  G4RegionStore::GetInstance()->UpdateMaterialList(pWorld);
116 
117  G4ProductionCutsTable::GetProductionCutsTable()->UpdateCoupleTable(pWorld);
118 
119  G4ProcessVector* pVector = G4Geantino::GeantinoDefinition()->GetProcessManager()->GetProcessList();
120  for (G4int j=0; j < pVector->size(); ++j) {
121  (*pVector)[j]->BuildPhysicsTable(*(G4Geantino::GeantinoDefinition()));
122  }
123 
124  // Close geometry and set the application state
125  G4GeometryManager* geomManager = G4GeometryManager::GetInstance();
126  geomManager->OpenGeometry();
127  geomManager->CloseGeometry(1,0);
128 
129  G4ThreeVector center(0,0,0);
130  G4Navigator* navigator = G4TransportationManager::GetTransportationManager()->GetNavigatorForTracking();
131  navigator->LocateGlobalPointAndSetup(center,0,false);
132 
133  G4StateManager* theStateMan = G4StateManager::GetStateManager();
134  theStateMan->SetNewState(G4State_GeomClosed);
135 
136  TGraph* theGraph = new TGraph();
137  theGraph->SetMarkerStyle(21);
138  theGraph->SetMarkerSize(0.02);
139 
140  // Find intersections along a horizontal grid of lines, starting from the bottom and going up
141  G4ThreeVector x0 = xMin*xAxis + z0*zAxis;
142  for (G4int iy = 0; iy < nY; iy++) {
143 
144  // Starting position for the ray
145  G4ThreeVector yVect = (iy*dy + yMin)*yAxis;
146  G4ThreeVector rayStart = yVect + x0;
147  //G4cout<<"Start ray position = "<<rayStart<<G4endl;
148 
149  std::vector<G4ThreeVector> hIntersections = this->findIntersections(rayStart, xAxis);
150 
151  G4int nI = hIntersections.size();
152  //G4cout<<"List of "<<nI<<" horizontal intersections:"<<G4endl;
153 
154  for (G4int j = 0; j < nI; j++) {
155 
156  G4ThreeVector hP = hIntersections[j];
157 
158  //G4cout<<hP<<G4endl;
159 
160  // Store points in the graph
161  theGraph->SetPoint(theGraph->GetN(), hP.dot(xAxis)/CLHEP::cm, hP.dot(yAxis)/CLHEP::cm);
162 
163  }
164 
165  }
166 
167  // Find intersections along a vertical grid of lines
168  G4ThreeVector y0 = yMin*yAxis + z0*zAxis;
169  for (G4int ix = 0; ix < nX; ix++) {
170 
171  // Starting position for the ray
172  G4ThreeVector xVect = (ix*dx + xMin)*xAxis;
173  G4ThreeVector rayStart = xVect + y0;
174  //G4cout<<"Start ray position = "<<rayStart<<G4endl;
175 
176  std::vector<G4ThreeVector> vIntersections = this->findIntersections(rayStart, yAxis);
177 
178  G4int nI = vIntersections.size();
179  //G4cout<<"List of "<<nI<<" vertical intersections:"<<G4endl;
180  for (G4int j = 0; j < nI; j++) {
181 
182  G4ThreeVector vP = vIntersections[j];
183  //G4cout<<vP<<G4endl;
184 
185  // Store points in the graph
186  theGraph->SetPoint(theGraph->GetN(), vP.dot(xAxis)/CLHEP::cm, vP.dot(yAxis)/CLHEP::cm);
187 
188  }
189 
190  }
191 
192  TCanvas theCanvas("theCanvas", "", 900, 700);
193  gROOT->SetStyle("Plain");
194  gStyle->SetOptStat(0);
195  theCanvas.UseCurrentStyle();
196 
197  theCanvas.SetGrid();
198 
199  // Create a 2d histogram to specify the drawing axes, then overlay the graph
200  TH2D* theHist = new TH2D("axes", "", 2, xMin/CLHEP::cm, xMax/CLHEP::cm, 2, yMin/CLHEP::cm, yMax/CLHEP::cm);
201  theHist->SetDirectory(0);
202  TString xLabel(xName), yLabel(yName);
203  xLabel.ReplaceAll("\"", "");
204  yLabel.ReplaceAll("\"", "");
205  theHist->GetXaxis()->SetTitle(xLabel);
206  theHist->GetYaxis()->SetTitle(yLabel);
207  theHist->Draw();
208 
209  theGraph->Draw("psame");
210  theCanvas.Update();
211 
212  theCanvas.Print(fileName);
213 
214  delete theGraph;
215  delete theHist;
216 
217  // Restore state to idle
218  theStateMan->SetNewState(G4State_Idle);
219 
220 }
221 
222 std::vector<G4ThreeVector> LBNFWormPlotter::findIntersections(const G4ThreeVector& rayStart,
223  const G4ThreeVector& rayDirection) const {
224 
225  // Vector of intersection points
226  std::vector<G4ThreeVector> theIntersections;
227 
228  G4int iEvent(1);
229  G4Event* anEvent = new G4Event(iEvent);
230 
231  // Use geantino "ray" to find the intersections with the geometry along the given direction.
232  // This will find intersections that may extend beyond the "plot boundary", so only store
233  // the points we need
234  theRayShooter->Shoot(anEvent, rayStart, rayDirection.unit());
235  theEventManager->ProcessOneEvent(anEvent);
236 
237  // Fractional distance cut (|P1-P0|/|P0|) to find steps across boundaries
238  G4double fracCut(1e-6);
239 
240  G4TrajectoryContainer* trajectoryContainer = anEvent->GetTrajectoryContainer();
241  if (trajectoryContainer) {
242 
243  //G4int nTraj = trajectoryContainer->entries();
244  //G4cout<<"nTraj = "<<nTraj<<G4endl;
245 
246  LBNETrajectory* trajectory = dynamic_cast<LBNETrajectory*>( (*trajectoryContainer)[0] );
247 
248  if (trajectory) {
249 
250  G4int nPoints = trajectory->GetPointEntries();
251  //G4cout<<"Number of points along trajectory = "<<nPoints<<G4endl;
252 
253  G4int iP(0);
254  G4int pInt(-1);
255 
256  for (iP = 0; iP < nPoints; iP++) {
257 
258  G4VTrajectoryPoint* thePoint = trajectory->GetPoint(iP);
259 
260  //G4cout<<"Trajectory point "<<iP<<" pre-step volume is "<<trajectory->GetPreStepVolumeName(iP)<<G4endl;
261 
262  if (thePoint) {
263 
264  G4ThreeVector thePos = thePoint->GetPosition();
265  // First, check to see if the point is inside the "plot square". If not, ignore it.
266  G4bool inside = this->insidePlot(thePos);
267 
268  if (inside) {
269 
270  //G4cout<<"Inside? Yes"<<G4endl;
271  pInt++;
272  //G4cout<<"The point "<<pInt<<" = "<<thePos<<G4endl;
273 
274  // Usually we get two very nearby step points on either side of a volume region change.
275  // Check the previous "intersection" point and if its very close to the current point, average them
276  if (pInt == 0) {
277 
278  //G4cout<<"Adding first point to theIntersections"<<G4endl;
279 
280  theIntersections.push_back(thePos);
281 
282  } else {
283 
284  G4int pInt2 = pInt - 1;
285  G4ThreeVector prevPos = theIntersections[pInt2];
286  G4ThreeVector diffPos = thePos - prevPos;
287  G4double d1 = prevPos.mag();
288  G4double fracD(1.0);
289  if (d1 > 0.0) {fracD = diffPos.mag()/d1;}
290 
291  //G4cout<<"pInt2 = "<<pInt2<<"; prevPos = "<<prevPos<<"; fracD = "<<fracD<<G4endl;
292 
293  if (fracD < fracCut) {
294 
295  // The current point is very close to the previous one. Average them
296  // and update the previous point stored in the vector
297  G4ThreeVector meanPos = 0.5*(prevPos + thePos);
298  //G4cout<<"Point - currentPoint fracD = "<<fracD<<"; average = "<<meanPos<<G4endl;
299  //G4cout<<"Intersection "<<pInt2<<" = "<<theIntersections[pInt2]<<G4endl;
300  G4ThreeVector& vectPos = theIntersections[pInt2];
301  vectPos.setX(meanPos.x());
302  vectPos.setY(meanPos.y());
303  vectPos.setZ(meanPos.z());
304  //G4cout<<"New Intersection "<<pInt2<<" = "<<theIntersections[pInt2]<<G4endl;
305 
306  // Decrement pInt, since we have merged the two points
307  pInt--;
308 
309  } else {
310 
311  // The current point is not close to the previous one. Add it to the vector
312  //G4cout<<"Adding "<<thePos<<G4endl;
313  theIntersections.push_back(thePos);
314 
315  } // d1 > 0.0
316 
317  } // Start comparison with previous point
318 
319  } // inside
320 
321  } // thePoint
322 
323  } // iP loop
324 
325  } // trajectory
326 
327  } // trajectoryContainer
328 
329  delete anEvent;
330 
331  return theIntersections;
332 
333 }
334 
335 G4bool LBNFWormPlotter::insidePlot(const G4ThreeVector& thePoint) const {
336 
337  G4bool inside(false);
338 
339  G4ThreeVector AP = thePoint - PointA;
340  G4double prod1 = AP.dot(AB);
341 
342  //G4cout<<"prod1 = "<<prod1<<"; ABSq = "<<ABSq<<G4endl;
343 
344  if (prod1 > 0.0 && prod1 < ABSq) {
345 
346  G4double prod2 = AP.dot(AD);
347 
348  //G4cout<<"prod2 = "<<prod2<<"; ADSq = "<<ADSq<<G4endl;
349 
350  if (prod2 > 0.0 && prod2 < ADSq) {
351 
352  inside = true;
353 
354  //G4cout<<"Point "<<thePoint<<" is inside the plot boundary"<<G4endl;
355 
356  }
357 
358  }
359 
360  //G4cout<<"insidePlot:: inside = "<<(G4int)inside<<G4endl;
361 
362  return inside;
363 
364 }
G4ThreeVector yAxis
void CreatePlot(const G4String &fileName)
virtual ~LBNFWormPlotter()
G4ThreeVector PointA
G4EventManager * theEventManager
G4ThreeVector zAxis
G4ThreeVector xAxis
virtual G4VTrajectoryPoint * GetPoint(G4int i) const
G4ThreeVector AB
G4bool insidePlot(const G4ThreeVector &thePoint) const
std::vector< G4ThreeVector > findIntersections(const G4ThreeVector &rayPosition, const G4ThreeVector &rayDirection) const
static LBNFWormPlotMessenger * GetInstance(LBNFWormPlotter *wPlot)
G4RayShooter * theRayShooter
virtual int GetPointEntries() const
G4ThreeVector AD
LBNFWormPlotMessenger * theMessenger