Esempio n. 1
0
class Cuypers(HasTraits):
    '''
    Stochastic cracking model due to H. Cuypers (W. Curtin)
    matrix tensile strength is assumed to follow the Weibull distribution
    '''

    material = Instance(Material)

    def _material_default(self):
        return Material()

    m = Float(
        5.3,
        auto_set=False,
        enter_set=True,  # [-]
        desc='Weibull shape parameter for the matrix tensional strength [-]',
        modified=True)

    orientation = Range(
        low=0.0,
        high=Pi / 2,
        value=0.0,
        auto_set=False,
        enter_set=True,  # [-]
        desc='fiber orientation [rad]',
        modified=True)

    sigma_mu = Float(
        12.0,
        auto_set=False,
        enter_set=True,  # [N/mm^2]
        desc='mean matrix tensional strength [MPa]',
        modified=True)

    sigma_fu = Float(
        720.0,
        auto_set=False,
        enter_set=True,  # [N/mm^2]
        desc='fiber tensional strength [MPa]',
        modified=True)

    reinf_ratio = EitherType(names=['grid fiber layout', 'explicit value'],
                             klasses=[GridReinforcement, SimplyRatio],
                             modified=True)

    Pf = Range(
        low=0.0,
        high=1.0 - 1e-15,
        value=0.9,
        auto_set=False,
        enter_set=True,  # [-]
        desc='probability of crack spacing to be of final range',
        modified=True)

    sigma_ref = Range(
        low=1e-10,
        high=80.0,
        value=12.0,
        auto_set=False,
        enter_set=True,  # [MPa]
        desc='reference matrix stress',
        modified=True)

    sigma_ref_2 = Property(Float, depends_on='m, sigma_mu')

    def _get_sigma_ref_2(self):
        return e**(0.0991 / self.m) * self.scale_sigma_m

    rho = Property(Float, depends_on='reinf_ratio.rho,orientation')

    def _get_rho(self):
        if self.reinf_ratio.rho * cos(self.orientation) == 0:
            return 1e-15
        else:
            return self.reinf_ratio.rho * cos(self.orientation)

    V_f = Property(Float, depends_on='reinf_ratio.rho, orientation')

    @cached_property
    def _get_V_f(self):
        return self.rho

    V_m = Property(Float, depends_on='reinf_ratio.rho, orientation')

    @cached_property
    def _get_V_m(self):
        return 1 - self.rho

    alpha = Property(Float, depends_on='E_m,E_f,reinf_ratio.rho, orientation')

    @cached_property
    def _get_alpha(self):
        return (self.material.E_m * self.V_m) / (self.material.E_f * self.V_f)

    E_c = Property(Float, depends_on='E_m,E_f,reinf_ratio.rho, orientation')

    @cached_property
    def _get_E_c(self):
        return self.material.E_f * self.V_f + self.material.E_m * self.V_m

    delta_final = Property(Float, depends_on='E_m,E_f,rho,r,sigma_ref,tau,m')

    @cached_property
    def _get_delta_final(self):
        return self.sigma_ref * (self.V_m * self.material.r) / (
            self.V_f * 2 * self.material.tau)

    cs_final = Property(Float)

    def _get_cs_final(self):
        return 1.337 * self.delta_final

    def _get_delta(self, sigma_c):
        return sigma_c * (self.V_m * self.material.r * self.material.E_m) / (
            self.V_f * 2 * self.material.tau * self.E_c)

    # matrix strength scale parameter for the Weibull distribution with sigma_mu as
    # mean and m as shape parameter
    scale_sigma_m = Property(Float, depends_on='sigma_mu, m')

    @cached_property
    def _get_scale_sigma_m(self):
        return self.sigma_mu / gamma(1. + 1. / self.m)

    # composite scale parameter for the Weibull distribution with sigma_mu as
    # mean and m as shape parameter
    scale_sigma_c = Property(
        Float,
        depends_on='sigma_mu, m, E_m, E_f, reinf_ratio.rho, orientation')

    @cached_property
    def _get_scale_sigma_c(self):
        return self.scale_sigma_m / self.material.E_m * self.E_c

    def _get_cs(self, sigma_c):
        Pf = weibull_min.cdf(sigma_c, self.m, scale=self.scale_sigma_c)
        if Pf == 0:
            Pf = 1e-15
        return self.cs_final * 1.0 / Pf

    def eps_c(self, sigma_c):
        cs = self._get_cs(sigma_c)
        delta = self._get_delta(sigma_c)
        if cs > 2 * delta:
            return sigma_c / self.E_c * (1 + self.alpha * delta / cs)
        else:
            return sigma_c * (1. / (self.material.E_f * self.V_f) -
                              (self.alpha * cs) / (4. * delta * self.E_c))

    def _get_epsilon_c(self, sigma_c):
        get_epsilon_c = np.vectorize(self.eps_c)
        return get_epsilon_c(sigma_c)

    sigma_cu = Property(depends_on='rho, orientation, sigma_fu')

    @cached_property
    def _get_sigma_cu(self):
        '''Ultimate composite strength.
        The strength is given by the fiber strength related to the composite
        cross section by the reinforcement ratio rho and projected
        by the cosine of the fiber inclination into the loading direction.
        '''
        # 0.05 quantile strength of the matrix as a criterion for matrix failure
        # when this value is higher than the composite strength governed by the
        # reinforcement stress
        quantile = weibull_min.ppf(0.05, self.m, scale=self.scale_sigma_m)
        # composite failure due to matrix failure
        if self.sigma_fu * self.V_f * cos(
                self.orientation) < quantile / self.V_m:
            return quantile / self.V_m
        else:
            # composite failure due to fiber failure
            return self.sigma_fu * self.V_f * cos(self.orientation)

    csf = Property(
        depends_on='m, sigma_mu, sigma_ref, Pf, sigma_fu, orientation, E_f, E_m'
    )

    @cached_property
    def _get_csf(self):
        # composite stress at Pf probability for CS to be of final range
        # scale parameter for composite stress
        scale_sigma_c = self.scale_sigma_m / self.E_m * self.E_c

        sigma = weibull_min.ppf(self.Pf, self.m, scale=scale_sigma_c)

        # point of reaching final crack spacing
        epsilon_csf = np.hstack(
            (0, self._get_epsilon_c(sigma), self._get_epsilon_c(sigma)))
        sigma_csf = np.hstack((sigma, sigma, 0))
        return epsilon_csf, sigma_csf

    sig_eps_fn = Property(depends_on='+modified, reinf_ratio.+modified')

    @cached_property
    def _get_sig_eps_fn(self):
        '''Get the stress and strain arrays'''
        n_points = 100
        sigma_c_arr = np.linspace(0, self.sigma_cu, n_points)
        if self.sigma_cu == self.sigma_fu * self.V_f * cos(self.orientation):
            epsilon_c_arr = self._get_epsilon_c(sigma_c_arr)
        else:
            epsilon_c_arr = sigma_c_arr / self.E_c

        # stress with respect to reinforcement
        sigma_f_arr = sigma_c_arr / self.rho

        # stress of reinforcement with no matrix interaction
        sigma_fiber = epsilon_c_arr[[0, -1]] * self.material.E_f * self.rho

        return epsilon_c_arr, sigma_c_arr, sigma_f_arr, sigma_fiber
Esempio n. 2
0
class RunTable(SimDBClass):
    '''Manage the combinations of exec configurations and randomization patterns.
    '''

    name = Str(simdb=True)

    memsize = Float(1e4, simdb=True)

    s = Property(Instance(SPIRRID), depends_on='rf')

    @cached_property
    def _get_s(self):
        return SPIRRID(rf=self.rf,
                       min_eps=0.00,
                       max_eps=1.0,
                       n_eps=20,
                       compiler_verbose=0)

    rf = Instance(IRF, simdb=True)

    config_list = List(config=True)

    def _config_list_default(self):
        return ['I', 'IV']

    config_dict = Property(depends_on='config_list')

    @cached_property
    def _get_config_dict(self):
        cd = {}
        for config_idx in self.config_list:
            cd[config_idx] = config_dict[config_idx]
        return cd

    rand_list = List(rand=True)

    run_arr = Property(Array, depends_on='+rand,+config')

    @cached_property
    def _get_run_arr(self):
        # generate the runs to be performed
        run_table = [[
            SingleRun(run_table=self, config=config, rand_idx_arr=rand_idx_arr)
            for rand_idx_arr in self.rand_list
        ] for config in self.config_dict.items()]

        return array(run_table)

    exec_time_arr = Array
    n_int_arr = Array
    real_memsize_arr = Array

    calculate = Button()

    def _calculate_fired(self):
        s = self.run_arr.shape
        self.exec_time_arr = array(
            [run.exec_time for run in self.run_arr.flatten()]).reshape(s)
        self.n_int_arr = array([run.n_int
                                for run in self.run_arr.flatten()]).reshape(s)
        self.real_memsize_arr = array(
            [run.real_memsize for run in self.run_arr.flatten()]).reshape(s)
        self.save()
        self._redraw_fired()

    clear = Button()

    def _clear_fired(self):
        figure = self.figure
        figure.clear()
        self.data_changed = True

    figure = Instance(Figure, transient=True)

    def _figure_default(self):
        figure = Figure(facecolor='white')
        #figure.add_axes( [0.08, 0.13, 0.85, 0.74] )
        return figure

    data_changed = Event(True)

    normalized_numpy = Bool(True)
    c_code = Bool(False)

    redraw = Button()

    def _redraw_fired(self):
        figure = self.figure
        axes = figure.gca()
        self.plot(axes)
        self.data_changed = True

    redraw_in_window = Button()

    def _redraw_in_window_fired(self):
        figure = plt.figure(0)
        axes = figure.gca()
        self.plot(axes)
        plt.show()

    def plot(self, ax):

        exec_time_arr = self.exec_time_arr
        n_int_arr = self.n_int_arr[0, :]
        real_memsize_arr = self.real_memsize_arr[0, :]

        rand_arr = arange(len(self.rand_list)) + 1
        width = 0.45

        if exec_time_arr.shape[0] == 1:
            shift = width / 2.0
            ax.bar(rand_arr - shift,
                   exec_time_arr[0, :],
                   width,
                   color='lightgrey')

        elif self.exec_time_arr.shape[0] == 2:
            max_exec_time = nmax(exec_time_arr)

            ax.set_ylabel('$\mathrm{execution \, time \, [sec]}$', size=20)
            ax.set_xlabel(
                '$n_{\mathrm{rnd}}  \;-\; \mathrm{number \, of \, random \, parameters}$',
                size=20)

            ax.bar(rand_arr - width,
                   exec_time_arr[0, :],
                   width,
                   hatch='/',
                   color='white',
                   label='C')  # , color = 'lightgrey' )
            ax.bar(rand_arr,
                   exec_time_arr[1, :],
                   width,
                   color='lightgrey',
                   label='numpy')

            yscale = 1.25
            ax_xlim = rand_arr[-1] + 1
            ax_ylim = max_exec_time * yscale

            ax.set_xlim(0, ax_xlim)
            ax.set_ylim(0, ax_ylim)

            ax2 = ax.twinx()
            ydata = exec_time_arr[1, :] / exec_time_arr[0, :]
            ax2.plot(rand_arr,
                     ydata,
                     '-o',
                     color='black',
                     linewidth=1,
                     label='numpy/C')

            ax2.plot([rand_arr[0] - 1, rand_arr[-1] + 1], [1, 1], '-')
            ax2.set_ylabel(
                '$\mathrm{time}(  \mathsf{numpy}  ) / \mathrm{ time }(\mathsf{C}) \; [-]$',
                size=20)
            ax2_ylim = nmax(ydata) * yscale
            ax2_xlim = rand_arr[-1] + 1
            ax2.set_ylim(0, ax2_ylim)
            ax2.set_xlim(0, ax2_xlim)

            ax.set_xticks(rand_arr)
            ax.set_xticklabels(rand_arr, size=14)
            xticks = ['%.2g' % n_int for n_int in n_int_arr]
            ax3 = ax.twiny()
            ax3.set_xlim(0, rand_arr[-1] + 1)
            ax3.set_xticks(rand_arr)
            ax3.set_xlabel('$n_{\mathrm{int}}$', size=20)
            ax3.set_xticklabels(xticks, rotation=30)

            'set the tick label size of the lower X axis'
            X_lower_tick = 14
            xt = ax.get_xticklabels()
            for t in xt:
                t.set_fontsize(X_lower_tick)

            'set the tick label size of the upper X axis'
            X_upper_tick = 12
            xt = ax3.get_xticklabels()
            for t in xt:
                t.set_fontsize(X_upper_tick)

            'set the tick label size of the Y axes'
            Y_tick = 14
            yt = ax2.get_yticklabels() + ax.get_yticklabels()
            for t in yt:
                t.set_fontsize(Y_tick)

            'set the legend position and font size'
            leg_fontsize = 16
            leg = ax.legend(loc=(0.02, 0.83))
            for t in leg.get_texts():
                t.set_fontsize(leg_fontsize)
            leg = ax2.legend(loc=(0.705, 0.90))
            for t in leg.get_texts():
                t.set_fontsize(leg_fontsize)

    traits_view = View(Item('name'),
                       Item('memsize'),
                       Item('rf'),
                       Item('config_dict'),
                       Item('rand_list'),
                       HGroup(
                           Item('calculate', show_label=False),
                           Item('redraw', show_label=False),
                           Item('clear', show_label=False),
                           Item('redraw_in_window', show_label=False),
                       ),
                       Item('figure',
                            editor=MPLFigureEditor(),
                            resizable=True,
                            show_label=False),
                       buttons=['OK', 'Cancel'])
Esempio n. 3
0
class SimBT4PTDB(SimBT4PT):

    # vary the failure strain in PhiFnGeneralExtended:
    factor_eps_fail = Float(1.0, input=True, ps_levels=(1.0, 1.2, 3))

    #-----------------
    # composite cross section unit cell:
    #-----------------
    #
    ccs_unit_cell_key = Enum('FIL-10-09_2D-05-11_0.00462_all0',
                             CCSUnitCell.db.keys(),
                             simdb=True,
                             input=True,
                             auto_set=False,
                             enter_set=True)

    ccs_unit_cell_ref = Property(Instance(SimDBClass),
                                 depends_on='ccs_unit_cell_key')

    @cached_property
    def _get_ccs_unit_cell_ref(self):
        return CCSUnitCell.db[self.ccs_unit_cell_key]

    #-----------------
    # damage function:
    #-----------------
    #
    material_model = Str(input=True)

    def _material_model_default(self):
        # return the material model key of the first DamageFunctionEntry
        # This is necessary to avoid an ValueError at setup
        return self.ccs_unit_cell_ref.damage_function_list[0].material_model

    calibration_test = Str(input=True)

    def _calibration_test_default(self):
        # return the material model key of the first DamageFunctionEntry
        # This is necessary to avoid an ValueError at setup
        return self.ccs_unit_cell_ref.damage_function_list[0].calibration_test

    damage_function = Property(Instance(MFnLineArray),
                               depends_on='input_change')

    @cached_property
    def _get_damage_function(self):
        return self.ccs_unit_cell_ref.get_param(self.material_model,
                                                self.calibration_test)

    #-----------------
    # phi function extended:
    #-----------------
    #


#    phi_fn = Property(Instance(PhiFnGeneralExtended),
#                       depends_on = 'input_change,+ps_levels')
#    @cached_property
#    def _get_phi_fn(self):
#        return PhiFnGeneralExtended(mfn = self.damage_function,
#                                     factor_eps_fail = self.factor_eps_fail)

#-----------------
# phi function General:
#-----------------
#
# definition of 'phi_fn' in order to run scripting
# @todo: how can the implementation be changed in order to allow for parameter passing, e.g. 'factor_eps_fail', etc.
#
    phi_fn_class = Enum(
        PhiFnGeneral,
        [PhiFnGeneral, PhiFnGeneralExtended, PhiFnGeneralExtendedExp],
        input=True,
    )
    phi_fn = Property(Instance(phi_fn_class),
                      depends_on='phi_fn_class, input_change, +ps_levels')

    @cached_property
    def _get_phi_fn(self):
        return self.phi_fn_class(mfn=self.damage_function)

    #----------------------------------------------------------------------------------
    # material properties stored in 'ccs'
    #----------------------------------------------------------------------------------

    # concrete matrix E-modulus (taken from 'ccs_unit_cell')
    #
    E_m = Property(Float, depends_on='input_change')

    @cached_property
    def _get_E_m(self):
        E_m = self.ccs_unit_cell_ref.get_E_m_time(self.age)
        print 'E_m (from ccs)', E_m
        return E_m

    # composite E-modulus (taken from 'ccs_unit_cell')
    #
    E_c = Property(Float, depends_on='input_change')

    @cached_property
    def _get_E_c(self):
        E_c = self.ccs_unit_cell_ref.get_E_c_time(self.age)
        print 'E_c (from ccs)', E_c
        return E_c

    # Poisson's ratio
    #
    nu = Property(Float, depends_on='input_change')

    @cached_property
    def _get_nu(self):
        nu = self.ccs_unit_cell_ref.nu
        print 'nu (from ccs)', nu
        # set nu explicitly corresponding to settings in 'mats_calib_damage_fn'
        #
        print 'nu set explicitly to 0.20'
        nu = 0.2
        return nu
Esempio n. 4
0
class Distribution(HasTraits):
    ''' takes a scipy.stats distribution '''
    def __init__(self, distribution, **kw):
        super(Distribution, self).__init__(**kw)
        self.distribution = distribution
        self.changes()

    distribution = Instance(rv_continuous)

    def add_listeners(self):
        self.on_trait_change(self.changes, '+params,+moments')

    def remove_listeners(self):
        self.on_trait_change(self.changes, '+params,+moments', remove=True)

    # precision for displayed numbers = 12 numbers corresponds with the numbers
    # displayed in the UI.
    decimal.getcontext().prec = 12

    # event that triggers the replot in pdistrib.py
    changed = Event

    # freezes the location to 0.0
    loc_zero = Bool(True)

    # old values are compared with new values to recognize which value changed
    old_values = Array(Float, value=zeros(7))
    new_values = Array(Float, value=zeros(7))

    # statistical parameters
    loc = Float(0.0, auto_set=False, enter_set=True, params=True)
    scale = Float(1.0, auto_set=False, enter_set=True, params=True)
    shape = Float(1.0, auto_set=False, enter_set=True, params=True)

    # statistical moments
    mean = Float(0.0, auto_set=False, enter_set=True, moments=True)
    variance = Float(0.0, auto_set=False, enter_set=True, moments=True)
    skewness = Float(0.0, auto_set=False, enter_set=True, moments=True)
    kurtosis = Float(0.0, auto_set=False, enter_set=True, moments=True)

    stdev = Property(depends_on='variance')

    def _get_stdev(self):
        return self.variance**(0.5)

    def get_mean(self):
        ''' Methods for evaluating the statistical moments. Decimal together with
        precision are needed in order to get the number which is actually displayed
        in the UI. Otherwise clicking in the interface or pressing enter on the
        displayed values would trigger new computation because these values are a
        representation of the computed values rounded to 12 numbers. '''
        self.mean = float(Decimal(str((self.distr.stats('m')))) / 1)

    def get_variance(self):
        self.variance = float(Decimal(str((self.distr.stats('v')))) / 1)

    def get_skewness(self):
        self.skewness = float(Decimal(str((self.distr.stats('s')))) / 1)

    def get_kurtosis(self):
        self.kurtosis = float(Decimal(str((self.distr.stats('k')))) / 1)

    def get_moments(self, specify):
        ''' specify is a string containing some of the letters 'mvsk' '''
        self.remove_listeners()

        moments = self.distr.stats(specify)

        moment_names = ['mean', 'variance', 'skewness', 'kurtosis']
        for idx, value in enumerate(moments):
            setattr(self, moment_names[idx][0], value)

        dict = {
            'm': self.get_mean,
            'v': self.get_variance,
            's': self.get_skewness,
            'k': self.get_kurtosis
        }

        # chooses the methods to calculate the three moments which didn't
        # trigger this method
        for idx in specify:
            dict[idx]()

        self.add_listeners()

    def changes(self):
        ''' coordinates the methods for computing
        parameters and moments when a change has occurred '''
        self.remove_listeners()
        self.new_values = array([
            self.shape, self.loc, self.scale, self.mean, self.variance,
            self.skewness, self.kurtosis
        ])
        # test which parameters or moments are significant
        indexing = arange(7)[abs(self.old_values - self.new_values) != 0]
        if len(indexing) > 0 and indexing[0] < 3:
            self.get_moments('mvsk')
        elif len(indexing) > 0 and indexing[0] > 2:
            self.param_methods[indexing[0] - 3]()
        else:
            pass
        self.old_values = array([
            self.shape, self.loc, self.scale, self.mean, self.variance,
            self.skewness, self.kurtosis
        ])
        self.add_listeners()
        self.changed = True

    param_methods = Property(Array, depends_on='distribution')

    @cached_property
    def _get_param_methods(self):
        methods = array([
            self.mean_change, self.variance_change_scale,
            self.variance_change_shape, self.skewness_change,
            self.kurtosis_change
        ])
        if self.distribution.shapes == None:
            return methods[0:2]
        else:
            if len(self.distribution.shapes) == 1:
                return hstack((methods[0], methods[2:5]))
            else:
                print 'more than 1 shape parameters'

    def shape_scale_mean_var_residuum(self, params):
        shape = params[0]
        scale = params[1]
        res_mean = self.mean - self.distribution(shape, \
            loc=self.loc, scale=scale).stats('m')
        res_var = self.variance - self.distribution(shape, \
            loc=self.loc, scale=scale).stats('v')
        return [res_mean, res_var]

    def mean_change(self):
        if self.loc_zero == True and self.distribution.__dict__[
                'shapes'] != None:
            self.loc = 0.0
            result = fsolve(self.shape_scale_mean_var_residuum, [1., 1.])
            self.shape = float(Decimal(str(result[0].sum())) / 1)
            self.scale = float(Decimal(str(result[1].sum())) / 1)
        else:
            self.loc += float(
                Decimal(str(self.mean - self.distr.stats('m'))) / 1)

    def scale_variance_residuum(self, scale):
        return self.variance - self.distribution(\
            loc=self.loc, scale=scale).stats('v')

    def variance_change_scale(self):
        self.scale = float(
            Decimal(str(fsolve(self.scale_variance_residuum, 1).sum())) / 1)

    def shape_variance_residuum(self, shape):
        return self.variance - self.distribution(shape, \
                loc=self.loc, scale=self.scale).stats('v')

    def variance_change_shape(self):
        self.shape = float(
            Decimal(str(fsolve(self.shape_variance_residuum, 1).sum())) / 1)
        self.get_moments('msk')

    def shape_skewness_residuum(self, shape):
        return self.skewness - self.distribution(shape, \
                loc=self.loc, scale=self.scale).stats('s')

    def skewness_change(self):
        self.shape = float(
            Decimal(str(fsolve(self.shape_skewness_residuum, 1).sum())) / 1)
        self.get_moments('mvk')

    def shape_kurtosis_residuum(self, shape):
        return self.kurtosis - self.distribution(shape, \
                loc=self.loc, scale=self.scale).stats('k')

    def kurtosis_change(self):
        self.shape = float(
            Decimal(str(fsolve(self.shape_kurtosis_residuum, 1).sum())) / 1)
        self.get_moments('mvs')

    distr = Property(depends_on='+params')

    @cached_property
    def _get_distr(self):
        if self.distribution.__dict__['numargs'] == 0:
            return self.distribution(self.loc, self.scale)
        elif self.distribution.__dict__['numargs'] == 1:
            return self.distribution(self.shape, self.loc, self.scale)

    def default_traits_view(self):
        '''checks the number of shape parameters of the distribution and adds them to
        the view instance'''
        label = str(self.distribution.name)
        if self.distribution.shapes == None:
            params = Item()
            if self.mean == infty:
                moments = Item(label='No finite moments defined')
            else:
                moments = Item('mean', label='mean'), \
                            Item('variance', label='variance'), \
                            Item('stdev', label='st. deviation', style='readonly')

        elif len(self.distribution.shapes) == 1:
            params = Item('shape', label='shape')
            if self.mean == infty:
                moments = Item(label='No finite moments defined')
            else:
                moments = Item('mean', label='mean'), \
                            Item('variance', label='variance'), \
                            Item('stdev', label='st. deviation', style='readonly'), \
                            Item('skewness', label='skewness'), \
                            Item('kurtosis', label='kurtosis'),
        else:
            params = Item()
            moments = Item()

        view = View(VGroup(Label(label, emphasized=True),
                           Group(params,
                                 Item('loc', label='location'),
                                 Item('scale', label='scale'),
                                 Item('loc_zero', label='loc = 0.0'),
                                 show_border=True,
                                 label='parameters',
                                 id='pdistrib.distribution.params'),
                           Group(
                               moments,
                               id='pdistrib.distribution.moments',
                               show_border=True,
                               label='moments',
                           ),
                           id='pdistrib.distribution.vgroup'),
                    kind='live',
                    resizable=True,
                    id='pdistrib.distribution.view')
        return view
