BDSIM
BDSIM is a Geant4 extension toolkit for simulation of particle transport in accelerator beamlines.
Loading...
Searching...
No Matches
BDSCavityFactoryElliptical.cc
1/*
2Beam Delivery Simulation (BDSIM) Copyright (C) BDSIM Collaboration, 2001 - 2026.
3
4This file is part of BDSIM.
5
6BDSIM is free software: you can redistribute it and/or modify
7it under the terms of the GNU General Public License as published
8by the Free Software Foundation version 3 of the License.
9
10BDSIM is distributed in the hope that it will be useful, but
11WITHOUT ANY WARRANTY; without even the implied warranty of
12MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13GNU General Public License for more details.
14
15You should have received a copy of the GNU General Public License
16along with BDSIM. If not, see <http://www.gnu.org/licenses/>.
17*/
18#include "BDSCavity.hh"
19#include "BDSCavityFactoryElliptical.hh"
20#include "BDSCavityInfo.hh"
21
22#include "globals.hh"
23#include "G4LogicalVolume.hh"
24#include "G4Polycone.hh"
25#include "G4SubtractionSolid.hh"
26#include "G4Tubs.hh"
27#include "G4VisAttributes.hh"
28#include "G4VSolid.hh"
29
30#include "CLHEP/Units/SystemOfUnits.h"
31
32#include <cmath>
33#include <vector>
34
35BDSCavityFactoryElliptical::BDSCavityFactoryElliptical()
36{;}
37
38BDSCavityFactoryElliptical::~BDSCavityFactoryElliptical()
39{;}
40
41G4double BDSCavityFactoryElliptical::CreateSolids(const G4String& name,
42 G4double totalChordLength,
43 const BDSCavityInfo* info)
44{
45 G4double chordLength = totalChordLength;
46 // Elliptical Cavity Parameters
47 // irisRSemiAxis --> Semi-axis of the iris ellipse perpendicular to the length of the cavity.
48 // irisZSemiAxis --> Semi-axis of the iris ellipse along the length of the cavity.
49 // equatorRSemiAxis --> Semi-axis of the equator ellipse perpendicular to the length of the cavity.
50 // equatorZSemiAxis --> Semi-axis of the equator ellipse along the length of the cavity.
51 // tangentAngle --> Angle between the line vertical to the z-axis and the line tangent to both ellipses.
52 // irisRadius --> Radius of the iris.
53 // noPoints --> Number of points used to define the shape. This is divided up between
54 // the 3 constituent shapes, 1/4 in each iris ellipse and 1/2 in central dome.
55 // length --> Length of the cell.
56 // equatorRadius --> Radius at the equator.
57 G4double equatorRadius = info->equatorRadius;
58 G4double irisRSemiAxis = info->irisVerticalAxis;
59 G4double irisZSemiAxis = info->irisHorizontalAxis; //iris ellipse horizontal semiaxis
60 G4double equatorRSemiAxis = info->equatorVerticalAxis ; //equator ellipse vertical semiaxis
61 G4double equatorZSemiAxis = info->equatorHorizontalAxis; //equator ellipse horizontal semiaxis
62 G4double tangentAngle = info->tangentLineAngle;
63 G4double irisRadius = info->irisRadius;
64 G4double thickness = info->thickness;
65 unsigned int noPoints = info->numberOfPoints;
66
67 // calculate cartesian coordinates (z, r) from parameters.
68 // 2D cylindrical coordinates, z along the beamline:
69 G4double zi = chordLength * 0.5; // z coord of iris ellipse centre
70 G4double ri = irisRadius + irisRSemiAxis; // r coord of iris ellipse centre
71 G4double ze = 0.0; // z coord of equator ellipse centre
72 G4double re = equatorRadius - equatorRSemiAxis; // r coord of equator ellipse centre.
73 // gradient of line connecting the ellipses.
74 // Add a pi/2 because angle is defined from the vertical, clockwise.
75 G4double m = std::tan(tangentAngle + CLHEP::halfpi);
76
77 // Gradient from tangentAngle. Find the derivative of ellipses. Equate
78 // and solve for the parameter.
79 // atan finds solution in the first quadrant.
80 G4double equatorParameterTangentPoint = std::atan(-equatorRSemiAxis/(m*equatorZSemiAxis));
81 // Add pi to get desired solution (third quadrant)
82 G4double irisParameterTangentPoint = std::atan(-irisRSemiAxis/(m*irisZSemiAxis)) + CLHEP::pi;
83
84 // Rounding down to a multiple of 4. This is so that number of points are
85 // share equally and consistently between the constituent ellipses.
86 noPoints = noPoints - (noPoints % 4);
87
88 // Vector Definitions:
89 // Parametric equation parameters:
90 // equatorParameter --> the values of a parameter for generating the central ellipses
91 // irisParameter --> the values of a parameter for generating the iris ellipse
92
93 //The Cartesian coordinates to be calculated from above parameters:
94 //rInnerCoord --> the values of radius for the inner geometry
95 //rOuterCoord --> the values of radius for the outer geometry
96 //zInnerCoord --> the values of z for the inner geometry
97 //zOuterCoord --> the values of z for the outer goemetry
98
99 //Vector declaration:
100 std::vector<G4double> equatorParameter;
101 std::vector<G4double> irisParameter;
102 std::vector<G4double> rInnerCoord;
103 std::vector<G4double> rOuterCoord;
104 std::vector<G4double> zInnerCoord;
105 std::vector<G4double> zOuterCoord;
106
107 // Generate values for the parameters used to define the ellipse shapes
108
109 // Vector of parameter values for generating the iris ellipse. This can then be
110 // reflected to find the iris ellipse on the other side.
111 for (unsigned int i = 0; i < noPoints/4; i++) //iris allocated one quarter of points.
112 {irisParameter.push_back(1.5*CLHEP::pi + (1.5*CLHEP::pi - irisParameterTangentPoint )*i/((noPoints/4)-1));}
113
114 //Vector of parameter values for generating the equator ellipse
115 for (unsigned int i = 0; i < noPoints/2; i++) //equator ellipse allocated half of the points
116 {
117 G4double term1 = CLHEP::pi - equatorParameterTangentPoint;
118 G4double term2 = CLHEP::pi - 2*equatorParameterTangentPoint;
119 G4double term3 = (noPoints*0.5) - 1;
120 G4double value = term1 - term2 * i / term3;
121 equatorParameter.push_back(value);
122 }
123
124 // Calculate the coordinates of the inner cavity shape, starting from -z through
125 // to +z, in 3 sections: -z iris ellipse -> equator ellipse -> +z iris ellipse.
126 // Geant requires the coordinates to be done in this (negative to positive)
127
128 // -z iris ellipse:
129 // noPoints/4 because of the total noPoints, the iris ellipse in -z is allocated a quarter of points.
130 for (unsigned int i = 0; i < noPoints/4; i++)
131 {
132 // An extra point at the very start for unambigious boolean subtraction later on.
133 // Will not actually be part of the final geometry.
134 if (i == 0)
135 {
136 //-10mm so boundaries don't lay upon each other when using boolean operation
137 zInnerCoord.push_back(- zi + irisZSemiAxis * std::cos(irisParameter[i]) - 10*CLHEP::mm);
138 rInnerCoord.push_back(ri + irisRSemiAxis * std::sin(irisParameter[i]));
139 }
140 zInnerCoord.push_back(- zi + irisZSemiAxis * std::cos(irisParameter[i]));
141 rInnerCoord.push_back(ri + irisRSemiAxis * std::sin(irisParameter[i]));
142 }
143
144 //equator ellipse (middle):
145 for (unsigned int i = 0; i < noPoints/2; i++) //central ellipse is allocated half the total points.
146 {
147 zInnerCoord.push_back(ze + equatorZSemiAxis * std::cos(equatorParameter[i]));
148 rInnerCoord.push_back(re + equatorRSemiAxis * std::sin(equatorParameter[i]));
149 };
150
151 //+z iris ellipse:
152 for (unsigned int i = 0; i < noPoints/4; i++) //the +z iris ellipse is allocated noPoints/4.
153 {
154 zInnerCoord.push_back(zi + irisZSemiAxis * std::cos(CLHEP::pi - irisParameter[noPoints/4 - 1 - i]));
155 rInnerCoord.push_back(ri + irisRSemiAxis * std::sin(CLHEP::pi - irisParameter[noPoints/4 - 1 - i]));
156 //If last point, add an extra point purely for unambigious boolean subtraction later.
157 if (i == (noPoints/4 - 1))
158 {
159 //+10mm so boundaries don't lay upon each other
160 zInnerCoord.push_back(zi + irisZSemiAxis * std::cos(CLHEP::pi - irisParameter[noPoints/4 - 1 - i]) + 10*CLHEP::mm);
161 rInnerCoord.push_back(ri + irisRSemiAxis * std::sin(CLHEP::pi - irisParameter[noPoints/4 - 1 - i]));
162 }
163 }
164
165 // Generating points for the entire outer cavity shape by using the inner cavity
166 // vector of coordinates--- This works by calculating the gradient at each point on the curve.
167 // It then finds a unit vector pointing perpendicularly outwards from this point and multiplies
168 // by the thickness. This creates a second vector of points for the outer geometry.
169 //starting from 1 and ending at n-1 so that the coordinates used for the boolean subtraction are excluded.
170 for (unsigned int i = 1; i < zInnerCoord.size() - 1; i++)
171 {
172 //calculate the gradient at point i
173 G4double gradientAt_i = (rInnerCoord[i-1]-rInnerCoord[i+1])/(zInnerCoord[i-1]-zInnerCoord[i+1]);
174
175 // Since the calculation relies on using the two points either side, and the
176 // ends have only one coordinate either side, take the ends as having gradient = 0.
177 // So that the vector points vertically upwards. Otherwise just do the calculation described above.
178 if (i == 1 || i == (zInnerCoord.size() - 2))
179 {
180 zOuterCoord.push_back(zInnerCoord[i]);
181 rOuterCoord.push_back(rInnerCoord[i] + thickness);
182 }
183 else
184 {
185 zOuterCoord.push_back(- gradientAt_i*thickness * std::pow( (gradientAt_i * gradientAt_i + 1), -0.5) + zInnerCoord[i]);
186 rOuterCoord.push_back(+ thickness * std::pow( (gradientAt_i*gradientAt_i + 1), -0.5) + rInnerCoord[i]);
187 }
188 }
189
190#ifdef BDSDEBUG
191 G4cout << "Now printing the values of (zInnerCoord,rInnerCoord):" << G4endl;
192 G4cout << "Length of zInnerCoord = " << zInnerCoord.size() << G4endl;
193 G4cout << "Length of rInnerCoord = " << rInnerCoord.size() << G4endl;
194 for (G4int i = 0; i < (G4int)zInnerCoord.size(); i++)
195 {G4cout << "(" << zInnerCoord[i] << "," << rInnerCoord[i] << ")" << G4endl;};
196
197 G4cout << "Now printing the values of (zOuterCoord,rOuterCoord):" << G4endl;
198 G4cout << "Length of zOuterCoord = " << zOuterCoord.size() << G4endl;
199 G4cout << "Length of rOuterCoord = " << rOuterCoord.size() << G4endl;
200 for (G4int i = 0; i < (G4int)zOuterCoord.size(); i++)
201 {G4cout << "(" << zOuterCoord[i] << "," << rOuterCoord[i] << ")" << G4endl;};
202#endif
203
204 // Array of inner r coordinates. zeroes ensures the polycone will be solid.
205 std::vector<G4double> solidArrayOuter(noPoints, 0.0);
206 // Array of inner r coordinates. zeroes ensures the polycone will be solid. 1 extra
207 // point either side for unambiguous boolean subtraction.
208 std::vector<G4double> solidArrayInner(noPoints+2, 0.0);
209
210 // Define the inner solid which is to be subtracted from the outer and also used to
211 // define the vacuum.
212 G4VSolid* innerSolid = new G4Polycone(name + "_inner_solid", //name
213 0.0, //start angle
214 CLHEP::twopi, //sweep angle
215 zInnerCoord.size(),
216 zInnerCoord.data(),
217 solidArrayInner.data(),
218 rInnerCoord.data()); //r coordinates
219
220 // Define the outer solid from which the inner is subtracted.
221 G4VSolid* outerSolid = new G4Polycone(name + "_outer_solid", // name
222 0.0, // start angle
223 CLHEP::twopi, // sweep angle
224 zOuterCoord.size(), // number of corners
225 zOuterCoord.data(), // zOuterCoord array of points
226 solidArrayOuter.data(),// array of zeroes for solid shape
227 rOuterCoord.data()); // rOuterCoord array of points.
228 allSolids.insert(innerSolid);
229 allSolids.insert(outerSolid);
230
231 // Do the subtraction
232 cavitySolid = new G4SubtractionSolid(name + "_cavity_solid", // name
233 outerSolid, // solid1
234 innerSolid); // minus solid2
235
236 // Delete first and last elements of the InnerCoord Vectors, as these entries.
237 // The reason we need to do this is the same vector is also used for making the
238 // vacuum filling the cavity, but without the extra points for subtraction.
239 rInnerCoord.erase (rInnerCoord.begin());
240 rInnerCoord.pop_back();
241 zInnerCoord.erase (zInnerCoord.begin());
242 zInnerCoord.pop_back();
243
244 //Take lengthsafety from all r points and the end z points, to avoid overlap with the cavity.
245 for (unsigned int i = 0; i < noPoints; i++)
246 {rInnerCoord[i] = rInnerCoord[i] - lengthSafetyLarge;}
247
248 zInnerCoord[0] = zInnerCoord[0] + 2*lengthSafety;
249 G4int lastInd = (G4int)zInnerCoord.size() - 1;
250 zInnerCoord[lastInd] = zInnerCoord[lastInd] - 2*lengthSafety; // last element
251
252 vacuumSolid = new G4Polycone(name + "_inner_solid", //name
253 0.0, //start angle
254 CLHEP::twopi, //sweep angle
255 zInnerCoord.size(),
256 zInnerCoord.data(),
257 solidArrayInner.data(),
258 rInnerCoord.data()); //r coordinates
259 allSolids.insert(vacuumSolid);
260
261 G4double containerRadius = equatorRadius + thickness + lengthSafetyLarge;
262 containerSolid = new G4Tubs(name + "_container_solid", // name
263 0.0, // innerRadius
264 containerRadius, // outerRadius
265 chordLength*0.5, // half length
266 0.0, // starting angle
267 CLHEP::twopi); // sweep angle
268 return containerRadius;
269}
270
271void BDSCavityFactoryElliptical::SetVisAttributes(const G4String& /*colourName*/)
272{
274}
virtual void SetVisAttributes(const G4String &colourName="rfcavity")
Set vis attributes for cavityLV, vacuumLV and containerLV.
G4VSolid * vacuumSolid
Cache of particular solid or lv for common functionality in this class.
G4VSolid * containerSolid
Cache of particular solid or lv for common functionality in this class.
G4VSolid * cavitySolid
Cache of particular solid or lv for common functionality in this class.
virtual G4double CreateSolids(const G4String &name, G4double totalChordLength, const BDSCavityInfo *info)
Create vacuumSolid and cavitySolid. Must return the container radius.
virtual void SetVisAttributes(const G4String &colourName)
Overload base class method, but use base class method with different colour.
Holder for all Geometrical information required to create an RF cavity.
G4double equatorRadius
Equator radius - half width of widest part.
G4double equatorVerticalAxis
Equator ellipse vertical semi-axis.
G4double tangentLineAngle
Tangent angle.
G4double irisRadius
Iris radius - half width of narrowest part.
G4double irisVerticalAxis
Iris ellipse vertical semi-axis.
G4double irisHorizontalAxis
Iris ellipse horizontal semi-axis.
G4double equatorHorizontalAxis
Equator ellipse horizontal semi-axis.
G4double thickness
Thickness of wall material.
G4double lengthSafety
Cache of global constants variable.
G4double lengthSafetyLarge
Cache of global constants variable.