LBNEMagneticField.cc
Go to the documentation of this file.
1 //----------------------------------------------------------------------
2 //LBNEMagneticField
3 // $Id
4 //----------------------------------------------------------------------
5 
6 #include "LBNEMagneticField.hh"
7 
8 #include "G4VPhysicalVolume.hh"
9 #include "G4ios.hh"
10 #include "G4TransportationManager.hh"
11 #include "LBNEVolumePlacements.hh"
12 #include "LBNESurveyor.hh"
13 #include "Randomize.hh"
14 #include "LBNERunManager.hh"
15 
16 //magnetic field between conductors ====================================================
17 
19 amHorn1(isOne),
20 fHornCurrent(0.),
21 fCoordinateSet(false),
22 fShift(2, 0.),
23 fShiftSlope(2,0.),
24 fZShiftDrawingCoordinate(-1.0e13),
25 fZShiftUpstrWorldToLocal(-1.0e13),
26 fEffectiveLength(0.),
27 fHornNeckOuterRadius(-1.0e13),
28 fHornNeckInnerRadius(-1.0e13),
29 fOuterRadius(1.0e9),
30 fOuterRadiusEff(1.0e9),
31 fSkinDepth(4.1*CLHEP::mm),
32 fSkinDepthInnerRad(1.0e10*CLHEP::mm) // Unrealistic high, because that was the default sometime ago.
33 
34 {
35  //
36  // We rely on the Volume Placement utility and the surveyor data to compute the coordinate transfers.
37  // Two distinct ones:
38  //
39  // (i) Going from G4 World to the local coordinate system. This is done in two steps: first a Z shift, fixed.
40  // Key variable: fZShiftUpstrWorldToLocal
41  // second, a linearized rotation due misalignement, in both X and Y.
42  //
43  // (ii) A Z translation to go from G4 World the 8875.112 MD 363xxx drawing coordinate system, such that
44  // we can used the exact parabolic equations (Outer radius one)
45  // fZShiftDrawingCoordinate
46  //
47  // This strategy has the drawback of the danger of making mistakes in the code below, but has
48  // has the advantage of less coordinate transforms. (inverse one done in the G4 Propagation. )
49  // It is assumed here that the misalignment are small, i.e., cos^2(tilt) ~ 0.
50 //
51 // Having the field manager assigned to the top level of the Horn volume instead of just
52 // the conductor polycones volumes, and the volume in between the two conductors,
53 // allows us to add fringe fields if need be, and avoid creating the volumes in between
54 // the conductors..
55 //
56  const LBNEVolumePlacements *aPlacementHandler = LBNEVolumePlacements::Instance();
57 // Radial equation interface. Take the outer equations..
58 
59  fEqnIndicesInner.clear();
60  fEqnIndicesOuter.clear();
61  fZDCBegin.clear();
62  fZDCEnd.clear();
63  fUseHorn1Polycone = false;
64  if(amHorn1) { // Use the Placement data to get the relevant Z coordinate to compute the distance to the inner or outer conductor.
65  const LBNEVolumePlacementData* plDatH1 = aPlacementHandler->Find("Bfield",
66  "Horn1PolyM1", "LBNEMagneticField::LBNEMagneticField");
68  const double zCDNeckStart = aPlacementHandler->GetHorn1NeckZPosition() - aPlacementHandler->GetHorn1NeckLength()/2.;
69  const double zCDNeckEnd = aPlacementHandler->GetHorn1NeckZPosition() + aPlacementHandler->GetHorn1NeckLength()/2.;
70  const double zCDFirstRing = 0.544*zCDNeckStart; // transition from drawing equation 1 to 2 .
71  // Drawing 8875.112-MD 363104
72 // std::cerr << " Horn1 Magnetized region, check, zCDNeckStart " << zCDNeckStart
73 // << " zCDNeckEnd " << zCDNeckEnd << std::endl;
74  //
75  // No Split geometry, August September 2014. Needs Checking..!!!.....
76  //
77  fZDCBegin.push_back(0.); fZDCEnd.push_back(zCDFirstRing);
78  fEqnIndicesInner.push_back(0); fEqnIndicesOuter.push_back(5);
79  fZDCBegin.push_back(zCDFirstRing); fZDCEnd.push_back(zCDNeckStart);
80  fEqnIndicesInner.push_back(1); fEqnIndicesOuter.push_back(5);
81  fZDCBegin.push_back(zCDNeckStart); fZDCEnd.push_back(zCDNeckEnd);
82  fEqnIndicesInner.push_back(99); fEqnIndicesOuter.push_back(99); // No equations, use the radius
83  fHornNeckOuterRadius = aPlacementHandler->GetHorn1NeckOuterRadius();
84  fHornNeckInnerRadius = aPlacementHandler->GetHorn1NeckInnerRadius();
85  const double zEndNR = aPlacementHandler->GetHorn1ZDEndNeckRegion();
86  fZDCBegin.push_back(zCDNeckEnd); fZDCEnd.push_back(zEndNR);
87  fEqnIndicesInner.push_back(3); fEqnIndicesOuter.push_back(7);
88  const double zEnd = aPlacementHandler->GetHorn1ZEndIC();
89  fZDCBegin.push_back(zEndNR); fZDCEnd.push_back(zEnd);
90  fEqnIndicesInner.push_back(4); fEqnIndicesOuter.push_back(7);
91  fEffectiveLength = aPlacementHandler->GetHorn1EffectiveLength();
92  fOuterRadius = aPlacementHandler->GetHorn1OuterTubeOuterRad();
93  fZShiftUpstrWorldToLocal = 0.; // by new definition (beginning of Oct. 2013 ) of the geometry.
94  fZShiftDrawingCoordinate = 30.0*CLHEP::mm*aPlacementHandler->GetHorn1LongRescale(); // Drawing 8875.112-MD-363097
95  if (aPlacementHandler->GetUseHorn1Polycone() || (aPlacementHandler->GetNumberOfHornsPolycone() > 0)) {
96  fUseHorn1Polycone = true;
97  fZShiftDrawingCoordinate = 0.; // Check with Geantino here...
98  fZDCBegin.clear();
99  fRadsInnerC.clear();
100  fRadsOuterC.clear();
101 // std::cerr << " Check coordinates of inner radius of Horn1 Polycone inner conductor... fOuterRadius " << fOuterRadius << std::endl;
102  if (aPlacementHandler->IsHornPnParabolic(1)) {
103  size_t nPts = aPlacementHandler->GetHornParabolicNumInnerPts(0);
104  const double epsil = 0.050*CLHEP::mm; // from LBNEVolumePlacements::UpdateParamsForHornMotherPolyNum
105  for (size_t k=0; k != nPts; k++) {
106  fZDCBegin.push_back(aPlacementHandler->GetHornParabolicRZCoord(0, k) + fZShiftDrawingCoordinate + epsil);
107  const double rIn = aPlacementHandler->GetHornParabolicRIn(0, k) - epsil;
108  fRadsInnerC.push_back(rIn);
109  const double rOut = rIn + aPlacementHandler->GetHornParabolicThick(0, k);
110  fRadsOuterC.push_back(rOut);
111  }
112  } else {
113  for (size_t k=0; k!= static_cast<size_t>(aPlacementHandler->GetUseHorn1PolyNumInnerPts()); k++) {
114  fZDCBegin.push_back(aPlacementHandler->GetHorn1PolyInnerConductorZCoord(k) + fZShiftDrawingCoordinate);
115  const double rIn = aPlacementHandler->GetHorn1PolyInnerConductorRadius(k);
116  fRadsInnerC.push_back(rIn);
117  const double rOut = rIn + aPlacementHandler->GetHorn1PolyInnerConductorThickness(k);
118  fRadsOuterC.push_back(rOut);
119 // std::cerr << " k " << k << " z " << fZDCBegin[fZDCBegin.size()-1] << " InnerC " << rIn << " out " << rOut << std::endl;
120  }
121 // std::cerr << " Horn 1 magentic field decalred.. And quit for now.. I say so.. " << std::endl; exit(2);
122  }
123  } // Polycone, Parabolic style...or straight...
124  } else {
125  const LBNEVolumePlacementData* plDatH2 = aPlacementHandler->Find("Bfield",
126  "Horn2TopLevel", "LBNEMagneticField::LBNEMagneticField");
127 // std::cerr << " Number of equation changes " << aPlacementHandler->GetHorn2ZEqnChangeNumEqn() << std::endl;
128 // for (size_t k=0; k != aPlacementHandler->GetHorn2ZEqnChangeNumEqn(); k++) {
129 // std::cerr << " Horn2 zone " << k << " at z "
130 // << aPlacementHandler->GetHorn2ZEqnChange(k)/25.4 << std::endl;
131 // }
132  fEffectiveLength = plDatH2->fParams[2];
133  const double z1 = aPlacementHandler->GetHorn2ZEqnChange(0);
134  fZDCBegin.push_back(0.); fZDCEnd.push_back(z1);
135  fEqnIndicesInner.push_back(6); fEqnIndicesOuter.push_back(10); //IO trasnsition, Part 1
136 
137  const double z2 = aPlacementHandler->GetHorn2ZEqnChange(1);
138  fZDCBegin.push_back(z1); fZDCEnd.push_back(z2);
139  fEqnIndicesInner.push_back(6); fEqnIndicesOuter.push_back(0); // Getting to the neck region
140 
141  const double z3 = aPlacementHandler->GetHorn2ZEqnChange(2);
142  fZDCBegin.push_back(z2); fZDCEnd.push_back(z3);
143  fEqnIndicesInner.push_back(6); fEqnIndicesOuter.push_back(0); // Getting to the neck, neck region
144 
145  const double z4 = aPlacementHandler->GetHorn2ZEqnChange(3);
146  fZDCBegin.push_back(z3); fZDCEnd.push_back(z4);
147  fEqnIndicesInner.push_back(6); fEqnIndicesOuter.push_back(1); // Just before the neck
148 
149  const double z5 = aPlacementHandler->GetHorn2ZEqnChange(4);
150  fZDCBegin.push_back(z4); fZDCEnd.push_back(z5);
151  fEqnIndicesInner.push_back(99); fEqnIndicesOuter.push_back(99); //The neck, fixe radius
152  fHornNeckOuterRadius = aPlacementHandler->GetHorn2NeckOuterRadius();
153  fHornNeckInnerRadius = aPlacementHandler->GetHorn2NeckInnerRadius();
154 
155  const double z6 = aPlacementHandler->GetHorn2ZEqnChange(5);
156  fZDCBegin.push_back(z5); fZDCEnd.push_back(z6);
157  fEqnIndicesInner.push_back(7); fEqnIndicesOuter.push_back(2); // Just after the neck
158 
159  const double z7 = aPlacementHandler->GetHorn2ZEqnChange(6);
160  fZDCBegin.push_back(z6); fZDCEnd.push_back(z7);
161  fEqnIndicesInner.push_back(7); fEqnIndicesOuter.push_back(3); // moving along positive Z, neck region
162 
163  const double z8 = aPlacementHandler->GetHorn2ZEqnChange(7); // Next physical section
164  fZDCBegin.push_back(z7); fZDCEnd.push_back(z8);
165  fEqnIndicesInner.push_back(7); fEqnIndicesOuter.push_back(3);
166 
167  const double z9 = aPlacementHandler->GetHorn2ZEqnChange(8); //
168  fZDCBegin.push_back(z8); fZDCEnd.push_back(z9);
169  fEqnIndicesInner.push_back(8); fEqnIndicesOuter.push_back(4);
170 
171  const double z10 = aPlacementHandler->GetHorn2ZEqnChange(9);
172  fZDCBegin.push_back(z9); fZDCEnd.push_back(z10);
173  fEqnIndicesInner.push_back(9); fEqnIndicesOuter.push_back(5);
174 
175  fOuterRadius = aPlacementHandler->GetHorn2OuterTubeOuterRad();
176  fZShiftUpstrWorldToLocal = aPlacementHandler->GetHorn2LongPosition() +
177  aPlacementHandler->GetHorn2LongRescale()*
178  aPlacementHandler->GetHorn2DeltaZEntranceToZOrigin(); // by new definition (beginning of Oct. 2013 ) of the geometry.
179  fZShiftDrawingCoordinate = -1.0*aPlacementHandler->GetHorn2LongRescale()*
180  aPlacementHandler->GetHorn2DeltaZEntranceToZOrigin();
181  const LBNEVolumePlacementData* plDatH2b = aPlacementHandler->Find("Bfield",
182  "Horn2Hall", "LBNEMagneticField::LBNEMagneticField");
184  }
185  std::cerr << " Magnetic field coordinate definition done. fZShiftUpstrWorldToLocal " <<
186  fZShiftUpstrWorldToLocal << " fZShiftDrawingCoordinate " << fZShiftDrawingCoordinate << std::endl;
187 // fCoordinateSet = true; obsolete. Except for use of dumping the field...
188  fOuterRadiusEff = fOuterRadius - 2.0*fSkinDepth; // skin depth at 0.43 kHz
189  // Z coordinate change not yet initialize, done at the first track.
190 /*
191  std::cerr << " Table of Z position and equations for ";
192  if (amHorn1) std::cerr << " Horn1 " ;
193  else std::cerr << " Horn2 " ;
194  std::cerr << std::endl << " Z-Start Z-End Innner Eqn Outer Eqn rIC thick" << std::endl;
195  for(size_t k=0; k!= fZDCBegin.size(); k++) {
196  std::cerr << " " << fZDCBegin[k] << " " << fZDCEnd[k]
197  << " " << fEqnIndicesInner[k] << " " << fEqnIndicesOuter[k];
198  const double zMid = 0.5 *( fZDCBegin[k] + fZDCEnd[k]);
199  double rOut = fHornNeckOuterRadius;
200  double rIn = fHornNeckInnerRadius;
201  if (fEqnIndicesInner[k] != 99) {
202  rOut = (amHorn1) ? aPlacementHandler->GetConductorRadiusHorn1(zMid, fEqnIndicesOuter[k]) :
203  aPlacementHandler->GetConductorRadiusHorn2(zMid, fEqnIndicesOuter[k]);
204  rIn = (amHorn1) ? aPlacementHandler->GetConductorRadiusHorn1(zMid, fEqnIndicesInner[k]) :
205  aPlacementHandler->GetConductorRadiusHorn2(zMid, fEqnIndicesInner[k]);
206  }
207  std::cerr << " " << rIn << " " << rOut - rIn << std::endl;
208  }
209 */
210 //
211 // Use now the survey data (simulated for now.. ) to establish the coordinate transform..
212 //
213  LBNESurveyor *theSurvey= LBNESurveyor::Instance();
214  std::string hornIndexStr = (amHorn1) ? std::string("1") : std::string("2");
215  std::string upstrStr("Upstream");std::string downstrStr("Downstream");
216  std::string leftStr("Left"); std::string rightStr("Right");
217  std::string ballStr("BallHorn");
219  theSurvey->GetPoint(G4String(upstrStr + leftStr + ballStr + hornIndexStr));
221  theSurvey->GetPoint(G4String(upstrStr + rightStr + ballStr + hornIndexStr));
223  theSurvey->GetPoint(G4String(downstrStr + leftStr + ballStr + hornIndexStr));
225  theSurvey->GetPoint(G4String(downstrStr + rightStr + ballStr + hornIndexStr));
226  const G4ThreeVector pUpLeft = itUpLeft->GetPosition();
227  const G4ThreeVector pUpRight = itUpRight->GetPosition();
228  const G4ThreeVector pDwLeft = itDwLeft->GetPosition();
229  const G4ThreeVector pDwRight = itDwRight->GetPosition();
230  fHornIsMisaligned = false;
231  for (size_t k=0; k!=2; k++) {
232  fShift[k] = -0.50*(pUpLeft[k] + pUpRight[k]); // minus sign comes from the global to local.
233  // Transverse shoft at the upstream entrance of Horn1
234  fShiftSlope[k] = 0.5*(pUpLeft[k] + pUpRight[k] - pDwLeft[k] - pDwRight[k])/fEffectiveLength;
235  if (std::abs(fShiftSlope[k]) > 1.0e-8) fHornIsMisaligned = true;
236  }
237  if (fHornIsMisaligned) {
238  if (amHorn1) std::cerr << " Horn1 ";
239  else std::cerr << " Horn2 ";
240  std::cerr << " is misaligned "
241  << " xz term " << fRotMatrixHornContainer[0][2] << " yz " << fRotMatrixHornContainer[1][2] << std::endl;
242  }
243 /*
244  if (!amHorn1) {
245  std::cerr << " fShift X " << fShift[0] << " Y " << fShift[1] << std::endl;
246  std::cerr << " fShiftSlope X " << fShiftSlope[0] << " Y " << fShiftSlope[1] << std::endl;
247  std::cerr << " UpLeft X " << pUpLeft[0] << " Y " << pUpLeft[1] << std::endl;
248  std::cerr << " UpRight X " << pUpRight[0] << " Y " << pUpRight[1] << std::endl;
249  std::cerr << " DwLeft X " << pDwLeft[0] << " Y " << pDwLeft[1] << std::endl;
250  std::cerr << " DwRight X " << pDwRight[0] << " Y " << pDwRight[1] << " eff L " << fEffectiveLength << std::endl;
251  exit(2);
252  }
253 */
254 //
255 // Open a file to study the value of the field for displaced trajectory...
256 //
257 // if (!fOutTraj.is_open()) {
258 // G4String fNameStr("./FieldTrajectories_Horn");
259 // if (amHorn1) fNameStr += G4String("1_1.txt");
260 // else fNameStr += G4String("2_1.txt");
261 // fOutTraj.open(fNameStr.c_str()); // we will place a GUI interface at a later stage...
262 // fOutTraj << " id x y z bx by " << std::endl;
263 // }
264 }
265 
266 void LBNEMagneticFieldHorn::GetFieldValue(const double Point[3],double *Bfield) const
267 {
268 
269 
270  G4double current = fHornCurrent/CLHEP::ampere/1000.;
271 // std::cerr << " LBNEMagneticFieldHorn::GetFieldValue Z " << Point[2] << " current " << current << std::endl;
272  for (size_t k=0; k!=3; ++k) Bfield[k] = 0.;
273  // Intialization of the coordinate transform.
274  const LBNEVolumePlacements *aPlacementHandler = LBNEVolumePlacements::Instance();
275  /* Obsolete...
276  if (!fCoordinateSet) {
277 
278  G4Navigator* numinavigator=new G4Navigator(); //geometry navigator
279  G4Navigator* theNavigator=G4TransportationManager::GetTransportationManager()->GetNavigatorForTracking();
280  numinavigator->SetWorldVolume(theNavigator->GetWorldVolume());
281  G4ThreeVector Position=G4ThreeVector(Point[0],Point[1],Point[2]);
282  G4VPhysicalVolume* myVolume = numinavigator->LocateGlobalPointAndSetup(Position);
283  G4TouchableHistoryHandle aTouchable = numinavigator->CreateTouchableHistoryHandle();
284  G4ThreeVector localPosition = aTouchable->GetHistory()->GetTopTransform().TransformPoint(Position);
285  delete numinavigator;
286  G4String vName = myVolume->GetLogicalVolume()->GetName();
287  if (amHorn1 ) {
288  if (vName != G4String("Horn1Hall") || (localPosition[2] > 0.)) return; // not there yet.., or getting by the back side.
289  fZShiftUpstrWorldToLocal = Point[2]; // to correct for the misalignment, via the first coordinate transform
290  // Note: because the logival Horn1 container volume is split into to of them,
291  // the offset for the field might a bit different than for the actual volume. This is a small correction.
292  // What matter most the field is the tilt, which is correct.
293  fZShiftDrawingCoordinate = Point[2] - aPlacementHandler->GetHorn1DeltaZEntranceToZOrigin(); // Check the sign !
294  } else {
295  if (vName != G4String("Horn2TopLevel") || (localPosition[2] > 0.)) return;
296  fZShiftUpstrWorldToLocal = Point[2]; // to correct for the misalignment, via the first coordinate transform
297  fZShiftDrawingCoordinate = Point[2] - aPlacementHandler->GetHorn2DeltaZEntranceToZOrigin();
298  }
299  fCoordinateSet = true;
300  this->dumpField();
301  std::cerr << " Coordinate transform, Z shifts at Z World " << Point[2] << " in " << vName << std::endl;
302 // if (!amHorn1) { std::cerr << " And quit !!!! " << std::endl; exit(2); }
303  } // Initialization of Z coordinate transform
304  if (!fCoordinateSet) return;
305  */
306  std::vector<double> ptTrans(2,0.);
307  const double zLocal = Point[2] - fZShiftUpstrWorldToLocal; // from the start of the relevant volume
308  for (size_t k=0; k != 2; k++)
309  ptTrans[k] = Point[k] + fShift[k] + zLocal*fShiftSlope[k];
310  const double r = std::sqrt(ptTrans[0]*ptTrans[0] + ptTrans[1]*ptTrans[1]);
311  if (r > fOuterRadius) return;
312  if ( r < 1.0e-3) return; // The field should go smoothly to zero at the center of the horm
313 
314  double magBField = current / (5.*r/CLHEP::cm)/10*CLHEP::tesla; //B(kG)=i(kA)/[5*r(cm)], 1T=10kG
315  double radIC = fHornNeckInnerRadius;
316  double radOC = fHornNeckOuterRadius;
317  if ( r > fOuterRadiusEff) {
318  const double dr = r - fOuterRadiusEff;
319  const double attLength = std::exp(-dr/fSkinDepth);
320  magBField *= attLength;
321  } else {
322  if (fUseHorn1Polycone) { // Custom Horn1, based on polygons
323  this->fillHorn1PolygonRadii(zLocal, &radIC, &radOC);
324  if (std::abs(radIC) > 1.0e6) return;
325  } else { // Numi style Horn1 (or Horn2)
326  size_t kSelZ = fEqnIndicesInner.size();
327  const double zLocD = zLocal - fZShiftDrawingCoordinate;
328  for (size_t k=0; k != fEqnIndicesInner.size(); ++k) {
329  if (zLocD < fZDCBegin[k]) break;
330  if (zLocD > fZDCEnd[k]) continue; // They are Z ordered..
331  kSelZ = k;
332  break;
333  }
334  if (kSelZ == fEqnIndicesInner.size()) return;
335  if (fEqnIndicesInner[kSelZ] != 99) {
336  radIC = (amHorn1) ? aPlacementHandler->GetConductorRadiusHorn1(zLocD,fEqnIndicesInner[kSelZ] ) :
337  aPlacementHandler->GetConductorRadiusHorn2(zLocD, fEqnIndicesInner[kSelZ]);
338  radOC = (amHorn1) ? aPlacementHandler->GetConductorRadiusHorn1(zLocD,fEqnIndicesOuter[kSelZ] ) :
339  aPlacementHandler->GetConductorRadiusHorn2(zLocD, fEqnIndicesOuter[kSelZ]);
340  }
341  if (amHorn1 && aPlacementHandler->IsHorn1RadiusBigEnough()) { // Obsolete.. (Aug, Sept. 2014)
342  radIC = std::max(radIC, aPlacementHandler->GetHorn1RMinAllBG());
343  radOC = std::max(radOC, aPlacementHandler->GetHorn1RMaxAllBG());
344  }
345  if ((radIC < 1.0e-3) || (radOC < 1.0e-3)) {
346  std::ostringstream mStrStr;
347  mStrStr << " Wrong equation index at Z " << Point[2] << std::endl;
348  G4String mStr(mStrStr.str());
349  G4Exception("LBNEMagneticFieldHorn::GetFieldValue", " ", FatalErrorInArgument, mStr.c_str());
350  return;
351  }
352  }
353  fEffectiveInnerRad = radIC;
354  fEffectiveOuterRad = radOC;
356  // Study of systematic effects. Define an effective radIC wich is large than the physics radIC.
357  // We assume here that the finite skin depth matter, and the current density is not
358  // uniform. Simply increase the radIC
359  if (r < radIC) return; // zero field region (Amps law).
360 // const double deltaRIC = radOC - radIC;
361 // Version from Dec 18-19 2013.
362 // radIC += deltaRIC*std::min(0.99, fSkinDepthCorrInnerRad);
363  //
364 // if ((r > radIC) && (r < radOC)) {
365 // const double surfCyl = radOC*radOC - radIC*radIC;
366 // const double deltaRSq = (r*r - radIC*radIC);
367 // magBField *= deltaRSq/surfCyl; // Assume uniform current density and apply Amps law.
368 // }
369 // Version from Zarko's thesis. ( (MINOS Document 5694-v1) )
370 //
371  if ((r > radIC) && (r < radOC)) {
372  const double surfCyl = radOC*radOC - radIC*radIC;
373  const double deltaRSq = (r*r - radIC*radIC);
374  const double factR = deltaRSq/surfCyl;
375  fEffectiveSkinDepthFact = factR;
376  if (fSkinDepthInnerRad > 10.*CLHEP::mm) { // default assume very large skin depth, assume constant current
377  // current density .
378  magBField *= factR; // Assume uniform current density and apply Amps law.
379  } else { // Realistic skin depth.
380  magBField *= factR*getNormCurrDensityInnerC((r-radIC), (radOC-radIC))
381  /getNormCurrDensityInnerC((radOC-radIC), (radOC-radIC));
382  }
383  }
384 // Sin and cos factor bphi -> bx, by
385  Bfield[0] = -magBField*ptTrans[1]/r;
386  Bfield[1] = magBField*ptTrans[0]/r;
387 //
388 // Important correction.. ( a bug from a long time ago !)
389 // One needs to rotate the field as well. It is expected to be given in global coordinate
390 //
391  if (fHornIsMisaligned) {
392  std::vector<double> bFieldLocal(3);
393  for(size_t k=0; k != 3; k++) { bFieldLocal[k] = Bfield[k]; Bfield[k] = 0.; }
394  for (size_t k1=0; k1 !=3; k1++) {
395  for (size_t k2=0; k2 !=3; k2++) Bfield[k1] += fRotMatrixHornContainer[k1][k2]*bFieldLocal[k2];
396  }
397 // std::cerr << " Misaligned Horn" << hornNumber+1 << ", rotation of the field ... " << std::endl;
398 // for(size_t k=0; k != 3; k++) std::cerr << " Component " << k
399 // << " local " << bFieldLocal[k] << " global " << Bfield[k] << std::endl;
400  }
401  if (!fCoordinateSet) {
402  fCoordinateSet = true; //done once and only once.
403 // this->dumpField();
404  }
405 // this->fillTrajectories(Point, Bfield[0], Bfield[1]);
406 // std::cerr << " Field region at Z " << Point[2] << " r = " << r
407 // << " radIC " << radIC << " radOC "
408 // << radOC << "zLocD " << zLocD << " magBField "
409 // << magBField/tesla << " Bx " << Bfield[0]/tesla << std::endl;
410  }
411 }
413 
414  std::string fName = (amHorn1) ? std::string("./FieldMapNuMIHorn1.txt") :
415  std::string("./FieldMapNuMIHorn2.txt");
416  std::ofstream fOut(fName.c_str());
417  fOut << " z zd r bphi " << std::endl;
418  double zStart = -500.;
419  double zEnd = 4000.;
420  double rMax = fOuterRadius + 5.0*CLHEP::mm;
421 // if (amHorn1) std::cerr << " Horn1, Dumpfield, r Max = " << rMax << std::endl;
422 // else std::cerr << " Horn2, Dumpfield, r Max = " << rMax << std::endl;
423  if (!amHorn1) { zStart = 6000.; zEnd = 11000.; }
424  const int numZStep = 100;
425  const int numRStep= 2000;
426  const double zStep = (zEnd-zStart)/numZStep;
427  const double rStep = rMax/numRStep;
428  double point[3];
429  for (int iZ=0; iZ !=numZStep; iZ++) {
430  double z = zStart + iZ*zStep;
431  point[2] = z;
432  const double zLocD = point[2] - fZShiftDrawingCoordinate;
433  double radIC = fHornNeckInnerRadius;
434 // size_t kSelZ = fEqnIndicesInner.size();
435 // for (size_t k=0; k != fEqnIndicesInner.size(); ++k) {
436 // if (zLocD < fZDCBegin[k]) break;
437 // if (zLocD > fZDCEnd[k]) continue; // They are Z ordered..
438 // kSelZ = k;
439 // break;
440 // }
441 // if (kSelZ == fEqnIndicesInner.size()) continue;
442 // if (fEqnIndicesInner[kSelZ] != 99) {
443 // radIC = (amHorn1) ? aPlacementHandler->GetConductorRadiusHorn1(zLocD,fEqnIndicesInner[kSelZ] ) :
444 // aPlacementHandler->GetConductorRadiusHorn2(zLocD, fEqnIndicesInner[kSelZ]);
445 // }
446  double r = std::max(0., (radIC - 5.*CLHEP::mm)); // make sure we cover the Horn1Poly volume
447  // inside the conductor...
448  while (r < rMax) {
449  const double phi = 2.0*M_PI*G4RandFlat::shoot();
450  point[0] = r*std::cos(phi);
451  point[1] = r*std::sin(phi);
452  double bf[3];
453  this->GetFieldValue(point, &bf[0]);
454  fOut << " " << z << " " << zLocD << " " << r << " "
455  << std::sqrt(bf[0]*bf[0] + bf[1]*bf[1])/CLHEP::tesla << std::endl;
456  if (r < (radIC + 5.0*CLHEP::mm)) r += 0.1*CLHEP::mm;
457  else r += rStep;
458  }
459  }
460  fOut.close();
461 }
462 
463 void LBNEMagneticFieldHorn::fillTrajectories(const double Point[3], double bx, double by) const {
464  if (!fOutTraj.is_open()) return;
465  LBNERunManager* pRunManager = dynamic_cast<LBNERunManager*>(G4RunManager::GetRunManager());
466  fOutTraj << " " << pRunManager->GetCurrentEvent()->GetEventID();
467  for (size_t k=0; k!= 3; k++) fOutTraj << " " << Point[k];
468  fOutTraj << " " << bx/CLHEP::tesla << " " << " " << by/CLHEP::tesla << std::endl;
469  // we flush, the destructor never called..
470  fOutTraj.flush();
471 }
473  std::cerr << " Closing Output Trajectory file in LBNEMagneticFieldHorn " << std::endl;
474  if (fOutTraj.is_open()) fOutTraj.close();
475 }
476 //
477 // Decay pipe field..
478 //
480 isToroid(isToroidal),
481 fWireCurrent(0.),
482 fWireRadius(0.)
483 {
484 }
485 void LBNEMagneticFieldDecayPipe::GetFieldValue(const double Point[3],double *Bfield) const
486 {
487 
488 
489  G4double current = fWireCurrent/CLHEP::ampere/1000.;
490  for (size_t k=0; k!=3; ++k) Bfield[k] = 0.;
491 //
492 // No misalignement of this wire..
493 //
494  const double r = std::sqrt(Point[0]*Point[0] + Point[1]*Point[1]);
495  if (r < fWireRadius) return;
496 
497  double magBField = current / (5.*r/CLHEP::cm)/10*CLHEP::tesla; //B(kG)=i(kA)/[5*r(cm)], 1T=10kG
498  Bfield[0] = -magBField*Point[1]/r;
499  Bfield[1] = magBField*Point[0]/r;
500 
501 // std::cerr << " LBNEMagneticFieldWire::GetFieldValue Z " << Point[2]
502 // << " current " << current << " r " << r << " magfield " << magBField << std::endl;
503 
504 }
double GetHorn1OuterTubeOuterRad() const
double getNormCurrDensityInnerC(double deltaR, double rOut) const
double GetHorn2ZEqnChange(size_t k) const
double GetHorn1EffectiveLength() const
const LBNEVolumePlacementData * Find(const G4String &name, const char *motherName, const char *method) const
std::string string
Definition: nybbler.cc:12
std::vector< LBNESurveyedPt >::const_iterator GetPoint(const std::string &aName) const
static LBNEVolumePlacements * Instance()
double GetHorn1RMinAllBG() const
double GetHorn2DeltaZEntranceToZOrigin() const
virtual void GetFieldValue(const double Point[3], double *Bfield) const
intermediate_table::const_iterator const_iterator
std::vector< size_t > fEqnIndicesInner
std::vector< double > fRadsInnerC
void G4Exception(const char *originOfException, const char *exceptionCode, G4ExceptionSeverity severity, const char *description)
Definition: G4Exception.cc:45
std::vector< double > fZDCBegin
double GetHornParabolicRZCoord(size_t iH, size_t k) const
LBNEMagneticFieldDecayPipe(bool isToroidal)
virtual void GetFieldValue(const double Point[3], double *Bfield) const
double GetHorn1NeckInnerRadius() const
double GetHorn1LongRescale() const
double GetHorn2OuterTubeOuterRad() const
T abs(T value)
std::vector< double > fParams
static LBNESurveyor * Instance()
double GetHorn2NeckInnerRadius() const
std::vector< double > fShift
double z
double GetHorn1ZEndIC() const
double GetHorn1PolyInnerConductorThickness(size_t numPts) const
static Entry * current
static int max(int a, int b)
bool IsHornPnParabolic(size_t numHorn) const
double GetHorn1NeckOuterRadius() const
std::vector< double > fZDCEnd
double GetConductorRadiusHorn2(double zD, size_t eqn) const
double GetHorn1NeckZPosition() const
double GetHorn1PolyInnerConductorRadius(size_t numPts) const
double GetHorn2LongRescale() const
std::vector< double > fShiftSlope
double GetHorn1PolyInnerConductorZCoord(size_t numPts) const
double GetHornParabolicThick(size_t iH, size_t k) const
G4RotationMatrix fRotMatrixHornContainer
double GetHorn1NeckLength() const
void fillHorn1PolygonRadii(double z, double *rIn, double *rOut) const
std::vector< double > fRadsOuterC
double GetConductorRadiusHorn1(double zD, size_t eqn) const
LBNEMagneticFieldHorn(bool isHorn1)
double GetHornParabolicRIn(size_t iH, size_t k) const
std::vector< size_t > fEqnIndicesOuter
void fillTrajectories(const double Point[3], double bx, double by) const
int GetNumberOfHornsPolycone() const
double GetHorn1ZDEndNeckRegion() const
size_t GetHornParabolicNumInnerPts(size_t iH) const
double GetHorn2LongPosition() const
int GetUseHorn1PolyNumInnerPts() const
double GetHorn1RMaxAllBG() const
QTextStream & endl(QTextStream &s)
bool IsHorn1RadiusBigEnough() const
double GetHorn2NeckOuterRadius() const