示例#1
0
    def _rebuild(self):
        assert self.panel1.model == self.panel2.model
        assert self.panel1.r == self.panel2.r
        assert self.panel1.alphadeg == self.panel2.alphadeg
        a = None
        b = None
        if self.panel1 is not None:
            a = self.panel1.a
            b = self.panel1.b
        elif self.panel2 is not None:
            a = self.panel2.a
            b = self.panel2.b
        if a is not None and b is not None:
            if a / b > 10.:
                if self.base.m <= 15 and self.flange.m <= 15:
                    raise RuntimeError(
                        'For a/b > 10. use base.m and flange.m > 15')
                else:
                    warn(
                        'For a/b > 10. be sure to check convergence for base.m and flange.m'
                    )

        self.flange.lam = laminate.read_stack(
            self.flange.stack,
            plyts=self.flange.plyts,
            laminaprops=self.flange.laminaprops)
        #NOTE below offset is not needed since it is already considered in the
        #     connectivity matrices, using dpb
        h = 0.5 * sum(self.panel1.plyts) + 0.5 * sum(self.panel2.plyts)
        hb = sum(self.base.plyts)
        self.dpb = h / 2. + hb / 2.
        self.base.lam = laminate.read_stack(self.base.stack,
                                            plyts=self.base.plyts,
                                            laminaprops=self.base.laminaprops,
                                            offset=0.)
示例#2
0
    def _rebuild(self):
        if not self.name:
            try:
                self.name = os.path.basename(__main__.__file__).split('.py')[0]
            except AttributeError:
                warn('StiffPanelBay name unchanged')

        if self.a is None:
            raise ValueError('The length a must be specified')

        if self.b is None:
            raise ValueError('The width b must be specified')

        for p in self.panels:
            p._rebuild()
            if self.model is not None:
                assert self.model == p.model
            else:
                self.model = p.model

        for s in self.bladestiff1ds:
            s._rebuild()

        for s in self.bladestiff2ds:
            s._rebuild()
示例#3
0
    def _rebuild(self):
        assert self.panel1.model == self.panel2.model
        assert self.panel1.r == self.panel2.r
        assert self.panel1.alphadeg == self.panel2.alphadeg
        a = None
        b = None
        if self.panel1 is not None:
            a = self.panel1.a
            b = self.panel1.b
        elif self.panel2 is not None:
            a = self.panel2.a
            b = self.panel2.b
        if a is not None and b is not None:
            if a / b > 10.:
                if self.base.m <= 15 and self.flange.m <= 15:
                    raise RuntimeError('For a/b > 10. use base.m and flange.m > 15')
                else:
                    warn('For a/b > 10. be sure to check convergence for base.m and flange.m')

        self.flange.lam = laminate.read_stack(self.flange.stack,
                plyts=self.flange.plyts, laminaprops=self.flange.laminaprops)
        #NOTE below offset is not needed since it is already considered in the
        #     connectivity matrices, using dpb
        h = 0.5*sum(self.panel1.plyts) + 0.5*sum(self.panel2.plyts)
        hb = sum(self.base.plyts)
        self.dpb = h/2. + hb/2.
        self.base.lam = laminate.read_stack(self.base.stack,
                plyts=self.base.plyts, laminaprops=self.base.laminaprops,
                offset=0.)
示例#4
0
    def static(self, NLgeom=False, silent=False):
        """Static analysis for cones and cylinders

        The analysis can be linear or geometrically non-linear. See
        :class:`.Analysis` for further details about the parameters
        controlling the non-linear analysis.

        Parameters
        ----------
        NLgeom : bool
            Flag to indicate whether a linear or a non-linear analysis is to
            be performed.

        silent : bool, optional
            A boolean to tell whether the log messages should be printed.

        Returns
        -------
        cs : list
            A list containing the Ritz constants for each load increment of
            the static analysis. The list will have only one entry in case
            of a linear analysis.

        Notes
        -----
        The returned ``cs`` is stored in ``self.analysis.cs``. The actual
        increments used in the non-linear analysis are stored in the
        ``self.analysis.increments`` parameter.

        """
        if self.c0 is not None:
            self.analysis.kT_initial_state = True
        else:
            self.analysis.kT_initial_state = False

        if NLgeom and not modelDB.db[self.model]['non-linear static']:
            msg('________________________________________________',
                silent=silent)
            msg('', silent=silent)
            warn('Model {} cannot be used in non-linear static analysis!'.
                 format(self.model), silent=silent)
            msg('________________________________________________',
                silent=silent)
            raise
        elif not NLgeom and not modelDB.db[self.model]['linear static']:
            msg('________________________________________________',
                level=1, silent=silent)
            msg('', level=1, silent=silent)
            warn('Model {} cannot be used in linear static analysis!'.
                 format(self.model), level=1, silent=silent)
            msg('________________________________________________',
                level=1, silent=silent)
            raise
        self.analysis.static(NLgeom=NLgeom, silent=silent)
        self.increments = self.analysis.increments

        return self.analysis.cs
