Ejemplo n.º 1
0
class MFnChacoEditorToolbar(HasPrivateTraits):
    """ Toolbar displayed in table editors.
    """
    #---------------------------------------------------------------------------
    #  Trait definitions:
    #---------------------------------------------------------------------------

    # Do not sort columns:
    save_data = Instance(
        Action, {
            'name': 'Save as data',
            'tooltip': 'Save the function values',
            'action': 'on_savedata',
            'enabled': True,
            'image': ImageResource('add')
        })

    # Move current object up one row:
    save_fig = Instance(
        Action, {
            'name': 'Save as fig',
            'tooltip': 'Save as figure',
            'action': 'on_savefig',
            'enabled': True,
            'image': ImageResource('save')
        })

    # The table editor that this is the toolbar for:
    editor = Instance(_MFnChacoEditor)

    # The toolbar control:
    control = Any

    #---------------------------------------------------------------------------
    #  Initializes the toolbar for a specified window:
    #---------------------------------------------------------------------------

    def __init__(self, parent=None, **traits):
        super(MFnChacoEditorToolbar, self).__init__(**traits)
        factory = self.editor.factory

        actions = [self.save_data, self.save_fig]
        toolbar = ToolBar(image_size=(16, 16),
                          show_tool_names=False,
                          show_divider=False,
                          *actions)
        self.control = toolbar.create_tool_bar(parent, self)
        self.control.SetBackgroundColour(parent.GetBackgroundColour())

        # fixme: Why do we have to explictly set the size of the toolbar?
        #        Is there some method that needs to be called to do the
        #        layout?
        self.control.SetSize(wx.Size(23 * len(actions), 16))

    #---------------------------------------------------------------------------
    #  PyFace/Traits menu/toolbar controller interface:
    #---------------------------------------------------------------------------

    #---------------------------------------------------------------------------
    #  Adds a menu item to the menu bar being constructed:
    #---------------------------------------------------------------------------

    def add_to_menu(self, menu_item):
        """ Adds a menu item to the menu bar being constructed.
        """
        pass

    #---------------------------------------------------------------------------
    #  Adds a tool bar item to the tool bar being constructed:
    #---------------------------------------------------------------------------

    def add_to_toolbar(self, toolbar_item):
        """ Adds a toolbar item to the too bar being constructed.
        """
        pass

    #---------------------------------------------------------------------------
    #  Returns whether the menu action should be defined in the user interface:
    #---------------------------------------------------------------------------

    def can_add_to_menu(self, action):
        """ Returns whether the action should be defined in the user interface.
        """
        return True

    #---------------------------------------------------------------------------
    #  Returns whether the toolbar action should be defined in the user
    #  interface:
    #---------------------------------------------------------------------------

    def can_add_to_toolbar(self, action):
        """ Returns whether the toolbar action should be defined in the user
            interface.
        """
        return True

    #---------------------------------------------------------------------------
    #  Performs the action described by a specified Action object:
    #---------------------------------------------------------------------------

    def perform(self, action, action_event=None):
        """ Performs the action described by a specified Action object.
        """
        getattr(self.editor, action.action)()
Ejemplo n.º 2
0
class SimArrayView(ModelView):
    '''
    View into the parametric space constructed over the model.

    The is associated with the PStudySpace instance covering the
    factor ranges using an n-dimensional array.
    
    The view is responsible for transferring the response values
    into 2D and 3D plots. Depending on the current view specification
    it also initiates the calculation of response values in the 
    currently viewed subspace of the study. 
    '''

    model = Instance(ISimArray)

    #---------------------------------------------------------------
    # PARAMETER RANGE SPECIFICATION
    #-------------------------------------------------------------------
    factor_dict = DelegatesTo('model')

    # alphabetically ordered names of factors
    #
    factor_names = DelegatesTo('model')

    # alphabetically ordered list of factors
    #
    factor_list = DelegatesTo('model')

    #---------------------------------------------------------------
    # X-PARAMETER RANGE SPECIFICATION
    #-------------------------------------------------------------------
    # Selected factor name for evalution along the X-axis
    #
    x_factor_name = Str(factors_modified=True)

    def _x_factor_name_default(self):
        return self.factor_names[0]

    def _x_factor_name_changed(self):
        if self.x_factor_name == self.y_factor_name:
            self.y_factor_name = '-'
        if self.x_factor_name == self.other_factor_name:
            self.other_factor_name = '-'
        self.x_factor = self.factor_dict[self.x_factor_name]

    x_factor = Instance(SimFactor)

    def _x_factor_default(self):
        return self.factor_dict[self.factor_names[0]]

    # index of the currently selected variable
    x_factor_idx = Property()

    def _get_x_factor_idx(self):
        return self.factor_names.index(self.x_factor_name)

    #---------------------------------------------------------------
    # Y-PARAMETER RANGE SPECIFICATION
    #-------------------------------------------------------------------
    y_factor_names = Property(depends_on='x_factor_name')

    @cached_property
    def _get_y_factor_names(self):
        current_x_factor = self.x_factor_name
        current_x_factor_idx = self.factor_names.index(current_x_factor)
        y_factor_names = self.factor_names[:current_x_factor_idx] + \
                        self.factor_names[current_x_factor_idx+1:]
        return ['-'] + y_factor_names

    #
    # Selected factor name for evalution of multiple lines
    #
    y_factor_name = Str('-', factors_modified=True)

    def _y_factor_name_changed(self):
        if self.y_factor_name == self.other_factor_name:
            self.other_factor_name = '-'
        if self.y_factor_name == '-':
            self.y_factor = None
        else:
            self.y_factor = self.factor_dict[self.y_factor_name]

    y_factor = Instance(SimFactor)

    y_factor_idx = Property()

    def _get_y_factor_idx(self):
        return self.factor_names.index(self.y_factor_name)

    #------------------------------------------------------------------
    # OTHER PARAM LEVELS
    #------------------------------------------------------------------
    other_factor_names = Property(depends_on='x_factor_name, y_factor_name')

    @cached_property
    def _get_other_factor_names(self):
        x_factor_idx = self.factor_names.index(self.x_factor_name)

        y_factor_idx = x_factor_idx
        if self.y_factor_name != '-':
            y_factor_idx = self.factor_names.index(self.y_factor_name)

        ignore_idx = [x_factor_idx, y_factor_idx]
        ignore_idx.sort()

        other_factor_names = self.factor_names[:ignore_idx[0] ] + \
                            self.factor_names[ignore_idx[0]+1: ignore_idx[1]] + \
                            self.factor_names[ignore_idx[1]+1:]

        return ['-'] + other_factor_names

    #
    # Selected factor name for evalution of multiple lines
    #
    other_factor_name = Str('-', factors_modified=True)

    def _other_factor_name_changed(self):
        if self.other_factor_name == '-':
            self.other_factor_levels = []
        else:
            levels = self.factor_dict[self.other_factor_name].level_list
            self.other_factor_levels = list(levels)
            other_factor_idx = self.factor_names.index(self.other_factor_name)
            other_factor_level_idx = self.frozen_factor_levels[
                other_factor_idx]
            self.other_factor_level = self.other_factor_levels[
                other_factor_level_idx]

    other_factor_levels = List
    other_factor_level = Any

    def _other_factor_level_changed(self):
        level_idx = self.other_factor_levels.index(self.other_factor_level)
        other_factor_idx = self.factor_names.index(self.other_factor_name)
        self.frozen_factor_levels[other_factor_idx] = level_idx

    frozen_factor_levels = Array

    def _frozen_factor_levels_default(self):
        return zeros(self.model.n_factors, dtype='int_')

    #---------------------------------------------------------------
    # OUTPUT ARRAY SPECIFICATION
    #-------------------------------------------------------------------
    outputs = DelegatesTo('model')

    # extract the available names
    output_names = DelegatesTo('model')

    # active selection to be plotted
    output_name = Str

    def _output_name_default(self):
        return self.output_names[0]

    output_idx = Property(Int, depends_on='output_name')

    def _get_output_idx(self):
        return self.output_names.index(self.output_name)

    def _output_name_changed(self):
        self.output = self.outputs[self.output_idx]

    output = Instance(SimOut)

    def _output_default(self):
        return self.outputs[0]

    #---------------------------------------------------------------
    # PLOT OBJECT
    #-------------------------------------------------------------------
    figure = Instance(Figure)

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

    #---------------------------------------------------------------------------
    # Public Controller interface
    #---------------------------------------------------------------------------
    def start_study(self, ui_info):
        self._start_study()

    def stop_study(self, ui_info):
        todo = ToDo()
        todo.configure_traits(kind='modal')

    def _start_study(self):

        # identify the runs to be performed
        # use slices along the varied factors
        # to obtain the indices of the values.

        # get the sliced dimensions
        #
        factor_levels = [level for level in self.frozen_factor_levels]
        factor_levels[self.x_factor_idx] = slice(None)
        if self.y_factor_name != '-':
            factor_levels[self.y_factor_idx] = slice(None)

        factor_slices = tuple(factor_levels)

        # get the response value for the given factor slices
        #
        output_array = self.model[factor_slices]

        # map the array dimensions to the plot axes
        #
        figure = self.figure

        axes = figure.axes[0]
        axes.clear()

        x_levels = self.x_factor.level_list

        if self.y_factor_name == '-':

            axes.plot(x_levels, output_array[:, self.output_idx]
                      # color = c, linewidth = w, linestyle = s
                      )
        else:
            y_levels = self.y_factor.level_list
            for i_y, y_level in enumerate(y_levels):

                index = x_levels

                # The dimensions of the returned array are given
                # by the index of the factors within the pstudy
                # In other words, the subspace to be plotted has
                # the same order of factors as the original space.
                # The remapping of the axes must therefore respect
                # this order and take y data from the first dimension
                # if y_factor_idx is lower than y_factor_idx
                #
                if self.y_factor_idx > self.x_factor_idx:
                    values = output_array[:, i_y, self.output_idx]
                else:
                    values = output_array[i_y, :, self.output_idx]

                axes.plot(index, values
                          # color = c, linewidth = w, linestyle = s
                          )
            legend = [str(level) for level in y_levels]
            axes.legend(legend, loc='best')

        axes.set_xlabel('%s [%s]' % (self.x_factor_name, self.x_factor.unit),
                        weight='semibold')
        axes.set_ylabel('%s [%s]' % (self.output_name, self.output.unit),
                        weight='semibold')

        #        axes.set_title( 'strength size effect',\
        #                        size = 'large', color = 'black',\
        #                        weight = 'bold', position = (.5,1.03))
        axes.set_axis_bgcolor(color='white')
        #        axes.ticklabel_format(scilimits = (-3.,4.))
        axes.grid(color='gray', linestyle='--', linewidth=0.1, alpha=0.4)
        #        axes.legend(( legend ), loc = 'best')
        #        axes.set_xscale('log' ) #, subsx = [0, 1, 2, 3 ] )
        #        axes.set_yscale('log' ) # , subsy = [0, 1, 2, 3, 4, 5, 6, 7, 8, 9] )
        #axes.set_xlim(10.e-4)

        self.data_changed = True

    data_changed = Event

    traits_view = View(
        HSplit(
            VGroup(
                VGroup(
                    Item('x_factor_name',
                         editor=EnumEditor(name='factor_names'),
                         label='horizontal axis'),
                    Item('y_factor_name',
                         editor=EnumEditor(name='y_factor_names'),
                         label='depth axis'),
                    Item('other_factor_name',
                         editor=EnumEditor(name='other_factor_names'),
                         label='other factors'),
                    Item('other_factor_level',
                         editor=EnumEditor(name='other_factor_levels'),
                         label='viewed level'),
                    label='viewed subspace',
                    id='sim_pstudy.viewmodel.factor.subspace',
                    dock='tab',
                    scrollable=True,
                ),
                VGroup(
                    Item('output_name',
                         editor=EnumEditor(name='output_names'),
                         show_label=False),
                    Item('output@', show_label=False, springy=True),
                    label='vertical axis',
                    id='sim_psrudy.viewmodel.control',
                    dock='tab',
                ),
                id='sim_pstudy.viewmodel.left',
                label='studied factors',
                layout='normal',
                dock='tab',
            ),
            VSplit(
                VGroup(
                    Item('figure',
                         editor=MPLFigureEditor(),
                         resizable=True,
                         show_label=False),
                    label='plot sheet',
                    id='sim_pstudy.viewmode.figure_window',
                    dock='tab',
                ),
                id='sim_pstudy.viewmodel.right',
            ),
            id='sim_pstudy.viewmodel.splitter',
            #group_theme = '@G',
            #item_theme  = '@B0B',
            #label_theme = '@BEA',
        ),
        toolbar=ToolBar(Action(name="Run",
                               tooltip='Start computation',
                               image=ImageResource('kt-start'),
                               action="start_study"),
                        Action(name="Pause",
                               tooltip='Pause computation',
                               image=ImageResource('kt-pause'),
                               action="pause_study"),
                        Action(name="Stop",
                               tooltip='Stop computation',
                               image=ImageResource('kt-stop'),
                               action="stop_study"),
                        image_size=(32, 32),
                        show_tool_names=False,
                        show_divider=True,
                        name='view_toolbar'),
        title='SimVisage Component: Parametric Studies',
        id='sim_pstudy.viewmodel',
        dock='tab',
        resizable=True,
        height=0.8,
        width=0.8,
        buttons=[OKButton])
