OPAL (Object Oriented Parallel Accelerator Library) 2024.2
OPAL
Vacuum.cpp
Go to the documentation of this file.
1//
2// Class Vacuum
3// Defines the abstract interface for vacuum.
4//
5// Copyright (c) 2018 - 2021, Pedro Calvo, CIEMAT, Spain
6// All rights reserved.
7//
8// Implemented as part of the PhD thesis
9// "Optimizing the radioisotope production of the novel AMIT
10// superconducting weak focusing cyclotron"
11//
12// This file is part of OPAL.
13//
14// OPAL is free software: you can redistribute it and/or modify
15// it under the terms of the GNU General Public License as published by
16// the Free Software Foundation, either version 3 of the License, or
17// (at your option) any later version.
18//
19// You should have received a copy of the GNU General Public License
20// along with OPAL. If not, see <https://www.gnu.org/licenses/>.
21//
22#include "AbsBeamline/Vacuum.h"
23
27#include "Physics/Physics.h"
28#include "Physics/Units.h"
33#include "Utilities/Util.h"
34
35#include <array>
36#include <cmath>
37#include <cstdio>
38#include <filesystem>
39#include <fstream>
40#include <iostream>
41
42#define CHECK_VAC_FSCANF_EOF(arg) if (arg == EOF)\
43throw GeneralClassicException("Vacuum::getPressureFromFile",\
44 "fscanf returned EOF at " #arg);
45
46extern Inform *gmsg;
47
49 Vacuum("")
50{}
51
52Vacuum::Vacuum(const Vacuum& right):
53 Component(right),
54 gas_m(right.gas_m),
55 pressure_m(right.pressure_m),
56 pmapfn_m(right.pmapfn_m),
57 pscale_m(right.pscale_m),
58 temperature_m(right.temperature_m),
59 stop_m(right.stop_m),
60 minr_m(right.minr_m),
61 maxr_m(right.maxr_m),
62 minz_m(right.minz_m),
63 maxz_m(right.maxz_m),
64 parmatint_m(nullptr)
65{}
66
67Vacuum::Vacuum(const std::string& name):
69 gas_m(ResidualGas::NOGAS),
70 pressure_m(0.0),
71 pmapfn_m(""),
72 pscale_m(1.0),
73 temperature_m(0.0),
74 stop_m(true),
75 minr_m(0.0),
76 maxr_m(0.0),
77 minz_m(0.0),
78 maxz_m(0.0),
79 parmatint_m(nullptr)
80{}
81
83 if (online_m)
84 goOffline();
85}
86
87void Vacuum::accept(BeamlineVisitor& visitor) const {
88 visitor.visitVacuum(*this);
89}
90
91constexpr std::array<std::pair<ResidualGas, std::string_view>, 2> residualGasMap {{
92 {ResidualGas::AIR, "AIR"},
93 {ResidualGas::H2, "H2"}
94}};
95
96void Vacuum::setResidualGas(std::string_view gas) noexcept {
98}
99
101 return gas_m;
102}
103
104std::string Vacuum::getResidualGasName() const {
105 if (gas_m == ResidualGas::NOGAS) {
106 throw GeneralClassicException("Vacuum::getResidualGasName",
107 "Residual gas not set");
108 } else {
109 return std::string(Util::enumToString(gas_m, residualGasMap, ""));
110 }
111}
112
113void Vacuum::setPressure(double pressure) {
114 pressure_m = pressure;
115}
116
117double Vacuum::getPressure() const {
118 if (pressure_m > 0.0) {
119 return pressure_m;
120 } else {
121 throw LogicalError("Vacuum::getPressure",
122 "Pressure must be positive");
123 }
124}
125
126void Vacuum::setPressureMapFN(std::string p) {
127 pmapfn_m = p;
128}
129
130std::string Vacuum::getPressureMapFN() const {
131 return pmapfn_m;
132}
133
134void Vacuum::setPScale(double ps) {
135 pscale_m = ps;
136}
137
138double Vacuum::getPScale() const {
139 if (pscale_m > 0.0) {
140 return pscale_m;
141 } else {
142 throw LogicalError("Vacuum::getPScale",
143 "PScale must be positive");
144 }
145}
146
147void Vacuum::setTemperature(double temperature) {
148 temperature_m = temperature;
149}
150
152 if (temperature_m > 0.0) {
153 return temperature_m;
154 } else {
155 throw LogicalError("Vacuum::getTemperature",
156 "Temperature must be positive");
157 }
158}
159
160void Vacuum::setStop(bool stopflag) {
161 stop_m = stopflag;
162}
163
164bool Vacuum::getStop() const {
165 return stop_m;
166}
167
169 bool hit = false;
170 if (OpalData::getInstance()->isInOPALCyclMode()) {
171 double rpos = std::sqrt(R(0) * R(0) + R(1) * R(1));
172 if (R(2) <= maxz_m || R(2) >= minz_m || rpos <= maxr_m || rpos >= minr_m) {
173 hit = true;
174 }
175 } else {
176 hit = ((R(2) > 0.0) && (R(2) <= getElementLength()));
177 }
178 return hit;
179}
180
181bool Vacuum::apply(const size_t& /*i*/, const double& /*t*/, Vector_t& /*E*/, Vector_t& /*B*/) {
182 return false;
183}
184
185bool Vacuum::applyToReferenceParticle(const Vector_t& /*R*/, const Vector_t& /*P*/,
186 const double& /*t*/, Vector_t& /*E*/, Vector_t& /*B*/) {
187 return false;
188}
189
191
192 bool flagNeedUpdate = false;
193
194 Vector_t rmin, rmax;
195 bunch->get_bounds(rmin, rmax);
196 std::pair<Vector_t, double> boundingSphere;
197 boundingSphere.first = 0.5 * (rmax + rmin);
198 boundingSphere.second = euclidean_norm(rmax - boundingSphere.first);
199
200 maxr_m = cycl->getMaxR();
201 minr_m = cycl->getMinR();
202 maxz_m = cycl->getMaxZ();
203 minz_m = cycl->getMinZ();
204
205 size_t tempnum = bunch->getLocalNum();
206 for (unsigned int i = 0; i < tempnum; ++i) {
207 int pflag = checkPoint(bunch->R[i]);
208 if ( (pflag != 0) && (bunch->Bin[i] != -1) )
209 flagNeedUpdate = true;
210 }
211
212 reduce(&flagNeedUpdate, &flagNeedUpdate + 1, &flagNeedUpdate, OpBitwiseOrAssign());
213
214 if (flagNeedUpdate && parmatint_m) {
215 dynamic_cast<BeamStrippingPhysics*>(parmatint_m)->setCyclotron(cycl);
216 parmatint_m->apply(bunch, boundingSphere);
218 }
219 return flagNeedUpdate;
220}
221
222void Vacuum::initialise(PartBunchBase<double, 3>* bunch, double& startField, double& endField) {
223
224 endField = startField + getElementLength();
225
226 initialise(bunch);
227
228 print();
229}
230
232
233 RefPartBunch_m = bunch;
234
236
237 goOnline(-1e6);
238
240
241 if (std::filesystem::exists(pmapfn_m)) {
243 // calculate the radii of initial grid.
245 }
246}
247
249 for (size_t i = 0; i < RefPartBunch_m->getLocalNum(); ++i) {
252 }
253}
254
256 *gmsg << "* Finalize vacuum " << getName() << endl;
257 if (online_m)
258 goOffline();
259}
260
261void Vacuum::goOnline(const double&) {
262 online_m = true;
263}
264
266 *gmsg << level2 << "\n" << parmatint_m->getElement()->getTypeString()
267 << ": " << getName() << " -> Residual gas = "
268 << getResidualGasName() << endl;
270 << ": " << getName() << " -> Pressure level = "
271 << std::scientific << pressure_m << " [mbar]" << endl;
272}
273
275 online_m = false;
276}
277
278void Vacuum::getDimensions(double& zBegin, double& zEnd) const {
279 zBegin = 0.0;
280 zEnd = getElementLength();
281}
282
286
288
289 const double x = R(0);
290 const double y = R(1);
291 double pressure = 0.0;
292
293 if (pmapfn_m.empty()) {
294 pressure = getPressure();
295 } else {
296 const double rad = std::sqrt(x * x + y * y);
297 const double xir = (rad - PP_m.rmin_m) / PP_m.delr_m;
298
299 // ir: the number of path whose radius is less than the 4 points of cell which surround the particle.
300 const int ir = (int)xir;
301 // wr1: the relative distance to the inner path radius
302 const double wr1 = xir - (double)ir;
303 // wr2: the relative distance to the outer path radius
304 const double wr2 = 1.0 - wr1;
305
306 const double tempv = std::atan(y / x);
307 double tet = tempv;
308 if ((x < 0) && (y >= 0)) tet = Physics::pi + tempv;
309 else if ((x < 0) && (y <= 0)) tet = Physics::pi + tempv;
310 else if ((x > 0) && (y <= 0)) tet = Physics::two_pi + tempv;
311 else if ((x == 0) && (y > 0)) tet = Physics::pi / 2.0;
312 else if ((x == 0) && (y < 0)) tet = 1.5 * Physics::pi;
313
314 // the actual angle of particle
315 tet = tet * Units::rad2deg;
316
317 // the corresponding angle on the field map
318 // Note: this does not work if the start point of field map does not equal zero.
319 double xit = tet / PP_m.dtet_m;
320 int it = (int) xit;
321 const double wt1 = xit - (double)it;
322 const double wt2 = 1.0 - wt1;
323 // it : the number of point on the inner path whose angle is less than the particle' corresponding angle.
324 // include zero degree point
325 it++;
326 double epsilon = 0.06;
327 if (tet > 360 - epsilon && tet < 360 + epsilon) it = 0;
328
329 int r1t1, r2t1, r1t2, r2t2;
330 // r1t1 : the index of the "min angle, min radius" point in the 2D field array.
331 // considering the array start with index of zero, minus 1.
332
333 r1t1 = idx(ir, it);
334 r2t1 = idx(ir + 1, it);
335 r1t2 = idx(ir, it + 1);
336 r2t2 = idx(ir + 1, it + 1);
337
338 if ((it >= 0) && (ir >= 0) && (it < PField_m.ntetS_m) && (ir < PField_m.nrad_m)) {
339 pressure = (PField_m.pfld_m[r1t1] * wr2 * wt2 +
340 PField_m.pfld_m[r2t1] * wr1 * wt2 +
341 PField_m.pfld_m[r1t2] * wr2 * wt1 +
342 PField_m.pfld_m[r2t2] * wr1 * wt1);
343 if (pressure <= 0.0) {
344 *gmsg << level4 << getName() << ": Pressure data from file zero." << endl;
345 *gmsg << level4 << getName() << ": Take constant value through Vacuum::getPressure" << endl;
346 pressure = getPressure();
347 }
348 } else if (ir >= PField_m.nrad_m) {
349 *gmsg << level4 << getName() << ": Particle out of maximum radial position of pressure field map." << endl;
350 *gmsg << level4 << getName() << ": Take constant value through Vacuum::getPressure" << endl;
351 pressure = getPressure();
352 } else {
353 throw GeneralClassicException("Vacuum::checkPressure",
354 "Pressure data not found");
355 }
356 }
357 return pressure;
358}
359
360// Calculates radius of initial grid (dimensions in [m]!)
361void Vacuum::initR(double rmin_m, double dr, int nrad_m) {
362 PP_m.rarr_m.resize(nrad_m);
363 for (int i = 0; i < nrad_m; i++) {
364 PP_m.rarr_m[i] = rmin_m + i * dr;
365 }
366 PP_m.delr_m = dr;
367}
368
369// Read pressure map from external file.
371
372 *gmsg << "* " << endl;
373 *gmsg << "* Reading pressure field map " << endl;
374
376 FILE* f = nullptr;
377 if ((f = std::fopen(pmapfn_m.c_str(), "r")) == nullptr) {
378 throw GeneralClassicException("Vacuum::getPressureFromFile",
379 "failed to open file '" + pmapfn_m +
380 "', please check if it exists");
381 }
382
383 CHECK_VAC_FSCANF_EOF(std::fscanf(f, "%lf", &PP_m.rmin_m));
384 *gmsg << "* --- Minimal radius of measured pressure map: " << PP_m.rmin_m << " [mm]" << endl;
385
386 CHECK_VAC_FSCANF_EOF(std::fscanf(f, "%lf", &PP_m.delr_m));
387 //if the value is negative, the actual value is its reciprocal.
388 if (PP_m.delr_m < 0.0) PP_m.delr_m = 1.0 / (-PP_m.delr_m);
389 *gmsg << "* --- Stepsize in radial direction: " << PP_m.delr_m << " [mm]" << endl;
390
391 CHECK_VAC_FSCANF_EOF(std::fscanf(f, "%lf", &PP_m.tetmin_m));
392 *gmsg << "* --- Minimal angle of measured pressure map: " << PP_m.tetmin_m << " [deg]" << endl;
393
394 CHECK_VAC_FSCANF_EOF(std::fscanf(f, "%lf", &PP_m.dtet_m));
395 //if the value is negative, the actual value is its reciprocal.
396 if (PP_m.dtet_m < 0.0) PP_m.dtet_m = 1.0 / (-PP_m.dtet_m);
397 *gmsg << "* --- Stepsize in azimuthal direction: " << PP_m.dtet_m << " [deg]" << endl;
398
399 CHECK_VAC_FSCANF_EOF(std::fscanf(f, "%d", &PField_m.ntet_m));
400 *gmsg << "* --- Grid points along azimuth (ntet_m): " << PField_m.ntet_m << endl;
401
402 CHECK_VAC_FSCANF_EOF(std::fscanf(f, "%d", &PField_m.nrad_m));
403 *gmsg << "* --- Grid points along radius (nrad_m): " << PField_m.nrad_m << endl;
404 *gmsg << "* --- Maximum radial position: " << PP_m.rmin_m + (PField_m.nrad_m-1)*PP_m.delr_m << " [mm]" << endl;
407
409 *gmsg << "* --- Adding a guard cell along azimuth" << endl;
410
413 *gmsg << "* --- Total stored grid point number ((ntet_m+1) * nrad_m) : " << PField_m.ntot_m << endl;
414 *gmsg << "* --- Escale factor: " << PP_m.Pfact_m << endl;
415
416 for (int i = 0; i < PField_m.nrad_m; i++) {
417 for (int k = 0; k < PField_m.ntet_m; k++) {
418 CHECK_VAC_FSCANF_EOF(std::fscanf(f, "%16lE", &(PField_m.pfld_m[idx(i, k)])));
419 PField_m.pfld_m[idx(i, k)] *= PP_m.Pfact_m;
420 }
421 }
422
423 std::fclose(f);
424}
425
426#undef CHECK_VAC_FSCANF_EOF
ResidualGas
Definition Vacuum.h:54
ElementType
Definition ElementBase.h:89
#define CHECK_VAC_FSCANF_EOF(arg)
Definition Vacuum.cpp:42
constexpr std::array< std::pair< ResidualGas, std::string_view >, 2 > residualGasMap
Definition Vacuum.cpp:91
Inform * gmsg
Definition Main.cpp:70
T euclidean_norm(const Vector< T > &)
Euclidean norm.
Definition Vector.h:243
Inform * gmsg
Definition Main.cpp:70
bool reduce(Communicate &, InputIterator, InputIterator, OutputIterator, const ReduceOp &, bool *IncludeVal=0)
Inform & level2(Inform &inf)
Definition Inform.cpp:46
Inform & level4(Inform &inf)
Definition Inform.cpp:48
Inform & endl(Inform &inf)
Definition Inform.cpp:42
const std::string name
constexpr double two_pi
The value of.
Definition Physics.h:33
constexpr double q_e
The elementary charge in As.
Definition Physics.h:69
constexpr double pi
The value of.
Definition Physics.h:30
constexpr double mm2m
Definition Units.h:29
constexpr double eV2GeV
Definition Units.h:71
constexpr double rad2deg
Definition Units.h:146
constexpr Enum stringToEnum(std::string_view str, const std::array< std::pair< Enum, std::string_view >, N > &map, Enum defaultEnum) noexcept
Definition Util.h:237
constexpr std::string_view enumToString(Enum e, const std::array< std::pair< Enum, std::string_view >, N > &map, std::string_view defaultStr) noexcept
Definition Util.h:247
ParticlePos_t & R
ParticleAttrib< int > Bin
void get_bounds(Vector_t &rmin, Vector_t &rmax) const
double getQ() const
Access to reference data.
size_t getLocalNum() const
ParticleAttrib< double > M
ParticleAttrib< double > Q
double getM() const
static OpalData * getInstance()
Definition OpalData.cpp:196
virtual void visitVacuum(const Vacuum &)=0
Apply the algorithm to a vacuum space.
Interface for a single beam element.
Definition Component.h:50
bool online_m
Definition Component.h:192
PartBunchBase< double, 3 > * RefPartBunch_m
Definition Component.h:191
virtual double getMaxR() const
virtual double getMaxZ() const
virtual double getMinZ() const
virtual double getMinR() const
virtual const std::string & getName() const
Get element name.
virtual ParticleMatterInteractionHandler * getParticleMatterInteraction() const
virtual double getElementLength() const
Get design length.
std::string getTypeString() const
std::vector< double > pfld_m
Definition Vacuum.h:37
int nrad_m
Definition Vacuum.h:38
int ntet_m
Definition Vacuum.h:38
int ntot_m
Definition Vacuum.h:40
int ntetS_m
Definition Vacuum.h:39
double tetmin_m
Definition Vacuum.h:46
double dtet_m
Definition Vacuum.h:46
double delr_m
Definition Vacuum.h:45
double Pfact_m
Definition Vacuum.h:51
double rmin_m
Definition Vacuum.h:45
std::vector< double > rarr_m
Definition Vacuum.h:49
double minr_m
Flag if particles should be stripped or stopped.
Definition Vacuum.h:147
double pressure_m
Type of gas for residual vacuum.
Definition Vacuum.h:139
ResidualGas getResidualGas() const noexcept
Definition Vacuum.cpp:100
void setPScale(double ps)
Definition Vacuum.cpp:134
bool stop_m
K.
Definition Vacuum.h:143
double pscale_m
stores the filename of the pressure map
Definition Vacuum.h:141
void setResidualGas(std::string_view gas) noexcept
Definition Vacuum.cpp:96
virtual void goOffline() override
Definition Vacuum.cpp:274
double getPressure() const
Definition Vacuum.cpp:117
std::string getPressureMapFN() const
Definition Vacuum.cpp:130
virtual void getDimensions(double &zBegin, double &zEnd) const override
Definition Vacuum.cpp:278
void initR(double rmin, double dr, int nrad)
Definition Vacuum.cpp:361
void setTemperature(double temperature)
Definition Vacuum.cpp:147
virtual ~Vacuum()
Definition Vacuum.cpp:82
virtual void goOnline(const double &kineticEnergy) override
Definition Vacuum.cpp:261
double minz_m
mm
Definition Vacuum.h:149
int idx(int irad, int ktet)
Definition Vacuum.h:126
double temperature_m
a scale factor for the P-field
Definition Vacuum.h:142
virtual ElementType getType() const override
Get element type std::string.
Definition Vacuum.cpp:283
double getPScale() const
Definition Vacuum.cpp:138
void getPressureFromFile()
Definition Vacuum.cpp:370
void setPressureMapFN(std::string pmapfn)
Definition Vacuum.cpp:126
double checkPressure(const Vector_t &R)
Definition Vacuum.cpp:287
virtual void finalise() override
Definition Vacuum.cpp:255
void print()
Definition Vacuum.cpp:265
virtual void initialise(PartBunchBase< double, 3 > *bunch, double &startField, double &endField) override
Definition Vacuum.cpp:222
virtual void accept(BeamlineVisitor &) const override
Apply visitor to Vacuum.
Definition Vacuum.cpp:87
void setPressure(double pressure)
Definition Vacuum.cpp:113
std::string getResidualGasName() const
Definition Vacuum.cpp:104
virtual bool applyToReferenceParticle(const Vector_t &R, const Vector_t &P, const double &t, Vector_t &E, Vector_t &B) override
Definition Vacuum.cpp:185
void updateParticleAttributes()
Definition Vacuum.cpp:248
virtual bool checkVacuum(PartBunchBase< double, 3 > *bunch, Cyclotron *cycl)
Definition Vacuum.cpp:190
ParticleMatterInteractionHandler * parmatint_m
mm
Definition Vacuum.h:153
std::string pmapfn_m
mbar
Definition Vacuum.h:140
double getTemperature() const
Definition Vacuum.cpp:151
virtual bool apply(const size_t &i, const double &t, Vector_t &E, Vector_t &B) override
Definition Vacuum.cpp:181
PFieldData PField_m
Definition Vacuum.h:157
double maxr_m
mm
Definition Vacuum.h:148
Vacuum()
Definition Vacuum.cpp:48
bool checkPoint(const Vector_t &R)
Definition Vacuum.cpp:168
bool getStop() const
Definition Vacuum.cpp:164
double maxz_m
mm
Definition Vacuum.h:150
PPositions PP_m
Definition Vacuum.h:160
ResidualGas gas_m
parameters for Vacuum
Definition Vacuum.h:138
void setStop(bool stopflag)
Definition Vacuum.cpp:160
virtual void print(Inform &os)=0
virtual void apply(PartBunchBase< double, 3 > *bunch, const std::pair< Vector_t, double > &boundingSphere)=0
Logical error exception.