Example #1
0
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)
Example #2
0
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]
Example #4
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]
Example #5
0
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'])