Beispiel #1
0
 def __init__(self, **kwargs):
     #if a keyword argument 'simul_params' is provided, then expand it into a list of keyword arguments and join it with the current keyword arguments
     if 'simul_params' in kwargs:
         p = kwargs['simul_params']
         if "component" in p:
             p["structure"] = p["component"]
             del p["component"]
             from pysimul.log import PYSIMUL_LOG as LOG
             LOG.deprecation_warning(
                 "Please switch the name of simulation parameter 'component' to 'structure'.",
                 3)
         if (not isinstance(p, dict)):
             raise PythonSimulateException(
                 "Keyword argument 'simul_params' must be of type 'dict'. Current type is : '%'"
                 % type(p))
         props = self.__unlocked_properties__()
         for name, val in p.items():
             if isinstance(val, SimulationParameterContainer):
                 self.__set_properties__(val, p)
             elif isinstance(val, list):
                 for v in val:
                     if isinstance(v, SimulationParameterContainer):
                         self.__set_properties__(v, p)
             if name in props:
                 kwargs[name] = val
         del kwargs['simul_params']
     super(SimulationParameterContainer, self).__init__(**kwargs)
 def get_window_south_west(self):
     if (not self.has_window_defined()):
         return self.size_info().south_west
     else:
         LOG.debug("Simulation window size : %f x %f" %
                   (self.window_width, self.window_height))
         sw = self.window_size_info.south_west
         return sw
 def define_geometry(self):
     LOG.debug("Running virtual fabrication 3d on structure %s...")
     from ipkiss.plugins.vfabrication.vfabrication import virtual_fabrication_3d
     vf = virtual_fabrication_3d(
         structure=self.structure,
         include_growth=self.include_growth,
         environment=self.environment,
         grid=1.0 /
         (float(self.resolution_factor) * float(self.resolution)),
         process_flow=self.vfabrication_process_flow,
         material_stack_factory=self.material_stack_factory)
     geometry = vf.geometry
     LOG.debug("Virtual fabrication ready.")
     return geometry
 def get_material_dataset_for_subset(self, corner, width, height, angle=0):
     angle = angle % 360.0
     H = do_hash("%s-%f-%f-%f" % (str(corner), width, height, angle))
     #cache already requested datasets in a dictionary attribute
     total_resolution = self.get_total_resolution()
     if not (H in self.material_dataset_dict):
         corner = Coord2(corner[0], corner[1])
         w_range = numpy.arange(0, numpy.ceil(width * total_resolution))
         h_range = numpy.arange(0, numpy.ceil(height * total_resolution))
         LOG.debug(
             "Creating the material matrix with resolution of %i : %i x %i elements."
             % (total_resolution, len(w_range), len(h_range)))
         mat = numpy.zeros([len(w_range), len(h_range)], Material)
         if (angle != 0):
             for w in w_range:
                 delta_w = float(w) / total_resolution
                 current_corner = corner.move_polar_copy(delta_w, angle)
                 for h in h_range:
                     delta_h = float(h) / total_resolution
                     point = current_corner.move_polar_copy(
                         delta_h, angle + 90)
                     mat[w, h] = self.geometry.get_material(point)
             self.material_dataset_dict[H] = mat
         else:
             #faster implementation for the special case where angle == 0
             ref_point = corner - self.geometry.size_info.south_west
             delta_x = int(ref_point[0] * float(total_resolution))
             delta_y = int(ref_point[1] * float(total_resolution))
             x_min = max(0, min(w_range) + delta_x)
             y_min = max(0, min(h_range) + delta_y)
             x_max = max(w_range) + delta_x
             y_max = max(h_range) + delta_y
             full_material_array = self.geometry.get_material_array()
             mat = full_material_array[x_min:x_max + 1, y_min:y_max + 1]
             self.material_dataset_dict[H] = mat
     return self.material_dataset_dict[H]
    def __init__(self, simul_params):
        if "component" in simul_params:
            #FIXME -- THIS MAY BE REMOVED IN A LATER PHASE...
            simul_params["structure"] = simul_params["component"]
            del simul_params["component"]
            LOG.deprecation_warning(
                "Please switch the name of simulation parameter 'component' to 'structure'.",
                -1)
        struct = simul_params["structure"]
        simul_params["simulation_id"] = struct.name.replace("<", "").replace(
            ">", "")
        if "vfabrication_process_flow" not in simul_params:
            simul_params[
                "vfabrication_process_flow"] = TECH.VFABRICATION.PROCESS_FLOW
        if "material_stack_factory" not in simul_params:
            simul_params["material_stack_factory"] = TECH.MATERIAL_STACKS
        dim = self.__get_simulation_dimension__(simul_params)

        if dim == 2:
            if ("engine" in simul_params):
                # FIXME: ENgine should check its parameters itself.
                # Possible solution: add parameter check to StrongPropertyInitializer
                # to check parameter requirements without need for instantiation.
                try:
                    from pysimul.runtime.camfr_engine.camfr_engine import CamfrEngine
                except ImportError:
                    pass
                try:
                    from pysimul.runtime.MeepFDTD.MeepFDTD import MeepSimulationEngine
                except ImportError:
                    pass

                if 'CamfrEngine' in sys.modules and isinstance(
                        simul_params["engine"], CamfrEngine):
                    if ("resolution_factor" not in simul_params) or (
                            simul_params["resolution_factor"] != 1):
                        simul_params["resolution_factor"] = 1
                        LOG.warning(
                            "Parameter 'resolution_factor' forced to 1 for CAMFR engine."
                        )

                elif 'MeepSimulationEngine' in sys.modules and isinstance(
                        simul_params["engine"], MeepSimulationEngine):
                    if ("resolution_factor" not in simul_params):
                        simul_params["resolution_factor"] = 2
                        LOG.warning(
                            "Parameter 'resolution_factor' was missing and thus set to 2 for MEEP engine."
                        )

        SimulationDefinition.__init__(self, simul_params=simul_params)
