class CodeGenCompiledFactory(HasStrictTraits): '''Depending on the sampling type return . ''' mapping_table = Dict(value = {'TGrid' : CodeGenCompiledTGrid, 'PGrid' : CodeGenCompiledPGrid, 'MCS' : CodeGenCompiledIrregular, 'LHS' : CodeGenCompiledIrregular })
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 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 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 FunctionRandomization(HasStrictTraits): # response function q = Callable(input=True) #=========================================================================== # Inspection of the response function parameters #=========================================================================== var_spec = Property(depends_on='q') @cached_property def _get_var_spec(self): '''Get the names of the q_parameters''' if type(self.q) is types.FunctionType: arg_offset = 0 q = self.q else: arg_offset = 1 q = self.q.__call__ argspec = inspect.getargspec(q) args = np.array(argspec.args[arg_offset:]) dflt = np.array(argspec.defaults) return args, dflt var_names = Property(depends_on='q') @cached_property def _get_var_names(self): '''Get the array of default values. None - means no default has been specified ''' return self.var_spec[0] var_defaults = Property(depends_on='q') @cached_property def _get_var_defaults(self): '''Get the array of default values. None - means no default has been specified ''' dflt = self.var_spec[1] defaults = np.repeat(None, len(self.var_names)) start_idx = min(len(dflt), len(defaults)) defaults[-start_idx:] = dflt[-start_idx:] return defaults #=========================================================================== # Control variable specification #=========================================================================== evars = Dict(Str, Array, input_change=True) def __evars_default(self): return {'e': [0, 1]} evar_lst = Property() def _get_evar_lst(self): ''' sort entries according to var_names.''' return [self.evars[nm] for nm in self.evar_names] evar_names = Property(depends_on='evars') @cached_property def _get_evar_names(self): evar_keys = list(self.evars.keys()) return [nm for nm in self.var_names if nm in evar_keys] evar_str = Property() def _get_evar_str(self): s_list = [ '%s = [%g, ..., %g] (%d)' % (name, value[0], value[-1], len(value)) for name, value in zip(self.evar_names, self.evar_lst) ] return string.join(s_list, '\n') # convenience property to specify a single control variable without # the need to send a dictionary e_arr = Property def _set_e_arr(self, e_arr): '''Get the first free argument of var_names and set it to e vars ''' self.evars[self.var_names[0]] = e_arr #=========================================================================== # Specification of parameter value / distribution #=========================================================================== tvars = Dict(input_change=True) tvar_lst = Property(depends_on='tvars') @cached_property def _get_tvar_lst(self): '''sort entries according to var_names ''' return [self.tvars[nm] for nm in self.tvar_names] tvar_names = Property def _get_tvar_names(self): '''get the tvar names in the order given by the callable''' tvar_keys = list(self.tvars.keys()) return np.array([nm for nm in self.var_names if nm in tvar_keys], dtype=str) tvar_str = Property() def _get_tvar_str(self): s_list = [ '%s = %s' % (name, str(value)) for name, value in zip(self.tvar_names, self.tvar_lst) ] return string.join(s_list, '\n') # number of integration points n_int = Int(10, input_change=True)
class FunctionRandomization(HasStrictTraits): # response function q = Callable(input=True) # =========================================================================== # Inspection of the response function parameters # =========================================================================== var_spec = Property(depends_on='q') @cached_property def _get_var_spec(self): '''Get the names of the q_parameters''' if type(self.q) is types.FunctionType: arg_offset = 0 q = self.q else: arg_offset = 1 q = self.q.__call__ argspec = inspect.getargspec(q) args = np.array(argspec.args[arg_offset:]) dflt = np.array(argspec.defaults) return args, dflt var_names = Property(depends_on='q') @cached_property def _get_var_names(self): '''Get the array of default values. None - means no default has been specified ''' return self.var_spec[0] var_defaults = Property(depends_on='q') @cached_property def _get_var_defaults(self): '''Get the array of default values. None - means no default has been specified ''' dflt = self.var_spec[1] defaults = np.repeat(None, len(self.var_names)) start_idx = min(len(dflt), len(defaults)) defaults[-start_idx:] = dflt[-start_idx:] return defaults # =========================================================================== # Control variable specification # =========================================================================== eps_vars = Dict(Str, Array, input_change=True) def _eps_vars_default(self): return {'e': [0, 1]} evar_lst = Property() def _get_evar_lst(self): ''' sort entries according to var_names.''' return [self.eps_vars[nm] for nm in self.evar_names] evar_names = Property(depends_on='eps_vars') @cached_property def _get_evar_names(self): evar_keys = self.eps_vars.keys() return [nm for nm in self.var_names if nm in evar_keys] evar_str = Property() def _get_evar_str(self): s_list = [ '%s = [%g, ..., %g] (%d)' % (name, value[0], value[-1], len(value)) for name, value in zip(self.evar_names, self.evar_lst) ] return string.join(s_list, '\n') # convenience property to specify a single control variable without # the need to send a dictionary e_arr = Property def _set_e_arr(self, e_arr): '''Get the first free argument of var_names and set it to e vars ''' self.eps_vars[self.var_names[0]] = e_arr # =========================================================================== # Specification of parameter value / distribution # =========================================================================== theta_vars = Dict(input_change=True) _theta_vars = Property(depends_on='theta_vars') @cached_property def _get__theta_vars(self): _theta_vars = {} for key, value in self.theta_vars.items(): # type checking is_admissible = False for admissible_type in [float, int, RV]: if isinstance(value, admissible_type): is_admissible = True if not is_admissible: raise TypeError, 'bad type of theta variable %s' % key # type conversion if isinstance(value, int): value = float(value) _theta_vars[key] = value return _theta_vars tvar_lst = Property() def _get_tvar_lst(self): '''sort entries according to var_names ''' return [self._theta_vars[nm] for nm in self.tvar_names] tvar_names = Property def _get_tvar_names(self): '''get the tvar names in the order given by the callable''' tvar_keys = self._theta_vars.keys() return np.array([nm for nm in self.var_names if nm in tvar_keys], dtype=str) tvar_str = Property() def _get_tvar_str(self): s_list = [ '%s = %s' % (name, str(value)) for name, value in zip(self.tvar_names, self.tvar_lst) ] return string.join(s_list, '\n') # number of integration points n_int = Int(10, input_change=True) # count the random variables n_rand_vars = Property def _get_n_rand_vars(self): dt = map(type, self.tvar_lst) return dt.count(RV) # get the indexes of the random variables within the parameter list rand_var_idx_list = Property(depends_on='theta_vars, recalc') @cached_property def _get_rand_var_idx_list(self): dt = np.array(map(type, self.tvar_lst)) return np.where(dt == RV)[0]
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]
class MFnPlotAdapter(HasPrivateTraits): """ The base class for adapting function implementation in order to plot it in a plotting toolkit (either Chaco or Matplotlib) """ # label on the x axis (only used when var_x empty) # label_x = Str('') # label on the y axis (only used when var_y empty) label_y = Str('') # title of the diagram # title = Str('') # color of the title title_color = Str('black') # when specified take the label of the axis from the value # of the variable trait in object # var_x = Str('') # when specified take the label of the axis from the value # of the variable trait in object # var_y = Str('') # label for line in legend # line_label = Str('') # @todo - further attributes to be made available # limits of number positions for switching into scientific notation 1eXX scilimits = Tuple(-3., 4.) # Plot properties line_color = List([ 'blue', 'red', 'green', 'black', 'magenta', 'yellow', 'white', 'cyan' ]) #rr: is the dictionary necessary here? #why not a list of keys? chaco as well mpl can work with the key line_style = Dict({ 'solid': '-', 'dash': '.', 'dot dash': '-.', 'dot': ':', }) #horisontal axis scale ('log', 'symlog', 'linear') xscale = Str('linear') #vertical axis scale ('log', 'symlog', 'linear') yscale = Str('linear') # linewidth line_width = List(2.0) # color of the plotting background bgcolor = Str('white') # Border, padding properties border_visible = Bool(False) # @todo - unused - padding defined below - should be used in Chaco - # in Matplotlib it is working already [Faezeh, Check please] border_width = Int(0) # @todo does this work in both Mpl and Chaco? [Faeseh Check please] # padding_bg_color = Str('white') # labels in legend # @todo - no labels here - the defaults should make sense - are they active? # legend_labels = Tuple() # maximum size - None means arbitrarily resizable # max_size = Tuple() # minimum size # min_size = Tuple((200, 200)) # padding padding = Dict({'left': 0.1, 'bottom': 0.1, 'right': 0.9, 'top': 0.9}) # No of values displayed on the x axis xticks = Int(0) # No of values displayed on the y axis yticks = Int(0)