示例#1
0
    def set_height(self, height):
        """(Deprecated) Set the height of the rectangle."""
        warning_message('set_width(...) is deprecated. Use property ' \
                        'myrect.width=... instead.', 'emopt.grid')

        libGrid.Rectangle_set_height(self._object, height)
        self._yspan = height
示例#2
0
    def set_width(self, width):
        """(Deprecated) Set the width of the rectangle.
        """
        warning_message('set_width(...) is deprecated. Use property ' \
                        'myrect.width=... instead.', 'emopt.grid')

        libGrid.Rectangle_set_width(self._object, width)
        self._xspan = width
示例#3
0
    def set_layer(self, layer):
        """Set the layer of the primitive.

        Parameters
        ----------
        layer : int
            The new layer.
        """
        warning_message('set_layer(...) is deprecated. Use property ' \
            'myprim.layer=... instead.', 'emopt.grid')
        libGrid.MaterialPrimitive_set_layer(self._object, c_int(layer))
示例#4
0
    def get_layer(self):
        """Get the layer of the primitive.

        Returns
        -------
        int
            The layer.
        """
        warning_message('get_layer() is deprecated. Use property ' \
            'myprim.layer instead.', 'emopt.grid')
        return libGrid.MaterialPrimitive_get_layer(self._object)
示例#5
0
    def set_for_version(self, value):
        self.for_version = self.for_version_prop.get_string_value()

        if self.for_version.startswith('3.'):
            ## disable lisp for wx > 2.8
            if self.codewriters_prop.get_string_value() == 'lisp':
                misc.warning_message( _('Generating Lisp code for wxWidgets version %s is not supported.\n'
                                        'Set version to "2.8" instead.') % self.for_version )
                self.for_version_prop.set_str_value('2.8')
                self.set_for_version('2.8')
                return
            self.codewriters_prop.enable_item('lisp', False)
        else:
            # enable lisp again
            self.codewriters_prop.enable_item('lisp', True)
示例#6
0
    def _set_language(self):
        "Set code generator language and adapt corresponding settings like file dialog wild cards (value: str or int)"
        language = self.language
        # update wildcards and default extension in the dialog
        self._update_output_path(language)

        # check that the new language supports all the widgets in the tree
        self.check_codegen()

        # disable lisp for wx > 2.8
        if language == 'lisp':
            for_version = self.for_version
            if for_version == '3.0':
                misc.warning_message(
                    _('Generating Lisp code for wxWidgets version %s is not supported.\n'
                      'Set version to "2.8" instead.') % self.for_version)
                self.properties["for_version"].set('2.8')
            self.properties["for_version"].set_blocked(True)
        else:
            self.properties["for_version"].set_blocked(False)

        # don't change the extension in multiple files mode
        if self.multiple_files == 1:
            return

        # update file extensions
        current_name = self.output_path
        if not current_name:
            return
        base, ext = os.path.splitext(current_name)

        # is already a valid extension? ext has a leading . but default_extensions hasn't
        if ext and ext[1:] in common.code_writers[language].default_extensions:
            return
        new_name = "%s.%s" % (
            base, common.code_writers[language].default_extensions[0])
        self.properties["output_path"].set(new_name)

        blocked = self.language != "C++"
        self.properties["source_extension"].set_blocked(blocked)
        self.properties["header_extension"].set_blocked(blocked)
