Ejemplo n.º 1
0
    def _get_stiffness( self, editor, object ):
        tstepper = editor.object.tstepper


        if isinstance( object, TStepper ):
            U_k = tstepper.U_k
            d_U = tstepper.d_U
            K, R = tstepper.eval( 'predictor', U_k, d_U, 0, 0 )
            print 'constraints'
            K.print_constraints()
            K.apply_constraints( R )
        else:

            dots = object.dots
            U_k = tstepper.U_k
            d_U = tstepper.d_U
            sctx = tstepper.sctx

            F_int, K_mtx = dots.get_corr_pred( sctx, U_k, d_U, 0, 0 )

            # put the matrix into the system assembly
            #
            K = SysMtxAssembly()
            if isinstance( K_mtx, ndarray ):
                K.add_mtx( K_mtx )
            elif isinstance( K_mtx, SysMtxArray ):
                K.sys_mtx_arrays.append( K_mtx )
            elif isinstance( K_mtx, list ):
                K.sys_mtx_arrays = K_mtx
            elif isinstance( K_mtx, SysMtxAssembly ):
                K.sys_mtx_arrays = K_mtx.sys_mtx_arrays

            n_dofs = tstepper.sdomain.n_dofs
            K.add_mtx( zeros( ( 1, 1 ), dtype = 'float_' ), array( [n_dofs - 1], dtype = 'int_' ) )

        return K
Ejemplo n.º 2
0
    def _get_stiffness(self, editor, object):
        tstepper = editor.object.tstepper

        if isinstance(object, TStepper):
            U_k = tstepper.U_k
            d_U = tstepper.d_U
            K, R = tstepper.eval('predictor', U_k, d_U, 0, 0)
            print 'constraints'
            K.print_constraints()
            K.apply_constraints(R)
        else:

            dots = object.dots
            U_k = tstepper.U_k
            d_U = tstepper.d_U
            sctx = tstepper.sctx

            F_int, K_mtx = dots.get_corr_pred(sctx, U_k, d_U, 0, 0)

            # put the matrix into the system assembly
            #
            K = SysMtxAssembly()
            if isinstance(K_mtx, ndarray):
                K.add_mtx(K_mtx)
            elif isinstance(K_mtx, SysMtxArray):
                K.sys_mtx_arrays.append(K_mtx)
            elif isinstance(K_mtx, list):
                K.sys_mtx_arrays = K_mtx
            elif isinstance(K_mtx, SysMtxAssembly):
                K.sys_mtx_arrays = K_mtx.sys_mtx_arrays

            n_dofs = tstepper.sdomain.n_dofs
            K.add_mtx(
                zeros((1, 1), dtype='float_'), array([n_dofs - 1], dtype='int_'))

        return K
