BDSIM
BDSIM is a Geant4 extension toolkit for simulation of particle transport in accelerator beamlines.
Loading...
Searching...
No Matches
BDSAperturePointsLoader.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 "BDSAperturePointsLoader.hh"
19#include "BDSDebug.hh"
20#include "BDSException.hh"
21#include "BDSUtilities.hh"
22
23#include "G4String.hh"
24#include "G4TwoVector.hh"
25#include "G4Types.hh"
26#include "G4UnitsTable.hh"
27#include "G4Version.hh"
28
29#include <algorithm>
30#include <array>
31#include <exception>
32#include <fstream>
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
42BDSAperturePointsCache* BDSAperturePointsCache::instance = nullptr;
43
44template <class T>
46{;}
47
48template <class T>
50{;}
51
52template <class T>
53std::vector<G4TwoVector>* BDSAperturePointsLoader<T>::Load(const G4String& fileName,
54 G4double unit) const
55{
56 G4String functionName = "BDSAperturePointsLoader::Load> ";
57 T file;
58
59 if (fileName.empty())
60 {throw BDSException(functionName, "empty file name given");}
61
62 file.open(fileName);
63
64 // test if file is valid
65#ifdef USE_GZSTREAM
66 bool validFile = file.rdbuf()->is_open();
67#else
68 bool validFile = file.is_open();
69#endif
70
71 if (!validFile)
72 {throw BDSException(functionName, "Cannot open file \"" + fileName + "\"");}
73 else
74 {G4cout << functionName << "loading \"" << fileName << "\"" << G4endl;}
75
76 std::string line;
77 auto result = new std::vector<G4TwoVector>();
78 std::array<G4double, 2> values({0,0});
79 G4int lineNo = 1;
80 std::regex commentLine("^\\s*[\\#!]");
81 while (std::getline(file, line))
82 {
83 // skip a line if it's only whitespace
84 if (std::all_of(line.begin(), line.end(), isspace))
85 {
86 lineNo += 1;
87 continue;
88 }
89 // or a comment
90 if (std::regex_search(line, commentLine))
91 {
92 lineNo += 1;
93 continue;
94 }
95
96 std::vector<G4String> wordsInLine = BDS::SplitOnWhiteSpace(line);
97
98 if ((G4int)wordsInLine.size() != 2)
99 {throw BDSException(functionName, "invalid number of coordinates on line " + std::to_string(lineNo));}
100
101 for (G4int i = 0; i < (G4int)values.size(); i++)
102 {
103 G4double coord = 0;
104 try
105 {coord = std::stod(wordsInLine[i]);}
106 catch (std::exception& e)
107 {throw BDSException(functionName, "Error on line> " + std::to_string(lineNo) + "> cannot convert to number");}
108 (values[i]) = coord * unit;
109 }
110
111 result->emplace_back(G4TwoVector(values[0], values[1]));
112
113 lineNo += 1;
114 }
115
116 file.close();
117
118 G4cout << functionName << "loaded " << result->size() << " points" << G4endl;
119
120 if (result->size() < 3)
121 {throw BDSException(functionName, "require at least 3 points to make an enclosed volume");}
122
123 return result;
124}
125
126std::vector<G4TwoVector>* BDS::LoadAperturePoints(const G4String& fileName,
127 const G4String& unit)
128{
129 G4String functionName = "BDS::LoadAperturePoints>"; // namespaced functions don't print so well
130
131 G4double unitAsNumber = 1.0;
132 if (!unit.empty())
133 {
134#if G4VERSION_NUMBER > 1029
135 if (!G4UnitDefinition::IsUnitDefined(unit))
136 {throw BDSException(functionName, "no such unit \"" + unit + "\"");}
137 else
138 {unitAsNumber = G4UnitDefinition::GetValueOf(unit);}
139#else
140 G4String unitLower = BDS::LowerCase(unit);
141 if (unitLower == "mm")
142 {unitAsNumber = 1.0;}
143 else if (unitLower == "cm")
144 {unitAsNumber = 10;}
145 else if (unitLower == "m")
146 {unitAsNumber = 1000;}
147 else
148 {throw BDSException(functionName, "Unknown unit \"" + unit + "\" (for this version of Geant4/BDSIM) - use one of (mm, cm, m)");}
149#endif
150 }
151
152 auto cachedResult = BDSAperturePointsCache::Instance()->FindCachedFile(fileName+unit); // can return nullptr
153 if (cachedResult)
154 {return cachedResult;}
155
156 G4String fullFilePath = BDS::GetFullPath(fileName);
157 if (!BDS::FileExists(fullFilePath))
158 {throw BDSException(functionName, "no such file: \"" + fullFilePath + "\"");}
159
160 std::vector<G4TwoVector>* result;
161 if (fullFilePath.rfind("gz") != std::string::npos)
162 {
163#ifdef USE_GZSTREAM
165 result = loader.Load(fullFilePath, unitAsNumber);
166#else
167 throw BDSException(functionName, "Compressed file loading - but BDSIM not compiled with ZLIB.");
168#endif
169 }
170 else
171 {
173 result = loader.Load(fullFilePath, unitAsNumber);
174 }
175
176 BDSAperturePointsCache::Instance()->CacheFile(fileName+unit, result);
177
178 return result;
179}
180
181
183{
184 if (!instance)
185 {instance = new BDSAperturePointsCache();}
186 return instance;
187}
188
189BDSAperturePointsCache::~BDSAperturePointsCache()
190{
192}
193
195{
196 for (auto& v : cachedFiles)
197 {delete v.second;}
198 cachedFiles.clear();
199}
200
201std::vector<G4TwoVector>* BDSAperturePointsCache::FindCachedFile(const G4String& fileNameAndUnits) const
202{
203 std::vector<G4TwoVector>* result = nullptr;
204 auto search = cachedFiles.find(fileNameAndUnits);
205 if (search != cachedFiles.end())
206 {return search->second;}
207 else
208 {return result;}
209}
210
211void BDSAperturePointsCache::CacheFile(const G4String& fileNameAndUnits,
212 std::vector<G4TwoVector>* contents)
213{
214 auto search = cachedFiles.find(fileNameAndUnits);
215 if (search != cachedFiles.end())
216 {
217 if (contents != search->second)
218 {throw BDSException(__METHOD_NAME__, "overwriting cache of aperture points with different contents for file name: "+fileNameAndUnits);}
219 return;
220 }
221 else
222 {cachedFiles[fileNameAndUnits] = contents;}
223}
224
225
227
228#ifdef USE_GZSTREAM
230#endif
A holder for loaded aperture points files.
void CacheFile(const G4String &fileNameAndUnits, std::vector< G4TwoVector > *contents)
Add an entry to the cache.
static BDSAperturePointsCache * Instance()
Access the singleton instance.
void ClearCachedFiles()
Delete all cached points from memory and clear the map of files loaded.
std::vector< G4TwoVector > * FindCachedFile(const G4String &fileNameAndUnits) const
Retrieve a cached files. Will return nullptr if not found.
A loader for up to set of XY points for an aperture.
std::vector< G4TwoVector > * Load(const G4String &fileName, G4double unit=1.0) const
General exception with possible name of object and message.
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.
std::vector< G4TwoVector > * LoadAperturePoints(const G4String &fileName, const G4String &unit="")
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'.