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"
Example #3
0
 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)))
Example #5
0
    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
Example #6
0
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:
Example #7
0
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:
Example #8
0
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()))
Example #9
0
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)
Example #11
0
#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,
Example #12
0
#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)
Example #14
0
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, 
Example #15
0
        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)