示例#5
0
    def plot(self, c, group, invert_y=False, vec='w', filename='', ax=None,
            figsize=(3.5, 2.), save=True, title='', identify=False,
            show_boundaries=False, boundary_line='--k', boundary_linewidth=1.,
            colorbar=False, cbar_nticks=2, cbar_format=None, cbar_title='',
            cbar_fontsize=10, colormap='jet', aspect='equal', clean=True,
            dpi=400, texts=[], xs=None, ys=None, gridx=50, gridy=50,
            num_levels=400, vecmin=None, vecmax=None, calc_data_only=False):
        r"""Contour plot for a Ritz constants vector.

        Parameters
        ----------
        c : np.ndarray
            The Ritz constants that will be used to compute the field contour.
        group : str
            A group to plot. Each panel in ``panels`` should contain an
            attribute ``group``, which is used to identify which entities
            should be plotted together.
        vec : str, optional
            Can be one of the components:

            - Displacement: ``'u'``, ``'v'``, ``'w'``, ``'phix'``, ``'phiy'``
            - Strain: ``'exx'``, ``'eyy'``, ``'gxy'``, ``'kxx'``, ``'kyy'``,
              ``'kxy'``, ``'gyz'``, ``'gxz'``
            - Stress: ``'Nxx'``, ``'Nyy'``, ``'Nxy'``, ``'Mxx'``, ``'Myy'``,
              ``'Mxy'``, ``'Qy'``, ``'Qx'``
        invert_y : bool, optional
            Inverts the `y` axis of the plot.
        save : bool, optional
            Flag telling whether the contour should be saved to an image file.
        dpi : int, optional
            Resolution of the saved file in dots per inch.
        filename : str, optional
            The file name for the generated image file. If no value is given,
            the `name` parameter of the ``Panel`` object will be used.
        ax : AxesSubplot, optional
            When ``ax`` is given, the contour plot will be created inside it.
        figsize : tuple, optional
            The figure size given by ``(width, height)``.
        title : str, optional
            If any string is given a title is added to the contour plot.
        indentify : bool, optional
            If domains should be identified. If yes, the name of each panel is
            used.
        show_boundaries : bool, optional
            If boundaries between domains should be drawn.
        boundary_line : str, optional
            Matplotlib string to define line type and color.
        boundary_linewidth : float, optional
            Matplotlib float to define line width.
        colorbar : bool, optional
            If a colorbar should be added to the contour plot.
        cbar_nticks : int, optional
            Number of ticks added to the colorbar.
        cbar_format : [ None | format string | Formatter object ], optional
            See the ``matplotlib.pyplot.colorbar`` documentation.
        cbar_title : str, optional
            Colorbar title. If ``cbar_title == ''`` no title is added.
        cbar_fontsize : int, optional
            Fontsize of the colorbar labels.
        colormap : string, optional
            Name of a matplotlib available colormap.
        aspect : str, optional
            String that will be passed to the ``AxesSubplot.set_aspect()``
            method.
        clean : bool, optional
            Clean axes ticks, grids, spines etc.
        xs : np.ndarray, optional
            The `x` positions where to calculate the displacement field.
            Default is ``None`` and the method ``_default_field`` is used.
        ys : np.ndarray, optional
            The ``y`` positions where to calculate the displacement field.
            Default is ``None`` and the method ``_default_field`` is used.
        gridx : int, optional
            Number of points along the `x` axis where to calculate the
            displacement field.
        gridy : int, optional
            Number of points along the `y` where to calculate the
            displacement field.
        num_levels : int, optional
            Number of contour levels (higher values make the contour smoother).
        vecmin : float, optional
            Minimum value for the contour scale (useful to compare with other
            results). If not specified it will be taken from the calculated
            field.
        vecmax : float, optional
            Maximum value for the contour scale.
        calc_data_only : bool, optional
            If only calculated data should be returned.

        Returns
        -------
        ax : matplotlib.axes.Axes
            The Matplotlib object that can be used to modify the current plot
            if needed.
        data : dict
            Data calculated during the plotting procedure.

        """
        msg('Plotting contour...')

        import matplotlib
        if platform.system().lower() == 'linux':
            matplotlib.use('Agg')
        import matplotlib.pyplot as plt

        msg('Computing field variables...', level=1)
        displs = ['u', 'v', 'w', 'phix', 'phiy']
        strains = ['exx', 'eyy', 'gxy', 'kxx', 'kyy', 'kxy', 'gyz', 'gxz']
        stresses = ['Nxx', 'Nyy', 'Nxy', 'Mxx', 'Myy', 'Mxy', 'Qy', 'Qx']
        if vec in displs:
            res = self.uvw(c, group, gridx=gridx, gridy=gridy)
        elif vec in strains:
            res = self.strain(c, group, gridx=gridx, gridy=gridy)
        elif vec in stresses:
            res = self.stress(c, group, gridx=gridx, gridy=gridy)
        else:
            raise ValueError(
                    '{0} is not a valid vec parameter value!'.format(vec))
        field = np.array(res[vec])
        msg('Finished!', level=1)

        if vecmin is None:
            vecmin = field.min()
        if vecmax is None:
            vecmax = field.max()

        data = dict(vecmin=vecmin, vecmax=vecmax)

        if calc_data_only:
            return None, data

        levels = linspace(vecmin, vecmax, num_levels)

        if ax is None:
            fig = plt.figure(figsize=figsize)
            ax = fig.add_subplot(111)
        else:
            if isinstance(ax, matplotlib.axes.Axes):
                ax = ax
                fig = ax.figure
                save = False
            else:
                raise ValueError('ax must be an Axes object')

        if invert_y == True:
            ax.invert_yaxis()
        ax.invert_xaxis()

        colormap_obj = getattr(cm, colormap, None)
        if colormap_obj is None:
            warn('Invalid colormap, using "jet"', level=1)
            colormap_obj = cm.jet

        count = -1
        for i, panel in enumerate(self.panels):
            if panel.group != group:
                continue
            count += 1
            xplot = res['y'][count] + panel.y0
            yplot = res['x'][count] + panel.x0
            field = res[vec][count]
            contour = ax.contourf(xplot, yplot, field, levels=levels,
                    cmap=colormap_obj)
            if identify:
                ax.text(xplot.mean(), yplot.mean(), 'P {0:02d}'.format(i+1),
                        transform=ax.transData, ha='center')
            if show_boundaries:
                x1, x2 = xplot.min(), xplot.max()
                y1, y2 = yplot.min(), yplot.max()
                ax.plot((x1, x2), (y1, y1), boundary_line, lw=boundary_linewidth)
                ax.plot((x1, x2), (y2, y2), boundary_line, lw=boundary_linewidth)
                ax.plot((x1, x1), (y1, y2), boundary_line, lw=boundary_linewidth)
                ax.plot((x2, x2), (y1, y2), boundary_line, lw=boundary_linewidth)

        if colorbar:
            from mpl_toolkits.axes_grid1 import make_axes_locatable

            fsize = cbar_fontsize
            divider = make_axes_locatable(ax)
            cax = divider.append_axes('right', size='5%', pad=0.05)
            cbarticks = linspace(vecmin, vecmax, cbar_nticks)
            cbar = plt.colorbar(contour, ticks=cbarticks, format=cbar_format,
                                cax=cax)
            if cbar_title:
                cax.text(0.5, 1.05, cbar_title, horizontalalignment='center',
                         verticalalignment='bottom', fontsize=fsize)
            cbar.outline.remove()
            cbar.ax.tick_params(labelsize=fsize, pad=0., tick2On=False)

        if title != '':
            ax.set_title(str(title))

        fig.tight_layout()
        ax.set_aspect(aspect)

        ax.grid(False)
        ax.set_frame_on(False)
        if clean:
            ax.xaxis.set_ticks_position('none')
            ax.yaxis.set_ticks_position('none')
            ax.xaxis.set_ticklabels([])
            ax.yaxis.set_ticklabels([])
        else:
            ax.xaxis.set_ticks_position('bottom')
            ax.yaxis.set_ticks_position('left')

        for kwargs in texts:
            ax.text(transform=ax.transAxes, **kwargs)

        if save:
            if not filename:
                filename = group + '.png'
            fig.savefig(filename, transparent=True,
                        bbox_inches='tight', pad_inches=0.05, dpi=dpi)
            plt.close()

        msg('finished!')

        return ax, data
示例#6
0
def _solver_NR(run, silent=False):
    """Newton-Raphson solver

    """
    msg('Initialization...', level=1, silent=silent)

    modified_NR = run.modified_NR
    inc = run.initialInc
    total = inc
    once_at_total = False
    max_total = 0.

    fext = run.calc_fext(inc=inc, silent=silent)
    k0 = run.calc_k0(silent=silent)
    c = solve(k0, fext, silent=silent)
    kT_last = k0

    if modified_NR:
        compute_kT = False
    else:
        compute_kT = True

    step_num = 1
    while True:
        msg('Started Load Step {} - '.format(step_num) +
            'Attempting time = {0}'.format(total),
            level=1,
            silent=silent)

        # TODO maybe for pdC=True, pdT the fext must be calculated with
        # the last kT available...

        absERR = 1.e6
        relERR = 1.e6
        min_Rmax = 1.e6
        prev_Rmax = 1.e6
        last_min_Rmax = 1.e6
        iteration = 0
        converged = False

        kT = kT_last

        fext = run.calc_fext(inc=total, silent=silent)

        iter_NR = 0
        while True:
            iteration += 1
            msg('Iteration: {}'.format(iteration), level=2, silent=silent)
            if iteration > run.maxNumIter:
                warn('Maximum number of iterations achieved!',
                     level=2,
                     silent=silent)
                break

            if compute_kT or (run.kT_initial_state and step_num == 1
                              and iteration
                              == 1) or iter_NR == (run.compute_every_n - 1):
                iter_NR = 0
                kT = run.calc_kT(c=c, inc=total, silent=silent)
            else:
                iter_NR += 1
                if not modified_NR:
                    compute_kT = True

            fint = run.calc_fint(c=c, inc=total, silent=silent)

            R = fext - fint

            # convergence criteria:
            # - maximum residual force Rmax
            Rmax = np.abs(R).max()
            msg('Rmax = {0}'.format(Rmax), level=3, silent=silent)

            if iteration >= 2 and Rmax < run.absTOL:
                converged = True
                break
            if (Rmax > prev_Rmax and Rmax > min_Rmax and iteration > 2):
                warn('Diverged!', level=2, silent=silent)
                break
            else:
                min_Rmax = min(min_Rmax, Rmax)
            change_rate_Rmax = abs(prev_Rmax - Rmax) / abs(prev_Rmax)
            if (iteration > 2 and change_rate_Rmax < run.too_slow_TOL):
                warn('Diverged! (convergence too slow)',
                     level=2,
                     silent=silent)
                break
            prev_Rmax = Rmax

            msg('Solving... ', level=2, silent=silent)
            delta_c = solve(kT, R, silent=silent)
            msg('finished!', level=2, silent=silent)

            eta1 = 0.
            eta2 = 1.
            if run.line_search:
                msg('Performing line-search... ', level=2, silent=silent)
                iter_line_search = 0
                while True:
                    c1 = c + eta1 * delta_c
                    c2 = c + eta2 * delta_c
                    fint1 = run.calc_fint(c=c1, inc=total, silent=silent)
                    fint2 = run.calc_fint(c=c2, inc=total, silent=silent)
                    R1 = fext - fint1
                    R2 = fext - fint2
                    s1 = delta_c.dot(R1)
                    s2 = delta_c.dot(R2)
                    eta_new = (eta2 - eta1) * (-s1 / (s2 - s1)) + eta1
                    eta1 = eta2
                    eta2 = eta_new
                    eta2 = min(max(eta2, 0.2), 10.)
                    if abs(eta2 - eta1) < 0.01:
                        break
                    iter_line_search += 1
                    if iter_line_search == run.max_iter_line_search:
                        eta2 = 1.
                        warn('maxinum number of iterations',
                             level=3,
                             silent=silent)
                        break
                msg('finished!', level=2, silent=silent)
            c = c + eta2 * delta_c

        if converged:
            msg('Finished Load Step {} at'.format(step_num) +
                ' time = {0}'.format(total),
                level=1,
                silent=silent)
            run.increments.append(total)
            run.cs.append(c.copy())  #NOTE copy required
            finished = False
            if abs(total - 1) < 1e-3:
                finished = True
            else:
                factor = 1.1
                if once_at_total:
                    inc_new = min(factor * inc, run.maxInc, (1. - total) / 2)
                else:
                    inc_new = min(factor * inc, run.maxInc, 1. - total)
                msg('Changing time increment from {0:1.9f} to {1:1.9f}'.format(
                    inc, inc_new),
                    level=1,
                    silent=silent)
                inc = inc_new
                total += inc
                total = min(1, total)
                step_num += 1
            if finished:
                break
            if modified_NR:
                msg('Updating kT...', level=1, silent=silent)
                kT = run.calc_kT(c=c, inc=total, silent=silent)
                msg('kT updated!', level=1, silent=silent)
            compute_kT = False
            kT_last = kT
        else:
            max_total = max(max_total, total)
            while True:
                factor = 0.3
                msg('Bisecting time increment from {0} to {1}'.format(
                    inc, inc * factor),
                    level=1,
                    silent=silent)
                if abs(total - 1) < 1e-3:
                    once_at_total = True
                total -= inc
                inc *= factor
                if inc < run.minInc:
                    msg('Minimum step size achieved!', level=1, silent=silent)
                    break
                total += inc
                if total >= max_total:
                    continue
                else:
                    break
            if inc < run.minInc:
                msg('Stopping solver: minimum step size achieved!',
                    level=1,
                    silent=silent)
                break

        if len(run.cs) > 0:
            c = run.cs[-1].copy()  #NOTE copy required
        else:
            # means that run bisection must be done in initialInc
            fext = run.calc_fext(inc=inc, silent=silent)
            c = solve(k0, fext, silent=silent)

    msg('Finished Non-Linear Static Analysis', silent=silent)
    msg('at time {0}'.format(total), level=1, silent=silent)
