model_param = meep_utils.process_param(sys.argv[1:]) model = metamaterial_models.models[model_param.get('model', 'default')](**model_param) ## 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) 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
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")]
def run(self): ## TEMPORARY SETTINGS wg_bottom = 0.7 wg_top = 0.7 + 0.22 wg_center = (wg_bottom + wg_top) / 2. #top = 0.7 + 0.38 ## preparing po = self.property_object self.engine.initialise_engine(self.landscape) fields = meep.fields(self.engine.structure) self.save_engine_dielectricum_to_file(po.eps_filename) ## Sources print 'Center wavelength:', po.wavelength print 'Bandwidth:', po.pulse_width center_freq = 1.0 / (float(po.wavelength)) pulse_width_freq = (float(po.pulse_width)) / ( float(po.wavelength)) * center_freq print 'Center frequency:', center_freq print 'Bandwidth:', pulse_width_freq if (po.pulsed_source): src = meep.gaussian_src_time(center_freq, pulse_width_freq) else: src = meep.continuous_src_time(center_freq) source_port_position = po.input_port.transform_copy( Translation(translation=(po.source_input_port_offset, 0))).position print 'wg_center_old:', wg_center wg_center = (po.input_port.wg_definition.process.wg_upper_z_coord + po.input_port.wg_definition.process.wg_lower_z_coord) / 2. print 'wg_center_new:', wg_center c = Coord3(source_port_position[0], source_port_position[1], wg_center) print 'coord:', c source_position_vec = self.make_meep_vec(c) fields.add_point_source(meep.Ey, src, source_position_vec) ## 2D Cross section volumes for oc in po.output_cuts: fn = '%s_eps.h5' % oc.filename vol = oc.get_output_volume(self.engine.meepVol) f_eps = meep.prepareHDF5File(fn) fields.output_hdf5(meep.Dielectric, vol, f_eps) del f_eps system('h5topng %s' % fn) ### Fluxplanes self.fluxes = [] for p in po.output_ports: pp = p.position port_width = p.wg_definition.wg_width wg_bottom = p.wg_definition.process.wg_lower_z_coord wg_top = p.wg_definition.process.wg_upper_z_coord ## Be aware: this is only for ports along y-axis!! vec_near = self.make_meep_vec( Coord3(pp[0], pp[1] - port_width / 2.0, wg_bottom)) vec_far = self.make_meep_vec( Coord3(pp[0], pp[1] + port_width / 2.0, wg_top)) fluxplane = meep.volume(vec_near, vec_far) fx = fields.add_dft_flux_plane( fluxplane, center_freq - (pulse_width_freq / 4.0), center_freq + (pulse_width_freq / 4.0), po.dft_terms) self.fluxes.append(fx) ## Reverse one of the fluxes if necessary if po.load_reversed_flux_from_file_ID > -1: self.fluxes[po.load_reversed_flux_from_file_ID].load_hdf5( fields, po.load_reversed_flux_from_file_filename) if (po.pulsed_source): stop = po.stop_time_multiplier * fields.last_source_time() else: stop = po.stop_time print 'Simulation will run for', stop, 'time units' output_files = [] for oc in po.output_cuts: fn = '%s.h5' % oc.filename oc_file = meep.prepareHDF5File(fn) output_files.append(oc_file) i = 0 n_o_output = 0 while (fields.time() < stop): if (i > po.output_steps): j = 0 for oc in po.output_cuts: vol = oc.get_output_volume(self.engine.meepVol) fields.output_hdf5(meep.Ey, vol, output_files[j], 1) j += 1 n_o_output += 1 i = 0 fields.step() i += 1 print n_o_output, 'images outputted' print 'Outputting field images..' del output_files[:] for oc in po.output_cuts: fn = '%s.h5' % oc.filename fn_eps = '%s_eps.h5' % oc.filename st = 'h5topng -t 0:%d -R -Zc dkbluered -a yarg -A %s %s' % ( n_o_output - 1, fn_eps, fn) print st system(st) print 'Outputting done!' #print 'obtaining fluxes:' self.flux_data = [] for i in range(len(po.output_ports)): fd = meep.getFluxData(self.fluxes[i]) self.flux_data.append(fd) #print fd ## Save flux data if necesarry if po.save_reversed_flux_to_file_ID > -1: fx = self.fluxes[po.save_reversed_flux_to_file_ID] fx.scale_dfts(-1) fx.save_hdf5(fields, po.save_reversed_flux_to_file_filename) return
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, meep.identity()) ## Add all the materials model.build_polarizabilities(s) ## Add the source dependence #srctype = meep.band_src_time(model.srcFreq/c, model.srcWidth/c, model.simtime*c/1.1) srctype = meep.gaussian_src_time(model.srcFreq / c, model.srcWidth / c) ## , 0, 1000e-12 ?? else: meep.master_printf( "== Frequency domain structure setup (for frequency of %g Hz) ==\n" % sim_param['frequency']) if (model.Kx != 0 or model.Ky != 0): print "Warning: frequency-domain solver may be broken for nonperpendicular incidence" ## Frequency-domain simulation does not support dispersive materials yet. We must define each material by ## using the nondispersive permittivity and the nondispersive conductivity ## (both calculated from polarizabilities at given frequency) ## Define the frequency-independent epsilon for all materials (has to be done _before_ defining s, or unstable) my_eps = meep_utils.MyHiFreqPermittivity(model, sim_param['frequency']) meep.set_EPS_Callback(my_eps.__disown__()) s = meep.structure(vol, meep.EPS, perfectly_matched_layers,
## 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) ## Add the source dependence #srctype = meep.band_src_time(model.srcFreq/c, model.srcWidth/c, model.simtime*c/1.1) srctype = meep.gaussian_src_time(model.srcFreq/c, model.srcWidth/c) ## , 0, 1000e-12 ?? else: meep.master_printf("== Frequency domain structure setup (for frequency of %g Hz) ==\n" % sim_param['frequency']) if (model.Kx!=0 or model.Ky!=0): print "Warning: frequency-domain solver may be broken for nonperpendicular incidence" ## Frequency-domain simulation does not support dispersive materials yet. We must define each material by ## using the nondispersive permittivity and the nondispersive conductivity ## (both calculated from polarizabilities at given frequency) ## Define the frequency-independent epsilon for all materials (has to be done _before_ defining s, or unstable) my_eps = meep_utils.MyHiFreqPermittivity(model, sim_param['frequency']) meep.set_EPS_Callback(my_eps.__disown__()) s = meep.structure(vol, meep.EPS, perfectly_matched_layers, meep.identity()) ## Create callback to set nondispersive conductivity (depends on material polarizabilities and frequency) mc = meep_utils.MyConductivity(model, sim_param['frequency'])
if sim_param['frequency_domain']: model.simulation_name += ("_frequency=%.4e" % sim_param['frequency']) ## Initialize volume and structure 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, 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()