Esempio n. 5
0
class POShortFiber(RF):
    '''
    Pullout of fiber from a stiff matrix;
    stress criterion for debonding, free fiber end
    '''

    implements(IRF)

    title = Str('pullout - short fiber with constant friction')
    image = Image('pics/cb_short_fiber.jpg')

    xi = Float(0.0179,
               auto_set=False,
               enter_set=True,
               input=True,
               distr=['weibull_min', 'uniform'])

    E_f = Float(200e+3,
                auto_set=False,
                enter_set=True,
                desc='filament stiffness [N/mm2]',
                distr=['uniform', 'norm'],
                scale=210e3,
                shape=0)

    D_f = Float(0.3,
                auto_set=False,
                enter_set=True,
                desc='filament diameter [mm]',
                distr=['uniform', 'norm'],
                scale=0.5,
                shape=0)

    le = Float(8.5,
               auto_set=False,
               enter_set=True,
               desc='embedded lentgh [mm]',
               distr=['uniform'],
               scale=8.5,
               shape=0)

    L_f = Float(17.0,
                auto_set=False,
                enter_set=True,
                desc='fiber length [mm]',
                distr=['uniform', 'norm'],
                scale=30,
                shape=0)

    tau = Float(1.76,
                auto_set=False,
                enter_set=True,
                desc='bond shear stress [N/mm2]',
                distr=['norm', 'uniform'],
                scale=1.76,
                shape=0.5)

    f = Float(0.03,
              auto_set=False,
              enter_set=True,
              desc='snubbing coefficient',
              distr=['uniform', 'norm'],
              scale=0.05,
              shape=0)

    phi = Float(0.0,
                auto_set=False,
                enter_set=True,
                desc='inclination angle',
                distr=['sin2x', 'sin_distr'],
                scale=1.0,
                shape=0)

    l = Float(0.0,
              auto_set=False,
              enter_set=True,
              distr=['uniform'],
              desc='free length')

    theta = Float(0.01,
                  auto_set=False,
                  enter_set=True,
                  distr=['uniform', 'norm'],
                  desc='slack')

    u = Float(ctrl_range=(0, 0.01, 100), auto_set=False, enter_set=True)

    x_label = Str('displacement [mm]', enter_set=True, auto_set=False)
    y_label = Str('force [N]', enter_set=True, auto_set=False)

    C_code = ''

    def __call__(self, u, tau, L_f, D_f, E_f, le, phi, f, l, theta, xi):

        l = l * (1 + theta)
        u = u - theta * l
        T = tau * pi * D_f
        E = E_f
        A = D_f**2 / 4. * pi

        # debonding stage
        q_deb = -l * T + sqrt((l * T)**2 + 2 * E * A * T * u * H(u))

        # displacement at which debonding is finished
        u0 = le * T * (le + 2 * l) / 2 / E_f / A

        q_pull = le * T * ((u0 - u) / (le - u0) + 1)
        q = q_deb * H(le * T - q_deb) + q_pull * H(q_deb - le * T)

        # include inclination influence
        q = q * H(q) * e**(f * phi)

        # include breaking strain
        q = q * H(A * E_f * xi - q)
        return q

    def get_q_x(self, u, x, tau, L_f, D_f, E_f, z, phi, f, l, theta, xi):
        q = self.__call__(u, tau, L_f, D_f, E_f, z, phi, f, l, theta, xi)
        l = l * (1 + theta)
        T = tau * pi * D_f
        qfree = q
        qbond = q - T * (x - l)

        return qfree * H(l - x) + qbond * H(x - l)

    traits_view = View(Item('E_f', label='fiber E-mod'),
                       Item('D_f', label='fiber diameter'),
                       Item('f', label='snubbing coef.'),
                       Item('phi', label='inclination angle'),
                       Item('le', label='embedded length'),
                       Item('tau', label='frictional coef.'),
                       resizable=True,
                       scrollable=True,
                       height=0.8,
                       width=0.8,
                       buttons=[OKButton, CancelButton])
Esempio n. 6
0
class ExpST(ExType):
    '''Experiment: Slab Test
    '''
#    label = Str('slab test')
    implements(IExType)

    #--------------------------------------------------------------------
    # register a change of the traits with metadata 'input'
    #--------------------------------------------------------------------

    input_change = Event
    @on_trait_change('+input, ccs.input_change, +ironing_param')
    def _set_input_change(self):
        self.input_change = True

    #--------------------------------------------------------------------------------
    # specify inputs:
    #--------------------------------------------------------------------------------

    edge_length = Float(1.25, unit='m', input=True, table_field=True,
                           auto_set=False, enter_set=True)
    thickness = Float(0.06, unit='m', input=True, table_field=True,
                           auto_set=False, enter_set=True)

    # age of the concrete at the time of testing
    age = Int(28, unit='d', input=True, table_field=True,
                             auto_set=False, enter_set=True)
    loading_rate = Float(2.0, unit='mm/min', input=True, table_field=True,
                            auto_set=False, enter_set=True)

    #--------------------------------------------------------------------------
    # composite cross section
    #--------------------------------------------------------------------------

    ccs = Instance(CompositeCrossSection)
    def _ccs_default(self):
        '''default settings correspond to
        setup '7u_MAG-07-03_PZ-0708-1'
        '''
        fabric_layout_key = '2D-05-11'
#        fabric_layout_key = 'MAG-07-03'
#        fabric_layout_key = '2D-02-06a'
#        concrete_mixture_key = 'PZ-0708-1'
#        concrete_mixture_key = 'FIL-10-09'
#        concrete_mixture_key = 'barrelshell'
        concrete_mixture_key = 'PZ-0708-1'
#        orientation_fn_key = 'all0'
        orientation_fn_key = '90_0'
        n_layers = 2
        s_tex_z = 0.015 / (n_layers + 1)
        ccs = CompositeCrossSection (
                    fabric_layup_list=[
                            plain_concrete(0.035),
#                            plain_concrete(s_tex_z * 0.5),
                            FabricLayUp (
                                   n_layers=n_layers,
                                   orientation_fn_key=orientation_fn_key,
                                   s_tex_z=s_tex_z,
                                   fabric_layout_key=fabric_layout_key
                                   ),
#                            plain_concrete(s_tex_z * 0.5)
                            plain_concrete(0.5)
                                        ],
                    concrete_mixture_key=concrete_mixture_key
                    )
        return ccs

    #--------------------------------------------------------------------------
    # Get properties of the composite
    #--------------------------------------------------------------------------

    # E-modulus of the composite at the time of testing
    E_c = Property(Float, unit='MPa', depends_on='input_change', table_field=True)
    def _get_E_c(self):
        return self.ccs.get_E_c_time(self.age)

    # E-modulus of the composite after 28 days
    E_c28 = DelegatesTo('ccs', listenable=False)

    # reinforcement ration of the composite
    rho_c = DelegatesTo('ccs', listenable=False)

    #--------------------------------------------------------------------------------
    # define processing
    #--------------------------------------------------------------------------------

    # put this into the ironing procedure processor
    #
    jump_rtol = Float(0.1,
                      auto_set=False, enter_set=True,
                      ironing_param=True)


    data_array_ironed = Property(Array(float),
                                  depends_on='data_array, +ironing_param, +axis_selection')
    @cached_property
    def _get_data_array_ironed(self):
        '''remove the jumps in the displacement curves
        due to resetting the displacement gauges.
        '''
        print '*** curve ironing activated ***'

        # each column from the data array corresponds to a measured parameter
        # e.g. displacement at a given point as function of time u = f(t))
        #
        data_array_ironed = copy(self.data_array)

        for idx in range(self.data_array.shape[1]):

            # use ironing method only for columns of the displacement gauges.
            #
            if self.names_and_units[0][ idx ] != 'Kraft' and \
                self.names_and_units[0][ idx ] != 'Bezugskanal' and \
                self.names_and_units[0][ idx ] != 'Weg':

                # 1d-array corresponding to column in data_array
                data_arr = copy(data_array_ironed[:, idx])

                # get the difference between each point and its successor
                jump_arr = data_arr[1:] - data_arr[0:-1]

                # get the range of the measured data
                data_arr_range = max(data_arr) - min(data_arr)

                # determine the relevant criteria for a jump
                # based on the data range and the specified tolerances:
                jump_crit = self.jump_rtol * data_arr_range

                # get the indexes in 'data_column' after which a
                # jump exceeds the defined tolerance criteria
                jump_idx = where(fabs(jump_arr) > jump_crit)[0]

                print 'number of jumps removed in data_arr_ironed for', self.names_and_units[0][ idx ], ': ', jump_idx.shape[0]
                # glue the curve at each jump together
                for jidx in jump_idx:
                    # get the offsets at each jump of the curve
                    shift = data_arr[jidx + 1] - data_arr[jidx]
                    # shift all succeeding values by the calculated offset
                    data_arr[jidx + 1:] -= shift

                data_array_ironed[:, idx] = data_arr[:]

        return data_array_ironed


    @on_trait_change('+ironing_param')
    def process_source_data(self):
        '''read in the measured data from file and assign
        attributes after array processing.

        NOTE: if center displacement gauge ('WA_M') is missing the measured
        displacement of the cylinder ('Weg') is used instead.
        A minor mistake is made depending on how much time passes
        before the cylinder has contact with the slab.
        '''
        print '*** process source data ***'

        self._read_data_array()
        # curve ironing:
        #
        self.processed_data_array = self.data_array_ironed

        # set attributes:
        #
        self._set_array_attribs()

        if 'WA_M' not in self.factor_list:
            print '*** NOTE: Displacement gauge at center ("WA_M") missing. Cylinder displacement ("Weg") is used instead! ***'
            self.WA_M = self.Weg


    #--------------------------------------------------------------------------------
    # plot templates
    #--------------------------------------------------------------------------------

    plot_templates = {'force / deflection (all)' : '_plot_force_deflection',
#                      'force / average deflection (c; ce; e) interpolated'    : '_plot_force_deflection_avg_interpolated',
#                      'force / deflection (center)'               : '_plot_force_center_deflection',
#                      'smoothed force / deflection (center)'      : '_plot_force_center_deflection_smoothed',
#                      'force / deflection (edges)'                : '_plot_force_edge_deflection',
#                      'force / deflection (center-edges)'         : '_plot_force_center_edge_deflection',
#                      'force / average deflection (edges)'        : '_plot_force_edge_deflection_avg',
#                      'force / average deflection (center-edges)' : '_plot_force_center_edge_deflection_avg',
#                      'force / average deflection (c; ce; e)'     : '_plot_force_deflection_avg',
#                      'force / deflection (center) interpolated'  : '_plot_force_center_deflection_interpolated',
#                      'force / deflection (corner)'               : '_plot_force_corner_deflection',
#                      'edge_deflection_avg (front/back) / edge_deflection_avg (left/right)' : '_plot_edge_deflection_edge_deflection_avg',

                     }

    default_plot_template = 'force / deflection (center)'


    n_fit_window_fraction = Float(0.1)

    # get only the ascending branch of the response curve
    #
    max_force_idx = Property(Int)
    def _get_max_force_idx(self):
        '''get the index of the maximum force'''
        return argmax(-self.Kraft)

    f_asc = Property(Array)
    def _get_f_asc(self):
        '''get only the ascending branch of the response curve'''
        return -self.Kraft[:self.max_force_idx + 1]

    w_asc = Property(Array)
    def _get_w_asc(self):
        '''get only the ascending branch of the response curve'''
        return -self.WA_M[:self.max_force_idx + 1]

    n_points = Property(Int)
    def _get_n_points(self):
        return int(self.n_fit_window_fraction * len(self.w_asc))

    f_smooth = Property()
    def _get_f_smooth(self):
        return smooth(self.f_asc, self.n_points, 'flat')

    w_smooth = Property()
    def _get_w_smooth(self):
        return smooth(self.w_asc, self.n_points, 'flat')

    def _plot_force_deflection(self, axes, offset_w=0., color='blue', linewidth=1.5, linestyle='-'):
        '''plot the F-w-diagramm for all displacement gauges including maschine displacement
        '''
        xkey = 'deflection [mm]'
        ykey = 'force [kN]'

        max_force_idx = self.max_force_idx
#        max_force_idx = -2
        f_asc = -self.Kraft[:max_force_idx + 1]

        print 'self.factor_list', self.factor_list
        header_string = ''
        for i in self.factor_list[2:]:
            header_string = header_string + i + '; '
            T_arr = -getattr(self, i)
            T_asc = T_arr[:max_force_idx + 1]
            axes.plot(T_asc, f_asc, label=i)

        axes.legend()

        img_dir = os.path.join(simdb.exdata_dir, 'img_dir')
        # check if directory exist otherwise create
        #
        if os.path.isdir(img_dir) == False:
            os.makedirs(img_dir)
        test_series_dir = os.path.join(img_dir, 'slab_test_astark')
        # check if directory exist otherwise create
        #
        if os.path.isdir(test_series_dir) == False:
            os.makedirs(test_series_dir)
        out_file = os.path.join(test_series_dir, self.key)

        np.savetxt(out_file, self.processed_data_array, delimiter=';')

        # workaround for old numpy.savetxt version:
        f = open(out_file, 'r')
        temp = f.read()
        f.close()

        f = open(out_file, 'w')
        f.write(header_string)

        f.write(temp)
        f.close()



    def _plot_force_center_deflection(self, axes, offset_w=0., color='blue', linewidth=1.5, linestyle='-'):
        '''plot the F-w-diagramm for the center (c) deflection
        '''
        xkey = 'deflection [mm]'
        ykey = 'force [kN]'
        xdata = -self.WA_M
        ydata = -self.Kraft

        xdata += offset_w
#        axes.set_xlabel('%s' % (xkey,))
#        axes.set_ylabel('%s' % (ykey,))
        axes.plot(xdata, ydata, color=color, linewidth=linewidth, linestyle=linestyle)

    def _plot_force_corner_deflection(self, axes):
        '''plot the F-w-diagramm for the corner deflection (at the center of one of the supports)
        '''
        xkey = 'deflection [mm]'
        ykey = 'force [kN]'
        xdata = -self.WA_Eck
        ydata = -self.Kraft

#        axes.set_xlabel('%s' % (xkey,))
#        axes.set_ylabel('%s' % (ykey,))
        axes.plot(xdata, ydata
                       # color = c, linewidth = w, linestyle = s
                       )

    def _plot_force_center_deflection_smoothed(self, axes):
        '''plot the F-w-diagramm for the center (c) deflection (smoothed curves)
        '''
        axes.plot(self.w_smooth, self.f_smooth, color='blue', linewidth=1)
#        secant_stiffness_w10 = (f_smooth[10] - f_smooth[0]) / (w_smooth[10] - w_smooth[0])
#        w0_lin = array([0.0, w_smooth[10] ], dtype = 'float_')
#        f0_lin = array([0.0, w_smooth[10] * secant_stiffness_w10 ], dtype = 'float_')
        # axes.plot( w0_lin, f0_lin, color = 'black' )

    def _plot_force_center_deflection_interpolated(self, axes, linestyle='-', linewidth=1.5, plot_elastic_stiffness=True):
        '''plot the F-w-diagramm for the center (c) deflection (interpolated initial stiffness)
        '''
        # get the index of the maximum stress
        max_force_idx = argmax(-self.Kraft)
        # get only the ascending branch of the response curve
        f_asc = -self.Kraft[:max_force_idx + 1]
        w_m = -self.WA_M[:max_force_idx + 1]

#        w_m -= 0.17
#        axes.plot(w_m, f_asc, color = 'blue', linewidth = 1)

        # move the starting point of the center deflection curve to the point where the force starts
        # (remove offset in measured displacement where there is still no force measured)
        #
        idx_0 = np.where(f_asc > 0.0)[0][0]

        f_asc_cut = np.hstack([f_asc[ idx_0: ]])
        w_m_cut = np.hstack([w_m[ idx_0: ]]) - w_m[ idx_0 ]
#        print 'f_asc_cut.shape', f_asc_cut.shape
#        fw_arr = np.hstack([f_asc_cut[:, None], w_m_cut[:, None]])
#        print 'fw_arr.shape', fw_arr.shape
#        np.savetxt('ST-6c-2cm-TU_bs2_f-w_asc.csv', fw_arr, delimiter=';')
        axes.plot(w_m_cut, f_asc_cut, color='k', linewidth=linewidth, linestyle=linestyle)

        # composite E-modulus
        #
        E_c = self.E_c
        print 'E_c', E_c

        if self.thickness == 0.02 and self.edge_length == 0.80 and plot_elastic_stiffness == True:
            K_linear = E_c / 24900. * 1.056  # [MN/m]=[kN/mm] bending stiffness with respect to center force
            max_f = f_asc_cut[-1]
            w_linear = np.array([0., max_f / K_linear])
            f_linear = np.array([0., max_f])
            axes.plot(w_linear, f_linear, linewidth=linewidth, linestyle='--', color='k')
        if self.thickness == 0.03 and self.edge_length == 1.25 and plot_elastic_stiffness == True:
            K_linear = E_c / 24900. * 1.267  # [MN/m]=[kN/mm] bending stiffness with respect to center force
            max_f = f_asc_cut[-1]
            w_linear = np.array([0., max_f / K_linear])
            f_linear = np.array([0., max_f])
            axes.plot(w_linear, f_linear, linewidth=linewidth, linestyle='--', color='k')
        if self.thickness == 0.06 and self.edge_length == 1.25 and plot_elastic_stiffness == True:
            K_linear = E_c / 24900. * 10.14  # [MN/m]=[kN/mm] bending stiffness with respect to center force
            max_f = f_asc_cut[-1]
            w_linear = np.array([0., max_f / K_linear])
            f_linear = np.array([0., max_f])
            axes.plot(w_linear, f_linear, linewidth=linewidth, linestyle='--', color='k')

    def _plot_force_edge_deflection(self, axes):
        '''plot the F-w-diagramm for the edge (e) deflections
        '''
        max_force_idx = self.max_force_idx
        f_asc = self.f_asc
        w_v_asc = -self.WA_V[:max_force_idx + 1]
        w_h_asc = -self.WA_H[:max_force_idx + 1]
        w_l_asc = -self.WA_L[:max_force_idx + 1]
        w_r_asc = -self.WA_R[:max_force_idx + 1]
        axes.plot(w_v_asc, f_asc, color='blue', linewidth=1)
        axes.plot(w_h_asc, f_asc, color='blue', linewidth=1)
        axes.plot(w_l_asc, f_asc, color='green', linewidth=1)
        axes.plot(w_r_asc, f_asc, color='green', linewidth=1)

    def _plot_force_edge_deflection_avg(self, axes):
        '''plot the average F-w-diagramm for the edge (e) deflections
        '''
        max_force_idx = self.max_force_idx
        f_asc = self.f_asc
        w_v_asc = -self.WA_V[:max_force_idx + 1]
        w_h_asc = -self.WA_H[:max_force_idx + 1]
        w_l_asc = -self.WA_L[:max_force_idx + 1]
        w_r_asc = -self.WA_R[:max_force_idx + 1]
        # get the average displacement values of the corresponding displacement gauges
        w_vh_asc = (w_v_asc + w_h_asc) / 2
        w_lr_asc = (w_l_asc + w_r_asc) / 2
        axes.plot(w_vh_asc, f_asc, color='blue', linewidth=1, label='w_vh')
        axes.plot(w_lr_asc, f_asc, color='blue', linewidth=1, label='w_lr')
        axes.legend()

    def _plot_edge_deflection_edge_deflection_avg(self, axes):
        '''plot the average edge (e) deflections for the front/back and left/right
        '''
        max_force_idx = self.max_force_idx
        w_v_asc = -self.WA_V[:max_force_idx + 1]
        w_h_asc = -self.WA_H[:max_force_idx + 1]
        w_l_asc = -self.WA_L[:max_force_idx + 1]
        w_r_asc = -self.WA_R[:max_force_idx + 1]
        # get the average displacement values of the corresponding displacement gauges
        w_vh_asc = (w_v_asc + w_h_asc) / 2
        w_lr_asc = (w_l_asc + w_r_asc) / 2
        axes.plot(w_vh_asc, w_lr_asc, color='blue', linewidth=1, label='w_vh / w_lr')
        axes.plot(np.array([0, w_vh_asc[-1]]), np.array([0, w_vh_asc[-1]]), color='k', linewidth=1, linestyle='-')
        axes.legend()

    def _plot_force_center_edge_deflection(self, axes):
        '''plot the F-w-diagramm for the center-edge (ce) deflections
        '''
        max_force_idx = argmax(-self.Kraft)
        # get only the ascending branch of the response curve
        f_asc = -self.Kraft[:max_force_idx + 1]
        w_ml_asc = -self.WA_ML[:max_force_idx + 1]
        w_mr_asc = -self.WA_MR[:max_force_idx + 1]
        axes.plot(w_ml_asc, f_asc, color='blue', linewidth=1, label='w_ml')
        axes.plot(w_mr_asc, f_asc, color='blue', linewidth=1, label='w_mr')
        axes.legend()

    def _plot_force_center_edge_deflection_avg(self, axes):
        '''plot the average F-w-diagramm for the center-edge (ce) deflections
        '''
        # get the index of the maximum stress
        max_force_idx = argmax(-self.Kraft)
        # get only the ascending branch of the response curve
        f_asc = -self.Kraft[:max_force_idx + 1]
        w_ml_asc = -self.WA_ML[:max_force_idx + 1]
        w_mr_asc = -self.WA_MR[:max_force_idx + 1]
        # get the average displacement values of the corresponding displacement gauges
        w_mlmr_asc = (w_ml_asc + w_mr_asc) / 2
        axes.plot(w_mlmr_asc, f_asc, color='blue', linewidth=1)

    def _plot_force_deflection_avg(self, axes):
        '''plot the average F-w-diagramms for the center(c), center-edge (ce) and edge(vh) and edge (lr) deflections
        '''
        # get the index of the maximum stress
        max_force_idx = argmax(-self.Kraft)
        # get only the ascending branch of the response curve
        f_asc = -self.Kraft[:max_force_idx + 1]

        w_m = -self.WA_M[:max_force_idx + 1]
        axes.plot(w_m, f_asc, color='blue', linewidth=1)

        # ## center-edge deflection (ce)
        w_ml_asc = -self.WA_ML[:max_force_idx + 1]
        w_mr_asc = -self.WA_MR[:max_force_idx + 1]
        # get the average displacement values of the corresponding displacement gauges
        w_mlmr_asc = (w_ml_asc + w_mr_asc) / 2
        axes.plot(w_mlmr_asc, f_asc, color='red', linewidth=1)

        # ## edge deflections (e)
        w_v_asc = -self.WA_V[:max_force_idx + 1]
        w_h_asc = -self.WA_H[:max_force_idx + 1]
        w_l_asc = -self.WA_L[:max_force_idx + 1]
        w_r_asc = -self.WA_R[:max_force_idx + 1]
        # get the average displacement values of the corresponding displacement gauges
        w_vh_asc = (w_v_asc + w_h_asc) / 2
        w_lr_asc = (w_l_asc + w_r_asc) / 2
        axes.plot(w_vh_asc, f_asc, color='green', linewidth=1, label='w_vh')
        axes.plot(w_lr_asc, f_asc, color='blue', linewidth=1, label='w_lr')