示例#7
0
    def freq(self, atype=4, tol=0, sparse_solver=False, silent=False,
            sort=True, reduced_dof=False):
        """Performs a frequency analysis

        The following parameters of the ``AeroPistonPlate`` object will affect
        the linear buckling analysis:

        =======================    =====================================
        parameter                  description
        =======================    =====================================
        ``num_eigenvalues``        Number of eigenvalues to be extracted
        ``num_eigvalues_print``    Number of eigenvalues to print after
                                   the analysis is completed
        =======================    =====================================

        Parameters
        ----------
        atype : int, optional
            Tells which analysis type should be performed:
            - ``1`` : considers k0, kA and kG0
            - ``2`` : considers k0 and kA
            - ``3`` : considers k0 and kG0
            - ``4`` : considers k0 only
        tol : float, optional
            A tolerance value passed to ``scipy.sparse.linalg.eigs``.
        sparse_solver : bool, optional
            Tells if solver :func:`scipy.linalg.eig` or
            :func:`scipy.sparse.linalg.eigs` should be used.

            .. note:: It is recommended ``sparse_solver=False``, because it
                      was verified that the sparse solver becomes unstable
                      for some cases, though the sparse solver is faster.
        silent : bool, optional
            A boolean to tell whether the log messages should be printed.
        sort : bool, optional
            Sort the output eigenvalues and eigenmodes.
        reduced_dof : bool, optional
            Considers only the contributions of `w` to the stiffness matrix
            and considerably accelerates the run. Only effective when
            ``sparse_solver=False``.

        Notes
        -----
        The extracted eigenvalues are stored in the ``eigvals`` parameter
        of the ``AeroPistonPlate`` object and the `i^{th}` eigenvector in the
        ``eigvecs[:, i-1]`` parameter.

        """
        if not modelDB.db[self.model]['linear buckling']:
            msg('________________________________________________')
            msg('')
            warn('Model {} cannot be used in linear buckling analysis!'.
                 format(self.model))
            msg('________________________________________________')

        msg('Running frequency analysis...', silent=silent)

        if atype == 1:
            self.calc_linear_matrices(silent=silent)
        elif atype == 2:
            self.calc_linear_matrices(silent=silent, calc_kG0=False)
        elif atype == 3:
            self.calc_linear_matrices(silent=silent, calc_kA=False)
        elif atype == 4:
            self.calc_linear_matrices(silent=silent, calc_kA=False,
                    calc_kG0=False)

        msg('Eigenvalue solver... ', level=2, silent=silent)

        if atype == 1:
            K = self.k0 - self.kA + self.kG0
        elif atype == 2:
            K = self.k0 - self.kA
        elif atype == 3:
            K = self.k0 + self.kG0
        elif atype == 4:
            K = self.k0
        M = self.kM

        msg('eigs() solver...', level=3, silent=silent)
        k = min(self.num_eigvalues, M.shape[0]-2)
        if sparse_solver:
            eigvals, eigvecs = eigs(A=M, M=K, k=k, tol=tol, which='SM', sigma=-1.)
        else:
            M = M.toarray()
            K = K.toarray()
            if reduced_dof:
                i = np.arange(M.shape[0])
                take = i[2::3]
                M = M[:, take][take, :]
                K = K[:, take][take, :]
            eigvals, eigvecs = eig(a=M, b=K)

        msg('finished!', level=3, silent=silent)

        eigvals = np.sqrt(1./eigvals) # omega^2 to omega, in rad/s

        if sort:
            sort_ind = np.lexsort((np.round(eigvals.imag, 1),
                                   np.round(eigvals.real, 1)))
            eigvals = eigvals[sort_ind]
            eigvecs = eigvecs[:, sort_ind]

        if not sparse_solver and reduced_dof:
            new_eigvecs = np.zeros((3*eigvecs.shape[0], eigvecs.shape[1]))
            new_eigvecs[2::3, :] = eigvecs
            eigvecs = new_eigvecs

        self.eigvals = eigvals
        self.eigvecs = eigvecs

        msg('finished!', level=2, silent=silent)

        msg('first {} eigenvalues:'.format(self.num_eigvalues_print), level=1,
                silent=silent)
        for eigval in eigvals[:self.num_eigvalues_print]:
            msg('{0} rad/s'.format(eigval), level=2, silent=silent)
        self.analysis.last_analysis = 'freq'
示例#8
0
    def lb(self, tol=0, combined_load_case=None, sparse_solver=True,
            calc_kA=False):
        """Performs a linear buckling analysis

        The following parameters of the ``AeroPistonPlate`` object will affect
        the linear buckling analysis:

        =======================    =====================================
        parameter                  description
        =======================    =====================================
        ``num_eigenvalues``        Number of eigenvalues to be extracted
        ``num_eigvalues_print``    Number of eigenvalues to print after
                                   the analysis is completed
        =======================    =====================================

        Parameters
        ----------
        combined_load_case : int, optional
            It tells whether the linear buckling analysis must be computed
            considering combined load cases, each value will tell
            the algorithm to rearrange the linear matrices in a different
            way. The valid values are ``1``, or ``2``, where:

            - ``1`` : find the critical Fx for a fixed Fxy
            - ``2`` : find the critical Fx for a fixed Fy
            - ``3`` : find the critical Fy for a fixed Fyx
            - ``4`` : find the critical Fy for a fixed Fx
        sparse_solver : bool, optional
            Tells if solver :func:`scipy.linalg.eigh` or
            :func:`scipy.sparse.linalg.eigs` should be used.

        Notes
        -----
        The extracted eigenvalues are stored in the ``eigvals`` parameter
        of the ``AeroPistonPlate`` object and the `i^{th}` eigenvector in the
        ``eigvecs[:, i-1]`` parameter.

        """
        if not modelDB.db[self.model]['linear buckling']:
            msg('________________________________________________')
            msg('')
            warn('Model {} cannot be used in linear buckling analysis!'.
                 format(self.model))
            msg('________________________________________________')

        msg('Running linear buckling analysis...')

        self.calc_linear_matrices(combined_load_case=combined_load_case,
                calc_kM=False, calc_kA=calc_kA)

        msg('Eigenvalue solver... ', level=2)

        if calc_kA:
            kA = self.kA
        else:
            kA = self.k0*0

        if combined_load_case is None:
            M = self.k0 + kA
            A = self.kG0
        elif combined_load_case == 1:
            M = self.k0 - kA + self.kG0_Fxy
            A = self.kG0_Fx
        elif combined_load_case == 2:
            M = self.k0 - kA + self.kG0_Fy
            A = self.kG0_Fx
        elif combined_load_case == 3:
            M = self.k0 - kA + self.kG0_Fyx
            A = self.kG0_Fy
        elif combined_load_case == 4:
            M = self.k0 - kA + self.kG0_Fx
            A = self.kG0_Fy

        Amin = abs(A.min())
        # normalizing A to improve numerical stability
        A /= Amin

        if sparse_solver:
            try:
                msg('eigs() solver...', level=3)
                eigvals, eigvecs = eigs(A=A, k=self.num_eigvalues, which='SM',
                                        M=M, tol=tol, sigma=1.)
                msg('finished!', level=3)
            except Exception, e:
                warn(str(e), level=4)
                msg('aborted!', level=3)
                sizebkp = A.shape[0]
                M, A, used_cols = remove_null_cols(M, A)
                msg('eigs() solver...', level=3)
                eigvals, peigvecs = eigs(A=A, k=self.num_eigvalues,
                        which='SM', M=M, tol=tol, sigma=1.)
                msg('finished!', level=3)
                eigvecs = np.zeros((sizebkp, self.num_eigvalues),
                                   dtype=DOUBLE)
                eigvecs[used_cols, :] = peigvecs

            # Un-normalizing eigvals
            eigvals *= Amin