Beispiel #6
0
    def visualize(self, aspect_ratio_equal=True):
        LOG.debug("Preparing the 2D visualization...")
        from dependencies.matplotlib_wrapper import Figure
        from dependencies.shapely_wrapper import PolygonPatch
        geom = self.simulation_volume.geometry
        si = geom.size_info
        fig = Figure()
        ax = fig.add_axes([0.05, 0.05, 0.85, 0.85], projection='rectilinear')
        LOG.debug("Painting the polygons per material stack type...")
        total = len(geom.material_stacks_shapely_polygons)
        count = 0.0
        from dependencies.shapely_wrapper import Polygon, PolygonPatch
        references_for_legend = dict()
        for (material_stack_id, mb) in geom.material_stacks_shapely_polygons:
            color = geom.material_stack_factory[
                material_stack_id].display_style.color.html_string()
            if (not (mb is None)) and (not mb.georep.is_empty):
                for polygon in mb.georep_list:
                    if isinstance(polygon, Polygon):
                        patch = PolygonPatch(polygon, fc=color)
                        patch.set_linewidth(1)
                        ax.add_patch(patch)
                        references_for_legend[material_stack_id] = (
                            patch,
                            geom.material_stack_factory[material_stack_id].name
                        )
                    else:
                        LOG.error(
                            "An element of type %s will not be plotted." %
                            type(polygon))
            count = count + 1.0
            percent_complete = int(count / total * 100.0)
        if aspect_ratio_equal:
            ax.set_aspect('equal')

        ##legend
        from dependencies.matplotlib_wrapper import font_manager
        prop = font_manager.FontProperties(size=10)
        patches_for_legend = [ref[0] for ref in references_for_legend.values()]
        labels_for_legend = [ref[1] for ref in references_for_legend.values()]

        ax.legend(patches_for_legend,
                  labels_for_legend,
                  loc=(0.5, 0.9),
                  prop=prop)

        ax.autoscale_view()

        return fig