#        # set axis-labels
#        xkey = 'deflection [mm]'
#        ykey = 'force [kN]'
#        axes.set_xlabel('%s' % (xkey,))
#        axes.set_ylabel('%s' % (ykey,))

    def _plot_force_deflection_avg_interpolated(self, axes, linewidth=1):
        '''plot the average F-w-diagrams for the center(c), center-edge (ce) and edge(vh) and edge (lr) deflections
        NOTE: center deflection curve is cut at its starting point in order to remove offset in the dispacement meassurement
        '''
        # get the index of the maximum stress
        max_force_idx = argmax(-self.Kraft)
        # get only the ascending branch of the response curve
        f_asc = -self.Kraft[:max_force_idx + 1]
        w_m = -self.WA_M[:max_force_idx + 1]

#        w_m -= 0.17
#        axes.plot(w_m, f_asc, color = 'blue', linewidth = 1)

        # move the starting point of the center deflection curve to the point where the force starts
        # (remove offset in measured displacement where there is still no force measured)
        #
        idx_0 = np.where(f_asc > 0.05)[0][0]

        f_asc_cut = f_asc[ idx_0: ]
        w_m_cut = w_m[ idx_0: ] - w_m[ idx_0 ]
        axes.plot(w_m_cut, f_asc_cut, color='k', linewidth=linewidth)

        # plot machine displacement (hydraulic cylinder)
        #
#        Weg_asc = -self.Weg[ :max_force_idx + 1 ]
#        axes.plot(Weg_asc, f_asc, color='k', linewidth=1.5)

        # ## center-edge deflection (ce)
        w_ml_asc = -self.WA_ML[:max_force_idx + 1]
        w_mr_asc = -self.WA_MR[:max_force_idx + 1]
        # get the average displacement values of the corresponding displacement gauges
        w_mlmr_asc = (w_ml_asc + w_mr_asc) / 2
#        axes.plot(w_mlmr_asc, f_asc, color='red', linewidth=1)
        axes.plot(w_ml_asc, f_asc, color='k', linewidth=linewidth)
        axes.plot(w_mr_asc, f_asc, color='k', linewidth=linewidth)

        # ## edge deflections (e)
        w_v_asc = -self.WA_V[:max_force_idx + 1]
        w_h_asc = -self.WA_H[:max_force_idx + 1]
        w_l_asc = -self.WA_L[:max_force_idx + 1]
        w_r_asc = -self.WA_R[:max_force_idx + 1]
        axes.plot(w_v_asc, f_asc, color='grey', linewidth=linewidth)
        axes.plot(w_h_asc, f_asc, color='grey', linewidth=linewidth)
        axes.plot(w_l_asc, f_asc, color='k', linewidth=linewidth)
        axes.plot(w_r_asc, f_asc, color='k', linewidth=linewidth)

        # get the average displacement values of the corresponding displacement gauges
#        w_vh_asc = (w_v_asc + w_h_asc) / 2
#        w_lr_asc = (w_l_asc + w_r_asc) / 2
#        axes.plot(w_vh_asc, f_asc, color='green', linewidth=1, label='w_vh')
#        axes.plot(w_lr_asc, f_asc, color='blue', linewidth=1, label='w_lr')

        # save 'F-w-arr_m-mlmr-vh-lr' in directory "/simdb/simdata/exp_st"
#        simdata_dir = os.path.join(simdb.simdata_dir, 'exp_st')
#        if os.path.isdir(simdata_dir) == False:
#            os.makedirs(simdata_dir)
#        filename = os.path.join(simdata_dir, 'F-w-arr_m-mlmr-vh-lr_' + self.key + '.csv')
#        Fw_m_mlmr_vh_lr_arr = np.hstack([f_asc[:, None], w_m[:, None] - w_m[ idx_0 ], w_mlmr_asc[:, None], w_vh_asc[:, None], w_lr_asc[:, None]])
#        print 'Fw_m_mlmr_vh_lr_arr'
#        np.savetxt(filename, Fw_m_mlmr_vh_lr_arr, delimiter=';')
#        print 'F-w-curves for center, middle, edges saved to file %s' % (filename)

    #--------------------------------------------------------------------------------
    # view
    #--------------------------------------------------------------------------------

    traits_view = View(VGroup(
                         Group(
                              Item('jump_rtol', format_str="%.4f"),
                              label='curve_ironing'
                              ),
                         Group(
                              Item('thickness', format_str="%.3f"),
                              Item('edge_length', format_str="%.3f"),
                              label='geometry'
                              ),
                         Group(
                              Item('loading_rate'),
                              Item('age'),
                              label='loading rate and age'
                              ),
                         Group(
                              Item('E_c', show_label=True, style='readonly', format_str="%.0f"),
                              Item('ccs@', show_label=False),
                              label='composite cross section'
                              )
                         ),
                        scrollable=True,
                        resizable=True,
                        height=0.8,
                        width=0.6
                        )
Esempio n. 7
0
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]
Esempio n. 8
0
class MRone(MushRoofModel):

    implements(ISimModel)
    mushroof_part = 'one'
    #===============================================================================
    # fe_grid
    #===============================================================================

    n_elems_xy_quarter = Int(10, input=True)  # , ps_levels = [4, 16, 5] )
    n_elems_z = Int(1, input=True)  # , ps_levels = [1, 2, 1] )
    n_elems_col_z = Int(10, input=True, ps_levels=[5, 20, 3])
    n_elems_col_xy = Int(2, input=True, ps_levels=[2, 4, 1])

    shift_elems = True

    vtk_r = Float(1.00)

    # default roof
    fe_roof = Instance((FETSEval), depends_on='+ps_levels, +input')

    def _fe_roof_default(self):
        fets = self.fe_quad_serendipity_roof
        fets.vtk_r *= self.vtk_r
        return fets

    # default plate
    fe_plate = Instance((FETSEval), depends_on='+ps_levels, +input')

    def _fe_plate_default(self):
        fets = self.fe_quad_serendipity_plate
        fets.ngp_r = 3
        fets.ngp_s = 3
        fets.ngp_t = 3
        fets.vtk_r *= self.vtk_r
        return fets

    # shell
    #
    hp_shell = Property(Instance(HPShell), depends_on='+ps_levels, +input')

    @cached_property
    def _get_hp_shell(self):
        return HPShell(length_xy_quarter=self.length_xy_quarter,
                       length_z=self.length_z,
                       n_elems_xy_quarter=self.n_elems_xy_quarter,
                       n_elems_z=self.n_elems_z,
                       scalefactor_delta_h=self.scalefactor_delta_h,
                       const_reinf_layer_elem=self.const_reinf_layer_elem,
                       width_top_col=self.width_top_col,
                       mushroof_part=self.mushroof_part,
                       shift_array=self.shift_array,
                       X0=self.X0)

    # plate
    #
    plate = Property(Instance(GEOColumn), depends_on='+ps_levels, +input')

    @cached_property
    def _get_plate(self):
        return GEOColumn(
            width_top=self.width_top_col,
            width_bottom=self.width_top_col,
            X0=[3.5, 3.5, -self.t_plate],  # - 0.25],
            h_col=self.t_plate)

    # column
    #
#    X0_column = Array( [ 4., 4., -3.] )
    column = Property(Instance(GEOColumn), depends_on='+ps_levels, +input')

    @cached_property
    def _get_column(self):
        return GEOColumn(
            width_top_col=self.width_top_col,
            width_bottom_col=self.width_bottom_col,
            h_col=self.h_col - self.t_plate,
            # r_pipe = self.r_pipe,
            X0=[3.5, 3.5, -(self.h_col)])  # - 0.5] )

    # default column
    fe_column = Instance((FETSEval),
                         transient=True,
                         depends_on='+ps_levels, +input')

    def _fe_column_default(self):
        fets = self.fe_quad_serendipity_column
        fets.vtk_r *= self.vtk_r
        return fets

    fe_grid_roof = Property(Instance(FEGrid), depends_on='+ps_levels, +input')

    @cached_property
    def _get_fe_grid_roof(self):
        return FEGrid(coord_min=(0.0, 0.0, 0.0),
                      coord_max=(1.0, 1.0, 1.0),
                      geo_transform=self.hp_shell,
                      shift_array=self.shift_array,
                      shape=(self.n_elems_xy, self.n_elems_xy, self.n_elems_z),
                      fets_eval=self.fe_roof)

    fe_grid_column = Property(Instance(FEGrid),
                              depends_on='+ps_levels, +input')

    @cached_property
    def _get_fe_grid_column(self):
        return FEGrid(coord_min=(0.0, 0.0, 0.0),
                      coord_max=(1.0, 1.0, 1.0),
                      geo_transform=self.column,
                      shape=(self.n_elems_col_xy, self.n_elems_col_xy,
                             self.n_elems_col_z),
                      fets_eval=self.fe_column)

    fe_grid_plate = Property(Instance(FEGrid), depends_on='+ps_levels, +input')

    @cached_property
    def _get_fe_grid_plate(self):
        return FEGrid(coord_min=(0.0, 0.0, 0.0),
                      coord_max=(1.0, 1.0, 1.0),
                      geo_transform=self.plate,
                      shape=(self.n_elems_col_xy, self.n_elems_col_xy, 2),
                      fets_eval=self.fe_plate)

    #===============================================================================
    # ps_study
    #===============================================================================
    def peval(self):
        '''
        Evaluate the model and return the array of results specified
        in the method get_sim_outputs.
        '''
        U = self.tloop.eval()

        U_edge = U[self.edge_corner_1_dof][0, 0, 2]

        F_int = self.tloop.tstepper.F_int

        F_int_slice_x = F_int[self.edge_roof_right]
        F_int_slice_y = F_int[self.edge_roof_top]

        # bring dofs into right order for plot
        #
        F_hinge_in_order_x = self.sort_by_dofs(self.edge_roof_top,
                                               F_int_slice_x)
        F_hinge_in_order_y = self.sort_by_dofs(self.edge_roof_top,
                                               F_int_slice_y)
        F_hinge_x = append(F_hinge_in_order_x[:, :-1, 0],
                           F_hinge_in_order_x[-1, -1, 0])
        F_hinge_y = append(F_hinge_in_order_y[:, :-1, 1],
                           F_hinge_in_order_y[-1, -1, 1])
        F_hinge_y_sum = sum(F_hinge_y.flatten())
        F_hinge_x_sum = sum(F_hinge_x.flatten())
        #
        #        self.visual_force_bar( F_hinge_x.flatten()
        #                               , y_label = "internal force x [MN]"
        #                               , Title = 'F_Hinge_x_shrinkage' )
        #        self.visual_force_bar( F_hinge_y.flatten()
        #                               , y_label = "internal force y [MN]"
        #                               , Title = 'F_Hinge_y_shrinkage' )
        print "u_edge", U_edge
        print "n_elems_xy_col", self.n_elems_col_xy
        print "n_elems_z_col", self.n_elems_col_z
        print "n_elems_xy_quarter", self.n_elems_xy_quarter
        print "n_elems_z", self.n_elems_z

        return array(
            [
                U_edge,
                #                        u_x_corner2,
                #                       F_hinge_y_sum] )
                #                        u_z_corner2,
                #                        max_princ_stress ]
            ],
            dtype='float_')

    def get_sim_outputs(self):
        '''
        Specifies the results and their order returned by the model
        evaluation.
        '''
        return [
            SimOut(name='U', unit='m'),
            #                 SimOut( name = 'u_x_corner2', unit = 'm' ),
            #                 SimOut( name = 'N Gelenk', unit = 'MN' ), ]
            #                 SimOut( name = 'u_z_corner2', unit = 'm' ),
            #                 SimOut( name = 'maximum principle stress', unit = 'MPa' )
        ]

    #===============================================================================
    # response tracer
    #===============================================================================

    rtrace_list = List

    def _rtrace_list_default(self):
        return [self.max_princ_stress, self.sig_app, self.u, self.f_dof]

    shift_array = Array(value=[
        [0.45 / 2**0.5, 0.45 / 2**0.5, 1],
    ],
                        input=True)

    #===============================================================================
    # boundary conditions
    #===============================================================================

    bc_plate_roof_link_list = Property(List, depends_on='+ps_levels, +input')

    @cached_property
    def _get_bc_plate_roof_link_list(self):
        '''
        links all plate corner nodes of each elements to the adjacent elements of the roof
        '''
        roof = self.fe_grid_roof
        plate = self.fe_grid_plate
        bc_col_link_list = []

        slice_1 = [
            BCSlice(var='u',
                    dims=[0, 1, 2],
                    slice=roof[self.n_elems_xy_quarter - 1,
                               self.n_elems_xy_quarter, 0, 0, 0, 0],
                    link_slice=plate[0, 0, -1, 0, 0, -1],
                    link_coeffs=[1.0],
                    value=0.)
        ]
        slice_2 = [
            BCSlice(var='u',
                    dims=[0, 1, 2],
                    slice=roof[self.n_elems_xy_quarter,
                               self.n_elems_xy_quarter - 1, 0, 0, 0, 0],
                    link_slice=plate[-1, 0, -1, -1, 0, -1],
                    link_coeffs=[1.0],
                    value=0.)
        ]

        slice_3 = [
            BCSlice(var='u',
                    dims=[0, 1, 2],
                    slice=roof[self.n_elems_xy_quarter + 1,
                               self.n_elems_xy_quarter, 0, 0, 0, 0],
                    link_slice=plate[-1, -1, -1, -1, -1, -1],
                    link_coeffs=[1.0],
                    value=0.)
        ]

        slice_4 = [
            BCSlice(var='u',
                    dims=[0, 1, 2],
                    slice=roof[self.n_elems_xy_quarter,
                               self.n_elems_xy_quarter + 1, 0, 0, 0, 0],
                    link_slice=plate[0, -1, -1, 0, -1, -1],
                    link_coeffs=[1.0],
                    value=0.)
        ]

        slice_5 = [
            BCSlice(var='u',
                    dims=[0, 1, 2],
                    slice=roof[self.n_elems_xy_quarter,
                               self.n_elems_xy_quarter, 0, 0, 0, 0],
                    link_slice=plate[self.n_elems_col_xy / 2.0,
                                     self.n_elems_col_xy / 2.0, -1, 0, 0, -1],
                    link_coeffs=[1.0],
                    value=0.)
        ]

        bc_plate_roof_link_list = slice_1 + slice_2 + slice_3 + slice_4 + slice_5

        return bc_plate_roof_link_list

    bc_roof_top_roof_low_link_list = Property(List,
                                              depends_on='+ps_levels, +input')

    @cached_property
    def _get_bc_roof_top_roof_low_link_list(self):
        '''
        links all plate corner nodes of each elements to the adjacent elements of the roof
        '''
        roof = self.fe_grid_roof
        plate = self.fe_grid_plate
        bc_roof_top_roof_low_link_list = []

        slice_1 = [
            BCSlice(var='u',
                    dims=[2],
                    link_slice=roof[self.n_elems_xy_quarter - 1,
                                    self.n_elems_xy_quarter, 0, 0, 0, 0],
                    slice=roof[self.n_elems_xy_quarter - 1,
                               self.n_elems_xy_quarter, -1, 0, 0, -1],
                    link_coeffs=[1.0],
                    value=0.)
        ]
        slice_2 = [
            BCSlice(var='u',
                    dims=[2],
                    link_slice=roof[self.n_elems_xy_quarter,
                                    self.n_elems_xy_quarter - 1, 0, 0, 0, 0],
                    slice=roof[self.n_elems_xy_quarter,
                               self.n_elems_xy_quarter - 1, -1, 0, 0, -1],
                    link_coeffs=[1.0],
                    value=0.)
        ]

        slice_3 = [
            BCSlice(var='u',
                    dims=[2],
                    link_slice=roof[self.n_elems_xy_quarter + 1,
                                    self.n_elems_xy_quarter, 0, 0, 0, 0],
                    slice=roof[self.n_elems_xy_quarter + 1,
                               self.n_elems_xy_quarter, -1, 0, 0, -1],
                    link_coeffs=[1.0],
                    value=0.)
        ]

        slice_4 = [
            BCSlice(var='u',
                    dims=[2],
                    link_slice=roof[self.n_elems_xy_quarter,
                                    self.n_elems_xy_quarter + 1, 0, 0, 0, 0],
                    slice=roof[self.n_elems_xy_quarter,
                               self.n_elems_xy_quarter + 1, -1, 0, 0, -1],
                    link_coeffs=[1.0],
                    value=0.)
        ]

        slice_5 = [
            BCSlice(var='u',
                    dims=[2],
                    link_slice=roof[self.n_elems_xy_quarter,
                                    self.n_elems_xy_quarter, 0, 0, 0, 0],
                    slice=roof[self.n_elems_xy_quarter,
                               self.n_elems_xy_quarter, -1, 0, 0, -1],
                    link_coeffs=[1.0],
                    value=0.)
        ]

        bc_roof_top_roof_low_link_list = slice_1 + slice_2 + slice_3 + slice_4 + slice_5

        return bc_roof_top_roof_low_link_list

    bc_plate_column_link_list = Property(List, depends_on='+ps_levels, +input')

    @cached_property
    def _get_bc_plate_column_link_list(self):
        '''
        links all column nodes to plate nodes
        '''
        column = self.fe_grid_column
        plate = self.fe_grid_plate

        slice_1 = [
            BCSlice(var='u',
                    dims=[0, 1, 2],
                    slice=plate[:, :, 0, -1, -1, 0],
                    link_slice=column[:, :, -1, -1, -1, -1],
                    link_coeffs=[1.0],
                    value=0.)
        ]

        slice_2 = [
            BCSlice(var='u',
                    dims=[0, 1, 2],
                    slice=plate[:, :, 0, 0, 0, 0],
                    link_slice=column[:, :, -1, 0, 0, -1],
                    link_coeffs=[1.0],
                    value=0.)
        ]

        slice_3 = [
            BCSlice(var='u',
                    dims=[0, 1, 2],
                    slice=plate[:, :, 0, 0, -1, 0],
                    link_slice=column[:, :, -1, 0, -1, -1],
                    link_coeffs=[1.0],
                    value=0.)
        ]

        slice_4 = [
            BCSlice(var='u',
                    dims=[0, 1, 2],
                    slice=plate[:, :, 0, -1, 0, 0],
                    link_slice=column[:, :, -1, -1, 0, -1],
                    link_coeffs=[1.0],
                    value=0.)
        ]

        return slice_1 + slice_2 + slice_3 + slice_4
#        return [BCSlice( var = 'u'  , dims = [0, 1, 2],
#                         slice = plate[:,:,0,:,:, 0 ],
#                         link_slice = column[ :,:,-1 ,:,:,-1], link_coeffs = [1.0], value = 0. )]

    link_edge_list = Property(List, depends_on='+ps_levels, +input')

    @cached_property
    def _get_link_edge_list(self):
        '''
        links all edge nodes to one node, for this node boundary conditions are applied,
        the complete force within the edge hinge can therefore be evaluated at one node
        '''
        roof = self.fe_grid_roof
        dof_constraint_0 = [
            BCSlice(var='u',
                    dims=[1],
                    slice=roof[:, -1, -1, :, -1, -1],
                    value=0.0)
        ]
        dof_constraint_1 = [
            BCSlice(var='u',
                    dims=[0],
                    slice=roof[-1, :, -1, -1, :, -1],
                    value=0.0)
        ]
        link_edge_list = dof_constraint_0 + dof_constraint_1
        return link_edge_list

    bc_col_clamped_list = Property(List, depends_on='+ps_levels, +input')

    @cached_property
    def _get_bc_col_clamped_list(self):
        column = self.fe_grid_column
        constraint = [
            BCSlice(var='u',
                    dims=[0, 1, 2],
                    slice=column[:, :, 0, :, :, 0],
                    value=0.0)
        ]
        return constraint

    bc_col_hinge_list = Property(List, depends_on='+ps_levels, +input')

    @cached_property
    def _get_bc_col_hinge_list(self):
        constraint = []
        column = self.fe_grid_column
        for i in range(0, self.n_elems_col):
            dof_const = [
                BCSlice(var='u',
                        dims=[0, 1, 2],
                        slice=column[i, 0, 0, 0, 0, 0],
                        link_slice=column[-1 - i, -1, 0, -1, -1, 0],
                        link_coeffs=[-1.0],
                        value=0.0)
            ]
            constraint = constraint + dof_const
        for i in range(0, self.n_elems_col):
            dof_const = [
                BCSlice(var='u',
                        dims=[0, 1, 2],
                        slice=column[0, -1 - i, 0, 0, -1, 0],
                        link_slice=column[-1, i, 0, -1, 0, 0],
                        link_coeffs=[-1.0],
                        value=0.0)
            ]
            constraint = constraint + dof_const

        return constraint

    #===============================================================================
    # loading cases for mr_one only symmetric
    #===============================================================================

    lc_g_list = Property(List, depends_on='+ps_levels, +input')

    @cached_property
    def _get_lc_g_list(self):
        # slices
        roof = self.fe_grid_roof
        column = self.fe_grid_column
        upper_surf = roof[:, :, -1, :, :, -1]
        bottom_edge_roof = roof[:, 0, -1, :, 0, -1]
        left_edge_roof = roof[0, :, -1, 0, :, -1]

        # loads in global z- direction
        material_density_roof = -22.4e-3  # [MN/m^3]
        material_density_column = -26e-3  # [MN/m^3]
        additional_surface_load = -0.20e-3  # [MN/m^2]
        additional_t_constr = -0.02 * 22.4e-3
        edge_load = -0.35e-3  # [MN/m]
        return [
            BCSlice(var='f',
                    value=material_density_roof,
                    dims=[2],
                    integ_domain='global',
                    slice=roof[:, :, :, :, :, :]),
            BCSlice(var='f',
                    value=material_density_column,
                    dims=[2],
                    integ_domain='global',
                    slice=column[:, :, :, :, :, :]),
        ]


#                 BCSlice( var = 'f', value = additional_surface_load + additional_t_constr,
#                          dims = [2], integ_domain = 'global',
#                          slice = upper_surf ),
#                 BCSlice( var = 'f', value = edge_load, dims = [2],
#                          integ_domain = 'global',
#                          slice = bottom_edge_roof ),
#                 BCSlice( var = 'f', value = edge_load, dims = [2],
#                          integ_domain = 'global',
#                          slice = left_edge_roof )]

    lc_s_list = Property(List, depends_on='+ps_levels, +input')

    @cached_property
    def _get_lc_s_list(self):
        # slices
        roof = self.fe_grid_roof
        upper_surf = roof[:, :, -1, :, :, -1]
        # loads in global z- direction
        snow_load = -0.85e-3
        return [
            BCSlice(var='f',
                    value=snow_load,
                    dims=[2],
                    integ_domain='global',
                    slice=upper_surf)
        ]

    lc_shrink_list = Property(List, depends_on='+ps_levels, +input')

    def _get_lc_shrink_list(self):
        self.initial_strain_roof = True
        self.initial_strain_col = True
        self.t_up = -100
        self.t_lo = -100

    #===============================================================================
    # time loop
    #===============================================================================

    tloop = Property(depends_on='+ps_levels, +input')

    @cached_property
    def _get_tloop(self):
        roof = self.fe_grid_roof
        column = self.fe_grid_column
        plate = self.fe_grid_plate

        ts = TS(
            sdomain=[roof, plate, column],
            dof_resultants=True,
            bcond_list=

            # boundary conditions
            #
            self.bc_roof_top_roof_low_link_list +
            self.bc_plate_column_link_list + self.bc_plate_roof_link_list +
            self.link_edge_list + self.bc_col_clamped_list +

            # loading
            #
            self.lc_g_list,
            rtrace_list=self.rtrace_list)

        # Add the time-loop control
        tloop = TLoop(tstepper=ts, tolerance=1e-4, tline=self.tline)
        self.edge_corner_1_dof = roof[0, 0, 0, 0, 0, 0].dofs
        self.edge_corner_2_dof = roof[-1, 0, -1, -1, 0, -1].dofs
        self.dof = roof[-1, 0, -1, -1, 0, -1].dofs[0][0][0]
        self.edge_roof_top = roof[:, -1, -1, :, -1, -1].dofs
        self.edge_roof_right = roof[-1, :, -1, -1, :, -1].dofs

        return tloop
