19#include "BDSAuxiliaryNavigator.hh"
21#include "BDSException.hh"
22#include "BDSFieldQuery.hh"
23#include "BDSFieldQueryInfo.hh"
24#include "BDSUtilities.hh"
25#include "BDSWarning.hh"
29#include "G4FieldManager.hh"
30#include "G4LogicalVolume.hh"
31#include "G4Navigator.hh"
33#include "G4ThreeVector.hh"
35#include "G4VPhysicalVolume.hh"
37#include "CLHEP/Units/SystemOfUnits.h"
46BDSFieldQuery::BDSFieldQuery():
57BDSFieldQuery::~BDSFieldQuery()
68 queryMagnetic =
false;
69 queryElectric =
false;
79 for (
const auto& fieldQuery : fieldQueries)
101 G4cout <<
"FieldQuery> \"" << query->name <<
"\" with N (x,y,z,t) points: ("
102 << query->xInfo.n <<
", " << query->yInfo.n <<
", " << query->zInfo.n <<
", " << query->tInfo.n
106 if (query->printTransform)
107 {G4cout << query->globalTransform << G4endl;}
110 BDSAuxiliaryNavigator::ResetNavigatorStates();
112 G4double xMin = query->xInfo.min;
113 G4double nStepsX = query->xInfo.n == 1 ? 1 : (G4double)query->xInfo.n-1;
114 G4double xStep = (query->xInfo.max - query->xInfo.min) / nStepsX;
115 if (std::isnan(xStep))
119 G4double yMin = query->yInfo.min;
120 G4double nStepsY = query->yInfo.n == 1 ? 1 : (G4double)query->yInfo.n-1;
121 G4double yStep = (query->yInfo.max - query->yInfo.min) / nStepsY;
122 if (std::isnan(yStep))
126 G4double zMin = query->zInfo.min;
127 G4double nStepsZ = query->zInfo.n == 1 ? 1 : (G4double)query->zInfo.n-1;
128 G4double zStep = (query->zInfo.max - query->zInfo.min) / nStepsZ;
129 if (std::isnan(zStep))
133 G4double tMin = query->tInfo.min;
134 G4double nStepsT = query->yInfo.n == 1 ? 1 : (G4double)query->tInfo.n-1;
135 G4double tStep = (query->tInfo.max - query->tInfo.min) / nStepsT;
136 if (std::isnan(tStep))
140 G4ThreeVector xyzGlobal = G4ThreeVector();
141 const G4AffineTransform& localToGlobalTransform = query->globalTransform;
142 G4AffineTransform globalToLocalTransform = localToGlobalTransform.Inverse();
144 G4ThreeVector generalUnitZ(0,0,1);
145 localToGlobalTransform.ApplyAxisTransform(generalUnitZ);
149 G4double globalFieldValue[6];
150 G4double localFieldValue[6];
152 G4double tLocal = tMin;
153 for (G4int i = 0; i < query->tInfo.n; i++)
155 G4double zLocal = zMin;
156 for (G4int j = 0; j < query->zInfo.n; j++)
158 G4double yLocal = yMin;
159 for (G4int k = 0; k < query->yInfo.n; k++)
161 G4double xLocal = xMin;
162 for (G4int l = 0; l < query->xInfo.n; l++)
165 GetFieldValue(xyzGlobal, generalUnitZ, tLocal, globalFieldValue);
181 G4cout <<
"FieldQuery> Complete" << G4endl;
185 const G4String& dimensionName,
186 const G4String& queryName)
const
188 const G4String& d = dimensionName;
189 G4bool nonZeroRange =
BDS::IsFinite(std::abs(dimensionInfo.max - dimensionInfo.min));
190 if (dimensionInfo.n > 1 && !nonZeroRange)
192 G4String msg =
"Problem in query \"" + queryName +
"\": n"+d+
" > 1, but |"+d;
193 msg +=
"max - "+d+
"min| = 0 -> cannot take more than 1 step in 0 range.";
196 if (dimensionInfo.n == 1 && nonZeroRange)
197 {BDS::Warning(
"Only 1 point to query in \"" + queryName +
"\" over a non-zero range - check n"+d);}
204 G4String msg =
"\"fieldObject\" variable is specified in query definition \"" + query->name;
205 msg +=
"\" - this has no effect\nInstead use \"referenceElement\"";
212 const std::vector<BDSFourVector<G4double>> points = query->pointsToQuery;
214 G4cout <<
"FieldQuery> \"" << query->name <<
"\" with N points: "
215 << points.size() <<
", writing to file";
221 G4ThreeVector generalUnitZ(0,0,1);
222 G4double globalFieldValue[6];
223 for (
auto const& xyzt : points)
225 xyz = G4ThreeVector(xyzt.x(), xyzt.y(), xyzt.z());
231 G4cout <<
"FieldQuery> Complete" << G4endl;
236 G4cout <<
", writing to file";
237 if (query->queryMagnetic && query->queryElectric)
238 {G4cout <<
"s B: \"" << query->outfileMagnetic <<
"\" and E: \"" << query->outfileElectric <<
"\"" << G4endl;}
239 else if (query->queryMagnetic)
240 {G4cout <<
" B: \"" << query->outfileMagnetic <<
"\"" << G4endl;}
242 {G4cout <<
" E: \"" << query->outfileElectric <<
"\"" << G4endl;}
247 if (!(query->pointsColumnNames.empty()))
249 std::map<G4String, G4bool*> columnNamesToFlag = { {
"x", &writeX},
253 for (
const auto& columnName : query->pointsColumnNames)
254 { *(columnNamesToFlag[columnName]) =
true;}
255 BDS::Warning(__METHOD_NAME__,
"the number of points and min max values in the output header will not be correct when using points");
259 writeX = query->xInfo.n > 1;
260 writeY = query->yInfo.n > 1;
261 writeZ = query->zInfo.n > 1;
262 writeT = query->tInfo.n > 1;
265 if (query->queryMagnetic)
267 if (
BDS::FileExists(query->outfileMagnetic) && !(query->overwriteExistingFiles))
269 G4String msg =
"\"" + query->outfileMagnetic +
"\" file already exists and \"overwriteExistingFiles\" in query \"";
270 msg += query->name +
"\" is false";
273 queryMagnetic =
true;
274 oFileMagnetic.open(query->outfileMagnetic);
278 if (query->queryElectric)
280 if (
BDS::FileExists(query->outfileElectric) && !(query->overwriteExistingFiles))
282 G4String msg =
"\"" + query->outfileElectric +
"\" file already exists and \"overwriteExistingFiles\" in query \"";
283 msg += query->name +
"\" is false";
286 queryElectric =
true;
287 oFileElectric.open(query->outfileElectric);
295 G4String columns =
"! ";
298 out <<
"nx> " << query->xInfo.n <<
"\n";
299 out <<
"xmin> " << query->xInfo.min/CLHEP::cm <<
"\n";
300 out <<
"xmax> " << query->xInfo.max/CLHEP::cm <<
"\n";
305 out <<
"ny> " << query->yInfo.n <<
"\n";
306 out <<
"ymin> " << query->yInfo.min/CLHEP::cm <<
"\n";
307 out <<
"ymax> " << query->yInfo.max/CLHEP::cm <<
"\n";
312 out <<
"nz> " << query->zInfo.n <<
"\n";
313 out <<
"zmin> " << query->zInfo.min/CLHEP::cm <<
"\n";
314 out <<
"zmax> " << query->zInfo.max/CLHEP::cm <<
"\n";
319 out <<
"nt> " << query->tInfo.n <<
"\n";
320 out <<
"tmin> " << query->tInfo.min/CLHEP::s <<
"\n";
321 out <<
"tmax> " << query->tInfo.max/CLHEP::s <<
"\n";
324 columns +=
" Fx Fy Fz\n";
330 if (oFileMagnetic.is_open())
331 {oFileMagnetic.close();}
332 if (oFileElectric.is_open())
333 {oFileElectric.close();}
339 G4double zLocal)
const
341 G4ThreeVector xyzGlobal = G4ThreeVector(xLocal, yLocal, zLocal);
342 localToGlobalTransform.ApplyPointTransform(xyzGlobal);
347 const G4double globalBEField[6],
348 G4double localBEField[6])
350 G4ThreeVector B(globalBEField[0], globalBEField[1], globalBEField[2]);
351 G4ThreeVector E(globalBEField[3], globalBEField[4], globalBEField[5]);
352 globalToLocalTransform.ApplyAxisTransform(B);
353 globalToLocalTransform.ApplyAxisTransform(E);
354 for (G4int i = 0; i < 3; i++)
356 localBEField[i] = B[i];
357 localBEField[i+3] = E[i];
362 const G4ThreeVector& globalDirection,
364 G4double fieldValue[6])
368 for (G4int i = 0; i < 6; i++)
370 G4VPhysicalVolume* pv =
navigator->LocateGlobalPointAndSetup(globalXYZ, &globalDirection,
false);
373 G4LogicalVolume* lv = pv->GetLogicalVolume();
374 G4FieldManager* fm = lv->GetFieldManager();
377 const G4Field* field = fm->GetDetectorField();
378 G4double position[4] = {globalXYZ.x(), globalXYZ.y(),globalXYZ.z(), tGlobal};
379 field->GetFieldValue(position, fieldValue);
385 const G4double fieldValue[6])
390 {oFileMagnetic << std::setprecision(6) << std::setw(10) << xyzLocal.x() / CLHEP::cm <<
" ";}
392 {oFileMagnetic << std::setprecision(6) << std::setw(10) << xyzLocal.y() / CLHEP::cm <<
" ";}
394 {oFileMagnetic << std::setprecision(6) << std::setw(10) << xyzLocal.z() / CLHEP::cm <<
" ";}
396 {oFileMagnetic << std::setprecision(6) << std::setw(10) << tLocal / CLHEP::s <<
" ";}
397 for (G4int i = 0; i < 3; i++)
398 {oFileMagnetic << std::setprecision(6) << std::setw(15) << fieldValue[i] / CLHEP::tesla <<
" ";}
399 oFileMagnetic <<
"\n";
404 {oFileElectric << std::setprecision(6) << std::setw(10) << xyzLocal.x() / CLHEP::cm <<
" ";}
406 {oFileElectric << std::setprecision(6) << std::setw(10) << xyzLocal.y() / CLHEP::cm <<
" ";}
408 {oFileElectric << std::setprecision(6) << std::setw(10) << xyzLocal.z() / CLHEP::cm <<
" ";}
410 {oFileElectric << std::setprecision(6) << std::setw(10) << tLocal / CLHEP::s <<
" ";}
411 for (G4int i = 3; i < 6; i++)
412 {oFileElectric << std::setprecision(6) << std::setw(15) << fieldValue[i] / (CLHEP::volt/CLHEP::m) <<
" ";}
413 oFileElectric <<
"\n";
General exception with possible name of object and message.
Holder class for all information required for a field query.
G4bool checkParameters
For internal testing use only.
G4bool SpecificPoints() const
Whether to query a specific set of points.
G4String fieldObject
Optional for use in interpolator.
static G4Navigator * navigator
One navigator used - static so we can externally link it up to the world PV.
static void AttachWorldVolumeToNavigator(G4VPhysicalVolume *worldPVIn)
Setup the navigator w.r.t. to a world volume.
virtual void OpenFiles(const BDSFieldQueryInfo *query)
Open potentially both electric and magnetic field map files.
virtual void WriteHeader(std::ofstream &out, const BDSFieldQueryInfo *query) const
Utility to write required header information.
void QueryFields(const std::vector< BDSFieldQueryInfo * > &fieldQueries)
Vector version of above function. Unique output files for each query.
virtual void CleanUp()
Reset any member variables used during a query. Closes any files if open.
G4ThreeVector LocalToGlobalPoint(const G4AffineTransform &localToGlobalTransform, G4double xLocal, G4double yLocal, G4double zLocal) const
Apply a transform to the coordinates. Does not apply to time.
void CheckNStepsAndRange(const BDSFieldQueryInfo::QueryDimensionInfo &dimensionInfo, const G4String &dimensionName, const G4String &queryName) const
Throw an exception if the number of steps is >1 and the difference between max and min is 0.
virtual void CheckIfFieldObjectSpecified(const BDSFieldQueryInfo *query) const
Warn the user if the fieldObject variable is use when it shouldn't be.
void QuerySpecificPoints(const BDSFieldQueryInfo *query)
Different algorithm where we query a specific list of points defined in the query info object.
virtual void CloseFiles()
Close any files if open.
virtual void PrintBAndEInfo(const BDSFieldQueryInfo *query) const
Print out whether B and E files are being generated and which ones.
virtual void QueryField(const BDSFieldQueryInfo *query)
Query the field in the Geant4 model according to information in query.
virtual void GetFieldValue(const G4ThreeVector &globalXYZ, const G4ThreeVector &globalDirection, G4double tGlobal, G4double fieldValue[6])
virtual void WriteFieldValue(const G4ThreeVector &xyzGlobal, G4double tGlobal, const G4double fieldValue[6])
Write an entry ta line of the output file(s). The array is assumed to be Bx,By,Bz,...
void GlobalToLocalAxisField(const G4AffineTransform &globalToLocalTransform, const G4double globalBEField[6], G4double localBEField[6])
Convert a global field axis to a local one.
G4bool FileExists(const G4String &filename)
Checks if filename exists.
G4bool IsFinite(G4double value, G4double tolerance=std::numeric_limits< double >::epsilon())