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