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 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 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 LC(HasTraits): '''Loading case class ''' # path to the directory containing the state data files # data_dir = Directory # name of the file containing the hinge forces # or the displacements # file_name = Str(input=True) plt_export = Property def _get_plt_export(self): basename = 'hf_' + self.name + '_' return os.path.join(data_dir, basename) # data filter (used to hide unwanted values, e.g. high sigularities etc.) # data_filter = Callable(input=True) def _data_filter_default(self): return lambda x: x # - do nothing by default # name of the loading case # name = Str(input=True) # category of the loading case # category = Enum('dead-load', 'additional dead-load', 'imposed-load', input=True) # list of keys specifying the names of the loading cases # that can not exist at the same time, i.e. which are exclusive to each other # exclusive_to = List(Str, input=True) def _exclusive_to_default(self): return [] # combination factors (need to be defined in case of imposed loads) # psi_0 = Float(input=True) psi_1 = Float(input=True) psi_2 = Float(input=True) # security factors ULS # gamma_fav = Float(input=True) def _gamma_fav_default(self): if self.category == 'dead-load': return 1.00 if self.category == 'additional dead-load': return 0.00 if self.category == 'imposed-load': return 0.00 gamma_unf = Float(input=True) def _gamma_unf_default(self): if self.category == 'dead-load': return 1.35 if self.category == 'additional dead-load': return 1.35 if self.category == 'imposed-load': return 1.50 # security factors SLS: # (used to distinguish combinations where imposed-loads # or additional-dead-loads are favorable or unfavorable.) # gamma_fav_SLS = Float(input=True) def _gamma_fav_SLS_default(self): if self.category == 'dead-load': return 1.00 elif self.category == 'additional dead-load' or \ self.category == 'imposed-load': return 0.00 gamma_unf_SLS = Float(input=True) def _gamma_unf_SLS_default(self): return 1.00 def _read_data(self, file_name): '''read state data and geo data from csv-file using ';' as filed delimiter and ' ' (blank) as text delimiter. ''' print '*** read state data from file: %s ***' % (file_name) # hinge forces N,V in global coordinates (as obtained from FE-modell) # # input_arr = loadtxt(file_name , delimiter=';', skiprows=2, usecols=(2, 3, 4, 5, 6)) # # hinge forces N*,V* in local (hinge) coordinate system (transformed by inclination angle of the hinges, i.e. shell geometry) # # input_arr = loadtxt(file_name, delimiter=';', skiprows=2, usecols=(2, 3, 4, 8, 9)) # hinge position [m] # X_hf = input_arr[:, 0][:, None] Y_hf = input_arr[:, 1][:, None] Z_hf = input_arr[:, 2][:, None] # INPUT Matthias - RFEM X_hf += 3.5 Y_hf += 3.5 # local hinge forces [kN] # N_ip = input_arr[:, 3][:, None] V_op = input_arr[:, 4][:, None] V_ip = 0. * V_op return { 'X_hf': X_hf, 'Y_hf': Y_hf, 'Z_hf': Z_hf, 'N_ip': N_ip, 'V_ip': V_ip, 'V_op': V_op, } # original data (before filtering) # data_orig = Property(Dict, depends_on='file_name') @cached_property def _get_data_orig(self): return self._read_data(self.file_name) # data (after filtering) # data_dict = Property(Dict, depends_on='file_name, data_filter') @cached_property def _get_data_dict(self): d = {} for k, arr in self.data_orig.items(): d[k] = self.data_filter(arr) return d sr_columns = List(['N_ip', 'V_ip', 'V_op']) geo_columns = List(['X_hf', 'Y_hf', 'Z_hf']) sr_arr = Property(Array) def _get_sr_arr(self): '''return the stress resultants of the loading case as stack of all sr-column arrays. ''' data_dict = self.data_dict return hstack([data_dict[sr_key] for sr_key in self.sr_columns]) geo_data_dict = Property(Array) def _get_geo_data_dict(self): '''Dict of coords as sub-Dict of read in data dict ''' data_dict = self.data_dict geo_data_dict = {} for geo_key in self.geo_columns: geo_data_dict[geo_key] = data_dict[geo_key] return geo_data_dict def _read_data_u(self, file_name_u): '''used to read RFEM files read state data and geo date from csv-file using ';' as filed delimiter and ' ' (blank) as text delimiter for displacement. ''' print '*** read state data from file: %s ***' % (file_name_u) # get the column headings defined in the first row # of the csv displacement input file # file = open(file_name_u, 'r') lines = file.readlines() column_headings = lines[1].split(';') # remove '\n' from last string element in list # column_headings[-1] = column_headings[-1][:-1] column_headings_arr = array(column_headings) # skip the first two columns for 'loadtxt'; # therefore subtract index by 2 # geo_data: # X_idx = where('jX' == column_headings_arr)[0] - 2 Y_idx = where('jY' == column_headings_arr)[0] - 2 Z_idx = where('jZ' == column_headings_arr)[0] - 2 # state_data: # U_x_idx = where('uX' == column_headings_arr)[0] - 2 U_y_idx = where('uY' == column_headings_arr)[0] - 2 U_z_idx = where('uZ' == column_headings_arr)[0] - 2 file.close() input_arr = loadtxt(file_name_u, delimiter=';', skiprows=2, usecols=(2, 3, 4, 5, 6, 7)) # global coords [m] # self.X_u = input_arr[:, X_idx] + 3.5 self.Y_u = input_arr[:, Y_idx] + 3.5 self.Z_u = input_arr[:, Z_idx] print 'self.X_u', self.X_u print 'self.Y_u', self.Y_u # hinge forces [kN] # self.U_x = input_arr[:, U_x_idx] self.U_y = input_arr[:, U_y_idx] self.U_z = input_arr[:, U_z_idx]
class ECBLCalib(HasStrictTraits): # rupture moment and normal force measured in the calibration experiment # (three point bending test) # Mu = Float(3.5, calib_input=True) # [kNm] Nu = Float(0.0, calib_input=True) # [kN] #=========================================================================== # Cross Section Specification (Geometry and Layout) #=========================================================================== cs = Instance(ECBCrossSection) def _cs_default(self): reinf = [ECBReinfTexUniform(n_layers=3)] matrix = ECBMatrixCrossSection(width=0.1, n_cj=20) return ECBCrossSection(reinf=reinf, matrix=matrix) ecb_law_type = DelegatesTo('cs') ecb_law = DelegatesTo('cs') cc_law_type = DelegatesTo('cs') cc_law = DelegatesTo('cs') width = DelegatesTo('cs') f_ck = DelegatesTo('cs') eps_c_u = DelegatesTo('cs') n_rovings = DelegatesTo('cs') n_layers = DelegatesTo('cs') notify_change = Callable(None) modified = Event @on_trait_change('cs.modified,+calib_input') def _set_modified(self): self.modified = True if self.notify_change != None: self.notify_change() u0 = Property(Array(float), depends_on='cs.modified') '''Construct the initial vector. ''' @cached_property def _get_u0(self): u0 = self.ecb_law.u0 #eps_up = u0[1] eps_up = -self.cs.eps_c_u eps_lo = self.cs.convert_eps_tex_u_2_lo(u0[0]) print 'eps_up', eps_up print 'eps_lo', eps_lo 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.eps_c_u eps_lo = u[0] self.cs.set(eps_lo=eps_lo, eps_up=eps_up) eps_tex_u = self.cs.convert_eps_lo_2_tex_u(u[0]) self.cs.ecb_law.set_cparams(eps_tex_u, u[1]) N_internal = self.cs.N M_internal = self.cs.M d_N = N_internal - self.Nu d_M = M_internal - self.Mu return np.array([d_N, d_M], dtype=float) u_sol = Property(Array(Float), depends_on='cs.modified,+calib_input') '''Solution vector returned by 'fit_response'.''' @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 = Property(depends_on='cs.modified,+calib_input') '''Calibrated ecbl_mfn ''' @cached_property def _get_calibrated_ecb_law(self): print 'NEW CALIBRATION' self.ecb_law.set_cparams(*self.u_sol) return self.ecb_law view = View(Item('Mu'), Item('Nu'), buttons=['OK', 'Cancel'])
class ECBLCalibHist(HasStrictTraits): # History of measured bending moments and compressive strains # eps_c_arr = Array(float) M_arr = Array(float) @on_trait_change('eps_c_arr, M_arr') def _reset_ecb_law(self): self.cs_geo.ecb_law.n_eps = len(self.M_arr) + 1 n_states = Property(depends_on='eps_c_arr, M_arr') @cached_property def _get_n_states(self): # assert that both arrays have the same length return self.eps_c_arr.shape[0] #=========================================================================== # Cross Section Specification (Geometry and Layout) #=========================================================================== cs_geo = Instance(ECBCrossSectionGeo) def _cs_geo_default(self): cs_geo = ECBCrossSectionGeo(notify_change=self.set_modified, ecb_law_type='piecewise_linear') cs_geo.ecb_law.n_eps = len(self.M_arr) + 1 def _cs_geo_changed(self): self.cs_geo.ecb_law_type = 'piecewise_linear' self.cs_geo.ecb_law.n_eps = len(self.M_arr) + 1 cs_states = Property(List(Instance(ECBCrossSectionState)), depends_on='cs_geo') @cached_property def _get_cs_states(self): return [ ECBCrossSectionState(cs_geo=self.cs_geo, notify_change=self.set_modified) for k in range(self.n_states) ] notify_change = Callable(None) modified = Event @on_trait_change('eps_c_arr, M_arr') def set_modified(self): self.modified = True if self.notify_change != None: self.notify_change() u0 = Property(Array(float), depends_on='cs_geo.modified') @cached_property def _get_u0(self): ecb_law = self.cs_geo.ecb_law eps_tex_u = ecb_law.eps_tex_u u0 = np.zeros((2 * self.n_states), dtype='float') d_eps = eps_tex_u / self.n_states u0[:self.n_states] = np.repeat(d_eps, n_states) u0[self.n_states:] = ecb_law.sig_level_arr[1:] #u0[:] = [1.233333e-02, 8.0e+4] return u0 * 0.1 # 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, '------------------------' print 'u', u sig_arr = np.hstack([[0.0], u[self.n_states:]]) d_eps_arr = np.hstack([[0.0], u[:self.n_states]]) eps_arr = np.cumsum(d_eps_arr) self.n += 1 # set iteration counter # for k, (state, eps_c) in enumerate(zip(self.cs_states, self.eps_c_arr)): state.eps_up = eps_c eps_lo = state.convert_eps_tex_u_2_lo(eps_arr[k + 1]) state.eps_lo = eps_lo #self.cs_geo.ecb_law.set_cparams(eps_tex_u, c_params) self.cs_geo.ecb_law.set_sig_eps_arr(eps_arr, sig_arr) d_MN_list = [] for k, (state, M) in enumerate(zip(self.cs_states, self.M_arr)): N_internal = state.N M_internal = state.M d_N = N_internal - 0.0 d_M = M_internal - M d_MN_list += [d_M, d_N] dR = np.array(d_MN_list, dtype=float) print 'R', dR return dR # 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' u = self.u_sol eps_tex_u = self.cs_states[-1].convert_eps_lo_2_tex_u(u[self.n_states - 1]) c_params = np.hstack([[0.0], u[self.n_states:]]) self.cs_geo.ecb_law.set_cparams(eps_tex_u, c_params) return self.cs_geo.ecb_law view = View(buttons=['OK', 'Cancel'])