Esempio n. 9
0
class Material(HasTraits):
    '''
    Material parameters
    '''
    E_f = Float(
        72e+3,
        auto_set=False,
        enter_set=True,  # [N/mm^2]
        desc='Modulus of elasticity of the fiber [MPa]',
        modified=True)

    E_m = Float(
        30e+3,
        auto_set=False,
        enter_set=True,  # [N/mm^2]
        desc='Modulus of elasticity the matrix [MPa]',
        modified=True)

    tau = Float(
        .1,
        auto_set=False,
        enter_set=True,  # [N/mm^2]
        desc='frictional stress between fiber and matrix [MPa]',
        modified=True)

    r = Float(
        5e-4,
        auto_set=False,
        enter_set=True,  # [mm]
        desc='radius of the fiber',
        modified=True)

    m = Float(
        5.3,
        auto_set=False,
        enter_set=True,  # [-]
        desc='Weibull shape parameter for the matrix tensile strength [-]',
        modified=True)

    sigma_0 = Float(
        6.0,
        auto_set=False,
        enter_set=True,  # [N/mm^2]
        desc='Weibull scale parameter for the matrix tensile strength [MPa]',
        modified=True)

    V_f = Float(
        0.0175,
        auto_set=False,
        enter_set=True,  # [-]
        desc='reinforcement ratio [-]',
        modified=True)

    l_0 = Float(
        10.,
        auto_set=False,
        enter_set=True,  # [-]
        desc='reference length for the matrix strength distribution [mm]',
        modified=True)

    L_c = Float(
        1000.,
        auto_set=False,
        enter_set=True,  # [-]
        desc='specimen length [mm]',
        modified=True)

    sigma = Float(
        auto_set=False,
        enter_set=True,  # [-]
        desc='load [MPa]',
        modified=True)

    V_m = Property(Float, depends_on='V_f')

    @cached_property
    def _get_V_m(self):
        return 1 - self.V_f

    E_c = Property(Float, depends_on='E_m, E_f, V_f')

    @cached_property
    def _get_E_c(self):
        return self.E_f * self.V_f + self.E_m * (1. - self.V_f)

    def sigma_mu_distr(self, L):
        return weibull_min(self.m,
                           scale=self.sigma_0 * (L / self.l_0)**(-1. / self.m))
Esempio n. 10
0
class MushRoofModelNonLin(MRquarter):
    '''Overload the nonlinear model.
    '''

    #-----------------
    # composite cross section unit cell:
    #-----------------
    #
    ccs_unit_cell_key = Enum(CCSUnitCell.db.keys(),
                             simdb=True,
                             input=True,
                             auto_set=False,
                             enter_set=True)

    ccs_unit_cell_ref = Property(Instance(SimDBClass),
                                 depends_on='ccs_unit_cell_key')

    @cached_property
    def _get_ccs_unit_cell_ref(self):
        return CCSUnitCell.db[self.ccs_unit_cell_key]

    # vary the failure strain in PhiFnGeneralExtended:
    factor_eps_fail = Float(1.0, input=True, ps_levels=(1.0, 1.2, 3))

    #-----------------
    # damage function:
    #-----------------
    #
    material_model = Str(input=True)

    def _material_model_default(self):
        # return the material model key of the first DamageFunctionEntry
        # This is necessary to avoid an ValueError at setup
        return self.ccs_unit_cell_ref.damage_function_list[0].material_model

    calibration_test = Str(input=True)

    def _calibration_test_default(self):
        # return the material model key of the first DamageFunctionEntry
        # This is necessary to avoid an ValueError at setup
        return self.ccs_unit_cell_ref.damage_function_list[0].calibration_test

    damage_function = Property(Instance(MFnLineArray),
                               depends_on='input_change')

    @cached_property
    def _get_damage_function(self):
        return self.ccs_unit_cell_ref.get_param(self.material_model,
                                                self.calibration_test)

    #-----------------
    # phi function extended:
    #-----------------
    #
    phi_fn = Property(Instance(PhiFnGeneralExtended),
                      depends_on='input_change,+ps_levels')

    @cached_property
    def _get_phi_fn(self):
        return PhiFnGeneralExtended(mfn=self.damage_function,
                                    factor_eps_fail=self.factor_eps_fail)

    #----------------------------------------------------------------------------------
    # mats_eval
    #----------------------------------------------------------------------------------

    # age of the plate at the time of testing
    # NOTE: that the same phi-function is used independent of age. This assumes a
    # an afine/proportional damage evolution for different ages.
    #
    age = Int(
        28,  #input = True
    )

    # composite E-modulus
    #
    E_c = Property(Float, depends_on='input_change')

    @cached_property
    def _get_E_c(self):
        return self.ccs_unit_cell_ref.get_E_c_time(self.age)

    # Poisson's ratio
    #
    nu = Property(Float, depends_on='input_change')

    @cached_property
    def _get_nu(self):
        return self.ccs_unit_cell_ref.nu

    # @todo: for mats_eval the information of the unit cell should be used
    # in order to use the same number of microplanes and model version etc...
    #
    mats = Property(Instance(MATS2D5MicroplaneDamage),
                    depends_on='input_change')

    @cached_property
    def _get_mats(self):
        mats = MATS2D5MicroplaneDamage(E=self.E_c,
                                       nu=self.nu,
                                       n_mp=30,
                                       symmetrization='sum-type',
                                       model_version='compliance',
                                       phi_fn=self.phi_fn)

        return mats

    tline = Instance(TLine)

    def _tline_default(self):
        return TLine(min=0.0, step=1.0, max=8.0)

    rtrace_list = List

    def _rtrace_list_default(self):
        return [
            #                                 RTraceDomainListField( name = 'Displacement' ,
            #                                                var = 'u', idx = 0, warp = True ),
            #                                 RTraceDomainListField( name = 'Stress' ,
            #                                                var = 'sig_app', idx = 0, warp = True,
            #                                                record_on = 'update', ),
            #                    self.max_princ_stress,
            RTraceDomainListField(name='Damage',
                                  var='omega_mtx',
                                  idx=0,
                                  warp=True,
                                  record_on='update'),
        ]
Esempio n. 11
0
class CBEMClampedFiberStress(RF):
    '''
    Crack bridged by a fiber with constant
    frictional interface to the elastic matrix; clamped fiber end;
    Gives tension.
    '''

    implements(IRF)

    title = Str('crack bridge - clamped fiber with constant friction')

    xi = Float(0.0179,
               auto_set=False,
               enter_set=True,
               input=True,
               distr=['weibull_min', 'uniform'])

    tau = Float(2.5,
                auto_set=False,
                enter_set=True,
                input=True,
                distr=['uniform', 'norm'])

    l = Float(10.0,
              auto_set=False,
              enter_set=True,
              input=True,
              distr=['uniform'],
              desc='free length')

    r = Float(0.013,
              auto_set=False,
              input=True,
              enter_set=True,
              desc='fiber radius in mm')

    E_f = Float(72e3,
                auto_set=False,
                enter_set=True,
                input=True,
                distr=['uniform'])

    E_m = Float(30e3,
                auto_set=False,
                enter_set=True,
                input=True,
                distr=['uniform'])

    V_f = Float(0.0175,
                auto_set=False,
                enter_set=True,
                input=True,
                distr=['uniform'])

    theta = Float(0.01,
                  auto_set=False,
                  enter_set=True,
                  input=True,
                  distr=['uniform', 'norm'],
                  desc='slack')

    phi = Float(1.,
                auto_set=False,
                enter_set=True,
                input=True,
                distr=['uniform', 'norm'],
                desc='bond quality')

    Ll = Float(1.,
               auto_set=False,
               enter_set=True,
               input=True,
               distr=['uniform'],
               desc='embedded length - left',
               ctrl_range=(0.0, 1.0, 10))

    Lr = Float(.5,
               auto_set=False,
               enter_set=True,
               input=True,
               distr=['uniform'],
               desc='embedded length - right',
               ctrl_range=(0.0, 1.0, 10))

    w = Float(auto_set=False,
              enter_set=True,
              input=True,
              distr=['uniform'],
              desc='crack width',
              ctrl_range=(0.0, 1.0, 10))

    x = Float(auto_set=False,
              enter_set=True,
              input=True,
              distr=['uniform'],
              desc='crack width',
              ctrl_range=(0.0, 1.0, 10))

    x_label = Str('crack opening [mm]')
    y_label = Str('force [N]')

    C_code = Str('')

    def crackbridge(self, w, l, T, Kf, Km, Vf):
        # Phase A : Both sides debonding .
        Kc = Kf + Km
        c = Kc * T * l / 2.
        q0 = (np.sqrt(c**2 + w * Kf * Km * Kc * T) - c) / Km
        return q0 / Vf

    def pullout(self, w, l, T, Kf, Km, Vf, Lmin, Lmax):
        # Phase B : Debonding of shorter side is finished
        Kc = Kf + Km
        c = Kc * T * (Lmin + l)
        f = T**2 * Lmin**2 * Kc**2
        q1 = (np.sqrt(c**2. + f + 2 * w * Kc * T * Kf * Km) - c) / Km
        return q1 / Vf

    def linel(self, w, l, T, Kf, Km, Vf, Lmax, Lmin):
        # Phase C: Both sides debonded - linear elastic behavior.
        Kc = Kf + Km
        q2 = (2. * w * Kf * Km + T * Kc *
              (Lmin**2 + Lmax**2)) / (2. * Km * (Lmax + l + Lmin))
        return q2 / Vf

    def __call__(self, w, tau, l, E_f, E_m, theta, xi, phi, Ll, Lr, V_f, r):
        # assigning short and long embedded length
        Lmin = np.minimum(Ll, Lr)
        Lmax = np.maximum(Ll, Lr)

        Lmin = np.maximum(Lmin - l / 2., 1e-15)
        Lmax = np.maximum(Lmax - l / 2., 1e-15)

        # maximum condition for free length
        l = np.minimum(l / 2., Lr) + np.minimum(l / 2., Ll)

        # defining variables
        w = w - theta * l
        l = l * (1 + theta)
        w = H(w) * w
        T = 2. * tau * V_f / r
        Km = (1. - V_f) * E_m
        Kf = V_f * E_f
        Kc = Km + Kf

        # double sided debonding
        # q0 = self.crackbridge(w, l, T, Kr, Km, Lmin, Lmax)
        q0 = self.crackbridge(w, l, T, Kf, Km, V_f)

        # displacement at which the debonding to the closer clamp is finished
        w0 = (Lmin + l) * Lmin * Kc * T / Kf / Km

        # debonding of one side; the other side is clamped
        q1 = self.pullout(w, l, T, Kf, Km, V_f, Lmin, Lmax)

        # displacement at which the debonding is finished at both sides
        e1 = Lmax * Kc * T / Km / Kf
        w1 = e1 * (l + Lmax / 2.) + (e1 + e1 * Lmin / Lmax) * Lmin / 2.

        # debonding completed at both sides, response becomes linear elastic
        q2 = self.linel(w, l, T, Kf, Km, V_f, Lmax, Lmin)

        # cut out definition ranges
        q0 = H(w) * (q0 + 1e-15) * H(w0 - w)
        q1 = H(w - w0) * q1 * H(w1 - w)
        q2 = H(w - w1) * q2

        # add all parts
        q = q0 + q1 + q2
        # include breaking strain
        q = q * H(E_f * xi - q)
        return q
Esempio n. 12
0
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)
Esempio n. 13
0
class GeoST(HasTraits):
    '''Geometry definition of the slab test with round load introduction area
    corresponding to steel plate in the test setup.
    '''

    #-----------------------------------------------------------------
    # geometric parameters of the slab
    #-----------------------------------------------------------------
    # NOTE: coordinate system is placed where the symmetry planes cut each other,
    # i.e the center of the load introduction area (=middle of steel plate)

    # discretization of total slab in x- and y-direction (region 'L')
    #
    shape_xy = Int(14, input=True)

    # discretization of the load introduction plate (region 'R')
    #
    shape_R = Int(2, input=True)

    # ratio of the discretization, i.e. number of elements for each region
    #
    r_ = Property(depends_on='+input')

    @cached_property
    def _get_r_(self):
        return 1. * self.shape_R / self.shape_xy

    #-----------------
    # geometry:
    #-----------------

    # x and y-direction
    #
    length_quarter = Float(0.625, input=True)

    # Radius of load introduction plate
    #
    radius_plate = Float(0.10, input=True)

    # z-direction
    #
    thickness = Float(0.06, input=True)

    # specify offset (translation) for the plain concrete patch (if used)
    # in global coordinates
    #
    zoffset = Float(0.0, input=True)

    #    # used regular discretization up to y = L1
    #    # (by default use regular discretization up to support)
    #    #
    #    L1 = Float(0.30, input = True)

    def __call__(self, pts):
        print '*** geo_slab_test called ***'

        x_, y_, z_ = pts.T

        R = self.radius_plate
        L = self.length_quarter
        t = self.thickness

        #-------------------------------------------
        # transformation to global coordinates
        #-------------------------------------------

        x = np.zeros_like(x_)
        y = np.zeros_like(y_)
        z = z_ * t

        r_ = self.r_

        # 1. quadrant
        #
        bool_x = x_ >= r_
        bool_y = y_ >= r_
        bool_xy = bool_x * bool_y
        idx_xy = np.where(bool_xy == 1.)[0]
        x[idx_xy] = R + (x_[idx_xy] - r_) / (1 - r_) * (L - R)
        y[idx_xy] = R + (y_[idx_xy] - r_) / (1 - r_) * (L - R)

        # 2. quadrant
        #
        bool_x = x_ >= r_
        bool_y = y_ <= r_
        bool_xy = bool_x * bool_y
        idx_xy = np.where(bool_xy == 1.)[0]
        xR = R * np.cos(y_[idx_xy] / r_ * np.pi / 4.)
        x[idx_xy] = xR + (x_[idx_xy] - r_) / (1 - r_) * (L - xR)
        y[idx_xy] = y_[idx_xy] / r_ * R

        # 4. quadrant
        #
        bool_x = x_ <= r_
        bool_y = y_ >= r_
        bool_xy = bool_x * bool_y
        idx_xy = np.where(bool_xy == 1.)[0]
        x[idx_xy] = x_[idx_xy] / r_ * R
        yR = R * np.cos(x_[idx_xy] / r_ * np.pi / 4.)
        y[idx_xy] = yR + (y_[idx_xy] - r_) / (1 - r_) * (L - yR)

        # 3. quadrant (mesh in load introduction area)
        #
        bool_x = x_ <= r_
        bool_y = y_ <= r_
        bool_xy = bool_x * bool_y
        idx_xy = np.where(bool_xy == 1.)[0]
        xR = R * np.cos(y_[idx_xy] / r_ * np.pi / 4.)
        yR = R * np.cos(x_[idx_xy] / r_ * np.pi / 4.)
        x[idx_xy] = x_[idx_xy] / r_ * xR
        y[idx_xy] = y_[idx_xy] / r_ * yR

        # rotate coordinates in order to have the load introduction plate at the
        # top left corner of the grid
        # and add offset for translation
        #
        zoffset = self.zoffset
        pts = np.c_[L - x, L - y, z + zoffset]
        #        pts = np.c_[x, y, z]

        # switch order of the points in order to start in the opposite corner of the slab
        # instead of the center of the load introduction plate. The opposite center of the
        # slab corresponds to the origin of the slab in the model 'sim_st' (as generated by
        # the FEGrid mesh;
        #
        pts = pts[::-1]
        # switch back the order of the z-axis in order to maintain starting from 0
        #
        pts[:, -1] = pts[:, -1][::-1]

        #        print pts
        return pts
Esempio n. 14
0
class CBRandXi(RF):
    '''
    Crack bridged by a fiber with constant
    frictional interface to rigid; free fiber end;
    '''

    implements(IRF)

    title = Str('crack bridge with rigid matrix')

    tau = Float(2.5,
                auto_set=False,
                enter_set=True,
                input=True,
                distr=['uniform', 'norm'])

    r = Float(0.013,
              auto_set=False,
              enter_set=True,
              input=True,
              distr=['uniform', 'norm'],
              desc='fiber radius')

    E_f = Float(72e3,
                auto_set=False,
                enter_set=True,
                input=True,
                distr=['uniform'])

    m = Float(5.,
              auto_set=False,
              enter_set=True,
              input=True,
              distr=['uniform'])

    sV0 = Float(3.e-3,
                auto_set=False,
                enter_set=True,
                input=True,
                distr=['uniform'])

    V_f = Float(0.0175,
                auto_set=False,
                enter_set=True,
                input=True,
                distr=['uniform'])

    w = Float(auto_set=False,
              enter_set=True,
              input=True,
              distr=['uniform'],
              desc='crack width',
              ctrl_range=(0.0, 1.0, 10))

    include_pullout = Bool(True)

    x_label = Str('crack opening [mm]')
    y_label = Str('composite stress [MPa]')

    C_code = Str('')

    def __call__(self, w, tau, E_f, V_f, r, m, sV0):
        #strain and debonded length of intact fibers
        T = 2. * tau / r
        ef0_inf = np.sqrt(T * w / E_f)
        #scale parameter with respect to a reference volume
        s0 = ((T * (m + 1) * sV0**m) / (2. * E_f * pi * r**2))**(1. / (m + 1))
        k = np.sqrt(T / E_f)
        ef0 = k * np.sqrt(w)
        G = 1 - np.exp(-(ef0 / s0)**(m + 1))
        mu_int = ef0 * E_f * V_f * (1 - G)
        I = s0 * gamma(1 + 1. / (m + 1)) * gammainc(1 + 1. / (m + 1),
                                                    (ef0 / s0)**(m + 1))
        mu_broken = E_f * V_f * I / (m + 1)
        res = mu_int + mu_broken
        return res * r**2
Esempio n. 15
0
class Model(HasTraits):

    test_xdata = Array
    test_ydata = Array
    w_min = Float(0.0, auto_set=False, enter_set=True, params=True)
    w_max = Float(2., auto_set=False, enter_set=True, params=True)
    w_pts = Int(100, auto_set=False, enter_set=True, params=True)
    Ef = Float(181e3, auto_set=False, enter_set=True, params=True)
    V_f = Float(1.0, params=True)
    r = Float(3.5e-3, params=True)

    w = Property(Array, depends_on='w_min,w_max,w_pts')

    @cached_property
    def _get_w(self):
        return np.linspace(self.w_min, self.w_max, self.w_pts)

    interpolate_experiment = Property(depends_on='test_xdata,test_ydata,w')

    @cached_property
    def _get_interpolate_experiment(self):
        interp = interp1d(self.test_xdata,
                          self.test_ydata,
                          bounds_error=False,
                          fill_value=0.0)
        return interp(self.w)

    def model_free(self, tau_loc, tau_shape, tau_scale):
        xi_shape = 6.7
        #xi_scale = 3243. / (182e3 * (pi * 3.5e-3 **2 * 50.)**(-1./xi_shape)*gamma(1+1./xi_shape))
        xi_scale = 7.6e-3
        #CS=8.
        #mu_tau = 1.3 * self.r * 3.6 * (1.-0.01) / (2. * 0.01 * CS)
        #tau_scale = (mu_tau - tau_loc)/tau_shape
        #xi_scale = 0.0077
        #xi_shape = 6.7
        #tau_scale = (mu_tau - tau_loc)/tau_shape
        cb = CBClampedRandXi(pullout=False)
        spirrid = SPIRRID(q=cb, sampling_type='LHS')
        tau = RV('gamma', shape=tau_shape, scale=tau_scale, loc=tau_loc)
        w = self.w
        spirrid.eps_vars = dict(w=w)
        spirrid.theta_vars = dict(tau=tau,
                                  E_f=self.Ef,
                                  V_f=self.V_f,
                                  r=self.r,
                                  m=xi_shape,
                                  sV0=xi_scale)
        spirrid.n_int = 5000
        sigma_c = spirrid.mu_q_arr / self.r**2
        plt.plot(w, sigma_c)
        return sigma_c

    lack = 1e10

    def lack_of_fit(self, params):
        tau_loc = params[0]
        tau_shape = params[1]
        tau_scale = params[2]
        print params
        lack = np.sum((self.model_free(tau_loc, tau_shape, tau_scale) -
                       self.interpolate_experiment)**2)
        print 'params = ', params
        print 'relative lack of fit', np.sqrt(lack) / np.sum(
            self.interpolate_experiment)
        if lack < self.lack:
            print 'DRAW'
            self.lack = lack
            plt.ion()
            plt.cla()
            plt.plot(self.w, self.interpolate_experiment, color='black')
            plt.plot(self.w,
                     self.model_free(tau_loc, tau_shape, tau_scale),
                     color='red',
                     lw=2)
            plt.draw()
            plt.show()

        return lack

    def eval_params(self):
        params = minimize(self.lack_of_fit,
                          np.array([0.0, 0.01, 1.0]),
                          method='L-BFGS-B',
                          bounds=((0.0, .01), (0.01, 1.), (0.1, 5.)))
        return params
Esempio n. 16
0
class ECBMatrixCrossSection(ECBCrossSectionComponent):
    '''Cross section characteristics needed for tensile specimens.
    '''

    n_cj = Float(30, auto_set=False, enter_set=True, geo_input=True)
    '''Number of integration points.
    '''

    f_ck = Float(55.7, auto_set=False, enter_set=True, cc_input=True)
    '''Ultimate compression stress  [MPa]
    '''

    eps_c_u = Float(0.0033, auto_set=False, enter_set=True, cc_input=True)
    '''Strain at failure of the matrix in compression [-]
    '''

    height = Float(0.4, auto_set=False, enter_set=True, geo_input=True)
    '''height of the cross section [m]
    '''

    width = Float(0.20, auto_set=False, enter_set=True, geo_input=True)
    '''width of the cross section [m]
    '''

    x = Property(depends_on=ECB_COMPONENT_AND_EPS_CHANGE)
    '''Height of the compressive zone
    '''
    @cached_property
    def _get_x(self):
        eps_lo = self.state.eps_lo
        eps_up = self.state.eps_up
        if eps_up == eps_lo:
            # @todo: explain
            return (abs(eps_up) / (abs(eps_up - eps_lo * 1e-9)) * self.height)
        else:
            return (abs(eps_up) / (abs(eps_up - eps_lo)) * self.height)

    z_ti_arr = Property(depends_on=ECB_COMPONENT_AND_EPS_CHANGE)
    '''Discretizaton of the  compressive zone
    '''

    @cached_property
    def _get_z_ti_arr(self):
        if self.state.eps_up <= 0:  # bending
            zx = min(self.height, self.x)
            return np.linspace(0, zx, self.n_cj)
        elif self.state.eps_lo <= 0:  # bending
            return np.linspace(self.x, self.height, self.n_cj)
        else:  # no compression
            return np.array([0], dtype='f')

    eps_ti_arr = Property(depends_on=ECB_COMPONENT_AND_EPS_CHANGE)
    '''Compressive strain at each integration layer of the compressive zone [-]:
    '''

    @cached_property
    def _get_eps_ti_arr(self):
        # for calibration us measured compressive strain
        # @todo: use mapped traits instead
        #
        height = self.height
        eps_up = self.state.eps_up
        eps_lo = self.state.eps_lo
        eps_j_arr = (eps_up + (eps_lo - eps_up) * self.z_ti_arr / height)
        return (-np.fabs(eps_j_arr) + eps_j_arr) / 2.0

    zz_ti_arr = Property(depends_on=ECB_COMPONENT_AND_EPS_CHANGE)
    '''Distance of reinforcement layers from the bottom
    '''

    @cached_property
    def _get_zz_ti_arr(self):
        return self.height - self.z_ti_arr

    #===========================================================================
    # Compressive concrete constitutive law
    #===========================================================================

    cc_law_type = Trait('constant',
                        dict(constant=CCLawBlock,
                             linear=CCLawLinear,
                             quadratic=CCLawQuadratic,
                             quad=CCLawQuad),
                        cc_input=True)
    '''Selector of the concrete compression law type
    ['constant', 'linear', 'quadratic', 'quad']'''

    cc_law = Property(Instance(CCLawBase), depends_on='+cc_input')
    '''Compressive concrete law corresponding to cc_law_type'''

    @cached_property
    def _get_cc_law(self):
        return self.cc_law_type_(f_ck=self.f_ck, eps_c_u=self.eps_c_u, cs=self)

    show_cc_law = Button
    '''Button launching a separate view of the compression law.
    '''

    def _show_cc_law_fired(self):
        cc_law_mw = ConstitutiveLawModelView(model=self.cc_law)
        cc_law_mw.edit_traits(kind='live')
        return

    cc_modified = Event

    #===========================================================================
    # Calculation of compressive stresses and forces
    #===========================================================================

    sig_ti_arr = Property(depends_on=ECB_COMPONENT_AND_EPS_CHANGE)
    '''Stresses at the j-th integration point.
    '''

    @cached_property
    def _get_sig_ti_arr(self):
        return -self.cc_law.mfn_vct(-self.eps_ti_arr)

    f_ti_arr = Property(depends_on=ECB_COMPONENT_AND_EPS_CHANGE)
    '''Layer force corresponding to the j-th integration point.
    '''

    @cached_property
    def _get_f_ti_arr(self):
        return self.width * self.sig_ti_arr * self.unit_conversion_factor

    def _get_N(self):
        return np.trapz(self.f_ti_arr, self.z_ti_arr)

    def _get_M(self):
        return np.trapz(self.f_ti_arr * self.z_ti_arr, self.z_ti_arr)

    modified = Event

    @on_trait_change('+geo_input')
    def set_modified(self):
        self.modified = True

    view = View(HGroup(
        Group(Item('height', springy=True),
              Item('width'),
              Item('n_layers'),
              Item('n_rovings'),
              Item('A_roving'),
              label='Geometry',
              springy=True),
        springy=True,
    ),
                resizable=True,
                buttons=['OK', 'Cancel'])