Ejemplo n.º 3
0
class SimCrackLoc( IBVModel ):
    '''Model assembling the components for studying the restrained crack localization.
    '''
    shape = Int( 1, desc = 'Number of finite elements',
                   ps_levsls = ( 10, 40, 4 ) )
    length = Float( 1, desc = 'Length of the simulated region' )

    #-------------------------------------------------------
    # Material model for the matrix
    #-------------------------------------------------------
    mats_m = Instance( MATS1DCrackLoc )
    def _mats_m_default( self ):
        E_m = 1
        mats_m = MATS1DCrackLoc( E = E_m,
                                 R = 0.5,
                                 epsilon_0 = 0.001,
                                 epsilon_f = 0.01 )
        return mats_m

    mats_f = Instance( MATS1DElastic )
    def _mats_f_default( self ):
        E_f = 0
        mats_f = MATS1DElastic( E = E_f )
        return mats_f

    mats_b = Instance( MATS1DElastic )
    def _mats_b_default( self ):
        E_b = 0
        mats_b = MATS1DElastic( E = E_b )
        return mats_b

    mats = Instance( MATS1D5Bond )
    def _mats_default( self ):

        # Material model construction
        mats = MATS1D5Bond( mats_phase1 = self.mats_m,
                            mats_phase2 = self.mats_f,
                            mats_ifslip = self.mats_b,
                            mats_ifopen = MATS1DElastic( E = 0 )   # elastic function of open - inactive
                            )
        return mats
    #-------------------------------------------------------
    # Finite element type
    #-------------------------------------------------------
    fets = Instance( FETSEval )
    def _fets_default( self ):
        #return FETS1D52L8ULRH( mats_eval = self.mats )        
        return FETS1D52L4ULRH( mats_eval = self.mats )
        #return FETS1D2L3U( mats_eval = self.mats ) 

    run = Button

    @on_trait_change( 'run' )
    def peval( self ):
        '''Evaluation procedure.
        '''
        #mv = MATS1DDamageView( model = mats_eval )
        #mv.configure_traits()

        self.mats_m.reset_state()
        # Discretization
        #
        length = self.length
        domain = FEGrid( coord_min = ( 0., length / 5. ),
                          coord_max = ( length, 0. ),
                          shape = ( self.shape, 1 ),
                          fets_eval = self.fets )

        right_dofs = domain[-1, -1, -1, :].dofs[0, :, 0]
        print 'concrete_dofs', id( domain ), domain[:, 0, :, 0].dofs
        # Response tracers
        self.stress_strain = RTraceGraph( name = 'Fi,right over u_right (iteration)' ,
                                   var_y = 'F_int', idx_y = right_dofs[0],
                                   var_x = 'U_k', idx_x = right_dofs[0] )
        self.eps_m_field = RTraceDomainListField( name = 'eps_m' , position = 'int_pnts',
                                           var = 'eps1', idx = 0,
                                           warp = True )

        self.eps_f_field = RTraceDomainListField( name = 'eps_f' , position = 'int_pnts',
                                           var = 'eps2', idx = 0,
                                           warp = True )

        # Response tracers
        self.sig_m_field = RTraceDomainListField( name = 'sig_m' , position = 'int_pnts',
                                              var = 'mats_phase1_sig_app', idx = 0 )
        self.sig_f_field = RTraceDomainListField( name = 'sig_f' , position = 'int_pnts',
                                              var = 'mats_phase2_sig_app', idx = 0 )
        self.omega_m_field = RTraceDomainListField( name = 'omega_m' , position = 'int_pnts',
                                           var = 'mats_phase1_omega', idx = 0,
                                           warp = True )
        # 

        damage_onset_displ = self.mats_m.epsilon_0 * self.length
        go_behind = 1.5
        finish_displ = go_behind * damage_onset_displ
        n_steps = 20
        step_size = ( finish_displ - damage_onset_displ ) / n_steps
        tmax = 1 + n_steps

        def ls( t ):
            if t <= 1:
                return t
            else:
                return 1.0 + ( t - 1.0 ) / n_steps * ( go_behind - 1 )

        ts = TSCrackLoc( 
                 dof_resultants = True,
                 on_update = self.plot,
                 sdomain = domain,
                 bcond_list = [# define the left clamping 
                                BCSlice( var = 'u', value = 0., dims = [0], slice = domain[ 0, 0, 0, :] ),
                                # loading at the right edge
                                 BCSlice( var = 'f', value = 1, dims = [0], slice = domain[-1, -1, -1, 0],
                                         time_function = ls ),
#                                 BCSlice(var='u', value = finish_displ, dims = [0], slice = domain[-1,-1,-1, 0],
#                                         time_function = ls ),
                                # fix horizontal displacement in the top layer
                                 BCSlice( var = 'u', value = 0., dims = [0], slice = domain[:, -1, :, -1] ),
                                # fix the vertical displacement all over the domain
                                 BCSlice( var = 'u', value = 0., dims = [1], slice = domain[ :, :, :, :] )
                                ],
                 rtrace_list = [ self.stress_strain,
                                  self.eps_m_field,
                                  self.eps_f_field,
                                  self.sig_m_field,
                                  self.sig_f_field,
                                  self.omega_m_field ]
                )

        # Add the time-loop control
        tloop = TLoop( tstepper = ts, KMAX = 200, debug = True, tolerance = 1e-5,
                       tline = TLine( min = 0.0, step = 1.0, max = 1.0 ) )

        print ts.rte_dict.keys()
        U = tloop.eval()

        self.plot()

        return array( [ U[right_dofs[-1]] ], dtype = 'float_' )

    #---------------------------------------------------------------
    # PLOT OBJECT
    #-------------------------------------------------------------------
    figure_ld = Instance( Figure )
    def _figure_ld_default( self ):
        figure = Figure( facecolor = 'white' )
        figure.add_axes( [0.12, 0.13, 0.85, 0.74] )
        return figure

    #---------------------------------------------------------------
    # PLOT OBJECT
    #-------------------------------------------------------------------
    figure_eps = Instance( Figure )
    def _figure_eps_default( self ):
        figure = Figure( facecolor = 'white' )
        figure.add_axes( [0.12, 0.13, 0.85, 0.74] )
        return figure

    #---------------------------------------------------------------
    # PLOT OBJECT
    #-------------------------------------------------------------------
    figure_omega = Instance( Figure )
    def _figure_omega_default( self ):
        figure = Figure( facecolor = 'white' )
        figure.add_axes( [0.12, 0.13, 0.85, 0.74] )
        return figure

    #---------------------------------------------------------------
    # PLOT OBJECT
    #-------------------------------------------------------------------
    figure_sig = Instance( Figure )
    def _figure_sig_default( self ):
        figure = Figure( facecolor = 'white' )
        figure.add_axes( [0.12, 0.13, 0.85, 0.74] )
        return figure

    def plot( self ):
        self.stress_strain.refresh()
        t = self.stress_strain.trace
        ax = self.figure_ld.axes[0]
        ax.clear()
        ax.plot( t.xdata, t.ydata, linewidth = 2, color = 'blue' )

        ax = self.figure_eps.axes[0]
        ax.clear()

        ef = self.eps_m_field.subfields[0]
        xdata = ef.vtk_X[:, 0]
        ydata = ef.field_arr[:, 0]
        idata = argsort( xdata )
        ax.plot( xdata[idata], ydata[idata], linewidth = 2, color = 'grey' )

        ef = self.eps_f_field.subfields[0]
        xdata = ef.vtk_X[:, 0]
        ydata = ef.field_arr[:, 0]
        idata = argsort( xdata )
        ax.plot( xdata[idata], ydata[idata], linewidth = 2, color = 'red' )
        ax.legend( ['eps_m', 'eps_f'] )

        ax = self.figure_sig.axes[0]
        ax.clear()

        ef = self.sig_m_field.subfields[0]
        xdata = ef.vtk_X[:, 0]
        ydata = ef.field_arr[:, 0]
        idata = argsort( xdata )
        ax.plot( xdata[idata], ydata[idata], linewidth = 2, color = 'grey' )

        ef = self.sig_f_field.subfields[0]
        xdata = ef.vtk_X[:, 0]
        ydata = ef.field_arr[:, 0]
        idata = argsort( xdata )
        ax.plot( xdata[idata], ydata[idata], linewidth = 2, color = 'red' )
        ax.legend( ['sig_m', 'sig_f'] )


        ax = self.figure_omega.axes[0]
        ax.clear()

        ef = self.omega_m_field.subfields[0]
        xdata = ef.vtk_X[:, 0]
        ydata = ef.field_arr[:, 0]
        idata = argsort( xdata )
        ax.plot( xdata[idata], ydata[idata], linewidth = 2, color = 'brown' )
        ax.legend( ['omega_m'] )


        self.data_changed = True

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

    data_changed = Event

    toolbar = ToolBar( 
                      Action( name = "Run",
                             tooltip = 'Start computation',
                             image = ImageResource( 'kt-start' ),
                             action = "start_study" ),
                      Action( name = "Pause",
                             tooltip = 'Pause computation',
                             image = ImageResource( 'kt-pause' ),
                             action = "pause_study" ),
                      Action( name = "Stop",
                             tooltip = 'Stop computation',
                             image = ImageResource( 'kt-stop' ),
                             action = "stop_study" ),
                      image_size = ( 32, 32 ),
                      show_tool_names = False,
                      show_divider = True,
                      name = 'view_toolbar' ),

    traits_view = View( 
                    HSplit( 
                        VSplit( 
                                Item( 'run', show_label = False ),
                            VGroup( 
                                 Item( 'shape' ),
                                 Item( 'n_sjteps' ),
                                 Item( 'length' ),
                                 label = 'parameters',
                                 id = 'crackloc.viewmodel.factor.geometry',
                                 dock = 'tab',
                                 scrollable = True,
                                 ),
                            VGroup( 
                                 Item( 'mats_m@', show_label = False ),
                                 label = 'Matrix',
                                 dock = 'tab',
                                 id = 'crackloc.viewmodel.factor.matrix',
                                 scrollable = True
                                 ),
                            VGroup( 
                                 Item( 'mats_f@', show_label = False ),
                                 label = 'Fiber',
                                 dock = 'tab',
                                 id = 'crackloc.viewmodel.factor.fiber',
                                 scrollable = True
                                 ),
                            VGroup( 
                                 Item( 'mats_b@', show_label = False ),
                                 label = 'Bond',
                                 dock = 'tab',
                                 id = 'crackloc.viewmodel.factor.bond',
                                 scrollable = True
                                ),
                            id = 'crackloc.viewmodel.left',
                            label = 'studied factors',
                            layout = 'tabbed',
                            dock = 'tab',
                            ),
                               VSplit( 
                                    VGroup( 
                                        Item( 'figure_ld', editor = MPLFigureEditor(),
                                             resizable = True, show_label = False ),
                                             label = 'stress-strain',
                                            id = 'crackloc.viewmode.figure_ld_window',
                                            dock = 'tab',
                                    ),
                                    VGroup( 
                                        Item( 'figure_eps', editor = MPLFigureEditor(),
                                             resizable = True, show_label = False ),
                                             label = 'strains profile',
                                            id = 'crackloc.viewmode.figure_eps_window',
                                            dock = 'tab',
                                        ),
                                    VGroup( 
                                        Item( 'figure_sig', editor = MPLFigureEditor(),
                                             resizable = True, show_label = False ),
                                             label = 'stress profile',
                                            id = 'crackloc.viewmode.figure_sig_window',
                                            dock = 'tab',
                                        ),
                                    VGroup( 
                                        Item( 'figure_omega', editor = MPLFigureEditor(),
                                             resizable = True, show_label = False ),
                                             label = 'omega profile',
                                            id = 'crackloc.viewmode.figure_omega_window',
                                            dock = 'tab',
                                        ),
                                   id = 'crackloc.viewmodel.right',
                                 ),
                            id = 'crackloc.viewmodel.splitter',
                        ),
                        title = 'SimVisage Component: Crack localization',
                        id = 'crackloc.viewmodel',
                        dock = 'tab',
                        resizable = True,
                        height = 0.8, width = 0.8,
                        buttons = [OKButton] )