示例#9
0
    def _rebuild(self):
        if not self.name:
            try:
                self.name = os.path.basename(__main__.__file__).split('.py')[0]
            except AttributeError:
                warn('AeroPistonPlate name unchanged')

        self.model = self.model.lower()

        valid_models = sorted(modelDB.db.keys())

        if not self.model in valid_models:
            raise ValueError('ERROR - valid models are:\n    ' +
                     '\n    '.join(valid_models))

        # boundary conditions
        inf = self.inf
        zero = self.zero

        if inf > self.maxinf:
            warn('inf reduced to {0:1.1e4} due to the verified'.format(
                 self.maxinf) +
                 ' numerical instability for higher values', level=2)
            inf = self.maxinf

        if self.bc is not None:
            bc = self.bc.lower()

            if '_' in bc:
                # different bc for Bot, Top, Left and Right
                bc_Bot, bc_Top, bc_Left, bc_Right = self.bc.split('_')
            elif '-' in bc:
                # different bc for Bot, Top, Left and Right
                bc_Bot, bc_Top, bc_Left, bc_Right = self.bc.split('-')
            else:
                bc_Bot = bc_Top = bc_Left = bc_Right = bc

            bcs = dict(bc_Bot=bc_Bot, bc_Top=bc_Top,
                       bc_Left=bc_Left, bc_Right=bc_Right)
            for k in bcs.keys():
                sufix = k.split('_')[1] # Bot or Top
                if bcs[k] == 'ss1':
                    setattr(self, 'ku' + sufix, inf)
                    setattr(self, 'kv' + sufix, inf)
                    setattr(self, 'kw' + sufix, inf)
                    setattr(self, 'kphix' + sufix, zero)
                    setattr(self, 'kphiy' + sufix, zero)
                elif bcs[k] == 'ss2':
                    setattr(self, 'ku' + sufix, zero)
                    setattr(self, 'kv' + sufix, inf)
                    setattr(self, 'kw' + sufix, inf)
                    setattr(self, 'kphix' + sufix, zero)
                    setattr(self, 'kphiy' + sufix, zero)
                elif bcs[k] == 'ss3':
                    setattr(self, 'ku' + sufix, inf)
                    setattr(self, 'kv' + sufix, zero)
                    setattr(self, 'kw' + sufix, inf)
                    setattr(self, 'kphix' + sufix, zero)
                    setattr(self, 'kphiy' + sufix, zero)
                elif bcs[k] == 'ss4':
                    setattr(self, 'ku' + sufix, zero)
                    setattr(self, 'kv' + sufix, zero)
                    setattr(self, 'kw' + sufix, inf)
                    setattr(self, 'kphix' + sufix, zero)
                    setattr(self, 'kphiy' + sufix, zero)

                elif bcs[k] == 'cc1':
                    setattr(self, 'ku' + sufix, inf)
                    setattr(self, 'kv' + sufix, inf)
                    setattr(self, 'kw' + sufix, inf)
                    setattr(self, 'kphix' + sufix, inf)
                    setattr(self, 'kphiy' + sufix, inf)
                elif bcs[k] == 'cc2':
                    setattr(self, 'ku' + sufix, zero)
                    setattr(self, 'kv' + sufix, inf)
                    setattr(self, 'kw' + sufix, inf)
                    setattr(self, 'kphix' + sufix, inf)
                    setattr(self, 'kphiy' + sufix, inf)
                elif bcs[k] == 'cc3':
                    setattr(self, 'ku' + sufix, inf)
                    setattr(self, 'kv' + sufix, zero)
                    setattr(self, 'kw' + sufix, inf)
                    setattr(self, 'kphix' + sufix, inf)
                    setattr(self, 'kphiy' + sufix, inf)
                elif bcs[k] == 'cc4':
                    setattr(self, 'ku' + sufix, zero)
                    setattr(self, 'kv' + sufix, zero)
                    setattr(self, 'kw' + sufix, inf)
                    setattr(self, 'kphix' + sufix, inf)
                    setattr(self, 'kphiy' + sufix, inf)

                elif bcs[k] == 'free':
                    setattr(self, 'ku' + sufix, zero)
                    setattr(self, 'kv' + sufix, zero)
                    setattr(self, 'kw' + sufix, zero)
                    setattr(self, 'kphix' + sufix, zero)
                    setattr(self, 'kphiy' + sufix, zero)

                else:
                    txt = '"{}" is not a valid boundary condition!'.format(bc)
                    raise ValueError(txt)

        if self.a is None:
            raise ValueError('The length a must be specified')

        if self.b is None:
            raise ValueError('The width b must be specified')

        if not self.laminaprops:
            self.laminaprops = [self.laminaprop for i in self.stack]
        if not self.plyts:
            self.plyts = [self.plyt for i in self.stack]

        # defining load components from force vectors
        if self.laminaprop is None:
            raise ValueError('laminaprop must be defined')
示例#10
0
def inv_weighted(data, mesh, num_sub, col, ncp=5, power_parameter=2):
    r"""Interpolates the values taken at one group of points into
    another using an inverse-weighted algorithm

    In the inverse-weighted algorithm a number of `n_{CP}` measured points
    of the input parameter ``data`` that are closest to a given node in
    the input parameter ``mesh`` are found and the imperfection value of
    this node (represented by the normal displacement `{w_0}_{node}`) is
    calculated as follows:

    .. math::
        {w_0}_{node} = \frac{\sum_{i}^{n_{CP}}{{w_0}_i\frac{1}{w_i}}}
                            {\sum_{i}^{n_{CP}}{\frac{1}{w_i}}}

    where `w_i` is the imperfection at each measured point, calculated as:

    .. math::
        w_i = \left[(x_{node}-x_i)^2+(y_{node}-y_i)^2+(z_{node}-y_i)^2
              \right]^p

    with `p` being a power parameter that when increased will increase the
    relative influence of a closest point.

    Parameters
    ----------
    data : numpy.ndarray, shape (N, ndim+1)
        The data or an array containing the imperfection file. The values
        to be interpolated must be in the last column.
    mesh : numpy.ndarray, shape (M, ndim)
        The new coordinates where the values will be interpolated to.
    num_sub : int
        The number of sub-sets used during the interpolation. The points
        are divided in sub-sets to increase the algorithm's efficiency.
    col : int
        The index of the column to be used in order to divide the data
        in sub-sets. Note that the first column index is ``0``.
    ncp : int, optional
        Number of closest points used in the inverse-weighted interpolation.
    power_parameter : float, optional
        Power of inverse weighted interpolation function.

    Returns
    -------
    ans : numpy.ndarray
        A 1-D array with the interpolated values. The size of this array
        is ``mesh.shape[0]``.

    """
    if mesh.shape[1] != data.shape[1]-1:
        raise ValueError('Invalid input: mesh.shape[1] != data.shape[1]')

    msg('Interpolating... ')
    num_sub = int(num_sub)
    mesh_size = mesh.shape[0]

    # memory control
    mem_limit = 1024*1024*1024*8*2    # 2 GB
    mem_entries = int(mem_limit / 64) # if float64 is used
    sec_size = int(mesh_size/num_sub)
    while sec_size**2*10 > mem_entries:
        num_sub +=1
        sec_size = int(mesh_size/num_sub)
        if sec_size**2*10 <= mem_entries:
            warn('New num_sub: {0}'.format(int(mesh_size/float(sec_size))))
            break

    mesh_seq = np.arange(mesh.shape[0])

    mesh_argsort = np.argsort(mesh[:, col])
    mesh_seq = mesh_seq[mesh_argsort]
    back_argsort = np.argsort(mesh_seq)

    mesh = np.asarray(mesh[mesh_argsort], order='F')

    length = mesh[:, col].max() - mesh[:, col].min()

    data = np.asarray(data[np.argsort(data[:, col])], order='F')

    ans = np.zeros(mesh.shape[0], dtype=mesh.dtype)

    # max_num_limits defines how many times the log will print
    # "processed ... out of ... entries"
    max_num_limits = 10
    for den in range(max_num_limits, 0, -1):
        if num_sub % den == 0:
            limit = int(num_sub/den)
            break

    for i in range(num_sub+1):
        i_inf = sec_size*i
        i_sup = sec_size*(i+1)

        if i % limit == 0:
            msg('\t processed {0:7d} out of {1:7d} entries'.format(
                  min(i_sup, mesh_size), mesh_size))
        sub_mesh = mesh[i_inf : i_sup]
        if not np.any(sub_mesh):
            continue
        inf = sub_mesh[:, col].min()
        sup = sub_mesh[:, col].max()

        tol = 0.03
        if i == 0 or i == num_sub:
            tol = 0.06

        while True:
            cond1 = data[:, col] >= inf - tol*length
            cond2 = data[:, col] <= sup + tol*length
            cond = np.all(np.array((cond1, cond2)), axis=0)
            sub_data = data[cond]
            if not np.any(sub_data):
                tol += 0.01
            else:
                break

        dist = np.subtract.outer(sub_mesh[:, 0], sub_data[:, 0])**2
        for j in range(1, sub_mesh.shape[1]):
            dist += np.subtract.outer(sub_mesh[:, j], sub_data[:, j])**2
        asort = np.argsort(dist, axis=1)
        lenn = sub_mesh.shape[0]
        lenp = sub_data.shape[0]
        asort_mesh = asort + np.meshgrid(np.arange(lenn)*lenp,
                                         np.arange(lenp))[0].transpose()
        # getting the distance of the closest points
        dist_cp = np.take(dist, asort_mesh[:, :ncp])
        # avoiding division by zero
        dist_cp[(dist_cp==0)] == 1.e-12
        # fetching the imperfection of the sub-data
        imp = sub_data[:, -1]
        # taking only the imperfection of the closest points
        imp_cp = np.take(imp, asort[:, :ncp])
        # weight calculation
        total_weight = np.sum(1./(dist_cp**power_parameter), axis=1)
        weight = 1./(dist_cp**power_parameter)
        # computing the new imp
        imp_new = np.sum(imp_cp*weight, axis=1)/total_weight
        # updating the answer array
        ans[i_inf : i_sup] = imp_new

    ans = ans[back_argsort]

    msg('Interpolation completed!')

    return ans