Esempio n. 17
0
class CBClampedRandXi(RF):
    '''
    Crack bridged by a fiber with constant
    frictional interface to rigid; free fiber end;
    '''

    implements(IRF)
    title = Str('crack bridge with rigid matrix')
    tau = Float(2.5,
                auto_set=False,
                enter_set=True,
                input=True,
                distr=['uniform', 'norm'])

    r = Float(0.013,
              auto_set=False,
              enter_set=True,
              input=True,
              distr=['uniform', 'norm'],
              desc='fiber radius')

    E_f = Float(72e3,
                auto_set=False,
                enter_set=True,
                input=True,
                distr=['uniform'])

    m = Float(5.,
              auto_set=False,
              enter_set=True,
              input=True,
              distr=['uniform'])

    sV0 = Float(3.e-3,
                auto_set=False,
                enter_set=True,
                input=True,
                distr=['uniform'])

    V_f = Float(0.0175,
                auto_set=False,
                enter_set=True,
                input=True,
                distr=['uniform'])

    lm = Float(np.inf,
               auto_set=False,
               enter_set=True,
               input=True,
               distr=['uniform'])

    w = Float(auto_set=False,
              enter_set=True,
              input=True,
              distr=['uniform'],
              desc='crack width',
              ctrl_range=(0.0, 1.0, 10))

    x_label = Str('crack opening [mm]')
    y_label = Str('composite stress [MPa]')

    C_code = Str('')

    def __call__(self, w, tau, E_f, V_f, r, m, sV0):
        '''free and fixed fibers combined
        the failure probability of fixed fibers
        is evaluated by integrating only
        between -lm/2 and lm/2.
        Only intact fibers are considered (no pullout contribution)'''
        T = 2. * tau / r + 1e-10
        k = np.sqrt(T / E_f)
        ef0cb = k * np.sqrt(w)
        s = ((T * (m + 1) * sV0**m) / (2. * E_f * pi * r**2))**(1. / (m + 1))
        Gxi_deb = 1 - np.exp(-(ef0cb / s)**(m + 1))
        if w == 1.00:
            a0 = ef0cb * E_f / T
            print np.sum(a0 > 500.) / float(np.sum(a0 > -0.1))
        return ef0cb * (1 - Gxi_deb) * E_f * V_f * r**2
Esempio n. 18
0
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
Esempio n. 19
0
    class CBClampedFiber(RF):
        '''
        Crack bridged by a short fiber with constant
        frictional interface to the matrix; clamped fiber end
        '''

        implements(IRF)

        title = Str('crack bridge - clamped fiber with constant friction')
        image = Image('pics/cb_short_fiber.jpg')

        xi = Float(0.0179,
                   auto_set=False,
                   enter_set=True,
                   input=True,
                   distr=['weibull_min', 'uniform'])

        tau = Float(2.5,
                    auto_set=False,
                    enter_set=True,
                    input=True,
                    distr=['uniform', 'norm'])

        l = Float(0.0,
                  auto_set=False,
                  enter_set=True,
                  input=True,
                  distr=['uniform'],
                  desc='free length')

        D_f = Float(26e-3,
                    auto_set=False,
                    input=True,
                    enter_set=True,
                    distr=['uniform', 'weibull_min'])

        E_f = Float(72.0e3,
                    auto_set=False,
                    enter_set=True,
                    input=True,
                    distr=['uniform'])

        theta = Float(0.01,
                      auto_set=False,
                      enter_set=True,
                      input=True,
                      distr=['uniform', 'norm'],
                      desc='slack')

        phi = Float(1.,
                    auto_set=False,
                    enter_set=True,
                    input=True,
                    distr=['uniform', 'norm'],
                    desc='bond quality')

        Ll = Float(1.,
                   auto_set=False,
                   enter_set=True,
                   input=True,
                   distr=['uniform'],
                   desc='embedded length - left')

        Lr = Float(.5,
                   auto_set=False,
                   enter_set=True,
                   input=True,
                   distr=['uniform'],
                   desc='embedded length - right')

        w = Float(auto_set=False,
                  enter_set=True,
                  input=True,
                  desc='crack width',
                  ctrl_range=(0, 0.01, 100))

        x_label = Str('crack opening [mm]')
        y_label = Str('force [N]')

        C_code = Str('')

        # TODO: case where Lmin is zero - gives a double sided pullout
        # should be one sided though
        def __call__(self, w, tau, l, D_f, E_f, theta, xi, phi, Ll, Lr):

            A = pi * D_f**2 / 4.
            Lmin = minimum(Ll, Lr)
            Lmax = maximum(Ll, Lr)

            Lmin = maximum(Lmin - l / 2., 0)
            Lmax = maximum(Lmax - l / 2., 0)

            l = minimum(Lr + Ll, l)

            l = l * (1 + theta)
            w = w - theta * l

            T = tau * phi * D_f * pi

            # double sided debonding
            l0 = l / 2.
            q0 = (-l0 * T + sqrt((l0 * T)**2 + w * Heaviside(w) * E_f * A * T))

            # displacement at which the debonding to the closer clamp is finished
            # the closer distance is min(L1,L2)

            w0 = Lmin * T * (Lmin + 2 * l0) / E_f / A

            # debonding from one side; the other side is clamped
            # equal to L1*T + one sided pullout with embedded length Lmax - Lmin and free length 2*L1 + l

            # force at w0
            Q0 = Lmin * T
            l1 = 2 * Lmin + l
            q1 = (-(l1) * T +
                  sqrt((l1 * T)**2 + 2 *
                       (w - w0) * Heaviside(w - w0) * E_f * A * T)) + Q0

            # displacement at debonding finished at both sides
            # equals a force of T*(larger clamp distance)

            # displacement, at which both sides are debonded
            w1 = w0 + (Lmax - Lmin) * T * ((Lmax - Lmin) + 2 *
                                           (l + 2 * Lmin)) / 2 / E_f / A
            # linear elastic response with stiffness EA/(clamp distance)
            q2 = E_f * A * (w - w1) / (Lmin + Lmax + l) + (Lmax) * T

            q0 = q0 * Heaviside(w0 - w)
            q1 = q1 * Heaviside(w - w0) * Heaviside(w1 - w)
            q2 = q2 * Heaviside(w - w1)

            q = q0 + q1 + q2

            # include breaking strain
            q = q * Heaviside(A * E_f * xi - q)
            #return q0, q1, q2 * Heaviside( A * E_f * xi - q2 ), w0 + theta * l, w1 + theta * l
            return q
Esempio n. 20
0
class CBClamped(RF):
    '''
    Crack bridged by a fiber with constant
    frictional interface to rigid; free fiber end;
    '''

    implements(IRF)

    title = Str('crack bridge with rigid matrix')

    tau = Float(2.5,
                auto_set=False,
                enter_set=True,
                input=True,
                distr=['uniform', 'norm'])

    r = Float(0.013,
              auto_set=False,
              enter_set=True,
              input=True,
              distr=['uniform', 'norm'],
              desc='fiber radius')

    E_f = Float(72e3,
                auto_set=False,
                enter_set=True,
                input=True,
                distr=['uniform'])

    m = Float(5.,
              auto_set=False,
              enter_set=True,
              input=True,
              distr=['uniform'])

    sV0 = Float(3.e-3,
                auto_set=False,
                enter_set=True,
                input=True,
                distr=['uniform'])

    V_f = Float(0.0175,
                auto_set=False,
                enter_set=True,
                input=True,
                distr=['uniform'])

    lm = Float(np.inf,
               auto_set=False,
               enter_set=True,
               input=True,
               distr=['uniform'])

    w = Float(auto_set=False,
              enter_set=True,
              input=True,
              distr=['uniform'],
              desc='crack width',
              ctrl_range=(0.0, 1.0, 10))

    x_label = Str('crack opening [mm]')
    y_label = Str('composite stress [MPa]')

    C_code = Str('')

    def e_broken(self, Pf, depsf, r, m, sV0, mask):
        '''weibull_fibers_cdf_mc'''
        s_free = ((depsf * (m + 1.) * sV0**m) / (2. * pi * r**2.))**(1. /
                                                                     (m + 1.))
        xi_free = s_free * (-np.log(1. - Pf))**(1. / (m + 1))
        s_fixed = ((depsf * sV0**m) / (2. * pi * r**2.))**(1. / (m + 1.))
        xi_fixed = s_fixed * (-np.log(1. - Pf))**(1. / (m + 1))
        return xi_free, xi_fixed

    def __call__(self, w, tau, E_f, V_f, r, m, sV0, lm, Pf):
        '''free and fixed fibers combined'''
        T = 2. * tau / r
        k = np.sqrt(T / E_f)
        ef0cb = k * np.sqrt(w)
        ef0lin = w / lm + T * lm / 4. / E_f
        depsf = T / E_f
        a0 = ef0cb / depsf
        mask = a0 < lm / 2.0
        e_int = ef0cb * mask + ef0lin * (mask == False)
        xi_free, xi_fixed = self.e_broken(Pf, depsf, r, m, sV0, mask)
        axi = xi_free / depsf
        mask_xi = axi < lm / 2.
        e_broken = xi_free / (m + 1.) * (mask_xi) + xi_fixed / 2. * (mask_xi
                                                                     == False)
        xi = xi_free * (mask_xi) + xi_fixed * (mask_xi == False)
        e = e_int * (e_int < xi) + e_broken * (e_int > xi)
        return e * E_f * V_f * r**2

    def __call__2(self, w, tau, E_f, V_f, r, m, sV0, Pf):
        '''free debonding only = __call__ with lm=infty'''
        #strain and debonded length of intact fibers
        T = 2. * tau / r
        ef0_inf = np.sqrt(T * w / E_f)
        #scale parameter with respect to a reference volume
        s0 = ((T * (m + 1) * sV0**m) / (2. * E_f * pi * r**2))**(1. / (m + 1))
        # strain at fiber breakage
        ef0_break = s0 * (-np.log(1. - Pf))**(1. / (m + 1))
        # debonded length at fiber breakage
        a_break = ef0_break * E_f / T
        #mean pullout length of broken fibers
        mu_Lpo = a_break / (m + 1)
        # strain carried by broken fibers
        ef0_residual = T / E_f * mu_Lpo

        if self.include_pullout == True:
            ef0_tot = ef0_residual * H(ef0_inf - ef0_break) + ef0_inf * H(
                ef0_break - ef0_inf)
        else:
            ef0_tot = ef0_inf * H(ef0_break - ef0_inf)
        return ef0_tot * E_f * V_f * r**2
Esempio n. 21
0
class MRfour(MushRoofModel):

    #----------------------------------------------------
    # elements
    #----------------------------------------------------
    vtk_r = Float(1.0)
    # default column
    fe_column = Instance(FETSEval, transient=True)

    def _fe_column_default(self):
        fets = self.fe_quad_serendipity_column
        fets.vtk_r *= self.vtk_r
        return fets

    # default roof
    fe_roof = Instance(FETSEval,
                       ps_levels=[
                           'fe_linear', 'fe2d5_quad_serendipity',
                           'fe_quad_serendipity_roof',
                           'fe_quad_serendipity_column', 'fe_quad_lagrange'
                       ])

    def _fe_roof_default(self):
        fets = self.fe_quad_serendipity_roof
        fets.vtk_r *= self.vtk_r
        return fets

    #----------------------------------------------------
    # geometric transformation
    #----------------------------------------------------

    hp_shells = Property(List(HPShell), depends_on='+ps_levels, +input')

    @cached_property
    def _get_hp_shells(self):
        X_list = [[0, 0, 0], [7, 0, 0], [0, 7, 0], [7, 7, 0]]
        return [
            HPShell(
                length_xy_quarter=self.length_xy_quarter,
                length_z=self.length_z,
                t_shell=self.t_shell,
                X0=X,
                n_elems_xy_quarter=self.n_elems_xy_quarter,
                n_elems_z=self.n_elems_z,
                #                    shift_elems_column = self.shift_elems_column,
                scalefactor_delta_h=self.scalefactor_delta_h,
                const_reinf_layer_elem=self.const_reinf_layer_elem,
                width_top_col=self.width_top_col,
                #                    n_elems_col = self.n_elems_col,
                mushroof_part=self.mushroof_part) for X in X_list
        ]

    columns = Property(Instance(GEOColumn), depends_on='+ps_levels, +input')

    @cached_property
    def _get_columns(self):
        ch = self.h_col / self.scalefactor_delta_h
        X_list = [[3.5, 3.5, -ch], [10.5, 3.5, -ch], [3.5, 10.5, -ch],
                  [10.5, 10.5, -ch]]
        return [
            GEOColumn(width_top=self.width_top_col,
                      X0=X,
                      width_bottom=self.width_bottom_col,
                      h_col=ch) for X in X_list
        ]

    #----------------------------------------------------
    # grid
    #----------------------------------------------------
    fe_grid_roofs = Property(Instance(FEGrid), depends_on='+ps_levels, +input')

    @cached_property
    def _get_fe_grid_roofs(self):
        return [
            FEGrid(coord_min=(0.0, 0.0, 0.0),
                   coord_max=(1.0, 1.0, 1.0),
                   geo_transform=hp_shell,
                   shape=(self.n_elems_xy_quarter, self.n_elems_xy_quarter,
                          self.n_elems_z),
                   fets_eval=self.fe_roof) for hp_shell in self.hp_shells
        ]

    fe_grid_columns = Property(Instance(FEGrid),
                               depends_on='+ps_levels, +input')

    @cached_property
    def _get_fe_grid_columns(self):
        return [
            FEGrid(coord_min=(0.0, 0.0, 0.0),
                   coord_max=(1.0, 1.0, 1.0),
                   geo_transform=column,
                   shape=(1, 1, 1),
                   fets_eval=self.fe_column) for column in self.columns
        ]

    #----------------------------------------------------
    # ps_study
    #----------------------------------------------------

    def peval(self):
        '''
        Evaluate the model and return the array of results specified
        in the method get_sim_outputs.
        '''
        U = self.tloop.eval()

        U_z = U[self.corner_dof_r00][0, 0, 2]

        #        max_princ_stress = max( self.max_princ_stress._get_field_data().flatten() )

        return array(
            [U_z],
            #                       max_princ_stress ],
            dtype='float_')

    def get_sim_outputs(self):
        '''
        Specifies the results and their order returned by the model
        evaluation.
        '''
        return [SimOut(name='u_z_free_corner', unit='m')]


#               SimOut( name = 'maximum principle stress', unit = 'MPa' ), ]

#----------------------------------------------------
# loading and boundaries
#----------------------------------------------------
#    lc_symm_dict = Property( Dict )
#    def _get_lc_symm_dict ( self ):
#        return {'g_mat_dens_roof':Float( -0.0224, unit = 'MN/m^3' ),
#                'g_mat_dens_column':Float( -0.024, unit = 'MN/m^3' ),
#                'g_surf_load_gA':Float( -0.20e-3, unit = 'MN/m^2' ),
#                's_surf_load':Float( -0.84e-3, unit = 'MN/m^2' ),
#                'w_surf_load':Float( -0.13e-3, unit = 'MN/m^2' ),
#                }
#--- LC0: verifying load for ps_study
# g = 1.0 kN/m^2
# orientation: global z-direction;

    f_z = Float(-1e-3, unit='MN/m^3')

    #--- LC1: dead load
    # g = 22.4 kN/m^3
    # orientation: global z-direction;
    material_density_roof = Float(-0.0224, unit='MN/m^3')
    material_density_column = Float(-0.0224, unit='MN/m^3')

    #--- LC2 additional dead load
    # gA = 0,20 kN/m^2
    # orientation: global z-direction (following the curved structure);
    surface_load_gA = Float(-0.20e-3, unit='MN/m^2')

    #--- LC3 snow
    # s = 0,79 kN/m^2
    # orientation: global z-direction (projection);
    surface_load_s = Float(-0.84e-3, unit='MN/m^2')

    #--- LC4 wind (pressure)
    # w = 0,13 kN/m^2
    # orientation: local t-direction (surface normal);
    surface_load_w = Float(-0.13e-3, unit='MN/m^2')

    force_bc_list = Property(List, depends_on='+ps_levels, +input')

    @cached_property
    def _get_force_bc_list(self):
        # NOTE: additional line-loads at the edge of the roof need to be considered!

        force_bc_list = []
        for roof, column in zip(self.fe_grid_roofs, self.fe_grid_columns):
            upper_surface = roof[:, :, -1, :, :, -1]
            #            whole_roof = roof[:, :, :, :, :, :]
            #            whole_column = column[:, :, :, :, :, :]

            force_bc = [
                #                         # LC0: dead load
                BCSlice(var='f',
                        value=self.f_z,
                        dims=[2],
                        integ_domain='global',
                        slice=upper_surface),

                #                         # LC1: dead load
                #                         BCSlice( var = 'f', value = self.material_density_roof, dims = [2],
                #                                  integ_domain = 'global',
                #                                  slice = whole_roof ),
                #                         BCSlice( var = 'f', value = self.material_density_column, dims = [2],
                #                                  integ_domain = 'global',
                #                                  slice = whole_column ),
                # LC2: additional dead load
                #                         BCSlice( var = 'f', value = self.surface_load_gA, dims = [2],
                #                                  integ_domain = 'global',
                #                                  slice = upper_surface ),
                #                         # LC3: snow load
                #                         BCSlice( var = 'f', value = self.surface_load_s, dims = [2],
                #                                  integ_domain = 'global',
                #                                  slice = upper_surface )
            ]
            force_bc_list += force_bc

        return force_bc_list

    displ_bc_list = Property(List, depends_on='+ps_levels, +input')

    @cached_property
    def _get_displ_bc_list(self):

        displ_bc_list = []
        for roof, column in zip(self.fe_grid_roofs, self.fe_grid_columns):
            bc_list = [
                BCSlice(var='u',
                        dims=[0, 1, 2],
                        slice=roof[self.n_elems_xy_quarter - 1,
                                   self.n_elems_xy_quarter - 1, 0, 0, -1, 0],
                        link_slice=column[0, 0, -1, 0, 0, -1],
                        link_coeffs=[1.0],
                        value=0.),
                BCSlice(var='u',
                        dims=[0, 1, 2],
                        slice=roof[self.n_elems_xy_quarter - 1,
                                   self.n_elems_xy_quarter - 1, 0, -1, 0, 0],
                        link_slice=column[-1, 0, -1, -1, 0, -1],
                        link_coeffs=[1.0],
                        value=0.),
                BCSlice(var='u',
                        dims=[0, 1, 2],
                        slice=roof[self.n_elems_xy_quarter,
                                   self.n_elems_xy_quarter, 0, -1, 0, 0],
                        link_slice=column[-1, -1, -1, -1, -1, -1],
                        link_coeffs=[1.0],
                        value=0.),
                BCSlice(var='u',
                        dims=[0, 1, 2],
                        slice=roof[self.n_elems_xy_quarter,
                                   self.n_elems_xy_quarter, 0, 0, -1, 0],
                        link_slice=column[0, -1, -1, 0, -1, -1],
                        link_coeffs=[1.0],
                        value=0.),
                BCSlice(
                    var='u',
                    dims=[0, 1, 2],
                    slice=column[:, :, 0, :, :, 0],
                    #                                 slice = column[ 0, 0, 0, -1, -1, 0 ],
                    value=0.0)
            ]
            displ_bc_list += bc_list
        return displ_bc_list

    wind_bc_list = Property(List, depends_on='+ps_levels, +input')

    @cached_property
    def _get_wind_bc_list(self):

        w_left_edge = 0.91e-3  # [MN/m]
        w_right_edge = 0.39e-3  # [MN/m]
        w_bottom_edge_0 = 1.14e-3  # [Mn/m]
        w_bottom_edge_1 = 0.65e-3  # [Mn/m]
        w_top_edge_0 = -w_bottom_edge_0  # [Mn/m]
        w_top_edge_1 = -w_bottom_edge_1  # [Mn/m]
        w_face_0_left = 0.89e-3  # MN/m^2
        w_face_0_right = -0.13e-3  # MN/m^2
        w_face_1_left = 0.72e-3  # MN/m^2
        w_face_1_right = w_face_0_right

        r00, r10, r01, r11 = self.fe_grid_roofs

        left_edge_0 = r00[0, :, -1, 0, :, -1]
        left_edge_1 = r01[0, :, -1, 0, :, -1]
        right_edge_0 = r10[-1, :, -1, 0, :, -1]
        right_edge_1 = r11[-1, :, -1, 0, :, -1]
        bottom_edge_0 = r00[:, 0, -1, :, 0, -1]
        bottom_edge_1 = r10[:, 0, -1, :, 0, -1]
        top_edge_0 = r01[:, -1, -1, :, -1, -1]
        top_edge_1 = r11[:, -1, -1, :, -1, -1]

        n_e_q = self.n_elems_xy_quarter
        face_00_left = r00[:n_e_q, :, -1, :, :, -1]
        face_00_right = r00[n_e_q:, :, -1, :, :, -1]
        face_01_left = r01[:n_e_q, :, -1, :, :, -1]
        face_01_right = r01[n_e_q:, :, -1, :, :, -1]
        face_10_left = r10[:n_e_q, :, -1, :, :, -1]
        face_10_right = r10[n_e_q:, :, -1, :, :, -1]
        face_11_left = r11[:n_e_q, :, -1, :, :, -1]
        face_11_right = r11[n_e_q:, :, -1, :, :, -1]

        wind_list = [
            # left edge - x direction
            BCSlice(var='f', dims=[0], slice=left_edge_0, value=w_left_edge),
            BCSlice(var='f', dims=[0], slice=left_edge_1, value=w_left_edge),
            # right edge - x direction
            BCSlice(var='f', dims=[0], slice=right_edge_0, value=w_right_edge),
            BCSlice(var='f', dims=[0], slice=right_edge_1, value=w_right_edge),
            # bottom edge - y direction
            BCSlice(var='f',
                    dims=[1],
                    slice=bottom_edge_0,
                    value=w_bottom_edge_0),
            BCSlice(var='f',
                    dims=[1],
                    slice=bottom_edge_1,
                    value=w_bottom_edge_1),
            # top edge - y direction
            BCSlice(var='f', dims=[1], slice=top_edge_0, value=w_top_edge_0),
            BCSlice(var='f', dims=[1], slice=top_edge_1, value=w_top_edge_1),
            # upper face left - left
            BCSlice(var='f', dims=[2], slice=face_00_left,
                    value=w_face_0_left),
            BCSlice(var='f', dims=[2], slice=face_01_left,
                    value=w_face_0_left),
            # upper face left - right
            BCSlice(var='f',
                    dims=[2],
                    slice=face_00_right,
                    value=w_face_0_right),
            BCSlice(var='f',
                    dims=[2],
                    slice=face_01_right,
                    value=w_face_0_right),
            # upper face right - left
            BCSlice(var='f', dims=[2], slice=face_10_left,
                    value=w_face_1_left),
            BCSlice(var='f', dims=[2], slice=face_11_left,
                    value=w_face_1_left),
            # upper face right - right
            BCSlice(var='f',
                    dims=[2],
                    slice=face_10_right,
                    value=w_face_1_right),
            BCSlice(var='f',
                    dims=[2],
                    slice=face_11_right,
                    value=w_face_1_right),
        ]
        return wind_list

    link_bc_list = Property(List, depends_on='+ps_levels, +input')

    @cached_property
    def _get_link_bc_list(self):
        r00, r10, r01, r11 = self.fe_grid_roofs
        link_bc_list = [
            BCSlice(var='u',
                    dims=[0, 1, 2],
                    slice=r00[-1, :, -1, -1, :-1, -1],
                    link_slice=r10[0, :, -1, 0, :-1, -1],
                    link_coeffs=[1.0],
                    value=0.),
            BCSlice(var='u',
                    dims=[0, 1, 2],
                    slice=r01[:, 0, -1, :-1, 0, -1],
                    link_slice=r00[:, -1, -1, :-1, -1, -1],
                    link_coeffs=[1.0],
                    value=0.),
            BCSlice(var='u',
                    dims=[0, 1, 2],
                    slice=r11[0, :, -1, 0, 1:, -1],
                    link_slice=r01[-1, :, -1, -1, 1:, -1],
                    link_coeffs=[1.0],
                    value=0.),
            BCSlice(var='u',
                    dims=[0, 1, 2],
                    slice=r10[:, -1, -1, 1:, -1, -1],
                    link_slice=r11[:, 0, -1, 1:, 0, -1],
                    link_coeffs=[1.0],
                    value=0.),
        ]
        return link_bc_list

    #----------------------------------------------------
    # response tracer
    #----------------------------------------------------

    rtrace_list = List

    def _rtrace_list_default(self):
        return [self.max_princ_stress, self.sig_app, self.u]

    # time loop
    tloop = Property(depends_on='+ps_levels, +input')

    @cached_property
    def _get_tloop(self):
        # self.fets.vtk_r *= 0.95

        roofs = self.fe_grid_roofs

        columns = self.fe_grid_columns

        r00, r10, r01, r11 = roofs

        self.corner_dof_r00 = r00[0, 0, 0, 0, 0, 0].dofs

        rtrace_list = self.rtrace_list

        ts = TS(
            sdomain=roofs + columns,
            dof_resultants=True,
            #                 bcond_list = self.wind_bc_list + self.displ_bc_list + self.link_bc_list,
            bcond_list=self.force_bc_list + self.displ_bc_list +
            self.link_bc_list,
            #                 bcond_list = self.displ_bc_list + self.link_bc_list,
            rtrace_list=rtrace_list)

        # Add the time-loop control
        tloop = TLoop(tstepper=ts, tolerance=1e-4, tline=self.tline)

        return tloop