Ejemplo n.º 4
0
class SimCrackLoc(IBVModel):
    '''Model assembling the components for studying the restrained crack localization.
    '''

    geo_transform = Instance(FlawCenteredGeoTransform)

    def _geo_transform_default(self):
        return FlawCenteredGeoTransform()

    shape = Int(10,
                desc='Number of finite elements',
                ps_levsls=(10, 40, 4),
                input=True)

    length = Float(1000,
                   desc='Length of the simulated region',
                   unit='mm',
                   input=True)

    flaw_position = Float(500, input=True, unit='mm')

    flaw_radius = Float(100, input=True, unit='mm')

    reduction_factor = Float(0.9, input=True)

    elastic_fraction = Float(0.9, input=True)

    avg_radius = Float(400, input=True, unit='mm')

    # tensile strength of concrete
    f_m_t = Float(3.0, input=True, unit='MPa')

    epsilon_0 = Property(unit='-')

    def _get_epsilon_0(self):
        return self.f_m_t / self.E_m

    epsilon_f = Float(10, input=True, unit='-')

    h_m = Float(10, input=True, unit='mm')

    b_m = Float(8, input=True, unit='mm')

    A_m = Property(unit='m^2')

    def _get_A_m(self):
        return self.b_m * self.h_m

    E_m = Float(30.0e5, input=True, unit='MPa')

    E_f = Float(70.0e6, input=True, unit='MPa')

    A_f = Float(1.0, input=True, unit='mm^2')

    s_crit = Float(0.009, input=True, unit='mm')

    P_f = Property(depends_on='+input')

    @cached_property
    def _get_P_f(self):
        return sqrt(4 * self.A_f * pi)

    K_b = Property(depends_on='+input')

    @cached_property
    def _get_K_b(self):
        return self.T_max / self.s_crit

    tau_max = Float(0.0, input=True, unit='MPa')

    T_max = Property(depends_on='+input', unit='N/mm')

    @cached_property
    def _get_T_max(self):
        return self.tau_max * self.P_f

    rho = Property(depends_on='+input')

    @cached_property
    def _get_rho(self):
        return self.A_f / (self.A_f + self.A_m)

    #-------------------------------------------------------
    # Material model for the matrix
    #-------------------------------------------------------
    mats_m = Property(Instance(MATS1DDamageWithFlaw), depends_on='+input')

    @cached_property
    def _get_mats_m(self):
        mats_m = MATS1DDamageWithFlaw(E=self.E_m * self.A_m,
                                      flaw_position=self.flaw_position,
                                      flaw_radius=self.flaw_radius,
                                      reduction_factor=self.reduction_factor,
                                      epsilon_0=self.epsilon_0,
                                      epsilon_f=self.epsilon_f)
        return mats_m

    mats_f = Instance(MATS1DElastic)

    def _mats_f_default(self):
        mats_f = MATS1DElastic(E=self.E_f * self.A_f)
        return mats_f

    mats_b = Instance(MATS1DEval)

    def _mats_b_default(self):
        mats_b = MATS1DElastic(E=self.K_b)
        mats_b = MATS1DPlastic(E=self.K_b,
                               sigma_y=self.T_max,
                               K_bar=0.,
                               H_bar=0.)  # plastic function of slip
        return mats_b

    mats_fb = Property(Instance(MATS1D5Bond), depends_on='+input')

    @cached_property
    def _get_mats_fb(self):

        # Material model construction
        return MATS1D5Bond(
            mats_phase1=MATS1DElastic(E=0),
            mats_phase2=self.mats_f,
            mats_ifslip=self.mats_b,
            mats_ifopen=MATS1DElastic(
                E=0)  # elastic function of open - inactive
        )

    #-------------------------------------------------------
    # Finite element type
    #-------------------------------------------------------
    fets_m = Property(depends_on='+input')

    @cached_property
    def _get_fets_m(self):
        fets_eval = FETS1D2L(mats_eval=self.mats_m)
        #fets_eval = FETS1D2L3U( mats_eval = self.mats_m )
        return fets_eval

    fets_fb = Property(depends_on='+input')

    @cached_property
    def _get_fets_fb(self):
        return FETS1D52L4ULRH(mats_eval=self.mats_fb)
        #return FETS1D52L6ULRH( mats_eval = self.mats_fb )
        #return FETS1D52L8ULRH( mats_eval = self.mats_fb )

    #--------------------------------------------------------------------------------------
    # Mesh integrator
    #--------------------------------------------------------------------------------------
    fe_domain_structure = Property(depends_on='+input')

    @cached_property
    def _get_fe_domain_structure(self):
        '''Root of the domain hierarchy
        '''
        elem_length = self.length / float(self.shape)

        fe_domain = FEDomain()

        fe_m_level = FERefinementGrid(name='matrix domain',
                                      domain=fe_domain,
                                      fets_eval=self.fets_m)

        fe_grid_m = FEGrid(name='matrix grid',
                           coord_max=(self.length, ),
                           shape=(self.shape, ),
                           level=fe_m_level,
                           fets_eval=self.fets_m,
                           geo_transform=self.geo_transform)

        fe_fb_level = FERefinementGrid(name='fiber bond domain',
                                       domain=fe_domain,
                                       fets_eval=self.fets_fb)

        fe_grid_fb = FEGrid(coord_min=(0., length / 5.),
                            coord_max=(length, 0.),
                            shape=(self.shape, 1),
                            level=fe_fb_level,
                            fets_eval=self.fets_fb,
                            geo_transform=self.geo_transform)

        return fe_domain, fe_grid_m, fe_grid_fb, fe_m_level, fe_fb_level

    fe_domain = Property

    def _get_fe_domain(self):
        return self.fe_domain_structure[0]

    fe_grid_m = Property

    def _get_fe_grid_m(self):
        return self.fe_domain_structure[1]

    fe_grid_fb = Property

    def _get_fe_grid_fb(self):
        return self.fe_domain_structure[2]

    fe_m_level = Property

    def _get_fe_m_level(self):
        return self.fe_domain_structure[3]

    fe_fb_level = Property

    def _get_fe_fb_level(self):
        return self.fe_domain_structure[4]

    #---------------------------------------------------------------------------
    # Load scaling adapted to the elastic and inelastic regime
    #---------------------------------------------------------------------------
    final_displ = Property(depends_on='+input')

    @cached_property
    def _get_final_displ(self):
        damage_onset_displ = self.mats_m.epsilon_0 * self.length
        return damage_onset_displ / self.elastic_fraction

    step_size = Property(depends_on='+input')

    @cached_property
    def _get_step_size(self):
        n_steps = self.n_steps
        return 1.0 / float(n_steps)

    time_function = Property(depends_on='+input')

    @cached_property
    def _get_time_function(self):
        '''Get the time function so that the elastic regime 
        is skipped in a single step.
        '''
        step_size = self.step_size

        elastic_value = self.elastic_fraction * 0.98 * self.reduction_factor
        inelastic_value = 1.0 - elastic_value

        def ls(t):
            if t <= step_size:
                return (elastic_value / step_size) * t
            else:
                return elastic_value + (t - step_size) * (inelastic_value) / (
                    1 - step_size)

        return ls

    def plot_time_function(self, p):
        '''Plot the time function.
        '''
        n_steps = self.n_steps
        mats = self.mats
        step_size = self.step_size

        ls_t = linspace(0, step_size * n_steps, n_steps + 1)
        ls_fn = frompyfunc(self.time_function, 1, 1)
        ls_v = ls_fn(ls_t)

        p.subplot(321)
        p.plot(ls_t, ls_v, 'ro-')

        final_epsilon = self.final_displ / self.length

        kappa = linspace(mats.epsilon_0, final_epsilon, 10)
        omega_fn = frompyfunc(lambda kappa: mats._get_omega(None, kappa), 1, 1)
        omega = omega_fn(kappa)
        kappa_scaled = (step_size + (1 - step_size) *
                        (kappa - mats.epsilon_0) /
                        (final_epsilon - mats.epsilon_0))
        xdata = hstack([array([0.0], dtype=float), kappa_scaled])
        ydata = hstack([array([0.0], dtype=float), omega])
        p.plot(xdata, ydata, 'g')
        p.xlabel('regular time [-]')
        p.ylabel('scaled time [-]')

    run = Button

    @on_trait_change('run')
    def peval(self):
        '''Evaluation procedure.
        '''
        #mv = MATS1DDamageView( model = mats_eval )
        #mv.configure_traits()

        right_dof_m = self.fe_grid_m[-1, -1].dofs[0, 0, 0]

        right_dof_fb = self.fe_grid_fb[-1, -1, -1, -1].dofs[0, 0, 0]
        # Response tracers
        A = self.A_m + self.A_f
        self.sig_eps_m = RTraceGraph(name='F_u_m',
                                     var_y='F_int',
                                     idx_y=right_dof_m,
                                     var_x='U_k',
                                     idx_x=right_dof_m,
                                     transform_y='y / %g' % A)

        # Response tracers
        self.sig_eps_f = RTraceGraph(name='F_u_f',
                                     var_y='F_int',
                                     idx_y=right_dof_fb,
                                     var_x='U_k',
                                     idx_x=right_dof_fb,
                                     transform_y='y / %g' % A)

        self.eps_m_field = RTraceDomainListField(name='eps_m',
                                                 position='int_pnts',
                                                 var='eps_app',
                                                 warp=False)

        self.eps_f_field = RTraceDomainListField(name='eps_f',
                                                 position='int_pnts',
                                                 var='mats_phase2_eps_app',
                                                 warp=False)
        # Response tracers
        self.sig_m_field = RTraceDomainListField(name='sig_m',
                                                 position='int_pnts',
                                                 var='sig_app')

        self.sig_f_field = RTraceDomainListField(name='sig_f',
                                                 position='int_pnts',
                                                 var='mats_phase2_sig_app')

        self.omega_m_field = RTraceDomainListField(name='omega_m',
                                                   position='int_pnts',
                                                   var='omega',
                                                   warp=False)

        self.shear_flow_field = RTraceDomainListField(name='shear flow',
                                                      position='int_pnts',
                                                      var='shear_flow',
                                                      warp=False)

        self.slip_field = RTraceDomainListField(name='slip',
                                                position='int_pnts',
                                                var='slip',
                                                warp=False)

        avg_processor = None
        if self.avg_radius > 0.0:
            n_dofs = self.fe_domain.n_dofs
            avg_processor = RTUAvg(sd=self.fe_m_level,
                                   n_dofs=n_dofs,
                                   avg_fn=QuarticAF(radius=self.avg_radius))

        ts = TStepper(
            u_processor=avg_processor,
            dof_resultants=True,
            sdomain=self.fe_domain,
            bcond_list=[  # define the left clamping 
                BCSlice(var='u',
                        value=0.,
                        dims=[0],
                        slice=self.fe_grid_fb[0, 0, 0, :]),
                #                                BCSlice( var = 'u', value = 0., dims = [0], slice = self.fe_grid_m[ 0, 0 ] ),
                # loading at the right edge
                #                                 BCSlice( var = 'f', value = 1, dims = [0], slice = domain[-1, -1, -1, 0],
                #                                         time_function = ls ),
                BCSlice(var='u',
                        value=self.final_displ,
                        dims=[0],
                        slice=self.fe_grid_fb[-1, -1, -1, :],
                        time_function=self.time_function),
                #                                 BCSlice( var = 'u', value = self.final_displ, dims = [0], slice = self.fe_grid_m[-1, -1],
                #                                         time_function = self.time_function ),
                # fix horizontal displacement in the top layer
                #                                 BCSlice( var = 'u', value = 0., dims = [0], slice = domain[:, -1, :, -1] ),
                # fix the vertical displacement all over the domain
                BCSlice(var='u',
                        value=0.,
                        dims=[1],
                        slice=self.fe_grid_fb[:, :, :, :]),
                #                            # Connect bond and matrix domains
                BCDofGroup(var='u',
                           value=0.,
                           dims=[0],
                           get_link_dof_method=self.fe_grid_fb.get_bottom_dofs,
                           get_dof_method=self.fe_grid_m.get_all_dofs,
                           link_coeffs=[1.])
            ],
            rtrace_list=[
                self.sig_eps_m,
                self.sig_eps_f,
                self.eps_m_field,
                self.eps_f_field,
                self.sig_m_field,
                self.sig_f_field,
                self.omega_m_field,
                self.shear_flow_field,
                self.slip_field,
            ])

        # Add the time-loop control
        tloop = TLoop(tstepper=ts,
                      KMAX=300,
                      tolerance=1e-5,
                      debug=False,
                      verbose_iteration=True,
                      verbose_time=False,
                      tline=TLine(min=0.0, step=self.step_size, max=1.0))

        tloop.on_accept_time_step = self.plot

        U = tloop.eval()

        self.sig_eps_f.refresh()
        max_sig_m = max(self.sig_eps_m.trace.ydata)
        return array([U[right_dof_m], max_sig_m], dtype='float_')

    #--------------------------------------------------------------------------------------
    # Tracers
    #--------------------------------------------------------------------------------------

    def plot_sig_eps(self, p):
        p.set_xlabel('control displacement [mm]')
        p.set_ylabel('stress [MPa]')

        self.sig_eps_m.refresh()
        self.sig_eps_m.trace.plot(p, 'o-')

        self.sig_eps_f.refresh()
        self.sig_eps_f.trace.plot(p, 'o-')

        p.plot(self.sig_eps_m.trace.xdata,
               self.sig_eps_m.trace.ydata + self.sig_eps_f.trace.ydata, 'o-')

    def plot_eps(self, p):
        eps_m = self.eps_m_field.subfields[0]
        xdata = eps_m.vtk_X[:, 0]
        ydata = eps_m.field_arr[:, 0, 0]
        idata = argsort(xdata)
        p.plot(xdata[idata], ydata[idata], 'o-')

        eps_f = self.eps_f_field.subfields[1]
        xdata = eps_f.vtk_X[:, 0]
        ydata = eps_f.field_arr[:, 0, 0]
        idata = argsort(xdata)
        p.plot(xdata[idata], ydata[idata], 'o-')

        p.set_ylim(ymin=0)
        p.set_xlabel('bar axis [mm]')
        p.set_ylabel('strain [-]')

    def plot_omega(self, p):
        omega_m = self.omega_m_field.subfields[0]
        xdata = omega_m.vtk_X[:, 0]
        ydata = omega_m.field_arr[:]
        idata = argsort(xdata)
        p.fill(xdata[idata], ydata[idata], facecolor='gray', alpha=0.2)

        print 'max omega', max(ydata[idata])

        p.set_ylim(ymin=0, ymax=1.0)
        p.set_xlabel('bar axis [mm]')
        p.set_ylabel('omega [-]')

    def plot_sig(self, p):
        sig_m = self.sig_m_field.subfields[0]
        xdata = sig_m.vtk_X[:, 0]
        ydata = sig_m.field_arr[:, 0, 0]
        idata = argsort(xdata)
        ymax = max(ydata)
        p.plot(xdata[idata], ydata[idata], 'o-')

        sig_f = self.sig_f_field.subfields[1]
        xdata = sig_f.vtk_X[:, 0]
        ydata = sig_f.field_arr[:, 0, 0]
        idata = argsort(xdata)
        p.plot(xdata[idata], ydata[idata], 'o-')

        xdata = sig_f.vtk_X[:, 0]
        ydata = sig_f.field_arr[:, 0, 0] + sig_m.field_arr[:, 0, 0]
        p.plot(xdata[idata], ydata[idata], 'ro-')

        p.set_ylim(ymin=0)  # , ymax = 1.2 * ymax )
        p.set_xlabel('bar axis [mm]')
        p.set_ylabel('stress [MPa]')

    def plot_shear_flow(self, p):
        shear_flow = self.shear_flow_field.subfields[1]
        xdata = shear_flow.vtk_X[:, 0]
        ydata = shear_flow.field_arr[:, 0] / self.P_f
        idata = argsort(xdata)
        ymax = max(ydata)
        p.plot(xdata[idata], ydata[idata], 'o-')

        p.set_xlabel('bar axis [mm]')
        p.set_ylabel('shear flow [N/m]')

    def plot_slip(self, p):
        slip = self.slip_field.subfields[1]
        xdata = slip.vtk_X[:, 0]
        ydata = slip.field_arr[:, 0]
        idata = argsort(xdata)
        ymax = max(ydata)
        p.plot(xdata[idata], ydata[idata], 'ro-')

        p.set_xlabel('bar axis [mm]')
        p.set_ylabel('slip [N/m]')

    def plot_tracers(self, p=p):

        p.subplot(221)
        self.plot_sig_eps(p)

        p.subplot(223)
        self.plot_eps(p)

        p.subplot(224)
        self.plot_sig(p)

    #---------------------------------------------------------------
    # PLOT OBJECT
    #-------------------------------------------------------------------
    figure_ld = Instance(Figure)

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

    #---------------------------------------------------------------
    # PLOT OBJECT
    #-------------------------------------------------------------------
    figure_eps = Instance(Figure)

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

    #---------------------------------------------------------------
    # PLOT OBJECT
    #-------------------------------------------------------------------
    figure_shear_flow = Instance(Figure)

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

    #---------------------------------------------------------------
    # PLOT OBJECT
    #-------------------------------------------------------------------
    figure_sig = Instance(Figure)

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

    #---------------------------------------------------------------
    # PLOT OBJECT
    #-------------------------------------------------------------------
    figure_shear_flow = Instance(Figure)

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

    def plot(self):

        self.figure_ld.clear()
        ax = self.figure_ld.gca()
        self.plot_sig_eps(ax)

        self.figure_eps.clear()
        ax = self.figure_eps.gca()
        self.plot_eps(ax)
        ax2 = ax.twinx()
        self.plot_omega(ax2)

        self.figure_sig.clear()
        ax = self.figure_sig.gca()
        self.plot_sig(ax)
        ax2 = ax.twinx()
        self.plot_omega(ax2)

        self.figure_shear_flow.clear()
        ax = self.figure_shear_flow.gca()
        self.plot_shear_flow(ax)
        ax2 = ax.twinx()
        self.plot_slip(ax2)

        self.data_changed = True

    def get_sim_outputs(self):
        '''
        Specifies the results and their order returned by the model
        evaluation.
        '''
        return [
            SimOut(name='right end displacement', unit='m'),
            SimOut(name='peak load', uni='MPa')
        ]

    data_changed = Event

    toolbar = ToolBar(Action(name="Run",
                             tooltip='Start computation',
                             image=ImageResource('kt-start'),
                             action="start_study"),
                      Action(name="Pause",
                             tooltip='Pause computation',
                             image=ImageResource('kt-pause'),
                             action="pause_study"),
                      Action(name="Stop",
                             tooltip='Stop computation',
                             image=ImageResource('kt-stop'),
                             action="stop_study"),
                      image_size=(32, 32),
                      show_tool_names=False,
                      show_divider=True,
                      name='view_toolbar'),

    traits_view = View(HSplit(
        VSplit(
            Item('run', show_label=False),
            VGroup(
                Item('shape'),
                Item('n_steps'),
                Item('length'),
                label='parameters',
                id='crackloc.viewmodel.factor.geometry',
                dock='tab',
                scrollable=True,
            ),
            VGroup(Item('E_m'),
                   Item('f_m_t'),
                   Item('avg_radius'),
                   Item('h_m'),
                   Item('b_m'),
                   Item('A_m', style='readonly'),
                   Item('mats_m', show_label=False),
                   label='Matrix',
                   dock='tab',
                   id='crackloc.viewmodel.factor.matrix',
                   scrollable=True),
            VGroup(Item('E_f'),
                   Item('A_f'),
                   Item('mats_f', show_label=False),
                   label='Fiber',
                   dock='tab',
                   id='crackloc.viewmodel.factor.fiber',
                   scrollable=True),
            VGroup(Group(
                Item('tau_max'),
                Item('s_crit'),
                Item('P_f', style='readonly', show_label=True),
                Item('K_b', style='readonly', show_label=True),
                Item('T_max', style='readonly', show_label=True),
            ),
                   Item('mats_b', show_label=False),
                   label='Bond',
                   dock='tab',
                   id='crackloc.viewmodel.factor.bond',
                   scrollable=True),
            VGroup(Item('rho', style='readonly', show_label=True),
                   label='Composite',
                   dock='tab',
                   id='crackloc.viewmodel.factor.jcomposite',
                   scrollable=True),
            id='crackloc.viewmodel.left',
            label='studied factors',
            layout='tabbed',
            dock='tab',
        ),
        VSplit(
            VGroup(
                Item('figure_ld',
                     editor=MPLFigureEditor(),
                     resizable=True,
                     show_label=False),
                label='stress-strain',
                id='crackloc.viewmode.figure_ld_window',
                dock='tab',
            ),
            VGroup(
                Item('figure_eps',
                     editor=MPLFigureEditor(),
                     resizable=True,
                     show_label=False),
                label='strains profile',
                id='crackloc.viewmode.figure_eps_window',
                dock='tab',
            ),
            VGroup(
                Item('figure_sig',
                     editor=MPLFigureEditor(),
                     resizable=True,
                     show_label=False),
                label='stress profile',
                id='crackloc.viewmode.figure_sig_window',
                dock='tab',
            ),
            VGroup(
                Item('figure_shear_flow',
                     editor=MPLFigureEditor(),
                     resizable=True,
                     show_label=False),
                label='bond shear and slip profiles',
                id='crackloc.viewmode.figure_shear_flow_window',
                dock='tab',
            ),
            id='crackloc.viewmodel.right',
        ),
        id='crackloc.viewmodel.splitter',
    ),
                       title='SimVisage Component: Crack localization',
                       id='crackloc.viewmodel',
                       dock='tab',
                       resizable=True,
                       height=0.8,
                       width=0.8,
                       buttons=[OKButton])
