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