Esempio n. 22
0
class MRquarterDB(MRquarter):
    '''get 'phi_fn' as calibrated by the fitter and stored in the DB
    '''

    # vary the failure strain in PhiFnGeneralExtended:
    factor_eps_fail = Float(1.4, input=True, ps_levels=(1.0, 1.2, 3))

    #-----------------
    # composite cross section unit cell:
    #-----------------
    #
    ccs_unit_cell_key = Enum('FIL-10-09_2D-05-11_0.00462_all0',
                             CCSUnitCell.db.keys(),
                             simdb=True,
                             input=True,
                             auto_set=False,
                             enter_set=True)

    ccs_unit_cell_ref = Property(Instance(SimDBClass),
                                 depends_on='ccs_unit_cell_key')

    @cached_property
    def _get_ccs_unit_cell_ref(self):
        return CCSUnitCell.db[self.ccs_unit_cell_key]

    #-----------------
    # damage function:
    #-----------------
    #
    material_model = Str(input=True)

    def _material_model_default(self):
        # return the material model key of the first DamageFunctionEntry
        # This is necessary to avoid an ValueError at setup
        return self.ccs_unit_cell_ref.damage_function_list[0].material_model

    calibration_test = Str(input=True)

    def _calibration_test_default(self):
        # return the material model key of the first DamageFunctionEntry
        # This is necessary to avoid an ValueError at setup
        return self.ccs_unit_cell_ref.damage_function_list[0].calibration_test

    damage_function = Property(Instance(MFnLineArray), depends_on='+input')

    @cached_property
    def _get_damage_function(self):
        print 'getting damage function'
        return self.ccs_unit_cell_ref.get_param(self.material_model,
                                                self.calibration_test)

    #-----------------
    # phi function extended:
    #-----------------
    #
    phi_fn = Property(Instance(PhiFnGeneralExtended),
                      depends_on='+input,+ps_levels')

    @cached_property
    def _get_phi_fn(self):
        return PhiFnGeneralExtendedExp(mfn=self.damage_function,
                                       Dfp=0.01,
                                       Efp_frac=0.007)


#        return PhiFnGeneralExtended( mfn = self.damage_function,
#                                     factor_eps_fail = self.factor_eps_fail )

#----------------------------------------------------------------------------------
# mats_eval
#----------------------------------------------------------------------------------

# age of the plate at the time of testing
# NOTE: that the same phi-function is used independent of age. This assumes a
# an afine/proportional damage evolution for different ages.
#

    age = Int(
        28,  # input = True
    )

    # composite E-modulus
    #
    E_c = Property(Float, depends_on='+input')

    @cached_property
    def _get_E_c(self):
        return self.ccs_unit_cell_ref.get_E_c_time(self.age)

    # Poisson's ratio
    #
    nu = Property(Float, depends_on='+input')

    @cached_property
    def _get_nu(self):
        return self.ccs_unit_cell_ref.nu
Esempio n. 23
0
class AramisBSA(AramisCDT):
    '''Crack Detection Tool for detection of cracks, etc. from Aramis data.
    '''

    d_ux_arr2 = Property(
        Array, depends_on='aramis_info_changed, aramis_data.+params_changed')
    '''The first derivative of displacement in x-direction
    '''
    @cached_property
    def _get_d_ux_arr2(self):
        x_und = self.aramis_data.x_arr_undeformed
        # print x_und
        # print np.ndim (x_und)
        # print np.shape (x_und)
        ux = self.aramis_data.ux_arr
        # print ux
        # print np.ndim (ux)
        # print np.shape (ux)
        du_arr = np.zeros_like(x_und)
        ir = self.integ_radius
        du_arr[:, ir:-ir] = (ux[:, 2 * ir:] - ux[:, :-2 * ir]) / (
            x_und[:, 2 * ir:] - x_und[:, :-2 * ir])
        # print 'ux'
        # print ux[:, :]
        # print 'ux[:, 2 * ir:]'
        # print ux[:, 2 * ir:]
        # print 'ux[:, :-2 * ir]'
        # print ux[:, :-2 * ir]
        # print 'x_und'
        # print x_und[:, :]
        # print 'x_und[:, 2 * ir:]'
        # print x_und[:, 2 * ir:]
        # print 'x_und[:, :-2 * ir]'
        # print x_und[:, :-2 * ir]
        # print 'du_arr[:, ir:-ir]'
        # print du_arr[:, ir:-ir]
        return du_arr

    #--------------------------------------------------------------------------------
    # get max tensile strain in the reinforcement layer
    #--------------------------------------------------------------------------------

    h_top_threshold = Float(1.5, auto_set=False, enter_set=True)
    '''Threshold for distance between specimen edge and aramis-mask on top side.
    '''
    h_bot_threshold = Float(1.0, auto_set=False, enter_set=True)
    '''Threshold for distance between specimen edge and aramis-mask on bottom side.
    '''
    h_re_6_threshold = Float(2.86, auto_set=False, enter_set=True)
    '''Threshold for position of first reinforcement layer (6 layers).
    '''
    h_re_4_threshold = Float(4.0, auto_set=False, enter_set=True)
    '''Threshold for position of first reinforcement layer (4 layers).
    '''

    d_ux_max_ten = Property(
        Array, depends_on='aramis_info_changed, aramis_data.+params_changed')

    @cached_property
    def _get_d_ux_max_ten(self):

        # get number of values in y-direction
        num_ele = self.d_ux_arr2.shape[0]

        # size of facet in y direction
        h_mask = 20.0 - self.h_top_threshold - self.h_bot_threshold
        size_fa_y = h_mask / num_ele

        # get indices of strain before strain of reinforcement layer
        pos_re_6 = self.h_re1_6_threshold - self.h_top_threshold
        pos_re_4 = self.h_re1_4_threshold - self.h_top_threshold

        idx_6 = pos_re_6 / size_fa_y
        idx_6 = round(idx_6)
        idx_4 = pos_re_4 / size_fa_y
        idx_4 = round(idx_4)

        # position of first node in y-direction
        pos_no_f = 20. - self.h_top_threshold - (size_fa_y / 2)
        # position of last node in y-direction
        pos_no_l = (size_fa_y / 2) + self.h_bot_threshold

        # get all values for x- axis and y-axis
        mid_idx = self.d_ux_arr2.shape[1] / 2
        x = np.mean(self.d_ux_arr2[:, mid_idx - 0:mid_idx + 1], axis=1)
        y = np.linspace(pos_no_f, pos_no_l, num=25)

        if '6layers':
            x1 = x[idx_6]
            y1 = y[idx_6]
            y_re = 20. - self.h_re_6_threshold
            x_re = (x1 * y_re) / y1
            return x_re
        else:
            x1 = x[idx_4]
            y1 = y[idx_4]
            y_re = 20. - self.h_re_4_threshold
            x_re = (x1 * y_re) / y1
            return x_re

    #--------------------------------------------------------------------------------
    # get heigth of compression zone
    #--------------------------------------------------------------------------------

    x_cz = Property(
        Array, depends_on='aramis_info_changed, aramis_data.+params_changed')

    @cached_property
    def _get_x_cz(self):

        # get indices of the strain before and after zero on x-axis
        x_idx = np.where(self.x < 0)
        x1_idx = x_idx[0]
        x2_idx = x1_idx - 1

        x1 = self.x[x1_idx]
        x2 = self.x[x2_idx]
        y2 = self.y[x2_idx]

        x_cz = (y2 * x1) / (x2 + x1)

        print 'x_cz'
        print x_cz
        return x_cz
Esempio n. 24
0
class MRquarter(MushRoofModel):

    implements(ISimModel)
    mushroof_part = 'quarter'

    n_elems_xy_quarter = Int(6, ps_levels=[3, 15, 5])
    n_elems_z = Int(2, ps_levels=[1, 4, 2])

    #----------------------------------------------------
    # elements
    #----------------------------------------------------
    vtk_r = Float(0.9)

    # default roof
    fe_roof = Instance(
        FETSEval,
        ps_levels=[
            'fe2d5_quad_serendipity', 'fe_quad_serendipity', 'fe_linear',
            'fe_quad_lagrange'
        ],
        depends_on='+initial_strain_roof, +initial_strain_col, +vtk_r')

    def _fe_roof_default(self):
        fets = self.fe2d5_quad_serendipity
        #        fets = self.fe_quad_serendipity
        fets.vtk_r *= self.vtk_r
        return fets

    #----------------------------------------------------
    # grid and geometric transformation
    #----------------------------------------------------
    fe_grid_roof = Property(Instance(FEGrid), depends_on='+ps_levels, +input')

    @cached_property
    def _get_fe_grid_roof(self):
        return FEGrid(coord_min=(0.0, 0.0, 0.0),
                      coord_max=(1.0, 1.0, 1.0),
                      geo_transform=self.hp_shell,
                      shape=(self.n_elems_xy, self.n_elems_xy, self.n_elems_z),
                      fets_eval=self.fe2d5_quad_serendipity)
#                       fets_eval = self.fe_roof)
#                       fets_eval = self.fe_quad_serendipity)

    mats_roof = Property(Instance(MATS2D5MicroplaneDamage),
                         depends_on='+input')
    #    mats_roof = Property( Instance( MATS3DElastic), depends_on = '+input' )
    @cached_property
    def _get_mats_roof(self):
        # return MATS3DElastic(E=self.E_roof, nu=self.nu)
        return MATS2D5MicroplaneDamage(E=29100.0,
                                       nu=0.2,
                                       n_mp=30,
                                       symmetrization='sum-type',
                                       model_version='compliance',
                                       phi_fn=self.phi_fn)

    fe2d5_quad_serendipity = Property(Instance(FETSEval, transient=True),
                                      depends_on='+input')

    def _get_fe2d5_quad_serendipity(self):
        return FETS2D58H20U(mats_eval=self.mats_roof)

    fe_quad_serendipity = Property(Instance(FETSEval, transient=True),
                                   depends_on='+input')

    def _get_fe_quad_serendipity(self):
        return FETS3D8H20U(mats_eval=self.mats_roof)

    shrink_factor = Float(1.0)
    # shell
    #
    hp_shell = Property(Instance(HPShell), depends_on='+ps_levels, +input')

    @cached_property
    def _get_hp_shell(self):
        return HPShell(length_xy_quarter=self.length_xy_quarter /
                       self.shrink_factor,
                       length_z=self.length_z / self.shrink_factor,
                       n_elems_xy_quarter=self.n_elems_xy_quarter,
                       n_elems_z=self.n_elems_z,
                       scalefactor_delta_h=self.scalefactor_delta_h,
                       mushroof_part='quarter',
                       shift_elems=False,
                       X0=self.X0)

    #----------------------------------------------------
    # ps_study
    #----------------------------------------------------
    def peval(self):
        '''
        Evaluate the model and return the array of results specified
        in the method get_sim_outputs.
        '''
        U = self.tloop.eval()
        u_center_top_z = U[self.center_top_dof][0, 0, 2]
        print 'u_center_top_z', u_center_top_z
        return np.array([u_center_top_z], dtype='float_')


#        max_princ_stress = max(self.max_princ_stress._get_field_data().flatten())
#        return np.array([ u_center_top_z, max_princ_stress ],
#                        dtype = 'float_')

    def get_sim_outputs(self):
        '''
        Specifies the results and their order returned by the model
        evaluation.
        '''
        return [
            SimOut(name='u_z_free_corner', unit='m'),
            SimOut(name='maximum principal stress', unit='MPa'),
        ]

    #----------------------------------------------------
    # response tracer
    #----------------------------------------------------

    rtrace_list = List

    def _rtrace_list_default(self):
        return [self.eps_app, self.sig_app, self.max_omega_i, self.phi_pdc]

    max_lambda = Float(1.0, input=True)
    '''Maximum lambda factor to impose on the structure.
    The final loading loading level is calculated
    as the reference boundary conditions multiplied by the lambda_factor
    and uls_factor. Thus, lambda factor defines the load level as a multiple
    of the load level predicted by the linear analysis.
    '''

    f_w_diagram = Property(Instance(RTraceGraph),
                           depends_on='+ps_levels, +input')

    @cached_property
    def _get_f_w_diagram(self):
        domain = self.fe_grid_roof
        w_z = domain[-1, -1, -1, -1, -1, -1].dofs[0, 0, 2]
        return RTraceGraph(
            name='load - corner deflection',
            var_x='U_k',
            idx_x=w_z,
            transform_x='-x',
            var_y='time',
            idx_y=0,
            # transform_y='y * %g' % self.lambda_factor,
            record_on='update')

    n_steps = Int(15.0, auto_set=False, enter_set=False, input=True)
    time_fn_load = Instance(MFnLineArray, input=True)

    def _time_fn_load_default(self):
        eta = 0.27 * 1.2
        return MFnLineArray(xdata=[0.0, 1.0, 3.0, 5.0, 8.0, 15.0],
                            ydata=[0.0, 1.0, 1.0 / eta, 1.78 / eta, 8.0, 9.05])

    boundary_x1 = Property(depends_on='+input')

    @cached_property
    def _get_boundary_x1(self):
        return self.fe_grid_roof.domain[-1, :, -1, -1, :, -1]

    #----------------------------------------------------
    # time loop
    #----------------------------------------------------

    tloop = Property(depends_on='+ps_levels, +input')

    @cached_property
    def _get_tloop(self):
        domain = self.fe_grid_roof

        #----------------------------------------------------
        # loading and boundaries
        #----------------------------------------------------

        #--- LC1: dead load
        # g = 22.4 kN/m^3
        # orientation: global z-direction;
        material_density_roof = -22.43e-3  # [MN/m^3]

        #--- LC2 additional dead load
        # gA = 0,20 kN/m^2
        # orientation: global z-direction (following the curved structure);
        additional_dead_load = -0.20e-3  # [MN/m^2]

        #--- LC2 additional boundary load
        # gA = 0,35 kN/m^2
        # orientation: global z-direction (following the curved structure);
        boundary_dead_load = -0.35e-3  # [MN/m]

        #--- LC3 snow
        # s = 0,79 kN/m^2
        # orientation: global z-direction (projection);
        surface_load_s = -0.85e-3  # [MN/m^2]

        #--- LC4 wind (pressure)
        # w = 0,13 kN/m^2
        # orientation: local t-direction (surface normal);
        surface_load_w = -0.13e-3  # [MN/m^2]

        # NOTE: additional line-loads at the edge of the roof need to be considered!

        upper_surface = domain[:, :, -1, :, :, -1]
        whole_domain = domain[:, :, :, :, :, :]
        boundary_x1 = domain[-1, :, -1, -1, :, -1]
        boundary_y1 = domain[:, -1, -1, :, -1, -1]

        time_fn_load = self.time_fn_load

        time_fn_permanent_load = MFnLineArray(xdata=[0.0, 1.0],
                                              ydata=[0.0, 1.0])
        time_fn_snow_load = MFnLineArray(xdata=[0.0, 1.0], ydata=[0.0, 0.0])

        force_bc = [
            # own weight
            BCSlice(name='self weight',
                    var='f',
                    value=material_density_roof,
                    dims=[2],
                    integ_domain='global',
                    time_function=time_fn_load.get_value,
                    slice=whole_domain),

            # LC2: additional dead-load
            BCSlice(name='additional load',
                    var='f',
                    value=additional_dead_load,
                    dims=[2],
                    integ_domain='global',
                    time_function=time_fn_load.get_value,
                    slice=upper_surface),

            # LC2: additional boundary-load
            BCSlice(name='additional boundary load 1',
                    var='f',
                    value=boundary_dead_load,
                    dims=[2],
                    integ_domain='global',
                    time_function=time_fn_load.get_value,
                    slice=boundary_x1),

            # LC2: additional boundary-load
            BCSlice(name='additional boundary load 2',
                    var='f',
                    value=boundary_dead_load,
                    dims=[2],
                    integ_domain='global',
                    time_function=time_fn_load.get_value,
                    slice=boundary_y1),
            # LC3: snow load
            BCSlice(name='snow load',
                    var='f',
                    value=surface_load_s,
                    dims=[2],
                    integ_domain='global',
                    time_function=time_fn_snow_load.get_value,
                    slice=upper_surface),

            #                     # LC3: wind
            #                     BCSlice( var = 'f', value = surface_load_w, dims = [2],
            #                              integ_domain = 'global',
            #                              slice = upper_surface )
        ]

        bc_symplane_yz = BCSlice(var='u',
                                 value=0.,
                                 dims=[0],
                                 slice=domain[0, :, :, 0, :, :])
        bc_symplane_xz = BCSlice(var='u',
                                 value=0.,
                                 dims=[1],
                                 slice=domain[:, 0, :, :, 0, :])
        bc_support_000 = BCSlice(var='u',
                                 value=0.,
                                 dims=[2],
                                 slice=domain[0, 0, 0, :, :, 0])

        #        bc_column = [
        #                     BCSlice( var = 'u'  , dims = [0, 1, 2],
        #                              slice = domain[self.n_elems_xy_quarter - 1,
        #                                               self.n_elems_xy_quarter - 1,
        #                                               0,
        #                                               0, -1, 0 ],
        #                              value = 0. ),
        #                    BCSlice( var = 'u'  , dims = [0, 1, 2],
        #                            slice = domain[self.n_elems_xy_quarter - 1,
        #                                           self.n_elems_xy_quarter - 1 ,
        #                                           0,
        #                                           - 1, 0, 0],
        #                            value = 0. )]

        # bc_corner_load   = BCSlice( var = 'f', value = -nodal_load, dims = [2], slice = domain[-1,-1,-1,-1,-1,-1] )
        # bc_topface_load  = BCSlice( var = 'f', value = -nodal_load, dims = [2], slice = domain[:,:,-1,:,:,-1] )

        #        support_z_dofs = domain[0, 0, 0, :, : , 0].dofs[:, :, 2]
        #        support_f_w = RTraceGraph(name='force - corner deflection',
        #                           var_x='time', idx_x=0,
        #                           transform_x='x * %g' % lambda_failure,
        #                           var_y='F_int', idx_y_arr=np.unique(support_z_dofs.flatten()),
        #                           transform_y='-y',
        #                           record_on='update')

        rtrace_list = [self.f_w_diagram] + self.rtrace_list

        ts = TS(sdomain=[domain],
                dof_resultants=True,
                bcond_list=[bc_symplane_yz, bc_symplane_xz, bc_support_000] +
                force_bc,
                rtrace_list=rtrace_list)

        step = 1.0  # self.n_steps
        # Add the time-loop control
        tloop = TLoop(tstepper=ts,
                      RESETMAX=0,
                      KMAX=70,
                      tolerance=0.5e-3,
                      tline=TLine(min=0.0, step=step,
                                  max=1.0))  # self.max_lambda))
        return tloop