Ejemplo n.º 5
0
 def _get_icon(self):
     fig = plt.figure(figsize=(4, 4), facecolor='white')
     self.plot(fig)
     tf_handle, tf_name = tempfile.mkstemp('.png')
     fig.savefig(tf_name, dpi=35)
     return ImageResource(name=tf_name)
Ejemplo n.º 6
0
class MATSCalibDamageFn(MATSExplore):
    '''
    Fitting algorithm for the damage function of the
    quasi-ductile anisotropic material model.

    The algorithm uses the TLoop instance to proceed step
    by step with the computation. The value of the damage function
    for the time step t_n is identified iteratively by adjusting
    the values and evaluating the corresponding equilibrated stresses.

    The control parameters of the algorithm are:

    @param step_size: time step for fitting the damage parameter.
    @param tmax: end time for fitting, it might be also be set implicitly
    for integrity = 1 - full damage of the material.
    '''

    # store the fitted 'PhiFn' in the data base, i.e. 'CCSUniteCell'
    store_fitted_phi_fn = Bool(True)

    # default settings are overloaded with settings specified in 'ec_config'

    max_eps = Property(Float)
    def _get_max_eps(self):
#        return 0.007  # set explicit value when calibration is aborted (mean value of strain)
        return self.mfn_line_array_target.xdata[-1]

    n_steps = Int(1)

    log = Bool(False)

    # TLine parameter
    #
    KMAX = Int
    tolerance = Float
    RESETMAX = Float

    step_size = Property(Float, depends_on='max_eps,n_steps')
    @cached_property
    def _get_step_size(self):
        print 'step_size = ', self.max_eps / self.n_steps
        return self.max_eps / self.n_steps


    def run_through(self):
        '''Run the computation without fitting from the start to the end
        '''
        self.tloop.tline.max = self.tmax
        self.tloop.tline.step = self.step_size
        self.tloop.eval()
        print 'ending time', self.tloop.t_n1
        # show the response

    def run_step_by_step(self):
        '''Run the computation step by step from the start to the end
        '''
        n_steps = int(self.tmax / self.step_size)
        self.tloop.tline.step = self.step_size
        current_time = 0.
        tmax = 0.
        for i in range(n_steps):
            print 'STEP', i
            self.run_one_step()

    def run_trial_step(self):
        '''Run the computation one step starting from the
        current time t_n to iterate the value for phi_new
        which gives a fit with macroscopic stress curve.
        NOTE: The trial step does not update 'U_n' or 't_n'!
        '''
        if self.log:
            print '--------- run trial step: --------- '
        if len(self.tloop.U_n) == 0:
            current_U_n = self.tloop.tstepper.new_cntl_var()
            print 'U_n = None: tloop.tstepper.new_cntl_var()', self.tloop.tstepper.new_cntl_var()
        else:
            current_U_n = self.tloop.U_n[:]
        current_time = self.tloop.t_n
        self.run_one_step()

        # reset the current time back
        self.tloop.t_n = current_time
        self.tloop.U_n[:] = current_U_n[:]
        if self.log:
            print '--------- end of trial step --------- '

        self.tloop.tstepper.sctx.update_state_on = False

    def run_one_step(self):
        '''Run the computation one step starting from the
        current time t_n with the iterated value for phi_new
        in order to update TLoop and save the new phi value in
        the array ydata of PhiFnGeneral
        NOTE: The calculated step does update 'U_n' or 't_n'!
        '''
        self.tloop.tline.step = self.step_size
        current_time = self.tloop.t_n
        tmax = current_time + self.step_size
        self.tloop.tline.max = tmax
        self.tloop.eval()
        self.update_e_max_value_new = True

    #--------------------------------------------------
    # Data source for calibration within simdb
    #--------------------------------------------------

    ex_run = Instance(ExRun)

    composite_tensile_test = Property
    def _get_composite_tensile_test(self):
        return self.ex_run.ex_type

    composite_cross_section = Property
    def _get_composite_cross_section(self):
        return self.composite_tensile_test.ccs

    def get_target_data_exdb_tensile_test(self):
        '''Use the data from the ExDB
        '''
        ctt = self.composite_tensile_test

        # save 'sig_eps_arr' in directory "/simdb/simdata/mats_calib_damage_fn"
        simdata_dir = os.path.join(simdb.simdata_dir, 'mats_calib_damage_fn')
        if os.path.isdir(simdata_dir) == False:
            os.makedirs(simdata_dir)
        ctt_key = str(self.composite_tensile_test.key)
        filename = os.path.join(simdata_dir, 'eps-sig-arr_' + ctt_key + '.csv')

        xdata, ydata = ctt.eps_c_interpolated_smoothed[:, None], ctt.sig_c_interpolated_smoothed[:, None]
        eps_sig_arr = np.hstack([xdata, ydata])
        print 'eps_sig_arr'
        np.savetxt(filename, eps_sig_arr, delimiter=';')
        print 'eps-sig-data saved to file %s' % (filename)

        return ctt.eps_c_interpolated_smoothed, ctt.sig_c_interpolated_smoothed  # smoothed data without jumps with interpolated starting point in the origin
