Ejemplo n.º 1
0
    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)))
Ejemplo n.º 2
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
Ejemplo n.º 3
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:
Ejemplo n.º 4
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:
Ejemplo n.º 5
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()))
Ejemplo n.º 6
0
                 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
Ejemplo n.º 7
0
sim_param, model_param = meep_utils.process_param(sys.argv[1:])
model = PlasmonFilm_model(**model_param)
if sim_param['frequency_domain']: model.simulation_name += ("_frequency=%.4e" % sim_param['frequency'])

## 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, sim_param=sim_param, pml_axes="All")

## Create fields with Bloch-periodic boundaries 
f = meep.fields(s)

# Add the field source (see meep_utils for an example of how an arbitrary source waveform is defined)
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)


## Define visualisation output
slices =  [meep_utils.Slice(model=model, field=f, components=(meep.Dielectric), at_t=0, name='EPS')]
slices += [meep_utils.Slice(model=model, field=f, components=meep.Ez, at_y=0, min_timestep=.3e-15, outputgif=True, name='ParallelCut')]
slices += [meep_utils.Slice(model=model, field=f, components=meep.Ez, at_z=model.metalthick/2+model.resolution, min_timestep=.3e-15, outputgif=True, name='PerpendicularCut')]
slices += [meep_utils.Slice(model=model, field=f, components=meep.Ex, at_t=100e-15)]

if not sim_param['frequency_domain']:       ## time-domain computation
    f.step(); timer = meep_utils.Timer(simtime=model.simtime); meep.quiet(True) # use custom progress messages
    while (f.time()/c < model.simtime):     # timestepping cycle
        f.step()
        timer.print_progress(f.time()/c)
Ejemplo n.º 8
0
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)
Ejemplo n.º 9
0
    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
Ejemplo n.º 10
0
#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,
Ejemplo n.º 11
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)
Ejemplo n.º 12
0
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)
Ejemplo n.º 13
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,