Esempio n. 25
0
class GeoSUPPRT(HasTraits):
    '''Geometry definition of the tappered support added from four hp-surfaces and a planar top-level.
    used for linear reduction of the stiffness of the support.
    '''

    #-----------------------------------------------------------------
    # geometric parameters of the support
    #-----------------------------------------------------------------

    #-----------------
    # geometry:
    #-----------------

    # x and y-direction 
    #
    width_supprt = Float(0.1, input = True)

    # z-direction
    #
    thickness_supprt = Float(0.02, input = True)
    
    # specify offset (translation) of the elastomer patch
    # in global coordinates
    #
    xyoffset = Float(0.0, input = True)
    zoffset = Float(0.0, input = True)

    def __call__(self, pts):
        print '*** geo_slab_test called ***' 
        
        L = self.width_supprt 
        t = self.thickness_supprt
        
        x_, y_, z_ = pts.T
                
        x = np.zeros_like(x_)
        y = np.zeros_like(y_)
        z = np.zeros_like(y_)

        # 1. quadrant     
        #
        bool_x = x_ >= 0.5
        bool_y = y_ >= 0.5 
        bool_xy = bool_x * bool_y
        idx_xy = np.where( bool_xy == 1. )[0]
        rx = (x_[ idx_xy ]-0.5)/0.5
        ry = (y_[ idx_xy ]-0.5)/0.5
        dz_red_ = 0.9 * (rx + ry - rx * ry )
        x[ idx_xy ] = L / 2. + rx * L / 2.
        y[ idx_xy ] = L / 2. + ry * L / 2.
        z[ idx_xy ] = dz_red_ * t

        # 2. quadrant     
        #
        bool_x = x_ >= 0.5
        bool_y = y_ < 0.5 
        bool_xy = bool_x * bool_y
        idx_xy = np.where( bool_xy == 1. )[0]
        rx = (x_[ idx_xy ]-0.5)/0.5
        ry = y_[ idx_xy ]/0.5
        dz_red_ = 0.9 * (rx + (1-ry) - rx * (1-ry) )
        x[ idx_xy ] = L / 2. + rx * L / 2.
        y[ idx_xy ] = ry * L / 2.
        z[ idx_xy ] = dz_red_ * t

        # 3. quadrant     
        #
        bool_x = x_ < 0.5
        bool_y = y_ < 0.5 
        bool_xy = bool_x * bool_y
        idx_xy = np.where( bool_xy == 1. )[0]
        rx = x_[ idx_xy ]/0.5
        ry = y_[ idx_xy ]/0.5
        dz_red_ = 0.9 * ((1-rx) + (1-ry) - (1-rx) * (1-ry) )
        x[ idx_xy ] = rx * L / 2.
        y[ idx_xy ] = ry * L / 2.
        z[ idx_xy ] = dz_red_ * t

        # 4. quadrant     
        #
        bool_x = x_ < 0.5
        bool_y = y_ >= 0.5 
        bool_xy = bool_x * bool_y
        idx_xy = np.where( bool_xy == 1. )[0]
        rx = x_[ idx_xy ]/0.5
        ry = (y_[ idx_xy ]-0.5)/0.5
        dz_red_ = 0.9 * ((1-rx) + ry - (1-rx) * ry )
        x[ idx_xy ] = rx * L / 2.
        y[ idx_xy ] = L / 2. + ry * L / 2.
        z[ idx_xy ] = dz_red_ * t

        # apply z-reduction only at lower row     
        #
        idx_z = np.where( z_ == 1. )[0]
        z[ idx_z ] = z_[ idx_z ] * t
        
        pts = np.c_[x, y, z]
        
        # specify the offset of the position of the support with respect to the global coordinate system
        #
        xyoffset = self.xyoffset
        zoffset = self.zoffset
        offset_arr = np.array([xyoffset, xyoffset, zoffset]) 
        pts = pts + offset_arr

        return pts
Esempio n. 26
0
class ECBReinfTexUniform(ECBReinfComponent):
    '''Cross section characteristics needed for tensile specimens
    '''

    height = DelegatesTo('matrix_cs')
    '''height of reinforced cross section
    '''

    n_layers = Int(12, auto_set=False, enter_set=True, geo_input=True)
    '''total number of reinforcement layers [-]
    '''

    n_rovings = Int(23, auto_set=False, enter_set=True, geo_input=True)
    '''number of rovings in 0-direction of one composite layer of the
    bending test [-]:
    '''

    A_roving = Float(0.461, auto_set=False, enter_set=True, geo_input=True)
    '''cross section of one roving [mm**2]'''
    def convert_eps_tex_u_2_lo(self, eps_tex_u):
        '''Convert the strain in the lowest reinforcement layer at failure
        to the strain at the bottom of the cross section'''
        eps_up = self.state.eps_up
        return eps_up + (eps_tex_u - eps_up) / self.z_ti_arr[0] * self.height

    def convert_eps_lo_2_tex_u(self, eps_lo):
        '''Convert the strain at the bottom of the cross section to the strain
        in the lowest reinforcement layer at failure'''
        eps_up = self.state.eps_up
        return (eps_up + (eps_lo - eps_up) / self.height * self.z_ti_arr[0])

    '''Convert the MN to kN
    '''

    #===========================================================================
    # material properties
    #===========================================================================

    sig_tex_u = Float(1216., auto_set=False, enter_set=True, tt_input=True)
    '''Ultimate textile stress measured in the tensile test [MPa]
    '''

    #===========================================================================
    # Distribution of reinforcement
    #===========================================================================

    s_tex_z = Property(depends_on=ECB_COMPONENT_AND_EPS_CHANGE)
    '''spacing between the layers [m]'''

    @cached_property
    def _get_s_tex_z(self):
        return self.height / (self.n_layers + 1)

    z_ti_arr = Property(depends_on=ECB_COMPONENT_AND_EPS_CHANGE)
    '''property: distance of each reinforcement layer from the top [m]:
    '''

    @cached_property
    def _get_z_ti_arr(self):
        return np.array([
            self.height - (i + 1) * self.s_tex_z for i in range(self.n_layers)
        ],
                        dtype=float)

    zz_ti_arr = Property
    '''property: distance of reinforcement layers from the bottom
    '''

    def _get_zz_ti_arr(self):
        return self.height - self.z_ti_arr

    #===========================================================================
    # Discretization conform to the tex layers
    #===========================================================================

    eps_i_arr = Property(depends_on=ECB_COMPONENT_AND_EPS_CHANGE)
    '''Strain at the level of the i-th reinforcement layer
    '''

    @cached_property
    def _get_eps_i_arr(self):
        # ------------------------------------------------------------------------
        # geometric params independent from the value for 'eps_t'
        # ------------------------------------------------------------------------
        height = self.height
        eps_lo = self.state.eps_lo
        eps_up = self.state.eps_up
        # strain at the height of each reinforcement layer [-]:
        #
        return eps_up + (eps_lo - eps_up) * self.z_ti_arr / height

    eps_ti_arr = Property(depends_on=ECB_COMPONENT_AND_EPS_CHANGE)
    '''Tension strain at the level of the i-th layer of the fabrics
    '''

    @cached_property
    def _get_eps_ti_arr(self):
        return (np.fabs(self.eps_i_arr) + self.eps_i_arr) / 2.0

    eps_ci_arr = Property(depends_on=ECB_COMPONENT_AND_EPS_CHANGE)
    '''Compression strain at the level of the i-th layer.
    '''

    @cached_property
    def _get_eps_ci_arr(self):
        return (-np.fabs(self.eps_i_arr) + self.eps_i_arr) / 2.0

    #===========================================================================
    # Effective crack bridge law
    #===========================================================================
    ecb_law_type = Trait('fbm',
                         dict(fbm=ECBLFBM,
                              cubic=ECBLCubic,
                              linear=ECBLLinear,
                              bilinear=ECBLBilinear),
                         tt_input=True)
    '''Selector of the effective crack bridge law type
    ['fbm', 'cubic', 'linear', 'bilinear']'''

    ecb_law = Property(Instance(ECBLBase), depends_on='+tt_input')
    '''Effective crack bridge law corresponding to ecb_law_type'''

    @cached_property
    def _get_ecb_law(self):
        return self.ecb_law_type_(sig_tex_u=self.sig_tex_u, cs=self)

    show_ecb_law = Button
    '''Button launching a separate view of the effective crack bridge law.
    '''

    def _show_ecb_law_fired(self):
        ecb_law_mw = ConstitutiveLawModelView(model=self.ecb_law)
        ecb_law_mw.edit_traits(kind='live')
        return

    tt_modified = Event

    sig_ti_arr = Property(depends_on=ECB_COMPONENT_AND_EPS_CHANGE)
    '''Stresses at the i-th fabric layer.
    '''

    @cached_property
    def _get_sig_ti_arr(self):
        return self.ecb_law.mfn_vct(self.eps_ti_arr)

    f_ti_arr = Property(depends_on=ECB_COMPONENT_AND_EPS_CHANGE)
    '''force at the height of each reinforcement layer [kN]:
    '''

    @cached_property
    def _get_f_ti_arr(self):
        sig_ti_arr = self.sig_ti_arr
        n_rovings = self.n_rovings
        A_roving = self.A_roving
        return sig_ti_arr * n_rovings * A_roving / self.unit_conversion_factor

    figure = Instance(Figure)

    def _figure_default(self):
        figure = Figure(facecolor='white')
        figure.add_axes([0.08, 0.13, 0.85, 0.74])
        return figure

    data_changed = Event

    replot = Button

    def _replot_fired(self):

        self.figure.clear()
        ax = self.figure.add_subplot(2, 2, 1)
        self.plot_eps(ax)

        ax = self.figure.add_subplot(2, 2, 2)
        self.plot_sig(ax)

        ax = self.figure.add_subplot(2, 2, 3)
        self.cc_law.plot(ax)

        ax = self.figure.add_subplot(2, 2, 4)
        self.ecb_law.plot(ax)

        self.data_changed = True

    def plot_eps(self, ax):
        #ax = self.figure.gca()

        d = self.height
        # eps ti
        ax.plot([-self.eps_lo, -self.eps_up], [0, self.height], color='black')
        ax.hlines(self.zz_ti_arr, [0], -self.eps_ti_arr, lw=4, color='red')

        # eps cj
        ec = np.hstack([self.eps_cj_arr] + [0, 0])
        zz = np.hstack([self.zz_cj_arr] + [0, self.height])
        ax.fill(-ec, zz, color='blue')

        # reinforcement layers
        eps_range = np.array([max(0.0, self.eps_lo),
                              min(0.0, self.eps_up)],
                             dtype='float')
        z_ti_arr = np.ones_like(eps_range)[:, None] * self.z_ti_arr[None, :]
        ax.plot(-eps_range, z_ti_arr, 'k--', color='black')

        # neutral axis
        ax.plot(-eps_range, [d, d], 'k--', color='green', lw=2)

        ax.spines['left'].set_position('zero')
        ax.spines['right'].set_color('none')
        ax.spines['top'].set_color('none')
        ax.spines['left'].set_smart_bounds(True)
        ax.spines['bottom'].set_smart_bounds(True)
        ax.xaxis.set_ticks_position('bottom')
        ax.yaxis.set_ticks_position('left')

    def plot_sig(self, ax):

        d = self.height
        # f ti
        ax.hlines(self.zz_ti_arr, [0], -self.f_ti_arr, lw=4, color='red')

        # f cj
        f_c = np.hstack([self.f_cj_arr] + [0, 0])
        zz = np.hstack([self.zz_cj_arr] + [0, self.height])
        ax.fill(-f_c, zz, color='blue')

        f_range = np.array(
            [np.max(self.f_ti_arr), np.min(f_c)], dtype='float_')
        # neutral axis
        ax.plot(-f_range, [d, d], 'k--', color='green', lw=2)

        ax.spines['left'].set_position('zero')
        ax.spines['right'].set_color('none')
        ax.spines['top'].set_color('none')
        ax.spines['left'].set_smart_bounds(True)
        ax.spines['bottom'].set_smart_bounds(True)
        ax.xaxis.set_ticks_position('bottom')
        ax.yaxis.set_ticks_position('left')

    view = View(HSplit(
        Group(
            HGroup(
                Group(Item('height', springy=True),
                      Item('width'),
                      Item('n_layers'),
                      Item('n_rovings'),
                      Item('A_roving'),
                      label='Geometry',
                      springy=True),
                Group(Item('eps_up', label='Upper strain', springy=True),
                      Item('eps_lo', label='Lower strain'),
                      label='Strain',
                      springy=True),
                springy=True,
            ),
            HGroup(
                Group(VGroup(Item('cc_law_type',
                                  show_label=False,
                                  springy=True),
                             Item('cc_law',
                                  label='Edit',
                                  show_label=False,
                                  springy=True),
                             Item('show_cc_law',
                                  label='Show',
                                  show_label=False,
                                  springy=True),
                             springy=True),
                      Item('f_ck', label='Compressive strength'),
                      Item('n_cj', label='Discretization'),
                      label='Concrete',
                      springy=True),
                Group(VGroup(
                    Item('ecb_law_type', show_label=False, springy=True),
                    Item('ecb_law',
                         label='Edit',
                         show_label=False,
                         springy=True),
                    Item('show_ecb_law',
                         label='Show',
                         show_label=False,
                         springy=True),
                    springy=True,
                ),
                      label='Reinforcement',
                      springy=True),
                springy=True,
            ),
            Group(
                Item('s_tex_z', label='vertical spacing', style='readonly'),
                label='Layout',
            ),
            Group(HGroup(
                Item('M', springy=True, style='readonly'),
                Item('N', springy=True, style='readonly'),
            ),
                  label='Stress resultants'),
            scrollable=True,
        ),
        Group(
            Item('replot', show_label=False),
            Item('figure',
                 editor=MPLFigureEditor(),
                 resizable=True,
                 show_label=False),
            id='simexdb.plot_sheet',
            label='plot sheet',
            dock='tab',
        ),
    ),
                width=0.8,
                height=0.7,
                resizable=True,
                buttons=['OK', 'Cancel'])
Esempio n. 27
0
class RFBase(RF):

    implements(IRF)

    title = Str('RFSumParams')

    a = Float(1,
              auto_set=False,
              enter_set=True,
              distr=['uniform'],
              loc=1.0,
              scale=0.1,
              shape=0.1)

    b = Float(1,
              auto_set=False,
              enter_set=True,
              distr=['uniform'],
              loc=1.0,
              scale=0.1,
              shape=0.1)

    c = Float(1,
              auto_set=False,
              enter_set=True,
              distr=['uniform'],
              loc=1.0,
              scale=0.1,
              shape=0.1)

    d = Float(1,
              auto_set=False,
              enter_set=True,
              distr=['uniform'],
              loc=1.0,
              scale=0.1,
              shape=0.1)

    ee = Float(1,
               auto_set=False,
               enter_set=True,
               distr=['uniform'],
               loc=1.0,
               scale=0.1,
               shape=0.1)

    f = Float(1,
              auto_set=False,
              enter_set=True,
              distr=['uniform'],
              loc=1.0,
              scale=0.1,
              shape=0.1)

    g = Float(1,
              auto_set=False,
              enter_set=True,
              distr=['uniform'],
              loc=1.0,
              scale=0.1,
              shape=0.1)

    h = Float(1,
              auto_set=False,
              enter_set=True,
              distr=['uniform'],
              loc=1.0,
              scale=0.1,
              shape=0.1)

    i = Float(1,
              auto_set=False,
              enter_set=True,
              distr=['uniform'],
              loc=1.0,
              scale=0.1,
              shape=0.1)

    k = Float(1,
              auto_set=False,
              enter_set=True,
              distr=['uniform'],
              loc=1.0,
              scale=0.1,
              shape=0.1)
Esempio n. 28
0
class SimDT(IBVModel):
    '''Simulation: Disk Test
    '''

    implements(ISimModel)

    material_density_roof = Float(-22.4e-3)  # [MN/m^3]

    #----------------------------------------------------
    # elements
    #----------------------------------------------------

    n_elems = Int(50, input=True)
    thickness = Float(1.0, input=True)

    vtk_r = Float(0.9, input=True)

    # fets used for roof
    #
    fets_disk = Instance((FETSEval), depends_on='+ps_levels, +input')

    def _fets_disk_default(self):
        # fe_quad_serendipity_roof is defined in base class
        # connected with material properties of the roof
        #
        mats = MATS2DElastic(E=3.1e5, nu=0.0, stress_state='plane_stress')
        fets = FETS2D4Q8U(mats_eval=mats)
        fets.vtk_r *= self.vtk_r
        return fets

    geo_disk = Property(depends_on='+ps_levels, +input')

    @cached_property
    def _get_geo_disk(self):
        # list of local origins of each roof defined in global coordinates
        # (for MRDetail two roofs are considered due to symmetry)
        #
        gt = GeoSquare2Circle(circle_center=[0.0, 0.0],
                              circle_radius=1.0,
                              square_edge=4.0)
        return gt

    #----------------------------------------------------
    # fe-grids
    #----------------------------------------------------

    fe_disk_grid = Property(Instance(FEGrid), depends_on='+ps_levels, +input')

    @cached_property
    def _get_fe_disk_grid(self):
        fe_grid = FEGrid(coord_min=(-1, -1),
                         coord_max=(1, 1),
                         geo_transform=self.geo_disk,
                         shape=(self.n_elems, self.n_elems),
                         fets_eval=self.fets_disk)
        return fe_grid

    bc_fixed = Property(depends_on='+ps_levels, +input')

    @cached_property
    def _get_bc_fixed(self):
        fe_disk_grid = self.fe_disk_grid

        extension = 0.1
        alpha_45 = math.pi / 4.0

        bc00 = BCDof(var='u',
                     dof=fe_disk_grid[0, 0, 0, 0].dofs[0, 0, 1],
                     value=-extension * math.cos(alpha_45))

        bc00_link = BCDof(var='u',
                          dof=fe_disk_grid[0, 0, 0, 0].dofs[0, 0, 0],
                          link_dofs=[fe_disk_grid[0, 0, 0, 0].dofs[0, 0, 1]],
                          link_coeffs=[1.0],
                          value=0)

        bc10 = BCDof(var='u',
                     dof=fe_disk_grid[-1, 0, -1, 0].dofs[0, 0, 1],
                     value=-extension * math.cos(alpha_45))

        bc10_link = BCDof(var='u',
                          dof=fe_disk_grid[-1, 0, -1, 0].dofs[0, 0, 0],
                          link_dofs=[fe_disk_grid[-1, 0, -1, 0].dofs[0, 0, 1]],
                          link_coeffs=[-1.0],
                          value=0)

        bc11 = BCDof(var='u',
                     dof=fe_disk_grid[-1, -1, -1, -1].dofs[0, 0, 1],
                     value=extension * math.cos(alpha_45))

        bc11_link = BCDof(
            var='u',
            dof=fe_disk_grid[-1, -1, -1, -1].dofs[0, 0, 0],
            link_dofs=[fe_disk_grid[-1, -1, -1, -1].dofs[0, 0, 1]],
            link_coeffs=[1.0],
            value=0)

        bc01 = BCDof(var='u',
                     dof=fe_disk_grid[0, -1, 0, -1].dofs[0, 0, 1],
                     value=extension * math.cos(alpha_45))

        bc01_link = BCDof(var='u',
                          dof=fe_disk_grid[0, -1, 0, -1].dofs[0, 0, 0],
                          link_dofs=[fe_disk_grid[0, -1, 0, -1].dofs[0, 0, 1]],
                          link_coeffs=[-1.0],
                          value=0)

        n_xy = self.n_elems / 2

        bc_bottom = BCDof(var='u',
                          dof=fe_disk_grid[n_xy, 0, 0, 0].dofs[0, 0, 1],
                          value=-extension)
        bc_right = BCDof(var='u',
                         dof=fe_disk_grid[-1, n_xy, -1, 0].dofs[0, 0, 0],
                         value=extension)
        bc_top = BCDof(var='u',
                       dof=fe_disk_grid[n_xy, -1, 0, -1].dofs[0, 0, 1],
                       value=extension)
        bc_left = BCDof(var='u',
                        dof=fe_disk_grid[0, n_xy, 0, 0].dofs[0, 0, 0],
                        value=-extension)

        return [
            bc_left, bc_right, bc_top, bc_bottom, bc00, bc00_link, bc10,
            bc10_link, bc11, bc11_link, bc01, bc01_link
        ]

    #----------------------------------------------------
    # ps_study
    #----------------------------------------------------
    def peval(self):
        '''
        Evaluate the model and return the array of results specified
        in the method get_sim_outputs.
        '''

        # DISPLACEMENT
        #
        U = self.tloop.eval()

    def get_sim_outputs(self):
        '''
        Specifies the results and their order returned by the model
        evaluation.
        '''
        return [
            SimOut(name='$u_z$', unit='[mm]'),
        ]

    #----------------------------------------------------
    # response tracer
    #----------------------------------------------------

    rtrace_list = List

    def _rtrace_list_default(self):
        return [self.max_princ_stress, self.sig_app, self.u]

    max_princ_stress = Instance(RTraceDomainListField)

    def _max_princ_stress_default(self):
        return RTraceDomainListField(
            name='max principle stress',
            idx=0,
            var='max_principle_sig',
            warp=True,
            #                                      position = 'int_pnts',
            record_on='update',
        )

    sig_app = Property(Instance(RTraceDomainListField),
                       depends_on='+ps_levels, +input')

    @cached_property
    def _get_sig_app(self):
        return RTraceDomainListField(
            name='sig_app',
            position='int_pnts',
            var='sig_app',
            record_on='update',
        )

    u = Property(Instance(RTraceDomainListField),
                 depends_on='+ps_levels, +input')

    @cached_property
    def _get_u(self):
        return RTraceDomainListField(
            name='displacement',
            var='u',
            warp=True,
            record_on='update',
        )

    #----------------------------------------------------
    # time loop
    #----------------------------------------------------

    tline = Instance(TLine)

    def _tline_default(self):
        return TLine(min=0.0, step=1.0, max=1.0)

    tloop = Property(depends_on='+ps_levels, +input')

    @cached_property
    def _get_tloop(self):

        roof = self.fe_disk_grid

        # self.bc_roof_deadweight + \
        bc_list = self.bc_fixed

        ts = TS(sdomain=[roof],
                dof_resultants=True,
                bcond_list=bc_list,
                rtrace_list=self.rtrace_list)

        # Add the time-loop control
        #
        tloop = TLoop(tstepper=ts, tolerance=1e-4, tline=self.tline)

        return tloop