#        return ctt.eps_c_interpolated, ctt.sig_c_interpolated  # original data without jumps with interpolated starting point in the origin
#        return ctt.eps_ironed, ctt.sig_c_ironed  # original data without smoothing (without jumps)
#        return ctt.eps_smooth, ctt.sig_c_smooth #smoothed data


    #--------------------------------------------------
    # interpolation function for fitting data:
    #--------------------------------------------------
    mfn_line_array_target = Property(Instance(MFnLineArray),
                                      depends_on='ex_run')
    @cached_property
    def _get_mfn_line_array_target(self):
        xdata, ydata = self.get_target_data_exdb_tensile_test()
        print 'xdata[-1]', xdata[-1]
        return MFnLineArray(xdata=xdata, ydata=ydata)

    fitted_phi_fn = Instance(MFnLineArray)

    #---------------------------------------------------------------
    # PLOT OBJECT
    #-------------------------------------------------------------------
    figure = Instance(Figure)
    def _figure_default(self):
        figure = Figure(facecolor='white')
        figure.add_axes([0.12, 0.13, 0.85, 0.74])
        return figure

    data_changed = Event

    def init(self):
        #--------------------------------------------------
        # for fitting use 'General'-function for 'phi_fn':
        #--------------------------------------------------
        # The value pair for the piecewise linear definition
        # of 'phi_fn' value consists of current strain and the
        # iterated 'phi_value'. The microplanes with a lower
        # microplane strain level use an interpolated value
        # for 'phi'
        self.fitted_phi_fn = self.dim.mats_eval.phi_fn.mfn
        self.fitted_phi_fn.xdata = [0]
        self.fitted_phi_fn.ydata = [1]
        self.fitted_phi_fn.data_changed = True
        # initialize TLoop parameters:
        self.tloop.setup()
        self.tloop.tstepper.sctx.mats_state_array[:] = 0.0
        self.tloop.U_n[:] = 0.0
        self.tloop.rtrace_mngr.clear()
        self.tloop.verbose_iteration = False
        self.tloop.verbose_load_step = False
        self.tloop.verbose_time = False
        # set TLine parameters
        self.tloop.tline.KMAX = self.KMAX
        self.tloop.tline.tolerance = self.tolerance
        self.tloop.tline.RESETMAX = self.RESETMAX

    # store trial step data in the lists if trial steps are to be stored
    # for the plotting method 'plot_trail_steps'
    #
    rec_trial_steps = True
    phi_trial_list_i = []
    sig_trial_list_i = []
    phi_trial_list_n = []
    sig_trial_list_n = []

    def get_lack_of_fit(self, phi_trial):
        '''Return the difference between the macroscopic stress calculated
        based on the value of phi_trial (damage at the next step) and the
        macroscopic stress defined as target data (=fitting curve)
        '''
        if self.log:
            print '\n'
            print "#'get_lack_of_fit' for the trial value # START"
            print '    phi_trial    = ', phi_trial

        # value of the principle macroscopic strain corresponds to control variable
        current_time = self.tloop.t_n

        if self.log:
            print '    current_time = ', current_time
            print '    step_size    = ', self.step_size

        # ------------------------------------
        # add new pair in fitted_phi_fn
        # ------------------------------------
        # consisting of 'e_max_value_new' and 'phi_trial'
        x = hstack([ self.fitted_phi_fn.xdata[:], current_time + self.step_size ])
        y = hstack([ self.fitted_phi_fn.ydata[:], phi_trial ])
        self.fitted_phi_fn.set(xdata=x, ydata=y)
        self.fitted_phi_fn.data_changed = True

        # ------------------------------------
        # get state array before trial:
        # ------------------------------------
        mats_state_array_old = copy(self.tloop.tstepper.sctx.mats_state_array)

        # ------------------------------------
        # run trial step:
        # ------------------------------------
        if self.log:
            print '    reset current_U_n   =', self.tloop.U_n
            print 'CURRENT PHI', self.dim.mats_eval.phi_fn.mfn.ydata
        # try the next equilibrium
        self.run_trial_step()

        # ------------------------------------
        # reset mats_state_array:
        # ------------------------------------
        # Note: the material state array (i.e. the maximum microstrains) are
        # updated within the iterations of each trial step, therefore a reset
        # is necessary in order to start each trial step with the same state variables
        self.tloop.tstepper.sctx.mats_state_array[:] = mats_state_array_old[:]
        if self.log:
            print '    reset state array'

        # ------------------------------------
        # remove trial value in fitted_phi_fn
        # ------------------------------------
        x = self.fitted_phi_fn.xdata[:-1]
        y = self.fitted_phi_fn.ydata[:-1]
        self.fitted_phi_fn.set(xdata=x, ydata=y)
        self.fitted_phi_fn.data_changed = True

        # ------------------------------------
        # get the lack of fit
        # ------------------------------------
        # get calculated value for 'sig_app' based on the current value of 'phi_trial':
        # and evaluate the difference between the obtained stress and the measured response
        self.tloop.rtrace_mngr.rtrace_bound_list[0].redraw()
        sig_app_trial = self.tloop.rtrace_mngr.rtrace_bound_list[0].trace.ydata[-1]
        # get corresponding value from the target data:
        sig_app_target = self.mfn_line_array_target.get_value(current_time + self.step_size)
        # absolut error:
        lack_of_fit_absolut = sig_app_trial - sig_app_target
        # relative error:
        lack_of_fit_relative = lack_of_fit_absolut / sig_app_target

        if self.log:
            print '    sig_app_trial ', sig_app_trial
            print '    sig_app_target', sig_app_target
            print '    lack_of_fit_absolute  ', lack_of_fit_absolut
            print '    lack_of_fit_relative  ', lack_of_fit_relative
            print '# get_lack_of_fit # END '

        if self.rec_trial_steps:
            # store all trial values of 'phi_trail' and 'sig_app_trail' within each iteration to a global list
            #
            self.phi_trial_list_i.append(phi_trial)
            self.sig_trial_list_i.append(sig_app_trial)

        return lack_of_fit_relative

    param_key = Str('')

    def fit_response(self):
        '''iterate phi_trial in each incremental step such that the
        lack of fit between the calculated stress and the target
        curve is smaller then xtol defined in function 'brentq'.
        NOTE: the method 'get_lack_of_fit' returns the relative error.
        '''

        self.tloop.reset()

        phi_old = 1.0

        # map the array dimensions to the plot axes
        #
        figure = self.figure

        axes = figure.axes[0]

        print 'n_steps', self.n_steps
        for n in range(self.n_steps):

            axes.clear()

            phi_new = phi_old

            # use scipy-functionality to get the iterated value of phi_new
            # If the trial value calculated with phi_trial = phi_old
            # is smaller then target value get_lack_of_fit has no sign change
            # for phi_trial = phi_old and phi_trial = 0. which is a requirement
            # for the function call 'brentq'. In this case the old value
            # for phi_trial is used and tloop moves on one step
            try:
                # The method brentq has optional arguments such as
                #   'xtol'    - absolut error (default value = 1.0e-12)
                #   'rtol'    - relative error (not supported at the time)
                #   'maxiter' - maximum numbers of iterations used
                #
                # Here xtol is used to specify the allowed RELATIVE error!
                # therefore the relative lack of fit is returned in
                # method 'get_lack_of_fit'
                _xtol = 1.0e-6
                phi_new = brentq(self.get_lack_of_fit, 0., phi_old, xtol=_xtol)
                # @todo: check if 'brenth' gives better fitting results; faster?
