class ECBLCalibState(HasStrictTraits): # rupture moment and normal force measured in the calibration experiment # (three point bending test) # Mu = Float(3.5, enter_set = True, auto_set = False, input = True) # [kNm] Nu = Float(0.0, enter_set = True, auto_set = False, input = True) # [kN] #=========================================================================== # Cross Section Specification (Geometry and Layout) #=========================================================================== cs_geo = Instance(ECBCrossSectionGeo) def _cs_geo_default(self): return ECBCrossSectionGeo(notify_change = self.set_modified) cs_state = Property(Instance(ECBCrossSectionState), depends_on = 'cs_geo') @cached_property def _get_cs_state(self): return ECBCrossSectionState(cs_geo = self.cs_geo, notify_change = self.set_modified) notify_change = Callable(None) modified = Event @on_trait_change('+input') def set_modified(self): self.modified = True if self.notify_change != None: self.notify_change() u0 = Property(Array(float), depends_on = 'cs_geo.modified, cs_state.modified') @cached_property def _get_u0(self): u0 = self.cs_state.ecb_law.u0 eps_up = -self.cs_geo.cc_law.eps_c_u self.cs_state.set(eps_up = eps_up) eps_lo = self.cs_state.convert_eps_tex_u_2_lo(u0[0]) return np.array([eps_lo, u0[1] ], dtype = 'float') # iteration counter # n = Int(0) def get_lack_of_fit(self, u): '''Return the difference between 'N_external' and 'N_internal' as well as 'M_external' and 'M_internal' N_c (=compressive force of the compressive zone of the concrete) N_t (=total tensile force of the reinforcement layers) ''' print '--------------------iteration', self.n, '------------------------' self.n += 1 # set iteration counter # eps_up = -self.cs_geo.cc_law.eps_c_u eps_lo = u[0] self.cs_state.set(eps_lo = eps_lo, eps_up = eps_up) eps_tex_u = self.cs_state.convert_eps_lo_2_tex_u(u[0]) self.cs_geo.ecb_law.set_cparams(eps_tex_u, u[1]) N_internal = self.cs_state.N M_internal = self.cs_state.M d_N = N_internal - self.Nu d_M = M_internal - self.Mu return np.array([ d_M, d_N ], dtype = float) # solution vector returned by 'fit_response' # u_sol = Property(Array(Float), depends_on = 'modified') @cached_property def _get_u_sol(self): '''iterate 'eps_t' such that the lack of fit between the calculated normal forces in the tensile reinforcement and the compressive zone (concrete) is smaller then 'xtol' defined in function 'brentq'. NOTE: the method 'get_lack_of_fit' returns the relative error. ''' # use scipy-functionality to get the iterated value of 'eps_t' # NOTE: get_lack_of_fit must have a sign change as a requirement # for the function call 'brentq' to work property. # The method brentq has optional arguments such as # 'xtol' - absolut error (default value = 1.0e-12) # 'rtol' - relative error (not supported at the time) # 'maxiter' - maximum numbers of iterations used # return fsolve(self.get_lack_of_fit, self.u0, xtol = 1.0e-5) #=========================================================================== # Calibrated ecb_law_mfn #=========================================================================== calibrated_ecb_law = Property(depends_on = 'modified') @cached_property def _get_calibrated_ecb_law(self): print 'NEW CALIBRATION' self.cs_geo.ecb_law.set_cparams(*self.u_sol) return self.cs_geo.ecb_law view = View(Item('Mu'), Item('Nu'), buttons = ['OK', 'Cancel'] )
class SimTTBC(IBVModel): '''Simulation: Tensile Test Buttsrap Clamping ''' implements(ISimModel) #=========================================================================== # Speciment geometry and discretization parameters #=========================================================================== specimen_ne_x = Int(2, input=True, label='number of elements in x-direction') specimen_ne_y = Int(2, input=True, label='number of elements in y-direction') specimen_thickness = Float(0.01, input=True, label='thickness of the tensile specimen') specimen_length = Float(0.6, input=True, label='length of the tensile specimen') specimen_width = Float(0.1, input=True, label='length of the tensile specimen') #=========================================================================== # Buttstrap geometry and discretization parameters #=========================================================================== buttstrap_length = Int(0.2, input=True, label='length of the buttstrap') buttstrap_ne_y = Int( 4, input=True, label='number of elements in buttstrap in y-direction') buttstrap_ne_x = Int( 7, input=True, label='number of elements in buttstrap in x-direction') buttstrap_max_thickness = Float(0.04, input=True, label='maximum thickness of the buttstrap') buttstrap_min_thickness = Float( 0.04, input=True, label='mimnimum thickness of the buttstrsp') #=========================================================================== # Elastomer geometry #=========================================================================== elastomer_thickness = Float(0.002, input=True, label='thickness of the elastomer') elastomer_ne_y = Int( 1, input=True, label='number of elements in buttstrap in y-direction') elastomer_ne_x = Property def _get_elastomer_ne_x(self): return self.buttstrap_ne_x #=========================================================================== # Friction interface geometry #=========================================================================== friction_thickness = Float(0.005, input=True, label='thickness of the elastomer') friction_ne_y = Int(1, input=True, label='number of elements in buttstrap in y-direction') friction_ne_x = Property def _get_friction_ne_x(self): return self.buttstrap_ne_x vtk_r = Float(1.0, input=True) #=========================================================================== # Element types #=========================================================================== E_specimen = Int(31000.0, input=True, label='E Modulus of the specimen [MPa]') nu_specimen = Int(0.2, input=True, label='E Modulus of the specimen [-]') specimen_fets = Instance((FETSEval), depends_on='+ps_levels, +input') def _specimen_fets_default(self): # fe_quad_serendipity_roof is defined in base class # connected with material properties of the roof # E_eff = self.E_specimen * self.specimen_width mats = MATS2DElastic(E=E_eff, nu=self.nu_specimen, stress_state='plane_stress') fets = FETS2D4Q8U(mats_eval=mats) fets.vtk_r *= self.vtk_r return fets E_buttstrap = Int(210000.0, input=True, label='E Modulus of the buttstrap [MPa]') nu_buttstrap = Int(0.2, input=True, label='Poisson ratio of the buttstrap [-]') buttstrap_fets = Instance((FETSEval), depends_on='+ps_levels, +input') def _buttstrap_fets_default(self): # fe_quad_serendipity_roof is defined in base class # connected with material properties of the roof # E_eff = self.E_buttstrap * self.specimen_width mats = MATS2DElastic(E=E_eff, nu=self.nu_buttstrap, stress_state='plane_stress') fets = FETS2D4Q8U(mats_eval=mats) fets.vtk_r *= self.vtk_r return fets E_elastomer = Int(100.0, input=True, label='E Modulus of the elastomer [MPa]') nu_elastomer = Int(0.3, input=True, label='Poisson ratio of the elastomer [-]') elastomer_fets = Instance((FETSEval), depends_on='+ps_levels, +input') def _elastomer_fets_default(self): # fe_quad_serendipity_roof is defined in base class # connected with material properties of the roof # E_eff = self.E_buttstrap * self.specimen_width mats = MATS2DElastic(E=E_eff, nu=self.nu_elastomer, stress_state='plane_stress') fets = FETS2D4Q8U(mats_eval=mats) fets.vtk_r *= self.vtk_r return fets g = Float(400000, input=True, label='Shear stiffness between elastomer and specimen') t_max = Float(50, input=True, label='Frictional stress between elastomer and specimen') friction_fets = Instance((FETSEval), depends_on='+ps_levels, +input') def _friction_fets_default(self): width = self.specimen_width G = self.g * width T_max = self.t_max * width ifopen_law = MFnLineArray(ydata=[-1.0e+1, 0., 1.0e+10], xdata=[-1., 0., 1.]) mats_ifopen = MATS1DElastic(stress_strain_curve=ifopen_law) mats = MATS1D5Bond(mats_phase1=MATS1DElastic(E=0), mats_phase2=MATS1DElastic(E=0), mats_ifslip=MATS1DPlastic(E=G, sigma_y=T_max, K_bar=0., H_bar=0.), mats_ifopen=mats_ifopen) fets = FETS1D52L6ULRH(mats_eval=mats) #quadratic fets.vtk_r *= self.vtk_r return fets #=========================================================================== # Geometry transformation #=========================================================================== specimen_cl_geo = Property(depends_on='+ps_levels, +input') @cached_property def _get_specimen_cl_geo(self): def geo_transform(points): points[:, 0] *= self.buttstrap_length points[:, 1] *= self.specimen_thickness return points return geo_transform specimen_fl_geo = Property(depends_on='+ps_levels, +input') @cached_property def _get_specimen_fl_geo(self): def geo_transform(points): points[:, 0] *= self.specimen_length points[:, 0] += self.buttstrap_length points[:, 1] *= self.specimen_thickness return points return geo_transform buttstrap_geo = Property(depends_on='+ps_levels, +input') @cached_property def _get_buttstrap_geo(self): def geo_transform(points): x, y = points.T x *= self.buttstrap_length h_max = self.buttstrap_max_thickness h_min = self.buttstrap_min_thickness y *= (h_max - (h_max - h_min) / self.buttstrap_length * x) y_offset = (self.specimen_thickness + self.friction_thickness + self.elastomer_thickness) points[:, 0], points[:, 1] = x, y + y_offset return points return geo_transform buttstrap_clamp_geo = Property(depends_on='+ps_levels, +input') @cached_property def _get_buttstrap_clamp_geo(self): def geo_transform(points): x, y = points.T x *= self.buttstrap_length x -= self.buttstrap_length y *= self.buttstrap_max_thickness y_offset = (self.specimen_thickness + self.friction_thickness + self.elastomer_thickness) points[:, 0], points[:, 1] = x, y + y_offset return points return geo_transform elastomer_geo = Property(depends_on='+ps_levels, +input') @cached_property def _get_elastomer_geo(self): def geo_transform(points): x, y = points.T x *= self.buttstrap_length h = self.elastomer_thickness y *= h y_offset = self.specimen_thickness + self.friction_thickness points[:, 0], points[:, 1] = x, y + y_offset return points return geo_transform friction_geo = Property(depends_on='+ps_levels, +input') @cached_property def _get_friction_geo(self): def geo_transform(points): x, y = points.T x *= self.buttstrap_length h = self.friction_thickness y *= h y_offset = self.specimen_thickness points[:, 0], points[:, 1] = x, y + y_offset return points return geo_transform #=========================================================================== # FE-grids #=========================================================================== fe_domain = Property(depends_on='+ps_levels, +input') @cached_property def _get_fe_domain(self): return FEDomain() specimen_fl_fe_level = Property(depends_on='+ps_levels, +input') def _get_specimen_fl_fe_level(self): return FERefinementGrid(name='specimen free level', fets_eval=self.specimen_fets, domain=self.fe_domain) specimen_cl_fe_level = Property(depends_on='+ps_levels, +input') def _get_specimen_cl_fe_level(self): return FERefinementGrid(name='specimen clamped level', fets_eval=self.specimen_fets, domain=self.fe_domain) buttstrap_fe_level = Property(depends_on='+ps_levels, +input') def _get_buttstrap_fe_level(self): return FERefinementGrid(name='buttstrap level', fets_eval=self.buttstrap_fets, domain=self.fe_domain) buttstrap_clamp_fe_level = Property(depends_on='+ps_levels, +input') def _get_buttstrap_clamp_fe_level(self): return FERefinementGrid(name='buttstrap clamp level', fets_eval=self.buttstrap_fets, domain=self.fe_domain) elastomer_fe_level = Property(depends_on='+ps_levels, +input') def _get_elastomer_fe_level(self): return FERefinementGrid(name='elastomer level', fets_eval=self.elastomer_fets, domain=self.fe_domain) friction_fe_level = Property(depends_on='+ps_levels, +input') def _get_friction_fe_level(self): return FERefinementGrid(name='friction level', fets_eval=self.friction_fets, domain=self.fe_domain) specimen_fl_fe_grid = Property(Instance(FEGrid), depends_on='+ps_levels, +input') @cached_property def _get_specimen_fl_fe_grid(self): fe_grid = FEGrid(coord_min=(0, 0), coord_max=(1, 1), level=self.specimen_fl_fe_level, geo_transform=self.specimen_fl_geo, shape=(self.specimen_ne_x, self.specimen_ne_y), fets_eval=self.specimen_fets) return fe_grid specimen_cl_fe_grid = Property(Instance(FEGrid), depends_on='+ps_levels, +input') @cached_property def _get_specimen_cl_fe_grid(self): fe_grid = FEGrid(coord_min=(0, 0), coord_max=(1, 1), level=self.specimen_cl_fe_level, geo_transform=self.specimen_cl_geo, shape=(self.buttstrap_ne_x, self.specimen_ne_y), fets_eval=self.specimen_fets) return fe_grid buttstrap_fe_grid = Property(Instance(FEGrid), depends_on='+ps_levels, +input') @cached_property def _get_buttstrap_fe_grid(self): fe_grid = FEGrid(coord_min=(0, 0), coord_max=(1, 1), level=self.buttstrap_fe_level, geo_transform=self.buttstrap_geo, shape=(self.buttstrap_ne_x, self.buttstrap_ne_y), fets_eval=self.buttstrap_fets) return fe_grid buttstrap_clamp_fe_grid = Property(Instance(FEGrid), depends_on='+ps_levels, +input') @cached_property def _get_buttstrap_clamp_fe_grid(self): fe_grid = FEGrid(coord_min=(0, 0), coord_max=(1, 1), level=self.buttstrap_clamp_fe_level, geo_transform=self.buttstrap_clamp_geo, shape=(1, self.buttstrap_ne_y), fets_eval=self.buttstrap_fets) return fe_grid elastomer_fe_grid = Property(Instance(FEGrid), depends_on='+ps_levels, +input') @cached_property def _get_elastomer_fe_grid(self): fe_grid = FEGrid(coord_min=(0, 0), coord_max=(1, 1), level=self.elastomer_fe_level, geo_transform=self.elastomer_geo, shape=(self.elastomer_ne_x, self.elastomer_ne_y), fets_eval=self.elastomer_fets) return fe_grid friction_fe_grid = Property(Instance(FEGrid), depends_on='+ps_levels, +input') @cached_property def _get_friction_fe_grid(self): fe_grid = FEGrid(coord_min=(0, 0), coord_max=(1, 1), level=self.friction_fe_level, geo_transform=self.friction_geo, shape=(self.friction_ne_x, self.friction_ne_y), fets_eval=self.friction_fets) return fe_grid #=========================================================================== # Boundary conditions #=========================================================================== bc_list = Property(depends_on='+ps_levels, +input') @cached_property def _get_bc_list(self): sp_fl_grid = self.specimen_fl_fe_grid sp_cl_grid = self.specimen_cl_fe_grid bs_grid = self.buttstrap_fe_grid bs_clamp_grid = self.buttstrap_clamp_fe_grid el_grid = self.elastomer_fe_grid fl_grid = self.friction_fe_grid link_sp_fl_cl = BCDofGroup( var='u', value=0., dims=[0, 1], get_dof_method=sp_cl_grid.get_right_dofs, get_link_dof_method=sp_fl_grid.get_left_dofs, link_coeffs=[1.]) link_fl_sp = BCDofGroup(var='u', value=0., dims=[0, 1], get_dof_method=fl_grid.get_bottom_dofs, get_link_dof_method=sp_cl_grid.get_top_dofs, link_coeffs=[1.]) link_el_fl = BCDofGroup(var='u', value=0., dims=[0, 1], get_dof_method=el_grid.get_bottom_dofs, get_link_dof_method=fl_grid.get_top_dofs, link_coeffs=[1.]) link_bs_el = BCDofGroup(var='u', value=0., dims=[0, 1], get_dof_method=bs_grid.get_bottom_dofs, get_link_dof_method=el_grid.get_top_dofs, link_coeffs=[1.]) link_bs_clamp = BCDofGroup(var='u', value=0., dims=[0, 1], get_dof_method=bs_clamp_grid.get_right_dofs, get_link_dof_method=bs_grid.get_left_dofs, link_coeffs=[1.]) symx_bc = BCSlice(var='u', slice=sp_fl_grid[-1, :, -1, :], dims=[0], value=0) symy_fl_bc = BCSlice(var='u', slice=sp_fl_grid[:, 0, :, 0], dims=[1], value=0) symy_cl_bc = BCSlice(var='u', slice=sp_cl_grid[:, 0, :, 0], dims=[1], value=0) cntl_bc = BCSlice(var='u', slice=bs_clamp_grid[0, :, 0, :], dims=[0], value=-0.001) return [ symx_bc, symy_fl_bc, symy_cl_bc, cntl_bc, link_sp_fl_cl, link_bs_clamp, link_fl_sp, link_el_fl, link_bs_el ] #---------------------------------------------------- # ps_study #---------------------------------------------------- def peval(self): ''' Evaluate the model and return the array of results specified in the method get_sim_outputs. ''' # DISPLACEMENT # U = self.tloop.eval() def get_sim_outputs(self): ''' Specifies the results and their order returned by the model evaluation. ''' return [ SimOut(name='$u_z$', unit='[mm]'), ] #---------------------------------------------------- # response tracer #---------------------------------------------------- rtrace_list = List def _rtrace_list_default(self): return [self.max_princ_stress, self.sig_app, self.u] max_princ_stress = Instance(RTraceDomainListField) def _max_princ_stress_default(self): return RTraceDomainListField( name='max principle stress', idx=0, var='max_principle_sig', warp=True, # position = 'int_pnts', record_on='update', ) sig_app = Property(Instance(RTraceDomainListField), depends_on='+ps_levels, +input') @cached_property def _get_sig_app(self): return RTraceDomainListField( name='sig_app', position='int_pnts', var='sig_app', record_on='update', ) u = Property(Instance(RTraceDomainListField), depends_on='+ps_levels, +input') @cached_property def _get_u(self): return RTraceDomainListField( name='displacement', var='u', warp=True, record_on='update', ) #---------------------------------------------------- # time loop #---------------------------------------------------- tline = Instance(TLine) def _tline_default(self): return TLine(min=0.0, step=1.0, max=1.0) tloop = Property(depends_on='+ps_levels, +input') @cached_property def _get_tloop(self): ts = TS(sdomain=self.fe_domain, dof_resultants=True, bcond_list=self.bc_list, rtrace_list=self.rtrace_list) # Add the time-loop control # tloop = TLoop(tstepper=ts, tolerance=1e-4, tline=self.tline) return tloop
class GridReinforcement(HasTraits): ''' Class delivering reinforcement ratio for a grid reinforcement of a cross section ''' h = Float( 30, auto_set=False, enter_set=True, # [mm] desc='the height of the cross section', modified=True) w = Float( 100, auto_set=False, enter_set=True, # [mm] desc='the width of the cross section', modified=True) n_f_h = Float( 9, auto_set=False, enter_set=True, # [-] desc='the number of fibers in the height direction', modified=True) n_f_w = Float( 12, auto_set=False, enter_set=True, # [-] desc='the number of fibers in the width direction', modified=True) a_f = Float( 0.89, auto_set=False, enter_set=True, # [m] desc='the cross sectional area of a single fiber', modified=True) A_tot = Property(Float, depends_on='+modified') def _get_A_tot(self): return self.h * self.w A_f = Property(Float, depends_on='+modified') def _get_A_f(self): n_f = self.n_f_h * self.n_f_w a_f = self.a_f return a_f * n_f rho = Property(Float, depends_on='+modified') @cached_property def _get_rho(self): return self.A_f / self.A_tot traits_view = View( VGroup( Group(Item('h', label='height'), Item('w', label='width'), label='cross section dimensions', orientation='vertical'), Group(Item('a_f', label='area of a single fiber'), Item('n_f_h', label='# in height direction'), Item('n_f_w', label='# in width direction'), label='layout of the fiber grid', orientation='vertical'), Item('rho', label='current reinforcement ratio', style='readonly', emphasized=True), # label = 'Cross section parameters', id='scm.cs.params', ), id='scm.cs', dock='horizontal', resizable=True, height=0.8, width=0.8)
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 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 probabilities 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): return self.demo_module.create_demo_object() qname = Property(depends_on='demo_module') @cached_property def _get_qname(self): return self.demo_object.get_qname() output_dir = Property(depends_on='demo_module') @cached_property def _get_output_dir(self): return os.path.join(EX_OUTPUT_DIR, self.qname) rst_file_name = Property(depends_on='demo_module') @cached_property def _get_rst_file_name(self): return os.path.join(self.output_dir, 'index.rst') def generate_examples_sampling_structure(self): dobj = self.demo_object dobj.set(fig_output_dir=self.output_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.output_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.output_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_types: rst_text += ''' .. image:: %s_%s.png :width: 24%% ''' % (self.qname, st) for st in dobj.sampling_types: 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' rst_file = open(self.rst_file_name, 'w') rst_file.write(rst_text) rst_file.close()
class CompositeCrackBridgeView(ModelView): model = Instance(CompositeCrackBridge) results = Property(depends_on='model.E_m, model.w, model.Ll, model.Lr, model.reinforcement_lst+') @cached_property def _get_results(self): if self.model.w <= 0.0: self.model.w = 1e-15 sigma_c = self.model.sigma_c # Kf_broken = np.sum(self.model.cont_fibers.sorted_V_f * self.model.cont_fibers.sorted_nu_r * # self.model.cont_fibers.sorted_stats_weights * self.model.cont_fibers.sorted_E_f * # self.model.cont_fibers.damage) if self.model.Ll > self.model.Lr: return -self.model._x_arr[::-1], self.model._epsm_arr[::-1], sigma_c, self.model._epsf_arr[::-1] else: return self.model._x_arr, self.model._epsm_arr, sigma_c, self.model._epsf_arr x_arr = Property(depends_on='model.E_m, model.w, model.Ll, model.Lr, model.reinforcement_lst+') @cached_property def _get_x_arr(self): return self.results[0] epsm_arr = Property(depends_on='model.E_m, model.w, model.Ll, model.Lr, model.reinforcement_lst+') @cached_property def _get_epsm_arr(self): return self.results[1] epsf_arr = Property(depends_on='model.E_m, model.w, model.Ll, model.Lr, model.reinforcement_lst+') @cached_property def _get_epsf_arr(self): return self.results[3] sigma_c = Property(depends_on='model.E_m, model.w, model.Ll, model.Lr, model.reinforcement_lst+') @cached_property def _get_sigma_c(self): return self.results[2] def sigma_c_arr(self, w_arr, u=False, damage=False): sigma_c_lst = [] u_lst = [] damage_lst = [] for i, w in enumerate(w_arr): self.model.w = w sigma_c_lst.append(self.sigma_c) if u == True: u_lst.append(self.u_evaluated) if damage == True: damage_lst.append(np.sum(self.model.cont_fibers.damage * self.model.cont_fibers.sorted_stats_weights * self.model.cont_fibers.sorted_nu_r)) if u == True or damage == True: return np.array(sigma_c_lst), np.array(u_lst), np.array(damage_lst) else: return np.array(sigma_c_lst) def secant_K(self, w_arr): secant_K_lst = [] for w_i in w_arr: self.model.w = w_i secant_K_lst.append(self.model.secant_K) return np.array(secant_K_lst) u_evaluated = Property(depends_on='model.E_m, model.w, model.Ll, model.Lr, model.reinforcement_lst+') @cached_property def _get_u_evaluated(self): return self.model.w + np.trapz(self.epsm_arr, self.x_arr) sigma_c_max = Property(depends_on='model.E_m, model.w, model.Ll, model.Lr, model.reinforcement_lst+') @cached_property def _get_sigma_c_max(self): def minfunc_sigma(w): self.model.w = w stiffness_loss = np.sum(self.model.cont_fibers.Kf * self.model.cont_fibers.damage) / np.sum(self.model.cont_fibers.Kf) if stiffness_loss > 0.90: return 1. + w #plt.plot(w, self.sigma_c, 'ro') return -self.sigma_c def residuum_stiffness(w): self.model.w = w stiffness_loss = np.sum(self.model.Kf * self.model.damage) / np.sum(self.model.Kf) if stiffness_loss > 0.90: return 1. + w if stiffness_loss < 0.65 and stiffness_loss > 0.45: residuum = 0.0 else: residuum = stiffness_loss - 0.5 return residuum if len(self.model.sorted_reinf_lst[0]) == 0: # there are only short fibers def minfunc_short_fibers(w): self.model.w = w return -self.sigma_c w_max = fminbound(minfunc_short_fibers, 0.0, 3.0, maxfun=10, disp=0) return self.sigma_c, w_max else: # continuous or mixed fibers try: w_max = brentq(residuum_stiffness, 0.0, min(0.1 * (self.model.Ll + self.model.Lr), 20.)) except: w_max = 0.03 * (self.model.Ll + self.model.Lr) w_points = np.linspace(0, w_max, len(self.model.reinforcement_lst) + 1) w_maxima = [] sigma_maxima = [] for i, w in enumerate(w_points[1:]): w_maxima.append(fminbound(minfunc_sigma, w_points[i], w_points[i + 1], maxfun=10, disp=0)) sigma_maxima.append(self.sigma_c) return sigma_maxima[np.argmax(np.array(sigma_maxima))], w_maxima[np.argmax(np.array(sigma_maxima))] def apply_load(self, sigma): if sigma > self.sigma_c_max[0]: raise ValueError('applied load ', sigma , 'MPa is larger than composite strength ', self.sigma_c_max[0], 'MPa') else: def residuum(w): self.model.w = float(w) return sigma - self.sigma_c brentq(residuum, 0.0, min(self.sigma_c_max[1], 20.)) def sigma_f_lst(self, w_arr): sigma_f_arr = np.zeros(len(w_arr) * len(self.model.reinforcement_lst)).reshape(len(w_arr), len(self.model.reinforcement_lst)) masks = [((self.model.sorted_xi == reinf.xi) * (self.model.sorted_E_f == reinf.E_f) * (self.model.sorted_V_f == reinf.V_f)) for reinf in self.model.reinforcement_lst] for i, w in enumerate(w_arr): if w == 0.0: self.model.w = 1e-15 else: self.model.w = w self.model.damage for j, reinf in enumerate(self.model.reinforcement_lst): sigma_fi = np.sum(self.model._epsf0_arr * self.model.sorted_stats_weights * self.model.sorted_nu_r * self.model.sorted_E_f * (1. - self.model.damage) * masks[j]) sigma_f_arr[i, j] = sigma_fi return sigma_f_arr Welm = Property(depends_on='model.E_m, model.w, model.Ll, model.Lr, model.reinforcement_lst+') @cached_property def _get_Welm(self): Km = self.results[4] bonded_l = self.epsm_arr[0] ** 2 * Km * (self.model.Ll - np.abs(self.x_arr[0])) bonded_r = self.epsm_arr[-1] ** 2 * Km * (self.model.Lr - np.abs(self.x_arr[-1])) return 0.5 * (np.trapz(self.epsm_arr ** 2 * Km, self.x_arr) + bonded_l + bonded_r) Welf = Property(depends_on='model.E_m, model.w, model.Ll, model.Lr, model.reinforcement_lst+') @cached_property def _get_Welf(self): Kf = self.model.E_c - self.results[4] bonded_l = self.mu_epsf_arr[0] ** 2 * Kf * (self.model.Ll - np.abs(self.x_arr[0])) bonded_r = self.mu_epsf_arr[-1] ** 2 * Kf * (self.model.Lr - np.abs(self.x_arr[-1])) return 0.5 * (np.trapz(self.mu_epsf_arr ** 2 * Kf, self.x_arr) + bonded_l + bonded_r) W_el_tot = Property(depends_on='model.E_m, model.w, model.Ll, model.Lr, model.reinforcement_lst+') @cached_property def _get_W_el_tot(self): '''total elastic energy stored in the specimen''' return self.Welf + self.Welm W_inel_tot = Property(depends_on='model.E_m, model.w, model.Ll, model.Lr, model.reinforcement_lst+') @cached_property def _get_W_inel_tot(self): '''total inelastic energy dissipated during loading up to w''' return self.U - self.W_el_tot U_line = Property(depends_on='model.E_m, model.Ll, model.Lr, model.reinforcement_lst+, w_arr_energy') @cached_property def _get_U_line(self): '''work done by external force - mfn_line''' w_arr = self.w_arr_energy u_lst = [] F_lst = [] for w in w_arr: self.model.w = w u_lst.append(self.u_evaluated) F_lst.append(self.sigma_c) u_arr = np.array(u_lst) F_arr = np.array(F_lst) U_line = MFnLineArray(xdata=w_arr, ydata=np.hstack((0, cumtrapz(F_arr, u_arr)))) return U_line U = Property(depends_on='model.E_m, model.Ll, model.Lr, model.reinforcement_lst+, model.w') @cached_property def _get_U(self): '''work done by external force U(w)''' return self.U_line.get_values(self.model.w) w_arr_energy = Array def get_sigma_m_x_input(self, sigma): self.apply_load(sigma) line = MFnLineArray(xdata=self.x_arr, ydata=self.epsm_arr) return line.get_values(self.x_input)
class RIDVariable(HasTraits): """ Association between a random variable and distribution. """ title = Str('RIDvarible') s = WeakRef rf = WeakRef n_int = Int(20, enter_set=True, auto_set=False, desc='Number of integration points') def _n_int_changed(self): if self.pd: self.pd.n_segments = self.n_int # should this variable be randomized random = Bool(False, randomization_changed=True) def _random_changed(self): # get the default distribution if self.random: self.s.rv_dict[self.varname] = RV(pd=self.pd, name=self.varname, n_int=self.n_int) else: del self.s.rv_dict[self.varname] # name of the random variable (within the response function) # varname = String source_trait = Trait trait_value = Float pd = Property(Instance(IPDistrib), depends_on='random') @cached_property def _get_pd(self): if self.random: tr = self.rf.trait(self.varname) pd = PDistrib(distr_choice=tr.distr[0], n_segments=self.n_int) trait = self.rf.trait(self.varname) # get the distribution parameters from the metadata # distr_params = { 'scale': trait.scale, 'loc': trait.loc, 'shape': trait.shape } dparams = {} for key, val in list(distr_params.items()): if val: dparams[key] = val pd.distr_type.set(**dparams) return pd else: return None value = Property def _get_value(self): if self.random: return '' else: return '%g' % self.trait_value # -------------------------------------------- # default view specification def default_traits_view(self): return View(HGroup(Item( 'n_int', visible_when='random', label='NIP', ), Spring(), show_border=True, label='Variable name: %s' % self.varname), Item('pd@', show_label=False), resizable=True, id='rid_variable', height=800)
class ECBLMNDiagram(HasTraits): # calibrator supplying the effective material law calib = Instance(ECBLCalib) def _calib_default(self): return ECBLCalib(notify_change=self.set_modified) def _calib_changed(self): self.calib.notify_change = self.set_modified modified = Event def set_modified(self): print 'MN:set_modifeid' self.modified = True # cross section cs = DelegatesTo('calib') calibrated_ecb_law = Property(depends_on='modified') @cached_property def _get_calibrated_ecb_law(self): print 'NEW CALIBRATION' return self.calib.calibrated_ecb_law eps_cu = Property() def _get_eps_cu(self): return -self.cs.cc_law.eps_c_u eps_tu = Property() def _get_eps_tu(self): return self.calibrated_ecb_law.eps_tex_u n_eps = Int(5, auto_set=False, enter_set=True) eps_range = Property(depends_on='n_eps') @cached_property def _get_eps_range(self): eps_c_space = np.linspace(self.eps_cu, 0, self.n_eps) eps_t_space = np.linspace(0, self.eps_tu, self.n_eps) eps_ccu = 0.8 * self.eps_cu #eps_cc = self.eps_cu * np.ones_like(eps_c_space) eps_cc = np.linspace(eps_ccu, self.eps_cu, self.n_eps) eps_ct = self.eps_cu * np.ones_like(eps_t_space) eps_tc = self.eps_tu * np.ones_like(eps_c_space) eps_tt = self.eps_tu * np.ones_like(eps_t_space) eps1 = np.vstack([eps_c_space, eps_cc]) eps2 = np.vstack([eps_t_space, eps_ct]) eps3 = np.vstack([eps_tc, eps_c_space]) eps4 = np.vstack([eps_tt, eps_t_space]) return np.hstack([eps1, eps2, eps3, eps4]) n_eps_range = Property(depends_on='n_eps') @cached_property def _get_n_eps_range(self): return self.eps_range.shape[1] #=========================================================================== # MN Diagram #=========================================================================== def _get_MN_fn(self, eps_lo, eps_up): self.cs.set(eps_lo=eps_lo, eps_up=eps_up) return (self.cs.M, self.cs.N) MN_vct = Property(depends_on='modified') def _get_MN_vct(self): return np.vectorize(self._get_MN_fn) MN_arr = Property(depends_on='modified') @cached_property def _get_MN_arr(self): return self.MN_vct(self.eps_range[0, :], self.eps_range[1, :]) #=========================================================================== # f_eps Diagram #=========================================================================== current_eps_idx = Int(0) # , auto_set = False, enter_set = True) def _current_eps_idx_changed(self): self._clear_fired() self._replot_fired() current_eps = Property(depends_on='current_eps_idx') @cached_property def _get_current_eps(self): return self.eps_range[(0, 1), self.current_eps_idx] current_MN = Property(depends_on='current_eps_idx') @cached_property def _get_current_MN(self): return self._get_MN_fn(*self.current_eps) #=========================================================================== # Plotting #=========================================================================== 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 clear = Button def _clear_fired(self): self.figure.clear() self.data_changed = True replot = Button def _replot_fired(self): ax = self.figure.add_subplot(2, 2, 1) ax.plot(-self.eps_range, [0, 0.06], color='black') ax.plot(-self.current_eps, [0, 0.06], lw=3, color='red') 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') ax = self.figure.add_subplot(2, 2, 2) ax.plot(self.MN_arr[0], -self.MN_arr[1], lw=2, color='blue') ax.plot(self.current_MN[0], -self.current_MN[1], 'g.', markersize=20.0, color='red') ax.spines['left'].set_position('zero') ax.spines['bottom'].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') ax.grid(b=None, which='major') self.cs.set(eps_lo=self.current_eps[0], eps_up=self.current_eps[1]) ax = self.figure.add_subplot(2, 2, 3) self.cs.plot_eps(ax) ax = self.figure.add_subplot(2, 2, 4) self.cs.plot_sig(ax) self.data_changed = True view = View(HSplit( Group( HGroup( Group(Item('n_eps', springy=True), label='Discretization', springy=True), springy=True, ), HGroup( Group(VGroup( Item( 'cs', label='Cross section', show_label=False, springy=True, editor=InstanceEditor(kind='live'), ), Item( 'calib', label='Calibration', show_label=False, springy=True, editor=InstanceEditor(kind='live'), ), springy=True, ), label='Cross sectoin', springy=True), springy=True, ), scrollable=True, ), Group( HGroup( Item('replot', show_label=False), Item('clear', show_label=False), ), Item( 'current_eps_idx', editor=RangeEditor( low=0, high_name='n_eps_range', format='(%s)', mode='slider', auto_set=False, enter_set=False, ), show_label=False, ), Item('figure', editor=MPLFigureEditor(), resizable=True, show_label=False), id='simexdb.plot_sheet', label='plot sheet', dock='tab', ), ), width=1.0, height=0.8, resizable=True, buttons=['OK', 'Cancel'])
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
class RF(HasTraits): qname = Property def _get_qname(self): return self.__class__.__name__ comment = Property @cached_property def _get_comment(self): return self.__doc__ rf_args = Property(Tuple) @cached_property def _get_rf_args(self): ''' Extract the traits that are floating points and can be associated with a statistical distribution. ''' # Get the parameters of the obligatory call method argspec_list = getargspec(self.__call__).args[1:] # this line extracts the traits having the 'distr' metadata # containers for control variables ctrl_trait_keys = self.traits(ctrl_range=lambda x: x != None) ctrl_keys = [] ctrl_traits = [] ctrl_values = [] # containers for parameters param_trait_keys = self.traits(distr=lambda x: x != None) param_keys = [] param_traits = [] param_values = [] # iterate through the arguments of the call function to get # and store them in the corresponding list. # for argspec in argspec_list: if argspec in param_trait_keys: param_keys.append(argspec) param_traits.append(self.trait(argspec)) param_values.append(getattr(self, argspec)) elif argspec in ctrl_trait_keys: ctrl_keys.append(argspec) ctrl_traits.append(self.trait(argspec)) ctrl_values.append(getattr(self, argspec)) else: raise RuntimeError('parameter %s not declared as a trait in the response function %s' % \ (argspec, self.__class__)) return (ctrl_keys, ctrl_traits, ctrl_values, param_keys, param_traits, param_values) #-------------------------------------------------------------------- # FUNCTION PARAMETERS #-------------------------------------------------------------------- # The declaration of parameters that can be randomized # (design parameters) param_keys = Property(List) def _get_param_keys(self): return self.rf_args[3] param_traits = Property(List) def _get_param_traits(self): return self.rf_args[4] param_values = Property(List) def _get_param_values(self): return self.rf_args[5] #-------------------------------------------------------------------- # FUNCTION CONTROL VARIABLES #-------------------------------------------------------------------- ctrl_keys = Property(List) def _get_ctrl_keys(self): return self.rf_args[0] ctrl_traits = Property(List) def _get_ctrl_traits(self): return self.rf_args[1] ctrl_values = Property(List) def _get_ctrl_values(self): return self.rf_args[2] changed = Event @on_trait_change('+distr') def _set_changed(self): self.changed = True #@todo: delete - this is motivated by views and interactive editing # - shall be done later. listener_string = Str('') def add_listeners(self): self.on_trait_change(self.get_value, self.listener_string) def remove_listeners(self): self.on_trait_change(self.get_value, self.listener_string, remove=True) def default_traits_view(self): ''' Generates the view from the param items. ''' param_items = [Item(name) for name in self.param_keys] ctrl_items = [Item(name) for name in self.ctrl_keys] view = View(VGroup(*param_items, id='stats.spirrid_bak.rf.params'), VGroup(*ctrl_items, id='stats.spirrid_bak.rf.ctrl'), kind='modal', height=0.3, width=0.2, scrollable=True, resizable=True, buttons=['OK', 'Cancel'], id='stats.spirrid_bak.rf') return view def plot(self, p, ctrl_idx=0, **kw): X = np.linspace(*self.ctrl_traits[ctrl_idx].ctrl_range) Y = self(X, *self.param_values) p.plot(X, Y, **kw) p.xlabel(self.x_label) p.ylabel(self.y_label) p.legend(loc='best') p.title(self.title) def plot3d(self, p, ctrl_idx=[0, 1], **kw): X = np.linspace(*self.ctrl_traits[ctrl_idx[0]].ctrl_range) Y = np.linspace(*self.ctrl_traits[ctrl_idx[1]].ctrl_range) Z = self(X, Y, *self.param_values) p.surf(X, Y, Z, **kw) def __str__(self): ctrl_list = ['%s' % nm for nm in self.ctrl_keys] param_list = [ '%s = %g' % (nm, v) for nm, v in zip(self.param_keys, self.param_values) ] ctrl = string.join(ctrl_list, ', ') params = string.join(param_list, ', ') return '%s\n%s' % (ctrl, params)
class RV(HasStrictTraits): def __init__(self, type, loc=0.0, scale=0.0, shape=1.0, *args, **kw): '''Convenience initialization''' super(RV, self).__init__(*args, **kw) self.type = type self.loc = loc self.scale = scale self.shape = shape self.args = args self.kw = kw def __str__(self): return '%s( loc = %g, scale = %g, shape = %g)[n_int = %s]' % \ (self.type, self.loc, self.scale, self.shape, str(self.n_int)) n_int = Int(None) '''Number of integration points ''' loc = Float '''Location parameter. ''' scale = Float '''Scale parameter. ''' shape = Float '''Shape parameter. ''' type = Str '''Type specifier. ''' args = Tuple '''Generic arguments. ''' kw = Dict '''Generic keyword arguments. ''' _distr = Property(depends_on='mu,std,loc,type') '''Construct a distribution. hidden property instance of the scipy stats distribution ''' @cached_property def _get__distr(self): if self.n_int == None: n_segments = 10 else: n_segments = self.n_int pd = PD(distr_choice=self.type, n_segments=n_segments) pd.distr_type.set(scale=self.scale, shape=self.shape, loc=self.loc) return pd # access methods to pdf, ppf, rvs def pdf(self, x): return self._distr.pdf(x) def ppf(self, x): return self._distr.ppf(x) def rvs(self, x): return self._distr.rvs(x) def cdf(self, x): return self._distr.cdf(x)
class RV( HasTraits ): '''Class representing the definition and discretization of a random variable. ''' name = Str pd = Instance( IPDistrib ) def _pd_changed( self ): self.pd.n_segments = self._n_int changed = Event @on_trait_change( 'pd.changed,+changed' ) def _set_changed( self ): self.changed = True _n_int = Int n_int = Property def _set_n_int( self, value ): if self.pd: self.pd.n_segments = value self._n_int = value def _get_n_int( self ): return self.pd.n_segments # index within the randomization idx = Int( 0 ) # type of the RV discretization discr_type = Enum( 'T grid', 'P grid', 'MC', changed = True ) def _discr_type_default( self ): return 'T grid' theta_arr = Property( Array( 'float_' ), depends_on = 'changed' ) @cached_property def _get_theta_arr( self ): '''Get the discr_type of the pdistrib ''' if self.discr_type == 'T grid': # Get the discr_type from pdistrib and shift it # such that the midpoints of the segments are used for the # integration. x_array = self.pd.x_array # Note assumption of T grid discr_type theta_array = x_array[:-1] + self.pd.dx / 2.0 elif self.discr_type == 'P grid': # P grid disretization generated from the inverse cummulative # probability # distr = self.pd.distr_type.distr # Grid of constant probabilities pi_arr = linspace( 0.5 / self.n_int, 1. - 0.5 / self.n_int, self.n_int ) theta_array = distr.ppf( pi_arr ) return theta_array dG_arr = Property( Array( 'float_' ), depends_on = 'changed' ) @cached_property def _get_dG_arr( self ): if self.discr_type == 'T grid': d_theta = self.theta_arr[1] - self.theta_arr[0] return self.pd.get_pdf_array( self.theta_arr ) * d_theta elif self.discr_type == 'P grid': # P grid disretization generated from the inverse cummulative # probability # return array( [ 1.0 / float( self.n_int ) ], dtype = 'float_' ) def get_rvs_theta_arr( self, n_samples ): return self.pd.get_rvs_array( n_samples )
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' ) self.rv_dict = {} #-------------------------------------------------------------------- # Specification of random parameters #-------------------------------------------------------------------- # rv_dict = Dict def add_rv( self, variable, distribution = 'uniform', discr_type = 'T grid', loc = 0., scale = 1., shape = 1., n_int = 30 ): '''Declare a variable as random ''' if variable not in self.rf.param_keys: raise AssertionError, 'parameter %s not defined by the response function' \ % variable params_with_distr = self.rf.traits( distr = lambda x: type( x ) == ListType and distribution in x ) if variable not in params_with_distr: raise AssertionError, 'distribution type %s not allowed for parameter %s' \ % ( distribution, variable ) # @todo - let the RV take care of PDistrib specification. # isolate the dirty two-step definition of the distrib from spirrid # pd = PDistrib( distr_choice = distribution, n_segments = n_int ) pd.distr_type.set( scale = scale, shape = shape, loc = loc ) self.rv_dict[variable] = RV( name = variable, discr_type = discr_type, pd = pd, n_int = n_int ) def del_rv( self, variable ): '''Delete declaration of random variable ''' del self.rv_dict[ variable ] def clear_rv( self ): self.rv_dict = {} # subsidiary methods for sorted access to the random variables. # (note dictionary has not defined order of its items) rv_keys = Property( List, depends_on = 'rv_dict' ) @cached_property def _get_rv_keys( self ): rv_keys = sorted( self.rv_dict.keys() ) # the random variable gets an index based on the # sorted keys for idx, key in enumerate( rv_keys ): self.rv_dict[ key ].idx = idx return rv_keys rv_list = Property( List, depends_on = 'rv_dict' ) @cached_property def _get_rv_list( self ): return map( self.rv_dict.get, self.rv_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_dict, rv_dict.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 # Dictionary with key = rf parameters # and values = default param values for the resp func # param_dict = Property( Dict, depends_on = 'rf_change, rand_change' ) @cached_property def _get_param_dict( self ): '''Gather all the traits with the metadata distr specified. ''' dict = {} for name, value in zip( self.rf.param_keys, self.rf.param_values ): rv = self.rv_dict.get( name, None ) if rv == None: dict[ name ] = value else: dict[ name ] = self.theta_ogrid[ rv.idx ] return dict def get_rvs_theta_arr( self, n_samples ): rvs_theta_arr = array( [ repeat( value, n_samples ) for value in self.rf.param_values ] ) for idx, name in enumerate( self.rf.param_keys ): rv = self.rv_dict.get( name, None ) if rv: rvs_theta_arr[ idx, :] = rv.get_rvs_theta_arr( n_samples ) return rvs_theta_arr # Constant parameters # const_param_dict = Property( Dict, depends_on = 'rf_change, rand_change' ) @cached_property def _get_const_param_dict( self ): const_param_dict = {} for name, v in zip( self.rf.param_keys, self.rf.param_values ): if name not in self.rv_keys: const_param_dict[ name ] = v return const_param_dict # 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 RVs. ''' 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 RVs. ''' 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 RepresentativeCB(HasTraits): CB_model = Instance(CompositeCrackBridge) n_w = Int n_BC = Int load_sigma_c_arr = Array length = Float CB_model_view = Property(Instance(CompositeCrackBridgeView), depends_on='CB_model') @cached_property def _get_CB_model_view(self): return CompositeCrackBridgeView(model=self.CB_model) def max_sigma_w(self, Ll, Lr): self.CB_model_view.model.Ll = Ll self.CB_model_view.model.Lr = Lr max_sigma_c, max_w = self.CB_model_view.sigma_c_max if max_sigma_c < self.load_sigma_c_arr[-1]: return max_sigma_c, max_w else: self.CB_model_view.apply_load(self.load_sigma_c_arr[-1] - 1e-10) return self.load_sigma_c_arr[-1] - 1e-10, self.CB_model_view.model.w BC_range = Property(depends_on='n_BC, CB_model') @cached_property def _get_BC_range(self): self.max_sigma_w(1e5, 1e5) Lmax = min(self.CB_model_view.x_arr[-2], self.length) bc_range = np.logspace(np.log10(1.0), np.log10(Lmax), self.n_BC) return bc_range def w_x_res(self, w_arr, ll, lr): self.CB_model_view.model.Ll = ll self.CB_model_view.model.Lr = lr cb_epsm_interpolators_lst = [ MFnLineArray(xdata=np.linspace(-1e5, 1e5, 5), ydata=np.zeros(5)) ] cb_epsf_interpolators_lst = [ MFnLineArray(xdata=np.linspace(-1e5, 1e5, 5), ydata=np.zeros(5)) ] sigma_c_lst = [0.0] w_lst = [0.0] for w in w_arr: self.CB_model_view.model.w = w if self.CB_model_view.sigma_c > sigma_c_lst[-1]: w_lst.append(w) sigma_c_lst.append(self.CB_model_view.sigma_c) x_i = np.hstack((-self.length - 1e-1, self.CB_model_view.x_arr, self.length + 1e-1)) epsm_i = np.hstack((self.CB_model_view.epsm_arr[0], self.CB_model_view.epsm_arr, self.CB_model_view.epsm_arr[-1])) epsf_i = np.hstack((self.CB_model_view.epsf_arr[0], self.CB_model_view.epsf_arr, self.CB_model_view.epsf_arr[-1])) cb_epsm_interpolators_lst.append( MFnLineArray(xdata=x_i, ydata=epsm_i)) cb_epsf_interpolators_lst.append( MFnLineArray(xdata=x_i, ydata=epsf_i)) w_interpolator = MFnLineArray(xdata=np.array(sigma_c_lst), ydata=np.array(w_lst)) return w_interpolator, [sigma_c_lst, cb_epsm_interpolators_lst ], [sigma_c_lst, cb_epsf_interpolators_lst] interpolator_lists = Property( Array, depends_on='CB_model, load_sigma_c_arr, n_w, n_x, n_BC') @cached_property def _get_interpolator_lists(self): epsm_interpolators = np.zeros((self.n_BC, self.n_BC), dtype=np.object) epsf_interpolators = np.zeros((self.n_BC, self.n_BC), dtype=np.object) w_interpolators = np.zeros((self.n_BC, self.n_BC), dtype=np.object) loops_tot = self.n_BC**2 max_sigma_c_arr = np.zeros((self.n_BC, self.n_BC)) for i, ll in enumerate(self.BC_range): for j, lr in enumerate(self.BC_range): if j >= i: # find maximum sigma_c_max, wmax = self.max_sigma_w(ll, lr) # print 'Ll, Lr, sigmacmax: ', ll, lr, sigma_c_max max_sigma_c_arr[i, j] = max_sigma_c_arr[j, i] = sigma_c_max w_arr0 = np.linspace(1e-10, wmax, self.n_w) w_interpolator, epsm_interp_lst, epsf_interp_lst = self.w_x_res( w_arr0, ll, lr) epsm_interpolators[i, j] = epsm_interpolators[ j, i] = epsm_interp_lst epsf_interpolators[i, j] = epsf_interpolators[ j, i] = epsf_interp_lst w_interpolators[i, j] = w_interpolators[j, i] = w_interpolator current_loop = i * len(self.BC_range) + j + 1 print 'progress: %2.1f %%' % \ (current_loop / float(loops_tot) * 100.) interp_max_sigma_c = interp2d(self.BC_range, self.BC_range, max_sigma_c_arr, fill_value=None) return interp_max_sigma_c, epsm_interpolators, w_interpolators, epsf_interpolators def get_BC_idxs(self, Ll, Lr): if Ll >= self.BC_range[-1]: ll_idx_high = -1 ll_idx_low = -1 elif Ll <= self.BC_range[0]: ll_idx_high = 0 ll_idx_low = 0 else: ll_idx_high = np.argwhere(Ll <= self.BC_range)[0][0] ll_idx_low = np.argwhere(Ll >= self.BC_range)[-1][0] if Lr > self.BC_range[-1]: lr_idx_high = -1 lr_idx_low = -1 elif Lr <= self.BC_range[0]: lr_idx_high = 0 lr_idx_low = 0 else: lr_idx_high = np.argwhere(Lr <= self.BC_range)[0][0] lr_idx_low = np.argwhere(Lr >= self.BC_range)[-1][0] return ll_idx_high, lr_idx_high, ll_idx_low, lr_idx_low def interpolate_max_sigma_c(self, Ll, Lr): return self.interpolator_lists[0](Ll, Lr) def interpolate_epsm(self, Ll, Lr, sigma_c, x_arr): ll_idx_high, lr_idx_high, ll_idx_low, lr_idx_low = self.get_BC_idxs( Ll, Lr) epsm_interpolator_lst = self.interpolator_lists[1][ll_idx_high, lr_idx_high] sigc = np.array(epsm_interpolator_lst[0]) if sigma_c > sigc[-1]: # applied stress is higher than crack bridge strength return np.repeat(np.nan, len(x_arr)) else: sigc_high = np.argwhere(sigc > sigma_c)[0][0] sigc_low = np.argwhere(sigc < sigma_c)[-1][0] coeff_low = (sigc[sigc_high] - sigma_c) / \ (sigc[sigc_high] - sigc[sigc_low]) coeff_high = (sigma_c - sigc[sigc_low]) / (sigc[sigc_high] - sigc[sigc_low]) if Lr >= Ll: epsm = epsm_interpolator_lst[1][sigc_low].get_values(x_arr) * coeff_low + \ epsm_interpolator_lst[1][ sigc_high].get_values(x_arr) * coeff_high else: import matplotlib.pyplot as plt epsm = epsm_interpolator_lst[1][sigc_low].get_values(-x_arr[::-1]) * coeff_low + \ epsm_interpolator_lst[1][ sigc_high].get_values(-x_arr[::-1]) * coeff_high epsm = epsm[::-1] return epsm def interpolate_epsf(self, Ll, Lr, sigma_c, x_arr): ll_idx_high, lr_idx_high, ll_idx_low, lr_idx_low = self.get_BC_idxs( Ll, Lr) epsf_interpolator_lst = self.interpolator_lists[3][ll_idx_high, lr_idx_high] sigc = np.array(epsf_interpolator_lst[0]) if sigma_c > sigc[-1]: # applied stress is higher than crack bridge strength return np.repeat(np.nan, len(x_arr)) else: sigc_high = np.argwhere(sigc > sigma_c)[0][0] sigc_low = np.argwhere(sigc < sigma_c)[-1][0] coeff_low = (sigc[sigc_high] - sigma_c) / \ (sigc[sigc_high] - sigc[sigc_low]) coeff_high = (sigma_c - sigc[sigc_low]) / (sigc[sigc_high] - sigc[sigc_low]) if Lr >= Ll: epsf = epsf_interpolator_lst[1][sigc_low].get_values(x_arr) * coeff_low + \ epsf_interpolator_lst[1][ sigc_high].get_values(x_arr) * coeff_high else: epsf = epsf_interpolator_lst[1][sigc_low].get_values(-x_arr[::-1]) * coeff_low + \ epsf_interpolator_lst[1][ sigc_high].get_values(-x_arr[::-1]) * coeff_high epsf = epsf[::-1] return epsf def interpolate_w(self, Ll, Lr, sigma_c): ''' interpolation of w using the approach of interpolation on a 4-node rectangular finite element ''' ll_idx_high, lr_idx_high, ll_idx_low, lr_idx_low = self.get_BC_idxs( Ll, Lr) ll_low, ll_high, lr_low, lr_high = self.BC_range[ ll_idx_low], self.BC_range[ll_idx_high], self.BC_range[ lr_idx_low], self.BC_range[lr_idx_high] # evaluating nodal values / note that w2 = w3 w1 = self.interpolator_lists[2][ll_idx_low, lr_idx_low].get_values( np.array([sigma_c])) w2 = self.interpolator_lists[2][ll_idx_low, lr_idx_high].get_values( np.array([sigma_c])) w3 = self.interpolator_lists[2][ll_idx_high, lr_idx_low].get_values( np.array([sigma_c])) w4 = self.interpolator_lists[2][ll_idx_high, lr_idx_high].get_values( np.array([sigma_c])) nodal_values = [w1, w2, w3, w4] # shape functions if ll_idx_low == ll_idx_high: if lr_idx_low == lr_idx_high: # no interpolation return w1 else: # 1D interpolation a = lr_high - lr_low N1 = lambda x: -(x - lr_high) / a N2 = lambda x: (x - lr_low) / a return w1 * N1(Lr) + w2 * N2(Lr) else: if lr_idx_low == lr_idx_high: # 1D interpolation a = ll_high - ll_low N1 = lambda x: -(x - ll_high) / a N2 = lambda x: (x - ll_low) / a return w2 * N1(Ll) + w3 * N2(Ll) else: # 2D interpolation ab = (ll_high - ll_low) * (lr_high - lr_low) N1 = lambda x, y: (x - ll_high) * (y - lr_high) / ab N2 = lambda x, y: -(x - ll_low) * (y - lr_high) / ab N3 = lambda x, y: (x - ll_low) * (y - lr_low) / ab N4 = lambda x, y: -(x - ll_high) * (y - lr_low) / ab shape_functions = [N1, N2, N3, N4] # interpolate w w_interpolated = 0.0 for i, Ni in enumerate(shape_functions): w_interpolated += nodal_values[i] * Ni(Ll, Lr) return w_interpolated
class YMBCrossCorrel(HasTraits): data = Instance(IYMBData) # convert the dictionary keys to an ordered list. var_name_list = Property(List) @cached_property def _get_var_name_list(self): return sorted(var_dict.keys()) # list of data arrays in the order of the var_name_list var_arr_list = Property(List, depends_on='data.input_change') @cached_property def _get_var_arr_list(self): return [ getattr(self.data, var_dict[var_name]).flatten()[:, None] for var_name in self.var_name_list ] corr_arr = Property(Array, depends_on='data.input_change') @cached_property def _get_corr_arr(self): print 'redrawing cross correl' # get the list of names and sort them alphabetically corr_data = ma.hstack(self.var_arr_list) # @kelidas: return small differences between ma and numpy corrcoef # return ma.corrcoef( corr_data, rowvar = False, allow_masked = True ) return MatSpearman(corr_data) figure = Instance(Figure) def _figure_default(self): figure = Figure() figure.add_axes([0.1, 0.1, 0.8, 0.8]) return figure data_changed = Event(True) @on_trait_change('data, data.input_change') def _redraw(self): figure = self.figure figure.clear() var_data = self.corr_arr figure.add_axes([0.1, 0.1, 0.8, 0.8]) axes = figure.axes[0] axes.clear() x_coor = arange(var_data.shape[1]) axes.grid() for i in range(0, var_data.shape[1]): axes.plot(x_coor[i:] - x_coor[i], var_data[i, (i):], '-x') axes.set_xlabel('$\mathrm{x}\, [\mu\mathrm{m}]$', fontsize=16) axes.set_ylabel('$\mathrm{correlation}$', fontsize=16) axes.set_ylim(-1, 1) self.data_changed = True traits_view_mpl = View( Group( # Group( Item( 'figure', style = 'custom', # editor = MPLFigureEditor(), # show_label = False ) # , id = 'figure.view' ), Item('corr_arr', show_label=False, style='readonly', editor=TabularEditor(adapter=ArrayAdapter()))), resizable=True, ) traits_view = View(Item('corr_arr', editor=tabular_editor, show_label=False), resizable=True, scrollable=True, buttons=['OK', 'Cancel'], width=1.0, height=0.5)
class SFBMushRoofModel(IBVModel): '''SFB - Demontrator model specification. ''' implements(ISimModel) # number of elements in all dims n_elems_xy = Int(10, ps_levels=(20, 80, 3)) n_dofs_xy = Property(Int, depends_on='+ps_levels') def _get_n_dofs_xy(self): if self.fets == self.fe_2D_linear: return self.n_elems_xy + 1 elif self.fets == self.fe_2D_quadratic: return int(self.n_elems_xy * 2) else: raise ValueError rtrace_list = Property(List, depends_on='+ps_levels') @cached_property def _get_rtrace_list(self): return [self.max_princ_stress, self.sig_app, self.u] # sig_trace = RTraceDomainListField( name = 'Stress' , # var = 'sig_app', warp = False, # record_on = 'update' ) # eps_trace = RTraceDomainListField( name = 'Epsilon' , # var = 'eps_app', warp = True, # record_on = 'update' ) # eps0_trace = RTraceDomainListField( name = 'Epsilon 0' , # var = 'eps0_app', warp = True, # record_on = 'update' ) # eps1t_trace = RTraceDomainListField( name = 'Epsilon 1-t' , # var = 'eps1t_app', warp = True, # record_on = 'update' ) # u_trace = RTraceDomainListField( name = 'Displacement' , # var = 'u', warp = True, # record_on = 'update' ) # dimensions of the shell structure length_xy = Float(1.) # [m] E = Float(30000) # [MPa] nu = Float(0.2) # [-] alpha = Float(1e-3) # variable type of the finite element fets = Instance(FETSEval, ps_levels=['fe_2D_linear', 'fe_2D_quadratic']) def _fets_default(self): return self.fe_2D_quadratic mats = Instance(MATS2DElastic) def _mats_default(self): return MATS2DElastic(E=self.E, nu=self.nu, initial_strain=TemperatureLinFn( length=self.length_xy, n_dims=2, T_right=50, T_left=50, offset=0.5, alpha=self.alpha)) fe_2D_linear = Instance(FETSEval, transient=True) def _fe_2D_linear_default(self): return FETS2D4Q(mats_eval=self.mats) fe_2D_quadratic = Instance(FETSEval, transient=True) def _fe_2D_quadratic_default(self): return FETS2D4Q8U(mats_eval=self.mats) 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='max principle stress', unit='MPa'), SimOut(name='max sig_yy', unit='MPa'), SimOut(name='max sig_xx', unit='MPa'), ] def peval(self): ''' Evaluate the model and return the array of results specified in the method get_sim_outputs. ''' U = self.tloop.eval() u_corner = U[self.center_top_dof][-1, -1, 0] max_princ_stress = max( self.max_princ_stress._get_field_data().flatten()) max_sig_yy = max(self.sig_app._get_field_data()[:, 4]) max_sig_xx = max(self.sig_app._get_field_data()[:, 0]) return array([u_corner, max_princ_stress, max_sig_yy, max_sig_xx], dtype='float_') tline = Instance(TLine) def _tline_default(self): return TLine(min=0.0, step=1.0, max=1.0) max_princ_stress = Property(Instance(RTraceDomainListField), depends_on='+ps_levels') @cached_property def _get_max_princ_stress(self): return RTraceDomainListField( name='max principle stress', idx=0, # position = 'int_pnts', var='max_principle_sig', record_on='update', ) sig_app = Property(Instance(RTraceDomainListField), depends_on='+ps_levels') @cached_property def _get_sig_app(self): return RTraceDomainListField( name='sig_app', # position = 'int_pnts', var='sig_app', record_on='update', ) u = Property(Instance(RTraceDomainListField), depends_on='+ps_levels') @cached_property def _get_u(self): return RTraceDomainListField( name='displacement', var='u', warp=True, record_on='update', ) #[ self.sig_trace, self.eps_trace, self.eps0_trace, self.eps1t_trace, self.u_trace]#, self.f_w_diagram ] fe_grid = Property(Instance(FEGrid), depends_on='+ps_levels') def _get_fe_grid(self): return FEGrid(coord_min=(0.0, 0.0), coord_max=(1.0, 1.0), shape=(self.n_elems_xy, self.n_elems_xy), fets_eval=self.fets) # time loop tloop = Property(depends_on='+ps_levels') @cached_property def _get_tloop(self): self.fets.vtk_r *= 0.95 domain = self.fe_grid self.center_top_dof = domain[-1, -1, -1, -1].dofs # NOTE: additional line-loads at the edge of the roof need to be considered! # upper_surface = domain[:, :, -1, :, :, -1] # whole_domain = domain[:, :, :, :, :, :] bcond_list = [ BCSlice(var='u', dims=[0, 1], slice=domain[0, 0, 0, 0], value=0), BCSlice(var='u', dims=[0], slice=domain[0, -1, 0, -1], value=0), ] # w_z = domain[-1, -1, -1, -1].dofs[0] # self.f_w_diagram = RTraceGraph( name = 'load - corner deflection', # var_x = 'U_k', idx_x = w_z, # var_y = 'time', idx_y = 0, # record_on = 'update' ) # rtrace_list = self.rtrace_list#[ self.f_w_diagram ] + self.rtrace_list ts = TS(sdomain=[domain], dof_resultants=True, bcond_list=bcond_list, rtrace_list=self.rtrace_list) # Add the time-loop control tloop = TLoop(tstepper=ts, tolerance=1e-4, tline=self.tline) return tloop
class RFView3D(ModelView): model = Instance(IRF) scalar_arr = Property(depends_on='var_enum') @cached_property def _get_scalar_arr(self): return getattr(self.data, self.var_enum_) color_map = Str('blue-red') scene = Instance(MlabSceneModel, ()) plot = Instance(PipelineBase) # When the scene is activated or parameters change the scene is updated @on_trait_change('model.') def update_plot(self): x_arrr, y_arrr, z_arrr = self.data.cut_data[0:3] scalar_arrr = self.scalar_arr mask = y_arrr > -1 x = x_arrr[mask] y = y_arrr[mask] z = z_arrr[mask] scalar = scalar_arrr[mask] connections = -ones_like(x_arrr) mesk = x_arrr.filled() > -1 connections[mesk] = list(range(0, len(connections[mesk]))) connections = connections[self.start_fib:self.end_fib + 1, :].filled() connection = connections.astype(int).copy() connection = connection.tolist() # TODO: better for i in range(0, self.data.n_cols + 1): for item in connection: try: item.remove(-1) except: pass if self.plot is None: print('plot 3d -- 1') #self.scene.parallel_projection = False pts = self.scene.mlab.pipeline.scalar_scatter( array(x), array(y), array(z), array(scalar)) pts.mlab_source.dataset.lines = connection self.plot = self.scene.mlab.pipeline.surface( self.scene.mlab.pipeline.tube( # fig.scene.mlab.pipeline.stripper( pts, figure=self.scene.mayavi_scene, # ), tube_sides=10, tube_radius=0.015, ), ) self.plot.actor.mapper.interpolate_scalars_before_mapping = True self.plot.module_manager.scalar_lut_manager.show_scalar_bar = True self.plot.module_manager.scalar_lut_manager.show_legend = True self.plot.module_manager.scalar_lut_manager.shadow = True self.plot.module_manager.scalar_lut_manager.label_text_property.italic = False self.plot.module_manager.scalar_lut_manager.scalar_bar.orientation = 'horizontal' self.plot.module_manager.scalar_lut_manager.scalar_bar_representation.position2 = array( [0.61775334, 0.17]) self.plot.module_manager.scalar_lut_manager.scalar_bar_representation.position = array( [0.18606834, 0.08273163]) self.plot.module_manager.scalar_lut_manager.scalar_bar.width = 0.17000000000000004 self.plot.module_manager.scalar_lut_manager.lut_mode = self.color_map #'black-white' self.plot.module_manager.scalar_lut_manager.data_name = self.var_enum self.plot.module_manager.scalar_lut_manager.label_text_property.font_family = 'times' self.plot.module_manager.scalar_lut_manager.label_text_property.shadow = True self.plot.module_manager.scalar_lut_manager.title_text_property.color = ( 0.0, 0.0, 0.0) self.plot.module_manager.scalar_lut_manager.label_text_property.color = ( 0.0, 0.0, 0.0) self.plot.module_manager.scalar_lut_manager.title_text_property.font_family = 'times' self.plot.module_manager.scalar_lut_manager.title_text_property.shadow = True #fig.scene.parallel_projection = True self.scene.scene.background = (1.0, 1.0, 1.0) self.scene.scene.camera.position = [ 16.319534155794827, 10.477447863842627, 6.1717943847883232 ] self.scene.scene.camera.focal_point = [ 3.8980860486356859, 2.4731178194274621, 0.14856957086692035 ] self.scene.scene.camera.view_angle = 30.0 self.scene.scene.camera.view_up = [ -0.27676100729835512, -0.26547169369097656, 0.92354107904740446 ] self.scene.scene.camera.clipping_range = [ 7.7372124315754673, 26.343575352248056 ] self.scene.scene.camera.compute_view_plane_normal() #fig.scene.reset_zoom() axes = Axes() self.scene.engine.add_filter(axes, self.plot) axes.label_text_property.font_family = 'times' axes.label_text_property.shadow = True axes.title_text_property.font_family = 'times' axes.title_text_property.shadow = True axes.property.color = (0.0, 0.0, 0.0) axes.title_text_property.color = (0.0, 0.0, 0.0) axes.label_text_property.color = (0.0, 0.0, 0.0) axes.axes.corner_offset = .1 axes.axes.x_label = 'x' axes.axes.y_label = 'y' axes.axes.z_label = 'z' else: print('plot 3d -- 2') #self.plot.mlab_source.dataset.reset() #self.plot.mlab_source.set( x = x, y = y, z = z, scalars = scalar ) #self.plot.mlab_source.dataset.points = array( [x, y, z] ).T self.plot.mlab_source.scalars = scalar self.plot.mlab_source.dataset.lines = connection self.plot.module_manager.scalar_lut_manager.data_name = self.var_enum # The layout of the dialog created view = View( Item('scene', editor=SceneEditor(scene_class=MayaviScene), height=250, width=300, show_label=False), Group( '_', 'start_fib', 'end_fib', 'var_enum', ), resizable=True, )
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 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( range( n ), n ) loop_run = True t = time.clock() while loop_run == True: try: idx = list( permutations.next() ) 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 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_random_keys ] ) + \ ');\n' else: # qg code_str = '\tdouble pdf = ' + \ '*'.join( [ ' *( %s_pdf + i_%s)' % ( name, name ) for name in self.rv_random_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, rv in self.rv_dict.items(): if not rv.random: code_str += 'double %s = %g;\n' % ( name, rv.trait_value ) # generate loops over random params for rv in self.rv_list: # skip the terministic variable if not rv.random: continue 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 self.n_rv > 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_random_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 = sysclock() 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.theta_ogrid ) # 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 = sysclock() - 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 YMBFieldVar(HasTraits): data = Instance(IYMBData) n_cols = Property() def _get_n_cols(self): return self.data.n_cuts var_enum = Trait('radius', var_dict, modified=True) scalar_arr = Property(depends_on='var_enum') def _get_scalar_arr(self): return getattr(self.data, self.var_enum_) sorted_on = Bool(False, modified=True) scalar_arr_sorted = Property(depends_on='var_enum') def _get_scalar_arr_sorted(self): ''' Return scalar array sorted by the shortest distance from the edge ''' scalar_arr = zeros_like(getattr(self.data, self.var_enum_)) scalar_mask_arr = zeros_like(getattr(self.data, self.var_enum_)) distance_arr = self.data.edge_distance.filled() for i in range(0, self.n_cols): scalar_mask_arr[:, i] = zip( *sorted(zip(distance_arr[:, i], getattr(self.data, self.var_enum_).mask[:, i]), reverse=True))[1] scalar_arr[:, i] = zip( *sorted(zip(distance_arr[:, i], getattr(self.data, self.var_enum_).filled()[:, i]), reverse=True))[1] return ma.array(scalar_arr, mask=array(scalar_mask_arr, dtype=bool)) figure = Instance(Figure, ()) def _figure_default(self): figure = Figure() figure.add_axes([0.1, 0.1, 0.8, 0.8]) return figure data_changed = Event(True) @on_trait_change('+modified, data') def _redraw(self): self.figure.clear() self.figure.add_axes([0.1, 0.1, 0.8, 0.8]) figure = self.figure axes = figure.axes[0] axes.clear() if self.sorted_on == True: scalar_arr = self.scalar_arr_sorted else: scalar_arr = self.scalar_arr xi = linspace(min(self.data.cut_x), max(self.data.cut_x), 100) x = (ones_like(scalar_arr) * self.data.cut_x).flatten() ny_row = scalar_arr.shape[0] dy = max(diff(self.data.cut_x)) yi = linspace(0, ny_row * dy, ny_row) y = (ones_like(scalar_arr).T * linspace(0, ny_row * dy, ny_row)).T.flatten() z = scalar_arr.flatten() zi = griddata(x, y, z, xi, yi, interp='nn') # contour the gridded data, plotting dots at the nonuniform data points # axes.contour( xi, yi, zi, 20, linewidths = .5, colors = 'k' ) # plotting filled contour axes.contourf(xi, yi, zi, 200, cmap=my_cmap_lin) # my_cmap_lin scat = axes.scatter(x, y, marker='o', c=z, s=20, linewidths=0, cmap=my_cmap_lin) figure.colorbar(scat) self.data_changed = True view = View('var_enum', 'sorted_on', Item('figure', style='custom', editor=MPLFigureEditor(), show_label=False), id='yarn_structure_view', resizable=True, scrollable=True, dock='tab', width=0.8, height=0.4)
class RandomVariable( HasTraits ): '''Class representing the definition and discretization of a random variable. ''' trait_value = Float source_trait = CTrait # name of the parameter name = Str pd = Instance( IPDistrib ) def _pd_changed( self ): self.pd.n_segments = self._n_int changed = Event @on_trait_change( 'pd.changed,+changed' ) def _set_changed( self ): self.changed = True # Switch the parameter random random = Bool( False, changed = True ) def set_random( self, distribution = 'uniform', discr_type = 'T grid', loc = 0., scale = 1., shape = 1., n_int = 30 ): possible_distr = self.source_trait.distr if distribution and distribution not in possible_distr: raise AssertionError, 'distribution type %s not allowed for parameter %s' \ % ( distribution, self.name ) self.pd = PDistrib( distr_choice = distribution, n_segments = n_int ) self.pd.distr_type.set( scale = scale, shape = shape, loc = loc ) self.n_int = n_int self.discr_type = discr_type self.random = True def unset_random( self ): self.random = False # Number of integration points (relevant only for grid based methods) _n_int = Int n_int = Property def _set_n_int( self, value ): if self.pd: self.pd.n_segments = value self._n_int = value def _get_n_int( self ): return self.pd.n_segments # type of the RandomVariable discretization discr_type = Enum( 'T grid', 'P grid', 'MC', changed = True ) def _discr_type_default( self ): return 'T grid' theta_arr = Property( Array( 'float_' ), depends_on = 'changed' ) @cached_property def _get_theta_arr( self ): '''Get the discr_type of the pdistrib ''' if not self.random: return array( [ self.trait_value ], dtype = float ) if self.discr_type == 'T grid': # Get the discr_type from pdistrib and shift it # such that the midpoints of the segments are used for the # integration. x_array = self.pd.x_array # Note assumption of T grid discr_type theta_array = x_array[:-1] + self.pd.dx / 2.0 elif self.discr_type == 'P grid': # P grid disretization generated from the inverse cummulative # probability # distr = self.pd.distr_type.distr # Grid of constant probabilities pi_arr = linspace( 0.5 / self.n_int, 1. - 0.5 / self.n_int, self.n_int ) theta_array = distr.ppf( pi_arr ) return theta_array dG_arr = Property( Array( 'float_' ), depends_on = 'changed' ) @cached_property def _get_dG_arr( self ): if not self.random: return array( [ 1.0 ], dtype = float ) if self.discr_type == 'T grid': d_theta = self.theta_arr[1] - self.theta_arr[0] return self.pd.get_pdf_array( self.theta_arr ) * d_theta elif self.discr_type == 'P grid': # P grid disretization generated from the inverse cummulative # probability # return array( [ 1.0 / float( self.n_int ) ], dtype = 'float_' ) def get_rvs_theta_arr( self, n_samples ): if self.random: return self.pd.get_rvs_array( n_samples ) else: return array( [self.trait_value], float )
class ExpEM(ExType): '''Experiment: Elastic Modulus Test ''' # label = Str('three point bending test') implements(IExType) file_ext = 'TRA' #-------------------------------------------------------------------- # register a change of the traits with metadata 'input' #-------------------------------------------------------------------- input_change = Event @on_trait_change('+input, ccs.input_change, +ironing_param') def _set_input_change(self): self.input_change = True #-------------------------------------------------------------------------------- # specify inputs: #-------------------------------------------------------------------------------- edge_length = Float(0.06, unit='m', input=True, table_field=True, auto_set=False, enter_set=True) height = Float(0.12, unit='m', input=True, table_field=True, auto_set=False, enter_set=True) gauge_length = Float(0.10, unit='m', input=True, table_field=True, auto_set=False, enter_set=True) # age of the concrete at the time of testing age = Int(39, unit='d', input=True, table_field=True, auto_set=False, enter_set=True) loading_rate = Float(0.6, unit='MPa/s', input=True, table_field=True, auto_set=False, enter_set=True) #-------------------------------------------------------------------------- # composite cross section #-------------------------------------------------------------------------- ccs = Instance(CompositeCrossSection) def _ccs_default(self): '''default settings correspond to setup '7u_MAG-07-03_PZ-0708-1' ''' # fabric_layout_key = 'MAG-07-03' # fabric_layout_key = '2D-02-06a' fabric_layout_key = '2D-05-11' # concrete_mixture_key = 'PZ-0708-1' concrete_mixture_key = 'FIL-10-09' orientation_fn_key = 'all0' # orientation_fn_key = 'all90' # orientation_fn_key = '90_0' n_layers = 12 s_tex_z = 0.060 / (n_layers + 1) ccs = CompositeCrossSection(fabric_layup_list=[ plain_concrete(s_tex_z * 0.5), FabricLayUp(n_layers=n_layers, orientation_fn_key=orientation_fn_key, s_tex_z=s_tex_z, fabric_layout_key=fabric_layout_key), plain_concrete(s_tex_z * 0.5) ], concrete_mixture_key=concrete_mixture_key) return ccs #-------------------------------------------------------------------------- # Get properties of the composite #-------------------------------------------------------------------------- # E-modulus of the composite at the time of testing E_c = Property(Float, unit='MPa', depends_on='input_change', table_field=True) def _get_E_c(self): return self.ccs.get_E_c_time(self.age) # E-modulus of the composite after 28 days E_c28 = DelegatesTo('ccs', listenable=False) # reinforcement ration of the composite rho_c = DelegatesTo('ccs', listenable=False) #-------------------------------------------------------------------------------- # define processing #-------------------------------------------------------------------------------- def _read_data_array(self): ''' Read the experiment data. ''' print 'READ FILE' _data_array = np.loadtxt(self.data_file, delimiter=';', skiprows=2, usecols=(4, 5, 10, 17, 20)) self.data_array = _data_array names_and_units = Property @cached_property def _get_names_and_units(self): ''' Set the names and units of the measured data. ''' names = ['delta_u1', 'delta_u2', 'w', 'F', 'time'] units = ['mm', 'mm', 'mm', 'kN', 's'] return names, units #0#"Arbeit"; #1#"Dehn. abs"; #2#"Dehn. abs (2. Kanal)"; #3#"Dehnung"; #4#"Dehnung (1. Kanal)"; #5#"Dehnung (2. Kanal)"; #6#"Dehnung nominell"; #7#"DeltaE"; #8#"E1 korr"; #9#"E2 korr"; #10#"Kolbenweg"; #11#"Kolbenweg abs."; #12#"Lastrahmen"; #13#"LE-Kanal"; #14#"PrXXXfzeit"; #15#"Querdehnung"; #16#"S korr"; #17#"Standardkraft"; #18#"Vorlaufzeit"; #19#"Weg"; #20#"Zeit"; #21#"Zyklus" # #"Nm"; #"mm"; #"mm"; #"mm"; #"mm"; #"mm"; #"mm"; #"%"; #"mm"; #" "; #"mm"; #"mm"; #" "; #"mm"; #"s"; #"mm"; #" "; #"N"; #"s"; #"mm"; #"s"; #" " #-------------------------------------------------------------------------------- # plot templates #-------------------------------------------------------------------------------- plot_templates = { 'force / displacement': '_plot_force_displacement', 'stress / strain': '_plot_stress_strain', 'stress / time': '_plot_stress_time', } default_plot_template = 'force / displacement' def _plot_force_displacement(self, axes): xkey = 'deflection [mm]' ykey = 'force [kN]' xdata = self.w ydata = self.F / 1000. # convert from [N] to [kN] axes.set_xlabel('%s' % (xkey, )) axes.set_ylabel('%s' % (ykey, )) axes.plot(xdata, ydata # color = c, linewidth = w, linestyle = s ) def _plot_stress_strain(self, axes): sig = (self.F / 1000000.) / (self.edge_length**2 ) # convert from [N] to [MN] eps1 = (self.delta_u1 / 1000.) / self.gauge_length eps2 = (self.delta_u2 / 1000.) / self.gauge_length eps_m = (eps1 + eps2) / 2. axes.plot(eps_m, sig, color='blue', linewidth=2) def _plot_stress_time(self, axes): sig = (self.F / 1000000.) / (self.edge_length**2 ) # convert from [N] to [MN] axes.plot(self.time, sig, color='blue', linewidth=2) def _plot_displ_time(self, axes): axes.plot(self.time, self.displ, color='blue', linewidth=2) #-------------------------------------------------------------------------------- # view #-------------------------------------------------------------------------------- traits_view = View(VGroup( Group(Item('edge_length', format_str="%.3f"), Item('height', format_str="%.3f"), Item('gauge_length', format_str="%.3f"), label='geometry'), Group(Item('loading_rate'), Item('age'), label='loading rate and age'), Group(Item('E_c', show_label=True, style='readonly', format_str="%.0f"), Item('ccs@', show_label=False), label='composite cross section')), scrollable=True, resizable=True, height=0.8, width=0.6)
class MFnLineArray(HasTraits): # Public Traits xdata = Array(float, value = [0.0, 1.0]) def _xdata_default(self): ''' convenience default - when xdata not defined created automatically as an array of integers with the same shape as ydata ''' return np.arange(self.ydata.shape[0]) ydata = Array(float, value = [0.0, 1.0]) extrapolate = Enum('constant', 'exception', 'diff', 'zero') # alternative vectorized interpolation using scipy.interpolate def get_values(self, x, k = 1): ''' vectorized interpolation, k is the spline order, default set to 1 (linear) ''' tck = ip.splrep(self.xdata, self.ydata, s = 0, k = k) x = np.array([x]).flatten() if self.extrapolate == 'diff': values = ip.splev(x, tck, der = 0) elif self.extrapolate == 'exception': if x.all() < self.xdata[0] and x.all() > self.xdata[-1]: values = values = ip.splev(x, tck, der = 0) else: raise ValueError('value(s) outside interpolation range') elif self.extrapolate == 'constant': mask = x >= self.xdata[0] mask *= x <= self.xdata[-1] l_mask = x < self.xdata[0] r_mask = x > self.xdata[-1] extrapol_left = np.repeat(ip.splev(self.xdata[0], tck, der = 0), len(x)) * l_mask extrapol_right = np.repeat(ip.splev(self.xdata[-1], tck, der = 0), len(x)) * r_mask extrapol = extrapol_left + extrapol_right values = ip.splev(x, tck, der = 0) * mask + extrapol elif self.extrapolate == 'zero': mask = x >= self.xdata[0] mask *= x <= self.xdata[-1] mask_extrapol = mask == False extrapol = np.zeros(len(x)) * mask_extrapol values = ip.splev(x, tck, der = 0) * mask + extrapol return values def get_value(self, x): x2idx = self.xdata.searchsorted(x) if x2idx == len(self.xdata): x2idx -= 1 x1idx = x2idx - 1 x1 = self.xdata[ x1idx ] x2 = self.xdata[ x2idx ] dx = x2 - x1 y1 = self.ydata[ x1idx ] y2 = self.ydata[ x2idx ] dy = y2 - y1 y = y1 + dy / dx * (x - x1) return y data_changed = Event def get_diffs(self, x, k = 1, der = 1): ''' vectorized interpolation, der is the nth derivative, default set to 1; k is the spline order of the data inetrpolation, default set to 1 (linear) ''' xdata = np.sort(np.hstack((self.xdata, x))) idx = np.argwhere(np.diff(xdata) == 0).flatten() xdata = np.delete(xdata, idx) tck = ip.splrep(xdata, self.get_values(xdata, k = k), s = 0, k = k) return ip.splev(x, tck, der = der) def get_diff(self, x): x2idx = self.xdata.searchsorted(x) if x2idx == len(self.xdata): x2idx -= 1 x1idx = x2idx - 1 x1 = self.xdata[ x1idx ] x2 = self.xdata[ x2idx ] dx = x2 - x1 y1 = self.ydata[ x1idx ] y2 = self.ydata[ x2idx ] dy = y2 - y1 return dy / dx dump_button = ToolbarButton('Print data', style = 'toolbar') @on_trait_change('dump_button') def print_data(self, event = None): print 'x = ', repr(self.xdata) print 'y = ', repr(self.ydata) integ_value = Property(Float(), depends_on = 'ydata') @cached_property def _get_integ_value(self): _xdata = self.xdata _ydata = self.ydata # integral under the stress strain curve E_t = np.trapz(_ydata, _xdata) # area of the stored elastic energy U_t = 0.0 if len(_xdata) != 0: U_t = 0.5 * _ydata[-1] * _xdata[-1] return E_t - U_t def clear(self): self.xdata = np.array([]) self.ydata = np.array([]) def plot(self, axes, *args, **kw): self.mpl_plot(axes, *args, **kw) def mpl_plot(self, axes, *args, **kw): '''plot within matplotlib window''' axes.plot(self.xdata, self.ydata, *args, **kw)
class RVTransformation(HasTraits): x_values = Array pdf_x = Array # TODO: the possibility to work with CDFs cdf_x = Array PDFx = Property(depends_on='x_values, pdf_x') @cached_property def _get_PDFx(self): pdfx_line = MFnLineArray(xdata=self.x_values, ydata=self.pdf_x) return pdfx_line transf_eqn = Callable def _transf_eqn_default(self): # define simple linear transfomation function return lambda x: x y_values = Property(Array, depends_on='x_values, transf_eqn') @cached_property def _get_y_values(self): y = self.transf_eqn(self.x_values) y = np.linspace(y.min(), y.max(), len(self.x_values)) return y transf_line = Property(depends_on='x_values, pdf_x, transf_eqn') @cached_property def _get_transf_line(self): x = np.linspace(self.x_values[0], self.x_values[-1], 500) y = self.transf_eqn(x) return MFnLineArray(xdata=x, ydata=y, extrapolate='diff') def transf_diff(self, x): return self.transf_line.get_diffs(x, k=1, der=1) def transf_inv_scalar(self, y): x = np.linspace(self.x_values[0], self.x_values[-1], 500) s = sp.interpolate.InterpolatedUnivariateSpline( x, self.transf_eqn(x) - y) roots = s.roots() return roots def transf_inv_vect(self, y): res = [] y_val = [] for yi in y: value = self.transf_inv_scalar(yi) if len(value) != 0: res.append(value) y_val.append(yi) return res, y_val PDFy = Property(depends_on='x_values, pdf_x, transf_eqn') @cached_property def _get_PDFy(self): x, y = self.transf_inv_vect(self.y_values) xdata = [] PDFy = [] for i, xi in enumerate(x): if np.abs(self.transf_diff(np.array(xi))).all() > 1e-15: PDFy_arr = self.PDFx.get_values(np.array(xi), k=1) / np.abs( self.transf_diff(np.array(xi))) PDFy.append(np.sum(PDFy_arr)) xdata.append(y[i]) return MFnLineArray(xdata=xdata, ydata=PDFy)
class SimCrackLoc(IBVModel): '''Model assembling the components for studying the restrained crack localization. ''' geo_transform = Instance(FlawCenteredGeoTransform) def _geo_transform_default(self): return FlawCenteredGeoTransform() shape = Int(10, desc='Number of finite elements', ps_levsls=(10, 40, 4), input=True) length = Float(1000, desc='Length of the simulated region', unit='mm', input=True) flaw_position = Float(500, input=True, unit='mm') flaw_radius = Float(100, input=True, unit='mm') reduction_factor = Float(0.9, input=True) elastic_fraction = Float(0.9, input=True) avg_radius = Float(400, input=True, unit='mm') # tensile strength of concrete f_m_t = Float(3.0, input=True, unit='MPa') epsilon_0 = Property(unit='-') def _get_epsilon_0(self): return self.f_m_t / self.E_m epsilon_f = Float(10, input=True, unit='-') h_m = Float(10, input=True, unit='mm') b_m = Float(8, input=True, unit='mm') A_m = Property(unit='m^2') def _get_A_m(self): return self.b_m * self.h_m E_m = Float(30.0e5, input=True, unit='MPa') E_f = Float(70.0e6, input=True, unit='MPa') A_f = Float(1.0, input=True, unit='mm^2') s_crit = Float(0.009, input=True, unit='mm') P_f = Property(depends_on='+input') @cached_property def _get_P_f(self): return sqrt(4 * self.A_f * pi) K_b = Property(depends_on='+input') @cached_property def _get_K_b(self): return self.T_max / self.s_crit tau_max = Float(0.0, input=True, unit='MPa') T_max = Property(depends_on='+input', unit='N/mm') @cached_property def _get_T_max(self): return self.tau_max * self.P_f rho = Property(depends_on='+input') @cached_property def _get_rho(self): return self.A_f / (self.A_f + self.A_m) #------------------------------------------------------- # Material model for the matrix #------------------------------------------------------- mats_m = Property(Instance(MATS1DDamageWithFlaw), depends_on='+input') @cached_property def _get_mats_m(self): mats_m = MATS1DDamageWithFlaw(E=self.E_m * self.A_m, flaw_position=self.flaw_position, flaw_radius=self.flaw_radius, reduction_factor=self.reduction_factor, epsilon_0=self.epsilon_0, epsilon_f=self.epsilon_f) return mats_m mats_f = Instance(MATS1DElastic) def _mats_f_default(self): mats_f = MATS1DElastic(E=self.E_f * self.A_f) return mats_f mats_b = Instance(MATS1DEval) def _mats_b_default(self): mats_b = MATS1DElastic(E=self.K_b) mats_b = MATS1DPlastic(E=self.K_b, sigma_y=self.T_max, K_bar=0., H_bar=0.) # plastic function of slip return mats_b mats_fb = Property(Instance(MATS1D5Bond), depends_on='+input') @cached_property def _get_mats_fb(self): # Material model construction return MATS1D5Bond( mats_phase1=MATS1DElastic(E=0), mats_phase2=self.mats_f, mats_ifslip=self.mats_b, mats_ifopen=MATS1DElastic( E=0) # elastic function of open - inactive ) #------------------------------------------------------- # Finite element type #------------------------------------------------------- fets_m = Property(depends_on='+input') @cached_property def _get_fets_m(self): fets_eval = FETS1D2L(mats_eval=self.mats_m) #fets_eval = FETS1D2L3U( mats_eval = self.mats_m ) return fets_eval fets_fb = Property(depends_on='+input') @cached_property def _get_fets_fb(self): return FETS1D52L4ULRH(mats_eval=self.mats_fb) #return FETS1D52L6ULRH( mats_eval = self.mats_fb ) #return FETS1D52L8ULRH( mats_eval = self.mats_fb ) #-------------------------------------------------------------------------------------- # Mesh integrator #-------------------------------------------------------------------------------------- fe_domain_structure = Property(depends_on='+input') @cached_property def _get_fe_domain_structure(self): '''Root of the domain hierarchy ''' elem_length = self.length / float(self.shape) fe_domain = FEDomain() fe_m_level = FERefinementGrid(name='matrix domain', domain=fe_domain, fets_eval=self.fets_m) fe_grid_m = FEGrid(name='matrix grid', coord_max=(self.length, ), shape=(self.shape, ), level=fe_m_level, fets_eval=self.fets_m, geo_transform=self.geo_transform) fe_fb_level = FERefinementGrid(name='fiber bond domain', domain=fe_domain, fets_eval=self.fets_fb) fe_grid_fb = FEGrid(coord_min=(0., length / 5.), coord_max=(length, 0.), shape=(self.shape, 1), level=fe_fb_level, fets_eval=self.fets_fb, geo_transform=self.geo_transform) return fe_domain, fe_grid_m, fe_grid_fb, fe_m_level, fe_fb_level fe_domain = Property def _get_fe_domain(self): return self.fe_domain_structure[0] fe_grid_m = Property def _get_fe_grid_m(self): return self.fe_domain_structure[1] fe_grid_fb = Property def _get_fe_grid_fb(self): return self.fe_domain_structure[2] fe_m_level = Property def _get_fe_m_level(self): return self.fe_domain_structure[3] fe_fb_level = Property def _get_fe_fb_level(self): return self.fe_domain_structure[4] #--------------------------------------------------------------------------- # Load scaling adapted to the elastic and inelastic regime #--------------------------------------------------------------------------- final_displ = Property(depends_on='+input') @cached_property def _get_final_displ(self): damage_onset_displ = self.mats_m.epsilon_0 * self.length return damage_onset_displ / self.elastic_fraction step_size = Property(depends_on='+input') @cached_property def _get_step_size(self): n_steps = self.n_steps return 1.0 / float(n_steps) time_function = Property(depends_on='+input') @cached_property def _get_time_function(self): '''Get the time function so that the elastic regime is skipped in a single step. ''' step_size = self.step_size elastic_value = self.elastic_fraction * 0.98 * self.reduction_factor inelastic_value = 1.0 - elastic_value def ls(t): if t <= step_size: return (elastic_value / step_size) * t else: return elastic_value + (t - step_size) * (inelastic_value) / ( 1 - step_size) return ls def plot_time_function(self, p): '''Plot the time function. ''' n_steps = self.n_steps mats = self.mats step_size = self.step_size ls_t = linspace(0, step_size * n_steps, n_steps + 1) ls_fn = frompyfunc(self.time_function, 1, 1) ls_v = ls_fn(ls_t) p.subplot(321) p.plot(ls_t, ls_v, 'ro-') final_epsilon = self.final_displ / self.length kappa = linspace(mats.epsilon_0, final_epsilon, 10) omega_fn = frompyfunc(lambda kappa: mats._get_omega(None, kappa), 1, 1) omega = omega_fn(kappa) kappa_scaled = (step_size + (1 - step_size) * (kappa - mats.epsilon_0) / (final_epsilon - mats.epsilon_0)) xdata = hstack([array([0.0], dtype=float), kappa_scaled]) ydata = hstack([array([0.0], dtype=float), omega]) p.plot(xdata, ydata, 'g') p.xlabel('regular time [-]') p.ylabel('scaled time [-]') run = Button @on_trait_change('run') def peval(self): '''Evaluation procedure. ''' #mv = MATS1DDamageView( model = mats_eval ) #mv.configure_traits() right_dof_m = self.fe_grid_m[-1, -1].dofs[0, 0, 0] right_dof_fb = self.fe_grid_fb[-1, -1, -1, -1].dofs[0, 0, 0] # Response tracers A = self.A_m + self.A_f self.sig_eps_m = RTraceGraph(name='F_u_m', var_y='F_int', idx_y=right_dof_m, var_x='U_k', idx_x=right_dof_m, transform_y='y / %g' % A) # Response tracers self.sig_eps_f = RTraceGraph(name='F_u_f', var_y='F_int', idx_y=right_dof_fb, var_x='U_k', idx_x=right_dof_fb, transform_y='y / %g' % A) self.eps_m_field = RTraceDomainListField(name='eps_m', position='int_pnts', var='eps_app', warp=False) self.eps_f_field = RTraceDomainListField(name='eps_f', position='int_pnts', var='mats_phase2_eps_app', warp=False) # Response tracers self.sig_m_field = RTraceDomainListField(name='sig_m', position='int_pnts', var='sig_app') self.sig_f_field = RTraceDomainListField(name='sig_f', position='int_pnts', var='mats_phase2_sig_app') self.omega_m_field = RTraceDomainListField(name='omega_m', position='int_pnts', var='omega', warp=False) self.shear_flow_field = RTraceDomainListField(name='shear flow', position='int_pnts', var='shear_flow', warp=False) self.slip_field = RTraceDomainListField(name='slip', position='int_pnts', var='slip', warp=False) avg_processor = None if self.avg_radius > 0.0: n_dofs = self.fe_domain.n_dofs avg_processor = RTUAvg(sd=self.fe_m_level, n_dofs=n_dofs, avg_fn=QuarticAF(radius=self.avg_radius)) ts = TStepper( u_processor=avg_processor, dof_resultants=True, sdomain=self.fe_domain, bcond_list=[ # define the left clamping BCSlice(var='u', value=0., dims=[0], slice=self.fe_grid_fb[0, 0, 0, :]), # BCSlice( var = 'u', value = 0., dims = [0], slice = self.fe_grid_m[ 0, 0 ] ), # loading at the right edge # BCSlice( var = 'f', value = 1, dims = [0], slice = domain[-1, -1, -1, 0], # time_function = ls ), BCSlice(var='u', value=self.final_displ, dims=[0], slice=self.fe_grid_fb[-1, -1, -1, :], time_function=self.time_function), # BCSlice( var = 'u', value = self.final_displ, dims = [0], slice = self.fe_grid_m[-1, -1], # time_function = self.time_function ), # fix horizontal displacement in the top layer # BCSlice( var = 'u', value = 0., dims = [0], slice = domain[:, -1, :, -1] ), # fix the vertical displacement all over the domain BCSlice(var='u', value=0., dims=[1], slice=self.fe_grid_fb[:, :, :, :]), # # Connect bond and matrix domains BCDofGroup(var='u', value=0., dims=[0], get_link_dof_method=self.fe_grid_fb.get_bottom_dofs, get_dof_method=self.fe_grid_m.get_all_dofs, link_coeffs=[1.]) ], rtrace_list=[ self.sig_eps_m, self.sig_eps_f, self.eps_m_field, self.eps_f_field, self.sig_m_field, self.sig_f_field, self.omega_m_field, self.shear_flow_field, self.slip_field, ]) # Add the time-loop control tloop = TLoop(tstepper=ts, KMAX=300, tolerance=1e-5, debug=False, verbose_iteration=True, verbose_time=False, tline=TLine(min=0.0, step=self.step_size, max=1.0)) tloop.on_accept_time_step = self.plot U = tloop.eval() self.sig_eps_f.refresh() max_sig_m = max(self.sig_eps_m.trace.ydata) return array([U[right_dof_m], max_sig_m], dtype='float_') #-------------------------------------------------------------------------------------- # Tracers #-------------------------------------------------------------------------------------- def plot_sig_eps(self, p): p.set_xlabel('control displacement [mm]') p.set_ylabel('stress [MPa]') self.sig_eps_m.refresh() self.sig_eps_m.trace.plot(p, 'o-') self.sig_eps_f.refresh() self.sig_eps_f.trace.plot(p, 'o-') p.plot(self.sig_eps_m.trace.xdata, self.sig_eps_m.trace.ydata + self.sig_eps_f.trace.ydata, 'o-') def plot_eps(self, p): eps_m = self.eps_m_field.subfields[0] xdata = eps_m.vtk_X[:, 0] ydata = eps_m.field_arr[:, 0, 0] idata = argsort(xdata) p.plot(xdata[idata], ydata[idata], 'o-') eps_f = self.eps_f_field.subfields[1] xdata = eps_f.vtk_X[:, 0] ydata = eps_f.field_arr[:, 0, 0] idata = argsort(xdata) p.plot(xdata[idata], ydata[idata], 'o-') p.set_ylim(ymin=0) p.set_xlabel('bar axis [mm]') p.set_ylabel('strain [-]') def plot_omega(self, p): omega_m = self.omega_m_field.subfields[0] xdata = omega_m.vtk_X[:, 0] ydata = omega_m.field_arr[:] idata = argsort(xdata) p.fill(xdata[idata], ydata[idata], facecolor='gray', alpha=0.2) print 'max omega', max(ydata[idata]) p.set_ylim(ymin=0, ymax=1.0) p.set_xlabel('bar axis [mm]') p.set_ylabel('omega [-]') def plot_sig(self, p): sig_m = self.sig_m_field.subfields[0] xdata = sig_m.vtk_X[:, 0] ydata = sig_m.field_arr[:, 0, 0] idata = argsort(xdata) ymax = max(ydata) p.plot(xdata[idata], ydata[idata], 'o-') sig_f = self.sig_f_field.subfields[1] xdata = sig_f.vtk_X[:, 0] ydata = sig_f.field_arr[:, 0, 0] idata = argsort(xdata) p.plot(xdata[idata], ydata[idata], 'o-') xdata = sig_f.vtk_X[:, 0] ydata = sig_f.field_arr[:, 0, 0] + sig_m.field_arr[:, 0, 0] p.plot(xdata[idata], ydata[idata], 'ro-') p.set_ylim(ymin=0) # , ymax = 1.2 * ymax ) p.set_xlabel('bar axis [mm]') p.set_ylabel('stress [MPa]') def plot_shear_flow(self, p): shear_flow = self.shear_flow_field.subfields[1] xdata = shear_flow.vtk_X[:, 0] ydata = shear_flow.field_arr[:, 0] / self.P_f idata = argsort(xdata) ymax = max(ydata) p.plot(xdata[idata], ydata[idata], 'o-') p.set_xlabel('bar axis [mm]') p.set_ylabel('shear flow [N/m]') def plot_slip(self, p): slip = self.slip_field.subfields[1] xdata = slip.vtk_X[:, 0] ydata = slip.field_arr[:, 0] idata = argsort(xdata) ymax = max(ydata) p.plot(xdata[idata], ydata[idata], 'ro-') p.set_xlabel('bar axis [mm]') p.set_ylabel('slip [N/m]') def plot_tracers(self, p=p): p.subplot(221) self.plot_sig_eps(p) p.subplot(223) self.plot_eps(p) p.subplot(224) self.plot_sig(p) #--------------------------------------------------------------- # PLOT OBJECT #------------------------------------------------------------------- figure_ld = Instance(Figure) def _figure_ld_default(self): figure = Figure(facecolor='white') figure.add_axes([0.12, 0.13, 0.85, 0.74]) return figure #--------------------------------------------------------------- # PLOT OBJECT #------------------------------------------------------------------- figure_eps = Instance(Figure) def _figure_eps_default(self): figure = Figure(facecolor='white') figure.add_axes([0.12, 0.13, 0.85, 0.74]) return figure #--------------------------------------------------------------- # PLOT OBJECT #------------------------------------------------------------------- figure_shear_flow = Instance(Figure) def _figure_shear_flow_default(self): figure = Figure(facecolor='white') figure.add_axes([0.12, 0.13, 0.85, 0.74]) return figure #--------------------------------------------------------------- # PLOT OBJECT #------------------------------------------------------------------- figure_sig = Instance(Figure) def _figure_sig_default(self): figure = Figure(facecolor='white') figure.add_axes([0.12, 0.13, 0.85, 0.74]) return figure #--------------------------------------------------------------- # PLOT OBJECT #------------------------------------------------------------------- figure_shear_flow = Instance(Figure) def _figure_shear_flow_default(self): figure = Figure(facecolor='white') figure.add_axes([0.12, 0.13, 0.85, 0.74]) return figure def plot(self): self.figure_ld.clear() ax = self.figure_ld.gca() self.plot_sig_eps(ax) self.figure_eps.clear() ax = self.figure_eps.gca() self.plot_eps(ax) ax2 = ax.twinx() self.plot_omega(ax2) self.figure_sig.clear() ax = self.figure_sig.gca() self.plot_sig(ax) ax2 = ax.twinx() self.plot_omega(ax2) self.figure_shear_flow.clear() ax = self.figure_shear_flow.gca() self.plot_shear_flow(ax) ax2 = ax.twinx() self.plot_slip(ax2) self.data_changed = True def get_sim_outputs(self): ''' Specifies the results and their order returned by the model evaluation. ''' return [ SimOut(name='right end displacement', unit='m'), SimOut(name='peak load', uni='MPa') ] data_changed = Event toolbar = ToolBar(Action(name="Run", tooltip='Start computation', image=ImageResource('kt-start'), action="start_study"), Action(name="Pause", tooltip='Pause computation', image=ImageResource('kt-pause'), action="pause_study"), Action(name="Stop", tooltip='Stop computation', image=ImageResource('kt-stop'), action="stop_study"), image_size=(32, 32), show_tool_names=False, show_divider=True, name='view_toolbar'), traits_view = View(HSplit( VSplit( Item('run', show_label=False), VGroup( Item('shape'), Item('n_steps'), Item('length'), label='parameters', id='crackloc.viewmodel.factor.geometry', dock='tab', scrollable=True, ), VGroup(Item('E_m'), Item('f_m_t'), Item('avg_radius'), Item('h_m'), Item('b_m'), Item('A_m', style='readonly'), Item('mats_m', show_label=False), label='Matrix', dock='tab', id='crackloc.viewmodel.factor.matrix', scrollable=True), VGroup(Item('E_f'), Item('A_f'), Item('mats_f', show_label=False), label='Fiber', dock='tab', id='crackloc.viewmodel.factor.fiber', scrollable=True), VGroup(Group( Item('tau_max'), Item('s_crit'), Item('P_f', style='readonly', show_label=True), Item('K_b', style='readonly', show_label=True), Item('T_max', style='readonly', show_label=True), ), Item('mats_b', show_label=False), label='Bond', dock='tab', id='crackloc.viewmodel.factor.bond', scrollable=True), VGroup(Item('rho', style='readonly', show_label=True), label='Composite', dock='tab', id='crackloc.viewmodel.factor.jcomposite', scrollable=True), id='crackloc.viewmodel.left', label='studied factors', layout='tabbed', dock='tab', ), VSplit( VGroup( Item('figure_ld', editor=MPLFigureEditor(), resizable=True, show_label=False), label='stress-strain', id='crackloc.viewmode.figure_ld_window', dock='tab', ), VGroup( Item('figure_eps', editor=MPLFigureEditor(), resizable=True, show_label=False), label='strains profile', id='crackloc.viewmode.figure_eps_window', dock='tab', ), VGroup( Item('figure_sig', editor=MPLFigureEditor(), resizable=True, show_label=False), label='stress profile', id='crackloc.viewmode.figure_sig_window', dock='tab', ), VGroup( Item('figure_shear_flow', editor=MPLFigureEditor(), resizable=True, show_label=False), label='bond shear and slip profiles', id='crackloc.viewmode.figure_shear_flow_window', dock='tab', ), id='crackloc.viewmodel.right', ), id='crackloc.viewmodel.splitter', ), title='SimVisage Component: Crack localization', id='crackloc.viewmodel', dock='tab', resizable=True, height=0.8, width=0.8, buttons=[OKButton])
class ExpBT3PT(ExType): '''Experiment: Bending Test Three Point ''' # label = Str('three point bending test') implements(IExType) file_ext = 'raw' #-------------------------------------------------------------------- # register a change of the traits with metadata 'input' #-------------------------------------------------------------------- input_change = Event @on_trait_change('+input, ccs.input_change, +ironing_param') def _set_input_change(self): self.input_change = True #-------------------------------------------------------------------------------- # specify inputs: #-------------------------------------------------------------------------------- length = Float(0.46, unit='m', input=True, table_field=True, auto_set=False, enter_set=True) width = Float(0.1, unit='m', input=True, table_field=True, auto_set=False, enter_set=True) thickness = Float(0.02, unit='m', input=True, table_field=True, auto_set=False, enter_set=True) # age of the concrete at the time of testing age = Int(33, unit='d', input=True, table_field=True, auto_set=False, enter_set=True) loading_rate = Float(4.0, unit='mm/min', input=True, table_field=True, auto_set=False, enter_set=True) #-------------------------------------------------------------------------- # composite cross section #-------------------------------------------------------------------------- ccs = Instance(CompositeCrossSection) def _ccs_default(self): '''default settings ''' # fabric_layout_key = 'MAG-07-03' # fabric_layout_key = '2D-02-06a' fabric_layout_key = '2D-05-11' # fabric_layout_key = '2D-09-12' # concrete_mixture_key = 'PZ-0708-1' # concrete_mixture_key = 'FIL-10-09' concrete_mixture_key = 'barrelshell' orientation_fn_key = 'all0' # orientation_fn_key = 'all90' # orientation_fn_key = '90_0' n_layers = 6 s_tex_z = 0.020 / (n_layers + 1) ccs = CompositeCrossSection(fabric_layup_list=[ plain_concrete(s_tex_z * 0.5), FabricLayUp(n_layers=n_layers, orientation_fn_key=orientation_fn_key, s_tex_z=s_tex_z, fabric_layout_key=fabric_layout_key), plain_concrete(s_tex_z * 0.5) ], concrete_mixture_key=concrete_mixture_key) return ccs #-------------------------------------------------------------------------- # Get properties of the composite #-------------------------------------------------------------------------- # E-modulus of the composite at the time of testing E_c = Property(Float, unit='MPa', depends_on='input_change', table_field=True) def _get_E_c(self): return self.ccs.get_E_c_time(self.age) # E-modulus of the composite after 28 days E_c28 = DelegatesTo('ccs', listenable=False) # reinforcement ration of the composite rho_c = DelegatesTo('ccs', listenable=False) #-------------------------------------------------------------------------------- # define processing #-------------------------------------------------------------------------------- # flag distinguishes weather data from a displacement gauge is available # stored in a separate ASC-file with a corresponding file name # flag_ASC_file = Bool(False) def _read_data_array(self): ''' Read the experiment data. ''' if exists(self.data_file): print 'READ FILE' file_split = self.data_file.split('.') # first check if a '.csv' file exists. If yes use the # data stored in the '.csv'-file and ignore # the data in the '.raw' file! # file_name = file_split[0] + '.csv' if not os.path.exists(file_name): file_name = file_split[0] + '.raw' if not os.path.exists(file_name): raise IOError, 'file %s does not exist' % file_name print 'file_name', file_name _data_array = loadtxt_bending(file_name) self.data_array = _data_array # check if a '.ASC'-file exists. If yes append this information # to the data array. # file_name = file_split[0] + '.ASC' if not os.path.exists(file_name): print 'NOTE: no data from displacement gauge is available (no .ASC file)' self.flag_ASC_file = False else: print 'NOTE: additional data from displacement gauge for center deflection is available (.ASC-file loaded)!' self.flag_ASC_file = True # add data array read in from .ASC-file; the values are assigned by '_set_array_attribs' based on the # read in values in 'names_and_units' read in from the corresponding .DAT-file # self.data_array_ASC = loadtxt(file_name, delimiter=';') else: print 'WARNING: data_file with path %s does not exist == False' % ( self.data_file) names_and_units = Property(depends_on='data_file') @cached_property def _get_names_and_units(self): '''names and units corresponding to the returned '_data_array' by 'loadtxt_bending' ''' names = ['w_raw', 'eps_c_raw', 'F_raw'] units = ['mm', '1*E-3', 'N'] print 'names, units from .raw-file', names, units return names, units names_and_units_ASC = Property(depends_on='data_file') @cached_property def _get_names_and_units_ASC(self): ''' Extract the names and units of the measured data. The order of the names in the .DAT-file corresponds to the order of the .ASC-file. ''' file_split = self.data_file.split('.') file_name = file_split[0] + '.DAT' data_file = open(file_name, 'r') lines = data_file.read().split() names = [] units = [] for i in range(len(lines)): if lines[i] == '#BEGINCHANNELHEADER': name = lines[i + 1].split(',')[1] unit = lines[i + 3].split(',')[1] names.append(name) units.append(unit) print 'names, units extracted from .DAT-file', names, units return names, units factor_list_ASC = Property(depends_on='data_file') def _get_factor_list_ASC(self): return self.names_and_units_ASC[0] def _set_array_attribs(self): '''Set the measured data as named attributes defining slices into the processed data array. ''' for i, factor in enumerate(self.factor_list): self.add_trait( factor, Array(value=self.processed_data_array[:, i], transient=True)) if self.flag_ASC_file: for i, factor in enumerate(self.factor_list_ASC): self.add_trait( factor, Array(value=self.data_array_ASC[:, i], transient=True)) elastomer_law = Property(depends_on='input_change') @cached_property def _get_elastomer_law(self): elastomer_path = os.path.join(simdb.exdata_dir, 'bending_tests', 'three_point', '2011-06-10_BT-3PT-12c-6cm-0-TU_ZiE', 'elastomer_f-w.raw') _data_array_elastomer = loadtxt_bending(elastomer_path) # force [kN]: # NOTE: after conversion 'F_elastomer' is a positive value # F_elastomer = -0.001 * _data_array_elastomer[:, 2].flatten() # displacement [mm]: # NOTE: after conversion 'w_elastomer' is a positive value # w_elastomer = -1.0 * _data_array_elastomer[:, 0].flatten() mfn_displacement_elastomer = MFnLineArray(xdata=F_elastomer, ydata=w_elastomer) return frompyfunc(mfn_displacement_elastomer.get_value, 1, 1) w_wo_elast = Property(depends_on='input_change') @cached_property def _get_w_wo_elast(self): # use the machine displacement for the center displacement: # subtract the deformation of the elastomer cushion between the cylinder # and change sign in positive values for vertical displacement [mm] # return self.w_raw - self.elastomer_law(self.F_raw) M_ASC = Property(Array('float_'), depends_on='input_change') @cached_property def _get_M_ASC(self): return self.F_ASC * self.length / 4.0 M_raw = Property(Array('float_'), depends_on='input_change') @cached_property def _get_M_raw(self): return self.F_raw * self.length / 4.0 # # get only the ascending branch of the response curve # # # max_force_idx = Property(Int) # def _get_max_force_idx(self): # '''get the index of the maximum force''' # return argmax(-self.Kraft) # # f_asc = Property(Array) # def _get_f_asc(self): # '''get only the ascending branch of the response curve''' # return -self.Kraft[:self.max_force_idx + 1] K_bending_elast = Property(Array('float_'), depends_on='input_change') @cached_property def _get_K_bending_elast(self): '''calculate the analytical bending stiffness of the beam (3 point bending) ''' t = self.thickness w = self.width L = self.length # coposite E-modulus # E_c = self.E_c # moment of inertia # I_yy = t**3 * w / 12. delta_11 = (L**3) / 48 / E_c / I_yy # [MN/m]=[kN/mm] bending stiffness with respect to a force applied at center of the beam # K_bending_elast = 1 / delta_11 # print 'K_bending_elast', K_bending_elast return K_bending_elast F_cr = Property(Array('float_'), depends_on='input_change') @cached_property def _get_F_cr(self): '''calculate the analytical cracking load of the beam ''' t = self.thickness w = self.width L = self.length # approx. flectural tensile strength # f_cfl = 6. # MPa # resistant moment # W_yy = t**2 * w / 6. # analytical cracking load of the beam # corresponds to l = 0.46m and f_cfl = approx. 8.4 MPa# # F_cr = W_yy * f_cfl * 1000. / L # [kN] return F_cr def process_source_data(self): '''read in the measured data from file and assign attributes after array processing. ''' super(ExpBT3PT, self).process_source_data() #--------------------------------------------- # process data from .raw file (machine data) #--------------------------------------------- # convert machine force [N] to [kN] and return only positive values # self.F_raw *= -0.001 # convert machine displacement [mm] to positive values # and remove offset # self.w_raw *= -1.0 self.w_raw -= self.w_raw[0] # convert [permille] to [-] and return only positive values # self.eps_c_raw *= -0.001 # access the derived arrays to initiate their processing # self.w_wo_elast self.M_raw #--------------------------------------------- # process data from .ASC file (displacement gauge) #--------------------------------------------- # only if separate ASC.-file with force-displacement data from displacement gauge is available # if self.flag_ASC_file == True: self.F_ASC = -1.0 * self.Kraft # remove offset and change sign to return positive displacement values # if hasattr(self, "WA50"): self.WA50 *= -1 self.WA50 -= self.WA50[0] WA50_avg = np.average(self.WA50) if hasattr(self, "W10_u"): self.W10_u *= -1 self.W10_u -= self.W10_u[0] W10_u_avg = np.average(self.W10_u) # check which displacement gauge has been used depending on weather two names are listed in .DAT file or only one # and assign values to 'w_ASC' # if hasattr(self, "W10_u") and hasattr(self, "WA50"): if W10_u_avg > WA50_avg: self.w_ASC = self.W10_u print 'self.W10_u assigned to self.w_ASC' else: self.w_ASC = self.WA50 print 'self.WA50 assigned to self.w_ASC' elif hasattr(self, "W10_u"): self.w_ASC = self.W10_u print 'self.W10_u assigned to self.w_ASC' elif hasattr(self, "WA50"): self.w_ASC = self.WA50 print 'self.WA50 assigned to self.w_ASC' # convert strain from [permille] to [-], # switch to positive values for compressive strains # and remove offset # self.eps_c_ASC = -0.001 * self.DMS_l self.eps_c_ASC -= self.eps_c_ASC[0] # access the derived arrays to initiate their processing # self.M_ASC #-------------------------------------------------------------------------------- # plot templates #-------------------------------------------------------------------------------- plot_templates = { 'force / machine displacement (incl. w_elast)': '_plot_force_machine_displacement', 'force / machine displacement (without w_elast)': '_plot_force_machine_displacement_wo_elast', 'force / machine displacement (without w_elast, interpolated)': '_plot_force_machine_displacement_wo_elast_interpolated', 'force / machine displacement (analytical offset)': '_plot_force_machine_displacement_wo_elast_analytical_offset', 'force / gauge displacement': '_plot_force_gauge_displacement', 'force / gauge displacement (analytical offset)': '_plot_force_gauge_displacement_with_analytical_offset', 'force / gauge displacement (interpolated)': '_plot_force_gauge_displacement_interpolated', # 'smoothed force / gauge displacement' : '_plot_smoothed_force_gauge_displacement', # 'smoothed force / machine displacement' : '_plot_smoothed_force_machine_displacement_wo_elast', # 'moment / eps_c (ASC)': '_plot_moment_eps_c_ASC', 'moment / eps_c (raw)': '_plot_moment_eps_c_raw', # # 'smoothed moment / eps_c (ASC)' : '_plot_smoothed_moment_eps_c_ASC', # 'smoothed moment / eps_c (raw)' : '_plot_smoothed_moment_eps_c_raw', # # 'analytical bending stiffness' : '_plot_analytical_bending_stiffness' } default_plot_template = 'force / deflection (displacement gauge)' def _plot_analytical_bending_stiffness(self, axes, color='red', linewidth=1., linestyle='--'): '''plot the analytical bending stiffness of the beam (3 point bending) ''' t = self.thickness w = self.width L = self.length # composite E-modulus # E_c = self.E_c # moment of inertia # I_yy = t**3 * w / 12. delta_11 = L**3 / 48 / E_c / I_yy K_linear = 1 / delta_11 # [MN/m] bending stiffness with respect to a force applied at center of the beam w_linear = 2 * np.array([0., 1.]) F_linear = 2 * np.array([0., K_linear]) axes.plot(w_linear, F_linear, linestyle='--') def _plot_force_machine_displacement_wo_elast(self, axes, color='blue', linewidth=1., linestyle='-'): # get the index of the maximum stress # max_force_idx = argmax(self.F_raw) # get only the ascending branch of the response curve # f_asc = self.F_raw[:max_force_idx + 1] w_asc = self.w_wo_elast[:max_force_idx + 1] axes.plot(w_asc, f_asc, color=color, linewidth=linewidth, linestyle=linestyle) # plot analytical bending stiffness # w_linear = 2 * np.array([0., 1.]) F_linear = 2 * np.array([0., self.K_bending_elast]) axes.plot(w_linear, F_linear, linestyle='--') # xkey = 'deflection [mm]' # ykey = 'force [kN]' # axes.set_xlabel('%s' % (xkey,)) # axes.set_ylabel('%s' % (ykey,)) def _plot_force_machine_displacement_wo_elast_interpolated( self, axes, color='green', linewidth=1., linestyle='-'): # get the index of the maximum stress # max_force_idx = argmax(self.F_raw) # get only the ascending branch of the response curve # f_asc = self.F_raw[:max_force_idx + 1] w_asc = np.copy(self.w_wo_elast[:max_force_idx + 1]) # interpolate the starting point of the center deflection curve based on the slope of the curve # (remove offset in measured displacement where there is still no force measured) # idx_10 = np.where(f_asc > f_asc[-1] * 0.10)[0][0] idx_8 = np.where(f_asc > f_asc[-1] * 0.08)[0][0] f8 = f_asc[idx_8] f10 = f_asc[idx_10] w8 = w_asc[idx_8] w10 = w_asc[idx_10] m = (f10 - f8) / (w10 - w8) delta_w = f8 / m w0 = w8 - delta_w * 0.9 # print 'w0', w0 f_asc_interpolated = np.hstack([0., f_asc[idx_8:]]) w_asc_interpolated = np.hstack([w0, w_asc[idx_8:]]) # print 'type( w_asc_interpolated )', type(w_asc_interpolated) w_asc_interpolated -= float(w0) axes.plot(w_asc_interpolated, f_asc_interpolated, color=color, linewidth=linewidth, linestyle=linestyle) # fw_arr = np.hstack([f_asc_interpolated[:, None], w_asc_interpolated[:, None]]) # print 'fw_arr.shape', fw_arr.shape # np.savetxt('BT-3PT-12c-6cm-TU_f-w_interpolated.csv', fw_arr, delimiter=';') # plot analytical bending stiffness # w_linear = 2 * np.array([0., 1.]) F_linear = 2 * np.array([0., self.K_bending_elast]) axes.plot(w_linear, F_linear, linestyle='--') def _plot_force_machine_displacement_wo_elast_analytical_offset( self, axes, color='green', linewidth=1., linestyle='-'): # get the index of the maximum stress # max_force_idx = argmax(self.F_raw) # get only the ascending branch of the response curve # f_asc = self.F_raw[:max_force_idx + 1] w_asc = np.copy(self.w_wo_elast[:max_force_idx + 1]) M_asc = f_asc * self.length / 4. eps_c_asc = self.eps_c_raw[:max_force_idx + 1] t = self.thickness w = self.width # coposite E-modulus # E_c = self.E_c # resistant moment # W_yy = t**2 * w / 6. K_I_analytic = W_yy * E_c # [MN/m] bending stiffness with respect to center moment K_I_analytic *= 1000. # [kN/m] bending stiffness with respect to center moment # interpolate the starting point of the center deflection curve based on the slope of the curve # (remove offset in measured displacement where there is still no force measured) # idx_lin = np.where(M_asc <= K_I_analytic * eps_c_asc)[0][0] idx_lin = int(idx_lin * 0.7) # idx_lin = 50 # idx_lin = np.where(M_asc - M_asc[0] / eps_c_asc <= 0.90 * K_I_analytic)[0][0] print 'idx_lin', idx_lin print 'F_asc[idx_lin]', f_asc[idx_lin] print 'M_asc[idx_lin]', M_asc[idx_lin] print 'w_asc[idx_lin]', w_asc[idx_lin] w_lin_epsc = w_asc[idx_lin] w_lin_analytic = f_asc[idx_lin] / self.K_bending_elast f_asc_offset_analytic = f_asc[idx_lin:] w_asc_offset_analytic = w_asc[idx_lin:] w_asc_offset_analytic -= np.array([w_lin_epsc]) w_asc_offset_analytic += np.array([w_lin_analytic]) axes.plot(w_asc_offset_analytic, f_asc_offset_analytic, color=color, linewidth=linewidth, linestyle=linestyle) # plot analytical bending stiffness # w_linear = 2 * np.array([0., 1.]) F_linear = 2 * np.array([0., self.K_bending_elast]) axes.plot(w_linear, F_linear, linestyle='--') def _plot_force_machine_displacement(self, axes, color='black', linewidth=1., linestyle='-'): xdata = self.w_raw ydata = self.F_raw axes.plot(xdata, ydata, color=color, linewidth=linewidth, linestyle=linestyle) # xkey = 'deflection [mm]' # ykey = 'force [kN]' # axes.set_xlabel('%s' % (xkey,)) # axes.set_ylabel('%s' % (ykey,)) # plot analytical bending stiffness # w_linear = 2 * np.array([0., 1.]) F_linear = 2 * np.array([0., self.K_bending_elast]) axes.plot(w_linear, F_linear, linestyle='--') def _plot_force_gauge_displacement_with_analytical_offset( self, axes, color='black', linewidth=1., linestyle='-'): # skip the first values (= first seconds of testing) # and start with the analytical bending stiffness instead to avoid artificial offset of F-w-diagram # # w_max = np.max(self.w_ASC) # cut_idx = np.where(self.w_ASC > 0.001 * w_max)[0] cut_idx = np.where(self.w_ASC > 0.01)[0] print 'F_cr ', self.F_cr # cut_idx = np.where(self.F_ASC > 0.6 * self.F_cr)[0] print 'cut_idx', cut_idx[0] print 'w_ASC[cut_idx[0]]', self.w_ASC[cut_idx[0]] xdata = np.copy(self.w_ASC[cut_idx]) ydata = np.copy(self.F_ASC[cut_idx]) # specify offset if force does not start at the origin with value 0. F_0 = ydata[0] print 'F_0 ', F_0 offset_w = F_0 / self.K_bending_elast xdata -= xdata[0] xdata += offset_w f_asc_interpolated = np.hstack([0, ydata]) w_asc_interpolated = np.hstack([0, xdata]) # fw_arr = np.hstack([f_asc_interpolated[:, None], w_asc_interpolated[:, None]]) # print 'fw_arr.shape', fw_arr.shape # np.savetxt('BT-3PT-6c-2cm-TU_f-w_interpolated.csv', fw_arr, delimiter=';') xdata = self.w_raw ydata = self.F_raw axes.plot(xdata, ydata, color='blue', linewidth=linewidth, linestyle=linestyle) axes.plot(w_asc_interpolated, f_asc_interpolated, color=color, linewidth=linewidth, linestyle=linestyle) # xkey = 'deflection [mm]' # ykey = 'force [kN]' # axes.set_xlabel('%s' % (xkey,)) # axes.set_ylabel('%s' % (ykey,)) # plot analytical bending stiffness # w_linear = 2 * np.array([0., 1.]) F_linear = 2 * np.array([0., self.K_bending_elast]) axes.plot(w_linear, F_linear, linestyle='--') def _plot_force_gauge_displacement(self, axes, offset_w=0., color='black', linewidth=1., linestyle='-'): xdata = self.w_ASC ydata = self.F_ASC # specify offset if force does not start at the origin xdata += offset_w axes.plot(xdata, ydata, color=color, linewidth=linewidth, linestyle=linestyle) # xkey = 'deflection [mm]' # ykey = 'force [kN]' # axes.set_xlabel('%s' % (xkey,)) # axes.set_ylabel('%s' % (ykey,)) # fw_arr = np.hstack([xdata[:, None], ydata[:, None]]) # print 'fw_arr.shape', fw_arr.shape # np.savetxt('BT-3PT-6c-2cm-TU-80cm-V3_f-w_asc.csv', fw_arr, delimiter=';') # plot analytical bending stiffness # w_linear = 2 * np.array([0., 1.]) F_linear = 2 * np.array([0., self.K_bending_elast]) axes.plot(w_linear, F_linear, linestyle='--') def _plot_smoothed_force_gauge_displacement(self, axes): # get the index of the maximum stress # max_force_idx = argmax(self.F_ASC) # get only the ascending branch of the response curve # F_asc = self.F_ASC[:max_force_idx + 1] w_asc = self.w_ASC[:max_force_idx + 1] n_points = int(self.n_fit_window_fraction * len(w_asc)) F_smooth = smooth(F_asc, n_points, 'flat') w_smooth = smooth(w_asc, n_points, 'flat') axes.plot(w_smooth, F_smooth, color='blue', linewidth=2) def _plot_force_gauge_displacement_interpolated(self, axes, color='green', linewidth=1., linestyle='-'): '''get only the ascending branch of the meassured load-displacement curve)''' # get the index of the maximum stress # max_force_idx = argmax(self.F_ASC) # get only the ascending branch of the response curve # f_asc = self.F_ASC[:max_force_idx + 1] w_asc = self.w_ASC[:max_force_idx + 1] # interpolate the starting point of the center deflection curve based on the slope of the curve # (remove offset in measured displacement where there is still no force measured) # idx_10 = np.where(f_asc > f_asc[-1] * 0.10)[0][0] idx_8 = np.where(f_asc > f_asc[-1] * 0.08)[0][0] f8 = f_asc[idx_8] f10 = f_asc[idx_10] w8 = w_asc[idx_8] w10 = w_asc[idx_10] m = (f10 - f8) / (w10 - w8) delta_w = f8 / m w0 = w8 - delta_w * 0.9 print 'w0', w0 f_asc_interpolated = np.hstack([0., f_asc[idx_8:]]) w_asc_interpolated = np.hstack([w0, w_asc[idx_8:]]) print 'type( w_asc_interpolated )', type(w_asc_interpolated) w_asc_interpolated -= float(w0) # w_offset = f_asc[idx_10] / self.K_bending_elast # f_asc_interpolated = np.hstack([0., f_asc[ idx_10: ]]) # w_asc_interpolated = np.hstack([0, w_asc[ idx_10: ] - w_asc[idx_10] + w_offset]) axes.plot(w_asc_interpolated, f_asc_interpolated, color=color, linewidth=linewidth, linestyle=linestyle) # plot analytical bending stiffness # w_linear = 2 * np.array([0., 1.]) F_linear = 2 * np.array([0., self.K_bending_elast]) axes.plot(w_linear, F_linear, linestyle='--') def _plot_smoothed_force_machine_displacement_wo_elast(self, axes): # get the index of the maximum stress # max_force_idx = argmax(self.F_raw) # get only the ascending branch of the response curve # F_asc = self.F_raw[:max_force_idx + 1] w_asc = self.w_wo_elast[:max_force_idx + 1] n_points = int(self.n_fit_window_fraction * len(w_asc)) F_smooth = smooth(F_asc, n_points, 'flat') w_smooth = smooth(w_asc, n_points, 'flat') axes.plot(w_smooth, F_smooth, color='blue', linewidth=2) # plot analytical bending stiffness # w_linear = 2 * np.array([0., 1.]) F_linear = 2 * np.array([0., self.K_bending_elast]) axes.plot(w_linear, F_linear, linestyle='--') # secant_stiffness_w10 = ( f_smooth[10] - f_smooth[0] ) / ( w_smooth[10] - w_smooth[0] ) # w0_lin = array( [0.0, w_smooth[10] ], dtype = 'float_' ) # f0_lin = array( [0.0, w_smooth[10] * secant_stiffness_w10 ], dtype = 'float_' ) # axes.plot( w0_lin, f0_lin, color = 'black' ) def _plot_moment_eps_c_ASC(self, axes): xkey = 'compressive strain [1*E-3]' ykey = 'moment [kNm]' xdata = self.eps_c_ASC ydata = self.M_ASC axes.set_xlabel('%s' % (xkey, )) axes.set_ylabel('%s' % (ykey, )) axes.plot(xdata, ydata) # plot stiffness in uncracked state t = self.thickness w = self.width # composite E-modulus # E_c = self.E_c # resistant moment # W_yy = t**2 * w / 6. max_M = np.max(self.M_raw) K_linear = W_yy * E_c # [MN/m] bending stiffness with respect to center moment K_linear *= 1000. # [kN/m] bending stiffness with respect to center moment w_linear = np.array([0., max_M / K_linear]) M_linear = np.array([0., max_M]) axes.plot(w_linear, M_linear, linestyle='--') def _plot_moment_eps_c_raw(self, axes, color='black', linewidth=1.5, linestyle='-'): xkey = 'compressive strain [1*E-3]' ykey = 'moment [kNm]' xdata = self.eps_c_raw ydata = self.M_raw axes.set_xlabel('%s' % (xkey, )) axes.set_ylabel('%s' % (ykey, )) axes.plot(xdata, ydata, color=color, linewidth=linewidth, linestyle=linestyle) # plot stiffness in uncracked state t = self.thickness w = self.width # composite E-modulus # E_c = self.E_c # resistant moment # W_yy = t**2 * w / 6. max_M = np.max(self.M_raw) K_linear = W_yy * E_c # [MN/m] bending stiffness with respect to center moment K_linear *= 1000. # [kN/m] bending stiffness with respect to center moment w_linear = np.array([0., max_M / K_linear]) M_linear = np.array([0., max_M]) axes.plot(w_linear, M_linear, linestyle='--') n_fit_window_fraction = Float(0.1) smoothed_M_eps_c_ASC = Property(depends_on='input_change') @cached_property def _get_smoothed_M_eps_c_ASC(self): # get the index of the maximum stress max_idx = argmax(self.M_ASC) # get only the ascending branch of the response curve m_asc = self.M_ASC[:max_idx + 1] eps_c_asc = self.eps_c_ASC[:max_idx + 1] n_points = int(self.n_fit_window_fraction * len(eps_c_asc)) m_smoothed = smooth(m_asc, n_points, 'flat') eps_c_smoothed = smooth(eps_c_asc, n_points, 'flat') return m_smoothed, eps_c_smoothed smoothed_eps_c_ASC = Property def _get_smoothed_eps_c_ASC(self): return self.smoothed_M_eps_c_ASC[1] smoothed_M_ASC = Property def _get_smoothed_M_ASC(self): return self.smoothed_M_eps_c_ASC[0] def _plot_smoothed_moment_eps_c_ASC(self, axes): axes.plot(self.smoothed_eps_c_ASC, self.smoothed_M_ASC, color='blue', linewidth=2) smoothed_M_eps_c_raw = Property(depends_on='input_change') @cached_property def _get_smoothed_M_eps_c_raw(self): # get the index of the maximum stress max_idx = argmax(self.M_raw) # get only the ascending branch of the response curve m_asc = self.M_raw[:max_idx + 1] eps_c_asc = self.eps_c_raw[:max_idx + 1] n_points = int(self.n_fit_window_fraction * len(eps_c_asc)) m_smoothed = smooth(m_asc, n_points, 'flat') eps_c_smoothed = smooth(eps_c_asc, n_points, 'flat') return m_smoothed, eps_c_smoothed smoothed_eps_c_raw = Property def _get_smoothed_eps_c_raw(self): return self.smoothed_M_eps_c_raw[1] smoothed_M_raw = Property def _get_smoothed_M_raw(self): return self.smoothed_M_eps_c_raw[0] def _plot_smoothed_moment_eps_c_raw(self, axes): axes.plot(self.smoothed_eps_c_raw, self.smoothed_M_raw, color='blue', linewidth=2) #-------------------------------------------------------------------------------- # view #-------------------------------------------------------------------------------- traits_view = View(VGroup( Group(Item('length', format_str="%.3f"), Item('width', format_str="%.3f"), Item('thickness', format_str="%.3f"), label='geometry'), Group(Item('loading_rate'), Item('age'), label='loading rate and age'), Group(Item('E_c', show_label=True, style='readonly', format_str="%.0f"), Item('ccs@', show_label=False), label='composite cross section')), scrollable=True, resizable=True, height=0.8, width=0.6)
class Model(HasTraits): test_xdata = Array test_ydata = Array sV0 = Float(auto_set=False, enter_set=True, params=True) m = Float(auto_set=False, enter_set=True, params=True) w_min = Float(auto_set=False, enter_set=True, params=True) w_max = Float(auto_set=False, enter_set=True, params=True) w_pts = Int(auto_set=False, enter_set=True, params=True) n_int = Int(auto_set=False, enter_set=True, params=True) w2_min = Float(auto_set=False, enter_set=True, params=True) w2_max = Float(auto_set=False, enter_set=True, params=True) w2_pts = Int(auto_set=False, enter_set=True, params=True) tau_scale = Float(auto_set=False, enter_set=True, params=True) tau_loc = Float(auto_set=False, enter_set=True, params=True) tau_shape = Float(auto_set=False, enter_set=True, params=True) Ef = Float(auto_set=False, enter_set=True, params=True) lm = Float(auto_set=False, enter_set=True, params=True) V_f = Float(.01, params=True) r = Float(3.5e-3, params=True) w = Property(Array) def _get_w(self): return np.linspace(self.w_min, self.w_max, self.w_pts) w2 = Property(Array) def _get_w2(self): return np.linspace(self.w2_min, self.w2_max, self.w2_pts) interpolate_experiment = Property(depends_on='test_xdata, test_ydata') @cached_property def _get_interpolate_experiment(self): return interp1d(self.test_xdata, self.test_ydata, bounds_error=False, fill_value=0.0) model_rand = Property(Array) def _get_model_rand(self): cb = CBClampedRandXi(pullout=False) spirrid = SPIRRID(q=cb, sampling_type='LHS') sV0 = self.sV0 tau_scale = self.tau_scale V_f = 1.0 r = 3.5e-3 m = self.m tau = RV('gamma', shape=self.tau_shape, scale=tau_scale, loc=self.tau_loc) n_int = self.n_int w = self.w lm = 1000. spirrid.eps_vars = dict(w=w) spirrid.theta_vars = dict(tau=tau, E_f=self.Ef, V_f=V_f, r=r, m=m, sV0=sV0, lm=lm) spirrid.n_int = n_int sigma_c = spirrid.mu_q_arr / self.r**2 return sigma_c model_extrapolate = Property(Array) def _get_model_extrapolate(self): cb = CBClampedRandXi(pullout=False) spirrid = SPIRRID(q=cb, sampling_type='LHS') sV0 = self.sV0 V_f = 1.0 r = 3.5e-3 m = self.m tau = RV('gamma', shape=self.tau_shape, scale=self.tau_scale, loc=self.tau_loc) n_int = self.n_int w = self.w2 lm = self.lm spirrid.eps_vars = dict(w=w) spirrid.theta_vars = dict(tau=tau, E_f=self.Ef, V_f=V_f, r=r, m=m, sV0=sV0, lm=lm) spirrid.n_int = n_int sigma_c = spirrid.mu_q_arr / self.r**2 return sigma_c
class TSCrackLoc( TStepper ): '''Modified time stepper with adjusted predictor and corrector. The management of the shared variable omega_0 is done before calling the standard corrector predictor. The strain state at the x = 0 is evaluated and provided to the MATS1DCrackLoc material model in order to evaluate the next trial damage state. During the corrpred call, the material model then uses these variables during the stress and stiffness integration. ''' mats_eval = Property( Instance( MATS1DCrackLoc ) ) def _get_mats_eval( self ): return self.subdomains[0].fets_eval.mats_eval.mats_phase1 on_update = Callable fe_grid = Property( Instance( FEGrid ) ) @cached_property def _get_fe_grid( self ): # get the single subgrid in the first subdomain. return self.subdomains[0].fe_subgrids[0] concrete_dofs = Property( Array( Float ) ) @cached_property def _get_concrete_dofs( self ): # get the dofs associated with the bottom layer - concrete return self.fe_grid[:, 0, :, 0].dofs[:, :, 0] # specialize the # def eval( self, step_flag, U_k, d_U, t_n, t_n1 ): print 'concrete dofs' print self.concrete_dofs if step_flag == 'corrector': # when in the corrector - switch the trial to accepted # self.mats_eval.update_state() self.on_update() #print 'E', self.subdomains[0].dots.state_array #---------------------------------- # calculate the epxilon_0 at x = 0 #---------------------------------- fe_grid = self.subdomains[0] # pick the first element elem_0 = fe_grid.elements[0] fets_eval = fe_grid.fets_eval # get the displacement vector in the first element u = U_k[ elem_0.get_dof_map() ] # and the coordinates # set the spatial context self.sctx.X = elem_0.get_X_mtx() self.sctx.x = elem_0.get_x_mtx() self.sctx.loc = array( [0], dtype = 'float_' ) # get epsilon eps = fets_eval.get_eps_eng( self.sctx, u ) # set the trial state for the obtained strain self.mats_eval.set_trial_state( eps ) print 'BEGIN TS' # run the standard calculation return super( TSCrackLoc, self ).eval( step_flag, U_k, d_U, t_n, t_n1 )
class GenDistr( HasTraits ): x_values = Array pdf_values = Array cdf_values = Array def check( self ): if len( self.x_values ) == 0: raise ValueError, 'x_values not defined' if len( self.pdf_values ) == 0 and len( self.cdf_values ) == 0: raise ValueError, 'either pdf_values or cdf_values have to be given' else: pass cached_pdf = Property( depends_on = 'x_values, pdf_values, cdf_values' ) @cached_property def _get_cached_pdf( self ): if len( self.pdf_values ) == 0: cdf_line = MFnLineArray( xdata = self.x_values, ydata = self.cdf_values ) pdf = [] for x in self.x_values: pdf.append( cdf_line.get_diff( x ) ) return MFnLineArray( xdata = self.x_values, ydata = pdf ) else: return MFnLineArray( xdata = self.x_values, ydata = self.pdf_values ) def pdf( self, x ): self.check() return self.cached_pdf.get_values( x ) cached_cdf = Property( depends_on = 'x_values, pdf_values, cdf_values' ) @cached_property def _get_cached_cdf( self ): if len( self.cdf_values ) == 0: cdf = [] for i in range( len( self.x_values ) ): cdf.append( np.trapz( self.pdf_values[:i], self.x_values[:i] ) ) return MFnLineArray( xdata = self.x_values, ydata = cdf ) else: return MFnLineArray( xdata = self.x_values, ydata = self.cdf_values ) def cdf( self, x ): self.check() return self.cached_cdf.get_values( x ) def sf( self, x ): self.check() return 1 - self.cdf( x ) def ppf( self, x ): self.check() if len( self.cdf_values ) != 0: xx, cdf = self.x_values, self.cdf_values else: xx, cdf = self.x_values, self.cdf( self.x_values ) ppf_mfn_line = MFnLineArray( xdata = cdf, ydata = xx ) return ppf_mfn_line.get_values( x ) def stats( self, str ): self.check() if str == 'm': return self.mean() elif str == 'v': return self.var() elif str == 'mv': return ( self.mean(), self.var() ) def median( self ): self.check() return self.ppf( 0.5 ) def mean( self ): self.check() if len( self.pdf_values ) != 0: x, pdf = self.x_values, self.pdf_values else: x, pdf = self.x_values, self.pdf( self.x_values ) return np.trapz( x * pdf , x ) def var( self ): self.check() if len( self.pdf_values ) != 0: x, pdf = self.x_values, self.pdf_values else: x, pdf = self.x_values, self.pdf( self.x_values ) mu = self.mean() return np.trapz( ( x ** 2 - mu ) * pdf , x ) def std( self ): self.check() return np.sqrt( self.var() )