def main():
    if len(sys.argv) > 1:
        mode = sys.argv[1]
    else:
        mode = 'sim'

    minrad = 0.2
    maxrad = 0.4
    radstep = 0.05
    numsteps = int((maxrad - minrad) / radstep + 1.5)
    steps = np.linspace(minrad, maxrad, num=numsteps, endpoint=True)

    for i, radius in enumerate(steps):

        log.info(
            "running simulation with {0:n} radius steps:\n{1}".format(
                numsteps, steps) +
            '\n  ### current step: #{0} ({1}) ###\n'.format(i + 1, radius))

        sim = TriHoles2D(
            material='SiN',
            radius=radius,
            numbands=4,  #8,
            k_interpolation=5,  #31, 
            resolution=16,
            mesh_size=7,
            runmode=mode,
            num_processors=2,
            save_field_patterns=True,
            convert_field_patterns=True)

        if not sim:
            log.error('an error occurred during simulation. See the .out file')
            return

        # load te mode band data:
        fname = path.join(sim.workingdir, sim.jobname + '_tefreqs.csv')
        data = np.loadtxt(fname, delimiter=',', skiprows=1)
        gapbands = get_gap_bands(data[:, 5:])

        # maybe there is no gap?
        if len(gapbands) == 0:
            gap = 0
        elif gapbands[0][0] != 1:
            # it must be a gap between band 1 and 2
            gap = 0
        else:
            gap = gapbands[0][3]

        # save gap sizes to file (first TE gap):
        with open("gaps.dat", "a") as f:
            f.write("{0}\t{1}\n".format(radius, gap))

        log.info(' ##### radius={0} - success! #####\n\n'.format(radius))

        # reset logger; the next stuff logged is going to next step's file:
        log.reset_logger()

    data = np.loadtxt('gaps.dat')
    fig = plt.figure()
    ax = fig.add_subplot(111)
    ax.plot(data[:, 0], data[:, 1], 'o-')
    fig.savefig('gaps.png')
