Exemple #1
0
class MATS2DMicroplaneDamage(MATSXDMicroplaneDamage, MATS2DEval):

    implements(IMATSEval)

    # number of spatial dimensions
    #
    n_dim = Constant(2)

    # number of components of engineering tensor representation
    #
    n_eng = Constant(3)

    # planar constraint
    stress_state = Enum("plane_strain", "plane_stress")

    # Specify the class to use for directional dependence
    mfn_class = Class(MFnPolar)

    # get the normal vectors of the microplanes
    _MPN = Property(depends_on='n_mp')

    @cached_property
    def _get__MPN(self):
        return array([[cos(alpha), sin(alpha)] for alpha in self.alpha_list])

    # get the weights of the microplanes
    _MPW = Property(depends_on='n_mp')

    @cached_property
    def _get__MPW(self):
        return ones(self.n_mp) / self.n_mp * 2

    elasticity_tensors = Property(depends_on='E, nu, stress_state')

    @cached_property
    def _get_elasticity_tensors(self):
        '''
        Intialize the fourth order elasticity tensor
        for 3D or 2D plane strain or 2D plane stress
        '''
        # ----------------------------------------------------------------------------
        # Lame constants calculated from E and nu
        # ----------------------------------------------------------------------------
        E = self.E
        nu = self.nu

        # first Lame paramter
        la = E * nu / ((1 + nu) * (1 - 2 * nu))
        # second Lame parameter (shear modulus)
        mu = E / (2 + 2 * nu)

        # -----------------------------------------------------------------------------------------------------
        # Get the fourth order elasticity and compliance tensors for the 3D-case
        # -----------------------------------------------------------------------------------------------------

        # The following lines correspond to the tensorial expression:
        # (using numpy functionality in order to avoid the loop):
        #
        # D4_e_3D = zeros((3,3,3,3),dtype=float)
        # C4_e_3D = zeros((3,3,3,3),dtype=float)
        # delta = identity(3)
        # for i in range(0,3):
        #     for j in range(0,3):
        #         for k in range(0,3):
        #             for l in range(0,3):
        #                 # elasticity tensor (cf. Jir/Baz Inelastic analysis of structures Eq.D25):
        #                 D4_e_3D[i,j,k,l] = la * delta[i,j] * delta[k,l] + \
        #                                    mu * ( delta[i,k] * delta[j,l] + delta[i,l] * delta[j,k] )
        #                 # elastic compliance tensor (cf. Simo, Computational Inelasticity, Eq.(2.7.16) AND (2.1.16)):
        #                 C4_e_3D[i,j,k,l] = (1+nu)/(2*E) * \
        #                                    ( delta[i,k] * delta[j,l] + delta[i,l]* delta[j,k] ) - \
        #                                    nu / E * delta[i,j] * delta[k,l]
        #
        # NOTE: swapaxes returns a reference not a copy!
        # (the index notation always refers to the initial indexing (i=0,j=1,k=2,l=3))
        delta = identity(3)
        delta_ijkl = outer(delta, delta).reshape(3, 3, 3, 3)
        delta_ikjl = delta_ijkl.swapaxes(1, 2)
        delta_iljk = delta_ikjl.swapaxes(2, 3)
        D4_e_3D = la * delta_ijkl + mu * (delta_ikjl + delta_iljk)
        C4_e_3D = -nu / E * delta_ijkl + \
            (1 + nu) / (2 * E) * (delta_ikjl + delta_iljk)

        # -----------------------------------------------------------------------------------------------------
        # Get the fourth order elasticity and compliance tensors for the 2D-case
        # -----------------------------------------------------------------------------------------------------
        # 1. step: Get the (6x6)-elasticity and compliance matrices
        #          for the 3D-case:
        D2_e_3D = map3d_tns4_to_tns2(D4_e_3D)
        C2_e_3D = map3d_tns4_to_tns2(C4_e_3D)

        # 2. step: Get the (3x3)-elasticity and compliance matrices
        #          for the 2D-cases plane stress and plane strain:
        D2_e_2D_plane_stress = get_D_plane_stress(D2_e_3D)
        D2_e_2D_plane_strain = get_D_plane_strain(D2_e_3D)
        C2_e_2D_plane_stress = get_C_plane_stress(C2_e_3D)
        C2_e_2D_plane_strain = get_C_plane_strain(C2_e_3D)

        if self.stress_state == 'plane_stress':
            D2_e = D2_e_2D_plane_stress

        if self.stress_state == 'plane_strain':
            D2_e = D2_e_2D_plane_strain

        # 3. step: Get the fourth order elasticity and compliance tensors
        # for the 2D-cases plane stress and plane strain (D4.shape = (2,2,2,2))
        D4_e_2D_plane_stress = map2d_tns2_to_tns4(D2_e_2D_plane_stress)
        D4_e_2D_plane_strain = map2d_tns2_to_tns4(D2_e_2D_plane_strain)
        C4_e_2D_plane_stress = map2d_tns2_to_tns4(C2_e_2D_plane_stress)
        C4_e_2D_plane_strain = map2d_tns2_to_tns4(C2_e_2D_plane_strain)

        # -----------------------------------------------------------------------------------------------------
        # assign the fourth order elasticity and compliance tensors as return values
        # -----------------------------------------------------------------------------------------------------
        if self.stress_state == 'plane_stress':
            # print 'stress state:   plane-stress'
            D4_e = D4_e_2D_plane_stress
            C4_e = C4_e_2D_plane_stress

        if self.stress_state == 'plane_strain':
            # print 'stress state:   plane-strain'
            D4_e = D4_e_2D_plane_strain
            C4_e = C4_e_2D_plane_strain

        return D4_e, C4_e, D2_e

    def _get_explorer_config(self):
        '''Get the specific configuration of this material model in the explorer
        '''
        c = super(MATS2DMicroplaneDamage, self)._get_explorer_config()

        from ibvpy.mats.mats2D.mats2D_rtrace_cylinder import MATS2DRTraceCylinder

        # overload the default configuration
        c['rtrace_list'] += [
            MATS2DRTraceCylinder(name='Laterne',
                                 var_axis='time',
                                 idx_axis=0,
                                 var_surface='microplane_damage',
                                 record_on='update'),
        ]

        return c

    #-------------------------------------------------------------------------
    # Dock-based view with its own id
    #-------------------------------------------------------------------------
    traits_view = View(Include('polar_fn_group'),
                       dock='tab',
                       id='ibvpy.mats.mats3D.mats_2D_cmdm.MATS2D_cmdm',
                       kind='modal',
                       resizable=True,
                       scrollable=True,
                       width=0.6,
                       height=0.8,
                       buttons=['OK', 'Cancel'])
