OPALX (Object Oriented Parallel Accelerator Library for Exascal) master (dc2a29eed580)
OPALX
Loading...
Searching...
No Matches
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 <fstream>
24#include <iostream>
25#include <limits>
26#include <map>
27#include <tuple>
28
31#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
44 : mapRange2Element_m(),
45 mapElement2Range_m(),
46 referencePathModel_m(),
47 referencePathModelDirty_m(false),
48 totalPathLength_m(0.0) {}
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: (" << std::setw(numDigits + 7) << std::right << key.begin << " - "
65 << std::setw(numDigits + 7) << std::right << key.end
66 << ") number of overlapping elements " << val.size() << "\n";
67
68 for (auto element : val) {
69 out << "* " << std::setw(25 + 2 * numDigits) << " " << element->getName() << "\n";
70 }
71 }
72}
73
75 const double lowerLimit = s - ds; //(ds < s? s - ds: 0);
76 const double upperLimit = std::min(totalPathLength_m, s + ds);
77 value_t elementSet;
78
79 map_t::reverse_iterator rit = mapRange2Element_m.rbegin();
80 if (rit != mapRange2Element_m.rend() && lowerLimit > (*rit).first.end) {
81 throw OutOfBounds("IndexMap::query", "out of bounds");
82 }
83
84 map_t::iterator it = mapRange2Element_m.begin();
85 const map_t::iterator end = mapRange2Element_m.end();
86
87 for (; it != end; ++it) {
88 const double low = (*it).first.begin;
89 const double high = (*it).first.end;
90
91 if (lowerLimit < high && upperLimit >= low) break;
92 }
93
94 if (it == end) return elementSet;
95
96 map_t::iterator last = std::next(it);
97 for (; last != end; ++last) {
98 const double low = (*last).first.begin;
99
100 if (upperLimit < low) break;
101 }
102
103 for (; it != last; ++it) {
104 const value_t& a = (*it).second;
105 elementSet.insert(a.cbegin(), a.cend());
106 }
107
108 return elementSet;
109}
110
111void IndexMap::add(key_t::first_type initialS, key_t::second_type finalS, const value_t& val) {
112 if (initialS > finalS) {
113 std::swap(initialS, finalS);
114 }
115 key_t key{initialS, finalS * oneMinusEpsilon_m};
116
117 mapRange2Element_m.insert(std::pair<key_t, value_t>(key, val));
118 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() && (*rit).second.empty() && zstop > (*rit).first.begin) {
151 key_t key{(*rit).first.begin, zstop};
152 value_t val;
153
154 mapRange2Element_m.erase(std::next(rit).base());
155 mapRange2Element_m.insert(std::pair<key_t, value_t>(key, val));
157 }
158}
159
162 for (const auto& [range, elements] : mapRange2Element_m) {
164 }
166}
167
181
182void IndexMap::saveSDDS(double initialPathLength) const {
183 if (mapRange2Element_m.empty()) return;
184
185 std::vector<std::tuple<double, std::vector<double>, std::string> > sectors;
186
187 // add for each sector four rows:
188 // (s_i, 0)
189 // (s_i, 1)
190 // (s_f, 1)
191 // (s_f, 0)
192 // to the file, where
193 // s_i is the start of the range and
194 // s_f is the end of the range.
195 for (const auto& segment : getReferencePathModel().getSegments()) {
196 const auto& sectorElements = segment.getActiveElements();
197 if (sectorElements.empty()) continue;
198
199 double sectorBegin = segment.getBegin();
200 double sectorEnd = segment.getEnd();
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 && 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 && type != ElementType::TRAVELINGWAVE) {
259 continue;
260 }
261
262 auto range = (*it).second;
263
264 unsigned int i = 0;
265 for (; i < numEntries; ++i) {
266 if (std::get<0>(sectors[i]) >= range.begin) {
267 break;
268 }
269 }
270
271 if (i == numEntries) continue;
272
273 unsigned int j = ++i;
274 while (std::get<0>(sectors[j]) < range.end) {
275 ++j;
276 }
277
278 double length = range.end - range.begin;
279 for (; i <= j; ++i) {
280 double pos = std::get<0>(sectors[i]);
281 auto& items = std::get<1>(sectors[i]);
282
283 items[RFCAVITY] = 1.0 - 2 * (pos - range.begin) / length;
284 }
285 }
286
287 // add row if range of first sector starts after initialPathLength
288 if (!sectors.empty() && std::get<0>(sectors[0]) > initialPathLength) {
289 auto tmp = sectors;
290 sectors = std::vector<std::tuple<double, std::vector<double>, std::string> >(1);
291 std::get<0>(sectors[0]) = initialPathLength;
292 std::get<1>(sectors[0]).resize(SIZE, 0.0);
293
294 sectors.insert(sectors.end(), tmp.begin(), tmp.end());
295 }
296
297 std::string fileName = Util::combineFilePath(
299 OpalData::getInstance()->getInputBasename() + "_ElementPositions.sdds"});
300 ElementPositionWriter writer(fileName);
301
302 for (auto sector : sectors) {
303 std::string names = std::get<2>(sector);
304 if (!names.empty()) {
305 names = names.substr(0, names.length() - 2);
306 }
307 names = "\"" + names + "\"";
308 writer.addRow(std::get<0>(sector), std::get<1>(sector), names);
309 }
310}
311
312namespace {
313 void insertFlags(std::vector<double>& flags, std::shared_ptr<Component> element) {
314 switch (element->getType()) {
316 const Multipole* mult = static_cast<const Multipole*>(element.get());
317 switch (mult->getMaxNormalComponentIndex()) {
318 case 1:
319 flags[DIPOLE] = (mult->isFocusing(0) ? 1 : -1);
320 break;
321 case 2:
322 flags[QUADRUPOLE] = (mult->isFocusing(1) ? 1 : -1);
323 break;
324 case 3:
325 flags[SEXTUPOLE] = (mult->isFocusing(2) ? 1 : -1);
326 break;
327 case 4:
328 flags[OCTUPOLE] = (mult->isFocusing(3) ? 1 : -1);
329 break;
330 case 5:
331 flags[DECAPOLE] = (mult->isFocusing(4) ? 1 : -1);
332 break;
333 default:
334 flags[MULTIPOLE] = 1;
335 }
336 } break;
339 flags[RFCAVITY] = 1;
340 break;
342 flags[SOLENOID] = 1;
343 break;
345 flags[OTHER] = 1;
346 break;
347 default:
348 flags[OTHER] = 1;
349 break;
350 }
351 }
352} // namespace
353
355 const IndexMap::value_t::value_type& element, double position) const {
356 double minDistance = std::numeric_limits<double>::max();
357 key_t range{0.0, 0.0};
358 const std::pair<invertedMap_t::const_iterator, invertedMap_t::const_iterator> its =
359 mapElement2Range_m.equal_range(element);
360 if (std::distance(its.first, its.second) == 0)
361 throw OpalException(
362 "IndexMap::getRange()", "Element \"" + element->getName() + "\" not registered");
363
364 for (invertedMap_t::const_iterator it = its.first; it != its.second; ++it) {
365 double distance = std::min(
366 std::abs((*it).second.begin - position), std::abs((*it).second.end - position));
367 if (distance < minDistance) {
368 minDistance = distance;
369 range = (*it).second;
370 }
371 }
372
373 return range;
374}
375
377 map_t::const_iterator it = mapRange2Element_m.begin();
378 const map_t::const_iterator end = mapRange2Element_m.end();
379 value_t touchingElements;
380
381 for (; it != end; ++it) {
382 if (almostEqual(it->first.begin, range.begin) || almostEqual(it->first.end, range.end))
383 touchingElements.insert((it->second).begin(), (it->second).end());
384 }
385
386 return touchingElements;
387}
388
389bool IndexMap::almostEqual(double x, double y) {
390 return (std::abs(x - y) < std::numeric_limits<double>::epsilon() * std::abs(x + y) * 2
391 || std::abs(x - y) < std::numeric_limits<double>::min());
392}
@ CONSTANTEFIELDCAVITY
elements
Definition IndexMap.cpp:168
@ OCTUPOLE
Definition IndexMap.cpp:172
@ RFCAVITY
Definition IndexMap.cpp:176
@ MULTIPOLE
Definition IndexMap.cpp:174
@ DIPOLE
Definition IndexMap.cpp:169
@ SIZE
Definition IndexMap.cpp:179
@ SOLENOID
Definition IndexMap.cpp:175
@ MONITOR
Definition IndexMap.cpp:177
@ DECAPOLE
Definition IndexMap.cpp:173
@ SEXTUPOLE
Definition IndexMap.cpp:171
@ QUADRUPOLE
Definition IndexMap.cpp:170
@ OTHER
Definition IndexMap.cpp:178
Inform * gmsg
Definition changes.cpp:7
static const double oneMinusEpsilon_m
Definition IndexMap.h:102
double totalPathLength_m
Definition IndexMap.h:98
first_type begin
Definition IndexMap.h:42
bool referencePathModelDirty_m
Definition IndexMap.h:96
void add(key_t::first_type initialStep, key_t::second_type finalStep, const value_t &val)
Definition IndexMap.cpp:111
void tidyUp(double zstop)
Definition IndexMap.cpp:147
ReferencePathModel referencePathModel_m
Definition IndexMap.h:95
std::set< std::shared_ptr< Component > > value_t
Definition IndexMap.h:46
value_t getTouchingElements(const key_t &range) const
Definition IndexMap.cpp:376
void rebuildReferencePathModel() const
Definition IndexMap.cpp:160
invertedMap_t mapElement2Range_m
Definition IndexMap.h:94
key_t getRange(const IndexMap::value_t::value_type &element, double position) const
Definition IndexMap.cpp:354
map_t mapRange2Element_m
Definition IndexMap.h:93
double first_type
Definition IndexMap.h:40
const ReferencePathModel & getReferencePathModel() const
Definition IndexMap.h:107
second_type end
Definition IndexMap.h:43
double second_type
Definition IndexMap.h:41
static bool almostEqual(double, double)
Definition IndexMap.cpp:389
void saveSDDS(double startS) const
Definition IndexMap.cpp:182
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:74
Interface for general multipole.
Definition Multipole.h:30
size_t getMaxNormalComponentIndex() const
Definition Multipole.h:219
bool isFocusing(int n) const
std::string getInputBasename()
get input file name without extension
Definition OpalData.cpp:571
static OpalData * getInstance()
Definition OpalData.cpp:193
std::string getAuxiliaryOutputDirectory() const
get the name of the the additional data directory
Definition OpalData.cpp:567
const container_type & getSegments() const
void addSegment(const ReferencePathSegment &segment)
Reference-coordinate interval with optional legacy ELEMEDGE anchor.
std::string combineFilePath(std::initializer_list< std::string > ilist)
Definition Util.cpp:193