def get_midplane_lcfs(self, psi_p=1.005): ''' Function for getting the inner and outer radial position of the LCFS at the midplane input: self, a reference to the object itself psi_p, the flux surface of the LCFS, standard is psi_p = 1.005 (otherwise the field-line is located inside the LCFS) return: Rcross, a list with the outer and inner radial position of the mid-plane LCFS ''' r_vec, z_vec = np.meshgrid(self.r_vec, self.z_vec) # Get contour cont = plt.contour(r_vec, z_vec, self.psi_n, [psi_p]) cont = cont.allsegs[0] # Loop over the contours for c_i in cont: is_core = any(c_i[:, 1] > 0) * any(c_i[:, 1] < 0) if is_core: func1 = np.array((c_i[:, 0], c_i[:, 1])) func2 = np.array( (np.array([0., np.max(r_vec)]), np.array([0., 0.]))) (_, _), (r_lcfs, _) = intersection(func1, func2) plt.close() # plt.contour opens a plot, close it return r_lcfs
def project_heat_flux(heat_flux_profile_omp, surface_position, equilibrium): ''' Function for projecting a heat flux from the OMP to a given surface (without taking diffusion into account) Input: heat_flux_profile_omp, a 2-by-n numpy array, where heat_flux_profile_omp[0] is the radial coordinates of each point at the OMP and heat_flux_profile_omp[1] is the parallel heat flux at the corresponding radial points surface_position, a 2-by-m numpy array with the surface_position[0] being the radial coordinates and surface_position[1] being the poloidal positions equilibrium, a string with the equilibrium to load, e.g. eq_0002 Return: heat_flux_at_intersection, a 3-by-n numpy array, where heat_flux_at_intersection[0] is the radial coordinates of each point at the target, heat_flux_at_intersection[1] is the vertical coordinates of each point at the target, and heat_flux_profile_omp[2] is the parallel heat flux at the corresponding positions ''' x_after_lcfs = heat_flux_profile_omp[0] equlibrium_file = '../fiesta/' + equilibrium if pathlib.Path(equlibrium_file + '.pickle').exists(): field_lines = load_pickle(equlibrium_file) else: field_lines = map_field_lines(x_after_lcfs, equlibrium_file) intersection_x = [] intersection_y = [] for i in field_lines: func1 = np.array((field_lines[i]['R'], field_lines[i]['Z'])) (_, _), (x_at_surface, y_at_surface) = intersection(func1, (surface_position)) if np.isnan(x_at_surface): break intersection_x.append(x_at_surface[0]) intersection_y.append(y_at_surface[0]) intersection_x = np.array(intersection_x) intersection_y = np.array(intersection_y) not_in_div = len(intersection_x) x_after_lcfs = x_after_lcfs[:not_in_div] f_x = np.zeros(not_in_div) dist_div = np.sqrt(np.square(intersection_x[1:]-intersection_x[:-1]) + np.square(intersection_y[1:]-intersection_y[:-1])) f_x[0:-1] = (dist_div)/(x_after_lcfs[1:]-x_after_lcfs[:-1]) f_x[-1] = f_x[-2] f_x = savgol_filter(f_x, 51, 3) q_div = x_after_lcfs/intersection_x * \ heat_flux_profile_omp[1, :not_in_div]/f_x heat_flux_at_intersection = np.array([intersection_x, intersection_y, q_div]) return heat_flux_at_intersection
def map_field_lines(x_vec_at_omp, file_path, configuration='diverted'): ''' Function for mapping each field-line to the intersection with the vessel walls Input: x_vec_at_omp, a numpy array with the radial points at the OMP where we want the mapping to start file_path, a string with the path to the FIESTA equilibrium .mat file configuration, a string with either 'limited' or 'diverted', where 'diverted' is the defualt configuration return: field_line_dict, a python dictionary with the radial position from the OMP in m as the key and the field-line dictionary with the R, phi and Z components along the field line as well as the length, l, from the LCFS to the current point along the field-line ''' field_line = FieldLine(file_path) field_line_dict = {} for i in x_vec_at_omp: field_lines = field_line.follow_field_in_plane(p_0=[i, 0, 0], max_length=10.0) func1 = np.array([field_lines["R"], field_lines["Z"]]) func2 = np.array([field_line.fiesta_equil.r_limiter, field_line.fiesta_equil.z_limiter]) (i_intersect_func1, _),\ (r_intersect, z_intersect) = intersection(func1, func2) if not np.any(np.isnan(r_intersect)): i_int = int(np.floor(i_intersect_func1)) i_first_intersect = np.argmin(field_lines["l"][i_int]) i_intersection = i_intersect_func1[i_first_intersect] i_intersection = int(np.ceil(i_intersection)) if configuration == 'limited': i_min_intersect = np.argmin(field_lines["R"][i_intersection] - r_intersect) i_intersection = np.where(field_lines["R"][:] < r_intersect[i_min_intersect])[0][0] elif configuration == 'diverted': i_min_intersect = np.argmin(field_lines["Z"][i_intersection] - z_intersect) i_intersection = np.where(field_lines["Z"][:] < z_intersect[i_min_intersect])[0][0] else: raise NotImplementedError("Error: unknown configuration.\ Please use either 'limited' or 'diverted'") field_lines["l"] = field_lines["l"][:i_intersection+1] field_lines["R"] = field_lines["R"][:i_intersection+1] field_lines["Z"] = field_lines["Z"][:i_intersection+1] field_lines["Vessel_Intersect"] = (r_intersect[i_min_intersect], z_intersect[i_min_intersect]) field_line_dict[i] = field_lines else: field_lines["Vessel_Intersect"] = (np.nan, np.nan) field_line_dict[i] = field_lines return field_line_dict
def project_field_lines(x_axis_omp, surface_coords, fiesta): ''' Function mapping the field-lines from the specified coordinates at the OMP to the specified coordinates at a given surface. Currently the surface is assumed to be represented by a 1D polynomial function, y = ax + b. Parameters ---------- x_axis_omp : n-x-1 np.array Numpy array with the radial coordinates we wish to map at the OMP fiesta : Fiesta A Fiesta object with the 2D equilibrium we wish to map divertor_coords : 2-x-2 np.array A 2-x-2 numpy array containg the corner points of the divertor in the 2D projection Returns ------- divertor_map : dictionary A dictionary containing: "R_div" : an n-x-1 array with the R-coordinates at the divertor tile corresponding to the same psi_n as at the OMP "Z_div" : an n-x-1 array with the Z-coordinates at the divertor tile corresponding to the same psi_n as at the OMP "Angles" : an n-x-1 array with the angles between the field lines and the divertor tile corresponding to the same psi_n as at the OMP "Flux_expansion" : an n-x-1 array with the flux expasion at the divertor tile corresponding to the same psi_n as at the OMP ''' # Interpolate b_pol (to be used when evaluating the flux expansion) b_pol = fiesta.b_theta.T b_pol_interp = Interpolate2DCubic(fiesta.r_vec, fiesta.z_vec, b_pol) field_lines = {} if os.path.exists("Random_filename"): field_lines = load_pickle("Random_filename") else: field_line = FieldLine(fiesta) for i in x_axis_omp: p_0 = [i, 0, 0] field_line_dict = field_line.follow_field_in_plane(p_0=p_0, max_length=15.0) field_lines[i] = field_line_dict _v_2 = np.array([ surface_coords[0, 1] - surface_coords[0, 0], surface_coords[1, 1] - surface_coords[1, 0] ]) divertor_map = {} for i in field_lines: func1 = np.array((field_lines[i]['R'], field_lines[i]['Z'])) (i_func1, _), (x_at_surface, y_at_surface) = intersection(func1, (surface_coords)) if np.isnan(x_at_surface): break _x_component = field_lines[i]['R'][int(i_func1)] - field_lines[i]['R'][ int(i_func1) + 1] _y_component = field_lines[i]['Z'][int(i_func1)] - field_lines[i]['Z'][ int(i_func1) + 1] _v_1 = [_x_component, _y_component] temp_dict = {} temp_dict["R_pos"] = x_at_surface[0] temp_dict["Z_pos"] = y_at_surface[0] temp_dict["alpha"] = calculate_angle(_v_1, _v_2) temp_dict["f_x"] = _flux_expansion(b_pol_interp, (i, 0), (x_at_surface[0], y_at_surface[0])) divertor_map[i] = temp_dict return divertor_map
#f.gca().set_aspect('equal', adjustable='box') #f.gca().set_ylim([-4,0]) #print (len(field_line_dict)) field_lines = [] for fl in field_line_dict: field_lines.append(np.array([fl['R'], fl['Z']])) divertor_points = 3 #divertor_x = np.linspace( 1.9, 2.45,divertor_points) #divertor_y = np.linspace(-3,-3.6,divertor_points) divertor_x = np.array([0.385, 0.425, 0.49]) divertor_y = np.array([-0.9, -0.75, -0.6]) divertor_xy = np.array([divertor_x, divertor_y]) result = np.array([intersection(i, divertor_xy) for i in field_lines]) (x_p, y_p) = zip(*result[:, 1]) for i in field_line_dict: plt.plot(i['R'], i['Z'], c='r') plt.plot(field_line.fiesta_equil.r_limiter, field_line.fiesta_equil.z_limiter) plt.plot(divertor_x, divertor_y, c='g') plt.plot(x_p, y_p, '*k') plt.gca().set_aspect('equal', adjustable='box') plt.gca().set_ylim([-1., -0.5]) plt.gca().set_xlim([0.0, 0.5]) imageFile = getOption('imageFile') if imageFile: plt.savefig(imageFile) else:
def map_psi(fiesta_equil, divertor_pos, nr_segments=1000, end_segment=1./10.): ''' Function for mapping the radial and poloidal positions to a given surface. Input: fiesta_equil, an object of the Fiesta class with the desired equilibrium divertor_pos, a 2-by-n numpy array with the coordinates for the surface we wish to calculate the intersection with, where divertor_pos[0] is the radial coordinates and divertor_pos[1] are the poloidal coordinates nr_segments, an integer with the number of contours we wish to evaluate, essentially giving the resolution end_segment, a float with the last psi_n you wish to evaluate, so e.g. end_segment = 1./10 will set the last contour to psi_n = 1.1 return: psi_map, a dictionary with: 'psi_n', the normalised flux surface position, 'R_omp', the radial position at the OMP, 'Z_omp', the vertical position at the OMP (all 0), 'R_div, the radial position of the intersection with the specified surface, 'Z_div', the radial position of the intersection with the specified surface ''' r_vec, z_vec = np.meshgrid(fiesta_equil.r_vec, fiesta_equil.z_vec) lcfs_psi_n = 1 psi_p = [] for i in range(nr_segments): psi_p.append(lcfs_psi_n+i/nr_segments*end_segment) cont = plt.contour(r_vec, z_vec, fiesta_equil.psi_n, psi_p) cont = cont.allsegs # plt.close() r_omp = [] z_omp = [] omp_pos = np.array((np.array([0.0, 1.0]), np.array([0.0, 0.0]))) r_div = [] z_div = [] psi = [] i = 0 for c_i in cont: c_i = c_i[0] is_core = any(c_i[:, 1] > 0)*any(c_i[:, 1] < 0) if is_core: psi_contour = np.array((c_i[:, 0], c_i[:, 1])) (_, _), (r_omp_intersect, z_omp_intersect) = intersection(psi_contour, omp_pos) (_, _), (r_div_intersect, z_div_intersect) = intersection(psi_contour, divertor_pos) r_omp.append(r_omp_intersect[1]) z_omp.append(z_omp_intersect[1]) r_div.append(r_div_intersect) z_div.append(z_div_intersect) psi.append(psi_p[i]) i += 1 psi_map = {} psi_map['R_div'] = r_div psi_map['Z_div'] = z_div psi_map['R_omp'] = r_omp psi_map['Z_omp'] = z_omp psi_map['psi_n'] = psi return psi_map
#f.gca().set_aspect('equal', adjustable='box') #f.gca().set_ylim([-4,0]) #print (len(field_line_dict)) field_lines = [] for fl in field_line_dict: field_lines.append( np.array([ fl['R'], fl['Z'] ]) ) divertor_points = 3 #divertor_x = np.linspace( 1.9, 2.45,divertor_points) #divertor_y = np.linspace(-3,-3.6,divertor_points) divertor_x = np.array([1.2, 1.2, 1.15]) divertor_y = np.array([-1.5, -1.7, -2.05]) divertor_xy = np.array([divertor_x, divertor_y]) result = [intersection(i, divertor_xy) for i in field_lines] x_p,y_p = zip (*result) for i in field_line_dict: plt.plot(i['R'],i['Z'],c='r') plt.plot(divertor_x,divertor_y,c='g') #plt.plot(x_p,y_p,'*k') plt.gca().set_aspect('equal', adjustable='box') #plt.gca().set_ylim([-4,-2.5]) plt.show(block=True) print(midplane_range) fx = [] for i in range(len(midplane_range)-1): fx.append( math.hypot(x_p[i+1] - x_p[i], y_p[i+1] - y_p[i]) / ( midplane_range[i+1] - midplane_range[i] ) *