def set_cassete_positions(self, dp=None, dcp=None, dgv=None, dgh=None): """ Change longitudinal cassette positions to adjust polarization and energy. """ if dp is None: dp = self._dp if dcp is None: dcp = self._dcp if dgv is None: dgv = self._dgv if dgh is None: dgh = self._dgh csd = self._cassettes['csd'] cse = self._cassettes['cse'] cid = self._cassettes['cid'] cie = self._cassettes['cie'] csd_z = _np.array(_rad.ObjM(csd.radia_object))[:, 0, 2] csd_shift = - (_np.max(csd_z) + _np.min(csd_z))/2 + dgv cse_z = _np.array(_rad.ObjM(cse.radia_object))[:, 0, 2] cse_shift = - ( _np.max(cse_z) + _np.min(cse_z))/2 + dgv + dgh + dp + dcp cid_z = _np.array(_rad.ObjM(cid.radia_object))[:, 0, 2] cid_shift = - (_np.max(cid_z) + _np.min(cid_z))/2 + dp - dcp cie_z = _np.array(_rad.ObjM(cie.radia_object))[:, 0, 2] cie_shift = - (_np.max(cie_z) + _np.min(cie_z))/2 + dgh csd.shift([0, 0, csd_shift]) cse.shift([0, 0, cse_shift]) cid.shift([0, 0, cid_shift]) cie.shift([0, 0, cie_shift]) self._dp = dp self._dcp = dcp self._dgv = dgv self._dgh = dgh return True
def build_model(self): """Build a Radia or Opera model with the current result set.""" length = self.length_spinbox.value() if self.build_button.text() == 'Radia': rad.UtiDelAll() item = self.listview.selectedItems()[0] # build magnet geometry magnet = rad.ObjCnt([rad.ObjThckPgn(0, length, pg[2:].reshape((4, 2)).tolist(), "z", list(pg[:2]) + [0, ]) for pg in self.state['results'][tuple(item.text().split(', '))]]) rad.MatApl(magnet, rad.MatStd('NdFeB', next(c for c in self.controls if c.switch == 'Br').control.value())) # plot geometry in 3d ax = self.plot3d.axes ax.cla() ax.set_axis_off() polygons = rad.ObjDrwVTK(magnet)['polygons'] vertices = np.array(polygons['vertices']).reshape((-1, 3)) # [x, y, z, x, y, z] -> [[x, y, z], [x, y, z]] [set_lim(vertices.min(), vertices.max()) for set_lim in (ax.set_xlim3d, ax.set_ylim3d, ax.set_zlim3d)] vertices = np.split(vertices, np.cumsum(polygons['lengths'])[:-1]) # split to find each face ax.add_collection3d(Poly3DCollection(vertices, linewidths=0.1, edgecolors='black', facecolors=self.get_colour(), alpha=0.2)) # add arrows magnetisation = np.array(rad.ObjM(magnet)).reshape((-1, 6)).T # reshape to [x, y, z, mx, my, mz] for end in (-1, 1): # one at each end of the block, not in the middle magnetisation[2] = end * length / 2 ax.quiver(*magnetisation, color='black', lw=1, pivot='middle') self.tab_control.setCurrentIndex(2) # switch to '3d' tab # solve the model try: rad.Solve(magnet, 0.00001, 10000) # precision and number of iterations except RuntimeError: self.statusBar().showMessage('Radia solve error') # get results dx = 0.1 multipoles = [mpole_names.index(c.label) for c in self.controls if c.label.endswith('pole') and c.get_arg()] i = multipoles[-1] xs = np.linspace(-dx, dx, 4) fit_field = np.polyfit(xs / 1000, [rad.Fld(magnet, 'by', [x, 0, 0]) for x in xs], i) fit_int = np.polyfit(xs / 1000, [rad.FldInt(magnet, 'inf', 'iby', [x, 0, -1], [x, 0, 1]) * 0.001 for x in xs], i) text = '' for j, (l, c, ic, u, iu) in enumerate( zip(mpole_names, fit_field[::-1], fit_int[::-1], units[1:], units[:-1])): if j in multipoles: f = factorial(j) # 1 for dip, quad; 2 for sext; 6 for oct text += f'{l} field = {c * f:.3g} {u}, integral = {ic * f:.3g} {iu}, length = {ic / c:.3g} m\n' ax.text2D(1, 1, text, transform=ax.transAxes, va='top', ha='right', fontdict={'size': 8}) self.plot3d.canvas.draw()
def check_segments(self, container): """Loop through all the objects in a container and evaluate the segmentation. Good shapes will have a magnetisation perpendicular to one of the faces. So find the normal of each face and evaluate the dot product with the magnetisation, both normalised to 1. The best have a max dot product of 1. Theoretical min is 1/sqrt(3) though most will be above 1/sqrt(2).""" shapes = rad.ObjCntStuf(container) xmin, xmax, ymin, ymax, zmin, zmax = rad.ObjGeoLim(container) print(f'Checking {len(shapes)} shapes in {container}, extent: x {xmin:.1f} to {xmax:.1f}, y {ymin:.1f} to {ymax:.1f}, z {zmin:.1f} to {zmax:.1f}') dot_products = {} for shape in shapes: sub_shapes = rad.ObjCntStuf(shape) if len(sub_shapes) > 0: # this shape is a container dot_products.update(self.check_segments(shape)) # recurse and update dict else: # it's an atomic shape mag = rad.ObjM(shape)[0] # returns [[mx, my, mz]], select the first element i.e. [mx, my, mz] norm = np.linalg.norm(mag) # normalise so total is 1 if norm == 0: continue mag = mag / norm # Have to parse the information from rad.UtiDmp, no other way of getting polyhedron faces! info = rad.UtiDmp(shape).replace('{', '[').replace('}', ']') # convert from Mathematica list format in_face_list = False # print(info) lines = info.split('\n') description = lines[0].split(': ') # print(description) object_type = description[-1] # print('Type is', object_type) if object_type == 'RecMag': # cuboid with axes parallel to x, y, z # simply find the largest component of normalised magnetisation - the closer to 1, the better dot_products[shape] = max(abs(mag)) elif object_type == 'Polyhedron': # need to loop over the faces product_list = [] for line in lines[1:]: if in_face_list: if '[' not in line: # reached the end of the face list break points = np.array(eval(line.rstrip(','))) normal = np.cross(points[1] - points[0], points[2] - points[0]) product_list.append(np.dot(normal / np.linalg.norm(normal), mag)) # normalise->unit vector elif 'Face Vertices' in line: in_face_list = True dot_products[shape] = max(product_list) # max seems to be a reasonable figure of merit return dot_products
def get_magnetization(g_id): return radia.ObjM(g_id)
def get_magnetization(self, name): return radia.ObjM(self.get_geom(name))
def get_magnetization(geom): return radia.ObjM(geom)