129 const unsigned int nDim)
131 G4String functionName =
"BDSIM Field Format> ";
135 long long unsigned int currentLineNumber = 0;
138 bool validFile = file.rdbuf()->is_open();
140 bool validFile = file.is_open();
143 {
throw BDSException(__METHOD_NAME__,
"Invalid file name or no such file named \"" + fileName +
"\"");}
145 {G4cout << functionName <<
"Loading \"" << fileName <<
"\"" << G4endl;}
148 unsigned long xIndex = 0;
149 unsigned long yIndex = 0;
150 unsigned long zIndex = 0;
151 G4bool intoData =
false;
157 G4int n1 = 1, n2 = 1, n3 = 1, n4 = 1;
160 G4String nominalOrder =
"xyzt";
162 float maximumFieldValue = 0;
163 float minimumFieldValue = 0;
167 std::getline(file, line);
171 if (std::all_of(line.begin(), line.end(), isspace))
174 if (currentLineNumber > 100)
176 G4String msg = functionName+
"did not encounter column specification line starting with '!' in the first 100 lines\n";
177 msg +=
"This does not appear to be a BDSIM-format field map.";
191 std::smatch matchHeaderNumber;
192 std::regex keyValue(R
"((\w*)\s*>\s*([0-9eE.+-]+))");
193 if (std::regex_search(line, matchHeaderNumber, keyValue))
195 if (matchHeaderNumber.size() < 2)
196 {Terminate(functionName+
"Invalid key definition in field format: " + line);}
199 G4String key = G4String(matchHeaderNumber[1]);
203 if (header.find(key) == header.end())
204 {Terminate(functionName+
"Invalid key \"" + key +
"\" in header");}
208 {value = std::stod(matchHeaderNumber[2]);}
209 catch (
const std::invalid_argument&)
210 {Terminate(functionName+
"Invalid argument " + std::string(matchHeaderNumber[2]));}
211 catch (
const std::out_of_range&)
212 {Terminate(functionName+
"Number out of range " + std::string(matchHeaderNumber[2]));}
214 if (std::find(headerMustBePositiveKeys.begin(), headerMustBePositiveKeys.end(), key) != headerMustBePositiveKeys.end())
217 {Terminate(functionName+
"Number of points in dimension must be greater than 0 -> see \"" + key +
"\"");}
225 std::smatch matchHeaderString;
229 std::regex keyWord(R
"((\w+)\s*>\s*([a-zA-Z]{1,4})\b\s*)");
230 if (std::regex_search(line, matchHeaderString, keyWord))
232 loopOrder = G4String(matchHeaderString[2]);
234 G4bool test1 = loopOrder ==
"xyzt";
235 G4bool test2 = loopOrder ==
"tzyx";
236 if (! (test1 || test2) )
237 {Terminate(functionName+
"loopOrder> header variable is not one of (\"xyzt\" or \"tzyx\")");}
244 std::regex columnRow(
"^\\s*!");
245 if (std::regex_search(line, columnRow))
249 std::regex afterExclamation(
"\\s*!\\s*(.+)");
251 std::regex_search(line, match, afterExclamation);
252 std::string restOfLine = match[1];
253 std::string columnName;
254 std::istringstream restOfLineSS(restOfLine);
255 std::vector<G4String> columnNames;
256 while (restOfLineSS >> columnName)
259 if (columnName.find(
"Fx") != std::string::npos)
260 {xIndex = nColumns;
continue;}
261 else if (columnName.find(
"Fy") != std::string::npos)
262 {yIndex = nColumns;
continue;}
263 else if (columnName.find(
"Fz") != std::string::npos)
264 {zIndex = nColumns;
continue;}
266 {columnNames.emplace_back(columnName);}
268 lineData.resize(nColumns + 1);
269 indexOfFirstFieldValue = std::min({xIndex, yIndex, zIndex});
271 for (
const auto& key : headerMustBePositiveKeys)
274 {Terminate(functionName+
"Number of points in dimension must be greater than 0 -> see \"" + key +
"\"");}
277 if (nColumns < (nDim + 3))
278 {Terminate(functionName+
"Too few columns for " + std::to_string(nDim) +
"D field loading");}
286 auto keys = dimKeyMap[firstDim];
287 double unit = dimUnitsMap[firstDim];
288 n1 = G4int(header[keys.number]);
290 header[keys.min] * unit,
291 header[keys.max] * unit,
299 auto fKeys = dimKeyMap[firstDim];
300 double fUnit = dimUnitsMap[firstDim];
301 auto sKeys = dimKeyMap[secondDim];
302 double sUnit = dimUnitsMap[secondDim];
303 n1 = G4int(header[fKeys.number]);
304 n2 = G4int(header[sKeys.number]);
306 header[fKeys.min] * fUnit,
307 header[fKeys.max] * fUnit,
308 header[sKeys.min] * sUnit,
309 header[sKeys.max] * sUnit,
319 auto fKeys = dimKeyMap[firstDim];
320 double fUnit = dimUnitsMap[firstDim];
321 auto sKeys = dimKeyMap[secondDim];
322 double sUnit = dimUnitsMap[secondDim];
323 auto tKeys = dimKeyMap[thirdDim];
324 double tUnit = dimUnitsMap[thirdDim];
325 n1 = G4int(header[fKeys.number]);
326 n2 = G4int(header[sKeys.number]);
327 n3 = G4int(header[tKeys.number]);
329 header[fKeys.min] * fUnit,
330 header[fKeys.max] * fUnit,
331 header[sKeys.min] * sUnit,
332 header[sKeys.max] * sUnit,
333 header[tKeys.min] * tUnit,
334 header[tKeys.max] * tUnit,
342 n1 = G4int(header[
"nx"]);
343 n2 = G4int(header[
"ny"]);
344 n3 = G4int(header[
"nz"]);
345 n4 = G4int(header[
"nt"]);
347 header[
"xmin"] * CLHEP::cm, header[
"xmax"] * CLHEP::cm,
348 header[
"ymin"] * CLHEP::cm, header[
"ymax"] * CLHEP::cm,
349 header[
"zmin"] * CLHEP::cm, header[
"zmax"] * CLHEP::cm,
350 header[
"tmin"] * CLHEP::s, header[
"tmax"] * CLHEP::s);
362 if (loopOrder ==
"tzyx")
364 for (G4int i = 0; i < n1; i++)
366 for (G4int j = 0; j < n2; j++)
368 for (G4int k = 0; k < n3; k++)
370 for (G4int l = 0; l < n4; l++)
372 if (!std::getline(file, line))
373 {Terminate(functionName +
"unexpected end to file on line number " + std::to_string(currentLineNumber));}
375 if (std::all_of(line.begin(), line.end(), isspace))
377 ProcessData(line, xIndex, yIndex, zIndex, currentLineNumber);
378 (*result)(i, j, k, l) = fv;
379 float mag = fv.mag();
380 maximumFieldValue = std::max(maximumFieldValue, mag);
381 minimumFieldValue = std::min(minimumFieldValue, mag);
389 for (G4int l = 0; l < n4; l++)
391 for (G4int k = 0; k < n3; k++)
393 for (G4int j = 0; j < n2; j++)
395 for (G4int i = 0; i < n1; i++)
397 if (!std::getline(file, line))
398 {Terminate(functionName +
"unexpected end to file on line number " + std::to_string(currentLineNumber));}
400 if (std::all_of(line.begin(), line.end(), isspace))
402 ProcessData(line, xIndex, yIndex, zIndex, currentLineNumber);
403 (*result)(i, j, k, l) = fv;
404 float mag = fv.mag();
405 maximumFieldValue = std::max(maximumFieldValue, mag);
406 minimumFieldValue = std::min(minimumFieldValue, mag);
414 G4cout << functionName <<
"Loaded " << currentLineNumber <<
" lines from file" << G4endl;
415 G4cout << functionName <<
"(Min | Max) field magnitudes in loaded file (before scaling): (" << minimumFieldValue <<
" | " << maximumFieldValue <<
")" << G4endl;