Belle II Software  release-08-01-10
create_and_plot_magneticfield.py
1 #!/usr/bin/env python3
2 # -*- coding: utf-8 -*-
3 
4 
11 
12 
16 
17 from matplotlib.backends.backend_pdf import PdfPages
18 from matplotlib import pyplot as pl
19 import os
20 from basf2 import Path, process
21 import ROOT as root
22 import numpy as np
23 
24 import matplotlib as mpl
25 # switch to non-interactive backend
26 mpl.use("Agg")
27 
28 
31 
32 scan_type = "zx"
33 stepsU = (1800, -400., 500.)
34 stepsV = (1600, -400., 400.)
35 fieldtype = "MagneticField"
36 filename = "fieldmap-%s.pdf" % scan_type
37 # if true, the magnetic field will be shown using a blue-white-red gradient,
38 # white being no field.
39 show_color = True
40 # if contours is defined and non empty, contour lines at the specified field
41 # strengths are drawn on top of the color map
42 show_contours = None
43 # colours for the chosen contours: can either be None, a single color name or a
44 # list of color names matching the chosen contours
45 contour_colors = 'k'
46 # line width of contour lines. Can either be one number or an array of numbers
47 # denoting the width of each line
48 contour_width = 0.1
49 
50 # example: show 1.4 to 1.6 tesla contours in blue, cyan, green, magenta, red
51 # show_contours = [1.4, 1.45, 1.5, 1.55, 1.6]
52 # contour_colors = ['b', 'c', 'g', 'm', 'r']
53 
54 
57 
58 fieldmap_file = os.path.splitext(filename)[0] + "-fieldmap.root"
59 material_file = os.path.splitext(filename)[0] + "-material.root"
60 
61 # set Materialscan plane to be consistent with magnetic field map
62 if scan_type == "xy":
63  material_plane = [0, 0, -0.1, 1, 0, 0, 0, 1, 0]
64 elif scan_type == "zx":
65  material_plane = [0, -0.1, 0, 0, 0, 1, 1, 0, 0]
66 elif scan_type == "zy":
67  material_plane = [-0.1, 0, 0, 0, 0, 1, 0, 1, 0]
68 
69 main = Path()
70 # create modules
71 main.add_module('EventInfoSetter')
72 main.add_module('Gearbox')
73 geometry = main.add_module('Geometry')
74 main.add_module('FullSim')
75 # override field if we want something different than the default
76 if fieldtype != "MagneticField":
77  geometry.param({
78  "useDB": False,
79  "excludedComponents": ["MagneticField"],
80  "additionalComponents": [fieldtype],
81  })
82 
83 # Field map creator
84 main.add_module('CreateFieldMap', **{
85  'filename': fieldmap_file,
86  "type": scan_type,
87  "nU": stepsU[0],
88  "minU": stepsU[1],
89  "maxU": stepsU[2],
90  "nV": stepsV[0],
91  "minV": stepsV[1],
92  "maxV": stepsV[2],
93 })
94 
95 # Material map creator
96 main.add_module('MaterialScan', **{
97  'Filename': material_file,
98  'spherical': False,
99  'planar': True,
100  'planar.plane': 'custom',
101  'planar.custom': material_plane,
102  'planar.maxDepth': 0.2,
103  'planar.nU': stepsU[0],
104  'planar.minU': stepsU[1],
105  'planar.maxU': stepsU[2],
106  'planar.nV': stepsV[0],
107  'planar.minV': stepsV[1],
108  'planar.maxV': stepsV[2],
109  'planar.splitByMaterials': False,
110  'planar.ignored': ['Air', 'Vacuum', 'G4_AIR', 'ColdAir'],
111 })
112 
113 # Process one event to perform the scans
114 process(main)
115 
116 
119 
120 
121 def get_hist_data(hist):
122  """Obtain the data and extent of a ROOT TH2 as a numpy array"""
123  nbinsX = hist.GetNbinsX()
124  nbinsY = hist.GetNbinsY()
125  data = np.frombuffer(hist.GetArray(), count=hist.GetSize())
126  # rehsape and strip overflow/underflow bins
127  data = data.reshape(nbinsY + 2, nbinsX + 2)[1:-1, 1:-1]
128 
129  xmin = hist.GetXaxis().GetXmin()
130  xmax = hist.GetXaxis().GetXmax()
131  ymin = hist.GetYaxis().GetXmin()
132  ymax = hist.GetYaxis().GetXmax()
133 
134  return data, (xmin, xmax, ymin, ymax)
135 
136 
137 def plotMap(axes, data, extent, cmap, **kwargs):
138  """Plot either material or field map"""
139  return axes.imshow(data, extent=extent, origin="lower", cmap=cmap,
140  aspect="auto", interpolation="nearest", **kwargs)
141 
142 
143 # open root files we just created
144 rfieldmap_file = root.TFile(fieldmap_file)
145 rmaterial_file = root.TFile(material_file)
146 # get the material map
147 mat_hist = rmaterial_file.Get("Planar/All_Regions_x0")
148 mat_data, mat_extent = get_hist_data(mat_hist)
149 # obtain nice colormaps
150 cmap_fieldmap = mpl.cm.get_cmap('seismic')
151 cmap_material = mpl.cm.get_cmap('binary')
152 # create pdf file and fill with plots
153 pdf = PdfPages(filename)
154 for component in ["Bx", "By", "Bz", "B"]:
155  print("Create %s fieldmap plot" % component)
156  h = rfieldmap_file.Get(component)
157  data, extent = get_hist_data(h)
158  # we need the scale to be symmetric so find out what is the maximal
159  # absolute value and we choose a minimum scale
160  field_max = max(np.abs(data).max(), 0.1)
161  f = pl.figure()
162  a = f.add_subplot(111)
163  # plot material
164  lognorm = mpl.colors.LogNorm()
165  plotMap(a, mat_data, mat_extent, cmap_material, norm=lognorm)
166  # and overlay magnetic field
167  if show_color:
168  m = plotMap(a, data, extent, cmap_fieldmap, alpha=0.9,
169  vmin=-field_max, vmax=field_max)
170  # add a colorbar and set the label
171  cb = f.colorbar(m)
172  if len(component) == 1:
173  cb.set_label(r"$B/{\rm T}$")
174  else:
175  cb.set_label(r"$B_%s/{\rm T}$" % component[1])
176 
177  if show_contours is not None and len(show_contours) > 0:
178  # get bin centers in x and y
179  x, xstep = np.linspace(extent[0], extent[1], h.GetNbinsX() + 1,
180  retstep=True)
181  x += xstep / 2
182  y, ystep = np.linspace(extent[2], extent[3], h.GetNbinsY() + 1,
183  retstep=True)
184  y += ystep / 2
185  x, y = np.meshgrid(x[:-1], y[:-1])
186  # draw contour plot and label it
187  cs = a.contour(x, y, data, levels=show_contours, colors=contour_colors,
188  linewidths=contour_width)
189  a.clabel(cs, fmt="%.2f T", fontsize=6)
190 
191  # label the plot
192  a.set_title(h.GetTitle())
193  a.set_xlabel(r"$%s/{\rm cm}$" % scan_type[0])
194  a.set_ylabel(r"$%s/{\rm cm}$" % scan_type[1])
195  # findally, save the plot
196  pdf.savefig(f)
197 
198 pdf.close()