Beispiel #7
0
 def set_camfr_settings(self, camfr_technology):
     camfr_technology.overwrite_allowed = ["WAVELENGTH"]
     self.camfr_technology = camfr_technology
     if (type(self.camfr_technology.WAVELENGTH) == int):
         raise Exception(
             "Invalid type for camfr_technology.WAVELENGTH : expected float, not int. "
         )
     if (self.camfr_technology.WAVELENGTH >
             1.7) or (self.camfr_technology.WAVELENGTH < 1.0):
         raise Exception(
             "Invalid range for camfr_technology.WAVELENGTH : expected a float value between 1.0 (1000 nm) and 1.7 (1.7000nm). "
         )
     camfr.set_lambda(self.camfr_technology.WAVELENGTH)
     LOG.debug("Camfr wavelength : %f micron" %
               self.camfr_technology.WAVELENGTH)
     camfr.set_N(self.camfr_technology.NMODES)
     LOG.debug("Camfr number of modes : %i" % self.camfr_technology.NMODES)
     camfr.set_polarisation(self.camfr_technology.POLARIZATION)
     LOG.debug("Camfr polarization : %s" %
               str(self.camfr_technology.POLARIZATION))
     camfr.set_lower_PML(self.camfr_technology.PML)
     camfr.set_upper_PML(self.camfr_technology.PML)
     LOG.debug("Camfr PML : %f" % self.camfr_technology.PML)
 def __init__(self, **kwargs):
     super(StructureSimulationVolume2D, self).__init__(**kwargs)
     LOG.debug("Size of simulation volume : %f x %f" %
               (self.width, self.height))
