OPAL (Object Oriented Parallel Accelerator Library) 2022.1
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 <map>
24#include <limits>
25#include <iostream>
26#include <fstream>
27#include <tuple>
28
29#include "Algorithms/IndexMap.h"
32#include "AbsBeamline/Bend2D.h"
33#include "Physics/Physics.h"
35#include "Utilities/Util.h"
36
37extern Inform *gmsg;
38
39const double IndexMap::oneMinusEpsilon_m = 1.0 - std::numeric_limits<double>::epsilon();
40namespace {
41 void insertFlags(std::vector<double> &flags, std::shared_ptr<Component> element);
42}
43
45 mapRange2Element_m(),
46 mapElement2Range_m(),
47 totalPathLength_m(0.0)
48{ }
49
50void IndexMap::print(std::ostream &out) const {
51 if (mapRange2Element_m.empty()) return;
52
53 out << "* Size of map " << mapRange2Element_m.size() << " sections " << std::endl;
54 out << std::fixed << std::setprecision(6);
55 auto mapIti = mapRange2Element_m.begin();
56 auto mapItf = mapRange2Element_m.end();
57
58 double totalLength = (*mapRange2Element_m.rbegin()).first.end;
59 unsigned int numDigits = std::floor(std::max(0.0, log(totalLength) / log(10.0))) + 1;
60
61 for (; mapIti != mapItf; mapIti++) {
62 const key_t key = (*mapIti).first;
63 const value_t val = (*mapIti).second;
64 out << "* Key: ("
65 << std::setw(numDigits + 7) << std::right << key.begin
66 << " - "
67 << std::setw(numDigits + 7) << std::right << key.end
68 << ") number of overlapping elements " << val.size() << "\n";
69
70 for (auto element: val) {
71 out << "* " << std::setw(25 + 2 * numDigits) << " " << element->getName() << "\n";
72 }
73 }
74}
75
77 const double lowerLimit = s - ds;//(ds < s? s - ds: 0);
78 const double upperLimit = std::min(totalPathLength_m, s + ds);
79 value_t elementSet;
80
81 map_t::reverse_iterator rit = mapRange2Element_m.rbegin();
82 if (rit != mapRange2Element_m.rend() && lowerLimit > (*rit).first.end) {
83 throw OutOfBounds("IndexMap::query", "out of bounds");
84 }
85
88
89 for (; it != end; ++ it) {
90 const double low = (*it).first.begin;
91 const double high = (*it).first.end;
92
93 if (lowerLimit < high && upperLimit >= low) break;
94 }
95
96 if (it == end) return elementSet;
97
98 map_t::iterator last = std::next(it);
99 for (; last != end; ++ last) {
100 const double low = (*last).first.begin;
101
102 if (upperLimit < low) break;
103 }
104
105 for (; it != last; ++ it) {
106 const value_t &a = (*it).second;
107 elementSet.insert(a.cbegin(), a.cend());
108 }
109
110 return elementSet;
111}
112
113void IndexMap::add(key_t::first_type initialS, key_t::second_type finalS, const value_t &val) {
114 if (initialS > finalS) {
115 std::swap(initialS, finalS);
116 }
117 key_t key{initialS, finalS * oneMinusEpsilon_m};
118
119 mapRange2Element_m.insert(std::pair<key_t, value_t>(key, val));
120 totalPathLength_m = (*mapRange2Element_m.rbegin()).first.end;
121
122 value_t::iterator setIt = val.begin();
123 const value_t::iterator setEnd = val.end();
124
125 for (; setIt != setEnd; ++ setIt) {
126 if (mapElement2Range_m.find(*setIt) == mapElement2Range_m.end()) {
127 mapElement2Range_m.insert(std::make_pair(*setIt, key));
128 } else {
129 auto itpair = mapElement2Range_m.equal_range(*setIt);
130
131 bool extendedExisting = false;
132 for (auto it = itpair.first; it != itpair.second; ++ it) {
133 key_t &currentRange = it->second;
134
135 if (almostEqual(key.begin, currentRange.end / oneMinusEpsilon_m)) {
136 currentRange.end = key.end;
137 extendedExisting = true;
138 break;
139 }
140 }
141 if (!extendedExisting) {
142 mapElement2Range_m.insert(std::make_pair(*setIt, key));
143 }
144 }
145 }
146}
147
148void IndexMap::tidyUp(double zstop) {
149 map_t::reverse_iterator rit = mapRange2Element_m.rbegin();
150
151 if (rit != mapRange2Element_m.rend() &&
152 (*rit).second.empty() &&
153 zstop > (*rit).first.begin) {
154
155 key_t key{(*rit).first.begin, zstop};
156 value_t val;
157
158 mapRange2Element_m.erase(std::next(rit).base());
159 mapRange2Element_m.insert(std::pair<key_t, value_t>(key, val));
160 }
161}
162
174 SIZE
176
177void IndexMap::saveSDDS(double initialPathLength) const {
178 if (mapRange2Element_m.empty()) return;
179
180 std::vector<std::tuple<double, std::vector<double>, std::string> > sectors;
181
182 // add for each sector four rows:
183 // (s_i, 0)
184 // (s_i, 1)
185 // (s_f, 1)
186 // (s_f, 0)
187 // to the file, where
188 // s_i is the start of the range and
189 // s_f is the end of the range.
190 auto mapIti = mapRange2Element_m.begin();
191 auto mapItf = mapRange2Element_m.end();
192 for (; mapIti != mapItf; mapIti++) {
193 const auto &sectorElements = (*mapIti).second;
194 if (sectorElements.empty())
195 continue;
196
197 const auto &sectorRange = (*mapIti).first;
198
199 double sectorBegin = sectorRange.begin;
200 double sectorEnd = sectorRange.end;
201
202 std::vector<std::tuple<double, std::vector<double>, std::string> > currentSector(4);
203 std::get<0>(currentSector[0]) = sectorBegin;
204 std::get<0>(currentSector[1]) = sectorBegin;
205 std::get<0>(currentSector[2]) = sectorEnd;
206 std::get<0>(currentSector[3]) = sectorEnd;
207
208 for (unsigned short i = 0; i < 4; ++ i) {
209 auto &flags = std::get<1>(currentSector[i]);
210 flags.resize(SIZE, 0);
211 }
212
213 for (auto element: sectorElements) {
214 auto elementPassages = mapElement2Range_m.equal_range(element);
215 auto passage = elementPassages.first;
216 auto end = elementPassages.second;
217 for (; passage != end; ++ passage) {
218 const auto &elementRange = (*passage).second;
219 double elementBegin = elementRange.begin;
220 double elementEnd = elementRange.end;
221
222 if (elementBegin <= sectorBegin &&
223 elementEnd >= sectorEnd) {
224 break;
225 }
226 }
227
228 const auto &elementRange = (*passage).second;
229 if (elementRange.begin < sectorBegin) {
230 ::insertFlags(std::get<1>(currentSector[0]), element);
231 std::get<2>(currentSector[0]) += element->getName() + ", ";
232 }
233
234 ::insertFlags(std::get<1>(currentSector[1]), element);
235 std::get<2>(currentSector[1]) += element->getName() + ", ";
236
237 ::insertFlags(std::get<1>(currentSector[2]), element);
238 std::get<2>(currentSector[2]) += element->getName() + ", ";
239
240 if (elementRange.end > sectorEnd) {
241 ::insertFlags(std::get<1>(currentSector[3]), element);
242 std::get<2>(currentSector[3]) += element->getName() + ", ";
243 }
244 }
245
246 for (unsigned short i = 0; i < 4; ++ i) {
247 sectors.push_back(currentSector[i]);
248 }
249 }
250
251 // make the entries of the rf cavities a zigzag line
252 const unsigned int numEntries = sectors.size();
253 auto it = mapElement2Range_m.begin();
254 auto end = mapElement2Range_m.end();
255 for (; it != end; ++ it) {
256 auto element = (*it).first;
257 auto name = element->getName();
258 auto type = element->getType();
261 continue;
262 }
263
264 auto range = (*it).second;
265
266 unsigned int i = 0;
267 for (; i < numEntries; ++ i) {
268 if (std::get<0>(sectors[i]) >= range.begin) {
269 break;
270 }
271 }
272
273 if (i == numEntries) continue;
274
275 unsigned int j = ++ i;
276 while (std::get<0>(sectors[j]) < range.end) {
277 ++ j;
278 }
279
280 double length = range.end - range.begin;
281 for (; i <= j; ++ i) {
282 double pos = std::get<0>(sectors[i]);
283 auto &items = std::get<1>(sectors[i]);
284
285 items[RFCAVITY] = 1.0 - 2 * (pos - range.begin) / length;
286 }
287 }
288
289 // add row if range of first sector starts after initialPathLength
290 if (!sectors.empty() &&
291 std::get<0>(sectors[0]) > initialPathLength) {
292 auto tmp = sectors;
293 sectors = std::vector<std::tuple<double, std::vector<double>, std::string> >(1);
294 std::get<0>(sectors[0]) = initialPathLength;
295 std::get<1>(sectors[0]).resize(SIZE, 0.0);
296
297 sectors.insert(sectors.end(), tmp.begin(), tmp.end());
298 }
299
300 std::string fileName = Util::combineFilePath({
302 OpalData::getInstance()->getInputBasename() + "_ElementPositions.sdds"
303 });
304 ElementPositionWriter writer(fileName);
305
306 for (auto sector: sectors) {
307 std::string names = std::get<2>(sector);
308 if (!names.empty()) {
309 names = names.substr(0, names.length() - 2);
310 }
311 names = "\"" + names + "\"";
312 writer.addRow(std::get<0>(sector),
313 std::get<1>(sector),
314 names);
315 }
316}
317
318namespace {
319 void insertFlags(std::vector<double> &flags, std::shared_ptr<Component> element) {
320 switch (element->getType()) {
323 {
324 const Bend2D* bend = static_cast<const Bend2D*>(element.get());
325 if (bend->getRotationAboutZ() > 0.5 * Physics::pi &&
326 bend->getRotationAboutZ() < 1.5 * Physics::pi) {
327 flags[DIPOLE] = -1;
328 } else {
329 flags[DIPOLE] = 1;
330 }
331 }
332 break;
334 {
335 const Multipole* mult = static_cast<const Multipole*>(element.get());
336 switch(mult->getMaxNormalComponentIndex()) {
337 case 1:
338 flags[DIPOLE] = (mult->isFocusing(0)? 1: -1);
339 break;
340 case 2:
341 flags[QUADRUPOLE] = (mult->isFocusing(1)? 1: -1);
342 break;
343 case 3:
344 flags[SEXTUPOLE] = (mult->isFocusing(2)? 1: -1);
345 break;
346 case 4:
347 flags[OCTUPOLE] = (mult->isFocusing(3)? 1: -1);
348 break;
349 case 5:
350 flags[DECAPOLE] = (mult->isFocusing(4)? 1: -1);
351 break;
352 default:
353 flags[MULTIPOLE] = 1;
354 }
355 }
356 break;
358 flags[SOLENOID] = 1;
359 break;
362 flags[RFCAVITY] = 1;
363 break;
365 flags[MONITOR] = 1;
366 break;
367 default:
368 flags[OTHER] = 1;
369 break;
370 }
371
372 }
373}
374
376 double position) const {
377 double minDistance = std::numeric_limits<double>::max();
378 key_t range{0.0, 0.0};
379 const std::pair<invertedMap_t::const_iterator, invertedMap_t::const_iterator> its = mapElement2Range_m.equal_range(element);
380 if (std::distance(its.first, its.second) == 0)
381 throw OpalException("IndexMap::getRange()",
382 "Element \"" + element->getName() + "\" not registered");
383
384 for (invertedMap_t::const_iterator it = its.first; it != its.second; ++ it) {
385 double distance = std::min(std::abs((*it).second.begin - position),
386 std::abs((*it).second.end - position));
387 if (distance < minDistance) {
388 minDistance = distance;
389 range = (*it).second;
390 }
391 }
392
393 return range;
394}
395
397 map_t::const_iterator it = mapRange2Element_m.begin();
398 const map_t::const_iterator end = mapRange2Element_m.end();
399 value_t touchingElements;
400
401 for (; it != end; ++ it) {
402 if (almostEqual(it->first.begin, range.begin) ||
403 almostEqual(it->first.end, range.end))
404 touchingElements.insert((it->second).begin(), (it->second).end());
405 }
406
407 return touchingElements;
408}
409
410bool IndexMap::almostEqual(double x, double y) {
411 return (std::abs(x - y) < std::numeric_limits<double>::epsilon() * std::abs(x + y) * 2 ||
413}
PartBunchBase< T, Dim >::ConstIterator end(PartBunchBase< T, Dim > const &bunch)
Tps< T > log(const Tps< T > &x)
Natural logarithm.
Definition: TpsMath.h:182
T * value_type(const SliceIterator< T > &)
elements
Definition: IndexMap.cpp:163
@ OCTUPOLE
Definition: IndexMap.cpp:167
@ RFCAVITY
Definition: IndexMap.cpp:171
@ MULTIPOLE
Definition: IndexMap.cpp:169
@ DIPOLE
Definition: IndexMap.cpp:164
@ SIZE
Definition: IndexMap.cpp:174
@ SOLENOID
Definition: IndexMap.cpp:170
@ MONITOR
Definition: IndexMap.cpp:172
@ DECAPOLE
Definition: IndexMap.cpp:168
@ SEXTUPOLE
Definition: IndexMap.cpp:166
@ QUADRUPOLE
Definition: IndexMap.cpp:165
@ OTHER
Definition: IndexMap.cpp:173
Inform * gmsg
Definition: Main.cpp:61
T::PETE_Expr_t::PETE_Return_t max(const PETE_Expr< T > &expr, NDIndex< D > &loc)
Definition: ReductionLoc.h:84
T::PETE_Expr_t::PETE_Return_t min(const PETE_Expr< T > &expr, NDIndex< D > &loc)
Definition: ReductionLoc.h:76
PETE_TUTree< FnFloor, typename T::PETE_Expr_t > floor(const PETE_Expr< T > &l)
Definition: PETE.h:733
std::complex< double > a
PETE_TUTree< FnAbs, typename T::PETE_Expr_t > abs(const PETE_Expr< T > &l)
Inform & endl(Inform &inf)
Definition: Inform.cpp:42
const std::string name
constexpr double pi
The value of.
Definition: Physics.h:30
std::string::iterator iterator
Definition: MSLang.h:16
std::string combineFilePath(std::initializer_list< std::string > ilist)
Definition: Util.cpp:196
boost::function< boost::tuple< double, bool >(arguments_t)> type
Definition: function.hpp:21
std::string getInputBasename()
get input file name without extension
Definition: OpalData.cpp:669
static OpalData * getInstance()
Definition: OpalData.cpp:196
std::string getAuxiliaryOutputDirectory() const
get the name of the the additional data directory
Definition: OpalData.cpp:661
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:113
void tidyUp(double zstop)
Definition: IndexMap.cpp:148
std::set< std::shared_ptr< Component > > value_t
Definition: IndexMap.h:47
value_t getTouchingElements(const key_t &range) const
Definition: IndexMap.cpp:396
invertedMap_t mapElement2Range_m
Definition: IndexMap.h:97
key_t getRange(const IndexMap::value_t::value_type &element, double position) const
Definition: IndexMap.cpp:375
map_t mapRange2Element_m
Definition: IndexMap.h:96
IndexMap()
Definition: IndexMap.cpp:44
static bool almostEqual(double, double)
Definition: IndexMap.cpp:410
void saveSDDS(double startS) const
Definition: IndexMap.cpp:177
void print(std::ostream &) const
Definition: IndexMap.cpp:50
value_t query(key_t::first_type s, key_t::second_type ds)
Definition: IndexMap.cpp:76
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
Definition: Bend2D.h:51
double getRotationAboutZ() const
Definition: ElementBase.h:573
Interface for general multipole.
Definition: Multipole.h:47
size_t getMaxNormalComponentIndex() const
Definition: Multipole.h:157
bool isFocusing(unsigned int component) const
Definition: Multipole.cpp:357
The base class for all OPAL exceptions.
Definition: OpalException.h:28
Definition: Inform.h:42