#                phi_new = brenth( self.get_lack_of_fit, 0., phi_old )
                print '(#) n = ', n
            except ValueError:

                if self.log:
                    lof_0 = self.get_lack_of_fit(0.)
                    lof_phi_old = self.get_lack_of_fit(phi_old)
                    print 'No sign change between get_lack_of_fit(phi_old) = ', lof_phi_old, ' and '
                    print 'get_lack_of_fit(0.) = ', lof_0
                    print 'Use old value for phi_trial. phi_old = ', phi_old
                else:
                    print '(!) n = ', n

            # current time corresponds to the current strain applied
            #
            current_time = self.tloop.t_n

            # replace old 'phi_value' with iterated value:
            #
            phi_old = phi_new

            # get mats_state_array:
#            mats_state_array = copy(self.tloop.tstepper.sctx.mats_state_array)

            # update phi_data:
            #
            x = hstack([ self.fitted_phi_fn.xdata[:], current_time + self.step_size  ])
            y = hstack([ self.fitted_phi_fn.ydata[:], phi_new             ])

            axes.plot(x, y, color='blue', linewidth=2)
            self.data_changed = True

            self.fitted_phi_fn.set(xdata=x, ydata=y)
            self.fitted_phi_fn.data_changed = True

            # run one step with the iterated value for phi in order to
            # update the state array and to move forward one step:
            if self.log:
                print '\n'
                print '### run_one_step ###'
                print '### step', n   , '###'
                print '### current time:', current_time

            if self.rec_trial_steps:
                # add entries of the iterations ('i') in the current step ('n')
                # (yields a list of lists)
                #
                self.phi_trial_list_n.append(self.phi_trial_list_i)
                self.sig_trial_list_n.append(self.sig_trial_list_i)
                # delete the entries of the iterations ('i') in the last step ('n')
                # and fill it with the iterations of the next step ('n+1')
                #
                self.phi_trial_list_i = []
                self.sig_trial_list_i = []

            self.run_one_step()