示例#11
0
def inv_weighted(data, mesh, num_sub, col, ncp=5, power_parameter=2):
    r"""Interpolates the values taken at one group of points into
    another using an inverse-weighted algorithm

    In the inverse-weighted algorithm a number of `n_{CP}` measured points
    of the input parameter ``data`` that are closest to a given node in
    the input parameter ``mesh`` are found and the imperfection value of
    this node (represented by the normal displacement `{w_0}_{node}`) is
    calculated as follows:

    .. math::
        {w_0}_{node} = \frac{\sum_{i}^{n_{CP}}{{w_0}_i\frac{1}{w_i}}}
                            {\sum_{i}^{n_{CP}}{\frac{1}{w_i}}}

    where `w_i` is the imperfection at each measured point, calculated as:

    .. math::
        w_i = \left[(x_{node}-x_i)^2+(y_{node}-y_i)^2+(z_{node}-y_i)^2
              \right]^p

    with `p` being a power parameter that when increased will increase the
    relative influence of a closest point.

    Parameters
    ----------
    data : numpy.ndarray, shape (N, ndim+1)
        The data or an array containing the imperfection file. The values
        to be interpolated must be in the last column.
    mesh : numpy.ndarray, shape (M, ndim)
        The new coordinates where the values will be interpolated to.
    num_sub : int
        The number of sub-sets used during the interpolation. The points
        are divided in sub-sets to increase the algorithm's efficiency.
    col : int
        The index of the column to be used in order to divide the data
        in sub-sets. Note that the first column index is ``0``.
    ncp : int, optional
        Number of closest points used in the inverse-weighted interpolation.
    power_parameter : float, optional
        Power of inverse weighted interpolation function.

    Returns
    -------
    ans : numpy.ndarray
        A 1-D array with the interpolated values. The size of this array
        is ``mesh.shape[0]``.

    """
    if mesh.shape[1] != data.shape[1] - 1:
        raise ValueError('Invalid input: mesh.shape[1] != data.shape[1]')

    msg('Interpolating... ')
    num_sub = int(num_sub)
    mesh_size = mesh.shape[0]

    # memory control
    mem_limit = 1024 * 1024 * 1024 * 8 * 2  # 2 GB
    mem_entries = int(mem_limit / 64)  # if float64 is used
    sec_size = int(mesh_size / num_sub)
    while sec_size**2 * 10 > mem_entries:
        num_sub += 1
        sec_size = int(mesh_size / num_sub)
        if sec_size**2 * 10 <= mem_entries:
            warn('New num_sub: {0}'.format(int(mesh_size / float(sec_size))))
            break

    mesh_seq = np.arange(mesh.shape[0])

    mesh_argsort = np.argsort(mesh[:, col])
    mesh_seq = mesh_seq[mesh_argsort]
    back_argsort = np.argsort(mesh_seq)

    mesh = np.asarray(mesh[mesh_argsort], order='F')

    length = mesh[:, col].max() - mesh[:, col].min()

    data = np.asarray(data[np.argsort(data[:, col])], order='F')

    ans = np.zeros(mesh.shape[0], dtype=mesh.dtype)

    # max_num_limits defines how many times the log will print
    # "processed ... out of ... entries"
    max_num_limits = 10
    for den in range(max_num_limits, 0, -1):
        if num_sub % den == 0:
            limit = int(num_sub / den)
            break

    for i in range(num_sub + 1):
        i_inf = sec_size * i
        i_sup = sec_size * (i + 1)

        if i % limit == 0:
            msg('\t processed {0:7d} out of {1:7d} entries'.format(
                min(i_sup, mesh_size), mesh_size))
        sub_mesh = mesh[i_inf:i_sup]
        if not np.any(sub_mesh):
            continue
        inf = sub_mesh[:, col].min()
        sup = sub_mesh[:, col].max()

        tol = 0.03
        if i == 0 or i == num_sub:
            tol = 0.06

        while True:
            cond1 = data[:, col] >= inf - tol * length
            cond2 = data[:, col] <= sup + tol * length
            cond = np.all(np.array((cond1, cond2)), axis=0)
            sub_data = data[cond]
            if not np.any(sub_data):
                tol += 0.01
            else:
                break

        dist = np.subtract.outer(sub_mesh[:, 0], sub_data[:, 0])**2
        for j in range(1, sub_mesh.shape[1]):
            dist += np.subtract.outer(sub_mesh[:, j], sub_data[:, j])**2
        asort = np.argsort(dist, axis=1)
        lenn = sub_mesh.shape[0]
        lenp = sub_data.shape[0]
        asort_mesh = asort + np.meshgrid(
            np.arange(lenn) * lenp, np.arange(lenp))[0].transpose()
        # getting the distance of the closest points
        dist_cp = np.take(dist, asort_mesh[:, :ncp])
        # avoiding division by zero
        dist_cp[(dist_cp == 0)] == 1.e-12
        # fetching the imperfection of the sub-data
        imp = sub_data[:, -1]
        # taking only the imperfection of the closest points
        imp_cp = np.take(imp, asort[:, :ncp])
        # weight calculation
        total_weight = np.sum(1. / (dist_cp**power_parameter), axis=1)
        weight = 1. / (dist_cp**power_parameter)
        # computing the new imp
        imp_new = np.sum(imp_cp * weight, axis=1) / total_weight
        # updating the answer array
        ans[i_inf:i_sup] = imp_new

    ans = ans[back_argsort]

    msg('Interpolation completed!')

    return ans
