OPAL (Object Oriented Parallel Accelerator Library)  2021.1.99
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"
31 #include "AbsBeamline/Multipole.h"
32 #include "AbsBeamline/Bend2D.h"
33 #include "Physics/Physics.h"
35 #include "Utilities/Util.h"
36 
37 extern Inform *gmsg;
38 
39 const double IndexMap::oneMinusEpsilon_m = 1.0 - std::numeric_limits<double>::epsilon();
40 namespace {
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 
50 void IndexMap::print(std::ostream &out) const {
51  if (mapRange2Element_m.size() == 0) 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 
113 void 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 
148 void IndexMap::tidyUp(double zstop) {
149  map_t::reverse_iterator rit = mapRange2Element_m.rbegin();
150 
151  if (rit != mapRange2Element_m.rend() &&
152  (*rit).second.size() == 0 &&
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 
163 enum elements {
164  DIPOLE = 0,
174  SIZE
175 };
176 
177 void IndexMap::saveSDDS(double initialPathLength) const {
178  if (mapRange2Element_m.size() == 0) 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.size() == 0)
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();
259  if (type != ElementBase::RFCAVITY &&
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.size() > 0 &&
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 != "") {
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 
318 namespace {
319  void insertFlags(std::vector<double> &flags, std::shared_ptr<Component> element) {
320  switch (element->getType()) {
321  case ElementBase::RBEND:
322  case ElementBase::SBEND:
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 
410 bool IndexMap::almostEqual(double x, double y) {
411  return (std::abs(x - y) < std::numeric_limits<double>::epsilon() * std::abs(x + y) * 2 ||
413 }
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:62
T * value_type(const SliceIterator< T > &)
Tps< T > log(const Tps< T > &x)
Natural logarithm.
Definition: TpsMath.h:182
PartBunchBase< T, Dim >::ConstIterator end(PartBunchBase< T, Dim > const &bunch)
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
std::complex< double > a
PETE_TUTree< FnAbs, typename T::PETE_Expr_t > abs(const PETE_Expr< T > &l)
PETE_TUTree< FnFloor, typename T::PETE_Expr_t > floor(const PETE_Expr< T > &l)
Definition: PETE.h:733
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:139
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:658
static OpalData * getInstance()
Definition: OpalData.cpp:195
std::string getAuxiliaryOutputDirectory() const
get the name of the the additional data directory
Definition: OpalData.cpp:650
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:591
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