class MFnMultiPlotAdapter(MFnPlotAdapter): """ The base class for adapting function implementation in order to plot it in a plotting toolkit (either Chaco or Matplotlib) """ # rr: test only, needs to be written in a more robust way mline_style = List(100 * ['solid']) mline_color = List(100 * ['black']) mline_width = List(100 * [2.0])
class MFnMultiLine(HasTraits): # Public Traits lines = List( MFnLineArray ) xdata = Property( List( Array ) ) def _get_xdata(self): return [ mfn.xdata for mfn in self.lines ] ydata = Property( List( Array ) ) def _get_ydata(self): return [ mfn.ydata for mfn in self.lines ] data_changed = Event
class ECBLFBM(ECBLBase): '''Effective crack bridge Law based on fiber-bundle-model.''' sig_tex_u = Float(1216, input=True) eps_tex_u = Float(0.014, input=True) m = Float(0.5, input=True) cnames = ['eps_tex_u', 'm'] u0 = List([0.01266923, 0.5]) eps_arr = Property(depends_on='+input') @cached_property def _get_eps_arr(self): return np.linspace(0, self.eps_tex_u, num=100.) sig_arr = Property(depends_on='+input') @cached_property def _get_sig_arr(self): sig_tex_u = self.sig_tex_u eps_tex_u = self.eps_tex_u eps_arr = self.eps_arr m = self.m return ( sig_tex_u / eps_tex_u / exp(-pow(exp(-log(m) / self.m), 1.0 * m)) * eps_arr * np.exp(-np.power(eps_arr / eps_tex_u * exp(-log(m) / m), 1.0 * m)))
class ECBLLinear(ECBLBase): '''Effective crack bridge Law with linear elastic response.''' eps_tex_u = Float(0.01, enter_set=True, auto_set=False, input=True) E_tex = Float(80000, enter_set=True, auto_set=False, input=True) u0 = List([0.01, 80000.], enter_set=True, auto_set=False) sig_tex_u = Property(depends_on='+input') @cached_property def _get_sig_tex_u(self): return self.E_tex * self.eps_tex_u cnames = ['eps_tex_u', 'E_tex'] eps_arr = Property(depends_on='+input') @cached_property def _get_eps_arr(self): return np.array([0., self.eps_tex_u]) sig_arr = Property(depends_on='+input') @cached_property def _get_sig_arr(self): # with limit for eps_tex # return self.E_tex * self.eps_arr
class WikiGen(HasTraits): rf_list = List([Filament, CBClampedFiber, CBInfiniteFiber, CBShortFiber, POClampedFiber, POInfiniteFiber, POShortFiber]) max_x = Float(0.01, enter_set=True, auto_set=False, config_change=True) n_points = Int(200, enter_set=True, auto_set=False, config_change=True) def export_wiki(self): fname = os.path.join('wiki', 'rf.wiki') f = open(fname, 'w') for rf_class in self.rf_list: q = rf_class() f.write(str(q) + '\n') qname = q.__class__.__name__ p.figure() q.plot(p, linewidth=2, color='navy') fig_fname = os.path.join('wiki', qname + '.png') p.savefig(fig_fname)
class ECBLCubic(ECBLBase): '''Effective crack bridge Law using a cubic polynomial.''' sig_tex_u = Float(1250, input=True) eps_tex_u = Float(0.016, input=True) var_a = Float(-5e+6, input=True) cnames = ['eps_tex_u', 'var_a'] u0 = List([0.016, -5000000.]) eps_arr = Property(depends_on='+input') @cached_property def _get_eps_arr(self): return np.linspace(0, self.eps_tex_u, num=100.) sig_arr = Property(depends_on='+input') @cached_property def _get_sig_arr(self): # for horizontal tangent at eps_tex_u sig_tex_u, var_a, eps_tex_u = self.sig_tex_u, self.var_a, self.eps_tex_u eps_arr = self.eps_arr var_b = -(sig_tex_u + 2. * var_a * eps_tex_u**3.) / eps_tex_u**2. var_c = -3. * var_a * eps_tex_u**2. - 2. * var_b * eps_tex_u sig_arr = var_a * eps_arr**3. + var_b * eps_arr**2. + var_c * eps_arr return sig_arr
class RVModelView(ModelView): ''' ModelView class for displaying the table of parameters and set the distribution parameters of random variables ''' title = Str('randomization setup') model = Instance(SPIRRID) rv_list = List(RIDVariable) @on_trait_change('model.rf') def get_rv_list(self): self.rv_list = [ RIDVariable(s=self.model, rf=self.model.rf, varname=nm, trait_value=st) for nm, st in zip(self.model.rf.param_keys, self.model.rf.param_values) ] selected_var = Instance(RIDVariable) def _selected_var_default(self): return self.rv_list[0] title = Str('random variable editor') selected_var = Instance(RIDVariable) traits_view = View(VSplit( HGroup( Item('rv_list', editor=rv_list_editor, show_label=False), id='rid.tview.randomization.rv', label='Model variables', ), HGroup( Item('selected_var@', show_label=False, resizable=True), id='rid.tview.randomization.distr', label='Distribution', ), scrollable=True, id='rid.tview.tabs', dock='tab', ), title='RANDOM VARIABLES', id='rid.ridview', dock='tab', resizable=True, height=1.0, width=1.0)
class NDIdxInterp(HasTraits): # nd array of values (measured, computed..) of # size orthogonalize(axes_values) data = Array # list of control input parameter values axes_values = List(Array(float)) def __call__(self, *gcoords, **kw): '''kw: dictionary of values to interpolate for; len(kw) has to be equal the data dimension ''' order = kw.get('order', 1) mode = kw.get('mode', 'nearest') # check if the number of dimensions to interpolate # in equals the number of given coordinates if len(self.axes_values) != len(gcoords): raise TypeError('''method takes {req} arguments ({given} given)'''.format(req=len(self.axes_values), given=len(gcoords))) icoords = self.get_icoords(gcoords) # create a meshgrid for the interpolation icoords = orthogonalize_filled(icoords) data = self.data # interpolate the value (linear) # a, b, c = [0.5, 0.5, 0.5], [0, 0, 0], [0, 1, 2] # icoords = [a, b, c] val = ndimage.map_coordinates(data, icoords, order=order, mode=mode) return val def get_icoords(self, gcoords): ''' gcoords: values to be interpolated for this method transforms the global coords to "index" coords ''' icoords = [ np.interp(gcoord, axis_values, np.arange(len(axis_values))) for gcoord, axis_values in zip(gcoords, self.axes_values) ] return icoords
class ECBLBilinear(ECBLBase): '''Effective crack bridge Law using a cubic polynomial.''' sig_tex_u = Float(1250, input=True) eps_tex_u = Float(0.014, input=True) var_a = Float(50000, input=True) eps_el_fraction = Float(0.0001, input=True) cnames = ['eps_tex_u', 'var_a'] u0 = List([0.014, 50000.]) eps_arr = Property(depends_on='+input') @cached_property def _get_tex_arr(self): return np.hstack( [0., self.eps_el_fraction * self.eps_tex_u, self.eps_tex_u]) sig_arr = Property(depends_on='+input') @cached_property def _get_sig_arr(self): return np.hstack([0., self.var_a * self.sig_tex_u, self.sig_tex_u])
class LS(HasTraits): '''Limit state class ''' # backward link to the info shell to access the # input data when calculating # the limit-state-specific values # ls_table = WeakRef # parameters of the limit state # dir = Enum(DIRLIST) stress_res = Enum(SRLIST) #------------------------------- # ls columns #------------------------------- # defined in the subclasses # ls_columns = List show_ls_columns = Bool(True) #------------------------------- # sr columns #------------------------------- # stress resultant columns - for ULS this is defined in the subclasses # sr_columns = List(['m', 'n']) show_sr_columns = Bool(True) # stress resultant columns - generated from the parameter combination # dir and stress_res - one of MX, NX, MY, NY # m_varname = Property(Str) def _get_m_varname(self): # e.g. mx_N appendix = self.dir + '_' + self.stress_res return 'm' + appendix n_varname = Property(Str) def _get_n_varname(self): # e.g. nx_N appendix = self.dir + '_' + self.stress_res return 'n' + appendix n = Property(Float) def _get_n(self): return getattr(self.ls_table, self.n_varname) m = Property(Float) def _get_m(self): return getattr(self.ls_table, self.m_varname) #------------------------------- # geo columns form info shell #------------------------------- geo_columns = List(['elem_no', 'X', 'Y', 'Z', 'D_elem']) show_geo_columns = Bool(True) elem_no = Property(Float) def _get_elem_no(self): return self.ls_table.elem_no X = Property(Float) def _get_X(self): return self.ls_table.X Y = Property(Float) def _get_Y(self): return self.ls_table.Y Z = Property(Float) def _get_Z(self): return self.ls_table.Z D_elem = Property(Float) def _get_D_elem(self): return self.ls_table.D_elem #------------------------------- # state columns form info shell #------------------------------- # state_columns = List( ['mx', 'my', 'mxy', 'nx', 'ny', 'nxy' ] ) state_columns = List([ 'mx', 'my', 'mxy', 'nx', 'ny', 'nxy', 'sigx_lo', 'sigy_lo', 'sigxy_lo', 'sig1_lo', 'sig2_lo', 'alpha_sig_lo', 'sigx_up', 'sigy_up', 'sigxy_up', 'sig1_up', 'sig2_up', 'alpha_sig_up', ]) show_state_columns = Bool(True) mx = Property(Float) def _get_mx(self): return self.ls_table.mx my = Property(Float) def _get_my(self): return self.ls_table.my mxy = Property(Float) def _get_mxy(self): return self.ls_table.mxy nx = Property(Float) def _get_nx(self): return self.ls_table.nx ny = Property(Float) def _get_ny(self): return self.ls_table.ny nxy = Property(Float) def _get_nxy(self): return self.ls_table.nxy # evaluate principal stresses # upper face: # sigx_up = Property(Float) def _get_sigx_up(self): return self.ls_table.sigx_up sigy_up = Property(Float) def _get_sigy_up(self): return self.ls_table.sigy_up sigxy_up = Property(Float) def _get_sigxy_up(self): return self.ls_table.sigxy_up sig1_up = Property(Float) def _get_sig1_up(self): return self.ls_table.sig1_up sig2_up = Property(Float) def _get_sig2_up(self): return self.ls_table.sig2_up alpha_sig_up = Property(Float) def _get_alpha_sig_up(self): return self.ls_table.alpha_sig_up # lower face: # sigx_lo = Property(Float) def _get_sigx_lo(self): return self.ls_table.sigx_lo sigy_lo = Property(Float) def _get_sigy_lo(self): return self.ls_table.sigy_lo sigxy_lo = Property(Float) def _get_sigxy_lo(self): return self.ls_table.sigxy_lo sig1_lo = Property(Float) def _get_sig1_lo(self): return self.ls_table.sig1_lo sig2_lo = Property(Float) def _get_sig2_lo(self): return self.ls_table.sig2_lo alpha_sig_lo = Property(Float) def _get_alpha_sig_lo(self): return self.ls_table.alpha_sig_lo #------------------------------- # ls table #------------------------------- # all columns associated with the limit state including the corresponding # stress resultants # columns = Property(List, depends_on='show_geo_columns, show_state_columns,\ show_sr_columns, show_ls_columns') @cached_property def _get_columns(self): columns = [] if self.show_geo_columns: columns += self.geo_columns if self.show_state_columns: columns += self.state_columns if self.show_sr_columns: columns += self.sr_columns if self.show_ls_columns: columns += self.ls_columns return columns # select column used for sorting the data in selected sorting order # sort_column = Enum(values='columns') def _sort_column_default(self): return self.columns[-1] sort_order = Enum('descending', 'ascending', 'unsorted') #------------------------------------------------------- # get the maximum value of the selected variable # 'max_in_column' of the current sheet (only one sheet) #------------------------------------------------------- # get the maximum value of the chosen column # max_in_column = Enum(values='columns') def _max_in_column_default(self): return self.columns[-1] max_value = Property(depends_on='max_in_column') def _get_max_value(self): col = getattr(self, self.max_in_column)[:, 0] return max(col) #------------------------------------------------------- # get the maximum value and the corresponding case of # the selected variable 'max_in_column' in all (!) sheets #------------------------------------------------------- max_value_all = Property(depends_on='max_in_column') def _get_max_value_all(self): return self.ls_table.max_value_and_case[ self.max_in_column]['max_value'] max_case = Property(depends_on='max_in_column') def _get_max_case(self): return self.ls_table.max_value_and_case[self.max_in_column]['max_case'] #------------------------------------------------------- # get ls_table for View #------------------------------------------------------- # stack columns together for table used by TabularEditor # ls_array = Property( Array, depends_on='sort_column, sort_order, show_geo_columns, \ show_state_columns, show_sr_columns, show_ls_columns' ) @cached_property def _get_ls_array(self): arr_list = [getattr(self, col) for col in self.columns] # get the array currently selected by the sort_column enumeration # sort_arr = getattr(self, self.sort_column)[:, 0] sort_idx = argsort(sort_arr) ls_array = hstack(arr_list) if self.sort_order == 'descending': return ls_array[sort_idx[::-1]] if self.sort_order == 'ascending': return ls_array[sort_idx] if self.sort_order == 'unsorted': return ls_array #--------------------------------- # plot outputs in mlab-window #--------------------------------- plot_column = Enum(values='columns') plot = Button def _plot_fired(self): X = self.ls_table.X[:, 0] Y = self.ls_table.Y[:, 0] Z = self.ls_table.Z[:, 0] plot_col = getattr(self, self.plot_column)[:, 0] if self.plot_column == 'n_tex': plot_col = where(plot_col < 0, 0, plot_col) mlab.figure(figure="SFB532Demo", bgcolor=(1.0, 1.0, 1.0), fgcolor=(0.0, 0.0, 0.0)) mlab.points3d( X, Y, (-1.0) * Z, plot_col, # colormap = "gist_rainbow", # colormap = "Reds", colormap="YlOrBr", mode="cube", scale_factor=0.15) mlab.scalarbar(title=self.plot_column, orientation='vertical') mlab.show # name of the trait that is used to assess the evaluated design # assess_name = Str('') #------------------------------- # ls group #------------------------------- # @todo: the dynamic selection of the columns to be displayed # does not work in connection with the LSArrayAdapter ls_group = VGroup( HGroup( #Item( 'assess_name' ), Item('max_in_column'), Item('max_value', style='readonly', format_str='%6.2f'), Item('max_value_all', style='readonly', format_str='%6.2f'), Item('max_case', style='readonly', label='found in case: '), ), HGroup( Item('sort_column'), Item('sort_order'), Item('show_geo_columns', label='show geo'), Item('show_state_columns', label='show state'), Item('show_sr_columns', label='show sr'), Item('plot_column'), Item('plot'), ), )
class Randomization( HasTraits ): '''Multidimensional statistical integration. Its name SPIRRID is an acronym for Set of Parallel Independent Random Responses with Identical Distributions The package implements the evaluation of an integral over a set of random variables affecting a response function RF and distributed according to a probabilistic distribution PDistrib. The input parameters are devided in four categories in order to define state consistency of the evaluation. The outputs are define as cached properties that are reevaluated in response to changes in the inputs. The following events accummulate changes in the input parameters of spirrid: rf_change - change in the response function rand_change - change in the randomization conf_change - change in the configuration of the algorithm eps_change - change in the studied range of the process control variable ''' #-------------------------------------------------------------------- # Response function #-------------------------------------------------------------------- # rf = Instance( IRF ) def _rf_changed( self ): self.on_trait_change( self._set_rf_change, 'rf.changed' ) #-------------------------------------------------------------------- # Specification of random parameters #-------------------------------------------------------------------- # rv_list = Property( List( RandomVariable ), depends_on = 'rf_change' ) @cached_property def _get_rv_list( self ): rf = self.rf param_tuple = zip( rf.param_keys, rf.param_values, rf.param_traits ) return [ RandomVariable( spirrid = self, rf = self.rf, name = nm, trait_value = tv, source_trait = st ) for nm, tv, st in param_tuple ] # key-based access to the random variables rv_dict = Property( Dict, depends_on = 'rf_change' ) @cached_property def _get_rv_dict( self ): d = {} for rv in self.rv_list: d[rv.name] = rv return d def set_random( self, variable, distribution = 'uniform', discr_type = 'T grid', loc = 0., scale = 1., shape = 1., n_int = 30 ): '''Declare a variable as random ''' self.rv_dict[ variable ].set_random( distribution, discr_type, loc, scale, shape, n_int ) def unset_random( self, variable ): '''Delete declaration of random variable ''' self.rv_dict[ variable ].unset_random() def unset_all_random( self ): '''Set all variables to detereministic''' map( lambda rv: rv.unset_random, self.rv_list ) n_rv = Property( depends_on = 'rnd_change' ) @cached_property def _get_n_rv( self ): return self.rv_random_keys.size # subsidiary methods for sorted access to the random variables. # (note dictionary has not defined order of its items) rv_random_keys = Property( List, depends_on = 'rf_change' ) @cached_property def _get_rv_random_keys( self ): random_pattern = array( [ rv.random for rv in self.rv_list ], dtype = bool ) ridx = where( random_pattern == True )[0] return self.rv_keys[ ridx ] # subsidiary methods for sorted access to the random variables. # (note dictionary has not defined order of its items) rv_keys = Property( List, depends_on = 'rf_change' ) @cached_property def _get_rv_keys( self ): return array( self.rf.param_keys ) #-------------------------------------------------------------------- # Define which changes in the response function and in the # statistical parameters are relevant for reevaluation of the response #-------------------------------------------------------------------- rf_change = Event @on_trait_change( 'rf.changed' ) def _set_rf_change( self ): self.rf_change = True rand_change = Event @on_trait_change( 'rv_list, rv_list.changed' ) def _set_rand_change( self ): self.rand_change = True conf_change = Event @on_trait_change( '+alg_option' ) def _set_conf_change( self ): self.conf_change = True eps_change = Event @on_trait_change( '+eps_range' ) def _set_eps_change( self ): self.eps_change = True # List of discretized statistical domains # theta_arr_list = Property( depends_on = 'rf_change, rand_change' ) @cached_property def _get_theta_arr_list( self ): '''Get list of arrays with discretized RandomVariables. ''' return [ rv.theta_arr for rv in self.rv_list ] # Discretized statistical domain # theta_ogrid = Property( depends_on = 'rf_change, rand_change' ) @cached_property def _get_theta_ogrid( self ): '''Get orthogonal list of arrays with discretized RandomVariables. ''' return orthogonalize( self.theta_arr_list ) #--------------------------------------------------------------------------------- # PDF * Theta arrays oriented in enumerated dimensions - broadcasting possible #--------------------------------------------------------------------------------- dG_ogrid = Property( depends_on = 'rf_change, rand_change' ) @cached_property def _get_dG_ogrid( self ): '''Get orthogonal list of arrays with PDF * Theta product of. ''' dG_arr_list = [ rv.dG_arr for rv in self.rv_list ] return orthogonalize( dG_arr_list ) #--------------------------------------------------------------------------------- # PDF grid - mutually multiplied arrays of PDF #--------------------------------------------------------------------------------- dG_grid = Property( depends_on = 'rf_change, rand_change' ) @cached_property def _get_dG_grid( self ): if len( self.dG_ogrid ): return reduce( lambda x, y: x * y, self.dG_ogrid ) else: return 1.0
class RunTable(SimDBClass): '''Manage the combinations of exec configurations and randomization patterns. ''' name = Str(simdb=True) memsize = Float(1e4, simdb=True) s = Property(Instance(SPIRRID), depends_on='rf') @cached_property def _get_s(self): return SPIRRID(rf=self.rf, min_eps=0.00, max_eps=1.0, n_eps=20, compiler_verbose=0) rf = Instance(IRF, simdb=True) config_list = List(config=True) def _config_list_default(self): return ['I', 'IV'] config_dict = Property(depends_on='config_list') @cached_property def _get_config_dict(self): cd = {} for config_idx in self.config_list: cd[config_idx] = config_dict[config_idx] return cd rand_list = List(rand=True) run_arr = Property(Array, depends_on='+rand,+config') @cached_property def _get_run_arr(self): # generate the runs to be performed run_table = [[ SingleRun(run_table=self, config=config, rand_idx_arr=rand_idx_arr) for rand_idx_arr in self.rand_list ] for config in self.config_dict.items()] return array(run_table) exec_time_arr = Array n_int_arr = Array real_memsize_arr = Array calculate = Button() def _calculate_fired(self): s = self.run_arr.shape self.exec_time_arr = array( [run.exec_time for run in self.run_arr.flatten()]).reshape(s) self.n_int_arr = array([run.n_int for run in self.run_arr.flatten()]).reshape(s) self.real_memsize_arr = array( [run.real_memsize for run in self.run_arr.flatten()]).reshape(s) self.save() self._redraw_fired() clear = Button() def _clear_fired(self): figure = self.figure figure.clear() self.data_changed = True figure = Instance(Figure, transient=True) def _figure_default(self): figure = Figure(facecolor='white') #figure.add_axes( [0.08, 0.13, 0.85, 0.74] ) return figure data_changed = Event(True) normalized_numpy = Bool(True) c_code = Bool(False) redraw = Button() def _redraw_fired(self): figure = self.figure axes = figure.gca() self.plot(axes) self.data_changed = True redraw_in_window = Button() def _redraw_in_window_fired(self): figure = plt.figure(0) axes = figure.gca() self.plot(axes) plt.show() def plot(self, ax): exec_time_arr = self.exec_time_arr n_int_arr = self.n_int_arr[0, :] real_memsize_arr = self.real_memsize_arr[0, :] rand_arr = arange(len(self.rand_list)) + 1 width = 0.45 if exec_time_arr.shape[0] == 1: shift = width / 2.0 ax.bar(rand_arr - shift, exec_time_arr[0, :], width, color='lightgrey') elif self.exec_time_arr.shape[0] == 2: max_exec_time = nmax(exec_time_arr) ax.set_ylabel('$\mathrm{execution \, time \, [sec]}$', size=20) ax.set_xlabel( '$n_{\mathrm{rnd}} \;-\; \mathrm{number \, of \, random \, parameters}$', size=20) ax.bar(rand_arr - width, exec_time_arr[0, :], width, hatch='/', color='white', label='C') # , color = 'lightgrey' ) ax.bar(rand_arr, exec_time_arr[1, :], width, color='lightgrey', label='numpy') yscale = 1.25 ax_xlim = rand_arr[-1] + 1 ax_ylim = max_exec_time * yscale ax.set_xlim(0, ax_xlim) ax.set_ylim(0, ax_ylim) ax2 = ax.twinx() ydata = exec_time_arr[1, :] / exec_time_arr[0, :] ax2.plot(rand_arr, ydata, '-o', color='black', linewidth=1, label='numpy/C') ax2.plot([rand_arr[0] - 1, rand_arr[-1] + 1], [1, 1], '-') ax2.set_ylabel( '$\mathrm{time}( \mathsf{numpy} ) / \mathrm{ time }(\mathsf{C}) \; [-]$', size=20) ax2_ylim = nmax(ydata) * yscale ax2_xlim = rand_arr[-1] + 1 ax2.set_ylim(0, ax2_ylim) ax2.set_xlim(0, ax2_xlim) ax.set_xticks(rand_arr) ax.set_xticklabels(rand_arr, size=14) xticks = ['%.2g' % n_int for n_int in n_int_arr] ax3 = ax.twiny() ax3.set_xlim(0, rand_arr[-1] + 1) ax3.set_xticks(rand_arr) ax3.set_xlabel('$n_{\mathrm{int}}$', size=20) ax3.set_xticklabels(xticks, rotation=30) 'set the tick label size of the lower X axis' X_lower_tick = 14 xt = ax.get_xticklabels() for t in xt: t.set_fontsize(X_lower_tick) 'set the tick label size of the upper X axis' X_upper_tick = 12 xt = ax3.get_xticklabels() for t in xt: t.set_fontsize(X_upper_tick) 'set the tick label size of the Y axes' Y_tick = 14 yt = ax2.get_yticklabels() + ax.get_yticklabels() for t in yt: t.set_fontsize(Y_tick) 'set the legend position and font size' leg_fontsize = 16 leg = ax.legend(loc=(0.02, 0.83)) for t in leg.get_texts(): t.set_fontsize(leg_fontsize) leg = ax2.legend(loc=(0.705, 0.90)) for t in leg.get_texts(): t.set_fontsize(leg_fontsize) traits_view = View(Item('name'), Item('memsize'), Item('rf'), Item('config_dict'), Item('rand_list'), HGroup( Item('calculate', show_label=False), Item('redraw', show_label=False), Item('clear', show_label=False), Item('redraw_in_window', show_label=False), ), Item('figure', editor=MPLFigureEditor(), resizable=True, show_label=False), buttons=['OK', 'Cancel'])
class ECBCrossSection(ECBCrossSectionState): '''Cross section characteristics needed for tensile specimens ''' matrix_cs = Instance(ECBMatrixCrossSection) def _matrix_cs_default(self): return ECBMatrixCrossSection() reinf = List(ECBReinfComponent) '''Components of the cross section including the matrix and reinforcement. ''' matrix_cs_with_state = Property(depends_on='matrix_cs') @cached_property def _get_matrix_cs_with_state(self): self.matrix_cs.state = self return self.matrix_cs reinf_components_with_state = Property(depends_on='reinf') '''Components linked to the strain state of the cross section ''' @cached_property def _get_reinf_components_with_state(self): for r in self.reinf: r.state = self r.matrix_cs = self.matrix_cs return self.reinf height = DelegatesTo('matrix_cs') unit_conversion_factor = Constant(1000.0) '''Convert the MN to kN ''' #=========================================================================== # State management #=========================================================================== changed = Event '''Notifier of a changed in some component of a cross section ''' @on_trait_change('+eps_input') def _notify_eps_change(self): self.changed = True self.matrix_cs.eps_changed = True for c in self.reinf: c.eps_changed = True #=========================================================================== # Cross-sectional stress resultants #=========================================================================== N = Property(depends_on='changed') '''Get the resulting normal force. ''' @cached_property def _get_N(self): N_matrix = self.matrix_cs_with_state.N return N_matrix + np.sum([c.N for c in self.reinf_components_with_state]) M = Property(depends_on='changed') '''Get the resulting moment. ''' @cached_property def _get_M(self): M_matrix = self.matrix_cs_with_state.M M = M_matrix + np.sum([c.M for c in self.reinf_components_with_state]) return M - self.N * self.height / 2. figure = Instance(Figure) def _figure_default(self): figure = Figure(facecolor='white') figure.add_axes([0.08, 0.13, 0.85, 0.74]) return figure data_changed = Event replot = Button def _replot_fired(self): self.figure.clear() ax = self.figure.add_subplot(2, 2, 1) self.plot_eps(ax) ax = self.figure.add_subplot(2, 2, 2) self.plot_sig(ax) ax = self.figure.add_subplot(2, 2, 3) self.cc_law.plot(ax) ax = self.figure.add_subplot(2, 2, 4) self.ecb_law.plot(ax) self.data_changed = True def plot_eps(self, ax): # ax = self.figure.gca() d = self.thickness # eps ti ax.plot([-self.eps_lo, -self.eps_up], [0, self.thickness], color='black') ax.hlines(self.zz_ti_arr, [0], -self.eps_ti_arr, lw=4, color='red') # eps cj ec = np.hstack([self.eps_cj_arr] + [0, 0]) zz = np.hstack([self.zz_cj_arr] + [0, self.thickness ]) ax.fill(-ec, zz, color='blue') # reinforcement layers eps_range = np.array([max(0.0, self.eps_lo), min(0.0, self.eps_up)], dtype='float') z_ti_arr = np.ones_like(eps_range)[:, None] * self.z_ti_arr[None, :] ax.plot(-eps_range, z_ti_arr, 'k--', color='black') # neutral axis ax.plot(-eps_range, [d, d], 'k--', color='green', lw=2) ax.spines['left'].set_position('zero') ax.spines['right'].set_color('none') ax.spines['top'].set_color('none') ax.spines['left'].set_smart_bounds(True) ax.spines['bottom'].set_smart_bounds(True) ax.xaxis.set_ticks_position('bottom') ax.yaxis.set_ticks_position('left') def plot_sig(self, ax): d = self.thickness # f ti ax.hlines(self.zz_ti_arr, [0], -self.f_ti_arr, lw=4, color='red') # f cj f_c = np.hstack([self.f_cj_arr] + [0, 0]) zz = np.hstack([self.zz_cj_arr] + [0, self.thickness ]) ax.fill(-f_c, zz, color='blue') f_range = np.array([np.max(self.f_ti_arr), np.min(f_c)], dtype='float_') # neutral axis ax.plot(-f_range, [d, d], 'k--', color='green', lw=2) ax.spines['left'].set_position('zero') ax.spines['right'].set_color('none') ax.spines['top'].set_color('none') ax.spines['left'].set_smart_bounds(True) ax.spines['bottom'].set_smart_bounds(True) ax.xaxis.set_ticks_position('bottom') ax.yaxis.set_ticks_position('left') view = View(HSplit(Group( HGroup( Group(Item('thickness', springy=True), Item('width'), Item('n_layers'), Item('n_rovings'), Item('A_roving'), label='Geometry', springy=True ), Group(Item('eps_up', label='Upper strain', springy=True), Item('eps_lo', label='Lower strain'), label='Strain', springy=True ), springy=True, ), HGroup( Group(VGroup( Item('cc_law_type', show_label=False, springy=True), Item('cc_law', label='Edit', show_label=False, springy=True), Item('show_cc_law', label='Show', show_label=False, springy=True), springy=True ), Item('f_ck', label='Compressive strength'), Item('n_cj', label='Discretization'), label='Concrete', springy=True ), Group(VGroup( Item('ecb_law_type', show_label=False, springy=True), Item('ecb_law', label='Edit', show_label=False, springy=True), Item('show_ecb_law', label='Show', show_label=False, springy=True), springy=True, ), label='Reinforcement', springy=True ), springy=True, ), Group(Item('s_tex_z', label='vertical spacing', style='readonly'), label='Layout', ), Group( HGroup(Item('M', springy=True, style='readonly'), Item('N', springy=True, style='readonly'), ), label='Stress resultants' ), scrollable=True, ), Group(Item('replot', show_label=False), Item('figure', editor=MPLFigureEditor(), resizable=True, show_label=False), id='simexdb.plot_sheet', label='plot sheet', dock='tab', ), ), width=0.8, height=0.7, resizable=True, buttons=['OK', 'Cancel'])
class ECBLBase(CLBase): '''Base class for Effective Crack Bridge Laws.''' u0 = List([0.0, 0.0])
class Solver(HasTraits): title = Str('solver') solver_components = List()
class CompositeCrackBridgeLoop(HasTraits): reinforcement_lst = List(Instance(Reinforcement)) w = Float E_m = Float Ll = Float Lr = Float V_f_tot = Property(depends_on='reinforcement_lst+') @cached_property def _get_V_f_tot(self): V_f_tot = 0.0 for reinf in self.reinforcement_lst: V_f_tot += reinf.V_f return V_f_tot E_c = Property(depends_on='reinforcement_lst+') @cached_property def _get_E_c(self): E_fibers = 0.0 for reinf in self.reinforcement_lst: E_fibers += reinf.V_f * reinf.E_f return self.E_m * (1. - self.V_f_tot) + E_fibers sorted_theta = Property(depends_on='reinforcement_lst+') @cached_property def _get_sorted_theta(self): '''sorts the integral points by bond in descending order''' depsf_arr = np.array([]) V_f_arr = np.array([]) E_f_arr = np.array([]) xi_arr = np.array([]) stat_weights_arr = np.array([]) nu_r_arr = np.array([]) for reinf in self.reinforcement_lst: n_int = len(np.hstack((np.array([]), reinf.depsf_arr))) depsf_arr = np.hstack((depsf_arr, reinf.depsf_arr)) V_f_arr = np.hstack((V_f_arr, np.repeat(reinf.V_f, n_int))) E_f_arr = np.hstack((E_f_arr, np.repeat(reinf.E_f, n_int))) xi_arr = np.hstack((xi_arr, np.repeat(reinf.xi, n_int))) stat_weights_arr = np.hstack( (stat_weights_arr, np.repeat(reinf.stat_weights, n_int))) nu_r_arr = np.hstack((nu_r_arr, reinf.nu_r)) argsort = np.argsort(depsf_arr)[::-1] return depsf_arr[argsort], V_f_arr[argsort], E_f_arr[argsort], \ xi_arr[argsort], stat_weights_arr[argsort], \ nu_r_arr[argsort] sorted_depsf = Property(depends_on='reinforcement_lst+') @cached_property def _get_sorted_depsf(self): return self.sorted_theta[0] sorted_V_f = Property(depends_on='reinforcement_lst+') @cached_property def _get_sorted_V_f(self): return self.sorted_theta[1] sorted_E_f = Property(depends_on='reinforcement_lst+') @cached_property def _get_sorted_E_f(self): return self.sorted_theta[2] sorted_xi = Property(depends_on='reinforcement_lst+') @cached_property def _get_sorted_xi(self): return self.sorted_theta[3] sorted_stats_weights = Property(depends_on='reinforcement_lst+') @cached_property def _get_sorted_stats_weights(self): return self.sorted_theta[4] sorted_nu_r = Property(depends_on='reinforcement_lst+') @cached_property def _get_sorted_nu_r(self): return self.sorted_theta[5] sorted_xi_cdf = Property(depends_on='reinforcement_lst+') @cached_property def _get_sorted_xi_cdf(self): '''breaking strain: CDF for random and Heaviside for discrete values''' # TODO: does not work for reinforcement types with the same xi methods = [] masks = [] for reinf in self.reinforcement_lst: masks.append(self.sorted_xi == reinf.xi) if isinstance(reinf.xi, FloatType): methods.append(lambda x: 1.0 * (reinf.xi <= x)) elif isinstance(reinf.xi, RV): methods.append(reinf.xi._distr.cdf) elif isinstance(reinf.xi, WeibullFibers): methods.append(reinf.xi.weibull_fibers_Pf) return methods, masks def vect_xi_cdf(self, epsy, x_short, x_long): Pf = np.zeros_like(self.sorted_depsf) methods, masks = self.sorted_xi_cdf for i, method in enumerate(methods): if method.__name__ == 'weibull_fibers_Pf': Pf += method(epsy * masks[i], self.sorted_depsf, x_short=x_short, x_long=x_long) else: Pf += method(epsy * masks[i]) return Pf def dem_depsf(self, depsf, damage): '''evaluates the deps_m given deps_f at that point and the damage array''' Kf = self.sorted_V_f * self.sorted_nu_r * \ self.sorted_stats_weights * self.sorted_E_f Kf_intact_bonded = np.sum(Kf * (depsf <= self.sorted_depsf) * (1. - damage)) Kf_broken = np.sum(Kf * damage) Kf_add = Kf_intact_bonded + Kf_broken Km = (1. - self.V_f_tot) * self.E_m E_mtrx = Km + Kf_add mean_acting_T = np.sum(self.sorted_depsf * (self.sorted_depsf < depsf) * Kf * (1. - damage)) return mean_acting_T / E_mtrx def double_sided(self, defi, x0, demi, em0, um0, damage): dxi = (-defi * x0 - demi * x0 + (defi * x0**2 * demi + demi**2 * x0**2 - 2 * defi * em0 * x0 + 2 * defi * um0 + defi * self.w - 2 * demi * em0 * x0 + 2 * demi * um0 + demi * self.w)**(.5)) / (defi + demi) dem = self.dem_depsf(defi, damage) emi = em0 + demi * dxi umi = um0 + (em0 + emi) * dxi / 2. return dxi, dem, emi, umi def one_sided(self, defi, x0, demi, em0, um0, clamped, damage): w = self.w xs = clamped[0] ums = clamped[1] dxi = (-xs * demi - demi * x0 - defi * xs - defi * x0 + (2 * demi * x0 * defi * xs + demi * x0**2 * defi + 2 * demi**2 * x0 * xs + 3 * defi * xs**2 * demi - 2 * demi * xs * em0 - 2 * demi * em0 * x0 - 2 * defi * xs * em0 - 2 * defi * em0 * x0 + demi**2 * x0**2 + 2 * defi**2 * xs**2 + xs**2 * demi**2 + 2 * demi * um0 + 2 * demi * ums + 2 * demi * w + 2 * defi * um0 + 2 * defi * ums + 2 * defi * w)**(0.5)) / (demi + defi) dem = self.dem_depsf(defi, damage) emi = em0 + demi * dxi umi = um0 + (em0 + emi) * dxi / 2. return dxi, dem, emi, umi def clamped(self, defi, xs, xl, ems, eml, ums, uml): c1 = eml * xl - uml c2 = ems * xs - ums c3 = defi * xl**2 / 2. c4 = defi * xs**2 / 2. c5 = (defi * (xl - xs) + (eml - ems)) * xs h = (self.w - c1 - c2 - c3 - c4 - c5) / (xl + xs) return defi * xl + eml + h def damage_residuum(self, iter_damage): um_short, em_short, x_short = [0.0], [0.0], [0.0] um_long, em_long, x_long = [0.0], [0.0], [0.0] init_dem = self.dem_depsf(np.infty, iter_damage) dem_short = [init_dem] dem_long = [init_dem] epsf0 = np.zeros_like(self.sorted_depsf) Lmin = min(self.Ll, self.Lr) Lmax = max(self.Ll, self.Lr) for i, defi in enumerate(self.sorted_depsf): if x_short[-1] < Lmin and x_long[-1] < Lmax: '''double sided pullout''' dxi, dem, emi, umi = self.double_sided(defi, x_short[-1], dem_short[-1], em_short[-1], um_short[-1], iter_damage) if x_short[-1] + dxi < Lmin: # dx increment does not reach the boundary dem_short.append(dem) dem_long.append(dem) x_short.append(x_short[-1] + dxi) x_long.append(x_long[-1] + dxi) em_short.append(emi) em_long.append(emi) um_short.append(umi) um_long.append(umi) epsf0[i] = (em_short[-1] + x_short[-1] * defi) else: # boundary reached at shorter side deltax = Lmin - x_short[-1] x_short.append(Lmin) em_short.append(em_short[-1] + dem_short[-1] * deltax) um_short.append(um_short[-1] + (em_short[-2] + em_short[-1]) * deltax / 2.) short_side = [x_short[-1], um_short[-1]] dxi, dem, emi, umi = self.one_sided( defi, x_long[-1], dem_long[-1], em_long[-1], um_long[-1], short_side, iter_damage) if x_long[-1] + dxi >= Lmax: # boundary reached at longer side deltax = Lmax - x_long[-1] x_long.append(Lmax) em_long.append(em_long[-1] + dem_long[-1] * deltax) um_long.append(um_long[-1] + (em_long[-2] + em_long[-1]) * deltax / 2.) epsf0_clamped = self.clamped(defi, x_short[-1], x_long[-1], em_short[-1], em_long[-1], um_short[-1], um_long[-1]) epsf0[i] = epsf0_clamped else: dem_long.append(dem) x_long.append(x_long[-1] + dxi) em_long.append(emi) um_long.append(umi) epsf0[i] = (em_long[-1] + x_long[-1] * defi) elif x_short[-1] == Lmin and x_long[-1] < Lmax: #one sided pullout clamped = [x_short[-1], um_short[-1]] dxi, dem, emi, umi = self.one_sided(defi, x_long[-1], dem_long[-1], em_long[-1], um_long[-1], clamped, iter_damage) if x_long[-1] + dxi < Lmax: dem_long.append(dem) x_long.append(x_long[-1] + dxi) em_long.append(emi) um_long.append(umi) epsf0[i] = (em_long[-1] + x_long[-1] * defi) else: dxi = Lmax - x_long[-1] x_long.append(Lmax) em_long.append(em_long[-1] + dem_long[-1] * dxi) um_long.append(um_long[-1] + (em_long[-2] + em_long[-1]) * dxi / 2.) epsf0_clamped = self.clamped(defi, x_short[-1], x_long[-1], em_short[-1], em_long[-1], um_short[-1], um_long[-1]) epsf0[i] = epsf0_clamped elif x_short[-1] == Lmin and x_long[-1] == Lmax: #clamped fibers epsf0_clamped = self.clamped(defi, x_short[-1], x_long[-1], em_short[-1], em_long[-1], um_short[-1], um_long[-1]) epsf0[i] = epsf0_clamped self._x_arr = np.hstack( (-np.array(x_short)[::-1][:-1], np.array(x_long))) self._epsm_arr = np.hstack( (np.array(em_short)[::-1][:-1], np.array(em_long))) self._epsf0_arr = epsf0 residuum = self.vect_xi_cdf(epsf0, x_short=x_short, x_long=x_long) - iter_damage return residuum _x_arr = Array def __x_arr_default(self): return np.repeat(1e-10, len(self.sorted_depsf)) _epsm_arr = Array def __epsm_arr_default(self): return np.repeat(1e-10, len(self.sorted_depsf)) _epsf0_arr = Array def __epsf0_arr_default(self): return np.repeat(1e-10, len(self.sorted_depsf)) damage = Property(depends_on='w, Ll, Lr, reinforcement+') @cached_property def _get_damage(self): ff = time.clock() if self.w == 0.: damage = np.zeros_like(self.sorted_depsf) else: ff = t.clock() try: damage = broyden2(self.damage_residuum, 0.2 * np.ones_like(self.sorted_depsf), maxiter=20) except: print 'broyden2 does not converge fast enough: switched to fsolve for this step' damage = fsolve(self.damage_residuum, 0.2 * np.ones_like(self.sorted_depsf)) print 'damage =', np.sum(damage) / len( damage), 'iteration time =', time.clock() - ff, 'sec' return damage
class ULS(LS): '''Ultimate limit state ''' #-------------------------------------------------------- # ULS: material parameters (Inputs) #-------------------------------------------------------- # gamma-factor gamma = Float(1.5, input=True) # long term reduction factor beta = Float(1.0, input=True) # INDEX l: longitudinal direction of the textile (MAG-02-02-06a) # characteristic tensile strength of the tensile specimen [N/mm2] f_tk_l = Float(537, input=True) # design value of the tensile strength of the tensile specimen [N/mm2] # containing a gamma-factor of 1.5 and d long term reduction factor of 0.7 # f_td_l = 251 f_td_l = Property(Float, depends_on='+input') def _get_f_td_l(self): return self.beta * self.f_tk_l / self.gamma # cross sectional area of the reinforcement [mm2/m] a_t_l = Float(71.65, input=True) # INDEX q: orthogonal direction of the textile (MAG-02-02-06a) # characteristic tensile strength of the tensile specimen [N/mm2] f_tk_q = Float(511, input=True) # design value of the tensile strength of the tensile specimen [kN/m] # f_td_q = 238 f_td_q = Property(Float, depends_on='+input') def _get_f_td_q(self): return self.beta * self.f_tk_q / self.gamma # cross sectional area of the reinforcement [mm2/m] a_t_q = Float(53.31, input=True) # tensile strength of the textile reinforcement [kN/m] f_Rtex_l = Property(Float, depends_on='+input') def _get_f_Rtex_l(self): return self.a_t_l * self.f_td_l / 1000. # tensile strength of the textile reinforcement [kN/m] f_Rtex_q = Property(Float) def _get_f_Rtex_q(self, depends_on='+input'): return self.a_t_q * self.f_td_q / 1000. # tensile strength of the textile reinforcement [kN/m] # as simplification the lower value of 0- and 90-direction is taken # # sig_composite,exp = 103.4 kN/14cm/6cm = 12.3 MPa # f_tex,exp = 103.4 kN/14cm/12layers = 61.5 kN/m # f_tex,k = f_tex,exp * 0,81 (EN-DIN 1990) = 0.82*61.5 kN/m = 50.4 kN/m # f_tex,d = f_tex,k / 1,5 = 33.6 kN/m # f_Rtex_l = f_Rtex_q = 34.3 print 'NOTE: f_Rtex_l = f_Rtex_q = set to %g kN/m !' % (f_Rtex_l) k_fl = 7.95 / 6.87 print 'NOTE: k_fl = set to %g [-] !' % (k_fl) # ------------------------------------------------------------ # ULS - derived params: # ------------------------------------------------------------ # Parameters for the cracked state (GdT): # assumptions! # (resultierende statische Nutzhoehe) # d = Property(Float) def _get_d(self): return 0.75 * self.ls_table.D_elem # (Abstand Schwereachse zur resultierende Bewehrungslage) # chose the same amount of reinforcement at the top as at the bottom # i.e. zs = zs1 = zs2 # zs = Property(Float) def _get_zs(self): return self.d - self.ls_table.D_elem / 2. # (Innerer Hebelarm) # z = Property(Float) def _get_z(self): return 0.9 * self.d # ------------------------------------------------------------ # ULS: outputs # ------------------------------------------------------------ ls_columns = List([ 'e', 'm_Eds', 'f_t', 'f_t_sig', 'beta_l', 'beta_q', 'f_Rtex', 'k_fl_NM', 'n_tex' ]) sr_columns = ['m', 'n', 'alpha', 'd', 'zs', 'z'] alpha_varname = Property() def _get_alpha_varname(self): return 'alpha_' + self.stress_res alpha = Property def _get_alpha(self): return getattr(self.ls_table, self.alpha_varname) ls_values = Property(depends_on='+input') @cached_property def _get_ls_values(self): '''get the outputs for ULS ''' #------------------------------------------------- # VAR 1:use simplified reinforced concrete approach #------------------------------------------------- n = self.n m = self.m alpha = self.alpha zs = self.zs z = self.z f_Rtex_l = self.f_Rtex_l f_Rtex_q = self.f_Rtex_q # (Exzentrizitaet) e = abs(m / n) e[n == 0] = 1E9 # if normal force is zero set e to very large value # moment at the height of the resulting reinforcement layer: m_Eds = abs(m) - zs * n # tensile force in the reinforcement for bending and compression f_t = m_Eds / z + n # check if the two conditions are true: cond1 = n > 0 cond2 = e < zs bool_arr = cond1 * cond2 # in case of pure tension in the cross section: f_t[bool_arr] = n[bool_arr] * (zs[bool_arr] + e[bool_arr]) / ( zs[bool_arr] + zs[bool_arr]) #------------------------------------------------- # VAR 2:use principal stresses to calculate the resulting tensile force #------------------------------------------------- # princ_stress_eval = True # princ_stress_eval = False f_t_sig = self.sig1_lo * self.D_elem * 1000. if princ_stress_eval == True: print "NOTE: the principle tensile stresses are used to evaluate 'n_tex'" # resulting tensile force of the composite cross section[kN] # the entire (!) cross section is used! # as the maximum value of the tensile stresses at the top or the bottom # i.e. sig1_max = min( 0, max( self.sig1_up, self.sig1_lo ) ) #--------------------------------------------------------- # initialize arrays t be filled by case distinction: #--------------------------------------------------------- # f_t_sig = zeros_like(self.sig1_up) alpha = zeros_like(self.sig1_up) k_fl_NM = ones_like(self.sig1_up) # absolute value of the bending stress created by mx or my sig_b = (abs(self.sig1_lo) + abs(self.sig1_up)) / 2 #--------------------------------------------------------- # conditions for case distinction #--------------------------------------------------------- cond_t_up = self.sig1_up > 0. # compression stress upper side cond_t_lo = self.sig1_lo > 0. # compression stress lower side cond_u_gt_l = abs(self.sig1_up) > abs( self.sig1_lo ) # absolute value of upper stress greater then lower stress cond_l_gt_u = abs(self.sig1_lo) > abs( self.sig1_up ) # absolute value of lower stress greater then lower stress cond_u_eq_l = abs(self.sig1_up) == abs( self.sig1_lo ) # absolute values of upper stress equals lower stress cond_b = self.sig1_up * self.sig1_lo < 0 # bending case cond_u_gt_0 = self.sig1_up > 0 # value of upper stress greater then 0. cond_l_gt_0 = self.sig1_lo > 0 # value of lower stress greater then 0. cond_c_up = self.sig1_up < 0. # compression stress upper side cond_c_lo = self.sig1_lo < 0. # compression stress lower side #--------------------------------------------------------- # tension case: #--------------------------------------------------------- # sig_up > sig_lo bool_arr = cond_t_up * cond_t_lo * cond_u_gt_l alpha[bool_arr] = self.alpha_sig_up[bool_arr] k_fl_NM[bool_arr] = 1.0 f_t_sig[bool_arr] = self.sig1_up[bool_arr] * self.D_elem[ bool_arr] * 1000. # sig_lo > sig_up bool_arr = cond_t_up * cond_t_lo * cond_l_gt_u alpha[bool_arr] = self.alpha_sig_lo[bool_arr] k_fl_NM[bool_arr] = 1.0 f_t_sig[bool_arr] = self.sig1_lo[bool_arr] * self.D_elem[ bool_arr] * 1000. # sig_lo = sig_up bool_arr = cond_t_up * cond_t_lo * cond_u_eq_l alpha[bool_arr] = (self.alpha_sig_lo[bool_arr] + self.alpha_sig_up[bool_arr]) / 2. k_fl_NM[bool_arr] = 1.0 f_t_sig[bool_arr] = self.sig1_lo[bool_arr] * self.D_elem[ bool_arr] * 1000. #--------------------------------------------------------- # bending case (= different signs) #--------------------------------------------------------- # bending with tension at the lower side # AND sig_N > 0 (--> bending and tension; sig1_lo results from bending and tension) bool_arr = cond_b * cond_l_gt_0 * cond_l_gt_u alpha[bool_arr] = self.alpha_sig_lo[bool_arr] k_fl_NM[ bool_arr ] = 1.0 + ( self.k_fl - 1.0 ) * \ ( 1.0 - ( sig_b[ bool_arr ] - abs( self.sig1_up[ bool_arr] ) ) / self.sig1_lo[ bool_arr ] ) f_t_sig[bool_arr] = self.sig1_lo[bool_arr] * self.D_elem[ bool_arr] * 1000. / k_fl_NM[bool_arr] # bending with tension at the lower side # AND sig_N < 0 (--> bending and compression; sig1_lo results only from bending) bool_arr = cond_b * cond_l_gt_0 * cond_u_gt_l alpha[bool_arr] = self.alpha_sig_lo[bool_arr] k_fl_NM[bool_arr] = self.k_fl f_t_sig[bool_arr] = self.sig1_lo[bool_arr] * self.D_elem[ bool_arr] * 1000. / k_fl_NM[bool_arr] # bending with tension at the upper side # AND sig_N > 0 (--> bending and tension; sig1_up results from bending and tension) bool_arr = cond_b * cond_u_gt_0 * cond_u_gt_l alpha[bool_arr] = self.alpha_sig_up[bool_arr] k_fl_NM[ bool_arr ] = 1.0 + ( self.k_fl - 1.0 ) * \ ( 1.0 - ( sig_b[ bool_arr ] - abs( self.sig1_lo[ bool_arr] ) ) / self.sig1_up[ bool_arr ] ) f_t_sig[bool_arr] = self.sig1_up[bool_arr] * self.D_elem[ bool_arr] * 1000. / k_fl_NM[bool_arr] # bending with tension at the upper side # AND sig_N < 0 (--> bending and compression; sig1_up results only from bending) bool_arr = cond_b * cond_u_gt_0 * cond_l_gt_u alpha[bool_arr] = self.alpha_sig_up[bool_arr] k_fl_NM[bool_arr] = self.k_fl f_t_sig[bool_arr] = self.sig1_up[bool_arr] * self.D_elem[ bool_arr] * 1000. / k_fl_NM[bool_arr] #--------------------------------------------------------- # compression case: #--------------------------------------------------------- bool_arr = cond_c_up * cond_c_lo # deflection angle is of minor interest use this simplification alpha[bool_arr] = (self.alpha_sig_up[bool_arr] + self.alpha_sig_up[bool_arr]) / 2. f_t_sig[bool_arr] = 0. k_fl_NM[bool_arr] = 1.0 #------------------------------------------------------------ # get angel of deflection of the textile reinforcement #------------------------------------------------------------ # angel of deflection of the textile reinforcement for dimensioning in x-direction # distinguished between longitudinal (l) and transversal (q) direction # # ASSUMPTION: worst case angle used # # as first step use the worst case reduction due to deflection possible (at 55 degrees) # beta_l = 55. * pi / 180. * ones_like( alpha ) # beta_q = ( 90. - 55. ) * pi / 180. * ones_like( alpha ) # @todo: as second step use the value for an alternating layup (i.e. deflection angle) # @todo: get the correct formula for the demonstrator arrangement # i.e. the RFEM coordinate system orientation # print "NOTE: deflection angle is used to evaluate 'n_tex'" beta_l = 90 - abs(alpha) # [degree] beta_q = abs(alpha) # [degree] # resulting strength of the bi-directional textile considering the # deflection of the reinforcement in the loading direction: f_Rtex = f_Rtex_l * cos( beta_l * pi / 180. ) * ( 1 - beta_l / 90. ) + \ f_Rtex_q * cos( beta_q * pi / 180. ) * ( 1 - beta_q / 90. ) # f_Rtex= 11.65 kN/m corresponds to sig_Rtex = 585 MPa # # f_Rtex = 11.65 * ones_like( alpha ) # f_Rtex= 10.9 kN/m corresponds to sig_Rtex = 678 MPa # with 1/3*( 679 + 690 + 667 ) = 678 MPa # # f_Rtex = 10.9 * ones_like( alpha ) # f_Rtex = 10.00 kN/m corresponds to sig_Rtex = 610 MPa # # f_Rtex = 10.00 * ones_like( alpha ) # print 'NOTE: f_Rtex set to %g kN/m !' % ( f_Rtex[0] ) if princ_stress_eval == False: # necessary number of reinforcement layers n_tex = f_t / f_Rtex return { 'e': e, 'm_Eds': m_Eds, 'f_t': f_t, 'f_t_sig': f_t_sig, 'beta_l': beta_l, 'beta_q': beta_q, 'f_Rtex': f_Rtex, 'n_tex': n_tex } elif princ_stress_eval == True: # NOTE: as the entire (!) cross section is used to calculate 'f_tex_sig' # the number of layers is evaluated also directly for the entire (!) # cross section! # n_tex = f_t_sig / f_Rtex return { 'e': e, 'm_Eds': m_Eds, 'f_t': f_t, 'f_t_sig': f_t_sig, 'beta_l': beta_l, 'beta_q': beta_q, 'f_Rtex': f_Rtex, 'n_tex': n_tex, 'k_fl_NM': k_fl_NM } e = Property def _get_e(self): return self.ls_values['e'] m_Eds = Property def _get_m_Eds(self): return self.ls_values['m_Eds'] f_t = Property def _get_f_t(self): return self.ls_values['f_t'] f_t_sig = Property def _get_f_t_sig(self): return self.ls_values['f_t_sig'] beta_l = Property def _get_beta_l(self): return self.ls_values['beta_l'] beta_q = Property def _get_beta_q(self): return self.ls_values['beta_q'] f_Rtex = Property def _get_f_Rtex(self): return self.ls_values['f_Rtex'] k_fl_NM = Property def _get_k_fl_NM(self): return self.ls_values['k_fl_NM'] n_tex = Property def _get_n_tex(self): return self.ls_values['n_tex'] assess_name = 'max_n_tex' max_n_tex = Property(depends_on='+input') @cached_property def _get_max_n_tex(self): return ndmax(self.n_tex) # assess_name = 'max_sig1_up' # max_sig1_up = Property( depends_on = '+input' ) # @cached_property # def _get_max_sig1_up( self ): # return ndmax( self.sig1_up ) # assess_name = 'max_sig1_lo' # max_sig1_lo = Property( depends_on = '+input' ) # @cached_property # def _get_max_sig1_lo( self ): # return ndmax( self.sig1_lo ) #------------------------------- # ls view #------------------------------- # @todo: the dynamic selection of the columns to be displayed # does not work in connection with the LSArrayAdapter traits_view = View(VGroup( HGroup( VGroup(Item(name='gamma', label='safety factor material [-]: gamma '), Item(name='beta', label='reduction long term durability [-]: beta '), label='safety factors'), VGroup(Item(name='f_tk_l', label='characteristic strength textil [MPa]: f_tk_l ', format_str="%.1f"), Item(name='f_td_l', label='design strength textil [MPa]: f_td_l ', style='readonly', format_str="%.1f"), Item(name='a_t_l', label='cross sectional area textil [mm^2]: a_t_l ', style='readonly', format_str="%.1f"), Item(name='f_Rtex_l', label='design strength textil [kN/m]: f_Rtex_l ', style='readonly', format_str="%.0f"), label='material properties (longitudinal)'), VGroup(Item(name='f_tk_q', label='characteristic strength textil [MPa]: f_tk_q ', format_str="%.1f"), Item(name='f_td_q', label='design strength textil [MPa]: f_td_q ', style='readonly', format_str="%.1f"), Item(name='a_t_q', label='cross sectional area textil [mm^2]: a_t_q ', style='readonly', format_str="%.1f"), Item(name='f_Rtex_q', label='design strength textil [kN/m]: f_Rtex_q ', style='readonly', format_str="%.0f"), label='material Properties (transversal)'), ), VGroup( Include('ls_group'), Item('ls_array', show_label=False, editor=TabularEditor(adapter=LSArrayAdapter()))), ), resizable=True, scrollable=True, height=1000, width=1100)
class SLS(LS): '''Serviceability limit state ''' # ------------------------------------------------------------ # SLS: material parameters (Inputs) # ------------------------------------------------------------ # tensile strength [MPa] f_ctk = Float(4.0, input=True) # flexural tensile strength [MPa] f_m = Float(5.0, input=True) # ------------------------------------------------------------ # SLS - derived params: # ------------------------------------------------------------ # area # A = Property(Float) def _get_A(self): return self.ls_table.D_elem * 1. # moment of inertia # W = Property(Float) def _get_W(self): return 1. * self.ls_table.D_elem**2 / 6. # ------------------------------------------------------------ # SLS: outputs # ------------------------------------------------------------ ls_columns = List([ 'sig_n', 'sig_m', 'eta_n', 'eta_m', 'eta_tot', ]) ls_values = Property(depends_on='+input') @cached_property def _get_ls_values(self): '''get the outputs for SLS ''' n = self.n m = self.m A = self.A W = self.W f_ctk = self.f_ctk f_m = self.f_m sig_n = n / A / 1000. sig_m = abs(m / W) / 1000. eta_n = sig_n / f_ctk eta_m = sig_m / f_m eta_tot = eta_n + eta_m return { 'sig_n': sig_n, 'sig_m': sig_m, 'eta_n': eta_n, 'eta_m': eta_m, 'eta_tot': eta_tot } sig_n = Property def _get_sig_n(self): return self.ls_values['sig_n'] sig_m = Property def _get_sig_m(self): return self.ls_values['sig_m'] eta_n = Property def _get_eta_n(self): return self.ls_values['eta_n'] eta_m = Property def _get_eta_m(self): return self.ls_values['eta_m'] eta_tot = Property def _get_eta_tot(self): return self.ls_values['eta_tot'] assess_name = 'max_eta_tot' # assess_name = 'max_sig1_up' # # max_sig1_up = Property( depends_on = '+input' ) # @cached_property # def _get_max_sig1_up( self ): # return ndmax( self.sig1_up ) # @todo: make it possible to select the assess value: # # assess_name = Enum( values = 'columns' ) # def _assess_name_default( self ): # return self.columns[-1] max_eta_tot = Property(depends_on='+input') @cached_property def _get_max_eta_tot(self): return ndmax(self.eta_tot) #------------------------------- # ls view #------------------------------- # @todo: the dynamic selection of the columns to be displayed # does not work in connection with the LSArrayAdapter traits_view = View( VGroup( HGroup( Item(name='f_ctk', label='Tensile strength concrete [MPa]: f_ctk '), Item(name='f_m', label='Flexural tensile trength concrete [MPa]: f_m ')), VGroup( Include('ls_group'), # @todo: currently LSArrayAdapter must be called both # in SLS and ULS separately to configure columns # arrangement individually # Item('ls_array', show_label=False, editor=TabularEditor(adapter=LSArrayAdapter()))), ), resizable=True, scrollable=True, height=1000, width=1100)
class SPIRRIDUI(HasTraits): title = Str('simvisage SPIRRID') image = Image('pics/spirrid.png') comp_parts = List()
class RandomField(HasTraits): ''' This class implements a 3D random field on a regular grid and allows for interpolation using the EOLE method ''' lacor_arr = Array(Float, modified=True) #(nD,1) array of autocorrelation lengths nDgrid = List(Array, modified=True) # list of nD entries: each entry is an array of points in the part. dimension reevaluate = Event seed = Bool(False) distr_type = Enum('Gauss', 'Weibull', modified=True) stdev = Float(1.0, modified=True) mean = Float(0.0, modified=True) shape = Float(5.0, modified=True) scale = Float(1.0, modified=True) loc = Float(0.0, modified=True) def acor(self, dx, lacor): '''autocorrelation function''' C = e ** (-(dx / lacor) ** 2) return C eigenvalues = Property(depends_on='+modified') @cached_property def _get_eigenvalues(self): '''evaluates the eigenvalues and eigenvectors of the covariance matrix''' # creating distances from the first coordinate for i, grid_i in enumerate(self.nDgrid): self.nDgrid[i] -= grid_i[0] # creating a symm. toeplitz matrix with (xgrid, xgrid) data points coords_lst = [toeplitz(grid_i) for grid_i in self.nDgrid] # apply the autocorrelation func. on the coord matrices to obtain the covariance matrices C_matrices = [self.acor(coords_i, self.lacor_arr[i]) for i, coords_i in enumerate(coords_lst)] # evaluate the eigenvalues and eigenvectors of the autocorrelation matrices eigen_lst = [] for i, C_i in enumerate(C_matrices): print 'evaluating eigenvalues for dimension ' + str(i+1) lambda_i, Phi_i = eigh(C_i) # truncate the eigenvalues at 99% of tr(C) truncation_limit = 0.99 * np.trace(C_i) argsort = np.argsort(lambda_i) cum_sum_lambda = np.cumsum(np.sort(lambda_i)[::-1]) idx_trunc = int(np.sum(cum_sum_lambda < truncation_limit)) eigen_lst.append([lambda_i[argsort[::-1]][:idx_trunc], Phi_i[:, argsort[::-1]][:,:idx_trunc]]) print 'complete' Lambda_C = 1.0 Phi_C = 1.0 for lambda_i, Phi_i in eigen_lst: Lambda_i = np.diag(lambda_i) Lambda_C = np.kron(Lambda_C, Lambda_i) Phi_C = np.kron(Phi_C, Phi_i) return Lambda_C, Phi_C generated_random_vector = Property(Array, depends_on='reevaluate') @cached_property def _get_generated_random_vector(self): if self.seed == True: np.random.seed(141) # points between 0 to 1 with an equidistant step for the LHS # No. of points = No. of truncated eigenvalues npts = self.eigenvalues[0].shape[0] randsim = np.linspace(0.5/npts, 1 - 0.5/npts, npts) # shuffling points for the simulation np.random.shuffle(randsim) # matrix containing standard Gauss distributed random numbers xi = norm().ppf(randsim) return xi random_field = Property(Array, depends_on='+modified') @cached_property def _get_random_field(self): '''simulates the Gaussian random field''' # evaluate the eigenvalues and eigenvectors of the autocorrelation matrix Lambda_C_sorted, Phi_C_sorted = self.eigenvalues # generate the RF with standardized Gaussian distribution ydata = np.dot(np.dot(Phi_C_sorted, (Lambda_C_sorted) ** 0.5), self.generated_random_vector) # transform the standardized Gaussian distribution if self.distr_type == 'Gauss': # scaling the std. distribution scaled_ydata = ydata * self.stdev + self.mean elif self.distr_type == 'Weibull': # setting Weibull params Pf = norm().cdf(ydata) scaled_ydata = weibull_min(self.shape, scale=self.scale, loc=self.loc).ppf(Pf) shape = tuple([len(grid_i) for grid_i in self.nDgrid]) rf = np.reshape(scaled_ydata, shape) return rf def interpolate_rf(self, coords): '''interpolate RF values using the EOLE method coords = list of 1d arrays of coordinates''' # check consistency of dimensions if len(coords) != len(self.nDgrid): raise ValueError('point dimension differs from random field dimension') # create the covariance matrix C_matrices = [self.acor(coords_i.reshape(1, len(coords_i)) - self.nDgrid[i].reshape(len(self.nDgrid[i]),1), self.lacor_arr[i]) for i, coords_i in enumerate(coords)] C_u = 1.0 for i, C_ui in enumerate(C_matrices): if i == 0: C_u *= C_ui else: C_u = C_u.reshape(C_u.shape[0], 1, C_u.shape[1]) * C_ui grid_size = 1.0 for j in np.arange(i+1): grid_size *= len(self.nDgrid[j]) C_u = C_u.reshape(grid_size,len(coords[0])) Lambda_Cx, Phi_Cx = self.eigenvalues # values interpolated in the standardized Gaussian rf u = np.sum(self.generated_random_vector / np.diag(Lambda_Cx) ** 0.5 * np.dot(C_u.T, Phi_Cx), axis=1) if self.distr_type == 'Gauss': scaled_u = u * self.stdev + self.mean elif self.distr_type == 'Weibull': Pf = norm().cdf(u) scaled_u = weibull_min(self.shape, scale=self.scale, loc=self.loc).ppf(Pf) return scaled_u
class Postprocessor(HasTraits): title = Str('postprocessor') post_components = List()
class CompositeCrackBridge(HasTraits): reinforcement_lst = List(Instance(Reinforcement)) w = Float E_m = Float Ll = Float Lr = Float V_f_tot = Property(depends_on='reinforcement_lst+') @cached_property def _get_V_f_tot(self): V_f_tot = 0.0 for reinf in self.reinforcement_lst: V_f_tot += reinf.V_f return V_f_tot E_c = Property(depends_on='reinforcement_lst+') @cached_property def _get_E_c(self): E_fibers = 0.0 for reinf in self.reinforcement_lst: E_fibers += reinf.V_f * reinf.E_f E_c = self.E_m * (1. - self.V_f_tot) + E_fibers return E_c * (1. + 1e-15) sorted_reinf_lst = Property(Tuple(List, List), depends_on='reinforcement_lst') @cached_property def _get_sorted_reinf_lst(self): cont_reinf_lst = [] short_reinf_lst = [] for reinf in self.reinforcement_lst: if reinf.__class__ == ContinuousFibers: cont_reinf_lst.append(reinf) elif reinf.__class__ == ShortFibers: short_reinf_lst.append(reinf) return cont_reinf_lst, short_reinf_lst cont_fibers_instance = Instance(CrackBridgeContFibers) def _cont_fibers_instance_default(self): return CrackBridgeContFibers() cont_fibers = Property(Instance(CrackBridgeContFibers), depends_on='reinforcement_lst+,Ll,Lr,E_m,w') @cached_property def _get_cont_fibers(self): cbcf = self.cont_fibers_instance cbcf.w = self.w cbcf.Ll = self.Ll cbcf.Lr = self.Lr cbcf.E_m = self.E_m cbcf.E_c = self.E_c cbcf.cont_reinf_lst = self.sorted_reinf_lst[0] return cbcf short_fibers_instance = Instance(CrackBridgeShortFibers) def _short_fibers_instance_default(self): return CrackBridgeShortFibers() short_fibers = Property(Instance(CrackBridgeShortFibers), depends_on='reinforcement_lst+,E_m,w') @cached_property def _get_short_fibers(self): cbsf = self.short_fibers_instance cbsf.w = self.w cbsf.E_m = self.E_m cbsf.E_c = self.E_c cbsf.short_reinf_lst = self.sorted_reinf_lst[1] return cbsf _x_arr = Property(Array, depends_on='w,E_m,Ll,Lr,reinforcement_lst+') @cached_property def _get__x_arr(self): if len(self.sorted_reinf_lst[0]) != 0 and len( self.sorted_reinf_lst[1]) != 0: added_x = np.hstack( (self.cont_fibers.x_arr, self.short_fibers.x_arr)) sorted_unique_x = np.unique(added_x) return sorted_unique_x elif len(self.sorted_reinf_lst[0]) != 0: return self.cont_fibers.x_arr elif len(self.sorted_reinf_lst[1]) != 0: return self.short_fibers.x_arr _epsm_arr = Property(Array, depends_on='w,E_m,Ll,Lr,reinforcement_lst+') @cached_property def _get__epsm_arr(self): if len(self.sorted_reinf_lst[0]) != 0 and len( self.sorted_reinf_lst[1]) != 0: epsm_cont_interp = MFnLineArray(xdata=self.cont_fibers.x_arr, ydata=self.cont_fibers.epsm_arr) epsm_short_interp = MFnLineArray(xdata=self.short_fibers.x_arr, ydata=self.short_fibers.epsm_arr) added_epsm_cont = self.cont_fibers.epsm_arr + epsm_short_interp.get_values( self.cont_fibers.x_arr) added_epsm_short = self.short_fibers.epsm_arr + epsm_cont_interp.get_values( self.short_fibers.x_arr) sorted_unique_idx = np.unique(np.hstack( (self.cont_fibers.x_arr, self.short_fibers.x_arr)), return_index=True)[1] return np.hstack( (added_epsm_cont, added_epsm_short))[sorted_unique_idx] elif len(self.sorted_reinf_lst[0]) != 0: return self.cont_fibers.epsm_arr elif len(self.sorted_reinf_lst[1]) != 0: self.short_fibers.w = self.w return self.short_fibers.epsm_arr _epsf_arr = Property(Array, depends_on='w,E_m,Ll,Lr,reinforcement_lst+') @cached_property def _get__epsf_arr(self): ''' only for continuous reinforcement ''' if len(self.sorted_reinf_lst[0]) != 0 and len( self.sorted_reinf_lst[1]) == 0: self.cont_fibers.w = self.w return self.cont_fibers.epsf_arr else: raise ValueError('epsf can only be computed for continuous fibers') _epsf0_arr = Property(Array, depends_on='w,E_m,Ll,Lr,reinforcement_lst+') @cached_property def _get__epsf0_arr(self): if len(self.sorted_reinf_lst[0]) != 0 and len( self.sorted_reinf_lst[1]) != 0: epsf0_cont = self.cont_fibers.epsf0_arr epsf0_short = self.short_fibers.epsf0_arr elif len(self.sorted_reinf_lst[0]) != 0: epsf0_cont = self.cont_fibers.epsf0_arr epsf0_short = np.array([]) elif len(self.sorted_reinf_lst[1]) != 0: epsf0_cont = np.array([]) epsf0_short = self.short_fibers.epsf0_arr return epsf0_cont, epsf0_short _epsf0_arr_cont = Property(Array, depends_on='w,E_m,Ll,Lr,reinforcement_lst+') @cached_property def _get__epsf0_arr_cont(self): return self._epsf0_arr[0] _epsf0_arr_short = Property(Array, depends_on='w,E_m,Ll,Lr,reinforcement_lst+') @cached_property def _get__epsf0_arr_short(self): return self._epsf0_arr[1] sigma_c = Property(depends_on='w,E_m,Ll,Lr,reinforcement_lst+') @cached_property def _get_sigma_c(self): if len(self.sorted_reinf_lst[0]) != 0 and len( self.sorted_reinf_lst[1]) != 0: sigma_c_cont = np.sum( self._epsf0_arr_cont * self.cont_fibers.sorted_stats_weights * self.cont_fibers.sorted_V_f * self.cont_fibers.sorted_nu_r * self.cont_fibers.sorted_E_f * (1. - self.cont_fibers.damage)) sigma_c_short = np.sum(self._epsf0_arr_short * self.short_fibers.sorted_V_f * self.short_fibers.sorted_E_f) elif len(self.sorted_reinf_lst[0]) != 0: sigma_c_cont = np.sum( self._epsf0_arr_cont * self.cont_fibers.sorted_stats_weights * self.cont_fibers.sorted_V_f * self.cont_fibers.sorted_nu_r * self.cont_fibers.sorted_E_f * (1. - self.cont_fibers.damage)) sigma_c_short = 0.0 elif len(self.sorted_reinf_lst[1]) != 0: sigma_c_cont = 0.0 sigma_c_short = np.sum(self._epsf0_arr_short * self.short_fibers.sorted_V_f * self.short_fibers.sorted_E_f) return sigma_c_cont + sigma_c_short
class InterpolatedSPIRRID(HasTraits): adaption = Instance(RangeAdaption) def preinterpolate(self, mu_w_x, sigma_f_cutoff, x_adapt): # values to create array grid axes_values = [sigma_f_cutoff, x_adapt] preinterp = NDIdxInterp(data=mu_w_x, axes_values=axes_values) # values to interpolate for load_sigma_f = self.initial_eps_vars[0] x = self.initial_eps_vars[1] interp_coords = [load_sigma_f, x] return preinterp(*interp_coords, mode='constant') interp_grid = Property() @cached_property def _get_interp_grid(self): print 'evaluating mean response and adapting ranges...' spirrid_result = self.spirrid_result print 'complete' axes_values = self.initial_eps_vars ni = NDIdxInterp(data=spirrid_result, axes_values=axes_values) return ni spirrid_result = Property(Array) @cached_property def _get_spirrid_result(self): Ll = self.adaption.BC_range Lr = Ll result = np.zeros((self.adaption.load_n_sigma_c, self.adaption.n_x, self.adaption.n_BC, self.adaption.n_BC)) loops_tot = len(Ll) * len(Lr) for i, ll in enumerate(Ll): for j, lr in enumerate(Lr): # adapt w range w_opt, sigma_f_opt = self.adaption.adapt_w_range(ll, lr) # adapt x range x_opt = np.linspace(-ll, lr, self.adaption.n_x) self.adaption.spirrid.eps_vars = dict(w=w_opt, x=x_opt) self.adaption.spirrid.theta_vars['Ll'] = ll self.adaption.spirrid.theta_vars['Lr'] = lr # evaluate 2D (w,x) SPIRRID with adapted ranges x and w mu_w_x = self.adaption.spirrid.mu_q_arr # preinterpolate particular result for the given x and sigma ranges mu_w_x_interp = \ self.preinterpolate(mu_w_x, sigma_f_opt, x_opt).T mask = np.where(self.adaption.load_sigma_f <= sigma_f_opt[-1], 1, np.NaN)[:, np.newaxis] mu_w_x_interp = mu_w_x_interp * mask # eps_vars = orthogonalize([np.arange(len(w_opt)), np.arange(len(x_opt))]) # m.surf(eps_vars[0], eps_vars[1], mu_w_x * 0.05) # m.surf(eps_vars[0], eps_vars[1], mu_w_x_interp * 0.05) # m.show() # store the particular result for BC ll and lr into the result array result[:, :, i, j] = mu_w_x_interp current_loop = i * len(Lr) + j + 1 print 'progress: %2.1f %%' % \ (current_loop / float(loops_tot) * 100.) return result initial_eps_vars = Property(List(Array)) @cached_property def _get_initial_eps_vars(self): return [ self.adaption.load_sigma_f, self.adaption.x_init, self.adaption.BC_range, self.adaption.BC_range ] def __call__(self, *args): ''' evaluation of force profile in the vicinity of a crack bridge ''' args = list(args) load_sigma_f = args[0] / self.adaption.spirrid.theta_vars['V_f'] # fiber stress args[0] = load_sigma_f self.load_sigma_f = load_sigma_f return self.interp_grid(*args)
class LCCTable(HasTraits): '''Loading Case Manager. Generates and sorts the loading case combinations of all specified loading cases. ''' # define ls # ls = Trait('ULS', {'ULS': ULS, 'SLS': SLS}) # lcc-instance for the view # lcc = Instance(LCC) #------------------------------- # Define loading cases: #------------------------------- # path to the directory containing the state data files # data_dir = Directory # list of load cases # lc_list_ = List(Instance(LC)) lc_list = Property(List, depends_on='+filter') def _set_lc_list(self, value): self.lc_list_ = value def _get_lc_list(self): # for lc in self.lc_list_: # if lc.data_filter != self.data_filter: # lc.data_filter = self.data_filter return self.lc_list_ lcc_table_columns = Property(depends_on='lc_list_, +filter') def _get_lcc_table_columns(self): return [ ObjectColumn(label='Id', name='lcc_id') ] + \ [ ObjectColumn(label=lc.name, name=lc.name) for idx, lc in enumerate(self.lc_list) ] + \ [ ObjectColumn(label='assess_value', name='assess_value') ] geo_columns = Property(List(Str), depends_on='lc_list_, +filter') def _get_geo_columns(self): '''derive the order of the geo columns from the first element in 'lc_list'. The internal consistency is checked separately in the 'check_consistency' method. ''' return self.lc_list[0].geo_columns sr_columns = Property(List(Str), depends_on='lc_list_, +filter') def _get_sr_columns(self): '''derive the order of the stress resultants from the first element in 'lc_list'. The internal consistency is checked separately in the 'check_consistency' method. ''' return self.lc_list[0].sr_columns #------------------------------- # check consistency #------------------------------- def _check_for_consistency(self): ''' check input files for consitency: ''' return True #------------------------------- # lc_arr #------------------------------- lc_arr = Property(Array) def _get_lc_arr(self): '''stack stress resultants arrays of all loading cases together. This yields an array of shape ( n_lc, n_elems, n_sr ) ''' sr_arr_list = [lc.sr_arr for lc in self.lc_list] # for x in sr_arr_list: # print x.shape return array(sr_arr_list) #------------------------------- # Array dimensions: #------------------------------- n_sr = Property(Int) def _get_n_sr(self): return len(self.sr_columns) n_lc = Property(Int) def _get_n_lc(self): return len(self.lc_list) n_lcc = Property(Int) def _get_n_lcc(self): return self.combi_arr.shape[0] n_elems = Property(Int) def _get_n_elems(self): return self.lc_list[0].sr_arr.shape[0] #------------------------------- # auxilary method for get_combi_arr #------------------------------- def _product(self, args): """ Get all possible permutations of the security factors without changing the order of the loading cases. The method corresponds to the build-in function 'itertools.product'. Instead of returning a generator object a list of all possible permutations is returned. As argument a list of list needs to be defined. In the original version of 'itertools.product' the function takes a tuple as argument ("*args"). """ pools = map(tuple, args) # within original version args defined as *args result = [[]] for pool in pools: result = [x + [y] for x in result for y in pool] return result # ------------------------------------------------------------ # 'combi_arr' - array containing indices of all loading case combinations: # ------------------------------------------------------------ # list of indices of the position of the imposed loads in 'lc_list' # # imposed_idx_list = Property( List, depends_on = 'lc_list_, lc_list_.+input' ) imposed_idx_list = Property(List, depends_on='lc_list_') @cached_property def _get_imposed_idx_list(self): '''list of indices for the imposed loads ''' imposed_idx_list = [] for i_lc, lc in enumerate(self.lc_list): cat = lc.category if cat == 'imposed-load': imposed_idx_list.append(i_lc) return imposed_idx_list # array containing the psi with name 'psi_key' for the specified # loading cases defined in 'lc_list'. For dead-loads no value for # psi exists. In this case a value of 1.0 is defined. # This yields an array of shape ( n_lc, ) # def _get_psi_arr(self, psi_key): '''psi_key must be defined as: 'psi_0', 'psi_1', or 'psi_2' Returns an 1d-array of shape ( n_lc, ) ''' # get list of ones (used for dead-loads): # psi_list = [1] * len(self.lc_list) # overwrite ones with psi-values in case of imposed-loads: # for imposed_idx in self.imposed_idx_list: psi_value = getattr(self.lc_list[imposed_idx], psi_key) psi_list[imposed_idx] = psi_value return array(psi_list, dtype='float_') # list containing names of the loading cases # lc_name_list = Property(List, depends_on='lc_list_') @cached_property def _get_lc_name_list(self): '''list of names of all loading cases ''' return [lc.name for lc in self.lc_list] show_lc_characteristic = Bool(True) # combination array: # combi_arr = Property(Array, depends_on='lc_list_, combination_SLS') @cached_property def _get_combi_arr(self): '''array containing the security and combination factors corresponding to the specified loading cases. This yields an array of shape ( n_lcc, n_lc ) Properties defined in the subclasses 'LCCTableULS', 'LCCTableSLS': - 'gamma_list' = list of security factors (gamma) - 'psi_lead' = combination factors (psi) of the leading imposed load - 'psi_non_lead' = combination factors (psi) of the non-leading imposed loads ''' # printouts: # if self.ls == 'ULS': print '*** load case combinations for limit state ULS ***' else: print '*** load case combinations for limit state SLS ***' print '*** SLS combination used: % s ***' % (self.combination_SLS) #--------------------------------------------------------------- # get permutations of safety factors ('gamma') #--------------------------------------------------------------- # permutation_list = self._product(self.gamma_list) combi_arr = array(permutation_list) # check if imposed loads are defined # if not no further processing of 'combi_arr' is necessary: # if self.imposed_idx_list == []: # if option is set to 'True' the loading case combination table # is enlarged with an identity matrix in order to see the # characteristic values of each loading case. # if self.show_lc_characteristic: combi_arr = vstack([identity(self.n_lc), combi_arr]) return combi_arr #--------------------------------------------------------------- # get leading and non leading combination factors ('psi') #--------------------------------------------------------------- # go through all possible cases of leading imposed loads # For the currently investigated imposed loading case the # psi value is taken from 'psi_leading_arr' for all other # imposed loads the psi value is taken from 'psi_non_lead_arr' # Properties are defined in the subclasses # psi_lead_arr = self.psi_lead_arr psi_non_lead_arr = self.psi_non_lead_arr # for SLS limit state case 'rare' all imposed loads are multiplied # with 'psi_2'. In this case no distinction between leading or # non-leading imposed loads needs to be performed. # if all(psi_lead_arr == psi_non_lead_arr): combi_arr_psi = combi_arr * psi_lead_arr # generate a list or arrays obtained by multiplication # with the psi-factors. # This yields a list of length = number of imposed-loads. # else: combi_arr_psi_list = [] for imposed_idx in self.imposed_idx_list: # copy in order to preserve initial state of the array # and avoid in place modification psi_arr = copy(psi_non_lead_arr) psi_arr[imposed_idx] = psi_lead_arr[imposed_idx] combi_arr_lead_i = combi_arr[where( combi_arr[:, imposed_idx] != 0)] * psi_arr combi_arr_psi_list.append(combi_arr_lead_i) combi_arr_psi_no_0 = vstack(combi_arr_psi_list) # missing cases without any dead load have to be added # get combinations with all!! imposed = 0 # lcc_all_imposed_zero = where( (combi_arr[:, self.imposed_idx_list] == 0).all(axis=1)) # add to combinations # combi_arr_psi = vstack( (combi_arr[lcc_all_imposed_zero], combi_arr_psi_no_0)) #--------------------------------------------------------------- # get exclusive loading cases ('exclusive_to') #--------------------------------------------------------------- # get a list of lists containing the indices of the loading cases # that are defined exclusive to each other. # The list still contains duplicates, e.g. [1,2] and [2,1] # exclusive_list = [] for i_lc, lc in enumerate(self.lc_list): # get related load case number # for exclusive_name in lc.exclusive_to: if exclusive_name in self.lc_name_list: exclusive_idx = self.lc_name_list.index(exclusive_name) exclusive_list.append([i_lc, exclusive_idx]) # eliminate the duplicates in 'exclusive_list' # exclusive_list_unique = [] for exclusive_list_entry in exclusive_list: if sorted(exclusive_list_entry) not in exclusive_list_unique: exclusive_list_unique.append(sorted(exclusive_list_entry)) # delete the rows in combination array that contain # loading case combinations with imposed-loads that have been defined # as exclusive to each other. # combi_arr_psi_exclusive = combi_arr_psi # print 'combi_arr_psi_exclusive', combi_arr_psi_exclusive for exclusive_list_entry in exclusive_list_unique: # check where maximum one value of the exclusive load cases is unequal to one # LC1 LC2 LC3 (all LCs are defined as exclusive to each other) # # e.g. 1.5 0.9 0.8 (example of 'combi_arr_psi') # 1.5 0.0 0.0 # 0.0 0.0 0.0 (combination with all imposed loads = 0 after multiplication wit psi and gamma) # ... ... ... # # this would yield the following mask_arr (containing ones or zeros): # e.g. 1.0 1.0 1.0 --> sum = 3 --> true combi --> accepted combination # 1.0 0.0 0.0 --> sum = 1 --> false combi --> no accepted combination # e.g. 0.0 0.0 0.0 --> sum = 0 --> true combi --> accepted combination (only body-loads) # ... ... ... # mask_arr = where( combi_arr_psi_exclusive[:, exclusive_list_entry] != 0, 1.0, 0.0) # print 'mask_arr', mask_arr true_combi = where(sum(mask_arr, axis=1) <= 1.0) # print 'true_combi', true_combi combi_arr_psi_exclusive = combi_arr_psi_exclusive[true_combi] #--------------------------------------------------------------- # create array with only unique load case combinations #--------------------------------------------------------------- # If the psi values of an imposed-load are defined as zero this # may led to zero entries in 'combi_arr'. This would yield rows # in 'combi_arr' which are duplicates. Those rows are removed. # Add first row in 'combi_arr_psi_exclusive' to '_unique' array # This array must have shape (1, n_lc) in order to use 'axis'-option # combi_arr_psi_exclusive_unique = combi_arr_psi_exclusive[0][None, :] for row in combi_arr_psi_exclusive: # Check if all factors in one row are equal to the rows in 'unique' array. # If this is not the case for any row the combination is added to 'unique'. # Broadcasting is used for the bool evaluation: # if (row == combi_arr_psi_exclusive_unique).all( axis=1.0).any() == False: combi_arr_psi_exclusive_unique = vstack( (combi_arr_psi_exclusive_unique, row)) # if option is set to 'True' the loading case combination table # is enlarged with an identity matrix in order to see the # characteristic values of each loading case. # # if self.show_lc_characteristic: # combi_arr_psi_exclusive_unique = vstack( [ identity( self.n_lc ), combi_arr_psi_exclusive_unique ] ) return combi_arr_psi_exclusive_unique #------------------------------- # lcc_arr #------------------------------- lcc_arr = Property(Array, depends_on='lc_list_') @cached_property def _get_lcc_arr(self): '''Array of all loading case combinations following the loading cases define in 'lc_list' and the combinations defined in 'combi_arr'. This yields an array of shape ( n_lcc, n_elems, n_sr ) ''' self._check_for_consistency() combi_arr = self.combi_arr # 'combi_arr' is of shape ( n_lcc, n_lc ) # 'lc_arr' is of shape ( n_lc, n_elems, n_sr ) # lc_arr = self.lc_arr # Broadcasting is used to generate array containing the multiplied lc's # yielding an array of shape ( n_lcc, n_lc, n_elems, n_sr ) # lc_combi_arr = lc_arr[None, :, :, :] * combi_arr[:, :, None, None] # Then the sum over index 'n_lc' is evaluated yielding # an array of all loading case combinations. # This yields an array of shape ( n_lcc, n_elem, n_sr ) # lcc_arr = sum(lc_combi_arr, axis=1) return lcc_arr #------------------------------- # lcc_lists #------------------------------- lcc_list = Property(List, depends_on='lc_list_') @cached_property def _get_lcc_list(self): '''list of loading case combinations (instances of LCC) ''' combi_arr = self.combi_arr lcc_arr = self.lcc_arr sr_columns = self.sr_columns geo_columns = self.geo_columns n_lcc = self.n_lcc # return a dictionary of the stress resultants # this is used by LSTable to determine the stress # resultants of the current limit state # lcc_list = [] for i_lcc in range(n_lcc): state_data_dict = {} for i_sr, name in enumerate(sr_columns): state_data_dict[name] = lcc_arr[i_lcc, :, i_sr][:, None] geo_data_dict = self.geo_data_dict lcc = LCC( # lcc_table = self, factors=combi_arr[i_lcc, :], lcc_id=i_lcc, ls_table=LSTable(geo_data=geo_data_dict, state_data=state_data_dict, ls=self.ls)) for idx, lc in enumerate(self.lc_list): lcc.add_trait(lc.name, Int(combi_arr[i_lcc, idx])) lcc_list.append(lcc) return lcc_list #------------------------------- # geo_arr #------------------------------- geo_data_dict = Property(Dict, depends_on='lc_list_') @cached_property def _get_geo_data_dict(self): '''Array of global coords derived from the first loading case defined in lc_list. Coords are identical for all LC's. ''' return self.lc_list[0].geo_data_dict #------------------------------- # min/max-values #------------------------------- def get_min_max_state_data(self): ''' get the surrounding curve of all 'lcc' values ''' lcc_arr = self.lcc_arr min_arr = ndmin(lcc_arr, axis=0) max_arr = ndmax(lcc_arr, axis=0) return min_arr, max_arr #-------------------------------------- # use for case 'max N*' nach ZiE # Fall 'maximale Normalkraft' nach ZiE #-------------------------------------- # max_sr_grouped_dict = Property( Dict ) # @cached_property # def _get_max_sr_grouped_dict( self ): # ''' get the surrounding curve for each stress resultant # shape lcc_array ( n_lcc, n_elems, n_sr ) # ''' # sr_columns = self.sr_columns # lcc_arr = self.lcc_arr # dict = {} # for i, sr in enumerate( self.sr_columns ): # idx_1 = argmax( abs( lcc_arr[:, :, i] ), axis = 0 ) # idx_2 = arange( 0, idx_1.shape[0], 1 ) # dict[sr] = lcc_arr[idx_1, idx_2, :] # return dict #-------------------------------------- # use for case 'max eta' nach ZiE # Fall max Ausnutzungsgrad nach ZiE #-------------------------------------- max_sr_grouped_dict = Property(Dict) @cached_property def _get_max_sr_grouped_dict(self): '''evaluate eta and prepare plot ''' sr_columns = self.sr_columns lcc_arr = self.lcc_arr # ## N_s6cm_d results from 'V_op_d'*1.5 # assume a distribution of stresses as for a simple # supported beam with cantilever corresponding # to the distance of the screws to each other and to the edge # of the TRC shell (33cm/17cm) # N_s6cm_d = lcc_arr[:, :, 2] * (17. + 33. + 1.) / 33. # ## V_s6cm_d results from 'N_ip_d'/2 # assume an equal distribution (50% each) of the # normal forces to each screw # V_s6cm_d = lcc_arr[:, :, 0] * 0.56 # V_s6cm_d = ( ( lcc_arr[:, :, 0] / 2 ) ** 2 + ( lcc_arr[:, :, 1] * 1.5 ) ** 2 ) ** 0.5 # resistance ac characteristic value obtained from the # experiment and EN DIN 1990 # N_ck = 28.3 V_ck = 63.8 gamma_s = 1.5 eta_N = N_s6cm_d / (N_ck / gamma_s) eta_V = abs(V_s6cm_d / (V_ck / gamma_s)) eta_inter = (eta_N) + (eta_V) idx_max_hinge = eta_inter.argmax(axis=0) dict = {} for i, sr in enumerate(self.sr_columns): idx_1 = idx_max_hinge idx_2 = arange(0, idx_1.shape[0], 1) dict[sr] = lcc_arr[idx_1, idx_2, :] return dict def export_hf_max_grouped(self, filename): """exports the hinge forces as consistent pairs for the two case 'max_eta' or 'max_N*' """ from matplotlib import pyplot sr_columns = self.sr_columns dict = self.max_sr_grouped_dict length_xy_quarter = self.length_xy_quarter def save_bar_plot(x, y, filename='bla', title='Title', xlabel='xlabel', ylabel='ylavel', width=0.1, xmin=0, xmax=1000, ymin=-1000, ymax=1000, figsize=[10, 5]): fig = pyplot.figure(facecolor="white", figsize=figsize) ax1 = fig.add_subplot(1, 1, 1) ax1.bar(x, y, width=width, align='center', color='green') ax1.set_xlim(xmin, xmax) ax1.set_ylim(ymin, ymax) ax1.set_xlabel(xlabel, fontsize=22) ax1.set_ylabel(ylabel, fontsize=22) if title == 'N_ip max': title = 'Fall max $\eta$' # title = 'Fall max $N^{*}$' if title == 'V_ip max': title = 'max $V_{ip}$' if title == 'V_op max': title = 'Fall max $V^{*}$' ax1.set_title(title) fig.savefig(filename, orientation='portrait', bbox_inches='tight') pyplot.clf() X = array(self.geo_data_dict['X_hf']) Y = array(self.geo_data_dict['Y_hf']) # symmetric axes # idx_sym = where(abs(Y[:, 0] - 2.0 * length_xy_quarter) <= 0.0001) X_sym = X[idx_sym].reshape(-1) idx_r0_r1 = where(abs(X[:, 0] - 2.0 * length_xy_quarter) <= 0.0001) X_r0_r1 = Y[idx_r0_r1].reshape(-1) for sr in sr_columns: F_int = dict[sr] # first row N_ip, second V_ip third V_op F_sym = F_int[idx_sym, :].reshape(-1, len(sr_columns)) F_r0_r1 = F_int[idx_r0_r1, :].reshape(-1, len(sr_columns)) save_bar_plot(X_sym, F_sym[:, 0].reshape(-1), xlabel='$X$ [m]', ylabel='$N^{*}_{Ed}$ [kN]', filename=filename + 'N_ip' + '_sym_' + sr + '_max', title=sr + ' max', xmin=0.0, xmax=3.5 * length_xy_quarter, figsize=[10, 5], ymin=-30, ymax=+30) if self.link_type == 'inc_V_ip': save_bar_plot(X_sym, F_sym[:, 1].reshape(-1), xlabel='$X$ [m]', ylabel='$V_{ip}$ [kN]', filename=filename + 'V_ip' + '_sym_' + sr + '_max', title=sr + ' max', xmin=0.0, xmax=3.5 * length_xy_quarter, figsize=[10, 5], ymin=-30, ymax=+30) save_bar_plot(X_sym, F_sym[:, 2].reshape(-1), xlabel='$X$ [m]', ylabel='$V^{*}_{Ed}$ [kN]', filename=filename + 'V_op' + '_sym_' + sr + '_max', title=sr + ' max', xmin=0.0, xmax=3.5 * length_xy_quarter, figsize=[10, 5], ymin=-10, ymax=+10) # r0_r1 # save_bar_plot(X_r0_r1, F_r0_r1[:, 0].reshape(-1), xlabel='$Y$ [m]', ylabel='$N^{*}_{Ed}$ [kN]', filename=filename + 'N_ip' + '_r0_r1_' + sr + '_max', title=sr + ' max', xmin=0.0, xmax=2.0 * length_xy_quarter, figsize=[5, 5], ymin=-30, ymax=+30) if self.link_type == 'inc_V_ip': save_bar_plot(X_r0_r1, F_r0_r1[:, 1].reshape(-1), xlabel='$Y$ [m]', ylabel='$V_{ip}$ [kN]', filename=filename + 'V_ip' + '_r0_r1_' + sr + '_max', title=sr + ' max', xmin=0.0, xmax=2.0 * length_xy_quarter, figsize=[5, 5], ymin=-30, ymax=+30) save_bar_plot(X_r0_r1, F_r0_r1[:, 2].reshape(-1), xlabel='$Y$ [m]', ylabel='$V^{*}_{Ed}$ [kN]', filename=filename + 'V_op' + '_r0_r1_' + sr + '_max', title=sr + ' max', xmin=0.0, xmax=2.0 * length_xy_quarter, figsize=[5, 5], ymin=-10, ymax=+10) def plot_interaction_s6cm(self): """get the maximum values (consistent pairs of N and V) and plot them in an interaction plot """ lcc_arr = self.lcc_arr # ## F_Edt results from 'V_op_d'*1.5 # assume a distribution of stresses as for a simple # supported beam with cantilever corresponding # to the distance of the screws to each other and to the edge # of the TRC shell (33cm/17cm) # F_Edt = lcc_arr[:, :, 2] * (17. + 33. + 1.) / 33. # ## F_EdV1 results from 'N_ip_d'/2 # assume an equal distribution (50% each) of the # normal forces to each screw # F_EdV1 = lcc_arr[:, :, 0] * 0.56 # V_s6cm_d = ( ( lcc_arr[:, :, 0] / 2 ) ** 2 + ( lcc_arr[:, :, 1] * 1.5 ) ** 2 ) ** 0.5 # resistance ac characteristic value obtained from the # experiment and EN DIN 1990 # F_Rkt = 28.3 F_RkV1 = 63.8 gamma_M = 1.5 eta_t = abs(F_Edt / (F_Rkt / gamma_M)) eta_V1 = abs(F_EdV1 / (F_RkV1 / gamma_M)) print 'eta_t.shape', eta_t.shape print 'eta_V1.shape', eta_V1.shape # self.interaction_plot(abs(F_Edt), abs(F_EdV1)) self.interaction_plot(eta_t, eta_V1) # eta_inter = ( eta_N ) + ( eta_V ) # # idx_max_hinge = eta_inter.argmax( axis = 0 ) # idx_hinge = arange( 0, len( idx_max_hinge ), 1 ) # plot_eta_N = eta_N[idx_max_hinge, idx_hinge] # plot_eta_V = eta_V[idx_max_hinge, idx_hinge] # self.interaction_plot( plot_eta_N, plot_eta_V ) def interaction_plot(self, eta_N, eta_V): from matplotlib import font_manager ticks_font = font_manager.FontProperties(family='Times', style='normal', size=18, weight='normal', stretch='normal') from matplotlib import pyplot fig = pyplot.figure(facecolor="white", figsize=[10, 10]) ax1 = fig.add_subplot(1, 1, 1) # x = arange(0, 1.01, 0.01) # y15 = (1 - x ** 1.5) ** (1 / 1.5) # y = (1 - x) ax1.set_xlabel('$F_\mathrm{Ed,V1}/F_\mathrm{Rd,V1}$', fontsize=24) ax1.set_ylabel('$F_\mathrm{Ed,t}/F_\mathrm{Rd,t}$', fontsize=24) # ax1.set_xlabel('$|N_\mathrm{Ed}|$' , fontsize=32) # ax1.set_ylabel('$|V_\mathrm{Ed}|$', fontsize=32) # ax1.plot(x , y, '--', color='black' # , linewidth=2.0) # ax1.plot(x , y15, '--', color='black' # , linewidth=2.0) ax1.plot(eta_V, eta_N, 'wo', markersize=3) # ax1.plot(eta_V, eta_N, 'o', color='green', markersize=8) # ax1.plot( eta_V[where( limit < 1 )] , eta_N[where( limit < 1 )], 'o', markersize = 8 ) # ax1.plot( eta_V[where( limit > 1 )] , eta_N[where( limit > 1 )], 'o', color = 'red', markersize = 8 ) for xlabel_i in ax1.get_xticklabels(): xlabel_i.set_fontsize(24) xlabel_i.set_family('serif') for ylabel_i in ax1.get_yticklabels(): ylabel_i.set_fontsize(24) ylabel_i.set_family('serif') # ax1.plot( x , 1 - x, '--', color = 'black', label = 'lineare Interaktion' ) ax1.set_xlim(0, 1.0) ax1.set_ylim(0, 1.0) ax1.legend() pyplot.show() pyplot.clf() # choose linking type (in-plane shear dof blocked or not) # link_type = Enum('exc_V_ip', 'inc_V_ip') # length of the shell (needed to plot the hinge forces plots correctly) # length_xy_quarter = 3.5 # m def export_hf_lc(self): """exports the hinge forces for each loading case separately """ from matplotlib import pyplot sr_columns = self.sr_columns dict = self.max_sr_grouped_dict length_xy_quarter = self.length_xy_quarter def save_bar_plot(x, y, filename='bla', xlabel='xlabel', ylabel='ylavel', ymin=-10, ymax=10, width=0.1, xmin=0, xmax=1000, figsize=[10, 5]): fig = pyplot.figure(facecolor="white", figsize=figsize) ax1 = fig.add_subplot(1, 1, 1) ax1.bar(x, y, width=width, align='center', color='blue') ax1.set_xlim(xmin, xmax) ax1.set_ylim(ymin, ymax) ax1.set_xlabel(xlabel, fontsize=22) ax1.set_ylabel(ylabel, fontsize=22) fig.savefig(filename, orientation='portrait', bbox_inches='tight') pyplot.clf() X = array(self.geo_data_dict['X_hf']) Y = array(self.geo_data_dict['Y_hf']) # symmetric axes # idx_sym = where(abs(Y[:, 0] - 2.0 * length_xy_quarter) <= 0.0001) X_sym = X[idx_sym].reshape(-1) idx_r0_r1 = where(abs(X[:, 0] - 2.0 * length_xy_quarter) <= 0.0001) X_r0_r1 = Y[idx_r0_r1].reshape(-1) F_int = self.lc_arr for i, lc_name in enumerate(self.lc_name_list): filename = self.lc_list[i].plt_export max_N_ip = max(int(ndmax(F_int[i, :, 0], axis=0)) + 1, 1) max_V_ip = max(int(ndmax(F_int[i, :, 1], axis=0)) + 1, 1) max_V_op = max(int(ndmax(F_int[i, :, 2], axis=0)) + 1, 1) F_int_lc = F_int[i, :, :] # first row N_ip, second V_ip third V_op F_sym = F_int_lc[idx_sym, :].reshape(-1, len(sr_columns)) F_r0_r1 = F_int_lc[idx_r0_r1, :].reshape(-1, len(sr_columns)) save_bar_plot( X_sym, F_sym[:, 0].reshape(-1), # xlabel = '$X$ [m]', ylabel = '$N^{ip}$ [kN]', xlabel='$X$ [m]', ylabel='$N^{*}$ [kN]', filename=filename + 'N_ip' + '_sym', xmin=0.0, xmax=3.5 * length_xy_quarter, ymin=-max_N_ip, ymax=max_N_ip, figsize=[10, 5]) save_bar_plot(X_sym, F_sym[:, 1].reshape(-1), xlabel='$X$ [m]', ylabel='$V_{ip}$ [kN]', filename=filename + 'V_ip' + '_sym', xmin=0.0, xmax=3.5 * length_xy_quarter, ymin=-max_V_ip, ymax=max_V_ip, figsize=[10, 5]) save_bar_plot( X_sym, F_sym[:, 2].reshape(-1), # xlabel = '$X$ [m]', ylabel = '$V_{op}$ [kN]', xlabel='$X$ [m]', ylabel='$V^{*}$ [kN]', filename=filename + 'V_op' + '_sym', xmin=0.0, xmax=3.5 * length_xy_quarter, ymin=-max_V_op, ymax=max_V_op, figsize=[10, 5]) # r0_r1 # save_bar_plot( X_r0_r1, F_r0_r1[:, 0].reshape(-1), # xlabel = '$Y$ [m]', ylabel = '$N_{ip}$ [kN]', xlabel='$Y$ [m]', ylabel='$N^{*}$ [kN]', filename=filename + 'N_ip' + '_r0_r1', xmin=0.0, xmax=2.0 * length_xy_quarter, ymin=-max_N_ip, ymax=max_N_ip, figsize=[5, 5]) save_bar_plot(X_r0_r1, F_r0_r1[:, 1].reshape(-1), xlabel='$Y$ [m]', ylabel='$V_{ip}$ [kN]', filename=filename + 'V_ip' + '_r0_r1', xmin=0.0, xmax=2.0 * length_xy_quarter, ymin=-max_V_ip, ymax=max_V_ip, figsize=[5, 5]) save_bar_plot( X_r0_r1, F_r0_r1[:, 2].reshape(-1), # xlabel = '$Y$ [m]', ylabel = '$V_{op}$ [kN]', xlabel='$Y$ [m]', ylabel='$V^{*}$ [kN]', filename=filename + 'V_op' + '_r0_r1', xmin=0.0, xmax=2.0 * length_xy_quarter, ymin=-max_V_op, ymax=max_V_op, figsize=[5, 5]) # ------------------------------------------------------------ # View # ------------------------------------------------------------ traits_view = View(VGroup( VSplit( Item('lcc_list', editor=lcc_list_editor, show_label=False), Item('lcc@', show_label=False), ), ), resizable=True, scrollable=True, height=1.0, width=1.0)
class MRfour(MushRoofModel): #---------------------------------------------------- # elements #---------------------------------------------------- vtk_r = Float(1.0) # default column fe_column = Instance(FETSEval, transient=True) def _fe_column_default(self): fets = self.fe_quad_serendipity_column fets.vtk_r *= self.vtk_r return fets # default roof fe_roof = Instance(FETSEval, ps_levels=[ 'fe_linear', 'fe2d5_quad_serendipity', 'fe_quad_serendipity_roof', 'fe_quad_serendipity_column', 'fe_quad_lagrange' ]) def _fe_roof_default(self): fets = self.fe_quad_serendipity_roof fets.vtk_r *= self.vtk_r return fets #---------------------------------------------------- # geometric transformation #---------------------------------------------------- hp_shells = Property(List(HPShell), depends_on='+ps_levels, +input') @cached_property def _get_hp_shells(self): X_list = [[0, 0, 0], [7, 0, 0], [0, 7, 0], [7, 7, 0]] return [ HPShell( length_xy_quarter=self.length_xy_quarter, length_z=self.length_z, t_shell=self.t_shell, X0=X, n_elems_xy_quarter=self.n_elems_xy_quarter, n_elems_z=self.n_elems_z, # shift_elems_column = self.shift_elems_column, scalefactor_delta_h=self.scalefactor_delta_h, const_reinf_layer_elem=self.const_reinf_layer_elem, width_top_col=self.width_top_col, # n_elems_col = self.n_elems_col, mushroof_part=self.mushroof_part) for X in X_list ] columns = Property(Instance(GEOColumn), depends_on='+ps_levels, +input') @cached_property def _get_columns(self): ch = self.h_col / self.scalefactor_delta_h X_list = [[3.5, 3.5, -ch], [10.5, 3.5, -ch], [3.5, 10.5, -ch], [10.5, 10.5, -ch]] return [ GEOColumn(width_top=self.width_top_col, X0=X, width_bottom=self.width_bottom_col, h_col=ch) for X in X_list ] #---------------------------------------------------- # grid #---------------------------------------------------- fe_grid_roofs = Property(Instance(FEGrid), depends_on='+ps_levels, +input') @cached_property def _get_fe_grid_roofs(self): return [ FEGrid(coord_min=(0.0, 0.0, 0.0), coord_max=(1.0, 1.0, 1.0), geo_transform=hp_shell, shape=(self.n_elems_xy_quarter, self.n_elems_xy_quarter, self.n_elems_z), fets_eval=self.fe_roof) for hp_shell in self.hp_shells ] fe_grid_columns = Property(Instance(FEGrid), depends_on='+ps_levels, +input') @cached_property def _get_fe_grid_columns(self): return [ FEGrid(coord_min=(0.0, 0.0, 0.0), coord_max=(1.0, 1.0, 1.0), geo_transform=column, shape=(1, 1, 1), fets_eval=self.fe_column) for column in self.columns ] #---------------------------------------------------- # ps_study #---------------------------------------------------- def peval(self): ''' Evaluate the model and return the array of results specified in the method get_sim_outputs. ''' U = self.tloop.eval() U_z = U[self.corner_dof_r00][0, 0, 2] # max_princ_stress = max( self.max_princ_stress._get_field_data().flatten() ) return array( [U_z], # max_princ_stress ], dtype='float_') def get_sim_outputs(self): ''' Specifies the results and their order returned by the model evaluation. ''' return [SimOut(name='u_z_free_corner', unit='m')] # SimOut( name = 'maximum principle stress', unit = 'MPa' ), ] #---------------------------------------------------- # loading and boundaries #---------------------------------------------------- # lc_symm_dict = Property( Dict ) # def _get_lc_symm_dict ( self ): # return {'g_mat_dens_roof':Float( -0.0224, unit = 'MN/m^3' ), # 'g_mat_dens_column':Float( -0.024, unit = 'MN/m^3' ), # 'g_surf_load_gA':Float( -0.20e-3, unit = 'MN/m^2' ), # 's_surf_load':Float( -0.84e-3, unit = 'MN/m^2' ), # 'w_surf_load':Float( -0.13e-3, unit = 'MN/m^2' ), # } #--- LC0: verifying load for ps_study # g = 1.0 kN/m^2 # orientation: global z-direction; f_z = Float(-1e-3, unit='MN/m^3') #--- LC1: dead load # g = 22.4 kN/m^3 # orientation: global z-direction; material_density_roof = Float(-0.0224, unit='MN/m^3') material_density_column = Float(-0.0224, unit='MN/m^3') #--- LC2 additional dead load # gA = 0,20 kN/m^2 # orientation: global z-direction (following the curved structure); surface_load_gA = Float(-0.20e-3, unit='MN/m^2') #--- LC3 snow # s = 0,79 kN/m^2 # orientation: global z-direction (projection); surface_load_s = Float(-0.84e-3, unit='MN/m^2') #--- LC4 wind (pressure) # w = 0,13 kN/m^2 # orientation: local t-direction (surface normal); surface_load_w = Float(-0.13e-3, unit='MN/m^2') force_bc_list = Property(List, depends_on='+ps_levels, +input') @cached_property def _get_force_bc_list(self): # NOTE: additional line-loads at the edge of the roof need to be considered! force_bc_list = [] for roof, column in zip(self.fe_grid_roofs, self.fe_grid_columns): upper_surface = roof[:, :, -1, :, :, -1] # whole_roof = roof[:, :, :, :, :, :] # whole_column = column[:, :, :, :, :, :] force_bc = [ # # LC0: dead load BCSlice(var='f', value=self.f_z, dims=[2], integ_domain='global', slice=upper_surface), # # LC1: dead load # BCSlice( var = 'f', value = self.material_density_roof, dims = [2], # integ_domain = 'global', # slice = whole_roof ), # BCSlice( var = 'f', value = self.material_density_column, dims = [2], # integ_domain = 'global', # slice = whole_column ), # LC2: additional dead load # BCSlice( var = 'f', value = self.surface_load_gA, dims = [2], # integ_domain = 'global', # slice = upper_surface ), # # LC3: snow load # BCSlice( var = 'f', value = self.surface_load_s, dims = [2], # integ_domain = 'global', # slice = upper_surface ) ] force_bc_list += force_bc return force_bc_list displ_bc_list = Property(List, depends_on='+ps_levels, +input') @cached_property def _get_displ_bc_list(self): displ_bc_list = [] for roof, column in zip(self.fe_grid_roofs, self.fe_grid_columns): bc_list = [ BCSlice(var='u', dims=[0, 1, 2], slice=roof[self.n_elems_xy_quarter - 1, self.n_elems_xy_quarter - 1, 0, 0, -1, 0], link_slice=column[0, 0, -1, 0, 0, -1], link_coeffs=[1.0], value=0.), BCSlice(var='u', dims=[0, 1, 2], slice=roof[self.n_elems_xy_quarter - 1, self.n_elems_xy_quarter - 1, 0, -1, 0, 0], link_slice=column[-1, 0, -1, -1, 0, -1], link_coeffs=[1.0], value=0.), BCSlice(var='u', dims=[0, 1, 2], slice=roof[self.n_elems_xy_quarter, self.n_elems_xy_quarter, 0, -1, 0, 0], link_slice=column[-1, -1, -1, -1, -1, -1], link_coeffs=[1.0], value=0.), BCSlice(var='u', dims=[0, 1, 2], slice=roof[self.n_elems_xy_quarter, self.n_elems_xy_quarter, 0, 0, -1, 0], link_slice=column[0, -1, -1, 0, -1, -1], link_coeffs=[1.0], value=0.), BCSlice( var='u', dims=[0, 1, 2], slice=column[:, :, 0, :, :, 0], # slice = column[ 0, 0, 0, -1, -1, 0 ], value=0.0) ] displ_bc_list += bc_list return displ_bc_list wind_bc_list = Property(List, depends_on='+ps_levels, +input') @cached_property def _get_wind_bc_list(self): w_left_edge = 0.91e-3 # [MN/m] w_right_edge = 0.39e-3 # [MN/m] w_bottom_edge_0 = 1.14e-3 # [Mn/m] w_bottom_edge_1 = 0.65e-3 # [Mn/m] w_top_edge_0 = -w_bottom_edge_0 # [Mn/m] w_top_edge_1 = -w_bottom_edge_1 # [Mn/m] w_face_0_left = 0.89e-3 # MN/m^2 w_face_0_right = -0.13e-3 # MN/m^2 w_face_1_left = 0.72e-3 # MN/m^2 w_face_1_right = w_face_0_right r00, r10, r01, r11 = self.fe_grid_roofs left_edge_0 = r00[0, :, -1, 0, :, -1] left_edge_1 = r01[0, :, -1, 0, :, -1] right_edge_0 = r10[-1, :, -1, 0, :, -1] right_edge_1 = r11[-1, :, -1, 0, :, -1] bottom_edge_0 = r00[:, 0, -1, :, 0, -1] bottom_edge_1 = r10[:, 0, -1, :, 0, -1] top_edge_0 = r01[:, -1, -1, :, -1, -1] top_edge_1 = r11[:, -1, -1, :, -1, -1] n_e_q = self.n_elems_xy_quarter face_00_left = r00[:n_e_q, :, -1, :, :, -1] face_00_right = r00[n_e_q:, :, -1, :, :, -1] face_01_left = r01[:n_e_q, :, -1, :, :, -1] face_01_right = r01[n_e_q:, :, -1, :, :, -1] face_10_left = r10[:n_e_q, :, -1, :, :, -1] face_10_right = r10[n_e_q:, :, -1, :, :, -1] face_11_left = r11[:n_e_q, :, -1, :, :, -1] face_11_right = r11[n_e_q:, :, -1, :, :, -1] wind_list = [ # left edge - x direction BCSlice(var='f', dims=[0], slice=left_edge_0, value=w_left_edge), BCSlice(var='f', dims=[0], slice=left_edge_1, value=w_left_edge), # right edge - x direction BCSlice(var='f', dims=[0], slice=right_edge_0, value=w_right_edge), BCSlice(var='f', dims=[0], slice=right_edge_1, value=w_right_edge), # bottom edge - y direction BCSlice(var='f', dims=[1], slice=bottom_edge_0, value=w_bottom_edge_0), BCSlice(var='f', dims=[1], slice=bottom_edge_1, value=w_bottom_edge_1), # top edge - y direction BCSlice(var='f', dims=[1], slice=top_edge_0, value=w_top_edge_0), BCSlice(var='f', dims=[1], slice=top_edge_1, value=w_top_edge_1), # upper face left - left BCSlice(var='f', dims=[2], slice=face_00_left, value=w_face_0_left), BCSlice(var='f', dims=[2], slice=face_01_left, value=w_face_0_left), # upper face left - right BCSlice(var='f', dims=[2], slice=face_00_right, value=w_face_0_right), BCSlice(var='f', dims=[2], slice=face_01_right, value=w_face_0_right), # upper face right - left BCSlice(var='f', dims=[2], slice=face_10_left, value=w_face_1_left), BCSlice(var='f', dims=[2], slice=face_11_left, value=w_face_1_left), # upper face right - right BCSlice(var='f', dims=[2], slice=face_10_right, value=w_face_1_right), BCSlice(var='f', dims=[2], slice=face_11_right, value=w_face_1_right), ] return wind_list link_bc_list = Property(List, depends_on='+ps_levels, +input') @cached_property def _get_link_bc_list(self): r00, r10, r01, r11 = self.fe_grid_roofs link_bc_list = [ BCSlice(var='u', dims=[0, 1, 2], slice=r00[-1, :, -1, -1, :-1, -1], link_slice=r10[0, :, -1, 0, :-1, -1], link_coeffs=[1.0], value=0.), BCSlice(var='u', dims=[0, 1, 2], slice=r01[:, 0, -1, :-1, 0, -1], link_slice=r00[:, -1, -1, :-1, -1, -1], link_coeffs=[1.0], value=0.), BCSlice(var='u', dims=[0, 1, 2], slice=r11[0, :, -1, 0, 1:, -1], link_slice=r01[-1, :, -1, -1, 1:, -1], link_coeffs=[1.0], value=0.), BCSlice(var='u', dims=[0, 1, 2], slice=r10[:, -1, -1, 1:, -1, -1], link_slice=r11[:, 0, -1, 1:, 0, -1], link_coeffs=[1.0], value=0.), ] return link_bc_list #---------------------------------------------------- # response tracer #---------------------------------------------------- rtrace_list = List def _rtrace_list_default(self): return [self.max_princ_stress, self.sig_app, self.u] # time loop tloop = Property(depends_on='+ps_levels, +input') @cached_property def _get_tloop(self): # self.fets.vtk_r *= 0.95 roofs = self.fe_grid_roofs columns = self.fe_grid_columns r00, r10, r01, r11 = roofs self.corner_dof_r00 = r00[0, 0, 0, 0, 0, 0].dofs rtrace_list = self.rtrace_list ts = TS( sdomain=roofs + columns, dof_resultants=True, # bcond_list = self.wind_bc_list + self.displ_bc_list + self.link_bc_list, bcond_list=self.force_bc_list + self.displ_bc_list + self.link_bc_list, # bcond_list = self.displ_bc_list + self.link_bc_list, rtrace_list=rtrace_list) # Add the time-loop control tloop = TLoop(tstepper=ts, tolerance=1e-4, tline=self.tline) return tloop
class LC(HasTraits): '''Loading case class ''' # path to the directory containing the state data files # data_dir = Directory # name of the file containing the hinge forces # or the displacements # file_name = Str(input=True) plt_export = Property def _get_plt_export(self): basename = 'hf_' + self.name + '_' return os.path.join(data_dir, basename) # data filter (used to hide unwanted values, e.g. high sigularities etc.) # data_filter = Callable(input=True) def _data_filter_default(self): return lambda x: x # - do nothing by default # name of the loading case # name = Str(input=True) # category of the loading case # category = Enum('dead-load', 'additional dead-load', 'imposed-load', input=True) # list of keys specifying the names of the loading cases # that can not exist at the same time, i.e. which are exclusive to each other # exclusive_to = List(Str, input=True) def _exclusive_to_default(self): return [] # combination factors (need to be defined in case of imposed loads) # psi_0 = Float(input=True) psi_1 = Float(input=True) psi_2 = Float(input=True) # security factors ULS # gamma_fav = Float(input=True) def _gamma_fav_default(self): if self.category == 'dead-load': return 1.00 if self.category == 'additional dead-load': return 0.00 if self.category == 'imposed-load': return 0.00 gamma_unf = Float(input=True) def _gamma_unf_default(self): if self.category == 'dead-load': return 1.35 if self.category == 'additional dead-load': return 1.35 if self.category == 'imposed-load': return 1.50 # security factors SLS: # (used to distinguish combinations where imposed-loads # or additional-dead-loads are favorable or unfavorable.) # gamma_fav_SLS = Float(input=True) def _gamma_fav_SLS_default(self): if self.category == 'dead-load': return 1.00 elif self.category == 'additional dead-load' or \ self.category == 'imposed-load': return 0.00 gamma_unf_SLS = Float(input=True) def _gamma_unf_SLS_default(self): return 1.00 def _read_data(self, file_name): '''read state data and geo data from csv-file using ';' as filed delimiter and ' ' (blank) as text delimiter. ''' print '*** read state data from file: %s ***' % (file_name) # hinge forces N,V in global coordinates (as obtained from FE-modell) # # input_arr = loadtxt(file_name , delimiter=';', skiprows=2, usecols=(2, 3, 4, 5, 6)) # # hinge forces N*,V* in local (hinge) coordinate system (transformed by inclination angle of the hinges, i.e. shell geometry) # # input_arr = loadtxt(file_name, delimiter=';', skiprows=2, usecols=(2, 3, 4, 8, 9)) # hinge position [m] # X_hf = input_arr[:, 0][:, None] Y_hf = input_arr[:, 1][:, None] Z_hf = input_arr[:, 2][:, None] # INPUT Matthias - RFEM X_hf += 3.5 Y_hf += 3.5 # local hinge forces [kN] # N_ip = input_arr[:, 3][:, None] V_op = input_arr[:, 4][:, None] V_ip = 0. * V_op return { 'X_hf': X_hf, 'Y_hf': Y_hf, 'Z_hf': Z_hf, 'N_ip': N_ip, 'V_ip': V_ip, 'V_op': V_op, } # original data (before filtering) # data_orig = Property(Dict, depends_on='file_name') @cached_property def _get_data_orig(self): return self._read_data(self.file_name) # data (after filtering) # data_dict = Property(Dict, depends_on='file_name, data_filter') @cached_property def _get_data_dict(self): d = {} for k, arr in self.data_orig.items(): d[k] = self.data_filter(arr) return d sr_columns = List(['N_ip', 'V_ip', 'V_op']) geo_columns = List(['X_hf', 'Y_hf', 'Z_hf']) sr_arr = Property(Array) def _get_sr_arr(self): '''return the stress resultants of the loading case as stack of all sr-column arrays. ''' data_dict = self.data_dict return hstack([data_dict[sr_key] for sr_key in self.sr_columns]) geo_data_dict = Property(Array) def _get_geo_data_dict(self): '''Dict of coords as sub-Dict of read in data dict ''' data_dict = self.data_dict geo_data_dict = {} for geo_key in self.geo_columns: geo_data_dict[geo_key] = data_dict[geo_key] return geo_data_dict def _read_data_u(self, file_name_u): '''used to read RFEM files read state data and geo date from csv-file using ';' as filed delimiter and ' ' (blank) as text delimiter for displacement. ''' print '*** read state data from file: %s ***' % (file_name_u) # get the column headings defined in the first row # of the csv displacement input file # file = open(file_name_u, 'r') lines = file.readlines() column_headings = lines[1].split(';') # remove '\n' from last string element in list # column_headings[-1] = column_headings[-1][:-1] column_headings_arr = array(column_headings) # skip the first two columns for 'loadtxt'; # therefore subtract index by 2 # geo_data: # X_idx = where('jX' == column_headings_arr)[0] - 2 Y_idx = where('jY' == column_headings_arr)[0] - 2 Z_idx = where('jZ' == column_headings_arr)[0] - 2 # state_data: # U_x_idx = where('uX' == column_headings_arr)[0] - 2 U_y_idx = where('uY' == column_headings_arr)[0] - 2 U_z_idx = where('uZ' == column_headings_arr)[0] - 2 file.close() input_arr = loadtxt(file_name_u, delimiter=';', skiprows=2, usecols=(2, 3, 4, 5, 6, 7)) # global coords [m] # self.X_u = input_arr[:, X_idx] + 3.5 self.Y_u = input_arr[:, Y_idx] + 3.5 self.Z_u = input_arr[:, Z_idx] print 'self.X_u', self.X_u print 'self.Y_u', self.Y_u # hinge forces [kN] # self.U_x = input_arr[:, U_x_idx] self.U_y = input_arr[:, U_y_idx] self.U_z = input_arr[:, U_z_idx]
class SPIRRIDLAB(HasTraits): '''Class used for elementary parametric studies of spirrid. ''' s = Instance(SPIRRID) evars = DelegatesTo('s') tvars = DelegatesTo('s') q = DelegatesTo('s') exact_arr = Array('float') dpi = Int plot_mode = Enum(['subplots', 'figures']) fig_output_dir = Directory('fig') @on_trait_change('fig_output_dir') def _check_dir(self): if os.access(self.fig_output_dir, os.F_OK) == False: os.mkdir(self.fig_output_dir) e_arr = Property def _get_e_arr(self): return self.s.evar_lst[0] hostname = Property def _get_hostname(self): return gethostname() qname = Str def get_qname(self): if self.qname == '': if isinstance(self.q, types.FunctionType): qname = self.q.__name__ else: # if isinstance(self.q, types.ClassType): qname = self.q.__class__.__name__ else: qname = self.qname return qname show_output = False save_output = True plot_sampling_idx = Array(value=[0, 1], dtype=int) def _plot_sampling(self, i, n_col, sampling_type, p=p, ylim=None, xlim=None): '''Construct a spirrid object, run the calculation plot the mu_q / e curve and save it in the subdirectory. ''' s = self.s s.sampling_type = sampling_type plot_idx = self.plot_sampling_idx qname = self.get_qname() # get n randomly selected realizations from the sampling theta = s.sampling.get_samples(500) tvar_x = s.tvar_lst[plot_idx[0]] tvar_y = s.tvar_lst[plot_idx[1]] min_x, max_x, d_x = s.sampling.get_theta_range(tvar_x) min_y, max_y, d_y = s.sampling.get_theta_range(tvar_y) # for vectorized execution add a dimension for control variable theta_args = [t[:, np.newaxis] for t in theta] q_arr = s.q(self.e_arr[None, :], *theta_args) if self.plot_mode == 'figures': f = p.figure(figsize=(7., 6.)) f.subplots_adjust(left=0.15, right=0.97, bottom=0.15, top=0.92) if self.plot_mode == 'subplots': if i == 0: f = p.figure() p.subplot('2%i%i' % (n_col, (i + 1))) p.plot(theta[plot_idx[0]], theta[plot_idx[1]], 'o', color='grey') p.xlabel('$\lambda$') p.ylabel('$\\xi$') p.xlim(min_x, max_x) p.ylim(min_y, max_y) p.title(s.sampling_type) if self.save_output: fname = os.path.join( self.fig_output_dir, qname + '_sampling_' + s.sampling_type + '.png') p.savefig(fname, dpi=self.dpi) if self.plot_mode == 'figures': f = p.figure(figsize=(7., 5)) f.subplots_adjust(left=0.15, right=0.97, bottom=0.18, top=0.91) elif self.plot_mode == 'subplots': p.subplot('2%i%i' % (n_col, (i + 5))) p.plot(self.e_arr, q_arr.T, color='grey') if len(self.exact_arr) > 0: p.plot(self.e_arr, self.exact_arr, label='exact solution', color='black', linestyle='--', linewidth=2) # numerically obtained result p.plot(self.e_arr, s.mu_q_arr, label='numerical integration', linewidth=3, color='black') p.title(s.sampling_type) p.xlabel('$\\varepsilon$ [-]') p.ylabel(r'$q(\varepsilon;\, \lambda,\, \xi)$') if ylim: p.ylim(0.0, ylim) if xlim: p.xlim(0.0, xlim) p.xticks(position=(0, -.015)) p.legend(loc=2) if self.save_output: fname = os.path.join(self.fig_output_dir, qname + '_' + s.sampling_type + '.png') p.savefig(fname, dpi=self.dpi) sampling_structure_btn = Button(label='compare sampling structure') @on_trait_change('sampling_structure_btn') def sampling_structure(self, **kw): '''Plot the response into the file in the fig subdirectory. ''' if self.plot_mode == 'subplots': p.rcdefaults() else: fsize = 28 p.rcParams['font.size'] = fsize rc('legend', fontsize=fsize - 8) rc('axes', titlesize=fsize) rc('axes', labelsize=fsize + 6) rc('xtick', labelsize=fsize - 8) rc('ytick', labelsize=fsize - 8) rc('xtick.major', pad=8) s_lst = ['TGrid', 'PGrid', 'MCS', 'LHS'] for i, s in enumerate(s_lst): self._plot_sampling(i, len(s_lst), sampling_type=s, **kw) if self.show_output: p.show() n_int_range = Array() #=========================================================================== # Output file names for sampling efficiency #=========================================================================== fname_sampling_efficiency_time_nint = Property def _get_fname_sampling_efficiency_time_nint(self): return self.get_qname( ) + '_' + '%s' % self.hostname + '_time_nint' + '.png' fname_sampling_efficiency_error_nint = Property def _get_fname_sampling_efficiency_error_nint(self): return self.get_qname( ) + '_' + '%s' % self.hostname + '_error_nint' + '.png' fname_sampling_efficiency_error_time = Property def _get_fname_sampling_efficiency_error_time(self): return self.get_qname( ) + '_' + '%s' % self.hostname + '_error_time' + '.png' fnames_sampling_efficiency = Property def _get_fnames_sampling_efficiency(self): fnames = [self.fname_sampling_efficiency_time_nint] if len(self.exact_arr) > 0: fnames += [ self.fname_sampling_efficiency_error_nint, self.fname_sampling_efficiency_error_time ] return fnames #=========================================================================== # Run sampling efficiency studies #=========================================================================== sampling_types = Array(value=['TGrid', 'PGrid', 'MCS', 'LHS'], dtype=str) sampling_efficiency_btn = Button(label='compare sampling efficiency') @on_trait_change('sampling_efficiency_btn') def sampling_efficiency(self): ''' Run the code for all available sampling types. Plot the results. ''' def run_estimation(n_int, sampling_type): # instantiate spirrid with samplingetization methods print 'running', sampling_type, n_int self.s.set(n_int=n_int, sampling_type=sampling_type) n_sim = self.s.sampling.n_sim exec_time = np.sum(self.s.exec_time) return self.s.mu_q_arr, exec_time, n_sim # vectorize the estimation to accept arrays run_estimation_vct = np.vectorize(run_estimation, [object, float, int]) #=========================================================================== # Generate the inspected domain of input parameters using broadcasting #=========================================================================== run_estimation_vct([5], ['PGrid']) sampling_types = self.sampling_types sampling_colors = np.array( ['grey', 'black', 'grey', 'black'], dtype=str) # 'blue', 'green', 'red', 'magenta' sampling_linestyle = np.array(['--', '--', '-', '-'], dtype=str) # run the estimation on all combinations of n_int and sampling_types mu_q, exec_time, n_sim_range = run_estimation_vct( self.n_int_range[:, None], sampling_types[None, :]) p.rcdefaults() f = p.figure(figsize=(12, 6)) f.subplots_adjust(left=0.06, right=0.94) #=========================================================================== # Plot the results #=========================================================================== p.subplot(1, 2, 1) p.title('response for %d $n_\mathrm{sim}$' % n_sim_range[-1, -1]) for i, (sampling, color, linestyle) in enumerate( zip(sampling_types, sampling_colors, sampling_linestyle)): p.plot(self.e_arr, mu_q[-1, i], color=color, label=sampling, linestyle=linestyle) if len(self.exact_arr) > 0: p.plot(self.e_arr, self.exact_arr, color='black', label='Exact solution') p.legend(loc=1) p.xlabel('e', fontsize=18) p.ylabel('q', fontsize=18) # @todo: get n_sim - x-axis p.subplot(1, 2, 2) for i, (sampling, color, linestyle) in enumerate( zip(sampling_types, sampling_colors, sampling_linestyle)): p.loglog(n_sim_range[:, i], exec_time[:, i], color=color, label=sampling, linestyle=linestyle) p.legend(loc=2) p.xlabel('$n_\mathrm{sim}$', fontsize=18) p.ylabel('$t$ [s]', fontsize=18) if self.save_output: basename = self.fname_sampling_efficiency_time_nint fname = os.path.join(self.fig_output_dir, basename) p.savefig(fname, dpi=self.dpi) #=========================================================================== # Evaluate the error #=========================================================================== if len(self.exact_arr) > 0: er = ErrorEval(exact_arr=self.exact_arr) def eval_error(mu_q, error_measure): return error_measure(mu_q) eval_error_vct = np.vectorize(eval_error) error_measures = np.array( [er.eval_error_max, er.eval_error_energy, er.eval_error_rms]) error_table = eval_error_vct(mu_q[:, :, None], error_measures[None, None, :]) f = p.figure(figsize=(14, 6)) f.subplots_adjust(left=0.07, right=0.97, wspace=0.26) p.subplot(1, 2, 1) p.title('max rel. lack of fit') for i, (sampling, color, linestyle) in enumerate( zip(sampling_types, sampling_colors, sampling_linestyle)): p.loglog(n_sim_range[:, i], error_table[:, i, 0], color=color, label=sampling, linestyle=linestyle) #p.ylim( 0, 10 ) p.legend() p.xlabel('$n_\mathrm{sim}$', fontsize=18) p.ylabel('$\mathrm{e}_{\max}$ [-]', fontsize=18) p.subplot(1, 2, 2) p.title('rel. root mean square error') for i, (sampling, color, linestyle) in enumerate( zip(sampling_types, sampling_colors, sampling_linestyle)): p.loglog(n_sim_range[:, i], error_table[:, i, 2], color=color, label=sampling, linestyle=linestyle) p.legend() p.xlabel('$n_{\mathrm{sim}}$', fontsize=18) p.ylabel('$\mathrm{e}_{\mathrm{rms}}$ [-]', fontsize=18) if self.save_output: basename = self.fname_sampling_efficiency_error_nint fname = os.path.join(self.fig_output_dir, basename) p.savefig(fname, dpi=self.dpi) f = p.figure(figsize=(14, 6)) f.subplots_adjust(left=0.07, right=0.97, wspace=0.26) p.subplot(1, 2, 1) p.title('rel. max lack of fit') for i, (sampling, color, linestyle) in enumerate( zip(sampling_types, sampling_colors, sampling_linestyle)): p.loglog(exec_time[:, i], error_table[:, i, 0], color=color, label=sampling, linestyle=linestyle) p.legend() p.xlabel('time [s]', fontsize=18) p.ylabel('$\mathrm{e}_{\max}$ [-]', fontsize=18) p.subplot(1, 2, 2) p.title('rel. root mean square error') for i, (sampling, color, linestyle) in enumerate( zip(sampling_types, sampling_colors, sampling_linestyle)): p.loglog(exec_time[:, i], error_table[:, i, 2], color=color, label=sampling, linestyle=linestyle) p.legend() p.xlabel('time [s]', fontsize=18) p.ylabel('$\mathrm{e}_{\mathrm{rms}}$ [-]', fontsize=18) if self.save_output: basename = self.fname_sampling_efficiency_error_time fname = os.path.join(self.fig_output_dir, basename) p.savefig(fname, dpi=self.dpi) if self.show_output: p.show() #=========================================================================== # Efficiency of numpy versus C code #=========================================================================== run_lst_detailed_config = Property(List) def _get_run_lst_detailed_config(self): run_lst = [] if hasattr(self.q, 'c_code'): run_lst += [ # ('c', # {'cached_dG' : True, # 'compiled_eps_loop' : True }, # 'go-', # '$\mathsf{C}_{\\varepsilon} \{\, \mathsf{C}_{\\theta} \{\, q(\\varepsilon,\\theta) \cdot G[\\theta] \,\}\,\} $ - %4.2f sec', # ), # ('c', # {'cached_dG' : True, # 'compiled_eps_loop' : False }, # 'r-2', # '$\mathsf{Python} _{\\varepsilon} \{\, \mathsf{C}_{\\theta} \{\, q(\\varepsilon,\\theta) \cdot G[\\theta] \,\}\,\} $ - %4.2f sec' # ), # ('c', # {'cached_dG' : False, # 'compiled_eps_loop' : True }, # 'r-2', # '$\mathsf{C}_{\\varepsilon} \{\, \mathsf{C}_{\\theta} \{\, q(\\varepsilon,\\theta) \cdot g[\\theta_1] \cdot \ldots \cdot g[\\theta_m] \,\}\,\} $ - %4.2f sec' # ), ( 'c', { 'cached_dG': False, 'compiled_eps_loop': False }, 'bx-', '$\mathsf{Python} _{\\varepsilon} \{\, \mathsf{C}_{\\theta} \{\, q(\\varepsilon,\\theta) \cdot g[\\theta_1] \cdot \ldots \cdot g[\\theta_m] \,\} \,\} $ - %4.2f sec', ) ] if hasattr(self.q, 'cython_code'): run_lst += [ # ('cython', # {'cached_dG' : True, # 'compiled_eps_loop' : True }, # 'go-', # '$\mathsf{Cython}_{\\varepsilon} \{\, \mathsf{Cython}_{\\theta} \{\, q(\\varepsilon,\\theta) \cdot G[\\theta] \,\}\,\} $ - %4.2f sec', # ), # ('cython', # {'cached_dG' : True, # 'compiled_eps_loop' : False }, # 'r-2', # '$\mathsf{Python} _{\\varepsilon} \{\, \mathsf{Cython}_{\\theta} \{\, q(\\varepsilon,\\theta) \cdot G[\\theta] \,\}\,\} $ - %4.2f sec' # ), # ('cython', # {'cached_dG' : False, # 'compiled_eps_loop' : True }, # 'r-2', # '$\mathsf{Cython}_{\\varepsilon} \{\, \mathsf{Cython}_{\\theta} \{\, q(\\varepsilon,\\theta) \cdot g[\\theta_1] \cdot \ldots \cdot g[\\theta_m] \,\}\,\} $ - %4.2f sec' # ), # ('cython', # {'cached_dG' : False, # 'compiled_eps_loop' : False }, # 'bx-', # '$\mathsf{Python} _{\\varepsilon} \{\, \mathsf{Cython}_{\\theta} \{\, q(\\varepsilon,\\theta) \cdot g[\\theta_1] \cdot \ldots \cdot g[\\theta_m] \,\} \,\} $ - %4.2f sec', # ) ] if hasattr(self.q, '__call__'): run_lst += [ # ('numpy', # {}, # 'y--', # '$\mathsf{Python}_{\\varepsilon} \{\, \mathsf{Numpy}_{\\theta} \{\, q(\\varepsilon,\\theta) \cdot G[\\theta] \,\} \,\} $ - %4.2f sec' # ) ] return run_lst # number of recalculations to get new time. n_recalc = Int(2) def codegen_efficiency(self): # define a tables with the run configurations to start in a batch basenames = [] qname = self.get_qname() s = self.s legend = [] legend_lst = [] time_lst = [] p.figure() for idx, run in enumerate(self.run_lst_detailed_config): code, run_options, plot_options, legend_string = run s.codegen_type = code s.codegen.set(**run_options) print 'run', idx, run_options for i in range(self.n_recalc): s.recalc = True # automatically proagated within spirrid print 'execution time', s.exec_time p.plot(s.evar_lst[0], s.mu_q_arr, plot_options) # @todo: this is not portable!! #legend.append(legend_string % s.exec_time) #legend_lst.append(legend_string[:-12]) time_lst.append(s.exec_time) p.xlabel('strain [-]') p.ylabel('stress') #p.legend(legend, loc = 2) p.title(qname) if self.save_output: print 'saving codegen_efficiency' basename = qname + '_' + 'codegen_efficiency' + '.png' basenames.append(basename) fname = os.path.join(self.fig_output_dir, basename) p.savefig(fname, dpi=self.dpi) self._bar_plot(legend_lst, time_lst) p.title('%s' % s.sampling_type) if self.save_output: basename = qname + '_' + 'codegen_efficiency_%s' % s.sampling_type + '.png' basenames.append(basename) fname = os.path.join(self.fig_output_dir, basename) p.savefig(fname, dpi=self.dpi) if self.show_output: p.show() return basenames #=========================================================================== # Efficiency of numpy versus C code #=========================================================================== run_lst_language_config = Property(List) def _get_run_lst_language_config(self): run_lst = [] if hasattr(self.q, 'c_code'): run_lst += [( 'c', { 'cached_dG': False, 'compiled_eps_loop': False }, 'bx-', '$\mathsf{Python} _{\\varepsilon} \{\, \mathsf{C}_{\\theta} \{\, q(\\varepsilon,\\theta) \cdot g[\\theta_1] \cdot \ldots \cdot g[\\theta_m] \,\} \,\} $ - %4.2f sec', )] if hasattr(self.q, 'cython_code'): run_lst += [( 'cython', { 'cached_dG': False, 'compiled_eps_loop': False }, 'bx-', '$\mathsf{Python} _{\\varepsilon} \{\, \mathsf{Cython}_{\\theta} \{\, q(\\varepsilon,\\theta) \cdot g[\\theta_1] \cdot \ldots \cdot g[\\theta_m] \,\} \,\} $ - %4.2f sec', )] if hasattr(self.q, '__call__'): run_lst += [( 'numpy', {}, 'y--', '$\mathsf{Python}_{\\varepsilon} \{\, \mathsf{Numpy}_{\\theta} \{\, q(\\varepsilon,\\theta) \cdot G[\\theta] \,\} \,\} $ - %4.2f sec' )] return run_lst extra_compiler_args = Bool(True) le_sampling_lst = List(['LHS', 'PGrid']) le_n_int_lst = List([440, 5000]) #=========================================================================== # Output file names for language efficiency #=========================================================================== fnames_language_efficiency = Property def _get_fnames_language_efficiency(self): return [ '%s_codegen_efficiency_%s_extra_%s.png' % (self.qname, self.hostname, extra) for extra in [self.extra_compiler_args] ] language_efficiency_btn = Button(label='compare language efficiency') @on_trait_change('language_efficiency_btn') def codegen_language_efficiency(self): # define a tables with the run configurations to start in a batch home_dir = expanduser("~") # pyxbld_dir = os.path.join(home_dir, '.pyxbld') # if os.path.exists(pyxbld_dir): # shutil.rmtree(pyxbld_dir) python_compiled_dir = os.path.join(home_dir, '.python27_compiled') if os.path.exists(python_compiled_dir): shutil.rmtree(python_compiled_dir) for extra, fname in zip([self.extra_compiler_args], self.fnames_language_efficiency): print 'extra compilation args:', extra legend_lst = [] error_lst = [] n_sim_lst = [] exec_times_sampling = [] meth_lst = zip(self.le_sampling_lst, self.le_n_int_lst) for item, n_int in meth_lst: print 'sampling method:', item s = self.s s.exec_time # eliminate first load time delay (first column) s.n_int = n_int s.sampling_type = item exec_times_lang = [] for idx, run in enumerate(self.run_lst_language_config): code, run_options, plot_options, legend_string = run #os.system('rm -fr ~/.python27_compiled') s.codegen_type = code s.codegen.set(**run_options) if s.codegen_type == 'c': s.codegen.set(**dict(use_extra=extra)) print 'run', idx, run_options exec_times_run = [] for i in range(self.n_recalc): s.recalc = True # automatically propagated exec_times_run.append(s.exec_time) print 'execution time', s.exec_time legend_lst.append(legend_string[:-12]) if s.codegen_type == 'c': # load weave.inline time from tmp file and fix values in time_arr #@todo - does not work on windows import tempfile tdir = tempfile.gettempdir() f = open(os.path.join(tdir, 'w_time'), 'r') value_t = float(f.read()) f.close() exec_times_run[0][1] = value_t exec_times_run[0][2] -= value_t exec_times_lang.append(exec_times_run) else: exec_times_lang.append(exec_times_run) print 'legend_lst', legend_lst n_sim_lst.append(s.sampling.n_sim) exec_times_sampling.append(exec_times_lang) #=========================================================================== # Evaluate the error #=========================================================================== if len(self.exact_arr) > 0: er = ErrorEval(exact_arr=self.exact_arr) error_lst.append((er.eval_error_rms(s.mu_q_arr), er.eval_error_max(s.mu_q_arr))) times_arr = np.array(exec_times_sampling, dtype='d') self._multi_bar_plot(meth_lst, legend_lst, times_arr, error_lst, n_sim_lst) if self.save_output: fname_path = os.path.join(self.fig_output_dir, fname) p.savefig(fname_path, dpi=self.dpi) if self.show_output: p.show() def combination_efficiency(self, tvars_det, tvars_rand): ''' Run the code for all available random parameter combinations. Plot the results. ''' qname = self.get_qname() s = self.s s.set(sampling_type='TGrid') # list of all combinations of response function parameters rv_comb_lst = list(powerset(s.tvars.keys())) p.figure() exec_time_lst = [] for id, rv_comb in enumerate(rv_comb_lst[163:219]): # [1:-1] s.tvars = tvars_det print 'Combination', rv_comb for rv in rv_comb: s.tvars[rv] = tvars_rand[rv] #legend = [] #p.figure() time_lst = [] for idx, run in enumerate(self.run_lst): code, run_options, plot_options, legend_string = run print 'run', idx, run_options s.codegen_type = code s.codegen.set(**run_options) #p.plot(s.evar_lst[0], s.mu_q_arr, plot_options) #print 'integral of the pdf theta', s.eval_i_dG_grid() print 'execution time', s.exec_time time_lst.append(s.exec_time) #legend.append(legend_string % s.exec_time) exec_time_lst.append(time_lst) p.plot(np.array((1, 2, 3, 4)), np.array(exec_time_lst).T) p.xlabel('method') p.ylabel('time') if self.save_output: print 'saving codegen_efficiency' fname = os.path.join( self.fig_output_dir, qname + '_' + 'combination_efficiency' + '.png') p.savefig(fname, dpi=self.dpi) if self.show_output: p.title(s.q.title) p.show() def _bar_plot(self, legend_lst, time_lst): rc('font', size=15) #rc('font', family = 'serif', style = 'normal', variant = 'normal', stretch = 'normal', size = 15) fig = p.figure(figsize=(10, 5)) n_tests = len(time_lst) times = np.array(time_lst) x_norm = times[1] xmax = times.max() rel_xmax = xmax / x_norm rel_times = times / x_norm m = int(rel_xmax % 10) if m < 5: x_max_plt = int(rel_xmax) - m + 10 else: x_max_plt = int(rel_xmax) - m + 15 ax1 = fig.add_subplot(111) p.subplots_adjust(left=0.45, right=0.88) #fig.canvas.set_window_title('window title') pos = np.arange(n_tests) + 0.5 rects = ax1.barh(pos, rel_times, align='center', height=0.5, color='w', edgecolor='k') ax1.set_xlabel('normalized execution time [-]') ax1.axis([0, x_max_plt, 0, n_tests]) ax1.set_yticks(pos) ax1.set_yticklabels(legend_lst) for rect, t in zip(rects, rel_times): width = rect.get_width() xloc = width + (0.03 * rel_xmax) clr = 'black' align = 'left' yloc = rect.get_y() + rect.get_height() / 2.0 ax1.text(xloc, yloc, '%4.2f' % t, horizontalalignment=align, verticalalignment='center', color=clr) #, weight = 'bold') ax2 = ax1.twinx() ax1.plot([1, 1], [0, n_tests], 'k--') ax2.set_yticks([0] + list(pos) + [n_tests]) ax2.set_yticklabels([''] + ['%4.2f s' % s for s in list(times)] + ['']) ax2.set_xticks([0, 1] + range(5, x_max_plt + 1, 5)) ax2.set_xticklabels( ['%i' % s for s in ([0, 1] + range(5, x_max_plt + 1, 5))]) def _multi_bar_plot(self, title_lst, legend_lst, time_arr, error_lst, n_sim_lst): '''Plot the results if the code efficiency. ''' p.rcdefaults() fsize = 14 fig = p.figure(figsize=(15, 3)) rc('font', size=fsize) rc('legend', fontsize=fsize - 2) legend_lst = ['weave', 'cython', 'numpy'] # times are stored in 3d array - dimensions are: n_sampling, n_lang, n_run, n_times = time_arr.shape print 'arr', time_arr.shape times_sum = np.sum(time_arr, axis=n_times) p.subplots_adjust(left=0.1, right=0.95, wspace=0.1, bottom=0.15, top=0.8) for meth_i in range(n_sampling): ax1 = fig.add_subplot(1, n_sampling, meth_i + 1) ax1.set_xlabel('execution time [s]') ytick_pos = np.arange(n_lang) + 1 # ax1.axis([0, x_max_plt, 0, n_lang]) # todo: **2 n_vars if len(self.exact_arr) > 0: ax1.set_title( '%s: $ n_\mathrm{sim} = %s, \mathrm{e}_\mathrm{rms}=%s, \mathrm{e}_\mathrm{max}=%s$' % (title_lst[meth_i][0], self._formatSciNotation('%.2e' % n_sim_lst[meth_i]), self._formatSciNotation('%.2e' % error_lst[meth_i][0]), self._formatSciNotation('%.2e' % error_lst[meth_i][1]))) else: ax1.set_title( '%s: $ n_\mathrm{sim} = %s$' % (title_lst[meth_i][0], self._formatSciNotation('%.2e' % n_sim_lst[meth_i]))) ax1.set_yticks(ytick_pos) if meth_i == 0: ax1.set_yticklabels(legend_lst, fontsize=fsize + 2) else: ax1.set_yticklabels([]) ax1.set_xlim(0, 1.2 * np.max(times_sum[meth_i])) distance = 0.2 height = 1.0 / n_run - distance offset = height / 2.0 colors = ['w', 'w', 'w', 'r', 'y', 'b', 'g', 'm'] hatches = ['/', '\\', 'x', '-', '+', '|', 'o', 'O', '.', '*'] label_lst = ['sampling', 'compilation', 'integration'] for i in range(n_run): pos = np.arange(n_lang) + 1 - offset + i * height end_bar_pos = np.zeros((n_lang, ), dtype='d') for j in range(n_times): if i > 0: label = label_lst[j] else: label = None bar_lengths = time_arr[meth_i, :, i, j] rects = ax1.barh(pos, bar_lengths, align='center', height=height, left=end_bar_pos, color=colors[j], edgecolor='k', hatch=hatches[j], label=label) end_bar_pos += bar_lengths for k in range(n_lang): x_val = times_sum[meth_i, k, i] + 0.01 * np.max(times_sum[meth_i]) ax1.text(x_val, pos[k], '$%4.2f\,$s' % x_val, horizontalalignment='left', verticalalignment='center', color='black') #, weight = 'bold') if meth_i == 0: ax1.text(0.02 * np.max(times_sum[0]), pos[k], '$%i.$' % (i + 1), horizontalalignment='left', verticalalignment='center', color='black', bbox=dict(pad=0., ec="w", fc="w")) p.legend(loc=0) def _formatSciNotation(self, s): # transform 1e+004 into 1e4, for example tup = s.split('e') try: significand = tup[0].rstrip('0').rstrip('.') sign = tup[1][0].replace('+', '') exponent = tup[1][1:].lstrip('0') if significand == '1': # reformat 1x10^y as 10^y significand = '' if exponent: exponent = '10^{%s%s}' % (sign, exponent) if significand and exponent: return r'%s{\cdot}%s' % (significand, exponent) else: return r'%s%s' % (significand, exponent) except IndexError, msg: return s
class YMBAutoCorrelView(HasTraits): correl_data = Instance(YMBAutoCorrel) axes_adjust = List([0.1, 0.1, 0.8, 0.8]) data = Property def _get_data(self): return self.correl_data.data zero = Constant(0) slider_max = Property() def _get_slider_max(self): return self.data.n_cuts - 1 cut_slider = Range('zero', 'slider_max', mode='slider', auto_set=False, enter_set=True, modified=True) vcut_slider = Range('zero', 'slider_max', mode='slider', auto_set=False, enter_set=True, modified=True) cut_slider_on = Bool(False, modified=True) color = Str('blue') figure = Instance(Figure) def _figure_default(self): figure = Figure() figure.add_axes(self.axes_adjust) return figure data_changed = Event(True) @on_trait_change('correl_data.input_change, +modified') def _redraw(self): # TODO: set correct ranges, fix axis range (axes.xlim) print 'redrawing xxxx' figure = self.figure figure.clear() var_data = self.correl_data.corr_arr id = self.cut_slider if self.cut_slider_on == True: i = self.cut_slider j = self.vcut_slider plot_data = getattr(self.data, self.correl_data.var_enum_) # plot_data = vstack( [plot_data[:, i], plot_data[:, j]] ).T # plot only values > -1 # plot_data = plot_data[prod( plot_data >= 0, axis = 1, dtype = bool )] plot_data_x = plot_data[:, i] plot_data_y = plot_data[:, j] plot_data_corr = min(corrcoef(plot_data_x, plot_data_y)) plot_data_corr_spear = spearmanr(plot_data_x, plot_data_y)[0] left, width = 0.1, 0.65 bottom, height = 0.1, 0.65 bottom_h = left_h = left + width + 0.02 rect_scatter = [left, bottom, width, height] rect_histx = [left, bottom_h, width, 0.2] rect_histy = [left_h, bottom, 0.2, height] axScatter = figure.add_axes(rect_scatter) axHistx = figure.add_axes(rect_histx) axHisty = figure.add_axes(rect_histy) axScatter.clear() axHistx.clear() axHisty.clear() from matplotlib.ticker import NullFormatter axHistx.xaxis.set_major_formatter(NullFormatter()) axHisty.yaxis.set_major_formatter(NullFormatter()) axScatter.scatter(plot_data_x, plot_data_y) # binwidth = 0.25 # xymax = max( [max( abs( self.data.cf[:, j] ) ), max( abs( self.data.cf[:, i] ) )] ) # lim = ( int( xymax / binwidth ) + 1 ) * binwidth # axScatter.set_xlim( ( -lim, lim ) ) # axScatter.set_ylim( ( -lim, lim ) ) # bins = arange( -lim, lim + binwidth, binwidth ) axHistx.hist(plot_data_x.compressed(), bins=40) axHisty.hist(plot_data_y.compressed(), bins=40, orientation='horizontal') axHistx.set_xlim(axScatter.get_xlim()) axHisty.set_ylim(axScatter.get_ylim()) axScatter.set_xlabel('$\mathrm{cut\, %i}$' % self.cut_slider, fontsize=16) axScatter.set_ylabel('$\mathrm{cut\, %i}$' % self.vcut_slider, fontsize=16) axScatter.text(axScatter.get_xlim()[0], axScatter.get_ylim()[0], 'actual set correlation %.3f (Pearson), %.3f (Spearman)' % (plot_data_corr, plot_data_corr_spear), color='r') if self.cut_slider_on == False: figure.add_axes(self.axes_adjust) axes = figure.axes[0] axes.clear() x_coor = self.data.x_coord axes.grid() for i in range(0, var_data.shape[1]): axes.plot(x_coor[i:] - x_coor[i], var_data[i, (i):], '-x', color=self.color) # approximate by the polynomial (of the i-th order) # axes.plot( x_coor, self.correl_data.peval( x_coor, self.correl_data.fit_correl ), 'b', linewidth = 3 ) setp(axes.get_xticklabels(), position=(0, -.025)) axes.set_xlabel('$x \, [\mathrm{mm}]$', fontsize=15) axes.set_ylabel('$\mathrm{correlation}$', fontsize=15) axes.set_ylim(-1, 1) self.data_changed = True traits_view = View(Group(Item('correl_data', show_label=False, style='custom'), HGroup( Item('cut_slider_on', label='Scatter'), Item('cut_slider', show_label=False, springy=True, enabled_when='cut_slider_on == True'), Item('vcut_slider', show_label=False, springy=True, enabled_when='cut_slider_on == True'), ), Group(Item('figure', style='custom', editor=MPLFigureEditor(), show_label=False) , id='figure.view'), ), resizable=True, )
class NIDOrderStats(HasTraits): distr_list = List(desc='NID distributions') n = Property(Int, depends_on='distr_list', desc='number of realizations') def _get_n(self): return len(self.distr_list) k = Int(1, auto_set=False, enter_set=True, desc='kth order statistics to evaluate') x_arr = np.linspace(0, 10, 200) cdf_arr = Property(Array, depends_on='distr_list') @cached_property def _get_cdf_arr(self): '''creates a 2D array of shape (m,x_arr) containing m CDFs''' cdf_arr = np.ones((self.n + 2, len(self.x_arr))) for i, distr in enumerate(self.distr_list): cdf_arr[i] = distr.cdf(self.x_arr) return cdf_arr sf_arr = Property(Array, depends_on='distr_list') @cached_property def _get_sf_arr(self): '''creates a 2D array of shape (m,x_arr) containing m SFs''' sf_arr = np.ones((self.n + 2, len(self.x_arr))) for i, distr in enumerate(self.distr_list): sf_arr[i] = distr.sf(self.x_arr) return sf_arr pdf_arr = Property(Array, depends_on='distr_list') @cached_property def _get_pdf_arr(self): '''creates a 2D array of shape (m,x_arr) containing m PDFs''' pdf_arr = np.ones((self.n + 2, len(self.x_arr))) for i, distr in enumerate(self.distr_list): pdf_arr[i] = distr.pdf(self.x_arr) return pdf_arr def kth_pdf(self): '''evaluates the PDF of the kth entry; cases k = 1 and k > 1 are distinguished The most general formula is used here. For higher performance use CIDOrderStats''' if len(self.distr_list) == self.n: n = self.n k = self.k if n >= k: fct = sp.misc.factorial # the constant actually tells how many redundances are present in the summation constant = 1. / (fct(k - 1) * fct(n - k)) summation = np.zeros(len(self.x_arr)) permutations = it.permutations(list(range(n)), n) loop_run = True t = time.clock() while loop_run == True: try: idx = list(next(permutations)) if k == 1: id_pdf = idx[k - 1] pdf = self.pdf_arr[id_pdf] if n == 1: PDF = pdf summation += PDF.flatten() elif n == 2: id_sf = idx[1] sf = self.sf_arr[id_sf] PDF = pdf * sf summation += PDF.flatten() else: id_sf = idx[k:] sf = self.sf_arr[id_sf] PDF = pdf * sf.prod(axis=0) summation += PDF.flatten() else: id_cdf = idx[:k - 1] cdf = self.cdf_arr[id_cdf] id_pdf = idx[k - 1] pdf = self.pdf_arr[id_pdf] id_sf = idx[k:] sf = self.sf_arr[id_sf] PDF = cdf.prod(axis=0) * pdf * sf.prod(axis=0) summation += PDF.flatten() except StopIteration: loop_run = False print(('NID', time.clock() - t, 's')) return constant * summation else: raise ValueError('n < k') else: raise ValueError('%i distributions required, %i given' % (self.n, len(self.distr_list)))
class CompositeCrackBridge(HasTraits): reinforcement_lst = List(Instance(Reinforcement)) w = Float E_m = Float Ll = Float Lr = Float damage_initial_value = Array V_f_tot = Property(depends_on='reinforcement_lst+') @cached_property def _get_V_f_tot(self): V_f_tot = 0.0 for reinf in self.reinforcement_lst: V_f_tot += reinf.V_f return V_f_tot E_c = Property(depends_on='reinforcement_lst+') @cached_property def _get_E_c(self): E_fibers = 0.0 for reinf in self.reinforcement_lst: E_fibers += reinf.V_f * reinf.E_f E_c = self.E_m * (1. - self.V_f_tot) + E_fibers return E_c * (1. + 1e-15) sorted_theta = Property(depends_on='reinforcement_lst+') @cached_property def _get_sorted_theta(self): '''sorts the integral points by bond in descending order''' depsf_arr = np.array([]) V_f_arr = np.array([]) E_f_arr = np.array([]) xi_arr = np.array([]) stat_weights_arr = np.array([]) nu_r_arr = np.array([]) r_arr = np.array([]) for reinf in self.reinforcement_lst: n_int = len(np.hstack((np.array([]), reinf.depsf_arr))) depsf_arr = np.hstack((depsf_arr, reinf.depsf_arr)) V_f_arr = np.hstack((V_f_arr, np.repeat(reinf.V_f, n_int))) E_f_arr = np.hstack((E_f_arr, np.repeat(reinf.E_f, n_int))) xi_arr = np.hstack((xi_arr, np.repeat(reinf.xi, n_int))) # stat_weights_arr = np.hstack((stat_weights_arr, # np.repeat(reinf.stat_weights, n_int))) stat_weights_arr = np.hstack( (stat_weights_arr, reinf.stat_weights)) nu_r_arr = np.hstack((nu_r_arr, reinf.nu_r)) r_arr = np.hstack((r_arr, reinf.r_arr)) argsort = np.argsort(depsf_arr)[::-1] # sorting the masks for the evaluation of F idxs = np.array([]) for i, reinf in enumerate(self.reinforcement_lst): idxs = np.hstack((idxs, i * np.ones_like(reinf.depsf_arr))) masks = [] for i, reinf in enumerate(self.reinforcement_lst): masks.append((idxs == i)[argsort]) max_depsf = [ np.max(reinf.depsf_arr) for reinf in self.reinforcement_lst ] masks = [masks[i] for i in np.argsort(max_depsf)[::-1]] return depsf_arr[argsort], V_f_arr[argsort], E_f_arr[argsort], \ xi_arr[argsort], stat_weights_arr[argsort], \ nu_r_arr[argsort], masks, r_arr[argsort] sorted_depsf = Property(depends_on='reinforcement_lst+') @cached_property def _get_sorted_depsf(self): return self.sorted_theta[0] sorted_V_f = Property(depends_on='reinforcement_lst+') @cached_property def _get_sorted_V_f(self): return self.sorted_theta[1] sorted_E_f = Property(depends_on='reinforcement_lst+') @cached_property def _get_sorted_E_f(self): return self.sorted_theta[2] sorted_xi = Property(depends_on='reinforcement_lst+') @cached_property def _get_sorted_xi(self): return self.sorted_theta[3] sorted_stats_weights = Property(depends_on='reinforcement_lst+') @cached_property def _get_sorted_stats_weights(self): return self.sorted_theta[4] sorted_nu_r = Property(depends_on='reinforcement_lst+') @cached_property def _get_sorted_nu_r(self): return self.sorted_theta[5] sorted_masks = Property(depends_on='reinforcement_lst+') @cached_property def _get_sorted_masks(self): return self.sorted_theta[6] sorted_r = Property(depends_on='reinforcement_lst+') @cached_property def _get_sorted_r(self): return self.sorted_theta[7] sorted_xi_cdf = Property(depends_on='reinforcement_lst+,Ll,Lr') @cached_property def _get_sorted_xi_cdf(self): '''breaking strain: CDF for random and Heaviside for discrete values''' # TODO: does not work for reinforcement types with the same xi methods = [] masks = [] for reinf in self.reinforcement_lst: masks.append(self.sorted_xi == reinf.xi) if isinstance(reinf.xi, FloatType): methods.append(lambda x: 1.0 * (reinf.xi <= x)) elif isinstance(reinf.xi, RV): methods.append(reinf.xi._distr.cdf) elif isinstance(reinf.xi, WeibullFibers): reinf.xi.Ll = self.Ll reinf.xi.Lr = self.Lr methods.append(reinf.xi.cdf) return methods, masks Kf = Property(depends_on='reinforcement_lst+') @cached_property def _get_Kf(self): return self.sorted_V_f * self.sorted_nu_r * \ self.sorted_stats_weights * self.sorted_E_f def vect_xi_cdf(self, epsy, x_short, x_long): Pf = np.zeros_like(self.sorted_depsf) methods, masks = self.sorted_xi_cdf for i, method in enumerate(methods): if method.__doc__ == 'weibull_fibers_cdf_mc': Pf[masks[i]] += method(epsy[masks[i]], self.sorted_depsf[masks[i]], self.sorted_r[masks[i]], x_short[masks[i]], x_long[masks[i]]) elif method.__doc__ == 'weibull_fibers_cdf_cb_elast': Pf[masks[i]] += method(epsy[masks[i]], self.sorted_depsf[masks[i]], self.sorted_r[masks[i]], x_short[masks[i]], x_long[masks[i]]) else: Pf[masks[i]] += method(epsy[masks[i]]) return Pf def dem_depsf_vect(self, damage): '''evaluates the deps_m given deps_f at that point and the damage array''' Kf_intact = self.Kf * (1. - damage) Kf_intact_bonded = np.hstack((0.0, np.cumsum((Kf_intact))))[:-1] Kf_broken = np.sum(self.Kf - Kf_intact) Kf_add = Kf_intact_bonded + Kf_broken Km = (1. - self.V_f_tot) * self.E_m E_mtrx = Km + Kf_add mu_T = np.cumsum((self.sorted_depsf * Kf_intact)[::-1])[::-1] return mu_T / E_mtrx def F(self, dems, amin): '''Auxiliary function (see Part II, appendix B) ''' F = np.zeros_like(self.sorted_depsf) for i, mask in enumerate(self.sorted_masks): depsfi = self.sorted_depsf[mask] demsi = dems[mask] fi = 1. / (depsfi + demsi) F[mask] = np.hstack((np.array([0.0]), cumtrapz(fi, -depsfi))) if i == 0: C = 0.0 else: depsf0 = self.sorted_depsf[self.sorted_masks[i - 1]] depsf1 = depsfi[0] idx = np.sum(depsf0 > depsf1) - 1 depsf2 = depsf0[idx] a1 = np.exp(F[self.sorted_masks[i - 1]][idx] / 2. + np.log(amin)) p = depsf2 - depsf1 q = depsf1 + demsi[0] amin_i = np.sqrt(a1**2 + p / q * a1**2) C = np.log(amin_i / amin) F[mask] += 2 * C return F def clamped(self, Lmin, Lmax, init_dem): a = np.hstack((-Lmin, 0.0, Lmax)) em = np.hstack((init_dem * Lmin, 0.0, init_dem * Lmax)) epsf0 = (self.sorted_depsf / 2. * (Lmin**2 + Lmax**2) + self.w + em[0] * Lmin / 2. + em[-1] * Lmax / 2.) / (Lmin + Lmax) return a, em, epsf0 def profile(self, iter_damage, Lmin, Lmax): ''' ''' # matrix strain derivative with resp. to z as a function of T dems = self.dem_depsf_vect(iter_damage) # initial matrix strain derivative init_dem = dems[0] # debonded length of fibers with Tmax amin = (self.w / (np.abs(init_dem) + np.abs(self.sorted_depsf[0])))**0.5 # integrated f(depsf) - see article F = self.F(dems, amin) # a1 is a(depsf) for double sided pullout a1 = amin * np.exp(F / 2.) #aX = np.exp((-np.log(np.abs(self.sorted_depsf) + dems) + np.log(self.w)) / 2.) if Lmin < a1[0] and Lmax < a1[0]: # all fibers debonded up to Lmin and Lmax a, em, epsf0 = self.clamped(Lmin, Lmax, init_dem) elif Lmin < a1[0] and Lmax >= a1[0]: # all fibers debonded up to Lmin but not up to Lmax amin = -Lmin + np.sqrt(2 * Lmin**2 + 2 * self.w / (self.sorted_depsf[0] + init_dem)) C = np.log(amin**2 + 2 * Lmin * amin - Lmin**2) a2 = np.sqrt(2 * Lmin**2 + np.exp((F + C))) - Lmin if Lmax < a2[0]: a, em, epsf0 = self.clamped(Lmin, Lmax, init_dem) else: if Lmax <= a2[-1]: idx = np.sum(a2 < Lmax) - 1 a = np.hstack((-Lmin, 0.0, a2[:idx + 1], Lmax)) em2 = np.cumsum(np.diff(np.hstack((0.0, a2))) * dems) em = np.hstack((init_dem * Lmin, 0.0, em2[:idx + 1], em2[idx] + (Lmax - a2[idx]) * dems[idx])) um = np.trapz(em, a) epsf01 = em2[:idx + 1] + a2[:idx + 1] * self.sorted_depsf[:idx + 1] epsf02 = (self.w + um + self.sorted_depsf[idx + 1:] / 2. * (Lmin**2 + Lmax**2)) / (Lmin + Lmax) epsf0 = np.hstack((epsf01, epsf02)) else: a = np.hstack((-Lmin, 0.0, a2, Lmax)) em2 = np.cumsum(np.diff(np.hstack((0.0, a2))) * dems) em = np.hstack((init_dem * Lmin, 0.0, em2, em2[-1])) epsf0 = em2 + self.sorted_depsf * a2 elif a1[0] < Lmin and a1[-1] > Lmin: # some fibers are debonded up to Lmin, some are not # boundary condition position idx1 = np.sum(a1 <= Lmin) # a(T) for one sided pullout # first debonded length amin for one sided PO depsfLmin = self.sorted_depsf[idx1] p = (depsfLmin + dems[idx1]) a_short = np.hstack((a1[:idx1], Lmin)) em_short = np.cumsum( np.diff(np.hstack((0.0, a_short))) * dems[:idx1 + 1]) emLmin = em_short[-1] umLmin = np.trapz(np.hstack((0.0, em_short)), np.hstack((0.0, a_short))) amin = -Lmin + np.sqrt(4 * Lmin**2 * p**2 - 4 * p * emLmin * Lmin + 4 * p * umLmin - 2 * p * Lmin**2 * depsfLmin + 2 * p * self.w) / p C = np.log(amin**2 + 2 * amin * Lmin - Lmin**2) a2 = (np.sqrt(2 * Lmin**2 + np.exp(F + C - F[idx1])) - Lmin)[idx1:] # matrix strain profiles - shorter side a_short = np.hstack((-Lmin, -a1[:idx1][::-1], 0.0)) dems_short = np.hstack((dems[:idx1], dems[idx1])) em_short = np.hstack( (0.0, np.cumsum(np.diff(-a_short[::-1]) * dems_short)))[::-1] if a2[-1] > Lmax: idx2 = np.sum(a2 <= Lmax) # matrix strain profiles - longer side a_long = np.hstack((a1[:idx1], a2[:idx2])) em_long = np.cumsum( np.diff(np.hstack((0.0, a_long))) * dems[:idx1 + idx2]) a = np.hstack((a_short, a_long, Lmax)) em = np.hstack( (em_short, em_long, em_long[-1] + (Lmax - a_long[-1]) * dems[idx1 + idx2])) um = np.trapz(em, a) epsf01 = em_long + a_long * self.sorted_depsf[:idx1 + idx2] epsf02 = (self.w + um + self.sorted_depsf[idx1 + idx2:] / 2. * (Lmin**2 + Lmax**2)) / (Lmin + Lmax) epsf0 = np.hstack((epsf01, epsf02)) else: a_long = np.hstack((0.0, a1[:idx1], a2, Lmax)) a = np.hstack((a_short, a_long[1:])) dems_long = dems em_long = np.hstack( (np.cumsum(np.diff(a_long[:-1]) * dems_long))) em_long = np.hstack((em_long, em_long[-1])) em = np.hstack((em_short, em_long)) epsf0 = em_long[:-1] + self.sorted_depsf * a_long[1:-1] elif a1[-1] <= Lmin: # double sided pullout a = np.hstack((-Lmin, -a1[::-1], 0.0, a1, Lmax)) em1 = np.cumsum(np.diff(np.hstack((0.0, a1))) * dems) em = np.hstack((em1[-1], em1[::-1], 0.0, em1, em1[-1])) epsf0 = em1 + self.sorted_depsf * a1 self._x_arr = a self._epsm_arr = em self._epsf0_arr = epsf0 a_short = -a[a < 0.0][1:][::-1] if len(a_short) < len(self.sorted_depsf): a_short = np.hstack( (a_short, Lmin * np.ones(len(self.sorted_depsf) - len(a_short)))) a_long = a[a > 0.0][:-1] if len(a_long) < len(self.sorted_depsf): a_long = np.hstack( (a_long, Lmax * np.ones(len(self.sorted_depsf) - len(a_long)))) return epsf0, a_short, a_long def damage_residuum(self, iter_damage): if np.any(iter_damage < 0.0) or np.any(iter_damage > 1.0): return np.ones_like(iter_damage) * 2.0 else: Lmin = min(self.Ll, self.Lr) Lmax = max(self.Ll, self.Lr) epsf0, x_short, x_long = self.profile(iter_damage, Lmin, Lmax) residuum = self.vect_xi_cdf(epsf0, x_short=x_short, x_long=x_long) - iter_damage return residuum _x_arr = Array def __x_arr_default(self): return np.repeat(1e-10, len(self.sorted_depsf)) _epsm_arr = Array def __epsm_arr_default(self): return np.repeat(1e-10, len(self.sorted_depsf)) _epsf0_arr = Array def __epsf0_arr_default(self): return np.repeat(1e-10, len(self.sorted_depsf)) damage = Property(depends_on='w, Ll, Lr, reinforcement+') @cached_property def _get_damage(self): if self.w == 0.: damage = np.zeros_like(self.sorted_depsf) else: ff = t.clock() try: damage = root(self.damage_residuum, np.ones_like(self.sorted_depsf) * 0.2, method='excitingmixing', options={'maxiter': 100}) if np.any(damage.x < 0.0) or np.any(damage.x > 1.0): raise ValueError damage = damage.x self.damage_initial_value = damage except: print 'fast opt method does not converge: switched to a slower, robust method for this step' damage = root(self.damage_residuum, np.ones_like(self.sorted_depsf) * 0.2, method='krylov') damage = damage.x # print 'damage =', np.sum(damage) / len(damage), 'iteration time =', t.clock() - ff, 'sec' return damage