示例#12
0
    def plot(self,
             c,
             group,
             invert_y=False,
             vec='w',
             filename='',
             ax=None,
             figsize=(3.5, 2.),
             save=True,
             title='',
             identify=False,
             show_boundaries=False,
             boundary_line='--k',
             boundary_linewidth=1.,
             colorbar=False,
             cbar_nticks=2,
             cbar_format=None,
             cbar_title='',
             cbar_fontsize=10,
             colormap='jet',
             aspect='equal',
             clean=True,
             dpi=400,
             texts=[],
             xs=None,
             ys=None,
             gridx=50,
             gridy=50,
             num_levels=400,
             vecmin=None,
             vecmax=None,
             calc_data_only=False):
        r"""Contour plot for a Ritz constants vector.

        Parameters
        ----------
        c : np.ndarray
            The Ritz constants that will be used to compute the field contour.
        group : str
            A group to plot. Each panel in ``panels`` should contain an
            attribute ``group``, which is used to identify which entities
            should be plotted together.
        vec : str, optional
            Can be one of the components:

            - Displacement: ``'u'``, ``'v'``, ``'w'``, ``'phix'``, ``'phiy'``
            - Strain: ``'exx'``, ``'eyy'``, ``'gxy'``, ``'kxx'``, ``'kyy'``,
              ``'kxy'``, ``'gyz'``, ``'gxz'``
            - Stress: ``'Nxx'``, ``'Nyy'``, ``'Nxy'``, ``'Mxx'``, ``'Myy'``,
              ``'Mxy'``, ``'Qy'``, ``'Qx'``
        invert_y : bool, optional
            Inverts the `y` axis of the plot.
        save : bool, optional
            Flag telling whether the contour should be saved to an image file.
        dpi : int, optional
            Resolution of the saved file in dots per inch.
        filename : str, optional
            The file name for the generated image file. If no value is given,
            the `name` parameter of the ``Panel`` object will be used.
        ax : AxesSubplot, optional
            When ``ax`` is given, the contour plot will be created inside it.
        figsize : tuple, optional
            The figure size given by ``(width, height)``.
        title : str, optional
            If any string is given a title is added to the contour plot.
        indentify : bool, optional
            If domains should be identified. If yes, the name of each panel is
            used.
        show_boundaries : bool, optional
            If boundaries between domains should be drawn.
        boundary_line : str, optional
            Matplotlib string to define line type and color.
        boundary_linewidth : float, optional
            Matplotlib float to define line width.
        colorbar : bool, optional
            If a colorbar should be added to the contour plot.
        cbar_nticks : int, optional
            Number of ticks added to the colorbar.
        cbar_format : [ None | format string | Formatter object ], optional
            See the ``matplotlib.pyplot.colorbar`` documentation.
        cbar_title : str, optional
            Colorbar title. If ``cbar_title == ''`` no title is added.
        cbar_fontsize : int, optional
            Fontsize of the colorbar labels.
        colormap : string, optional
            Name of a matplotlib available colormap.
        aspect : str, optional
            String that will be passed to the ``AxesSubplot.set_aspect()``
            method.
        clean : bool, optional
            Clean axes ticks, grids, spines etc.
        xs : np.ndarray, optional
            The `x` positions where to calculate the displacement field.
            Default is ``None`` and the method ``_default_field`` is used.
        ys : np.ndarray, optional
            The ``y`` positions where to calculate the displacement field.
            Default is ``None`` and the method ``_default_field`` is used.
        gridx : int, optional
            Number of points along the `x` axis where to calculate the
            displacement field.
        gridy : int, optional
            Number of points along the `y` where to calculate the
            displacement field.
        num_levels : int, optional
            Number of contour levels (higher values make the contour smoother).
        vecmin : float, optional
            Minimum value for the contour scale (useful to compare with other
            results). If not specified it will be taken from the calculated
            field.
        vecmax : float, optional
            Maximum value for the contour scale.
        calc_data_only : bool, optional
            If only calculated data should be returned.

        Returns
        -------
        ax : matplotlib.axes.Axes
            The Matplotlib object that can be used to modify the current plot
            if needed.
        data : dict
            Data calculated during the plotting procedure.

        """
        msg('Plotting contour...')

        import matplotlib
        if platform.system().lower() == 'linux':
            matplotlib.use('Agg')
        import matplotlib.pyplot as plt

        msg('Computing field variables...', level=1)
        displs = ['u', 'v', 'w', 'phix', 'phiy']
        strains = ['exx', 'eyy', 'gxy', 'kxx', 'kyy', 'kxy', 'gyz', 'gxz']
        stresses = ['Nxx', 'Nyy', 'Nxy', 'Mxx', 'Myy', 'Mxy', 'Qy', 'Qx']
        if vec in displs:
            res = self.uvw(c, group, gridx=gridx, gridy=gridy)
        elif vec in strains:
            res = self.strain(c, group, gridx=gridx, gridy=gridy)
        elif vec in stresses:
            res = self.stress(c, group, gridx=gridx, gridy=gridy)
        else:
            raise ValueError(
                '{0} is not a valid vec parameter value!'.format(vec))
        field = np.array(res[vec])
        msg('Finished!', level=1)

        if vecmin is None:
            vecmin = field.min()
        if vecmax is None:
            vecmax = field.max()

        data = dict(vecmin=vecmin, vecmax=vecmax)

        if calc_data_only:
            return None, data

        levels = linspace(vecmin, vecmax, num_levels)

        if ax is None:
            fig = plt.figure(figsize=figsize)
            ax = fig.add_subplot(111)
        else:
            if isinstance(ax, matplotlib.axes.Axes):
                ax = ax
                fig = ax.figure
                save = False
            else:
                raise ValueError('ax must be an Axes object')

        if invert_y == True:
            ax.invert_yaxis()
        ax.invert_xaxis()

        colormap_obj = getattr(cm, colormap, None)
        if colormap_obj is None:
            warn('Invalid colormap, using "jet"', level=1)
            colormap_obj = cm.jet

        count = -1
        for i, panel in enumerate(self.panels):
            if panel.group != group:
                continue
            count += 1
            xplot = res['y'][count] + panel.y0
            yplot = res['x'][count] + panel.x0
            field = res[vec][count]
            contour = ax.contourf(xplot,
                                  yplot,
                                  field,
                                  levels=levels,
                                  cmap=colormap_obj)
            if identify:
                ax.text(xplot.mean(),
                        yplot.mean(),
                        'P {0:02d}'.format(i + 1),
                        transform=ax.transData,
                        ha='center')
            if show_boundaries:
                x1, x2 = xplot.min(), xplot.max()
                y1, y2 = yplot.min(), yplot.max()
                ax.plot((x1, x2), (y1, y1),
                        boundary_line,
                        lw=boundary_linewidth)
                ax.plot((x1, x2), (y2, y2),
                        boundary_line,
                        lw=boundary_linewidth)
                ax.plot((x1, x1), (y1, y2),
                        boundary_line,
                        lw=boundary_linewidth)
                ax.plot((x2, x2), (y1, y2),
                        boundary_line,
                        lw=boundary_linewidth)

        if colorbar:
            from mpl_toolkits.axes_grid1 import make_axes_locatable

            fsize = cbar_fontsize
            divider = make_axes_locatable(ax)
            cax = divider.append_axes('right', size='5%', pad=0.05)
            cbarticks = linspace(vecmin, vecmax, cbar_nticks)
            cbar = plt.colorbar(contour,
                                ticks=cbarticks,
                                format=cbar_format,
                                cax=cax)
            if cbar_title:
                cax.text(0.5,
                         1.05,
                         cbar_title,
                         horizontalalignment='center',
                         verticalalignment='bottom',
                         fontsize=fsize)
            cbar.outline.remove()
            cbar.ax.tick_params(labelsize=fsize, pad=0., tick2On=False)

        if title != '':
            ax.set_title(str(title))

        fig.tight_layout()
        ax.set_aspect(aspect)

        ax.grid(False)
        ax.set_frame_on(False)
        if clean:
            ax.xaxis.set_ticks_position('none')
            ax.yaxis.set_ticks_position('none')
            ax.xaxis.set_ticklabels([])
            ax.yaxis.set_ticklabels([])
        else:
            ax.xaxis.set_ticks_position('bottom')
            ax.yaxis.set_ticks_position('left')

        for kwargs in texts:
            ax.text(transform=ax.transAxes, **kwargs)

        if save:
            if not filename:
                filename = group + '.png'
            fig.savefig(filename,
                        transparent=True,
                        bbox_inches='tight',
                        pad_inches=0.05,
                        dpi=dpi)
            plt.close()

        msg('finished!')

        return ax, data
示例#13
0
def _solver_NR(a):
    """Newton-Raphson solver

    """
    msg('Initialization...', level=1)

    modified_NR = a.modified_NR
    inc = a.initialInc
    total = inc
    once_at_total = False
    max_total = 0.

    fext = a.calc_fext(inc=inc)
    k0 = a.calc_k0()
    c = solve(k0, fext)
    kT_last = k0

    if modified_NR:
        compute_kT = False
    else:
        compute_kT = True

    step_num = 1
    while True:
        msg('Started Load Step {} - '.format(step_num)
            + 'Attempting time = {0}'.format(total), level=1)

        # TODO maybe for pdC=True, pdT the fext must be calculated with
        # the last kT available...

        absERR = 1.e6
        relERR = 1.e6
        min_Rmax = 1.e6
        prev_Rmax = 1.e6
        last_min_Rmax = 1.e6
        iteration = 0
        converged = False

        kT = kT_last

        fext = a.calc_fext(inc=total)

        iter_NR = 0
        while True:
            iteration += 1
            msg('Iteration: {}'.format(iteration), level=2)
            if iteration > a.maxNumIter:
                warn('Maximum number of iterations achieved!', level=2)
                break

            if compute_kT or (a.kT_initial_state and step_num==1 and
                    iteration==1) or iter_NR==(a.compute_every_n-1):
                iter_NR = 0
                kT = a.calc_kT(c, inc=total)
            else:
                iter_NR += 1
                if not modified_NR:
                    compute_kT = True

            fint = a.calc_fint(c=c, inc=total)

            R = fext - fint

            # convergence criteria:
            # - maximum residual force Rmax
            Rmax = np.abs(R).max()
            msg('Rmax = {0}'.format(Rmax), level=3)

            if iteration >= 2 and Rmax < a.absTOL:
                converged = True
                break
            if (Rmax > prev_Rmax and Rmax > min_Rmax and iteration > 2):
                warn('Diverged!', level=2)
                break
            else:
                min_Rmax = min(min_Rmax, Rmax)
            change_rate_Rmax = abs(prev_Rmax-Rmax)/abs(prev_Rmax)
            if (iteration > 2 and change_rate_Rmax < a.too_slow_TOL):
                warn('Diverged! (convergence too slow)', level=2)
                break
            prev_Rmax = Rmax

            msg('Solving... ', level=2)
            delta_c = solve(kT, R)
            msg('finished!', level=2)

            eta1 = 0.
            eta2 = 1.
            if a.line_search:
                msg('Performing line-search... ', level=2)
                iter_line_search = 0
                while True:
                    c1 = c + eta1*delta_c
                    c2 = c + eta2*delta_c
                    fint1 = a.calc_fint(c1, inc=total)
                    fint2 = a.calc_fint(c2, inc=total)
                    R1 = fext - fint1
                    R2 = fext - fint2
                    s1 = delta_c.dot(R1)
                    s2 = delta_c.dot(R2)
                    eta_new = (eta2-eta1)*(-s1/(s2-s1)) + eta1
                    eta1 = eta2
                    eta2 = eta_new
                    eta2 = min(max(eta2, 0.2), 10.)
                    if abs(eta2-eta1) < 0.01:
                        break
                    iter_line_search += 1
                    if iter_line_search == a.max_iter_line_search:
                        eta2 = 1.
                        warn('maxinum number of iterations', level=3)
                        break
                msg('finished!', level=2)
            c = c + eta2*delta_c

        if converged:
            msg('Finished Load Step {} at'.format(step_num)
                + ' time = {0}'.format(total), level=1)
            a.increments.append(total)
            a.cs.append(c.copy()) #NOTE copy required
            finished = False
            if abs(total - 1) < 1e-3:
                finished = True
            else:
                factor = 1.1
                if once_at_total:
                    inc_new = min(factor*inc, a.maxInc, (1.-total)/2)
                else:
                    inc_new = min(factor*inc, a.maxInc, 1.-total)
                msg('Changing time increment from {0} to {1}'.format(
                    inc, inc_new), level=1)
                inc = inc_new
                total += inc
                total = min(1, total)
                step_num += 1
            if finished:
                break
            if modified_NR:
                msg('Updating kT...', level=1)
                kT = a.calc_kT(c, inc=total)
                msg('kT updated!', level=1)
            compute_kT = False
            kT_last = kT
        else:
            max_total = max(max_total, total)
            while True:
                factor = 0.3
                msg('Bisecting time increment from {0} to {1}'.format(
                    inc, inc*factor), level=1)
                if abs(total -1) < 1e-3:
                    once_at_total = True
                total -= inc
                inc *= factor
                if inc < a.minInc:
                    msg('Minimum step size achieved!', level=1)
                    break
                total += inc
                if total >= max_total:
                    continue
                else:
                    break
            if inc < a.minInc:
                msg('Stopping solver: minimum step size achieved!',
                        level=1)
                break

        if len(a.cs)>0:
            c = a.cs[-1].copy() #NOTE copy required
        else:
            # means that a bisection must be done in initialInc
            fext = a.calc_fext(inc=inc)
            c = solve(k0, fext)

    msg('Finished Non-Linear Static Analysis')
    msg('at time {0}'.format(total), level=1)
