130 const unsigned int nDim)
132 G4String functionName =
"BDSIM Field Format> ";
136 long long unsigned int currentLineNumber = 0;
139 bool validFile = file.rdbuf()->is_open();
141 bool validFile = file.is_open();
144 {
throw BDSException(__METHOD_NAME__,
"Invalid file name or no such file named \"" + fileName +
"\"");}
146 {G4cout << functionName <<
"Loading \"" << fileName <<
"\"" << G4endl;}
149 unsigned long xIndex = 0;
150 unsigned long yIndex = 0;
151 unsigned long zIndex = 0;
152 G4bool intoData =
false;
158 G4int n1 = 1, n2 = 1, n3 = 1, n4 = 1;
161 G4String nominalOrder =
"xyzt";
163 float maximumFieldValue = 0;
164 float minimumFieldValue = 0;
168 std::getline(file, line);
172 if (std::all_of(line.begin(), line.end(), isspace))
175 if (currentLineNumber > 100)
177 G4String msg = functionName+
"did not encounter column specification line starting with '!' in the first 100 lines\n";
178 msg +=
"This does not appear to be a BDSIM-format field map.";
192 std::smatch matchHeaderNumber;
193 std::regex keyValue(R
"((\w*)\s*>\s*([0-9eE.+-]+))");
194 if (std::regex_search(line, matchHeaderNumber, keyValue))
196 if (matchHeaderNumber.size() < 2)
197 {Terminate(functionName+
"Invalid key definition in field format: " + line);}
200 G4String key = G4String(matchHeaderNumber[1]);
204 if (header.find(key) == header.end())
205 {Terminate(functionName+
"Invalid key \"" + key +
"\" in header");}
209 {value = std::stod(matchHeaderNumber[2]);}
210 catch (
const std::invalid_argument&)
211 {Terminate(functionName+
"Invalid argument " + std::string(matchHeaderNumber[2]));}
212 catch (
const std::out_of_range&)
213 {Terminate(functionName+
"Number out of range " + std::string(matchHeaderNumber[2]));}
215 if (std::find(headerMustBePositiveKeys.begin(), headerMustBePositiveKeys.end(), key) != headerMustBePositiveKeys.end())
218 {Terminate(functionName+
"Number of points in dimension must be greater than 0 -> see \"" + key +
"\"");}
226 std::smatch matchHeaderString;
230 std::regex keyWord(R
"((\w+)\s*>\s*([a-zA-Z]{1,4})\b\s*)");
231 if (std::regex_search(line, matchHeaderString, keyWord))
233 loopOrder = G4String(matchHeaderString[2]);
235 G4bool test1 = loopOrder ==
"xyzt";
236 G4bool test2 = loopOrder ==
"tzyx";
237 if (! (test1 || test2) )
238 {Terminate(functionName+
"loopOrder> header variable is not one of (\"xyzt\" or \"tzyx\")");}
245 std::regex columnRow(
"^\\s*!");
246 if (std::regex_search(line, columnRow))
250 std::regex afterExclamation(
"\\s*!\\s*(.+)");
252 std::regex_search(line, match, afterExclamation);
253 std::string restOfLine = match[1];
254 std::string columnName;
255 std::istringstream restOfLineSS(restOfLine);
256 std::vector<G4String> columnNames;
257 while (restOfLineSS >> columnName)
260 if (columnName.find(
"Fx") != std::string::npos)
261 {xIndex = nColumns;
continue;}
262 else if (columnName.find(
"Fy") != std::string::npos)
263 {yIndex = nColumns;
continue;}
264 else if (columnName.find(
"Fz") != std::string::npos)
265 {zIndex = nColumns;
continue;}
267 {columnNames.emplace_back(columnName);}
269 lineData.resize(nColumns + 1);
270 indexOfFirstFieldValue = std::min({xIndex, yIndex, zIndex});
272 for (
const auto& key : headerMustBePositiveKeys)
275 {Terminate(functionName+
"Number of points in dimension must be greater than 0 -> see \"" + key +
"\"");}
278 if (nColumns < (nDim + 3))
279 {Terminate(functionName+
"Too few columns for " + std::to_string(nDim) +
"D field loading");}
287 auto keys = dimKeyMap[firstDim];
288 double unit = dimUnitsMap[firstDim];
289 n1 = G4int(header[keys.number]);
291 header[keys.min] * unit,
292 header[keys.max] * unit,
300 auto fKeys = dimKeyMap[firstDim];
301 double fUnit = dimUnitsMap[firstDim];
302 auto sKeys = dimKeyMap[secondDim];
303 double sUnit = dimUnitsMap[secondDim];
304 n1 = G4int(header[fKeys.number]);
305 n2 = G4int(header[sKeys.number]);
307 header[fKeys.min] * fUnit,
308 header[fKeys.max] * fUnit,
309 header[sKeys.min] * sUnit,
310 header[sKeys.max] * sUnit,
320 auto fKeys = dimKeyMap[firstDim];
321 double fUnit = dimUnitsMap[firstDim];
322 auto sKeys = dimKeyMap[secondDim];
323 double sUnit = dimUnitsMap[secondDim];
324 auto tKeys = dimKeyMap[thirdDim];
325 double tUnit = dimUnitsMap[thirdDim];
326 n1 = G4int(header[fKeys.number]);
327 n2 = G4int(header[sKeys.number]);
328 n3 = G4int(header[tKeys.number]);
330 header[fKeys.min] * fUnit,
331 header[fKeys.max] * fUnit,
332 header[sKeys.min] * sUnit,
333 header[sKeys.max] * sUnit,
334 header[tKeys.min] * tUnit,
335 header[tKeys.max] * tUnit,
343 n1 = G4int(header[
"nx"]);
344 n2 = G4int(header[
"ny"]);
345 n3 = G4int(header[
"nz"]);
346 n4 = G4int(header[
"nt"]);
348 header[
"xmin"] * CLHEP::cm, header[
"xmax"] * CLHEP::cm,
349 header[
"ymin"] * CLHEP::cm, header[
"ymax"] * CLHEP::cm,
350 header[
"zmin"] * CLHEP::cm, header[
"zmax"] * CLHEP::cm,
351 header[
"tmin"] * CLHEP::s, header[
"tmax"] * CLHEP::s);
363 if (loopOrder ==
"tzyx")
365 for (G4int i = 0; i < n1; i++)
367 for (G4int j = 0; j < n2; j++)
369 for (G4int k = 0; k < n3; k++)
371 for (G4int l = 0; l < n4; l++)
373 if (!std::getline(file, line))
374 {Terminate(functionName +
"unexpected end to file on line number " + std::to_string(currentLineNumber));}
376 if (std::all_of(line.begin(), line.end(), isspace))
378 ProcessData(line, xIndex, yIndex, zIndex, currentLineNumber);
379 (*result)(i, j, k, l) = fv;
380 float mag = fv.mag();
381 maximumFieldValue = std::max(maximumFieldValue, mag);
382 minimumFieldValue = std::min(minimumFieldValue, mag);
390 for (G4int l = 0; l < n4; l++)
392 for (G4int k = 0; k < n3; k++)
394 for (G4int j = 0; j < n2; j++)
396 for (G4int i = 0; i < n1; i++)
398 if (!std::getline(file, line))
399 {Terminate(functionName +
"unexpected end to file on line number " + std::to_string(currentLineNumber));}
401 if (std::all_of(line.begin(), line.end(), isspace))
403 ProcessData(line, xIndex, yIndex, zIndex, currentLineNumber);
404 (*result)(i, j, k, l) = fv;
405 float mag = fv.mag();
406 maximumFieldValue = std::max(maximumFieldValue, mag);
407 minimumFieldValue = std::min(minimumFieldValue, mag);
415 G4cout << functionName <<
"Loaded " << currentLineNumber <<
" lines from file" << G4endl;
416 G4cout << functionName <<
"(Min | Max) field magnitudes in loaded file (before scaling): (" << minimumFieldValue <<
" | " << maximumFieldValue <<
")" << G4endl;