def test_plot2D(self): # Check plotting of geometry with several sources, monitors, and PMLs f = plt.figure() ax = f.gca() sim = setup_sim() ax = sim.plot2D(ax=ax) if mp.am_master(): hash_figure(f) #self.assertAlmostEqual(hash_figure(f),10231488) # Check plotting of fields after timestepping f = plt.figure() ax = f.gca() sim.run(until=200) ax = sim.plot2D(ax=ax, fields=mp.Ez) if mp.am_master(): hash_figure(f) #self.assertAlmostEqual(hash_figure(f),79786722) # Check output_plane feature f = plt.figure() ax = f.gca() vol = mp.Volume(center=mp.Vector3(), size=mp.Vector3(2, 2)) ax = sim.plot2D(ax=ax, fields=mp.Ez, output_plane=vol) if mp.am_master(): hash_figure(f)
def visualize_dft_flux(sim, superpose=True, flux_cells=[], options=None, nf=0): if not mp.am_master(): return options=options if options else def_flux_options # first pass to get arrays of poynting flux strength for all cells if len(flux_cells)==0: flux_cells=[cell for cell in sim.dft_objects if is_flux_cell(cell)] flux_arrays=[] for cell in flux_cells: # first pass to compute flux data (x,y,z,w,c,EH)=unpack_dft_cell(sim,cell,nf=nf) flux_arrays.append( 0.25*np.real(w*(np.conj(EH[0])*EH[3] - np.conj(EH[1])*EH[2])) ) # second pass to plot for n, cell in enumerate(flux_cells): # second pass to plot if superpose==False: if n==0: plt.figure() plt.title('Poynting flux') plt.subplot(len(flux_cells),1,n) plt.gca().set_title('Flux cell {}'.format(n)) cn,sz=mp.get_center_and_size(cell.where) max_flux=np.amax([np.amax(fa) for fa in flux_arrays]) plot_data_curves(sim, center=cn, size=sz, data=[flux_arrays[n]], superpose=superpose, options=options, labels=['flux through cell {}'.format(n)], dmin=-max_flux,dmax=max_flux)
def __init__(self,sim,fields,f=None,realtime=False,normalize=False, plot_modifiers=None,**customization_args): self.fields = fields if f: self.f = f self.ax = self.f.gca() elif mp.am_master(): from matplotlib import pyplot as plt self.f = plt.figure() self.ax = self.f.gca() else: self.f = None self.ax = None self.realtime = realtime self.normalize = normalize self.plot_modifiers = plot_modifiers self.customization_args = customization_args self.cumulative_fields = [] self._saved_frames = [] self.frame_format = 'png' # format in which each frame is saved in memory self.codec = 'h264' # encoding of mp4 video self.default_mode = 'loop' # html5 video control mode self.init = False # Needed for step functions self.__code__ = namedtuple('gna_hack',['co_argcount']) self.__code__.co_argcount=2
def to_mp4(self,fps,filename): # Exports an mp4 of the recorded animation # requires ffmpeg to be installed # modified from the matplotlib library if mp.am_master(): from subprocess import Popen, PIPE from io import TextIOWrapper, BytesIO FFMPEG_BIN = 'ffmpeg' command = [FFMPEG_BIN, '-f', 'image2pipe', # force piping of rawvideo '-vcodec', self.frame_format, # raw input codec '-s', '%dx%d' % (self.frame_size), #'-pix_fmt', self.frame_format, '-r', str(fps), # frame rate in frames per second '-i', 'pipe:', # The input comes from a pipe '-vcodec', self.codec, # output mp4 format '-pix_fmt','yuv420p', '-r', str(fps), # frame rate in frames per second '-y', '-vf', 'pad=width=ceil(iw/2)*2:height=ceil(ih/2)*2', '-an', filename # output filename ] if mp.cvar.verbosity > 0: print("Generating MP4...") proc = Popen(command, stdin=PIPE, stdout=PIPE, stderr=PIPE) for i in range(len(self._saved_frames)): proc.stdin.write(self._saved_frames[i]) out, err = proc.communicate() # pipe in images proc.stdin.close() proc.wait() return
def visualize_dft_flux(sim, superpose=True, flux_cells=[], options=None, nf=0): if not mp.am_master(): return options = options if options else def_flux_options # first pass to get arrays of poynting flux strength for all cells if len(flux_cells) == 0: flux_cells = [cell for cell in sim.dft_objects if is_flux_cell(cell)] flux_arrays = [] for cell in flux_cells: # first pass to compute flux data (x, y, z, w, c, EH) = unpack_dft_cell(sim, cell, nf=nf) flux_arrays.append( 0.25 * np.real(w * (np.conj(EH[0]) * EH[3] - np.conj(EH[1]) * EH[2]))) # second pass to plot for n, cell in enumerate(flux_cells): # second pass to plot if superpose == False: if n == 0: plt.figure() plt.title('Poynting flux') plt.subplot(len(flux_cells), 1, n) plt.gca().set_title('Flux cell {}'.format(n)) cn, sz = mp.get_center_and_size(cell.where) max_flux = np.amax([np.amax(fa) for fa in flux_arrays]) plot_data_curves(sim, center=cn, size=sz, data=[flux_arrays[n]], superpose=superpose, options=options, labels=['flux through cell {}'.format(n)], dmin=-max_flux, dmax=max_flux)
def visualize_source_distribution(sim, superpose=True, options=None): if not mp.am_master(): return options = options if options else def_src_options for ns, s in enumerate(sim.sources): sc, ss = s.center, s.size J2 = sum( [abs2(sim.get_source_slice(c, center=sc, size=ss)) for c in Exyz]) # M2=sum([abs2(sim.get_source_slice(c,center=sc,size=ss)) for c in Hxyz]) if superpose == False: if ns == 0: plt.ion() plt.figure() plt.title('Source regions') plt.fig().subplot(len(sim.sources), 1, ns + 1) plt.fig().title('Currents in source region {}'.format(ns)) # plot_data_curves(sim,superpose,[J2,M2],labels=['||J||','||M||'], # styles=['bo-','rs-'],center=sc,size=ssu plot_data_curves(sim, center=sc, size=ss, superpose=superpose, data=[J2], labels=['J'], options=options)
def closeHDF5File(self, pFileRef): '''Close the HDF5 file''' if (Meep.am_master()): LOG.debug("Meep node %i - Closing HDF5 file..." %(self.node_nr)) if pFileRef == None: raise PythonSimulateException("MeepSimulationEngine::getFieldAtMonitorPoint - call prepareHDF5File first : cannot close a file that is not open.") del(pFileRef)
def log(msg): from meep import am_master if not am_master(): return from meep.adjoint import options tm = dt.now().strftime("%T ") channel = options.get('logfile', None) if channel is not None: with open(channel, 'a') as f: f.write("{} {}\n".format(tm, msg))
def plot_fields(sim, ax=None, fields=None, output_plane=None, field_parameters=None): if not sim._is_initialized: sim.init_sim() if fields is None: return ax # user specifies a field component if fields in [mp.Ex, mp.Ey, mp.Ez, mp.Hx, mp.Hy, mp.Hz]: # Get domain measurements sim_center, sim_size = get_2D_dimensions(sim, output_plane) xmin = sim_center.x - sim_size.x / 2 xmax = sim_center.x + sim_size.x / 2 ymin = sim_center.y - sim_size.y / 2 ymax = sim_center.y + sim_size.y / 2 zmin = sim_center.z - sim_size.z / 2 zmax = sim_center.z + sim_size.z / 2 center = Vector3(sim_center.x, sim_center.y, sim_center.z) cell_size = Vector3(sim_size.x, sim_size.y, sim_size.z) if sim_size.x == 0: # Plot y on x axis, z on y axis (YZ plane) extent = [ymin, ymax, zmin, zmax] xlabel = 'Y' ylabel = 'Z' elif sim_size.y == 0: # Plot x on x axis, z on y axis (XZ plane) extent = [xmin, xmax, zmin, zmax] xlabel = 'X' ylabel = 'Z' elif sim_size.z == 0: # Plot x on x axis, y on y axis (XY plane) extent = [xmin, xmax, ymin, ymax] xlabel = 'X' ylabel = 'Y' fields = sim.get_array(center=center, size=cell_size, component=fields) else: raise ValueError( 'Please specify a valid field component (mp.Ex, mp.Ey, ...') # Either plot the field, or return the array if ax: field_parameters = default_field_parameters if field_parameters is None else dict( default_field_parameters, **field_parameters) if mp.am_master(): ax.imshow(np.rot90(fields), extent=extent, **field_parameters) return ax else: return np.rot90(fields) return ax
def visualize_chunks(sim): if sim.structure is None: sim.init_sim() import matplotlib.pyplot as plt import matplotlib.cm import matplotlib.colors from mpl_toolkits.mplot3d import Axes3D from mpl_toolkits.mplot3d.art3d import Poly3DCollection, Line3DCollection vols = sim.structure.get_chunk_volumes() owners = sim.structure.get_chunk_owners() def plot_box(box, proc, fig, ax): low = mp.Vector3(box.low.x, box.low.y, box.low.z) high = mp.Vector3(box.high.x, box.high.y, box.high.z) points = [low, high] x_len = mp.Vector3(high.x) - mp.Vector3(low.x) y_len = mp.Vector3(y=high.y) - mp.Vector3(y=low.y) xy_len = mp.Vector3(high.x, high.y) - mp.Vector3(low.x, low.y) points += [low + x_len] points += [low + y_len] points += [low + xy_len] points += [high - x_len] points += [high - y_len] points += [high - xy_len] points = np.array([np.array(v) for v in points]) edges = [[points[0], points[2], points[4], points[3]], [points[1], points[5], points[7], points[6]], [points[0], points[3], points[5], points[7]], [points[1], points[4], points[2], points[6]], [points[3], points[4], points[1], points[5]], [points[0], points[7], points[6], points[2]]] faces = Poly3DCollection(edges, linewidths=1, edgecolors='k') color_with_alpha = matplotlib.colors.to_rgba(chunk_colors[proc], alpha=0.2) faces.set_facecolor(color_with_alpha) ax.add_collection3d(faces) # Plot the points themselves to force the scaling of the axes ax.scatter(points[:, 0], points[:, 1], points[:, 2], s=0) if mp.am_master(): fig = plt.figure() ax = fig.add_subplot(111, projection='3d') chunk_colors = matplotlib.cm.rainbow( np.linspace(0, 1, mp.count_processors())) for i, v in enumerate(vols): plot_box(mp.gv2box(v.surroundings()), owners[i], fig, ax) ax.set_aspect('auto') plt.show()
def plot2D(sim,ax=None, output_plane=None, fields=None, labels=False, eps_parameters=None,boundary_parameters=None, source_parameters=None,monitor_parameters=None, field_parameters=None, frequency=None, plot_eps_flag=True, plot_sources_flag=True, plot_monitors_flag=True, plot_boundaries_flag=True): # Initialize the simulation if sim.structure is None: sim.init_sim() # Ensure a figure axis exists if ax is None and mp.am_master(): from matplotlib import pyplot as plt ax = plt.gca() # Determine a frequency to plot all epsilon if frequency is None: try: # Continuous sources frequency = sim.sources[0].frequency except: try: # Gaussian sources frequency = sim.sources[0].src.frequency except: try: # Custom sources frequency = sim.sources[0].src.center_frequency except: # No sources frequency = 0 # validate the output plane to ensure proper 2D coordinates from meep.simulation import Volume sim_center, sim_size = get_2D_dimensions(sim,output_plane) output_plane = Volume(center=sim_center,size=sim_size) # Plot geometry if plot_eps_flag: ax = plot_eps(sim,ax,output_plane=output_plane,eps_parameters=eps_parameters,frequency=frequency) # Plot boundaries if plot_boundaries_flag: ax = plot_boundaries(sim,ax,output_plane=output_plane,boundary_parameters=boundary_parameters) # Plot sources if plot_sources_flag: ax = plot_sources(sim,ax,output_plane=output_plane,labels=labels,source_parameters=source_parameters) # Plot monitors if plot_monitors_flag: ax = plot_monitors(sim,ax,output_plane=output_plane,labels=labels,monitor_parameters=monitor_parameters) # Plot fields ax = plot_fields(sim,ax,fields,output_plane=output_plane,field_parameters=field_parameters) return ax
def test_at_time(self): sim = self.init_simple_simulation() sim.run(mp.at_time(100, mp.output_efield_z), until=200) fname = 'simulation-ez-000100.00.h5' self.assertTrue(os.path.exists(fname)) mp.all_wait() if mp.am_master(): os.remove(fname)
def test_with_prefix(self): sim = self.init_simple_simulation() sim.run(mp.with_prefix('test_prefix-', mp.at_end(mp.output_efield_z)), until=200) fname = 'test_prefix-simulation-ez-000200.00.h5' self.assertTrue(os.path.exists(fname)) mp.all_wait() if mp.am_master(): os.remove(fname)
def test_in_point(self): sim = self.init_simple_simulation(filename_prefix='test_in_point') fn = sim.filename_prefix + '-ez-000200.00.h5' pt = mp.Vector3() sim.run(mp.at_end(mp.in_point(pt, mp.output_efield_z)), until=200) self.assertTrue(os.path.exists(fn)) mp.all_wait() if mp.am_master(): os.remove(fn)
def test_load_dump_structure(self): from meep.materials import Al resolution = 50 cell = mp.Vector3(5, 5) sources = mp.Source(src=mp.GaussianSource(1, fwidth=0.2), center=mp.Vector3(), component=mp.Ez) one_by_one = mp.Vector3(1, 1, mp.inf) geometry = [ mp.Block(material=Al, center=mp.Vector3(-1.5, -1.5), size=one_by_one), mp.Block(material=mp.Medium(epsilon=13), center=mp.Vector3(1.5, 1.5), size=one_by_one) ] pml_layers = [mp.PML(0.5)] sim = mp.Simulation(resolution=resolution, cell_size=cell, boundary_layers=pml_layers, geometry=geometry, sources=[sources]) sample_point = mp.Vector3(0.12, -0.29) ref_field_points = [] def get_ref_field_point(sim): p = sim.get_field_point(mp.Ez, sample_point) ref_field_points.append(p.real) sim.run(mp.at_every(5, get_ref_field_point), until=50) dump_fn = 'test_load_dump_structure.h5' sim.dump_structure(dump_fn) sim = mp.Simulation(resolution=resolution, cell_size=cell, boundary_layers=pml_layers, sources=[sources], load_structure=dump_fn) field_points = [] def get_field_point(sim): p = sim.get_field_point(mp.Ez, sample_point) field_points.append(p.real) sim.run(mp.at_every(5, get_field_point), until=50) for ref_pt, pt in zip(ref_field_points, field_points): self.assertAlmostEqual(ref_pt, pt) mp.all_wait() if mp.am_master(): os.remove(dump_fn)
def plot_eps(sim, ax, output_plane=None, eps_parameters=None): if sim.structure is None: sim.init_sim() # consolidate plotting parameters eps_parameters = default_eps_parameters if eps_parameters is None else dict( default_eps_parameters, **eps_parameters) # Get domain measurements if output_plane: sim_center, sim_size = (output_plane.center, output_plane.size) elif sim.output_volume: sim_center, sim_size = mp.get_center_and_size(sim.output_volume) else: sim_center, sim_size = (sim.geometry_center, sim.cell_size) xmin = sim_center.x - sim_size.x / 2 xmax = sim_center.x + sim_size.x / 2 ymin = sim_center.y - sim_size.y / 2 ymax = sim_center.y + sim_size.y / 2 zmin = sim_center.z - sim_size.z / 2 zmax = sim_center.z + sim_size.z / 2 center = Vector3(sim_center.x, sim_center.y, sim_center.z) cell_size = Vector3(sim_size.x, sim_size.y, sim_size.z) if sim_size.x == 0: # Plot y on x axis, z on y axis (YZ plane) extent = [ymin, ymax, zmin, zmax] xlabel = 'Y' ylabel = 'Z' elif sim_size.y == 0: # Plot x on x axis, z on y axis (XZ plane) extent = [xmin, xmax, zmin, zmax] xlabel = 'X' ylabel = 'Z' elif sim_size.z == 0: # Plot x on x axis, y on y axis (XY plane) extent = [xmin, xmax, ymin, ymax] xlabel = 'X' ylabel = 'Y' else: raise ValueError("A 2D plane has not been specified...") eps_data = np.rot90( np.real( sim.get_array(center=center, size=cell_size, component=mp.Dielectric))) if mp.am_master(): ax.imshow(eps_data, extent=extent, **eps_parameters) ax.set_xlabel(xlabel) ax.set_ylabel(ylabel) return ax
def test_use_output_directory_custom(self): sim = self.init_simple_simulation() sim.use_output_directory('custom_dir') sim.run(mp.at_end(mp.output_efield_z), until=200) output_dir = 'custom_dir' self.assertTrue(os.path.exists(os.path.join(output_dir, self.fname))) mp.all_wait() if mp.am_master(): shutil.rmtree(output_dir)
def test_use_output_directory_default(self): sim = self.init_simple_simulation() output_dir = os.path.join(temp_dir, 'simulation-out') sim.use_output_directory(output_dir) sim.run(mp.at_end(mp.output_efield_z), until=200) self.assertTrue(os.path.exists(os.path.join(output_dir, self.fname))) mp.all_wait() if mp.am_master(): shutil.rmtree(output_dir)
def save_dielectricum_image(self, filename = None): #prepare the filename for the export to HDF5 if (filename is None): filename = self.landscape.simulation_id+"_Eps.h5" #let Meep export the dielectricum to HDF5 self.exportDielectricH5(filename) if (Meep.am_master()): LOG.debug("Meep node %i -Dielectricum saved to file %s..." %(self.node_nr,filename)) if self.dim == 2: cmd = "h5topng -a /home/emmanuel/workspace/Meep_tutorial/colormaps/yarg "+filename os.system(cmd) return filename
def __call__(self, sim, todo): from matplotlib import pyplot as plt if todo == 'step': # Initialize the plot if not self.init: filtered_plot2D = filter_dict(self.customization_args, plot2D) ax = sim.plot2D(ax=self.ax, fields=self.fields, **filtered_plot2D) # Run the plot modifier functions if self.plot_modifiers: for k in range(len(self.plot_modifiers)): ax = self.plot_modifiers[k](self.ax) # Store the fields if mp.am_master(): fields = ax.images[-1].get_array() self.ax = ax self.w, self.h = self.f.get_size_inches() self.init = True else: # Update the plot filtered_plot_fields = filter_dict(self.customization_args, plot_fields) fields = sim.plot_fields(fields=self.fields, **filtered_plot_fields) if mp.am_master(): self.ax.images[-1].set_data(fields) self.ax.images[-1].set_clim(vmin=0.8 * np.min(fields), vmax=0.8 * np.max(fields)) if self.realtime and mp.am_master(): # Redraw the current figure if requested plt.pause(0.05) if self.normalize and mp.am_master(): # Save fields as a numpy array to be normalized # and saved later. self.cumulative_fields.append(fields) elif mp.am_master(): # Capture figure as a png, but store the png in memory # to avoid writing to disk. self.grab_frame() return elif todo == 'finish': # Normalize the frames, if requested, and export if self.normalize and mp.am_master(): if mp.verbosity > 0: print("Normalizing field data...") fields = np.array(self.cumulative_fields) / np.max( np.abs(self.cumulative_fields), axis=(0, 1, 2)) for k in range(len(self.cumulative_fields)): self.ax.images[-1].set_data(fields[k, :, :]) self.ax.images[-1].set_clim(vmin=-0.8, vmax=0.8) self.grab_frame() return
def plot_eps(sim,ax,output_plane=None,eps_parameters=None,frequency=0): if sim.structure is None: sim.init_sim() # consolidate plotting parameters eps_parameters = default_eps_parameters if eps_parameters is None else dict(default_eps_parameters, **eps_parameters) # Get domain measurements sim_center, sim_size = get_2D_dimensions(sim,output_plane) xmin = sim_center.x - sim_size.x/2 xmax = sim_center.x + sim_size.x/2 ymin = sim_center.y - sim_size.y/2 ymax = sim_center.y + sim_size.y/2 zmin = sim_center.z - sim_size.z/2 zmax = sim_center.z + sim_size.z/2 center = Vector3(sim_center.x,sim_center.y,sim_center.z) cell_size = Vector3(sim_size.x,sim_size.y,sim_size.z) if sim_size.x == 0: # Plot y on x axis, z on y axis (YZ plane) extent = [ymin,ymax,zmin,zmax] xlabel = 'Y' ylabel = 'Z' elif sim_size.y == 0: # Plot x on x axis, z on y axis (XZ plane) extent = [xmin,xmax,zmin,zmax] xlabel = 'X' ylabel = 'Z' elif sim_size.z == 0: # Plot x on x axis, y on y axis (XY plane) extent = [xmin,xmax,ymin,ymax] xlabel = 'X' ylabel = 'Y' else: raise ValueError("A 2D plane has not been specified...") eps_data = np.rot90(np.real(sim.get_array(center=center, size=cell_size, component=mp.Dielectric, frequency=frequency))) if mp.am_master(): if eps_parameters['contour']: ax.contour(eps_data, 0, colors='black', origin='upper', extent=extent, linewidths=eps_parameters['contour_linewidth']) else: ax.imshow(eps_data, extent=extent, **filter_dict(eps_parameters, ax.imshow)) ax.set_xlabel(xlabel) ax.set_ylabel(ylabel) return ax
def to_jshtml(self, fps): """ Outputs an interactable JSHTML animation object that is embeddable in Jupyter notebooks. The object is packaged with controls to manipulate the video's playback. User must specify a frame rate `fps` in frames per second. """ # Exports a javascript enabled html object that is # ready for jupyter notebook embedding. # modified from matplotlib/animation.py code. # Only works with Python3 and matplotlib > 3.1.0 from distutils.version import LooseVersion import matplotlib if LooseVersion(matplotlib.__version__) < LooseVersion("3.1.0"): print('-------------------------------') print( 'Warning: JSHTML output is not supported with your current matplotlib build. Consider upgrading to 3.1.0+' ) print('-------------------------------') return if mp.am_master(): from uuid import uuid4 from matplotlib._animation_data import (DISPLAY_TEMPLATE, INCLUDED_FRAMES, JS_INCLUDE, STYLE_INCLUDE) # save the frames to an html file fill_frames = self._embedded_frames(self._saved_frames, self.frame_format) Nframes = len(self._saved_frames) mode_dict = dict(once_checked='', loop_checked='', reflect_checked='') mode_dict[self.default_mode + '_checked'] = 'checked' interval = 1000 // fps html_string = "" html_string += JS_INCLUDE html_string += STYLE_INCLUDE html_string += DISPLAY_TEMPLATE.format(id=uuid4().hex, Nframes=Nframes, fill_frames=fill_frames, interval=interval, **mode_dict) return JS_Animation(html_string)
def to_gif(self, fps, filename): """ Generates and outputs a GIF file of the animation with the filename, `filename`, and the frame rate, `fps`. Note that GIFs are significantly larger than mp4 videos since they don't use any compression. Artifacts are also common because the GIF format only supports 256 colors from a _predefined_ color palette. Requires `ffmpeg`. """ # Exports a gif of the recorded animation # requires ffmpeg to be installed # modified from the matplotlib library if mp.am_master(): from subprocess import Popen, PIPE from io import TextIOWrapper, BytesIO FFMPEG_BIN = 'ffmpeg' command = [ FFMPEG_BIN, '-f', 'image2pipe', # force piping of rawvideo '-vcodec', self.frame_format, # raw input codec '-s', '%dx%d' % (self.frame_size), '-r', str(fps), # frame rate in frames per second '-i', 'pipe:', # The input comes from a pipe '-vcodec', 'gif', # output gif format '-r', str(fps), # frame rate in frames per second '-y', '-vf', 'pad=width=ceil(iw/2)*2:height=ceil(ih/2)*2', '-an', filename # output filename ] if mp.verbosity > 0: print("Generating GIF...") proc = Popen(command, stdin=PIPE, stdout=PIPE, stderr=PIPE) for i in range(len(self._saved_frames)): proc.stdin.write(self._saved_frames[i]) out, err = proc.communicate() # pipe in images proc.stdin.close() proc.wait() return
def plot2D(sim,ax=None, output_plane=None, fields=None, labels=False, eps_parameters=None,boundary_parameters=None, source_parameters=None,monitor_parameters=None, field_parameters=None, omega=None): # Initialize the simulation if sim.structure is None: sim.init_sim() # Ensure a figure axis exists if ax is None and mp.am_master(): from matplotlib import pyplot as plt ax = plt.gca() # Determine a frequency to plot all epsilon if omega is None: try: omega = sim.sources[0].frequency except: try: omega = sim.sources[0].src.frequency except: omega = 0 # User incorrectly specified a 3D output plane if output_plane and (output_plane.size.x != 0) and (output_plane.size.y != 0) and (output_plane.size.z != 0): raise ValueError("output_plane must be a 2 dimensional volume (a plane).") # User forgot to specify a 2D output plane for a 3D simulation elif output_plane is None and (sim.cell_size.x != 0) and (sim.cell_size.y != 0) and (sim.cell_size.z != 0): raise ValueError("For 3D simulations, you must specify an output_plane.") # Plot geometry ax = plot_eps(sim,ax,output_plane=output_plane,eps_parameters=eps_parameters,omega=omega) # Plot boundaries ax = plot_boundaries(sim,ax,output_plane=output_plane,boundary_parameters=boundary_parameters) # Plot sources ax = plot_sources(sim,ax,output_plane=output_plane,labels=labels,source_parameters=source_parameters) # Plot monitors ax = plot_monitors(sim,ax,output_plane=output_plane,labels=labels,monitor_parameters=monitor_parameters) # Plot fields ax = plot_fields(sim,ax,fields,output_plane=output_plane,field_parameters=field_parameters) return ax
def visualize_source_distribution(sim, superpose=True, options=None): if not mp.am_master(): return options=options if options else def_src_options for ns,s in enumerate(sim.sources): sc,ss=s.center,s.size J2=sum([abs2(sim.get_source_slice(c,center=sc,size=ss)) for c in Exyz]) # M2=sum([abs2(sim.get_source_slice(c,center=sc,size=ss)) for c in Hxyz]) if superpose==False: if ns==0: plt.ion() plt.figure() plt.title('Source regions') plt.fig().subplot(len(sim.sources),1,ns+1) plt.fig().title('Currents in source region {}'.format(ns)) # plot_data_curves(sim,superpose,[J2,M2],labels=['||J||','||M||'], # styles=['bo-','rs-'],center=sc,size=ssu plot_data_curves(sim,center=sc,size=ss, superpose=superpose, data=[J2], labels=['J'], options=options)
def compute_insertion(thickness, n_eff, width, radius, resolution, wavelength, pml): name = f'h{thickness:04.3f}_w{width:04.2f}_n{n_eff:04.3}_r{radius:05.2f}' print(f'Computing insertion for {name}') sim, regions = simulate(n_eff, width, radius, resolution, wavelength, pml) losses = inspect(sim, regions, name) print(f'r{name} >>> {losses*100:05.2f}%') try: if mp.am_master(): run([ 'curl', f'https://api.simplepush.io/send/mjjFz4/Simulation step/{name}' f' {losses*100:05.2f}' ]) run(['git', 'add', '.']) run(['git', 'commit', '-m', 'sim results']) run(['git', 'push']) print('Pushed') except BaseException as e: print(f'Push failed: {e}') return losses
def plot_dft_flux(sim, dft_cells, superpose=True, nf=0, options={}): if not mp.am_master(): return method = vis_opt('method', section='flux_data', overrides=options) if method.lower() in ['omit', 'none']: return # first pass to get arrays of poynting flux strength for all cells flux_cells, flux_arrays = [c for c in dft_cells if c.celltype == 'flux'], [] for cell in flux_cells: w, EH = cell.grid.weights, cell.get_EH_slices(nf=nf) flux_arrays.append( 0.25 * np.real(w * (np.conj(EH[0]) * EH[3] - np.conj(EH[1]) * EH[2]))) # second pass to plot for n, cell in enumerate(flux_cells): # second pass to plot if superpose == False: if n == 0: plt.figure() plt.title('Poynting flux') plt.subplot(len(flux_cells), 1, n) plt.gca().set_title('Flux cell {}'.format(n)) cn, sz = cell.region.center, cell.region.size max_flux = np.amax([np.amax(fa) for fa in flux_arrays]) plot_data_curves(sim, center=cell.region.center, size=cell.region.size, data=[flux_arrays[n]], superpose=superpose, labels=['flux through cell {}'.format(n)], dmin=-max_flux, dmax=max_flux, section='flux_data', options=options)
def test_load_dump_structure(self): resolution = 10 cell = mp.Vector3(10, 10) pml_layers = mp.PML(1.0) fcen = 1.0 df = 1.0 sources = mp.Source(src=mp.GaussianSource(fcen, fwidth=df), center=mp.Vector3(), component=mp.Hz) geometry = mp.Cylinder(0.2, material=mp.Medium(index=3)) sim = mp.Simulation(resolution=resolution, cell_size=cell, default_material=mp.Medium(index=1), geometry=[geometry], boundary_layers=[pml_layers], sources=[sources]) sim.run(until=200) ref_field = sim.get_field_point(mp.Hz, mp.Vector3(z=2)) dump_fn = 'test_load_dump_structure.h5' sim.dump_structure(dump_fn) sim = mp.Simulation(resolution=resolution, cell_size=cell, default_material=mp.Medium(index=1), geometry=[], boundary_layers=[pml_layers], sources=[sources], load_structure=dump_fn) sim.run(until=200) field = sim.get_field_point(mp.Hz, mp.Vector3(z=2)) self.assertAlmostEqual(ref_field, field) mp.all_wait() if mp.am_master(): os.remove(dump_fn)
def plot_volume(sim, ax, volume, output_plane=None, plotting_parameters=None, label=None): if not sim._is_initialized: sim.init_sim() import matplotlib.patches as patches from matplotlib import pyplot as plt from meep.simulation import Volume # Set up the plotting parameters plotting_parameters = default_volume_parameters if plotting_parameters is None else dict( default_volume_parameters, **plotting_parameters) # Get domain measurements if output_plane: sim_center, sim_size = (output_plane.center, output_plane.size) elif sim.output_volume: sim_center, sim_size = mp.get_center_and_size(sim.output_volume) else: sim_center, sim_size = (sim.geometry_center, sim.cell_size) plane = Volume(center=sim_center, size=sim_size) # Pull volume parameters size = volume.size center = volume.center xmax = center.x + size.x / 2 xmin = center.x - size.x / 2 ymax = center.y + size.y / 2 ymin = center.y - size.y / 2 zmax = center.z + size.z / 2 zmin = center.z - size.z / 2 # Add labels if requested if label is not None and mp.am_master(): if sim_size.x == 0: ax = place_label(ax, label, center.y, center.z, sim_center.y, sim_center.z, label_parameters=plotting_parameters) elif sim_size.y == 0: ax = place_label(ax, label, center.x, center.z, sim_center.x, sim_center.z, label_parameters=plotting_parameters) elif sim_size.z == 0: ax = place_label(ax, label, center.x, center.y, sim_center.x, sim_center.y, label_parameters=plotting_parameters) # Intersect plane with volume intersection = intersect_volume_plane(volume, plane) # Sort the points in a counter clockwise manner to ensure convex polygon is formed def sort_points(xy): xy = np.squeeze(xy) theta = np.arctan2(xy[:, 1], xy[:, 0]) return xy[np.argsort(theta, axis=0)] if mp.am_master(): # Point volume if len(intersection) == 1: point_args = { key: value for key, value in plotting_parameters.items() if key in ['color', 'marker', 'alpha', 'linewidth'] } if sim_center.y == center.y: ax.scatter(center.x, center.z, **point_args) return ax elif sim_center.x == center.x: ax.scatter(center.y, center.z, **point_args) return ax elif sim_center.z == center.z: ax.scatter(center.x, center.y, **point_args) return ax else: return ax # Line volume elif len(intersection) == 2: line_args = { key: value for key, value in plotting_parameters.items() if key in ['color', 'linestyle', 'linewidth', 'alpha'] } # Plot YZ if sim_size.x == 0: ax.plot([a.y for a in intersection], [a.z for a in intersection], **line_args) return ax #Plot XZ elif sim_size.y == 0: ax.plot([a.x for a in intersection], [a.z for a in intersection], **line_args) return ax # Plot XY elif sim_size.z == 0: ax.plot([a.x for a in intersection], [a.y for a in intersection], **line_args) return ax else: return ax # Planar volume elif len(intersection) > 2: planar_args = { key: value for key, value in plotting_parameters.items() if key in ['edgecolor', 'linewidth', 'facecolor', 'hatch', 'alpha'] } # Plot YZ if sim_size.x == 0: ax.add_patch( patches.Polygon( sort_points([[a.y, a.z] for a in intersection]), **planar_args)) return ax #Plot XZ elif sim_size.y == 0: ax.add_patch( patches.Polygon( sort_points([[a.x, a.z] for a in intersection]), **planar_args)) return ax # Plot XY elif sim_size.z == 0: ax.add_patch( patches.Polygon( sort_points([[a.x, a.y] for a in intersection]), **planar_args)) return ax else: return ax else: return ax return ax
time = time ) #---------------------------------------------------------------------- #- Get gradient #---------------------------------------------------------------------- f0, g_adjoint = opt() #---------------------------------------------------------------------- #- FD run #---------------------------------------------------------------------- db = 1e-3 n = Nx*Ny choose = 20 if mp.am_master(): if path.exists('simple_broadband_{}_seed_{}_Nx_{}_Ny_{}.npz'.format(resolution,seed,Nx,Ny)) and load_from_file: data = np.load('simple_broadband_{}_seed_{}_Nx_{}_Ny_{}.npz'.format(resolution,seed,Nx,Ny)) idx = data['idx'] g_discrete = data['g_discrete'] else: g_discrete, idx = opt.calculate_fd_gradient(num_gradients=choose,db=db) print("Chosen indices: ",idx) print("adjoint method: {}".format(g_adjoint[idx])) print("discrete method: {}".format(g_discrete[idx])) print("ratio: {}".format(g_adjoint[idx]/g_discrete[idx])) (m, b) = np.polyfit(g_discrete, g_adjoint, 1) print("slope: {}".format(m))
def __init__(self, cell_size=None, background_geometry=[], foreground_geometry=[], sources=None, source_region=[], objective_regions=[], basis=None, design_region=None, extra_regions=[], objective_function=None, extra_quantities=[]): """ Parameters: ----------- cell_size: array-like background_geometry: list of meep.GeometricObject foreground_geometry: list of meep.GeometricObject Size of computational cell and lists of GeometricObjects that {precede,follow} the design object in the overall geometry. sources: list of meep.Source source_region: Subregion (*either* `sources` **or** `source_region` should be non-None) Specification of forward source distribution, i.e. the source excitation(s) that produce the fields from which the objective function is computed. In general, sources will be an arbitrary caller-created list of Source objects, in which case source_region, source_component are ignored. As an alternative convenience convention, the caller may omit sources and instead specify source_region; in this case, a source distribution over the given region is automatically created based on the values of the module-wide configuration options fcen, df, source_component, source_mode. objective regions: list of Subregion subregions of the computational cell over which frequency-domain fields are tabulated and used to compute objective quantities basis: (Basis) design_region: (Subregion) (*either* `basis` **or** `design_region` should be non-None) Specification of function space for the design permittivity. In general, basis will be a caller-created instance of some subclass of meep.adjoint.Basis. Then the spatial extent of the design region is determined by basis and the design_region argument is ignored. As an alternative convenience convention, the caller may omit basis and set design_region; in this case, an appropriate basis for the given design_region is automatically created based on the values of various module-wide adj_opt such as 'element_type' and 'element_length'. This convenience convention is only available for box-shaped (hyperrectangular) design regions. extra_regions: list of Subregion Optional list of additional subregions over which to tabulate frequency-domain fields. objective_function: str definition of the quantity to be maximized. This should be a mathematical expression in which the names of one or more objective quantities appear, and which should evaluate to a real number when numerical values are substituted for the names of all objective quantities. extra_quantities: list of str Optional list of additional objective quantities to be computed and reported together with the objective function. """ #----------------------------------------------------------------------- # process convenience arguments: # (a) if no basis was specified, create one using the given design # region plus global option values # (b) if no sources were specified, create one using the given source # region plus global option values #----------------------------------------------------------------------- self.basis = basis or FiniteElementBasis( region=design_region, element_length=adj_opt('element_length'), element_type=adj_opt('element_type')) design_region = self.basis.domain design_region.name = design_region.name or 'design' if not sources: f, df, m, c = [ adj_opt(s) for s in ['fcen', 'df', 'source_mode', 'source_component'] ] envelope = mp.GaussianSource(f, fwidth=df) kws = { 'center': V3(source_region.center), 'size': V3(source_region.size), 'src': envelope } #, 'eig_band': m, 'component': c } sources = [ mp.EigenModeSource(eig_band=m, **kws) if m > 0 else mp.Source(component=c, **kws) ] rescale_sources(sources) #----------------------------------------------------------------------- # initialize lower-level helper classes #----------------------------------------------------------------------- # DFTCells dft_cell_names = [] objective_cells = [DFTCell(r) for r in objective_regions] extra_cells = [DFTCell(r) for r in extra_regions] design_cell = DFTCell(design_region, E_CPTS) dft_cells = objective_cells + extra_cells + [design_cell] # ObjectiveFunction obj_func = ObjectiveFunction(fstr=objective_function, extra_quantities=extra_quantities) # initial values of (a) design variables, (b) the spatially-varying # permittivity function they define (the 'design function'), (c) the # GeometricObject describing a material body with this permittivity # (the 'design object'), and (d) mp.Simulation superposing the design # object with the rest of the caller's geometry. # Note that sources and DFT cells are not added to the Simulation at # this stage; this is done later by internal methods of TimeStepper # on a just-in-time basis before starting a timestepping run. self.beta_vector = self.basis.project(adj_opt('eps_design')) self.design_function = self.basis.parameterized_function( self.beta_vector) design_object = mp.Block(center=V3(design_region.center), size=V3(design_region.size), epsilon_func=self.design_function.func()) geometry = background_geometry + [design_object] + foreground_geometry sim = mp.Simulation(resolution=adj_opt('res'), cell_size=V3(cell_size), boundary_layers=[mp.PML(adj_opt('dpml'))], geometry=geometry) # TimeStepper self.stepper = TimeStepper(obj_func, dft_cells, self.basis, sim, sources) #----------------------------------------------------------------------- # if the 'filebase' configuration option wasn't specified, set it # to the base filename of the caller's script #----------------------------------------------------------------------- if not adj_opt('filebase'): script = inspect.stack()[1][0].f_code.co_filename or 'meep_adjoint' script_base = os.path.basename(script).split('.')[0] set_adjoint_options({'filebase': os.path.basename(script_base)}) if mp.am_master(): init_log(filename=adj_opt('logfile') or adj_opt('filebase') + '.log', usecs=True) self.dashboard_state = None
def __init__(self, sim, fields, f=None, realtime=False, normalize=False, plot_modifiers=None, **customization_args): """ Construct an `Animate2D` object. + **`sim`** — Simulation object. + **`fields`** — Field component to record at each time instant. + **`f=None`** — Optional `matplotlib` figure object that the routine will update on each call. If not supplied, then a new one will be created upon initialization. + **`realtime=False`** — Whether or not to update a figure window in realtime as the simulation progresses. Disabled by default. Not compatible with IPython/Jupyter notebooks. + **`normalize=False`** — Records fields at each time step in memory in a NumPy array and then normalizes the result by dividing by the maximum field value at a single point in the cell over all the time snapshots. + **`plot_modifiers=None`** — A list of functions that can modify the figure's `axis` object. Each function modifier accepts a single argument, an `axis` object, and must return that same axis object. The following modifier changes the `xlabel`: ```py def mod1(ax): ax.set_xlabel('Testing') return ax plot_modifiers = [mod1] ``` + **`**customization_args`** — Customization keyword arguments passed to `plot2D()` (i.e. `labels`, `eps_parameters`, `boundary_parameters`, etc.) """ self.fields = fields if f: self.f = f self.ax = self.f.gca() elif mp.am_master(): from matplotlib import pyplot as plt self.f = plt.figure() self.ax = self.f.gca() else: self.f = None self.ax = None self.realtime = realtime self.normalize = normalize self.plot_modifiers = plot_modifiers self.customization_args = customization_args self.cumulative_fields = [] self._saved_frames = [] self.frame_format = 'png' # format in which each frame is saved in memory self.codec = 'h264' # encoding of mp4 video self.default_mode = 'loop' # html5 video control mode self.init = False # Needed for step functions self.__code__ = namedtuple('gna_hack', ['co_argcount']) self.__code__.co_argcount = 2
def visualize_dft_fields(sim, superpose=True, field_cells=[], field_funcs=None, ff_arrays=None, zrels=None, options=None, nf=0): if not mp.am_master(): return if len(field_cells)==0: field_cells=[cl for cl in sim.dft_objects if dft_cell_type(cl)=='fields'] full_cells=[cell for cell in field_cells if cell.regions[0].size==sim.cell_size] field_cells=full_cells if full_cells else field_cells if len(field_cells)==0: return if superpose and not isinstance(plt.gcf().gca(),axes3d.Axes3D): warnings.warn("visualize_dft_fields: non-3D plot, can't superpose.") superpose=False if not superpose: return plot_dft_fields(sim, field_cells, field_funcs, ff_arrays, options, nf=nf) # the remainder of this routine is for the superposition case options = options if options else def_field_options cmap = options['cmap'] alpha = options['alpha'] num_contours = options['num_contours'] fontsize = options['fontsize'] if field_funcs is None: field_funcs = ['abs2(E)'] if zrels is None: zrel_min, zrel_max, nz = options['zrel_min'], options['zrel_max'], len(field_funcs) zrels=[0.5*(zrel_min+zrel_max)] if nz==1 else np.linspace(zrel_min,zrel_max,nz) for n, cell in enumerate(field_cells): (x,y,z,w,cEH,EH)=unpack_dft_cell(sim,cell,nf=nf) X, Y = np.meshgrid(x, y) fig = plt.gcf() ax = fig.gca(projection='3d') (zmin,zmax)=ax.get_zlim() for n,(ff,zrel) in enumerate(zip(field_funcs,zrels)): data = ff_arrays[n] if ff_arrays else field_func_array(ff,x,y,z,w,cEH,EH) z0 = zmin + zrel*(zmax-zmin) img = ax.contourf(X, Y, np.transpose(data), num_contours, cmap=cmap, alpha=alpha, zdir='z', offset=z0) pad=options['colorbar_pad'] shrink=options['colorbar_shrink'] if options['colorbar_cannibalize']: cax=fig.axes[-1] cb=plt.colorbar(img, cax=cax) else: cb=plt.colorbar(img, shrink=shrink, pad=pad, panchor=(0.0,0.5)) #cb.set_label(ff,fontsize=1.0*fontsize,rotation=0,labelpad=0.5*fontsize) cb.ax.set_xlabel(texify(ff),fontsize=1.5*fontsize,rotation=0,labelpad=0.5*fontsize) cb.ax.tick_params(labelsize=0.75*fontsize) cb.locator = ticker.MaxNLocator(nbins=5) cb.update_ticks() cb.draw_all() plt.show(False) plt.draw()
def visualize_sim(sim, fig=None, plot3D=None, eps_min=0.0, eps_max=None, eps_options=None, src_options=None, pml_options=None, dft_options=None, flux_options=None, field_options=None, set_rcParams=True, plot_dft_data=None): if not mp.am_master(): return # if plot3D not specified, set it automatically: false # if we are plotting only the geometry (at the beginning # of a simulation), true if we are also plotting results # (at the end of a simulation). sources_finished = sim.round_time() > sim.fields.last_source_time() if plot3D is None: plot3D=sources_finished ###################################################### # create figure and set some global parameters, unless # the caller asked us not to ###################################################### if fig is None: plt.ion fig=plt.gcf() fig.clf() if set_rcParams: set_meep_rcParams() ax = axes3d.Axes3D(fig) if plot3D else fig.gca() if not plot3D: ax.set_aspect('equal') plt.tight_layout() ################################################## # plot permittivity ################################################## eps_options = eps_options if eps_options else def_eps_options plot_eps(sim, eps_min=eps_min, eps_max=eps_max, options=eps_options, plot3D=plot3D) ################################################### ## plot source regions and optionally source amplitudes ################################################### src_options = src_options if src_options else def_src_options for ns,s in enumerate(sim.sources): plot_volume(sim, center=s.center, size=s.size, options=src_options, plot3D=plot3D, label=( None if src_options['fontsize']==0 else 'src' + ( '\_'+str(ns) if len(sim.sources)>1 else '')) ) if src_options['zrel_min']!=src_options['zrel_max']: visualize_source_distribution(sim, superpose=plot3D, options=src_options) ################################################### ## plot PML regions ################################################### if sim.boundary_layers and hasattr(sim.boundary_layers[0],'thickness'): dpml = sim.boundary_layers[0].thickness sx, sy = sim.cell_size.x, sim.cell_size.y y0, x0 = mp.Vector3(0.0, 0.5*(sy-dpml)), mp.Vector3(0.5*(sx-dpml), 0.0) ns, ew = mp.Vector3(sx-2*dpml, dpml), mp.Vector3(dpml,sy) centers = [ y0, -1*y0, x0, -1*x0 ] # north, south, east, west sizes = [ ns, ns, ew, ew ] for c,s in zip(centers,sizes): plot_volume(sim, center=c, size=s, plot3D=plot3D, options=pml_options if pml_options else def_pml_options) ###################################################################### # plot DFT cell regions, with labels for flux cells. ###################################################################### dft_options = dft_options if dft_options else def_dft_options for nc, c in enumerate(sim.dft_objects): plot_volume(sim,center=c.regions[0].center,size=c.regions[0].size, options=dft_options, plot3D=plot3D, label=dft_cell_name(nc) if dft_cell_type(c)=='flux' else None) ################################################### ################################################### ################################################### if plot_dft_data is None: plot_dft_data=sources_finished if plot_dft_data==True or plot_dft_data=='flux': visualize_dft_flux(sim, superpose=True, options=flux_options) if plot_dft_data==True: visualize_dft_fields(sim, superpose=True, options=field_options) plt.show(False) plt.draw() return fig
def _load_dump_structure(self, chunk_file=False, chunk_sim=False): from meep.materials import Al resolution = 50 cell = mp.Vector3(5, 5) sources = mp.Source(src=mp.GaussianSource(1, fwidth=0.2), center=mp.Vector3(), component=mp.Ez) one_by_one = mp.Vector3(1, 1, mp.inf) geometry = [mp.Block(material=Al, center=mp.Vector3(), size=one_by_one), mp.Block(material=mp.Medium(epsilon=13), center=mp.Vector3(1), size=one_by_one)] pml_layers = [mp.PML(0.5)] symmetries = [mp.Mirror(mp.Y)] sim1 = mp.Simulation(resolution=resolution, cell_size=cell, boundary_layers=pml_layers, geometry=geometry, symmetries=symmetries, sources=[sources]) sample_point = mp.Vector3(0.12, -0.29) ref_field_points = [] def get_ref_field_point(sim): p = sim.get_field_point(mp.Ez, sample_point) ref_field_points.append(p.real) sim1.run(mp.at_every(5, get_ref_field_point), until=50) dump_fn = 'test_load_dump_structure.h5' dump_chunk_fname = None chunk_layout = None sim1.dump_structure(dump_fn) if chunk_file: dump_chunk_fname = 'test_load_dump_structure_chunks.h5' sim1.dump_chunk_layout(dump_chunk_fname) chunk_layout = dump_chunk_fname if chunk_sim: chunk_layout = sim1 sim = mp.Simulation(resolution=resolution, cell_size=cell, boundary_layers=pml_layers, sources=[sources], symmetries=symmetries, chunk_layout=chunk_layout, load_structure=dump_fn) field_points = [] def get_field_point(sim): p = sim.get_field_point(mp.Ez, sample_point) field_points.append(p.real) sim.run(mp.at_every(5, get_field_point), until=50) for ref_pt, pt in zip(ref_field_points, field_points): self.assertAlmostEqual(ref_pt, pt) mp.all_wait() if mp.am_master(): os.remove(dump_fn) if dump_chunk_fname: os.remove(dump_chunk_fname)
def log(msg): if not mp.am_master() or adjoint_options['logfile'] is None: return tm=dt2.now().strftime("%T ") with open(adjoint_options['logfile'],'a') as f: f.write("{} {}\n".format(tm,msg))
sim = mp.Simulation(resolution=resolution, cell_size=cell_size, boundary_layers=boundary_layers, geometry=[mp.Prism(vertices,height=mp.inf,material=Si)], sources=sources, symmetries=symmetries) flux = sim.add_flux(fcen,0,1,mp.FluxRegion(center=mon_pt,size=mp.Vector3(y=sy-2*dpml_y))) sim.load_minus_flux_data(flux,incident_flux_data) sim.run(until_after_sources=mp.stop_when_fields_decayed(50,mp.Ez,mon_pt,1e-9)) res2 = sim.get_eigenmode_coefficients(flux,[1],eig_parity=mp.ODD_Z+mp.EVEN_Y) taper_coeffs = res2.alpha taper_flux = mp.get_fluxes(flux) R_coeffs.append(abs(taper_coeffs[0,0,1])**2/abs(incident_coeffs[0,0,0])**2) R_flux.append(-taper_flux[0]/incident_flux[0]) print("refl:, {}, {:.8f}, {:.8f}".format(Lt,R_coeffs[-1],R_flux[-1])) if mp.am_master(): plt.figure() plt.loglog(Lts,R_coeffs,'bo-',label='mode decomposition') plt.loglog(Lts,R_flux,'ro-',label='Poynting flux') plt.loglog(Lts,[0.005/Lt**2 for Lt in Lts],'k-',label=r'quadratic reference (1/Lt$^2$)') plt.legend(loc='upper right') plt.xlabel('taper length Lt (μm)') plt.ylabel('reflectance') plt.show()