示例#14
0
    def _rebuild(self):
        if not self.name:
            try:
                self.name = os.path.basename(__main__.__file__).split('.py')[0]
            except AttributeError:
                warn('Plate name unchanged')

        self.model = self.model.lower()

        valid_models = sorted(modelDB.db.keys())

        if not self.model in valid_models:
            raise ValueError('ERROR - valid models are:\n    ' +
                     '\n    '.join(valid_models))

        # boundary conditions
        inf = self.inf
        zero = self.zero

        if inf > self.maxinf:
            warn('inf reduced to {0:1.1e4} due to the verified'.format(
                 self.maxinf) +
                 ' numerical instability for higher values', level=2)
            inf = self.maxinf

        if self.bc is not None:
            bc = self.bc.lower()

            if '_' in bc:
                # different bc for Bot, Top, Left and Right
                bc_Bot, bc_Top, bc_Left, bc_Right = self.bc.split('_')
            elif '-' in bc:
                # different bc for Bot, Top, Left and Right
                bc_Bot, bc_Top, bc_Left, bc_Right = self.bc.split('-')
            else:
                bc_Bot = bc_Top = bc_Left = bc_Right = bc

            bcs = dict(bc_Bot=bc_Bot, bc_Top=bc_Top,
                       bc_Left=bc_Left, bc_Right=bc_Right)
            for k in bcs.keys():
                sufix = k.split('_')[1] # Bot or Top
                if bcs[k] == 'ss1':
                    setattr(self, 'ku' + sufix, inf)
                    setattr(self, 'kv' + sufix, inf)
                    setattr(self, 'kw' + sufix, inf)
                    setattr(self, 'kphix' + sufix, zero)
                    setattr(self, 'kphiy' + sufix, zero)
                elif bcs[k] == 'ss2':
                    setattr(self, 'ku' + sufix, zero)
                    setattr(self, 'kv' + sufix, inf)
                    setattr(self, 'kw' + sufix, inf)
                    setattr(self, 'kphix' + sufix, zero)
                    setattr(self, 'kphiy' + sufix, zero)
                elif bcs[k] == 'ss3':
                    setattr(self, 'ku' + sufix, inf)
                    setattr(self, 'kv' + sufix, zero)
                    setattr(self, 'kw' + sufix, inf)
                    setattr(self, 'kphix' + sufix, zero)
                    setattr(self, 'kphiy' + sufix, zero)
                elif bcs[k] == 'ss4':
                    setattr(self, 'ku' + sufix, zero)
                    setattr(self, 'kv' + sufix, zero)
                    setattr(self, 'kw' + sufix, inf)
                    setattr(self, 'kphix' + sufix, zero)
                    setattr(self, 'kphiy' + sufix, zero)

                elif bcs[k] == 'cc1':
                    setattr(self, 'ku' + sufix, inf)
                    setattr(self, 'kv' + sufix, inf)
                    setattr(self, 'kw' + sufix, inf)
                    setattr(self, 'kphix' + sufix, inf)
                    setattr(self, 'kphiy' + sufix, inf)
                elif bcs[k] == 'cc2':
                    setattr(self, 'ku' + sufix, zero)
                    setattr(self, 'kv' + sufix, inf)
                    setattr(self, 'kw' + sufix, inf)
                    setattr(self, 'kphix' + sufix, inf)
                    setattr(self, 'kphiy' + sufix, inf)
                elif bcs[k] == 'cc3':
                    setattr(self, 'ku' + sufix, inf)
                    setattr(self, 'kv' + sufix, zero)
                    setattr(self, 'kw' + sufix, inf)
                    setattr(self, 'kphix' + sufix, inf)
                    setattr(self, 'kphiy' + sufix, inf)
                elif bcs[k] == 'cc4':
                    setattr(self, 'ku' + sufix, zero)
                    setattr(self, 'kv' + sufix, zero)
                    setattr(self, 'kw' + sufix, inf)
                    setattr(self, 'kphix' + sufix, inf)
                    setattr(self, 'kphiy' + sufix, inf)

                elif bcs[k] == 'free':
                    setattr(self, 'ku' + sufix, zero)
                    setattr(self, 'kv' + sufix, zero)
                    setattr(self, 'kw' + sufix, zero)
                    setattr(self, 'kphix' + sufix, zero)
                    setattr(self, 'kphiy' + sufix, zero)

                else:
                    txt = '"{}" is not a valid boundary condition!'.format(bc)
                    raise ValueError(txt)

        if self.a is None:
            raise ValueError('The length a must be specified')

        if self.b is None:
            raise ValueError('The width b must be specified')

        if not self.laminaprops:
            self.laminaprops = [self.laminaprop for i in self.stack]
        if not self.plyts:
            self.plyts = [self.plyt for i in self.stack]

        def check_load(load, size):
            if load is not None:
                check = False
                if isinstance(load, np.ndarray):
                    if load.ndim == 1:
                        assert load.shape[0] == size

                        return load
                elif type(load) in (int, float):
                    newload = np.zeros(size, dtype=DOUBLE)
                    newload[0] = load

                    return newload
                if not check:
                    raise ValueError('Invalid NxxTop input')
            else:
                return np.zeros(size, dtype=DOUBLE)


        # axial load
        size = self.n1+1
        self.NxxTop = check_load(self.NxxTop, size)
        self.NxxTop_inc = check_load(self.NxxTop_inc, size)
        # shear xt
        self.NxyTop = check_load(self.NxyTop, size)
        self.NxyTop_inc = check_load(self.NxyTop_inc, size)
        # circumferential load
        size = self.m1+1
        self.NyyLeft = check_load(self.NyyLeft, size)
        self.NyyLeft_inc = check_load(self.NyyLeft_inc, size)
        # shear tx
        self.NyxLeft = check_load(self.NyxLeft, size)
        self.NyxLeft_inc = check_load(self.NyxLeft_inc, size)

        # defining load components from force vectors
        if self.laminaprop is None:
            raise ValueError('laminaprop must be defined')
