BDSIM
BDSIM is a Geant4 extension toolkit for simulation of particle transport in accelerator beamlines.
BDSFieldLoaderQueryPoints.cc
1/*
2Beam Delivery Simulation (BDSIM) Copyright (C) Royal Holloway,
3University of London 2001 - 2022.
4
5This file is part of BDSIM.
6
7BDSIM is free software: you can redistribute it and/or modify
8it under the terms of the GNU General Public License as published
9by the Free Software Foundation version 3 of the License.
10
11BDSIM is distributed in the hope that it will be useful, but
12WITHOUT ANY WARRANTY; without even the implied warranty of
13MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14GNU General Public License for more details.
15
16You should have received a copy of the GNU General Public License
17along with BDSIM. If not, see <http://www.gnu.org/licenses/>.
18*/
19#include "BDSException.hh"
20#include "BDSFieldLoaderQueryPoints.hh"
21#include "BDSFourVector.hh"
22#include "BDSUtilities.hh"
23
24#include "globals.hh"
25#include "G4String.hh"
26
27#include "CLHEP/Units/SystemOfUnits.h"
28
29#include <algorithm>
30#include <fstream>
31#include <iostream>
32#include <map>
33#include <regex>
34#include <sstream>
35#include <string>
36#include <vector>
37
38#ifdef USE_GZSTREAM
39#include "src-external/gzstream/gzstream.h"
40#endif
41
42template <class T>
44{;}
45
46template <class T>
48{;}
49
50template <class T>
51std::vector<BDSFourVector<G4double>> BDSFieldLoaderQueryPoints<T>::Load(const G4String& fileName,
52 std::vector<G4String>* columnNamesIn) const
53{
54 G4String functionName = "BDSFieldLoaderQueryPoints::Load> ";
55 T file;
56
57 file.open(fileName);
58
59 // test if file is valid
60#ifdef USE_GZSTREAM
61 bool validFile = file.rdbuf()->is_open();
62#else
63 bool validFile = file.is_open();
64#endif
65
66 if (!validFile)
67 {throw BDSException(functionName, "Cannot open file \"" + fileName + "\"");}
68 else
69 {G4cout << functionName << "loading \"" << fileName << "\"" << G4endl;}
70
71 std::string line;
72 std::vector<BDSFourVector<G4double>> result;
73
74 G4double x = 0;
75 G4double y = 0;
76 G4double z = 0;
77 G4double t = 0;
78 std::map<G4String, G4double*> columnNameToVariableAddress = { {"x",&x},
79 {"y",&y},
80 {"z",&z},
81 {"t",&t} };
82 std::map<G4String, G4double> columnNameToUnits = { {"x", CLHEP::m},
83 {"y", CLHEP::m},
84 {"z", CLHEP::m},
85 {"t", CLHEP::ns} };
86 std::vector<G4double*> values;
87 std::vector<G4double> units;
88 std::vector<G4String> columnNamesToPrint;
89 G4int nCoordinates = 0;
90 G4bool intoData = false;
91 G4int lineNo = 1;
92 while (std::getline(file, line))
93 {
94 x = 0;
95 y = 0;
96 z = 0;
97 t = 0;
98
99 // skip a line if it's only whitespace
100 if (std::all_of(line.begin(), line.end(), isspace))
101 {
102 lineNo += 1;
103 continue;
104 }
105
106 if (!intoData)
107 {
108 std::regex columnRow("^\\s*[!\\#]"); // ignore any initial white space and look for '!'
109 if (std::regex_search(line, columnRow))
110 {
111 std::regex afterExclamation("\\s*!\\s*(.+)");
112 std::smatch match;
113 std::regex_search(line, match, afterExclamation);
114 std::string restOfLine = match[1];
115
116 if (restOfLine.empty())
117 {
118 G4String msg = "Error on line> " + std::to_string(lineNo);
119 msg += ": column specification missing variables";
120 throw BDSException(functionName, msg);
121 }
122
123 std::vector<G4String> columnNames = BDS::SplitOnWhiteSpace(restOfLine);
124 for (const auto& columnName : columnNames)
125 {
126 G4String variableName = BDS::LowerCase(columnName);
127 auto search = columnNameToVariableAddress.find(variableName);
128 if (search == columnNameToVariableAddress.end())
129 {
130 G4String msg = "Error on line> " + std::to_string(lineNo) + "> variable name \"";
131 msg += variableName + "\" is not one of 'x', 'y', 'z', 't'";
132 throw BDSException(functionName, msg);
133 }
134 values.push_back(search->second);
135 units.push_back(columnNameToUnits[search->first]);
136 if (std::find(columnNamesToPrint.begin(), columnNamesToPrint.end(), search->first) != columnNamesToPrint.end())
137 {throw BDSException(functionName, "duplicate column name");}
138 columnNamesToPrint.push_back(search->first);
139 }
140 nCoordinates = (G4int)values.size();
141 G4cout << functionName << "assuming " << nCoordinates << " coordinate";
142 if (nCoordinates > 1)
143 {G4cout << "s";}
144 G4cout << " in each line: (";
145 for (const auto& coordName : columnNamesToPrint)
146 {G4cout << " " << coordName;}
147 G4cout << " )" << G4endl;
148 if (columnNamesIn)
149 {*columnNamesIn = columnNamesToPrint;}
150 }
151 intoData = true;
152 lineNo += 1;
153 continue;
154 }
155
156 std::vector<G4String> wordsInLine = BDS::SplitOnWhiteSpace(line);
157
158 if ((G4int)wordsInLine.size() != nCoordinates)
159 {throw BDSException(functionName, "invalid number of coordinates on line " + std::to_string(lineNo));}
160
161 for (G4int i = 0; i < (G4int)values.size(); i++)
162 {
163 G4double coord = 0;
164 try
165 {coord = std::stod(wordsInLine[i]);}
166 catch (std::exception& e)
167 {throw BDSException(functionName, "Error on line> " + std::to_string(lineNo) + "> cannot convert to number");}
168 (*values[i]) = coord * units[i];
169 }
170
171 result.emplace_back(BDSFourVector<G4double>(x,y,z,t));
172
173 lineNo += 1;
174 }
175
176 file.close();
177
178 G4cout << functionName << "loaded " << result.size() << " points" << G4endl;
179
180 return result;
181}
182
183std::vector<BDSFourVector<G4double>> BDS::LoadFieldQueryPoints(const G4String& fileName,
184 std::vector<G4String>* columnNamesIn)
185{
186 G4String functionName = "BDS::LoadFieldQueryPoints>"; // namespaced functions don't print so well
187
188 G4String fullFilePath = BDS::GetFullPath(fileName);
189 if (!BDS::FileExists(fullFilePath))
190 {throw BDSException(functionName, "no such file: \"" + fullFilePath + "\"");}
191
192 std::vector<BDSFourVector<G4double>> result;
193 if (fullFilePath.rfind("gz") != std::string::npos)
194 {
195#ifdef USE_GZSTREAM
197 result = loader.Load(fullFilePath, columnNamesIn);
198#else
199 throw BDSException(functionName, "Compressed file loading - but BDSIM not compiled with ZLIB.");
200#endif
201 }
202 else
203 {
205 result = loader.Load(fullFilePath, columnNamesIn);
206 }
207 return result;
208}
209
211
212#ifdef USE_GZSTREAM
214#endif
General exception with possible name of object and message.
Definition: BDSException.hh:35
A loader for up to 4D points for querying fields.
std::vector< BDSFourVector< G4double > > LoadFieldQueryPoints(const G4String &fileName, std::vector< G4String > *columnNamesIn)
G4String GetFullPath(G4String filename, bool excludeNameFromPath=false, bool useCWDForPrefix=false)
G4String LowerCase(const G4String &str)
Utility function to simplify lots of syntax changes for pedantic g4 changes.
G4bool FileExists(const G4String &filename)
Checks if filename exists.
std::vector< G4String > SplitOnWhiteSpace(const G4String &input)
Split a string on whitespace and return a vector of these 'words'.