Example #2
0
def draw_bands(jobname,
               modes,
               x_axis_hint=default_x_axis_hint,
               custom_plotter=None,
               title='',
               crop_y=True,
               band_gaps=True,
               light_cone=False,
               projected_bands=False,
               mask_proj_bands_above_light_line=False,
               add_epsilon_as_inset=False,
               color_by_parity=False,
               interactive_mode=False):
    """Plot dispersion relation of all bands calculated along all k
    vectors.

    :param jobname: The band data is loaded from previously saved .csv
    files. (filenames: [*jobname* + '_' + *mode* + 'freqs.csv' for mode
    in modes])
    :param modes: see *jobname*
    :param x_axis_hint: gives a hint on which kind of ticks and labels
    should be shown on the x-axis and provides the data needed.
    *x_axis_hint* can be one of the following:
        -- integer number:
            The axis' labels will be the 3D k-vectors. The number
            denotes the number of major ticks and labels distributed on
            the axis.
        -- [integer, format-string]:
            Same as above, but the labels are formatted with the
            format-string - this gives the possibility to only show one
            of the three vector components, e.g. the string "{2}" to
            only show the k-vector's z-component. The axis title will be
            inferred from the format-string.
        -- KSpace object:
            This must be a KSpace object created with point_labels.
            These labels usually denote the high symmetry or crititical
            points, and they will be shown on the axis.
        -- CustomAxisFormatter object:
            This gives the possibility to completely customize the
            x-axis' tick positions, tick labels and axis label. If the
            CustomAxisFormatter's hover data have not been set, it will
            be set here with the k-vectors read from the .csv file.

    :param custom_plotter: If you want to add the graph to an existing
    figure, supply a BandPlotter with *custom_plotter*, otherwise
    (default: custom_plotter=None) a new BandPlotter is created and
    returned.
    :param title: the subplot's title.
    :param crop_y: If this is true (default), the y-axis (frequency)
    will be limited so that only frequency values are shown where all
    bands are known. Alternatively, a numeric value of *crop_y* denotes
    the upper frequency value where the plot will be cropped, or if
    *crop_y* is a 2-tuple, it denotes the minimum and maximum y-value.
    :param band_gaps: If True, draw the band gaps (with colored boxes).
    :param light_cone: If True, add a light cone and crop the bandgaps
    at the light line. If the simulation was run on a substrate,
    light_cone must be the index of the refraction of this substrate.
    The light cone will then be scaled accordingly.
    :param projected_bands: If True, add bands that span a range of
    frequencies to the plot. Bandgaps are not drawn in this case. The
    data needed will be read from previously saved .csv files
    (filenames: [ jobname* + '_' + *mode* + '_projected.csv' for mode in
    modes]).
    :param mask_proj_bands_above_light_line: If *projected_bands* is
    True, some projected bands might be completely above the light line.
    These bands will not be drawn, if *mask_proj_bands_above_light_line*
    is True.
    :param add_epsilon_as_inset: epsilon,png will be added as inset. See
    defaults.py for parameters like size and location.
    :param color_by_parity: Specify 'y' or 'z' to color the plot lines
    with the data taken from the parity files
    <jobname>_<mode>[z/y]parity.csv.
    :param interactive_mode: This is useful if the plot is not intended for
    saving, but for showing on the screen. Then defaults.default_onclick()
    will be called if the user clicks on a graph in the figure.
    :return: a created BandPlotter instance (if *custom_plotter*) was
    None, or the *custom_plotter*.

    """
    if custom_plotter is None:
        plotter = BandPlotter(figure_size=defaults.fig_size)
    else:
        plotter = custom_plotter
        plotter.next_plot()

    refr_index = 1 if isinstance(light_cone, bool) else light_cone

    x_axis_formatter = None
    if isinstance(x_axis_hint, axis_formatter.CustomAxisFormatter):
        # use the supplied CustomAxisFormatter:
        x_axis_formatter = x_axis_hint
    elif isinstance(x_axis_hint, KSpace):
        # make a KSpaceAxisFormatter instance from kspace object:
        x_axis_formatter = axis_formatter.KSpaceAxisFormatter(x_axis_hint)
    elif isinstance(x_axis_hint, int):
        # make a standard KVectorAxisFormatter with supplied number of ticks:
        x_axis_formatter = axis_formatter.KVectorAxisFormatter(x_axis_hint)
    else:
        num = 0
        hintlen = 0
        if hasattr(x_axis_hint, '__len__'):
            hintlen = len(x_axis_hint)
        else:
            # no sequence
            try:
                # is this a number?
                num = int(x_axis_hint)
            except ValueError:
                # no number
                pass
        if hintlen > 1 and (isinstance(x_axis_hint[0], int)
                            and hasattr(x_axis_hint[1], 'format')):
            # Supplied a list with at least an int and format_str.
            # Use all items in list as KVectorAxisFormatter arguments:
            x_axis_formatter = axis_formatter.KVectorAxisFormatter(
                *x_axis_hint)
        elif num > 0:
            # make a standard KVectorAxisFormatter with supplied number
            # of ticks:
            x_axis_formatter = axis_formatter.KVectorAxisFormatter(num)
    if x_axis_formatter is None:
        log.warning('draw_bands: Did not understand x_axis_hint, '
                    'using default.')
        x_axis_formatter = axis_formatter.KVectorAxisFormatter(
            default_x_axis_hint)

    for i, mode in enumerate(modes):
        fname = '{0}_{1}freqs.csv'.format(jobname, mode)
        data = loadtxt(fname, delimiter=',', skiprows=1)

        # add hover data:
        if x_axis_formatter._hover_func_is_default:
            x_axis_formatter.set_hover_data(data[:, 1:4])

        parities = None
        if color_by_parity:
            # try to load parity file:
            fname = '{0}_{1}{2}parity.csv'.format(jobname, mode,
                                                  color_by_parity)
            try:
                # load data, ignore first column with band numbers:
                parities = loadtxt(fname, delimiter=',')[:, 1:]
            except IOError:
                parities = None

        plotter.plot_bands(data[:, 5:],
                           data[:, 1:5],
                           formatstr=defaults.draw_bands_formatstr,
                           x_axis_formatter=x_axis_formatter,
                           label=mode.upper(),
                           crop_y=crop_y,
                           picker=interactive_mode * 3,
                           color_by_parity=parities,
                           **defaults.draw_bands_kwargs)

        if projected_bands:
            fname = '{0}_{1}_projected.csv'.format(jobname, mode)
            with np.warnings.catch_warnings():
                # ignore numpy warning if the file does not contain any
                # data, just return empty ndarray:
                np.warnings.simplefilter("ignore")
                projdata = loadtxt(fname, delimiter=',', ndmin=2)
            if projdata.shape[0] != 0:
                if projdata.shape[1] % 2 != 0:
                    # knums added in first column, drop it:
                    projdata = projdata[:, 1:]

                if light_cone and mask_proj_bands_above_light_line:
                    # ignore projected bands above the light line:
                    mask = np.zeros_like(projdata, dtype=np.bool)
                    numbands = projdata.shape[1] // 2
                    for i in range(numbands):
                        if (projdata[:, 2 * i] >
                                data[:, 4] / refr_index).all():
                            mask[:, 2 * i:2 * i + 2] = True
                    projdata = np.ma.array(projdata, mask=mask)

                if projdata.shape[0] == 1 and data.shape[0] != 1:
                    # the same band ranges for all k-vecs:
                    newproj = np.empty((data.shape[0], projdata.shape[1]))
                    newproj[None, :] = projdata
                    projdata = newproj

                plotter.add_continuum_bands(projdata)
        if band_gaps:
            if light_cone:
                gapbands = get_gap_bands(data[:, 5:],
                                         light_line=data[:, 4] / refr_index)
            else:
                gapbands = get_gap_bands(data[:, 5:])
            for band in gapbands:
                plotter.add_band_gap_rectangle(
                    band[1],
                    band[2],
                    light_line=data[:, 4] / refr_index if light_cone else None)

    if light_cone:
        plotter.add_light_cone(refr_index)

    plotter.set_plot_title(title)

    if len(modes) > 1 or (len(modes) == 1 and modes[0] != ''):
        plotter.add_legend()

    if color_by_parity:
        plotter.add_color_bar_for_parity(parity_direction=color_by_parity)

    if add_epsilon_as_inset:
        fname = path.join(path.split(jobname)[0], 'epsilon.png')
        if path.isfile(fname):
            plotter.add_image_inset(fname,
                                    loc=defaults.epsilon_inset_location,
                                    zoom=defaults.epsilon_inset_zoom,
                                    transpose=defaults.epsilon_inset_transpose)

    return plotter