Esempio n. 29
0
class SimBT4PT(IBVModel):
    '''Simulation: four point bending test.
    '''

    input_change = Event

    @on_trait_change('+input,ccs_unit_cell.input_change')
    def _set_input_change(self):
        self.input_change = True

    implements(ISimModel)

    #-----------------
    # discretization:
    #-----------------

    # specify weather the elastomer is to be modeled or if the load is
    # introduced as line load
    #
    elstmr_flag = Bool(True)

    # discretization in x-direction (longitudinal):
    #
    outer_zone_shape_x = Int(6, input=True, ps_levels=(4, 12, 3))

    # discretization in x-direction (longitudinal):
    #
    load_zone_shape_x = Int(2, input=True, ps_levels=(1, 4, 1))

    # middle part discretization in x-direction (longitudinal):
    #
    mid_zone_shape_x = Int(3, input=True, ps_levels=(1, 4, 1))

    # discretization in y-direction (width):
    #
    shape_y = Int(2, input=True, ps_levels=(1, 4, 2))

    # discretization in z-direction:
    #
    shape_z = Int(2, input=True, ps_levels=(1, 3, 3))

    #-----------------
    # geometry:
    #-----------------
    #
    # edge length of the bending specimen (beam) (entire length without symmetry)
    #
    length = Float(1.50, input=True)

    elstmr_length = Float(0.05, input=True)
    mid_zone_length = Float(0.50, input=True)
    elstmr_thickness = Float(0.005, input=True)
    width = Float(0.20, input=True)
    thickness = Float(0.06, input=True)

    #-----------------
    # derived geometric parameters
    #-----------------
    #
    # half the length of the elastomer (load introduction
    # with included symmetry)
    #
    sym_specmn_length = Property

    def _get_sym_specmn_length(self):
        return self.length / 2.

    sym_mid_zone_specmn_length = Property

    def _get_sym_mid_zone_specmn_length(self):
        return self.mid_zone_length / 2.

    # half the length of the elastomer (load introduction
    # with included symmetry
    #
    sym_elstmr_length = Property

    def _get_sym_elstmr_length(self):
        return self.elstmr_length / 2.

    # half the specimen width
    #
    sym_width = Property

    def _get_sym_width(self):
        return self.width / 2.

    #----------------------------------------------------------------------------------
    # mats_eval
    #----------------------------------------------------------------------------------

    # age of the plate at the time of testing
    # NOTE: that the same phi-function is used independent of age. This assumes a
    # an afine/proportional damage evolution for different ages.
    #
    age = Int(28, input=True)

    # time stepping params
    #
    tstep = Float(0.05, auto_set=False, enter_set=True, input=True)
    tmax = Float(1.0, auto_set=False, enter_set=True, input=True)
    tolerance = Float(0.001, auto_set=False, enter_set=True, input=True)

    # specify type of 'linalg.norm'
    # default value 'None' sets norm to 2-norm,
    # i.e "norm = sqrt(sum(x_i**2))
    #
    # set 'ord=np.inf' to switch norm to
    # "norm = max(abs(x_i))"
    #
    ord = Enum(np.inf, None)

    n_mp = Int(30, input=True)

    # @todo: for mats_eval the information of the unit cell should be used
    # in order to use the same number of microplanes and model version etc...
    #
    specmn_mats = Property(Instance(MATS2D5MicroplaneDamage),
                           depends_on='input_change')

    @cached_property
    def _get_specmn_mats(self):
        return MATS2D5MicroplaneDamage(
            E=self.E_c,
            #                                 E=self.E_m,
            nu=self.nu,
            # corresponding to settings in "MatsCalib"
            n_mp=self.n_mp,
            symmetrization='sum-type',
            model_version='compliance',
            phi_fn=self.phi_fn)

    if elstmr_flag:
        elstmr_mats = Property(Instance(MATS3DElastic),
                               depends_on='input_change')

        @cached_property
        def _get_elstmr_mats(self):
            # specify a small elastomer stiffness (approximation)
            E_elast = self.E_c / 10.
            print 'effective elastomer E_modulus', E_elast
            return MATS3DElastic(E=E_elast, nu=0.4)

    #-----------------
    # fets:
    #-----------------

    # specify element shrink factor in plot of fe-model
    #
    vtk_r = Float(0.95)

    # use quadratic serendipity elements
    #
    specmn_fets = Property(Instance(FETSEval), depends_on='input_change')

    @cached_property
    def _get_specmn_fets(self):
        fets = FETS2D58H20U(mats_eval=self.specmn_mats)
        fets.vtk_r *= self.vtk_r
        return fets

    # use quadratic serendipity elements
    #
    elstmr_fets = Property(Instance(FETSEval), depends_on='input_change')

    @cached_property
    def _get_elstmr_fets(self):
        fets = FETS2D58H20U(mats_eval=self.elstmr_mats)
        fets.vtk_r *= self.vtk_r
        return fets

    fe_domain = Property(depends_on='+ps_levels, +input')

    @cached_property
    def _get_fe_domain(self):
        return FEDomain()

    #===========================================================================
    # fe level
    #===========================================================================

    outer_zone_specmn_fe_level = Property(depends_on='+ps_levels, +input')

    def _get_outer_zone_specmn_fe_level(self):
        return FERefinementGrid(name='outer zone specimen patch',
                                fets_eval=self.specmn_fets,
                                domain=self.fe_domain)

    load_zone_specmn_fe_level = Property(depends_on='+ps_levels, +input')

    def _get_load_zone_specmn_fe_level(self):
        return FERefinementGrid(name='load zone specimen patch',
                                fets_eval=self.specmn_fets,
                                domain=self.fe_domain)

    mid_zone_specmn_fe_level = Property(depends_on='+ps_levels, +input')

    def _get_mid_zone_specmn_fe_level(self):
        return FERefinementGrid(name='mid zone specimen patch',
                                fets_eval=self.specmn_fets,
                                domain=self.fe_domain)

    elstmr_fe_level = Property(depends_on='+ps_levels, +input')

    def _get_elstmr_fe_level(self):
        return FERefinementGrid(name='elastomer patch',
                                fets_eval=self.elstmr_fets,
                                domain=self.fe_domain)

    #===========================================================================
    # Grid definition
    #===========================================================================

    mid_zone_specmn_fe_grid = Property(Instance(FEGrid),
                                       depends_on='+ps_levels, +input')

    @cached_property
    def _get_mid_zone_specmn_fe_grid(self):
        # only a quarter of the beam is simulated due to symmetry:
        fe_grid = FEGrid(coord_min=(0., 0., 0.),
                         coord_max=(self.sym_mid_zone_specmn_length -
                                    self.sym_elstmr_length, self.sym_width,
                                    self.thickness),
                         shape=(self.mid_zone_shape_x, self.shape_y,
                                self.shape_z),
                         level=self.mid_zone_specmn_fe_level,
                         fets_eval=self.specmn_fets)
        return fe_grid

    load_zone_specmn_fe_grid = Property(Instance(FEGrid),
                                        depends_on='+ps_levels, +input')

    @cached_property
    def _get_load_zone_specmn_fe_grid(self):
        # only a quarter of the beam is simulated due to symmetry:
        fe_grid = FEGrid(coord_min=(self.sym_mid_zone_specmn_length -
                                    self.sym_elstmr_length, 0., 0.),
                         coord_max=(self.sym_mid_zone_specmn_length +
                                    self.sym_elstmr_length, self.sym_width,
                                    self.thickness),
                         shape=(self.load_zone_shape_x, self.shape_y,
                                self.shape_z),
                         level=self.load_zone_specmn_fe_level,
                         fets_eval=self.specmn_fets)
        return fe_grid

#    if elstmr_flag:

    elstmr_fe_grid = Property(Instance(FEGrid),
                              depends_on='+ps_levels, +input')

    @cached_property
    def _get_elstmr_fe_grid(self):
        fe_grid = FEGrid(coord_min=(self.sym_mid_zone_specmn_length -
                                    self.sym_elstmr_length, 0.,
                                    self.thickness),
                         coord_max=(self.sym_mid_zone_specmn_length +
                                    self.sym_elstmr_length, self.sym_width,
                                    self.thickness + self.elstmr_thickness),
                         level=self.elstmr_fe_level,
                         shape=(self.load_zone_shape_x, self.shape_y, 1),
                         fets_eval=self.elstmr_fets)
        return fe_grid

    outer_zone_specmn_fe_grid = Property(Instance(FEGrid),
                                         depends_on='+ps_levels, +input')

    @cached_property
    def _get_outer_zone_specmn_fe_grid(self):
        # only a quarter of the plate is simulated due to symmetry:
        fe_grid = FEGrid(coord_min=(self.sym_mid_zone_specmn_length +
                                    self.sym_elstmr_length, 0., 0.),
                         coord_max=(self.sym_specmn_length, self.sym_width,
                                    self.thickness),
                         shape=(self.outer_zone_shape_x, self.shape_y,
                                self.shape_z),
                         level=self.outer_zone_specmn_fe_level,
                         fets_eval=self.specmn_fets)
        return fe_grid

    #===========================================================================
    # Boundary conditions
    #===========================================================================
    w_max = Float(-0.030, input=True)  # [m]

    w_max = Float(-0.030, input=True)  # [m]

    bc_list = Property(depends_on='+ps_levels, +input')

    @cached_property
    def _get_bc_list(self):
        mid_zone_specimen = self.mid_zone_specmn_fe_grid
        load_zone_specimen = self.load_zone_specmn_fe_grid
        outer_zone_specimen = self.outer_zone_specmn_fe_grid

        if self.elstmr_flag:
            elastomer = self.elstmr_fe_grid

        #--------------------------------------------------------------
        # boundary conditions for the symmetry
        #--------------------------------------------------------------
        # symmetry in the xz-plane
        # (Note: the x-axis corresponds to the axis of symmetry along the longitudinal axis of the beam)
        #
        bc_outer_zone_symplane_xz = BCSlice(var='u',
                                            value=0.,
                                            dims=[1],
                                            slice=outer_zone_specimen[:,
                                                                      0, :, :,
                                                                      0, :])
        bc_load_zone_symplane_xz = BCSlice(var='u',
                                           value=0.,
                                           dims=[1],
                                           slice=load_zone_specimen[:, 0, :, :,
                                                                    0, :])
        bc_mid_zone_symplane_xz = BCSlice(var='u',
                                          value=0.,
                                          dims=[1],
                                          slice=mid_zone_specimen[:, 0, :, :,
                                                                  0, :])

        if self.elstmr_flag:
            bc_el_symplane_xz = BCSlice(var='u',
                                        value=0.,
                                        dims=[1],
                                        slice=elastomer[:, 0, :, :, 0, :])
        # symmetry in the yz-plane
        #
        bc_mid_zone_symplane_yz = BCSlice(var='u',
                                          value=0.,
                                          dims=[0],
                                          slice=mid_zone_specimen[0, :, :,
                                                                  0, :, :])

        #--------------------------------------------------------------
        # boundary conditions for the support
        #--------------------------------------------------------------
        bc_support_0y0 = BCSlice(var='u',
                                 value=0.,
                                 dims=[2],
                                 slice=outer_zone_specimen[-1, :, 0, -1, :, 0])

        #--------------------------------------------------------------
        # connect all grids
        #--------------------------------------------------------------
        link_loadzn_outerzn = BCDofGroup(
            var='u',
            value=0.,
            dims=[0, 1, 2],
            get_dof_method=load_zone_specimen.get_right_dofs,
            get_link_dof_method=outer_zone_specimen.get_left_dofs,
            link_coeffs=[1.])
        link_midzn_loadzn = BCDofGroup(
            var='u',
            value=0.,
            dims=[0, 1, 2],
            get_dof_method=mid_zone_specimen.get_right_dofs,
            get_link_dof_method=load_zone_specimen.get_left_dofs,
            link_coeffs=[1.])

        if self.elstmr_flag:
            link_elstmr_loadzn_z = BCDofGroup(
                var='u',
                value=0.,
                dims=[2],
                get_dof_method=elastomer.get_back_dofs,
                get_link_dof_method=load_zone_specimen.get_front_dofs,
                link_coeffs=[1.])

            # hold elastomer in a single point in order to avoid kinematic movement yielding singular K_mtx
            #
            bc_elstmr_fix = BCSlice(var='u',
                                    value=0.,
                                    dims=[0],
                                    slice=elastomer[0, 0, 0, 0, 0, 0])

        #--------------------------------------------------------------
        # loading
        #--------------------------------------------------------------
        # w_max = center displacement:
        w_max = self.w_max

        if self.elstmr_flag:
            # apply displacement at all top nodes of the elastomer (surface load)
            #
            bc_w = BCSlice(var='u',
                           value=w_max,
                           dims=[2],
                           slice=elastomer[:, :, -1, :, :, -1])
        else:
            bc_w = BCSlice(
                var='u',
                value=w_max,
                dims=[2],
                # slice is only exactly in the center of the loading zone for 'load_zone_shape_x' = 2
                # center line of the load zone
                slice=load_zone_specimen[0, :, -1, -1, :, -1])


#        f_max = 0.010 / 4. / self.sym_width
#        bc_line_f = BCSlice(var = 'f', value = f_max, dims = [2],
#                            # slice is only valid for 'load_zone_shape_x' = 2
#                            # center line of the load zone
#                            slice = load_zone_specimen[0, :, -1, -1, :, -1])

        bc_list = [
            bc_outer_zone_symplane_xz,
            bc_load_zone_symplane_xz,
            bc_mid_zone_symplane_xz,
            bc_mid_zone_symplane_yz,
            #
            link_midzn_loadzn,
            link_loadzn_outerzn,
            bc_support_0y0,
            #
            bc_w,
        ]

        if self.elstmr_flag:
            bc_list += [bc_el_symplane_xz, link_elstmr_loadzn_z, bc_elstmr_fix]

        return bc_list

    #----------------------
    # tloop
    #----------------------

    tloop = Property(depends_on='input_change')

    @cached_property
    def _get_tloop(self):

        #--------------------------------------------------------------
        # ts
        #--------------------------------------------------------------

        mid_zone_spec = self.mid_zone_specmn_fe_grid
        load_zone_spec = self.load_zone_specmn_fe_grid
        outer_zone_spec = self.outer_zone_specmn_fe_grid

        if self.elstmr_flag:
            # ELSTRMR TOP SURFACE
            # dofs at elastomer top surface (used to integrate the force)
            #
            elastomer = self.elstmr_fe_grid
            elstmr_top_dofs_z = elastomer[:, :, -1, :, :,
                                          -1].dofs[:, :, 2].flatten()
            load_dofs_z = np.unique(elstmr_top_dofs_z)
            print 'load_dofs_z', load_dofs_z
        else:
            # LINE LOAD TOP OF LOAD ZONE
            # dofs at center line of the specmn load zone (used to integrate the force)
            # note slice index in x-direction is only valid for load_zone_shape_x = 2 !
            #
            load_zone_spec_topline_dofs_z = load_zone_spec[
                0, :, -1, -1, :, -1].dofs[:, :, 2].flatten()
            load_dofs_z = np.unique(load_zone_spec_topline_dofs_z)
            print 'load_dofs_z', load_dofs_z

        # SUPPRT LINE
        # dofs at support line of the specmn (used to integrate the force)
        #
        outer_zone_spec_supprtline_dofs_z = outer_zone_spec[
            -1, :, 0, -1, :, 0].dofs[:, :, 2].flatten()
        supprt_dofs_z = np.unique(outer_zone_spec_supprtline_dofs_z)
        print 'supprt_dofs_z', supprt_dofs_z

        # CENTER DOF (used for tracing of the displacement)
        #
        center_bottom_dof = mid_zone_spec[0, 0, 0, 0, 0, 0].dofs[0, 0, 2]
        print 'center_bottom_dof', center_bottom_dof

        # THIRDPOINT DOF (used for tracing of the displacement)
        # dofs at center middle of the laod zone at the bottom side
        #
        # NOTE: slice index in x-direction is only valid for load_zone_shape_x = 2 !
        thirdpoint_bottom_dof = load_zone_spec[0, 0, 0, -1, 0, 0].dofs[0, 0, 2]
        print 'thirdpoint_bottom_dof', thirdpoint_bottom_dof

        # force-displacement-diagram (CENTER)
        #
        self.f_w_diagram_center = RTraceGraph(
            name='displacement_elasttop (center) - force',
            var_x='U_k',
            idx_x=center_bottom_dof,
            var_y='F_int',
            idx_y_arr=load_dofs_z,
            record_on='update',
            transform_x='-x * 1000',  # %g * x' % ( fabs( w_max ),),
            # due to symmetry the total force sums up from four parts of the beam (2 symmetry axis):
            #
            transform_y='-4000. * y')

        # force-displacement-diagram_supprt (SUPPRT)
        #
        self.f_w_diagram_supprt = RTraceGraph(
            name='displacement_supprtline (center) - force',
            var_x='U_k',
            idx_x=center_bottom_dof,
            var_y='F_int',
            idx_y_arr=supprt_dofs_z,
            record_on='update',
            transform_x='-x * 1000',  # %g * x' % ( fabs( w_max ),),
            # due to symmetry the total force sums up from four parts of the beam (2 symmetry axis):
            #
            transform_y='4000. * y')

        # force-displacement-diagram (THIRDPOINT)
        #
        self.f_w_diagram_thirdpoint = RTraceGraph(
            name='displacement_elasttop (thirdpoint) - force',
            var_x='U_k',
            idx_x=thirdpoint_bottom_dof,
            var_y='F_int',
            idx_y_arr=load_dofs_z,
            record_on='update',
            transform_x='-x * 1000',  # %g * x' % ( fabs( w_max ),),
            # due to symmetry the total force sums up from four parts of the beam (2 symmetry axis):
            #
            transform_y='-4000. * y')

        ts = TS(
            sdomain=self.fe_domain,
            bcond_list=self.bc_list,
            rtrace_list=[
                self.f_w_diagram_center,
                self.f_w_diagram_thirdpoint,
                self.f_w_diagram_supprt,
                RTraceDomainListField(name='Displacement',
                                      var='u',
                                      idx=0,
                                      warp=True),
                #                             RTraceDomainListField(name = 'Stress' ,
                #                                            var = 'sig_app', idx = 0, warp = True,
                #                                            record_on = 'update'),
                #                             RTraceDomainListField(name = 'Strain' ,
                #                                        var = 'eps_app', idx = 0, warp = True,
                #                                        record_on = 'update'),
                #                             RTraceDomainListField(name = 'Damage' ,
                #                                        var = 'omega_mtx', idx = 0, warp = True,
                #                                        record_on = 'update'),
                RTraceDomainListField(name='max_omega_i',
                                      warp=True,
                                      var='max_omega_i',
                                      idx=0,
                                      record_on='update'),
                #                             RTraceDomainListField(name = 'IStress' ,
                #                                            position = 'int_pnts',
                #                                            var = 'sig_app', idx = 0,
                #                                            record_on = 'update'),
                #                             RTraceDomainListField(name = 'IStrain' ,
                #                                            position = 'int_pnts',
                #                                            var = 'eps_app', idx = 0,
                #                                            record_on = 'update'),
            ])

        # Add the time-loop control
        tloop = TLoop(tstepper=ts,
                      KMAX=50,
                      tolerance=self.tolerance,
                      RESETMAX=0,
                      tline=TLine(min=0.0, step=self.tstep, max=self.tmax),
                      ord=self.ord)

        return tloop

    def peval(self):
        '''
        Evaluate the model and return the array of results specified
        in the method get_sim_outputs.
        '''
        U = self.tloop.eval()

        self.f_w_diagram_center.refresh()
        F_max = max(self.f_w_diagram_center.trace.ydata)

        u_center_top_z = U[self.center_top_dofs][0, 0, 2]
        return array([u_center_top_z, F_max], dtype='float_')

    def get_sim_outputs(self):
        '''
        Specifies the results and their order returned by the model
        evaluation.
        '''
        return [
            SimOut(name='u_center_top_z', unit='m'),
            SimOut(name='F_max', unit='kN')
        ]
Esempio n. 30
0
class SCM(HasTraits):
    '''Stochastic Cracking Model - compares matrix strength and stress,
    inserts new CS instances at positions, where the matrix strength
    is lower than the stress; evaluates stress-strain diagram
    by integrating the strain profile along the composite'''

    length = Float(desc='composite specimen length')
    nx = Int(desc='# of discretization points for the whole specimen')
    CB_model = Instance(CompositeCrackBridge)
    load_sigma_c_arr = Array
    n_w_CB = Int(100, desc='# of discretization points for w')
    n_BC_CB = Int(15,
                  desc='# of discretization points for boundary conditions')

    representative_cb = Instance(RepresentativeCB)

    def _representative_cb_default(self):
        return RepresentativeCB(CB_model=self.CB_model,
                                load_sigma_c_arr=self.load_sigma_c_arr,
                                length=self.length,
                                n_w=self.n_w_CB,
                                n_BC=self.n_BC_CB)

    # list of composite stress at which cracks occur
    cracking_stress_lst = List
    # list of cracks positions
    crack_positions_lst = List

    x_arr = Property(Array, depends_on='length, nx')

    @cached_property
    def _get_x_arr(self):
        # discretizes the specimen length
        return np.linspace(0., self.length, self.nx)

    random_field = Instance(RandomField)

    matrix_strength = Property(depends_on='random_field.+modified')

    @cached_property
    def _get_matrix_strength(self):
        # evaluates a random field
        # realization and creates a spline reprezentation
        rf = self.random_field.random_field
        rf_spline = MFnLineArray(xdata=self.random_field.xgrid, ydata=rf)
        return rf_spline.get_values(self.x_arr)

    def get_cbs_lst(self, positions, cracking_stresses):
        # sorts the CBs by position and adjusts the boundary conditions
        # sort the CBs
        positions = np.array(positions)
        cracking_stresses = np.array(cracking_stresses)
        argsort = np.argsort(positions)
        sorted_positions = positions[argsort]
        sorted_cracking_stresses = cracking_stresses[argsort]

        cb_lst = []
        for i, position_i in enumerate(list(sorted_positions)):
            cb_i = CB(position=position_i,
                      representative_cb=self.representative_cb,
                      crack_load_sigma_c=sorted_cracking_stresses[i])
            # specify the boundaries
            if i == 0:
                # the leftmost crack
                cb_i.Ll = cb_i.position
            else:
                # there is a crack at the left hand side
                cb_i.Ll = (cb_i.position - cb_lst[-1].position) / 2.
                cb_lst[-1].Lr = cb_i.Ll
            if i == len(positions) - 1:
                # the rightmost crack
                cb_i.Lr = self.length - cb_i.position
            cb_lst.append(cb_i)

        for cb_i in cb_lst:
            # specify the x range for cracks
            mask_right = self.x_arr >= (cb_i.position - cb_i.Ll)
            mask_left = self.x_arr <= (cb_i.position + cb_i.Lr)
            cb_i.x = self.x_arr[mask_left * mask_right] - cb_i.position
        return cb_lst

    def get_current_cracking_state(self, load):
        '''Creates the list of CB objects that have been formed up to the current load
        '''
        idx_load_level = np.sum(np.array(self.cracking_stress_lst) <= load)
        cb_lst = self.get_cbs_lst(self.crack_positions_lst[:idx_load_level],
                                  self.cracking_stress_lst[:idx_load_level])
        return cb_lst

    def get_current_strnegth(self, load):
        if len(self.crack_positions_lst) is not 0:
            cb_lst = self.get_current_cracking_state(load)
            strengths = np.array([cb_i.max_sigma_c for cb_i in cb_lst])
            return np.min(strengths)
        else:
            return np.inf

    def sigma_m(self, load):
        Em = self.CB_model.E_m
        Ec = self.CB_model.E_c
        sigma_m = load * Em / Ec * np.ones(len(self.x_arr))
        if len(self.crack_positions_lst) != 0:
            cb_lst = self.get_current_cracking_state(load)
            for cb_i in cb_lst:
                crack_position_idx = np.argwhere(self.x_arr == cb_i.position)
                idx_l = crack_position_idx - len(np.nonzero(cb_i.x < 0.)[0])
                idx_r = crack_position_idx + len(
                    np.nonzero(cb_i.x > 0.)[0]) + 1
                sigma_m[idx_l:idx_r] = cb_i.get_epsm_x(float(load)) * Em
        return sigma_m

    def sigma_m_given_crack_lst(self, load):
        Em = self.CB_model.E_m
        Ec = self.CB_model.E_c
        sigma_m = load * Em / Ec * np.ones(len(self.x_arr))
        if len(self.crack_positions_lst) != 0:
            cb_lst = self.get_cbs_lst(self.crack_positions_lst,
                                      self.cracking_stress_lst)
            for cb_i in cb_lst:
                crack_position_idx = np.argwhere(self.x_arr == cb_i.position)
                idx_l = crack_position_idx - len(np.nonzero(cb_i.x < 0.)[0])
                idx_r = crack_position_idx + len(
                    np.nonzero(cb_i.x > 0.)[0]) + 1
                sigma_m[idx_l:idx_r] = cb_i.get_epsm_x(float(load)) * Em
        return sigma_m

    def residuum(self, q):
        '''Callback method for the identification of the
        next emerging crack calculated as the difference between
        the current matrix stress and strength. See the scipy newton call below.
        '''
        residuum = np.min(self.matrix_strength -
                          self.sigma_m_given_crack_lst(q))
        return residuum

    def evaluate(self):
        # seek for the minimum strength redundancy to find the position
        # of the next crack
        last_pos = pi
        sigc_min = 0.0
        while True:
            try:
                s = t.clock()
                sigc_min = newton(self.residuum, sigc_min)
                try:
                    sigc_min = brentq(self.residuum, 0.0, sigc_min - 1e-10)
                    print 'another root found!!!'
                except:
                    pass
                print 'evaluation of the matrix crack #' + str(
                    len(self.cracking_stress_lst) + 1), t.clock() - s, 's'
            except:
                print 'composite saturated'
                break
            print 'current strength = ', self.get_current_strnegth(sigc_min)
            crack_position = self.x_arr[np.argmin(self.matrix_strength -
                                                  self.sigma_m(sigc_min))]
            self.crack_positions_lst.append(crack_position)
            self.cracking_stress_lst.append(sigc_min - 1e-10)
            plt.plot(self.x_arr,
                     self.sigma_m(sigc_min) / self.CB_model.E_m,
                     color='blue',
                     lw=2)
            plt.plot(self.x_arr,
                     self.matrix_strength / self.CB_model.E_m,
                     color='black',
                     lw=2)
            plt.show()
            if float(crack_position) == last_pos:
                print last_pos
                raise ValueError('''got stuck in loop,
                try to adapt x, w, BC ranges''')
            last_pos = float(crack_position)