class SizeEffect( HasTraits ): ''' Size effect depending on the yarn length ''' l_b = Float( 0.1, auto_set = False, enter_set = True, # [m] desc = 'yarn total length', modified = True ) m_f = Float( 5, auto_set = False, enter_set = True, # [-] desc = 'Weibull shape parameter for filaments', modified = True ) Nf = Int( 24000, auto_set = False, enter_set = True, # [-] desc = 'number of filaments in yarn', modified = True ) l_rho = Float( 0.02, auto_set = False, enter_set = True, # [m] desc = 'autocorrelation length for fiber strength dispersion', modified = True ) s_rho = Float( 2500, auto_set = False, enter_set = True, # [m] desc = 'scale parameter for autocorrelation length', modified = True ) # these parameters are called plot, but the model should not # interfere with the view (@todo resolve) l_plot = Float( 80., auto_set = False, enter_set = True, # [m] desc = 'maximum yarn length', modified = True ) min_plot_length = Float( 0.0001, auto_set = False, enter_set = True, # [m] desc = 'minimum yarn length', modified = True ) n_points = Int( 100, auto_set = False, enter_set = True, desc = 'points to plot', modified = True ) # autocorrelation length function def fl( self, l ): return ( self.l_rho / ( self.l_rho + l ) ) ** ( 1. / self.m_f ) '''second option''' # return (l/self.l_rho + self.l_rho/(self.l_rho + l))**(-1./self.m_f) # scale parameter depending on length def s( self, l ): return self.fl( l ) * self.s_rho def mu_f( self, l ): return weibull_min( self.m_f, scale = self.s( l ), loc = 0.0 ).stats( 'm' ) def mu_b( self, l ): return self.m_f ** ( -1.0 / self.m_f ) * self.s( l ) * exp( -1.0 / self.m_f )
class WikiGen(HasTraits): rf_list = List([Filament, CBClampedFiber, CBInfiniteFiber, CBShortFiber, POClampedFiber, POInfiniteFiber, POShortFiber]) max_x = Float(0.01, enter_set=True, auto_set=False, config_change=True) n_points = Int(200, enter_set=True, auto_set=False, config_change=True) def export_wiki(self): fname = os.path.join('wiki', 'rf.wiki') f = open(fname, 'w') for rf_class in self.rf_list: q = rf_class() f.write(str(q) + '\n') qname = q.__class__.__name__ p.figure() q.plot(p, linewidth=2, color='navy') fig_fname = os.path.join('wiki', qname + '.png') p.savefig(fig_fname)
class 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') 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) theta_arr = Property(Array('float_'), depends_on='changed') @cached_property def _get_theta_arr(self): '''Get the discretization 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 equidistant discretization theta_array = x_array[:-1] + self.pd.dx / 2.0 return theta_array pdf_arr = Property(Array('float_'), depends_on='changed') @cached_property def _get_pdf_arr(self): return self.pd.get_pdf_array(self.theta_arr) dG_arr = Property(Array('float_'), depends_on='changed') @cached_property def _get_dG_arr(self): d_theta = self.theta_arr[1] - self.theta_arr[0] return self.pdf_arr * d_theta def get_rvs_theta_arr(self, n_samples): return self.pd.get_rvs_array(n_samples)
class RV(HasTraits): 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)) # number of integration points n_int = Int(None) # location parameter loc = Float # scale parameter scale = Float # shape parameter shape = Float # type specifier type = Str # hidden property instance of the scipy stats distribution _distr = Property(depends_on = 'mu,std,loc,type') @cached_property def _get__distr(self): '''Construct a distribution. ''' 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)
class FilBun( SizeEffect ): nf = Int( 50 ) K = Float( 72e9 * 0.89e-6 ) weib = Property def _get_weib( self ): return weibull_min( self.m_f, scale = self.s( 0.2 ) / self.K ) def filaments( self ): no = linspace( 0.001, 0.999, self.nf ) strains = self.weib.ppf( no ) return strains
class IIDOrderStats(HasTraits): distr = 'distribution' n = Int(10, auto_set=False, enter_set=True, desc='number of realizations') k = Int(1, auto_set=False, enter_set=True, desc='kth order statistics to evaluate') x_arr = np.linspace(0, 13, 300) def n_realizations(self): return self.distr.ppf(np.random.rand(self.n)) def kth_pdf(self): '''evaluates the PDF of the kth entry''' n = self.n k = self.k x = self.x_arr fct = sp.misc.factorial pdf = self.distr.pdf cdf = self.distr.cdf constant = fct(n) / (fct(k - 1) * fct(n - k)) return constant * pdf(x) * cdf(x)**(k - 1) * (1 - cdf(x))**(n - k) def kth_cdf(self): '''evaluates the CDF of the kth entry''' n = self.n k = self.k x = self.x_arr sf = self.distr.sf cdf = self.distr.cdf CDF = np.zeros(len(x)) CDF2 = np.zeros(len(x)) for l in range(n - k + 1): i = l + k CDF += sp.misc.common.comb(n, i) * cdf(x)**i * sf(x)**(n - i) return CDF
class ECBLPiecewiseLinear(ECBLBase): '''Effective crack bridge Law using a piecewise linear function.''' sig_level_arr = Array(float, input=True) def _sig_level_arr_default(self): E_eff = self.sig_tex_u / self.eps_tex_u return E_eff * self.eps_arr sig_tex_u = Float(800.0, input=True) eps_tex_u = Float(0.01, input=True) n_eps = Int(2, input=True) eps_fraction_arr = Property(depends_on='n_eps') @cached_property def _get_eps_fraction_arr(self): return np.linspace(0.0, 1.0, self.n_eps) cnames = ['eps_tex_u', 'sig_level_arr'] u0 = Property(depends_on='eps_tex_u, sig_tex_u, eps_fraction_list') @cached_property def _get_u0(self): return self.sig_level_arr[1:] eps_arr = Array(float) def _eps_arr_default(self): return self.eps_fraction_arr * self.eps_tex_u sig_arr = Array(float) def _sig_arr_default(self): return self.sig_level_arr def set_sig_eps_arr(self, eps_arr, sig_arr): self.eps_arr = eps_arr self.sig_arr = sig_arr
def _get_lcc_list(self): '''list of loading case combinations (instances of LCC) ''' combi_arr = self.combi_arr lcc_arr = self.lcc_arr sr_columns = self.sr_columns geo_columns = self.geo_columns n_lcc = self.n_lcc # return a dictionary of the stress resultants # this is used by LSTable to determine the stress # resultants of the current limit state # lcc_list = [] for i_lcc in range(n_lcc): state_data_dict = {} for i_sr, name in enumerate(sr_columns): state_data_dict[name] = lcc_arr[i_lcc, :, i_sr][:, None] geo_data_dict = self.geo_data_dict lcc = LCC( # lcc_table = self, factors=combi_arr[i_lcc, :], lcc_id=i_lcc, ls_table=LSTable(geo_data=geo_data_dict, state_data=state_data_dict, ls=self.ls)) for idx, lc in enumerate(self.lc_list): lcc.add_trait(lc.name, Int(combi_arr[i_lcc, idx])) lcc_list.append(lcc) return lcc_list
class SimDT(IBVModel): '''Simulation: Disk Test ''' implements(ISimModel) material_density_roof = Float(-22.4e-3) # [MN/m^3] #---------------------------------------------------- # elements #---------------------------------------------------- n_elems = Int(50, input=True) thickness = Float(1.0, input=True) vtk_r = Float(0.9, input=True) # fets used for roof # fets_disk = Instance((FETSEval), depends_on='+ps_levels, +input') def _fets_disk_default(self): # fe_quad_serendipity_roof is defined in base class # connected with material properties of the roof # mats = MATS2DElastic(E=3.1e5, nu=0.0, stress_state='plane_stress') fets = FETS2D4Q8U(mats_eval=mats) fets.vtk_r *= self.vtk_r return fets geo_disk = Property(depends_on='+ps_levels, +input') @cached_property def _get_geo_disk(self): # list of local origins of each roof defined in global coordinates # (for MRDetail two roofs are considered due to symmetry) # gt = GeoSquare2Circle(circle_center=[0.0, 0.0], circle_radius=1.0, square_edge=4.0) return gt #---------------------------------------------------- # fe-grids #---------------------------------------------------- fe_disk_grid = Property(Instance(FEGrid), depends_on='+ps_levels, +input') @cached_property def _get_fe_disk_grid(self): fe_grid = FEGrid(coord_min=(-1, -1), coord_max=(1, 1), geo_transform=self.geo_disk, shape=(self.n_elems, self.n_elems), fets_eval=self.fets_disk) return fe_grid bc_fixed = Property(depends_on='+ps_levels, +input') @cached_property def _get_bc_fixed(self): fe_disk_grid = self.fe_disk_grid extension = 0.1 alpha_45 = math.pi / 4.0 bc00 = BCDof(var='u', dof=fe_disk_grid[0, 0, 0, 0].dofs[0, 0, 1], value=-extension * math.cos(alpha_45)) bc00_link = BCDof(var='u', dof=fe_disk_grid[0, 0, 0, 0].dofs[0, 0, 0], link_dofs=[fe_disk_grid[0, 0, 0, 0].dofs[0, 0, 1]], link_coeffs=[1.0], value=0) bc10 = BCDof(var='u', dof=fe_disk_grid[-1, 0, -1, 0].dofs[0, 0, 1], value=-extension * math.cos(alpha_45)) bc10_link = BCDof(var='u', dof=fe_disk_grid[-1, 0, -1, 0].dofs[0, 0, 0], link_dofs=[fe_disk_grid[-1, 0, -1, 0].dofs[0, 0, 1]], link_coeffs=[-1.0], value=0) bc11 = BCDof(var='u', dof=fe_disk_grid[-1, -1, -1, -1].dofs[0, 0, 1], value=extension * math.cos(alpha_45)) bc11_link = BCDof( var='u', dof=fe_disk_grid[-1, -1, -1, -1].dofs[0, 0, 0], link_dofs=[fe_disk_grid[-1, -1, -1, -1].dofs[0, 0, 1]], link_coeffs=[1.0], value=0) bc01 = BCDof(var='u', dof=fe_disk_grid[0, -1, 0, -1].dofs[0, 0, 1], value=extension * math.cos(alpha_45)) bc01_link = BCDof(var='u', dof=fe_disk_grid[0, -1, 0, -1].dofs[0, 0, 0], link_dofs=[fe_disk_grid[0, -1, 0, -1].dofs[0, 0, 1]], link_coeffs=[-1.0], value=0) n_xy = self.n_elems / 2 bc_bottom = BCDof(var='u', dof=fe_disk_grid[n_xy, 0, 0, 0].dofs[0, 0, 1], value=-extension) bc_right = BCDof(var='u', dof=fe_disk_grid[-1, n_xy, -1, 0].dofs[0, 0, 0], value=extension) bc_top = BCDof(var='u', dof=fe_disk_grid[n_xy, -1, 0, -1].dofs[0, 0, 1], value=extension) bc_left = BCDof(var='u', dof=fe_disk_grid[0, n_xy, 0, 0].dofs[0, 0, 0], value=-extension) return [ bc_left, bc_right, bc_top, bc_bottom, bc00, bc00_link, bc10, bc10_link, bc11, bc11_link, bc01, bc01_link ] #---------------------------------------------------- # 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): roof = self.fe_disk_grid # self.bc_roof_deadweight + \ bc_list = self.bc_fixed ts = TS(sdomain=[roof], dof_resultants=True, bcond_list=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 ECBReinfTexUniform(ECBReinfComponent): '''Cross section characteristics needed for tensile specimens ''' height = DelegatesTo('matrix_cs') '''height of reinforced cross section ''' n_layers = Int(12, auto_set=False, enter_set=True, geo_input=True) '''total number of reinforcement layers [-] ''' n_rovings = Int(23, auto_set=False, enter_set=True, geo_input=True) '''number of rovings in 0-direction of one composite layer of the bending test [-]: ''' A_roving = Float(0.461, auto_set=False, enter_set=True, geo_input=True) '''cross section of one roving [mm**2]''' def convert_eps_tex_u_2_lo(self, eps_tex_u): '''Convert the strain in the lowest reinforcement layer at failure to the strain at the bottom of the cross section''' eps_up = self.state.eps_up return eps_up + (eps_tex_u - eps_up) / self.z_ti_arr[0] * self.height def convert_eps_lo_2_tex_u(self, eps_lo): '''Convert the strain at the bottom of the cross section to the strain in the lowest reinforcement layer at failure''' eps_up = self.state.eps_up return (eps_up + (eps_lo - eps_up) / self.height * self.z_ti_arr[0]) '''Convert the MN to kN ''' #=========================================================================== # material properties #=========================================================================== sig_tex_u = Float(1216., auto_set=False, enter_set=True, tt_input=True) '''Ultimate textile stress measured in the tensile test [MPa] ''' #=========================================================================== # Distribution of reinforcement #=========================================================================== s_tex_z = Property(depends_on=ECB_COMPONENT_AND_EPS_CHANGE) '''spacing between the layers [m]''' @cached_property def _get_s_tex_z(self): return self.height / (self.n_layers + 1) z_ti_arr = Property(depends_on=ECB_COMPONENT_AND_EPS_CHANGE) '''property: distance of each reinforcement layer from the top [m]: ''' @cached_property def _get_z_ti_arr(self): return np.array([ self.height - (i + 1) * self.s_tex_z for i in range(self.n_layers) ], dtype=float) zz_ti_arr = Property '''property: distance of reinforcement layers from the bottom ''' def _get_zz_ti_arr(self): return self.height - self.z_ti_arr #=========================================================================== # Discretization conform to the tex layers #=========================================================================== eps_i_arr = Property(depends_on=ECB_COMPONENT_AND_EPS_CHANGE) '''Strain at the level of the i-th reinforcement layer ''' @cached_property def _get_eps_i_arr(self): # ------------------------------------------------------------------------ # geometric params independent from the value for 'eps_t' # ------------------------------------------------------------------------ height = self.height eps_lo = self.state.eps_lo eps_up = self.state.eps_up # strain at the height of each reinforcement layer [-]: # return eps_up + (eps_lo - eps_up) * self.z_ti_arr / height eps_ti_arr = Property(depends_on=ECB_COMPONENT_AND_EPS_CHANGE) '''Tension strain at the level of the i-th layer of the fabrics ''' @cached_property def _get_eps_ti_arr(self): return (np.fabs(self.eps_i_arr) + self.eps_i_arr) / 2.0 eps_ci_arr = Property(depends_on=ECB_COMPONENT_AND_EPS_CHANGE) '''Compression strain at the level of the i-th layer. ''' @cached_property def _get_eps_ci_arr(self): return (-np.fabs(self.eps_i_arr) + self.eps_i_arr) / 2.0 #=========================================================================== # Effective crack bridge law #=========================================================================== ecb_law_type = Trait('fbm', dict(fbm=ECBLFBM, cubic=ECBLCubic, linear=ECBLLinear, bilinear=ECBLBilinear), tt_input=True) '''Selector of the effective crack bridge law type ['fbm', 'cubic', 'linear', 'bilinear']''' ecb_law = Property(Instance(ECBLBase), depends_on='+tt_input') '''Effective crack bridge law corresponding to ecb_law_type''' @cached_property def _get_ecb_law(self): return self.ecb_law_type_(sig_tex_u=self.sig_tex_u, cs=self) show_ecb_law = Button '''Button launching a separate view of the effective crack bridge law. ''' def _show_ecb_law_fired(self): ecb_law_mw = ConstitutiveLawModelView(model=self.ecb_law) ecb_law_mw.edit_traits(kind='live') return tt_modified = Event sig_ti_arr = Property(depends_on=ECB_COMPONENT_AND_EPS_CHANGE) '''Stresses at the i-th fabric layer. ''' @cached_property def _get_sig_ti_arr(self): return self.ecb_law.mfn_vct(self.eps_ti_arr) f_ti_arr = Property(depends_on=ECB_COMPONENT_AND_EPS_CHANGE) '''force at the height of each reinforcement layer [kN]: ''' @cached_property def _get_f_ti_arr(self): sig_ti_arr = self.sig_ti_arr n_rovings = self.n_rovings A_roving = self.A_roving return sig_ti_arr * n_rovings * A_roving / self.unit_conversion_factor figure = Instance(Figure) def _figure_default(self): figure = Figure(facecolor='white') figure.add_axes([0.08, 0.13, 0.85, 0.74]) return figure data_changed = Event replot = Button def _replot_fired(self): self.figure.clear() ax = self.figure.add_subplot(2, 2, 1) self.plot_eps(ax) ax = self.figure.add_subplot(2, 2, 2) self.plot_sig(ax) ax = self.figure.add_subplot(2, 2, 3) self.cc_law.plot(ax) ax = self.figure.add_subplot(2, 2, 4) self.ecb_law.plot(ax) self.data_changed = True def plot_eps(self, ax): #ax = self.figure.gca() d = self.height # eps ti ax.plot([-self.eps_lo, -self.eps_up], [0, self.height], color='black') ax.hlines(self.zz_ti_arr, [0], -self.eps_ti_arr, lw=4, color='red') # eps cj ec = np.hstack([self.eps_cj_arr] + [0, 0]) zz = np.hstack([self.zz_cj_arr] + [0, self.height]) ax.fill(-ec, zz, color='blue') # reinforcement layers eps_range = np.array([max(0.0, self.eps_lo), min(0.0, self.eps_up)], dtype='float') z_ti_arr = np.ones_like(eps_range)[:, None] * self.z_ti_arr[None, :] ax.plot(-eps_range, z_ti_arr, 'k--', color='black') # neutral axis ax.plot(-eps_range, [d, d], 'k--', color='green', lw=2) ax.spines['left'].set_position('zero') ax.spines['right'].set_color('none') ax.spines['top'].set_color('none') ax.spines['left'].set_smart_bounds(True) ax.spines['bottom'].set_smart_bounds(True) ax.xaxis.set_ticks_position('bottom') ax.yaxis.set_ticks_position('left') def plot_sig(self, ax): d = self.height # f ti ax.hlines(self.zz_ti_arr, [0], -self.f_ti_arr, lw=4, color='red') # f cj f_c = np.hstack([self.f_cj_arr] + [0, 0]) zz = np.hstack([self.zz_cj_arr] + [0, self.height]) ax.fill(-f_c, zz, color='blue') f_range = np.array( [np.max(self.f_ti_arr), np.min(f_c)], dtype='float_') # neutral axis ax.plot(-f_range, [d, d], 'k--', color='green', lw=2) ax.spines['left'].set_position('zero') ax.spines['right'].set_color('none') ax.spines['top'].set_color('none') ax.spines['left'].set_smart_bounds(True) ax.spines['bottom'].set_smart_bounds(True) ax.xaxis.set_ticks_position('bottom') ax.yaxis.set_ticks_position('left') view = View(HSplit( Group( HGroup( Group(Item('height', springy=True), Item('width'), Item('n_layers'), Item('n_rovings'), Item('A_roving'), label='Geometry', springy=True), Group(Item('eps_up', label='Upper strain', springy=True), Item('eps_lo', label='Lower strain'), label='Strain', springy=True), springy=True, ), HGroup( Group(VGroup(Item('cc_law_type', show_label=False, springy=True), Item('cc_law', label='Edit', show_label=False, springy=True), Item('show_cc_law', label='Show', show_label=False, springy=True), springy=True), Item('f_ck', label='Compressive strength'), Item('n_cj', label='Discretization'), label='Concrete', springy=True), Group(VGroup( Item('ecb_law_type', show_label=False, springy=True), Item('ecb_law', label='Edit', show_label=False, springy=True), Item('show_ecb_law', label='Show', show_label=False, springy=True), springy=True, ), label='Reinforcement', springy=True), springy=True, ), Group( Item('s_tex_z', label='vertical spacing', style='readonly'), label='Layout', ), Group(HGroup( Item('M', springy=True, style='readonly'), Item('N', springy=True, style='readonly'), ), label='Stress resultants'), scrollable=True, ), Group( Item('replot', show_label=False), Item('figure', editor=MPLFigureEditor(), resizable=True, show_label=False), id='simexdb.plot_sheet', label='plot sheet', dock='tab', ), ), width=0.8, height=0.7, resizable=True, buttons=['OK', 'Cancel'])
class MRquarter(MushRoofModel): implements(ISimModel) mushroof_part = 'quarter' n_elems_xy_quarter = Int(6, ps_levels=[3, 15, 5]) n_elems_z = Int(2, ps_levels=[1, 4, 2]) #---------------------------------------------------- # elements #---------------------------------------------------- vtk_r = Float(0.9) # default roof fe_roof = Instance( FETSEval, ps_levels=[ 'fe2d5_quad_serendipity', 'fe_quad_serendipity', 'fe_linear', 'fe_quad_lagrange' ], depends_on='+initial_strain_roof, +initial_strain_col, +vtk_r') def _fe_roof_default(self): fets = self.fe2d5_quad_serendipity # fets = self.fe_quad_serendipity fets.vtk_r *= self.vtk_r return fets #---------------------------------------------------- # grid and geometric transformation #---------------------------------------------------- fe_grid_roof = Property(Instance(FEGrid), depends_on='+ps_levels, +input') @cached_property def _get_fe_grid_roof(self): return FEGrid(coord_min=(0.0, 0.0, 0.0), coord_max=(1.0, 1.0, 1.0), geo_transform=self.hp_shell, shape=(self.n_elems_xy, self.n_elems_xy, self.n_elems_z), fets_eval=self.fe2d5_quad_serendipity) # fets_eval = self.fe_roof) # fets_eval = self.fe_quad_serendipity) mats_roof = Property(Instance(MATS2D5MicroplaneDamage), depends_on='+input') # mats_roof = Property( Instance( MATS3DElastic), depends_on = '+input' ) @cached_property def _get_mats_roof(self): # return MATS3DElastic(E=self.E_roof, nu=self.nu) return MATS2D5MicroplaneDamage(E=29100.0, nu=0.2, n_mp=30, symmetrization='sum-type', model_version='compliance', phi_fn=self.phi_fn) fe2d5_quad_serendipity = Property(Instance(FETSEval, transient=True), depends_on='+input') def _get_fe2d5_quad_serendipity(self): return FETS2D58H20U(mats_eval=self.mats_roof) fe_quad_serendipity = Property(Instance(FETSEval, transient=True), depends_on='+input') def _get_fe_quad_serendipity(self): return FETS3D8H20U(mats_eval=self.mats_roof) shrink_factor = Float(1.0) # shell # hp_shell = Property(Instance(HPShell), depends_on='+ps_levels, +input') @cached_property def _get_hp_shell(self): return HPShell(length_xy_quarter=self.length_xy_quarter / self.shrink_factor, length_z=self.length_z / self.shrink_factor, n_elems_xy_quarter=self.n_elems_xy_quarter, n_elems_z=self.n_elems_z, scalefactor_delta_h=self.scalefactor_delta_h, mushroof_part='quarter', shift_elems=False, X0=self.X0) #---------------------------------------------------- # ps_study #---------------------------------------------------- def peval(self): ''' Evaluate the model and return the array of results specified in the method get_sim_outputs. ''' U = self.tloop.eval() u_center_top_z = U[self.center_top_dof][0, 0, 2] print 'u_center_top_z', u_center_top_z return np.array([u_center_top_z], dtype='float_') # max_princ_stress = max(self.max_princ_stress._get_field_data().flatten()) # return np.array([ u_center_top_z, max_princ_stress ], # dtype = 'float_') def get_sim_outputs(self): ''' Specifies the results and their order returned by the model evaluation. ''' return [ SimOut(name='u_z_free_corner', unit='m'), SimOut(name='maximum principal stress', unit='MPa'), ] #---------------------------------------------------- # response tracer #---------------------------------------------------- rtrace_list = List def _rtrace_list_default(self): return [self.eps_app, self.sig_app, self.max_omega_i, self.phi_pdc] max_lambda = Float(1.0, input=True) '''Maximum lambda factor to impose on the structure. The final loading loading level is calculated as the reference boundary conditions multiplied by the lambda_factor and uls_factor. Thus, lambda factor defines the load level as a multiple of the load level predicted by the linear analysis. ''' f_w_diagram = Property(Instance(RTraceGraph), depends_on='+ps_levels, +input') @cached_property def _get_f_w_diagram(self): domain = self.fe_grid_roof w_z = domain[-1, -1, -1, -1, -1, -1].dofs[0, 0, 2] return RTraceGraph( name='load - corner deflection', var_x='U_k', idx_x=w_z, transform_x='-x', var_y='time', idx_y=0, # transform_y='y * %g' % self.lambda_factor, record_on='update') n_steps = Int(15.0, auto_set=False, enter_set=False, input=True) time_fn_load = Instance(MFnLineArray, input=True) def _time_fn_load_default(self): eta = 0.27 * 1.2 return MFnLineArray(xdata=[0.0, 1.0, 3.0, 5.0, 8.0, 15.0], ydata=[0.0, 1.0, 1.0 / eta, 1.78 / eta, 8.0, 9.05]) boundary_x1 = Property(depends_on='+input') @cached_property def _get_boundary_x1(self): return self.fe_grid_roof.domain[-1, :, -1, -1, :, -1] #---------------------------------------------------- # time loop #---------------------------------------------------- tloop = Property(depends_on='+ps_levels, +input') @cached_property def _get_tloop(self): domain = self.fe_grid_roof #---------------------------------------------------- # loading and boundaries #---------------------------------------------------- #--- LC1: dead load # g = 22.4 kN/m^3 # orientation: global z-direction; material_density_roof = -22.43e-3 # [MN/m^3] #--- LC2 additional dead load # gA = 0,20 kN/m^2 # orientation: global z-direction (following the curved structure); additional_dead_load = -0.20e-3 # [MN/m^2] #--- LC2 additional boundary load # gA = 0,35 kN/m^2 # orientation: global z-direction (following the curved structure); boundary_dead_load = -0.35e-3 # [MN/m] #--- LC3 snow # s = 0,79 kN/m^2 # orientation: global z-direction (projection); surface_load_s = -0.85e-3 # [MN/m^2] #--- LC4 wind (pressure) # w = 0,13 kN/m^2 # orientation: local t-direction (surface normal); surface_load_w = -0.13e-3 # [MN/m^2] # NOTE: additional line-loads at the edge of the roof need to be considered! upper_surface = domain[:, :, -1, :, :, -1] whole_domain = domain[:, :, :, :, :, :] boundary_x1 = domain[-1, :, -1, -1, :, -1] boundary_y1 = domain[:, -1, -1, :, -1, -1] time_fn_load = self.time_fn_load time_fn_permanent_load = MFnLineArray(xdata=[0.0, 1.0], ydata=[0.0, 1.0]) time_fn_snow_load = MFnLineArray(xdata=[0.0, 1.0], ydata=[0.0, 0.0]) force_bc = [ # own weight BCSlice(name='self weight', var='f', value=material_density_roof, dims=[2], integ_domain='global', time_function=time_fn_load.get_value, slice=whole_domain), # LC2: additional dead-load BCSlice(name='additional load', var='f', value=additional_dead_load, dims=[2], integ_domain='global', time_function=time_fn_load.get_value, slice=upper_surface), # LC2: additional boundary-load BCSlice(name='additional boundary load 1', var='f', value=boundary_dead_load, dims=[2], integ_domain='global', time_function=time_fn_load.get_value, slice=boundary_x1), # LC2: additional boundary-load BCSlice(name='additional boundary load 2', var='f', value=boundary_dead_load, dims=[2], integ_domain='global', time_function=time_fn_load.get_value, slice=boundary_y1), # LC3: snow load BCSlice(name='snow load', var='f', value=surface_load_s, dims=[2], integ_domain='global', time_function=time_fn_snow_load.get_value, slice=upper_surface), # # LC3: wind # BCSlice( var = 'f', value = surface_load_w, dims = [2], # integ_domain = 'global', # slice = upper_surface ) ] bc_symplane_yz = BCSlice(var='u', value=0., dims=[0], slice=domain[0, :, :, 0, :, :]) bc_symplane_xz = BCSlice(var='u', value=0., dims=[1], slice=domain[:, 0, :, :, 0, :]) bc_support_000 = BCSlice(var='u', value=0., dims=[2], slice=domain[0, 0, 0, :, :, 0]) # bc_column = [ # BCSlice( var = 'u' , dims = [0, 1, 2], # slice = domain[self.n_elems_xy_quarter - 1, # self.n_elems_xy_quarter - 1, # 0, # 0, -1, 0 ], # value = 0. ), # BCSlice( var = 'u' , dims = [0, 1, 2], # slice = domain[self.n_elems_xy_quarter - 1, # self.n_elems_xy_quarter - 1 , # 0, # - 1, 0, 0], # value = 0. )] # bc_corner_load = BCSlice( var = 'f', value = -nodal_load, dims = [2], slice = domain[-1,-1,-1,-1,-1,-1] ) # bc_topface_load = BCSlice( var = 'f', value = -nodal_load, dims = [2], slice = domain[:,:,-1,:,:,-1] ) # support_z_dofs = domain[0, 0, 0, :, : , 0].dofs[:, :, 2] # support_f_w = RTraceGraph(name='force - corner deflection', # var_x='time', idx_x=0, # transform_x='x * %g' % lambda_failure, # var_y='F_int', idx_y_arr=np.unique(support_z_dofs.flatten()), # transform_y='-y', # record_on='update') rtrace_list = [self.f_w_diagram] + self.rtrace_list ts = TS(sdomain=[domain], dof_resultants=True, bcond_list=[bc_symplane_yz, bc_symplane_xz, bc_support_000] + force_bc, rtrace_list=rtrace_list) step = 1.0 # self.n_steps # Add the time-loop control tloop = TLoop(tstepper=ts, RESETMAX=0, KMAX=70, tolerance=0.5e-3, tline=TLine(min=0.0, step=step, max=1.0)) # self.max_lambda)) return tloop
class MRquarterDB(MRquarter): '''get 'phi_fn' as calibrated by the fitter and stored in the DB ''' # vary the failure strain in PhiFnGeneralExtended: factor_eps_fail = Float(1.4, input=True, ps_levels=(1.0, 1.2, 3)) #----------------- # composite cross section unit cell: #----------------- # ccs_unit_cell_key = Enum('FIL-10-09_2D-05-11_0.00462_all0', CCSUnitCell.db.keys(), simdb=True, input=True, auto_set=False, enter_set=True) ccs_unit_cell_ref = Property(Instance(SimDBClass), depends_on='ccs_unit_cell_key') @cached_property def _get_ccs_unit_cell_ref(self): return CCSUnitCell.db[self.ccs_unit_cell_key] #----------------- # damage function: #----------------- # material_model = Str(input=True) def _material_model_default(self): # return the material model key of the first DamageFunctionEntry # This is necessary to avoid an ValueError at setup return self.ccs_unit_cell_ref.damage_function_list[0].material_model calibration_test = Str(input=True) def _calibration_test_default(self): # return the material model key of the first DamageFunctionEntry # This is necessary to avoid an ValueError at setup return self.ccs_unit_cell_ref.damage_function_list[0].calibration_test damage_function = Property(Instance(MFnLineArray), depends_on='+input') @cached_property def _get_damage_function(self): print 'getting damage function' return self.ccs_unit_cell_ref.get_param(self.material_model, self.calibration_test) #----------------- # phi function extended: #----------------- # phi_fn = Property(Instance(PhiFnGeneralExtended), depends_on='+input,+ps_levels') @cached_property def _get_phi_fn(self): return PhiFnGeneralExtendedExp(mfn=self.damage_function, Dfp=0.01, Efp_frac=0.007) # return PhiFnGeneralExtended( mfn = self.damage_function, # factor_eps_fail = self.factor_eps_fail ) #---------------------------------------------------------------------------------- # mats_eval #---------------------------------------------------------------------------------- # age of the plate at the time of testing # NOTE: that the same phi-function is used independent of age. This assumes a # an afine/proportional damage evolution for different ages. # age = Int( 28, # input = True ) # composite E-modulus # E_c = Property(Float, depends_on='+input') @cached_property def _get_E_c(self): return self.ccs_unit_cell_ref.get_E_c_time(self.age) # Poisson's ratio # nu = Property(Float, depends_on='+input') @cached_property def _get_nu(self): return self.ccs_unit_cell_ref.nu
class SPIRRID( Randomization ): #--------------------------------------------------------------------------------------------- # Range of the control process variable epsilon # Define particular control variable points with # the cv array or an equidistant range with (min, max, n) #--------------------------------------------------------------------------------------------- cv = Array( eps_range = True ) min_eps = Float( 0.0, eps_range = True ) max_eps = Float( 0.0, eps_range = True ) n_eps = Float( 80, eps_range = True ) eps_arr = Property( depends_on = 'eps_change' ) @cached_property def _get_eps_arr( self ): # @todo: !!! # This is a side-effect in a property - CRIME !! [rch] # No clear access interface points - naming inconsistent. # define a clean property with a getter and setter # # if the array of control variable points is not given if len( self.cv ) == 0: n_eps = self.n_eps min_eps = self.min_eps max_eps = self.max_eps return linspace( min_eps, max_eps, n_eps ) else: return self.cv #------------------------------------------------------------------------------------ # Configuration of the algorithm #------------------------------------------------------------------------------------ # # cached_dG_grid: # If set to True, the cross product between the pdf values of all random variables # will be precalculated and stored in an n-dimensional grid # otherwise the product is performed for every epsilon in the inner loop anew # cached_dG = Bool( True, alg_option = True ) # compiled_eps_loop: # If set True, the loop over the control variable epsilon is compiled # otherwise, python loop is used. compiled_eps_loop = Bool( False, alg_option = True ) # compiled_QdG_loop: # If set True, the integration loop over the product between the response function # and the pdf . theta product is performed in c # otherwise the numpy arrays are used. compiled_QdG_loop = Bool( False, alg_option = True ) def _compiled_QdG_loop_changed( self ): '''If the inner loop is not compiled, the outer loop must not be compiled as well. ''' if self.compiled_QdG_loop == False: self.compiled_eps = False arg_list = Property( depends_on = 'rf_change, rand_change, conf_change' ) @cached_property def _get_arg_list( self ): arg_list = [] # create argument string for inline function if self.compiled_eps_loop: arg_list += [ 'mu_q_arr', 'e_arr' ] else: arg_list.append( 'e' ) arg_list += ['%s_flat' % name for name in self.rv_keys ] if self.cached_dG: arg_list += [ 'dG_grid' ] else: arg_list += [ '%s_pdf' % name for name in self.rv_keys ] return arg_list dG_C_code = Property( depends_on = 'rf_change, rand_change, conf_change' ) @cached_property def _get_dG_C_code( self ): if self.cached_dG: # q_g - blitz matrix used to store the grid code_str = '\tdouble pdf = dG_grid(' + \ ','.join( [ 'i_%s' % name for name in self.rv_keys ] ) + \ ');\n' else: # qg code_str = '\tdouble pdf = ' + \ '*'.join( [ ' *( %s_pdf + i_%s)' % ( name, name ) for name in self.rv_keys ] ) + \ ';\n' return code_str #------------------------------------------------------------------------------------ # Configurable generation of C-code for mean curve evaluation #------------------------------------------------------------------------------------ C_code = Property( depends_on = 'rf_change, rand_change, conf_change, eps_change' ) @cached_property def _get_C_code( self ): code_str = '' if self.compiled_eps_loop: # create code string for inline function # code_str += 'for( int i_eps = 0; i_eps < %g; i_eps++){\n' % self.n_eps if self.cached_dG: # multidimensional index needed for dG_grid # blitz arrays must be used also for other arrays # code_str += 'double eps = e_arr( i_eps );\n' else: # pointer access possible for single dimensional arrays # use the pointer arithmetics for accessing the pdfs code_str += '\tdouble eps = *( e_arr + i_eps );\n' else: # create code string for inline function # code_str += 'double eps = e;\n' code_str += 'double mu_q(0);\n' code_str += 'double q(0);\n' code_str += '#line 100\n' # create code for constant params for name, value in list(self.const_param_dict.items()): code_str += 'double %s = %g;\n' % ( name, value ) # generate loops over random params for rv in self.rv_list: name = rv.name n_int = rv.n_int # create the loop over the random variable # code_str += 'for( int i_%s = 0; i_%s < %g; i_%s++){\n' % ( name, name, n_int, name ) if self.cached_dG: # multidimensional index needed for pdf_grid - use blitz arrays # code_str += '\tdouble %s = %s_flat( i_%s );\n' % ( name, name, name ) else: # pointer access possible for single dimensional arrays # use the pointer arithmetics for accessing the pdfs code_str += '\tdouble %s = *( %s_flat + i_%s );\n' % ( name, name, name ) if len( self.rv_keys ) > 0: code_str += self.dG_C_code code_str += self.rf.C_code + \ '// Store the values in the grid\n' + \ '\tmu_q += q * pdf;\n' else: code_str += self.rf.C_code + \ '\tmu_q += q;\n' # close the random loops # for name in self.rv_keys: code_str += '};\n' if self.compiled_eps_loop: if self.cached_dG: # blitz matrix code_str += 'mu_q_arr(i_eps) = mu_q;\n' else: code_str += '*(mu_q_arr + i_eps) = mu_q;\n' code_str += '};\n' else: code_str += 'return_val = mu_q;' return code_str compiler_verbose = Int( 0 ) compiler = Str( 'gcc' ) # Option of eval that induces the calculation of variation # in parallel with the mean value so that interim values of Q_grid # are directly used for both. # implicit_var_eval = Bool( False, alg_option = True ) def _eval( self ): '''Evaluate the integral based on the configuration of algorithm. ''' if self.cached_dG == False and self.compiled_QdG_loop == False: raise NotImplementedError('Configuration for pure Python integration is too slow and is not implemented') self._set_compiler() # prepare the array of the control variable discretization # eps_arr = self.eps_arr mu_q_arr = zeros_like( eps_arr ) # prepare the variable for the variance var_q_arr = None if self.implicit_var_eval: var_q_arr = zeros_like( eps_arr ) # prepare the parameters for the compiled function in # a separate dictionary c_params = {} if self.compiled_eps_loop: # for compiled eps_loop the whole input and output array must be passed to c # c_params['e_arr'] = eps_arr c_params['mu_q_arr'] = mu_q_arr #c_params['n_eps' ] = n_eps if self.compiled_QdG_loop: # prepare the lengths of the arrays to set the iteration bounds # for rv in self.rv_list: c_params[ '%s_flat' % rv.name ] = rv.theta_arr if len( self.rv_list ) > 0: if self.cached_dG: c_params[ 'dG_grid' ] = self.dG_grid else: for rv in self.rv_list: c_params['%s_pdf' % rv.name] = rv.dG_arr else: c_params[ 'dG_grid' ] = self.dG_grid if self.cached_dG: conv = converters.blitz else: conv = converters.default t = time.clock() if self.compiled_eps_loop: # C loop over eps, all inner loops must be compiled as well # if self.implicit_var_eval: raise NotImplementedError('calculation of variance not available in the compiled version') inline( self.C_code, self.arg_list, local_dict = c_params, type_converters = conv, compiler = self.compiler, verbose = self.compiler_verbose ) else: # Python loop over eps # for idx, e in enumerate( eps_arr ): if self.compiled_QdG_loop: if self.implicit_var_eval: raise NotImplementedError('calculation of variance not available in the compiled version') # C loop over random dimensions # c_params['e'] = e # prepare the parameter mu_q = inline( self.C_code, self.arg_list, local_dict = c_params, type_converters = conv, compiler = self.compiler, verbose = self.compiler_verbose ) else: # Numpy loops over random dimensions # # get the rf grid for all combinations of # parameter values # Q_grid = self.rf( e, **self.param_dict ) # multiply the response grid with the contributions # of pdf distributions (weighted by the delta of the # random variable disretization) # if not self.implicit_var_eval: # only mean value needed, the multiplication can be done # in-place Q_grid *= self.dG_grid # sum all the values to get the integral mu_q = sum( Q_grid ) else: # get the square values of the grid Q_grid2 = Q_grid ** 2 # make an inplace product of Q_grid with the weights Q_grid *= self.dG_grid # make an inplace product of the squared Q_grid with the weights Q_grid2 *= self.dG_grid # sum all values to get the mean mu_q = sum( Q_grid ) # sum all squared values to get the variance var_q = sum( Q_grid2 ) - mu_q ** 2 # add the value to the return array mu_q_arr[idx] = mu_q if self.implicit_var_eval: var_q_arr[idx] = var_q duration = time.clock() - t return mu_q_arr, var_q_arr, duration def eval_i_dG_grid( self ): '''Get the integral of the pdf * theta grid. ''' return sum( self.dG_grid ) #--------------------------------------------------------------------------------------------- # Output properties #--------------------------------------------------------------------------------------------- # container for the data obtained in the integration # # This is not only the mean curve but also variance and # execution statistics. Such an implementation # concentrates the critical part of the algorithmic # evaluation and avoids duplication of code and # repeated calls. The results are cached in the tuple. # They are accessed by the convenience properties defined # below. # results = Property( depends_on = 'rand_change, conf_change, eps_change' ) @cached_property def _get_results( self ): return self._eval() #--------------------------------------------------------------------------------------------- # Output accessors #--------------------------------------------------------------------------------------------- # the properties that access the cached results and give them a name mu_q_arr = Property() def _get_mu_q_arr( self ): '''mean of q at eps''' return self.results[0] var_q_arr = Property() def _get_var_q_arr( self ): '''variance of q at eps''' # switch on the implicit evaluation of variance # if it has not been the case so far if not self.implicit_var_eval: self.implicit_var_eval = True return self.results[1] exec_time = Property() def _get_exec_time( self ): '''Execution time of the last evaluation. ''' return self.results[2] mean_curve = Property() def _get_mean_curve( self ): '''Mean response curve. ''' return MFnLineArray( xdata = self.eps_arr, ydata = self.mu_q_arr ) var_curve = Property() def _get_var_curve( self ): '''variance of q at eps''' return MFnLineArray( xdata = self.eps_arr, ydata = self.var_q_arr ) #--------------------------------------------------------------------------------------------- # Auxiliary methods #--------------------------------------------------------------------------------------------- def _set_compiler( self ): '''Catch eventual mismatch between scipy.weave and compiler ''' try: uname = os.uname()[3] except: # it is not Linux - just let it go and suffer return #if self.compiler == 'gcc': #os.environ['CC'] = 'gcc-4.1' #os.environ['CXX'] = 'g++-4.1' #os.environ['OPT'] = '-DNDEBUG -g -fwrapv -O3' traits_view = View( Item( 'rf@', show_label = False ), width = 0.3, height = 0.3, resizable = True, scrollable = True, )
class SPIRRIDLAB(HasTraits): '''Class used for elementary parametric studies of spirrid. ''' s = Instance(SPIRRID) evars = DelegatesTo('s') tvars = DelegatesTo('s') q = DelegatesTo('s') exact_arr = Array('float') dpi = Int plot_mode = Enum(['subplots', 'figures']) fig_output_dir = Directory('fig') @on_trait_change('fig_output_dir') def _check_dir(self): if os.access(self.fig_output_dir, os.F_OK) == False: os.mkdir(self.fig_output_dir) e_arr = Property def _get_e_arr(self): return self.s.evar_lst[0] hostname = Property def _get_hostname(self): return gethostname() qname = Str def get_qname(self): if self.qname == '': if isinstance(self.q, types.FunctionType): qname = self.q.__name__ else: # if isinstance(self.q, types.ClassType): qname = self.q.__class__.__name__ else: qname = self.qname return qname show_output = False save_output = True plot_sampling_idx = Array(value=[0, 1], dtype=int) def _plot_sampling(self, i, n_col, sampling_type, p=p, ylim=None, xlim=None): '''Construct a spirrid object, run the calculation plot the mu_q / e curve and save it in the subdirectory. ''' s = self.s s.sampling_type = sampling_type plot_idx = self.plot_sampling_idx qname = self.get_qname() # get n randomly selected realizations from the sampling theta = s.sampling.get_samples(500) tvar_x = s.tvar_lst[plot_idx[0]] tvar_y = s.tvar_lst[plot_idx[1]] min_x, max_x, d_x = s.sampling.get_theta_range(tvar_x) min_y, max_y, d_y = s.sampling.get_theta_range(tvar_y) # for vectorized execution add a dimension for control variable theta_args = [t[:, np.newaxis] for t in theta] q_arr = s.q(self.e_arr[None, :], *theta_args) if self.plot_mode == 'figures': f = p.figure(figsize=(7., 6.)) f.subplots_adjust(left=0.15, right=0.97, bottom=0.15, top=0.92) if self.plot_mode == 'subplots': if i == 0: f = p.figure() p.subplot('2%i%i' % (n_col, (i + 1))) p.plot(theta[plot_idx[0]], theta[plot_idx[1]], 'o', color='grey') p.xlabel('$\lambda$') p.ylabel('$\\xi$') p.xlim(min_x, max_x) p.ylim(min_y, max_y) p.title(s.sampling_type) if self.save_output: fname = os.path.join( self.fig_output_dir, qname + '_sampling_' + s.sampling_type + '.png') p.savefig(fname, dpi=self.dpi) if self.plot_mode == 'figures': f = p.figure(figsize=(7., 5)) f.subplots_adjust(left=0.15, right=0.97, bottom=0.18, top=0.91) elif self.plot_mode == 'subplots': p.subplot('2%i%i' % (n_col, (i + 5))) p.plot(self.e_arr, q_arr.T, color='grey') if len(self.exact_arr) > 0: p.plot(self.e_arr, self.exact_arr, label='exact solution', color='black', linestyle='--', linewidth=2) # numerically obtained result p.plot(self.e_arr, s.mu_q_arr, label='numerical integration', linewidth=3, color='black') p.title(s.sampling_type) p.xlabel('$\\varepsilon$ [-]') p.ylabel(r'$q(\varepsilon;\, \lambda,\, \xi)$') if ylim: p.ylim(0.0, ylim) if xlim: p.xlim(0.0, xlim) p.xticks(position=(0, -.015)) p.legend(loc=2) if self.save_output: fname = os.path.join(self.fig_output_dir, qname + '_' + s.sampling_type + '.png') p.savefig(fname, dpi=self.dpi) sampling_structure_btn = Button(label='compare sampling structure') @on_trait_change('sampling_structure_btn') def sampling_structure(self, **kw): '''Plot the response into the file in the fig subdirectory. ''' if self.plot_mode == 'subplots': p.rcdefaults() else: fsize = 28 p.rcParams['font.size'] = fsize rc('legend', fontsize=fsize - 8) rc('axes', titlesize=fsize) rc('axes', labelsize=fsize + 6) rc('xtick', labelsize=fsize - 8) rc('ytick', labelsize=fsize - 8) rc('xtick.major', pad=8) s_lst = ['TGrid', 'PGrid', 'MCS', 'LHS'] for i, s in enumerate(s_lst): self._plot_sampling(i, len(s_lst), sampling_type=s, **kw) if self.show_output: p.show() n_int_range = Array() #=========================================================================== # Output file names for sampling efficiency #=========================================================================== fname_sampling_efficiency_time_nint = Property def _get_fname_sampling_efficiency_time_nint(self): return self.get_qname( ) + '_' + '%s' % self.hostname + '_time_nint' + '.png' fname_sampling_efficiency_error_nint = Property def _get_fname_sampling_efficiency_error_nint(self): return self.get_qname( ) + '_' + '%s' % self.hostname + '_error_nint' + '.png' fname_sampling_efficiency_error_time = Property def _get_fname_sampling_efficiency_error_time(self): return self.get_qname( ) + '_' + '%s' % self.hostname + '_error_time' + '.png' fnames_sampling_efficiency = Property def _get_fnames_sampling_efficiency(self): fnames = [self.fname_sampling_efficiency_time_nint] if len(self.exact_arr) > 0: fnames += [ self.fname_sampling_efficiency_error_nint, self.fname_sampling_efficiency_error_time ] return fnames #=========================================================================== # Run sampling efficiency studies #=========================================================================== sampling_types = Array(value=['TGrid', 'PGrid', 'MCS', 'LHS'], dtype=str) sampling_efficiency_btn = Button(label='compare sampling efficiency') @on_trait_change('sampling_efficiency_btn') def sampling_efficiency(self): ''' Run the code for all available sampling types. Plot the results. ''' def run_estimation(n_int, sampling_type): # instantiate spirrid with samplingetization methods print 'running', sampling_type, n_int self.s.set(n_int=n_int, sampling_type=sampling_type) n_sim = self.s.sampling.n_sim exec_time = np.sum(self.s.exec_time) return self.s.mu_q_arr, exec_time, n_sim # vectorize the estimation to accept arrays run_estimation_vct = np.vectorize(run_estimation, [object, float, int]) #=========================================================================== # Generate the inspected domain of input parameters using broadcasting #=========================================================================== run_estimation_vct([5], ['PGrid']) sampling_types = self.sampling_types sampling_colors = np.array( ['grey', 'black', 'grey', 'black'], dtype=str) # 'blue', 'green', 'red', 'magenta' sampling_linestyle = np.array(['--', '--', '-', '-'], dtype=str) # run the estimation on all combinations of n_int and sampling_types mu_q, exec_time, n_sim_range = run_estimation_vct( self.n_int_range[:, None], sampling_types[None, :]) p.rcdefaults() f = p.figure(figsize=(12, 6)) f.subplots_adjust(left=0.06, right=0.94) #=========================================================================== # Plot the results #=========================================================================== p.subplot(1, 2, 1) p.title('response for %d $n_\mathrm{sim}$' % n_sim_range[-1, -1]) for i, (sampling, color, linestyle) in enumerate( zip(sampling_types, sampling_colors, sampling_linestyle)): p.plot(self.e_arr, mu_q[-1, i], color=color, label=sampling, linestyle=linestyle) if len(self.exact_arr) > 0: p.plot(self.e_arr, self.exact_arr, color='black', label='Exact solution') p.legend(loc=1) p.xlabel('e', fontsize=18) p.ylabel('q', fontsize=18) # @todo: get n_sim - x-axis p.subplot(1, 2, 2) for i, (sampling, color, linestyle) in enumerate( zip(sampling_types, sampling_colors, sampling_linestyle)): p.loglog(n_sim_range[:, i], exec_time[:, i], color=color, label=sampling, linestyle=linestyle) p.legend(loc=2) p.xlabel('$n_\mathrm{sim}$', fontsize=18) p.ylabel('$t$ [s]', fontsize=18) if self.save_output: basename = self.fname_sampling_efficiency_time_nint fname = os.path.join(self.fig_output_dir, basename) p.savefig(fname, dpi=self.dpi) #=========================================================================== # Evaluate the error #=========================================================================== if len(self.exact_arr) > 0: er = ErrorEval(exact_arr=self.exact_arr) def eval_error(mu_q, error_measure): return error_measure(mu_q) eval_error_vct = np.vectorize(eval_error) error_measures = np.array( [er.eval_error_max, er.eval_error_energy, er.eval_error_rms]) error_table = eval_error_vct(mu_q[:, :, None], error_measures[None, None, :]) f = p.figure(figsize=(14, 6)) f.subplots_adjust(left=0.07, right=0.97, wspace=0.26) p.subplot(1, 2, 1) p.title('max rel. lack of fit') for i, (sampling, color, linestyle) in enumerate( zip(sampling_types, sampling_colors, sampling_linestyle)): p.loglog(n_sim_range[:, i], error_table[:, i, 0], color=color, label=sampling, linestyle=linestyle) #p.ylim( 0, 10 ) p.legend() p.xlabel('$n_\mathrm{sim}$', fontsize=18) p.ylabel('$\mathrm{e}_{\max}$ [-]', fontsize=18) p.subplot(1, 2, 2) p.title('rel. root mean square error') for i, (sampling, color, linestyle) in enumerate( zip(sampling_types, sampling_colors, sampling_linestyle)): p.loglog(n_sim_range[:, i], error_table[:, i, 2], color=color, label=sampling, linestyle=linestyle) p.legend() p.xlabel('$n_{\mathrm{sim}}$', fontsize=18) p.ylabel('$\mathrm{e}_{\mathrm{rms}}$ [-]', fontsize=18) if self.save_output: basename = self.fname_sampling_efficiency_error_nint fname = os.path.join(self.fig_output_dir, basename) p.savefig(fname, dpi=self.dpi) f = p.figure(figsize=(14, 6)) f.subplots_adjust(left=0.07, right=0.97, wspace=0.26) p.subplot(1, 2, 1) p.title('rel. max lack of fit') for i, (sampling, color, linestyle) in enumerate( zip(sampling_types, sampling_colors, sampling_linestyle)): p.loglog(exec_time[:, i], error_table[:, i, 0], color=color, label=sampling, linestyle=linestyle) p.legend() p.xlabel('time [s]', fontsize=18) p.ylabel('$\mathrm{e}_{\max}$ [-]', fontsize=18) p.subplot(1, 2, 2) p.title('rel. root mean square error') for i, (sampling, color, linestyle) in enumerate( zip(sampling_types, sampling_colors, sampling_linestyle)): p.loglog(exec_time[:, i], error_table[:, i, 2], color=color, label=sampling, linestyle=linestyle) p.legend() p.xlabel('time [s]', fontsize=18) p.ylabel('$\mathrm{e}_{\mathrm{rms}}$ [-]', fontsize=18) if self.save_output: basename = self.fname_sampling_efficiency_error_time fname = os.path.join(self.fig_output_dir, basename) p.savefig(fname, dpi=self.dpi) if self.show_output: p.show() #=========================================================================== # Efficiency of numpy versus C code #=========================================================================== run_lst_detailed_config = Property(List) def _get_run_lst_detailed_config(self): run_lst = [] if hasattr(self.q, 'c_code'): run_lst += [ # ('c', # {'cached_dG' : True, # 'compiled_eps_loop' : True }, # 'go-', # '$\mathsf{C}_{\\varepsilon} \{\, \mathsf{C}_{\\theta} \{\, q(\\varepsilon,\\theta) \cdot G[\\theta] \,\}\,\} $ - %4.2f sec', # ), # ('c', # {'cached_dG' : True, # 'compiled_eps_loop' : False }, # 'r-2', # '$\mathsf{Python} _{\\varepsilon} \{\, \mathsf{C}_{\\theta} \{\, q(\\varepsilon,\\theta) \cdot G[\\theta] \,\}\,\} $ - %4.2f sec' # ), # ('c', # {'cached_dG' : False, # 'compiled_eps_loop' : True }, # 'r-2', # '$\mathsf{C}_{\\varepsilon} \{\, \mathsf{C}_{\\theta} \{\, q(\\varepsilon,\\theta) \cdot g[\\theta_1] \cdot \ldots \cdot g[\\theta_m] \,\}\,\} $ - %4.2f sec' # ), ( 'c', { 'cached_dG': False, 'compiled_eps_loop': False }, 'bx-', '$\mathsf{Python} _{\\varepsilon} \{\, \mathsf{C}_{\\theta} \{\, q(\\varepsilon,\\theta) \cdot g[\\theta_1] \cdot \ldots \cdot g[\\theta_m] \,\} \,\} $ - %4.2f sec', ) ] if hasattr(self.q, 'cython_code'): run_lst += [ # ('cython', # {'cached_dG' : True, # 'compiled_eps_loop' : True }, # 'go-', # '$\mathsf{Cython}_{\\varepsilon} \{\, \mathsf{Cython}_{\\theta} \{\, q(\\varepsilon,\\theta) \cdot G[\\theta] \,\}\,\} $ - %4.2f sec', # ), # ('cython', # {'cached_dG' : True, # 'compiled_eps_loop' : False }, # 'r-2', # '$\mathsf{Python} _{\\varepsilon} \{\, \mathsf{Cython}_{\\theta} \{\, q(\\varepsilon,\\theta) \cdot G[\\theta] \,\}\,\} $ - %4.2f sec' # ), # ('cython', # {'cached_dG' : False, # 'compiled_eps_loop' : True }, # 'r-2', # '$\mathsf{Cython}_{\\varepsilon} \{\, \mathsf{Cython}_{\\theta} \{\, q(\\varepsilon,\\theta) \cdot g[\\theta_1] \cdot \ldots \cdot g[\\theta_m] \,\}\,\} $ - %4.2f sec' # ), # ('cython', # {'cached_dG' : False, # 'compiled_eps_loop' : False }, # 'bx-', # '$\mathsf{Python} _{\\varepsilon} \{\, \mathsf{Cython}_{\\theta} \{\, q(\\varepsilon,\\theta) \cdot g[\\theta_1] \cdot \ldots \cdot g[\\theta_m] \,\} \,\} $ - %4.2f sec', # ) ] if hasattr(self.q, '__call__'): run_lst += [ # ('numpy', # {}, # 'y--', # '$\mathsf{Python}_{\\varepsilon} \{\, \mathsf{Numpy}_{\\theta} \{\, q(\\varepsilon,\\theta) \cdot G[\\theta] \,\} \,\} $ - %4.2f sec' # ) ] return run_lst # number of recalculations to get new time. n_recalc = Int(2) def codegen_efficiency(self): # define a tables with the run configurations to start in a batch basenames = [] qname = self.get_qname() s = self.s legend = [] legend_lst = [] time_lst = [] p.figure() for idx, run in enumerate(self.run_lst_detailed_config): code, run_options, plot_options, legend_string = run s.codegen_type = code s.codegen.set(**run_options) print 'run', idx, run_options for i in range(self.n_recalc): s.recalc = True # automatically proagated within spirrid print 'execution time', s.exec_time p.plot(s.evar_lst[0], s.mu_q_arr, plot_options) # @todo: this is not portable!! #legend.append(legend_string % s.exec_time) #legend_lst.append(legend_string[:-12]) time_lst.append(s.exec_time) p.xlabel('strain [-]') p.ylabel('stress') #p.legend(legend, loc = 2) p.title(qname) if self.save_output: print 'saving codegen_efficiency' basename = qname + '_' + 'codegen_efficiency' + '.png' basenames.append(basename) fname = os.path.join(self.fig_output_dir, basename) p.savefig(fname, dpi=self.dpi) self._bar_plot(legend_lst, time_lst) p.title('%s' % s.sampling_type) if self.save_output: basename = qname + '_' + 'codegen_efficiency_%s' % s.sampling_type + '.png' basenames.append(basename) fname = os.path.join(self.fig_output_dir, basename) p.savefig(fname, dpi=self.dpi) if self.show_output: p.show() return basenames #=========================================================================== # Efficiency of numpy versus C code #=========================================================================== run_lst_language_config = Property(List) def _get_run_lst_language_config(self): run_lst = [] if hasattr(self.q, 'c_code'): run_lst += [( 'c', { 'cached_dG': False, 'compiled_eps_loop': False }, 'bx-', '$\mathsf{Python} _{\\varepsilon} \{\, \mathsf{C}_{\\theta} \{\, q(\\varepsilon,\\theta) \cdot g[\\theta_1] \cdot \ldots \cdot g[\\theta_m] \,\} \,\} $ - %4.2f sec', )] if hasattr(self.q, 'cython_code'): run_lst += [( 'cython', { 'cached_dG': False, 'compiled_eps_loop': False }, 'bx-', '$\mathsf{Python} _{\\varepsilon} \{\, \mathsf{Cython}_{\\theta} \{\, q(\\varepsilon,\\theta) \cdot g[\\theta_1] \cdot \ldots \cdot g[\\theta_m] \,\} \,\} $ - %4.2f sec', )] if hasattr(self.q, '__call__'): run_lst += [( 'numpy', {}, 'y--', '$\mathsf{Python}_{\\varepsilon} \{\, \mathsf{Numpy}_{\\theta} \{\, q(\\varepsilon,\\theta) \cdot G[\\theta] \,\} \,\} $ - %4.2f sec' )] return run_lst extra_compiler_args = Bool(True) le_sampling_lst = List(['LHS', 'PGrid']) le_n_int_lst = List([440, 5000]) #=========================================================================== # Output file names for language efficiency #=========================================================================== fnames_language_efficiency = Property def _get_fnames_language_efficiency(self): return [ '%s_codegen_efficiency_%s_extra_%s.png' % (self.qname, self.hostname, extra) for extra in [self.extra_compiler_args] ] language_efficiency_btn = Button(label='compare language efficiency') @on_trait_change('language_efficiency_btn') def codegen_language_efficiency(self): # define a tables with the run configurations to start in a batch home_dir = expanduser("~") # pyxbld_dir = os.path.join(home_dir, '.pyxbld') # if os.path.exists(pyxbld_dir): # shutil.rmtree(pyxbld_dir) python_compiled_dir = os.path.join(home_dir, '.python27_compiled') if os.path.exists(python_compiled_dir): shutil.rmtree(python_compiled_dir) for extra, fname in zip([self.extra_compiler_args], self.fnames_language_efficiency): print 'extra compilation args:', extra legend_lst = [] error_lst = [] n_sim_lst = [] exec_times_sampling = [] meth_lst = zip(self.le_sampling_lst, self.le_n_int_lst) for item, n_int in meth_lst: print 'sampling method:', item s = self.s s.exec_time # eliminate first load time delay (first column) s.n_int = n_int s.sampling_type = item exec_times_lang = [] for idx, run in enumerate(self.run_lst_language_config): code, run_options, plot_options, legend_string = run #os.system('rm -fr ~/.python27_compiled') s.codegen_type = code s.codegen.set(**run_options) if s.codegen_type == 'c': s.codegen.set(**dict(use_extra=extra)) print 'run', idx, run_options exec_times_run = [] for i in range(self.n_recalc): s.recalc = True # automatically propagated exec_times_run.append(s.exec_time) print 'execution time', s.exec_time legend_lst.append(legend_string[:-12]) if s.codegen_type == 'c': # load weave.inline time from tmp file and fix values in time_arr #@todo - does not work on windows import tempfile tdir = tempfile.gettempdir() f = open(os.path.join(tdir, 'w_time'), 'r') value_t = float(f.read()) f.close() exec_times_run[0][1] = value_t exec_times_run[0][2] -= value_t exec_times_lang.append(exec_times_run) else: exec_times_lang.append(exec_times_run) print 'legend_lst', legend_lst n_sim_lst.append(s.sampling.n_sim) exec_times_sampling.append(exec_times_lang) #=========================================================================== # Evaluate the error #=========================================================================== if len(self.exact_arr) > 0: er = ErrorEval(exact_arr=self.exact_arr) error_lst.append((er.eval_error_rms(s.mu_q_arr), er.eval_error_max(s.mu_q_arr))) times_arr = np.array(exec_times_sampling, dtype='d') self._multi_bar_plot(meth_lst, legend_lst, times_arr, error_lst, n_sim_lst) if self.save_output: fname_path = os.path.join(self.fig_output_dir, fname) p.savefig(fname_path, dpi=self.dpi) if self.show_output: p.show() def combination_efficiency(self, tvars_det, tvars_rand): ''' Run the code for all available random parameter combinations. Plot the results. ''' qname = self.get_qname() s = self.s s.set(sampling_type='TGrid') # list of all combinations of response function parameters rv_comb_lst = list(powerset(s.tvars.keys())) p.figure() exec_time_lst = [] for id, rv_comb in enumerate(rv_comb_lst[163:219]): # [1:-1] s.tvars = tvars_det print 'Combination', rv_comb for rv in rv_comb: s.tvars[rv] = tvars_rand[rv] #legend = [] #p.figure() time_lst = [] for idx, run in enumerate(self.run_lst): code, run_options, plot_options, legend_string = run print 'run', idx, run_options s.codegen_type = code s.codegen.set(**run_options) #p.plot(s.evar_lst[0], s.mu_q_arr, plot_options) #print 'integral of the pdf theta', s.eval_i_dG_grid() print 'execution time', s.exec_time time_lst.append(s.exec_time) #legend.append(legend_string % s.exec_time) exec_time_lst.append(time_lst) p.plot(np.array((1, 2, 3, 4)), np.array(exec_time_lst).T) p.xlabel('method') p.ylabel('time') if self.save_output: print 'saving codegen_efficiency' fname = os.path.join( self.fig_output_dir, qname + '_' + 'combination_efficiency' + '.png') p.savefig(fname, dpi=self.dpi) if self.show_output: p.title(s.q.title) p.show() def _bar_plot(self, legend_lst, time_lst): rc('font', size=15) #rc('font', family = 'serif', style = 'normal', variant = 'normal', stretch = 'normal', size = 15) fig = p.figure(figsize=(10, 5)) n_tests = len(time_lst) times = np.array(time_lst) x_norm = times[1] xmax = times.max() rel_xmax = xmax / x_norm rel_times = times / x_norm m = int(rel_xmax % 10) if m < 5: x_max_plt = int(rel_xmax) - m + 10 else: x_max_plt = int(rel_xmax) - m + 15 ax1 = fig.add_subplot(111) p.subplots_adjust(left=0.45, right=0.88) #fig.canvas.set_window_title('window title') pos = np.arange(n_tests) + 0.5 rects = ax1.barh(pos, rel_times, align='center', height=0.5, color='w', edgecolor='k') ax1.set_xlabel('normalized execution time [-]') ax1.axis([0, x_max_plt, 0, n_tests]) ax1.set_yticks(pos) ax1.set_yticklabels(legend_lst) for rect, t in zip(rects, rel_times): width = rect.get_width() xloc = width + (0.03 * rel_xmax) clr = 'black' align = 'left' yloc = rect.get_y() + rect.get_height() / 2.0 ax1.text(xloc, yloc, '%4.2f' % t, horizontalalignment=align, verticalalignment='center', color=clr) #, weight = 'bold') ax2 = ax1.twinx() ax1.plot([1, 1], [0, n_tests], 'k--') ax2.set_yticks([0] + list(pos) + [n_tests]) ax2.set_yticklabels([''] + ['%4.2f s' % s for s in list(times)] + ['']) ax2.set_xticks([0, 1] + range(5, x_max_plt + 1, 5)) ax2.set_xticklabels( ['%i' % s for s in ([0, 1] + range(5, x_max_plt + 1, 5))]) def _multi_bar_plot(self, title_lst, legend_lst, time_arr, error_lst, n_sim_lst): '''Plot the results if the code efficiency. ''' p.rcdefaults() fsize = 14 fig = p.figure(figsize=(15, 3)) rc('font', size=fsize) rc('legend', fontsize=fsize - 2) legend_lst = ['weave', 'cython', 'numpy'] # times are stored in 3d array - dimensions are: n_sampling, n_lang, n_run, n_times = time_arr.shape print 'arr', time_arr.shape times_sum = np.sum(time_arr, axis=n_times) p.subplots_adjust(left=0.1, right=0.95, wspace=0.1, bottom=0.15, top=0.8) for meth_i in range(n_sampling): ax1 = fig.add_subplot(1, n_sampling, meth_i + 1) ax1.set_xlabel('execution time [s]') ytick_pos = np.arange(n_lang) + 1 # ax1.axis([0, x_max_plt, 0, n_lang]) # todo: **2 n_vars if len(self.exact_arr) > 0: ax1.set_title( '%s: $ n_\mathrm{sim} = %s, \mathrm{e}_\mathrm{rms}=%s, \mathrm{e}_\mathrm{max}=%s$' % (title_lst[meth_i][0], self._formatSciNotation('%.2e' % n_sim_lst[meth_i]), self._formatSciNotation('%.2e' % error_lst[meth_i][0]), self._formatSciNotation('%.2e' % error_lst[meth_i][1]))) else: ax1.set_title( '%s: $ n_\mathrm{sim} = %s$' % (title_lst[meth_i][0], self._formatSciNotation('%.2e' % n_sim_lst[meth_i]))) ax1.set_yticks(ytick_pos) if meth_i == 0: ax1.set_yticklabels(legend_lst, fontsize=fsize + 2) else: ax1.set_yticklabels([]) ax1.set_xlim(0, 1.2 * np.max(times_sum[meth_i])) distance = 0.2 height = 1.0 / n_run - distance offset = height / 2.0 colors = ['w', 'w', 'w', 'r', 'y', 'b', 'g', 'm'] hatches = ['/', '\\', 'x', '-', '+', '|', 'o', 'O', '.', '*'] label_lst = ['sampling', 'compilation', 'integration'] for i in range(n_run): pos = np.arange(n_lang) + 1 - offset + i * height end_bar_pos = np.zeros((n_lang, ), dtype='d') for j in range(n_times): if i > 0: label = label_lst[j] else: label = None bar_lengths = time_arr[meth_i, :, i, j] rects = ax1.barh(pos, bar_lengths, align='center', height=height, left=end_bar_pos, color=colors[j], edgecolor='k', hatch=hatches[j], label=label) end_bar_pos += bar_lengths for k in range(n_lang): x_val = times_sum[meth_i, k, i] + 0.01 * np.max(times_sum[meth_i]) ax1.text(x_val, pos[k], '$%4.2f\,$s' % x_val, horizontalalignment='left', verticalalignment='center', color='black') #, weight = 'bold') if meth_i == 0: ax1.text(0.02 * np.max(times_sum[0]), pos[k], '$%i.$' % (i + 1), horizontalalignment='left', verticalalignment='center', color='black', bbox=dict(pad=0., ec="w", fc="w")) p.legend(loc=0) def _formatSciNotation(self, s): # transform 1e+004 into 1e4, for example tup = s.split('e') try: significand = tup[0].rstrip('0').rstrip('.') sign = tup[1][0].replace('+', '') exponent = tup[1][1:].lstrip('0') if significand == '1': # reformat 1x10^y as 10^y significand = '' if exponent: exponent = '10^{%s%s}' % (sign, exponent) if significand and exponent: return r'%s{\cdot}%s' % (significand, exponent) else: return r'%s%s' % (significand, exponent) except IndexError, msg: return s
class NIDOrderStats(HasTraits): distr_list = List(desc='NID distributions') n = Property(Int, depends_on='distr_list', desc='number of realizations') def _get_n(self): return len(self.distr_list) k = Int(1, auto_set=False, enter_set=True, desc='kth order statistics to evaluate') x_arr = np.linspace(0, 10, 200) cdf_arr = Property(Array, depends_on='distr_list') @cached_property def _get_cdf_arr(self): '''creates a 2D array of shape (m,x_arr) containing m CDFs''' cdf_arr = np.ones((self.n + 2, len(self.x_arr))) for i, distr in enumerate(self.distr_list): cdf_arr[i] = distr.cdf(self.x_arr) return cdf_arr sf_arr = Property(Array, depends_on='distr_list') @cached_property def _get_sf_arr(self): '''creates a 2D array of shape (m,x_arr) containing m SFs''' sf_arr = np.ones((self.n + 2, len(self.x_arr))) for i, distr in enumerate(self.distr_list): sf_arr[i] = distr.sf(self.x_arr) return sf_arr pdf_arr = Property(Array, depends_on='distr_list') @cached_property def _get_pdf_arr(self): '''creates a 2D array of shape (m,x_arr) containing m PDFs''' pdf_arr = np.ones((self.n + 2, len(self.x_arr))) for i, distr in enumerate(self.distr_list): pdf_arr[i] = distr.pdf(self.x_arr) return pdf_arr def kth_pdf(self): '''evaluates the PDF of the kth entry; cases k = 1 and k > 1 are distinguished The most general formula is used here. For higher performance use CIDOrderStats''' if len(self.distr_list) == self.n: n = self.n k = self.k if n >= k: fct = sp.misc.factorial # the constant actually tells how many redundances are present in the summation constant = 1. / (fct(k - 1) * fct(n - k)) summation = np.zeros(len(self.x_arr)) permutations = it.permutations(list(range(n)), n) loop_run = True t = time.clock() while loop_run == True: try: idx = list(next(permutations)) if k == 1: id_pdf = idx[k - 1] pdf = self.pdf_arr[id_pdf] if n == 1: PDF = pdf summation += PDF.flatten() elif n == 2: id_sf = idx[1] sf = self.sf_arr[id_sf] PDF = pdf * sf summation += PDF.flatten() else: id_sf = idx[k:] sf = self.sf_arr[id_sf] PDF = pdf * sf.prod(axis=0) summation += PDF.flatten() else: id_cdf = idx[:k - 1] cdf = self.cdf_arr[id_cdf] id_pdf = idx[k - 1] pdf = self.pdf_arr[id_pdf] id_sf = idx[k:] sf = self.sf_arr[id_sf] PDF = cdf.prod(axis=0) * pdf * sf.prod(axis=0) summation += PDF.flatten() except StopIteration: loop_run = False print(('NID', time.clock() - t, 's')) return constant * summation else: raise ValueError('n < k') else: raise ValueError('%i distributions required, %i given' % (self.n, len(self.distr_list)))
class HPShell(HasTraits): '''Geometry definition of a hyperbolic parabolid shell. ''' #----------------------------------------------------------------- # geometric parameters of the shell #----------------------------------------------------------------- # dimensions of the shell for one quarter of mush_roof # length_xy_quarter = Float(3.5, input=True) # [m] length_z = Float(0.927, input=True) # [m] # corresponds to the delta in the geometry .obj-file with name '4x4m' as a cut off # delta_h = Float(0.865, input=True) # [m] # scale factors for geometric dimensions # NOTE: parameters can be scaled separately, i.e. scaling of 'delta_h' (inclination of the shell) # does not effect the scaling of the thickness # scalefactor_delta_h = Float(1.00, input=True) # [-] scalefactor_length_xy = Float(1.00, input=True) # [-] # thickness of the shell # NOTE: only used by the option 'const_reinf_layer' # t_shell = Float(0.06, input=True) # [m] width_top_col = Float(0.45, input=True) # [m] # factor shifting the z coordinates at the middle nodes of the edges upwards # in order to include the effect of imperfection in the formwork z_imperfection_factor = Float(0.0) #----------------------------------------------------------------- # specify the relation of the total structure (in the 'mushroof'-model) # with respect to a quarter of one shell defined in 'HPShell' #----------------------------------------------------------------- # @todo: "four" is not supported by "n_elems_xy_dict"in mushroff_model mushroof_part = Enum('one', 'quarter', 'four', input=True) # 'scale_size' parameter is used as scale factor for different mushroof parts # Defines the proportion between the length of the total model # with respect to the length of a quarter shell as the # basic substructure of which the model consists of. # @todo: add "depends_on" or remove "cached_property" # @todo: move to class definition of "mushroof_model" not in "HPShell" # (also see there "n_elems_dict" with implicit "scale_factor") # scale_size = Property(Float, depends_on='mushroof_part') @cached_property def _get_scale_size(self): scale_dict = {'quarter': 1.0, 'one': 2.0, 'four': 4.0} return scale_dict[self.mushroof_part] # origin of the shell # X0 = Array(float, input=True) def _X0_default(self): return array([0., 0., 0.]) #----------------------------------------------------------------- # discretisation #----------------------------------------------------------------- # number of element used for the discretisation ( dimensions of the entire model) # n_elems_xy_quarter = Int(5, input=True) n_elems_z = Int(3, input=True) n_elems_xy = Property(Int, depends_on='n_elems_xy_quarter, +input') @cached_property def _get_n_elems_xy(self): return self.n_elems_xy_quarter * self.scale_size #----------------------------------------------------------------- # option: 'shift_elems' #----------------------------------------------------------------- # shift of column elements # if set to "True" (default) the information defined in 'shift_array' is used. # shift_elems = Bool(True, input=True) # 'shift_array' is used to place element corners at a defined global # position in order to connect the shell with the corner nodes of the column. # [x_shift, y_shift, number of element s between the coordinate position] # NOTE: 'shift_array' needs to have shape (:,3)! # shift_array = Array(float, input=True) def _shift_array_default(self): return array( [[self.width_top_col / 2**0.5, self.width_top_col / 2**0.5, 1]]) #----------------------------------------------------------------- # option: 'const_reinf_layer' #----------------------------------------------------------------- # 'const_reinf_layer' - parameter is used only for the non-linear analysis, # where an element layer with a constant thickness is needed to simulate the # reinforced concrete at the top and bottom of the TRC-shell. # const_reinf_layer_elem = Bool(False, input=True) t_reinf_layer = Float(0.03, input=True) # [m] n_elems_reinf_layer = Int( 1, input=True) #number of dofs used for edge refinement #----------------------------------------------------------------- # read vertice points of the shell and derive a normalized # RBF-function for the shell approximation #----------------------------------------------------------------- # "lowerface_cut_off" - option replaces constant height for the coordinates # which connect to the column (this cuts of the shell geometry horizontally # at the bottom of the lower face of the shell geometry. # cut_off_lowerface = Bool(True, input=True) # choose geometric file (obj-data file) # geo_input_name = Enum('350x350cm', '4x4m', '02', input=True) # filter for '4x4m' file needs to be done to have regular grid # in order to rbf-function leading to stable solution without oscilation # geo_filter = Dict({'4x4m': delete_second_rows}) # ,'350x350cm' : delete_second_rows} ) def _read_arr(self, side='lowerface_'): '''read the robj-file saved in the subdirectory 'geometry_files' ''' file_name = side + self.geo_input_name + '.robj' file_path = join('geometry_files', file_name) # get an array with the vertice coordinates # v_arr = read_rsurface(file_path) # print 'v_arr before filtering \n', v_arr # print 'v_arr.shape before filtering \n', v_arr.shape filter = self.geo_filter.get(self.geo_input_name, None) if filter != None: v_arr = filter(v_arr) # print 'v_arr after filtering \n', v_arr # print 'v_arr.shape after filtering \n', v_arr.shape return v_arr # array of the vertex positions in global # x,y,z-coordinates defining the lower surface of the shell # vl_arr = Property(Array(float), depends_on='geo_input_name') @cached_property def _get_vl_arr(self): vl_arr = self._read_arr('lowerface_') if self.cut_off_lowerface == True: print '--- lower face z-coords cut off ---' # z-values of the coords from the lower face are cut off. # From the highest z-coordinate of the lower face the vertical # distance is 'delta h (for 4x4m: delta_h = 1.0m). # At this limit the lower face is cut off. # NOTE: the global z coordinate is assumed to point up # and must be given in the same unite as 'delta_h', i.e. in [m]. # vl_z_max = max(vl_arr[:, 2]) if self.geo_input_name == '4x4m': # NOTE: the global z-coordinates are given in the geo data file in [m] # no conversion of unites necessary (self.delta_h is given in [m]) delta_h = self.delta_h elif self.geo_input_name == '350x350cm': # NOTE: the global z-coordinates are given in the geo data file in [cm] # convert delta_h from [m] to [cm] # delta_h = self.delta_h * 100. vl_z_min = vl_z_max - delta_h vl_arr_z = where(vl_arr[:, 2] < vl_z_min, vl_z_min, vl_arr[:, 2]) vl_arr = c_[vl_arr[:, 0:2], vl_arr_z] return vl_arr # array of the vertex positions in global # x,y,z-coordinates defining the upper surface of the shell # vu_arr = Property(Array(float), depends_on='geo_input_name') @cached_property def _get_vu_arr(self): return self._read_arr('upperface_') # normalized coordinates of the vertices for the lowerface # NOTE: the underline character indicates a normalized value # @todo: 'normalize_rsurfaces' is called twice for 'vl_arr_' and 'vu_arr_' # vl_arr_ = Property(Array(float), depends_on='geo_input_name') @cached_property def _get_vl_arr_(self): vl_arr_, vu_arr_ = normalize_rsurfaces(self.vl_arr, self.vu_arr) return vl_arr_ # normalized coordinates of the vertices for the lowerface # NOTE: the underline character indicates a normalized value # vu_arr_ = Property(Array(float), depends_on='geo_input_name') @cached_property def _get_vu_arr_(self): vl_arr_, vu_arr_ = normalize_rsurfaces(self.vl_arr, self.vu_arr) return vu_arr_ rbf_l_ = Property(Instance(Rbf), depends_on='geo_input_name') @cached_property def _get_rbf_l_(self): # use a radial basis function approximation (rbf) (i.e. interpolation of # scattered data) based on the normalized vertex points of the lower face # xl_ = self.vl_arr_[:, 0] yl_ = self.vl_arr_[:, 1] zl_ = self.vl_arr_[:, 2] # flip the orientation of the local coordinate axis # depending on the geometry file used # if self.geo_input_name == '350x350cm': xl_ = 1 - self.vl_arr_[:, 0] if self.geo_input_name == '4x4m': yl_ = 1 - self.vl_arr_[:, 1] rbf_l_ = Rbf(xl_, yl_, zl_, function='cubic') # rbf_l_ = Rbf( xl_, yl_, zl_, function = 'linear' ) return rbf_l_ rbf_u_ = Property(Instance(Rbf), depends_on='geo_input_name') @cached_property def _get_rbf_u_(self): # use a radial basis function approximation (rbf) (i.e. interpolation of # scattered data) based on the normalized vertex points of the upper face # xu_ = self.vu_arr_[:, 0] yu_ = self.vu_arr_[:, 1] zu_ = self.vu_arr_[:, 2] # flip the orientation of the local coordinate axis # depending on the geometry file used # if self.geo_input_name == '350x350cm': xu_ = 1 - self.vu_arr_[:, 0] if self.geo_input_name == '4x4m': yu_ = 1 - self.vu_arr_[:, 1] rbf_u_ = Rbf(xu_, yu_, zu_, function='cubic') # rbf_u_ = Rbf( xu_, yu_, zu_, function = 'linear' ) return rbf_u_ #------------------------------------------------------------------------------ # hp_shell geometric transformation # NOTE: returns the global coordinates of the shell based on the supplied local # grid points #------------------------------------------------------------------------------ def __call__(self, points): '''Return the global coordinates of the supplied local points. ''' # number of local grid points for each coordinate direction # NOTE: values must range between 0 and 1 # xi_, yi_, zi_ = points[:, 0], points[:, 1], points[:, 2] # insert imperfection (shift the middle node of the shell upwards) imp = self.z_imperfection_factor zi_ += imp * xi_ + imp * yi_ - 2 * imp * xi_ * yi_ # size of total structure # # @todo: move to class definition of "mushroof_model" and send to "__call__" scale_size = self.scale_size # @todo: add "_quarter" (see above) length_xy_tot = self.length_xy_quarter * scale_size n_elems_xy_quarter = self.n_elems_xy_quarter # print 'HPShell n_elems_xy_quarter', n_elems_xy_quarter # distance from origin for each mushroof_part # def d_origin_fn(self, coords): if self.mushroof_part == 'quarter': return coords if self.mushroof_part == 'one': return abs(2.0 * coords - 1.0) # @todo: corresponding "scale_factor" needs to be added # in order for this to work if self.mushroof_part == 'four': return where(coords < 0.5, abs(4 * coords - 1), abs(-4 * coords + 3)) # element at column shift # if self.shift_elems == True: # define the origin for each model part # def origin_fn(self, coords): if self.mushroof_part == 'quarter': return zeros_like(coords) if self.mushroof_part == 'one': return ones_like(xi_) * 0.5 if self.mushroof_part == 'four': return where(coords < 0.5, 0.25, 0.75) def piecewise_linear_fn(x, x_fix_arr_, y_fix_arr_): '''creates a piecewise linear_fn going through the fix_points values need to be normed running between 0..1 and values have to be unique''' x_fix_arr_ = hstack((0, x_fix_arr_, 1)) y_fix_arr_ = hstack((0, y_fix_arr_, 1)) rbf_fn_ = Rbf(x_fix_arr_, y_fix_arr_, function='linear') #rbf has to be linear return rbf_fn_(x) # define origin for quarter # xi_origin_arr_ = origin_fn(self, xi_) yi_origin_arr_ = origin_fn(self, yi_) # print 'xi_origin_arr_', xi_origin_arr_ # delta towards origin # xi_delta_arr_ = (xi_ - xi_origin_arr_) * scale_size yi_delta_arr_ = (yi_ - yi_origin_arr_) * scale_size # print 'xi_delta_arr_', xi_delta_arr # define sign # xi_sign_arr = where(xi_delta_arr_ == 0., 0., xi_delta_arr_ / abs(xi_delta_arr_)) yi_sign_arr = where(yi_delta_arr_ == 0., 0., yi_delta_arr_ / abs(yi_delta_arr_)) # print 'xi_sign_arr', xi_sign_arr # fix points defined in shift array as normelized values # x_fix_ = self.shift_array[:, 0] / self.length_xy_quarter # print 'x_fix_', x_fix_ y_fix_ = self.shift_array[:, 1] / self.length_xy_quarter n_fix_ = add.accumulate(self.shift_array[:, 2]) / n_elems_xy_quarter # print 'add.accumulate( self.shift_array[:, 2] )', add.accumulate( self.shift_array[:, 2] ) # print 'n_fix_', n_fix_ # print 'piecewise_linear_fn', piecewise_linear_fn( abs( xi_delta_arr_ ), # n_fix_, # x_fix_ ) / scale_size # new xi_ # xi_ = xi_origin_arr_ + xi_sign_arr * piecewise_linear_fn( abs(xi_delta_arr_), n_fix_, x_fix_) / scale_size # print 'xi_new', xi_ # new yi # yi_ = yi_origin_arr_ + yi_sign_arr * piecewise_linear_fn( abs(yi_delta_arr_), n_fix_, y_fix_) / scale_size #------------------------------------------------------------------------------------- # values are used to calculate the z-coordinate using RBF-function of the quarter # (= values of the distance to the origin as absolute value) # xi_rbf_ = d_origin_fn(self, xi_) # print 'xi_rbf_', xi_rbf_ yi_rbf_ = d_origin_fn(self, yi_) # get the z-value at the supplied local grid points # of the lower face # zi_lower_ = self.rbf_l_(xi_rbf_, yi_rbf_) # get the z-value at the supplied local grid points # of the upper face # zi_upper_ = self.rbf_u_(xi_rbf_, yi_rbf_) # constant edge element transformation # if self.const_reinf_layer_elem == True: # arrange and check data # if self.t_reinf_layer > self.t_shell / 2. or self.n_elems_z < 3: print '--- constant edge element transformation canceled ---' print 'the following condition needs to be fullfilled: \n' print 'self.t_reinf_layer <= self.t_shell/2 and self.n_elems_z >= 3' else: n_elems_z = float(self.n_elems_z) # normed thickness will evaluate as t_reinf_layer at each element t_reinf_layer_ = self.t_reinf_layer / self.length_z / ( zi_upper_ - zi_lower_) # zi_old set off from top which needs to be shifted delta_ = self.n_elems_reinf_layer / n_elems_z # get upper, lower and internal coordinates, that need to be shifted zi_lower = where(zi_ <= delta_) zi_upper = where(abs(1 - zi_) <= delta_ + 1e-10) zi_inter = where(abs(zi_ - 0.5) < 0.5 - (delta_ + 1e-10)) # narrowing of coordinates zi_[zi_lower] = zi_[zi_lower] * t_reinf_layer_[ zi_lower] / delta_ zi_[zi_upper] = 1 - ( 1 - zi_[zi_upper]) * t_reinf_layer_[zi_upper] / delta_ zi_[zi_inter] = t_reinf_layer_[zi_inter] + \ (zi_[zi_inter] - delta_) / (1 - 2 * delta_)\ * (1 - 2 * t_reinf_layer_[zi_inter]) print '--- constant edge elements transformation done ---' # thickness is multiplied by the supplied zi coordinate # z_ = (zi_lower_ * self.scalefactor_delta_h + (zi_upper_ - zi_lower_) * zi_) # coordinates of origin # X_0, Y_0, Z_0 = self.X0 print '--- geometric transformation done ---' # multiply the local grid points with the real dimensions in order to obtain the # global coordinates of the mushroof_part: # return c_[X_0 + (xi_ * length_xy_tot) * self.scalefactor_length_xy, Y_0 + (yi_ * length_xy_tot) * self.scalefactor_length_xy, Z_0 + z_ * self.length_z]
class Model(HasTraits): test_xdata = Array test_ydata = Array w_min = Float(0.0, auto_set=False, enter_set=True, params=True) w_max = Float(2., auto_set=False, enter_set=True, params=True) w_pts = Int(100, auto_set=False, enter_set=True, params=True) Ef = Float(181e3, auto_set=False, enter_set=True, params=True) V_f = Float(1.0, params=True) r = Float(3.5e-3, params=True) w = Property(Array, depends_on='w_min,w_max,w_pts') @cached_property def _get_w(self): return np.linspace(self.w_min, self.w_max, self.w_pts) interpolate_experiment = Property(depends_on='test_xdata,test_ydata,w') @cached_property def _get_interpolate_experiment(self): interp = interp1d(self.test_xdata, self.test_ydata, bounds_error=False, fill_value=0.0) return interp(self.w) def model_free(self, tau_loc, tau_shape, tau_scale): xi_shape = 6.7 #xi_scale = 3243. / (182e3 * (pi * 3.5e-3 **2 * 50.)**(-1./xi_shape)*gamma(1+1./xi_shape)) xi_scale = 7.6e-3 #CS=8. #mu_tau = 1.3 * self.r * 3.6 * (1.-0.01) / (2. * 0.01 * CS) #tau_scale = (mu_tau - tau_loc)/tau_shape #xi_scale = 0.0077 #xi_shape = 6.7 #tau_scale = (mu_tau - tau_loc)/tau_shape cb = CBClampedRandXi(pullout=False) spirrid = SPIRRID(q=cb, sampling_type='LHS') tau = RV('gamma', shape=tau_shape, scale=tau_scale, loc=tau_loc) w = self.w spirrid.eps_vars = dict(w=w) spirrid.theta_vars = dict(tau=tau, E_f=self.Ef, V_f=self.V_f, r=self.r, m=xi_shape, sV0=xi_scale) spirrid.n_int = 5000 sigma_c = spirrid.mu_q_arr / self.r**2 plt.plot(w, sigma_c) return sigma_c lack = 1e10 def lack_of_fit(self, params): tau_loc = params[0] tau_shape = params[1] tau_scale = params[2] print params lack = np.sum((self.model_free(tau_loc, tau_shape, tau_scale) - self.interpolate_experiment)**2) print 'params = ', params print 'relative lack of fit', np.sqrt(lack) / np.sum( self.interpolate_experiment) if lack < self.lack: print 'DRAW' self.lack = lack plt.ion() plt.cla() plt.plot(self.w, self.interpolate_experiment, color='black') plt.plot(self.w, self.model_free(tau_loc, tau_shape, tau_scale), color='red', lw=2) plt.draw() plt.show() return lack def eval_params(self): params = minimize(self.lack_of_fit, np.array([0.0, 0.01, 1.0]), method='L-BFGS-B', bounds=((0.0, .01), (0.01, 1.), (0.1, 5.))) return params
class ExpSH(ExType): '''Experiment: Shell Test ''' # label = Str('slab test') implements(IExType) #-------------------------------------------------------------------- # 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(1.25, unit = 'm', input = True, table_field = True, auto_set = False, enter_set = True) thickness = Float(0.03, unit = 'm', input = True, table_field = True, auto_set = False, enter_set = True) # age of the concrete at the time of testing age = Int(28, unit = 'd', input = True, table_field = True, auto_set = False, enter_set = True) loading_rate = Float(0.50, 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 correspond to setup '7u_MAG-07-03_PZ-0708-1' ''' fabric_layout_key = 'MAG-07-03' # fabric_layout_key = '2D-02-06a' concrete_mixture_key = 'PZ-0708-1' # concrete_mixture_key = 'FIL-10-09' # orientation_fn_key = 'all0' orientation_fn_key = '90_0' n_layers = 10 s_tex_z = 0.030 / (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 #-------------------------------------------------------------------------------- # put this into the ironing procedure processor # jump_rtol = Float(1, auto_set = False, enter_set = True, ironing_param = True) data_array_ironed = Property(Array(float), depends_on = 'data_array, +ironing_param, +axis_selection') @cached_property def _get_data_array_ironed(self): '''remove the jumps in the displacement curves due to resetting the displacement gauges. ''' print '*** curve ironing activated ***' # each column from the data array corresponds to a measured parameter # e.g. displacement at a given point as function of time u = f(t)) # data_array_ironed = copy(self.data_array) for idx in range(self.data_array.shape[1]): # use ironing method only for columns of the displacement gauges. # if self.names_and_units[0][ idx ] != 'Kraft' and \ self.names_and_units[0][ idx ] != 'Bezugskanal' and \ self.names_and_units[0][ idx ] != 'D_1o'and \ self.names_and_units[0][ idx ] != 'D_2o'and \ self.names_and_units[0][ idx ] != 'D_3o'and \ self.names_and_units[0][ idx ] != 'D_4o'and \ self.names_and_units[0][ idx ] != 'D_1u'and \ self.names_and_units[0][ idx ] != 'D_2u'and \ self.names_and_units[0][ idx ] != 'D_3u'and \ self.names_and_units[0][ idx ] != 'D_4u'and \ self.names_and_units[0][ idx ] != 'W30_vo'and \ self.names_and_units[0][ idx ] != 'W30_hi': # 1d-array corresponding to column in data_array data_arr = copy(data_array_ironed[:, idx]) # get the difference between each point and its successor jump_arr = data_arr[1:] - data_arr[0:-1] # get the range of the measured data data_arr_range = max(data_arr) - min(data_arr) # determine the relevant criteria for a jump # based on the data range and the specified tolerances: jump_crit = self.jump_rtol * data_arr_range # get the indexes in 'data_column' after which a # jump exceeds the defined tolerance criteria jump_idx = where(fabs(jump_arr) > jump_crit)[0] print 'number of jumps removed in data_arr_ironed for', self.names_and_units[0][ idx ], ': ', jump_idx.shape[0] # glue the curve at each jump together for jidx in jump_idx: # get the offsets at each jump of the curve shift = data_arr[jidx + 1] - data_arr[jidx] # shift all succeeding values by the calculated offset data_arr[jidx + 1:] -= shift data_array_ironed[:, idx] = data_arr[:] return data_array_ironed @on_trait_change('+ironing_param') def process_source_data(self): '''read in the measured data from file and assign attributes after array processing. NOTE: if center displacement gauge ('WA_M') is missing the measured displacement of the cylinder ('Weg') is used instead. A minor mistake is made depending on how much time passes before the cylinder has contact with the slab. ''' print '*** process source data ***' self._read_data_array() # curve ironing: # self.processed_data_array = self.data_array_ironed # set attributes: # self._set_array_attribs() #-------------------------------------------------------------------------------- # plot templates #-------------------------------------------------------------------------------- plot_templates = {'force / time' : '_plot_force_time', 'force / deflections center' : '_plot_force_deflection_center', 'force / smoothed deflections center' : '_plot_smoothed_force_deflection_center', 'force / deflections' : '_plot_force_deflections', 'force / eps_t' : '_plot_force_eps_t', 'force / eps_c' : '_plot_force_eps_c', 'force / w_elastomer' : '_plot_force_w_elastomer', 'time / deflections' : '_plot_time_deflections' } default_plot_template = 'force / time' def _plot_force_w_elastomer(self, axes): xkey = 'displacement [mm]' ykey = 'force [kN]' W_vl = self.W_vl W_vr = self.W_vr W_hl = self.W_hl W_hr = self.W_hr force = self.Kraft axes.set_xlabel('%s' % (xkey,)) axes.set_ylabel('%s' % (ykey,)) axes.plot(W_vl, force) axes.plot(W_vr, force) axes.plot(W_hl, force) axes.plot(W_hr, force) def _plot_force_time(self, axes): xkey = 'time [s]' ykey = 'force [kN]' xdata = self.Bezugskanal ydata = self.Kraft axes.set_xlabel('%s' % (xkey,)) axes.set_ylabel('%s' % (ykey,)) axes.plot(xdata, ydata # color = c, linewidth = w, linestyle = s ) def _plot_force_deflection_center(self, axes): xkey = 'deflection [mm]' ykey = 'force [kN]' xdata = -self.WD4 ydata = self.Kraft axes.set_xlabel('%s' % (xkey,)) axes.set_ylabel('%s' % (ykey,)) axes.plot(xdata, ydata # color = c, linewidth = w, linestyle = s ) n_fit_window_fraction = Float(0.1) def _plot_smoothed_force_deflection_center(self, axes): xkey = 'deflection [mm]' ykey = 'force [kN]' # get the index of the maximum stress max_force_idx = argmax(self.Kraft) # get only the ascending branch of the response curve f_asc = self.Kraft[:max_force_idx + 1] w_asc = -self.WD4[:max_force_idx + 1] f_max = f_asc[-1] w_max = w_asc[-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) 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.set_xlabel('%s' % (xkey,)) axes.set_ylabel('%s' % (ykey,)) def _plot_force_deflections(self, axes): xkey = 'displacement [mm]' ykey = 'force [kN]' # get the index of the maximum stress max_force_idx = argmax(self.Kraft) # get only the ascending branch of the response curve f_asc = self.Kraft[:max_force_idx + 1] WD1 = -self.WD1[:max_force_idx + 1] WD2 = -self.WD2[:max_force_idx + 1] WD3 = -self.WD3[:max_force_idx + 1] WD4 = -self.WD4[:max_force_idx + 1] WD5 = -self.WD5[:max_force_idx + 1] WD6 = -self.WD6[:max_force_idx + 1] WD7 = -self.WD7[:max_force_idx + 1] axes.plot(WD1, f_asc, color = 'blue', linewidth = 1 ) axes.plot(WD2, f_asc, color = 'green', linewidth = 1 ) axes.plot(WD3, f_asc, color = 'red', linewidth = 1 ) axes.plot(WD4, f_asc, color = 'black', linewidth = 3 ) axes.plot(WD5, f_asc, color = 'red', linewidth = 1 ) axes.plot(WD6, f_asc, color = 'green', linewidth = 1 ) axes.plot(WD7, f_asc, color = 'blue', linewidth = 1 ) axes.set_xlabel('%s' % (xkey,)) axes.set_ylabel('%s' % (ykey,)) def _plot_time_deflections(self, axes): xkey = 'time [s]' ykey = 'deflections [mm]' time = self.Bezugskanal WD1 = -self.WD1 WD2 = -self.WD2 WD3 = -self.WD3 WD4 = -self.WD4 WD5 = -self.WD5 WD6 = -self.WD6 WD7 = -self.WD7 axes.plot(time, WD1, color = 'blue', linewidth = 1 ) axes.plot(time, WD2, color = 'green', linewidth = 1 ) axes.plot(time, WD3, color = 'red', linewidth = 1 ) axes.plot(time, WD4, color = 'black', linewidth = 3 ) axes.plot(time, WD5, color = 'red', linewidth = 1 ) axes.plot(time, WD6, color = 'green', linewidth = 1 ) axes.plot(time, WD7, color = 'blue', linewidth = 1 ) axes.set_xlabel('%s' % (xkey,)) axes.set_ylabel('%s' % (ykey,)) def _plot_force_eps_c(self, axes): xkey = 'force [kN]' ykey = 'strain [mm/m]' # get the index of the maximum stress max_force_idx = argmax(self.Kraft) # get only the ascending branch of the response curve f_asc = self.Kraft[:max_force_idx + 1] D_1u = -self.D_1u[:max_force_idx + 1] D_2u = -self.D_2u[:max_force_idx + 1] D_3u = -self.D_3u[:max_force_idx + 1] D_4u = -self.D_4u[:max_force_idx + 1] D_1o = -self.D_1o[:max_force_idx + 1] D_2o = -self.D_2o[:max_force_idx + 1] D_3o = -self.D_3o[:max_force_idx + 1] D_4o = -self.D_4o[:max_force_idx + 1] axes.plot(f_asc, D_1u, color = 'blue', linewidth = 1 ) axes.plot(f_asc, D_2u, color = 'blue', linewidth = 1 ) axes.plot(f_asc, D_3u, color = 'blue', linewidth = 1 ) axes.plot(f_asc, D_4u, color = 'blue', linewidth = 1 ) axes.plot(f_asc, D_1o, color = 'red', linewidth = 1 ) axes.plot(f_asc, D_2o, color = 'red', linewidth = 1 ) axes.plot(f_asc, D_3o, color = 'red', linewidth = 1 ) axes.plot(f_asc, D_4o, color = 'red', linewidth = 1 ) axes.set_xlabel('%s' % (xkey,)) axes.set_ylabel('%s' % (ykey,)) def _plot_force_eps_t(self, axes): xkey = 'strain [mm/m]' ykey = 'force [kN]' # get the index of the maximum stress max_force_idx = argmax(self.Kraft) # get only the ascending branch of the response curve f_asc = self.Kraft[:max_force_idx + 1] eps_vo = -self.W30_vo[:max_force_idx + 1] / 300. eps_hi = -self.W30_hi[:max_force_idx + 1] / 300. axes.plot(eps_vo, f_asc, color = 'blue', linewidth = 1 ) axes.plot(eps_hi, f_asc, color = 'green', linewidth = 1 ) axes.set_xlabel('%s' % (xkey,)) axes.set_ylabel('%s' % (ykey,)) #-------------------------------------------------------------------------------- # view #-------------------------------------------------------------------------------- traits_view = View(VGroup( Group( Item('jump_rtol', format_str = "%.4f"), label = 'curve_ironing' ), Group( Item('thickness', format_str = "%.3f"), Item('edge_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 RFModelView(ModelView): ''' Size effect depending on the yarn length ''' model = Instance(IRF) title = Str('RF browser') def init(self, info): for name in self.model.param_keys: self.on_trait_change(self._redraw, 'model.' + name) def close(self, info, is_ok): for name in self.model.param_keys: self.on_trait_change(self._redraw, 'model.' + name, remove=True) return is_ok figure = Instance(Figure) def _figure_default(self): figure = Figure(facecolor='white') figure.add_axes([0.08, 0.13, 0.85, 0.74]) return figure data_changed = Event(True) eps_max = Float(0.1, enter_set=True, auto_set=False, config_change=True) n_eps = Int(20, enter_set=True, auto_set=False, config_change=True) x_name = Str('epsilon', enter_set=True, auto_set=False) y_name = Str('sigma', enter_set=True, auto_set=False) @on_trait_change('+config_change') def _redraw(self): figure = self.figure axes = self.figure.axes[0] in_arr = linspace(0.0, self.eps_max, self.n_eps) args = [in_arr] + self.model.param_values # get the number of parameters of the response function n_args = len(args) fn = frompyfunc(self.model.__call__, n_args, 1) out_arr = fn(*args) axes = self.figure.axes[0] axes.plot(in_arr, out_arr, linewidth=2) axes.set_xlabel(self.x_name) axes.set_ylabel(self.y_name) axes.legend(loc='best') self.data_changed = True show = Button def _show_fired(self): self._redraw() clear = Button def _clear_fired(self): axes = self.figure.axes[0] axes.clear() self.data_changed = True def default_traits_view(self): ''' Generates the view from the param items. ''' rf_param_items = [ Item('model.' + name, format_str='%g') for name in self.model.param_keys ] plot_param_items = [ Item('eps_max'), Item('n_eps'), Item('x_name', label='x-axis'), Item('y_name', label='y-axis') ] control_items = [ Item('show', show_label=False), Item('clear', show_label=False), ] view = View(HSplit( VGroup(*rf_param_items, label='Function Parameters', id='stats.spirrid_bak.rf_model_view.rf_params', scrollable=True), VGroup(*plot_param_items, label='Plot Parameters', id='stats.spirrid_bak.rf_model_view.plot_params'), VGroup( Item('model.comment', show_label=False, style='readonly'), label='Comment', id='stats.spirrid_bak.rf_model_view.comment', scrollable=True, ), VGroup(HGroup(*control_items), Item('figure', editor=MPLFigureEditor(), resizable=True, show_label=False), label='Plot', id='stats.spirrid_bak.rf_model_view.plot'), dock='tab', id='stats.spirrid_bak.rf_model_view.split'), kind='modal', resizable=True, dock='tab', buttons=['Ok', 'Cancel'], id='stats.spirrid_bak.rf_model_view') return view
class FunctionRandomization(HasStrictTraits): # response function q = Callable(input=True) #=========================================================================== # Inspection of the response function parameters #=========================================================================== var_spec = Property(depends_on='q') @cached_property def _get_var_spec(self): '''Get the names of the q_parameters''' if type(self.q) is types.FunctionType: arg_offset = 0 q = self.q else: arg_offset = 1 q = self.q.__call__ argspec = inspect.getargspec(q) args = np.array(argspec.args[arg_offset:]) dflt = np.array(argspec.defaults) return args, dflt var_names = Property(depends_on='q') @cached_property def _get_var_names(self): '''Get the array of default values. None - means no default has been specified ''' return self.var_spec[0] var_defaults = Property(depends_on='q') @cached_property def _get_var_defaults(self): '''Get the array of default values. None - means no default has been specified ''' dflt = self.var_spec[1] defaults = np.repeat(None, len(self.var_names)) start_idx = min(len(dflt), len(defaults)) defaults[-start_idx:] = dflt[-start_idx:] return defaults #=========================================================================== # Control variable specification #=========================================================================== evars = Dict(Str, Array, input_change=True) def __evars_default(self): return {'e': [0, 1]} evar_lst = Property() def _get_evar_lst(self): ''' sort entries according to var_names.''' return [self.evars[nm] for nm in self.evar_names] evar_names = Property(depends_on='evars') @cached_property def _get_evar_names(self): evar_keys = list(self.evars.keys()) return [nm for nm in self.var_names if nm in evar_keys] evar_str = Property() def _get_evar_str(self): s_list = [ '%s = [%g, ..., %g] (%d)' % (name, value[0], value[-1], len(value)) for name, value in zip(self.evar_names, self.evar_lst) ] return string.join(s_list, '\n') # convenience property to specify a single control variable without # the need to send a dictionary e_arr = Property def _set_e_arr(self, e_arr): '''Get the first free argument of var_names and set it to e vars ''' self.evars[self.var_names[0]] = e_arr #=========================================================================== # Specification of parameter value / distribution #=========================================================================== tvars = Dict(input_change=True) tvar_lst = Property(depends_on='tvars') @cached_property def _get_tvar_lst(self): '''sort entries according to var_names ''' return [self.tvars[nm] for nm in self.tvar_names] tvar_names = Property def _get_tvar_names(self): '''get the tvar names in the order given by the callable''' tvar_keys = list(self.tvars.keys()) return np.array([nm for nm in self.var_names if nm in tvar_keys], dtype=str) tvar_str = Property() def _get_tvar_str(self): s_list = [ '%s = %s' % (name, str(value)) for name, value in zip(self.tvar_names, self.tvar_lst) ] return string.join(s_list, '\n') # number of integration points n_int = Int(10, input_change=True)
class ExpST(ExType): '''Experiment: Slab Test ''' # label = Str('slab test') implements(IExType) #-------------------------------------------------------------------- # 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(1.25, unit='m', input=True, table_field=True, auto_set=False, enter_set=True) thickness = Float(0.06, unit='m', input=True, table_field=True, auto_set=False, enter_set=True) # age of the concrete at the time of testing age = Int(28, unit='d', input=True, table_field=True, auto_set=False, enter_set=True) loading_rate = Float(2.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 correspond to setup '7u_MAG-07-03_PZ-0708-1' ''' fabric_layout_key = '2D-05-11' # fabric_layout_key = 'MAG-07-03' # fabric_layout_key = '2D-02-06a' # concrete_mixture_key = 'PZ-0708-1' # concrete_mixture_key = 'FIL-10-09' # concrete_mixture_key = 'barrelshell' concrete_mixture_key = 'PZ-0708-1' # orientation_fn_key = 'all0' orientation_fn_key = '90_0' n_layers = 2 s_tex_z = 0.015 / (n_layers + 1) ccs = CompositeCrossSection ( fabric_layup_list=[ plain_concrete(0.035), # 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) plain_concrete(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 #-------------------------------------------------------------------------------- # put this into the ironing procedure processor # jump_rtol = Float(0.1, auto_set=False, enter_set=True, ironing_param=True) data_array_ironed = Property(Array(float), depends_on='data_array, +ironing_param, +axis_selection') @cached_property def _get_data_array_ironed(self): '''remove the jumps in the displacement curves due to resetting the displacement gauges. ''' print '*** curve ironing activated ***' # each column from the data array corresponds to a measured parameter # e.g. displacement at a given point as function of time u = f(t)) # data_array_ironed = copy(self.data_array) for idx in range(self.data_array.shape[1]): # use ironing method only for columns of the displacement gauges. # if self.names_and_units[0][ idx ] != 'Kraft' and \ self.names_and_units[0][ idx ] != 'Bezugskanal' and \ self.names_and_units[0][ idx ] != 'Weg': # 1d-array corresponding to column in data_array data_arr = copy(data_array_ironed[:, idx]) # get the difference between each point and its successor jump_arr = data_arr[1:] - data_arr[0:-1] # get the range of the measured data data_arr_range = max(data_arr) - min(data_arr) # determine the relevant criteria for a jump # based on the data range and the specified tolerances: jump_crit = self.jump_rtol * data_arr_range # get the indexes in 'data_column' after which a # jump exceeds the defined tolerance criteria jump_idx = where(fabs(jump_arr) > jump_crit)[0] print 'number of jumps removed in data_arr_ironed for', self.names_and_units[0][ idx ], ': ', jump_idx.shape[0] # glue the curve at each jump together for jidx in jump_idx: # get the offsets at each jump of the curve shift = data_arr[jidx + 1] - data_arr[jidx] # shift all succeeding values by the calculated offset data_arr[jidx + 1:] -= shift data_array_ironed[:, idx] = data_arr[:] return data_array_ironed @on_trait_change('+ironing_param') def process_source_data(self): '''read in the measured data from file and assign attributes after array processing. NOTE: if center displacement gauge ('WA_M') is missing the measured displacement of the cylinder ('Weg') is used instead. A minor mistake is made depending on how much time passes before the cylinder has contact with the slab. ''' print '*** process source data ***' self._read_data_array() # curve ironing: # self.processed_data_array = self.data_array_ironed # set attributes: # self._set_array_attribs() if 'WA_M' not in self.factor_list: print '*** NOTE: Displacement gauge at center ("WA_M") missing. Cylinder displacement ("Weg") is used instead! ***' self.WA_M = self.Weg #-------------------------------------------------------------------------------- # plot templates #-------------------------------------------------------------------------------- plot_templates = {'force / deflection (all)' : '_plot_force_deflection', # 'force / average deflection (c; ce; e) interpolated' : '_plot_force_deflection_avg_interpolated', # 'force / deflection (center)' : '_plot_force_center_deflection', # 'smoothed force / deflection (center)' : '_plot_force_center_deflection_smoothed', # 'force / deflection (edges)' : '_plot_force_edge_deflection', # 'force / deflection (center-edges)' : '_plot_force_center_edge_deflection', # 'force / average deflection (edges)' : '_plot_force_edge_deflection_avg', # 'force / average deflection (center-edges)' : '_plot_force_center_edge_deflection_avg', # 'force / average deflection (c; ce; e)' : '_plot_force_deflection_avg', # 'force / deflection (center) interpolated' : '_plot_force_center_deflection_interpolated', # 'force / deflection (corner)' : '_plot_force_corner_deflection', # 'edge_deflection_avg (front/back) / edge_deflection_avg (left/right)' : '_plot_edge_deflection_edge_deflection_avg', } default_plot_template = 'force / deflection (center)' n_fit_window_fraction = Float(0.1) # 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] w_asc = Property(Array) def _get_w_asc(self): '''get only the ascending branch of the response curve''' return -self.WA_M[:self.max_force_idx + 1] n_points = Property(Int) def _get_n_points(self): return int(self.n_fit_window_fraction * len(self.w_asc)) f_smooth = Property() def _get_f_smooth(self): return smooth(self.f_asc, self.n_points, 'flat') w_smooth = Property() def _get_w_smooth(self): return smooth(self.w_asc, self.n_points, 'flat') def _plot_force_deflection(self, axes, offset_w=0., color='blue', linewidth=1.5, linestyle='-'): '''plot the F-w-diagramm for all displacement gauges including maschine displacement ''' xkey = 'deflection [mm]' ykey = 'force [kN]' max_force_idx = self.max_force_idx # max_force_idx = -2 f_asc = -self.Kraft[:max_force_idx + 1] print 'self.factor_list', self.factor_list header_string = '' for i in self.factor_list[2:]: header_string = header_string + i + '; ' T_arr = -getattr(self, i) T_asc = T_arr[:max_force_idx + 1] axes.plot(T_asc, f_asc, label=i) axes.legend() img_dir = os.path.join(simdb.exdata_dir, 'img_dir') # check if directory exist otherwise create # if os.path.isdir(img_dir) == False: os.makedirs(img_dir) test_series_dir = os.path.join(img_dir, 'slab_test_astark') # check if directory exist otherwise create # if os.path.isdir(test_series_dir) == False: os.makedirs(test_series_dir) out_file = os.path.join(test_series_dir, self.key) np.savetxt(out_file, self.processed_data_array, delimiter=';') # workaround for old numpy.savetxt version: f = open(out_file, 'r') temp = f.read() f.close() f = open(out_file, 'w') f.write(header_string) f.write(temp) f.close() def _plot_force_center_deflection(self, axes, offset_w=0., color='blue', linewidth=1.5, linestyle='-'): '''plot the F-w-diagramm for the center (c) deflection ''' xkey = 'deflection [mm]' ykey = 'force [kN]' xdata = -self.WA_M ydata = -self.Kraft xdata += offset_w # axes.set_xlabel('%s' % (xkey,)) # axes.set_ylabel('%s' % (ykey,)) axes.plot(xdata, ydata, color=color, linewidth=linewidth, linestyle=linestyle) def _plot_force_corner_deflection(self, axes): '''plot the F-w-diagramm for the corner deflection (at the center of one of the supports) ''' xkey = 'deflection [mm]' ykey = 'force [kN]' xdata = -self.WA_Eck ydata = -self.Kraft # axes.set_xlabel('%s' % (xkey,)) # axes.set_ylabel('%s' % (ykey,)) axes.plot(xdata, ydata # color = c, linewidth = w, linestyle = s ) def _plot_force_center_deflection_smoothed(self, axes): '''plot the F-w-diagramm for the center (c) deflection (smoothed curves) ''' axes.plot(self.w_smooth, self.f_smooth, color='blue', linewidth=1) # 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_force_center_deflection_interpolated(self, axes, linestyle='-', linewidth=1.5, plot_elastic_stiffness=True): '''plot the F-w-diagramm for the center (c) deflection (interpolated initial stiffness) ''' # get the index of the maximum stress max_force_idx = argmax(-self.Kraft) # get only the ascending branch of the response curve f_asc = -self.Kraft[:max_force_idx + 1] w_m = -self.WA_M[:max_force_idx + 1] # w_m -= 0.17 # axes.plot(w_m, f_asc, color = 'blue', linewidth = 1) # move the starting point of the center deflection curve to the point where the force starts # (remove offset in measured displacement where there is still no force measured) # idx_0 = np.where(f_asc > 0.0)[0][0] f_asc_cut = np.hstack([f_asc[ idx_0: ]]) w_m_cut = np.hstack([w_m[ idx_0: ]]) - w_m[ idx_0 ] # print 'f_asc_cut.shape', f_asc_cut.shape # fw_arr = np.hstack([f_asc_cut[:, None], w_m_cut[:, None]]) # print 'fw_arr.shape', fw_arr.shape # np.savetxt('ST-6c-2cm-TU_bs2_f-w_asc.csv', fw_arr, delimiter=';') axes.plot(w_m_cut, f_asc_cut, color='k', linewidth=linewidth, linestyle=linestyle) # composite E-modulus # E_c = self.E_c print 'E_c', E_c if self.thickness == 0.02 and self.edge_length == 0.80 and plot_elastic_stiffness == True: K_linear = E_c / 24900. * 1.056 # [MN/m]=[kN/mm] bending stiffness with respect to center force max_f = f_asc_cut[-1] w_linear = np.array([0., max_f / K_linear]) f_linear = np.array([0., max_f]) axes.plot(w_linear, f_linear, linewidth=linewidth, linestyle='--', color='k') if self.thickness == 0.03 and self.edge_length == 1.25 and plot_elastic_stiffness == True: K_linear = E_c / 24900. * 1.267 # [MN/m]=[kN/mm] bending stiffness with respect to center force max_f = f_asc_cut[-1] w_linear = np.array([0., max_f / K_linear]) f_linear = np.array([0., max_f]) axes.plot(w_linear, f_linear, linewidth=linewidth, linestyle='--', color='k') if self.thickness == 0.06 and self.edge_length == 1.25 and plot_elastic_stiffness == True: K_linear = E_c / 24900. * 10.14 # [MN/m]=[kN/mm] bending stiffness with respect to center force max_f = f_asc_cut[-1] w_linear = np.array([0., max_f / K_linear]) f_linear = np.array([0., max_f]) axes.plot(w_linear, f_linear, linewidth=linewidth, linestyle='--', color='k') def _plot_force_edge_deflection(self, axes): '''plot the F-w-diagramm for the edge (e) deflections ''' max_force_idx = self.max_force_idx f_asc = self.f_asc w_v_asc = -self.WA_V[:max_force_idx + 1] w_h_asc = -self.WA_H[:max_force_idx + 1] w_l_asc = -self.WA_L[:max_force_idx + 1] w_r_asc = -self.WA_R[:max_force_idx + 1] axes.plot(w_v_asc, f_asc, color='blue', linewidth=1) axes.plot(w_h_asc, f_asc, color='blue', linewidth=1) axes.plot(w_l_asc, f_asc, color='green', linewidth=1) axes.plot(w_r_asc, f_asc, color='green', linewidth=1) def _plot_force_edge_deflection_avg(self, axes): '''plot the average F-w-diagramm for the edge (e) deflections ''' max_force_idx = self.max_force_idx f_asc = self.f_asc w_v_asc = -self.WA_V[:max_force_idx + 1] w_h_asc = -self.WA_H[:max_force_idx + 1] w_l_asc = -self.WA_L[:max_force_idx + 1] w_r_asc = -self.WA_R[:max_force_idx + 1] # get the average displacement values of the corresponding displacement gauges w_vh_asc = (w_v_asc + w_h_asc) / 2 w_lr_asc = (w_l_asc + w_r_asc) / 2 axes.plot(w_vh_asc, f_asc, color='blue', linewidth=1, label='w_vh') axes.plot(w_lr_asc, f_asc, color='blue', linewidth=1, label='w_lr') axes.legend() def _plot_edge_deflection_edge_deflection_avg(self, axes): '''plot the average edge (e) deflections for the front/back and left/right ''' max_force_idx = self.max_force_idx w_v_asc = -self.WA_V[:max_force_idx + 1] w_h_asc = -self.WA_H[:max_force_idx + 1] w_l_asc = -self.WA_L[:max_force_idx + 1] w_r_asc = -self.WA_R[:max_force_idx + 1] # get the average displacement values of the corresponding displacement gauges w_vh_asc = (w_v_asc + w_h_asc) / 2 w_lr_asc = (w_l_asc + w_r_asc) / 2 axes.plot(w_vh_asc, w_lr_asc, color='blue', linewidth=1, label='w_vh / w_lr') axes.plot(np.array([0, w_vh_asc[-1]]), np.array([0, w_vh_asc[-1]]), color='k', linewidth=1, linestyle='-') axes.legend() def _plot_force_center_edge_deflection(self, axes): '''plot the F-w-diagramm for the center-edge (ce) deflections ''' max_force_idx = argmax(-self.Kraft) # get only the ascending branch of the response curve f_asc = -self.Kraft[:max_force_idx + 1] w_ml_asc = -self.WA_ML[:max_force_idx + 1] w_mr_asc = -self.WA_MR[:max_force_idx + 1] axes.plot(w_ml_asc, f_asc, color='blue', linewidth=1, label='w_ml') axes.plot(w_mr_asc, f_asc, color='blue', linewidth=1, label='w_mr') axes.legend() def _plot_force_center_edge_deflection_avg(self, axes): '''plot the average F-w-diagramm for the center-edge (ce) deflections ''' # get the index of the maximum stress max_force_idx = argmax(-self.Kraft) # get only the ascending branch of the response curve f_asc = -self.Kraft[:max_force_idx + 1] w_ml_asc = -self.WA_ML[:max_force_idx + 1] w_mr_asc = -self.WA_MR[:max_force_idx + 1] # get the average displacement values of the corresponding displacement gauges w_mlmr_asc = (w_ml_asc + w_mr_asc) / 2 axes.plot(w_mlmr_asc, f_asc, color='blue', linewidth=1) def _plot_force_deflection_avg(self, axes): '''plot the average F-w-diagramms for the center(c), center-edge (ce) and edge(vh) and edge (lr) deflections ''' # get the index of the maximum stress max_force_idx = argmax(-self.Kraft) # get only the ascending branch of the response curve f_asc = -self.Kraft[:max_force_idx + 1] w_m = -self.WA_M[:max_force_idx + 1] axes.plot(w_m, f_asc, color='blue', linewidth=1) # ## center-edge deflection (ce) w_ml_asc = -self.WA_ML[:max_force_idx + 1] w_mr_asc = -self.WA_MR[:max_force_idx + 1] # get the average displacement values of the corresponding displacement gauges w_mlmr_asc = (w_ml_asc + w_mr_asc) / 2 axes.plot(w_mlmr_asc, f_asc, color='red', linewidth=1) # ## edge deflections (e) w_v_asc = -self.WA_V[:max_force_idx + 1] w_h_asc = -self.WA_H[:max_force_idx + 1] w_l_asc = -self.WA_L[:max_force_idx + 1] w_r_asc = -self.WA_R[:max_force_idx + 1] # get the average displacement values of the corresponding displacement gauges w_vh_asc = (w_v_asc + w_h_asc) / 2 w_lr_asc = (w_l_asc + w_r_asc) / 2 axes.plot(w_vh_asc, f_asc, color='green', linewidth=1, label='w_vh') axes.plot(w_lr_asc, f_asc, color='blue', linewidth=1, label='w_lr') # # set axis-labels # xkey = 'deflection [mm]' # ykey = 'force [kN]' # axes.set_xlabel('%s' % (xkey,)) # axes.set_ylabel('%s' % (ykey,)) def _plot_force_deflection_avg_interpolated(self, axes, linewidth=1): '''plot the average F-w-diagrams for the center(c), center-edge (ce) and edge(vh) and edge (lr) deflections NOTE: center deflection curve is cut at its starting point in order to remove offset in the dispacement meassurement ''' # get the index of the maximum stress max_force_idx = argmax(-self.Kraft) # get only the ascending branch of the response curve f_asc = -self.Kraft[:max_force_idx + 1] w_m = -self.WA_M[:max_force_idx + 1] # w_m -= 0.17 # axes.plot(w_m, f_asc, color = 'blue', linewidth = 1) # move the starting point of the center deflection curve to the point where the force starts # (remove offset in measured displacement where there is still no force measured) # idx_0 = np.where(f_asc > 0.05)[0][0] f_asc_cut = f_asc[ idx_0: ] w_m_cut = w_m[ idx_0: ] - w_m[ idx_0 ] axes.plot(w_m_cut, f_asc_cut, color='k', linewidth=linewidth) # plot machine displacement (hydraulic cylinder) # # Weg_asc = -self.Weg[ :max_force_idx + 1 ] # axes.plot(Weg_asc, f_asc, color='k', linewidth=1.5) # ## center-edge deflection (ce) w_ml_asc = -self.WA_ML[:max_force_idx + 1] w_mr_asc = -self.WA_MR[:max_force_idx + 1] # get the average displacement values of the corresponding displacement gauges w_mlmr_asc = (w_ml_asc + w_mr_asc) / 2 # axes.plot(w_mlmr_asc, f_asc, color='red', linewidth=1) axes.plot(w_ml_asc, f_asc, color='k', linewidth=linewidth) axes.plot(w_mr_asc, f_asc, color='k', linewidth=linewidth) # ## edge deflections (e) w_v_asc = -self.WA_V[:max_force_idx + 1] w_h_asc = -self.WA_H[:max_force_idx + 1] w_l_asc = -self.WA_L[:max_force_idx + 1] w_r_asc = -self.WA_R[:max_force_idx + 1] axes.plot(w_v_asc, f_asc, color='grey', linewidth=linewidth) axes.plot(w_h_asc, f_asc, color='grey', linewidth=linewidth) axes.plot(w_l_asc, f_asc, color='k', linewidth=linewidth) axes.plot(w_r_asc, f_asc, color='k', linewidth=linewidth) # get the average displacement values of the corresponding displacement gauges # w_vh_asc = (w_v_asc + w_h_asc) / 2 # w_lr_asc = (w_l_asc + w_r_asc) / 2 # axes.plot(w_vh_asc, f_asc, color='green', linewidth=1, label='w_vh') # axes.plot(w_lr_asc, f_asc, color='blue', linewidth=1, label='w_lr') # save 'F-w-arr_m-mlmr-vh-lr' in directory "/simdb/simdata/exp_st" # simdata_dir = os.path.join(simdb.simdata_dir, 'exp_st') # if os.path.isdir(simdata_dir) == False: # os.makedirs(simdata_dir) # filename = os.path.join(simdata_dir, 'F-w-arr_m-mlmr-vh-lr_' + self.key + '.csv') # Fw_m_mlmr_vh_lr_arr = np.hstack([f_asc[:, None], w_m[:, None] - w_m[ idx_0 ], w_mlmr_asc[:, None], w_vh_asc[:, None], w_lr_asc[:, None]]) # print 'Fw_m_mlmr_vh_lr_arr' # np.savetxt(filename, Fw_m_mlmr_vh_lr_arr, delimiter=';') # print 'F-w-curves for center, middle, edges saved to file %s' % (filename) #-------------------------------------------------------------------------------- # view #-------------------------------------------------------------------------------- traits_view = View(VGroup( Group( Item('jump_rtol', format_str="%.4f"), label='curve_ironing' ), Group( Item('thickness', format_str="%.3f"), Item('edge_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 SCM(HasTraits): '''Stochastic Cracking Model - compares matrix strength and stress, inserts new CS instances at positions, where the matrix strength is lower than the stress; evaluates stress-strain diagram by integrating the strain profile along the composite''' length = Float(desc='composite specimen length') nx = Int(desc='# of discretization points for the whole specimen') CB_model = Instance(CompositeCrackBridge) load_sigma_c_arr = Array n_w_CB = Int(100, desc='# of discretization points for w') n_BC_CB = Int(15, desc='# of discretization points for boundary conditions') representative_cb = Instance(RepresentativeCB) def _representative_cb_default(self): return RepresentativeCB(CB_model=self.CB_model, load_sigma_c_arr=self.load_sigma_c_arr, length=self.length, n_w=self.n_w_CB, n_BC=self.n_BC_CB) # list of composite stress at which cracks occur cracking_stress_lst = List # list of cracks positions crack_positions_lst = List x_arr = Property(Array, depends_on='length, nx') @cached_property def _get_x_arr(self): # discretizes the specimen length return np.linspace(0., self.length, self.nx) random_field = Instance(RandomField) matrix_strength = Property(depends_on='random_field.+modified') @cached_property def _get_matrix_strength(self): # evaluates a random field # realization and creates a spline reprezentation rf = self.random_field.random_field rf_spline = MFnLineArray(xdata=self.random_field.xgrid, ydata=rf) return rf_spline.get_values(self.x_arr) def get_cbs_lst(self, positions, cracking_stresses): # sorts the CBs by position and adjusts the boundary conditions # sort the CBs positions = np.array(positions) cracking_stresses = np.array(cracking_stresses) argsort = np.argsort(positions) sorted_positions = positions[argsort] sorted_cracking_stresses = cracking_stresses[argsort] cb_lst = [] for i, position_i in enumerate(list(sorted_positions)): cb_i = CB(position=position_i, representative_cb=self.representative_cb, crack_load_sigma_c=sorted_cracking_stresses[i]) # specify the boundaries if i == 0: # the leftmost crack cb_i.Ll = cb_i.position else: # there is a crack at the left hand side cb_i.Ll = (cb_i.position - cb_lst[-1].position) / 2. cb_lst[-1].Lr = cb_i.Ll if i == len(positions) - 1: # the rightmost crack cb_i.Lr = self.length - cb_i.position cb_lst.append(cb_i) for cb_i in cb_lst: # specify the x range for cracks mask_right = self.x_arr >= (cb_i.position - cb_i.Ll) mask_left = self.x_arr <= (cb_i.position + cb_i.Lr) cb_i.x = self.x_arr[mask_left * mask_right] - cb_i.position return cb_lst def get_current_cracking_state(self, load): '''Creates the list of CB objects that have been formed up to the current load ''' idx_load_level = np.sum(np.array(self.cracking_stress_lst) <= load) cb_lst = self.get_cbs_lst(self.crack_positions_lst[:idx_load_level], self.cracking_stress_lst[:idx_load_level]) return cb_lst def get_current_strnegth(self, load): if len(self.crack_positions_lst) is not 0: cb_lst = self.get_current_cracking_state(load) strengths = np.array([cb_i.max_sigma_c for cb_i in cb_lst]) return np.min(strengths) else: return np.inf def sigma_m(self, load): Em = self.CB_model.E_m Ec = self.CB_model.E_c sigma_m = load * Em / Ec * np.ones(len(self.x_arr)) if len(self.crack_positions_lst) != 0: cb_lst = self.get_current_cracking_state(load) for cb_i in cb_lst: crack_position_idx = np.argwhere(self.x_arr == cb_i.position) idx_l = crack_position_idx - len(np.nonzero(cb_i.x < 0.)[0]) idx_r = crack_position_idx + len( np.nonzero(cb_i.x > 0.)[0]) + 1 sigma_m[idx_l:idx_r] = cb_i.get_epsm_x(float(load)) * Em return sigma_m def sigma_m_given_crack_lst(self, load): Em = self.CB_model.E_m Ec = self.CB_model.E_c sigma_m = load * Em / Ec * np.ones(len(self.x_arr)) if len(self.crack_positions_lst) != 0: cb_lst = self.get_cbs_lst(self.crack_positions_lst, self.cracking_stress_lst) for cb_i in cb_lst: crack_position_idx = np.argwhere(self.x_arr == cb_i.position) idx_l = crack_position_idx - len(np.nonzero(cb_i.x < 0.)[0]) idx_r = crack_position_idx + len( np.nonzero(cb_i.x > 0.)[0]) + 1 sigma_m[idx_l:idx_r] = cb_i.get_epsm_x(float(load)) * Em return sigma_m def residuum(self, q): '''Callback method for the identification of the next emerging crack calculated as the difference between the current matrix stress and strength. See the scipy newton call below. ''' residuum = np.min(self.matrix_strength - self.sigma_m_given_crack_lst(q)) return residuum def evaluate(self): # seek for the minimum strength redundancy to find the position # of the next crack last_pos = pi sigc_min = 0.0 while True: try: s = t.clock() sigc_min = newton(self.residuum, sigc_min) try: sigc_min = brentq(self.residuum, 0.0, sigc_min - 1e-10) print 'another root found!!!' except: pass print 'evaluation of the matrix crack #' + str( len(self.cracking_stress_lst) + 1), t.clock() - s, 's' except: print 'composite saturated' break print 'current strength = ', self.get_current_strnegth(sigc_min) crack_position = self.x_arr[np.argmin(self.matrix_strength - self.sigma_m(sigc_min))] self.crack_positions_lst.append(crack_position) self.cracking_stress_lst.append(sigc_min - 1e-10) plt.plot(self.x_arr, self.sigma_m(sigc_min) / self.CB_model.E_m, color='blue', lw=2) plt.plot(self.x_arr, self.matrix_strength / self.CB_model.E_m, color='black', lw=2) plt.show() if float(crack_position) == last_pos: print last_pos raise ValueError('''got stuck in loop, try to adapt x, w, BC ranges''') last_pos = float(crack_position)
class CodeGenCompiled(CodeGen): ''' C-code is generated using the inline feature of scipy. ''' # =========================================================================== # Inspection of the randomization - needed by CodeGenCompiled # =========================================================================== evar_names = Property(depends_on='q, recalc') @cached_property def _get_evar_names(self): return self.spirrid.evar_names var_names = Property(depends_on='q, recalc') @cached_property def _get_var_names(self): return self.spirrid.tvar_names # count the random variables n_rand_vars = Property(depends_on='theta_vars, recalc') @cached_property def _get_n_rand_vars(self): return self.spirrid.n_rand_vars # get the indexes of the random variables within the parameter list rand_var_idx_list = Property(depends_on='theta_vars, recalc') @cached_property def _get_rand_var_idx_list(self): return self.spirrid.rand_var_idx_list # get the names of the random variables rand_var_names = Property(depends_on='theta_vars, recalc') @cached_property def _get_rand_var_names(self): return self.var_names[self.rand_var_idx_list] # get the randomization arrays theta_arrs = Property(List, depends_on='theta_vars, recalc') @cached_property def _get_theta_arrs(self): '''Get flattened list of theta arrays. ''' theta = self.spirrid.sampling.theta return _get_flat_arrays_from_list(self.rand_var_idx_list, theta) # get the randomization arrays dG_arrs = Property(List, depends_on='theta_vars, recalc') @cached_property def _get_dG_arrs(self): '''Get flattened list of weight factor arrays. ''' dG = self.spirrid.sampling.dG_ogrid return _get_flat_arrays_from_list(self.rand_var_idx_list, dG) arg_names = Property( depends_on='rf_change, rand_change, +codegen_option, recalc') @cached_property def _get_arg_names(self): arg_names = [] # create argument string for inline function if self.compiled_eps_loop: # @todo: e_arr must be evar_names arg_names += ['mu_q_arr', 'e_arr'] else: arg_names.append('e') arg_names += ['%s_flat' % name for name in self.rand_var_names] arg_names += self._get_arg_names_dG() return arg_names ld = Trait('weave', dict(weave=CodeGenLangDictC(), cython=CodeGenLangDictCython())) # =========================================================================== # Configuration of the code # =========================================================================== # # compiled_eps_loop: # If set True, the loop over the control variable epsilon is compiled # otherwise, python loop is used. compiled_eps_loop = Bool(True, codegen_option=True) # =========================================================================== # compiled_eps_loop - dependent code # =========================================================================== compiled_eps_loop_feature = Property( depends_on='compiled_eps_loop, recalc') @cached_property def _get_compiled_eps_loop_feature(self): if self.compiled_eps_loop == True: return self.ld_.LD_BEGIN_EPS_LOOP_ACTIVE, self.ld_.LD_END_EPS_LOOP_ACTIVE else: return self.ld_.LD_ASSIGN_EPS, '' LD_BEGIN_EPS_LOOP = Property def _get_LD_BEGIN_EPS_LOOP(self): return self.compiled_eps_loop_feature[0] LD_END_EPS_LOOP = Property def _get_LD_END_EPS_LOOP(self): return self.compiled_eps_loop_feature[1] # # cached_dG: # 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(False, codegen_option=True) # =========================================================================== # cached_dG - dependent code # =========================================================================== cached_dG_feature = Property(depends_on='cached_dG, recalc') @cached_property def _get_cached_dG_feature(self): if self.compiled_eps_loop: if self.cached_dG == True: return self.ld_.LD_ACCESS_EPS_IDX, self.ld_.LD_ACCESS_THETA_IDX, self.ld_.LD_ASSIGN_MU_Q_IDX else: return self.ld_.LD_ACCESS_EPS_PTR, self.ld_.LD_ACCESS_THETA_PTR, self.ld_.LD_ASSIGN_MU_Q_PTR else: if self.cached_dG == True: return self.ld_.LD_ACCESS_EPS_IDX, self.ld_.LD_ACCESS_THETA_IDX, self.ld_.LD_ASSIGN_MU_Q_IDX else: return self.ld_.LD_ACCESS_EPS_PTR, self.ld_.LD_ACCESS_THETA_PTR, self.ld_.LD_ASSIGN_MU_Q_PTR LD_ACCESS_EPS = Property def _get_LD_ACCESS_EPS(self): return self.cached_dG_feature[0] LD_ACCESS_THETA = Property def _get_LD_ACCESS_THETA(self): return '%s' + self.cached_dG_feature[1] LD_ASSIGN_MU_Q = Property def _get_LD_ASSIGN_MU_Q(self): return self.cached_dG_feature[2] LD_N_TAB = Property def _get_LD_N_TAB(self): if self.spirrid.sampling_type == 'LHS' or self.spirrid.sampling_type == 'MCS': if self.compiled_eps_loop: return 3 else: return 2 else: if self.compiled_eps_loop: return self.n_rand_vars + 2 else: return self.n_rand_vars + 1 # ------------------------------------------------------------------------------------ # Configurable generation of C-code for the mean curve evaluation # ------------------------------------------------------------------------------------ code = Property( depends_on='rf_change, rand_change, +codegen_option, eps_change, recalc' ) @cached_property def _get_code(self): code_str = '' if self.compiled_eps_loop: # create code string for inline function # n_eps = len(self.spirrid.evar_lst[0]) code_str += self.LD_BEGIN_EPS_LOOP % {'i': n_eps} code_str += self.LD_ACCESS_EPS else: # create code string for inline function # code_str += self.ld_.LD_ASSIGN_EPS code_str += self.ld_.LD_INIT_MU_Q if self.compiled_eps_loop: code_str += '\t' + self.ld_.LD_INIT_Q else: code_str += self.ld_.LD_INIT_Q code_str += self.ld_.LD_LINE_MACRO # create code for constant params for name, distr in zip(self.var_names, self.spirrid.tvar_lst): if type(distr) is float: code_str += self.ld_.LD_INIT_THETA % (name, distr) code_str += self._get_code_dG_declare() inner_code_str = '' lang = self.ld + '_code' q_code = getattr(self.spirrid.q, lang) import textwrap q_code = textwrap.dedent(q_code) q_code_split = q_code.split('\n') for i, s in enumerate(q_code_split): q_code_split[i] = self.LD_N_TAB * '\t' + s q_code = '\n'.join(q_code_split) if self.n_rand_vars > 0: inner_code_str += self._get_code_dG_access() inner_code_str += q_code + '\n' + \ (self.LD_N_TAB) * '\t' + self.ld_.LD_EVAL_MU_Q else: inner_code_str += q_code + \ self.ld_.LD_ADD_MU_Q code_str += self._get_code_inner_loops(inner_code_str) if self.compiled_eps_loop: if self.cached_dG: # blitz matrix code_str += self.ld_.LD_ASSIGN_MU_Q_IDX else: code_str += self.ld_.LD_ASSIGN_MU_Q_PTR code_str += self.LD_END_EPS_LOOP else: code_str += self.ld_.LD_RETURN_MU_Q return code_str compiler_verbose = Int(1) compiler = Property(Str) def _get_compiler(self): if platform.system() == 'Linux': return 'gcc' elif platform.system() == 'Windows': return 'mingw32' def get_code(self): if self.ld == 'weave': return self.get_c_code() elif self.ld == 'cython': return self.get_cython_code() def get_cython_code(self): cython_header = 'print "## spirrid_cython library reloaded!"\nimport numpy as np\ncimport numpy as np\nctypedef np.double_t DTYPE_t\ncimport cython\n\[email protected](False)\[email protected](False)\[email protected](True)\ndef mu_q(%s):\n\tcdef double mu_q\n' # @todo - for Cython cdef variables and generalize function def() arg_values = {} for name, theta_arr in zip(self.rand_var_names, self.theta_arrs): arg_values['%s_flat' % name] = theta_arr arg_values.update(self._get_arg_values_dG()) DECLARE_ARRAY = 'np.ndarray[DTYPE_t, ndim=1] ' def_dec = DECLARE_ARRAY + 'e_arr' def_dec += ',' + DECLARE_ARRAY def_dec += (',' + DECLARE_ARRAY).join(arg_values) cython_header = cython_header % def_dec cython_header += ' cdef double ' cython_header += ', '.join(self.var_names) + ', eps, dG, q\n' cython_header += ' cdef int i_' cython_header += ', i_'.join(self.var_names) + '\n' if self.cached_dG: cython_header = cython_header.replace( r'1] dG_grid', r'%i] dG_grid' % self.n_rand_vars) if self.compiled_eps_loop == False: cython_header = cython_header.replace( r'np.ndarray[DTYPE_t, ndim=1] e_arr', r'double e_arr') cython_header = cython_header.replace(r'eps,', r'eps = e_arr,') cython_code = (cython_header + self.code).replace('\t', ' ') cython_file_name = 'spirrid_cython.pyx' print 'checking for previous cython code' regenerate_code = True if os.path.exists(cython_file_name): f_in = open(cython_file_name, 'r').read() if f_in == cython_code: regenerate_code = False if regenerate_code: infile = open(cython_file_name, 'w') infile.write(cython_code) infile.close() print 'pyx file updated' t = sysclock() import pyximport pyximport.install(reload_support=True, setup_args={"script_args": ["--force"]}) import spirrid_cython if regenerate_code: reload(spirrid_cython) print '>>> pyximport', sysclock() - t mu_q = spirrid_cython.mu_q def mu_q_method(eps): if self.compiled_eps_loop: args = {'e_arr': eps} args.update(arg_values) mu_q_arr = mu_q(**args) else: # Python loop over eps # mu_q_arr = np.zeros_like(eps, dtype=np.float64) for idx, e in enumerate(eps): # C loop over random dimensions # arg_values['e_arr'] = e # prepare the parameter mu_q_val = mu_q(**arg_values) # add the value to the return array mu_q_arr[idx] = mu_q_val return mu_q_arr, None return mu_q_method def get_c_code(self): ''' Return the code for the given sampling of the rand domain. ''' def mu_q_method(e): '''Template for the evaluation of the mean response. ''' self._set_compiler() compiler_args, linker_args = self.extra_args print 'compiler arguments' print compiler_args # prepare the array of the control variable discretization # eps_arr = e mu_q_arr = np.zeros_like(eps_arr) # prepare the parameters for the compiled function in # a separate dictionary arg_values = {} if self.compiled_eps_loop: # for compiled eps_loop the whole input and output array must be passed to c # arg_values['e_arr'] = eps_arr arg_values['mu_q_arr'] = mu_q_arr # prepare the lengths of the arrays to set the iteration bounds # for name, theta_arr in zip(self.rand_var_names, self.theta_arrs): arg_values['%s_flat' % name] = theta_arr arg_values.update(self._get_arg_values_dG()) if self.cached_dG: conv = weave.converters.blitz else: conv = weave.converters.default if self.compiled_eps_loop: # C loop over eps, all inner loops must be compiled as well # weave.inline(self.code, self.arg_names, local_dict=arg_values, extra_compile_args=compiler_args, extra_link_args=linker_args, type_converters=conv, compiler=self.compiler, verbose=self.compiler_verbose) else: # Python loop over eps # for idx, e in enumerate(eps_arr): # C loop over random dimensions # arg_values['e'] = e # prepare the parameter mu_q = weave.inline(self.code, self.arg_names, local_dict=arg_values, extra_compile_args=compiler_args, extra_link_args=linker_args, type_converters=conv, compiler=self.compiler, verbose=self.compiler_verbose) # add the value to the return array mu_q_arr[idx] = mu_q var_q_arr = np.zeros_like(mu_q_arr) return mu_q_arr, var_q_arr return mu_q_method # =========================================================================== # Extra compiler arguments # =========================================================================== use_extra = Bool(False, codegen_option=True) extra_args = Property(depends_on='use_extra, +codegen_option, recalc') @cached_property def _get_extra_args(self): if self.use_extra == True: compiler_args = [ "-DNDEBUG -g -fwrapv -O3 -march=native", "-ffast-math" ] # , "-fno-openmp", "-ftree-vectorizer-verbose=3"] linker_args = [] # ["-fno-openmp"] return compiler_args, linker_args elif self.use_extra == False: return [], [] # =========================================================================== # Auxiliary methods # =========================================================================== def _set_compiler(self): '''Catch eventual mismatch between scipy.weave and compiler ''' if platform.system() == 'Linux': # os.environ['CC'] = 'gcc-4.1' # os.environ['CXX'] = 'g++-4.1' os.environ['OPT'] = '-DNDEBUG -g -fwrapv -O3' elif platform.system() == 'Windows': # not implemented pass def _get_code_dG_declare(self): '''Constant dG value - for PGrid, MCS, LHS ''' return '' def _get_code_dG_access(self): '''Default access to dG array - only needed by TGrid''' return '' def _get_arg_names_dG(self): return [] def _get_arg_values_dG(self): return {} def __str__(self): s = 'C( ' s += 'var_eval = %s, ' % ` self.implicit_var_eval ` s += 'compiled_eps_loop = %s, ' % ` self.compiled_eps_loop ` s += 'cached_dG = %s)' % ` self.cached_dG ` return s
class GeoST(HasTraits): '''Geometry definition of the slab test with round load introduction area corresponding to steel plate in the test setup. ''' #----------------------------------------------------------------- # geometric parameters of the slab #----------------------------------------------------------------- # NOTE: coordinate system is placed where the symmetry planes cut each other, # i.e the center of the load introduction area (=middle of steel plate) # discretization of total slab in x- and y-direction (region 'L') # shape_xy = Int(14, input=True) # discretization of the load introduction plate (region 'R') # shape_R = Int(2, input=True) # ratio of the discretization, i.e. number of elements for each region # r_ = Property(depends_on='+input') @cached_property def _get_r_(self): return 1. * self.shape_R / self.shape_xy #----------------- # geometry: #----------------- # x and y-direction # length_quarter = Float(0.625, input=True) # Radius of load introduction plate # radius_plate = Float(0.10, input=True) # z-direction # thickness = Float(0.06, input=True) # specify offset (translation) for the plain concrete patch (if used) # in global coordinates # zoffset = Float(0.0, input=True) # # used regular discretization up to y = L1 # # (by default use regular discretization up to support) # # # L1 = Float(0.30, input = True) def __call__(self, pts): print '*** geo_slab_test called ***' x_, y_, z_ = pts.T R = self.radius_plate L = self.length_quarter t = self.thickness #------------------------------------------- # transformation to global coordinates #------------------------------------------- x = np.zeros_like(x_) y = np.zeros_like(y_) z = z_ * t r_ = self.r_ # 1. quadrant # bool_x = x_ >= r_ bool_y = y_ >= r_ bool_xy = bool_x * bool_y idx_xy = np.where(bool_xy == 1.)[0] x[idx_xy] = R + (x_[idx_xy] - r_) / (1 - r_) * (L - R) y[idx_xy] = R + (y_[idx_xy] - r_) / (1 - r_) * (L - R) # 2. quadrant # bool_x = x_ >= r_ bool_y = y_ <= r_ bool_xy = bool_x * bool_y idx_xy = np.where(bool_xy == 1.)[0] xR = R * np.cos(y_[idx_xy] / r_ * np.pi / 4.) x[idx_xy] = xR + (x_[idx_xy] - r_) / (1 - r_) * (L - xR) y[idx_xy] = y_[idx_xy] / r_ * R # 4. quadrant # bool_x = x_ <= r_ bool_y = y_ >= r_ bool_xy = bool_x * bool_y idx_xy = np.where(bool_xy == 1.)[0] x[idx_xy] = x_[idx_xy] / r_ * R yR = R * np.cos(x_[idx_xy] / r_ * np.pi / 4.) y[idx_xy] = yR + (y_[idx_xy] - r_) / (1 - r_) * (L - yR) # 3. quadrant (mesh in load introduction area) # bool_x = x_ <= r_ bool_y = y_ <= r_ bool_xy = bool_x * bool_y idx_xy = np.where(bool_xy == 1.)[0] xR = R * np.cos(y_[idx_xy] / r_ * np.pi / 4.) yR = R * np.cos(x_[idx_xy] / r_ * np.pi / 4.) x[idx_xy] = x_[idx_xy] / r_ * xR y[idx_xy] = y_[idx_xy] / r_ * yR # rotate coordinates in order to have the load introduction plate at the # top left corner of the grid # and add offset for translation # zoffset = self.zoffset pts = np.c_[L - x, L - y, z + zoffset] # pts = np.c_[x, y, z] # switch order of the points in order to start in the opposite corner of the slab # instead of the center of the load introduction plate. The opposite center of the # slab corresponds to the origin of the slab in the model 'sim_st' (as generated by # the FEGrid mesh; # pts = pts[::-1] # switch back the order of the z-axis in order to maintain starting from 0 # pts[:, -1] = pts[:, -1][::-1] # print pts return pts
class SimBT4PT(IBVModel): '''Simulation: four point bending test. ''' input_change = Event @on_trait_change('+input,ccs_unit_cell.input_change') def _set_input_change(self): self.input_change = True implements(ISimModel) #----------------- # discretization: #----------------- # specify weather the elastomer is to be modeled or if the load is # introduced as line load # elstmr_flag = Bool(True) # discretization in x-direction (longitudinal): # outer_zone_shape_x = Int(6, input=True, ps_levels=(4, 12, 3)) # discretization in x-direction (longitudinal): # load_zone_shape_x = Int(2, input=True, ps_levels=(1, 4, 1)) # middle part discretization in x-direction (longitudinal): # mid_zone_shape_x = Int(3, input=True, ps_levels=(1, 4, 1)) # discretization in y-direction (width): # shape_y = Int(2, input=True, ps_levels=(1, 4, 2)) # discretization in z-direction: # shape_z = Int(2, input=True, ps_levels=(1, 3, 3)) #----------------- # geometry: #----------------- # # edge length of the bending specimen (beam) (entire length without symmetry) # length = Float(1.50, input=True) elstmr_length = Float(0.05, input=True) mid_zone_length = Float(0.50, input=True) elstmr_thickness = Float(0.005, input=True) width = Float(0.20, input=True) thickness = Float(0.06, input=True) #----------------- # derived geometric parameters #----------------- # # half the length of the elastomer (load introduction # with included symmetry) # sym_specmn_length = Property def _get_sym_specmn_length(self): return self.length / 2. sym_mid_zone_specmn_length = Property def _get_sym_mid_zone_specmn_length(self): return self.mid_zone_length / 2. # half the length of the elastomer (load introduction # with included symmetry # sym_elstmr_length = Property def _get_sym_elstmr_length(self): return self.elstmr_length / 2. # half the specimen width # sym_width = Property def _get_sym_width(self): return self.width / 2. #---------------------------------------------------------------------------------- # mats_eval #---------------------------------------------------------------------------------- # age of the plate at the time of testing # NOTE: that the same phi-function is used independent of age. This assumes a # an afine/proportional damage evolution for different ages. # age = Int(28, input=True) # time stepping params # tstep = Float(0.05, auto_set=False, enter_set=True, input=True) tmax = Float(1.0, auto_set=False, enter_set=True, input=True) tolerance = Float(0.001, auto_set=False, enter_set=True, input=True) # specify type of 'linalg.norm' # default value 'None' sets norm to 2-norm, # i.e "norm = sqrt(sum(x_i**2)) # # set 'ord=np.inf' to switch norm to # "norm = max(abs(x_i))" # ord = Enum(np.inf, None) n_mp = Int(30, input=True) # @todo: for mats_eval the information of the unit cell should be used # in order to use the same number of microplanes and model version etc... # specmn_mats = Property(Instance(MATS2D5MicroplaneDamage), depends_on='input_change') @cached_property def _get_specmn_mats(self): return MATS2D5MicroplaneDamage( E=self.E_c, # E=self.E_m, nu=self.nu, # corresponding to settings in "MatsCalib" n_mp=self.n_mp, symmetrization='sum-type', model_version='compliance', phi_fn=self.phi_fn) if elstmr_flag: elstmr_mats = Property(Instance(MATS3DElastic), depends_on='input_change') @cached_property def _get_elstmr_mats(self): # specify a small elastomer stiffness (approximation) E_elast = self.E_c / 10. print 'effective elastomer E_modulus', E_elast return MATS3DElastic(E=E_elast, nu=0.4) #----------------- # fets: #----------------- # specify element shrink factor in plot of fe-model # vtk_r = Float(0.95) # use quadratic serendipity elements # specmn_fets = Property(Instance(FETSEval), depends_on='input_change') @cached_property def _get_specmn_fets(self): fets = FETS2D58H20U(mats_eval=self.specmn_mats) fets.vtk_r *= self.vtk_r return fets # use quadratic serendipity elements # elstmr_fets = Property(Instance(FETSEval), depends_on='input_change') @cached_property def _get_elstmr_fets(self): fets = FETS2D58H20U(mats_eval=self.elstmr_mats) fets.vtk_r *= self.vtk_r return fets fe_domain = Property(depends_on='+ps_levels, +input') @cached_property def _get_fe_domain(self): return FEDomain() #=========================================================================== # fe level #=========================================================================== outer_zone_specmn_fe_level = Property(depends_on='+ps_levels, +input') def _get_outer_zone_specmn_fe_level(self): return FERefinementGrid(name='outer zone specimen patch', fets_eval=self.specmn_fets, domain=self.fe_domain) load_zone_specmn_fe_level = Property(depends_on='+ps_levels, +input') def _get_load_zone_specmn_fe_level(self): return FERefinementGrid(name='load zone specimen patch', fets_eval=self.specmn_fets, domain=self.fe_domain) mid_zone_specmn_fe_level = Property(depends_on='+ps_levels, +input') def _get_mid_zone_specmn_fe_level(self): return FERefinementGrid(name='mid zone specimen patch', fets_eval=self.specmn_fets, domain=self.fe_domain) elstmr_fe_level = Property(depends_on='+ps_levels, +input') def _get_elstmr_fe_level(self): return FERefinementGrid(name='elastomer patch', fets_eval=self.elstmr_fets, domain=self.fe_domain) #=========================================================================== # Grid definition #=========================================================================== mid_zone_specmn_fe_grid = Property(Instance(FEGrid), depends_on='+ps_levels, +input') @cached_property def _get_mid_zone_specmn_fe_grid(self): # only a quarter of the beam is simulated due to symmetry: fe_grid = FEGrid(coord_min=(0., 0., 0.), coord_max=(self.sym_mid_zone_specmn_length - self.sym_elstmr_length, self.sym_width, self.thickness), shape=(self.mid_zone_shape_x, self.shape_y, self.shape_z), level=self.mid_zone_specmn_fe_level, fets_eval=self.specmn_fets) return fe_grid load_zone_specmn_fe_grid = Property(Instance(FEGrid), depends_on='+ps_levels, +input') @cached_property def _get_load_zone_specmn_fe_grid(self): # only a quarter of the beam is simulated due to symmetry: fe_grid = FEGrid(coord_min=(self.sym_mid_zone_specmn_length - self.sym_elstmr_length, 0., 0.), coord_max=(self.sym_mid_zone_specmn_length + self.sym_elstmr_length, self.sym_width, self.thickness), shape=(self.load_zone_shape_x, self.shape_y, self.shape_z), level=self.load_zone_specmn_fe_level, fets_eval=self.specmn_fets) return fe_grid # if elstmr_flag: elstmr_fe_grid = Property(Instance(FEGrid), depends_on='+ps_levels, +input') @cached_property def _get_elstmr_fe_grid(self): fe_grid = FEGrid(coord_min=(self.sym_mid_zone_specmn_length - self.sym_elstmr_length, 0., self.thickness), coord_max=(self.sym_mid_zone_specmn_length + self.sym_elstmr_length, self.sym_width, self.thickness + self.elstmr_thickness), level=self.elstmr_fe_level, shape=(self.load_zone_shape_x, self.shape_y, 1), fets_eval=self.elstmr_fets) return fe_grid outer_zone_specmn_fe_grid = Property(Instance(FEGrid), depends_on='+ps_levels, +input') @cached_property def _get_outer_zone_specmn_fe_grid(self): # only a quarter of the plate is simulated due to symmetry: fe_grid = FEGrid(coord_min=(self.sym_mid_zone_specmn_length + self.sym_elstmr_length, 0., 0.), coord_max=(self.sym_specmn_length, self.sym_width, self.thickness), shape=(self.outer_zone_shape_x, self.shape_y, self.shape_z), level=self.outer_zone_specmn_fe_level, fets_eval=self.specmn_fets) return fe_grid #=========================================================================== # Boundary conditions #=========================================================================== w_max = Float(-0.030, input=True) # [m] w_max = Float(-0.030, input=True) # [m] bc_list = Property(depends_on='+ps_levels, +input') @cached_property def _get_bc_list(self): mid_zone_specimen = self.mid_zone_specmn_fe_grid load_zone_specimen = self.load_zone_specmn_fe_grid outer_zone_specimen = self.outer_zone_specmn_fe_grid if self.elstmr_flag: elastomer = self.elstmr_fe_grid #-------------------------------------------------------------- # boundary conditions for the symmetry #-------------------------------------------------------------- # symmetry in the xz-plane # (Note: the x-axis corresponds to the axis of symmetry along the longitudinal axis of the beam) # bc_outer_zone_symplane_xz = BCSlice(var='u', value=0., dims=[1], slice=outer_zone_specimen[:, 0, :, :, 0, :]) bc_load_zone_symplane_xz = BCSlice(var='u', value=0., dims=[1], slice=load_zone_specimen[:, 0, :, :, 0, :]) bc_mid_zone_symplane_xz = BCSlice(var='u', value=0., dims=[1], slice=mid_zone_specimen[:, 0, :, :, 0, :]) if self.elstmr_flag: bc_el_symplane_xz = BCSlice(var='u', value=0., dims=[1], slice=elastomer[:, 0, :, :, 0, :]) # symmetry in the yz-plane # bc_mid_zone_symplane_yz = BCSlice(var='u', value=0., dims=[0], slice=mid_zone_specimen[0, :, :, 0, :, :]) #-------------------------------------------------------------- # boundary conditions for the support #-------------------------------------------------------------- bc_support_0y0 = BCSlice(var='u', value=0., dims=[2], slice=outer_zone_specimen[-1, :, 0, -1, :, 0]) #-------------------------------------------------------------- # connect all grids #-------------------------------------------------------------- link_loadzn_outerzn = BCDofGroup( var='u', value=0., dims=[0, 1, 2], get_dof_method=load_zone_specimen.get_right_dofs, get_link_dof_method=outer_zone_specimen.get_left_dofs, link_coeffs=[1.]) link_midzn_loadzn = BCDofGroup( var='u', value=0., dims=[0, 1, 2], get_dof_method=mid_zone_specimen.get_right_dofs, get_link_dof_method=load_zone_specimen.get_left_dofs, link_coeffs=[1.]) if self.elstmr_flag: link_elstmr_loadzn_z = BCDofGroup( var='u', value=0., dims=[2], get_dof_method=elastomer.get_back_dofs, get_link_dof_method=load_zone_specimen.get_front_dofs, link_coeffs=[1.]) # hold elastomer in a single point in order to avoid kinematic movement yielding singular K_mtx # bc_elstmr_fix = BCSlice(var='u', value=0., dims=[0], slice=elastomer[0, 0, 0, 0, 0, 0]) #-------------------------------------------------------------- # loading #-------------------------------------------------------------- # w_max = center displacement: w_max = self.w_max if self.elstmr_flag: # apply displacement at all top nodes of the elastomer (surface load) # bc_w = BCSlice(var='u', value=w_max, dims=[2], slice=elastomer[:, :, -1, :, :, -1]) else: bc_w = BCSlice( var='u', value=w_max, dims=[2], # slice is only exactly in the center of the loading zone for 'load_zone_shape_x' = 2 # center line of the load zone slice=load_zone_specimen[0, :, -1, -1, :, -1]) # f_max = 0.010 / 4. / self.sym_width # bc_line_f = BCSlice(var = 'f', value = f_max, dims = [2], # # slice is only valid for 'load_zone_shape_x' = 2 # # center line of the load zone # slice = load_zone_specimen[0, :, -1, -1, :, -1]) bc_list = [ bc_outer_zone_symplane_xz, bc_load_zone_symplane_xz, bc_mid_zone_symplane_xz, bc_mid_zone_symplane_yz, # link_midzn_loadzn, link_loadzn_outerzn, bc_support_0y0, # bc_w, ] if self.elstmr_flag: bc_list += [bc_el_symplane_xz, link_elstmr_loadzn_z, bc_elstmr_fix] return bc_list #---------------------- # tloop #---------------------- tloop = Property(depends_on='input_change') @cached_property def _get_tloop(self): #-------------------------------------------------------------- # ts #-------------------------------------------------------------- mid_zone_spec = self.mid_zone_specmn_fe_grid load_zone_spec = self.load_zone_specmn_fe_grid outer_zone_spec = self.outer_zone_specmn_fe_grid if self.elstmr_flag: # ELSTRMR TOP SURFACE # dofs at elastomer top surface (used to integrate the force) # elastomer = self.elstmr_fe_grid elstmr_top_dofs_z = elastomer[:, :, -1, :, :, -1].dofs[:, :, 2].flatten() load_dofs_z = np.unique(elstmr_top_dofs_z) print 'load_dofs_z', load_dofs_z else: # LINE LOAD TOP OF LOAD ZONE # dofs at center line of the specmn load zone (used to integrate the force) # note slice index in x-direction is only valid for load_zone_shape_x = 2 ! # load_zone_spec_topline_dofs_z = load_zone_spec[ 0, :, -1, -1, :, -1].dofs[:, :, 2].flatten() load_dofs_z = np.unique(load_zone_spec_topline_dofs_z) print 'load_dofs_z', load_dofs_z # SUPPRT LINE # dofs at support line of the specmn (used to integrate the force) # outer_zone_spec_supprtline_dofs_z = outer_zone_spec[ -1, :, 0, -1, :, 0].dofs[:, :, 2].flatten() supprt_dofs_z = np.unique(outer_zone_spec_supprtline_dofs_z) print 'supprt_dofs_z', supprt_dofs_z # CENTER DOF (used for tracing of the displacement) # center_bottom_dof = mid_zone_spec[0, 0, 0, 0, 0, 0].dofs[0, 0, 2] print 'center_bottom_dof', center_bottom_dof # THIRDPOINT DOF (used for tracing of the displacement) # dofs at center middle of the laod zone at the bottom side # # NOTE: slice index in x-direction is only valid for load_zone_shape_x = 2 ! thirdpoint_bottom_dof = load_zone_spec[0, 0, 0, -1, 0, 0].dofs[0, 0, 2] print 'thirdpoint_bottom_dof', thirdpoint_bottom_dof # force-displacement-diagram (CENTER) # self.f_w_diagram_center = RTraceGraph( name='displacement_elasttop (center) - force', var_x='U_k', idx_x=center_bottom_dof, var_y='F_int', idx_y_arr=load_dofs_z, record_on='update', transform_x='-x * 1000', # %g * x' % ( fabs( w_max ),), # due to symmetry the total force sums up from four parts of the beam (2 symmetry axis): # transform_y='-4000. * y') # force-displacement-diagram_supprt (SUPPRT) # self.f_w_diagram_supprt = RTraceGraph( name='displacement_supprtline (center) - force', var_x='U_k', idx_x=center_bottom_dof, var_y='F_int', idx_y_arr=supprt_dofs_z, record_on='update', transform_x='-x * 1000', # %g * x' % ( fabs( w_max ),), # due to symmetry the total force sums up from four parts of the beam (2 symmetry axis): # transform_y='4000. * y') # force-displacement-diagram (THIRDPOINT) # self.f_w_diagram_thirdpoint = RTraceGraph( name='displacement_elasttop (thirdpoint) - force', var_x='U_k', idx_x=thirdpoint_bottom_dof, var_y='F_int', idx_y_arr=load_dofs_z, record_on='update', transform_x='-x * 1000', # %g * x' % ( fabs( w_max ),), # due to symmetry the total force sums up from four parts of the beam (2 symmetry axis): # transform_y='-4000. * y') ts = TS( sdomain=self.fe_domain, bcond_list=self.bc_list, rtrace_list=[ self.f_w_diagram_center, self.f_w_diagram_thirdpoint, self.f_w_diagram_supprt, RTraceDomainListField(name='Displacement', var='u', idx=0, warp=True), # RTraceDomainListField(name = 'Stress' , # var = 'sig_app', idx = 0, warp = True, # record_on = 'update'), # RTraceDomainListField(name = 'Strain' , # var = 'eps_app', idx = 0, warp = True, # record_on = 'update'), # RTraceDomainListField(name = 'Damage' , # var = 'omega_mtx', idx = 0, warp = True, # record_on = 'update'), RTraceDomainListField(name='max_omega_i', warp=True, var='max_omega_i', idx=0, record_on='update'), # RTraceDomainListField(name = 'IStress' , # position = 'int_pnts', # var = 'sig_app', idx = 0, # record_on = 'update'), # RTraceDomainListField(name = 'IStrain' , # position = 'int_pnts', # var = 'eps_app', idx = 0, # record_on = 'update'), ]) # Add the time-loop control tloop = TLoop(tstepper=ts, KMAX=50, tolerance=self.tolerance, RESETMAX=0, tline=TLine(min=0.0, step=self.tstep, max=self.tmax), ord=self.ord) return tloop def peval(self): ''' Evaluate the model and return the array of results specified in the method get_sim_outputs. ''' U = self.tloop.eval() self.f_w_diagram_center.refresh() F_max = max(self.f_w_diagram_center.trace.ydata) u_center_top_z = U[self.center_top_dofs][0, 0, 2] return array([u_center_top_z, F_max], dtype='float_') def get_sim_outputs(self): ''' Specifies the results and their order returned by the model evaluation. ''' return [ SimOut(name='u_center_top_z', unit='m'), SimOut(name='F_max', unit='kN') ]
class PDistrib(HasTraits): implements = IPDistrib # puts all chosen continuous distributions distributions defined # in the scipy.stats.distributions module as a list of strings # into the Enum trait distr_choice = Enum(distr_enum) distr_dict = Dict(distr_dict) # distr_choice = Enum('sin2x', 'weibull_min', 'sin_distr', 'uniform', 'norm') # distr_dict = {'sin2x' : sin2x, # 'uniform' : uniform, # 'norm' : norm, # 'weibull_min' : weibull_min, # 'sin_distr' : sin_distr} # instantiating the continuous distributions distr_type = Property(Instance(Distribution), depends_on='distr_choice') @cached_property def _get_distr_type(self): return Distribution(self.distr_dict[self.distr_choice]) # change monitor - accumulate the changes in a single event trait changed = Event @on_trait_change('distr_choice, distr_type.changed, quantile, n_segments') def _set_changed(self): self.changed = True # ------------------------------------------------------------------------ # Methods setting the statistical modments # ------------------------------------------------------------------------ mean = Property def _get_mean(self): return self.distr_type.mean def _set_mean(self, value): self.distr_type.mean = value variance = Property def _get_variance(self): return self.distr_type.mean def _set_variance(self, value): self.distr_type.mean = value # ------------------------------------------------------------------------ # Methods preparing visualization # ------------------------------------------------------------------------ quantile = Float(0.00001, auto_set=False, enter_set=True) range = Property(Tuple(Float), depends_on='distr_type.changed, quantile') @cached_property def _get_range(self): return (self.distr_type.distr.ppf(self.quantile), self.distr_type.distr.ppf(1 - self.quantile)) n_segments = Int(500, auto_set=False, enter_set=True) dx = Property(Float, depends_on='distr_type.changed, quantile, n_segments') @cached_property def _get_dx(self): range_length = self.range[1] - self.range[0] return range_length / self.n_segments # ------------------------------------------------------------------------- # Discretization of the distribution domain # ------------------------------------------------------------------------- x_array = Property(Array('float_'), depends_on='distr_type.changed,' 'quantile, n_segments') @cached_property def _get_x_array(self): '''Get the intrinsic discretization of the distribution respecting its bounds. ''' return linspace(self.range[0], self.range[1], self.n_segments + 1) # =========================================================================== # Access function to the scipy distribution # =========================================================================== def pdf(self, x): return self.distr_type.distr.pdf(x) def cdf(self, x): return self.distr_type.distr.cdf(x) def rvs(self, n): return self.distr_type.distr.rvs(n) def ppf(self, e): return self.distr_type.distr.ppf(e) # =========================================================================== # PDF - permanent array # =========================================================================== pdf_array = Property(Array('float_'), depends_on='distr_type.changed,' 'quantile, n_segments') @cached_property def _get_pdf_array(self): '''Get pdf values in intrinsic positions''' return self.distr_type.distr.pdf(self.x_array) def get_pdf_array(self, x_array): '''Get pdf values in externally specified positions''' return self.distr_type.distr.pdf(x_array) # =========================================================================== # CDF permanent array # =========================================================================== cdf_array = Property(Array('float_'), depends_on='distr_type.changed,' 'quantile, n_segments') @cached_property def _get_cdf_array(self): '''Get cdf values in intrinsic positions''' return self.distr_type.distr.cdf(self.x_array) def get_cdf_array(self, x_array): '''Get cdf values in externally specified positions''' return self.distr_type.distr.cdf(x_array) # ------------------------------------------------------------------------- # Randomization # ------------------------------------------------------------------------- def get_rvs_array(self, n_samples): return self.distr_type.distr.rvs(n_samples)
class ResultView(HasTraits): spirrid_view = Instance(SPIRRIDModelView) title = Str('result plot') n_samples = Int(10) figure = Instance(Figure) def _figure_default(self): figure = Figure(facecolor='white') #figure.add_axes( [0.08, 0.13, 0.85, 0.74] ) return figure data_changed = Event(True) clear = Button def _clear_fired(self): axes = self.figure.axes[0] axes.clear() self.data_changed = True def get_rvs_theta_arr(self, n_samples): rvs_theta_arr = array([ repeat(value, n_samples) for value in self.spirrid_view.model.rf.param_values ]) for idx, name in enumerate(self.spirrid_view.model.rf.param_keys): rv = self.spirrid_view.model.rv_dict.get(name, None) if rv: rvs_theta_arr[idx, :] = rv.get_rvs_theta_arr(n_samples) return rvs_theta_arr sample = Button(desc='Show samples') def _sample_fired(self): n_samples = 20 self.spirrid_view.model.set( min_eps=0.00, max_eps=self.spirrid_view.max_eps, n_eps=self.spirrid_view.n_eps, ) # get the parameter combinations for plotting rvs_theta_arr = self.get_rvs_theta_arr(n_samples) eps_arr = self.spirrid_view.model.eps_arr figure = self.figure axes = figure.gca() for theta_arr in rvs_theta_arr.T: q_arr = self.spirrid_view.model.rf(eps_arr, *theta_arr) axes.plot(eps_arr, q_arr, color='grey') self.data_changed = True @on_trait_change('spirrid_view.data_changed') def _redraw(self): figure = self.figure axes = figure.gca() mc = self.spirrid_view.model.mean_curve xdata = mc.xdata mean_per_fiber = mc.ydata # total expectation for independent variables = product of marginal expectations mean = mean_per_fiber * self.spirrid_view.mean_parallel_links axes.set_title(self.spirrid_view.plot_title, weight='bold') axes.plot(xdata, mean, linewidth=2, label=self.spirrid_view.run_legend) if self.spirrid_view.stdev: # get the variance at x from SPIRRID variance = self.spirrid_view.model.var_curve.ydata # evaluate variance for the given mean and variance of parallel links # law of total variance D[xy] = E[x]*D[y] + D[x]*[E[y]]**2 variance = self.spirrid_view.mean_parallel_links * variance + \ self.spirrid_view.stdev_parallel_links ** 2 * mean_per_fiber ** 2 stdev = sqrt(variance) axes.plot(xdata, mean + stdev, linewidth=2, color='black', ls='dashed', label='stdev') axes.plot(xdata, mean - stdev, linewidth=2, ls='dashed', color='black') axes.fill_between(xdata, mean + stdev, mean - stdev, color='lightgrey') axes.set_xlabel(self.spirrid_view.label_x, weight='semibold') axes.set_ylabel(self.spirrid_view.label_y, weight='semibold') axes.legend(loc='best') if xdata.any() == 0.: self.figure.clear() self.data_changed = True traits_view = View( HGroup(Item('n_samples', label='No of samples'), Item('sample', show_label=False, resizable=False), Item('clear', show_label=False, resizable=False, springy=False)), Item('figure', show_label=False, editor=MPLFigureEditor()))
class MushRoofModelNonLin(MRquarter): '''Overload the nonlinear model. ''' #----------------- # composite cross section unit cell: #----------------- # ccs_unit_cell_key = Enum(CCSUnitCell.db.keys(), simdb=True, input=True, auto_set=False, enter_set=True) ccs_unit_cell_ref = Property(Instance(SimDBClass), depends_on='ccs_unit_cell_key') @cached_property def _get_ccs_unit_cell_ref(self): return CCSUnitCell.db[self.ccs_unit_cell_key] # vary the failure strain in PhiFnGeneralExtended: factor_eps_fail = Float(1.0, input=True, ps_levels=(1.0, 1.2, 3)) #----------------- # damage function: #----------------- # material_model = Str(input=True) def _material_model_default(self): # return the material model key of the first DamageFunctionEntry # This is necessary to avoid an ValueError at setup return self.ccs_unit_cell_ref.damage_function_list[0].material_model calibration_test = Str(input=True) def _calibration_test_default(self): # return the material model key of the first DamageFunctionEntry # This is necessary to avoid an ValueError at setup return self.ccs_unit_cell_ref.damage_function_list[0].calibration_test damage_function = Property(Instance(MFnLineArray), depends_on='input_change') @cached_property def _get_damage_function(self): return self.ccs_unit_cell_ref.get_param(self.material_model, self.calibration_test) #----------------- # phi function extended: #----------------- # phi_fn = Property(Instance(PhiFnGeneralExtended), depends_on='input_change,+ps_levels') @cached_property def _get_phi_fn(self): return PhiFnGeneralExtended(mfn=self.damage_function, factor_eps_fail=self.factor_eps_fail) #---------------------------------------------------------------------------------- # mats_eval #---------------------------------------------------------------------------------- # age of the plate at the time of testing # NOTE: that the same phi-function is used independent of age. This assumes a # an afine/proportional damage evolution for different ages. # age = Int( 28, #input = True ) # composite E-modulus # E_c = Property(Float, depends_on='input_change') @cached_property def _get_E_c(self): return self.ccs_unit_cell_ref.get_E_c_time(self.age) # Poisson's ratio # nu = Property(Float, depends_on='input_change') @cached_property def _get_nu(self): return self.ccs_unit_cell_ref.nu # @todo: for mats_eval the information of the unit cell should be used # in order to use the same number of microplanes and model version etc... # mats = Property(Instance(MATS2D5MicroplaneDamage), depends_on='input_change') @cached_property def _get_mats(self): mats = MATS2D5MicroplaneDamage(E=self.E_c, nu=self.nu, n_mp=30, symmetrization='sum-type', model_version='compliance', phi_fn=self.phi_fn) return mats tline = Instance(TLine) def _tline_default(self): return TLine(min=0.0, step=1.0, max=8.0) rtrace_list = List def _rtrace_list_default(self): return [ # RTraceDomainListField( name = 'Displacement' , # var = 'u', idx = 0, warp = True ), # RTraceDomainListField( name = 'Stress' , # var = 'sig_app', idx = 0, warp = True, # record_on = 'update', ), # self.max_princ_stress, RTraceDomainListField(name='Damage', var='omega_mtx', idx=0, warp=True, record_on='update'), ]
class 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 MRone(MushRoofModel): implements(ISimModel) mushroof_part = 'one' #=============================================================================== # fe_grid #=============================================================================== n_elems_xy_quarter = Int(10, input=True) # , ps_levels = [4, 16, 5] ) n_elems_z = Int(1, input=True) # , ps_levels = [1, 2, 1] ) n_elems_col_z = Int(10, input=True, ps_levels=[5, 20, 3]) n_elems_col_xy = Int(2, input=True, ps_levels=[2, 4, 1]) shift_elems = True vtk_r = Float(1.00) # default roof fe_roof = Instance((FETSEval), depends_on='+ps_levels, +input') def _fe_roof_default(self): fets = self.fe_quad_serendipity_roof fets.vtk_r *= self.vtk_r return fets # default plate fe_plate = Instance((FETSEval), depends_on='+ps_levels, +input') def _fe_plate_default(self): fets = self.fe_quad_serendipity_plate fets.ngp_r = 3 fets.ngp_s = 3 fets.ngp_t = 3 fets.vtk_r *= self.vtk_r return fets # shell # hp_shell = Property(Instance(HPShell), depends_on='+ps_levels, +input') @cached_property def _get_hp_shell(self): return HPShell(length_xy_quarter=self.length_xy_quarter, length_z=self.length_z, n_elems_xy_quarter=self.n_elems_xy_quarter, n_elems_z=self.n_elems_z, scalefactor_delta_h=self.scalefactor_delta_h, const_reinf_layer_elem=self.const_reinf_layer_elem, width_top_col=self.width_top_col, mushroof_part=self.mushroof_part, shift_array=self.shift_array, X0=self.X0) # plate # plate = Property(Instance(GEOColumn), depends_on='+ps_levels, +input') @cached_property def _get_plate(self): return GEOColumn( width_top=self.width_top_col, width_bottom=self.width_top_col, X0=[3.5, 3.5, -self.t_plate], # - 0.25], h_col=self.t_plate) # column # # X0_column = Array( [ 4., 4., -3.] ) column = Property(Instance(GEOColumn), depends_on='+ps_levels, +input') @cached_property def _get_column(self): return GEOColumn( width_top_col=self.width_top_col, width_bottom_col=self.width_bottom_col, h_col=self.h_col - self.t_plate, # r_pipe = self.r_pipe, X0=[3.5, 3.5, -(self.h_col)]) # - 0.5] ) # default column fe_column = Instance((FETSEval), transient=True, depends_on='+ps_levels, +input') def _fe_column_default(self): fets = self.fe_quad_serendipity_column fets.vtk_r *= self.vtk_r return fets fe_grid_roof = Property(Instance(FEGrid), depends_on='+ps_levels, +input') @cached_property def _get_fe_grid_roof(self): return FEGrid(coord_min=(0.0, 0.0, 0.0), coord_max=(1.0, 1.0, 1.0), geo_transform=self.hp_shell, shift_array=self.shift_array, shape=(self.n_elems_xy, self.n_elems_xy, self.n_elems_z), fets_eval=self.fe_roof) fe_grid_column = Property(Instance(FEGrid), depends_on='+ps_levels, +input') @cached_property def _get_fe_grid_column(self): return FEGrid(coord_min=(0.0, 0.0, 0.0), coord_max=(1.0, 1.0, 1.0), geo_transform=self.column, shape=(self.n_elems_col_xy, self.n_elems_col_xy, self.n_elems_col_z), fets_eval=self.fe_column) fe_grid_plate = Property(Instance(FEGrid), depends_on='+ps_levels, +input') @cached_property def _get_fe_grid_plate(self): return FEGrid(coord_min=(0.0, 0.0, 0.0), coord_max=(1.0, 1.0, 1.0), geo_transform=self.plate, shape=(self.n_elems_col_xy, self.n_elems_col_xy, 2), fets_eval=self.fe_plate) #=============================================================================== # ps_study #=============================================================================== def peval(self): ''' Evaluate the model and return the array of results specified in the method get_sim_outputs. ''' U = self.tloop.eval() U_edge = U[self.edge_corner_1_dof][0, 0, 2] F_int = self.tloop.tstepper.F_int F_int_slice_x = F_int[self.edge_roof_right] F_int_slice_y = F_int[self.edge_roof_top] # bring dofs into right order for plot # F_hinge_in_order_x = self.sort_by_dofs(self.edge_roof_top, F_int_slice_x) F_hinge_in_order_y = self.sort_by_dofs(self.edge_roof_top, F_int_slice_y) F_hinge_x = append(F_hinge_in_order_x[:, :-1, 0], F_hinge_in_order_x[-1, -1, 0]) F_hinge_y = append(F_hinge_in_order_y[:, :-1, 1], F_hinge_in_order_y[-1, -1, 1]) F_hinge_y_sum = sum(F_hinge_y.flatten()) F_hinge_x_sum = sum(F_hinge_x.flatten()) # # self.visual_force_bar( F_hinge_x.flatten() # , y_label = "internal force x [MN]" # , Title = 'F_Hinge_x_shrinkage' ) # self.visual_force_bar( F_hinge_y.flatten() # , y_label = "internal force y [MN]" # , Title = 'F_Hinge_y_shrinkage' ) print "u_edge", U_edge print "n_elems_xy_col", self.n_elems_col_xy print "n_elems_z_col", self.n_elems_col_z print "n_elems_xy_quarter", self.n_elems_xy_quarter print "n_elems_z", self.n_elems_z return array( [ U_edge, # u_x_corner2, # F_hinge_y_sum] ) # u_z_corner2, # max_princ_stress ] ], dtype='float_') def get_sim_outputs(self): ''' Specifies the results and their order returned by the model evaluation. ''' return [ SimOut(name='U', unit='m'), # SimOut( name = 'u_x_corner2', unit = 'm' ), # SimOut( name = 'N Gelenk', unit = 'MN' ), ] # SimOut( name = 'u_z_corner2', unit = 'm' ), # SimOut( name = 'maximum principle stress', unit = 'MPa' ) ] #=============================================================================== # response tracer #=============================================================================== rtrace_list = List def _rtrace_list_default(self): return [self.max_princ_stress, self.sig_app, self.u, self.f_dof] shift_array = Array(value=[ [0.45 / 2**0.5, 0.45 / 2**0.5, 1], ], input=True) #=============================================================================== # boundary conditions #=============================================================================== bc_plate_roof_link_list = Property(List, depends_on='+ps_levels, +input') @cached_property def _get_bc_plate_roof_link_list(self): ''' links all plate corner nodes of each elements to the adjacent elements of the roof ''' roof = self.fe_grid_roof plate = self.fe_grid_plate bc_col_link_list = [] slice_1 = [ BCSlice(var='u', dims=[0, 1, 2], slice=roof[self.n_elems_xy_quarter - 1, self.n_elems_xy_quarter, 0, 0, 0, 0], link_slice=plate[0, 0, -1, 0, 0, -1], link_coeffs=[1.0], value=0.) ] slice_2 = [ BCSlice(var='u', dims=[0, 1, 2], slice=roof[self.n_elems_xy_quarter, self.n_elems_xy_quarter - 1, 0, 0, 0, 0], link_slice=plate[-1, 0, -1, -1, 0, -1], link_coeffs=[1.0], value=0.) ] slice_3 = [ BCSlice(var='u', dims=[0, 1, 2], slice=roof[self.n_elems_xy_quarter + 1, self.n_elems_xy_quarter, 0, 0, 0, 0], link_slice=plate[-1, -1, -1, -1, -1, -1], link_coeffs=[1.0], value=0.) ] slice_4 = [ BCSlice(var='u', dims=[0, 1, 2], slice=roof[self.n_elems_xy_quarter, self.n_elems_xy_quarter + 1, 0, 0, 0, 0], link_slice=plate[0, -1, -1, 0, -1, -1], link_coeffs=[1.0], value=0.) ] slice_5 = [ BCSlice(var='u', dims=[0, 1, 2], slice=roof[self.n_elems_xy_quarter, self.n_elems_xy_quarter, 0, 0, 0, 0], link_slice=plate[self.n_elems_col_xy / 2.0, self.n_elems_col_xy / 2.0, -1, 0, 0, -1], link_coeffs=[1.0], value=0.) ] bc_plate_roof_link_list = slice_1 + slice_2 + slice_3 + slice_4 + slice_5 return bc_plate_roof_link_list bc_roof_top_roof_low_link_list = Property(List, depends_on='+ps_levels, +input') @cached_property def _get_bc_roof_top_roof_low_link_list(self): ''' links all plate corner nodes of each elements to the adjacent elements of the roof ''' roof = self.fe_grid_roof plate = self.fe_grid_plate bc_roof_top_roof_low_link_list = [] slice_1 = [ BCSlice(var='u', dims=[2], link_slice=roof[self.n_elems_xy_quarter - 1, self.n_elems_xy_quarter, 0, 0, 0, 0], slice=roof[self.n_elems_xy_quarter - 1, self.n_elems_xy_quarter, -1, 0, 0, -1], link_coeffs=[1.0], value=0.) ] slice_2 = [ BCSlice(var='u', dims=[2], link_slice=roof[self.n_elems_xy_quarter, self.n_elems_xy_quarter - 1, 0, 0, 0, 0], slice=roof[self.n_elems_xy_quarter, self.n_elems_xy_quarter - 1, -1, 0, 0, -1], link_coeffs=[1.0], value=0.) ] slice_3 = [ BCSlice(var='u', dims=[2], link_slice=roof[self.n_elems_xy_quarter + 1, self.n_elems_xy_quarter, 0, 0, 0, 0], slice=roof[self.n_elems_xy_quarter + 1, self.n_elems_xy_quarter, -1, 0, 0, -1], link_coeffs=[1.0], value=0.) ] slice_4 = [ BCSlice(var='u', dims=[2], link_slice=roof[self.n_elems_xy_quarter, self.n_elems_xy_quarter + 1, 0, 0, 0, 0], slice=roof[self.n_elems_xy_quarter, self.n_elems_xy_quarter + 1, -1, 0, 0, -1], link_coeffs=[1.0], value=0.) ] slice_5 = [ BCSlice(var='u', dims=[2], link_slice=roof[self.n_elems_xy_quarter, self.n_elems_xy_quarter, 0, 0, 0, 0], slice=roof[self.n_elems_xy_quarter, self.n_elems_xy_quarter, -1, 0, 0, -1], link_coeffs=[1.0], value=0.) ] bc_roof_top_roof_low_link_list = slice_1 + slice_2 + slice_3 + slice_4 + slice_5 return bc_roof_top_roof_low_link_list bc_plate_column_link_list = Property(List, depends_on='+ps_levels, +input') @cached_property def _get_bc_plate_column_link_list(self): ''' links all column nodes to plate nodes ''' column = self.fe_grid_column plate = self.fe_grid_plate slice_1 = [ BCSlice(var='u', dims=[0, 1, 2], slice=plate[:, :, 0, -1, -1, 0], link_slice=column[:, :, -1, -1, -1, -1], link_coeffs=[1.0], value=0.) ] slice_2 = [ BCSlice(var='u', dims=[0, 1, 2], slice=plate[:, :, 0, 0, 0, 0], link_slice=column[:, :, -1, 0, 0, -1], link_coeffs=[1.0], value=0.) ] slice_3 = [ BCSlice(var='u', dims=[0, 1, 2], slice=plate[:, :, 0, 0, -1, 0], link_slice=column[:, :, -1, 0, -1, -1], link_coeffs=[1.0], value=0.) ] slice_4 = [ BCSlice(var='u', dims=[0, 1, 2], slice=plate[:, :, 0, -1, 0, 0], link_slice=column[:, :, -1, -1, 0, -1], link_coeffs=[1.0], value=0.) ] return slice_1 + slice_2 + slice_3 + slice_4 # return [BCSlice( var = 'u' , dims = [0, 1, 2], # slice = plate[:,:,0,:,:, 0 ], # link_slice = column[ :,:,-1 ,:,:,-1], link_coeffs = [1.0], value = 0. )] link_edge_list = Property(List, depends_on='+ps_levels, +input') @cached_property def _get_link_edge_list(self): ''' links all edge nodes to one node, for this node boundary conditions are applied, the complete force within the edge hinge can therefore be evaluated at one node ''' roof = self.fe_grid_roof dof_constraint_0 = [ BCSlice(var='u', dims=[1], slice=roof[:, -1, -1, :, -1, -1], value=0.0) ] dof_constraint_1 = [ BCSlice(var='u', dims=[0], slice=roof[-1, :, -1, -1, :, -1], value=0.0) ] link_edge_list = dof_constraint_0 + dof_constraint_1 return link_edge_list bc_col_clamped_list = Property(List, depends_on='+ps_levels, +input') @cached_property def _get_bc_col_clamped_list(self): column = self.fe_grid_column constraint = [ BCSlice(var='u', dims=[0, 1, 2], slice=column[:, :, 0, :, :, 0], value=0.0) ] return constraint bc_col_hinge_list = Property(List, depends_on='+ps_levels, +input') @cached_property def _get_bc_col_hinge_list(self): constraint = [] column = self.fe_grid_column for i in range(0, self.n_elems_col): dof_const = [ BCSlice(var='u', dims=[0, 1, 2], slice=column[i, 0, 0, 0, 0, 0], link_slice=column[-1 - i, -1, 0, -1, -1, 0], link_coeffs=[-1.0], value=0.0) ] constraint = constraint + dof_const for i in range(0, self.n_elems_col): dof_const = [ BCSlice(var='u', dims=[0, 1, 2], slice=column[0, -1 - i, 0, 0, -1, 0], link_slice=column[-1, i, 0, -1, 0, 0], link_coeffs=[-1.0], value=0.0) ] constraint = constraint + dof_const return constraint #=============================================================================== # loading cases for mr_one only symmetric #=============================================================================== lc_g_list = Property(List, depends_on='+ps_levels, +input') @cached_property def _get_lc_g_list(self): # slices roof = self.fe_grid_roof column = self.fe_grid_column upper_surf = roof[:, :, -1, :, :, -1] bottom_edge_roof = roof[:, 0, -1, :, 0, -1] left_edge_roof = roof[0, :, -1, 0, :, -1] # loads in global z- direction material_density_roof = -22.4e-3 # [MN/m^3] material_density_column = -26e-3 # [MN/m^3] additional_surface_load = -0.20e-3 # [MN/m^2] additional_t_constr = -0.02 * 22.4e-3 edge_load = -0.35e-3 # [MN/m] return [ BCSlice(var='f', value=material_density_roof, dims=[2], integ_domain='global', slice=roof[:, :, :, :, :, :]), BCSlice(var='f', value=material_density_column, dims=[2], integ_domain='global', slice=column[:, :, :, :, :, :]), ] # BCSlice( var = 'f', value = additional_surface_load + additional_t_constr, # dims = [2], integ_domain = 'global', # slice = upper_surf ), # BCSlice( var = 'f', value = edge_load, dims = [2], # integ_domain = 'global', # slice = bottom_edge_roof ), # BCSlice( var = 'f', value = edge_load, dims = [2], # integ_domain = 'global', # slice = left_edge_roof )] lc_s_list = Property(List, depends_on='+ps_levels, +input') @cached_property def _get_lc_s_list(self): # slices roof = self.fe_grid_roof upper_surf = roof[:, :, -1, :, :, -1] # loads in global z- direction snow_load = -0.85e-3 return [ BCSlice(var='f', value=snow_load, dims=[2], integ_domain='global', slice=upper_surf) ] lc_shrink_list = Property(List, depends_on='+ps_levels, +input') def _get_lc_shrink_list(self): self.initial_strain_roof = True self.initial_strain_col = True self.t_up = -100 self.t_lo = -100 #=============================================================================== # time loop #=============================================================================== tloop = Property(depends_on='+ps_levels, +input') @cached_property def _get_tloop(self): roof = self.fe_grid_roof column = self.fe_grid_column plate = self.fe_grid_plate ts = TS( sdomain=[roof, plate, column], dof_resultants=True, bcond_list= # boundary conditions # self.bc_roof_top_roof_low_link_list + self.bc_plate_column_link_list + self.bc_plate_roof_link_list + self.link_edge_list + self.bc_col_clamped_list + # loading # self.lc_g_list, rtrace_list=self.rtrace_list) # Add the time-loop control tloop = TLoop(tstepper=ts, tolerance=1e-4, tline=self.tline) self.edge_corner_1_dof = roof[0, 0, 0, 0, 0, 0].dofs self.edge_corner_2_dof = roof[-1, 0, -1, -1, 0, -1].dofs self.dof = roof[-1, 0, -1, -1, 0, -1].dofs[0][0][0] self.edge_roof_top = roof[:, -1, -1, :, -1, -1].dofs self.edge_roof_right = roof[-1, :, -1, -1, :, -1].dofs return tloop