class TGrid(RegularGrid): ''' Regular grid of random variables theta. ''' theta_11 = Array(float) def _theta_11_default(self): ''' 'discretize the range (-1,1) symmetrically with n_int points ''' n_int = self.randomization.n_int return np.linspace(-(1.0 - 1.0 / n_int), (1.0 - 1.0 / n_int), n_int) def get_theta_for_distrib(self, tvar): if tvar.n_int != None: n_int = tvar.n_int else: n_int = self.randomization.n_int min_theta, max_theta, d_theta = self.get_theta_range(tvar) return np.linspace(min_theta + 0.5 * d_theta, max_theta - 0.5 * d_theta, n_int) dG_ogrid = Property(Array(float), depends_on='recalc') @cached_property def _get_dG_ogrid(self): dG_ogrid = [1.0 for i in range(len(self.theta))] for i, (tvar, theta) in \ enumerate(zip(self.randomization.tvar_lst, self.theta)): if not isinstance(tvar, float): # get the size of the integration cell min_theta, max_theta, d_theta = self.get_theta_range(tvar) dG_ogrid[i] = tvar.pdf(theta) * d_theta return dG_ogrid
class LatinHypercubeSampling(IrregularSampling): ''' Latin hypercube sampling generated from the samples of the individual random variables with random perturbation. ''' pi = Array(float) def _pi_default(self): return np.linspace(0.5 / self.n_sim, 1. - 0.5 / self.n_sim, self.n_sim) theta = Property(Array(float), depends_on='recalc') @cached_property def _get_theta(self): theta_list = [] for tvar in self.randomization.tvar_lst: if isinstance(tvar, float): theta_list.append(tvar) else: # point probability function theta_arr = tvar.ppf(self.pi) theta_list.append(np.random.permutation(theta_arr)) return theta_list
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)
def _set_array_attribs(self): '''Set the measured data as named attributes defining slices into the processed data array. ''' for i, factor in enumerate(self.factor_list): self.add_trait( factor, Array(value=self.processed_data_array[:, i], transient=True)) if self.flag_ASC_file: for i, factor in enumerate(self.factor_list_ASC): self.add_trait( factor, Array(value=self.data_array_ASC[:, i], transient=True))
class RegularGrid(RandomSampling): '''Grid shape randomization ''' theta_list = Property(Array(float), depends_on='recalc') @cached_property def _get_theta_list(self): '''Get the orthogonally oriented arrays of random variables. ''' theta_list = [] for tvar in self.randomization.tvar_lst: if isinstance(tvar, float): theta_list.append(tvar) elif isinstance(tvar, int): theta_list.append(float(tvar)) elif isinstance(tvar, RV): theta_list.append(self.get_theta_for_distrib(tvar)) else: raise TypeError, 'bad random variable specification: %s' % tvar return theta_list theta = Property(Array(float), depends_on='recalc') @cached_property def _get_theta(self): return make_ogrid(self.theta_list) dG = Property(Array(float), depends_on='recalc') @cached_property def _get_dG(self): if len(self.dG_ogrid) == 0: # deterministic case return 1.0 else: # cross product of dG marginal values return reduce(lambda x, y: x * y, self.dG_ogrid) def get_samples(self, n): '''Get the fully expanded samples. ''' # make the random permutation of the simulations and take n of them idx = np.random.permutation(np.arange(self.n_sim))[:n] # full orthogonalization (including scalars) otheta = make_ogrid_full(self.theta_list) # array of ones used for expansion oarray = np.ones(np.broadcast(*otheta).shape, dtype=float) # expand (broadcast), flatten and stack the arrays return np.vstack([ (t * oarray).flatten()[idx] for t in otheta ])
class PGrid(RegularGrid): ''' Regular grid of probabilities ''' pi = Array(float) def _pi_default(self): n_int = self.randomization.n_int return np.linspace(0.5 / n_int, 1. - 0.5 / n_int, n_int) def get_theta_for_distrib(self, distrib): return distrib.ppf(self.pi) dG_ogrid = Property(Array(float), depends_on='recalc') @cached_property def _get_dG_ogrid(self): return np.repeat(1. / self.randomization.n_int, self.n_rand_vars) def _get_dG(self): return 1.0 / self.n_sim
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
class IrregularSampling(RandomSampling): '''Irregular sampling based on Monte Carlo concept ''' dG = Property(Array(float)) @cached_property def _get_dG(self): return 1. / self.n_sim def get_samples(self, n): n = min(self.n_sim, n) idx = np.random.permutation(np.arange(self.n_sim))[:n] s_list = [] for t in self.theta: if isinstance(t, np.ndarray): s_list.append(t[idx]) else: s_list.append(np.repeat(t, n)) return np.vstack(s_list)
class NDIdxInterp(HasTraits): # nd array of values (measured, computed..) of # size orthogonalize(axes_values) data = Array # list of control input parameter values axes_values = List(Array(float)) def __call__(self, *gcoords, **kw): '''kw: dictionary of values to interpolate for; len(kw) has to be equal the data dimension ''' order = kw.get('order', 1) mode = kw.get('mode', 'nearest') # check if the number of dimensions to interpolate # in equals the number of given coordinates if len(self.axes_values) != len(gcoords): raise TypeError('''method takes {req} arguments ({given} given)'''.format(req=len(self.axes_values), given=len(gcoords))) icoords = self.get_icoords(gcoords) # create a meshgrid for the interpolation icoords = orthogonalize_filled(icoords) data = self.data # interpolate the value (linear) # a, b, c = [0.5, 0.5, 0.5], [0, 0, 0], [0, 1, 2] # icoords = [a, b, c] val = ndimage.map_coordinates(data, icoords, order=order, mode=mode) return val def get_icoords(self, gcoords): ''' gcoords: values to be interpolated for this method transforms the global coords to "index" coords ''' icoords = [ np.interp(gcoord, axis_values, np.arange(len(axis_values))) for gcoord, axis_values in zip(gcoords, self.axes_values) ] return icoords
class MonteCarlo(IrregularSampling): ''' Standard Monte Carlo randomization: For each variable generate n_sim = n_int ** n_rv number of sampling points. ''' theta = Property(Array(float), depends_on='recalc') @cached_property def _get_theta(self): theta_list = [] for tvar in self.randomization.tvar_lst: if isinstance(tvar, types.FloatType): theta_list.append(tvar) else: theta_arr = tvar.rvs(self.n_sim) theta_list.append(theta_arr) return theta_list
class GEOColumn( HasTraits ): h_col = Float( 3.00, unit = 'm' ) X0 = Array( float, value = [ 4., 4., -3.0 ] ) width_top = Float( 0.45, unit = 'm' ) width_bottom = Float( 0.35, unit = 'm' ) r_pipe = Float( 0.1, unit = 'm' ) def __call__( self, points ): xi, yi, zi = points[:, 0], points[:, 1], points[:, 2] # grid from 0 to 1, shift origin for rotation # xi -= 0.5 yi -= 0.5 # setting of global coordinates different width over h_col # f_QS: # xi = ( ( self.width_top - self.width_bottom ) * zi + self.width_bottom ) * xi yi = ( ( self.width_top - self.width_bottom ) * zi + self.width_bottom ) * yi zi *= self.h_col # rotation of 45 with global coordinates # x = cos( pi / 4.0 ) * xi + sin( pi / 4.0 ) * yi y = -sin( pi / 4.0 ) * xi + cos( pi / 4.0 ) * yi z = zi + self.X0[2] # @TODO: kill element in the center of the columns: #shift of internal elements # # r_0 = where( ( xi ** 2 + yi ** 2 ) ** 0.5 >= self.r_pipe, self.r_pipe , ( xi ** 2 + yi ** 2 ) ** 0.5 ) # scale_r = where ( r_0 == 0, 0, self.r_pipe / r_0 ) # x = scale_r * x + self.X0[0] # y = scale_r * y + self.X0[1] x = x + self.X0[0] y = y + self.X0[1] return c_[x, y, z]
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
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 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 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 TSCrackLoc( TStepper ): '''Modified time stepper with adjusted predictor and corrector. The management of the shared variable omega_0 is done before calling the standard corrector predictor. The strain state at the x = 0 is evaluated and provided to the MATS1DCrackLoc material model in order to evaluate the next trial damage state. During the corrpred call, the material model then uses these variables during the stress and stiffness integration. ''' mats_eval = Property( Instance( MATS1DCrackLoc ) ) def _get_mats_eval( self ): return self.subdomains[0].fets_eval.mats_eval.mats_phase1 on_update = Callable fe_grid = Property( Instance( FEGrid ) ) @cached_property def _get_fe_grid( self ): # get the single subgrid in the first subdomain. return self.subdomains[0].fe_subgrids[0] concrete_dofs = Property( Array( Float ) ) @cached_property def _get_concrete_dofs( self ): # get the dofs associated with the bottom layer - concrete return self.fe_grid[:, 0, :, 0].dofs[:, :, 0] # specialize the # def eval( self, step_flag, U_k, d_U, t_n, t_n1 ): print 'concrete dofs' print self.concrete_dofs if step_flag == 'corrector': # when in the corrector - switch the trial to accepted # self.mats_eval.update_state() self.on_update() #print 'E', self.subdomains[0].dots.state_array #---------------------------------- # calculate the epxilon_0 at x = 0 #---------------------------------- fe_grid = self.subdomains[0] # pick the first element elem_0 = fe_grid.elements[0] fets_eval = fe_grid.fets_eval # get the displacement vector in the first element u = U_k[ elem_0.get_dof_map() ] # and the coordinates # set the spatial context self.sctx.X = elem_0.get_X_mtx() self.sctx.x = elem_0.get_x_mtx() self.sctx.loc = array( [0], dtype = 'float_' ) # get epsilon eps = fets_eval.get_eps_eng( self.sctx, u ) # set the trial state for the obtained strain self.mats_eval.set_trial_state( eps ) print 'BEGIN TS' # run the standard calculation return super( TSCrackLoc, self ).eval( step_flag, U_k, d_U, t_n, t_n1 )
class ECBLCalibState(HasStrictTraits): # rupture moment and normal force measured in the calibration experiment # (three point bending test) # Mu = Float(3.5, enter_set = True, auto_set = False, input = True) # [kNm] Nu = Float(0.0, enter_set = True, auto_set = False, input = True) # [kN] #=========================================================================== # Cross Section Specification (Geometry and Layout) #=========================================================================== cs_geo = Instance(ECBCrossSectionGeo) def _cs_geo_default(self): return ECBCrossSectionGeo(notify_change = self.set_modified) cs_state = Property(Instance(ECBCrossSectionState), depends_on = 'cs_geo') @cached_property def _get_cs_state(self): return ECBCrossSectionState(cs_geo = self.cs_geo, notify_change = self.set_modified) notify_change = Callable(None) modified = Event @on_trait_change('+input') def set_modified(self): self.modified = True if self.notify_change != None: self.notify_change() u0 = Property(Array(float), depends_on = 'cs_geo.modified, cs_state.modified') @cached_property def _get_u0(self): u0 = self.cs_state.ecb_law.u0 eps_up = -self.cs_geo.cc_law.eps_c_u self.cs_state.set(eps_up = eps_up) eps_lo = self.cs_state.convert_eps_tex_u_2_lo(u0[0]) return np.array([eps_lo, u0[1] ], dtype = 'float') # iteration counter # n = Int(0) def get_lack_of_fit(self, u): '''Return the difference between 'N_external' and 'N_internal' as well as 'M_external' and 'M_internal' N_c (=compressive force of the compressive zone of the concrete) N_t (=total tensile force of the reinforcement layers) ''' print '--------------------iteration', self.n, '------------------------' self.n += 1 # set iteration counter # eps_up = -self.cs_geo.cc_law.eps_c_u eps_lo = u[0] self.cs_state.set(eps_lo = eps_lo, eps_up = eps_up) eps_tex_u = self.cs_state.convert_eps_lo_2_tex_u(u[0]) self.cs_geo.ecb_law.set_cparams(eps_tex_u, u[1]) N_internal = self.cs_state.N M_internal = self.cs_state.M d_N = N_internal - self.Nu d_M = M_internal - self.Mu return np.array([ d_M, d_N ], dtype = float) # solution vector returned by 'fit_response' # u_sol = Property(Array(Float), depends_on = 'modified') @cached_property def _get_u_sol(self): '''iterate 'eps_t' such that the lack of fit between the calculated normal forces in the tensile reinforcement and the compressive zone (concrete) is smaller then 'xtol' defined in function 'brentq'. NOTE: the method 'get_lack_of_fit' returns the relative error. ''' # use scipy-functionality to get the iterated value of 'eps_t' # NOTE: get_lack_of_fit must have a sign change as a requirement # for the function call 'brentq' to work property. # The method brentq has optional arguments such as # 'xtol' - absolut error (default value = 1.0e-12) # 'rtol' - relative error (not supported at the time) # 'maxiter' - maximum numbers of iterations used # return fsolve(self.get_lack_of_fit, self.u0, xtol = 1.0e-5) #=========================================================================== # Calibrated ecb_law_mfn #=========================================================================== calibrated_ecb_law = Property(depends_on = 'modified') @cached_property def _get_calibrated_ecb_law(self): print 'NEW CALIBRATION' self.cs_geo.ecb_law.set_cparams(*self.u_sol) return self.cs_geo.ecb_law view = View(Item('Mu'), Item('Nu'), buttons = ['OK', 'Cancel'] )
class ExpBT3PT(ExType): '''Experiment: Bending Test Three Point ''' # label = Str('three point bending test') implements(IExType) file_ext = 'raw' #-------------------------------------------------------------------- # register a change of the traits with metadata 'input' #-------------------------------------------------------------------- input_change = Event @on_trait_change('+input, ccs.input_change, +ironing_param') def _set_input_change(self): self.input_change = True #-------------------------------------------------------------------------------- # specify inputs: #-------------------------------------------------------------------------------- length = Float(0.46, unit='m', input=True, table_field=True, auto_set=False, enter_set=True) width = Float(0.1, unit='m', input=True, table_field=True, auto_set=False, enter_set=True) thickness = Float(0.02, unit='m', input=True, table_field=True, auto_set=False, enter_set=True) # age of the concrete at the time of testing age = Int(33, unit='d', input=True, table_field=True, auto_set=False, enter_set=True) loading_rate = Float(4.0, unit='mm/min', input=True, table_field=True, auto_set=False, enter_set=True) #-------------------------------------------------------------------------- # composite cross section #-------------------------------------------------------------------------- ccs = Instance(CompositeCrossSection) def _ccs_default(self): '''default settings ''' # fabric_layout_key = 'MAG-07-03' # fabric_layout_key = '2D-02-06a' fabric_layout_key = '2D-05-11' # fabric_layout_key = '2D-09-12' # concrete_mixture_key = 'PZ-0708-1' # concrete_mixture_key = 'FIL-10-09' concrete_mixture_key = 'barrelshell' orientation_fn_key = 'all0' # orientation_fn_key = 'all90' # orientation_fn_key = '90_0' n_layers = 6 s_tex_z = 0.020 / (n_layers + 1) ccs = CompositeCrossSection(fabric_layup_list=[ plain_concrete(s_tex_z * 0.5), FabricLayUp(n_layers=n_layers, orientation_fn_key=orientation_fn_key, s_tex_z=s_tex_z, fabric_layout_key=fabric_layout_key), plain_concrete(s_tex_z * 0.5) ], concrete_mixture_key=concrete_mixture_key) return ccs #-------------------------------------------------------------------------- # Get properties of the composite #-------------------------------------------------------------------------- # E-modulus of the composite at the time of testing E_c = Property(Float, unit='MPa', depends_on='input_change', table_field=True) def _get_E_c(self): return self.ccs.get_E_c_time(self.age) # E-modulus of the composite after 28 days E_c28 = DelegatesTo('ccs', listenable=False) # reinforcement ration of the composite rho_c = DelegatesTo('ccs', listenable=False) #-------------------------------------------------------------------------------- # define processing #-------------------------------------------------------------------------------- # flag distinguishes weather data from a displacement gauge is available # stored in a separate ASC-file with a corresponding file name # flag_ASC_file = Bool(False) def _read_data_array(self): ''' Read the experiment data. ''' if exists(self.data_file): print 'READ FILE' file_split = self.data_file.split('.') # first check if a '.csv' file exists. If yes use the # data stored in the '.csv'-file and ignore # the data in the '.raw' file! # file_name = file_split[0] + '.csv' if not os.path.exists(file_name): file_name = file_split[0] + '.raw' if not os.path.exists(file_name): raise IOError, 'file %s does not exist' % file_name print 'file_name', file_name _data_array = loadtxt_bending(file_name) self.data_array = _data_array # check if a '.ASC'-file exists. If yes append this information # to the data array. # file_name = file_split[0] + '.ASC' if not os.path.exists(file_name): print 'NOTE: no data from displacement gauge is available (no .ASC file)' self.flag_ASC_file = False else: print 'NOTE: additional data from displacement gauge for center deflection is available (.ASC-file loaded)!' self.flag_ASC_file = True # add data array read in from .ASC-file; the values are assigned by '_set_array_attribs' based on the # read in values in 'names_and_units' read in from the corresponding .DAT-file # self.data_array_ASC = loadtxt(file_name, delimiter=';') else: print 'WARNING: data_file with path %s does not exist == False' % ( self.data_file) names_and_units = Property(depends_on='data_file') @cached_property def _get_names_and_units(self): '''names and units corresponding to the returned '_data_array' by 'loadtxt_bending' ''' names = ['w_raw', 'eps_c_raw', 'F_raw'] units = ['mm', '1*E-3', 'N'] print 'names, units from .raw-file', names, units return names, units names_and_units_ASC = Property(depends_on='data_file') @cached_property def _get_names_and_units_ASC(self): ''' Extract the names and units of the measured data. The order of the names in the .DAT-file corresponds to the order of the .ASC-file. ''' file_split = self.data_file.split('.') file_name = file_split[0] + '.DAT' data_file = open(file_name, 'r') lines = data_file.read().split() names = [] units = [] for i in range(len(lines)): if lines[i] == '#BEGINCHANNELHEADER': name = lines[i + 1].split(',')[1] unit = lines[i + 3].split(',')[1] names.append(name) units.append(unit) print 'names, units extracted from .DAT-file', names, units return names, units factor_list_ASC = Property(depends_on='data_file') def _get_factor_list_ASC(self): return self.names_and_units_ASC[0] def _set_array_attribs(self): '''Set the measured data as named attributes defining slices into the processed data array. ''' for i, factor in enumerate(self.factor_list): self.add_trait( factor, Array(value=self.processed_data_array[:, i], transient=True)) if self.flag_ASC_file: for i, factor in enumerate(self.factor_list_ASC): self.add_trait( factor, Array(value=self.data_array_ASC[:, i], transient=True)) elastomer_law = Property(depends_on='input_change') @cached_property def _get_elastomer_law(self): elastomer_path = os.path.join(simdb.exdata_dir, 'bending_tests', 'three_point', '2011-06-10_BT-3PT-12c-6cm-0-TU_ZiE', 'elastomer_f-w.raw') _data_array_elastomer = loadtxt_bending(elastomer_path) # force [kN]: # NOTE: after conversion 'F_elastomer' is a positive value # F_elastomer = -0.001 * _data_array_elastomer[:, 2].flatten() # displacement [mm]: # NOTE: after conversion 'w_elastomer' is a positive value # w_elastomer = -1.0 * _data_array_elastomer[:, 0].flatten() mfn_displacement_elastomer = MFnLineArray(xdata=F_elastomer, ydata=w_elastomer) return frompyfunc(mfn_displacement_elastomer.get_value, 1, 1) w_wo_elast = Property(depends_on='input_change') @cached_property def _get_w_wo_elast(self): # use the machine displacement for the center displacement: # subtract the deformation of the elastomer cushion between the cylinder # and change sign in positive values for vertical displacement [mm] # return self.w_raw - self.elastomer_law(self.F_raw) M_ASC = Property(Array('float_'), depends_on='input_change') @cached_property def _get_M_ASC(self): return self.F_ASC * self.length / 4.0 M_raw = Property(Array('float_'), depends_on='input_change') @cached_property def _get_M_raw(self): return self.F_raw * self.length / 4.0 # # get only the ascending branch of the response curve # # # max_force_idx = Property(Int) # def _get_max_force_idx(self): # '''get the index of the maximum force''' # return argmax(-self.Kraft) # # f_asc = Property(Array) # def _get_f_asc(self): # '''get only the ascending branch of the response curve''' # return -self.Kraft[:self.max_force_idx + 1] K_bending_elast = Property(Array('float_'), depends_on='input_change') @cached_property def _get_K_bending_elast(self): '''calculate the analytical bending stiffness of the beam (3 point bending) ''' t = self.thickness w = self.width L = self.length # coposite E-modulus # E_c = self.E_c # moment of inertia # I_yy = t**3 * w / 12. delta_11 = (L**3) / 48 / E_c / I_yy # [MN/m]=[kN/mm] bending stiffness with respect to a force applied at center of the beam # K_bending_elast = 1 / delta_11 # print 'K_bending_elast', K_bending_elast return K_bending_elast F_cr = Property(Array('float_'), depends_on='input_change') @cached_property def _get_F_cr(self): '''calculate the analytical cracking load of the beam ''' t = self.thickness w = self.width L = self.length # approx. flectural tensile strength # f_cfl = 6. # MPa # resistant moment # W_yy = t**2 * w / 6. # analytical cracking load of the beam # corresponds to l = 0.46m and f_cfl = approx. 8.4 MPa# # F_cr = W_yy * f_cfl * 1000. / L # [kN] return F_cr def process_source_data(self): '''read in the measured data from file and assign attributes after array processing. ''' super(ExpBT3PT, self).process_source_data() #--------------------------------------------- # process data from .raw file (machine data) #--------------------------------------------- # convert machine force [N] to [kN] and return only positive values # self.F_raw *= -0.001 # convert machine displacement [mm] to positive values # and remove offset # self.w_raw *= -1.0 self.w_raw -= self.w_raw[0] # convert [permille] to [-] and return only positive values # self.eps_c_raw *= -0.001 # access the derived arrays to initiate their processing # self.w_wo_elast self.M_raw #--------------------------------------------- # process data from .ASC file (displacement gauge) #--------------------------------------------- # only if separate ASC.-file with force-displacement data from displacement gauge is available # if self.flag_ASC_file == True: self.F_ASC = -1.0 * self.Kraft # remove offset and change sign to return positive displacement values # if hasattr(self, "WA50"): self.WA50 *= -1 self.WA50 -= self.WA50[0] WA50_avg = np.average(self.WA50) if hasattr(self, "W10_u"): self.W10_u *= -1 self.W10_u -= self.W10_u[0] W10_u_avg = np.average(self.W10_u) # check which displacement gauge has been used depending on weather two names are listed in .DAT file or only one # and assign values to 'w_ASC' # if hasattr(self, "W10_u") and hasattr(self, "WA50"): if W10_u_avg > WA50_avg: self.w_ASC = self.W10_u print 'self.W10_u assigned to self.w_ASC' else: self.w_ASC = self.WA50 print 'self.WA50 assigned to self.w_ASC' elif hasattr(self, "W10_u"): self.w_ASC = self.W10_u print 'self.W10_u assigned to self.w_ASC' elif hasattr(self, "WA50"): self.w_ASC = self.WA50 print 'self.WA50 assigned to self.w_ASC' # convert strain from [permille] to [-], # switch to positive values for compressive strains # and remove offset # self.eps_c_ASC = -0.001 * self.DMS_l self.eps_c_ASC -= self.eps_c_ASC[0] # access the derived arrays to initiate their processing # self.M_ASC #-------------------------------------------------------------------------------- # plot templates #-------------------------------------------------------------------------------- plot_templates = { 'force / machine displacement (incl. w_elast)': '_plot_force_machine_displacement', 'force / machine displacement (without w_elast)': '_plot_force_machine_displacement_wo_elast', 'force / machine displacement (without w_elast, interpolated)': '_plot_force_machine_displacement_wo_elast_interpolated', 'force / machine displacement (analytical offset)': '_plot_force_machine_displacement_wo_elast_analytical_offset', 'force / gauge displacement': '_plot_force_gauge_displacement', 'force / gauge displacement (analytical offset)': '_plot_force_gauge_displacement_with_analytical_offset', 'force / gauge displacement (interpolated)': '_plot_force_gauge_displacement_interpolated', # 'smoothed force / gauge displacement' : '_plot_smoothed_force_gauge_displacement', # 'smoothed force / machine displacement' : '_plot_smoothed_force_machine_displacement_wo_elast', # 'moment / eps_c (ASC)': '_plot_moment_eps_c_ASC', 'moment / eps_c (raw)': '_plot_moment_eps_c_raw', # # 'smoothed moment / eps_c (ASC)' : '_plot_smoothed_moment_eps_c_ASC', # 'smoothed moment / eps_c (raw)' : '_plot_smoothed_moment_eps_c_raw', # # 'analytical bending stiffness' : '_plot_analytical_bending_stiffness' } default_plot_template = 'force / deflection (displacement gauge)' def _plot_analytical_bending_stiffness(self, axes, color='red', linewidth=1., linestyle='--'): '''plot the analytical bending stiffness of the beam (3 point bending) ''' t = self.thickness w = self.width L = self.length # composite E-modulus # E_c = self.E_c # moment of inertia # I_yy = t**3 * w / 12. delta_11 = L**3 / 48 / E_c / I_yy K_linear = 1 / delta_11 # [MN/m] bending stiffness with respect to a force applied at center of the beam w_linear = 2 * np.array([0., 1.]) F_linear = 2 * np.array([0., K_linear]) axes.plot(w_linear, F_linear, linestyle='--') def _plot_force_machine_displacement_wo_elast(self, axes, color='blue', linewidth=1., linestyle='-'): # get the index of the maximum stress # max_force_idx = argmax(self.F_raw) # get only the ascending branch of the response curve # f_asc = self.F_raw[:max_force_idx + 1] w_asc = self.w_wo_elast[:max_force_idx + 1] axes.plot(w_asc, f_asc, color=color, linewidth=linewidth, linestyle=linestyle) # plot analytical bending stiffness # w_linear = 2 * np.array([0., 1.]) F_linear = 2 * np.array([0., self.K_bending_elast]) axes.plot(w_linear, F_linear, linestyle='--') # xkey = 'deflection [mm]' # ykey = 'force [kN]' # axes.set_xlabel('%s' % (xkey,)) # axes.set_ylabel('%s' % (ykey,)) def _plot_force_machine_displacement_wo_elast_interpolated( self, axes, color='green', linewidth=1., linestyle='-'): # get the index of the maximum stress # max_force_idx = argmax(self.F_raw) # get only the ascending branch of the response curve # f_asc = self.F_raw[:max_force_idx + 1] w_asc = np.copy(self.w_wo_elast[:max_force_idx + 1]) # interpolate the starting point of the center deflection curve based on the slope of the curve # (remove offset in measured displacement where there is still no force measured) # idx_10 = np.where(f_asc > f_asc[-1] * 0.10)[0][0] idx_8 = np.where(f_asc > f_asc[-1] * 0.08)[0][0] f8 = f_asc[idx_8] f10 = f_asc[idx_10] w8 = w_asc[idx_8] w10 = w_asc[idx_10] m = (f10 - f8) / (w10 - w8) delta_w = f8 / m w0 = w8 - delta_w * 0.9 # print 'w0', w0 f_asc_interpolated = np.hstack([0., f_asc[idx_8:]]) w_asc_interpolated = np.hstack([w0, w_asc[idx_8:]]) # print 'type( w_asc_interpolated )', type(w_asc_interpolated) w_asc_interpolated -= float(w0) axes.plot(w_asc_interpolated, f_asc_interpolated, color=color, linewidth=linewidth, linestyle=linestyle) # fw_arr = np.hstack([f_asc_interpolated[:, None], w_asc_interpolated[:, None]]) # print 'fw_arr.shape', fw_arr.shape # np.savetxt('BT-3PT-12c-6cm-TU_f-w_interpolated.csv', fw_arr, delimiter=';') # plot analytical bending stiffness # w_linear = 2 * np.array([0., 1.]) F_linear = 2 * np.array([0., self.K_bending_elast]) axes.plot(w_linear, F_linear, linestyle='--') def _plot_force_machine_displacement_wo_elast_analytical_offset( self, axes, color='green', linewidth=1., linestyle='-'): # get the index of the maximum stress # max_force_idx = argmax(self.F_raw) # get only the ascending branch of the response curve # f_asc = self.F_raw[:max_force_idx + 1] w_asc = np.copy(self.w_wo_elast[:max_force_idx + 1]) M_asc = f_asc * self.length / 4. eps_c_asc = self.eps_c_raw[:max_force_idx + 1] t = self.thickness w = self.width # coposite E-modulus # E_c = self.E_c # resistant moment # W_yy = t**2 * w / 6. K_I_analytic = W_yy * E_c # [MN/m] bending stiffness with respect to center moment K_I_analytic *= 1000. # [kN/m] bending stiffness with respect to center moment # interpolate the starting point of the center deflection curve based on the slope of the curve # (remove offset in measured displacement where there is still no force measured) # idx_lin = np.where(M_asc <= K_I_analytic * eps_c_asc)[0][0] idx_lin = int(idx_lin * 0.7) # idx_lin = 50 # idx_lin = np.where(M_asc - M_asc[0] / eps_c_asc <= 0.90 * K_I_analytic)[0][0] print 'idx_lin', idx_lin print 'F_asc[idx_lin]', f_asc[idx_lin] print 'M_asc[idx_lin]', M_asc[idx_lin] print 'w_asc[idx_lin]', w_asc[idx_lin] w_lin_epsc = w_asc[idx_lin] w_lin_analytic = f_asc[idx_lin] / self.K_bending_elast f_asc_offset_analytic = f_asc[idx_lin:] w_asc_offset_analytic = w_asc[idx_lin:] w_asc_offset_analytic -= np.array([w_lin_epsc]) w_asc_offset_analytic += np.array([w_lin_analytic]) axes.plot(w_asc_offset_analytic, f_asc_offset_analytic, color=color, linewidth=linewidth, linestyle=linestyle) # plot analytical bending stiffness # w_linear = 2 * np.array([0., 1.]) F_linear = 2 * np.array([0., self.K_bending_elast]) axes.plot(w_linear, F_linear, linestyle='--') def _plot_force_machine_displacement(self, axes, color='black', linewidth=1., linestyle='-'): xdata = self.w_raw ydata = self.F_raw axes.plot(xdata, ydata, color=color, linewidth=linewidth, linestyle=linestyle) # xkey = 'deflection [mm]' # ykey = 'force [kN]' # axes.set_xlabel('%s' % (xkey,)) # axes.set_ylabel('%s' % (ykey,)) # plot analytical bending stiffness # w_linear = 2 * np.array([0., 1.]) F_linear = 2 * np.array([0., self.K_bending_elast]) axes.plot(w_linear, F_linear, linestyle='--') def _plot_force_gauge_displacement_with_analytical_offset( self, axes, color='black', linewidth=1., linestyle='-'): # skip the first values (= first seconds of testing) # and start with the analytical bending stiffness instead to avoid artificial offset of F-w-diagram # # w_max = np.max(self.w_ASC) # cut_idx = np.where(self.w_ASC > 0.001 * w_max)[0] cut_idx = np.where(self.w_ASC > 0.01)[0] print 'F_cr ', self.F_cr # cut_idx = np.where(self.F_ASC > 0.6 * self.F_cr)[0] print 'cut_idx', cut_idx[0] print 'w_ASC[cut_idx[0]]', self.w_ASC[cut_idx[0]] xdata = np.copy(self.w_ASC[cut_idx]) ydata = np.copy(self.F_ASC[cut_idx]) # specify offset if force does not start at the origin with value 0. F_0 = ydata[0] print 'F_0 ', F_0 offset_w = F_0 / self.K_bending_elast xdata -= xdata[0] xdata += offset_w f_asc_interpolated = np.hstack([0, ydata]) w_asc_interpolated = np.hstack([0, xdata]) # fw_arr = np.hstack([f_asc_interpolated[:, None], w_asc_interpolated[:, None]]) # print 'fw_arr.shape', fw_arr.shape # np.savetxt('BT-3PT-6c-2cm-TU_f-w_interpolated.csv', fw_arr, delimiter=';') xdata = self.w_raw ydata = self.F_raw axes.plot(xdata, ydata, color='blue', linewidth=linewidth, linestyle=linestyle) axes.plot(w_asc_interpolated, f_asc_interpolated, color=color, linewidth=linewidth, linestyle=linestyle) # xkey = 'deflection [mm]' # ykey = 'force [kN]' # axes.set_xlabel('%s' % (xkey,)) # axes.set_ylabel('%s' % (ykey,)) # plot analytical bending stiffness # w_linear = 2 * np.array([0., 1.]) F_linear = 2 * np.array([0., self.K_bending_elast]) axes.plot(w_linear, F_linear, linestyle='--') def _plot_force_gauge_displacement(self, axes, offset_w=0., color='black', linewidth=1., linestyle='-'): xdata = self.w_ASC ydata = self.F_ASC # specify offset if force does not start at the origin xdata += offset_w axes.plot(xdata, ydata, color=color, linewidth=linewidth, linestyle=linestyle) # xkey = 'deflection [mm]' # ykey = 'force [kN]' # axes.set_xlabel('%s' % (xkey,)) # axes.set_ylabel('%s' % (ykey,)) # fw_arr = np.hstack([xdata[:, None], ydata[:, None]]) # print 'fw_arr.shape', fw_arr.shape # np.savetxt('BT-3PT-6c-2cm-TU-80cm-V3_f-w_asc.csv', fw_arr, delimiter=';') # plot analytical bending stiffness # w_linear = 2 * np.array([0., 1.]) F_linear = 2 * np.array([0., self.K_bending_elast]) axes.plot(w_linear, F_linear, linestyle='--') def _plot_smoothed_force_gauge_displacement(self, axes): # get the index of the maximum stress # max_force_idx = argmax(self.F_ASC) # get only the ascending branch of the response curve # F_asc = self.F_ASC[:max_force_idx + 1] w_asc = self.w_ASC[:max_force_idx + 1] n_points = int(self.n_fit_window_fraction * len(w_asc)) F_smooth = smooth(F_asc, n_points, 'flat') w_smooth = smooth(w_asc, n_points, 'flat') axes.plot(w_smooth, F_smooth, color='blue', linewidth=2) def _plot_force_gauge_displacement_interpolated(self, axes, color='green', linewidth=1., linestyle='-'): '''get only the ascending branch of the meassured load-displacement curve)''' # get the index of the maximum stress # max_force_idx = argmax(self.F_ASC) # get only the ascending branch of the response curve # f_asc = self.F_ASC[:max_force_idx + 1] w_asc = self.w_ASC[:max_force_idx + 1] # interpolate the starting point of the center deflection curve based on the slope of the curve # (remove offset in measured displacement where there is still no force measured) # idx_10 = np.where(f_asc > f_asc[-1] * 0.10)[0][0] idx_8 = np.where(f_asc > f_asc[-1] * 0.08)[0][0] f8 = f_asc[idx_8] f10 = f_asc[idx_10] w8 = w_asc[idx_8] w10 = w_asc[idx_10] m = (f10 - f8) / (w10 - w8) delta_w = f8 / m w0 = w8 - delta_w * 0.9 print 'w0', w0 f_asc_interpolated = np.hstack([0., f_asc[idx_8:]]) w_asc_interpolated = np.hstack([w0, w_asc[idx_8:]]) print 'type( w_asc_interpolated )', type(w_asc_interpolated) w_asc_interpolated -= float(w0) # w_offset = f_asc[idx_10] / self.K_bending_elast # f_asc_interpolated = np.hstack([0., f_asc[ idx_10: ]]) # w_asc_interpolated = np.hstack([0, w_asc[ idx_10: ] - w_asc[idx_10] + w_offset]) axes.plot(w_asc_interpolated, f_asc_interpolated, color=color, linewidth=linewidth, linestyle=linestyle) # plot analytical bending stiffness # w_linear = 2 * np.array([0., 1.]) F_linear = 2 * np.array([0., self.K_bending_elast]) axes.plot(w_linear, F_linear, linestyle='--') def _plot_smoothed_force_machine_displacement_wo_elast(self, axes): # get the index of the maximum stress # max_force_idx = argmax(self.F_raw) # get only the ascending branch of the response curve # F_asc = self.F_raw[:max_force_idx + 1] w_asc = self.w_wo_elast[:max_force_idx + 1] n_points = int(self.n_fit_window_fraction * len(w_asc)) F_smooth = smooth(F_asc, n_points, 'flat') w_smooth = smooth(w_asc, n_points, 'flat') axes.plot(w_smooth, F_smooth, color='blue', linewidth=2) # plot analytical bending stiffness # w_linear = 2 * np.array([0., 1.]) F_linear = 2 * np.array([0., self.K_bending_elast]) axes.plot(w_linear, F_linear, linestyle='--') # secant_stiffness_w10 = ( f_smooth[10] - f_smooth[0] ) / ( w_smooth[10] - w_smooth[0] ) # w0_lin = array( [0.0, w_smooth[10] ], dtype = 'float_' ) # f0_lin = array( [0.0, w_smooth[10] * secant_stiffness_w10 ], dtype = 'float_' ) # axes.plot( w0_lin, f0_lin, color = 'black' ) def _plot_moment_eps_c_ASC(self, axes): xkey = 'compressive strain [1*E-3]' ykey = 'moment [kNm]' xdata = self.eps_c_ASC ydata = self.M_ASC axes.set_xlabel('%s' % (xkey, )) axes.set_ylabel('%s' % (ykey, )) axes.plot(xdata, ydata) # plot stiffness in uncracked state t = self.thickness w = self.width # composite E-modulus # E_c = self.E_c # resistant moment # W_yy = t**2 * w / 6. max_M = np.max(self.M_raw) K_linear = W_yy * E_c # [MN/m] bending stiffness with respect to center moment K_linear *= 1000. # [kN/m] bending stiffness with respect to center moment w_linear = np.array([0., max_M / K_linear]) M_linear = np.array([0., max_M]) axes.plot(w_linear, M_linear, linestyle='--') def _plot_moment_eps_c_raw(self, axes, color='black', linewidth=1.5, linestyle='-'): xkey = 'compressive strain [1*E-3]' ykey = 'moment [kNm]' xdata = self.eps_c_raw ydata = self.M_raw axes.set_xlabel('%s' % (xkey, )) axes.set_ylabel('%s' % (ykey, )) axes.plot(xdata, ydata, color=color, linewidth=linewidth, linestyle=linestyle) # plot stiffness in uncracked state t = self.thickness w = self.width # composite E-modulus # E_c = self.E_c # resistant moment # W_yy = t**2 * w / 6. max_M = np.max(self.M_raw) K_linear = W_yy * E_c # [MN/m] bending stiffness with respect to center moment K_linear *= 1000. # [kN/m] bending stiffness with respect to center moment w_linear = np.array([0., max_M / K_linear]) M_linear = np.array([0., max_M]) axes.plot(w_linear, M_linear, linestyle='--') n_fit_window_fraction = Float(0.1) smoothed_M_eps_c_ASC = Property(depends_on='input_change') @cached_property def _get_smoothed_M_eps_c_ASC(self): # get the index of the maximum stress max_idx = argmax(self.M_ASC) # get only the ascending branch of the response curve m_asc = self.M_ASC[:max_idx + 1] eps_c_asc = self.eps_c_ASC[:max_idx + 1] n_points = int(self.n_fit_window_fraction * len(eps_c_asc)) m_smoothed = smooth(m_asc, n_points, 'flat') eps_c_smoothed = smooth(eps_c_asc, n_points, 'flat') return m_smoothed, eps_c_smoothed smoothed_eps_c_ASC = Property def _get_smoothed_eps_c_ASC(self): return self.smoothed_M_eps_c_ASC[1] smoothed_M_ASC = Property def _get_smoothed_M_ASC(self): return self.smoothed_M_eps_c_ASC[0] def _plot_smoothed_moment_eps_c_ASC(self, axes): axes.plot(self.smoothed_eps_c_ASC, self.smoothed_M_ASC, color='blue', linewidth=2) smoothed_M_eps_c_raw = Property(depends_on='input_change') @cached_property def _get_smoothed_M_eps_c_raw(self): # get the index of the maximum stress max_idx = argmax(self.M_raw) # get only the ascending branch of the response curve m_asc = self.M_raw[:max_idx + 1] eps_c_asc = self.eps_c_raw[:max_idx + 1] n_points = int(self.n_fit_window_fraction * len(eps_c_asc)) m_smoothed = smooth(m_asc, n_points, 'flat') eps_c_smoothed = smooth(eps_c_asc, n_points, 'flat') return m_smoothed, eps_c_smoothed smoothed_eps_c_raw = Property def _get_smoothed_eps_c_raw(self): return self.smoothed_M_eps_c_raw[1] smoothed_M_raw = Property def _get_smoothed_M_raw(self): return self.smoothed_M_eps_c_raw[0] def _plot_smoothed_moment_eps_c_raw(self, axes): axes.plot(self.smoothed_eps_c_raw, self.smoothed_M_raw, color='blue', linewidth=2) #-------------------------------------------------------------------------------- # view #-------------------------------------------------------------------------------- traits_view = View(VGroup( Group(Item('length', format_str="%.3f"), Item('width', format_str="%.3f"), Item('thickness', format_str="%.3f"), label='geometry'), Group(Item('loading_rate'), Item('age'), label='loading rate and age'), Group(Item('E_c', show_label=True, style='readonly', format_str="%.0f"), Item('ccs@', show_label=False), label='composite cross section')), scrollable=True, resizable=True, height=0.8, width=0.6)
class MFnLineArray(HasTraits): # Public Traits xdata = Array(float, value = [0.0, 1.0]) def _xdata_default(self): ''' convenience default - when xdata not defined created automatically as an array of integers with the same shape as ydata ''' return np.arange(self.ydata.shape[0]) ydata = Array(float, value = [0.0, 1.0]) extrapolate = Enum('constant', 'exception', 'diff', 'zero') # alternative vectorized interpolation using scipy.interpolate def get_values(self, x, k = 1): ''' vectorized interpolation, k is the spline order, default set to 1 (linear) ''' tck = ip.splrep(self.xdata, self.ydata, s = 0, k = k) x = np.array([x]).flatten() if self.extrapolate == 'diff': values = ip.splev(x, tck, der = 0) elif self.extrapolate == 'exception': if x.all() < self.xdata[0] and x.all() > self.xdata[-1]: values = values = ip.splev(x, tck, der = 0) else: raise ValueError('value(s) outside interpolation range') elif self.extrapolate == 'constant': mask = x >= self.xdata[0] mask *= x <= self.xdata[-1] l_mask = x < self.xdata[0] r_mask = x > self.xdata[-1] extrapol_left = np.repeat(ip.splev(self.xdata[0], tck, der = 0), len(x)) * l_mask extrapol_right = np.repeat(ip.splev(self.xdata[-1], tck, der = 0), len(x)) * r_mask extrapol = extrapol_left + extrapol_right values = ip.splev(x, tck, der = 0) * mask + extrapol elif self.extrapolate == 'zero': mask = x >= self.xdata[0] mask *= x <= self.xdata[-1] mask_extrapol = mask == False extrapol = np.zeros(len(x)) * mask_extrapol values = ip.splev(x, tck, der = 0) * mask + extrapol return values def get_value(self, x): x2idx = self.xdata.searchsorted(x) if x2idx == len(self.xdata): x2idx -= 1 x1idx = x2idx - 1 x1 = self.xdata[ x1idx ] x2 = self.xdata[ x2idx ] dx = x2 - x1 y1 = self.ydata[ x1idx ] y2 = self.ydata[ x2idx ] dy = y2 - y1 y = y1 + dy / dx * (x - x1) return y data_changed = Event def get_diffs(self, x, k = 1, der = 1): ''' vectorized interpolation, der is the nth derivative, default set to 1; k is the spline order of the data inetrpolation, default set to 1 (linear) ''' xdata = np.sort(np.hstack((self.xdata, x))) idx = np.argwhere(np.diff(xdata) == 0).flatten() xdata = np.delete(xdata, idx) tck = ip.splrep(xdata, self.get_values(xdata, k = k), s = 0, k = k) return ip.splev(x, tck, der = der) def get_diff(self, x): x2idx = self.xdata.searchsorted(x) if x2idx == len(self.xdata): x2idx -= 1 x1idx = x2idx - 1 x1 = self.xdata[ x1idx ] x2 = self.xdata[ x2idx ] dx = x2 - x1 y1 = self.ydata[ x1idx ] y2 = self.ydata[ x2idx ] dy = y2 - y1 return dy / dx dump_button = ToolbarButton('Print data', style = 'toolbar') @on_trait_change('dump_button') def print_data(self, event = None): print 'x = ', repr(self.xdata) print 'y = ', repr(self.ydata) integ_value = Property(Float(), depends_on = 'ydata') @cached_property def _get_integ_value(self): _xdata = self.xdata _ydata = self.ydata # integral under the stress strain curve E_t = np.trapz(_ydata, _xdata) # area of the stored elastic energy U_t = 0.0 if len(_xdata) != 0: U_t = 0.5 * _ydata[-1] * _xdata[-1] return E_t - U_t def clear(self): self.xdata = np.array([]) self.ydata = np.array([]) def plot(self, axes, *args, **kw): self.mpl_plot(axes, *args, **kw) def mpl_plot(self, axes, *args, **kw): '''plot within matplotlib window''' axes.plot(self.xdata, self.ydata, *args, **kw)
class RandomVariable( HasTraits ): '''Class representing the definition and discretization of a random variable. ''' trait_value = Float source_trait = CTrait # name of the parameter name = Str pd = Instance( IPDistrib ) def _pd_changed( self ): self.pd.n_segments = self._n_int changed = Event @on_trait_change( 'pd.changed,+changed' ) def _set_changed( self ): self.changed = True # Switch the parameter random random = Bool( False, changed = True ) def set_random( self, distribution = 'uniform', discr_type = 'T grid', loc = 0., scale = 1., shape = 1., n_int = 30 ): possible_distr = self.source_trait.distr if distribution and distribution not in possible_distr: raise AssertionError, 'distribution type %s not allowed for parameter %s' \ % ( distribution, self.name ) self.pd = PDistrib( distr_choice = distribution, n_segments = n_int ) self.pd.distr_type.set( scale = scale, shape = shape, loc = loc ) self.n_int = n_int self.discr_type = discr_type self.random = True def unset_random( self ): self.random = False # Number of integration points (relevant only for grid based methods) _n_int = Int n_int = Property def _set_n_int( self, value ): if self.pd: self.pd.n_segments = value self._n_int = value def _get_n_int( self ): return self.pd.n_segments # type of the RandomVariable discretization discr_type = Enum( 'T grid', 'P grid', 'MC', changed = True ) def _discr_type_default( self ): return 'T grid' theta_arr = Property( Array( 'float_' ), depends_on = 'changed' ) @cached_property def _get_theta_arr( self ): '''Get the discr_type of the pdistrib ''' if not self.random: return array( [ self.trait_value ], dtype = float ) if self.discr_type == 'T grid': # Get the discr_type from pdistrib and shift it # such that the midpoints of the segments are used for the # integration. x_array = self.pd.x_array # Note assumption of T grid discr_type theta_array = x_array[:-1] + self.pd.dx / 2.0 elif self.discr_type == 'P grid': # P grid disretization generated from the inverse cummulative # probability # distr = self.pd.distr_type.distr # Grid of constant probabilities pi_arr = linspace( 0.5 / self.n_int, 1. - 0.5 / self.n_int, self.n_int ) theta_array = distr.ppf( pi_arr ) return theta_array dG_arr = Property( Array( 'float_' ), depends_on = 'changed' ) @cached_property def _get_dG_arr( self ): if not self.random: return array( [ 1.0 ], dtype = float ) if self.discr_type == 'T grid': d_theta = self.theta_arr[1] - self.theta_arr[0] return self.pd.get_pdf_array( self.theta_arr ) * d_theta elif self.discr_type == 'P grid': # P grid disretization generated from the inverse cummulative # probability # return array( [ 1.0 / float( self.n_int ) ], dtype = 'float_' ) def get_rvs_theta_arr( self, n_samples ): if self.random: return self.pd.get_rvs_array( n_samples ) else: return array( [self.trait_value], float )
class HPShell(HasTraits): '''Geometry definition. ''' # dimensions of the shell structure [m] # (only one quart of the shell structure) # # NOTE: lenth_z = 1.0 m + 0.062 m = 1.062 # NOTE: lenth_z = 0.865 m + 0.062 m = 0.927 length_x = Float(3.50) length_y = Float(3.50) length_z = Float(0.927) # corresponds to the delta in the geometry obj file '4x4m' delta_h = Float(0.865) # [m] # factor to scale height of lower surface # thickness remains unchanged as 0.06 m # delta_h_scalefactor = Float(1.00) # [-] # cut of the z-coordinates of the lowerface if set to True # cut_off_lowerface = Bool(True) geo_input_name = Enum('350x350cm') geo_filter = Dict({'4x4m': delete_second_rows}) def _read_arr(self, side='lowerface_'): file_name = side + self.geo_input_name + '.robj' file_path = join('geometry_files', file_name) v_arr = read_rsurface(file_path) filter = self.geo_filter.get(self.geo_input_name, None) if filter != None: v_arr = filter(v_arr) 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)) @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 1 m (=delta h). At this limit the lower face is # cut off. Global z coordinate is assumed to point up. # 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 - self.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)) @cached_property def _get_vu_arr(self): return self._read_arr('upperface_') def get_mid_surface_and_thickness(self, points, perpendicular_t=True): '''Return the global coordinates of the supplied local points. ''' print '*** get mid surface and thickness ***' #----------------------------------------------- # get the global coordinates as defined in the # input file and transform them to the coordinate # system of the master quarter #----------------------------------------------- # if self.geo_input_name == '350x350cm': X0 = [3.50, 3.50, 0.] else: X0 = [0., 0., 0.] # number of global grid points for each coordinate direction # xi, yi = points[:, 0] - X0[0], points[:, 1] - X0[1] # NOTE: # -- The available rbf-function is only defined for a quarter of one shell. # in order to get z and t values for an entire shell the abs-function # is used. The coordinate system of the quarter must be defined in the # lower left corner; the coordinate systemn of the entire one shell must # be defined in the center of the shell so that the coordinate system # for the master quarter remains unchanged. # -- The transformation is performed based on the defined class attributes # of hp_shell_stb: length_x, length_y, length_z, delta_h, delta_h_scalefactor # characterizing the properties of the master quarter # number of local grid points for each coordinate direction # values must range between 0 and 1 # points_tilde_list = [] for i_row in range(points.shape[0]): # get the x, y coordinate pair defined in the input # file in global coordinates # x = xi[i_row] y = yi[i_row] # transform values to local coordinate system, # i.e. move point to the 'master roof' containing the # global coordinate system: # if x <= self.length_x and y <= self.length_y: # point lays in first (master) roof # x_tilde = x y_tilde = y elif x >= self.length_x and y <= self.length_y: # point lays in second roof: # # roof length = 2* length of the master quarter # (e.g. 2*4,0m = 8,00m for obj-file "4x4m") x_tilde = x - 2 * self.length_x y_tilde = y elif x <= self.length_x and y >= self.length_y: # point lays in third roof: # x_tilde = x y_tilde = y - 2 * self.length_y elif x >= self.length_x and y >= self.length_y: # point lays in fourth roof: # x_tilde = x - 2 * self.length_x y_tilde = y - 2 * self.length_y points_tilde_list.append([x_tilde, y_tilde]) points_tilde_arr = array(points_tilde_list, dtype='float_') xi_tilde = points_tilde_arr[:, 0] yi_tilde = points_tilde_arr[:, 1] # print 'points_tilde_arr', points_tilde_arr xi_ = abs(xi_tilde) / self.length_x yi_ = abs(yi_tilde) / self.length_y #----------------------------------------------- # get the normalized rbf-function for the upper # and lower face of the master quarter #----------------------------------------------- # NOTE: the underline character indicates a normalized value # normalized coordinates of the vertices for lower- and upper-face # vl_arr_, vu_arr_ = normalize_rsurfaces(self.vl_arr, self.vu_arr) # use a radial basis function approximation (rbf) (i.e. interpolation of # scattered data) based on the normalized vertex points of the lower face # x_ = vl_arr_[:, 0] y_ = vl_arr_[:, 1] if self.geo_input_name == '350x350cm': x_ = 1 - vl_arr_[:, 0] z_l_ = vl_arr_[:, 2] rbf_l = Rbf(x_, y_, z_l_, function='cubic') # get the z-value at the supplied local grid points # of the lower face # zi_lower_ = rbf_l(xi_, yi_) # use a radial basis function approximation (rbf) (i.e. interpolation of # scattered data) based on the normalized vertex points of the upper face # x_ = vu_arr_[:, 0] y_ = vu_arr_[:, 1] if self.geo_input_name == '350x350cm': x_ = 1 - vu_arr_[:, 0] z_u_ = vu_arr_[:, 2] rbf_u = Rbf(x_, y_, z_u_, function='cubic') # get the z-value at the supplied local grid points # of the upper face # zi_upper_ = rbf_u(xi_, yi_) # approach of the slope to get thickness perpendicular to slope # # thickness is multiplied by the supplied zi coordinate # and z value of mid plane # t_ = zi_upper_ - zi_lower_ z_middle_ = (zi_lower_ + (zi_upper_ - zi_lower_) * 0.5 / self.delta_h_scalefactor) * self.delta_h_scalefactor if perpendicular_t == True: # delta shift of x and y for estimation of slope will be done in 4 direction # 0, 45, 90 and 135 degrees print "--- perpendicular ---" delta = 0.000001 # shift in x dz_x_p_ = (rbf_u(xi_ + delta, yi_) + rbf_l(xi_ + delta, yi_)) / 2.0 dz_x_m_ = (rbf_u(xi_ - delta, yi_) + rbf_l(xi_ - delta, yi_)) / 2.0 slope_x_ = (dz_x_p_ - dz_x_m_) / (2.0 * delta) angle_x = arctan(slope_x_ * self.length_z / self.length_x) f_1 = cos(angle_x) # shift in y dz_y_p_ = (rbf_u(xi_, yi_ + delta) + rbf_l(xi_, yi_ + delta)) / 2.0 dz_y_m_ = (rbf_u(xi_, yi_ - delta) + rbf_l(xi_, yi_ - delta)) / 2.0 slope_y_ = (dz_y_p_ - dz_y_m_) / (2.0 * delta) angle_y = arctan(slope_y_ * self.length_z / self.length_x) f_2 = cos(angle_y) #shift +x +y; -x -y dz_x_p_y_p_ = (rbf_u(xi_ + delta, yi_ + delta) + rbf_l(xi_ + delta, yi_ + delta)) / 2.0 dz_x_m_y_m_ = (rbf_u(xi_ - delta, yi_ - delta) + rbf_l(xi_ - delta, yi_ - delta)) / 2.0 slope_x_p_y_p_ = (dz_x_p_y_p_ - dz_x_m_y_m_) / (2.0 * sqrt(2) * delta) angle_x_p_y_p = arctan(slope_x_p_y_p_ * self.length_z / (self.length_x**2 + self.length_y**2)**0.5) f_3 = cos(angle_x_p_y_p) # shift in +x,-y ; -x and +y dz_x_p_y_m_ = (rbf_u(xi_ + delta, yi_ - delta) + rbf_l(xi_ + delta, yi_ - delta)) / 2.0 dz_x_m_y_p_ = (rbf_u(xi_ - delta, yi_ + delta) + rbf_l(xi_ - delta, yi_ + delta)) / 2.0 slope_x_p_y_m_ = (dz_x_p_y_m_ - dz_x_m_y_p_) / (sqrt(2) * 2.0 * delta) angle_x_p_y_m = arctan(slope_x_p_y_m_ * self.length_z / (self.length_x**2 + self.length_y**2)**0.5) f_4 = cos(angle_x_p_y_m) # obtain minimum factor for good estimate of maximum slope factor = min([f_1, f_2, f_3, f_4], axis=0) t_ = t_ * factor return xi, yi, z_middle_ * self.length_z, t_ * self.length_z def _read_thickness_data(self, file_name): '''to read the stb - X and Y coordinates ( m ) save the xls - worksheet to a csv - file using ';' as filed delimiter and ' ' ( blank ) as text delimiter. Stb Data needs to have same range of values in X and Y direction and same unit [m], as defined as length_x and length_y ''' print '*** reading thickness data from file: ', file_name, ' ***' # get the column headings defined in the second row # of the csv thickness input file # "Nr.;X;Y;Z;[mm]" # file = open(file_name, 'r') lines = file.readlines() column_headings = array(lines[1].split(';')) elem_no_idx = where('Nr.' == column_headings)[0] X_idx = where('X' == column_headings)[0] Y_idx = where('Y' == column_headings)[0] Z_idx = where('Z' == column_headings)[0] thickness_idx = where('[mm]\n' == column_headings)[0] input_arr = loadtxt(file_name, delimiter=';', skiprows=2) # elem number: # elem_no = input_arr[:, elem_no_idx] # coordinates [m]: # X = input_arr[:, X_idx][:, 0] Y = input_arr[:, Y_idx][:, 0] # print 'thickness_idx', thickness_idx if thickness_idx != []: thickness_stb = input_arr[:, thickness_idx][:, 0] / 1000. return elem_no, X, Y, thickness_stb else: thickness_stb = ones_like(elem_no) return elem_no, X, Y, thickness_stb def _read_elem_coords(self, file_name): '''x,y -coordinates must be read from old file ''' input_arr = loadtxt(file_name, delimiter=';', skiprows=2) elem_no = input_arr[:, 0] X = input_arr[:, 2] Y = input_arr[:, 3] return elem_no, X, Y def _read_nodal_coords(self, file_name): '''read the nodal coordinates of the mid - surface defined in a csv - file. To export the excel sheet to csv use ";" as a field delimiter and "" ( none ) as a text delimiter. Note that some lines do not contain values ! ''' print '*** reading nodal coordinates from file: ', file_name, ' ***' file = open(file_name, 'r') # read the column headings (first two lines) # first_line = file.readline() second_line = file.readline() column_headings = second_line.split(';') # remove '\n' from last string element in list column_headings[-1] = column_headings[-1][:-1] column_headings_arr = array(column_headings) # check in which column the node number and the # carthesian coordinates can be found # elem_no_idx = where('Nr.' == column_headings_arr)[0] X_idx = where('X [m]' == column_headings_arr)[0] Y_idx = where('Y [m]' == column_headings_arr)[0] Z_idx = where('Z [m]' == column_headings_arr)[0] lines = file.readlines() lines_list = [line.split(';') for line in lines] empty_lines_idx = [] ll = [] for i_line, line in enumerate(lines_list): # check if line contains values or only a node number! # if line[1] == 'Standard': ll.append( [line[elem_no_idx], line[X_idx], line[Y_idx], line[Z_idx]]) else: # NOTE: current number in file starts with 1, index in loop starts with 0 # therefore add 1 in the index list # empty_lines_idx.append(i_line + 1) input_arr = array(ll, dtype='float_') node_no = input_arr[:, 0] X = input_arr[:, 1] Y = input_arr[:, 2] Z = input_arr[:, 2] return node_no, X, Y, Z, empty_lines_idx def compare_thickness_values(self, thickness, thickness_stb): '''get relative difference between the calucated thickness read in from the obj file, cut of and projected with respect to the approximated data given from stb. ''' thickness = thickness.reshape(shape(thickness_stb)) error = abs(1 - thickness / thickness_stb) * 100 return error def export_midsurface_data(self, node_no, x, y, z_middle, file_name, empty_lines_idx): '''exports data to csv - worksheet ''' print '*** writing middle surface data to file,', file_name, ' ***' data = c_[node_no, x, y, z_middle] file = open(file_name, 'w') writer = csv.writer(file, delimiter=";", lineterminator="\n") writer.writerow(['node_number', 'x[m]', 'y[m]', 'z[m]']) writer.writerows(data) file = file.close() # if file contains empty lines add them at the positions # defined in 'empty_lines_idx' # if len(empty_lines_idx) != 0: print '--- file contains ', len( empty_lines_idx), ' empty_lines ---' # file without empty lines # file = open(file_name, 'r') lines = file.readlines() # overwrite file including empty lines # file = open(file_name, 'w') # index 'n' runs in the array without empty lines # index 'i' runs in the array with empty lines # n = 0 for i in range(data.shape[0] + len(empty_lines_idx)): if i in empty_lines_idx: file.writelines(str(i) + ";;;;\n") else: file.writelines(lines[n]) n += 1 # add last line: # file.writelines(lines[-1]) file.close() print '--- empty lines added to file ---' return def export_thickness_data(self, elem_no, x, y, t, file_name): '''exports data to csv - worksheet ''' print '*** writing thickness data to file,', file_name, ' ***' data = c_[elem_no, x, y, t * 1000] print shape(data) writer = csv.writer(open(file_name, 'w'), delimiter=";", lineterminator="\n") writer.writerow(['element_number', 'x[m]', 'y[m]', 't[mm]']) writer.writerows(data) return @show def show(self, x, y, z_middle, displayed_value): """Test contour_surf on regularly spaced co-ordinates like MayaVi. """ print '*** plotting data***' s = points3d(X, Y, z_middle, displayed_value, colormap="gist_rainbow", mode="cube", scale_factor=0.3) sb = colorbar(s) # Recorded script from Mayavi2 #try: # engine = mayavi.engine #except NameError: # from etsproxy.mayavi.api import Engine # engine = Engine() # engine.start() #if len(engine.scenes) == 0: # engine.new_scene() # ------------------------------------------- glyph = s #.pipeline.scenes[0].children[0].children[0].children[0] glyph.glyph.glyph_source.glyph_source.center = array([0., 0., 0.]) glyph.glyph.glyph_source.glyph_source.progress = 1.0 glyph.glyph.glyph_source.glyph_source.x_length = 0.6 glyph.glyph.glyph_source.glyph_source.y_length = 0.6 sb.scalar_bar.title = 'thickness [m]' #print s.pipeline #s.scene.background = (1.0, 1.0, 1.0) return s
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 RandomField(HasTraits): ''' This class implements a 3D random field on a regular grid and allows for interpolation using the EOLE method ''' lacor_arr = Array(Float, modified=True) #(nD,1) array of autocorrelation lengths nDgrid = List(Array, modified=True) # list of nD entries: each entry is an array of points in the part. dimension reevaluate = Event seed = Bool(False) distr_type = Enum('Gauss', 'Weibull', modified=True) stdev = Float(1.0, modified=True) mean = Float(0.0, modified=True) shape = Float(5.0, modified=True) scale = Float(1.0, modified=True) loc = Float(0.0, modified=True) def acor(self, dx, lacor): '''autocorrelation function''' C = e ** (-(dx / lacor) ** 2) return C eigenvalues = Property(depends_on='+modified') @cached_property def _get_eigenvalues(self): '''evaluates the eigenvalues and eigenvectors of the covariance matrix''' # creating distances from the first coordinate for i, grid_i in enumerate(self.nDgrid): self.nDgrid[i] -= grid_i[0] # creating a symm. toeplitz matrix with (xgrid, xgrid) data points coords_lst = [toeplitz(grid_i) for grid_i in self.nDgrid] # apply the autocorrelation func. on the coord matrices to obtain the covariance matrices C_matrices = [self.acor(coords_i, self.lacor_arr[i]) for i, coords_i in enumerate(coords_lst)] # evaluate the eigenvalues and eigenvectors of the autocorrelation matrices eigen_lst = [] for i, C_i in enumerate(C_matrices): print 'evaluating eigenvalues for dimension ' + str(i+1) lambda_i, Phi_i = eigh(C_i) # truncate the eigenvalues at 99% of tr(C) truncation_limit = 0.99 * np.trace(C_i) argsort = np.argsort(lambda_i) cum_sum_lambda = np.cumsum(np.sort(lambda_i)[::-1]) idx_trunc = int(np.sum(cum_sum_lambda < truncation_limit)) eigen_lst.append([lambda_i[argsort[::-1]][:idx_trunc], Phi_i[:, argsort[::-1]][:,:idx_trunc]]) print 'complete' Lambda_C = 1.0 Phi_C = 1.0 for lambda_i, Phi_i in eigen_lst: Lambda_i = np.diag(lambda_i) Lambda_C = np.kron(Lambda_C, Lambda_i) Phi_C = np.kron(Phi_C, Phi_i) return Lambda_C, Phi_C generated_random_vector = Property(Array, depends_on='reevaluate') @cached_property def _get_generated_random_vector(self): if self.seed == True: np.random.seed(141) # points between 0 to 1 with an equidistant step for the LHS # No. of points = No. of truncated eigenvalues npts = self.eigenvalues[0].shape[0] randsim = np.linspace(0.5/npts, 1 - 0.5/npts, npts) # shuffling points for the simulation np.random.shuffle(randsim) # matrix containing standard Gauss distributed random numbers xi = norm().ppf(randsim) return xi random_field = Property(Array, depends_on='+modified') @cached_property def _get_random_field(self): '''simulates the Gaussian random field''' # evaluate the eigenvalues and eigenvectors of the autocorrelation matrix Lambda_C_sorted, Phi_C_sorted = self.eigenvalues # generate the RF with standardized Gaussian distribution ydata = np.dot(np.dot(Phi_C_sorted, (Lambda_C_sorted) ** 0.5), self.generated_random_vector) # transform the standardized Gaussian distribution if self.distr_type == 'Gauss': # scaling the std. distribution scaled_ydata = ydata * self.stdev + self.mean elif self.distr_type == 'Weibull': # setting Weibull params Pf = norm().cdf(ydata) scaled_ydata = weibull_min(self.shape, scale=self.scale, loc=self.loc).ppf(Pf) shape = tuple([len(grid_i) for grid_i in self.nDgrid]) rf = np.reshape(scaled_ydata, shape) return rf def interpolate_rf(self, coords): '''interpolate RF values using the EOLE method coords = list of 1d arrays of coordinates''' # check consistency of dimensions if len(coords) != len(self.nDgrid): raise ValueError('point dimension differs from random field dimension') # create the covariance matrix C_matrices = [self.acor(coords_i.reshape(1, len(coords_i)) - self.nDgrid[i].reshape(len(self.nDgrid[i]),1), self.lacor_arr[i]) for i, coords_i in enumerate(coords)] C_u = 1.0 for i, C_ui in enumerate(C_matrices): if i == 0: C_u *= C_ui else: C_u = C_u.reshape(C_u.shape[0], 1, C_u.shape[1]) * C_ui grid_size = 1.0 for j in np.arange(i+1): grid_size *= len(self.nDgrid[j]) C_u = C_u.reshape(grid_size,len(coords[0])) Lambda_Cx, Phi_Cx = self.eigenvalues # values interpolated in the standardized Gaussian rf u = np.sum(self.generated_random_vector / np.diag(Lambda_Cx) ** 0.5 * np.dot(C_u.T, Phi_Cx), axis=1) if self.distr_type == 'Gauss': scaled_u = u * self.stdev + self.mean elif self.distr_type == 'Weibull': Pf = norm().cdf(u) scaled_u = weibull_min(self.shape, scale=self.scale, loc=self.loc).ppf(Pf) return scaled_u
class Distribution(HasTraits): ''' takes a scipy.stats distribution ''' def __init__(self, distribution, **kw): super(Distribution, self).__init__(**kw) self.distribution = distribution self.changes() distribution = Instance(rv_continuous) def add_listeners(self): self.on_trait_change(self.changes, '+params,+moments') def remove_listeners(self): self.on_trait_change(self.changes, '+params,+moments', remove=True) # precision for displayed numbers = 12 numbers corresponds with the numbers # displayed in the UI. decimal.getcontext().prec = 12 # event that triggers the replot in pdistrib.py changed = Event # freezes the location to 0.0 loc_zero = Bool(True) # old values are compared with new values to recognize which value changed old_values = Array(Float, value=zeros(7)) new_values = Array(Float, value=zeros(7)) # statistical parameters loc = Float(0.0, auto_set=False, enter_set=True, params=True) scale = Float(1.0, auto_set=False, enter_set=True, params=True) shape = Float(1.0, auto_set=False, enter_set=True, params=True) # statistical moments mean = Float(0.0, auto_set=False, enter_set=True, moments=True) variance = Float(0.0, auto_set=False, enter_set=True, moments=True) skewness = Float(0.0, auto_set=False, enter_set=True, moments=True) kurtosis = Float(0.0, auto_set=False, enter_set=True, moments=True) stdev = Property(depends_on='variance') def _get_stdev(self): return self.variance**(0.5) def get_mean(self): ''' Methods for evaluating the statistical moments. Decimal together with precision are needed in order to get the number which is actually displayed in the UI. Otherwise clicking in the interface or pressing enter on the displayed values would trigger new computation because these values are a representation of the computed values rounded to 12 numbers. ''' self.mean = float(Decimal(str((self.distr.stats('m')))) / 1) def get_variance(self): self.variance = float(Decimal(str((self.distr.stats('v')))) / 1) def get_skewness(self): self.skewness = float(Decimal(str((self.distr.stats('s')))) / 1) def get_kurtosis(self): self.kurtosis = float(Decimal(str((self.distr.stats('k')))) / 1) def get_moments(self, specify): ''' specify is a string containing some of the letters 'mvsk' ''' self.remove_listeners() moments = self.distr.stats(specify) moment_names = ['mean', 'variance', 'skewness', 'kurtosis'] for idx, value in enumerate(moments): setattr(self, moment_names[idx][0], value) dict = { 'm': self.get_mean, 'v': self.get_variance, 's': self.get_skewness, 'k': self.get_kurtosis } # chooses the methods to calculate the three moments which didn't # trigger this method for idx in specify: dict[idx]() self.add_listeners() def changes(self): ''' coordinates the methods for computing parameters and moments when a change has occurred ''' self.remove_listeners() self.new_values = array([ self.shape, self.loc, self.scale, self.mean, self.variance, self.skewness, self.kurtosis ]) # test which parameters or moments are significant indexing = arange(7)[abs(self.old_values - self.new_values) != 0] if len(indexing) > 0 and indexing[0] < 3: self.get_moments('mvsk') elif len(indexing) > 0 and indexing[0] > 2: self.param_methods[indexing[0] - 3]() else: pass self.old_values = array([ self.shape, self.loc, self.scale, self.mean, self.variance, self.skewness, self.kurtosis ]) self.add_listeners() self.changed = True param_methods = Property(Array, depends_on='distribution') @cached_property def _get_param_methods(self): methods = array([ self.mean_change, self.variance_change_scale, self.variance_change_shape, self.skewness_change, self.kurtosis_change ]) if self.distribution.shapes == None: return methods[0:2] else: if len(self.distribution.shapes) == 1: return hstack((methods[0], methods[2:5])) else: print 'more than 1 shape parameters' def shape_scale_mean_var_residuum(self, params): shape = params[0] scale = params[1] res_mean = self.mean - self.distribution(shape, \ loc=self.loc, scale=scale).stats('m') res_var = self.variance - self.distribution(shape, \ loc=self.loc, scale=scale).stats('v') return [res_mean, res_var] def mean_change(self): if self.loc_zero == True and self.distribution.__dict__[ 'shapes'] != None: self.loc = 0.0 result = fsolve(self.shape_scale_mean_var_residuum, [1., 1.]) self.shape = float(Decimal(str(result[0].sum())) / 1) self.scale = float(Decimal(str(result[1].sum())) / 1) else: self.loc += float( Decimal(str(self.mean - self.distr.stats('m'))) / 1) def scale_variance_residuum(self, scale): return self.variance - self.distribution(\ loc=self.loc, scale=scale).stats('v') def variance_change_scale(self): self.scale = float( Decimal(str(fsolve(self.scale_variance_residuum, 1).sum())) / 1) def shape_variance_residuum(self, shape): return self.variance - self.distribution(shape, \ loc=self.loc, scale=self.scale).stats('v') def variance_change_shape(self): self.shape = float( Decimal(str(fsolve(self.shape_variance_residuum, 1).sum())) / 1) self.get_moments('msk') def shape_skewness_residuum(self, shape): return self.skewness - self.distribution(shape, \ loc=self.loc, scale=self.scale).stats('s') def skewness_change(self): self.shape = float( Decimal(str(fsolve(self.shape_skewness_residuum, 1).sum())) / 1) self.get_moments('mvk') def shape_kurtosis_residuum(self, shape): return self.kurtosis - self.distribution(shape, \ loc=self.loc, scale=self.scale).stats('k') def kurtosis_change(self): self.shape = float( Decimal(str(fsolve(self.shape_kurtosis_residuum, 1).sum())) / 1) self.get_moments('mvs') distr = Property(depends_on='+params') @cached_property def _get_distr(self): if self.distribution.__dict__['numargs'] == 0: return self.distribution(self.loc, self.scale) elif self.distribution.__dict__['numargs'] == 1: return self.distribution(self.shape, self.loc, self.scale) def default_traits_view(self): '''checks the number of shape parameters of the distribution and adds them to the view instance''' label = str(self.distribution.name) if self.distribution.shapes == None: params = Item() if self.mean == infty: moments = Item(label='No finite moments defined') else: moments = Item('mean', label='mean'), \ Item('variance', label='variance'), \ Item('stdev', label='st. deviation', style='readonly') elif len(self.distribution.shapes) == 1: params = Item('shape', label='shape') if self.mean == infty: moments = Item(label='No finite moments defined') else: moments = Item('mean', label='mean'), \ Item('variance', label='variance'), \ Item('stdev', label='st. deviation', style='readonly'), \ Item('skewness', label='skewness'), \ Item('kurtosis', label='kurtosis'), else: params = Item() moments = Item() view = View(VGroup(Label(label, emphasized=True), Group(params, Item('loc', label='location'), Item('scale', label='scale'), Item('loc_zero', label='loc = 0.0'), show_border=True, label='parameters', id='pdistrib.distribution.params'), Group( moments, id='pdistrib.distribution.moments', show_border=True, label='moments', ), id='pdistrib.distribution.vgroup'), kind='live', resizable=True, id='pdistrib.distribution.view') return view
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 SingleRun(HasTraits): '''Pairing of algorithm configuration and randomization pattern. ''' rf = Property def _get_rf(self): return self.run_table.rf config = Tuple conf_idx = Property def _get_conf_idx(self): return self.config[0] conf_options = Property def _get_conf_options(self): return self.config[1][0] conf_latex_label = Property def _get_conf_latex_label(self): return self.config[1][1] rand_idx_arr = Array(int, rand=True) run_table = WeakRef # derived stuff s = Property def _get_s(self): return self.run_table.s n_rv = Property def _get_n_rv(self): return len(self.rand_idx_arr) memsize = Property def _get_memsize(self): return self.run_table.memsize n_int = Property def _get_n_int(self): return int(pow(self.memsize, 1 / float(self.n_rv))) real_memsize = Property def _get_real_memsize(self): return pow(self.n_int, self.n_rv) exec_time = Property def _get_exec_time(self): '''Run spirrid with the given dictionary of configurations. ''' s = self.s # apply the randomization pattern s.clear_rv() for rv in self.rand_idx_arr: param_key = self.rf.param_keys[rv] s.add_rv(param_key, n_int=self.n_int) # setup the spirrid exec configuration s.set(**self.conf_options) return s.exec_time def __str__(self): return 'conf: %s, rand_idx_arr %s' % (self.conf_options, self.rand_idx_arr)
class PDistrib(HasTraits): implements = IPDistrib def __init__(self, **kw): super(PDistrib, self).__init__(**kw) self.on_trait_change(self.refresh, 'distr_type.changed,quantile,n_segments') self.refresh() # 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_choice = Enum('sin2x', 'weibull_min', 'sin_distr', 'uniform', 'norm', 'piecewise_uniform', 'gamma') distr_dict = { 'sin2x': sin2x, 'uniform': uniform, 'norm': norm, 'weibull_min': weibull_min, 'sin_distr': sin_distr, 'piecewise_uniform': piecewise_uniform, 'gamma': gamma } # 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(1e-14, 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) figure = Instance(Figure) def _figure_default(self): figure = Figure(facecolor='white') return figure data_changed = Event def plot(self, fig): figure = fig figure.clear() axes = figure.gca() # plot PDF axes.plot(self.x_array, self.pdf_array, lw=1.0, color='blue', \ label='PDF') axes2 = axes.twinx() # plot CDF on a separate axis (tick labels left) axes2.plot(self.x_array, self.cdf_array, lw=2, color='red', \ label='CDF') # fill the unity area given by integrating PDF along the X-axis axes.fill_between(self.x_array, 0, self.pdf_array, color='lightblue', alpha=0.8, linewidth=2) # plot mean mean = self.distr_type.distr.stats('m') axes.plot([mean, mean], [0.0, self.distr_type.distr.pdf(mean)], lw=1.5, color='black', linestyle='-') # plot stdev stdev = sqrt(self.distr_type.distr.stats('v')) axes.plot([mean - stdev, mean - stdev], [0.0, self.distr_type.distr.pdf(mean - stdev)], lw=1.5, color='black', linestyle='--') axes.plot([mean + stdev, mean + stdev], [0.0, self.distr_type.distr.pdf(mean + stdev)], lw=1.5, color='black', linestyle='--') axes.legend(loc='center left') axes2.legend(loc='center right') axes.ticklabel_format(scilimits=(-3., 4.)) axes2.ticklabel_format(scilimits=(-3., 4.)) # plot limits on X and Y axes axes.set_ylim(0.0, max(self.pdf_array) * 1.15) axes2.set_ylim(0.0, 1.15) range = self.range[1] - self.range[0] axes.set_xlim(self.x_array[0] - 0.05 * range, self.x_array[-1] + 0.05 * range) axes2.set_xlim(self.x_array[0] - 0.05 * range, self.x_array[-1] + 0.05 * range) def refresh(self): self.plot(self.figure) self.data_changed = True icon = Property(Instance(ImageResource), depends_on='distr_type.changed,quantile,n_segments') @cached_property def _get_icon(self): fig = plt.figure(figsize=(4, 4), facecolor='white') self.plot(fig) tf_handle, tf_name = tempfile.mkstemp('.png') fig.savefig(tf_name, dpi=35) return ImageResource(name=tf_name) traits_view = View(HSplit(VGroup( Group( Item('distr_choice', show_label=False), Item('@distr_type', show_label=False), ), id='pdistrib.distr_type.pltctrls', label='Distribution parameters', scrollable=True, ), Tabbed( Group( Item('figure', editor=MPLFigureEditor(), show_label=False, resizable=True), scrollable=True, label='Plot', ), Group(Item('quantile', label='quantile'), Item('n_segments', label='plot points'), label='Plot parameters'), label='Plot', id='pdistrib.figure.params', dock='tab', ), dock='tab', id='pdistrib.figure.view'), id='pdistrib.view', dock='tab', title='Statistical distribution', buttons=['Ok', 'Cancel'], scrollable=True, resizable=True, width=600, height=400)
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 HPShell(HasTraits): '''Geometry definition. ''' #=========================================================================== # geometric variables and values #=========================================================================== # part of mushroof # # @todo: "four" is not supported by "n_elems_xy_dict"in mushroff_model mushroof_part = Enum('detail', 'quarter', 'one', 'four') # origin # @todo: define as "_default" # X0 = Array(float, value=[0., 0., 0.]) # element properties of grid # n_elems_xy = Int(6) n_elems_z = Int(3) n_elems_xy_quarter = Property(Int) @cached_property def _get_n_elems_xy_quarter(self): return self.n_elems_xy / self.scale_size # standard array for column shift # shift array shifts the elements towards the defined coordinates # [x_shift,y_shift,element_between] # array needs to have the right shape (:,3)!! # # @todo: define as "_default" # shift_array = Array(float, shape=(None, 3), value=[[0.45 / 2**0.5, 0.45 / 2**0.5, 1]]) # dimensions of the shell for one quarter of mush_roof # @todo: add "_quarter" # length_x = Float(4.0) # [m] length_y = Float(4.0) # [m] length_z = Float(1.062) # [m] t_shell = Float(0.06) # [m] width_column = Float(0.45) # [m] length_x_detail = Float(1.5) # [m] length_y_detail = Float(1.5) # [m] scale_size_detail_x = Property(Float) def _get_scale_size_detail_x(self): return self.length_x_detail / self.length_x * 2. scale_size_detail_y = Property(Float) def _get_scale_size_detail_y(self): return self.length_y_detail / self.length_y * 2. # scale factor for different mushroof parts # Defines the proportion between the lenght of the model # with respect to the length of a quarter shell as the # basic substructure of which the model consists of. # @todo: add "depend_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) # @cached_property def _get_scale_size(self): # scale_size_detail = self.lenght_x_detail / self.length_x scale_dict = { 'detail': self.scale_size_detail_x, 'quarter': 1.0, 'one': 2.0, 'four': 4.0 } return scale_dict[self.mushroof_part] # factor to scale delta_h (inclination of the shell) # The thickness remains unchanged by this scaling, e.g. self.thickness = 0.06 [m] # delta_h_scalefactor = Float(1.00) # [-] # shift of column elements # shift_elems = Bool(True) # const_edge element operator # (for non-linear analysis only, where an element layer of constant # thickness is needed to simulate the reinforced behaviour of the # concrete. # const_edge_elem = Bool(False) t_edge = Float(0.03) # [m] n_elems_edge = Int(1) #number of dofs used for edge refinement #=========================================================================== # reading options #=========================================================================== # "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. # Option should be used for the robj-file with 4x4m geometry # cut_off_lowerface = Bool(True) # corresponds to the delta in the geometry .obj-file with name '4x4m' as a cut off # delta_h = Float(1.00) # [m] # choose geometric file (obj-data file) # geo_input_name = Enum('4x4m', '02') # 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}) def _read_arr(self, side='lowerface_'): file_name = side + self.geo_input_name + '.robj' file_path = join('geometry_files', file_name) v_arr = read_rsurface(file_path) filter = self.geo_filter.get(self.geo_input_name, None) if filter != None: v_arr = filter(v_arr) 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)) @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 1 m (=delta h). At this limit the lower face is # cut off. Global z coordinate is assumed to point up. # vl_z_max = max(vl_arr[:, 2]) vl_z_min = vl_z_max - self.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)) @cached_property def _get_vu_arr(self): return self._read_arr('upperface_') #------------------------------------------------------------------------------ # hp_shell geometric transformation #------------------------------------------------------------------------------ def __call__(self, points): '''Return the global coordinates of the supplied local points. ''' # number of local grid points for each coordinate direction # values must range between 0 and 1 # xi, yi, zi = points[:, 0], points[:, 1], points[:, 2] print "xi", xi print "xi.shape", xi.shape # size of total structure # # @todo: move to class definition of "mushroof_model" and send to "__call__" scale_size = self.scale_size print "scale_size", scale_size # @todo: add "_quarter" (see above) length_x_tot = self.length_x * scale_size length_y_tot = self.length_y * scale_size n_elems_xy_quarter = self.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 ) if self.mushroof_part == 'detail': print 'in d_origin_fn' return abs(1.0 * coords - 0.5) * scale_size # # @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 ) ) # 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) # normalized coordinates of the vertices for lower- and upperface # NOTE: the underline character indicates a normalized value # vl_arr_, vu_arr_ = normalize_rsurfaces(self.vl_arr, self.vu_arr) # use a radial basis function approximation (rbf) (i.e. interpolation of # scattered data) based on the normalized vertex points of the lower face # x_ = vl_arr_[:, 0] # flip the orientation of the local coordinate system in the # corresponding y-direction depending on the data file # geo_input_name = self.geo_input_name if geo_input_name == '4x4m': y_ = vl_arr_[:, 1] else: y_ = 1 - vl_arr_[:, 1] z_ = vl_arr_[:, 2] rbf = Rbf(x_, y_, z_, function='cubic') # get the z-value at the supplied local grid points # of the lower face # zi_lower_ = rbf(xi_rbf, yi_rbf) # use a radial basis function approximation (rbf) (i.e. interpolation of # scattered data) based on the normalized vertex points of the upper face # x_ = vu_arr_[:, 0] # flip the orientation of the local coordinate system in the # corresponding y-direction depending on the data file # geo_input_name = self.geo_input_name if geo_input_name == '4x4m': y_ = vu_arr_[:, 1] else: y_ = 1 - vu_arr_[:, 1] z_ = vu_arr_[:, 2] rbf = Rbf(x_, y_, z_, function='cubic') # get the z-value at the supplied local grid points # of the upper face # # note that zi_upper_ is a normalized coordinate! # zi_upper_ = rbf(xi_rbf, yi_rbf) # thickness is multiplied by the supplied zi coordinate # z_ = (zi_lower_ + (zi_upper_ - zi_lower_) * zi / self.delta_h_scalefactor) * self.delta_h_scalefactor # coordinates of origin # X, Y, Z = 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 + xi * length_x_tot, Y + yi * length_y_tot, Z + z_ * self.length_z]