Ejemplo n.º 3
0
class TStepper( IBVResource ):
    """
    The TStepper is a spatially bounded TStepperEval.

    The binding is done by associating the time-stepper with a spatial
    object. In fact, any TStepper, not only the top-level one must
    be associated with spatial object. For the chained
    sub-time-steppers, this association is done using a parameter sctx
    (see the specification above). This parameters stands for spatial
    context. Note, the distinction between the spatial object and
    spatial context. While the spatial object represents a single
    spatial entity (one of domain, element, layer or material point)
    the spatial context represents a complex reference within the
    spatial object In particular, spatial context of a particular
    material point is represented as tuple containing tuple of
    references to [domain, element, layer, integration cell, material
    point].
    """

    # service specifiers - used to link the service to this object
    service_class = 'ibvpy.plugins.tstepper_service.TStepperService'
    service_attrib = 'tstepper'

    # Integration terms involved in the evaluation of the 
    # incremetal spatial integrals.
    # Must be either an instance of ts_eval or a tuple specifying a pair 
    # ( ts_eval, sdomain ) or a list of tuples with the pairs 
    # [ ( ts_eval, sdomain ), ( ts_eval, sdomain ), ... ]
    #

    # Sub-time-stepper or integrator.
    #
    tse = Instance( ITStepperEval )

    tse_integ = Property( depends_on = 'tse,_sdomain, _sdomain.changed_structure' )
    @cached_property
    def _get_tse_integ( self ):
        if self.tse:
            self.tse.tstepper = self
            return self.tse
        else:
            self.sdomain.dots.tstepper = self
            return self.sdomain.dots

    # Spatial domain to bind the time-stepper to.
    # For convenience automatically convert the plain list to FEDomainList
    #
    _sdomain = Instance( ISDomain )
    sdomain = Property( Instance( ISDomain ) )
    def _set_sdomain( self, value ):
        if isinstance( value, FEGrid ):
            # construct FERefinementGrid and FEDomain
            self._sdomain = FEDomain()
            fe_rgrid = FERefinementGrid( domain = self._sdomain,
                                         fets_eval = value.fets_eval )
            value.level = fe_rgrid
        elif isinstance( value, FERefinementGrid ):
            # construct FEDomain
            self._sdomain = FEDomain()
            value.domain = self._sdomain
        elif isinstance( value, list ):
            self._sdomain = FEDomain()
            for d in value:
                if isinstance( d, FEGrid ):
                    fe_rgrid = FERefinementGrid( domain = self._sdomain,
                                                 fets_eval = d.fets_eval )
                    d.level = fe_rgrid
                elif isinstance( d, FESubDomain ):
                    d.domain = self._sdomain
                else:
                    raise TypeError, 'The list can contain only FEGrid or FERefinementGrid'
        else:
            self._sdomain = value
    def _get_sdomain( self ):
        if self._sdomain == None:
            self._sdomain = SDomain()
        return self._sdomain

    subdomains = Property()
    def _get_subdomains( self ):
        if self.sdomain == None:
            return []
        return self.sdomain.subdomains

    xdomains = Property()
    def _get_xdomains( self ):
        if self.sdomain == None:
            return []
        return self.sdomain.xdomains

    def redraw( self ):
        self.sdomain.redraw()

    sctx = Instance( SContext )

    # Boundary condition manager
    #
    bcond_mngr = Instance( BCondMngr )
    def _bcond_mngr_default( self ):
        return BCondMngr()

    # Convenience constructor 
    #
    # This property provides the possibility to write
    # tstepper.bcond_list = [BCDof(var='u',dof=5,value=0, ... ]
    # The result gets propageted to the BCondMngr
    #
    bcond_list = Property( List )
    def _get_bcond_list( self ):
        return self.bcond_mngr.bcond_list
    def _set_bcond_list( self, bcond_list ):
        self.bcond_mngr.bcond_list = bcond_list

    # Response variable manager
    #
    rtrace_mngr = Instance( RTraceMngr )
    def _rtrace_mngr_default( self ):
        return RTraceMngr( tstepper = self )

    # Convenience constructor 
    #
    # This property provides the possibility to write
    # tstepper.bcond_list = [RVDof(var='u',dof=5,value=0, ... ]
    # The result gets propageted to the RTraceMngr
    #
    rtrace_list = Property( List )
    def _get_rtrace_list( self ):
        return self.rtrace_mngr.rtrace_list
    def _set_rtrace_list( self, rtrace_list ):
        self.rtrace_mngr.rtrace_list = rtrace_list

    # Possibility to add a callable for derived 
    # variables of the control variable. 
    u_processor = Callable

    # Backward reference to the time-loop in order to accommadate the
    # response-trace-evaluators from the top level. These include
    # bookkeeping data like memory usage or solving time per selected
    # type of operation.
    #
    tloop = WeakRef

    dir = Property
    def _get_dir( self ):
        return self.tloop.dir

    dof_resultants = Bool( True )

    rte_dict = Property( Dict, depends_on = 'tse' )
    @cached_property
    def _get_rte_dict( self ):
        '''
        Gather all the currently applicable evaluators from the sub-ts
        and from the time-loop.

        Note the control data (time-loop data) is available within the
        model to construct flexible views (tracers) on the model.
        '''
        _rte_dict = {}

        def _get_F_int( sctx, U_k, *args, **kw ):
            return self.F_int

        if self.dof_resultants:
            _rte_dict['F_int'] = _get_F_int # lambda sctx, U_k: self.F_int
            _rte_dict['F_ext'] = lambda sctx, U_k, *args, **kw: self.F_ext

        _rte_dict.update( self.tse_integ.rte_dict )
        if self.tloop:
            _rte_dict.update( self.tloop.rte_dict )
        return _rte_dict

    def new_cntl_var( self ):
        return self.tse_integ.new_cntl_var()

    def new_resp_var( self ):
        return self.tse_integ.new_resp_var()

    U_k = Property( depends_on = '_sdomain.changed_structure' )
    @cached_property
    def _get_U_k( self ):
        '''
         Setup the primary state variables on demand
        '''
        U_k = self.new_cntl_var()
        return U_k

    d_U = Property( depends_on = '_sdomain.changed_structure' )
    @cached_property
    def _get_d_U( self ):
        '''
         Current increment of the displacement variable 
        '''
        return self.new_cntl_var()

    F_ext = Property( depends_on = '_sdomain.changed_structure' )
    @cached_property
    def _get_F_ext( self ):
        '''
         Return the response variable to be used when assembling the
         boundary conditions. Should the bcond_mngr take care of this? 
         That's the source object, isn't it? BCondMngr is the bounded
         version of the conditions, it could supply the matrix
         autonomously.
        
        '''
        return self.new_resp_var()

    # missing - setup of the time-stepper itself. reacting to changes
    # in the sub time-steppers. bcond_list and rtrace_list must be reset once
    # a change has been performed either in a spatial domain or in
    # tse.
    #
    def setup( self ):

        # Put the spatial domain into the spatial context
        #
        self.sctx = sctx = self.sdomain.new_scontext()
        self.sctx.sdomain = self.sdomain

        # Let the boundary conditions setup themselves within the
        # spatial context
        #
        # TODO - the setup needs the link to the algorithm and to the
        # time-steppers as well.!
        #
        self.bcond_mngr.setup( sctx )

        # Let the response variables setup themselves within the
        # spatial context
        #
        self.rtrace_mngr.setup( self.sdomain )

        # Set up the system matrix
        #
        self.K = SysMtxAssembly()

        # Register the essential boundary conditions in the system matrix
        #
        self.bcond_mngr.apply_essential( self.K )

        self.tse_integ.apply_constraints( self.K )

        # Prepare the global update flag
        sctx.update_state_on = False

        if self.u_processor:
            if self.u_processor.sd == None:
                self.u_processor.sd = self.sdomain

        # add-on parameters to be passed to every inner loop
        # they are provided by u_processors 
        #
        self.kw = {}
        self.args = []


    def eval( self, step_flag, U_k, d_U, t_n, t_n1 ):
        '''Get the tangential operator (system matrix) and residuum
        associated with the current time step.
        
        @param step_flag: indicator of the predictor | corrector step
           it is needed for proper handling of constraint equations 
           (essential boundary conditions and explicit links between 
           the variables.
           
        @param U_k: current value of the control variable (including 
            the value of the last increment d_U
        
        @param d_U: increment of the control variable 
            U[k] = U[k-1] + d_U
            
        @param t_n: value of the time control parameters in the 
            last equilibrated step.
            
        @param t_n1: value of the target time in the current 
            time step.
        '''

        # Reset the system matrix (constraints are preserved)
        #
        self.K.reset_mtx()

        # Put the spatial domain into the spatial context
        #
        sctx = self.sctx

        if self.u_processor:
            self.args, self.kw = self.u_processor( U_k )

        # Let the time sub-stepper evaluate its contribution.
        #
        F_int, K_mtx = self.tse_integ.get_corr_pred( sctx, U_k, d_U, t_n, t_n1,
                                                     *self.args, **self.kw )

        # Promote the system matrix to the SysMtxAssembly
        # Supported representation of the system matrix is
        # float, ndarray, SysMtxArray and SysMtxAssembly
        #
        # @todo use coerce in order to hide this conversions.
        # or is adapter concept of traits a possibility?
        #
        if isinstance( K_mtx, ndarray ):
            self.K.add_mtx( K_mtx )
        elif isinstance( K_mtx, SysMtxArray ):
            self.K.sys_mtx_arrays.append( K_mtx )
        elif isinstance( K_mtx, list ):
            self.K.sys_mtx_arrays = K_mtx
        elif isinstance( K_mtx, SysMtxAssembly ):
            self.K.sys_mtx_arrays = K_mtx.sys_mtx_arrays

        # Switch off the global update flag
        #
        sctx.update_state_on = False

        # Apply the boundary conditions
        #
        if self.dof_resultants == True:

            # The code below is somewhat wasteful as it explicitly constructs the
            # array of external forces and then makes the subraction
            # F_ext - F_int to obtain the residual forces. As a result, there two unnecessary 
            # intermediate instances of the vector of the size [n_dofs].
            #
            # The two arrays are needed only for postprocessing, if there is a need
            # to get the reaction forces at particular DOF stored in F_int 
            # or when the imposed time-dependent loading in a DOF should be visualized 
            # for verification, the two vectors must be defined as 
            # attributes of the tstepper objects. For this reasons, the more demanding
            # implementation is used here. 
            #
            # Remember F_int
            #
            self.F_int = F_int

            # Prepare F_ext by zeroing it
            #
            self.F_ext[:] = 0.0

            # Assemble boundary conditions in K and self.F_ext 
            #
            self.bcond_mngr.apply( step_flag, sctx, self.K, self.F_ext, t_n, t_n1 )

            # Return the system matrix assembly K and the residuum
            #
            return self.K, self.F_ext - self.F_int

        else:

            # On the other hand, the time-loop only requires the residuum 
            # which can be obtained withoug an additional
            # memory consumption by issuing an in-place switch of the sign
            # 
            F_int *= -1 # in-place sign change of the internal forces
            # 
            # Then F_int can be used as the target for the boundary conditions
            #
            self.bcond_mngr.apply( step_flag, sctx, self.K, F_int, t_n, t_n1 )

            #
            # The subtraction F_ext - F_int has then been performed implicitly
            # and the residuum can be returned by issuing
            #
            return self.K, F_int

    def update_state( self, U ):
        '''
        spatial context represents a stack with the top object
         representing the current level.
        @param U: 
        '''
        #sctx = ( self.sdomain, )
        self.sctx.update_state_on = True
        #self.tse_integ.update_state( sctx, U )

    def register_mv_pipelines( self, e ):
        '''Register the visualization pipelines in mayavi engine
        '''
        self.tse_integ.register_mv_pipelines( e )
        scene = e.new_scene()
        scene.name = 'Spatial domain'
        self.sdomain.register_mv_pipelines( e )
        self.rtrace_mngr.register_mv_pipelines( e )

    traits_view = View( Group( Item( 'sdomain', style = 'custom', show_label = False ),
                               label = 'Discretization' ),
                        Group( Item( 'tse', style = 'simple', show_label = False ),
                               label = 'Integrator' ),
                        Group( Item( 'bcond_mngr', style = 'custom', show_label = False ),
                               label = 'Boundary conditions' ),
                        Group( Item( 'dof_resultants' ),
                               label = 'Options' ),
                        resizable = True,
                        height = 0.8,
                        width = 0.8,
                        buttons = [OKButton, CancelButton],
                        kind = 'subpanel',
                        )