示例#7
0
    def check_gradient(self, params, indices=[], plot=True):
        """Verify that the gradient is accurate.

        It is highly recommended that the accuracy of the gradients be checked
        prior to being used. If the accuracy is above ~1%, it is likely that
        there is an inconsitency between how the figure of merit and adjoint
        sources (dFdx) are being computed.

        The adjoint method gradient error is evaluated by comparing the
        gradient computed using the adjoint method to a gradient computed by
        direct finite differences.  In other words, the "correct" derivatives
        to which the adjoint method gradient is compared are given by

        .. math::
            \\frac{\partial F}{\partial p_i} \\approx \\frac{F(p_i + \Delta p) - F(p_i)}{\Delta p}

        Note that this method for calculating the gradient is not used in a
        practical setting because it requires performing N+1 simulations in
        order to compute the gradient with respect to N design variables
        (compared to only 2 simulations in the case of the adjoint method).

        Parameters
        ----------
        params : numpy.ndarray
            design parameters
        indices : list or numpy.ndarray
            list of gradient indices to check. An empty list indicates that the
            whole gradient should be verified. A subset of indices may be
            desirable for large problems.  (default = [])

        Returns
        -------
        float
            Relative error in gradient.
        """

        if (indices == []):
            indices = np.arange(0, len(params), 1)

        # make sure everything is up to date
        self.update_system(params)
        self.sim.update()

        grad_am = self.gradient(params)
        grad_fd = np.zeros(len(indices))

        fom0 = self.fom(params)

        # calculate the "true" derivatives using finite differences
        if (NOT_PARALLEL):
            info_message('Checking gradient...')

        for i in range(len(indices)):
            if (NOT_PARALLEL):
                print('\tDerivative %d of %d' % (i + 1, len(indices)))

            j = indices[i]
            p0 = params[j]
            params[j] += self._step
            fom1 = self.fom(params)
            if (NOT_PARALLEL):
                grad_fd[i] = (fom1 - fom0) / self._step
            params[j] = p0

        if (NOT_PARALLEL):
            errors = np.abs(grad_fd - grad_am[indices]) / np.abs(grad_fd)
            error_tot = np.linalg.norm(
                grad_fd - grad_am[indices]) / np.linalg.norm(grad_fd)

            if (error_tot < 0.01):
                info_message('The total error in the gradient is %0.4E' % \
                             (error_tot))
            else:
                warning_message('The total error in the gradient is %0.4E '
                                'which is over 1%%' % (error_tot), \
                                'emopt.adjoint_method')

            if (plot):
                import matplotlib.pyplot as plt
                f = plt.figure()
                ax1 = f.add_subplot(311)
                ax2 = f.add_subplot(312)
                ax3 = f.add_subplot(313)

                ax1.bar(indices, grad_fd)
                ax1.set_title('Finite Differences')
                ax2.bar(indices, grad_am[indices])
                ax2.set_title('Adjoint Method')
                ax3.bar(indices, errors)
                ax3.set_title('Error in Adjoint Method')

                ax3.set_yscale('log', nonposy='clip')

                plt.show()

            return error_tot
        else:
            return None
示例#8
0
 def step(self, val):
     if (np.abs(val) > self.sim.dx / 1e3):
         if (NOT_PARALLEL):
             warning_message('Step size used for adjoint method may be too '
                             'large.  Consider reducing it to ~1e-3*dx')
     self._step = val
