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')
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
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')
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')
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