示例#15
0
def lb(K, KG, tol=0, sparse_solver=True, silent=False,
       num_eigvalues=25, num_eigvalues_print=5):
    """Linear Buckling Analysis

    It can also be used for more general eigenvalue analyzes if `K` is the
    tangent stiffness matrix of a given load state.

    Parameters
    ----------
    K : sparse_matrix
        Stiffness matrix. Should include all constant terms of the initial
        stress stiffness matrix, aerodynamic matrix and so forth when
        applicable.
    KG : sparse_matrix
        Initial stress stiffness matrix that multiplies the load multiplcator
        `\lambda` of the eigenvalue problem.
    tol : float, optional
        A float tolerance passsed to the eigenvalue solver.
    sparse_solver : bool, optional
        Tells if solver :func:`scipy.linalg.eigh` or
        :func:`scipy.sparse.linalg.eigsh` should be used.
    silent : bool, optional
        A boolean to tell whether the log messages should be printed.
    num_eigvalues : int, optional
        Number of calculated eigenvalues.
    num_eigvalues_print : int, optional
        Number of eigenvalues to print.

    Notes
    -----
    The extracted eigenvalues are stored in the ``eigvals`` parameter
    of the ``Panel`` object and the `i^{th}` eigenvector in the
    ``eigvecs[:, i-1]`` parameter.

    """
    msg('Running linear buckling analysis...', silent=silent)

    msg('Eigenvalue solver... ', level=2, silent=silent)

    k = min(num_eigvalues, KG.shape[0]-2)
    if sparse_solver:
        mode = 'cayley'
        try:
            msg('eigsh() solver...', level=3, silent=silent)
            eigvals, eigvecs = eigsh(A=KG, k=k,
                    which='SM', M=K, tol=tol, sigma=1., mode=mode)
            msg('finished!', level=3, silent=silent)
        except Exception as e:
            warn(str(e), level=4, silent=silent)
            msg('aborted!', level=3, silent=silent)
            sizebkp = KG.shape[0]
            K, KG, used_cols = remove_null_cols(K, KG, silent=silent)
            msg('eigsh() solver...', level=3, silent=silent)
            eigvals, peigvecs = eigsh(A=KG, k=k,
                    which='SM', M=K, tol=tol, sigma=1., mode=mode)
            msg('finished!', level=3, silent=silent)
            eigvecs = np.zeros((sizebkp, num_eigvalues),
                               dtype=peigvecs.dtype)
            eigvecs[used_cols, :] = peigvecs

    else:
        size = KG.shape[0]
        K, KG, used_cols = remove_null_cols(K, KG, silent=silent)
        K = K.toarray()
        KG = KG.toarray()
        msg('eigh() solver...', level=3, silent=silent)
        eigvals, peigvecs = eigh(a=KG, b=K)
        msg('finished!', level=3, silent=silent)
        eigvecs = np.zeros((size, num_eigvalues), dtype=peigvecs.dtype)
        eigvecs[used_cols, :] = peigvecs[:, :num_eigvalues]

    eigvals = -1./eigvals

    eigvals = eigvals
    eigvecs = eigvecs

    msg('finished!', level=2, silent=silent)

    msg('first {0} eigenvalues:'.format(num_eigvalues_print), level=1,
        silent=silent)

    for eig in eigvals[:num_eigvalues_print]:
        msg('{0}'.format(eig), level=2, silent=silent)

    return eigvals, eigvecs
示例#16
0
    def freq(self, atype=4, tol=0, sparse_solver=False, silent=False,
            sort=True, damping=False, reduced_dof=False):
        """Performs a frequency analysis

        The following parameters of the ``AeroPistonStiffPanel`` object will
        affect the linear buckling analysis:

        =======================    =====================================
        parameter                  description
        =======================    =====================================
        ``num_eigenvalues``        Number of eigenvalues to be extracted
        ``num_eigvalues_print``    Number of eigenvalues to print after
                                   the analysis is completed
        =======================    =====================================

        Parameters
        ----------
        atype : int, optional
            Tells which analysis type should be performed:
            - ``1`` : considers k0, kA and kG0
            - ``2`` : considers k0 and kA
            - ``3`` : considers k0 and kG0
            - ``4`` : considers k0 only
        tol : float, optional
            A tolerance value passed to ``scipy.sparse.linalg.eigs``.
        sparse_solver : bool, optional
            Tells if solver :func:`scipy.linalg.eig` or
            :func:`scipy.sparse.linalg.eigs` should be used.

            .. note:: It is recommended ``sparse_solver=False``, because it
                      was verified that the sparse solver becomes unstable
                      for some cases, though the sparse solver is faster.
        silent : bool, optional
            A boolean to tell whether the log messages should be printed.
        sort : bool, optional
            Sort the output eigenvalues and eigenmodes.
        damping : bool, optinal
            If aerodynamic damping should be taken into account.
        reduced_dof : bool, optional
            Considers only the contributions of `v` and `w` to the stiffness
            matrix and accelerates the run. Only effective when
            ``sparse_solver=False``.

        Notes
        -----
        The extracted eigenvalues are stored in the ``eigvals`` parameter
        of the ``AeroPistonStiffPanel`` object and the `i^{th}` eigenvector in
        the ``eigvecs[:, i-1]`` parameter.

        """
        if not modelDB.db[self.model]['linear buckling']:
            msg('________________________________________________')
            msg('')
            warn('Model {0} cannot be used in linear buckling analysis!'.
                 format(self.model))
            msg('________________________________________________')

        msg('Running frequency analysis...', silent=silent)

        if atype == 1:
            self.calc_linear_matrices(silent=silent)
        elif atype == 2:
            self.calc_linear_matrices(silent=silent, calc_kG0=False)
        elif atype == 3:
            self.calc_linear_matrices(silent=silent, calc_kA=False)
        elif atype == 4:
            self.calc_linear_matrices(silent=silent, calc_kA=False,
                                      calc_kG0=False)

        msg('Eigenvalue solver... ', level=2, silent=silent)

        if atype == 1:
            K = self.k0 + self.kA + self.kG0
        elif atype == 2:
            K = self.k0 + self.kA
        elif atype == 3:
            K = self.k0 + self.kG0
        elif atype == 4:
            K = self.k0
        M = self.kM

        if damping and self.cA is None:
            warn('Aerodynamic damping could not be calculated!', level=3,
                    silent=silent)
            damping = False
        elif damping and self.cA is not None:
            if self.cA.sum() == 0j:
                damping = False

        msg('eigs() solver...', level=3, silent=silent)
        k = min(self.num_eigvalues, M.shape[0]-2)
        if sparse_solver:
            eigvals, eigvecs = eigs(A=M, M=K, k=k, tol=tol, which='SM',
                                    sigma=-1.)
            eigvals = np.sqrt(1./eigvals) # omega^2 to omega, in rad/s
        else:
            M = M.toarray()
            K = K.toarray()
            if reduced_dof:
                i = np.arange(M.shape[0])
                take = np.column_stack((i[1::3], i[2::3])).flatten()
                M = M[:, take][take, :]
                K = K[:, take][take, :]
            if not damping:
                M = -M
            else:
                size = M.shape[0]
                cA = self.cA.toarray()
                if reduced_dof:
                    cA = cA[:, take][take, :]
                I = np.identity(M.shape[0])
                Z = np.zeros_like(M)
                M = np.row_stack((np.column_stack((I, Z)),
                                  np.column_stack((Z, -M))))
                K = np.row_stack((np.column_stack((Z, -I)),
                                  np.column_stack((K, cA))))

            eigvals, eigvecs = eig(a=M, b=K)

            if not damping:
                eigvals = np.sqrt(-1./eigvals) # -1/omega^2 to omega, in rad/s
                eigvals = eigvals
            else:
                eigvals = -1./eigvals # -1/omega to omega, in rad/s
                shape = eigvals.shape
                eigvals = eigvals[:shape[0]//2]
                eigvecs = eigvecs[:eigvecs.shape[0]//2, :shape[0]//2]

        msg('finished!', level=3, silent=silent)

        if sort:
            if damping:
                higher_zero = eigvals.real > 1e-6

                eigvals = eigvals[higher_zero]
                eigvecs = eigvecs[:, higher_zero]

                sort_ind = np.lexsort((np.round(eigvals.imag, 1),
                                       np.round(eigvals.real, 0)))
                eigvals = eigvals[sort_ind]
                eigvecs = eigvecs[:, sort_ind]

            else:
                sort_ind = np.lexsort((np.round(eigvals.imag, 1),
                                       np.round(eigvals.real, 1)))
                eigvals = eigvals[sort_ind]
                eigvecs = eigvecs[:, sort_ind]

                higher_zero = eigvals.real > 1e-6

                eigvals = eigvals[higher_zero]
                eigvecs = eigvecs[:, higher_zero]

        if not sparse_solver and reduced_dof:
            new_eigvecs = np.zeros((3*eigvecs.shape[0]//2, eigvecs.shape[1]),
                    dtype=eigvecs.dtype)
            new_eigvecs[take, :] = eigvecs
            eigvecs = new_eigvecs

        self.eigvals = eigvals
        self.eigvecs = eigvecs

        msg('finished!', level=2, silent=silent)

        msg('first {0} eigenvalues:'.format(self.num_eigvalues_print), level=1,
                silent=silent)
        for eigval in eigvals[:self.num_eigvalues_print]:
            msg('{0} rad/s'.format(eigval), level=2, silent=silent)
        self.analysis.last_analysis = 'freq'