Source code for compmech.panel.assembly.assembly

import numpy as np
from numpy import linspace

from compmech.logger import msg, warn
from compmech.constants import DOUBLE
import compmech.panel.modelDB as modelDB


[docs]class PanelAssembly(object): r"""Class for Panel Assemblies This class has some useful methods that will help plotting output for different panel groups within the assembly and so forth. Parameters ---------- panels : iterable A list, tuple etc of :class:`.Panel` objects. """ def __init__(self, panels): self.panels = panels self.size = None self.out_num_cores = 4 def get_size(self): self.size = sum([3*p.m*p.n for p in panels]) return self.size
[docs] 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, 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_fontsize : int, optional Fontsize of the colorbar labels. cbar_title : str, optional Colorbar title. If ``cbar_title == ''`` no title is added. 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.pyplot as plt import matplotlib 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) field = np.array(res[vec]) elif vec in strains: raise NotImplementedError('Strains not implemented') elif vec in stresses: raise NotImplementedError('Stresses not implemented') else: raise ValueError( '{0} is not a valid vec parameter value!'.format(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() 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) 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
[docs] def uvw(self, c, group, gridx=50, gridy=50): r"""Calculates the displacement field For a given full set of Ritz constants ``c``, the displacement field is calculated and stored in the parameters ``u``, ``v``, ``w``, ``phix``, ``phiy`` of the ``Panel`` object. Parameters ---------- c : float The full set of Ritz constants 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. 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. Returns ------- out : tuple A tuple of ``np.ndarrays`` containing ``(xs, ys, u, v, w, phix, phiy)``. Notes ----- The returned values ``u```, ``v``, ``w``, ``phix``, ``phiy`` are stored as parameters with the same name in the ``Panel`` object. """ def default_field(panel): xs = linspace(0, panel.a, gridx) ys = linspace(0, panel.b, gridy) xs, ys = np.meshgrid(xs, ys, copy=False) xs = np.atleast_1d(np.array(xs, dtype=DOUBLE)) ys = np.atleast_1d(np.array(ys, dtype=DOUBLE)) shape = xs.shape xs = xs.ravel() ys = ys.ravel() return xs, ys, shape res = dict(x=[], y=[], u=[], v=[], w=[], phix=[], phiy=[]) for panel in self.panels: if panel.group != group: continue cpanel = c[panel.col_start: panel.col_end] cpanel = np.ascontiguousarray(cpanel, dtype=DOUBLE) m = panel.m n = panel.n a = panel.a b = panel.b model = panel.model fuvw = modelDB.db[model]['field'].fuvw x, y, shape = default_field(panel) u, v, w, phix, phiy = fuvw(cpanel, m, n, a, b, np.ascontiguousarray(x), np.ascontiguousarray(y), self.out_num_cores) res['x'].append(x.reshape(shape)) res['y'].append(y.reshape(shape)) res['u'].append(u.reshape(shape)) res['v'].append(v.reshape(shape)) res['w'].append(w.reshape(shape)) res['phix'].append(phix.reshape(shape)) res['phiy'].append(phiy.reshape(shape)) return res