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