Ejemplo n.º 1
0
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)
Ejemplo n.º 2
0
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
Ejemplo n.º 3
0
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)