def read_field_circ(filename, iteration, field, coord, slice_relative_position, slice_across, units, m=0, theta=0.): """ Extract a given field from an HDF5 file in the openPMD format, when the geometry is thetaMode Parameters ---------- filename : string The absolute path to the HDF5 file iteration : int The iteration at which to obtain the data field : string, optional Which field to extract coord : string, optional Which component of the field to extract m : int or string, optional The azimuthal mode to be extracted theta : float or None Angle of the plane of observation with respect to the x axis If `theta` is not None, then this function returns a 2D array corresponding to the plane of observation given by `theta` ; otherwise it returns a full 3D Cartesian array slice_across : list of str or None Direction(s) across which the data should be sliced Elements can be 'r' and/or 'z' Returned array is reduced by 1 dimension per slicing. slice_relative_position : list of float or None Number(s) between -1 and 1 that indicate where to slice the data, along the directions in `slice_across` -1 : lower edge of the simulation box 0 : middle of the simulation box 1 : upper edge of the simulation box units: string Type of units to be used for data reading. Returns ------- A tuple with F : a 3darray or 2darray containing the required field, depending on whether `theta` is None or not info : a FieldMetaInformation object (contains information about the grid; see the corresponding docstring) """ # Open the HDF5 file dfile = h5py.File(filename, 'r') # Extract the dataset and and corresponding group if coord is None: field_path = field else: field_path = join_infile_path(field, coord) group, dset = find_dataset(dfile, iteration, field_path) # Extract the metainformation Nm, Nr, Nz = get_shape(dset) info = FieldMetaInformation({ 0: 'r', 1: 'z' }, (Nr, Nz), group.attrs['gridSpacing'], group.attrs['gridGlobalOffset'], group.attrs['gridUnitSI'], dset.attrs['position'], thetaMode=True) # Convert to a 3D Cartesian array if theta is None if theta is None: # Get cylindrical info rmax = info.rmax inv_dr = 1. / info.dr Fcirc = get_data(dset, units) # (Extracts all modes) nr = Fcirc.shape[1] if m == 'all': modes = [mode for mode in range(0, int(Nm / 2) + 1)] else: modes = [m] modes = np.array(modes, dtype='int') nmodes = len(modes) # Convert cylindrical data to Cartesian data info._convert_cylindrical_to_3Dcartesian() nx, ny, nz = len(info.x), len(info.y), len(info.z) F_total = np.zeros((nx, ny, nz)) construct_3d_from_circ(F_total, Fcirc, info.x, info.y, modes, nx, ny, nz, nr, nmodes, inv_dr, rmax) else: # Extract the modes and recombine them properly F_total = np.zeros((2 * Nr, Nz)) if m == 'all': # Sum of all the modes # - Prepare the multiplier arrays mult_above_axis = [1] mult_below_axis = [1] for mode in range(1, int(Nm / 2) + 1): cos = np.cos(mode * theta) sin = np.sin(mode * theta) mult_above_axis += [cos, sin] mult_below_axis += [(-1)**mode * cos, (-1)**mode * sin] mult_above_axis = np.array(mult_above_axis) mult_below_axis = np.array(mult_below_axis) # - Sum the modes F = get_data(dset, units) # (Extracts all modes) F_total[Nr:, :] = np.tensordot(mult_above_axis, F, axes=(0, 0))[:, :] F_total[:Nr, :] = np.tensordot(mult_below_axis, F, axes=(0, 0))[::-1, :] elif m == 0: # Extract mode 0 F = get_data(dset, units, 0, 0) F_total[Nr:, :] = F[:, :] F_total[:Nr, :] = F[::-1, :] else: # Extract higher mode cos = np.cos(m * theta) sin = np.sin(m * theta) F_cos = get_data(dset, units, 2 * m - 1, 0) F_sin = get_data(dset, units, 2 * m, 0) F = cos * F_cos + sin * F_sin F_total[Nr:, :] = F[:, :] F_total[:Nr, :] = (-1)**m * F[::-1, :] # Perform slicing if needed if slice_across is not None: # Slice field and clear metadata inverted_axes_dict = {info.axes[key]: key for key in info.axes.keys()} for count, slice_across_item in enumerate(slice_across): slicing_index = inverted_axes_dict[slice_across_item] coord_array = getattr(info, slice_across_item) # Number of cells along the slicing direction n_cells = len(coord_array) # Index of the slice (prevent stepping out of the array) i_cell = int(0.5 * (slice_relative_position[count] + 1.) * n_cells) i_cell = max(i_cell, 0) i_cell = min(i_cell, n_cells - 1) F_total = np.take(F_total, [i_cell], axis=slicing_index) F_total = np.squeeze(F_total) # Remove the sliced labels from the FieldMetaInformation for slice_across_item in slice_across: info._remove_axis(slice_across_item) # Close the file dfile.close() return (F_total, info)
def read_field_circ( series, iteration, field_name, component_name, slice_relative_position, slice_across, m=0, theta=0., max_resolution_3d=None ): """ Extract a given field from a file in the openPMD format, when the geometry is thetaMode Parameters ---------- series: openpmd_api.Series An open, readable openPMD-api series object iteration: integer Iteration from which parameters should be extracted field_name : string, optional Which field to extract component_name : string, optional Which component of the field to extract m : int or string, optional The azimuthal mode to be extracted theta : float or None Angle of the plane of observation with respect to the x axis If `theta` is not None, then this function returns a 2D array corresponding to the plane of observation given by `theta` ; otherwise it returns a full 3D Cartesian array slice_across : list of str or None Direction(s) across which the data should be sliced Elements can be 'r' and/or 'z' Returned array is reduced by 1 dimension per slicing. slice_relative_position : list of float or None Number(s) between -1 and 1 that indicate where to slice the data, along the directions in `slice_across` -1 : lower edge of the simulation box 0 : middle of the simulation box 1 : upper edge of the simulation box max_resolution_3d : list of int or None Maximum resolution that the 3D reconstruction of the field (when `theta` is None) can have. The list should contain two values, e.g. `[200, 100]`, indicating the maximum longitudinal and transverse resolution, respectively. This is useful for performance reasons, particularly for 3D visualization. Returns ------- A tuple with F : a 3darray or 2darray containing the required field, depending on whether `theta` is None or not info : a FieldMetaInformation object (contains information about the grid; see the corresponding docstring) """ it = series.iterations[iteration] # Extract the dataset and and corresponding group field = it.meshes[field_name] if field.scalar: component = next(field.items())[1] else: component = field[component_name] # Extract the metainformation # FIXME here and in h5py reader, we need to invert the order on 'F' for # grid spacing/offset/position Nm, Nr, Nz = component.shape info = FieldMetaInformation( { 0: 'r', 1: 'z' }, (Nr, Nz), field.grid_spacing, field.grid_global_offset, field.grid_unit_SI, component.position, thetaMode=True ) # Convert to a 3D Cartesian array if theta is None if theta is None: # Get cylindrical info rmax = info.rmax inv_dr = 1./info.dr Fcirc = get_data( series, component ) # (Extracts all modes) nr = Fcirc.shape[1] if m == 'all': modes = [ mode for mode in range(0, int(Nm / 2) + 1) ] else: modes = [ m ] modes = np.array( modes, dtype='int' ) nmodes = len(modes) # If necessary, reduce resolution of 3D reconstruction if max_resolution_3d is not None: max_res_lon, max_res_transv = max_resolution_3d if Nz > max_res_lon: # Calculate excess of elements along z excess_z = int(np.round(Nz/max_res_lon)) # Preserve only one every excess_z elements Fcirc = Fcirc[:, :, ::excess_z] # Update info accordingly info.z = info.z[::excess_z] info.dz = info.z[1] - info.z[0] if nr > max_res_transv/2: # Calculate excess of elements along r excess_r = int(np.round(nr/(max_res_transv/2))) # Preserve only one every excess_r elements Fcirc = Fcirc[:, ::excess_r, :] # Update info and necessary parameters accordingly info.r = info.r[::excess_r] info.dr = info.r[1] - info.r[0] inv_dr = 1./info.dr nr = Fcirc.shape[1] # Convert cylindrical data to Cartesian data info._convert_cylindrical_to_3Dcartesian() nx, ny, nz = len(info.x), len(info.y), len(info.z) F_total = np.zeros( (nx, ny, nz) ) construct_3d_from_circ( F_total, Fcirc, info.x, info.y, modes, nx, ny, nz, nr, nmodes, inv_dr, rmax ) else: # Extract the modes and recombine them properly F_total = np.zeros( (2 * Nr, Nz ) ) if m == 'all': # Sum of all the modes # - Prepare the multiplier arrays mult_above_axis = [1] mult_below_axis = [1] for mode in range(1, int(Nm / 2) + 1): cos = np.cos( mode * theta ) sin = np.sin( mode * theta ) mult_above_axis += [cos, sin] mult_below_axis += [ (-1) ** mode * cos, (-1) ** mode * sin ] mult_above_axis = np.array( mult_above_axis ) mult_below_axis = np.array( mult_below_axis ) # - Sum the modes F = get_data( series, component ) # (Extracts all modes) F_total[Nr:, :] = np.tensordot( mult_above_axis, F, axes=(0, 0) )[:, :] F_total[:Nr, :] = np.tensordot( mult_below_axis, F, axes=(0, 0) )[::-1, :] elif m == 0: # Extract mode 0 F = get_data( series, component, 0, 0 ) F_total[Nr:, :] = F[:, :] F_total[:Nr, :] = F[::-1, :] else: # Extract higher mode cos = np.cos( m * theta ) sin = np.sin( m * theta ) F_cos = get_data( series, component, 2 * m - 1, 0 ) F_sin = get_data( series, component, 2 * m, 0 ) F = cos * F_cos + sin * F_sin F_total[Nr:, :] = F[:, :] F_total[:Nr, :] = (-1) ** m * F[::-1, :] # Perform slicing if needed if slice_across is not None: # Slice field and clear metadata inverted_axes_dict = {info.axes[key]: key for key in info.axes.keys()} for count, slice_across_item in enumerate(slice_across): slicing_index = inverted_axes_dict[slice_across_item] coord_array = getattr( info, slice_across_item ) # Number of cells along the slicing direction n_cells = len(coord_array) # Index of the slice (prevent stepping out of the array) i_cell = int( 0.5 * (slice_relative_position[count] + 1.) * n_cells ) i_cell = max( i_cell, 0 ) i_cell = min( i_cell, n_cells - 1) F_total = np.take( F_total, [i_cell], axis=slicing_index ) F_total = np.squeeze(F_total) # Remove the sliced labels from the FieldMetaInformation for slice_across_item in slice_across: info._remove_axis(slice_across_item) return F_total, info
def read_field_circ(filename, iteration, field, coord, slice_relative_position, slice_across, m=0, theta=0., max_resolution_3d=None): """ Extract a given field from an HDF5 file in the openPMD format, when the geometry is thetaMode Parameters ---------- filename : string The absolute path to the HDF5 file iteration : int The iteration at which to obtain the data field : string, optional Which field to extract coord : string, optional Which component of the field to extract m : int or string, optional The azimuthal mode to be extracted theta : float or None Angle of the plane of observation with respect to the x axis If `theta` is not None, then this function returns a 2D array corresponding to the plane of observation given by `theta` ; otherwise it returns a full 3D Cartesian array slice_across : list of str or None Direction(s) across which the data should be sliced Elements can be 'r' and/or 'z' Returned array is reduced by 1 dimension per slicing. slice_relative_position : list of float or None Number(s) between -1 and 1 that indicate where to slice the data, along the directions in `slice_across` -1 : lower edge of the simulation box 0 : middle of the simulation box 1 : upper edge of the simulation box max_resolution_3d : list of int or None Maximum resolution that the 3D reconstruction of the field (when `theta` is None) can have. The list should contain two values, e.g. `[200, 100]`, indicating the maximum longitudinal and transverse resolution, respectively. This is useful for performance reasons, particularly for 3D visualization. Returns ------- A tuple with F : a 3darray or 2darray containing the required field, depending on whether `theta` is None or not info : a FieldMetaInformation object (contains information about the grid; see the corresponding docstring) """ # Open the HDF5 file dfile = h5py.File(filename, 'r') # Extract the dataset and and corresponding group if coord is None: field_path = field else: field_path = join_infile_path(field, coord) group, dset = find_dataset(dfile, iteration, field_path) # Extract the metainformation coord_labels = { ii: coord.decode() for (ii, coord) in enumerate(group.attrs['axisLabels']) } if coord_labels[0] == 'r': rz_switch = False # fastest varying index is z Nm, Nr, Nz = get_shape(dset) N_pair = (Nr, Nz) else: rz_switch = True # fastest varying index is r Nm, Nz, Nr = get_shape(dset) N_pair = (Nz, Nr) info = FieldMetaInformation(coord_labels, N_pair, group.attrs['gridSpacing'], group.attrs['gridGlobalOffset'], group.attrs['gridUnitSI'], dset.attrs['position'], thetaMode=True) # Convert to a 3D Cartesian array if theta is None if theta is None: # Get cylindrical info rmax = info.rmax inv_dr = 1. / info.dr Fcirc = get_data(dset) # (Extracts all modes) if m == 'all': modes = [mode for mode in range(0, int(Nm / 2) + 1)] else: modes = [m] modes = np.array(modes, dtype='int') nmodes = len(modes) # If necessary, reduce resolution of 3D reconstruction if max_resolution_3d is not None: max_res_lon, max_res_transv = max_resolution_3d if Nz > max_res_lon: # Calculate excess of elements along z excess_z = int(np.round(Nz / max_res_lon)) # Preserve only one every excess_z elements if not rz_switch: Fcirc = Fcirc[:, :, ::excess_z] else: Fcirc = Fcirc[:, ::excess_z, :] # Update info accordingly info.z = info.z[::excess_z] info.dz = info.z[1] - info.z[0] if Nr > max_res_transv / 2: # Calculate excess of elements along r excess_r = int(np.round(Nr / (max_res_transv / 2))) # Preserve only one every excess_r elements if not rz_switch: Fcirc = Fcirc[:, ::excess_r, :] else: Fcirc = Fcirc[:, :, ::excess_r] # Update info and necessary parameters accordingly info.r = info.r[::excess_r] info.dr = info.r[1] - info.r[0] inv_dr = 1. / info.dr # Convert cylindrical data to Cartesian data info._convert_cylindrical_to_3Dcartesian() nx, ny, nz = len(info.x), len(info.y), len(info.z) F_total = np.zeros((nx, ny, nz)) construct_3d_from_circ(F_total, Fcirc, info.x, info.y, modes, nx, ny, nz, Nr, nmodes, inv_dr, rmax, rz_switch=rz_switch) else: # Extract the modes and recombine them properly if not rz_switch: F_total = np.zeros((2 * Nr, Nz)) else: F_total = np.zeros((Nz, 2 * Nr)) if m == 'all': # Sum of all the modes # - Prepare the multiplier arrays mult_above_axis = [1] mult_below_axis = [1] for mode in range(1, int(Nm / 2) + 1): cos = np.cos(mode * theta) sin = np.sin(mode * theta) mult_above_axis += [cos, sin] mult_below_axis += [(-1)**mode * cos, (-1)**mode * sin] mult_above_axis = np.array(mult_above_axis) mult_below_axis = np.array(mult_below_axis) # - Sum the modes F = get_data(dset) # (Extracts all modes) if not rz_switch: F_total[Nr:, :] = np.tensordot(mult_above_axis, F, axes=(0, 0))[:, :] F_total[:Nr, :] = np.tensordot(mult_below_axis, F, axes=(0, 0))[::-1, :] else: F_total[:, Nr:] = np.tensordot(mult_above_axis, F, axes=(0, 0))[:, :] F_total[:, :Nr] = np.tensordot(mult_below_axis, F, axes=(0, 0))[:, ::-1] elif m == 0: # Extract mode 0 F = get_data(dset, 0, 0) if not rz_switch: F_total[Nr:, :] = F[:, :] F_total[:Nr, :] = F[::-1, :] else: F_total[:, Nr:] = F[:, :] F_total[:, :Nr] = F[:, ::-1] else: # Extract higher mode cos = np.cos(m * theta) sin = np.sin(m * theta) F_cos = get_data(dset, 2 * m - 1, 0) F_sin = get_data(dset, 2 * m, 0) F = cos * F_cos + sin * F_sin if not rz_switch: F_total[Nr:, :] = F[:, :] F_total[:Nr, :] = (-1)**m * F[::-1, :] else: F_total[:, Nr:] = F[:, :] F_total[:, :Nr] = (-1)**m * F[:, ::-1] # Perform slicing if needed if slice_across is not None: # Slice field and clear metadata inverted_axes_dict = {info.axes[key]: key for key in info.axes.keys()} for count, slice_across_item in enumerate(slice_across): slicing_index = inverted_axes_dict[slice_across_item] coord_array = getattr(info, slice_across_item) # Number of cells along the slicing direction n_cells = len(coord_array) # Index of the slice (prevent stepping out of the array) i_cell = int(0.5 * (slice_relative_position[count] + 1.) * n_cells) i_cell = max(i_cell, 0) i_cell = min(i_cell, n_cells - 1) F_total = np.take(F_total, [i_cell], axis=slicing_index) F_total = np.squeeze(F_total) # Remove the sliced labels from the FieldMetaInformation for slice_across_item in slice_across: info._remove_axis(slice_across_item) # Close the file dfile.close() return (F_total, info)