Exemple #2
0
class FETSLSEval(FETSEval):

    x_slice = slice(0, 0)
    parent_fets = Instance(FETSEval)

    nip_disc = Int(0)  #number of integration points on the discontinuity

    def setup(self, sctx, n_ip):
        '''
        overloading the default method
        mats state array has to account for different number of ip in elements
        Perform the setup in the all integration points.
        TODO: original setup can be used after adaptation the ip_coords param
        '''
        #        print 'n_ip ', n_ip
        #        print 'self.m_arr_size ',self.m_arr_size
        #        print 'shape ',sctx.elem_state_array.shape
        for i in range(n_ip):
            sctx.mats_state_array = sctx.elem_state_array[(
                i * self.m_arr_size):((i + 1) * self.m_arr_size)]
            self.mats_eval.setup(sctx)

    n_nodes = Property  #TODO: define dependencies

    @cached_property
    def _get_n_nodes(self):
        return self.parent_fets.n_e_dofs / self.parent_fets.n_nodal_dofs

    #dots_class = DOTSUnstructuredEval
    dots_class = Class(DOTSEval)

    int_order = Int(1)

    mats_eval = Delegate('parent_fets')
    mats_eval_pos = Trait(None, Instance(IMATSEval))
    mats_eval_neg = Trait(None, Instance(IMATSEval))
    mats_eval_disc = Trait(None, Instance(IMATSEval))
    dim_slice = Delegate('parent_fets')

    dof_r = Delegate('parent_fets')
    geo_r = Delegate('parent_fets')
    n_nodal_dofs = Delegate('parent_fets')
    n_e_dofs = Delegate('parent_fets')

    get_dNr_mtx = Delegate('parent_fets')
    get_dNr_geo_mtx = Delegate('parent_fets')

    get_N_geo_mtx = Delegate('parent_fets')

    def get_B_mtx(self, r_pnt, X_mtx, node_ls_values, r_ls_value):
        B_mtx = self.parent_fets.get_B_mtx(r_pnt, X_mtx)
        return B_mtx

    def get_u(self, sctx, u):
        N_mtx = self.parent_fets.get_N_mtx(sctx.loc)
        return dot(N_mtx, u)

    def get_eps_eng(self, sctx, u):
        B_mtx = self.parent_fets.get_B_mtx(sctx.loc, sctx.X)
        return dot(B_mtx, u)

    dof_r = Delegate('parent_fets')
    geo_r = Delegate('parent_fets')

    node_ls_values = Array(float)

    tri_subdivision = Int(0)

    def get_triangulation(self, point_set):
        dim = point_set[0].shape[1]
        n_add = 3 - dim
        if dim == 1:  #sideway for 1D
            structure = [
                array([
                    min(point_set[0]),
                    max(point_set[0]),
                    min(point_set[1]),
                    max(point_set[1])
                ],
                      dtype=float),
                array([[0, 1], [2, 3]], dtype=int)
            ]
            return structure
        points_list = []
        triangles_list = []
        point_offset = 0
        for pts in point_set:
            if self.tri_subdivision == 1:
                new_pt = average(pts, 0)
                pts = vstack((pts, new_pt))
            if n_add > 0:
                points = hstack(
                    [pts, zeros([pts.shape[0], n_add], dtype='float_')])
            # Create a polydata with the points we just created.
            profile = tvtk.PolyData(points=points)

            # Perform a 2D Delaunay triangulation on them.
            delny = tvtk.Delaunay2D(input=profile, offset=1.e1)
            tri = delny.output
            tri.update()  #initiate triangulation
            triangles = array(tri.polys.data, dtype=int_)
            pt = tri.points.data
            tri = (triangles.reshape((triangles.shape[0] / 4), 4))[:, 1:]
            points_list += list(pt)
            triangles_list += list(tri + point_offset)
            point_offset += len(unique(tri))  #Triangulation
        points = array(points_list)
        triangles = array(triangles_list)
        return [points, triangles]

    vtk_point_ip_map = Property(Array(Int))

    def _get_vtk_point_ip_map(self):
        '''
        mapping of the visualization point to the integration points
        according to mutual proximity in the local coordinates
        '''
        vtk_pt_arr = zeros((1, 3), dtype='float_')
        ip_map = zeros(self.vtk_r.shape[0], dtype='int_')
        for i, vtk_pt in enumerate(self.vtk_r):
            vtk_pt_arr[0, self.dim_slice] = vtk_pt
            # get the nearest ip_coord
            ip_map[i] = argmin(cdist(vtk_pt_arr, self.ip_coords))
        return array(ip_map)

    def get_ip_coords(self, int_triangles, int_order):
        '''Get the array of integration points'''
        gps = []
        points, triangles = int_triangles
        if triangles.shape[1] == 1:  #0D - points
            if int_order == 1:
                gps.append(points[0])
            else:
                raise TraitError, 'does not make sense'
        elif triangles.shape[1] == 2:  #1D - lines
            if int_order == 1:
                for id in triangles:
                    gp = average(points[ix_(id)], 0)
                    gps.append(gp)
            elif int_order == 2:
                weigths = array([[0.21132486540518713, 0.78867513459481287],
                                 [0.78867513459481287, 0.21132486540518713]])
                for id in triangles:
                    gps += average( points[ix_( id )], 0, weigths[0] ), \
                            average( points[ix_( id )], 0, weigths[1] )
            else:
                raise NotImplementedError
        elif triangles.shape[1] == 3:  #2D - triangles
            if int_order == 1:
                for id in triangles:
                    gp = average(points[ix_(id)], 0)
                    #print "gp ",gp
                    gps.append(gp)
            elif int_order == 2:
                raise NotImplementedError
            elif int_order == 3:
                weigths = array([[0.6, 0.2, 0.2], [0.2, 0.6, 0.2],
                                 [0.2, 0.2, 0.6]])
                for id in triangles:
                    gps += average( points[ix_( id )], 0 ), \
                        average( points[ix_( id )], 0, weigths[0] ), \
                        average( points[ix_( id )], 0, weigths[1] ), \
                        average( points[ix_( id )], 0, weigths[2] )

            elif int_order == 4:
                raise NotImplementedError
            elif int_order == 5:
                weigths = array( [[0.0597158717, 0.4701420641, 0.4701420641], \
                                 [0.4701420641, 0.0597158717, 0.4701420641], \
                                 [0.4701420641, 0.4701420641, 0.0597158717], \
                                 [0.7974269853, 0.1012865073, 0.1012865073], \
                                 [0.1012865073, 0.7974269853, 0.1012865073], \
                                 [0.1012865073, 0.1012865073, 0.7974269853]] )
                for id in triangles:
                    weigts_sum = False  #for debug
                    gps += average( points[ix_( id )], 0 ), \
                         average( points[ix_( id )], 0, weigths[0], weigts_sum ), \
                         average( points[ix_( id )], 0, weigths[1], weigts_sum ), \
                         average( points[ix_( id )], 0, weigths[2], weigts_sum ), \
                         average( points[ix_( id )], 0, weigths[3], weigts_sum ), \
                         average( points[ix_( id )], 0, weigths[4], weigts_sum ), \
                         average( points[ix_( id )], 0, weigths[5], weigts_sum )
            else:
                raise NotImplementedError
        elif triangles.shape[1] == 4:  #3D - tetrahedrons
            raise NotImplementedError
        else:
            raise TraitError, 'unsupported geometric form with %s nodes ' % triangles.shape[
                1]
        return array(gps, dtype='float_')

    def get_ip_weights(self, int_triangles, int_order):
        '''Get the array of integration points'''
        gps = []
        points, triangles = int_triangles
        if triangles.shape[1] == 1:  #0D - points
            if int_order == 1:
                gps.append(1.)
            else:
                raise TraitError, 'does not make sense'
        elif triangles.shape[1] == 2:  #1D - lines
            if int_order == 1:
                for id in triangles:
                    r_pnt = points[ix_(id)]
                    J_det_ip = norm(r_pnt[1] - r_pnt[0]) * 0.5
                    gp = 2. * J_det_ip
                    gps.append(gp)
            elif int_order == 2:
                for id in triangles:
                    r_pnt = points[ix_(id)]
                    J_det_ip = norm(r_pnt[1] - r_pnt[0]) * 0.5
                    gps += J_det_ip, J_det_ip
            else:
                raise NotImplementedError
        elif triangles.shape[1] == 3:  #2D - triangles
            if int_order == 1:
                for id in triangles:
                    r_pnt = points[ix_(id)]
                    J_det_ip = self._get_J_det_ip(r_pnt)
                    gp = 1. * J_det_ip
                    #print "gp ",gp
                    gps.append(gp)
            elif int_order == 2:
                raise NotImplementedError
            elif int_order == 3:
                for id in triangles:
                    r_pnt = points[ix_(id)]
                    J_det_ip = self._get_J_det_ip(r_pnt)
                    gps += -0.5625 * J_det_ip, \
                            0.52083333333333337 * J_det_ip, \
                            0.52083333333333337 * J_det_ip, \
                            0.52083333333333337 * J_det_ip
            elif int_order == 4:
                raise NotImplementedError
            elif int_order == 5:
                for id in triangles:
                    r_pnt = points[ix_(id)]
                    J_det_ip = self._get_J_det_ip(r_pnt)
                    gps += 0.225 * J_det_ip, 0.1323941527 * J_det_ip, \
                            0.1323941527 * J_det_ip, 0.1323941527 * J_det_ip, \
                            0.1259391805 * J_det_ip, 0.1259391805 * J_det_ip, \
                            0.1259391805 * J_det_ip
            else:
                raise NotImplementedError
        elif triangles.shape[1] == 4:  #3D - tetrahedrons
            raise NotImplementedError
        else:
            raise TraitError, 'unsupported geometric form with %s nodes ' % triangles.shape[
                1]
        return array(gps, dtype='float_')

    def _get_J_det_ip(self, r_pnt):
        '''
        Helper function 
        just for 2D
        #todo:3D
        @param r_pnt:
        '''
        dNr_geo = self.dNr_geo_triangle
        return det(dot(dNr_geo,
                       r_pnt[:, :2])) / 2.  #factor 2 due to triangular form

    dNr_geo_triangle = Property(Array(float))

    @cached_property
    def _get_dNr_geo_triangle(self):
        dN_geo = array([[-1., 1., 0.], [-1., 0., 1.]], dtype='float_')
        return dN_geo

    def get_corr_pred(self,
                      sctx,
                      u,
                      du,
                      tn,
                      tn1,
                      u_avg=None,
                      B_mtx_grid=None,
                      J_det_grid=None,
                      ip_coords=None,
                      ip_weights=None):
        '''
        Corrector and predictor evaluation.

        @param u current element displacement vector
        '''
        if J_det_grid == None or B_mtx_grid == None:
            X_mtx = sctx.X

        show_comparison = True
        if ip_coords == None:
            ip_coords = self.ip_coords
            show_comparison = False
        if ip_weights == None:
            ip_weights = self.ip_weights

        ### Use for Jacobi Transformation

        n_e_dofs = self.n_e_dofs
        K = zeros((n_e_dofs, n_e_dofs))
        F = zeros(n_e_dofs)
        sctx.fets_eval = self
        ip = 0

        for r_pnt, wt in zip(ip_coords, ip_weights):
            #r_pnt = gp[0]
            sctx.r_pnt = r_pnt
            #caching cannot be switched off in the moment
            #            if J_det_grid == None:
            #                J_det = self._get_J_det( r_pnt, X_mtx )
            #            else:
            #                J_det = J_det_grid[ip, ... ]
            #            if B_mtx_grid == None:
            #                B_mtx = self.get_B_mtx( r_pnt, X_mtx )
            #            else:
            #                B_mtx = B_mtx_grid[ip, ... ]
            J_det = J_det_grid[ip, ...]
            B_mtx = B_mtx_grid[ip, ...]

            eps_mtx = dot(B_mtx, u)
            d_eps_mtx = dot(B_mtx, du)
            sctx.mats_state_array = sctx.elem_state_array[ip *
                                                          self.m_arr_size:(ip +
                                                                           1) *
                                                          self.m_arr_size]
            #print 'elem state ', sctx.elem_state_array
            #print 'mats state ', sctx.mats_state_array
            sctx.r_ls = sctx.ls_val[ip]
            sig_mtx, D_mtx = self.get_mtrl_corr_pred(sctx, eps_mtx, d_eps_mtx,
                                                     tn, tn1)
            k = dot(B_mtx.T, dot(D_mtx, B_mtx))
            k *= (wt * J_det)
            K += k
            f = dot(B_mtx.T, sig_mtx)
            f *= (wt * J_det)
            F += f
            ip += 1

        return F, K

    def get_J_det(self, r_pnt, X_mtx, ls_nodes,
                  ls_r):  #unified interface for caching
        return array(self._get_J_det(r_pnt, X_mtx), dtype='float_')

    def get_mtrl_corr_pred(self, sctx, eps_mtx, d_eps, tn, tn1):
        ls = sctx.r_ls
        if ls == 0. and self.mats_eval_disc:
            sig_mtx, D_mtx = self.mats_eval_disc.get_corr_pred(
                sctx,
                eps_mtx,
                d_eps,
                tn,
                tn1,
            )
        elif ls > 0. and self.mats_eval_pos:
            sig_mtx, D_mtx = self.mats_eval_pos.get_corr_pred(
                sctx,
                eps_mtx,
                d_eps,
                tn,
                tn1,
            )
        elif ls < 0. and self.mats_eval_neg:
            sig_mtx, D_mtx = self.mats_eval_neg.get_corr_pred(
                sctx,
                eps_mtx,
                d_eps,
                tn,
                tn1,
            )
        else:
            sig_mtx, D_mtx = self.mats_eval.get_corr_pred(
                sctx,
                eps_mtx,
                d_eps,
                tn,
                tn1,
            )
        return sig_mtx, D_mtx
