class CBClampedFiberSP(CBClampedFiber): ''' stress profile for a crack bridged by a short fiber with constant frictional interface to the matrix; clamped fiber end ''' x = Float(0.0, auto_set=False, enter_set=True, input=True, distr=['uniform'], desc='distance from crack') x_label = Str('position [mm]') y_label = Str('force [N]') C_code = Str('') def __call__(self, w, x, tau, l, D_f, E_f, theta, xi, phi, Ll, Lr): T = tau * phi * D_f * pi q = super(CBClampedFiberSP, self).__call__(w, tau, l, D_f, E_f, theta, xi, phi, Ll, Lr) q_x = q * Heaviside(l / 2. - abs(x)) + ( q - T * (abs(x) - l / 2.)) * Heaviside(abs(x) - l / 2.) q_x = q_x * Heaviside(x + Ll) * Heaviside(Lr - x) q_x = q_x * Heaviside(q_x) return q_x
class POClampedFiber(RF): ''' Pullout of fiber from a stiff matrix; stress criterion for debonding, fixed fiber end ''' implements(IRF) title = Str('pullout - clamped fiber with constant friction') image = Image('pics/cb_short_fiber.jpg', size=2) xi = Float(0.0179, auto_set=False, enter_set=True, input=True, distr=['weibull_min', 'uniform']) tau = Float(2.5, auto_set=False, enter_set=True, input=True, distr=['uniform', 'norm']) l = Float(0.0, auto_set=False, enter_set=True, input=True, distr=['uniform'], desc='free length') D_f = Float(26e-3, auto_set=False, input=True, enter_set=True, distr=['uniform', 'weibull_min']) E_f = Float(72.0e3, auto_set=False, enter_set=True, input=True, distr=['uniform']) theta = Float(0.01, auto_set=False, enter_set=True, input=True, distr=['uniform', 'norm'], desc='slack') phi = Float(1., auto_set=False, enter_set=True, input=True, distr=['uniform', 'norm'], desc='bond quality') L = Float(1., auto_set=False, enter_set=True, input=True, distr=['uniform'], desc='embedded length') u = Float(auto_set=False, enter_set=True, ctrl_range=(0.0, 0.02, 100)) x_label = Str('displacement [mm]') y_label = Str('force [N]') C_code = Str('') def __call__(self, u, tau, l, D_f, E_f, theta, xi, phi, L): A = pi * D_f ** 2 / 4. l = l * (1 + theta) u = u - theta * l T = tau * phi * D_f * pi q = (-l * T + sqrt(l ** 2 * T ** 2 + 2 * u * H(u) * E_f * A * T)) # displacement at which the debonding is finished u0 = L * T * (L + 2 * l) / 2 / E_f / A q = q * H(T * L - q) + (T * L + (u - u0) / (l + L) * A * E_f) * H(q - T * L) # ---------------------------------- q = q * H(A * E_f * xi - q) return q
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 fiber_tt_2p(RF): r''' Response Function with two-parameters. ====================================== The function describes a linear dependency with a coefficient :math:`\lambda` up to the threshold :math:`\xi` and zero value beyond the threshold: .. math:: q( \varepsilon; \theta, \lambda ) = \lambda \varepsilon H( \xi - \varepsilon ) where the variables :math:`\lambda=` stiffness parameter and :math:`\xi=` breaking strain are considered random and normally distributed. The function :math:`H(\eta)` represents the Heaviside function with values 0 for :math:`\eta < 0` and 1 for :math:`\eta > 0`. ''' implements(IRF) title = Str('brittle filament') def __call__(self, e, la, xi): ''' Response function of a single fiber ''' return la * e * Heaviside(xi - e) cython_code = ''' # Computation of the q( ... ) function if eps < 0 or eps > xi: q = 0.0 else: q = la * eps ''' c_code = '''
class ConstantFrictionAndFreeLength(RF): ''' ''' implements(IRF) title = Str('pull-out with constant friction and free length ') tau = Float(8, auto_set=False, enter_set=True, distr=['uniform']) # free length l = Float(1, auto_set=False, enter_set=True, distr=['uniform', 'norm']) E = Float(70e9, auto_set=False, enter_set=True, distr=['uniform']) A = Float(5.30929158457e-10, auto_set=False, enter_set=True, distr=['uniform', 'weibull_min']) # waviness in strains slack = Float(0.1, auto_set=False, enter_set=True, distr=['uniform']) u = Float(auto_set=False, enter_set=True, ctrl_range=(0.0, 1.0, 10)) def __call__(self, u, tau, l, E, A, slack): return -l * (1 + slack) * tau * Heaviside(u - l * (slack)) + \ + sqrt((l * (1 + slack) * tau) ** 2 \ + 2 * E * A * (u - (l * slack)) * Heaviside(u - l * (slack)))
class RFSumParams(RF): implements(IRF) title = Str('RFSumParams') a = Float(1, auto_set=False, enter_set=True, distr=['uniform'], loc=1.0, scale=0.1, shape=0.1) b = Float(1, auto_set=False, enter_set=True, distr=['uniform'], loc=1.0, scale=0.1, shape=0.1) c = Float(1, auto_set=False, enter_set=True, distr=['uniform'], loc=1.0, scale=0.1, shape=0.1) d = Float(1, auto_set=False, enter_set=True, distr=['uniform'], loc=1.0, scale=0.1, shape=0.1) ee = Float(1, auto_set=False, enter_set=True, distr=['uniform'], loc=1.0, scale=0.1, shape=0.1) f = Float(1, auto_set=False, enter_set=True, distr=['uniform'], loc=1.0, scale=0.1, shape=0.1) g = Float(1, auto_set=False, enter_set=True, distr=['uniform'], loc=1.0, scale=0.1, shape=0.1) h = Float(1, auto_set=False, enter_set=True, distr=['uniform'], loc=1.0, scale=0.1, shape=0.1) i = Float(1, auto_set=False, enter_set=True, distr=['uniform'], loc=1.0, scale=0.1, shape=0.1) eps = Float(0, ctrl_range=(0, 0.2, 10)) C_code = ''' // Computation of the q( ... ) function //q = ( cos( a ) + cos( b ) + cos( c ) + cos( d ) + cos( ee ) + cos( f ) + cos( g ) + cos( h ) + cos( i )) * eps; q = ( ( a ) + ( b ) + ( c ) + ( d ) + ( ee ) + ( f ) + ( g ) + ( h ) + ( i )) * eps; ''' def __call__(self, eps, a, b, c, d, ee, f, g, h, i): ''' Implements the response function with arrays as variables. first extract the variable discretizations from the orthogonal grid. ''' # broadcast eps also in the xi - dimension # (by multiplying with array containing ones with the same shape as xi ) # # return ( cos( a ) + cos( b ) + cos( c ) + cos( d ) + cos( ee ) + cos( f ) + cos( g ) + cos( h ) + cos( i ) ) * eps return ((a) + (b) + (c) + (d) + (ee) + (f) + (g) + (h) + (i)) * eps;
class S(YMBSource): yarn_type = Enum('__TEST__', changed_source=True, editor=EnumEditor(values=['__TEST__'])) root_dir = Str('') view = View(Item('yarn_type'))
class Preprocessor(HasTraits): title = Str('preprocessor') prep_components = Property(List) def _get_prep_components(self): rf_view = RFModelView(model=default_rf, child=spirrid) rf_view._redraw() rv_view = RVModelView(model=spirrid) return [rf_view, rv_view]
class ConstantFrictionFreeLengthFiniteFiber(RF): ''' ''' implements(IRF) title = Str('pull-out with constant friction and free length ') tau = Float(0.5e6, auto_set=False, enter_set=True, distr=['uniform', 'weibull_min', 'norm']) # free length l = Float(0.01, auto_set=False, enter_set=True, distr=['uniform', 'norm']) E = Float(70e9, auto_set=False, enter_set=True, distr=['uniform']) A = Float(5.30929158457e-10, auto_set=False, enter_set=True, distr=['uniform', 'weibull_min']) # waviness in strains slack = Float(0.0, auto_set=False, enter_set=True, distr=['uniform']) # embedded length L = Float(0.03, auto_set=False, enter_set=True, distr=['uniform']) # breking stress sigma_fu = Float(1200.e6, auto_set=False, enter_set=True, distr=['uniform']) u = Float(auto_set=False, enter_set=True, ctrl_range=(0.0, 1.0, 10)) # def __call__(self, u, tau, l, E, A, slack, L, sigma_fu): ''' method for evaluating the u-F diagram for pullout with constant friction at the interface and free fiber length sticking out of the matrix ''' # defining tau as length dependent tau = tau * sqrt(4 * A * pi) # constitutive law for a pullout without free length q = ( -l * ( 1 + slack ) * tau * Heaviside( u / 2 - l * ( slack ) ) + \ + sqrt( ( l * ( 1 + slack ) * tau ) ** 2 * Heaviside( u / 2 - l * ( slack ) ) \ + 2 * E * A * ( u / 2 - ( l * slack ) ) * Heaviside( u / 2 - l * ( slack ) ) ) ) # deformation of the free length added continuous = q * Heaviside( L - l - q / tau )\ + ( L - l ) * tau * Heaviside( l + q / tau - L ) # a check whether the fiber has reached the breaking stress return continuous * Heaviside(sigma_fu - continuous / A)
class fiber_tt_2p(RF): '''Linear elastic, brittle filament. ''' implements(IRF) title = Str('brittle filament') def __call__(self, e, la, xi): ''' Response function of a single fiber ''' return la * e * Heaviside(xi - e) C_code = '''
class CBEMClampedFiberStressSP(CBEMClampedFiberStress): ''' stress profile for a crack bridged by a fiber with constant frictional interface to the matrix; clamped fiber end ''' x = Float(0.0, auto_set=False, enter_set=True, input=True, distr=['uniform'], desc='distance from crack') x_label = Str('position [mm]') y_label = Str('force [N]') C_code = Str('') def __call__(self, w, x, tau, l, E_f, E_m, theta, xi, phi, Ll, Lr, V_f, r): T = 2. * tau * V_f / r q = super(CBEMClampedFiberStressSP, self).__call__(w, tau, l, E_f, E_m, theta, xi, phi, Ll, Lr, V_f, r) # stress in the free length l = l * (1 + theta) q_l = q * H(l / 2 - abs(x)) # stress in the part, where fiber transmits stress to the matrix q_e = (q - T / V_f * (abs(x) - l / 2.)) * H(abs(x) - l / 2.) # q_e = q_e * H(x + Ll) * H (Lr - x) # far field stress E_c = E_m * (1 - V_f) + E_f * V_f q_const = q * V_f * E_f / E_c # putting all parts together q_x = q_l + q_e q_x = np.maximum(q_x, q_const) return q_x
class Reinforcement(HasTraits): '''common class for all reinforcement types''' label = Str('reinforcement') r = EitherType(klasses=[FloatType, RV]) V_f = Float E_f = Float xi = EitherType(klasses=[FloatType, RV, WeibullFibers]) tau = EitherType(klasses=[FloatType, RV]) n_int = Int @on_trait_change('n_int') def check(self): if self.n_int < 50: print 'Warning: integration with', self.n_int, 'points might not be accurate enough' print 'a minimum of 50 integration points is recommended'
class CBEMClampedFiberSP(CBEMClampedFiber): ''' stress profile for a crack bridged by a short fiber with constant frictional interface to the matrix; clamped fiber end ''' x = Float(0.0, auto_set=False, enter_set=True, input=True, distr=['uniform'], desc='distance from crack') x_label = Str('position [mm]') y_label = Str('force [N]') C_code = Str('') def __call__(self, w, x, tau, l, A_r, E_f, A_m, E_m, theta, xi, phi, Ll, Lr, Nf): D = sqrt(A_r * Nf / pi) * 2 T = tau * phi * D * pi Km = A_m * E_m Kr = A_r * E_f q = super(CBEMClampedFiberSP, self).__call__(w, tau, l, A_r, E_f, A_m, E_m, theta, xi, phi, Ll, Lr, Nf) q_x = q * H(l / 2. - abs(x)) + (q - T * (abs(x) - l / 2.)) * H(abs(x) - l / 2.) # q_x = q_x * H(x + Ll) * H (Lr - x) a = q * Km / (T * (Km + Kr)) q_const = (q - T * a) q_x = maximum(q_x, q_const) return q_x
class fiber_tt_5p_np(RF): ''' Response function of a single fiber ''' implements(IRF) title = Str('brittle filament') def __call__(self, eps, lambd, xi, E_mod, theta, A): ''' Implements the response function with arrays as variables. first extract the variable discretizations from the orthogonal grid. ''' eps_ = (eps - theta * (1 + lambd)) / ((1 + theta) * (1 + lambd)) eps_ *= Heaviside(eps_) eps_grid = eps_ * Heaviside(xi - eps_) q_grid = E_mod * A * eps_grid return q_grid
class fiber_tt_2p(RF): '''Linear elastic, brittle filament. ''' implements(IRF) title = Str('brittle filament') def __call__(self, e, la, xi): ''' Response function of a single fiber ''' return la * e * Heaviside(xi - e) cython_code = ''' # Computation of the q( ... ) function if eps < 0 or eps > xi: q = 0.0 else: q = la * eps ''' weave_code = '''
class fiber_tt_5p_ne(RF): ''' Response function of a single fiber ''' implements(IRF) title = Str('brittle filament') def __call__(self, eps, lambd, xi, E_mod, theta, A): ''' Implements the response function with arrays as variables. first extract the variable discretizations from the orthogonal grid. ''' eps_ = ne.evaluate( "((eps - theta * (1 + lambd)) / ((1 + theta) * (1 + lambd)))") tmp = Heaviside_ne(eps_) eps_ = ne.evaluate('eps_*tmp') tmp = Heaviside_ne(ne.evaluate("(xi - eps_)")) eps_grid = ne.evaluate("eps_ * tmp") q_grid = ne.evaluate("E_mod * A * eps_grid") return q_grid
class RFBase(RF): implements(IRF) title = Str('RFSumParams') a = Float(1, auto_set=False, enter_set=True, distr=['uniform'], loc=1.0, scale=0.1, shape=0.1) b = Float(1, auto_set=False, enter_set=True, distr=['uniform'], loc=1.0, scale=0.1, shape=0.1) c = Float(1, auto_set=False, enter_set=True, distr=['uniform'], loc=1.0, scale=0.1, shape=0.1) d = Float(1, auto_set=False, enter_set=True, distr=['uniform'], loc=1.0, scale=0.1, shape=0.1) ee = Float(1, auto_set=False, enter_set=True, distr=['uniform'], loc=1.0, scale=0.1, shape=0.1) f = Float(1, auto_set=False, enter_set=True, distr=['uniform'], loc=1.0, scale=0.1, shape=0.1) g = Float(1, auto_set=False, enter_set=True, distr=['uniform'], loc=1.0, scale=0.1, shape=0.1) h = Float(1, auto_set=False, enter_set=True, distr=['uniform'], loc=1.0, scale=0.1, shape=0.1) i = Float(1, auto_set=False, enter_set=True, distr=['uniform'], loc=1.0, scale=0.1, shape=0.1) k = Float(1, auto_set=False, enter_set=True, distr=['uniform'], loc=1.0, scale=0.1, shape=0.1)
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 POShortFiber(RF): ''' Pullout of fiber from a stiff matrix; stress criterion for debonding, free fiber end ''' implements(IRF) title = Str('pullout - short fiber with constant friction') image = Image('pics/cb_short_fiber.jpg') xi = Float(0.0179, auto_set=False, enter_set=True, input=True, distr=['weibull_min', 'uniform']) E_f = Float(200e+3, auto_set=False, enter_set=True, desc='filament stiffness [N/mm2]', distr=['uniform', 'norm'], scale=210e3, shape=0) D_f = Float(0.3, auto_set=False, enter_set=True, desc='filament diameter [mm]', distr=['uniform', 'norm'], scale=0.5, shape=0) le = Float(8.5, auto_set=False, enter_set=True, desc='embedded lentgh [mm]', distr=['uniform'], scale=8.5, shape=0) L_f = Float(17.0, auto_set=False, enter_set=True, desc='fiber length [mm]', distr=['uniform', 'norm'], scale=30, shape=0) tau = Float(1.76, auto_set=False, enter_set=True, desc='bond shear stress [N/mm2]', distr=['norm', 'uniform'], scale=1.76, shape=0.5) f = Float(0.03, auto_set=False, enter_set=True, desc='snubbing coefficient', distr=['uniform', 'norm'], scale=0.05, shape=0) phi = Float(0.0, auto_set=False, enter_set=True, desc='inclination angle', distr=['sin2x', 'sin_distr'], scale=1.0, shape=0) l = Float(0.0, auto_set=False, enter_set=True, distr=['uniform'], desc='free length') theta = Float(0.01, auto_set=False, enter_set=True, distr=['uniform', 'norm'], desc='slack') u = Float(ctrl_range=(0, 0.01, 100), auto_set=False, enter_set=True) x_label = Str('displacement [mm]', enter_set=True, auto_set=False) y_label = Str('force [N]', enter_set=True, auto_set=False) C_code = '' def __call__(self, u, tau, L_f, D_f, E_f, le, phi, f, l, theta, xi): l = l * (1 + theta) u = u - theta * l T = tau * pi * D_f E = E_f A = D_f**2 / 4. * pi # debonding stage q_deb = -l * T + sqrt((l * T)**2 + 2 * E * A * T * u * H(u)) # displacement at which debonding is finished u0 = le * T * (le + 2 * l) / 2 / E_f / A q_pull = le * T * ((u0 - u) / (le - u0) + 1) q = q_deb * H(le * T - q_deb) + q_pull * H(q_deb - le * T) # include inclination influence q = q * H(q) * e**(f * phi) # include breaking strain q = q * H(A * E_f * xi - q) return q def get_q_x(self, u, x, tau, L_f, D_f, E_f, z, phi, f, l, theta, xi): q = self.__call__(u, tau, L_f, D_f, E_f, z, phi, f, l, theta, xi) l = l * (1 + theta) T = tau * pi * D_f qfree = q qbond = q - T * (x - l) return qfree * H(l - x) + qbond * H(x - l) traits_view = View(Item('E_f', label='fiber E-mod'), Item('D_f', label='fiber diameter'), Item('f', label='snubbing coef.'), Item('phi', label='inclination angle'), Item('le', label='embedded length'), Item('tau', label='frictional coef.'), resizable=True, scrollable=True, height=0.8, width=0.8, buttons=[OKButton, CancelButton])
class CBClampedFiber(RF): ''' Crack bridged by a short fiber with constant frictional interface to the matrix; clamped fiber end ''' implements(IRF) title = Str('crack bridge - clamped fiber with constant friction') image = Image('pics/cb_short_fiber.jpg') xi = Float(0.0179, auto_set=False, enter_set=True, input=True, distr=['weibull_min', 'uniform']) tau = Float(2.5, auto_set=False, enter_set=True, input=True, distr=['uniform', 'norm']) l = Float(0.0, auto_set=False, enter_set=True, input=True, distr=['uniform'], desc='free length') D_f = Float(26e-3, auto_set=False, input=True, enter_set=True, distr=['uniform', 'weibull_min']) E_f = Float(72.0e3, auto_set=False, enter_set=True, input=True, distr=['uniform']) theta = Float(0.01, auto_set=False, enter_set=True, input=True, distr=['uniform', 'norm'], desc='slack') phi = Float(1., auto_set=False, enter_set=True, input=True, distr=['uniform', 'norm'], desc='bond quality') Ll = Float(1., auto_set=False, enter_set=True, input=True, distr=['uniform'], desc='embedded length - left') Lr = Float(.5, auto_set=False, enter_set=True, input=True, distr=['uniform'], desc='embedded length - right') w = Float(auto_set=False, enter_set=True, input=True, desc='crack width', ctrl_range=(0, 0.01, 100)) x_label = Str('crack opening [mm]') y_label = Str('force [N]') C_code = Str('') # TODO: case where Lmin is zero - gives a double sided pullout # should be one sided though def __call__(self, w, tau, l, D_f, E_f, theta, xi, phi, Ll, Lr): A = pi * D_f**2 / 4. Lmin = minimum(Ll, Lr) Lmax = maximum(Ll, Lr) Lmin = maximum(Lmin - l / 2., 0) Lmax = maximum(Lmax - l / 2., 0) l = minimum(Lr + Ll, l) l = l * (1 + theta) w = w - theta * l T = tau * phi * D_f * pi # double sided debonding l0 = l / 2. q0 = (-l0 * T + sqrt((l0 * T)**2 + w * Heaviside(w) * E_f * A * T)) # displacement at which the debonding to the closer clamp is finished # the closer distance is min(L1,L2) w0 = Lmin * T * (Lmin + 2 * l0) / E_f / A # debonding from one side; the other side is clamped # equal to L1*T + one sided pullout with embedded length Lmax - Lmin and free length 2*L1 + l # force at w0 Q0 = Lmin * T l1 = 2 * Lmin + l q1 = (-(l1) * T + sqrt((l1 * T)**2 + 2 * (w - w0) * Heaviside(w - w0) * E_f * A * T)) + Q0 # displacement at debonding finished at both sides # equals a force of T*(larger clamp distance) # displacement, at which both sides are debonded w1 = w0 + (Lmax - Lmin) * T * ((Lmax - Lmin) + 2 * (l + 2 * Lmin)) / 2 / E_f / A # linear elastic response with stiffness EA/(clamp distance) q2 = E_f * A * (w - w1) / (Lmin + Lmax + l) + (Lmax) * T q0 = q0 * Heaviside(w0 - w) q1 = q1 * Heaviside(w - w0) * Heaviside(w1 - w) q2 = q2 * Heaviside(w - w1) q = q0 + q1 + q2 # include breaking strain q = q * Heaviside(A * E_f * xi - q) #return q0, q1, q2 * Heaviside( A * E_f * xi - q2 ), w0 + theta * l, w1 + theta * l return q
class MushRoofModelNonLin(MRquarter): '''Overload the nonlinear model. ''' #----------------- # composite cross section unit cell: #----------------- # ccs_unit_cell_key = Enum(CCSUnitCell.db.keys(), simdb=True, input=True, auto_set=False, enter_set=True) ccs_unit_cell_ref = Property(Instance(SimDBClass), depends_on='ccs_unit_cell_key') @cached_property def _get_ccs_unit_cell_ref(self): return CCSUnitCell.db[self.ccs_unit_cell_key] # vary the failure strain in PhiFnGeneralExtended: factor_eps_fail = Float(1.0, input=True, ps_levels=(1.0, 1.2, 3)) #----------------- # damage function: #----------------- # material_model = Str(input=True) def _material_model_default(self): # return the material model key of the first DamageFunctionEntry # This is necessary to avoid an ValueError at setup return self.ccs_unit_cell_ref.damage_function_list[0].material_model calibration_test = Str(input=True) def _calibration_test_default(self): # return the material model key of the first DamageFunctionEntry # This is necessary to avoid an ValueError at setup return self.ccs_unit_cell_ref.damage_function_list[0].calibration_test damage_function = Property(Instance(MFnLineArray), depends_on='input_change') @cached_property def _get_damage_function(self): return self.ccs_unit_cell_ref.get_param(self.material_model, self.calibration_test) #----------------- # phi function extended: #----------------- # phi_fn = Property(Instance(PhiFnGeneralExtended), depends_on='input_change,+ps_levels') @cached_property def _get_phi_fn(self): return PhiFnGeneralExtended(mfn=self.damage_function, factor_eps_fail=self.factor_eps_fail) #---------------------------------------------------------------------------------- # mats_eval #---------------------------------------------------------------------------------- # age of the plate at the time of testing # NOTE: that the same phi-function is used independent of age. This assumes a # an afine/proportional damage evolution for different ages. # age = Int( 28, #input = True ) # composite E-modulus # E_c = Property(Float, depends_on='input_change') @cached_property def _get_E_c(self): return self.ccs_unit_cell_ref.get_E_c_time(self.age) # Poisson's ratio # nu = Property(Float, depends_on='input_change') @cached_property def _get_nu(self): return self.ccs_unit_cell_ref.nu # @todo: for mats_eval the information of the unit cell should be used # in order to use the same number of microplanes and model version etc... # mats = Property(Instance(MATS2D5MicroplaneDamage), depends_on='input_change') @cached_property def _get_mats(self): mats = MATS2D5MicroplaneDamage(E=self.E_c, nu=self.nu, n_mp=30, symmetrization='sum-type', model_version='compliance', phi_fn=self.phi_fn) return mats tline = Instance(TLine) def _tline_default(self): return TLine(min=0.0, step=1.0, max=8.0) rtrace_list = List def _rtrace_list_default(self): return [ # RTraceDomainListField( name = 'Displacement' , # var = 'u', idx = 0, warp = True ), # RTraceDomainListField( name = 'Stress' , # var = 'sig_app', idx = 0, warp = True, # record_on = 'update', ), # self.max_princ_stress, RTraceDomainListField(name='Damage', var='omega_mtx', idx=0, warp=True, record_on='update'), ]
class SimBT4PTDB(SimBT4PT): # vary the failure strain in PhiFnGeneralExtended: factor_eps_fail = Float(1.0, input=True, ps_levels=(1.0, 1.2, 3)) #----------------- # composite cross section unit cell: #----------------- # ccs_unit_cell_key = Enum('FIL-10-09_2D-05-11_0.00462_all0', CCSUnitCell.db.keys(), simdb=True, input=True, auto_set=False, enter_set=True) ccs_unit_cell_ref = Property(Instance(SimDBClass), depends_on='ccs_unit_cell_key') @cached_property def _get_ccs_unit_cell_ref(self): return CCSUnitCell.db[self.ccs_unit_cell_key] #----------------- # damage function: #----------------- # material_model = Str(input=True) def _material_model_default(self): # return the material model key of the first DamageFunctionEntry # This is necessary to avoid an ValueError at setup return self.ccs_unit_cell_ref.damage_function_list[0].material_model calibration_test = Str(input=True) def _calibration_test_default(self): # return the material model key of the first DamageFunctionEntry # This is necessary to avoid an ValueError at setup return self.ccs_unit_cell_ref.damage_function_list[0].calibration_test damage_function = Property(Instance(MFnLineArray), depends_on='input_change') @cached_property def _get_damage_function(self): return self.ccs_unit_cell_ref.get_param(self.material_model, self.calibration_test) #----------------- # phi function extended: #----------------- # # phi_fn = Property(Instance(PhiFnGeneralExtended), # depends_on = 'input_change,+ps_levels') # @cached_property # def _get_phi_fn(self): # return PhiFnGeneralExtended(mfn = self.damage_function, # factor_eps_fail = self.factor_eps_fail) #----------------- # phi function General: #----------------- # # definition of 'phi_fn' in order to run scripting # @todo: how can the implementation be changed in order to allow for parameter passing, e.g. 'factor_eps_fail', etc. # phi_fn_class = Enum( PhiFnGeneral, [PhiFnGeneral, PhiFnGeneralExtended, PhiFnGeneralExtendedExp], input=True, ) phi_fn = Property(Instance(phi_fn_class), depends_on='phi_fn_class, input_change, +ps_levels') @cached_property def _get_phi_fn(self): return self.phi_fn_class(mfn=self.damage_function) #---------------------------------------------------------------------------------- # material properties stored in 'ccs' #---------------------------------------------------------------------------------- # concrete matrix E-modulus (taken from 'ccs_unit_cell') # E_m = Property(Float, depends_on='input_change') @cached_property def _get_E_m(self): E_m = self.ccs_unit_cell_ref.get_E_m_time(self.age) print 'E_m (from ccs)', E_m return E_m # composite E-modulus (taken from 'ccs_unit_cell') # E_c = Property(Float, depends_on='input_change') @cached_property def _get_E_c(self): E_c = self.ccs_unit_cell_ref.get_E_c_time(self.age) print 'E_c (from ccs)', E_c return E_c # Poisson's ratio # nu = Property(Float, depends_on='input_change') @cached_property def _get_nu(self): nu = self.ccs_unit_cell_ref.nu print 'nu (from ccs)', nu # set nu explicitly corresponding to settings in 'mats_calib_damage_fn' # print 'nu set explicitly to 0.20' nu = 0.2 return nu
class MRquarterDB(MRquarter): '''get 'phi_fn' as calibrated by the fitter and stored in the DB ''' # vary the failure strain in PhiFnGeneralExtended: factor_eps_fail = Float(1.4, input=True, ps_levels=(1.0, 1.2, 3)) #----------------- # composite cross section unit cell: #----------------- # ccs_unit_cell_key = Enum('FIL-10-09_2D-05-11_0.00462_all0', CCSUnitCell.db.keys(), simdb=True, input=True, auto_set=False, enter_set=True) ccs_unit_cell_ref = Property(Instance(SimDBClass), depends_on='ccs_unit_cell_key') @cached_property def _get_ccs_unit_cell_ref(self): return CCSUnitCell.db[self.ccs_unit_cell_key] #----------------- # damage function: #----------------- # material_model = Str(input=True) def _material_model_default(self): # return the material model key of the first DamageFunctionEntry # This is necessary to avoid an ValueError at setup return self.ccs_unit_cell_ref.damage_function_list[0].material_model calibration_test = Str(input=True) def _calibration_test_default(self): # return the material model key of the first DamageFunctionEntry # This is necessary to avoid an ValueError at setup return self.ccs_unit_cell_ref.damage_function_list[0].calibration_test damage_function = Property(Instance(MFnLineArray), depends_on='+input') @cached_property def _get_damage_function(self): print 'getting damage function' return self.ccs_unit_cell_ref.get_param(self.material_model, self.calibration_test) #----------------- # phi function extended: #----------------- # phi_fn = Property(Instance(PhiFnGeneralExtended), depends_on='+input,+ps_levels') @cached_property def _get_phi_fn(self): return PhiFnGeneralExtendedExp(mfn=self.damage_function, Dfp=0.01, Efp_frac=0.007) # return PhiFnGeneralExtended( mfn = self.damage_function, # factor_eps_fail = self.factor_eps_fail ) #---------------------------------------------------------------------------------- # mats_eval #---------------------------------------------------------------------------------- # age of the plate at the time of testing # NOTE: that the same phi-function is used independent of age. This assumes a # an afine/proportional damage evolution for different ages. # age = Int( 28, # input = True ) # composite E-modulus # E_c = Property(Float, depends_on='+input') @cached_property def _get_E_c(self): return self.ccs_unit_cell_ref.get_E_c_time(self.age) # Poisson's ratio # nu = Property(Float, depends_on='+input') @cached_property def _get_nu(self): return self.ccs_unit_cell_ref.nu
class ResultView(HasTraits): spirrid_view = Instance(SPIRRIDModelView) title = Str('result plot') n_samples = Int(10) 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(True) clear = Button def _clear_fired(self): axes = self.figure.axes[0] axes.clear() self.data_changed = True def get_rvs_theta_arr(self, n_samples): rvs_theta_arr = array([ repeat(value, n_samples) for value in self.spirrid_view.model.rf.param_values ]) for idx, name in enumerate(self.spirrid_view.model.rf.param_keys): rv = self.spirrid_view.model.rv_dict.get(name, None) if rv: rvs_theta_arr[idx, :] = rv.get_rvs_theta_arr(n_samples) return rvs_theta_arr sample = Button(desc='Show samples') def _sample_fired(self): n_samples = 20 self.spirrid_view.model.set( min_eps=0.00, max_eps=self.spirrid_view.max_eps, n_eps=self.spirrid_view.n_eps, ) # get the parameter combinations for plotting rvs_theta_arr = self.get_rvs_theta_arr(n_samples) eps_arr = self.spirrid_view.model.eps_arr figure = self.figure axes = figure.gca() for theta_arr in rvs_theta_arr.T: q_arr = self.spirrid_view.model.rf(eps_arr, *theta_arr) axes.plot(eps_arr, q_arr, color='grey') self.data_changed = True @on_trait_change('spirrid_view.data_changed') def _redraw(self): figure = self.figure axes = figure.gca() mc = self.spirrid_view.model.mean_curve xdata = mc.xdata mean_per_fiber = mc.ydata # total expectation for independent variables = product of marginal expectations mean = mean_per_fiber * self.spirrid_view.mean_parallel_links axes.set_title(self.spirrid_view.plot_title, weight='bold') axes.plot(xdata, mean, linewidth=2, label=self.spirrid_view.run_legend) if self.spirrid_view.stdev: # get the variance at x from SPIRRID variance = self.spirrid_view.model.var_curve.ydata # evaluate variance for the given mean and variance of parallel links # law of total variance D[xy] = E[x]*D[y] + D[x]*[E[y]]**2 variance = self.spirrid_view.mean_parallel_links * variance + \ self.spirrid_view.stdev_parallel_links ** 2 * mean_per_fiber ** 2 stdev = sqrt(variance) axes.plot(xdata, mean + stdev, linewidth=2, color='black', ls='dashed', label='stdev') axes.plot(xdata, mean - stdev, linewidth=2, ls='dashed', color='black') axes.fill_between(xdata, mean + stdev, mean - stdev, color='lightgrey') axes.set_xlabel(self.spirrid_view.label_x, weight='semibold') axes.set_ylabel(self.spirrid_view.label_y, weight='semibold') axes.legend(loc='best') if xdata.any() == 0.: self.figure.clear() self.data_changed = True traits_view = View( HGroup(Item('n_samples', label='No of samples'), Item('sample', show_label=False, resizable=False), Item('clear', show_label=False, resizable=False, springy=False)), Item('figure', show_label=False, editor=MPLFigureEditor()))
class GenExampleDoc(HasTraits): header = Str(''' %s ================================ ''') component_module = None #========================================================================= # Derived traits #========================================================================= component_obj = Property(depends_on='component_module') @cached_property def _get_component_obj(self): return self.component_module.create_doc_object() name = Property(depends_on='component_module') @cached_property def _get_name(self): return self.component_obj.__class__ output_dir = Property(depends_on='component_module') @cached_property def _get_output_dir(self): return os.path.join(EX_OUTPUT_DIR, self.name) rst_file_name = Property(depends_on='component_module') @cached_property def _get_rst_file_name(self): return os.path.join(self.output_dir, 'index.rst') def generate_html(self): print 'generating documentation for', self.name, '...' rst_text = ''' ================================ Parametric study for %s ================================ ''' % self.name dobj = self.component_obj if dobj.s.q.__doc__ != None: rst_text += dobj.s.q.__doc__ rst_text += self.header for st in dobj.sampling_types: rst_text += ''' .. image:: %s_%s.png :width: 24%% ''' % (self.name, st) for st in dobj.sampling_types: rst_text += ''' .. image:: %s_sampling_%s.png :width: 24%% ''' % (self.name, st) rst_text += '\nFollowing oricrete configuration has been used to produce the sampling figures:\n\n' rst_text += '\n>>> print component_obj\n' + str(dobj.s) + '\n' rst_text += ''' Comparison of execution time for different sampling types ========================================================= Execution time evaluated for an increasing number of sampling points n_sim: ''' for basename in dobj.fnames_sampling_efficiency: rst_text += ''' .. image:: %s :width: 100%% ''' % basename print 'written file %s', basename rst_text += '\n' rst_text += ''' Comparison of efficiency for different code types ========================================================= Execution time evaluated for an numpy, weave and cython code: ''' for basename in dobj.fnames_language_efficiency: rst_text += ''' .. image:: %s :width: 100%% ''' % basename print 'written file %s', basename rst_text += '\n' rst_file = open(self.rst_file_name, 'w') rst_file.write(rst_text) rst_file.close()
class CBEMClampedFiberStress(RF): ''' Crack bridged by a fiber with constant frictional interface to the elastic matrix; clamped fiber end; Gives tension. ''' implements(IRF) title = Str('crack bridge - clamped fiber with constant friction') xi = Float(0.0179, auto_set=False, enter_set=True, input=True, distr=['weibull_min', 'uniform']) tau = Float(2.5, auto_set=False, enter_set=True, input=True, distr=['uniform', 'norm']) l = Float(10.0, auto_set=False, enter_set=True, input=True, distr=['uniform'], desc='free length') r = Float(0.013, auto_set=False, input=True, enter_set=True, desc='fiber radius in mm') E_f = Float(72e3, auto_set=False, enter_set=True, input=True, distr=['uniform']) E_m = Float(30e3, auto_set=False, enter_set=True, input=True, distr=['uniform']) V_f = Float(0.0175, auto_set=False, enter_set=True, input=True, distr=['uniform']) theta = Float(0.01, auto_set=False, enter_set=True, input=True, distr=['uniform', 'norm'], desc='slack') phi = Float(1., auto_set=False, enter_set=True, input=True, distr=['uniform', 'norm'], desc='bond quality') Ll = Float(1., auto_set=False, enter_set=True, input=True, distr=['uniform'], desc='embedded length - left', ctrl_range=(0.0, 1.0, 10)) Lr = Float(.5, auto_set=False, enter_set=True, input=True, distr=['uniform'], desc='embedded length - right', ctrl_range=(0.0, 1.0, 10)) w = Float(auto_set=False, enter_set=True, input=True, distr=['uniform'], desc='crack width', ctrl_range=(0.0, 1.0, 10)) x = Float(auto_set=False, enter_set=True, input=True, distr=['uniform'], desc='crack width', ctrl_range=(0.0, 1.0, 10)) x_label = Str('crack opening [mm]') y_label = Str('force [N]') C_code = Str('') def crackbridge(self, w, l, T, Kf, Km, Vf): # Phase A : Both sides debonding . Kc = Kf + Km c = Kc * T * l / 2. q0 = (np.sqrt(c**2 + w * Kf * Km * Kc * T) - c) / Km return q0 / Vf def pullout(self, w, l, T, Kf, Km, Vf, Lmin, Lmax): # Phase B : Debonding of shorter side is finished Kc = Kf + Km c = Kc * T * (Lmin + l) f = T**2 * Lmin**2 * Kc**2 q1 = (np.sqrt(c**2. + f + 2 * w * Kc * T * Kf * Km) - c) / Km return q1 / Vf def linel(self, w, l, T, Kf, Km, Vf, Lmax, Lmin): # Phase C: Both sides debonded - linear elastic behavior. Kc = Kf + Km q2 = (2. * w * Kf * Km + T * Kc * (Lmin**2 + Lmax**2)) / (2. * Km * (Lmax + l + Lmin)) return q2 / Vf def __call__(self, w, tau, l, E_f, E_m, theta, xi, phi, Ll, Lr, V_f, r): # assigning short and long embedded length Lmin = np.minimum(Ll, Lr) Lmax = np.maximum(Ll, Lr) Lmin = np.maximum(Lmin - l / 2., 1e-15) Lmax = np.maximum(Lmax - l / 2., 1e-15) # maximum condition for free length l = np.minimum(l / 2., Lr) + np.minimum(l / 2., Ll) # defining variables w = w - theta * l l = l * (1 + theta) w = H(w) * w T = 2. * tau * V_f / r Km = (1. - V_f) * E_m Kf = V_f * E_f Kc = Km + Kf # double sided debonding # q0 = self.crackbridge(w, l, T, Kr, Km, Lmin, Lmax) q0 = self.crackbridge(w, l, T, Kf, Km, V_f) # displacement at which the debonding to the closer clamp is finished w0 = (Lmin + l) * Lmin * Kc * T / Kf / Km # debonding of one side; the other side is clamped q1 = self.pullout(w, l, T, Kf, Km, V_f, Lmin, Lmax) # displacement at which the debonding is finished at both sides e1 = Lmax * Kc * T / Km / Kf w1 = e1 * (l + Lmax / 2.) + (e1 + e1 * Lmin / Lmax) * Lmin / 2. # debonding completed at both sides, response becomes linear elastic q2 = self.linel(w, l, T, Kf, Km, V_f, Lmax, Lmin) # cut out definition ranges q0 = H(w) * (q0 + 1e-15) * H(w0 - w) q1 = H(w - w0) * q1 * H(w1 - w) q2 = H(w - w1) * q2 # add all parts q = q0 + q1 + q2 # include breaking strain q = q * H(E_f * xi - q) return q
class CBClamped(RF): ''' Crack bridged by a fiber with constant frictional interface to rigid; free fiber end; ''' implements(IRF) title = Str('crack bridge with rigid matrix') tau = Float(2.5, auto_set=False, enter_set=True, input=True, distr=['uniform', 'norm']) r = Float(0.013, auto_set=False, enter_set=True, input=True, distr=['uniform', 'norm'], desc='fiber radius') E_f = Float(72e3, auto_set=False, enter_set=True, input=True, distr=['uniform']) m = Float(5., auto_set=False, enter_set=True, input=True, distr=['uniform']) sV0 = Float(3.e-3, auto_set=False, enter_set=True, input=True, distr=['uniform']) V_f = Float(0.0175, auto_set=False, enter_set=True, input=True, distr=['uniform']) lm = Float(np.inf, auto_set=False, enter_set=True, input=True, distr=['uniform']) w = Float(auto_set=False, enter_set=True, input=True, distr=['uniform'], desc='crack width', ctrl_range=(0.0, 1.0, 10)) x_label = Str('crack opening [mm]') y_label = Str('composite stress [MPa]') C_code = Str('') def e_broken(self, Pf, depsf, r, m, sV0, mask): '''weibull_fibers_cdf_mc''' s_free = ((depsf * (m + 1.) * sV0**m) / (2. * pi * r**2.))**(1. / (m + 1.)) xi_free = s_free * (-np.log(1. - Pf))**(1. / (m + 1)) s_fixed = ((depsf * sV0**m) / (2. * pi * r**2.))**(1. / (m + 1.)) xi_fixed = s_fixed * (-np.log(1. - Pf))**(1. / (m + 1)) return xi_free, xi_fixed def __call__(self, w, tau, E_f, V_f, r, m, sV0, lm, Pf): '''free and fixed fibers combined''' T = 2. * tau / r k = np.sqrt(T / E_f) ef0cb = k * np.sqrt(w) ef0lin = w / lm + T * lm / 4. / E_f depsf = T / E_f a0 = ef0cb / depsf mask = a0 < lm / 2.0 e_int = ef0cb * mask + ef0lin * (mask == False) xi_free, xi_fixed = self.e_broken(Pf, depsf, r, m, sV0, mask) axi = xi_free / depsf mask_xi = axi < lm / 2. e_broken = xi_free / (m + 1.) * (mask_xi) + xi_fixed / 2. * (mask_xi == False) xi = xi_free * (mask_xi) + xi_fixed * (mask_xi == False) e = e_int * (e_int < xi) + e_broken * (e_int > xi) return e * E_f * V_f * r**2 def __call__2(self, w, tau, E_f, V_f, r, m, sV0, Pf): '''free debonding only = __call__ with lm=infty''' #strain and debonded length of intact fibers T = 2. * tau / r ef0_inf = np.sqrt(T * w / E_f) #scale parameter with respect to a reference volume s0 = ((T * (m + 1) * sV0**m) / (2. * E_f * pi * r**2))**(1. / (m + 1)) # strain at fiber breakage ef0_break = s0 * (-np.log(1. - Pf))**(1. / (m + 1)) # debonded length at fiber breakage a_break = ef0_break * E_f / T #mean pullout length of broken fibers mu_Lpo = a_break / (m + 1) # strain carried by broken fibers ef0_residual = T / E_f * mu_Lpo if self.include_pullout == True: ef0_tot = ef0_residual * H(ef0_inf - ef0_break) + ef0_inf * H( ef0_break - ef0_inf) else: ef0_tot = ef0_inf * H(ef0_break - ef0_inf) return ef0_tot * E_f * V_f * r**2
class CBClampedRandXi(RF): ''' Crack bridged by a fiber with constant frictional interface to rigid; free fiber end; ''' implements(IRF) title = Str('crack bridge with rigid matrix') tau = Float(2.5, auto_set=False, enter_set=True, input=True, distr=['uniform', 'norm']) r = Float(0.013, auto_set=False, enter_set=True, input=True, distr=['uniform', 'norm'], desc='fiber radius') E_f = Float(72e3, auto_set=False, enter_set=True, input=True, distr=['uniform']) m = Float(5., auto_set=False, enter_set=True, input=True, distr=['uniform']) sV0 = Float(3.e-3, auto_set=False, enter_set=True, input=True, distr=['uniform']) V_f = Float(0.0175, auto_set=False, enter_set=True, input=True, distr=['uniform']) lm = Float(np.inf, auto_set=False, enter_set=True, input=True, distr=['uniform']) w = Float(auto_set=False, enter_set=True, input=True, distr=['uniform'], desc='crack width', ctrl_range=(0.0, 1.0, 10)) x_label = Str('crack opening [mm]') y_label = Str('composite stress [MPa]') C_code = Str('') def __call__(self, w, tau, E_f, V_f, r, m, sV0): '''free and fixed fibers combined the failure probability of fixed fibers is evaluated by integrating only between -lm/2 and lm/2. Only intact fibers are considered (no pullout contribution)''' T = 2. * tau / r + 1e-10 k = np.sqrt(T / E_f) ef0cb = k * np.sqrt(w) s = ((T * (m + 1) * sV0**m) / (2. * E_f * pi * r**2))**(1. / (m + 1)) Gxi_deb = 1 - np.exp(-(ef0cb / s)**(m + 1)) if w == 1.00: a0 = ef0cb * E_f / T print np.sum(a0 > 500.) / float(np.sum(a0 > -0.1)) return ef0cb * (1 - Gxi_deb) * E_f * V_f * r**2
class SPIRRID( Randomization ): #--------------------------------------------------------------------------------------------- # Range of the control process variable epsilon # Define particular control variable points with # the cv array or an equidistant range with (min, max, n) #--------------------------------------------------------------------------------------------- cv = Array( eps_range = True ) min_eps = Float( 0.0, eps_range = True ) max_eps = Float( 0.0, eps_range = True ) n_eps = Float( 80, eps_range = True ) eps_arr = Property( depends_on = 'eps_change' ) @cached_property def _get_eps_arr( self ): # @todo: !!! # This is a side-effect in a property - CRIME !! [rch] # No clear access interface points - naming inconsistent. # define a clean property with a getter and setter # # if the array of control variable points is not given if len( self.cv ) == 0: n_eps = self.n_eps min_eps = self.min_eps max_eps = self.max_eps return linspace( min_eps, max_eps, n_eps ) else: return self.cv #------------------------------------------------------------------------------------ # Configuration of the algorithm #------------------------------------------------------------------------------------ # # cached_dG_grid: # If set to True, the cross product between the pdf values of all random variables # will be precalculated and stored in an n-dimensional grid # otherwise the product is performed for every epsilon in the inner loop anew # cached_dG = Bool( True, alg_option = True ) # compiled_eps_loop: # If set True, the loop over the control variable epsilon is compiled # otherwise, python loop is used. compiled_eps_loop = Bool( False, alg_option = True ) # compiled_QdG_loop: # If set True, the integration loop over the product between the response function # and the pdf . theta product is performed in c # otherwise the numpy arrays are used. compiled_QdG_loop = Bool( False, alg_option = True ) def _compiled_QdG_loop_changed( self ): '''If the inner loop is not compiled, the outer loop must not be compiled as well. ''' if self.compiled_QdG_loop == False: self.compiled_eps = False arg_list = Property( depends_on = 'rf_change, rand_change, conf_change' ) @cached_property def _get_arg_list( self ): arg_list = [] # create argument string for inline function if self.compiled_eps_loop: arg_list += [ 'mu_q_arr', 'e_arr' ] else: arg_list.append( 'e' ) arg_list += ['%s_flat' % name for name in self.rv_keys ] if self.cached_dG: arg_list += [ 'dG_grid' ] else: arg_list += [ '%s_pdf' % name for name in self.rv_keys ] return arg_list dG_C_code = Property( depends_on = 'rf_change, rand_change, conf_change' ) @cached_property def _get_dG_C_code( self ): if self.cached_dG: # q_g - blitz matrix used to store the grid code_str = '\tdouble pdf = dG_grid(' + \ ','.join( [ 'i_%s' % name for name in self.rv_keys ] ) + \ ');\n' else: # qg code_str = '\tdouble pdf = ' + \ '*'.join( [ ' *( %s_pdf + i_%s)' % ( name, name ) for name in self.rv_keys ] ) + \ ';\n' return code_str #------------------------------------------------------------------------------------ # Configurable generation of C-code for mean curve evaluation #------------------------------------------------------------------------------------ C_code = Property( depends_on = 'rf_change, rand_change, conf_change, eps_change' ) @cached_property def _get_C_code( self ): code_str = '' if self.compiled_eps_loop: # create code string for inline function # code_str += 'for( int i_eps = 0; i_eps < %g; i_eps++){\n' % self.n_eps if self.cached_dG: # multidimensional index needed for dG_grid # blitz arrays must be used also for other arrays # code_str += 'double eps = e_arr( i_eps );\n' else: # pointer access possible for single dimensional arrays # use the pointer arithmetics for accessing the pdfs code_str += '\tdouble eps = *( e_arr + i_eps );\n' else: # create code string for inline function # code_str += 'double eps = e;\n' code_str += 'double mu_q(0);\n' code_str += 'double q(0);\n' code_str += '#line 100\n' # create code for constant params for name, value in list(self.const_param_dict.items()): code_str += 'double %s = %g;\n' % ( name, value ) # generate loops over random params for rv in self.rv_list: name = rv.name n_int = rv.n_int # create the loop over the random variable # code_str += 'for( int i_%s = 0; i_%s < %g; i_%s++){\n' % ( name, name, n_int, name ) if self.cached_dG: # multidimensional index needed for pdf_grid - use blitz arrays # code_str += '\tdouble %s = %s_flat( i_%s );\n' % ( name, name, name ) else: # pointer access possible for single dimensional arrays # use the pointer arithmetics for accessing the pdfs code_str += '\tdouble %s = *( %s_flat + i_%s );\n' % ( name, name, name ) if len( self.rv_keys ) > 0: code_str += self.dG_C_code code_str += self.rf.C_code + \ '// Store the values in the grid\n' + \ '\tmu_q += q * pdf;\n' else: code_str += self.rf.C_code + \ '\tmu_q += q;\n' # close the random loops # for name in self.rv_keys: code_str += '};\n' if self.compiled_eps_loop: if self.cached_dG: # blitz matrix code_str += 'mu_q_arr(i_eps) = mu_q;\n' else: code_str += '*(mu_q_arr + i_eps) = mu_q;\n' code_str += '};\n' else: code_str += 'return_val = mu_q;' return code_str compiler_verbose = Int( 0 ) compiler = Str( 'gcc' ) # Option of eval that induces the calculation of variation # in parallel with the mean value so that interim values of Q_grid # are directly used for both. # implicit_var_eval = Bool( False, alg_option = True ) def _eval( self ): '''Evaluate the integral based on the configuration of algorithm. ''' if self.cached_dG == False and self.compiled_QdG_loop == False: raise NotImplementedError('Configuration for pure Python integration is too slow and is not implemented') self._set_compiler() # prepare the array of the control variable discretization # eps_arr = self.eps_arr mu_q_arr = zeros_like( eps_arr ) # prepare the variable for the variance var_q_arr = None if self.implicit_var_eval: var_q_arr = zeros_like( eps_arr ) # prepare the parameters for the compiled function in # a separate dictionary c_params = {} if self.compiled_eps_loop: # for compiled eps_loop the whole input and output array must be passed to c # c_params['e_arr'] = eps_arr c_params['mu_q_arr'] = mu_q_arr #c_params['n_eps' ] = n_eps if self.compiled_QdG_loop: # prepare the lengths of the arrays to set the iteration bounds # for rv in self.rv_list: c_params[ '%s_flat' % rv.name ] = rv.theta_arr if len( self.rv_list ) > 0: if self.cached_dG: c_params[ 'dG_grid' ] = self.dG_grid else: for rv in self.rv_list: c_params['%s_pdf' % rv.name] = rv.dG_arr else: c_params[ 'dG_grid' ] = self.dG_grid if self.cached_dG: conv = converters.blitz else: conv = converters.default t = time.clock() if self.compiled_eps_loop: # C loop over eps, all inner loops must be compiled as well # if self.implicit_var_eval: raise NotImplementedError('calculation of variance not available in the compiled version') inline( self.C_code, self.arg_list, local_dict = c_params, type_converters = conv, compiler = self.compiler, verbose = self.compiler_verbose ) else: # Python loop over eps # for idx, e in enumerate( eps_arr ): if self.compiled_QdG_loop: if self.implicit_var_eval: raise NotImplementedError('calculation of variance not available in the compiled version') # C loop over random dimensions # c_params['e'] = e # prepare the parameter mu_q = inline( self.C_code, self.arg_list, local_dict = c_params, type_converters = conv, compiler = self.compiler, verbose = self.compiler_verbose ) else: # Numpy loops over random dimensions # # get the rf grid for all combinations of # parameter values # Q_grid = self.rf( e, **self.param_dict ) # multiply the response grid with the contributions # of pdf distributions (weighted by the delta of the # random variable disretization) # if not self.implicit_var_eval: # only mean value needed, the multiplication can be done # in-place Q_grid *= self.dG_grid # sum all the values to get the integral mu_q = sum( Q_grid ) else: # get the square values of the grid Q_grid2 = Q_grid ** 2 # make an inplace product of Q_grid with the weights Q_grid *= self.dG_grid # make an inplace product of the squared Q_grid with the weights Q_grid2 *= self.dG_grid # sum all values to get the mean mu_q = sum( Q_grid ) # sum all squared values to get the variance var_q = sum( Q_grid2 ) - mu_q ** 2 # add the value to the return array mu_q_arr[idx] = mu_q if self.implicit_var_eval: var_q_arr[idx] = var_q duration = time.clock() - t return mu_q_arr, var_q_arr, duration def eval_i_dG_grid( self ): '''Get the integral of the pdf * theta grid. ''' return sum( self.dG_grid ) #--------------------------------------------------------------------------------------------- # Output properties #--------------------------------------------------------------------------------------------- # container for the data obtained in the integration # # This is not only the mean curve but also variance and # execution statistics. Such an implementation # concentrates the critical part of the algorithmic # evaluation and avoids duplication of code and # repeated calls. The results are cached in the tuple. # They are accessed by the convenience properties defined # below. # results = Property( depends_on = 'rand_change, conf_change, eps_change' ) @cached_property def _get_results( self ): return self._eval() #--------------------------------------------------------------------------------------------- # Output accessors #--------------------------------------------------------------------------------------------- # the properties that access the cached results and give them a name mu_q_arr = Property() def _get_mu_q_arr( self ): '''mean of q at eps''' return self.results[0] var_q_arr = Property() def _get_var_q_arr( self ): '''variance of q at eps''' # switch on the implicit evaluation of variance # if it has not been the case so far if not self.implicit_var_eval: self.implicit_var_eval = True return self.results[1] exec_time = Property() def _get_exec_time( self ): '''Execution time of the last evaluation. ''' return self.results[2] mean_curve = Property() def _get_mean_curve( self ): '''Mean response curve. ''' return MFnLineArray( xdata = self.eps_arr, ydata = self.mu_q_arr ) var_curve = Property() def _get_var_curve( self ): '''variance of q at eps''' return MFnLineArray( xdata = self.eps_arr, ydata = self.var_q_arr ) #--------------------------------------------------------------------------------------------- # Auxiliary methods #--------------------------------------------------------------------------------------------- def _set_compiler( self ): '''Catch eventual mismatch between scipy.weave and compiler ''' try: uname = os.uname()[3] except: # it is not Linux - just let it go and suffer return #if self.compiler == 'gcc': #os.environ['CC'] = 'gcc-4.1' #os.environ['CXX'] = 'g++-4.1' #os.environ['OPT'] = '-DNDEBUG -g -fwrapv -O3' traits_view = View( Item( 'rf@', show_label = False ), width = 0.3, height = 0.3, resizable = True, scrollable = True, )
class GenExampleDoc(HasTraits): header = Str(''' Comparison of sampling structure ================================ The different types of sampling for sample size 100. Both variables are randomized with normal distribution. The exact solution is depicted with the black line. The gray lines indicate the sampling. The response diagram correspond to the sampling types (left to right): Regular grid of random variables Grid of constant probabilities8 Monte Carlo sampling Latin Hypercube Sampling ''') demo_module = fiber_tt_2p #=========================================================================== # Derived traits #=========================================================================== demo_object = Property(depends_on='demo_module') @cached_property def _get_demo_object(self): dm = self.demo_module return dm.create_demo_object() qname = Property(depends_on='demo_module') @cached_property def _get_qname(self): return self.demo_object.get_qname() ex_build_dir = Property(depends_on='demo_module') @cached_property def _get_ex_build_dir(self): # check if the directory exists out_dir = os.path.join(EX_BUILD_DIR, self.qname) if not os.path.exists(out_dir): os.makedirs(out_dir) return out_dir ex_cache_dir = Property(depends_on='demo_module') @cached_property def _get_ex_cache_dir(self): # check if the directory exists out_dir = os.path.join(EX_CACHE_DIR, self.qname) if not os.path.exists(out_dir): os.makedirs(out_dir) return out_dir fig_cache_dir = Property() @cached_property def _get_fig_cache_dir(self): # check if the directory exists out_dir = os.path.join(self.ex_cache_dir, 'fig') if not os.path.exists(out_dir): os.makedirs(out_dir) return out_dir rst_file_name = Property(depends_on='demo_module') @cached_property def _get_rst_file_name(self): return os.path.join(self.ex_cache_dir, 'index.rst') def generate_examples_sampling_structure(self): dobj = self.demo_object dobj.set(fig_output_dir=self.ex_cache_dir, show_output=False, dpi=70, save_output=True, plot_mode='figures') dobj.sampling_structure() def generate_examples_sampling_efficiency(self): dobj = self.demo_object dobj.set(fig_output_dir=self.ex_cache_dir, show_output=False, dpi=70, save_output=True, plot_mode='figures') dobj.sampling_efficiency() def generate_examples_language_efficiency(self): dobj = self.demo_object dobj.set(fig_output_dir=self.ex_cache_dir, show_output=False, dpi=70, save_output=True, plot_mode='figures') dobj.codegen_language_efficiency() def generate_examples(self): self.generate_examples_sampling_structure() self.generate_examples_sampling_efficiency() self.generate_examples_language_efficiency() def generate_html(self): print 'generating documentation for', self.qname, '...' rst_text = ''' ================================ Parametric study for %s ================================ ''' % self.qname dobj = self.demo_object if dobj.s.q.__doc__ != None: rst_text += dobj.s.q.__doc__ rst_text += self.header for st in dobj.sampling_lst: rst_text += ''' .. image:: %s_%s.png :width: 24%% ''' % (self.qname, st) for st in dobj.sampling_lst: rst_text += ''' .. image:: %s_sampling_%s.png :width: 24%% ''' % (self.qname, st) rst_text += '\nFollowing spirrid configuration has been used to produce the sampling figures:\n\n' rst_text += '\n>>> print demo_object\n' + str(dobj.s) + '\n' rst_text += ''' Comparison of execution time for different sampling types ========================================================= Execution time evaluated for an increasing number of sampling points n_sim: ''' for basename in dobj.fnames_sampling_efficiency: rst_text += ''' .. image:: %s :width: 100%% ''' % basename print 'written file %s' % basename rst_text += '\n' rst_text += ''' Comparison of efficiency for different code types ========================================================= Execution time evaluated for an numpy, weave and cython code: ''' for basename in dobj.fnames_language_efficiency: rst_text += ''' .. image:: %s :width: 100%% ''' % basename print 'written file %s' % basename rst_text += '\n' print 'writing rst file %s' % self.rst_file_name rst_file = open(self.rst_file_name, 'w') rst_file.write(rst_text) rst_file.close()