Beispiel #9
0
    def field_for_geometry(
            self,
            geometry,
            field_extraction_geometry_x_positions=[],
            field_extraction_grid=0.01,
            max_slabs=None,
            geometry_figure_filename="geometry_for_camfr_field_calculation_%s.png",
            mode_profile_figure_filename="mode_profile_%s.png",
            geometry_name=None,
            validation_criterium=__criterium_always_ok__,
            ref_filename=None,
            delta_wavelength_faulty_result=0.000001,
            inc_field=None):
        LOG.debug("Now starting camfr_engine::field_for_geometry...")
        mode_profile_figure_filename = mode_profile_figure_filename % geometry_name
        if len(field_extraction_geometry_x_positions) == 0:
            raise PythonSimulateException(
                "Please specify the x positions at which to extract the field profiles. Parameter 'field_extraction_geometry_x_positions' is empty list."
            )

        maximum_faulty_iterations = 5
        validation = False
        iterations_counter = 0

        while (not validation) and (iterations_counter <
                                    maximum_faulty_iterations):
            camfr_stack_expr = self.get_camfr_stack_expr_for_geometry(
                geometry=geometry,
                max_slabs=max_slabs,
                geometry_figure_filename=geometry_figure_filename,
                geometry_name=geometry_name)
            camfr_stack = camfr.Stack(camfr_stack_expr)
            LOG.debug("Camfr stack dimensions : (%f,%f)" %
                      (camfr_stack.length(), camfr_stack.width()))
            #set the incident field and calculate
            if inc_field is None:
                self.set_inc_field(camfr_stack)
            else:
                self.set_mode_profile_field(camfr_stack, inc_field, si.south)

            LOG.debug("Initiating the camfr calculation...")
            camfr_stack.calc()

            #LOG.debug("Initiating the camfr plot...")
            #camfr_stack.plot() - doesn't work with Python 2.6 yet
            beta = camfr_stack.inc().mode(0).kz()
            si = geometry.size_info
            camfr_z_positions = [
                p - si.west for p in field_extraction_geometry_x_positions
            ]

            field_profiles = []
            for z_position in camfr_z_positions:
                LOG.debug(
                    "Now getting the field profile for Camfr z-position %f (geometry position %f)..."
                    % (z_position, z_position + si.west))
                # get the field profile
                f = []
                invalid_probing = True
                geometry_y_positions = numpy.arange(si.south, si.north,
                                                    field_extraction_grid)
                camfr_x_positions = geometry_y_positions - si.south
                for camfr_x in camfr_x_positions:
                    coord = camfr.Coord(camfr_x, 0.0, z_position)
                    cf = camfr_stack.field(coord)
                    f += [
                        ElectroMagneticField(value=[
                            ElectricField(value=(cf.Ez(), cf.E1(), cf.E2())),
                            MagneticField(value=(cf.Hz(), cf.H1(), cf.H2()))
                        ])
                    ]
                geometry_x_position = z_position + si.west
                fp = ElectroMagneticFieldProfile2D(positions=[
                    Coord2(geometry_x_position, camfr_x + si.south)
                    for camfr_x in camfr_x_positions
                ],
                                                   fields=f)
                field_profiles.append(fp)
                transmission = camfr_stack.T21(0, 0)

                if self.save_images:
                    #ensure that output directories exist
                    csv_output_dir = "pysimul_camfr_output/csv/"
                    if not os.path.exists(csv_output_dir):
                        os.makedirs(csv_output_dir)
                    img_output_dir = "pysimul_camfr_output/images/"
                    if not os.path.exists(img_output_dir):
                        os.makedirs(img_output_dir)

                    #from dependencies.matplotlib_wrapper import pyplot

                    #save field to file (image and csv)
                    #Hz
                    #save to image
                    #pyplot.clf()
                    #field_for_plot_real = [f.H.value.z.real for f in fp.fields]  #Hz | Ey -> f.E.value.y
                    #field_for_plot_imag = [f.H.value.z.imag for f in fp.fields]
                    #field_for_plot_abs = list(abs(numpy.array(field_for_plot_real) + (1j)*numpy.array(field_for_plot_imag)))
                    #pyplot.plot(geometry_y_positions,field_for_plot_abs ,'g')
                    #pyplot.plot(geometry_y_positions,field_for_plot_real,'b')
                    #pyplot.plot(geometry_y_positions,field_for_plot_imag,'r')
                    image_file = "%sHz_%f_W%f_%s" % (
                        img_output_dir, geometry_x_position,
                        self.camfr_technology.WAVELENGTH,
                        mode_profile_figure_filename)
                    #pyplot.savefig(image_file)
                    #save values to csv
                    csv_file = image_file.replace('images', 'csv')
                    csv_file = csv_file.replace('png', 'csv')
                    csv_file_handle = open(csv_file, 'w')
                    data_for_csv = [[
                        p, f.H.value.z.real
                    ] for p, f in zip(geometry_y_positions, fp.fields)]
                    numpy.savetxt(csv_file_handle,
                                  numpy.array(data_for_csv),
                                  delimiter=', ')
                    csv_file_handle.close()

                    #Hy
                    #save to image
                    #pyplot.clf()
                    #field_for_plot_real = [f.H.value.y.real for f in fp.fields]  #Hz | Ey -> f.E.value.y
                    #field_for_plot_imag = [f.H.value.y.imag for f in fp.fields]
                    #field_for_plot_abs = list(abs(numpy.array(field_for_plot_real) + (1j)*numpy.array(field_for_plot_imag)))
                    #pyplot.plot(geometry_y_positions,field_for_plot_abs ,'g')
                    #pyplot.plot(geometry_y_positions,field_for_plot_real,'b')
                    #pyplot.plot(geometry_y_positions,field_for_plot_imag,'r')
                    image_file = "%sHy_%f_W%f_%s" % (
                        img_output_dir, geometry_x_position,
                        self.camfr_technology.WAVELENGTH,
                        mode_profile_figure_filename)
                    #pyplot.savefig(image_file)
                    #save values to csv
                    csv_file = image_file.replace('images', 'csv')
                    csv_file = csv_file.replace('png', 'csv')
                    csv_file_handle = open(csv_file, 'w')
                    data_for_csv = [[
                        p, f.H.value.y.real
                    ] for p, f in zip(geometry_y_positions, fp.fields)]
                    numpy.savetxt(csv_file_handle,
                                  numpy.array(data_for_csv),
                                  delimiter=', ')
                    csv_file_handle.close()

                    #Hx
                    #save to image
                    #pyplot.clf()
                    #field_for_plot_real = [f.H.value.x.real for f in fp.fields]  #Hz | Ey -> f.E.value.y
                    #field_for_plot_imag = [f.H.value.x.imag for f in fp.fields]
                    #field_for_plot_abs = list(abs(numpy.array(field_for_plot_real) + (1j)*numpy.array(field_for_plot_imag)))
                    #pyplot.plot(geometry_y_positions,field_for_plot_abs ,'g')
                    #pyplot.plot(geometry_y_positions,field_for_plot_real,'b')
                    #pyplot.plot(geometry_y_positions,field_for_plot_imag,'r')
                    image_file = "%sHx_%f_W%f_%s" % (
                        img_output_dir, geometry_x_position,
                        self.camfr_technology.WAVELENGTH,
                        mode_profile_figure_filename)
                    #pyplot.savefig(image_file)
                    #save values to csv
                    csv_file = image_file.replace('images', 'csv')
                    csv_file = csv_file.replace('png', 'csv')
                    csv_file_handle = open(csv_file, 'w')
                    data_for_csv = [[
                        p, f.H.value.x.real
                    ] for p, f in zip(geometry_y_positions, fp.fields)]
                    numpy.savetxt(csv_file_handle,
                                  numpy.array(data_for_csv),
                                  delimiter=', ')
                    csv_file_handle.close()

                    #Ez
                    #save to image
                    #pyplot.clf()
                    #field_for_plot_real = [f.E.value.z.real for f in fp.fields]
                    #field_for_plot_imag = [f.E.value.z.imag for f in fp.fields]
                    #field_for_plot_abs = list(abs(numpy.array(field_for_plot_real) + (1j)*numpy.array(field_for_plot_imag)))
                    #pyplot.plot(geometry_y_positions,field_for_plot_abs ,'g')
                    #pyplot.plot(geometry_y_positions,field_for_plot_real,'b')
                    #pyplot.plot(geometry_y_positions,field_for_plot_imag,'r')
                    image_file = "%sEz_%f_W%f_%s" % (
                        img_output_dir, geometry_x_position,
                        self.camfr_technology.WAVELENGTH,
                        mode_profile_figure_filename)
                    #pyplot.savefig(image_file)
                    ##save values to csv
                    csv_file = image_file.replace('images', 'csv')
                    csv_file = csv_file.replace('png', 'csv')
                    csv_file_handle = open(csv_file, 'w')
                    data_for_csv = [[
                        p, f.E.value.z.real
                    ] for p, f in zip(geometry_y_positions, fp.fields)]
                    numpy.savetxt(csv_file_handle,
                                  numpy.array(data_for_csv),
                                  delimiter=', ')
                    csv_file_handle.close()

                    #Ey
                    #save to image
                    #pyplot.clf()
                    #field_for_plot_real = [f.E.value.y.real for f in fp.fields]
                    #field_for_plot_imag = [f.E.value.y.imag for f in fp.fields]
                    #field_for_plot_abs = list(abs(numpy.array(field_for_plot_real) + (1j)*numpy.array(field_for_plot_imag)))
                    #pyplot.plot(geometry_y_positions,field_for_plot_abs ,'g')
                    #pyplot.plot(geometry_y_positions,field_for_plot_real,'b')
                    #pyplot.plot(geometry_y_positions,field_for_plot_imag,'r')
                    image_file = "%sEy_%f_W%f_%s" % (
                        img_output_dir, geometry_x_position,
                        self.camfr_technology.WAVELENGTH,
                        mode_profile_figure_filename)
                    #pyplot.savefig(image_file)
                    ##save values to csv
                    csv_file = image_file.replace('images', 'csv')
                    csv_file = csv_file.replace('png', 'csv')
                    csv_file_handle = open(csv_file, 'w')
                    data_for_csv = [[
                        p, f.E.value.y.real
                    ] for p, f in zip(geometry_y_positions, fp.fields)]
                    numpy.savetxt(csv_file_handle,
                                  numpy.array(data_for_csv),
                                  delimiter=', ')
                    csv_file_handle.close()

                    #Ex
                    #save to image
                    #pyplot.clf()
                    #field_for_plot_real = [f.E.value.x.real for f in fp.fields]
                    #field_for_plot_imag = [f.E.value.x.imag for f in fp.fields]
                    #field_for_plot_abs = list(abs(numpy.array(field_for_plot_real) + (1j)*numpy.array(field_for_plot_imag)))
                    #pyplot.plot(geometry_y_positions,field_for_plot_abs ,'g')
                    #pyplot.plot(geometry_y_positions,field_for_plot_real,'b')
                    #pyplot.plot(geometry_y_positions,field_for_plot_imag,'r')
                    image_file = "%sEx_%f_W%f_%s" % (
                        img_output_dir, geometry_x_position,
                        self.camfr_technology.WAVELENGTH,
                        mode_profile_figure_filename)
                    #pyplot.savefig(image_file)
                    ##save values to csv
                    csv_file = image_file.replace('images', 'csv')
                    csv_file = csv_file.replace('png', 'csv')
                    csv_file_handle = open(csv_file, 'w')
                    data_for_csv = [[
                        p, f.E.value.x.real
                    ] for p, f in zip(geometry_y_positions, fp.fields)]
                    numpy.savetxt(csv_file_handle,
                                  numpy.array(data_for_csv),
                                  delimiter=', ')
                    csv_file_handle.close()

            iterations_counter = iterations_counter + 1
            validation = validation_criterium(ref_filename, field_profiles)
            if (not validation):
                self.camfr_technology.WAVELENGTH = self.camfr_technology.WAVELENGTH + delta_wavelength_faulty_result
                LOG.warning(
                    "WARNING FROM CAMFR_ENGINE : little bit shift of wavelength due to wrong result. New wavelength = %f"
                    % self.camfr_technology.WAVELENGTH)
                self.set_camfr_settings(self.camfr_technology)

            camfr.free_tmps()

        if (iterations_counter >= maximum_faulty_iterations):
            LOG.warning(
                "ERROR FROM CAMFR_ENGINE : no result could be obtained that is accepted by the validation criterium ! Is your criterium correct ??"
            )

        return (field_profiles, beta, transmission)
