def average_field(self, field): """ Average field component in some plane, return amplitudes This function is ineffective - it should be implemented in C++ in meep itself 5x5 grid is usually optimal (no visible difference between 10x10 grid and 5x5 grid) TODO: This class implements a workaround for unavailable amplitude averaging in python-meep. In this implementation, the geometrical averaging is ineffective and inflexible here. """ xcount, ycount = (1,1) field_sum = 0 # The mode function has the form of an oblique plane wave #for x in [x0*self.size_x/xcount+(self.size_x/2/xcount)-self.size_x/2 for x0 in range(xcount)]: #for y in [y0*self.size_y/ycount+(self.size_y/2/ycount)-self.size_y/2 for y0 in range(ycount)]: #field_sum += (field.get_field(self.comp, meep.vec(x, y, self.z_position)) * #np.exp(1j*(self.Kx*x + self.Ky*y)) ) #return field_sum/(xcount*ycount) return field.get_field(self.comp, meep.vec(0,0, self.z_position)) ## New way (removes explicit cycle, few percent faster) xr = [x0*self.size_x/xcount+(self.size_x/2/xcount)-self.size_x/2 for x0 in range(xcount)] yr = [x0*self.size_x/xcount+(self.size_x/2/xcount)-self.size_x/2 for x0 in range(xcount)] xm, ym = np.meshgrid(xr,yr) points = zip(xm.flatten(), ym.flatten()) sum_ = sum(map(lambda pos: field.get_field(self.comp, meep.vec(pos[0], pos[1], self.z_position)), points)) return sum_/(xcount*ycount)
def TestMaterials(self): """ Call the where() function for each material, in order to make sure there are no errors (SWIG callback does not report where the error occured, it just crashes) """ for material in self.materials: for x in np.linspace(-self.size_x/2, self.size_x/2, 10): for y in np.linspace(-self.size_y/2, self.size_y/2, 10): for z in np.linspace(-self.size_z/2, self.size_z/2, 10): if material.where(meep.vec(x, y, z)): print "teotueot"
def average_field(self, field): """ Average field component in whole simulation volume """ xcount, ycount, zcount = (1, 5, 3) field_sum = 0 for x in [x0*self.size_x/xcount+(self.size_x/2/xcount)-self.size_x/2 for x0 in range(xcount)]: for y in [y0*self.size_y/ycount+(self.size_y/2/ycount)-self.size_y/2 for y0 in range(ycount)]: for z in [z0*self.size_z/zcount+(self.size_z/2/zcount)-self.size_z/2 for z0 in range(zcount)]: field_sum += (field.get_field(self.comp, meep.vec(x, y, z)) / np.exp(-1j*(self.Kx*x + self.Ky*y + self.Kz*z)) ) return field_sum/(xcount*ycount*zcount) return sum_/(xcount*ycount)
def __init__(self, field=None, component=meep.Ex, timebounds=(0, np.inf), timestep=0, volume=None, normal=None, position=None, model=None, pad=0, outputdir="", name=None, outputPNGs=False, outputGIF=True, outputHDF=False, outputVTK=False): """ """ self.field = field self.outputdir = outputdir self.component = component self.timebounds = timebounds self.timestep = timestep self.outputPNGs = outputPNGs self.outputGIF = outputGIF self.outputHDF = outputHDF self.outputVTK = outputVTK if volume: self.volume = volume meep.master_printf("Will record slices at times %.3g, %.3g ... %.3g s \n" % (timebounds[0], timebounds[0]+timestep, timebounds[1])) else: #if not position: #raise RuntimeError("Specify the position of the cut plane (on the axis perpendicular to it)") if normal=="x": self.volume = meep.volume( meep.vec(position, -model.size_y/2+pad, -model.size_z/2+pad), meep.vec(position, model.size_y/2-pad, model.size_z/2-pad)) elif normal=="y": self.volume = meep.volume( meep.vec(-model.size_x/2+pad, position, -model.size_z/2+pad), meep.vec(model.size_x/2-pad, position, model.size_z/2-pad)) elif normal=="z": self.volume = meep.volume( meep.vec(-model.size_x/2+pad, -model.size_y/2+pad, position), meep.vec(model.size_x/2-pad, model.size_y/2-pad, position)) #else: #print normal #raise RuntimeError("Specify the normal parameter as 'x', 'y' or 'z'") meep.master_printf("Will record slices at %s=%.3g m, at times %g, %g ... %g s \n" \ % (normal, position, timebounds[0], timebounds[0]+timestep, timebounds[1])) self.outputdir = outputdir if not name: if not position or not normal: self.name = "SliceByVolume" else: self.name = "Slice_%s%.3e" % (normal, position) else: self.name = name self.images_number = 0 self.last_slice_time = 0. #slices=[] #slices.append({"name":"Ex_xz_slice", "component":meep.Ex, "geom": if not os.path.exists(outputdir): run_bash("mkdir -p %s" % outputdir, anyprocess=True) self.openfile = meep.prepareHDF5File("%s.h5" % (os.path.join(self.outputdir, self.name)))
def get_output_volume(self, meepVolume): sur_max_vec = meepVolume.surroundings().get_max_corner() if (self.normal_vector == 'x'): if (self.cut_value < 0.): self.cut_value = sur_max_vec.x() / 2.0 front_vec = meep.vec(self.cut_value, 0.0, 0.0) rear_vec = meep.vec(self.cut_value, sur_max_vec.y(), sur_max_vec.z()) elif (self.normal_vector == 'y'): if (self.cut_value < 0.): self.cut_value = sur_max_vec.y() / 2.0 front_vec = meep.vec(0.0, self.cut_value, 0.0) rear_vec = meep.vec(sur_max_vec.x(), self.cut_value, sur_max_vec.z()) else: if (self.cut_value < 0.): self.cut_value = sur_max_vec.z() / 2.0 front_vec = meep.vec(0.0, 0.0, self.cut_value) rear_vec = meep.vec(sur_max_vec.x(), sur_max_vec.y(), self.cut_value) perp_vol = meep.volume(front_vec, rear_vec) return perp_vol
vol = meep.vol3d(model.size_x, model.size_y, model.size_z, 1./model.resolution) vol.center_origin() s = meep_utils.init_structure(model=model, volume=vol, pml_axes=meep.Z) f = meep.fields(s) # Define the Bloch-periodic boundaries (any transversal component of k-vector is allowed) f.use_bloch(meep.X, getattr(model, 'Kx', 0) / (-2*np.pi)) f.use_bloch(meep.Y, getattr(model, 'Ky', 0) / (-2*np.pi)) # Add the field source (see meep_utils for an example of how an arbitrary source waveform is defined) if not getattr(model, 'frequency', None): ## (temporal source shape) #src_time_type = meep.band_src_time(model.src_freq/c, model.src_width/c, model.simtime*c/1.1) src_time_type = meep.gaussian_src_time(model.src_freq/c, model.src_width/c) else: src_time_type = meep.continuous_src_time(getattr(model, 'frequency', None)/c) srcvolume = meep.volume( ## (spatial source shape) meep.vec(-model.size_x/2, -model.size_y/2, -model.size_z/2+model.pml_thickness), meep.vec( model.size_x/2, model.size_y/2, -model.size_z/2+model.pml_thickness)) #f.add_volume_source(meep.Ex, src_time_type, srcvolume) ## Replace the f.add_volume_source(meep.Ex, srctype, srcvolume) line with following: ## Option for a custom source (e.g. exciting some waveguide mode) class SrcAmplitudeFactor(meep.Callback): ## The source amplitude is complex -> phase factor modifies its direction ## todo: implement in MEEP: we should define an AmplitudeVolume() object and reuse it for monitors later def __init__(self, Kx=0, Ky=0): meep.Callback.__init__(self) (self.Kx, self.Ky) = Kx, Ky def complex_vec(self, vec): ## Note: the 'vec' coordinates are _relative_ to the source center # (oblique) plane wave source: return np.exp(-1j*(self.Kx*vec.x() + self.Ky*vec.y())) # (oblique) Gaussian beam source:
f.use_bloch(meep.X, getattr(model, 'Kx', 0) / (-2 * np.pi)) f.use_bloch(meep.Y, getattr(model, 'Ky', 0) / (-2 * np.pi)) f.use_bloch(meep.Z, getattr(model, 'Kz', 0) / (-2 * np.pi)) # Add the field source (see meep_utils for an example of how an arbitrary source waveform is defined) if not getattr(model, 'frequency_domain', None): ## Select the source dependence on time src_time_type = meep_utils.band_src_time(model.src_freq / c, model.src_width / c, model.simtime * c / 10) #src_time_type = meep.gaussian_src_time(model.src_freq/c, model.src_width/c) else: src_time_type = meep.continuous_src_time( getattr(model, 'frequency', None) / c) srcvolume = meep.volume( ## Source must fill the whole simulation volume meep.vec(-model.size_x / 2, -model.size_y / 2, -model.size_z / 2), meep.vec(model.size_x / 2, model.size_y / 2, model.size_z / 2)) class AmplitudeFactor(meep.Callback): def __init__(self, Kx=0, Ky=0, Kz=0): meep.Callback.__init__(self) (self.Kx, self.Ky, self.Kz) = Kx, Ky, Kz def complex_vec( self, vec ): ## Note: the 'vec' coordinates are _relative_ to the source center ## Current-driven homogenisation source forces the K-vector in whole unit cell return np.exp( -1j * (self.Kx * vec.x() + self.Ky * vec.y() + self.Kz * vec.z()))
vol = meep.vol3d(model.size_x, model.size_y, model.size_z, 1. / model.resolution) vol.center_origin() s = meep_utils.init_structure(model=model, volume=vol, pml_axes=meep.Z) ## Create fields with Bloch-periodic boundaries f = meep.fields(s) # Define the Bloch-periodic boundaries (any transversal component of k-vector is allowed) f.use_bloch(meep.X, getattr(model, 'Kx', 0) / (-2 * np.pi)) f.use_bloch(meep.Y, getattr(model, 'Ky', 0) / (-2 * np.pi)) # Add the field source (see meep_utils for an example of how an arbitrary source waveform is defined) src_time_type = meep.gaussian_src_time(model.src_freq / c, model.src_width / c) #src_time_type = meep.continuous_src_time(model.src_freq/c) srcvolume = meep.volume( meep.vec(-model.size_x / 2, -model.size_y / 2, -model.size_z / 2 + model.pml_thickness), meep.vec(+model.size_x / 2, +model.size_y / 2, -model.size_z / 2 + model.pml_thickness)) #f.add_volume_source(meep.Ex, src_time_type, srcvolume) class SrcAmplitudeFactor(meep.Callback): ## The source amplitude is complex -> phase factor modifies its direction ## todo: implement in MEEP: we should define an AmplitudeVolume() object and reuse it for monitors later def __init__(self, Kx=0, Ky=0): meep.Callback.__init__(self) (self.Kx, self.Ky) = Kx, Ky def complex_vec( self, vec
field = meep.fields(s) #field.use_bloch(meep.Z, 1) ## periodic along the cylinder XXX # (removing cylinder caps -> making an infinite waveguide with periodic boundary condition, change pml_axes=meep.XY) # Add the field source (see meep_utils for an example of how an arbitrary source waveform is defined) if not sim_param['frequency_domain']: ## Select the source dependence on time #src_time_type = meep.band_src_time(-model.src_freq/c, model.src_width/c, model.simtime*c/1.1) src_time_type = meep.gaussian_src_time( -model.src_freq / c, model.src_width / c) ## negative frequency supplied -> e^(+i omega t) convention else: src_time_type = meep.continuous_src_time( -sim_param['frequency'] / c ) ## TODO check in freq domain that negative frequency is OK, and is it needed? srcvolume = meep.volume( meep.vec(model.radius * .15, -model.radius * .25, -model.height * .15), meep.vec(model.radius * .15, -model.radius * .25, -model.height * .15)) field.add_volume_source( meep.Ez, src_time_type, srcvolume ) ## source of oblique polarization - excites both TE and TM modes field.add_volume_source(meep.Ex, src_time_type, srcvolume) slice_makers = [] #slice_makers += [meep_utils.Slice(model=model, field=field, components=(meep.Ex, meep.Ey, meep.Ez), at_t=3, name="ElectricAtEnd")] #slice_makers += [meep_utils.Slice(model=model, field=field, components=(meep.Hx, meep.Hy, meep.Hz), at_t=3, name="MagneticAtEnd")] #slice_makers = [meep_utils.Slice(model=model, field=field, components=(meep.Dielectric), at_t=0, name='EPS')] if not sim_param['frequency_domain']: ## time-domain computation field.step() dt = (field.time() / c) meep_utils.lorentzian_unstable_check_new(model, dt, quit_on_warning=False)
#model = Fishnet_model(**model_param) #model = Wedge_model(**model_param) #from model_SapphireBars import * #model = SapphireBars(**model_param) if sim_param['frequency_domain']: model.simulation_name += ("_frequency=%.4e" % sim_param['frequency']) meep.master_printf("Simulation name:\n\t%s\n" % model.simulation_name) ## TODO print parameters in a table ## Initialize volume vol = meep.vol3d(model.size_x, model.size_y, model.size_z, 1. / model.resolution) volume_except_pml = meep.volume( meep.vec(-model.size_x / 2, -model.size_y / 2, -model.size_z / 2 + model.pml_thickness * 0), meep.vec(model.size_x / 2, model.size_y / 2, model.size_z / 2 - model.pml_thickness * 0)) vol.center_origin() ## Define the Perfectly Matched Layers #perfectly_matched_layers = meep.pml(model.pml_thickness, meep.Z) ## PML on both faces at Z axis perfectly_matched_layers = meep.pml(model.pml_thickness) ## PML on all faces if not sim_param['frequency_domain']: meep.master_printf("== Time domain structure setup ==\n") ## Define each polarizability by redirecting the callback to the corresponding "where_material" function ## Define the frequency-independent epsilon for all materials (needed here, before defining s, or unstable) model.double_vec = model.eps meep.set_EPS_Callback(model.__disown__()) s = meep.structure(vol, meep.EPS, perfectly_matched_layers,
#model = PKCutSheet_model_test(**model_param) #model = Fishnet_model(**model_param) model = Wedge_model(**model_param) #from model_SapphireBars import * #model = SapphireBars(**model_param) if sim_param['frequency_domain']: model.simulation_name += ("_frequency=%.4e" % sim_param['frequency']) meep.master_printf("Simulation name:\n\t%s\n" % model.simulation_name) ## TODO print parameters in a table ## Initialize volume vol = meep.vol3d(model.size_x, model.size_y, model.size_z, 1./model.resolution) volume_except_pml = meep.volume( meep.vec(-model.size_x/2, -model.size_y/2, -model.size_z/2+model.pml_thickness*0), meep.vec(model.size_x/2, model.size_y/2, model.size_z/2-model.pml_thickness*0)) vol.center_origin() ## Define the Perfectly Matched Layers perfectly_matched_layers = meep.pml(model.pml_thickness) ## PML on both faces at Z axis if not sim_param['frequency_domain']: meep.master_printf("== Time domain structure setup ==\n") ## Define each polarizability by redirecting the callback to the corresponding "where_material" function ## Define the frequency-independent epsilon for all materials (needed here, before defining s, or unstable) model.double_vec = model.get_static_permittivity; meep.set_EPS_Callback(model.__disown__()) s = meep.structure(vol, meep.EPS, perfectly_matched_layers, meep.identity()) ## Add all the materials model.build_polarizabilities(s)
vol.center_origin() s = meep_utils.init_structure(model=model, volume=vol, sim_param=sim_param, pml_axes="All") ## XXX meep.XY ## Create the fields object, and define the Bloch-periodic boundaries (any transversal component of k-vector is allowed) field = meep.fields(s) #field.use_bloch(meep.Z, 1) ## periodic along the cylinder XXX # (removing cylinder caps -> making an infinite waveguide with periodic boundary condition, change pml_axes=meep.XY) # Add the field source (see meep_utils for an example of how an arbitrary source waveform is defined) if not sim_param['frequency_domain']: ## Select the source dependence on time #src_time_type = meep.band_src_time(-model.src_freq/c, model.src_width/c, model.simtime*c/1.1) src_time_type = meep.gaussian_src_time(-model.src_freq/c, model.src_width/c) ## negative frequency supplied -> e^(+i omega t) convention else: src_time_type = meep.continuous_src_time(-sim_param['frequency']/c) ## TODO check in freq domain that negative frequency is OK, and is it needed? srcvolume = meep.volume( meep.vec(model.radius*.15, -model.radius*.25, -model.height*.15), meep.vec(model.radius*.15, -model.radius*.25, -model.height*.15)) field.add_volume_source(meep.Ez, src_time_type, srcvolume) ## source of oblique polarization - excites both TE and TM modes field.add_volume_source(meep.Ex, src_time_type, srcvolume) slice_makers = [] #slice_makers += [meep_utils.Slice(model=model, field=field, components=(meep.Ex, meep.Ey, meep.Ez), at_t=3, name="ElectricAtEnd")] #slice_makers += [meep_utils.Slice(model=model, field=field, components=(meep.Hx, meep.Hy, meep.Hz), at_t=3, name="MagneticAtEnd")] #slice_makers = [meep_utils.Slice(model=model, field=field, components=(meep.Dielectric), at_t=0, name='EPS')] if not sim_param['frequency_domain']: ## time-domain computation field.step() dt = (field.time()/c) meep_utils.lorentzian_unstable_check_new(model, dt, quit_on_warning=False) timer = meep_utils.Timer(simtime=model.simtime); meep.quiet(True) # use custom progress messages monitor_point = meep.vec(-model.radius*.5, model.radius*.3, model.height*.3)
vol.center_origin() s = meep_utils.init_structure(model=model, volume=vol, pml_axes="None") f = meep.fields(s) # Define the Bloch-periodic boundaries (any transversal component of k-vector is allowed) f.use_bloch(meep.X, getattr(model, 'Kx', 0) / (-2*np.pi)) f.use_bloch(meep.Y, getattr(model, 'Ky', 0) / (-2*np.pi)) f.use_bloch(meep.Z, getattr(model, 'Kz', 0) / (-2*np.pi)) # Add the field source (see meep_utils for an example of how an arbitrary source waveform is defined) if not getattr(model, 'frequency_domain', None): ## Select the source dependence on time src_time_type = meep_utils.band_src_time(model.src_freq/c, model.src_width/c, model.simtime*c/10) #src_time_type = meep.gaussian_src_time(model.src_freq/c, model.src_width/c) else: src_time_type = meep.continuous_src_time(getattr(model, 'frequency', None)/c) srcvolume = meep.volume( ## Source must fill the whole simulation volume meep.vec(-model.size_x/2, -model.size_y/2, -model.size_z/2), meep.vec( model.size_x/2, model.size_y/2, model.size_z/2)) class AmplitudeFactor(meep.Callback): def __init__(self, Kx=0, Ky=0, Kz=0): meep.Callback.__init__(self) (self.Kx, self.Ky, self.Kz) = Kx, Ky, Kz def complex_vec(self, vec): ## Note: the 'vec' coordinates are _relative_ to the source center ## Current-driven homogenisation source forces the K-vector in whole unit cell return np.exp(-1j*(self.Kx*vec.x() + self.Ky*vec.y() + self.Kz*vec.z())) af = AmplitudeFactor(Kx=getattr(model, 'Kx',.0), Ky=getattr(model, 'Ky',.0), Kz=getattr(model, 'Kz',.0)) meep.set_AMPL_Callback(af.__disown__()) f.add_volume_source(meep.Ex, src_time_type, srcvolume, meep.AMPL) ## Define the volume monitor for CDH monitor_options = {'size_x':model.size_x, 'size_y':model.size_y, 'size_z':model.size_z,
eps_matrix = numpy.absolute( eps_matrix / numpy.amax(eps_matrix))**2 * modulation print(eps_matrix[10, 10]) # grating = numpy.abs(eps_matrix) ** 2 # plt.figure(1) # plt.imshow(_eps_matrix, cmap='hot', extent=[0, gridSizeX, 0, gridSizeY]) # plt.colorbar() # plt.show() meep.master_printf("Setting the material matrix...\n") self.set_matrix_2D(eps_matrix, vol) # self.setMatrix(grating) self.stored_eps_matrix = eps_matrix # to prevent the garbage collector from cleaning up the matrix... meep.master_printf("MeepMaterial object initialized.\n") meep.set_EPS_Callback(epsilon().__disown__()) struct = meep.structure(vol, EPS, no_pml()) fld = meep.fields(struct) fld.add_volume_source(Ex, gaussian_src_time(freq_read / c, 1.5e9 / c), vol) while fld.time() / c < 30e-15: fld.step() meep.print_f.get_field(Ex, meep.vec(0.5e-6, 0.5e-6, 3e-6)) meep.del_EPS_Callback()
## Initialize volume, structure and the fields according to the model vol = meep.vol3d(model.size_x, model.size_y, model.size_z, 1./model.resolution) vol.center_origin() s = meep_utils.init_structure(model=model, volume=vol, pml_axes=meep.Z) ## Create fields with Bloch-periodic boundaries f = meep.fields(s) # Define the Bloch-periodic boundaries (any transversal component of k-vector is allowed) f.use_bloch(meep.X, getattr(model, 'Kx', 0) / (-2*np.pi)) f.use_bloch(meep.Y, getattr(model, 'Ky', 0) / (-2*np.pi)) # Add the field source (see meep_utils for an example of how an arbitrary source waveform is defined) src_time_type = meep.gaussian_src_time(model.src_freq/c, model.src_width/c) #src_time_type = meep.continuous_src_time(model.src_freq/c) srcvolume = meep.volume( meep.vec(-model.size_x/2, -model.size_y/2, -model.size_z/2+model.pml_thickness), meep.vec(+model.size_x/2, +model.size_y/2, -model.size_z/2+model.pml_thickness)) #f.add_volume_source(meep.Ex, src_time_type, srcvolume) class SrcAmplitudeFactor(meep.Callback): ## The source amplitude is complex -> phase factor modifies its direction ## todo: implement in MEEP: we should define an AmplitudeVolume() object and reuse it for monitors later def __init__(self, Kx=0, Ky=0): meep.Callback.__init__(self) (self.Kx, self.Ky) = Kx, Ky def complex_vec(self, vec): ## Note: the 'vec' coordinates are _relative_ to the source center # (oblique) plane wave source: return np.exp(-1.0j*(self.Kx*vec.x() + self.Ky*vec.y())) # (oblique) Gaussian beam source: #return np.exp(-1j*(self.Kx*vec.x() + self.Ky*vec.y()) - (vec.x()/100e-6)**2 - (vec.y()/100e-6)**2)