OPAL (Object Oriented Parallel Accelerator Library) 2024.2
OPAL
IndexMap.cpp
Go to the documentation of this file.
1//
2// Class IndexMap
3//
4// This class stores and prints the sequence of elements that the referenc particle passes.
5// Each time the reference particle enters or leaves an element an entry is added to the map.
6// With help of this map one can determine which element can be found at a given position.
7//
8// Copyright (c) 2016, Christof Metzger-Kraus, Helmholtz-Zentrum Berlin, Germany
9// 2017 - 2020 Christof Metzger-Kraus
10//
11// All rights reserved
12//
13// This file is part of OPAL.
14//
15// OPAL is free software: you can redistribute it and/or modify
16// it under the terms of the GNU General Public License as published by
17// the Free Software Foundation, either version 3 of the License, or
18// (at your option) any later version.
19//
20// You should have received a copy of the GNU General Public License
21// along with OPAL. If not, see <https://www.gnu.org/licenses/>.
22//
23#include <algorithm>
24#include <cmath>
25#include <iomanip>
26#include <iostream>
27#include <limits>
28#include <map>
29#include <memory>
30#include <tuple>
31#include <vector>
32
33#include "Algorithms/IndexMap.h"
36#include "AbsBeamline/Bend2D.h"
37#include "Physics/Physics.h"
39#include "Utilities/Util.h"
40
41extern Inform *gmsg;
42
43const double IndexMap::oneMinusEpsilon_m = 1.0 - std::numeric_limits<double>::epsilon();
44namespace {
45 void insertFlags(std::vector<double> &flags, std::shared_ptr<Component> element);
46}
47
49 mapRange2Element_m(),
50 mapElement2Range_m(),
51 totalPathLength_m(0.0)
52{ }
53
54void IndexMap::print(std::ostream &out) const {
55 if (mapRange2Element_m.empty()) return;
56
57 out << "* Size of map " << mapRange2Element_m.size() << " sections " << std::endl;
58 out << std::fixed << std::setprecision(6);
59 auto mapIti = mapRange2Element_m.begin();
60 auto mapItf = mapRange2Element_m.end();
61
62 double totalLength = (*mapRange2Element_m.rbegin()).first.end;
63 unsigned int numDigits = std::floor(std::max(0.0, std::log(totalLength) / std::log(10.0))) + 1;
64
65 for (; mapIti != mapItf; mapIti++) {
66 const key_t key = (*mapIti).first;
67 const value_t val = (*mapIti).second;
68 out << "* Key: ("
69 << std::setw(numDigits + 7) << std::right << key.begin
70 << " - "
71 << std::setw(numDigits + 7) << std::right << key.end
72 << ") number of overlapping elements " << val.size() << "\n";
73
74 for (auto element: val) {
75 out << "* " << std::setw(25 + 2 * numDigits) << " " << element->getName() << "\n";
76 }
77 }
78}
79
81 const double lowerLimit = s - ds;//(ds < s? s - ds: 0);
82 const double upperLimit = std::min(totalPathLength_m, s + ds);
83 value_t elementSet;
84
85 map_t::reverse_iterator rit = mapRange2Element_m.rbegin();
86 if (rit != mapRange2Element_m.rend() && lowerLimit > (*rit).first.end) {
87 throw OutOfBounds("IndexMap::query", "out of bounds");
88 }
89
90 map_t::iterator it = mapRange2Element_m.begin();
91 const map_t::iterator end = mapRange2Element_m.end();
92
93 for (; it != end; ++ it) {
94 const double low = (*it).first.begin;
95 const double high = (*it).first.end;
96
97 if (lowerLimit < high && upperLimit >= low) break;
98 }
99
100 if (it == end) return elementSet;
101
102 map_t::iterator last = std::next(it);
103 for (; last != end; ++ last) {
104 const double low = (*last).first.begin;
105
106 if (upperLimit < low) break;
107 }
108
109 for (; it != last; ++ it) {
110 const value_t &a = (*it).second;
111 elementSet.insert(a.cbegin(), a.cend());
112 }
113
114 return elementSet;
115}
116
117void IndexMap::add(key_t::first_type initialS, key_t::second_type finalS, const value_t &val) {
118 if (initialS > finalS) {
119 std::swap(initialS, finalS);
120 }
121 key_t key{initialS, finalS * oneMinusEpsilon_m};
122
123 mapRange2Element_m.insert(std::pair<key_t, value_t>(key, val));
124 totalPathLength_m = (*mapRange2Element_m.rbegin()).first.end;
125
126 value_t::iterator setIt = val.begin();
127 const value_t::iterator setEnd = val.end();
128
129 for (; setIt != setEnd; ++ setIt) {
130 if (mapElement2Range_m.find(*setIt) == mapElement2Range_m.end()) {
131 mapElement2Range_m.insert(std::make_pair(*setIt, key));
132 } else {
133 auto itpair = mapElement2Range_m.equal_range(*setIt);
134
135 bool extendedExisting = false;
136 for (auto it = itpair.first; it != itpair.second; ++ it) {
137 key_t &currentRange = it->second;
138
139 if (almostEqual(key.begin, currentRange.end / oneMinusEpsilon_m)) {
140 currentRange.end = key.end;
141 extendedExisting = true;
142 break;
143 }
144 }
145 if (!extendedExisting) {
146 mapElement2Range_m.insert(std::make_pair(*setIt, key));
147 }
148 }
149 }
150}
151
152void IndexMap::tidyUp(double zstop) {
153 map_t::reverse_iterator rit = mapRange2Element_m.rbegin();
154
155 if (rit != mapRange2Element_m.rend() &&
156 (*rit).second.empty() &&
157 zstop > (*rit).first.begin) {
158
159 key_t key{(*rit).first.begin, zstop};
160 value_t val;
161
162 mapRange2Element_m.erase(std::next(rit).base());
163 mapRange2Element_m.insert(std::pair<key_t, value_t>(key, val));
164 }
165}
166
180
181void IndexMap::saveSDDS(double initialPathLength) const {
182 if (mapRange2Element_m.empty()) return;
183
184 std::vector<std::tuple<double, std::vector<double>, std::string> > sectors;
185
186 // add for each sector four rows:
187 // (s_i, 0)
188 // (s_i, 1)
189 // (s_f, 1)
190 // (s_f, 0)
191 // to the file, where
192 // s_i is the start of the range and
193 // s_f is the end of the range.
194 auto mapIti = mapRange2Element_m.begin();
195 auto mapItf = mapRange2Element_m.end();
196 for (; mapIti != mapItf; mapIti++) {
197 const auto &sectorElements = (*mapIti).second;
198 if (sectorElements.empty())
199 continue;
200
201 const auto &sectorRange = (*mapIti).first;
202
203 double sectorBegin = sectorRange.begin;
204 double sectorEnd = sectorRange.end;
205
206 std::vector<std::tuple<double, std::vector<double>, std::string> > currentSector(4);
207 std::get<0>(currentSector[0]) = sectorBegin;
208 std::get<0>(currentSector[1]) = sectorBegin;
209 std::get<0>(currentSector[2]) = sectorEnd;
210 std::get<0>(currentSector[3]) = sectorEnd;
211
212 for (unsigned short i = 0; i < 4; ++ i) {
213 auto &flags = std::get<1>(currentSector[i]);
214 flags.resize(SIZE, 0);
215 }
216
217 for (auto element: sectorElements) {
218 auto elementPassages = mapElement2Range_m.equal_range(element);
219 auto passage = elementPassages.first;
220 auto end = elementPassages.second;
221 for (; passage != end; ++ passage) {
222 const auto &elementRange = (*passage).second;
223 double elementBegin = elementRange.begin;
224 double elementEnd = elementRange.end;
225
226 if (elementBegin <= sectorBegin &&
227 elementEnd >= sectorEnd) {
228 break;
229 }
230 }
231
232 const auto &elementRange = (*passage).second;
233 if (elementRange.begin < sectorBegin) {
234 ::insertFlags(std::get<1>(currentSector[0]), element);
235 std::get<2>(currentSector[0]) += element->getName() + ", ";
236 }
237
238 ::insertFlags(std::get<1>(currentSector[1]), element);
239 std::get<2>(currentSector[1]) += element->getName() + ", ";
240
241 ::insertFlags(std::get<1>(currentSector[2]), element);
242 std::get<2>(currentSector[2]) += element->getName() + ", ";
243
244 if (elementRange.end > sectorEnd) {
245 ::insertFlags(std::get<1>(currentSector[3]), element);
246 std::get<2>(currentSector[3]) += element->getName() + ", ";
247 }
248 }
249
250 for (unsigned short i = 0; i < 4; ++ i) {
251 sectors.push_back(currentSector[i]);
252 }
253 }
254
255 // make the entries of the rf cavities a zigzag line
256 const unsigned int numEntries = sectors.size();
257 auto it = mapElement2Range_m.begin();
258 auto end = mapElement2Range_m.end();
259 for (; it != end; ++ it) {
260 auto element = (*it).first;
261 auto name = element->getName();
262 auto type = element->getType();
263 if (type != ElementType::RFCAVITY &&
265 continue;
266 }
267
268 auto range = (*it).second;
269
270 unsigned int i = 0;
271 for (; i < numEntries; ++ i) {
272 if (std::get<0>(sectors[i]) >= range.begin) {
273 break;
274 }
275 }
276
277 if (i == numEntries) continue;
278
279 unsigned int j = ++ i;
280 while (std::get<0>(sectors[j]) < range.end) {
281 ++ j;
282 }
283
284 double length = range.end - range.begin;
285 for (; i <= j; ++ i) {
286 double pos = std::get<0>(sectors[i]);
287 auto &items = std::get<1>(sectors[i]);
288
289 items[RFCAVITY] = 1.0 - 2 * (pos - range.begin) / length;
290 }
291 }
292
293 // add row if range of first sector starts after initialPathLength
294 if (!sectors.empty() &&
295 std::get<0>(sectors[0]) > initialPathLength) {
296 auto tmp = sectors;
297 sectors = std::vector<std::tuple<double, std::vector<double>, std::string> >(1);
298 std::get<0>(sectors[0]) = initialPathLength;
299 std::get<1>(sectors[0]).resize(SIZE, 0.0);
300
301 sectors.insert(sectors.end(), tmp.begin(), tmp.end());
302 }
303
304 std::string fileName = Util::combineFilePath({
306 OpalData::getInstance()->getInputBasename() + "_ElementPositions.sdds"
307 });
308 ElementPositionWriter writer(fileName);
309
310 for (auto sector: sectors) {
311 std::string names = std::get<2>(sector);
312 if (!names.empty()) {
313 names = names.substr(0, names.length() - 2);
314 }
315 names = "\"" + names + "\"";
316 writer.addRow(std::get<0>(sector),
317 std::get<1>(sector),
318 names);
319 }
320}
321
322namespace {
323 void insertFlags(std::vector<double> &flags, std::shared_ptr<Component> element) {
324 switch (element->getType()) {
327 {
328 const Bend2D* bend = static_cast<const Bend2D*>(element.get());
329 if (bend->getRotationAboutZ() > 0.5 * Physics::pi &&
330 bend->getRotationAboutZ() < 1.5 * Physics::pi) {
331 flags[DIPOLE] = -1;
332 } else {
333 flags[DIPOLE] = 1;
334 }
335 }
336 break;
338 {
339 const Multipole* mult = static_cast<const Multipole*>(element.get());
340 switch(mult->getMaxNormalComponentIndex()) {
341 case 1:
342 flags[DIPOLE] = (mult->isFocusing(0)? 1: -1);
343 break;
344 case 2:
345 flags[QUADRUPOLE] = (mult->isFocusing(1)? 1: -1);
346 break;
347 case 3:
348 flags[SEXTUPOLE] = (mult->isFocusing(2)? 1: -1);
349 break;
350 case 4:
351 flags[OCTUPOLE] = (mult->isFocusing(3)? 1: -1);
352 break;
353 case 5:
354 flags[DECAPOLE] = (mult->isFocusing(4)? 1: -1);
355 break;
356 default:
357 flags[MULTIPOLE] = 1;
358 }
359 }
360 break;
362 flags[SOLENOID] = 1;
363 break;
366 flags[RFCAVITY] = 1;
367 break;
369 flags[MONITOR] = 1;
370 break;
371 default:
372 flags[OTHER] = 1;
373 break;
374 }
375
376 }
377}
378
379IndexMap::key_t IndexMap::getRange(const IndexMap::value_t::value_type &element,
380 double position) const {
381 double minDistance = std::numeric_limits<double>::max();
382 key_t range{0.0, 0.0};
383 const std::pair<invertedMap_t::const_iterator, invertedMap_t::const_iterator> its = mapElement2Range_m.equal_range(element);
384 if (std::distance(its.first, its.second) == 0)
385 throw OpalException("IndexMap::getRange()",
386 "Element \"" + element->getName() + "\" not registered");
387
388 for (invertedMap_t::const_iterator it = its.first; it != its.second; ++ it) {
389 double distance = std::min(std::abs((*it).second.begin - position),
390 std::abs((*it).second.end - position));
391 if (distance < minDistance) {
392 minDistance = distance;
393 range = (*it).second;
394 }
395 }
396
397 return range;
398}
399
401 map_t::const_iterator it = mapRange2Element_m.begin();
402 const map_t::const_iterator end = mapRange2Element_m.end();
403 value_t touchingElements;
404
405 for (; it != end; ++ it) {
406 if (almostEqual(it->first.begin, range.begin) ||
407 almostEqual(it->first.end, range.end))
408 touchingElements.insert((it->second).begin(), (it->second).end());
409 }
410
411 return touchingElements;
412}
413
414bool IndexMap::almostEqual(double x, double y) {
415 return (std::abs(x - y) < std::numeric_limits<double>::epsilon() * std::abs(x + y) * 2 ||
416 std::abs(x - y) < std::numeric_limits<double>::min());
417}
PartBunchBase< T, Dim >::ConstIterator end(PartBunchBase< T, Dim > const &bunch)
elements
Definition IndexMap.cpp:167
@ OCTUPOLE
Definition IndexMap.cpp:171
@ RFCAVITY
Definition IndexMap.cpp:175
@ MULTIPOLE
Definition IndexMap.cpp:173
@ DIPOLE
Definition IndexMap.cpp:168
@ SIZE
Definition IndexMap.cpp:178
@ SOLENOID
Definition IndexMap.cpp:174
@ MONITOR
Definition IndexMap.cpp:176
@ DECAPOLE
Definition IndexMap.cpp:172
@ SEXTUPOLE
Definition IndexMap.cpp:170
@ QUADRUPOLE
Definition IndexMap.cpp:169
@ OTHER
Definition IndexMap.cpp:177
Inform * gmsg
Definition Main.cpp:69
std::complex< double > a
const std::string name
constexpr double pi
The value of.
Definition Physics.h:30
std::string combineFilePath(std::initializer_list< std::string > ilist)
Definition Util.cpp:204
std::string getInputBasename()
get input file name without extension
Definition OpalData.cpp:674
static OpalData * getInstance()
Definition OpalData.cpp:196
std::string getAuxiliaryOutputDirectory() const
get the name of the the additional data directory
Definition OpalData.cpp:666
static const double oneMinusEpsilon_m
Definition IndexMap.h:102
double totalPathLength_m
Definition IndexMap.h:99
void add(key_t::first_type initialStep, key_t::second_type finalStep, const value_t &val)
Definition IndexMap.cpp:117
void tidyUp(double zstop)
Definition IndexMap.cpp:152
std::set< std::shared_ptr< Component > > value_t
Definition IndexMap.h:47
value_t getTouchingElements(const key_t &range) const
Definition IndexMap.cpp:400
invertedMap_t mapElement2Range_m
Definition IndexMap.h:97
key_t getRange(const IndexMap::value_t::value_type &element, double position) const
Definition IndexMap.cpp:379
map_t mapRange2Element_m
Definition IndexMap.h:96
static bool almostEqual(double, double)
Definition IndexMap.cpp:414
void saveSDDS(double startS) const
Definition IndexMap.cpp:181
void print(std::ostream &) const
Definition IndexMap.cpp:54
value_t query(key_t::first_type s, key_t::second_type ds)
Definition IndexMap.cpp:80
first_type begin
Definition IndexMap.h:43
double first_type
Definition IndexMap.h:41
second_type end
Definition IndexMap.h:44
double second_type
Definition IndexMap.h:42
double getRotationAboutZ() const
Interface for general multipole.
Definition Multipole.h:47
size_t getMaxNormalComponentIndex() const
Definition Multipole.h:157
bool isFocusing(unsigned int component) const
The base class for all OPAL exceptions.