18 Module to hold FFAFieldMapper
27 import matplotlib.pyplot
29 import pyopal.objects.field
34 Class to make field maps, intended for FFAs/ring geometries
64 """Build a set of bins based on a list of grid coordinates"""
65 return [a_list[0]+(a_list[1]-a_list[0])*(i-0.5) \
66 for i
in range(len(a_list)+1)]
70 Load tracks from track_orbit file
71 - track_orbit: string file name
74 with open(track_orbit, encoding=
"utf8")
as fin:
75 for i, line
in enumerate(fin.readlines()):
85 "x":[],
"px":[],
"y":[],
"py":[],
"r":[], "phi":[]
87 pos_r = (float(words[1])**2+float(words[3])**2)**0.5
88 phi = math.atan2(float(words[3]), float(words[1]))
98 Generate the colour mapping for field bz
99 - bz_grid: set of bz values. Colour mapping will proceed symmetrically
100 0 in the positive and negative direction. Maximum value is
101 the maximum absolute value in the bz_grid, up to self.bmax.
102 If the grid contains a value greater than self.bmax, then
103 self.bmax becomes the maximum value. To disable the bmax
104 behaviour, set self.bmax to None
105 Returns a tuple of (min_bz in the grid,
107 max value of bz to be used in the colormap)
109 min_bz =
min(bz_grid)
110 max_bz =
max(bz_grid)
111 if self.
bmax is None:
115 return min_bz, max_bz, cmax
119 Plot a field map in cylindrical coordinates.
121 - axes: matplotlib Axes object or None. If defined, plot the field map
122 on axes as a hist2d; if None make a new figure/axes and plot it there.
124 Returns the figure, either a new figure or the parent figure to which
133 r_grid.append(radius)
135 point = (radius*math.cos(math.radians(phi)),
136 radius*math.sin(math.radians(phi)),
139 value = pyopal.objects.field.get_field_value(*point)
140 bz_grid.append(value[3])
142 print(
"Field value at r, phi", radius, round(phi, 2),
149 figure = matplotlib.pyplot.figure()
150 axes = figure.add_subplot(1, 1, 1)
152 min_by, max_by, cmax = self.
gen_cmap(bz_grid)
153 axes.hist2d(phi_grid, r_grid, bins=[phi_bins, r_bins], weights=bz_grid,
154 cmin=min_by, cmax=max_by, cmap=self.
cmap, vmin=-cmax, vmax=cmax)
155 axes.set_xlabel(
"$\\phi$ [deg]")
156 axes.set_ylabel(
"r [m]")
157 axes.set_title(
"$B_z$ [T]")
162 fig_fname = os.path.join(self.
plot_dir,
"scaling_ffa_map_cyl.png")
163 figure.savefig(fig_fname)
164 print(
"Generated cylindrical field map in", fig_fname)
170 Draw a purely radial contour on axes
171 - axes: matplotlib Axes object to draw on.
172 - contour: dictionary (see default_contour for definitions)
174 print(
"Plotting cylindrical radial contour", contour)
175 xlim = axes.get_xlim()
176 ylim = axes.get_ylim()
178 [contour[
"radius"]]*2,
179 linestyle=contour[
"linestyle"],
180 color=contour[
"colour"])
184 horizontalalignment=
"right",
186 color=contour[
"colour"])
192 Draw a radially spiralling contour on axes
193 - axes: matplotlib Axes object to draw on.
194 - contour: dictionary (see default_contour for definitions)
196 xlim = axes.get_xlim()
197 ylim = axes.get_ylim()
198 tan_d = math.tan(math.radians(contour[
"spiral_angle"]))
199 phi_points = [math.radians(contour[
"phi0"]) + \
200 tan_d*math.log(r/contour[
"r0"])
for r
in self.
r_points]
201 phi_points = [math.degrees(phi)
for phi
in phi_points]
202 axes.plot(phi_points, self.
r_points,
203 linestyle=contour[
"linestyle"],
204 color=contour[
"colour"])
205 axes.text(phi_points[-1],
210 color=contour[
"colour"])
216 Plot a field map in cartesian coordinates.
218 - axes: matplotlib Axes object or None. If defined, plot the field map
219 on axes as a hist2d; if None make a new figure/axes and plot it there.
221 Returns the figure, either a new figure or the parent figure to which
231 point = (pos_x, pos_y, 0, 0)
232 value = pyopal.objects.field.get_field_value(*point)
233 bz_grid.append(value[3])
235 print(
"Field value at point", point,
236 "is B:", value[1:4],
"E:", value[4:])
240 figure = matplotlib.pyplot.figure()
241 axes = figure.add_subplot(1, 1, 1)
242 min_by, max_by, cmax = self.
gen_cmap(bz_grid)
243 hist = axes.hist2d(x_grid, y_grid, bins=[x_bins, y_bins], weights=bz_grid,
244 cmin=min_by, cmax=max_by, cmap=self.
cmap, vmin=-cmax, vmax=cmax)
245 axes.set_xlabel(
"x [m]")
246 axes.set_ylabel(
"y [m]")
247 axes.set_title(
"$B_{z}$ [T]")
248 figure.colorbar(hist[3])
249 fig_fname = os.path.join(self.
plot_dir,
"scaling_ffa_map_cart.png")
250 figure.savefig(fig_fname)
251 print(
"Generated cartesian field map in", fig_fname)
256 Plot tracks in cartesian coordinates
257 - axes: Axes object to draw on
259 for pid, track
in self.track_orbit_dict.items():
262 axes.plot(pos_x, pos_y)
266 Plot tracks in cylindrical coordinates
267 - axes: Axes object to draw on
268 If phi changes by more than 180 degrees in a single step, the track is
269 assumed to have gone through an entire turn (360 <-> 0) and a new plot
272 for pid, track
in self.track_orbit_dict.items():
274 delta_list = [i+1
for i, phi1
in enumerate(track[
"phi"][1:]) \
275 if abs(track[
"phi"][i] - phi1) > 180]
276 phi_list_of_lists = numpy.split(track[
"phi"], delta_list)
277 r_list_of_lists = numpy.split(track[
"r"], delta_list)
278 for i
in range(len(phi_list_of_lists)):
279 axes.plot(phi_list_of_lists[i], r_list_of_lists[i])
284 Make a one dimensional field map along a line of constant radius
285 - radius: line to draw the fields on
286 - axes: Axes object to draw on
291 point = (radius*math.cos(math.radians(phi)),
292 radius*math.sin(math.radians(phi)),
295 value = pyopal.objects.field.get_field_value(*point)
296 bz_points.append(value[3])
299 figure = matplotlib.pyplot.figure()
300 axes = figure.add_subplot(1, 1, 1)
306 axes.set_xlabel(
"$\\phi$ [deg]")
307 axes.set_ylabel(
"$B_z$ [T]")
308 return axes.figure, bz_points
313 Draw an azimuthal contour (including spiral angle if required)
314 - radius: r0 for spiral angle calculations
315 - axes: Axes object to draw on
316 - contour: contour object
318 xlim = axes.get_xlim()
319 ylim = axes.get_ylim()
320 tan_d = math.tan(contour[
"spiral_angle"])
321 phi = contour[
"phi0"] + tan_d*math.log(radius/contour[
"r0"])
322 phi = math.degrees(phi)
323 axes.plot([phi, phi], ylim,
324 linestyle=contour[
"linestyle"],
325 color=contour[
"colour"])
326 axes.text(phi, ylim[-1],
327 contour[
"label"], va=
"top",
329 color=contour[
"colour"])
336 Calculate a numerical derivative of the field in cartesian coordinates
337 - var1: variable in the numerator, should be one of self.position_variables
338 - var2: variable in the denominator (range 1 to 4)
340 pos_vec = [pos_x, pos_y, pos_z, time]
341 var2 = self.position_variables.index(var2)
343 field_plus = pyopal.objects.field.get_field_value(*pos_vec)[var1]
344 pos_vec[var2] -= 2*self.
delta_x
345 field_minus = pyopal.objects.field.get_field_value(*pos_vec)[var1]
346 derivative = (field_plus-field_minus)/2.0/self.
delta_x
351 Calculate a numerical derivative of the field in cartesian coordinates
352 - var1: should be an integer range 1 to 6 inclusive for bx, by, bz, ex, ey, ez
353 - var2: should be an integer range 0 to 3 inclusive for x, y, z, t
354 - x, y, z, t: position at which the derivative should be calculated
356 raise RuntimeError(
"Not implemented")
362 div_b = self.
get_derivative(
"bx",
"x", pos_x, pos_y, pos_z, time) + \
381 default_radial_contour = {
"radius":0.0,
385 default_spiral_contour = {
392 position_variables = [
"x",
"y",
"z",
"t"]
393 field_variables = [
"out_of_bounds",
"bx",
"by",
"bz",
"ex",
"ey",
"ez"]
def plot_tracks_cylindrical
def plot_tracks_cartesian
PETE_TUTree< FnAbs, typename T::PETE_Expr_t > abs(const PETE_Expr< T > &l)
def field_map_cylindrical
T::PETE_Expr_t::PETE_Return_t min(const PETE_Expr< T > &expr, NDIndex< D > &loc)
T::PETE_Expr_t::PETE_Return_t max(const PETE_Expr< T > &expr, NDIndex< D > &loc)
def draw_cylindrical_radial_contour
def draw_azimuthal_contour
def draw_cylindrical_spiral_contour