示例#9
0
def plot_iteration(field,
                   structure,
                   W,
                   H,
                   foms,
                   fname='',
                   layout='auto',
                   show_now=False,
                   dark=True,
                   Nmats=2):
    """Plot the current iteration of an optimization.

    Plots the following:
        1) A 2D field
        2) A 2D representation of the geometry
        3) A line plot of the figure of merit history

    When plotting 3D structures, multiple 2D slices of the geometry can be
    passed in by passing a 3D array to structure. The different "pages" of this
    array will be flattened into a 2D representation of the sliced geometry.

    Furthermore, multiple figures of merit may be plotted. This is done by
    putting more than one key:value pair in the foms dictionary. The key names
    will be used as the legend label.

    Parameters
    ----------
    field : numpy.ndarray
        2D array containing current iteration's field slice
    structure : numpy.ndarray
        Either a 2D array containing a representation of the current structure
        or a 3D array containing a FEW 2D slices.
    W : float
        The width of the field/structure
    H : float
        The height of the field/structure
    foms : dict
        A dictionary containing the fom history. The key strings should be
        names which describe each supplied figure of merit
    fname : str
        Filename for saving
    layout : str
        Layout method. 'auto' = automatically choose layout based on aspect
        ratio. 'horizontal' = single row layour. 'vertical' = single column
        layout. 'balanced' = field+structure on left, foms on right.
    show_now : bool
        If True, show plot now (warning: this is a blocking operation)
    dark : bool
        If True, use a dark color scheme for plot. (default = True)

    Returns
    -------
    matplotlib.pyplot.figure
        The current matplotlib figure
    """
    import matplotlib.pyplot as plt
    import matplotlib.gridspec as gridspec
    from matplotlib.colors import LinearSegmentedColormap

    dpi = 300
    aspect = W / H

    # determine and setup the plot layout
    unknown_layout = layout not in [
        'auto', 'horizontal', 'vertical', 'balanced'
    ]
    if (unknown_layout):
        warning_message("Unknown layout '%s'. Using 'auto'" % (layout),
                        'emopt.io')

    if (layout == 'auto' or unknown_layout):
        if (aspect < 1.0):
            layout = 'horizontal'
        elif (aspect >= 1.0 and aspect <= 2.5):
            layout = 'balanced'
        else:
            layout = 'vertical'

    gs = None
    Wplot = 10.0
    if (layout == 'horizontal'):
        f = plt.figure(figsize=(Wplot * aspect * 3, Wplot))
        gs = gridspec.GridSpec(1, 3, height_ratios=[1])
        ax_field = f.add_subplot(gs[:, 0])
        ax_struct = f.add_subplot(gs[:, 1])
        ax_foms = f.add_subplot(gs[:, 2])
    elif (layout == 'vertical'):
        f = plt.figure(figsize=(Wplot, Wplot / aspect * 3))
        gs = gridspec.GridSpec(3, 1, height_ratios=[1, 1, 1])
        ax_field = f.add_subplot(gs[0, :])
        ax_struct = f.add_subplot(gs[1, :])
        ax_foms = f.add_subplot(gs[2, :])
    elif (layout == 'balanced'):
        f = plt.figure(figsize=(Wplot, Wplot / aspect * 2 / 1.5))
        gs = gridspec.GridSpec(2, 3, height_ratios=[1, 1])
        ax_field = f.add_subplot(gs[0, 0:2])
        ax_struct = f.add_subplot(gs[1, 0:2])
        ax_foms = f.add_subplot(gs[:, 2])

    # define dark colormaps
    if (dark):
        field_cols = ['#3d9aff', '#111111', '#ff3d63']
        field_cmap = LinearSegmentedColormap.from_list('field_cmap',
                                                       field_cols)

        struct_cols = ['#212730', '#bcccdb']
        struct_cmap = LinearSegmentedColormap.from_list(
            'struct_cmap', struct_cols)
    else:
        field_cmap = 'seismic'
        struct_cmap = 'Blues'

    extent = [0, W, 0, H]
    fmin = -1 * np.max(np.abs(field))
    fmax = -1 * fmin
    ax_field.imshow(field,
                    extent=extent,
                    vmin=fmin,
                    vmax=fmax,
                    cmap=field_cmap)

    # "flatten" multi-layer structure
    if (len(structure.shape) == 3):
        Nlevels = structure.shape[0] + 1
        structure = np.sum(structure, axis=0) / structure.shape[0]
    else:
        Nlevels = Nmats

    smin = np.min(structure)
    smax = np.max(structure)
    ax_struct.imshow(structure,
                     extent=extent,
                     vmin=smin,
                     vmax=smax,
                     cmap=struct_cmap)

    # outline structure in field plot
    ax_field.contour(np.flipud(structure),
                     extent=extent,
                     levels=Nlevels,
                     colors='#666666',
                     linewidths=0.1)

    # set dark colors
    # plot title with important iteration number, etc
    # sum along z-axis for structure

    # define fom plot colors
    Nplot = len(foms.keys())
    red = np.linspace(0.2, 1.0, Nplot)
    blue = np.linspace(1.0, 0.2, Nplot)
    green = np.zeros(Nplot)
    red_base = 0.0
    blue_base = 0.0
    green_base = 0.55

    i = 0
    Niter = 0
    current_foms = []
    for desc in foms.keys():
        fom = foms[desc]
        Niter = len(fom)
        iters = np.arange(Niter)
        current_foms.append(fom[-1])

        pcolor = (red_base + red[i], green_base + green[i],
                  blue_base + blue[i])
        i += 1
        pline = ax_foms.plot(iters, fom, '.-', color=pcolor, markersize=10)

    ax_foms.set_xlabel('Iteration', fontsize=12)
    ax_foms.set_ylabel('Figure of Merit', fontsize=12)
    ax_foms.legend(foms.keys(), loc=4)
    ax_foms.grid(True, linewidth=0.5)

    # general tick properties
    for ax in [ax_field, ax_struct, ax_foms]:
        ax.get_yaxis().set_tick_params(which='both',
                                       direction='in',
                                       top=True,
                                       right=True)
        ax.get_xaxis().set_tick_params(which='both',
                                       direction='in',
                                       top=True,
                                       right=True)

    # Dark theme easier on eyes
    if (dark):
        c_text_main = '#BBBBBB'
        c_bg_main = '#101010'
        c_plot_bg = '#353535'
        c_lines = '#666666'
        c_plot_tick = '#CCCCCC'
        c_plot_grid = '#555555'
        f.patch.set_facecolor(c_bg_main)
        for ax in [ax_field, ax_struct, ax_foms]:
            for tl in ax.get_xticklabels():
                tl.set_color(c_text_main)
            for tl in ax.get_yticklabels():
                tl.set_color(c_text_main)
            ax.xaxis.get_label().set_color(c_text_main)
            ax.yaxis.get_label().set_color(c_text_main)

            for spine in ax.spines:
                ax.spines[spine].set_color(c_lines)

            ax.get_yaxis().set_tick_params(color=c_plot_tick)
            ax.get_xaxis().set_tick_params(color=c_plot_tick)

        ax_foms.set_facecolor(c_plot_bg)
        ax_foms.grid(True, color=c_plot_grid, linewidth=0.5)
    else:
        c_text_main = '#000000'

    # title contains info of current iteration
    f.suptitle(''.join(['Iteration %d, ' % (Niter), 'FOMs = '] +
                       ['%0.4f  ' % (fom) for fom in current_foms]),
               fontsize=12,
               color=c_text_main)

    if (fname != ''):
        if (dark):
            plt.savefig(fname,
                        dpi=300,
                        facecolor=c_bg_main,
                        bbox_inches='tight')
        else:
            plt.savefig(fname, dpi=300, bbox_inches='tight')

    if (show_now):
        plt.tight_layout()
        plt.show()