Example #3
0
def main():
    if len(sys.argv) > 1:
        mode=sys.argv[1]
    else:
        mode='sim'
    minrad = 0.2
    maxrad = 0.4
    radstep = 0.05
    numsteps = int((maxrad - minrad) / radstep + 1.5)
    steps = np.linspace(minrad, maxrad, num=numsteps, endpoint=True)
    
    for i, radius in enumerate(steps):

        log.info("running simulation with {0:n} radius steps:\n{1}".format(
            numsteps, steps) +
            '\n  ### current step: #{0} ({1}) ###\n'.format(i+1, radius))

        sim = TriHolesSlab3D(
            material='SiN',
            radius=radius,
            thickness=0.8,
            numbands=4,#8,
            k_interpolation=5,#31,
            resolution=16,#32,
            mesh_size=3,#7,
            supercell_z=6,
            runmode=mode,
            num_processors=2,
            save_field_patterns=True,
            convert_field_patterns=True)
        
        if not sim:
            log.error('an error occurred during simulation. See the .out file')
            return
    
        # load zeven mode band data:
        fname = path.join(sim.workingdir, sim.jobname + '_zevenfreqs.csv')
        data = np.loadtxt(fname, delimiter=',', skiprows=1)
        gapbands = get_gap_bands(data[:, 5:], light_line=data[:, 4])

        # maybe there is no gap?
        if len(gapbands) == 0:
            gap = 0
        elif gapbands[0][0] != 1:
            # it must be a gap between band 1 and 2
            gap = 0
        else:
            gap = gapbands[0][3]

        # save gap sizes to file (first TE gap):
        with open("gaps.dat", "a") as f:
            f.write("{0}\t{1}\n".format(radius, gap))
    
        log.info(' ##### radius={0} - success! #####\n\n'.format(radius))

        # reset logger; the next stuff logged is going to next step's file:
        log.reset_logger()
        
    data = np.loadtxt('gaps.dat')
    fig = plt.figure()
    ax = fig.add_subplot(111)
    ax.plot(data[:,0], data[:,1], 'o-')
    fig.savefig('gaps.png')