class PolarDiscr(HasTraits):
    '''
    Manager of the microplane arrays.

    This class is responsible for the generation and initialization
    and state management of an array of microplanes. Additionally, it
    can perform the setup of damage function parameters using the
    value of the microplane integrator object.
    '''

    mfn_class = Class(None)
    #-------------------------------------------------------------------------
    # Common parameters for for isotropic and anisotropic damage function specifications
    #-------------------------------------------------------------------------
    n_mp = Range(0, 50, 6, label='Number of microplanes', auto_set=False)

    E = Float(34e+3,
              label="E",
              desc="Young's Modulus",
              auto_set=False,
              enter_set=True)
    nu = Float(0.2,
               label='nu',
               desc="Poison's ratio",
               auto_set=False,
               enter_set=True)

    c_T = Float(
        0.0,
        label='c_T',
        desc='fraction of tangential stress accounted on each microplane',
        auto_set=False,
        enter_set=True)

    #-------------------------------------------------------------------------
    # list of angles
    #-------------------------------------------------------------------------
    alpha_list = Property(Array, depends_on='n_mp')

    @cached_property
    def _get_alpha_list(self):
        return array(
            [Pi / self.n_mp * (i - 0.5) for i in range(1, self.n_mp + 1)])

    #-------------------------------------------------------------------------
    # Damage function specification
    #-------------------------------------------------------------------------

    phi_fn = EitherType(klasses=[
        PhiFnGeneral, PhiFnGeneralExtended, PhiFnGeneralExtendedExp,
        PhiFnStrainSoftening, PhiFnStrainHardening, PhiFnStrainHardeningLinear,
        PhiFnStrainHardeningBezier
    ])

    def _phi_fn_default(self):
        print 'setting phi_fn default'
        return PhiFnStrainSoftening(polar_discr=self)

    def _phi_fn_changed(self):
        print 'setting phi_fn changed'
        self.phi_fn.polar_discr = self

    varied_params = List(Str, [])

    #-------------------------------------------------------------------------
    # Management of spatially varying parameters depending on the value of mats_eval
    #-------------------------------------------------------------------------
    varpars = Dict

    def _varpars_default(self):
        return self._get_varpars()

    @on_trait_change('phi_fn,varied_params')
    def _update_varpars(self):
        self.varpars = self._get_varpars()

    def _get_varpars(self):
        '''
        reset the varpar list according to the current phi_fn object.
        '''
        params = self.phi_fn.identify_parameters()
        varset = {}
        for key in params:
            par_val = getattr(self.phi_fn, key)
            varset[key] = VariedParam(phi_fn=self.phi_fn,
                                      mats_eval=self,
                                      varname=key)
            if key in self.varied_params:
                varset[key].switched_on = True
        return varset

    varpar_list = Property(List(VariedParam), depends_on='varpars')

    @cached_property
    def _get_varpar_list(self):
        return [self.varpars[key] for key in self.phi_fn.identify_parameters()]

    # variable selectable in the table of varied params (just for viewing)
    current_varpar = Instance(VariedParam)

    def _current_varpar_default(self):
        if len(self.varpar_list) > 0:
            return self.varpar_list[0]
        return None

    @on_trait_change('phi_fn')
    def set_current_varpar(self):
        if len(self.varpar_list) > 0:
            self.current_varpar = self.varpar_list[0]

    #-------------------------------------------------------------------------
    # Get the damage state for all microplanes
    #-------------------------------------------------------------------------
    def get_phi_arr(self, sctx, e_max_arr):
        '''
        Return the damage coefficients
        '''
        # gather the coefficients for parameters depending on the orientation
        carr_list = [
            self.varpars[key].polar_fn_vectorized(self.alpha_list)
            for key in self.phi_fn.identify_parameters()
        ]
        # vectorize the damage function evaluation
        n_arr = 1 + len(carr_list)
        phi_fn_vectorized = frompyfunc(self.phi_fn.get_value, n_arr, 1)
        # damage parameter for each microplane
        return phi_fn_vectorized(e_max_arr, *carr_list)

    def get_polar_fn_fracture_energy_arr(self, sctx, e_max_arr):
        '''
        Return the fracture energy contributions
        '''
        carr_list = [
            self.varpars[key].polar_fn_vectorized(self.alpha_list)
            for key in self.phi_fn.identify_parameters()
        ]
        # vectorize the damage function evaluation
        n_arr = 1 + len(carr_list)
        integ_phi_fn_vectorized = frompyfunc(self.phi_fn.get_integ, n_arr, 1)
        return self.E * integ_phi_fn_vectorized(e_max_arr, *carr_list)

    polar_fn_group = Group(
        Group(Item('n_mp@', width=200),
              Item('E'),
              Item('nu'),
              Item('c_T'),
              Spring(),
              label='Elasticity parameters'),
        Group(Item('phi_fn@', show_label=False), label='Damage parameters'),
        Group(VSplit(
            Item('varpar_list',
                 label='List of material variables',
                 show_label=False,
                 editor=varpar_editor),
            Item('current_varpar',
                 label='Selected variable',
                 show_label=False,
                 style='custom',
                 resizable=True),
            dock='tab',
        ),
              label='Angle-dependent variations'),
        Include('config_param_vgroup'),
        layout='tabbed',
        springy=True,
        dock='tab',
        id='ibvpy.mats.matsXD_cmdm.MATSXDPolarDiscr',
    )

    traits_view = View(Include('polar_fn_group'),
                       resizable=True,
                       scrollable=True,
                       width=0.6,
                       height=0.9)