示例#10
0
 def zmaxs(self):
     warning_message(
         'The list of maximum z coordinates cannot be changed in this way.',
         'emopt.grid')
示例#11
0
 def primitive(self):
     warning_message('The primitive list cannot be modified in this way.',
                     'emopt.grid')
示例#12
0
 def set_material(self, mat):
     warning_message('set_material(...) is deprecated. Use property ' \
                     'mypoly.material_value=... instead.', 'emopt.grid')
     libGrid.Polygon_set_material(self._object, mat.real, mat.imag)
     self._value = mat
示例#13
0
 def Np(self, N):
     warning_message('Polygon.Np cannot be modified in this way.', \
                     'emopt.grid.Polygon')
示例#14
0
 def ys(self, vals):
     warning_message('Polygon.ys cannot be set on its own. Use ' \
                     'set_points(x,y) instead', 'emopt.grid.Polygon')
示例#15
0
 def set_material(self, mat):
     """(Deprecated) Set the material value of the Rectangle's interior.
     """
     warning_message('set_mateiral(...) is deprecated. Use property ' \
                     'myrect.material_value=... instead.', 'emopt.grid')
     libGrid.Rectangle_set_material(self._object, mat.real, mat.imag)
示例#16
0
def fillet(x, y, R, make_round=None, points_per_90=10, equal_thresh=1e-8,
           ignore_roc_lim=False):
    """Round corners of a polygon.

    This function replaces sharp corners with circular arcs. The radius of
    these arcs will be equal to the specified radius as long as the line
    segments which make up the corner are sufficiently long. If they are too
    short, the arc will be made with a smaller radius.

    If a non-closed polygon is supplied, the end points will be ignored. A
    polygon is considered closed if the first and last point in the provided
    x,y coordinate lists are the same.

    Parameters
    ----------
    x : list
        The x coordinates of the chain of line segments to round.
    y : list
        The y coordinates of the chain of line segments to round.
    R : float
        The desired fillet radius
    make_round : list or None (optional)
        A list of boolean values which specifies which points should be
        rounded. If None, then all roundable points are rounded. If supplying a
        list, the list must have the same length as x and y. (default = None)
    points_per_90 : int (optional)
        The number of points to generate per 90 degrees of the arc. (default =
        10)
    equal_thresh : float
        The threshold used for comparing values. If the |difference| between
        two values is less than this value, they are considered equal.

    Returns
    -------
    list, list
        The x and y coordinates of the new set of lines segments or polygon.
    """
    xn = []
    yn = []
    i = 0
    N = len(x)
    N0 = N

    # we always ignore the last point
    N -= 1

    closed = True
    if(x[0] != x[-1] or y[0] != y[-1]):
        closed = False
        i += 1
        xn.append(x[0])
        yn.append(y[0])

    i = 0
    while(i < N):
        if(make_round is None or make_round[i]):
            # get current and adjacent points
            x1 = x[i]
            y1 = y[i]
            if(i == 0):
                x0 = x[-2]
                y0 = y[-2]
            else:
                x0 = x[i-1]
                y0 = y[i-1]
            if(i == N0-1):
                x2 = x[1]
                y2 = y[1]
            else:
                x2 = x[i+1]
                y2 = y[i+1]

            # calc angle
            dx10 = x0-x1
            dy10 = y0-y1
            dx12 = x2-x1
            dy12 = y2-y1
            d10 = np.sqrt(dx10**2 + dy10**2)
            d12 = np.sqrt(dx12**2 + dy12**2)

            theta = np.arccos((dx10*dx12 + dy10*dy12)/(d10*d12))

            if(theta != 0 and theta != pi):
                dxc = (dx10/d10 + dx12/d12)
                dyc = (dy10/d10 + dy12/d12)
                dc = np.sqrt(dxc**2 + dyc**2)
                nxc = dxc/dc
                nyc = dyc/dc

                nx10 = dx10/d10
                ny10 = dy10/d10

                nx12 = dx12/d12
                ny12 = dy12/d12

                # reduce fillet radius if necessary
                Ri = R
                iprev = i-1
                inext = i+1
                if(iprev < 0): iprev = N0-1
                if(inext > N0-1): inext = 0

                if( (d10 < 2*R or d12 < 2*R) and not ignore_roc_lim):
                    Ri = np.min([d12, d10])/2.0
                    if(NOT_PARALLEL):
                        warning_message('Warning: Desired radius of curvature too large at ' \
                                        'point %d. Reducing to maximum allowed.' % \
                                        (i), 'emopt.geometry')

                # figure out where the circle "fits" in the corner
                S10 = Ri / np.tan(theta/2.0)
                S12 = S10
                Sc = np.sqrt(S10**2 + Ri**2)

                # generate the fillet
                theta1 = np.arctan2((S10*ny10 - Sc*nyc), (S10*nx10 - Sc*nxc))
                theta2 = np.arctan2((S12*ny12 - Sc*nyc), (S12*nx12 - Sc*nxc))

                if(theta1 < 0): theta1 += 2*pi
                if(theta2 < 0): theta2 += 2*pi

                theta1 = np.mod(theta1, 2*pi)
                theta2 = np.mod(theta2, 2*pi)

                if(theta2 - theta1 > pi): theta2 -= 2*pi
                elif(theta1 - theta2 > pi): theta2 += 2*pi

                Np = int(np.abs(theta2-theta1) / (pi/2) * points_per_90)
                if(Np < 1):
                    Np = 1
                thetas = np.linspace(theta1, theta2, Np)
                for t in thetas:
                    xfil = x[i] + Sc*nxc + Ri*np.cos(t)
                    yfil = y[i] + Sc*nyc + Ri*np.sin(t)

                    # only add point if not duplicate (this can happen if
                    # the desired radis of curvature equals or exceeds the
                    # maximum allowed)
                    if(np.abs(xfil - xn[-1]) > equal_thresh or
                       np.abs(yfil - yn[-1]) > equal_thresh):
                        xn.append(xfil)
                        yn.append(yfil)

            else:
                xn.append(x[i])
                yn.append(y[i])
        else:
            xn.append(x[i])
            yn.append(y[i])
        i += 1

    if(not closed):
        xn.append(x[-1])
        yn.append(y[-1])
    else:
        xn.append(xn[0])
        yn.append(yn[0])

    return np.array(xn), np.array(yn)