Ejemplo n.º 4
0
class TStepper(IBVResource):
    """
    The TStepper is a spatially bounded TStepperEval.

    The binding is done by associating the time-stepper with a spatial
    object. In fact, any TStepper, not only the top-level one must
    be associated with spatial object. For the chained
    sub-time-steppers, this association is done using a parameter sctx
    (see the specification above). This parameters stands for spatial
    context. Note, the distinction between the spatial object and
    spatial context. While the spatial object represents a single
    spatial entity (one of domain, element, layer or material point)
    the spatial context represents a complex reference within the
    spatial object In particular, spatial context of a particular
    material point is represented as tuple containing tuple of
    references to [domain, element, layer, integration cell, material
    point].
    """

    # service specifiers - used to link the service to this object
    service_class = 'ibvpy.plugins.tstepper_service.TStepperService'
    service_attrib = 'tstepper'

    # Integration terms involved in the evaluation of the
    # incremetal spatial integrals.
    # Must be either an instance of ts_eval or a tuple specifying a pair
    # ( ts_eval, sdomain ) or a list of tuples with the pairs
    # [ ( ts_eval, sdomain ), ( ts_eval, sdomain ), ... ]
    #

    # Sub-time-stepper or integrator.
    #
    tse = Instance(ITStepperEval)

    tse_integ = Property(depends_on='tse,_sdomain, _sdomain.changed_structure')

    @cached_property
    def _get_tse_integ(self):
        if self.tse:
            self.tse.tstepper = self
            return self.tse
        else:
            self.sdomain.dots.tstepper = self
            return self.sdomain.dots

    # Spatial domain to bind the time-stepper to.
    # For convenience automatically convert the plain list to FEDomainList
    #
    _sdomain = Instance(ISDomain)
    sdomain = Property(Instance(ISDomain))

    def _set_sdomain(self, value):
        if isinstance(value, FEGrid):
            # construct FERefinementGrid and FEDomain
            self._sdomain = FEDomain()
            fe_rgrid = FERefinementGrid(domain=self._sdomain,
                                        fets_eval=value.fets_eval)
            value.level = fe_rgrid
        elif isinstance(value, FERefinementGrid):
            # construct FEDomain
            self._sdomain = FEDomain()
            value.domain = self._sdomain
        elif isinstance(value, list):
            self._sdomain = FEDomain()
            for d in value:
                if isinstance(d, FEGrid):
                    fe_rgrid = FERefinementGrid(domain=self._sdomain,
                                                fets_eval=d.fets_eval)
                    d.level = fe_rgrid
                elif isinstance(d, FESubDomain):
                    d.domain = self._sdomain
                else:
                    raise TypeError, 'The list can contain only FEGrid or FERefinementGrid'
        else:
            self._sdomain = value

    def _get_sdomain(self):
        if self._sdomain == None:
            self._sdomain = SDomain()
        return self._sdomain

    subdomains = Property()

    def _get_subdomains(self):
        if self.sdomain == None:
            return []
        return self.sdomain.subdomains

    xdomains = Property()

    def _get_xdomains(self):
        if self.sdomain == None:
            return []
        return self.sdomain.xdomains

    def redraw(self):
        self.sdomain.redraw()

    sctx = Instance(SContext)

    # Boundary condition manager
    #
    bcond_mngr = Instance(BCondMngr)

    def _bcond_mngr_default(self):
        return BCondMngr()

    # Convenience constructor
    #
    # This property provides the possibility to write
    # tstepper.bcond_list = [BCDof(var='u',dof=5,value=0, ... ]
    # The result gets propageted to the BCondMngr
    #
    bcond_list = Property(List)

    def _get_bcond_list(self):
        return self.bcond_mngr.bcond_list

    def _set_bcond_list(self, bcond_list):
        self.bcond_mngr.bcond_list = bcond_list

    # Response variable manager
    #
    rtrace_mngr = Instance(RTraceMngr)

    def _rtrace_mngr_default(self):
        return RTraceMngr(tstepper=self)

    # Convenience constructor
    #
    # This property provides the possibility to write
    # tstepper.bcond_list = [RVDof(var='u',dof=5,value=0, ... ]
    # The result gets propageted to the RTraceMngr
    #
    rtrace_list = Property(List)

    def _get_rtrace_list(self):
        return self.rtrace_mngr.rtrace_list

    def _set_rtrace_list(self, rtrace_list):
        self.rtrace_mngr.rtrace_list = rtrace_list

    # Possibility to add a callable for derived
    # variables of the control variable.
    u_processor = Callable

    # Backward reference to the time-loop in order to accommadate the
    # response-trace-evaluators from the top level. These include
    # bookkeeping data like memory usage or solving time per selected
    # type of operation.
    #
    tloop = WeakRef

    dir = Property

    def _get_dir(self):
        return self.tloop.dir

    dof_resultants = Bool(True)

    rte_dict = Property(Dict, depends_on='tse')

    @cached_property
    def _get_rte_dict(self):
        '''
        Gather all the currently applicable evaluators from the sub-ts
        and from the time-loop.

        Note the control data (time-loop data) is available within the
        model to construct flexible views (tracers) on the model.
        '''
        _rte_dict = {}

        def _get_F_int(sctx, U_k, *args, **kw):
            return self.F_int

        if self.dof_resultants:
            _rte_dict['F_int'] = _get_F_int  # lambda sctx, U_k: self.F_int
            _rte_dict['F_ext'] = lambda sctx, U_k, *args, **kw: self.F_ext

        _rte_dict.update(self.tse_integ.rte_dict)
        if self.tloop:
            _rte_dict.update(self.tloop.rte_dict)
        return _rte_dict

    def new_cntl_var(self):
        return self.tse_integ.new_cntl_var()

    def new_resp_var(self):
        return self.tse_integ.new_resp_var()

    U_k = Property(depends_on='_sdomain.changed_structure')

    @cached_property
    def _get_U_k(self):
        '''
         Setup the primary state variables on demand
        '''
        U_k = self.new_cntl_var()
        return U_k

    d_U = Property(depends_on='_sdomain.changed_structure')

    @cached_property
    def _get_d_U(self):
        '''
         Current increment of the displacement variable
        '''
        return self.new_cntl_var()

    F_ext = Property(depends_on='_sdomain.changed_structure')

    @cached_property
    def _get_F_ext(self):
        '''
         Return the response variable to be used when assembling the
         boundary conditions. Should the bcond_mngr take care of this?
         That's the source object, isn't it? BCondMngr is the bounded
         version of the conditions, it could supply the matrix
         autonomously.

        '''
        return self.new_resp_var()

    # missing - setup of the time-stepper itself. reacting to changes
    # in the sub time-steppers. bcond_list and rtrace_list must be reset once
    # a change has been performed either in a spatial domain or in
    # tse.
    #
    def setup(self):

        # Put the spatial domain into the spatial context
        #
        self.sctx = sctx = self.sdomain.new_scontext()
        self.sctx.sdomain = self.sdomain

        # Let the boundary conditions setup themselves within the
        # spatial context
        #
        # TODO - the setup needs the link to the algorithm and to the
        # time-steppers as well.!
        #
        self.bcond_mngr.setup(sctx)

        # Let the response variables setup themselves within the
        # spatial context
        #
        self.rtrace_mngr.setup(self.sdomain)

        # Set up the system matrix
        #
        self.K = SysMtxAssembly()

        # Register the essential boundary conditions in the system matrix
        #
        self.bcond_mngr.apply_essential(self.K)

        self.tse_integ.apply_constraints(self.K)

        # Prepare the global update flag
        sctx.update_state_on = False

        if self.u_processor:
            if self.u_processor.sd == None:
                self.u_processor.sd = self.sdomain

        # add-on parameters to be passed to every inner loop
        # they are provided by u_processors
        #
        self.kw = {}
        self.args = []

    def eval(self, step_flag, U_k, d_U, t_n, t_n1):
        '''Get the tangential operator (system matrix) and residuum
        associated with the current time step.

        @param step_flag: indicator of the predictor | corrector step
           it is needed for proper handling of constraint equations
           (essential boundary conditions and explicit links between
           the variables.

        @param U_k: current value of the control variable (including
            the value of the last increment d_U

        @param d_U: increment of the control variable
            U[k] = U[k-1] + d_U

        @param t_n: value of the time control parameters in the
            last equilibrated step.

        @param t_n1: value of the target time in the current
            time step.
        '''

        # Reset the system matrix (constraints are preserved)
        #
        self.K.reset_mtx()

        # Put the spatial domain into the spatial context
        #
        sctx = self.sctx

        if self.u_processor:
            self.args, self.kw = self.u_processor(U_k)

        # Let the time sub-stepper evaluate its contribution.
        #
        F_int, K_mtx = self.tse_integ.get_corr_pred(sctx, U_k, d_U, t_n, t_n1,
                                                    *self.args, **self.kw)

        # Promote the system matrix to the SysMtxAssembly
        # Supported representation of the system matrix is
        # float, ndarray, SysMtxArray and SysMtxAssembly
        #
        # @todo use coerce in order to hide this conversions.
        # or is adapter concept of traits a possibility?
        #
        if isinstance(K_mtx, np.ndarray):
            self.K.add_mtx(K_mtx)
        elif isinstance(K_mtx, SysMtxArray):
            self.K.sys_mtx_arrays.append(K_mtx)
        elif isinstance(K_mtx, list):
            self.K.sys_mtx_arrays = K_mtx
        elif isinstance(K_mtx, SysMtxAssembly):
            self.K.sys_mtx_arrays = K_mtx.sys_mtx_arrays

        norm_F_int = np.linalg.norm(F_int)
        # Switch off the global update flag
        #
        sctx.update_state_on = False

        # Apply the boundary conditions
        #
        if self.dof_resultants == True:

            # The code below is somewhat wasteful as it explicitly constructs the
            # array of external forces and then makes the subraction
            # F_ext - F_int to obtain the residual forces. As a result, there two unnecessary
            # intermediate instances of the vector of the size [n_dofs].
            #
            # The two arrays are needed only for postprocessing, if there is a need
            # to get the reaction forces at particular DOF stored in F_int
            # or when the imposed time-dependent loading in a DOF should be visualized
            # for verification, the two vectors must be defined as
            # attributes of the tstepper objects. For this reasons, the more demanding
            # implementation is used here.
            #
            # Remember F_int
            #
            self.F_int = F_int

            # Prepare F_ext by zeroing it
            #
            self.F_ext[:] = 0.0

            # Assemble boundary conditions in K and self.F_ext
            #
            self.bcond_mngr.apply(step_flag, sctx, self.K, self.F_ext, t_n,
                                  t_n1)

            # Return the system matrix assembly K and the residuum
            #
            return self.K, self.F_ext - self.F_int, norm_F_int

        else:

            # On the other hand, the time-loop only requires the residuum
            # which can be obtained without an additional
            # memory consumption by issuing an in-place switch of the sign
            #
            F_int *= -1  # in-place sign change of the internal forces
            #
            # Then F_int can be used as the target for the boundary conditions
            #
            self.bcond_mngr.apply(step_flag, sctx, self.K, F_int, t_n, t_n1)

            #
            # The subtraction F_ext - F_int has then been performed implicitly
            # and the residuum can be returned by issuing
            #
            return self.K, F_int, norm_F_int

    def update_state(self, U):
        '''
        spatial context represents a stack with the top object
         representing the current level.
        @param U:
        '''
        #sctx = ( self.sdomain, )
        self.sctx.update_state_on = True
        #self.tse_integ.update_state( sctx, U )

    def register_mv_pipelines(self, e):
        '''Register the visualization pipelines in mayavi engine
        '''
        self.tse_integ.register_mv_pipelines(e)
        scene = e.new_scene()
        scene.name = 'Spatial domain'
        self.sdomain.register_mv_pipelines(e)
        self.rtrace_mngr.register_mv_pipelines(e)

    traits_view = View(
        Group(Item('sdomain', style='custom', show_label=False),
              label='Discretization'),
        Group(Item('tse', style='simple', show_label=False),
              label='Integrator'),
        Group(Item('bcond_mngr', style='custom', show_label=False),
              label='Boundary conditions'),
        Group(Item('dof_resultants'), label='Options'),
        resizable=True,
        height=0.8,
        width=0.8,
        buttons=[OKButton, CancelButton],
        kind='subpanel',
    )