Example #4
0
def main():
    if len(sys.argv) > 1:
        mode=sys.argv[1]
    else:
        mode='sim'
    minstep = 1
    maxstep = 8.0
    stepsize = 0.5
    numsteps = int((maxstep - minstep) / stepsize + 1.5)
    steps = np.linspace(minstep, maxstep, num=numsteps, endpoint=True)
    # save previous step's data, needed for comparison with current data:
    prev_step_data = None

    for i, step in enumerate(steps):

        log.info("running simulation with {0:n} supercell height steps:\n{1}".format(
            numsteps, steps) +
            '\n  ### current step: #{0} ({1}) ###\n'.format(i+1, step))


        ### create and run simulation (according to mode) ###

        sim = TriHolesSlab3D(
            material='SiN',
            radius=0.375,
            thickness=0.8,
            numbands=8,
            k_interpolation=31,
            resolution=32,
            mesh_size=7,
            supercell_z=step,
            runmode=mode,
            num_processors=8,
            save_field_patterns=True,
            convert_field_patterns=True,
            job_name_suffix='_sct{0:03.0f}'.format(step*10),
            bands_title_appendix=', supercell thickness={0:02.1f}'.format(step))
        
        if not sim:
            log.error('an error occurred during simulation. See the .out file')
            return


        ### load some data ###

        # load zeven mode band data:
        fname = path.join(sim.workingdir, sim.jobname + '_zevenfreqs.csv')
        data = np.loadtxt(fname, delimiter=',', skiprows=1)
        gapbands = get_gap_bands(data[:, 5:], light_line=data[:, 4])


        ### save comparison data to file ###

        # If this is not the first step, we have previous data to compare
        # with:
        if prev_step_data is not None:
            sums = []
            # compare the first 3 zeven bands:
            for j in range(3):
                sums.append(
                    sum_of_squares(
                        prev_step_data[:, 5 + j],
                        data[:, 5 + j],
                        data[:, 4]
                    )
                )
            with open("sum_of_squares.dat", "a") as f:
                f.write('\t'.join([str(step)] + map(str, sums)) + '\n')
        # save data for next iteration:
        prev_step_data = data


        ### save the gap to file ###

        # maybe there is no gap?
        if len(gapbands) == 0:
            gap = 0
        elif gapbands[0][0] != 1:
            # it must be a gap between band 1 and 2
            gap = 0
        else:
            gap = gapbands[0][3]

        # save gap sizes to file (first z-even gap):
        with open("gaps.dat", "a") as f:
            f.write("{0}\t{1}\n".format(step, gap))
    


        log.info(' ##### step={0} - success! #####\n\n'.format(step))

        # reset logger; the next stuff logged is going to next step's file:
        log.reset_logger()

    ### finally, save some plots ###

    data = np.loadtxt('sum_of_squares.dat')
    fig = plt.figure()
    ax = fig.add_subplot(111)
    # make double-logarithmic plot for every band:
    for i in range(data.shape[1] -1):
        ax.loglog(data[:,0], data[:,i + 1], 'o-',
                  label='band {0}'.format(i+1))

    compdata = np.power(data[:,0], -2)
    ax.loglog(data[:,0], compdata, '.:', label='$x^{-2}$')
    compdata = np.power(data[:,0], -4)
    ax.loglog(data[:,0], compdata, '.:', label='$x^{-4}$')
    compdata = np.power(data[:,0], -6)
    ax.loglog(data[:,0], compdata, '.:', label='$x^{-6}$')
    plt.legend()
    plt.title('sum of squared differences between simulation steps')
    fig.savefig('sum_of_squares.png')

    data = np.loadtxt('gaps.dat')
    fig = plt.figure()
    ax = fig.add_subplot(111)
    ax.plot(data[:,0], data[:,1], 'o-')
    plt.title('First z-even band gap for each simulation step')
    fig.savefig('gaps.png')