Exemple #4
0
class FETSEval(TStepperEval):

    implements(IFETSEval)

    dots_class = Class(DOTSEval)

    dof_r = Array(
        'float_',
        desc='Local coordinates of nodes included in the field ansatz')

    geo_r = Array(
        'float_',
        desc='Local coordinates of nodes included in the geometry ansatz')

    n_nodal_dofs = Int(desc='Number of nodal degrees of freedom')

    id_number = Int

    mats_eval = Instance(IMATSEval, desc='Material model')

    #-------------------------------------------------------------------------
    # Derived info about the finite element formulation
    #-------------------------------------------------------------------------
    n_dof_r = Int

    def _n_dof_r_default(self):
        return len(self.dof_r)

    n_geo_r = Int

    def _n_geo_r_default(self):
        return len(self.geo_r)

    #-------------------------------------------------------------------------
    # Field visualization
    #-------------------------------------------------------------------------

    vtk_r = Array(
        Float,
        desc='Local coordinates of nodes included in the field visualization')

    vtk_cell_types = Any(
        desc=
        'Tuple of vtk cell types in the same order as they are specified in the vtk_cells list'
    )

    vtk_cells = List(
        desc=
        'List of maps of nodes constituting the vtk cells covering the single element'
    )

    # Distinguish the type of base geometric entity to be used for
    # the visualization of the results.
    #
    # field_entity_type = Enum('vertex','line','triangle','quad','tetra','hexa')

    vtk_node_cell_data = Property(depends_on='vtk_cells, vtk_cell_types')

    @cached_property
    def _get_vtk_node_cell_data(self):

        n_cells = len(self.vtk_cells)

        # check if vtk_cell_types is a list, if not make one
        if isinstance(self.vtk_cell_types, str):
            cell_classes = [self.vtk_cell_types for i in range(n_cells)]
        else:
            cell_classes = self.vtk_cell_types

        cell_types = []
        for cell_str in cell_classes:
            cell_class = tvtk_helper.get_class(cell_str)
            cell_types.append(cell_class().cell_type)

        if isinstance(self.vtk_cells[0], int):
            # just a single cell defined
            return (array([
                0,
            ], dtype=int), array(self.vtk_cells.shape[0],
                                 dtype=int), array(self.vtk_cells,
                                                   dtype=int), cell_types)

        offset_list = []
        length_list = []
        cell_list = []
        vtk_offset = 0
        for cell in self.vtk_cells:
            cell_len = len(cell)
            cell_list += cell
            length_list.append(cell_len)
            offset_list.append(vtk_offset)
            vtk_offset += cell_len + 1

        return (array(offset_list, dtype=int), array(length_list, dtype=int),
                array(cell_list, dtype=int), array(cell_types, dtype=int))

    vtk_ip_cell_data = Property(depends_on='vtk_cells, vtk_cell_types')

    @cached_property
    def _get_vtk_ip_cell_data(self):

        n_ip_pnts = self.ip_coords.shape[0]

        cell_types = array([(tvtk_helper.get_class('PolyVertex')()).cell_type])

        return (array([
            0,
        ], dtype=int), array([n_ip_pnts],
                             dtype=int), arange(n_ip_pnts), cell_types)

    n_vtk_r = Property(Int, depends_on='vtk_r')

    @cached_property
    def _get_n_vtk_r(self):
        return self.vtk_r.shape[0]

    n_vtk_cells = Property(Int, depends_on='field_faces')

    @cached_property
    def _get_n_vtk_cells(self):
        return self.field_faces.shape[0]

    vtk_pnt_ip_map = Property(Array(Int))

    @cached_property
    def _get_vtk_pnt_ip_map(self):
        return self.get_vtk_pnt_ip_map_data(self.vtk_r)

    def adjust_spatial_context_for_point(self, sctx):
        '''
        Method gets called prior to the evaluation at the material point level.

        The method can be used for dimensionally reduced evaluators.
        This is FETS specific and should be moved there.
        However, the RTraceEval is not distinguished at the moment, therefore
        it is here - move!!!.   
        '''
        sctx.X_reg = sctx.X

    def get_vtk_pnt_ip_map_data(self, vtk_r):
        '''
        mapping of the visualization point to the integration points
        according to mutual proximity in the local coordinates
        '''
        vtk_pt_arr = zeros((1, 3), dtype='float_')
        ip_map = zeros(vtk_r.shape[0], dtype='int_')
        for i, vtk_pt in enumerate(vtk_r):
            vtk_pt_arr[0, self.dim_slice] = vtk_pt[self.dim_slice]
            # get the nearest ip_coord
            ip_map[i] = argmin(cdist(vtk_pt_arr, self.ip_coords))
        return array(ip_map)

    #-------------------------------------------------------------------------
    # NUMERICAL INTEGRATION
    #-------------------------------------------------------------------------
    #
    # The integration grid is constructed using broadcasting
    # provided by numpy. This provides a loopless implementation
    # with well defined ordering of gauss points and further the
    # slicing of gauss points using the numpy indexing slices.
    #
    # The old loop-based expansion is preserved below for reference.
    #
    gp_r_grid = Property(depends_on='ngp_r,ngp_s,ngp_t')

    @cached_property
    def _get_gp_r_grid(self):
        '''Return a tuple of three arrays for X, Y, Z coordinates of the
        gauss points within the element.
        '''
        # get the oriented arrays for each direction prepared for broadcasting
        #
        gp_coords = [
            oriented_3d_array(self._GP_COORDS[ngp], dim)
            for dim, ngp in enumerate(self.n_gp_list)
        ]

        # broadcast the values to construct all combinations of all gauss point
        # coordinates.
        #
        x, y, z = apply(broadcast_arrays, gp_coords)
        return x, y, z

    gp_w_grid = Property(depends_on='ngp_r,ngp_s,ngp_t')

    @cached_property
    def _get_gp_w_grid(self):
        '''In analogy to the above, get the grid of gauss weights in 3D.
        '''
        # get the oriented arrays for each direction prepared for broadcasting
        #
        gp_w = [
            oriented_3d_array(self._GP_WEIGHTS[ngp], dim)
            for dim, ngp in enumerate(self.n_gp_list)
        ]

        # broadcast the values to construct all combinations of all gauss point
        # coordinates.
        #
        w = reduce(lambda x, y: x * y, gp_w)
        return w

    ip_coords = Property(depends_on='ngp_r,ngp_s,ngp_t')

    def _get_ip_coords(self):
        '''Generate the flat array of ip_coords used for integration.
        '''
        x, y, z = self.gp_r_grid
        return c_[x.flatten(), y.flatten(), z.flatten()]

    ip_coords_grid = Property(depends_on='ngp_r,ngp_s,ngp_t')

    def _get_ip_coords_grid(self):
        '''Generate the grid of ip_coords
        '''
        return c_[self.gp_r_grid]

    ip_weights = Property(depends_on='ngp_r,ngp_s,ngp_t')

    def _get_ip_weights(self):
        '''Generate the flat array of ip_coords used for integration.
        '''
        w = self.gp_w_grid
        return w.flatten()

    ip_weights_grid = Property(depends_on='ngp_r,ngp_s,ngp_t')

    def _get_ip_weights_grid(self):
        '''Generate the flat array of ip_coords used for integration.
        '''
        w = self.gp_w_grid
        return w

    def get_ip_scheme(self, *params):
        return (self.ip_coords, self.ip_weights)

    n_gp = Property(depends_on='ngp_r,ngp_s,ngp_t')

    @cached_property
    def _get_n_gp(self):
        nr = max(1, self.ngp_r)
        ns = max(1, self.ngp_s)
        nt = max(1, self.ngp_t)
        return nr * ns * nt

    n_gp_list = Property(depends_on='ngp_r,ngp_s,ngp_r')

    @cached_property
    def _get_n_gp_list(self):
        nr = self.ngp_r
        ns = self.ngp_s
        nt = self.ngp_t
        return [nr, ns, nt]

    #-------------------------------------------------------------------------
    # SUBSPACE INTEGRATION
    #-------------------------------------------------------------------------
    #
    # Get the integration scheme for a subspace specified using the slicing indexes.
    #

    def get_sliced_ip_scheme(self, ip_idx_list):

        minmax = {0: min, -1: max}
        w = []
        r = []
        ix = []
        for dim_idx, ip_idx in enumerate(ip_idx_list):
            if isinstance(ip_idx, types.IntType):
                w.append(1.0)
                r.append(minmax[ip_idx](self.dof_r[:, dim_idx]))
            elif isinstance(ip_idx, types.SliceType):
                # if there is a slice - put the array in the corresponding dimension
                # - only the full slide - i.e. slice(None,None,None)
                #   is allowed
                n_gp = self.n_gp_list[dim_idx]
                w.append(oriented_3d_array(self._GP_WEIGHTS[n_gp], dim_idx))
                r.append(oriented_3d_array(self._GP_COORDS[n_gp], dim_idx))
                ix.append(dim_idx)
        r_grid = apply(broadcast_arrays, r)
        r_c = c_[tuple([r.flatten() for r in r_grid])]
        w_grid = reduce(lambda x, y: x * y, w)
        if isinstance(w_grid, types.FloatType):
            w_grid = array([w_grid], dtype='float_')
        else:
            w_grid = w_grid.flatten()
        return r_c, w_grid, ix

    #-------------------------------------------------------------------------
    # FIELD TRACING / VISUALIZATION
    #-------------------------------------------------------------------------
    # The user-specified fv_loc_coords list gets transform to an internal
    # array representation
    #
    vtk_r_arr = Property(depends_on='vtk_r')

    @cached_property
    def _get_vtk_r_arr(self):
        if len(self.vtk_r) == 0:
            raise ValueError, 'Cannot generate plot, no vtk_r specified in fets_eval'
        return array(self.vtk_r)

    def get_vtk_r_glb_arr(self, X_mtx, r_mtx=None):
        '''
        Get an array with global coordinates of the element decomposition.

        If the local_point_list is non-empty then use it instead of the one supplied 
        by the element specification. This is useful for augmented specification of RTraceEval 
        evaluations with a specific profile of a field variable to be traced.
        '''
        if self.dim_slice:
            X_mtx = X_mtx[:, self.dim_slice]

        if r_mtx == None:
            r_mtx = self.vtk_r_arr

        # TODO - efficiency in the extraction of the global coordinates. Is broadcasting
        # a possibility - we only need to augment the matrix with zero coordinates in the
        # in the unhandled dimensions.
        #
        X3D = array(
            [dot(self.get_N_geo_mtx(r_pnt), X_mtx)[0, :] for r_pnt in r_mtx])
        n_dims = r_mtx.shape[1]
        n_add = 3 - n_dims
        if n_add > 0:
            X3D = hstack([X3D, zeros([r_mtx.shape[0], n_add], dtype='float_')])
        return X3D

    def get_X_pnt(self, sctx):
        '''
        Get the global coordinates for the specified local coordinats r_pnt
        @param r_pnt: local coordinates
        '''
        r_pnt = sctx.r_pnt
        X_mtx = sctx.X

        return np.einsum('', self.Nr_i_geo, X_mtx)
        return dot(self.get_N_geo(r_pnt), X_mtx)

    def get_x_pnt(self, sctx):
        '''
        Get the global coordinates for the specified local coordinats r_pnt
        @param r_pnt: local coordinates
        '''
        r_pnt = sctx.r_pnt
        x_mtx = sctx.x

        # TODO - efficiency in the extraction of the global coordinates. Is broadcasting
        # a possibility - we only need to augment the matrix with zero coordinates in the
        # in the unhandled dimensions.
        #
        return dot(self.get_N_geo(r_pnt), x_mtx)

    def map_r2X(self, r_pnt, X_mtx):
        '''
        Map the local coords to global
        @param r_pnt: local coords
        @param X_mtx: matrix of the global coords of geo nodes
        '''
        # print "mapping ",dot( self.get_N_geo_mtx(r_pnt)[0], X_mtx )," ",
        # r_pnt
        return dot(self.get_N_geo(r_pnt), X_mtx)

    # Number of element DOFs
    #
    n_e_dofs = Int

    # Dimensionality
    dim_slice = None

    # Parameters for the time-loop
    #
    def new_cntl_var(self):
        return zeros(self.n_e_dofs, float_)

    def new_resp_var(self):
        return zeros(self.n_e_dofs, float_)

    def get_state_array_size(self):
        r_range = max(1, self.ngp_r)
        s_range = max(1, self.ngp_s)
        t_range = max(1, self.ngp_t)
        return self.m_arr_size * r_range * s_range * t_range

    m_arr_size = Property()

    @cached_property
    def _get_m_arr_size(self):
        return self.get_mp_state_array_size(None)

    def get_mp_state_array_size(self, sctx):
        '''Get the size of the state array for a single material point.
        '''
        return self.mats_eval.get_state_array_size()

    def setup(self, sctx):
        '''Perform the setup in the all integration points.
        '''
        for i, gp in enumerate(self.ip_coords):
            sctx.mats_state_array = sctx.elem_state_array[(
                i * self.m_arr_size):((i + 1) * self.m_arr_size)]
            self.mats_eval.setup(sctx)

    ngp_r = Int(0, label='Number of Gauss points in r-direction')
    ngp_s = Int(0, label='Number of Gauss points in s-direction')
    ngp_t = Int(0, label='Number of Gauss points in t-direction')

    #-------------------------------------------------------------------
    # Overloadable methods
    #-------------------------------------------------------------------
    def get_corr_pred(self,
                      sctx,
                      u,
                      du,
                      tn,
                      tn1,
                      eps_avg=None,
                      B_mtx_grid=None,
                      J_det_grid=None,
                      ip_coords=None,
                      ip_weights=None):
        '''
        Corrector and predictor evaluation.

        @param u current element displacement vector
        '''
        u_avg = eps_avg  # temporary
        if J_det_grid == None or B_mtx_grid == None:
            #            if self.dim_slice:
            #                X_mtx = sctx.X[:, self.dim_slice]
            #            else:
            X_mtx = sctx.X

        show_comparison = True
        if ip_coords == None:
            ip_coords = self.ip_coords
            show_comparison = False
        if ip_weights == None:
            ip_weights = self.ip_weights

        # Use for Jacobi Transformation

        n_e_dofs = self.n_e_dofs
        K = zeros((n_e_dofs, n_e_dofs))
        F = zeros(n_e_dofs)
        sctx.fets_eval = self

        ip = 0  # use enumerate

        # Element formulation-specific adjustment of the spatial context
        # for the material level (needed for combination of regularized
        # material models with elements of lower dimensions.
        #
        self.adjust_spatial_context_for_point(sctx)

        # Numerical quadrature loop
        #
        for r_pnt, wt in zip(ip_coords, ip_weights):

            sctx.r_pnt = r_pnt
            if J_det_grid == None:
                J_det = self._get_J_det(r_pnt, X_mtx)
            else:
                J_det = J_det_grid[ip, ...]
            if B_mtx_grid == None:
                B_mtx = self.get_B_mtx(r_pnt, X_mtx)
            else:
                B_mtx = B_mtx_grid[ip, ...]

            # Map displacements to strains
            #
            eps_mtx = dot(B_mtx, u)
            d_eps_mtx = dot(B_mtx, du)

            # Set the state array slice into the spatial context
            #
            sctx.mats_state_array = sctx.elem_state_array[ip *
                                                          self.m_arr_size:(ip +
                                                                           1) *
                                                          self.m_arr_size]

            # Evaluate the corrector and predictor for the current iteration
            #
            if u_avg != None:
                eps_avg = dot(B_mtx, u_avg)
                sig_mtx, D_mtx = self.get_mtrl_corr_pred(
                    sctx, eps_mtx, d_eps_mtx, tn, tn1, eps_avg)
            else:
                sig_mtx, D_mtx = self.get_mtrl_corr_pred(
                    sctx, eps_mtx, d_eps_mtx, tn, tn1)

            # Evaluate the element stiffness matrix
            #
            k = dot(B_mtx.T, dot(D_mtx, B_mtx))
            k *= (wt * J_det)
            K += k

            # Evaluate the internal force vector
            #
            f = dot(B_mtx.T, sig_mtx)
            f *= (wt * J_det)
            F += f

            ip += 1

        return F, K

    #-------------------------------------------------------------------
    # Standard evaluation methods
    #-------------------------------------------------------------------
    def get_J_mtx(self, r_pnt, X_mtx):
        dNr_geo_mtx = self.get_dNr_geo_mtx(r_pnt)
        return dot(dNr_geo_mtx, X_mtx)

    #-------------------------------------------------------------------
    # Required methods
    #-------------------------------------------------------------------

    def get_N_geo_mtx(self, r_pnt):
        raise NotImplementedError

    def get_dNr_geo_mtx(self, r_pnt):
        raise NotImplementedError

    def get_N_mtx(self, r_pnt):
        raise NotImplementedError

    def get_B_mtx(self, r_pnt, X_mtx):
        '''
        Get the matrix for kinematic mapping between displacements and strains.
        @param r local position within the element.
        @param X nodal coordinates of the element.

        @TODO[jakub] generalize
        '''
        raise NotImplementedError

    def get_mtrl_corr_pred(self,
                           sctx,
                           eps_eng,
                           d_eps_eng,
                           tn,
                           tn1,
                           eps_avg=None):
        if self.mats_eval.initial_strain:
            X_pnt = self.get_X_pnt(sctx)
            x_pnt = self.get_x_pnt(sctx)
            eps_ini_mtx = self.mats_eval.initial_strain(X_pnt, x_pnt)
            eps0_eng = self.mats_eval.map_eps_mtx_to_eng(eps_ini_mtx)
            eps_eng -= eps0_eng
        if eps_avg != None:
            sig_mtx, D_mtx = self.mats_eval.get_corr_pred(
                sctx, eps_eng, d_eps_eng, tn, tn1, eps_avg)
        else:
            sig_mtx, D_mtx = self.mats_eval.get_corr_pred(
                sctx,
                eps_eng,
                d_eps_eng,
                tn,
                tn1,
            )
        return sig_mtx, D_mtx

    #-------------------------------------------------------------------
    # Private methods
    #-------------------------------------------------------------------

    def get_J_det(self, r_pnt, X_mtx):
        return array(self._get_J_det(r_pnt, X_mtx), dtype='float_')

    def _get_J_det(self, r_pnt3d, X_mtx):
        if self.dim_slice:
            r_pnt = r_pnt3d[self.dim_slice]
        return det(self.get_J_mtx(r_pnt, X_mtx))

    # if no gauss point is defined in one direction (e.g. for ngp_t=0 for a 2D-problem)
    # then the default value for ngp_t=0 is used and a weighting coefficient of value 1.
    # In 'get_gp' the maximum of npg and 1 is used as range in the loop which leads to
    # a simple multiplication with 1 for that direction. The coordinate of the gauss point
    # in this direction is set to zero ('gp' : [0.]).

    # The index of the entry corresponds to the order of the polynomial
    #
    _GP_COORDS = [
        [0.],  # for polynomial order  = 0
        [0.],  # for polynomial order  = 1
        # por polynomial order = 2
        [-0.57735026918962584, 0.57735026918962584],
        # for polynomial order = 3
        [-0.7745966692414834, 0., 0.7745966692414834],
        # for polynomial order = 4
        [
            -0.861136311594053, -0.339981043584856, 0.339981043584856,
            0.861136311594053
        ]
    ]

    _GP_WEIGHTS = [[1.], [2.], [1., 1.],
                   [
                       0.55555555555555558, 0.88888888888888884,
                       0.55555555555555558
                   ],
                   [
                       0.347854845137454, 0.652145154862546, 0.652145154862546,
                       0.347854845137454
                   ]]

    #-------------------------------------------------------------------------
    # Epsilon as an engineering value
    #-------------------------------------------------------------------------
    def get_eps0_eng(self, sctx, u):
        '''Get epsilon without the initial strain
        '''
        if self.mats_eval.initial_strain:
            X_pnt = self.get_X_pnt(sctx)
            x_pnt = self.get_x_pnt(sctx)
            eps0_mtx = self.mats_eval.initial_strain(X_pnt, x_pnt)
            return self.mats_eval.map_eps_mtx_to_eng(eps0_mtx)
        else:
            return None

    def get_eps_eng(self, sctx, u):
        X_mtx = sctx.X
        r_pnt = sctx.loc
        B_mtx = self.get_B_mtx(r_pnt, X_mtx)
        eps_eng = dot(B_mtx, u)
        return eps_eng

    def get_eps1t_eng(self, sctx, u):
        '''Get epsilon without the initial strain
        '''
        eps_eng = self.get_eps_eng(sctx, u)
        eps0_eng = self.get_eps0_eng(sctx, u)
        if eps0_eng != None:
            eps_eng -= eps0_eng
        return eps_eng

    #-------------------------------------------------------------------------
    # Epsilon as a tensorial value - used for visualization in mayavi
    #-------------------------------------------------------------------------
    def get_eps0_mtx33(self, sctx, u):
        '''Get epsilon without the initial strain
        '''
        eps0_mtx33 = zeros((3, 3), dtype='float_')
        if self.mats_eval.initial_strain:
            X_pnt = self.get_X_pnt(sctx)
            x_pnt = self.get_x_pnt(sctx)
            eps0_mtx33[self.dim_slice,
                       self.dim_slice] = self.mats_eval.initial_strain(
                           X_pnt, x_pnt)
        return eps0_mtx33

    def get_eps_mtx33(self, sctx, u):
        eps_eng = self.get_eps_eng(sctx, u)
        eps_mtx33 = zeros((3, 3), dtype='float_')
        eps_mtx33[self.dim_slice,
                  self.dim_slice] = self.mats_eval.map_eps_eng_to_mtx(eps_eng)
        return eps_mtx33

    def get_eps1t_mtx33(self, sctx, u):
        '''Get epsilon without the initial strain
        '''
        eps_mtx33 = self.get_eps_mtx33(sctx, u)
        eps0_mtx33 = self.get_eps0_mtx33(sctx, u)
        return eps_mtx33 - eps0_mtx33

    #-------------------------------------------------------------------------
    # Displacement in a n arbitrary point within an element
    #-------------------------------------------------------------------------
    def map_eps(self, sctx, u):
        X_mtx = sctx.X
        r_pnt = sctx.loc
        B_mtx = self.get_B_mtx(r_pnt, X_mtx)
        eps = dot(B_mtx, u)
        return eps

    def get_u(self, sctx, u):
        N_mtx = self.get_N_mtx(sctx.loc)
        return dot(N_mtx, u)

    debug_on = Bool(False)

    def _debug_rte_dict(self):
        '''
        RTraceEval dictionary with field variables used to verify the element implementation
        '''
        if self.debug_on:
            return {
                'Ngeo_mtx':
                RTraceEvalElemFieldVar(
                    eval=lambda sctx, u: self.get_N_geo_mtx(sctx.loc),
                    ts=self),
                'N_mtx':
                RTraceEvalElemFieldVar(
                    eval=lambda sctx, u: self.get_N_mtx(sctx.loc)[0], ts=self),
                'B_mtx0':
                RTraceEvalElemFieldVar(
                    eval=lambda sctx, u: self.get_B_mtx(sctx.loc, sctx.X)[0],
                    ts=self),
                'B_mtx1':
                RTraceEvalElemFieldVar(
                    eval=lambda sctx, u: self.get_B_mtx(sctx.loc, sctx.X)[1],
                    ts=self),
                'B_mtx2':
                RTraceEvalElemFieldVar(
                    eval=lambda sctx, u: self.get_B_mtx(sctx.loc, sctx.X)[2],
                    ts=self),
                'J_det':
                RTraceEvalElemFieldVar(eval=lambda sctx, u: array(
                    [det(self.get_J_mtx(sctx.loc, sctx.X))]),
                                       ts=self)
            }
        else:
            return {}

    # List of mats that are to be chained
    #

    # Declare and fill-in the rte_dict - it is used by the clients to
    # assemble all the available time-steppers.
    #
    rte_dict = Trait(Dict)

    def _rte_dict_default(self):
        '''
        RTraceEval dictionary with standard field variables.
        '''
        rte_dict = self._debug_rte_dict()
        for key, v_eval in self.mats_eval.rte_dict.items():

            # add the eval into the loop.
            #
            rte_dict[key] = RTraceEvalElemFieldVar(
                name=key, u_mapping=self.get_eps1t_eng, eval=v_eval)

        rte_dict.update({
            'eps_app':
            RTraceEvalElemFieldVar(eval=self.get_eps_mtx33),
            'eps0_app':
            RTraceEvalElemFieldVar(eval=self.get_eps0_mtx33),
            'eps1t_app':
            RTraceEvalElemFieldVar(eval=self.get_eps1t_mtx33),
            'u':
            RTraceEvalElemFieldVar(eval=self.get_u)
        })

        return rte_dict

    traits_view = View(
        Group(Item('mats_eval'),
              Item('n_e_dofs'),
              Item('n_nodal_dofs'),
              label='Numerical parameters'),
        Group(
            #                              Item( 'dof_r' ),
            #                              Item( 'geo_r' ),
            Item('vtk_r'),
            Item('vtk_cells'),
            Item('vtk_cell_types'),
            label='Visualization parameters'),
        #                         Item('rte_dict'),
        resizable=True,
        scrollable=True,
        width=0.2,
        height=0.4)