#            print '(g%)' %(n)

        self.fitted_phi_fn.changed = True
        mats_key = self.dim.mats_eval.__class__.__name__
        ctt_key = str(self.composite_tensile_test.key)
        if self.store_fitted_phi_fn:
            print "stored 'fitted_phi_fn' in CCSUnitCell with material model %s and calibration test %s" % (mats_key, ctt_key)
            print 'ctt_key + self.param_key', ctt_key + self.param_key
            self.composite_cross_section.set_param(mats_key, ctt_key + self.param_key,
#            self.composite_cross_section.set_param(mats_key, ctt_key,
                                                   copy(self.fitted_phi_fn))
            # save 'sig_eps_arr' in directory "/simdb/simdata/mats_calib_damage_fn"
            simdata_dir = os.path.join(simdb.simdata_dir, 'mats_calib_damage_fn')
            if os.path.isdir(simdata_dir) == False:
                os.makedirs(simdata_dir)
            ctt_key = str(self.composite_tensile_test.key)
            filename = os.path.join(simdata_dir, 'eps-phi-arr_' + ctt_key + self.param_key + '.csv')

            xdata, ydata = self.fitted_phi_fn.xdata[:, None], self.fitted_phi_fn.ydata[:, None]
            eps_phi_arr = np.hstack([xdata, ydata])
            np.savetxt(filename, eps_phi_arr, delimiter=';')
            print 'eps-phi-data saved to file %s' % (filename)

    format_ticks = Bool(False)
    def plot_trial_steps(self):
        '''Plot target (sig-eps-curve of the tensile test) and trial curves
        and corresponding phi function together with trail steps from the iteration process.
        NOTE: the global variable 'rec_trial_steps' must be set to 'True' in order to store the iteration values
              within the global variables 'phi_trial_list_n' and 'sig_trial_list_n'
        n - index of the time steps to be considered
        i - index of the iteration steps performed in order to fit the target curve
        '''
        #-------------------------------------------------------------------
        # configure the style of the font to be used for labels and ticks
        #-------------------------------------------------------------------
        #
        from matplotlib.font_manager import FontProperties
        font = FontProperties()