Example #5
0
def draw_bands(
        jobname, modes, x_axis_hint=default_x_axis_hint,
        custom_plotter=None, title='', crop_y=True,
        band_gaps=True, light_cone=False, projected_bands=False,
        mask_proj_bands_above_light_line=False,
        add_epsilon_as_inset=False, color_by_parity=False,
        interactive_mode=False):
    """Plot dispersion relation of all bands calculated along all k
    vectors.

    :param jobname: The band data is loaded from previously saved .csv
    files. (filenames: [*jobname* + '_' + *mode* + 'freqs.csv' for mode
    in modes])
    :param modes: see *jobname*
    :param x_axis_hint: gives a hint on which kind of ticks and labels
    should be shown on the x-axis and provides the data needed.
    *x_axis_hint* can be one of the following:
        -- integer number:
            The axis' labels will be the 3D k-vectors. The number
            denotes the number of major ticks and labels distributed on
            the axis.
        -- [integer, format-string]:
            Same as above, but the labels are formatted with the
            format-string - this gives the possibility to only show one
            of the three vector components, e.g. the string "{2}" to
            only show the k-vector's z-component. The axis title will be
            inferred from the format-string.
        -- KSpace object:
            This must be a KSpace object created with point_labels.
            These labels usually denote the high symmetry or crititical
            points, and they will be shown on the axis.
        -- CustomAxisFormatter object:
            This gives the possibility to completely customize the
            x-axis' tick positions, tick labels and axis label. If the
            CustomAxisFormatter's hover data have not been set, it will
            be set here with the k-vectors read from the .csv file.

    :param custom_plotter: If you want to add the graph to an existing
    figure, supply a BandPlotter with *custom_plotter*, otherwise
    (default: custom_plotter=None) a new BandPlotter is created and
    returned.
    :param title: the subplot's title.
    :param crop_y: If this is true (default), the y-axis (frequency)
    will be limited so that only frequency values are shown where all
    bands are known. Alternatively, a numeric value of *crop_y* denotes
    the upper frequency value where the plot will be cropped, or if
    *crop_y* is a 2-tuple, it denotes the minimum and maximum y-value.
    :param band_gaps: If True, draw the band gaps (with colored boxes).
    :param light_cone: If True, add a light cone and crop the bandgaps
    at the light line. If the simulation was run on a substrate,
    light_cone must be the index of the refraction of this substrate.
    The light cone will then be scaled accordingly.
    :param projected_bands: If True, add bands that span a range of
    frequencies to the plot. Bandgaps are not drawn in this case. The
    data needed will be read from previously saved .csv files
    (filenames: [ jobname* + '_' + *mode* + '_projected.csv' for mode in
    modes]).
    :param mask_proj_bands_above_light_line: If *projected_bands* is
    True, some projected bands might be completely above the light line.
    These bands will not be drawn, if *mask_proj_bands_above_light_line*
    is True.
    :param add_epsilon_as_inset: epsilon,png will be added as inset. See
    defaults.py for parameters like size and location.
    :param color_by_parity: Specify 'y' or 'z' to color the plot lines
    with the data taken from the parity files
    <jobname>_<mode>[z/y]parity.csv.
    :param interactive_mode: This is useful if the plot is not intended for
    saving, but for showing on the screen. Then defaults.default_onclick()
    will be called if the user clicks on a graph in the figure.
    :return: a created BandPlotter instance (if *custom_plotter*) was
    None, or the *custom_plotter*.

    """
    if custom_plotter is None:
        plotter = BandPlotter(figure_size=defaults.fig_size)
    else:
        plotter = custom_plotter
        plotter.next_plot()

    refr_index = 1 if isinstance(light_cone, bool) else light_cone

    x_axis_formatter = None
    if isinstance(x_axis_hint, axis_formatter.CustomAxisFormatter):
        # use the supplied CustomAxisFormatter:
        x_axis_formatter = x_axis_hint
    elif isinstance(x_axis_hint, KSpace):
        # make a KSpaceAxisFormatter instance from kspace object:
        x_axis_formatter = axis_formatter.KSpaceAxisFormatter(x_axis_hint)
    elif isinstance(x_axis_hint, int):
        # make a standard KVectorAxisFormatter with supplied number of ticks:
        x_axis_formatter = axis_formatter.KVectorAxisFormatter(x_axis_hint)
    else:
        num = 0
        hintlen = 0
        if hasattr(x_axis_hint, '__len__'):
            hintlen = len(x_axis_hint)
        else:
            # no sequence
            try:
                # is this a number?
                num = int(x_axis_hint)
            except ValueError:
                # no number
                pass
        if hintlen > 1 and (isinstance(x_axis_hint[0], int) and
                hasattr(x_axis_hint[1], 'format')):
            # Supplied a list with at least an int and format_str.
            # Use all items in list as KVectorAxisFormatter arguments:
            x_axis_formatter = axis_formatter.KVectorAxisFormatter(
                *x_axis_hint)
        elif num > 0:
            # make a standard KVectorAxisFormatter with supplied number
            # of ticks:
            x_axis_formatter = axis_formatter.KVectorAxisFormatter(num)
    if x_axis_formatter is None:
        log.warning('draw_bands: Did not understand x_axis_hint, '
            'using default.')
        x_axis_formatter = axis_formatter.KVectorAxisFormatter(
            default_x_axis_hint)

    for i, mode in enumerate(modes):
        fname = '{0}_{1}freqs.csv'.format(jobname, mode)
        data = loadtxt(fname, delimiter=',', skiprows=1)

        # add hover data:
        if x_axis_formatter._hover_func_is_default:
            x_axis_formatter.set_hover_data(data[:, 1:4])

        parities = None
        if color_by_parity:
            # try to load parity file:
            fname = '{0}_{1}{2}parity.csv'.format(
                jobname, mode, color_by_parity)
            try:
                # load data, ignore first column with band numbers:
                parities = loadtxt(fname, delimiter=',')[:, 1:]
            except IOError:
                parities = None

        plotter.plot_bands(
            data[:, 5:], data[:, 1:5],
            formatstr=defaults.draw_bands_formatstr,
            x_axis_formatter=x_axis_formatter,
            label=mode.upper(),
            crop_y=crop_y,
            picker = interactive_mode * 3,
            color_by_parity=parities,
            **defaults.draw_bands_kwargs)

        if projected_bands:
            fname = '{0}_{1}_projected.csv'.format(jobname, mode)
            with np.warnings.catch_warnings():
                # ignore numpy warning if the file does not contain any
                # data, just return empty ndarray:
                np.warnings.simplefilter("ignore")
                projdata = loadtxt(fname, delimiter=',', ndmin=2)
            if projdata.shape[0] != 0:
                if projdata.shape[1] % 2 != 0:
                    # knums added in first column, drop it:
                    projdata = projdata[:, 1:]

                if light_cone and mask_proj_bands_above_light_line:
                    # ignore projected bands above the light line:
                    mask = np.zeros_like(projdata, dtype=np.bool)
                    numbands = projdata.shape[1] // 2
                    for i in range(numbands):
                        if (projdata[:, 2 * i] >
                                    data[:, 4] / refr_index).all():
                            mask[:, 2 * i:2 * i + 2] = True
                    projdata = np.ma.array(projdata, mask=mask)

                if projdata.shape[0] == 1 and data.shape[0] != 1:
                    # the same band ranges for all k-vecs:
                    newproj = np.empty((data.shape[0], projdata.shape[1]))
                    newproj[None, :] = projdata
                    projdata = newproj

                plotter.add_continuum_bands(projdata)
        if band_gaps:
            if light_cone:
                gapbands = get_gap_bands(
                    data[:, 5:], light_line=data[:, 4] / refr_index)
            else:
                gapbands = get_gap_bands(data[:, 5:])
            for band in gapbands:
                bsize = 2 * (band[2] - band[1]) / (band[2] + band[1])
                if bsize >= defaults.min_gapsize:
                    plotter.add_band_gap_rectangle(
                        band[1], band[2],
                        light_line= \
                            data[:,4] / refr_index if light_cone else None)

    if light_cone:
        plotter.add_light_cone(refr_index)

    plotter.set_plot_title(title)

    if len(modes) > 1 or (len(modes) == 1 and modes[0]!=''):
        plotter.add_legend()

    if color_by_parity:
        plotter.add_color_bar_for_parity(parity_direction=color_by_parity)

    if add_epsilon_as_inset:
        fname = path.join(path.split(jobname)[0], 'epsilon.png')
        if path.isfile(fname):
            plotter.add_image_inset(
                fname,
                loc=defaults.epsilon_inset_location,
                zoom=defaults.epsilon_inset_zoom,
                transpose=defaults.epsilon_inset_transpose
            )

    return plotter