Ejemplo n.º 5
0
class TLoop(HasStrictTraits):

    ts = Instance(MATS3DExplore)

    tline = Instance(TLine, ())
    d_t = Float(0.005)
    t_max = Float(1.0)
    k_max = Int(50)
    tolerance = Float(1e-4)
    step_tolerance = Float(1e-8)

    t_record = List
    U_n = Array(dtype=np.float_)
    K = Array(dtype=np.float_)
    state = Array(dtype=np.float_)
    F_record = List
    U_record = List
    state_record = List

    K = Instance(SysMtxAssembly)

    paused = Bool(False)
    restart = Bool(True)

    def setup(self):
        n_comps = 6
        n_dofs = n_comps
        self.U_n = np.zeros((n_dofs, ))
        t_n = self.tline.val
        self.t_record = [t_n]
        self.U_record = [np.zeros_like(self.U_n)]
        self.F_record = [np.copy(self.U_n)]
        self.state_record = [np.copy(self.state)]
        # Set up the system matrix
        #
        self.K = SysMtxAssembly()
        self.ts.bcond_mngr.apply_essential(self.K)

    state_changed = Event
    state_arrays = Property(Dict(Str, Array), depends_on='state_changed')
    '''Dictionary of state arrays.
    The entry names and shapes are defined by the material
    model.
    '''

    @cached_property
    def _get_state_arrays(self):
        sa_shapes = self.ts.state_array_shapes
        print('state array generated', sa_shapes)
        return {
            name: np.zeros(mats_sa_shape, dtype=np.float_)[np.newaxis, ...]
            for name, mats_sa_shape in list(sa_shapes.items())
        }

    def init(self):
        if self.paused:
            self.paused = False
        if self.restart:
            self.tline.val = 0
            self.state_changed = True
            self.setup()
            self.restart = False

    def eval(self):
        # Reset the system matrix (constraints are preserved)
        #
        self.d_t = self.tline.step
        F_ext = np.zeros_like(self.U_n)
        t_n = self.tline.val
        t_n1 = t_n
        U_n = self.U_n
        while (t_n1 - self.tline.max) <= self.step_tolerance and \
                not (self.restart or self.paused):
            k = 0
            print('load factor', t_n1, end=' ')
            step_flag = 'predictor'
            U_k = np.copy(U_n)
            d_U_k = np.zeros_like(U_k)
            while k <= self.k_max and \
                    not (self.restart or self.paused):

                self.K.reset_mtx()

                K_mtx, F_int = self.ts.get_corr_pred(U_k, d_U_k, t_n, t_n1,
                                                     step_flag,
                                                     **self.state_arrays)

                self.K.add_mtx(K_mtx)

                # Prepare F_ext by zeroing it
                #
                F_ext[:] = 0.0

                # Assemble boundary conditions in K and self.F_ext
                #
                self.ts.bcond_mngr.apply(step_flag, None, self.K, F_ext, t_n,
                                         t_n1)

                # Return the system matrix assembly K and the residuum
                #
                R = F_ext - F_int

                self.K.apply_constraints(R)
                d_U_k, pos_def = self.K.solve()
                U_k += d_U_k
                if np.linalg.norm(R) < self.tolerance:
                    U_n[:] = U_k[:]
                    self.t_record.append(t_n1)
                    self.U_record.append(U_k)
                    self.F_record.append(F_int)
                    self.state_record.append(np.copy(self.state))
                    break
                k += 1
                step_flag = 'corrector'

            if k >= self.k_max:
                print(' ----------> no convergence')
                break
            else:
                print('(', k, ')')
            if self.restart or self.paused:
                print('interrupted iteration')
                break

            t_n = t_n1
            t_n1 = t_n + self.d_t
            self.tline.val = min(t_n, self.tline.max)
        return U_k

    def get_time_idx_arr(self, vot):
        '''Get the index corresponding to visual time
        '''
        x = self.t_record
        idx = np.array(np.arange(len(x)), dtype=np.float_)
        t_idx = np.interp(vot, x, idx)
        return np.array(t_idx + 0.5, np.int_)

    def get_time_idx(self, vot):
        return int(self.get_time_idx_arr(vot))