#        font.serif         : Times, Palatino, New Century Schoolbook, Bookman, Computer Modern Roman
#        font.sans-serif    : Helvetica, Avant Garde, Computer Modern Sans serif
#        font.cursive       : Zapf Chancery
#        font.monospace     : Courier, Computer Modern Typewriter
        font.set_name('Script MT')
        # name = ['Times New Roman', 'Helvetica', 'Script MT'] #?
        font.set_family('serif')
        # family = ['serif', 'sans-serif', 'cursive', 'fantasy', 'monospace']
        font.set_style('normal')
        # style  = ['normal', 'italic', 'oblique']
        font.set_size('small')
        # size  = ['xx-small', 'x-small', 'small', 'medium', 'large', 'x-large', 'xx-large', '11']
        font.set_variant('normal')
        # variant= ['normal', 'small-caps']
        font.set_weight('medium')
        # weight = ['light', 'normal', 'medium', 'semibold', 'bold', 'heavy', 'black']

        #-------------------------------------------------------------------

        p.figure(facecolor='white', dpi=600, figsize=(8, 6))  # white background

        # time list corresponding to the specified numbers of steps and step size
        #
        step_list = [n * self.step_size for n in range(self.n_steps + 1)]

        # get list of lists containing the trial values of 'sig_app' and 'phi_trail'
        # the lists are defined as global variables of 'MATSCalibDamageFn' and are filled
        # within the iteration process when the method 'get_lack_of_fit" is called
        #
        phi_trial_list_n = [[1.]] + self.phi_trial_list_n
        sig_trial_list_n = [[0.]] + self.sig_trial_list_n

        xrange = 10.  # plotting range for strain [mm/m]
        yrange = 15.  # plotting range for stress [MPa]

        for n in range(self.n_steps):
            for i in range(len(phi_trial_list_n[n + 1])):
                x = np.array([step_list[n], step_list[n + 1]])
                eps = 1000. * x  # plot strains in permil on the x-axis
                #--------------------------------------
                # sig-eps trial
                #--------------------------------------
                # plot the numerically calculated sig-eps-curve (tensile test)
                # (with trial steps)
                #
                sig_trail = np.array([sig_trial_list_n[n][-1], sig_trial_list_n[n + 1][i]])
                p.subplot(222)
                p.plot(eps, sig_trail, color='k', linewidth=1)
                p.xlabel(r'strain $\varepsilon$ [1E-3]', fontproperties=font)
                p.ylabel('stress $\sigma$ [MPa]', fontproperties=font)
                if self.format_ticks:
                    # format ticks for plot
                    p.axis([0, xrange, 0., yrange], fontproperties=font)
                    locs, labels = p.xticks()
                    p.xticks(locs, map(lambda x: "%.0f" % x, locs), fontproperties=font)
                    locs, labels = p.yticks()
                    p.yticks(locs, map(lambda x: "%.0f" % x, locs), fontproperties=font)

                #--------------------------------------
                # phi_trail
                #--------------------------------------
                # plot the fitted phi-function
                # (with trial steps)
                #
                p.subplot(224)
                phi_trail = np.array([phi_trial_list_n[n][-1], phi_trial_list_n[n + 1][i]])
                p.plot(eps, phi_trail, color='k', linewidth=1)
                p.xlabel(r'strain $\varepsilon$ [1E-3]', fontproperties=font)
                p.ylabel('integrity $\phi$ [-]', fontproperties=font)
                if self.format_ticks:
                    # format ticks for plot
                    p.yticks([0, 0.2, 0.4, 0.6, 0.8, 1.0])
                    p.axis([0, xrange, 0., 1.])
                    locs, labels = p.xticks()
                    p.xticks(locs, map(lambda x: "%.0f" % x, locs), fontproperties=font)
                    locs, labels = p.yticks()
                    p.yticks(locs, map(lambda x: "%.1f" % x, locs), fontproperties=font)

        #--------------------------------------
        # sig-eps target
        #--------------------------------------
        # plot the sig-eps-target curve (tensile test)
        #
        p.subplot(221)
        eps = 1000. * self.mfn_line_array_target.xdata[:-1]
        sig_target = self.mfn_line_array_target.ydata[:-1]
        p.plot(eps, sig_target, color='black', linewidth=1)
        p.xlabel(r'strain $\varepsilon$ [1E-3]', fontproperties=font)
        p.ylabel('stress $\sigma$ [MPa]', fontproperties=font)
        if self.format_ticks:
            # format ticks for plot
            p.axis([0, xrange, 0., yrange])
            locs, labels = p.xticks()
            p.xticks(locs, map(lambda x: "%.0f" % x, locs), fontproperties=font)
            locs, labels = p.yticks()
            p.yticks(locs, map(lambda x: "%.0f" % x, locs), fontproperties=font)

        #--------------------------------------
        # phi_trail (final)
        #--------------------------------------
        # plot the corresponding fitted phi-function
        # (without trial steps)
        #
        p.subplot(223)
        eps = 1000. * self.fitted_phi_fn.xdata[:-1]
        phi_fn = self.fitted_phi_fn.ydata[:-1]
        p.plot(eps, phi_fn, color='black', linewidth=1)
        p.xlabel(r'strain $\varepsilon$ [1E-3]', fontproperties=font)
        p.ylabel('integrity $\phi$ [-]', fontproperties=font)
        if self.format_ticks:
            # format ticks for plot
            p.yticks([0, 0.2, 0.4, 0.6, 0.8, 1.0])
            p.axis([0, xrange, 0., 1.])
            locs, labels = p.xticks()
            p.xticks(locs, map(lambda x: "%.0f" % x, locs), fontproperties=font)
            locs, labels = p.yticks()
            p.yticks(locs, map(lambda x: "%.1f" % x, locs), fontproperties=font)

        # save figure with calibration process in directory "/simdb/simdata/lcc_table/output_images/save_fig_to_file.png"
        simdata_dir = os.path.join(simdb.simdata_dir, 'mats_calib_damage_fn')
        if os.path.isdir(simdata_dir) == False:
            os.makedirs(simdata_dir)

        ctt_key = str(self.composite_tensile_test.key)
        filename = os.path.join(simdata_dir, ctt_key + self.param_key + '.pdf')
        p.savefig(filename)
        print 'plot_trail_steps.png saved to file %s' % (filename)
        filename = os.path.join(simdata_dir, ctt_key + self.param_key + '.png')
        p.savefig(filename, dpi=600)
        print 'plot_trail_steps.png saved to file %s' % (filename)

        p.show()

    #-----------------------------------------------------------------------------------------
    # User interaction
    #-----------------------------------------------------------------------------------------
    toolbar = ToolBar(
                  Action(name="Run Calibration",
                         tooltip='Run damage function calibration for the current parameters',
                         image=ImageResource('kt-start'),
                         action="run_calibration"),
                  image_size=(22, 22),
                  show_tool_names=False,
                  show_divider=True,
                  name='calibration_toolbar')

    traits_view = View(HSplit(
                            Item('ex_run@',
                                    show_label=False),
                            VSplit(
                               Item('dim@',
                                    id='mats_calib_damage_fn.run.split',
                                    dock='tab',
                                    resizable=True,
                                    label='experiment run',
                                    show_label=False),
                                    id='mats_calib_damage_fn.mode_plot_data.vsplit',
                                    dock='tab',
                                ),
                            VSplit(
                                Group(
                                      Item('figure', editor=MPLFigureEditor(),
                                         resizable=True, show_label=False),
                                    id='mats_calib_damage_fn.plot_sheet',
                                    label='fitted damage function',
                                    dock='tab',
                                    ),
                                    id='mats_calib_damage_fn.plot.vsplit',
                                    dock='tab',
                                   ),
                                    id='mats_calib_damage_fn.hsplit',
                                    dock='tab',
                                ),
#                        menubar = self.default_menubar(),
                        resizable=True,
                        toolbar=toolbar,
                        handler=MATSCalibDamageFnController(),
                        title='Simvisage: damage function calibration',
                        id='mats_calib_damage_fn',
                        dock='tab',
                        buttons=[ OKButton, CancelButton ],
                        height=0.8,
                        width=0.8)
Ejemplo n.º 7
0
class SimPStudy(HasTraits):
    """ The main application window. """
    def __init__(self, **kw):
        super(SimPStudy, self).__init__(**kw)

        # The initialization should not be considered dirty
        # therefore set the flag to indicate unsaved study to false
        #
        self.dirty = False

    sim_array = Instance(SimArray)

    def _sim_array_default(self):
        return SimArray()

    sim_model = Property()

    def _set_sim_model(self, value):
        self.sim_array.sim_model = value

    def __getitem__(self, factor_slices):
        '''Direct access to the sim_array.
        '''
        return self.sim_array[factor_slices]

    #---------------------------------------------------------------
    # PERSISTENCY
    #-------------------------------------------------------------------

    file_base_name = Property()

    def _get_file_base_name(self):
        return self.sim_model.__class__.__name__

    file_path = Str('')

    dirty = False

    @on_trait_change('sim_array.changed')
    def _set_dirty(self):
        self.dirty = True

    def new(self):
        sim_model = self.sim_array.sim_model
        self.sim_array = SimArray(sim_model=sim_model)
        self.dirty = False

    def load(self, file_name):
        file = open(file_name, 'r')
        self.sim_array = pickle.load(file)
        file.close()
        self.dirty = False

    def save(self, file_name):
        file = open(file_name, 'w')
        pickle.dump(self.sim_array, file)
        file.close()
        self.dirty = False

    def clear_cache(self):
        self.sim_array.clear_cache()

    toolbar = ToolBar(Action(name="New Study",
                             tooltip='Create a new study',
                             image=ImageResource('New-32'),
                             action="new_study"),
                      Action(name="Open Study",
                             tooltip='Open a study',
                             image=ImageResource('fileopen-32'),
                             action="open_study"),
                      Action(name="Save Study",
                             tooltip='Save study',
                             image=ImageResource('save'),
                             action="save_study"),
                      Action(name="New View",
                             tooltip='Create new view',
                             image=ImageResource('new_view'),
                             action="new_view"),
                      Action(name="Clear Cache",
                             tooltip='Reset cache',
                             image=ImageResource('reset'),
                             action="clear_cache"),
                      image_size=(22, 22),
                      show_tool_names=False,
                      show_divider=True,
                      name='study_toolbar')

    menubar = MenuBar(
        Menu(Action(name="&New", action="new_study"),
             Action(name="&Open", action="open_study"),
             Action(name="&Save", action="save_study"),
             Action(name="Save &As", action="save_study_as"),
             Action(name="&Exit", action="exit_study"),
             name="&File"),
        Menu(Action(name="&New View", action="new_view"), name="&View"),
        Menu(Action(name="&Clear Cache", action="clear_cache"), name="&Data"),
        Menu(Action(name="About PStudy", action="about_pstudy"),
             HelpAction,
             name="Help"))

    view = View(
        Item('sim_array@', show_label=False),
        id='simvisage.simiter.pstudy',
        dock='tab',
        menubar=menubar,
        toolbar=toolbar,
        resizable=True,
        width=0.8,
        height=0.8,
        title='SimVisage: Parametric Study',
        handler=SimPStudyController,
    )