Beispiel #10
0
    def get_camfr_stack_expr_for_geometry(
            self,
            geometry,
            max_slabs=None,
            geometry_figure_filename="geometry_for_camfr_field_calculation_%s.png",
            geometry_name=None):
        LOG.debug("Now starting camfr_engine::field_for_geometry...")
        geometry_figure_filename = geometry_figure_filename % geometry_name
        from pysics.materials.electromagnetics import get_epsilon_for_material_id
        #retrieve the material matrix for the geometry
        mat = geometry.get_material_array()
        #convert into matrix with epsilon valie
        from pysics.materials.electromagnetics import transform_material_stack_matrix_in_effective_index_epsilon_matrix
        eps = transform_material_stack_matrix_in_effective_index_epsilon_matrix(
            mat, geometry.material_stack_factory)
        #create auxiliary arrays for plotting
        grid_step = 1.0 / float(geometry.resolution)
        si = geometry.size_info
        len_x = eps.shape[0]
        len_y = eps.shape[1]
        X = numpy.linspace(si.west, si.east, num=len_x)
        Y = numpy.linspace(si.south, si.north, num=len_y)
        if self.save_images:
            #plot
            from pysics.materials.all import *
            #from dependencies.matplotlib_wrapper import pyplot
            #pyplot.clf()
            #pyplot.contourf(X, Y, eps.transpose(), antialiased = True) #transpose: for some reason, contourf uses flipped x en y axes.... the other matplotlib functions work on regular x/y axes...
            #pyplot.colorbar(orientation='vertical', format = '%i', shrink = 0.5)
            #pyplot.axis('equal')
            #pyplot.savefig(geometry_figure_filename, dpi=300)
        #create a working array 'deltas' with the same dimensions as eps : the first column should contain ones,
        #the other columns will indicate if there is a difference between that columns in "eps" and the next column
        deltas = numpy.ones_like(eps)
        d = numpy.diff(eps, axis=0)
        for d_counter in xrange(d.shape[0]):
            deltas[d_counter + 1] = d[d_counter]
        #now identify the slabs and their width
        slabs_specifications = []
        current_slab_eps = []
        current_slab_pixel_width = 0
        LOG.debug("Calculating the camfr slabs...")
        for eps_column, delta_column in zip(eps, deltas):
            if (any(delta_column)):
                #if the current eps-column is different from the previous ones, finish the previous slab and add it to the list "slabs_specifications"
                slabs_specifications.append(
                    (current_slab_eps, current_slab_pixel_width))
                #start a new slab
                current_slab_eps = eps_column
                current_slab_pixel_width = 1
            else:
                current_slab_pixel_width = current_slab_pixel_width + 1
        slabs_specifications.append(
            (current_slab_eps, current_slab_pixel_width))

        camfr_stack_expr = camfr.Expression()
        #must hold materials and slabs in an attribute list, otherwise camfr segmentation faults when cleanup by the garbage collector
        self.materials = dict()
        self.slabs = []
        #create camfr slabs
        if (max_slabs == None):
            max_slabs = len(slabs_specifications)
        stack_width = 0.0
        for slab_spec in slabs_specifications[1:max_slabs + 1]:
            eps_column = slab_spec[0]
            slab_width = slab_spec[1]
            if (slab_width == 0) and (len(slabs_specifications[1:]) == 1):
                raise PythonSimulateException(
                    "No slabs could be determined. Fatal error in camfr_engine::mode_profile_for_geometry (is your resolution high enough??)"
                )
            #do the same trick again, but now for the heights
            material_specifications = []
            current_material_eps = 0
            current_material_height = 0
            deltas = [1]
            for d in numpy.diff(eps_column):
                deltas.append(d)
            for eps, delta in zip(eps_column, deltas):
                if (delta != 0):
                    material_specifications.append(
                        (current_material_eps, current_material_height))
                    current_material_eps = eps
                    current_material_height = 1
                else:
                    current_material_height = current_material_height + 1
            material_specifications.append(
                (current_material_eps, current_material_height))
            LOG.debug("Camfr slab %i : z-width = %f - materials: " %
                      (len(self.slabs) + 1, slab_width * grid_step))
            for ms in material_specifications[1:]:
                LOG.debug("                n=%s, height=%s" %
                          (numpy.sqrt(ms[0]), ms[1] * grid_step))
            #now we know for the current slab which materials are needed with what height
            camfr_slab_expr = camfr.Expression()
            for mat_eps, mat_height in material_specifications[1:]:
                if mat_eps in self.materials:
                    mat = self.materials[mat_eps]
                else:
                    mat = camfr.Material(numpy.sqrt(mat_eps))
                    self.materials[mat_eps] = mat
                camfr_slab_expr.add(mat(mat_height * grid_step))
            camfr_slab = camfr.Slab(camfr_slab_expr)
            self.slabs.append(camfr_slab)
            #now add this slab to the camfr stack expression
            camfr_stack_expr.add(camfr_slab(slab_width * grid_step))
            stack_width = stack_width + slab_width
            LOG.debug("Camfr: cumulative width of slabs : %f" %
                      (stack_width * grid_step))
        LOG.debug("Camfr stack total width = %f" % (stack_width * grid_step))
        LOG.debug("Camfr stack expression created.")
        return camfr_stack_expr