def make_dipole(pole_dimensions, center, length, current=-10000, trimesh_mode=0, triangle_min_size=TRIANGLE_MIN_SIZE, triangle_max_size=TRIANGLE_MAX_SIZE, longitudinal_divisions=4): """ Construct a complete H-dipole made of iron. :param pole_dimensions: (dict) Parameters describing geometry of pole piece. See `_create_point_table`. :param center: (float) Center point of dipole in x (longitudinal center for beam frame). :param length: (float) Length of the dipole in x :param current: (float) Current carried by dipole coils (default: -10000) :param trimesh_mode: (int) If 0 (default) then the pole piece is divisioned into polygons based on point ordering from coordinate list. If != 0 then a Triangular mesh is automatically generated. :param longitudinal_divisions: (int) Number of slices to divide up the dipole into along the x-axis (default: 4) :return: """ # coil_factor increases coil size slightly to accommodate sharp corners of pole piece coil_length_factor = 1.005 coil_height_factor = 3. / 4. coil_or_factor = 0.85 # Geometry for the poles table_quadrant_one = _create_point_table(**pole_dimensions) top_coodinates = _get_all_points_top(table_quadrant_one) bottom_coordinates = _get_all_points_bottom(top_coodinates) top_pole = create_pole(top_coodinates, center, length, mode=trimesh_mode, triangle_min_size=triangle_min_size, triangle_max_size=triangle_max_size) bottom_pole = create_pole(bottom_coordinates, center, length, mode=trimesh_mode, triangle_min_size=triangle_min_size, triangle_max_size=triangle_max_size) # Material for the poles (uses Iron) ironmat = rad.MatSatIsoFrm([20000, 2], [0.1, 2], [0.1, 2]) rad.MatApl(top_pole, ironmat) rad.MatApl(bottom_pole, ironmat) # Coils coil_outer_radius = pole_dimensions['pole_separation'] * coil_or_factor top_coil = make_racetrack_coil( center=[ 0, 0.0, pole_dimensions['gap_height'] + pole_dimensions['pole_height'] / 2. ], radii=[0.1, coil_outer_radius], sizes=[ length * coil_length_factor, pole_dimensions['pole_width'] * 2 * coil_length_factor, pole_dimensions['pole_height'] * coil_height_factor ], current=current) bottom_coil = make_racetrack_coil(center=[ 0, 0.0, -1. * (pole_dimensions['gap_height'] + pole_dimensions['pole_height'] / 2.) ], radii=[0.1, coil_outer_radius], sizes=[ length * coil_length_factor, pole_dimensions['pole_width'] * 2 * coil_length_factor, pole_dimensions['pole_height'] * coil_height_factor ], current=current) # Visualization rad.ObjDrwAtr(top_pole, [0, 0.4, 0.8]) rad.ObjDrwAtr(bottom_pole, [0, 0.4, 0.8]) rad.ObjDrwAtr(top_coil, [0.2, 0.9, 0.6]) rad.ObjDrwAtr(bottom_coil, [0.2, 0.9, 0.6]) # Element Division rad.ObjDivMag(top_pole, [longitudinal_divisions, 1, 1]) rad.ObjDivMag(bottom_pole, [longitudinal_divisions, 1, 1]) return rad.ObjCnt([top_pole, bottom_pole, top_coil, bottom_coil])
def build(self): """Create a quadrupole with the given geometry.""" if self.solve_state < SolveState.SHAPES: self.define_shapes() rad.UtiDelAll() origin = [0, 0, 0] nx = [1, 0, 0] ny = [0, 1, 0] nz = [0, 0, 1] tip_mesh = round(self.min_mesh) pole_mesh = round(self.min_mesh * self.pole_mult) yoke_mesh = round(self.min_mesh * self.yoke_mult) length = self.length # Subdivide the pole tip cylindrically. The axis is where the edge of the tapered pole meets the Y-axis. points = rotate45(self.tip_points) x2, y2 = points[-2] # top right of pole x3, y3 = points[-3] # bottom right of pole m = (y2 - y3) / (x2 - x3) c = y2 - m * x2 pole_tip = rad.ObjThckPgn(length / 2, length, points, "z") # Slice off the chamfer (note the indexing at the end here - selects the pole not the cut-off piece) pole_tip = rad.ObjCutMag(pole_tip, [length - self.chamfer, 0, self.r], [1, 0, -1])[0] n_div = max(1, round(math.sqrt((x2 - x3) ** 2 + (y2 - y3) ** 2) / pole_mesh)) # We have to specify the q values here (second element of each sublist in the subdivision argument) # otherwise weird things happen mesh = [[n_div, 4], [tip_mesh / 3, 1], [tip_mesh, 1]] div_opts = 'Frame->Lab;kxkykz->Size' # rad.ObjDivMag(pole_tip, [[tip_mesh, 1], [tip_mesh, 1], [tip_mesh, 3]], div_opts) rad.ObjDivMag(pole_tip, mesh, "cyl", [[[0, c, 0], nz], nx, 1], div_opts) rad.TrfOrnt(pole_tip, rad.TrfRot(origin, nz, -math.pi / 4)) pole = rad.ObjThckPgn(length / 2, length, rotate45(self.pole_points), "z") rad.ObjDivMag(pole, [pole_mesh, ] * 3, div_opts) rad.TrfOrnt(pole, rad.TrfRot(origin, nz, -math.pi / 4)) # Need to split yoke since Radia can't build concave blocks points = rotate45(self.yoke_points[:2] + self.yoke_points[-2:]) # yoke1 is the part that joins the pole to the yoke # Subdivide this cylindrically since the flux goes around a corner here # The axis is the second point (x1, y1) x1, y1 = points[1] yoke1 = rad.ObjThckPgn(length / 2, length, points, "z") cyl_div = [[[x1, y1, 0], nz], [self.width, self.width, 0], 1] # The first (kr) argument, corresponding to radial subdivision, # in rad.ObjDivMag cuts by number not size even though kxkykz->Size is specified. # So we have to fudge this. It seems to require a larger number to give the right number of subdivisions. n_div = max(1, round(2 * self.width / yoke_mesh)) rad.ObjDivMag(yoke1, [n_div, yoke_mesh, yoke_mesh], "cyl", cyl_div, div_opts) rad.TrfOrnt(yoke1, rad.TrfRot(origin, nz, -math.pi / 4)) # For the second part of the yoke, we use cylindrical subdivision again. But the axis is not on the corner; # instead we calculate the point where the two lines converge (xc, yc). points = self.yoke_points[1:3] + self.yoke_points[-3:-1] x0, y0 = points[0] x1, y1 = points[1] x2, y2 = points[2] x3, y3 = points[3] m1 = (y3 - y0) / (x3 - x0) m2 = (y2 - y1) / (x2 - x1) c1 = y0 - m1 * x0 c2 = y1 - m2 * x1 xc = (c2 - c1) / (m1 - m2) yc = m1 * xc + c1 yoke2 = rad.ObjThckPgn(length / 2, length, points, 'z') cyl_div = [[[xc, yc, 0], nz], [x3 - xc, y3 - yc, 0], 1] n_div = max(1, round(0.7 * n_div)) # this is a bit of a fudge rad.ObjDivMag(yoke2, [n_div, yoke_mesh, yoke_mesh], "cyl", cyl_div, div_opts) yoke3 = rad.ObjThckPgn(length / 2, length, self.yoke_points[2:6], "z") rad.ObjDivMag(yoke3, [yoke_mesh, ] * 3, div_opts) steel = rad.ObjCnt([pole_tip, pole, yoke1, yoke2, yoke3]) rad.ObjDrwAtr(steel, [0, 0, 1], 0.001) # blue steel rad.TrfOrnt(steel, rad.TrfRot(origin, ny, -math.pi / 2)) rad.ObjDrwOpenGL(steel) rad.TrfOrnt(steel, rad.TrfRot(origin, ny, math.pi / 2)) # rad.TrfMlt(steel, rad.TrfPlSym([0, 0, 0], [1, -1, 0]), 2) # reflect along X=Y line to create a quadrant rad.TrfZerPerp(steel, origin, [1, -1, 0]) rad.TrfZerPerp(steel, origin, nz) steel_material = rad.MatSatIsoFrm([2000, 2], [0.1, 2], [0.1, 2]) steel_material = rad.MatStd('Steel42') steel_material = rad.MatSatIsoFrm([959.703184, 1.41019852], [33.9916543, 0.5389669], [1.39161186, 0.64144324]) rad.MatApl(steel, steel_material) coil = rad.ObjRaceTrk(origin, [5, 5 + self.coil_width], [self.coil_x * 2 - self.r, length * 2], self.coil_height, 4, self.current_density) rad.TrfOrnt(coil, rad.TrfRot(origin, nx, -math.pi / 2)) rad.TrfOrnt(coil, rad.TrfTrsl([0, self.r + self.taper_height + self.coil_height / 2, 0])) rad.TrfOrnt(coil, rad.TrfRot(origin, nz, -math.pi / 4)) rad.ObjDrwAtr(coil, [1, 0, 0], 0.001) # red coil quad = rad.ObjCnt([steel, coil]) rad.TrfZerPara(quad, origin, nx) rad.TrfZerPara(quad, origin, ny) # rad.ObjDrwOpenGL(quad) self.radia_object = quad self.solve_state = SolveState.BUILT
def geom(circ): eps = 0 ironcolor = [0, 0.5, 1] coilcolor = [1, 0, 0] ironmat = radia.MatSatIsoFrm([20000, 2], [0.1, 2], [0.1, 2]) # Pole faces lx1 = thick / 2 ly1 = width lz1 = 20 l1 = [lx1, ly1, lz1] k1 = [[thick / 4. - chamfer / 2., 0, gap / 2.], [thick / 2. - chamfer, ly1 - 2. * chamfer]] k2 = [[thick / 4., 0., gap / 2. + chamfer], [thick / 2., ly1]] k3 = [[thick / 4., 0., gap / 2. + lz1], [thick / 2, ly1]] g1 = radia.ObjMltExtRtg([k1, k2, k3]) radia.ObjDivMag(g1, n1) radia.ObjDrwAtr(g1, ironcolor) # Vertical segment on top of pole faces lx2 = thick / 2 ly2 = ly1 lz2 = 30 l2 = [lx2, ly2, lz2] p2 = [thick / 4, 0, lz1 + gap / 2 + lz2 / 2 + 1 * eps] g2 = radia.ObjRecMag(p2, l2) radia.ObjDivMag(g2, n2) radia.ObjDrwAtr(g2, ironcolor) # Corner lx3 = thick / 2 ly3 = ly2 lz3 = ly2 * 1.25 l3 = [lx3, ly3, lz3] p3 = [thick / 4, 0, lz1 + gap / 2 + lz2 + lz3 / 2 + 2 * eps] g3 = radia.ObjRecMag(p3, l3) typ = [ [p3[0], p3[1] + ly3 / 2, p3[2] - lz3 / 2], [1, 0, 0], [p3[0], p3[1] - ly3 / 2, p3[2] - lz3 / 2], lz3 / ly3 ] if circ == 1: radia.ObjDivMag(g3, [nbr, nbp, n3[1]], 'cyl', typ) else: radia.ObjDivMag(g3, n3) radia.ObjDrwAtr(g3, ironcolor) # Horizontal segment between the corners lx4 = thick / 2 ly4 = 80 lz4 = lz3 l4 = [lx4, ly4, lz4] p4 = [thick / 4, ly3 / 2 + eps + ly4 / 2, p3[2]] g4 = radia.ObjRecMag(p4, l4) radia.ObjDivMag(g4, n4) radia.ObjDrwAtr(g4, ironcolor) # The other corner lx5 = thick / 2 ly5 = lz4 * 1.25 lz5 = lz4 l5 = [lx5, ly5, lz5] p5 = [thick / 4, p4[1] + eps + (ly4 + ly5) / 2, p4[2]] g5 = radia.ObjRecMag(p5, l5) typ = [ [p5[0], p5[1] - ly5 / 2, p5[2] - lz5 / 2], [1, 0, 0], [p5[0], p5[1] + ly5 / 2, p5[2] - lz5 / 2], lz5 / ly5 ] if circ == 1: radia.ObjDivMag(g5, [nbr, nbp, n5[0]], 'cyl', typ) else: radia.ObjDivMag(g5, n5) radia.ObjDrwAtr(g5, ironcolor) # Vertical segment inside the coil lx6 = thick / 2 ly6 = ly5 lz6 = gap / 2 + lz1 + lz2 l6 = [lx6, ly6, lz6] p6 = [thick / 4, p5[1], p5[2] - (lz6 + lz5) / 2 - eps] g6 = radia.ObjRecMag(p6, l6) radia.ObjDivMag(g6, n6) radia.ObjDrwAtr(g6, ironcolor) # Generation of the coil r_min = 5 r_max = 40 h = 2 * lz6 - 5 cur_dens = current / h / (r_max - r_min) pc = [0, p6[1], 0] coil = radia.ObjRaceTrk(pc, [r_min, r_max], [thick, ly6], h, 3, cur_dens) radia.ObjDrwAtr(coil, coilcolor) # Make container and set the colors g = radia.ObjCnt([g1, g2, g3, g4, g5, g6]) radia.ObjDrwAtr(g, ironcolor) radia.MatApl(g, ironmat) t = radia.ObjCnt([g, coil]) # Define the symmetries radia.TrfZerPerp(g, [0, 0, 0], [1, 0, 0]) radia.TrfZerPara(g, [0, 0, 0], [0, 0, 1]) return t
#Segmentation Params nx = 2 ny = 2 n1 = [nx, ny, 3] n2 = [nx, ny, 3] np3 = 2 nr3 = ny n4 = [nx, 3, ny] np5 = ceil(np3 / 2) print() nr5 = ny t0 = time() rad.UtiDelAll() ironmat = rad.MatSatIsoFrm([2000, 2], [0.1, 2], [0.1, 2]) g = Geom() size = rad.ObjDegFre(g) t1 = time() Nmax = 10000 res = rad.Solve(g, 0.00001, Nmax) t2 = time() Bz = rad.Fld(g, 'Bz', [0, 1, 0]) * 1000 Iz = rad.FldInt(g, 'inf', 'ibz', [-1, 1, 0], [1, 1, 0]) Iz1 = rad.FldInt(g, 'inf', 'ibz', [-1, 10, 0], [1, 10, 0]) / 10 print('M_Max H_Max N_Iter = ', round(res[1], 4), 'T', round(res[2], 4), 'T', round(res[3])) if (res[3] == Nmax): print('Unstable or Incomplete Relaxation')